x86保護模式 實模式與保護模式切換實例


x86保護模式     實模式與保護模式切換實例

實例一
邏輯功能   以十六進制數的形式顯示從內存地址110000h開始的256個字節的值   
實現步驟:
1  切換保護方式的准備
2. 切換到保護方式
3. 把指定內存區域的內容傳送到位於常規內存的緩沖區中
4. 切換回實模式
5. 顯示緩沖區內容
 
代碼:
386保護模式匯編語言程序用到的包含文件如下所示,該包含文件在后面的程序中還要用到。
;名稱:386SCD.INC
;功能:符號常量等的定義
;----------------------------------------------------------------------------
;IFNDEF         __386SCD_INC     //宏定義
;__386SCD_INC   EQU     1
;----------------------------------------------------------------------------
.386P
;----------------------------------------------------------------------------
;打開A20地址線     宏定義
;----------------------------------------------------------------------------
EnableA20       MACRO        					// 使用32為地址線
                push    ax		//ax壓棧保存
                in      al,92h		//讀端口指令   92h端口的值送到al寄存器
                or      al,00000010b	//處理al的值  將位1變為1
                out     92h,al        //寫端口指令  將al的值送到92h   此時就是打開a20地址線
                pop     ax		//彈出棧中的ax值
                ENDM
;----------------------------------------------------------------------------
;關閉A20地址線
;----------------------------------------------------------------------------
DisableA20      MACRO
                push    ax
                in      al,92h
                and     al,11111101b		//將位1置為0   就是關閉a20地址線
                out     92h,al
                pop     ax
                ENDM
;----------------------------------------------------------------------------
;16位偏移的段間直接轉移指令的宏定義(在16位代碼段中使用)
;----------------------------------------------------------------------------
JUMP16          MACRO   Selector,Offset   	//宏定義: 【宏指令名】 MACRO 【形式參數,......】
                DB      0eah     ;操作碼		//宏使用格式      【宏指令名】【實在參數】
                DW      Offset   ;16位偏移量
                DW      Selector ;段值或段選擇子
                ENDM
;----------------------------------------------------------------------------
;32位偏移的段間直接轉移指令的宏定義(在32位代碼段中使用)
;----------------------------------------------------------------------------
COMMENT <JUMP32>
JUMP32          MACRO   Selector,Offset			//宏定義
                DB      0eah     ;操作碼		//根據x86操作碼結構和指令表   0eah的指令為jmpf
                DD      OFFSET				//此時偏移為32位     選擇子為16位
                DW      Selector ;段值或段選擇子
                ENDM
<JUMP32>
;-------------------------------------------------
JUMP32          MACRO   Selector,Offset			
                DB      0eah     ;操作碼			
                DW      OFFSET				//此時偏移為16位
                DW      0				//?高位是0    還是低位是0
                DW      Selector ;段值或段選擇子		//選擇子為16位	
                ENDM
;----------------------------------------------------------------------------
;16位偏移的段間調用指令的宏定義(在16位代碼段中使用)
;----------------------------------------------------------------------------
CALL16          MACRO   Selector,Offset      		//16位調用    宏定義
                DB      9ah      ;操作碼			//操作碼9ah 指令為callf
                DW      Offset   ;16位偏移量
                DW      Selector ;段值或段選擇子
                ENDM
;----------------------------------------------------------------------------
;32位偏移的段間調用指令的宏定義(在32位代碼段中使用)
;----------------------------------------------------------------------------
COMMENT <CALL32>
CALL32          MACRO   Selector,Offset
                DB      9ah      ;操作碼
                DD      Offset			//偏移為32位
                DW      Selector ;段值或段選擇子
                ENDM
<CALL32>
;-------------------------------------------------
CALL32          MACRO   Selector,Offset
                DB      9ah      ;操作碼
                DW      Offset			//偏移為16位
                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			//gdtr寄存器 idtr寄存器為48位
Limit           DW      0 ;16位界限     //規定gdtr表的大小    項目
Base            DD      0 ;32位基地址	//gdtr表的存儲位置
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	//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 ;存在的可執行可讀一致代碼段屬性值
;----------------------------------------------------------------------------
;系統段描述符類型值說明 		門描述符    ldt    tss  三種
;----------------------------------------------------------------------------
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     	//dos系統功能調用int21h    ah=02 表示顯示輸出
                mov     ah,2		//dl=輸出字符
                mov     dl,ascii
                int     21h
                ENDM
;----------------------------------------------------------------------------
DSEG            SEGMENT USE16                 ;16位數據段
;----------------------------------------------------------------------------
GDT             LABEL   BYTE                  ;全局描述符表
DUMMY           Desc    <>                    ;空描述符
Code            Desc    <0ffffh,,,ATCE,,>     ;代碼段描述符    以下分別為8字節長  空為全0
DataS           Desc    <0ffffh,0,11h,ATDW,,> ;源數據段描述符
DataD           Desc    <0ffffh,,,ATDW,,>     ;目標數據段描述符
;----------------------------------------------------------------------------
GDTLen          =       $-GDT                 ;全局描述符表長度    當前值-gdt首地址   為字節長度
VGDTR           PDesc   <GDTLen-1,>           ;偽描述符   GDtr寄存器值 16位的界限值定義   基地址為空
;----------------------------------------------------------------------------
Code_Sel        =       Code-GDT              ;代碼段選擇子   以下為定義16為選擇子相對於與表首的偏移值
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			//設置數據段寄存器  指向dseg定義處
                ;准備要加載到GDTR的偽描述符   //設置基地址 32位   界限已經定義過了
                mov     bx,16
                mul     bx			//mul是進行無符號乘法的指令 ax*bx,結果高16位存dx 低16位存ax 
											//相當於ax的值向左移4位			
                add     ax,OFFSET GDT          ;計算並設置基地址 實模式下段寄存器左移4位變為20位的段基地址再加偏移
                adc     dx,0                   ;界限已在定義時設置好    注意dx需要帶進位  根據上一個操作
                mov     WORD PTR VGDTR.Base,ax//高16位
                mov     WORD PTR VGDTR.Base+2,dx//低16位   並且帶進位   dx:ax共同組成32位的基地址
                ;設置代碼段描述符
                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                            ;關中斷       開中斷sti
                EnableA20                      ;打開地址線A20
                ;切換到保護方式
                mov     eax,cr0
                or      eax,1        //cr0中的位0置為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				//si   di  變化方向  加還是減
                xor     si,si			//si和di清零
                xor     di,di                  ;設置指針初值
                mov     cx,BufLen/4            ;設置4字節為單位的緩沖區長度  設置計數器
                repz    movsd                  ;傳送雙字
                ;切換回實模式
                mov     eax,cr0
                and     al,11111110b    		//最低位清0   進入實模式
                mov     cr0,eax
                ;清指令預取隊列,進入實方式
                JUMP16  <SEG Real>,<OFFSET Real>
Real:           ;現在又回到實方式
                DisableA20			開中斷
                sti				//開中斷
                mov     ax,DSEG
                mov     ds,ax
                mov     si,OFFSET Buffer		//ds:si
                cld						
                mov     bp,BufLen/16		//bp 外循環次數 16行
NextLine:       mov     cx,16 //內循環次數 一行16個字符
NextCh:         lodsb //目的地址的內容讀到源地址  串操作 塊讀出指令
 // 即目標地址為es:di 源地址為ds:si 字節為單位傳送
                push    ax
                shr     al,1 //右移1位
                call    ToASCII			//調用子程序 toascii
                EchoCh  al //宏展開 echoch
                pop     ax
                call    ToASCII
                EchoCh  al
                EchoCh  ' '
                loop    NextCh 			//計數器為16    為0時跳出
                EchoCh  0dh			//實參傳遞給宏
                EchoCh  0ah
                dec     bp			//外循環的次數減1
                jnz     NextLine
                mov     ax,4c00h			//中斷
                int     21h
Start           ENDP
;----------------------------------------------------------------------------
//子程序定義
ToASCII         PROC			//轉換為ascii碼
                and     al,0fh		//al低4位不變    高四位   變為0
                add     al,90h		//高4位變為9  低4位不變
                daa			//說明三
                adc     al,40h		//帶進位加法   al變為對應的ascii碼
                daa
                ret
ToASCII         ENDP
;----------------------------------------------------------------------------
CSEG            ENDS                           ;代碼段定義結束
;----------------------------------------------------------------------------
                END     Start
說明:一mul指令
1將8位的操作數與al相乘 2將16位的操作數與ax相乘 3是將32位的操作數與eax相乘 乘積是乘數大小的2倍 三種格式都接受寄存器操作數和內存操作數 但是不接受立即數;
被乘數 乘數 積
al 8位 ax
ax 16位 dx:ax         dx存高16位      ax存低16位
eax 32位 edx:eax
 
二 lodsb   lodsw      與stosb   stosw 分別對應
串操作指令    lodsb   lodsw是塊讀出指令   具體操作是把si指向的存儲單元讀入累加器   器中lodsb是寫入al    lodsw寫入
ax  ,然后si自動增加或減少1或2位   當方向df為0時   si自增 ;df為1則自減
stosb從al中讀取      stosw從ax讀取
三 daa   bcd碼的加法調整指令
將al的內容調整為兩位的組合型的二進制數   daa指令要分別考慮al的高4位和低4位
如果al的低4位大於9或af=1 ,則al的內容加06h   並將af置1;然后如果al的高4位大於9或cf=1  則al的內容加60h,且將cf置為1   如果兩個都不滿足   則將af,cf清零。
四切換到保護方式的准備工作
1.建立合適的全局描述符表  並使gdtr指向該gdt    在切換到保護方式時   至少要把代碼段的選擇子裝載到cs  所以gdt中至少含有代碼段的描述符
實例中各使用的存儲段的描述符的界限都定義為0ffffh    根據屬性可知三個段都是16位段
加載gdtr    
LGDT  QWORD  PTR   VGDTR
將存儲器中的偽描述符VGDTR裝入全局描述符表寄存器GDTR中   
2.由實模式切換到保護模式
cr0中的PE位置置為1即可
之后要馬上把代碼段的選擇子存入cs   
jmp16 code_sel,<OFFSET VIRTUAL>
上面的段間轉移指令在實模式下被預取   並在保護模式下被執行
3.由保護模式切換到實模式
cr0中的pe位為0   同時后面也要有一條段間轉移指令    目的1為清除指令序列   目的2為將實模式下的代碼段的段值送cs   此指令在保護方式下被預取  但是在實模式下執行
4.保護模式下的數據傳送
源數據段和目的數據段的選擇子裝入ds    和es寄存器    這兩個描述符已經在實模式下設置好   並把選擇子裝入段寄存器同時把描述符的信息裝入到對應的高速緩沖寄存器      再設置si和di指針   cs計數器   ;根據段屬性的值可以判斷都為16位的段   串操作指令只是用16位的si和di 和cx寄存器   最后利用串操作指令實施傳送
5.顯示緩沖區的內容
緩沖區在常規內存中   即1m之內   所以需要在實模式下按要求以16進制數的形式顯示其內容
五   內存映像

 

 

六特別說明
本實例簡化程序   未定義中斷描述符表      所以整個過程實在關中斷的情況下運行的   
未定義ldt表   所以進入保護模式后默認的段選擇子都位於gdt中
未定義保護模式下的堆棧段   gdt中沒有堆棧描述符    所以程序不涉及堆棧的操作
各個描述符的特權級別均為0   dpl  rpl   cpl 均為0
未采用分頁管理機制   cr0中的PG位為0   線性地址就是存儲單元的物理地址
打開和關閉a20地址線      pc兼容機中的第21根地址線
系統中的一個門控制該地址線   是否有效   
為了訪問地址在1m以上的存儲段安源 應該先打開控制地址線a20的門   ;此設置與實模式只用1m內的空間有關  ,而與cpu是否工作在實模式還是保護模式無關   即使關閉a20地址線   也可以進入保護模式
 
 
實例二 32位代碼段和16位代碼段切換的實例
 
低聲飛過  同實例一的邏輯功能相同    
具體實現步驟:
1.切換保護方式准備
2.切換到保護方式的一個32位代碼段
3.將指定內存區域的內容以字節為單位  轉換成對應的十六進制數的ascii碼  並 填入顯示緩沖區實現顯示
4.再變換到保護方式下的一個16代碼段
5.將指定內存區域的內容直接作為ascii碼填入顯示緩沖區中實現顯示
6.切換到實模式
源程序如下:
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) //定義256個字節長度
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     		// 代碼段開始偏移為0   
                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 //用來保存ss段寄存器中的值
                mov     WORD PTR SaveSP,sp //用來保存sp段寄存器中的值
                movax,StackSeg		
mulbxmovWORDPTR Stacks.BaseL,axmovBYTEPTR Stacks.BaseM,dlmovBYTEPTR Stacks.BaseH,dh;加載GDTRlgdtQWORDPTR VGDTR			//加載偽描述符 到gdtr寄存器
                cli;關中斷EnableA20;打開地址線A20;切換到保護方式moveax,cr0oral,1movcr0,eax;清指令預取隊列,並真正進入保護方式JUMP16Code32_Sel,<OFFSET SPM32> 	//跳轉指令  傳給宏JUMP16 實參值ToReal:;現在又回到實方式     movax,DSEG
                movds,axmovsp,SaveSP
                movss,SaveSS
                DisableA20				//關閉a20地址線sti					//打開中斷movax,4c00h			int21h
Start           ENDP					//程序的末尾;----------------------------------------------------------------------------
CSEG1           ENDS;代碼段定義結束
;----------------------------------------------------------------------------
CSEG2           SEGMENTUSE32'PM32'   		//32位 代碼段   保護模式下執行ASSUMECS:CSEG2
;----------------------------------------------------------------------------
SPM32           PROCmovax,Stacks_Sel
                movss,ax			//將堆棧的選擇子裝入到ss段寄存器movesp,StackLen		//esp指向棧頂
                movax,DataS_Sel		//將源數據段選擇子裝入ds段寄存器
                movds,ax			movax,DataD_Sel		//目的數據段選擇子裝入es寄存器
                moves,axxoresi,esi			//指針清零   用 ds:esixoredi,edi			//用es:edimovecx,DataLen		//計數器賦初值
                cldNext:lodsb //塊傳送 si指向的字節內容寫入al 算法過程看備注pushax 入棧CALL ToASCII			//調用子程序 顯示ascii碼 movah,7shleax,16 //左移 16位popaxshral,4 //右移4位CALL ToASCII movah,7stosd //將al的內容存入edi指向的內存單元中moval,20h //空格stosw //從ax讀取出數據 存入edi指向的內存單元
 //如果使用的是stosd 則將eax的內容存入edi指向的內存單元 loop Next //循環 ecx-1 直到ecx=0為止
                JUMP32   Code16_Sel,<OFFSET SPM16> //跳轉到16位代碼段
SPM32           ENDP
;----------------------------------------------------------------------------
ToASCII         PROC
                and     al,00001111b //高4位清0
                add     al,30h //加30h 0+30h=30h 對應的ascii碼為0
                cmp     al,39h //比較低4位與9的大小
                jbe     Isdig			//小於等於 39h 跳轉   說明是數字   判斷是數字還是字母
                add     al,7 //大於39h的就是字母 對應的
IsDig:          ret
ToASCII         ENDP
;----------------------------------------------------------------------------
C32Len          =       $
;----------------------------------------------------------------------------
CSEG2           ENDS
 
        
;----------------------------------------------------------------------------
CSEG3           SEGMENT USE16 'PM16'	//16位代碼段
                ASSUME  CS:CSEG3		
;----------------------------------------------------------------------------
SPM16           PROC
                xor     si,si
                mov     di,DataLen*3*2
                mov     ah,7
                mov     cx,DataLen
AGain:          lodsb		//從di指向的內存地址  取數據存入al
                stosw		//讀ax數據   寫到edi指向的內存單元  ah為7
                loop    AGain	//循環塊傳送  直到cx值為0
                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
注釋
1.切換到保護模式的准備工作
建立全局描述符表,含有兩個16位數據段的描述符  一個16位代碼段的描述符和一個16位堆棧段描述符    
一個32位代碼段描述符      
2.實模式切換到保護模式
JUMP32 CODE16_SEL,<OFFSET SPM16>
該轉移指令含48位指針  其中高16位是選擇子   低32位是16位代碼段的入口偏移
3.顯示指定內存區域的內容
直接寫顯示緩沖區的方法實現顯示 
4.特別說明  在程序的結尾   給各個段寄存器傳遞一個normal的選擇子
在分段管理機制中  每個段寄存器都有高速緩沖寄存器    這些寄存器在實模式下仍然有作用    僅僅是內容上與保護方式不同;段屬性值在實模式下沒有意義 實模式下不可設置;  而且段的基地址位數不同保護為32位  而實模式下位20位    
所以在准備結束保護模式回到實模式之前,要通過加載一個合適的描述符選擇子到有關段寄存器   以使 得對應段描述符高速緩沖寄存器中含有合適的段界限和屬性值
需要注意的是不能從32位代碼段返回到實模式    而是需要從16位代碼段返回
在32位代碼段中  缺省的操作數大小是32位    缺省的存儲單元地址大小是32位 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM