While writing the below bootloader (with no prior experience in the field), I've encountered many completely different implementations for x86; Now I've been trying to cover all the cases for it to become a "complete" example.
The code below is running as expected (by simply running qemu-systems-x86_64 kern.img), but there's one main thing I still can't completely wrap my head around, and it's what about the stack
- do I need to explicitly define the stack? what happens if I don't? (it's working as is)
- how
call/retinstructions work without defining the stack explicitly, I'm aware that both modify the stack (push/popIP/BP)
Any tips, corrections, or suggestions are welcomed.
org 0x7C00
bits 16
start:
mov ax, cs
mov ds, ax
mov si, title_str
call print_str
mov si, loading_str
call print_str
call load_kernel_to_mem
jmp 0x0900:0x00
load_kernel_to_mem:
mov ax, 0x0900
mov es, ax
mov ah, 0x02 ; read sectors from disk into mem
mov al, 0x01 ; sectors to read count
mov ch, 0x00 ; track
mov cl, 0x02 ; sector
mov dh, 0x00 ; head
mov dl, 0x80 ; disk type 1st hard disk
mov bx, 0x00 ; ES:BX buffer address pointer (bx=offset)
int 0x13 ; CF=0 on success, otherwise CF=1 AX=errno
jc handle_load_err ; handle error if CF=1
ret
handle_load_err:
mov si, load_error_str
call print_str
hlt ; stop cpu from executing further instruction (breaks on interrupts)
print_str:
mov ah, 0x0E ; teletype output
.loop lodsb ; load byte from si to al then advance si
cmp al, 0 ; cmp loaded byte to 0
je finished_printing ; jmp if curr byte is 0
int 0x10 ; print byte to screen
jmp .loop
finished_printing:
mov al, 10d ; print new line
int 0x10
mov ah, 0x03 ; get cursor position and shape
mov bh, 0 ; page number
int 0x10
mov ah, 0x02 ; set cursor position
mov dl, 0 ; col 0
int 0x10
ret
title_str db "Bootloader", 0
loading_str db "Loading...", 0
load_error_str db "Failed to load", 0
times 510 - ($ - $$) db 0
dw 0xAA55