忆杰的博客

忆杰的博客

保护模式5:特权级

对于Intel的CPU, 关于这个特权级转换, 套用小胡的话说, 有点罗嗦..

当前特权级(CPL):  
   当前执行程序或任务的特权级存在于已装载的CS, SS描述符中的0和1位中.
 
描述符特权级(DPL):
   段或者门的特权级,存在于段或者门描述符中.的DPL中. 同时描述不同的类型时还有不同的含义:
      数据段: DPL指明了访问该段的最小特权级, CPL <= DPL才可以访问
      非一致代码段(不使用调用门): DPL指明了访问该段应该有的特权级, CPL == DPL, 没有其他大于等于或者什么的说法. 必须相等
      调用门:和数据段相同
      通过调用门访问一致代码段或者非一致代码:段CPL >= DPL才可以访问. 和数据段完全相反.
      TSS:同数据段

请求特权级(RPL):
   存在于段选择子的0和1位中, 一般来说访问一个段时, 如果CPL <= DPL, 这时候RPL就会取代CPL.

访问数据段时的特权检查:
   为了访问数据段,必须将段选择子装入DS,FS, GS, SS. 如果在数值上(DPL >= CPL)and(DPL >= RPL )和那么就可以装入, 否则产生(#GP)

访问代码段中的数据:
   有时候我们需要访问代码段中的数据, 可以采用以下几种方法.
   1:将一个非一致的, 可读代码段选择子装入数据段寄存器
   2:将一个一致的, 可读代码段的段选择子装入数据段寄存器.(可读的代码段可以装入DS, ES, FS, GS )
   3:使用CS前缀来强制访问选择子已经装入CS寄存器的可读代码段

装入SS寄存器时的特权检查:
   当选择子装入SS段寄存器时, 所有的特权级必须与CPL一致, (CPL == DPL ) and(CPL == RPL), 否则(#GP)

代码段间转移的特权检查:
   目标转移中直接包含转移的选择子和偏移:
      跳转到非一致代码段(C=0):在数值上(CPL == DPL ) and( RPL <= RPL ),否则(#GP), 当CS装入一个非一致代码段选择子时不改变CPL
      跳转到一致代码段(C=1):在数值上(CPL >= DPL ) RPL废弃, 否则(#GP), 对于一致代码段, DPL代码调用例程对该代码段进行访问时需要的特权级的最低数值. 当CS装入一个一致代码段选择子时也不改变CPL.

   通过调用门的转移:
      对于通过调用门的转移, CALL指令和JMP指令是不同的, 而且调用门中涉及的 CPL(当前特权级), RPL(调用门选择子欲跳转的选择子), DPL(调用门描述符中的), DPL(目标代码段描述符中的).另外目标代码段中的C标记还有影响. 
      CALL: CPL <= 调用门DPL; RPL <= 调用门DPL
            目标是一致代码段(c=1):DPL <= CPL
            目标是非一致代码段(C=0):DPL <= CPL

      JMP:  CPL <= 调用门DPL RPL <= 调用门DPL
            目标是一致代码段(C=1):DPL <= CPL
            目标是非一致代码段(C=1):DPL == CPL

     
      调用门中的DPL规定来访问该描述符的最大特权级数值, 要访问该调用门 (CPL <= DPL)and(CPL <= DPL), 也就是特权级比较高, 数值比较小.
      如果调用门中的检查通过, 接下来检查代码段描述符和CPL, 此外CALL, 和JMP是不一样的, 只有CALL指令可以转移到特权级, 也就是数值更小的非一致代码段上,也就是说CALL可以跳转到DPL <= CPL的代码段上, JMP不行. JMP只可以跳转到DPL == CPL上面..
      如果调用特权级更高的非一致代码段, CPL就降级为目标代码段的DPL上, 逻辑上来说是升级来, 数值变小了. 这时候会发生特权级变换, 切换到相应的特权级上面. 但是如果跳转的是一致代码段, 那么CPL不变, 堆栈也不切换
     
      前面讲了CALL, 那么ret返回的时候是个什么款式呢? 其实是这样的.首先ret只能够返回到较低的特权级上面. 数值比较大的特权级, 和CALL对应. 那么如果确定返回的特权级是什么级别呢? 是和CS中的存放的RPL进行对比的, 如果CS中的RPL的数值>CPL, 也就是RPL数值大CPL数值小, 那么就执行跨段返回. 这时候还要特权级检查.

      从调用例程的栈上装入CS和EIP寄存器, 做特权级检验, 然后跳过堆栈中的参数.. 然后检查DS, ES, FS, GS, 如果在返回到的特权级是不可访问的, 那么装入NULL.然后返回

通过TSS直接进行任务切换:
    当段间转移指令的段选择子指向一个可用的TSS描述符时,正常情况下就发生特权级转移,目标任务的入口由目标任务TSS内的CS:EIP指定, 而jmp call内的偏移将丢弃. 另外如果如果是CALL指令, 则返回地址和外层堆栈指针并不压栈. 在访问TSS的时候采用与访问数据段相同的规则做特权级检测, CPL <= DPL, TSS描述符内的DPL规定了可用访问该描述符的最外层特权级, 这个和调用门是一样的,在数值上, (CPL <= DPL )and( RPL <= DPL ), 只有条件满足才进行任务切换

通过任务门进行任务切换:
    当段间转移指令的段选择子指向一个任务门的时候,从当前任务切换到由任务门的选择子所指示的TSS描述符对应的任务, 这样jmp call内的偏移被丢弃, 任务门内的偏移也没有意义. 访问任务门的规则也是和访问数据段的规则是一致的, 在数值上(CPL <= DPL ), 任务门的DPL也是规定了访问该任务门的最外层特权级, 也就是说在数值上(CPL <= DPL)and(RPL <= DPL )以上检测通过的话, 就差不多了, 对于任务门指向的TSS描述符的DPL不做检测, 直接进行切换

   差不多就这些吧. 通过其他形式的转移回头再添加!

发表评论


Warning: Undefined variable $user_ID in /www/wwwroot/joenchen.com/wp-content/themes/agan/comments.php on line 66

您必须登录 才能进行评论。