1
From 39bcaed680a5967ae0d6aef96b98e7b8e8f6da60 Mon Sep 17 00:00:00 2001
2
From: "Mian M. Hamayun" <m.hamayun@virtualopensystems.com>
3
Date: Tue, 17 Dec 2013 19:42:30 +0000
4
Subject: [PATCH 19/49] target-arm: Add minimal KVM AArch64 support
6
Add the bare minimum set of functions needed for control of an
9
* minimal get/put register functions which only handle the
10
basic state of the CPU
12
Signed-off-by: Mian M. Hamayun <m.hamayun@virtualopensystems.com>
13
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
14
Message-id: 1385645602-18662-4-git-send-email-peter.maydell@linaro.org
15
[PMM: significantly overhauled; most notably:
16
* code lives in kvm64.c rather than using #ifdefs
17
* support '-cpu host' rather than implicitly using whatever the
18
host's CPU is regardless of what the user requests
19
* fix bug attempting to get/set nonexistent X[31]
20
* fix bug writing 64 bit kernel pstate into uint32_t env field
22
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
23
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
25
target-arm/Makefile.objs | 1 +
26
target-arm/kvm.c | 4 +
27
target-arm/kvm64.c | 204 +++++++++++++++++++++++++++++++++++++++++++++++
28
3 files changed, 209 insertions(+)
29
create mode 100644 target-arm/kvm64.c
31
diff --git a/target-arm/Makefile.objs b/target-arm/Makefile.objs
32
index c9f7944..bc23563 100644
33
--- a/target-arm/Makefile.objs
34
+++ b/target-arm/Makefile.objs
35
@@ -2,6 +2,7 @@ obj-y += arm-semi.o
36
obj-$(CONFIG_SOFTMMU) += machine.o
37
obj-$(CONFIG_KVM) += kvm.o
38
obj-$(call land,$(CONFIG_KVM),$(call lnot,$(TARGET_AARCH64))) += kvm32.o
39
+obj-$(call land,$(CONFIG_KVM),$(TARGET_AARCH64)) += kvm64.o
40
obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
41
obj-y += translate.o op_helper.o helper.o cpu.o
42
obj-y += neon_helper.o iwmmxt_helper.o
43
diff --git a/target-arm/kvm.c b/target-arm/kvm.c
44
index 5cdb3b9..1d2688d 100644
45
--- a/target-arm/kvm.c
46
+++ b/target-arm/kvm.c
47
@@ -128,7 +128,11 @@ static void kvm_arm_host_cpu_initfn(Object *obj)
49
static const TypeInfo host_arm_cpu_type_info = {
50
.name = TYPE_ARM_HOST_CPU,
51
+#ifdef TARGET_AARCH64
52
+ .parent = TYPE_AARCH64_CPU,
54
.parent = TYPE_ARM_CPU,
56
.instance_init = kvm_arm_host_cpu_initfn,
57
.class_init = kvm_arm_host_cpu_class_init,
58
.class_size = sizeof(ARMHostCPUClass),
59
diff --git a/target-arm/kvm64.c b/target-arm/kvm64.c
61
index 0000000..1b7ca90
63
+++ b/target-arm/kvm64.c
66
+ * ARM implementation of KVM hooks, 64 bit specific code
68
+ * Copyright Mian-M. Hamayun 2013, Virtual Open Systems
70
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
71
+ * See the COPYING file in the top-level directory.
76
+#include <sys/types.h>
77
+#include <sys/ioctl.h>
78
+#include <sys/mman.h>
80
+#include <linux/kvm.h>
82
+#include "qemu-common.h"
83
+#include "qemu/timer.h"
84
+#include "sysemu/sysemu.h"
85
+#include "sysemu/kvm.h"
88
+#include "hw/arm/arm.h"
90
+static inline void set_feature(uint64_t *features, int feature)
92
+ *features |= 1ULL << feature;
95
+bool kvm_arm_get_host_cpu_features(ARMHostCPUClass *ahcc)
97
+ /* Identify the feature bits corresponding to the host CPU, and
98
+ * fill out the ARMHostCPUClass fields accordingly. To do this
99
+ * we have to create a scratch VM, create a single CPU inside it,
100
+ * and then query that CPU for the relevant ID registers.
101
+ * For AArch64 we currently don't care about ID registers at
102
+ * all; we just want to know the CPU type.
105
+ uint64_t features = 0;
106
+ /* Old kernels may not know about the PREFERRED_TARGET ioctl: however
107
+ * we know these will only support creating one kind of guest CPU,
108
+ * which is its preferred CPU type. Fortunately these old kernels
109
+ * support only a very limited number of CPUs.
111
+ static const uint32_t cpus_to_try[] = {
112
+ KVM_ARM_TARGET_AEM_V8,
113
+ KVM_ARM_TARGET_FOUNDATION_V8,
114
+ KVM_ARM_TARGET_CORTEX_A57,
115
+ QEMU_KVM_ARM_TARGET_NONE
117
+ struct kvm_vcpu_init init;
119
+ if (!kvm_arm_create_scratch_host_vcpu(cpus_to_try, fdarray, &init)) {
123
+ ahcc->target = init.target;
124
+ ahcc->dtb_compatible = "arm,arm-v8";
126
+ kvm_arm_destroy_scratch_host_vcpu(fdarray);
128
+ /* We can assume any KVM supporting CPU is at least a v8
129
+ * with VFPv4+Neon; this in turn implies most of the other
132
+ set_feature(&features, ARM_FEATURE_V8);
133
+ set_feature(&features, ARM_FEATURE_VFP4);
134
+ set_feature(&features, ARM_FEATURE_NEON);
135
+ set_feature(&features, ARM_FEATURE_AARCH64);
137
+ ahcc->features = features;
142
+int kvm_arch_init_vcpu(CPUState *cs)
144
+ ARMCPU *cpu = ARM_CPU(cs);
145
+ struct kvm_vcpu_init init;
148
+ if (cpu->kvm_target == QEMU_KVM_ARM_TARGET_NONE ||
149
+ !arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
150
+ fprintf(stderr, "KVM is not supported for this guest CPU type\n");
154
+ init.target = cpu->kvm_target;
155
+ memset(init.features, 0, sizeof(init.features));
156
+ if (cpu->start_powered_off) {
157
+ init.features[0] = 1 << KVM_ARM_VCPU_POWER_OFF;
159
+ ret = kvm_vcpu_ioctl(cs, KVM_ARM_VCPU_INIT, &init);
161
+ /* TODO : support for save/restore/reset of system regs via tuple list */
166
+#define AARCH64_CORE_REG(x) (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \
167
+ KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(x))
169
+int kvm_arch_put_registers(CPUState *cs, int level)
171
+ struct kvm_one_reg reg;
176
+ ARMCPU *cpu = ARM_CPU(cs);
177
+ CPUARMState *env = &cpu->env;
179
+ for (i = 0; i < 31; i++) {
180
+ reg.id = AARCH64_CORE_REG(regs.regs[i]);
181
+ reg.addr = (uintptr_t) &env->xregs[i];
182
+ ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®);
188
+ reg.id = AARCH64_CORE_REG(regs.sp);
189
+ reg.addr = (uintptr_t) &env->xregs[31];
190
+ ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®);
195
+ /* Note that KVM thinks pstate is 64 bit but we use a uint32_t */
196
+ val = pstate_read(env);
197
+ reg.id = AARCH64_CORE_REG(regs.pstate);
198
+ reg.addr = (uintptr_t) &val;
199
+ ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®);
204
+ reg.id = AARCH64_CORE_REG(regs.pc);
205
+ reg.addr = (uintptr_t) &env->pc;
206
+ ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®);
221
+int kvm_arch_get_registers(CPUState *cs)
223
+ struct kvm_one_reg reg;
228
+ ARMCPU *cpu = ARM_CPU(cs);
229
+ CPUARMState *env = &cpu->env;
231
+ for (i = 0; i < 31; i++) {
232
+ reg.id = AARCH64_CORE_REG(regs.regs[i]);
233
+ reg.addr = (uintptr_t) &env->xregs[i];
234
+ ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®);
240
+ reg.id = AARCH64_CORE_REG(regs.sp);
241
+ reg.addr = (uintptr_t) &env->xregs[31];
242
+ ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®);
247
+ reg.id = AARCH64_CORE_REG(regs.pstate);
248
+ reg.addr = (uintptr_t) &val;
249
+ ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®);
253
+ pstate_write(env, val);
255
+ reg.id = AARCH64_CORE_REG(regs.pc);
256
+ reg.addr = (uintptr_t) &env->pc;
257
+ ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®);
262
+ /* TODO: other registers */
266
+void kvm_arch_reset_vcpu(CPUState *cs)