您的位置:首页 > 编程语言

特权级代码段之间的转移---任务内特权级变换转移

2016-09-03 12:07 239 查看
一、演示任务内特权级变换的实例 

下面给出一个演示任务内特权级变换的实例。该实例演示在任务内通过调用门从外层特权级变换到内层特权级;也演示通过段间返回指令从内层特权级变换到外层特权级;还演示通过调用门的无特权级变换的转移。实例使用了任务状态段 TSS,这是因为任务内特权级变换时要使用的内层堆栈指针存放在 TSS 中。

1.实现步骤
该实例的实现步骤为:

(1)实方式下初始化;

(2)切换到保护模式;

(3)设置 TR 和 LDTR。由于在任务内发生特权级变换时要切换堆栈,而内层堆栈的指针存放在当前任务的 TSS 中,所以在进入保护

模式后设置任务状态段寄存器 TR。由于演示任务使用了局部描述符表,所以设置 LDTR;

(4)经调用门进入 32 位过渡代码段;

(5)建立返回 3 级演示代码段的环境;

(6)利用 RET 指令转移到 3 级的演示代码段。为了演示外层程序通过调用门调用内层程序,要使 CPL>0。实例先通过段间返回指令

RET 从特权级 0 变换到特权级 3 的演示代码段。在特权级 3 下,通过调用门调用 1 级的子程序。随着执行段间返回指令 RET,又回到 3级的演示代码段;

(7)在 3 级的演示代码段中,经调用门转移到 0 级的 32 位过渡代码段;(8)直接转 0 级的临时代码段;

(9)准备返回实模式;

(10)切换回实模式;

(11)实模式下的恢复工作。

2.源程序组织和清单
实例四由如下部分组成:

(1)全局描述符表 GDT。GDT 含有演示任务的 TSS 段描述符和 LDT 段描述符,此外还含有临时代码段的描述符、规范数据段描述符和视频缓冲区段描述符。

(2)演示任务的 LDT 段。它含有除临时代码段外的其它代码段的描述符和演示任务各级堆栈段描述符,还含有 3 个调用门。

(3)演示任务的 TSS 段。

(4)演示任务的 0 级、1 级和 3 级堆栈段。

(5)显示子程序段。32 位代码段,特权级 1。

(6)演示代码段。32 位代码段,特权级 3。

(7)过渡代码段。32 位段,特权级 0。

(8)临时代码段。16 位段,特权级 0。

(9)实模式下的数据和代码段。该实例的逻辑功能是显示演示代码段执行时的当前特权级 CPL和TI。源程序清单如下: 

[cpp]
view plain
copy

;windows  
;16位偏移的段间直接转移指令的宏定义(在16位代码段中使用)  
;----------------------------------------------------------------------------  
JUMP16 MACRO Selector,Offsetv  
    DB 0eah ;操作码  
    DW Offsetv ;16位偏移量  
    DW Selector ;段值或段选择子  
ENDM  
;----------------------------------------------------------------------------  
;32位偏移的段间直接转移指令的宏定义(在32位代码段中使用)  
;----------------------------------------------------------------------------  
COMMENT <JUMP32>  
JUMP32 MACRO Selector,Offsetv  
    DB 0eah ;操作码  
    DD Offsetv  
    DW Selector ;段值或段选择子  
ENDM  
<JUMP32>  
;-------------------------------------------------  
JUMP32 MACRO Selector,Offsetv  
    DB 0eah ;操作码  
    DW Offsetv  
    DW 0  
    DW Selector ;段值或段选择子  
ENDM  
;----------------------------------------------------------------------------  
;门描述符结构类型定义  
;----------------------------------------------------------------------------  
Gate STRUC  
OffsetL DW 0 ;32位偏移的低16位  
Selector DW 0 ;选择子  
DCount DB 0 ;双字计数  
GType DB 0 ;类型  
OffsetH DW 0 ;32位偏移的高16位  
Gate ENDS  
;----------------------------------------------------------------------------  
  
;16位偏移的段间调用指令的宏定义(在16位代码段中使用)  
;----------------------------------------------------------------------------  
CALL16 MACRO Selector,Offsetv  
    DB 9ah ;操作码  
    DW Offsetv ;16位偏移量  
    DW Selector ;段值或段选择子  
ENDM  
;----------------------------------------------------------------------------  
;32位偏移的段间调用指令的宏定义(在32位代码段中使用)  
;----------------------------------------------------------------------------  
COMMENT <CALL32>  
CALL32 MACRO Selector,Offsetv  
    DB 9ah ;操作码  
    DD Offsetv  
    DW Selector ;段值或段选择子  
ENDM  
<CALL32>  
;-------------------------------------------------  
CALL32 MACRO Selector,Offsetv  
    DB 9ah ;操作码  
    DW Offsetv  
    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  
;----------------------------------------------------------------------------  
  
  
;伪描述符结构类型定义(用于装入全局或中断描述符表寄存器)  
;----------------------------------------------------------------------------  
PDesc STRUC  
    Limit DW 0 ;16位界限  
    Base DD 0 ;32位基地址  
PDesc ENDS  
;----------------------------------------------------------------------------  
;存储段描述符类型值说明  
;----------------------------------------------------------------------------  
D32 EQU 40h ;32位代码段标志  
ATDR EQU 90h ;存在的只读数据段类型值  
ATDW EQU 92h ;存在的可读写数据段属性值  
ATDWA EQU 93h ;存在的已访问可读写数据段类型值  
ATCE EQU 98h ;存在的只执行代码段属性值  
ATCER EQU 9ah ;存在的可执行可读代码段属性值  
  
;----------------------------------------------------------------------------  
;系统段描述符类型值说明  
;----------------------------------------------------------------------------  
ATLDT EQU 82h ;局部描述符表段类型值  
  
;----------------------------------------------------------------------------  
;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  
;----------------------------------------------------------------------------  
  
;----------------------------------------------------------------------------  
;其它常量值说明  
;----------------------------------------------------------------------------  
  
TIL EQU 04h ;TI=1(局部描述符表标志)  
AT386TSS EQU 89h ;可用386任务状态段类型值  
AT386CGate EQU 8ch ;386调用门类型值  
;----------------------------------------------------------------------------  
  
.386p  
  
GDTSeg          SEGMENT PARA USE16                ;全局描述符表数据段(16位)  
;----------------------------------------------------------------------------  
                ;全局描述符表  
GDT             LABEL   BYTE  
                ;空描述符  
DUMMY           Desc    <>  
                ;规范段描述符  
Normal          Desc    <0ffffh,,,ATDW,,>  
                ;视频缓冲区段描述符(DPL=3)  
VideoBuf        Desc    <07fffh,8000h,0bh,ATDW+DPL3,,>  
;----------------------------------------------------------------------------  
EFFGDT          LABEL   BYTE  
                ;任务状态段TSS描述符  
DemoTSS         Desc    <DemoTSSLen-1,DemoTSSSeg,,AT386TSS,,>  
                ;局部描述符表段的描述符  
DemoLDTD        Desc    <DemoLDTLen-1,DemoLDTSeg,,ATLDT,,>  
                ;临时代码段描述符  
TempCode        Desc    <0ffffh,TempCodeSeg,,ATCE,,>  ;注意它的存储段描述符  
;----------------------------------------------------------------------------  
GDTLen          =       $-GDT                     ;全局描述符表长度  
GDNum           =       ($-EFFGDT)/(SIZE Desc)    ;需特殊处理的描述符数  
;----------------------------------------------------------------------------  
Normal_Sel      =       Normal-GDT                ;规范段描述符选择子  
Video_Sel       =       VideoBuf-GDT              ;视频缓冲区段描述符选择子  
;----------------------------------------------------------------------------  
DemoTSS_Sel     =       DemoTSS-GDT               ;任务状态段描述符选择子  
DemoLDT_Sel     =       DemoLDTD-GDT              ;局部描述符表段的选择子  
TempCode_Sel    =       TempCode-GDT              ;临时代码段的选择子  
;----------------------------------------------------------------------------  
GDTSeg          ENDS                              ;全局描述符表段定义结束  
;----------------------------------------------------------------------------  
DemoLDTSeg      SEGMENT PARA USE16                ;局部描述符表数据段(16位)  
;----------------------------------------------------------------------------  
DemoLDT         LABEL   BYTE                      ;局部描述符表  
                ;0级堆栈段描述符(32位段)  
DemoStack0      Desc    <DemoStack0Len-1,DemoStack0Seg,,ATDW+DPL0,D32,>  
                ;1级堆栈段描述符(32位段)  
DemoStack1      Desc    <DemoStack1Len-1,DemoStack1Seg,,ATDW+DPL1,D32,>  
                ;3级堆栈段描述符(16位段)  
DemoStack3      Desc    <DemoStack3Len-1,DemoStack3Seg,,ATDW+DPL3,,>  
                ;代码段描述符(32位段,DPL=3)  
DemoCode        Desc    <DemoCodeLEN-1,DemoCodeSeg,,ATCE+DPL3,D32,>  
                ;过渡代码段描述符(32位段)  
T32Code         Desc    <T32CodeLen-1,T32CodeSeg,,ATCE,D32,>  
                ;显示子程序代码段描述符(32位段,DPL=1)  
EchoSubR        Desc    <EchoSubRLen-1,EchoSubRSeg,,ATCER+DPL1,D32,>  
;----------------------------------------------------------------------------  
DemoLDNum       =       ($-DemoLDT)/(SIZE Desc)  
;----------------------------------------------------------------------------  
                ;0级堆栈描述符选择子(RPL=0)  
DemoStack0_Sel  =       DemoStack0-DemoLDT+TIL+RPL0  
                ;1级堆栈描述符选择子(RPL=1)  
DemoStack1_Sel  =       DemoStack1-DemoLDT+TIL+RPL1  
                ;3级堆栈描述符选择子(RPL=3)  
DemoStack3_Sel  =       DemoStack3-DemoLDT+TIL+RPL3  
                ;代码段描述符选择子(RPL=3)  
DemoCode_Sel    =       DemoCode-DemoLDT+TIL+RPL3  
                ;过渡代码段描述符选择子  
T32Code_Sel     =       T32Code-DemoLDT+TIL  
                ;显示子程序代码段描述符选择子(RPL=1)  
Echo_Sel1       =       EchoSubR-DemoLDT+TIL+RPL1  
                ;显示子程序代码段描述符选择子(RPL=3)  
Echo_Sel3       =       EchoSubR-DemoLDT+TIL+RPL3  
;----------------------------------------------------------------------------  
                ;指向过渡代码段内T32Begin点的调用门(DPL=0)  
ToT32GateA      Gate    <T32Begin,T32Code_Sel,,AT386CGate,>  
                ;指向过渡代码段内T32End点的调用门(DPL=3)  
ToT32GateB      Gate    <T32End,T32Code_Sel,,AT386CGate+DPL3,>  
                ;指向显示子程序代码段的调用门(DPL=3)  
ToEchoGate      Gate    <EchoSUB,Echo_Sel3,,AT386CGate+DPL3,>  
;----------------------------------------------------------------------------  
DemoLDTLen      =       $-DemoLDT  
;----------------------------------------------------------------------------  
                ;指向过渡代码段内T32Begin点的调用门的选择子  
ToT32A_Sel      =       ToT32GateA-DemoLDT+TIL  
                ;指向过渡代码段内T32End点的调用门的选择子  
ToT32B_Sel      =       ToT32GateB-DemoLDT+TIL  
                ;显示子程序调用门的选择子  
ToEcho_Sel      =       ToEchoGate-DemoLDT+TIL  
;----------------------------------------------------------------------------  
DemoLDTSeg      ENDS                              ;局部描述符表段定义结束  
;----------------------------------------------------------------------------  
DemoTSSSeg      SEGMENT PARA USE16                ;任务状态段TSS  
;----------------------------------------------------------------------------  
                DD      0                         ;Back  
                DW      DemoStack0Len,0            ;0级堆栈指针  
                DW      DemoStack0_Sel,0            ;初始化  
                DW      DemoStack1Len,0             ;1级堆栈指针  
                DW      DemoStack1_Sel,0            ;初始化  
                DD      0                         ;2级堆栈指针  
                DD      0                         ;未初始化  
                DD      0                         ;CR3  
                DD      0                         ;EIP  
                DD      0                         ;EFLAGS  
                DD      0                         ;EAX  
                DD      0                         ;ECX  
                DD      0                         ;EDX  
                DD      0                         ;EBX  
                DD      0                         ;ESP  
                DD      0                         ;EBP  
                DD      0                         ;ESI  
                DD      0                         ;EDI  
                DW      ?,0                         ;ES  
                DW      ?,0                         ;CS  
                DW      ?,0                         ;SS  
                DW      ?,0                         ;DS  
                DW      ?,0                         ;FS  
                DW      ?,0                         ;GS  
                DW      DemoLDT_Sel,0               ;LDT  
                DW      0                         ;调试陷阱标志  
                DW      $+2                       ;指向I/O许可位图  
                DB      0ffh                    ;I/O许可位图结束标志  
;----------------------------------------------------------------------------  
DemoTSSLen      =       $-DemoTSSSeg  
;----------------------------------------------------------------------------  
DemoTSSSeg      ENDS                              ;任务状态段TSS结束  
;----------------------------------------------------------------------------  
DemoStack0Seg   SEGMENT DWORD STACK USE32         ;0级堆栈段(32位段)  
DemoStack0Len   =       512  
                DB      DemoStack0Len DUP(0)  
DemoStack0Seg   ENDS                              ;0级堆栈段结束  
;----------------------------------------------------------------------------  
DemoStack1Seg   SEGMENT DWORD STACK USE32         ;1级堆栈段(32位段)  
DemoStack1Len   =       512  
                DB      DemoStack1Len DUP(0)  
DemoStack1Seg   ENDS                              ;1级堆栈段结束  
;----------------------------------------------------------------------------  
DemoStack3Seg   SEGMENT DWORD STACK USE16         ;3级堆栈段(16位段)  
DemoStack3Len   =       512  
                DB      DemoStack3Len DUP(?)  
DemoStack3Seg   ENDS                              ;3级堆栈段结束  
;----------------------------------------------------------------------------  
EchoSubRSeg     SEGMENT PARA USE32                ;显示子程序代码段(32位,1级)  
                ASSUME  CS:EchoSubRSeg  
;----------------------------------------------------------------------------  
Message         DB      'CPL=  TI=',0                  ;显示信息(该代码段可读)  
;----------------------------------------------------------------------------  
EchoSub         PROC    FAR  
                cld  
                push    ebp  
                mov     ebp,esp  
                mov     ax,Echo_Sel1                ;该代码段是可读段  
                mov     ds,ax                     ;采用RPL=1的选择子  
                mov     ax,Video_Sel  
                mov     es,ax  
                mov     edi,320                   ;信息显示位置  
                mov     esi,OFFSET Message  
                mov     ah,4eh                    ;置显示属性(红底黄字)  
EchoSub1:        lodsb  
                or      al,al  
                jz      EchoSub2  
                stosw  
                jmp     EchoSub1  
EchoSub2:         mov     al,[ebp+8]               ;从堆栈中取调用程序的选择子  
                and     al,3                      ;调用程序的CPL在CS的RPL字段  
                add     al,'0'  
                mov     ah,4eh                    ;置显示属性(红底黄字)  
           sub     edi,10  
                stosw  
           add     edi,8  
           mov     al,[ebp+8]               ;从堆栈中取调用程序的选择子  
                and     al,1                     ;调用程序TI字段  
                add     al,'0'  
                mov     ah,4eh    
           stosw  
                pop     ebp  
                retf  
EchoSub         ENDP  
;----------------------------------------------------------------------------  
EchoSubRLen     =       $-EchoSubRSeg  
;----------------------------------------------------------------------------  
EchoSubRSeg     ENDS                              ;显示子程序代码段结束  
;----------------------------------------------------------------------------  
DemoCodeSeg     SEGMENT PARA USE32                ;32位代码段(3级)  
                ASSUME  CS:DemoCodeSeg  
;----------------------------------------------------------------------------  
DemoBegin       PROC    FAR  
                CALL32  ToEcho_Sel,0              ;显示当前特权级(变换到1级)  
                CALL32  ToT32B_Sel,0              ;转到过渡代码段(变换到0级)  
DemoBegin       ENDP  
DemoCodeLen     =       $-DemoCodeSeg  
;----------------------------------------------------------------------------  
DemoCodeSeg     ENDS                              ;32位代码段结束  
;----------------------------------------------------------------------------  
T32CodeSeg      SEGMENT PARA USE32                ;32位过渡代码段(0级)  
                ASSUME  CS:T32CodeSeg  
;----------------------------------------------------------------------------  
T32Begin        PROC    FAR  
                mov     ax,DemoStack0_Sel         ;建立0级堆栈  
                mov     ss,ax  
                mov     esp,DemoStack0Len  
                push    DWORD PTR DemoStack3_Sel  ;压入3级堆栈指针  
                push    DemoStack3Len  
                push    DWORD PTR DemoCode_SEL    ;压入入口点  
                push    OFFSET DemoBegin  
                retf                              ;利用RET实现转3级的演示代码  
T32Begin        ENDP  
;----------------------------------------------------------------------------  
T32End          PROC    FAR  
                JUMP32  TempCode_Sel,<OFFSET ToReal>  
T32End          ENDP  
T32CodeLen      =       $-T32CodeSeg  
;----------------------------------------------------------------------------  
T32CodeSeg      ENDS  
;----------------------------------------------------------------------------  
TempCodeSeg     SEGMENT PARA USE16                ;16位临时代码段(0级)  
                ASSUME  CS:TempCodeSeg  
;----------------------------------------------------------------------------  
Virtual         PROC    FAR  
                mov     ax,DemoTSS_Sel            ;装载TR  
                ltr     ax  
                mov     ax,DemoLDT_Sel            ;装载LDTR  
                lldt    ax  
                JUMP16  ToT32A_Sel,0              ;通过调用门转过渡段  
ToReal:          mov     ax,Normal_Sel             ;准备切换回实模式  
                mov     ds,ax  
                mov     es,ax  
                mov     fs,ax  
                mov     gs,ax  
                mov     ss,ax  
                mov     eax,cr0  
                and     al,11111110b  
                mov     cr0,eax  
                JUMP16  <SEG Real>,<OFFSET Real>  
Virtual         ENDP  
;----------------------------------------------------------------------------  
TempCodeLen     =       $-TempCodeSeg  
TempCodeSeg     ENDS  
  
;============================================================================  
RDataSeg        SEGMENT PARA USE16                ;实方式数据段  
VGDTR           PDesc   <GDTLen-1,>               ;GDT伪描述符  
SPVar           DW      ?                         ;用于保存实方式下的SP  
SSVar           DW      ?                         ;用于保存实方式下的SS  
RDataSeg        ENDS  
;----------------------------------------------------------------------------  
RCodeSeg        SEGMENT PARA USE16  
                ASSUME  CS:RCodeSeg,DS:RDataSeg  
;----------------------------------------------------------------------------  
Start           PROC  
                mov     ax,RDataSeg  
                mov     ds,ax  
                cld  
                CALL    InitGDT                   ;初始化全局描述符表GDT  
                mov     ax,DemoLDTSeg  
                mov     fs,ax  
                mov     si,OFFSET DemoLDT  
                mov     cx,DemoLDNum  
                CALL    InitLDT                   ;初始化局部描述符表LDT  
                mov     SSVar,ss  
                mov     SPVar,sp  
                lgdt    FWORD PTR VGDTR           ;装载GDTR并切换到保护方式  
                cli  
                mov     eax,cr0  
                or      al,1  
                mov     cr0,eax  
                JUMP16  <TempCode_Sel>,<OFFSET Virtual>  
Real:            mov     ax,RDataSeg  
                mov     ds,ax  
                lss     sp,DWORD PTR SPVar        ;又回到实方式  
                sti  
                mov     ax,4c00h  
                int     21h  
Start           ENDP  
;----------------------------------------------------------------------------  
;初始化GDT表  
InitGDT         PROC  
                push    ds  
                mov     ax,GDTSeg  
                mov     ds,ax  
                mov     cx,GDNum  
                mov     si,OFFSET EFFGDT  
InitG:           mov     ax,[si].BaseL  
                movzx   eax,ax  
                shl     eax,4  
                shld    edx,eax,16  
                mov     WORD PTR [si].BaseL,ax  
                mov     BYTE PTR [si].BaseM,dl  
                mov     BYTE PTR [si].BaseH,dh  
                add     si,SIZE Desc  
                loop    InitG  
                pop     ds  
                mov     bx,16  
                mov     ax,GDTSeg  
                mul     bx  
                mov     WORD PTR VGDTR.Base,ax  
                mov     WORD PTR VGDTR.Base+2,dx  
                ret  
InitGDT         ENDP  
;----------------------------------------------------------------------------  
;初始化LDT表  
;入口参数:FS:SI=第一个要初始化的描述符,CX=要初始化的描述符数  
;----------------------------------------------------------------------------  
InitLDT         PROC  
ILDT:            mov     ax,WORD PTR FS:[si].BaseL  
                movzx   eax,ax  
                shl     eax,4  
                shld    edx,eax,16  
                mov     WORD PTR fs:[si].BaseL,ax  
                mov     BYTE PTR fs:[si].BaseM,dl  
                mov     BYTE PTR fs:[si].BaseH,dh  
                add     si,SIZE Desc  
                loop    ILDT  
                ret  
InitLDT         ENDP  
;----------------------------------------------------------------------------  
RCodeSeg        ENDS  
                END     Start    

程序中部分片段的背景和实现方法在前面的实例中做过介绍,下面主要就如何实现任务内特权级变换做些说明:

(1)通过段间返回指令实现特权级变换

实例在两处使用段间返回指令实现任务内的特权级变换。一处是在 0 级的过渡代码段中用段间 RET 指令从特权级 0 变换到特权级 3的演示代码段。该处 RET 指令并不对应 CALL 指令。实例从实模式切换到保护模式后 CPL=0。为了演示如何通过调用门调用内层程序,要设法使 CPL>0。为此,实例先建立一个已发生的从外层到内层变换的环境,即按上图所示在当前堆栈(0 级堆栈)中放入外层堆栈的指

针和外层演示程序的入口指针,形成一个如下图所示的 0 级堆栈,无需传递参数。然后,执行段间返回指令 RET,从堆栈中弹出 3 级演示代码段的选择子,RPL=3,而当时 CPL=0,所以导致向外层变换特权级,从 0 级的过渡代码段变换到 3 级的演示代码段,同时切换到3 级堆栈。

另一处是从 1 级的显示子程序 EchoSub 返回到 3 级的演示程序段。该处的 RET 指令与演示程序中使用的通过调用门的段间调用指令 CALL 相对应,执行段间返回指令 RET 时的 1 级堆栈也如上图所示,其中的返回地址和外层栈指针由 CALL 指令压入。

(2)通过调用门实现特权级变换

实例在两处使用了段间调用指令,通过调用门实现特权级的变换。一处是 3 级演示代码通过调用门 ToEchoGate 调用 1 级的显示子程序。调用门 ToEchoGate 自身的 DPL=3,只有这样,3 级的演示代码才能够使用该调用门。由于调用门内的选择子 Echo_Sel3 所指示的显示子程序代码段描述符 DPL=1,而当时 CPL=3,所以引起从外层特权级向内层特权级的变换,使 CPL=1。同时形成如上图所示的
1级堆栈。虽然调用门内的选择子 Echo_Sel3 的 RPL=3,大于目标代码段的 DPL,但没有关系,因为在通过调用门转移时,门内指示目标代码段的选择子 RPL 总被作 0 对待。

另一处是 3 级演示代码还通过调用门 ToT32GateB 调用了 0 级的过渡代码。该处使用的调用门描述符 DPL 也等于 3。由于调用门内的选择子 T32Code_Sel 所指示的过渡代码段描述符的 DPL=0,而当时 CPL=3,所以引起从 3 特权级向 0 特权级的变换,使 CPL=0。同时形成如上图所示的 0 级堆栈。但该处的调用实际上是 “有去无回”的,调用的目的是转移到 0
级的过渡代码,准备返回实模式。由于从 3级的演示代码到 0 级的过渡代码要发生特权级变换,所以不能使用转移指令 JMP,必须使用调用指令 CALL。

(3)通过调用门实现无特权级变换
在临时代码段中,使用调用门 ToT32GateA 转移到过渡代码段。尽管调用门内的选择子 T32Code_Sel 所指示的过渡代码段描述符的

DPL=0,但当时 CPL=0,所以不发生特权级变换。正是这个原因,才可以使用段间转移指令 JMP。

(4)子程序EchoSub的实现

子程序 EchoSub 的功能是显示调用程序执行时的特权级。调用程序的执行特权级在代码段寄存器 CS 内选择子的 RPL 字段,在调用EchoSub 时,CS 寄存器的内容被压入堆栈。子程序从堆栈取得调用程序的代码段选择子,再从中分离出 RPL 就可得调用程序的执行特权级。

(5)装载任务状态段寄存器TR

在任务内发生特权级变换时堆栈也随着自动切换,外层堆栈指针保存在内层堆栈中,而内层堆栈指针存放在当前任务的 TSS 中。所以,在从外层向内层变换时,要访问 TSS(从内层向外层转移时不需要访问 TSS,而只需内层栈中保存的栈指针)。实例在进入保护模式下的临时代码段后,通过如下两条指令装载任务状态段寄存器 TR,使其指向已预置好的任务的 TSS:

mov  ax,DemoTSS_Sel

ltr    ax
LTR 指令是专门用于装载任务状态段寄存器 TR 的指令。该指令的操作数是对应 TSS 段描述符的选择子。LTR 指令从 GDT 中取出

相应的 TSS 段描述符,把 TSS 段描述符的基地址和界限等信息装入 TR 的高速缓冲寄存器中。 

我要说的:
如果从开始慢慢学到这里的话,看这个代码应该没什么大问题的,说一下调用栈里面的选择子显示CPL,TI值的代码

[cpp]
view plain
copy

EchoSub2:       mov     al,[ebp+8]               ;从堆栈中取调用程序的选择子  
                and     al,3                      ;调用程序的CPL在CS的RPL字段  
                add     al,'0'  
                mov     ah,4eh                    ;置显示属性(红底黄字)  
        sub     edi,10  
                stosw  
        add     edi,8  
        mov     al,[ebp+8]               ;从堆栈中取调用程序的选择子  
                and     al,1                     ;调用程序TI字段  
                add     al,'0'  
                mov     ah,4eh    
        stosw  
                pop     ebp  
                retf  

为什么是ebp+8?调用这段代码的是

[cpp]
view plain
copy

CALL32  ToEcho_Sel,0              ;显示当前特权级(变换到1级)  

该代码所在段是3级,转到1级代码段,发生特权级变换,会切换栈,将当前的段选择子(被扩展为32位)和偏移(32位)压入3级栈,进入到1级代码段,由外层栈切换到内层栈,然后进行参数复制,复制开始压入的段选择子和偏移,然后push ebp,1级栈里面存的就是这些了示意图如下:



目前还有一个问题未弄明白:

[cpp]
view plain
copy

TempCode        Desc    <0ffffh,TempCodeSeg,,ATCE,,>  ;注意它的存储段描述符  

我在测试的时候发现它的选择子的段界限不能是TempCodeLen-1(或TempCodeLen),前者直接让DOS崩溃了,TempCodeLen+4到是可以正常输出,但是就是没有办法正常返回,段界限为0ffffh就可以正常执行并返回,难道是存在访问越界,被处理器终止或者访问出错吗,这点现在我还没有很好的想明白。
运行结果:



下面是书上的代码(Linux平台)在特权级切换的同时输出字符(这里我做了一点小改动)



这里的value是特权级为3的选择子的输出,本来打算直接在ring3代码段中输出,后来发现DOS会崩溃,突然才发现数据段CPL=0,而ring3的CPL=3,不能访问数据段,所以就干脆放到了CPL=0的代码段(LABEL_SEG_CODE32)中输出了。

[cpp]
view plain
copy

%macro Descriptor 3  
  
    dw  %2 & 0FFFFh             ; 段界限 1             (2 字节)  
  
    dw  %1 & 0FFFFh             ; 段基址 1             (2 字节)  
  
    db  (%1 >> 16) & 0FFh         ; 段基址 2             (1 字节)  
  
    dw  ((%2 >> 8) & 0F00h) | (%3 & 0F0FFh)   ; 属性 1 + 段界限 2 + 属性 2       (2 字节)  
  
    db  (%1 >> 24) & 0FFh         ; 段基址 3             (1 字节)  
  
%endmacro ; 共 8 字节  
  
  
  
%macro Gate 4  
  
    dw  (%2 & 0FFFFh)               ; 偏移 1              (2 字节)  
  
    dw  %1                  ; 选择子               (2 字节)  
  
    dw  (%3 & 1Fh) | ((%4 << 8) & 0FF00h) ; 属性                    (2 字节)  
  
    dw  ((%2 >> 16) & 0FFFFh)         ; 偏移 2              (2 字节)  
  
%endmacro ; 共 8 字节  
  
  
  
DA_32       EQU 4000h   ; 32 位段  
  
DA_DPL3     EQU   60h   ; DPL = 3  
  
; 存储段描述符类型值说明  
  
;----------------------------------------------------------------------------  
  
DA_DR       EQU 90h ; 存在的只读数据段类型值  
  
DA_DRW      EQU 92h ; 存在的可读写数据段属性值  
  
DA_DRWA     EQU 93h ; 存在的已访问可读写数据段类型值  
  
DA_C        EQU 98h ; 存在的只执行代码段属性值  
  
  
  
;----------------------------------------------------------------------------  
  
; 系统段描述符类型值说明  
  
;----------------------------------------------------------------------------  
  
DA_LDT      EQU   82h   ; 局部描述符表段类型值  
  
DA_TaskGate EQU   85h   ; 任务门类型值  
  
DA_386TSS   EQU   89h   ; 可用 386 任务状态段类型值  
  
DA_386CGate EQU   8Ch   ; 386 调用门类型值  
  
; 选择子类型值说明  
  
; 其中:  
  
;       SA_  : Selector Attribute  
  
  
  
SA_RPL0     EQU 0   ; ┓  
  
SA_RPL1     EQU 1   ; ┣ RPL  
  
SA_RPL2     EQU 2   ; ┃  
  
SA_RPL3     EQU 3   ; ┛  
  
  
  
SA_TIG      EQU 0   ; ┓TI  
  
SA_TIL      EQU 4   ; ┛  
  
  
  
  
  
org 0100h  
  
    jmp LABEL_BEGIN  
  
  
  
[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_C+DA_32     ;非一致,32  
  
LABEL_DESC_CODE16:     Descriptor 0,            0ffffh, DA_C           ;非一致,16  
  
LABEL_DESC_CODE_DEST:  Descriptor 0,  SegCodeDestLen-1, DA_C+DA_32     ;非一致,32  
  
LABEL_DESC_CODE_RING3: Descriptor 0, SegCodeRing3Len-1, DA_C+DA_32+DA_DPL3  
  
LABEL_DESC_DATA:       Descriptor 0,         DataLen-1, DA_DRW             ;Data  
  
LABEL_DESC_STACK:      Descriptor 0,        TopOfStack, DA_DRWA+DA_32      ;Stack,32  
  
LABEL_DESC_STACK3:     Descriptor 0,       TopOfStack3, DA_DRWA+DA_32+DA_DPL3  
  
LABEL_DESC_LDT:        Descriptor 0,          LDTLen-1, DA_LDT         ;LDT  
  
LABEL_DESC_TSS:        Descriptor 0,          TSSLen-1, DA_386TSS      ;TSS  
  
LABEL_DESC_VIDEO:      Descriptor 0B8000h,      0ffffh, DA_DRW+DA_DPL3  
  
  
  
; 门                                            目标选择子,       偏移, DCount, 属性  
  
LABEL_CALL_GATE_TEST:   Gate          SelectorCodeDest,          0,      0, DA_386CGate + DA_DPL3  
  
; 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  
  
SelectorCodeDest    equ LABEL_DESC_CODE_DEST    - LABEL_GDT  
  
SelectorCodeRing3   equ LABEL_DESC_CODE_RING3   - LABEL_GDT + SA_RPL3  
  
SelectorData        equ LABEL_DESC_DATA     - LABEL_GDT  
  
SelectorStack       equ LABEL_DESC_STACK    - LABEL_GDT  
  
SelectorStack3      equ LABEL_DESC_STACK3   - LABEL_GDT + SA_RPL3  
  
SelectorLDT     equ LABEL_DESC_LDT      - LABEL_GDT  
  
SelectorTSS     equ LABEL_DESC_TSS      - LABEL_GDT  
  
SelectorVideo       equ LABEL_DESC_VIDEO    - LABEL_GDT  
  
  
  
SelectorCallGateTest    equ LABEL_CALL_GATE_TEST    - LABEL_GDT + SA_RPL3  
  
; END of [SECTION .gdt]  
  
  
  
[SECTION .data1]     ; 数据段  
  
ALIGN   32  
  
[BITS   32]  
  
LABEL_DATA:  
  
SPValueInRealMode   dw  0  
  
; 字符串  
  
PMMessage:      db  "In Protect Mode now. ^-^", 0   ; 进入保护模式后显示此字符串  
  
OffsetPMMessage     equ PMMessage - $$  
  
StrTest:        db  "value=", 0  
  
OffsetStrTest       equ StrTest - $$  
  
DataLen         equ $ - LABEL_DATA  
  
; END of [SECTION .data1]  
  
  
  
  
  
; 全局堆栈段  
  
[SECTION .gs]  
  
ALIGN   32  
  
[BITS   32]  
  
LABEL_STACK:  
  
    times 512 db 0  
  
TopOfStack  equ $ - LABEL_STACK - 1  
  
; END of [SECTION .gs]  
  
  
  
  
  
; 堆栈段ring3  
  
[SECTION .s3]  
  
ALIGN   32  
  
[BITS   32]  
  
LABEL_STACK3:  
  
    times 512 db 0  
  
TopOfStack3 equ $ - LABEL_STACK3 - 1  
  
; END of [SECTION .s3]  
  
  
  
  
  
; TSS ---------------------------------------------------------------------------------------------  
  
[SECTION .tss]  
  
ALIGN   32  
  
[BITS   32]  
  
LABEL_TSS:  
  
        DD  0           ; Back  
  
        DD  TopOfStack      ; 0 级堆栈  
  
        DD  SelectorStack       ;   
  
        DD  0           ; 1 级堆栈  
  
        DD  0           ;   
  
        DD  0           ; 2 级堆栈  
  
        DD  0           ;   
  
        DD  0           ; CR3  
  
        DD  0           ; EIP  
  
        DD  0           ; EFLAGS  
  
        DD  0           ; EAX  
  
        DD  0           ; ECX  
  
        DD  0           ; EDX  
  
        DD  0           ; EBX  
  
        DD  0           ; ESP  
  
        DD  0           ; EBP  
  
        DD  0           ; ESI  
  
        DD  0           ; EDI  
  
        DD  0           ; ES  
  
        DD  0           ; CS  
  
        DD  0           ; SS  
  
        DD  0           ; DS  
  
        DD  0           ; FS  
  
        DD  0           ; GS  
  
        DD  0           ; LDT  
  
        DW  0           ; 调试陷阱标志  
  
        DW  $ - LABEL_TSS + 2   ; I/O位图基址  
  
        DB  0ffh            ; I/O位图结束标志  
  
TSSLen      equ $ - LABEL_TSS  
  
; TSS ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  
  
  
  
  
  
[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 [SPValueInRealMode], 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, cs  
  
    shl eax, 4  
  
    add eax, LABEL_SEG_CODE_DEST  
  
    mov word [LABEL_DESC_CODE_DEST + 2], ax  
  
    shr eax, 16  
  
    mov byte [LABEL_DESC_CODE_DEST + 4], al  
  
    mov byte [LABEL_DESC_CODE_DEST + 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  
  
  
  
    ; 初始化堆栈段描述符(ring3)  
  
    xor eax, eax  
  
    mov ax, ds  
  
    shl eax, 4  
  
    add eax, LABEL_STACK3  
  
    mov word [LABEL_DESC_STACK3 + 2], ax  
  
    shr eax, 16  
  
    mov byte [LABEL_DESC_STACK3 + 4], al  
  
    mov byte [LABEL_DESC_STACK3 + 7], ah  
  
  
  
    ; 初始化 LDT 在 GDT 中的描述符  
  
    xor eax, eax  
  
    mov ax, ds  
  
    shl eax, 4  
  
    add eax, LABEL_LDT  
  
    mov word [LABEL_DESC_LDT + 2], ax  
  
    shr eax, 16  
  
    mov byte [LABEL_DESC_LDT + 4], al  
  
    mov byte [LABEL_DESC_LDT + 7], ah  
  
  
  
    ; 初始化 LDT 中的描述符  
  
    xor eax, eax  
  
    mov ax, ds  
  
    shl eax, 4  
  
    add eax, LABEL_CODE_A  
  
    mov word [LABEL_LDT_DESC_CODEA + 2], ax  
  
    shr eax, 16  
  
    mov byte [LABEL_LDT_DESC_CODEA + 4], al  
  
    mov byte [LABEL_LDT_DESC_CODEA + 7], ah  
  
  
  
    ; 初始化Ring3描述符  
  
    xor eax, eax  
  
    mov ax, ds  
  
    shl eax, 4  
  
    add eax, LABEL_CODE_RING3  
  
    mov word [LABEL_DESC_CODE_RING3 + 2], ax  
  
    shr eax, 16  
  
    mov byte [LABEL_DESC_CODE_RING3 + 4], al  
  
    mov byte [LABEL_DESC_CODE_RING3 + 7], ah  
  
  
  
    ; 初始化 TSS 描述符  
  
    xor eax, eax  
  
    mov ax, ds  
  
    shl eax, 4  
  
    add eax, LABEL_TSS  
  
    mov word [LABEL_DESC_TSS + 2], ax  
  
    shr eax, 16  
  
    mov byte [LABEL_DESC_TSS + 4], al  
  
    mov byte [LABEL_DESC_TSS + 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 基地址  
  
  
  
    ; 加载 GDTR  
  
    lgdt    [GdtPtr]  
  
  
  
    ; 关中断  
  
    cli  
  
  
  
    ; 打开地址线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, [SPValueInRealMode]  
  
  
  
    in  al, 92h     ; ┓  
  
    and al, 11111101b   ; ┣ 关闭 A20 地址线  
  
    out 92h, al     ; ┛  
  
  
  
    sti         ; 开中断  
  
  
  
    mov ax, 4c00h   ; ┓  
  
    int 21h     ; ┛回到 DOS  
  
; END of [SECTION .s16]  
  
  
  
  
  
[SECTION .s32]; 32 位代码段. 由实模式跳入.  
  
[BITS   32]  
  
  
  
LABEL_SEG_CODE32:  
  
    mov ax, SelectorData  
  
    mov ds, ax          ; 数据段选择子  
  
    mov ax, SelectorVideo  
  
    mov gs, ax          ; 视频段选择子  
  
  
  
    mov ax, SelectorStack  
  
    mov ss, ax          ; 堆栈段选择子  
  
  
  
    mov esp, TopOfStack  
  
  
  
  
  
    ; 下面显示一个字符串  
  
    mov ah, 0Ch         ; 0000: 黑底    1100: 红字  
  
    xor esi, esi  
  
    xor edi, edi  
  
    mov esi, OffsetPMMessage    ; 源数据偏移  
  
    mov edi, (80 * 10 + 0) * 2  ; 目的数据偏移。屏幕第 10 行, 第 0 列。  
  
    cld  
  
.1:  
  
    lodsb  
  
    test    al, al  
  
    jz  .2  
  
    mov [gs:edi], ax  
  
    add edi, 2  
  
    jmp .1  
  
.2: ; 显示完毕  
  
  
  
    call    DispReturn  
  
  
;显示LABEL_CODE_RING3的CPL  
        mov     ax,SelectorData  
    mov     ds,ax  
    mov     esi,OffsetStrTest  
  
    mov     ax,SelectorVideo  
    mov     es,ax  
    mov     ah,4eh                    ;置显示属性(红底黄字)  
EchoSub1:   
    lodsb  
        or      al,al  
        jz      EchoSub2  
        stosw  
        jmp     EchoSub1  
EchoSub2:  
    mov ax,SelectorCodeRing3               
        and     al,3                      ;调用程序的CPL在CS的RPL字段  
        add     al,'0'  
        mov     ah,4eh                    ;置显示属性(红底黄字)  
        mov [gs:edi], ax  
  
    ; Load TSS  
  
    mov ax, SelectorTSS  
  
    ltr ax  ; 在任务内发生特权级变换时要切换堆栈,而内层堆栈的指针存放在当前任务的TSS中,所以要设置任务状态段寄存器 TR。  
  
    push    SelectorStack3  
  
    push    TopOfStack3  
  
    push    SelectorCodeRing3  
  
    push    0  
  
    retf        ; Ring0 -> Ring3,历史性转移!将打印数字 '3'。  
  
  
  
; ------------------------------------------------------------------------  
  
DispReturn:  
  
    push    eax  
  
    push    ebx  
  
    mov eax, edi  
  
    mov bl, 160  
  
    div bl  
  
    and eax, 0FFh  
  
    inc eax  
  
    mov bl, 160  
  
    mul bl  
  
    mov edi, eax  
  
    pop ebx  
  
    pop eax  
  
  
  
    ret  
  
; DispReturn 结束---------------------------------------------------------  
  
  
  
SegCode32Len    equ $ - LABEL_SEG_CODE32  
  
; END of [SECTION .s32]  
  
  
  
  
  
[SECTION .sdest]; 调用门目标段  
  
[BITS   32]  
  
  
  
LABEL_SEG_CODE_DEST:  
  
    mov ax, SelectorVideo  
  
    mov gs, ax          ; 视频段选择子(目的)  
  
  
  
    mov edi, (80 * 12 + 0) * 2  ; 屏幕第 12 行, 第 0 列。  
  
    mov ah, 0Ch         ; 0000: 黑底    1100: 红字  
  
    mov al, 'C'  
  
    mov [gs:edi], ax  
  
    ; Load LDT  
  
    mov ax, SelectorLDT  
  
    lldt    ax  
  
    jmp SelectorLDTCodeA:0  ; 跳入局部任务,将打印字母 'L'。  
  
  
  
SegCodeDestLen  equ $ - LABEL_SEG_CODE_DEST  
  
; END of [SECTION .sdest]  
  
  
  
  
  
; 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]  
  
  
  
  
  
; LDT  
  
[SECTION .ldt]  
  
ALIGN   32  
  
LABEL_LDT:  
  
;                                         段基址       段界限     ,   属性  
  
LABEL_LDT_DESC_CODEA:   Descriptor         0,     CodeALen - 1,   DA_C + DA_32  ; Code, 32 位  
  
  
  
LDTLen      equ $ - LABEL_LDT  
  
  
  
; LDT 选择子  
  
SelectorLDTCodeA    equ LABEL_LDT_DESC_CODEA    - LABEL_LDT + SA_TIL  
  
; END of [SECTION .ldt]  
  
  
  
  
  
; CodeA (LDT, 32 位代码段)  
  
[SECTION .la]  
  
ALIGN   32  
  
[BITS   32]  
  
LABEL_CODE_A:  
  
    mov ax, SelectorVideo  
  
    mov gs, ax          ; 视频段选择子(目的)  
  
  
  
    mov edi, (80 * 13 + 0) * 2  ; 屏幕第 13 行, 第 0 列。  
  
    mov ah, 0Ch         ; 0000: 黑底    1100: 红字  
  
    mov al, 'L'  
  
    mov [gs:edi], ax  
  
  
  
    ; 准备经由16位代码段跳回实模式  
  
    jmp SelectorCode16:0  
  
CodeALen    equ $ - LABEL_CODE_A  
  
; END of [SECTION .la]  
  
  
  
  
  
; CodeRing3  
  
[SECTION .ring3]  
  
ALIGN   32  
  
[BITS   32]  
  
LABEL_CODE_RING3:  
  
    mov ax, SelectorVideo  
  
    mov gs, ax          ; 视频段选择子(目的)  
  
  
  
    mov edi, (80 * 14 + 0) * 2  ; 屏幕第 14 行, 第 0 列。  
  
    mov ah, 0Ch         ; 0000: 黑底    1100: 红字  
  
    mov al, '3'  
  
    mov [gs:edi], ax  
  
    call    SelectorCallGateTest:0  ; 测试调用门(有特权级变换),将打印字母 'C'。                   
  
SegCodeRing3Len equ $ - LABEL_CODE_RING3  
  
; END of [SECTION .ring3]  

在代码段LABEL_DESC_CODE32中有这么一段代码。

[cpp]
view plain
copy

push    SelectorStack3  
  
push    TopOfStack3  
  
push    SelectorCodeRing3  
  
push    0  
  
retf        ; Ring0 -> Ring3,历史性转移!将打印数字 '3'。  

后面三句语句都理解吧,就是把选择子,偏移压栈,利用retf指令返回,但是为什么要前两个语句了,这里需要回顾一下:
《Orange's
一个操作系统的实现》学习笔记--特权级代码段之间的转移(二)里面的内容,看下面图示:



有ring0到ring3转移过程中,会把调用者的ss,esp恢复,并且esp调整,废除开始前入栈的参数,但是我们这里没有从ring3进入ring0,返回从ring0直接进入ring3,所以这里我们需要自己手动的把目的栈的选择子和偏移压入栈,这样才能顺利执行,这里没有函数参数,所以返回后不用调整esp.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: