Saturday, January 02, 2010

The Bootstrap Problem

When you turn your computer on, it just boots. You take it for granted. It says "Windows loading" or "Grub", or "L..I..L..O".

But a lot of work goes into getting your computer to boot.

The main problem is the processor just runs programs. And it needs a program to tell it how to load programs. But you need to load a program, to run the program...

The solution is a program which lives at a particular address in permanent memory (ROM). This program is called the BIOS, and it has a really remarkable history going back to the original IBM PC.

The BIOS finds a boot device (usually floppy, harddrive, or CD-ROM, but now usually includes USB). It then loads the "boot sector". This is a 512 byte block of memory containing code which is placed at address 0x7c00. It then jumps to 0x7c00, and you're off!

In my NedOS musings, I considered using Grub as a boot loader. It handles a lot of stuff, and allows you to build your kernel like a regular program. In the end, I rejected it, because:
  1. I wanted to learn how to do a bootloader
  2. I didn't want to be bound to ext2fs and Elf (or worse, FAT32 and PE)
  3. You really need to build a cross compiler to use it
  4. Grub seems bound to 32bit kernels
  5. Grub is 3 stage, I wanted to see if I can get into 64bit mode in 1 hop
The fifth point is the most interesting. Your first stage is the bootsector (512 bytes, really 448 on a boot floppy). That's all you've got to get going, it is really cramped! But loading a second stage requires disk accesses and some sort of file system. I don't want to think about file systems right now, and I don't want to pick an existing one and get stuck with those assumptions.

After most of the day hacking, I have a minimal 64bit bootloader, in 170 bytes!

Now I need to figure out what BIOS info I want to extract before kicking into protected mode, and how I want to find the kernel.

Ugly/cool tip:
You cannot get to 64 bit mode in one step. You have to go through protected mode (because the bit for long mode is in a different register than the register used to enter protected mode - jerks). Further complicating things, the code descriptor for 32bit code is incompatible with the descriptor for 64bit code (nice work guys).

So what I do:
  • set the descriptor for 16bit protected mode code (yes, the original 286 style)
  • kick into protected mode
  • set for long mode (I'm now in a really tenuous position, but interrupts are off)
  • flip the descriptor bit for 64bit code
I could switch to 64 bit mode now, but I turn on paging first, just for good measure. Then with a far jump, I'm into 64 bit/paged mode!

No comments: