1
From 97d36eb8b450a0f1f01c0ae73a1c60b5a85a4e72 Mon Sep 17 00:00:00 2001
2
From: Peter Maydell <peter.maydell@linaro.org>
3
Date: Fri, 22 Nov 2013 17:17:17 +0000
4
Subject: [PATCH 10/49] target-arm: Provide '-cpu host' when running KVM
6
Implement '-cpu host' for ARM when we're using KVM, broadly
7
in line with other KVM-supporting architectures.
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
11
Message-id: 1385140638-10444-11-git-send-email-peter.maydell@linaro.org
13
target-arm/helper.c | 6 ++
14
target-arm/kvm.c | 224 +++++++++++++++++++++++++++++++++++++++++++++++++++
15
target-arm/kvm_arm.h | 55 +++++++++++++
16
3 files changed, 285 insertions(+)
18
diff --git a/target-arm/helper.c b/target-arm/helper.c
19
index 3445813..263dbbf 100644
20
--- a/target-arm/helper.c
21
+++ b/target-arm/helper.c
22
@@ -1842,6 +1842,12 @@ void arm_cpu_list(FILE *f, fprintf_function cpu_fprintf)
23
(*cpu_fprintf)(f, "Available CPUs:\n");
24
g_slist_foreach(list, arm_cpu_list_entry, &s);
27
+ /* The 'host' CPU type is dynamically registered only if KVM is
28
+ * enabled, so we have to special-case it here:
30
+ (*cpu_fprintf)(f, " host (only available in KVM mode)\n");
34
static void arm_cpu_add_definition(gpointer data, gpointer user_data)
35
diff --git a/target-arm/kvm.c b/target-arm/kvm.c
36
index 182db85..f865dac 100644
37
--- a/target-arm/kvm.c
38
+++ b/target-arm/kvm.c
39
@@ -27,12 +27,236 @@ const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
43
+bool kvm_arm_create_scratch_host_vcpu(const uint32_t *cpus_to_try,
45
+ struct kvm_vcpu_init *init)
47
+ int ret, kvmfd = -1, vmfd = -1, cpufd = -1;
49
+ kvmfd = qemu_open("/dev/kvm", O_RDWR);
53
+ vmfd = ioctl(kvmfd, KVM_CREATE_VM, 0);
57
+ cpufd = ioctl(vmfd, KVM_CREATE_VCPU, 0);
62
+ ret = ioctl(vmfd, KVM_ARM_PREFERRED_TARGET, init);
64
+ ret = ioctl(cpufd, KVM_ARM_VCPU_INIT, init);
69
+ /* Old kernel which doesn't know about the
70
+ * PREFERRED_TARGET ioctl: we know it will only support
71
+ * creating one kind of guest CPU which is its preferred
74
+ while (*cpus_to_try != QEMU_KVM_ARM_TARGET_NONE) {
75
+ init->target = *cpus_to_try++;
76
+ memset(init->features, 0, sizeof(init->features));
77
+ ret = ioctl(cpufd, KVM_ARM_VCPU_INIT, init);
107
+void kvm_arm_destroy_scratch_host_vcpu(int *fdarray)
111
+ for (i = 2; i >= 0; i--) {
116
+static inline void set_feature(uint64_t *features, int feature)
118
+ *features |= 1ULL << feature;
121
+bool kvm_arm_get_host_cpu_features(ARMHostCPUClass *ahcc)
123
+ /* Identify the feature bits corresponding to the host CPU, and
124
+ * fill out the ARMHostCPUClass fields accordingly. To do this
125
+ * we have to create a scratch VM, create a single CPU inside it,
126
+ * and then query that CPU for the relevant ID registers.
128
+ int i, ret, fdarray[3];
129
+ uint32_t midr, id_pfr0, id_isar0, mvfr1;
130
+ uint64_t features = 0;
131
+ /* Old kernels may not know about the PREFERRED_TARGET ioctl: however
132
+ * we know these will only support creating one kind of guest CPU,
133
+ * which is its preferred CPU type.
135
+ static const uint32_t cpus_to_try[] = {
136
+ QEMU_KVM_ARM_TARGET_CORTEX_A15,
137
+ QEMU_KVM_ARM_TARGET_NONE
139
+ struct kvm_vcpu_init init;
140
+ struct kvm_one_reg idregs[] = {
142
+ .id = KVM_REG_ARM | KVM_REG_SIZE_U32
143
+ | ENCODE_CP_REG(15, 0, 0, 0, 0, 0),
144
+ .addr = (uintptr_t)&midr,
147
+ .id = KVM_REG_ARM | KVM_REG_SIZE_U32
148
+ | ENCODE_CP_REG(15, 0, 0, 1, 0, 0),
149
+ .addr = (uintptr_t)&id_pfr0,
152
+ .id = KVM_REG_ARM | KVM_REG_SIZE_U32
153
+ | ENCODE_CP_REG(15, 0, 0, 2, 0, 0),
154
+ .addr = (uintptr_t)&id_isar0,
157
+ .id = KVM_REG_ARM | KVM_REG_SIZE_U32
158
+ | KVM_REG_ARM_VFP | KVM_REG_ARM_VFP_MVFR1,
159
+ .addr = (uintptr_t)&mvfr1,
163
+ if (!kvm_arm_create_scratch_host_vcpu(cpus_to_try, fdarray, &init)) {
167
+ ahcc->target = init.target;
169
+ /* This is not strictly blessed by the device tree binding docs yet,
170
+ * but in practice the kernel does not care about this string so
171
+ * there is no point maintaining an KVM_ARM_TARGET_* -> string table.
173
+ ahcc->dtb_compatible = "arm,arm-v7";
175
+ for (i = 0; i < ARRAY_SIZE(idregs); i++) {
176
+ ret = ioctl(fdarray[2], KVM_GET_ONE_REG, &idregs[i]);
182
+ kvm_arm_destroy_scratch_host_vcpu(fdarray);
188
+ /* Now we've retrieved all the register information we can
189
+ * set the feature bits based on the ID register fields.
190
+ * We can assume any KVM supporting CPU is at least a v7
191
+ * with VFPv3, LPAE and the generic timers; this in turn implies
192
+ * most of the other feature bits, but a few must be tested.
194
+ set_feature(&features, ARM_FEATURE_V7);
195
+ set_feature(&features, ARM_FEATURE_VFP3);
196
+ set_feature(&features, ARM_FEATURE_LPAE);
197
+ set_feature(&features, ARM_FEATURE_GENERIC_TIMER);
199
+ switch (extract32(id_isar0, 24, 4)) {
201
+ set_feature(&features, ARM_FEATURE_THUMB_DIV);
204
+ set_feature(&features, ARM_FEATURE_ARM_DIV);
205
+ set_feature(&features, ARM_FEATURE_THUMB_DIV);
211
+ if (extract32(id_pfr0, 12, 4) == 1) {
212
+ set_feature(&features, ARM_FEATURE_THUMB2EE);
214
+ if (extract32(mvfr1, 20, 4) == 1) {
215
+ set_feature(&features, ARM_FEATURE_VFP_FP16);
217
+ if (extract32(mvfr1, 12, 4) == 1) {
218
+ set_feature(&features, ARM_FEATURE_NEON);
220
+ if (extract32(mvfr1, 28, 4) == 1) {
221
+ /* FMAC support implies VFPv4 */
222
+ set_feature(&features, ARM_FEATURE_VFP4);
225
+ ahcc->features = features;
230
+static void kvm_arm_host_cpu_class_init(ObjectClass *oc, void *data)
232
+ ARMHostCPUClass *ahcc = ARM_HOST_CPU_CLASS(oc);
234
+ /* All we really need to set up for the 'host' CPU
235
+ * is the feature bits -- we rely on the fact that the
236
+ * various ID register values in ARMCPU are only used for
239
+ if (!kvm_arm_get_host_cpu_features(ahcc)) {
240
+ fprintf(stderr, "Failed to retrieve host CPU features!\n");
245
+static void kvm_arm_host_cpu_initfn(Object *obj)
247
+ ARMHostCPUClass *ahcc = ARM_HOST_CPU_GET_CLASS(obj);
248
+ ARMCPU *cpu = ARM_CPU(obj);
249
+ CPUARMState *env = &cpu->env;
251
+ cpu->kvm_target = ahcc->target;
252
+ cpu->dtb_compatible = ahcc->dtb_compatible;
253
+ env->features = ahcc->features;
256
+static const TypeInfo host_arm_cpu_type_info = {
257
+ .name = TYPE_ARM_HOST_CPU,
258
+ .parent = TYPE_ARM_CPU,
259
+ .instance_init = kvm_arm_host_cpu_initfn,
260
+ .class_init = kvm_arm_host_cpu_class_init,
261
+ .class_size = sizeof(ARMHostCPUClass),
264
int kvm_arch_init(KVMState *s)
266
/* For ARM interrupt delivery is always asynchronous,
267
* whether we are using an in-kernel VGIC or not.
269
kvm_async_interrupts_allowed = true;
271
+ type_register_static(&host_arm_cpu_type_info);
276
diff --git a/target-arm/kvm_arm.h b/target-arm/kvm_arm.h
277
index 5d14887..cd3d13c 100644
278
--- a/target-arm/kvm_arm.h
279
+++ b/target-arm/kvm_arm.h
280
@@ -62,4 +62,59 @@ bool write_list_to_kvmstate(ARMCPU *cpu);
282
bool write_kvmstate_to_list(ARMCPU *cpu);
286
+ * kvm_arm_create_scratch_host_vcpu:
287
+ * @cpus_to_try: array of QEMU_KVM_ARM_TARGET_* values (terminated with
288
+ * QEMU_KVM_ARM_TARGET_NONE) to try as fallback if the kernel does not
289
+ * know the PREFERRED_TARGET ioctl
290
+ * @fdarray: filled in with kvmfd, vmfd, cpufd file descriptors in that order
291
+ * @init: filled in with the necessary values for creating a host vcpu
293
+ * Create a scratch vcpu in its own VM of the type preferred by the host
294
+ * kernel (as would be used for '-cpu host'), for purposes of probing it
295
+ * for capabilities.
297
+ * Returns: true on success (and fdarray and init are filled in),
298
+ * false on failure (and fdarray and init are not valid).
300
+bool kvm_arm_create_scratch_host_vcpu(const uint32_t *cpus_to_try,
302
+ struct kvm_vcpu_init *init);
305
+ * kvm_arm_destroy_scratch_host_vcpu:
306
+ * @fdarray: array of fds as set up by kvm_arm_create_scratch_host_vcpu
308
+ * Tear down the scratch vcpu created by kvm_arm_create_scratch_host_vcpu.
310
+void kvm_arm_destroy_scratch_host_vcpu(int *fdarray);
312
+#define TYPE_ARM_HOST_CPU "host-" TYPE_ARM_CPU
313
+#define ARM_HOST_CPU_CLASS(klass) \
314
+ OBJECT_CLASS_CHECK(ARMHostCPUClass, (klass), TYPE_ARM_HOST_CPU)
315
+#define ARM_HOST_CPU_GET_CLASS(obj) \
316
+ OBJECT_GET_CLASS(ARMHostCPUClass, (obj), TYPE_ARM_HOST_CPU)
318
+typedef struct ARMHostCPUClass {
320
+ ARMCPUClass parent_class;
325
+ const char *dtb_compatible;
329
+ * kvm_arm_get_host_cpu_features:
330
+ * @ahcc: ARMHostCPUClass to fill in
332
+ * Probe the capabilities of the host kernel's preferred CPU and fill
333
+ * in the ARMHostCPUClass struct accordingly.
335
+bool kvm_arm_get_host_cpu_features(ARMHostCPUClass *ahcc);