Thursday, August 02, 2012

Launch Boot loader from MBR

In previous posts I went into the process of building a Boot loader in assembler on the MBR (Master Boot Record).

If you open a binary editor to inspect the contents of the Boot loader created in the previous post you will realize that the assembled code occupies around 203 bytes.

Due to the distribution of the MBR, there are around 440 bytes available for the code. So this simple code used to print basic drive information takes around 50% of the total available.

In modern OS (ie Linux) the MBR is used to launch the Boot loader (Linux) from a specific location in the Disk (where there should be more than enough space). Linux, in particular, uses the MBR to launch it's Boot loader (GRUB)

The following code will launch our boot loader from the MBR. First, our launcher must load the Bootloader from the media (aka Disk Drive) to a specific location in memory. Then we call a "jmp" to transfer the flow of execution to the loaded application.

BITS 16;Tell compiler that this is 16 Bit code

org07C00h;Tell compiler code will be loaded in this memory section

movsi, txtStr

call printTxt

call crlf

movsi, txtStr2

call printTxt

call crlf

movah,02h

moval,1; Sectors to Read

movcl,2; Sector to Start Reading [5..0]

movch,0; Cylinder [15..6]

movdh,0; Head Number

movdl,80h; Drive Number Hard Drive 1

movbx,0x07E0;Where to load Bootloader 0x70E0:00

moves,bx

movbx,0x00

int13h;Int 13 is all functions for disks

movsi, txtLaunch

call printTxt

call crlf

jmp0x07E0:0x00;Run Bootloader.

; PhysicalAddress = Segment * 16 + Offset

JMP $

%include"utils.asm"

;AppData

txtStr db"Hello Again..",0

txtStr2 db"Loading Kernel",0

txtLaunch db"Launching Kernel",0

times 510-($-$$)db0;Fill the rest of the Loader with "0"

dw0AA55h;Bootloader Signature

Loading from Disk is achieved in lines 11-22. Please read INT 13H documentation to get more details about the "02h" service. In the code above I will read 1 sector from the (virtual) Hard Drive starting from sector #2 cx[5..0], Cylinder 0 cx[15..6], Head #0. It's important to know what this location means in the logical space on Disk; refer to CHS to LBA mapping. Logical space in this code point to the Sector #1 (It's the second sector, having MBR as the first one).

Bootloader will be stored in memory in the location 0x07E0:0x00 just after the location of the MBR. This area of memory is around 480 KB of available space (See Memory Map).

After it has been loaded in the memory, the code will jump to that location in memory and continue executing (line 28).

The following code is an example of our Boot loader. It simply prints "Bootloader Running" if everything is working correctly. There's not much to say other than the data registry (ds) must be reset, otherwise data will point to wrong locations in memory.

BITS 16;Tell compiler that this is 16 Bit code

pushcs;Reset ds

popds

movsi, txtStr

call printTxt

call crlf

JMP $

%include"utils.asm"

;AppData

txtStr db"Bootloader Running!",0

There's no special magic during the assembly step. Files are compiled as in previous posts.

Only one question is left to answer. Where is our Boot loader stored? The answer lies in the line 13 on the first piece of code. Binary file must be stored in Sector 1 of the hard drive. The following instruction will do the job for us:

dd if=test.bin bs=512 of=/dev/sdb seek=1

As usual (It will be usual in the following posts) there are a lot of steps to be done. You can complete them as exercise.

Take proper actions on the result of INT 13h. What if it returns an error?