static int bad_address(void *p)
{
unsigned long dummy;
//arm 体系没有这个函数实现
return 0;
//return probe_kernel_address((unsigned long *)p, dummy);
}
//该函数用于查询逻辑address 虚地址 对应的页表. 摘自arch/x86/mm/fault.c
static void dump_pagetable( unsigned long address )
{
//pgd_t *base = __va(read_cr3() & PHYSICAL_PAGE_MASK);
unsigned long pa;
pgd_t *base = swapper_pg_dir;
//页目录表基址
pgd_t *pgd = base + pgd_index(address);
pud_t *pud; //页表级数大于 3 [4]
pmd_t *pmd; //页表级数大于 2 [3]
pte_t *pte; //页表级数大于等于 1 小于等于2 x>=1 && x<=2 [1,2]
printk( "in address = %lx\n", address );
printk( "base = %lx\n", base );
printk( "pgd_index(address) = 0x%lx\n", pgd_index(address) );
printk( "PGD1 = %lx\n", pgd );
printk( "PGD2 = %lx\n", pgd_val(*pgd) );
if( !pgd_present(*pgd) ){
goto out;
}
pud = pud_offset(pgd, address);
if( bad_address(pud) ){
goto bad;
}
printk("PUD = %lx\n", pud_val(*pud));
if (!pud_present(*pud) ){
goto out;
}
pmd = pmd_offset(pud, address);
if (bad_address(pmd)){
goto bad;
}
printk("PMD = %lx\n", pmd_val(*pmd));
if (!pmd_present(*pmd) || pmd_large(*pmd)){
//值为空退出
//虽然值不为空 但是他有段描述符属性 也退出 即他不是一级页描述符入口
//段表的话 一级就可以定位到物理地址 只要前面的12bit, 以1M为单位
goto out;
}
pte = pte_offset_kernel(pmd, address);
if (bad_address(pte)){
goto bad;
}
printk("PTE = %lx\n", pte_val(*pte));
//由二级页表定位到实际的物理地址
pa = (pte_val(*pte) & PAGE_MASK) | (address & ~PAGE_MASK);
printk("pa = %lx\n", pa );
out:
printk("\n");
return;
bad:
printk("BAD!!!\n");
}
//版权声明:本文为CSDN博主「leolinux」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
//原文链接:https://blog.csdn.net/leolinux/article/details/6100799v
static int pttest_show(struct seq_file *m, void *v)
{
unsigned int pgd;
printk("in pttest_show\n");
pgd = cpu_get_pgd();
printk("pgd = 0x%lx\n", pgd);
printk("init_mm.pgd = 0x%lx\n", init_mm.pgd);
dump_pagetable(0);
dump_pagetable(0xc0000000);
dump_pagetable(0xc0004000);
dump_pagetable(0xffff0000);
dump_pagetable(0xff000000);
return 0;
}
https://www.cnblogs.com/pengdonglin137/p/7818386.html
关于内存映射方面 这哥们说的不错!