80x86的保护
1段级保护
包括以下几种方式 :
1.1 段界限检查
段描述符中的段限长字段用于防止程序或过程寻址到段外内存位置。段限长的有效值依赖于颗粒度G标志的设置状态。
1.2 段类型TYPE检查
1.3特权级检查
段保护机制提供了四种特权级,0级到3级。
特权级有以下三种:
1.3.1 当前特权级 CPL CPL是当
前正在执行程序或任务的特权级。它存
放在CS活着SS段寄存器中位0和位1中。 通常CPL等于当前代码段的特权级。当程序把控制转移到
另一个具有不同特权级的代码段中时,处理器就会改变CPL。
当访问一个一致代码段的时候,处理器对CPL的设置有所不同,特权级高于或等于一致代码段DPL的任何段都可以访问一致代码段,并且当处理器访问一个
特权级不同于CPL的一致代码段时,CPL不会修改成一致代码段的DPL 。
1.3.2 描述符特权级 DPL
DPL是一个段或者门的特权级,它
存放在段或门的DPL字段中。当执行代码段试图访问一个段或者门的时候,段或者门DPL就会于
CPL以及短或者门选择符中的RPL相比较。 根据被访问的段或者门的类型不同,DPL也有不同的含义。
(1) 数据段
其DPL指出允许访问本程序段的程序或任务应具有的最大特权级数值。例如,如果数据段的特权级DPL是1,那么只有运行在CPL为0或者1的
程序,才可以访问这个段。
(2) 非一致代码段
其DPL指出程序或者任务访问该段必须具有的特权级。 例如如果某个非一致代码段的DPL为0 ,那么就只有运行在CPL为0 的程序能够访问这个段。
(3) 调用门
与数据段的访问规则相同。
(4) 一致和非一致代码段(通过调用门访问)
DPL指示允许代码段的程序或者任务应该具有的最小特权级数值。如果一致代码段的DPL是2,那么CPL为0的程序段就不能访问。
(5) 任务状态段 TSS
其DPL指出访问TSS的当前执行程序或任务可处于的最大特权级。与数据段访问规则相同。
1.3.3 请求特权级 RPL
RPL是一种赋予段选择符的超越特权级,它存放在选择符的位0或者位1中。处理器会同时检查RPL或者CPL 。以确定是否允许访问一个段。
始终取RPL或者CPL之间数值最大的特权级作为访问段时的最大比较对象。
2 访问数据段时的特权级检查
为了访问数据段中的操作数,数据段中的段选择符,必须加载进数据段寄存器中或者堆栈段寄存器中。在把一个段选择符加载进段寄存器中之前,
处理器就会进行特权级检查。
它会把当前的段描述符的DPL与 当前段选择符的RPL 和任务的CPL 进行比较,只有DPL大于或者等于 CPL或者RPL 时,CPU才会把选择符加载进段寄存器。
3 代码段之间的转移控制时的特权级检查
当程序的控制权从一个代码段移到另一个代码段中时,目标代码段的段选择符必须加载进代码段寄存器,作为这个加载过程的一部分,处理器会检测目标代码段的段描述符,并执行各种安全的检测。如果这些检查都通过了,那么CPU就会把目标代码段的选择符加载进段寄存器,于是程序的控制权就被转移到新的代码段中。
JMP CALL 指令可以利用以下四种方法来引用另外一个代码段:
(1) 目标操作数含有目标代码段的段选择符。
(2)目标操作数指向一个调用门描述符,该描述符含有目标代码段的选择符。
(3) 目标操作数指向一个TSS ,而该TSS中含有目标代码段的选择符 。
(4) 目标操作数指向一个任务门,该任务指向一个TSS ,该TSS中含有目标代码段的选择符。
3.1 当不通过门调用把程序控制权转移到另一个代码段时,程序会进行以下四种特权级和类型信息。
目的代码段中的一致性标志C, 它确定了一个代码段是非一致代码段还是一致代码段。
当C==0 ,即为非一致代码段,则调用者的CPL必须等于目的代码段的DPL ,RPL 则作用不大。RPL在数值上必须小于或者等于调用者的CPL才能使它的
控制转移成功。 当非一致代码的段选择符被加载进CS寄存器中时,特权级字段并不会改变,它仍然是调用者的CPL ,即使段选择符的RPL与CPL不同,但是
仍然是正确的。
当C == 1 时,即访问一致代码段的时候,CPL必须在数值上大于或者等于目的代码段的DPL,CPU忽略对RPL的检查。对于一致代码段,DPL表示调用者对代码段进行成功调用可以处于的最低数值特权级。
大多数代码段都是非一致代码段,这样代码段只能转移到相同特权级的代码段上,除非转移是通过一个调用门来进行的。
4 门描述符
为了对不同特权级的代码段进行受控的访问,处理器提供了称为门描述符的特殊描述符集。
有以下四种门描述符:
(1) 调用门 TYPE = 12
(2) 陷阱门 TYPE = 15
(3) 中断门 TYPE = 14
(4) 任务门 TYPE = 5 。
当CPU访问调用门时,它会使用调用门的段选择符来定位目的代码段的段描述符,然后CPU会把代码段描述符的基地址与调用门中的偏移值进行组合。
形成代码段中指定程序的入口点的线性地址。
通过调用门进行程序控制转移的时候,CPU会对4种不同的特权级进行检查。
(1)当前特权级CPL 。
(2) 调用门描述符的请求特权级RPL 。
(3) 调用门描述符特权级DPL 。
(4) 目的代码段描述符中的DPL。
(5)目的代码段描述符的DPL 。
5 栈的切换
每当调用门用于把程序控制转移到一个更高级别的非一致代码段时,CPU会自动切换到目的代码段特权级的堆栈去。
执行堆栈切换的目的是为了,防止高级特权程序由于堆栈空间不足而引起的崩溃。 同时也为了防止低特权级程序,通过共享堆栈
而干扰高特权级程序。
每个任务最多定义4个堆栈,一个运行在特权级3的应用程序代码,其他分别运行在特权级0,1,2上。
5.1堆栈的具体切换
当特权级3的程序在执行时,特权级3的堆栈的段选择符和栈指针会被存放在SS和ESP中,并且在发生堆栈切换时保存在被调用过程的堆栈上。
而特权级0、1和2 的堆栈的初始指针都存放在当前运行任务的TSS段中,TSS段中这些指针都是只读值。当调用更高特权级的时候,CPU才会
使用它们建立新的堆栈。 当从调用过程返回时,相应的栈就不存在了,下一次调用该过程的时候,就会再次使用TSS中的初始指针建立一个
新栈。
OS需要负责为所有用到的特权级建立堆栈和堆栈段描述符,并且在任务的TSS中设置初始指针值。
当通过一个过程调用其他过程时而造成的特权级改变的时候,CPU会执行以下步骤进行切换操作,并开始在新的特权级上执行调用过程。
(1) 使用目的代码段的DPL从TSS中选择新栈的指针,从当前的TSS中读取新栈的段选择符和栈指针。
(2) 检查栈段描述符特权级和类型是否有效 ,若无效则产生一个无效的TSS 。
(3) 临时保存SS和ESP寄存器的当前值,把新栈的段选择符和栈指针加载到SS中和ESP中。然后把临时保存的SS和ESP压入到新栈中。
(4) 把调用门中描述符中指定参数个数的参数从调用过程栈复制到新栈中。
(5) 把返回指令指针压入(即当前CS和EIP内容) 压入新栈。把新代码段选择符加载到CS中,同时把调用门中偏移值加载到EIP中。最后开始执行
被调用的过程。
5.2 从被调用过程返回
指令RET用于执行近返回、同特权级远返回、不同特权级远返回。
当执行远返回到一个调用过程时,CPU会执行以下步骤:
(1) 检查保存的CS寄存器中RPL字段,以确定在返回时特权级是否需要改变。
(2) 弹出并使用被调用过程堆栈上的值加载CS和EIP寄存器
6 页级保护
页目录和页表项中的读写标志R/W和用户/超级用户标志U/S提供了分段机制保护属性的一个子集。
超级用户级为 特权级 0 , 1 , 2 。
普通用户级为 特权级 3 。
6.1 页转换高速缓冲 TLB
为了避免每次内存访问都要访问驻留在内存中的页表,最近使用到的线性地址到物理地址的转换信息被保存在处理器内的
页转换高速缓冲中。只有当前需要的转换信息不在高速缓存时,才会访问内存中的页表。
6.2 组合页级别和段级保护
当启用了分页机制,CPU会首先执行段级保护,然后再处页级保护。