Bootloader加载内核至1MB地址失败:QEMU内存为空问题
排查两阶段Bootloader内核加载至
0x100000失败的问题 以下是针对你的场景补充的排查方向和解决方案:
1. 确认实模式下内存访问的地址合法性
实模式下CPU仅支持16位地址总线(最大访问物理地址0xFFFFF,即1MB-1),直接访问0x100000会触发地址回卷。如果Stage2仍处于实模式,必须通过段地址+偏移地址的方式访问1MB以上内存:
- 设置段寄存器
ES = 0x1000,偏移BX = 0x0,此时物理地址为ES*16 + BX = 0x100000 - 调用
int 0x13时必须使用这个段偏移组合,而非直接将偏移设为0x100000(16位寄存器无法存储该值)
2. 验证int 0x13的调用参数与返回状态
- 如果使用传统
int 0x13(AH=0x02):- 检查
CX(柱面/扇区)、DX(磁头/驱动器)参数是否与磁盘镜像中内核的位置匹配 - 调用后立即检查
AH寄存器的值:AH=0表示成功,非0值对应BIOS错误码(如0x01表示无效命令,0x04表示扇区未找到)
- 检查
- 如果使用扩展
int 0x13(AH=0x42):- 确认DAP(Disk Address Packet)结构体中的起始LBA扇区号、扇区数、内存地址(段+偏移)是否正确
3. 检查Stage2的模式切换与跳转逻辑
若内核是32位保护模式代码:
- 确认Stage2已正确进入保护模式:加载GDT、设置CR0寄存器的PE位
- 跳转至
0x100000时,需使用保护模式下的段描述符(如代码段描述符的基地址设为0,限长覆盖足够内存),而非实模式的段跳转指令
4. 验证内核二进制文件的生成正确性
- 确保内核编译后通过
objcopy -O binary kernel.elf kernel.bin转换为纯二进制文件,而非直接使用ELF格式(ELF头会占据前若干字节,导致加载的代码无法正确映射到0x100000) - 再次检查链接脚本:确认
ENTRY指向内核的入口函数,且.text段的起始地址明确设为0x100000
5. 添加Bootloader调试输出
在Stage2的关键节点添加BIOS打印(调用int 0x10):
- 加载内核前打印"Loading kernel to 0x100000..."
- 调用
int 0x13后打印返回状态(如AH的值) - 加载完成后打印"Kernel loaded, jumping..."
通过这些输出可以定位是磁盘读取失败,还是跳转逻辑有问题
6. 检查QEMU的启动参数
确认QEMU启动时使用的磁盘镜像路径正确,且未启用任何会修改内存映射的参数(如-m设置的内存足够,至少16MB)
内容的提问来源于stack exchange,提问作者Ilan Vinograd
相关产品推荐
相关产品推荐

