162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci// Copyright (C) 2019 Arm Ltd. 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/arm-smccc.h> 562306a36Sopenharmony_ci#include <linux/kvm_host.h> 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <asm/kvm_emulate.h> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <kvm/arm_hypercalls.h> 1062306a36Sopenharmony_ci#include <kvm/arm_psci.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#define KVM_ARM_SMCCC_STD_FEATURES \ 1362306a36Sopenharmony_ci GENMASK(KVM_REG_ARM_STD_BMAP_BIT_COUNT - 1, 0) 1462306a36Sopenharmony_ci#define KVM_ARM_SMCCC_STD_HYP_FEATURES \ 1562306a36Sopenharmony_ci GENMASK(KVM_REG_ARM_STD_HYP_BMAP_BIT_COUNT - 1, 0) 1662306a36Sopenharmony_ci#define KVM_ARM_SMCCC_VENDOR_HYP_FEATURES \ 1762306a36Sopenharmony_ci GENMASK(KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_COUNT - 1, 0) 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistatic void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val) 2062306a36Sopenharmony_ci{ 2162306a36Sopenharmony_ci struct system_time_snapshot systime_snapshot; 2262306a36Sopenharmony_ci u64 cycles = ~0UL; 2362306a36Sopenharmony_ci u32 feature; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci /* 2662306a36Sopenharmony_ci * system time and counter value must captured at the same 2762306a36Sopenharmony_ci * time to keep consistency and precision. 2862306a36Sopenharmony_ci */ 2962306a36Sopenharmony_ci ktime_get_snapshot(&systime_snapshot); 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci /* 3262306a36Sopenharmony_ci * This is only valid if the current clocksource is the 3362306a36Sopenharmony_ci * architected counter, as this is the only one the guest 3462306a36Sopenharmony_ci * can see. 3562306a36Sopenharmony_ci */ 3662306a36Sopenharmony_ci if (systime_snapshot.cs_id != CSID_ARM_ARCH_COUNTER) 3762306a36Sopenharmony_ci return; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci /* 4062306a36Sopenharmony_ci * The guest selects one of the two reference counters 4162306a36Sopenharmony_ci * (virtual or physical) with the first argument of the SMCCC 4262306a36Sopenharmony_ci * call. In case the identifier is not supported, error out. 4362306a36Sopenharmony_ci */ 4462306a36Sopenharmony_ci feature = smccc_get_arg1(vcpu); 4562306a36Sopenharmony_ci switch (feature) { 4662306a36Sopenharmony_ci case KVM_PTP_VIRT_COUNTER: 4762306a36Sopenharmony_ci cycles = systime_snapshot.cycles - vcpu->kvm->arch.timer_data.voffset; 4862306a36Sopenharmony_ci break; 4962306a36Sopenharmony_ci case KVM_PTP_PHYS_COUNTER: 5062306a36Sopenharmony_ci cycles = systime_snapshot.cycles - vcpu->kvm->arch.timer_data.poffset; 5162306a36Sopenharmony_ci break; 5262306a36Sopenharmony_ci default: 5362306a36Sopenharmony_ci return; 5462306a36Sopenharmony_ci } 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci /* 5762306a36Sopenharmony_ci * This relies on the top bit of val[0] never being set for 5862306a36Sopenharmony_ci * valid values of system time, because that is *really* far 5962306a36Sopenharmony_ci * in the future (about 292 years from 1970, and at that stage 6062306a36Sopenharmony_ci * nobody will give a damn about it). 6162306a36Sopenharmony_ci */ 6262306a36Sopenharmony_ci val[0] = upper_32_bits(systime_snapshot.real); 6362306a36Sopenharmony_ci val[1] = lower_32_bits(systime_snapshot.real); 6462306a36Sopenharmony_ci val[2] = upper_32_bits(cycles); 6562306a36Sopenharmony_ci val[3] = lower_32_bits(cycles); 6662306a36Sopenharmony_ci} 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistatic bool kvm_smccc_default_allowed(u32 func_id) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci switch (func_id) { 7162306a36Sopenharmony_ci /* 7262306a36Sopenharmony_ci * List of function-ids that are not gated with the bitmapped 7362306a36Sopenharmony_ci * feature firmware registers, and are to be allowed for 7462306a36Sopenharmony_ci * servicing the call by default. 7562306a36Sopenharmony_ci */ 7662306a36Sopenharmony_ci case ARM_SMCCC_VERSION_FUNC_ID: 7762306a36Sopenharmony_ci case ARM_SMCCC_ARCH_FEATURES_FUNC_ID: 7862306a36Sopenharmony_ci return true; 7962306a36Sopenharmony_ci default: 8062306a36Sopenharmony_ci /* PSCI 0.2 and up is in the 0:0x1f range */ 8162306a36Sopenharmony_ci if (ARM_SMCCC_OWNER_NUM(func_id) == ARM_SMCCC_OWNER_STANDARD && 8262306a36Sopenharmony_ci ARM_SMCCC_FUNC_NUM(func_id) <= 0x1f) 8362306a36Sopenharmony_ci return true; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci /* 8662306a36Sopenharmony_ci * KVM's PSCI 0.1 doesn't comply with SMCCC, and has 8762306a36Sopenharmony_ci * its own function-id base and range 8862306a36Sopenharmony_ci */ 8962306a36Sopenharmony_ci if (func_id >= KVM_PSCI_FN(0) && func_id <= KVM_PSCI_FN(3)) 9062306a36Sopenharmony_ci return true; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci return false; 9362306a36Sopenharmony_ci } 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cistatic bool kvm_smccc_test_fw_bmap(struct kvm_vcpu *vcpu, u32 func_id) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci switch (func_id) { 10162306a36Sopenharmony_ci case ARM_SMCCC_TRNG_VERSION: 10262306a36Sopenharmony_ci case ARM_SMCCC_TRNG_FEATURES: 10362306a36Sopenharmony_ci case ARM_SMCCC_TRNG_GET_UUID: 10462306a36Sopenharmony_ci case ARM_SMCCC_TRNG_RND32: 10562306a36Sopenharmony_ci case ARM_SMCCC_TRNG_RND64: 10662306a36Sopenharmony_ci return test_bit(KVM_REG_ARM_STD_BIT_TRNG_V1_0, 10762306a36Sopenharmony_ci &smccc_feat->std_bmap); 10862306a36Sopenharmony_ci case ARM_SMCCC_HV_PV_TIME_FEATURES: 10962306a36Sopenharmony_ci case ARM_SMCCC_HV_PV_TIME_ST: 11062306a36Sopenharmony_ci return test_bit(KVM_REG_ARM_STD_HYP_BIT_PV_TIME, 11162306a36Sopenharmony_ci &smccc_feat->std_hyp_bmap); 11262306a36Sopenharmony_ci case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID: 11362306a36Sopenharmony_ci case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID: 11462306a36Sopenharmony_ci return test_bit(KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT, 11562306a36Sopenharmony_ci &smccc_feat->vendor_hyp_bmap); 11662306a36Sopenharmony_ci case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID: 11762306a36Sopenharmony_ci return test_bit(KVM_REG_ARM_VENDOR_HYP_BIT_PTP, 11862306a36Sopenharmony_ci &smccc_feat->vendor_hyp_bmap); 11962306a36Sopenharmony_ci default: 12062306a36Sopenharmony_ci return false; 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci#define SMC32_ARCH_RANGE_BEGIN ARM_SMCCC_VERSION_FUNC_ID 12562306a36Sopenharmony_ci#define SMC32_ARCH_RANGE_END ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ 12662306a36Sopenharmony_ci ARM_SMCCC_SMC_32, \ 12762306a36Sopenharmony_ci 0, ARM_SMCCC_FUNC_MASK) 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci#define SMC64_ARCH_RANGE_BEGIN ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ 13062306a36Sopenharmony_ci ARM_SMCCC_SMC_64, \ 13162306a36Sopenharmony_ci 0, 0) 13262306a36Sopenharmony_ci#define SMC64_ARCH_RANGE_END ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ 13362306a36Sopenharmony_ci ARM_SMCCC_SMC_64, \ 13462306a36Sopenharmony_ci 0, ARM_SMCCC_FUNC_MASK) 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic void init_smccc_filter(struct kvm *kvm) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci int r; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci mt_init(&kvm->arch.smccc_filter); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci /* 14362306a36Sopenharmony_ci * Prevent userspace from handling any SMCCC calls in the architecture 14462306a36Sopenharmony_ci * range, avoiding the risk of misrepresenting Spectre mitigation status 14562306a36Sopenharmony_ci * to the guest. 14662306a36Sopenharmony_ci */ 14762306a36Sopenharmony_ci r = mtree_insert_range(&kvm->arch.smccc_filter, 14862306a36Sopenharmony_ci SMC32_ARCH_RANGE_BEGIN, SMC32_ARCH_RANGE_END, 14962306a36Sopenharmony_ci xa_mk_value(KVM_SMCCC_FILTER_HANDLE), 15062306a36Sopenharmony_ci GFP_KERNEL_ACCOUNT); 15162306a36Sopenharmony_ci WARN_ON_ONCE(r); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci r = mtree_insert_range(&kvm->arch.smccc_filter, 15462306a36Sopenharmony_ci SMC64_ARCH_RANGE_BEGIN, SMC64_ARCH_RANGE_END, 15562306a36Sopenharmony_ci xa_mk_value(KVM_SMCCC_FILTER_HANDLE), 15662306a36Sopenharmony_ci GFP_KERNEL_ACCOUNT); 15762306a36Sopenharmony_ci WARN_ON_ONCE(r); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic int kvm_smccc_set_filter(struct kvm *kvm, struct kvm_smccc_filter __user *uaddr) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci const void *zero_page = page_to_virt(ZERO_PAGE(0)); 16462306a36Sopenharmony_ci struct kvm_smccc_filter filter; 16562306a36Sopenharmony_ci u32 start, end; 16662306a36Sopenharmony_ci int r; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci if (copy_from_user(&filter, uaddr, sizeof(filter))) 16962306a36Sopenharmony_ci return -EFAULT; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci if (memcmp(filter.pad, zero_page, sizeof(filter.pad))) 17262306a36Sopenharmony_ci return -EINVAL; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci start = filter.base; 17562306a36Sopenharmony_ci end = start + filter.nr_functions - 1; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci if (end < start || filter.action >= NR_SMCCC_FILTER_ACTIONS) 17862306a36Sopenharmony_ci return -EINVAL; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci mutex_lock(&kvm->arch.config_lock); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci if (kvm_vm_has_ran_once(kvm)) { 18362306a36Sopenharmony_ci r = -EBUSY; 18462306a36Sopenharmony_ci goto out_unlock; 18562306a36Sopenharmony_ci } 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci r = mtree_insert_range(&kvm->arch.smccc_filter, start, end, 18862306a36Sopenharmony_ci xa_mk_value(filter.action), GFP_KERNEL_ACCOUNT); 18962306a36Sopenharmony_ci if (r) 19062306a36Sopenharmony_ci goto out_unlock; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci set_bit(KVM_ARCH_FLAG_SMCCC_FILTER_CONFIGURED, &kvm->arch.flags); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ciout_unlock: 19562306a36Sopenharmony_ci mutex_unlock(&kvm->arch.config_lock); 19662306a36Sopenharmony_ci return r; 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_cistatic u8 kvm_smccc_filter_get_action(struct kvm *kvm, u32 func_id) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci unsigned long idx = func_id; 20262306a36Sopenharmony_ci void *val; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci if (!test_bit(KVM_ARCH_FLAG_SMCCC_FILTER_CONFIGURED, &kvm->arch.flags)) 20562306a36Sopenharmony_ci return KVM_SMCCC_FILTER_HANDLE; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci /* 20862306a36Sopenharmony_ci * But where's the error handling, you say? 20962306a36Sopenharmony_ci * 21062306a36Sopenharmony_ci * mt_find() returns NULL if no entry was found, which just so happens 21162306a36Sopenharmony_ci * to match KVM_SMCCC_FILTER_HANDLE. 21262306a36Sopenharmony_ci */ 21362306a36Sopenharmony_ci val = mt_find(&kvm->arch.smccc_filter, &idx, idx); 21462306a36Sopenharmony_ci return xa_to_value(val); 21562306a36Sopenharmony_ci} 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_cistatic u8 kvm_smccc_get_action(struct kvm_vcpu *vcpu, u32 func_id) 21862306a36Sopenharmony_ci{ 21962306a36Sopenharmony_ci /* 22062306a36Sopenharmony_ci * Intervening actions in the SMCCC filter take precedence over the 22162306a36Sopenharmony_ci * pseudo-firmware register bitmaps. 22262306a36Sopenharmony_ci */ 22362306a36Sopenharmony_ci u8 action = kvm_smccc_filter_get_action(vcpu->kvm, func_id); 22462306a36Sopenharmony_ci if (action != KVM_SMCCC_FILTER_HANDLE) 22562306a36Sopenharmony_ci return action; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci if (kvm_smccc_test_fw_bmap(vcpu, func_id) || 22862306a36Sopenharmony_ci kvm_smccc_default_allowed(func_id)) 22962306a36Sopenharmony_ci return KVM_SMCCC_FILTER_HANDLE; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci return KVM_SMCCC_FILTER_DENY; 23262306a36Sopenharmony_ci} 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_cistatic void kvm_prepare_hypercall_exit(struct kvm_vcpu *vcpu, u32 func_id) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci u8 ec = ESR_ELx_EC(kvm_vcpu_get_esr(vcpu)); 23762306a36Sopenharmony_ci struct kvm_run *run = vcpu->run; 23862306a36Sopenharmony_ci u64 flags = 0; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci if (ec == ESR_ELx_EC_SMC32 || ec == ESR_ELx_EC_SMC64) 24162306a36Sopenharmony_ci flags |= KVM_HYPERCALL_EXIT_SMC; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci if (!kvm_vcpu_trap_il_is32bit(vcpu)) 24462306a36Sopenharmony_ci flags |= KVM_HYPERCALL_EXIT_16BIT; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci run->exit_reason = KVM_EXIT_HYPERCALL; 24762306a36Sopenharmony_ci run->hypercall = (typeof(run->hypercall)) { 24862306a36Sopenharmony_ci .nr = func_id, 24962306a36Sopenharmony_ci .flags = flags, 25062306a36Sopenharmony_ci }; 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ciint kvm_smccc_call_handler(struct kvm_vcpu *vcpu) 25462306a36Sopenharmony_ci{ 25562306a36Sopenharmony_ci struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat; 25662306a36Sopenharmony_ci u32 func_id = smccc_get_function(vcpu); 25762306a36Sopenharmony_ci u64 val[4] = {SMCCC_RET_NOT_SUPPORTED}; 25862306a36Sopenharmony_ci u32 feature; 25962306a36Sopenharmony_ci u8 action; 26062306a36Sopenharmony_ci gpa_t gpa; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci action = kvm_smccc_get_action(vcpu, func_id); 26362306a36Sopenharmony_ci switch (action) { 26462306a36Sopenharmony_ci case KVM_SMCCC_FILTER_HANDLE: 26562306a36Sopenharmony_ci break; 26662306a36Sopenharmony_ci case KVM_SMCCC_FILTER_DENY: 26762306a36Sopenharmony_ci goto out; 26862306a36Sopenharmony_ci case KVM_SMCCC_FILTER_FWD_TO_USER: 26962306a36Sopenharmony_ci kvm_prepare_hypercall_exit(vcpu, func_id); 27062306a36Sopenharmony_ci return 0; 27162306a36Sopenharmony_ci default: 27262306a36Sopenharmony_ci WARN_RATELIMIT(1, "Unhandled SMCCC filter action: %d\n", action); 27362306a36Sopenharmony_ci goto out; 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci switch (func_id) { 27762306a36Sopenharmony_ci case ARM_SMCCC_VERSION_FUNC_ID: 27862306a36Sopenharmony_ci val[0] = ARM_SMCCC_VERSION_1_1; 27962306a36Sopenharmony_ci break; 28062306a36Sopenharmony_ci case ARM_SMCCC_ARCH_FEATURES_FUNC_ID: 28162306a36Sopenharmony_ci feature = smccc_get_arg1(vcpu); 28262306a36Sopenharmony_ci switch (feature) { 28362306a36Sopenharmony_ci case ARM_SMCCC_ARCH_WORKAROUND_1: 28462306a36Sopenharmony_ci switch (arm64_get_spectre_v2_state()) { 28562306a36Sopenharmony_ci case SPECTRE_VULNERABLE: 28662306a36Sopenharmony_ci break; 28762306a36Sopenharmony_ci case SPECTRE_MITIGATED: 28862306a36Sopenharmony_ci val[0] = SMCCC_RET_SUCCESS; 28962306a36Sopenharmony_ci break; 29062306a36Sopenharmony_ci case SPECTRE_UNAFFECTED: 29162306a36Sopenharmony_ci val[0] = SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED; 29262306a36Sopenharmony_ci break; 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci break; 29562306a36Sopenharmony_ci case ARM_SMCCC_ARCH_WORKAROUND_2: 29662306a36Sopenharmony_ci switch (arm64_get_spectre_v4_state()) { 29762306a36Sopenharmony_ci case SPECTRE_VULNERABLE: 29862306a36Sopenharmony_ci break; 29962306a36Sopenharmony_ci case SPECTRE_MITIGATED: 30062306a36Sopenharmony_ci /* 30162306a36Sopenharmony_ci * SSBS everywhere: Indicate no firmware 30262306a36Sopenharmony_ci * support, as the SSBS support will be 30362306a36Sopenharmony_ci * indicated to the guest and the default is 30462306a36Sopenharmony_ci * safe. 30562306a36Sopenharmony_ci * 30662306a36Sopenharmony_ci * Otherwise, expose a permanent mitigation 30762306a36Sopenharmony_ci * to the guest, and hide SSBS so that the 30862306a36Sopenharmony_ci * guest stays protected. 30962306a36Sopenharmony_ci */ 31062306a36Sopenharmony_ci if (cpus_have_final_cap(ARM64_SSBS)) 31162306a36Sopenharmony_ci break; 31262306a36Sopenharmony_ci fallthrough; 31362306a36Sopenharmony_ci case SPECTRE_UNAFFECTED: 31462306a36Sopenharmony_ci val[0] = SMCCC_RET_NOT_REQUIRED; 31562306a36Sopenharmony_ci break; 31662306a36Sopenharmony_ci } 31762306a36Sopenharmony_ci break; 31862306a36Sopenharmony_ci case ARM_SMCCC_ARCH_WORKAROUND_3: 31962306a36Sopenharmony_ci switch (arm64_get_spectre_bhb_state()) { 32062306a36Sopenharmony_ci case SPECTRE_VULNERABLE: 32162306a36Sopenharmony_ci break; 32262306a36Sopenharmony_ci case SPECTRE_MITIGATED: 32362306a36Sopenharmony_ci val[0] = SMCCC_RET_SUCCESS; 32462306a36Sopenharmony_ci break; 32562306a36Sopenharmony_ci case SPECTRE_UNAFFECTED: 32662306a36Sopenharmony_ci val[0] = SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED; 32762306a36Sopenharmony_ci break; 32862306a36Sopenharmony_ci } 32962306a36Sopenharmony_ci break; 33062306a36Sopenharmony_ci case ARM_SMCCC_HV_PV_TIME_FEATURES: 33162306a36Sopenharmony_ci if (test_bit(KVM_REG_ARM_STD_HYP_BIT_PV_TIME, 33262306a36Sopenharmony_ci &smccc_feat->std_hyp_bmap)) 33362306a36Sopenharmony_ci val[0] = SMCCC_RET_SUCCESS; 33462306a36Sopenharmony_ci break; 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci break; 33762306a36Sopenharmony_ci case ARM_SMCCC_HV_PV_TIME_FEATURES: 33862306a36Sopenharmony_ci val[0] = kvm_hypercall_pv_features(vcpu); 33962306a36Sopenharmony_ci break; 34062306a36Sopenharmony_ci case ARM_SMCCC_HV_PV_TIME_ST: 34162306a36Sopenharmony_ci gpa = kvm_init_stolen_time(vcpu); 34262306a36Sopenharmony_ci if (gpa != INVALID_GPA) 34362306a36Sopenharmony_ci val[0] = gpa; 34462306a36Sopenharmony_ci break; 34562306a36Sopenharmony_ci case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID: 34662306a36Sopenharmony_ci val[0] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_0; 34762306a36Sopenharmony_ci val[1] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_1; 34862306a36Sopenharmony_ci val[2] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_2; 34962306a36Sopenharmony_ci val[3] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_3; 35062306a36Sopenharmony_ci break; 35162306a36Sopenharmony_ci case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID: 35262306a36Sopenharmony_ci val[0] = smccc_feat->vendor_hyp_bmap; 35362306a36Sopenharmony_ci break; 35462306a36Sopenharmony_ci case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID: 35562306a36Sopenharmony_ci kvm_ptp_get_time(vcpu, val); 35662306a36Sopenharmony_ci break; 35762306a36Sopenharmony_ci case ARM_SMCCC_TRNG_VERSION: 35862306a36Sopenharmony_ci case ARM_SMCCC_TRNG_FEATURES: 35962306a36Sopenharmony_ci case ARM_SMCCC_TRNG_GET_UUID: 36062306a36Sopenharmony_ci case ARM_SMCCC_TRNG_RND32: 36162306a36Sopenharmony_ci case ARM_SMCCC_TRNG_RND64: 36262306a36Sopenharmony_ci return kvm_trng_call(vcpu); 36362306a36Sopenharmony_ci default: 36462306a36Sopenharmony_ci return kvm_psci_call(vcpu); 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ciout: 36862306a36Sopenharmony_ci smccc_set_retval(vcpu, val[0], val[1], val[2], val[3]); 36962306a36Sopenharmony_ci return 1; 37062306a36Sopenharmony_ci} 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_cistatic const u64 kvm_arm_fw_reg_ids[] = { 37362306a36Sopenharmony_ci KVM_REG_ARM_PSCI_VERSION, 37462306a36Sopenharmony_ci KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1, 37562306a36Sopenharmony_ci KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2, 37662306a36Sopenharmony_ci KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3, 37762306a36Sopenharmony_ci KVM_REG_ARM_STD_BMAP, 37862306a36Sopenharmony_ci KVM_REG_ARM_STD_HYP_BMAP, 37962306a36Sopenharmony_ci KVM_REG_ARM_VENDOR_HYP_BMAP, 38062306a36Sopenharmony_ci}; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_civoid kvm_arm_init_hypercalls(struct kvm *kvm) 38362306a36Sopenharmony_ci{ 38462306a36Sopenharmony_ci struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES; 38762306a36Sopenharmony_ci smccc_feat->std_hyp_bmap = KVM_ARM_SMCCC_STD_HYP_FEATURES; 38862306a36Sopenharmony_ci smccc_feat->vendor_hyp_bmap = KVM_ARM_SMCCC_VENDOR_HYP_FEATURES; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci init_smccc_filter(kvm); 39162306a36Sopenharmony_ci} 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_civoid kvm_arm_teardown_hypercalls(struct kvm *kvm) 39462306a36Sopenharmony_ci{ 39562306a36Sopenharmony_ci mtree_destroy(&kvm->arch.smccc_filter); 39662306a36Sopenharmony_ci} 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ciint kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu) 39962306a36Sopenharmony_ci{ 40062306a36Sopenharmony_ci return ARRAY_SIZE(kvm_arm_fw_reg_ids); 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ciint kvm_arm_copy_fw_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci int i; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(kvm_arm_fw_reg_ids); i++) { 40862306a36Sopenharmony_ci if (put_user(kvm_arm_fw_reg_ids[i], uindices++)) 40962306a36Sopenharmony_ci return -EFAULT; 41062306a36Sopenharmony_ci } 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci return 0; 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci#define KVM_REG_FEATURE_LEVEL_MASK GENMASK(3, 0) 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci/* 41862306a36Sopenharmony_ci * Convert the workaround level into an easy-to-compare number, where higher 41962306a36Sopenharmony_ci * values mean better protection. 42062306a36Sopenharmony_ci */ 42162306a36Sopenharmony_cistatic int get_kernel_wa_level(u64 regid) 42262306a36Sopenharmony_ci{ 42362306a36Sopenharmony_ci switch (regid) { 42462306a36Sopenharmony_ci case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1: 42562306a36Sopenharmony_ci switch (arm64_get_spectre_v2_state()) { 42662306a36Sopenharmony_ci case SPECTRE_VULNERABLE: 42762306a36Sopenharmony_ci return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL; 42862306a36Sopenharmony_ci case SPECTRE_MITIGATED: 42962306a36Sopenharmony_ci return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_AVAIL; 43062306a36Sopenharmony_ci case SPECTRE_UNAFFECTED: 43162306a36Sopenharmony_ci return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_REQUIRED; 43262306a36Sopenharmony_ci } 43362306a36Sopenharmony_ci return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL; 43462306a36Sopenharmony_ci case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2: 43562306a36Sopenharmony_ci switch (arm64_get_spectre_v4_state()) { 43662306a36Sopenharmony_ci case SPECTRE_MITIGATED: 43762306a36Sopenharmony_ci /* 43862306a36Sopenharmony_ci * As for the hypercall discovery, we pretend we 43962306a36Sopenharmony_ci * don't have any FW mitigation if SSBS is there at 44062306a36Sopenharmony_ci * all times. 44162306a36Sopenharmony_ci */ 44262306a36Sopenharmony_ci if (cpus_have_final_cap(ARM64_SSBS)) 44362306a36Sopenharmony_ci return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL; 44462306a36Sopenharmony_ci fallthrough; 44562306a36Sopenharmony_ci case SPECTRE_UNAFFECTED: 44662306a36Sopenharmony_ci return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED; 44762306a36Sopenharmony_ci case SPECTRE_VULNERABLE: 44862306a36Sopenharmony_ci return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL; 44962306a36Sopenharmony_ci } 45062306a36Sopenharmony_ci break; 45162306a36Sopenharmony_ci case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3: 45262306a36Sopenharmony_ci switch (arm64_get_spectre_bhb_state()) { 45362306a36Sopenharmony_ci case SPECTRE_VULNERABLE: 45462306a36Sopenharmony_ci return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL; 45562306a36Sopenharmony_ci case SPECTRE_MITIGATED: 45662306a36Sopenharmony_ci return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_AVAIL; 45762306a36Sopenharmony_ci case SPECTRE_UNAFFECTED: 45862306a36Sopenharmony_ci return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_REQUIRED; 45962306a36Sopenharmony_ci } 46062306a36Sopenharmony_ci return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL; 46162306a36Sopenharmony_ci } 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci return -EINVAL; 46462306a36Sopenharmony_ci} 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ciint kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) 46762306a36Sopenharmony_ci{ 46862306a36Sopenharmony_ci struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat; 46962306a36Sopenharmony_ci void __user *uaddr = (void __user *)(long)reg->addr; 47062306a36Sopenharmony_ci u64 val; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci switch (reg->id) { 47362306a36Sopenharmony_ci case KVM_REG_ARM_PSCI_VERSION: 47462306a36Sopenharmony_ci val = kvm_psci_version(vcpu); 47562306a36Sopenharmony_ci break; 47662306a36Sopenharmony_ci case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1: 47762306a36Sopenharmony_ci case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2: 47862306a36Sopenharmony_ci case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3: 47962306a36Sopenharmony_ci val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK; 48062306a36Sopenharmony_ci break; 48162306a36Sopenharmony_ci case KVM_REG_ARM_STD_BMAP: 48262306a36Sopenharmony_ci val = READ_ONCE(smccc_feat->std_bmap); 48362306a36Sopenharmony_ci break; 48462306a36Sopenharmony_ci case KVM_REG_ARM_STD_HYP_BMAP: 48562306a36Sopenharmony_ci val = READ_ONCE(smccc_feat->std_hyp_bmap); 48662306a36Sopenharmony_ci break; 48762306a36Sopenharmony_ci case KVM_REG_ARM_VENDOR_HYP_BMAP: 48862306a36Sopenharmony_ci val = READ_ONCE(smccc_feat->vendor_hyp_bmap); 48962306a36Sopenharmony_ci break; 49062306a36Sopenharmony_ci default: 49162306a36Sopenharmony_ci return -ENOENT; 49262306a36Sopenharmony_ci } 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci if (copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id))) 49562306a36Sopenharmony_ci return -EFAULT; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci return 0; 49862306a36Sopenharmony_ci} 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_cistatic int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val) 50162306a36Sopenharmony_ci{ 50262306a36Sopenharmony_ci int ret = 0; 50362306a36Sopenharmony_ci struct kvm *kvm = vcpu->kvm; 50462306a36Sopenharmony_ci struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat; 50562306a36Sopenharmony_ci unsigned long *fw_reg_bmap, fw_reg_features; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci switch (reg_id) { 50862306a36Sopenharmony_ci case KVM_REG_ARM_STD_BMAP: 50962306a36Sopenharmony_ci fw_reg_bmap = &smccc_feat->std_bmap; 51062306a36Sopenharmony_ci fw_reg_features = KVM_ARM_SMCCC_STD_FEATURES; 51162306a36Sopenharmony_ci break; 51262306a36Sopenharmony_ci case KVM_REG_ARM_STD_HYP_BMAP: 51362306a36Sopenharmony_ci fw_reg_bmap = &smccc_feat->std_hyp_bmap; 51462306a36Sopenharmony_ci fw_reg_features = KVM_ARM_SMCCC_STD_HYP_FEATURES; 51562306a36Sopenharmony_ci break; 51662306a36Sopenharmony_ci case KVM_REG_ARM_VENDOR_HYP_BMAP: 51762306a36Sopenharmony_ci fw_reg_bmap = &smccc_feat->vendor_hyp_bmap; 51862306a36Sopenharmony_ci fw_reg_features = KVM_ARM_SMCCC_VENDOR_HYP_FEATURES; 51962306a36Sopenharmony_ci break; 52062306a36Sopenharmony_ci default: 52162306a36Sopenharmony_ci return -ENOENT; 52262306a36Sopenharmony_ci } 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci /* Check for unsupported bit */ 52562306a36Sopenharmony_ci if (val & ~fw_reg_features) 52662306a36Sopenharmony_ci return -EINVAL; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci mutex_lock(&kvm->arch.config_lock); 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci if (kvm_vm_has_ran_once(kvm) && val != *fw_reg_bmap) { 53162306a36Sopenharmony_ci ret = -EBUSY; 53262306a36Sopenharmony_ci goto out; 53362306a36Sopenharmony_ci } 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci WRITE_ONCE(*fw_reg_bmap, val); 53662306a36Sopenharmony_ciout: 53762306a36Sopenharmony_ci mutex_unlock(&kvm->arch.config_lock); 53862306a36Sopenharmony_ci return ret; 53962306a36Sopenharmony_ci} 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ciint kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) 54262306a36Sopenharmony_ci{ 54362306a36Sopenharmony_ci void __user *uaddr = (void __user *)(long)reg->addr; 54462306a36Sopenharmony_ci u64 val; 54562306a36Sopenharmony_ci int wa_level; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci if (KVM_REG_SIZE(reg->id) != sizeof(val)) 54862306a36Sopenharmony_ci return -ENOENT; 54962306a36Sopenharmony_ci if (copy_from_user(&val, uaddr, KVM_REG_SIZE(reg->id))) 55062306a36Sopenharmony_ci return -EFAULT; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci switch (reg->id) { 55362306a36Sopenharmony_ci case KVM_REG_ARM_PSCI_VERSION: 55462306a36Sopenharmony_ci { 55562306a36Sopenharmony_ci bool wants_02; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci wants_02 = test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features); 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci switch (val) { 56062306a36Sopenharmony_ci case KVM_ARM_PSCI_0_1: 56162306a36Sopenharmony_ci if (wants_02) 56262306a36Sopenharmony_ci return -EINVAL; 56362306a36Sopenharmony_ci vcpu->kvm->arch.psci_version = val; 56462306a36Sopenharmony_ci return 0; 56562306a36Sopenharmony_ci case KVM_ARM_PSCI_0_2: 56662306a36Sopenharmony_ci case KVM_ARM_PSCI_1_0: 56762306a36Sopenharmony_ci case KVM_ARM_PSCI_1_1: 56862306a36Sopenharmony_ci if (!wants_02) 56962306a36Sopenharmony_ci return -EINVAL; 57062306a36Sopenharmony_ci vcpu->kvm->arch.psci_version = val; 57162306a36Sopenharmony_ci return 0; 57262306a36Sopenharmony_ci } 57362306a36Sopenharmony_ci break; 57462306a36Sopenharmony_ci } 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1: 57762306a36Sopenharmony_ci case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3: 57862306a36Sopenharmony_ci if (val & ~KVM_REG_FEATURE_LEVEL_MASK) 57962306a36Sopenharmony_ci return -EINVAL; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci if (get_kernel_wa_level(reg->id) < val) 58262306a36Sopenharmony_ci return -EINVAL; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci return 0; 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2: 58762306a36Sopenharmony_ci if (val & ~(KVM_REG_FEATURE_LEVEL_MASK | 58862306a36Sopenharmony_ci KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED)) 58962306a36Sopenharmony_ci return -EINVAL; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci /* The enabled bit must not be set unless the level is AVAIL. */ 59262306a36Sopenharmony_ci if ((val & KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED) && 59362306a36Sopenharmony_ci (val & KVM_REG_FEATURE_LEVEL_MASK) != KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL) 59462306a36Sopenharmony_ci return -EINVAL; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci /* 59762306a36Sopenharmony_ci * Map all the possible incoming states to the only two we 59862306a36Sopenharmony_ci * really want to deal with. 59962306a36Sopenharmony_ci */ 60062306a36Sopenharmony_ci switch (val & KVM_REG_FEATURE_LEVEL_MASK) { 60162306a36Sopenharmony_ci case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL: 60262306a36Sopenharmony_ci case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_UNKNOWN: 60362306a36Sopenharmony_ci wa_level = KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL; 60462306a36Sopenharmony_ci break; 60562306a36Sopenharmony_ci case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL: 60662306a36Sopenharmony_ci case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED: 60762306a36Sopenharmony_ci wa_level = KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED; 60862306a36Sopenharmony_ci break; 60962306a36Sopenharmony_ci default: 61062306a36Sopenharmony_ci return -EINVAL; 61162306a36Sopenharmony_ci } 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci /* 61462306a36Sopenharmony_ci * We can deal with NOT_AVAIL on NOT_REQUIRED, but not the 61562306a36Sopenharmony_ci * other way around. 61662306a36Sopenharmony_ci */ 61762306a36Sopenharmony_ci if (get_kernel_wa_level(reg->id) < wa_level) 61862306a36Sopenharmony_ci return -EINVAL; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci return 0; 62162306a36Sopenharmony_ci case KVM_REG_ARM_STD_BMAP: 62262306a36Sopenharmony_ci case KVM_REG_ARM_STD_HYP_BMAP: 62362306a36Sopenharmony_ci case KVM_REG_ARM_VENDOR_HYP_BMAP: 62462306a36Sopenharmony_ci return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val); 62562306a36Sopenharmony_ci default: 62662306a36Sopenharmony_ci return -ENOENT; 62762306a36Sopenharmony_ci } 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci return -EINVAL; 63062306a36Sopenharmony_ci} 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ciint kvm_vm_smccc_has_attr(struct kvm *kvm, struct kvm_device_attr *attr) 63362306a36Sopenharmony_ci{ 63462306a36Sopenharmony_ci switch (attr->attr) { 63562306a36Sopenharmony_ci case KVM_ARM_VM_SMCCC_FILTER: 63662306a36Sopenharmony_ci return 0; 63762306a36Sopenharmony_ci default: 63862306a36Sopenharmony_ci return -ENXIO; 63962306a36Sopenharmony_ci } 64062306a36Sopenharmony_ci} 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ciint kvm_vm_smccc_set_attr(struct kvm *kvm, struct kvm_device_attr *attr) 64362306a36Sopenharmony_ci{ 64462306a36Sopenharmony_ci void __user *uaddr = (void __user *)attr->addr; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci switch (attr->attr) { 64762306a36Sopenharmony_ci case KVM_ARM_VM_SMCCC_FILTER: 64862306a36Sopenharmony_ci return kvm_smccc_set_filter(kvm, uaddr); 64962306a36Sopenharmony_ci default: 65062306a36Sopenharmony_ci return -ENXIO; 65162306a36Sopenharmony_ci } 65262306a36Sopenharmony_ci} 653