在图中有个页表基址寄存器,这个是存储在每个进程的mm_struct中的一个字段,叫pgd,它指明了这个进程的页表在存储器中的地址,要是把页表看作是个数组的话,那么它就相当于是个数组首地址。上面说了页大小为4K,所以对一个页来说地址中的低12位是被屏蔽的,这12位就是地址中的偏移量,我们在上图看到,地址中的偏移量是不经过任何操作直接从虚拟地址复制到物理地址中的。
在上面也出现了一个有效位,它主要是检测我们当前需要转换的虚拟页面在存储器中是否有相应的物理页面与它对应,若有则进行查找,否则就会引发一个缺页异常。
缺页异常
当某个可执行文件映像映射到进程用户空间中并开始执行时,因为只有很少一部分虚拟页面装入到了物理内存,可能会遇到所访问的数据不在物理内存,就是上面的有效位为0的情况。这时,处理器将向linux报告一个页故障及其对应的故障原因。
当出现一个缺页异常时,这个异常会导致控制转移到内核的缺页处理程序,这个程序将会执行以下一些步骤:
1)、内核会先判断这个引发异常的地址A是否合法,也就是说A在某个区域中吗,若不再则引发一个段错误,从而终止这个进程。
2)、试图进行的存储器访问是否合法,也就是说我们是否对一个只读的区域执行了写操作。若是则执行一个保护异常。
当内核知道我们这个缺页是因为对合法的虚拟地址进行合法的操作造成的,它是这样来处理一个缺页的:选择一个牺牲页面,如果这个牺牲页面被修改过,那么就将它交换出去,还入新的页面并更新页表。当缺页处理程序返回时,CPU重新启动引起缺页的指令,这条指令将再次发送地址A到MMU。这次,就能正常的翻译地址A而不会产生缺页中断了。
对于上面的一个过程是在一级页表中完成的,实际上都是多级页表(2级或者3级等),其实地址翻译的过程还是一样的,下面这个图就是对多级页表的一个翻译过程:
总之就是把一个虚拟地址分为好几段,分别作为一级、二级、、K级的索引,当然别忘了我们的PGD,他在程序运行的过程中是保存在CR3这个寄存器中的。
在虚拟页到物理页的翻译过程中最重要的数据结构就是页表了,是它打通了虚拟到物理的通道,页表存在于主存中,进程只需要记住它的首地址。