我正在按照这个教程构建一个简单的操作系统。我的问题是它调用磁盘加载函数,当我启动它时,它给我一个磁盘读取错误。这是我的 boot_sect.asm 代码:
[org 0x7c00]
KERNEL_OFFSET equ 0x1000
mov [BOOT_DRIVE], dl
mov bp, 0x9000
mov sp, bp
mov bx, MSG_REAL_MODE
call print_string
call load_kernel
mov bx, MSG_LOAD_KERNEL
call print_string
call switch_to_pm
jmp $
%include "print_string.asm"
%include "disk_load.asm"
%include "gdt.asm"
%include "print_string_pm.asm"
%include "switch_to_pm.asm"
[bits 16]
load_kernel:
mov bx, MSG_LOAD_KERNEL
call print_string
mov bx, KERNEL_OFFSET
mov dh, 15
mov dl, [BOOT_DRIVE]
call disk_load
ret
[bits 32]
BEGIN_PM:
mov ebx, MSG_PROT_MODE
call print_string_pm
call KERNEL_OFFSET
jmp $
BOOT_DRIVE db 0
MSG_REAL_MODE db "Started in 16-bit Real Mode", 0
MSG_PROT_MODE db "Successfully landed in 32-bit Protected Mode", 0
MSG_LOAD_KERNEL db "Loading kernel into memory", 0
; Padding
times 510-($-$$) db 0
dw 0xaa55
和我的disk_load.asm:
; load DH sectors to ES:BX from drive DL
disk_load :
push dx ; Store DX on stack so later we can recall
; how many sectors were request to be read ,
; even if it is altered in the meantime
mov ah, 0x02 ; BIOS read sector function
mov al, dh ; Read DH sectors
mov ch, 0x00 ; Select cylinder 0
mov dh, 0x00 ; Select head 0
mov cl, 0x02 ; Start reading from second sector ( i.e.
; after the boot sector )
int 0x13; BIOS interrupt
jc disk_error ; Jump if error ( i.e. carry flag set )
pop dx ; Restore DX from the stack
cmp dh, al ; if AL ( sectors read ) != DH ( sectors expected )
jne disk_error2 ; display error message
ret
disk_error :
mov bx , DISK_ERROR_MSG
call print_string
jmp $
disk_error2 :
mov bx , DISK_ERROR_MSG2
call print_string
jmp $
; Variables
DISK_ERROR_MSG db " Disk read error 1 !" , 0
DISK_ERROR_MSG2 db " Disk read error 2 !" , 0
这篇文章说我可能需要
es
为零,但是当我把
xor bx, bx
mov es, bx
在
int 0x13
之上,它只是在中断时挂起。我该如何解决这个问题?
编辑
在这个例子中,我让它在中断后显示
hello
,但是,除非我删除xor bx, bx mov es, bx
,否则它不会显示它,所以这就是为什么我认为它卡在那里:
; load DH sectors to ES:BX from drive DL
disk_load :
push dx ; Store DX on stack so later we can recall
; how many sectors were request to be read ,
; even if it is altered in the meantime
mov ah, 0x02 ; BIOS read sector function
mov al, dh ; Read DH sectors
mov ch, 0x00 ; Select cylinder 0
mov dh, 0x00 ; Select head 0
mov cl, 0x02 ; Start reading from second sector ( i.e.
; after the boot sector )
xor bx, bx
mov es, bx
int 0x13; BIOS interrupt
mov bx, message ; This should print `hello` after the interrrupt
call print_string ;
jc disk_error ; Jump if error ( i.e. carry flag set )
pop dx ; Restore DX from the stack
cmp dh, al ; if AL ( sectors read ) != DH ( sectors expected )
jne disk_error2 ; display error message
ret
. . .
当我启动它时,它给我一个磁盘读取错误。
每当返回时设置进位标志时,向我们展示 BIOS 在 AH 寄存器中返回的实际 状态字节 将是最有用的!
请阅读将扇区加载到内存时出现磁盘读取错误以获取解释和工作代码。
[org 0x7c00] KERNEL_OFFSET equ 0x1000 mov [BOOT_DRIVE], dl mov bp, 0x9000 mov sp, bp
当 BIOS 将引导加载程序放入内存时,您唯一可以确定的寄存器是 DL,它保存着 driveID。由于段寄存器在实模式编程中非常重要,因此您必须正确设置它们。根据您的
[org 0x7c00]
,接下来是您必须写的:
[org 0x7C00]
KERNEL_OFFSET equ 0x1000
xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax ; Keep these two together and
mov sp, 0x9000 ; very importantly in this order
mov [BOOT_DRIVE], dl
我建议您将当前的 disk_load 过程替换为我提供链接的答案中的过程。确保正确调用它。
int 0x13; BIOS interrupt mov bx, message ; This should print `hello` after the interrrupt call print_string ; jc disk_error ; Jump if error ( i.e. carry flag set )
在屏幕上显示临时消息是一种很好的调试技术,但不要忘记print_string过程将破坏从BIOS.ReadSectors函数02h获得的进位标志。
要成功检查进位标志,请使用
pushf
和 popf
,如下所示:
mov ah, 02h ; BIOS.ReadSectors
int 0x13
pushf
mov bx, message
call print_string
popf
jc disk_error ; Jump if error ( i.e. carry flag set )
这将保留堆栈上的进位标志。如果您不能确定 print_string 已保留 AX,则以相同的方式在此处保留 AX...