来看代码:
-
unsigned
long virtuladdr, physicaladdr;
-
unsigned
long *mmu_tlb_base = (
unsigned
long *)
0x30000000;
//对应上图TTB
-
virtuladdr =
0xA0000000;
//对应上图MVA
-
physicaladdr =
0x56000000;
//对应上图PA
-
*(mmu_tlb_base + (virtuladdr >>
20)) = (physicaladdr &
0xFFF00000) | \
-
MMU_SECDESC;
-
//*(mmu_tlb_base + (virtuladdr >> 20)) =
-
//*(TTB[31-14]+MVA[31-20]+00) = *(描述符地址)
-
//这里作用就是将描述符的值给定(bit[31-20]为PA的[31-20],bit[19-0]自己给定一些段描述符的操作),CPU系统自动根据此发生操作,获得实际PA地址。
我们根据上面可以得到:段描述符的地址=Translation base(高18位)-TTB bit[31-14]+Table index(低12位)-MVA bit[31-20]+00(低两位)不少人会以为*(mmu_tlb_base | virtuladdr>>18)才是正确的。
解释:
首先mmu_tlb_base是一个unsigned long *型,而virtuladdr是unsigned long型,位或操作会出错!
查阅资料可知,一级页表的地址TTB必须16KB对齐,且位[14:0]必为0!
所以我们用+
和|
是一样的。而我们的mmu_tlb_base是unsigned long*型的,
在32位中,mmu_tlb_base + 1 = mmu_tlb_base + 1*sizeof(unsigned long*)
=mmu_tlb_base + 4
所以我们mmu_tlb_base + (virtuladdr >> 20) = mmu_tlb_base +( (virtuladdr >> 20))* 4 = mmu_tlb_base +( (virtuladdr >> 20))<<2 = mmu_tlb_base + (virtuladdr >>18
实验验证:
-
#include <stdio.h>
-
-
int
main(
int
argc,
char
** argv)
-
{
-
unsigned
long *a = (
unsigned
long *)
0x30000000;
-
unsigned
long b =
0xA0000000;
-
printf(
"a+(b>>20) = %#x.\n\n",a+(b>>
20));
-
printf(
"a | ((b>>20)<<2) = %#x",
0x30000000 | ((b>>
20)<<
2));
-
return
0;
-
}
结果: