问题描述
Cortex-A35 处理器,AArch64 模式。 在设置 MMU 和 GIC 之前,我正在尝试从 EL3 转到非安全 EL1:
msr VTTBR_EL2,xzr
mov x0,SCR_EL3.RES1 or SCR_EL3.NS or SCR_EL3.RW or SCR_EL3.ST
msr SCR_EL3,x0
mov x1,SPSR.M.AArch64_EL1h or SPSR_EL3.A or SPSR_EL3.I or SPSR_EL3.F
msr SPSR_EL3,x1
adr x2,__el1
msr ELR_EL3,x2
; all other system registers are set to their reset values.
; SCTLR_EL1 = 0x00C50838
; HCR_EL2 = 0x0000000000000002
eret
__el1:
mov x10,0xff220000 ; this simply turns on the LED on the board,mov w11,0x0020 ; for testing only
str w11,[x10,4] ;
str w11,0] ;
b.al $
切换到安全 EL1(SCR_EL3.NS
未设置)工作正常并且 LED 亮起。当我尝试转到非安全 EL1 时它不起作用。
设置 HCR_EL2.RW
也不起作用:
mov x0,HCR_EL2.RW
msr HCR_EL2,x0
我错过了什么?
解决方法
您缺少 ARMv8 的异常级别和安全状态实现。
您不能直接更改 EL3(安全)-> EL1(非安全)。
到达 EL1 有两种可能的方式:
- EL3(安全)-> EL1(安全)
- EL3(安全)-> EL2(非安全)-> EL1(非安全)
我正在使用 Raspberry Pi 3,最后我做对了。
我看不出你的代码有什么不同,除非你没有设置堆栈指针。 SP_EL1的复位值基本上是随机的,不一定是16字节对齐的。
这对我有用:
设置:
#define get_system_reg( name,value ) asm ( "mrs %[v],"#name : [v] "=&r" (value) )
#define set_system_reg( name,value ) asm ( "msr "#name",%[v]" : : [v] "r" (value) )
#define modify_system_reg( name,bits,set ) asm ( "mrs x4,"#name \
"\nbic x4,x4,%[b]" \
"\norr x4,%[s]" \
"\nmsr "#name",x4" \
: \
: [b] "r" (bits) \,[s] "r" (set) \
: "x4" )
asm volatile ( "msr VBAR_EL3,%[table]\n" : : [table] "r" (VBAR_EL3) );
asm volatile ( "msr VBAR_EL2,%[table]\n" : : [table] "r" (VBAR_EL2) );
asm volatile ( "msr VBAR_EL1,%[table]\n" : : [table] "r" (VBAR_EL1) );
// Make lower levels 64-bit
modify_system_reg( scr_el3,(1 << 10),(1 << 10) ); // Set RW (64-bit)
// Some stacks at random memory locations
set_system_reg( sp_el2,0x200000 );
set_system_reg( sp_el1,0x300000 );
set_system_reg( sp_el0,0x400000 );
要在 EL1 (M32_Svc
= 0x1d3) 上运行 aarch32 代码:
set_system_reg( elr_el3,example_a32 ); // Address of the code
set_system_reg( spsr_el3,M32_Svc ); // Mode to run at
modify_system_reg( scr_el3,1,1 ); // Set NS bit
modify_system_reg( hcr_el2,(1 << 31),(0 << 31) ); // Clear RW (32-bit)
asm ( "eret" );
在非安全的 el1 上运行 aarch64 代码
set_system_reg( elr_el3,example_a64 );
set_system_reg( spsr_el3,EL1t );
modify_system_reg( scr_el3,(1 << 31) ); // Set RW (64-bit)
asm ( "eret" );
我的示例代码由一条 SVC 指令组成,在两种情况下都进入 VBAR_EL3
LOWER_AARCH64_SYNC
异常向量,大概是因为被跳过的 EL2 是 aarch64。 ESR_EL3
值是:
4e000000
(AArch32 中的 SMC 指令执行),以及
5e000000
(SMC 指令在 AArch64 状态下执行)。