~ubuntu-branches/ubuntu/utopic/qemu/utopic

« back to all changes in this revision

Viewing changes to debian/patches/arm64/0010-target-arm-Provide-cpu-host-when-running-KVM.patch

  • Committer: Package Import Robot
  • Author(s): Serge Hallyn, Serge Hallyn, dann frazier
  • Date: 2014-01-10 12:19:08 UTC
  • Revision ID: package-import@ubuntu.com-20140110121908-6lsn06rypqbokbaf
Tags: 1.7.0+dfsg-2ubuntu6
[ Serge Hallyn ]
* add arm64 patchset from upstream.  The three arm virt patches previously
  pushed are in that set, so drop them.

[ dann frazier ]
* Add packaging for qemu-system-aarch64. This package is currently only
  available for arm64, as full software emulation is not yet supported.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
5
 
 
6
Implement '-cpu host' for ARM when we're using KVM, broadly
 
7
in line with other KVM-supporting architectures.
 
8
 
 
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
 
12
---
 
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(+)
 
17
 
 
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);
 
25
     g_slist_free(list);
 
26
+#ifdef CONFIG_KVM
 
27
+    /* The 'host' CPU type is dynamically registered only if KVM is
 
28
+     * enabled, so we have to special-case it here:
 
29
+     */
 
30
+    (*cpu_fprintf)(f, "  host (only available in KVM mode)\n");
 
31
+#endif
 
32
 }
 
33
 
 
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[] = {
 
40
     KVM_CAP_LAST_INFO
 
41
 };
 
42
 
 
43
+bool kvm_arm_create_scratch_host_vcpu(const uint32_t *cpus_to_try,
 
44
+                                      int *fdarray,
 
45
+                                      struct kvm_vcpu_init *init)
 
46
+{
 
47
+    int ret, kvmfd = -1, vmfd = -1, cpufd = -1;
 
48
+
 
49
+    kvmfd = qemu_open("/dev/kvm", O_RDWR);
 
50
+    if (kvmfd < 0) {
 
51
+        goto err;
 
52
+    }
 
53
+    vmfd = ioctl(kvmfd, KVM_CREATE_VM, 0);
 
54
+    if (vmfd < 0) {
 
55
+        goto err;
 
56
+    }
 
57
+    cpufd = ioctl(vmfd, KVM_CREATE_VCPU, 0);
 
58
+    if (cpufd < 0) {
 
59
+        goto err;
 
60
+    }
 
61
+
 
62
+    ret = ioctl(vmfd, KVM_ARM_PREFERRED_TARGET, init);
 
63
+    if (ret >= 0) {
 
64
+        ret = ioctl(cpufd, KVM_ARM_VCPU_INIT, init);
 
65
+        if (ret < 0) {
 
66
+            goto err;
 
67
+        }
 
68
+    } else {
 
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
 
72
+         * CPU type.
 
73
+         */
 
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);
 
78
+            if (ret >= 0) {
 
79
+                break;
 
80
+            }
 
81
+        }
 
82
+        if (ret < 0) {
 
83
+            goto err;
 
84
+        }
 
85
+    }
 
86
+
 
87
+    fdarray[0] = kvmfd;
 
88
+    fdarray[1] = vmfd;
 
89
+    fdarray[2] = cpufd;
 
90
+
 
91
+    return true;
 
92
+
 
93
+err:
 
94
+    if (cpufd >= 0) {
 
95
+        close(cpufd);
 
96
+    }
 
97
+    if (vmfd >= 0) {
 
98
+        close(vmfd);
 
99
+    }
 
100
+    if (kvmfd >= 0) {
 
101
+        close(kvmfd);
 
102
+    }
 
103
+
 
104
+    return false;
 
105
+}
 
106
+
 
107
+void kvm_arm_destroy_scratch_host_vcpu(int *fdarray)
 
108
+{
 
109
+    int i;
 
110
+
 
111
+    for (i = 2; i >= 0; i--) {
 
112
+        close(fdarray[i]);
 
113
+    }
 
114
+}
 
115
+
 
116
+static inline void set_feature(uint64_t *features, int feature)
 
117
+{
 
118
+    *features |= 1ULL << feature;
 
119
+}
 
120
+
 
121
+bool kvm_arm_get_host_cpu_features(ARMHostCPUClass *ahcc)
 
122
+{
 
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.
 
127
+     */
 
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.
 
134
+     */
 
135
+    static const uint32_t cpus_to_try[] = {
 
136
+        QEMU_KVM_ARM_TARGET_CORTEX_A15,
 
137
+        QEMU_KVM_ARM_TARGET_NONE
 
138
+    };
 
139
+    struct kvm_vcpu_init init;
 
140
+    struct kvm_one_reg idregs[] = {
 
141
+        {
 
142
+            .id = KVM_REG_ARM | KVM_REG_SIZE_U32
 
143
+            | ENCODE_CP_REG(15, 0, 0, 0, 0, 0),
 
144
+            .addr = (uintptr_t)&midr,
 
145
+        },
 
146
+        {
 
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,
 
150
+        },
 
151
+        {
 
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,
 
155
+        },
 
156
+        {
 
157
+            .id = KVM_REG_ARM | KVM_REG_SIZE_U32
 
158
+            | KVM_REG_ARM_VFP | KVM_REG_ARM_VFP_MVFR1,
 
159
+            .addr = (uintptr_t)&mvfr1,
 
160
+        },
 
161
+    };
 
162
+
 
163
+    if (!kvm_arm_create_scratch_host_vcpu(cpus_to_try, fdarray, &init)) {
 
164
+        return false;
 
165
+    }
 
166
+
 
167
+    ahcc->target = init.target;
 
168
+
 
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.
 
172
+     */
 
173
+    ahcc->dtb_compatible = "arm,arm-v7";
 
174
+
 
175
+    for (i = 0; i < ARRAY_SIZE(idregs); i++) {
 
176
+        ret = ioctl(fdarray[2], KVM_GET_ONE_REG, &idregs[i]);
 
177
+        if (ret) {
 
178
+            break;
 
179
+        }
 
180
+    }
 
181
+
 
182
+    kvm_arm_destroy_scratch_host_vcpu(fdarray);
 
183
+
 
184
+    if (ret) {
 
185
+        return false;
 
186
+    }
 
187
+
 
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.
 
193
+     */
 
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);
 
198
+
 
199
+    switch (extract32(id_isar0, 24, 4)) {
 
200
+    case 1:
 
201
+        set_feature(&features, ARM_FEATURE_THUMB_DIV);
 
202
+        break;
 
203
+    case 2:
 
204
+        set_feature(&features, ARM_FEATURE_ARM_DIV);
 
205
+        set_feature(&features, ARM_FEATURE_THUMB_DIV);
 
206
+        break;
 
207
+    default:
 
208
+        break;
 
209
+    }
 
210
+
 
211
+    if (extract32(id_pfr0, 12, 4) == 1) {
 
212
+        set_feature(&features, ARM_FEATURE_THUMB2EE);
 
213
+    }
 
214
+    if (extract32(mvfr1, 20, 4) == 1) {
 
215
+        set_feature(&features, ARM_FEATURE_VFP_FP16);
 
216
+    }
 
217
+    if (extract32(mvfr1, 12, 4) == 1) {
 
218
+        set_feature(&features, ARM_FEATURE_NEON);
 
219
+    }
 
220
+    if (extract32(mvfr1, 28, 4) == 1) {
 
221
+        /* FMAC support implies VFPv4 */
 
222
+        set_feature(&features, ARM_FEATURE_VFP4);
 
223
+    }
 
224
+
 
225
+    ahcc->features = features;
 
226
+
 
227
+    return true;
 
228
+}
 
229
+
 
230
+static void kvm_arm_host_cpu_class_init(ObjectClass *oc, void *data)
 
231
+{
 
232
+    ARMHostCPUClass *ahcc = ARM_HOST_CPU_CLASS(oc);
 
233
+
 
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
 
237
+     * TCG CPUs.
 
238
+     */
 
239
+    if (!kvm_arm_get_host_cpu_features(ahcc)) {
 
240
+        fprintf(stderr, "Failed to retrieve host CPU features!\n");
 
241
+        abort();
 
242
+    }
 
243
+}
 
244
+
 
245
+static void kvm_arm_host_cpu_initfn(Object *obj)
 
246
+{
 
247
+    ARMHostCPUClass *ahcc = ARM_HOST_CPU_GET_CLASS(obj);
 
248
+    ARMCPU *cpu = ARM_CPU(obj);
 
249
+    CPUARMState *env = &cpu->env;
 
250
+
 
251
+    cpu->kvm_target = ahcc->target;
 
252
+    cpu->dtb_compatible = ahcc->dtb_compatible;
 
253
+    env->features = ahcc->features;
 
254
+}
 
255
+
 
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),
 
262
+};
 
263
+
 
264
 int kvm_arch_init(KVMState *s)
 
265
 {
 
266
     /* For ARM interrupt delivery is always asynchronous,
 
267
      * whether we are using an in-kernel VGIC or not.
 
268
      */
 
269
     kvm_async_interrupts_allowed = true;
 
270
+
 
271
+    type_register_static(&host_arm_cpu_type_info);
 
272
+
 
273
     return 0;
 
274
 }
 
275
 
 
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);
 
281
  */
 
282
 bool write_kvmstate_to_list(ARMCPU *cpu);
 
283
 
 
284
+#ifdef CONFIG_KVM
 
285
+/**
 
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
 
292
+ *
 
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.
 
296
+ *
 
297
+ * Returns: true on success (and fdarray and init are filled in),
 
298
+ * false on failure (and fdarray and init are not valid).
 
299
+ */
 
300
+bool kvm_arm_create_scratch_host_vcpu(const uint32_t *cpus_to_try,
 
301
+                                      int *fdarray,
 
302
+                                      struct kvm_vcpu_init *init);
 
303
+
 
304
+/**
 
305
+ * kvm_arm_destroy_scratch_host_vcpu:
 
306
+ * @fdarray: array of fds as set up by kvm_arm_create_scratch_host_vcpu
 
307
+ *
 
308
+ * Tear down the scratch vcpu created by kvm_arm_create_scratch_host_vcpu.
 
309
+ */
 
310
+void kvm_arm_destroy_scratch_host_vcpu(int *fdarray);
 
311
+
 
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)
 
317
+
 
318
+typedef struct ARMHostCPUClass {
 
319
+    /*< private >*/
 
320
+    ARMCPUClass parent_class;
 
321
+    /*< public >*/
 
322
+
 
323
+    uint64_t features;
 
324
+    uint32_t target;
 
325
+    const char *dtb_compatible;
 
326
+} ARMHostCPUClass;
 
327
+
 
328
+/**
 
329
+ * kvm_arm_get_host_cpu_features:
 
330
+ * @ahcc: ARMHostCPUClass to fill in
 
331
+ *
 
332
+ * Probe the capabilities of the host kernel's preferred CPU and fill
 
333
+ * in the ARMHostCPUClass struct accordingly.
 
334
+ */
 
335
+bool kvm_arm_get_host_cpu_features(ARMHostCPUClass *ahcc);
 
336
+
 
337
+#endif
 
338
+
 
339
 #endif
 
340
-- 
 
341
1.8.5.2
 
342