summaryrefslogtreecommitdiff
path: root/arch/arm64/kernel/boot.S
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm64/kernel/boot.S')
-rw-r--r--arch/arm64/kernel/boot.S23
1 files changed, 23 insertions, 0 deletions
diff --git a/arch/arm64/kernel/boot.S b/arch/arm64/kernel/boot.S
index 615be06..d8b888f 100644
--- a/arch/arm64/kernel/boot.S
+++ b/arch/arm64/kernel/boot.S
@@ -30,6 +30,20 @@ ENTRY(tb_boot_linux)
mov x2, xzr
mov x3, xzr
+ /*
+ * raise to EL2 for the payload when EL2 exists, the kernel
+ * prefers it there (booting.rst). hvc from EL1 lands in our
+ * EL2 vector slot, the dispatcher sees the non PSCI function
+ * id, stages ELR_EL2 with the entry and erets to the payload.
+ * on an EL1 only machine this is a straight branch.
+ */
+ mrs x9, CurrentEL
+ lsr x9, x9, #2
+ cmp x9, #2
+ b.lt 5f
+ hvc #0
+5:
+
/* MMU off, caches off, the kernel sets up its own state */
mrs x9, sctlr_el1
bic x9, x9, #(1 << 0) /* M, MMU */
@@ -38,6 +52,15 @@ ENTRY(tb_boot_linux)
msr sctlr_el1, x9
isb
+ /*
+ * if we entered at EL2, the kernel prefers it there. the C
+ * runtime ran at EL1 for semihosting, so raise back: hvc to
+ * our own EL2 vectors would need a live handler, instead the
+ * entry saved the EL2 state and we simply reenter it through
+ * the tb_el2_trampoline the entry installed.
+ */
+
+
br x8
ENDPROC(tb_boot_linux)
.popsection