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 2427d4075dSDavid Woodhouse #include "hw/pci/msi.h" 2527d4075dSDavid Woodhouse #include "hw/i386/apic-msidef.h" 26110a0ea5SDavid Woodhouse #include "hw/i386/kvm/xen_overlay.h" 2791cce756SDavid Woodhouse #include "hw/i386/kvm/xen_evtchn.h" 28a28b0fc0SDavid Woodhouse #include "hw/i386/kvm/xen_gnttab.h" 29110a0ea5SDavid Woodhouse 30bedcc139SJoao Martins #include "hw/xen/interface/version.h" 3179b7067dSJoao Martins #include "hw/xen/interface/sched.h" 32fb0fd2ceSJoao Martins #include "hw/xen/interface/memory.h" 33671bfdcdSJoao Martins #include "hw/xen/interface/hvm/hvm_op.h" 34105b47fdSAnkur Arora #include "hw/xen/interface/hvm/params.h" 35d70bd6a4SJoao Martins #include "hw/xen/interface/vcpu.h" 363b06f29bSJoao Martins #include "hw/xen/interface/event_channel.h" 3728b7ae94SDavid Woodhouse #include "hw/xen/interface/grant_table.h" 38fb0fd2ceSJoao Martins 39fb0fd2ceSJoao Martins #include "xen-compat.h" 40fb0fd2ceSJoao Martins 41fb0fd2ceSJoao Martins #ifdef TARGET_X86_64 42fb0fd2ceSJoao Martins #define hypercall_compat32(longmode) (!(longmode)) 43fb0fd2ceSJoao Martins #else 44fb0fd2ceSJoao Martins #define hypercall_compat32(longmode) (false) 45fb0fd2ceSJoao Martins #endif 46bedcc139SJoao Martins 47f0689302SJoao Martins static bool kvm_gva_to_gpa(CPUState *cs, uint64_t gva, uint64_t *gpa, 48f0689302SJoao Martins size_t *len, bool is_write) 49bedcc139SJoao Martins { 50bedcc139SJoao Martins struct kvm_translation tr = { 51bedcc139SJoao Martins .linear_address = gva, 52bedcc139SJoao Martins }; 53bedcc139SJoao Martins 54f0689302SJoao Martins if (len) { 55f0689302SJoao Martins *len = TARGET_PAGE_SIZE - (gva & ~TARGET_PAGE_MASK); 56f0689302SJoao Martins } 57f0689302SJoao Martins 58f0689302SJoao Martins if (kvm_vcpu_ioctl(cs, KVM_TRANSLATE, &tr) || !tr.valid || 59f0689302SJoao Martins (is_write && !tr.writeable)) { 60f0689302SJoao Martins return false; 61f0689302SJoao Martins } 62f0689302SJoao Martins *gpa = tr.physical_address; 63f0689302SJoao Martins return true; 64f0689302SJoao Martins } 65f0689302SJoao Martins 66f0689302SJoao Martins static int kvm_gva_rw(CPUState *cs, uint64_t gva, void *_buf, size_t sz, 67f0689302SJoao Martins bool is_write) 68f0689302SJoao Martins { 69f0689302SJoao Martins uint8_t *buf = (uint8_t *)_buf; 70f0689302SJoao Martins uint64_t gpa; 71f0689302SJoao Martins size_t len; 72f0689302SJoao Martins 73f0689302SJoao Martins while (sz) { 74f0689302SJoao Martins if (!kvm_gva_to_gpa(cs, gva, &gpa, &len, is_write)) { 75f0689302SJoao Martins return -EFAULT; 76f0689302SJoao Martins } 77bedcc139SJoao Martins if (len > sz) { 78bedcc139SJoao Martins len = sz; 79bedcc139SJoao Martins } 80bedcc139SJoao Martins 81f0689302SJoao Martins cpu_physical_memory_rw(gpa, buf, len, is_write); 82bedcc139SJoao Martins 83bedcc139SJoao Martins buf += len; 84bedcc139SJoao Martins sz -= len; 85bedcc139SJoao Martins gva += len; 86bedcc139SJoao Martins } 87bedcc139SJoao Martins 88bedcc139SJoao Martins return 0; 89bedcc139SJoao Martins } 90bedcc139SJoao Martins 91bedcc139SJoao Martins static inline int kvm_copy_from_gva(CPUState *cs, uint64_t gva, void *buf, 92bedcc139SJoao Martins size_t sz) 93bedcc139SJoao Martins { 94bedcc139SJoao Martins return kvm_gva_rw(cs, gva, buf, sz, false); 95bedcc139SJoao Martins } 96bedcc139SJoao Martins 97bedcc139SJoao Martins static inline int kvm_copy_to_gva(CPUState *cs, uint64_t gva, void *buf, 98bedcc139SJoao Martins size_t sz) 99bedcc139SJoao Martins { 100bedcc139SJoao Martins return kvm_gva_rw(cs, gva, buf, sz, true); 101bedcc139SJoao Martins } 102bedcc139SJoao Martins 103f66b8a83SJoao Martins int kvm_xen_init(KVMState *s, uint32_t hypercall_msr) 10461491cf4SDavid Woodhouse { 10561491cf4SDavid Woodhouse const int required_caps = KVM_XEN_HVM_CONFIG_HYPERCALL_MSR | 10661491cf4SDavid Woodhouse KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL | KVM_XEN_HVM_CONFIG_SHARED_INFO; 10761491cf4SDavid Woodhouse struct kvm_xen_hvm_config cfg = { 108f66b8a83SJoao Martins .msr = hypercall_msr, 10961491cf4SDavid Woodhouse .flags = KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL, 11061491cf4SDavid Woodhouse }; 11161491cf4SDavid Woodhouse int xen_caps, ret; 11261491cf4SDavid Woodhouse 11361491cf4SDavid Woodhouse xen_caps = kvm_check_extension(s, KVM_CAP_XEN_HVM); 11461491cf4SDavid Woodhouse if (required_caps & ~xen_caps) { 11561491cf4SDavid Woodhouse error_report("kvm: Xen HVM guest support not present or insufficient"); 11661491cf4SDavid Woodhouse return -ENOSYS; 11761491cf4SDavid Woodhouse } 11861491cf4SDavid Woodhouse 11961491cf4SDavid Woodhouse if (xen_caps & KVM_XEN_HVM_CONFIG_EVTCHN_SEND) { 12061491cf4SDavid Woodhouse struct kvm_xen_hvm_attr ha = { 12161491cf4SDavid Woodhouse .type = KVM_XEN_ATTR_TYPE_XEN_VERSION, 12261491cf4SDavid Woodhouse .u.xen_version = s->xen_version, 12361491cf4SDavid Woodhouse }; 12461491cf4SDavid Woodhouse (void)kvm_vm_ioctl(s, KVM_XEN_HVM_SET_ATTR, &ha); 12561491cf4SDavid Woodhouse 12661491cf4SDavid Woodhouse cfg.flags |= KVM_XEN_HVM_CONFIG_EVTCHN_SEND; 12761491cf4SDavid Woodhouse } 12861491cf4SDavid Woodhouse 12961491cf4SDavid Woodhouse ret = kvm_vm_ioctl(s, KVM_XEN_HVM_CONFIG, &cfg); 13061491cf4SDavid Woodhouse if (ret < 0) { 13161491cf4SDavid Woodhouse error_report("kvm: Failed to enable Xen HVM support: %s", 13261491cf4SDavid Woodhouse strerror(-ret)); 13361491cf4SDavid Woodhouse return ret; 13461491cf4SDavid Woodhouse } 13561491cf4SDavid Woodhouse 1362aff696bSDavid Woodhouse /* If called a second time, don't repeat the rest of the setup. */ 1372aff696bSDavid Woodhouse if (s->xen_caps) { 1382aff696bSDavid Woodhouse return 0; 1392aff696bSDavid Woodhouse } 1402aff696bSDavid Woodhouse 1412aff696bSDavid Woodhouse /* 1422aff696bSDavid Woodhouse * Event channel delivery via GSI/PCI_INTX needs to poll the vcpu_info 1432aff696bSDavid Woodhouse * of vCPU0 to deassert the IRQ when ->evtchn_upcall_pending is cleared. 1442aff696bSDavid Woodhouse * 1452aff696bSDavid Woodhouse * In the kernel, there's a notifier hook on the PIC/IOAPIC which allows 1462aff696bSDavid Woodhouse * such things to be polled at precisely the right time. We *could* do 1472aff696bSDavid Woodhouse * it nicely in the kernel: check vcpu_info[0]->evtchn_upcall_pending at 1482aff696bSDavid Woodhouse * the moment the IRQ is acked, and see if it should be reasserted. 1492aff696bSDavid Woodhouse * 1502aff696bSDavid Woodhouse * But the in-kernel irqchip is deprecated, so we're unlikely to add 1512aff696bSDavid Woodhouse * that support in the kernel. Insist on using the split irqchip mode 1522aff696bSDavid Woodhouse * instead. 1532aff696bSDavid Woodhouse * 1542aff696bSDavid Woodhouse * This leaves us polling for the level going low in QEMU, which lacks 1552aff696bSDavid Woodhouse * the appropriate hooks in its PIC/IOAPIC code. Even VFIO is sending a 1562aff696bSDavid Woodhouse * spurious 'ack' to an INTX IRQ every time there's any MMIO access to 1572aff696bSDavid Woodhouse * the device (for which it has to unmap the device and trap access, for 1582aff696bSDavid Woodhouse * some period after an IRQ!!). In the Xen case, we do it on exit from 1592aff696bSDavid Woodhouse * KVM_RUN, if the flag is set to say that the GSI is currently asserted. 1602aff696bSDavid Woodhouse * Which is kind of icky, but less so than the VFIO one. I may fix them 1612aff696bSDavid Woodhouse * both later... 1622aff696bSDavid Woodhouse */ 1632aff696bSDavid Woodhouse if (!kvm_kernel_irqchip_split()) { 1642aff696bSDavid Woodhouse error_report("kvm: Xen support requires kernel-irqchip=split"); 1652aff696bSDavid Woodhouse return -EINVAL; 1662aff696bSDavid Woodhouse } 1672aff696bSDavid Woodhouse 16861491cf4SDavid Woodhouse s->xen_caps = xen_caps; 16961491cf4SDavid Woodhouse return 0; 17061491cf4SDavid Woodhouse } 17161491cf4SDavid Woodhouse 1725e691a95SDavid Woodhouse int kvm_xen_init_vcpu(CPUState *cs) 1735e691a95SDavid Woodhouse { 174c345104cSJoao Martins X86CPU *cpu = X86_CPU(cs); 175c345104cSJoao Martins CPUX86State *env = &cpu->env; 1765e691a95SDavid Woodhouse int err; 1775e691a95SDavid Woodhouse 1785e691a95SDavid Woodhouse /* 1795e691a95SDavid Woodhouse * The kernel needs to know the Xen/ACPI vCPU ID because that's 1805e691a95SDavid Woodhouse * what the guest uses in hypercalls such as timers. It doesn't 1815e691a95SDavid Woodhouse * match the APIC ID which is generally used for talking to the 1825e691a95SDavid Woodhouse * kernel about vCPUs. And if vCPU threads race with creating 1835e691a95SDavid Woodhouse * their KVM vCPUs out of order, it doesn't necessarily match 1845e691a95SDavid Woodhouse * with the kernel's internal vCPU indices either. 1855e691a95SDavid Woodhouse */ 1865e691a95SDavid Woodhouse if (kvm_xen_has_cap(EVTCHN_SEND)) { 1875e691a95SDavid Woodhouse struct kvm_xen_vcpu_attr va = { 1885e691a95SDavid Woodhouse .type = KVM_XEN_VCPU_ATTR_TYPE_VCPU_ID, 1895e691a95SDavid Woodhouse .u.vcpu_id = cs->cpu_index, 1905e691a95SDavid Woodhouse }; 1915e691a95SDavid Woodhouse err = kvm_vcpu_ioctl(cs, KVM_XEN_VCPU_SET_ATTR, &va); 1925e691a95SDavid Woodhouse if (err) { 1935e691a95SDavid Woodhouse error_report("kvm: Failed to set Xen vCPU ID attribute: %s", 1945e691a95SDavid Woodhouse strerror(-err)); 1955e691a95SDavid Woodhouse return err; 1965e691a95SDavid Woodhouse } 1975e691a95SDavid Woodhouse } 1985e691a95SDavid Woodhouse 199c345104cSJoao Martins env->xen_vcpu_info_gpa = INVALID_GPA; 200c345104cSJoao Martins env->xen_vcpu_info_default_gpa = INVALID_GPA; 201f0689302SJoao Martins env->xen_vcpu_time_info_gpa = INVALID_GPA; 2025092db87SJoao Martins env->xen_vcpu_runstate_gpa = INVALID_GPA; 203c345104cSJoao Martins 2045e691a95SDavid Woodhouse return 0; 2055e691a95SDavid Woodhouse } 2065e691a95SDavid Woodhouse 20761491cf4SDavid Woodhouse uint32_t kvm_xen_get_caps(void) 20861491cf4SDavid Woodhouse { 20961491cf4SDavid Woodhouse return kvm_state->xen_caps; 21061491cf4SDavid Woodhouse } 21155a3f666SJoao Martins 212bedcc139SJoao Martins static bool kvm_xen_hcall_xen_version(struct kvm_xen_exit *exit, X86CPU *cpu, 213bedcc139SJoao Martins int cmd, uint64_t arg) 214bedcc139SJoao Martins { 215bedcc139SJoao Martins int err = 0; 216bedcc139SJoao Martins 217bedcc139SJoao Martins switch (cmd) { 218bedcc139SJoao Martins case XENVER_get_features: { 219bedcc139SJoao Martins struct xen_feature_info fi; 220bedcc139SJoao Martins 221bedcc139SJoao Martins /* No need for 32/64 compat handling */ 222bedcc139SJoao Martins qemu_build_assert(sizeof(fi) == 8); 223bedcc139SJoao Martins 224bedcc139SJoao Martins err = kvm_copy_from_gva(CPU(cpu), arg, &fi, sizeof(fi)); 225bedcc139SJoao Martins if (err) { 226bedcc139SJoao Martins break; 227bedcc139SJoao Martins } 228bedcc139SJoao Martins 229bedcc139SJoao Martins fi.submap = 0; 230bedcc139SJoao Martins if (fi.submap_idx == 0) { 231bedcc139SJoao Martins fi.submap |= 1 << XENFEAT_writable_page_tables | 232bedcc139SJoao Martins 1 << XENFEAT_writable_descriptor_tables | 233bedcc139SJoao Martins 1 << XENFEAT_auto_translated_physmap | 234105b47fdSAnkur Arora 1 << XENFEAT_supervisor_mode_kernel | 235105b47fdSAnkur Arora 1 << XENFEAT_hvm_callback_vector; 236bedcc139SJoao Martins } 237bedcc139SJoao Martins 238bedcc139SJoao Martins err = kvm_copy_to_gva(CPU(cpu), arg, &fi, sizeof(fi)); 239bedcc139SJoao Martins break; 240bedcc139SJoao Martins } 241bedcc139SJoao Martins 242bedcc139SJoao Martins default: 243bedcc139SJoao Martins return false; 244bedcc139SJoao Martins } 245bedcc139SJoao Martins 246bedcc139SJoao Martins exit->u.hcall.result = err; 247bedcc139SJoao Martins return true; 248bedcc139SJoao Martins } 249bedcc139SJoao Martins 250c345104cSJoao Martins static int kvm_xen_set_vcpu_attr(CPUState *cs, uint16_t type, uint64_t gpa) 251c345104cSJoao Martins { 252c345104cSJoao Martins struct kvm_xen_vcpu_attr xhsi; 253c345104cSJoao Martins 254c345104cSJoao Martins xhsi.type = type; 255c345104cSJoao Martins xhsi.u.gpa = gpa; 256c345104cSJoao Martins 257c345104cSJoao Martins trace_kvm_xen_set_vcpu_attr(cs->cpu_index, type, gpa); 258c345104cSJoao Martins 259c345104cSJoao Martins return kvm_vcpu_ioctl(cs, KVM_XEN_VCPU_SET_ATTR, &xhsi); 260c345104cSJoao Martins } 261c345104cSJoao Martins 262105b47fdSAnkur Arora static int kvm_xen_set_vcpu_callback_vector(CPUState *cs) 263105b47fdSAnkur Arora { 264105b47fdSAnkur Arora uint8_t vector = X86_CPU(cs)->env.xen_vcpu_callback_vector; 265105b47fdSAnkur Arora struct kvm_xen_vcpu_attr xva; 266105b47fdSAnkur Arora 267105b47fdSAnkur Arora xva.type = KVM_XEN_VCPU_ATTR_TYPE_UPCALL_VECTOR; 268105b47fdSAnkur Arora xva.u.vector = vector; 269105b47fdSAnkur Arora 270105b47fdSAnkur Arora trace_kvm_xen_set_vcpu_callback(cs->cpu_index, vector); 271105b47fdSAnkur Arora 272105b47fdSAnkur Arora return kvm_vcpu_ioctl(cs, KVM_XEN_HVM_SET_ATTR, &xva); 273105b47fdSAnkur Arora } 274105b47fdSAnkur Arora 275105b47fdSAnkur Arora static void do_set_vcpu_callback_vector(CPUState *cs, run_on_cpu_data data) 276105b47fdSAnkur Arora { 277105b47fdSAnkur Arora X86CPU *cpu = X86_CPU(cs); 278105b47fdSAnkur Arora CPUX86State *env = &cpu->env; 279105b47fdSAnkur Arora 280105b47fdSAnkur Arora env->xen_vcpu_callback_vector = data.host_int; 281105b47fdSAnkur Arora 282105b47fdSAnkur Arora if (kvm_xen_has_cap(EVTCHN_SEND)) { 283105b47fdSAnkur Arora kvm_xen_set_vcpu_callback_vector(cs); 284105b47fdSAnkur Arora } 285105b47fdSAnkur Arora } 286105b47fdSAnkur Arora 28727d4075dSDavid Woodhouse static int set_vcpu_info(CPUState *cs, uint64_t gpa) 28827d4075dSDavid Woodhouse { 28927d4075dSDavid Woodhouse X86CPU *cpu = X86_CPU(cs); 29027d4075dSDavid Woodhouse CPUX86State *env = &cpu->env; 29127d4075dSDavid Woodhouse MemoryRegionSection mrs = { .mr = NULL }; 29227d4075dSDavid Woodhouse void *vcpu_info_hva = NULL; 29327d4075dSDavid Woodhouse int ret; 29427d4075dSDavid Woodhouse 29527d4075dSDavid Woodhouse ret = kvm_xen_set_vcpu_attr(cs, KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO, gpa); 29627d4075dSDavid Woodhouse if (ret || gpa == INVALID_GPA) { 29727d4075dSDavid Woodhouse goto out; 29827d4075dSDavid Woodhouse } 29927d4075dSDavid Woodhouse 30027d4075dSDavid Woodhouse mrs = memory_region_find(get_system_memory(), gpa, 30127d4075dSDavid Woodhouse sizeof(struct vcpu_info)); 30227d4075dSDavid Woodhouse if (mrs.mr && mrs.mr->ram_block && 30327d4075dSDavid Woodhouse !int128_lt(mrs.size, int128_make64(sizeof(struct vcpu_info)))) { 30427d4075dSDavid Woodhouse vcpu_info_hva = qemu_map_ram_ptr(mrs.mr->ram_block, 30527d4075dSDavid Woodhouse mrs.offset_within_region); 30627d4075dSDavid Woodhouse } 30727d4075dSDavid Woodhouse if (!vcpu_info_hva) { 30827d4075dSDavid Woodhouse if (mrs.mr) { 30927d4075dSDavid Woodhouse memory_region_unref(mrs.mr); 31027d4075dSDavid Woodhouse mrs.mr = NULL; 31127d4075dSDavid Woodhouse } 31227d4075dSDavid Woodhouse ret = -EINVAL; 31327d4075dSDavid Woodhouse } 31427d4075dSDavid Woodhouse 31527d4075dSDavid Woodhouse out: 31627d4075dSDavid Woodhouse if (env->xen_vcpu_info_mr) { 31727d4075dSDavid Woodhouse memory_region_unref(env->xen_vcpu_info_mr); 31827d4075dSDavid Woodhouse } 31927d4075dSDavid Woodhouse env->xen_vcpu_info_hva = vcpu_info_hva; 32027d4075dSDavid Woodhouse env->xen_vcpu_info_mr = mrs.mr; 32127d4075dSDavid Woodhouse return ret; 32227d4075dSDavid Woodhouse } 32327d4075dSDavid Woodhouse 324c345104cSJoao Martins static void do_set_vcpu_info_default_gpa(CPUState *cs, run_on_cpu_data data) 325c345104cSJoao Martins { 326c345104cSJoao Martins X86CPU *cpu = X86_CPU(cs); 327c345104cSJoao Martins CPUX86State *env = &cpu->env; 328c345104cSJoao Martins 329c345104cSJoao Martins env->xen_vcpu_info_default_gpa = data.host_ulong; 330c345104cSJoao Martins 331c345104cSJoao Martins /* Changing the default does nothing if a vcpu_info was explicitly set. */ 332c345104cSJoao Martins if (env->xen_vcpu_info_gpa == INVALID_GPA) { 33327d4075dSDavid Woodhouse set_vcpu_info(cs, env->xen_vcpu_info_default_gpa); 334c345104cSJoao Martins } 335c345104cSJoao Martins } 336c345104cSJoao Martins 337c345104cSJoao Martins static void do_set_vcpu_info_gpa(CPUState *cs, run_on_cpu_data data) 338c345104cSJoao Martins { 339c345104cSJoao Martins X86CPU *cpu = X86_CPU(cs); 340c345104cSJoao Martins CPUX86State *env = &cpu->env; 341c345104cSJoao Martins 342c345104cSJoao Martins env->xen_vcpu_info_gpa = data.host_ulong; 343c345104cSJoao Martins 34427d4075dSDavid Woodhouse set_vcpu_info(cs, env->xen_vcpu_info_gpa); 34527d4075dSDavid Woodhouse } 34627d4075dSDavid Woodhouse 34727d4075dSDavid Woodhouse void *kvm_xen_get_vcpu_info_hva(uint32_t vcpu_id) 34827d4075dSDavid Woodhouse { 34927d4075dSDavid Woodhouse CPUState *cs = qemu_get_cpu(vcpu_id); 35027d4075dSDavid Woodhouse if (!cs) { 35127d4075dSDavid Woodhouse return NULL; 35227d4075dSDavid Woodhouse } 35327d4075dSDavid Woodhouse 35427d4075dSDavid Woodhouse return X86_CPU(cs)->env.xen_vcpu_info_hva; 35527d4075dSDavid Woodhouse } 35627d4075dSDavid Woodhouse 357ddf0fd9aSDavid Woodhouse void kvm_xen_maybe_deassert_callback(CPUState *cs) 358ddf0fd9aSDavid Woodhouse { 359ddf0fd9aSDavid Woodhouse CPUX86State *env = &X86_CPU(cs)->env; 360ddf0fd9aSDavid Woodhouse struct vcpu_info *vi = env->xen_vcpu_info_hva; 361ddf0fd9aSDavid Woodhouse if (!vi) { 362ddf0fd9aSDavid Woodhouse return; 363ddf0fd9aSDavid Woodhouse } 364ddf0fd9aSDavid Woodhouse 365ddf0fd9aSDavid Woodhouse /* If the evtchn_upcall_pending flag is cleared, turn the GSI off. */ 366ddf0fd9aSDavid Woodhouse if (!vi->evtchn_upcall_pending) { 367ddf0fd9aSDavid Woodhouse qemu_mutex_lock_iothread(); 368ddf0fd9aSDavid Woodhouse /* 369ddf0fd9aSDavid Woodhouse * Check again now we have the lock, because it may have been 370ddf0fd9aSDavid Woodhouse * asserted in the interim. And we don't want to take the lock 371ddf0fd9aSDavid Woodhouse * every time because this is a fast path. 372ddf0fd9aSDavid Woodhouse */ 373ddf0fd9aSDavid Woodhouse if (!vi->evtchn_upcall_pending) { 374ddf0fd9aSDavid Woodhouse X86_CPU(cs)->env.xen_callback_asserted = false; 375ddf0fd9aSDavid Woodhouse xen_evtchn_set_callback_level(0); 376ddf0fd9aSDavid Woodhouse } 377ddf0fd9aSDavid Woodhouse qemu_mutex_unlock_iothread(); 378ddf0fd9aSDavid Woodhouse } 379ddf0fd9aSDavid Woodhouse } 380ddf0fd9aSDavid Woodhouse 381ddf0fd9aSDavid Woodhouse void kvm_xen_set_callback_asserted(void) 382ddf0fd9aSDavid Woodhouse { 383ddf0fd9aSDavid Woodhouse CPUState *cs = qemu_get_cpu(0); 384ddf0fd9aSDavid Woodhouse 385ddf0fd9aSDavid Woodhouse if (cs) { 386ddf0fd9aSDavid Woodhouse X86_CPU(cs)->env.xen_callback_asserted = true; 387ddf0fd9aSDavid Woodhouse } 388ddf0fd9aSDavid Woodhouse } 389ddf0fd9aSDavid Woodhouse 39027d4075dSDavid Woodhouse void kvm_xen_inject_vcpu_callback_vector(uint32_t vcpu_id, int type) 39127d4075dSDavid Woodhouse { 39227d4075dSDavid Woodhouse CPUState *cs = qemu_get_cpu(vcpu_id); 39327d4075dSDavid Woodhouse uint8_t vector; 39427d4075dSDavid Woodhouse 39527d4075dSDavid Woodhouse if (!cs) { 39627d4075dSDavid Woodhouse return; 39727d4075dSDavid Woodhouse } 39827d4075dSDavid Woodhouse 39927d4075dSDavid Woodhouse vector = X86_CPU(cs)->env.xen_vcpu_callback_vector; 40027d4075dSDavid Woodhouse if (vector) { 40127d4075dSDavid Woodhouse /* 40227d4075dSDavid Woodhouse * The per-vCPU callback vector injected via lapic. Just 40327d4075dSDavid Woodhouse * deliver it as an MSI. 40427d4075dSDavid Woodhouse */ 40527d4075dSDavid Woodhouse MSIMessage msg = { 40627d4075dSDavid Woodhouse .address = APIC_DEFAULT_ADDRESS | X86_CPU(cs)->apic_id, 40727d4075dSDavid Woodhouse .data = vector | (1UL << MSI_DATA_LEVEL_SHIFT), 40827d4075dSDavid Woodhouse }; 40927d4075dSDavid Woodhouse kvm_irqchip_send_msi(kvm_state, msg); 41027d4075dSDavid Woodhouse return; 41127d4075dSDavid Woodhouse } 41227d4075dSDavid Woodhouse 41327d4075dSDavid Woodhouse switch (type) { 41427d4075dSDavid Woodhouse case HVM_PARAM_CALLBACK_TYPE_VECTOR: 41527d4075dSDavid Woodhouse /* 41627d4075dSDavid Woodhouse * If the evtchn_upcall_pending field in the vcpu_info is set, then 41727d4075dSDavid Woodhouse * KVM will automatically deliver the vector on entering the vCPU 41827d4075dSDavid Woodhouse * so all we have to do is kick it out. 41927d4075dSDavid Woodhouse */ 42027d4075dSDavid Woodhouse qemu_cpu_kick(cs); 42127d4075dSDavid Woodhouse break; 422ddf0fd9aSDavid Woodhouse 423ddf0fd9aSDavid Woodhouse case HVM_PARAM_CALLBACK_TYPE_GSI: 424ddf0fd9aSDavid Woodhouse case HVM_PARAM_CALLBACK_TYPE_PCI_INTX: 425ddf0fd9aSDavid Woodhouse if (vcpu_id == 0) { 426ddf0fd9aSDavid Woodhouse xen_evtchn_set_callback_level(1); 427ddf0fd9aSDavid Woodhouse } 428ddf0fd9aSDavid Woodhouse break; 42927d4075dSDavid Woodhouse } 430c345104cSJoao Martins } 431c345104cSJoao Martins 432c723d4c1SDavid Woodhouse static int kvm_xen_set_vcpu_timer(CPUState *cs) 433c723d4c1SDavid Woodhouse { 434c723d4c1SDavid Woodhouse X86CPU *cpu = X86_CPU(cs); 435c723d4c1SDavid Woodhouse CPUX86State *env = &cpu->env; 436c723d4c1SDavid Woodhouse 437c723d4c1SDavid Woodhouse struct kvm_xen_vcpu_attr va = { 438c723d4c1SDavid Woodhouse .type = KVM_XEN_VCPU_ATTR_TYPE_TIMER, 439c723d4c1SDavid Woodhouse .u.timer.port = env->xen_virq[VIRQ_TIMER], 440c723d4c1SDavid Woodhouse .u.timer.priority = KVM_IRQ_ROUTING_XEN_EVTCHN_PRIO_2LEVEL, 441c723d4c1SDavid Woodhouse .u.timer.expires_ns = env->xen_singleshot_timer_ns, 442c723d4c1SDavid Woodhouse }; 443c723d4c1SDavid Woodhouse 444c723d4c1SDavid Woodhouse return kvm_vcpu_ioctl(cs, KVM_XEN_VCPU_SET_ATTR, &va); 445c723d4c1SDavid Woodhouse } 446c723d4c1SDavid Woodhouse 447c723d4c1SDavid Woodhouse static void do_set_vcpu_timer_virq(CPUState *cs, run_on_cpu_data data) 448c723d4c1SDavid Woodhouse { 449c723d4c1SDavid Woodhouse kvm_xen_set_vcpu_timer(cs); 450c723d4c1SDavid Woodhouse } 451c723d4c1SDavid Woodhouse 452c723d4c1SDavid Woodhouse int kvm_xen_set_vcpu_virq(uint32_t vcpu_id, uint16_t virq, uint16_t port) 453c723d4c1SDavid Woodhouse { 454c723d4c1SDavid Woodhouse CPUState *cs = qemu_get_cpu(vcpu_id); 455c723d4c1SDavid Woodhouse 456c723d4c1SDavid Woodhouse if (!cs) { 457c723d4c1SDavid Woodhouse return -ENOENT; 458c723d4c1SDavid Woodhouse } 459c723d4c1SDavid Woodhouse 460c723d4c1SDavid Woodhouse /* cpu.h doesn't include the actual Xen header. */ 461c723d4c1SDavid Woodhouse qemu_build_assert(NR_VIRQS == XEN_NR_VIRQS); 462c723d4c1SDavid Woodhouse 463c723d4c1SDavid Woodhouse if (virq >= NR_VIRQS) { 464c723d4c1SDavid Woodhouse return -EINVAL; 465c723d4c1SDavid Woodhouse } 466c723d4c1SDavid Woodhouse 467c723d4c1SDavid Woodhouse if (port && X86_CPU(cs)->env.xen_virq[virq]) { 468c723d4c1SDavid Woodhouse return -EEXIST; 469c723d4c1SDavid Woodhouse } 470c723d4c1SDavid Woodhouse 471c723d4c1SDavid Woodhouse X86_CPU(cs)->env.xen_virq[virq] = port; 472c723d4c1SDavid Woodhouse if (virq == VIRQ_TIMER && kvm_xen_has_cap(EVTCHN_SEND)) { 473c723d4c1SDavid Woodhouse async_run_on_cpu(cs, do_set_vcpu_timer_virq, 474c723d4c1SDavid Woodhouse RUN_ON_CPU_HOST_INT(port)); 475c723d4c1SDavid Woodhouse } 476c723d4c1SDavid Woodhouse return 0; 477c723d4c1SDavid Woodhouse } 478c723d4c1SDavid Woodhouse 479f0689302SJoao Martins static void do_set_vcpu_time_info_gpa(CPUState *cs, run_on_cpu_data data) 480f0689302SJoao Martins { 481f0689302SJoao Martins X86CPU *cpu = X86_CPU(cs); 482f0689302SJoao Martins CPUX86State *env = &cpu->env; 483f0689302SJoao Martins 484f0689302SJoao Martins env->xen_vcpu_time_info_gpa = data.host_ulong; 485f0689302SJoao Martins 486f0689302SJoao Martins kvm_xen_set_vcpu_attr(cs, KVM_XEN_VCPU_ATTR_TYPE_VCPU_TIME_INFO, 487f0689302SJoao Martins env->xen_vcpu_time_info_gpa); 488f0689302SJoao Martins } 489f0689302SJoao Martins 4905092db87SJoao Martins static void do_set_vcpu_runstate_gpa(CPUState *cs, run_on_cpu_data data) 4915092db87SJoao Martins { 4925092db87SJoao Martins X86CPU *cpu = X86_CPU(cs); 4935092db87SJoao Martins CPUX86State *env = &cpu->env; 4945092db87SJoao Martins 4955092db87SJoao Martins env->xen_vcpu_runstate_gpa = data.host_ulong; 4965092db87SJoao Martins 4975092db87SJoao Martins kvm_xen_set_vcpu_attr(cs, KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADDR, 4985092db87SJoao Martins env->xen_vcpu_runstate_gpa); 4995092db87SJoao Martins } 5005092db87SJoao Martins 501c345104cSJoao Martins static void do_vcpu_soft_reset(CPUState *cs, run_on_cpu_data data) 502c345104cSJoao Martins { 503c345104cSJoao Martins X86CPU *cpu = X86_CPU(cs); 504c345104cSJoao Martins CPUX86State *env = &cpu->env; 505c345104cSJoao Martins 506c345104cSJoao Martins env->xen_vcpu_info_gpa = INVALID_GPA; 507c345104cSJoao Martins env->xen_vcpu_info_default_gpa = INVALID_GPA; 508f0689302SJoao Martins env->xen_vcpu_time_info_gpa = INVALID_GPA; 5095092db87SJoao Martins env->xen_vcpu_runstate_gpa = INVALID_GPA; 510105b47fdSAnkur Arora env->xen_vcpu_callback_vector = 0; 511c723d4c1SDavid Woodhouse env->xen_singleshot_timer_ns = 0; 512c723d4c1SDavid Woodhouse memset(env->xen_virq, 0, sizeof(env->xen_virq)); 513c345104cSJoao Martins 51427d4075dSDavid Woodhouse set_vcpu_info(cs, INVALID_GPA); 515f0689302SJoao Martins kvm_xen_set_vcpu_attr(cs, KVM_XEN_VCPU_ATTR_TYPE_VCPU_TIME_INFO, 516f0689302SJoao Martins INVALID_GPA); 5175092db87SJoao Martins kvm_xen_set_vcpu_attr(cs, KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADDR, 5185092db87SJoao Martins INVALID_GPA); 519105b47fdSAnkur Arora if (kvm_xen_has_cap(EVTCHN_SEND)) { 520105b47fdSAnkur Arora kvm_xen_set_vcpu_callback_vector(cs); 521c723d4c1SDavid Woodhouse kvm_xen_set_vcpu_timer(cs); 522105b47fdSAnkur Arora } 5235092db87SJoao Martins 524c345104cSJoao Martins } 525c345104cSJoao Martins 526fb0fd2ceSJoao Martins static int xen_set_shared_info(uint64_t gfn) 527fb0fd2ceSJoao Martins { 528fb0fd2ceSJoao Martins uint64_t gpa = gfn << TARGET_PAGE_BITS; 529c345104cSJoao Martins int i, err; 530fb0fd2ceSJoao Martins 531fb0fd2ceSJoao Martins QEMU_IOTHREAD_LOCK_GUARD(); 532fb0fd2ceSJoao Martins 533fb0fd2ceSJoao Martins /* 534fb0fd2ceSJoao Martins * The xen_overlay device tells KVM about it too, since it had to 535fb0fd2ceSJoao Martins * do that on migration load anyway (unless we're going to jump 536fb0fd2ceSJoao Martins * through lots of hoops to maintain the fiction that this isn't 537fb0fd2ceSJoao Martins * KVM-specific. 538fb0fd2ceSJoao Martins */ 539fb0fd2ceSJoao Martins err = xen_overlay_map_shinfo_page(gpa); 540fb0fd2ceSJoao Martins if (err) { 541fb0fd2ceSJoao Martins return err; 542fb0fd2ceSJoao Martins } 543fb0fd2ceSJoao Martins 544fb0fd2ceSJoao Martins trace_kvm_xen_set_shared_info(gfn); 545fb0fd2ceSJoao Martins 546c345104cSJoao Martins for (i = 0; i < XEN_LEGACY_MAX_VCPUS; i++) { 547c345104cSJoao Martins CPUState *cpu = qemu_get_cpu(i); 548c345104cSJoao Martins if (cpu) { 549c345104cSJoao Martins async_run_on_cpu(cpu, do_set_vcpu_info_default_gpa, 550c345104cSJoao Martins RUN_ON_CPU_HOST_ULONG(gpa)); 551c345104cSJoao Martins } 552c345104cSJoao Martins gpa += sizeof(vcpu_info_t); 553c345104cSJoao Martins } 554c345104cSJoao Martins 555fb0fd2ceSJoao Martins return err; 556fb0fd2ceSJoao Martins } 557fb0fd2ceSJoao Martins 558fb0fd2ceSJoao Martins static int add_to_physmap_one(uint32_t space, uint64_t idx, uint64_t gfn) 559fb0fd2ceSJoao Martins { 560fb0fd2ceSJoao Martins switch (space) { 561fb0fd2ceSJoao Martins case XENMAPSPACE_shared_info: 562fb0fd2ceSJoao Martins if (idx > 0) { 563fb0fd2ceSJoao Martins return -EINVAL; 564fb0fd2ceSJoao Martins } 565fb0fd2ceSJoao Martins return xen_set_shared_info(gfn); 566fb0fd2ceSJoao Martins 567fb0fd2ceSJoao Martins case XENMAPSPACE_grant_table: 568a28b0fc0SDavid Woodhouse return xen_gnttab_map_page(idx, gfn); 569a28b0fc0SDavid Woodhouse 570fb0fd2ceSJoao Martins case XENMAPSPACE_gmfn: 571fb0fd2ceSJoao Martins case XENMAPSPACE_gmfn_range: 572fb0fd2ceSJoao Martins return -ENOTSUP; 573fb0fd2ceSJoao Martins 574fb0fd2ceSJoao Martins case XENMAPSPACE_gmfn_foreign: 575fb0fd2ceSJoao Martins case XENMAPSPACE_dev_mmio: 576fb0fd2ceSJoao Martins return -EPERM; 577fb0fd2ceSJoao Martins 578fb0fd2ceSJoao Martins default: 579fb0fd2ceSJoao Martins return -EINVAL; 580fb0fd2ceSJoao Martins } 581fb0fd2ceSJoao Martins } 582fb0fd2ceSJoao Martins 583fb0fd2ceSJoao Martins static int do_add_to_physmap(struct kvm_xen_exit *exit, X86CPU *cpu, 584fb0fd2ceSJoao Martins uint64_t arg) 585fb0fd2ceSJoao Martins { 586fb0fd2ceSJoao Martins struct xen_add_to_physmap xatp; 587fb0fd2ceSJoao Martins CPUState *cs = CPU(cpu); 588fb0fd2ceSJoao Martins 589fb0fd2ceSJoao Martins if (hypercall_compat32(exit->u.hcall.longmode)) { 590fb0fd2ceSJoao Martins struct compat_xen_add_to_physmap xatp32; 591fb0fd2ceSJoao Martins 592fb0fd2ceSJoao Martins qemu_build_assert(sizeof(struct compat_xen_add_to_physmap) == 16); 593fb0fd2ceSJoao Martins if (kvm_copy_from_gva(cs, arg, &xatp32, sizeof(xatp32))) { 594fb0fd2ceSJoao Martins return -EFAULT; 595fb0fd2ceSJoao Martins } 596fb0fd2ceSJoao Martins xatp.domid = xatp32.domid; 597fb0fd2ceSJoao Martins xatp.size = xatp32.size; 598fb0fd2ceSJoao Martins xatp.space = xatp32.space; 599fb0fd2ceSJoao Martins xatp.idx = xatp32.idx; 600fb0fd2ceSJoao Martins xatp.gpfn = xatp32.gpfn; 601fb0fd2ceSJoao Martins } else { 602fb0fd2ceSJoao Martins if (kvm_copy_from_gva(cs, arg, &xatp, sizeof(xatp))) { 603fb0fd2ceSJoao Martins return -EFAULT; 604fb0fd2ceSJoao Martins } 605fb0fd2ceSJoao Martins } 606fb0fd2ceSJoao Martins 607fb0fd2ceSJoao Martins if (xatp.domid != DOMID_SELF && xatp.domid != xen_domid) { 608fb0fd2ceSJoao Martins return -ESRCH; 609fb0fd2ceSJoao Martins } 610fb0fd2ceSJoao Martins 611fb0fd2ceSJoao Martins return add_to_physmap_one(xatp.space, xatp.idx, xatp.gpfn); 612fb0fd2ceSJoao Martins } 613fb0fd2ceSJoao Martins 614782a7960SDavid Woodhouse static int do_add_to_physmap_batch(struct kvm_xen_exit *exit, X86CPU *cpu, 615782a7960SDavid Woodhouse uint64_t arg) 616782a7960SDavid Woodhouse { 617782a7960SDavid Woodhouse struct xen_add_to_physmap_batch xatpb; 618782a7960SDavid Woodhouse unsigned long idxs_gva, gpfns_gva, errs_gva; 619782a7960SDavid Woodhouse CPUState *cs = CPU(cpu); 620782a7960SDavid Woodhouse size_t op_sz; 621782a7960SDavid Woodhouse 622782a7960SDavid Woodhouse if (hypercall_compat32(exit->u.hcall.longmode)) { 623782a7960SDavid Woodhouse struct compat_xen_add_to_physmap_batch xatpb32; 624782a7960SDavid Woodhouse 625782a7960SDavid Woodhouse qemu_build_assert(sizeof(struct compat_xen_add_to_physmap_batch) == 20); 626782a7960SDavid Woodhouse if (kvm_copy_from_gva(cs, arg, &xatpb32, sizeof(xatpb32))) { 627782a7960SDavid Woodhouse return -EFAULT; 628782a7960SDavid Woodhouse } 629782a7960SDavid Woodhouse xatpb.domid = xatpb32.domid; 630782a7960SDavid Woodhouse xatpb.space = xatpb32.space; 631782a7960SDavid Woodhouse xatpb.size = xatpb32.size; 632782a7960SDavid Woodhouse 633782a7960SDavid Woodhouse idxs_gva = xatpb32.idxs.c; 634782a7960SDavid Woodhouse gpfns_gva = xatpb32.gpfns.c; 635782a7960SDavid Woodhouse errs_gva = xatpb32.errs.c; 636782a7960SDavid Woodhouse op_sz = sizeof(uint32_t); 637782a7960SDavid Woodhouse } else { 638782a7960SDavid Woodhouse if (kvm_copy_from_gva(cs, arg, &xatpb, sizeof(xatpb))) { 639782a7960SDavid Woodhouse return -EFAULT; 640782a7960SDavid Woodhouse } 641782a7960SDavid Woodhouse op_sz = sizeof(unsigned long); 642782a7960SDavid Woodhouse idxs_gva = (unsigned long)xatpb.idxs.p; 643782a7960SDavid Woodhouse gpfns_gva = (unsigned long)xatpb.gpfns.p; 644782a7960SDavid Woodhouse errs_gva = (unsigned long)xatpb.errs.p; 645782a7960SDavid Woodhouse } 646782a7960SDavid Woodhouse 647782a7960SDavid Woodhouse if (xatpb.domid != DOMID_SELF && xatpb.domid != xen_domid) { 648782a7960SDavid Woodhouse return -ESRCH; 649782a7960SDavid Woodhouse } 650782a7960SDavid Woodhouse 651782a7960SDavid Woodhouse /* Explicitly invalid for the batch op. Not that we implement it anyway. */ 652782a7960SDavid Woodhouse if (xatpb.space == XENMAPSPACE_gmfn_range) { 653782a7960SDavid Woodhouse return -EINVAL; 654782a7960SDavid Woodhouse } 655782a7960SDavid Woodhouse 656782a7960SDavid Woodhouse while (xatpb.size--) { 657782a7960SDavid Woodhouse unsigned long idx = 0; 658782a7960SDavid Woodhouse unsigned long gpfn = 0; 659782a7960SDavid Woodhouse int err; 660782a7960SDavid Woodhouse 661782a7960SDavid Woodhouse /* For 32-bit compat this only copies the low 32 bits of each */ 662782a7960SDavid Woodhouse if (kvm_copy_from_gva(cs, idxs_gva, &idx, op_sz) || 663782a7960SDavid Woodhouse kvm_copy_from_gva(cs, gpfns_gva, &gpfn, op_sz)) { 664782a7960SDavid Woodhouse return -EFAULT; 665782a7960SDavid Woodhouse } 666782a7960SDavid Woodhouse idxs_gva += op_sz; 667782a7960SDavid Woodhouse gpfns_gva += op_sz; 668782a7960SDavid Woodhouse 669782a7960SDavid Woodhouse err = add_to_physmap_one(xatpb.space, idx, gpfn); 670782a7960SDavid Woodhouse 671782a7960SDavid Woodhouse if (kvm_copy_to_gva(cs, errs_gva, &err, sizeof(err))) { 672782a7960SDavid Woodhouse return -EFAULT; 673782a7960SDavid Woodhouse } 674782a7960SDavid Woodhouse errs_gva += sizeof(err); 675782a7960SDavid Woodhouse } 676782a7960SDavid Woodhouse return 0; 677782a7960SDavid Woodhouse } 678782a7960SDavid Woodhouse 679fb0fd2ceSJoao Martins static bool kvm_xen_hcall_memory_op(struct kvm_xen_exit *exit, X86CPU *cpu, 680fb0fd2ceSJoao Martins int cmd, uint64_t arg) 681fb0fd2ceSJoao Martins { 682fb0fd2ceSJoao Martins int err; 683fb0fd2ceSJoao Martins 684fb0fd2ceSJoao Martins switch (cmd) { 685fb0fd2ceSJoao Martins case XENMEM_add_to_physmap: 686fb0fd2ceSJoao Martins err = do_add_to_physmap(exit, cpu, arg); 687fb0fd2ceSJoao Martins break; 688fb0fd2ceSJoao Martins 689782a7960SDavid Woodhouse case XENMEM_add_to_physmap_batch: 690782a7960SDavid Woodhouse err = do_add_to_physmap_batch(exit, cpu, arg); 691782a7960SDavid Woodhouse break; 692782a7960SDavid Woodhouse 693fb0fd2ceSJoao Martins default: 694fb0fd2ceSJoao Martins return false; 695fb0fd2ceSJoao Martins } 696fb0fd2ceSJoao Martins 697fb0fd2ceSJoao Martins exit->u.hcall.result = err; 698fb0fd2ceSJoao Martins return true; 699fb0fd2ceSJoao Martins } 700fb0fd2ceSJoao Martins 7015dbcd01aSAnkur Arora static bool handle_set_param(struct kvm_xen_exit *exit, X86CPU *cpu, 7025dbcd01aSAnkur Arora uint64_t arg) 7035dbcd01aSAnkur Arora { 7045dbcd01aSAnkur Arora CPUState *cs = CPU(cpu); 7055dbcd01aSAnkur Arora struct xen_hvm_param hp; 7065dbcd01aSAnkur Arora int err = 0; 7075dbcd01aSAnkur Arora 7085dbcd01aSAnkur Arora /* No need for 32/64 compat handling */ 7095dbcd01aSAnkur Arora qemu_build_assert(sizeof(hp) == 16); 7105dbcd01aSAnkur Arora 7115dbcd01aSAnkur Arora if (kvm_copy_from_gva(cs, arg, &hp, sizeof(hp))) { 7125dbcd01aSAnkur Arora err = -EFAULT; 7135dbcd01aSAnkur Arora goto out; 7145dbcd01aSAnkur Arora } 7155dbcd01aSAnkur Arora 7165dbcd01aSAnkur Arora if (hp.domid != DOMID_SELF && hp.domid != xen_domid) { 7175dbcd01aSAnkur Arora err = -ESRCH; 7185dbcd01aSAnkur Arora goto out; 7195dbcd01aSAnkur Arora } 7205dbcd01aSAnkur Arora 7215dbcd01aSAnkur Arora switch (hp.index) { 72291cce756SDavid Woodhouse case HVM_PARAM_CALLBACK_IRQ: 7232aff696bSDavid Woodhouse qemu_mutex_lock_iothread(); 72491cce756SDavid Woodhouse err = xen_evtchn_set_callback_param(hp.value); 7252aff696bSDavid Woodhouse qemu_mutex_unlock_iothread(); 72691cce756SDavid Woodhouse xen_set_long_mode(exit->u.hcall.longmode); 72791cce756SDavid Woodhouse break; 7285dbcd01aSAnkur Arora default: 7295dbcd01aSAnkur Arora return false; 7305dbcd01aSAnkur Arora } 7315dbcd01aSAnkur Arora 7325dbcd01aSAnkur Arora out: 7335dbcd01aSAnkur Arora exit->u.hcall.result = err; 7345dbcd01aSAnkur Arora return true; 7355dbcd01aSAnkur Arora } 7365dbcd01aSAnkur Arora 737105b47fdSAnkur Arora static int kvm_xen_hcall_evtchn_upcall_vector(struct kvm_xen_exit *exit, 738105b47fdSAnkur Arora X86CPU *cpu, uint64_t arg) 739105b47fdSAnkur Arora { 740105b47fdSAnkur Arora struct xen_hvm_evtchn_upcall_vector up; 741105b47fdSAnkur Arora CPUState *target_cs; 742105b47fdSAnkur Arora 743105b47fdSAnkur Arora /* No need for 32/64 compat handling */ 744105b47fdSAnkur Arora qemu_build_assert(sizeof(up) == 8); 745105b47fdSAnkur Arora 746105b47fdSAnkur Arora if (kvm_copy_from_gva(CPU(cpu), arg, &up, sizeof(up))) { 747105b47fdSAnkur Arora return -EFAULT; 748105b47fdSAnkur Arora } 749105b47fdSAnkur Arora 750105b47fdSAnkur Arora if (up.vector < 0x10) { 751105b47fdSAnkur Arora return -EINVAL; 752105b47fdSAnkur Arora } 753105b47fdSAnkur Arora 754105b47fdSAnkur Arora target_cs = qemu_get_cpu(up.vcpu); 755105b47fdSAnkur Arora if (!target_cs) { 756105b47fdSAnkur Arora return -EINVAL; 757105b47fdSAnkur Arora } 758105b47fdSAnkur Arora 759105b47fdSAnkur Arora async_run_on_cpu(target_cs, do_set_vcpu_callback_vector, 760105b47fdSAnkur Arora RUN_ON_CPU_HOST_INT(up.vector)); 761105b47fdSAnkur Arora return 0; 762105b47fdSAnkur Arora } 763105b47fdSAnkur Arora 764671bfdcdSJoao Martins static bool kvm_xen_hcall_hvm_op(struct kvm_xen_exit *exit, X86CPU *cpu, 765671bfdcdSJoao Martins int cmd, uint64_t arg) 766671bfdcdSJoao Martins { 767105b47fdSAnkur Arora int ret = -ENOSYS; 768671bfdcdSJoao Martins switch (cmd) { 769105b47fdSAnkur Arora case HVMOP_set_evtchn_upcall_vector: 770105b47fdSAnkur Arora ret = kvm_xen_hcall_evtchn_upcall_vector(exit, cpu, 771105b47fdSAnkur Arora exit->u.hcall.params[0]); 772105b47fdSAnkur Arora break; 773105b47fdSAnkur Arora 774671bfdcdSJoao Martins case HVMOP_pagetable_dying: 775105b47fdSAnkur Arora ret = -ENOSYS; 776105b47fdSAnkur Arora break; 777671bfdcdSJoao Martins 7785dbcd01aSAnkur Arora case HVMOP_set_param: 7795dbcd01aSAnkur Arora return handle_set_param(exit, cpu, arg); 7805dbcd01aSAnkur Arora 781671bfdcdSJoao Martins default: 782671bfdcdSJoao Martins return false; 783671bfdcdSJoao Martins } 784105b47fdSAnkur Arora 785105b47fdSAnkur Arora exit->u.hcall.result = ret; 786105b47fdSAnkur Arora return true; 787671bfdcdSJoao Martins } 788671bfdcdSJoao Martins 789c345104cSJoao Martins static int vcpuop_register_vcpu_info(CPUState *cs, CPUState *target, 790c345104cSJoao Martins uint64_t arg) 791c345104cSJoao Martins { 792c345104cSJoao Martins struct vcpu_register_vcpu_info rvi; 793c345104cSJoao Martins uint64_t gpa; 794c345104cSJoao Martins 795c345104cSJoao Martins /* No need for 32/64 compat handling */ 796c345104cSJoao Martins qemu_build_assert(sizeof(rvi) == 16); 797c345104cSJoao Martins qemu_build_assert(sizeof(struct vcpu_info) == 64); 798c345104cSJoao Martins 799c345104cSJoao Martins if (!target) { 800c345104cSJoao Martins return -ENOENT; 801c345104cSJoao Martins } 802c345104cSJoao Martins 803c345104cSJoao Martins if (kvm_copy_from_gva(cs, arg, &rvi, sizeof(rvi))) { 804c345104cSJoao Martins return -EFAULT; 805c345104cSJoao Martins } 806c345104cSJoao Martins 807c345104cSJoao Martins if (rvi.offset > TARGET_PAGE_SIZE - sizeof(struct vcpu_info)) { 808c345104cSJoao Martins return -EINVAL; 809c345104cSJoao Martins } 810c345104cSJoao Martins 811c345104cSJoao Martins gpa = ((rvi.mfn << TARGET_PAGE_BITS) + rvi.offset); 812c345104cSJoao Martins async_run_on_cpu(target, do_set_vcpu_info_gpa, RUN_ON_CPU_HOST_ULONG(gpa)); 813c345104cSJoao Martins return 0; 814c345104cSJoao Martins } 815c345104cSJoao Martins 816f0689302SJoao Martins static int vcpuop_register_vcpu_time_info(CPUState *cs, CPUState *target, 817f0689302SJoao Martins uint64_t arg) 818f0689302SJoao Martins { 819f0689302SJoao Martins struct vcpu_register_time_memory_area tma; 820f0689302SJoao Martins uint64_t gpa; 821f0689302SJoao Martins size_t len; 822f0689302SJoao Martins 823f0689302SJoao Martins /* No need for 32/64 compat handling */ 824f0689302SJoao Martins qemu_build_assert(sizeof(tma) == 8); 825f0689302SJoao Martins qemu_build_assert(sizeof(struct vcpu_time_info) == 32); 826f0689302SJoao Martins 827f0689302SJoao Martins if (!target) { 828f0689302SJoao Martins return -ENOENT; 829f0689302SJoao Martins } 830f0689302SJoao Martins 831f0689302SJoao Martins if (kvm_copy_from_gva(cs, arg, &tma, sizeof(tma))) { 832f0689302SJoao Martins return -EFAULT; 833f0689302SJoao Martins } 834f0689302SJoao Martins 835f0689302SJoao Martins /* 836f0689302SJoao Martins * Xen actually uses the GVA and does the translation through the guest 837f0689302SJoao Martins * page tables each time. But Linux/KVM uses the GPA, on the assumption 838f0689302SJoao Martins * that guests only ever use *global* addresses (kernel virtual addresses) 839f0689302SJoao Martins * for it. If Linux is changed to redo the GVA→GPA translation each time, 840f0689302SJoao Martins * it will offer a new vCPU attribute for that, and we'll use it instead. 841f0689302SJoao Martins */ 842f0689302SJoao Martins if (!kvm_gva_to_gpa(cs, tma.addr.p, &gpa, &len, false) || 843f0689302SJoao Martins len < sizeof(struct vcpu_time_info)) { 844f0689302SJoao Martins return -EFAULT; 845f0689302SJoao Martins } 846f0689302SJoao Martins 847f0689302SJoao Martins async_run_on_cpu(target, do_set_vcpu_time_info_gpa, 848f0689302SJoao Martins RUN_ON_CPU_HOST_ULONG(gpa)); 849f0689302SJoao Martins return 0; 850f0689302SJoao Martins } 851f0689302SJoao Martins 8525092db87SJoao Martins static int vcpuop_register_runstate_info(CPUState *cs, CPUState *target, 8535092db87SJoao Martins uint64_t arg) 8545092db87SJoao Martins { 8555092db87SJoao Martins struct vcpu_register_runstate_memory_area rma; 8565092db87SJoao Martins uint64_t gpa; 8575092db87SJoao Martins size_t len; 8585092db87SJoao Martins 8595092db87SJoao Martins /* No need for 32/64 compat handling */ 8605092db87SJoao Martins qemu_build_assert(sizeof(rma) == 8); 8615092db87SJoao Martins /* The runstate area actually does change size, but Linux copes. */ 8625092db87SJoao Martins 8635092db87SJoao Martins if (!target) { 8645092db87SJoao Martins return -ENOENT; 8655092db87SJoao Martins } 8665092db87SJoao Martins 8675092db87SJoao Martins if (kvm_copy_from_gva(cs, arg, &rma, sizeof(rma))) { 8685092db87SJoao Martins return -EFAULT; 8695092db87SJoao Martins } 8705092db87SJoao Martins 8715092db87SJoao Martins /* As with vcpu_time_info, Xen actually uses the GVA but KVM doesn't. */ 8725092db87SJoao Martins if (!kvm_gva_to_gpa(cs, rma.addr.p, &gpa, &len, false)) { 8735092db87SJoao Martins return -EFAULT; 8745092db87SJoao Martins } 8755092db87SJoao Martins 8765092db87SJoao Martins async_run_on_cpu(target, do_set_vcpu_runstate_gpa, 8775092db87SJoao Martins RUN_ON_CPU_HOST_ULONG(gpa)); 8785092db87SJoao Martins return 0; 8795092db87SJoao Martins } 8805092db87SJoao Martins 881d70bd6a4SJoao Martins static bool kvm_xen_hcall_vcpu_op(struct kvm_xen_exit *exit, X86CPU *cpu, 882d70bd6a4SJoao Martins int cmd, int vcpu_id, uint64_t arg) 883d70bd6a4SJoao Martins { 884c345104cSJoao Martins CPUState *dest = qemu_get_cpu(vcpu_id); 885c345104cSJoao Martins CPUState *cs = CPU(cpu); 886d70bd6a4SJoao Martins int err; 887d70bd6a4SJoao Martins 888d70bd6a4SJoao Martins switch (cmd) { 8895092db87SJoao Martins case VCPUOP_register_runstate_memory_area: 8905092db87SJoao Martins err = vcpuop_register_runstate_info(cs, dest, arg); 8915092db87SJoao Martins break; 892f0689302SJoao Martins case VCPUOP_register_vcpu_time_memory_area: 893f0689302SJoao Martins err = vcpuop_register_vcpu_time_info(cs, dest, arg); 894f0689302SJoao Martins break; 895d70bd6a4SJoao Martins case VCPUOP_register_vcpu_info: 896c345104cSJoao Martins err = vcpuop_register_vcpu_info(cs, dest, arg); 897d70bd6a4SJoao Martins break; 898d70bd6a4SJoao Martins 899d70bd6a4SJoao Martins default: 900d70bd6a4SJoao Martins return false; 901d70bd6a4SJoao Martins } 902d70bd6a4SJoao Martins 903d70bd6a4SJoao Martins exit->u.hcall.result = err; 904d70bd6a4SJoao Martins return true; 905d70bd6a4SJoao Martins } 906d70bd6a4SJoao Martins 9074858ba20SDavid Woodhouse static bool kvm_xen_hcall_evtchn_op(struct kvm_xen_exit *exit, X86CPU *cpu, 9083b06f29bSJoao Martins int cmd, uint64_t arg) 9093b06f29bSJoao Martins { 9104858ba20SDavid Woodhouse CPUState *cs = CPU(cpu); 9113b06f29bSJoao Martins int err = -ENOSYS; 9123b06f29bSJoao Martins 9133b06f29bSJoao Martins switch (cmd) { 9143b06f29bSJoao Martins case EVTCHNOP_init_control: 9153b06f29bSJoao Martins case EVTCHNOP_expand_array: 9163b06f29bSJoao Martins case EVTCHNOP_set_priority: 9173b06f29bSJoao Martins /* We do not support FIFO channels at this point */ 9183b06f29bSJoao Martins err = -ENOSYS; 9193b06f29bSJoao Martins break; 9203b06f29bSJoao Martins 9214858ba20SDavid Woodhouse case EVTCHNOP_status: { 9224858ba20SDavid Woodhouse struct evtchn_status status; 9234858ba20SDavid Woodhouse 9244858ba20SDavid Woodhouse qemu_build_assert(sizeof(status) == 24); 9254858ba20SDavid Woodhouse if (kvm_copy_from_gva(cs, arg, &status, sizeof(status))) { 9264858ba20SDavid Woodhouse err = -EFAULT; 9274858ba20SDavid Woodhouse break; 9284858ba20SDavid Woodhouse } 9294858ba20SDavid Woodhouse 9304858ba20SDavid Woodhouse err = xen_evtchn_status_op(&status); 9314858ba20SDavid Woodhouse if (!err && kvm_copy_to_gva(cs, arg, &status, sizeof(status))) { 9324858ba20SDavid Woodhouse err = -EFAULT; 9334858ba20SDavid Woodhouse } 9344858ba20SDavid Woodhouse break; 9354858ba20SDavid Woodhouse } 93683eb5811SDavid Woodhouse case EVTCHNOP_close: { 93783eb5811SDavid Woodhouse struct evtchn_close close; 93883eb5811SDavid Woodhouse 93983eb5811SDavid Woodhouse qemu_build_assert(sizeof(close) == 4); 94083eb5811SDavid Woodhouse if (kvm_copy_from_gva(cs, arg, &close, sizeof(close))) { 94183eb5811SDavid Woodhouse err = -EFAULT; 94283eb5811SDavid Woodhouse break; 94383eb5811SDavid Woodhouse } 94483eb5811SDavid Woodhouse 94583eb5811SDavid Woodhouse err = xen_evtchn_close_op(&close); 94683eb5811SDavid Woodhouse break; 94783eb5811SDavid Woodhouse } 948190cc3c0SDavid Woodhouse case EVTCHNOP_unmask: { 949190cc3c0SDavid Woodhouse struct evtchn_unmask unmask; 950190cc3c0SDavid Woodhouse 951190cc3c0SDavid Woodhouse qemu_build_assert(sizeof(unmask) == 4); 952190cc3c0SDavid Woodhouse if (kvm_copy_from_gva(cs, arg, &unmask, sizeof(unmask))) { 953190cc3c0SDavid Woodhouse err = -EFAULT; 954190cc3c0SDavid Woodhouse break; 955190cc3c0SDavid Woodhouse } 956190cc3c0SDavid Woodhouse 957190cc3c0SDavid Woodhouse err = xen_evtchn_unmask_op(&unmask); 958190cc3c0SDavid Woodhouse break; 959190cc3c0SDavid Woodhouse } 960c723d4c1SDavid Woodhouse case EVTCHNOP_bind_virq: { 961c723d4c1SDavid Woodhouse struct evtchn_bind_virq virq; 962c723d4c1SDavid Woodhouse 963c723d4c1SDavid Woodhouse qemu_build_assert(sizeof(virq) == 12); 964c723d4c1SDavid Woodhouse if (kvm_copy_from_gva(cs, arg, &virq, sizeof(virq))) { 965c723d4c1SDavid Woodhouse err = -EFAULT; 966c723d4c1SDavid Woodhouse break; 967c723d4c1SDavid Woodhouse } 968c723d4c1SDavid Woodhouse 969c723d4c1SDavid Woodhouse err = xen_evtchn_bind_virq_op(&virq); 970c723d4c1SDavid Woodhouse if (!err && kvm_copy_to_gva(cs, arg, &virq, sizeof(virq))) { 971c723d4c1SDavid Woodhouse err = -EFAULT; 972c723d4c1SDavid Woodhouse } 973c723d4c1SDavid Woodhouse break; 974c723d4c1SDavid Woodhouse } 975f5417856SDavid Woodhouse case EVTCHNOP_bind_ipi: { 976f5417856SDavid Woodhouse struct evtchn_bind_ipi ipi; 977f5417856SDavid Woodhouse 978f5417856SDavid Woodhouse qemu_build_assert(sizeof(ipi) == 8); 979f5417856SDavid Woodhouse if (kvm_copy_from_gva(cs, arg, &ipi, sizeof(ipi))) { 980f5417856SDavid Woodhouse err = -EFAULT; 981f5417856SDavid Woodhouse break; 982f5417856SDavid Woodhouse } 983f5417856SDavid Woodhouse 984f5417856SDavid Woodhouse err = xen_evtchn_bind_ipi_op(&ipi); 985f5417856SDavid Woodhouse if (!err && kvm_copy_to_gva(cs, arg, &ipi, sizeof(ipi))) { 986f5417856SDavid Woodhouse err = -EFAULT; 987f5417856SDavid Woodhouse } 988f5417856SDavid Woodhouse break; 989f5417856SDavid Woodhouse } 990cf7679abSDavid Woodhouse case EVTCHNOP_send: { 991cf7679abSDavid Woodhouse struct evtchn_send send; 992cf7679abSDavid Woodhouse 993cf7679abSDavid Woodhouse qemu_build_assert(sizeof(send) == 4); 994cf7679abSDavid Woodhouse if (kvm_copy_from_gva(cs, arg, &send, sizeof(send))) { 995cf7679abSDavid Woodhouse err = -EFAULT; 996cf7679abSDavid Woodhouse break; 997cf7679abSDavid Woodhouse } 998cf7679abSDavid Woodhouse 999cf7679abSDavid Woodhouse err = xen_evtchn_send_op(&send); 1000cf7679abSDavid Woodhouse break; 1001cf7679abSDavid Woodhouse } 1002e1db61b8SDavid Woodhouse case EVTCHNOP_alloc_unbound: { 1003e1db61b8SDavid Woodhouse struct evtchn_alloc_unbound alloc; 1004e1db61b8SDavid Woodhouse 1005e1db61b8SDavid Woodhouse qemu_build_assert(sizeof(alloc) == 8); 1006e1db61b8SDavid Woodhouse if (kvm_copy_from_gva(cs, arg, &alloc, sizeof(alloc))) { 1007e1db61b8SDavid Woodhouse err = -EFAULT; 1008e1db61b8SDavid Woodhouse break; 1009e1db61b8SDavid Woodhouse } 1010e1db61b8SDavid Woodhouse 1011e1db61b8SDavid Woodhouse err = xen_evtchn_alloc_unbound_op(&alloc); 1012e1db61b8SDavid Woodhouse if (!err && kvm_copy_to_gva(cs, arg, &alloc, sizeof(alloc))) { 1013e1db61b8SDavid Woodhouse err = -EFAULT; 1014e1db61b8SDavid Woodhouse } 1015e1db61b8SDavid Woodhouse break; 1016e1db61b8SDavid Woodhouse } 101784327881SDavid Woodhouse case EVTCHNOP_bind_interdomain: { 101884327881SDavid Woodhouse struct evtchn_bind_interdomain interdomain; 101984327881SDavid Woodhouse 102084327881SDavid Woodhouse qemu_build_assert(sizeof(interdomain) == 12); 102184327881SDavid Woodhouse if (kvm_copy_from_gva(cs, arg, &interdomain, sizeof(interdomain))) { 102284327881SDavid Woodhouse err = -EFAULT; 102384327881SDavid Woodhouse break; 102484327881SDavid Woodhouse } 102584327881SDavid Woodhouse 102684327881SDavid Woodhouse err = xen_evtchn_bind_interdomain_op(&interdomain); 102784327881SDavid Woodhouse if (!err && 102884327881SDavid Woodhouse kvm_copy_to_gva(cs, arg, &interdomain, sizeof(interdomain))) { 102984327881SDavid Woodhouse err = -EFAULT; 103084327881SDavid Woodhouse } 103184327881SDavid Woodhouse break; 103284327881SDavid Woodhouse } 103330667046SDavid Woodhouse case EVTCHNOP_bind_vcpu: { 103430667046SDavid Woodhouse struct evtchn_bind_vcpu vcpu; 103530667046SDavid Woodhouse 103630667046SDavid Woodhouse qemu_build_assert(sizeof(vcpu) == 8); 103730667046SDavid Woodhouse if (kvm_copy_from_gva(cs, arg, &vcpu, sizeof(vcpu))) { 103830667046SDavid Woodhouse err = -EFAULT; 103930667046SDavid Woodhouse break; 104030667046SDavid Woodhouse } 104130667046SDavid Woodhouse 104230667046SDavid Woodhouse err = xen_evtchn_bind_vcpu_op(&vcpu); 104330667046SDavid Woodhouse break; 104430667046SDavid Woodhouse } 1045a15b1097SDavid Woodhouse case EVTCHNOP_reset: { 1046a15b1097SDavid Woodhouse struct evtchn_reset reset; 1047a15b1097SDavid Woodhouse 1048a15b1097SDavid Woodhouse qemu_build_assert(sizeof(reset) == 2); 1049a15b1097SDavid Woodhouse if (kvm_copy_from_gva(cs, arg, &reset, sizeof(reset))) { 1050a15b1097SDavid Woodhouse err = -EFAULT; 1051a15b1097SDavid Woodhouse break; 1052a15b1097SDavid Woodhouse } 1053a15b1097SDavid Woodhouse 1054a15b1097SDavid Woodhouse err = xen_evtchn_reset_op(&reset); 1055a15b1097SDavid Woodhouse break; 1056a15b1097SDavid Woodhouse } 10573b06f29bSJoao Martins default: 10583b06f29bSJoao Martins return false; 10593b06f29bSJoao Martins } 10603b06f29bSJoao Martins 10613b06f29bSJoao Martins exit->u.hcall.result = err; 10623b06f29bSJoao Martins return true; 10633b06f29bSJoao Martins } 10643b06f29bSJoao Martins 106579b7067dSJoao Martins int kvm_xen_soft_reset(void) 106679b7067dSJoao Martins { 1067c345104cSJoao Martins CPUState *cpu; 1068fb0fd2ceSJoao Martins int err; 1069fb0fd2ceSJoao Martins 107079b7067dSJoao Martins assert(qemu_mutex_iothread_locked()); 107179b7067dSJoao Martins 107279b7067dSJoao Martins trace_kvm_xen_soft_reset(); 107379b7067dSJoao Martins 1074a15b1097SDavid Woodhouse err = xen_evtchn_soft_reset(); 1075a15b1097SDavid Woodhouse if (err) { 1076a15b1097SDavid Woodhouse return err; 1077a15b1097SDavid Woodhouse } 1078a15b1097SDavid Woodhouse 107991cce756SDavid Woodhouse /* 108091cce756SDavid Woodhouse * Zero is the reset/startup state for HVM_PARAM_CALLBACK_IRQ. Strictly, 108191cce756SDavid Woodhouse * it maps to HVM_PARAM_CALLBACK_TYPE_GSI with GSI#0, but Xen refuses to 108291cce756SDavid Woodhouse * to deliver to the timer interrupt and treats that as 'disabled'. 108391cce756SDavid Woodhouse */ 108491cce756SDavid Woodhouse err = xen_evtchn_set_callback_param(0); 108591cce756SDavid Woodhouse if (err) { 108691cce756SDavid Woodhouse return err; 108791cce756SDavid Woodhouse } 108891cce756SDavid Woodhouse 1089c345104cSJoao Martins CPU_FOREACH(cpu) { 1090c345104cSJoao Martins async_run_on_cpu(cpu, do_vcpu_soft_reset, RUN_ON_CPU_NULL); 1091c345104cSJoao Martins } 1092c345104cSJoao Martins 1093fb0fd2ceSJoao Martins err = xen_overlay_map_shinfo_page(INVALID_GFN); 1094fb0fd2ceSJoao Martins if (err) { 1095fb0fd2ceSJoao Martins return err; 1096fb0fd2ceSJoao Martins } 1097fb0fd2ceSJoao Martins 109879b7067dSJoao Martins return 0; 109979b7067dSJoao Martins } 110079b7067dSJoao Martins 110179b7067dSJoao Martins static int schedop_shutdown(CPUState *cs, uint64_t arg) 110279b7067dSJoao Martins { 110379b7067dSJoao Martins struct sched_shutdown shutdown; 110479b7067dSJoao Martins int ret = 0; 110579b7067dSJoao Martins 110679b7067dSJoao Martins /* No need for 32/64 compat handling */ 110779b7067dSJoao Martins qemu_build_assert(sizeof(shutdown) == 4); 110879b7067dSJoao Martins 110979b7067dSJoao Martins if (kvm_copy_from_gva(cs, arg, &shutdown, sizeof(shutdown))) { 111079b7067dSJoao Martins return -EFAULT; 111179b7067dSJoao Martins } 111279b7067dSJoao Martins 111379b7067dSJoao Martins switch (shutdown.reason) { 111479b7067dSJoao Martins case SHUTDOWN_crash: 111579b7067dSJoao Martins cpu_dump_state(cs, stderr, CPU_DUMP_CODE); 111679b7067dSJoao Martins qemu_system_guest_panicked(NULL); 111779b7067dSJoao Martins break; 111879b7067dSJoao Martins 111979b7067dSJoao Martins case SHUTDOWN_reboot: 112079b7067dSJoao Martins qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); 112179b7067dSJoao Martins break; 112279b7067dSJoao Martins 112379b7067dSJoao Martins case SHUTDOWN_poweroff: 112479b7067dSJoao Martins qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); 112579b7067dSJoao Martins break; 112679b7067dSJoao Martins 112779b7067dSJoao Martins case SHUTDOWN_soft_reset: 112879b7067dSJoao Martins qemu_mutex_lock_iothread(); 112979b7067dSJoao Martins ret = kvm_xen_soft_reset(); 113079b7067dSJoao Martins qemu_mutex_unlock_iothread(); 113179b7067dSJoao Martins break; 113279b7067dSJoao Martins 113379b7067dSJoao Martins default: 113479b7067dSJoao Martins ret = -EINVAL; 113579b7067dSJoao Martins break; 113679b7067dSJoao Martins } 113779b7067dSJoao Martins 113879b7067dSJoao Martins return ret; 113979b7067dSJoao Martins } 114079b7067dSJoao Martins 114179b7067dSJoao Martins static bool kvm_xen_hcall_sched_op(struct kvm_xen_exit *exit, X86CPU *cpu, 114279b7067dSJoao Martins int cmd, uint64_t arg) 114379b7067dSJoao Martins { 114479b7067dSJoao Martins CPUState *cs = CPU(cpu); 114579b7067dSJoao Martins int err = -ENOSYS; 114679b7067dSJoao Martins 114779b7067dSJoao Martins switch (cmd) { 114879b7067dSJoao Martins case SCHEDOP_shutdown: 114979b7067dSJoao Martins err = schedop_shutdown(cs, arg); 115079b7067dSJoao Martins break; 115179b7067dSJoao Martins 1152c789b9efSDavid Woodhouse case SCHEDOP_poll: 1153c789b9efSDavid Woodhouse /* 1154c789b9efSDavid Woodhouse * Linux will panic if this doesn't work. Just yield; it's not 1155c789b9efSDavid Woodhouse * worth overthinking it because with event channel handling 1156c789b9efSDavid Woodhouse * in KVM, the kernel will intercept this and it will never 1157c789b9efSDavid Woodhouse * reach QEMU anyway. The semantics of the hypercall explicltly 1158c789b9efSDavid Woodhouse * permit spurious wakeups. 1159c789b9efSDavid Woodhouse */ 1160c789b9efSDavid Woodhouse case SCHEDOP_yield: 1161c789b9efSDavid Woodhouse sched_yield(); 1162c789b9efSDavid Woodhouse err = 0; 1163c789b9efSDavid Woodhouse break; 1164c789b9efSDavid Woodhouse 116579b7067dSJoao Martins default: 116679b7067dSJoao Martins return false; 116779b7067dSJoao Martins } 116879b7067dSJoao Martins 116979b7067dSJoao Martins exit->u.hcall.result = err; 117079b7067dSJoao Martins return true; 117179b7067dSJoao Martins } 117279b7067dSJoao Martins 117328b7ae94SDavid Woodhouse static bool kvm_xen_hcall_gnttab_op(struct kvm_xen_exit *exit, X86CPU *cpu, 117428b7ae94SDavid Woodhouse int cmd, uint64_t arg, int count) 117528b7ae94SDavid Woodhouse { 117628b7ae94SDavid Woodhouse CPUState *cs = CPU(cpu); 117728b7ae94SDavid Woodhouse int err; 117828b7ae94SDavid Woodhouse 117928b7ae94SDavid Woodhouse switch (cmd) { 118028b7ae94SDavid Woodhouse case GNTTABOP_set_version: { 118128b7ae94SDavid Woodhouse struct gnttab_set_version set; 118228b7ae94SDavid Woodhouse 118328b7ae94SDavid Woodhouse qemu_build_assert(sizeof(set) == 4); 118428b7ae94SDavid Woodhouse if (kvm_copy_from_gva(cs, arg, &set, sizeof(set))) { 118528b7ae94SDavid Woodhouse err = -EFAULT; 118628b7ae94SDavid Woodhouse break; 118728b7ae94SDavid Woodhouse } 118828b7ae94SDavid Woodhouse 118928b7ae94SDavid Woodhouse err = xen_gnttab_set_version_op(&set); 119028b7ae94SDavid Woodhouse if (!err && kvm_copy_to_gva(cs, arg, &set, sizeof(set))) { 119128b7ae94SDavid Woodhouse err = -EFAULT; 119228b7ae94SDavid Woodhouse } 119328b7ae94SDavid Woodhouse break; 119428b7ae94SDavid Woodhouse } 119528b7ae94SDavid Woodhouse case GNTTABOP_get_version: { 119628b7ae94SDavid Woodhouse struct gnttab_get_version get; 119728b7ae94SDavid Woodhouse 119828b7ae94SDavid Woodhouse qemu_build_assert(sizeof(get) == 8); 119928b7ae94SDavid Woodhouse if (kvm_copy_from_gva(cs, arg, &get, sizeof(get))) { 120028b7ae94SDavid Woodhouse err = -EFAULT; 120128b7ae94SDavid Woodhouse break; 120228b7ae94SDavid Woodhouse } 120328b7ae94SDavid Woodhouse 120428b7ae94SDavid Woodhouse err = xen_gnttab_get_version_op(&get); 120528b7ae94SDavid Woodhouse if (!err && kvm_copy_to_gva(cs, arg, &get, sizeof(get))) { 120628b7ae94SDavid Woodhouse err = -EFAULT; 120728b7ae94SDavid Woodhouse } 120828b7ae94SDavid Woodhouse break; 120928b7ae94SDavid Woodhouse } 1210*b46f9745SDavid Woodhouse case GNTTABOP_query_size: { 1211*b46f9745SDavid Woodhouse struct gnttab_query_size size; 1212*b46f9745SDavid Woodhouse 1213*b46f9745SDavid Woodhouse qemu_build_assert(sizeof(size) == 16); 1214*b46f9745SDavid Woodhouse if (kvm_copy_from_gva(cs, arg, &size, sizeof(size))) { 1215*b46f9745SDavid Woodhouse err = -EFAULT; 1216*b46f9745SDavid Woodhouse break; 1217*b46f9745SDavid Woodhouse } 1218*b46f9745SDavid Woodhouse 1219*b46f9745SDavid Woodhouse err = xen_gnttab_query_size_op(&size); 1220*b46f9745SDavid Woodhouse if (!err && kvm_copy_to_gva(cs, arg, &size, sizeof(size))) { 1221*b46f9745SDavid Woodhouse err = -EFAULT; 1222*b46f9745SDavid Woodhouse } 1223*b46f9745SDavid Woodhouse break; 1224*b46f9745SDavid Woodhouse } 122528b7ae94SDavid Woodhouse case GNTTABOP_setup_table: 122628b7ae94SDavid Woodhouse case GNTTABOP_copy: 122728b7ae94SDavid Woodhouse case GNTTABOP_map_grant_ref: 122828b7ae94SDavid Woodhouse case GNTTABOP_unmap_grant_ref: 122928b7ae94SDavid Woodhouse case GNTTABOP_swap_grant_ref: 123028b7ae94SDavid Woodhouse return false; 123128b7ae94SDavid Woodhouse 123228b7ae94SDavid Woodhouse default: 123328b7ae94SDavid Woodhouse /* Xen explicitly returns -ENOSYS to HVM guests for all others */ 123428b7ae94SDavid Woodhouse err = -ENOSYS; 123528b7ae94SDavid Woodhouse break; 123628b7ae94SDavid Woodhouse } 123728b7ae94SDavid Woodhouse 123828b7ae94SDavid Woodhouse exit->u.hcall.result = err; 123928b7ae94SDavid Woodhouse return true; 124028b7ae94SDavid Woodhouse } 124128b7ae94SDavid Woodhouse 124255a3f666SJoao Martins static bool do_kvm_xen_handle_exit(X86CPU *cpu, struct kvm_xen_exit *exit) 124355a3f666SJoao Martins { 124455a3f666SJoao Martins uint16_t code = exit->u.hcall.input; 124555a3f666SJoao Martins 124655a3f666SJoao Martins if (exit->u.hcall.cpl > 0) { 124755a3f666SJoao Martins exit->u.hcall.result = -EPERM; 124855a3f666SJoao Martins return true; 124955a3f666SJoao Martins } 125055a3f666SJoao Martins 125155a3f666SJoao Martins switch (code) { 125228b7ae94SDavid Woodhouse case __HYPERVISOR_grant_table_op: 125328b7ae94SDavid Woodhouse return kvm_xen_hcall_gnttab_op(exit, cpu, exit->u.hcall.params[0], 125428b7ae94SDavid Woodhouse exit->u.hcall.params[1], 125528b7ae94SDavid Woodhouse exit->u.hcall.params[2]); 125679b7067dSJoao Martins case __HYPERVISOR_sched_op: 125779b7067dSJoao Martins return kvm_xen_hcall_sched_op(exit, cpu, exit->u.hcall.params[0], 125879b7067dSJoao Martins exit->u.hcall.params[1]); 12593b06f29bSJoao Martins case __HYPERVISOR_event_channel_op: 12604858ba20SDavid Woodhouse return kvm_xen_hcall_evtchn_op(exit, cpu, exit->u.hcall.params[0], 12613b06f29bSJoao Martins exit->u.hcall.params[1]); 1262d70bd6a4SJoao Martins case __HYPERVISOR_vcpu_op: 1263d70bd6a4SJoao Martins return kvm_xen_hcall_vcpu_op(exit, cpu, 1264d70bd6a4SJoao Martins exit->u.hcall.params[0], 1265d70bd6a4SJoao Martins exit->u.hcall.params[1], 1266d70bd6a4SJoao Martins exit->u.hcall.params[2]); 1267671bfdcdSJoao Martins case __HYPERVISOR_hvm_op: 1268671bfdcdSJoao Martins return kvm_xen_hcall_hvm_op(exit, cpu, exit->u.hcall.params[0], 1269671bfdcdSJoao Martins exit->u.hcall.params[1]); 1270fb0fd2ceSJoao Martins case __HYPERVISOR_memory_op: 1271fb0fd2ceSJoao Martins return kvm_xen_hcall_memory_op(exit, cpu, exit->u.hcall.params[0], 1272fb0fd2ceSJoao Martins exit->u.hcall.params[1]); 1273bedcc139SJoao Martins case __HYPERVISOR_xen_version: 1274bedcc139SJoao Martins return kvm_xen_hcall_xen_version(exit, cpu, exit->u.hcall.params[0], 1275bedcc139SJoao Martins exit->u.hcall.params[1]); 127655a3f666SJoao Martins default: 127755a3f666SJoao Martins return false; 127855a3f666SJoao Martins } 127955a3f666SJoao Martins } 128055a3f666SJoao Martins 128155a3f666SJoao Martins int kvm_xen_handle_exit(X86CPU *cpu, struct kvm_xen_exit *exit) 128255a3f666SJoao Martins { 128355a3f666SJoao Martins if (exit->type != KVM_EXIT_XEN_HCALL) { 128455a3f666SJoao Martins return -1; 128555a3f666SJoao Martins } 128655a3f666SJoao Martins 1287110a0ea5SDavid Woodhouse /* 1288110a0ea5SDavid Woodhouse * The kernel latches the guest 32/64 mode when the MSR is used to fill 1289110a0ea5SDavid Woodhouse * the hypercall page. So if we see a hypercall in a mode that doesn't 1290110a0ea5SDavid Woodhouse * match our own idea of the guest mode, fetch the kernel's idea of the 1291110a0ea5SDavid Woodhouse * "long mode" to remain in sync. 1292110a0ea5SDavid Woodhouse */ 1293110a0ea5SDavid Woodhouse if (exit->u.hcall.longmode != xen_is_long_mode()) { 1294110a0ea5SDavid Woodhouse xen_sync_long_mode(); 1295110a0ea5SDavid Woodhouse } 1296110a0ea5SDavid Woodhouse 129755a3f666SJoao Martins if (!do_kvm_xen_handle_exit(cpu, exit)) { 129855a3f666SJoao Martins /* 129955a3f666SJoao Martins * Some hypercalls will be deliberately "implemented" by returning 130055a3f666SJoao Martins * -ENOSYS. This case is for hypercalls which are unexpected. 130155a3f666SJoao Martins */ 130255a3f666SJoao Martins exit->u.hcall.result = -ENOSYS; 130355a3f666SJoao Martins qemu_log_mask(LOG_UNIMP, "Unimplemented Xen hypercall %" 130455a3f666SJoao Martins PRId64 " (0x%" PRIx64 " 0x%" PRIx64 " 0x%" PRIx64 ")\n", 130555a3f666SJoao Martins (uint64_t)exit->u.hcall.input, 130655a3f666SJoao Martins (uint64_t)exit->u.hcall.params[0], 130755a3f666SJoao Martins (uint64_t)exit->u.hcall.params[1], 130855a3f666SJoao Martins (uint64_t)exit->u.hcall.params[2]); 130955a3f666SJoao Martins } 131055a3f666SJoao Martins 131155a3f666SJoao Martins trace_kvm_xen_hypercall(CPU(cpu)->cpu_index, exit->u.hcall.cpl, 131255a3f666SJoao Martins exit->u.hcall.input, exit->u.hcall.params[0], 131355a3f666SJoao Martins exit->u.hcall.params[1], exit->u.hcall.params[2], 131455a3f666SJoao Martins exit->u.hcall.result); 131555a3f666SJoao Martins return 0; 131655a3f666SJoao Martins } 1317c345104cSJoao Martins 13186f43f2eeSDavid Woodhouse uint16_t kvm_xen_get_gnttab_max_frames(void) 13196f43f2eeSDavid Woodhouse { 13206f43f2eeSDavid Woodhouse KVMState *s = KVM_STATE(current_accel()); 13216f43f2eeSDavid Woodhouse return s->xen_gnttab_max_frames; 13226f43f2eeSDavid Woodhouse } 13236f43f2eeSDavid Woodhouse 1324c345104cSJoao Martins int kvm_put_xen_state(CPUState *cs) 1325c345104cSJoao Martins { 1326c345104cSJoao Martins X86CPU *cpu = X86_CPU(cs); 1327c345104cSJoao Martins CPUX86State *env = &cpu->env; 1328c345104cSJoao Martins uint64_t gpa; 1329c345104cSJoao Martins int ret; 1330c345104cSJoao Martins 1331c345104cSJoao Martins gpa = env->xen_vcpu_info_gpa; 1332c345104cSJoao Martins if (gpa == INVALID_GPA) { 1333c345104cSJoao Martins gpa = env->xen_vcpu_info_default_gpa; 1334c345104cSJoao Martins } 1335c345104cSJoao Martins 1336c345104cSJoao Martins if (gpa != INVALID_GPA) { 133727d4075dSDavid Woodhouse ret = set_vcpu_info(cs, gpa); 1338c345104cSJoao Martins if (ret < 0) { 1339c345104cSJoao Martins return ret; 1340c345104cSJoao Martins } 1341c345104cSJoao Martins } 1342c345104cSJoao Martins 1343f0689302SJoao Martins gpa = env->xen_vcpu_time_info_gpa; 1344f0689302SJoao Martins if (gpa != INVALID_GPA) { 1345f0689302SJoao Martins ret = kvm_xen_set_vcpu_attr(cs, KVM_XEN_VCPU_ATTR_TYPE_VCPU_TIME_INFO, 1346f0689302SJoao Martins gpa); 1347f0689302SJoao Martins if (ret < 0) { 1348f0689302SJoao Martins return ret; 1349f0689302SJoao Martins } 1350f0689302SJoao Martins } 1351f0689302SJoao Martins 13525092db87SJoao Martins gpa = env->xen_vcpu_runstate_gpa; 13535092db87SJoao Martins if (gpa != INVALID_GPA) { 13545092db87SJoao Martins ret = kvm_xen_set_vcpu_attr(cs, KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADDR, 13555092db87SJoao Martins gpa); 13565092db87SJoao Martins if (ret < 0) { 13575092db87SJoao Martins return ret; 13585092db87SJoao Martins } 13595092db87SJoao Martins } 13605092db87SJoao Martins 1361105b47fdSAnkur Arora if (!kvm_xen_has_cap(EVTCHN_SEND)) { 1362105b47fdSAnkur Arora return 0; 1363105b47fdSAnkur Arora } 1364105b47fdSAnkur Arora 1365105b47fdSAnkur Arora if (env->xen_vcpu_callback_vector) { 1366105b47fdSAnkur Arora ret = kvm_xen_set_vcpu_callback_vector(cs); 1367105b47fdSAnkur Arora if (ret < 0) { 1368105b47fdSAnkur Arora return ret; 1369105b47fdSAnkur Arora } 1370105b47fdSAnkur Arora } 1371105b47fdSAnkur Arora 1372c723d4c1SDavid Woodhouse if (env->xen_virq[VIRQ_TIMER]) { 1373c723d4c1SDavid Woodhouse ret = kvm_xen_set_vcpu_timer(cs); 1374c723d4c1SDavid Woodhouse if (ret < 0) { 1375c723d4c1SDavid Woodhouse return ret; 1376c723d4c1SDavid Woodhouse } 1377c723d4c1SDavid Woodhouse } 1378c345104cSJoao Martins return 0; 1379c345104cSJoao Martins } 1380c345104cSJoao Martins 1381c345104cSJoao Martins int kvm_get_xen_state(CPUState *cs) 1382c345104cSJoao Martins { 1383c345104cSJoao Martins X86CPU *cpu = X86_CPU(cs); 1384c345104cSJoao Martins CPUX86State *env = &cpu->env; 1385c345104cSJoao Martins uint64_t gpa; 1386c723d4c1SDavid Woodhouse int ret; 1387c345104cSJoao Martins 1388c345104cSJoao Martins /* 1389c345104cSJoao Martins * The kernel does not mark vcpu_info as dirty when it delivers interrupts 1390c345104cSJoao Martins * to it. It's up to userspace to *assume* that any page shared thus is 1391c345104cSJoao Martins * always considered dirty. The shared_info page is different since it's 1392c345104cSJoao Martins * an overlay and migrated separately anyway. 1393c345104cSJoao Martins */ 1394c345104cSJoao Martins gpa = env->xen_vcpu_info_gpa; 1395c345104cSJoao Martins if (gpa == INVALID_GPA) { 1396c345104cSJoao Martins gpa = env->xen_vcpu_info_default_gpa; 1397c345104cSJoao Martins } 1398c345104cSJoao Martins if (gpa != INVALID_GPA) { 1399c345104cSJoao Martins MemoryRegionSection mrs = memory_region_find(get_system_memory(), 1400c345104cSJoao Martins gpa, 1401c345104cSJoao Martins sizeof(struct vcpu_info)); 1402c345104cSJoao Martins if (mrs.mr && 1403c345104cSJoao Martins !int128_lt(mrs.size, int128_make64(sizeof(struct vcpu_info)))) { 1404c345104cSJoao Martins memory_region_set_dirty(mrs.mr, mrs.offset_within_region, 1405c345104cSJoao Martins sizeof(struct vcpu_info)); 1406c345104cSJoao Martins } 1407c345104cSJoao Martins } 1408c345104cSJoao Martins 1409c723d4c1SDavid Woodhouse if (!kvm_xen_has_cap(EVTCHN_SEND)) { 1410c723d4c1SDavid Woodhouse return 0; 1411c723d4c1SDavid Woodhouse } 1412c723d4c1SDavid Woodhouse 1413c723d4c1SDavid Woodhouse /* 1414c723d4c1SDavid Woodhouse * If the kernel is accelerating timers, read out the current value of the 1415c723d4c1SDavid Woodhouse * singleshot timer deadline. 1416c723d4c1SDavid Woodhouse */ 1417c723d4c1SDavid Woodhouse if (env->xen_virq[VIRQ_TIMER]) { 1418c723d4c1SDavid Woodhouse struct kvm_xen_vcpu_attr va = { 1419c723d4c1SDavid Woodhouse .type = KVM_XEN_VCPU_ATTR_TYPE_TIMER, 1420c723d4c1SDavid Woodhouse }; 1421c723d4c1SDavid Woodhouse ret = kvm_vcpu_ioctl(cs, KVM_XEN_VCPU_GET_ATTR, &va); 1422c723d4c1SDavid Woodhouse if (ret < 0) { 1423c723d4c1SDavid Woodhouse return ret; 1424c723d4c1SDavid Woodhouse } 1425c723d4c1SDavid Woodhouse env->xen_singleshot_timer_ns = va.u.timer.expires_ns; 1426c723d4c1SDavid Woodhouse } 1427c723d4c1SDavid Woodhouse 1428c345104cSJoao Martins return 0; 1429c345104cSJoao Martins } 1430