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
16 static DECLARE_BITMAP(__kvm_arm_hyp_services, ARM_SMCCC_KVM_NUM_FUNCS) __ro_after_init = { };
17
kvm_init_hyp_services(void)18 void __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
kvm_arm_hyp_service_available(u32 func_id)43 bool 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 }
50 EXPORT_SYMBOL_GPL(kvm_arm_hyp_service_available);
51
52 #ifdef CONFIG_ARM64
kvm_arm_target_impl_cpu_init(void)53 void __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
110 mem_free:
111 memblock_free(target, sizeof(*target) * max_cpus);
112 }
113 #endif
114