0x0000:0x7000是否为不安全内核加载地址?还是QEMU导致异常?
问题描述
我正在开发一款运行于软盘、基于FAT12分区的类DOS系统,用于加载用户程序与驱动。遇到以下异常现象:
- 最初尝试通过
int 13h, 02h将11字节测试内核加载到0x0000:0x7000时,CF标志位被置位,但AH寄存器返回无错误码; - 将加载地址更换为
0x0000:0x0600后,磁盘读取成功; - 手动设置
DL寄存器指定启动盘号后,又可正常将内核加载到0x0000:0x7000。
我使用qemu-system-i386进行测试,原本认为0x7000地址及附近区域是安全的,对上述现象感到困惑,寻求原因。
MBR代码
[bits 16] org 0x7C00 ; macros %include "../include/misc.inc" jmp 0x0000:start ; notice: perserve the boot drive in dl so the kernel can save it start: cli xor ax, ax ; cs mov ds, ax mov es, ax mov ss, ax mov sp, 0x8000 sti ; set video mode mov al, 0x13 int 0x10 ; load kernel into 0x0000:0x7000 from floppy mov bx, 0x7000 mov ah, 0x02 mov al, 1 xor ch, ch ; 0 mov cl, 2 xor dh, dh ; 0 ; drive number (DL) int 0x13 jc disk_error jmp 0x0000:0x7000 disk_error: ; error handling for int 13,2h failure xor ah, ah mov al, 0x03 int 0x10 mov ah, 0x0E mov si, disk_error_message mov cl, 17 .log_error: mov al, [si] int 0x10 inc si loop cl, .log_error hlt ; Variables disk_error_message: db "Disk read failure" times 510 - ($ - $$) db 0 db 0x55, 0xAA ; boot signature
软盘构建命令
make -C src/boot/ make[1]: Entering directory '/home/mekebabman/Desktop/Simple16/src/boot' nasm -f bin mbr.nasm -o ../../build/mbr.bin make[1]: Leaving directory '/home/mekebabman/Desktop/Simple16/src/boot' dd if=/dev/zero of=build/img/S16-0.0-floppy.img bs=512 count=2880 conv=notrunc 2880+0 records in 2880+0 records out 1474560 bytes (1.5 MB, 1.4 MiB) copied, 0.0301179 s, 49.0 MB/s dd if=build/mbr.bin of=build/img/S16-0.0-floppy.img bs=512 seek=0 count=1 conv=notrunc 1+0 records in 1+0 records out 512 bytes copied, 0.000161682 s, 3.2 MB/s dd if=build/kernel/main.bin of=build/img/S16-0.0-floppy.img bs=512 seek=1 conv=notrunc 0+1 records in 0+1 records out 11 bytes copied, 0.00014582 s, 75.4 kB/s
QEMU启动命令
qemu-system-i386 -drive file=$<,format=raw,if=floppy -boot order=a
测试内核代码
[bits 16] org 0x7000 ; macros %include "../include/misc.inc" kstart: cli ; Segments are already 0x0000 ; xor ax, ax ; mov ds, ax ; mov es, ax ; mov sp, ax mov sp, 0x7400 ; 1kib stack (IGNORE THIS! RANDOM POSITION I PICKED) mov byte [boot_drive], dl sti hlt ; variables boot_drive: db 0
loop宏定义
dec <reg> jnz <address>
问题原因分析
- DL寄存器被意外修改:BIOS启动MBR时会将启动盘号存入
DL寄存器,但你的代码中调用int 10h设置视频模式(al=0x13)后,没有保存和恢复DL的值。部分BIOS的int 10h功能会修改DL寄存器,导致后续调用int 13h,02h时使用了错误的驱动器号,触发磁盘读取失败(CF置位)。而手动设置DL时,强制指定了正确的启动盘号,因此读取成功。 - 地址
0x7000本身无问题:0x0000:0x7000位于MBR加载地址0x7C00下方,栈设置在0x8000向下生长,该区域不会被MBR或栈覆盖,是安全的内存区域。更换到0x0600能成功属于巧合,本质是此时BIOS的错误驱动器读取行为未触发CF置位(或存在BIOS兼容问题),但核心问题仍在于DL寄存器的正确性。
解决方案:在调用int 10h前保存DL的值(例如存入内存或其他寄存器),调用完成后恢复DL,确保int 13h使用正确的驱动器号。
内容的提问来源于stack exchange,提问作者laween
相关产品推荐
相关产品推荐

