01_interrupt.asm文件提供了X86中断处理的初始化代码,同时还提供了一个接口供不同硬件安装自己的中断处理程序。
interrupt_init:初始化X86中断,最后启动中断功能;
general_interrupt_handler:通用的中断处理过程;
general_exception_handler:通用的异常处理过程
install_XXX_interrupt:提供给不同的硬件安装自己的中断向量;
;===============================================================================
;=== 本程序包括了中断处理的主要功能: ===
;=== 1.中断初始化 ===
;=== 2.安装中断的对外接口 ===
;===============================================================================
;-------------------------------------------------------------------------------
interrupt_init: ;初始化X86中断,最后启动中断功能
;前20个向量是处理器异常使用的
mov eax,general_exception_handler ;门代码在段内偏移地址
mov bx,flat_4gb_code_seg_sel ;门代码所在段的选择子
mov cx,0x8e00 ;32位中断门,0特权级
call make_gate_descriptor
mov ebx,idt_linear_address ;中断描述符表的线性地址
xor esi,esi
_idt0:
mov [ebx+esi*8],eax
mov [ebx+esi*8+4],edx
inc esi
cmp esi,19 ;安装前20个异常中断处理过程
jle _idt0
;其余为保留或硬件使用的中断向量
mov eax,general_interrupt_handler ;门代码在段内偏移地址
mov bx,flat_4gb_code_seg_sel ;门代码所在段的选择子
mov cx,0x8e00 ;32位中断门,0特权级
call make_gate_descriptor
mov ebx,idt_linear_address ;中断描述符表的线性地址
_idt1:
mov [ebx+esi*8],eax
mov [ebx+esi*8+4],edx
inc esi
cmp esi,255 ;安装普通的中断处理过程
jle _idt1
;准备开放中断
mov word [pidt],256*8-1 ;IDT的界限
mov dword [pidt+2],idt_linear_address
lidt [pidt] ;加载中断描述符表寄存器IDTR
;设置8259A中断控制器
mov al,0x11
out 0x20,al ;ICW1:边沿触发/级联方式
mov al,0x20 ;设置主片的8个中断号从0x20开始
out 0x21,al ;ICW2:起始中断向量
mov al,0x04
out 0x21,al ;ICW3:从片级联到IR2
mov al,0x01
out 0x21,al ;ICW4:非总线缓冲,全嵌套,正常EOI
mov al,0x11
out 0xa0,al ;ICW1:边沿触发/级联方式
mov al,0x70 ;设置从片的8个中断号从0x70开始
out 0xa1,al ;ICW2:起始中断向量
mov al,0x04
out 0xa1,al ;ICW3:从片级联到IR2
mov al,0x01
out 0xa1,al ;ICW4:非总线缓冲,全嵌套,正常EOI
sti ;开放硬件中断
ret
;-------------------------------------------------------------------------------
general_interrupt_handler: ;通用的中断处理过程
push eax
mov al,0x20 ;中断结束命令EOI
out 0xa0,al ;向从片发送
out 0x20,al ;向主片发送
pop eax
iretd
;-------------------------------------------------------------------------------
general_exception_handler: ;通用的异常处理过程
mov byte [show_mem_addr+1600], '!'
mov byte [show_mem_addr+1601], 0x7
hlt
;-------------------------------------------------------------------------------
install_XXX_interrupt: ;安装第XXX号中断向量
;输入参数:eax -- 中断向量地址
;输入参数:ebx -- 中断向量号
;输入参数:ch -- 主/从IMR寄存器(0-主片/1-从片)
;输入参数:cl -- 需要清除IMR的哪一位
push ebx ;[ebp+4] - 中断向量号
push ecx ;[ebp] - 中断向量对应的IMR信息
mov ebp, esp
cli ;关中断
sidt [pidt] ;取idt段地址
;创建中断向量对应的门信息
mov bx, flat_4gb_code_seg_sel ;门代码所在段的选择子
mov cx, 0x8e00 ;32位中断门,0特权级
call make_gate_descriptor
;将中断向量对应的门信息写入idt
mov ecx, [ebp+4] ;中断向量号
shl ecx, 3 ;中断向量号左移3位(*8)
mov ebx, [pidt + 2] ;中断描述符表的线性地址
mov [ebx + ecx], eax ;中断描述符低32位
mov [ebx + ecx + 4], edx ;中断描述符高32位
lidt [pidt] ;重新加载中断描述符表寄存器IDTR
;设置8259主/从片的IMR寄存器
mov ecx, [ebp]
cmp ch, 0x0 ;8259主片还是从片
jnz _slave_8259 ;跳转到从片处进行处理
in al,0x21 ;读8259主片的IMR寄存器
mov bl, 0x01 ;bl第0位赋1
shl bl, cl ;向左移动对应位数
not bl ;取反
and al, bl ;将向量对应位取反
out 0x21,al ;写回此寄存器
jmp _interrupt_install_ok
_slave_8259: ;中断对应8259从片
in al,0xa1 ;读8259从片的IMR寄存器
mov bl, 0x01 ;bl第0位赋1
shl bl, cl ;向左移动对应位数
not bl ;取反
and al, bl ;将向量对应位取反
out 0xa1,al ;写回此寄存器
_interrupt_install_ok:
sti ;开中断
add esp, 8
ret