I'm working on making my own boot loader and kernel in D, and I've come across a stumbling block.
kmain()
, the entrypoint of my kernel.It's part of the kernel's job to be able to load PE files. So how do I load the kernel itself into memory in the first place, so that it can actually execute correctly?
I can't do this from the boot sector because (1) it doesn't fit in 512 bytes, and (2) it's painful to do in assembly. Obviously, I can't do it in the kernel itself either. So how should I do this?
How does GRUB do it?
In GRUB, the 512 byte boot sector does not load the kernel. Instead, it loads the rest of the bootloader, which is much larger than 512 bytes. It is this second-stage bootloader that loads the kernel. You will have to do something similar.
The code for loading this second stage can be much simpler than the code for loading the full kernel - it basically loads a few sectors directly into a fixed memory address (in low memory - it is still in real mode by this point) and jumps to a fixed memory address.
This second stage can be mostly written in C. You only need a bit of setup in assembly (entering protected mode, setting up the stack, and few other bits of low-level processor stuff) before jumping to a C function to do the rest of the setup.
The Linux kernel did something like this in the past. You could copy the raw kernel directly into a floppy disk. Its first 512 bytes were a floppy disk boot sector, which loaded the next few sectors (still in real mode) into a fixed address in low memory. These next few sectors had the code (still in assembly) to load the rest of the kernel into a fixed memory address, and jump to its real entry point. Nowadays, IIRC most of this code was ripped out and the Linux kernel now depends on external bootloaders.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With