19ed24f4bSMarc Zyngier // SPDX-License-Identifier: GPL-2.0 29ed24f4bSMarc Zyngier // Copyright (C) 2019 Arm Ltd. 39ed24f4bSMarc Zyngier 49ed24f4bSMarc Zyngier #include <linux/arm-smccc.h> 59ed24f4bSMarc Zyngier #include <linux/kvm_host.h> 69ed24f4bSMarc Zyngier 79ed24f4bSMarc Zyngier #include <asm/kvm_emulate.h> 89ed24f4bSMarc Zyngier 99ed24f4bSMarc Zyngier #include <kvm/arm_hypercalls.h> 109ed24f4bSMarc Zyngier #include <kvm/arm_psci.h> 119ed24f4bSMarc Zyngier 1205714cabSRaghavendra Rao Ananta #define KVM_ARM_SMCCC_STD_FEATURES \ 1305714cabSRaghavendra Rao Ananta GENMASK(KVM_REG_ARM_STD_BMAP_BIT_COUNT - 1, 0) 14428fd678SRaghavendra Rao Ananta #define KVM_ARM_SMCCC_STD_HYP_FEATURES \ 15428fd678SRaghavendra Rao Ananta GENMASK(KVM_REG_ARM_STD_HYP_BMAP_BIT_COUNT - 1, 0) 16b22216e1SRaghavendra Rao Ananta #define KVM_ARM_SMCCC_VENDOR_HYP_FEATURES \ 17b22216e1SRaghavendra Rao Ananta GENMASK(KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_COUNT - 1, 0) 1805714cabSRaghavendra Rao Ananta 193bf72569SJianyong Wu static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val) 203bf72569SJianyong Wu { 213bf72569SJianyong Wu struct system_time_snapshot systime_snapshot; 223bf72569SJianyong Wu u64 cycles = ~0UL; 233bf72569SJianyong Wu u32 feature; 243bf72569SJianyong Wu 253bf72569SJianyong Wu /* 263bf72569SJianyong Wu * system time and counter value must captured at the same 273bf72569SJianyong Wu * time to keep consistency and precision. 283bf72569SJianyong Wu */ 293bf72569SJianyong Wu ktime_get_snapshot(&systime_snapshot); 303bf72569SJianyong Wu 313bf72569SJianyong Wu /* 323bf72569SJianyong Wu * This is only valid if the current clocksource is the 333bf72569SJianyong Wu * architected counter, as this is the only one the guest 343bf72569SJianyong Wu * can see. 353bf72569SJianyong Wu */ 363bf72569SJianyong Wu if (systime_snapshot.cs_id != CSID_ARM_ARCH_COUNTER) 373bf72569SJianyong Wu return; 383bf72569SJianyong Wu 393bf72569SJianyong Wu /* 403bf72569SJianyong Wu * The guest selects one of the two reference counters 413bf72569SJianyong Wu * (virtual or physical) with the first argument of the SMCCC 423bf72569SJianyong Wu * call. In case the identifier is not supported, error out. 433bf72569SJianyong Wu */ 443bf72569SJianyong Wu feature = smccc_get_arg1(vcpu); 453bf72569SJianyong Wu switch (feature) { 463bf72569SJianyong Wu case KVM_PTP_VIRT_COUNTER: 4747053904SMarc Zyngier cycles = systime_snapshot.cycles - vcpu->kvm->arch.timer_data.voffset; 483bf72569SJianyong Wu break; 493bf72569SJianyong Wu case KVM_PTP_PHYS_COUNTER: 503bf72569SJianyong Wu cycles = systime_snapshot.cycles; 513bf72569SJianyong Wu break; 523bf72569SJianyong Wu default: 533bf72569SJianyong Wu return; 543bf72569SJianyong Wu } 553bf72569SJianyong Wu 563bf72569SJianyong Wu /* 573bf72569SJianyong Wu * This relies on the top bit of val[0] never being set for 583bf72569SJianyong Wu * valid values of system time, because that is *really* far 593bf72569SJianyong Wu * in the future (about 292 years from 1970, and at that stage 603bf72569SJianyong Wu * nobody will give a damn about it). 613bf72569SJianyong Wu */ 623bf72569SJianyong Wu val[0] = upper_32_bits(systime_snapshot.real); 633bf72569SJianyong Wu val[1] = lower_32_bits(systime_snapshot.real); 643bf72569SJianyong Wu val[2] = upper_32_bits(cycles); 653bf72569SJianyong Wu val[3] = lower_32_bits(cycles); 663bf72569SJianyong Wu } 673bf72569SJianyong Wu 6805714cabSRaghavendra Rao Ananta static bool kvm_hvc_call_default_allowed(u32 func_id) 6905714cabSRaghavendra Rao Ananta { 7005714cabSRaghavendra Rao Ananta switch (func_id) { 7105714cabSRaghavendra Rao Ananta /* 7205714cabSRaghavendra Rao Ananta * List of function-ids that are not gated with the bitmapped 7305714cabSRaghavendra Rao Ananta * feature firmware registers, and are to be allowed for 7405714cabSRaghavendra Rao Ananta * servicing the call by default. 7505714cabSRaghavendra Rao Ananta */ 7605714cabSRaghavendra Rao Ananta case ARM_SMCCC_VERSION_FUNC_ID: 7705714cabSRaghavendra Rao Ananta case ARM_SMCCC_ARCH_FEATURES_FUNC_ID: 7805714cabSRaghavendra Rao Ananta return true; 7905714cabSRaghavendra Rao Ananta default: 8005714cabSRaghavendra Rao Ananta /* PSCI 0.2 and up is in the 0:0x1f range */ 8105714cabSRaghavendra Rao Ananta if (ARM_SMCCC_OWNER_NUM(func_id) == ARM_SMCCC_OWNER_STANDARD && 8205714cabSRaghavendra Rao Ananta ARM_SMCCC_FUNC_NUM(func_id) <= 0x1f) 8305714cabSRaghavendra Rao Ananta return true; 8405714cabSRaghavendra Rao Ananta 8505714cabSRaghavendra Rao Ananta /* 8605714cabSRaghavendra Rao Ananta * KVM's PSCI 0.1 doesn't comply with SMCCC, and has 8705714cabSRaghavendra Rao Ananta * its own function-id base and range 8805714cabSRaghavendra Rao Ananta */ 8905714cabSRaghavendra Rao Ananta if (func_id >= KVM_PSCI_FN(0) && func_id <= KVM_PSCI_FN(3)) 9005714cabSRaghavendra Rao Ananta return true; 9105714cabSRaghavendra Rao Ananta 9205714cabSRaghavendra Rao Ananta return false; 9305714cabSRaghavendra Rao Ananta } 9405714cabSRaghavendra Rao Ananta } 9505714cabSRaghavendra Rao Ananta 9605714cabSRaghavendra Rao Ananta static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id) 9705714cabSRaghavendra Rao Ananta { 9805714cabSRaghavendra Rao Ananta struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat; 9905714cabSRaghavendra Rao Ananta 10005714cabSRaghavendra Rao Ananta switch (func_id) { 10105714cabSRaghavendra Rao Ananta case ARM_SMCCC_TRNG_VERSION: 10205714cabSRaghavendra Rao Ananta case ARM_SMCCC_TRNG_FEATURES: 10305714cabSRaghavendra Rao Ananta case ARM_SMCCC_TRNG_GET_UUID: 10405714cabSRaghavendra Rao Ananta case ARM_SMCCC_TRNG_RND32: 10505714cabSRaghavendra Rao Ananta case ARM_SMCCC_TRNG_RND64: 10605714cabSRaghavendra Rao Ananta return test_bit(KVM_REG_ARM_STD_BIT_TRNG_V1_0, 10705714cabSRaghavendra Rao Ananta &smccc_feat->std_bmap); 108428fd678SRaghavendra Rao Ananta case ARM_SMCCC_HV_PV_TIME_FEATURES: 109428fd678SRaghavendra Rao Ananta case ARM_SMCCC_HV_PV_TIME_ST: 110428fd678SRaghavendra Rao Ananta return test_bit(KVM_REG_ARM_STD_HYP_BIT_PV_TIME, 111428fd678SRaghavendra Rao Ananta &smccc_feat->std_hyp_bmap); 112b22216e1SRaghavendra Rao Ananta case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID: 113b22216e1SRaghavendra Rao Ananta case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID: 114b22216e1SRaghavendra Rao Ananta return test_bit(KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT, 115b22216e1SRaghavendra Rao Ananta &smccc_feat->vendor_hyp_bmap); 116b22216e1SRaghavendra Rao Ananta case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID: 117b22216e1SRaghavendra Rao Ananta return test_bit(KVM_REG_ARM_VENDOR_HYP_BIT_PTP, 118b22216e1SRaghavendra Rao Ananta &smccc_feat->vendor_hyp_bmap); 11905714cabSRaghavendra Rao Ananta default: 12005714cabSRaghavendra Rao Ananta return kvm_hvc_call_default_allowed(func_id); 12105714cabSRaghavendra Rao Ananta } 12205714cabSRaghavendra Rao Ananta } 12305714cabSRaghavendra Rao Ananta 1249ed24f4bSMarc Zyngier int kvm_hvc_call_handler(struct kvm_vcpu *vcpu) 1259ed24f4bSMarc Zyngier { 126428fd678SRaghavendra Rao Ananta struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat; 1279ed24f4bSMarc Zyngier u32 func_id = smccc_get_function(vcpu); 128923961a7SWill Deacon u64 val[4] = {SMCCC_RET_NOT_SUPPORTED}; 1299ed24f4bSMarc Zyngier u32 feature; 1309ed24f4bSMarc Zyngier gpa_t gpa; 1319ed24f4bSMarc Zyngier 13205714cabSRaghavendra Rao Ananta if (!kvm_hvc_call_allowed(vcpu, func_id)) 13305714cabSRaghavendra Rao Ananta goto out; 13405714cabSRaghavendra Rao Ananta 1359ed24f4bSMarc Zyngier switch (func_id) { 1369ed24f4bSMarc Zyngier case ARM_SMCCC_VERSION_FUNC_ID: 137923961a7SWill Deacon val[0] = ARM_SMCCC_VERSION_1_1; 1389ed24f4bSMarc Zyngier break; 1399ed24f4bSMarc Zyngier case ARM_SMCCC_ARCH_FEATURES_FUNC_ID: 1409ed24f4bSMarc Zyngier feature = smccc_get_arg1(vcpu); 1419ed24f4bSMarc Zyngier switch (feature) { 1429ed24f4bSMarc Zyngier case ARM_SMCCC_ARCH_WORKAROUND_1: 143d4647f0aSWill Deacon switch (arm64_get_spectre_v2_state()) { 144d4647f0aSWill Deacon case SPECTRE_VULNERABLE: 1459ed24f4bSMarc Zyngier break; 146d4647f0aSWill Deacon case SPECTRE_MITIGATED: 147923961a7SWill Deacon val[0] = SMCCC_RET_SUCCESS; 1489ed24f4bSMarc Zyngier break; 149d4647f0aSWill Deacon case SPECTRE_UNAFFECTED: 150923961a7SWill Deacon val[0] = SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED; 1519ed24f4bSMarc Zyngier break; 1529ed24f4bSMarc Zyngier } 1539ed24f4bSMarc Zyngier break; 1549ed24f4bSMarc Zyngier case ARM_SMCCC_ARCH_WORKAROUND_2: 155d63d975aSMarc Zyngier switch (arm64_get_spectre_v4_state()) { 156d63d975aSMarc Zyngier case SPECTRE_VULNERABLE: 1579ed24f4bSMarc Zyngier break; 158d63d975aSMarc Zyngier case SPECTRE_MITIGATED: 159d63d975aSMarc Zyngier /* 160d63d975aSMarc Zyngier * SSBS everywhere: Indicate no firmware 161d63d975aSMarc Zyngier * support, as the SSBS support will be 162d63d975aSMarc Zyngier * indicated to the guest and the default is 163d63d975aSMarc Zyngier * safe. 164d63d975aSMarc Zyngier * 165d63d975aSMarc Zyngier * Otherwise, expose a permanent mitigation 166d63d975aSMarc Zyngier * to the guest, and hide SSBS so that the 167d63d975aSMarc Zyngier * guest stays protected. 168d63d975aSMarc Zyngier */ 169d63d975aSMarc Zyngier if (cpus_have_final_cap(ARM64_SSBS)) 170d63d975aSMarc Zyngier break; 171d63d975aSMarc Zyngier fallthrough; 172d63d975aSMarc Zyngier case SPECTRE_UNAFFECTED: 173923961a7SWill Deacon val[0] = SMCCC_RET_NOT_REQUIRED; 1749ed24f4bSMarc Zyngier break; 1759ed24f4bSMarc Zyngier } 1769ed24f4bSMarc Zyngier break; 177a5905d6aSJames Morse case ARM_SMCCC_ARCH_WORKAROUND_3: 178a5905d6aSJames Morse switch (arm64_get_spectre_bhb_state()) { 179a5905d6aSJames Morse case SPECTRE_VULNERABLE: 180a5905d6aSJames Morse break; 181a5905d6aSJames Morse case SPECTRE_MITIGATED: 182a5905d6aSJames Morse val[0] = SMCCC_RET_SUCCESS; 183a5905d6aSJames Morse break; 184a5905d6aSJames Morse case SPECTRE_UNAFFECTED: 185a5905d6aSJames Morse val[0] = SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED; 186a5905d6aSJames Morse break; 187a5905d6aSJames Morse } 188a5905d6aSJames Morse break; 1899ed24f4bSMarc Zyngier case ARM_SMCCC_HV_PV_TIME_FEATURES: 190428fd678SRaghavendra Rao Ananta if (test_bit(KVM_REG_ARM_STD_HYP_BIT_PV_TIME, 191428fd678SRaghavendra Rao Ananta &smccc_feat->std_hyp_bmap)) 192923961a7SWill Deacon val[0] = SMCCC_RET_SUCCESS; 1939ed24f4bSMarc Zyngier break; 1949ed24f4bSMarc Zyngier } 1959ed24f4bSMarc Zyngier break; 1969ed24f4bSMarc Zyngier case ARM_SMCCC_HV_PV_TIME_FEATURES: 197923961a7SWill Deacon val[0] = kvm_hypercall_pv_features(vcpu); 1989ed24f4bSMarc Zyngier break; 1999ed24f4bSMarc Zyngier case ARM_SMCCC_HV_PV_TIME_ST: 2009ed24f4bSMarc Zyngier gpa = kvm_init_stolen_time(vcpu); 201cecafc0aSYu Zhang if (gpa != INVALID_GPA) 202923961a7SWill Deacon val[0] = gpa; 203923961a7SWill Deacon break; 204923961a7SWill Deacon case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID: 205923961a7SWill Deacon val[0] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_0; 206923961a7SWill Deacon val[1] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_1; 207923961a7SWill Deacon val[2] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_2; 208923961a7SWill Deacon val[3] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_3; 209923961a7SWill Deacon break; 210923961a7SWill Deacon case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID: 211b22216e1SRaghavendra Rao Ananta val[0] = smccc_feat->vendor_hyp_bmap; 2123bf72569SJianyong Wu break; 2133bf72569SJianyong Wu case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID: 2143bf72569SJianyong Wu kvm_ptp_get_time(vcpu, val); 2159ed24f4bSMarc Zyngier break; 216a8e190cdSArd Biesheuvel case ARM_SMCCC_TRNG_VERSION: 217a8e190cdSArd Biesheuvel case ARM_SMCCC_TRNG_FEATURES: 218a8e190cdSArd Biesheuvel case ARM_SMCCC_TRNG_GET_UUID: 219a8e190cdSArd Biesheuvel case ARM_SMCCC_TRNG_RND32: 220a8e190cdSArd Biesheuvel case ARM_SMCCC_TRNG_RND64: 221a8e190cdSArd Biesheuvel return kvm_trng_call(vcpu); 2229ed24f4bSMarc Zyngier default: 2239ed24f4bSMarc Zyngier return kvm_psci_call(vcpu); 2249ed24f4bSMarc Zyngier } 2259ed24f4bSMarc Zyngier 22605714cabSRaghavendra Rao Ananta out: 227923961a7SWill Deacon smccc_set_retval(vcpu, val[0], val[1], val[2], val[3]); 2289ed24f4bSMarc Zyngier return 1; 2299ed24f4bSMarc Zyngier } 23085fbe08eSRaghavendra Rao Ananta 23185fbe08eSRaghavendra Rao Ananta static const u64 kvm_arm_fw_reg_ids[] = { 23285fbe08eSRaghavendra Rao Ananta KVM_REG_ARM_PSCI_VERSION, 23385fbe08eSRaghavendra Rao Ananta KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1, 23485fbe08eSRaghavendra Rao Ananta KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2, 23585fbe08eSRaghavendra Rao Ananta KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3, 23605714cabSRaghavendra Rao Ananta KVM_REG_ARM_STD_BMAP, 237428fd678SRaghavendra Rao Ananta KVM_REG_ARM_STD_HYP_BMAP, 238b22216e1SRaghavendra Rao Ananta KVM_REG_ARM_VENDOR_HYP_BMAP, 23985fbe08eSRaghavendra Rao Ananta }; 24085fbe08eSRaghavendra Rao Ananta 24105714cabSRaghavendra Rao Ananta void kvm_arm_init_hypercalls(struct kvm *kvm) 24205714cabSRaghavendra Rao Ananta { 24305714cabSRaghavendra Rao Ananta struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat; 24405714cabSRaghavendra Rao Ananta 24505714cabSRaghavendra Rao Ananta smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES; 246428fd678SRaghavendra Rao Ananta smccc_feat->std_hyp_bmap = KVM_ARM_SMCCC_STD_HYP_FEATURES; 247b22216e1SRaghavendra Rao Ananta smccc_feat->vendor_hyp_bmap = KVM_ARM_SMCCC_VENDOR_HYP_FEATURES; 24805714cabSRaghavendra Rao Ananta } 24905714cabSRaghavendra Rao Ananta 25085fbe08eSRaghavendra Rao Ananta int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu) 25185fbe08eSRaghavendra Rao Ananta { 25285fbe08eSRaghavendra Rao Ananta return ARRAY_SIZE(kvm_arm_fw_reg_ids); 25385fbe08eSRaghavendra Rao Ananta } 25485fbe08eSRaghavendra Rao Ananta 25585fbe08eSRaghavendra Rao Ananta int kvm_arm_copy_fw_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices) 25685fbe08eSRaghavendra Rao Ananta { 25785fbe08eSRaghavendra Rao Ananta int i; 25885fbe08eSRaghavendra Rao Ananta 25985fbe08eSRaghavendra Rao Ananta for (i = 0; i < ARRAY_SIZE(kvm_arm_fw_reg_ids); i++) { 26085fbe08eSRaghavendra Rao Ananta if (put_user(kvm_arm_fw_reg_ids[i], uindices++)) 26185fbe08eSRaghavendra Rao Ananta return -EFAULT; 26285fbe08eSRaghavendra Rao Ananta } 26385fbe08eSRaghavendra Rao Ananta 26485fbe08eSRaghavendra Rao Ananta return 0; 26585fbe08eSRaghavendra Rao Ananta } 26685fbe08eSRaghavendra Rao Ananta 26785fbe08eSRaghavendra Rao Ananta #define KVM_REG_FEATURE_LEVEL_MASK GENMASK(3, 0) 26885fbe08eSRaghavendra Rao Ananta 26985fbe08eSRaghavendra Rao Ananta /* 27085fbe08eSRaghavendra Rao Ananta * Convert the workaround level into an easy-to-compare number, where higher 27185fbe08eSRaghavendra Rao Ananta * values mean better protection. 27285fbe08eSRaghavendra Rao Ananta */ 27385fbe08eSRaghavendra Rao Ananta static int get_kernel_wa_level(u64 regid) 27485fbe08eSRaghavendra Rao Ananta { 27585fbe08eSRaghavendra Rao Ananta switch (regid) { 27685fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1: 27785fbe08eSRaghavendra Rao Ananta switch (arm64_get_spectre_v2_state()) { 27885fbe08eSRaghavendra Rao Ananta case SPECTRE_VULNERABLE: 27985fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL; 28085fbe08eSRaghavendra Rao Ananta case SPECTRE_MITIGATED: 28185fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_AVAIL; 28285fbe08eSRaghavendra Rao Ananta case SPECTRE_UNAFFECTED: 28385fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_REQUIRED; 28485fbe08eSRaghavendra Rao Ananta } 28585fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL; 28685fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2: 28785fbe08eSRaghavendra Rao Ananta switch (arm64_get_spectre_v4_state()) { 28885fbe08eSRaghavendra Rao Ananta case SPECTRE_MITIGATED: 28985fbe08eSRaghavendra Rao Ananta /* 29085fbe08eSRaghavendra Rao Ananta * As for the hypercall discovery, we pretend we 29185fbe08eSRaghavendra Rao Ananta * don't have any FW mitigation if SSBS is there at 29285fbe08eSRaghavendra Rao Ananta * all times. 29385fbe08eSRaghavendra Rao Ananta */ 29485fbe08eSRaghavendra Rao Ananta if (cpus_have_final_cap(ARM64_SSBS)) 29585fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL; 29685fbe08eSRaghavendra Rao Ananta fallthrough; 29785fbe08eSRaghavendra Rao Ananta case SPECTRE_UNAFFECTED: 29885fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED; 29985fbe08eSRaghavendra Rao Ananta case SPECTRE_VULNERABLE: 30085fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL; 30185fbe08eSRaghavendra Rao Ananta } 30285fbe08eSRaghavendra Rao Ananta break; 30385fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3: 30485fbe08eSRaghavendra Rao Ananta switch (arm64_get_spectre_bhb_state()) { 30585fbe08eSRaghavendra Rao Ananta case SPECTRE_VULNERABLE: 30685fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL; 30785fbe08eSRaghavendra Rao Ananta case SPECTRE_MITIGATED: 30885fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_AVAIL; 30985fbe08eSRaghavendra Rao Ananta case SPECTRE_UNAFFECTED: 31085fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_REQUIRED; 31185fbe08eSRaghavendra Rao Ananta } 31285fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL; 31385fbe08eSRaghavendra Rao Ananta } 31485fbe08eSRaghavendra Rao Ananta 31585fbe08eSRaghavendra Rao Ananta return -EINVAL; 31685fbe08eSRaghavendra Rao Ananta } 31785fbe08eSRaghavendra Rao Ananta 31885fbe08eSRaghavendra Rao Ananta int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) 31985fbe08eSRaghavendra Rao Ananta { 32005714cabSRaghavendra Rao Ananta struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat; 32185fbe08eSRaghavendra Rao Ananta void __user *uaddr = (void __user *)(long)reg->addr; 32285fbe08eSRaghavendra Rao Ananta u64 val; 32385fbe08eSRaghavendra Rao Ananta 32485fbe08eSRaghavendra Rao Ananta switch (reg->id) { 32585fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_PSCI_VERSION: 32685fbe08eSRaghavendra Rao Ananta val = kvm_psci_version(vcpu); 32785fbe08eSRaghavendra Rao Ananta break; 32885fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1: 32985fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2: 33085fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3: 33185fbe08eSRaghavendra Rao Ananta val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK; 33285fbe08eSRaghavendra Rao Ananta break; 33305714cabSRaghavendra Rao Ananta case KVM_REG_ARM_STD_BMAP: 33405714cabSRaghavendra Rao Ananta val = READ_ONCE(smccc_feat->std_bmap); 33505714cabSRaghavendra Rao Ananta break; 336428fd678SRaghavendra Rao Ananta case KVM_REG_ARM_STD_HYP_BMAP: 337428fd678SRaghavendra Rao Ananta val = READ_ONCE(smccc_feat->std_hyp_bmap); 338428fd678SRaghavendra Rao Ananta break; 339b22216e1SRaghavendra Rao Ananta case KVM_REG_ARM_VENDOR_HYP_BMAP: 340b22216e1SRaghavendra Rao Ananta val = READ_ONCE(smccc_feat->vendor_hyp_bmap); 341b22216e1SRaghavendra Rao Ananta break; 34285fbe08eSRaghavendra Rao Ananta default: 34385fbe08eSRaghavendra Rao Ananta return -ENOENT; 34485fbe08eSRaghavendra Rao Ananta } 34585fbe08eSRaghavendra Rao Ananta 34685fbe08eSRaghavendra Rao Ananta if (copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id))) 34785fbe08eSRaghavendra Rao Ananta return -EFAULT; 34885fbe08eSRaghavendra Rao Ananta 34985fbe08eSRaghavendra Rao Ananta return 0; 35085fbe08eSRaghavendra Rao Ananta } 35185fbe08eSRaghavendra Rao Ananta 35205714cabSRaghavendra Rao Ananta static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val) 35305714cabSRaghavendra Rao Ananta { 35405714cabSRaghavendra Rao Ananta int ret = 0; 35505714cabSRaghavendra Rao Ananta struct kvm *kvm = vcpu->kvm; 35605714cabSRaghavendra Rao Ananta struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat; 35705714cabSRaghavendra Rao Ananta unsigned long *fw_reg_bmap, fw_reg_features; 35805714cabSRaghavendra Rao Ananta 35905714cabSRaghavendra Rao Ananta switch (reg_id) { 36005714cabSRaghavendra Rao Ananta case KVM_REG_ARM_STD_BMAP: 36105714cabSRaghavendra Rao Ananta fw_reg_bmap = &smccc_feat->std_bmap; 36205714cabSRaghavendra Rao Ananta fw_reg_features = KVM_ARM_SMCCC_STD_FEATURES; 36305714cabSRaghavendra Rao Ananta break; 364428fd678SRaghavendra Rao Ananta case KVM_REG_ARM_STD_HYP_BMAP: 365428fd678SRaghavendra Rao Ananta fw_reg_bmap = &smccc_feat->std_hyp_bmap; 366428fd678SRaghavendra Rao Ananta fw_reg_features = KVM_ARM_SMCCC_STD_HYP_FEATURES; 367428fd678SRaghavendra Rao Ananta break; 368b22216e1SRaghavendra Rao Ananta case KVM_REG_ARM_VENDOR_HYP_BMAP: 369b22216e1SRaghavendra Rao Ananta fw_reg_bmap = &smccc_feat->vendor_hyp_bmap; 370b22216e1SRaghavendra Rao Ananta fw_reg_features = KVM_ARM_SMCCC_VENDOR_HYP_FEATURES; 371b22216e1SRaghavendra Rao Ananta break; 37205714cabSRaghavendra Rao Ananta default: 37305714cabSRaghavendra Rao Ananta return -ENOENT; 37405714cabSRaghavendra Rao Ananta } 37505714cabSRaghavendra Rao Ananta 37605714cabSRaghavendra Rao Ananta /* Check for unsupported bit */ 37705714cabSRaghavendra Rao Ananta if (val & ~fw_reg_features) 37805714cabSRaghavendra Rao Ananta return -EINVAL; 37905714cabSRaghavendra Rao Ananta 38005714cabSRaghavendra Rao Ananta mutex_lock(&kvm->lock); 38105714cabSRaghavendra Rao Ananta 382528ada28SMarc Zyngier if (test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags) && 383528ada28SMarc Zyngier val != *fw_reg_bmap) { 38405714cabSRaghavendra Rao Ananta ret = -EBUSY; 38505714cabSRaghavendra Rao Ananta goto out; 38605714cabSRaghavendra Rao Ananta } 38705714cabSRaghavendra Rao Ananta 38805714cabSRaghavendra Rao Ananta WRITE_ONCE(*fw_reg_bmap, val); 38905714cabSRaghavendra Rao Ananta out: 39005714cabSRaghavendra Rao Ananta mutex_unlock(&kvm->lock); 39105714cabSRaghavendra Rao Ananta return ret; 39205714cabSRaghavendra Rao Ananta } 39305714cabSRaghavendra Rao Ananta 39485fbe08eSRaghavendra Rao Ananta int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) 39585fbe08eSRaghavendra Rao Ananta { 39685fbe08eSRaghavendra Rao Ananta void __user *uaddr = (void __user *)(long)reg->addr; 39785fbe08eSRaghavendra Rao Ananta u64 val; 39885fbe08eSRaghavendra Rao Ananta int wa_level; 39985fbe08eSRaghavendra Rao Ananta 400*a25bc848SDan Carpenter if (KVM_REG_SIZE(reg->id) != sizeof(val)) 401*a25bc848SDan Carpenter return -ENOENT; 40285fbe08eSRaghavendra Rao Ananta if (copy_from_user(&val, uaddr, KVM_REG_SIZE(reg->id))) 40385fbe08eSRaghavendra Rao Ananta return -EFAULT; 40485fbe08eSRaghavendra Rao Ananta 40585fbe08eSRaghavendra Rao Ananta switch (reg->id) { 40685fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_PSCI_VERSION: 40785fbe08eSRaghavendra Rao Ananta { 40885fbe08eSRaghavendra Rao Ananta bool wants_02; 40985fbe08eSRaghavendra Rao Ananta 41085fbe08eSRaghavendra Rao Ananta wants_02 = test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features); 41185fbe08eSRaghavendra Rao Ananta 41285fbe08eSRaghavendra Rao Ananta switch (val) { 41385fbe08eSRaghavendra Rao Ananta case KVM_ARM_PSCI_0_1: 41485fbe08eSRaghavendra Rao Ananta if (wants_02) 41585fbe08eSRaghavendra Rao Ananta return -EINVAL; 41685fbe08eSRaghavendra Rao Ananta vcpu->kvm->arch.psci_version = val; 41785fbe08eSRaghavendra Rao Ananta return 0; 41885fbe08eSRaghavendra Rao Ananta case KVM_ARM_PSCI_0_2: 41985fbe08eSRaghavendra Rao Ananta case KVM_ARM_PSCI_1_0: 42085fbe08eSRaghavendra Rao Ananta case KVM_ARM_PSCI_1_1: 42185fbe08eSRaghavendra Rao Ananta if (!wants_02) 42285fbe08eSRaghavendra Rao Ananta return -EINVAL; 42385fbe08eSRaghavendra Rao Ananta vcpu->kvm->arch.psci_version = val; 42485fbe08eSRaghavendra Rao Ananta return 0; 42585fbe08eSRaghavendra Rao Ananta } 42685fbe08eSRaghavendra Rao Ananta break; 42785fbe08eSRaghavendra Rao Ananta } 42885fbe08eSRaghavendra Rao Ananta 42985fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1: 43085fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3: 43185fbe08eSRaghavendra Rao Ananta if (val & ~KVM_REG_FEATURE_LEVEL_MASK) 43285fbe08eSRaghavendra Rao Ananta return -EINVAL; 43385fbe08eSRaghavendra Rao Ananta 43485fbe08eSRaghavendra Rao Ananta if (get_kernel_wa_level(reg->id) < val) 43585fbe08eSRaghavendra Rao Ananta return -EINVAL; 43685fbe08eSRaghavendra Rao Ananta 43785fbe08eSRaghavendra Rao Ananta return 0; 43885fbe08eSRaghavendra Rao Ananta 43985fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2: 44085fbe08eSRaghavendra Rao Ananta if (val & ~(KVM_REG_FEATURE_LEVEL_MASK | 44185fbe08eSRaghavendra Rao Ananta KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED)) 44285fbe08eSRaghavendra Rao Ananta return -EINVAL; 44385fbe08eSRaghavendra Rao Ananta 44485fbe08eSRaghavendra Rao Ananta /* The enabled bit must not be set unless the level is AVAIL. */ 44585fbe08eSRaghavendra Rao Ananta if ((val & KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED) && 44685fbe08eSRaghavendra Rao Ananta (val & KVM_REG_FEATURE_LEVEL_MASK) != KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL) 44785fbe08eSRaghavendra Rao Ananta return -EINVAL; 44885fbe08eSRaghavendra Rao Ananta 44985fbe08eSRaghavendra Rao Ananta /* 45085fbe08eSRaghavendra Rao Ananta * Map all the possible incoming states to the only two we 45185fbe08eSRaghavendra Rao Ananta * really want to deal with. 45285fbe08eSRaghavendra Rao Ananta */ 45385fbe08eSRaghavendra Rao Ananta switch (val & KVM_REG_FEATURE_LEVEL_MASK) { 45485fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL: 45585fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_UNKNOWN: 45685fbe08eSRaghavendra Rao Ananta wa_level = KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL; 45785fbe08eSRaghavendra Rao Ananta break; 45885fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL: 45985fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED: 46085fbe08eSRaghavendra Rao Ananta wa_level = KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED; 46185fbe08eSRaghavendra Rao Ananta break; 46285fbe08eSRaghavendra Rao Ananta default: 46385fbe08eSRaghavendra Rao Ananta return -EINVAL; 46485fbe08eSRaghavendra Rao Ananta } 46585fbe08eSRaghavendra Rao Ananta 46685fbe08eSRaghavendra Rao Ananta /* 46785fbe08eSRaghavendra Rao Ananta * We can deal with NOT_AVAIL on NOT_REQUIRED, but not the 46885fbe08eSRaghavendra Rao Ananta * other way around. 46985fbe08eSRaghavendra Rao Ananta */ 47085fbe08eSRaghavendra Rao Ananta if (get_kernel_wa_level(reg->id) < wa_level) 47185fbe08eSRaghavendra Rao Ananta return -EINVAL; 47285fbe08eSRaghavendra Rao Ananta 47385fbe08eSRaghavendra Rao Ananta return 0; 47405714cabSRaghavendra Rao Ananta case KVM_REG_ARM_STD_BMAP: 475428fd678SRaghavendra Rao Ananta case KVM_REG_ARM_STD_HYP_BMAP: 476b22216e1SRaghavendra Rao Ananta case KVM_REG_ARM_VENDOR_HYP_BMAP: 47705714cabSRaghavendra Rao Ananta return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val); 47885fbe08eSRaghavendra Rao Ananta default: 47985fbe08eSRaghavendra Rao Ananta return -ENOENT; 48085fbe08eSRaghavendra Rao Ananta } 48185fbe08eSRaghavendra Rao Ananta 48285fbe08eSRaghavendra Rao Ananta return -EINVAL; 48385fbe08eSRaghavendra Rao Ananta } 484