x86架构中的保护模式

来源:互联网 发布:多级审批数据库设计 编辑:程序博客网 时间:2024/05/29 11:46

        在x86架构中所谓保护模式其实就是段的存储方式能够达到一种保护机制。也正因为有了保护模式(段的存储方式)所以才会有特权模式,以及后面的多任务之说;

        在实模式下段的存储很简单,就是代表一个段基地址;如:ds(ds=0x7c00),那么数据段的基地址就是0x7c00;再比如:ds:ax(ds=0x0000;ax=0x7c00)那么段基地址就是0x00;线性地址(物理地址)就是:(ds * 16) + ax;在实模式下给段基地址赋值也非常简单,直接用通用寄存器赋值实际物理基地址就可以。如:mov ax , 0x7c00;mov ds , ax;就可以了;

        在保护模式下段地址却没有那么单纯了,他是有全局描述符表来提供的(其实可以认为是多级存储段地址);在保护模式下所有段地址都是集中在全局描述符表中定义的(忘记说明下,在保护模式下地址也是以段为基础的,这是他的兼容性;当然也可以把所有的地址都当作一个段,这就叫内存的平坦模式);当你想引用某个段时,比如:mov ds , ax ;ax则不再是地址了,而是一个选择子,一个索引号,表示该段在全局描述符表中的第几个位置;最后由处理器找到这个位置,然后把该位置下的段描述符加载到ds中去。

        ------------------------------------------------------------------------全局描述符格式--------------------------------------------------------------------------------------

        全局描述符表GDT(global descriptor table)是有多个全局段描述符构成的,可以定义在随意位置(最好定义在地址空间1MB内,因为首先要有实模式下进入保护模式,而在实模式下所能查找的地址只有20位,也即是1MB);下面是全局段描述符格式(一直说全局描述符,是因为有与其相对应的局部描述符LDT):

        

        下面32位是低地址,上面32位是高地址;大概说明下各个字段表示的意思:

        段基地址:分三部分,0~15的,0~23的,0~31的,这代表了x86中的三个不同寻址位数(现在处理器有64位的),32位寻址可以有4GB内存地址了;

        段界限:分两部分,0~15的,0~19的,其实低32位是实模式下的寻址范围;这让我想起了实模式下两种地址划分:第一种,段基地址为0x0000,0x0010,0x0020,0x0030(16字节对齐)......而偏移量则只有0~15;第二种,以偏移量为中心,0x0000~0xFFFF,每个段都是64kb;

        高地址23位的G:表示粒度,为1,则表示以4kb为单位;为0,则表示以字节为单位;

       D/B:对代码段用D,若D为0,则表示是16位的保护模式(几乎没有这种模式了),用IP;若D为1,则表示是32位保护模式,用EIP;对堆栈用B,若B为0,则用SP;为1则用ESP;

        L:表示64位的;AVL是软件使用位,不讨论;

        P:表示这个段是否在内存中存在(1表示存在),这个位一般用在虚拟内存中;这个位可以用来做段的访问量统计,首先把该段的P位置零,然后当处理器访问该段时,产生一个缺页中断,处理器去处理中断程序,在中断程序中进行统计,最后中断程序还会把该段内容交换会内存;

        DPL:特权模式,这是个非常重要的字段,有4种模式(00 01 10 11 == 0 1 2 3),其中0是特权最高的,一般为操作系统程序的特权,3最低的,一般给用户程序;

        S:当为0时,表示该描述符是一个系统段的描述符(GDT,LDT,还有任务段等等);为1时,则表示该描述符是个普通段的描述符(数据段ds,代码段cs,堆栈段ss等等);

        TYPE:该段的读写类型;对于数据段(堆栈段也是特殊的数据段)来说,这四位分别为:X E W A(执行,扩展方向,写,已访问)。扩展方向,是向高地址扩展还是低地址扩展;对数据段来说一定是可以读的(默认是可读的);对代码段来说,四位分别为:X C R A(执行,依从,读,已访问),其他位好理解,依从则是表示是否能从不同特权级之间切换,为0表示不依从,则只能从同等特权之间切换,为1,则可以在不同特权之间切换,但是当前特权会依从目标特权;对于代码段来说一定要可以执行的;所以当把描述符加载到数据段中时,是没有什么限制的,但第二、三位会当作E W;当加载到CS中时会检查是否可执行,第一位是否为1;

        上面就是段描述符格式字段了,有了这些格式字段,想定义段描述符就简单了,先定义一个代码段试试,低32位:0x7c000000,高32位:0x00409800;

        ----------------------------------------------------------------------------GDTR操作-------------------------------------------------------------------------------------

        定义好这些段描述符表,然后要加载到处理器指定的地方,以便加载段时,处理器知道该往哪里去寻址;处理器指定的地方就是全局描述符寄存器GDTR,GDTR有48位,其中低16位是界限值(全局描述符表减一,因为偏移量是从零开始的),高32位是全局描述符表的基地址;由界限值可以知道能定义最多多少个段描述符,2^16 = 64KB,而每一个段描述符是8个字节,所有64KB/8B = 8K个;

 

        还有两个操作GDTR命令,把全局描述符表加载到GDTR中,用lgdt 偏移量:全局描述符表基地址;把GDTR中的内容加载到指定位置,sgdt指定位置;(一般是先用sgdt加载到指定位置,然后修改下,最后再用lgdt加载回GDTR中去);

        -----------------------------------------------------------------------------选择子---------------------------------------------------------------------------------------------

        前面已经说了,在保护模式下加载段不是加载地址而是加载选择子,那么什么是选择子?请看下面选择子格式:

        

        这就是段选择子了,共有16位(这样才能由通用寄存器来加载)。

        RPL字段是请求特权,这个有点复杂,简单的解释下:比如处理器是运行在代码段中,那么当前特权级(CPL)就是该代码段的描述符中的DPL;当处理器需要调用某个例程或者转移到另外的程序(不同段)中去执行,那么就要加载段选择子了,而这时候段选择子中的RPL就是请求特权级,表示运行程序的特权级当前特权级CPL。一般来说RPL会等于当前特权级;但有些特例,是当用户程序调用内核例程时,CPL为内核特权级0,而请求特权级则还是为用户特权级3。

        TI字段:表示处理器应该去GDTR中找段描述符还是LDTR中,若TI为0,则表示是全局描述符表中查找,否则是局部描述符中查找;

        描述符索引号:选择子共16位,RPL占2位,TI占一位,那么索引号只有13位了,所能查找的描述符为2^13 = 8k 个,和上面GDTR操作中界限值分析的个数一样;

        -----------------------------------------------------------------------段寄存器------------------------------------------------------------------------------------

        在保护模式下段寄存器和实模式下的完全不一样,在保护模式下的段寄存器其实是有80位的(实模式下真真切切只有16位),但是有64是隐藏的,只有处理器可以访问和加载,高16位才是我们可以操作的。存放的内容也不一样,实模式下存放的是地址,而保护模式下存放的是段选择子;保护模式下段寄存器格式见下图:

        

        --------------------------------------------------------------------处理器加载段过程---------------------------------------------------------------------------

        保护模式下的段加载过程如下图所示:

     

        当然里面还有各种检查机制没有体现,当引用一个段是,处理器会把GDT中的描述符加载到段寄存器中隐藏的64位中,这是第一次加载到段寄存器。以后如果要使用该段内容,则直接从段寄存器中隐藏部分获取基地址和检查的段界限(这是由处理器固件操作的)。

        -----------------------------------------------------------------------------段描述符加载检查---------------------------------------------------------------------

        第一、指定的描述符索引号是否超出了界限值,由选择子中的索引号和GDTR中的界限值比较,超出则报中断错误;

        第二、如果选择子中TI指定为0,则表示不能加载0号描述符,cs一定禁止加载GDT中0号描述符,其他段寄存器可以加载,但使用时会报中断错误;

        第三、检查描述符中P位是否为1,表示该段是否在内存中;

        第四、检查段描述符的属性和段寄存器是否匹配,如下图:

        

        看上图可以得出结论:cs中的段一定要可执行的,其他的段只要是可读就可以(SS特殊点,必须要可读可写);

        保护模式下的基础知识基本就这些了,后面还有特权级,多任务等等。上面除了加载寄存器流程图外,其他的图都是来自于《x86汇编语言--从实模式到保护模式》

         转载请注明作者和原文出处,原文地址:http://blog.csdn.net/yuzhihui_no1/article/details/42386915

        

0 0
原创粉丝点击