162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2012,2013 - ARM Ltd 462306a36Sopenharmony_ci * Author: Marc Zyngier <marc.zyngier@arm.com> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/arm-smccc.h> 862306a36Sopenharmony_ci#include <linux/linkage.h> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <asm/alternative.h> 1162306a36Sopenharmony_ci#include <asm/assembler.h> 1262306a36Sopenharmony_ci#include <asm/el2_setup.h> 1362306a36Sopenharmony_ci#include <asm/kvm_arm.h> 1462306a36Sopenharmony_ci#include <asm/kvm_asm.h> 1562306a36Sopenharmony_ci#include <asm/kvm_mmu.h> 1662306a36Sopenharmony_ci#include <asm/pgtable-hwdef.h> 1762306a36Sopenharmony_ci#include <asm/sysreg.h> 1862306a36Sopenharmony_ci#include <asm/virt.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci .text 2162306a36Sopenharmony_ci .pushsection .idmap.text, "ax" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci .align 11 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ciSYM_CODE_START(__kvm_hyp_init) 2662306a36Sopenharmony_ci ventry __invalid // Synchronous EL2t 2762306a36Sopenharmony_ci ventry __invalid // IRQ EL2t 2862306a36Sopenharmony_ci ventry __invalid // FIQ EL2t 2962306a36Sopenharmony_ci ventry __invalid // Error EL2t 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci ventry __invalid // Synchronous EL2h 3262306a36Sopenharmony_ci ventry __invalid // IRQ EL2h 3362306a36Sopenharmony_ci ventry __invalid // FIQ EL2h 3462306a36Sopenharmony_ci ventry __invalid // Error EL2h 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci ventry __do_hyp_init // Synchronous 64-bit EL1 3762306a36Sopenharmony_ci ventry __invalid // IRQ 64-bit EL1 3862306a36Sopenharmony_ci ventry __invalid // FIQ 64-bit EL1 3962306a36Sopenharmony_ci ventry __invalid // Error 64-bit EL1 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci ventry __invalid // Synchronous 32-bit EL1 4262306a36Sopenharmony_ci ventry __invalid // IRQ 32-bit EL1 4362306a36Sopenharmony_ci ventry __invalid // FIQ 32-bit EL1 4462306a36Sopenharmony_ci ventry __invalid // Error 32-bit EL1 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci__invalid: 4762306a36Sopenharmony_ci b . 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci /* 5062306a36Sopenharmony_ci * Only uses x0..x3 so as to not clobber callee-saved SMCCC registers. 5162306a36Sopenharmony_ci * 5262306a36Sopenharmony_ci * x0: SMCCC function ID 5362306a36Sopenharmony_ci * x1: struct kvm_nvhe_init_params PA 5462306a36Sopenharmony_ci */ 5562306a36Sopenharmony_ci__do_hyp_init: 5662306a36Sopenharmony_ci /* Check for a stub HVC call */ 5762306a36Sopenharmony_ci cmp x0, #HVC_STUB_HCALL_NR 5862306a36Sopenharmony_ci b.lo __kvm_handle_stub_hvc 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci bic x0, x0, #ARM_SMCCC_CALL_HINTS 6162306a36Sopenharmony_ci mov x3, #KVM_HOST_SMCCC_FUNC(__kvm_hyp_init) 6262306a36Sopenharmony_ci cmp x0, x3 6362306a36Sopenharmony_ci b.eq 1f 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci mov x0, #SMCCC_RET_NOT_SUPPORTED 6662306a36Sopenharmony_ci eret 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci1: mov x0, x1 6962306a36Sopenharmony_ci mov x3, lr 7062306a36Sopenharmony_ci bl ___kvm_hyp_init // Clobbers x0..x2 7162306a36Sopenharmony_ci mov lr, x3 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci /* Hello, World! */ 7462306a36Sopenharmony_ci mov x0, #SMCCC_RET_SUCCESS 7562306a36Sopenharmony_ci eret 7662306a36Sopenharmony_ciSYM_CODE_END(__kvm_hyp_init) 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci/* 7962306a36Sopenharmony_ci * Initialize the hypervisor in EL2. 8062306a36Sopenharmony_ci * 8162306a36Sopenharmony_ci * Only uses x0..x2 so as to not clobber callee-saved SMCCC registers 8262306a36Sopenharmony_ci * and leave x3 for the caller. 8362306a36Sopenharmony_ci * 8462306a36Sopenharmony_ci * x0: struct kvm_nvhe_init_params PA 8562306a36Sopenharmony_ci */ 8662306a36Sopenharmony_ciSYM_CODE_START_LOCAL(___kvm_hyp_init) 8762306a36Sopenharmony_ci ldr x1, [x0, #NVHE_INIT_STACK_HYP_VA] 8862306a36Sopenharmony_ci mov sp, x1 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci ldr x1, [x0, #NVHE_INIT_MAIR_EL2] 9162306a36Sopenharmony_ci msr mair_el2, x1 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci ldr x1, [x0, #NVHE_INIT_HCR_EL2] 9462306a36Sopenharmony_ci msr hcr_el2, x1 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci mov x2, #HCR_E2H 9762306a36Sopenharmony_ci and x2, x1, x2 9862306a36Sopenharmony_ci cbz x2, 1f 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci // hVHE: Replay the EL2 setup to account for the E2H bit 10162306a36Sopenharmony_ci // TPIDR_EL2 is used to preserve x0 across the macro maze... 10262306a36Sopenharmony_ci isb 10362306a36Sopenharmony_ci msr tpidr_el2, x0 10462306a36Sopenharmony_ci init_el2_state 10562306a36Sopenharmony_ci finalise_el2_state 10662306a36Sopenharmony_ci mrs x0, tpidr_el2 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci1: 10962306a36Sopenharmony_ci ldr x1, [x0, #NVHE_INIT_TPIDR_EL2] 11062306a36Sopenharmony_ci msr tpidr_el2, x1 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci ldr x1, [x0, #NVHE_INIT_VTTBR] 11362306a36Sopenharmony_ci msr vttbr_el2, x1 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci ldr x1, [x0, #NVHE_INIT_VTCR] 11662306a36Sopenharmony_ci msr vtcr_el2, x1 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci ldr x1, [x0, #NVHE_INIT_PGD_PA] 11962306a36Sopenharmony_ci phys_to_ttbr x2, x1 12062306a36Sopenharmony_cialternative_if ARM64_HAS_CNP 12162306a36Sopenharmony_ci orr x2, x2, #TTBR_CNP_BIT 12262306a36Sopenharmony_cialternative_else_nop_endif 12362306a36Sopenharmony_ci msr ttbr0_el2, x2 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci /* 12662306a36Sopenharmony_ci * Set the PS bits in TCR_EL2. 12762306a36Sopenharmony_ci */ 12862306a36Sopenharmony_ci ldr x0, [x0, #NVHE_INIT_TCR_EL2] 12962306a36Sopenharmony_ci tcr_compute_pa_size x0, #TCR_EL2_PS_SHIFT, x1, x2 13062306a36Sopenharmony_ci msr tcr_el2, x0 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci isb 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci /* Invalidate the stale TLBs from Bootloader */ 13562306a36Sopenharmony_ci tlbi alle2 13662306a36Sopenharmony_ci tlbi vmalls12e1 13762306a36Sopenharmony_ci dsb sy 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci mov_q x0, INIT_SCTLR_EL2_MMU_ON 14062306a36Sopenharmony_cialternative_if ARM64_HAS_ADDRESS_AUTH 14162306a36Sopenharmony_ci mov_q x1, (SCTLR_ELx_ENIA | SCTLR_ELx_ENIB | \ 14262306a36Sopenharmony_ci SCTLR_ELx_ENDA | SCTLR_ELx_ENDB) 14362306a36Sopenharmony_ci orr x0, x0, x1 14462306a36Sopenharmony_cialternative_else_nop_endif 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci#ifdef CONFIG_ARM64_BTI_KERNEL 14762306a36Sopenharmony_cialternative_if ARM64_BTI 14862306a36Sopenharmony_ci orr x0, x0, #SCTLR_EL2_BT 14962306a36Sopenharmony_cialternative_else_nop_endif 15062306a36Sopenharmony_ci#endif /* CONFIG_ARM64_BTI_KERNEL */ 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci msr sctlr_el2, x0 15362306a36Sopenharmony_ci isb 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci /* Set the host vector */ 15662306a36Sopenharmony_ci ldr x0, =__kvm_hyp_host_vector 15762306a36Sopenharmony_ci msr vbar_el2, x0 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci ret 16062306a36Sopenharmony_ciSYM_CODE_END(___kvm_hyp_init) 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci/* 16362306a36Sopenharmony_ci * PSCI CPU_ON entry point 16462306a36Sopenharmony_ci * 16562306a36Sopenharmony_ci * x0: struct kvm_nvhe_init_params PA 16662306a36Sopenharmony_ci */ 16762306a36Sopenharmony_ciSYM_CODE_START(kvm_hyp_cpu_entry) 16862306a36Sopenharmony_ci mov x1, #1 // is_cpu_on = true 16962306a36Sopenharmony_ci b __kvm_hyp_init_cpu 17062306a36Sopenharmony_ciSYM_CODE_END(kvm_hyp_cpu_entry) 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci/* 17362306a36Sopenharmony_ci * PSCI CPU_SUSPEND / SYSTEM_SUSPEND entry point 17462306a36Sopenharmony_ci * 17562306a36Sopenharmony_ci * x0: struct kvm_nvhe_init_params PA 17662306a36Sopenharmony_ci */ 17762306a36Sopenharmony_ciSYM_CODE_START(kvm_hyp_cpu_resume) 17862306a36Sopenharmony_ci mov x1, #0 // is_cpu_on = false 17962306a36Sopenharmony_ci b __kvm_hyp_init_cpu 18062306a36Sopenharmony_ciSYM_CODE_END(kvm_hyp_cpu_resume) 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci/* 18362306a36Sopenharmony_ci * Common code for CPU entry points. Initializes EL2 state and 18462306a36Sopenharmony_ci * installs the hypervisor before handing over to a C handler. 18562306a36Sopenharmony_ci * 18662306a36Sopenharmony_ci * x0: struct kvm_nvhe_init_params PA 18762306a36Sopenharmony_ci * x1: bool is_cpu_on 18862306a36Sopenharmony_ci */ 18962306a36Sopenharmony_ciSYM_CODE_START_LOCAL(__kvm_hyp_init_cpu) 19062306a36Sopenharmony_ci mov x28, x0 // Stash arguments 19162306a36Sopenharmony_ci mov x29, x1 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci /* Check that the core was booted in EL2. */ 19462306a36Sopenharmony_ci mrs x0, CurrentEL 19562306a36Sopenharmony_ci cmp x0, #CurrentEL_EL2 19662306a36Sopenharmony_ci b.eq 2f 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci /* The core booted in EL1. KVM cannot be initialized on it. */ 19962306a36Sopenharmony_ci1: wfe 20062306a36Sopenharmony_ci wfi 20162306a36Sopenharmony_ci b 1b 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci2: msr SPsel, #1 // We want to use SP_EL{1,2} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci /* Initialize EL2 CPU state to sane values. */ 20662306a36Sopenharmony_ci init_el2_state // Clobbers x0..x2 20762306a36Sopenharmony_ci finalise_el2_state 20862306a36Sopenharmony_ci __init_el2_nvhe_prepare_eret 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci /* Enable MMU, set vectors and stack. */ 21162306a36Sopenharmony_ci mov x0, x28 21262306a36Sopenharmony_ci bl ___kvm_hyp_init // Clobbers x0..x2 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci /* Leave idmap. */ 21562306a36Sopenharmony_ci mov x0, x29 21662306a36Sopenharmony_ci ldr x1, =kvm_host_psci_cpu_entry 21762306a36Sopenharmony_ci br x1 21862306a36Sopenharmony_ciSYM_CODE_END(__kvm_hyp_init_cpu) 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ciSYM_CODE_START(__kvm_handle_stub_hvc) 22162306a36Sopenharmony_ci /* 22262306a36Sopenharmony_ci * __kvm_handle_stub_hvc called from __host_hvc through branch instruction(br) so 22362306a36Sopenharmony_ci * we need bti j at beginning. 22462306a36Sopenharmony_ci */ 22562306a36Sopenharmony_ci bti j 22662306a36Sopenharmony_ci cmp x0, #HVC_SOFT_RESTART 22762306a36Sopenharmony_ci b.ne 1f 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci /* This is where we're about to jump, staying at EL2 */ 23062306a36Sopenharmony_ci msr elr_el2, x1 23162306a36Sopenharmony_ci mov x0, #(PSR_F_BIT | PSR_I_BIT | PSR_A_BIT | PSR_D_BIT | PSR_MODE_EL2h) 23262306a36Sopenharmony_ci msr spsr_el2, x0 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci /* Shuffle the arguments, and don't come back */ 23562306a36Sopenharmony_ci mov x0, x2 23662306a36Sopenharmony_ci mov x1, x3 23762306a36Sopenharmony_ci mov x2, x4 23862306a36Sopenharmony_ci b reset 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci1: cmp x0, #HVC_RESET_VECTORS 24162306a36Sopenharmony_ci b.ne 1f 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci /* 24462306a36Sopenharmony_ci * Set the HVC_RESET_VECTORS return code before entering the common 24562306a36Sopenharmony_ci * path so that we do not clobber x0-x2 in case we are coming via 24662306a36Sopenharmony_ci * HVC_SOFT_RESTART. 24762306a36Sopenharmony_ci */ 24862306a36Sopenharmony_ci mov x0, xzr 24962306a36Sopenharmony_cireset: 25062306a36Sopenharmony_ci /* Reset kvm back to the hyp stub. */ 25162306a36Sopenharmony_ci mov_q x5, INIT_SCTLR_EL2_MMU_OFF 25262306a36Sopenharmony_ci pre_disable_mmu_workaround 25362306a36Sopenharmony_ci msr sctlr_el2, x5 25462306a36Sopenharmony_ci isb 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_cialternative_if ARM64_KVM_PROTECTED_MODE 25762306a36Sopenharmony_ci mov_q x5, HCR_HOST_NVHE_FLAGS 25862306a36Sopenharmony_ci msr hcr_el2, x5 25962306a36Sopenharmony_cialternative_else_nop_endif 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci /* Install stub vectors */ 26262306a36Sopenharmony_ci adr_l x5, __hyp_stub_vectors 26362306a36Sopenharmony_ci msr vbar_el2, x5 26462306a36Sopenharmony_ci eret 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci1: /* Bad stub call */ 26762306a36Sopenharmony_ci mov_q x0, HVC_STUB_ERR 26862306a36Sopenharmony_ci eret 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ciSYM_CODE_END(__kvm_handle_stub_hvc) 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ciSYM_FUNC_START(__pkvm_init_switch_pgd) 27362306a36Sopenharmony_ci /* Turn the MMU off */ 27462306a36Sopenharmony_ci pre_disable_mmu_workaround 27562306a36Sopenharmony_ci mrs x2, sctlr_el2 27662306a36Sopenharmony_ci bic x3, x2, #SCTLR_ELx_M 27762306a36Sopenharmony_ci msr sctlr_el2, x3 27862306a36Sopenharmony_ci isb 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci tlbi alle2 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci /* Install the new pgtables */ 28362306a36Sopenharmony_ci ldr x3, [x0, #NVHE_INIT_PGD_PA] 28462306a36Sopenharmony_ci phys_to_ttbr x4, x3 28562306a36Sopenharmony_cialternative_if ARM64_HAS_CNP 28662306a36Sopenharmony_ci orr x4, x4, #TTBR_CNP_BIT 28762306a36Sopenharmony_cialternative_else_nop_endif 28862306a36Sopenharmony_ci msr ttbr0_el2, x4 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci /* Set the new stack pointer */ 29162306a36Sopenharmony_ci ldr x0, [x0, #NVHE_INIT_STACK_HYP_VA] 29262306a36Sopenharmony_ci mov sp, x0 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci /* And turn the MMU back on! */ 29562306a36Sopenharmony_ci set_sctlr_el2 x2 29662306a36Sopenharmony_ci ret x1 29762306a36Sopenharmony_ciSYM_FUNC_END(__pkvm_init_switch_pgd) 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci .popsection 300