特权级检查的时间
在选择子没有被装入CS
之前进行检查,如果检查成功则将选择子装入CS
寄存器。相应的RPL
变为CPL
。我觉得这个检查的机制就像是数据库的对内容的约束检查,或者说更像是一个before
类型的触发器。当CPL
、RPL
、DPL
都通过检查后,CPU
将选择子装入相应的寄存器中。否则产生一个通用保护异常。
特权级检查的几种情况:
● 访问数据段
只要将选择子装入对应的数据段寄存器(
DS
、ES
、FS
、GS
)时就按照这个访问规则进行的检查,无论选择子对应的描述符的属性标识是否为数据段(TYPE
域的最高位——段描述符的第二个双字的第11
位将决定该描述符为数据段描述符(为0
)还是代码段描述符(为1
)
)。因为有的时候也需要访问代码段的数据。
数据段的访问原则就是可以被高级的代码访问,不能够被比自己权限低的代码访问。
因此要求 DPL>=CPL && DPL>=RPL
即 destination.DPL >= max{CPL, RPL}
这里所说的DPL
、RPL
、CPL
都是指其相应位对应的值,值越大表示的特权级别就越低,下同。
● 访问堆栈段(将选择子装入堆栈段寄存器SS
时)
CPL = destination.DPL = destination.RPL
● 不通过调用门访问代码段
选择子装入CS
寄存器时进行检查。由于使用JMP
、CALL
和RET
指令在当前代码段内进行进程控制的转移的时候不进行段切换不需要更新选择子所以不进行特权级的检查。只有将新的选择子装入CS
寄存器的时候才进行特权级检查。
调用可以通过门调用,也可以不通过,但是如果不通过调用门,那么CPL
不会发生变化。
1.
访问非一致码(跳转目的选择子对应的描述符的一致性标志位C=0
)
非一致码只允许访问(调用)处于同一特权级别的代码。大多数代码都应该是非一致的。这样,除非使用调用门否则程序只能在同级别之间发生转移。只有 destination.DPL=CPL && destination.RPL<=CPL
时才允许访问。
2.
访问一致代码(跳转目的选择子对应的描述符的一致性标志位C=1
)
一致代码段就是无须进行特权转换的代码段。当一致代码段被调用时,直接使用当前特权级执行该代码段,这样是为了从外层级跳到自由内层级。
一致代码段描述符中的DPL
规定了可以转移到一致代码段的最内层特权级。一致代码段描述符内DPL
的这种解释,正好与非一致代码段DPL
的解释相反。于是3
级的程序可以转移到任何一致的代码段,而0
级的程序只允许转移到DPL
等于0
的一致代码段。
一致代码一般用于一些公共程序,
如数学库函数、异常处理等。这些程序本身是系统或应用程序的一部分,但它们应该能被低级别应用程序任意调用而不需要访问受保护的系统模块。
如果是非一致码则会忽略RPL
,不检查RPL
,而只检查CPL
和DPL
。此时只要满足 destination.DPL>=CPL
即:目的(需要调用的系统函数)的特权级别比当前(应用程序)的特权级别高就可以被调用。但是目的选择子的RPL
不会被装入CS
寄存器,原选择子的CPL
值被延续了下来保持不变。