Loading... # 中断和异常 ## 中断产生的原因 1. 外部中断:由硬件产生的中断 1. 不可屏蔽中断: 由CPU的引脚`NMI`产生 2. 可屏蔽中断: 由8259的`INTR`引脚产生 2. 指令中断 1. 由`int n`指令产生的中断 ## 指令中断 **在保护模式下,无法使用实模式下使用的`BIOS`中断,需要使用`IDT`描述符设置保护模式中断** ### `IDT`结构 ![IDT](https://y0k1n0-1323330522.cos.ap-beijing.myqcloud.com/image-20241003112754075.png) ### 中断向量到中断处理程序 ![中断向量到中断处理程序](https://y0k1n0-1323330522.cos.ap-beijing.myqcloud.com/image-20241003112943775.png) 1. 首先由中断向量对应的`IDT`描述符的选择子找到对应的段描述符`GDT`,并根据GDT找到对应的段基址 2. 然后根据中断向量对应的`IDT`描述符的选择子找到对应的偏移量,结合段基址定位到中断程序的入口地址 3. 执行中断处理程序 ### `IDT`设置 ```nasm ; IDT [SECTION .idt] ALIGN 32 [BITS 32] LABEL_IDT: ; 门 目标选择子, 偏移, DCount, 属性 %rep 128 Gate SelectorCode32, SpuriousHandler, 0, DA_386IGate %endrep .080h: Gate SelectorCode32, UserIntHandler, 0, DA_386IGate IdtLen equ $ - LABEL_IDT IdtPtr dw IdtLen - 1 ; 段界限 dd 0 ; 基地址 ; END of [SECTION .idt] ``` 这里定义了前129号中断的内容(128+1): 其中,前128号中断对应的中断处理函数都是`SpuriousHandler`,第129号中断(0x80)对应的中断处理函数为`UserIntHandler`. 下面是两个中断处理函数的定义 ```nasm _UserIntHandler: UserIntHandler equ _UserIntHandler - $$ mov ah, 0Ch ; 0000: 黑底 1100: 红字 mov al, 'I' mov [gs:((80 * 0 + 70) * 2)], ax ; 屏幕第 0 行, 第 70 列。 iretd _SpuriousHandler: SpuriousHandler equ _SpuriousHandler - $$ mov ah, 0Ch ; 0000: 黑底 1100: 红字 mov al, '!' mov [gs:((80 * 0 + 75) * 2)], ax ; 屏幕第 0 行, 第 75 列。 jmp $ iretd ``` `_SpuriousHandler`中断处理函数会让程序陷入死循环,而`_UserIntHandler`中断处理函数可以正常的结束中断 下面的程序实现了如何加载`IDT` ```nasm ... ; 为加载 IDTR 作准备 xor eax, eax mov ax, ds shl eax, 4 add eax, LABEL_IDT ; eax <- idt 基地址 mov dword [IdtPtr + 2], eax ; [IdtPtr + 2] <- idt 基地址 ... ; 关中断 cli ; 加载 IDTR lidt [IdtPtr] ``` 加载`IDT`的方法与加载`GDT`类似,其中`cli`关中断是为了暂时不响应可屏蔽中断 在保护模式下执行`int 80h`后会成功调用`_UserIntHandler`函数,在屏幕第0行第70列打出`'I'` ## 外部中断 下图为外部中断的构成: ![外部中断](https://y0k1n0-1323330522.cos.ap-beijing.myqcloud.com/image-20241003144526459.png) 其中,非屏蔽中断对应的中断号为2,8259A对应的中断号由用户设置 ### `8259A`设置 8259A是可编程中断控制器,对它的设置并不复杂,是通过向相应的端口写入特定的ICW来实现的。主8259A对应的端口地址是20h和21h,从8259A对应的端口地址是A0h和A1h。ICW共有4个,每一个都是具有特定格式的字节。 1. 向主\从片写入`ICW1` ![ICW1](https://y0k1n0-1323330522.cos.ap-beijing.myqcloud.com/852fc57ea58fd54651928fc2bb85100.png) - 0: 1=需要`ICW4`, 0=不需要`ICW4` - 1: 1=单个8259, 0=级联8259 - 2: 1=4字节中断向量, 0=8字节中断向量 - 3: 1=level triggered模式, 0=edge triggered模式 - 4: 对于`ICW1`必须为1 - 5-7:对于PC系统必须为1 2. 向主\从片写入`ICW2` ![ICW1](https://y0k1n0-1323330522.cos.ap-beijing.myqcloud.com/852fc57ea58fd54651928fc2bb85100.png) - 0-2: 000=80x86系统 - 3-7:对应开始的中断向量号 3. 向主片写入`ICW3` ![ICW1](https://y0k1n0-1323330522.cos.ap-beijing.myqcloud.com/852fc57ea58fd54651928fc2bb85100.png) - 0: 1=`IR0`级联从片, 0=无从片 - 1: 1=`IR1`级联从片, 0=无从片 - 2: 1=`IR2`级联从片, 0=无从片 - 3: 1=`IR3`级联从片, 0=无从片 - 4: 1=`IR4`级联从片, 0=无从片 - 5: 1=`IR5`级联从片, 0=无从片 - 6: 1=`IR6`级联从片, 0=无从片 - 7: 1=`IR7`级联从片, 0=无从片 4. 向从片写入`ICW3` ![ICW1](https://y0k1n0-1323330522.cos.ap-beijing.myqcloud.com/852fc57ea58fd54651928fc2bb85100.png) - 0-2: 从片连接的主片IR号(二进制表示) - 3-7:必须为0 5. 向主\从片写入`ICW4` ![ICW1](https://y0k1n0-1323330522.cos.ap-beijing.myqcloud.com/852fc57ea58fd54651928fc2bb85100.png) - 0: 1=80x86模式, 0=MCS 80/85 - 1: 1=自动EOI, 0=正常EOI - 2-3: 主从缓冲模式 - 4: 1=SFNM模式, 0=sequential模式 - 5-7: 未使用 6. 写OCW1(屏蔽外部中断) ![ICW1](https://y0k1n0-1323330522.cos.ap-beijing.myqcloud.com/852fc57ea58fd54651928fc2bb85100.png) - 0: 1=`IR0`打开, 0=关闭 - 1: 1=`IR1`打开, 0=关闭 - 2: 1=`IR2`打开, 0=关闭 - 3: 1=`IR3`打开, 0=关闭 - 4: 1=`IR4`打开, 0=关闭 - 5: 1=`IR5`打开, 0=关闭 - 6: 1=`IR6`打开, 0=关闭 - 7: 1=`IR7`打开, 0=关闭 最后修改:2024 年 10 月 03 日 © 允许规范转载 赞 如果觉得我的文章对你有用,请随意赞赏