- 论坛徽章:
- 0
|
回复 1# arm-linux-gcc
疑问1,
为什么这里不把后续的两个1M全都映射了呢,这样就不会浪费了
arm下面会使用两份页表来保存页表内容,原因是arm的页表格式定义与LINUX的标准定义相差颇大,为了方便管理,在使用linux标准接口设置页表属性时,会将其页表项值保存在一份“Linux页表”备份上,之后调用架构相关的页表项填写函数时会从这份linux页表里读取值,转换成相应的硬件标志位。供硬件解析的页表位置存放在MMU解析得到的地址,linux页表备份则放在物理页表加2k偏移的位置,之所以这样设置的原因是为了不浪费空间。因为arm二级页表的大小为2^8 * 4 = 1K,再加一份linux拷贝也才2k,会导致大量的页内碎片;所以将两个连续的一级页表项映射到连续的一段空间,这样就能保证在一个两级页表的存放刚好占满一个页了。arm原来的页表解析是12+8+12,这样修改后的结果可以看做是,arm的页表解析变为了11+9+12,一级页表项中两项被合为一项了。
下面是arm下的二级页表存放格式,在arch/arm/include/asm/pgtable.h里有详细介绍
*
* pgd pte
* | |
* +--------+ +0
* | |-----> +------------+ +0
* +- - - - + +4 | h/w pt 0 |
* | |-----> +------------+ +1024
* +--------+ +8 | h/w pt 1 |
* | | +------------+ +2048
* +- - - - + | Linux pt 0 |
* | | +------------+ +3072
* +--------+ | Linux pt 1 |
* | | +------------+ +4096
这个是arm v7架构的页表属性设置函数:- ENTRY(cpu_v7_set_pte_ext)
- #ifdef CONFIG_MMU
- ARM( str r1, [r0], #-2048 ) @ linux version [b][color=Red] /*取偏移2k的位置的linux页表备份*/[/color][/b]
- THUMB( str r1, [r0] ) @ linux version
- THUMB( sub r0, r0, #2048 )
- bic r3, r1, #0x000003f0
- bic r3, r3, #PTE_TYPE_MASK
- orr r3, r3, r2
- orr r3, r3, #PTE_EXT_AP0 | 2
- tst r1, #1 << 4
- orrne r3, r3, #PTE_EXT_TEX(1)
- tst r1, #L_PTE_WRITE
- tstne r1, #L_PTE_DIRTY
- orreq r3, r3, #PTE_EXT_APX
- tst r1, #L_PTE_USER
- orrne r3, r3, #PTE_EXT_AP1
- tstne r3, #PTE_EXT_APX
- bicne r3, r3, #PTE_EXT_APX | PTE_EXT_AP0
- tst r1, #L_PTE_EXEC
- orreq r3, r3, #PTE_EXT_XN
- tst r1, #L_PTE_YOUNG
- tstne r1, #L_PTE_PRESENT
- moveq r3, #0
- str r3, [r0]
- mcr p15, 0, r0, c7, c10, 1 @ flush_pte
- #endif
- mov pc, lr
- ENDPROC(cpu_v7_set_pte_ext)
复制代码 疑问2,
如果map_desc[]数组中的写死的那些虚拟地址是按照从小到大排列的,那么当跨越1M的时候,不会发生问题,因为会此时后面那个1M会判断到没有二级页表,于是会调用early_pte_alloc去分配
但是如果map_desc[]数组中的写死的那些虚拟地址是按照从大到小排列的,那么当跨越1M的时候,低地址的那个1M判断到没有二级页表,于是也会去调用early_pte_alloc去分配,但是问题就来了,因为分配之后是写了两个1M的一级页表项的(指向的二级页表),于是pmdp[1] = __pmd(pmdval + 256 * sizeof(pte_t));这句就会把相邻的高地址的1M的一级页表项给覆盖了,但是此时那个高地址1M的一级页表项已经有内容了(之前做高地址1M的映射时分配的)。这样的话map_desc[]数组中的虚拟地址必须从小到大了,感觉这是个bug啊,是不是我哪里看漏了?
|
|