一 保护模式下中断
保护模式下的中断机制下,中断模式发生很大的变化,原来的中断向量表已经被IDT替代,实模式下能用的BIOS中断,在
保护模式下已然不能使用,IDT 和GDT 、LDT 有相似之处,本质上都是描述符表。
1 IDT
IDT的作用是在保护模式下将每一个中断向量和一个描述符对应起来。从这个意义上说IDT也是一个中断向量表。
2 中断和异常机制
中断经常和异常联系起来,实际上它们都是程序执行过程中的强制性转移,转移到处理程序。不管中断还是异常,都是
软件或者硬件发生了某种情形而通知处理器的行为。
中断分类:
(1)外部中断:由硬件引起的中断。
(2)由指令int引起的中断。
; ==================设置8259A=================
; pmtest9.asm
; 编译方法:nasm pmtest9.asm -o pmtest9.com
;
; 1,理解中断机制
; 2,理解硬中断和软中断的区别
; 3,会设置8259A可编程控制器
; 4,理解设置8259A的作用
;
; IDT 可以看做是装有N个中断门的数组,IDT[N]
; 中断门 一个指向过程的指针
; int 80 中断描述符表的一个索引,IDT[80]
; ==========================================
%include "pm.inc" ; 常量, 宏, 以及一些说明
org 0100h
jmp LABEL_BEGIN
;===============================GDT=================================
[SECTION .gdt]
; GDT
; 段基址, 段界限 , 属性
LABEL_GDT: Descriptor 0, 0, 0 ; 空描述符
LABEL_DESC_NORMAL: Descriptor 0, 0ffffh, DA_DRW ; Normal 描述符
LABEL_DESC_CODE32: Descriptor 0, SegCode32Len - 1, DA_CR | DA_32 ; 非一致代码段, 32
LABEL_DESC_CODE16: Descriptor 0, 0ffffh, DA_C ; 非一致代码段, 16
LABEL_DESC_DATA: Descriptor 0, DataLen - 1, DA_DRW ; Data
LABEL_DESC_STACK: Descriptor 0, TopOfStack, DA_DRWA | DA_32 ; Stack, 32 位
LABEL_DESC_VIDEO: Descriptor 0B8000h, 0ffffh, DA_DRW ; 显存首地址
; GDT 结束
GdtLen equ $ - LABEL_GDT ; GDT长度
GdtPtr dw GdtLen - 1 ; GDT界限
dd 0 ; GDT基地址
; GDT 选择子
SelectorNormal equ LABEL_DESC_NORMAL - LABEL_GDT
SelectorCode32 equ LABEL_DESC_CODE32 - LABEL_GDT
SelectorCode16 equ LABEL_DESC_CODE16 - LABEL_GDT
SelectorData equ LABEL_DESC_DATA - LABEL_GDT
SelectorStack equ LABEL_DESC_STACK - LABEL_GDT
SelectorVideo equ LABEL_DESC_VIDEO - LABEL_GDT
; END of [SECTION .gdt]
;===============================DATA=================================
[SECTION .data1] ; 数据段
ALIGN 32
[BITS 32]
LABEL_DATA:
; 实模式下使用这些符号
_szReturn db 0Ah, 0
_wSPValueInRealMode dw 0
_dwMCRNumber: dd 0 ; Memory Check Result
_dwDispPos: dd (80 * 6 + 0) * 2 ; 屏幕第 6 行, 第 0 列。
_dwMemSize: dd 0
_SavedIDTR: dd 0 ; 用于保存 IDTR
dd 0
_SavedIMREG: db 0 ; 中断屏蔽寄存器值
_INT80 db "int 80 userdefine",0
; 保护模式下使用这些符号
szReturn equ _szReturn - $$
dwDispPos equ _dwDispPos - $$
dwMemSize equ _dwMemSize - $$
dwMCRNumber equ _dwMCRNumber - $$
SavedIDTR equ _SavedIDTR - $$
SavedIMREG equ _SavedIMREG - $$
INT80 equ _INT80 - $$
DataLen equ $ - LABEL_DATA
; END of [SECTION .data1]
;==================IDT中断向量表,用于指向一个过程==================
; int 80 从这里数第129个中断门(80H=128,数组从0开始)
;
;
[SECTION .idt]
ALIGN 32
[BITS 32]
LABEL_IDT:
; 门 目标选择子, 偏移, DCount, 属性
%rep 32 ;重复32次 32=0x20
Gate SelectorCode32, SpuriousHandler, 0, DA_386IGate
%endrep
.020h: Gate SelectorCode32, ClockHandler, 0, DA_386IGate
%rep 95 ;再重复95次 95=0x5F
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 .gs]
ALIGN 32
[BITS 32]
LABEL_STACK:
times 512 db 0
TopOfStack equ $ - LABEL_STACK - 1
; END of [SECTION .gs]
;=================================================================
[SECTION .s16]
[BITS 16]
LABEL_BEGIN:
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0100h
mov [LABEL_GO_BACK_TO_REAL+3], ax
mov [_wSPValueInRealMode], sp
; 初始化 16 位代码段描述符
mov ax, cs
movzx eax, ax
shl eax, 4
add eax, LABEL_SEG_CODE16
mov word [LABEL_DESC_CODE16 + 2], ax
shr eax, 16
mov byte [LABEL_DESC_CODE16 + 4], al
mov byte [LABEL_DESC_CODE16 + 7], ah
; 初始化 32 位代码段描述符
xor eax, eax
mov ax, cs
shl eax, 4
add eax, LABEL_SEG_CODE32
mov word [LABEL_DESC_CODE32 + 2], ax
shr eax, 16
mov byte [LABEL_DESC_CODE32 + 4], al
mov byte [LABEL_DESC_CODE32 + 7], ah
; 初始化数据段描述符
xor eax, eax
mov ax, ds
shl eax, 4
add eax, LABEL_DATA
mov word [LABEL_DESC_DATA + 2], ax
shr eax, 16
mov byte [LABEL_DESC_DATA + 4], al
mov byte [LABEL_DESC_DATA + 7], ah
; 初始化堆栈段描述符
xor eax, eax
mov ax, ds
shl eax, 4
add eax, LABEL_STACK
mov word [LABEL_DESC_STACK + 2], ax
shr eax, 16
mov byte [LABEL_DESC_STACK + 4], al
mov byte [LABEL_DESC_STACK + 7], ah
; 为加载 GDTR 作准备
xor eax, eax
mov ax, ds
shl eax, 4
add eax, LABEL_GDT ; eax <- gdt 基地址
mov dword [GdtPtr + 2], eax ; [GdtPtr + 2] <- gdt 基地址
; 为加载 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 处
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
LABEL_REAL_ENTRY: ; 从保护模式跳回到实模式就到了这里
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax
mov sp, [_wSPValueInRealMode]
lidt [_SavedIDTR] ; 恢复 IDTR 的原值
mov al, [_SavedIMREG] ; ┓恢复中断屏蔽寄存器(IMREG)的原值
out 21h, al ; ┛
in al, 92h ; ┓
and al, 11111101b ; ┣ 关闭 A20 地址线
out 92h, al ; ┛
sti ; 开中断
mov ax, 4c00h ; ┓
int 21h ; ┛回到 DOS
; END of [SECTION .s16]
;============================CODE32==================================
[SECTION .s32]; 32 位代码段. 由实模式跳入.
[BITS 32]
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 ;调用一次80h中断,显示"int 80 userdefine"
;int 020h ;将外部中断屏蔽掉,可以使用软中断调用时钟函数,体会软中断和硬中断的区别
sti
jmp $ ;死循环,但会接收时钟中断
;-----------------------------------------
call SetRealmode8259A
; 到此停止
jmp SelectorCode16:0
; Init8259A ---------------------------------------------------------------------------------------------
Init8259A:
;---------ICW
mov al, 011h ;------------------------------------------------------------------;
out 020h, al ; 主8259, ICW1. ;
call io_delay ;
;ICW1
out 0A0h, al ; 从8259, ICW1. ;
call io_delay ;
;-----------------------------------------------------------------;
mov al, 020h ; IRQ0 对应中断向量 0x20 ;
out 021h, al ; 主8259, ICW2. ;
call io_delay ;
;ICW2
mov al, 028h ; IRQ8 对应中断向量 0x28 ;
out 0A1h, al ; 从8259, ICW2. ;
call io_delay ;
;-----------------------------------------------------------------;=========ICW(整体)
mov al, 004h ; IR2 对应从8259 ;
out 021h, al ; 主8259, ICW3. ;
call io_delay ;
;ICW3
mov al, 002h ; 对应主8259的 IR2 ;
out 0A1h, al ; 从8259, ICW3. ;
call io_delay ;
;-----------------------------------------------------------------;
mov al, 001h ;
out 021h, al ; 主8259, ICW4. ;
call io_delay ;ICW4
;
out 0A1h, al ; 从8259, ICW4. ;
call io_delay ;-----------------------------------------------------------------;
;-------------OCW
mov al, 11111110b ; 仅仅开启定时器中断 ----------------------;
;mov al, 11111111b ; 屏蔽主8259所有中断 ;
out 021h, al ; 主8259, OCW1. ;
call io_delay ;
;------------------------------------------------------;=====OCW
mov al, 11111111b ; 屏蔽从8259所有中断 ;
out 0A1h, al ; 从8259, OCW1. ;
call io_delay ;------------------------------------------------------; ;
ret
; Init8259A ---------------------------------------------------------------------------------------------
; SetRealmode8259A ---------------------------------------------------------------------------------------------
SetRealmode8259A:
mov ax, SelectorData
mov fs, ax
mov al, 017h
out 020h, al ; 主8259, ICW1.
call io_delay
mov al, 008h ; IRQ0 对应中断向量 0x8
out 021h, al ; 主8259, ICW2.
call io_delay
mov al, 001h
out 021h, al ; 主8259, ICW4.
call io_delay
mov al, [fs:SavedIMREG] ; ┓恢复中断屏蔽寄存器(IMREG)的原值
out 021h, al ; ┛
call io_delay
ret
; SetRealmode8259A ---------------------------------------------------------------------------------------------
io_delay:
nop
nop
nop
nop
ret
; int handler ---------------------------------------------------------------
_ClockHandler: ;始终中断,每隔 毫秒在屏幕右上角的相同位置上打印一个字符
ClockHandler equ _ClockHandler - $$
inc byte [gs:((80 * 0 + 70) * 2)] ; 屏幕第 0 行, 第 70 列。
mov al, 20h
out 20h, al ; 发送 EOI
iretd
_UserIntHandler:
UserIntHandler equ _UserIntHandler - $$
push INT80
call DispStr
add esp, 4
iretd
_SpuriousHandler:
SpuriousHandler equ _SpuriousHandler - $$
mov ah, 0Ch ; 0000: 黑底 1100: 红字
mov al, '!'
mov [gs:((80 * 0 + 0) * 2)], ax ; 屏幕第 0 行, 第 75 列。
jmp $
iretd
; ---------------------------------------------------------------------------
%include "lib.inc" ; 库函数
SegCode32Len equ $ - LABEL_SEG_CODE32
; END of [SECTION .s32]
;===========================================================
; 16 位代码段. 由 32 位代码段跳入, 跳出后到实模式
[SECTION .s16code]
ALIGN 32
[BITS 16]
LABEL_SEG_CODE16:
; 跳回实模式:
mov ax, SelectorNormal
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov eax, cr0
and al, 11111110b
mov cr0, eax
LABEL_GO_BACK_TO_REAL:
jmp 0:LABEL_REAL_ENTRY ; 段地址会在程序开始处被设置成正确的值
Code16Len equ $ - LABEL_SEG_CODE16
; END of [SECTION .s16code]
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/unikingest/archive/2009/04/14/4074318.aspx