assembly - BIOS int 13中的 "invalid command (error code 0x01)"是什么意思

标签 assembly x86-16 att bios real-mode

我正在和我的一个 friend 一起开发一个简单的引导加载程序,并没有假装它会成为任何可用的东西。编写完屏幕输入和输出函数后,我们继续编写从磁盘读取扇区的函数,这就是出现第一个问题的地方。我声明在 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 相同)的值与偏移量相加(如本例中的 7c2e )来计算物理地址。 。我们经常看到符号 AAAA:BBBB表示地址AAAA * 16 + BBBB 。为了确定内存中用于读取或写入某种数据的位置的物理地址,CPU 默认情况下利用存储在数据段寄存器 %ds 中的值。 。这意味着我们存储数据的实际地址确实是 ds * 16 + drive_number .

当 BIOS 跳转到引导扇区中写入的代码时,它不能向我们保证段寄存器中的值就是我们想要的值。因此,在每个程序开始时,我们必须初始化这些寄存器以包含我们需要的值。如果%ds不为零,对应drive_number的物理地址%ds初始化后就不一样了为零,这意味着该标签根据 %ds 中包含的值指向内存中的不同位置。 .

BIOS 告诉我们从哪个驱动器启动

BIOS中断13, 2要求 dl 包含指示我们应该从哪个驱动器读取的代码。然而,无需查阅一本又一本的手册来从我们启动的驱动器中读取文本:事实上,BIOS 位于 %dl 中。与我们在跳转到 07c0:0000 之前启动的驱动器相对应的值并开始执行引导扇区中的代码。 使用%dl中BIOS传递的代码使代码更加可靠和健壮。

关于assembly - BIOS int 13中的 "invalid command (error code 0x01)"是什么意思,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67608079/

相关文章:

assembly - 当中断发生时,x86 架构中会发生什么?

c - 如何在内联汇编中使用 C 中声明的变量

assembly - 如何在汇编中弹跳字符

assembly - 为什么 `cmpsb`似乎没有比较寄存器的值?

assembly - 循环 "xorl %edx,%eax; shrl $1,%edx"的目的是什么?

linux - 如何将 8086 emu 汇编程序转换为 linux 汇编兼容

assembly - 如何在 i386 上将 "pushl 2000"从 AT&T asm 转换为 Intel 语法

assembly - 如何将 ADD 指令与 MASM 一起使用?

c++ - 获取内存地址 X 的值

assembly - 如何将 ASM 程序包含到我的 Turbo Basic 程序中?