- 中断
- 中断识别码
- 中断描述符(ID 中断向量)
- 中断描述符表(IDT 中断向量表)
- 中断描述符表寄存器(IDTR)
- CPU 中断当前执行的程序,将 PC 指针跳转到一个固定的位置,我们称为一次中断(interrupt)。
中断可以分为中断和异常,异常又可以分为故障、陷阱、中止。
给 CPU 一个中断号有三种方式
a.中断是一个异步事件,通常由 IO 设备触发,比如点击一下鼠标、敲击一下键盘等。 可编程中断控制器 IRQ 引脚线 -> CPU INTR 引脚 -> INTR 引脚信号 -> 中断号 -> CPU
b.异常是一个同步事件,是 CPU 在执行指令时检测到的反常条件。比如除法异常、错误指令异常,缺页异常等。
c.INT 指令 INT 指令后面跟一个数字,就相当于直接用指令的形式,告诉 CPU 一个中断号 比如 INT 0x80,就是告诉 CPU 中断号是 0x80。Linux 内核提供的系统调用,就是用了 INT 0x80 这种指令
- 无论是中断还是异常,最终都是通过各种方式,让 CPU 得到一个中断号。只不过中断是通过外部设备给 CPU 的 INTR 引脚发信号,异常是 CPU 自己执行指令的时候发现特殊情况触发的,自己给自己一个中断号。
- 上面不管是因为硬件触发中断还是软件触发中断,都是由硬件实现的中断,因此都称为硬中断。为什么叫硬中断呢?因为这是 Intel CPU 这个硬件实现的中断机制,注意这里是实现机制,并不是触发机制,因为触发可以通过外部硬件,也可以通过软件的 INT 指令。
- 对应的由软件实现的中断,是纯粹由软件实现的一种类似中断的机制,实际上它就是模仿硬件,在内存中有一个地方存储着软中断的标志位,然后由内核的一个线程不断轮询这些标志位,如果有哪个标志位有效,则再去另一个地方寻找这个软中断对应的中断处理程序。
- 我们需要把不同的中断类型进行分类,这个类型叫作中断识别码。比如按键,我们可以考虑用编号 16,数字 16 就是按键中断类型的识别码。
- 不同类型的中断发生时,CPU 需要知道 PC 指针该跳转到哪个地址,这个地址,称为中断向量(Interupt Vector)
中断描述符表这个数组里的存储的数据结构,是一个叫 desc_struct 的结构
struct desc_struct {
unsigned long a,b;
};
Linux 源码中,一个中断描述符的大小为 64 位,也就是 8 个字节
4. 维护不同中断识别码与中断向量的对应关系,如果设计最多有 255 个中断,编号就是从 0~255,刚好需要 一定空间的内存地址存储中断向量。这个空间,称为中断向量表。
操作系统初始化过程中,有很多结构都称之为 XXX 表,其实就是个数组罢了
以 linux-2.6.0 源码为例
struct desc_struct idt_table[256] = { {0, 0}, };
- 中断描述符表寄存器
中断描述符表在哪里,全凭各个操作系统的喜好,想放在哪里就放在哪里,但需要通过某种方式告诉 CPU,CPU 提前预留了一个寄存器叫 IDTR 寄存器,这里面存放的就是中断描述符表的起始地址,以及中断描述符表的大小。
操作系统的代码可以通过 LIDT 指令,将中断描述符表的地址放在这个寄存器里。操作系统启动时将除法异常、非法指令异常、缺页异常,以及之后可能通过 INT 0x80 触发系统调用的中断处理函数 system_call,就是这样被写到了中断描述符表里
https://mp.weixin.qq.com/s/bTfeI5p4eO5j6I9edeV73g
https://kaiwu.lagou.com/course/courseInfo.htm?courseId=478#/detail/pc?id=4622