NASM 简单引导加载程序不会使用 INT 13H 加载扇区

NASM Simple Bootloader won't Load a Sector Using INT 13H

如果我直接从引导扇区 运行 到目前为止,我所做的任何事情都可以正常工作,但就直接从引导扇区加载而言,我无法使任何工作正常进行。我尝试了许多不同的驱动器编号:0x00 --> 0x03、0x80 --> 0x83。此外,这与 ep.4 of Queso Fuego's OSDEV series

基本完全相同
org 0x7c00
bits 16

mov bx, 0x1000
mov es, bx
mov bx, 0x0000

mov dh, 0x00
mov dl, 0x00
mov ch, 0x00
mov cl, 0x02

read_disk:
    mov ah, 0x02
    mov al, 0x01
    int 0x13
    
    jc read_disk

mov ax, 0x1000
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax

jmp 0x1000

times 510-($-$$) db 0

dw 0xaa55

mov ah, 0x00
mov al, 0x01
int 0x10

mov ah, 0x0b
mov bh, 0x00
mov bl, 0x01
int 0x10

mov si, testString
call print_string

hlt

print_string:
    mov ah, 0x0e
    mov bh, 0x00
    mov bl, 0x07

print_char:
    mov al, [si]
    cmp al, 0
    je end_print
    int 0x10
    add si, 1
    jmp print_char

end_print:
    ret

testString: db 'Kernel Booted!', 0xa, 0xd, 0

times 1024-($-$$) db 0

任何建议将不胜感激,我已经坚持了好几天了。 我一直在使用 INT 10H and INT 13H 维基百科页面,认为它们可能有助于了解我正在尝试使用寄存器做什么。提前致谢!

主要问题可能是“jmp 0x1000”,它(取决于 CS 是什么)可能跳转到 0x0000:0x1000(物理地址 0x00001000)但也可能跳转到 0x007C0:0x10000(物理地址 0x00008C00 ) 或者别的地方。您在“0x1000:0x0000”(或物理地址 0x00010000)加载扇区,因此跳转几乎不可能正确。相反,你需要一个像“jmp 0x1000:0x0000”这样的“远跳”来设置 CS 和 IP(而不只是设置 IP 并让 CS 保持 BIOS 的感觉)。

其他问题有:

a) 要使用的正确设备号(在 dl 中,当你要求 BIOS 加载一个扇区时)是 BIOS 告诉你的正确设备号是什么(在 dl 您的代码开始时)

b) BIOS 几乎可以在任何地方留下堆栈 (SS:SP),包括将堆栈留在您在加载扇区时覆盖的同一地址。这意味着加载一个扇区有可能会破坏堆栈(而 BIOS 正在使用它)并导致 BIOS 崩溃。在对任何其他内存执行任何操作之前,您需要将 SS:SP 设置为不会导致问题的内容。请注意,您的代码设置了 SS 而未设置 SP(这也是一个错误)并且为时已晚。

c) 如果像“int 0x13, ah=0x02”这样的 BIOS 函数失败,BIOS 会告诉您一个错误代码(在 ah 中)。使用该错误代码来通知用户出了什么问题是非常重要的,这样他们就可以解决问题(例如,这样他们就可以确定是软件问题还是硬件问题)并且不会被无法解决的计算机卡住t 引导,不知道为什么。这也有助于开发人员(您)发现并修复错误。这意味着使用错误代码查找错误字符串,然后打印错误字符串。不幸的是,不可能在 512 字节中获得良好的错误处理(字符串占用太多 space);但是您可以轻松地在 512 字节中进行“总比没有好”的错误处理(例如,在通用字符串的末尾打印原始十六进制代码,例如“ERROR: Failed to load sector, BIOS error code 0x02”后跟“Boot aborted”)。

d) 软盘是出了名的不可靠;因此标准做法是在您假设错误有效之前重试(至少)3 次,同时要求 BIOS 在(某些)重试之间重置磁盘系统(“int 0x13,ah=0x00”)。

e) hlt 指令不会永远停止 CPU - 它只是要求 CPU 等待直到 IRQ 发生(对于 BIOS,仅来自计时器的 IRQ 通常每秒发生 18.2 次)。这意味着 CPU 不会在您的 hlt 处停止,而是会在 hlt 之后继续执行代码(可能导致您的代码打印随机垃圾然后执行“return到未定义的地址,因为例程没有被正常调用”并且可能会崩溃)。要解决这个问题,请使用循环;比如“.die:”、“hlt”,然后是“jmp .die”。

f) 软盘已经过时了大约 20 年。对于硬盘驱动器,您必须处理某种分区系统,并且您的引导加载程序不会从磁盘的第一个扇区开始。t/can。相反,您的引导加载程序将从分区的第一个扇区开始。

g) BIOS 也应该被认为是过时的(被 UEFI 取代)。即使现在 BIOS 仍然存在于旧计算机上,但是当您写完一个 OS 后,它就不会存在于旧计算机上了。因此,最好了解 UEFI(而不是学习 BIOS)。

注意:如果您使用的是 BIOS,那么最好依靠 Ralph Brown 的中断列表来获取 BIOS 函数的文档。您可以在 http://www.ctyme.com/rbrown.htm (but you'll typically want the table of interrupts at http://www.ctyme.com/intr/int.htm ).

找到它