I currently have a basic bootloader setup to load my kernel with some debug statements:
; Set offsets
[org 0x7c00]
KERNEL_OFFSET equ 0x2000
[bits 16]
; Setup Stack
mov bp, 0x1000
mov sp, bp
mov bx, RM_BOOT_MSG
call print_rm
call nl_rm
; Load kernel
mov bx, KERNEL_OFFSET ; Read from disk and store in KERNEL_OFFSET
mov dh, 10 ; Read X sectors
call load_disk
mov bx, KERNEL_LOAD_MSG
call print_rm
call nl_rm
mov bx, KERNEL_OFFSET
call print_rm_hex
call nl_rm
mov bx, [KERNEL_OFFSET]
call print_rm_hex
call nl_rm
mov bh, 0
mov bl, dl
call print_rm_hex
call nl_rm
call KERNEL_OFFSET ; Begin entering kernel
jmp $
%include "boot/disk.asm"
%include "boot/32b_gdt.asm"
RM_BOOT_MSG: dw "16-bit RM", 0
KERNEL_LOAD_MSG: dw "Kernel Successfully Loaded", 0
; Padding
times 510 - ($ - $$) db 0
dw 0xaa55
Here is my load_disk function:
; Disk
; See this for all int 0x13 notes: https://stanislavs.org/helppc/int_13-2.html
; AH = 02
; AL = number of sectors to read (1-128 dec.)
; CH = track/cylinder number (0-1023 dec., see below)
; CL = sector number (1-17 dec.)
; DH = head number (0-15 dec.)
; DL = drive number (0=A:, 1=2nd floppy, 80h=drive 0, 81h=drive 1)
; ES:BX = pointer to buffer
; on return:
; AH = status (see INT 13,STATUS)
; AL = number of sectors read
; CF = 0 if successful
; = 1 if error
; Note 0x01 is the boot sector, 0x02 is the first free one
[bits 16]
; Load "dh" sectors for drive "dl" at es:bx
load_disk:
pusha
push dx
mov ah, 0x02
mov al, dh
mov ch, 0x00
mov cl, 0x02
mov dh, 0x00
int 0x13
jc .disk_error
pop dx
cmp al, dh
jne .sector_error
popa
ret
.disk_error:
mov bx, DISK_ERR_MSG
call print_rm
mov dh, ah
call print_rm_hex
call nl_rm
jmp .fail_loop
.sector_error:
mov bx, SECTOR_ERR_MSG
call print_rm
call nl_rm
.fail_loop:
jmp $
DISK_ERR_MSG: dw "Error loading from disk: ", 0
SECTOR_ERR_MSG: dw "Incorrect number of sectors read", 0
%include "boot/print_rm.asm"
When run via qemu-system-i386 -s -usb -drive format=raw,file=\\.\PHYSICALDRIVE2
, it works as expected with no errors, specifically outputting
Kernel Successfully Loaded
0x2000 (the Kernel offset)
0xC6BB (what is stored at 0x2000)
0x0080 (the drive)
On hardware, it instead outputs:
Kernel Successfully Loaded
0x2000 (the Kernel offset)
0x519B (what is stored at 0x2000)
0x0080 (the drive)
I.e. it fails to load the correct data, causing call KERNEL_OFFSET
to fail (it may be noted that when call load_disk
is commented out, it still prints 0x519B as the data stored at 0x2000).
Any suggestions on how to resolve this difference between QEMU and hardware would be greatly appreciated.
As noted by Michael Petch, this is resolved by ensuring relevant segment registers are set to 0
mov ax, 0
mov ds, ax
mov ss, ax
mov es, ax
mov fs, ax
mov gs, ax