zoukankan      html  css  js  c++  java
  • 第十五课 保护模式中的特权级(上)

    保护模式小结:

      -使用选择子访问段描述符表时,索引值的合法性检测,这个检测是处理器做的

        当索引值越界时,引发异常

        判断规则:索引值*8 + 7 <= 段描述表界限值

    段描述表界限值就是段描述表中的地址最大值

      

      -内存段类型合法性检测,使用选择子给相应的段寄存器赋值的时候会进行这个合法性检测

        具备可执行属性的段(代码段)才能加载到CS寄存器

        具备可写属性的段(数据段)才能加载到SS寄存器,加载到SS寄存器的段是栈段

        具备可读属性的段才能加载到DS,ES,FS,GS寄存器

     这里列出来的都是最低的条件

      -代码段和数据段的保护

        处理器每访问一个地址都要确认该地址不超过界限值

        判断规则:

          代码段:IP + 指令长度 <= 代码段界限

          数据段:访问起始地址 + 访问数据长度 <= 数据段界限

        段界限是相对于段基址而言的,而不是绝对物理地址

     注意:

      保护模式中代码中定义的界限值通常为:

        最大偏移地址值(相对于段基址)。

    实验分析:

    正常程序如下:

      1 %include "inc.asm"
      2 
      3 org 0x9000
      4 
      5 jmp CODE16_SEGMENT
      6 
      7 [section .gdt]
      8 ; GDT definition
      9 ;                                 段基址,       段界限,       段属性
     10 GDT_ENTRY       :     Descriptor    0,            0,           0
     11 CODE32_DESC     :     Descriptor    0,    Code32SegLen  - 1,   DA_C + DA_32
     12 VIDEO_DESC      :     Descriptor 0xB8000,       0x07FFF,       DA_DRWA + DA_32
     13 DATA32_DESC     :     Descriptor    0,    Data32SegLen  - 1,   DA_DR + DA_32
     14 STACK32_DESC    :     Descriptor    0,      TopOfStack32,      DA_DRW + DA_32        
     15 ; GDT end
     16 
     17 GdtLen    equ   $ - GDT_ENTRY
     18 
     19 GdtPtr:
     20           dw   GdtLen - 1
     21           dd   0
     22           
     23           
     24 ; GDT Selector
     25 
     26 Code32Selector    equ (0x0001 << 3) + SA_TIG + SA_RPL0
     27 VideoSelector     equ (0x0002 << 3) + SA_TIG + SA_RPL0
     28 Data32Selector    equ (0x0003 << 3) + SA_TIG + SA_RPL0
     29 Stack32Selector   equ (0x0004 << 3) + SA_TIG + SA_RPL0
     30 
     31 ; end of [section .gdt]
     32 
     33 TopOfStack16    equ  0x7c00
     34 
     35 [section .dat]
     36 [bits 32]
     37 DATA32_SEGMENT:
     38     DTOS                 db    "D.T.OS!", 0
     39     DTOS_OFFSET          equ   DTOS - $$
     40     HELLO_WORLD          db    "Hello World!", 0
     41     HELLO_WORLD_OFFSET   equ  HELLO_WORLD - $$
     42 
     43 Data32SegLen  equ $ - DATA32_SEGMENT
     44 
     45 [section .s16]
     46 [bits 16]
     47 CODE16_SEGMENT:
     48     mov ax, cs
     49     mov ds, ax
     50     mov es, ax
     51     mov ss, ax
     52     mov sp, TopOfStack16
     53     
     54     ; initialize GDT for 32 bits code segment
     55     mov esi, CODE32_SEGMENT
     56     mov edi, CODE32_DESC
     57     
     58     call InitDescItem
     59     
     60     mov esi, DATA32_SEGMENT
     61     mov edi, DATA32_DESC
     62     
     63     call InitDescItem
     64     
     65     mov esi, DATA32_SEGMENT
     66     mov edi, STACK32_DESC
     67     
     68     call InitDescItem
     69     
     70     ; initialize GDT pointer struct
     71     mov eax, 0
     72     mov ax, ds
     73     shl eax, 4
     74     add eax, GDT_ENTRY
     75     mov dword [GdtPtr + 2], eax
     76 
     77     ; 1. load GDT
     78     lgdt [GdtPtr]
     79     
     80     ; 2. close interrupt
     81     cli 
     82     
     83     ; 3. open A20
     84     in al, 0x92
     85     or al, 00000010b
     86     out 0x92, al
     87     
     88     ; 4. enter protect mode
     89     mov eax, cr0
     90     or eax, 0x01
     91     mov cr0, eax
     92     
     93     ; 5. jump to 32 bits code
     94     jmp dword Code32Selector : 0
     95 
     96     
     97 ; esi    --> code segment label
     98 ; edi    --> descriptor label
     99 InitDescItem:
    100     push eax
    101     
    102     mov eax, 0
    103     mov ax, cs
    104     shl eax, 4
    105     add eax, esi
    106     mov word [edi + 2], ax
    107     shr eax, 16
    108     mov byte [edi + 4], al
    109     mov byte [edi + 7], ah
    110     
    111     pop eax
    112     
    113     ret
    114     
    115     
    116 [section .s32]
    117 [bits 32]
    118 CODE32_SEGMENT:
    119     mov ax, VideoSelector
    120     mov gs, ax
    121     
    122     mov ax, Stack32Selector
    123     mov ss, ax
    124     
    125     mov eax, TopOfStack32
    126     mov esp, eax
    127     
    128     mov ax, Data32Selector
    129     mov ds, ax
    130     
    131     mov ebp, DTOS_OFFSET
    132     mov bx, 0x0C
    133     mov dh, 12
    134     mov dl, 33
    135     
    136     call PrintString
    137     
    138     mov ebp, HELLO_WORLD_OFFSET
    139     mov bx, 0x0C
    140     mov dh, 13
    141     mov dl, 30
    142     
    143     call PrintString
    144     
    145     jmp $
    146 
    147 ; ds:ebp   --> string address
    148 ; bx       --> attribute
    149 ; dx       --> dh : row, dl : col
    150 PrintString:
    151     push ebp
    152     push eax
    153     push edi 
    154     push cx
    155     push dx
    156     
    157 print:
    158     mov cl, [ds:ebp]
    159     cmp cl, 0
    160     je end
    161     mov eax, 80
    162     mul dh
    163     add al, dl
    164     shl eax, 1
    165     mov edi, eax
    166     mov ah, bl
    167     mov al, cl
    168     mov [gs:edi], ax
    169     inc ebp
    170     inc dl
    171     jmp print
    172     
    173 end:
    174     pop dx
    175     pop cx
    176     pop edi
    177     pop eax
    178     pop ebp
    179     
    180     ret
    181 
    182 Code32SegLen    equ    $ - CODE32_SEGMENT
    183 
    184 [section .gs]
    185 [bits 32]
    186 STACK32_SEGMENT:
    187     times 1024 * 4 db 0
    188     
    189 Stack32SegLen    equ $ - STACK32_SEGMENT
    190 TopOfStack32    equ Stack32SegLen - 1

    运行结果如下:

    修改程序如下:

      1 %include "inc.asm"
      2 
      3 org 0x9000
      4 
      5 jmp CODE16_SEGMENT
      6 
      7 [section .gdt]
      8 ; GDT definition
      9 ;                                 段基址,       段界限,       段属性
     10 GDT_ENTRY       :     Descriptor    0,            0,           0
     11 CODE32_DESC     :     Descriptor    0,    Code32SegLen  - 1,   DA_C + DA_32
     12 VIDEO_DESC      :     Descriptor 0xB8000,       0x07FFF,       DA_DRWA + DA_32
     13 DATA32_DESC     :     Descriptor    0,    Data32SegLen  - 1,   DA_DR + DA_32
     14 STACK32_DESC    :     Descriptor    0,      TopOfStack32,      DA_DRW + DA_32        
     15 ; GDT end
     16 
     17 GdtLen    equ   $ - GDT_ENTRY
     18 
     19 GdtPtr:
     20           dw   GdtLen - 1
     21           dd   0
     22           
     23           
     24 ; GDT Selector
     25 
     26 Code32Selector    equ (0x0001 << 3) + SA_TIG + SA_RPL0
     27 VideoSelector     equ (0x0002 << 3) + SA_TIG + SA_RPL0
     28 Data32Selector    equ (0x0003 << 3) + SA_TIG + SA_RPL0
     29 Stack32Selector   equ (0x0004 << 3) + SA_TIG + SA_RPL0
     30 ExceptionSelector   equ (0x0005 << 3) + SA_TIG + SA_RPL0
     31 
     32 ; end of [section .gdt]
     33 
     34 TopOfStack16    equ  0x7c00
     35 
     36 [section .dat]
     37 [bits 32]
     38 DATA32_SEGMENT:
     39     DTOS                 db    "D.T.OS!", 0
     40     DTOS_OFFSET          equ   DTOS - $$
     41     HELLO_WORLD          db    "Hello World!", 0
     42     HELLO_WORLD_OFFSET   equ  HELLO_WORLD - $$
     43 
     44 Data32SegLen  equ $ - DATA32_SEGMENT
     45 
     46 [section .s16]
     47 [bits 16]
     48 CODE16_SEGMENT:
     49     mov ax, cs
     50     mov ds, ax
     51     mov es, ax
     52     mov ss, ax
     53     mov sp, TopOfStack16
     54     
     55     ; initialize GDT for 32 bits code segment
     56     mov esi, CODE32_SEGMENT
     57     mov edi, CODE32_DESC
     58     
     59     call InitDescItem
     60     
     61     mov esi, DATA32_SEGMENT
     62     mov edi, DATA32_DESC
     63     
     64     call InitDescItem
     65     
     66     mov esi, DATA32_SEGMENT
     67     mov edi, STACK32_DESC
     68     
     69     call InitDescItem
     70     
     71     ; initialize GDT pointer struct
     72     mov eax, 0
     73     mov ax, ds
     74     shl eax, 4
     75     add eax, GDT_ENTRY
     76     mov dword [GdtPtr + 2], eax
     77 
     78     ; 1. load GDT
     79     lgdt [GdtPtr]
     80     
     81     ; 2. close interrupt
     82     cli 
     83     
     84     ; 3. open A20
     85     in al, 0x92
     86     or al, 00000010b
     87     out 0x92, al
     88     
     89     ; 4. enter protect mode
     90     mov eax, cr0
     91     or eax, 0x01
     92     mov cr0, eax
     93     
     94     ; 5. jump to 32 bits code
     95     jmp dword ExceptionSelector : 0
     96 
     97     
     98 ; esi    --> code segment label
     99 ; edi    --> descriptor label
    100 InitDescItem:
    101     push eax
    102     
    103     mov eax, 0
    104     mov ax, cs
    105     shl eax, 4
    106     add eax, esi
    107     mov word [edi + 2], ax
    108     shr eax, 16
    109     mov byte [edi + 4], al
    110     mov byte [edi + 7], ah
    111     
    112     pop eax
    113     
    114     ret
    115     
    116     
    117 [section .s32]
    118 [bits 32]
    119 CODE32_SEGMENT:
    120     mov ax, VideoSelector
    121     mov gs, ax
    122     
    123     mov ax, Stack32Selector
    124     mov ss, ax
    125     
    126     mov eax, TopOfStack32
    127     mov esp, eax
    128     
    129     mov ax, Data32Selector
    130     mov ds, ax
    131     
    132     mov ebp, DTOS_OFFSET
    133     mov bx, 0x0C
    134     mov dh, 12
    135     mov dl, 33
    136     
    137     call PrintString
    138     
    139     mov ebp, HELLO_WORLD_OFFSET
    140     mov bx, 0x0C
    141     mov dh, 13
    142     mov dl, 30
    143     
    144     call PrintString
    145     
    146     jmp $
    147 
    148 ; ds:ebp   --> string address
    149 ; bx       --> attribute
    150 ; dx       --> dh : row, dl : col
    151 PrintString:
    152     push ebp
    153     push eax
    154     push edi 
    155     push cx
    156     push dx
    157     
    158 print:
    159     mov cl, [ds:ebp]
    160     cmp cl, 0
    161     je end
    162     mov eax, 80
    163     mul dh
    164     add al, dl
    165     shl eax, 1
    166     mov edi, eax
    167     mov ah, bl
    168     mov al, cl
    169     mov [gs:edi], ax
    170     inc ebp
    171     inc dl
    172     jmp print
    173     
    174 end:
    175     pop dx
    176     pop cx
    177     pop edi
    178     pop eax
    179     pop ebp
    180     
    181     ret
    182 
    183 Code32SegLen    equ    $ - CODE32_SEGMENT
    184 
    185 [section .gs]
    186 [bits 32]
    187 STACK32_SEGMENT:
    188     times 1024 * 4 db 0
    189     
    190 Stack32SegLen    equ $ - STACK32_SEGMENT
    191 TopOfStack32    equ Stack32SegLen - 1

    我们在第30行新添加了一个段选择子,选择子号是5,而在第8-14行的段描述符表中没有为5的描述符。第95行跳转时我们使用新添加的段选择子,启动bochs,实验结果如下:

     可以看出CPU复位了,因为选择子对用的描述符越界了。

     下面进行属性的实验:

    在正常的程序基础上进行修改:

    1、修改代码段属性

    将第11行的代码段的可执行属性改成可读属性,程序运行崩溃,运行结果如下:

    2、修改栈段属性,将可写属性去掉,只留下可读属性,程序崩溃,如下:

    可以看到程序在执行第123行的mov ss,ax是崩溃的,因为这时候栈段的属性没有可写了,所以会出错。

    3、修改数据段属性,将可读写属性改为可执行属性

     运行结果如下:

     可以看到在第129行出错,mov ds,ax导致程序崩溃。

    下面做界限值的实验:

    1、代码段界限修改

    将第11行的代码段界限改小一个字节,运行结果如下:

    程序崩溃了,是在执行180行的ret时崩溃的,因为这时候的代码已经超出了界限。

    2、修改数据段界限

    将第13行的数据段界限改小1个字节,运行结果如下:

     这是在执行第158行的打印时崩溃了,当我们打印字符串的最后一个0时,超出了数据段的界限。

    问题:

    保护模式除了利用段界限对内存访问进行保护,是否还提供其他的保护机制?

    保护模式中的特权级:

      - X86架构中的保护模式提供了四个特权级(0,1,2,3)

      - 特权级从高到低分别是0,1,2,3(数字越大特权级越低)

    linux和window只用到0和3级,即内核态和用户态。

    特权级的表现形式:

      CPL(Current Privilege Level)

        当前可执行代码段的特权级,由CS寄存器最低2位定义,CS保存的段选择子

      DPL(Descriptor Privilege Level)

        内存段的特权级,在段描述符表中定义

      RPL(Request Privilege Level)

        选择子的特权级,由选择子最低2位定义

     段描述符中的DPL用于标识内存段的特权级,可执行代码访问内存段时必须满足一定的特权级(CPL),否则,处理器将产生异常

    可执行代码访问数据段的情形:

      应用程序访问内核的数据,会崩溃,因为内核的数据的DPL是0,应用程序的CPL是3。CPL应该小于等于DPL才可以访问。

    CPL和DPL的关系:代码段之间的跳转

      保护模式中每一个代码段都定义了一个DPL

      当处理器从A代码段成功跳转到B代码段执行

        跳转之前:CPL = DPLa

        跳转之后:CPL = DPLb

       

    保护模式中,每一个数据段都定义了一个DPL

    当处理器执行过程中需要访问数据段时:

      CPL <= DPLdata

    CPL和DPL实验:

    首先在inc.asm文件中定义特权级

    1、修改代码段的DPL

    11行将代码段的DPL设置为3,执行结果如下:

     

    程序崩溃了,提示DPL不等于CPL。

    程序进入保护模式后默认的CPL为0,而我们的32位代码段DPL为3。

    第88-91行的程序执行完就进入了保护模式,这时的CPL默认为0,在第94行跳转时,从CPL为0向DPL为3跳转就发生了异常。

    运行结果告诉我们从CPL为0的代码段不能跳转到DPL位3的代码段。

    将DPL改为0,运行结果如下:

     

    程序正常运行了,这时候CPL等于DPL。从CPL为0的代码段可以跳转到DPL位0的代码段。

    2、修改数据段的DPL

     

    程序依然能正常运行,这说明程序在访问数据时,只要CPL小于等于相应数据段的DPL即可。

    RPL实验:

    1、修改代码段选择子的RPL

    运行结果如下:

    提示我们RPL > CPL,可见在代码段跳转时,RPL也参与了合法性判断。

    将代码段RPL改回0即可正常运行。

    2、修改数据段的RPL

    28行将RPL改为3,运行结果:

    再次修改28行的RPL:

    运行结果如下:

    可见访问数据段时RPL并没有参与合法性判断。

     3、栈段的RPL实验

    第14行的栈的DPL改为3,第29行栈的RPL改为3,运行结果如下:

    将上述两个特权级都改为0,如下:

    结果如下:

    都改为0后程序就可以正常运行了。

    可见,栈段和数据段的特权级判断使用的规则并不一样。

     实验结论:

      处理器进入保护模式后CPL = 0(最高特权级)

      处理器不能从高特权级转换到低特权级执行

      选择子RPL大于对应段描述符的DPL时,产生异常

    处理器进入保护模式后默认特权级为0,我们必须将它降下来,这样才能从高特权级跳转到低特权级代码执行。从低到高跳转也需要改变特权级。

    小结:

      保护模式对内存的访问范围有严格定义

      保护模式定义了内存段的特权级(0,1,2,3)

        每个内存段都有固定的特权级(DPL)

        不同代码段之间成功跳转后CPL可能发生改变

        CPL小于或等于数据段DPL才能成功访问数据

      

  • 相关阅读:
    onload执行顺序
    让EXCHANGE可以接收外部邮件服务器发送的邮件
    QQ网站里AppTui对象脚本
    owa2007写新邮件时已经选择人员不能带入到与通讯录选人界面问题解决方法
    qq网站里动态加载脚本的实现
    qq网站里对元素的操作方法
    让Exchange可以发送邮件到互联网的邮件服务器
    js实现的hashtable
    无线网卡共享网络发射
    css省略号效果
  • 原文地址:https://www.cnblogs.com/wanmeishenghuo/p/9614608.html
Copyright © 2011-2022 走看看