xref: /qemu/target/i386/kvm/xen-emu.c (revision 91cce756179195f0725f551a5b2922ae2abbef9f)
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"
25*91cce756SDavid Woodhouse #include "hw/i386/kvm/xen_evtchn.h"
26110a0ea5SDavid Woodhouse 
27bedcc139SJoao Martins #include "hw/xen/interface/version.h"
2879b7067dSJoao Martins #include "hw/xen/interface/sched.h"
29fb0fd2ceSJoao Martins #include "hw/xen/interface/memory.h"
30671bfdcdSJoao Martins #include "hw/xen/interface/hvm/hvm_op.h"
31105b47fdSAnkur Arora #include "hw/xen/interface/hvm/params.h"
32d70bd6a4SJoao Martins #include "hw/xen/interface/vcpu.h"
333b06f29bSJoao Martins #include "hw/xen/interface/event_channel.h"
34fb0fd2ceSJoao Martins 
35fb0fd2ceSJoao Martins #include "xen-compat.h"
36fb0fd2ceSJoao Martins 
37fb0fd2ceSJoao Martins #ifdef TARGET_X86_64
38fb0fd2ceSJoao Martins #define hypercall_compat32(longmode) (!(longmode))
39fb0fd2ceSJoao Martins #else
40fb0fd2ceSJoao Martins #define hypercall_compat32(longmode) (false)
41fb0fd2ceSJoao Martins #endif
42bedcc139SJoao Martins 
43f0689302SJoao Martins static bool kvm_gva_to_gpa(CPUState *cs, uint64_t gva, uint64_t *gpa,
44f0689302SJoao Martins                            size_t *len, bool is_write)
45bedcc139SJoao Martins {
46bedcc139SJoao Martins         struct kvm_translation tr = {
47bedcc139SJoao Martins             .linear_address = gva,
48bedcc139SJoao Martins         };
49bedcc139SJoao Martins 
50f0689302SJoao Martins         if (len) {
51f0689302SJoao Martins             *len = TARGET_PAGE_SIZE - (gva & ~TARGET_PAGE_MASK);
52f0689302SJoao Martins         }
53f0689302SJoao Martins 
54f0689302SJoao Martins         if (kvm_vcpu_ioctl(cs, KVM_TRANSLATE, &tr) || !tr.valid ||
55f0689302SJoao Martins             (is_write && !tr.writeable)) {
56f0689302SJoao Martins             return false;
57f0689302SJoao Martins         }
58f0689302SJoao Martins         *gpa = tr.physical_address;
59f0689302SJoao Martins         return true;
60f0689302SJoao Martins }
61f0689302SJoao Martins 
62f0689302SJoao Martins static int kvm_gva_rw(CPUState *cs, uint64_t gva, void *_buf, size_t sz,
63f0689302SJoao Martins                       bool is_write)
64f0689302SJoao Martins {
65f0689302SJoao Martins     uint8_t *buf = (uint8_t *)_buf;
66f0689302SJoao Martins     uint64_t gpa;
67f0689302SJoao Martins     size_t len;
68f0689302SJoao Martins 
69f0689302SJoao Martins     while (sz) {
70f0689302SJoao Martins         if (!kvm_gva_to_gpa(cs, gva, &gpa, &len, is_write)) {
71f0689302SJoao Martins             return -EFAULT;
72f0689302SJoao Martins         }
73bedcc139SJoao Martins         if (len > sz) {
74bedcc139SJoao Martins             len = sz;
75bedcc139SJoao Martins         }
76bedcc139SJoao Martins 
77f0689302SJoao Martins         cpu_physical_memory_rw(gpa, buf, len, is_write);
78bedcc139SJoao Martins 
79bedcc139SJoao Martins         buf += len;
80bedcc139SJoao Martins         sz -= len;
81bedcc139SJoao Martins         gva += len;
82bedcc139SJoao Martins     }
83bedcc139SJoao Martins 
84bedcc139SJoao Martins     return 0;
85bedcc139SJoao Martins }
86bedcc139SJoao Martins 
87bedcc139SJoao Martins static inline int kvm_copy_from_gva(CPUState *cs, uint64_t gva, void *buf,
88bedcc139SJoao Martins                                     size_t sz)
89bedcc139SJoao Martins {
90bedcc139SJoao Martins     return kvm_gva_rw(cs, gva, buf, sz, false);
91bedcc139SJoao Martins }
92bedcc139SJoao Martins 
93bedcc139SJoao Martins static inline int kvm_copy_to_gva(CPUState *cs, uint64_t gva, void *buf,
94bedcc139SJoao Martins                                   size_t sz)
95bedcc139SJoao Martins {
96bedcc139SJoao Martins     return kvm_gva_rw(cs, gva, buf, sz, true);
97bedcc139SJoao Martins }
98bedcc139SJoao Martins 
99f66b8a83SJoao Martins int kvm_xen_init(KVMState *s, uint32_t hypercall_msr)
10061491cf4SDavid Woodhouse {
10161491cf4SDavid Woodhouse     const int required_caps = KVM_XEN_HVM_CONFIG_HYPERCALL_MSR |
10261491cf4SDavid Woodhouse         KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL | KVM_XEN_HVM_CONFIG_SHARED_INFO;
10361491cf4SDavid Woodhouse     struct kvm_xen_hvm_config cfg = {
104f66b8a83SJoao Martins         .msr = hypercall_msr,
10561491cf4SDavid Woodhouse         .flags = KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL,
10661491cf4SDavid Woodhouse     };
10761491cf4SDavid Woodhouse     int xen_caps, ret;
10861491cf4SDavid Woodhouse 
10961491cf4SDavid Woodhouse     xen_caps = kvm_check_extension(s, KVM_CAP_XEN_HVM);
11061491cf4SDavid Woodhouse     if (required_caps & ~xen_caps) {
11161491cf4SDavid Woodhouse         error_report("kvm: Xen HVM guest support not present or insufficient");
11261491cf4SDavid Woodhouse         return -ENOSYS;
11361491cf4SDavid Woodhouse     }
11461491cf4SDavid Woodhouse 
11561491cf4SDavid Woodhouse     if (xen_caps & KVM_XEN_HVM_CONFIG_EVTCHN_SEND) {
11661491cf4SDavid Woodhouse         struct kvm_xen_hvm_attr ha = {
11761491cf4SDavid Woodhouse             .type = KVM_XEN_ATTR_TYPE_XEN_VERSION,
11861491cf4SDavid Woodhouse             .u.xen_version = s->xen_version,
11961491cf4SDavid Woodhouse         };
12061491cf4SDavid Woodhouse         (void)kvm_vm_ioctl(s, KVM_XEN_HVM_SET_ATTR, &ha);
12161491cf4SDavid Woodhouse 
12261491cf4SDavid Woodhouse         cfg.flags |= KVM_XEN_HVM_CONFIG_EVTCHN_SEND;
12361491cf4SDavid Woodhouse     }
12461491cf4SDavid Woodhouse 
12561491cf4SDavid Woodhouse     ret = kvm_vm_ioctl(s, KVM_XEN_HVM_CONFIG, &cfg);
12661491cf4SDavid Woodhouse     if (ret < 0) {
12761491cf4SDavid Woodhouse         error_report("kvm: Failed to enable Xen HVM support: %s",
12861491cf4SDavid Woodhouse                      strerror(-ret));
12961491cf4SDavid Woodhouse         return ret;
13061491cf4SDavid Woodhouse     }
13161491cf4SDavid Woodhouse 
13261491cf4SDavid Woodhouse     s->xen_caps = xen_caps;
13361491cf4SDavid Woodhouse     return 0;
13461491cf4SDavid Woodhouse }
13561491cf4SDavid Woodhouse 
1365e691a95SDavid Woodhouse int kvm_xen_init_vcpu(CPUState *cs)
1375e691a95SDavid Woodhouse {
138c345104cSJoao Martins     X86CPU *cpu = X86_CPU(cs);
139c345104cSJoao Martins     CPUX86State *env = &cpu->env;
1405e691a95SDavid Woodhouse     int err;
1415e691a95SDavid Woodhouse 
1425e691a95SDavid Woodhouse     /*
1435e691a95SDavid Woodhouse      * The kernel needs to know the Xen/ACPI vCPU ID because that's
1445e691a95SDavid Woodhouse      * what the guest uses in hypercalls such as timers. It doesn't
1455e691a95SDavid Woodhouse      * match the APIC ID which is generally used for talking to the
1465e691a95SDavid Woodhouse      * kernel about vCPUs. And if vCPU threads race with creating
1475e691a95SDavid Woodhouse      * their KVM vCPUs out of order, it doesn't necessarily match
1485e691a95SDavid Woodhouse      * with the kernel's internal vCPU indices either.
1495e691a95SDavid Woodhouse      */
1505e691a95SDavid Woodhouse     if (kvm_xen_has_cap(EVTCHN_SEND)) {
1515e691a95SDavid Woodhouse         struct kvm_xen_vcpu_attr va = {
1525e691a95SDavid Woodhouse             .type = KVM_XEN_VCPU_ATTR_TYPE_VCPU_ID,
1535e691a95SDavid Woodhouse             .u.vcpu_id = cs->cpu_index,
1545e691a95SDavid Woodhouse         };
1555e691a95SDavid Woodhouse         err = kvm_vcpu_ioctl(cs, KVM_XEN_VCPU_SET_ATTR, &va);
1565e691a95SDavid Woodhouse         if (err) {
1575e691a95SDavid Woodhouse             error_report("kvm: Failed to set Xen vCPU ID attribute: %s",
1585e691a95SDavid Woodhouse                          strerror(-err));
1595e691a95SDavid Woodhouse             return err;
1605e691a95SDavid Woodhouse         }
1615e691a95SDavid Woodhouse     }
1625e691a95SDavid Woodhouse 
163c345104cSJoao Martins     env->xen_vcpu_info_gpa = INVALID_GPA;
164c345104cSJoao Martins     env->xen_vcpu_info_default_gpa = INVALID_GPA;
165f0689302SJoao Martins     env->xen_vcpu_time_info_gpa = INVALID_GPA;
1665092db87SJoao Martins     env->xen_vcpu_runstate_gpa = INVALID_GPA;
167c345104cSJoao Martins 
1685e691a95SDavid Woodhouse     return 0;
1695e691a95SDavid Woodhouse }
1705e691a95SDavid Woodhouse 
17161491cf4SDavid Woodhouse uint32_t kvm_xen_get_caps(void)
17261491cf4SDavid Woodhouse {
17361491cf4SDavid Woodhouse     return kvm_state->xen_caps;
17461491cf4SDavid Woodhouse }
17555a3f666SJoao Martins 
176bedcc139SJoao Martins static bool kvm_xen_hcall_xen_version(struct kvm_xen_exit *exit, X86CPU *cpu,
177bedcc139SJoao Martins                                      int cmd, uint64_t arg)
178bedcc139SJoao Martins {
179bedcc139SJoao Martins     int err = 0;
180bedcc139SJoao Martins 
181bedcc139SJoao Martins     switch (cmd) {
182bedcc139SJoao Martins     case XENVER_get_features: {
183bedcc139SJoao Martins         struct xen_feature_info fi;
184bedcc139SJoao Martins 
185bedcc139SJoao Martins         /* No need for 32/64 compat handling */
186bedcc139SJoao Martins         qemu_build_assert(sizeof(fi) == 8);
187bedcc139SJoao Martins 
188bedcc139SJoao Martins         err = kvm_copy_from_gva(CPU(cpu), arg, &fi, sizeof(fi));
189bedcc139SJoao Martins         if (err) {
190bedcc139SJoao Martins             break;
191bedcc139SJoao Martins         }
192bedcc139SJoao Martins 
193bedcc139SJoao Martins         fi.submap = 0;
194bedcc139SJoao Martins         if (fi.submap_idx == 0) {
195bedcc139SJoao Martins             fi.submap |= 1 << XENFEAT_writable_page_tables |
196bedcc139SJoao Martins                          1 << XENFEAT_writable_descriptor_tables |
197bedcc139SJoao Martins                          1 << XENFEAT_auto_translated_physmap |
198105b47fdSAnkur Arora                          1 << XENFEAT_supervisor_mode_kernel |
199105b47fdSAnkur Arora                          1 << XENFEAT_hvm_callback_vector;
200bedcc139SJoao Martins         }
201bedcc139SJoao Martins 
202bedcc139SJoao Martins         err = kvm_copy_to_gva(CPU(cpu), arg, &fi, sizeof(fi));
203bedcc139SJoao Martins         break;
204bedcc139SJoao Martins     }
205bedcc139SJoao Martins 
206bedcc139SJoao Martins     default:
207bedcc139SJoao Martins         return false;
208bedcc139SJoao Martins     }
209bedcc139SJoao Martins 
210bedcc139SJoao Martins     exit->u.hcall.result = err;
211bedcc139SJoao Martins     return true;
212bedcc139SJoao Martins }
213bedcc139SJoao Martins 
214c345104cSJoao Martins static int kvm_xen_set_vcpu_attr(CPUState *cs, uint16_t type, uint64_t gpa)
215c345104cSJoao Martins {
216c345104cSJoao Martins     struct kvm_xen_vcpu_attr xhsi;
217c345104cSJoao Martins 
218c345104cSJoao Martins     xhsi.type = type;
219c345104cSJoao Martins     xhsi.u.gpa = gpa;
220c345104cSJoao Martins 
221c345104cSJoao Martins     trace_kvm_xen_set_vcpu_attr(cs->cpu_index, type, gpa);
222c345104cSJoao Martins 
223c345104cSJoao Martins     return kvm_vcpu_ioctl(cs, KVM_XEN_VCPU_SET_ATTR, &xhsi);
224c345104cSJoao Martins }
225c345104cSJoao Martins 
226105b47fdSAnkur Arora static int kvm_xen_set_vcpu_callback_vector(CPUState *cs)
227105b47fdSAnkur Arora {
228105b47fdSAnkur Arora     uint8_t vector = X86_CPU(cs)->env.xen_vcpu_callback_vector;
229105b47fdSAnkur Arora     struct kvm_xen_vcpu_attr xva;
230105b47fdSAnkur Arora 
231105b47fdSAnkur Arora     xva.type = KVM_XEN_VCPU_ATTR_TYPE_UPCALL_VECTOR;
232105b47fdSAnkur Arora     xva.u.vector = vector;
233105b47fdSAnkur Arora 
234105b47fdSAnkur Arora     trace_kvm_xen_set_vcpu_callback(cs->cpu_index, vector);
235105b47fdSAnkur Arora 
236105b47fdSAnkur Arora     return kvm_vcpu_ioctl(cs, KVM_XEN_HVM_SET_ATTR, &xva);
237105b47fdSAnkur Arora }
238105b47fdSAnkur Arora 
239105b47fdSAnkur Arora static void do_set_vcpu_callback_vector(CPUState *cs, run_on_cpu_data data)
240105b47fdSAnkur Arora {
241105b47fdSAnkur Arora     X86CPU *cpu = X86_CPU(cs);
242105b47fdSAnkur Arora     CPUX86State *env = &cpu->env;
243105b47fdSAnkur Arora 
244105b47fdSAnkur Arora     env->xen_vcpu_callback_vector = data.host_int;
245105b47fdSAnkur Arora 
246105b47fdSAnkur Arora     if (kvm_xen_has_cap(EVTCHN_SEND)) {
247105b47fdSAnkur Arora         kvm_xen_set_vcpu_callback_vector(cs);
248105b47fdSAnkur Arora     }
249105b47fdSAnkur Arora }
250105b47fdSAnkur Arora 
251c345104cSJoao Martins static void do_set_vcpu_info_default_gpa(CPUState *cs, run_on_cpu_data data)
252c345104cSJoao Martins {
253c345104cSJoao Martins     X86CPU *cpu = X86_CPU(cs);
254c345104cSJoao Martins     CPUX86State *env = &cpu->env;
255c345104cSJoao Martins 
256c345104cSJoao Martins     env->xen_vcpu_info_default_gpa = data.host_ulong;
257c345104cSJoao Martins 
258c345104cSJoao Martins     /* Changing the default does nothing if a vcpu_info was explicitly set. */
259c345104cSJoao Martins     if (env->xen_vcpu_info_gpa == INVALID_GPA) {
260c345104cSJoao Martins         kvm_xen_set_vcpu_attr(cs, KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO,
261c345104cSJoao Martins                               env->xen_vcpu_info_default_gpa);
262c345104cSJoao Martins     }
263c345104cSJoao Martins }
264c345104cSJoao Martins 
265c345104cSJoao Martins static void do_set_vcpu_info_gpa(CPUState *cs, run_on_cpu_data data)
266c345104cSJoao Martins {
267c345104cSJoao Martins     X86CPU *cpu = X86_CPU(cs);
268c345104cSJoao Martins     CPUX86State *env = &cpu->env;
269c345104cSJoao Martins 
270c345104cSJoao Martins     env->xen_vcpu_info_gpa = data.host_ulong;
271c345104cSJoao Martins 
272c345104cSJoao Martins     kvm_xen_set_vcpu_attr(cs, KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO,
273c345104cSJoao Martins                           env->xen_vcpu_info_gpa);
274c345104cSJoao Martins }
275c345104cSJoao Martins 
276f0689302SJoao Martins static void do_set_vcpu_time_info_gpa(CPUState *cs, run_on_cpu_data data)
277f0689302SJoao Martins {
278f0689302SJoao Martins     X86CPU *cpu = X86_CPU(cs);
279f0689302SJoao Martins     CPUX86State *env = &cpu->env;
280f0689302SJoao Martins 
281f0689302SJoao Martins     env->xen_vcpu_time_info_gpa = data.host_ulong;
282f0689302SJoao Martins 
283f0689302SJoao Martins     kvm_xen_set_vcpu_attr(cs, KVM_XEN_VCPU_ATTR_TYPE_VCPU_TIME_INFO,
284f0689302SJoao Martins                           env->xen_vcpu_time_info_gpa);
285f0689302SJoao Martins }
286f0689302SJoao Martins 
2875092db87SJoao Martins static void do_set_vcpu_runstate_gpa(CPUState *cs, run_on_cpu_data data)
2885092db87SJoao Martins {
2895092db87SJoao Martins     X86CPU *cpu = X86_CPU(cs);
2905092db87SJoao Martins     CPUX86State *env = &cpu->env;
2915092db87SJoao Martins 
2925092db87SJoao Martins     env->xen_vcpu_runstate_gpa = data.host_ulong;
2935092db87SJoao Martins 
2945092db87SJoao Martins     kvm_xen_set_vcpu_attr(cs, KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADDR,
2955092db87SJoao Martins                           env->xen_vcpu_runstate_gpa);
2965092db87SJoao Martins }
2975092db87SJoao Martins 
298c345104cSJoao Martins static void do_vcpu_soft_reset(CPUState *cs, run_on_cpu_data data)
299c345104cSJoao Martins {
300c345104cSJoao Martins     X86CPU *cpu = X86_CPU(cs);
301c345104cSJoao Martins     CPUX86State *env = &cpu->env;
302c345104cSJoao Martins 
303c345104cSJoao Martins     env->xen_vcpu_info_gpa = INVALID_GPA;
304c345104cSJoao Martins     env->xen_vcpu_info_default_gpa = INVALID_GPA;
305f0689302SJoao Martins     env->xen_vcpu_time_info_gpa = INVALID_GPA;
3065092db87SJoao Martins     env->xen_vcpu_runstate_gpa = INVALID_GPA;
307105b47fdSAnkur Arora     env->xen_vcpu_callback_vector = 0;
308c345104cSJoao Martins 
309c345104cSJoao Martins     kvm_xen_set_vcpu_attr(cs, KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO, INVALID_GPA);
310f0689302SJoao Martins     kvm_xen_set_vcpu_attr(cs, KVM_XEN_VCPU_ATTR_TYPE_VCPU_TIME_INFO,
311f0689302SJoao Martins                           INVALID_GPA);
3125092db87SJoao Martins     kvm_xen_set_vcpu_attr(cs, KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADDR,
3135092db87SJoao Martins                           INVALID_GPA);
314105b47fdSAnkur Arora     if (kvm_xen_has_cap(EVTCHN_SEND)) {
315105b47fdSAnkur Arora         kvm_xen_set_vcpu_callback_vector(cs);
316105b47fdSAnkur Arora     }
3175092db87SJoao Martins 
318c345104cSJoao Martins }
319c345104cSJoao Martins 
320fb0fd2ceSJoao Martins static int xen_set_shared_info(uint64_t gfn)
321fb0fd2ceSJoao Martins {
322fb0fd2ceSJoao Martins     uint64_t gpa = gfn << TARGET_PAGE_BITS;
323c345104cSJoao Martins     int i, err;
324fb0fd2ceSJoao Martins 
325fb0fd2ceSJoao Martins     QEMU_IOTHREAD_LOCK_GUARD();
326fb0fd2ceSJoao Martins 
327fb0fd2ceSJoao Martins     /*
328fb0fd2ceSJoao Martins      * The xen_overlay device tells KVM about it too, since it had to
329fb0fd2ceSJoao Martins      * do that on migration load anyway (unless we're going to jump
330fb0fd2ceSJoao Martins      * through lots of hoops to maintain the fiction that this isn't
331fb0fd2ceSJoao Martins      * KVM-specific.
332fb0fd2ceSJoao Martins      */
333fb0fd2ceSJoao Martins     err = xen_overlay_map_shinfo_page(gpa);
334fb0fd2ceSJoao Martins     if (err) {
335fb0fd2ceSJoao Martins             return err;
336fb0fd2ceSJoao Martins     }
337fb0fd2ceSJoao Martins 
338fb0fd2ceSJoao Martins     trace_kvm_xen_set_shared_info(gfn);
339fb0fd2ceSJoao Martins 
340c345104cSJoao Martins     for (i = 0; i < XEN_LEGACY_MAX_VCPUS; i++) {
341c345104cSJoao Martins         CPUState *cpu = qemu_get_cpu(i);
342c345104cSJoao Martins         if (cpu) {
343c345104cSJoao Martins             async_run_on_cpu(cpu, do_set_vcpu_info_default_gpa,
344c345104cSJoao Martins                              RUN_ON_CPU_HOST_ULONG(gpa));
345c345104cSJoao Martins         }
346c345104cSJoao Martins         gpa += sizeof(vcpu_info_t);
347c345104cSJoao Martins     }
348c345104cSJoao Martins 
349fb0fd2ceSJoao Martins     return err;
350fb0fd2ceSJoao Martins }
351fb0fd2ceSJoao Martins 
352fb0fd2ceSJoao Martins static int add_to_physmap_one(uint32_t space, uint64_t idx, uint64_t gfn)
353fb0fd2ceSJoao Martins {
354fb0fd2ceSJoao Martins     switch (space) {
355fb0fd2ceSJoao Martins     case XENMAPSPACE_shared_info:
356fb0fd2ceSJoao Martins         if (idx > 0) {
357fb0fd2ceSJoao Martins             return -EINVAL;
358fb0fd2ceSJoao Martins         }
359fb0fd2ceSJoao Martins         return xen_set_shared_info(gfn);
360fb0fd2ceSJoao Martins 
361fb0fd2ceSJoao Martins     case XENMAPSPACE_grant_table:
362fb0fd2ceSJoao Martins     case XENMAPSPACE_gmfn:
363fb0fd2ceSJoao Martins     case XENMAPSPACE_gmfn_range:
364fb0fd2ceSJoao Martins         return -ENOTSUP;
365fb0fd2ceSJoao Martins 
366fb0fd2ceSJoao Martins     case XENMAPSPACE_gmfn_foreign:
367fb0fd2ceSJoao Martins     case XENMAPSPACE_dev_mmio:
368fb0fd2ceSJoao Martins         return -EPERM;
369fb0fd2ceSJoao Martins 
370fb0fd2ceSJoao Martins     default:
371fb0fd2ceSJoao Martins         return -EINVAL;
372fb0fd2ceSJoao Martins     }
373fb0fd2ceSJoao Martins }
374fb0fd2ceSJoao Martins 
375fb0fd2ceSJoao Martins static int do_add_to_physmap(struct kvm_xen_exit *exit, X86CPU *cpu,
376fb0fd2ceSJoao Martins                              uint64_t arg)
377fb0fd2ceSJoao Martins {
378fb0fd2ceSJoao Martins     struct xen_add_to_physmap xatp;
379fb0fd2ceSJoao Martins     CPUState *cs = CPU(cpu);
380fb0fd2ceSJoao Martins 
381fb0fd2ceSJoao Martins     if (hypercall_compat32(exit->u.hcall.longmode)) {
382fb0fd2ceSJoao Martins         struct compat_xen_add_to_physmap xatp32;
383fb0fd2ceSJoao Martins 
384fb0fd2ceSJoao Martins         qemu_build_assert(sizeof(struct compat_xen_add_to_physmap) == 16);
385fb0fd2ceSJoao Martins         if (kvm_copy_from_gva(cs, arg, &xatp32, sizeof(xatp32))) {
386fb0fd2ceSJoao Martins             return -EFAULT;
387fb0fd2ceSJoao Martins         }
388fb0fd2ceSJoao Martins         xatp.domid = xatp32.domid;
389fb0fd2ceSJoao Martins         xatp.size = xatp32.size;
390fb0fd2ceSJoao Martins         xatp.space = xatp32.space;
391fb0fd2ceSJoao Martins         xatp.idx = xatp32.idx;
392fb0fd2ceSJoao Martins         xatp.gpfn = xatp32.gpfn;
393fb0fd2ceSJoao Martins     } else {
394fb0fd2ceSJoao Martins         if (kvm_copy_from_gva(cs, arg, &xatp, sizeof(xatp))) {
395fb0fd2ceSJoao Martins             return -EFAULT;
396fb0fd2ceSJoao Martins         }
397fb0fd2ceSJoao Martins     }
398fb0fd2ceSJoao Martins 
399fb0fd2ceSJoao Martins     if (xatp.domid != DOMID_SELF && xatp.domid != xen_domid) {
400fb0fd2ceSJoao Martins         return -ESRCH;
401fb0fd2ceSJoao Martins     }
402fb0fd2ceSJoao Martins 
403fb0fd2ceSJoao Martins     return add_to_physmap_one(xatp.space, xatp.idx, xatp.gpfn);
404fb0fd2ceSJoao Martins }
405fb0fd2ceSJoao Martins 
406782a7960SDavid Woodhouse static int do_add_to_physmap_batch(struct kvm_xen_exit *exit, X86CPU *cpu,
407782a7960SDavid Woodhouse                                    uint64_t arg)
408782a7960SDavid Woodhouse {
409782a7960SDavid Woodhouse     struct xen_add_to_physmap_batch xatpb;
410782a7960SDavid Woodhouse     unsigned long idxs_gva, gpfns_gva, errs_gva;
411782a7960SDavid Woodhouse     CPUState *cs = CPU(cpu);
412782a7960SDavid Woodhouse     size_t op_sz;
413782a7960SDavid Woodhouse 
414782a7960SDavid Woodhouse     if (hypercall_compat32(exit->u.hcall.longmode)) {
415782a7960SDavid Woodhouse         struct compat_xen_add_to_physmap_batch xatpb32;
416782a7960SDavid Woodhouse 
417782a7960SDavid Woodhouse         qemu_build_assert(sizeof(struct compat_xen_add_to_physmap_batch) == 20);
418782a7960SDavid Woodhouse         if (kvm_copy_from_gva(cs, arg, &xatpb32, sizeof(xatpb32))) {
419782a7960SDavid Woodhouse             return -EFAULT;
420782a7960SDavid Woodhouse         }
421782a7960SDavid Woodhouse         xatpb.domid = xatpb32.domid;
422782a7960SDavid Woodhouse         xatpb.space = xatpb32.space;
423782a7960SDavid Woodhouse         xatpb.size = xatpb32.size;
424782a7960SDavid Woodhouse 
425782a7960SDavid Woodhouse         idxs_gva = xatpb32.idxs.c;
426782a7960SDavid Woodhouse         gpfns_gva = xatpb32.gpfns.c;
427782a7960SDavid Woodhouse         errs_gva = xatpb32.errs.c;
428782a7960SDavid Woodhouse         op_sz = sizeof(uint32_t);
429782a7960SDavid Woodhouse     } else {
430782a7960SDavid Woodhouse         if (kvm_copy_from_gva(cs, arg, &xatpb, sizeof(xatpb))) {
431782a7960SDavid Woodhouse             return -EFAULT;
432782a7960SDavid Woodhouse         }
433782a7960SDavid Woodhouse         op_sz = sizeof(unsigned long);
434782a7960SDavid Woodhouse         idxs_gva = (unsigned long)xatpb.idxs.p;
435782a7960SDavid Woodhouse         gpfns_gva = (unsigned long)xatpb.gpfns.p;
436782a7960SDavid Woodhouse         errs_gva = (unsigned long)xatpb.errs.p;
437782a7960SDavid Woodhouse     }
438782a7960SDavid Woodhouse 
439782a7960SDavid Woodhouse     if (xatpb.domid != DOMID_SELF && xatpb.domid != xen_domid) {
440782a7960SDavid Woodhouse         return -ESRCH;
441782a7960SDavid Woodhouse     }
442782a7960SDavid Woodhouse 
443782a7960SDavid Woodhouse     /* Explicitly invalid for the batch op. Not that we implement it anyway. */
444782a7960SDavid Woodhouse     if (xatpb.space == XENMAPSPACE_gmfn_range) {
445782a7960SDavid Woodhouse         return -EINVAL;
446782a7960SDavid Woodhouse     }
447782a7960SDavid Woodhouse 
448782a7960SDavid Woodhouse     while (xatpb.size--) {
449782a7960SDavid Woodhouse         unsigned long idx = 0;
450782a7960SDavid Woodhouse         unsigned long gpfn = 0;
451782a7960SDavid Woodhouse         int err;
452782a7960SDavid Woodhouse 
453782a7960SDavid Woodhouse         /* For 32-bit compat this only copies the low 32 bits of each */
454782a7960SDavid Woodhouse         if (kvm_copy_from_gva(cs, idxs_gva, &idx, op_sz) ||
455782a7960SDavid Woodhouse             kvm_copy_from_gva(cs, gpfns_gva, &gpfn, op_sz)) {
456782a7960SDavid Woodhouse             return -EFAULT;
457782a7960SDavid Woodhouse         }
458782a7960SDavid Woodhouse         idxs_gva += op_sz;
459782a7960SDavid Woodhouse         gpfns_gva += op_sz;
460782a7960SDavid Woodhouse 
461782a7960SDavid Woodhouse         err = add_to_physmap_one(xatpb.space, idx, gpfn);
462782a7960SDavid Woodhouse 
463782a7960SDavid Woodhouse         if (kvm_copy_to_gva(cs, errs_gva, &err, sizeof(err))) {
464782a7960SDavid Woodhouse             return -EFAULT;
465782a7960SDavid Woodhouse         }
466782a7960SDavid Woodhouse         errs_gva += sizeof(err);
467782a7960SDavid Woodhouse     }
468782a7960SDavid Woodhouse     return 0;
469782a7960SDavid Woodhouse }
470782a7960SDavid Woodhouse 
471fb0fd2ceSJoao Martins static bool kvm_xen_hcall_memory_op(struct kvm_xen_exit *exit, X86CPU *cpu,
472fb0fd2ceSJoao Martins                                    int cmd, uint64_t arg)
473fb0fd2ceSJoao Martins {
474fb0fd2ceSJoao Martins     int err;
475fb0fd2ceSJoao Martins 
476fb0fd2ceSJoao Martins     switch (cmd) {
477fb0fd2ceSJoao Martins     case XENMEM_add_to_physmap:
478fb0fd2ceSJoao Martins         err = do_add_to_physmap(exit, cpu, arg);
479fb0fd2ceSJoao Martins         break;
480fb0fd2ceSJoao Martins 
481782a7960SDavid Woodhouse     case XENMEM_add_to_physmap_batch:
482782a7960SDavid Woodhouse         err = do_add_to_physmap_batch(exit, cpu, arg);
483782a7960SDavid Woodhouse         break;
484782a7960SDavid Woodhouse 
485fb0fd2ceSJoao Martins     default:
486fb0fd2ceSJoao Martins         return false;
487fb0fd2ceSJoao Martins     }
488fb0fd2ceSJoao Martins 
489fb0fd2ceSJoao Martins     exit->u.hcall.result = err;
490fb0fd2ceSJoao Martins     return true;
491fb0fd2ceSJoao Martins }
492fb0fd2ceSJoao Martins 
4935dbcd01aSAnkur Arora static bool handle_set_param(struct kvm_xen_exit *exit, X86CPU *cpu,
4945dbcd01aSAnkur Arora                              uint64_t arg)
4955dbcd01aSAnkur Arora {
4965dbcd01aSAnkur Arora     CPUState *cs = CPU(cpu);
4975dbcd01aSAnkur Arora     struct xen_hvm_param hp;
4985dbcd01aSAnkur Arora     int err = 0;
4995dbcd01aSAnkur Arora 
5005dbcd01aSAnkur Arora     /* No need for 32/64 compat handling */
5015dbcd01aSAnkur Arora     qemu_build_assert(sizeof(hp) == 16);
5025dbcd01aSAnkur Arora 
5035dbcd01aSAnkur Arora     if (kvm_copy_from_gva(cs, arg, &hp, sizeof(hp))) {
5045dbcd01aSAnkur Arora         err = -EFAULT;
5055dbcd01aSAnkur Arora         goto out;
5065dbcd01aSAnkur Arora     }
5075dbcd01aSAnkur Arora 
5085dbcd01aSAnkur Arora     if (hp.domid != DOMID_SELF && hp.domid != xen_domid) {
5095dbcd01aSAnkur Arora         err = -ESRCH;
5105dbcd01aSAnkur Arora         goto out;
5115dbcd01aSAnkur Arora     }
5125dbcd01aSAnkur Arora 
5135dbcd01aSAnkur Arora     switch (hp.index) {
514*91cce756SDavid Woodhouse     case HVM_PARAM_CALLBACK_IRQ:
515*91cce756SDavid Woodhouse         err = xen_evtchn_set_callback_param(hp.value);
516*91cce756SDavid Woodhouse         xen_set_long_mode(exit->u.hcall.longmode);
517*91cce756SDavid Woodhouse         break;
5185dbcd01aSAnkur Arora     default:
5195dbcd01aSAnkur Arora         return false;
5205dbcd01aSAnkur Arora     }
5215dbcd01aSAnkur Arora 
5225dbcd01aSAnkur Arora out:
5235dbcd01aSAnkur Arora     exit->u.hcall.result = err;
5245dbcd01aSAnkur Arora     return true;
5255dbcd01aSAnkur Arora }
5265dbcd01aSAnkur Arora 
527105b47fdSAnkur Arora static int kvm_xen_hcall_evtchn_upcall_vector(struct kvm_xen_exit *exit,
528105b47fdSAnkur Arora                                               X86CPU *cpu, uint64_t arg)
529105b47fdSAnkur Arora {
530105b47fdSAnkur Arora     struct xen_hvm_evtchn_upcall_vector up;
531105b47fdSAnkur Arora     CPUState *target_cs;
532105b47fdSAnkur Arora 
533105b47fdSAnkur Arora     /* No need for 32/64 compat handling */
534105b47fdSAnkur Arora     qemu_build_assert(sizeof(up) == 8);
535105b47fdSAnkur Arora 
536105b47fdSAnkur Arora     if (kvm_copy_from_gva(CPU(cpu), arg, &up, sizeof(up))) {
537105b47fdSAnkur Arora         return -EFAULT;
538105b47fdSAnkur Arora     }
539105b47fdSAnkur Arora 
540105b47fdSAnkur Arora     if (up.vector < 0x10) {
541105b47fdSAnkur Arora         return -EINVAL;
542105b47fdSAnkur Arora     }
543105b47fdSAnkur Arora 
544105b47fdSAnkur Arora     target_cs = qemu_get_cpu(up.vcpu);
545105b47fdSAnkur Arora     if (!target_cs) {
546105b47fdSAnkur Arora         return -EINVAL;
547105b47fdSAnkur Arora     }
548105b47fdSAnkur Arora 
549105b47fdSAnkur Arora     async_run_on_cpu(target_cs, do_set_vcpu_callback_vector,
550105b47fdSAnkur Arora                      RUN_ON_CPU_HOST_INT(up.vector));
551105b47fdSAnkur Arora     return 0;
552105b47fdSAnkur Arora }
553105b47fdSAnkur Arora 
554671bfdcdSJoao Martins static bool kvm_xen_hcall_hvm_op(struct kvm_xen_exit *exit, X86CPU *cpu,
555671bfdcdSJoao Martins                                  int cmd, uint64_t arg)
556671bfdcdSJoao Martins {
557105b47fdSAnkur Arora     int ret = -ENOSYS;
558671bfdcdSJoao Martins     switch (cmd) {
559105b47fdSAnkur Arora     case HVMOP_set_evtchn_upcall_vector:
560105b47fdSAnkur Arora         ret = kvm_xen_hcall_evtchn_upcall_vector(exit, cpu,
561105b47fdSAnkur Arora                                                  exit->u.hcall.params[0]);
562105b47fdSAnkur Arora         break;
563105b47fdSAnkur Arora 
564671bfdcdSJoao Martins     case HVMOP_pagetable_dying:
565105b47fdSAnkur Arora         ret = -ENOSYS;
566105b47fdSAnkur Arora         break;
567671bfdcdSJoao Martins 
5685dbcd01aSAnkur Arora     case HVMOP_set_param:
5695dbcd01aSAnkur Arora         return handle_set_param(exit, cpu, arg);
5705dbcd01aSAnkur Arora 
571671bfdcdSJoao Martins     default:
572671bfdcdSJoao Martins         return false;
573671bfdcdSJoao Martins     }
574105b47fdSAnkur Arora 
575105b47fdSAnkur Arora     exit->u.hcall.result = ret;
576105b47fdSAnkur Arora     return true;
577671bfdcdSJoao Martins }
578671bfdcdSJoao Martins 
579c345104cSJoao Martins static int vcpuop_register_vcpu_info(CPUState *cs, CPUState *target,
580c345104cSJoao Martins                                      uint64_t arg)
581c345104cSJoao Martins {
582c345104cSJoao Martins     struct vcpu_register_vcpu_info rvi;
583c345104cSJoao Martins     uint64_t gpa;
584c345104cSJoao Martins 
585c345104cSJoao Martins     /* No need for 32/64 compat handling */
586c345104cSJoao Martins     qemu_build_assert(sizeof(rvi) == 16);
587c345104cSJoao Martins     qemu_build_assert(sizeof(struct vcpu_info) == 64);
588c345104cSJoao Martins 
589c345104cSJoao Martins     if (!target) {
590c345104cSJoao Martins         return -ENOENT;
591c345104cSJoao Martins     }
592c345104cSJoao Martins 
593c345104cSJoao Martins     if (kvm_copy_from_gva(cs, arg, &rvi, sizeof(rvi))) {
594c345104cSJoao Martins         return -EFAULT;
595c345104cSJoao Martins     }
596c345104cSJoao Martins 
597c345104cSJoao Martins     if (rvi.offset > TARGET_PAGE_SIZE - sizeof(struct vcpu_info)) {
598c345104cSJoao Martins         return -EINVAL;
599c345104cSJoao Martins     }
600c345104cSJoao Martins 
601c345104cSJoao Martins     gpa = ((rvi.mfn << TARGET_PAGE_BITS) + rvi.offset);
602c345104cSJoao Martins     async_run_on_cpu(target, do_set_vcpu_info_gpa, RUN_ON_CPU_HOST_ULONG(gpa));
603c345104cSJoao Martins     return 0;
604c345104cSJoao Martins }
605c345104cSJoao Martins 
606f0689302SJoao Martins static int vcpuop_register_vcpu_time_info(CPUState *cs, CPUState *target,
607f0689302SJoao Martins                                           uint64_t arg)
608f0689302SJoao Martins {
609f0689302SJoao Martins     struct vcpu_register_time_memory_area tma;
610f0689302SJoao Martins     uint64_t gpa;
611f0689302SJoao Martins     size_t len;
612f0689302SJoao Martins 
613f0689302SJoao Martins     /* No need for 32/64 compat handling */
614f0689302SJoao Martins     qemu_build_assert(sizeof(tma) == 8);
615f0689302SJoao Martins     qemu_build_assert(sizeof(struct vcpu_time_info) == 32);
616f0689302SJoao Martins 
617f0689302SJoao Martins     if (!target) {
618f0689302SJoao Martins         return -ENOENT;
619f0689302SJoao Martins     }
620f0689302SJoao Martins 
621f0689302SJoao Martins     if (kvm_copy_from_gva(cs, arg, &tma, sizeof(tma))) {
622f0689302SJoao Martins         return -EFAULT;
623f0689302SJoao Martins     }
624f0689302SJoao Martins 
625f0689302SJoao Martins     /*
626f0689302SJoao Martins      * Xen actually uses the GVA and does the translation through the guest
627f0689302SJoao Martins      * page tables each time. But Linux/KVM uses the GPA, on the assumption
628f0689302SJoao Martins      * that guests only ever use *global* addresses (kernel virtual addresses)
629f0689302SJoao Martins      * for it. If Linux is changed to redo the GVA→GPA translation each time,
630f0689302SJoao Martins      * it will offer a new vCPU attribute for that, and we'll use it instead.
631f0689302SJoao Martins      */
632f0689302SJoao Martins     if (!kvm_gva_to_gpa(cs, tma.addr.p, &gpa, &len, false) ||
633f0689302SJoao Martins         len < sizeof(struct vcpu_time_info)) {
634f0689302SJoao Martins         return -EFAULT;
635f0689302SJoao Martins     }
636f0689302SJoao Martins 
637f0689302SJoao Martins     async_run_on_cpu(target, do_set_vcpu_time_info_gpa,
638f0689302SJoao Martins                      RUN_ON_CPU_HOST_ULONG(gpa));
639f0689302SJoao Martins     return 0;
640f0689302SJoao Martins }
641f0689302SJoao Martins 
6425092db87SJoao Martins static int vcpuop_register_runstate_info(CPUState *cs, CPUState *target,
6435092db87SJoao Martins                                          uint64_t arg)
6445092db87SJoao Martins {
6455092db87SJoao Martins     struct vcpu_register_runstate_memory_area rma;
6465092db87SJoao Martins     uint64_t gpa;
6475092db87SJoao Martins     size_t len;
6485092db87SJoao Martins 
6495092db87SJoao Martins     /* No need for 32/64 compat handling */
6505092db87SJoao Martins     qemu_build_assert(sizeof(rma) == 8);
6515092db87SJoao Martins     /* The runstate area actually does change size, but Linux copes. */
6525092db87SJoao Martins 
6535092db87SJoao Martins     if (!target) {
6545092db87SJoao Martins         return -ENOENT;
6555092db87SJoao Martins     }
6565092db87SJoao Martins 
6575092db87SJoao Martins     if (kvm_copy_from_gva(cs, arg, &rma, sizeof(rma))) {
6585092db87SJoao Martins         return -EFAULT;
6595092db87SJoao Martins     }
6605092db87SJoao Martins 
6615092db87SJoao Martins     /* As with vcpu_time_info, Xen actually uses the GVA but KVM doesn't. */
6625092db87SJoao Martins     if (!kvm_gva_to_gpa(cs, rma.addr.p, &gpa, &len, false)) {
6635092db87SJoao Martins         return -EFAULT;
6645092db87SJoao Martins     }
6655092db87SJoao Martins 
6665092db87SJoao Martins     async_run_on_cpu(target, do_set_vcpu_runstate_gpa,
6675092db87SJoao Martins                      RUN_ON_CPU_HOST_ULONG(gpa));
6685092db87SJoao Martins     return 0;
6695092db87SJoao Martins }
6705092db87SJoao Martins 
671d70bd6a4SJoao Martins static bool kvm_xen_hcall_vcpu_op(struct kvm_xen_exit *exit, X86CPU *cpu,
672d70bd6a4SJoao Martins                                   int cmd, int vcpu_id, uint64_t arg)
673d70bd6a4SJoao Martins {
674c345104cSJoao Martins     CPUState *dest = qemu_get_cpu(vcpu_id);
675c345104cSJoao Martins     CPUState *cs = CPU(cpu);
676d70bd6a4SJoao Martins     int err;
677d70bd6a4SJoao Martins 
678d70bd6a4SJoao Martins     switch (cmd) {
6795092db87SJoao Martins     case VCPUOP_register_runstate_memory_area:
6805092db87SJoao Martins         err = vcpuop_register_runstate_info(cs, dest, arg);
6815092db87SJoao Martins         break;
682f0689302SJoao Martins     case VCPUOP_register_vcpu_time_memory_area:
683f0689302SJoao Martins         err = vcpuop_register_vcpu_time_info(cs, dest, arg);
684f0689302SJoao Martins         break;
685d70bd6a4SJoao Martins     case VCPUOP_register_vcpu_info:
686c345104cSJoao Martins         err = vcpuop_register_vcpu_info(cs, dest, arg);
687d70bd6a4SJoao Martins         break;
688d70bd6a4SJoao Martins 
689d70bd6a4SJoao Martins     default:
690d70bd6a4SJoao Martins         return false;
691d70bd6a4SJoao Martins     }
692d70bd6a4SJoao Martins 
693d70bd6a4SJoao Martins     exit->u.hcall.result = err;
694d70bd6a4SJoao Martins     return true;
695d70bd6a4SJoao Martins }
696d70bd6a4SJoao Martins 
6973b06f29bSJoao Martins static bool kvm_xen_hcall_evtchn_op(struct kvm_xen_exit *exit,
6983b06f29bSJoao Martins                                     int cmd, uint64_t arg)
6993b06f29bSJoao Martins {
7003b06f29bSJoao Martins     int err = -ENOSYS;
7013b06f29bSJoao Martins 
7023b06f29bSJoao Martins     switch (cmd) {
7033b06f29bSJoao Martins     case EVTCHNOP_init_control:
7043b06f29bSJoao Martins     case EVTCHNOP_expand_array:
7053b06f29bSJoao Martins     case EVTCHNOP_set_priority:
7063b06f29bSJoao Martins         /* We do not support FIFO channels at this point */
7073b06f29bSJoao Martins         err = -ENOSYS;
7083b06f29bSJoao Martins         break;
7093b06f29bSJoao Martins 
7103b06f29bSJoao Martins     default:
7113b06f29bSJoao Martins         return false;
7123b06f29bSJoao Martins     }
7133b06f29bSJoao Martins 
7143b06f29bSJoao Martins     exit->u.hcall.result = err;
7153b06f29bSJoao Martins     return true;
7163b06f29bSJoao Martins }
7173b06f29bSJoao Martins 
71879b7067dSJoao Martins int kvm_xen_soft_reset(void)
71979b7067dSJoao Martins {
720c345104cSJoao Martins     CPUState *cpu;
721fb0fd2ceSJoao Martins     int err;
722fb0fd2ceSJoao Martins 
72379b7067dSJoao Martins     assert(qemu_mutex_iothread_locked());
72479b7067dSJoao Martins 
72579b7067dSJoao Martins     trace_kvm_xen_soft_reset();
72679b7067dSJoao Martins 
727*91cce756SDavid Woodhouse     /*
728*91cce756SDavid Woodhouse      * Zero is the reset/startup state for HVM_PARAM_CALLBACK_IRQ. Strictly,
729*91cce756SDavid Woodhouse      * it maps to HVM_PARAM_CALLBACK_TYPE_GSI with GSI#0, but Xen refuses to
730*91cce756SDavid Woodhouse      * to deliver to the timer interrupt and treats that as 'disabled'.
731*91cce756SDavid Woodhouse      */
732*91cce756SDavid Woodhouse     err = xen_evtchn_set_callback_param(0);
733*91cce756SDavid Woodhouse     if (err) {
734*91cce756SDavid Woodhouse         return err;
735*91cce756SDavid Woodhouse     }
736*91cce756SDavid Woodhouse 
737c345104cSJoao Martins     CPU_FOREACH(cpu) {
738c345104cSJoao Martins         async_run_on_cpu(cpu, do_vcpu_soft_reset, RUN_ON_CPU_NULL);
739c345104cSJoao Martins     }
740c345104cSJoao Martins 
741fb0fd2ceSJoao Martins     err = xen_overlay_map_shinfo_page(INVALID_GFN);
742fb0fd2ceSJoao Martins     if (err) {
743fb0fd2ceSJoao Martins         return err;
744fb0fd2ceSJoao Martins     }
745fb0fd2ceSJoao Martins 
74679b7067dSJoao Martins     return 0;
74779b7067dSJoao Martins }
74879b7067dSJoao Martins 
74979b7067dSJoao Martins static int schedop_shutdown(CPUState *cs, uint64_t arg)
75079b7067dSJoao Martins {
75179b7067dSJoao Martins     struct sched_shutdown shutdown;
75279b7067dSJoao Martins     int ret = 0;
75379b7067dSJoao Martins 
75479b7067dSJoao Martins     /* No need for 32/64 compat handling */
75579b7067dSJoao Martins     qemu_build_assert(sizeof(shutdown) == 4);
75679b7067dSJoao Martins 
75779b7067dSJoao Martins     if (kvm_copy_from_gva(cs, arg, &shutdown, sizeof(shutdown))) {
75879b7067dSJoao Martins         return -EFAULT;
75979b7067dSJoao Martins     }
76079b7067dSJoao Martins 
76179b7067dSJoao Martins     switch (shutdown.reason) {
76279b7067dSJoao Martins     case SHUTDOWN_crash:
76379b7067dSJoao Martins         cpu_dump_state(cs, stderr, CPU_DUMP_CODE);
76479b7067dSJoao Martins         qemu_system_guest_panicked(NULL);
76579b7067dSJoao Martins         break;
76679b7067dSJoao Martins 
76779b7067dSJoao Martins     case SHUTDOWN_reboot:
76879b7067dSJoao Martins         qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
76979b7067dSJoao Martins         break;
77079b7067dSJoao Martins 
77179b7067dSJoao Martins     case SHUTDOWN_poweroff:
77279b7067dSJoao Martins         qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
77379b7067dSJoao Martins         break;
77479b7067dSJoao Martins 
77579b7067dSJoao Martins     case SHUTDOWN_soft_reset:
77679b7067dSJoao Martins         qemu_mutex_lock_iothread();
77779b7067dSJoao Martins         ret = kvm_xen_soft_reset();
77879b7067dSJoao Martins         qemu_mutex_unlock_iothread();
77979b7067dSJoao Martins         break;
78079b7067dSJoao Martins 
78179b7067dSJoao Martins     default:
78279b7067dSJoao Martins         ret = -EINVAL;
78379b7067dSJoao Martins         break;
78479b7067dSJoao Martins     }
78579b7067dSJoao Martins 
78679b7067dSJoao Martins     return ret;
78779b7067dSJoao Martins }
78879b7067dSJoao Martins 
78979b7067dSJoao Martins static bool kvm_xen_hcall_sched_op(struct kvm_xen_exit *exit, X86CPU *cpu,
79079b7067dSJoao Martins                                    int cmd, uint64_t arg)
79179b7067dSJoao Martins {
79279b7067dSJoao Martins     CPUState *cs = CPU(cpu);
79379b7067dSJoao Martins     int err = -ENOSYS;
79479b7067dSJoao Martins 
79579b7067dSJoao Martins     switch (cmd) {
79679b7067dSJoao Martins     case SCHEDOP_shutdown:
79779b7067dSJoao Martins         err = schedop_shutdown(cs, arg);
79879b7067dSJoao Martins         break;
79979b7067dSJoao Martins 
800c789b9efSDavid Woodhouse     case SCHEDOP_poll:
801c789b9efSDavid Woodhouse         /*
802c789b9efSDavid Woodhouse          * Linux will panic if this doesn't work. Just yield; it's not
803c789b9efSDavid Woodhouse          * worth overthinking it because with event channel handling
804c789b9efSDavid Woodhouse          * in KVM, the kernel will intercept this and it will never
805c789b9efSDavid Woodhouse          * reach QEMU anyway. The semantics of the hypercall explicltly
806c789b9efSDavid Woodhouse          * permit spurious wakeups.
807c789b9efSDavid Woodhouse          */
808c789b9efSDavid Woodhouse     case SCHEDOP_yield:
809c789b9efSDavid Woodhouse         sched_yield();
810c789b9efSDavid Woodhouse         err = 0;
811c789b9efSDavid Woodhouse         break;
812c789b9efSDavid Woodhouse 
81379b7067dSJoao Martins     default:
81479b7067dSJoao Martins         return false;
81579b7067dSJoao Martins     }
81679b7067dSJoao Martins 
81779b7067dSJoao Martins     exit->u.hcall.result = err;
81879b7067dSJoao Martins     return true;
81979b7067dSJoao Martins }
82079b7067dSJoao Martins 
82155a3f666SJoao Martins static bool do_kvm_xen_handle_exit(X86CPU *cpu, struct kvm_xen_exit *exit)
82255a3f666SJoao Martins {
82355a3f666SJoao Martins     uint16_t code = exit->u.hcall.input;
82455a3f666SJoao Martins 
82555a3f666SJoao Martins     if (exit->u.hcall.cpl > 0) {
82655a3f666SJoao Martins         exit->u.hcall.result = -EPERM;
82755a3f666SJoao Martins         return true;
82855a3f666SJoao Martins     }
82955a3f666SJoao Martins 
83055a3f666SJoao Martins     switch (code) {
83179b7067dSJoao Martins     case __HYPERVISOR_sched_op:
83279b7067dSJoao Martins         return kvm_xen_hcall_sched_op(exit, cpu, exit->u.hcall.params[0],
83379b7067dSJoao Martins                                       exit->u.hcall.params[1]);
8343b06f29bSJoao Martins     case __HYPERVISOR_event_channel_op:
8353b06f29bSJoao Martins         return kvm_xen_hcall_evtchn_op(exit, exit->u.hcall.params[0],
8363b06f29bSJoao Martins                                        exit->u.hcall.params[1]);
837d70bd6a4SJoao Martins     case __HYPERVISOR_vcpu_op:
838d70bd6a4SJoao Martins         return kvm_xen_hcall_vcpu_op(exit, cpu,
839d70bd6a4SJoao Martins                                      exit->u.hcall.params[0],
840d70bd6a4SJoao Martins                                      exit->u.hcall.params[1],
841d70bd6a4SJoao Martins                                      exit->u.hcall.params[2]);
842671bfdcdSJoao Martins     case __HYPERVISOR_hvm_op:
843671bfdcdSJoao Martins         return kvm_xen_hcall_hvm_op(exit, cpu, exit->u.hcall.params[0],
844671bfdcdSJoao Martins                                     exit->u.hcall.params[1]);
845fb0fd2ceSJoao Martins     case __HYPERVISOR_memory_op:
846fb0fd2ceSJoao Martins         return kvm_xen_hcall_memory_op(exit, cpu, exit->u.hcall.params[0],
847fb0fd2ceSJoao Martins                                        exit->u.hcall.params[1]);
848bedcc139SJoao Martins     case __HYPERVISOR_xen_version:
849bedcc139SJoao Martins         return kvm_xen_hcall_xen_version(exit, cpu, exit->u.hcall.params[0],
850bedcc139SJoao Martins                                          exit->u.hcall.params[1]);
85155a3f666SJoao Martins     default:
85255a3f666SJoao Martins         return false;
85355a3f666SJoao Martins     }
85455a3f666SJoao Martins }
85555a3f666SJoao Martins 
85655a3f666SJoao Martins int kvm_xen_handle_exit(X86CPU *cpu, struct kvm_xen_exit *exit)
85755a3f666SJoao Martins {
85855a3f666SJoao Martins     if (exit->type != KVM_EXIT_XEN_HCALL) {
85955a3f666SJoao Martins         return -1;
86055a3f666SJoao Martins     }
86155a3f666SJoao Martins 
862110a0ea5SDavid Woodhouse     /*
863110a0ea5SDavid Woodhouse      * The kernel latches the guest 32/64 mode when the MSR is used to fill
864110a0ea5SDavid Woodhouse      * the hypercall page. So if we see a hypercall in a mode that doesn't
865110a0ea5SDavid Woodhouse      * match our own idea of the guest mode, fetch the kernel's idea of the
866110a0ea5SDavid Woodhouse      * "long mode" to remain in sync.
867110a0ea5SDavid Woodhouse      */
868110a0ea5SDavid Woodhouse     if (exit->u.hcall.longmode != xen_is_long_mode()) {
869110a0ea5SDavid Woodhouse         xen_sync_long_mode();
870110a0ea5SDavid Woodhouse     }
871110a0ea5SDavid Woodhouse 
87255a3f666SJoao Martins     if (!do_kvm_xen_handle_exit(cpu, exit)) {
87355a3f666SJoao Martins         /*
87455a3f666SJoao Martins          * Some hypercalls will be deliberately "implemented" by returning
87555a3f666SJoao Martins          * -ENOSYS. This case is for hypercalls which are unexpected.
87655a3f666SJoao Martins          */
87755a3f666SJoao Martins         exit->u.hcall.result = -ENOSYS;
87855a3f666SJoao Martins         qemu_log_mask(LOG_UNIMP, "Unimplemented Xen hypercall %"
87955a3f666SJoao Martins                       PRId64 " (0x%" PRIx64 " 0x%" PRIx64 " 0x%" PRIx64 ")\n",
88055a3f666SJoao Martins                       (uint64_t)exit->u.hcall.input,
88155a3f666SJoao Martins                       (uint64_t)exit->u.hcall.params[0],
88255a3f666SJoao Martins                       (uint64_t)exit->u.hcall.params[1],
88355a3f666SJoao Martins                       (uint64_t)exit->u.hcall.params[2]);
88455a3f666SJoao Martins     }
88555a3f666SJoao Martins 
88655a3f666SJoao Martins     trace_kvm_xen_hypercall(CPU(cpu)->cpu_index, exit->u.hcall.cpl,
88755a3f666SJoao Martins                             exit->u.hcall.input, exit->u.hcall.params[0],
88855a3f666SJoao Martins                             exit->u.hcall.params[1], exit->u.hcall.params[2],
88955a3f666SJoao Martins                             exit->u.hcall.result);
89055a3f666SJoao Martins     return 0;
89155a3f666SJoao Martins }
892c345104cSJoao Martins 
893c345104cSJoao Martins int kvm_put_xen_state(CPUState *cs)
894c345104cSJoao Martins {
895c345104cSJoao Martins     X86CPU *cpu = X86_CPU(cs);
896c345104cSJoao Martins     CPUX86State *env = &cpu->env;
897c345104cSJoao Martins     uint64_t gpa;
898c345104cSJoao Martins     int ret;
899c345104cSJoao Martins 
900c345104cSJoao Martins     gpa = env->xen_vcpu_info_gpa;
901c345104cSJoao Martins     if (gpa == INVALID_GPA) {
902c345104cSJoao Martins         gpa = env->xen_vcpu_info_default_gpa;
903c345104cSJoao Martins     }
904c345104cSJoao Martins 
905c345104cSJoao Martins     if (gpa != INVALID_GPA) {
906c345104cSJoao Martins         ret = kvm_xen_set_vcpu_attr(cs, KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO, gpa);
907c345104cSJoao Martins         if (ret < 0) {
908c345104cSJoao Martins             return ret;
909c345104cSJoao Martins         }
910c345104cSJoao Martins     }
911c345104cSJoao Martins 
912f0689302SJoao Martins     gpa = env->xen_vcpu_time_info_gpa;
913f0689302SJoao Martins     if (gpa != INVALID_GPA) {
914f0689302SJoao Martins         ret = kvm_xen_set_vcpu_attr(cs, KVM_XEN_VCPU_ATTR_TYPE_VCPU_TIME_INFO,
915f0689302SJoao Martins                                     gpa);
916f0689302SJoao Martins         if (ret < 0) {
917f0689302SJoao Martins             return ret;
918f0689302SJoao Martins         }
919f0689302SJoao Martins     }
920f0689302SJoao Martins 
9215092db87SJoao Martins     gpa = env->xen_vcpu_runstate_gpa;
9225092db87SJoao Martins     if (gpa != INVALID_GPA) {
9235092db87SJoao Martins         ret = kvm_xen_set_vcpu_attr(cs, KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADDR,
9245092db87SJoao Martins                                     gpa);
9255092db87SJoao Martins         if (ret < 0) {
9265092db87SJoao Martins             return ret;
9275092db87SJoao Martins         }
9285092db87SJoao Martins     }
9295092db87SJoao Martins 
930105b47fdSAnkur Arora     if (!kvm_xen_has_cap(EVTCHN_SEND)) {
931105b47fdSAnkur Arora         return 0;
932105b47fdSAnkur Arora     }
933105b47fdSAnkur Arora 
934105b47fdSAnkur Arora     if (env->xen_vcpu_callback_vector) {
935105b47fdSAnkur Arora         ret = kvm_xen_set_vcpu_callback_vector(cs);
936105b47fdSAnkur Arora         if (ret < 0) {
937105b47fdSAnkur Arora             return ret;
938105b47fdSAnkur Arora         }
939105b47fdSAnkur Arora     }
940105b47fdSAnkur Arora 
941c345104cSJoao Martins     return 0;
942c345104cSJoao Martins }
943c345104cSJoao Martins 
944c345104cSJoao Martins int kvm_get_xen_state(CPUState *cs)
945c345104cSJoao Martins {
946c345104cSJoao Martins     X86CPU *cpu = X86_CPU(cs);
947c345104cSJoao Martins     CPUX86State *env = &cpu->env;
948c345104cSJoao Martins     uint64_t gpa;
949c345104cSJoao Martins 
950c345104cSJoao Martins     /*
951c345104cSJoao Martins      * The kernel does not mark vcpu_info as dirty when it delivers interrupts
952c345104cSJoao Martins      * to it. It's up to userspace to *assume* that any page shared thus is
953c345104cSJoao Martins      * always considered dirty. The shared_info page is different since it's
954c345104cSJoao Martins      * an overlay and migrated separately anyway.
955c345104cSJoao Martins      */
956c345104cSJoao Martins     gpa = env->xen_vcpu_info_gpa;
957c345104cSJoao Martins     if (gpa == INVALID_GPA) {
958c345104cSJoao Martins         gpa = env->xen_vcpu_info_default_gpa;
959c345104cSJoao Martins     }
960c345104cSJoao Martins     if (gpa != INVALID_GPA) {
961c345104cSJoao Martins         MemoryRegionSection mrs = memory_region_find(get_system_memory(),
962c345104cSJoao Martins                                                      gpa,
963c345104cSJoao Martins                                                      sizeof(struct vcpu_info));
964c345104cSJoao Martins         if (mrs.mr &&
965c345104cSJoao Martins             !int128_lt(mrs.size, int128_make64(sizeof(struct vcpu_info)))) {
966c345104cSJoao Martins             memory_region_set_dirty(mrs.mr, mrs.offset_within_region,
967c345104cSJoao Martins                                     sizeof(struct vcpu_info));
968c345104cSJoao Martins         }
969c345104cSJoao Martins     }
970c345104cSJoao Martins 
971c345104cSJoao Martins     return 0;
972c345104cSJoao Martins }
973