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 68a8308b3fSOliver Upton static bool kvm_smccc_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 96a8308b3fSOliver Upton static bool kvm_smccc_test_fw_bmap(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: 120a8308b3fSOliver Upton return false; 12105714cabSRaghavendra Rao Ananta } 12205714cabSRaghavendra Rao Ananta } 12305714cabSRaghavendra Rao Ananta 124*fb88707dSOliver Upton #define SMCCC_ARCH_RANGE_BEGIN ARM_SMCCC_VERSION_FUNC_ID 125*fb88707dSOliver Upton #define SMCCC_ARCH_RANGE_END \ 126*fb88707dSOliver Upton ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ 127*fb88707dSOliver Upton ARM_SMCCC_SMC_32, \ 128*fb88707dSOliver Upton 0, ARM_SMCCC_FUNC_MASK) 129*fb88707dSOliver Upton 130*fb88707dSOliver Upton static void init_smccc_filter(struct kvm *kvm) 131*fb88707dSOliver Upton { 132*fb88707dSOliver Upton int r; 133*fb88707dSOliver Upton 134*fb88707dSOliver Upton mt_init(&kvm->arch.smccc_filter); 135*fb88707dSOliver Upton 136*fb88707dSOliver Upton /* 137*fb88707dSOliver Upton * Prevent userspace from handling any SMCCC calls in the architecture 138*fb88707dSOliver Upton * range, avoiding the risk of misrepresenting Spectre mitigation status 139*fb88707dSOliver Upton * to the guest. 140*fb88707dSOliver Upton */ 141*fb88707dSOliver Upton r = mtree_insert_range(&kvm->arch.smccc_filter, 142*fb88707dSOliver Upton SMCCC_ARCH_RANGE_BEGIN, SMCCC_ARCH_RANGE_END, 143*fb88707dSOliver Upton xa_mk_value(KVM_SMCCC_FILTER_HANDLE), 144*fb88707dSOliver Upton GFP_KERNEL_ACCOUNT); 145*fb88707dSOliver Upton WARN_ON_ONCE(r); 146*fb88707dSOliver Upton } 147*fb88707dSOliver Upton 148*fb88707dSOliver Upton static u8 kvm_smccc_filter_get_action(struct kvm *kvm, u32 func_id) 149*fb88707dSOliver Upton { 150*fb88707dSOliver Upton unsigned long idx = func_id; 151*fb88707dSOliver Upton void *val; 152*fb88707dSOliver Upton 153*fb88707dSOliver Upton if (!test_bit(KVM_ARCH_FLAG_SMCCC_FILTER_CONFIGURED, &kvm->arch.flags)) 154*fb88707dSOliver Upton return KVM_SMCCC_FILTER_HANDLE; 155*fb88707dSOliver Upton 156*fb88707dSOliver Upton /* 157*fb88707dSOliver Upton * But where's the error handling, you say? 158*fb88707dSOliver Upton * 159*fb88707dSOliver Upton * mt_find() returns NULL if no entry was found, which just so happens 160*fb88707dSOliver Upton * to match KVM_SMCCC_FILTER_HANDLE. 161*fb88707dSOliver Upton */ 162*fb88707dSOliver Upton val = mt_find(&kvm->arch.smccc_filter, &idx, idx); 163*fb88707dSOliver Upton return xa_to_value(val); 164*fb88707dSOliver Upton } 165*fb88707dSOliver Upton 166a8308b3fSOliver Upton static u8 kvm_smccc_get_action(struct kvm_vcpu *vcpu, u32 func_id) 167a8308b3fSOliver Upton { 168*fb88707dSOliver Upton /* 169*fb88707dSOliver Upton * Intervening actions in the SMCCC filter take precedence over the 170*fb88707dSOliver Upton * pseudo-firmware register bitmaps. 171*fb88707dSOliver Upton */ 172*fb88707dSOliver Upton u8 action = kvm_smccc_filter_get_action(vcpu->kvm, func_id); 173*fb88707dSOliver Upton if (action != KVM_SMCCC_FILTER_HANDLE) 174*fb88707dSOliver Upton return action; 175*fb88707dSOliver Upton 176a8308b3fSOliver Upton if (kvm_smccc_test_fw_bmap(vcpu, func_id) || 177a8308b3fSOliver Upton kvm_smccc_default_allowed(func_id)) 178a8308b3fSOliver Upton return KVM_SMCCC_FILTER_HANDLE; 179a8308b3fSOliver Upton 180a8308b3fSOliver Upton return KVM_SMCCC_FILTER_DENY; 181a8308b3fSOliver Upton } 182a8308b3fSOliver Upton 183aac94968SOliver Upton int kvm_smccc_call_handler(struct kvm_vcpu *vcpu) 1849ed24f4bSMarc Zyngier { 185428fd678SRaghavendra Rao Ananta struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat; 1869ed24f4bSMarc Zyngier u32 func_id = smccc_get_function(vcpu); 187923961a7SWill Deacon u64 val[4] = {SMCCC_RET_NOT_SUPPORTED}; 1889ed24f4bSMarc Zyngier u32 feature; 189a8308b3fSOliver Upton u8 action; 1909ed24f4bSMarc Zyngier gpa_t gpa; 1919ed24f4bSMarc Zyngier 192a8308b3fSOliver Upton action = kvm_smccc_get_action(vcpu, func_id); 193a8308b3fSOliver Upton switch (action) { 194a8308b3fSOliver Upton case KVM_SMCCC_FILTER_HANDLE: 195a8308b3fSOliver Upton break; 196a8308b3fSOliver Upton case KVM_SMCCC_FILTER_DENY: 19705714cabSRaghavendra Rao Ananta goto out; 198a8308b3fSOliver Upton default: 199a8308b3fSOliver Upton WARN_RATELIMIT(1, "Unhandled SMCCC filter action: %d\n", action); 200a8308b3fSOliver Upton goto out; 201a8308b3fSOliver Upton } 20205714cabSRaghavendra Rao Ananta 2039ed24f4bSMarc Zyngier switch (func_id) { 2049ed24f4bSMarc Zyngier case ARM_SMCCC_VERSION_FUNC_ID: 205923961a7SWill Deacon val[0] = ARM_SMCCC_VERSION_1_1; 2069ed24f4bSMarc Zyngier break; 2079ed24f4bSMarc Zyngier case ARM_SMCCC_ARCH_FEATURES_FUNC_ID: 2089ed24f4bSMarc Zyngier feature = smccc_get_arg1(vcpu); 2099ed24f4bSMarc Zyngier switch (feature) { 2109ed24f4bSMarc Zyngier case ARM_SMCCC_ARCH_WORKAROUND_1: 211d4647f0aSWill Deacon switch (arm64_get_spectre_v2_state()) { 212d4647f0aSWill Deacon case SPECTRE_VULNERABLE: 2139ed24f4bSMarc Zyngier break; 214d4647f0aSWill Deacon case SPECTRE_MITIGATED: 215923961a7SWill Deacon val[0] = SMCCC_RET_SUCCESS; 2169ed24f4bSMarc Zyngier break; 217d4647f0aSWill Deacon case SPECTRE_UNAFFECTED: 218923961a7SWill Deacon val[0] = SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED; 2199ed24f4bSMarc Zyngier break; 2209ed24f4bSMarc Zyngier } 2219ed24f4bSMarc Zyngier break; 2229ed24f4bSMarc Zyngier case ARM_SMCCC_ARCH_WORKAROUND_2: 223d63d975aSMarc Zyngier switch (arm64_get_spectre_v4_state()) { 224d63d975aSMarc Zyngier case SPECTRE_VULNERABLE: 2259ed24f4bSMarc Zyngier break; 226d63d975aSMarc Zyngier case SPECTRE_MITIGATED: 227d63d975aSMarc Zyngier /* 228d63d975aSMarc Zyngier * SSBS everywhere: Indicate no firmware 229d63d975aSMarc Zyngier * support, as the SSBS support will be 230d63d975aSMarc Zyngier * indicated to the guest and the default is 231d63d975aSMarc Zyngier * safe. 232d63d975aSMarc Zyngier * 233d63d975aSMarc Zyngier * Otherwise, expose a permanent mitigation 234d63d975aSMarc Zyngier * to the guest, and hide SSBS so that the 235d63d975aSMarc Zyngier * guest stays protected. 236d63d975aSMarc Zyngier */ 237d63d975aSMarc Zyngier if (cpus_have_final_cap(ARM64_SSBS)) 238d63d975aSMarc Zyngier break; 239d63d975aSMarc Zyngier fallthrough; 240d63d975aSMarc Zyngier case SPECTRE_UNAFFECTED: 241923961a7SWill Deacon val[0] = SMCCC_RET_NOT_REQUIRED; 2429ed24f4bSMarc Zyngier break; 2439ed24f4bSMarc Zyngier } 2449ed24f4bSMarc Zyngier break; 245a5905d6aSJames Morse case ARM_SMCCC_ARCH_WORKAROUND_3: 246a5905d6aSJames Morse switch (arm64_get_spectre_bhb_state()) { 247a5905d6aSJames Morse case SPECTRE_VULNERABLE: 248a5905d6aSJames Morse break; 249a5905d6aSJames Morse case SPECTRE_MITIGATED: 250a5905d6aSJames Morse val[0] = SMCCC_RET_SUCCESS; 251a5905d6aSJames Morse break; 252a5905d6aSJames Morse case SPECTRE_UNAFFECTED: 253a5905d6aSJames Morse val[0] = SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED; 254a5905d6aSJames Morse break; 255a5905d6aSJames Morse } 256a5905d6aSJames Morse break; 2579ed24f4bSMarc Zyngier case ARM_SMCCC_HV_PV_TIME_FEATURES: 258428fd678SRaghavendra Rao Ananta if (test_bit(KVM_REG_ARM_STD_HYP_BIT_PV_TIME, 259428fd678SRaghavendra Rao Ananta &smccc_feat->std_hyp_bmap)) 260923961a7SWill Deacon val[0] = SMCCC_RET_SUCCESS; 2619ed24f4bSMarc Zyngier break; 2629ed24f4bSMarc Zyngier } 2639ed24f4bSMarc Zyngier break; 2649ed24f4bSMarc Zyngier case ARM_SMCCC_HV_PV_TIME_FEATURES: 265923961a7SWill Deacon val[0] = kvm_hypercall_pv_features(vcpu); 2669ed24f4bSMarc Zyngier break; 2679ed24f4bSMarc Zyngier case ARM_SMCCC_HV_PV_TIME_ST: 2689ed24f4bSMarc Zyngier gpa = kvm_init_stolen_time(vcpu); 269cecafc0aSYu Zhang if (gpa != INVALID_GPA) 270923961a7SWill Deacon val[0] = gpa; 271923961a7SWill Deacon break; 272923961a7SWill Deacon case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID: 273923961a7SWill Deacon val[0] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_0; 274923961a7SWill Deacon val[1] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_1; 275923961a7SWill Deacon val[2] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_2; 276923961a7SWill Deacon val[3] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_3; 277923961a7SWill Deacon break; 278923961a7SWill Deacon case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID: 279b22216e1SRaghavendra Rao Ananta val[0] = smccc_feat->vendor_hyp_bmap; 2803bf72569SJianyong Wu break; 2813bf72569SJianyong Wu case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID: 2823bf72569SJianyong Wu kvm_ptp_get_time(vcpu, val); 2839ed24f4bSMarc Zyngier break; 284a8e190cdSArd Biesheuvel case ARM_SMCCC_TRNG_VERSION: 285a8e190cdSArd Biesheuvel case ARM_SMCCC_TRNG_FEATURES: 286a8e190cdSArd Biesheuvel case ARM_SMCCC_TRNG_GET_UUID: 287a8e190cdSArd Biesheuvel case ARM_SMCCC_TRNG_RND32: 288a8e190cdSArd Biesheuvel case ARM_SMCCC_TRNG_RND64: 289a8e190cdSArd Biesheuvel return kvm_trng_call(vcpu); 2909ed24f4bSMarc Zyngier default: 2919ed24f4bSMarc Zyngier return kvm_psci_call(vcpu); 2929ed24f4bSMarc Zyngier } 2939ed24f4bSMarc Zyngier 29405714cabSRaghavendra Rao Ananta out: 295923961a7SWill Deacon smccc_set_retval(vcpu, val[0], val[1], val[2], val[3]); 2969ed24f4bSMarc Zyngier return 1; 2979ed24f4bSMarc Zyngier } 29885fbe08eSRaghavendra Rao Ananta 29985fbe08eSRaghavendra Rao Ananta static const u64 kvm_arm_fw_reg_ids[] = { 30085fbe08eSRaghavendra Rao Ananta KVM_REG_ARM_PSCI_VERSION, 30185fbe08eSRaghavendra Rao Ananta KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1, 30285fbe08eSRaghavendra Rao Ananta KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2, 30385fbe08eSRaghavendra Rao Ananta KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3, 30405714cabSRaghavendra Rao Ananta KVM_REG_ARM_STD_BMAP, 305428fd678SRaghavendra Rao Ananta KVM_REG_ARM_STD_HYP_BMAP, 306b22216e1SRaghavendra Rao Ananta KVM_REG_ARM_VENDOR_HYP_BMAP, 30785fbe08eSRaghavendra Rao Ananta }; 30885fbe08eSRaghavendra Rao Ananta 30905714cabSRaghavendra Rao Ananta void kvm_arm_init_hypercalls(struct kvm *kvm) 31005714cabSRaghavendra Rao Ananta { 31105714cabSRaghavendra Rao Ananta struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat; 31205714cabSRaghavendra Rao Ananta 31305714cabSRaghavendra Rao Ananta smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES; 314428fd678SRaghavendra Rao Ananta smccc_feat->std_hyp_bmap = KVM_ARM_SMCCC_STD_HYP_FEATURES; 315b22216e1SRaghavendra Rao Ananta smccc_feat->vendor_hyp_bmap = KVM_ARM_SMCCC_VENDOR_HYP_FEATURES; 316*fb88707dSOliver Upton 317*fb88707dSOliver Upton init_smccc_filter(kvm); 318*fb88707dSOliver Upton } 319*fb88707dSOliver Upton 320*fb88707dSOliver Upton void kvm_arm_teardown_hypercalls(struct kvm *kvm) 321*fb88707dSOliver Upton { 322*fb88707dSOliver Upton mtree_destroy(&kvm->arch.smccc_filter); 32305714cabSRaghavendra Rao Ananta } 32405714cabSRaghavendra Rao Ananta 32585fbe08eSRaghavendra Rao Ananta int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu) 32685fbe08eSRaghavendra Rao Ananta { 32785fbe08eSRaghavendra Rao Ananta return ARRAY_SIZE(kvm_arm_fw_reg_ids); 32885fbe08eSRaghavendra Rao Ananta } 32985fbe08eSRaghavendra Rao Ananta 33085fbe08eSRaghavendra Rao Ananta int kvm_arm_copy_fw_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices) 33185fbe08eSRaghavendra Rao Ananta { 33285fbe08eSRaghavendra Rao Ananta int i; 33385fbe08eSRaghavendra Rao Ananta 33485fbe08eSRaghavendra Rao Ananta for (i = 0; i < ARRAY_SIZE(kvm_arm_fw_reg_ids); i++) { 33585fbe08eSRaghavendra Rao Ananta if (put_user(kvm_arm_fw_reg_ids[i], uindices++)) 33685fbe08eSRaghavendra Rao Ananta return -EFAULT; 33785fbe08eSRaghavendra Rao Ananta } 33885fbe08eSRaghavendra Rao Ananta 33985fbe08eSRaghavendra Rao Ananta return 0; 34085fbe08eSRaghavendra Rao Ananta } 34185fbe08eSRaghavendra Rao Ananta 34285fbe08eSRaghavendra Rao Ananta #define KVM_REG_FEATURE_LEVEL_MASK GENMASK(3, 0) 34385fbe08eSRaghavendra Rao Ananta 34485fbe08eSRaghavendra Rao Ananta /* 34585fbe08eSRaghavendra Rao Ananta * Convert the workaround level into an easy-to-compare number, where higher 34685fbe08eSRaghavendra Rao Ananta * values mean better protection. 34785fbe08eSRaghavendra Rao Ananta */ 34885fbe08eSRaghavendra Rao Ananta static int get_kernel_wa_level(u64 regid) 34985fbe08eSRaghavendra Rao Ananta { 35085fbe08eSRaghavendra Rao Ananta switch (regid) { 35185fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1: 35285fbe08eSRaghavendra Rao Ananta switch (arm64_get_spectre_v2_state()) { 35385fbe08eSRaghavendra Rao Ananta case SPECTRE_VULNERABLE: 35485fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL; 35585fbe08eSRaghavendra Rao Ananta case SPECTRE_MITIGATED: 35685fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_AVAIL; 35785fbe08eSRaghavendra Rao Ananta case SPECTRE_UNAFFECTED: 35885fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_REQUIRED; 35985fbe08eSRaghavendra Rao Ananta } 36085fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL; 36185fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2: 36285fbe08eSRaghavendra Rao Ananta switch (arm64_get_spectre_v4_state()) { 36385fbe08eSRaghavendra Rao Ananta case SPECTRE_MITIGATED: 36485fbe08eSRaghavendra Rao Ananta /* 36585fbe08eSRaghavendra Rao Ananta * As for the hypercall discovery, we pretend we 36685fbe08eSRaghavendra Rao Ananta * don't have any FW mitigation if SSBS is there at 36785fbe08eSRaghavendra Rao Ananta * all times. 36885fbe08eSRaghavendra Rao Ananta */ 36985fbe08eSRaghavendra Rao Ananta if (cpus_have_final_cap(ARM64_SSBS)) 37085fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL; 37185fbe08eSRaghavendra Rao Ananta fallthrough; 37285fbe08eSRaghavendra Rao Ananta case SPECTRE_UNAFFECTED: 37385fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED; 37485fbe08eSRaghavendra Rao Ananta case SPECTRE_VULNERABLE: 37585fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL; 37685fbe08eSRaghavendra Rao Ananta } 37785fbe08eSRaghavendra Rao Ananta break; 37885fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3: 37985fbe08eSRaghavendra Rao Ananta switch (arm64_get_spectre_bhb_state()) { 38085fbe08eSRaghavendra Rao Ananta case SPECTRE_VULNERABLE: 38185fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL; 38285fbe08eSRaghavendra Rao Ananta case SPECTRE_MITIGATED: 38385fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_AVAIL; 38485fbe08eSRaghavendra Rao Ananta case SPECTRE_UNAFFECTED: 38585fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_REQUIRED; 38685fbe08eSRaghavendra Rao Ananta } 38785fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL; 38885fbe08eSRaghavendra Rao Ananta } 38985fbe08eSRaghavendra Rao Ananta 39085fbe08eSRaghavendra Rao Ananta return -EINVAL; 39185fbe08eSRaghavendra Rao Ananta } 39285fbe08eSRaghavendra Rao Ananta 39385fbe08eSRaghavendra Rao Ananta int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) 39485fbe08eSRaghavendra Rao Ananta { 39505714cabSRaghavendra Rao Ananta struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat; 39685fbe08eSRaghavendra Rao Ananta void __user *uaddr = (void __user *)(long)reg->addr; 39785fbe08eSRaghavendra Rao Ananta u64 val; 39885fbe08eSRaghavendra Rao Ananta 39985fbe08eSRaghavendra Rao Ananta switch (reg->id) { 40085fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_PSCI_VERSION: 40185fbe08eSRaghavendra Rao Ananta val = kvm_psci_version(vcpu); 40285fbe08eSRaghavendra Rao Ananta break; 40385fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1: 40485fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2: 40585fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3: 40685fbe08eSRaghavendra Rao Ananta val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK; 40785fbe08eSRaghavendra Rao Ananta break; 40805714cabSRaghavendra Rao Ananta case KVM_REG_ARM_STD_BMAP: 40905714cabSRaghavendra Rao Ananta val = READ_ONCE(smccc_feat->std_bmap); 41005714cabSRaghavendra Rao Ananta break; 411428fd678SRaghavendra Rao Ananta case KVM_REG_ARM_STD_HYP_BMAP: 412428fd678SRaghavendra Rao Ananta val = READ_ONCE(smccc_feat->std_hyp_bmap); 413428fd678SRaghavendra Rao Ananta break; 414b22216e1SRaghavendra Rao Ananta case KVM_REG_ARM_VENDOR_HYP_BMAP: 415b22216e1SRaghavendra Rao Ananta val = READ_ONCE(smccc_feat->vendor_hyp_bmap); 416b22216e1SRaghavendra Rao Ananta break; 41785fbe08eSRaghavendra Rao Ananta default: 41885fbe08eSRaghavendra Rao Ananta return -ENOENT; 41985fbe08eSRaghavendra Rao Ananta } 42085fbe08eSRaghavendra Rao Ananta 42185fbe08eSRaghavendra Rao Ananta if (copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id))) 42285fbe08eSRaghavendra Rao Ananta return -EFAULT; 42385fbe08eSRaghavendra Rao Ananta 42485fbe08eSRaghavendra Rao Ananta return 0; 42585fbe08eSRaghavendra Rao Ananta } 42685fbe08eSRaghavendra Rao Ananta 42705714cabSRaghavendra Rao Ananta static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val) 42805714cabSRaghavendra Rao Ananta { 42905714cabSRaghavendra Rao Ananta int ret = 0; 43005714cabSRaghavendra Rao Ananta struct kvm *kvm = vcpu->kvm; 43105714cabSRaghavendra Rao Ananta struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat; 43205714cabSRaghavendra Rao Ananta unsigned long *fw_reg_bmap, fw_reg_features; 43305714cabSRaghavendra Rao Ananta 43405714cabSRaghavendra Rao Ananta switch (reg_id) { 43505714cabSRaghavendra Rao Ananta case KVM_REG_ARM_STD_BMAP: 43605714cabSRaghavendra Rao Ananta fw_reg_bmap = &smccc_feat->std_bmap; 43705714cabSRaghavendra Rao Ananta fw_reg_features = KVM_ARM_SMCCC_STD_FEATURES; 43805714cabSRaghavendra Rao Ananta break; 439428fd678SRaghavendra Rao Ananta case KVM_REG_ARM_STD_HYP_BMAP: 440428fd678SRaghavendra Rao Ananta fw_reg_bmap = &smccc_feat->std_hyp_bmap; 441428fd678SRaghavendra Rao Ananta fw_reg_features = KVM_ARM_SMCCC_STD_HYP_FEATURES; 442428fd678SRaghavendra Rao Ananta break; 443b22216e1SRaghavendra Rao Ananta case KVM_REG_ARM_VENDOR_HYP_BMAP: 444b22216e1SRaghavendra Rao Ananta fw_reg_bmap = &smccc_feat->vendor_hyp_bmap; 445b22216e1SRaghavendra Rao Ananta fw_reg_features = KVM_ARM_SMCCC_VENDOR_HYP_FEATURES; 446b22216e1SRaghavendra Rao Ananta break; 44705714cabSRaghavendra Rao Ananta default: 44805714cabSRaghavendra Rao Ananta return -ENOENT; 44905714cabSRaghavendra Rao Ananta } 45005714cabSRaghavendra Rao Ananta 45105714cabSRaghavendra Rao Ananta /* Check for unsupported bit */ 45205714cabSRaghavendra Rao Ananta if (val & ~fw_reg_features) 45305714cabSRaghavendra Rao Ananta return -EINVAL; 45405714cabSRaghavendra Rao Ananta 45505714cabSRaghavendra Rao Ananta mutex_lock(&kvm->lock); 45605714cabSRaghavendra Rao Ananta 457de40bb8aSOliver Upton if (kvm_vm_has_ran_once(kvm) && val != *fw_reg_bmap) { 45805714cabSRaghavendra Rao Ananta ret = -EBUSY; 45905714cabSRaghavendra Rao Ananta goto out; 46005714cabSRaghavendra Rao Ananta } 46105714cabSRaghavendra Rao Ananta 46205714cabSRaghavendra Rao Ananta WRITE_ONCE(*fw_reg_bmap, val); 46305714cabSRaghavendra Rao Ananta out: 46405714cabSRaghavendra Rao Ananta mutex_unlock(&kvm->lock); 46505714cabSRaghavendra Rao Ananta return ret; 46605714cabSRaghavendra Rao Ananta } 46705714cabSRaghavendra Rao Ananta 46885fbe08eSRaghavendra Rao Ananta int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) 46985fbe08eSRaghavendra Rao Ananta { 47085fbe08eSRaghavendra Rao Ananta void __user *uaddr = (void __user *)(long)reg->addr; 47185fbe08eSRaghavendra Rao Ananta u64 val; 47285fbe08eSRaghavendra Rao Ananta int wa_level; 47385fbe08eSRaghavendra Rao Ananta 47485fbe08eSRaghavendra Rao Ananta if (copy_from_user(&val, uaddr, KVM_REG_SIZE(reg->id))) 47585fbe08eSRaghavendra Rao Ananta return -EFAULT; 47685fbe08eSRaghavendra Rao Ananta 47785fbe08eSRaghavendra Rao Ananta switch (reg->id) { 47885fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_PSCI_VERSION: 47985fbe08eSRaghavendra Rao Ananta { 48085fbe08eSRaghavendra Rao Ananta bool wants_02; 48185fbe08eSRaghavendra Rao Ananta 48285fbe08eSRaghavendra Rao Ananta wants_02 = test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features); 48385fbe08eSRaghavendra Rao Ananta 48485fbe08eSRaghavendra Rao Ananta switch (val) { 48585fbe08eSRaghavendra Rao Ananta case KVM_ARM_PSCI_0_1: 48685fbe08eSRaghavendra Rao Ananta if (wants_02) 48785fbe08eSRaghavendra Rao Ananta return -EINVAL; 48885fbe08eSRaghavendra Rao Ananta vcpu->kvm->arch.psci_version = val; 48985fbe08eSRaghavendra Rao Ananta return 0; 49085fbe08eSRaghavendra Rao Ananta case KVM_ARM_PSCI_0_2: 49185fbe08eSRaghavendra Rao Ananta case KVM_ARM_PSCI_1_0: 49285fbe08eSRaghavendra Rao Ananta case KVM_ARM_PSCI_1_1: 49385fbe08eSRaghavendra Rao Ananta if (!wants_02) 49485fbe08eSRaghavendra Rao Ananta return -EINVAL; 49585fbe08eSRaghavendra Rao Ananta vcpu->kvm->arch.psci_version = val; 49685fbe08eSRaghavendra Rao Ananta return 0; 49785fbe08eSRaghavendra Rao Ananta } 49885fbe08eSRaghavendra Rao Ananta break; 49985fbe08eSRaghavendra Rao Ananta } 50085fbe08eSRaghavendra Rao Ananta 50185fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1: 50285fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3: 50385fbe08eSRaghavendra Rao Ananta if (val & ~KVM_REG_FEATURE_LEVEL_MASK) 50485fbe08eSRaghavendra Rao Ananta return -EINVAL; 50585fbe08eSRaghavendra Rao Ananta 50685fbe08eSRaghavendra Rao Ananta if (get_kernel_wa_level(reg->id) < val) 50785fbe08eSRaghavendra Rao Ananta return -EINVAL; 50885fbe08eSRaghavendra Rao Ananta 50985fbe08eSRaghavendra Rao Ananta return 0; 51085fbe08eSRaghavendra Rao Ananta 51185fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2: 51285fbe08eSRaghavendra Rao Ananta if (val & ~(KVM_REG_FEATURE_LEVEL_MASK | 51385fbe08eSRaghavendra Rao Ananta KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED)) 51485fbe08eSRaghavendra Rao Ananta return -EINVAL; 51585fbe08eSRaghavendra Rao Ananta 51685fbe08eSRaghavendra Rao Ananta /* The enabled bit must not be set unless the level is AVAIL. */ 51785fbe08eSRaghavendra Rao Ananta if ((val & KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED) && 51885fbe08eSRaghavendra Rao Ananta (val & KVM_REG_FEATURE_LEVEL_MASK) != KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL) 51985fbe08eSRaghavendra Rao Ananta return -EINVAL; 52085fbe08eSRaghavendra Rao Ananta 52185fbe08eSRaghavendra Rao Ananta /* 52285fbe08eSRaghavendra Rao Ananta * Map all the possible incoming states to the only two we 52385fbe08eSRaghavendra Rao Ananta * really want to deal with. 52485fbe08eSRaghavendra Rao Ananta */ 52585fbe08eSRaghavendra Rao Ananta switch (val & KVM_REG_FEATURE_LEVEL_MASK) { 52685fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL: 52785fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_UNKNOWN: 52885fbe08eSRaghavendra Rao Ananta wa_level = KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL; 52985fbe08eSRaghavendra Rao Ananta break; 53085fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL: 53185fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED: 53285fbe08eSRaghavendra Rao Ananta wa_level = KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED; 53385fbe08eSRaghavendra Rao Ananta break; 53485fbe08eSRaghavendra Rao Ananta default: 53585fbe08eSRaghavendra Rao Ananta return -EINVAL; 53685fbe08eSRaghavendra Rao Ananta } 53785fbe08eSRaghavendra Rao Ananta 53885fbe08eSRaghavendra Rao Ananta /* 53985fbe08eSRaghavendra Rao Ananta * We can deal with NOT_AVAIL on NOT_REQUIRED, but not the 54085fbe08eSRaghavendra Rao Ananta * other way around. 54185fbe08eSRaghavendra Rao Ananta */ 54285fbe08eSRaghavendra Rao Ananta if (get_kernel_wa_level(reg->id) < wa_level) 54385fbe08eSRaghavendra Rao Ananta return -EINVAL; 54485fbe08eSRaghavendra Rao Ananta 54585fbe08eSRaghavendra Rao Ananta return 0; 54605714cabSRaghavendra Rao Ananta case KVM_REG_ARM_STD_BMAP: 547428fd678SRaghavendra Rao Ananta case KVM_REG_ARM_STD_HYP_BMAP: 548b22216e1SRaghavendra Rao Ananta case KVM_REG_ARM_VENDOR_HYP_BMAP: 54905714cabSRaghavendra Rao Ananta return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val); 55085fbe08eSRaghavendra Rao Ananta default: 55185fbe08eSRaghavendra Rao Ananta return -ENOENT; 55285fbe08eSRaghavendra Rao Ananta } 55385fbe08eSRaghavendra Rao Ananta 55485fbe08eSRaghavendra Rao Ananta return -EINVAL; 55585fbe08eSRaghavendra Rao Ananta } 556