We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
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?
Did you try to switch directly from EL3 to EL1?What SoC do you use? Do you have a JTAG debugger? This comes rather handy for this kind of problems.
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.