那么我们相信分析一下页表的映射过程:
第一步:定义一个表的开始地址
main_tll[0]=(unsigned long)((unsigned char*)&T0_L1[0]) | // physical address
PTE_TYPE_PAGE | // it has the "Present" flag, which must be set, and we have area in it mapped by pages
MEM_ATTR_MEMORY;
其中main_tll为组表的表头,可以看main_tll[0]可以映射的空间范围是0到(0x4000 0000 - 1)。
这里由于用不到0x4000 0000以上的空间,所以把这部分空间再进行第二次映射。直接指向了T0_L1表的地址。
T0_L1[0]=(unsigned long)(0) | // physical address
PT_BLOCK | // we have area in it mapped by pages
MEM_ATTR_MEMORY;
可以看到,这里直接将T0_L1的地址赋值为0,这里表示这0-0x200000这2M空间直接映射。如果此时访问这2M虚拟地址,则直接1:1访问到物理地址上去了。
当然,如果想将这个地址映射的更加具体,也就是将这2M的空间,映射成4K,那就需要第三级的页表项来映射。
现在我们用树莓派3B来举例。
树莓派的串口寄存器地址0x3F200000。只需要映射到后面4k就可以了。
所以,总的表的映射过程如下:
//第一次映射
main_tll[0]=(unsigned long)((unsigned char*)&T0_L1[0]) | // physical address
PTE_TYPE_PAGE | // it has the "Present" flag, which must be set, and we have area in it mapped by pages
MEM_ATTR_MEMORY;
//第二次映射
T0_L1[505]=((unsigned long)(&T0_L2[0]) | // physical address
PT_PAGE | // map 4K
MEM_ATTR_MEMORY); // different attributes for device memory
//第三次映射
T0_L2[0]=(unsigned long)((505<<21)) | // physical address
PTE_TYPE_PAGE | // map 4k
MEM_ATTR_MEMORY;
这样就可以正常的访问地址空间了,至于为什么有个505,实际上0x3F200000 << 21得到的。21=12+9。
到这里三级映射关系就建立完成了。这时4K空间已经映射完成。