linux 中断

 

参考

概念

中断是指CPU对系统发生某事件时, 暂停正在执行程序, 在保留现场后自动地转去执行该事件中断处理程序, 执行完后, 再返回到原程序断点处继续执行的一种响应

发生异常(exception)和中断(interrupt)事件后, 系统将进入OS内核态对相应事件进行处理

类别

graph LR;
    X(事件)
    X-->A(中断/外中断)
        A-->A1(I/O中断)
        A-->A2(时钟中断)
        A-->A3(硬件故障)
    X-->B(异常/内中断)
        B-->B1(系统调用)
        B-->B2(页故障/错误)
        B-->B3(保护性异常)
        B-->B4(断点指令)

外中断(中断)

graph TB;
    subgraph S[中断]
        A(硬件设备产生)--发送-->B(处理器)--通知-->C(操作系统/内核)
    end

指中断, 是指由于外部设备事件所引起中断, 如磁盘中断、打印机中断等

中断是由于系统中某事件引起, 该事件与现行指令无关

可屏蔽中断

I/O设备发出所有中断请求(IRQ)都产生可屏蔽中断

通过INTR(中断请求信号, 高电平有效)向 CPU 请求, 可通过设置屏蔽字来屏蔽请求

若中断请求被屏蔽, 则不会被送到CPU

非屏蔽中断

危急时机, 如硬件故障引起, 由CPU辨认, 通过NMI(不可中断信号)向 CPU 请求

一旦产生, 就被立即送 CPU以便快速处理, 中断服务程序会尽快保存系统重要信息, 然后在屏幕上显示相应消息或直接重启系统

  • 示例, 网卡中断流程

(1) 数据到达网卡

(2) 网卡产生一个中断给内核

(3) 内核使用I/O指令, 从网卡I/O区域中去读取数据

内中断(异常)

graph TB;
    subgraph S[异常]
        A(处理器)--通知-->B(操作系统/内核)
    end

指异常, 是指由于CPU内部事件所引起中断, 如程序出错(非法指令、地址越界), 也被译为”捕获”或”陷入”

异常是由于执行了现行指令所引起, 由于系统调用所引起中断属于异常

故障

执行指令所引起异常, 如缺页、越权、越级、溢出、非法指令, 断点为故障发生地方

陷阱

预先安排事件, 如调试程序时断点, 单步跟踪, 系统调用, 是一种自愿中断, 断点为自陷指令下一条指令

终止

不可恢复错误, 如硬件故障事件, 此时机器会终止, 调出中断服务程序来终止程序甚至重启操作系统

异常类别

除零异常

当系统返现除零时, 会抛出异常, 若程序不处理这个异常, 那么操作系统将发出一个异步信号终止当前执行程序

对比

相同点

都是CPU对系统发生某个事情所做出一种反应, 最后都是由CPU发送给内核, 由内核去处理

区别

分类 中断 异常
产生地点 处理器外部, 由与运行程序无关中断信号触发 处理器内部, CPU控制单元产生
能否被屏蔽 高优先级中断可屏蔽低优先级中断 不可被屏蔽
处理程序能否被阻塞 不能被阻塞, 处理器休要即使响应中断信号 可以被阻塞
CPU 与CPU异步, 无论处理器处于什么状态都需处理外部中断请求 与CPU异步
能否嵌套 允许嵌套, 一般不超过三重 大多为一重
相互之间影响 中断过程不会产生异常 异常处理过程中可能产生中断

概念

中断向量

每个异常和中断由0~255间数标识, 称为中断向量(vector)

中断向量表

存放中断向量到中断执行程序地址映射

部分映射需在内核初始化开启中断前完成设置, 也能够后续执行过程中动态修改与添加映射

通过在指令操作数中提供中断向量号, INT n 指令可用于从软件中产生中断

例如, 指令 INT 0x80 会执行linux系统中断调用中断0x80. 向量0到255中任何一个都可以用作INT指令中断号

graph LR;
    subgraph 中断向量表
        A(0  ~ 19)
        B(32 ~ 127)
        C("128(0x80)")
        D(129 ~ 238)
    end
    
    A1(不可屏蔽中断与异常)
        A1-->A11(0 - 除零)
        A1-->A12(1 - 单步调试)
        A1-->A13(4 - 算术溢出)
        A1-->A14(6 - 非法操作数)
        A1-->A15(12 - 栈异常)
        A1-->A16(13 - 保护性错误)
        A1-->A17(14 - 缺页异常)
    B1(外部中断IRQ)
    C1(系统调用可编程异常)
    D1(外部中断)
    
    A --> A1
    B --> B1
    C --> C1
    D --> D1

中断执行程序

中断向量对应所执行程序, 用于执行具体中断逻辑, 需用户自定义

中断执行流程

CPU在执行过程中, 触发中断, 而后CPU根据触发中断携带的中断向量, 从中断向量表中找出中断执行程序, 跳转执行中断执行程序, 执行完成再跳回中断前程序执行

处理流程

graph LR;
    subgraph 用户空间
        X(进程)
    end

    subgraph 内核空间
        A(保存上下文)

        subgraph 设备驱动程序
            B(中断处理函数)
        end
        
        C(中断处理)
        D(恢复上下文)
        E(外部设备)
        F(中断控制器)
        G(CPU)
    end

    用户空间 --> A --> B --> C --> D --> 用户空间
    设备驱动程序 --> E --> F --> G --中断-->用户空间

准备

保护现场

将各寄存器内容压入堆栈保存

判断中断

是否能够中断切换

开中断

允许高级版中断, 实现中断嵌套

执行

中断处理

跳转到中断处理代码处

中断控制器中有一个中断优先级判别器, 它自动判别出目前提出中断请求优先级中最高中断源, 并将其中断向量码送到数据总线, CPU接收中断向量码并据此找到其中断服务程序

收尾

关中断

保护恢复现场过程

恢复现场

将保存在堆栈中现场信息弹出到原来寄存器中

开中断

响应下一次中断

示例

键盘输入

那当用户输入了键盘字符, 键盘控制器就会产生扫描码数据, 并将其缓冲在键盘控制器寄存器中, 紧接着键盘控制器通过总线给 CPU 发送中断请求

CPU 收到中断请求后, 操作系统会保存被中断进程 CPU 上下文, 然后调用键盘中断处理程序

键盘中断处理程序是在键盘驱动程序初始化时注册, 键盘中断处理函数功能就是从键盘控制器寄存器缓冲区读取扫描码, 再根据扫描码找到用户在键盘输入字符

若输入字符是显示字符, 那就会把扫描码翻译成对应显示字符ASCII 码,

比如用户在键盘输入是字母 A, 是显示字符, 于是就会把扫描码翻译成 A 字符ASCII 码

得到了显示字符ASCII 码后, 就会把 ASCII 码放到「读缓冲区队列」, 显示设备驱动程序会定时从「读缓冲区队列」读取数据放到「写缓冲区队列

最后把「写缓冲区队列」数据一个一个写入到显示设备控制器寄存器中数据缓冲区, 最后将这些数据显示在屏幕里

显示出结果后, 恢复被中断进程上下文