You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

bootloader切换LBA模式后QEMU运行正常但真实硬件反复重启问题求助

问题1:32位保护模式下数据段寄存器未初始化

进入32位保护模式执行load32标签后的代码前,你没有手动将所有数据相关段寄存器(ds/es/ss/fs/gs)设置为DATA_SEG的值。insw指令默认使用es作为段基址,未初始化的es会导致读取的磁盘数据写入错误内存地址,触发三重故障导致系统无限重启。QEMU对段寄存器初始值的处理比较宽松,因此未触发问题。
修复方案:在load32最开头添加如下代码:

mov ax, DATA_SEG
mov ds, ax
mov es, ax
mov ss, ax
mov fs, ax
mov gs, ax
mov esp, 0x90000 ; 重新设置栈指针到安全内存区域,避免栈覆盖代码

问题2:ATA驱动读取逻辑不符合真实硬件要求

当前ata_lba_read只检查了状态寄存器的DRQ位(第3位),未先检查BSY位(第7位)是否清零。真实ATA设备在接收命令后会先将BSY位置1,此时读取状态寄存器的结果无效,直接读取会导致逻辑错误。
修复方案:修改.try_again部分的逻辑,先等待BSY位清零再检查DRQ位:

.try_again:
    mov dx, 0x1F7
    in al, dx
    test al, 0x80 ; 检查BSY位是否为1
    jnz .try_again
    test al, 0x08 ; 再检查DRQ位是否为1
    jz .try_again

问题3:驱动器号硬编码不符合真实硬件场景

你在FAT16的BPB中硬编码了DriveNumber db 0x80,但真实BIOS会将当前启动盘的驱动器号存入dl寄存器传入bootloader,硬编码为0x80在从非第一硬盘启动的场景下会直接失败。
修复方案:在16位实模式的load标签开头,将BIOS传入的dl的值写入DriveNumber地址保存,后续如果有16位磁盘操作可以直接使用该值。

问题4:32位打印函数存在多个逻辑错误

  1. 显存地址计算错误:VGA文本模式下每个字符占2字节(1字节ASCII+1字节属性),你当前的地址计算直接加x坐标,没有乘以2,会导致字符写入错误位置,甚至越界触发异常。
  2. 列计数重复自增:printchar32中打印完字符先执行了inc ebx,判断不需要换行后在newcol标签下又执行了inc ebx,等于每打印一个字符列号加2,会出现隔一个字符打印一个的问题,最终很快超出列范围触发异常。
  3. 未初始化行列变量:你没有给出col和row变量的定义与初始化代码,若未初始化为0,首次访问会读取到随机值,导致字符写入非法地址触发崩溃。
  4. lodsb使用错误:lodsb只会读取al寄存器,你后续判断cmp eax,0是多余的,若eax高24位有垃圾值会导致字符串判断提前终止。

修复方案:

  • 显存地址计算时将x坐标乘以2
  • 删除newcol标签下多余的inc ebx
  • 在32位代码开头初始化col和row为0
  • 将cmp eax, 0改为cmp al, 0

问题5:16位实模式栈设置错误

你将16位下的栈指针sp设置为0,栈向下增长时会写入0xFFFF~0x0000的内存区域,该区域属于BIOS数据区,会破坏BIOS运行需要的关键数据,导致真实硬件运行异常。
修复方案:将16位的栈指针设置到0x7C00之前的安全区域,比如mov sp, 0x7C00,保证栈不会覆盖bootloader自身代码,也不会破坏BIOS数据区。

内容的提问来源于stack exchange,提问作者NotMyCode

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 23:27:05