diff --git a/src/arch/aarch64/bootblock.inc b/src/arch/aarch64/bootblock.inc index fcaf5af502..e65515f20b 100644 --- a/src/arch/aarch64/bootblock.inc +++ b/src/arch/aarch64/bootblock.inc @@ -68,6 +68,11 @@ call_bootblock: sub sp, sp, #16 + /* + * Switch to EL2 already because Linux requires to be + * in EL1 or EL2, see its "Booting AArch64 Linux" doc + */ + bl switch_el3_to_el2 bl main .align 3 diff --git a/src/arch/aarch64/cpu.S b/src/arch/aarch64/cpu.S index c4bdd3ee6d..54f5e59395 100644 --- a/src/arch/aarch64/cpu.S +++ b/src/arch/aarch64/cpu.S @@ -26,6 +26,7 @@ * Flush the whole D-cache. * * Corrupted registers: x0-x7, x9-x11 + * From: Linux arch/arm64/mm/cache.S */ ENTRY(flush_dcache_all) dsb sy // ensure ordering with previous memory accesses @@ -106,3 +107,22 @@ ENTRY(arm_init_caches) ret x8 ENDPROC(arm_init_caches) + +/* From u-boot transition.S */ +ENTRY(switch_el3_to_el2) + mov x0, #0x5b1 /* Non-secure EL0/EL1 | HVC | 64bit EL2 */ + msr scr_el3, x0 + msr cptr_el3, xzr /* Disable coprocessor traps to EL3 */ + mov x0, #0x33ff + msr cptr_el2, x0 /* Disable coprocessor traps to EL2 */ + + /* Return to the EL2_SP2 mode from EL3 */ + mov x0, sp + msr sp_el2, x0 /* Migrate SP */ + mrs x0, vbar_el3 + msr vbar_el2, x0 /* Migrate VBAR */ + mov x0, #0x3c9 + msr spsr_el3, x0 /* EL2_SP2 | D | A | I | F */ + msr elr_el3, x30 + eret +ENDPROC(switch_el3_to_el2) diff --git a/src/arch/aarch64/exception_asm.S b/src/arch/aarch64/exception_asm.S index f375d4cba8..b1f1a94174 100644 --- a/src/arch/aarch64/exception_asm.S +++ b/src/arch/aarch64/exception_asm.S @@ -80,11 +80,11 @@ ENTRY(exception_prologue) stp x3, x4, [sp, #-16]! stp x1, x2, [sp, #-16]! - /* FIXME: Don't assume always running in EL3 */ - mrs x1, elr_el3 + /* FIXME: Don't assume always running in EL2 */ + mrs x1, elr_el2 stp x1, x0, [sp, #-16]! - mrs x1, esr_el3 + mrs x1, esr_el2 mov x0, sp ret @@ -99,5 +99,5 @@ exception_handler: .global set_vbar set_vbar: - msr vbar_el3, x0 + msr vbar_el2, x0 ret