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 124fb88707dSOliver Upton #define SMCCC_ARCH_RANGE_BEGIN ARM_SMCCC_VERSION_FUNC_ID 125fb88707dSOliver Upton #define SMCCC_ARCH_RANGE_END \ 126fb88707dSOliver Upton ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ 127fb88707dSOliver Upton ARM_SMCCC_SMC_32, \ 128fb88707dSOliver Upton 0, ARM_SMCCC_FUNC_MASK) 129fb88707dSOliver Upton 130fb88707dSOliver Upton static void init_smccc_filter(struct kvm *kvm) 131fb88707dSOliver Upton { 132fb88707dSOliver Upton int r; 133fb88707dSOliver Upton 134fb88707dSOliver Upton mt_init(&kvm->arch.smccc_filter); 135fb88707dSOliver Upton 136fb88707dSOliver Upton /* 137fb88707dSOliver Upton * Prevent userspace from handling any SMCCC calls in the architecture 138fb88707dSOliver Upton * range, avoiding the risk of misrepresenting Spectre mitigation status 139fb88707dSOliver Upton * to the guest. 140fb88707dSOliver Upton */ 141fb88707dSOliver Upton r = mtree_insert_range(&kvm->arch.smccc_filter, 142fb88707dSOliver Upton SMCCC_ARCH_RANGE_BEGIN, SMCCC_ARCH_RANGE_END, 143fb88707dSOliver Upton xa_mk_value(KVM_SMCCC_FILTER_HANDLE), 144fb88707dSOliver Upton GFP_KERNEL_ACCOUNT); 145fb88707dSOliver Upton WARN_ON_ONCE(r); 146fb88707dSOliver Upton } 147fb88707dSOliver Upton 148fb88707dSOliver Upton static u8 kvm_smccc_filter_get_action(struct kvm *kvm, u32 func_id) 149fb88707dSOliver Upton { 150fb88707dSOliver Upton unsigned long idx = func_id; 151fb88707dSOliver Upton void *val; 152fb88707dSOliver Upton 153fb88707dSOliver Upton if (!test_bit(KVM_ARCH_FLAG_SMCCC_FILTER_CONFIGURED, &kvm->arch.flags)) 154fb88707dSOliver Upton return KVM_SMCCC_FILTER_HANDLE; 155fb88707dSOliver Upton 156fb88707dSOliver Upton /* 157fb88707dSOliver Upton * But where's the error handling, you say? 158fb88707dSOliver Upton * 159fb88707dSOliver Upton * mt_find() returns NULL if no entry was found, which just so happens 160fb88707dSOliver Upton * to match KVM_SMCCC_FILTER_HANDLE. 161fb88707dSOliver Upton */ 162fb88707dSOliver Upton val = mt_find(&kvm->arch.smccc_filter, &idx, idx); 163fb88707dSOliver Upton return xa_to_value(val); 164fb88707dSOliver Upton } 165fb88707dSOliver Upton 166a8308b3fSOliver Upton static u8 kvm_smccc_get_action(struct kvm_vcpu *vcpu, u32 func_id) 167a8308b3fSOliver Upton { 168fb88707dSOliver Upton /* 169fb88707dSOliver Upton * Intervening actions in the SMCCC filter take precedence over the 170fb88707dSOliver Upton * pseudo-firmware register bitmaps. 171fb88707dSOliver Upton */ 172fb88707dSOliver Upton u8 action = kvm_smccc_filter_get_action(vcpu->kvm, func_id); 173fb88707dSOliver Upton if (action != KVM_SMCCC_FILTER_HANDLE) 174fb88707dSOliver Upton return action; 175fb88707dSOliver 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 183*d824dff1SOliver Upton static void kvm_prepare_hypercall_exit(struct kvm_vcpu *vcpu, u32 func_id) 184*d824dff1SOliver Upton { 185*d824dff1SOliver Upton u8 ec = ESR_ELx_EC(kvm_vcpu_get_esr(vcpu)); 186*d824dff1SOliver Upton struct kvm_run *run = vcpu->run; 187*d824dff1SOliver Upton 188*d824dff1SOliver Upton run->exit_reason = KVM_EXIT_HYPERCALL; 189*d824dff1SOliver Upton run->hypercall.nr = func_id; 190*d824dff1SOliver Upton run->hypercall.flags = 0; 191*d824dff1SOliver Upton 192*d824dff1SOliver Upton if (ec == ESR_ELx_EC_SMC32 || ec == ESR_ELx_EC_SMC64) 193*d824dff1SOliver Upton run->hypercall.flags |= KVM_HYPERCALL_EXIT_SMC; 194*d824dff1SOliver Upton } 195*d824dff1SOliver Upton 196aac94968SOliver Upton int kvm_smccc_call_handler(struct kvm_vcpu *vcpu) 1979ed24f4bSMarc Zyngier { 198428fd678SRaghavendra Rao Ananta struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat; 1999ed24f4bSMarc Zyngier u32 func_id = smccc_get_function(vcpu); 200923961a7SWill Deacon u64 val[4] = {SMCCC_RET_NOT_SUPPORTED}; 2019ed24f4bSMarc Zyngier u32 feature; 202a8308b3fSOliver Upton u8 action; 2039ed24f4bSMarc Zyngier gpa_t gpa; 2049ed24f4bSMarc Zyngier 205a8308b3fSOliver Upton action = kvm_smccc_get_action(vcpu, func_id); 206a8308b3fSOliver Upton switch (action) { 207a8308b3fSOliver Upton case KVM_SMCCC_FILTER_HANDLE: 208a8308b3fSOliver Upton break; 209a8308b3fSOliver Upton case KVM_SMCCC_FILTER_DENY: 21005714cabSRaghavendra Rao Ananta goto out; 211*d824dff1SOliver Upton case KVM_SMCCC_FILTER_FWD_TO_USER: 212*d824dff1SOliver Upton kvm_prepare_hypercall_exit(vcpu, func_id); 213*d824dff1SOliver Upton return 0; 214a8308b3fSOliver Upton default: 215a8308b3fSOliver Upton WARN_RATELIMIT(1, "Unhandled SMCCC filter action: %d\n", action); 216a8308b3fSOliver Upton goto out; 217a8308b3fSOliver Upton } 21805714cabSRaghavendra Rao Ananta 2199ed24f4bSMarc Zyngier switch (func_id) { 2209ed24f4bSMarc Zyngier case ARM_SMCCC_VERSION_FUNC_ID: 221923961a7SWill Deacon val[0] = ARM_SMCCC_VERSION_1_1; 2229ed24f4bSMarc Zyngier break; 2239ed24f4bSMarc Zyngier case ARM_SMCCC_ARCH_FEATURES_FUNC_ID: 2249ed24f4bSMarc Zyngier feature = smccc_get_arg1(vcpu); 2259ed24f4bSMarc Zyngier switch (feature) { 2269ed24f4bSMarc Zyngier case ARM_SMCCC_ARCH_WORKAROUND_1: 227d4647f0aSWill Deacon switch (arm64_get_spectre_v2_state()) { 228d4647f0aSWill Deacon case SPECTRE_VULNERABLE: 2299ed24f4bSMarc Zyngier break; 230d4647f0aSWill Deacon case SPECTRE_MITIGATED: 231923961a7SWill Deacon val[0] = SMCCC_RET_SUCCESS; 2329ed24f4bSMarc Zyngier break; 233d4647f0aSWill Deacon case SPECTRE_UNAFFECTED: 234923961a7SWill Deacon val[0] = SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED; 2359ed24f4bSMarc Zyngier break; 2369ed24f4bSMarc Zyngier } 2379ed24f4bSMarc Zyngier break; 2389ed24f4bSMarc Zyngier case ARM_SMCCC_ARCH_WORKAROUND_2: 239d63d975aSMarc Zyngier switch (arm64_get_spectre_v4_state()) { 240d63d975aSMarc Zyngier case SPECTRE_VULNERABLE: 2419ed24f4bSMarc Zyngier break; 242d63d975aSMarc Zyngier case SPECTRE_MITIGATED: 243d63d975aSMarc Zyngier /* 244d63d975aSMarc Zyngier * SSBS everywhere: Indicate no firmware 245d63d975aSMarc Zyngier * support, as the SSBS support will be 246d63d975aSMarc Zyngier * indicated to the guest and the default is 247d63d975aSMarc Zyngier * safe. 248d63d975aSMarc Zyngier * 249d63d975aSMarc Zyngier * Otherwise, expose a permanent mitigation 250d63d975aSMarc Zyngier * to the guest, and hide SSBS so that the 251d63d975aSMarc Zyngier * guest stays protected. 252d63d975aSMarc Zyngier */ 253d63d975aSMarc Zyngier if (cpus_have_final_cap(ARM64_SSBS)) 254d63d975aSMarc Zyngier break; 255d63d975aSMarc Zyngier fallthrough; 256d63d975aSMarc Zyngier case SPECTRE_UNAFFECTED: 257923961a7SWill Deacon val[0] = SMCCC_RET_NOT_REQUIRED; 2589ed24f4bSMarc Zyngier break; 2599ed24f4bSMarc Zyngier } 2609ed24f4bSMarc Zyngier break; 261a5905d6aSJames Morse case ARM_SMCCC_ARCH_WORKAROUND_3: 262a5905d6aSJames Morse switch (arm64_get_spectre_bhb_state()) { 263a5905d6aSJames Morse case SPECTRE_VULNERABLE: 264a5905d6aSJames Morse break; 265a5905d6aSJames Morse case SPECTRE_MITIGATED: 266a5905d6aSJames Morse val[0] = SMCCC_RET_SUCCESS; 267a5905d6aSJames Morse break; 268a5905d6aSJames Morse case SPECTRE_UNAFFECTED: 269a5905d6aSJames Morse val[0] = SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED; 270a5905d6aSJames Morse break; 271a5905d6aSJames Morse } 272a5905d6aSJames Morse break; 2739ed24f4bSMarc Zyngier case ARM_SMCCC_HV_PV_TIME_FEATURES: 274428fd678SRaghavendra Rao Ananta if (test_bit(KVM_REG_ARM_STD_HYP_BIT_PV_TIME, 275428fd678SRaghavendra Rao Ananta &smccc_feat->std_hyp_bmap)) 276923961a7SWill Deacon val[0] = SMCCC_RET_SUCCESS; 2779ed24f4bSMarc Zyngier break; 2789ed24f4bSMarc Zyngier } 2799ed24f4bSMarc Zyngier break; 2809ed24f4bSMarc Zyngier case ARM_SMCCC_HV_PV_TIME_FEATURES: 281923961a7SWill Deacon val[0] = kvm_hypercall_pv_features(vcpu); 2829ed24f4bSMarc Zyngier break; 2839ed24f4bSMarc Zyngier case ARM_SMCCC_HV_PV_TIME_ST: 2849ed24f4bSMarc Zyngier gpa = kvm_init_stolen_time(vcpu); 285cecafc0aSYu Zhang if (gpa != INVALID_GPA) 286923961a7SWill Deacon val[0] = gpa; 287923961a7SWill Deacon break; 288923961a7SWill Deacon case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID: 289923961a7SWill Deacon val[0] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_0; 290923961a7SWill Deacon val[1] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_1; 291923961a7SWill Deacon val[2] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_2; 292923961a7SWill Deacon val[3] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_3; 293923961a7SWill Deacon break; 294923961a7SWill Deacon case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID: 295b22216e1SRaghavendra Rao Ananta val[0] = smccc_feat->vendor_hyp_bmap; 2963bf72569SJianyong Wu break; 2973bf72569SJianyong Wu case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID: 2983bf72569SJianyong Wu kvm_ptp_get_time(vcpu, val); 2999ed24f4bSMarc Zyngier break; 300a8e190cdSArd Biesheuvel case ARM_SMCCC_TRNG_VERSION: 301a8e190cdSArd Biesheuvel case ARM_SMCCC_TRNG_FEATURES: 302a8e190cdSArd Biesheuvel case ARM_SMCCC_TRNG_GET_UUID: 303a8e190cdSArd Biesheuvel case ARM_SMCCC_TRNG_RND32: 304a8e190cdSArd Biesheuvel case ARM_SMCCC_TRNG_RND64: 305a8e190cdSArd Biesheuvel return kvm_trng_call(vcpu); 3069ed24f4bSMarc Zyngier default: 3079ed24f4bSMarc Zyngier return kvm_psci_call(vcpu); 3089ed24f4bSMarc Zyngier } 3099ed24f4bSMarc Zyngier 31005714cabSRaghavendra Rao Ananta out: 311923961a7SWill Deacon smccc_set_retval(vcpu, val[0], val[1], val[2], val[3]); 3129ed24f4bSMarc Zyngier return 1; 3139ed24f4bSMarc Zyngier } 31485fbe08eSRaghavendra Rao Ananta 31585fbe08eSRaghavendra Rao Ananta static const u64 kvm_arm_fw_reg_ids[] = { 31685fbe08eSRaghavendra Rao Ananta KVM_REG_ARM_PSCI_VERSION, 31785fbe08eSRaghavendra Rao Ananta KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1, 31885fbe08eSRaghavendra Rao Ananta KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2, 31985fbe08eSRaghavendra Rao Ananta KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3, 32005714cabSRaghavendra Rao Ananta KVM_REG_ARM_STD_BMAP, 321428fd678SRaghavendra Rao Ananta KVM_REG_ARM_STD_HYP_BMAP, 322b22216e1SRaghavendra Rao Ananta KVM_REG_ARM_VENDOR_HYP_BMAP, 32385fbe08eSRaghavendra Rao Ananta }; 32485fbe08eSRaghavendra Rao Ananta 32505714cabSRaghavendra Rao Ananta void kvm_arm_init_hypercalls(struct kvm *kvm) 32605714cabSRaghavendra Rao Ananta { 32705714cabSRaghavendra Rao Ananta struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat; 32805714cabSRaghavendra Rao Ananta 32905714cabSRaghavendra Rao Ananta smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES; 330428fd678SRaghavendra Rao Ananta smccc_feat->std_hyp_bmap = KVM_ARM_SMCCC_STD_HYP_FEATURES; 331b22216e1SRaghavendra Rao Ananta smccc_feat->vendor_hyp_bmap = KVM_ARM_SMCCC_VENDOR_HYP_FEATURES; 332fb88707dSOliver Upton 333fb88707dSOliver Upton init_smccc_filter(kvm); 334fb88707dSOliver Upton } 335fb88707dSOliver Upton 336fb88707dSOliver Upton void kvm_arm_teardown_hypercalls(struct kvm *kvm) 337fb88707dSOliver Upton { 338fb88707dSOliver Upton mtree_destroy(&kvm->arch.smccc_filter); 33905714cabSRaghavendra Rao Ananta } 34005714cabSRaghavendra Rao Ananta 34185fbe08eSRaghavendra Rao Ananta int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu) 34285fbe08eSRaghavendra Rao Ananta { 34385fbe08eSRaghavendra Rao Ananta return ARRAY_SIZE(kvm_arm_fw_reg_ids); 34485fbe08eSRaghavendra Rao Ananta } 34585fbe08eSRaghavendra Rao Ananta 34685fbe08eSRaghavendra Rao Ananta int kvm_arm_copy_fw_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices) 34785fbe08eSRaghavendra Rao Ananta { 34885fbe08eSRaghavendra Rao Ananta int i; 34985fbe08eSRaghavendra Rao Ananta 35085fbe08eSRaghavendra Rao Ananta for (i = 0; i < ARRAY_SIZE(kvm_arm_fw_reg_ids); i++) { 35185fbe08eSRaghavendra Rao Ananta if (put_user(kvm_arm_fw_reg_ids[i], uindices++)) 35285fbe08eSRaghavendra Rao Ananta return -EFAULT; 35385fbe08eSRaghavendra Rao Ananta } 35485fbe08eSRaghavendra Rao Ananta 35585fbe08eSRaghavendra Rao Ananta return 0; 35685fbe08eSRaghavendra Rao Ananta } 35785fbe08eSRaghavendra Rao Ananta 35885fbe08eSRaghavendra Rao Ananta #define KVM_REG_FEATURE_LEVEL_MASK GENMASK(3, 0) 35985fbe08eSRaghavendra Rao Ananta 36085fbe08eSRaghavendra Rao Ananta /* 36185fbe08eSRaghavendra Rao Ananta * Convert the workaround level into an easy-to-compare number, where higher 36285fbe08eSRaghavendra Rao Ananta * values mean better protection. 36385fbe08eSRaghavendra Rao Ananta */ 36485fbe08eSRaghavendra Rao Ananta static int get_kernel_wa_level(u64 regid) 36585fbe08eSRaghavendra Rao Ananta { 36685fbe08eSRaghavendra Rao Ananta switch (regid) { 36785fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1: 36885fbe08eSRaghavendra Rao Ananta switch (arm64_get_spectre_v2_state()) { 36985fbe08eSRaghavendra Rao Ananta case SPECTRE_VULNERABLE: 37085fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL; 37185fbe08eSRaghavendra Rao Ananta case SPECTRE_MITIGATED: 37285fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_AVAIL; 37385fbe08eSRaghavendra Rao Ananta case SPECTRE_UNAFFECTED: 37485fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_REQUIRED; 37585fbe08eSRaghavendra Rao Ananta } 37685fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL; 37785fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2: 37885fbe08eSRaghavendra Rao Ananta switch (arm64_get_spectre_v4_state()) { 37985fbe08eSRaghavendra Rao Ananta case SPECTRE_MITIGATED: 38085fbe08eSRaghavendra Rao Ananta /* 38185fbe08eSRaghavendra Rao Ananta * As for the hypercall discovery, we pretend we 38285fbe08eSRaghavendra Rao Ananta * don't have any FW mitigation if SSBS is there at 38385fbe08eSRaghavendra Rao Ananta * all times. 38485fbe08eSRaghavendra Rao Ananta */ 38585fbe08eSRaghavendra Rao Ananta if (cpus_have_final_cap(ARM64_SSBS)) 38685fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL; 38785fbe08eSRaghavendra Rao Ananta fallthrough; 38885fbe08eSRaghavendra Rao Ananta case SPECTRE_UNAFFECTED: 38985fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED; 39085fbe08eSRaghavendra Rao Ananta case SPECTRE_VULNERABLE: 39185fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL; 39285fbe08eSRaghavendra Rao Ananta } 39385fbe08eSRaghavendra Rao Ananta break; 39485fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3: 39585fbe08eSRaghavendra Rao Ananta switch (arm64_get_spectre_bhb_state()) { 39685fbe08eSRaghavendra Rao Ananta case SPECTRE_VULNERABLE: 39785fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL; 39885fbe08eSRaghavendra Rao Ananta case SPECTRE_MITIGATED: 39985fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_AVAIL; 40085fbe08eSRaghavendra Rao Ananta case SPECTRE_UNAFFECTED: 40185fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_REQUIRED; 40285fbe08eSRaghavendra Rao Ananta } 40385fbe08eSRaghavendra Rao Ananta return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL; 40485fbe08eSRaghavendra Rao Ananta } 40585fbe08eSRaghavendra Rao Ananta 40685fbe08eSRaghavendra Rao Ananta return -EINVAL; 40785fbe08eSRaghavendra Rao Ananta } 40885fbe08eSRaghavendra Rao Ananta 40985fbe08eSRaghavendra Rao Ananta int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) 41085fbe08eSRaghavendra Rao Ananta { 41105714cabSRaghavendra Rao Ananta struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat; 41285fbe08eSRaghavendra Rao Ananta void __user *uaddr = (void __user *)(long)reg->addr; 41385fbe08eSRaghavendra Rao Ananta u64 val; 41485fbe08eSRaghavendra Rao Ananta 41585fbe08eSRaghavendra Rao Ananta switch (reg->id) { 41685fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_PSCI_VERSION: 41785fbe08eSRaghavendra Rao Ananta val = kvm_psci_version(vcpu); 41885fbe08eSRaghavendra Rao Ananta break; 41985fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1: 42085fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2: 42185fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3: 42285fbe08eSRaghavendra Rao Ananta val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK; 42385fbe08eSRaghavendra Rao Ananta break; 42405714cabSRaghavendra Rao Ananta case KVM_REG_ARM_STD_BMAP: 42505714cabSRaghavendra Rao Ananta val = READ_ONCE(smccc_feat->std_bmap); 42605714cabSRaghavendra Rao Ananta break; 427428fd678SRaghavendra Rao Ananta case KVM_REG_ARM_STD_HYP_BMAP: 428428fd678SRaghavendra Rao Ananta val = READ_ONCE(smccc_feat->std_hyp_bmap); 429428fd678SRaghavendra Rao Ananta break; 430b22216e1SRaghavendra Rao Ananta case KVM_REG_ARM_VENDOR_HYP_BMAP: 431b22216e1SRaghavendra Rao Ananta val = READ_ONCE(smccc_feat->vendor_hyp_bmap); 432b22216e1SRaghavendra Rao Ananta break; 43385fbe08eSRaghavendra Rao Ananta default: 43485fbe08eSRaghavendra Rao Ananta return -ENOENT; 43585fbe08eSRaghavendra Rao Ananta } 43685fbe08eSRaghavendra Rao Ananta 43785fbe08eSRaghavendra Rao Ananta if (copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id))) 43885fbe08eSRaghavendra Rao Ananta return -EFAULT; 43985fbe08eSRaghavendra Rao Ananta 44085fbe08eSRaghavendra Rao Ananta return 0; 44185fbe08eSRaghavendra Rao Ananta } 44285fbe08eSRaghavendra Rao Ananta 44305714cabSRaghavendra Rao Ananta static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val) 44405714cabSRaghavendra Rao Ananta { 44505714cabSRaghavendra Rao Ananta int ret = 0; 44605714cabSRaghavendra Rao Ananta struct kvm *kvm = vcpu->kvm; 44705714cabSRaghavendra Rao Ananta struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat; 44805714cabSRaghavendra Rao Ananta unsigned long *fw_reg_bmap, fw_reg_features; 44905714cabSRaghavendra Rao Ananta 45005714cabSRaghavendra Rao Ananta switch (reg_id) { 45105714cabSRaghavendra Rao Ananta case KVM_REG_ARM_STD_BMAP: 45205714cabSRaghavendra Rao Ananta fw_reg_bmap = &smccc_feat->std_bmap; 45305714cabSRaghavendra Rao Ananta fw_reg_features = KVM_ARM_SMCCC_STD_FEATURES; 45405714cabSRaghavendra Rao Ananta break; 455428fd678SRaghavendra Rao Ananta case KVM_REG_ARM_STD_HYP_BMAP: 456428fd678SRaghavendra Rao Ananta fw_reg_bmap = &smccc_feat->std_hyp_bmap; 457428fd678SRaghavendra Rao Ananta fw_reg_features = KVM_ARM_SMCCC_STD_HYP_FEATURES; 458428fd678SRaghavendra Rao Ananta break; 459b22216e1SRaghavendra Rao Ananta case KVM_REG_ARM_VENDOR_HYP_BMAP: 460b22216e1SRaghavendra Rao Ananta fw_reg_bmap = &smccc_feat->vendor_hyp_bmap; 461b22216e1SRaghavendra Rao Ananta fw_reg_features = KVM_ARM_SMCCC_VENDOR_HYP_FEATURES; 462b22216e1SRaghavendra Rao Ananta break; 46305714cabSRaghavendra Rao Ananta default: 46405714cabSRaghavendra Rao Ananta return -ENOENT; 46505714cabSRaghavendra Rao Ananta } 46605714cabSRaghavendra Rao Ananta 46705714cabSRaghavendra Rao Ananta /* Check for unsupported bit */ 46805714cabSRaghavendra Rao Ananta if (val & ~fw_reg_features) 46905714cabSRaghavendra Rao Ananta return -EINVAL; 47005714cabSRaghavendra Rao Ananta 47105714cabSRaghavendra Rao Ananta mutex_lock(&kvm->lock); 47205714cabSRaghavendra Rao Ananta 473de40bb8aSOliver Upton if (kvm_vm_has_ran_once(kvm) && val != *fw_reg_bmap) { 47405714cabSRaghavendra Rao Ananta ret = -EBUSY; 47505714cabSRaghavendra Rao Ananta goto out; 47605714cabSRaghavendra Rao Ananta } 47705714cabSRaghavendra Rao Ananta 47805714cabSRaghavendra Rao Ananta WRITE_ONCE(*fw_reg_bmap, val); 47905714cabSRaghavendra Rao Ananta out: 48005714cabSRaghavendra Rao Ananta mutex_unlock(&kvm->lock); 48105714cabSRaghavendra Rao Ananta return ret; 48205714cabSRaghavendra Rao Ananta } 48305714cabSRaghavendra Rao Ananta 48485fbe08eSRaghavendra Rao Ananta int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) 48585fbe08eSRaghavendra Rao Ananta { 48685fbe08eSRaghavendra Rao Ananta void __user *uaddr = (void __user *)(long)reg->addr; 48785fbe08eSRaghavendra Rao Ananta u64 val; 48885fbe08eSRaghavendra Rao Ananta int wa_level; 48985fbe08eSRaghavendra Rao Ananta 49085fbe08eSRaghavendra Rao Ananta if (copy_from_user(&val, uaddr, KVM_REG_SIZE(reg->id))) 49185fbe08eSRaghavendra Rao Ananta return -EFAULT; 49285fbe08eSRaghavendra Rao Ananta 49385fbe08eSRaghavendra Rao Ananta switch (reg->id) { 49485fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_PSCI_VERSION: 49585fbe08eSRaghavendra Rao Ananta { 49685fbe08eSRaghavendra Rao Ananta bool wants_02; 49785fbe08eSRaghavendra Rao Ananta 49885fbe08eSRaghavendra Rao Ananta wants_02 = test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features); 49985fbe08eSRaghavendra Rao Ananta 50085fbe08eSRaghavendra Rao Ananta switch (val) { 50185fbe08eSRaghavendra Rao Ananta case KVM_ARM_PSCI_0_1: 50285fbe08eSRaghavendra Rao Ananta if (wants_02) 50385fbe08eSRaghavendra Rao Ananta return -EINVAL; 50485fbe08eSRaghavendra Rao Ananta vcpu->kvm->arch.psci_version = val; 50585fbe08eSRaghavendra Rao Ananta return 0; 50685fbe08eSRaghavendra Rao Ananta case KVM_ARM_PSCI_0_2: 50785fbe08eSRaghavendra Rao Ananta case KVM_ARM_PSCI_1_0: 50885fbe08eSRaghavendra Rao Ananta case KVM_ARM_PSCI_1_1: 50985fbe08eSRaghavendra Rao Ananta if (!wants_02) 51085fbe08eSRaghavendra Rao Ananta return -EINVAL; 51185fbe08eSRaghavendra Rao Ananta vcpu->kvm->arch.psci_version = val; 51285fbe08eSRaghavendra Rao Ananta return 0; 51385fbe08eSRaghavendra Rao Ananta } 51485fbe08eSRaghavendra Rao Ananta break; 51585fbe08eSRaghavendra Rao Ananta } 51685fbe08eSRaghavendra Rao Ananta 51785fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1: 51885fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3: 51985fbe08eSRaghavendra Rao Ananta if (val & ~KVM_REG_FEATURE_LEVEL_MASK) 52085fbe08eSRaghavendra Rao Ananta return -EINVAL; 52185fbe08eSRaghavendra Rao Ananta 52285fbe08eSRaghavendra Rao Ananta if (get_kernel_wa_level(reg->id) < val) 52385fbe08eSRaghavendra Rao Ananta return -EINVAL; 52485fbe08eSRaghavendra Rao Ananta 52585fbe08eSRaghavendra Rao Ananta return 0; 52685fbe08eSRaghavendra Rao Ananta 52785fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2: 52885fbe08eSRaghavendra Rao Ananta if (val & ~(KVM_REG_FEATURE_LEVEL_MASK | 52985fbe08eSRaghavendra Rao Ananta KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED)) 53085fbe08eSRaghavendra Rao Ananta return -EINVAL; 53185fbe08eSRaghavendra Rao Ananta 53285fbe08eSRaghavendra Rao Ananta /* The enabled bit must not be set unless the level is AVAIL. */ 53385fbe08eSRaghavendra Rao Ananta if ((val & KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED) && 53485fbe08eSRaghavendra Rao Ananta (val & KVM_REG_FEATURE_LEVEL_MASK) != KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL) 53585fbe08eSRaghavendra Rao Ananta return -EINVAL; 53685fbe08eSRaghavendra Rao Ananta 53785fbe08eSRaghavendra Rao Ananta /* 53885fbe08eSRaghavendra Rao Ananta * Map all the possible incoming states to the only two we 53985fbe08eSRaghavendra Rao Ananta * really want to deal with. 54085fbe08eSRaghavendra Rao Ananta */ 54185fbe08eSRaghavendra Rao Ananta switch (val & KVM_REG_FEATURE_LEVEL_MASK) { 54285fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL: 54385fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_UNKNOWN: 54485fbe08eSRaghavendra Rao Ananta wa_level = KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL; 54585fbe08eSRaghavendra Rao Ananta break; 54685fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL: 54785fbe08eSRaghavendra Rao Ananta case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED: 54885fbe08eSRaghavendra Rao Ananta wa_level = KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED; 54985fbe08eSRaghavendra Rao Ananta break; 55085fbe08eSRaghavendra Rao Ananta default: 55185fbe08eSRaghavendra Rao Ananta return -EINVAL; 55285fbe08eSRaghavendra Rao Ananta } 55385fbe08eSRaghavendra Rao Ananta 55485fbe08eSRaghavendra Rao Ananta /* 55585fbe08eSRaghavendra Rao Ananta * We can deal with NOT_AVAIL on NOT_REQUIRED, but not the 55685fbe08eSRaghavendra Rao Ananta * other way around. 55785fbe08eSRaghavendra Rao Ananta */ 55885fbe08eSRaghavendra Rao Ananta if (get_kernel_wa_level(reg->id) < wa_level) 55985fbe08eSRaghavendra Rao Ananta return -EINVAL; 56085fbe08eSRaghavendra Rao Ananta 56185fbe08eSRaghavendra Rao Ananta return 0; 56205714cabSRaghavendra Rao Ananta case KVM_REG_ARM_STD_BMAP: 563428fd678SRaghavendra Rao Ananta case KVM_REG_ARM_STD_HYP_BMAP: 564b22216e1SRaghavendra Rao Ananta case KVM_REG_ARM_VENDOR_HYP_BMAP: 56505714cabSRaghavendra Rao Ananta return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val); 56685fbe08eSRaghavendra Rao Ananta default: 56785fbe08eSRaghavendra Rao Ananta return -ENOENT; 56885fbe08eSRaghavendra Rao Ananta } 56985fbe08eSRaghavendra Rao Ananta 57085fbe08eSRaghavendra Rao Ananta return -EINVAL; 57185fbe08eSRaghavendra Rao Ananta } 572