Search code examples
rustqemuelfosdevriscv

Why won't me custom kernel launch in QEMU?


I'm looking into creating my own OS for a hobby/learning purpose.

I have created a simple rust program but cannot get it to start with QEMU. My rust code is shown below.

#![no_std]
#![no_main]

mod panic;

#[no_mangle]
pub extern "C" fn _start() -> ! {
    loop{}
}

I am compiling this to the following format.

riscv64gc-unknown-none-elf

and the attempting to run it in QEMU with this command

qemu-system-riscv64 -M virt -bios none -kernel

This will launch QEMU but the debugging tools show nothing in the memory.

I can see that it is not in the correct location in memory so I added the following arguments to the linker so that it would be loaded into the correct location (beginning of memory).

--image-base=0x80000000

I can see it is now in the correct location but then will not execute anything because there is no valid code at the starting address of 0x80000000 as the elf header is the first thing there.

I was under the impression that QEMU was able to read the elf file and jump to the entry address specified in the header. Is this not true or am I just missing something?


Solution

  • QEMU has probably decided that your ELF file isn't the right format and fallen back to "assume this is a raw binary". If you want to debug what's going wrong you could run QEMU under gdb and look at the code path taken starting with the riscv_load_kernel() function.

    More generally, though, '-kernel' behaviour in QEMU is architecture-dependent, but mostly is designed for "boot a Linux kernel". So if you're definitely building your custom OS to match the image format and boot protocol that Linux uses, then it's the right option. If you're just building a random ELF file and want to have QEMU start from its entry point, though, you might find the generic loader a better fit.