我们在工作中,公司都给员工配有员工卡,此员工卡就是员工身份的“标签”,用它来出入公司、食堂就餐等。给公司创造价值的是员工的生产力,不是员工卡,员工卡只是公司人事部门管理员工的一种手段而已。
现在说计算机,既然是用特权级来维护计算机世界的和平,那总该给每个被管理的对象加个特权“标签”,也就是说cpu得知道谁的特权高谁的特权低,这样才能辨识出是否有低特权级的程序越级访问高特权级资源的违法行为。
员工的标签体现在工卡,计算机特权级的标签体现DPL,CPL和RPL,下面咱们围绕这几个概念展开讨论。
先看看访问者的特权标签在哪里。
最初我们刚接触保护模式的时候,最先感受到的区别是,访问内存不像在实模式下那么自由、直接啦,在保护模式下有了段描述符,访问内存得先经过它才行,它的作用是通过各种属性描述一段内存区域,该描述符就相当该内存区域的“身份证”。
前情提要,x86访问内存的机制是“段基址:偏移地址”,无论是实模式还是保护模式,都要遵循此方式。在实模式下,段基址直接写在段寄存器中,而在保护模式下,段寄存器中的不再是段基址,而是段选择子,通过该选择子从GDT或LDT中找到相应的段描述符,从该描述符中获取段的起始地址。大伙儿还记得选择子的结构吧,第0~1位是RPL字段,第2位是TI位,第3~15位是段描述符索引,好啦,回忆到此为止。咱们要关注的就是RPL字段,它就是请求特权级,后面讲RPL的时候咱们会细说。请求特权级中的“请求”是个动词,只有具备“能动性”的访问者才能做出动作。
话说回来了,谁是访问者?计算机中,具备“能动性”的只有计算机指令,只有指令才具备访问、请求其它资源的能力,指令便是资源的请求者。指令“请求”、“访问”其它资源的能力等级便称之为请求特权级,指令是存放在代码段中,所以,就用代码段寄存器CS中选择子的RPL位表示代码请求别人资源能力的等级。代码段寄存器CS和指令指针寄存器EIP中指向的指令便是当前在处理器中正在运行的代码,所以,位于CS寄存器中选择子低2位的值不仅称为请求特权级,又称为处理器的当前特权级,也就是说处理器的当前特权级是CS.RPL。
处理器的当前特权级的真实面目是什么?
在cpu运行的是指令,其运行过程中的指令总会属于某个代码段,该代码段的特权级(也就是代码段描述符中的DPL)便是当前cpu所处的特权级,这个特权级称为当前特权级,即CPL(Current Privilege Level),它表示处理器正在执行的代码的特权级别。除一致性代码段外(后面会说),转移后的目标代码据段的DPL是将来处理器的当前特权级CPL。
指令最终是用处理器执行的,执行到不同特权的代码,处理器的特权级就换到不同的等级。所以,当前特权级实际上是指处理器当前所处的特权级,是指处理器的特权角色,更形象一点地说,是指cpu当前在计算机世界中的特权地位。再次提醒大伙儿,在任意时刻,当前特权级CPL保存在CS中选择子中的RPL部分。
当前特权级是存储在CS.RPL中,谁为代码段寄存器CS赋值的呢? 要回答上面的问题,得先搞清楚处理器的当前特权级为什么会变化。
当前正在运行的代码所在的代码段的特权级DPL就是处理器的当前特权级,当处理器从一个特权级的代码段转移到另一个特权级的代码段上执行时,由于两个代码段的特权级不一样,处理器当前的特权身份起了变化,这就是当前特权级CPL改变的原因。好像说的有点神秘,其实就是使用了那些能够改变程序执行流的指令如int、call等,这样就使CS和EIP的值改变,从而使处理器执行到了不同特权级的代码。不过,特权转移可不是随便进行的,处理器要检查特权变换的条件,这里咱们暂不讨论条件是什么,因为它需要过会儿结合RPL一块说,等小弟把RPL给大伙儿说清楚了再解释这个“条件”不迟。当处理器特权级检查的条件通过后,新代码段的DPL就变成了处理器的CPL,也就是目标代码段描述符的DPL将保存在代码段寄存器CS中的RPL位。
总之,代码是资源的请求者,代码段寄存器CS所指向的是处理器中当前运行的指令,所以代码段寄存器CS中选择子的RPL位称为当前特权级CPL,这是再合理不过的事了。
RPL变成了CPL,似乎有点晕是吗?其实只是代码段寄存器CS中的RPL是CPL,其它段寄存器中选择子的RPL与CPL无关,因为CPL是针对具有“能动性”的访问者(执行者)来说的,代码是执行者,它表示访问的请求者,所以CPL只存放在代码段寄存器CS中低2位的RPL中。
以上几段内容想表达的就是处理器的当前特权级CPL为什么放在CS.RPL中,CPL和CS.RPL有什么关系,不信您再回头看一遍^_^。
大多数情况下,处理器都是在“访问者”访问“受访者”时进行特权检查,访问者(某个代码段)的特权就是当前特权级CPL,在进行特权检查时,都会以CPL为基础,说到这里,不禁我要自问一下,既然CPL就是目标代码段的DPL,那处理器总该有个初始CPL吧。答案是肯定的,特权级是保护模式下的概念,处理器进入保护模式后才有的当前特权级,让我们回忆下处理器是怎么进入保护模式的,也许答案自然就揭晓啦。
在这之前,我和大家说过,MBR从BIOS接过接力棒的时候,它已经处于0特权级啦,其实这么说不太合适,毕竟在保护模式下才有特权级,而MBR是运行在实模式下,还谈不上特权级。BIOS将控制权交给MBR,是用一个远跳转指令实现的,即jmp 0:0x7c00,也就是说进入MBR后,段寄存器CS会被替换为0,如果此时把CS看作是选择子的话,RPL的值为0,也就是说“相当于”处于0特权级,段寄存器CS为0的情况一直持续到在loader中进入保护模式之后的第一条指令:流水线刷新跳转。该跳转语句如图