xref: /qemu/target/i386/kvm/xen-emu.c (revision f068930277347667125a10e9d8612a585d84738d)
161491cf4SDavid Woodhouse /*
261491cf4SDavid Woodhouse  * Xen HVM emulation support in KVM
361491cf4SDavid Woodhouse  *
461491cf4SDavid Woodhouse  * Copyright © 2019 Oracle and/or its affiliates. All rights reserved.
561491cf4SDavid Woodhouse  * Copyright © 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
661491cf4SDavid Woodhouse  *
761491cf4SDavid Woodhouse  * This work is licensed under the terms of the GNU GPL, version 2 or later.
861491cf4SDavid Woodhouse  * See the COPYING file in the top-level directory.
961491cf4SDavid Woodhouse  *
1061491cf4SDavid Woodhouse  */
1161491cf4SDavid Woodhouse 
1261491cf4SDavid Woodhouse #include "qemu/osdep.h"
1355a3f666SJoao Martins #include "qemu/log.h"
1479b7067dSJoao Martins #include "qemu/main-loop.h"
15fb0fd2ceSJoao Martins #include "hw/xen/xen.h"
1661491cf4SDavid Woodhouse #include "sysemu/kvm_int.h"
1761491cf4SDavid Woodhouse #include "sysemu/kvm_xen.h"
1861491cf4SDavid Woodhouse #include "kvm/kvm_i386.h"
19bedcc139SJoao Martins #include "exec/address-spaces.h"
2061491cf4SDavid Woodhouse #include "xen-emu.h"
2155a3f666SJoao Martins #include "trace.h"
2279b7067dSJoao Martins #include "sysemu/runstate.h"
2361491cf4SDavid Woodhouse 
24110a0ea5SDavid Woodhouse #include "hw/i386/kvm/xen_overlay.h"
25110a0ea5SDavid Woodhouse 
26bedcc139SJoao Martins #include "hw/xen/interface/version.h"
2779b7067dSJoao Martins #include "hw/xen/interface/sched.h"
28fb0fd2ceSJoao Martins #include "hw/xen/interface/memory.h"
29671bfdcdSJoao Martins #include "hw/xen/interface/hvm/hvm_op.h"
30d70bd6a4SJoao Martins #include "hw/xen/interface/vcpu.h"
31fb0fd2ceSJoao Martins 
32fb0fd2ceSJoao Martins #include "xen-compat.h"
33fb0fd2ceSJoao Martins 
34fb0fd2ceSJoao Martins #ifdef TARGET_X86_64
35fb0fd2ceSJoao Martins #define hypercall_compat32(longmode) (!(longmode))
36fb0fd2ceSJoao Martins #else
37fb0fd2ceSJoao Martins #define hypercall_compat32(longmode) (false)
38fb0fd2ceSJoao Martins #endif
39bedcc139SJoao Martins 
40*f0689302SJoao Martins static bool kvm_gva_to_gpa(CPUState *cs, uint64_t gva, uint64_t *gpa,
41*f0689302SJoao Martins                            size_t *len, bool is_write)
42bedcc139SJoao Martins {
43bedcc139SJoao Martins         struct kvm_translation tr = {
44bedcc139SJoao Martins             .linear_address = gva,
45bedcc139SJoao Martins         };
46bedcc139SJoao Martins 
47*f0689302SJoao Martins         if (len) {
48*f0689302SJoao Martins             *len = TARGET_PAGE_SIZE - (gva & ~TARGET_PAGE_MASK);
49*f0689302SJoao Martins         }
50*f0689302SJoao Martins 
51*f0689302SJoao Martins         if (kvm_vcpu_ioctl(cs, KVM_TRANSLATE, &tr) || !tr.valid ||
52*f0689302SJoao Martins             (is_write && !tr.writeable)) {
53*f0689302SJoao Martins             return false;
54*f0689302SJoao Martins         }
55*f0689302SJoao Martins         *gpa = tr.physical_address;
56*f0689302SJoao Martins         return true;
57*f0689302SJoao Martins }
58*f0689302SJoao Martins 
59*f0689302SJoao Martins static int kvm_gva_rw(CPUState *cs, uint64_t gva, void *_buf, size_t sz,
60*f0689302SJoao Martins                       bool is_write)
61*f0689302SJoao Martins {
62*f0689302SJoao Martins     uint8_t *buf = (uint8_t *)_buf;
63*f0689302SJoao Martins     uint64_t gpa;
64*f0689302SJoao Martins     size_t len;
65*f0689302SJoao Martins 
66*f0689302SJoao Martins     while (sz) {
67*f0689302SJoao Martins         if (!kvm_gva_to_gpa(cs, gva, &gpa, &len, is_write)) {
68*f0689302SJoao Martins             return -EFAULT;
69*f0689302SJoao Martins         }
70bedcc139SJoao Martins         if (len > sz) {
71bedcc139SJoao Martins             len = sz;
72bedcc139SJoao Martins         }
73bedcc139SJoao Martins 
74*f0689302SJoao Martins         cpu_physical_memory_rw(gpa, buf, len, is_write);
75bedcc139SJoao Martins 
76bedcc139SJoao Martins         buf += len;
77bedcc139SJoao Martins         sz -= len;
78bedcc139SJoao Martins         gva += len;
79bedcc139SJoao Martins     }
80bedcc139SJoao Martins 
81bedcc139SJoao Martins     return 0;
82bedcc139SJoao Martins }
83bedcc139SJoao Martins 
84bedcc139SJoao Martins static inline int kvm_copy_from_gva(CPUState *cs, uint64_t gva, void *buf,
85bedcc139SJoao Martins                                     size_t sz)
86bedcc139SJoao Martins {
87bedcc139SJoao Martins     return kvm_gva_rw(cs, gva, buf, sz, false);
88bedcc139SJoao Martins }
89bedcc139SJoao Martins 
90bedcc139SJoao Martins static inline int kvm_copy_to_gva(CPUState *cs, uint64_t gva, void *buf,
91bedcc139SJoao Martins                                   size_t sz)
92bedcc139SJoao Martins {
93bedcc139SJoao Martins     return kvm_gva_rw(cs, gva, buf, sz, true);
94bedcc139SJoao Martins }
95bedcc139SJoao Martins 
96f66b8a83SJoao Martins int kvm_xen_init(KVMState *s, uint32_t hypercall_msr)
9761491cf4SDavid Woodhouse {
9861491cf4SDavid Woodhouse     const int required_caps = KVM_XEN_HVM_CONFIG_HYPERCALL_MSR |
9961491cf4SDavid Woodhouse         KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL | KVM_XEN_HVM_CONFIG_SHARED_INFO;
10061491cf4SDavid Woodhouse     struct kvm_xen_hvm_config cfg = {
101f66b8a83SJoao Martins         .msr = hypercall_msr,
10261491cf4SDavid Woodhouse         .flags = KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL,
10361491cf4SDavid Woodhouse     };
10461491cf4SDavid Woodhouse     int xen_caps, ret;
10561491cf4SDavid Woodhouse 
10661491cf4SDavid Woodhouse     xen_caps = kvm_check_extension(s, KVM_CAP_XEN_HVM);
10761491cf4SDavid Woodhouse     if (required_caps & ~xen_caps) {
10861491cf4SDavid Woodhouse         error_report("kvm: Xen HVM guest support not present or insufficient");
10961491cf4SDavid Woodhouse         return -ENOSYS;
11061491cf4SDavid Woodhouse     }
11161491cf4SDavid Woodhouse 
11261491cf4SDavid Woodhouse     if (xen_caps & KVM_XEN_HVM_CONFIG_EVTCHN_SEND) {
11361491cf4SDavid Woodhouse         struct kvm_xen_hvm_attr ha = {
11461491cf4SDavid Woodhouse             .type = KVM_XEN_ATTR_TYPE_XEN_VERSION,
11561491cf4SDavid Woodhouse             .u.xen_version = s->xen_version,
11661491cf4SDavid Woodhouse         };
11761491cf4SDavid Woodhouse         (void)kvm_vm_ioctl(s, KVM_XEN_HVM_SET_ATTR, &ha);
11861491cf4SDavid Woodhouse 
11961491cf4SDavid Woodhouse         cfg.flags |= KVM_XEN_HVM_CONFIG_EVTCHN_SEND;
12061491cf4SDavid Woodhouse     }
12161491cf4SDavid Woodhouse 
12261491cf4SDavid Woodhouse     ret = kvm_vm_ioctl(s, KVM_XEN_HVM_CONFIG, &cfg);
12361491cf4SDavid Woodhouse     if (ret < 0) {
12461491cf4SDavid Woodhouse         error_report("kvm: Failed to enable Xen HVM support: %s",
12561491cf4SDavid Woodhouse                      strerror(-ret));
12661491cf4SDavid Woodhouse         return ret;
12761491cf4SDavid Woodhouse     }
12861491cf4SDavid Woodhouse 
12961491cf4SDavid Woodhouse     s->xen_caps = xen_caps;
13061491cf4SDavid Woodhouse     return 0;
13161491cf4SDavid Woodhouse }
13261491cf4SDavid Woodhouse 
1335e691a95SDavid Woodhouse int kvm_xen_init_vcpu(CPUState *cs)
1345e691a95SDavid Woodhouse {
135c345104cSJoao Martins     X86CPU *cpu = X86_CPU(cs);
136c345104cSJoao Martins     CPUX86State *env = &cpu->env;
1375e691a95SDavid Woodhouse     int err;
1385e691a95SDavid Woodhouse 
1395e691a95SDavid Woodhouse     /*
1405e691a95SDavid Woodhouse      * The kernel needs to know the Xen/ACPI vCPU ID because that's
1415e691a95SDavid Woodhouse      * what the guest uses in hypercalls such as timers. It doesn't
1425e691a95SDavid Woodhouse      * match the APIC ID which is generally used for talking to the
1435e691a95SDavid Woodhouse      * kernel about vCPUs. And if vCPU threads race with creating
1445e691a95SDavid Woodhouse      * their KVM vCPUs out of order, it doesn't necessarily match
1455e691a95SDavid Woodhouse      * with the kernel's internal vCPU indices either.
1465e691a95SDavid Woodhouse      */
1475e691a95SDavid Woodhouse     if (kvm_xen_has_cap(EVTCHN_SEND)) {
1485e691a95SDavid Woodhouse         struct kvm_xen_vcpu_attr va = {
1495e691a95SDavid Woodhouse             .type = KVM_XEN_VCPU_ATTR_TYPE_VCPU_ID,
1505e691a95SDavid Woodhouse             .u.vcpu_id = cs->cpu_index,
1515e691a95SDavid Woodhouse         };
1525e691a95SDavid Woodhouse         err = kvm_vcpu_ioctl(cs, KVM_XEN_VCPU_SET_ATTR, &va);
1535e691a95SDavid Woodhouse         if (err) {
1545e691a95SDavid Woodhouse             error_report("kvm: Failed to set Xen vCPU ID attribute: %s",
1555e691a95SDavid Woodhouse                          strerror(-err));
1565e691a95SDavid Woodhouse             return err;
1575e691a95SDavid Woodhouse         }
1585e691a95SDavid Woodhouse     }
1595e691a95SDavid Woodhouse 
160c345104cSJoao Martins     env->xen_vcpu_info_gpa = INVALID_GPA;
161c345104cSJoao Martins     env->xen_vcpu_info_default_gpa = INVALID_GPA;
162*f0689302SJoao Martins     env->xen_vcpu_time_info_gpa = INVALID_GPA;
163c345104cSJoao Martins 
1645e691a95SDavid Woodhouse     return 0;
1655e691a95SDavid Woodhouse }
1665e691a95SDavid Woodhouse 
16761491cf4SDavid Woodhouse uint32_t kvm_xen_get_caps(void)
16861491cf4SDavid Woodhouse {
16961491cf4SDavid Woodhouse     return kvm_state->xen_caps;
17061491cf4SDavid Woodhouse }
17155a3f666SJoao Martins 
172bedcc139SJoao Martins static bool kvm_xen_hcall_xen_version(struct kvm_xen_exit *exit, X86CPU *cpu,
173bedcc139SJoao Martins                                      int cmd, uint64_t arg)
174bedcc139SJoao Martins {
175bedcc139SJoao Martins     int err = 0;
176bedcc139SJoao Martins 
177bedcc139SJoao Martins     switch (cmd) {
178bedcc139SJoao Martins     case XENVER_get_features: {
179bedcc139SJoao Martins         struct xen_feature_info fi;
180bedcc139SJoao Martins 
181bedcc139SJoao Martins         /* No need for 32/64 compat handling */
182bedcc139SJoao Martins         qemu_build_assert(sizeof(fi) == 8);
183bedcc139SJoao Martins 
184bedcc139SJoao Martins         err = kvm_copy_from_gva(CPU(cpu), arg, &fi, sizeof(fi));
185bedcc139SJoao Martins         if (err) {
186bedcc139SJoao Martins             break;
187bedcc139SJoao Martins         }
188bedcc139SJoao Martins 
189bedcc139SJoao Martins         fi.submap = 0;
190bedcc139SJoao Martins         if (fi.submap_idx == 0) {
191bedcc139SJoao Martins             fi.submap |= 1 << XENFEAT_writable_page_tables |
192bedcc139SJoao Martins                          1 << XENFEAT_writable_descriptor_tables |
193bedcc139SJoao Martins                          1 << XENFEAT_auto_translated_physmap |
194bedcc139SJoao Martins                          1 << XENFEAT_supervisor_mode_kernel;
195bedcc139SJoao Martins         }
196bedcc139SJoao Martins 
197bedcc139SJoao Martins         err = kvm_copy_to_gva(CPU(cpu), arg, &fi, sizeof(fi));
198bedcc139SJoao Martins         break;
199bedcc139SJoao Martins     }
200bedcc139SJoao Martins 
201bedcc139SJoao Martins     default:
202bedcc139SJoao Martins         return false;
203bedcc139SJoao Martins     }
204bedcc139SJoao Martins 
205bedcc139SJoao Martins     exit->u.hcall.result = err;
206bedcc139SJoao Martins     return true;
207bedcc139SJoao Martins }
208bedcc139SJoao Martins 
209c345104cSJoao Martins static int kvm_xen_set_vcpu_attr(CPUState *cs, uint16_t type, uint64_t gpa)
210c345104cSJoao Martins {
211c345104cSJoao Martins     struct kvm_xen_vcpu_attr xhsi;
212c345104cSJoao Martins 
213c345104cSJoao Martins     xhsi.type = type;
214c345104cSJoao Martins     xhsi.u.gpa = gpa;
215c345104cSJoao Martins 
216c345104cSJoao Martins     trace_kvm_xen_set_vcpu_attr(cs->cpu_index, type, gpa);
217c345104cSJoao Martins 
218c345104cSJoao Martins     return kvm_vcpu_ioctl(cs, KVM_XEN_VCPU_SET_ATTR, &xhsi);
219c345104cSJoao Martins }
220c345104cSJoao Martins 
221c345104cSJoao Martins static void do_set_vcpu_info_default_gpa(CPUState *cs, run_on_cpu_data data)
222c345104cSJoao Martins {
223c345104cSJoao Martins     X86CPU *cpu = X86_CPU(cs);
224c345104cSJoao Martins     CPUX86State *env = &cpu->env;
225c345104cSJoao Martins 
226c345104cSJoao Martins     env->xen_vcpu_info_default_gpa = data.host_ulong;
227c345104cSJoao Martins 
228c345104cSJoao Martins     /* Changing the default does nothing if a vcpu_info was explicitly set. */
229c345104cSJoao Martins     if (env->xen_vcpu_info_gpa == INVALID_GPA) {
230c345104cSJoao Martins         kvm_xen_set_vcpu_attr(cs, KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO,
231c345104cSJoao Martins                               env->xen_vcpu_info_default_gpa);
232c345104cSJoao Martins     }
233c345104cSJoao Martins }
234c345104cSJoao Martins 
235c345104cSJoao Martins static void do_set_vcpu_info_gpa(CPUState *cs, run_on_cpu_data data)
236c345104cSJoao Martins {
237c345104cSJoao Martins     X86CPU *cpu = X86_CPU(cs);
238c345104cSJoao Martins     CPUX86State *env = &cpu->env;
239c345104cSJoao Martins 
240c345104cSJoao Martins     env->xen_vcpu_info_gpa = data.host_ulong;
241c345104cSJoao Martins 
242c345104cSJoao Martins     kvm_xen_set_vcpu_attr(cs, KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO,
243c345104cSJoao Martins                           env->xen_vcpu_info_gpa);
244c345104cSJoao Martins }
245c345104cSJoao Martins 
246*f0689302SJoao Martins static void do_set_vcpu_time_info_gpa(CPUState *cs, run_on_cpu_data data)
247*f0689302SJoao Martins {
248*f0689302SJoao Martins     X86CPU *cpu = X86_CPU(cs);
249*f0689302SJoao Martins     CPUX86State *env = &cpu->env;
250*f0689302SJoao Martins 
251*f0689302SJoao Martins     env->xen_vcpu_time_info_gpa = data.host_ulong;
252*f0689302SJoao Martins 
253*f0689302SJoao Martins     kvm_xen_set_vcpu_attr(cs, KVM_XEN_VCPU_ATTR_TYPE_VCPU_TIME_INFO,
254*f0689302SJoao Martins                           env->xen_vcpu_time_info_gpa);
255*f0689302SJoao Martins }
256*f0689302SJoao Martins 
257c345104cSJoao Martins static void do_vcpu_soft_reset(CPUState *cs, run_on_cpu_data data)
258c345104cSJoao Martins {
259c345104cSJoao Martins     X86CPU *cpu = X86_CPU(cs);
260c345104cSJoao Martins     CPUX86State *env = &cpu->env;
261c345104cSJoao Martins 
262c345104cSJoao Martins     env->xen_vcpu_info_gpa = INVALID_GPA;
263c345104cSJoao Martins     env->xen_vcpu_info_default_gpa = INVALID_GPA;
264*f0689302SJoao Martins     env->xen_vcpu_time_info_gpa = INVALID_GPA;
265c345104cSJoao Martins 
266c345104cSJoao Martins     kvm_xen_set_vcpu_attr(cs, KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO, INVALID_GPA);
267*f0689302SJoao Martins     kvm_xen_set_vcpu_attr(cs, KVM_XEN_VCPU_ATTR_TYPE_VCPU_TIME_INFO,
268*f0689302SJoao Martins                           INVALID_GPA);
269c345104cSJoao Martins }
270c345104cSJoao Martins 
271fb0fd2ceSJoao Martins static int xen_set_shared_info(uint64_t gfn)
272fb0fd2ceSJoao Martins {
273fb0fd2ceSJoao Martins     uint64_t gpa = gfn << TARGET_PAGE_BITS;
274c345104cSJoao Martins     int i, err;
275fb0fd2ceSJoao Martins 
276fb0fd2ceSJoao Martins     QEMU_IOTHREAD_LOCK_GUARD();
277fb0fd2ceSJoao Martins 
278fb0fd2ceSJoao Martins     /*
279fb0fd2ceSJoao Martins      * The xen_overlay device tells KVM about it too, since it had to
280fb0fd2ceSJoao Martins      * do that on migration load anyway (unless we're going to jump
281fb0fd2ceSJoao Martins      * through lots of hoops to maintain the fiction that this isn't
282fb0fd2ceSJoao Martins      * KVM-specific.
283fb0fd2ceSJoao Martins      */
284fb0fd2ceSJoao Martins     err = xen_overlay_map_shinfo_page(gpa);
285fb0fd2ceSJoao Martins     if (err) {
286fb0fd2ceSJoao Martins             return err;
287fb0fd2ceSJoao Martins     }
288fb0fd2ceSJoao Martins 
289fb0fd2ceSJoao Martins     trace_kvm_xen_set_shared_info(gfn);
290fb0fd2ceSJoao Martins 
291c345104cSJoao Martins     for (i = 0; i < XEN_LEGACY_MAX_VCPUS; i++) {
292c345104cSJoao Martins         CPUState *cpu = qemu_get_cpu(i);
293c345104cSJoao Martins         if (cpu) {
294c345104cSJoao Martins             async_run_on_cpu(cpu, do_set_vcpu_info_default_gpa,
295c345104cSJoao Martins                              RUN_ON_CPU_HOST_ULONG(gpa));
296c345104cSJoao Martins         }
297c345104cSJoao Martins         gpa += sizeof(vcpu_info_t);
298c345104cSJoao Martins     }
299c345104cSJoao Martins 
300fb0fd2ceSJoao Martins     return err;
301fb0fd2ceSJoao Martins }
302fb0fd2ceSJoao Martins 
303fb0fd2ceSJoao Martins static int add_to_physmap_one(uint32_t space, uint64_t idx, uint64_t gfn)
304fb0fd2ceSJoao Martins {
305fb0fd2ceSJoao Martins     switch (space) {
306fb0fd2ceSJoao Martins     case XENMAPSPACE_shared_info:
307fb0fd2ceSJoao Martins         if (idx > 0) {
308fb0fd2ceSJoao Martins             return -EINVAL;
309fb0fd2ceSJoao Martins         }
310fb0fd2ceSJoao Martins         return xen_set_shared_info(gfn);
311fb0fd2ceSJoao Martins 
312fb0fd2ceSJoao Martins     case XENMAPSPACE_grant_table:
313fb0fd2ceSJoao Martins     case XENMAPSPACE_gmfn:
314fb0fd2ceSJoao Martins     case XENMAPSPACE_gmfn_range:
315fb0fd2ceSJoao Martins         return -ENOTSUP;
316fb0fd2ceSJoao Martins 
317fb0fd2ceSJoao Martins     case XENMAPSPACE_gmfn_foreign:
318fb0fd2ceSJoao Martins     case XENMAPSPACE_dev_mmio:
319fb0fd2ceSJoao Martins         return -EPERM;
320fb0fd2ceSJoao Martins 
321fb0fd2ceSJoao Martins     default:
322fb0fd2ceSJoao Martins         return -EINVAL;
323fb0fd2ceSJoao Martins     }
324fb0fd2ceSJoao Martins }
325fb0fd2ceSJoao Martins 
326fb0fd2ceSJoao Martins static int do_add_to_physmap(struct kvm_xen_exit *exit, X86CPU *cpu,
327fb0fd2ceSJoao Martins                              uint64_t arg)
328fb0fd2ceSJoao Martins {
329fb0fd2ceSJoao Martins     struct xen_add_to_physmap xatp;
330fb0fd2ceSJoao Martins     CPUState *cs = CPU(cpu);
331fb0fd2ceSJoao Martins 
332fb0fd2ceSJoao Martins     if (hypercall_compat32(exit->u.hcall.longmode)) {
333fb0fd2ceSJoao Martins         struct compat_xen_add_to_physmap xatp32;
334fb0fd2ceSJoao Martins 
335fb0fd2ceSJoao Martins         qemu_build_assert(sizeof(struct compat_xen_add_to_physmap) == 16);
336fb0fd2ceSJoao Martins         if (kvm_copy_from_gva(cs, arg, &xatp32, sizeof(xatp32))) {
337fb0fd2ceSJoao Martins             return -EFAULT;
338fb0fd2ceSJoao Martins         }
339fb0fd2ceSJoao Martins         xatp.domid = xatp32.domid;
340fb0fd2ceSJoao Martins         xatp.size = xatp32.size;
341fb0fd2ceSJoao Martins         xatp.space = xatp32.space;
342fb0fd2ceSJoao Martins         xatp.idx = xatp32.idx;
343fb0fd2ceSJoao Martins         xatp.gpfn = xatp32.gpfn;
344fb0fd2ceSJoao Martins     } else {
345fb0fd2ceSJoao Martins         if (kvm_copy_from_gva(cs, arg, &xatp, sizeof(xatp))) {
346fb0fd2ceSJoao Martins             return -EFAULT;
347fb0fd2ceSJoao Martins         }
348fb0fd2ceSJoao Martins     }
349fb0fd2ceSJoao Martins 
350fb0fd2ceSJoao Martins     if (xatp.domid != DOMID_SELF && xatp.domid != xen_domid) {
351fb0fd2ceSJoao Martins         return -ESRCH;
352fb0fd2ceSJoao Martins     }
353fb0fd2ceSJoao Martins 
354fb0fd2ceSJoao Martins     return add_to_physmap_one(xatp.space, xatp.idx, xatp.gpfn);
355fb0fd2ceSJoao Martins }
356fb0fd2ceSJoao Martins 
357782a7960SDavid Woodhouse static int do_add_to_physmap_batch(struct kvm_xen_exit *exit, X86CPU *cpu,
358782a7960SDavid Woodhouse                                    uint64_t arg)
359782a7960SDavid Woodhouse {
360782a7960SDavid Woodhouse     struct xen_add_to_physmap_batch xatpb;
361782a7960SDavid Woodhouse     unsigned long idxs_gva, gpfns_gva, errs_gva;
362782a7960SDavid Woodhouse     CPUState *cs = CPU(cpu);
363782a7960SDavid Woodhouse     size_t op_sz;
364782a7960SDavid Woodhouse 
365782a7960SDavid Woodhouse     if (hypercall_compat32(exit->u.hcall.longmode)) {
366782a7960SDavid Woodhouse         struct compat_xen_add_to_physmap_batch xatpb32;
367782a7960SDavid Woodhouse 
368782a7960SDavid Woodhouse         qemu_build_assert(sizeof(struct compat_xen_add_to_physmap_batch) == 20);
369782a7960SDavid Woodhouse         if (kvm_copy_from_gva(cs, arg, &xatpb32, sizeof(xatpb32))) {
370782a7960SDavid Woodhouse             return -EFAULT;
371782a7960SDavid Woodhouse         }
372782a7960SDavid Woodhouse         xatpb.domid = xatpb32.domid;
373782a7960SDavid Woodhouse         xatpb.space = xatpb32.space;
374782a7960SDavid Woodhouse         xatpb.size = xatpb32.size;
375782a7960SDavid Woodhouse 
376782a7960SDavid Woodhouse         idxs_gva = xatpb32.idxs.c;
377782a7960SDavid Woodhouse         gpfns_gva = xatpb32.gpfns.c;
378782a7960SDavid Woodhouse         errs_gva = xatpb32.errs.c;
379782a7960SDavid Woodhouse         op_sz = sizeof(uint32_t);
380782a7960SDavid Woodhouse     } else {
381782a7960SDavid Woodhouse         if (kvm_copy_from_gva(cs, arg, &xatpb, sizeof(xatpb))) {
382782a7960SDavid Woodhouse             return -EFAULT;
383782a7960SDavid Woodhouse         }
384782a7960SDavid Woodhouse         op_sz = sizeof(unsigned long);
385782a7960SDavid Woodhouse         idxs_gva = (unsigned long)xatpb.idxs.p;
386782a7960SDavid Woodhouse         gpfns_gva = (unsigned long)xatpb.gpfns.p;
387782a7960SDavid Woodhouse         errs_gva = (unsigned long)xatpb.errs.p;
388782a7960SDavid Woodhouse     }
389782a7960SDavid Woodhouse 
390782a7960SDavid Woodhouse     if (xatpb.domid != DOMID_SELF && xatpb.domid != xen_domid) {
391782a7960SDavid Woodhouse         return -ESRCH;
392782a7960SDavid Woodhouse     }
393782a7960SDavid Woodhouse 
394782a7960SDavid Woodhouse     /* Explicitly invalid for the batch op. Not that we implement it anyway. */
395782a7960SDavid Woodhouse     if (xatpb.space == XENMAPSPACE_gmfn_range) {
396782a7960SDavid Woodhouse         return -EINVAL;
397782a7960SDavid Woodhouse     }
398782a7960SDavid Woodhouse 
399782a7960SDavid Woodhouse     while (xatpb.size--) {
400782a7960SDavid Woodhouse         unsigned long idx = 0;
401782a7960SDavid Woodhouse         unsigned long gpfn = 0;
402782a7960SDavid Woodhouse         int err;
403782a7960SDavid Woodhouse 
404782a7960SDavid Woodhouse         /* For 32-bit compat this only copies the low 32 bits of each */
405782a7960SDavid Woodhouse         if (kvm_copy_from_gva(cs, idxs_gva, &idx, op_sz) ||
406782a7960SDavid Woodhouse             kvm_copy_from_gva(cs, gpfns_gva, &gpfn, op_sz)) {
407782a7960SDavid Woodhouse             return -EFAULT;
408782a7960SDavid Woodhouse         }
409782a7960SDavid Woodhouse         idxs_gva += op_sz;
410782a7960SDavid Woodhouse         gpfns_gva += op_sz;
411782a7960SDavid Woodhouse 
412782a7960SDavid Woodhouse         err = add_to_physmap_one(xatpb.space, idx, gpfn);
413782a7960SDavid Woodhouse 
414782a7960SDavid Woodhouse         if (kvm_copy_to_gva(cs, errs_gva, &err, sizeof(err))) {
415782a7960SDavid Woodhouse             return -EFAULT;
416782a7960SDavid Woodhouse         }
417782a7960SDavid Woodhouse         errs_gva += sizeof(err);
418782a7960SDavid Woodhouse     }
419782a7960SDavid Woodhouse     return 0;
420782a7960SDavid Woodhouse }
421782a7960SDavid Woodhouse 
422fb0fd2ceSJoao Martins static bool kvm_xen_hcall_memory_op(struct kvm_xen_exit *exit, X86CPU *cpu,
423fb0fd2ceSJoao Martins                                    int cmd, uint64_t arg)
424fb0fd2ceSJoao Martins {
425fb0fd2ceSJoao Martins     int err;
426fb0fd2ceSJoao Martins 
427fb0fd2ceSJoao Martins     switch (cmd) {
428fb0fd2ceSJoao Martins     case XENMEM_add_to_physmap:
429fb0fd2ceSJoao Martins         err = do_add_to_physmap(exit, cpu, arg);
430fb0fd2ceSJoao Martins         break;
431fb0fd2ceSJoao Martins 
432782a7960SDavid Woodhouse     case XENMEM_add_to_physmap_batch:
433782a7960SDavid Woodhouse         err = do_add_to_physmap_batch(exit, cpu, arg);
434782a7960SDavid Woodhouse         break;
435782a7960SDavid Woodhouse 
436fb0fd2ceSJoao Martins     default:
437fb0fd2ceSJoao Martins         return false;
438fb0fd2ceSJoao Martins     }
439fb0fd2ceSJoao Martins 
440fb0fd2ceSJoao Martins     exit->u.hcall.result = err;
441fb0fd2ceSJoao Martins     return true;
442fb0fd2ceSJoao Martins }
443fb0fd2ceSJoao Martins 
444671bfdcdSJoao Martins static bool kvm_xen_hcall_hvm_op(struct kvm_xen_exit *exit, X86CPU *cpu,
445671bfdcdSJoao Martins                                  int cmd, uint64_t arg)
446671bfdcdSJoao Martins {
447671bfdcdSJoao Martins     switch (cmd) {
448671bfdcdSJoao Martins     case HVMOP_pagetable_dying:
449671bfdcdSJoao Martins         exit->u.hcall.result = -ENOSYS;
450671bfdcdSJoao Martins         return true;
451671bfdcdSJoao Martins 
452671bfdcdSJoao Martins     default:
453671bfdcdSJoao Martins         return false;
454671bfdcdSJoao Martins     }
455671bfdcdSJoao Martins }
456671bfdcdSJoao Martins 
457c345104cSJoao Martins static int vcpuop_register_vcpu_info(CPUState *cs, CPUState *target,
458c345104cSJoao Martins                                      uint64_t arg)
459c345104cSJoao Martins {
460c345104cSJoao Martins     struct vcpu_register_vcpu_info rvi;
461c345104cSJoao Martins     uint64_t gpa;
462c345104cSJoao Martins 
463c345104cSJoao Martins     /* No need for 32/64 compat handling */
464c345104cSJoao Martins     qemu_build_assert(sizeof(rvi) == 16);
465c345104cSJoao Martins     qemu_build_assert(sizeof(struct vcpu_info) == 64);
466c345104cSJoao Martins 
467c345104cSJoao Martins     if (!target) {
468c345104cSJoao Martins         return -ENOENT;
469c345104cSJoao Martins     }
470c345104cSJoao Martins 
471c345104cSJoao Martins     if (kvm_copy_from_gva(cs, arg, &rvi, sizeof(rvi))) {
472c345104cSJoao Martins         return -EFAULT;
473c345104cSJoao Martins     }
474c345104cSJoao Martins 
475c345104cSJoao Martins     if (rvi.offset > TARGET_PAGE_SIZE - sizeof(struct vcpu_info)) {
476c345104cSJoao Martins         return -EINVAL;
477c345104cSJoao Martins     }
478c345104cSJoao Martins 
479c345104cSJoao Martins     gpa = ((rvi.mfn << TARGET_PAGE_BITS) + rvi.offset);
480c345104cSJoao Martins     async_run_on_cpu(target, do_set_vcpu_info_gpa, RUN_ON_CPU_HOST_ULONG(gpa));
481c345104cSJoao Martins     return 0;
482c345104cSJoao Martins }
483c345104cSJoao Martins 
484*f0689302SJoao Martins static int vcpuop_register_vcpu_time_info(CPUState *cs, CPUState *target,
485*f0689302SJoao Martins                                           uint64_t arg)
486*f0689302SJoao Martins {
487*f0689302SJoao Martins     struct vcpu_register_time_memory_area tma;
488*f0689302SJoao Martins     uint64_t gpa;
489*f0689302SJoao Martins     size_t len;
490*f0689302SJoao Martins 
491*f0689302SJoao Martins     /* No need for 32/64 compat handling */
492*f0689302SJoao Martins     qemu_build_assert(sizeof(tma) == 8);
493*f0689302SJoao Martins     qemu_build_assert(sizeof(struct vcpu_time_info) == 32);
494*f0689302SJoao Martins 
495*f0689302SJoao Martins     if (!target) {
496*f0689302SJoao Martins         return -ENOENT;
497*f0689302SJoao Martins     }
498*f0689302SJoao Martins 
499*f0689302SJoao Martins     if (kvm_copy_from_gva(cs, arg, &tma, sizeof(tma))) {
500*f0689302SJoao Martins         return -EFAULT;
501*f0689302SJoao Martins     }
502*f0689302SJoao Martins 
503*f0689302SJoao Martins     /*
504*f0689302SJoao Martins      * Xen actually uses the GVA and does the translation through the guest
505*f0689302SJoao Martins      * page tables each time. But Linux/KVM uses the GPA, on the assumption
506*f0689302SJoao Martins      * that guests only ever use *global* addresses (kernel virtual addresses)
507*f0689302SJoao Martins      * for it. If Linux is changed to redo the GVA→GPA translation each time,
508*f0689302SJoao Martins      * it will offer a new vCPU attribute for that, and we'll use it instead.
509*f0689302SJoao Martins      */
510*f0689302SJoao Martins     if (!kvm_gva_to_gpa(cs, tma.addr.p, &gpa, &len, false) ||
511*f0689302SJoao Martins         len < sizeof(struct vcpu_time_info)) {
512*f0689302SJoao Martins         return -EFAULT;
513*f0689302SJoao Martins     }
514*f0689302SJoao Martins 
515*f0689302SJoao Martins     async_run_on_cpu(target, do_set_vcpu_time_info_gpa,
516*f0689302SJoao Martins                      RUN_ON_CPU_HOST_ULONG(gpa));
517*f0689302SJoao Martins     return 0;
518*f0689302SJoao Martins }
519*f0689302SJoao Martins 
520d70bd6a4SJoao Martins static bool kvm_xen_hcall_vcpu_op(struct kvm_xen_exit *exit, X86CPU *cpu,
521d70bd6a4SJoao Martins                                   int cmd, int vcpu_id, uint64_t arg)
522d70bd6a4SJoao Martins {
523c345104cSJoao Martins     CPUState *dest = qemu_get_cpu(vcpu_id);
524c345104cSJoao Martins     CPUState *cs = CPU(cpu);
525d70bd6a4SJoao Martins     int err;
526d70bd6a4SJoao Martins 
527d70bd6a4SJoao Martins     switch (cmd) {
528*f0689302SJoao Martins     case VCPUOP_register_vcpu_time_memory_area:
529*f0689302SJoao Martins         err = vcpuop_register_vcpu_time_info(cs, dest, arg);
530*f0689302SJoao Martins         break;
531d70bd6a4SJoao Martins     case VCPUOP_register_vcpu_info:
532c345104cSJoao Martins         err = vcpuop_register_vcpu_info(cs, dest, arg);
533d70bd6a4SJoao Martins         break;
534d70bd6a4SJoao Martins 
535d70bd6a4SJoao Martins     default:
536d70bd6a4SJoao Martins         return false;
537d70bd6a4SJoao Martins     }
538d70bd6a4SJoao Martins 
539d70bd6a4SJoao Martins     exit->u.hcall.result = err;
540d70bd6a4SJoao Martins     return true;
541d70bd6a4SJoao Martins }
542d70bd6a4SJoao Martins 
54379b7067dSJoao Martins int kvm_xen_soft_reset(void)
54479b7067dSJoao Martins {
545c345104cSJoao Martins     CPUState *cpu;
546fb0fd2ceSJoao Martins     int err;
547fb0fd2ceSJoao Martins 
54879b7067dSJoao Martins     assert(qemu_mutex_iothread_locked());
54979b7067dSJoao Martins 
55079b7067dSJoao Martins     trace_kvm_xen_soft_reset();
55179b7067dSJoao Martins 
552c345104cSJoao Martins     CPU_FOREACH(cpu) {
553c345104cSJoao Martins         async_run_on_cpu(cpu, do_vcpu_soft_reset, RUN_ON_CPU_NULL);
554c345104cSJoao Martins     }
555c345104cSJoao Martins 
556fb0fd2ceSJoao Martins     err = xen_overlay_map_shinfo_page(INVALID_GFN);
557fb0fd2ceSJoao Martins     if (err) {
558fb0fd2ceSJoao Martins         return err;
559fb0fd2ceSJoao Martins     }
560fb0fd2ceSJoao Martins 
56179b7067dSJoao Martins     return 0;
56279b7067dSJoao Martins }
56379b7067dSJoao Martins 
56479b7067dSJoao Martins static int schedop_shutdown(CPUState *cs, uint64_t arg)
56579b7067dSJoao Martins {
56679b7067dSJoao Martins     struct sched_shutdown shutdown;
56779b7067dSJoao Martins     int ret = 0;
56879b7067dSJoao Martins 
56979b7067dSJoao Martins     /* No need for 32/64 compat handling */
57079b7067dSJoao Martins     qemu_build_assert(sizeof(shutdown) == 4);
57179b7067dSJoao Martins 
57279b7067dSJoao Martins     if (kvm_copy_from_gva(cs, arg, &shutdown, sizeof(shutdown))) {
57379b7067dSJoao Martins         return -EFAULT;
57479b7067dSJoao Martins     }
57579b7067dSJoao Martins 
57679b7067dSJoao Martins     switch (shutdown.reason) {
57779b7067dSJoao Martins     case SHUTDOWN_crash:
57879b7067dSJoao Martins         cpu_dump_state(cs, stderr, CPU_DUMP_CODE);
57979b7067dSJoao Martins         qemu_system_guest_panicked(NULL);
58079b7067dSJoao Martins         break;
58179b7067dSJoao Martins 
58279b7067dSJoao Martins     case SHUTDOWN_reboot:
58379b7067dSJoao Martins         qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
58479b7067dSJoao Martins         break;
58579b7067dSJoao Martins 
58679b7067dSJoao Martins     case SHUTDOWN_poweroff:
58779b7067dSJoao Martins         qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
58879b7067dSJoao Martins         break;
58979b7067dSJoao Martins 
59079b7067dSJoao Martins     case SHUTDOWN_soft_reset:
59179b7067dSJoao Martins         qemu_mutex_lock_iothread();
59279b7067dSJoao Martins         ret = kvm_xen_soft_reset();
59379b7067dSJoao Martins         qemu_mutex_unlock_iothread();
59479b7067dSJoao Martins         break;
59579b7067dSJoao Martins 
59679b7067dSJoao Martins     default:
59779b7067dSJoao Martins         ret = -EINVAL;
59879b7067dSJoao Martins         break;
59979b7067dSJoao Martins     }
60079b7067dSJoao Martins 
60179b7067dSJoao Martins     return ret;
60279b7067dSJoao Martins }
60379b7067dSJoao Martins 
60479b7067dSJoao Martins static bool kvm_xen_hcall_sched_op(struct kvm_xen_exit *exit, X86CPU *cpu,
60579b7067dSJoao Martins                                    int cmd, uint64_t arg)
60679b7067dSJoao Martins {
60779b7067dSJoao Martins     CPUState *cs = CPU(cpu);
60879b7067dSJoao Martins     int err = -ENOSYS;
60979b7067dSJoao Martins 
61079b7067dSJoao Martins     switch (cmd) {
61179b7067dSJoao Martins     case SCHEDOP_shutdown:
61279b7067dSJoao Martins         err = schedop_shutdown(cs, arg);
61379b7067dSJoao Martins         break;
61479b7067dSJoao Martins 
615c789b9efSDavid Woodhouse     case SCHEDOP_poll:
616c789b9efSDavid Woodhouse         /*
617c789b9efSDavid Woodhouse          * Linux will panic if this doesn't work. Just yield; it's not
618c789b9efSDavid Woodhouse          * worth overthinking it because with event channel handling
619c789b9efSDavid Woodhouse          * in KVM, the kernel will intercept this and it will never
620c789b9efSDavid Woodhouse          * reach QEMU anyway. The semantics of the hypercall explicltly
621c789b9efSDavid Woodhouse          * permit spurious wakeups.
622c789b9efSDavid Woodhouse          */
623c789b9efSDavid Woodhouse     case SCHEDOP_yield:
624c789b9efSDavid Woodhouse         sched_yield();
625c789b9efSDavid Woodhouse         err = 0;
626c789b9efSDavid Woodhouse         break;
627c789b9efSDavid Woodhouse 
62879b7067dSJoao Martins     default:
62979b7067dSJoao Martins         return false;
63079b7067dSJoao Martins     }
63179b7067dSJoao Martins 
63279b7067dSJoao Martins     exit->u.hcall.result = err;
63379b7067dSJoao Martins     return true;
63479b7067dSJoao Martins }
63579b7067dSJoao Martins 
63655a3f666SJoao Martins static bool do_kvm_xen_handle_exit(X86CPU *cpu, struct kvm_xen_exit *exit)
63755a3f666SJoao Martins {
63855a3f666SJoao Martins     uint16_t code = exit->u.hcall.input;
63955a3f666SJoao Martins 
64055a3f666SJoao Martins     if (exit->u.hcall.cpl > 0) {
64155a3f666SJoao Martins         exit->u.hcall.result = -EPERM;
64255a3f666SJoao Martins         return true;
64355a3f666SJoao Martins     }
64455a3f666SJoao Martins 
64555a3f666SJoao Martins     switch (code) {
64679b7067dSJoao Martins     case __HYPERVISOR_sched_op:
64779b7067dSJoao Martins         return kvm_xen_hcall_sched_op(exit, cpu, exit->u.hcall.params[0],
64879b7067dSJoao Martins                                       exit->u.hcall.params[1]);
649d70bd6a4SJoao Martins     case __HYPERVISOR_vcpu_op:
650d70bd6a4SJoao Martins         return kvm_xen_hcall_vcpu_op(exit, cpu,
651d70bd6a4SJoao Martins                                      exit->u.hcall.params[0],
652d70bd6a4SJoao Martins                                      exit->u.hcall.params[1],
653d70bd6a4SJoao Martins                                      exit->u.hcall.params[2]);
654671bfdcdSJoao Martins     case __HYPERVISOR_hvm_op:
655671bfdcdSJoao Martins         return kvm_xen_hcall_hvm_op(exit, cpu, exit->u.hcall.params[0],
656671bfdcdSJoao Martins                                     exit->u.hcall.params[1]);
657fb0fd2ceSJoao Martins     case __HYPERVISOR_memory_op:
658fb0fd2ceSJoao Martins         return kvm_xen_hcall_memory_op(exit, cpu, exit->u.hcall.params[0],
659fb0fd2ceSJoao Martins                                        exit->u.hcall.params[1]);
660bedcc139SJoao Martins     case __HYPERVISOR_xen_version:
661bedcc139SJoao Martins         return kvm_xen_hcall_xen_version(exit, cpu, exit->u.hcall.params[0],
662bedcc139SJoao Martins                                          exit->u.hcall.params[1]);
66355a3f666SJoao Martins     default:
66455a3f666SJoao Martins         return false;
66555a3f666SJoao Martins     }
66655a3f666SJoao Martins }
66755a3f666SJoao Martins 
66855a3f666SJoao Martins int kvm_xen_handle_exit(X86CPU *cpu, struct kvm_xen_exit *exit)
66955a3f666SJoao Martins {
67055a3f666SJoao Martins     if (exit->type != KVM_EXIT_XEN_HCALL) {
67155a3f666SJoao Martins         return -1;
67255a3f666SJoao Martins     }
67355a3f666SJoao Martins 
674110a0ea5SDavid Woodhouse     /*
675110a0ea5SDavid Woodhouse      * The kernel latches the guest 32/64 mode when the MSR is used to fill
676110a0ea5SDavid Woodhouse      * the hypercall page. So if we see a hypercall in a mode that doesn't
677110a0ea5SDavid Woodhouse      * match our own idea of the guest mode, fetch the kernel's idea of the
678110a0ea5SDavid Woodhouse      * "long mode" to remain in sync.
679110a0ea5SDavid Woodhouse      */
680110a0ea5SDavid Woodhouse     if (exit->u.hcall.longmode != xen_is_long_mode()) {
681110a0ea5SDavid Woodhouse         xen_sync_long_mode();
682110a0ea5SDavid Woodhouse     }
683110a0ea5SDavid Woodhouse 
68455a3f666SJoao Martins     if (!do_kvm_xen_handle_exit(cpu, exit)) {
68555a3f666SJoao Martins         /*
68655a3f666SJoao Martins          * Some hypercalls will be deliberately "implemented" by returning
68755a3f666SJoao Martins          * -ENOSYS. This case is for hypercalls which are unexpected.
68855a3f666SJoao Martins          */
68955a3f666SJoao Martins         exit->u.hcall.result = -ENOSYS;
69055a3f666SJoao Martins         qemu_log_mask(LOG_UNIMP, "Unimplemented Xen hypercall %"
69155a3f666SJoao Martins                       PRId64 " (0x%" PRIx64 " 0x%" PRIx64 " 0x%" PRIx64 ")\n",
69255a3f666SJoao Martins                       (uint64_t)exit->u.hcall.input,
69355a3f666SJoao Martins                       (uint64_t)exit->u.hcall.params[0],
69455a3f666SJoao Martins                       (uint64_t)exit->u.hcall.params[1],
69555a3f666SJoao Martins                       (uint64_t)exit->u.hcall.params[2]);
69655a3f666SJoao Martins     }
69755a3f666SJoao Martins 
69855a3f666SJoao Martins     trace_kvm_xen_hypercall(CPU(cpu)->cpu_index, exit->u.hcall.cpl,
69955a3f666SJoao Martins                             exit->u.hcall.input, exit->u.hcall.params[0],
70055a3f666SJoao Martins                             exit->u.hcall.params[1], exit->u.hcall.params[2],
70155a3f666SJoao Martins                             exit->u.hcall.result);
70255a3f666SJoao Martins     return 0;
70355a3f666SJoao Martins }
704c345104cSJoao Martins 
705c345104cSJoao Martins int kvm_put_xen_state(CPUState *cs)
706c345104cSJoao Martins {
707c345104cSJoao Martins     X86CPU *cpu = X86_CPU(cs);
708c345104cSJoao Martins     CPUX86State *env = &cpu->env;
709c345104cSJoao Martins     uint64_t gpa;
710c345104cSJoao Martins     int ret;
711c345104cSJoao Martins 
712c345104cSJoao Martins     gpa = env->xen_vcpu_info_gpa;
713c345104cSJoao Martins     if (gpa == INVALID_GPA) {
714c345104cSJoao Martins         gpa = env->xen_vcpu_info_default_gpa;
715c345104cSJoao Martins     }
716c345104cSJoao Martins 
717c345104cSJoao Martins     if (gpa != INVALID_GPA) {
718c345104cSJoao Martins         ret = kvm_xen_set_vcpu_attr(cs, KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO, gpa);
719c345104cSJoao Martins         if (ret < 0) {
720c345104cSJoao Martins             return ret;
721c345104cSJoao Martins         }
722c345104cSJoao Martins     }
723c345104cSJoao Martins 
724*f0689302SJoao Martins     gpa = env->xen_vcpu_time_info_gpa;
725*f0689302SJoao Martins     if (gpa != INVALID_GPA) {
726*f0689302SJoao Martins         ret = kvm_xen_set_vcpu_attr(cs, KVM_XEN_VCPU_ATTR_TYPE_VCPU_TIME_INFO,
727*f0689302SJoao Martins                                     gpa);
728*f0689302SJoao Martins         if (ret < 0) {
729*f0689302SJoao Martins             return ret;
730*f0689302SJoao Martins         }
731*f0689302SJoao Martins     }
732*f0689302SJoao Martins 
733c345104cSJoao Martins     return 0;
734c345104cSJoao Martins }
735c345104cSJoao Martins 
736c345104cSJoao Martins int kvm_get_xen_state(CPUState *cs)
737c345104cSJoao Martins {
738c345104cSJoao Martins     X86CPU *cpu = X86_CPU(cs);
739c345104cSJoao Martins     CPUX86State *env = &cpu->env;
740c345104cSJoao Martins     uint64_t gpa;
741c345104cSJoao Martins 
742c345104cSJoao Martins     /*
743c345104cSJoao Martins      * The kernel does not mark vcpu_info as dirty when it delivers interrupts
744c345104cSJoao Martins      * to it. It's up to userspace to *assume* that any page shared thus is
745c345104cSJoao Martins      * always considered dirty. The shared_info page is different since it's
746c345104cSJoao Martins      * an overlay and migrated separately anyway.
747c345104cSJoao Martins      */
748c345104cSJoao Martins     gpa = env->xen_vcpu_info_gpa;
749c345104cSJoao Martins     if (gpa == INVALID_GPA) {
750c345104cSJoao Martins         gpa = env->xen_vcpu_info_default_gpa;
751c345104cSJoao Martins     }
752c345104cSJoao Martins     if (gpa != INVALID_GPA) {
753c345104cSJoao Martins         MemoryRegionSection mrs = memory_region_find(get_system_memory(),
754c345104cSJoao Martins                                                      gpa,
755c345104cSJoao Martins                                                      sizeof(struct vcpu_info));
756c345104cSJoao Martins         if (mrs.mr &&
757c345104cSJoao Martins             !int128_lt(mrs.size, int128_make64(sizeof(struct vcpu_info)))) {
758c345104cSJoao Martins             memory_region_set_dirty(mrs.mr, mrs.offset_within_region,
759c345104cSJoao Martins                                     sizeof(struct vcpu_info));
760c345104cSJoao Martins         }
761c345104cSJoao Martins     }
762c345104cSJoao Martins 
763c345104cSJoao Martins     return 0;
764c345104cSJoao Martins }
765