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

64位C内核触发IRQ中断即崩溃,如何使中断触发时执行exception_handler?

问题根因与修改方案

1. 完成PIC中断向量重映射

PIC默认的IRQ中断向量范围是0x08~0x0F(主片)和0x70~0x77(从片),和CPU预定义的031号异常向量重叠,触发IRQ时会被CPU识别为非法异常直接崩溃。必须先将PIC的IRQ重映射到3247号空闲向量,在idt_init执行前调用如下函数:

void pic_remap(void) {
    outb(0x20, 0x11);
    outb(0xA0, 0x11);
    outb(0x21, 0x20); // 主片IRQ映射到0x20(32)开始
    outb(0xA1, 0x28); // 从片IRQ映射到0x28(40)开始
    outb(0x21, 0x04);
    outb(0xA1, 0x02);
    outb(0x21, 0x01);
    outb(0xA1, 0x01);
    outb(0x21, 0x0);
    outb(0xA1, 0x0);
}

2. 扩展IDT条目注册范围

你当前只注册了031号异常向量,重映射后的IRQ对应3247号向量,需要补充注册这部分的IDT条目;同时将IST参数改为0(未初始化TSS的IST1段的前提下指定IST=1会导致栈指针异常):

// idt_init函数内修改
for (uint8_t vector = 0; vector < 48; vector++) { // 扩展到48,覆盖32个异常+16个IRQ
    idt_set_descriptor(vector, isr_stub_table[vector], 0x8E, 0); 
    vectors[vector] = true;
}

同步修改idt.asm,补充32~47号中断stub并扩展stub表长度:

; 原有31个stub定义后新增
%assign i 32
%rep    16
isr_no_err_stub i
%assign i i+1
%endrep

global isr_stub_table
isr_stub_table:
%assign i 0 
%rep    48 ; 扩展到48个条目
    dq isr_stub_%+i
%assign i i+1 
%endrep

3. 修复中断Stub的上下文保存与栈平衡

x86_64下调用C函数前必须保存所有通用寄存器,带错误码的中断需要手动弹出错误码保证iretq执行前栈结构正确,修改idt.asm中的两个宏定义:

%macro isr_err_stub 1
isr_stub_%+%1:
    push rax
    push rbx
    push rcx
    push rdx
    push rsi
    push rdi
    push rbp
    push r8
    push r9
    push r10
    push r11
    push r12
    push r13
    push r14
    push r15
    mov rdi, %1 ; 把中断向量号传递给C处理函数
    call exception_handler
    pop r15
    pop r14
    pop r13
    pop r12
    pop r11
    pop r10
    pop r9
    pop r8
    pop rbp
    pop rdi
    pop rsi
    pop rdx
    pop rcx
    pop rbx
    pop rax
    add rsp, 8 ; 弹出CPU自动压入的错误码
    iretq
%endmacro

%macro isr_no_err_stub 1
isr_stub_%+%1:
    push 0 ; 插入虚拟错误码,和带错误码的中断保持栈结构一致
    push rax
    push rbx
    push rcx
    push rdx
    push rsi
    push rdi
    push rbp
    push r8
    push r9
    push r10
    push r11
    push r12
    push r13
    push r14
    push r15
    mov rdi, %1
    call exception_handler
    pop r15
    pop r14
    pop r13
    pop r12
    pop r11
    pop r10
    pop r9
    pop r8
    pop rbp
    pop rdi
    pop rsi
    pop rdx
    pop rcx
    pop rbx
    pop rax
    add rsp, 8 ; 弹出虚拟错误码
    iretq
%endmacro

4. 补充中断结束(EOI)发送逻辑

处理完PIC触发的中断后,必须向PIC发送EOI命令,否则PIC会停止响应后续中断,同步修改C处理函数的参数匹配:

void exception_handler(uint8_t vector) {
    terminal_puts("Hello");
    // 仅IRQ中断需要发送EOI
    if (vector >= 32) {
        if (vector >= 40) { // 从片触发的IRQ需要同时给从片发EOI
            outb(0xA0, 0x20);
        }
        outb(0x20, 0x20); // 给主片发EOI
    }
}

内容的提问来源于stack exchange,提问作者Timon Gärtner

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 18:18:01