Lec 9: Interrupts
- Ref: https://github.com/huihongxiao/MIT6.S081/tree/master/lec09-interrupts
- Preparation: xv6 book Chapter 5
概述
中断场景: 硬件需要得到操作系统的关注, 如网卡收到数据包, 用户按下按键
中断与系统调用, trap 机制相似.
- 中断与系统调用的不同
- 异步(asynchronous): 硬件生成中断时, Interrupt handler 中断处理程序与 CPU 上当前运行的进程无关; 而系统调用在进入内核后仍在调用进程的上下文 Context 中运行
- 并发(concurrency): CPU 和生成中断的设备是并行运行的, 设备和 CPU 之间有真正的并行
- 设备编程(program device): 主要关注外部设备
中断相关硬件
所有设备连接到处理器上, 处理器通过PLIC(Platform Level Interrupt Control)处理中断.
PLIC 会将终端路由到某一个 CPU 的核, 若所有 CPU 核都在处理中断, PLIC 会保留中断直到有可用 CPU. PLIC 需要保存一些内部数据跟踪中断的状态.
- 中断处理流程:
- 表示当前有一个中断, 等待一个 CPU 核心声称拥有它, 这样 PLIC 就不会将中断发个其他核心
- CPU 处理中断, 处理完成后会通知 PLIC
- PLIC 将清除该中断的信息
设备驱动
驱动: 管理设备的代码, 驱动都在内核中.
驱动一般分为两个部分(不是地址空间): 底部部分(bottom part)和顶部部分(top part).
- 底部部分: 通常是中断处理程序. CPU收到中断会调用此处的中断处理程序. 中断处理程序并不运行在特定进程的上下文中, 只是处理中断
- 顶部部分: 用户进程, 或者内核其余部分调用的接口. 对于 UART, 是 read/write 接口.
通常, 驱动中会有一些队列(缓冲区). 顶部部分代码和底部的中断处理程序都可以向队列进行读写. 队列使得驱动顶部和底部部分解耦, 运行设备和 CPU 上其他代码并行运行.
中断寄存器
- SIE(Supervisor Interrupt Enable)寄存器: 其中有 1 比特(E)专门处理外设中断, 1 个比特(S)处理软件中断, 1 个比特(T)处理定时器中断.
- SSTATUS(Supervisor Status)寄存器. 有 1 个比特控制中断的开关. 每个 CPU 有对立的 SIE 和 SSTATUS 寄存器.
- SIP(Supervisor Interrupt Pending)寄存器: 发生中断时, 处理器根据该寄存器获知当前中断的类型
- SCAUSE 寄存器: 中断产生的原因
- STVEC 寄存器: 保存中断程序地址
中断过程
- 前提: CPU 核设置了 SIE 寄存器的外部中断比特 (E)
- 硬件清除 SIE 寄存器的比特位, 阻止其他任何中断打断 CPU
- SEPC 寄存器记录当前程序计数器
- 保存当前的模式(用户/内核)
- 设置为内核模式(supervisor mode)
- 将程序计数器的值设置为 STVEC 寄存器的值
中断和并发
- 中断并发涉及的方面:
- 设备与 CPU 是并行运行的. 这里的并行为生产者/消费者并行
- 中断会停止当前运行的程序.
- 驱动的顶部(top)和底部(bottom)部分是并行运行的. 可以并行运行在不同 CPU, 通过锁管理并行.
- 生产者/消费者并行
- 环形队列
- 队空: 读指针 == 写指针
- 队满: 写指针+1 == 读指针. 队满时生产者会休眠.
中断的发展
过去: 中断处理得很快, 硬件可以设计的很简单
现在: 中断处理变慢, 需要很多步骤, 设备需要进行更多工作, 以减轻 CPU 处理负担
对于快速设备(高性能设备, 常规情况下 CPU 处理需要产生大量中断, 超过 CPU 本身处理能力)处理的方式是轮询(polling): CPU 不停轮询(spin)设备直到有数据, 但会浪费 CPU 周期(cycles).
对于慢设备, 不需要轮询, 而是在没有数据时 CPU 切换运行其他设备.