@@ -154,6 +154,7 @@ struct kvm_nvhe_init_params {
unsigned long tpidr_el2;
unsigned long vector_hyp_va;
unsigned long stack_hyp_va;
+ unsigned long entry_hyp_va;
phys_addr_t pgd_pa;
};
@@ -113,6 +113,7 @@ int main(void)
DEFINE(NVHE_INIT_TPIDR_EL2, offsetof(struct kvm_nvhe_init_params, tpidr_el2));
DEFINE(NVHE_INIT_VECTOR_HYP_VA, offsetof(struct kvm_nvhe_init_params, vector_hyp_va));
DEFINE(NVHE_INIT_STACK_HYP_VA, offsetof(struct kvm_nvhe_init_params, stack_hyp_va));
+ DEFINE(NVHE_INIT_ENTRY_HYP_VA, offsetof(struct kvm_nvhe_init_params, entry_hyp_va));
DEFINE(NVHE_INIT_PGD_PA, offsetof(struct kvm_nvhe_init_params, pgd_pa));
#endif
#ifdef CONFIG_CPU_PM
@@ -9,6 +9,7 @@
#include <asm/alternative.h>
#include <asm/assembler.h>
+#include <asm/el2_setup.h>
#include <asm/kvm_arm.h>
#include <asm/kvm_asm.h>
#include <asm/kvm_mmu.h>
@@ -159,6 +160,37 @@ alternative_else_nop_endif
ret
SYM_CODE_END(___kvm_hyp_init)
+SYM_CODE_START(__kvm_hyp_cpu_entry)
+ msr SPsel, #1 // We want to use SP_EL{1,2}
+
+ /* Check that the core was booted in EL2. */
+ mrs x1, CurrentEL
+ cmp x1, #CurrentEL_EL2
+ b.eq 2f
+
+ /* The core booted in EL1. KVM cannot be initialized on it. */
+1: wfe
+ wfi
+ b 1b
+
+ /* Initialize EL2 CPU state to sane values. */
+2: mov x29, x0
+ init_el2_state nvhe
+ mov x0, x29
+
+ /*
+ * Load hyp VA of C entry function. Must do so before switching on the
+ * MMU because the struct pointer is PA and not identity-mapped in hyp.
+ */
+ ldr x29, [x0, #NVHE_INIT_ENTRY_HYP_VA]
+
+ /* Enable MMU, set vectors and stack. */
+ bl ___kvm_hyp_init
+
+ /* Leave idmap. */
+ br x29
+SYM_CODE_END(__kvm_hyp_cpu_entry)
+
SYM_CODE_START(__kvm_handle_stub_hvc)
cmp x0, #HVC_SOFT_RESTART
b.ne 1f
When nVHE hyp starts interception host's PSCI CPU_ON SMCs, it will need to install KVM on the newly booted CPU before returning to the host. Add an entry point which expects the same kvm_nvhe_init_params struct as the __kvm_hyp_init HVC in the CPU_ON context argument (x0). The entry point initializes EL2 state with the same init_el2_state macro used by the kernel's entry point. It then initializes KVM using the same helper function used in the __kvm_hyp_init HVC. When done, the entry point branches to a function provided in the init params. Signed-off-by: David Brazdil <dbrazdil@google.com> --- arch/arm64/include/asm/kvm_asm.h | 1 + arch/arm64/kernel/asm-offsets.c | 1 + arch/arm64/kvm/hyp/nvhe/hyp-init.S | 32 ++++++++++++++++++++++++++++++ 3 files changed, 34 insertions(+)