科技速递|linux内核页表映射机制:线性地址如何转为物理地址?

关注”技术简说“(13站同名) , 带你由浅入深学习linux内核源码 。 linux内核开发100讲免费教程 , 每天晚上9点准时更新 , 敬请收看 。 进我主页点”视频“栏目即可观看 。
在前面《逻辑地址、虚拟地址、线性地址和物理地址大扫盲》一节我们讲到了:
cpu在访问某个逻辑地址的数据的时候需要先把这些逻辑地址转换为线性地址 , 然后再把线性地址转换为物理地址 , 这样才能真正的访问到相应的数据 。 而我们也讲到了在linux系统中 , 逻辑地址跟线性地址是一致的(也可以理解成是相同的) 。 所以逻辑地址转换成物理地址 , 其实就差一个环节了 , 那就是线性地址到物理地址的转换 , 那我们今天就来看这部分内容 。
Linux内核里把线性地址转换成物理地址是通过页表映射来实现的 。 页表映射具体还可以分为二级页表、三级页表等 , 但是原理是相同的 , 三级页表只是比二级页表多了一个中间转换环节而已 。 本文以二级页表的映射机制来做说明 。 原理图如下:
科技速递|linux内核页表映射机制:线性地址如何转为物理地址?二级页表映射机制
名词解释:
Page Directory: 页目录表 , 本文也称一级页表 , 表里的内容叫页目录表项 。
Page Table: 页表 , 本文也称二级页表 , 表里的内容叫页表项 。
本文的讲解以32位系统为例 , 在32位系统中 , 线性地址长度为32 bits , 总大小4G 。
科技速递|linux内核页表映射机制:线性地址如何转为物理地址?线性地址的划分
【科技速递|linux内核页表映射机制:线性地址如何转为物理地址?】从上图可以看出 , linux把32的线性地址划分成了3段:

  • 高10bit:对应上图里的(Dir) , 表示在页目录表内部的偏移 , 用来定位页表的物理地址 。
  • 中间10bite:对应上图里的(Table) , 表示在页表内部的偏移 , 用来定位具体的物理内存的的基地址 。
  • 最低12bit:对应上图里的(Offset) , 刚好表示4K大小 , 用来定位在物理内存某个块里的偏移 。
想想看:从线性地址经过2次查询加上1次汇总 , 是不是就得到相应的物理地址?
科技速递|linux内核页表映射机制:线性地址如何转为物理地址?线性地址到物理地址转换
但是 , 这个时候 , 大家对细节还是不太了解的 , 因为我们还不太清楚这个页目录表(Page Directory)和页表(Page Table)里存的一条一条的都是什么?
科技速递|linux内核页表映射机制:线性地址如何转为物理地址?页目录里表和页表
  • 第一级表称为页目录表(Page Directory) 。 它被存放在1页物理内存中(1页等于4KB大小) , 页目录表里有2^10(1024)个4B长度的页目录表项 。 这些页目录表项指向对应的二级页表的物理地址(其实是物理内存按4k大小统一编号之后的块编号) 。 x86 CPU的CR3寄存器中保存了系统中页目录表的物理地址 。 linux内核有自己的页目录表 , 而每个进程也有自己的页目录表 , 想想看 , CR3切换了页目录表的地址 , 那么cpu对线性地址的解读是不是就不一样了?那么某个相同的线性地址映射的实际的物理地址是不是也就不一样了?所以 , 虽然linux下所有的进程都运行在0x00000000~0xBFFFFFFF这3G的线性地址空间里 , 但是他们访问的物理地址却都是不一样的 。