如何解决BIOS int 13 中的“无效命令错误代码 0x01”是什么意思
我正在和我的一个朋友一起开发一个简单的引导加载程序,并没有伪装成任何可用的东西。在编写了屏幕输入和输出函数之后,我们继续编写从磁盘读取扇区的函数,这就是第一个问题出现的地方。我声明在 qemu 和 bochs 上一切正常。对于物理硬件,我不能说同样的事情,在那里我遇到错误 0x0001,这意味着 Invalid Command。
但是,我没有找到有关此错误的太多信息。在我看来,这可能意味着我弄错了一些论点,但我在屏幕上打印了所有日志,但没有发现任何奇怪的值可以证明这种行为是正确的。
我从闪存驱动器启动。我认为这也可能是一个问题(因为它不是真正的软盘),但是如果 BIOS 可以加载引导扇区,那么加载下一个扇区也应该没有问题。
read_sector:
start_f
pusha
mov (drive_number),%dl # drive number is stored from the main function into a global variable
mov $0x03,%si # try three times
1:
mov $0x0201,%ax
int $disk_int
jnc end
dec %si
jz 2f
xor %ah,%ah
int $disk_int
jmp 1b
2:
movzx %ah,%dx
call printh # print error code
end:
popa
end_f
这里是调用函数(dl = 0):
# ...
mov $0x0002,%cx
xor %dh,%dh
mov $0x7e00,%bx
call read_sector
# ...
我们可能做错了什么?
解决方法
这里的问题在于文件 init.s
。在初始化代码段之前,我将一个值放入 drive_number
。
CPU 如何计算物理地址
real mode memory segmentation。
当我将此列表翻译成机器语言时,链接器通过引用它所在部分的开头来计算 drive_number
的地址(在本例中为 .text
部分,它开始于地址 7c00
,如链接描述文件中所指定):
.text 0x7c00 :
{
*(.text);
}
这意味着指令 mov $0,(drive_number)
被翻译成 mov $0,7c2e
。然而,这不是一个实际的物理地址,而只是一个偏移量。
在实模式下,物理地址是通过将移位 4 位(相当于乘以 16)的特定段寄存器中的值与偏移量相加(如本例中的 {{1} })。我们经常看到符号 7c2e
表示地址 AAAA:BBBB
。为了确定用于读取或写入某种数据的内存中某个位置的物理地址,默认情况下 CPU 会利用存储在数据段寄存器 AAAA * 16 + BBBB
中的值。这意味着我们存储数据的实际地址确实是 %ds
。
当 BIOS 跳转到引导扇区中编写的代码时,它不能向我们保证段寄存器中的值就是我们想要的值。因此,在每个程序开始时,我们必须初始化这些寄存器以包含我们需要的值。如果 ds * 16 + drive_number
不为零,则 %ds
初始化为零后,drive_number
对应的物理地址将不相同,这意味着该标签指向不同的位置内存取决于 %ds
中包含的值。
BIOS 告诉我们从哪个驱动器启动
BIOS 中断 %ds
要求 dl 包含指示我们应该从哪个驱动器读取的代码。但是,无需逐个查阅手册以从我们正在启动的驱动器中读取文本:实际上,BIOS 在跳转到 {{1} 之前将与我们正在启动的驱动器对应的值放在 13,2
中并开始执行引导扇区中的代码。
使用 %dl
中 BIOS 传递的代码使代码更加可靠和健壮。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。