中断和异常

本文详细介绍了计算机系统中中断和异常机制的工作原理。中断由外部设备触发,使CPU执行相应的中断处理程序;异常则源于CPU内部,如程序错误或特殊指令。文章还探讨了不同类型的异常及其处理方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在计算机系统中,包括任务切换、时间更新、软件调试在内的很多功能都是依靠中断和异常机制实现的。
中断

中断通常是由CPU外部的输入输出设备(硬件)所触发的,供外部设备通知CPU“有事情需要处理”,因此又叫中断请求。
中断请求的目的是希望CPU暂时停止执行当前正在执行的程序,转去执行中断请求所对应的终端处理例程(Interrupt Service Routine,ISR)。

有些任务是不能被打断的,为了防止CPU在执行这些任务的时候被打断,可以通过执行CLI(clear interrupt)指令清除标志寄存器的IF位,使得此时的CPU不会被“打扰”
有个特殊的东西:一旦有不可屏蔽中断(Non-Maskable Interrupt,NMI)发生时,CPU要立即转去处理。【这种情况非常少】
异常

异常就是满足了CPU内部定义的一些特定条件而产生的 同步事件。
异常来源:

  1. 程序错误(比如除零)
  2. 特殊指令(INT3 ==》 断点异常)
  3. 机器检查异常:CPU执行指令期间检测到CPU内部或外部的硬件错误
异常的分类
  • 错误类异常
    导致错误异常的情况通常可以被纠正,而且一旦纠正后,程序可以无损失地恢复执行。(比如内存页错误(page fault))
    CPU报告错误类异常时,CPU将其状态恢复成导致该异常的指令被执行之前的状态。而且在CPU转去执行异常处理程序前,在栈中保存的CS和EIP指针是指向导致异常的这条指令,所以,当异常处理程序返回继续执行时,CPU接下来被执行的第一条指令仍然是刚才导致异常的那条指令。【如果导致异常的情况还没有被消除,那么CPU会再次产生异常】
  • 陷阱类异常
    导致陷阱类异常的情况通常可以无损失地恢复执行。(比如INT3导致的断点异常就属于陷阱类异常)。
    当CPU报告陷阱类异常时,导致该异常的指令已经执行完成,压入栈的CS和EIP的值是导致该异常的指令执行后接着要执行的下一条指令。【不一定是相邻的指令(比如异常的那一句是跳转指令)】
  • 中止类异常
    中止类异常主要用来报告严重的错误(比如硬件错误和系统表中包含非法值),这种异常是不允许恢复继续执行的
    比如:栈溢出等
    在这里插入图片描述
    在这里插入图片描述
中断/异常优先级

多个异常同时发生时,按照优先级处理:
在这里插入图片描述在这里插入图片描述

异常分发

内核服务NtRaiseException是产生软件异常的主要方法,用户态代码可以通过RaiseException这个API来调用此内核服务。 NtRaiseException内部会调用KiRaiseException,KiRaiseException再调用内核函数KiDispatchException进行异常分发。

对于CPU级别的异常,CPU会通过IDT表寻找异常的处理函数入口(也就是KiTrapXX例程)。对于需要按异常流程分发的异常,KiTrapXX例程会调用CommonDispatchException准备必要的参数,然后调用KiDispatchException进行异常分发。

<think>我们正在讨论中断异常的处理机制及流程。根据引用内容,中断异常是处理器响应外部事件或内部错误的方式。下面我将结合引用内容,详细解释中断异常的处理机制及流程。 ### 1. **中断(Interrupt)** 中断是由外部设备或事件引起的异步事件,会打断处理器的当前执行流程。 #### 处理流程: 1. **中断请求(IRQ)**:外部设备(如磁盘、键盘)通过中断控制器向CPU发送中断请求信号[^1]。 2. **中断响应**: - CPU在每条指令执行结束后检查中断请求。 - 若中断请求存在且未被屏蔽,则响应中断: - 保存当前执行上下文(程序计数器PC、状态寄存器等)到堆栈或专用寄存器。 - 关闭中断(防止嵌套中断,除非支持中断优先级)。 3. **中断处理**: - CPU根据中断向量号(由中断控制器提供)从中断描述符表(IDT)中获取中断处理程序的入口地址。 - 跳转至中断处理程序执行: - 保存现场(通用寄存器等)。 - 执行设备服务(如读取键盘输入)。 - 发送EOI(End of Interrupt)信号给中断控制器。 4. **中断返回**: - 恢复现场(寄存器)。 - 执行中断返回指令(如`IRET`),恢复之前保存的上下文并继续执行原程序。 #### 中断类型(引用[2]): - **I/O设备中断**:磁盘、网卡、键盘等。 - **时钟中断**:定时器周期性触发,用于任务调度。 - **非可屏蔽中断(NMI)**:硬件故障等紧急事件。 - **处理器间中断(IPI)**:多核系统中用于核间通信[^2]。 ### 2. **异常(Exception)** 异常是处理器执行指令时检测到的同步事件(如除零错误),分为三类(引用[3]): 1. **故障(Fault)**:可修复的错误(如页错误)。处理流程: - CPU保存当前状态,跳转到异常处理程序。 - 处理程序修复问题(如加载缺失的页)后,重新执行触发异常的指令。 2. **陷阱(Trap)**:用于调试(如断点)。处理流程: - 保存状态后执行处理程序。 - 处理完成后继续执行触发指令的下一条指令。 3. **中止(Abort)**:严重错误(如硬件故障)。处理流程: - 系统可能直接终止进程或重启。 #### 异常处理流程: 1. **异常检测**:执行指令时由CPU硬件检测(如除零、非法指令)。 2. **异常响应**: - 立即停止当前指令。 - 保存上下文(PC、状态寄存器等)。 3. **异常处理**: - 根据异常类型(向量号)查询IDT,跳转到对应的异常处理程序。 - 执行错误处理(如终止进程或修复错误)。 4. **异常返回**: - 故障类异常:返回触发指令重新执行。 - 陷阱类异常:返回触发指令的下一条指令。 ### 3. **中断异常的对比** | **特性** | **中断** | **异常** | |----------------|-----------------------------|-----------------------------| | 触发源 | 外部设备 | CPU执行指令时检测到错误 | | 同步性 | 异步(随机发生) | 同步(由特定指令触发) | | 是否可屏蔽 | 部分可屏蔽(NMI除外) | 不可屏蔽 | | 处理目标 | 响应设备请求 | 处理错误或调试 | | 返回行为 | 返回原指令的下一条 | 故障:返回原指令;陷阱:返回下一条 | ### 4. **中断/异常处理的关键机制** - **中断描述符表(IDT)**:存储中断/异常处理程序的入口地址(引用[4])。 - **中断控制器**:管理多个中断源(如APIC、PIC)。 - **上下文保存**:通过硬件自动完成(如`pushad`指令)。 - **嵌套处理**:高优先级中断可打断低优先级处理程序(需硬件支持)。 ### 5. **处理流程代码示例(简化)** 引用[4]展示了一个中断分发器的伪代码: ```c void _global_interrupt_handler(intptr_t sp, int mcause) { intr_handler_item_t it = s_intr_handlers[mcause]; // 根据中断原因查询处理函数 if (it.handler) { (*it.handler)(it.arg); // 调用注册的中断处理函数 } } ``` > **说明**:`mcause`寄存器存储中断/异常原因码,通过查表调用对应的处理函数[^4]。 ### 6. **实际案例:Linux内核处理流程** 1. **中断入口**(汇编):保存现场,调用`do_IRQ()`。 2. **中断处理**(C语言): - 调用设备驱动注册的中断服务例程(ISR)。 - 处理中断共享优先级。 3. **中断退出**:恢复现场,执行调度(若需要)。 --- §§相关问题§§ 1. 在多核系统中,如何通过处理器间中断(IPI)实现缓存一致性? 2. 页错误(Page Fault)异常的处理流程是怎样的? 3. 非可屏蔽中断(NMI)通常用于处理哪些紧急情况? 4. 中断描述符表(IDT)在操作系统中是如何初始化的? 5. 硬件中断软件中断(如`INT 0x80`系统调用)的处理机制有何异同?</think>### 中断异常处理机制及流程详解 #### 1. **基本概念与分类** - **中断(Interrupt)**:由**外部硬件事件**触发的异步信号(如键盘输入、时钟信号)[^3] - 可屏蔽中断(INTR):可通过中断屏蔽寄存器忽略 - 非可屏蔽中断(NMI):必须立即处理的严重事件(如硬件故障)[^2] - **异常(Exception)**:由**CPU执行指令**触发的同步事件[^3] - 故障(Fault):可修复错误(如页错误) - 陷阱(Trap):调试中断(如断点) - 中止(Abort):不可恢复错误(如硬件故障) #### 2. **中断处理流程** ```mermaid sequenceDiagram participant H as 硬件设备 participant C as CPU participant I as 中断控制器 participant M as 内存(IDT) participant H as 处理程序 H->>I: 1. 发送中断请求(IRQ) I->>C: 2. 转发中断信号 C->>C: 3. 保存现场(EFLAGS, CS, EIP) C->>M: 4. 查询IDT获取处理程序地址 C->>H: 5. 跳转执行中断处理程序 H->>I: 6. 发送EOI(中断结束命令) H->>C: 7. 恢复现场(IRET指令) ``` 具体步骤: 1. **中断请求**:设备通过IRQ线发送请求到中断控制器(如APIC)[^1] 2. **中断响应**: - CPU完成当前指令后检查中断请求 - 保存状态寄存器(EFLAGS)返回地址(CS:EIP)到内核栈 3. **中断分发**: - 通过中断向量号查询中断描述符表(IDT)[^4] - 获取中断处理程序入口地址(如`_global_interrupt_handler`) 4. **处理程序执行**: - 保存通用寄存器状态 - 执行设备服务(如读取键盘缓冲区) - 发送EOI信号通知中断控制器[^2] 5. **中断返回**: - 恢复寄存器状态 - 执行`IRET`指令返回原程序 #### 3. **异常处理流程** ```mermaid graph TD A[指令执行] --> B{检测异常} B -->|无异常| C[继续执行] B -->|有异常| D[保存现场] D --> E[查询IDT] E --> F{异常类型} F -->|故障 Fault| G[修复后重试指令] F -->|陷阱 Trap| H[继续下条指令] F -->|中止 Abort| I[终止进程] ``` 关键差异点: - **同步触发**:异常在特定指令执行时立即发生(如除零错误) - **无EOI信号**:异常处理无需通知外部控制器 - **返回行为**: - 故障:返回触发指令重新执行(如页错误修复后) - 陷阱:返回下一条指令(如断点调试) #### 4. **多核处理机制** - **处理器间中断(IPI)**: - 核心A通过ICR(中断命令寄存器)向核心B发送中断[^2] - 用途: - 任务调度(唤醒空闲核心) - TLB一致性维护(TLB shootdown) - 系统关闭信号广播 - **中断性**:将特定设备中断绑定到指定CPU核心 #### 5. **关键数据结构** - **中断描述符表(IDT)**: ```c struct idt_entry { uint16_t offset_low; // 处理程序地址低16位 uint16_t selector; // 代码段选择子 uint8_t ist; // 中断栈表 uint8_t attributes; // 门类型(P=1表示有效) uint16_t offset_mid; // 处理程序地址中16位 uint32_t offset_high; // 处理程序地址高32位 uint32_t reserved; } __attribute__((packed)); ``` - **中断处理注册**(引用[4]示例): ```c void _global_interrupt_handler(intptr_t sp, int mcause) { intr_handler_item_t it = s_intr_handlers[mcause]; if (it.handler) { (*it.handler)(it.arg); // 执行注册的处理函数 } } ``` #### 6. **优先级与嵌套** - **中断优先级**: 1. 机器检查 > NMI > 硬件中断 > 陷阱 > 故障 - **嵌套处理**: - 高优先级中断可打断低优先级处理程序 - 内核栈保存多层执行上下文(最多5-8层) #### 7. **典型场景示例** 1. **时钟中断**: - IRQ0触发 → 更新系统时间 → 执行任务调度 2. **页错误异常**: - 访问无效地址 → 触发#PF异常 → 内核分配物理页 → 重试指令 3. **系统调用**: - 执行`INT 0x80` → 陷入内核 → 根据EAX值分发系统调用 > **性能指标**: > 中断延迟 $t_{latency} = t_{detect} + t_{save} + t_{dispatch}$ > 现代系统典型值:$\leq 10\mu s$ (实时系统要求 $\leq 1\mu s$) ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值