Allwinner A64通过热重置从AArch32切换至AArch64的裸机部署问询
我来帮你梳理下在搭载Allwinner A64的Pine64开发板上,从AArch32切换到AArch64执行裸机程序的完整流程,结合你提到的补丁实现和反汇编验证情况,咱们一步步来:
核心背景:为什么要切换模式?
Allwinner A64的boot0启动U-Boot后,默认会进入AArch32的SVC特权模式(这是因为A64架构的EL3启动阶段可能默认初始化到AArch32的Secure PL0环境)。而你的裸机软件是基于AArch64开发的,所以必须先完成模式切换,才能正确执行后续代码。
已验证的切换代码实现
你提到的补丁里的切换逻辑,核心是通过配置ARM架构的系统寄存器,然后执行异常返回指令(eret)进入AArch64模式。以下是整理后的可直接使用的AArch32汇编代码(和你反汇编匹配的版本):
.global switch_to_aarch64 switch_to_aarch64: // 确保当前处于SVC模式(U-Boot默认运行模式) mrs r0, cpsr bic r0, r0, #0x1F // 清除当前模式位 orr r0, r0, #0x13 // 设置为SVC模式 msr cpsr_c, r0 // 配置EL1寄存器:禁用MMU、缓存(裸机环境不需要虚拟地址) mov x0, #0x0 msr sctlr_el1, x0 // 配置EL2寄存器(A64支持EL2,默认可能未初始化) mov x0, #0x0 msr hcr_el2, x0 // 配置EL3的SCR寄存器:允许非安全模式进入AArch64 mov x0, #0x3 // NS=1(非安全) + EA=1(异常路由到EL3) msr scr_el3, x0 // 设置异常返回后的入口地址:跳过切换代码,指向AArch64程序起始位置 ldr x0, =0x40000000 + switch_size msr elr_el3, x0 // 设置SPSR_EL3:指定返回后进入EL1h模式(AArch64特权级1,使用SP_EL1栈) mov x0, #0x3C5 // M[3:0]=0b101(EL1h) + 禁用FIQ/IRQ/ABT异常 msr spsr_el3, x0 // 执行异常返回,正式切换到AArch64模式 eret // 标记切换代码的大小,方便计算AArch64入口地址 switch_size = . - switch_to_aarch64
编译与链接的关键步骤
因为你的程序混合了AArch32切换代码和AArch64业务代码,需要分别编译再链接:
- 编译AArch32切换代码:用ARM32交叉编译器
arm-linux-gnueabihf-as -march=armv8-a -o switch32.o switch32.s - 编译AArch64业务代码:用AArch64交叉编译器
aarch64-linux-gnu-gcc -c -march=armv8-a -o hello64.o hello64.c - 编写链接脚本(
link.ld):指定代码加载地址和入口ENTRY(switch_to_aarch64) SECTIONS { . = 0x40000000; // U-Boot加载的目标地址 .text : { switch32.o(.text) // 先放AArch32切换代码 hello64.o(.text) // 再放AArch64业务代码 } } - 链接生成可执行文件:用ARM32的链接器(因为入口是AArch32代码)
arm-linux-gnueabihf-ld -T link.ld switch32.o hello64.o -o hello.elf - 提取二进制文件:
arm-linux-gnueabihf-objcopy -O binary hello.elf hello.bin
验证与部署
- 你已经用
objdump -d hello.o确认了反汇编和补丁一致,这一步没问题。额外可以用objdump -d hello.elf检查整体布局,确保AArch32代码在前,AArch64代码在后,且eret指令正确。 - 部署到Pine64:通过U-Boot加载
hello.bin到0x40000000,执行go 0x40000000即可触发模式切换并运行你的AArch64程序。
关键注意事项
- 必须保证切换代码在AArch32模式下执行:U-Boot本身是AArch32,所以加载后第一个执行的指令就是切换代码,这一点你当前的配置已经满足。
- 裸机环境下务必禁用MMU和缓存:避免虚拟地址和物理地址不匹配导致的崩溃。
- SPSR_EL3的配置不能错:如果模式位设置错误,会导致切换失败甚至CPU挂死,一定要确保M字段是
0b101(对应EL1h模式)。
内容的提问来源于stack exchange,提问作者Maciej Bielski
相关产品推荐
相关产品推荐

