Hi,
I trying to switch from EL2 to EL1 on Cortex-A53. But it doesn't work.
Here is my current startup code:
#include <asm.h> IMPORT_ASM(_cpu_el3_vec_tbl_set) IMPORT_ASM(_cpu_el2_vec_tbl_set) IMPORT_ASM(_cpu_el1_vec_tbl_set) IMPORT_C(init) IMPORT_C(main) .text ENTRY(_start) mrs x0, MPIDR_EL1 and x0, x0, #0x3 cmp x0, #0 beq __elx __wfe_cpu1_3: wfe b __wfe_cpu1_3 __elx: __el3: mrs x0, CurrentEL and x0, x0, #0xC asr x0, x0, #2 cmp x0, #3 bne __el2 __el3_stack: ldr x0, =_stack_el3_e mov sp, x0 __el3_vector: bl _cpu_el3_vec_tbl_set msr SCTLR_EL2, xzr msr HCR_EL2, xzr mrs x0, SCR_EL3 orr x0, x0, #(1<<10) orr x0, x0, #(1<<0) msr SCR_EL3, x0 mov x0, #0b01001 msr SPSR_EL3, x0 adr x0, __el2 msr ELR_EL3, x0 eret __el2: mrs x0, CurrentEL and x0, x0, #0xC asr x0, x0, #2 cmp x0, #2 bne __el1 __el2_stack: ldr x0, =_stack_el2_e mov sp, x0 __el2_vector: bl _cpu_el2_vec_tbl_set msr SCTLR_EL1, xzr mov x0, xzr orr x0, x0, #(1 << 31) msr HCR_EL2, x0 /*orr x0, x0, #(7 << 6) */ adr x0, __el1 msr ELR_EL2, x0 mov x0, xzr orr x0, x0, #(1 << 2) orr x0, x0, #(1 << 0) msr SPSR_EL2, x0 eret __el1: __el1_stack: ldr x0, =_stack_el1_e mov sp, x0 __el1_vector: bl _cpu_el1_vec_tbl_set ldr x0, =_bss_s ldr x1, =_bss_e sub x1, x1, x0 mov x2, #0x0 cbz x1, __init __bss: strb w2, [x0], #1 sub x1, x1, #1 cbnz x1, __bss __init: bl init __main: bl main __main_wfe: wfe b __main_wfe .end
When I comment out from label __elx to __el1 everything works (the C functions init and main are called).
I also setup a vector table and handlers for EL2 and EL1. But there is no exception.
I have no idea what's going wrong.
What's the correct way change to a lower exception level?
I think, it's running on EL2. The C function init currently only contains a function which prints out the current exception level. I'm using U-Boot as bootloader with ARM Trusted Firmware. The SoC is the RK3328 from Rockchip. The board is the PINE64 ROCK64. No currently I don't own a JTAG Debugger.
I have also tried to place the init function before and after the ERET instruction. The result: Before the instruction the init functions prints out the exception level via UART. But after the ERET the CPU seems to hang.
I am not familiar with ATF (I work bare-metal w/o u-boot/atf), but shouldn't ATF boot into EL1?
Currently I don't know the answer. I'm quite new on AArch64 with ATF/U-Boot. When I read out (without trying to change the EL) CurrentEL, it' returns EL2. Not sure, if ATF or U-Boot set the HCR_EL.NV bit. Although I understand the ,documentation if this bit is set, CurrentEL always returns EL2 when read it from EL1.
But if U-Boot/ATF setup EL1, shouldn't be there an exception if I want to try access higher privileges register?
HCR_EL.NV is not implemented in CA53. Therefore, if you read "2" your are in EL2.
Linux needs to boot in EL2 if you want virtualisation (kvm) to work. I see RK3328 implements all ELs so I guess the non-secure world will boot in EL2 on this platform.