18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci// Copyright (C) 2019 Arm Ltd.
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci#include <linux/arm-smccc.h>
58c2ecf20Sopenharmony_ci#include <linux/kvm_host.h>
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <asm/kvm_emulate.h>
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <kvm/arm_hypercalls.h>
108c2ecf20Sopenharmony_ci#include <kvm/arm_psci.h>
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ciint kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
138c2ecf20Sopenharmony_ci{
148c2ecf20Sopenharmony_ci	u32 func_id = smccc_get_function(vcpu);
158c2ecf20Sopenharmony_ci	long val = SMCCC_RET_NOT_SUPPORTED;
168c2ecf20Sopenharmony_ci	u32 feature;
178c2ecf20Sopenharmony_ci	gpa_t gpa;
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci	switch (func_id) {
208c2ecf20Sopenharmony_ci	case ARM_SMCCC_VERSION_FUNC_ID:
218c2ecf20Sopenharmony_ci		val = ARM_SMCCC_VERSION_1_1;
228c2ecf20Sopenharmony_ci		break;
238c2ecf20Sopenharmony_ci	case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
248c2ecf20Sopenharmony_ci		feature = smccc_get_arg1(vcpu);
258c2ecf20Sopenharmony_ci		switch (feature) {
268c2ecf20Sopenharmony_ci		case ARM_SMCCC_ARCH_WORKAROUND_1:
278c2ecf20Sopenharmony_ci			switch (arm64_get_spectre_v2_state()) {
288c2ecf20Sopenharmony_ci			case SPECTRE_VULNERABLE:
298c2ecf20Sopenharmony_ci				break;
308c2ecf20Sopenharmony_ci			case SPECTRE_MITIGATED:
318c2ecf20Sopenharmony_ci				val = SMCCC_RET_SUCCESS;
328c2ecf20Sopenharmony_ci				break;
338c2ecf20Sopenharmony_ci			case SPECTRE_UNAFFECTED:
348c2ecf20Sopenharmony_ci				val = SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED;
358c2ecf20Sopenharmony_ci				break;
368c2ecf20Sopenharmony_ci			}
378c2ecf20Sopenharmony_ci			break;
388c2ecf20Sopenharmony_ci		case ARM_SMCCC_ARCH_WORKAROUND_2:
398c2ecf20Sopenharmony_ci			switch (arm64_get_spectre_v4_state()) {
408c2ecf20Sopenharmony_ci			case SPECTRE_VULNERABLE:
418c2ecf20Sopenharmony_ci				break;
428c2ecf20Sopenharmony_ci			case SPECTRE_MITIGATED:
438c2ecf20Sopenharmony_ci				/*
448c2ecf20Sopenharmony_ci				 * SSBS everywhere: Indicate no firmware
458c2ecf20Sopenharmony_ci				 * support, as the SSBS support will be
468c2ecf20Sopenharmony_ci				 * indicated to the guest and the default is
478c2ecf20Sopenharmony_ci				 * safe.
488c2ecf20Sopenharmony_ci				 *
498c2ecf20Sopenharmony_ci				 * Otherwise, expose a permanent mitigation
508c2ecf20Sopenharmony_ci				 * to the guest, and hide SSBS so that the
518c2ecf20Sopenharmony_ci				 * guest stays protected.
528c2ecf20Sopenharmony_ci				 */
538c2ecf20Sopenharmony_ci				if (cpus_have_final_cap(ARM64_SSBS))
548c2ecf20Sopenharmony_ci					break;
558c2ecf20Sopenharmony_ci				fallthrough;
568c2ecf20Sopenharmony_ci			case SPECTRE_UNAFFECTED:
578c2ecf20Sopenharmony_ci				val = SMCCC_RET_NOT_REQUIRED;
588c2ecf20Sopenharmony_ci				break;
598c2ecf20Sopenharmony_ci			}
608c2ecf20Sopenharmony_ci			break;
618c2ecf20Sopenharmony_ci		case ARM_SMCCC_ARCH_WORKAROUND_3:
628c2ecf20Sopenharmony_ci			switch (arm64_get_spectre_bhb_state()) {
638c2ecf20Sopenharmony_ci			case SPECTRE_VULNERABLE:
648c2ecf20Sopenharmony_ci				break;
658c2ecf20Sopenharmony_ci			case SPECTRE_MITIGATED:
668c2ecf20Sopenharmony_ci				val = SMCCC_RET_SUCCESS;
678c2ecf20Sopenharmony_ci				break;
688c2ecf20Sopenharmony_ci			case SPECTRE_UNAFFECTED:
698c2ecf20Sopenharmony_ci				val = SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED;
708c2ecf20Sopenharmony_ci				break;
718c2ecf20Sopenharmony_ci			}
728c2ecf20Sopenharmony_ci			break;
738c2ecf20Sopenharmony_ci		case ARM_SMCCC_HV_PV_TIME_FEATURES:
748c2ecf20Sopenharmony_ci			val = SMCCC_RET_SUCCESS;
758c2ecf20Sopenharmony_ci			break;
768c2ecf20Sopenharmony_ci		}
778c2ecf20Sopenharmony_ci		break;
788c2ecf20Sopenharmony_ci	case ARM_SMCCC_HV_PV_TIME_FEATURES:
798c2ecf20Sopenharmony_ci		val = kvm_hypercall_pv_features(vcpu);
808c2ecf20Sopenharmony_ci		break;
818c2ecf20Sopenharmony_ci	case ARM_SMCCC_HV_PV_TIME_ST:
828c2ecf20Sopenharmony_ci		gpa = kvm_init_stolen_time(vcpu);
838c2ecf20Sopenharmony_ci		if (gpa != GPA_INVALID)
848c2ecf20Sopenharmony_ci			val = gpa;
858c2ecf20Sopenharmony_ci		break;
868c2ecf20Sopenharmony_ci	default:
878c2ecf20Sopenharmony_ci		return kvm_psci_call(vcpu);
888c2ecf20Sopenharmony_ci	}
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	smccc_set_retval(vcpu, val, 0, 0, 0);
918c2ecf20Sopenharmony_ci	return 1;
928c2ecf20Sopenharmony_ci}
93