zoukankan      html  css  js  c++  java
  • 《一个操作系统的实现》读书笔记--第三章---不同特权级代码段之间的跳转

    http://blog.csdn.net/begginghard/article/details/7262901

    1、特权级 2、一致代码段和非一致代码段 3、DPL、RPL、CPL分别代表的含义,存储在什么位置,以及它们之间的关系 4、不同特权级数据段之间的访问规则 5、不同特权级代码段之间的转移 6、代码段之间的转移对堆栈的影响 7、结合pmtest5.asm来见证不同特权级代码段之间的跳转

    一、特权级
    在IA32的分段机制下,特权级总共有4个特权级别,从高到低分别是0、1、2、3。数字越小表示的特权级越大。特权级如下图所示:

    较为核心的代码和数据,将被存放在特权级较高的层级中。处理器将用这样的机制来避免低特权级的任务在不被允许的情况下访问位于高特权级的段。

    二、一致代码段 和 非一致代码段 系统要安全,必须保证内核与用户程序分离开,内核要安全,必须不能被用户来打扰。但是有的时候,用户程序也是需要访问内核中的部分数据,那怎么办?

    于是操作系统就将内核中的段分为共享的代码段和非共享的代码段两部分。 其中一致代码段就是操作系统拿出来被共享的代码段,可以被低特权级的用户直接访问的代码。 一致代码段的限制作用: (1)特权级高的代码段不允许访问特权级低的代码段:即内核态不允许调用用户态下的代码。 (2)特权级低的代码段可以访问特权级高的代码段,但是当前的特权级不发生变化。即:用户态可以访问内核态的代码,但是用户态仍然是用户态。

    非一致代码段:为了避免低特权级的访问而被操作系统保护起来的系统代码,也就是非共享代码。 非一致代码段的限制作用: (1)只允许同特权级间访问 (2)绝对禁止不同级间访问,即:用户态不能访问内核态,内核态也不访问用户态。

    下图为一致码段与非一致码段的访问规则:

     

    三、CPL、DPL、RPL分别代表的含义,存储在什么位置,以及它们之间的关系 1、CPL(Current Privilege Level)是当前执行的程序或任务的特权级。它被存储在CS和SS的第0位和第1位上。通常情况下,CPL等于代码的段的特权级。在遇到一致代码段时,一致代码段可以被相同或者更低特权级的代码访问。当处理器访问一个与CPL特权级不同的一致代码段时,CPL不会被改变。

    2、DPL(Descriptor Privilege Level):DPL表示段或者门的特权级,它被存储在段描述符或者门描述符的DPL字段中。当当前代码段试图访问一个段或者门时,DPL将会和CPL以及段或门选择子的RPL相比较,根据段或者门类型的不同,DPL将会被区别对待,下面介绍一下各种类型的段或者门的情况。 (1)数据段:DPL规定了可以访问此段的最低特权级。比如,一个数据段的DPL是1,那么只有运行在CPL为0或者1的程序才有权访问它。 (2)非一致代码段(不使用调用门的情况下):DPL规定访问此段的特权级。比如一个非一致代码段的特权级为0,那么只有CPL为0的程序才可以访问它。 (3)调用门:DPL规定了当前执行的程序或任务可以访问此调用门的最低特权级(这与数据段的规则是一致的)。 (4)一致代码段和通过调用门访问的非一致代码段:DPL规定了访问此段的最高特权级。比如,一个一致代码段的DPL是2,那么CPL为0和1的程序将无法访问此段。

    3、RPL(Requested Privilege Level):RPL是通过选择子的第0位和第1位表现出来的。处理器通过检查RPL和CPL来确认一个访问请求是否合法。

    四、不同特权级数据段之间的访问规则
    数据段中DPL规定了可以访问此段的最低特权级,因此,对数据的访问,只要CPL和RPL都小于被访问的数据段的DPL就可以了,即CPL<=DPL和RPL<=DPL。

     

    五、不同特权级代码段之间的转移 使用jmp或call指令可以实现下列4种转移 (1)目标操作数包含目标代码段的段选择子。 (2)目标操作数指向一个包含目标代码段选择子的调用门描述符。 (3)目标操作数指向一个包含目标代码段选择子的TSS。 (4)目标操作数指向一个任务门,这个任务门指向一个包含目标代码段选择子的TSS。 这4种方式可以看做是两大类,一类是通过jmp和call的直接转移(上述第一种),另一类是通过某个描述  符的间接转移(上述第2,3,4种)。

    1、通过jmp或call进行直接转移

     

    2、通过调用门进行转移 (1)门描述符的结构

    调用门描述符里面保存着目标代码段的段选择子,偏移量,以及属性。

    (2)调用门的使用方式

    假设我们想由代码A转移到代码B,运用一个调用门G,即调用门G中的目标选择子指向代码B的段。实际上,这个问题主要涉及这几个元素:CPL、RPL、代码B的DPL(记做DPL_B),调用门G的DPL(记做DPL_G)。
    调用门使用时特权级检验的规则如下:

    也就是说,通过调用门和call指令,可以实现从低特权级到高特权级的转移,无论目标代码段时一致的还是非一致的。
    通过调用门和jmp指令,如果目标代码段是一致的,则可以实现从低特权级到高特权级的转移。如果目标代码段是非一致的,则只能实现相同特权级的转移。

     

    六、代码段之间的转移对堆栈的影响

    1、“长”跳转/调用 和 “短”跳转/调用 如果一个调用或跳转指令时段间而不是段内进行的,那么我们称之为“长”的(Far jmp/call),反之,如果在段内则是“短”的(Near jmp/call)。

    那么长的和短的jmp或call有什么分别呢? 对于jmp而言,仅仅是结果不同罢了,短跳转对应段内,长跳转对应段间。 对于call来说,就比较复杂一些,因为call指令是会影响堆栈的,长调用和短调用对堆栈的影响是不同的。

    下面我们讨论短调用对堆栈的影响,call指令执行时下一条指令的eip压栈,到ret指令执行时,这个eip会被从堆栈中弹出, 如下图所示:

     

    这是短调用的情况。

    下面我们讨论长调用对堆栈的影响,call指令执行时会将调用者的cs和eip压栈,到ret指令执行时,这个eip和cs会被从堆栈中弹出,如下图所示:

    2、有特权级变换的转移对堆栈的影响
    在不同特权级下的堆栈段不同,所以每一个任务最多可能在4个特权级间转移,所以,每个任务实际上需要4个堆栈。可是我们只有一个ss和一个esp,那么当发生堆栈切换,我们该从哪里获得其余堆栈的ss和esp呢?
    解决这个问题,需要一个数据结构TSS(Task-State Stack),如图:

    当堆栈发生切换时,内层的ss和esp就是从这里取得的,比如,我们当前所在的是ring3,当转移至ring1时,堆栈将被自动切换到由ss1和esp1指定的位置。由于只是在由外层转移到内层(低特权级到高特权级)切换时新堆栈才会从TSS中取得,所以TSS中没有位于最外层的ring3的堆栈信息。
    下面让我们来看看整个的转移过程是怎么样的?

    执行call前后堆栈段的变化:

     

    (1)根据目标代码段的DPL(新的CPL)从TSS中选择应该切换至哪个ss和esp (2)从TSS中读取新的ss和esp。在这过程中如果发现ss、esp或者TSS界限错误都会导致无效TSS异常 (3)对ss描述符进行检验,如果发生错误,同样产生#TS异常 (4)暂时性地保存当前ss和esp的值 (5)加载新的ss和esp (6)将刚刚保存起来的ss和esp的值压入新栈 (7)从调用者堆栈中将参数复制到被调用者堆栈(新堆栈)中,复制参数的数目由调用门中Param Count一项来决定。 (8)如果Param Count是零的话,将不会复制参数。 (9)将当前的cs和eip压栈 (10)加载调用门中指定的新的cs和eip,开始执行被调用者过程。

    执行ret前后堆栈段的变化:

    (1)检查保存的cs中的RPL以判断返回时是否要变换特权级
    (2)加载被调用者堆栈上的cs和eip(此时会进行代码段描述符和选择子类型和特权级检验)
    (3)如果ret指令含有参数,则增加esp的值以跳过参数,然后esp将指向被保存过的调用者ss和esp。注意,ret的参数必须对应调用门中的Param Count的值
    (4)加载ss和esp,切换到调用者堆栈,被调用者的ss和esp被丢弃。在这里将会进行ss描述符、esp、以及ss段描述符的检验
    (5)如果ret指令含有参数,增加esp的值以跳过参数(此时已经在调用者堆栈中)
    (6)检查ds、es、fs、gs的值,如果其中哪一个寄存器指向的段的DPL小于CPL(此规则不适合于一致代码段),那么一个空描述符会被加载到该寄存器中。
    综上所述,使用调用门的过程实际上分为两部分,一部分是从低特权级到高特权级,通过调用门和call指令来实现;另一部分则是从高特权级到低特权级,通过ret指令来实现。

    七、结合pmtest5.asm来见证不同特权级代码段之间的跳转

    1. ; ==========================================  
    2. ; pmtest5.asm  
    3. ; 编译方法:nasm pmtest5.asm -o pmtest5.com  
    4. ; ==========================================  
    5.   
    6. %include    "pm.inc"    ; 常量, 宏, 以及一些说明  
    7.   
    8. org 0100h  
    9.     jmp LABEL_BEGIN  
    10.   
    11. [SECTION .gdt]  
    12. ; GDT  
    13. ;                                         段基址,         段界限     , 属性  
    14. LABEL_GDT:      Descriptor         0,                   0, 0            ; 空描述符  
    15. LABEL_DESC_NORMAL:  Descriptor         0,              0ffffh, DA_DRW           ; Normal 描述符  
    16. LABEL_DESC_CODE32:  Descriptor         0,    SegCode32Len - 1, DA_C + DA_32     ; 非一致代码段, 32  
    17. LABEL_DESC_CODE16:  Descriptor         0,              0ffffh, DA_C         ; 非一致代码段, 16  
    18. LABEL_DESC_CODE_DEST:   Descriptor         0,  SegCodeDestLen - 1, DA_C + DA_32     ; 非一致代码段, 32  
    19. LABEL_DESC_CODE_RING3:  Descriptor         0, SegCodeRing3Len - 1, DA_C + DA_32 + DA_DPL3   ; 非一致代码段, 32  
    20. LABEL_DESC_DATA:    Descriptor         0,     DataLen - 1, DA_DRW           ; Data  
    21. LABEL_DESC_STACK:   Descriptor         0,          TopOfStack, DA_DRWA + DA_32      ; Stack, 32 位  
    22. LABEL_DESC_STACK3:  Descriptor         0,         TopOfStack3, DA_DRWA + DA_32 + DA_DPL3; Stack, 32 位  
    23. LABEL_DESC_TSS:     Descriptor         0,          TSSLen - 1, DA_386TSS        ; TSS  
    24. LABEL_DESC_VIDEO:   Descriptor   0B8000h,              0ffffh, DA_DRW + DA_DPL3     ; 显存首地址  
    25.   
    26. ; 门                                            目标选择子,       偏移, DCount, 属性  
    27. LABEL_CALL_GATE_TEST:   Gate          SelectorCodeDest,          0,      0, DA_386CGate + DA_DPL3  
    28. ; GDT 结束  
    29.   
    30. GdtLen      equ $ - LABEL_GDT   ; GDT长度  
    31. GdtPtr      dw  GdtLen - 1  ; GDT界限  
    32.         dd  0       ; GDT基地址  
    33.   
    34. ; GDT 选择子  
    35. SelectorNormal      equ LABEL_DESC_NORMAL   - LABEL_GDT  
    36. SelectorCode32      equ LABEL_DESC_CODE32   - LABEL_GDT  
    37. SelectorCode16      equ LABEL_DESC_CODE16   - LABEL_GDT  
    38. SelectorCodeDest    equ LABEL_DESC_CODE_DEST    - LABEL_GDT  
    39. SelectorCodeRing3   equ LABEL_DESC_CODE_RING3   - LABEL_GDT + SA_RPL3  
    40. SelectorData        equ LABEL_DESC_DATA     - LABEL_GDT  
    41. SelectorStack       equ LABEL_DESC_STACK    - LABEL_GDT  
    42. SelectorStack3      equ LABEL_DESC_STACK3   - LABEL_GDT + SA_RPL3  
    43. SelectorTSS     equ LABEL_DESC_TSS      - LABEL_GDT  
    44. SelectorVideo       equ LABEL_DESC_VIDEO    - LABEL_GDT  
    45.   
    46. SelectorCallGateTest    equ LABEL_CALL_GATE_TEST    - LABEL_GDT + SA_RPL3  
    47. ; END of [SECTION .gdt]  
    48.   
    49. [SECTION .data1]     ; 数据段  
    50. ALIGN   32  
    51. [BITS   32]  
    52. LABEL_DATA:  
    53. SPValueInRealMode   dw  0  
    54. ; 字符串  
    55. PMMessage:      db  "In Protect Mode now. ^-^", 0   ; 进入保护模式后显示此字符串  
    56. OffsetPMMessage     equ PMMessage - $  
    57. StrTest:        db  "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 0  
    58. OffsetStrTest       equ StrTest - $  
    59. DataLen         equ $ - LABEL_DATA  
    60. ; END of [SECTION .data1]  
    61.   
    62.   
    63. ; 全局堆栈段  
    64. [SECTION .gs]  
    65. ALIGN   32  
    66. [BITS   32]  
    67. LABEL_STACK:  
    68.     times 512 db 0  
    69. TopOfStack  equ $ - LABEL_STACK - 1  
    70. ; END of [SECTION .gs]  
    71.   
    72.   
    73. ; 堆栈段ring3  
    74. [SECTION .s3]  
    75. ALIGN   32  
    76. [BITS   32]  
    77. LABEL_STACK3:  
    78.     times 512 db 0  
    79. TopOfStack3 equ $ - LABEL_STACK3 - 1  
    80. ; END of [SECTION .s3]  
    81.   
    82.   
    83. ; TSS ---------------------------------------------------------------------------------------------  
    84. [SECTION .tss]  
    85. ALIGN   32  
    86. [BITS   32]  
    87. LABEL_TSS:  
    88.         DD  0           ; Back  
    89.         DD  TopOfStack      ; 0 级堆栈  
    90.         DD  SelectorStack       ;   
    91.         DD  0           ; 1 级堆栈  
    92.         DD  0           ;   
    93.         DD  0           ; 2 级堆栈  
    94.         DD  0           ;   
    95.         DD  0           ; CR3  
    96.         DD  0           ; EIP  
    97.         DD  0           ; EFLAGS  
    98.         DD  0           ; EAX  
    99.         DD  0           ; ECX  
    100.         DD  0           ; EDX  
    101.         DD  0           ; EBX  
    102.         DD  0           ; ESP  
    103.         DD  0           ; EBP  
    104.         DD  0           ; ESI  
    105.         DD  0           ; EDI  
    106.         DD  0           ; ES  
    107.         DD  0           ; CS  
    108.         DD  0           ; SS  
    109.         DD  0           ; DS  
    110.         DD  0           ; FS  
    111.         DD  0           ; GS  
    112.         DD  0           ; LDT  
    113.         DW  0           ; 调试陷阱标志  
    114.         DW  $ - LABEL_TSS + 2   ; I/O位图基址  
    115.         DB  0ffh            ; I/O位图结束标志  
    116. TSSLen      equ $ - LABEL_TSS  
    117. ; TSS ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  
    118.   
    119.   
    120. [SECTION .s16]  
    121. [BITS   16]  
    122. LABEL_BEGIN:  
    123.     mov ax, cs  
    124.     mov ds, ax  
    125.     mov es, ax  
    126.     mov ss, ax  
    127.     mov sp, 0100h  
    128.   
    129.     mov [LABEL_GO_BACK_TO_REAL+3], ax  
    130.     mov [SPValueInRealMode], sp  
    131.   
    132.     ; 初始化 16 位代码段描述符  
    133.     mov ax, cs  
    134.     movzx   eax, ax  
    135.     shl eax, 4  
    136.     add eax, LABEL_SEG_CODE16  
    137.     mov word [LABEL_DESC_CODE16 + 2], ax  
    138.     shr eax, 16  
    139.     mov byte [LABEL_DESC_CODE16 + 4], al  
    140.     mov byte [LABEL_DESC_CODE16 + 7], ah  
    141.   
    142.     ; 初始化 32 位代码段描述符  
    143.     xor eax, eax  
    144.     mov ax, cs  
    145.     shl eax, 4  
    146.     add eax, LABEL_SEG_CODE32  
    147.     mov word [LABEL_DESC_CODE32 + 2], ax  
    148.     shr eax, 16  
    149.     mov byte [LABEL_DESC_CODE32 + 4], al  
    150.     mov byte [LABEL_DESC_CODE32 + 7], ah  
    151.   
    152.     ; 初始化测试调用门的代码段描述符  
    153.     xor eax, eax  
    154.     mov ax, cs  
    155.     shl eax, 4  
    156.     add eax, LABEL_SEG_CODE_DEST  
    157.     mov word [LABEL_DESC_CODE_DEST + 2], ax  
    158.     shr eax, 16  
    159.     mov byte [LABEL_DESC_CODE_DEST + 4], al  
    160.     mov byte [LABEL_DESC_CODE_DEST + 7], ah  
    161.   
    162.     ; 初始化数据段描述符  
    163.     xor eax, eax  
    164.     mov ax, ds  
    165.     shl eax, 4  
    166.     add eax, LABEL_DATA  
    167.     mov word [LABEL_DESC_DATA + 2], ax  
    168.     shr eax, 16  
    169.     mov byte [LABEL_DESC_DATA + 4], al  
    170.     mov byte [LABEL_DESC_DATA + 7], ah  
    171.   
    172.     ; 初始化堆栈段描述符  
    173.     xor eax, eax  
    174.     mov ax, ds  
    175.     shl eax, 4  
    176.     add eax, LABEL_STACK  
    177.     mov word [LABEL_DESC_STACK + 2], ax  
    178.     shr eax, 16  
    179.     mov byte [LABEL_DESC_STACK + 4], al  
    180.     mov byte [LABEL_DESC_STACK + 7], ah  
    181.   
    182.     ; 初始化堆栈段描述符(ring3)  
    183.     xor eax, eax  
    184.     mov ax, ds  
    185.     shl eax, 4  
    186.     add eax, LABEL_STACK3  
    187.     mov word [LABEL_DESC_STACK3 + 2], ax  
    188.     shr eax, 16  
    189.     mov byte [LABEL_DESC_STACK3 + 4], al  
    190.     mov byte [LABEL_DESC_STACK3 + 7], ah  
    191.   
    192.     ; 初始化Ring3描述符  
    193.     xor eax, eax  
    194.     mov ax, ds  
    195.     shl eax, 4  
    196.     add eax, LABEL_CODE_RING3  
    197.     mov word [LABEL_DESC_CODE_RING3 + 2], ax  
    198.     shr eax, 16  
    199.     mov byte [LABEL_DESC_CODE_RING3 + 4], al  
    200.     mov byte [LABEL_DESC_CODE_RING3 + 7], ah  
    201.   
    202.     ; 初始化 TSS 描述符  
    203.     xor eax, eax  
    204.     mov ax, ds  
    205.     shl eax, 4  
    206.     add eax, LABEL_TSS  
    207.     mov word [LABEL_DESC_TSS + 2], ax  
    208.     shr eax, 16  
    209.     mov byte [LABEL_DESC_TSS + 4], al  
    210.     mov byte [LABEL_DESC_TSS + 7], ah  
    211.   
    212.     ; 为加载 GDTR 作准备  
    213.     xor eax, eax  
    214.     mov ax, ds  
    215.     shl eax, 4  
    216.     add eax, LABEL_GDT      ; eax <- gdt 基地址  
    217.     mov dword [GdtPtr + 2], eax ; [GdtPtr + 2] <- gdt 基地址  
    218.   
    219.     ; 加载 GDTR  
    220.     lgdt    [GdtPtr]  
    221.   
    222.     ; 关中断  
    223.     cli  
    224.   
    225.     ; 打开地址线A20  
    226.     in  al, 92h  
    227.     or  al, 00000010b  
    228.     out 92h, al  
    229.   
    230.     ; 准备切换到保护模式  
    231.     mov eax, cr0  
    232.     or  eax, 1  
    233.     mov cr0, eax  
    234.   
    235.     ; 真正进入保护模式  
    236.     jmp dword SelectorCode32:0  ; 执行这一句会把 SelectorCode32 装入 cs, 并跳转到 Code32Selector:0  处  
    237.   
    238. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;  
    239.   
    240. LABEL_REAL_ENTRY:       ; 从保护模式跳回到实模式就到了这里  
    241.     mov ax, cs  
    242.     mov ds, ax  
    243.     mov es, ax  
    244.     mov ss, ax  
    245.   
    246.     mov sp, [SPValueInRealMode]  
    247.   
    248.     in  al, 92h     ; ┓  
    249.     and al, 11111101b   ; ┣ 关闭 A20 地址线  
    250.     out 92h, al     ; ┛  
    251.   
    252.     sti         ; 开中断  
    253.   
    254.     mov ax, 4c00h   ; ┓  
    255.     int 21h     ; ┛回到 DOS  
    256. ; END of [SECTION .s16]  
    257.   
    258.   
    259. [SECTION .s32]; 32 位代码段. 由实模式跳入.  
    260. [BITS   32]  
    261.   
    262. LABEL_SEG_CODE32:  
    263.     mov ax, SelectorData  
    264.     mov ds, ax          ; 数据段选择子  
    265.     mov ax, SelectorVideo  
    266.     mov gs, ax          ; 视频段选择子  
    267.   
    268.     mov ax, SelectorStack  
    269.     mov ss, ax          ; 堆栈段选择子  
    270.   
    271.     mov esp, TopOfStack  
    272.   
    273.   
    274.     ; 下面显示一个字符串  
    275.     mov ah, 0Ch         ; 0000: 黑底    1100: 红字  
    276.     xor esi, esi  
    277.     xor edi, edi  
    278.     mov esi, OffsetPMMessage    ; 源数据偏移  
    279.     mov edi, (80 * 10 + 0) * 2  ; 目的数据偏移。屏幕第 10 行, 第 0 列。  
    280.     cld  
    281. .1:  
    282.     lodsb  
    283.     test    al, al  
    284.     jz  .2  
    285.     mov [gs:edi], ax  
    286.     add edi, 2  
    287.     jmp .1  
    288. .2: ; 显示完毕  
    289.   
    290.     call    DispReturn  
    291.   
    292.     ; Load TSS  
    293.     mov ax, SelectorTSS  
    294.     ltr ax  ; 在任务内发生特权级变换时要切换堆栈,而内层堆栈的指针存放在当前任务的TSS中,所以要设置任务状态段寄存器 TR。  
    295.   
    296.     push    SelectorStack3  
    297.     push    TopOfStack3  
    298.     push    SelectorCodeRing3  
    299.     push    0  
    300.     retf                ; Ring0 -> Ring3,历史性转移!将打印数字 '3'。  
    301.   
    302. ; ------------------------------------------------------------------------  
    303. DispReturn:  
    304.     push    eax  
    305.     push    ebx  
    306.     mov eax, edi  
    307.     mov bl, 160  
    308.     div bl  
    309.     and eax, 0FFh  
    310.     inc eax  
    311.     mov bl, 160  
    312.     mul bl  
    313.     mov edi, eax  
    314.     pop ebx  
    315.     pop eax  
    316.   
    317.     ret  
    318. ; DispReturn 结束---------------------------------------------------------  
    319.   
    320. SegCode32Len    equ $ - LABEL_SEG_CODE32  
    321. ; END of [SECTION .s32]  
    322.   
    323.   
    324. [SECTION .sdest]; 调用门目标段  
    325. [BITS   32]  
    326.   
    327. LABEL_SEG_CODE_DEST:  
    328.     mov ax, SelectorVideo  
    329.     mov gs, ax          ; 视频段选择子(目的)  
    330.   
    331.     mov edi, (80 * 12 + 0) * 2  ; 屏幕第 12 行, 第 0 列。  
    332.     mov ah, 0Ch         ; 0000: 黑底    1100: 红字  
    333.     mov al, 'C'  
    334.     mov [gs:edi], ax  
    335.   
    336.     retf  
    337. SegCodeDestLen  equ $ - LABEL_SEG_CODE_DEST  
    338. ; END of [SECTION .sdest]  
    339.   
    340.   
    341. ; 16 位代码段. 由 32 位代码段跳入, 跳出后到实模式  
    342. [SECTION .s16code]  
    343. ALIGN   32  
    344. [BITS   16]  
    345. LABEL_SEG_CODE16:  
    346.     ; 跳回实模式:  
    347.     mov ax, SelectorNormal  
    348.     mov ds, ax  
    349.     mov es, ax  
    350.     mov fs, ax  
    351.     mov gs, ax  
    352.     mov ss, ax  
    353.   
    354.     mov eax, cr0  
    355.     and al, 11111110b  
    356.     mov cr0, eax  
    357.   
    358. LABEL_GO_BACK_TO_REAL:  
    359.     jmp 0:LABEL_REAL_ENTRY  ; 段地址会在程序开始处被设置成正确的值  
    360.   
    361. Code16Len   equ $ - LABEL_SEG_CODE16  
    362.   
    363. ; END of [SECTION .s16code]  
    364.   
    365. ; CodeRing3  
    366. [SECTION .ring3]  
    367. ALIGN   32  
    368. [BITS   32]  
    369. LABEL_CODE_RING3:  
    370.     mov ax, SelectorVideo  
    371.     mov gs, ax          ; 视频段选择子(目的)  
    372.   
    373.     mov edi, (80 * 14 + 0) * 2  ; 屏幕第 14 行, 第 0 列。  
    374.     mov ah, 0Ch         ; 0000: 黑底    1100: 红字  
    375.     mov al, '3'  
    376.     mov [gs:edi], ax  
    377.   
    378.     call    SelectorCallGateTest:0  ; 测试调用门(有特权级变换),将打印字母 'C'。  
    379.     jmp $  
    380. SegCodeRing3Len equ $ - LABEL_CODE_RING3  
    381. ; END of [SECTION .ring3]  
    ; ==========================================
    ; pmtest5.asm
    ; 编译方法:nasm pmtest5.asm -o pmtest5.com
    ; ==========================================
    
    %include	"pm.inc"	; 常量, 宏, 以及一些说明
    
    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	; 非一致代码段, 32
    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; Stack, 32 位
    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
    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	"ABCDEFGHIJKLMNOPQRSTUVWXYZ", 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
    
    	; 初始化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
    
    	; 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
    
    	retf
    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]
    
    ; 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'。
    	jmp	$
    SegCodeRing3Len	equ	$ - LABEL_CODE_RING3
    ; END of [SECTION .ring3]
    

    83—117初始化任务状态堆栈段(TSS) 292—300 通过使用retf完成从Ring0-->Ring3的跳转,即高特权级跳转到低特权级,跳转到LABEL_CODE_RING3。 380—380 通过调用门,完成从Ring3-->Ring0的跳转,即低特权级跳转到高特权级,跳转到LABEL_SEG_CODE_DEST 336—336 通过retf,完成从Ring0-->Ring3的跳转,即高特权级跳转到低特权级,跳转到379。 到目前为止,我们已经实现了两次从高特权级到低特权级以及一次从低特权级到高特权级的转移,最终在低特权级的代码中让程序停住。

  • 相关阅读:
    使用RoboCopy 命令[转载]
    取得超级管理员权限
    重置网络命令win7
    ASP.NET Global.asax详解【转】
    逆波兰式算法
    设计模式【转自JackFrost的博客】
    VS2013 F12无法转到函数的定义处,总是从“元数据”获取的问题 ——解决方法
    扩展方法 C#
    委托Func和Action【转】
    添加路由
  • 原文地址:https://www.cnblogs.com/wanghj-dz/p/3987599.html
Copyright © 2011-2022 走看看