酒店 网站构建,电商货源网站大全,现代网站建设,企业做网站需要什么资料前言
在段式内存中#xff0c;当申请内存的时候就划分一块内存给它#xff0c;假如一个空间有4096MB大小内存#xff0c;实际使用了3000MB#xff0c;假如想运行一个程序是1024MB大小的看起来是能满足#xff0c;但是数据段或者代码段对于内存的要求必须是连续了#xf…前言
在段式内存中当申请内存的时候就划分一块内存给它假如一个空间有4096MB大小内存实际使用了3000MB假如想运行一个程序是1024MB大小的看起来是能满足但是数据段或者代码段对于内存的要求必须是连续了实际的物理内存占用是非常碎片化的所以不一定能满足这个程序的要求。
为了解决这个问题提出了分页的管理方式。把内存切分成等大的页面常见的页面大小是4096也就是2^12字节这就是一个访问单位。 寻找一个分页只需要知道高20位就可以了低12位可以忽略全是0。4GB可以分为2^20个4KB的分页把分页的高20位保存起来同时每一个分页还有一些属性比如分页的计算单位、读写属性等,也保存起来。
页地址和页属性用4个字节保存起来每4个字节作为一个内存分页的入口成为PTE/Page Table Entrance,而这些一个个分页的入口组成了一个表叫页表Page Table。页表就像一本书一样可以寻找到每一个4kb的内存分页页表作为内存的目录也存放在内存中。4GB的内存可以分为2^20 个4kb的分页每个分页入口占4个字节页表一共会占据2^20* 2^24MB。
这4MB会分页存放4MB/4KB 1024,这1024个分页就是一个个页表里面保存的就是其他内存分页入口但是这1024个页表可能是随机存放了所以为了找到这些页表增加了一个页表目录页表目录存放页表的入口一共1024个入口每个入口占4个字节1024* 4 4096刚好是一个标准页的大小。
内存分页页表和页表目录就构成了一个三层的内存管理组织结构当我们想寻找某个具体页的时候就在页目录里面找页表再到页表里找具体的页有个专门的寄存器CR3来保存页目录的内存地址类似GDTR的作用。
CPU加载内存段的过程
在保护模式下段描述符是内存段的身份证。 CPU 在引用一个段时都要先查看段描述符。很多时候段描述符存在于描述符表中 GDT 或 LDT但与此对应的段并不在内存中也就是说CPU 允许在描述符表中已注册的段不在内存中存在这就是它提供给软件使用的策略我们利用它实现段式内存管理。如果该描述符中的 P 位为 1 表示该段在内存中存在。访问过该段后CPU 将段描述符中的 A 位置 l 表示近来刚访问过该段。
相反如果 P 位为 0说明内存中并不存在该段这时候 CPU 将会抛出个 NP 段不存在异常转而去执行中断描述符表中 NP 异常对应的中断处理程序此中断处理程序是操作系统负责提供的该程序的工作是将相应的段从外存比如硬盘中载入到内存并将段描述符的 P 位置 1 中断处理函数结束后返回 CPU 重复执行这个检查继续查看该段描述符的 P 位此时已经为 1 了在检查通过后将段描述符的 A 位置 1 。
段描述符的 A 位由 CPU 置 l 但清 0 工作可是由操作系统来完成的。此位干吗用的呢操作系统每发现该位为 1 后就将该位清 0这样一来在一个周期内统计该位为 1 的次数就知道该段的使用频率了从而可以找出使用频率最低的段。
当物理内存不足时可以将使用频率最低的段换出到硬盘以腾出内存空间给新的进程。当段被换出到硬盘后操作系统将该段描述符的 P 位置 0。
当下次这个进程上 CPU 运行后如果访问了这个段这样程序流就回到了刚开始 CPU 检查出 P 位为 0、紧接着抛出异常、执行操作系统中断处理程序、换入内存段的循环。
一级页表
CPU 在不打开分页机制的情况下是按照默认的分段方式进行的段基址和段内偏移地址经过段部件处理后所输出的线性地址CPU 就认为是物理地址。如果打开了分页机制段部件输出的线性地址就不再等同于物理地址了我们称之为虚拟地址它是逻辑上的是假的不应该被送上地址总线。
经过段部件处理后保护模式的寻址空间是 4GB注意这个寻址空间是指线性地址空间它在逻辑上是连续的。分页机制的思想是通过映射可以使连续的线性地址与任意物理内存地址相关联逻辑上连续的线性地址其对应的物理地址可以不连续 。 操作系统在分页机制下加载进程的过程
从线性空间到虚拟空间再到物理地址空间每个空间大小都是 4GB图上的 4GB 物理地址空间属于所有进程包括操作系统在内的共享资源当前进程只能使用未分配页。此转换过程对任意一个进程都是一样的也就是说每个进程都有自己的 4GB 虚拟空间。
每加载一个进程操作系统按照进程中各段的起始范围在进程自 己的 4GB 虚拟地址空间中寻找可用空间分配内存段此虚拟地址空间可以是页表也可以是操作系统维护的某种数据结构总之此阶段的分配是逻辑上的并没有真正写入物理内存。
在分页机制下代码段和数据段在逻辑上被拆分成以页为单位的小内存块。这时的虚拟地址虚如其名不能存放任何数据。接着操作系统开始为这些虚拟内存页分配真实的物理内存页它查找物理内存中可用的页然后在页表中登记这些物理页地址这样就完成了虚拟页到物理页的映射每个进程都以为自己独享 4GB 地址空间。
页表与物理地址映射
用页表来存放映射关系页表就是个 N 行l 列的表格页表的每一行称为页表项PTE其大小是4个字节。页表项的作用是存储内存的物理地址。当访问一个线性地址时实际上就是在访问页表项中所记录的物理内存地址。
32 位地址表示 4GB 空间4G空间可以划分为4G个内存块每个内存块的大小是1个字节。可以将 32 位地址分成高低两部分低地址部分是内存块大小高地址部分是内存块数量它们是这样一种关系内存块数内存块大小4GB。这里所说的内存块叫页只要是4KB的地址空间都可以称为一页这样一来4GB 地址空间被划分成 4GB/4KBlM 个页也就是 4GB 空间中可以容1048576 个页页表中自然也要有 1048576 个页表项。
由于页大小是4KB所以页表项中的物理地址都是4K的整数倍 故用十六进制表示的地址低 3 位都是 0。在 32 位保护模式下任何地址都是用 32 位二进制表示的包括虚拟地址也是。虚拟地址的高20 位可用来定位一个物理页低 12 位可用来在该物理页内寻址。
一个页表项对应一个页所以用线性地址的高 20 位作为页表项的索引每个页表项要占用 4 字节大小所以这高 20 位的索引乘以 4 后才是该页表项相对于页表物理地址的字节偏移量。
用 cr3 寄存器中的页表物理地址加上此偏移量便是该页表项的物理地址从该页表项中得到映射的物理页地址然后用线性地址的低 12 位与该物理页地址相加所得的地址之和便是最终要访问的物理地址。
举个例子
mov ax, [0x1234]假设是在平坦模型下工作不管段选择子值是多少其所指向的段基址都是 0指令 mov ax[0x1234]中的0x1234 称为有效地址它作为“段基址段内偏移地址”中的段内偏移地址。
这样段基址为 0段内偏移地址为 0x1234经过段部件处理后输出的线性地址是 0x1234。当线性地址 0x1234被送入了页部件。页部件分析 0x1234的高20 位用十六进制表示高 20 位是 0x00001。将此项作为页表项索引再将该索引乘以 4 后加上 cr3 寄存器中页表的物理地址这样便得到索引所指代的页表项的物理地址从该物理地址处页表项中〉读取所映射的物理页地址 Ox9000 。线性地址的低12 位是 0x234 它作为物理页的页内偏移地址与物理页地址。与0x9000 相加为 Ox9234这就是线性地址 0x1234 最终转换成的物理地址。 二级页表
一级页表中最多可容纳 IM ( 1048576 个页表项每个页表项是 4 字节如果页表项全满的话便是 4MB大小。一级页表中所有页表项必须要提前建好原因是操作系统要占用 4GB 虚拟地址空间的高 1GB,用户进程要占用低 3GB 。
我们要的是不要一次性地将全部页表项建好需要时动态创建页表项 。
无论是几级页表标准页的尺寸都是 4KB这一点是不变的。所以 4GB 线性地址空间最多有 1M 个标准页 。 一级页表是将这 1M 个标准页放置到一张页表中二级页表是将这 1M个标准页平均放置 1K个页表中 。
每个页表中包含有 lK 个页表项。页表项是 4 字节大小页表包含 lK 个页表项故页表大小为4KB这恰恰是一个标准页的大小。 页目录表中共 1024 个页表也就是有 1024 个页目录项 。一个页目录项中记录一个页表物理页地址物理页地址是指页的物理地址在页目录项及页表项中记录的都是页的物理地址页大小都 是 OxlOOO 即 4096 因此页地址是以 000 为结尾的十六进制数字 。
每个页表中有 1024 个页表项每个页表项中是一个物理页地址最终数据写在这页表项中指定的物理页中。页表项中分配的物理页地址在真正物理内存中离散分布毫无规律可言 操作系统负责这些物理页的分配与释放。由于页目录表和页表本身都要占用内存且为 4KB大小故它们也会由操作系统在物理内存中分配一物理页存放 。
虚拟地址到物理地址转换
二级页表地址转换原理是将 32 位虚拟地址拆分成高 10 位、中间10位、低 12 位三部分它们的作用是
高 10 位作为页衰的索引用于在页目录表中定位一个页目录项 PDE页目录项中有页表物理地址也就是定位到了某个页表。中间 10 位作为物理页的索引用于在页表内定位到某个页表项 PTE页表项中有分配的物理页地址也就是定位到了某个物理页。低 12 位作为页内偏移量用于在已经定位到的物理页内寻址。
具体步骤
用虚拟地址的高10 位乘以 4作为页目录表内的偏移地址加上页目录表的物理地址所得的和便是页目录项的物理地址。读取该页目录项从中获取到页表的物理地址。用虚拟地址的中间1 0 位乘以 4作为页表内的偏移地址加上在第1 步中得到的页表物理地址所得的和便是页表项的物理地址。读取该页表项从中获取到分配的物理页地址。虚拟地址的高 10 位和中间 10 位分别是 PDE 和 PIE 的索引值所以它们需要乘以 4。但低 12 位就不是索引值啦其表示的范围是 0Ox筒作为页内偏移最合适所以虚拟地址的低12 位加上第 2 步中得到的物理页地址所得的和便是最终转换的物理地址。
举个例子
进入保护模式后通过段选择子加偏移地址的方式就能找到每一个字节举个例子Offset 0x7F9A45D3 加上起始地址 0x 0000 000 0x7F9A45D3就是实际的物理地址而开启分页机制之后0x7F9A45D3并不是物理地址而是一个虚拟的地址 将这个地址拆成3部分。 CR3寄存器保存了页目录的起始内存地址B页目录和页表都是保存在标准页里所以它们的地址都是4K对齐的假设B 0x 00010000只要低12位是0就是4K字节对齐高10位页表编号是T中10位的内存页编号是P低12位偏移地址是O。
1.计算页表地址页目录的起始地址是B页表编号是T每个页表在页目录中占4个字节B T*4 就是页表项0x 00010000 0x1FE *4 0x 000107F8,这个地址是实际的物理地址从0x 000107F8开始往后的4个字节就保存了页表项的地址和属性把高20位拿出来假设为0x00023低12位补0得到0x00023000,这个值是计算内存页的基地址
2.计算内存页地址内存页编号0x1A4每个内存页在页表中占4个字节用内存页的基地址0x00023000加上P*4得到0x00023690从0x00023690开始往后4个字节保存内存页的地址和属性把高20位拿出来假设为0x00035低12位补0得到0x00035000。
3.计算实际内存地址0x00035000加上O 0x5D30X 000355D3这个就是实际访问的物理地址。可以看看下面的图方便理解 页目录项和页表项 1.P, Present意为存在位。若为 1 表示该页存在于物理内存中若为 0 表示该表不在物理内存中。操作系统的页式虚拟内存管理便是通过 P 位和相应的 pagefault异常来实现的。 2.RW, Read/Write意为读写位 。若为 1 表示可读可写若为 0 表示可读不可写。 3.US, User/Supervisor意为普通用户超级用户位。若为 1 时表示处于 User 级任意级别 0 、l 、2 、3 特权的程序都可以访问该页若为 0表示处于 Supervisor 级特权级别为 3 的程序不允许访问该页该页只允许特权级别为 0、l 、2 的程序可以访问。 4.PWT, Page-level WriteThrough意为页级通写位也称页级写透位 。 若为 1 表示此项采用通写方式表示该页不仅是普通内存还是高速缓存。此项和高速缓存有关“通写”是高速缓存的一种工作方式本位用来间接决定是否用此方式改善该页的访问效率 。 这里直接置为0就可以。 5.PCD, Page-level Cache Disable意为页级高速缓存禁止位 若为 1 表示该页启用高速缓存为 0 表示禁止将该页缓存。这里咱们将其置为0 。 6.A, Accessed意为访问位。若为 1 表示该页被 CPU 访问过啦所以该位是由 CPU设置的。还记得段描述符中的 A 位和 P 位吗这两位在一起可以实现段式虚拟内存管理。和它们一样这里页目录项和页表项中的 A 位也可以用来记录某一 内存页的使用频率操作系统定期将该位清 0统计一段时间内变成 1 的次 数从而当内存不足时可以将使用频率较低的页面换出到外存如硬盘同时将页目录项或页表项的 P位置 0下次访问该页引起 pagefault 异常时中断处理程序将硬盘上的页再次换入同时将 P 位置 l. 7.D, D让ty意为脏页位。当 CPU 对一个页面执行写操作时就会设置对应页表项的 D 位为l 。 此项仅针对页表项有效并不会修改页目录项中的 D 位。 8.PAT, Page Attribute Table意为页属性表位能够在页面一级的粒度上设置内存属性 。比较复杂将此位置0即可 。 9.G;Global意为全局位 。 由于内存地址转换也是颇费周折先得拆分虚拟地址然后又要查页目录又要查页表的所以为了提高获取物理地址的速度将虚拟地址与物理地址转换结果存储在 TLB (TrnnslationLookaside Buffer 中TLB 是用来缓存地址转换结果的高速缓存 。此 G 位用来指定该页是否为全局页为 1 表示是全局页为 0 表示不是全局页。若为全局页该页将在高速缓存 TLB 中一直保存给出虚拟地址直接就出物理地址啦无需那三步骤转换。由于 TLB 容量比较小 一般速度较快的存储设备容量都比较小所以这里面就存放使用频率较高的页面。清空 TLB 有两种方式一是用 invlpg 指令针对单独虚拟地址条目清理或者是重新加载 cr3 寄存器这将直接清空 TLB 。 10.AVL意为 Available 位表示可用谁可以用当然是软件操作系统可用该位CPU 不理会该位的值。
启用分页机制我们要按顺序做好三件事
准备好页目录表及页表。将页表地址写入控制寄存器 cr3 。寄存器 cr0的 PG 位置1 。
控制寄存器 cr3 用于存储页表物理地址所以 cr3 寄存器又称为页目录基址寄存器。 由于页目录表所在的地址要求在一个自然页内即页目录的起始地址是 4阻的整数倍低 12 位地址全是 0。所以只要在 cr3 寄存器的第 31 12 位中写入物理地址的高 20 位就行了。另外cr3 寄存器的低 12 位中除第 3 位的 PWT 位和第 4 位的 PCD 位外其余位都没用。 PWT 位和 PCD 位它们用于设置高速缓存相关的特性在此将其置为 0 即可。这样一来低 12 位全部为 0故只需要把页目录表物理地址的高 20 位写入 cr3 寄存器即可。 启动分页机制的开关是将控制寄存器 crO 的 PG 位置1,PG 位是 cr0寄存器的最后一位第 31 位。PG位为1后便进入了内存分页运行机制段部件输出的线性地址成为虚拟地址顺便说一下第 0 位是 PE位用来进入保护模式的开关。在将 PG 位置1 之前系统都是在内存分段机制下工作段部件输出的线性地址便直接是物理地址也就意味着在第 2 步中cr3 寄存器中的页表地址是真实的物理地址。