Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Loading a Kernel into Memory -- How to Write the Loader Itself?

I'm working on making my own boot loader and kernel in D, and I've come across a stumbling block.

Background:

  • I'm writing everything from scratch. So the boot sector is in assembly. And I'm not using GRUB.
  • I'm using Qemu for testing.
  • The boot sector reads the kernel from the "disk" (which is currently just a flat binary file, whose first sector is the boot loader and the rest of which is the kernel code) into virtual address 0xC0000000, and calls kmain(), the entrypoint of my kernel.
  • I'm using the PE file format for my kernel. (Please don't tell me to use Elf -- my choice is PE.)

The Problem

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?

like image 950
user541686 Avatar asked Dec 27 '22 18:12

user541686


1 Answers

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.

like image 80
CesarB Avatar answered Jan 21 '23 22:01

CesarB