不打算按别人的思路来,因为在我学的过程中上网查,发现网上的博客都是互相抄的,最终还是抄书的。
Intel 64 和 IA-32架构处理器在进入保护模式之后,就会有一些列保护机制。其中出现了三个特别重要的东西:CPL、DPL、RPL。
CPL表示当前正在执行程序的特权级,它保存在cs段寄存器里面;
DPL表示某个段的特权级,保存在这个段对应的段描述符中;
RPL表示请求访问特权级,保存在选择子中(表示程序希望通过这个级别的特权级区访问另一个段)。
所谓的特权级一共有4个,ring0,ring1,ring2,ring3,数字越小,特权级越高。对于数据段和代码段的访问都要满足特权级规则。
对于数据段(数据段都是非一致的),只允许高特权级访低特权级,或者同级之间访问,不允许低特权级程序访问高特权级数据段;
对于一致代码段,只允许低特权级访问高特权级代码段,或者同级访问;
对于非一致代码段,只允许同一特权级访问。
(这里的一致不一致大致是指这个代码段在系统中是否是拿出来共享的,也就是描述符中的一位,不必特别在意,因为大部分段都是非一致的)
我们用Intel手册中的例子来说:
在这里面代码段C是非一致代码段,D是一致代码段。代码段A能够访问到代码段C,因为它们处在同一个特权级,使用的选择子的RPL也是2;
代码段B就不能访问C,因为它的特权级比C要低;但是它却可以访问D,因为D是一致代码段,只能被低特权级的程序访问。
大致就是这么一个过程,我们现在正在执行某一个代码段的程序,我们的CPL一般就等于这个代码段的DPL,然后我们忽然想要访问另外一个段,则在保护模式下,我们必须使用一个叫段选择子的东西去访问另一个段,而这个选择子又包含一个RPL,它相当于我们给出一张一卡通,用这张一卡通去访问目标段,看看这个一卡通能不能满足目标段的DPL要求。
我们在访问代码段的过程中,我们的特权级也可能发生变化,每当我们的特权级CPL发生变化,处理器就要求我们切换堆栈,所以一个程序按道理需要配上4个备用堆栈,但是实际上如果我们能保证我们不会用到某个特权级,就可以不设对应的堆栈,例如在linux里面,只用到了ring0和ring3,则就不需要设置特权级为1和2的堆栈,关于怎么设置堆栈,下面等一下在讲。
现在我们先说说特权级切换,我打算先从ring0切换到ring2,在从ring2切换到ring0。但是我们知道,非一致代码段是不能从低特权级切换到高特权级的,这里我们