好 我们接下来看看
怎么来建立这个页的映射机制
为了能够理解这个机制
我们首先去了解一下我们整个这个
X86 CPU里面怎么来完成
基于页机制的一个地址映射的
它的硬件操作过程怎么回事
那可以看这幅图
这里面假定已经建好了一个
所谓的页目录表 页表
这一块是它的物理内存
对于一个地址 我们说一个虚拟地址
它分了三块 分了三部分
这实际上是一个典型的二级页表
第一个是Offset这是32位的地址
占了12位 那么中间的二级页表
对应的页表项占了10位
高的页目录项也占了10位
那么高的这10位是用来去查找
作为index查找这个页目录表里面的对应的项
这叫PDE
就是页目录的entry 在PDE记录什么信息
PDE记录的是二级页表里面的起始地址
可以放在这个地方
所以说根据PDE里面的信息
可以找到Page Table的起始地址
同时根据第二级Table这里面的10位
作为index来查这个Page Table对应的项
称之为PTE
这个PTE就是Page Table Entry
它里面存的什么
存的是你这个线性地址
它所对应的一个页的起始地址
这一个页大小多少
其实由它的Offset可以算出来
它12位 那意味着一个页的大小是4K
那这里面PTE里面会存到
这么一个页的起始地址
它会按照4K地址来对齐
那么这个作为Base Address
来加上它Offset
来形成最终的这个物理地址
这就形成了物理地址
这是说在X86里面完成的一个
基于二级页表的一个地址映射关系
那你可以看出来我们的硬件是
这么来查找一个线性地址
怎么转到一个物理地址
那它为什么不是虚拟地址
而称之为线性地址 大家想想
因为我们前面说到了
进入保护模式之后这个段机制是一定存在的
即使这个00映射 我们说的对等映射存在
你也不能说为此把段
这个映射关系给取消掉
这是它必须存在的一个很重要的原因
也是为了上下兼容 所以这是线性地址
那其实这个线性地址和
我们说应用程序虚拟地址是一样的
因为它是对等映射
我们既然知道了这么一个映射关系
我们来看一看 看一个实际的例子
怎么能够把一个所谓的线性地址
或者是虚拟地址转换成一个物理地址
那我们需要建好这个页目录表
需要建好这个页表 以及才能找到对应的页
那么页目录表和页表它其实也是4K大小
那么每一项每一个PTE
或者PTE是32位的一项
那意味着4K存1024项
那我们需要把这里面的信息填对了
才使得对于一个虚拟的地址
这是一个虚拟地址 32位的虚拟地址
0xC后面是1234567
这随便举了一个例子
它这个虚拟地址对应的物理地址多少
可以算出来
它实际上是根据这里面的
PDE PTE来算的
首先来看一下 它的高10位
它的高10位其实是这里面
你数这10项实际上这10项
它其实代表的是304
需要注意了一下这个304
那意味着我们需要查
1024项里面的第0x304项
找到这个地方之后这里面会存一个信息
这个信息比如说存的是0x233
0x233它是按照4K来做一个偏移
偏移了12位 向右偏移12位
所以把它向左再偏移12位
形成0x233000这么一个地址
这个地址实际上是我们说
它存的是Page Table的一个物理地址的基址
找到这个Page Table之后
我们的CPU会查中间10位
中间10位实际上对应的是0x234
234作为index
找到PDE PDE存的什么
存的是0x22333
同样它也是按照4K对齐 右移了12位
所以我们把它通过左移12位
得到正确的你所对应的物理页的基址
就是0x22333后面3个0正好是12位
这是这个物理页的基址
加上它的Offset Offset是它的低12位
0x567 那么合在一起就形成了最终的物理地址
就是0x22333加上567
这就是它的物理地址
所以说可以看到我们需要在lab2里面
来完成对这两个表的建立
从而可以实现正确的映射关系
另外还要提醒一下 就是在这里面存的
就比如说在页表项里面
存放的地址内容是线性地址
那这里面还有一点是
第一个页目录的起始地址在哪儿
这里面其实已经看到了
它是一个特殊的寄存器 称之为CR3寄存器
这个CR3寄存器来保存了
页目录的表的起始地址
那为什么只要一个CR3就够了呢
因为它是二级页表 二级页表里面的
页目录表这个4K的页目录表只有一个
所以我们只需要一个CR3寄存器就够了
好 我们前面已经把页表的映射机制
给大家做了一个介绍
接下来我们可以看看对于页表
或者页目录表里面的一项
到底包含了哪些关键信息 作为一个理解
这里面列出来了页目录表项和页表项
它的一个大致的属性的表示
一共是32位 一个页表项
和一个页目录表项是32位
我们这里面除了关注它
所谓的基址记录之外
还需要关注里面的一些属性位
因为基址 就是存放的无论是页的基址
还是页表的基址
物理页的基址 或者页表的基址都是20位
还有剩下12位形成32位这么一项
那么那12位其实很重要的信息
就是低12位 低12位存了一些属性
就你将来访问页的一些属性
比如说这个页是否是只读的
用R/W位来表示
这个页是内核态访问的还是用户态能访问的
那么有一个U/S 是user还是supervisor
就是属于一般用户访问的
还是超级用户访问的
实际上就对应我们的用户态和内核态
那么其实和我们前面说的
段的安全保护机制有异曲同工之妙
只是说基于段的保护机制它更加灵活
它可以表示一个可大可小的一块区域
到底是属于用户态还是内核态
它的特权级是ring 0 ring 1
ring 2 ring 3它有四级
而对于页表而言 它就两级
就是用户态和内核态 当然这也够了
对我们前面讲到操作系统来说
你只有两级是完全够的
还有其它一些位我们讲内存管理的时候
会再逐步展开
它这些位可以有效的用来
做内存的一些有效的管理
那我们假定你建立好什么 建立好页表
页目录表 都建好了
这是我们ucore操作系统来建立的
建好之后我们要使能页机制
这和我们前面说的段机制是一样的
保护模式一样的
你需要对一个特定的寄存器
这里面是CR0的一个PG寄存器
它最高位 31位
前面是最低位 最低位来enable保护模式
那么我们最高位31位
CR0的寄存器 31位 如果给它置1的话
就代表启动了页机制
这就是这个特殊的寄存器
它是一个需要在内核态访问的一个寄存器
好前面我给大家介绍一下CPU硬件的
一个对内存的页表的机制建立的过程
它的访问过程
那我们操作系统怎么来使这个能正常运作
我们ucore其实为此做了一系列的工作
比如说我们前面说要分配页
因为我们前面已经讲到了
我们的内核以及ucore已经有一套
基于连续内生存的一个
内存分配的一套算法和机制
从而可以说我们分配一个页
分配一个4K来作为一个页目录的一个table
然后再把这个里面的page给清掉
清掉是为了做初始化
然后你需要对除了这个页目录表之外
还要建立对应的页表
来对一定空间的内存来建立对应关系
为此你需要在页目录表和页表里面
填好相应的项
那我们这里面建立的映射关系是什么
0xC0000000到0xF8000000
这块空间会映射到物理地址的
0x00000000到0x38000000这么一个地址
那这个其实是可以看出来
它们的偏移值就是0xC0000000的偏移值
虚拟地址比物理地址要多出来0xC0000000
那实际上映射的是内核空间
使得我们内核态的代码和数据
都是在0xC0000000这个之上的一个空间
那这个和我们在lab2时候
你可以看到它在编译 链接
形成最后的uCore代码的时候
它链接时候用的起始地址就是0xC0000000
这是对应起来的
同时我们又建立了一个很奇怪的一个映射
就是0x00000000-0x00100000虚拟地址
映射到0x00000000-0x00100000这物理地址
这是一个对等映射
按道理说我们建好这个映射就OK了
为什么还要建立一个对等映射
且在enable了
把这个CR0的31位给它置1之后
enable了的页机制之后
我们再次更新了GDT
为什么要update GDT
是由于我们的页机制已经起作用了
页机制来完成从0xC0000000到0的映射
就是0xC0000000是虚拟地址 0是物理地址
这个映射靠页机制完成了
那我们段机制只需要完成对等映射就OK
就0-0映射就行了
那我们说update GDT之后
其实就是让我们段机制映射的关系
从之前的不是那种对等映射变成对等映射
但变成对等映射之后它又做了一次取消操作
就刚才这里面会有一步
就是完成从0到0x100000的映射
这里面又取消了0到0x100000的映射
这个映射是页机制的映射
把它取消了 有点多余好像感觉
做了一步又取消了 为什么
大家思考一下 作为一个练习
大家想一想怎么来解决
那所有的这些代码
是放在pmm.c里面来实现的
这是ucore里面的一个文件
专门属于管理页表机制的
假设我们这个页表建立好了
接下来我可能需要你再去完成
再完成一个特定的内存的映射
这时候你就可能需要去对
这个PTE PDE来做一个处理
甚至还会涉及说
如果我们这个内存它属于
另一块空间我们现在页表
我们现在页表它没有对应到
所以说我们需要干什么建立一个新的页表
这就是我们的一个作业 我们练习
你尝试着给你一个虚拟地址和物理地址
你尝试着能不能分配一个对应的页表项
使得虚拟地址能够正确的
映射到对等的物理地址
这就是我们说在页表里面来建立
页的这个映射关系的这么一个练习
作为我们这个lab2的一个主要的完成部分
需要大家去完成
好我们最后再看一下对于X86而言
它确实比较全面
既包含了段机制 也包含了页机制
虽然我们这里面弱化了段机制这个映射关系
但其实通过这个段和页一个组合
我们可以形成一个更灵活的组织方式
当然在现在操作系统里面主要
还是用页机制来完成了整个的映射
段机制它的作用更多的体现在安全管理上面
那其实即使在安全管理上面
段和页也有一定的重复
在X86里面有一定的重复
所以说可以看到我们会根据
具体的运用情况来了解
好 这是列出来在intel
那个系统软件软件开发手册里面
对应的章节
它对页表机制有更深入的讲解
站在硬件的角度
怎么去便于软件开发人员
去理解这个页机制
可以看一看
好那这就是这一讲的内容 谢谢大家