中断和异常简介
在计算机体系结构和操作系统中,中断(Interrupt) 和 异常(Exception) 是CPU应对突发事件、实现多任务并发和错误处理的核心机制。二者均通过暂停当前任务、转去执行特定处理程序来响应事件,但在触发源、同步性、处理目标上存在本质区别。下面将从定义、分类、处理流程、核心差异四个维度详细解析。
一、中断(Interrupt):外部设备的“信号请求”
中断是外部硬件设备(如键盘、网卡、硬盘)向CPU发送的“事件通知”,目的是让CPU暂停当前低优先级任务,优先处理设备的紧急需求(如数据接收、操作完成)。中断是异步事件(不依赖当前CPU执行的指令),且不破坏程序的正常上下文。
1. 中断的核心特征
- 触发源:外部硬件:由CPU之外的设备发起(如打印机完成打印、网卡收到网络数据包)。
- 同步性:异步:中断的发生时间不确定,与CPU当前执行的指令无关(CPU会在每条指令执行完毕后检查是否有中断请求)。
- 上下文安全性:中断发生时,程序的执行状态(寄存器、程序计数器PC)完整,处理完毕后可精确回到中断前的指令继续执行。
- 可屏蔽性:大部分中断可通过CPU的“中断屏蔽位”(如x86的IF标志)暂时关闭,避免干扰关键任务(如内核初始化)。
2. 中断的分类
根据“是否可被屏蔽”和“优先级”,中断主要分为两类:
分类 | 定义 | 典型场景 |
---|---|---|
可屏蔽中断(Maskable) | 可通过CPU指令(如cli )关闭的中断,优先级较低,非紧急需求。 | 键盘输入、鼠标操作、硬盘读写完成、打印机就绪。 |
不可屏蔽中断(NMI) | 无法被屏蔽的中断,优先级最高,对应紧急故障,必须立即处理。 | 电源掉电(需快速保存数据)、内存硬件错误、CPU温度过高(防止硬件损坏)。 |
此外,按设备类型还可细分(如PCIe中断、串口中断),但核心分类以“可屏蔽性”为标准。
3. 中断的处理流程
中断处理需遵循严格的步骤,确保不丢失当前任务状态,且高效响应设备需求。以x86架构为例,流程如下:
- 设备发起请求:外部设备(如网卡)完成操作后,通过“中断请求线(IRQ)”向中断控制器(如APIC)发送信号。
- CPU检查中断:CPU在每条指令执行完毕后,自动检查中断控制器是否有未处理的请求:
- 若中断被屏蔽(IF=0),则忽略可屏蔽中断,继续执行下一条指令;
- 若未被屏蔽,且存在高优先级中断,则暂停当前任务。
- 保存现场(Context Save):CPU将当前执行状态(PC、通用寄存器、标志位)压入内核栈,确保后续能恢复原任务。
- 查找中断处理程序:根据中断的“向量号”(如键盘中断向量号为0x09),查询中断描述符表(IDT),获取对应的“中断服务程序(ISR)”地址。
- 执行ISR:ISR是内核中针对该设备的专用处理逻辑(如读取网卡接收的数据、通知用户进程“数据已就绪”)。执行期间可能会关闭低优先级中断,避免嵌套干扰。
- 恢复现场与返回:ISR执行完毕后,CPU从内核栈中恢复中断前的状态(PC、寄存器),开启中断(如
sti
),回到原任务的中断点继续执行。
4. 中断的核心作用
- 提高CPU利用率:避免CPU“轮询”设备(如反复检查硬盘是否就绪),让CPU在设备忙碌时可执行其他任务,实现“并发”。
- 实时响应外部事件:确保设备的紧急需求(如网卡接收数据包)被及时处理,避免数据丢失或延迟。
二、异常(Exception):CPU内部的“指令错误/请求”
异常是CPU执行指令时内部检测到的异常情况(如错误、调试需求、系统调用),是同步事件(与当前执行的指令直接相关)。异常的发生意味着程序可能存在错误,或需要内核提供服务(如系统调用),处理结果可能是“恢复程序”“终止程序”或“切换到内核态”。
1. 异常的核心特征
- 触发源:CPU内部:由当前执行的指令触发(如除以零、访问不存在的内存、执行
syscall
指令)。 - 同步性:同步:异常的发生时间确定——必然与某条具体指令绑定(如执行
1/0
时必触发“除以零异常”)。 - 上下文依赖性:异常可能破坏程序执行状态(如内存访问错误),部分异常(如“终止类”)无法恢复,需终止程序。
- 不可屏蔽性:异常由指令执行直接引发,无法通过“屏蔽位”关闭(若屏蔽,程序错误将无法被处理,导致系统崩溃)。
2. 异常的分类
异常的分类依赖于事件性质和处理结果,不同架构(如x86、ARM)的分类标准一致,核心分为三类:
分类 | 定义 | 处理逻辑 | 典型场景 |
---|---|---|---|
故障(Fault) | 指令执行前检测到的可恢复错误(如资源缺失),目的是“修复后重新执行该指令”。 | 内核修复错误(如补全缺失的内存页)→ 恢复现场 → 重新执行引发故障的指令。 | 页面错误(Page Fault,程序访问的内存页未加载到物理内存)、段权限错误(访问无权限的内存段)。 |
陷阱(Trap) | 指令执行后主动触发的异常,目的是“提供服务或调试”,无需修复。 | 执行陷阱处理程序(如系统调用逻辑)→ 恢复现场 → 执行下一条指令(跳过引发陷阱的指令)。 | 系统调用(如Linux的syscall 指令)、调试断点(int3 指令,用于GDB调试)。 |
终止(Abort) | 严重且不可恢复的错误,无法确定故障指令的位置,程序无法继续执行。 | 内核终止故障程序(释放资源),生成核心转储(Core Dump) 供调试,不返回原程序。 | 内存硬件错误(如双总线错误)、非法指令(程序执行了CPU不支持的指令)、段错误(访问不存在的内存地址)。 |
3. 异常的处理流程
异常处理与中断流程相似,但触发起点和最终结果不同(以“页面错误”为例):
- 指令触发异常:程序执行
mov eax, [0x12345678]
(访问某内存地址),CPU检测到该地址对应的“内存页未加载到物理内存”,自动生成“页面错误”异常(向量号#PF)。 - 保存现场:CPU暂停当前程序,将PC(指向引发异常的指令)、寄存器、标志位压入内核栈(注意:PC仍指向故障指令,以便后续重新执行)。
- 查找异常处理程序:通过异常向量号#PF查询IDT,获取“页面错误处理程序”的地址。
- 执行处理程序:内核检查缺失的内存页是否合法(如是否属于程序的地址空间):
- 若合法:从硬盘的“交换分区”加载该页到物理内存,更新页表;
- 若非法(如访问不属于程序的地址):触发“段错误”,转为终止类异常,终止程序。
- 恢复现场与返回:若合法加载完成,CPU从内核栈恢复状态,重新执行引发异常的
mov
指令(此时内存页已存在,指令可正常执行)。
4. 异常的核心作用
- 错误处理:捕获程序的非法操作(如除以零、越界访问),避免错误扩散,保证系统稳定。
- 系统调用接口:通过“陷阱类异常”(如
syscall
)实现用户态到内核态的切换,让程序获取内核服务(如文件读写、进程创建)。 - 调试支持:通过“断点陷阱”(
int3
)让调试器(如GDB)暂停程序、查看内存和寄存器,实现程序调试。
三、中断与异常的核心差异对比
中断和异常虽均通过“暂停-处理-恢复”流程响应事件,但本质是两类不同机制,核心差异可通过下表清晰区分:
对比维度 | 中断(Interrupt) | 异常(Exception) |
---|---|---|
触发源 | 外部硬件设备(如键盘、网卡) | CPU内部(当前执行的指令) |
同步性 | 异步(与当前指令无关,发生时间不确定) | 同步(与某条指令绑定,发生时间确定) |
处理时机 | 每条指令执行完毕后检查 | 指令执行中/执行后立即触发 |
可屏蔽性 | 大部分可屏蔽(可通过cli 关闭),NMI不可屏蔽 | 全部不可屏蔽(必须处理,否则系统崩溃) |
上下文恢复结果 | 回到中断前的指令继续执行(上下文完整) | 故障:回到原指令;陷阱:回到下一条指令;终止:不返回 |
典型场景 | 键盘输入、网卡收包、硬盘就绪 | 页面错误、系统调用、除以零、段错误 |
核心目标 | 响应外部设备需求,提高CPU利用率 | 处理程序错误、提供内核服务、支持调试 |
四、易混淆点澄清
-
系统调用是中断还是异常?
系统调用是异常(陷阱类),而非中断。例如Linux的syscall
指令会主动触发陷阱,让CPU从用户态切换到内核态执行内核逻辑,处理完毕后返回用户态。其本质是“程序主动请求内核服务”,属于CPU内部的同步事件,符合异常的定义。 -
中断嵌套与异常嵌套的区别?
- 中断支持嵌套:高优先级中断(如NMI)可打断低优先级中断的处理程序(如键盘中断),处理完高优先级中断后再回到低优先级流程。
- 异常不支持嵌套:异常由当前指令触发,若在异常处理中再次触发异常(如处理页面错误时又发生内存错误),会被判定为“致命错误”,直接终止程序。
-
中断向量表与异常向量表的关系?
多数架构(如x86、ARM)中,中断和异常共用一个“向量表”(如x86的IDT、ARM的向量表)。表中每个“向量号”对应一个处理程序:低编号向量(如0-31)通常分配给异常(如#0除以零、#13通用保护错误),高编号向量(如32+)分配给中断(如#32对应IRQ0定时器中断)。
五、总结
中断和异常是计算机系统“应对突发情况”的两大支柱:
- 中断是“外部设备与CPU的沟通桥梁”,通过异步响应实现设备并发,让CPU摆脱轮询的低效;
- 异常是“CPU与程序的错误/服务接口”,通过同步处理保证程序正确性,同时提供用户态到内核态的切换通道。
理解二者的差异,是掌握操作系统并发机制、错误处理、系统调用原理的关键基础。
中断描述符表(IDT)
在x86架构(及x86-64兼容架构)中,中断描述表(Interrupt Descriptor Table, IDT) 是连接“硬件事件/软件错误”与“处理逻辑”的硬件级核心数据结构,本质是中断与异常的“系统导航中枢”。它通过标准化表项定义,确保CPU在遇到中断(如键盘输入、定时器超时)或异常(如除零错误、内存越界)时,能快速、安全地跳转到对应处理程序,是操作系统稳定运行的底层基石。
一、IDT的核心定位:解决“事件响应”的核心问题
计算机运行中会频繁面临两类需要优先处理的事件,IDT的核心作用就是“统一管理、安全调度”这两类事件的处理逻辑:
- 中断(Interrupt):外部硬件触发的“请求信号”(如键盘按键、硬盘I/O完成、网卡接收数据),需CPU暂停当前任务,优先响应硬件需求;
- 异常(Exception):CPU执行指令时检测到的“内部错误”(如除零错误、非法指令、内存访问越界、调试断点),需紧急处理以避免程序崩溃或系统宕机。
没有IDT时,CPU面对这些事件会“无章可循”——无法定位处理程序地址,甚至直接陷入“无响应”。IDT通过三大核心价值解决这一问题:
- 统一管理:将所有256种中断/异常(对应0-255的“中断向量”)的处理逻辑集中登记,避免分散混乱;
- 安全隔离:通过“特权级控制”(如“仅内核可处理高优先级事件”),防止低权限用户程序滥用中断(如伪造系统调用);
- 高效响应:以“查表定位”替代“遍历搜索”,CPU可通过中断向量直接找到处理程序,减少中断延迟(关键场景如实时控制、高频I/O)。
二、IDT的硬件基础:IDTR寄存器与门描述符
IDT的功能依赖两大硬件组件协同:IDTR寄存器(定位IDT) 和门描述符(存储处理信息),二者共同构成IDT的“物理骨架”。
1. IDTR寄存器:IDT的“内存定位器”
CPU通过IDTR(Interrupt Descriptor Table Register,中断描述符表寄存器) 确定IDT在内存中的位置,是CPU的专用寄存器,结构随运行模式(32位/64位)差异而变化:
运行模式 | 寄存器位数 | 核心组成(按功能划分) | 关键作用 |
---|---|---|---|
32位(IA-32) | 48位 | 16位限长(Limit) + 32位基地址(Base Address) | 限长:IDT总字节数-1(如256个8字节表项,限长=2047); 基地址:IDT在内存中的起始物理地址 |
64位(IA-32e) | 80位 | 16位限长 + 64位基地址 | 基地址扩展为64位,适配现代系统的大内存寻址需求 |
操作系统通过特权指令操作IDTR(仅内核态可执行):
LIDT
(Load IDT):将内存中预定义的“IDT基地址+限长”加载到IDTR,完成IDT初始化;SIDT
(Store IDT):将IDTR内容保存到内存,用于调试(如查看IDT当前位置)或备份。
2. 门描述符:IDT的“条目卡片”
IDT是一个包含256个条目的数组,每个条目是门描述符(Gate Descriptor)——相当于一张“处理程序地址卡片”,记录某类中断/异常的处理程序地址、权限、类型等关键信息。根据处理场景不同,门描述符分为三大类,且32位与64位模式下结构有显著差异。
(1)32位模式:8字节门描述符结构
32位模式下,每个门描述符占8字节,按内存布局包含5个核心字段:
字节偏移 | 字段 | 位数 | 功能说明 |
---|---|---|---|
0-1 | 偏移量(低16位) | 16 | 处理程序入口地址的低16位(与高16位拼接为32位完整地址) |
2-3 | 段选择子 | 16 | 指向GDT/LDT中“处理程序所在代码段”的索引,确保处理程序在合法内存空间执行 |
4 | 零填充 | 8 | 固定为0,用于内存对齐 |
5 | 类型与权限 | 8 | 4位“类型字段”(区分门类型)+ 2位“DPL(描述符特权级)”+ 2位保留位 |
6-7 | 偏移量(高16位) | 16 | 处理程序入口地址的高16位 |
(2)64位模式:16字节门描述符扩展
64位模式下,门描述符扩展为16字节,以支持64位地址空间和更稳定的中断处理,核心新增/修改字段:
- 64位偏移量:分“低16位(0-1字节)、中32位(6-9字节)、高16位(14-15字节)”,拼接为64位处理程序地址,适配x86-64的64位指令指针(RIP);
- IST字段(7位):新增“中断栈表(Interrupt Stack Table)”字段,支持为高优先级中断/异常(如双重故障#DF、不可屏蔽中断NMI)分配独立栈,避免原栈溢出导致系统崩溃;
- 类型与权限优化:保留“类型字段”和“DPL”,但扩展系统段标识,兼容64位特权级机制。
(3)三大门描述符类型:中断门、陷阱门、任务门
不同门类型对应不同场景,核心差异在“类型字段”和“中断响应行为”,是IDT功能分化的核心:
门类型 | 32位类型字段(二进制) | 64位类型字段(十六进制) | 核心行为特性 | 典型应用场景 |
---|---|---|---|---|
中断门 | 1110B(0xE) | 0x8E(DPL=0)/0xCE(DPL=3) | 1. 自动关闭IF标志(IF=0 ),禁止可屏蔽中断嵌套,避免硬件冲突;2. 特权级切换时强制换栈(如用户态→内核态); 3. 处理后通过 IRETD /IRETQ 返回 | 硬件中断(键盘、定时器、网卡)、高优先级异常(NMI) |
陷阱门 | 1111B(0xF) | 0x8F(DPL=0)/0xCF(DPL=3) | 1. 保持IF标志(IF 不变),允许中断嵌套;2. 仅当CPL>DPL时换栈(如用户态触发内核系统调用); 3. 支持主动软件调用 | 系统调用(Linux int 0x80 )、调试异常(断点、单步)、软件错误(溢出) |
任务门 | 1001B(0x9) | 不支持(废弃) | 1. 不跳转处理程序,触发任务切换(加载TSS上下文); 2. 偏移量无效,仅用段选择子指向TSS; 3. 自动保存原任务状态 | 32位模式多任务调度(现代系统极少用,被线程调度替代) |
三、IDT的完整工作流程(硬件自动驱动)
当中断或异常发生时,CPU会遵循固定的硬件流程,通过IDT完成“事件响应→处理→恢复”的闭环,整个过程无需软件干预(除最终执行处理程序),确保高效与安全:
1. 阶段1:事件触发与中断向量生成
中断/异常的源头不同,但最终都会生成一个8位中断向量(0-255)(IDT查表的“索引”):
- 硬件中断:外部设备(如键盘)通过APIC(高级可编程中断控制器)向CPU发信号,APIC分配向量(如键盘默认33,定时器32);
- 软件异常:CPU检测到错误(如除零、页错误),自动生成固定向量(如除零=0,页错误=14);
- 软件中断:程序通过
INT n
指令主动触发,向量由指令指定(如INT 0x80
=128,INT 3
=3)。
2. 阶段2:IDT查表(定位处理程序)
CPU根据中断向量计算IDT表项地址:
表项地址 = IDTR.基地址 + 向量编号 × 表项长度
- 32位模式:表项长度=8字节(如向量33的地址=IDTR基地址+33×8);
- 64位模式:表项长度=16字节(如向量14的地址=IDTR基地址+14×16)。
3. 阶段3:权限与合法性校验(安全屏障)
CPU对门描述符做双重校验,不通过则触发“一般保护错误(#GP)”:
- DPL校验:当前程序的特权级(CPL,用户态=3、内核态=0)必须≤门描述符的DPL(数值越小特权级越高)。例如,内核中断门(DPL=0)不允许用户态程序(CPL=3)触发;
- 段选择子校验:门描述符的“段选择子”必须指向GDT/LDT中合法的“可执行代码段”,且代码段DPL≥门DPL(确保处理程序权限足够)。
4. 阶段4:上下文保存(防止执行状态丢失)
CPU自动将当前执行状态压入栈中,确保处理完成后能恢复原程序,32位与64位模式差异显著:
- 32位模式:
压入EFLAGS
(标志寄存器)→CS:EIP
(代码段+指令指针)→ 错误码(部分异常);
若特权级切换(用户态→内核态),额外压入用户态SS:ESP
(栈段+栈指针),并切换到内核栈。 - 64位模式:
无论特权级是否变化,强制压入SS
→RSP
→EFLAGS
→CS
→RIP
→错误码(若有);
若门描述符的IST字段非0,切换到TSS中IST指定的独立栈(如双重故障用IST1),避免栈溢出。
5. 阶段5:执行处理程序
CPU从门描述符中提取处理程序入口地址(代码段基址+偏移量),跳转到该地址执行逻辑:
- 硬件中断:如键盘中断程序读取扫描码、转换为字符并存入内核缓冲区;
- 异常处理:如页错误程序分配物理内存、更新页表,或致命错误(如双重故障)触发系统panic;
- 系统调用:如
INT 0x80
触发内核system_call
函数,根据eax
寄存器调用对应服务(如文件读写)。
6. 阶段6:恢复上下文与返回
处理程序执行完成后,通过专用指令恢复上下文:
- 32位模式:
IRETD
指令,从栈中弹出EIP→CS→EFLAGS
(特权级变化时额外弹出ESP→SS
); - 64位模式:
IRETQ
指令,从栈中弹出RIP→CS→EFLAGS→RSP→SS
。
指令执行后,CPU恢复中断前的状态,原程序继续运行。
四、IDT的模式差异:实模式IVT vs 保护模式IDT
IDT的设计随x86运行模式演进,核心分为“实模式中断向量表(IVT)”和“保护模式IDT”,二者差异体现了系统从“无保护”到“安全可控”的进步:
对比维度 | 实模式中断向量表(IVT) | 保护模式IDT |
---|---|---|
内存位置 | 固定于物理地址0x0000:0x0000 -0x0000:0x03FF (1KB) | 动态定位(IDTR指定),可位于内存任意位置 |
表项结构 | 256个4字节向量(16位段地址+16位偏移) | 256个8字节(32位)/16字节(64位)门描述符 |
权限控制 | 无(所有中断共享同一特权级,易被攻击) | 有(DPL区分内核态/用户态,安全隔离) |
动态修改 | 不可(BIOS初始化,操作系统无法修改) | 可(内核通过接口动态更新,支持驱动加载) |
地址空间支持 | 仅1MB(实模式寻址限制) | 支持32位/64位地址空间(适配大内存) |
典型应用 | DOS系统、BIOS启动阶段、早期8086处理器 | Windows、Linux等现代操作系统 |
五、IDT在操作系统中的实现(以Linux为例)
IDT并非硬件自动初始化,而是由操作系统(内核)在启动阶段构建和维护,确保适配硬件与软件逻辑:
1. 初始化流程
-
临时IDT(启动阶段):
内核启动初期(如arch/x86/kernel/head64.S
)创建“临时IDT”,所有中断指向default_idt_handler
,防止未初始化中断导致崩溃。 -
正式IDT初始化(
idt_init()
函数):- 清空IDT:
memset(idt, 0, sizeof(idt))
; - 注册异常:
set_except_gate
注册32个CPU保留异常(DPL=0,仅内核可处理); - 注册中断:
set_irq_gate
注册外部硬件中断(DPL=3,允许用户态触发); - 注册系统调用:
set_system_gate(0x80, &system_call)
,支持int 0x80
调用内核。
- 清空IDT:
-
动态修改:
内核通过set_intr_gate
(修改中断门)、update_descriptor
(更新表项)等接口,支持运行时修改IDT(如驱动加载、热补丁):// 动态注册定时器中断处理程序(向量32) set_irq_gate(32, &timer_interrupt);
2. 64位模式IST配置
Linux通过setup_ist()
初始化IST,为高风险异常分配独立栈:
- 双重故障(#DF,向量8)→ IST1;
- 不可屏蔽中断(NMI,向量2)→ IST2;
- 调试中断(向量1)→ IST3。
六、IDT的安全与性能优化
现代操作系统通过一系列机制增强IDT的安全性和效率:
1. 安全加固
- NX保护:将IDT所在内存页标记为“不可执行(NX)”,防止攻击者篡改IDT注入恶意代码;
- 权限隔离:通过DPL严格限制中断触发权限(如内核异常DPL=0,用户态无法伪造);
- 完整性校验:内核启动时对IDT做哈希校验,检测非法修改(如恶意软件篡改处理程序)。
2. 性能优化
- 中断合并:APIC将同类中断(如网卡I/O)合并到同一CPU核心,减少跨核上下文切换;
- 中断亲和性:
irqbalance
工具将中断绑定到固定CPU核心(如定时器→核心0),提升缓存命中率; - 快速系统调用:64位系统通过
sysenter/sysexit
绕过IDT,减少查表延迟(IDT作为 fallback)。
七、总结
IDT是x86架构中“硬件事件响应”与“软件处理逻辑”的桥梁,其核心价值在于:
- 功能性:统一管理所有中断/异常,确保系统能正确应对突发状况;
- 安全性:通过权限校验和栈隔离,防止非法访问与滥用;
- 高效性:以查表方式快速定位处理程序,减少中断延迟。
从实模式的固定IVT到64位模式的动态IDT(含IST机制),IDT的演进始终围绕“更安全、更高效、更灵活”的目标,是操作系统从简单单任务(DOS)走向复杂多任务(Windows/Linux)的关键硬件基础。无论是日常的键盘输入、硬盘I/O,还是内核的异常处理、系统调用,都依赖IDT的“导航”功能,是计算机稳定运行的核心组件。
中断向量号
在x86/x86-64架构中,中断向量是8位标识(编号0-255),每个向量唯一对应一类“中断/异常事件”,其类型划分严格遵循硬件标准,核心按“CPU保留范围”和“用户可配置范围”区分。以下列表详细拆解每个向量(或向量范围)对应的事件类型、触发源、处理特点及典型场景,清晰覆盖架构定义与实际应用:
一、CPU保留中断向量(0-31):绑定核心异常与不可屏蔽中断
该范围由CPU硬件固定定义,不可由操作系统修改,对应内部异常(98%) 和1个不可屏蔽中断(NMI),是系统运行的“基础错误/特殊事件处理通道”。
向量编号 | 向量类型(事件类别) | 所属大类(中断/异常) | 触发源/触发条件 | 处理特点 | 典型场景 |
---|---|---|---|---|---|
0 | 除法错误(Divide Error) | 异常-故障 | 执行DIV /IDIV 指令时:1. 除数为0; 2. 商溢出目标寄存器 | 不可恢复,触发进程崩溃(如Linux发送SIGFPE ) | C语言1/0 、汇编DIV BX (BX=0) |
1 | 调试异常(Debug Exception, #DB) | 异常-陷阱 | 1. 调试寄存器(DR0-DR7)匹配(如断点地址、数据访问); 2. 单步执行(TF标志=1); 3. INT 1 指令 | 调试工具核心,处理后执行下一条指令 | GDB单步调试、设置内存断点 |
2 | 不可屏蔽中断(NMI) | 中断-不可屏蔽 | 硬件致命故障: 1. 内存ECC错误、CPU过热; 2. 电源故障预警 | 优先级最高,强制响应,64位需绑定IST2栈 | 服务器内存硬件损坏、工业设备紧急停机信号 |
3 | 断点中断(Breakpoint, #BP) | 异常-陷阱 | 执行INT 3 指令(单字节 opcode:0xCC) | 用户态可主动触发,处理后跳至下一条指令 | 调试器插入0xCC 设置断点 |
4 | 溢出错误(Overflow, #OF) | 异常-故障 | 执行INTO 指令时,OF (溢出标志)=1 | 可恢复(调整运算精度),不重试INTO | 汇编ADD AX, 0x7FFF 后INTO (AX溢出) |
5 | 边界检查错误(#BR) | 异常-陷阱 | 执行BOUND 指令时,操作数超出指定范围(如数组越界) | 可恢复(修正索引),处理后执行下一条指令 | 汇编BOUND CX, [SI] (CX > [SI+2]) |
6 | 非法指令(Invalid Opcode, #UD) | 异常-故障 | 1. 执行未定义 opcode(如0x0F 0x0B); 2. 32位指令在64位模式执行; 3. 特权指令在用户态执行 | 不可恢复,终止进程(SIGILL ) | 编译错误生成无效指令、恶意代码注入非法 opcode |
7 | 设备不可用(Device Not Available, #NM) | 异常-故障 | 1. 执行浮点指令(FPU/SSE)但协处理器未初始化; 2. 64位模式下访问32位FPU状态 | 可恢复(初始化协处理器),重试指令 | 首次执行sin() (浮点函数)未初始化FPU |
8 | 双重故障(Double Fault, #DF) | 异常-终止 | 处理一个异常时,又触发另一个未处理异常(如页错误中访问非法内存) | 64位需绑定IST1栈,处理失败则重启 | 内核驱动bug(如#PF处理程序指针越界) |
9 | 协处理器段越界(Coprocessor Segment Overrun) | 异常-终止 | 早期FPU访问超出段范围(现代CPU已废弃,映射为#GP) | 不可恢复,终止进程 | 老旧DOS程序使用FPU访问非法段 |
10 | 无效TSS(Invalid TSS, #TS) | 异常-故障 | 任务切换时TSS非法: 1. TSS段选择子无效; 2. TSS栈地址越界 | 部分可恢复(修复TSS),多数终止 | 32位多任务系统TSS配置错误 |
11 | 段不存在(Segment Not Present, #NP) | 异常-故障 | 访问的段(代码/数据)在GDT/LDT中“P位=0”(未加载) | 可恢复(加载段到内存),重试指令 | 内存紧张时,段被换出到磁盘后访问 |
12 | 栈错误(Stack Fault, #SS) | 异常-故障 | 1. 栈访问越界(超出栈段范围); 2. 栈段P位=0; 3. 栈权限不足 | 部分可恢复(扩展栈/加载段) | 递归过深导致栈溢出、栈段被换出后访问 |
13 | 一般保护错误(General Protection Fault, #GP) | 异常-故障 | 最广泛的权限/合法性错误: 1. 用户态访问内核段; 2. 写只读内存; 3. IDT表项非法 | 部分可恢复,多数终止(SIGSEGV ) | 指针越界访问内核内存、修改const 变量 |
14 | 页错误(Page Fault, #PF) | 异常-故障 | 虚拟内存访问错误: 1. 页未映射(P位=0); 2. 权限不足; 3. 页被换出 | 完全可恢复(分配页/加载页),重试指令 | 首次访问动态内存、内存不足时页被换出 |
15 | 保留(Reserved) | - | CPU硬件预留,无定义 | 触发#GP(一般保护错误) | 非法访问该向量(如INT 15 未配置) |
16 | x87 FPU错误(x87 Floating-Point Error, #MF) | 异常-故障 | FPU运算错误: 1. 除零、溢出、NaN操作; 2. FPU状态字错误 | 可恢复(修正运算),重试指令 | 浮点运算sqrt(-1) 、log(0) |
17 | 对齐检查错误(Alignment Check, #AC) | 异常-故障 | 1. 非对齐访问(如16位数据存奇地址); 2. AC 标志=1 | 可恢复(调整访问地址) | 结构体未对齐(如struct {char a; int b;} 未加aligned ) |
18 | 机器检查异常(Machine Check Exception, #MC) | 异常-终止 | CPU硬件故障: 1. 缓存错误、总线错误; 2. 指令执行单元故障 | 不可恢复,记录日志后停机 | 服务器CPU缓存损坏、内存插槽接触不良 |
19 | SIMD浮点异常(SIMD Floating-Point Exception, #XM) | 异常-故障 | SSE/AVX指令运算错误(如溢出、除零) | 可恢复(修正运算),重试指令 | _mm_add_ps (SSE加法)溢出 |
20 | 安全异常(Security Exception, #SX) | 异常-终止 | 违反CPU安全机制: 1. SGX enclaves权限违规; 2. 内存加密错误 | 终止进程/虚拟机,防止安全漏洞 | SGX应用越权访问加密内存、AMD SEV权限错误 |
21-31 | 保留(Reserved) | - | CPU硬件预留(未来扩展) | 触发#GP(一般保护错误) | 非法访问该范围向量(如INT 25 ) |
二、用户可配置中断向量(32-255):绑定可屏蔽中断与软件中断
该范围由操作系统通过APIC(高级可编程中断控制器)动态配置,对应外部可屏蔽中断和软件主动触发的中断,是系统与外设交互、用户态调用内核的核心通道。
向量范围 | 向量类型(事件类别) | 所属大类(中断/异常) | 触发源/触发条件 | 处理特点 | 典型场景 |
---|---|---|---|---|---|
32 | 定时器中断(Timer Interrupt) | 中断-可屏蔽 | 系统定时器(如PIT/HPET)定时周期到(通常1ms) | 操作系统核心中断,用于进程调度、计时 | Linux的jiffies 计时、Windows线程时间片切换 |
33 | 键盘中断(Keyboard Interrupt) | 中断-可屏蔽 | 键盘按键按下/弹起,产生扫描码 | 读取扫描码→转换为ASCII→存入内核缓冲区 | 按下键盘“A”键,触发中断处理字符输入 |
34-47 | 传统PIC设备中断 | 中断-可屏蔽 | 早期8259A PIC控制器管理的设备: 34:串口1; 35:串口2; 36:并行口1; 37:软盘; 38:并行口2; 39:保留; 40:实时时钟(RTC); 41-47:保留 | 现代系统多弃用PIC,改用APIC动态分配 | 老旧电脑使用软盘、并行口打印机 |
48-254 | 现代APIC设备中断 | 中断-可屏蔽 | 由I/O APIC分配的外部设备: - 网卡(如Intel i219); - 硬盘(SATA/NVMe); - USB控制器; - 声卡、显卡; - 处理器间中断(IPI) | 支持“中断共享”(多设备共用向量); 可绑定到指定CPU核心(中断亲和性) | 网卡接收数据包、NVMe硬盘I/O完成、USB鼠标移动 |
255 | 处理器间中断(IPI-特殊) | 中断-可屏蔽 | 多核心CPU间的控制信号: 1. 唤醒休眠核心; 2. 负载均衡; 3. TLB刷新 | 无外部设备参与,由Local APIC发起 | Linuxsmp_send_reschedule (调度请求)、多核TLB同步 |
128 | 系统调用(System Call) | 异常-陷阱(软件触发) | 32位系统:INT 0x80 指令;64位系统: SYSCALL 指令(映射到向量128) | 用户态→内核态的核心通道,DPL=3(允许用户态触发) | Linuxwrite /read 系统调用、WindowsCreateProcess |
其他未用向量(如60-80) | 自定义软件中断/驱动中断 | 中断-可屏蔽/陷阱 | 1. 驱动程序主动触发(如INT 0x60 );2. 专用硬件(如FPGA)中断 | 按需配置处理逻辑,支持用户态/内核态触发 | 工业控制设备自定义中断、驱动调试信号 |
三、中断向量类型核心属性总结
向量范围 | 所有权 | 事件类型主导 | 可配置性 | 典型用途 |
---|---|---|---|---|
0-31 | CPU硬件 | 异常(97%)+ NMI(3%) | 不可配置 | 错误处理、调试、硬件致命故障 |
32-255 | 操作系统 | 可屏蔽中断(90%)+ 软件中断(10%) | 完全可配置 | 外设I/O、进程调度、系统调用、多核同步 |