Creating A X86 Bootloader From Scratch
What is a bootloader?
A bootloader is a piece of software responsible for booting a computer. When a computer is powered on, it typically does not have an operating system loaded in RAM. A bootloader is software that starts the loading of the operating system (OS) into RAM.
When the computer boots up, the first thing that happens is the operation of the BIOS. The BIOS then runs a power on self-test to check that devices the computer relies on are functioning properly. If all the devices are functioning properly, BIOS then goes through the configured boot sequence searching for a bootable device. BIOS deems a device as bootable when the first 512 bytes of a device are readable and end in the exact bytes 0x55AA. Ox55AA is a magic number marking a boot sector as bootable. The first block of the bootable medium is where the bootloader is stored. Once a bootable device is found, BIOS loads the first 512 bytes of the drive into memory address 0x7C00, and transfers program control to this address with a jump instruction to the processor.
The language mostly used to write bootloaders is Assembly Language. I used NASM assembler in this project, so go ahead and download the NASM assembler if you haven’t done that already. NASM can be downloaded from https://www.nasm.us/. Now that you have NASM downloaded and installed, let’s get started writing our bootloader.
The bootloader being created in this article is a simple bootloader, it does nothing more than print a message ‘Hello, there!’ out to the screen.
bits 16 ; tell NASM to use 16 bits, at this point computer is running in 16 bit real mode
org 0x7C00 ; set the start address for this code
mov si, message ; point SI register to ‘message’ label memory location
mov ah, 0x0e ; set higher bits to the display character command 'Writing in TTY Mode'
lodsb ; loads the current byte from SI into AL and increments the address in SI
cmp al, 0 ; compares AL to zero (null byte)
je _stop ; if AL == 0, end of string, jump to '_stop'
int 0x10 ; runs BIOS interrupt 0x10 - video services
jmp .loop ; repeat with next byte
hlt ; stop execution
db "Hello, there!", 0 ; 0 (string terminator)
times 510-($-$$) db 0 ; pad remaining 510 bytes with zeroes
dw 0xAA55 ; magic number - marks this 512 byte sector bootable!
Assembling and testing our bootloader
Let's save the code above as boot.asm and assemble it using this command:
nasm -f bin boot.asm -o boot.bin
We can now run our bootloader using an emulator by issuing the following command, considering we already have QEMU installed on our machines, and if not you can download the emulator here https://www.qemu.org/, QEMU is a generic and open source machine emulator and virtualizer. We are not going to be using a real machine, just an emulator instead.
Now run qemu-system-x86_64 -fda boot.bin
After that command runs without errors we should see a message, 'Hello, there!' on the screen. That's it! To learn more about Assembly Language, visit https://dragonzap.com/course/x86-assembly-language.
You can learn how to create a 32-bit kernel here: https://dragonzap.com/course/developing-a-multithreaded-kernel-from-scratch