arm32段+页映射 手撕mmu的行为之软件模拟


static int pt_walk_init( void )   
{
    unsigned long virt;
    pgd_t *pgd_base;
    pgd_t *pgd;

    pmd_t *pmd;
    pte_t *pte;
    uint32_t pgd_valx, pmd_valx, pte_valx;
    
    unsigned long va;
    unsigned long pfn_base;
    unsigned long pa; 
    phys_addr_t calc_pa, real_pa;
    unsigned long val1,val2,val3;
    unsigned int *pgd_one;
    unsigned int page_mode;unsigned long offset;

    // 分配内核线性映射地址
    virt = (unsigned long)__get_free_page(GFP_KERNEL);
    if (!virt) {
        pr_err("alloc page failed\n");
        return -ENOMEM;
    }

    
    //pr_info("virt1 = %08lx\n", virt);

    virt = vmalloc(PAGE_SIZE);

    pr_info("virt2 = %08lx\n", virt);

    va = virt;
    //写入 VA
    *(volatile unsigned long *)va     = 0x12345678;    //先访问一次,触发缺页,填充真实页表
    *(volatile unsigned long *)(va+4) = 0x87654321; 
    //pr_info("va = %08lx\n", va);
      
    //然后用 MMU 算出的物理地址读
    calc_pa = (unsigned long)virt_to_phys((void *)va);
    //pr_info("calc_pa = %08lx\n", calc_pa);
    val1 = *(volatile unsigned long *)phys_to_virt(calc_pa);
    //pr_info("val1 = %08lx\n", val1);
    //pr_info("phys_to_virt(calc_pa) = %08lx\n", phys_to_virt(calc_pa) );

    //PAGE_OFFSET     = 0x80000000
    //PHYS_OFFSET     = 0x68000000
    
    //步骤1:打印虚拟地址拆分 (硬件行为)                                                                                 
    pr_info("[步骤1] 虚拟地址硬件拆分 (VA = 索引 + 偏移)\n");                               
                                                                         
    unsigned int idx = (va >> 20) & 0xFFF;    // 高12位 → PGD索引
    unsigned int off = va & 0xFFFFF;          // 低20位 → 偏移

    pr_info("VA [31:20] 索引   = 0x%03x\n", idx);
    pr_info("VA [19:0]  偏移   = 0x%05x\n\n", off);

    
    pr_info("[步骤2] 读取 PGD 原始值\n");
    pgd_base = init_mm.pgd;
    pgd = pgd_offset(&init_mm, va);
    pgd_valx = pgd_val(*pgd);

    pr_info( "PGD base addr = 0x%08x\n", (unsigned int)pgd_base );    
    pr_info( "PGD calc addr = 0x%08x\n", (unsigned int)pgd );
    pr_info( "PGD value     = 0x%08x\n", pgd_valx );
            
    page_mode = pgd_valx & 0x00000003;
    pgd_one   = pgd;


    if( page_mode ==0x02){
        pr_info( "打印内核内存布局真相\n" );
        pr_info( "虚拟地址         VA = 0x%08lx\n", va );
        pr_info( "真实物理地址 PA = 0x%08lx\n", (unsigned long)virt_to_phys((void *)va) );
        pr_info( "VA - PAGE_OFFSET  = 0x%08lx\n", va - PAGE_OFFSET );
        pr_info( "VA - virt_to_phys = 0x%08lx\n", va - (unsigned long)virt_to_phys((void *)va) );
    }
    if( page_mode == 0x02 ){
        if( (virt>>20) & 1 ){   
            pgd_one++;
            pgd_valx = pgd_one[0];
            pr_info("PGD 修正值          = 0x%08x\n", pgd_valx);
        }
    }
    
    //HEXDUMP PGD 内存
    pr_info("PGD 内存 hexdump:\n");
    print_hex_dump(KERN_INFO, "PGD: ", DUMP_PREFIX_ADDRESS, 16, 4,
               pgd_base+pgd_index(va), 0x40, false);
    pr_info("\n");

    //步骤3:解析 PGD 位格式(ARM Section 格式)
    pr_info("[步骤3] 解析 PGD 硬件格式 \n");


    if( page_mode == 2 ){            
        pr_info("Bit[1:0] 类型     = %d (10=Section 1MB大页)\n", page_mode );
    }else{
        pr_info("Bit[1:0] 类型     = %d (01=Section 4kB小页)\n", page_mode );
    }

    pr_info("Bit[4:2] AP       = %d\n", (pgd_valx >> 2) & 7);
    pr_info("Bit[5] CB         = %d\n", (pgd_valx >> 5) & 1);
    pr_info( "Bit[31:12] 基地址 = 0x%08x\n", (unsigned int)(pgd_valx & 0xFFF00000) );


    if( page_mode == 2){    
        //步骤4:硬件计算最终物理地址
        pr_info("\n[步骤4] 硬件计算最终物理地址\n");

        pfn_base = (pgd_valx & 0xFFF00000);
        pa = pfn_base | (va & 0x000FFFFF);  

        pr_info("PA = PGD[31:12] + VA[19:0]\n");
        pr_info("PA = 0x%08lx + 0x%05x = 0x%08lx\n", pfn_base, off, pa);
    }else if( page_mode == 0x1 ){
        unsigned long pte_phys;
        pr_info("\n[步骤5] 解析 PTE 硬件格式 \n");
        pr_info("=> 4KB 小页模式 (PGD → PTE)\n");

        //1.从 PGD 取出 PTE 物理地址
        pte_phys = pgd_valx & 0xFFFFFC00;
        pr_info("PTE 物理地址 = 0x%08lx\n", pte_phys);

        //2.转虚拟地址 找到对应 PTE 项               
        pte = (pte_t *)phys_to_virt(pte_phys);
        pr_info("pte1 = 0x%08lx\n", pte);
        pr_info("pte_index(va) = 0x%08lx\n", pte_index(va));
        //(((addr) >> 12) & (0x1ff))  Bit[31:21] Bit[20:12] Bit[11:0]
        //获取 pte的索引数 Bit[20:12]
        pte = pte + pte_index(va);
        //pte基地址 + 索引偏移 得到pte条目的入口
        pr_info("pte2 = 0x%08lx\n", pte);

        print_hex_dump(KERN_INFO, "PTE: ", DUMP_PREFIX_ADDRESS, 16, 4,
                       pte, 0x20, false);  
        pte_valx = pte_val(*pte);
        //取pte条目的值
        pr_info("PTE 项地址 = 0x%08x, PTE 值 = 0x%08x\n", (unsigned int)pte, pte_valx );

        // 3.计算最终物理地址 (4KB)
        pfn_base = pte_valx & 0xFFFFF000;
        offset = va & 0x00000FFF;
        pa = pfn_base | offset;
        print_hex_dump(KERN_INFO, "PTE: ", DUMP_PREFIX_ADDRESS, 16, 4,
                       phys_to_virt(pa), 0x40, false);  
        pr_info("PA = 0x%08lx\n", pa);
    }else {
        pr_err("不支持的页表类型: %d\n", page_mode);
    }   
       

    
    // =========================================================================
    // 总结
    // =========================================================================
    pr_info("\n=======================================================\n");
    pr_info( "[硬件流程完成]\n" );      
    pr_info("VA = 0x%08lx --> PA = 0x%08lx\n", va, pa);

    //free_page(virt);
    return 0;
}
 

run log:

/ # cat /dev/test_char_dev 
[   21.843404] virt2 = 992ed000
[   21.843714] [步骤1] 虚拟地址硬件拆分 (VA = 索引 + 偏移)
[   21.844116] VA [31:20] 索引   = 0x992
[   21.844347] VA [19:0]  偏移   = 0xed000
[   21.844347] 
[   21.844764] [步骤2] 读取 PGD 原始值
[   21.844990] PGD base addr = 0x80004000
[   21.845208] PGD calc addr = 0x80006648
[   21.845428] PGD value     = 0x7edfa811
[   21.845695] PGD 内存 hexdump:
[   21.845957] PGD: 80006648: 7edfa811 7edfac11 7ede7811 7ede7c11
[   21.846231] PGD: 80006658: 7ede6811 7ede6c11 7ede5811 7ede5c11
[   21.846504] PGD: 80006668: 7ede4811 7ede4c11 7ede3811 7ede3c11
[   21.846819] PGD: 80006678: 7ede2811 7ede2c11 7ede1811 7ede1c11
[   21.847083] 
[   21.847167] [步骤3] 解析 PGD 硬件格式 
[   21.847375] Bit[1:0] 类型     = 1 (01=Section 4kB小页)
[   21.847625] Bit[4:2] AP       = 4
[   21.847802] Bit[5] CB         = 0
[   21.847962] Bit[31:12] 基地址 = 0x7ed00000
[   21.848163] 
[   21.848163] [步骤5] 解析 PTE 硬件格式 
[   21.848444] => 4KB 小页模式 (PGD → PTE)
[   21.848677] PTE 物理地址 = 0x7edfa800
[   21.849121] pte1 = 0x96dfa800
[   21.849309] pte_index(va) = 0x000000ed
[   21.849484] pte2 = 0x96dfabb4
[   21.849705] PTE: 96dfabb4: 7ef2101f 00000000 00000000 00000000
[   21.849986] PTE: 96dfabc4: 00000000 00000000 00000000 00000000
[   21.850266] PTE 项地址 = 0x96dfabb4, PTE 值 = 0x7ef2101f
[   21.850612] PTE: 96f21000: 12345678 87654321 00000000 00000000
[   21.850987] PTE: 96f21010: 00000000 00000000 00000000 00000000
[   21.851288] PTE: 96f21020: 00000000 00000000 00000000 00000000
[   21.851609] PTE: 96f21030: 00000000 00000000 00000000 00000000
[   21.852043] PA = 0x7ef21000
[   21.852220] 
[   21.852220] =======================================================
[   21.852561] [硬件流程完成]
[   21.852754] VA = 0x992ed000 --> PA = 0x7ef21000
A
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值