Thursday, July 26, 2012

Writing a Bootloader

I am starting to think of any reason to Write a Bootloader ...

I've been always interested not only how to write applications but understanding how the whole system works, from the moment the machine boots.

The first steps in computer booting can be described in general as follows:
  • Power Up
  • Start Processing ROM BIOS
  • Execute POS (Power-on self Test)
  • Check hardware devices
  • Look for OS to load

During the last step, BIOS will search for Storage Devices (described in the device Boot Order). These are usually CD-Rom, Hard Drives, USB Drives, Disk Drives, etc.

For each Device (In order), BIOS will look for MBR (Master Boot Record) which corresponds to the first 512 bytes of the Device Image. These 512 Bytes are loaded then into the memory and executed. It's a very small space in memory to be able to achieve many tasks. 

Bootloaders are commonly used to access the kernel loader located in the boot sector of the drive. Other tasks includes initialize critical hardware devices and initialize other resources such as memory, interrupts, clocks and timers.

Hmm looks like I found a reason to create a bootloader ... Just for Fun! (Anyway, I got sick note from Doctor so I have to stay home ... It looks like I am getting Bored!)

Let's get our hands Dirty. Which tools from the Hardware store do we need?
Good news is we don't need any (If you want to go farther, then get some old USB Flash Drive)

Software of course is a must:
  • Any Linux flavor (I used fedora)
  • A Virtualization Application (Virtual Box)
I will run the Bootloader in a Virtual Machine because it will allow me to test easier every change I do to the source code and performing a real test will require me to have a spare machine for tests. (My wife would kill me if She finds her computer broken when She arrives Home)

As my computer is running Windows 7, I have trouble finding appropriate tools to develop a bootloader (It must be compiled as 16Bit Binary File). If you are interested, there's nasm for windows to compile your code, and partcopy to write the MBR of a Device.

Instead a Virtual Environment is also possible to use Bochs which is a x86 (PC) emulator.

First, create the Linux virtual machine in VirtualBox (It's pretty straightforward). After you spent some time installing it, let's create the next Virtual Machine.

I've created a Virtual Machine with 64MB of memory and "Other" as operating system. For the storage I've created a virtual Drive with 64MB of space and type "Shareable". (It will be used inside Linux and our new OS).

Then, Include this Drive in your linux configuration as IDE Primary slave. I will allow linux to recognize it as a valid drive.

Now it's time to code. Run your Linux Virtual Machine and open your favorite text editor.

There are four important requirements for the bootloader:

  • Must be compiled in 16Bit mode
  • Define Memory offset when code is loaded into the physical address.
  • Boot Memory space not used must be cleared.
  • Boot Signature: This is required by the BIOS to determine if the Device is Bootable. Failing to find this signature will cause BIOS to ignore the device.
The following code will generate a basic bootloader:

  1. BITS 16                 ;Tell compiler that this is 16 Bit code
  2. org 07C00h              ;Tell compiler code will be loaded in this memory section
  3. mov si, txtStr
  4. call printTxt
  5. JMP $
  6. printTxt:
  7.   lodsb
  8.   cmp al, 0
  9.   je exitFn
  10.   mov ah, 0Eh
  11.   int 10h
  12.   jmp printTxt
  13. exitFn:
  14.   RET
  15. ;AppData
  16. txtStr db "Hello You!", 0
  17. times 510-($-$$) db 0   ;Fill the rest of the Loader with "0"
  18. dw 0AA55h               ;Bootloader Signature

I will not go into the details of each call. Briefly, it defines code as 16 Bits, tells compiler where in physical memory code will be loaded, prints the string defined in "txtStr", fills the rest of bytes with "0" and finally writes the bootloader signature.

Now I will compile code above using nasm:

     nasm bootload.asm -f bin -o bootload.bin

In the final step I will use the linux "dd" command to copy the generated binary file to the device:

     dd if= bootload.bin bs=512 of=/dev/sdb

Notice that /dev/fd0 is the additional virtual drive we added to the Linux machine. Do not mount the device!

If command above succeeded, go to to Virtual Box Manager and launch the OS where you just copied the Bootloader. Hopefully you will get a screen like this:

If you get this screen, then you can continue your research and go beyond the typical "Hello World" example. Low level programming and OS development is a very interesting topic that is worth exploring.

No comments: