微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

BIOS int 13 中的“无效命令错误代码 0x01”是什么意思

如何解决BIOS int 13 中的“无效命令错误代码 0x01”是什么意思

我正在和我的一个朋友一起开发一个简单的引导加载程序,并没有伪装成任何可用的东西。在编写了屏幕输入和输出函数之后,我们继续编写从磁盘读取扇区的函数,这就是第一个问题出现的地方。我声明在 qemu 和 bochs 上一切正常。对于物理硬件,我不能说同样的事情,在那里我遇到错误 0x0001,这意味着 Invalid Command

但是,我没有找到有关此错误的太多信息。在我看来,这可能意味着我弄错了一些论点,但我在屏幕上打印了所有日志,但没有发现任何奇怪的值可以证明这种行为是正确的。

我从闪存驱动器启动。我认为这也可能是一个问题(因为它不是真正的软盘),但是如果 BIOS 可以加载引导扇区,那么加载下一个扇区也应该没有问题。

然而,这里是 read_sector 函数代码

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 举报,一经查实,本站将立刻删除。