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

时间:2017-11-25 03:21:06

标签: assembly x86-16 bootloader bios mbr

一些背景:

我正在使用基本的引导加载程序,它使用BIOS INT 13h中断将辅助引导加载程序读入内存。我已经在仿真器(Virtualbox,Qemu和Bochs)中工作了。

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

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

问题:

使用添加的分区表代码,引导加载程序无法将辅助引导加载程序加载到内存中,并且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) 失败。我不知道为什么会发生这种情况,因为我没有改变任何实际的引导加载程序代码。我刚刚添加了64位MBR分区表,并且将数据读入内存立即失败。

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

; 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

MBR分区表

{{1}}

问题

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

非常感谢任何帮助。我并不打算这个问题这么久;它只是积累了。感谢您的时间。

1 个答案:

答案 0 :(得分:3)

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

我有一个Stackoverflow答案,其中包含一般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], dl DS 中的细分非常重要。如果BIOS通过 DS 段将控制权转移到引导加载程序,而不是0x0000,那么mov [drive_n], dl会将驱动器号写入您不希望的内存位置。 / p>

如果 DS 的值不为零且启动驱动器不是0​​x00,那么很有可能失败。如果将实际启动驱动器存储到错误的存储器位置,则将使用存储在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