使用自定义Bootloader与Kernel时VirtualBox触发Guru Meditation求排查
问题排查:VirtualBox Guru Meditation 触发原因及修复
核心问题分析
你的代码存在两个致命错误,直接导致VirtualBox崩溃:
- 保护模式下调用BIOS中断:在32位保护模式的
init_pm代码块中,你调用了BIOS磁盘中断int 0x13。BIOS中断仅在16位实模式下有效,保护模式下中断向量表结构、特权级规则完全不同,强行调用会触发非法操作,这是Guru Meditation的主要诱因。 - 磁盘读取逻辑冗余且错误:你先在保护模式读盘到0x7E00,再复制到0x10000,完全没必要,且读盘操作本身就不应该在保护模式执行。
修复后的Bootloader代码(boot.asm)
[org 0x7C00] ; 设置加载基址为0x7C00 ; --- 实模式初始化 --- mov bp, 0x9000 ; 设置栈基址 mov sp, bp ; 初始化栈指针 ; --- 实模式下读取Kernel到内存 --- ; 将Kernel读取到0x10000位置(无需后续复制) mov bx, 0x1000 ; ES:BX = 0x0000:0x1000 = 0x10000 mov dh, 1 ; 读取1个扇区 mov dl, 0x80 ; 从第一块硬盘读取 mov ah, 0x02 ; BIOS读扇区功能 mov al, dh ; 读取的扇区数 mov ch, 0 ; 磁道号0 mov cl, 2 ; 起始扇区2 mov dh, 0 ; 磁头0 int 0x13 ; 调用BIOS中断 jc disk_error ; 读盘失败则跳转错误处理 ; --- 设置GDT并进入保护模式 --- cli ; 关闭中断 lgdt [gdt_descriptor] ; 加载GDT描述符 mov eax, cr0 or eax, 0x1 ; 设置PE位开启保护模式 mov cr0, eax jmp 0x08:init_pm ; 长跳转到保护模式代码(刷新指令流水线) [bits 32] init_pm: ; 初始化段寄存器(使用GDT的数据段选择子0x10) mov ax, 0x10 mov ds, ax mov es, ax mov fs, ax mov gs, ax mov ss, ax mov esp, 0x90000 ; 设置保护模式栈指针(更高的安全地址) jmp 0x08:0x10000 ; 跳转到Kernel入口 disk_error: hlt jmp disk_error ; 无限循环处理错误 [bits 16] ; --- GDT定义 --- GDT: ; 空描述符 dd 0x0 dd 0x0 ; 32位代码段描述符 dw 0xffff ; 段限长低16位 dw 0x0 ; 段基址低16位 db 0x0 ; 段基址中8位 db 0b10011010 ; 类型:可执行、可读、非特权级 db 0b11001111 ; 粒度:4KB,段限长高4位 db 0x0 ; 段基址高8位 ; 32位数据段描述符 dw 0xffff dw 0x0 db 0x0 db 0b10010010 ; 类型:可读可写、非特权级 db 0b11001111 db 0x0 gdt_descriptor: dw $ - GDT - 1 ; GDT长度(减1) dd GDT ; GDT基地址 ; --- 引导扇区填充 --- times 510 - ($ - $$) db 0 dw 0xAA55 ; 引导签名
Kernel编译与链接注意事项
确保你的Kernel被编译为32位无依赖的二进制文件,使用以下命令:
- 编译Kernel:
gcc -m32 -ffreestanding -c kernel.c -o kernel.o
- 链接到指定地址0x10000:
ld -m elf_i386 -Ttext 0x10000 --oformat binary kernel.o -o kernel.bin
- 制作启动盘镜像:
cat boot.bin kernel.bin > os.img
其他注意点
- VirtualBox中选择启动盘为
os.img,并确保虚拟机设置为"Legacy BIOS"模式(UEFI模式不兼容MBR引导)。 - 你的Kernel代码本身没有问题,只要能正确跳转到
_start入口,就能正常输出字符串。
内容的提问来源于stack exchange,提问作者sixty nine
相关产品推荐
相关产品推荐

