18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2012,2013 - ARM Ltd 48c2ecf20Sopenharmony_ci * Author: Marc Zyngier <marc.zyngier@arm.com> 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Derived from arch/arm/kvm/reset.c 78c2ecf20Sopenharmony_ci * Copyright (C) 2012 - Virtual Open Systems and Columbia University 88c2ecf20Sopenharmony_ci * Author: Christoffer Dall <c.dall@virtualopensystems.com> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/errno.h> 128c2ecf20Sopenharmony_ci#include <linux/kernel.h> 138c2ecf20Sopenharmony_ci#include <linux/kvm_host.h> 148c2ecf20Sopenharmony_ci#include <linux/kvm.h> 158c2ecf20Sopenharmony_ci#include <linux/hw_breakpoint.h> 168c2ecf20Sopenharmony_ci#include <linux/slab.h> 178c2ecf20Sopenharmony_ci#include <linux/string.h> 188c2ecf20Sopenharmony_ci#include <linux/types.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include <kvm/arm_arch_timer.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include <asm/cpufeature.h> 238c2ecf20Sopenharmony_ci#include <asm/cputype.h> 248c2ecf20Sopenharmony_ci#include <asm/fpsimd.h> 258c2ecf20Sopenharmony_ci#include <asm/ptrace.h> 268c2ecf20Sopenharmony_ci#include <asm/kvm_arm.h> 278c2ecf20Sopenharmony_ci#include <asm/kvm_asm.h> 288c2ecf20Sopenharmony_ci#include <asm/kvm_coproc.h> 298c2ecf20Sopenharmony_ci#include <asm/kvm_emulate.h> 308c2ecf20Sopenharmony_ci#include <asm/kvm_mmu.h> 318c2ecf20Sopenharmony_ci#include <asm/virt.h> 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/* Maximum phys_shift supported for any VM on this host */ 348c2ecf20Sopenharmony_cistatic u32 kvm_ipa_limit; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci/* 378c2ecf20Sopenharmony_ci * ARMv8 Reset Values 388c2ecf20Sopenharmony_ci */ 398c2ecf20Sopenharmony_ci#define VCPU_RESET_PSTATE_EL1 (PSR_MODE_EL1h | PSR_A_BIT | PSR_I_BIT | \ 408c2ecf20Sopenharmony_ci PSR_F_BIT | PSR_D_BIT) 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#define VCPU_RESET_PSTATE_SVC (PSR_AA32_MODE_SVC | PSR_AA32_A_BIT | \ 438c2ecf20Sopenharmony_ci PSR_AA32_I_BIT | PSR_AA32_F_BIT) 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic bool system_has_full_ptr_auth(void) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci return system_supports_address_auth() && system_supports_generic_auth(); 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci/** 518c2ecf20Sopenharmony_ci * kvm_arch_vm_ioctl_check_extension 528c2ecf20Sopenharmony_ci * 538c2ecf20Sopenharmony_ci * We currently assume that the number of HW registers is uniform 548c2ecf20Sopenharmony_ci * across all CPUs (see cpuinfo_sanity_check). 558c2ecf20Sopenharmony_ci */ 568c2ecf20Sopenharmony_ciint kvm_arch_vm_ioctl_check_extension(struct kvm *kvm, long ext) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci int r; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci switch (ext) { 618c2ecf20Sopenharmony_ci case KVM_CAP_ARM_EL1_32BIT: 628c2ecf20Sopenharmony_ci r = cpus_have_const_cap(ARM64_HAS_32BIT_EL1); 638c2ecf20Sopenharmony_ci break; 648c2ecf20Sopenharmony_ci case KVM_CAP_GUEST_DEBUG_HW_BPS: 658c2ecf20Sopenharmony_ci r = get_num_brps(); 668c2ecf20Sopenharmony_ci break; 678c2ecf20Sopenharmony_ci case KVM_CAP_GUEST_DEBUG_HW_WPS: 688c2ecf20Sopenharmony_ci r = get_num_wrps(); 698c2ecf20Sopenharmony_ci break; 708c2ecf20Sopenharmony_ci case KVM_CAP_ARM_PMU_V3: 718c2ecf20Sopenharmony_ci r = kvm_arm_support_pmu_v3(); 728c2ecf20Sopenharmony_ci break; 738c2ecf20Sopenharmony_ci case KVM_CAP_ARM_INJECT_SERROR_ESR: 748c2ecf20Sopenharmony_ci r = cpus_have_const_cap(ARM64_HAS_RAS_EXTN); 758c2ecf20Sopenharmony_ci break; 768c2ecf20Sopenharmony_ci case KVM_CAP_SET_GUEST_DEBUG: 778c2ecf20Sopenharmony_ci case KVM_CAP_VCPU_ATTRIBUTES: 788c2ecf20Sopenharmony_ci r = 1; 798c2ecf20Sopenharmony_ci break; 808c2ecf20Sopenharmony_ci case KVM_CAP_ARM_VM_IPA_SIZE: 818c2ecf20Sopenharmony_ci r = kvm_ipa_limit; 828c2ecf20Sopenharmony_ci break; 838c2ecf20Sopenharmony_ci case KVM_CAP_ARM_SVE: 848c2ecf20Sopenharmony_ci r = system_supports_sve(); 858c2ecf20Sopenharmony_ci break; 868c2ecf20Sopenharmony_ci case KVM_CAP_ARM_PTRAUTH_ADDRESS: 878c2ecf20Sopenharmony_ci case KVM_CAP_ARM_PTRAUTH_GENERIC: 888c2ecf20Sopenharmony_ci r = system_has_full_ptr_auth(); 898c2ecf20Sopenharmony_ci break; 908c2ecf20Sopenharmony_ci default: 918c2ecf20Sopenharmony_ci r = 0; 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci return r; 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ciunsigned int kvm_sve_max_vl; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ciint kvm_arm_init_sve(void) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci if (system_supports_sve()) { 1028c2ecf20Sopenharmony_ci kvm_sve_max_vl = sve_max_virtualisable_vl; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci /* 1058c2ecf20Sopenharmony_ci * The get_sve_reg()/set_sve_reg() ioctl interface will need 1068c2ecf20Sopenharmony_ci * to be extended with multiple register slice support in 1078c2ecf20Sopenharmony_ci * order to support vector lengths greater than 1088c2ecf20Sopenharmony_ci * SVE_VL_ARCH_MAX: 1098c2ecf20Sopenharmony_ci */ 1108c2ecf20Sopenharmony_ci if (WARN_ON(kvm_sve_max_vl > SVE_VL_ARCH_MAX)) 1118c2ecf20Sopenharmony_ci kvm_sve_max_vl = SVE_VL_ARCH_MAX; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci /* 1148c2ecf20Sopenharmony_ci * Don't even try to make use of vector lengths that 1158c2ecf20Sopenharmony_ci * aren't available on all CPUs, for now: 1168c2ecf20Sopenharmony_ci */ 1178c2ecf20Sopenharmony_ci if (kvm_sve_max_vl < sve_max_vl) 1188c2ecf20Sopenharmony_ci pr_warn("KVM: SVE vector length for guests limited to %u bytes\n", 1198c2ecf20Sopenharmony_ci kvm_sve_max_vl); 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci return 0; 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic int kvm_vcpu_enable_sve(struct kvm_vcpu *vcpu) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci if (!system_supports_sve()) 1288c2ecf20Sopenharmony_ci return -EINVAL; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci /* Verify that KVM startup enforced this when SVE was detected: */ 1318c2ecf20Sopenharmony_ci if (WARN_ON(!has_vhe())) 1328c2ecf20Sopenharmony_ci return -EINVAL; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci vcpu->arch.sve_max_vl = kvm_sve_max_vl; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci /* 1378c2ecf20Sopenharmony_ci * Userspace can still customize the vector lengths by writing 1388c2ecf20Sopenharmony_ci * KVM_REG_ARM64_SVE_VLS. Allocation is deferred until 1398c2ecf20Sopenharmony_ci * kvm_arm_vcpu_finalize(), which freezes the configuration. 1408c2ecf20Sopenharmony_ci */ 1418c2ecf20Sopenharmony_ci vcpu->arch.flags |= KVM_ARM64_GUEST_HAS_SVE; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci return 0; 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci/* 1478c2ecf20Sopenharmony_ci * Finalize vcpu's maximum SVE vector length, allocating 1488c2ecf20Sopenharmony_ci * vcpu->arch.sve_state as necessary. 1498c2ecf20Sopenharmony_ci */ 1508c2ecf20Sopenharmony_cistatic int kvm_vcpu_finalize_sve(struct kvm_vcpu *vcpu) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci void *buf; 1538c2ecf20Sopenharmony_ci unsigned int vl; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci vl = vcpu->arch.sve_max_vl; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci /* 1588c2ecf20Sopenharmony_ci * Responsibility for these properties is shared between 1598c2ecf20Sopenharmony_ci * kvm_arm_init_arch_resources(), kvm_vcpu_enable_sve() and 1608c2ecf20Sopenharmony_ci * set_sve_vls(). Double-check here just to be sure: 1618c2ecf20Sopenharmony_ci */ 1628c2ecf20Sopenharmony_ci if (WARN_ON(!sve_vl_valid(vl) || vl > sve_max_virtualisable_vl || 1638c2ecf20Sopenharmony_ci vl > SVE_VL_ARCH_MAX)) 1648c2ecf20Sopenharmony_ci return -EIO; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci buf = kzalloc(SVE_SIG_REGS_SIZE(sve_vq_from_vl(vl)), GFP_KERNEL); 1678c2ecf20Sopenharmony_ci if (!buf) 1688c2ecf20Sopenharmony_ci return -ENOMEM; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci vcpu->arch.sve_state = buf; 1718c2ecf20Sopenharmony_ci vcpu->arch.flags |= KVM_ARM64_VCPU_SVE_FINALIZED; 1728c2ecf20Sopenharmony_ci return 0; 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ciint kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu, int feature) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci switch (feature) { 1788c2ecf20Sopenharmony_ci case KVM_ARM_VCPU_SVE: 1798c2ecf20Sopenharmony_ci if (!vcpu_has_sve(vcpu)) 1808c2ecf20Sopenharmony_ci return -EINVAL; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci if (kvm_arm_vcpu_sve_finalized(vcpu)) 1838c2ecf20Sopenharmony_ci return -EPERM; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci return kvm_vcpu_finalize_sve(vcpu); 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci return -EINVAL; 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cibool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci if (vcpu_has_sve(vcpu) && !kvm_arm_vcpu_sve_finalized(vcpu)) 1948c2ecf20Sopenharmony_ci return false; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci return true; 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_civoid kvm_arm_vcpu_destroy(struct kvm_vcpu *vcpu) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci kfree(vcpu->arch.sve_state); 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistatic void kvm_vcpu_reset_sve(struct kvm_vcpu *vcpu) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci if (vcpu_has_sve(vcpu)) 2078c2ecf20Sopenharmony_ci memset(vcpu->arch.sve_state, 0, vcpu_sve_state_size(vcpu)); 2088c2ecf20Sopenharmony_ci} 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_cistatic int kvm_vcpu_enable_ptrauth(struct kvm_vcpu *vcpu) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci /* 2138c2ecf20Sopenharmony_ci * For now make sure that both address/generic pointer authentication 2148c2ecf20Sopenharmony_ci * features are requested by the userspace together and the system 2158c2ecf20Sopenharmony_ci * supports these capabilities. 2168c2ecf20Sopenharmony_ci */ 2178c2ecf20Sopenharmony_ci if (!test_bit(KVM_ARM_VCPU_PTRAUTH_ADDRESS, vcpu->arch.features) || 2188c2ecf20Sopenharmony_ci !test_bit(KVM_ARM_VCPU_PTRAUTH_GENERIC, vcpu->arch.features) || 2198c2ecf20Sopenharmony_ci !system_has_full_ptr_auth()) 2208c2ecf20Sopenharmony_ci return -EINVAL; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci vcpu->arch.flags |= KVM_ARM64_GUEST_HAS_PTRAUTH; 2238c2ecf20Sopenharmony_ci return 0; 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cistatic bool vcpu_allowed_register_width(struct kvm_vcpu *vcpu) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci struct kvm_vcpu *tmp; 2298c2ecf20Sopenharmony_ci bool is32bit; 2308c2ecf20Sopenharmony_ci int i; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci is32bit = vcpu_has_feature(vcpu, KVM_ARM_VCPU_EL1_32BIT); 2338c2ecf20Sopenharmony_ci if (!cpus_have_const_cap(ARM64_HAS_32BIT_EL1) && is32bit) 2348c2ecf20Sopenharmony_ci return false; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci /* Check that the vcpus are either all 32bit or all 64bit */ 2378c2ecf20Sopenharmony_ci kvm_for_each_vcpu(i, tmp, vcpu->kvm) { 2388c2ecf20Sopenharmony_ci if (vcpu_has_feature(tmp, KVM_ARM_VCPU_EL1_32BIT) != is32bit) 2398c2ecf20Sopenharmony_ci return false; 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci return true; 2438c2ecf20Sopenharmony_ci} 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci/** 2468c2ecf20Sopenharmony_ci * kvm_reset_vcpu - sets core registers and sys_regs to reset value 2478c2ecf20Sopenharmony_ci * @vcpu: The VCPU pointer 2488c2ecf20Sopenharmony_ci * 2498c2ecf20Sopenharmony_ci * This function finds the right table above and sets the registers on 2508c2ecf20Sopenharmony_ci * the virtual CPU struct to their architecturally defined reset 2518c2ecf20Sopenharmony_ci * values, except for registers whose reset is deferred until 2528c2ecf20Sopenharmony_ci * kvm_arm_vcpu_finalize(). 2538c2ecf20Sopenharmony_ci * 2548c2ecf20Sopenharmony_ci * Note: This function can be called from two paths: The KVM_ARM_VCPU_INIT 2558c2ecf20Sopenharmony_ci * ioctl or as part of handling a request issued by another VCPU in the PSCI 2568c2ecf20Sopenharmony_ci * handling code. In the first case, the VCPU will not be loaded, and in the 2578c2ecf20Sopenharmony_ci * second case the VCPU will be loaded. Because this function operates purely 2588c2ecf20Sopenharmony_ci * on the memory-backed values of system registers, we want to do a full put if 2598c2ecf20Sopenharmony_ci * we were loaded (handling a request) and load the values back at the end of 2608c2ecf20Sopenharmony_ci * the function. Otherwise we leave the state alone. In both cases, we 2618c2ecf20Sopenharmony_ci * disable preemption around the vcpu reset as we would otherwise race with 2628c2ecf20Sopenharmony_ci * preempt notifiers which also call put/load. 2638c2ecf20Sopenharmony_ci */ 2648c2ecf20Sopenharmony_ciint kvm_reset_vcpu(struct kvm_vcpu *vcpu) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci struct vcpu_reset_state reset_state; 2678c2ecf20Sopenharmony_ci int ret; 2688c2ecf20Sopenharmony_ci bool loaded; 2698c2ecf20Sopenharmony_ci u32 pstate; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci mutex_lock(&vcpu->kvm->lock); 2728c2ecf20Sopenharmony_ci reset_state = vcpu->arch.reset_state; 2738c2ecf20Sopenharmony_ci WRITE_ONCE(vcpu->arch.reset_state.reset, false); 2748c2ecf20Sopenharmony_ci mutex_unlock(&vcpu->kvm->lock); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci /* Reset PMU outside of the non-preemptible section */ 2778c2ecf20Sopenharmony_ci kvm_pmu_vcpu_reset(vcpu); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci preempt_disable(); 2808c2ecf20Sopenharmony_ci loaded = (vcpu->cpu != -1); 2818c2ecf20Sopenharmony_ci if (loaded) 2828c2ecf20Sopenharmony_ci kvm_arch_vcpu_put(vcpu); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci if (!kvm_arm_vcpu_sve_finalized(vcpu)) { 2858c2ecf20Sopenharmony_ci if (test_bit(KVM_ARM_VCPU_SVE, vcpu->arch.features)) { 2868c2ecf20Sopenharmony_ci ret = kvm_vcpu_enable_sve(vcpu); 2878c2ecf20Sopenharmony_ci if (ret) 2888c2ecf20Sopenharmony_ci goto out; 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci } else { 2918c2ecf20Sopenharmony_ci kvm_vcpu_reset_sve(vcpu); 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci if (test_bit(KVM_ARM_VCPU_PTRAUTH_ADDRESS, vcpu->arch.features) || 2958c2ecf20Sopenharmony_ci test_bit(KVM_ARM_VCPU_PTRAUTH_GENERIC, vcpu->arch.features)) { 2968c2ecf20Sopenharmony_ci if (kvm_vcpu_enable_ptrauth(vcpu)) { 2978c2ecf20Sopenharmony_ci ret = -EINVAL; 2988c2ecf20Sopenharmony_ci goto out; 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci if (!vcpu_allowed_register_width(vcpu)) { 3038c2ecf20Sopenharmony_ci ret = -EINVAL; 3048c2ecf20Sopenharmony_ci goto out; 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci switch (vcpu->arch.target) { 3088c2ecf20Sopenharmony_ci default: 3098c2ecf20Sopenharmony_ci if (test_bit(KVM_ARM_VCPU_EL1_32BIT, vcpu->arch.features)) { 3108c2ecf20Sopenharmony_ci pstate = VCPU_RESET_PSTATE_SVC; 3118c2ecf20Sopenharmony_ci } else { 3128c2ecf20Sopenharmony_ci pstate = VCPU_RESET_PSTATE_EL1; 3138c2ecf20Sopenharmony_ci } 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci break; 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci /* Reset core registers */ 3198c2ecf20Sopenharmony_ci memset(vcpu_gp_regs(vcpu), 0, sizeof(*vcpu_gp_regs(vcpu))); 3208c2ecf20Sopenharmony_ci memset(&vcpu->arch.ctxt.fp_regs, 0, sizeof(vcpu->arch.ctxt.fp_regs)); 3218c2ecf20Sopenharmony_ci vcpu->arch.ctxt.spsr_abt = 0; 3228c2ecf20Sopenharmony_ci vcpu->arch.ctxt.spsr_und = 0; 3238c2ecf20Sopenharmony_ci vcpu->arch.ctxt.spsr_irq = 0; 3248c2ecf20Sopenharmony_ci vcpu->arch.ctxt.spsr_fiq = 0; 3258c2ecf20Sopenharmony_ci vcpu_gp_regs(vcpu)->pstate = pstate; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci /* Reset system registers */ 3288c2ecf20Sopenharmony_ci kvm_reset_sys_regs(vcpu); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci /* 3318c2ecf20Sopenharmony_ci * Additional reset state handling that PSCI may have imposed on us. 3328c2ecf20Sopenharmony_ci * Must be done after all the sys_reg reset. 3338c2ecf20Sopenharmony_ci */ 3348c2ecf20Sopenharmony_ci if (reset_state.reset) { 3358c2ecf20Sopenharmony_ci unsigned long target_pc = reset_state.pc; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci /* Gracefully handle Thumb2 entry point */ 3388c2ecf20Sopenharmony_ci if (vcpu_mode_is_32bit(vcpu) && (target_pc & 1)) { 3398c2ecf20Sopenharmony_ci target_pc &= ~1UL; 3408c2ecf20Sopenharmony_ci vcpu_set_thumb(vcpu); 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci /* Propagate caller endianness */ 3448c2ecf20Sopenharmony_ci if (reset_state.be) 3458c2ecf20Sopenharmony_ci kvm_vcpu_set_be(vcpu); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci *vcpu_pc(vcpu) = target_pc; 3488c2ecf20Sopenharmony_ci vcpu_set_reg(vcpu, 0, reset_state.r0); 3498c2ecf20Sopenharmony_ci } 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci /* Reset timer */ 3528c2ecf20Sopenharmony_ci ret = kvm_timer_vcpu_reset(vcpu); 3538c2ecf20Sopenharmony_ciout: 3548c2ecf20Sopenharmony_ci if (loaded) 3558c2ecf20Sopenharmony_ci kvm_arch_vcpu_load(vcpu, smp_processor_id()); 3568c2ecf20Sopenharmony_ci preempt_enable(); 3578c2ecf20Sopenharmony_ci return ret; 3588c2ecf20Sopenharmony_ci} 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ciu32 get_kvm_ipa_limit(void) 3618c2ecf20Sopenharmony_ci{ 3628c2ecf20Sopenharmony_ci return kvm_ipa_limit; 3638c2ecf20Sopenharmony_ci} 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ciint kvm_set_ipa_limit(void) 3668c2ecf20Sopenharmony_ci{ 3678c2ecf20Sopenharmony_ci unsigned int parange, tgran_2; 3688c2ecf20Sopenharmony_ci u64 mmfr0; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci mmfr0 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1); 3718c2ecf20Sopenharmony_ci parange = cpuid_feature_extract_unsigned_field(mmfr0, 3728c2ecf20Sopenharmony_ci ID_AA64MMFR0_PARANGE_SHIFT); 3738c2ecf20Sopenharmony_ci /* 3748c2ecf20Sopenharmony_ci * IPA size beyond 48 bits could not be supported 3758c2ecf20Sopenharmony_ci * on either 4K or 16K page size. Hence let's cap 3768c2ecf20Sopenharmony_ci * it to 48 bits, in case it's reported as larger 3778c2ecf20Sopenharmony_ci * on the system. 3788c2ecf20Sopenharmony_ci */ 3798c2ecf20Sopenharmony_ci if (PAGE_SIZE != SZ_64K) 3808c2ecf20Sopenharmony_ci parange = min(parange, (unsigned int)ID_AA64MMFR0_PARANGE_48); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci /* 3838c2ecf20Sopenharmony_ci * Check with ARMv8.5-GTG that our PAGE_SIZE is supported at 3848c2ecf20Sopenharmony_ci * Stage-2. If not, things will stop very quickly. 3858c2ecf20Sopenharmony_ci */ 3868c2ecf20Sopenharmony_ci switch (PAGE_SIZE) { 3878c2ecf20Sopenharmony_ci default: 3888c2ecf20Sopenharmony_ci case SZ_4K: 3898c2ecf20Sopenharmony_ci tgran_2 = ID_AA64MMFR0_TGRAN4_2_SHIFT; 3908c2ecf20Sopenharmony_ci break; 3918c2ecf20Sopenharmony_ci case SZ_16K: 3928c2ecf20Sopenharmony_ci tgran_2 = ID_AA64MMFR0_TGRAN16_2_SHIFT; 3938c2ecf20Sopenharmony_ci break; 3948c2ecf20Sopenharmony_ci case SZ_64K: 3958c2ecf20Sopenharmony_ci tgran_2 = ID_AA64MMFR0_TGRAN64_2_SHIFT; 3968c2ecf20Sopenharmony_ci break; 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci switch (cpuid_feature_extract_unsigned_field(mmfr0, tgran_2)) { 4008c2ecf20Sopenharmony_ci case ID_AA64MMFR0_TGRAN_2_SUPPORTED_NONE: 4018c2ecf20Sopenharmony_ci kvm_err("PAGE_SIZE not supported at Stage-2, giving up\n"); 4028c2ecf20Sopenharmony_ci return -EINVAL; 4038c2ecf20Sopenharmony_ci case ID_AA64MMFR0_TGRAN_2_SUPPORTED_DEFAULT: 4048c2ecf20Sopenharmony_ci kvm_debug("PAGE_SIZE supported at Stage-2 (default)\n"); 4058c2ecf20Sopenharmony_ci break; 4068c2ecf20Sopenharmony_ci case ID_AA64MMFR0_TGRAN_2_SUPPORTED_MIN ... ID_AA64MMFR0_TGRAN_2_SUPPORTED_MAX: 4078c2ecf20Sopenharmony_ci kvm_debug("PAGE_SIZE supported at Stage-2 (advertised)\n"); 4088c2ecf20Sopenharmony_ci break; 4098c2ecf20Sopenharmony_ci default: 4108c2ecf20Sopenharmony_ci kvm_err("Unsupported value for TGRAN_2, giving up\n"); 4118c2ecf20Sopenharmony_ci return -EINVAL; 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci kvm_ipa_limit = id_aa64mmfr0_parange_to_phys_shift(parange); 4158c2ecf20Sopenharmony_ci kvm_info("IPA Size Limit: %d bits%s\n", kvm_ipa_limit, 4168c2ecf20Sopenharmony_ci ((kvm_ipa_limit < KVM_PHYS_SHIFT) ? 4178c2ecf20Sopenharmony_ci " (Reduced IPA size, limited VM/VMM compatibility)" : "")); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci return 0; 4208c2ecf20Sopenharmony_ci} 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci/* 4238c2ecf20Sopenharmony_ci * Configure the VTCR_EL2 for this VM. The VTCR value is common 4248c2ecf20Sopenharmony_ci * across all the physical CPUs on the system. We use system wide 4258c2ecf20Sopenharmony_ci * sanitised values to fill in different fields, except for Hardware 4268c2ecf20Sopenharmony_ci * Management of Access Flags. HA Flag is set unconditionally on 4278c2ecf20Sopenharmony_ci * all CPUs, as it is safe to run with or without the feature and 4288c2ecf20Sopenharmony_ci * the bit is RES0 on CPUs that don't support it. 4298c2ecf20Sopenharmony_ci */ 4308c2ecf20Sopenharmony_ciint kvm_arm_setup_stage2(struct kvm *kvm, unsigned long type) 4318c2ecf20Sopenharmony_ci{ 4328c2ecf20Sopenharmony_ci u64 vtcr = VTCR_EL2_FLAGS, mmfr0; 4338c2ecf20Sopenharmony_ci u32 parange, phys_shift; 4348c2ecf20Sopenharmony_ci u8 lvls; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci if (type & ~KVM_VM_TYPE_ARM_IPA_SIZE_MASK) 4378c2ecf20Sopenharmony_ci return -EINVAL; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci phys_shift = KVM_VM_TYPE_ARM_IPA_SIZE(type); 4408c2ecf20Sopenharmony_ci if (phys_shift) { 4418c2ecf20Sopenharmony_ci if (phys_shift > kvm_ipa_limit || 4428c2ecf20Sopenharmony_ci phys_shift < 32) 4438c2ecf20Sopenharmony_ci return -EINVAL; 4448c2ecf20Sopenharmony_ci } else { 4458c2ecf20Sopenharmony_ci phys_shift = KVM_PHYS_SHIFT; 4468c2ecf20Sopenharmony_ci if (phys_shift > kvm_ipa_limit) { 4478c2ecf20Sopenharmony_ci pr_warn_once("%s using unsupported default IPA limit, upgrade your VMM\n", 4488c2ecf20Sopenharmony_ci current->comm); 4498c2ecf20Sopenharmony_ci return -EINVAL; 4508c2ecf20Sopenharmony_ci } 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci mmfr0 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1); 4548c2ecf20Sopenharmony_ci parange = cpuid_feature_extract_unsigned_field(mmfr0, 4558c2ecf20Sopenharmony_ci ID_AA64MMFR0_PARANGE_SHIFT); 4568c2ecf20Sopenharmony_ci if (parange > ID_AA64MMFR0_PARANGE_MAX) 4578c2ecf20Sopenharmony_ci parange = ID_AA64MMFR0_PARANGE_MAX; 4588c2ecf20Sopenharmony_ci vtcr |= parange << VTCR_EL2_PS_SHIFT; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci vtcr |= VTCR_EL2_T0SZ(phys_shift); 4618c2ecf20Sopenharmony_ci /* 4628c2ecf20Sopenharmony_ci * Use a minimum 2 level page table to prevent splitting 4638c2ecf20Sopenharmony_ci * host PMD huge pages at stage2. 4648c2ecf20Sopenharmony_ci */ 4658c2ecf20Sopenharmony_ci lvls = stage2_pgtable_levels(phys_shift); 4668c2ecf20Sopenharmony_ci if (lvls < 2) 4678c2ecf20Sopenharmony_ci lvls = 2; 4688c2ecf20Sopenharmony_ci vtcr |= VTCR_EL2_LVLS_TO_SL0(lvls); 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci /* 4718c2ecf20Sopenharmony_ci * Enable the Hardware Access Flag management, unconditionally 4728c2ecf20Sopenharmony_ci * on all CPUs. The features is RES0 on CPUs without the support 4738c2ecf20Sopenharmony_ci * and must be ignored by the CPUs. 4748c2ecf20Sopenharmony_ci */ 4758c2ecf20Sopenharmony_ci vtcr |= VTCR_EL2_HA; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci /* Set the vmid bits */ 4788c2ecf20Sopenharmony_ci vtcr |= (kvm_get_vmid_bits() == 16) ? 4798c2ecf20Sopenharmony_ci VTCR_EL2_VS_16BIT : 4808c2ecf20Sopenharmony_ci VTCR_EL2_VS_8BIT; 4818c2ecf20Sopenharmony_ci kvm->arch.vtcr = vtcr; 4828c2ecf20Sopenharmony_ci return 0; 4838c2ecf20Sopenharmony_ci} 484