ARM64内核中MMU启用前后如何加载变量虚拟地址至寄存器?
ARM64汇编宏MMU开启后加载虚拟地址的解决方案
问题背景
编写了适用于ARM64的汇编宏write_mark,用于向调试缓冲区mydebug2写入标记数据,MMU启用前功能正常,但MMU开启后宏失效,经调试确认是因为加载mydebug2和myidx时使用的是物理地址,而非虚拟地址。
宏代码:
.macro write_mark, data adr_l x25, mydebug2 // x25 = &mydebug2 adr_l x26, myidx // x26 = &myidx ldr x27, [x26] // x27 = myidx mov x26, \data // x26 = data //add x27, x27, x27, LSL #1 // x27, 3 // to double word address lsl x27, x27, #3 // x27, 3 // to double word address add x25, x25, x27 str x26, [x25] // mydebug2[myidx] = data adr_l x26, myidx // x26 = &myidx ldr x27, [x26] // x27 = myidx add x27, x27, 1 // x27(myidx) ++ str x27, [x26] // myidx++ .endm
调用方式:
adrp x1, init_pg_dir write_mark 0x5555 bl __enable_mmu write_mark 0x6666
解决方案
方案1:区分MMU状态的宏版本
修改宏,增加参数控制是否使用虚拟地址加载,MMU开启前用物理地址(原有逻辑),MMU开启后直接加载虚拟地址:
.macro write_mark, data, use_virt=0 .if \use_virt // MMU开启后,直接加载虚拟地址 ldr x25, =mydebug2 ldr x26, =myidx .else // MMU开启前,加载物理地址 adr_l x25, mydebug2 adr_l x26, myidx .endif ldr x27, [x26] mov x26, \data lsl x27, x27, #3 add x25, x25, x27 str x26, [x25] .if \use_virt ldr x26, =myidx .else adr_l x26, myidx .endif ldr x27, [x26] add x27, x27, 1 str x27, [x26] .endm
调用时指定参数:
adrp x1, init_pg_dir write_mark 0x5555 // MMU未开启,用物理地址 bl __enable_mmu write_mark 0x6666, 1 // MMU已开启,用虚拟地址
方案2:自动检测MMU状态并切换地址
通过读取SCTLR_EL1寄存器的M位(第0位)判断MMU是否开启,自动切换物理/虚拟地址:
// 先定义虚拟地址与物理地址的偏移量,根据你的系统配置修改 .equ VIRT_OFFSET, 0xFFFFFF7F80000000 // 示例:虚拟基址0xFFFFFF8000000000 - 物理基址0x80000000 .macro write_mark, data adr_l x25, mydebug2 adr_l x26, myidx // 检查MMU是否开启 mrs x28, sctlr_el1 tst x28, #(1 << 0) beq 1f // MMU未开启,跳过偏移计算 // MMU已开启,加上虚拟地址偏移 add x25, x25, #VIRT_OFFSET add x26, x26, #VIRT_OFFSET 1: ldr x27, [x26] mov x26, \data lsl x27, x27, #3 add x25, x25, x27 str x26, [x25] adr_l x26, myidx mrs x28, sctlr_el1 tst x28, #(1 << 0) beq 2f add x26, x26, #VIRT_OFFSET 2: ldr x27, [x26] add x27, x27, 1 str x27, [x26] .endm
方案3:调整链接脚本保证地址偏移一致
修改链接脚本,让数据段(包含mydebug2和myidx)的虚拟地址与物理地址的偏移和代码段完全一致。例如:
假设代码段物理地址为0x80000000,虚拟地址为0xFFFFFF8000000000,则数据段的虚拟地址应设为物理地址 + (0xFFFFFF8000000000 - 0x80000000)。这样adr_l宏在MMU开启后会自动基于PC的虚拟地址计算出正确的虚拟地址,无需修改宏代码。
内容的提问来源于stack exchange,提问作者Chan Kim
相关产品推荐
相关产品推荐

