xref: /openbmc/linux/arch/arm64/kvm/hypercalls.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
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 
kvm_ptp_get_time(struct kvm_vcpu * vcpu,u64 * val)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:
502b4825a8SMarc Zyngier 		cycles = systime_snapshot.cycles - vcpu->kvm->arch.timer_data.poffset;
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 
kvm_smccc_default_allowed(u32 func_id)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 
kvm_smccc_test_fw_bmap(struct kvm_vcpu * vcpu,u32 func_id)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 
1245a23ad65SOliver Upton #define SMC32_ARCH_RANGE_BEGIN	ARM_SMCCC_VERSION_FUNC_ID
1255a23ad65SOliver Upton #define SMC32_ARCH_RANGE_END	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,		\
126fb88707dSOliver Upton 						   ARM_SMCCC_SMC_32,		\
127fb88707dSOliver Upton 						   0, ARM_SMCCC_FUNC_MASK)
128fb88707dSOliver Upton 
1295a23ad65SOliver Upton #define SMC64_ARCH_RANGE_BEGIN	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,		\
1305a23ad65SOliver Upton 						   ARM_SMCCC_SMC_64,		\
1315a23ad65SOliver Upton 						   0, 0)
1325a23ad65SOliver Upton #define SMC64_ARCH_RANGE_END	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,		\
1335a23ad65SOliver Upton 						   ARM_SMCCC_SMC_64,		\
1345a23ad65SOliver Upton 						   0, ARM_SMCCC_FUNC_MASK)
1355a23ad65SOliver Upton 
init_smccc_filter(struct kvm * kvm)136fb88707dSOliver Upton static void init_smccc_filter(struct kvm *kvm)
137fb88707dSOliver Upton {
138fb88707dSOliver Upton 	int r;
139fb88707dSOliver Upton 
140fb88707dSOliver Upton 	mt_init(&kvm->arch.smccc_filter);
141fb88707dSOliver Upton 
142fb88707dSOliver Upton 	/*
143fb88707dSOliver Upton 	 * Prevent userspace from handling any SMCCC calls in the architecture
144fb88707dSOliver Upton 	 * range, avoiding the risk of misrepresenting Spectre mitigation status
145fb88707dSOliver Upton 	 * to the guest.
146fb88707dSOliver Upton 	 */
147fb88707dSOliver Upton 	r = mtree_insert_range(&kvm->arch.smccc_filter,
1485a23ad65SOliver Upton 			       SMC32_ARCH_RANGE_BEGIN, SMC32_ARCH_RANGE_END,
149fb88707dSOliver Upton 			       xa_mk_value(KVM_SMCCC_FILTER_HANDLE),
150fb88707dSOliver Upton 			       GFP_KERNEL_ACCOUNT);
151fb88707dSOliver Upton 	WARN_ON_ONCE(r);
1525a23ad65SOliver Upton 
1535a23ad65SOliver Upton 	r = mtree_insert_range(&kvm->arch.smccc_filter,
1545a23ad65SOliver Upton 			       SMC64_ARCH_RANGE_BEGIN, SMC64_ARCH_RANGE_END,
1555a23ad65SOliver Upton 			       xa_mk_value(KVM_SMCCC_FILTER_HANDLE),
1565a23ad65SOliver Upton 			       GFP_KERNEL_ACCOUNT);
1575a23ad65SOliver Upton 	WARN_ON_ONCE(r);
1585a23ad65SOliver Upton 
159fb88707dSOliver Upton }
160fb88707dSOliver Upton 
kvm_smccc_set_filter(struct kvm * kvm,struct kvm_smccc_filter __user * uaddr)161821d935cSOliver Upton static int kvm_smccc_set_filter(struct kvm *kvm, struct kvm_smccc_filter __user *uaddr)
162821d935cSOliver Upton {
163821d935cSOliver Upton 	const void *zero_page = page_to_virt(ZERO_PAGE(0));
164821d935cSOliver Upton 	struct kvm_smccc_filter filter;
165821d935cSOliver Upton 	u32 start, end;
166821d935cSOliver Upton 	int r;
167821d935cSOliver Upton 
168821d935cSOliver Upton 	if (copy_from_user(&filter, uaddr, sizeof(filter)))
169821d935cSOliver Upton 		return -EFAULT;
170821d935cSOliver Upton 
171821d935cSOliver Upton 	if (memcmp(filter.pad, zero_page, sizeof(filter.pad)))
172821d935cSOliver Upton 		return -EINVAL;
173821d935cSOliver Upton 
174821d935cSOliver Upton 	start = filter.base;
175821d935cSOliver Upton 	end = start + filter.nr_functions - 1;
176821d935cSOliver Upton 
177821d935cSOliver Upton 	if (end < start || filter.action >= NR_SMCCC_FILTER_ACTIONS)
178821d935cSOliver Upton 		return -EINVAL;
179821d935cSOliver Upton 
180*6dcf7316SMarc Zyngier 	mutex_lock(&kvm->arch.config_lock);
181821d935cSOliver Upton 
182821d935cSOliver Upton 	if (kvm_vm_has_ran_once(kvm)) {
183821d935cSOliver Upton 		r = -EBUSY;
184821d935cSOliver Upton 		goto out_unlock;
185821d935cSOliver Upton 	}
186821d935cSOliver Upton 
187821d935cSOliver Upton 	r = mtree_insert_range(&kvm->arch.smccc_filter, start, end,
188821d935cSOliver Upton 			       xa_mk_value(filter.action), GFP_KERNEL_ACCOUNT);
189821d935cSOliver Upton 	if (r)
190821d935cSOliver Upton 		goto out_unlock;
191821d935cSOliver Upton 
192821d935cSOliver Upton 	set_bit(KVM_ARCH_FLAG_SMCCC_FILTER_CONFIGURED, &kvm->arch.flags);
193821d935cSOliver Upton 
194821d935cSOliver Upton out_unlock:
195*6dcf7316SMarc Zyngier 	mutex_unlock(&kvm->arch.config_lock);
196821d935cSOliver Upton 	return r;
197821d935cSOliver Upton }
198821d935cSOliver Upton 
kvm_smccc_filter_get_action(struct kvm * kvm,u32 func_id)199fb88707dSOliver Upton static u8 kvm_smccc_filter_get_action(struct kvm *kvm, u32 func_id)
200fb88707dSOliver Upton {
201fb88707dSOliver Upton 	unsigned long idx = func_id;
202fb88707dSOliver Upton 	void *val;
203fb88707dSOliver Upton 
204fb88707dSOliver Upton 	if (!test_bit(KVM_ARCH_FLAG_SMCCC_FILTER_CONFIGURED, &kvm->arch.flags))
205fb88707dSOliver Upton 		return KVM_SMCCC_FILTER_HANDLE;
206fb88707dSOliver Upton 
207fb88707dSOliver Upton 	/*
208fb88707dSOliver Upton 	 * But where's the error handling, you say?
209fb88707dSOliver Upton 	 *
210fb88707dSOliver Upton 	 * mt_find() returns NULL if no entry was found, which just so happens
211fb88707dSOliver Upton 	 * to match KVM_SMCCC_FILTER_HANDLE.
212fb88707dSOliver Upton 	 */
213fb88707dSOliver Upton 	val = mt_find(&kvm->arch.smccc_filter, &idx, idx);
214fb88707dSOliver Upton 	return xa_to_value(val);
215fb88707dSOliver Upton }
216fb88707dSOliver Upton 
kvm_smccc_get_action(struct kvm_vcpu * vcpu,u32 func_id)217a8308b3fSOliver Upton static u8 kvm_smccc_get_action(struct kvm_vcpu *vcpu, u32 func_id)
218a8308b3fSOliver Upton {
219fb88707dSOliver Upton 	/*
220fb88707dSOliver Upton 	 * Intervening actions in the SMCCC filter take precedence over the
221fb88707dSOliver Upton 	 * pseudo-firmware register bitmaps.
222fb88707dSOliver Upton 	 */
223fb88707dSOliver Upton 	u8 action = kvm_smccc_filter_get_action(vcpu->kvm, func_id);
224fb88707dSOliver Upton 	if (action != KVM_SMCCC_FILTER_HANDLE)
225fb88707dSOliver Upton 		return action;
226fb88707dSOliver Upton 
227a8308b3fSOliver Upton 	if (kvm_smccc_test_fw_bmap(vcpu, func_id) ||
228a8308b3fSOliver Upton 	    kvm_smccc_default_allowed(func_id))
229a8308b3fSOliver Upton 		return KVM_SMCCC_FILTER_HANDLE;
230a8308b3fSOliver Upton 
231a8308b3fSOliver Upton 	return KVM_SMCCC_FILTER_DENY;
232a8308b3fSOliver Upton }
233a8308b3fSOliver Upton 
kvm_prepare_hypercall_exit(struct kvm_vcpu * vcpu,u32 func_id)234d824dff1SOliver Upton static void kvm_prepare_hypercall_exit(struct kvm_vcpu *vcpu, u32 func_id)
235d824dff1SOliver Upton {
236d824dff1SOliver Upton 	u8 ec = ESR_ELx_EC(kvm_vcpu_get_esr(vcpu));
237d824dff1SOliver Upton 	struct kvm_run *run = vcpu->run;
2380e5c9a9dSMarc Zyngier 	u64 flags = 0;
239d824dff1SOliver Upton 
240d824dff1SOliver Upton 	if (ec == ESR_ELx_EC_SMC32 || ec == ESR_ELx_EC_SMC64)
2410e5c9a9dSMarc Zyngier 		flags |= KVM_HYPERCALL_EXIT_SMC;
2420e5c9a9dSMarc Zyngier 
2430e5c9a9dSMarc Zyngier 	if (!kvm_vcpu_trap_il_is32bit(vcpu))
2440e5c9a9dSMarc Zyngier 		flags |= KVM_HYPERCALL_EXIT_16BIT;
2450e5c9a9dSMarc Zyngier 
2460e5c9a9dSMarc Zyngier 	run->exit_reason = KVM_EXIT_HYPERCALL;
2470e5c9a9dSMarc Zyngier 	run->hypercall = (typeof(run->hypercall)) {
2480e5c9a9dSMarc Zyngier 		.nr	= func_id,
2490e5c9a9dSMarc Zyngier 		.flags	= flags,
2500e5c9a9dSMarc Zyngier 	};
251d824dff1SOliver Upton }
252d824dff1SOliver Upton 
kvm_smccc_call_handler(struct kvm_vcpu * vcpu)253aac94968SOliver Upton int kvm_smccc_call_handler(struct kvm_vcpu *vcpu)
2549ed24f4bSMarc Zyngier {
255428fd678SRaghavendra Rao Ananta 	struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
2569ed24f4bSMarc Zyngier 	u32 func_id = smccc_get_function(vcpu);
257923961a7SWill Deacon 	u64 val[4] = {SMCCC_RET_NOT_SUPPORTED};
2589ed24f4bSMarc Zyngier 	u32 feature;
259a8308b3fSOliver Upton 	u8 action;
2609ed24f4bSMarc Zyngier 	gpa_t gpa;
2619ed24f4bSMarc Zyngier 
262a8308b3fSOliver Upton 	action = kvm_smccc_get_action(vcpu, func_id);
263a8308b3fSOliver Upton 	switch (action) {
264a8308b3fSOliver Upton 	case KVM_SMCCC_FILTER_HANDLE:
265a8308b3fSOliver Upton 		break;
266a8308b3fSOliver Upton 	case KVM_SMCCC_FILTER_DENY:
26705714cabSRaghavendra Rao Ananta 		goto out;
268d824dff1SOliver Upton 	case KVM_SMCCC_FILTER_FWD_TO_USER:
269d824dff1SOliver Upton 		kvm_prepare_hypercall_exit(vcpu, func_id);
270d824dff1SOliver Upton 		return 0;
271a8308b3fSOliver Upton 	default:
272a8308b3fSOliver Upton 		WARN_RATELIMIT(1, "Unhandled SMCCC filter action: %d\n", action);
273a8308b3fSOliver Upton 		goto out;
274a8308b3fSOliver Upton 	}
27505714cabSRaghavendra Rao Ananta 
2769ed24f4bSMarc Zyngier 	switch (func_id) {
2779ed24f4bSMarc Zyngier 	case ARM_SMCCC_VERSION_FUNC_ID:
278923961a7SWill Deacon 		val[0] = ARM_SMCCC_VERSION_1_1;
2799ed24f4bSMarc Zyngier 		break;
2809ed24f4bSMarc Zyngier 	case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
2819ed24f4bSMarc Zyngier 		feature = smccc_get_arg1(vcpu);
2829ed24f4bSMarc Zyngier 		switch (feature) {
2839ed24f4bSMarc Zyngier 		case ARM_SMCCC_ARCH_WORKAROUND_1:
284d4647f0aSWill Deacon 			switch (arm64_get_spectre_v2_state()) {
285d4647f0aSWill Deacon 			case SPECTRE_VULNERABLE:
2869ed24f4bSMarc Zyngier 				break;
287d4647f0aSWill Deacon 			case SPECTRE_MITIGATED:
288923961a7SWill Deacon 				val[0] = SMCCC_RET_SUCCESS;
2899ed24f4bSMarc Zyngier 				break;
290d4647f0aSWill Deacon 			case SPECTRE_UNAFFECTED:
291923961a7SWill Deacon 				val[0] = SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED;
2929ed24f4bSMarc Zyngier 				break;
2939ed24f4bSMarc Zyngier 			}
2949ed24f4bSMarc Zyngier 			break;
2959ed24f4bSMarc Zyngier 		case ARM_SMCCC_ARCH_WORKAROUND_2:
296d63d975aSMarc Zyngier 			switch (arm64_get_spectre_v4_state()) {
297d63d975aSMarc Zyngier 			case SPECTRE_VULNERABLE:
2989ed24f4bSMarc Zyngier 				break;
299d63d975aSMarc Zyngier 			case SPECTRE_MITIGATED:
300d63d975aSMarc Zyngier 				/*
301d63d975aSMarc Zyngier 				 * SSBS everywhere: Indicate no firmware
302d63d975aSMarc Zyngier 				 * support, as the SSBS support will be
303d63d975aSMarc Zyngier 				 * indicated to the guest and the default is
304d63d975aSMarc Zyngier 				 * safe.
305d63d975aSMarc Zyngier 				 *
306d63d975aSMarc Zyngier 				 * Otherwise, expose a permanent mitigation
307d63d975aSMarc Zyngier 				 * to the guest, and hide SSBS so that the
308d63d975aSMarc Zyngier 				 * guest stays protected.
309d63d975aSMarc Zyngier 				 */
310d63d975aSMarc Zyngier 				if (cpus_have_final_cap(ARM64_SSBS))
311d63d975aSMarc Zyngier 					break;
312d63d975aSMarc Zyngier 				fallthrough;
313d63d975aSMarc Zyngier 			case SPECTRE_UNAFFECTED:
314923961a7SWill Deacon 				val[0] = SMCCC_RET_NOT_REQUIRED;
3159ed24f4bSMarc Zyngier 				break;
3169ed24f4bSMarc Zyngier 			}
3179ed24f4bSMarc Zyngier 			break;
318a5905d6aSJames Morse 		case ARM_SMCCC_ARCH_WORKAROUND_3:
319a5905d6aSJames Morse 			switch (arm64_get_spectre_bhb_state()) {
320a5905d6aSJames Morse 			case SPECTRE_VULNERABLE:
321a5905d6aSJames Morse 				break;
322a5905d6aSJames Morse 			case SPECTRE_MITIGATED:
323a5905d6aSJames Morse 				val[0] = SMCCC_RET_SUCCESS;
324a5905d6aSJames Morse 				break;
325a5905d6aSJames Morse 			case SPECTRE_UNAFFECTED:
326a5905d6aSJames Morse 				val[0] = SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED;
327a5905d6aSJames Morse 				break;
328a5905d6aSJames Morse 			}
329a5905d6aSJames Morse 			break;
3309ed24f4bSMarc Zyngier 		case ARM_SMCCC_HV_PV_TIME_FEATURES:
331428fd678SRaghavendra Rao Ananta 			if (test_bit(KVM_REG_ARM_STD_HYP_BIT_PV_TIME,
332428fd678SRaghavendra Rao Ananta 				     &smccc_feat->std_hyp_bmap))
333923961a7SWill Deacon 				val[0] = SMCCC_RET_SUCCESS;
3349ed24f4bSMarc Zyngier 			break;
3359ed24f4bSMarc Zyngier 		}
3369ed24f4bSMarc Zyngier 		break;
3379ed24f4bSMarc Zyngier 	case ARM_SMCCC_HV_PV_TIME_FEATURES:
338923961a7SWill Deacon 		val[0] = kvm_hypercall_pv_features(vcpu);
3399ed24f4bSMarc Zyngier 		break;
3409ed24f4bSMarc Zyngier 	case ARM_SMCCC_HV_PV_TIME_ST:
3419ed24f4bSMarc Zyngier 		gpa = kvm_init_stolen_time(vcpu);
342cecafc0aSYu Zhang 		if (gpa != INVALID_GPA)
343923961a7SWill Deacon 			val[0] = gpa;
344923961a7SWill Deacon 		break;
345923961a7SWill Deacon 	case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
346923961a7SWill Deacon 		val[0] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_0;
347923961a7SWill Deacon 		val[1] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_1;
348923961a7SWill Deacon 		val[2] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_2;
349923961a7SWill Deacon 		val[3] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_3;
350923961a7SWill Deacon 		break;
351923961a7SWill Deacon 	case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
352b22216e1SRaghavendra Rao Ananta 		val[0] = smccc_feat->vendor_hyp_bmap;
3533bf72569SJianyong Wu 		break;
3543bf72569SJianyong Wu 	case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
3553bf72569SJianyong Wu 		kvm_ptp_get_time(vcpu, val);
3569ed24f4bSMarc Zyngier 		break;
357a8e190cdSArd Biesheuvel 	case ARM_SMCCC_TRNG_VERSION:
358a8e190cdSArd Biesheuvel 	case ARM_SMCCC_TRNG_FEATURES:
359a8e190cdSArd Biesheuvel 	case ARM_SMCCC_TRNG_GET_UUID:
360a8e190cdSArd Biesheuvel 	case ARM_SMCCC_TRNG_RND32:
361a8e190cdSArd Biesheuvel 	case ARM_SMCCC_TRNG_RND64:
362a8e190cdSArd Biesheuvel 		return kvm_trng_call(vcpu);
3639ed24f4bSMarc Zyngier 	default:
3649ed24f4bSMarc Zyngier 		return kvm_psci_call(vcpu);
3659ed24f4bSMarc Zyngier 	}
3669ed24f4bSMarc Zyngier 
36705714cabSRaghavendra Rao Ananta out:
368923961a7SWill Deacon 	smccc_set_retval(vcpu, val[0], val[1], val[2], val[3]);
3699ed24f4bSMarc Zyngier 	return 1;
3709ed24f4bSMarc Zyngier }
37185fbe08eSRaghavendra Rao Ananta 
37285fbe08eSRaghavendra Rao Ananta static const u64 kvm_arm_fw_reg_ids[] = {
37385fbe08eSRaghavendra Rao Ananta 	KVM_REG_ARM_PSCI_VERSION,
37485fbe08eSRaghavendra Rao Ananta 	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1,
37585fbe08eSRaghavendra Rao Ananta 	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2,
37685fbe08eSRaghavendra Rao Ananta 	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
37705714cabSRaghavendra Rao Ananta 	KVM_REG_ARM_STD_BMAP,
378428fd678SRaghavendra Rao Ananta 	KVM_REG_ARM_STD_HYP_BMAP,
379b22216e1SRaghavendra Rao Ananta 	KVM_REG_ARM_VENDOR_HYP_BMAP,
38085fbe08eSRaghavendra Rao Ananta };
38185fbe08eSRaghavendra Rao Ananta 
kvm_arm_init_hypercalls(struct kvm * kvm)38205714cabSRaghavendra Rao Ananta void kvm_arm_init_hypercalls(struct kvm *kvm)
38305714cabSRaghavendra Rao Ananta {
38405714cabSRaghavendra Rao Ananta 	struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
38505714cabSRaghavendra Rao Ananta 
38605714cabSRaghavendra Rao Ananta 	smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES;
387428fd678SRaghavendra Rao Ananta 	smccc_feat->std_hyp_bmap = KVM_ARM_SMCCC_STD_HYP_FEATURES;
388b22216e1SRaghavendra Rao Ananta 	smccc_feat->vendor_hyp_bmap = KVM_ARM_SMCCC_VENDOR_HYP_FEATURES;
389fb88707dSOliver Upton 
390fb88707dSOliver Upton 	init_smccc_filter(kvm);
391fb88707dSOliver Upton }
392fb88707dSOliver Upton 
kvm_arm_teardown_hypercalls(struct kvm * kvm)393fb88707dSOliver Upton void kvm_arm_teardown_hypercalls(struct kvm *kvm)
394fb88707dSOliver Upton {
395fb88707dSOliver Upton 	mtree_destroy(&kvm->arch.smccc_filter);
39605714cabSRaghavendra Rao Ananta }
39705714cabSRaghavendra Rao Ananta 
kvm_arm_get_fw_num_regs(struct kvm_vcpu * vcpu)39885fbe08eSRaghavendra Rao Ananta int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
39985fbe08eSRaghavendra Rao Ananta {
40085fbe08eSRaghavendra Rao Ananta 	return ARRAY_SIZE(kvm_arm_fw_reg_ids);
40185fbe08eSRaghavendra Rao Ananta }
40285fbe08eSRaghavendra Rao Ananta 
kvm_arm_copy_fw_reg_indices(struct kvm_vcpu * vcpu,u64 __user * uindices)40385fbe08eSRaghavendra Rao Ananta int kvm_arm_copy_fw_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
40485fbe08eSRaghavendra Rao Ananta {
40585fbe08eSRaghavendra Rao Ananta 	int i;
40685fbe08eSRaghavendra Rao Ananta 
40785fbe08eSRaghavendra Rao Ananta 	for (i = 0; i < ARRAY_SIZE(kvm_arm_fw_reg_ids); i++) {
40885fbe08eSRaghavendra Rao Ananta 		if (put_user(kvm_arm_fw_reg_ids[i], uindices++))
40985fbe08eSRaghavendra Rao Ananta 			return -EFAULT;
41085fbe08eSRaghavendra Rao Ananta 	}
41185fbe08eSRaghavendra Rao Ananta 
41285fbe08eSRaghavendra Rao Ananta 	return 0;
41385fbe08eSRaghavendra Rao Ananta }
41485fbe08eSRaghavendra Rao Ananta 
41585fbe08eSRaghavendra Rao Ananta #define KVM_REG_FEATURE_LEVEL_MASK	GENMASK(3, 0)
41685fbe08eSRaghavendra Rao Ananta 
41785fbe08eSRaghavendra Rao Ananta /*
41885fbe08eSRaghavendra Rao Ananta  * Convert the workaround level into an easy-to-compare number, where higher
41985fbe08eSRaghavendra Rao Ananta  * values mean better protection.
42085fbe08eSRaghavendra Rao Ananta  */
get_kernel_wa_level(u64 regid)42185fbe08eSRaghavendra Rao Ananta static int get_kernel_wa_level(u64 regid)
42285fbe08eSRaghavendra Rao Ananta {
42385fbe08eSRaghavendra Rao Ananta 	switch (regid) {
42485fbe08eSRaghavendra Rao Ananta 	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1:
42585fbe08eSRaghavendra Rao Ananta 		switch (arm64_get_spectre_v2_state()) {
42685fbe08eSRaghavendra Rao Ananta 		case SPECTRE_VULNERABLE:
42785fbe08eSRaghavendra Rao Ananta 			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL;
42885fbe08eSRaghavendra Rao Ananta 		case SPECTRE_MITIGATED:
42985fbe08eSRaghavendra Rao Ananta 			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_AVAIL;
43085fbe08eSRaghavendra Rao Ananta 		case SPECTRE_UNAFFECTED:
43185fbe08eSRaghavendra Rao Ananta 			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_REQUIRED;
43285fbe08eSRaghavendra Rao Ananta 		}
43385fbe08eSRaghavendra Rao Ananta 		return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL;
43485fbe08eSRaghavendra Rao Ananta 	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2:
43585fbe08eSRaghavendra Rao Ananta 		switch (arm64_get_spectre_v4_state()) {
43685fbe08eSRaghavendra Rao Ananta 		case SPECTRE_MITIGATED:
43785fbe08eSRaghavendra Rao Ananta 			/*
43885fbe08eSRaghavendra Rao Ananta 			 * As for the hypercall discovery, we pretend we
43985fbe08eSRaghavendra Rao Ananta 			 * don't have any FW mitigation if SSBS is there at
44085fbe08eSRaghavendra Rao Ananta 			 * all times.
44185fbe08eSRaghavendra Rao Ananta 			 */
44285fbe08eSRaghavendra Rao Ananta 			if (cpus_have_final_cap(ARM64_SSBS))
44385fbe08eSRaghavendra Rao Ananta 				return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL;
44485fbe08eSRaghavendra Rao Ananta 			fallthrough;
44585fbe08eSRaghavendra Rao Ananta 		case SPECTRE_UNAFFECTED:
44685fbe08eSRaghavendra Rao Ananta 			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED;
44785fbe08eSRaghavendra Rao Ananta 		case SPECTRE_VULNERABLE:
44885fbe08eSRaghavendra Rao Ananta 			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL;
44985fbe08eSRaghavendra Rao Ananta 		}
45085fbe08eSRaghavendra Rao Ananta 		break;
45185fbe08eSRaghavendra Rao Ananta 	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
45285fbe08eSRaghavendra Rao Ananta 		switch (arm64_get_spectre_bhb_state()) {
45385fbe08eSRaghavendra Rao Ananta 		case SPECTRE_VULNERABLE:
45485fbe08eSRaghavendra Rao Ananta 			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL;
45585fbe08eSRaghavendra Rao Ananta 		case SPECTRE_MITIGATED:
45685fbe08eSRaghavendra Rao Ananta 			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_AVAIL;
45785fbe08eSRaghavendra Rao Ananta 		case SPECTRE_UNAFFECTED:
45885fbe08eSRaghavendra Rao Ananta 			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_REQUIRED;
45985fbe08eSRaghavendra Rao Ananta 		}
46085fbe08eSRaghavendra Rao Ananta 		return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL;
46185fbe08eSRaghavendra Rao Ananta 	}
46285fbe08eSRaghavendra Rao Ananta 
46385fbe08eSRaghavendra Rao Ananta 	return -EINVAL;
46485fbe08eSRaghavendra Rao Ananta }
46585fbe08eSRaghavendra Rao Ananta 
kvm_arm_get_fw_reg(struct kvm_vcpu * vcpu,const struct kvm_one_reg * reg)46685fbe08eSRaghavendra Rao Ananta int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
46785fbe08eSRaghavendra Rao Ananta {
46805714cabSRaghavendra Rao Ananta 	struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
46985fbe08eSRaghavendra Rao Ananta 	void __user *uaddr = (void __user *)(long)reg->addr;
47085fbe08eSRaghavendra Rao Ananta 	u64 val;
47185fbe08eSRaghavendra Rao Ananta 
47285fbe08eSRaghavendra Rao Ananta 	switch (reg->id) {
47385fbe08eSRaghavendra Rao Ananta 	case KVM_REG_ARM_PSCI_VERSION:
47485fbe08eSRaghavendra Rao Ananta 		val = kvm_psci_version(vcpu);
47585fbe08eSRaghavendra Rao Ananta 		break;
47685fbe08eSRaghavendra Rao Ananta 	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1:
47785fbe08eSRaghavendra Rao Ananta 	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2:
47885fbe08eSRaghavendra Rao Ananta 	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
47985fbe08eSRaghavendra Rao Ananta 		val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK;
48085fbe08eSRaghavendra Rao Ananta 		break;
48105714cabSRaghavendra Rao Ananta 	case KVM_REG_ARM_STD_BMAP:
48205714cabSRaghavendra Rao Ananta 		val = READ_ONCE(smccc_feat->std_bmap);
48305714cabSRaghavendra Rao Ananta 		break;
484428fd678SRaghavendra Rao Ananta 	case KVM_REG_ARM_STD_HYP_BMAP:
485428fd678SRaghavendra Rao Ananta 		val = READ_ONCE(smccc_feat->std_hyp_bmap);
486428fd678SRaghavendra Rao Ananta 		break;
487b22216e1SRaghavendra Rao Ananta 	case KVM_REG_ARM_VENDOR_HYP_BMAP:
488b22216e1SRaghavendra Rao Ananta 		val = READ_ONCE(smccc_feat->vendor_hyp_bmap);
489b22216e1SRaghavendra Rao Ananta 		break;
49085fbe08eSRaghavendra Rao Ananta 	default:
49185fbe08eSRaghavendra Rao Ananta 		return -ENOENT;
49285fbe08eSRaghavendra Rao Ananta 	}
49385fbe08eSRaghavendra Rao Ananta 
49485fbe08eSRaghavendra Rao Ananta 	if (copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id)))
49585fbe08eSRaghavendra Rao Ananta 		return -EFAULT;
49685fbe08eSRaghavendra Rao Ananta 
49785fbe08eSRaghavendra Rao Ananta 	return 0;
49885fbe08eSRaghavendra Rao Ananta }
49985fbe08eSRaghavendra Rao Ananta 
kvm_arm_set_fw_reg_bmap(struct kvm_vcpu * vcpu,u64 reg_id,u64 val)50005714cabSRaghavendra Rao Ananta static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val)
50105714cabSRaghavendra Rao Ananta {
50205714cabSRaghavendra Rao Ananta 	int ret = 0;
50305714cabSRaghavendra Rao Ananta 	struct kvm *kvm = vcpu->kvm;
50405714cabSRaghavendra Rao Ananta 	struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
50505714cabSRaghavendra Rao Ananta 	unsigned long *fw_reg_bmap, fw_reg_features;
50605714cabSRaghavendra Rao Ananta 
50705714cabSRaghavendra Rao Ananta 	switch (reg_id) {
50805714cabSRaghavendra Rao Ananta 	case KVM_REG_ARM_STD_BMAP:
50905714cabSRaghavendra Rao Ananta 		fw_reg_bmap = &smccc_feat->std_bmap;
51005714cabSRaghavendra Rao Ananta 		fw_reg_features = KVM_ARM_SMCCC_STD_FEATURES;
51105714cabSRaghavendra Rao Ananta 		break;
512428fd678SRaghavendra Rao Ananta 	case KVM_REG_ARM_STD_HYP_BMAP:
513428fd678SRaghavendra Rao Ananta 		fw_reg_bmap = &smccc_feat->std_hyp_bmap;
514428fd678SRaghavendra Rao Ananta 		fw_reg_features = KVM_ARM_SMCCC_STD_HYP_FEATURES;
515428fd678SRaghavendra Rao Ananta 		break;
516b22216e1SRaghavendra Rao Ananta 	case KVM_REG_ARM_VENDOR_HYP_BMAP:
517b22216e1SRaghavendra Rao Ananta 		fw_reg_bmap = &smccc_feat->vendor_hyp_bmap;
518b22216e1SRaghavendra Rao Ananta 		fw_reg_features = KVM_ARM_SMCCC_VENDOR_HYP_FEATURES;
519b22216e1SRaghavendra Rao Ananta 		break;
52005714cabSRaghavendra Rao Ananta 	default:
52105714cabSRaghavendra Rao Ananta 		return -ENOENT;
52205714cabSRaghavendra Rao Ananta 	}
52305714cabSRaghavendra Rao Ananta 
52405714cabSRaghavendra Rao Ananta 	/* Check for unsupported bit */
52505714cabSRaghavendra Rao Ananta 	if (val & ~fw_reg_features)
52605714cabSRaghavendra Rao Ananta 		return -EINVAL;
52705714cabSRaghavendra Rao Ananta 
5284bba7f7dSOliver Upton 	mutex_lock(&kvm->arch.config_lock);
52905714cabSRaghavendra Rao Ananta 
530de40bb8aSOliver Upton 	if (kvm_vm_has_ran_once(kvm) && val != *fw_reg_bmap) {
53105714cabSRaghavendra Rao Ananta 		ret = -EBUSY;
53205714cabSRaghavendra Rao Ananta 		goto out;
53305714cabSRaghavendra Rao Ananta 	}
53405714cabSRaghavendra Rao Ananta 
53505714cabSRaghavendra Rao Ananta 	WRITE_ONCE(*fw_reg_bmap, val);
53605714cabSRaghavendra Rao Ananta out:
5374bba7f7dSOliver Upton 	mutex_unlock(&kvm->arch.config_lock);
53805714cabSRaghavendra Rao Ananta 	return ret;
53905714cabSRaghavendra Rao Ananta }
54005714cabSRaghavendra Rao Ananta 
kvm_arm_set_fw_reg(struct kvm_vcpu * vcpu,const struct kvm_one_reg * reg)54185fbe08eSRaghavendra Rao Ananta int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
54285fbe08eSRaghavendra Rao Ananta {
54385fbe08eSRaghavendra Rao Ananta 	void __user *uaddr = (void __user *)(long)reg->addr;
54485fbe08eSRaghavendra Rao Ananta 	u64 val;
54585fbe08eSRaghavendra Rao Ananta 	int wa_level;
54685fbe08eSRaghavendra Rao Ananta 
547a25bc848SDan Carpenter 	if (KVM_REG_SIZE(reg->id) != sizeof(val))
548a25bc848SDan Carpenter 		return -ENOENT;
54985fbe08eSRaghavendra Rao Ananta 	if (copy_from_user(&val, uaddr, KVM_REG_SIZE(reg->id)))
55085fbe08eSRaghavendra Rao Ananta 		return -EFAULT;
55185fbe08eSRaghavendra Rao Ananta 
55285fbe08eSRaghavendra Rao Ananta 	switch (reg->id) {
55385fbe08eSRaghavendra Rao Ananta 	case KVM_REG_ARM_PSCI_VERSION:
55485fbe08eSRaghavendra Rao Ananta 	{
55585fbe08eSRaghavendra Rao Ananta 		bool wants_02;
55685fbe08eSRaghavendra Rao Ananta 
55785fbe08eSRaghavendra Rao Ananta 		wants_02 = test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features);
55885fbe08eSRaghavendra Rao Ananta 
55985fbe08eSRaghavendra Rao Ananta 		switch (val) {
56085fbe08eSRaghavendra Rao Ananta 		case KVM_ARM_PSCI_0_1:
56185fbe08eSRaghavendra Rao Ananta 			if (wants_02)
56285fbe08eSRaghavendra Rao Ananta 				return -EINVAL;
56385fbe08eSRaghavendra Rao Ananta 			vcpu->kvm->arch.psci_version = val;
56485fbe08eSRaghavendra Rao Ananta 			return 0;
56585fbe08eSRaghavendra Rao Ananta 		case KVM_ARM_PSCI_0_2:
56685fbe08eSRaghavendra Rao Ananta 		case KVM_ARM_PSCI_1_0:
56785fbe08eSRaghavendra Rao Ananta 		case KVM_ARM_PSCI_1_1:
56885fbe08eSRaghavendra Rao Ananta 			if (!wants_02)
56985fbe08eSRaghavendra Rao Ananta 				return -EINVAL;
57085fbe08eSRaghavendra Rao Ananta 			vcpu->kvm->arch.psci_version = val;
57185fbe08eSRaghavendra Rao Ananta 			return 0;
57285fbe08eSRaghavendra Rao Ananta 		}
57385fbe08eSRaghavendra Rao Ananta 		break;
57485fbe08eSRaghavendra Rao Ananta 	}
57585fbe08eSRaghavendra Rao Ananta 
57685fbe08eSRaghavendra Rao Ananta 	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1:
57785fbe08eSRaghavendra Rao Ananta 	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
57885fbe08eSRaghavendra Rao Ananta 		if (val & ~KVM_REG_FEATURE_LEVEL_MASK)
57985fbe08eSRaghavendra Rao Ananta 			return -EINVAL;
58085fbe08eSRaghavendra Rao Ananta 
58185fbe08eSRaghavendra Rao Ananta 		if (get_kernel_wa_level(reg->id) < val)
58285fbe08eSRaghavendra Rao Ananta 			return -EINVAL;
58385fbe08eSRaghavendra Rao Ananta 
58485fbe08eSRaghavendra Rao Ananta 		return 0;
58585fbe08eSRaghavendra Rao Ananta 
58685fbe08eSRaghavendra Rao Ananta 	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2:
58785fbe08eSRaghavendra Rao Ananta 		if (val & ~(KVM_REG_FEATURE_LEVEL_MASK |
58885fbe08eSRaghavendra Rao Ananta 			    KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED))
58985fbe08eSRaghavendra Rao Ananta 			return -EINVAL;
59085fbe08eSRaghavendra Rao Ananta 
59185fbe08eSRaghavendra Rao Ananta 		/* The enabled bit must not be set unless the level is AVAIL. */
59285fbe08eSRaghavendra Rao Ananta 		if ((val & KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED) &&
59385fbe08eSRaghavendra Rao Ananta 		    (val & KVM_REG_FEATURE_LEVEL_MASK) != KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL)
59485fbe08eSRaghavendra Rao Ananta 			return -EINVAL;
59585fbe08eSRaghavendra Rao Ananta 
59685fbe08eSRaghavendra Rao Ananta 		/*
59785fbe08eSRaghavendra Rao Ananta 		 * Map all the possible incoming states to the only two we
59885fbe08eSRaghavendra Rao Ananta 		 * really want to deal with.
59985fbe08eSRaghavendra Rao Ananta 		 */
60085fbe08eSRaghavendra Rao Ananta 		switch (val & KVM_REG_FEATURE_LEVEL_MASK) {
60185fbe08eSRaghavendra Rao Ananta 		case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL:
60285fbe08eSRaghavendra Rao Ananta 		case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_UNKNOWN:
60385fbe08eSRaghavendra Rao Ananta 			wa_level = KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL;
60485fbe08eSRaghavendra Rao Ananta 			break;
60585fbe08eSRaghavendra Rao Ananta 		case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL:
60685fbe08eSRaghavendra Rao Ananta 		case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED:
60785fbe08eSRaghavendra Rao Ananta 			wa_level = KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED;
60885fbe08eSRaghavendra Rao Ananta 			break;
60985fbe08eSRaghavendra Rao Ananta 		default:
61085fbe08eSRaghavendra Rao Ananta 			return -EINVAL;
61185fbe08eSRaghavendra Rao Ananta 		}
61285fbe08eSRaghavendra Rao Ananta 
61385fbe08eSRaghavendra Rao Ananta 		/*
61485fbe08eSRaghavendra Rao Ananta 		 * We can deal with NOT_AVAIL on NOT_REQUIRED, but not the
61585fbe08eSRaghavendra Rao Ananta 		 * other way around.
61685fbe08eSRaghavendra Rao Ananta 		 */
61785fbe08eSRaghavendra Rao Ananta 		if (get_kernel_wa_level(reg->id) < wa_level)
61885fbe08eSRaghavendra Rao Ananta 			return -EINVAL;
61985fbe08eSRaghavendra Rao Ananta 
62085fbe08eSRaghavendra Rao Ananta 		return 0;
62105714cabSRaghavendra Rao Ananta 	case KVM_REG_ARM_STD_BMAP:
622428fd678SRaghavendra Rao Ananta 	case KVM_REG_ARM_STD_HYP_BMAP:
623b22216e1SRaghavendra Rao Ananta 	case KVM_REG_ARM_VENDOR_HYP_BMAP:
62405714cabSRaghavendra Rao Ananta 		return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val);
62585fbe08eSRaghavendra Rao Ananta 	default:
62685fbe08eSRaghavendra Rao Ananta 		return -ENOENT;
62785fbe08eSRaghavendra Rao Ananta 	}
62885fbe08eSRaghavendra Rao Ananta 
62985fbe08eSRaghavendra Rao Ananta 	return -EINVAL;
63085fbe08eSRaghavendra Rao Ananta }
631821d935cSOliver Upton 
kvm_vm_smccc_has_attr(struct kvm * kvm,struct kvm_device_attr * attr)632821d935cSOliver Upton int kvm_vm_smccc_has_attr(struct kvm *kvm, struct kvm_device_attr *attr)
633821d935cSOliver Upton {
634821d935cSOliver Upton 	switch (attr->attr) {
635821d935cSOliver Upton 	case KVM_ARM_VM_SMCCC_FILTER:
636821d935cSOliver Upton 		return 0;
637821d935cSOliver Upton 	default:
638821d935cSOliver Upton 		return -ENXIO;
639821d935cSOliver Upton 	}
640821d935cSOliver Upton }
641821d935cSOliver Upton 
kvm_vm_smccc_set_attr(struct kvm * kvm,struct kvm_device_attr * attr)642821d935cSOliver Upton int kvm_vm_smccc_set_attr(struct kvm *kvm, struct kvm_device_attr *attr)
643821d935cSOliver Upton {
644821d935cSOliver Upton 	void __user *uaddr = (void __user *)attr->addr;
645821d935cSOliver Upton 
646821d935cSOliver Upton 	switch (attr->attr) {
647821d935cSOliver Upton 	case KVM_ARM_VM_SMCCC_FILTER:
648821d935cSOliver Upton 		return kvm_smccc_set_filter(kvm, uaddr);
649821d935cSOliver Upton 	default:
650821d935cSOliver Upton 		return -ENXIO;
651821d935cSOliver Upton 	}
652821d935cSOliver Upton }
653