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_one0;

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("Bit1:0 类型 = %d (10=Section 1MB大页)\n", page_mode );

}else{

pr_info("Bit1:0 类型 = %d (01=Section 4kB小页)\n", page_mode );

}

pr_info("Bit4:2 AP = %d\n", (pgd_valx >> 2) & 7);

pr_info("Bit5 CB = %d\n", (pgd_valx >> 5) & 1);

pr_info( "Bit31: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 = PGD31:12 + VA19: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)) Bit31:21 Bit20:12 Bit11:0

//获取 pte的索引数 Bit20: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 Bit1:0 类型 = 1 (01=Section 4kB小页)

21.847625 Bit4:2 AP = 4

21.847802 Bit5 CB = 0

21.847962 Bit31: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

相关推荐
企鹅侠客22 分钟前
Linux CPU 负载平均值(Load Average)详解:从原理到实践
linux·运维·服务器·服务器负载
易点云徐源27 分钟前
HP 暗影精灵 PRO 16 安装双系统后,开机直接进入 Windows,按 F9 才能进入 Ubuntu:GRUB 菜单不显示的处理方法
linux·运维·ubuntu
吃一碗粉只付一碗钱37 分钟前
10-令牌里的用户主键不要明文
服务器·数据库·sql·sqlserver·c#
第404号工位1 小时前
离职退电脑前别只点“清空回收站”!手把手教你彻底抹除凭证与数字痕迹
linux·python·架构
lazy H1 小时前
【计算机网络】第 13 篇:NAT 和端口映射是什么?为什么本地服务外网访问不了?
java·网络·网络协议·学习·计算机网络·408
Linux运维技术栈1 小时前
WAF部署在防火墙后面,获取不到真实IP怎么办?
服务器·网络·tcp/ip·安全·防火墙·waf
就像楞次定律1 小时前
【Linux 学习记之二】C++ 构建体系与底层链接机制的深度透视(1)
linux·后端
广目软件1 小时前
HA分布式架构采集节点变更操作手册20261029
运维·服务器·ansible·zabbix·prometheus
米优1 小时前
linux下获取崩溃程序的core文件
linux·运维·服务器
qeen871 小时前
【Linux】动静态库的制作使用及ELF文件的宏观理解
linux·运维·库