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