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

一、演示任务内特权级变换的实例 

下面给出一个演示任务内特权级变换的实例。该实例演示在任务内通过调用门从外层特权级变换到内层特权级;也演示通过段间返回指令从内层特权级变换到外层特权级;还演示通过调用门的无特权级变换的转移。实例使用了任务状态段 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。源程序清单如下: 


  1. ;windows  
  2. ;16位偏移的段间直接转移指令的宏定义(在16位代码段中使用)  
  3. ;----------------------------------------------------------------------------  
  4. JUMP16 MACRO Selector,Offsetv  
  5.     DB 0eah ;操作码  
  6.     DW Offsetv ;16位偏移量  
  7.     DW Selector ;段值或段选择子  
  8. ENDM  
  9. ;----------------------------------------------------------------------------  
  10. ;32位偏移的段间直接转移指令的宏定义(在32位代码段中使用)  
  11. ;----------------------------------------------------------------------------  
  12. COMMENT <JUMP32>  
  13. JUMP32 MACRO Selector,Offsetv  
  14.     DB 0eah ;操作码  
  15.     DD Offsetv  
  16.     DW Selector ;段值或段选择子  
  17. ENDM  
  18. <JUMP32>  
  19. ;-------------------------------------------------  
  20. JUMP32 MACRO Selector,Offsetv  
  21.     DB 0eah ;操作码  
  22.     DW Offsetv  
  23.     DW 0  
  24.     DW Selector ;段值或段选择子  
  25. ENDM  
  26. ;----------------------------------------------------------------------------  
  27. ;门描述符结构类型定义  
  28. ;----------------------------------------------------------------------------  
  29. Gate STRUC  
  30. OffsetL DW 0 ;32位偏移的低16位  
  31. Selector DW 0 ;选择子  
  32. DCount DB 0 ;双字计数  
  33. GType DB 0 ;类型  
  34. OffsetH DW 0 ;32位偏移的高16位  
  35. Gate ENDS  
  36. ;----------------------------------------------------------------------------  
  37.   
  38. ;16位偏移的段间调用指令的宏定义(在16位代码段中使用)  
  39. ;----------------------------------------------------------------------------  
  40. CALL16 MACRO Selector,Offsetv  
  41.     DB 9ah ;操作码  
  42.     DW Offsetv ;16位偏移量  
  43.     DW Selector ;段值或段选择子  
  44. ENDM  
  45. ;----------------------------------------------------------------------------  
  46. ;32位偏移的段间调用指令的宏定义(在32位代码段中使用)  
  47. ;----------------------------------------------------------------------------  
  48. COMMENT <CALL32>  
  49. CALL32 MACRO Selector,Offsetv  
  50.     DB 9ah ;操作码  
  51.     DD Offsetv  
  52.     DW Selector ;段值或段选择子  
  53. ENDM  
  54. <CALL32>  
  55. ;-------------------------------------------------  
  56. CALL32 MACRO Selector,Offsetv  
  57.     DB 9ah ;操作码  
  58.     DW Offsetv  
  59.     DW 0  
  60.     DW Selector ;段值或段选择子  
  61. ENDM  
  62. ;----------------------------------------------------------------------------  
  63. ;存储段描述符结构类型定义  
  64. ;----------------------------------------------------------------------------  
  65. Desc STRUC  
  66.     LimitL DW 0 ;段界限(BIT0-15)  
  67.     BaseL DW 0 ;段基地址(BIT0-15)  
  68.     BaseM DB 0 ;段基地址(BIT16-23)  
  69.     Attributes DB 0 ;段属性  
  70.     LimitH DB 0 ;段界限(BIT16-19)(含段属性的高4位)  
  71.     BaseH DB 0 ;段基地址(BIT24-31)  
  72. Desc ENDS  
  73. ;----------------------------------------------------------------------------  
  74.   
  75.   
  76. ;伪描述符结构类型定义(用于装入全局或中断描述符表寄存器)  
  77. ;----------------------------------------------------------------------------  
  78. PDesc STRUC  
  79.     Limit DW 0 ;16位界限  
  80.     Base DD 0 ;32位基地址  
  81. PDesc ENDS  
  82. ;----------------------------------------------------------------------------  
  83. ;存储段描述符类型值说明  
  84. ;----------------------------------------------------------------------------  
  85. D32 EQU 40h ;32位代码段标志  
  86. ATDR EQU 90h ;存在的只读数据段类型值  
  87. ATDW EQU 92h ;存在的可读写数据段属性值  
  88. ATDWA EQU 93h ;存在的已访问可读写数据段类型值  
  89. ATCE EQU 98h ;存在的只执行代码段属性值  
  90. ATCER EQU 9ah ;存在的可执行可读代码段属性值  
  91.   
  92. ;----------------------------------------------------------------------------  
  93. ;系统段描述符类型值说明  
  94. ;----------------------------------------------------------------------------  
  95. ATLDT EQU 82h ;局部描述符表段类型值  
  96.   
  97. ;----------------------------------------------------------------------------  
  98. ;DPL值说明  
  99. ;----------------------------------------------------------------------------  
  100. DPL0 EQU 00h ;DPL=0  
  101. DPL1 EQU 20h ;DPL=1  
  102. DPL2 EQU 40h ;DPL=2  
  103. DPL3 EQU 60h ;DPL=3  
  104. ;----------------------------------------------------------------------------  
  105. ;RPL值说明  
  106. ;----------------------------------------------------------------------------  
  107. RPL0 EQU 00h ;RPL=0  
  108. RPL1 EQU 01h ;RPL=1  
  109. RPL2 EQU 02h ;RPL=2  
  110. RPL3 EQU 03h ;RPL=3  
  111. ;----------------------------------------------------------------------------  
  112.   
  113. ;----------------------------------------------------------------------------  
  114. ;其它常量值说明  
  115. ;----------------------------------------------------------------------------  
  116.   
  117. TIL EQU 04h ;TI=1(局部描述符表标志)  
  118. AT386TSS EQU 89h ;可用386任务状态段类型值  
  119. AT386CGate EQU 8ch ;386调用门类型值  
  120. ;----------------------------------------------------------------------------  
  121.   
  122. .386p  
  123.   
  124. GDTSeg          SEGMENT PARA USE16                ;全局描述符表数据段(16位)  
  125. ;----------------------------------------------------------------------------  
  126.                 ;全局描述符表  
  127. GDT             LABEL   BYTE  
  128.                 ;空描述符  
  129. DUMMY           Desc    <>  
  130.                 ;规范段描述符  
  131. Normal          Desc    <0ffffh,,,ATDW,,>  
  132.                 ;视频缓冲区段描述符(DPL=3)  
  133. VideoBuf        Desc    <07fffh,8000h,0bh,ATDW+DPL3,,>  
  134. ;----------------------------------------------------------------------------  
  135. EFFGDT          LABEL   BYTE  
  136.                 ;任务状态段TSS描述符  
  137. DemoTSS         Desc    <DemoTSSLen-1,DemoTSSSeg,,AT386TSS,,>  
  138.                 ;局部描述符表段的描述符  
  139. DemoLDTD        Desc    <DemoLDTLen-1,DemoLDTSeg,,ATLDT,,>  
  140.                 ;临时代码段描述符  
  141. TempCode        Desc    <0ffffh,TempCodeSeg,,ATCE,,>  ;注意它的存储段描述符  
  142. ;----------------------------------------------------------------------------  
  143. GDTLen          =       $-GDT                     ;全局描述符表长度  
  144. GDNum           =       ($-EFFGDT)/(SIZE Desc)    ;需特殊处理的描述符数  
  145. ;----------------------------------------------------------------------------  
  146. Normal_Sel      =       Normal-GDT                ;规范段描述符选择子  
  147. Video_Sel       =       VideoBuf-GDT              ;视频缓冲区段描述符选择子  
  148. ;----------------------------------------------------------------------------  
  149. DemoTSS_Sel     =       DemoTSS-GDT               ;任务状态段描述符选择子  
  150. DemoLDT_Sel     =       DemoLDTD-GDT              ;局部描述符表段的选择子  
  151. TempCode_Sel    =       TempCode-GDT              ;临时代码段的选择子  
  152. ;----------------------------------------------------------------------------  
  153. GDTSeg          ENDS                              ;全局描述符表段定义结束  
  154. ;----------------------------------------------------------------------------  
  155. DemoLDTSeg      SEGMENT PARA USE16                ;局部描述符表数据段(16位)  
  156. ;----------------------------------------------------------------------------  
  157. DemoLDT         LABEL   BYTE                      ;局部描述符表  
  158.                 ;0级堆栈段描述符(32位段)  
  159. DemoStack0      Desc    <DemoStack0Len-1,DemoStack0Seg,,ATDW+DPL0,D32,>  
  160.                 ;1级堆栈段描述符(32位段)  
  161. DemoStack1      Desc    <DemoStack1Len-1,DemoStack1Seg,,ATDW+DPL1,D32,>  
  162.                 ;3级堆栈段描述符(16位段)  
  163. DemoStack3      Desc    <DemoStack3Len-1,DemoStack3Seg,,ATDW+DPL3,,>  
  164.                 ;代码段描述符(32位段,DPL=3)  
  165. DemoCode        Desc    <DemoCodeLEN-1,DemoCodeSeg,,ATCE+DPL3,D32,>  
  166.                 ;过渡代码段描述符(32位段)  
  167. T32Code         Desc    <T32CodeLen-1,T32CodeSeg,,ATCE,D32,>  
  168.                 ;显示子程序代码段描述符(32位段,DPL=1)  
  169. EchoSubR        Desc    <EchoSubRLen-1,EchoSubRSeg,,ATCER+DPL1,D32,>  
  170. ;----------------------------------------------------------------------------  
  171. DemoLDNum       =       ($-DemoLDT)/(SIZE Desc)  
  172. ;----------------------------------------------------------------------------  
  173.                 ;0级堆栈描述符选择子(RPL=0)  
  174. DemoStack0_Sel  =       DemoStack0-DemoLDT+TIL+RPL0  
  175.                 ;1级堆栈描述符选择子(RPL=1)  
  176. DemoStack1_Sel  =       DemoStack1-DemoLDT+TIL+RPL1  
  177.                 ;3级堆栈描述符选择子(RPL=3)  
  178. DemoStack3_Sel  =       DemoStack3-DemoLDT+TIL+RPL3  
  179.                 ;代码段描述符选择子(RPL=3)  
  180. DemoCode_Sel    =       DemoCode-DemoLDT+TIL+RPL3  
  181.                 ;过渡代码段描述符选择子  
  182. T32Code_Sel     =       T32Code-DemoLDT+TIL  
  183.                 ;显示子程序代码段描述符选择子(RPL=1)  
  184. Echo_Sel1       =       EchoSubR-DemoLDT+TIL+RPL1  
  185.                 ;显示子程序代码段描述符选择子(RPL=3)  
  186. Echo_Sel3       =       EchoSubR-DemoLDT+TIL+RPL3  
  187. ;----------------------------------------------------------------------------  
  188.                 ;指向过渡代码段内T32Begin点的调用门(DPL=0)  
  189. ToT32GateA      Gate    <T32Begin,T32Code_Sel,,AT386CGate,>  
  190.                 ;指向过渡代码段内T32End点的调用门(DPL=3)  
  191. ToT32GateB      Gate    <T32End,T32Code_Sel,,AT386CGate+DPL3,>  
  192.                 ;指向显示子程序代码段的调用门(DPL=3)  
  193. ToEchoGate      Gate    <EchoSUB,Echo_Sel3,,AT386CGate+DPL3,>  
  194. ;----------------------------------------------------------------------------  
  195. DemoLDTLen      =       $-DemoLDT  
  196. ;----------------------------------------------------------------------------  
  197.                 ;指向过渡代码段内T32Begin点的调用门的选择子  
  198. ToT32A_Sel      =       ToT32GateA-DemoLDT+TIL  
  199.                 ;指向过渡代码段内T32End点的调用门的选择子  
  200. ToT32B_Sel      =       ToT32GateB-DemoLDT+TIL  
  201.                 ;显示子程序调用门的选择子  
  202. ToEcho_Sel      =       ToEchoGate-DemoLDT+TIL  
  203. ;----------------------------------------------------------------------------  
  204. DemoLDTSeg      ENDS                              ;局部描述符表段定义结束  
  205. ;----------------------------------------------------------------------------  
  206. DemoTSSSeg      SEGMENT PARA USE16                ;任务状态段TSS  
  207. ;----------------------------------------------------------------------------  
  208.                 DD      0                         ;Back  
  209.                 DW      DemoStack0Len,0            ;0级堆栈指针  
  210.                 DW      DemoStack0_Sel,0            ;初始化  
  211.                 DW      DemoStack1Len,0             ;1级堆栈指针  
  212.                 DW      DemoStack1_Sel,0            ;初始化  
  213.                 DD      0                         ;2级堆栈指针  
  214.                 DD      0                         ;未初始化  
  215.                 DD      0                         ;CR3  
  216.                 DD      0                         ;EIP  
  217.                 DD      0                         ;EFLAGS  
  218.                 DD      0                         ;EAX  
  219.                 DD      0                         ;ECX  
  220.                 DD      0                         ;EDX  
  221.                 DD      0                         ;EBX  
  222.                 DD      0                         ;ESP  
  223.                 DD      0                         ;EBP  
  224.                 DD      0                         ;ESI  
  225.                 DD      0                         ;EDI  
  226.                 DW      ?,0                         ;ES  
  227.                 DW      ?,0                         ;CS  
  228.                 DW      ?,0                         ;SS  
  229.                 DW      ?,0                         ;DS  
  230.                 DW      ?,0                         ;FS  
  231.                 DW      ?,0                         ;GS  
  232.                 DW      DemoLDT_Sel,0               ;LDT  
  233.                 DW      0                         ;调试陷阱标志  
  234.                 DW      $+2                       ;指向I/O许可位图  
  235.                 DB      0ffh                    ;I/O许可位图结束标志  
  236. ;----------------------------------------------------------------------------  
  237. DemoTSSLen      =       $-DemoTSSSeg  
  238. ;----------------------------------------------------------------------------  
  239. DemoTSSSeg      ENDS                              ;任务状态段TSS结束  
  240. ;----------------------------------------------------------------------------  
  241. DemoStack0Seg   SEGMENT DWORD STACK USE32         ;0级堆栈段(32位段)  
  242. DemoStack0Len   =       512  
  243.                 DB      DemoStack0Len DUP(0)  
  244. DemoStack0Seg   ENDS                              ;0级堆栈段结束  
  245. ;----------------------------------------------------------------------------  
  246. DemoStack1Seg   SEGMENT DWORD STACK USE32         ;1级堆栈段(32位段)  
  247. DemoStack1Len   =       512  
  248.                 DB      DemoStack1Len DUP(0)  
  249. DemoStack1Seg   ENDS                              ;1级堆栈段结束  
  250. ;----------------------------------------------------------------------------  
  251. DemoStack3Seg   SEGMENT DWORD STACK USE16         ;3级堆栈段(16位段)  
  252. DemoStack3Len   =       512  
  253.                 DB      DemoStack3Len DUP(?)  
  254. DemoStack3Seg   ENDS                              ;3级堆栈段结束  
  255. ;----------------------------------------------------------------------------  
  256. EchoSubRSeg     SEGMENT PARA USE32                ;显示子程序代码段(32位,1级)  
  257.                 ASSUME  CS:EchoSubRSeg  
  258. ;----------------------------------------------------------------------------  
  259. Message         DB      'CPL=  TI=',0                  ;显示信息(该代码段可读)  
  260. ;----------------------------------------------------------------------------  
  261. EchoSub         PROC    FAR  
  262.                 cld  
  263.                 push    ebp  
  264.                 mov     ebp,esp  
  265.                 mov     ax,Echo_Sel1                ;该代码段是可读段  
  266.                 mov     ds,ax                     ;采用RPL=1的选择子  
  267.                 mov     ax,Video_Sel  
  268.                 mov     es,ax  
  269.                 mov     edi,320                   ;信息显示位置  
  270.                 mov     esi,OFFSET Message  
  271.                 mov     ah,4eh                    ;置显示属性(红底黄字)  
  272. EchoSub1:        lodsb  
  273.                 or      al,al  
  274.                 jz      EchoSub2  
  275.                 stosw  
  276.                 jmp     EchoSub1  
  277. EchoSub2:         mov     al,[ebp+8]               ;从堆栈中取调用程序的选择子  
  278.                 and     al,3                      ;调用程序的CPL在CS的RPL字段  
  279.                 add     al,'0'  
  280.                 mov     ah,4eh                    ;置显示属性(红底黄字)  
  281.            sub     edi,10  
  282.                 stosw  
  283.            add     edi,8  
  284.            mov     al,[ebp+8]               ;从堆栈中取调用程序的选择子  
  285.                 and     al,1                     ;调用程序TI字段  
  286.                 add     al,'0'  
  287.                 mov     ah,4eh    
  288.            stosw  
  289.                 pop     ebp  
  290.                 retf  
  291. EchoSub         ENDP  
  292. ;----------------------------------------------------------------------------  
  293. EchoSubRLen     =       $-EchoSubRSeg  
  294. ;----------------------------------------------------------------------------  
  295. EchoSubRSeg     ENDS                              ;显示子程序代码段结束  
  296. ;----------------------------------------------------------------------------  
  297. DemoCodeSeg     SEGMENT PARA USE32                ;32位代码段(3级)  
  298.                 ASSUME  CS:DemoCodeSeg  
  299. ;----------------------------------------------------------------------------  
  300. DemoBegin       PROC    FAR  
  301.                 CALL32  ToEcho_Sel,0              ;显示当前特权级(变换到1级)  
  302.                 CALL32  ToT32B_Sel,0              ;转到过渡代码段(变换到0级)  
  303. DemoBegin       ENDP  
  304. DemoCodeLen     =       $-DemoCodeSeg  
  305. ;----------------------------------------------------------------------------  
  306. DemoCodeSeg     ENDS                              ;32位代码段结束  
  307. ;----------------------------------------------------------------------------  
  308. T32CodeSeg      SEGMENT PARA USE32                ;32位过渡代码段(0级)  
  309.                 ASSUME  CS:T32CodeSeg  
  310. ;----------------------------------------------------------------------------  
  311. T32Begin        PROC    FAR  
  312.                 mov     ax,DemoStack0_Sel         ;建立0级堆栈  
  313.                 mov     ss,ax  
  314.                 mov     esp,DemoStack0Len  
  315.                 push    DWORD PTR DemoStack3_Sel  ;压入3级堆栈指针  
  316.                 push    DemoStack3Len  
  317.                 push    DWORD PTR DemoCode_SEL    ;压入入口点  
  318.                 push    OFFSET DemoBegin  
  319.                 retf                              ;利用RET实现转3级的演示代码  
  320. T32Begin        ENDP  
  321. ;----------------------------------------------------------------------------  
  322. T32End          PROC    FAR  
  323.                 JUMP32  TempCode_Sel,<OFFSET ToReal>  
  324. T32End          ENDP  
  325. T32CodeLen      =       $-T32CodeSeg  
  326. ;----------------------------------------------------------------------------  
  327. T32CodeSeg      ENDS  
  328. ;----------------------------------------------------------------------------  
  329. TempCodeSeg     SEGMENT PARA USE16                ;16位临时代码段(0级)  
  330.                 ASSUME  CS:TempCodeSeg  
  331. ;----------------------------------------------------------------------------  
  332. Virtual         PROC    FAR  
  333.                 mov     ax,DemoTSS_Sel            ;装载TR  
  334.                 ltr     ax  
  335.                 mov     ax,DemoLDT_Sel            ;装载LDTR  
  336.                 lldt    ax  
  337.                 JUMP16  ToT32A_Sel,0              ;通过调用门转过渡段  
  338. ToReal:          mov     ax,Normal_Sel             ;准备切换回实模式  
  339.                 mov     ds,ax  
  340.                 mov     es,ax  
  341.                 mov     fs,ax  
  342.                 mov     gs,ax  
  343.                 mov     ss,ax  
  344.                 mov     eax,cr0  
  345.                 and     al,11111110b  
  346.                 mov     cr0,eax  
  347.                 JUMP16  <SEG Real>,<OFFSET Real>  
  348. Virtual         ENDP  
  349. ;----------------------------------------------------------------------------  
  350. TempCodeLen     =       $-TempCodeSeg  
  351. TempCodeSeg     ENDS  
  352.   
  353. ;============================================================================  
  354. RDataSeg        SEGMENT PARA USE16                ;实方式数据段  
  355. VGDTR           PDesc   <GDTLen-1,>               ;GDT伪描述符  
  356. SPVar           DW      ?                         ;用于保存实方式下的SP  
  357. SSVar           DW      ?                         ;用于保存实方式下的SS  
  358. RDataSeg        ENDS  
  359. ;----------------------------------------------------------------------------  
  360. RCodeSeg        SEGMENT PARA USE16  
  361.                 ASSUME  CS:RCodeSeg,DS:RDataSeg  
  362. ;----------------------------------------------------------------------------  
  363. Start           PROC  
  364.                 mov     ax,RDataSeg  
  365.                 mov     ds,ax  
  366.                 cld  
  367.                 CALL    InitGDT                   ;初始化全局描述符表GDT  
  368.                 mov     ax,DemoLDTSeg  
  369.                 mov     fs,ax  
  370.                 mov     si,OFFSET DemoLDT  
  371.                 mov     cx,DemoLDNum  
  372.                 CALL    InitLDT                   ;初始化局部描述符表LDT  
  373.                 mov     SSVar,ss  
  374.                 mov     SPVar,sp  
  375.                 lgdt    FWORD PTR VGDTR           ;装载GDTR并切换到保护方式  
  376.                 cli  
  377.                 mov     eax,cr0  
  378.                 or      al,1  
  379.                 mov     cr0,eax  
  380.                 JUMP16  <TempCode_Sel>,<OFFSET Virtual>  
  381. Real:            mov     ax,RDataSeg  
  382.                 mov     ds,ax  
  383.                 lss     sp,DWORD PTR SPVar        ;又回到实方式  
  384.                 sti  
  385.                 mov     ax,4c00h  
  386.                 int     21h  
  387. Start           ENDP  
  388. ;----------------------------------------------------------------------------  
  389. ;初始化GDT表  
  390. InitGDT         PROC  
  391.                 push    ds  
  392.                 mov     ax,GDTSeg  
  393.                 mov     ds,ax  
  394.                 mov     cx,GDNum  
  395.                 mov     si,OFFSET EFFGDT  
  396. InitG:           mov     ax,[si].BaseL  
  397.                 movzx   eax,ax  
  398.                 shl     eax,4  
  399.                 shld    edx,eax,16  
  400.                 mov     WORD PTR [si].BaseL,ax  
  401.                 mov     BYTE PTR [si].BaseM,dl  
  402.                 mov     BYTE PTR [si].BaseH,dh  
  403.                 add     si,SIZE Desc  
  404.                 loop    InitG  
  405.                 pop     ds  
  406.                 mov     bx,16  
  407.                 mov     ax,GDTSeg  
  408.                 mul     bx  
  409.                 mov     WORD PTR VGDTR.Base,ax  
  410.                 mov     WORD PTR VGDTR.Base+2,dx  
  411.                 ret  
  412. InitGDT         ENDP  
  413. ;----------------------------------------------------------------------------  
  414. ;初始化LDT表  
  415. ;入口参数:FS:SI=第一个要初始化的描述符,CX=要初始化的描述符数  
  416. ;----------------------------------------------------------------------------  
  417. InitLDT         PROC  
  418. ILDT:            mov     ax,WORD PTR FS:[si].BaseL  
  419.                 movzx   eax,ax  
  420.                 shl     eax,4  
  421.                 shld    edx,eax,16  
  422.                 mov     WORD PTR fs:[si].BaseL,ax  
  423.                 mov     BYTE PTR fs:[si].BaseM,dl  
  424.                 mov     BYTE PTR fs:[si].BaseH,dh  
  425.                 add     si,SIZE Desc  
  426.                 loop    ILDT  
  427.                 ret  
  428. InitLDT         ENDP  
  429. ;----------------------------------------------------------------------------  
  430. RCodeSeg        ENDS  
  431.                 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值的代码

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

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

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

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




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

  1. 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)中输出了。

  1. %macro Descriptor 3  
  2.   
  3.     dw  %2 & 0FFFFh             ; 段界限 1             (2 字节)  
  4.   
  5.     dw  %1 & 0FFFFh             ; 段基址 1             (2 字节)  
  6.   
  7.     db  (%1 >> 16) & 0FFh         ; 段基址 2             (1 字节)  
  8.   
  9.     dw  ((%2 >> 8) & 0F00h) | (%3 & 0F0FFh)   ; 属性 1 + 段界限 2 + 属性 2       (2 字节)  
  10.   
  11.     db  (%1 >> 24) & 0FFh         ; 段基址 3             (1 字节)  
  12.   
  13. %endmacro ; 共 8 字节  
  14.   
  15.   
  16.   
  17. %macro Gate 4  
  18.   
  19.     dw  (%2 & 0FFFFh)               ; 偏移 1              (2 字节)  
  20.   
  21.     dw  %1                  ; 选择子               (2 字节)  
  22.   
  23.     dw  (%3 & 1Fh) | ((%4 << 8) & 0FF00h) ; 属性                    (2 字节)  
  24.   
  25.     dw  ((%2 >> 16) & 0FFFFh)         ; 偏移 2              (2 字节)  
  26.   
  27. %endmacro ; 共 8 字节  
  28.   
  29.   
  30.   
  31. DA_32       EQU 4000h   ; 32 位段  
  32.   
  33. DA_DPL3     EQU   60h   ; DPL = 3  
  34.   
  35. ; 存储段描述符类型值说明  
  36.   
  37. ;----------------------------------------------------------------------------  
  38.   
  39. DA_DR       EQU 90h ; 存在的只读数据段类型值  
  40.   
  41. DA_DRW      EQU 92h ; 存在的可读写数据段属性值  
  42.   
  43. DA_DRWA     EQU 93h ; 存在的已访问可读写数据段类型值  
  44.   
  45. DA_C        EQU 98h ; 存在的只执行代码段属性值  
  46.   
  47.   
  48.   
  49. ;----------------------------------------------------------------------------  
  50.   
  51. ; 系统段描述符类型值说明  
  52.   
  53. ;----------------------------------------------------------------------------  
  54.   
  55. DA_LDT      EQU   82h   ; 局部描述符表段类型值  
  56.   
  57. DA_TaskGate EQU   85h   ; 任务门类型值  
  58.   
  59. DA_386TSS   EQU   89h   ; 可用 386 任务状态段类型值  
  60.   
  61. DA_386CGate EQU   8Ch   ; 386 调用门类型值  
  62.   
  63. ; 选择子类型值说明  
  64.   
  65. ; 其中:  
  66.   
  67. ;       SA_  : Selector Attribute  
  68.   
  69.   
  70.   
  71. SA_RPL0     EQU 0   ; ┓  
  72.   
  73. SA_RPL1     EQU 1   ; ┣ RPL  
  74.   
  75. SA_RPL2     EQU 2   ; ┃  
  76.   
  77. SA_RPL3     EQU 3   ; ┛  
  78.   
  79.   
  80.   
  81. SA_TIG      EQU 0   ; ┓TI  
  82.   
  83. SA_TIL      EQU 4   ; ┛  
  84.   
  85.   
  86.   
  87.   
  88.   
  89. org 0100h  
  90.   
  91.     jmp LABEL_BEGIN  
  92.   
  93.   
  94.   
  95. [SECTION .gdt]  
  96.   
  97. ; GDT  
  98.   
  99. ;                            段基址,           段界限     , 属性  
  100.   
  101. LABEL_GDT:             Descriptor 0,                 0, 0          ;空描述符  
  102.   
  103. LABEL_DESC_NORMAL:     Descriptor 0,            0ffffh, DA_DRW         ;Normal描述符  
  104.   
  105. LABEL_DESC_CODE32:     Descriptor 0,    SegCode32Len-1, DA_C+DA_32     ;非一致,32  
  106.   
  107. LABEL_DESC_CODE16:     Descriptor 0,            0ffffh, DA_C           ;非一致,16  
  108.   
  109. LABEL_DESC_CODE_DEST:  Descriptor 0,  SegCodeDestLen-1, DA_C+DA_32     ;非一致,32  
  110.   
  111. LABEL_DESC_CODE_RING3: Descriptor 0, SegCodeRing3Len-1, DA_C+DA_32+DA_DPL3  
  112.   
  113. LABEL_DESC_DATA:       Descriptor 0,         DataLen-1, DA_DRW             ;Data  
  114.   
  115. LABEL_DESC_STACK:      Descriptor 0,        TopOfStack, DA_DRWA+DA_32      ;Stack,32  
  116.   
  117. LABEL_DESC_STACK3:     Descriptor 0,       TopOfStack3, DA_DRWA+DA_32+DA_DPL3  
  118.   
  119. LABEL_DESC_LDT:        Descriptor 0,          LDTLen-1, DA_LDT         ;LDT  
  120.   
  121. LABEL_DESC_TSS:        Descriptor 0,          TSSLen-1, DA_386TSS      ;TSS  
  122.   
  123. LABEL_DESC_VIDEO:      Descriptor 0B8000h,      0ffffh, DA_DRW+DA_DPL3  
  124.   
  125.   
  126.   
  127. ; 门                                            目标选择子,       偏移, DCount, 属性  
  128.   
  129. LABEL_CALL_GATE_TEST:   Gate          SelectorCodeDest,          0,      0, DA_386CGate + DA_DPL3  
  130.   
  131. ; GDT 结束  
  132.   
  133.   
  134.   
  135. GdtLen      equ $ - LABEL_GDT   ; GDT长度  
  136.   
  137. GdtPtr      dw  GdtLen - 1  ; GDT界限  
  138.   
  139.         dd  0       ; GDT基地址  
  140.   
  141.   
  142.   
  143. ; GDT 选择子  
  144.   
  145. SelectorNormal      equ LABEL_DESC_NORMAL   - LABEL_GDT  
  146.   
  147. SelectorCode32      equ LABEL_DESC_CODE32   - LABEL_GDT  
  148.   
  149. SelectorCode16      equ LABEL_DESC_CODE16   - LABEL_GDT  
  150.   
  151. SelectorCodeDest    equ LABEL_DESC_CODE_DEST    - LABEL_GDT  
  152.   
  153. SelectorCodeRing3   equ LABEL_DESC_CODE_RING3   - LABEL_GDT + SA_RPL3  
  154.   
  155. SelectorData        equ LABEL_DESC_DATA     - LABEL_GDT  
  156.   
  157. SelectorStack       equ LABEL_DESC_STACK    - LABEL_GDT  
  158.   
  159. SelectorStack3      equ LABEL_DESC_STACK3   - LABEL_GDT + SA_RPL3  
  160.   
  161. SelectorLDT     equ LABEL_DESC_LDT      - LABEL_GDT  
  162.   
  163. SelectorTSS     equ LABEL_DESC_TSS      - LABEL_GDT  
  164.   
  165. SelectorVideo       equ LABEL_DESC_VIDEO    - LABEL_GDT  
  166.   
  167.   
  168.   
  169. SelectorCallGateTest    equ LABEL_CALL_GATE_TEST    - LABEL_GDT + SA_RPL3  
  170.   
  171. ; END of [SECTION .gdt]  
  172.   
  173.   
  174.   
  175. [SECTION .data1]     ; 数据段  
  176.   
  177. ALIGN   32  
  178.   
  179. [BITS   32]  
  180.   
  181. LABEL_DATA:  
  182.   
  183. SPValueInRealMode   dw  0  
  184.   
  185. ; 字符串  
  186.   
  187. PMMessage:      db  "In Protect Mode now. ^-^", 0   ; 进入保护模式后显示此字符串  
  188.   
  189. OffsetPMMessage     equ PMMessage - $$  
  190.   
  191. StrTest:        db  "value=", 0  
  192.   
  193. OffsetStrTest       equ StrTest - $$  
  194.   
  195. DataLen         equ $ - LABEL_DATA  
  196.   
  197. ; END of [SECTION .data1]  
  198.   
  199.   
  200.   
  201.   
  202.   
  203. ; 全局堆栈段  
  204.   
  205. [SECTION .gs]  
  206.   
  207. ALIGN   32  
  208.   
  209. [BITS   32]  
  210.   
  211. LABEL_STACK:  
  212.   
  213.     times 512 db 0  
  214.   
  215. TopOfStack  equ $ - LABEL_STACK - 1  
  216.   
  217. ; END of [SECTION .gs]  
  218.   
  219.   
  220.   
  221.   
  222.   
  223. ; 堆栈段ring3  
  224.   
  225. [SECTION .s3]  
  226.   
  227. ALIGN   32  
  228.   
  229. [BITS   32]  
  230.   
  231. LABEL_STACK3:  
  232.   
  233.     times 512 db 0  
  234.   
  235. TopOfStack3 equ $ - LABEL_STACK3 - 1  
  236.   
  237. ; END of [SECTION .s3]  
  238.   
  239.   
  240.   
  241.   
  242.   
  243. ; TSS ---------------------------------------------------------------------------------------------  
  244.   
  245. [SECTION .tss]  
  246.   
  247. ALIGN   32  
  248.   
  249. [BITS   32]  
  250.   
  251. LABEL_TSS:  
  252.   
  253.         DD  0           ; Back  
  254.   
  255.         DD  TopOfStack      ; 0 级堆栈  
  256.   
  257.         DD  SelectorStack       ;   
  258.   
  259.         DD  0           ; 1 级堆栈  
  260.   
  261.         DD  0           ;   
  262.   
  263.         DD  0           ; 2 级堆栈  
  264.   
  265.         DD  0           ;   
  266.   
  267.         DD  0           ; CR3  
  268.   
  269.         DD  0           ; EIP  
  270.   
  271.         DD  0           ; EFLAGS  
  272.   
  273.         DD  0           ; EAX  
  274.   
  275.         DD  0           ; ECX  
  276.   
  277.         DD  0           ; EDX  
  278.   
  279.         DD  0           ; EBX  
  280.   
  281.         DD  0           ; ESP  
  282.   
  283.         DD  0           ; EBP  
  284.   
  285.         DD  0           ; ESI  
  286.   
  287.         DD  0           ; EDI  
  288.   
  289.         DD  0           ; ES  
  290.   
  291.         DD  0           ; CS  
  292.   
  293.         DD  0           ; SS  
  294.   
  295.         DD  0           ; DS  
  296.   
  297.         DD  0           ; FS  
  298.   
  299.         DD  0           ; GS  
  300.   
  301.         DD  0           ; LDT  
  302.   
  303.         DW  0           ; 调试陷阱标志  
  304.   
  305.         DW  $ - LABEL_TSS + 2   ; I/O位图基址  
  306.   
  307.         DB  0ffh            ; I/O位图结束标志  
  308.   
  309. TSSLen      equ $ - LABEL_TSS  
  310.   
  311. ; TSS ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  
  312.   
  313.   
  314.   
  315.   
  316.   
  317. [SECTION .s16]  
  318.   
  319. [BITS   16]  
  320.   
  321. LABEL_BEGIN:  
  322.   
  323.     mov ax, cs  
  324.   
  325.     mov ds, ax  
  326.   
  327.     mov es, ax  
  328.   
  329.     mov ss, ax  
  330.   
  331.     mov sp, 0100h  
  332.   
  333.   
  334.   
  335.     mov [LABEL_GO_BACK_TO_REAL+3], ax  
  336.   
  337.     mov [SPValueInRealMode], sp  
  338.   
  339.   
  340.   
  341.     ; 初始化 16 位代码段描述符  
  342.   
  343.     mov ax, cs  
  344.   
  345.     movzx   eax, ax  
  346.   
  347.     shl eax, 4  
  348.   
  349.     add eax, LABEL_SEG_CODE16  
  350.   
  351.     mov word [LABEL_DESC_CODE16 + 2], ax  
  352.   
  353.     shr eax, 16  
  354.   
  355.     mov byte [LABEL_DESC_CODE16 + 4], al  
  356.   
  357.     mov byte [LABEL_DESC_CODE16 + 7], ah  
  358.   
  359.   
  360.   
  361.     ; 初始化 32 位代码段描述符  
  362.   
  363.     xor eax, eax  
  364.   
  365.     mov ax, cs  
  366.   
  367.     shl eax, 4  
  368.   
  369.     add eax, LABEL_SEG_CODE32  
  370.   
  371.     mov word [LABEL_DESC_CODE32 + 2], ax  
  372.   
  373.     shr eax, 16  
  374.   
  375.     mov byte [LABEL_DESC_CODE32 + 4], al  
  376.   
  377.     mov byte [LABEL_DESC_CODE32 + 7], ah  
  378.   
  379.   
  380.   
  381.     ; 初始化测试调用门的代码段描述符  
  382.   
  383.     xor eax, eax  
  384.   
  385.     mov ax, cs  
  386.   
  387.     shl eax, 4  
  388.   
  389.     add eax, LABEL_SEG_CODE_DEST  
  390.   
  391.     mov word [LABEL_DESC_CODE_DEST + 2], ax  
  392.   
  393.     shr eax, 16  
  394.   
  395.     mov byte [LABEL_DESC_CODE_DEST + 4], al  
  396.   
  397.     mov byte [LABEL_DESC_CODE_DEST + 7], ah  
  398.   
  399.   
  400.   
  401.     ; 初始化数据段描述符  
  402.   
  403.     xor eax, eax  
  404.   
  405.     mov ax, ds  
  406.   
  407.     shl eax, 4  
  408.   
  409.     add eax, LABEL_DATA  
  410.   
  411.     mov word [LABEL_DESC_DATA + 2], ax  
  412.   
  413.     shr eax, 16  
  414.   
  415.     mov byte [LABEL_DESC_DATA + 4], al  
  416.   
  417.     mov byte [LABEL_DESC_DATA + 7], ah  
  418.   
  419.   
  420.   
  421.     ; 初始化堆栈段描述符  
  422.   
  423.     xor eax, eax  
  424.   
  425.     mov ax, ds  
  426.   
  427.     shl eax, 4  
  428.   
  429.     add eax, LABEL_STACK  
  430.   
  431.     mov word [LABEL_DESC_STACK + 2], ax  
  432.   
  433.     shr eax, 16  
  434.   
  435.     mov byte [LABEL_DESC_STACK + 4], al  
  436.   
  437.     mov byte [LABEL_DESC_STACK + 7], ah  
  438.   
  439.   
  440.   
  441.     ; 初始化堆栈段描述符(ring3)  
  442.   
  443.     xor eax, eax  
  444.   
  445.     mov ax, ds  
  446.   
  447.     shl eax, 4  
  448.   
  449.     add eax, LABEL_STACK3  
  450.   
  451.     mov word [LABEL_DESC_STACK3 + 2], ax  
  452.   
  453.     shr eax, 16  
  454.   
  455.     mov byte [LABEL_DESC_STACK3 + 4], al  
  456.   
  457.     mov byte [LABEL_DESC_STACK3 + 7], ah  
  458.   
  459.   
  460.   
  461.     ; 初始化 LDT 在 GDT 中的描述符  
  462.   
  463.     xor eax, eax  
  464.   
  465.     mov ax, ds  
  466.   
  467.     shl eax, 4  
  468.   
  469.     add eax, LABEL_LDT  
  470.   
  471.     mov word [LABEL_DESC_LDT + 2], ax  
  472.   
  473.     shr eax, 16  
  474.   
  475.     mov byte [LABEL_DESC_LDT + 4], al  
  476.   
  477.     mov byte [LABEL_DESC_LDT + 7], ah  
  478.   
  479.   
  480.   
  481.     ; 初始化 LDT 中的描述符  
  482.   
  483.     xor eax, eax  
  484.   
  485.     mov ax, ds  
  486.   
  487.     shl eax, 4  
  488.   
  489.     add eax, LABEL_CODE_A  
  490.   
  491.     mov word [LABEL_LDT_DESC_CODEA + 2], ax  
  492.   
  493.     shr eax, 16  
  494.   
  495.     mov byte [LABEL_LDT_DESC_CODEA + 4], al  
  496.   
  497.     mov byte [LABEL_LDT_DESC_CODEA + 7], ah  
  498.   
  499.   
  500.   
  501.     ; 初始化Ring3描述符  
  502.   
  503.     xor eax, eax  
  504.   
  505.     mov ax, ds  
  506.   
  507.     shl eax, 4  
  508.   
  509.     add eax, LABEL_CODE_RING3  
  510.   
  511.     mov word [LABEL_DESC_CODE_RING3 + 2], ax  
  512.   
  513.     shr eax, 16  
  514.   
  515.     mov byte [LABEL_DESC_CODE_RING3 + 4], al  
  516.   
  517.     mov byte [LABEL_DESC_CODE_RING3 + 7], ah  
  518.   
  519.   
  520.   
  521.     ; 初始化 TSS 描述符  
  522.   
  523.     xor eax, eax  
  524.   
  525.     mov ax, ds  
  526.   
  527.     shl eax, 4  
  528.   
  529.     add eax, LABEL_TSS  
  530.   
  531.     mov word [LABEL_DESC_TSS + 2], ax  
  532.   
  533.     shr eax, 16  
  534.   
  535.     mov byte [LABEL_DESC_TSS + 4], al  
  536.   
  537.     mov byte [LABEL_DESC_TSS + 7], ah  
  538.   
  539.   
  540.   
  541.     ; 为加载 GDTR 作准备  
  542.   
  543.     xor eax, eax  
  544.   
  545.     mov ax, ds  
  546.   
  547.     shl eax, 4  
  548.   
  549.     add eax, LABEL_GDT      ; eax <- gdt 基地址  
  550.   
  551.     mov dword [GdtPtr + 2], eax ; [GdtPtr + 2] <- gdt 基地址  
  552.   
  553.   
  554.   
  555.     ; 加载 GDTR  
  556.   
  557.     lgdt    [GdtPtr]  
  558.   
  559.   
  560.   
  561.     ; 关中断  
  562.   
  563.     cli  
  564.   
  565.   
  566.   
  567.     ; 打开地址线A20  
  568.   
  569.     in  al, 92h  
  570.   
  571.     or  al, 00000010b  
  572.   
  573.     out 92h, al  
  574.   
  575.   
  576.   
  577.     ; 准备切换到保护模式  
  578.   
  579.     mov eax, cr0  
  580.   
  581.     or  eax, 1  
  582.   
  583.     mov cr0, eax  
  584.   
  585.   
  586.   
  587.     ; 真正进入保护模式  
  588.   
  589.     jmp dword SelectorCode32:0  ; 执行这一句会把 SelectorCode32 装入 cs, 并跳转到 Code32Selector:0  处  
  590.   
  591.   
  592.   
  593. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;  
  594.   
  595.   
  596.   
  597. LABEL_REAL_ENTRY:       ; 从保护模式跳回到实模式就到了这里  
  598.   
  599.     mov ax, cs  
  600.   
  601.     mov ds, ax  
  602.   
  603.     mov es, ax  
  604.   
  605.     mov ss, ax  
  606.   
  607.   
  608.   
  609.     mov sp, [SPValueInRealMode]  
  610.   
  611.   
  612.   
  613.     in  al, 92h     ; ┓  
  614.   
  615.     and al, 11111101b   ; ┣ 关闭 A20 地址线  
  616.   
  617.     out 92h, al     ; ┛  
  618.   
  619.   
  620.   
  621.     sti         ; 开中断  
  622.   
  623.   
  624.   
  625.     mov ax, 4c00h   ; ┓  
  626.   
  627.     int 21h     ; ┛回到 DOS  
  628.   
  629. ; END of [SECTION .s16]  
  630.   
  631.   
  632.   
  633.   
  634.   
  635. [SECTION .s32]; 32 位代码段. 由实模式跳入.  
  636.   
  637. [BITS   32]  
  638.   
  639.   
  640.   
  641. LABEL_SEG_CODE32:  
  642.   
  643.     mov ax, SelectorData  
  644.   
  645.     mov ds, ax          ; 数据段选择子  
  646.   
  647.     mov ax, SelectorVideo  
  648.   
  649.     mov gs, ax          ; 视频段选择子  
  650.   
  651.   
  652.   
  653.     mov ax, SelectorStack  
  654.   
  655.     mov ss, ax          ; 堆栈段选择子  
  656.   
  657.   
  658.   
  659.     mov esp, TopOfStack  
  660.   
  661.   
  662.   
  663.   
  664.   
  665.     ; 下面显示一个字符串  
  666.   
  667.     mov ah, 0Ch         ; 0000: 黑底    1100: 红字  
  668.   
  669.     xor esi, esi  
  670.   
  671.     xor edi, edi  
  672.   
  673.     mov esi, OffsetPMMessage    ; 源数据偏移  
  674.   
  675.     mov edi, (80 * 10 + 0) * 2  ; 目的数据偏移。屏幕第 10 行, 第 0 列。  
  676.   
  677.     cld  
  678.   
  679. .1:  
  680.   
  681.     lodsb  
  682.   
  683.     test    al, al  
  684.   
  685.     jz  .2  
  686.   
  687.     mov [gs:edi], ax  
  688.   
  689.     add edi, 2  
  690.   
  691.     jmp .1  
  692.   
  693. .2: ; 显示完毕  
  694.   
  695.   
  696.   
  697.     call    DispReturn  
  698.   
  699.   
  700. ;显示LABEL_CODE_RING3的CPL  
  701.         mov     ax,SelectorData  
  702.     mov     ds,ax  
  703.     mov     esi,OffsetStrTest  
  704.   
  705.     mov     ax,SelectorVideo  
  706.     mov     es,ax  
  707.     mov     ah,4eh                    ;置显示属性(红底黄字)  
  708. EchoSub1:   
  709.     lodsb  
  710.         or      al,al  
  711.         jz      EchoSub2  
  712.         stosw  
  713.         jmp     EchoSub1  
  714. EchoSub2:  
  715.     mov ax,SelectorCodeRing3               
  716.         and     al,3                      ;调用程序的CPL在CS的RPL字段  
  717.         add     al,'0'  
  718.         mov     ah,4eh                    ;置显示属性(红底黄字)  
  719.         mov [gs:edi], ax  
  720.   
  721.     ; Load TSS  
  722.   
  723.     mov ax, SelectorTSS  
  724.   
  725.     ltr ax  ; 在任务内发生特权级变换时要切换堆栈,而内层堆栈的指针存放在当前任务的TSS中,所以要设置任务状态段寄存器 TR。  
  726.   
  727.     push    SelectorStack3  
  728.   
  729.     push    TopOfStack3  
  730.   
  731.     push    SelectorCodeRing3  
  732.   
  733.     push    0  
  734.   
  735.     retf        ; Ring0 -> Ring3,历史性转移!将打印数字 '3'。  
  736.   
  737.   
  738.   
  739. ; ------------------------------------------------------------------------  
  740.   
  741. DispReturn:  
  742.   
  743.     push    eax  
  744.   
  745.     push    ebx  
  746.   
  747.     mov eax, edi  
  748.   
  749.     mov bl, 160  
  750.   
  751.     div bl  
  752.   
  753.     and eax, 0FFh  
  754.   
  755.     inc eax  
  756.   
  757.     mov bl, 160  
  758.   
  759.     mul bl  
  760.   
  761.     mov edi, eax  
  762.   
  763.     pop ebx  
  764.   
  765.     pop eax  
  766.   
  767.   
  768.   
  769.     ret  
  770.   
  771. ; DispReturn 结束---------------------------------------------------------  
  772.   
  773.   
  774.   
  775. SegCode32Len    equ $ - LABEL_SEG_CODE32  
  776.   
  777. ; END of [SECTION .s32]  
  778.   
  779.   
  780.   
  781.   
  782.   
  783. [SECTION .sdest]; 调用门目标段  
  784.   
  785. [BITS   32]  
  786.   
  787.   
  788.   
  789. LABEL_SEG_CODE_DEST:  
  790.   
  791.     mov ax, SelectorVideo  
  792.   
  793.     mov gs, ax          ; 视频段选择子(目的)  
  794.   
  795.   
  796.   
  797.     mov edi, (80 * 12 + 0) * 2  ; 屏幕第 12 行, 第 0 列。  
  798.   
  799.     mov ah, 0Ch         ; 0000: 黑底    1100: 红字  
  800.   
  801.     mov al, 'C'  
  802.   
  803.     mov [gs:edi], ax  
  804.   
  805.     ; Load LDT  
  806.   
  807.     mov ax, SelectorLDT  
  808.   
  809.     lldt    ax  
  810.   
  811.     jmp SelectorLDTCodeA:0  ; 跳入局部任务,将打印字母 'L'。  
  812.   
  813.   
  814.   
  815. SegCodeDestLen  equ $ - LABEL_SEG_CODE_DEST  
  816.   
  817. ; END of [SECTION .sdest]  
  818.   
  819.   
  820.   
  821.   
  822.   
  823. ; 16 位代码段. 由 32 位代码段跳入, 跳出后到实模式  
  824.   
  825. [SECTION .s16code]  
  826.   
  827. ALIGN   32  
  828.   
  829. [BITS   16]  
  830.   
  831. LABEL_SEG_CODE16:  
  832.   
  833.     ; 跳回实模式:  
  834.   
  835.     mov ax, SelectorNormal  
  836.   
  837.     mov ds, ax  
  838.   
  839.     mov es, ax  
  840.   
  841.     mov fs, ax  
  842.   
  843.     mov gs, ax  
  844.   
  845.     mov ss, ax  
  846.   
  847.   
  848.   
  849.     mov eax, cr0  
  850.   
  851.     and al, 11111110b  
  852.   
  853.     mov cr0, eax  
  854.   
  855.   
  856.   
  857. LABEL_GO_BACK_TO_REAL:  
  858.   
  859.     jmp 0:LABEL_REAL_ENTRY  ; 段地址会在程序开始处被设置成正确的值  
  860.   
  861.   
  862.   
  863. Code16Len   equ $ - LABEL_SEG_CODE16  
  864.   
  865.   
  866.   
  867. ; END of [SECTION .s16code]  
  868.   
  869.   
  870.   
  871.   
  872.   
  873. ; LDT  
  874.   
  875. [SECTION .ldt]  
  876.   
  877. ALIGN   32  
  878.   
  879. LABEL_LDT:  
  880.   
  881. ;                                         段基址       段界限     ,   属性  
  882.   
  883. LABEL_LDT_DESC_CODEA:   Descriptor         0,     CodeALen - 1,   DA_C + DA_32  ; Code, 32 位  
  884.   
  885.   
  886.   
  887. LDTLen      equ $ - LABEL_LDT  
  888.   
  889.   
  890.   
  891. ; LDT 选择子  
  892.   
  893. SelectorLDTCodeA    equ LABEL_LDT_DESC_CODEA    - LABEL_LDT + SA_TIL  
  894.   
  895. ; END of [SECTION .ldt]  
  896.   
  897.   
  898.   
  899.   
  900.   
  901. ; CodeA (LDT, 32 位代码段)  
  902.   
  903. [SECTION .la]  
  904.   
  905. ALIGN   32  
  906.   
  907. [BITS   32]  
  908.   
  909. LABEL_CODE_A:  
  910.   
  911.     mov ax, SelectorVideo  
  912.   
  913.     mov gs, ax          ; 视频段选择子(目的)  
  914.   
  915.   
  916.   
  917.     mov edi, (80 * 13 + 0) * 2  ; 屏幕第 13 行, 第 0 列。  
  918.   
  919.     mov ah, 0Ch         ; 0000: 黑底    1100: 红字  
  920.   
  921.     mov al, 'L'  
  922.   
  923.     mov [gs:edi], ax  
  924.   
  925.   
  926.   
  927.     ; 准备经由16位代码段跳回实模式  
  928.   
  929.     jmp SelectorCode16:0  
  930.   
  931. CodeALen    equ $ - LABEL_CODE_A  
  932.   
  933. ; END of [SECTION .la]  
  934.   
  935.   
  936.   
  937.   
  938.   
  939. ; CodeRing3  
  940.   
  941. [SECTION .ring3]  
  942.   
  943. ALIGN   32  
  944.   
  945. [BITS   32]  
  946.   
  947. LABEL_CODE_RING3:  
  948.   
  949.     mov ax, SelectorVideo  
  950.   
  951.     mov gs, ax          ; 视频段选择子(目的)  
  952.   
  953.   
  954.   
  955.     mov edi, (80 * 14 + 0) * 2  ; 屏幕第 14 行, 第 0 列。  
  956.   
  957.     mov ah, 0Ch         ; 0000: 黑底    1100: 红字  
  958.   
  959.     mov al, '3'  
  960.   
  961.     mov [gs:edi], ax  
  962.   
  963.     call    SelectorCallGateTest:0  ; 测试调用门(有特权级变换),将打印字母 'C'。                   
  964.   
  965. SegCodeRing3Len equ $ - LABEL_CODE_RING3  
  966.   
  967. ; END of [SECTION .ring3]  

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

  1. push    SelectorStack3  
  2.   
  3. push    TopOfStack3  
  4.   
  5. push    SelectorCodeRing3  
  6.   
  7. push    0  
  8.   
  9. retf        ; Ring0 -> Ring3,历史性转移!将打印数字 '3'。  

后面三句语句都理解吧,就是把选择子,偏移压栈,利用retf指令返回,但是为什么要前两个语句了,这里需要回顾一下:

《Orange's 一个操作系统的实现》学习笔记--特权级代码段之间的转移(二)里面的内容,看下面图示:


有ring0到ring3转移过程中,会把调用者的ss,esp恢复,并且esp调整,废除开始前入栈的参数,但是我们这里没有从ring3进入ring0,返回从ring0直接进入ring3,所以这里我们需要自己手动的把目的栈的选择子和偏移压入栈,这样才能顺利执行,这里没有函数参数,所以返回后不用调整esp.

对x86架构的处理器,业界一向是褒贬不一。但是毫无疑问的是,x86架构的处理器是迄今为止在市场上最成功的处理器。它既催生了Intel、微软这样的业界巨头,也改变了普通人们的生活。到今天,虽然有arm的异军突起,但是大部分程序员所编写的程序依然在运行在x86架构上。 虽然很多上层的程序员绕过了对CPU架构本身的理解,而直接使用高语言进行编程,但是对CPU本身的熟悉,其实依然是所有想被称为优秀的程序员所难以绕过的一道坎。对CPU的不熟悉,实际上限制了程序员的思维方式、对程序的理解和实际解决问题的能力。 对于普通的芯片,阅读几页的说明书就可以大致理解如何让它工作。CPU是比较复杂的一种,对于比较简单的CPU架构,阅读几十页的文档也能大致熟悉。然而 x86架构的CPU的说明可不是这么简单,其手册估计有一共有四、五千页之巨。不要说理解透彻,就是从头到尾翻一遍也不是一件简单的事情。并非Intel 有意将它做得复杂,这里有历史的原因。因为这个架构的应用实在太广了,全世界有无数的软件都在它的基础之上工作。为此它自身的升也就变得举步维艰。每次升都不得不要兼容之前的特性。这也就导致了新旧指令层层堆积,种种特性互相兼顾,最终变成如今的一团乱麻了。 对于入门的选手,读完那些手册可不是一件容易的事情。但是于渊的这本《orange's:一个操作系统的实现》却是一条难得的终南捷径。因为要理解如何让一个芯片正常工作,最简单的办法就是从头开始去写程序让它运行起来,然后操作它做自己想做的事情。如果是平时的编程,这些下层的工作都已经有操作系统帮你做了,对理解x86架构的帮助就大为有限。如果去读那几千页的文档,不但读起来很痛苦,中间又没有多少可以实际操作的工作来帮助你温故而知新,这其中的枯燥乏味,绝对不是一般人可以忍受的了。而且更重要的手册中虽然包含了x86所有的特性,然而其中有些特性是现代操作系统根本就没有用到的。努力的去理解的话,又是吃力不讨好了。如果每个读者都可以随着这本书的介绍,去逐步的实现一个操作系统,不但这中间其乐无穷,而且实现到最后,对x86架构的理解也就不在话下。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值