中断

中断在linux驱动中占有很重要的地位,所以也一定要好好分析一下。还是一样的套路,先讲一下基本的概念,然后分析源码再来加深理解。

中断门与其他三个门(调用门、陷阱门、任务门)一起是操作系统里的四扇门。它们之间的区别以后再补充,今天重点分析中断门。

那么什么是门呢?门其实就是一中描述符,直观来看这个描述符描述了由一个选择子和一个偏移所指定的线性地址,程序正是通过这个地址进行转移的。中断描述符放在中断描述符表里(IDT),也就是这个IDT将中断向量和中断服务程序联系起来,他们之间的关系如下图:

那中断向量怎么来得呢,其实每一种中断(异常)都会对应一个中断向量号,具体有哪些中断向量,可以看下面这张图:

 

向量号 助记符 描述 类型 出错码
0 #DE 除法错 Fault DIV和IDIV指令
1 #DB 调试异常 Fault/Trap 任何代码和数据的访问
2 非屏蔽中断 Interrupt 非屏蔽外部中断
3 #BP 调试断点 Trap 指令INT 3
4 #OF 溢出 Trap 指令INTO
5 #BR 越界 Fault 指令BOUND
6 #UD 无效(未定义)操作码 Fault 指令UD2或无效指令
7 #NM 设备不可用(无数学协处理器) Fault 浮点或WAIT/FWAIT指令
8 #DF 双重错误 Abort 有(0) 所有能产生异常或NMI或INTR
的指令
9   协处理器段越界(保留) Fault 浮点指令(386后不再处理此
异常)
10 #TS 无效TSS Fault 任务切换或访问TSS时
11 #NP 段不存在 Fault 加载段寄存器或访问系统段时
12 #SS 堆栈段错误 Fault 堆栈操作或加载SS时
13 #GP 常规保护错误 Fault 内存或其他保护检验
14 #PF 页错误 Fault 内存访问
15 Intel保留,未使用      
16 #MF x87FPU浮点错(数学错) Fault x87FPU浮点指令或WAIT/FWAIT指令
17 #AC 对齐检验 Fault 有(0) 内存中的数据访问(486开始支持)
18 #MC Machine Check Abort 错误码(若有的话)和源依赖于
具体模式(奔腾CPU开始支持)
19 #XF SIMD浮点异常 Fault SSE和SSE2浮点指令(奔腾三
开始支持)
20~31 Inter保留,未使用      
32~255 用户定义中断 Interrupt   外部中断或int n指令

 

上图中除了两个Interrupt(中断)外,其他还有三种Fault、Trap、Abort异常。我们这里讨论的中断主要是用户定义中断,这种中断产生的原因有两种:一是外部中断,就是由硬件产生的中断;另一种是由指令int n产生的中断。

通过指令int n产生中断的情形如第一张图所示,这有点像调用门的适用。

外部中断的情况则复杂一些,因为需要建立硬件中断和向量号之间的对应关系。外部中断的简单示意图如下:

通过对8259A的配置,可将IRQ0~IRQ7对应到中断向量20h~27h,同样地IRQ8~IRQ15可对应到中断向量28h~2Fh。具体初始化配置代码就不进行分析了。

; IDT
[SECTION .idt] ;sect.idt #show#-->
ALIGN 32
[BITS 32]
LABEL_IDT:
; 门 目标选择子, 偏移, DCount, 属性
%rep 32
Gate SelectorCode32, SpuriousHandler, 0, DA_386IGate
%endrep
.020h: Gate SelectorCode32, ClockHandler, 0, DA_386IGate
%rep 95
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]


[SECTION .s16]
[BITS 16]
LABEL_BEGIN:
; 为加载 IDTR 作准备
xor eax, eax
mov ax, ds
shl eax, 4
add eax, LABEL_IDT ; eax <- idt 基地址
mov dword [IdtPtr + 2], eax ; [IdtPtr + 2] <- idt 基地址

; 保存 IDTR
sidt [_SavedIDTR]

; 保存中断屏蔽寄存器(IMREG)值
in al, 21h
mov [_SavedIMREG], al

; 加载 GDTR
lgdt [GdtPtr]

; 关中断
;cli

; 加载 IDTR
lidt [IdtPtr]
; 打开地址线A20
in al, 92h
or al, 00000010b
out 92h, al

; 准备切换到保护模式
mov eax, cr0
or eax, 1
mov cr0, eax

; 真正进入保护模式
jmp dword SelectorCode32:0 ; 执行这一句会把 SelectorCode32 装入 cs, 并跳转到 Code32Selector:0 处

; Init8259A ---------------------------------------------------------------------------------------------
Init8259A:
mov al, 011h
out 020h, al ; 主8259, ICW1.
call io_delay

out 0A0h, al ; 从8259, ICW1.
call io_delay

mov al, 020h ; IRQ0 对应中断向量 0x20
out 021h, al ; 主8259, ICW2.
call io_delay

mov al, 028h ; IRQ8 对应中断向量 0x28
out 0A1h, al ; 从8259, ICW2.
call io_delay

mov al, 004h ; IR2 对应从8259
out 021h, al ; 主8259, ICW3.
call io_delay

mov al, 002h ; 对应主8259的 IR2
out 0A1h, al ; 从8259, ICW3.
call io_delay

mov al, 001h
out 021h, al ; 主8259, ICW4.
call io_delay

out 0A1h, al ; 从8259, ICW4.
call io_delay

;mov al, 11111111b ; 屏蔽主8259所有中断
mov al, 11111110b ; 仅仅开启定时器中断
out 021h, al ; 主8259, OCW1.
call io_delay

mov al, 11111111b ; 屏蔽从8259所有中断
out 0A1h, al ; 从8259, OCW1.
call io_delay

ret
; Init8259A ---------------------------------------------------------------------------------------------


LABEL_SEG_CODE32:
mov ax, SelectorData
mov ds, ax ; 数据段选择子
mov es, ax
mov ax, SelectorVideo
mov gs, ax ; 视频段选择子

mov ax, SelectorStack
mov ss, ax ; 堆栈段选择子
mov esp, TopOfStack

call Init8259A

int 080h
sti
jmp $


; int handler ---------------------------------------------------------------
_UserIntHandler:
UserIntHandler equ _UserIntHandler - $$
mov ah, 0Ch ; 0000: 黑底 1100: 红字
mov al, 'I'
mov [gs:((80 * 0 + 70) * 2)], ax ; 屏幕第 0 行, 第 70 列。
iretd

posted on 2015-05-22 21:55  swek  阅读(243)  评论(0)    收藏  举报