?? 386pi2b.asm
字號:
;**********************************************************************
; 保護模式下的編程示例 --- 中斷 陳家祺 1996.6
;
; 1 實模式進入保護模式及保護模式返回實模式方法
; 2 保護模式下的指令操作(清屏)
; 3 保護模式下的軟中斷調用方法
; 4 保護模式下的硬中斷處理方法(時鐘,鍵盤)
; 5 保護模式下的異常中斷(13)處理方法
; * 環境: MASM6.0, DOS6.2, 80486主機, Himem.sys, 不能裝栽Emm386.exe
;**********************************************************************
desc struc ;選擇器描述符結構
limit_15_0 dw ? ;界限15-0
base_15_0 dw ? ;基地址15-0
base_23_16 db ? ;基地址23-16
access db ? ;訪問權
gran db ? ;粒度,類型,界限19-16
base_31_24 db ? ;基地址31-24
desc ends
idesc struc ;中斷門描述符結構
off_15_0 dw ? ;入口偏移量15-0
sel dw ? ;目標選擇器
no db 0 ;
access db ? ;訪問權
off_31_16 dw ? ;入口偏移量31-16
idesc ends
dos_data segment word public 'data' ;數據段
save_gdt dw 4 dup (?) ;GDT保存區
save_idt dw 4 dup (?) ;IDT保存區
save_ss dw ? ;SS保存區
save_sp dw ? ;SP保存區
dtsize dw ? ;設置GDTR用
dtload dw ?
dw ?
idtsize dw ? ;設置IDTR用
idtload dw ?
dw ?
tc db 0 ;時鐘中斷計數單元
; ***** GDT 描述符表 *****
gdt_def equ $
desc < > ;空描述符
gdt_kcs desc <0ffffh,0000h,00h,9ah,0fh,00h> ;00000 - fffffH (1Mb)
gdt_kds desc <0ffffh,0000h,00h,92h,0fh,00h> ;00000 - fffffH (1Mb)
gdt_kss desc <00000h,0000h,00h,96h,00h,00h>
gdt_uds desc <0ffffh,0000h,00h,92h,0fh,00h> ;00000 - fffffH (1Mb)
gdt_size equ $-gdt_def
; ***** IDT 描述符表 *****
idt_def equ $
idesc 8 dup (<4000h,0008h,00h,8eh,0000h >) ;缺省中斷門
idt_08 idesc <1000h,0008h,00h,8eh,0000h> ;時鐘中斷門
idt_09 idesc <1800h,0008h,00h,8eh,0000h> ;鍵盤中斷門
idesc 3 dup (<4000h,0008h,00h,8eh,0000h >) ;缺省中斷門
idt_13 idesc <3000h,0008h,00h,8fh,0000h> ;異常中斷門
idesc 18 dup (<4000h,0008h,00h,8eh,0000h >) ;缺省中斷門
idt_20h idesc <2000h,0008h,00h,8fh,0000h> ;軟中斷門
idesc 256-20h dup (<4000h,0008h,00h,8eh,0000h >);缺省中斷門
idt_size equ $-idt_def
dos_data ends
dos_stack segment stack para 'stack' ;堆棧段
db 1024 dup (0)
dos_stack_sp dw 0
dos_stack ends
dos_code segment word public 'code' ;代碼段
assume cs:dos_code, ds:dos_data, ss:dos_stack
gdt_kcs_sel equ 08h ; CS選擇器
gdt_kds_sel equ 10h ; DS選擇器
gdt_kss_sel equ 18h ; SS選擇器
gdt_uds_sel equ 20h ; 用戶DS選擇器
main proc near
start :
mov ax,dos_data
mov ds,ax ; 設置DS
cli
mov ax,dos_stack
mov ss,ax ; 設置SS
mov save_ss,ax ; 保存SS
mov sp,offset dos_stack_sp ; 定義堆棧
mov save_sp,sp ; 保存SP
call prot ; 調用保護模式操作子程
sti
mov ah,0
int 16h ; BIOS鍵盤中斷調用,等待按鍵!
mov ah,4ch
int 21h ; 返回DOS!
main endp
prot proc near
.386p
SGDT fword ptr save_gdt ; 保存原GDT
SIDT fword ptr save_idt ; 保存原IDT
mov di,offset gdt_kcs ; 設置CS描述符的基地址
mov ax,cs ; 將實模式DOS的段地址
call copy_desc ; 換算為線性基地址
mov di,offset gdt_kds ; 設置DS描述符的基地址
mov ax,ds ; 將實模式DOS的段地址
call copy_desc ; 換算為線性基地址
mov di,offset gdt_kss ; 設置SS描述符的基地址
mov ax,ss ; 將實模式DOS的段地址
call copy_desc ; 換算為線性基地址
mov ax,ds ; 計算GTD表的線性地址
mov cx,10h
mul cx
add ax,offset gdt_def
adc dx,0
mov dtload,ax
mov dtload+2,dx
mov dtsize,gdt_size-1
mov ax,ds ; 計算IDT表的線性地址
mov cx,10h
mul cx
add ax,offset idt_def
adc dx,0
mov idtload,ax
mov idtload+2,dx
mov idtsize,idt_size-1
LGDT fword ptr dtsize ; 裝載GDT
LIDT fword ptr idtsize ; 裝載IDT
mov eax,cr0
or al,1 ; 設置控制寄存器CR0的PE位
mov cr0,eax ; 進入保護模式
; ***** 進入保護模式 ******
db 0eah ; 清除指令隊列,
dw offset vram_disp ; CS=gdt_kcs_sel(保護模式碼段)
dw gdt_kcs_sel
vram_disp:
mov ax,gdt_uds_sel
mov ds,ax
mov cx,80*25 ;清屏, 藍色屏幕.
mov ebx,0b8000h
mov ah,10h ;字符顏色屬性,背景色為藍色
mov al,' '
l1: mov [ebx],ax
add ebx,2
loop l1
sti
mov dx,1000 ;延時,等待外中斷(時鐘)產生
mov ecx,0h
llc: loop llc
dec dx
jnz llc
cli
int 20h ;調用保護模式軟中斷
x:
mov eax,cr0
and al,0feh ;清除控制寄存器CR0的PE位
mov cr0,eax ;切換到實模式
db 0eah ;清除指令隊列,CS=dos_code(實模式碼段)
dw offset real_mode
dw dos_code
; ***** 退出保護模式 *****
real_mode:
mov ax,dos_data
mov ds,ax
LGDT fword ptr save_gdt ;恢復原GDT
LIDT fword ptr save_idt ;恢復原IDT
mov ss,save_ss ;恢復堆棧段
; mov sp,save_sp
ret
prot endp
.8086
copy_desc proc near ;設置GDT描述符的基地址
mov cx,10h ;將實模式DOS的段地址
mul cx ;換算為線性地址
mov [di].base_15_0,ax ;存入GDT描述符中
mov [di].base_23_16 ,dl
ret
copy_desc endp
.386p
org 1000h ;保護模式時鐘中斷08h - 中斷處理程序
int_08h proc near ;每次中斷tc=tc+20,
pushad ;如果tc>127顯示'*',否則顯示' ';
mov ax,gdt_kds_sel ;效果: '*'閃爍.
mov ds,ax
add tc,20
cmp tc,127
jb char0
mov cl,'*' ;顯示'*'
jmp char1
char0: mov cl,' ' ;顯示' ',即清除'*'
char1: mov ch,1eh ;字符顏色屬性
mov ax,gdt_uds_sel
mov ds,ax
mov ebx,0b8000h ;屏幕第0行
mov [ebx],cx
mov al,20h ;通知8259結束中斷
out 20h,al
popad
iretd
int_08h endp
KEY_PA equ 60h
KEY_PB equ 61h
org 1800h ;保護模式鍵盤中斷09h - 中斷處理程序
int_09h proc near
pushad
in al,KEY_PA ;輸入鍵盤掃描碼
mov al,10000000b ;復位鍵盤,發送應答
out KEY_PB,al
mov al,01000000b ;允許鍵盤工作
out KEY_PB,al
mov ebx,0b8000h+160*3 ;屏幕第3行
mov ah,1eh ;字符顏色屬性
mov al,'K' ;顯示'K'
mov [ebx],ax
mov al,20h ;通知8259結束中斷
out 20h,al
popad
iretd
int_09h endp
org 2000h ;保護模式軟中斷20h - 中斷處理程序
int_20h proc near
pushad
mov ebx,0b8000h ;屏幕第0行
mov ah,1eh ;字符顏色屬性
mov al,'!' ;顯示'!'
mov [ebx],ax
popad
iretd
int_20h endp
org 3000h ;保護模式異常中斷13 - 中斷處理程序
int_13 proc near
pushad
mov ebx,0b8000h+160*4 ;屏幕第4行
mov ah,1eh ;字符顏色屬性
mov al,'?' ;顯示'?'
mov [ebx],ax
popad
; jmp x
iretd
int_13 endp
org 4000h ;保護模式缺省中斷 - 中斷處理程序
int_nn proc near
pushad
mov ebx,0b8000h+160*5 ;屏幕第5行
mov ah,1eh ;字符顏色屬性
mov al,'#' ;顯示'#'
mov [ebx],ax
mov al,20h
out 20h,al
popad
iretd
int_nn endp
dos_code ends
end start
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -