当前课程知识点:Linux 内核分析与应用 > 第2章 内存寻址 > 2.3分页机制 > Video
大家好
这一讲我们来讲一下保护模式的分页机制
我们知道分页是在分段之后进行的
它的目的是完成从线性地址
到物理地址的转换过程
那么前面我们说段机制呢
它是把虚地址转换成线性地址
而分页机制进一步的呢
把线性地址再转化为物理地址
那么X86规定分页机制是可选的
但是这只是硬件厂家的一厢情愿
很多的操作系统的设计者呢
主要采用的是分页机制
那么什么是分页呢
所谓分页就是将虚拟地址空间
或者说线性地址空间呢
划分成若干个大小相等的片 也称为页
同样的我们对于物理地址空间进行划分
划分成什么样的划分成
与页大小相等的存储块
那么这个地方我们把它称为块或者页面
那么页的大小为多少比较合适
在32位的系统上一般默认的是4K的大小
但是也可以是2MB的大小和4MB的大小
那么在64位系统上就可选项比较多了
从4KB 8KB
最大可以达到256MB
那么 分页的原理是什么呢
我们说分页使得每个进程可以拥有自己独立的虚拟地址空间
为了达到这个目的 CPU在访存的时候 就需要进行
一次地址的变化
也就是说需要把虚地址转化为物理地址
于是我们给出了一个映射函数
Pa=f(va)
这种转化在时间和空间上实际上要付出代价的
因此就必须进行优化
进行哪些方面的优化 实际上进行两方面的优化
一方面就是时间的优化
因为访存很频繁因此呢
映射函数f一定要简单
否则效率就会比较低
所以需要简单的查表算法
这也就是页表引入的原因
那么第二个方面就是空间的优化
因为内存空间是按字节编址的
地址一一进行映射的 话效率实际上是很低的
于是要按照一定的粒度
也就是说页呢进行映射
那么这样的话粒度内的相对地址 也就是页的偏移量呢
在映射的时候就可以保持不变了
那么什么是页表呢?
实际上页表它就是一种影射机制
存放的是什么 存放的是虚拟地址空间
与物理地址空间的一种映射关系
也就是说页号对应的块号
那么页表项是什么样的结构呢
如图为32位的X86的页表项的具体结构
在32位的地址空间
通常页的大小是4KB
这样的话 每个页的起始地址最低12位就是0了
那么这样的话呢我们就可以用高20位表示页的起始地址
而低12位就可以用来表示页的属性
也就是说一个页表项就占四个字节
那么4KB的大小的页就可以存放1K个页表项
那么这里我们特别关注一下页表属性中的P位
也就是存在位
这一位它是来判别缺页的一个重要标志
那么更具体的信息 Intel的手册中都有特别详细的描述
大家手边务必有Intel的手册 那么问题来了
这种结构是由谁来确定的
仅仅是硬件厂家呢
还是os的设计者共同商定的
这个问题就留给大家来思考
那么我们前面给出的页表项是一级页表
如果只用一级页表的话
因为每个页表最大就可以占用
4MB的空间
而且还必须是连续的
这就为内存的分配带来困难 怎么办呢
依然采用分而治之的原则
于是我们将20位分为两部分
分别占十位 这样就形成了两级页表
那么两级页表如何进行地址转换
这张图呢
就是从线性地址到物理地址转换的一张图
下面我们对这张图给予详细的介绍
那么第一步我们就用
最高十位作为页目录项的索引
将它乘以4 4表示
每一个页表项占4个字节
然后与CR3中的页目录的起始地址相加
这样我们就获得相应目录项
在内存的地址
第二步我们从这个地址就开始读取
32位的页目录项
取出其最高的20位
然后再给最低的12位补零
就形成页表在内存的起始地址
第三步呢 我们用中间的十位作为
页表中的页表项的索引
依然将它乘以4
与页表的起始地址相加
获得相应页表项在内存的地址
那么最后一步呢
我们从这个地址开始读取32位的页表项
取出它高20位
再将线性地址的第11到0位呢
放在低12位
最终呢形成32位的页面物理地址
那么这个转换过程听起来很复杂
到底是谁来完成的
是硬件呢还是操作系统
这个问题也抛给大家来思考
那么整个地址转换过程我们看起来是比较复杂的
由于在分页的情况下呢
页表是放在内存中的
这就使得CPU在每次存取一个数据的时候呢
都要至少两次访存
从而大大的降低了访问的速度
所以呢为了提高速度呢
在X86中设置了一个高速缓存硬件机制
也叫做转换旁路缓冲器TLB
那么当CPU访问地址空间的某个地址时候呢
实际上是先检查对应的页表项
是不是在高速缓存中
如果在也就是说命中了
就不必经过两级访存了
如果失败 这个时候再进行两级访存
平均来说呢页面的高速缓存呢
大约有90%的命中率
也就是说每次访存的时候呢
只有10%的情况呢
必须访问两级页表
这就大大的加快了访存的速度
那么Linux中到底是如何分页的呢
这个图就是Linux中的分页机制
那么Linux中主要采用
分页机制来实现虚拟存储器的管理
为什么这么说这是因为有以下两个原因
第一个原因是Linux巧妙的绕过了段机制
第二个原因呢Linux设计的目标之一呢
就是具有可移植性
但是很多CPU并不支持段
目前许多处理器都采用64位的结构了
为了保持这种可移植性呢
Linux目前采用了四级分页模式
为此就定义了四种类型的页表
那么第一级叫页总目录PGD((Page Global Directory))
第二级叫页上级目录PUD(Page Upper Directory)
第三级叫页中间目录PMD(Page Middle Derectory)
那么最低的一级就叫页表PT(Page table)
不管是四级
或者三级页表
那么如何与我们前面所讲的二级页表兼容
Linux内核代码中进行了巧妙的处理
这个需要大家来通过源代码进一步的来理解它
那么源代码中呢
与页表相关的头文件有哪些呢
我们这里列出了五个相关的头文件
大家感兴趣的话 一定要打开这些头文件
来一一查看相关的数据结构
前面我们对分页的原理进行了简单的介绍
那么下面我们通过一个例子 什么样的例子呢
就是分页的初始化的例子 把前面的知识应用起来
在了解了页表的基本原理以后呢
通过代码可以模拟内核的初始化页表的过程
那么在这个代码中我们看到呢
第1到7行呢
是页目录的基地址
偏移量以及页表属性的定义
第14行是在为物理内存的第二个页呢
设置了页目录
然后第9到23行的循环呢
初始化了页目录中的四个页目录项
也就是四个页表
第27到31行呢
循环初始化了四个页表中的第一个页表
也就是说映射了4MB的物理内存
到此页表已经初始化了
那么剩下的工作是什么
就是将页目录的地址呢
传递给CR3寄存器
这是由第33到38行的嵌入式汇编代码来完成的
并且设置了CR0寄存器中的
分页允许位
虽然上述的代码比较简单
但却描述了页表初始化的整个过程
以此为模型呢我们可以很容易地理解
Linux内核中关于页表的代码
最后我们需要动手实践
那么在Linux内核之旅网站的电子杂志栏目的第二期呢
i386体系结构下呢
实现了一个最短小的可启动内核
一是为了加深大家对X86体系的了解
第二是演示了系统开发的原始过程
大家可以下载代码并进行调试
那么最后我们给出参考资料
大家可以参考
《深入理解Linux内核》的第二章
以及Intel的64位和32位的手册
那么最后给大家抛出一个问题
我们说页的大小不仅仅只有4KB
还可以是4M或者更大的
那么在海量内存中如何使用大页内存
这个问题留给大家来思考
谢谢大家
-1.1 Linux操作系统概述
-1.2 Linux内核结构以及内核模块编程
--Video
-1.3 Linux内核源码中的双链表结构
--Video
-1.4 源码分析-内核中的哈希表
--Video
-1.5 动手实践-Linux内核模块的插入和删除
--Video
-第1章 概述--章节测验
-2.1 内存管理之内存寻址
--Video
-2.2 段机制
--Video
-2.3分页机制
--Video
-2.4 动手实践-把虚拟地址转换成物理地址
--Video
-第2章 内存寻址--章节测验
-3.1 进程概述
--Video
-3.2 Linux进程创建
--Video
-3.3 Linux进程调度
--Video
-3.4 动手实践-打印进程描述符task_struct中的字段
--Video
-3.5工程实践-基于内核模块的负载监控
--Video
-第3章 进程管理--章节测验
-4.1 Linux内存管理机制
--Video
-4.2 进程用户空间管理机制
--Video
-4.3 物理内存分配与回收机制(上)
--Video
-4.4 物理内存分配与回收机制(下)
--Video
-4.5 动手实践-Linux内存映射基础(上)
--Video
-4.6 动手实践-Linux内存映射实现(中)
--Video
-4.7 动手实践-Linux内存映射测试(下)
--Video
-4.8 初学者对内存管理的常见疑惑
-第4章 内存管理--章节测验
-5.1 中断机制概述
--Video
-5.2 中断处理机制
--Video
-5.3 中断下半部处理机制
--Video
-5.4 时钟中断机制
--Video
-5.5 动手实践-中断上半部的代码分析及应用
--Video
-5.6 动手实践-中断下半部的代码分析及应用
--Video
-第5章 中断--章节测验
-6.1 Linux中的各种API
--Video
-6.2 系统调用机制
--Video
-6.3 动手实践-添加系统调用(系统调用日志收集系统)
--Video
-第6章 系统调用--章节测验
-7.1 内核同步概述
--Video
-7.2 内核同步机制
--Video
-7.3 动手实践-内核多任务并发实例(上)
--Video
-7.4 动手实践-内核多任务并发实例(下)
--Video
-第7章 内核同步--章节测验
-8.1 虚拟文件系统的引入
--Video
-8.2 虚拟文件系统的主要数据结构
--Video
-8.3 文件系统中的各种缓存
--Video
-8.4 页高速缓存机制以及读写
--Video
-8.5 动手实践-编写一个文件系统(上)
--Video
-8.6 动手实践-编写一个文件系统(中)
--Video
-8.7 动手实践-编写一个文件系统(下)
--Video
-第8章 文件系统--章节测验
-9.1 设备驱动概述
--Video
-9.2 I/O空间管理
--Video
-9.3 设备驱动模型
--Video
-9.4 字符设备驱动程序简介
--Video
-9.5 块设备驱动程序简介
--Video
-9.6 动手实践-编写字符设备驱动程序
--Video
-9.7工程实践-编写块设备驱动的基础(上)
--Video
-9.8 工程实践-块设备驱动程序分析(中)
--Video
-9.9 工程实践-块设备驱动程序实现(下)
--Video
-第9章 设备驱动--章节测验
-致谢与说明
--Video