启用中断时崩溃:x86 32位保护模式下IDT配置问题排查
问题修复方案
核心问题分析
你的代码导致QEMU崩溃主要有3个关键错误:
中断服务程序(ISR)不符合x86保护模式规范
32位保护模式下,CPU触发中断时会自动向栈中压入EFLAGS、CS、EIP三个值,而你的interrupt_test是普通C函数,既没有处理这个固定栈帧,也没有用iret指令返回(普通ret无法恢复EFLAGS),会直接导致栈混乱、CPU执行流异常。IDT描述符(IDTR)结构错误
x86的IDTR是一个6字节的打包结构:低16位是IDT的限长(sizeof(idt)-1),高32位是IDT的基地址。你用uint32_t idt_ptr[2]存储,会因为32位数组的对齐问题,把限长放在第一个32位的低16位,高16位填充垃圾数据,CPU加载IDTR时会读取错误的限长,直接触发异常崩溃。寄存器上下文未保存
C函数默认会修改部分通用寄存器(如EAX、ECX等),但中断服务程序需要保证所有寄存器的值在返回时与进入时一致,否则会破坏被中断程序的上下文。
修复后的代码示例
1. 修正IDTR结构与IDT初始化
#include "idt.h" #include "screen.h" // 正确的IDT条目结构(已正确打包) struct IDTEntry { uint16_t base_low; uint16_t selector; uint8_t reserved; uint8_t flags; uint16_t base_high; } __attribute__((packed)); // 正确的IDTR结构(6字节打包) typedef struct { uint16_t limit; uint32_t base; } __attribute__((packed)) IDTR; struct IDTEntry idt[256]; IDTR idt_reg; void set_idt_entry(int index, uint32_t isr_address, uint16_t selector, uint8_t flags) { idt[index].base_low = (uint16_t)(isr_address & 0xFFFF); idt[index].base_high = (uint16_t)((isr_address >> 16) & 0xFFFF); idt[index].selector = selector; idt[index].reserved = 0; idt[index].flags = flags; } // 汇编包装的ISR入口,负责保存寄存器、调用C函数、恢复寄存器并返回 void interrupt_wrapper() { __asm__ volatile ( "pusha\n" // 保存所有通用寄存器 "call interrupt_test\n" // 调用C语言处理函数 "popa\n" // 恢复所有通用寄存器 "iret\n" // 中断返回,恢复EFLAGS/CS/EIP ); } void init_idt() { for(int i = 0; i < 256; i++) { set_idt_entry(i, (uint32_t)interrupt_wrapper, 0x08, 0x8E); } // 正确初始化IDTR idt_reg.limit = sizeof(idt) - 1; idt_reg.base = (uint32_t)&idt; __asm__ volatile("lidt (%0)" : : "r"(&idt_reg)); } void disable_interrupts() { __asm__ volatile("cli"); } void enable_interrupts() { __asm__ volatile("sti"); } void interrupt_test() { print_str("Yay", 100, 100, to_color(0, 255, 0)); // 注意:如果是可屏蔽中断,需要发送EOI信号给PIC,避免重复触发 // 比如对于主PIC:outb(0x20, 0x20); }
2. 额外注意事项
- 如果是使用PIC(可编程中断控制器)的场景,在处理完中断后必须向PIC发送EOI(中断结束)信号,否则PIC会持续发送该中断请求,导致系统反复触发中断崩溃。例如主PIC的EOI指令是
outb(0x20, 0x20),从PIC需要先发送给从PIC再发送给主PIC。 - 确保
0x08这个段选择符对应的是GDT中正确的代码段(可读可执行、DPL=0的32位代码段),如果段选择符错误,CPU会触发段异常。
内容的提问来源于stack exchange,提问作者Endrix
相关产品推荐
相关产品推荐

