gpt4 book ai didi

assembly - 引导加载程序在 qemu 中工作,但在 virtualbox 和硬件上失败

转载 作者:行者123 更新时间:2023-12-03 14:06:53 25 4
gpt4 key购买 nike

我的引导加载程序由两个 512 字节的阶段组成。阶段 1 由 bios 加载到 MBR 区域。
stage1 然后继续从驱动器加载 stage2 并跳转到它。
我用十六进制编辑器确认最终二进制“program.bin”的大小正好是 1024 字节长,并且包含两个“签名”(每个阶段的最后两个字节,0xAA55 用于 stage1(MBR 签名)和 0xCC77 用于 stage2)。
预期产出是:

1 // stage1 started
0000 or 0080 // drive# in hex
CC77 // stage2 "signature" in hex
2 // stage2 started
这在 QEMU 中工作正常,但在 virtualbox 和硬件上失败。
在我看来,stage2 加载无声无息地失败(错误分支没有被调用),我希望解决这个问题两周,但没有成功。
QEMU 输出
QEMU output
硬件和 Virtual Box 输出
VBox output
stage1.asm:
global _start
extern _stage2
extern _stage2data

BITS 16

_start:
; init registers
xor ax, ax
mov es, ax
mov gs, ax
mov ss, ax
mov sp, 0x7C00 ; right before MBR, counting upwards

mov ax, 0x7C0 ; set DS to 0x7c0 so pointing at 0x0 resolves to 0x7C0:x0000 = 0x7C00
mov ds, ax

cld ; set direction flag to make string operations count forward

; mark start of stage 1 by printing "1"
mov al, '1'
call real_mode_print_char
call real_mode_new_line

print_drive_number:
; drive# is put into DL by BIOS
mov dh, 0x0
mov bx, dx
call real_mode_print_hex

load_sector2:
mov al, 0x01 ; load 1 sector
mov bx, 0x7E00 ; destination, right after your bootloader
mov cx, 0x0002 ; cylinder 0, sector 2
; mov dl, [BootDrv] ; boot drive
xor dh, dh ; head 0
call read_sectors_16
jnc execute_stage2 ; if carry flag is set, disk read failed
jmp error

execute_stage2:
mov bx, [_stage2data] ; print data at _stage2data to confirm stage 2 was loaded
call real_mode_print_hex

jmp _stage2 ; start execude instructions of _stage2

error:
; print "E" if an error occurs
mov al, 'E'
call real_mode_print_char

; infinite loop
loop:
jmp loop

; read_sectors_16
;
; Reads sectors from disk into memory using BIOS services
;
; input: dl = drive
; ch = cylinder[7:0]
; cl[7:6] = cylinder[9:8]
; dh = head
; cl[5:0] = sector (1-63)
; es:bx -> destination
; al = number of sectors
;
; output: cf (0 = success, 1 = failure)

read_sectors_16:
push ax
mov si, 0x02 ; maximum attempts - 1
.top:
mov ah, 0x02 ; read sectors into memory (int 0x13, ah = 0x02)
int 0x13
jnc .end ; exit if read succeeded
dec si ; decrement remaining attempts
jc .end ; exit if maximum attempts exceeded
xor ah, ah ; reset disk system (int 0x13, ah = 0x00)
int 0x13
jnc .top ; retry if reset succeeded, otherwise exit
.end:
pop ax
retn

# print a number in hex
# IN
# bx: the number
# CLOBBER
# al, cx
real_mode_print_hex:
mov cx, 4
.lp:
mov al, bh
shr al, 4

cmp al, 0xA
jb .below_0xA

add al, 'A' - 0xA - '0'
.below_0xA:
add al, '0'

call real_mode_print_char

shl bx, 4
loop .lp

call real_mode_new_line

ret

real_mode_new_line:
mov al, 0x0D
call real_mode_print_char
mov al, 0x0A
call real_mode_print_char
ret

real_mode_print_char:
push bx
xor bx, bx ; Attribute=0/Current Video Page=0
mov ah, 0x0e
int 0x10 ; Display character
pop bx
ret

; boot signature
TIMES 510-($-$$) db 0

mbr_id:
dw 0xAA55
stage2.asm:
global _stage2
global _stage2data

BITS 16

_stage2:
mov al, '2'
call bios_print_char

loop:
jmp loop

bios_print_char:
push bx
xor bx, bx ; Attribute=0/Current Video Page=0
mov ah, 0x0e
int 0x10 ; Display character
pop bx
ret

; boot signature
TIMES 510-($-$$) db 0
_stage2data:
dw 0xCC77
链接器脚本“linker.ld”:
ENTRY(_start)
OUTPUT_FORMAT(binary)

SECTIONS
{
output :
{
stage1.elf(.text)
stage2.elf(.text)
}
}
我使用以下命令将所有内容编译和链接在一起:
nasm -f elf64 stage1.asm -o stage1.elf
nasm -f elf64 stage2.asm -o stage2.elf
ld -m elf_x86_64 -o program.bin stage2.elf stage1.elf -nostdlib -T linker.ld
我在 QEMU 上运行二进制文件:
qemu-system-x86_64 -drive format=raw,file=program.bin
要在硬件上运行它,我将二进制文件写入 USB:
dd if=program.bin of=/dev/sdb1 && sync

最佳答案

你的 bootstrap 实际上看起来很不错。正如@jester 在真实硬件上指出的那样,如果您使用软盘仿真 (FDD) 启动 USB,那么您很可能需要一个 BPB .您的屏幕截图中有迹象表明您正在将 USB 作为硬盘仿真 (HDD) 启动,因为驱动器编号似乎是 0x0080。如果是这种情况,则不需要 BPB。
使用 USB HDD 仿真时,您可能需要一个分区表,其中一个分区标记为事件/可启动,以便某些 BIOS 将驱动器识别为可启动。如果没有它,一些 BIOS 可能会拒绝将驱动器识别为它应该启动的东西,即使它在最后 2 个字节中有正确的磁盘签名( 0xaa55 )。
我相信真正的问题在于您如何写入 USB 驱动器。您正在使用:

dd if=program.bin of=/dev/sdb1 && sync 
/dev/sdb1实际上是第一个分区,而不是驱动器的开头。看起来您想要的是写入驱动器的开头:
dd if=program.bin of=/dev/sdb && sync
您可能会问:如果没有写入驱动器的开头,您编写的引导加载程序如何实际运行?我怀疑您的 USB 驱动器被格式化为 Master Boot Record (MBR)那个 chain loaded Volume Boot Record (VBR)分区 1 中的引导加载程序,然后开始执行它。如果 U 盘在 Windows 中进行了格式化和分区,那么这种链式加载 MBR 是非常可能的。 Windows 通常将 USB 格式化为一个大分区,并将 MBR 放在驱动器的第一个扇区中,该驱动器从第一个分区的第一个扇区链式加载 VBR。

其他观察
由于您似乎正在将所有内容作为硬盘介质启动,您可能希望考虑使用扩展磁盘功能,如 Int 13h/AH=42h而不是 Int 13h/AH=2h . Int 13/AH=2 可以加载的内容非常有限 CHS addressing而不是 LBA addressing处理较大的媒体时(通常大于约 8GiB)。

关于assembly - 引导加载程序在 qemu 中工作,但在 virtualbox 和硬件上失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62484061/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com