Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Preparing to load a kernel

Even though there are wonderfully complete boot loaders available, I've been writing one on and off in my spare time as an educational exercise. I've run into a problem.

I am able to perform an initial boot and chain load other sectors with no problem. If I were writing my own OS I'd be good to go. :) Instead, I'm trying to bootstrap Linux. The challenge I'm having is two-fold.

  1. I understand that I need to load the kernel (Linux) into memory at 0x100000. I know that I should find the "HdrS" signature at offset 0x202 of the kernel. I also know that the start address should be in 0x214. However, when I jump to the address in that location it halts. Obviously, it's pretty hard to wrap a debugger around this. :) Am I missing something in this chain of facts necessary to determine that correct start address of the kernel?
  2. I suspect that the answer to (1) could be something to do with needing to fill some memory area with hardware discovery information. I've seen several passing references to this on OSDev Wiki but I seem to be missing where this is and precisely which data needs to be there. Is the boot loader responsible for hardware discovery? If so, what data needs to be put where?

An additional point to take note of is that I am already in 32 bit protected mode because I'm dealing with creating an EFI boot system, so 16 bit real mode isn't really an option here, eliminating the real mode start location in the kernel.

like image 924
David Hoelzer Avatar asked Oct 31 '22 13:10

David Hoelzer


1 Answers

@Jester found my issue and answered both questions. The solution was actually in the file that I had linked, though I had missed the relevant section. I'm including the relevant piece here for posterity:

In 32-bit boot protocol, the first step in loading a Linux kernel should be to setup the boot parameters (struct boot_params, traditionally known as "zero page"). The memory for struct boot_params should be allocated and initialized to all zero. Then the setup header from offset 0x01f1 of kernel image on should be loaded into struct boot_params and examined. The end of setup header can be calculated as follow:

0x0202 + byte value at offset 0x0201

In addition to read/modify/write the setup header of the struct boot_params as that of 16-bit boot protocol, the boot loader should also fill the additional fields of the struct boot_params as that described in zero-page.txt.

After setting up the struct boot_params, the boot loader can load the 32/64-bit kernel in the same way as that of 16-bit boot protocol.

In 32-bit boot protocol, the kernel is started by jumping to the 32-bit kernel entry point, which is the start address of loaded 32/64-bit kernel.

At entry, the CPU must be in 32-bit protected mode with paging disabled; a GDT must be loaded with the descriptors for selectors __BOOT_CS(0x10) and __BOOT_DS(0x18); both descriptors must be 4G flat segment; __BOOT_CS must have execute/read permission, and __BOOT_DS must have read/write permission; CS must be __BOOT_CS and DS, ES, SS must be __BOOT_DS; interrupt must be disabled; %esi must hold the base address of the struct boot_params; %ebp, %edi and %ebx must be zero.

64 bit instructions can also be found in this same document.

like image 56
David Hoelzer Avatar answered Nov 02 '22 09:11

David Hoelzer