3. 中断向量表与中断描述符表:中断向量号、IDT的结构、实模式与保护模式下的中断处理差异

中断处理是操作系统响应硬件事件和软件异常的核心机制。在 x86 架构中,中断处理程序的查找与分发依赖于两种关键数据结构:中断向量表(IVT)和中断描述符表(IDT)。这两种结构分别对应实模式和保护模式下的中断处理体系,其设计差异直接影响了系统的安全性、灵活性和性能。

3.1 中断向量号:中断源的唯一标识

无论是外部硬件中断、内部异常还是软件中断(INT 指令),每个中断源都被分配一个唯一的中断向量号(Vector Number),范围通常为 0~255。CPU 通过该向量号在中断表中索引对应的处理程序入口。

向量号范围 类型 典型用途
0~31 异常与保留 除零错(#DE, 0)、调试异常(#DB, 1)、非屏蔽中断(NMI, 2)、断点(#BP, 3)、溢出(#OF, 4)、边界范围(#BR, 5)、无效操作码(#UD, 6)、设备不可用(#NM, 7)、双重故障(#DF, 8)、协处理器段越界(#CSO, 9)、无效 TSS(#TS, 10)、段不存在(#NP, 11)、堆栈段错误(#SS, 12)、通用保护(#GP, 13)、页错误(#PF, 14)、x87 FPU 错误(#MF, 16)、对齐检查(#AC, 17)、机器检查(#MC, 18)、SIMD 浮点异常(#XM, 19)等
32~255 可屏蔽中断(IRQ) 由中断控制器(如 8259A、APIC、GIC)路由的外部设备中断,以及通过 INT 指令触发的软件中断
关键概念:向量号 0~31 由 Intel/AMD 架构固定保留,操作系统不得重新分配。向量号 32~255 可由系统软件自由使用,其中 32~47 通常映射到 8259A 或 I/O APIC 的 IRQ 输入。

3.2 实模式下的中断向量表(IVT)

在实模式下,CPU 使用中断向量表(Interrupt Vector Table, IVT)来查找中断处理程序。IVT 固定在物理地址 0x00000 ~ 0x003FF(共 1 KB),包含 256 个表项,每个表项 4 字节,格式为 段地址:偏移地址(Segment:Offset)。

; IVT 表项结构(4 字节)
; 偏移地址低 16 位(2 字节)
; 段地址高 16 位(2 字节)
;
; 示例:向量号 0x08(IRQ0 – 定时器)
; 物理地址 = 0x0000 + (0x08 * 4) = 0x0020
; 该地址存放:偏移地址(2 字节)+ 段地址(2 字节)
; 实际入口 = 段地址 * 16 + 偏移地址
实模式中断处理流程:
  1. CPU 接收到中断信号或执行 INT 指令,获取向量号 N。
  2. CPU 将 FLAGS、CS、IP 依次压栈(保护现场)。
  3. CPU 清除 IF(可屏蔽中断标志)和 TF(陷阱标志)。
  4. CPU 从物理地址 0x0000 + N * 4 读取 4 字节,得到段地址和偏移地址。
  5. CPU 跳转到该地址执行中断处理程序。
  6. 处理程序执行 IRET 指令,恢复 CS、IP、FLAGS,返回被中断的程序。

实模式 IVT 的缺点非常明显:

  • 固定位置:IVT 必须位于物理地址 0 处,无法重定位,不利于多任务或保护机制。
  • 无权限检查:任何代码都可以修改 IVT,恶意程序可轻易劫持中断。
  • 表项过小:仅 4 字节,无法存储更多属性(如特权级、门类型)。
实模式中断向量表(IVT)结构 物理地址 0x00000 ~ 0x003FF(1 KB) 向量号 0 (除零错) 向量号 1 (调试) 向量号 2 (NMI) 向量号 3 (断点) … 255 单个 IVT 表项(4 字节) 偏移地址(2 字节) | 段地址(2 字节) CPU 通过向量号 N 计算物理地址:0x0000 + N * 4 读取段地址:偏移地址 → 跳转到处理程序

3.3 保护模式下的中断描述符表(IDT)

进入保护模式后,CPU 不再使用 IVT,而是使用中断描述符表(Interrupt Descriptor Table, IDT)。IDT 的位置由 IDTR(Interrupt Descriptor Table Register) 指定,可以位于物理内存的任何位置。IDT 包含 256 个表项,每个表项 8 字节(64 位模式为 16 字节),称为门描述符(Gate Descriptor)。

3.3.1 IDT 门描述符类型

门类型 描述 典型用途
任务门(Task Gate) 通过 TSS 切换任务来处理中断 早期 x86 用于双重故障(#DF)处理
中断门(Interrupt Gate) 进入处理程序时自动清除 IF(禁止嵌套中断) 大多数硬件中断处理
陷阱门(Trap Gate) 进入处理程序时不清除 IF(允许嵌套中断) 异常处理、系统调用(INT 0x80)

3.3.2 中断门与陷阱门结构(8 字节)

; 中断门 / 陷阱门描述符(8 字节)
; 字节 0-1: 偏移地址低 16 位
; 字节 2-3: 段选择子(目标代码段)
; 字节 4:   IST(Interrupt Stack Table,仅 64 位模式)/ 保留
; 字节 5:   门类型 + DPL + Present 位
; 字节 6-7: 偏移地址高 16 位
;
; 位域详解(字节 5):
; Bit 7:    Present (P) – 1=有效
; Bit 6-5:  DPL (Descriptor Privilege Level) – 0~3
; Bit 4:    0 (固定)
; Bit 3-0:  门类型 – 0xE=中断门, 0xF=陷阱门
重要区别:中断门在进入处理程序时自动将 IF 标志清零,防止嵌套中断;陷阱门则保留 IF 不变。对于需要快速响应且不允许被其他中断打断的关键操作(如时钟中断),应使用中断门。对于可能触发其他异常或需要嵌套中断的场景(如系统调用),应使用陷阱门。

3.4 实模式与保护模式中断处理差异对比

对比维度 实模式(IVT) 保护模式(IDT)
数据结构 中断向量表(IVT) 中断描述符表(IDT)
表项大小 4 字节(段:偏移) 8 字节(门描述符)
表项数量 256 256
位置 固定物理地址 0x00000 由 IDTR 寄存器指定,可任意
权限检查 无(任何代码可修改) 有(DPL、CPL、RPL 检查)
门类型 无(直接跳转) 任务门、中断门、陷阱门
栈切换 无(使用当前栈) 支持(通过 TSS 自动切换栈)
错误码 无 部分异常自动压入错误码
中断嵌套控制 手动控制 IF 中断门自动清 IF,陷阱门保留 IF
安全性 低(易被篡改) 高(保护机制完善)
保护模式中断描述符表(IDT)结构 IDT 基地址由 IDTR 指定(可位于任意物理地址) 向量号 0 中断门 向量号 1 陷阱门 向量号 2 任务门 向量号 3 中断门 … 255 单个 IDT 门描述符(8 字节) 偏移低 16 位 | 段选择子 | IST/保留 | 类型+DPL+P | 偏移高 16 位 字节 0-1 字节 2-3 字节 4 字节 5 字节 6-7 类型:0xE=中断门(清 IF),0xF=陷阱门(保留 IF) IDTR 寄存器:基地址(32/64 位)+ 限长(16 位)

3.5 中断处理流程对比:实模式 vs 保护模式

保护模式中断处理完整流程(以中断门为例):
  1. CPU 获取中断向量号 N。
  2. CPU 从 IDTR 中读取 IDT 基地址,计算门描述符位置:基地址 + N * 8。
  3. CPU 检查门描述符的 Present 位、DPL(与当前 CPL 比较)、段选择子有效性。
  4. CPU 从 TSS 中读取目标特权级对应的栈指针(如果发生特权级切换)。
  5. CPU 将 SS、ESP、EFLAGS、CS、EIP 压入新栈(特权级切换时)或当前栈(同级时)。
  6. CPU 清除 IF(中断门)或保留 IF(陷阱门),清除 TF、NT、VM 等标志。
  7. CPU 通过门描述符中的段选择子和偏移地址跳转到中断处理程序。
  8. 处理程序执行 IRETD/IRETQ 指令,恢复现场并返回。

相比之下,实模式的处理流程简单但缺乏保护:无权限检查、无栈切换、无错误码压栈、无门类型区分。保护模式通过 IDT 和门描述符提供了更强大的隔离能力和灵活性,为现代操作系统(如 Linux、Windows)的多任务、多特权级环境奠定了基础。

实践要点:在编写操作系统启动代码时,通常需要在实模式下初始化 IVT(至少设置关键异常和 IRQ 的临时处理程序),然后在切换到保护模式后立即加载 IDTR 并填充 IDT。IDT 的初始化是保护模式中断子系统正常工作的前提,任何遗漏或错误的门描述符都可能导致三重故障(Triple Fault)并触发系统复位。