特权级的东西很乱,我决定今天花一点时间好好的整理一下,我一步一步慢慢开始,比较郁闷的是还不知道理解得正确不正确,先写着吧:
首先,特权级别一共有四个特权级别(0-3),然后呢,数字越小,级别越高。
其次,处理器通过CPL,DPL,RPL来进行特权级管理。
接下来,我想分为2种模块来总结,之前,我一直没把特权级访问和特权级转移分开理解,这里我想分成2块来总结。
第一种:访问。
我想访问主要针对数据段,TSS之类的,当然代码段也会涉及,他们的规则如下:
数据段:DPL规定了可以访问此数据段的最低特权级。
非一致代码段:DPL规定了可以访问此代码段的特权级(即特权级必须相同)
调用门:DPL规定了可以访问此调用门的最低特权级
一致代码段:DPL规定了可以访问此一致代码段的最高特权级
TSS:DPL规定了可以访问此TSS的最低特权级
访问的规则应该主要是如上所述,我想访问的准确定义是对段或门进行读写吧
第二种:不同级代码段之间的转移。
主要说2种方式:
I.通过jmp和call直接转移:
对于这种直接转移的方法,会受到很大的限制,只有以下几种情况才能成功转移:
1.目标段是非一致代码段:要求CPL必须等于目标段的DPL,同时要求RPL小于等于DPL
2.目标段是一致代码段
II.通过调用门转移:
由于上面的转移方式受到诸多限制,所以调用门就显得很重要了。
A.call(通常是从低特权级代码段转至高特权级代码段)
准备工作:
1.准备一个调用门描述符和调用门选择子(注意描述符的DPL大于等于源代码段的CPL和RPL),并初始化
2.准备TSS,只需要目标段DPL的堆栈位置即可
3.加载TSS
4.call调用门
B.retf(通常从高特权级转至低特权级)
总结就四个压栈:
1.压入目标段的SS
2.压入目标段的esp
3.压入目标段的CS
4.压入目标段的eip
5.retf即可
堆栈的使用:
1.不同的特权等级使用不同的堆栈,只有使用调用门的转移才能实现堆栈的切换。所以,利用call和jmp直接转移,对于非一致性代码,只能同级转移(没有堆栈切换);对于一致性代码,cpl必须在转移过程中保持不变(这样也不存在堆栈切换)。
2.如果用jmp+调用门转移,cpl必须等于目标代码段的dpl。因为jmp也无法实现堆栈切换。
3.总结,只有call+调用门才能实现堆栈切换,这是理解这些乱七八糟cpl与dpl规则的关键。
4. call只能实现低特权级到高特权级的转移
5.如果要堆栈切换(从低特权堆栈切换到高特权堆栈),则必须把TSS准备好。
5. 高特权级到低特权级,必须用retf指令