KVM: arm64: Fix hVHE init on CPUs where HCR_EL2.E2H is not RES1
Marc Zyngier
maintainerPATCH 1/1 KVM: arm64: Fix hVHE init on CPUs where HCR_EL2.E2H is not RES1
On CPUs where E2H is RES1, we very quickly set the scene for running EL2 with a VHE configuration, as we do not have any other choice.
However, CPUs that conform to the current writing of the architecture start with E2H=0, and only later upgrade with E2H=1. This is all good, but nothing there is actually reconfiguring EL2 to be able to correctly run the kernel at EL1. Huhuh...
The "obvious" solution is not to just reinitialise the timer controls like we do, but to really intitialise *everything* unconditionally.
This requires a bit of surgery, and is a good opportunity to remove the macro that messes with SPSR_EL2 in init_el2_state.
With that, hVHE now works correctly on my trusted A55 machine!
--- arch/arm64/include/asm/el2_setup.h | 1 - arch/arm64/kernel/head.S | 2 ++ arch/arm64/kvm/hyp/nvhe/hyp-init.S | 19 ++++++++++++------- 3 files changed, 14 insertions(+), 8 deletions(-)
arch/arm64/include/asm/el2_setup.h +0 -1
@@ -205,7 +205,6 @@__init_el2_nvhe_idregs __init_el2_cptr __init_el2_fgt - __init_el2_nvhe_prepare_eret .endm#ifndef __KVM_NVHE_HYPERVISOR__
arch/arm64/kernel/head.S +2 -0
@@ -603,6 +603,8 @@ SYM_INNER_LABEL(init_el2, SYM_L_LOCAL) msr sctlr_el1, x1 mov x2, xzr 2: + __init_el2_nvhe_prepare_eret + mov w0, #BOOT_CPU_MODE_EL2 orr x0, x0, x2 eret
arch/arm64/kvm/hyp/nvhe/hyp-init.S +12 -7
@@ -83,9 +83,6 @@ SYM_CODE_END(__kvm_hyp_init) * x0: struct kvm_nvhe_init_params PA */ SYM_CODE_START_LOCAL(___kvm_hyp_init) - ldr x1, [x0, #NVHE_INIT_TPIDR_EL2] - msr tpidr_el2, x1 - ldr x1, [x0, #NVHE_INIT_STACK_HYP_VA] mov sp, x1
@@ -99,11 +96,18 @@ SYM_CODE_START_LOCAL(___kvm_hyp_init) and x2, x1, x2 cbz x2, 1f - mrs x1, cnthctl_el2 - and x1, x1, #~(BIT(0) | BIT(1)) - orr x1, x1, #(BIT(10) | BIT(11)) - msr cnthctl_el2, x1 + // hVHE: Replay the EL2 setup to account for the E2H bit + // TPIDR_EL2 is used to preserve x0 across the macro maze... + isb + msr tpidr_el2, x0 + init_el2_state + finalise_el2_state + mrs x0, tpidr_el2 + 1: + ldr x1, [x0, #NVHE_INIT_TPIDR_EL2] + msr tpidr_el2, x1 + ldr x1, [x0, #NVHE_INIT_VTTBR] msr vttbr_el2, x1
@@ -193,6 +197,7 @@ SYM_CODE_START_LOCAL(__kvm_hyp_init_cpu) /* Initialize EL2 CPU state to sane values. */ init_el2_state // Clobbers x0..x2 finalise_el2_state + __init_el2_nvhe_prepare_eret /* Enable MMU, set vectors and stack. */ mov x0, x28
Signature · 1 line
2.34.1
Oliver Upton
AppliedQuoted 10 lines · Marc Zyngier
On CPUs where E2H is RES1, we very quickly set the scene for running EL2 with a VHE configuration, as we do not have any other choice.
However, CPUs that conform to the current writing of the architecture start with E2H=0, and only later upgrade with E2H=1. This is all good, but nothing there is actually reconfiguring EL2 to be able to correctly run the kernel at EL1. Huhuh...
[...]
Applied to kvmarm/next, thanks!
[1/1] KVM: arm64: Fix hVHE init on CPUs where HCR_EL2.E2H is not RES1
https://git.kernel.org/kvmarm/kvmarm/c/1700f89cb99a
--
Best,
Oliver