USB 硬盘仿真导致磁盘读取失败(BIOS int 13)?

Posted

技术标签:

【中文标题】USB 硬盘仿真导致磁盘读取失败(BIOS int 13)?【英文标题】:USB hard disk emulation cause a disk read to fail (BIOS int 13)? 【发布时间】:2018-05-09 00:02:59 【问题描述】:

一些背景:

我正在开发一个基本的引导加载程序,它使用 Bios INT 13h AH=02h 中断将辅助引导加载程序读入内存。我已经让它在模拟器(Virtualbox、Qemu 和 Bochs)中工作。

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

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

问题:

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

BPB(BIOS 参数块)和磁盘访问例程

bits    16 
org 0x7C00

jmp start
nop
;------------------------------------------;
;  Standard BIOS Parameter Block, "BPB".   ;
;------------------------------------------;
     bpbOEM         db  'MSDOS5.0'
     bpbSectSize    dw  512
     bpbClustSize   db  1
     bpbReservedSe  dw  1
     bpbFats        db  2
     bpbRootSize    dw  224
     bpbTotalSect   dw  2880
     bpbMedia       db  240
     bpbFatSize     dw  9
     bpbTrackSect   dw  18
     bpbHeads       dw  2
     bpbHiddenSect  dd  0
     bpbLargeSect   dd  0
     ;---------------------------------;
     ;  extended BPB for FAT12/FAT16   ;
     ;---------------------------------;
     bpbDriveNo     db  0
     bpbReserved    db  0
     bpbSignature   db  41            
     bpbID          dd  1
     bpbVolumeLabel db  'BOOT FLOPPY'
     bpbFileSystem  db  'FAT12   '

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

    ; write start string
    mov si, start_str    ; start_str = pointer to "Bootloader Found..."
    call write_str       ; routine that prints string in si register to screen 

    ; read bootstrapper into memory
    mov dl, [drive_n]; drive number
    mov dh, 0x00    ; head (base = 0)
    mov ch, 0x00    ; track /cylinder = 0
    mov cl, 0x02    ; (1= bootloader, 2=start of bootstrapper
    mov bx, 0x7E00  ; location to load bootstrapper 
    mov si, 0x04    ; number of attempts

    ; attempt read 4 times 
  read_floppy:
    ; reset floppy disk
    xor ax, ax
    int 0x13

    ; check if attempts to read remain, if not, hlt system (jmp to fail_read)
    test    si, si
    je  fail_read   ; *** This jump happens only on real machines with 
    dec si          ; USB hard drive emulation ***

    ; attempt read 
    mov ah, 0x02    ; select read
    mov al, 0x0F    ; num sectors
    int     0x13
    jc  read_floppy

    ...             ; continue onward happily! (without any errors)

MBR 分区表

; 0x1b4
db "12345678", 0x0, 0x0     ; 10 byte unique id

; 0x1be         ; Partition 1 -- create one big partition that spans the whole disk (2880 sectors, 1.44mb)
db 0x80         ; boot indicator flag = on

; start sector
db 0            ; starting head = 0
db 0b00000001   ; cyilinder = 0, sector = 1 (2 cylinder high bits, and sector. 00 000001 = high bits db 0x00)
db 0            ; 7-0 bits of cylinder (insgesamt 9 bits) 

; filesystem type
db 1            ; filesystem type = fat12

; end sector = 2880th sector (because a floppy disk is 1.44mb)
db 1            ; ending head = 1
db 18           ; cyilinder = 79, sector = 18 (2 cylinder high bits, and sector. 00 000001 = high bits db 0x00)
db 79           ; 7-0 bits of cylinder (insgesamt 9 bits) 

dd 0            ; 32 bit value of number of sectors between MBR and partition
dd 2880         ; 32 bit value of total number of sectors

; 0x1ce         ; Partition 2
times 16 db 0

; 0x1de         ; Partition 3
times 16 db 0

; 0x1ee         ; Parititon 4
times 16 db 0

; 0x1fe         ; Signature
dw  0xAA55

问题

当且仅当在 BIOS 中启用 USB 硬盘驱动器仿真时,导致读取磁盘失败的原因是什么?我已经尝试更改分区表和 BPB,但似乎没有任何效果。我敢打赌,这与计算机处理软盘和硬盘信息的方式不同有关,但很难找到任何相关信息。

任何帮助将不胜感激。我不打算让这个问题这么长。它只是积累。

【问题讨论】:

在我阅读了你的代码后,我删除了我的原始评论,认为它与这里的场景无关。我确实注意到您的分区表具有包括 MBR 在内的整个磁盘。 (第 1 区)。这是设计使然。当您使用 USB 硬盘启动系统时,您确定它实际上开始执行 MBR 中的代码吗? 是的,我确定。我让它在它开始在 MBR 中执行之后立即写入字符串“Bootloader found...”——事实上,它打印了字符串。是的,我知道你所说的从 MBR 开始的分区是什么意思。我决定这样做是因为我链接的 osdev 页面建议“MBR 必须有一个带有活动分区的分区表,引导加载程序从活动分区开始(以防固件不支持“软盘仿真”)“ .所以这就是我选择分区在MBR中启动的原因。我不确定这是否很好 作为一个实验,如果您尝试读取 1 个扇区会发生什么。而不是 mov al, 0x0F ; num sectors 尝试 mov al, 0x01 。我很好奇这是否有效 改成mov al, 0x01也有同样的效果。无论如何都会发生读取错误:-/ 您没有显示所有代码,但是您将堆栈放置在哪里以及如何初始化 ES 寄存器?单扇区读取出现读取错误提示其中一个参数错误。 【参考方案1】:

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


我有一个 *** 答案,其中包含一组通用的 bootloader tips。一个重要的提示是:

当 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_n], dl 等价于 mov [ds:drive_n], dlDS 中的片段很重要。如果 BIOS 使用不是 0x0000 的 DS 段将控制权转移到您的引导加载程序,那么 mov [drive_n], 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

【讨论】:

以上是关于USB 硬盘仿真导致磁盘读取失败(BIOS int 13)?的主要内容,如果未能解决你的问题,请参考以下文章

win7添加usb3.0驱动(错误代码1392,文件或目录损坏且无法读取)

读取磁盘:CHS方式

惠普笔记本无法识别移动硬盘,该怎么解决?

BIOS int 13h/AH=42 未读取磁盘或未读取到内存中的正确位置

U盘启动CDlinux失败

移动硬盘无法读取,是啥原因?