曾经,在一些文档和代码中看到过说arm-linux的二级页表分为linux版别和硬件版别。一向觉得概念比较紊乱,没有细心研讨,今日总算遇到了这个问题,不得不学习一下了。
在do_page_fault()进程中,有下面函数会被调到:
[c]static inline void __pmd_populate(pmd_t *pmdp, unsigned long pmdval){pmdp[0] = __pmd(pmdval);pmdp[1] = __pmd(pmdval 256 * sizeof(pte_t));flush_pmd_entry(pmdp);}[/c]
它的功用是把在这一个新请求的二级页表与PMD相关起来。在这之前,pmdp指向的PMD项是空的,当时的进程正是在为它树立映射。在调用这个函数之前,现已请求好了一张4K巨细的二级页表。
pmdp[0] = __pmd(pmdval); 这一行很简单了解,这是在把依据pte生成的PMD表项值赋值给PMD项。可是下面这一句是为什么呢?
首要先看一张二级页表有多大,arm-linux选用的是粗粒度二级页表映射,运用这种一映射联系,一个PMD表项下面映射/掩盖1M内存,一个PTE项下面映射/掩盖4K内存,所以一张二级表应该有1M/4K=256个表项。而一个二级表项是4字节,所以一张二级表应该占用空间256*4=1K字节。一个4K的内存页能够包容4张二级表。
其次,关于二级页表,不知为什么内核要为一张二级页表供给两份版别(一个Linux版别,一个硬件版别)。并且两个版别的表的方位联系界说得很别扭。看pgalloc.h中的一个注释图:
从上(低地址)到下(高地址)分别是:第一张表的硬件版别、第二张表的硬件版别,第一张表的Linux版别、第二张表的Linux版别。可见,同一张表的linux版别和硬件版别是不接连的,但两张不同表的同一版别是接连的。我想,把这样的4张表放在一同,正是为了向4K的页面巨细对齐,不至于糟蹋空间。
这样,全部就都好了解了。上述函数中,接下来这一行:
pmdp[1] = __pmd(pmdval 256 * sizeof(pte_t));
正是把第二张硬件表的对应的PMD值写到接下来的一个PMD表项中去。
这个函数实际上是完成了两张二级表的映射。