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) 14*428fd678SRaghavendra Rao Ananta #define KVM_ARM_SMCCC_STD_HYP_FEATURES \ 15*428fd678SRaghavendra Rao Ananta GENMASK(KVM_REG_ARM_STD_HYP_BMAP_BIT_COUNT - 1, 0) 1605714cabSRaghavendra Rao Ananta 173bf72569SJianyong Wu static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val) 183bf72569SJianyong Wu { 193bf72569SJianyong Wu struct system_time_snapshot systime_snapshot; 203bf72569SJianyong Wu u64 cycles = ~0UL; 213bf72569SJianyong Wu u32 feature; 223bf72569SJianyong Wu 233bf72569SJianyong Wu /* 243bf72569SJianyong Wu * system time and counter value must captured at the same 253bf72569SJianyong Wu * time to keep consistency and precision. 263bf72569SJianyong Wu */ 273bf72569SJianyong Wu ktime_get_snapshot(&systime_snapshot); 283bf72569SJianyong Wu 293bf72569SJianyong Wu /* 303bf72569SJianyong Wu * This is only valid if the current clocksource is the 313bf72569SJianyong Wu * architected counter, as this is the only one the guest 323bf72569SJianyong Wu * can see. 333bf72569SJianyong Wu */ 343bf72569SJianyong Wu if (systime_snapshot.cs_id != CSID_ARM_ARCH_COUNTER) 353bf72569SJianyong Wu return; 363bf72569SJianyong Wu 373bf72569SJianyong Wu /* 383bf72569SJianyong Wu * The guest selects one of the two reference counters 393bf72569SJianyong Wu * (virtual or physical) with the first argument of the SMCCC 403bf72569SJianyong Wu * call. In case the identifier is not supported, error out. 413bf72569SJianyong Wu */ 423bf72569SJianyong Wu feature = smccc_get_arg1(vcpu); 433bf72569SJianyong Wu switch (feature) { 443bf72569SJianyong Wu case KVM_PTP_VIRT_COUNTER: 453bf72569SJianyong Wu cycles = systime_snapshot.cycles - vcpu_read_sys_reg(vcpu, CNTVOFF_EL2); 463bf72569SJianyong Wu break; 473bf72569SJianyong Wu case KVM_PTP_PHYS_COUNTER: 483bf72569SJianyong Wu cycles = systime_snapshot.cycles; 493bf72569SJianyong Wu break; 503bf72569SJianyong Wu default: 513bf72569SJianyong Wu return; 523bf72569SJianyong Wu } 533bf72569SJianyong Wu 543bf72569SJianyong Wu /* 553bf72569SJianyong Wu * This relies on the top bit of val[0] never being set for 563bf72569SJianyong Wu * valid values of system time, because that is *really* far 573bf72569SJianyong Wu * in the future (about 292 years from 1970, and at that stage 583bf72569SJianyong Wu * nobody will give a damn about it). 593bf72569SJianyong Wu */ 603bf72569SJianyong Wu val[0] = upper_32_bits(systime_snapshot.real); 613bf72569SJianyong Wu val[1] = lower_32_bits(systime_snapshot.real); 623bf72569SJianyong Wu val[2] = upper_32_bits(cycles); 633bf72569SJianyong Wu val[3] = lower_32_bits(cycles); 643bf72569SJianyong Wu } 653bf72569SJianyong Wu 6605714cabSRaghavendra Rao Ananta static bool kvm_hvc_call_default_allowed(u32 func_id) 6705714cabSRaghavendra Rao Ananta { 6805714cabSRaghavendra Rao Ananta switch (func_id) { 6905714cabSRaghavendra Rao Ananta /* 7005714cabSRaghavendra Rao Ananta * List of function-ids that are not gated with the bitmapped 7105714cabSRaghavendra Rao Ananta * feature firmware registers, and are to be allowed for 7205714cabSRaghavendra Rao Ananta * servicing the call by default. 7305714cabSRaghavendra Rao Ananta */ 7405714cabSRaghavendra Rao Ananta case ARM_SMCCC_VERSION_FUNC_ID: 7505714cabSRaghavendra Rao Ananta case ARM_SMCCC_ARCH_FEATURES_FUNC_ID: 7605714cabSRaghavendra Rao Ananta case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID: 7705714cabSRaghavendra Rao Ananta case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID: 7805714cabSRaghavendra Rao Ananta case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID: 7905714cabSRaghavendra Rao Ananta return true; 8005714cabSRaghavendra Rao Ananta default: 8105714cabSRaghavendra Rao Ananta /* PSCI 0.2 and up is in the 0:0x1f range */ 8205714cabSRaghavendra Rao Ananta if (ARM_SMCCC_OWNER_NUM(func_id) == ARM_SMCCC_OWNER_STANDARD && 8305714cabSRaghavendra Rao Ananta ARM_SMCCC_FUNC_NUM(func_id) <= 0x1f) 8405714cabSRaghavendra Rao Ananta return true; 8505714cabSRaghavendra Rao Ananta 8605714cabSRaghavendra Rao Ananta /* 8705714cabSRaghavendra Rao Ananta * KVM's PSCI 0.1 doesn't comply with SMCCC, and has 8805714cabSRaghavendra Rao Ananta * its own function-id base and range 8905714cabSRaghavendra Rao Ananta */ 9005714cabSRaghavendra Rao Ananta if (func_id >= KVM_PSCI_FN(0) && func_id <= KVM_PSCI_FN(3)) 9105714cabSRaghavendra Rao Ananta return true; 9205714cabSRaghavendra Rao Ananta 9305714cabSRaghavendra Rao Ananta return false; 9405714cabSRaghavendra Rao Ananta } 9505714cabSRaghavendra Rao Ananta } 9605714cabSRaghavendra Rao Ananta 9705714cabSRaghavendra Rao Ananta static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id) 9805714cabSRaghavendra Rao Ananta { 9905714cabSRaghavendra Rao Ananta struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat; 10005714cabSRaghavendra Rao Ananta 10105714cabSRaghavendra Rao Ananta switch (func_id) { 10205714cabSRaghavendra Rao Ananta case ARM_SMCCC_TRNG_VERSION: 10305714cabSRaghavendra Rao Ananta case ARM_SMCCC_TRNG_FEATURES: 10405714cabSRaghavendra Rao Ananta case ARM_SMCCC_TRNG_GET_UUID: 10505714cabSRaghavendra Rao Ananta case ARM_SMCCC_TRNG_RND32: 10605714cabSRaghavendra Rao Ananta case ARM_SMCCC_TRNG_RND64: 10705714cabSRaghavendra Rao Ananta return test_bit(KVM_REG_ARM_STD_BIT_TRNG_V1_0, 10805714cabSRaghavendra Rao Ananta &smccc_feat->std_bmap); 109*428fd678SRaghavendra Rao Ananta case ARM_SMCCC_HV_PV_TIME_FEATURES: 110*428fd678SRaghavendra Rao Ananta case ARM_SMCCC_HV_PV_TIME_ST: 111*428fd678SRaghavendra Rao Ananta return test_bit(KVM_REG_ARM_STD_HYP_BIT_PV_TIME, 112*428fd678SRaghavendra Rao Ananta &smccc_feat->std_hyp_bmap); 11305714cabSRaghavendra Rao Ananta default: 11405714cabSRaghavendra Rao Ananta return kvm_hvc_call_default_allowed(func_id); 11505714cabSRaghavendra Rao Ananta } 11605714cabSRaghavendra Rao Ananta } 11705714cabSRaghavendra Rao Ananta 1189ed24f4bSMarc Zyngier int kvm_hvc_call_handler(struct kvm_vcpu *vcpu) 1199ed24f4bSMarc Zyngier { 120*428fd678SRaghavendra Rao Ananta struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat; 1219ed24f4bSMarc Zyngier u32 func_id = smccc_get_function(vcpu); 122923961a7SWill Deacon u64 val[4] = {SMCCC_RET_NOT_SUPPORTED}; 1239ed24f4bSMarc Zyngier u32 feature; 1249ed24f4bSMarc Zyngier gpa_t gpa; 1259ed24f4bSMarc Zyngier 12605714cabSRaghavendra Rao Ananta if (!kvm_hvc_call_allowed(vcpu, func_id)) 12705714cabSRaghavendra Rao Ananta goto out; 12805714cabSRaghavendra Rao Ananta 1299ed24f4bSMarc Zyngier switch (func_id) { 1309ed24f4bSMarc Zyngier case ARM_SMCCC_VERSION_FUNC_ID: 131923961a7SWill Deacon val[0] = ARM_SMCCC_VERSION_1_1; 1329ed24f4bSMarc Zyngier break; 1339ed24f4bSMarc Zyngier case ARM_SMCCC_ARCH_FEATURES_FUNC_ID: 1349ed24f4bSMarc Zyngier feature = smccc_get_arg1(vcpu); 1359ed24f4bSMarc Zyngier switch (feature) { 1369ed24f4bSMarc Zyngier case ARM_SMCCC_ARCH_WORKAROUND_1: 137d4647f0aSWill Deacon switch (arm64_get_spectre_v2_state()) { 138d4647f0aSWill Deacon case SPECTRE_VULNERABLE: 1399ed24f4bSMarc Zyngier break; 140d4647f0aSWill Deacon case SPECTRE_MITIGATED: 141923961a7SWill Deacon val[0] = SMCCC_RET_SUCCESS; 1429ed24f4bSMarc Zyngier break; 143d4647f0aSWill Deacon case SPECTRE_UNAFFECTED: 144923961a7SWill Deacon val[0] = SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED; 1459ed24f4bSMarc Zyngier break; 1469ed24f4bSMarc Zyngier } 1479ed24f4bSMarc Zyngier break; 1489ed24f4bSMarc Zyngier case ARM_SMCCC_ARCH_WORKAROUND_2: 149d63d975aSMarc Zyngier switch (arm64_get_spectre_v4_state()) { 150d63d975aSMarc Zyngier case SPECTRE_VULNERABLE: 1519ed24f4bSMarc Zyngier break; 152d63d975aSMarc Zyngier case SPECTRE_MITIGATED: 153d63d975aSMarc Zyngier /* 154d63d975aSMarc Zyngier * SSBS everywhere: Indicate no firmware 155d63d975aSMarc Zyngier * support, as the SSBS support will be 156d63d975aSMarc Zyngier * indicated to the guest and the default is 157d63d975aSMarc Zyngier * safe. 158d63d975aSMarc Zyngier * 159d63d975aSMarc Zyngier * Otherwise, expose a permanent mitigation 160d63d975aSMarc Zyngier * to the guest, and hide SSBS so that the 161d63d975aSMarc Zyngier * guest stays protected. 162d63d975aSMarc Zyngier */ 163d63d975aSMarc Zyngier if (cpus_have_final_cap(ARM64_SSBS)) 164d63d975aSMarc Zyngier break; 165d63d975aSMarc Zyngier fallthrough; 166d63d975aSMarc Zyngier case SPECTRE_UNAFFECTED: 167923961a7SWill Deacon val[0] = SMCCC_RET_NOT_REQUIRED; 1689ed24f4bSMarc Zyngier break; 1699ed24f4bSMarc Zyngier } 1709ed24f4bSMarc Zyngier break; 171a5905d6aSJames Morse case ARM_SMCCC_ARCH_WORKAROUND_3: 172a5905d6aSJames Morse switch (arm64_get_spectre_bhb_state()) { 173a5905d6aSJames Morse case SPECTRE_VULNERABLE: 174a5905d6aSJames Morse break; 175a5905d6aSJames Morse case SPECTRE_MITIGATED: 176a5905d6aSJames Morse val[0] = SMCCC_RET_SUCCESS; 177a5905d6aSJames Morse break; 178a5905d6aSJames Morse case SPECTRE_UNAFFECTED: 179a5905d6aSJames Morse val[0] = SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED; 180a5905d6aSJames Morse break; 181a5905d6aSJames Morse } 182a5905d6aSJames Morse break; 1839ed24f4bSMarc Zyngier case ARM_SMCCC_HV_PV_TIME_FEATURES: 184*428fd678SRaghavendra Rao Ananta if (test_bit(KVM_REG_ARM_STD_HYP_BIT_PV_TIME, 185*428fd678SRaghavendra Rao Ananta &smccc_feat->std_hyp_bmap)) 186923961a7SWill Deacon val[0] = SMCCC_RET_SUCCESS; 1879ed24f4bSMarc Zyngier break; 1889ed24f4bSMarc Zyngier } 1899ed24f4bSMarc Zyngier break; 1909ed24f4bSMarc Zyngier case ARM_SMCCC_HV_PV_TIME_FEATURES: 191923961a7SWill Deacon val[0] = kvm_hypercall_pv_features(vcpu); 1929ed24f4bSMarc Zyngier break; 1939ed24f4bSMarc Zyngier case ARM_SMCCC_HV_PV_TIME_ST: 1949ed24f4bSMarc Zyngier gpa = kvm_init_stolen_time(vcpu); 1959ed24f4bSMarc Zyngier if (gpa != GPA_INVALID) 196923961a7SWill Deacon val[0] = gpa; 197923961a7SWill Deacon break; 198923961a7SWill Deacon case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID: 199923961a7SWill Deacon val[0] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_0; 200923961a7SWill Deacon val[1] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_1; 201923961a7SWill Deacon val[2] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_2; 202923961a7SWill Deacon val[3] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_3; 203923961a7SWill Deacon break; 204923961a7SWill Deacon case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID: 205923961a7SWill Deacon val[0] = BIT(ARM_SMCCC_KVM_FUNC_FEATURES); 2063bf72569SJianyong Wu val[0] |= BIT(ARM_SMCCC_KVM_FUNC_PTP); 2073bf72569SJianyong Wu break; 2083bf72569SJianyong Wu case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID: 2093bf72569SJianyong Wu kvm_ptp_get_time(vcpu, val); 2109ed24f4bSMarc Zyngier break; 211a8e190cdSArd Biesheuvel case ARM_SMCCC_TRNG_VERSION: 212a8e190cdSArd Biesheuvel case ARM_SMCCC_TRNG_FEATURES: 213a8e190cdSArd Biesheuvel case ARM_SMCCC_TRNG_GET_UUID: 214a8e190cdSArd Biesheuvel case ARM_SMCCC_TRNG_RND32: 215a8e190cdSArd Biesheuvel case ARM_SMCCC_TRNG_RND64: 216a8e190cdSArd Biesheuvel return kvm_trng_call(vcpu); 2179ed24f4bSMarc Zyngier default: 2189ed24f4bSMarc Zyngier return kvm_psci_call(vcpu); 2199ed24f4bSMarc Zyngier } 2209ed24f4bSMarc Zyngier 22105714cabSRaghavendra Rao Ananta out: 222923961a7SWill Deacon smccc_set_retval(vcpu, val[0], val[1], val[2], val[3]); 2239ed24f4bSMarc Zyngier return 1; 2249ed24f4bSMarc Zyngier } 22585fbe08eSRaghavendra Rao Ananta 22685fbe08eSRaghavendra Rao Ananta static const u64 kvm_arm_fw_reg_ids[] = { 22785fbe08eSRaghavendra Rao Ananta KVM_REG_ARM_PSCI_VERSION, 22885fbe08eSRaghavendra Rao Ananta KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1, 22985fbe08eSRaghavendra Rao Ananta KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2, 23085fbe08eSRaghavendra Rao Ananta KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3, 23105714cabSRaghavendra Rao Ananta KVM_REG_ARM_STD_BMAP, 232*428fd678SRaghavendra Rao Ananta KVM_REG_ARM_STD_HYP_BMAP, 23385fbe08eSRaghavendra Rao Ananta }; 23485fbe08eSRaghavendra Rao Ananta 23505714cabSRaghavendra Rao Ananta void kvm_arm_init_hypercalls(struct kvm *kvm) 23605714cabSRaghavendra Rao Ananta { 23705714cabSRaghavendra Rao Ananta struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat; 23805714cabSRaghavendra Rao Ananta 23905714cabSRaghavendra Rao Ananta smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES; 240*428fd678SRaghavendra Rao Ananta smccc_feat->std_hyp_bmap = KVM_ARM_SMCCC_STD_HYP_FEATURES; 24105714cabSRaghavendra Rao Ananta } 24205714cabSRaghavendra Rao Ananta 24385fbe08eSRaghavendra Rao Ananta int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu) 24485fbe08eSRaghavendra Rao Ananta { 24585fbe08eSRaghavendra Rao Ananta return ARRAY_SIZE(kvm_arm_fw_reg_ids); 24685fbe08eSRaghavendra Rao Ananta } 24785fbe08eSRaghavendra Rao Ananta 24885fbe08eSRaghavendra Rao Ananta int kvm_arm_copy_fw_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices) 24985fbe08eSRaghavendra Rao Ananta { 25085fbe08eSRaghavendra Rao Ananta int i; 25185fbe08eSRaghavendra Rao Ananta 25285fbe08eSRaghavendra Rao Ananta for (i = 0; i < ARRAY_SIZE(kvm_arm_fw_reg_ids); i++) { 25385fbe08eSRaghavendra Rao Ananta if (put_user(kvm_arm_fw_reg_ids[i], uindices++)) 25485fbe08eSRaghavendra Rao Ananta return -EFAULT; 25585fbe08eSRaghavendra Rao Ananta } 25685fbe08eSRaghavendra Rao Ananta 25785fbe08eSRaghavendra Rao Ananta return 0; 25885fbe08eSRaghavendra Rao Ananta } 25985fbe08eSRaghavendra Rao Ananta 26085fbe08eSRaghavendra Rao Ananta #define KVM_REG_FEATURE_LEVEL_MASK GENMASK(3, 0) 26185fbe08eSRaghavendra Rao Ananta 26285fbe08eSRaghavendra Rao Ananta /* 26385fbe08eSRaghavendra Rao Ananta * Convert the workaround level into an easy-to-compare number, where higher 26485fbe08eSRaghavendra Rao Ananta * values mean better protection. 26585fbe08eSRaghavendra Rao Ananta */ 26685fbe08eSRaghavendra Rao Ananta static int get_kernel_wa_level(u64 regid) 26785fbe08eSRaghavendra Rao Ananta { 26885fbe08eSRaghavendra Rao Ananta switch (regid) { 26985fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1: 27085fbe08eSRaghavendra Rao Ananta switch (arm64_get_spectre_v2_state()) { 27185fbe08eSRaghavendra Rao Ananta case SPECTRE_VULNERABLE: 27285fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL; 27385fbe08eSRaghavendra Rao Ananta case SPECTRE_MITIGATED: 27485fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_AVAIL; 27585fbe08eSRaghavendra Rao Ananta case SPECTRE_UNAFFECTED: 27685fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_REQUIRED; 27785fbe08eSRaghavendra Rao Ananta } 27885fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL; 27985fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2: 28085fbe08eSRaghavendra Rao Ananta switch (arm64_get_spectre_v4_state()) { 28185fbe08eSRaghavendra Rao Ananta case SPECTRE_MITIGATED: 28285fbe08eSRaghavendra Rao Ananta /* 28385fbe08eSRaghavendra Rao Ananta * As for the hypercall discovery, we pretend we 28485fbe08eSRaghavendra Rao Ananta * don't have any FW mitigation if SSBS is there at 28585fbe08eSRaghavendra Rao Ananta * all times. 28685fbe08eSRaghavendra Rao Ananta */ 28785fbe08eSRaghavendra Rao Ananta if (cpus_have_final_cap(ARM64_SSBS)) 28885fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL; 28985fbe08eSRaghavendra Rao Ananta fallthrough; 29085fbe08eSRaghavendra Rao Ananta case SPECTRE_UNAFFECTED: 29185fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED; 29285fbe08eSRaghavendra Rao Ananta case SPECTRE_VULNERABLE: 29385fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL; 29485fbe08eSRaghavendra Rao Ananta } 29585fbe08eSRaghavendra Rao Ananta break; 29685fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3: 29785fbe08eSRaghavendra Rao Ananta switch (arm64_get_spectre_bhb_state()) { 29885fbe08eSRaghavendra Rao Ananta case SPECTRE_VULNERABLE: 29985fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL; 30085fbe08eSRaghavendra Rao Ananta case SPECTRE_MITIGATED: 30185fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_AVAIL; 30285fbe08eSRaghavendra Rao Ananta case SPECTRE_UNAFFECTED: 30385fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_REQUIRED; 30485fbe08eSRaghavendra Rao Ananta } 30585fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL; 30685fbe08eSRaghavendra Rao Ananta } 30785fbe08eSRaghavendra Rao Ananta 30885fbe08eSRaghavendra Rao Ananta return -EINVAL; 30985fbe08eSRaghavendra Rao Ananta } 31085fbe08eSRaghavendra Rao Ananta 31185fbe08eSRaghavendra Rao Ananta int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) 31285fbe08eSRaghavendra Rao Ananta { 31305714cabSRaghavendra Rao Ananta struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat; 31485fbe08eSRaghavendra Rao Ananta void __user *uaddr = (void __user *)(long)reg->addr; 31585fbe08eSRaghavendra Rao Ananta u64 val; 31685fbe08eSRaghavendra Rao Ananta 31785fbe08eSRaghavendra Rao Ananta switch (reg->id) { 31885fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_PSCI_VERSION: 31985fbe08eSRaghavendra Rao Ananta val = kvm_psci_version(vcpu); 32085fbe08eSRaghavendra Rao Ananta break; 32185fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1: 32285fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2: 32385fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3: 32485fbe08eSRaghavendra Rao Ananta val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK; 32585fbe08eSRaghavendra Rao Ananta break; 32605714cabSRaghavendra Rao Ananta case KVM_REG_ARM_STD_BMAP: 32705714cabSRaghavendra Rao Ananta val = READ_ONCE(smccc_feat->std_bmap); 32805714cabSRaghavendra Rao Ananta break; 329*428fd678SRaghavendra Rao Ananta case KVM_REG_ARM_STD_HYP_BMAP: 330*428fd678SRaghavendra Rao Ananta val = READ_ONCE(smccc_feat->std_hyp_bmap); 331*428fd678SRaghavendra Rao Ananta break; 33285fbe08eSRaghavendra Rao Ananta default: 33385fbe08eSRaghavendra Rao Ananta return -ENOENT; 33485fbe08eSRaghavendra Rao Ananta } 33585fbe08eSRaghavendra Rao Ananta 33685fbe08eSRaghavendra Rao Ananta if (copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id))) 33785fbe08eSRaghavendra Rao Ananta return -EFAULT; 33885fbe08eSRaghavendra Rao Ananta 33985fbe08eSRaghavendra Rao Ananta return 0; 34085fbe08eSRaghavendra Rao Ananta } 34185fbe08eSRaghavendra Rao Ananta 34205714cabSRaghavendra Rao Ananta static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val) 34305714cabSRaghavendra Rao Ananta { 34405714cabSRaghavendra Rao Ananta int ret = 0; 34505714cabSRaghavendra Rao Ananta struct kvm *kvm = vcpu->kvm; 34605714cabSRaghavendra Rao Ananta struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat; 34705714cabSRaghavendra Rao Ananta unsigned long *fw_reg_bmap, fw_reg_features; 34805714cabSRaghavendra Rao Ananta 34905714cabSRaghavendra Rao Ananta switch (reg_id) { 35005714cabSRaghavendra Rao Ananta case KVM_REG_ARM_STD_BMAP: 35105714cabSRaghavendra Rao Ananta fw_reg_bmap = &smccc_feat->std_bmap; 35205714cabSRaghavendra Rao Ananta fw_reg_features = KVM_ARM_SMCCC_STD_FEATURES; 35305714cabSRaghavendra Rao Ananta break; 354*428fd678SRaghavendra Rao Ananta case KVM_REG_ARM_STD_HYP_BMAP: 355*428fd678SRaghavendra Rao Ananta fw_reg_bmap = &smccc_feat->std_hyp_bmap; 356*428fd678SRaghavendra Rao Ananta fw_reg_features = KVM_ARM_SMCCC_STD_HYP_FEATURES; 357*428fd678SRaghavendra Rao Ananta break; 35805714cabSRaghavendra Rao Ananta default: 35905714cabSRaghavendra Rao Ananta return -ENOENT; 36005714cabSRaghavendra Rao Ananta } 36105714cabSRaghavendra Rao Ananta 36205714cabSRaghavendra Rao Ananta /* Check for unsupported bit */ 36305714cabSRaghavendra Rao Ananta if (val & ~fw_reg_features) 36405714cabSRaghavendra Rao Ananta return -EINVAL; 36505714cabSRaghavendra Rao Ananta 36605714cabSRaghavendra Rao Ananta mutex_lock(&kvm->lock); 36705714cabSRaghavendra Rao Ananta 36805714cabSRaghavendra Rao Ananta if (test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags)) { 36905714cabSRaghavendra Rao Ananta ret = -EBUSY; 37005714cabSRaghavendra Rao Ananta goto out; 37105714cabSRaghavendra Rao Ananta } 37205714cabSRaghavendra Rao Ananta 37305714cabSRaghavendra Rao Ananta WRITE_ONCE(*fw_reg_bmap, val); 37405714cabSRaghavendra Rao Ananta out: 37505714cabSRaghavendra Rao Ananta mutex_unlock(&kvm->lock); 37605714cabSRaghavendra Rao Ananta return ret; 37705714cabSRaghavendra Rao Ananta } 37805714cabSRaghavendra Rao Ananta 37985fbe08eSRaghavendra Rao Ananta int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) 38085fbe08eSRaghavendra Rao Ananta { 38185fbe08eSRaghavendra Rao Ananta void __user *uaddr = (void __user *)(long)reg->addr; 38285fbe08eSRaghavendra Rao Ananta u64 val; 38385fbe08eSRaghavendra Rao Ananta int wa_level; 38485fbe08eSRaghavendra Rao Ananta 38585fbe08eSRaghavendra Rao Ananta if (copy_from_user(&val, uaddr, KVM_REG_SIZE(reg->id))) 38685fbe08eSRaghavendra Rao Ananta return -EFAULT; 38785fbe08eSRaghavendra Rao Ananta 38885fbe08eSRaghavendra Rao Ananta switch (reg->id) { 38985fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_PSCI_VERSION: 39085fbe08eSRaghavendra Rao Ananta { 39185fbe08eSRaghavendra Rao Ananta bool wants_02; 39285fbe08eSRaghavendra Rao Ananta 39385fbe08eSRaghavendra Rao Ananta wants_02 = test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features); 39485fbe08eSRaghavendra Rao Ananta 39585fbe08eSRaghavendra Rao Ananta switch (val) { 39685fbe08eSRaghavendra Rao Ananta case KVM_ARM_PSCI_0_1: 39785fbe08eSRaghavendra Rao Ananta if (wants_02) 39885fbe08eSRaghavendra Rao Ananta return -EINVAL; 39985fbe08eSRaghavendra Rao Ananta vcpu->kvm->arch.psci_version = val; 40085fbe08eSRaghavendra Rao Ananta return 0; 40185fbe08eSRaghavendra Rao Ananta case KVM_ARM_PSCI_0_2: 40285fbe08eSRaghavendra Rao Ananta case KVM_ARM_PSCI_1_0: 40385fbe08eSRaghavendra Rao Ananta case KVM_ARM_PSCI_1_1: 40485fbe08eSRaghavendra Rao Ananta if (!wants_02) 40585fbe08eSRaghavendra Rao Ananta return -EINVAL; 40685fbe08eSRaghavendra Rao Ananta vcpu->kvm->arch.psci_version = val; 40785fbe08eSRaghavendra Rao Ananta return 0; 40885fbe08eSRaghavendra Rao Ananta } 40985fbe08eSRaghavendra Rao Ananta break; 41085fbe08eSRaghavendra Rao Ananta } 41185fbe08eSRaghavendra Rao Ananta 41285fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1: 41385fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3: 41485fbe08eSRaghavendra Rao Ananta if (val & ~KVM_REG_FEATURE_LEVEL_MASK) 41585fbe08eSRaghavendra Rao Ananta return -EINVAL; 41685fbe08eSRaghavendra Rao Ananta 41785fbe08eSRaghavendra Rao Ananta if (get_kernel_wa_level(reg->id) < val) 41885fbe08eSRaghavendra Rao Ananta return -EINVAL; 41985fbe08eSRaghavendra Rao Ananta 42085fbe08eSRaghavendra Rao Ananta return 0; 42185fbe08eSRaghavendra Rao Ananta 42285fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2: 42385fbe08eSRaghavendra Rao Ananta if (val & ~(KVM_REG_FEATURE_LEVEL_MASK | 42485fbe08eSRaghavendra Rao Ananta KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED)) 42585fbe08eSRaghavendra Rao Ananta return -EINVAL; 42685fbe08eSRaghavendra Rao Ananta 42785fbe08eSRaghavendra Rao Ananta /* The enabled bit must not be set unless the level is AVAIL. */ 42885fbe08eSRaghavendra Rao Ananta if ((val & KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED) && 42985fbe08eSRaghavendra Rao Ananta (val & KVM_REG_FEATURE_LEVEL_MASK) != KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL) 43085fbe08eSRaghavendra Rao Ananta return -EINVAL; 43185fbe08eSRaghavendra Rao Ananta 43285fbe08eSRaghavendra Rao Ananta /* 43385fbe08eSRaghavendra Rao Ananta * Map all the possible incoming states to the only two we 43485fbe08eSRaghavendra Rao Ananta * really want to deal with. 43585fbe08eSRaghavendra Rao Ananta */ 43685fbe08eSRaghavendra Rao Ananta switch (val & KVM_REG_FEATURE_LEVEL_MASK) { 43785fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL: 43885fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_UNKNOWN: 43985fbe08eSRaghavendra Rao Ananta wa_level = KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL; 44085fbe08eSRaghavendra Rao Ananta break; 44185fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL: 44285fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED: 44385fbe08eSRaghavendra Rao Ananta wa_level = KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED; 44485fbe08eSRaghavendra Rao Ananta break; 44585fbe08eSRaghavendra Rao Ananta default: 44685fbe08eSRaghavendra Rao Ananta return -EINVAL; 44785fbe08eSRaghavendra Rao Ananta } 44885fbe08eSRaghavendra Rao Ananta 44985fbe08eSRaghavendra Rao Ananta /* 45085fbe08eSRaghavendra Rao Ananta * We can deal with NOT_AVAIL on NOT_REQUIRED, but not the 45185fbe08eSRaghavendra Rao Ananta * other way around. 45285fbe08eSRaghavendra Rao Ananta */ 45385fbe08eSRaghavendra Rao Ananta if (get_kernel_wa_level(reg->id) < wa_level) 45485fbe08eSRaghavendra Rao Ananta return -EINVAL; 45585fbe08eSRaghavendra Rao Ananta 45685fbe08eSRaghavendra Rao Ananta return 0; 45705714cabSRaghavendra Rao Ananta case KVM_REG_ARM_STD_BMAP: 458*428fd678SRaghavendra Rao Ananta case KVM_REG_ARM_STD_HYP_BMAP: 45905714cabSRaghavendra Rao Ananta return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val); 46085fbe08eSRaghavendra Rao Ananta default: 46185fbe08eSRaghavendra Rao Ananta return -ENOENT; 46285fbe08eSRaghavendra Rao Ananta } 46385fbe08eSRaghavendra Rao Ananta 46485fbe08eSRaghavendra Rao Ananta return -EINVAL; 46585fbe08eSRaghavendra Rao Ananta } 466