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 123bf72569SJianyong Wu static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val) 133bf72569SJianyong Wu { 143bf72569SJianyong Wu struct system_time_snapshot systime_snapshot; 153bf72569SJianyong Wu u64 cycles = ~0UL; 163bf72569SJianyong Wu u32 feature; 173bf72569SJianyong Wu 183bf72569SJianyong Wu /* 193bf72569SJianyong Wu * system time and counter value must captured at the same 203bf72569SJianyong Wu * time to keep consistency and precision. 213bf72569SJianyong Wu */ 223bf72569SJianyong Wu ktime_get_snapshot(&systime_snapshot); 233bf72569SJianyong Wu 243bf72569SJianyong Wu /* 253bf72569SJianyong Wu * This is only valid if the current clocksource is the 263bf72569SJianyong Wu * architected counter, as this is the only one the guest 273bf72569SJianyong Wu * can see. 283bf72569SJianyong Wu */ 293bf72569SJianyong Wu if (systime_snapshot.cs_id != CSID_ARM_ARCH_COUNTER) 303bf72569SJianyong Wu return; 313bf72569SJianyong Wu 323bf72569SJianyong Wu /* 333bf72569SJianyong Wu * The guest selects one of the two reference counters 343bf72569SJianyong Wu * (virtual or physical) with the first argument of the SMCCC 353bf72569SJianyong Wu * call. In case the identifier is not supported, error out. 363bf72569SJianyong Wu */ 373bf72569SJianyong Wu feature = smccc_get_arg1(vcpu); 383bf72569SJianyong Wu switch (feature) { 393bf72569SJianyong Wu case KVM_PTP_VIRT_COUNTER: 403bf72569SJianyong Wu cycles = systime_snapshot.cycles - vcpu_read_sys_reg(vcpu, CNTVOFF_EL2); 413bf72569SJianyong Wu break; 423bf72569SJianyong Wu case KVM_PTP_PHYS_COUNTER: 433bf72569SJianyong Wu cycles = systime_snapshot.cycles; 443bf72569SJianyong Wu break; 453bf72569SJianyong Wu default: 463bf72569SJianyong Wu return; 473bf72569SJianyong Wu } 483bf72569SJianyong Wu 493bf72569SJianyong Wu /* 503bf72569SJianyong Wu * This relies on the top bit of val[0] never being set for 513bf72569SJianyong Wu * valid values of system time, because that is *really* far 523bf72569SJianyong Wu * in the future (about 292 years from 1970, and at that stage 533bf72569SJianyong Wu * nobody will give a damn about it). 543bf72569SJianyong Wu */ 553bf72569SJianyong Wu val[0] = upper_32_bits(systime_snapshot.real); 563bf72569SJianyong Wu val[1] = lower_32_bits(systime_snapshot.real); 573bf72569SJianyong Wu val[2] = upper_32_bits(cycles); 583bf72569SJianyong Wu val[3] = lower_32_bits(cycles); 593bf72569SJianyong Wu } 603bf72569SJianyong Wu 619ed24f4bSMarc Zyngier int kvm_hvc_call_handler(struct kvm_vcpu *vcpu) 629ed24f4bSMarc Zyngier { 639ed24f4bSMarc Zyngier u32 func_id = smccc_get_function(vcpu); 64923961a7SWill Deacon u64 val[4] = {SMCCC_RET_NOT_SUPPORTED}; 659ed24f4bSMarc Zyngier u32 feature; 669ed24f4bSMarc Zyngier gpa_t gpa; 679ed24f4bSMarc Zyngier 689ed24f4bSMarc Zyngier switch (func_id) { 699ed24f4bSMarc Zyngier case ARM_SMCCC_VERSION_FUNC_ID: 70923961a7SWill Deacon val[0] = ARM_SMCCC_VERSION_1_1; 719ed24f4bSMarc Zyngier break; 729ed24f4bSMarc Zyngier case ARM_SMCCC_ARCH_FEATURES_FUNC_ID: 739ed24f4bSMarc Zyngier feature = smccc_get_arg1(vcpu); 749ed24f4bSMarc Zyngier switch (feature) { 759ed24f4bSMarc Zyngier case ARM_SMCCC_ARCH_WORKAROUND_1: 76d4647f0aSWill Deacon switch (arm64_get_spectre_v2_state()) { 77d4647f0aSWill Deacon case SPECTRE_VULNERABLE: 789ed24f4bSMarc Zyngier break; 79d4647f0aSWill Deacon case SPECTRE_MITIGATED: 80923961a7SWill Deacon val[0] = SMCCC_RET_SUCCESS; 819ed24f4bSMarc Zyngier break; 82d4647f0aSWill Deacon case SPECTRE_UNAFFECTED: 83923961a7SWill Deacon val[0] = SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED; 849ed24f4bSMarc Zyngier break; 859ed24f4bSMarc Zyngier } 869ed24f4bSMarc Zyngier break; 879ed24f4bSMarc Zyngier case ARM_SMCCC_ARCH_WORKAROUND_2: 88d63d975aSMarc Zyngier switch (arm64_get_spectre_v4_state()) { 89d63d975aSMarc Zyngier case SPECTRE_VULNERABLE: 909ed24f4bSMarc Zyngier break; 91d63d975aSMarc Zyngier case SPECTRE_MITIGATED: 92d63d975aSMarc Zyngier /* 93d63d975aSMarc Zyngier * SSBS everywhere: Indicate no firmware 94d63d975aSMarc Zyngier * support, as the SSBS support will be 95d63d975aSMarc Zyngier * indicated to the guest and the default is 96d63d975aSMarc Zyngier * safe. 97d63d975aSMarc Zyngier * 98d63d975aSMarc Zyngier * Otherwise, expose a permanent mitigation 99d63d975aSMarc Zyngier * to the guest, and hide SSBS so that the 100d63d975aSMarc Zyngier * guest stays protected. 101d63d975aSMarc Zyngier */ 102d63d975aSMarc Zyngier if (cpus_have_final_cap(ARM64_SSBS)) 103d63d975aSMarc Zyngier break; 104d63d975aSMarc Zyngier fallthrough; 105d63d975aSMarc Zyngier case SPECTRE_UNAFFECTED: 106923961a7SWill Deacon val[0] = SMCCC_RET_NOT_REQUIRED; 1079ed24f4bSMarc Zyngier break; 1089ed24f4bSMarc Zyngier } 1099ed24f4bSMarc Zyngier break; 110a5905d6aSJames Morse case ARM_SMCCC_ARCH_WORKAROUND_3: 111a5905d6aSJames Morse switch (arm64_get_spectre_bhb_state()) { 112a5905d6aSJames Morse case SPECTRE_VULNERABLE: 113a5905d6aSJames Morse break; 114a5905d6aSJames Morse case SPECTRE_MITIGATED: 115a5905d6aSJames Morse val[0] = SMCCC_RET_SUCCESS; 116a5905d6aSJames Morse break; 117a5905d6aSJames Morse case SPECTRE_UNAFFECTED: 118a5905d6aSJames Morse val[0] = SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED; 119a5905d6aSJames Morse break; 120a5905d6aSJames Morse } 121a5905d6aSJames Morse break; 1229ed24f4bSMarc Zyngier case ARM_SMCCC_HV_PV_TIME_FEATURES: 123923961a7SWill Deacon val[0] = SMCCC_RET_SUCCESS; 1249ed24f4bSMarc Zyngier break; 1259ed24f4bSMarc Zyngier } 1269ed24f4bSMarc Zyngier break; 1279ed24f4bSMarc Zyngier case ARM_SMCCC_HV_PV_TIME_FEATURES: 128923961a7SWill Deacon val[0] = kvm_hypercall_pv_features(vcpu); 1299ed24f4bSMarc Zyngier break; 1309ed24f4bSMarc Zyngier case ARM_SMCCC_HV_PV_TIME_ST: 1319ed24f4bSMarc Zyngier gpa = kvm_init_stolen_time(vcpu); 1329ed24f4bSMarc Zyngier if (gpa != GPA_INVALID) 133923961a7SWill Deacon val[0] = gpa; 134923961a7SWill Deacon break; 135923961a7SWill Deacon case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID: 136923961a7SWill Deacon val[0] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_0; 137923961a7SWill Deacon val[1] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_1; 138923961a7SWill Deacon val[2] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_2; 139923961a7SWill Deacon val[3] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_3; 140923961a7SWill Deacon break; 141923961a7SWill Deacon case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID: 142923961a7SWill Deacon val[0] = BIT(ARM_SMCCC_KVM_FUNC_FEATURES); 1433bf72569SJianyong Wu val[0] |= BIT(ARM_SMCCC_KVM_FUNC_PTP); 1443bf72569SJianyong Wu break; 1453bf72569SJianyong Wu case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID: 1463bf72569SJianyong Wu kvm_ptp_get_time(vcpu, val); 1479ed24f4bSMarc Zyngier break; 148a8e190cdSArd Biesheuvel case ARM_SMCCC_TRNG_VERSION: 149a8e190cdSArd Biesheuvel case ARM_SMCCC_TRNG_FEATURES: 150a8e190cdSArd Biesheuvel case ARM_SMCCC_TRNG_GET_UUID: 151a8e190cdSArd Biesheuvel case ARM_SMCCC_TRNG_RND32: 152a8e190cdSArd Biesheuvel case ARM_SMCCC_TRNG_RND64: 153a8e190cdSArd Biesheuvel return kvm_trng_call(vcpu); 1549ed24f4bSMarc Zyngier default: 1559ed24f4bSMarc Zyngier return kvm_psci_call(vcpu); 1569ed24f4bSMarc Zyngier } 1579ed24f4bSMarc Zyngier 158923961a7SWill Deacon smccc_set_retval(vcpu, val[0], val[1], val[2], val[3]); 1599ed24f4bSMarc Zyngier return 1; 1609ed24f4bSMarc Zyngier } 161*85fbe08eSRaghavendra Rao Ananta 162*85fbe08eSRaghavendra Rao Ananta static const u64 kvm_arm_fw_reg_ids[] = { 163*85fbe08eSRaghavendra Rao Ananta KVM_REG_ARM_PSCI_VERSION, 164*85fbe08eSRaghavendra Rao Ananta KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1, 165*85fbe08eSRaghavendra Rao Ananta KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2, 166*85fbe08eSRaghavendra Rao Ananta KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3, 167*85fbe08eSRaghavendra Rao Ananta }; 168*85fbe08eSRaghavendra Rao Ananta 169*85fbe08eSRaghavendra Rao Ananta int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu) 170*85fbe08eSRaghavendra Rao Ananta { 171*85fbe08eSRaghavendra Rao Ananta return ARRAY_SIZE(kvm_arm_fw_reg_ids); 172*85fbe08eSRaghavendra Rao Ananta } 173*85fbe08eSRaghavendra Rao Ananta 174*85fbe08eSRaghavendra Rao Ananta int kvm_arm_copy_fw_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices) 175*85fbe08eSRaghavendra Rao Ananta { 176*85fbe08eSRaghavendra Rao Ananta int i; 177*85fbe08eSRaghavendra Rao Ananta 178*85fbe08eSRaghavendra Rao Ananta for (i = 0; i < ARRAY_SIZE(kvm_arm_fw_reg_ids); i++) { 179*85fbe08eSRaghavendra Rao Ananta if (put_user(kvm_arm_fw_reg_ids[i], uindices++)) 180*85fbe08eSRaghavendra Rao Ananta return -EFAULT; 181*85fbe08eSRaghavendra Rao Ananta } 182*85fbe08eSRaghavendra Rao Ananta 183*85fbe08eSRaghavendra Rao Ananta return 0; 184*85fbe08eSRaghavendra Rao Ananta } 185*85fbe08eSRaghavendra Rao Ananta 186*85fbe08eSRaghavendra Rao Ananta #define KVM_REG_FEATURE_LEVEL_MASK GENMASK(3, 0) 187*85fbe08eSRaghavendra Rao Ananta 188*85fbe08eSRaghavendra Rao Ananta /* 189*85fbe08eSRaghavendra Rao Ananta * Convert the workaround level into an easy-to-compare number, where higher 190*85fbe08eSRaghavendra Rao Ananta * values mean better protection. 191*85fbe08eSRaghavendra Rao Ananta */ 192*85fbe08eSRaghavendra Rao Ananta static int get_kernel_wa_level(u64 regid) 193*85fbe08eSRaghavendra Rao Ananta { 194*85fbe08eSRaghavendra Rao Ananta switch (regid) { 195*85fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1: 196*85fbe08eSRaghavendra Rao Ananta switch (arm64_get_spectre_v2_state()) { 197*85fbe08eSRaghavendra Rao Ananta case SPECTRE_VULNERABLE: 198*85fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL; 199*85fbe08eSRaghavendra Rao Ananta case SPECTRE_MITIGATED: 200*85fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_AVAIL; 201*85fbe08eSRaghavendra Rao Ananta case SPECTRE_UNAFFECTED: 202*85fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_REQUIRED; 203*85fbe08eSRaghavendra Rao Ananta } 204*85fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL; 205*85fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2: 206*85fbe08eSRaghavendra Rao Ananta switch (arm64_get_spectre_v4_state()) { 207*85fbe08eSRaghavendra Rao Ananta case SPECTRE_MITIGATED: 208*85fbe08eSRaghavendra Rao Ananta /* 209*85fbe08eSRaghavendra Rao Ananta * As for the hypercall discovery, we pretend we 210*85fbe08eSRaghavendra Rao Ananta * don't have any FW mitigation if SSBS is there at 211*85fbe08eSRaghavendra Rao Ananta * all times. 212*85fbe08eSRaghavendra Rao Ananta */ 213*85fbe08eSRaghavendra Rao Ananta if (cpus_have_final_cap(ARM64_SSBS)) 214*85fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL; 215*85fbe08eSRaghavendra Rao Ananta fallthrough; 216*85fbe08eSRaghavendra Rao Ananta case SPECTRE_UNAFFECTED: 217*85fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED; 218*85fbe08eSRaghavendra Rao Ananta case SPECTRE_VULNERABLE: 219*85fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL; 220*85fbe08eSRaghavendra Rao Ananta } 221*85fbe08eSRaghavendra Rao Ananta break; 222*85fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3: 223*85fbe08eSRaghavendra Rao Ananta switch (arm64_get_spectre_bhb_state()) { 224*85fbe08eSRaghavendra Rao Ananta case SPECTRE_VULNERABLE: 225*85fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL; 226*85fbe08eSRaghavendra Rao Ananta case SPECTRE_MITIGATED: 227*85fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_AVAIL; 228*85fbe08eSRaghavendra Rao Ananta case SPECTRE_UNAFFECTED: 229*85fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_REQUIRED; 230*85fbe08eSRaghavendra Rao Ananta } 231*85fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL; 232*85fbe08eSRaghavendra Rao Ananta } 233*85fbe08eSRaghavendra Rao Ananta 234*85fbe08eSRaghavendra Rao Ananta return -EINVAL; 235*85fbe08eSRaghavendra Rao Ananta } 236*85fbe08eSRaghavendra Rao Ananta 237*85fbe08eSRaghavendra Rao Ananta int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) 238*85fbe08eSRaghavendra Rao Ananta { 239*85fbe08eSRaghavendra Rao Ananta void __user *uaddr = (void __user *)(long)reg->addr; 240*85fbe08eSRaghavendra Rao Ananta u64 val; 241*85fbe08eSRaghavendra Rao Ananta 242*85fbe08eSRaghavendra Rao Ananta switch (reg->id) { 243*85fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_PSCI_VERSION: 244*85fbe08eSRaghavendra Rao Ananta val = kvm_psci_version(vcpu); 245*85fbe08eSRaghavendra Rao Ananta break; 246*85fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1: 247*85fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2: 248*85fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3: 249*85fbe08eSRaghavendra Rao Ananta val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK; 250*85fbe08eSRaghavendra Rao Ananta break; 251*85fbe08eSRaghavendra Rao Ananta default: 252*85fbe08eSRaghavendra Rao Ananta return -ENOENT; 253*85fbe08eSRaghavendra Rao Ananta } 254*85fbe08eSRaghavendra Rao Ananta 255*85fbe08eSRaghavendra Rao Ananta if (copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id))) 256*85fbe08eSRaghavendra Rao Ananta return -EFAULT; 257*85fbe08eSRaghavendra Rao Ananta 258*85fbe08eSRaghavendra Rao Ananta return 0; 259*85fbe08eSRaghavendra Rao Ananta } 260*85fbe08eSRaghavendra Rao Ananta 261*85fbe08eSRaghavendra Rao Ananta int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) 262*85fbe08eSRaghavendra Rao Ananta { 263*85fbe08eSRaghavendra Rao Ananta void __user *uaddr = (void __user *)(long)reg->addr; 264*85fbe08eSRaghavendra Rao Ananta u64 val; 265*85fbe08eSRaghavendra Rao Ananta int wa_level; 266*85fbe08eSRaghavendra Rao Ananta 267*85fbe08eSRaghavendra Rao Ananta if (copy_from_user(&val, uaddr, KVM_REG_SIZE(reg->id))) 268*85fbe08eSRaghavendra Rao Ananta return -EFAULT; 269*85fbe08eSRaghavendra Rao Ananta 270*85fbe08eSRaghavendra Rao Ananta switch (reg->id) { 271*85fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_PSCI_VERSION: 272*85fbe08eSRaghavendra Rao Ananta { 273*85fbe08eSRaghavendra Rao Ananta bool wants_02; 274*85fbe08eSRaghavendra Rao Ananta 275*85fbe08eSRaghavendra Rao Ananta wants_02 = test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features); 276*85fbe08eSRaghavendra Rao Ananta 277*85fbe08eSRaghavendra Rao Ananta switch (val) { 278*85fbe08eSRaghavendra Rao Ananta case KVM_ARM_PSCI_0_1: 279*85fbe08eSRaghavendra Rao Ananta if (wants_02) 280*85fbe08eSRaghavendra Rao Ananta return -EINVAL; 281*85fbe08eSRaghavendra Rao Ananta vcpu->kvm->arch.psci_version = val; 282*85fbe08eSRaghavendra Rao Ananta return 0; 283*85fbe08eSRaghavendra Rao Ananta case KVM_ARM_PSCI_0_2: 284*85fbe08eSRaghavendra Rao Ananta case KVM_ARM_PSCI_1_0: 285*85fbe08eSRaghavendra Rao Ananta case KVM_ARM_PSCI_1_1: 286*85fbe08eSRaghavendra Rao Ananta if (!wants_02) 287*85fbe08eSRaghavendra Rao Ananta return -EINVAL; 288*85fbe08eSRaghavendra Rao Ananta vcpu->kvm->arch.psci_version = val; 289*85fbe08eSRaghavendra Rao Ananta return 0; 290*85fbe08eSRaghavendra Rao Ananta } 291*85fbe08eSRaghavendra Rao Ananta break; 292*85fbe08eSRaghavendra Rao Ananta } 293*85fbe08eSRaghavendra Rao Ananta 294*85fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1: 295*85fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3: 296*85fbe08eSRaghavendra Rao Ananta if (val & ~KVM_REG_FEATURE_LEVEL_MASK) 297*85fbe08eSRaghavendra Rao Ananta return -EINVAL; 298*85fbe08eSRaghavendra Rao Ananta 299*85fbe08eSRaghavendra Rao Ananta if (get_kernel_wa_level(reg->id) < val) 300*85fbe08eSRaghavendra Rao Ananta return -EINVAL; 301*85fbe08eSRaghavendra Rao Ananta 302*85fbe08eSRaghavendra Rao Ananta return 0; 303*85fbe08eSRaghavendra Rao Ananta 304*85fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2: 305*85fbe08eSRaghavendra Rao Ananta if (val & ~(KVM_REG_FEATURE_LEVEL_MASK | 306*85fbe08eSRaghavendra Rao Ananta KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED)) 307*85fbe08eSRaghavendra Rao Ananta return -EINVAL; 308*85fbe08eSRaghavendra Rao Ananta 309*85fbe08eSRaghavendra Rao Ananta /* The enabled bit must not be set unless the level is AVAIL. */ 310*85fbe08eSRaghavendra Rao Ananta if ((val & KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED) && 311*85fbe08eSRaghavendra Rao Ananta (val & KVM_REG_FEATURE_LEVEL_MASK) != KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL) 312*85fbe08eSRaghavendra Rao Ananta return -EINVAL; 313*85fbe08eSRaghavendra Rao Ananta 314*85fbe08eSRaghavendra Rao Ananta /* 315*85fbe08eSRaghavendra Rao Ananta * Map all the possible incoming states to the only two we 316*85fbe08eSRaghavendra Rao Ananta * really want to deal with. 317*85fbe08eSRaghavendra Rao Ananta */ 318*85fbe08eSRaghavendra Rao Ananta switch (val & KVM_REG_FEATURE_LEVEL_MASK) { 319*85fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL: 320*85fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_UNKNOWN: 321*85fbe08eSRaghavendra Rao Ananta wa_level = KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL; 322*85fbe08eSRaghavendra Rao Ananta break; 323*85fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL: 324*85fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED: 325*85fbe08eSRaghavendra Rao Ananta wa_level = KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED; 326*85fbe08eSRaghavendra Rao Ananta break; 327*85fbe08eSRaghavendra Rao Ananta default: 328*85fbe08eSRaghavendra Rao Ananta return -EINVAL; 329*85fbe08eSRaghavendra Rao Ananta } 330*85fbe08eSRaghavendra Rao Ananta 331*85fbe08eSRaghavendra Rao Ananta /* 332*85fbe08eSRaghavendra Rao Ananta * We can deal with NOT_AVAIL on NOT_REQUIRED, but not the 333*85fbe08eSRaghavendra Rao Ananta * other way around. 334*85fbe08eSRaghavendra Rao Ananta */ 335*85fbe08eSRaghavendra Rao Ananta if (get_kernel_wa_level(reg->id) < wa_level) 336*85fbe08eSRaghavendra Rao Ananta return -EINVAL; 337*85fbe08eSRaghavendra Rao Ananta 338*85fbe08eSRaghavendra Rao Ananta return 0; 339*85fbe08eSRaghavendra Rao Ananta default: 340*85fbe08eSRaghavendra Rao Ananta return -ENOENT; 341*85fbe08eSRaghavendra Rao Ananta } 342*85fbe08eSRaghavendra Rao Ananta 343*85fbe08eSRaghavendra Rao Ananta return -EINVAL; 344*85fbe08eSRaghavendra Rao Ananta } 345