《真象还原》读书笔记——第五章 保护模式进阶,向内核迈进(内存分页机制)

5.2 启用内存分页机制,畅游虚拟空间

为了让每个进程都能用到4GB。

5.2.1 内存为什么要分页

  1. 为了让碎片内存也得以利用。
  2. 为了让不连续的碎片内存也得以连续。

办法:通过映射关系,将(连续的)线性地址映射到任意物理地址。

5.2.2 一级页表

分页是建立在分段的基础上。必须先分段,后分页
内存分段机制下地址访问
如果N,则按线性地址
如果Y,则按虚拟地址
分页机制

分页机制的作用有两个方面
  • 将线性地址转换成物理地址(通过线性地址寻找到对应的物理地址)
  • 用大小相等的页代替大小不等的段
    分页机制的作用
    逐字节对应的情况:
    结果:得不偿失
    页表于物理内存关系示意
    干脆将32为地址分为两部分,数量单位此处的32位数是页的地址。存放的是内存地址
    例如:6000,分为6和k。

寻找合适的页尺寸
这里的内存块,官方称为。按照合适的划分,以12为界限。
0~11为4KB,12位,是一个页指向一块大小为0x1000的内存,该内存地址范围为4KB/0x1000。
12~31为1MB,20位,是一个页表中页的数量。一个页表中有1MB个页,即1048576个页。

这就是一级页表
页表及页表项

  1. 页表地址放到控制寄存器CR3中。
  2. 查找页用cr3+高20位索引*4,乘以4是因为每个页表项4字节。得到的结果即是对应页表项的地址了。
  3. 从找到的页表项中读取内存地址与页表项自身地址的低12位相加。就是该表的范围内的指向的内存地址

总结:用线性地址的高20位在页表中索引页表项,用线性地址的低12位于页表项中的物理地址相加,和就是线性地址对应的物理地址。
举例:mov ax,[0x1234]
通过一级页表将线性地址转换成物理地址过程

5.2.3 二级页表

为什么要建二级页表?
答:

  1. 一级页表,20位索引,最多1MB个页,一个页表项占4字节大小。所以一个页表共占4MB大小。
  2. 一级页表必须提前建好。
  3. 每一个进程都有自己的页表,大量进程导致页表占用空间巨大。

总结:一次性将页表建立好,需要动态创建页表
页表
页表和页目录表都在物理内存中。
页目录表中有1024=2^10 个页目录项,一个页目录项指向一个页表,一个页表中有1024=2^10 个页表项。
也就是一共的2^20个页表项。但页目录表和页表处于线性物理地址中
二级页表占用内存示意
页目录表中一共1024个页表,所以只要10位(31~22位)就能全部遍历。
页表中有1024个项,所以用10位(21~12位)就能锁定。
标准页的4K就由剩下的12位(11~0位)用于页内偏移量。
因为每一项都是4字节,所以计算索引偏移地址时候都要乘以4.

  1. 虚拟地址高10位*4得到页目录表内的偏移地址,加上页目录表的基地址,得到的就是页目录项的物理地址。
  2. 虚拟地址中10位*4得到页表内的偏移地址,加上页表物理基地址,得到的就是页表项的物理地址。
  3. 低12位不是索引了,所以不用*4 ,范围为0~0xfff,作为页内便宜最合适。
  4. 由第二步得到的物理地址加上第三步得到的偏移地址,和为最终的物理地址。

举例:mov ax, [0x1234567]
二级页表虚拟地址到物理地址转换
这种自动化的工作会由页部件自动完成。

每个进程都有自己的页表

每个进程都有自己的虚拟空间

页目录项,页表项的结构页目录项及页表项
PPresent存在位1:该页存在于物理内存中,0:不存在物理内存中
RWRead/Write读写1:可读可写,0:可读不可写
USUser/Supervisor普通用户/超级用户1:User,0,1,2,3都可以访问。若为0,表示处于Supervisor级,特权级别为3的程序不允许访问该页,只允许等级为0,1,2的程序可以访问。
PWTPage-level Write-Through页级通写位1:此项采用通写方式,表示该页不仅是普通内存,还是高速缓存。书中认为在此填0就好了。
PCDPage-level Cache Disable页级告诉缓存禁止位1:启用高速缓存,0:禁止将该页缓存。书中先设置为0
AAccessed访问位1:该页被CPU访问过了。0:与1相反。
DDirty脏页位对一个页面执行写操作时候,就会设置对应页表项D位为1.只对页表项有效
PATPage Attribute Table页属性表位能够在页面一级的粒度上设置内存属性。该位置书中设置0
GGlobal全局位1:全局页,0:非全局页
AVLAvailabel表示可用表示软件可以用
启用分页机制,按顺序做好三件事
  1. 准备页目录表和页表
  2. 将页表地址写入控制寄存器CR3(CR3又称页目录基质寄存器)。
  3. 寄存器CR0的PG位置1
    页目录基质寄存器PDBR
    可以设置低12位全为0,只需要将高20位写入CR3寄存器即可。
    cr3赋值。mov指令中控制寄存器与通用寄存器互传数据的格式:mov cr[0~7],r32或mov r32,cr[0 ~ 7].
    启动第三步中,启动分页机制的开关是将控制寄存器cr0的PG位置1,PG位即是cr0的最后一位:31位。将PG位置1后就进入内存分页运行机制,段部件输出的线性地址变成虚拟地址。

5.2.4 规划页表之操作系统与用户进程关系

进程共享操作系统:
进程共享操作系统与完整的程序
我们学习linux的做法:
用户进程4GB中,3GB以上到4GB的部分给操作系统,0~3GB给用户进程自己。

5.2.5 用分页机制

开始布局:为了方便起见,将页目录表放在最下面,依次往上加页表。
页目录表基址定为0x100000,经过计算第一个页表的基址为0x101000 如图5-21。
页目录表页页表的关系布局

代码部分

为了避免混乱。MBR.asm,loader.asm,boot.inc都放在这篇文章中了
代码运行结果分页操作后的运行结果界面

5.2.6 用虚拟地址访问页表

页表是动态的数据结构,需要动态增删。

  • 申请内存时,需要增加页表项或是页目录项
  • 释放内存时,需要清零页表项或是页目录项。
虚拟地址映射情况

左边是32为位虚拟地址范围,右边是虚拟地址对应的物理地址。
虚拟地址映射情况

第一行虚拟地址 0x0000 0000~0x000F FFFF虚拟空间低端1MB内存
第二行虚拟地址 0xC000 0000~0xC00F FFFF第768个页表,即是操作系统所占的最上层的1GB的第一个页表
第三行虚拟地址 0xFFC0 0000~0xFFC0 0FFF最后一个页目录项指向的正是页目录的基址
第四行虚拟地址 0xFFF0 0000~0xFFF0 0FFF第768个页目录项,也就是1024个目录项的3/4的末尾项指向的和第三行一样。
第五行虚拟地址 0xFFFF F000~0xFFFF FFFF先找到最后一个页目录项,然后找到该目录指向的页表(其实指向的是本目录),又找到了最后一项(其实又转回来了还是本目录)。最后的低12位为0x000,所以得到的最终结果就是本目录的基址。

根据第五行的情况,就可以用0xFFFF Fxxx的方式更改页目录项。12位的范围就是4K,所以使用时不用再乘以4。

总结下用虚拟地址获取页表中各种数据类型的方法
  • 获取页目录表物理地址:让虚拟地址的高20位0xFFFFF,低12位为0x000,即0xFFFF F000,这也是页目录表中的第0个页目录项自身的物理地址
  • 访问页目录中的页目录项,即获取页表物理地址:要使虚拟地址为0xFFFF FXXX,其中XXX是页目录项的索引乘以4的积
  • 访问页表中的页表项:使虚拟地址高10位为0x3FF,目的是获取页目录表物理地址。中间10位页表索引,最后12位也表内偏移地址。
    公式为:0x3FF<<22+中间10位<<12+低12位。

5.2.7 块表TLB(Translation Lookaside Buffer)简介

为了快速查找到虚拟地址对应的物理地址。
TLB的更新靠操作系统开发人员。
重载CR3会间接更新TLB。还有invlpg指令,例如更新虚拟地址0x1234对应的条目,用invlpg[0x1234]。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值