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

自制简易OS跳转内核时三重故障,GDT/IDT相关报错求助

问题排查与解决方案

核心问题:带错误码的异常Stub未处理栈上的错误码,导致栈不平衡

Bochs日志里的fetch_raw_descriptor: GDT: index (bf) 17 > limit (17)是栈被破坏后的连锁反应:当发生带错误码的异常(比如你定义的isr_err_stub 30)时,CPU会自动将错误码压入栈中,但当前Stub没有弹出这个错误码就执行iret,导致:

  • iret错误地将栈中的错误码当作返回EIP,把原本的EIP当作CS选择子
  • 非法的CS选择子(如日志里的0xBF)触发GDT索引越界,进而引发通用保护故障(0x0D)
  • 异常处理流程本身存在错误,最终导致三重故障

修复步骤

1. 修正带错误码的异常Stub

修改idt.asm中的isr_err_stub宏,在iret之前弹出栈上的错误码,恢复栈平衡:

; 带错误码的异常Stub:移除CPU自动压入的错误码
%macro isr_err_stub 1
isr_stub_%+%1:
    call exception_handler
    add esp, 4  ; 弹出错误码,保证iret时栈结构正确
    iret
%endmacro

如果后续需要在处理函数中获取错误码,可以调整Stub将错误码传入:

%macro isr_err_stub 1
isr_stub_%+%1:
    push eax                ; 临时保存寄存器
    mov eax, [esp+4]        ; 读取栈上的错误码
    push eax                ; 将错误码作为参数传入处理函数
    call exception_handler
    add esp, 8              ; 弹出错误码+临时保存的eax
    iret
%endmacro

同时更新C语言处理函数的定义:

void exception_handler(u32 error_code){
    __asm__ volatile("cli; hlt");
}

2. 验证GDT配置(当前GDT定义无问题)

你的GDT配置是正确的:

  • 包含空描述符、32位代码段、32位数据段,共3个描述符,总大小24字节
  • g_GDTDesc中的limit计算为g_GDTDesc - g_GDT -1 = 24-1=23(0x17),符合GDT limit的定义(表示最后一个字节的偏移量)

3. 可选:推迟中断开启时机

如果内核初始化阶段还有未完成的操作,可以将STI()推迟到所有初始化工作完成后执行,避免提前触发待处理的异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 17:17:02