BootLoader and OS

Posted on July 2, 2014
Tags: operatingsys
graph TD; A["Stack"] --> B["Heap"] B-->C[.bss \nUninitialized Data\n Global variables \n int a;] C-->D[.data \nInitialized Data\n Global variables assigned content\n int a=9;] D-->E[".text \n User's functions and local variable inside these functions \n int main(){..}"]

1 Bootloader

1.1 Summary

  1. BIOS reads first 512 bytes
  2. Check for magic 2-byte at end
  3. 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
e9 fd ff 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[ 29 more lines with sixteen zero-bytes each ]
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.

  1. 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

png
org 0x7C00 ;this puts 0x7C at 00000024 if you open the *.bin
bits 16 ;BIOS boots the bootloader into 16 bit realmode

%define ENDL 0x0D, 0x0A

start:
    jmp main

puts:
    ;save register we will modify
    push si
    push ax
    push bx

.loop:
    lodsb ; loads a byte in the al register, then increments si
    or al, al 
    jz .done 
    

    mov ah, 0x0e
    mov bh, 0
    int 0x10

    jmp .loop 

.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
    mov ax, 0
    mov ds, ax ;;segment register ds
    mov es, ax ;;segment register es

    ;setup stack segment
    mov ss, ax ;;segment register ss
    mov sp, 0x7C00 ;;pointer register sp

    ;print message
    mov si, msg_hello
    call puts

    hlt

msg_hello: db "hello World", ENDL, 0

;bootloader is the first 512 bytes and 
;the last 0x55 0xaa tells the BIOS it is the bootloader 
times 510-($-$$) db 0
db 0x55, 0xaa