因为中断这块的知识和代码都占较大篇幅,所以分红两章来说,本章不包含任何中断的代码,只讲理论部分,以及中断的大概流程。代码实现部分由下一章来说解html
【自制操做系统09】中断的代码实现linux
为了让你们清楚目前的程序进度,画了到目前为止的程序流程图,以下。git
这里咱们先从形象的角度来描述,中断就是让操做系统中止手中正在进行的工做,先把中断信号对应的处理程序执行完毕,再回到以前的程序中继续进行,这样一个机制。编程
一个很形象的说法是,咱们的操做系统就是 中断驱动 的,能够把操做系统简单理解为一个 死循环,无时无刻不在等待中断的来临,被动 地执行相应的任务。数组
while(true){ 操做系统代码 }
外部中断经过两个引脚链接到 CPU 上,一个是可屏蔽中断 INTR,一个是不可屏蔽中断 NMIide
对于可屏蔽中断,Linux 的处理方式是分红 上半部 和 下半部。上半部执行时关闭中断,马上执行完毕;下半部执行时打开中断,此时若是有其余中断进来,则让给其余中断(也是上半部执行完毕)。学习
内部中断可分为 软中断 和 异常,两者均是不可屏蔽的(即不受 eflags 的 IF 位影响)测试
咱们知道一个中断对应着一个 中断号(中断向量号),下面列表说明操作系统
中断号 | 含义 | 来源 | 类型 | 是否有错误码 |
---|---|---|---|---|
0 | divide error | DIV and IDIV instructions | Fault | 无 |
1 | debug | any code or data reference | Fault/Trap | 无 |
2 | NMI Interrupt | NMI | Interrupt | 无 |
3 | Breakpoint | INT3 instruction | Trap | 无 |
4 | Overflow | INTO instruction | Trap | 无 |
5 | bound range exceeded | BOUND instruction | Fault | 无 |
6 | invalid opcode | UD2 instruction or reserved opcode.1 | Fault | 无 |
7 | device not available | floationg-point or WAIT/FWAIT instruction | Fault | 无 |
8 | double fault | any instruction that can generate an exception, an NMI, or an INTR | Fault | Y(0) |
9 | CoProcessor Segment Overrun | Floating-point instruction.2 | Fault | 无 |
10 | invalid TSS | task switch or TSS access | Fault | Y |
11 | segment not present | loading segment registers or accessing system segments | Fault | Y |
12 | stack segment fault | stack operations and SS register loads | Fault | Y |
13 | general protection | any memory reference and other protection checks | Fault | Y |
14 | page fault | any memory reference | Fault | Y |
15 | reserved | |||
16 | floating-point error | floating-point or WAIT/FWAIT instruction | Fault | 无 |
17 | alignment check | any data refrence in memory.3 | Fault | Y(0) |
18 | machine check | error codes and source are model dependent.4 | Fault | 无 |
19 | SIMD floating-point exception | SIMD floating-point instruction5 | Fault | 无 |
20-31 | reserved | |||
32-255 | maskable interrupts | External Interrupt from INTR pin or INT n instruction | Interrupt | 无 |
门 | type值 | 存在位置 | 用法 |
---|---|---|---|
任务门 | 0101 | GDT、LDT、IDT | 与TSS配合实现任务切换,不过大多数操做系统都不这么玩 |
中断门 | 1110 | IDT | 进入中断后屏蔽中断(eflags的IF位置0),linux利用此实现系统调用,int 0x80 |
陷阱门 | 1111 | IDT | 进入中断后不屏蔽中断 |
调用门 | 1100 | GDT、LDT | 用户用call或jmp指令从用户进程进入0特权级 |
你看,正如上一讲所说,中断门进入后先是屏蔽了中断,也就是中断例程的 上半部,程序中能够随时打开中断,也就天然到了 下半部,这就是 linux 系统的处理方式。debug
如何找到中断描述符表呢?你猜的没错,正如找 段描述符表,页表 等同样,有个 IDTR 寄存器存储它的位置(0-15位是表界限,16-47位表示表基址),有个 lidt 指令负责加载 IDTR。经典作法,咱们见过太屡次了,就很少说啦,不理解的能够从本系列开头开始看哟。
上图就表示了整个中断处理的过程,不过还有几处图中没有显示
特权级检查:CPL <= 门描述符DPL && CPL > 目标代码段DPL
栈的处理:将 CS、EIP、EFLAGS、SS、ESP 寄存器的值压入中断处理程序使用的栈
咱们以前说过,外部设备发出中断信号,进入 CPU 的 INT 引脚上。但若是有多个外部设备近乎同时发送中断信号,CPU 先处理哪个呢?未被处理的中断信号又记录在哪里呢?这时候就须要有个 中间的代理设备 来负责这个事情。
这个代理设备叫作 可编程中断控制器 PIC,其中 8259A 芯片是最多见的一种,咱们这里把它的内部结构展现出来,因为是硬件相关,就不展开细说了,但因为以后要为其进行编程,因此你们先有个印象。
因为到此篇幅过长,且中断代码的实现也是须要很大篇幅描述的,包括 可编程中断控制器的初始化,IDT 的初始化,以及中断例程代码的编写,因此将放在下一章进行讲解。
若是你对自制一个操做系统感兴趣,不妨跟随这个系列课程看下去,甚至加入咱们,一块儿来开发。
《操做系统真相还原》这本书真的赞!强烈推荐
当你看到该文章时,代码可能已经比文章中的又多写了一些部分了。你能够经过提交记录历史来查看历史的代码,我会慢慢梳理提交历史以及项目说明文档,争取给每一课都准备一个可执行的代码。固然文章中的代码也是全的,采用复制粘贴的方式也是彻底能够的。
若是你有兴趣加入这个自制操做系统的大军,也能够在留言区留下您的联系方式,或者在 gitee 私信我您的联系方式。
本课程打算出系列课程,我写到哪以为能够写成一篇文章了就写出来分享给你们,最终会完成一个功能全面的操做系统,我以为这是最好的学习操做系统的方式了。因此中间遇到的各类坎也会写进去,若是你能持续跟进,跟着我一块写,必然会有很好的收货。即便没有,交个朋友也是好的哈哈。
目前的系列包括