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 12*05714cabSRaghavendra Rao Ananta #define KVM_ARM_SMCCC_STD_FEATURES \ 13*05714cabSRaghavendra Rao Ananta GENMASK(KVM_REG_ARM_STD_BMAP_BIT_COUNT - 1, 0) 14*05714cabSRaghavendra Rao Ananta 153bf72569SJianyong Wu static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val) 163bf72569SJianyong Wu { 173bf72569SJianyong Wu struct system_time_snapshot systime_snapshot; 183bf72569SJianyong Wu u64 cycles = ~0UL; 193bf72569SJianyong Wu u32 feature; 203bf72569SJianyong Wu 213bf72569SJianyong Wu /* 223bf72569SJianyong Wu * system time and counter value must captured at the same 233bf72569SJianyong Wu * time to keep consistency and precision. 243bf72569SJianyong Wu */ 253bf72569SJianyong Wu ktime_get_snapshot(&systime_snapshot); 263bf72569SJianyong Wu 273bf72569SJianyong Wu /* 283bf72569SJianyong Wu * This is only valid if the current clocksource is the 293bf72569SJianyong Wu * architected counter, as this is the only one the guest 303bf72569SJianyong Wu * can see. 313bf72569SJianyong Wu */ 323bf72569SJianyong Wu if (systime_snapshot.cs_id != CSID_ARM_ARCH_COUNTER) 333bf72569SJianyong Wu return; 343bf72569SJianyong Wu 353bf72569SJianyong Wu /* 363bf72569SJianyong Wu * The guest selects one of the two reference counters 373bf72569SJianyong Wu * (virtual or physical) with the first argument of the SMCCC 383bf72569SJianyong Wu * call. In case the identifier is not supported, error out. 393bf72569SJianyong Wu */ 403bf72569SJianyong Wu feature = smccc_get_arg1(vcpu); 413bf72569SJianyong Wu switch (feature) { 423bf72569SJianyong Wu case KVM_PTP_VIRT_COUNTER: 433bf72569SJianyong Wu cycles = systime_snapshot.cycles - vcpu_read_sys_reg(vcpu, CNTVOFF_EL2); 443bf72569SJianyong Wu break; 453bf72569SJianyong Wu case KVM_PTP_PHYS_COUNTER: 463bf72569SJianyong Wu cycles = systime_snapshot.cycles; 473bf72569SJianyong Wu break; 483bf72569SJianyong Wu default: 493bf72569SJianyong Wu return; 503bf72569SJianyong Wu } 513bf72569SJianyong Wu 523bf72569SJianyong Wu /* 533bf72569SJianyong Wu * This relies on the top bit of val[0] never being set for 543bf72569SJianyong Wu * valid values of system time, because that is *really* far 553bf72569SJianyong Wu * in the future (about 292 years from 1970, and at that stage 563bf72569SJianyong Wu * nobody will give a damn about it). 573bf72569SJianyong Wu */ 583bf72569SJianyong Wu val[0] = upper_32_bits(systime_snapshot.real); 593bf72569SJianyong Wu val[1] = lower_32_bits(systime_snapshot.real); 603bf72569SJianyong Wu val[2] = upper_32_bits(cycles); 613bf72569SJianyong Wu val[3] = lower_32_bits(cycles); 623bf72569SJianyong Wu } 633bf72569SJianyong Wu 64*05714cabSRaghavendra Rao Ananta static bool kvm_hvc_call_default_allowed(u32 func_id) 65*05714cabSRaghavendra Rao Ananta { 66*05714cabSRaghavendra Rao Ananta switch (func_id) { 67*05714cabSRaghavendra Rao Ananta /* 68*05714cabSRaghavendra Rao Ananta * List of function-ids that are not gated with the bitmapped 69*05714cabSRaghavendra Rao Ananta * feature firmware registers, and are to be allowed for 70*05714cabSRaghavendra Rao Ananta * servicing the call by default. 71*05714cabSRaghavendra Rao Ananta */ 72*05714cabSRaghavendra Rao Ananta case ARM_SMCCC_VERSION_FUNC_ID: 73*05714cabSRaghavendra Rao Ananta case ARM_SMCCC_ARCH_FEATURES_FUNC_ID: 74*05714cabSRaghavendra Rao Ananta case ARM_SMCCC_HV_PV_TIME_FEATURES: 75*05714cabSRaghavendra Rao Ananta case ARM_SMCCC_HV_PV_TIME_ST: 76*05714cabSRaghavendra Rao Ananta case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID: 77*05714cabSRaghavendra Rao Ananta case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID: 78*05714cabSRaghavendra Rao Ananta case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID: 79*05714cabSRaghavendra Rao Ananta return true; 80*05714cabSRaghavendra Rao Ananta default: 81*05714cabSRaghavendra Rao Ananta /* PSCI 0.2 and up is in the 0:0x1f range */ 82*05714cabSRaghavendra Rao Ananta if (ARM_SMCCC_OWNER_NUM(func_id) == ARM_SMCCC_OWNER_STANDARD && 83*05714cabSRaghavendra Rao Ananta ARM_SMCCC_FUNC_NUM(func_id) <= 0x1f) 84*05714cabSRaghavendra Rao Ananta return true; 85*05714cabSRaghavendra Rao Ananta 86*05714cabSRaghavendra Rao Ananta /* 87*05714cabSRaghavendra Rao Ananta * KVM's PSCI 0.1 doesn't comply with SMCCC, and has 88*05714cabSRaghavendra Rao Ananta * its own function-id base and range 89*05714cabSRaghavendra Rao Ananta */ 90*05714cabSRaghavendra Rao Ananta if (func_id >= KVM_PSCI_FN(0) && func_id <= KVM_PSCI_FN(3)) 91*05714cabSRaghavendra Rao Ananta return true; 92*05714cabSRaghavendra Rao Ananta 93*05714cabSRaghavendra Rao Ananta return false; 94*05714cabSRaghavendra Rao Ananta } 95*05714cabSRaghavendra Rao Ananta } 96*05714cabSRaghavendra Rao Ananta 97*05714cabSRaghavendra Rao Ananta static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id) 98*05714cabSRaghavendra Rao Ananta { 99*05714cabSRaghavendra Rao Ananta struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat; 100*05714cabSRaghavendra Rao Ananta 101*05714cabSRaghavendra Rao Ananta switch (func_id) { 102*05714cabSRaghavendra Rao Ananta case ARM_SMCCC_TRNG_VERSION: 103*05714cabSRaghavendra Rao Ananta case ARM_SMCCC_TRNG_FEATURES: 104*05714cabSRaghavendra Rao Ananta case ARM_SMCCC_TRNG_GET_UUID: 105*05714cabSRaghavendra Rao Ananta case ARM_SMCCC_TRNG_RND32: 106*05714cabSRaghavendra Rao Ananta case ARM_SMCCC_TRNG_RND64: 107*05714cabSRaghavendra Rao Ananta return test_bit(KVM_REG_ARM_STD_BIT_TRNG_V1_0, 108*05714cabSRaghavendra Rao Ananta &smccc_feat->std_bmap); 109*05714cabSRaghavendra Rao Ananta default: 110*05714cabSRaghavendra Rao Ananta return kvm_hvc_call_default_allowed(func_id); 111*05714cabSRaghavendra Rao Ananta } 112*05714cabSRaghavendra Rao Ananta } 113*05714cabSRaghavendra Rao Ananta 1149ed24f4bSMarc Zyngier int kvm_hvc_call_handler(struct kvm_vcpu *vcpu) 1159ed24f4bSMarc Zyngier { 1169ed24f4bSMarc Zyngier u32 func_id = smccc_get_function(vcpu); 117923961a7SWill Deacon u64 val[4] = {SMCCC_RET_NOT_SUPPORTED}; 1189ed24f4bSMarc Zyngier u32 feature; 1199ed24f4bSMarc Zyngier gpa_t gpa; 1209ed24f4bSMarc Zyngier 121*05714cabSRaghavendra Rao Ananta if (!kvm_hvc_call_allowed(vcpu, func_id)) 122*05714cabSRaghavendra Rao Ananta goto out; 123*05714cabSRaghavendra Rao Ananta 1249ed24f4bSMarc Zyngier switch (func_id) { 1259ed24f4bSMarc Zyngier case ARM_SMCCC_VERSION_FUNC_ID: 126923961a7SWill Deacon val[0] = ARM_SMCCC_VERSION_1_1; 1279ed24f4bSMarc Zyngier break; 1289ed24f4bSMarc Zyngier case ARM_SMCCC_ARCH_FEATURES_FUNC_ID: 1299ed24f4bSMarc Zyngier feature = smccc_get_arg1(vcpu); 1309ed24f4bSMarc Zyngier switch (feature) { 1319ed24f4bSMarc Zyngier case ARM_SMCCC_ARCH_WORKAROUND_1: 132d4647f0aSWill Deacon switch (arm64_get_spectre_v2_state()) { 133d4647f0aSWill Deacon case SPECTRE_VULNERABLE: 1349ed24f4bSMarc Zyngier break; 135d4647f0aSWill Deacon case SPECTRE_MITIGATED: 136923961a7SWill Deacon val[0] = SMCCC_RET_SUCCESS; 1379ed24f4bSMarc Zyngier break; 138d4647f0aSWill Deacon case SPECTRE_UNAFFECTED: 139923961a7SWill Deacon val[0] = SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED; 1409ed24f4bSMarc Zyngier break; 1419ed24f4bSMarc Zyngier } 1429ed24f4bSMarc Zyngier break; 1439ed24f4bSMarc Zyngier case ARM_SMCCC_ARCH_WORKAROUND_2: 144d63d975aSMarc Zyngier switch (arm64_get_spectre_v4_state()) { 145d63d975aSMarc Zyngier case SPECTRE_VULNERABLE: 1469ed24f4bSMarc Zyngier break; 147d63d975aSMarc Zyngier case SPECTRE_MITIGATED: 148d63d975aSMarc Zyngier /* 149d63d975aSMarc Zyngier * SSBS everywhere: Indicate no firmware 150d63d975aSMarc Zyngier * support, as the SSBS support will be 151d63d975aSMarc Zyngier * indicated to the guest and the default is 152d63d975aSMarc Zyngier * safe. 153d63d975aSMarc Zyngier * 154d63d975aSMarc Zyngier * Otherwise, expose a permanent mitigation 155d63d975aSMarc Zyngier * to the guest, and hide SSBS so that the 156d63d975aSMarc Zyngier * guest stays protected. 157d63d975aSMarc Zyngier */ 158d63d975aSMarc Zyngier if (cpus_have_final_cap(ARM64_SSBS)) 159d63d975aSMarc Zyngier break; 160d63d975aSMarc Zyngier fallthrough; 161d63d975aSMarc Zyngier case SPECTRE_UNAFFECTED: 162923961a7SWill Deacon val[0] = SMCCC_RET_NOT_REQUIRED; 1639ed24f4bSMarc Zyngier break; 1649ed24f4bSMarc Zyngier } 1659ed24f4bSMarc Zyngier break; 166a5905d6aSJames Morse case ARM_SMCCC_ARCH_WORKAROUND_3: 167a5905d6aSJames Morse switch (arm64_get_spectre_bhb_state()) { 168a5905d6aSJames Morse case SPECTRE_VULNERABLE: 169a5905d6aSJames Morse break; 170a5905d6aSJames Morse case SPECTRE_MITIGATED: 171a5905d6aSJames Morse val[0] = SMCCC_RET_SUCCESS; 172a5905d6aSJames Morse break; 173a5905d6aSJames Morse case SPECTRE_UNAFFECTED: 174a5905d6aSJames Morse val[0] = SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED; 175a5905d6aSJames Morse break; 176a5905d6aSJames Morse } 177a5905d6aSJames Morse break; 1789ed24f4bSMarc Zyngier case ARM_SMCCC_HV_PV_TIME_FEATURES: 179923961a7SWill Deacon val[0] = SMCCC_RET_SUCCESS; 1809ed24f4bSMarc Zyngier break; 1819ed24f4bSMarc Zyngier } 1829ed24f4bSMarc Zyngier break; 1839ed24f4bSMarc Zyngier case ARM_SMCCC_HV_PV_TIME_FEATURES: 184923961a7SWill Deacon val[0] = kvm_hypercall_pv_features(vcpu); 1859ed24f4bSMarc Zyngier break; 1869ed24f4bSMarc Zyngier case ARM_SMCCC_HV_PV_TIME_ST: 1879ed24f4bSMarc Zyngier gpa = kvm_init_stolen_time(vcpu); 1889ed24f4bSMarc Zyngier if (gpa != GPA_INVALID) 189923961a7SWill Deacon val[0] = gpa; 190923961a7SWill Deacon break; 191923961a7SWill Deacon case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID: 192923961a7SWill Deacon val[0] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_0; 193923961a7SWill Deacon val[1] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_1; 194923961a7SWill Deacon val[2] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_2; 195923961a7SWill Deacon val[3] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_3; 196923961a7SWill Deacon break; 197923961a7SWill Deacon case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID: 198923961a7SWill Deacon val[0] = BIT(ARM_SMCCC_KVM_FUNC_FEATURES); 1993bf72569SJianyong Wu val[0] |= BIT(ARM_SMCCC_KVM_FUNC_PTP); 2003bf72569SJianyong Wu break; 2013bf72569SJianyong Wu case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID: 2023bf72569SJianyong Wu kvm_ptp_get_time(vcpu, val); 2039ed24f4bSMarc Zyngier break; 204a8e190cdSArd Biesheuvel case ARM_SMCCC_TRNG_VERSION: 205a8e190cdSArd Biesheuvel case ARM_SMCCC_TRNG_FEATURES: 206a8e190cdSArd Biesheuvel case ARM_SMCCC_TRNG_GET_UUID: 207a8e190cdSArd Biesheuvel case ARM_SMCCC_TRNG_RND32: 208a8e190cdSArd Biesheuvel case ARM_SMCCC_TRNG_RND64: 209a8e190cdSArd Biesheuvel return kvm_trng_call(vcpu); 2109ed24f4bSMarc Zyngier default: 2119ed24f4bSMarc Zyngier return kvm_psci_call(vcpu); 2129ed24f4bSMarc Zyngier } 2139ed24f4bSMarc Zyngier 214*05714cabSRaghavendra Rao Ananta out: 215923961a7SWill Deacon smccc_set_retval(vcpu, val[0], val[1], val[2], val[3]); 2169ed24f4bSMarc Zyngier return 1; 2179ed24f4bSMarc Zyngier } 21885fbe08eSRaghavendra Rao Ananta 21985fbe08eSRaghavendra Rao Ananta static const u64 kvm_arm_fw_reg_ids[] = { 22085fbe08eSRaghavendra Rao Ananta KVM_REG_ARM_PSCI_VERSION, 22185fbe08eSRaghavendra Rao Ananta KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1, 22285fbe08eSRaghavendra Rao Ananta KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2, 22385fbe08eSRaghavendra Rao Ananta KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3, 224*05714cabSRaghavendra Rao Ananta KVM_REG_ARM_STD_BMAP, 22585fbe08eSRaghavendra Rao Ananta }; 22685fbe08eSRaghavendra Rao Ananta 227*05714cabSRaghavendra Rao Ananta void kvm_arm_init_hypercalls(struct kvm *kvm) 228*05714cabSRaghavendra Rao Ananta { 229*05714cabSRaghavendra Rao Ananta struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat; 230*05714cabSRaghavendra Rao Ananta 231*05714cabSRaghavendra Rao Ananta smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES; 232*05714cabSRaghavendra Rao Ananta } 233*05714cabSRaghavendra Rao Ananta 23485fbe08eSRaghavendra Rao Ananta int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu) 23585fbe08eSRaghavendra Rao Ananta { 23685fbe08eSRaghavendra Rao Ananta return ARRAY_SIZE(kvm_arm_fw_reg_ids); 23785fbe08eSRaghavendra Rao Ananta } 23885fbe08eSRaghavendra Rao Ananta 23985fbe08eSRaghavendra Rao Ananta int kvm_arm_copy_fw_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices) 24085fbe08eSRaghavendra Rao Ananta { 24185fbe08eSRaghavendra Rao Ananta int i; 24285fbe08eSRaghavendra Rao Ananta 24385fbe08eSRaghavendra Rao Ananta for (i = 0; i < ARRAY_SIZE(kvm_arm_fw_reg_ids); i++) { 24485fbe08eSRaghavendra Rao Ananta if (put_user(kvm_arm_fw_reg_ids[i], uindices++)) 24585fbe08eSRaghavendra Rao Ananta return -EFAULT; 24685fbe08eSRaghavendra Rao Ananta } 24785fbe08eSRaghavendra Rao Ananta 24885fbe08eSRaghavendra Rao Ananta return 0; 24985fbe08eSRaghavendra Rao Ananta } 25085fbe08eSRaghavendra Rao Ananta 25185fbe08eSRaghavendra Rao Ananta #define KVM_REG_FEATURE_LEVEL_MASK GENMASK(3, 0) 25285fbe08eSRaghavendra Rao Ananta 25385fbe08eSRaghavendra Rao Ananta /* 25485fbe08eSRaghavendra Rao Ananta * Convert the workaround level into an easy-to-compare number, where higher 25585fbe08eSRaghavendra Rao Ananta * values mean better protection. 25685fbe08eSRaghavendra Rao Ananta */ 25785fbe08eSRaghavendra Rao Ananta static int get_kernel_wa_level(u64 regid) 25885fbe08eSRaghavendra Rao Ananta { 25985fbe08eSRaghavendra Rao Ananta switch (regid) { 26085fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1: 26185fbe08eSRaghavendra Rao Ananta switch (arm64_get_spectre_v2_state()) { 26285fbe08eSRaghavendra Rao Ananta case SPECTRE_VULNERABLE: 26385fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL; 26485fbe08eSRaghavendra Rao Ananta case SPECTRE_MITIGATED: 26585fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_AVAIL; 26685fbe08eSRaghavendra Rao Ananta case SPECTRE_UNAFFECTED: 26785fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_REQUIRED; 26885fbe08eSRaghavendra Rao Ananta } 26985fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL; 27085fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2: 27185fbe08eSRaghavendra Rao Ananta switch (arm64_get_spectre_v4_state()) { 27285fbe08eSRaghavendra Rao Ananta case SPECTRE_MITIGATED: 27385fbe08eSRaghavendra Rao Ananta /* 27485fbe08eSRaghavendra Rao Ananta * As for the hypercall discovery, we pretend we 27585fbe08eSRaghavendra Rao Ananta * don't have any FW mitigation if SSBS is there at 27685fbe08eSRaghavendra Rao Ananta * all times. 27785fbe08eSRaghavendra Rao Ananta */ 27885fbe08eSRaghavendra Rao Ananta if (cpus_have_final_cap(ARM64_SSBS)) 27985fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL; 28085fbe08eSRaghavendra Rao Ananta fallthrough; 28185fbe08eSRaghavendra Rao Ananta case SPECTRE_UNAFFECTED: 28285fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED; 28385fbe08eSRaghavendra Rao Ananta case SPECTRE_VULNERABLE: 28485fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL; 28585fbe08eSRaghavendra Rao Ananta } 28685fbe08eSRaghavendra Rao Ananta break; 28785fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3: 28885fbe08eSRaghavendra Rao Ananta switch (arm64_get_spectre_bhb_state()) { 28985fbe08eSRaghavendra Rao Ananta case SPECTRE_VULNERABLE: 29085fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL; 29185fbe08eSRaghavendra Rao Ananta case SPECTRE_MITIGATED: 29285fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_AVAIL; 29385fbe08eSRaghavendra Rao Ananta case SPECTRE_UNAFFECTED: 29485fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_REQUIRED; 29585fbe08eSRaghavendra Rao Ananta } 29685fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL; 29785fbe08eSRaghavendra Rao Ananta } 29885fbe08eSRaghavendra Rao Ananta 29985fbe08eSRaghavendra Rao Ananta return -EINVAL; 30085fbe08eSRaghavendra Rao Ananta } 30185fbe08eSRaghavendra Rao Ananta 30285fbe08eSRaghavendra Rao Ananta int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) 30385fbe08eSRaghavendra Rao Ananta { 304*05714cabSRaghavendra Rao Ananta struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat; 30585fbe08eSRaghavendra Rao Ananta void __user *uaddr = (void __user *)(long)reg->addr; 30685fbe08eSRaghavendra Rao Ananta u64 val; 30785fbe08eSRaghavendra Rao Ananta 30885fbe08eSRaghavendra Rao Ananta switch (reg->id) { 30985fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_PSCI_VERSION: 31085fbe08eSRaghavendra Rao Ananta val = kvm_psci_version(vcpu); 31185fbe08eSRaghavendra Rao Ananta break; 31285fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1: 31385fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2: 31485fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3: 31585fbe08eSRaghavendra Rao Ananta val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK; 31685fbe08eSRaghavendra Rao Ananta break; 317*05714cabSRaghavendra Rao Ananta case KVM_REG_ARM_STD_BMAP: 318*05714cabSRaghavendra Rao Ananta val = READ_ONCE(smccc_feat->std_bmap); 319*05714cabSRaghavendra Rao Ananta break; 32085fbe08eSRaghavendra Rao Ananta default: 32185fbe08eSRaghavendra Rao Ananta return -ENOENT; 32285fbe08eSRaghavendra Rao Ananta } 32385fbe08eSRaghavendra Rao Ananta 32485fbe08eSRaghavendra Rao Ananta if (copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id))) 32585fbe08eSRaghavendra Rao Ananta return -EFAULT; 32685fbe08eSRaghavendra Rao Ananta 32785fbe08eSRaghavendra Rao Ananta return 0; 32885fbe08eSRaghavendra Rao Ananta } 32985fbe08eSRaghavendra Rao Ananta 330*05714cabSRaghavendra Rao Ananta static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val) 331*05714cabSRaghavendra Rao Ananta { 332*05714cabSRaghavendra Rao Ananta int ret = 0; 333*05714cabSRaghavendra Rao Ananta struct kvm *kvm = vcpu->kvm; 334*05714cabSRaghavendra Rao Ananta struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat; 335*05714cabSRaghavendra Rao Ananta unsigned long *fw_reg_bmap, fw_reg_features; 336*05714cabSRaghavendra Rao Ananta 337*05714cabSRaghavendra Rao Ananta switch (reg_id) { 338*05714cabSRaghavendra Rao Ananta case KVM_REG_ARM_STD_BMAP: 339*05714cabSRaghavendra Rao Ananta fw_reg_bmap = &smccc_feat->std_bmap; 340*05714cabSRaghavendra Rao Ananta fw_reg_features = KVM_ARM_SMCCC_STD_FEATURES; 341*05714cabSRaghavendra Rao Ananta break; 342*05714cabSRaghavendra Rao Ananta default: 343*05714cabSRaghavendra Rao Ananta return -ENOENT; 344*05714cabSRaghavendra Rao Ananta } 345*05714cabSRaghavendra Rao Ananta 346*05714cabSRaghavendra Rao Ananta /* Check for unsupported bit */ 347*05714cabSRaghavendra Rao Ananta if (val & ~fw_reg_features) 348*05714cabSRaghavendra Rao Ananta return -EINVAL; 349*05714cabSRaghavendra Rao Ananta 350*05714cabSRaghavendra Rao Ananta mutex_lock(&kvm->lock); 351*05714cabSRaghavendra Rao Ananta 352*05714cabSRaghavendra Rao Ananta if (test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags)) { 353*05714cabSRaghavendra Rao Ananta ret = -EBUSY; 354*05714cabSRaghavendra Rao Ananta goto out; 355*05714cabSRaghavendra Rao Ananta } 356*05714cabSRaghavendra Rao Ananta 357*05714cabSRaghavendra Rao Ananta WRITE_ONCE(*fw_reg_bmap, val); 358*05714cabSRaghavendra Rao Ananta out: 359*05714cabSRaghavendra Rao Ananta mutex_unlock(&kvm->lock); 360*05714cabSRaghavendra Rao Ananta return ret; 361*05714cabSRaghavendra Rao Ananta } 362*05714cabSRaghavendra Rao Ananta 36385fbe08eSRaghavendra Rao Ananta int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) 36485fbe08eSRaghavendra Rao Ananta { 36585fbe08eSRaghavendra Rao Ananta void __user *uaddr = (void __user *)(long)reg->addr; 36685fbe08eSRaghavendra Rao Ananta u64 val; 36785fbe08eSRaghavendra Rao Ananta int wa_level; 36885fbe08eSRaghavendra Rao Ananta 36985fbe08eSRaghavendra Rao Ananta if (copy_from_user(&val, uaddr, KVM_REG_SIZE(reg->id))) 37085fbe08eSRaghavendra Rao Ananta return -EFAULT; 37185fbe08eSRaghavendra Rao Ananta 37285fbe08eSRaghavendra Rao Ananta switch (reg->id) { 37385fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_PSCI_VERSION: 37485fbe08eSRaghavendra Rao Ananta { 37585fbe08eSRaghavendra Rao Ananta bool wants_02; 37685fbe08eSRaghavendra Rao Ananta 37785fbe08eSRaghavendra Rao Ananta wants_02 = test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features); 37885fbe08eSRaghavendra Rao Ananta 37985fbe08eSRaghavendra Rao Ananta switch (val) { 38085fbe08eSRaghavendra Rao Ananta case KVM_ARM_PSCI_0_1: 38185fbe08eSRaghavendra Rao Ananta if (wants_02) 38285fbe08eSRaghavendra Rao Ananta return -EINVAL; 38385fbe08eSRaghavendra Rao Ananta vcpu->kvm->arch.psci_version = val; 38485fbe08eSRaghavendra Rao Ananta return 0; 38585fbe08eSRaghavendra Rao Ananta case KVM_ARM_PSCI_0_2: 38685fbe08eSRaghavendra Rao Ananta case KVM_ARM_PSCI_1_0: 38785fbe08eSRaghavendra Rao Ananta case KVM_ARM_PSCI_1_1: 38885fbe08eSRaghavendra Rao Ananta if (!wants_02) 38985fbe08eSRaghavendra Rao Ananta return -EINVAL; 39085fbe08eSRaghavendra Rao Ananta vcpu->kvm->arch.psci_version = val; 39185fbe08eSRaghavendra Rao Ananta return 0; 39285fbe08eSRaghavendra Rao Ananta } 39385fbe08eSRaghavendra Rao Ananta break; 39485fbe08eSRaghavendra Rao Ananta } 39585fbe08eSRaghavendra Rao Ananta 39685fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1: 39785fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3: 39885fbe08eSRaghavendra Rao Ananta if (val & ~KVM_REG_FEATURE_LEVEL_MASK) 39985fbe08eSRaghavendra Rao Ananta return -EINVAL; 40085fbe08eSRaghavendra Rao Ananta 40185fbe08eSRaghavendra Rao Ananta if (get_kernel_wa_level(reg->id) < val) 40285fbe08eSRaghavendra Rao Ananta return -EINVAL; 40385fbe08eSRaghavendra Rao Ananta 40485fbe08eSRaghavendra Rao Ananta return 0; 40585fbe08eSRaghavendra Rao Ananta 40685fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2: 40785fbe08eSRaghavendra Rao Ananta if (val & ~(KVM_REG_FEATURE_LEVEL_MASK | 40885fbe08eSRaghavendra Rao Ananta KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED)) 40985fbe08eSRaghavendra Rao Ananta return -EINVAL; 41085fbe08eSRaghavendra Rao Ananta 41185fbe08eSRaghavendra Rao Ananta /* The enabled bit must not be set unless the level is AVAIL. */ 41285fbe08eSRaghavendra Rao Ananta if ((val & KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED) && 41385fbe08eSRaghavendra Rao Ananta (val & KVM_REG_FEATURE_LEVEL_MASK) != KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL) 41485fbe08eSRaghavendra Rao Ananta return -EINVAL; 41585fbe08eSRaghavendra Rao Ananta 41685fbe08eSRaghavendra Rao Ananta /* 41785fbe08eSRaghavendra Rao Ananta * Map all the possible incoming states to the only two we 41885fbe08eSRaghavendra Rao Ananta * really want to deal with. 41985fbe08eSRaghavendra Rao Ananta */ 42085fbe08eSRaghavendra Rao Ananta switch (val & KVM_REG_FEATURE_LEVEL_MASK) { 42185fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL: 42285fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_UNKNOWN: 42385fbe08eSRaghavendra Rao Ananta wa_level = KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL; 42485fbe08eSRaghavendra Rao Ananta break; 42585fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL: 42685fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED: 42785fbe08eSRaghavendra Rao Ananta wa_level = KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED; 42885fbe08eSRaghavendra Rao Ananta break; 42985fbe08eSRaghavendra Rao Ananta default: 43085fbe08eSRaghavendra Rao Ananta return -EINVAL; 43185fbe08eSRaghavendra Rao Ananta } 43285fbe08eSRaghavendra Rao Ananta 43385fbe08eSRaghavendra Rao Ananta /* 43485fbe08eSRaghavendra Rao Ananta * We can deal with NOT_AVAIL on NOT_REQUIRED, but not the 43585fbe08eSRaghavendra Rao Ananta * other way around. 43685fbe08eSRaghavendra Rao Ananta */ 43785fbe08eSRaghavendra Rao Ananta if (get_kernel_wa_level(reg->id) < wa_level) 43885fbe08eSRaghavendra Rao Ananta return -EINVAL; 43985fbe08eSRaghavendra Rao Ananta 44085fbe08eSRaghavendra Rao Ananta return 0; 441*05714cabSRaghavendra Rao Ananta case KVM_REG_ARM_STD_BMAP: 442*05714cabSRaghavendra Rao Ananta return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val); 44385fbe08eSRaghavendra Rao Ananta default: 44485fbe08eSRaghavendra Rao Ananta return -ENOENT; 44585fbe08eSRaghavendra Rao Ananta } 44685fbe08eSRaghavendra Rao Ananta 44785fbe08eSRaghavendra Rao Ananta return -EINVAL; 44885fbe08eSRaghavendra Rao Ananta } 449