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
/ret
instructions 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