我正在使用基本的引导加载程序,它使用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分区表,并且将数据读入内存立即失败。
; 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
{{1}}
当且仅当在BIOS中启用USB硬盘驱动器仿真时,导致磁盘读取失败的原因是什么?我尝试过更改分区表和BPB,但似乎没有任何效果。我敢打赌它与计算机处理软盘与硬盘信息的方式有何不同,但很难找到任何信息。
非常感谢任何帮助。我并不打算这个问题这么久;它只是积累了。感谢您的时间。
答案 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 的值不为零且启动驱动器不是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