分段机制
简介
-
80X86 使用了一种称为 段(Segment)的寻址技术。这种寻址技术把内存空间分成一个或多个称为段的线性区域,从而对内存中一个数据对象的寻址就需要使用一个段的起始地址(即段地址)和一个段内偏移地址两部分构成。
段地址部分使用 16 位的 段选择符 指定,其中 14 位可以选择 次方即 64K 个段。
段内偏移地址部分使用 32 位的值来指定,因此段内地址可以是 0 到 4G。即一个段的最大长度可达 4G。
程序中由 16 位的段和 32 位的偏移构成的 48 位地址称为一个 逻辑地址(虚拟地址)。
-
分段提供了一种机制,用于把处理器可寻址的 线性地址空间 划分成一些较小的称为段的受保护地址空间区域。
段可以用来存放程序的代码、数据和堆栈,或者用来存放系统数据结构(例如 TSS或 LDT)。
如果处理器中有多个程序在运行,那么每个程序可分配各自的一套段。此时处理器就可以加强这些段之间的界限,并且确保一个程序不会通过访问另一个程序的段而干扰程序的执行。
段的定义
-
每个段由三个参数定义:
- 段基地址(Base address):指定段在线性地址空间中的开始地址。基地址是线性地址,对应于段中偏移 0 处。
- 段限长(limit):是虚拟地址空间中段内最大可用偏移位置。它定义了段的长度。
- 段属性(Attributes):指定段的特性。例如该段是否可读、可写或可作为一个程序执行以及段的特权级等。
-
段的基地址、段限长以及段的保护属性存储在一个称为段描述符(Segment Descriptor)的数据结构中。
段描述符保存在内存中的段描述符表(Descriptor table)中。段描述符表是包含段描述符项的一个简单数组。
-
逻辑地址由 16 位的段选择符和 32 位的偏移量组成,见图 4-7 所示。
段选择符指定字节所在的段,而偏移量指定该字节在段中相对于段基地址的位置。
处理器会把每个逻辑地址转换成线性地址。与物理地址空间类似,线性地址空间也是平坦的 4GB 地址空间,地址范围从 0 到 0xFFFFFFFF。
-
为了把逻辑地址转换成一个线性地址,处理器会执行以下操作:
- 使用段选择符中的偏移值(段索引)在 GDT 或 LDT 表中定位相应的段描述符。
- 利用段描述符检验段的访问权限和范围,以确保该段是可访问的并且偏移量位于段界限内。
- 把段描述符中取得的段基地址加到偏移量上,最后形成一个线性地址。
段描述符表
-
段描述符表是段描述符的一个数组。
-
有两种描述符表:全局描述符表 GDT(Global descriptor table)、局部描述符表 LDT(Local descriptor table)。
虚拟地址空间被分割成大小相等的两半。一半由 GDT 来映射变换到线性地址,另一半则由 LDT 来映射。
整个虚拟地址空间共含有 个段:一半空间(即 个段)是由 GDT 映射的全局虚拟地址空间,另一半是由 LDT 映射的局部虚拟地址空间。
通过指定一个描述符表(GDT 或 LDT)以及表中描述符号,我们就可以定位一个描述符。
-
当发生任务切换时, LDT 会更换成新任务的 LDT,但是 GDT 并不会改变。因此, GDT 所映射的一半虚拟地址空间是系统中所有任务共有的,但是 LDT 所映射的另一半则在任务切换时被改变。系统中所有任务共享的段由 GDT 来映射。
-
GDT 的基线性地址和长度值必须加载进 GDTR 寄存器中。
LDT 表存放在 LDT 类型的系统段中。此时 GDT 必须含有 LDT 的段描述符。如果系统支持多 LDT 的话,那么每个 LDT 都必须在 GDT 中有一个段描述符和段选择符。
访问 LDT 需使用其段选择符。为了在访问 LDT 时减少地址转换次数, LDT 的段选择符、基地址、段限长以及访问权限需要存放在 LDTR 寄存器中。
段选择符
-
段选择符(或称段选择子)是段的一个 16 位标识符,见图 4-10 所示。
段选择符 3 个字段内容:
-
请求特权级 RPL(Requested Privilege Level):提供了段保护信息。
-
表指示标志 TI(Table Index):指出包含该段描述符的段描述符表 GDT 或 LDT。 TI=0 表示描述符在 GDT 中; TI=1 表示描述符在 LDT 中。
-
索引值(Index):给出了描述符在 GDT 或 LDT 表中的索引项号。
-
-
为减少地址转换时间和编程复杂性,处理器提供了可存放段选择符的 6个寄存器,即段寄存器。
原则上执行每个程序都起码需要把有效的段选择符加载到代码段 CS)、数据段(DS)和堆栈段(SS)寄存器中。
处理器还另外提供三个辅助的数据段寄存器(ES、 FS 和 GS),可用于让当前执行程序能够访问其他几个数据段。
段描述符
- 每个段描述符长度是 8 字节,含有三个主要字段:段基地址、段限长和段属性。
- 图 4-13 示出了所有类型段描述符的一般格式。
-
段限长(LIMIT):指定段的长度。处理器会把段描述符中两个段限长字段组合成一个 20 位的值,并根据颗粒度标志 G 来指定段限长 Limit 值的实际含义。如果 G=0,则段长度 Limit 范围可从 1 字节到 1MB() 字节,单位是字节。如果 G=1,则段长度 Limit 范围可从 4KB 到 4GB,单位是4KB。
根据段类型中的段扩展方向标志 E,处理器以两种不同方式使用段限长 Limit。对于向上扩展的段(简称上扩段),逻辑地址中的偏移值范围可以从 0 到段限长值 Limit。大于段限长 Limit 的偏移值将产生一般保护性异常。
对于向下扩展的段(简称下扩段),段限长 Limit 的含义相反(即 LIMIT 不再是终点,而是起点)。根据默认栈指针大小标志 B 的设置,偏移值范围可从段限长 Limit 到 0xFFFFFFFF 或 0xFFFF。而小于段限长 Limit 的偏移值将产生一般保护性异常。对于下扩段,减小段限长字段中的值会在该段地址空间底部分配新的内存,而不是在顶部分配。 80X86 的栈总是向下扩展的,因此这种实现方式很适合扩展堆栈。
-
基地址字段( BASE):指出在 4GB 线性地址空间中一个段的起始位置。处理器会把 3 个分立的基地址字段组合形成一个 32 位的值。
-
段类型字段 (TYPE):指定段或门(Gate)的类型、说明段的访问种类以及段的扩展方向。对该字段的解释依赖于描述符类型标志 S。
-
描述符类型标志 (S):指明一个段描述符是系统段描述符(当 S=0)还是代码或数据段描述符(当 S=1)。
-
描述符特权级字段 (DPL):指明描述符的特权级。特权级范围从 0 到 3。 0 级特最高, 3 级最低。 DPL 用于控制对段的访问。
-
段存在标志(P):指出一个段是在内存中( P=1)还是不在内存中( P=0)。
-
D/B(默认操作大小/默认栈指针大小和/或上界限)标志:根据段描述符描述的是一个可执行代码段、下扩数据段还是一个堆栈段,这个标志具有不同的功能。
- 可执行代码段:此时这个标志称为 D 标志并用于指出该段中的指令引用有效地址和操作数的默认长度。如果该标志置位,则默认值是 32 位地址和 32 位或 8 位的操作数;如果该标志为0,则默认值是 16 位地址和 16 位或 8 位的操作数。
- 栈段(由 SS 寄存器指向的数据段):此时该标志称为 B( Big)标志,用于指明隐含堆栈操作(例如 PUSH、 POP 或 CALL)时,栈指针的大小。如果该标志置位,则使用 32 位栈指针并存放在 ESP 寄存器中;如果该标志为 0,则使用 16 位栈指针并存放在 SP 寄存器中。如果堆栈段被设置成一个下扩数据段,这个 B 标志也同时指定了堆栈段的上界限。
- 下扩数据段:此时该标志称为 B 标志,用于指明堆栈段的上界限。如果设置了该标志,则堆栈段的上界限是 0xFFFFFFFF( 4GB);如果没有设置该标志,则堆栈段的上界限是 0xFFFF(64KB)
-
颗粒度标志 (G):用于确定段限长字段 Limit 值的单位。如果颗粒度标志为 0,则段限长值的单位是字节;如果设置了颗粒度标志,则段限长值使用 4KB 单位。
-
可用和保留比特位( Available and reserved bits):第 20 位可供系统软件使用;第 21 位是保留位并应该总是设置为 0。
-
代码和数据段描述符类型
-
当段描述符中 S(描述符类型)标志被置位,则该描述符用于代码或数据段。此时类型字段中最高比特位(位 11)用于确定是数据段的描述符(复位)还是代码段的描述符(置位)。
-
对于数据段的描述符,类型字段的低 3 位(位 8、 9、 10)被分别用于表示已访问 A(Accessed)、可写 W(Write-enable)和扩展方向 E(Expansion-direction)。
-
对于代码段,类型字段的低 3 位被解释成已访问 A(Accessed)、可读 R(Read-enable)和一致的 C(Conforming)。
代码段可以是一致性的或非一致性的。向更高特权级一致性代码段的执行控制转移,允许程序以当前特权级继续执行。向一个不同特权级的非一致性代码段的转移将导致一般保护异常,除非使用了一个调用门或任务门。
系统描述符类型
-
当段描述符中的 S 标志(描述符类型)是复位状态(0)的话,那么该描述符是一个系统描述符。
处理器能够识别以下一些类型的系统段描述符:
- 局部描述符表(LDT)的段描述符;
- 任务状态段(TSS)描述符;
- 调用门描述符;
- 中断门描述符;
- 陷阱门描述符;
- 任务门描述符。
-
系统段描述符指向系统段(如 LDT 和 TSS段),门描述符就是一个“门”,对于调用、中断或陷阱门,其中含有代码段的选择符和段中程序入口点的指针;对于任务门,其中含有 TSS 的段选择符。
分页机制
简介
-
虚拟存储是一种内存管理技术,使用这种技术可让编程人员产生内存空间要比计算机中实际物理内存容量大很多的错觉。
-
分页机制支持虚拟存储技术。在使用虚拟存储的环境中,大容量的线性地址空间需要使用小块的物理内存(RAM 或 ROM)以及某些外部存储空间(例如大容量硬盘)来模拟。
当使用分页时,每个段被划分成页面(通常每页为 4KB 大小),页面会被存储于物理内存中或硬盘上。操作系统通过维护一个页目录和一些页表来留意这些页面。
当程序试图访问线性地址空间中的一个地址位置时,处理器就会使用页目录和页表把线性地址转换成一个物理地址,然后在该内存位置上执行所要求的操作(读或写)。
如果当前被访问的页面不在物理内存中,处理器就会中断程序的执行(通过产生一个页错误异常)。然后操作系统就可以从硬盘上把该页面读入物理内存中,并继续执行刚才被中断的程序。
-
分页机制是 80X86 内存管理机制的第二部分。它在分段机制的基础上完成虚拟(逻辑)地址到物理地址转换的过程。
分段机制把逻辑地址转换成线性地址,而分页则把线性地址转换成物理地址。分页可以用于任何一种分段模型。
-
处理器分页机制会把线性地址空间(段已映射到其中)划分成页面,然后这些线性地址空间页面被映射到物理地址空间的页面上。
-
通过设置控制寄存器 CR0 的 PG 位可以启用分页机制。如果 PG=1,则启用分页操作,处理器会将线性地址转换成物理地址。如果 PG=0,则禁用分页机制,此时分段机制产生的线性地址被直接用作物理地址。
-
与分段机制不同,分页机制对固定大小的内存块(称为页面)进行操作。
分页机制把线性和物理地址空间都划分成页面。线性地址空间中的任何页面
可以被映射到物理地址空间的任何页面上。 -
80X86 使用 4K()字节固定大小的页面。每个页面均是 4KB,并且对齐于 4K 地址边界处。这表示分页机制把 字节(4GB)的线性地址空间划分成 (1M )个页面。
分页机制通过把线性地址空间中的页面重新定位到物理地址空间中进行操作。由于 4K 大小的页面作为一个单元进行映射,并且对齐于 4K 边界,因此线性地址的低 12 比特位可作为页内偏移量直接作为物理地址的低 12 位。分页机制执行的重定位功能可以看作是把线性地址的高 20 位转换到对应物理地址的高 20 位。
-
为了减少地址转换所要求的总线周期数量,最近访问的页目录和页表会被存放在处理器的缓冲器件中,该缓冲器件被称为 TLB(Translation Lookaside Buffer)。
页表结构
-
分页转换功能由驻留在内存中的表来描述,该表称为页表(page table),存放在物理地址空间中。
页表可以看作是简单的具有 个项的数组。 线性到物理地址的映射功能可以简单地看作是进行数组查找。线性地址的高 20 位构成这个数组的索引值,用于选择对应页面的物理(基)地址。线性地址的低 12 位给出了页面中的偏移量,加上页面的基地址最终形成对应的物理地址。
由于页面基地址对齐在 4K 边界上,因此页面基地址的低 12 位肯定是 0。这意味着高 20 位的页面基地址和 12 位偏移量连接组合在一起就能得到对应的物理地址。
-
页表中每个页表项大小为 32 位。由于只需要其中的 20 位来存放页面的物理基地址,因此剩下的 12位可用于存放诸如页面是否存在等属性信息。
两级页表结构
-
页表含有 (1M)个表项,而每项占用 4 字节。如果作为一个表来存放的话,它们最多将占用 4MB的内存。因此为了减少内存占用量, 80X86 使用了两级表。由此,高 20 位线性地址到物理地址的转换也被分成两步来进行,每步使用(转换)其中 10 个比特。
-
第一级表称为页目录(page directory)。它被存放在 1 页 4K 页面中,具有 (1K)个 4 字节长度的表项。这些表项指向对应的二级表。线性地址的最高 10 位(位 31–22)用作一级表(页目录)中的索引值来选择 个二级表之一。
-
第二级表称为页表(page table),它的长度也是 1 个页面,最多含有 1K 个 4 字节的表项。每个 4 字节表项含有相关页面的 20 位物理基地址。二级页表使用线性地址中间 10 位(位 21–12)作为表项索引值,以获取含有页面 20 位物理基地址的表项。该 20 位页面物理基地址和线性地址中的低 12 位(页内偏移)组合在一起就得到了分页转换过程的输出值,即对应的最终物理地址。
-
图 4-17 示出了二级表的查找过程。其中 CR3 寄存器指定页目录表的基地址。线性地址的高 10 位用于索引这个页目录表,以获得指向相关第二级页表的指针。线性地址中间 10 位用于索引二级页表,以获得物理地址的高 20 位。线性地址的低 12 位直接作为物理地址低 12 位,从而组成一个完整的 32 位物理地址。
-
二级表结构允许页表被分散在内存各个页面中,而不需要保存在连续的 4MB 内存块中。另外,并不需要为不存在的或线性地址空间未使用部分分配二级页表。虽然目录表页面必须总是存在于物理内存中,但是二级页表可以在需要时再分配。这使得页表结构的大小对应于实际使用的线性地址空间大小。
-
页目录表中每个表项也有一个存在(present)属性,类似于页表中的表项。页目录表项中的存在属性指明对应的二级页表是否存在。如果目录表项指明对应的二级页表存在,那么通过访问二级表,表查找过程第 2 步将同如上描述继续下去。
如果存在位表明对应的二级表不存在,那么处理器就会产生一个异常来通知操作系统。页目录表项中的存在属性使得操作系统可以根据实际使用的线性地址范围来分配二级页表页面。
-
目录表项中的存在位还可以用于在虚拟内存中存放二级页表。这意味着在任何时候只有部分二级页表需要存放在物理内存中,而其余的可保存在磁盘上。
处于物理内存中页表对应的页目录项将被标注为存在,以表明可用它们进行分页转换。处于磁盘上的页表对应的页目录项将被标注为不存在。由于二级页表不存在而引发的异常会通知操作系统把缺少的页表从磁盘上加载进物理内存。
页表项格式
- 其中位 31–12 含有物理地址的高 20 位,用于定位物理地址空间中一个页面(也称为页帧)的物理基地址。
- 表项的低 12 位含有页属性信息。
- P – 位 0 是存在(Present)标志,用于指明表项对地址转换是否有效。 P=1 表示有效; P=0 表示无效。
- R/W – 位 1 是读/写(Read/Write)标志。如果等于 1,表示页面可以被读、写或执行。如果为 0,表示页面只读或可执行。当处理器运行在超级用户特权级(级别 0、 1 或 2)时,则 R/W 位不起作用。页目录项中的 R/W 位对其所映射的所有页面起作用。
- U/S – 位 2 是用户/超级用户(User/Supervisor)标志。如果为 1,那么运行在任何特权级上的程序都可以访问该页面。如果为 0,那么页面只能被运行在超级用户特权级( 0、 1 或 2)上的程序访问。页目录项中的 U/S 位对其所映射的所有页面起作用。
- A – 位 5 是已访问(Accessed)标志。当处理器访问页表项映射的页面时,页表表项的这个标志就会被置为 1。当处理器访问页目录表项映射的任何页面时,页目录表项的这个标志就会被置为 1。
- D – 位 6 是页面已被修改(Dirty)标志。当处理器对一个页面执行写操作时,就会设置对应页表表项的 D 标志。处理器并不会修改页目录项中的 D 标志。
- AVL – 该字段保留专供程序使用。处理器不会修改这几位。
区别
-
分页机制会使用大小固定的内存块,而分段管理则使用了大小可变的块来管理内存。
-
段表存储在线性地址空间,而页表则保存在物理地址空间。
段变换机制把虚拟地址(逻辑地址)变换成线性地址,并且在线性地址空间中访问自己的表,但是并不知晓分页机制把这些线性地址转换到物理地址的过程。
类似地,分页机制也不知道程序产生地址的虚拟地址空间。分页机制只是简单地把线性地址转换成物理地址,并且在物理内存中访问自己的转换表。
来源:CSDN
作者:W.T.F.
链接:https://blog.csdn.net/fcku_88/article/details/103718552