arm的第一级页表条目数为4096个,对于4K页第二级目录条目个数为256个,一级二级条目都是每个条目4字节。
在linux下二级分页如下:虚拟地址——> PGD转换——> PTE转换——>物理地址。
arm-linux假装第一级目录只有2048个条目,但其实每个条目是2个ulong大小即8字节,所以最终设置MMU的还是4096个条目,只是每访问1个pgd条目将可以访问到2个pte条目,linux为了实现其内存管理功能又在后面加上2个对应的假pte表,这个假pte表专门给linux内核代码自己用的,不会影响arm硬件(事实上还有一个重要原因是,linux要求pte表长度为4K即一页)。
#define PTRS_PER_PTE 512 #define PTRS_PER_PMD 1 #define PTRS_PER_PGD 2048
看懂这个就很容易弄懂所有的创建内存映射的内容了,像为什么PTRS_PER_PTE定义为512、为什么PTRS_PER_PGD是2048、为什么PGDIR_SHIFT是21等等
/*获得addr在dir一级页表描述符指定的二级页表中的二级页表描述符对应的linux_pte的虚拟地址*/ #define pte_offset_kernel(dir,addr) (pmd_page_vaddr(*(dir)) + __pte_index(addr)) /*获得二级页表linux pte的虚拟地址*/ static inline pte_t *pmd_page_vaddr(pmd_t pmd) { unsigned long ptr; ptr = pmd_val(pmd) & ~(PTRS_PER_PTE * sizeof(void *) - 1); ptr += PTRS_PER_PTE * sizeof(void *); return __va(ptr); } /*获得addr对应的pte entry在二级页表中的索引*/ #define __pte_index(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
typedef struct { unsigned long pte; } pte_t; typedef struct { unsigned long pmd; } pmd_t; typedef struct { unsigned long pgd[2]; } pgd_t; typedef struct { unsigned long pgprot; } pgprot_t;