?? 386ldt.asm
字號(hào):
;**********************************************************************
; 保護(hù)模式下的編程示例 陳家祺 1996.6
; ---局部描述符的應(yīng)用方法
; 1 實(shí)模式進(jìn)入保護(hù)模式及保護(hù)模式返回實(shí)模式方法
; 2 保護(hù)模式下的指令操作(直接寫(xiě)屏,滿屏顯示'A')
; * 環(huán)境: MASM6.0,TASM3.0, DOS6.2, 80486主機(jī), Himem.sys, 不能裝載Emm386.exe
; 不能裝載Emm386.exe,因?yàn)镋mm386.exe裝載后,cpu處于虛擬8086方式下
;**********************************************************************
jumpfar MACRO segf,offsetf ; 保護(hù)模式跳轉(zhuǎn)指令
db 0eah ; 功能與目的:
dw offsetf ; 1. 清除指令隊(duì)列
dw segf ; 2. segf -> CS;offsetf -> IP
ENDM
desc struc ; 描述符的結(jié)構(gòu)
limit_15_0 dw ? ; 界限15-0
base_15_0 dw ? ; 基地址15-0
base_23_16 db ? ; 基地址23-16
access db ? ; 訪問(wèn)權(quán)
gran db ? ; 粒度,類型,界限19-16
base_31_24 db ? ; 基地址31-24
desc ends
dos_data segment ; 數(shù)據(jù)段
char db 'A' ; 要顯示的字符
save_ss dw ? ; SS保存區(qū)
; ***** GDT 描述符表 *****
gdt_def LABEL BYTE
desc < > ; 必須為空描述符
gdt_kcs desc <0ffffh, ?, ?,9ah,0fh,00h> ;00000 - fffffH (1Mb)
gdt_kds desc <00000h, ?, ?,92h,00h,00h> ;00000 - 00000H (1b)
gdt_kss desc <00000h, ?, ?,96h,00h,00h>;(sp=)00400 - 00000H (1K)
gdt_ldt1 desc <ldt1_end-ldt1_def, ?, ?,82h,00h, ? > ;LDT1表的描述符
gdt_ldt2 desc <ldt2_end-ldt2_def, ?, ?,82h,00h, ? > ;LDT2表的描述符
gdt_end LABEL BYTE
; 設(shè)置GDTR用
gdtsize dw gdt_end-gdt_def ; GDT描述符表的長(zhǎng)度
gdtload dw ? ; GDT描述符表的線性基地址15-0,
dw ? ; GDT描述符表的線性基地址31-16
; ***** LDT1 描述符表 *****
ldt1_def LABEL BYTE
ldt1_uds desc <0ffffh,8000h,0bh,92h,00h,00h> ;00000 - 0ffffH (64Kb)
ldt1_end LABEL BYTE
; ***** LDT2 描述符表 *****
ldt2_def LABEL BYTE
ldt2_uds desc <0ffffh,0000h,00h,92h,0fh,00h> ;00000 - fffffH (1Mb)
ldt2_end LABEL BYTE
; GDT的選擇子
gdt_kcs_sel equ 08h ; CS選擇子
gdt_kds_sel equ 10h ; DS選擇子
gdt_kss_sel equ 18h ; SS選擇子
gdt_ldt1_sel equ 20h ; LDT1表的選擇子
gdt_ldt2_sel equ 28h ; LDT2表的選擇子
ldt1_uds_sel equ 04h ; LDT1的用戶DS選擇子
ldt2_uds_sel equ 04h ; LDT2的用戶DS選擇子
dos_data ends
dos_stack segment stack ; 堆棧段
db 1024 dup (0)
dos_stack_sp dw 0
dos_stack ends
dos_code segment ; 代碼段
assume cs:dos_code, ds:dos_data, ss:dos_stack
main proc near
start :
mov ax,dos_data
mov ds,ax ; 設(shè)置DS
cli
mov ax,dos_stack
mov ss,ax ; 設(shè)置SS
mov save_ss,ax ; 保存SS
mov sp,offset dos_stack_sp ; 設(shè)置SP, 定義堆棧
call prot ; 調(diào)用保護(hù)模式操作子程
sti
mov ah,0
int 16h ; BIOS鍵盤中斷調(diào)用,等待按鍵!
mov ah,4ch
int 21h ; 返回DOS!
main endp
.386p
prot proc near
; ***** 設(shè)置GDT描述符的基地址 *****
mov di,offset gdt_kcs ; 設(shè)置CS描述符的基地址
mov ax,cs ; 將實(shí)模式DOS的段地址
call copy_desc ; 換算為線性基地址
mov di,offset gdt_kds ; 設(shè)置DS描述符的基地址
mov ax,ds ; 將實(shí)模式DOS的段地址
call copy_desc ; 換算為線性基地址
mov di,offset gdt_kss ; 設(shè)置SS描述符的基地址
mov ax,ss ; 將實(shí)模式DOS的段地址
call copy_desc ; 換算為線性基地址
mov ax,ds ; 計(jì)算GTD表的線性地址
mov cx,10h
mul cx
add ax,offset gdt_def
adc dx,0
mov gdtload,ax
mov gdtload+2,dx
; ***** 設(shè)置LDT1描述符的基地址 *****
mov di,offset gdt_ldt1 ; 設(shè)置DS描述符的基地址
mov bx,offset ldt1_def ; 將實(shí)模式DOS的段地址
call copy_ldt_desc ; 換算為線性基地址
; ***** 設(shè)置LDT1描述符的基地址 *****
mov di,offset gdt_ldt2 ; 設(shè)置DS描述符的基地址
mov bx,offset ldt2_def ; 將實(shí)模式DOS的段地址
call copy_ldt_desc ; 換算為線性基地址
LGDT fword ptr gdtsize ; 裝載GDT
mov ax,gdt_kss_sel ; 初始化保護(hù)模式的ss
mov ss,ax ; 在保護(hù)模式下初始化ss將出錯(cuò)!
; 原因?
mov eax,cr0
or al,1 ; 設(shè)置控制寄存器CR0的PE位
mov cr0,eax ; 進(jìn)入保護(hù)模式
jumpfar gdt_kcs_sel,prot_user ; 清除指令隊(duì)列,
prot_user: ; CS=gdt_kcs_sel(保護(hù)模式碼段)
call vram_disp ; 調(diào)用保護(hù)模式下顯示子程
mov eax,cr0
and al,0feh ; 清除控制寄存器CR0的PE位
mov cr0,eax ; 切換到實(shí)模式
jumpfar dos_code,real_mode ; 清除指令隊(duì)列,CS=dos_code(實(shí)模式碼段)
real_mode:
mov ax,dos_data
mov ds,ax
mov ss,save_ss ; 恢復(fù)堆棧段
ret
prot endp
vram_disp proc near ; 保護(hù)模式下直接寫(xiě)屏子程
pushad
mov ax,gdt_kds_sel ; 設(shè)置GDT的數(shù)據(jù)段
mov ds,ax
mov dl,char ; 取出要顯示字符'A'
mov ax,gdt_ldt1_sel ; 設(shè)置LDT1的選擇子
LLDT ax ; 裝載LDT1 -> LDTR
mov ax,ldt1_uds_sel ; 設(shè)置LDT1的數(shù)據(jù)段
mov ds,ax
mov ebx,000000h
mov ah,17h ; 字符顏色屬性,藍(lán)底白字
mov al,dl ; 顯示字符'A'
mov [ebx],ax
mov ax,gdt_ldt2_sel ; 設(shè)置LDT2的選擇子
LLDT ax ; 裝載LDT2 -> LDTR
mov ax,ldt2_uds_sel ; 設(shè)置LDT1的數(shù)據(jù)段
mov ds,ax
mov ebx,0b8002h
mov ah,1eh ; 字符顏色屬性,藍(lán)底黃字
mov al,dl ; 顯示字符'A'
mov [ebx],ax
popad
ret
vram_disp endp
copy_desc proc near ; 設(shè)置描述符的基地址
mov cx,10h ; 將實(shí)模式DOS的段地址
mul cx ; 換算為24位線性地址
mov [di].base_15_0,ax ; 存入描述符中
mov [di].base_23_16 ,dl
ret
copy_desc endp
copy_ldt_desc proc near ; 設(shè)置LDT描述符的基地址
mov ax,ds ; 將LDT表的基地址
mov cx,10h ; 換算為32位線性地址
mul cx
add ax,bx
adc dx,0
mov [di].base_15_0,ax ; 存入描述符中
mov [di].base_23_16 ,dl
mov [di].base_31_24 ,dh
ret
copy_ldt_desc endp
dos_code ends
end start
;****************************** 源程序結(jié)束 ******************************
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -