File Index
Files and directories
Sign in
FILE

kvm_guest.c

File preview with syntax highlighting.

linux-6.19.14/drivers/firmware/smccc/kvm_guest.c C
  1// SPDX-License-Identifier: GPL-2.0
  2
  3#define pr_fmt(fmt) "smccc: KVM: " fmt
  4
  5#include <linux/arm-smccc.h>
  6#include <linux/bitmap.h>
  7#include <linux/cache.h>
  8#include <linux/kernel.h>
  9#include <linux/memblock.h>
 10#include <linux/string.h>
 11
 12#include <uapi/linux/psci.h>
 13
 14#include <asm/hypervisor.h>
 15
 16static DECLARE_BITMAP(__kvm_arm_hyp_services, ARM_SMCCC_KVM_NUM_FUNCS) __ro_after_init = { };
 17
 18void __init kvm_init_hyp_services(void)
 19{
 20	uuid_t kvm_uuid = ARM_SMCCC_VENDOR_HYP_UID_KVM;
 21	struct arm_smccc_res res;
 22	u32 val[4];
 23
 24	if (!arm_smccc_hypervisor_has_uuid(&kvm_uuid))
 25		return;
 26
 27	memset(&res, 0, sizeof(res));
 28	arm_smccc_1_1_invoke(ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID, &res);
 29
 30	val[0] = lower_32_bits(res.a0);
 31	val[1] = lower_32_bits(res.a1);
 32	val[2] = lower_32_bits(res.a2);
 33	val[3] = lower_32_bits(res.a3);
 34
 35	bitmap_from_arr32(__kvm_arm_hyp_services, val, ARM_SMCCC_KVM_NUM_FUNCS);
 36
 37	pr_info("hypervisor services detected (0x%08lx 0x%08lx 0x%08lx 0x%08lx)\n",
 38		 res.a3, res.a2, res.a1, res.a0);
 39
 40	kvm_arch_init_hyp_services();
 41}
 42
 43bool kvm_arm_hyp_service_available(u32 func_id)
 44{
 45	if (func_id >= ARM_SMCCC_KVM_NUM_FUNCS)
 46		return false;
 47
 48	return test_bit(func_id, __kvm_arm_hyp_services);
 49}
 50EXPORT_SYMBOL_GPL(kvm_arm_hyp_service_available);
 51
 52#ifdef CONFIG_ARM64
 53void  __init kvm_arm_target_impl_cpu_init(void)
 54{
 55	int i;
 56	u32 ver;
 57	u64 max_cpus;
 58	struct arm_smccc_res res;
 59	struct target_impl_cpu *target;
 60
 61	if (!kvm_arm_hyp_service_available(ARM_SMCCC_KVM_FUNC_DISCOVER_IMPL_VER) ||
 62	    !kvm_arm_hyp_service_available(ARM_SMCCC_KVM_FUNC_DISCOVER_IMPL_CPUS))
 63		return;
 64
 65	arm_smccc_1_1_invoke(ARM_SMCCC_VENDOR_HYP_KVM_DISCOVER_IMPL_VER_FUNC_ID,
 66			     0, &res);
 67	if (res.a0 != SMCCC_RET_SUCCESS)
 68		return;
 69
 70	/* Version info is in lower 32 bits and is in SMMCCC_VERSION format */
 71	ver = lower_32_bits(res.a1);
 72	if (PSCI_VERSION_MAJOR(ver) != 1) {
 73		pr_warn("Unsupported target CPU implementation version v%d.%d\n",
 74			PSCI_VERSION_MAJOR(ver), PSCI_VERSION_MINOR(ver));
 75		return;
 76	}
 77
 78	if (!res.a2) {
 79		pr_warn("No target implementation CPUs specified\n");
 80		return;
 81	}
 82
 83	max_cpus = res.a2;
 84	target = memblock_alloc(sizeof(*target) * max_cpus,  __alignof__(*target));
 85	if (!target) {
 86		pr_warn("Not enough memory for struct target_impl_cpu\n");
 87		return;
 88	}
 89
 90	for (i = 0; i < max_cpus; i++) {
 91		arm_smccc_1_1_invoke(ARM_SMCCC_VENDOR_HYP_KVM_DISCOVER_IMPL_CPUS_FUNC_ID,
 92				     i, 0, 0, &res);
 93		if (res.a0 != SMCCC_RET_SUCCESS) {
 94			pr_warn("Discovering target implementation CPUs failed\n");
 95			goto mem_free;
 96		}
 97		target[i].midr = res.a1;
 98		target[i].revidr = res.a2;
 99		target[i].aidr = res.a3;
100	}
101
102	if (!cpu_errata_set_target_impl(max_cpus, target)) {
103		pr_warn("Failed to set target implementation CPUs\n");
104		goto mem_free;
105	}
106
107	pr_info("Number of target implementation CPUs is %lld\n", max_cpus);
108	return;
109
110mem_free:
111	memblock_free(target, sizeof(*target) * max_cpus);
112}
113#endif
~/ Read-only file preview.