123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515 |
- // SPDX-License-Identifier: GPL-2.0
- // Copyright (C) 2019 Arm Ltd.
- #include <linux/arm-smccc.h>
- #include <linux/kvm_host.h>
- #include <asm/kvm_emulate.h>
- #include <asm/kvm_pkvm.h>
- #include <kvm/arm_hypercalls.h>
- #include <kvm/arm_psci.h>
- #define KVM_ARM_SMCCC_STD_FEATURES \
- GENMASK(KVM_REG_ARM_STD_BMAP_BIT_COUNT - 1, 0)
- #define KVM_ARM_SMCCC_STD_HYP_FEATURES \
- GENMASK(KVM_REG_ARM_STD_HYP_BMAP_BIT_COUNT - 1, 0)
- #define KVM_ARM_SMCCC_VENDOR_HYP_FEATURES ({ \
- unsigned long f; \
- f = GENMASK(KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_COUNT - 1, 0); \
- if (is_protected_kvm_enabled()) { \
- f |= BIT(ARM_SMCCC_KVM_FUNC_HYP_MEMINFO); \
- f |= BIT(ARM_SMCCC_KVM_FUNC_MEM_RELINQUISH); \
- } \
- f; \
- })
- static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val)
- {
- struct system_time_snapshot systime_snapshot;
- u64 cycles = ~0UL;
- u32 feature;
- /*
- * system time and counter value must captured at the same
- * time to keep consistency and precision.
- */
- ktime_get_snapshot(&systime_snapshot);
- /*
- * This is only valid if the current clocksource is the
- * architected counter, as this is the only one the guest
- * can see.
- */
- if (systime_snapshot.cs_id != CSID_ARM_ARCH_COUNTER)
- return;
- /*
- * The guest selects one of the two reference counters
- * (virtual or physical) with the first argument of the SMCCC
- * call. In case the identifier is not supported, error out.
- */
- feature = smccc_get_arg1(vcpu);
- switch (feature) {
- case KVM_PTP_VIRT_COUNTER:
- cycles = systime_snapshot.cycles - vcpu_read_sys_reg(vcpu, CNTVOFF_EL2);
- break;
- case KVM_PTP_PHYS_COUNTER:
- cycles = systime_snapshot.cycles;
- break;
- default:
- return;
- }
- /*
- * This relies on the top bit of val[0] never being set for
- * valid values of system time, because that is *really* far
- * in the future (about 292 years from 1970, and at that stage
- * nobody will give a damn about it).
- */
- val[0] = upper_32_bits(systime_snapshot.real);
- val[1] = lower_32_bits(systime_snapshot.real);
- val[2] = upper_32_bits(cycles);
- val[3] = lower_32_bits(cycles);
- }
- static bool kvm_hvc_call_default_allowed(u32 func_id)
- {
- switch (func_id) {
- /*
- * List of function-ids that are not gated with the bitmapped
- * feature firmware registers, and are to be allowed for
- * servicing the call by default.
- */
- case ARM_SMCCC_VERSION_FUNC_ID:
- case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
- case ARM_SMCCC_VENDOR_HYP_KVM_MEM_SHARE_FUNC_ID:
- case ARM_SMCCC_VENDOR_HYP_KVM_MEM_UNSHARE_FUNC_ID:
- case ARM_SMCCC_VENDOR_HYP_KVM_MMIO_GUARD_MAP_FUNC_ID:
- return true;
- default:
- /* PSCI 0.2 and up is in the 0:0x1f range */
- if (ARM_SMCCC_OWNER_NUM(func_id) == ARM_SMCCC_OWNER_STANDARD &&
- ARM_SMCCC_FUNC_NUM(func_id) <= 0x1f)
- return true;
- /*
- * KVM's PSCI 0.1 doesn't comply with SMCCC, and has
- * its own function-id base and range
- */
- if (func_id >= KVM_PSCI_FN(0) && func_id <= KVM_PSCI_FN(3))
- return true;
- return false;
- }
- }
- static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id)
- {
- struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
- switch (func_id) {
- case ARM_SMCCC_TRNG_VERSION:
- case ARM_SMCCC_TRNG_FEATURES:
- case ARM_SMCCC_TRNG_GET_UUID:
- case ARM_SMCCC_TRNG_RND32:
- case ARM_SMCCC_TRNG_RND64:
- return test_bit(KVM_REG_ARM_STD_BIT_TRNG_V1_0,
- &smccc_feat->std_bmap);
- case ARM_SMCCC_HV_PV_TIME_FEATURES:
- case ARM_SMCCC_HV_PV_TIME_ST:
- return test_bit(KVM_REG_ARM_STD_HYP_BIT_PV_TIME,
- &smccc_feat->std_hyp_bmap);
- case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
- case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
- return test_bit(KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT,
- &smccc_feat->vendor_hyp_bmap);
- case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
- return test_bit(KVM_REG_ARM_VENDOR_HYP_BIT_PTP,
- &smccc_feat->vendor_hyp_bmap);
- case ARM_SMCCC_VENDOR_HYP_KVM_MEM_RELINQUISH_FUNC_ID:
- return test_bit(ARM_SMCCC_KVM_FUNC_MEM_RELINQUISH,
- &smccc_feat->vendor_hyp_bmap);
- default:
- return kvm_hvc_call_default_allowed(func_id);
- }
- }
- int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
- {
- struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
- u32 func_id = smccc_get_function(vcpu);
- u64 val[4] = {SMCCC_RET_NOT_SUPPORTED};
- u32 feature;
- gpa_t gpa;
- if (!kvm_hvc_call_allowed(vcpu, func_id))
- goto out;
- switch (func_id) {
- case ARM_SMCCC_VERSION_FUNC_ID:
- val[0] = ARM_SMCCC_VERSION_1_1;
- break;
- case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
- feature = smccc_get_arg1(vcpu);
- switch (feature) {
- case ARM_SMCCC_ARCH_WORKAROUND_1:
- switch (arm64_get_spectre_v2_state()) {
- case SPECTRE_VULNERABLE:
- break;
- case SPECTRE_MITIGATED:
- val[0] = SMCCC_RET_SUCCESS;
- break;
- case SPECTRE_UNAFFECTED:
- val[0] = SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED;
- break;
- }
- break;
- case ARM_SMCCC_ARCH_WORKAROUND_2:
- switch (arm64_get_spectre_v4_state()) {
- case SPECTRE_VULNERABLE:
- break;
- case SPECTRE_MITIGATED:
- /*
- * SSBS everywhere: Indicate no firmware
- * support, as the SSBS support will be
- * indicated to the guest and the default is
- * safe.
- *
- * Otherwise, expose a permanent mitigation
- * to the guest, and hide SSBS so that the
- * guest stays protected.
- */
- if (cpus_have_final_cap(ARM64_SSBS))
- break;
- fallthrough;
- case SPECTRE_UNAFFECTED:
- val[0] = SMCCC_RET_NOT_REQUIRED;
- break;
- }
- break;
- case ARM_SMCCC_ARCH_WORKAROUND_3:
- switch (arm64_get_spectre_bhb_state()) {
- case SPECTRE_VULNERABLE:
- break;
- case SPECTRE_MITIGATED:
- val[0] = SMCCC_RET_SUCCESS;
- break;
- case SPECTRE_UNAFFECTED:
- val[0] = SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED;
- break;
- }
- break;
- case ARM_SMCCC_HV_PV_TIME_FEATURES:
- if (test_bit(KVM_REG_ARM_STD_HYP_BIT_PV_TIME,
- &smccc_feat->std_hyp_bmap))
- val[0] = SMCCC_RET_SUCCESS;
- break;
- }
- break;
- case ARM_SMCCC_HV_PV_TIME_FEATURES:
- val[0] = kvm_hypercall_pv_features(vcpu);
- break;
- case ARM_SMCCC_HV_PV_TIME_ST:
- gpa = kvm_init_stolen_time(vcpu);
- if (gpa != GPA_INVALID)
- val[0] = gpa;
- break;
- case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
- val[0] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_0;
- val[1] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_1;
- val[2] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_2;
- val[3] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_3;
- break;
- case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
- val[0] = smccc_feat->vendor_hyp_bmap;
- break;
- case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
- kvm_ptp_get_time(vcpu, val);
- break;
- case ARM_SMCCC_VENDOR_HYP_KVM_MEM_SHARE_FUNC_ID:
- case ARM_SMCCC_VENDOR_HYP_KVM_MEM_UNSHARE_FUNC_ID:
- if (!kvm_vm_is_protected(vcpu->kvm))
- break;
- atomic64_add(
- func_id == ARM_SMCCC_VENDOR_HYP_KVM_MEM_SHARE_FUNC_ID ?
- PAGE_SIZE : -PAGE_SIZE,
- &vcpu->kvm->stat.protected_shared_mem);
- val[0] = SMCCC_RET_SUCCESS;
- break;
- case ARM_SMCCC_VENDOR_HYP_KVM_MEM_RELINQUISH_FUNC_ID:
- pkvm_host_reclaim_page(vcpu->kvm, smccc_get_arg1(vcpu));
- val[0] = SMCCC_RET_SUCCESS;
- break;
- case ARM_SMCCC_VENDOR_HYP_KVM_MMIO_GUARD_MAP_FUNC_ID:
- if (kvm_vm_is_protected(vcpu->kvm) && !topup_hyp_memcache(vcpu))
- val[0] = SMCCC_RET_SUCCESS;
- break;
- case ARM_SMCCC_TRNG_VERSION:
- case ARM_SMCCC_TRNG_FEATURES:
- case ARM_SMCCC_TRNG_GET_UUID:
- case ARM_SMCCC_TRNG_RND32:
- case ARM_SMCCC_TRNG_RND64:
- return kvm_trng_call(vcpu);
- default:
- return kvm_psci_call(vcpu);
- }
- out:
- smccc_set_retval(vcpu, val[0], val[1], val[2], val[3]);
- return 1;
- }
- static const u64 kvm_arm_fw_reg_ids[] = {
- KVM_REG_ARM_PSCI_VERSION,
- KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1,
- KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2,
- KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
- KVM_REG_ARM_STD_BMAP,
- KVM_REG_ARM_STD_HYP_BMAP,
- KVM_REG_ARM_VENDOR_HYP_BMAP,
- };
- void kvm_arm_init_hypercalls(struct kvm *kvm)
- {
- struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
- smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES;
- smccc_feat->std_hyp_bmap = KVM_ARM_SMCCC_STD_HYP_FEATURES;
- smccc_feat->vendor_hyp_bmap = KVM_ARM_SMCCC_VENDOR_HYP_FEATURES;
- }
- int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
- {
- return ARRAY_SIZE(kvm_arm_fw_reg_ids);
- }
- int kvm_arm_copy_fw_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
- {
- int i;
- for (i = 0; i < ARRAY_SIZE(kvm_arm_fw_reg_ids); i++) {
- if (put_user(kvm_arm_fw_reg_ids[i], uindices++))
- return -EFAULT;
- }
- return 0;
- }
- #define KVM_REG_FEATURE_LEVEL_MASK GENMASK(3, 0)
- /*
- * Convert the workaround level into an easy-to-compare number, where higher
- * values mean better protection.
- */
- static int get_kernel_wa_level(u64 regid)
- {
- switch (regid) {
- case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1:
- switch (arm64_get_spectre_v2_state()) {
- case SPECTRE_VULNERABLE:
- return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL;
- case SPECTRE_MITIGATED:
- return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_AVAIL;
- case SPECTRE_UNAFFECTED:
- return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_REQUIRED;
- }
- return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL;
- case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2:
- switch (arm64_get_spectre_v4_state()) {
- case SPECTRE_MITIGATED:
- /*
- * As for the hypercall discovery, we pretend we
- * don't have any FW mitigation if SSBS is there at
- * all times.
- */
- if (cpus_have_final_cap(ARM64_SSBS))
- return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL;
- fallthrough;
- case SPECTRE_UNAFFECTED:
- return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED;
- case SPECTRE_VULNERABLE:
- return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL;
- }
- break;
- case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
- switch (arm64_get_spectre_bhb_state()) {
- case SPECTRE_VULNERABLE:
- return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL;
- case SPECTRE_MITIGATED:
- return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_AVAIL;
- case SPECTRE_UNAFFECTED:
- return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_REQUIRED;
- }
- return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL;
- }
- return -EINVAL;
- }
- int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
- {
- struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
- void __user *uaddr = (void __user *)(long)reg->addr;
- u64 val;
- switch (reg->id) {
- case KVM_REG_ARM_PSCI_VERSION:
- val = kvm_psci_version(vcpu);
- break;
- case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1:
- case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2:
- case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
- val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK;
- break;
- case KVM_REG_ARM_STD_BMAP:
- val = READ_ONCE(smccc_feat->std_bmap);
- break;
- case KVM_REG_ARM_STD_HYP_BMAP:
- val = READ_ONCE(smccc_feat->std_hyp_bmap);
- break;
- case KVM_REG_ARM_VENDOR_HYP_BMAP:
- val = READ_ONCE(smccc_feat->vendor_hyp_bmap);
- break;
- default:
- return -ENOENT;
- }
- if (copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id)))
- return -EFAULT;
- return 0;
- }
- static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val)
- {
- int ret = 0;
- struct kvm *kvm = vcpu->kvm;
- struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
- unsigned long *fw_reg_bmap, fw_reg_features;
- switch (reg_id) {
- case KVM_REG_ARM_STD_BMAP:
- fw_reg_bmap = &smccc_feat->std_bmap;
- fw_reg_features = KVM_ARM_SMCCC_STD_FEATURES;
- break;
- case KVM_REG_ARM_STD_HYP_BMAP:
- fw_reg_bmap = &smccc_feat->std_hyp_bmap;
- fw_reg_features = KVM_ARM_SMCCC_STD_HYP_FEATURES;
- break;
- case KVM_REG_ARM_VENDOR_HYP_BMAP:
- fw_reg_bmap = &smccc_feat->vendor_hyp_bmap;
- fw_reg_features = KVM_ARM_SMCCC_VENDOR_HYP_FEATURES;
- break;
- default:
- return -ENOENT;
- }
- /* Check for unsupported bit */
- if (val & ~fw_reg_features)
- return -EINVAL;
- mutex_lock(&kvm->arch.config_lock);
- if (test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags) &&
- val != *fw_reg_bmap) {
- ret = -EBUSY;
- goto out;
- }
- WRITE_ONCE(*fw_reg_bmap, val);
- out:
- mutex_unlock(&kvm->arch.config_lock);
- return ret;
- }
- int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
- {
- void __user *uaddr = (void __user *)(long)reg->addr;
- u64 val;
- int wa_level;
- if (KVM_REG_SIZE(reg->id) != sizeof(val))
- return -ENOENT;
- if (copy_from_user(&val, uaddr, KVM_REG_SIZE(reg->id)))
- return -EFAULT;
- switch (reg->id) {
- case KVM_REG_ARM_PSCI_VERSION:
- {
- bool wants_02;
- wants_02 = test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features);
- switch (val) {
- case KVM_ARM_PSCI_0_1:
- if (wants_02)
- return -EINVAL;
- vcpu->kvm->arch.psci_version = val;
- return 0;
- case KVM_ARM_PSCI_0_2:
- case KVM_ARM_PSCI_1_0:
- case KVM_ARM_PSCI_1_1:
- if (!wants_02)
- return -EINVAL;
- vcpu->kvm->arch.psci_version = val;
- return 0;
- }
- break;
- }
- case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1:
- case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
- if (val & ~KVM_REG_FEATURE_LEVEL_MASK)
- return -EINVAL;
- if (get_kernel_wa_level(reg->id) < val)
- return -EINVAL;
- return 0;
- case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2:
- if (val & ~(KVM_REG_FEATURE_LEVEL_MASK |
- KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED))
- return -EINVAL;
- /* The enabled bit must not be set unless the level is AVAIL. */
- if ((val & KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED) &&
- (val & KVM_REG_FEATURE_LEVEL_MASK) != KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL)
- return -EINVAL;
- /*
- * Map all the possible incoming states to the only two we
- * really want to deal with.
- */
- switch (val & KVM_REG_FEATURE_LEVEL_MASK) {
- case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL:
- case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_UNKNOWN:
- wa_level = KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL;
- break;
- case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL:
- case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED:
- wa_level = KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED;
- break;
- default:
- return -EINVAL;
- }
- /*
- * We can deal with NOT_AVAIL on NOT_REQUIRED, but not the
- * other way around.
- */
- if (get_kernel_wa_level(reg->id) < wa_level)
- return -EINVAL;
- return 0;
- case KVM_REG_ARM_STD_BMAP:
- case KVM_REG_ARM_STD_HYP_BMAP:
- case KVM_REG_ARM_VENDOR_HYP_BMAP:
- return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val);
- default:
- return -ENOENT;
- }
- return -EINVAL;
- }
|