162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci// Copyright (C) 2019 Arm Ltd.
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <linux/arm-smccc.h>
562306a36Sopenharmony_ci#include <linux/kvm_host.h>
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <asm/kvm_emulate.h>
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <kvm/arm_hypercalls.h>
1062306a36Sopenharmony_ci#include <kvm/arm_psci.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#define KVM_ARM_SMCCC_STD_FEATURES				\
1362306a36Sopenharmony_ci	GENMASK(KVM_REG_ARM_STD_BMAP_BIT_COUNT - 1, 0)
1462306a36Sopenharmony_ci#define KVM_ARM_SMCCC_STD_HYP_FEATURES				\
1562306a36Sopenharmony_ci	GENMASK(KVM_REG_ARM_STD_HYP_BMAP_BIT_COUNT - 1, 0)
1662306a36Sopenharmony_ci#define KVM_ARM_SMCCC_VENDOR_HYP_FEATURES			\
1762306a36Sopenharmony_ci	GENMASK(KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_COUNT - 1, 0)
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistatic void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val)
2062306a36Sopenharmony_ci{
2162306a36Sopenharmony_ci	struct system_time_snapshot systime_snapshot;
2262306a36Sopenharmony_ci	u64 cycles = ~0UL;
2362306a36Sopenharmony_ci	u32 feature;
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci	/*
2662306a36Sopenharmony_ci	 * system time and counter value must captured at the same
2762306a36Sopenharmony_ci	 * time to keep consistency and precision.
2862306a36Sopenharmony_ci	 */
2962306a36Sopenharmony_ci	ktime_get_snapshot(&systime_snapshot);
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	/*
3262306a36Sopenharmony_ci	 * This is only valid if the current clocksource is the
3362306a36Sopenharmony_ci	 * architected counter, as this is the only one the guest
3462306a36Sopenharmony_ci	 * can see.
3562306a36Sopenharmony_ci	 */
3662306a36Sopenharmony_ci	if (systime_snapshot.cs_id != CSID_ARM_ARCH_COUNTER)
3762306a36Sopenharmony_ci		return;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	/*
4062306a36Sopenharmony_ci	 * The guest selects one of the two reference counters
4162306a36Sopenharmony_ci	 * (virtual or physical) with the first argument of the SMCCC
4262306a36Sopenharmony_ci	 * call. In case the identifier is not supported, error out.
4362306a36Sopenharmony_ci	 */
4462306a36Sopenharmony_ci	feature = smccc_get_arg1(vcpu);
4562306a36Sopenharmony_ci	switch (feature) {
4662306a36Sopenharmony_ci	case KVM_PTP_VIRT_COUNTER:
4762306a36Sopenharmony_ci		cycles = systime_snapshot.cycles - vcpu->kvm->arch.timer_data.voffset;
4862306a36Sopenharmony_ci		break;
4962306a36Sopenharmony_ci	case KVM_PTP_PHYS_COUNTER:
5062306a36Sopenharmony_ci		cycles = systime_snapshot.cycles - vcpu->kvm->arch.timer_data.poffset;
5162306a36Sopenharmony_ci		break;
5262306a36Sopenharmony_ci	default:
5362306a36Sopenharmony_ci		return;
5462306a36Sopenharmony_ci	}
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	/*
5762306a36Sopenharmony_ci	 * This relies on the top bit of val[0] never being set for
5862306a36Sopenharmony_ci	 * valid values of system time, because that is *really* far
5962306a36Sopenharmony_ci	 * in the future (about 292 years from 1970, and at that stage
6062306a36Sopenharmony_ci	 * nobody will give a damn about it).
6162306a36Sopenharmony_ci	 */
6262306a36Sopenharmony_ci	val[0] = upper_32_bits(systime_snapshot.real);
6362306a36Sopenharmony_ci	val[1] = lower_32_bits(systime_snapshot.real);
6462306a36Sopenharmony_ci	val[2] = upper_32_bits(cycles);
6562306a36Sopenharmony_ci	val[3] = lower_32_bits(cycles);
6662306a36Sopenharmony_ci}
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cistatic bool kvm_smccc_default_allowed(u32 func_id)
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	switch (func_id) {
7162306a36Sopenharmony_ci	/*
7262306a36Sopenharmony_ci	 * List of function-ids that are not gated with the bitmapped
7362306a36Sopenharmony_ci	 * feature firmware registers, and are to be allowed for
7462306a36Sopenharmony_ci	 * servicing the call by default.
7562306a36Sopenharmony_ci	 */
7662306a36Sopenharmony_ci	case ARM_SMCCC_VERSION_FUNC_ID:
7762306a36Sopenharmony_ci	case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
7862306a36Sopenharmony_ci		return true;
7962306a36Sopenharmony_ci	default:
8062306a36Sopenharmony_ci		/* PSCI 0.2 and up is in the 0:0x1f range */
8162306a36Sopenharmony_ci		if (ARM_SMCCC_OWNER_NUM(func_id) == ARM_SMCCC_OWNER_STANDARD &&
8262306a36Sopenharmony_ci		    ARM_SMCCC_FUNC_NUM(func_id) <= 0x1f)
8362306a36Sopenharmony_ci			return true;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci		/*
8662306a36Sopenharmony_ci		 * KVM's PSCI 0.1 doesn't comply with SMCCC, and has
8762306a36Sopenharmony_ci		 * its own function-id base and range
8862306a36Sopenharmony_ci		 */
8962306a36Sopenharmony_ci		if (func_id >= KVM_PSCI_FN(0) && func_id <= KVM_PSCI_FN(3))
9062306a36Sopenharmony_ci			return true;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci		return false;
9362306a36Sopenharmony_ci	}
9462306a36Sopenharmony_ci}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_cistatic bool kvm_smccc_test_fw_bmap(struct kvm_vcpu *vcpu, u32 func_id)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	switch (func_id) {
10162306a36Sopenharmony_ci	case ARM_SMCCC_TRNG_VERSION:
10262306a36Sopenharmony_ci	case ARM_SMCCC_TRNG_FEATURES:
10362306a36Sopenharmony_ci	case ARM_SMCCC_TRNG_GET_UUID:
10462306a36Sopenharmony_ci	case ARM_SMCCC_TRNG_RND32:
10562306a36Sopenharmony_ci	case ARM_SMCCC_TRNG_RND64:
10662306a36Sopenharmony_ci		return test_bit(KVM_REG_ARM_STD_BIT_TRNG_V1_0,
10762306a36Sopenharmony_ci				&smccc_feat->std_bmap);
10862306a36Sopenharmony_ci	case ARM_SMCCC_HV_PV_TIME_FEATURES:
10962306a36Sopenharmony_ci	case ARM_SMCCC_HV_PV_TIME_ST:
11062306a36Sopenharmony_ci		return test_bit(KVM_REG_ARM_STD_HYP_BIT_PV_TIME,
11162306a36Sopenharmony_ci				&smccc_feat->std_hyp_bmap);
11262306a36Sopenharmony_ci	case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
11362306a36Sopenharmony_ci	case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
11462306a36Sopenharmony_ci		return test_bit(KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT,
11562306a36Sopenharmony_ci				&smccc_feat->vendor_hyp_bmap);
11662306a36Sopenharmony_ci	case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
11762306a36Sopenharmony_ci		return test_bit(KVM_REG_ARM_VENDOR_HYP_BIT_PTP,
11862306a36Sopenharmony_ci				&smccc_feat->vendor_hyp_bmap);
11962306a36Sopenharmony_ci	default:
12062306a36Sopenharmony_ci		return false;
12162306a36Sopenharmony_ci	}
12262306a36Sopenharmony_ci}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci#define SMC32_ARCH_RANGE_BEGIN	ARM_SMCCC_VERSION_FUNC_ID
12562306a36Sopenharmony_ci#define SMC32_ARCH_RANGE_END	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,		\
12662306a36Sopenharmony_ci						   ARM_SMCCC_SMC_32,		\
12762306a36Sopenharmony_ci						   0, ARM_SMCCC_FUNC_MASK)
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci#define SMC64_ARCH_RANGE_BEGIN	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,		\
13062306a36Sopenharmony_ci						   ARM_SMCCC_SMC_64,		\
13162306a36Sopenharmony_ci						   0, 0)
13262306a36Sopenharmony_ci#define SMC64_ARCH_RANGE_END	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,		\
13362306a36Sopenharmony_ci						   ARM_SMCCC_SMC_64,		\
13462306a36Sopenharmony_ci						   0, ARM_SMCCC_FUNC_MASK)
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cistatic void init_smccc_filter(struct kvm *kvm)
13762306a36Sopenharmony_ci{
13862306a36Sopenharmony_ci	int r;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	mt_init(&kvm->arch.smccc_filter);
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	/*
14362306a36Sopenharmony_ci	 * Prevent userspace from handling any SMCCC calls in the architecture
14462306a36Sopenharmony_ci	 * range, avoiding the risk of misrepresenting Spectre mitigation status
14562306a36Sopenharmony_ci	 * to the guest.
14662306a36Sopenharmony_ci	 */
14762306a36Sopenharmony_ci	r = mtree_insert_range(&kvm->arch.smccc_filter,
14862306a36Sopenharmony_ci			       SMC32_ARCH_RANGE_BEGIN, SMC32_ARCH_RANGE_END,
14962306a36Sopenharmony_ci			       xa_mk_value(KVM_SMCCC_FILTER_HANDLE),
15062306a36Sopenharmony_ci			       GFP_KERNEL_ACCOUNT);
15162306a36Sopenharmony_ci	WARN_ON_ONCE(r);
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	r = mtree_insert_range(&kvm->arch.smccc_filter,
15462306a36Sopenharmony_ci			       SMC64_ARCH_RANGE_BEGIN, SMC64_ARCH_RANGE_END,
15562306a36Sopenharmony_ci			       xa_mk_value(KVM_SMCCC_FILTER_HANDLE),
15662306a36Sopenharmony_ci			       GFP_KERNEL_ACCOUNT);
15762306a36Sopenharmony_ci	WARN_ON_ONCE(r);
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_cistatic int kvm_smccc_set_filter(struct kvm *kvm, struct kvm_smccc_filter __user *uaddr)
16262306a36Sopenharmony_ci{
16362306a36Sopenharmony_ci	const void *zero_page = page_to_virt(ZERO_PAGE(0));
16462306a36Sopenharmony_ci	struct kvm_smccc_filter filter;
16562306a36Sopenharmony_ci	u32 start, end;
16662306a36Sopenharmony_ci	int r;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	if (copy_from_user(&filter, uaddr, sizeof(filter)))
16962306a36Sopenharmony_ci		return -EFAULT;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	if (memcmp(filter.pad, zero_page, sizeof(filter.pad)))
17262306a36Sopenharmony_ci		return -EINVAL;
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	start = filter.base;
17562306a36Sopenharmony_ci	end = start + filter.nr_functions - 1;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	if (end < start || filter.action >= NR_SMCCC_FILTER_ACTIONS)
17862306a36Sopenharmony_ci		return -EINVAL;
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	mutex_lock(&kvm->arch.config_lock);
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	if (kvm_vm_has_ran_once(kvm)) {
18362306a36Sopenharmony_ci		r = -EBUSY;
18462306a36Sopenharmony_ci		goto out_unlock;
18562306a36Sopenharmony_ci	}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	r = mtree_insert_range(&kvm->arch.smccc_filter, start, end,
18862306a36Sopenharmony_ci			       xa_mk_value(filter.action), GFP_KERNEL_ACCOUNT);
18962306a36Sopenharmony_ci	if (r)
19062306a36Sopenharmony_ci		goto out_unlock;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	set_bit(KVM_ARCH_FLAG_SMCCC_FILTER_CONFIGURED, &kvm->arch.flags);
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ciout_unlock:
19562306a36Sopenharmony_ci	mutex_unlock(&kvm->arch.config_lock);
19662306a36Sopenharmony_ci	return r;
19762306a36Sopenharmony_ci}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_cistatic u8 kvm_smccc_filter_get_action(struct kvm *kvm, u32 func_id)
20062306a36Sopenharmony_ci{
20162306a36Sopenharmony_ci	unsigned long idx = func_id;
20262306a36Sopenharmony_ci	void *val;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	if (!test_bit(KVM_ARCH_FLAG_SMCCC_FILTER_CONFIGURED, &kvm->arch.flags))
20562306a36Sopenharmony_ci		return KVM_SMCCC_FILTER_HANDLE;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	/*
20862306a36Sopenharmony_ci	 * But where's the error handling, you say?
20962306a36Sopenharmony_ci	 *
21062306a36Sopenharmony_ci	 * mt_find() returns NULL if no entry was found, which just so happens
21162306a36Sopenharmony_ci	 * to match KVM_SMCCC_FILTER_HANDLE.
21262306a36Sopenharmony_ci	 */
21362306a36Sopenharmony_ci	val = mt_find(&kvm->arch.smccc_filter, &idx, idx);
21462306a36Sopenharmony_ci	return xa_to_value(val);
21562306a36Sopenharmony_ci}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_cistatic u8 kvm_smccc_get_action(struct kvm_vcpu *vcpu, u32 func_id)
21862306a36Sopenharmony_ci{
21962306a36Sopenharmony_ci	/*
22062306a36Sopenharmony_ci	 * Intervening actions in the SMCCC filter take precedence over the
22162306a36Sopenharmony_ci	 * pseudo-firmware register bitmaps.
22262306a36Sopenharmony_ci	 */
22362306a36Sopenharmony_ci	u8 action = kvm_smccc_filter_get_action(vcpu->kvm, func_id);
22462306a36Sopenharmony_ci	if (action != KVM_SMCCC_FILTER_HANDLE)
22562306a36Sopenharmony_ci		return action;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	if (kvm_smccc_test_fw_bmap(vcpu, func_id) ||
22862306a36Sopenharmony_ci	    kvm_smccc_default_allowed(func_id))
22962306a36Sopenharmony_ci		return KVM_SMCCC_FILTER_HANDLE;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	return KVM_SMCCC_FILTER_DENY;
23262306a36Sopenharmony_ci}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_cistatic void kvm_prepare_hypercall_exit(struct kvm_vcpu *vcpu, u32 func_id)
23562306a36Sopenharmony_ci{
23662306a36Sopenharmony_ci	u8 ec = ESR_ELx_EC(kvm_vcpu_get_esr(vcpu));
23762306a36Sopenharmony_ci	struct kvm_run *run = vcpu->run;
23862306a36Sopenharmony_ci	u64 flags = 0;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	if (ec == ESR_ELx_EC_SMC32 || ec == ESR_ELx_EC_SMC64)
24162306a36Sopenharmony_ci		flags |= KVM_HYPERCALL_EXIT_SMC;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	if (!kvm_vcpu_trap_il_is32bit(vcpu))
24462306a36Sopenharmony_ci		flags |= KVM_HYPERCALL_EXIT_16BIT;
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	run->exit_reason = KVM_EXIT_HYPERCALL;
24762306a36Sopenharmony_ci	run->hypercall = (typeof(run->hypercall)) {
24862306a36Sopenharmony_ci		.nr	= func_id,
24962306a36Sopenharmony_ci		.flags	= flags,
25062306a36Sopenharmony_ci	};
25162306a36Sopenharmony_ci}
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ciint kvm_smccc_call_handler(struct kvm_vcpu *vcpu)
25462306a36Sopenharmony_ci{
25562306a36Sopenharmony_ci	struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
25662306a36Sopenharmony_ci	u32 func_id = smccc_get_function(vcpu);
25762306a36Sopenharmony_ci	u64 val[4] = {SMCCC_RET_NOT_SUPPORTED};
25862306a36Sopenharmony_ci	u32 feature;
25962306a36Sopenharmony_ci	u8 action;
26062306a36Sopenharmony_ci	gpa_t gpa;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	action = kvm_smccc_get_action(vcpu, func_id);
26362306a36Sopenharmony_ci	switch (action) {
26462306a36Sopenharmony_ci	case KVM_SMCCC_FILTER_HANDLE:
26562306a36Sopenharmony_ci		break;
26662306a36Sopenharmony_ci	case KVM_SMCCC_FILTER_DENY:
26762306a36Sopenharmony_ci		goto out;
26862306a36Sopenharmony_ci	case KVM_SMCCC_FILTER_FWD_TO_USER:
26962306a36Sopenharmony_ci		kvm_prepare_hypercall_exit(vcpu, func_id);
27062306a36Sopenharmony_ci		return 0;
27162306a36Sopenharmony_ci	default:
27262306a36Sopenharmony_ci		WARN_RATELIMIT(1, "Unhandled SMCCC filter action: %d\n", action);
27362306a36Sopenharmony_ci		goto out;
27462306a36Sopenharmony_ci	}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	switch (func_id) {
27762306a36Sopenharmony_ci	case ARM_SMCCC_VERSION_FUNC_ID:
27862306a36Sopenharmony_ci		val[0] = ARM_SMCCC_VERSION_1_1;
27962306a36Sopenharmony_ci		break;
28062306a36Sopenharmony_ci	case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
28162306a36Sopenharmony_ci		feature = smccc_get_arg1(vcpu);
28262306a36Sopenharmony_ci		switch (feature) {
28362306a36Sopenharmony_ci		case ARM_SMCCC_ARCH_WORKAROUND_1:
28462306a36Sopenharmony_ci			switch (arm64_get_spectre_v2_state()) {
28562306a36Sopenharmony_ci			case SPECTRE_VULNERABLE:
28662306a36Sopenharmony_ci				break;
28762306a36Sopenharmony_ci			case SPECTRE_MITIGATED:
28862306a36Sopenharmony_ci				val[0] = SMCCC_RET_SUCCESS;
28962306a36Sopenharmony_ci				break;
29062306a36Sopenharmony_ci			case SPECTRE_UNAFFECTED:
29162306a36Sopenharmony_ci				val[0] = SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED;
29262306a36Sopenharmony_ci				break;
29362306a36Sopenharmony_ci			}
29462306a36Sopenharmony_ci			break;
29562306a36Sopenharmony_ci		case ARM_SMCCC_ARCH_WORKAROUND_2:
29662306a36Sopenharmony_ci			switch (arm64_get_spectre_v4_state()) {
29762306a36Sopenharmony_ci			case SPECTRE_VULNERABLE:
29862306a36Sopenharmony_ci				break;
29962306a36Sopenharmony_ci			case SPECTRE_MITIGATED:
30062306a36Sopenharmony_ci				/*
30162306a36Sopenharmony_ci				 * SSBS everywhere: Indicate no firmware
30262306a36Sopenharmony_ci				 * support, as the SSBS support will be
30362306a36Sopenharmony_ci				 * indicated to the guest and the default is
30462306a36Sopenharmony_ci				 * safe.
30562306a36Sopenharmony_ci				 *
30662306a36Sopenharmony_ci				 * Otherwise, expose a permanent mitigation
30762306a36Sopenharmony_ci				 * to the guest, and hide SSBS so that the
30862306a36Sopenharmony_ci				 * guest stays protected.
30962306a36Sopenharmony_ci				 */
31062306a36Sopenharmony_ci				if (cpus_have_final_cap(ARM64_SSBS))
31162306a36Sopenharmony_ci					break;
31262306a36Sopenharmony_ci				fallthrough;
31362306a36Sopenharmony_ci			case SPECTRE_UNAFFECTED:
31462306a36Sopenharmony_ci				val[0] = SMCCC_RET_NOT_REQUIRED;
31562306a36Sopenharmony_ci				break;
31662306a36Sopenharmony_ci			}
31762306a36Sopenharmony_ci			break;
31862306a36Sopenharmony_ci		case ARM_SMCCC_ARCH_WORKAROUND_3:
31962306a36Sopenharmony_ci			switch (arm64_get_spectre_bhb_state()) {
32062306a36Sopenharmony_ci			case SPECTRE_VULNERABLE:
32162306a36Sopenharmony_ci				break;
32262306a36Sopenharmony_ci			case SPECTRE_MITIGATED:
32362306a36Sopenharmony_ci				val[0] = SMCCC_RET_SUCCESS;
32462306a36Sopenharmony_ci				break;
32562306a36Sopenharmony_ci			case SPECTRE_UNAFFECTED:
32662306a36Sopenharmony_ci				val[0] = SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED;
32762306a36Sopenharmony_ci				break;
32862306a36Sopenharmony_ci			}
32962306a36Sopenharmony_ci			break;
33062306a36Sopenharmony_ci		case ARM_SMCCC_HV_PV_TIME_FEATURES:
33162306a36Sopenharmony_ci			if (test_bit(KVM_REG_ARM_STD_HYP_BIT_PV_TIME,
33262306a36Sopenharmony_ci				     &smccc_feat->std_hyp_bmap))
33362306a36Sopenharmony_ci				val[0] = SMCCC_RET_SUCCESS;
33462306a36Sopenharmony_ci			break;
33562306a36Sopenharmony_ci		}
33662306a36Sopenharmony_ci		break;
33762306a36Sopenharmony_ci	case ARM_SMCCC_HV_PV_TIME_FEATURES:
33862306a36Sopenharmony_ci		val[0] = kvm_hypercall_pv_features(vcpu);
33962306a36Sopenharmony_ci		break;
34062306a36Sopenharmony_ci	case ARM_SMCCC_HV_PV_TIME_ST:
34162306a36Sopenharmony_ci		gpa = kvm_init_stolen_time(vcpu);
34262306a36Sopenharmony_ci		if (gpa != INVALID_GPA)
34362306a36Sopenharmony_ci			val[0] = gpa;
34462306a36Sopenharmony_ci		break;
34562306a36Sopenharmony_ci	case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
34662306a36Sopenharmony_ci		val[0] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_0;
34762306a36Sopenharmony_ci		val[1] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_1;
34862306a36Sopenharmony_ci		val[2] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_2;
34962306a36Sopenharmony_ci		val[3] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_3;
35062306a36Sopenharmony_ci		break;
35162306a36Sopenharmony_ci	case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
35262306a36Sopenharmony_ci		val[0] = smccc_feat->vendor_hyp_bmap;
35362306a36Sopenharmony_ci		break;
35462306a36Sopenharmony_ci	case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
35562306a36Sopenharmony_ci		kvm_ptp_get_time(vcpu, val);
35662306a36Sopenharmony_ci		break;
35762306a36Sopenharmony_ci	case ARM_SMCCC_TRNG_VERSION:
35862306a36Sopenharmony_ci	case ARM_SMCCC_TRNG_FEATURES:
35962306a36Sopenharmony_ci	case ARM_SMCCC_TRNG_GET_UUID:
36062306a36Sopenharmony_ci	case ARM_SMCCC_TRNG_RND32:
36162306a36Sopenharmony_ci	case ARM_SMCCC_TRNG_RND64:
36262306a36Sopenharmony_ci		return kvm_trng_call(vcpu);
36362306a36Sopenharmony_ci	default:
36462306a36Sopenharmony_ci		return kvm_psci_call(vcpu);
36562306a36Sopenharmony_ci	}
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ciout:
36862306a36Sopenharmony_ci	smccc_set_retval(vcpu, val[0], val[1], val[2], val[3]);
36962306a36Sopenharmony_ci	return 1;
37062306a36Sopenharmony_ci}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_cistatic const u64 kvm_arm_fw_reg_ids[] = {
37362306a36Sopenharmony_ci	KVM_REG_ARM_PSCI_VERSION,
37462306a36Sopenharmony_ci	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1,
37562306a36Sopenharmony_ci	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2,
37662306a36Sopenharmony_ci	KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3,
37762306a36Sopenharmony_ci	KVM_REG_ARM_STD_BMAP,
37862306a36Sopenharmony_ci	KVM_REG_ARM_STD_HYP_BMAP,
37962306a36Sopenharmony_ci	KVM_REG_ARM_VENDOR_HYP_BMAP,
38062306a36Sopenharmony_ci};
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_civoid kvm_arm_init_hypercalls(struct kvm *kvm)
38362306a36Sopenharmony_ci{
38462306a36Sopenharmony_ci	struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES;
38762306a36Sopenharmony_ci	smccc_feat->std_hyp_bmap = KVM_ARM_SMCCC_STD_HYP_FEATURES;
38862306a36Sopenharmony_ci	smccc_feat->vendor_hyp_bmap = KVM_ARM_SMCCC_VENDOR_HYP_FEATURES;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	init_smccc_filter(kvm);
39162306a36Sopenharmony_ci}
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_civoid kvm_arm_teardown_hypercalls(struct kvm *kvm)
39462306a36Sopenharmony_ci{
39562306a36Sopenharmony_ci	mtree_destroy(&kvm->arch.smccc_filter);
39662306a36Sopenharmony_ci}
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ciint kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
39962306a36Sopenharmony_ci{
40062306a36Sopenharmony_ci	return ARRAY_SIZE(kvm_arm_fw_reg_ids);
40162306a36Sopenharmony_ci}
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ciint kvm_arm_copy_fw_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
40462306a36Sopenharmony_ci{
40562306a36Sopenharmony_ci	int i;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(kvm_arm_fw_reg_ids); i++) {
40862306a36Sopenharmony_ci		if (put_user(kvm_arm_fw_reg_ids[i], uindices++))
40962306a36Sopenharmony_ci			return -EFAULT;
41062306a36Sopenharmony_ci	}
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	return 0;
41362306a36Sopenharmony_ci}
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci#define KVM_REG_FEATURE_LEVEL_MASK	GENMASK(3, 0)
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci/*
41862306a36Sopenharmony_ci * Convert the workaround level into an easy-to-compare number, where higher
41962306a36Sopenharmony_ci * values mean better protection.
42062306a36Sopenharmony_ci */
42162306a36Sopenharmony_cistatic int get_kernel_wa_level(u64 regid)
42262306a36Sopenharmony_ci{
42362306a36Sopenharmony_ci	switch (regid) {
42462306a36Sopenharmony_ci	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1:
42562306a36Sopenharmony_ci		switch (arm64_get_spectre_v2_state()) {
42662306a36Sopenharmony_ci		case SPECTRE_VULNERABLE:
42762306a36Sopenharmony_ci			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL;
42862306a36Sopenharmony_ci		case SPECTRE_MITIGATED:
42962306a36Sopenharmony_ci			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_AVAIL;
43062306a36Sopenharmony_ci		case SPECTRE_UNAFFECTED:
43162306a36Sopenharmony_ci			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_REQUIRED;
43262306a36Sopenharmony_ci		}
43362306a36Sopenharmony_ci		return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL;
43462306a36Sopenharmony_ci	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2:
43562306a36Sopenharmony_ci		switch (arm64_get_spectre_v4_state()) {
43662306a36Sopenharmony_ci		case SPECTRE_MITIGATED:
43762306a36Sopenharmony_ci			/*
43862306a36Sopenharmony_ci			 * As for the hypercall discovery, we pretend we
43962306a36Sopenharmony_ci			 * don't have any FW mitigation if SSBS is there at
44062306a36Sopenharmony_ci			 * all times.
44162306a36Sopenharmony_ci			 */
44262306a36Sopenharmony_ci			if (cpus_have_final_cap(ARM64_SSBS))
44362306a36Sopenharmony_ci				return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL;
44462306a36Sopenharmony_ci			fallthrough;
44562306a36Sopenharmony_ci		case SPECTRE_UNAFFECTED:
44662306a36Sopenharmony_ci			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED;
44762306a36Sopenharmony_ci		case SPECTRE_VULNERABLE:
44862306a36Sopenharmony_ci			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL;
44962306a36Sopenharmony_ci		}
45062306a36Sopenharmony_ci		break;
45162306a36Sopenharmony_ci	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
45262306a36Sopenharmony_ci		switch (arm64_get_spectre_bhb_state()) {
45362306a36Sopenharmony_ci		case SPECTRE_VULNERABLE:
45462306a36Sopenharmony_ci			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL;
45562306a36Sopenharmony_ci		case SPECTRE_MITIGATED:
45662306a36Sopenharmony_ci			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_AVAIL;
45762306a36Sopenharmony_ci		case SPECTRE_UNAFFECTED:
45862306a36Sopenharmony_ci			return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_REQUIRED;
45962306a36Sopenharmony_ci		}
46062306a36Sopenharmony_ci		return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL;
46162306a36Sopenharmony_ci	}
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	return -EINVAL;
46462306a36Sopenharmony_ci}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ciint kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
46762306a36Sopenharmony_ci{
46862306a36Sopenharmony_ci	struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
46962306a36Sopenharmony_ci	void __user *uaddr = (void __user *)(long)reg->addr;
47062306a36Sopenharmony_ci	u64 val;
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	switch (reg->id) {
47362306a36Sopenharmony_ci	case KVM_REG_ARM_PSCI_VERSION:
47462306a36Sopenharmony_ci		val = kvm_psci_version(vcpu);
47562306a36Sopenharmony_ci		break;
47662306a36Sopenharmony_ci	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1:
47762306a36Sopenharmony_ci	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2:
47862306a36Sopenharmony_ci	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
47962306a36Sopenharmony_ci		val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK;
48062306a36Sopenharmony_ci		break;
48162306a36Sopenharmony_ci	case KVM_REG_ARM_STD_BMAP:
48262306a36Sopenharmony_ci		val = READ_ONCE(smccc_feat->std_bmap);
48362306a36Sopenharmony_ci		break;
48462306a36Sopenharmony_ci	case KVM_REG_ARM_STD_HYP_BMAP:
48562306a36Sopenharmony_ci		val = READ_ONCE(smccc_feat->std_hyp_bmap);
48662306a36Sopenharmony_ci		break;
48762306a36Sopenharmony_ci	case KVM_REG_ARM_VENDOR_HYP_BMAP:
48862306a36Sopenharmony_ci		val = READ_ONCE(smccc_feat->vendor_hyp_bmap);
48962306a36Sopenharmony_ci		break;
49062306a36Sopenharmony_ci	default:
49162306a36Sopenharmony_ci		return -ENOENT;
49262306a36Sopenharmony_ci	}
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	if (copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id)))
49562306a36Sopenharmony_ci		return -EFAULT;
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	return 0;
49862306a36Sopenharmony_ci}
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_cistatic int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val)
50162306a36Sopenharmony_ci{
50262306a36Sopenharmony_ci	int ret = 0;
50362306a36Sopenharmony_ci	struct kvm *kvm = vcpu->kvm;
50462306a36Sopenharmony_ci	struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat;
50562306a36Sopenharmony_ci	unsigned long *fw_reg_bmap, fw_reg_features;
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	switch (reg_id) {
50862306a36Sopenharmony_ci	case KVM_REG_ARM_STD_BMAP:
50962306a36Sopenharmony_ci		fw_reg_bmap = &smccc_feat->std_bmap;
51062306a36Sopenharmony_ci		fw_reg_features = KVM_ARM_SMCCC_STD_FEATURES;
51162306a36Sopenharmony_ci		break;
51262306a36Sopenharmony_ci	case KVM_REG_ARM_STD_HYP_BMAP:
51362306a36Sopenharmony_ci		fw_reg_bmap = &smccc_feat->std_hyp_bmap;
51462306a36Sopenharmony_ci		fw_reg_features = KVM_ARM_SMCCC_STD_HYP_FEATURES;
51562306a36Sopenharmony_ci		break;
51662306a36Sopenharmony_ci	case KVM_REG_ARM_VENDOR_HYP_BMAP:
51762306a36Sopenharmony_ci		fw_reg_bmap = &smccc_feat->vendor_hyp_bmap;
51862306a36Sopenharmony_ci		fw_reg_features = KVM_ARM_SMCCC_VENDOR_HYP_FEATURES;
51962306a36Sopenharmony_ci		break;
52062306a36Sopenharmony_ci	default:
52162306a36Sopenharmony_ci		return -ENOENT;
52262306a36Sopenharmony_ci	}
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	/* Check for unsupported bit */
52562306a36Sopenharmony_ci	if (val & ~fw_reg_features)
52662306a36Sopenharmony_ci		return -EINVAL;
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	mutex_lock(&kvm->arch.config_lock);
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	if (kvm_vm_has_ran_once(kvm) && val != *fw_reg_bmap) {
53162306a36Sopenharmony_ci		ret = -EBUSY;
53262306a36Sopenharmony_ci		goto out;
53362306a36Sopenharmony_ci	}
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	WRITE_ONCE(*fw_reg_bmap, val);
53662306a36Sopenharmony_ciout:
53762306a36Sopenharmony_ci	mutex_unlock(&kvm->arch.config_lock);
53862306a36Sopenharmony_ci	return ret;
53962306a36Sopenharmony_ci}
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ciint kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
54262306a36Sopenharmony_ci{
54362306a36Sopenharmony_ci	void __user *uaddr = (void __user *)(long)reg->addr;
54462306a36Sopenharmony_ci	u64 val;
54562306a36Sopenharmony_ci	int wa_level;
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	if (KVM_REG_SIZE(reg->id) != sizeof(val))
54862306a36Sopenharmony_ci		return -ENOENT;
54962306a36Sopenharmony_ci	if (copy_from_user(&val, uaddr, KVM_REG_SIZE(reg->id)))
55062306a36Sopenharmony_ci		return -EFAULT;
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	switch (reg->id) {
55362306a36Sopenharmony_ci	case KVM_REG_ARM_PSCI_VERSION:
55462306a36Sopenharmony_ci	{
55562306a36Sopenharmony_ci		bool wants_02;
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci		wants_02 = test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features);
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci		switch (val) {
56062306a36Sopenharmony_ci		case KVM_ARM_PSCI_0_1:
56162306a36Sopenharmony_ci			if (wants_02)
56262306a36Sopenharmony_ci				return -EINVAL;
56362306a36Sopenharmony_ci			vcpu->kvm->arch.psci_version = val;
56462306a36Sopenharmony_ci			return 0;
56562306a36Sopenharmony_ci		case KVM_ARM_PSCI_0_2:
56662306a36Sopenharmony_ci		case KVM_ARM_PSCI_1_0:
56762306a36Sopenharmony_ci		case KVM_ARM_PSCI_1_1:
56862306a36Sopenharmony_ci			if (!wants_02)
56962306a36Sopenharmony_ci				return -EINVAL;
57062306a36Sopenharmony_ci			vcpu->kvm->arch.psci_version = val;
57162306a36Sopenharmony_ci			return 0;
57262306a36Sopenharmony_ci		}
57362306a36Sopenharmony_ci		break;
57462306a36Sopenharmony_ci	}
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1:
57762306a36Sopenharmony_ci	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
57862306a36Sopenharmony_ci		if (val & ~KVM_REG_FEATURE_LEVEL_MASK)
57962306a36Sopenharmony_ci			return -EINVAL;
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci		if (get_kernel_wa_level(reg->id) < val)
58262306a36Sopenharmony_ci			return -EINVAL;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci		return 0;
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2:
58762306a36Sopenharmony_ci		if (val & ~(KVM_REG_FEATURE_LEVEL_MASK |
58862306a36Sopenharmony_ci			    KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED))
58962306a36Sopenharmony_ci			return -EINVAL;
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci		/* The enabled bit must not be set unless the level is AVAIL. */
59262306a36Sopenharmony_ci		if ((val & KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED) &&
59362306a36Sopenharmony_ci		    (val & KVM_REG_FEATURE_LEVEL_MASK) != KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL)
59462306a36Sopenharmony_ci			return -EINVAL;
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci		/*
59762306a36Sopenharmony_ci		 * Map all the possible incoming states to the only two we
59862306a36Sopenharmony_ci		 * really want to deal with.
59962306a36Sopenharmony_ci		 */
60062306a36Sopenharmony_ci		switch (val & KVM_REG_FEATURE_LEVEL_MASK) {
60162306a36Sopenharmony_ci		case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL:
60262306a36Sopenharmony_ci		case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_UNKNOWN:
60362306a36Sopenharmony_ci			wa_level = KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL;
60462306a36Sopenharmony_ci			break;
60562306a36Sopenharmony_ci		case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL:
60662306a36Sopenharmony_ci		case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED:
60762306a36Sopenharmony_ci			wa_level = KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED;
60862306a36Sopenharmony_ci			break;
60962306a36Sopenharmony_ci		default:
61062306a36Sopenharmony_ci			return -EINVAL;
61162306a36Sopenharmony_ci		}
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci		/*
61462306a36Sopenharmony_ci		 * We can deal with NOT_AVAIL on NOT_REQUIRED, but not the
61562306a36Sopenharmony_ci		 * other way around.
61662306a36Sopenharmony_ci		 */
61762306a36Sopenharmony_ci		if (get_kernel_wa_level(reg->id) < wa_level)
61862306a36Sopenharmony_ci			return -EINVAL;
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci		return 0;
62162306a36Sopenharmony_ci	case KVM_REG_ARM_STD_BMAP:
62262306a36Sopenharmony_ci	case KVM_REG_ARM_STD_HYP_BMAP:
62362306a36Sopenharmony_ci	case KVM_REG_ARM_VENDOR_HYP_BMAP:
62462306a36Sopenharmony_ci		return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val);
62562306a36Sopenharmony_ci	default:
62662306a36Sopenharmony_ci		return -ENOENT;
62762306a36Sopenharmony_ci	}
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	return -EINVAL;
63062306a36Sopenharmony_ci}
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ciint kvm_vm_smccc_has_attr(struct kvm *kvm, struct kvm_device_attr *attr)
63362306a36Sopenharmony_ci{
63462306a36Sopenharmony_ci	switch (attr->attr) {
63562306a36Sopenharmony_ci	case KVM_ARM_VM_SMCCC_FILTER:
63662306a36Sopenharmony_ci		return 0;
63762306a36Sopenharmony_ci	default:
63862306a36Sopenharmony_ci		return -ENXIO;
63962306a36Sopenharmony_ci	}
64062306a36Sopenharmony_ci}
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ciint kvm_vm_smccc_set_attr(struct kvm *kvm, struct kvm_device_attr *attr)
64362306a36Sopenharmony_ci{
64462306a36Sopenharmony_ci	void __user *uaddr = (void __user *)attr->addr;
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	switch (attr->attr) {
64762306a36Sopenharmony_ci	case KVM_ARM_VM_SMCCC_FILTER:
64862306a36Sopenharmony_ci		return kvm_smccc_set_filter(kvm, uaddr);
64962306a36Sopenharmony_ci	default:
65062306a36Sopenharmony_ci		return -ENXIO;
65162306a36Sopenharmony_ci	}
65262306a36Sopenharmony_ci}
653