CPL:当前任务特权(Current Privilege Level)
表示当前正在执行的代码所处的特权级。CPL保存在CS中的最低两位,是针对CS而言的。
RPL:请求特权级RPL(Request Privilege Level)
RPL保存在选择子的最低两位。
DPL:描述符特权(Descriptor Privilege Level)
存储在描述符中的权限位,用于描述代码的所属的特权等级,也就是代码本身真正的特权级。一个程序可以使用多个段(Data,Code,Stack)也可以只用一个code段等。正常的情况下,当程序的环境建立好后,段描述符都不需要改变——当然DPL也不需要改变,因此每个段的DPL值是固定。
以上是网上随处可搜的说明, 之前一直不理解, 为什么会有 CPL/RPL之分, 后来看了 https://bbs.pediy.com/thread-92921.htm 上面的回答,才算是理解了.
举个例子:
这个call调用,就是明显需要加载选择子,寻找描述符的过程
只要这样理解, 实际上的比较, 实在加载选择子之前的, 因为如果校验不通过, 是不允许加载的, 所以 ,CS != Selector != DPL (是不一定等于,而不是一定不等于,也就是说, 这是三个明显不同的东西, 之前一直以为, 是需要把selector加载到CS后,才比较的,所以一直认为,CPL一定== RPL,产生了纠结)
call 0x08:0 // 这是一个 call-gate (使用调用门)
那么:
processor 会做:
1、根据选择子 0x08 在 GDT 中寻找 descriptor
2、processor 检查 descriptor 的 Type 是什么?
这里设为是 call-gate descriptor
3、processor 进行权限检查:
(1) RPL = 00, 因为: selector = 0x08
(2) CPL = 03,(这里设为 03)
(3) DPL 这里要分为两种 DPL:
分别是: call gate descriptor 的 DPL,表示为 DPLg
code segment descriptr 的 DPL,表示为 DPLs
-------------------------------------------------------------------------------
processor 检查:
(1)RPL <= DPLg 且 CPL <= DPLg: 表示当前的运行级别和选择子级别比调用门符级别要高。
因此:调用门符级别必须设为低权限级别,即在这里必须为 DPLg = 3
(2)如果使用的是 call 指令无论代码是 conforming 还是 non-conforming,只要
CPL >= DPLs
都会成功。
4、processor 检查通过后,进行加载 selector 到 CS 中
CS.selector = selector
5、更新 CS 寄存器的内部缓存
(1) CS.slector.RPL = DPLs // 目标代码的运行级别
(2) CS 的 descriptor 结构用 code segment descriptor 来更新