chap3.7_分页模式
为什么要分页
**1. 实模式分段: **
原因: cpu段寄存器太小, 和cpu总线不匹配. ( cpu段寄存器16位,cpu总线20位.)
解决方案:通过 16位段寄存器 , 16位指针寄存器 ,使用2个16位寄存器配合达到20位总线寻址.
段寄存器:此时段寄存器是物理地址的偏移地址。
段地址:此时段地址是实际的物理地址
**2. 保护模式分段: **
原因: 实模式下20位总线,寻址只有1M,需要突破实模式1M内存寻址的限制。保护模式下使用32位总线,寻址可以达到4G,使用到更多内存。
解决方法: 创建全局描述符表, 先根据全局描述符表定位到分段信息,然后根据分段信息定义的起始物理地址 和 当前偏移地址找到实际物理地址。
段寄存器:此时段寄存器是全局描述符表的分段信息的选择子序号。
段地址:此时段地址是实际的物理地址
3. 分页模式:
原因: 实际物理地址存在范围比较小, 且不连续的问题. 碎片化后可使用内存减少。
解决方法: 创建页表,建立虚拟地址和物理地址的映射,加载的是是虚拟地址,然后根据虚拟地址查到物理地址并执行代码
段寄存器:此时段寄存器是全局描述符表的分段信息的选择子序号。
段地址:此时段地址是映射的虚拟地址,需要查找页表转换成实际分配的物理地址。
不同架构的分页机制
32位下分页
32位系统,内存支持到4G,使用二级页表,就可以满足要求了、
64位下分页
64位系统,支持到128G内存,使用二级页表无法满足要求,此时需要使用三级,四级页表了。
Linux采用的四级页表目录的大小有所不同:对于i386而言,仅采用二级页表,即页上层目录和页中层目录长度为0;对于启用PAE的i386,采用了三级页表,即页上层目录长度为0;对于64位体系结构,可以采用三级或四级页表,具体选择由硬件决定。
从上述过程中,可以看出,对虚拟地址的分级解析过程,实际上就是不断深入页表层次,逐渐定位到最终地址的过程,所以这一过程被叫做page talbe walk。
至于这种做法为什么能节省内存,举个更简单的例子更容易明白。比如要记录16个球场的使用情况,每张纸能记录4个场地的情况。采用4+4+4+4,共4张纸即可记录,但问题是球场使用得很少,有时候一整张纸记录的4个球场都没人使用。于是,采用4 x 4方案,即把16个球场分为4组,同样每张纸刚好能记录4组情况。这样,使用一张纸A来记录4个分组球场情况,当某个球场在使用时,只要额外使用多一张纸B来记录该球场,同时,在A上记录”某球场由纸B在记录”即可。这样在大部分球场使用很少的情况下,只要很少的纸即困记录,当有球场被使用,有需要再用额外的纸来记录,当不用就擦除。这里一个很重要的前提就是:局部性。
页目录和页表
1. 一级页表
物理内存分块:
在分页的情况下,将物理内存划分为最小4K (即2^12寻址范围)的内存块。
页表:
4G内存下,使用4G/4K=1048576=1M个页。一个页地址占4个字节,需要1048576 x 页地址4字节 = 4M空间。
页地址:
一个页地址占4个字节,高20位为页号,低12位为物理内存分块的偏移地址
虚拟地址映射:
页地址:
- 高20位:页号(1M)。
- 低12位:物理内存分块的偏移地址(4K)。
物理地址: 虚拟地址 = 页号(高20位) + 物理内存分块的偏移地址(低12位)物理地址 = [ (页起始地址 + 页号 x 页表项大小) -> 物理内存开始地址 ] + 物理内存分块的偏移地址- 页表项大小 :4字节
一级页表存储结构:
| 一级页表 | |
|---|---|
| 0页:高20位页号 | 0页:低12位偏移地址 |
| 1页:高20位页号 | 1页:低12位偏移地址 |
| … | … |
| 1048576页:高20位页号 | 1048576页:低12位偏移地址 |
2. 二级页表
一级页表大小是4M, 占用内存过大。如果把地址拆分开存放,用两个页表来存放地址,每个页表只需要1024K。(第一个表存页开始地址,第二个存物理内存开始地址)。
此时第一个称为页目录,第二个称为页表,页地址大小为4字节。
继续把一级的1M大页表 。拆分开1024 x 1024的页,每个页大小1K x 页地址4字节。
一级页表虚拟地址:1M页地址(20位) + 4K物理分块偏移地址(12位)
二级页表虚拟地址:1K页目录地址(10位) + 1K页地址(10位) + 4K物理分块偏移地址(12位)
页表项:
虚拟地址映射
页地址:
高10位:页目录号(1K)
中10位:页号(1K)
低12位:物理内存分块的偏移地址(4K)。
物理地址:虚拟地址 = 页目录序号(高10位) + 页序号(中10位) + 物理内存分块的偏移地址(低12位)物理地址 = [([页目录表起始地址 + 页目录号 x 页表大小) -> 页表起始地址] + 页号 x 页表项大小 ) -> 物理内存开始地址 ] + 物理内存分块的偏移地址页表大小:4K字节,页表项大小 :4字节。
| 页目录表 | |
|---|---|
| 0目录:高20位页表起始地址 | |
| 1目录:高20位页表起始地址 | |
| … | … |
| 1024页:高20位页表起始地址 | |
| 一级页表(按需分配) | |
| 0页:物理页起始地址 | |
| 1页:物理页起始地址 | |
| … | … |
| 1024页:物理页起始地址 |
为什么要使用多级页表
多级页表优势:
1.可以离散存储页表。
2.在某种意义上节省页表内存空间。
多级页表劣势:
增加寻址次数,从而延长访存时间。
那么使用多级页表比使用以及页表有没有什么劣势呢?
当然是有的。比如:使用以及页表时,读取内存中一页内容需要2次访问内存,第一次是访问页表项,第二次是访问要读取的一页数据。但如果是使用二级页表的话,就需要3次访问内存了,第一次访问页目录项,第二次访问页表项,第三次访问要读取的一页数据。访存次数的增加也就意味着访问数据所花费的总时间增加。
4. 动态分页
一个页表项,寻址范围为4M,16M需要4个页表项,4G需要1024个列表项。
进入分页模式
1. 进入分页模式
代码:
1 | ;------------------ |
2.加载CR3
加载页目录基址到cr3寄存器
1 | mov cr3, edx |
头文件io.h
汇编代码如下:
1 | io_load_page: ;void io_load_page(uint32 pde_address) |