I'm writing a simple operating system and I'm having a lot of problems with reading from the disk. I use int 0x13 and ah=0x02 to read data from the drive and I've been getting several different error messages. When I run with
$ qemu-system-x86_64 -drive file=os.bin,if=floppy,index=0,media=disk,format=raw
it works great. When I do
$ qemu-system-x86_64 -drive file=os.bin,format=raw
the carry flag is set and ah is 0x20. According to http://www.ctyme.com/intr/rb-0606.htm#Table234, it's a "controller failure" error. This doesn't make much sense, as it's running in a vm, so I'm pretty sure that it's my code that is wrong.
When I write my boot image to a disk (dd to a partition on a flashdrive) it boots and successfully starts my program but fails at the same disk load, with ah being 0x01. The same site says that this is a "invalid function in AH or invalid parameter" error, which further confirms that the problem is in my code. I've had to throw together a poor print_hex solution that prints ah number of X's, because I haven't had the motivation to put something better together.
Here is my load_disk.asm file:
disk_load:
pusha
push bx
mov bx, DISK_START
call print_string
pop bx
push dx
mov ah, 0x02
mov al, dh
mov cl, 0x02
mov ch, 0x00
mov dh, 0x00
int 0x13
jc disk_error0
pop dx
cmp dh, al
jne disk_error1
push bx
mov bx, DISK_SUCC
call print_string
pop bx
popa
ret
disk_error0:
loopY:
cmp ah, 0x0
je cont
mov bx, STARTING_DISK_ERROR
call print_string
sub ah, 1
jmp loopY
cont:
; print a nice little counter
mov bx,NEWLINE
call print_string
mov ah,8 ; 80 character screen, 10 characters
loopS:
cmp ah,0x0
je cont2
mov bx, NUMBERS
call print_string
sub ah, 1
jmp loopS
cont2:
mov bx,NEWLINE
call print_string
mov bx, DISK_ERROR_0
call print_string
jmp $
disk_error1:
mov bx, DISK_ERROR_1
call print_string
jmp $
STARTING_DISK_ERROR : db "X",0
NEWLINE: db 10,13,0
NUMBERS: db "1234567890",0
DISK_ERROR_0 : db "Error0",10,13, 0
DISK_ERROR_1 : db "Error1",10,13, 0
DISK_START : db "Startingdisk", 10,13, 0
DISK_SUCC : db "Loadeddisk", 10,13,0
I've truncated my strings to make room in the 512 bytes for debug code. This code is called from boot.asm, which is
[bits 16]
[org 0x7c00]
jmp 0x0000:main_entry ; ensures cs = 0x0000
main_entry:
xor ax, ax
mov ds, ax
mov es, ax
KERNAL_OFFSET equ 0x1000
mov [BOOT_DRIVE], dl
mov bp, 0x9000
mov sp, bp
mov bx, MSG_REAL_MODE
call print_string
call load_kernal
call switch_to_pm
;this line will never execute
jmp $
%include "src/print_string.asm"
%include "src/disk_load.asm"
%include "src/gdt.asm"
%include "src/print_string_pm.asm"
%include "src/switch_to_pm.asm"
%include "src/print_hex.asm" ; this is broken, don't use
[bits 16]
load_kernal:
mov bx, MSG_LOAD_KERNAL
call print_string
mov bx, KERNAL_OFFSET
mov dh, 31 ; load 31 sectors. gives plenty of room
mov dl, [BOOT_DRIVE]
call disk_load
; mov bx, MSG_LOAD_DISK
; call print_string
ret
[bits 32]
BEGIN_PM:
mov ebx, MSG_PROT_MODE
call print_string_pm
call KERNAL_OFFSET
mov ebx, 0x5000
call print_string_pm
jmp $ ; if the kernal returns, stay here
BOOT_DRIVE db 0
MSG_REAL_MODE db "Started in 16-bit", 10, 13, 0
MSG_PROT_MODE db "Sted in 32-bit", 0
;MSG_SHOULD_NEVER_PRINT db "Frack",10,13, 0
MSG_LOAD_KERNAL db "Loding kernal",10,13, 0
;MSG_LOAD_DISK db "Loaded disk!", 10,13,0
MSG_KERNAL_EXIT db "kernal has exited",10,13,0
times 510-($-$$) db 0
dw 0xaa55
I've been looking through https://www.cs.bham.ac.uk/~exr/lectures/opsys/10_11/lectures/os-dev.pdf as my foundation for this project. However, it assumes a floppy disk, so it is of limited help in this situation.
Edit: I thought I got all the relevant files, and it appears I didn't :(
Here's print_string.asm
:
; prints the string at location BX
print_string:
push ax
push bx
push dx ; NEW
mov ah, 0x0e
loop1:
mov al, [bx]
int 0x10
add bx, 1
mov dl, [bx]
cmp dl, 0x0
jne loop1
pop dx ; NEW
pop bx
pop ax
ret
After a comment mentioned it, I added a push dx/pop dx to that file. ah
is now 12, or 0x0C, which is "unsupported track or invalid media".
There's a chance that it's an issue with how hard drives are structured or something. I'm using cat
to assemble my final os.bin file, which doesn't make that much sense to me. Here's my Makefile line (I can post the entire makefile if that would be helpful)
os.bin : build/boot.bin build/kernal.bin
cat build/boot.bin build/kernal.bin > $@
build/boot.bin is all of my assembly that is loaded in the first 512 bytes. kernal.bin is my C code that I should be loading from the disk