分类: LINUX
2011-03-09 19:47:24
一。地址空间类型
一。[[Anchor(NBE1)]]地址空间类型
1。虚拟地址(逻辑地址)
虚拟地址是程序中的逻辑地址,一般以段地址加偏移量方式表示,应用程序通过虚拟地址进行数据操作。
2。线性地址
操作系统所处理的地址,操作系统使用线性地址以平坦内存模式处理数据操作。
3。物理地址
数据或代码在物理内存上的地址,一般需要操作系统来规范和保证物理地址的使用。
x86的分段机制实际上是解决了虚拟地址到线性地址的转换,同样x86的分页机制实际上就是解决线性地址到物理地址的转换。其中x86中的分页机制是可选的,如果不使用分页机制,就需要保证线性地址和物理地址的一一对应。
在Linux中,实际上是通过使用一些技巧,保证了虚拟地址和线性地址的一一对应,而主要使用分页机制来实现线性地址到物理地址的转换。
二。[[Anchor(NBE2)]]x86中的控制寄存器和系统地址寄存器
80386控制寄存器和系统地址寄存器用于控制工作方式(实模式和保护模式),控制分段管理机制及分页管理机制的实施。
1。控制寄存器
80386有四个32位的控制寄存器,分别命名位CR0、CR1、CR2和CR3。但CR1被保留,供今后开发的 处理器使用,在80386中不能使用CR1,否则会引起无效指令操作异常。CR0包括指示处理器工作方式的控制位,包含启用和禁止分页管理机制的控制位, 包含控制浮点协处理器操作的控制位。CR2及CR3由分页管理机制使用。CR0中的位5—位30及CR3中的位0至位11是保留位,这些位不能是随意值, 必须为0。
控制寄存器CR0的低16位等同于80286的机器状态字MSW。
1.1CR0
控制寄存器CR0中的位0用PE标记,位31用PG标记,这两个位控制分段和分页管理机制的操作,所以把它们称为 保护控制位。PE控制分段管理机制。PE=0,处理器运行于实模式;PE=1,处理器运行于保护方式。PG控制分页管理机制。PG=0,禁用分页管理机 制,此时分段管理机制产生的线性地址直接作为物理地址使用;PG=1,启用分页管理机制,此时线性地址经分页管理机制转换位物理地址。关于分页管理机制的 具体介绍在后面的文章中进行。
下表列出了通过使用PE和PG位选择的处理器工作方式。由于只有在保护方式下才可启用分页机制,所以尽管两个位分别为0和1共可以有四种组合,但只有三种组合方式有效。PE=0且PG=1是无效组合,因此,用PG为1且PE为0的值装入CR0寄存器将引起通用保护异常。
需要注意的是,PG位的改变将使系统启用或禁用分页机制,因而只有当所执行的程序的代码和至少有一部分数据在线性地址空间和物理地址空间具有相同的地址的情况下,才能改变PG位。
控制寄存器CR0中的位1—位4分别标记为MP(算术存在位)、EM(模拟位)、TS(任务切换位) 和ET(扩展类型位),它们控制浮点协处理器的操作。
1.2CR2和CR3
控制寄存器CR2和CR3由分页管理机制使用。
CR2用于发生页异常时报告出错信息。当发生页异常时,处理器把引起页异常的线性地址保存在CR2中。操作系统中的页异常处理程序可以检查CR2的内容,从而查出线性地址空间中的哪一页引起本次异常。
CR3用于保存页目录表的其始物理地址。由于目录是页对齐的,而且页以4k为单位,所以仅高20位有效,低12 位保留未用。向CR3中装入一个新值时,低12位必须为0;但从CR3中取值时,低12位被忽略。每当用MOV指令重置CR3的值时,会导致分页机制高速 缓冲区的内容无效,用此方法,可以在启用分页机制之前,即把PG位置1之前,预先刷新分页机制的高速缓存。CR3寄存器即使在CR0寄存器的PG位或PE 位为0时也可装入,如在实模式下也可设置CR3,以便进行分页机制的初始化。在任务切换时,CR3要被改变,但是如果新任务中CR3的值与原任务中CR3 的值相同,那么处理器不刷新分页高速缓存,以便当任务共享也表时有较快的执行速度。
2。系统地址寄存器
全局描述符表GDT、局部描述符表LDT和中断描述符表IDT等都是保护方式下非常重要的特殊段,它们包含有为段机制所用的重要表格。为了方便快速地定位这些段,处理器采用一些特殊的寄存器保存这些段的基地址和段界限。我们把这些特殊的寄存器称为系统地址寄存器。
2.1全局描述符表寄存器GDTR
全局描述符表寄存器GDTR保存着指向全局描述符表GDT位置的地址,GDTR长48位,其中高32位为基地址,低16位为界限。如下图所示。
GDTR中的段界限以字节为单位。由于段选择子中只有13位作为描述符索引(见段选择子介绍),而每个描述符长8个字节,所以用16位的界限足够容纳最多8192个描述符。通常,对于含有N个描述符的描述符表的段界限设为8*N-1。
2.2中断描述符表寄存器IDTR
中断描述符表寄存器IDTR指向中断描述符表IDT。IDTR长48 位,其中32位的基地址规定IDT的基地址,16位的界限规定IDT的段界限。由于80386只支持256个中断/异常,所以IDT表最大长度是2K,以 字节位单位的段界限为7FFH。IDTR 指示IDT的方式与GDTR指示GDT的方式相同。
2.3局部描述符表寄存器LDTR
局部描述符表寄存器LDTR规定当前任务使用的局部描述符表LDT。LDTR类似于段寄存器,由程序员可见的16 位的寄存器和程序员不可见的高速缓冲寄存器(如DS、CS等段寄存器)组成。实际上,每个任务的局部描述符表LDT作为系统的一个特殊段,由一个描述符描 述。而用于描述符LDT的描述符存放在GDT中。在初始化或任务切换过程中,把描述符对应任务LDT的描述符的选择子装入LDTR,处理器根据装入 LDTR可见部分的选择子,从GDT中取出对应的描述符,并把LDT的基地址、界限和属性等信息保存到LDTR的不可见的高速缓冲寄存器中。随后对LDT 的访问,就可根据保存在高速缓冲寄存器中的有关信息进行合法性检查。
LDTR寄存器包含当前任务的LDT的选择子。所以,装入到LDTR的选择子必须确定一个位于GDT中的类型为LDT的系统段描述符,也即选择子中的TI位必须是0,而且描述符中的类型字段所表示的类型必须为LDT。
可以用一个空选择子装入LDTR,这表示当前任务没有LDT。在这种情况下,所有装入到段寄存器的选择子都必须指示GDT中的描述符,也即当前任务涉及的段均由GDT中的描述符来描述。如果再把一个TI位为1的选择子装入到段寄存器,将引起异常。
2.4任务状态段寄存器TR
任务状态段寄存器TR包含指示描述当前任务的任务状态段的描述符选择子,从而规定了当前任务的状态段。任务状态段 的格式在后面的文章中介绍。如本文开始处的表格所示,TR也有程序员可见和不可见两部分。当把任务状态段的选择子装入到TR可见部分时,处理器自动把选择 子所索引的描述符中的段基地址等信息保存到不可见的高速缓冲寄存器中。在此之后,对当前任务状态段的访问可快速方便地进行。装入到TR的选择子不能为空, 必须索引位于GDT中的描述符,且描述符的类型必须是TSS。
三。[[Anchor(NBE3)]]x86中段的相关概念
分段机制主要是考虑如何把程序的虚拟地址,也就是逻辑地址转换为线性地址。在32位系统中,逻辑地址也是按照段地 址加偏移量方式计算的,逻辑地址中的段数,可以达到16K个(由段选择子个数决定,下面会介绍),每个段有4G的空间,这样实际上,逻辑地址的最大空间可 以是64T字节。
1。段
段是实现虚拟地址到线性地址转换机制的基础,段基地址和偏移量就形成了线性地址。在保护方式下,每个段由如下三个参数进行定义:段基地址(Base Address)、段界限(Limit)和段属性(Attributes)。
1.1段基地址
段基地址规定线性地址空间中段的开始地址。在80386保护方式下,段基地址长32位。因为基地址长度与寻址地址的长度相同,所以任何一个段都可以从32位线性地址空间中的任何一个字节开始,而不象实方式下规定的边界必须被16整除。
1.2段界限
段界限规定段的大小。在80386保护模式下,段界限用20位表示,而且段界限可以是以字节为单位或以4K字节为 单位。段属性中有一位对此进行定义,把该位成为粒度位,用符号G标记。G=0表示段界限以字节位位单位,于是20位的界限可表示的范围是1字节至1M字 节,增量为1字节;G=1表示段界限以4K字节为单位,于是20位的界限可表示的范围是4K字节至4G字节,增量为4K字节。
1.3段属性
段属性规定段的主要特性。例如上面已经提到的段粒度G就是段属性的一部分。在对段进行各种访问时,将对访问是否合法进行检查,主要依据是段属性。例如:如果向一个只读段进行写入操作,那么不仅不能写入,而且会引起异常。在下面会详细说明各个段熟属性位的定义和作用。
2。段描述符
段描述符用于描述上述定义段的三个参数:段基地址、段界限和段属性。每个描述符长8个字节。在保护方式下,每一个段都有一个相应的描述符来描述。
按描述符所描述的对象来划分,描述符可分为如下三类:存储段描述符、系统段描述符和门描述符(控制描述符)。
2.1存储段描述符
存储段是存放可由程序直接进行访问的代码和数据的段。存储段描述符描述存储段,所以存储段描述符也被称为代码和数据段描述符。
可以看到,存储段描述符中头两个字节是段界限前16位,段基地址被段属性从中分开,第六和第七个字节组成段属性,其余字节组成段基地址,在段属性中的第9到第12位,也就是第七个字节的前4位是段界限的高4位。这样,段基地址为32位,段界限为20位,其余为段属性。
大家对这样奇怪的安排一定很好奇,实际上这是由于要兼容80286的保护模式才造成这样的,因为80286的段基地址只有24位,段界限也只有16位。
下面介绍段属性个位的意义:
第6字节的第8位G:这是段界限粒度(Granularity)位。G=0表示界限粒度为字节;G=1表示界限粒度为4K 字节。注意,界限粒度只对段界限有效,对段基地址无效,段基地址总是以字节为单位。
第6字节的第7位D:这是一个很特殊的位,在描述可执行段、向下扩展数据段或由SS寄存器寻址的段(通常是堆栈段)这三种描述符时的意义各不相同。
在描述可执行段的描述符中,D位决定了指令使用的地址及操作数所默认的大小。D=1表示默认情况下指令使用32位 地址及32位或8位操作数,这样的代码段也称为32位代码段;D=0 表示默认情况下,使用16位地址及16位或8位操作数,这样的代码段也称为16位代码段,它与80286兼容。可以使用地址大小前缀和操作数大小前缀分别 改变默认的地址或操作数的大小。
在向下扩展数据段的描述符中,D位决定段的上部边界。D=1表示段的上部界限为4G;D=0表示段的上部界限为64K,这是为了与80286兼容。
在描述由SS寄存器寻址的段描述符中,D位决定隐式的堆栈访问指令(如PUSH和POP指令)使用何种堆栈指针寄存器。D=1表示使用32位堆栈指针寄存器ESP;D=0表示使用16位堆栈指针寄存器SP,这与80286兼容。
第6字节的第6位:必须置为0,可以理解成是为以后的处理器保留的。
第6字节的第5位AVL:这是软件可利用位。80386对该位的使用未左规定,Intel公司也保证今后开发生产的处理器只要与80386兼容,就不会对该位的使用做任何定义或规定。
第5字节的第8位P:称为存在(Present)位。P=1表示描述符对地址转换是有效的,或者说该描述符所描述的段存在,即在内存中;P=0表示描述符对地址转换无效,即该段不存在。使用该描述符进行内存访问时会引起异常。
第5字节的第7和第6位DPL:表示描述符特权级(Descriptor Privilege level),共2位。它规定了所描述段的特权级,用于特权检查,以决定对该段能否访问。
第5字节的第5位DT:说明描述符的类型。对于存储段描述符而言,DT=1,以区别与系统段描述符和门描述符(DT=0)。
第5字节最后4位TYPE:描述如下
2.2系统段描述符
系统段是为了实现存储管理机制所使用的一种特别的段。在80386中,有两种系统段:任务状态段TSS和局部描述符表LDT段。用于描述系统段的描述符称为系统段描述符。
前面已经指出,但DT为0时,表示是系统段描述符或门描述符。系统段描述符中的段基地址和段界限字段与存储段描述符中的意义完全相同;属性中的G位、AVL位、P位和DPL字段的作用也完全相同。存储段描述符属性中的D位在系统段描述符中不使用,现用符号X表示。
只是这时TYPE的描述有很大不同:
可以看到,只有类型编码为2、1、3、9和B的描述符才是真正的系统段描述符,它们用于描述系统段LDT和任务状态段TSS,其它类型的描述符是门描述符。
2.2.1LDT段描述符
LDT段描述符描述任务的局部描述符表段。
LDT段描述符必须安排在全局描述符表中才有效。在装载LDTR寄存器时,描述符中的LDT段基地址和段界限等信息被装入LDT段描述符高速缓冲寄存器中。
2.2.2任务状态段描述符
任务状态段(Task State Segment)是保存一个任务重要信息的特殊段。任务状态段描述符用于描述这样的系统段。任务状态段寄存器TR的可见部分含有当前任务的任务状态段描述 符的选择子,TR的不可见的高速缓冲寄存器部分含有当前任务状态段的段基地址和段界限等信息。
TSS在任务切换过程中起着重要作用,通过它实现任务的挂起和恢复。所谓任务切换是指,挂起当前正在执行的任务, 恢复或启动另一任务的执行。在任务切换过程中,首先,处理器中各寄存器的当前值被自动保存到TR所指定的TSS中;然后,下一任务的TSS的选择子被装入 TR;最后,从TR所指定的TSS中取出各寄存器的值送到处理器的各寄存器中。由此可见,通过在TSS中保存任务现场各寄存器状态的完整映象,实现任务的 切换。 但在Linux中并没有使用,大家这里只是了解一下。
2.3门描述符
门描述符并不描述某种内存段,而是描述控制转移的入口点。这种描述符好比一个同向另一代码段的门。通过这种门,可实现任务内特权级的变换和任务间的切换。所以,这种门描述符也称为控制门。
门描述符的一般格式如下图所示。门描述符只有位于描述符内偏移5的类型字节与系统段保持一致(DT=0),也由该 字节标示门描述符和系统段描述符。该字节内的P和DPL的意义与其它描述符种中的意义相同。其它字节主要用于存放一个48位的全指针(16位的选择子和 32位的偏移量)。
门描述符又可分为:任务门、调用门、中断门和陷阱门。
2.3.1调用门
调用门描述某个子程序的入口。调用门内的选择子必须实现代码段描述符,调用门内的偏移是对应代码段内的偏移。利用段间调用指令CALL,通过调用门可实现任务内从外层特权级变换到内层特权级。
2.3.2任务门
任务门指示任务。任务门内的选择子必须指示GDT中的任务状态段TSS描述符,门中的偏移无意义。任务的入口点保存在TSS中。利用段间转移指令JMP和段间调用指令CALL,通过任务门可实现任务切换。
2.3.3中断门和陷阱门
中断门和陷阱门描述中断/异常处理程序的人口点。中断门和陷阱门内的选择子必须指向代码段描述符,门内的偏移就是对应代码段的人口点的偏移。中断门和陷阱门只有在中断描述符表IDT中才有效,这将在下面中断机制章节说明。
3。全局描述符表和局部描述符表
在80386中有三种类型的描述符表:全局描述符表GDT(Global Descriptor Table)、局部描述符表LDT(Local Descriptor Table)和中断描述符表IDT(Interrupt Descriptor Table)。在整个系统中,全局描述符表GDT和中断描述符表IDT只有一张,局部描述符表可以有若干张,每个任务可以有一张。
全局描述符表GDT含有每一个任务都可能或可以访问的段的描述符,通常包含描述操作系统所使用的代码段、数据段和堆栈段的描述符,也包含多种特殊数据段描述符,如各个用于描述任务LDT的特殊数据段等。在任务切换时,并不切换GDT。
每个任务的局部描述符表LDT含有该任务自己的代码段、数据段和堆栈段的描述符,也包含该任务所使用的一些门描述符,如任务门和调用门描述符等。随着任务的切换,系统当前的局部描述符表LDT也随之切换。
通过LDT可以使各个任务私有的各个段与其它任务相隔离,从而达到受保护的目的。而通过GDT可以使各任务都需要使用的段能够被共享。
一个任务可使用的整个虚拟地址空间分为相等的两半(实际上在Linux中缺省情况下是3G/1G的用户空间/内核 空间分配),一半空间的描述符在全局描述符表中,另一半空间的描述符在局部描述符表中。由于全局和局部描述符表都可以包含多达8192个描述符(由选择子 决定,下面介绍),而每个描述符所描述的段的最大值可达4G字节,因此最大的虚拟地址空间可为: 4GB*8192*2=64MMB=64TB
4。段选择子
在实模式下,逻辑地址空间中存储单元的地址由段值和段内偏移两部分组成。在保护方式下,虚拟地址空间(相当于逻辑地址空间)中存储单元的地址由段选择子和段内偏移两部分组成。与实模式相比,段选择子代替了段值。
段选择子长16位,其格式如下表所示。从表中可见,段选择子的高13位是描述符索引(Index)。所谓描述符索 引是指描述符在描述符表中的序号。段选择子的第2位是引用描述符表指示位,标记为TI(Table Indicator),TI=0指示从全局描述符表GDT中读取描述符;TI=1指示从局部描述符表LDT中读取描述符。
选择子的最低两位是请求特权级RPL(Requested Privilege Level),用于特权检查。
由于选择子中的描述符索引字段用13位表示,所以可区分8192个描述符。这也就是描述符表最多包含8192个描 述符的原因。由于每个描述符长8字节,根据上表所示选择子的格式,屏蔽选择子低3位后所得的值就是选择子所指定的描述符在描述符表中的偏移,这可认为是安 排选择子高13位作为描述符索引的原因。
有一个特殊的选择子称为空(Null)选择子,它的Index=0,TI=0,而RPL字段可以为任意值。空选择 子有特定的用途,当用空选择子进行存储访问时会引起异常。空选择子是特别定义的,它不对应于全局描述符表GDT中的第0个描述符,因此处理器中的第0个描 述符总不被处理器访问,一般把它置成全0。但当TI=1时,Index为0的选择子不是空选择子,它指定了当前任务局部描述符表LDT中的第0个描述符
四。[[Anchor(NBE4)]]x86中段寻址过程
我们知道,虚拟地址由段值和偏移地址构成,在保护模式下,段值就是段选择子。段选择子中包含了段描述符在GDT或LDT表中的位置索引,通过段选择子可以确定描述符内容,通过描述符可以获得段基地址,段基地址与偏移之和就是线性地址。
五。[[Anchor(NBE5)]]x86中页的相关概念
1。分页原理
分页机制把线性地址空间和物理地址空间分别划分为大小相同的块。这样的块称之为页。通过在线性地址空间的页与物理 地址空间的页之间建立的映射,分页机制实现线性地址到物理地址的转换。线性地址空间的页与物理地址空间的页之间的映射可根据需要而确定,可根据需要而改 变。线性地址空间的任何一页,可以映射为物理地址空间中的任何一页。
采用分页管理机制实现线性地址到物理地址转换映射的主要目的是便于实现虚拟存储器。不象段的大小可变,页的大小是相等并固定的。根据程序的逻辑划分段,而根据实现虚拟存储器的方便划分页。
在80386中,页的大小固定为4K字节,每一页的边界地址必须是4K的倍数。因此,4G大小的地址空间被划分为 1M个页,页的开始地址具有“XXXXX000H”的形式。为此,我们把页开始地址的高20位XXXXXH称为页码。线性地址空间页的页码也就是页开始边 界线性地址的高20位;物理地址空间页的页码也就是页开始边界物理地址的高20位。可见,页码左移12位就是页的开始地址,所以页码规定了页。
由于页的大小固定为4K字节,且页的边界是4K的倍数,所以在把32位线性地址转换成32位物理地址的过程中,低 12位地址保持不变。也就是说,线性地址的低12位就是物理地址的低12位。假设分页机制采用的转换映射把线性地址空间的XXXXXH页映射到物理地址空 间的YYYYYH页,那么线性地址XXXXXxxxH被转换为YYYYYxxxH。因此,线性地址到物理地址的转换要解决的是线性地址空间的页到物理地址 空间的页的映射,也就是线性地址高20位到物理地址高20位的转换。
2。映射表结构
线性地址空间的页到物理地址空间的页之间的映射用表来描述。由于4G的地址空间划分为1M个页,因此,如果用一张 表来描述这种映射,那么该映射表就要有1M个表项,若每个表项占用4个字节,那么该映射表就要占用4M字节。为避免映射表占用如此巨大的存储器资源,所以 80386把页映射表分为两级。
这里要注意的是,Linux系统里不仅支持页表的两级映射,还支持页表的三级映射。
页映射表的第一级称为页目录表,存储在一个4K字节的物理页中。页目录表共有1K个表项,其中,每个表项为4字节 长,包含对应第二级表所在物理地址空间页的页码。页映射表的第二级称为页表,每张页表也安排在一个4K字节的页中。每张页表都有1K个表项,每个表项为4 字节长,包含对应物理地址空间页的页码。由于页目录表和页表均由1K个表项组成,所以使用10位的索引就能指定表项,即用10位的索引值乘以4加基地址就 得到了表项的物理地址。
下图显示了由页目录表和页表构成的页映射表结构。从图中可见,控制寄存器CR3指定页目录表;页目录表可以指定 1K个页表,这些页表可以分散存放在任意的物理页中,而不需要连续存放;每张页表可以指定1K个物理地址空间的页,这些物理地址空间的页可以任意地分散在 物理地址空间中。需要注意的是,存储页目录表和页表的基地址是对齐在4K字节边界上的。
3。表项格式
页目录表和页表中的表项都采用如下图所示的格式。从图中可见,最高20位(位12—位31)包含物理地址空间页的 页码,也就是物理地址的高20位。低12位包含页的属性。下图所示的属性中内容为0的位是Intel公司为80486等处理器所保留的位,在为80386 编程使用到它们时必须设置为0。在位9至位11的AVL字段供软件使用。表项的最低位是存在属性位,记作P。P位表示该表项是否有效。P=1表项有 效;P=0表项无效,此时表项中的其余各位均可供软件使用,80386不解释P=0的表项中的任何其它的位。在通过页目录表和页表进行的线性地址到物理地 址的转换过程中,无论在页目录表还是在页表中遇到无效表项,都会引起页故障。
4。支持虚拟存储器
页表项中的P位是支持采用分页机制虚拟存储器的关键。P=1,表示表项指定的页存在于物理存储器中,并且表项的高 20位是物理页的页码;P=0,表示该线性地址空间中的页所对应的物理地址空中的页不在物理存储器中。如果程序访问不存在的页,会引起页异常,这样操作系 统可把该不存在的页从磁盘上读入,把所在物理页的页码填入对应表项并把表项中的P位置为1,然后使引起异常的程序恢复运行。
此外,表项中的访问位A和写标志位D也用于支持有效地实现虚拟存储器。
表项的位5是访问属性位,记作A。在为了访问某存储单元而进行线性地址到物理地址的转换过程中,处理器总是把页目 录表内的对应表项和其所指定页表内的对应表项中的A位置1,除非页表或页不存在,或者访问违反保护属性规定。所以,A=1表示已访问过对应的物理页。处理 器永不清除A位。通过周期性地检测及清除A位,操作系统就可确定哪些页在最近一段时间未被访问过。当存储器资源紧缺时,这些最近未被访问的页很可能就被选 择出来,将它们从内存换出到磁盘上去。
表项的位6是写标志位,记作D。在为了访问某存储单元而进行线性地址到物理地址的转换过程中,如果是写访问并且可 以写访问,处理器就把页表内对应表项中的D位置1,但并不把页目录表内对应表项中的D置1。当某页从磁盘上读入内存时,页表中对应对应表项的D位被清0。 所以,D=1表示已写过对应的物理页。当某页需要从内存换出到磁盘上时,如果该页的D位为1,那么必须进行写操作(把内存中的页写入磁盘时,处理器并不清 除对应页表项的D位)。但是,如果要写到磁盘上的页的D位为0,那么不需要实际的磁盘写操作,而只要简单地放弃内存中该页即可。因为内存中的页与磁盘中的 页具有完全相同的内容。
5。页级保护
80386不仅提供段级保护,也提供页级保护。分页机制只区分两种特权级。特权级0、1和2统称为系统特权级,特权级3称为用户特权级。在上图所示页目录表和页表的表项中的保护属性位R/W和U/S就是用于对页进行保护。
表项的位1是读写属性位,记作R/W。R/W位指示该表项所指定的页是否可读、写或执行。若R/W=1,对表项所 指定的页可进行读、写或执行;若R/W=0,对表项所指定的页可读或执行,但不能对该指定的页写入。但是,R/W位对页的写保护只在处理器处于用户特权级 时发挥作用;当处理器处于系统特权级时,R/W位被忽略,即总可以读、写或执行。
表项的位2是用户/系统属性位,记作U/S。U/S位指示该表项所指定的页是否是用户级页。若U/S=1,表项所 指定的页是用户级页,可由任何特权级下执行的程序访问;如果U/S=0,表项所指定的页是系统级页,只能由系统特权级下执行的程序访问。下表列出了上述属 性位R/W和U/S所确定的页级保护下,用户级程序和系统级程序分别具有的对用户级页和系统级页进行操作的权限。
由上表可见,用户级页可以规定为只允许读/执行或规定为读/写/执行。系统级页对于系统级程序总是可读/写/执 行,而对用户级程序总是不可访问的。于分段机制一样,外层用户级执行的程序只能访问用户级的页,而内层系统级执行的程序,既可访问系统级页,也可访问用户 级页。与分段机制不同的是,在内层系统级执行的程序,对任何页都有读/写/执行访问权,即使规定为只允许读/执行的用户页,内层系统级程序也对该页有写访 问权。
页目录表项中的保护属性位R/W和U/S对由该表项指定页表所指定的全部1K各页起到保护作用。所以,对页访问时引用的保护属性位R/W和U/S的值是组合计算页目录表项和页表项中的保护属性位的值所得。组合计算是“与”操作。
正如在80386地址转换机制中分页机制在分段机制之后起作用一样,由分页机制支持的页级保护也在由分段机制支持 的段级保护之后起作用。先测试有关的段级保护,如果启用分页机制,那么在检查通过后,再测试页级保护。如果段的类型为读/写,而页规定为只允许读/执行, 那么不允许写;如果段的类型为只读/执行,那么不论页保护如何,也不允许写。
页级保护的检查是在线性地址转换为物理地址的过程中进行的,如果违反页保护属性的规定,对页进行访问(读/写/执行),那么将引起页异常。
6。分页机制的启用
最后再次提一下分页机制的起用。在保护模式下,控制寄存器CR0中的最高位PG位控制分页管理机制是否生效。如果 PG=1,分页机制生效,把线性地址转换为物理地址。如果PG=0,分页机制无效,线性地址就直接作为物理地址。必须注意,只有在保护方式下分页机制才可 能生效。只有在保证使PE位为1的前提下,才能够使PG位为1,否则将引起通用保护故障。
六。[[Anchor(NBE6)]]x86中页寻址过程
分页管理机制通过上述页目录表和页表实现32位线性地址到32位物理地址的转换。控制寄存器CR3的高20位作为 页目录表所在物理页的页码。首先把线性地址的最高10位(即位22至位31)作为页目录表的索引,对应表项所包含的页码指定页表;然后,再把线性地址的中 间10位(即位12至位21)作为所指定的页目录表中的页表项的索引,对应表项所包含的页码指定物理地址空间中的一页;最后,把所指定的物理页的页码作为 高20位,把线性地址的低12位不加改变地作为32位物理地址的低12位。
为了避免在每次存储器访问时都要访问内存中的页表,以便提高访问内存的速度,80386处理器的硬件把最近使用的 线性—物理地址转换函数存储在处理器内部的页转换高速缓存中。在访问存储器页表之前总是先查阅高速缓存,仅当必须的转换不在高速缓存中时,才访问存储器中 的两级页表。页转换高速缓存也称为页转换查找缓存,记为TLB。
在分页机制转换高速缓存中的数据与页表中数据的相关性,不是由80386处理器进行维护的,而必须由操作系统软件 保存,也就是说,处理器不知道软件什么时候会修改页表,在一个合理的系统中,页表只能由操作系统修改,操作系统可以直接地在软件修改页表后通过刷新高速缓 存来保证相关性。高速缓存的刷新通过装入处理器控制寄存器CR3完成,实际过程可能用如下的两条指令实现:
一个重要的修改页表项的特殊情况不需要对页转换高速缓存刷新,这种情况是指修改不存在表项的任一部分,即使P位本 身从P=0改变为P=1时也一样,因为无效的表项不会存入高速缓存。因此,当无效的表项被改变时,不需要刷新高速缓存。这表明在从磁盘上读入一页使其存在 时,不必刷新高速缓存。
在一个多处理器系统中,必须特别注意是否在一个处理器中执行的程序,会改变可能由另外的处理器同时访问的页表。在 80386处理器中,每当要更新页表项并设置D位和A位时,通过使用不可分的读/修改/写周期支持多处理器的配置。对于页表项的软件更新需要借助于使用 LOCK前缀,从而保证修改页表的指令工作在不可分的读/修改/写周期中。在改变一个可能由另外的处理器使用的页表之前,最好使用一条加锁的AND指令在 一个不可分的操作中将P位清除为0,然后,该表项可根据要求进行修改,并随后把P位置成1而使表项成为可用。当修改页表项时必须及时通知(通常使用中断方 式)系统中该表项已被高速缓存的所有处理器刷新各自的页转换高速缓存,以撤消该表项的旧拷贝。在表项的旧拷贝被刷新之前,各处理器仍可继续访问旧的页,并 可以设置正被修改的表项的D位。如果这样做引起表项修改失败,则分页机制高速缓存最好在标记为不存在之后,并在对表项进行另外的修改之前进行刷新。
七。[[Anchor(NBE7)]]x86中页寻址的优点
1。节省页表占用存储空间
采用上述二次映射的页寻址方式,存储全部1K张页表需要4M字节,此外还需要4K字节用于存储页目录表。这样的两 级页映射表似乎反而比单一的整张页映射表多占用4K字节。其实不然,事实上不需要在内存中存储完整的两级页映射表。两级页映射表结构中对于线性地址空间中 不存在的或未使用的部分不必分配页表。除必须给页目录表分配物理页外,仅当在需要时才给页表分配物理页,于是页映射表的大小就对应于实际使用的线性地址空 间大小。因为任何一个实际运行的程序使用的线性地址空间都远小于4G字节,所以用于分配给页表的物理页也远小于4M字节。
页目录表项中的存在位P表明对应页表是否有效。如果P=1,表明对应页表有效,可利用它进行地址转换;如果 P=0,表明对应页表无效。如果试图通过无效的页表进行线性地址到物理地址的转换,那么将引起页故障。因此,页目录表项中的属性位P使得操作系统只需给覆 盖实际使用的线性地址范围的页表分配物理页。
页目录表项中的属性位P页可用于把页表存储在虚拟存储器中。当发生由于所需页表无效而引起的页故障时,页故障处理 程序再申请物理页,从磁盘上把对应的页表读入,并把对应页目录表项中的P位置1。换言之,可以当需要时才为所要的页表分配物理页。这样页表占用的物理页数 量可降到最小。
2。共享页面
由上述页映射表结构可见,分页机制没有全局页和局部页的规定。每一个任务可使用自己的页映射表独立地实现线性地址 到物理地址的转换。但是,如果使每一个任务所用的页映射表具有部分相同的映射,那么也就可以实现部分页的共享。 常用的实现页共享的方法是线性地址空间的共享,也就是不同任务的部分相同的线性地址空间的映射信息相同,具体表现为部分页表相同或页表内的部分表项的页码 相同。例如,如果任务A和任务B分别使用的页目录表A和页目录表B内的第0项中的页码相同,也就是页表0相同,那么任务A和任务B的00000000H至 003FFFFFH线性地址空间就映射到相同的物理页。再如,任务A和任务B使用的页表0不同,但这两张页表内第0至第0FFH项的页码对应相同,那么任 务A和任务B的00000000H至000FFFFFH线性地址空间就映射到相同的物理页。
需要注意的是,共享的页表最好由两个页目录中同样的目录项所指定。这一点很重要,因为它保证了在两个任务中同样的线性地址范围将映射到该全局区域。