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

启用定时器中断时触发页错误或GPF问题求助

定时器中断触发页错误/一般保护错误的排查与修复

启用定时器中断时,遇到了页错误(page fault)或一般保护错误(general protection fault)。具体现象:删除print("testing")语句后,定时器中断处理函数timerh能持续正常打印;但保留该语句时,系统会触发GPF或页错误,定时器可能运行几次后就报错。

相关代码

汇编中断服务例程(ISR)

extern timerh
isr_timer:
    push rax
    push rdi
    push rdx
    push rcx
    push rsi
    push rbx
    push rsp
    push rbp
    push r8
    push r9
    push r10
    push r11
    push r12
    push r13
    push r14
    push r15
    call timerh
    pop r15
    pop r14
    pop r13
    pop r12
    pop r11
    pop r10
    pop r9 
    pop r8
    pop rbp
    pop rsp
    pop rbx
    pop rsi
    pop rcx
    pop rdx
    pop rdi 
    pop rax
    iretq

C语言中断处理函数

void timerh(uint64_t t) {
    print("timer\n");
    *EOI = 0;
    return;
}

启动定时器的代码

acpi();

print("testing\n");

问题分析与修复方案

  1. 核心问题:错误的栈指针操作
    你的ISR中错误地执行了push rsp和pop rsp指令:

    • push rsp会将当前栈指针值压入栈,但后续pop rsp会直接把这个旧值赋值给rsp,导致栈指针跳回压栈前的位置,此时栈上还有其他未弹出的寄存器值,后续的pop操作会在错误的栈地址执行,彻底破坏栈结构,最终触发页错误或GPF。
    • 修复:直接移除push rsp和pop rsp指令,因为rsp不需要手动保存(CPU在进入中断时已自动处理栈指针切换),修正后的ISR代码如下:
      extern timerh
      isr_timer:
          push rax
          push rdi
          push rdx
          push rcx
          push rsi
          push rbx
          push rbp
          push r8
          push r9
          push r10
          push r11
          push r12
          push r13
          push r14
          push r15
          call timerh
          pop r15
          pop r14
          pop r13
          pop r12
          pop r11
          pop r10
          pop r9 
          pop r8
          pop rbp
          pop rbx
          pop rsi
          pop rcx
          pop rdx
          pop rdi 
          pop rax
          iretq
      
  2. 中断上下文的函数安全性
    print函数在主程序和中断中同时调用时,必须是可重入的:

    • 如果print操作VGA显存或全局缓冲区,未做同步保护的话,主程序和中断的并发访问会导致数据冲突,触发错误。
    • 修复:在ISR开头添加cli关闭中断(处理完成后发送EOI再执行sti开启),或者为print实现自旋锁,确保同一时间只有一个上下文访问输出资源。
  3. EOI信号的正确性
    确认EOI指向的是正确的硬件寄存器:

    • 若使用PIC,主片EOI端口是0x20,从片是0xA0;若使用APIC,需写入对应的EOI寄存器。错误的EOI会导致中断无法正常结束,引发重复触发或嵌套错误。
  4. 栈页表权限检查
    确保中断使用的栈(无论是内核栈还是单独的中断栈)对应的页表项被标记为可读写,如果页表项被错误设置为只读或不存在,压栈操作会直接触发页错误。

现象解释

删除print("testing")后暂时正常,是因为主程序栈的布局变化较小,错误的栈恢复操作暂时没有立刻触发致命错误;但保留print时,主程序的栈操作改变了栈的深度和布局,ISR中错误的栈指针恢复会立刻破坏栈结构,触发页错误或GPF。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 12:57:11