轉自:http://www.chinaitpower.com/A/2001-12-10/7366.html
<一>演示實模式和保護模式切換的實例(實例一)
1.包含文件
;名稱:386SCD.INC ;功能:符號常量等的定義 ;---------------------------------------------------------------------------- ;IFNDEF __386SCD_INC ;__386SCD_INC EQU 1 ;---------------------------------------------------------------------------- .386P ;---------------------------------------------------------------------------- ;打開A20地址線 ;---------------------------------------------------------------------------- EnableA20 MACRO push ax in al,92h or al,00000010b out 92h,al pop ax ENDM ;---------------------------------------------------------------------------- ;關閉A20地址線 ;---------------------------------------------------------------------------- DisableA20 MACRO push ax in al,92h and al,11111101b out 92h,al pop ax ENDM ;---------------------------------------------------------------------------- ;16位偏移的段間直接轉移指令的宏定義(在16位代碼段中使用) ;---------------------------------------------------------------------------- JUMP16 MACRO Selector,Offset DB 0eah ;操作碼 DW Offset ;16位偏移量 DW Selector ;段值或段選擇子 ENDM ;---------------------------------------------------------------------------- ;32位偏移的段間直接轉移指令的宏定義(在32位代碼段中使用) ;---------------------------------------------------------------------------- COMMENT <JUMP32> JUMP32 MACRO Selector,Offset DB 0eah ;操作碼 DD OFFSET DW Selector ;段值或段選擇子 ENDM <JUMP32> ;------------------------------------------------- JUMP32 MACRO Selector,Offset DB 0eah ;操作碼 DW OFFSET DW 0 DW Selector ;段值或段選擇子 ENDM ;---------------------------------------------------------------------------- ;16位偏移的段間調用指令的宏定義(在16位代碼段中使用) ;---------------------------------------------------------------------------- CALL16 MACRO Selector,Offset DB 9ah ;操作碼 DW Offset ;16位偏移量 DW Selector ;段值或段選擇子 ENDM ;---------------------------------------------------------------------------- ;32位偏移的段間調用指令的宏定義(在32位代碼段中使用) ;---------------------------------------------------------------------------- COMMENT <CALL32> CALL32 MACRO Selector,Offset DB 9ah ;操作碼 DD Offset DW Selector ;段值或段選擇子 ENDM <CALL32> ;------------------------------------------------- CALL32 MACRO Selector,Offset DB 9ah ;操作碼 DW Offset DW 0 DW Selector ;段值或段選擇子 ENDM ;---------------------------------------------------------------------------- ;存儲段描述符結構類型定義 ;---------------------------------------------------------------------------- Desc STRUC LimitL DW 0 ;段界限(BIT0-15) BaseL DW 0 ;段基地址(BIT0-15) BaseM DB 0 ;段基地址(BIT16-23) Attributes DB 0 ;段屬性 LimitH DB 0 ;段界限(BIT16-19)(含段屬性的高4位) BaseH DB 0 ;段基地址(BIT24-31) Desc ENDS ;---------------------------------------------------------------------------- ;門描述符結構類型定義 ;---------------------------------------------------------------------------- Gate STRUC OffsetL DW 0 ;32位偏移的低16位 Selector DW 0 ;選擇子 DCount DB 0 ;雙字計數 GType DB 0 ;類型 OffsetH DW 0 ;32位偏移的高16位 Gate ENDS ;---------------------------------------------------------------------------- ;僞描述符結構類型定義(用於裝入全局或中斷描述符表寄存器) ;---------------------------------------------------------------------------- PDesc STRUC Limit DW 0 ;16位界限 Base DD 0 ;32位基地址 PDesc ENDS ;---------------------------------------------------------------------------- ;任務狀態段結構類型定義 ;---------------------------------------------------------------------------- TSS STRUC TRLink DW 0 ;鏈接字段 DW 0 ;不使用,置爲0 TRESP0 DD 0 ;0級堆棧指針 TRSS0 DW 0 ;0級堆棧段寄存器 DW 0 ;不使用,置爲0 TRESP1 DD 0 ;1級堆棧指針 TRSS1 DW 0 ;1級堆棧段寄存器 DW 0 ;不使用,置爲0 TRESP2 DD 0 ;2級堆棧指針 TRSS2 DW 0 ;2級堆棧段寄存器 DW 0 ;不使用,置爲0 TRCR3 DD 0 ;CR3 TREIP DD 0 ;EIP TREFlag DD 0 ;EFLAGS TREAX DD 0 ;EAX TRECX DD 0 ;ECX TREDX DD 0 ;EDX TREBX DD 0 ;EBX TRESP DD 0 ;ESP TREBP DD 0 ;EBP TRESI DD 0 ;ESI TREDI DD 0 ;EDI TRES DW 0 ;ES DW 0 ;不使用,置爲0 TRCS DW 0 ;CS DW 0 ;不使用,置爲0 TRSS DW 0 ;SS DW 0 ;不使用,置爲0 TRDS DW 0 ;DS DW 0 ;不使用,置爲0 TRFS DW 0 ;FS DW 0 ;不使用,置爲0 TRGS DW 0 ;GS DW 0 ;不使用,置爲0 TRLDTR DW 0 ;LDTR DW 0 ;不使用,置爲0 TRTrip DW 0 ;調試陷阱標誌(只用位0) TRIOMap DW $+2 ;指向I/O許可位圖區的段內偏移 TSS ENDS ;---------------------------------------------------------------------------- ;存儲段描述符類型值說明 ;---------------------------------------------------------------------------- ATDR EQU 90h ;存在的只讀數據段類型值 ATDW EQU 92h ;存在的可讀寫數據段屬性值 ATDWA EQU 93h ;存在的已訪問可讀寫數據段類型值 ATCE EQU 98h ;存在的只執行代碼段屬性值 ATCER EQU 9ah ;存在的可執行可讀代碼段屬性值 ATCCO EQU 9ch ;存在的只執行一致代碼段屬性值 ATCCOR EQU 9eh ;存在的可執行可讀一致代碼段屬性值 ;---------------------------------------------------------------------------- ;系統段描述符類型值說明 ;---------------------------------------------------------------------------- ATLDT EQU 82h ;局部描述符表段類型值 ATTaskGate EQU 85h ;任務門類型值 AT386TSS EQU 89h ;可用386任務狀態段類型值 AT386CGate EQU 8ch ;386調用門類型值 AT386IGate EQU 8eh ;386中斷門類型值 AT386TGate EQU 8fh ;386陷阱門類型值 ;---------------------------------------------------------------------------- ;DPL值說明 ;---------------------------------------------------------------------------- DPL0 EQU 00h ;DPL=0 DPL1 EQU 20h ;DPL=1 DPL2 EQU 40h ;DPL=2 DPL3 EQU 60h ;DPL=3 ;---------------------------------------------------------------------------- ;RPL值說明 ;---------------------------------------------------------------------------- RPL0 EQU 00h ;RPL=0 RPL1 EQU 01h ;RPL=1 RPL2 EQU 02h ;RPL=2 RPL3 EQU 03h ;RPL=3 ;---------------------------------------------------------------------------- ;IOPL值說明 ;---------------------------------------------------------------------------- IOPL0 EQU 0000h ;IOPL=0 IOPL1 EQU 1000h ;IOPL=1 IOPL2 EQU 2000h ;IOPL=2 IOPL3 EQU 3000h ;IOPL=3 ;---------------------------------------------------------------------------- ;其它常量值說明 ;---------------------------------------------------------------------------- D32 EQU 40h ;32位代碼段標誌 GL EQU 80h ;段界限以4K爲單位標誌 TIL EQU 04h ;TI=1(局部描述符表標誌) VMFL EQU 00020000h ;VMF=1 VMFLW EQU 0002h IFL EQU 00000200h ;IF=1 RFL EQU 00010000h ;RF=1(重啓動標誌,爲1表示忽略調試故障) RFLW EQU 0001h NTL EQU 00004000h ;NT=1 ;---------------------------------------------------------------------------- ;分頁機制使用的常量說明 ;---------------------------------------------------------------------------- PL EQU 1 ;頁存在屬性位 RWR EQU 0 ;R/W屬性位值,讀/執行 RWW EQU 2 ;R/W屬性位值,讀/寫/執行 USS EQU 0 ;U/S屬性位值,系統級 USU EQU 4 ;U/S屬性位值,用戶級 ;---------------------------------------------------------------------------- ;ENDIF
2.實例源程序
;名稱:ASM1.ASM ;功能:演示實方式和保護方式切換(切換到16位代碼段) ;---------------------------------------------------------------------------- INCLUDE 386SCD.INC ;---------------------------------------------------------------------------- ;字符顯示宏指令的定義 ;---------------------------------------------------------------------------- EchoCh MACRO ascii mov ah,2 mov dl,ascii int 21h ENDM ;---------------------------------------------------------------------------- DSEG SEGMENT USE16 ;16位數據段 ;---------------------------------------------------------------------------- GDT LABEL BYTE ;全局描述符表 DUMMY Desc <> ;空描述符 Code Desc <0ffffh,,,ATCE,,> ;代碼段描述符 DataS Desc <0ffffh,0,11h,ATDW,,> ;源數據段描述符 DataD Desc <0ffffh,,,ATDW,,> ;目標數據段描述符 ;---------------------------------------------------------------------------- GDTLen = $-GDT ;全局描述符表長度 VGDTR PDesc <GDTLen-1,> ;僞描述符 ;---------------------------------------------------------------------------- Code_Sel = Code-GDT ;代碼段選擇子 DataS_Sel = Datas-GDT ;源數據段選擇子 DataD_Sel = DataD-GDT ;目標數據段選擇子 ;---------------------------------------------------------------------------- BufLen = 256 ;緩衝區字節長度 Buffer DB BufLen DUP(0) ;緩衝區 ;---------------------------------------------------------------------------- DSEG ENDS ;數據段定義結束 ;---------------------------------------------------------------------------- CSEG SEGMENT USE16 ;16位代碼段 ASSUME CS:CSEG,DS:DSEG ;---------------------------------------------------------------------------- Start PROC mov ax,DSEG mov ds,ax ;準備要加載到GDTR的僞描述符 mov bx,16 mul bx add ax,OFFSET GDT ;計算並設置基地址 adc dx,0 ;界限已在定義時設置好 mov WORD PTR VGDTR.Base,ax mov WORD PTR VGDTR.Base+2,dx ;設置代碼段描述符 mov ax,cs mul bx mov WORD PTR Code.BaseL,ax ;代碼段開始偏移爲0 mov BYTE PTR Code.BaseM,dl ;代碼段界限已在定義時設置好 mov BYTE PTR Code.BaseH,dh ;設置目標數據段描述符 mov ax,ds mul bx ;計算並設置目標數據段基址 add ax,OFFSET Buffer adc dx,0 mov WORD PTR DataD.BaseL,ax mov BYTE PTR DataD.BaseM,dl mov BYTE PTR DataD.BaseH,dh ;加載GDTR lgdt QWORD PTR VGDTR cli ;關中斷 EnableA20 ;打開地址線A20 ;切換到保護方式 mov eax,cr0 or eax,1 mov cr0,eax ;清指令預取隊列,並真正進入保護方式 JUMP16 Code_Sel,<OFFSET Virtual> Virtual: ;現在開始在保護方式下運行 mov ax,DataS_Sel mov ds,ax ;加載源數據段描述符 mov ax,DataD_Sel mov es,ax ;加載目標數據段描述符 cld xor si,si xor di,di ;設置指針初值 mov cx,BufLen/4 ;設置4字節爲單位的緩衝區長度 repz movsd ;傳送 ;切換回實模式 mov eax,cr0 and al,11111110b mov cr0,eax ;清指令預取隊列,進入實方式 JUMP16 <SEG Real>,<OFFSET Real> Real: ;現在又回到實方式 DisableA20 sti mov ax,DSEG mov ds,ax mov si,OFFSET Buffer cld mov bp,BufLen/16 NextLine: mov cx,16 NextCh: lodsb push ax shr al,1 call ToASCII EchoCh al pop ax call ToASCII EchoCh al EchoCh ' ' loop NextCh EchoCh 0dh EchoCh 0ah dec bp jnz NextLine mov ax,4c00h int 21h Start ENDP ;---------------------------------------------------------------------------- ToASCII PROC and al,0fh add al,90h daa adc al,40h daa ret ToASCII ENDP ;---------------------------------------------------------------------------- CSEG ENDS ;代碼段定義結束 ;---------------------------------------------------------------------------- END Start
3.關於實例步驟的註釋
(1)切換到保護方式的準備工作
LGDT QWORD PTR VGDTR
(2)由實模式切換到保護模式
mov eax,cr0 or eax,1 mov cr0,eax
JUMP16 Code_Sel,<OFFSET Virtual>
(3)由保護模式切換到實模式
(4)保護模式下的數據傳送
(5)顯示緩衝區中的內容
4.內存映象
5.特別說明
6.打開和關閉地址線A20
<二>演示32位代碼段和16位代碼段切換的實例(實例二)
1.實例二源程序
;名稱:ASM2.ASM ;功能:演示實方式和保護方式切換(切換到32位代碼段) ;---------------------------------------------------------------------------- INCLUDE 386SCD.INC ;---------------------------------------------------------------------------- DSEG SEGMENT USE16 ;16位數據段 ;---------------------------------------------------------------------------- GDT LABEL BYTE ;全局描述符表 DUMMY Desc <> ;空描述符 Normal Desc <0ffffh,,,ATDW,,> ;規範段描述符 Code32 Desc <C32Len-1,,,ATCE,D32,> ;32位代碼段描述符 Code16 Desc <0ffffh,,,ATCE,,> ;16位代碼段描述符 DataS Desc <DataLen-1,0,10h,ATDR,,> ;源數據段描述符 DataD Desc <3999,8000h,0bh,ATDW,,> ;顯示緩衝區描述符 Stacks Desc <StackLen-1,,,ATDW,,> ;堆棧段描述符 ;---------------------------------------------------------------------------- GDTLen = $-GDT ;全局描述符表長度 VGDTR PDesc <GDTLen-1,> ;僞描述符 ;---------------------------------------------------------------------------- SaveSP DW ? ;用於保存SP寄存器 SaveSS DW ? ;用於保存SS寄存器 ;---------------------------------------------------------------------------- Normal_Sel = Normal-GDT ;規範段描述符選擇子 Code32_Sel = Code32-GDT ;32位代碼段選擇子 Code16_Sel = Code16-GDT ;16位代碼段選擇子 DataS_Sel = Datas-GDT ;源數據段選擇子 DataD_Sel = DataD-GDT ;目標數據段選擇子 Stacks_Sel = Stacks-GDT ;堆棧段描述符選擇子 ;---------------------------------------------------------------------------- DataLen = 16 ;---------------------------------------------------------------------------- DSEG ENDS ;數據段定義結束 ;---------------------------------------------------------------------------- StackSeg SEGMENT PARA STACK USE16 StackLen = 256 DB StackLen DUP(0) StackSeg ENDS ;---------------------------------------------------------------------------- CSEG1 SEGMENT USE16 'REAL' ;16位代碼段 ASSUME CS:CSEG1,DS:DSEG ;---------------------------------------------------------------------------- Start PROC mov ax,DSEG mov ds,ax ;準備要加載到GDTR的僞描述符 mov bx,16 mul bx add ax,OFFSET GDT ;計算並設置基地址 adc dx,0 ;界限已在定義時設置好 mov WORD PTR VGDTR.Base,ax mov WORD PTR VGDTR.Base+2,dx ;設置32位代碼段描述符 mov ax,CSEG2 mul bx mov WORD PTR Code32.BaseL,ax mov BYTE PTR Code32.BaseM,dl mov BYTE PTR Code32.BaseH,dh ;設置16位代碼段描述符 mov ax,CSEG3 mul bx mov WORD PTR Code16.BaseL,ax ;代碼段開始偏移爲0 mov BYTE PTR Code16.BaseM,dl ;代碼段界限已在定義時設置好 mov BYTE PTR Code16.BaseH,dh ;設置堆棧段描述符 mov ax,ss mov WORD PTR SaveSS,ax mov WORD PTR SaveSP,sp mov ax,StackSeg mul bx mov WORD PTR Stacks.BaseL,ax mov BYTE PTR Stacks.BaseM,dl mov BYTE PTR Stacks.BaseH,dh ;加載GDTR lgdt QWORD PTR VGDTR cli ;關中斷 EnableA20 ;打開地址線A20 ;切換到保護方式 mov eax,cr0 or al,1 mov cr0,eax ;清指令預取隊列,並真正進入保護方式 JUMP16 Code32_Sel,<OFFSET SPM32> ToReal: ;現在又回到實方式 mov ax,DSEG mov ds,ax mov sp,SaveSP mov ss,SaveSS DisableA20 sti mov ax,4c00h int 21h Start ENDP ;---------------------------------------------------------------------------- CSEG1 ENDS ;代碼段定義結束 ;---------------------------------------------------------------------------- CSEG2 SEGMENT USE32 'PM32' ASSUME CS:CSEG2 ;---------------------------------------------------------------------------- SPM32 PROC mov ax,Stacks_Sel mov ss,ax mov esp,StackLen mov ax,DataS_Sel mov ds,ax mov ax,DataD_Sel mov es,ax xor esi,esi xor edi,edi mov ecx,DataLen cld Next: lodsb push ax CALL ToASCII mov ah,7 shl eax,16 pop ax shr al,4 CALL ToASCII mov ah,7 stosd mov al,20h stosw loop Next JUMP32 Code16_Sel,<OFFSET SPM16> SPM32 ENDP ;---------------------------------------------------------------------------- ToASCII PROC and al,00001111b add al,30h cmp al,39h jbe Isdig add al,7 IsDig: ret ToASCII ENDP ;---------------------------------------------------------------------------- C32Len = $ ;---------------------------------------------------------------------------- CSEG2 ENDS ;---------------------------------------------------------------------------- CSEG3 SEGMENT USE16 'PM16' ASSUME CS:CSEG3 ;---------------------------------------------------------------------------- SPM16 PROC xor si,si mov di,DataLen*3*2 mov ah,7 mov cx,DataLen AGain: lodsb stosw loop AGain mov ax,Normal_sel mov ds,ax mov es,ax mov ss,ax mov eax,cr0 and al,11111110b mov cr0,eax jmp FAR PTR ToReal SPM16 ENDP ;---------------------------------------------------------------------------- CSEG3 ENDS ;---------------------------------------------------------------------------- END Start
2.關於實現步驟的註釋
(1)切換到保護模式的準備工作
(2)由實模式切換到保護模式
JUMP32 Code16_Sel,<OFFSET SPM16>
(3)顯示指定內存區域的內容
3.特別說明
實模 式下 段描 述符 高速 緩衝 寄存 器的 內容 |
段寄存器 | 段基地址 | 段界限(固定) | 段屬性(固定) | |||||||||
存在性 | 特權級 | 已存取 | 粒度 | 擴展方向 | 可讀性 | 可寫性 | 可執行 | 堆棧大小 | 一致特權 | ||||
CS | 當前CS*16 | 0000FFFFH | Y | 0 | Y | B | U | Y | Y | Y | - | N | |
SS | 當前SS*16 | 0000FFFFH | Y | 0 | Y | B | U | Y | Y | N | W | - | |
DS | 當前DS*16 | 0000FFFFH | Y | 0 | Y | B | U | Y | Y | N | - | - | |
ES | 當前ES*16 | 0000FFFFH | Y | 0 | Y | B | U | Y | Y | N | - | - | |
FS | 當前FS*16 | 0000FFFFH | Y | 0 | Y | B | U | Y | Y | N | - | - | |
GS | 當前GS*16 | 0000FFFFH | Y | 0 | Y | B | U | Y | Y | N | - | - |
4.關於32位代碼段程序設計的說明
參考資料 | 書 名 | 出 版 社 | 作 者 |
《保護方式下的80386及其編程》 | 清華大學出版社 | 周明德主編 | |
《80X86彙編語言程序設計教程》 | 清華大學出版社 | 揚季文主編 |