Linux页表与ARM硬件页表
早期Linux内核是基于x86体系结构设计的,x86页表中有3个标志位是ARM32硬件页表项没有的。
PTE_DIRTY:cpu在写操作时会设置该标志位,表示对应页面被写过,为脏页。
PTE_YOUNG:CPU访问该页时会设置该标志位。在页面换出时,如果该标志位位置了,说明该页刚被访问过,页面是young的,不适合把该页换出,同时清除该标志位。
PTE_PRESENT:表示页在内存中。
针对这种情况,Linux维护了一份Linux版本的页表,用于模拟这些标志位。由于一个页面是4KB大小,一级PGD页表项对应256个pte,256*sizeof(u32)占用1KB,Linux版本pte也需要占用1KB,所以Linux创建二级页表时,以两个pgd页表项为单位,申请1个page存放对应的linux版本pte和硬件pte。前2KB存放linux版本页表,后2KB存放硬件页表。存放地址如下。
* pgd pte * | | * +--------+ * | | +------------+ +0 * +- - - - + | Linux pt 0 | * | | +------------+ +1024 * +--------+ +0 | Linux pt 1 | * | |-----> +------------+ +2048 * +- - - - + +4 | h/w pt 0 | * | |-----> +------------+ +3072 * +--------+ +8 | h/w pt 1 | * | | +------------+ +4096
左边是一级页表项 block,而右边是一个 page 中包含的四个(两对)二级页表 block 项,硬件页表项放在软件页表项 +2048 处。
#define PMD_SHIFT 21
从硬件定义来看,每个 pte block 应该是 1M,SHIFT 值应该是 20,但是软件上的处理为:将两个 pte block 放在一个页面中,因此每个 PGD 占用 8 bytes,而 PMD = PGD,因此 PMD 也就相当于两个 pte block,两个页面也就是 2M,SHIFT 为 21。