xref: /qemu/target/arm/kvm.c (revision 20c83dc9)
1fcf5ef2aSThomas Huth /*
2fcf5ef2aSThomas Huth  * ARM implementation of KVM hooks
3fcf5ef2aSThomas Huth  *
4fcf5ef2aSThomas Huth  * Copyright Christoffer Dall 2009-2010
5fcf5ef2aSThomas Huth  *
6fcf5ef2aSThomas Huth  * This work is licensed under the terms of the GNU GPL, version 2 or later.
7fcf5ef2aSThomas Huth  * See the COPYING file in the top-level directory.
8fcf5ef2aSThomas Huth  *
9fcf5ef2aSThomas Huth  */
10fcf5ef2aSThomas Huth 
11fcf5ef2aSThomas Huth #include "qemu/osdep.h"
12fcf5ef2aSThomas Huth #include <sys/ioctl.h>
13fcf5ef2aSThomas Huth 
14fcf5ef2aSThomas Huth #include <linux/kvm.h>
15fcf5ef2aSThomas Huth 
16fcf5ef2aSThomas Huth #include "qemu/timer.h"
17fcf5ef2aSThomas Huth #include "qemu/error-report.h"
18db725815SMarkus Armbruster #include "qemu/main-loop.h"
19dea101a1SAndrew Jones #include "qom/object.h"
20dea101a1SAndrew Jones #include "qapi/error.h"
21fcf5ef2aSThomas Huth #include "sysemu/sysemu.h"
22fcf5ef2aSThomas Huth #include "sysemu/kvm.h"
23a27382e2SEric Auger #include "sysemu/kvm_int.h"
24fcf5ef2aSThomas Huth #include "kvm_arm.h"
25fcf5ef2aSThomas Huth #include "cpu.h"
26b05c81d2SEric Auger #include "trace.h"
27fcf5ef2aSThomas Huth #include "internals.h"
28b05c81d2SEric Auger #include "hw/pci/pci.h"
29fcf5ef2aSThomas Huth #include "exec/memattrs.h"
30fcf5ef2aSThomas Huth #include "exec/address-spaces.h"
31fcf5ef2aSThomas Huth #include "hw/boards.h"
3264552b6bSMarkus Armbruster #include "hw/irq.h"
33c8f2eb5dSShameer Kolothum #include "qapi/visitor.h"
34fcf5ef2aSThomas Huth #include "qemu/log.h"
35fcf5ef2aSThomas Huth 
36fcf5ef2aSThomas Huth const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
37fcf5ef2aSThomas Huth     KVM_CAP_LAST_INFO
38fcf5ef2aSThomas Huth };
39fcf5ef2aSThomas Huth 
40fcf5ef2aSThomas Huth static bool cap_has_mp_state;
41202ccb6bSDongjiu Geng static bool cap_has_inject_serror_esr;
42694bcaa8SBeata Michalska static bool cap_has_inject_ext_dabt;
43fcf5ef2aSThomas Huth 
44c4487d76SPeter Maydell static ARMHostCPUFeatures arm_host_cpu_features;
45c4487d76SPeter Maydell 
46fcf5ef2aSThomas Huth int kvm_arm_vcpu_init(CPUState *cs)
47fcf5ef2aSThomas Huth {
48fcf5ef2aSThomas Huth     ARMCPU *cpu = ARM_CPU(cs);
49fcf5ef2aSThomas Huth     struct kvm_vcpu_init init;
50fcf5ef2aSThomas Huth 
51fcf5ef2aSThomas Huth     init.target = cpu->kvm_target;
52fcf5ef2aSThomas Huth     memcpy(init.features, cpu->kvm_init_features, sizeof(init.features));
53fcf5ef2aSThomas Huth 
54fcf5ef2aSThomas Huth     return kvm_vcpu_ioctl(cs, KVM_ARM_VCPU_INIT, &init);
55fcf5ef2aSThomas Huth }
56fcf5ef2aSThomas Huth 
5714e99e0fSAndrew Jones int kvm_arm_vcpu_finalize(CPUState *cs, int feature)
5814e99e0fSAndrew Jones {
5914e99e0fSAndrew Jones     return kvm_vcpu_ioctl(cs, KVM_ARM_VCPU_FINALIZE, &feature);
6014e99e0fSAndrew Jones }
6114e99e0fSAndrew Jones 
62202ccb6bSDongjiu Geng void kvm_arm_init_serror_injection(CPUState *cs)
63202ccb6bSDongjiu Geng {
64202ccb6bSDongjiu Geng     cap_has_inject_serror_esr = kvm_check_extension(cs->kvm_state,
65202ccb6bSDongjiu Geng                                     KVM_CAP_ARM_INJECT_SERROR_ESR);
66202ccb6bSDongjiu Geng }
67202ccb6bSDongjiu Geng 
68fcf5ef2aSThomas Huth bool kvm_arm_create_scratch_host_vcpu(const uint32_t *cpus_to_try,
69fcf5ef2aSThomas Huth                                       int *fdarray,
70fcf5ef2aSThomas Huth                                       struct kvm_vcpu_init *init)
71fcf5ef2aSThomas Huth {
720cdb4020SAndrew Jones     int ret = 0, kvmfd = -1, vmfd = -1, cpufd = -1;
73d26f2f93SMarc Zyngier     int max_vm_pa_size;
74fcf5ef2aSThomas Huth 
75448058aaSDaniel P. Berrangé     kvmfd = qemu_open_old("/dev/kvm", O_RDWR);
76fcf5ef2aSThomas Huth     if (kvmfd < 0) {
77fcf5ef2aSThomas Huth         goto err;
78fcf5ef2aSThomas Huth     }
79d26f2f93SMarc Zyngier     max_vm_pa_size = ioctl(kvmfd, KVM_CHECK_EXTENSION, KVM_CAP_ARM_VM_IPA_SIZE);
80d26f2f93SMarc Zyngier     if (max_vm_pa_size < 0) {
81d26f2f93SMarc Zyngier         max_vm_pa_size = 0;
82d26f2f93SMarc Zyngier     }
83bbde13cdSPeter Maydell     do {
84d26f2f93SMarc Zyngier         vmfd = ioctl(kvmfd, KVM_CREATE_VM, max_vm_pa_size);
85bbde13cdSPeter Maydell     } while (vmfd == -1 && errno == EINTR);
86fcf5ef2aSThomas Huth     if (vmfd < 0) {
87fcf5ef2aSThomas Huth         goto err;
88fcf5ef2aSThomas Huth     }
89fcf5ef2aSThomas Huth     cpufd = ioctl(vmfd, KVM_CREATE_VCPU, 0);
90fcf5ef2aSThomas Huth     if (cpufd < 0) {
91fcf5ef2aSThomas Huth         goto err;
92fcf5ef2aSThomas Huth     }
93fcf5ef2aSThomas Huth 
94fcf5ef2aSThomas Huth     if (!init) {
95fcf5ef2aSThomas Huth         /* Caller doesn't want the VCPU to be initialized, so skip it */
96fcf5ef2aSThomas Huth         goto finish;
97fcf5ef2aSThomas Huth     }
98fcf5ef2aSThomas Huth 
990cdb4020SAndrew Jones     if (init->target == -1) {
1000cdb4020SAndrew Jones         struct kvm_vcpu_init preferred;
1010cdb4020SAndrew Jones 
1020cdb4020SAndrew Jones         ret = ioctl(vmfd, KVM_ARM_PREFERRED_TARGET, &preferred);
1030cdb4020SAndrew Jones         if (!ret) {
1040cdb4020SAndrew Jones             init->target = preferred.target;
1050cdb4020SAndrew Jones         }
1060cdb4020SAndrew Jones     }
107fcf5ef2aSThomas Huth     if (ret >= 0) {
108fcf5ef2aSThomas Huth         ret = ioctl(cpufd, KVM_ARM_VCPU_INIT, init);
109fcf5ef2aSThomas Huth         if (ret < 0) {
110fcf5ef2aSThomas Huth             goto err;
111fcf5ef2aSThomas Huth         }
112fcf5ef2aSThomas Huth     } else if (cpus_to_try) {
113fcf5ef2aSThomas Huth         /* Old kernel which doesn't know about the
114fcf5ef2aSThomas Huth          * PREFERRED_TARGET ioctl: we know it will only support
115fcf5ef2aSThomas Huth          * creating one kind of guest CPU which is its preferred
116fcf5ef2aSThomas Huth          * CPU type.
117fcf5ef2aSThomas Huth          */
1180cdb4020SAndrew Jones         struct kvm_vcpu_init try;
1190cdb4020SAndrew Jones 
120fcf5ef2aSThomas Huth         while (*cpus_to_try != QEMU_KVM_ARM_TARGET_NONE) {
1210cdb4020SAndrew Jones             try.target = *cpus_to_try++;
1220cdb4020SAndrew Jones             memcpy(try.features, init->features, sizeof(init->features));
1230cdb4020SAndrew Jones             ret = ioctl(cpufd, KVM_ARM_VCPU_INIT, &try);
124fcf5ef2aSThomas Huth             if (ret >= 0) {
125fcf5ef2aSThomas Huth                 break;
126fcf5ef2aSThomas Huth             }
127fcf5ef2aSThomas Huth         }
128fcf5ef2aSThomas Huth         if (ret < 0) {
129fcf5ef2aSThomas Huth             goto err;
130fcf5ef2aSThomas Huth         }
1310cdb4020SAndrew Jones         init->target = try.target;
132fcf5ef2aSThomas Huth     } else {
133fcf5ef2aSThomas Huth         /* Treat a NULL cpus_to_try argument the same as an empty
134fcf5ef2aSThomas Huth          * list, which means we will fail the call since this must
135fcf5ef2aSThomas Huth          * be an old kernel which doesn't support PREFERRED_TARGET.
136fcf5ef2aSThomas Huth          */
137fcf5ef2aSThomas Huth         goto err;
138fcf5ef2aSThomas Huth     }
139fcf5ef2aSThomas Huth 
140fcf5ef2aSThomas Huth finish:
141fcf5ef2aSThomas Huth     fdarray[0] = kvmfd;
142fcf5ef2aSThomas Huth     fdarray[1] = vmfd;
143fcf5ef2aSThomas Huth     fdarray[2] = cpufd;
144fcf5ef2aSThomas Huth 
145fcf5ef2aSThomas Huth     return true;
146fcf5ef2aSThomas Huth 
147fcf5ef2aSThomas Huth err:
148fcf5ef2aSThomas Huth     if (cpufd >= 0) {
149fcf5ef2aSThomas Huth         close(cpufd);
150fcf5ef2aSThomas Huth     }
151fcf5ef2aSThomas Huth     if (vmfd >= 0) {
152fcf5ef2aSThomas Huth         close(vmfd);
153fcf5ef2aSThomas Huth     }
154fcf5ef2aSThomas Huth     if (kvmfd >= 0) {
155fcf5ef2aSThomas Huth         close(kvmfd);
156fcf5ef2aSThomas Huth     }
157fcf5ef2aSThomas Huth 
158fcf5ef2aSThomas Huth     return false;
159fcf5ef2aSThomas Huth }
160fcf5ef2aSThomas Huth 
161fcf5ef2aSThomas Huth void kvm_arm_destroy_scratch_host_vcpu(int *fdarray)
162fcf5ef2aSThomas Huth {
163fcf5ef2aSThomas Huth     int i;
164fcf5ef2aSThomas Huth 
165fcf5ef2aSThomas Huth     for (i = 2; i >= 0; i--) {
166fcf5ef2aSThomas Huth         close(fdarray[i]);
167fcf5ef2aSThomas Huth     }
168fcf5ef2aSThomas Huth }
169fcf5ef2aSThomas Huth 
170c4487d76SPeter Maydell void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu)
171fcf5ef2aSThomas Huth {
172c4487d76SPeter Maydell     CPUARMState *env = &cpu->env;
173fcf5ef2aSThomas Huth 
174c4487d76SPeter Maydell     if (!arm_host_cpu_features.dtb_compatible) {
175c4487d76SPeter Maydell         if (!kvm_enabled() ||
176c4487d76SPeter Maydell             !kvm_arm_get_host_cpu_features(&arm_host_cpu_features)) {
177c4487d76SPeter Maydell             /* We can't report this error yet, so flag that we need to
178c4487d76SPeter Maydell              * in arm_cpu_realizefn().
179fcf5ef2aSThomas Huth              */
180c4487d76SPeter Maydell             cpu->kvm_target = QEMU_KVM_ARM_TARGET_NONE;
181c4487d76SPeter Maydell             cpu->host_cpu_probe_failed = true;
182c4487d76SPeter Maydell             return;
183fcf5ef2aSThomas Huth         }
184fcf5ef2aSThomas Huth     }
185fcf5ef2aSThomas Huth 
186c4487d76SPeter Maydell     cpu->kvm_target = arm_host_cpu_features.target;
187c4487d76SPeter Maydell     cpu->dtb_compatible = arm_host_cpu_features.dtb_compatible;
1884674097cSRichard Henderson     cpu->isar = arm_host_cpu_features.isar;
189c4487d76SPeter Maydell     env->features = arm_host_cpu_features.features;
190c4487d76SPeter Maydell }
191c4487d76SPeter Maydell 
192dea101a1SAndrew Jones static bool kvm_no_adjvtime_get(Object *obj, Error **errp)
193dea101a1SAndrew Jones {
194dea101a1SAndrew Jones     return !ARM_CPU(obj)->kvm_adjvtime;
195dea101a1SAndrew Jones }
196dea101a1SAndrew Jones 
197dea101a1SAndrew Jones static void kvm_no_adjvtime_set(Object *obj, bool value, Error **errp)
198dea101a1SAndrew Jones {
199dea101a1SAndrew Jones     ARM_CPU(obj)->kvm_adjvtime = !value;
200dea101a1SAndrew Jones }
201dea101a1SAndrew Jones 
20268970d1eSAndrew Jones static bool kvm_steal_time_get(Object *obj, Error **errp)
20368970d1eSAndrew Jones {
20468970d1eSAndrew Jones     return ARM_CPU(obj)->kvm_steal_time != ON_OFF_AUTO_OFF;
20568970d1eSAndrew Jones }
20668970d1eSAndrew Jones 
20768970d1eSAndrew Jones static void kvm_steal_time_set(Object *obj, bool value, Error **errp)
20868970d1eSAndrew Jones {
20968970d1eSAndrew Jones     ARM_CPU(obj)->kvm_steal_time = value ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF;
21068970d1eSAndrew Jones }
21168970d1eSAndrew Jones 
212dea101a1SAndrew Jones /* KVM VCPU properties should be prefixed with "kvm-". */
213dea101a1SAndrew Jones void kvm_arm_add_vcpu_properties(Object *obj)
214dea101a1SAndrew Jones {
2159e6f8d8aSfangying     ARMCPU *cpu = ARM_CPU(obj);
2169e6f8d8aSfangying     CPUARMState *env = &cpu->env;
217dea101a1SAndrew Jones 
2189e6f8d8aSfangying     if (arm_feature(env, ARM_FEATURE_GENERIC_TIMER)) {
2199e6f8d8aSfangying         cpu->kvm_adjvtime = true;
220dea101a1SAndrew Jones         object_property_add_bool(obj, "kvm-no-adjvtime", kvm_no_adjvtime_get,
221d2623129SMarkus Armbruster                                  kvm_no_adjvtime_set);
222dea101a1SAndrew Jones         object_property_set_description(obj, "kvm-no-adjvtime",
223dea101a1SAndrew Jones                                         "Set on to disable the adjustment of "
224dea101a1SAndrew Jones                                         "the virtual counter. VM stopped time "
2257eecec7dSMarkus Armbruster                                         "will be counted.");
226dea101a1SAndrew Jones     }
22768970d1eSAndrew Jones 
22868970d1eSAndrew Jones     cpu->kvm_steal_time = ON_OFF_AUTO_AUTO;
22968970d1eSAndrew Jones     object_property_add_bool(obj, "kvm-steal-time", kvm_steal_time_get,
23068970d1eSAndrew Jones                              kvm_steal_time_set);
23168970d1eSAndrew Jones     object_property_set_description(obj, "kvm-steal-time",
23268970d1eSAndrew Jones                                     "Set off to disable KVM steal time.");
2339e6f8d8aSfangying }
234dea101a1SAndrew Jones 
2357d20e681SPhilippe Mathieu-Daudé bool kvm_arm_pmu_supported(void)
236ae502508SAndrew Jones {
2377d20e681SPhilippe Mathieu-Daudé     return kvm_check_extension(kvm_state, KVM_CAP_ARM_PMU_V3);
238ae502508SAndrew Jones }
239ae502508SAndrew Jones 
240bcb902a1SAndrew Jones int kvm_arm_get_max_vm_ipa_size(MachineState *ms, bool *fixed_ipa)
241a27382e2SEric Auger {
242a27382e2SEric Auger     KVMState *s = KVM_STATE(ms->accelerator);
243a27382e2SEric Auger     int ret;
244a27382e2SEric Auger 
245a27382e2SEric Auger     ret = kvm_check_extension(s, KVM_CAP_ARM_VM_IPA_SIZE);
246bcb902a1SAndrew Jones     *fixed_ipa = ret <= 0;
247bcb902a1SAndrew Jones 
248a27382e2SEric Auger     return ret > 0 ? ret : 40;
249a27382e2SEric Auger }
250a27382e2SEric Auger 
2515e0d6590SAkihiko Odaki int kvm_arch_get_default_type(MachineState *ms)
2525e0d6590SAkihiko Odaki {
2531ab445afSAkihiko Odaki     bool fixed_ipa;
2541ab445afSAkihiko Odaki     int size = kvm_arm_get_max_vm_ipa_size(ms, &fixed_ipa);
2551ab445afSAkihiko Odaki     return fixed_ipa ? 0 : size;
2565e0d6590SAkihiko Odaki }
2575e0d6590SAkihiko Odaki 
258fcf5ef2aSThomas Huth int kvm_arch_init(MachineState *ms, KVMState *s)
259fcf5ef2aSThomas Huth {
260fff9f555SEric Auger     int ret = 0;
261fcf5ef2aSThomas Huth     /* For ARM interrupt delivery is always asynchronous,
262fcf5ef2aSThomas Huth      * whether we are using an in-kernel VGIC or not.
263fcf5ef2aSThomas Huth      */
264fcf5ef2aSThomas Huth     kvm_async_interrupts_allowed = true;
265fcf5ef2aSThomas Huth 
2665d721b78SAlexander Graf     /*
2675d721b78SAlexander Graf      * PSCI wakes up secondary cores, so we always need to
2685d721b78SAlexander Graf      * have vCPUs waiting in kernel space
2695d721b78SAlexander Graf      */
2705d721b78SAlexander Graf     kvm_halt_in_kernel_allowed = true;
2715d721b78SAlexander Graf 
272fcf5ef2aSThomas Huth     cap_has_mp_state = kvm_check_extension(s, KVM_CAP_MP_STATE);
273fcf5ef2aSThomas Huth 
274fff9f555SEric Auger     if (ms->smp.cpus > 256 &&
275fff9f555SEric Auger         !kvm_check_extension(s, KVM_CAP_ARM_IRQ_LINE_LAYOUT_2)) {
276fff9f555SEric Auger         error_report("Using more than 256 vcpus requires a host kernel "
277fff9f555SEric Auger                      "with KVM_CAP_ARM_IRQ_LINE_LAYOUT_2");
278fff9f555SEric Auger         ret = -EINVAL;
279fff9f555SEric Auger     }
280fff9f555SEric Auger 
281694bcaa8SBeata Michalska     if (kvm_check_extension(s, KVM_CAP_ARM_NISV_TO_USER)) {
282694bcaa8SBeata Michalska         if (kvm_vm_enable_cap(s, KVM_CAP_ARM_NISV_TO_USER, 0)) {
283694bcaa8SBeata Michalska             error_report("Failed to enable KVM_CAP_ARM_NISV_TO_USER cap");
284694bcaa8SBeata Michalska         } else {
285694bcaa8SBeata Michalska             /* Set status for supporting the external dabt injection */
286694bcaa8SBeata Michalska             cap_has_inject_ext_dabt = kvm_check_extension(s,
287694bcaa8SBeata Michalska                                     KVM_CAP_ARM_INJECT_EXT_DABT);
288694bcaa8SBeata Michalska         }
289694bcaa8SBeata Michalska     }
290694bcaa8SBeata Michalska 
291c8f2eb5dSShameer Kolothum     if (s->kvm_eager_split_size) {
292c8f2eb5dSShameer Kolothum         uint32_t sizes;
293c8f2eb5dSShameer Kolothum 
294c8f2eb5dSShameer Kolothum         sizes = kvm_vm_check_extension(s, KVM_CAP_ARM_SUPPORTED_BLOCK_SIZES);
295c8f2eb5dSShameer Kolothum         if (!sizes) {
296c8f2eb5dSShameer Kolothum             s->kvm_eager_split_size = 0;
297c8f2eb5dSShameer Kolothum             warn_report("Eager Page Split support not available");
298c8f2eb5dSShameer Kolothum         } else if (!(s->kvm_eager_split_size & sizes)) {
299c8f2eb5dSShameer Kolothum             error_report("Eager Page Split requested chunk size not valid");
300c8f2eb5dSShameer Kolothum             ret = -EINVAL;
301c8f2eb5dSShameer Kolothum         } else {
302c8f2eb5dSShameer Kolothum             ret = kvm_vm_enable_cap(s, KVM_CAP_ARM_EAGER_SPLIT_CHUNK_SIZE, 0,
303c8f2eb5dSShameer Kolothum                                     s->kvm_eager_split_size);
304c8f2eb5dSShameer Kolothum             if (ret < 0) {
305c8f2eb5dSShameer Kolothum                 error_report("Enabling of Eager Page Split failed: %s",
306c8f2eb5dSShameer Kolothum                              strerror(-ret));
307c8f2eb5dSShameer Kolothum             }
308c8f2eb5dSShameer Kolothum         }
309c8f2eb5dSShameer Kolothum     }
310c8f2eb5dSShameer Kolothum 
311dd2157d2SRichard Henderson     max_hw_wps = kvm_check_extension(s, KVM_CAP_GUEST_DEBUG_HW_WPS);
312dd2157d2SRichard Henderson     hw_watchpoints = g_array_sized_new(true, true,
313dd2157d2SRichard Henderson                                        sizeof(HWWatchpoint), max_hw_wps);
314dd2157d2SRichard Henderson 
315dd2157d2SRichard Henderson     max_hw_bps = kvm_check_extension(s, KVM_CAP_GUEST_DEBUG_HW_BPS);
316dd2157d2SRichard Henderson     hw_breakpoints = g_array_sized_new(true, true,
317dd2157d2SRichard Henderson                                        sizeof(HWBreakpoint), max_hw_bps);
318ad5c6ddeSAkihiko Odaki 
319fff9f555SEric Auger     return ret;
320fcf5ef2aSThomas Huth }
321fcf5ef2aSThomas Huth 
322fcf5ef2aSThomas Huth unsigned long kvm_arch_vcpu_id(CPUState *cpu)
323fcf5ef2aSThomas Huth {
324fcf5ef2aSThomas Huth     return cpu->cpu_index;
325fcf5ef2aSThomas Huth }
326fcf5ef2aSThomas Huth 
327fcf5ef2aSThomas Huth /* We track all the KVM devices which need their memory addresses
328fcf5ef2aSThomas Huth  * passing to the kernel in a list of these structures.
329fcf5ef2aSThomas Huth  * When board init is complete we run through the list and
330fcf5ef2aSThomas Huth  * tell the kernel the base addresses of the memory regions.
331fcf5ef2aSThomas Huth  * We use a MemoryListener to track mapping and unmapping of
332fcf5ef2aSThomas Huth  * the regions during board creation, so the board models don't
333fcf5ef2aSThomas Huth  * need to do anything special for the KVM case.
33419d1bd0bSEric Auger  *
33519d1bd0bSEric Auger  * Sometimes the address must be OR'ed with some other fields
33619d1bd0bSEric Auger  * (for example for KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION).
33719d1bd0bSEric Auger  * @kda_addr_ormask aims at storing the value of those fields.
338fcf5ef2aSThomas Huth  */
339fcf5ef2aSThomas Huth typedef struct KVMDevice {
340fcf5ef2aSThomas Huth     struct kvm_arm_device_addr kda;
341fcf5ef2aSThomas Huth     struct kvm_device_attr kdattr;
34219d1bd0bSEric Auger     uint64_t kda_addr_ormask;
343fcf5ef2aSThomas Huth     MemoryRegion *mr;
344fcf5ef2aSThomas Huth     QSLIST_ENTRY(KVMDevice) entries;
345fcf5ef2aSThomas Huth     int dev_fd;
346fcf5ef2aSThomas Huth } KVMDevice;
347fcf5ef2aSThomas Huth 
348b58deb34SPaolo Bonzini static QSLIST_HEAD(, KVMDevice) kvm_devices_head;
349fcf5ef2aSThomas Huth 
350fcf5ef2aSThomas Huth static void kvm_arm_devlistener_add(MemoryListener *listener,
351fcf5ef2aSThomas Huth                                     MemoryRegionSection *section)
352fcf5ef2aSThomas Huth {
353fcf5ef2aSThomas Huth     KVMDevice *kd;
354fcf5ef2aSThomas Huth 
355fcf5ef2aSThomas Huth     QSLIST_FOREACH(kd, &kvm_devices_head, entries) {
356fcf5ef2aSThomas Huth         if (section->mr == kd->mr) {
357fcf5ef2aSThomas Huth             kd->kda.addr = section->offset_within_address_space;
358fcf5ef2aSThomas Huth         }
359fcf5ef2aSThomas Huth     }
360fcf5ef2aSThomas Huth }
361fcf5ef2aSThomas Huth 
362fcf5ef2aSThomas Huth static void kvm_arm_devlistener_del(MemoryListener *listener,
363fcf5ef2aSThomas Huth                                     MemoryRegionSection *section)
364fcf5ef2aSThomas Huth {
365fcf5ef2aSThomas Huth     KVMDevice *kd;
366fcf5ef2aSThomas Huth 
367fcf5ef2aSThomas Huth     QSLIST_FOREACH(kd, &kvm_devices_head, entries) {
368fcf5ef2aSThomas Huth         if (section->mr == kd->mr) {
369fcf5ef2aSThomas Huth             kd->kda.addr = -1;
370fcf5ef2aSThomas Huth         }
371fcf5ef2aSThomas Huth     }
372fcf5ef2aSThomas Huth }
373fcf5ef2aSThomas Huth 
374fcf5ef2aSThomas Huth static MemoryListener devlistener = {
375142518bdSPeter Xu     .name = "kvm-arm",
376fcf5ef2aSThomas Huth     .region_add = kvm_arm_devlistener_add,
377fcf5ef2aSThomas Huth     .region_del = kvm_arm_devlistener_del,
37814a868c6SIsaku Yamahata     .priority = MEMORY_LISTENER_PRIORITY_MIN,
379fcf5ef2aSThomas Huth };
380fcf5ef2aSThomas Huth 
381fcf5ef2aSThomas Huth static void kvm_arm_set_device_addr(KVMDevice *kd)
382fcf5ef2aSThomas Huth {
383fcf5ef2aSThomas Huth     struct kvm_device_attr *attr = &kd->kdattr;
384fcf5ef2aSThomas Huth     int ret;
385fcf5ef2aSThomas Huth 
386fcf5ef2aSThomas Huth     /* If the device control API is available and we have a device fd on the
387fcf5ef2aSThomas Huth      * KVMDevice struct, let's use the newer API
388fcf5ef2aSThomas Huth      */
389fcf5ef2aSThomas Huth     if (kd->dev_fd >= 0) {
390fcf5ef2aSThomas Huth         uint64_t addr = kd->kda.addr;
39119d1bd0bSEric Auger 
39219d1bd0bSEric Auger         addr |= kd->kda_addr_ormask;
393fcf5ef2aSThomas Huth         attr->addr = (uintptr_t)&addr;
394fcf5ef2aSThomas Huth         ret = kvm_device_ioctl(kd->dev_fd, KVM_SET_DEVICE_ATTR, attr);
395fcf5ef2aSThomas Huth     } else {
396fcf5ef2aSThomas Huth         ret = kvm_vm_ioctl(kvm_state, KVM_ARM_SET_DEVICE_ADDR, &kd->kda);
397fcf5ef2aSThomas Huth     }
398fcf5ef2aSThomas Huth 
399fcf5ef2aSThomas Huth     if (ret < 0) {
400fcf5ef2aSThomas Huth         fprintf(stderr, "Failed to set device address: %s\n",
401fcf5ef2aSThomas Huth                 strerror(-ret));
402fcf5ef2aSThomas Huth         abort();
403fcf5ef2aSThomas Huth     }
404fcf5ef2aSThomas Huth }
405fcf5ef2aSThomas Huth 
406fcf5ef2aSThomas Huth static void kvm_arm_machine_init_done(Notifier *notifier, void *data)
407fcf5ef2aSThomas Huth {
408fcf5ef2aSThomas Huth     KVMDevice *kd, *tkd;
409fcf5ef2aSThomas Huth 
410fcf5ef2aSThomas Huth     QSLIST_FOREACH_SAFE(kd, &kvm_devices_head, entries, tkd) {
411fcf5ef2aSThomas Huth         if (kd->kda.addr != -1) {
412fcf5ef2aSThomas Huth             kvm_arm_set_device_addr(kd);
413fcf5ef2aSThomas Huth         }
414fcf5ef2aSThomas Huth         memory_region_unref(kd->mr);
4155ff9aaabSZheng Xiang         QSLIST_REMOVE_HEAD(&kvm_devices_head, entries);
416fcf5ef2aSThomas Huth         g_free(kd);
417fcf5ef2aSThomas Huth     }
4180bbe4354SPeter Xu     memory_listener_unregister(&devlistener);
419fcf5ef2aSThomas Huth }
420fcf5ef2aSThomas Huth 
421fcf5ef2aSThomas Huth static Notifier notify = {
422fcf5ef2aSThomas Huth     .notify = kvm_arm_machine_init_done,
423fcf5ef2aSThomas Huth };
424fcf5ef2aSThomas Huth 
425fcf5ef2aSThomas Huth void kvm_arm_register_device(MemoryRegion *mr, uint64_t devid, uint64_t group,
42619d1bd0bSEric Auger                              uint64_t attr, int dev_fd, uint64_t addr_ormask)
427fcf5ef2aSThomas Huth {
428fcf5ef2aSThomas Huth     KVMDevice *kd;
429fcf5ef2aSThomas Huth 
430fcf5ef2aSThomas Huth     if (!kvm_irqchip_in_kernel()) {
431fcf5ef2aSThomas Huth         return;
432fcf5ef2aSThomas Huth     }
433fcf5ef2aSThomas Huth 
434fcf5ef2aSThomas Huth     if (QSLIST_EMPTY(&kvm_devices_head)) {
435fcf5ef2aSThomas Huth         memory_listener_register(&devlistener, &address_space_memory);
436fcf5ef2aSThomas Huth         qemu_add_machine_init_done_notifier(&notify);
437fcf5ef2aSThomas Huth     }
438fcf5ef2aSThomas Huth     kd = g_new0(KVMDevice, 1);
439fcf5ef2aSThomas Huth     kd->mr = mr;
440fcf5ef2aSThomas Huth     kd->kda.id = devid;
441fcf5ef2aSThomas Huth     kd->kda.addr = -1;
442fcf5ef2aSThomas Huth     kd->kdattr.flags = 0;
443fcf5ef2aSThomas Huth     kd->kdattr.group = group;
444fcf5ef2aSThomas Huth     kd->kdattr.attr = attr;
445fcf5ef2aSThomas Huth     kd->dev_fd = dev_fd;
44619d1bd0bSEric Auger     kd->kda_addr_ormask = addr_ormask;
447fcf5ef2aSThomas Huth     QSLIST_INSERT_HEAD(&kvm_devices_head, kd, entries);
448fcf5ef2aSThomas Huth     memory_region_ref(kd->mr);
449fcf5ef2aSThomas Huth }
450fcf5ef2aSThomas Huth 
451fcf5ef2aSThomas Huth static int compare_u64(const void *a, const void *b)
452fcf5ef2aSThomas Huth {
453fcf5ef2aSThomas Huth     if (*(uint64_t *)a > *(uint64_t *)b) {
454fcf5ef2aSThomas Huth         return 1;
455fcf5ef2aSThomas Huth     }
456fcf5ef2aSThomas Huth     if (*(uint64_t *)a < *(uint64_t *)b) {
457fcf5ef2aSThomas Huth         return -1;
458fcf5ef2aSThomas Huth     }
459fcf5ef2aSThomas Huth     return 0;
460fcf5ef2aSThomas Huth }
461fcf5ef2aSThomas Huth 
462e5ac4200SAndrew Jones /*
463e5ac4200SAndrew Jones  * cpreg_values are sorted in ascending order by KVM register ID
464e5ac4200SAndrew Jones  * (see kvm_arm_init_cpreg_list). This allows us to cheaply find
465e5ac4200SAndrew Jones  * the storage for a KVM register by ID with a binary search.
466e5ac4200SAndrew Jones  */
467e5ac4200SAndrew Jones static uint64_t *kvm_arm_get_cpreg_ptr(ARMCPU *cpu, uint64_t regidx)
468e5ac4200SAndrew Jones {
469e5ac4200SAndrew Jones     uint64_t *res;
470e5ac4200SAndrew Jones 
471e5ac4200SAndrew Jones     res = bsearch(&regidx, cpu->cpreg_indexes, cpu->cpreg_array_len,
472e5ac4200SAndrew Jones                   sizeof(uint64_t), compare_u64);
473e5ac4200SAndrew Jones     assert(res);
474e5ac4200SAndrew Jones 
475e5ac4200SAndrew Jones     return &cpu->cpreg_values[res - cpu->cpreg_indexes];
476e5ac4200SAndrew Jones }
477e5ac4200SAndrew Jones 
478c8a44709SDongjiu Geng /* Initialize the ARMCPU cpreg list according to the kernel's
479fcf5ef2aSThomas Huth  * definition of what CPU registers it knows about (and throw away
480fcf5ef2aSThomas Huth  * the previous TCG-created cpreg list).
481fcf5ef2aSThomas Huth  */
482fcf5ef2aSThomas Huth int kvm_arm_init_cpreg_list(ARMCPU *cpu)
483fcf5ef2aSThomas Huth {
484fcf5ef2aSThomas Huth     struct kvm_reg_list rl;
485fcf5ef2aSThomas Huth     struct kvm_reg_list *rlp;
486fcf5ef2aSThomas Huth     int i, ret, arraylen;
487fcf5ef2aSThomas Huth     CPUState *cs = CPU(cpu);
488fcf5ef2aSThomas Huth 
489fcf5ef2aSThomas Huth     rl.n = 0;
490fcf5ef2aSThomas Huth     ret = kvm_vcpu_ioctl(cs, KVM_GET_REG_LIST, &rl);
491fcf5ef2aSThomas Huth     if (ret != -E2BIG) {
492fcf5ef2aSThomas Huth         return ret;
493fcf5ef2aSThomas Huth     }
494fcf5ef2aSThomas Huth     rlp = g_malloc(sizeof(struct kvm_reg_list) + rl.n * sizeof(uint64_t));
495fcf5ef2aSThomas Huth     rlp->n = rl.n;
496fcf5ef2aSThomas Huth     ret = kvm_vcpu_ioctl(cs, KVM_GET_REG_LIST, rlp);
497fcf5ef2aSThomas Huth     if (ret) {
498fcf5ef2aSThomas Huth         goto out;
499fcf5ef2aSThomas Huth     }
500fcf5ef2aSThomas Huth     /* Sort the list we get back from the kernel, since cpreg_tuples
501fcf5ef2aSThomas Huth      * must be in strictly ascending order.
502fcf5ef2aSThomas Huth      */
503fcf5ef2aSThomas Huth     qsort(&rlp->reg, rlp->n, sizeof(rlp->reg[0]), compare_u64);
504fcf5ef2aSThomas Huth 
505fcf5ef2aSThomas Huth     for (i = 0, arraylen = 0; i < rlp->n; i++) {
506fcf5ef2aSThomas Huth         if (!kvm_arm_reg_syncs_via_cpreg_list(rlp->reg[i])) {
507fcf5ef2aSThomas Huth             continue;
508fcf5ef2aSThomas Huth         }
509fcf5ef2aSThomas Huth         switch (rlp->reg[i] & KVM_REG_SIZE_MASK) {
510fcf5ef2aSThomas Huth         case KVM_REG_SIZE_U32:
511fcf5ef2aSThomas Huth         case KVM_REG_SIZE_U64:
512fcf5ef2aSThomas Huth             break;
513fcf5ef2aSThomas Huth         default:
514fcf5ef2aSThomas Huth             fprintf(stderr, "Can't handle size of register in kernel list\n");
515fcf5ef2aSThomas Huth             ret = -EINVAL;
516fcf5ef2aSThomas Huth             goto out;
517fcf5ef2aSThomas Huth         }
518fcf5ef2aSThomas Huth 
519fcf5ef2aSThomas Huth         arraylen++;
520fcf5ef2aSThomas Huth     }
521fcf5ef2aSThomas Huth 
522fcf5ef2aSThomas Huth     cpu->cpreg_indexes = g_renew(uint64_t, cpu->cpreg_indexes, arraylen);
523fcf5ef2aSThomas Huth     cpu->cpreg_values = g_renew(uint64_t, cpu->cpreg_values, arraylen);
524fcf5ef2aSThomas Huth     cpu->cpreg_vmstate_indexes = g_renew(uint64_t, cpu->cpreg_vmstate_indexes,
525fcf5ef2aSThomas Huth                                          arraylen);
526fcf5ef2aSThomas Huth     cpu->cpreg_vmstate_values = g_renew(uint64_t, cpu->cpreg_vmstate_values,
527fcf5ef2aSThomas Huth                                         arraylen);
528fcf5ef2aSThomas Huth     cpu->cpreg_array_len = arraylen;
529fcf5ef2aSThomas Huth     cpu->cpreg_vmstate_array_len = arraylen;
530fcf5ef2aSThomas Huth 
531fcf5ef2aSThomas Huth     for (i = 0, arraylen = 0; i < rlp->n; i++) {
532fcf5ef2aSThomas Huth         uint64_t regidx = rlp->reg[i];
533fcf5ef2aSThomas Huth         if (!kvm_arm_reg_syncs_via_cpreg_list(regidx)) {
534fcf5ef2aSThomas Huth             continue;
535fcf5ef2aSThomas Huth         }
536fcf5ef2aSThomas Huth         cpu->cpreg_indexes[arraylen] = regidx;
537fcf5ef2aSThomas Huth         arraylen++;
538fcf5ef2aSThomas Huth     }
539fcf5ef2aSThomas Huth     assert(cpu->cpreg_array_len == arraylen);
540fcf5ef2aSThomas Huth 
541fcf5ef2aSThomas Huth     if (!write_kvmstate_to_list(cpu)) {
542fcf5ef2aSThomas Huth         /* Shouldn't happen unless kernel is inconsistent about
543fcf5ef2aSThomas Huth          * what registers exist.
544fcf5ef2aSThomas Huth          */
545fcf5ef2aSThomas Huth         fprintf(stderr, "Initial read of kernel register state failed\n");
546fcf5ef2aSThomas Huth         ret = -EINVAL;
547fcf5ef2aSThomas Huth         goto out;
548fcf5ef2aSThomas Huth     }
549fcf5ef2aSThomas Huth 
550fcf5ef2aSThomas Huth out:
551fcf5ef2aSThomas Huth     g_free(rlp);
552fcf5ef2aSThomas Huth     return ret;
553fcf5ef2aSThomas Huth }
554fcf5ef2aSThomas Huth 
555fcf5ef2aSThomas Huth bool write_kvmstate_to_list(ARMCPU *cpu)
556fcf5ef2aSThomas Huth {
557fcf5ef2aSThomas Huth     CPUState *cs = CPU(cpu);
558fcf5ef2aSThomas Huth     int i;
559fcf5ef2aSThomas Huth     bool ok = true;
560fcf5ef2aSThomas Huth 
561fcf5ef2aSThomas Huth     for (i = 0; i < cpu->cpreg_array_len; i++) {
562fcf5ef2aSThomas Huth         uint64_t regidx = cpu->cpreg_indexes[i];
563fcf5ef2aSThomas Huth         uint32_t v32;
564fcf5ef2aSThomas Huth         int ret;
565fcf5ef2aSThomas Huth 
566fcf5ef2aSThomas Huth         switch (regidx & KVM_REG_SIZE_MASK) {
567fcf5ef2aSThomas Huth         case KVM_REG_SIZE_U32:
56840d45b85SCornelia Huck             ret = kvm_get_one_reg(cs, regidx, &v32);
569fcf5ef2aSThomas Huth             if (!ret) {
570fcf5ef2aSThomas Huth                 cpu->cpreg_values[i] = v32;
571fcf5ef2aSThomas Huth             }
572fcf5ef2aSThomas Huth             break;
573fcf5ef2aSThomas Huth         case KVM_REG_SIZE_U64:
57440d45b85SCornelia Huck             ret = kvm_get_one_reg(cs, regidx, cpu->cpreg_values + i);
575fcf5ef2aSThomas Huth             break;
576fcf5ef2aSThomas Huth         default:
577d385a605SRichard Henderson             g_assert_not_reached();
578fcf5ef2aSThomas Huth         }
579fcf5ef2aSThomas Huth         if (ret) {
580fcf5ef2aSThomas Huth             ok = false;
581fcf5ef2aSThomas Huth         }
582fcf5ef2aSThomas Huth     }
583fcf5ef2aSThomas Huth     return ok;
584fcf5ef2aSThomas Huth }
585fcf5ef2aSThomas Huth 
586fcf5ef2aSThomas Huth bool write_list_to_kvmstate(ARMCPU *cpu, int level)
587fcf5ef2aSThomas Huth {
588fcf5ef2aSThomas Huth     CPUState *cs = CPU(cpu);
589fcf5ef2aSThomas Huth     int i;
590fcf5ef2aSThomas Huth     bool ok = true;
591fcf5ef2aSThomas Huth 
592fcf5ef2aSThomas Huth     for (i = 0; i < cpu->cpreg_array_len; i++) {
593fcf5ef2aSThomas Huth         uint64_t regidx = cpu->cpreg_indexes[i];
594fcf5ef2aSThomas Huth         uint32_t v32;
595fcf5ef2aSThomas Huth         int ret;
596fcf5ef2aSThomas Huth 
597fcf5ef2aSThomas Huth         if (kvm_arm_cpreg_level(regidx) > level) {
598fcf5ef2aSThomas Huth             continue;
599fcf5ef2aSThomas Huth         }
600fcf5ef2aSThomas Huth 
601fcf5ef2aSThomas Huth         switch (regidx & KVM_REG_SIZE_MASK) {
602fcf5ef2aSThomas Huth         case KVM_REG_SIZE_U32:
603fcf5ef2aSThomas Huth             v32 = cpu->cpreg_values[i];
6046c8b9a74SCornelia Huck             ret = kvm_set_one_reg(cs, regidx, &v32);
605fcf5ef2aSThomas Huth             break;
606fcf5ef2aSThomas Huth         case KVM_REG_SIZE_U64:
6076c8b9a74SCornelia Huck             ret = kvm_set_one_reg(cs, regidx, cpu->cpreg_values + i);
608fcf5ef2aSThomas Huth             break;
609fcf5ef2aSThomas Huth         default:
610d385a605SRichard Henderson             g_assert_not_reached();
611fcf5ef2aSThomas Huth         }
612fcf5ef2aSThomas Huth         if (ret) {
613fcf5ef2aSThomas Huth             /* We might fail for "unknown register" and also for
614fcf5ef2aSThomas Huth              * "you tried to set a register which is constant with
615fcf5ef2aSThomas Huth              * a different value from what it actually contains".
616fcf5ef2aSThomas Huth              */
617fcf5ef2aSThomas Huth             ok = false;
618fcf5ef2aSThomas Huth         }
619fcf5ef2aSThomas Huth     }
620fcf5ef2aSThomas Huth     return ok;
621fcf5ef2aSThomas Huth }
622fcf5ef2aSThomas Huth 
623e5ac4200SAndrew Jones void kvm_arm_cpu_pre_save(ARMCPU *cpu)
624e5ac4200SAndrew Jones {
625e5ac4200SAndrew Jones     /* KVM virtual time adjustment */
626e5ac4200SAndrew Jones     if (cpu->kvm_vtime_dirty) {
627e5ac4200SAndrew Jones         *kvm_arm_get_cpreg_ptr(cpu, KVM_REG_ARM_TIMER_CNT) = cpu->kvm_vtime;
628e5ac4200SAndrew Jones     }
629e5ac4200SAndrew Jones }
630e5ac4200SAndrew Jones 
631e5ac4200SAndrew Jones void kvm_arm_cpu_post_load(ARMCPU *cpu)
632e5ac4200SAndrew Jones {
633e5ac4200SAndrew Jones     /* KVM virtual time adjustment */
634e5ac4200SAndrew Jones     if (cpu->kvm_adjvtime) {
635e5ac4200SAndrew Jones         cpu->kvm_vtime = *kvm_arm_get_cpreg_ptr(cpu, KVM_REG_ARM_TIMER_CNT);
636e5ac4200SAndrew Jones         cpu->kvm_vtime_dirty = true;
637e5ac4200SAndrew Jones     }
638e5ac4200SAndrew Jones }
639e5ac4200SAndrew Jones 
640fcf5ef2aSThomas Huth void kvm_arm_reset_vcpu(ARMCPU *cpu)
641fcf5ef2aSThomas Huth {
642fcf5ef2aSThomas Huth     int ret;
643fcf5ef2aSThomas Huth 
644fcf5ef2aSThomas Huth     /* Re-init VCPU so that all registers are set to
645fcf5ef2aSThomas Huth      * their respective reset values.
646fcf5ef2aSThomas Huth      */
647fcf5ef2aSThomas Huth     ret = kvm_arm_vcpu_init(CPU(cpu));
648fcf5ef2aSThomas Huth     if (ret < 0) {
649fcf5ef2aSThomas Huth         fprintf(stderr, "kvm_arm_vcpu_init failed: %s\n", strerror(-ret));
650fcf5ef2aSThomas Huth         abort();
651fcf5ef2aSThomas Huth     }
652fcf5ef2aSThomas Huth     if (!write_kvmstate_to_list(cpu)) {
653fcf5ef2aSThomas Huth         fprintf(stderr, "write_kvmstate_to_list failed\n");
654fcf5ef2aSThomas Huth         abort();
655fcf5ef2aSThomas Huth     }
656b698e4eeSPeter Maydell     /*
657b698e4eeSPeter Maydell      * Sync the reset values also into the CPUState. This is necessary
658b698e4eeSPeter Maydell      * because the next thing we do will be a kvm_arch_put_registers()
659b698e4eeSPeter Maydell      * which will update the list values from the CPUState before copying
660b698e4eeSPeter Maydell      * the list values back to KVM. It's OK to ignore failure returns here
661b698e4eeSPeter Maydell      * for the same reason we do so in kvm_arch_get_registers().
662b698e4eeSPeter Maydell      */
663b698e4eeSPeter Maydell     write_list_to_cpustate(cpu);
664fcf5ef2aSThomas Huth }
665fcf5ef2aSThomas Huth 
666fcf5ef2aSThomas Huth /*
667fcf5ef2aSThomas Huth  * Update KVM's MP_STATE based on what QEMU thinks it is
668fcf5ef2aSThomas Huth  */
669fcf5ef2aSThomas Huth int kvm_arm_sync_mpstate_to_kvm(ARMCPU *cpu)
670fcf5ef2aSThomas Huth {
671fcf5ef2aSThomas Huth     if (cap_has_mp_state) {
672fcf5ef2aSThomas Huth         struct kvm_mp_state mp_state = {
673062ba099SAlex Bennée             .mp_state = (cpu->power_state == PSCI_OFF) ?
674062ba099SAlex Bennée             KVM_MP_STATE_STOPPED : KVM_MP_STATE_RUNNABLE
675fcf5ef2aSThomas Huth         };
676fcf5ef2aSThomas Huth         int ret = kvm_vcpu_ioctl(CPU(cpu), KVM_SET_MP_STATE, &mp_state);
677fcf5ef2aSThomas Huth         if (ret) {
678fcf5ef2aSThomas Huth             fprintf(stderr, "%s: failed to set MP_STATE %d/%s\n",
679fcf5ef2aSThomas Huth                     __func__, ret, strerror(-ret));
680fcf5ef2aSThomas Huth             return -1;
681fcf5ef2aSThomas Huth         }
682fcf5ef2aSThomas Huth     }
683fcf5ef2aSThomas Huth 
684fcf5ef2aSThomas Huth     return 0;
685fcf5ef2aSThomas Huth }
686fcf5ef2aSThomas Huth 
687fcf5ef2aSThomas Huth /*
688fcf5ef2aSThomas Huth  * Sync the KVM MP_STATE into QEMU
689fcf5ef2aSThomas Huth  */
690fcf5ef2aSThomas Huth int kvm_arm_sync_mpstate_to_qemu(ARMCPU *cpu)
691fcf5ef2aSThomas Huth {
692fcf5ef2aSThomas Huth     if (cap_has_mp_state) {
693fcf5ef2aSThomas Huth         struct kvm_mp_state mp_state;
694fcf5ef2aSThomas Huth         int ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_MP_STATE, &mp_state);
695fcf5ef2aSThomas Huth         if (ret) {
696fcf5ef2aSThomas Huth             fprintf(stderr, "%s: failed to get MP_STATE %d/%s\n",
697fcf5ef2aSThomas Huth                     __func__, ret, strerror(-ret));
698fcf5ef2aSThomas Huth             abort();
699fcf5ef2aSThomas Huth         }
700062ba099SAlex Bennée         cpu->power_state = (mp_state.mp_state == KVM_MP_STATE_STOPPED) ?
701062ba099SAlex Bennée             PSCI_OFF : PSCI_ON;
702fcf5ef2aSThomas Huth     }
703fcf5ef2aSThomas Huth 
704fcf5ef2aSThomas Huth     return 0;
705fcf5ef2aSThomas Huth }
706fcf5ef2aSThomas Huth 
707e5ac4200SAndrew Jones void kvm_arm_get_virtual_time(CPUState *cs)
708e5ac4200SAndrew Jones {
709e5ac4200SAndrew Jones     ARMCPU *cpu = ARM_CPU(cs);
710e5ac4200SAndrew Jones     int ret;
711e5ac4200SAndrew Jones 
712e5ac4200SAndrew Jones     if (cpu->kvm_vtime_dirty) {
713e5ac4200SAndrew Jones         return;
714e5ac4200SAndrew Jones     }
715e5ac4200SAndrew Jones 
71640d45b85SCornelia Huck     ret = kvm_get_one_reg(cs, KVM_REG_ARM_TIMER_CNT, &cpu->kvm_vtime);
717e5ac4200SAndrew Jones     if (ret) {
718e5ac4200SAndrew Jones         error_report("Failed to get KVM_REG_ARM_TIMER_CNT");
719e5ac4200SAndrew Jones         abort();
720e5ac4200SAndrew Jones     }
721e5ac4200SAndrew Jones 
722e5ac4200SAndrew Jones     cpu->kvm_vtime_dirty = true;
723e5ac4200SAndrew Jones }
724e5ac4200SAndrew Jones 
725e5ac4200SAndrew Jones void kvm_arm_put_virtual_time(CPUState *cs)
726e5ac4200SAndrew Jones {
727e5ac4200SAndrew Jones     ARMCPU *cpu = ARM_CPU(cs);
728e5ac4200SAndrew Jones     int ret;
729e5ac4200SAndrew Jones 
730e5ac4200SAndrew Jones     if (!cpu->kvm_vtime_dirty) {
731e5ac4200SAndrew Jones         return;
732e5ac4200SAndrew Jones     }
733e5ac4200SAndrew Jones 
7346c8b9a74SCornelia Huck     ret = kvm_set_one_reg(cs, KVM_REG_ARM_TIMER_CNT, &cpu->kvm_vtime);
735e5ac4200SAndrew Jones     if (ret) {
736e5ac4200SAndrew Jones         error_report("Failed to set KVM_REG_ARM_TIMER_CNT");
737e5ac4200SAndrew Jones         abort();
738e5ac4200SAndrew Jones     }
739e5ac4200SAndrew Jones 
740e5ac4200SAndrew Jones     cpu->kvm_vtime_dirty = false;
741e5ac4200SAndrew Jones }
742e5ac4200SAndrew Jones 
743202ccb6bSDongjiu Geng int kvm_put_vcpu_events(ARMCPU *cpu)
744202ccb6bSDongjiu Geng {
745202ccb6bSDongjiu Geng     CPUARMState *env = &cpu->env;
746202ccb6bSDongjiu Geng     struct kvm_vcpu_events events;
747202ccb6bSDongjiu Geng     int ret;
748202ccb6bSDongjiu Geng 
749202ccb6bSDongjiu Geng     if (!kvm_has_vcpu_events()) {
750202ccb6bSDongjiu Geng         return 0;
751202ccb6bSDongjiu Geng     }
752202ccb6bSDongjiu Geng 
753202ccb6bSDongjiu Geng     memset(&events, 0, sizeof(events));
754202ccb6bSDongjiu Geng     events.exception.serror_pending = env->serror.pending;
755202ccb6bSDongjiu Geng 
756202ccb6bSDongjiu Geng     /* Inject SError to guest with specified syndrome if host kernel
757202ccb6bSDongjiu Geng      * supports it, otherwise inject SError without syndrome.
758202ccb6bSDongjiu Geng      */
759202ccb6bSDongjiu Geng     if (cap_has_inject_serror_esr) {
760202ccb6bSDongjiu Geng         events.exception.serror_has_esr = env->serror.has_esr;
761202ccb6bSDongjiu Geng         events.exception.serror_esr = env->serror.esr;
762202ccb6bSDongjiu Geng     }
763202ccb6bSDongjiu Geng 
764202ccb6bSDongjiu Geng     ret = kvm_vcpu_ioctl(CPU(cpu), KVM_SET_VCPU_EVENTS, &events);
765202ccb6bSDongjiu Geng     if (ret) {
766202ccb6bSDongjiu Geng         error_report("failed to put vcpu events");
767202ccb6bSDongjiu Geng     }
768202ccb6bSDongjiu Geng 
769202ccb6bSDongjiu Geng     return ret;
770202ccb6bSDongjiu Geng }
771202ccb6bSDongjiu Geng 
772202ccb6bSDongjiu Geng int kvm_get_vcpu_events(ARMCPU *cpu)
773202ccb6bSDongjiu Geng {
774202ccb6bSDongjiu Geng     CPUARMState *env = &cpu->env;
775202ccb6bSDongjiu Geng     struct kvm_vcpu_events events;
776202ccb6bSDongjiu Geng     int ret;
777202ccb6bSDongjiu Geng 
778202ccb6bSDongjiu Geng     if (!kvm_has_vcpu_events()) {
779202ccb6bSDongjiu Geng         return 0;
780202ccb6bSDongjiu Geng     }
781202ccb6bSDongjiu Geng 
782202ccb6bSDongjiu Geng     memset(&events, 0, sizeof(events));
783202ccb6bSDongjiu Geng     ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_VCPU_EVENTS, &events);
784202ccb6bSDongjiu Geng     if (ret) {
785202ccb6bSDongjiu Geng         error_report("failed to get vcpu events");
786202ccb6bSDongjiu Geng         return ret;
787202ccb6bSDongjiu Geng     }
788202ccb6bSDongjiu Geng 
789202ccb6bSDongjiu Geng     env->serror.pending = events.exception.serror_pending;
790202ccb6bSDongjiu Geng     env->serror.has_esr = events.exception.serror_has_esr;
791202ccb6bSDongjiu Geng     env->serror.esr = events.exception.serror_esr;
792202ccb6bSDongjiu Geng 
793202ccb6bSDongjiu Geng     return 0;
794202ccb6bSDongjiu Geng }
795202ccb6bSDongjiu Geng 
796*20c83dc9SRichard Henderson #define ARM64_REG_ESR_EL1 ARM64_SYS_REG(3, 0, 5, 2, 0)
797*20c83dc9SRichard Henderson #define ARM64_REG_TCR_EL1 ARM64_SYS_REG(3, 0, 2, 0, 2)
798*20c83dc9SRichard Henderson 
799*20c83dc9SRichard Henderson /*
800*20c83dc9SRichard Henderson  * ESR_EL1
801*20c83dc9SRichard Henderson  * ISS encoding
802*20c83dc9SRichard Henderson  * AARCH64: DFSC,   bits [5:0]
803*20c83dc9SRichard Henderson  * AARCH32:
804*20c83dc9SRichard Henderson  *      TTBCR.EAE == 0
805*20c83dc9SRichard Henderson  *          FS[4]   - DFSR[10]
806*20c83dc9SRichard Henderson  *          FS[3:0] - DFSR[3:0]
807*20c83dc9SRichard Henderson  *      TTBCR.EAE == 1
808*20c83dc9SRichard Henderson  *          FS, bits [5:0]
809*20c83dc9SRichard Henderson  */
810*20c83dc9SRichard Henderson #define ESR_DFSC(aarch64, lpae, v)        \
811*20c83dc9SRichard Henderson     ((aarch64 || (lpae)) ? ((v) & 0x3F)   \
812*20c83dc9SRichard Henderson                : (((v) >> 6) | ((v) & 0x1F)))
813*20c83dc9SRichard Henderson 
814*20c83dc9SRichard Henderson #define ESR_DFSC_EXTABT(aarch64, lpae) \
815*20c83dc9SRichard Henderson     ((aarch64) ? 0x10 : (lpae) ? 0x10 : 0x8)
816*20c83dc9SRichard Henderson 
817*20c83dc9SRichard Henderson /**
818*20c83dc9SRichard Henderson  * kvm_arm_verify_ext_dabt_pending:
819*20c83dc9SRichard Henderson  * @cs: CPUState
820*20c83dc9SRichard Henderson  *
821*20c83dc9SRichard Henderson  * Verify the fault status code wrt the Ext DABT injection
822*20c83dc9SRichard Henderson  *
823*20c83dc9SRichard Henderson  * Returns: true if the fault status code is as expected, false otherwise
824*20c83dc9SRichard Henderson  */
825*20c83dc9SRichard Henderson static bool kvm_arm_verify_ext_dabt_pending(CPUState *cs)
826*20c83dc9SRichard Henderson {
827*20c83dc9SRichard Henderson     uint64_t dfsr_val;
828*20c83dc9SRichard Henderson 
829*20c83dc9SRichard Henderson     if (!kvm_get_one_reg(cs, ARM64_REG_ESR_EL1, &dfsr_val)) {
830*20c83dc9SRichard Henderson         ARMCPU *cpu = ARM_CPU(cs);
831*20c83dc9SRichard Henderson         CPUARMState *env = &cpu->env;
832*20c83dc9SRichard Henderson         int aarch64_mode = arm_feature(env, ARM_FEATURE_AARCH64);
833*20c83dc9SRichard Henderson         int lpae = 0;
834*20c83dc9SRichard Henderson 
835*20c83dc9SRichard Henderson         if (!aarch64_mode) {
836*20c83dc9SRichard Henderson             uint64_t ttbcr;
837*20c83dc9SRichard Henderson 
838*20c83dc9SRichard Henderson             if (!kvm_get_one_reg(cs, ARM64_REG_TCR_EL1, &ttbcr)) {
839*20c83dc9SRichard Henderson                 lpae = arm_feature(env, ARM_FEATURE_LPAE)
840*20c83dc9SRichard Henderson                         && (ttbcr & TTBCR_EAE);
841*20c83dc9SRichard Henderson             }
842*20c83dc9SRichard Henderson         }
843*20c83dc9SRichard Henderson         /*
844*20c83dc9SRichard Henderson          * The verification here is based on the DFSC bits
845*20c83dc9SRichard Henderson          * of the ESR_EL1 reg only
846*20c83dc9SRichard Henderson          */
847*20c83dc9SRichard Henderson          return (ESR_DFSC(aarch64_mode, lpae, dfsr_val) ==
848*20c83dc9SRichard Henderson                 ESR_DFSC_EXTABT(aarch64_mode, lpae));
849*20c83dc9SRichard Henderson     }
850*20c83dc9SRichard Henderson     return false;
851*20c83dc9SRichard Henderson }
852*20c83dc9SRichard Henderson 
853fcf5ef2aSThomas Huth void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run)
854fcf5ef2aSThomas Huth {
8551711bfa5SBeata Michalska     ARMCPU *cpu = ARM_CPU(cs);
8561711bfa5SBeata Michalska     CPUARMState *env = &cpu->env;
8571711bfa5SBeata Michalska 
8581711bfa5SBeata Michalska     if (unlikely(env->ext_dabt_raised)) {
8591711bfa5SBeata Michalska         /*
8601711bfa5SBeata Michalska          * Verifying that the ext DABT has been properly injected,
8611711bfa5SBeata Michalska          * otherwise risking indefinitely re-running the faulting instruction
8621711bfa5SBeata Michalska          * Covering a very narrow case for kernels 5.5..5.5.4
8631711bfa5SBeata Michalska          * when injected abort was misconfigured to be
8641711bfa5SBeata Michalska          * an IMPLEMENTATION DEFINED exception (for 32-bit EL1)
8651711bfa5SBeata Michalska          */
8661711bfa5SBeata Michalska         if (!arm_feature(env, ARM_FEATURE_AARCH64) &&
8671711bfa5SBeata Michalska             unlikely(!kvm_arm_verify_ext_dabt_pending(cs))) {
8681711bfa5SBeata Michalska 
8691711bfa5SBeata Michalska             error_report("Data abort exception with no valid ISS generated by "
8701711bfa5SBeata Michalska                    "guest memory access. KVM unable to emulate faulting "
8711711bfa5SBeata Michalska                    "instruction. Failed to inject an external data abort "
8721711bfa5SBeata Michalska                    "into the guest.");
8731711bfa5SBeata Michalska             abort();
8741711bfa5SBeata Michalska        }
8751711bfa5SBeata Michalska        /* Clear the status */
8761711bfa5SBeata Michalska        env->ext_dabt_raised = 0;
8771711bfa5SBeata Michalska     }
878fcf5ef2aSThomas Huth }
879fcf5ef2aSThomas Huth 
880fcf5ef2aSThomas Huth MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run)
881fcf5ef2aSThomas Huth {
8825d721b78SAlexander Graf     ARMCPU *cpu;
8835d721b78SAlexander Graf     uint32_t switched_level;
8845d721b78SAlexander Graf 
8855d721b78SAlexander Graf     if (kvm_irqchip_in_kernel()) {
8865d721b78SAlexander Graf         /*
8875d721b78SAlexander Graf          * We only need to sync timer states with user-space interrupt
8885d721b78SAlexander Graf          * controllers, so return early and save cycles if we don't.
8895d721b78SAlexander Graf          */
8905d721b78SAlexander Graf         return MEMTXATTRS_UNSPECIFIED;
8915d721b78SAlexander Graf     }
8925d721b78SAlexander Graf 
8935d721b78SAlexander Graf     cpu = ARM_CPU(cs);
8945d721b78SAlexander Graf 
8955d721b78SAlexander Graf     /* Synchronize our shadowed in-kernel device irq lines with the kvm ones */
8965d721b78SAlexander Graf     if (run->s.regs.device_irq_level != cpu->device_irq_level) {
8975d721b78SAlexander Graf         switched_level = cpu->device_irq_level ^ run->s.regs.device_irq_level;
8985d721b78SAlexander Graf 
8995d721b78SAlexander Graf         qemu_mutex_lock_iothread();
9005d721b78SAlexander Graf 
9015d721b78SAlexander Graf         if (switched_level & KVM_ARM_DEV_EL1_VTIMER) {
9025d721b78SAlexander Graf             qemu_set_irq(cpu->gt_timer_outputs[GTIMER_VIRT],
9035d721b78SAlexander Graf                          !!(run->s.regs.device_irq_level &
9045d721b78SAlexander Graf                             KVM_ARM_DEV_EL1_VTIMER));
9055d721b78SAlexander Graf             switched_level &= ~KVM_ARM_DEV_EL1_VTIMER;
9065d721b78SAlexander Graf         }
9075d721b78SAlexander Graf 
9085d721b78SAlexander Graf         if (switched_level & KVM_ARM_DEV_EL1_PTIMER) {
9095d721b78SAlexander Graf             qemu_set_irq(cpu->gt_timer_outputs[GTIMER_PHYS],
9105d721b78SAlexander Graf                          !!(run->s.regs.device_irq_level &
9115d721b78SAlexander Graf                             KVM_ARM_DEV_EL1_PTIMER));
9125d721b78SAlexander Graf             switched_level &= ~KVM_ARM_DEV_EL1_PTIMER;
9135d721b78SAlexander Graf         }
9145d721b78SAlexander Graf 
915b1659527SAndrew Jones         if (switched_level & KVM_ARM_DEV_PMU) {
916b1659527SAndrew Jones             qemu_set_irq(cpu->pmu_interrupt,
917b1659527SAndrew Jones                          !!(run->s.regs.device_irq_level & KVM_ARM_DEV_PMU));
918b1659527SAndrew Jones             switched_level &= ~KVM_ARM_DEV_PMU;
919b1659527SAndrew Jones         }
9205d721b78SAlexander Graf 
9215d721b78SAlexander Graf         if (switched_level) {
9225d721b78SAlexander Graf             qemu_log_mask(LOG_UNIMP, "%s: unhandled in-kernel device IRQ %x\n",
9235d721b78SAlexander Graf                           __func__, switched_level);
9245d721b78SAlexander Graf         }
9255d721b78SAlexander Graf 
9265d721b78SAlexander Graf         /* We also mark unknown levels as processed to not waste cycles */
9275d721b78SAlexander Graf         cpu->device_irq_level = run->s.regs.device_irq_level;
9285d721b78SAlexander Graf         qemu_mutex_unlock_iothread();
9295d721b78SAlexander Graf     }
9305d721b78SAlexander Graf 
931fcf5ef2aSThomas Huth     return MEMTXATTRS_UNSPECIFIED;
932fcf5ef2aSThomas Huth }
933fcf5ef2aSThomas Huth 
934538f0497SPhilippe Mathieu-Daudé void kvm_arm_vm_state_change(void *opaque, bool running, RunState state)
935e5ac4200SAndrew Jones {
936e5ac4200SAndrew Jones     CPUState *cs = opaque;
937e5ac4200SAndrew Jones     ARMCPU *cpu = ARM_CPU(cs);
938e5ac4200SAndrew Jones 
939e5ac4200SAndrew Jones     if (running) {
940e5ac4200SAndrew Jones         if (cpu->kvm_adjvtime) {
941e5ac4200SAndrew Jones             kvm_arm_put_virtual_time(cs);
942e5ac4200SAndrew Jones         }
943e5ac4200SAndrew Jones     } else {
944e5ac4200SAndrew Jones         if (cpu->kvm_adjvtime) {
945e5ac4200SAndrew Jones             kvm_arm_get_virtual_time(cs);
946e5ac4200SAndrew Jones         }
947e5ac4200SAndrew Jones     }
948e5ac4200SAndrew Jones }
949fcf5ef2aSThomas Huth 
950694bcaa8SBeata Michalska /**
951694bcaa8SBeata Michalska  * kvm_arm_handle_dabt_nisv:
952694bcaa8SBeata Michalska  * @cs: CPUState
953694bcaa8SBeata Michalska  * @esr_iss: ISS encoding (limited) for the exception from Data Abort
954694bcaa8SBeata Michalska  *           ISV bit set to '0b0' -> no valid instruction syndrome
955694bcaa8SBeata Michalska  * @fault_ipa: faulting address for the synchronous data abort
956694bcaa8SBeata Michalska  *
957694bcaa8SBeata Michalska  * Returns: 0 if the exception has been handled, < 0 otherwise
958694bcaa8SBeata Michalska  */
959694bcaa8SBeata Michalska static int kvm_arm_handle_dabt_nisv(CPUState *cs, uint64_t esr_iss,
960694bcaa8SBeata Michalska                                     uint64_t fault_ipa)
961694bcaa8SBeata Michalska {
9621711bfa5SBeata Michalska     ARMCPU *cpu = ARM_CPU(cs);
9631711bfa5SBeata Michalska     CPUARMState *env = &cpu->env;
964694bcaa8SBeata Michalska     /*
965694bcaa8SBeata Michalska      * Request KVM to inject the external data abort into the guest
966694bcaa8SBeata Michalska      */
967694bcaa8SBeata Michalska     if (cap_has_inject_ext_dabt) {
968694bcaa8SBeata Michalska         struct kvm_vcpu_events events = { };
969694bcaa8SBeata Michalska         /*
970694bcaa8SBeata Michalska          * The external data abort event will be handled immediately by KVM
971694bcaa8SBeata Michalska          * using the address fault that triggered the exit on given VCPU.
972694bcaa8SBeata Michalska          * Requesting injection of the external data abort does not rely
973694bcaa8SBeata Michalska          * on any other VCPU state. Therefore, in this particular case, the VCPU
974694bcaa8SBeata Michalska          * synchronization can be exceptionally skipped.
975694bcaa8SBeata Michalska          */
976694bcaa8SBeata Michalska         events.exception.ext_dabt_pending = 1;
977694bcaa8SBeata Michalska         /* KVM_CAP_ARM_INJECT_EXT_DABT implies KVM_CAP_VCPU_EVENTS */
9781711bfa5SBeata Michalska         if (!kvm_vcpu_ioctl(cs, KVM_SET_VCPU_EVENTS, &events)) {
9791711bfa5SBeata Michalska             env->ext_dabt_raised = 1;
9801711bfa5SBeata Michalska             return 0;
9811711bfa5SBeata Michalska         }
982694bcaa8SBeata Michalska     } else {
983694bcaa8SBeata Michalska         error_report("Data abort exception triggered by guest memory access "
984694bcaa8SBeata Michalska                      "at physical address: 0x"  TARGET_FMT_lx,
985694bcaa8SBeata Michalska                      (target_ulong)fault_ipa);
986694bcaa8SBeata Michalska         error_printf("KVM unable to emulate faulting instruction.\n");
987694bcaa8SBeata Michalska     }
988694bcaa8SBeata Michalska     return -1;
989694bcaa8SBeata Michalska }
990694bcaa8SBeata Michalska 
991fcf5ef2aSThomas Huth int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
992fcf5ef2aSThomas Huth {
993fcf5ef2aSThomas Huth     int ret = 0;
994fcf5ef2aSThomas Huth 
995fcf5ef2aSThomas Huth     switch (run->exit_reason) {
996fcf5ef2aSThomas Huth     case KVM_EXIT_DEBUG:
997fcf5ef2aSThomas Huth         if (kvm_arm_handle_debug(cs, &run->debug.arch)) {
998fcf5ef2aSThomas Huth             ret = EXCP_DEBUG;
999fcf5ef2aSThomas Huth         } /* otherwise return to guest */
1000fcf5ef2aSThomas Huth         break;
1001694bcaa8SBeata Michalska     case KVM_EXIT_ARM_NISV:
1002694bcaa8SBeata Michalska         /* External DABT with no valid iss to decode */
1003694bcaa8SBeata Michalska         ret = kvm_arm_handle_dabt_nisv(cs, run->arm_nisv.esr_iss,
1004694bcaa8SBeata Michalska                                        run->arm_nisv.fault_ipa);
1005694bcaa8SBeata Michalska         break;
1006fcf5ef2aSThomas Huth     default:
1007fcf5ef2aSThomas Huth         qemu_log_mask(LOG_UNIMP, "%s: un-handled exit reason %d\n",
1008fcf5ef2aSThomas Huth                       __func__, run->exit_reason);
1009fcf5ef2aSThomas Huth         break;
1010fcf5ef2aSThomas Huth     }
1011fcf5ef2aSThomas Huth     return ret;
1012fcf5ef2aSThomas Huth }
1013fcf5ef2aSThomas Huth 
1014fcf5ef2aSThomas Huth bool kvm_arch_stop_on_emulation_error(CPUState *cs)
1015fcf5ef2aSThomas Huth {
1016fcf5ef2aSThomas Huth     return true;
1017fcf5ef2aSThomas Huth }
1018fcf5ef2aSThomas Huth 
1019fcf5ef2aSThomas Huth int kvm_arch_process_async_events(CPUState *cs)
1020fcf5ef2aSThomas Huth {
1021fcf5ef2aSThomas Huth     return 0;
1022fcf5ef2aSThomas Huth }
1023fcf5ef2aSThomas Huth 
1024fcf5ef2aSThomas Huth void kvm_arch_update_guest_debug(CPUState *cs, struct kvm_guest_debug *dbg)
1025fcf5ef2aSThomas Huth {
1026fcf5ef2aSThomas Huth     if (kvm_sw_breakpoints_active(cs)) {
1027fcf5ef2aSThomas Huth         dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP;
1028fcf5ef2aSThomas Huth     }
1029fcf5ef2aSThomas Huth     if (kvm_arm_hw_debug_active(cs)) {
1030fcf5ef2aSThomas Huth         dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_HW;
1031fcf5ef2aSThomas Huth         kvm_arm_copy_hw_debug_data(&dbg->arch);
1032fcf5ef2aSThomas Huth     }
1033fcf5ef2aSThomas Huth }
1034fcf5ef2aSThomas Huth 
1035fcf5ef2aSThomas Huth void kvm_arch_init_irq_routing(KVMState *s)
1036fcf5ef2aSThomas Huth {
1037fcf5ef2aSThomas Huth }
1038fcf5ef2aSThomas Huth 
10394376c40dSPaolo Bonzini int kvm_arch_irqchip_create(KVMState *s)
1040fcf5ef2aSThomas Huth {
10414376c40dSPaolo Bonzini     if (kvm_kernel_irqchip_split()) {
104247c182feSCornelia Huck         error_report("-machine kernel_irqchip=split is not supported on ARM.");
1043fcf5ef2aSThomas Huth         exit(1);
1044fcf5ef2aSThomas Huth     }
1045fcf5ef2aSThomas Huth 
1046fcf5ef2aSThomas Huth     /* If we can create the VGIC using the newer device control API, we
1047fcf5ef2aSThomas Huth      * let the device do this when it initializes itself, otherwise we
1048fcf5ef2aSThomas Huth      * fall back to the old API */
1049fcf5ef2aSThomas Huth     return kvm_check_extension(s, KVM_CAP_DEVICE_CTRL);
1050fcf5ef2aSThomas Huth }
1051fcf5ef2aSThomas Huth 
1052fcf5ef2aSThomas Huth int kvm_arm_vgic_probe(void)
1053fcf5ef2aSThomas Huth {
1054d45efe47SEric Auger     int val = 0;
1055d45efe47SEric Auger 
1056fcf5ef2aSThomas Huth     if (kvm_create_device(kvm_state,
1057fcf5ef2aSThomas Huth                           KVM_DEV_TYPE_ARM_VGIC_V3, true) == 0) {
1058d45efe47SEric Auger         val |= KVM_ARM_VGIC_V3;
1059fcf5ef2aSThomas Huth     }
1060d45efe47SEric Auger     if (kvm_create_device(kvm_state,
1061d45efe47SEric Auger                           KVM_DEV_TYPE_ARM_VGIC_V2, true) == 0) {
1062d45efe47SEric Auger         val |= KVM_ARM_VGIC_V2;
1063d45efe47SEric Auger     }
1064d45efe47SEric Auger     return val;
1065fcf5ef2aSThomas Huth }
1066fcf5ef2aSThomas Huth 
1067f6530926SEric Auger int kvm_arm_set_irq(int cpu, int irqtype, int irq, int level)
1068f6530926SEric Auger {
1069f6530926SEric Auger     int kvm_irq = (irqtype << KVM_ARM_IRQ_TYPE_SHIFT) | irq;
1070f6530926SEric Auger     int cpu_idx1 = cpu % 256;
1071f6530926SEric Auger     int cpu_idx2 = cpu / 256;
1072f6530926SEric Auger 
1073f6530926SEric Auger     kvm_irq |= (cpu_idx1 << KVM_ARM_IRQ_VCPU_SHIFT) |
1074f6530926SEric Auger                (cpu_idx2 << KVM_ARM_IRQ_VCPU2_SHIFT);
1075f6530926SEric Auger 
1076f6530926SEric Auger     return kvm_set_irq(kvm_state, kvm_irq, !!level);
1077f6530926SEric Auger }
1078f6530926SEric Auger 
1079fcf5ef2aSThomas Huth int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route,
1080fcf5ef2aSThomas Huth                              uint64_t address, uint32_t data, PCIDevice *dev)
1081fcf5ef2aSThomas Huth {
1082b05c81d2SEric Auger     AddressSpace *as = pci_device_iommu_address_space(dev);
1083b05c81d2SEric Auger     hwaddr xlat, len, doorbell_gpa;
1084b05c81d2SEric Auger     MemoryRegionSection mrs;
1085b05c81d2SEric Auger     MemoryRegion *mr;
1086b05c81d2SEric Auger 
1087b05c81d2SEric Auger     if (as == &address_space_memory) {
1088fcf5ef2aSThomas Huth         return 0;
1089fcf5ef2aSThomas Huth     }
1090fcf5ef2aSThomas Huth 
1091b05c81d2SEric Auger     /* MSI doorbell address is translated by an IOMMU */
1092b05c81d2SEric Auger 
1093dfa0d9b8SHamza Mahfooz     RCU_READ_LOCK_GUARD();
1094dfa0d9b8SHamza Mahfooz 
1095bc6b1cecSPeter Maydell     mr = address_space_translate(as, address, &xlat, &len, true,
1096bc6b1cecSPeter Maydell                                  MEMTXATTRS_UNSPECIFIED);
1097dfa0d9b8SHamza Mahfooz 
1098b05c81d2SEric Auger     if (!mr) {
1099dfa0d9b8SHamza Mahfooz         return 1;
1100b05c81d2SEric Auger     }
1101dfa0d9b8SHamza Mahfooz 
1102b05c81d2SEric Auger     mrs = memory_region_find(mr, xlat, 1);
1103dfa0d9b8SHamza Mahfooz 
1104b05c81d2SEric Auger     if (!mrs.mr) {
1105dfa0d9b8SHamza Mahfooz         return 1;
1106b05c81d2SEric Auger     }
1107b05c81d2SEric Auger 
1108b05c81d2SEric Auger     doorbell_gpa = mrs.offset_within_address_space;
1109b05c81d2SEric Auger     memory_region_unref(mrs.mr);
1110b05c81d2SEric Auger 
1111b05c81d2SEric Auger     route->u.msi.address_lo = doorbell_gpa;
1112b05c81d2SEric Auger     route->u.msi.address_hi = doorbell_gpa >> 32;
1113b05c81d2SEric Auger 
1114b05c81d2SEric Auger     trace_kvm_arm_fixup_msi_route(address, doorbell_gpa);
1115b05c81d2SEric Auger 
1116dfa0d9b8SHamza Mahfooz     return 0;
1117b05c81d2SEric Auger }
1118b05c81d2SEric Auger 
1119fcf5ef2aSThomas Huth int kvm_arch_add_msi_route_post(struct kvm_irq_routing_entry *route,
1120fcf5ef2aSThomas Huth                                 int vector, PCIDevice *dev)
1121fcf5ef2aSThomas Huth {
1122fcf5ef2aSThomas Huth     return 0;
1123fcf5ef2aSThomas Huth }
1124fcf5ef2aSThomas Huth 
1125fcf5ef2aSThomas Huth int kvm_arch_release_virq_post(int virq)
1126fcf5ef2aSThomas Huth {
1127fcf5ef2aSThomas Huth     return 0;
1128fcf5ef2aSThomas Huth }
1129fcf5ef2aSThomas Huth 
1130fcf5ef2aSThomas Huth int kvm_arch_msi_data_to_gsi(uint32_t data)
1131fcf5ef2aSThomas Huth {
1132fcf5ef2aSThomas Huth     return (data - 32) & 0xffff;
1133fcf5ef2aSThomas Huth }
113492a5199bSTom Lendacky 
113592a5199bSTom Lendacky bool kvm_arch_cpu_check_are_resettable(void)
113692a5199bSTom Lendacky {
113792a5199bSTom Lendacky     return true;
113892a5199bSTom Lendacky }
11393dba0a33SPaolo Bonzini 
1140c8f2eb5dSShameer Kolothum static void kvm_arch_get_eager_split_size(Object *obj, Visitor *v,
1141c8f2eb5dSShameer Kolothum                                           const char *name, void *opaque,
1142c8f2eb5dSShameer Kolothum                                           Error **errp)
1143c8f2eb5dSShameer Kolothum {
1144c8f2eb5dSShameer Kolothum     KVMState *s = KVM_STATE(obj);
1145c8f2eb5dSShameer Kolothum     uint64_t value = s->kvm_eager_split_size;
1146c8f2eb5dSShameer Kolothum 
1147c8f2eb5dSShameer Kolothum     visit_type_size(v, name, &value, errp);
1148c8f2eb5dSShameer Kolothum }
1149c8f2eb5dSShameer Kolothum 
1150c8f2eb5dSShameer Kolothum static void kvm_arch_set_eager_split_size(Object *obj, Visitor *v,
1151c8f2eb5dSShameer Kolothum                                           const char *name, void *opaque,
1152c8f2eb5dSShameer Kolothum                                           Error **errp)
1153c8f2eb5dSShameer Kolothum {
1154c8f2eb5dSShameer Kolothum     KVMState *s = KVM_STATE(obj);
1155c8f2eb5dSShameer Kolothum     uint64_t value;
1156c8f2eb5dSShameer Kolothum 
1157c8f2eb5dSShameer Kolothum     if (s->fd != -1) {
1158c8f2eb5dSShameer Kolothum         error_setg(errp, "Unable to set early-split-size after KVM has been initialized");
1159c8f2eb5dSShameer Kolothum         return;
1160c8f2eb5dSShameer Kolothum     }
1161c8f2eb5dSShameer Kolothum 
1162c8f2eb5dSShameer Kolothum     if (!visit_type_size(v, name, &value, errp)) {
1163c8f2eb5dSShameer Kolothum         return;
1164c8f2eb5dSShameer Kolothum     }
1165c8f2eb5dSShameer Kolothum 
1166c8f2eb5dSShameer Kolothum     if (value && !is_power_of_2(value)) {
1167c8f2eb5dSShameer Kolothum         error_setg(errp, "early-split-size must be a power of two");
1168c8f2eb5dSShameer Kolothum         return;
1169c8f2eb5dSShameer Kolothum     }
1170c8f2eb5dSShameer Kolothum 
1171c8f2eb5dSShameer Kolothum     s->kvm_eager_split_size = value;
1172c8f2eb5dSShameer Kolothum }
1173c8f2eb5dSShameer Kolothum 
11743dba0a33SPaolo Bonzini void kvm_arch_accel_class_init(ObjectClass *oc)
11753dba0a33SPaolo Bonzini {
1176c8f2eb5dSShameer Kolothum     object_class_property_add(oc, "eager-split-size", "size",
1177c8f2eb5dSShameer Kolothum                               kvm_arch_get_eager_split_size,
1178c8f2eb5dSShameer Kolothum                               kvm_arch_set_eager_split_size, NULL, NULL);
1179c8f2eb5dSShameer Kolothum 
1180c8f2eb5dSShameer Kolothum     object_class_property_set_description(oc, "eager-split-size",
1181c8f2eb5dSShameer Kolothum         "Eager Page Split chunk size for hugepages. (default: 0, disabled)");
11823dba0a33SPaolo Bonzini }
1183