此文档历史久远, 系学习过程中的知识整理, 难免存在疏漏, 欢迎批评指正!

IRQ

IRQ CPU会在以下场景中打断当前正在运行的指令, 转而去运行其他指令:

  • 外部设备完成了某个操作
  • 执行了未知指令
  • 访问了无法访问的内存
  • 某些特定事件被触发

中断理论上分为三种类型:

  • 外部中断, External Interrupt
    又叫硬件中断(Hardware Interrupt). 由外部硬件设备以异步的方式产生. 它一般通过触发CPU上对应的中断引脚来通知CPU对其进行处理, 这就是中断请求: IRQ.
    CPU会根据内部时钟不停的(Intel-i9-13900k 每隔10ns会检查一次)对引脚的电平进行检查, 如果发现电平变化了, 就知道IRQ请求来了, 于是会跳转到中断处理例程: ISR: Interrupt Service Routine.
    系统启动时, BIOS 会对ISR进行首轮初始化!
  • 内部中断, Internal Interrupt
    又叫异常(Exception). 一般由CPU内部的一些特殊事件触发:
    • /0 错误
    • 内存访问错误
    • 系统调用
  • 软中断, Software Interrupt
    又名自陷(Trap). 由指令触发,如 X86int 指令, 或 ARMswi 指令.
    由于是指令触发, 故是同步的(CPU会立即跳到ISR,而不会等待电平发生变化)

中断信号

中断信号分为两类:

  • 水平触发(level-sensitive) —- 没错!对应了 epoll 模型中的 level-triggered 参数!
    变化的电平会一直保持, 直到 ISR 处理完毕
  • 边缘触发(edge-triggered)
    电平仅变化一次. ISR 必须立即处理, 否则会导致中断信号丢失

如何区分多个设备的中断?

上面的模型过于简单, 未能描述清楚CPU如何区分不同设备的中断

计算机界解决复杂问题有一个老套路(请参考网络模型) —- 加一层 –> 中断控制器(PIC: Programmable Interrupt Controller)

PIC

PIC首次出现于 1976 年, 8085系列. 目前最新的Intel系列仍然使用

PIC帮助CPU将并发的,带优先级的中断信号, 转换成串行的中断信号, 简化了CPU的设计

IDTR

CPU使用了 IDTR(Interrupt Descriptor/Vector Table Register) 寄存器来保存中断向量表.
该寄存此有64位,高32位是表的起始地址,低16位描述表的大小.
当CPU收到中断时, 首先通过IDTR找到中断向量表, 然后通过该表再借助于 IVN(中断向量号,其有8个引脚连接着总线) 找到对应的 ISR(中断服务历程).
系统启动时OS会对ISR进行二次初始化!

IVN

中断向量号的区域划分

  • 0-31
    CPU保留的向量号, 用于CPU内部的异常处理, 硬编码
  • 32-255
    外部中断向量号. 可由BIOS或OS自行分配. 提供了每个设备对应的中断描述符.

IDTR的C描述

中断描述符包含了中断服务历程 ISR 的地址, 以及一些其他基本信息.
x86平台该结构大小: 8B
x86-64平台: 16B

struct idt_entry {
    uint16_t base_lo; // 中断服务例程的低16位,task gate没有这个字段
    uint16_t sel;     // 段选择子
    uint8_t  always0; // 保留字段,必须为0
    union {
        uint8_t  flags;   // 中断描述符标志
        struct {
            uint8_t type : 3;             // 中断门类型
            uint8_t size : 1;             // 中断门大小,0 = 16-bit, 1 = 32-bit
            uint8_t descriptor_type : 1;  // 描述符类型,0 = 系统描述符,1 = 代码或数据描述符,
                                          // 对于中断描述符来说,这个字段必须为0
            uint8_t dpl : 2;              // 描述符特权级(Descriptor Privilege Level)
            uint8_t p : 1;                // Segment Present Flag
        };
    };
    uint16_t base_hi; // 中断服务例程的高16位,task gate没有这个字段
} __attribute__((packed));

中断链

need to be improved

上下文恢复

need to be improved