Linux内核初始化(二):早期中断与异常处理机制解析
linux-insides 项目地址: https://gitcode.com/gh_mirrors/li/linux-insides
中断与异常基础概念
在计算机系统中,中断和异常是处理器响应外部事件或内部错误的重要机制。当这些事件发生时,CPU会暂停当前执行的任务,转而执行特定的处理程序。
中断类型划分
- 硬件中断:由外部设备触发,如键盘按键、定时器到期等
- 软件中断:通过特定指令(如
int
)主动触发,常用于系统调用 - 异常:CPU执行指令时检测到的错误条件,如除零错误、页错误等
x86架构的中断向量表
x86体系结构使用0-255的向量号来标识不同中断和异常:
- 0-31:保留给处理器定义的异常
- 32-255:用于用户定义的中断
关键异常列表
| 向量号 | 助记符 | 描述 | 类型 | 错误码 | |--------|--------|--------------------|--------|--------| | 0 | #DE | 除零错误 | 故障 | 无 | | 6 | #UD | 无效操作码 | 故障 | 无 | | 8 | #DF | 双重错误 | 中止 | 有 | | 13 | #GP | 通用保护错误 | 故障 | 有 | | 14 | #PF | 页错误 | 故障 | 有 |
中断描述符表(IDT)详解
IDT是x86架构中用于管理中断处理程序的关键数据结构,每个条目称为"门描述符"。在64位模式下,每个门描述符占16字节。
门描述符结构
127-96位:保留
95-64位:偏移量63-32
63-48位:偏移量31-16
47-32位:属性字段
31-16位:段选择子
15-0位:偏移量15-0
其中属性字段包含:
- P:段存在标志
- DPL:描述符特权级
- Type:门类型(任务门/中断门/陷阱门)
Linux内核早期IDT初始化
在初始化过程中,内核首先设置一个基本的IDT来处理早期异常。
idt_setup_early_handler函数
void __init idt_setup_early_handler(void)
{
for (i = 0; i < NUM_EXCEPTION_VECTORS; i++)
set_intr_gate(i, early_idt_handler_array[i]);
load_idt(&idt_descr);
}
这个函数完成以下工作:
- 遍历前32个异常向量
- 为每个向量设置中断门
- 通过
lidt
指令加载IDT
早期异常处理程序布局
early_idt_handler_array
是一个包含32个异常处理程序入口的数组,每个入口的汇编结构如下:
- 对于不产生错误码的异常:压入0作为占位符
- 压入向量号
- 跳转到通用处理程序
early_idt_handler_common
示例反汇编:
pushq $0x0 ; 错误码占位
pushq $0x1 ; 向量号1
jmp common_handler
中断处理流程详解
当CPU检测到中断或异常时,硬件自动执行以下操作:
- 将RFLAGS、CS和RIP寄存器压栈
- 如果异常产生错误码,将其压栈
- 根据向量号查找IDT并跳转到对应处理程序
- 处理程序执行完毕后通过
iret
指令返回
栈帧布局
处理程序执行时的栈结构:
| RFLAGS |
| CS |
| RIP |
| 错误码 |
| 向量号 | ← RSP
技术实现细节
set_intr_gate函数
static void set_intr_gate(unsigned int n, const void *addr)
{
struct idt_data data = {
.vector = n,
.addr = addr,
.segment = __KERNEL_CS,
.bits.type = GATE_INTERRUPT,
.bits.p = 1
};
idt_setup_from_table(idt_table, &data, 1, false);
}
该函数构造一个中断门描述符并写入IDT的指定位置。
IDT内存布局
内核使用gate_desc idt_table[IDT_ENTRIES]
数组存储IDT,通过desc_ptr
结构描述其位置和大小:
struct desc_ptr {
unsigned short size;
unsigned long address;
} __attribute__((packed));
总结
Linux内核在早期初始化阶段建立了一个基本的中断处理框架,通过精心设计的IDT结构和统一的异常处理流程,为后续更复杂的中断管理机制奠定了基础。理解这部分代码对于掌握Linux内核中断子系统至关重要。
linux-insides 项目地址: https://gitcode.com/gh_mirrors/li/linux-insides
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考