CPL/RPL/DPL
这三个特权级均由两位(bit)组成,可以表示0~3共4个等级。
CPL:全称current privilege level,存放在代码段寄存器中(cs),代表当前执行程序的特权级
RPL: 全称request privilege level,请求特权级,存放在段选择子中
DPL: 全称descriptor privilege level,存放在段描述符中,用于表示段的特权级
在保护模式下,cpu利用cpl/rpl/dpl对程序的访问操作进行特权级检查,数据段和代码段的特权级检查规则有所不同。
数据段和堆栈段:
数据段和堆栈段访问的特权级检查比较简单,只需cpl <= 目标段dpl 且 rpl <= 目标段dpl便可成功访问,即当前程序的特权级和请求特权级必须高于被访问的数据段的特权级,通俗理解就是程序处于高特权级时可以访问低特权级数据。
代码段:
代码段的访问分为以下两种情况
1一致代码段,一致代码段是高特权级的代码共享给低特权级程序使用的,访问时不会更改特权级
2非一致代码段,为避免低特权级访问而保护起来的系统代码,只允许同级访问
成功跳转到一致代码段时,cpl跳转后不发生改变。成功跳转到非一致代码段时,cpl跳转后等于目标代码段的dpl。
跳转又分为两种情况,
1普通跳转,即通过jmp/call完成跳转,跳转的规则如上,cpl跳转后不会发生改变
2通过门(中断门/调用门)进行跳转
调用门,jmp或call后面跟着目标段选择子指向一个调用门描述符(选择子之后的偏移无用,调用门描述符中包含了目标段选择子和段内偏移),访问该描述符时,采用数据段的访问规则检查特权级(调用门描述符的dpl,而非目标段的dpl,这块儿不需要检查调用门内的rpl,会被自动清零),同样要求cpl <= 调用门dpl,rpl <= 调用门dpl。成功将调用门内的目标段选择子和偏移取出后的操作和jmp/call类似,即一致代码段访问需要cpl >= 目标段dpl,且跳转后cpl不变,非一致代码段稍有区别,如果采用jmp的方式跳转,则cpl必须和目标段dpl相同才能跳转,特权级不会发生改变,采用call跳转时,则需cpl >= 目标段dpl,当cpl > 目标段dpl时,跳转后cpl=目标段dpl,特权级发生改变。
总结:
程序成功跳转后cpu并不会把段选择子中的rpl赋给跳转后的代码段寄存器(即发生特权级跳转)
程序跳转后的cpl只有两种可能1跳转后的cpl和跳转前相同2跳转后的cpl等于dpl
Cpu不允许程序向低特权级跳转(认为低特权级的代码不可靠,有风险)
只有一种方式能够使特权级发生改变,call + 调用门 + 非一致代码段,且当前cpl大于目标段dpl,且特权级只能向上跳转。