Reputation: 604
I am trying to make a very basic 2 stage boot loader and I am running into issues reading the second stage. When I try to use int 13h
with ah = 2
, The interrupt fails with return code 1 (Invalid Command). I am compiling with nasm and testing with qemu. I have been testing to see if it has worked using qemu's console to check address 0x8C00
and see ax
and the carry flag. I always see that the memory around 0x8C00
is zeroed, ax = 0x0101
and the carry flag is set.
bootloader.s
[org 0x7c00]
[bits 16]
mov [driveNum], dl
mov ah, 0x0A
mov al, '-'
mov cx, 80
int 0x10
;read drive
mov ax, 0
mov es, ax
mov ah, 2
mov al, 1 ;sectors to read
mov ch, 0 ;cylinder
mov cl, 0 ;sector
mov dh, 0 ;head
mov dl, byte [driveNum] ; drive
mov bx, 0x8c00
int 13h
hang:
jmp $
driveNum: db 0xAA
times (510 - ($ - $$)) db 0
db 0x55
db 0xAA
secondstage.s
jmp $
times 512 db 0xFF
Compiled With
nasm -f bin bootloader.s -o bootloader
nasm -f bin secondstage.s -o secondstage
cat bootloader secondstage > boot
Run Using
qemu-system-x86_64 -fda boot
Upvotes: 1
Views: 382
Reputation: 39166
BIOS returns with the "Invalid Command" error because you've asked to load the non-existent disk sector 0. In the CHS notation Cylinder numbers start at 0, Head numbers start at 0, but Sector numbers start at 1.
The sector that contains your bootloader is at (0,0,1). If your secondstage is in the next higher sector (but it could be anywhere else if you chose so!) then you need to ask for sector (0,0,2).
mov cx, 0002h ;Cylinder 0, Sector 2
Your dangerously working with the assumption that the DS
segment register points to your bootloader. You cannot trust BIOS in this respect! The only thing that you can assume is that your bootloader sits in memory at linear address 0000h:7C00h and that the DL
register holds the code for the boot drive.
Because you wrote [org 0x7c00]
the setup that is missing is setting DS=0
xor ax, ax <<===
mov ds, ax <<===
mov [driveNum], dl
The video BIOS function "WriteCharacterAtCursorPosition" additionally requires a display page number in BH
and if the video mode is a graphical one then also a color in BL
. Please don't rely on any register contents that you didn't check. All it takes is writing:
mov ax, 0A00h + '-'
mov bx, 0007h <<===
mov cx, 80
int 10h
jmp $ times 512 db 0xFF
This creates 514 bytes which is 2 bytes more than a complete sector. Your bootloader will read 1 sector of 512 bytes. Technically there's no error here, but it might be indicative for some misconception.
jmp $
times (512 - ($ - $$)) db 255
Upvotes: 2