内核代码学习==>深入介绍Linux内核(五)

来源:百度文库 编辑:神马文学网 时间:2024/04/28 02:29:47
深入介绍Linux内核(五)
.......(续第四章)
4.3.2 段描述符号表
段描述符号表是段描述符号的一个阵列,见图4-8所示。描述符号表的长度可变,最多可以包含8192个8位元组描述符号。有两种描述符号表:全域描述符号表GDT(Global descriptor table):区域描述符号表LDT(Local descriptor table)。

描述符号表储存在由作业系统维护著的特殊资料结构中,並且由处理器的记忆体管理硬体来参照引用。这些特殊结构应该保存在仅由作业系统软体存取的受保护的记忆体区域中,以防止应用程式修改其中的位址转換资讯。虛拟位址空间被分割成大小相等的两半。一半由GDT来映射变換到線性位址,另一半则由LDT来映射。整个虛拟位址空问共含有2¹个段:一半空间(即2¹³个段)是由GDT映射的全域虛拟位址空间,另一半是由LD了映射的区域虛拟位址空间。透过指定一个描述符号表(GDT或LDT)以及表中描述符号号,我们就可以定位一个描述符号。
当发生任务切換时,LDT会更換成新任务的LDT,但是GDT並不会改变。因此,GDT所映射的一半虛拟位址空间是系统中所有任务共有的,但是LDT所映射的另一半则在任务切換时被改变。系统中所有任务共用的段由GDT来映射。这樣的段通常包括含有作业系统的段以及所有任务各自的包含LDT的特殊段。LDT段可以想像成属於作业系统的资料。
图4-9示出一个任务中的段如何能在GDT和LDT之间分开。图中共有6个段,分別用於两个应用程式(A和B)以及作业系统。系统中每个应用程式对应一个任务,並且每个任务有自己的LDT。应用程式A在任务A中执行,拥有LDTA,用来映射段CodeA和DataA。类似地,应用程式B在任务B中执行,使用LDTB来映射CodeB和DataB段。包含作业系统內核的两个段Codeos和Dataos使用GDT来映射,这樣它们可以被两个任务所共用。两个LDT段:LDTA和LDTB也使用GDT来映射。

当任务A在执行时,可存取的段包括LDTA反射的CodeA和DataA段,加上GDT映射的作业系统的CodeOS 和dataOS段,加上影射的段。
这个例子透过让每个任务使用不同的LDT,演示了虛拟位址空间如何能夠被组织成隔离每个任务。当任务A在执行时,任务B的段不是虛拟位址空间的部分,因此任务A沒有办法存取任务B的记忆体。同樣地,当任务B执务A的段也不能被定址。这种使用LDT来隔离每个应用程式任务的方法,正是关键保护需求之一。
每个系统必须定义一个GDT,并可用于系统中所有程式或任务。另外,可以选定义一个或多个LDT。例如,可以为每个执行任务定义一个LDT,或者某些或所有任务共用一个LDT。
GDT本身並不是一个段,而足線性位址空间中的一个资料结构。GDT的基線性位址和长度值必须载入进GDTR寄存器中。GDT的基底位址应该进行记忆体8位元组对齐,以得到最佳处理器性能。GDT的限长以位元组为单位。与段类似,限长值加上基底位址可得到最后表中最后一个位元组的有效位址。限长为0表示有1个有效位元组。因为段描述符号总是8位元组长,因此GDT的限长值应该设置成总是8的倍数減1(即8N-1) 。
处理器並不使用GDT中的第l个描述符号。把这个“空描述符号”的段选择符号载入进一个资料段寄存器(DS、ES、FS或GS)並不会產生一个異常,但是若使用这些载入了空描述符号的段选择符号存取记忆体时就肯定会產生一般保护性異常。透过使用这个段选择符号初始化段寄存器,那麼意外引用未使用的段寄存器肯定会产生一个異常。
LDT表存放在LDT类型的系统段中。此时GDT必须含有LDT的段描述符2号。如果系统支援多LDT的话,那麼每个LDT都必须在GDT中有一个段描述符号和段选择符号。一个LDT的段描述符号可以存放在GDT表的任何地方。
存取LDT需使用其段选择符号。为了在存取LDT时減少位址转換次数,LDT的段选择符号、基底位址、段限长以及存取许可权需要存放在LDTR寄存器中。
当保存GDTR寄存器內容时(使用SGDT指令),一个48位元的“偽描述符号”被储存在记忆体中。为了在用戶模式(特权级3)避免对齐检查出错,偽描述符号应该存放在一个奇字位址处(即位址MOD 4 = 2)。这会让处理器先存放一个对齐的字,随后是一个对齐的双字(4位元组对齐处)。用戶模式程式通常不会保存偽描述符号,但是可以透过使用这种对齐方式来避免產生一个对齐检查出错的可能性。当使用SIDT指令保存IDTR寄存器內容时也需要使用同樣的对齐方式。然而,当保存LDTR或任务寄存器(分別使用SLTR或STR指令)时,偽描述符号应该存放在双字对齐的地址处(即地址MOD 4=0)。
4.3.3 段选择符号
段选择符号(或称段选择子)是段的一个16位识別字,见图4-l0所示。段选择符号並不直接指向段,而是指向段描述符号表中定义段的段描述符号。段选择符号3个栏位內容:
▓ 请求特权级RPL (Requested Privilege Level);
▓ 表指示旗标TI (Table Index);
▓ 索引值 (Index)。

请求特权级栏位RPL提供了段保护资讯,将在后面作详细說明。表索引栏位TI用来指出包含指定段描述符号的段描述符号表GDT或LDT。TI = 0表示描述符号在GDT中;TI =1表示描述符号在LDT中。索引栏位给出了描述符号在GDT或LDT表中的索引项号。可见,选择符号透过定位段表中的一个描述符号来指定一个段,並且描述符号中包含有存取一个段的所有资讯,例如段的基底位址、段长度和段属性。
例如,图4-11(a)中选择符号指定了GDT中具有RPL = 0的段3,其索引栏位值是0b 11(即3) ,Ti位是0,指定GDT表。图4-11(b)中的选择符号指定LDT表中RPL=3的段819l。其索引栏位值是0b11 11 111111111 (即8l 91) ,TI位等於l,指定LDT表。

另外,处理器不使用GDT表中的第1项。指向GDT该项的选择符号(即索引值为0,TI标志为0的选择符号)用作为“空选择符号”,见图4-11(C)所示,当把空选择符号载入到一个段寄存器(除了CS和SS以外)中时,处理器並不產生異常。但是当使用含有空选择符号的段寄存器用於存取记忆体时就会產生異常。当把空选择符号载入到CS或SS段寄存器中时将会导致一个異常。
对应用程式来說段选择符号是作为指标变数的一部分而可见,但选择符号的值通常是由链结编辑器或链结载入程式进行设置或修改,而非应用程式。
为減少位址转換时间和程式设计复杂性,处理器提供可存放最多6个段选择符号的寄存器(见图4-12所示),即段寄存器。每个段寄存器支援特定类型的记忆体引用(代码、资料或堆栈) 。原则上执行每个程式都起码需要把有效的段选择符号载入到代码段(CS)、资料段(DS)和堆栈段(SS)寄存器中。处理器还另外提供三个辅助的资料段寄存器(ES、FS和GS),可被用於让当前执行对於存取某个段的程式(或任务)能够存取其他几个资料段。

对于存取某个段的程式,必须已经把段选择符号载入到一个段寄存器中。因此,尽管一个系统可以定义很多的段,但同时只有6个段可供立即存取。若要存取其他段就需要载入这些段的选择符号。
另外,为了避免每次存取记忆体时都去引用描述符号表,去读和解码一个段描述符号,每个段暂存器都有一个“可见”部分和一个“隐藏”部分(隐藏部分也被称为“描述符号缓冲”或“影子寄存器”)。当一个段选择符号被载入到一个段寄存器可见部分中时,处理器也同时把段选择符号指向的段描述符号中的段位址、段限长以及存取控制资讯载入到段寄存器的隐藏部分中。缓冲在段寄存器(可见和隐藏部分)中的资讯使得处理器可以在进行位址转換时不再需要花费时间从段描述符号中读取基底位址和限长值。
由於影子寄存器含有描述符号资讯的一个拷贝,因此作业系统必须确保对描述符号表的改动应反映在影子寄存器中。否则描述符号表中一个段的基底位址或限长被修改过,但改动卻沒有反映到影子寄存器中。处理这种问题最简捷的方法是在对描述符号表中描述符号作过任何改动之后就立刻重新载入6个段寄存器。这将把描述符号表中的相应段资讯重新载入到影子寄存器中。
为载入段寄存器,提供了两类载入指令:
⒈ 像MOV、POP、LDS、LES、LSS、LGS以及LFS指令。这些指令显式地直接引用段暂存器;
⒉ 隐式载入指令,例如使用长指标的CALL、JMP和RET指令、IRET、INTn、INTO
和INT3等指令。这些指令在操作行程中会附带改变CS寄存器(和某些其他段寄存器)的內容。
⒊ MOV指令当然也可以用於把段寄存器可见部分內容储存到一个通用寄存器中。
4.3.4 段描述符号
前面我们已经說明了使用段选择符号来定位描述符号表中的一个描述符号。段描述符号是GDT和LDT表中的一个资料结构项,用於向处理器提供有关一个段的位置和大小资讯以及存取控制的状态资讯。每个段描述符号长度是8位元组,含有三个主要栏位:段基底位址、段限长和段属性。段描述符号通常由编译器、链结器、载入器或者作业系统来建立,但絕不是应用程式。图4-13示出了所有类型段描述符号的一般格式。

一个段描述符号中各栏位和标志的含义如下:
▓ 段限长栏位LIMIT (Segment limit field)
段限长Limit栏位用於指定段的长度。处理器会把段描述符号中两个段限长栏位组合成一个20位元的值,並根据颗粒度标志G来指定段限长Limit值的实际含义。如果G=0,则段长度Limit范围可从l位元组到1MB位元组,单位是位元组。如果G=l,则段长度Limit范围可从4KB到4GB,单位是4KB。
根据段类型中的段扩充方向标志E,处理器以两种不同方式使用段限长Limit。对於向上扩充的段(简称上扩段),逻辑位址中的偏移值范围可以从。到段限长值Limit。大於段限长Limit的偏移值将產生一般保护性異常。对於向下扩充的段(简称下扩段),段限长Limit的含义相反。根据预设堆栈指标大小标志B的设置,偏移值范围可从段限长Limit到0xFFFFFFFF或OxFFFF 。而小於段限长Limit的偏栘值将產生一般保护性異常。对於下扩段,減小段限长栏位中的值会在该段位址空间底部分配新的记忆体,而不是在顶部分配。80X86的堆栈总是向下扩充的,因此这种实现方式很适合扩充堆栈。
▓ 基底位址栏位BASE(Base address field)
该栏位定义在4GB線性位址空间中一个段位元组0所处的位置。处理器会把3个分立的基底位址栏位组合形成一个32位元的值。段级位址应该对齐16位元组边界。虽然这不是要求的,但透过把程式的代码和资料段对齐在16位元组边界上,可以让程式具有最佳效能。
▓ 段类型栏位TYPE(Type field)
类型栏位指定段或闸(Gate)的类型、說明段的存取种类以及段的扩充方向。该栏位的解释依赖于描述符号类型标志S指明是一个应用(代码或资料)描述符号还是一个系统描述符号。TYPE栏位的编码对代码、资料或系统描述符号都不同,见图4-14所示。
▓ 描述符号类型标志S(Descriptor type flag)
描述符号类型标志S指明一个段描述符号是系统段描述符号(当S=0)还是代码或资料段描述符号(当S=1)。
▓ 描述符号特权级栏位DPL(Descriptor privilege level)
DPL栏位指明描述符号的特权级。特权级范围从0到3。0级特权级最高,3级最低。
DPL用於控制对段的存取。
▓ 段存在标志P(Segment present)
段存在标志P指出一个段是在记忆体中(P=1)还是不在记忆体中(P=0)。当一个测描述符号的P标志为0时,那麼把指向这个段描述符号的选择符号载入进段寄存器将导致產生一个段不存在異常。记忆体管理软体可以使用这个标志来控制在某一给定时间实际需要把那个段载入进记忆体中。这个功能为虛拟储存提供了除分页机制以外的控制。图4-15给出了当P=0时的段描述符号格式。当P标志为0时,作业系统可以自由使用格式中标注为可用(Avaliable)的栏位位置来保存自己的资料,例如有关不存在段实际在什麼地方的资讯。
▓ D/B(预设操作大小/预设堆栈指标大小和/或上界限)标志
(Default operation size/default stack pointer size and/or upper bound)
根据段描述符号描述的是一个可执行代码段、下扩资料段还是一个堆栈段,这个标志具有不同的功能。(对於32位元代码和资料段,这个标志应该总是设置为1;对於16位元代码和资料段,这个标志被设置为0。)
● 可执行代码段。此时这个标志称为D标志並用於指出该段中的指令参照引用有效位址和运算元的预设长度。如果该标志置位元,则预设值是32位位址和32位或8位的运算元:如果该标志为0,则预设值是16位位址和16位或8位的运算元。指令首码ox66可以用来选择非预设值的运算元大小;首码0x67可用来选择非预设值的位址大小。
● 堆栈段(由SS寄存器指向的资料段)。此时该标志称为B(Big)标志,用於指明隐含堆栈操作(例如PUSH、POP或CALL)时的堆栈指标大小。如果该标志置位元,则使用32位堆栈指标並存放在ESP寄存器中;如果该标志为0,则使用l 6位堆栈指标並存放在SP寄存器中。如果堆栈段被设置成一个下扩资料段,这个B标志也同时指定了堆栈段的上界限。
● 下扩资料段。此时该标志称为B标志,用於指明堆栈段的上界限。如果设置了该标志,则堆栈段的上界限是0xFFFFFFFF(4GB) ;如果沒有设置该标志,则堆栈段的上界限是OxFFFF(64KB)。
▓ 颗粒度标志G (Granularity)
该栏位用於确定段限长栏位Limit值的单位。如果颗粒度标志为0,则段限长值的单位是位元组;如果设置了颗粒度标志,则段限长值使用4KB单位。(这个标志不影响段基底位址的颗粒度,基底位址的颗粒度总是位元组单位。)若设置了G标志,那麼当使用段限长来检查偏栘值时,並不会去检查偏栘值的12位最低有效位。例如,当G=l时,段限长为0表明有效偏移值为0到4095。
▓ 可用和保留位元(Available and reserved bits)
段描述符号第2个双字的位元20可供系统软体使用;位2l是保留位並应该总是设置为0。


4.3.5 代码和资料段描述符号类型
当段描述符号中S (描述符号类型) 标志被置位元,则该描述符号用於代码或资料段。此时类型栏位中最高Bit位(第2个双字的位11)用於确定是资料段的描述符号(复位)还是代码段的描述符号(置位) 。
对於资料段的描述符号,类型栏位的低3位(8、9、l0位元)被分別用於表示已存取 A(Accessed)、可写W(Write-enable)和扩充方向E (Expansion-direction),参见表4-3中有关代码和资料段类型栏位Bit位的說明。根据可写Bit位W的设置,一个资料段可以是唯读的,也可以是可读可写的。

堆栈段必须是可读/写的资料段。若使用不可写资料段的选择符号载入到SS暂存器中,将导致一个一般保护異常。如果堆栈的长度需要动态地改变,那么堆栈段可以是一个向下扩充的资料段(扩充方向标志置位元)。这裡,动态改变段限长将导致堆栈空间被添加到堆栈底部。
已存取Bit位元指明自从上次作业系统重定该位元之后一个段是否被存取过。每当处理器把一个段的段选择符号载入进段寄存器,它就会设置该位。该位元需要明确地清除,否则一直保持置位元状态。该位可用於虛拟记忆体管理和除错。
对於代码段,类型栏位的低3位被解释成已存取A (Accessed) 、可读R (Read-enable)和一致的C( Conforming)。根据可读R标志的设置,代码座可以是只能执行、可执行/可读。当常数或其他靜态资料以及指令码被放在了一个ROM中时就可以使用一个可执行/可读代码段。这裡,透过使用带CS首码的指令或者把代码段选择符号载入进一个资料段暂存(DS、ES、FS或GS),我们可以读取代码段中的资料。在保护模式下,代码段是不可写的。
代码段可以是一致性的或非一致性的。向更高特权级一致性代码段的执行控制转移,允许程式以当前特权级继续执行。向一个不同特权级的非一致性代码段的转移将导致一般保护異常,除非使用了一个呼叫门或任务门(有关一致性和非一致性代码段的详细资讯请参见“直接呼叫或跳转到代码段”)。不存取保护设施的系统工具以及某些異常类型(例如除出错、溢出)的处理行程可以存放在一致性代码段中。需要防止低特权级程式或行程存取的工具应该存放在非一致性代码段中。
所有资料段都是非一致性的,即意味著它们不能被低特权级的程式或行程存取。然而,与代码段不同,资料段可以被更高特权级的程式或行程存取,而无须使用特殊的存取门。
如果GDT或LDT中一个段描述符号被存放在ROM中,那麼若软体或处理器试图更新(写)在ROM中的段描述符号时,处理器就会进入一个无限回圈。
为了防止这个问题,需要存放在ROM中的所有描述符号的已存取位应该预先设置成置位元状态。同时,刪除作业系统中任何试图修改ROM中段描述符号的代码。
4.3.6 系统描述符号类型
当段描述符号中的S标志(描述符号类型)是重定模式(0)的话,那麼该描述符号是一个系统描述符号。处理器能夠识別以下一些类型的系统段描述符号:
▓ 区域描述符号表(LDT)的段描述符号:
▓ 任务状态段(TSS)描述符号;
▓ 呼叫门描述符号;
▓ 中断门描述符号;
▓ 陷阱门描述符号;
▓ 任务门描述符号。
这些描述符号类型可分为两大类:系统段描述符号和门描述符号。系统段描述符号指向系统段(如LDT和TSS段) ,门描述符号就是一个“门”,对於呼叫、中断或陷阱门,其中含有代码段的选择符号和段中程式入口点的指标;对於任务门,其中含有TSS的段选择符号。表4-4给出了系统段描述符号和门描述符号类型栏位的编码。

有关TSS状态段和任务门的使用方法将在任务管理一节中进行说明,呼叫门的使用方法将放在保护一节中說明,中断和陷阱门的使用方法将在中断和異常处理一节中给予說明。
4.4 分页机制
分页机制是80X86记忆体管理机制的第二部分。它在分段机制的基础上完成虛拟(逻辑)位址到实体位址转換的行程。分段机制把逻辑位址转換成線性位址,而分页则把線性位址转換成实体位址。分页可以用於任何一种分段模型。处理器分页机制会把線性位址空间(段已映射到其中)划分成页面,然后这些线性位址空间页面被映射到实体位址空间的页面上。分页机制几种页面级保护措施,可和分段机制保护机制合用或替代分段机制的保护措施。例如,在基於页面的基础上可以加強读/防写。另外,在页面单元上,分页机制还提供了用戶- 超级用户两级保护。
我们透过设置控制寄存器CR0的PG位元可以啟用分页机制。如果PG=1,则啟用分页操作,处理器会使用本节描述的机制将線性位址转換成实体位址。果PG=0,则禁用分页机制,此时分段机制產生的線性位址被直接用作实体位址。
前面介绍的分段机制在各种可变长度的记忆体区域上操作。与分段机制不同,分页机制对固定大小的记忆体区块(称为页面)进行操作。分页机制把线性和实体位址空间都划分成页面。線性位址空间中的任何页面可以被映射到实体位址空间的任何页面上。图4-16示出了分页机制是如何把線性和实体位址空间都划分成各个页面,並在这两个空间之间提供了任意映射。图中的箭头把線性位址空间中的页面与实体位址空间中的页面对应了起来。

80X86使用4K(2¹²)位元组固定大小的页面。每个页面均是4KB,並且在对齐4K地址边界。这表示分页机制把2³²位元组(4GB)的線性位址空间划分成2²°(1M=1048576)个页面。分页机制透过把線性位址空间中的页面重新定位到实体位址空间中进行操作。由於4K大小的页面作为一个单元进行映射,並且对齐於4K边界,因此線性位址的低12Bit可作为页內偏移量直接作为实体位址的低12位元。分页机制执行的重定位功能可以看作是把线性位址的高20位元转换到对应实体位址的高20位元。
另外,線性到实体位址的转換功能被扩展成允许一个線性位址被标注为无效的,而非让其產生一个实体位址。在两种情況下一个页面可以被标注为无效的:①作业系统不支援的線性位址;②对应在虛拟记忆体系统中的页面在磁碟上而非在实体记忆体中。在第一种情況下,產生无效位址的程式必须被终止。在第二种情况下,该无效位址实际上是请求作业系统虛拟记忆体管理器把对应页面从磁片上载入到实体记忆体中,以供程式存取。因为无效页面通常与虛拟储存系统相关,因此它们被称为不存在的页面,並且由页表中称为存在(present)的属性来确定。
在保护模式中,80X86允许線性位址空间直接映射到大容量的实体记忆体(例如4GB的RAM)上,或者(使用分页)间接地映射到较小容量的实体记忆体和磁片储存空间中。这后一种映射線性位址空间的方法被称为虛拟储存或者需求页(Demand-paged)虛拟储存。当使用分页时,处理器会把線性位址空问划分成固定大小的页面(长度4KB) ,这些页面可以映射到实体记忆体中和/或磁片储存空间中。当一个程式(或任务)参照记忆体中的逻辑位址时,处理器会把该逻辑位址转換成一个線性位址,然后使用分页机制把该線性位址转換成对应的实体位址。
如果包含線性位址的页面当前不在实体记忆体中,处理器就会產生一个页错误異常。页错误異常的处理程式通常就会让作业系统从磁碟中把相应页面载入到实体记忆体中(操作行程中可能还会把实体记忆体中不同的页面写到磁片上)。当页面载入到实体记忆体中之后,从異常处理行程的返回操作会使得导致異常的指令被重新执行。处理器用於把線性位址转換成实体位址和用於產生页错误異常(若必要的话)的资讯包含在储存於记忆体中的页目錄和页表中。
分页与分段最大的不同之处在於分页使用了固定长度的页面。段的长度通常与存放在其中的代码或资料结构具有相同的长度。与段不同,页面有固定的长度。如果仅使用分段位址转換,那麼储存在实体记忆体中的一个资料结构将包含其所有的部分。但如果使用了分页,那麼一个资料结构就可以一部分储存於实体记忆体中,而另一部分保存在磁碟中。
为了減少位址转換所要求的汇流排週期数量,最近存取的页目錄和页表会被存放在处理器的缓冲器件中,该缓冲器件被称为转換查找缓冲区TLB(Translation Lookaside Buffer)。TLB可以满足大多数读页目錄和页表的请求而无需使用汇流排週期。只有当TLB中不包含要求的页表项时才会使用额外的汇流排週期从记忆体中读取页表项,这通常在一个页表项很长时间沒有存取过时才会出现这种情況。
4.4.1 页表结构
分页转換功能由驻留在记忆体中的表来描述,该表称为页表(page table),存放在实体位址空间中。页表可以看作足简单的2²°实体位址阵列。線性到实体位址的映射功能可以简单地看作是进行阵列查找。線性位址的高20位元构成这个阵列的索引值,用於选择对应页面的实体(基)位址。線性位址的低12位元给出了页面中的偏移量,加上页面的基底位址最终形成对应的实体位址。由於页面基底位址对齐在4K边界上,因此页面基底位址的低12位元肯定是0。这意味着高20位元的页面基底位址和12位元偏移量连接组合在一起就能得到对应的实体位址。
页表中每个页表项大小为32位元。由於只需要其中的20位元来存放页面的实体基底位址,因此剩下的12位元可用于存放诸如页面是否存在等的属性资讯。如果線性位址索引的页表项被标注为存在的,则表示该项即有效,我们可以从中取得页面的实体位址。如果项中表明不存在,那么当存取对应实体页面时就会产生一个异常。
两级页表结构
页表含有2²°(1M)个表项,而每项佔用4位元组。如果作为一个表来存放的话,它们最多将佔用4MB的记忆体。因此为了減少记忆体占用量,80X86使用了两级表。由此,高20位元線性位址到实体位址的转換也被分成两步来进行,每步使用(转換)其中10个Bit。
第一级表称为页目錄(page directory) 。它被存放在]页4K页面中,具有2¹°(1K)个4位元组长度的表项。这些表项指向对应的二级表。線性位址的最高10位元(位3 1- -22)用作一级表(页目錄)中的索引值来选择2¹°个二级表之一。
第二级表称为页表(page table) ,它的长度也是1个页面,最多含有1K个4位元组的表项。每个4位元组表项含有相关页面的20位元实体基底位址。二级页表使用線性位址中间10位元(位21- -12)作为表项索引值,以获取含有页面20位元实体基底位址的表项。该20位元页面实体基底位址和線性位址中的低12位元(页內偏移)组合在一起就得到了分页转換行程的输出值,即对应的最终实体位址。
图4-17示出了二级表的查找行程。其中CR3暂存器指定页目錄表的基底位址。線性位址的高10位元用於索引这个页目錄表,以获得指向相关第二级页表的指标。線性位址中间10位元用於索引二级页表,以获得实体位址的高20位元。線性位址的低12位元直接作为实体位址低12位元,从而组成一个完整的32位元实体位址。

不存在的页表
透过使用二级表结构,我们还沒有解決需要使用4MB记忆体问题。实际上,我们把问题搞得有些复杂了。因为我们需要另增一页面来存放目錄表。然而,二级表结构允许页表被分散在记忆体各个页面中,而不需要保存在在连续的4MB记忆体区块中。另外,并不需要为不存在的或線性位址空间未使用部分配二级页表。虽然目錄表页面必须总是存在於实体记忆体中,但是二级页表可以在需要时再分配。这使得页表结构的大小对应於实际使用的线性位址空间大小。
页目錄表中每个表项也有一个存在(present)属性,类似於页表中的表项,页目录表项中的存在属性指明对应的二级页表是否存在。如果目錄表项指明对应的二级页表存在,那么透过存取二级表,表查找行程第2步将同如上描述继续下去。如果存在位表明对应的二级表不存在,那么处理器就会产生一个异常来通知作业系统。页目录表项中的存在属性使得作业系统可以根据实际使用的线性位址范围来分配二级页表页面。
目錄表项中的存在位元还可以用於在虛拟记忆体中存放二级页表。这意着在任何时候只有部分二级页表需要存放在实体记忆体中,而其余的可保存在磁片上。处於实体记忆体中页表对应的页目錄项将被标注为存在,以表明可用它们进行分页转換。处於磁碟上的页表对应的页目錄项将被标注为不存在。由於二级页表不存在而引发的異常会通知作业系统把缺少的页表从磁碟上载入进实体记忆体。把页表储存在虛拟记忆体中減少了保存分页转換表所需要的实体记忆体量。
4.4.2页表项格式
页目录和页表的表项格式见图4-l 8所示。其中位元3 l- -12含有实体位址的高20位元,用于定位实体位址空间中一个页面(也称为页框)的实体基底位址。表项的低12位元含有页属性资讯。我们已经讨论过存在属性,这裡简要說明其余属性的功能和用途。

▓ P- -位元0是存在(Present)标志,用於指明表项对位址转換是否有效。P=1表示有效;P=0表示无效。在页转換行程中,如果說涉及的页目錄或页表的表项无效,则会导致一个異常。如果P=0,那麼除表示表项无效外,其余Bit位元可供程式自由使用,见图4-18(b)所示。例如,作业系统可以使用这些位元来保存已储存在磁片上的页面的序号。
▓ R/W一位元l是读/写(Read/Write)标志。如果等於l,表示页面可以被读、写或执行。如果为0,表示页面唯读或可执行。当处理器执行在超级用戶特权级(级別0、l或2)时,则R/W位不起作用。页目錄项中的R/W位元对其所映射的所有页面起作用。
▓ U/S一位元2是用戶/超级用戶(User/Supervisor)标志。如果为1,那麼执行在任何特权级上的程式都可以存取该页面。如果为0,那麼页面只能被执行在超级用户特权级(0、1或2)上的程式存取。页目錄项中的U/S位元对其所映射的所有
页面起作用。
▓ A- -位元5是已存取(Accessed)标志。当处理器存取页表项映射的页面时,页表表项的这个标志就会被置为l。当处理器存取页目錄表项映射的任何页面时,页目錄表项的这个标志就会被置为1。处理器只负责设置该标志,作业系统可透过定期地重定该标志来统计页面的使用情況。
▓ D- -位元6是页面已被修改(Dirty)标志。当处理器对一个页面执行写操作时,就会设置对应页表表项的D标志。处理器並不会修改页目錄项中的D标志。
▓ AVL- -该栏位保留专供程式使用。处理器不会修改这几个位元,以后的升级处理器也不会。
4.4.3 虛拟储存
页目錄和页表表项中的存在标志P为使用分页技术的虛拟储存提供了必要的支援。若線性位址空间中的页面存在於实体记忆体中,则对应表项中的标志P=l,並且该表项中含有相应实体位址。页面不在实体记忆体中的表项其标志P=0。如果程式存取实体记忆体中不存在的页面,处理器就会產生一个缺页異常。此时作业系统就可以利用这个異常处理行程把缺少的页面从磁碟上调入实体记忆体中,並把相应实体位址存放在表项中。最后在返回程式重新执行引起異常的指令之前设置标志P=1.
已存取标志A和已修改标志D可以用於有效地实现虛拟储存技术。透过週期性地检查和重定所有A标志,作业系统能夠确定哪些页面最近沒有存取过。这些页面可以成为移出到磁碟上的候选者。假设当一页面从磁碟上读入记忆体时,标志D=0,那麼当页面再次被移出到磁碟上时,若D标志还是为0,则该页面就无需被写入磁碟中。若此时D=l,则說明页面內容已被修改过,於是就必须将该页面写到磁碟上。
注译:
Stack - 堆叠 或者称呼为 堆栈
Segment - 段
Flag - 旗标 或者称呼为 标志
暂存器又称呼为寄存器