BootLoader and OS
1 Bootloader
1.1 Summary
- BIOS reads first 512 bytes
- Check for magic 2-byte at end
- Loads the 512 bytes
1.2 Theory
- The 512 bytes is in the first boot sector of the bootable drive.
- The magic 2-bytes is
0x55 0xaa
00 00 00 00 00 00 00 00 00 00 00 00 00
e9 fd ff
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00-bytes each ]
[ 29 more lines with sixteen zero 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa
1.3 Implement
Using nasm x86 asm
sudo apt install nasm
sudo apt-get install qemu-system
nasm -fbin boot.asm -o boot.bin
qemu-system-x86_64 -nographic boot.bin
Zero out 510 bytes, then add the 2-byte bootloader identifier 0x55 0xaa
jmp $
times 510-($-$$) db 0
db 0x55, 0xaa
Booting from Hard Disk...
jmp $
means jump back to this line AKA infinite loop.
single dollar = current address
double dollar = section start
(\$-\$\$)
= (current addr - section start) = length of previous code
db := define byte
db 0x55, 0xaa
is equivalent to dw 0xaa55
510 - length of previous code = allows us to fill the memory to 510 bytes
BIOS (vs UEFI)
Boot into the bootsector we enter into “REAL MODE”.
“REAL MODE” is a 16 bit mode assisted by BIOS.
- Switch to teletype mode by modifying a register then calling a BIOS interrupt
mov ah, 0x0e
mov al, 'A'
int 0x10
Printing ‘A’s. ’A’ = 65 in dec = 0x41 in hex = 0b1000001 in binary(0b means binary)
mov ah, 0x0e
mov al, 'A'
int 0x10
mov ah, 0x0e
mov al, 65
int 0x10
mov ah, 0x0e
mov al, 0x41
int 0x10
mov ah, 0x0e
mov al, 0b1000001
int 0x10
2 Disks
Memory is divided into 512 chunks.
Cylinder = [0..) Head = [0..) Sector = [1..)
The location of each 512 chunk of memory on a disk is determined by
(Cylinder,Head,Sector)
The first chunk of memory = “Boot Sector” at (C=0,H=0,S=1)
2.0.1 OS
We need to write a bootloader.
To compiler
3 Diassembly
Here you can see a diasssembler used against boot.bin with “x86 Real mode 16 bit” since when we compiled boot.bin, our nasm compiler defaults to x86 16 bit real mode Note: press D to decompile

0x7C00 ;this puts 0x7C at 00000024 if you open the *.bin
org 16 ;BIOS boots the bootloader into 16 bit realmode
bits
%define ENDL 0x0D, 0x0A
:
start
jmp main
:
puts;save register we will modify
push si
push ax
push bx
.loop:
; loads a byte in the al register, then increments si
lodsb , al
or al.done
jz
, 0x0e
mov ah, 0
mov bhint 0x10
.loop
jmp
.done:
pop bx
pop ax
pop si
ret
:
main;;GoodToKnow: segment registers are cs, ss, ds, es, fs, gs
;;cs = currently running code segment
;;ds = data segment
;;es,fs,gs = (extra) data segment
;;ss = stack segment
;setup data segment
, 0
mov ax, ax ;;segment register ds
mov ds, ax ;;segment register es
mov es
;setup stack segment
, ax ;;segment register ss
mov ss, 0x7C00 ;;pointer register sp
mov sp
;print message
, msg_hello
mov si
call puts
hlt
: db "hello World", ENDL, 0
msg_hello
;bootloader is the first 512 bytes and
;the last 0x55 0xaa tells the BIOS it is the bootloader
510-($-$$) db 0
times 0x55, 0xaa db