3. CPU 和指令系统|中断机制
重要的四个概念区分
| Interrupts | Exceptions | Trap | System call |
|---|---|---|---|
| Interrupts are asynchronous events triggered by external devices. | Exceptions are synchronous events caused by instruction execution. | A trap is a synchronous transfer of control to the OS, typically used for system calls or debugging. Traps are a type of exception that return to the next instruction. |
System calls are implemented via traps. A system call is a controlled entry point into the kernel. |
| 中断的特点: * 来自于硬件 * 和 CPU 当前正在执行的指令无关,是异步的. * 例如键盘输入、磁盘完成、时钟中断、网络包到达。 目的是通知 CPU 有硬件事件发生,需要 OS 介入处理。 |
异常的特点 * 是 CPU 执行某个指令的过程中发生的,和当前正在执行的指令是同步的。 * 例如除 0、page fault(缺页、也叫缺页中断)、访问越界。 |
* Trap 本质是一种特殊的异常(a sub class of exceptions),由软件主动触发,和当前执行的指令是同步的。 * 用途:系统调用(syscall)、断点 (breakpoint))、调试陷阱 (debug trap) * 和 Exceptions 的区别是 Trap 是故意触发的,而 Exceptions 是错误,是预期之外的。 |
* 系统调用就是用户程序通过 trap 指令主动让 CPU 转入内核态,来执行内核服务。 |
| 【注:408 中管 Exceptions 叫做内部中断。即 408 中没有这些区分,Interrupts 和 Exceptions 通通叫中断,然后把中断分了个内部中断和外部中断,纯纯傻逼行为。】 | |||
| 【Trap 和 System call 也是,统称为系统调用。】 |
中断机制
中断的本质是硬件或者 CPU 主动打断当前执行的流程,让内核处理事件的一种通知机制。整个过程由硬件+软件一起完成。
中断可以分为两类,根据是不是发生在 CPU 核心内部(ALU、寄存器、流水线等),分为内部中断和外部中断。
内部中断例如 ALU 中除 0、MMU 中缺页,
外部中断例如计时器到时、硬盘、键盘、网卡等(计时器虽然封装在 CPU 里,但是属于 CPU 的外围设备,不在 Core 里)
进程 P 通过执行系统调用从键盘接受一个字符输入的过程:
- 【用户程序调用】用户进程执行
read(STDIN_FILENO, buf ,1),触发trap,在x86中叫做syscall.- 触发
trap后,硬件自动完成以下- 保存当前用户态寄存器
- 切换到内核态
- 切换到内核栈
- 跳转到系统调用入口
syscall_entry
- 触发
- 【内核程序处理】内核执行对应的系统调用函数(假设为 sys_read, 通过 syscall_entry 进入),内核检查键盘缓冲区为空,故 read 无法立刻返回。于是内核将程序 P 放入到阻塞队列中. 并通过
schedule()切换到另外一个进程执行。 - 【用户通过硬件发中断】用户在键盘上输入字符,键盘控制器向 CPU 发送硬件中断,CPU 响应
- 自动切换到内核态(如果此时 CPU 是用户态的话)
- 自动保存当前执行现场(现场:context 是包含断点的,断点指的是程序计数器 PC、程序状态字等信息。)
- 断点:由硬件(也叫中断隐指令)保存完成,包含 PC 计数器、程序状态字等信息。
- 其他寄存器由软件完成,在对应的
syscall_entry的汇编程序的入口。
- 根据 IDT 跳转到对应的中断服务例程(ISR)
- 【内核的中断处理程序执行】启动键盘中断处理程序(ISR)
- ISR 只扫描哪个按钮按下, 然后传递给键盘驱动程序。
- 键盘驱动程序继续处理。
- 将字符从键盘控制器读入系统缓冲区(键盘驱动程序做的事情:将按钮映射为键值、处理修饰键、更新键盘状态、写入 input event ring buffer、通过
wake_up()唤醒被阻塞的进程) - 将进程 p 插入到就绪队列(是键盘驱动程序做的)
- 将字符从键盘控制器读入系统缓冲区(键盘驱动程序做的事情:将按钮映射为键值、处理修饰键、更新键盘状态、写入 input event ring buffer、通过
- 【又调度到了用户程序】进程 P 从系统调用返回(C 语言层面)
- 系统调用出口(内核汇编层)
- CPU 执行iretq 汇编指令,CPU 返回到用户态。
- 执行之前的指令(Exceptions 类,例如缺页中断)或执行下一条指令(外部中断、Trap、System Call,例如键盘输入)。
中断的过程为:
- 保护现场(现场 context 是包含断点的,断点指的是程序计数器 PC、程序状态字等信息。)
- 切换到内核态
- 查找 IDT(中断描述符表)
- 跳转到对应的中断处理程序(这些中断处理程序并不一定都是内核本来就带的,可能是设备制造商的驱动程序,不过这种驱动程序本身就是内核代码的一部分)
- 处理完成后通过 iret 返回先前执行点,执行中断前的指令(缺页中断,要重新执行)或者下一条指令(硬件中断,例如键盘输入)。
对比系统调用:
- 保存当前执行状态(用户态寄存器)
- 切换到内核态
- 切换到内核栈
- 跳转到系统调用表处理对应的函数(这些系统调用函数都是内核的)
- 执行完成后返回用户态,执行下一条指令。