我正在编写一个引导加载程序,旨在加载一个超过引导扇区允许长度的程序。然而,每次我运行该程序(我在Virtualbox和QEMU中测试),磁盘读取都会失败,磁盘重置也是如此。
该引导加载程序被设计为加载其后的一个扇区(这将是一个FAT16卷,因此我已经在磁盘描述中将其设为保留扇区),并立即运行该程序。但是,磁盘读取总是失败(CF被设置为1),而磁盘重置也是如此。这种情况在Virtualbox和QEMU中都会发生。
以下是引导扇区和第二个扇区的完整代码:
正如我所说的,第二个区段中的代码应该被执行,但由于磁盘重置失败,这并没有发生。
该引导加载程序被设计为加载其后的一个扇区(这将是一个FAT16卷,因此我已经在磁盘描述中将其设为保留扇区),并立即运行该程序。但是,磁盘读取总是失败(CF被设置为1),而磁盘重置也是如此。这种情况在Virtualbox和QEMU中都会发生。
以下是引导扇区和第二个扇区的完整代码:
BITS 16
jmp strict short main ; Jump to main bootloader
nop ; Pad out remaining bytes until boot descriptor
; Disk descriptor
OEM_name db "HOUSE " ; Disk label
bytes_sector dw 0x0200 ; Bytes per sector
sectors_cluster db 0x01 ; Sectors per cluster
sectors_reserved dw 0x0002 ; Number of sectors reserved (in this case 1 for MARBLE, the rest for R)
fats db 0x02 ; Number of file allocation tables
max_root_entries dw 0x0200 ; Max number of root entries
sectors dw 0x1040 ; Number of sectors
medium_type db 0xF0 ; Type of medium (removable or fixed?)
sectors_fat dw 0x0010 ; Sectors per file allocation table
sectors_track dw 0x0020 ; Sectors per track
heads dw 0x0002 ; Number of heads
hidden_sectors dd 0x00000000 ; Number of sectors before partition
total_sectors dd 0x00000000 ; Number of sectors in medium (zero because 2B != 0)
drive_number db 0x00 ; Drive number (for BIOS int 0x13)
drive_signature db 0x00 ; NOT USED
ext_signature db 0x29 ; Extended boot signature
volume_serial dd 0x00000000 ; Volume's serial number
volume_label db "HOUSEHOUSE "; Volume label
fs_type db "FAT16 " ; Filesystem type
main:
mov sp, 0x1000 ; 4K of stack
mov ax, word [sectors_reserved] ; Read all reserved sectors
sub al, 0x01 ; Except this one
mov ah, 0x02 ; Read disk sectors
mov bx, r_buffer ; Read contents into our buffer
mov ch, 0x00 ; Cylinder 0
mov cl, 0x02 ; Sector 2
mov dh, 0x00 ; Head 0
jmp .read ; Read the disk
.reset:
pusha ; Push register states to stack
call lps
mov ah, 0x00 ; Reset disk
int 0x13 ; BIOS disk interrupt
jnc .read ; If successsul, read again
call lps
mov ah, 0x00 ; Otherwise, prepare to reboot
int 0x19 ; Reboot
.read:
call lps
int 0x13 ; BIOS disk interrupt
jc .reset ; If failed, reset disk
jmp r_buffer ; Otherwise, jump to R
lps: ; Debug message
pusha
mov ah, 0x0E
mov al, 0x52
mov bh, 0x00
int 0x10
mov ah, 0x00
int 0x16
popa
ret
times 510-($-$$) db 0x00 ; Pad remainder of boot sector with zeros
sig dw 0xAA55 ; Boot signature
r_buffer: ; Space in memory for loading R
r_start: ; Beginning of second sector
mov ax, 0x07C0
add ax, 0x0220
mov ss, ax
mov ax, 0x07C0
mov ds, ax
mov si, success ; Successful
call print_str ; Print!
hlt ; Halt here
print_str: ; Prints string pointed to by REGISTER SI to cursor location (si=str)
pusha ; Push register states to stack
mov ah, 0x0E ; Print in teletype mode
mov bh, 0x00 ; Page 0
.repeat:
lodsb ; Load next character from si
cmp al, 0x00 ; Is this a null character?
je .ret ; If it is, return to caller
int 0x10 ; Otherwise, BIOS interrupt
jmp .repeat ; Do the same thing
.ret:
popa ; Restore register states
ret ; Return to caller
.data:
success db "!", 0x00 ; Success!
times 1024-($-$$) db 0x00 ; Pad remainder of reserved sectors with zeros
正如我所说的,第二个区段中的代码应该被执行,但由于磁盘重置失败,这并没有发生。
pusha
。有趣的是,仅仅不从堆栈中弹出某些东西就会导致许多问题。我一直在使用 DD 将引导扇区写入空白磁盘映像。 - House