关注”技术简说“(13站同名),带你由浅入深学习linux内核源码。linux内核开发100讲免费教程,每天晚上9点准时更新,敬请收看。进我主页点”视频“栏目即可观看。
在前面《逻辑地址、虚拟地址、线性地址和物理地址大扫盲》一节我们讲到了:
cpu在访问某个逻辑地址的数据的时候需要先把这些逻辑地址转换为线性地址,然后再把线性地址转换为物理地址,这样才能真正的访问到相应的数据。而我们也讲到了在linux系统中,逻辑地址跟线性地址是一致的(也可以理解成是相同的)。所以逻辑地址转换成物理地址,其实就差一个环节了,那就是线性地址到物理地址的转换,那我们今天就来看这部分内容。
Linux内核里把线性地址转换成物理地址是通过页表映射来实现的。页表映射具体还可以分为二级页表、三级页表等,但是原理是相同的,三级页表只是比二级页表多了一个中间转换环节而已。本文以二级页表的映射机制来做说明。原理图如下:
二级页表映射机制
名词解释:
Page Directory: 页目录表,本文也称一级页表,表里的内容叫页目录表项。
Page Table: 页表,本文也称二级页表,表里的内容叫页表项。
本文的讲解以32位系统为例,在32位系统中,线性地址长度为32 bits,总大小4G。
线性地址的划分
从上图可以看出,linux把32的线性地址划分成了3段:
- 高10bit:对应上图里的(Dir),表示在页目录表内部的偏移,用来定位页表的物理地址。
- 中间10bite:对应上图里的(Table),表示在页表内部的偏移,用来定位具体的物理内存的的基地址。
- 最低12bit:对应上图里的(Offset),刚好表示4K大小,用来定位在物理内存某个块里的偏移。
想想看:从线性地址经过2次查询加上1次汇总,是不是就得到相应的物理地址?
线性地址到物理地址转换
但是,这个时候,大家对细节还是不太了解的,因为我们还不太清楚这个页目录表(Page Directory)和页表(Page Table)里存的一条一条的都是什么?
页目录里表和页表
- 第一级表称为页目录表(Page Directory)。它被存放在1页物理内存中(1页等于4KB大小),页目录表里有2^10(1024)个4B长度的页目录表项。这些页目录表项指向对应的二级页表的物理地址(其实是物理内存按4k大小统一编号之后的块编号)。x86 CPU的CR3寄存器中保存了系统中页目录表的物理地址。linux内核有自己的页目录表,而每个进程也有自己的页目录表,想想看,CR3切换了页目录表的地址,那么cpu对线性地址的解读是不是就不一样了?那么某个相同的线性地址映射的实际的物理地址是不是也就不一样了?所以,虽然linux下所有的进程都运行在0x00000000~0xBFFFFFFF这3G的线性地址空间里,但是他们访问的物理地址却都是不一样的。
- 第二级表称为页表(page table),它也被存放在1页物理内存中(1页等于4KB大小),最多含有2^10(1024)个4B的页表项。每个页表项含有相关页面的20位物理基地址(其实就是物理内存块编号)。二级页表使用线性地址中间10位(位21~12)作为页表项索引值,以获取含有页面20位物理基地址的表项。该20位页面物理基地址和线性地址中的低12位(页内偏移)组合在一起就得到了分页转换过程的输出值,即对应的最终物理地址。
我们刚刚讲过页目录表(一级页表)里保存的是1024个页目录表项,二级页表里保存的是1024个页表项,而且每个页目录表项和页表项的大小都是4个字节。那这些页目录表项和页表项的格式怎样的呢?
P-- 位0,是存在(Present)标志,用于指明表项对地址转换是否有效。P=1表示有效;P=0表示无效。在页转换过程中,如果说涉及的页目录或页表的表项无效,则会导致一个异常。
R/W--位1,是读/写(Read/Write)标志。如果等于1,表示页面可以被读、写或执行。如果为0,表示页面只读或可执行。当处理器运行在超级用户特权级(级别0、1或2)时,则R/W位不起作用。页目录项中的R/W位对其所映射的所有页面起作用。
U/S--位2是用户/超级用户(User/Supervisor)标志。如果为1,那么运行在任何特权级上的程序都可以访问该页面。如果为0,那么页面只能被运行在超级用户特权级(0、1或2)上的程序访问。页目录项中的U/S位对其所映射的所有页面起作用。
A--位5是已访问(Accessed)标志。当处理器访问页表项映射的页面时,页表表项的这个标志就会被置为1。当处理器访问页目录表项映射的任何页面时,页目录表项的这个标志就会被置为1。处理器只负责设置该标志,操作系统可通过定期地复位该标志来统计页面的使用情况。
D--位6是页面已被修改(Dirty)标志。当处理器对一个页面执行写操作时,就会设置对应页表表项的D标志。处理器并不会修改页目录项中的D标志。
AVL--该字段保留专供程序使用。处理器不会修改这几位,以后的升级处理器也不会。
高20位是物理地址页面的基地址。
转换过程
cpu先将32位线性地址分为三段,高10位,中间10位,低12位。
- 用高10位的值作为索引在页目录表里找到相应的页目录表项,页目录表项里记录了二级页表的物理地址
- 用中间10位的值作为索引在二级页表(步骤1得到了二级页表的物理地址)里找到相应的物理内存基地址。
- 物理内存的基地址左移12位加上线性地址的低12位,就得到了最终的物理地址。
缺页
在需要访问某一个页表或页面时,首先要检查P位,若P为1,表明该页表或页面存在于物理存储器中,则可以直接访问它们。若P为0,表明该页表或页面不在物理存储器中,这时分页机制将发出缺页中断信号,引起操作系统进入中断处理例程,把所需的页面从外存(比如磁盘)调入内存。
需要指出,80x86处理器在P位为0时,对页表和页目录表的表项其它位不做任何解释,此时这些位可以由软件自行使用和解释, Linux就利用此特性,在其它位中存放该页面在交换空间的地址。
当新页面调入物理内存时,若没有空闲的物理页面可用,需要从该进程占用的物理页面中选择某一页淘汰,选中某一页面淘汰时,需要检查D位,当D为1时,表明该页面已被修改过,需要把它写回外存。D=0时,表明该页面未曾修改,可以直接淘汰而不需写回外存,访问位A可以用于实现页面淘汰的有关算法。
关注”技术简说“(13站同名),带你由浅入深学习linux内核源码。linux内核开发100讲免费教程,每天晚上9点准时更新,敬请收看。进我主页点”视频“栏目即可观看。
,