【发布时间】:2020-01-03 22:27:07
【问题描述】:
我正在编写一个简单的操作系统,但在从磁盘读取时遇到了很多问题。我使用 int 0x13 和 ah=0x02 从驱动器读取数据,我收到了几个不同的错误消息。当我跑步时
$ qemu-system-x86_64 -drive file=os.bin,if=floppy,index=0,media=disk,format=raw
效果很好。当我这样做时
$ qemu-system-x86_64 -drive file=os.bin,format=raw
进位标志已设置,ah 为 0x20。根据http://www.ctyme.com/intr/rb-0606.htm#Table234,这是一个“控制器故障”错误。这没有多大意义,因为它是在虚拟机中运行的,所以我很确定是我的代码错了。
当我将启动映像写入磁盘(dd 到闪存驱动器上的分区)时,它会启动并成功启动我的程序,但在相同的磁盘加载时失败,ah 为 0x01。同一个站点说这是“AH 中的无效函数或无效参数”错误,这进一步证实了问题出在我的代码中。我不得不拼凑一个糟糕的 print_hex 解决方案,它可以打印出很多个 X,因为我没有动力去拼凑更好的东西。
这是我的 load_disk.asm 文件:
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
我已经截断了我的字符串,以便在 512 字节中为调试代码腾出空间。这段代码是从boot.asm调用的,就是
[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
我一直在寻找 https://www.cs.bham.ac.uk/~exr/lectures/opsys/10_11/lectures/os-dev.pdf 作为这个项目的基础。但是,它假定为软盘,因此在这种情况下它的帮助有限。
编辑:我以为我得到了所有相关文件,但似乎我没有:(
这里是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
在评论提到它之后,我向该文件添加了 push dx/pop dx。 ah 现在是 12 或 0x0C,即“不支持的轨道或无效媒体”。
有可能是硬盘驱动器的结构或其他问题。我正在使用cat 来组装我的最终 os.bin 文件,这对我来说没有多大意义。这是我的 Makefile 行(如果有帮助,我可以发布整个 makefile)
os.bin : build/boot.bin build/kernal.bin
cat build/boot.bin build/kernal.bin > $@
build/boot.bin 是我在前 512 个字节中加载的所有程序集。 kernal.bin 是我应该从磁盘加载的 C 代码
【问题讨论】:
-
请发布您的完整代码。例如,我看不到您的
print_string例程是否会破坏dl。 -
@fuz 编辑了额外的细节。我现在将尝试使用该编辑从闪存驱动器启动。
-
我很好奇你用来写入 USB 驱动器的 DD 命令到底是什么。
-
不幸的是,我还没来得及做这件事,就离开了周末。您的回答看起来很棒,并且可能解决了我遇到的所有主要问题,非常感谢。我会及时通知你。
标签: assembly x86 x86-16 bootloader osdev