Assembly USB硬盘模拟导致磁盘读取失败(BIOS int 13)? 一些背景:

Assembly USB硬盘模拟导致磁盘读取失败(BIOS int 13)? 一些背景:,assembly,x86-16,bootloader,bios,mbr,Assembly,X86 16,Bootloader,Bios,Mbr,我正在使用BIOSint13h AH=02h中断将辅助引导加载程序读入内存。我已经让它在模拟器(Virtualbox、Qemu和Bochs)中工作 随后,我在我的引导加载程序中添加了一个BPB(BIOS参数块),制作了一个可引导的USB,并用USB软盘模拟(我在我的真实机器的BIOS配置屏幕中设置)在我的真实机器上进行了测试。它就像一个符咒 在我自己的机器上测试引导加载程序之后,我在另一台更新的机器上测试了它。这台新计算机的BIOS配置中没有软盘模拟选项,因此无法从USB驱动器启动。因此,在os

我正在使用BIOS
int13h AH=02h
中断将辅助引导加载程序读入内存。我已经让它在模拟器(Virtualbox、Qemu和Bochs)中工作

随后,我在我的引导加载程序中添加了一个BPB(BIOS参数块),制作了一个可引导的USB,并用USB软盘模拟(我在我的真实机器的BIOS配置屏幕中设置)在我的真实机器上进行了测试。它就像一个符咒

在我自己的机器上测试引导加载程序之后,我在另一台更新的机器上测试了它。这台新计算机的BIOS配置中没有软盘模拟选项,因此无法从USB驱动器启动。因此,在osdev wikipage之后,我在MBR的末尾添加了一个分区表,以便新机器可以从USB启动

问题是: 添加分区表代码后,引导加载程序无法将辅助引导加载程序加载到内存中,BIOS
INT 13h
也会失败。我不知道为什么会发生这种情况,因为我没有更改任何实际的引导加载程序代码。我刚刚添加了64位MBR分区表,将数据读入内存会立即失败

BPB(BIOS参数块)&磁盘访问例程 MBR分区表 问题 当且仅当BIOS中启用USB硬盘驱动器模拟时,是什么导致读取磁盘失败?我尝试过修改分区表和BPB,但似乎没有任何效果。我敢打赌,这与电脑处理软盘和硬盘信息的方式不同有关,但很难找到这方面的任何信息


任何帮助都将不胜感激。我不想让这个问题持续这么久;它刚刚积累起来。

TL;DR:在某些情况下,引导驱动器未正确存储在标签
驱动器中。这会导致磁盘读取例程在某些硬件上失败


我有一个Stackoverflow的答案,有一个一般的答案集。一个重要提示是:

当BIOS跳转到您的代码时,您不能依赖具有有效或预期值的CS、DS、ES、SS、SP寄存器。它们应该在引导加载程序启动时进行适当设置。您只能保证引导加载程序将从物理地址0x00007c00加载并运行,并且引导驱动器号已加载到DL寄存器中

在您的问题被更新为更相关的代码后,阅读之前发生了什么,问题变得明显:

drive_n: db 0
start: 
    mov [drive_n], dl

    ; setup segments
    xor ax, ax
    mov ds, ax
    mov es, ax

    ; setup stack
    cli
    mov ss, ax
    mov sp, 0x7C00   ; stack will grow downward to lower adresses
    sti
问题是,在设置段寄存器之前,会执行
mov[drive\n],dl
mov[drive\u n],dl
相当于
mov[ds:drive\u n],dl
。DS中的部分很重要。如果BIOS使用非0x0000的DS段将控制权转移到引导加载程序,则dl会将驱动器号写入您不期望的内存位置

如果DS的值不是零,并且引导驱动器不是0x00,则很有可能出现故障。在实际启动驱动器存储到错误内存位置的情况下,将使用存储在
drive\n
标签上的初始值。在你的例子中,这是0x00

在大多数情况下,你很幸运它能起作用。这个问题的解决办法很简单。确保在设置段寄存器(尤其是DS)后,将DL值写入内存。代码应该如下所示:

drive_n: db 0
start: 
    ; setup segments
    xor ax, ax
    mov ds, ax
    mov es, ax

    ; setup stack
    cli
    mov ss, ax
    mov sp, 0x7C00   ; stack will grow downward to lower adresses
    sti

    mov [drive_n], dl

在阅读了你的代码后,我删除了我最初的评论,认为这与这里的场景无关。我注意到分区表包含整个磁盘,包括MBR。(部门1)。那是故意的。当你用USB硬盘引导系统时,你确定它真的开始执行MBR中的代码了吗?是的,我确定。我使它在MBR中开始执行后立即写入字符串“Bootloader found…”,实际上,它会打印字符串。是的,我知道你说的从MBR开始的分区是什么意思。我决定这样做是因为我链接的osdev页面建议“MBR必须有一个带有活动分区的分区表,引导加载程序在活动分区中启动(以防固件不支持“软盘模拟”)。这就是为什么我选择在MBR中启动分区。我不确定这是否是一个好主意作为一个实验,如果你尝试阅读1个扇区会发生什么。而不是
mov al,0x0F;num扇区
try
mov al,0x01
。我很好奇,如果更改为
mov al,0x01
是否具有相同的效果。不管怎样,读取错误都会发生:-/您没有显示所有代码,但是堆栈放在哪里,以及如何初始化ES寄存器?单个扇区读取时发生的读取错误表明其中一个参数错误。
drive_n: db 0
start: 
    mov [drive_n], dl

    ; setup segments
    xor ax, ax
    mov ds, ax
    mov es, ax

    ; setup stack
    cli
    mov ss, ax
    mov sp, 0x7C00   ; stack will grow downward to lower adresses
    sti
drive_n: db 0
start: 
    ; setup segments
    xor ax, ax
    mov ds, ax
    mov es, ax

    ; setup stack
    cli
    mov ss, ax
    mov sp, 0x7C00   ; stack will grow downward to lower adresses
    sti

    mov [drive_n], dl