中断和异常
中断和异常
中断产生的原因
- 外部中断:由硬件产生的中断
- 不可屏蔽中断: 由CPU的引脚
NMI
产生 - 可屏蔽中断: 由8259的
INTR
引脚产生
- 不可屏蔽中断: 由CPU的引脚
- 指令中断
- 由
int n
指令产生的中断
- 由
指令中断
在保护模式下,无法使用实模式下使用的BIOS
中断,需要使用IDT
描述符设置保护模式中断
IDT
结构
中断向量到中断处理程序
- 首先由中断向量对应的
IDT
描述符的选择子找到对应的段描述符GDT
,并根据GDT找到对应的段基址 - 然后根据中断向量对应的
IDT
描述符的选择子找到对应的偏移量,结合段基址定位到中断程序的入口地址 - 执行中断处理程序
IDT
设置
; IDT
[SECTION .idt]
ALIGN 32
[BITS 32]
LABEL_IDT:
; 门 目标选择子, 偏移, DCount, 属性
%rep 128Gate SelectorCode32, SpuriousHandler, 0, DA_386IGate
%endrep
.080h: Gate SelectorCode32, UserIntHandler, 0, DA_386IGateIdtLen equ $ - LABEL_IDT
IdtPtr dw IdtLen - 1 ; 段界限dd 0 ; 基地址
; END of [SECTION .idt]
这里定义了前129号中断的内容(128+1): 其中,前128号中断对应的中断处理函数都是SpuriousHandler
,第129号中断(0x80)对应的中断处理函数为UserIntHandler
. 下面是两个中断处理函数的定义
_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
...; 为加载 IDTR 作准备xor eax, eaxmov ax, dsshl eax, 4add eax, LABEL_IDT ; eax <- idt 基地址mov dword [IdtPtr + 2], eax ; [IdtPtr + 2] <- idt 基地址...; 关中断cli; 加载 IDTRlidt [IdtPtr]
加载IDT
的方法与加载GDT
类似,其中cli
关中断是为了暂时不响应可屏蔽中断
在保护模式下执行int 80h
后会成功调用_UserIntHandler
函数,在屏幕第0行第70列打出'I'
外部中断
下图为外部中断的构成:
其中,非屏蔽中断对应的中断号为2,8259A对应的中断号由用户设置
8259A
设置
8259A是可编程中断控制器,对它的设置并不复杂,是通过向相应的端口写入特定的ICW来实现的。主8259A对应的端口地址是20h和21h,从8259A对应的端口地址是A0h和A1h。ICW共有4个,每一个都是具有特定格式的字节。
-
向主\从片写入
ICW1
- 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
- 0: 1=需要
-
向主\从片写入
ICW2
- 0-2: 000=80x86系统
- 3-7:对应开始的中断向量号
-
向主片写入
ICW3
- 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=无从片
- 0: 1=
-
向从片写入
ICW3
- 0-2: 从片连接的主片IR号(二进制表示)
- 3-7:必须为0
-
向主\从片写入
ICW4
- 0: 1=80x86模式, 0=MCS 80/85
- 1: 1=自动EOI, 0=正常EOI
- 2-3: 主从缓冲模式
- 4: 1=SFNM模式, 0=sequential模式
- 5-7: 未使用
-
写OCW1(屏蔽外部中断)
- 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=关闭
- 0: 1=