概述
背景:
在看内核代码初始化arm页表的时候,发现linux内核做了一些特殊处理,引入了硬件页表、linux页表的概念,这篇文章描述为何需要这样处理以及具体的实现方式。
原因:
linux中ARM32采用2级页表映射方式,MMU映射过程如下:
图1 ARM MMU映射过程
从图1可以得知,ARM MMU页表(称为硬件页表或hw pt)如下:
页表中的每一项称为一个entry,entry存放的是物理地址值,PGD entry值指向2级页表(PTE页表),PTE entry值指向物理页。
由于以下两个原因,linux代码对图2的映射过程做了一些调整:
1)PTE entry中的一些低bit位被硬件使用了,没有linux需要的“accessed”、“dirty”等标志位。
参考内核代码注释: Hardware-wise, we have a two level page table structure, where the first level has 4096 entries, and the second level has 256 entries. Each entry is one 32-bit word. Most of the bits in the second level entry are used by hardware, and there aren't any "accessed" and "dirty" bits。
2)linux希望PTE页表本身也是一个页面大小。
参考内核代码注释:However, Linux also expects one "PTE" table per page, and at least a "dirty" bit.,但图1表明PTE页表是256*4 byte=1k大小。
解决方案
针对上面提到的问题,linux做了一些处理,使内核中实现的页表能够满足硬件需求,最终的arm页表见图4。
对于图4,解释如下:
1)软件实现必须符合硬件要求。ARM要求4096个PGD entry、256个PTE entry。
解决:PGD每个entry为8 bytes,定义为pmdval_t pgd[2],故共2048*2=4096 PGD entry。ARM MMU用va的bit[31,20](见图1)在PGD 4096项中找到对应的entry,每个entry指向一个hw页表(见图4中pmdp)。每一个hw页表有256个entry,ARM MMU用va的bit[19,12]在hw页表中找到对应的entry。所以从硬件角度看,linux实现的arm页表,完全符合硬件要求。
2)Linux需要 "accessed" and "dirty"位。
解决:从图3中可以看出,PTE entry的低位已经被硬件占用,所以只能再复制出一份页表(称为linux页表或linux pt),图4的hw pt 0对应Linux pt 0,linux页表的低bit位被linux系统用来提供需要的 "accessed" and "dirty"位。hw pt由MMU使用,linux pt由操作系统使用。
3)Linux期望PTE页表占用1个page。
解决:ARM的hw pt为256*4 bytes=1k,不满一个page大小。内核代码在实现上采用了一个小技巧,让一个PGD entry映射2个连续的hw pt,同时将对应的2个linux pt也组织在一起,共1k*4=4k。
因为linux代码让PGD一次映射2个hw pt,所以软件需要做一些处理来实现这个目的。软件定义PGD表项为pmdval_t pgd[2],pgd[i]指向一个hw pt,所以PGD表项一共有4096/2=2048项,也就是说需要用bit[31,21]来寻址这2048项,所以pgtable-2level.h中定义了:#define PGDIR_SHIFT 21 (注意,图1中PGD偏移20bit,那是给硬件MMU用的,跟我们这里的软件偏移没有关系)。
上面部分内容,可以结合代码来仔细品味(从__create_mapping函数看起),代码路径:
start_kernel-->setup_arch-->paging_init-->map_lowmem->
create_mapping-->__create_mapping-->alloc_init_pud-->alloc_init_pmd
-->alloc_init_pte
最后
以上就是清爽胡萝卜为你收集整理的ARM中的linux页表与硬件页表(linux4.0)的全部内容,希望文章能够帮你解决ARM中的linux页表与硬件页表(linux4.0)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复