Bootloader跳转Kernel失败求助(已进入Protected Mode,附代码)
Bootloader跳转至Kernel失败问题排查与解决
核心问题定位
跳转失败、QEMU陷入循环的问题,大概率源于以下几个关键点:
- 内核代码的编译链接地址与加载地址不匹配
- 磁盘加载的内核内容无效
- 内核入口点未适配32位保护模式
具体排查与修复步骤
1. 确保内核编译链接地址与加载地址一致
你将内核加载到物理地址0x8000,因此内核必须以该地址为基址编译:
- 内核汇编开头需声明
bits 32和org 0x8000 - 链接时指定入口地址,例如用GNU ld:
ld -m elf_i386 -Ttext 0x8000 -o kernel.elf kernel.o
示例32位内核代码(kernel.asm):
bits 32 org 0x8000 kernel_start: ; 往VGA显存写字符,确认内核正常运行 mov byte [0xB8000 + 2], 'K' mov byte [0xB8000 + 3], 0x0F cli hlt jmp $
2. 验证磁盘加载的内核有效性
在Bootloader的32位模式代码中,跳转前添加检查逻辑,确认内核已正确加载到0x8000:
[bits 32] protected_mode: ; ... 原有段寄存器、栈设置代码 ... mov byte [0xB8000], 'P' mov byte [0xB8001], 0x0e ; 检查内核开头的签名(可在内核代码开头定义0xDEADBEEF) cmp dword [0x8000], 0xDEADBEEF jne kernel_load_fail ; 执行跳转 jmp 0x08:KERNEL kernel_load_fail: mov byte [0xB8000 + 4], 'E' mov byte [0xB8000 + 5], 0x0C cli hlt
3. 确认跳转指令与模式切换正确性
你的jmp 0x08:KERNEL指令本身是正确的(0x08对应GDT中基址0、限长4GB的代码段选择子),需确保:
- 模式切换完成:
jmp 0x08:protected_mode已完成16位到32位保护模式的切换,这部分代码无问题 - 栈指针安全:
esp=0x90000避开了Bootloader和内核的内存区域,设置合理
4. 额外注意事项
- 中断控制:跳转前已执行
cli,避免中断干扰模式切换与内核运行 - A20线:你用的
0x92端口快速启用方法在QEMU中有效,若后续适配真实硬件,建议改用键盘控制器兼容方法 - 磁盘参数:
rdisk函数中dl=0x80对应第一块硬盘,QEMU环境下参数正确
完整修改后的Bootloader跳转代码段
[bits 32] protected_mode: cli mov eax, 0x10 mov ds, eax mov es, eax mov ss, eax mov fs, eax mov gs, eax mov ebp, 0x90000 mov esp, ebp mov byte [0xB8000], 'P' mov byte [0xB8001], 0x0e ; 验证内核加载状态(可选) cmp dword [KERNEL], 0xDEADBEEF jne .load_err ; 跳转到内核入口 jmp 0x08:KERNEL .load_err: mov byte [0xB8000 + 2], 'E' mov byte [0xB8000 + 3], 0x0C cli hlt jmp $
内容的提问来源于stack exchange,提问作者user32721188
相关产品推荐
相关产品推荐

