Int 0x13在真实硬件无报错失效,QEMU中正常的内核加载问题
真实硬件与QEMU下引导加载程序磁盘加载差异问题
问题现象
编写的16位引导加载程序在QEMU中运行正常,能正确加载内核数据;但在真实硬件上执行时,内核加载逻辑未写入预期数据到0x2000地址,即使注释掉call load_disk,该地址仍显示固定值0x519B,最终导致call KERNEL_OFFSET执行失败。
QEMU运行输出
Kernel Successfully Loaded
0x2000 (the Kernel offset)
0xC6BB (what is stored at 0x2000)
0x0080 (the drive)
真实硬件运行输出
Kernel Successfully Loaded
0x2000 (the Kernel offset)
0x519B (what is stored at 0x2000)
0x0080 (the drive)
引导加载程序主代码
; Set offsets [org 0x7c00] KERNEL_OFFSET equ 0x2000 [bits 16] ; Setup Stack mov bp, 0x1000 mov sp, bp mov bx, RM_BOOT_MSG call print_rm call nl_rm ; Load kernel mov bx, KERNEL_OFFSET ; Read from disk and store in KERNEL_OFFSET mov dh, 10 ; Read X sectors call load_disk mov bx, KERNEL_LOAD_MSG call print_rm call nl_rm mov bx, KERNEL_OFFSET call print_rm_hex call nl_rm mov bx, [KERNEL_OFFSET] call print_rm_hex call nl_rm mov bh, 0 mov bl, dl call print_rm_hex call nl_rm call KERNEL_OFFSET ; Begin entering kernel jmp $ %include "boot/disk.asm" %include "boot/32b_gdt.asm" RM_BOOT_MSG: dw "16-bit RM", 0 KERNEL_LOAD_MSG: dw "Kernel Successfully Loaded", 0 ; Padding times 510 - ($ - $$) db 0 dw 0xaa55
磁盘加载函数代码
; Disk ; INT 0x13 0x02 功能说明 ; AH = 02 ; AL = 读取扇区数 (1-128 十进制) ; CH = 磁道/柱面号 (0-1023 十进制) ; CL = 扇区号 (1-17 十进制) ; DH = 磁头号 (0-15 十进制) ; DL = 驱动器号 (0=A盘, 1=第二个软盘, 80h=主硬盘, 81h=从硬盘) ; ES:BX = 缓冲区指针 ; 返回值: ; AH = 状态码 ; AL = 实际读取扇区数 ; CF = 0表示成功, 1表示错误 ; 注: 0x01是引导扇区, 0x02是第一个可用扇区 [bits 16] ; 将驱动器dl上的dh个扇区读取到es:bx指向的位置 load_disk: pusha push dx mov ah, 0x02 mov al, dh mov ch, 0x00 mov cl, 0x02 mov dh, 0x00 int 0x13 jc .disk_error pop dx cmp al, dh jne .sector_error popa ret .disk_error: mov bx, DISK_ERR_MSG call print_rm mov dh, ah call print_rm_hex call nl_rm jmp .fail_loop .sector_error: mov bx, SECTOR_ERR_MSG call print_rm call nl_rm .fail_loop: jmp $ DISK_ERR_MSG: dw "Error loading from disk: ", 0 SECTOR_ERR_MSG: dw "Incorrect number of sectors read", 0 %include "boot/print_rm.asm"
QEMU运行命令
qemu-system-i386 -s -usb -drive format=raw, file=\\.\PHYSICALDRIVE2
解决建议
- 显式设置ES寄存器:当前代码仅指定BX为
KERNEL_OFFSET,但ES默认值在真实硬件与QEMU中可能不同,导致实际写入地址不是预期的0x0000:0x2000。调用load_disk前添加:mov ax, 0x0000 mov es, ax - 添加磁盘读取重试逻辑:真实硬件磁盘读取可能出现偶发错误,INT 0x13返回错误时可重试3-5次,而非直接进入死循环。
- 调整内核加载地址:
0x2000地址在真实硬件中可能被BIOS初始化或占用,尝试将KERNEL_OFFSET改为更高地址(如0x10000)。 - 验证磁盘镜像写入完整性:确保写入到物理磁盘的镜像包含正确内核数据,真实硬件对磁盘扇区对齐、写入方式要求更严格,可重新写入并校验。
- 减少单次读取扇区数:部分真实硬件不支持CHS模式下一次性读取10个扇区,先尝试读取1个扇区测试,确认正常后再逐步增加。
内容的提问来源于stack exchange,提问作者MichaelT572
相关产品推荐
相关产品推荐

