Custom Master Boot Record [MBR]

15 Aug 2013

Sometimes it's fun to dig into some technical topic as low as you can. In this note I'll talk about some experiments with creating software that runs right after the BIOS has done it's job.

Master Boot Record

The Master Boot Record or mbr is a 512 byte file which is loaded by the BIOS right after your computer boots up. The BIOS searches for this file in configured locations, it can be a harddisk, floppy disk, usb drive or a cd/dvd. The file is loaded by your machine into physical memory at offset 0x7c00 and then the CPU starts executing the instructions in that file.

The mbr often does boring things like finding partition tables, locating disks and loading and calling other bootloaders. However since this is just code then we can build our own master boot record that does just what we need.

Our computers are made for just burning through instructions one at a time and I wish there was a bootloader which just used these cycles to do nothing at all. So let's create one of those.

The first thing we need to know is how do we program these bootloaders. Well it turns out that when an ordinary PC boots up, it is as dumb as sheep. The BIOS sets the CPU into something called "real mode" which means that the CPU is executing 16bit 8086 instructions. It also means that the CPU is doing segmented adressing so we have to use segment registers to get at certain memory locations. It should really be called "old mode"

So since there are no modern compilers which will produce this old style binaries then we will use an assembler and we will be programming in assembler language. The good stuff. I will be using the nasm assembler for these experiments.

[bits 16]
[org 0x7C00]

jmp $

times 510 - ($ - $$) db 0
dw 0xAA55

This is it... This is the source code for a mbr bootloader which does absolutly nothing. We can compile and test it with the following Makefile.

boot.bin: bootloader.asm
    nasm $^ -f bin -o $@

test: boot.bin
    qemu-system-i386 -hda boot.bin

The source code is small and delicious, first we say to nasm that it should produce 16 bit code. Then we say that the code is going to be loaded into address offset 0x7C00. Next we have one x86 instruction which says "jump to the current location". Then we fill the rest of the file with 0 and end with the two magic bytes 0xAA55. The last two bytes are a signature that tells the BIOS that this is in fact a bootloader.

Running the previous code a few times is fun, but we need something more to keep the bootloader interresting. So we will produce some code to write a string to the screen.

[bits 16]
[org 0x7c00]

    mov si, my_string
    call print_string
    jmp loop

    mov ah, 0x0e
    mov bh, 0x00
    mov bl, 0x07

    int 0x10

    mov al, [si]
    inc si
    or al, al
    jz exit_function
    call print_char
    jmp next_char

my_string db 'all work and no play', 0

times 510 - ($ - $$) db 0
dw 0xaa55

Awsome, now we have something to show off. If you are more of the colorful type then we can create another bootloader which shows colors on the screen.

[bits 16]
[org 0x7c00]

    ;; Call VideoService interrupt 0x10
    ;; ah = 0x00 -> SetVideoMode
    ;; al = 0x13 -> 320x200 16 color
    mov ah, 0x00
    mov al, 0x13
    int 0x10

    ;; Setup registers to point to video address 
    ;;   es:di = 0xa000:0x0000
    mov ax, 0xa000
    mov es, ax
    xor di, di

    ;; Fill screen with color from al register
    ;; it will start with color 0x00
    mov cx, 0x0000
    mov byte [es:di], al
    inc di
    cmp di, 0xffff
    jnz .loop

    ;; Increment color
    inc al

    ;; Set data register to 0 for beginning of video address
    xor di, di
    jmp .loop

times 510 - ($ - $$) db 0
dw 0xaa55

Now I'm happy with my new bootloader. It does what it's supposed to do, be a colorful addition to my workplace.

For more information on master boot records take a look at osdev. The osdev site is a good source for juicy details on operating systems and other low level fruits.