上图中除了两个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