天天看点

80x86 cpu的保护模式

转贴 80x86 cpu的保护模式

对于学习任何编程语言的朋友来说掌握CPU的操作模式都是一件非常重要的事,其中就数保护模式这部分最重要了,现在关于保护模式的中文资料就只有杨季文先生那一家还算全面,但有些人还是觉得看不太懂,为此我就写了这篇文章,看看是否对您的胃口!

一、保护模式概述

        顾名思义,就是对程序的运行加以保护。我们知道在实模式下通常只能寻址1M的内存空间,且只能是单任务,就是说同一时间不能有两个任务被激活。从8086/8088的20根地址线,80286的24根地址线到80386的32根地址线,直至今天Puntium4已经发展到了36根地址线,它们分别可以寻址1M、16M、4G、64G的内存空间,然而在实模式下,通常的寻址范围还是1M。也就是对于在纯DOS下运行的Puntium4也只能是一个快速的8086。

        前面已经说了,保护模式就是对程序的运行加以保护,所以说保护模式较实模式的增强的最主要体现还不是寻址能力而是对多任务的支持,所提到的保护就是对不同任务间和同一任务内的程序加以保护,使它们的运行不受对方“有意”或“无意”影响,但同时也要对两个任务都要用到的部分代码实现共享。另外一个重要的增强就是对虚拟存储器的支持,从一定意义上说可以使程序设计人员不必考虑物理内存的大小。

 有了新的模式,当然要有大量的新增寄存器的支持,学习这些寄存器也是学习保护模式的关键.

三个重要的系统表GDT、LDT和IDT

 首先说明的是,这三个表是在内存中由操作系统或系统程序员所建,并不是固化在哪里,所以从理论上是可以被读写的。

 这三个表都是描述符表.描述符表是由若干个描述符组成,每个描述符占用8个字节的内存空间,每个描述符表内最多可以有8129个描述符.描述符是描述一个段的大小,地址及各种状态的.描述符表有三种,分别为全局描述符表GDT、局部描述符表LDT和中断描述符表IDT。

 1.全局描述符表GDT:

 全局描述符表在系统中只能有一个,且可以被每一个任务所共享.任何描述符都可以放在GDT中,但中断门和陷阱门放在GDT中是不会起作用的.能被多个任务共享的内存区就是通过GDT完成的,

 2.局部描述符表LDT:

 局部描述符表在系统中可以有多个,通常情况下是与任务的数量保持对等,但任务可以没有局部描述符表.任务间不相干的部分也是通过LDT实现的.这里涉及到地址映射的问题.和GDT一样,中断门和陷阱门放在LDT中是不会起作用的.

 3.中断描述符表IDT:

 和GDT一样,中断描述符表在系统最多只能有一个,中断描述符表内可以存放256个描述符,分别对应256个中断.因为每个描述符占用8个字节,所以IDT的长度可达2K.中断描述符表中可以有任务门、中断门、陷阱门三个门描述符,其它的描述符在中断描述符表中无意义。

段选择子

在保护模式下,段寄存器的内容已不是段值,而称其为选择子.该选择子指示描述符在上面这三个表中的位置,所以说选择子即是索引值.

描述符

 前面已经提到,描述符是描述一个段的大小,地址及各种状态的8个字节的结构,在编程时它可以定义它.

   根据描述符所描述对象的不同,描述符可分为存储段描述符、系统段描述符、门描述符三种,而门描述符又可分为调用门、任务门、中断门和陷阱门四类。下面将分别介绍各描述符作用及其各位的意义:

 一、存储段描述符

 存储段描述符是描述程序中的代码段和数据段的,这其中也包括堆栈段,在保护模式下,应该把堆栈段理解为特殊的数据段。

 分析存储段描述符时应该把它分成4个域来理解:

第一个域为描述符的第0至1字节,该字是段界线的低16位,段界线是描述段的大小共20位,高4位在第六字节的低4位中;第二个域为描述符的第2至4字节,这三个字节是段基址的低24位;第三个域是描述符的第5、6字节,该字存放的是段的一些属性;第四个域是最后一个字节,该字节存放的是段基址的高8位。下面对属性字的每一位进行描述:

 P位说明所描述的段是否存在,P=1表示描述符所描述的段存在于内存中,P=0表示描述符所描述的段不在内存中。

 DPL为描述符所描述段的特权级,只有有效特权级EPL大于等于DPL时,才能对段进行访问。

 DT位必有为1以区别于系统段描述符。

 TYPE字段:

 位0表示被描述的段是否被访问过,该位为0表示未被访问过,为1则表示该段先前已经被访问过。

 位1的定义在于描述符所描述段的类型。当所描述的是代码段时,该位指示所描述的代码段是否可读,为1则可读,为0则不可读;当所描述的是数据段时,该位指示所描述的数据段是否可写,为1则可写,为0则不可写。

 位2的定义也在于描述符所描述段的类型。当所描述的是代码段时,该位指示所描述的代码段是否是一至代码段,为1表示该代码段是一至代码段,为0表示该代码段不是一至代码段,即是普通的代码段。当所描述的是数据段时,该位指示该段的扩展方向,为1时表示该段向低地址扩展,为0时表示该段向高地址扩展。

 位3指示所描述的段类型,为1表示所描述的段是代码段,是可以被执行的,为0表示所描述的段是数据段,是不能被执行的。前面已经说了,在保护模式下应该把堆栈段理解为特殊的数据段,为0时也包括堆栈段。

 G位表示段界限的计数单位,该位为0时表示段界限以字节为单位,为1时表示以4K为单位。这样计算下来,20位的段界限就可以描述大小为64K或4G的段了,

 D位说明描述符所描述的段是32位环境还是16位的环境。该决定了指令所使用的操作数以及地址的默认大小,为1时说明是32位地址和32位操作数,即32位段;为0时说明是16位地址和16位操作数,即是16位段。但这时仍可使用操作数及地址大小前缀来改变这种默认设置。该位还决定了系统是使用IP还是EIP,使用SP还是ESP

 二、系统段描述符

 系统段描述符是描述两个特殊的段,它们分别为局部描述符表LDT段和任务状态段TSS。

 从图2中可见,系统段描述符与存储段描述符的区别只在于DT位,DT=1则为存储段描述符,DT=0则为系统段描述符,两种描述符就靠此位区分.但系统段描述符的TYPE字段与存储段描述符的TYPE却截然不同.描述如下:

 TYPE字段:

 0、1两位的定义取决于位2。当位2为1时,说明是门描述符,为0时说明是非门描述符。当位2为1时,0、1两位确定门描述符的类型,因为两位可有4种状态,所以正好描述4个描述符,为0时则是调用门,为1时则是任务门,为2时则是中断门,为3时则是陷阱门;当位2为0时,低两位0位、1位为0时未定义,为1时则是可用的286的TSS,为2时则是LDT,为3时则是忙的286的TSS。

 位4为0时,如其它位也为0或低两位为2或3时则也是未定义,否则该位提示是386还是286描述符,关于段基地址和段界限为何都安排在两个分开的域中的原因也与此有关,请读者自己想想!

 三、门描述符

 从系统段描述符的说明中可以看出门描述符是靠TYPE字段与系统段描述符区分的,但从图2中可见门描述符却与系统段描述符在结构上也不一至,其实这才是区分二者关键。门描述符的第四字节的低4位为双字计数字段,该字段是说是在发生特权级变换时,把外层堆栈中的参数拷贝到内层堆栈中的数量,计数以双字为单位。