特权级和调用门

转自:http://blog.csdn.net/wjwbin1986/article/details/6144058

           http://1025250620.iteye.com/blog/1175568

在IA32的分段机制中,总共有4个特权级别,从高到低分别是0、1、2、3。处理器通过识别下面3中特权级进行特权级检验

1.CPL(Current Privilege Level)CPL是当前执行的程序或者任务的特权级,它被存储在CS和SS的第0位和第1位上,通常情况下,CPL等于代码所在的段的特权级,但是有一个例外是如果在遇到一致代码段时,当处理器访问一个与CPL特权级不同的代码段时,CPL不会发生改变。

什么是一致码段呢?它其实是由段描述符数据结构中的属性字段决定的,“一致”的意思是当转移的目标是一个特权级更高的代码段时,当前的特权级会被延续下去,而向特权级更高的非一致代码段转移会引起常规保护错误,除非使用调用们或者任务门。而当目标代码段的特权级低的话,无论它是不是一致代码段,都不能通过call或者jmp转移进去。另外所以的数据段都是非一致的,这意味着不可能被低特权级的代码访问到,然而,与代码段不同的是,数据段可以被更高特权级的代码段访问,而不需要特定的门。

2.DPL(Descriptor Privilege Level) DPL表示段或者门的特权级,它被存储在段描述符或者门描述符的DPL字段中,当当前代码段试图访问一个段或者门时,DPL将会和CPL以及段或者门选择自的RPL相比较。DPL的比较分下面5种情况:

  • 数据段:DPL规定了可以访问此段的最低特权级
  • 非一致代码段(不使用调用门情况下):DPL规定了访问此段的特权级
  • 调用门:DPL规定了当前执行的程序或者任务可以访问此调用门的最低特权级(这个和数据段的规则是一致的)
  • 一致代码段和通过调用门访问的非一致代码段:DPL规定了可以访问此段的最高特权级
  • TSS:DPL规定了可以访问此TSS的最低特权级

3.RPL(Requested Privilege Level) RPL是通过段选择子的第0位和第1位表示出来的。处理器通过检查RPL和CPL来确认一个访问请求是否合法。

所以对数据段的访问比较简单,就是检验特权级,只要CPL和RPL都小于被访问的数据段的DPL就可以了

对程序段的访问比较复杂,程序从一个代码转移到另外一个代码之前,目标代码段的选择子会被加载到cs中,作为加载的一部分,处理器将检查描述符的界限、类型、特权级的内容。如果检验成功,cs将会被加载。

使用jmp或者call指令可以实现下列4种转移:

  • 目标操作数包含目标代码段的段选择子(直接转移)
  • 目标操作数指向一个包含目标代码段选择子的调用门描述符(间接转移)
  • 目标操作数指向一个包含目标代码段选择子的TSS(间接转移)
  • 目标操作数指向一个任务门,这个任务门指向一个包含目标代码段选择子的TSS(间接转移)

调用门:什么是调用门,它也是一种描述符,它的结构定义如下:

; 门

; usage: Gate Selector, Offset, DCount, Attr

;        Selector:  dw

;        Offset:    dd

;        DCount:    db

;        Attr:      db

%macro Gate 4

dw (%2 & 0FFFFh); 偏移 1(2 字节)

dw %1; 选择子(2 字节)

dw (%3 & 1Fh) | ((%4 << 8) & 0FF00h) ; 属性(2 字节)

dw ((%2 >> 16) & 0FFFFh); 偏移 2(2 字节)

%endmacro ; 共 8 字节

和段描述符的6个字节结构不一样,门是由8字节构成,这个描述符也是放置在GDT,LDT或者IDT中以供调用。门描述符分为4种:

  • 调用门
  • 中断门
  • 陷阱门
  • 任务门

门调用其实就是提供了一个入口地址,它可以实现的是不同特权级的代码之间的转移。下面介绍一下具体的过程:

假设我们想由代码A转移到代码B,运用一个调用门G,即调用门G中的目标选择子指向代码B的段,我们涉及这么几个要素:CPL、RPL、代码B的DPL(DPL_B)和调用门的DPL(DPL_G)。根据门调用的规则,A要调用G,则A的CPL和RPL要小于DPL_G,另外还要比较CPL和DPL_B,如果是一致代码段的话,要求DPL_B小于等于CPL,如果是非一致代码段的话,call指令要求DPL_B小于等于CPL,jmp指令要求DPL_B=CPL。

这里我不是特别清楚,可能是如果没有通过门调用,会直接比较RPL和DPL_B,因此门调用能够实现从低特权级到高特权级的转移。

TSS介绍:在进行call和jmp时候,必然要使用堆栈,然而由于不同的特权级会使用不同的堆栈,因此一个任务最多可能有4个堆栈,那么当转移指令在不同特权级之间变化的时候,压入堆栈的内容在另外一个特权级里面已经不是原来的堆栈了,对于这个问题,就引出了TSS(Task-State Stack)这个数据结构。这个数据结构中存在着ss2、esp2;ss1、esp1;ss0、esp0,转移过程如下:

  1. 根据目标代码的DPL从TSS中选择应该切换至哪个ss和esp
  2. 从TSS中读取新的ss和esp
  3. 暂时性地保存当前的ss和esp的值
  4. 加载新的ss和esp
  5. 将刚刚保存起来的ss和esp的值压入新栈
  6. 将当前的cs和eip压栈
  7. 加载调用门中指定的新的cs和eip。

所以,从上面的过程中我们可以知道,在进行特权级转移时,首先根据目标代码的DPL从TSS中取得对应的ss和esp,然后加载新的ss和esp,也就是使用新的堆栈,并把老的堆栈的信息压入新栈,以便返回时使用,然后再进行转移

 

 

 

下面说明代码段和数据段的访问:


一、代码段间跳转


1、普通(直接)跳转:

JMP Selector:0 或 CALL Selector:0

1)一致代码段(JMP&CALL)

要求:CPL>=DPL,RPL不作检查

特权变化:跳转后程序CPL=跳转前程序CPL

2)非一致代码段(JMP&CALL)

要求:CPL=DPL & RPL<=DPL

特权变化:跳转后程序CPL=目标代码段DPL


2、通过调用门跳转:

JMP 调用门Selector:0 或 CALL 调用门Selector:0 (注意:此时如果选择子后面跟着32位偏移量也不会被CPU使用,因为调用门描述符已经记录了目标代码的偏移)


step1: 要求:指示调用门的选择子的RPL<=门描述符DPL & 当前代码段的CPL<=门描述符的DPL。


只有满足以上条件时,CPU才会进一步从调用门描述符中读取代码段的选择子或地址偏移。而从调用门中读取代码选择子和地址偏移后,跟普通跳转又站在同一起跑线上了。

唯一不同的是CPU会将目标代码段RPL清0。此后需要分类讨论,如下:


step2:

1)一致代码段(JMP&CALL)  <------------------------------------------------------------------------------------------------------

要求:CPL>=DPL,RPL不作检查(因为RPL总被清0)                                                        |

特权变化:跳转后程序CPL=跳转前程序CPL                                                                        |

                                                                                                                                             比较

2)非一致代码段(JMP)                                                                                                                |

要求:CPL=DPL,RPL不作检查(因为RPL总被清0)                                                          |

特权变化:跳转后程序CPL=目标代码段DPL                                                                        |

3)非一致代码段(CALL)  <------------------------------------------------------------------------------------------------------------

要求:CPL>=DPL,RPL不作检查(因为RPL总被清0)

特权变化:跳转后程序CPL=目标代码段DPL(CPL>DPL的情况下,特权级发生跃迁)


二、访问数据段

数据段:特权级低->高:NO | 特权级高->低:YES | 特权级同级之间:YES


注意:

1、一致代码段:无论那种方式跳转到一致代码段,CPL都不会改变(不变化为目标代码段的DPL),也即加载目标代码段选择子时,只加载高14位,表示CPL的低2位保持不变。

因此,“一致”的意思就是——代码段被调用执行时,不使用自己描述符的DPL,而采用调用这特权级,CS的低2位保持不变(与“调用者保持一致”)

2、非一致代码段:无论采用哪种方式跳转到非一致代码段,CPL都发生变化,也即在加载目标代码段选择子时,将整个选择子放入到CS中。

3、为了访问调用门,调用者程序的特权级CPL必须小于或等于调用门的DPL。调用门段选择符的RPL也要同调用CPL一样遵守相同的规则,即RPL也必须小于或等于调用门的DPL

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值