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" 28110a0ea5SDavid Woodhouse 29bedcc139SJoao Martins #include "hw/xen/interface/version.h" 3079b7067dSJoao Martins #include "hw/xen/interface/sched.h" 31fb0fd2ceSJoao Martins #include "hw/xen/interface/memory.h" 32671bfdcdSJoao Martins #include "hw/xen/interface/hvm/hvm_op.h" 33105b47fdSAnkur Arora #include "hw/xen/interface/hvm/params.h" 34d70bd6a4SJoao Martins #include "hw/xen/interface/vcpu.h" 353b06f29bSJoao Martins #include "hw/xen/interface/event_channel.h" 36fb0fd2ceSJoao Martins 37fb0fd2ceSJoao Martins #include "xen-compat.h" 38fb0fd2ceSJoao Martins 39fb0fd2ceSJoao Martins #ifdef TARGET_X86_64 40fb0fd2ceSJoao Martins #define hypercall_compat32(longmode) (!(longmode)) 41fb0fd2ceSJoao Martins #else 42fb0fd2ceSJoao Martins #define hypercall_compat32(longmode) (false) 43fb0fd2ceSJoao Martins #endif 44bedcc139SJoao Martins 45f0689302SJoao Martins static bool kvm_gva_to_gpa(CPUState *cs, uint64_t gva, uint64_t *gpa, 46f0689302SJoao Martins size_t *len, bool is_write) 47bedcc139SJoao Martins { 48bedcc139SJoao Martins struct kvm_translation tr = { 49bedcc139SJoao Martins .linear_address = gva, 50bedcc139SJoao Martins }; 51bedcc139SJoao Martins 52f0689302SJoao Martins if (len) { 53f0689302SJoao Martins *len = TARGET_PAGE_SIZE - (gva & ~TARGET_PAGE_MASK); 54f0689302SJoao Martins } 55f0689302SJoao Martins 56f0689302SJoao Martins if (kvm_vcpu_ioctl(cs, KVM_TRANSLATE, &tr) || !tr.valid || 57f0689302SJoao Martins (is_write && !tr.writeable)) { 58f0689302SJoao Martins return false; 59f0689302SJoao Martins } 60f0689302SJoao Martins *gpa = tr.physical_address; 61f0689302SJoao Martins return true; 62f0689302SJoao Martins } 63f0689302SJoao Martins 64f0689302SJoao Martins static int kvm_gva_rw(CPUState *cs, uint64_t gva, void *_buf, size_t sz, 65f0689302SJoao Martins bool is_write) 66f0689302SJoao Martins { 67f0689302SJoao Martins uint8_t *buf = (uint8_t *)_buf; 68f0689302SJoao Martins uint64_t gpa; 69f0689302SJoao Martins size_t len; 70f0689302SJoao Martins 71f0689302SJoao Martins while (sz) { 72f0689302SJoao Martins if (!kvm_gva_to_gpa(cs, gva, &gpa, &len, is_write)) { 73f0689302SJoao Martins return -EFAULT; 74f0689302SJoao Martins } 75bedcc139SJoao Martins if (len > sz) { 76bedcc139SJoao Martins len = sz; 77bedcc139SJoao Martins } 78bedcc139SJoao Martins 79f0689302SJoao Martins cpu_physical_memory_rw(gpa, buf, len, is_write); 80bedcc139SJoao Martins 81bedcc139SJoao Martins buf += len; 82bedcc139SJoao Martins sz -= len; 83bedcc139SJoao Martins gva += len; 84bedcc139SJoao Martins } 85bedcc139SJoao Martins 86bedcc139SJoao Martins return 0; 87bedcc139SJoao Martins } 88bedcc139SJoao Martins 89bedcc139SJoao Martins static inline int kvm_copy_from_gva(CPUState *cs, uint64_t gva, void *buf, 90bedcc139SJoao Martins size_t sz) 91bedcc139SJoao Martins { 92bedcc139SJoao Martins return kvm_gva_rw(cs, gva, buf, sz, false); 93bedcc139SJoao Martins } 94bedcc139SJoao Martins 95bedcc139SJoao Martins static inline int kvm_copy_to_gva(CPUState *cs, uint64_t gva, void *buf, 96bedcc139SJoao Martins size_t sz) 97bedcc139SJoao Martins { 98bedcc139SJoao Martins return kvm_gva_rw(cs, gva, buf, sz, true); 99bedcc139SJoao Martins } 100bedcc139SJoao Martins 101f66b8a83SJoao Martins int kvm_xen_init(KVMState *s, uint32_t hypercall_msr) 10261491cf4SDavid Woodhouse { 10361491cf4SDavid Woodhouse const int required_caps = KVM_XEN_HVM_CONFIG_HYPERCALL_MSR | 10461491cf4SDavid Woodhouse KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL | KVM_XEN_HVM_CONFIG_SHARED_INFO; 10561491cf4SDavid Woodhouse struct kvm_xen_hvm_config cfg = { 106f66b8a83SJoao Martins .msr = hypercall_msr, 10761491cf4SDavid Woodhouse .flags = KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL, 10861491cf4SDavid Woodhouse }; 10961491cf4SDavid Woodhouse int xen_caps, ret; 11061491cf4SDavid Woodhouse 11161491cf4SDavid Woodhouse xen_caps = kvm_check_extension(s, KVM_CAP_XEN_HVM); 11261491cf4SDavid Woodhouse if (required_caps & ~xen_caps) { 11361491cf4SDavid Woodhouse error_report("kvm: Xen HVM guest support not present or insufficient"); 11461491cf4SDavid Woodhouse return -ENOSYS; 11561491cf4SDavid Woodhouse } 11661491cf4SDavid Woodhouse 11761491cf4SDavid Woodhouse if (xen_caps & KVM_XEN_HVM_CONFIG_EVTCHN_SEND) { 11861491cf4SDavid Woodhouse struct kvm_xen_hvm_attr ha = { 11961491cf4SDavid Woodhouse .type = KVM_XEN_ATTR_TYPE_XEN_VERSION, 12061491cf4SDavid Woodhouse .u.xen_version = s->xen_version, 12161491cf4SDavid Woodhouse }; 12261491cf4SDavid Woodhouse (void)kvm_vm_ioctl(s, KVM_XEN_HVM_SET_ATTR, &ha); 12361491cf4SDavid Woodhouse 12461491cf4SDavid Woodhouse cfg.flags |= KVM_XEN_HVM_CONFIG_EVTCHN_SEND; 12561491cf4SDavid Woodhouse } 12661491cf4SDavid Woodhouse 12761491cf4SDavid Woodhouse ret = kvm_vm_ioctl(s, KVM_XEN_HVM_CONFIG, &cfg); 12861491cf4SDavid Woodhouse if (ret < 0) { 12961491cf4SDavid Woodhouse error_report("kvm: Failed to enable Xen HVM support: %s", 13061491cf4SDavid Woodhouse strerror(-ret)); 13161491cf4SDavid Woodhouse return ret; 13261491cf4SDavid Woodhouse } 13361491cf4SDavid Woodhouse 134*2aff696bSDavid Woodhouse /* If called a second time, don't repeat the rest of the setup. */ 135*2aff696bSDavid Woodhouse if (s->xen_caps) { 136*2aff696bSDavid Woodhouse return 0; 137*2aff696bSDavid Woodhouse } 138*2aff696bSDavid Woodhouse 139*2aff696bSDavid Woodhouse /* 140*2aff696bSDavid Woodhouse * Event channel delivery via GSI/PCI_INTX needs to poll the vcpu_info 141*2aff696bSDavid Woodhouse * of vCPU0 to deassert the IRQ when ->evtchn_upcall_pending is cleared. 142*2aff696bSDavid Woodhouse * 143*2aff696bSDavid Woodhouse * In the kernel, there's a notifier hook on the PIC/IOAPIC which allows 144*2aff696bSDavid Woodhouse * such things to be polled at precisely the right time. We *could* do 145*2aff696bSDavid Woodhouse * it nicely in the kernel: check vcpu_info[0]->evtchn_upcall_pending at 146*2aff696bSDavid Woodhouse * the moment the IRQ is acked, and see if it should be reasserted. 147*2aff696bSDavid Woodhouse * 148*2aff696bSDavid Woodhouse * But the in-kernel irqchip is deprecated, so we're unlikely to add 149*2aff696bSDavid Woodhouse * that support in the kernel. Insist on using the split irqchip mode 150*2aff696bSDavid Woodhouse * instead. 151*2aff696bSDavid Woodhouse * 152*2aff696bSDavid Woodhouse * This leaves us polling for the level going low in QEMU, which lacks 153*2aff696bSDavid Woodhouse * the appropriate hooks in its PIC/IOAPIC code. Even VFIO is sending a 154*2aff696bSDavid Woodhouse * spurious 'ack' to an INTX IRQ every time there's any MMIO access to 155*2aff696bSDavid Woodhouse * the device (for which it has to unmap the device and trap access, for 156*2aff696bSDavid Woodhouse * some period after an IRQ!!). In the Xen case, we do it on exit from 157*2aff696bSDavid Woodhouse * KVM_RUN, if the flag is set to say that the GSI is currently asserted. 158*2aff696bSDavid Woodhouse * Which is kind of icky, but less so than the VFIO one. I may fix them 159*2aff696bSDavid Woodhouse * both later... 160*2aff696bSDavid Woodhouse */ 161*2aff696bSDavid Woodhouse if (!kvm_kernel_irqchip_split()) { 162*2aff696bSDavid Woodhouse error_report("kvm: Xen support requires kernel-irqchip=split"); 163*2aff696bSDavid Woodhouse return -EINVAL; 164*2aff696bSDavid Woodhouse } 165*2aff696bSDavid Woodhouse 16661491cf4SDavid Woodhouse s->xen_caps = xen_caps; 16761491cf4SDavid Woodhouse return 0; 16861491cf4SDavid Woodhouse } 16961491cf4SDavid Woodhouse 1705e691a95SDavid Woodhouse int kvm_xen_init_vcpu(CPUState *cs) 1715e691a95SDavid Woodhouse { 172c345104cSJoao Martins X86CPU *cpu = X86_CPU(cs); 173c345104cSJoao Martins CPUX86State *env = &cpu->env; 1745e691a95SDavid Woodhouse int err; 1755e691a95SDavid Woodhouse 1765e691a95SDavid Woodhouse /* 1775e691a95SDavid Woodhouse * The kernel needs to know the Xen/ACPI vCPU ID because that's 1785e691a95SDavid Woodhouse * what the guest uses in hypercalls such as timers. It doesn't 1795e691a95SDavid Woodhouse * match the APIC ID which is generally used for talking to the 1805e691a95SDavid Woodhouse * kernel about vCPUs. And if vCPU threads race with creating 1815e691a95SDavid Woodhouse * their KVM vCPUs out of order, it doesn't necessarily match 1825e691a95SDavid Woodhouse * with the kernel's internal vCPU indices either. 1835e691a95SDavid Woodhouse */ 1845e691a95SDavid Woodhouse if (kvm_xen_has_cap(EVTCHN_SEND)) { 1855e691a95SDavid Woodhouse struct kvm_xen_vcpu_attr va = { 1865e691a95SDavid Woodhouse .type = KVM_XEN_VCPU_ATTR_TYPE_VCPU_ID, 1875e691a95SDavid Woodhouse .u.vcpu_id = cs->cpu_index, 1885e691a95SDavid Woodhouse }; 1895e691a95SDavid Woodhouse err = kvm_vcpu_ioctl(cs, KVM_XEN_VCPU_SET_ATTR, &va); 1905e691a95SDavid Woodhouse if (err) { 1915e691a95SDavid Woodhouse error_report("kvm: Failed to set Xen vCPU ID attribute: %s", 1925e691a95SDavid Woodhouse strerror(-err)); 1935e691a95SDavid Woodhouse return err; 1945e691a95SDavid Woodhouse } 1955e691a95SDavid Woodhouse } 1965e691a95SDavid Woodhouse 197c345104cSJoao Martins env->xen_vcpu_info_gpa = INVALID_GPA; 198c345104cSJoao Martins env->xen_vcpu_info_default_gpa = INVALID_GPA; 199f0689302SJoao Martins env->xen_vcpu_time_info_gpa = INVALID_GPA; 2005092db87SJoao Martins env->xen_vcpu_runstate_gpa = INVALID_GPA; 201c345104cSJoao Martins 2025e691a95SDavid Woodhouse return 0; 2035e691a95SDavid Woodhouse } 2045e691a95SDavid Woodhouse 20561491cf4SDavid Woodhouse uint32_t kvm_xen_get_caps(void) 20661491cf4SDavid Woodhouse { 20761491cf4SDavid Woodhouse return kvm_state->xen_caps; 20861491cf4SDavid Woodhouse } 20955a3f666SJoao Martins 210bedcc139SJoao Martins static bool kvm_xen_hcall_xen_version(struct kvm_xen_exit *exit, X86CPU *cpu, 211bedcc139SJoao Martins int cmd, uint64_t arg) 212bedcc139SJoao Martins { 213bedcc139SJoao Martins int err = 0; 214bedcc139SJoao Martins 215bedcc139SJoao Martins switch (cmd) { 216bedcc139SJoao Martins case XENVER_get_features: { 217bedcc139SJoao Martins struct xen_feature_info fi; 218bedcc139SJoao Martins 219bedcc139SJoao Martins /* No need for 32/64 compat handling */ 220bedcc139SJoao Martins qemu_build_assert(sizeof(fi) == 8); 221bedcc139SJoao Martins 222bedcc139SJoao Martins err = kvm_copy_from_gva(CPU(cpu), arg, &fi, sizeof(fi)); 223bedcc139SJoao Martins if (err) { 224bedcc139SJoao Martins break; 225bedcc139SJoao Martins } 226bedcc139SJoao Martins 227bedcc139SJoao Martins fi.submap = 0; 228bedcc139SJoao Martins if (fi.submap_idx == 0) { 229bedcc139SJoao Martins fi.submap |= 1 << XENFEAT_writable_page_tables | 230bedcc139SJoao Martins 1 << XENFEAT_writable_descriptor_tables | 231bedcc139SJoao Martins 1 << XENFEAT_auto_translated_physmap | 232105b47fdSAnkur Arora 1 << XENFEAT_supervisor_mode_kernel | 233105b47fdSAnkur Arora 1 << XENFEAT_hvm_callback_vector; 234bedcc139SJoao Martins } 235bedcc139SJoao Martins 236bedcc139SJoao Martins err = kvm_copy_to_gva(CPU(cpu), arg, &fi, sizeof(fi)); 237bedcc139SJoao Martins break; 238bedcc139SJoao Martins } 239bedcc139SJoao Martins 240bedcc139SJoao Martins default: 241bedcc139SJoao Martins return false; 242bedcc139SJoao Martins } 243bedcc139SJoao Martins 244bedcc139SJoao Martins exit->u.hcall.result = err; 245bedcc139SJoao Martins return true; 246bedcc139SJoao Martins } 247bedcc139SJoao Martins 248c345104cSJoao Martins static int kvm_xen_set_vcpu_attr(CPUState *cs, uint16_t type, uint64_t gpa) 249c345104cSJoao Martins { 250c345104cSJoao Martins struct kvm_xen_vcpu_attr xhsi; 251c345104cSJoao Martins 252c345104cSJoao Martins xhsi.type = type; 253c345104cSJoao Martins xhsi.u.gpa = gpa; 254c345104cSJoao Martins 255c345104cSJoao Martins trace_kvm_xen_set_vcpu_attr(cs->cpu_index, type, gpa); 256c345104cSJoao Martins 257c345104cSJoao Martins return kvm_vcpu_ioctl(cs, KVM_XEN_VCPU_SET_ATTR, &xhsi); 258c345104cSJoao Martins } 259c345104cSJoao Martins 260105b47fdSAnkur Arora static int kvm_xen_set_vcpu_callback_vector(CPUState *cs) 261105b47fdSAnkur Arora { 262105b47fdSAnkur Arora uint8_t vector = X86_CPU(cs)->env.xen_vcpu_callback_vector; 263105b47fdSAnkur Arora struct kvm_xen_vcpu_attr xva; 264105b47fdSAnkur Arora 265105b47fdSAnkur Arora xva.type = KVM_XEN_VCPU_ATTR_TYPE_UPCALL_VECTOR; 266105b47fdSAnkur Arora xva.u.vector = vector; 267105b47fdSAnkur Arora 268105b47fdSAnkur Arora trace_kvm_xen_set_vcpu_callback(cs->cpu_index, vector); 269105b47fdSAnkur Arora 270105b47fdSAnkur Arora return kvm_vcpu_ioctl(cs, KVM_XEN_HVM_SET_ATTR, &xva); 271105b47fdSAnkur Arora } 272105b47fdSAnkur Arora 273105b47fdSAnkur Arora static void do_set_vcpu_callback_vector(CPUState *cs, run_on_cpu_data data) 274105b47fdSAnkur Arora { 275105b47fdSAnkur Arora X86CPU *cpu = X86_CPU(cs); 276105b47fdSAnkur Arora CPUX86State *env = &cpu->env; 277105b47fdSAnkur Arora 278105b47fdSAnkur Arora env->xen_vcpu_callback_vector = data.host_int; 279105b47fdSAnkur Arora 280105b47fdSAnkur Arora if (kvm_xen_has_cap(EVTCHN_SEND)) { 281105b47fdSAnkur Arora kvm_xen_set_vcpu_callback_vector(cs); 282105b47fdSAnkur Arora } 283105b47fdSAnkur Arora } 284105b47fdSAnkur Arora 28527d4075dSDavid Woodhouse static int set_vcpu_info(CPUState *cs, uint64_t gpa) 28627d4075dSDavid Woodhouse { 28727d4075dSDavid Woodhouse X86CPU *cpu = X86_CPU(cs); 28827d4075dSDavid Woodhouse CPUX86State *env = &cpu->env; 28927d4075dSDavid Woodhouse MemoryRegionSection mrs = { .mr = NULL }; 29027d4075dSDavid Woodhouse void *vcpu_info_hva = NULL; 29127d4075dSDavid Woodhouse int ret; 29227d4075dSDavid Woodhouse 29327d4075dSDavid Woodhouse ret = kvm_xen_set_vcpu_attr(cs, KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO, gpa); 29427d4075dSDavid Woodhouse if (ret || gpa == INVALID_GPA) { 29527d4075dSDavid Woodhouse goto out; 29627d4075dSDavid Woodhouse } 29727d4075dSDavid Woodhouse 29827d4075dSDavid Woodhouse mrs = memory_region_find(get_system_memory(), gpa, 29927d4075dSDavid Woodhouse sizeof(struct vcpu_info)); 30027d4075dSDavid Woodhouse if (mrs.mr && mrs.mr->ram_block && 30127d4075dSDavid Woodhouse !int128_lt(mrs.size, int128_make64(sizeof(struct vcpu_info)))) { 30227d4075dSDavid Woodhouse vcpu_info_hva = qemu_map_ram_ptr(mrs.mr->ram_block, 30327d4075dSDavid Woodhouse mrs.offset_within_region); 30427d4075dSDavid Woodhouse } 30527d4075dSDavid Woodhouse if (!vcpu_info_hva) { 30627d4075dSDavid Woodhouse if (mrs.mr) { 30727d4075dSDavid Woodhouse memory_region_unref(mrs.mr); 30827d4075dSDavid Woodhouse mrs.mr = NULL; 30927d4075dSDavid Woodhouse } 31027d4075dSDavid Woodhouse ret = -EINVAL; 31127d4075dSDavid Woodhouse } 31227d4075dSDavid Woodhouse 31327d4075dSDavid Woodhouse out: 31427d4075dSDavid Woodhouse if (env->xen_vcpu_info_mr) { 31527d4075dSDavid Woodhouse memory_region_unref(env->xen_vcpu_info_mr); 31627d4075dSDavid Woodhouse } 31727d4075dSDavid Woodhouse env->xen_vcpu_info_hva = vcpu_info_hva; 31827d4075dSDavid Woodhouse env->xen_vcpu_info_mr = mrs.mr; 31927d4075dSDavid Woodhouse return ret; 32027d4075dSDavid Woodhouse } 32127d4075dSDavid Woodhouse 322c345104cSJoao Martins static void do_set_vcpu_info_default_gpa(CPUState *cs, run_on_cpu_data data) 323c345104cSJoao Martins { 324c345104cSJoao Martins X86CPU *cpu = X86_CPU(cs); 325c345104cSJoao Martins CPUX86State *env = &cpu->env; 326c345104cSJoao Martins 327c345104cSJoao Martins env->xen_vcpu_info_default_gpa = data.host_ulong; 328c345104cSJoao Martins 329c345104cSJoao Martins /* Changing the default does nothing if a vcpu_info was explicitly set. */ 330c345104cSJoao Martins if (env->xen_vcpu_info_gpa == INVALID_GPA) { 33127d4075dSDavid Woodhouse set_vcpu_info(cs, env->xen_vcpu_info_default_gpa); 332c345104cSJoao Martins } 333c345104cSJoao Martins } 334c345104cSJoao Martins 335c345104cSJoao Martins static void do_set_vcpu_info_gpa(CPUState *cs, run_on_cpu_data data) 336c345104cSJoao Martins { 337c345104cSJoao Martins X86CPU *cpu = X86_CPU(cs); 338c345104cSJoao Martins CPUX86State *env = &cpu->env; 339c345104cSJoao Martins 340c345104cSJoao Martins env->xen_vcpu_info_gpa = data.host_ulong; 341c345104cSJoao Martins 34227d4075dSDavid Woodhouse set_vcpu_info(cs, env->xen_vcpu_info_gpa); 34327d4075dSDavid Woodhouse } 34427d4075dSDavid Woodhouse 34527d4075dSDavid Woodhouse void *kvm_xen_get_vcpu_info_hva(uint32_t vcpu_id) 34627d4075dSDavid Woodhouse { 34727d4075dSDavid Woodhouse CPUState *cs = qemu_get_cpu(vcpu_id); 34827d4075dSDavid Woodhouse if (!cs) { 34927d4075dSDavid Woodhouse return NULL; 35027d4075dSDavid Woodhouse } 35127d4075dSDavid Woodhouse 35227d4075dSDavid Woodhouse return X86_CPU(cs)->env.xen_vcpu_info_hva; 35327d4075dSDavid Woodhouse } 35427d4075dSDavid Woodhouse 355ddf0fd9aSDavid Woodhouse void kvm_xen_maybe_deassert_callback(CPUState *cs) 356ddf0fd9aSDavid Woodhouse { 357ddf0fd9aSDavid Woodhouse CPUX86State *env = &X86_CPU(cs)->env; 358ddf0fd9aSDavid Woodhouse struct vcpu_info *vi = env->xen_vcpu_info_hva; 359ddf0fd9aSDavid Woodhouse if (!vi) { 360ddf0fd9aSDavid Woodhouse return; 361ddf0fd9aSDavid Woodhouse } 362ddf0fd9aSDavid Woodhouse 363ddf0fd9aSDavid Woodhouse /* If the evtchn_upcall_pending flag is cleared, turn the GSI off. */ 364ddf0fd9aSDavid Woodhouse if (!vi->evtchn_upcall_pending) { 365ddf0fd9aSDavid Woodhouse qemu_mutex_lock_iothread(); 366ddf0fd9aSDavid Woodhouse /* 367ddf0fd9aSDavid Woodhouse * Check again now we have the lock, because it may have been 368ddf0fd9aSDavid Woodhouse * asserted in the interim. And we don't want to take the lock 369ddf0fd9aSDavid Woodhouse * every time because this is a fast path. 370ddf0fd9aSDavid Woodhouse */ 371ddf0fd9aSDavid Woodhouse if (!vi->evtchn_upcall_pending) { 372ddf0fd9aSDavid Woodhouse X86_CPU(cs)->env.xen_callback_asserted = false; 373ddf0fd9aSDavid Woodhouse xen_evtchn_set_callback_level(0); 374ddf0fd9aSDavid Woodhouse } 375ddf0fd9aSDavid Woodhouse qemu_mutex_unlock_iothread(); 376ddf0fd9aSDavid Woodhouse } 377ddf0fd9aSDavid Woodhouse } 378ddf0fd9aSDavid Woodhouse 379ddf0fd9aSDavid Woodhouse void kvm_xen_set_callback_asserted(void) 380ddf0fd9aSDavid Woodhouse { 381ddf0fd9aSDavid Woodhouse CPUState *cs = qemu_get_cpu(0); 382ddf0fd9aSDavid Woodhouse 383ddf0fd9aSDavid Woodhouse if (cs) { 384ddf0fd9aSDavid Woodhouse X86_CPU(cs)->env.xen_callback_asserted = true; 385ddf0fd9aSDavid Woodhouse } 386ddf0fd9aSDavid Woodhouse } 387ddf0fd9aSDavid Woodhouse 38827d4075dSDavid Woodhouse void kvm_xen_inject_vcpu_callback_vector(uint32_t vcpu_id, int type) 38927d4075dSDavid Woodhouse { 39027d4075dSDavid Woodhouse CPUState *cs = qemu_get_cpu(vcpu_id); 39127d4075dSDavid Woodhouse uint8_t vector; 39227d4075dSDavid Woodhouse 39327d4075dSDavid Woodhouse if (!cs) { 39427d4075dSDavid Woodhouse return; 39527d4075dSDavid Woodhouse } 39627d4075dSDavid Woodhouse 39727d4075dSDavid Woodhouse vector = X86_CPU(cs)->env.xen_vcpu_callback_vector; 39827d4075dSDavid Woodhouse if (vector) { 39927d4075dSDavid Woodhouse /* 40027d4075dSDavid Woodhouse * The per-vCPU callback vector injected via lapic. Just 40127d4075dSDavid Woodhouse * deliver it as an MSI. 40227d4075dSDavid Woodhouse */ 40327d4075dSDavid Woodhouse MSIMessage msg = { 40427d4075dSDavid Woodhouse .address = APIC_DEFAULT_ADDRESS | X86_CPU(cs)->apic_id, 40527d4075dSDavid Woodhouse .data = vector | (1UL << MSI_DATA_LEVEL_SHIFT), 40627d4075dSDavid Woodhouse }; 40727d4075dSDavid Woodhouse kvm_irqchip_send_msi(kvm_state, msg); 40827d4075dSDavid Woodhouse return; 40927d4075dSDavid Woodhouse } 41027d4075dSDavid Woodhouse 41127d4075dSDavid Woodhouse switch (type) { 41227d4075dSDavid Woodhouse case HVM_PARAM_CALLBACK_TYPE_VECTOR: 41327d4075dSDavid Woodhouse /* 41427d4075dSDavid Woodhouse * If the evtchn_upcall_pending field in the vcpu_info is set, then 41527d4075dSDavid Woodhouse * KVM will automatically deliver the vector on entering the vCPU 41627d4075dSDavid Woodhouse * so all we have to do is kick it out. 41727d4075dSDavid Woodhouse */ 41827d4075dSDavid Woodhouse qemu_cpu_kick(cs); 41927d4075dSDavid Woodhouse break; 420ddf0fd9aSDavid Woodhouse 421ddf0fd9aSDavid Woodhouse case HVM_PARAM_CALLBACK_TYPE_GSI: 422ddf0fd9aSDavid Woodhouse case HVM_PARAM_CALLBACK_TYPE_PCI_INTX: 423ddf0fd9aSDavid Woodhouse if (vcpu_id == 0) { 424ddf0fd9aSDavid Woodhouse xen_evtchn_set_callback_level(1); 425ddf0fd9aSDavid Woodhouse } 426ddf0fd9aSDavid Woodhouse break; 42727d4075dSDavid Woodhouse } 428c345104cSJoao Martins } 429c345104cSJoao Martins 430c723d4c1SDavid Woodhouse static int kvm_xen_set_vcpu_timer(CPUState *cs) 431c723d4c1SDavid Woodhouse { 432c723d4c1SDavid Woodhouse X86CPU *cpu = X86_CPU(cs); 433c723d4c1SDavid Woodhouse CPUX86State *env = &cpu->env; 434c723d4c1SDavid Woodhouse 435c723d4c1SDavid Woodhouse struct kvm_xen_vcpu_attr va = { 436c723d4c1SDavid Woodhouse .type = KVM_XEN_VCPU_ATTR_TYPE_TIMER, 437c723d4c1SDavid Woodhouse .u.timer.port = env->xen_virq[VIRQ_TIMER], 438c723d4c1SDavid Woodhouse .u.timer.priority = KVM_IRQ_ROUTING_XEN_EVTCHN_PRIO_2LEVEL, 439c723d4c1SDavid Woodhouse .u.timer.expires_ns = env->xen_singleshot_timer_ns, 440c723d4c1SDavid Woodhouse }; 441c723d4c1SDavid Woodhouse 442c723d4c1SDavid Woodhouse return kvm_vcpu_ioctl(cs, KVM_XEN_VCPU_SET_ATTR, &va); 443c723d4c1SDavid Woodhouse } 444c723d4c1SDavid Woodhouse 445c723d4c1SDavid Woodhouse static void do_set_vcpu_timer_virq(CPUState *cs, run_on_cpu_data data) 446c723d4c1SDavid Woodhouse { 447c723d4c1SDavid Woodhouse kvm_xen_set_vcpu_timer(cs); 448c723d4c1SDavid Woodhouse } 449c723d4c1SDavid Woodhouse 450c723d4c1SDavid Woodhouse int kvm_xen_set_vcpu_virq(uint32_t vcpu_id, uint16_t virq, uint16_t port) 451c723d4c1SDavid Woodhouse { 452c723d4c1SDavid Woodhouse CPUState *cs = qemu_get_cpu(vcpu_id); 453c723d4c1SDavid Woodhouse 454c723d4c1SDavid Woodhouse if (!cs) { 455c723d4c1SDavid Woodhouse return -ENOENT; 456c723d4c1SDavid Woodhouse } 457c723d4c1SDavid Woodhouse 458c723d4c1SDavid Woodhouse /* cpu.h doesn't include the actual Xen header. */ 459c723d4c1SDavid Woodhouse qemu_build_assert(NR_VIRQS == XEN_NR_VIRQS); 460c723d4c1SDavid Woodhouse 461c723d4c1SDavid Woodhouse if (virq >= NR_VIRQS) { 462c723d4c1SDavid Woodhouse return -EINVAL; 463c723d4c1SDavid Woodhouse } 464c723d4c1SDavid Woodhouse 465c723d4c1SDavid Woodhouse if (port && X86_CPU(cs)->env.xen_virq[virq]) { 466c723d4c1SDavid Woodhouse return -EEXIST; 467c723d4c1SDavid Woodhouse } 468c723d4c1SDavid Woodhouse 469c723d4c1SDavid Woodhouse X86_CPU(cs)->env.xen_virq[virq] = port; 470c723d4c1SDavid Woodhouse if (virq == VIRQ_TIMER && kvm_xen_has_cap(EVTCHN_SEND)) { 471c723d4c1SDavid Woodhouse async_run_on_cpu(cs, do_set_vcpu_timer_virq, 472c723d4c1SDavid Woodhouse RUN_ON_CPU_HOST_INT(port)); 473c723d4c1SDavid Woodhouse } 474c723d4c1SDavid Woodhouse return 0; 475c723d4c1SDavid Woodhouse } 476c723d4c1SDavid Woodhouse 477f0689302SJoao Martins static void do_set_vcpu_time_info_gpa(CPUState *cs, run_on_cpu_data data) 478f0689302SJoao Martins { 479f0689302SJoao Martins X86CPU *cpu = X86_CPU(cs); 480f0689302SJoao Martins CPUX86State *env = &cpu->env; 481f0689302SJoao Martins 482f0689302SJoao Martins env->xen_vcpu_time_info_gpa = data.host_ulong; 483f0689302SJoao Martins 484f0689302SJoao Martins kvm_xen_set_vcpu_attr(cs, KVM_XEN_VCPU_ATTR_TYPE_VCPU_TIME_INFO, 485f0689302SJoao Martins env->xen_vcpu_time_info_gpa); 486f0689302SJoao Martins } 487f0689302SJoao Martins 4885092db87SJoao Martins static void do_set_vcpu_runstate_gpa(CPUState *cs, run_on_cpu_data data) 4895092db87SJoao Martins { 4905092db87SJoao Martins X86CPU *cpu = X86_CPU(cs); 4915092db87SJoao Martins CPUX86State *env = &cpu->env; 4925092db87SJoao Martins 4935092db87SJoao Martins env->xen_vcpu_runstate_gpa = data.host_ulong; 4945092db87SJoao Martins 4955092db87SJoao Martins kvm_xen_set_vcpu_attr(cs, KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADDR, 4965092db87SJoao Martins env->xen_vcpu_runstate_gpa); 4975092db87SJoao Martins } 4985092db87SJoao Martins 499c345104cSJoao Martins static void do_vcpu_soft_reset(CPUState *cs, run_on_cpu_data data) 500c345104cSJoao Martins { 501c345104cSJoao Martins X86CPU *cpu = X86_CPU(cs); 502c345104cSJoao Martins CPUX86State *env = &cpu->env; 503c345104cSJoao Martins 504c345104cSJoao Martins env->xen_vcpu_info_gpa = INVALID_GPA; 505c345104cSJoao Martins env->xen_vcpu_info_default_gpa = INVALID_GPA; 506f0689302SJoao Martins env->xen_vcpu_time_info_gpa = INVALID_GPA; 5075092db87SJoao Martins env->xen_vcpu_runstate_gpa = INVALID_GPA; 508105b47fdSAnkur Arora env->xen_vcpu_callback_vector = 0; 509c723d4c1SDavid Woodhouse env->xen_singleshot_timer_ns = 0; 510c723d4c1SDavid Woodhouse memset(env->xen_virq, 0, sizeof(env->xen_virq)); 511c345104cSJoao Martins 51227d4075dSDavid Woodhouse set_vcpu_info(cs, INVALID_GPA); 513f0689302SJoao Martins kvm_xen_set_vcpu_attr(cs, KVM_XEN_VCPU_ATTR_TYPE_VCPU_TIME_INFO, 514f0689302SJoao Martins INVALID_GPA); 5155092db87SJoao Martins kvm_xen_set_vcpu_attr(cs, KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADDR, 5165092db87SJoao Martins INVALID_GPA); 517105b47fdSAnkur Arora if (kvm_xen_has_cap(EVTCHN_SEND)) { 518105b47fdSAnkur Arora kvm_xen_set_vcpu_callback_vector(cs); 519c723d4c1SDavid Woodhouse kvm_xen_set_vcpu_timer(cs); 520105b47fdSAnkur Arora } 5215092db87SJoao Martins 522c345104cSJoao Martins } 523c345104cSJoao Martins 524fb0fd2ceSJoao Martins static int xen_set_shared_info(uint64_t gfn) 525fb0fd2ceSJoao Martins { 526fb0fd2ceSJoao Martins uint64_t gpa = gfn << TARGET_PAGE_BITS; 527c345104cSJoao Martins int i, err; 528fb0fd2ceSJoao Martins 529fb0fd2ceSJoao Martins QEMU_IOTHREAD_LOCK_GUARD(); 530fb0fd2ceSJoao Martins 531fb0fd2ceSJoao Martins /* 532fb0fd2ceSJoao Martins * The xen_overlay device tells KVM about it too, since it had to 533fb0fd2ceSJoao Martins * do that on migration load anyway (unless we're going to jump 534fb0fd2ceSJoao Martins * through lots of hoops to maintain the fiction that this isn't 535fb0fd2ceSJoao Martins * KVM-specific. 536fb0fd2ceSJoao Martins */ 537fb0fd2ceSJoao Martins err = xen_overlay_map_shinfo_page(gpa); 538fb0fd2ceSJoao Martins if (err) { 539fb0fd2ceSJoao Martins return err; 540fb0fd2ceSJoao Martins } 541fb0fd2ceSJoao Martins 542fb0fd2ceSJoao Martins trace_kvm_xen_set_shared_info(gfn); 543fb0fd2ceSJoao Martins 544c345104cSJoao Martins for (i = 0; i < XEN_LEGACY_MAX_VCPUS; i++) { 545c345104cSJoao Martins CPUState *cpu = qemu_get_cpu(i); 546c345104cSJoao Martins if (cpu) { 547c345104cSJoao Martins async_run_on_cpu(cpu, do_set_vcpu_info_default_gpa, 548c345104cSJoao Martins RUN_ON_CPU_HOST_ULONG(gpa)); 549c345104cSJoao Martins } 550c345104cSJoao Martins gpa += sizeof(vcpu_info_t); 551c345104cSJoao Martins } 552c345104cSJoao Martins 553fb0fd2ceSJoao Martins return err; 554fb0fd2ceSJoao Martins } 555fb0fd2ceSJoao Martins 556fb0fd2ceSJoao Martins static int add_to_physmap_one(uint32_t space, uint64_t idx, uint64_t gfn) 557fb0fd2ceSJoao Martins { 558fb0fd2ceSJoao Martins switch (space) { 559fb0fd2ceSJoao Martins case XENMAPSPACE_shared_info: 560fb0fd2ceSJoao Martins if (idx > 0) { 561fb0fd2ceSJoao Martins return -EINVAL; 562fb0fd2ceSJoao Martins } 563fb0fd2ceSJoao Martins return xen_set_shared_info(gfn); 564fb0fd2ceSJoao Martins 565fb0fd2ceSJoao Martins case XENMAPSPACE_grant_table: 566fb0fd2ceSJoao Martins case XENMAPSPACE_gmfn: 567fb0fd2ceSJoao Martins case XENMAPSPACE_gmfn_range: 568fb0fd2ceSJoao Martins return -ENOTSUP; 569fb0fd2ceSJoao Martins 570fb0fd2ceSJoao Martins case XENMAPSPACE_gmfn_foreign: 571fb0fd2ceSJoao Martins case XENMAPSPACE_dev_mmio: 572fb0fd2ceSJoao Martins return -EPERM; 573fb0fd2ceSJoao Martins 574fb0fd2ceSJoao Martins default: 575fb0fd2ceSJoao Martins return -EINVAL; 576fb0fd2ceSJoao Martins } 577fb0fd2ceSJoao Martins } 578fb0fd2ceSJoao Martins 579fb0fd2ceSJoao Martins static int do_add_to_physmap(struct kvm_xen_exit *exit, X86CPU *cpu, 580fb0fd2ceSJoao Martins uint64_t arg) 581fb0fd2ceSJoao Martins { 582fb0fd2ceSJoao Martins struct xen_add_to_physmap xatp; 583fb0fd2ceSJoao Martins CPUState *cs = CPU(cpu); 584fb0fd2ceSJoao Martins 585fb0fd2ceSJoao Martins if (hypercall_compat32(exit->u.hcall.longmode)) { 586fb0fd2ceSJoao Martins struct compat_xen_add_to_physmap xatp32; 587fb0fd2ceSJoao Martins 588fb0fd2ceSJoao Martins qemu_build_assert(sizeof(struct compat_xen_add_to_physmap) == 16); 589fb0fd2ceSJoao Martins if (kvm_copy_from_gva(cs, arg, &xatp32, sizeof(xatp32))) { 590fb0fd2ceSJoao Martins return -EFAULT; 591fb0fd2ceSJoao Martins } 592fb0fd2ceSJoao Martins xatp.domid = xatp32.domid; 593fb0fd2ceSJoao Martins xatp.size = xatp32.size; 594fb0fd2ceSJoao Martins xatp.space = xatp32.space; 595fb0fd2ceSJoao Martins xatp.idx = xatp32.idx; 596fb0fd2ceSJoao Martins xatp.gpfn = xatp32.gpfn; 597fb0fd2ceSJoao Martins } else { 598fb0fd2ceSJoao Martins if (kvm_copy_from_gva(cs, arg, &xatp, sizeof(xatp))) { 599fb0fd2ceSJoao Martins return -EFAULT; 600fb0fd2ceSJoao Martins } 601fb0fd2ceSJoao Martins } 602fb0fd2ceSJoao Martins 603fb0fd2ceSJoao Martins if (xatp.domid != DOMID_SELF && xatp.domid != xen_domid) { 604fb0fd2ceSJoao Martins return -ESRCH; 605fb0fd2ceSJoao Martins } 606fb0fd2ceSJoao Martins 607fb0fd2ceSJoao Martins return add_to_physmap_one(xatp.space, xatp.idx, xatp.gpfn); 608fb0fd2ceSJoao Martins } 609fb0fd2ceSJoao Martins 610782a7960SDavid Woodhouse static int do_add_to_physmap_batch(struct kvm_xen_exit *exit, X86CPU *cpu, 611782a7960SDavid Woodhouse uint64_t arg) 612782a7960SDavid Woodhouse { 613782a7960SDavid Woodhouse struct xen_add_to_physmap_batch xatpb; 614782a7960SDavid Woodhouse unsigned long idxs_gva, gpfns_gva, errs_gva; 615782a7960SDavid Woodhouse CPUState *cs = CPU(cpu); 616782a7960SDavid Woodhouse size_t op_sz; 617782a7960SDavid Woodhouse 618782a7960SDavid Woodhouse if (hypercall_compat32(exit->u.hcall.longmode)) { 619782a7960SDavid Woodhouse struct compat_xen_add_to_physmap_batch xatpb32; 620782a7960SDavid Woodhouse 621782a7960SDavid Woodhouse qemu_build_assert(sizeof(struct compat_xen_add_to_physmap_batch) == 20); 622782a7960SDavid Woodhouse if (kvm_copy_from_gva(cs, arg, &xatpb32, sizeof(xatpb32))) { 623782a7960SDavid Woodhouse return -EFAULT; 624782a7960SDavid Woodhouse } 625782a7960SDavid Woodhouse xatpb.domid = xatpb32.domid; 626782a7960SDavid Woodhouse xatpb.space = xatpb32.space; 627782a7960SDavid Woodhouse xatpb.size = xatpb32.size; 628782a7960SDavid Woodhouse 629782a7960SDavid Woodhouse idxs_gva = xatpb32.idxs.c; 630782a7960SDavid Woodhouse gpfns_gva = xatpb32.gpfns.c; 631782a7960SDavid Woodhouse errs_gva = xatpb32.errs.c; 632782a7960SDavid Woodhouse op_sz = sizeof(uint32_t); 633782a7960SDavid Woodhouse } else { 634782a7960SDavid Woodhouse if (kvm_copy_from_gva(cs, arg, &xatpb, sizeof(xatpb))) { 635782a7960SDavid Woodhouse return -EFAULT; 636782a7960SDavid Woodhouse } 637782a7960SDavid Woodhouse op_sz = sizeof(unsigned long); 638782a7960SDavid Woodhouse idxs_gva = (unsigned long)xatpb.idxs.p; 639782a7960SDavid Woodhouse gpfns_gva = (unsigned long)xatpb.gpfns.p; 640782a7960SDavid Woodhouse errs_gva = (unsigned long)xatpb.errs.p; 641782a7960SDavid Woodhouse } 642782a7960SDavid Woodhouse 643782a7960SDavid Woodhouse if (xatpb.domid != DOMID_SELF && xatpb.domid != xen_domid) { 644782a7960SDavid Woodhouse return -ESRCH; 645782a7960SDavid Woodhouse } 646782a7960SDavid Woodhouse 647782a7960SDavid Woodhouse /* Explicitly invalid for the batch op. Not that we implement it anyway. */ 648782a7960SDavid Woodhouse if (xatpb.space == XENMAPSPACE_gmfn_range) { 649782a7960SDavid Woodhouse return -EINVAL; 650782a7960SDavid Woodhouse } 651782a7960SDavid Woodhouse 652782a7960SDavid Woodhouse while (xatpb.size--) { 653782a7960SDavid Woodhouse unsigned long idx = 0; 654782a7960SDavid Woodhouse unsigned long gpfn = 0; 655782a7960SDavid Woodhouse int err; 656782a7960SDavid Woodhouse 657782a7960SDavid Woodhouse /* For 32-bit compat this only copies the low 32 bits of each */ 658782a7960SDavid Woodhouse if (kvm_copy_from_gva(cs, idxs_gva, &idx, op_sz) || 659782a7960SDavid Woodhouse kvm_copy_from_gva(cs, gpfns_gva, &gpfn, op_sz)) { 660782a7960SDavid Woodhouse return -EFAULT; 661782a7960SDavid Woodhouse } 662782a7960SDavid Woodhouse idxs_gva += op_sz; 663782a7960SDavid Woodhouse gpfns_gva += op_sz; 664782a7960SDavid Woodhouse 665782a7960SDavid Woodhouse err = add_to_physmap_one(xatpb.space, idx, gpfn); 666782a7960SDavid Woodhouse 667782a7960SDavid Woodhouse if (kvm_copy_to_gva(cs, errs_gva, &err, sizeof(err))) { 668782a7960SDavid Woodhouse return -EFAULT; 669782a7960SDavid Woodhouse } 670782a7960SDavid Woodhouse errs_gva += sizeof(err); 671782a7960SDavid Woodhouse } 672782a7960SDavid Woodhouse return 0; 673782a7960SDavid Woodhouse } 674782a7960SDavid Woodhouse 675fb0fd2ceSJoao Martins static bool kvm_xen_hcall_memory_op(struct kvm_xen_exit *exit, X86CPU *cpu, 676fb0fd2ceSJoao Martins int cmd, uint64_t arg) 677fb0fd2ceSJoao Martins { 678fb0fd2ceSJoao Martins int err; 679fb0fd2ceSJoao Martins 680fb0fd2ceSJoao Martins switch (cmd) { 681fb0fd2ceSJoao Martins case XENMEM_add_to_physmap: 682fb0fd2ceSJoao Martins err = do_add_to_physmap(exit, cpu, arg); 683fb0fd2ceSJoao Martins break; 684fb0fd2ceSJoao Martins 685782a7960SDavid Woodhouse case XENMEM_add_to_physmap_batch: 686782a7960SDavid Woodhouse err = do_add_to_physmap_batch(exit, cpu, arg); 687782a7960SDavid Woodhouse break; 688782a7960SDavid Woodhouse 689fb0fd2ceSJoao Martins default: 690fb0fd2ceSJoao Martins return false; 691fb0fd2ceSJoao Martins } 692fb0fd2ceSJoao Martins 693fb0fd2ceSJoao Martins exit->u.hcall.result = err; 694fb0fd2ceSJoao Martins return true; 695fb0fd2ceSJoao Martins } 696fb0fd2ceSJoao Martins 6975dbcd01aSAnkur Arora static bool handle_set_param(struct kvm_xen_exit *exit, X86CPU *cpu, 6985dbcd01aSAnkur Arora uint64_t arg) 6995dbcd01aSAnkur Arora { 7005dbcd01aSAnkur Arora CPUState *cs = CPU(cpu); 7015dbcd01aSAnkur Arora struct xen_hvm_param hp; 7025dbcd01aSAnkur Arora int err = 0; 7035dbcd01aSAnkur Arora 7045dbcd01aSAnkur Arora /* No need for 32/64 compat handling */ 7055dbcd01aSAnkur Arora qemu_build_assert(sizeof(hp) == 16); 7065dbcd01aSAnkur Arora 7075dbcd01aSAnkur Arora if (kvm_copy_from_gva(cs, arg, &hp, sizeof(hp))) { 7085dbcd01aSAnkur Arora err = -EFAULT; 7095dbcd01aSAnkur Arora goto out; 7105dbcd01aSAnkur Arora } 7115dbcd01aSAnkur Arora 7125dbcd01aSAnkur Arora if (hp.domid != DOMID_SELF && hp.domid != xen_domid) { 7135dbcd01aSAnkur Arora err = -ESRCH; 7145dbcd01aSAnkur Arora goto out; 7155dbcd01aSAnkur Arora } 7165dbcd01aSAnkur Arora 7175dbcd01aSAnkur Arora switch (hp.index) { 71891cce756SDavid Woodhouse case HVM_PARAM_CALLBACK_IRQ: 719*2aff696bSDavid Woodhouse qemu_mutex_lock_iothread(); 72091cce756SDavid Woodhouse err = xen_evtchn_set_callback_param(hp.value); 721*2aff696bSDavid Woodhouse qemu_mutex_unlock_iothread(); 72291cce756SDavid Woodhouse xen_set_long_mode(exit->u.hcall.longmode); 72391cce756SDavid Woodhouse break; 7245dbcd01aSAnkur Arora default: 7255dbcd01aSAnkur Arora return false; 7265dbcd01aSAnkur Arora } 7275dbcd01aSAnkur Arora 7285dbcd01aSAnkur Arora out: 7295dbcd01aSAnkur Arora exit->u.hcall.result = err; 7305dbcd01aSAnkur Arora return true; 7315dbcd01aSAnkur Arora } 7325dbcd01aSAnkur Arora 733105b47fdSAnkur Arora static int kvm_xen_hcall_evtchn_upcall_vector(struct kvm_xen_exit *exit, 734105b47fdSAnkur Arora X86CPU *cpu, uint64_t arg) 735105b47fdSAnkur Arora { 736105b47fdSAnkur Arora struct xen_hvm_evtchn_upcall_vector up; 737105b47fdSAnkur Arora CPUState *target_cs; 738105b47fdSAnkur Arora 739105b47fdSAnkur Arora /* No need for 32/64 compat handling */ 740105b47fdSAnkur Arora qemu_build_assert(sizeof(up) == 8); 741105b47fdSAnkur Arora 742105b47fdSAnkur Arora if (kvm_copy_from_gva(CPU(cpu), arg, &up, sizeof(up))) { 743105b47fdSAnkur Arora return -EFAULT; 744105b47fdSAnkur Arora } 745105b47fdSAnkur Arora 746105b47fdSAnkur Arora if (up.vector < 0x10) { 747105b47fdSAnkur Arora return -EINVAL; 748105b47fdSAnkur Arora } 749105b47fdSAnkur Arora 750105b47fdSAnkur Arora target_cs = qemu_get_cpu(up.vcpu); 751105b47fdSAnkur Arora if (!target_cs) { 752105b47fdSAnkur Arora return -EINVAL; 753105b47fdSAnkur Arora } 754105b47fdSAnkur Arora 755105b47fdSAnkur Arora async_run_on_cpu(target_cs, do_set_vcpu_callback_vector, 756105b47fdSAnkur Arora RUN_ON_CPU_HOST_INT(up.vector)); 757105b47fdSAnkur Arora return 0; 758105b47fdSAnkur Arora } 759105b47fdSAnkur Arora 760671bfdcdSJoao Martins static bool kvm_xen_hcall_hvm_op(struct kvm_xen_exit *exit, X86CPU *cpu, 761671bfdcdSJoao Martins int cmd, uint64_t arg) 762671bfdcdSJoao Martins { 763105b47fdSAnkur Arora int ret = -ENOSYS; 764671bfdcdSJoao Martins switch (cmd) { 765105b47fdSAnkur Arora case HVMOP_set_evtchn_upcall_vector: 766105b47fdSAnkur Arora ret = kvm_xen_hcall_evtchn_upcall_vector(exit, cpu, 767105b47fdSAnkur Arora exit->u.hcall.params[0]); 768105b47fdSAnkur Arora break; 769105b47fdSAnkur Arora 770671bfdcdSJoao Martins case HVMOP_pagetable_dying: 771105b47fdSAnkur Arora ret = -ENOSYS; 772105b47fdSAnkur Arora break; 773671bfdcdSJoao Martins 7745dbcd01aSAnkur Arora case HVMOP_set_param: 7755dbcd01aSAnkur Arora return handle_set_param(exit, cpu, arg); 7765dbcd01aSAnkur Arora 777671bfdcdSJoao Martins default: 778671bfdcdSJoao Martins return false; 779671bfdcdSJoao Martins } 780105b47fdSAnkur Arora 781105b47fdSAnkur Arora exit->u.hcall.result = ret; 782105b47fdSAnkur Arora return true; 783671bfdcdSJoao Martins } 784671bfdcdSJoao Martins 785c345104cSJoao Martins static int vcpuop_register_vcpu_info(CPUState *cs, CPUState *target, 786c345104cSJoao Martins uint64_t arg) 787c345104cSJoao Martins { 788c345104cSJoao Martins struct vcpu_register_vcpu_info rvi; 789c345104cSJoao Martins uint64_t gpa; 790c345104cSJoao Martins 791c345104cSJoao Martins /* No need for 32/64 compat handling */ 792c345104cSJoao Martins qemu_build_assert(sizeof(rvi) == 16); 793c345104cSJoao Martins qemu_build_assert(sizeof(struct vcpu_info) == 64); 794c345104cSJoao Martins 795c345104cSJoao Martins if (!target) { 796c345104cSJoao Martins return -ENOENT; 797c345104cSJoao Martins } 798c345104cSJoao Martins 799c345104cSJoao Martins if (kvm_copy_from_gva(cs, arg, &rvi, sizeof(rvi))) { 800c345104cSJoao Martins return -EFAULT; 801c345104cSJoao Martins } 802c345104cSJoao Martins 803c345104cSJoao Martins if (rvi.offset > TARGET_PAGE_SIZE - sizeof(struct vcpu_info)) { 804c345104cSJoao Martins return -EINVAL; 805c345104cSJoao Martins } 806c345104cSJoao Martins 807c345104cSJoao Martins gpa = ((rvi.mfn << TARGET_PAGE_BITS) + rvi.offset); 808c345104cSJoao Martins async_run_on_cpu(target, do_set_vcpu_info_gpa, RUN_ON_CPU_HOST_ULONG(gpa)); 809c345104cSJoao Martins return 0; 810c345104cSJoao Martins } 811c345104cSJoao Martins 812f0689302SJoao Martins static int vcpuop_register_vcpu_time_info(CPUState *cs, CPUState *target, 813f0689302SJoao Martins uint64_t arg) 814f0689302SJoao Martins { 815f0689302SJoao Martins struct vcpu_register_time_memory_area tma; 816f0689302SJoao Martins uint64_t gpa; 817f0689302SJoao Martins size_t len; 818f0689302SJoao Martins 819f0689302SJoao Martins /* No need for 32/64 compat handling */ 820f0689302SJoao Martins qemu_build_assert(sizeof(tma) == 8); 821f0689302SJoao Martins qemu_build_assert(sizeof(struct vcpu_time_info) == 32); 822f0689302SJoao Martins 823f0689302SJoao Martins if (!target) { 824f0689302SJoao Martins return -ENOENT; 825f0689302SJoao Martins } 826f0689302SJoao Martins 827f0689302SJoao Martins if (kvm_copy_from_gva(cs, arg, &tma, sizeof(tma))) { 828f0689302SJoao Martins return -EFAULT; 829f0689302SJoao Martins } 830f0689302SJoao Martins 831f0689302SJoao Martins /* 832f0689302SJoao Martins * Xen actually uses the GVA and does the translation through the guest 833f0689302SJoao Martins * page tables each time. But Linux/KVM uses the GPA, on the assumption 834f0689302SJoao Martins * that guests only ever use *global* addresses (kernel virtual addresses) 835f0689302SJoao Martins * for it. If Linux is changed to redo the GVA→GPA translation each time, 836f0689302SJoao Martins * it will offer a new vCPU attribute for that, and we'll use it instead. 837f0689302SJoao Martins */ 838f0689302SJoao Martins if (!kvm_gva_to_gpa(cs, tma.addr.p, &gpa, &len, false) || 839f0689302SJoao Martins len < sizeof(struct vcpu_time_info)) { 840f0689302SJoao Martins return -EFAULT; 841f0689302SJoao Martins } 842f0689302SJoao Martins 843f0689302SJoao Martins async_run_on_cpu(target, do_set_vcpu_time_info_gpa, 844f0689302SJoao Martins RUN_ON_CPU_HOST_ULONG(gpa)); 845f0689302SJoao Martins return 0; 846f0689302SJoao Martins } 847f0689302SJoao Martins 8485092db87SJoao Martins static int vcpuop_register_runstate_info(CPUState *cs, CPUState *target, 8495092db87SJoao Martins uint64_t arg) 8505092db87SJoao Martins { 8515092db87SJoao Martins struct vcpu_register_runstate_memory_area rma; 8525092db87SJoao Martins uint64_t gpa; 8535092db87SJoao Martins size_t len; 8545092db87SJoao Martins 8555092db87SJoao Martins /* No need for 32/64 compat handling */ 8565092db87SJoao Martins qemu_build_assert(sizeof(rma) == 8); 8575092db87SJoao Martins /* The runstate area actually does change size, but Linux copes. */ 8585092db87SJoao Martins 8595092db87SJoao Martins if (!target) { 8605092db87SJoao Martins return -ENOENT; 8615092db87SJoao Martins } 8625092db87SJoao Martins 8635092db87SJoao Martins if (kvm_copy_from_gva(cs, arg, &rma, sizeof(rma))) { 8645092db87SJoao Martins return -EFAULT; 8655092db87SJoao Martins } 8665092db87SJoao Martins 8675092db87SJoao Martins /* As with vcpu_time_info, Xen actually uses the GVA but KVM doesn't. */ 8685092db87SJoao Martins if (!kvm_gva_to_gpa(cs, rma.addr.p, &gpa, &len, false)) { 8695092db87SJoao Martins return -EFAULT; 8705092db87SJoao Martins } 8715092db87SJoao Martins 8725092db87SJoao Martins async_run_on_cpu(target, do_set_vcpu_runstate_gpa, 8735092db87SJoao Martins RUN_ON_CPU_HOST_ULONG(gpa)); 8745092db87SJoao Martins return 0; 8755092db87SJoao Martins } 8765092db87SJoao Martins 877d70bd6a4SJoao Martins static bool kvm_xen_hcall_vcpu_op(struct kvm_xen_exit *exit, X86CPU *cpu, 878d70bd6a4SJoao Martins int cmd, int vcpu_id, uint64_t arg) 879d70bd6a4SJoao Martins { 880c345104cSJoao Martins CPUState *dest = qemu_get_cpu(vcpu_id); 881c345104cSJoao Martins CPUState *cs = CPU(cpu); 882d70bd6a4SJoao Martins int err; 883d70bd6a4SJoao Martins 884d70bd6a4SJoao Martins switch (cmd) { 8855092db87SJoao Martins case VCPUOP_register_runstate_memory_area: 8865092db87SJoao Martins err = vcpuop_register_runstate_info(cs, dest, arg); 8875092db87SJoao Martins break; 888f0689302SJoao Martins case VCPUOP_register_vcpu_time_memory_area: 889f0689302SJoao Martins err = vcpuop_register_vcpu_time_info(cs, dest, arg); 890f0689302SJoao Martins break; 891d70bd6a4SJoao Martins case VCPUOP_register_vcpu_info: 892c345104cSJoao Martins err = vcpuop_register_vcpu_info(cs, dest, arg); 893d70bd6a4SJoao Martins break; 894d70bd6a4SJoao Martins 895d70bd6a4SJoao Martins default: 896d70bd6a4SJoao Martins return false; 897d70bd6a4SJoao Martins } 898d70bd6a4SJoao Martins 899d70bd6a4SJoao Martins exit->u.hcall.result = err; 900d70bd6a4SJoao Martins return true; 901d70bd6a4SJoao Martins } 902d70bd6a4SJoao Martins 9034858ba20SDavid Woodhouse static bool kvm_xen_hcall_evtchn_op(struct kvm_xen_exit *exit, X86CPU *cpu, 9043b06f29bSJoao Martins int cmd, uint64_t arg) 9053b06f29bSJoao Martins { 9064858ba20SDavid Woodhouse CPUState *cs = CPU(cpu); 9073b06f29bSJoao Martins int err = -ENOSYS; 9083b06f29bSJoao Martins 9093b06f29bSJoao Martins switch (cmd) { 9103b06f29bSJoao Martins case EVTCHNOP_init_control: 9113b06f29bSJoao Martins case EVTCHNOP_expand_array: 9123b06f29bSJoao Martins case EVTCHNOP_set_priority: 9133b06f29bSJoao Martins /* We do not support FIFO channels at this point */ 9143b06f29bSJoao Martins err = -ENOSYS; 9153b06f29bSJoao Martins break; 9163b06f29bSJoao Martins 9174858ba20SDavid Woodhouse case EVTCHNOP_status: { 9184858ba20SDavid Woodhouse struct evtchn_status status; 9194858ba20SDavid Woodhouse 9204858ba20SDavid Woodhouse qemu_build_assert(sizeof(status) == 24); 9214858ba20SDavid Woodhouse if (kvm_copy_from_gva(cs, arg, &status, sizeof(status))) { 9224858ba20SDavid Woodhouse err = -EFAULT; 9234858ba20SDavid Woodhouse break; 9244858ba20SDavid Woodhouse } 9254858ba20SDavid Woodhouse 9264858ba20SDavid Woodhouse err = xen_evtchn_status_op(&status); 9274858ba20SDavid Woodhouse if (!err && kvm_copy_to_gva(cs, arg, &status, sizeof(status))) { 9284858ba20SDavid Woodhouse err = -EFAULT; 9294858ba20SDavid Woodhouse } 9304858ba20SDavid Woodhouse break; 9314858ba20SDavid Woodhouse } 93283eb5811SDavid Woodhouse case EVTCHNOP_close: { 93383eb5811SDavid Woodhouse struct evtchn_close close; 93483eb5811SDavid Woodhouse 93583eb5811SDavid Woodhouse qemu_build_assert(sizeof(close) == 4); 93683eb5811SDavid Woodhouse if (kvm_copy_from_gva(cs, arg, &close, sizeof(close))) { 93783eb5811SDavid Woodhouse err = -EFAULT; 93883eb5811SDavid Woodhouse break; 93983eb5811SDavid Woodhouse } 94083eb5811SDavid Woodhouse 94183eb5811SDavid Woodhouse err = xen_evtchn_close_op(&close); 94283eb5811SDavid Woodhouse break; 94383eb5811SDavid Woodhouse } 944190cc3c0SDavid Woodhouse case EVTCHNOP_unmask: { 945190cc3c0SDavid Woodhouse struct evtchn_unmask unmask; 946190cc3c0SDavid Woodhouse 947190cc3c0SDavid Woodhouse qemu_build_assert(sizeof(unmask) == 4); 948190cc3c0SDavid Woodhouse if (kvm_copy_from_gva(cs, arg, &unmask, sizeof(unmask))) { 949190cc3c0SDavid Woodhouse err = -EFAULT; 950190cc3c0SDavid Woodhouse break; 951190cc3c0SDavid Woodhouse } 952190cc3c0SDavid Woodhouse 953190cc3c0SDavid Woodhouse err = xen_evtchn_unmask_op(&unmask); 954190cc3c0SDavid Woodhouse break; 955190cc3c0SDavid Woodhouse } 956c723d4c1SDavid Woodhouse case EVTCHNOP_bind_virq: { 957c723d4c1SDavid Woodhouse struct evtchn_bind_virq virq; 958c723d4c1SDavid Woodhouse 959c723d4c1SDavid Woodhouse qemu_build_assert(sizeof(virq) == 12); 960c723d4c1SDavid Woodhouse if (kvm_copy_from_gva(cs, arg, &virq, sizeof(virq))) { 961c723d4c1SDavid Woodhouse err = -EFAULT; 962c723d4c1SDavid Woodhouse break; 963c723d4c1SDavid Woodhouse } 964c723d4c1SDavid Woodhouse 965c723d4c1SDavid Woodhouse err = xen_evtchn_bind_virq_op(&virq); 966c723d4c1SDavid Woodhouse if (!err && kvm_copy_to_gva(cs, arg, &virq, sizeof(virq))) { 967c723d4c1SDavid Woodhouse err = -EFAULT; 968c723d4c1SDavid Woodhouse } 969c723d4c1SDavid Woodhouse break; 970c723d4c1SDavid Woodhouse } 971f5417856SDavid Woodhouse case EVTCHNOP_bind_ipi: { 972f5417856SDavid Woodhouse struct evtchn_bind_ipi ipi; 973f5417856SDavid Woodhouse 974f5417856SDavid Woodhouse qemu_build_assert(sizeof(ipi) == 8); 975f5417856SDavid Woodhouse if (kvm_copy_from_gva(cs, arg, &ipi, sizeof(ipi))) { 976f5417856SDavid Woodhouse err = -EFAULT; 977f5417856SDavid Woodhouse break; 978f5417856SDavid Woodhouse } 979f5417856SDavid Woodhouse 980f5417856SDavid Woodhouse err = xen_evtchn_bind_ipi_op(&ipi); 981f5417856SDavid Woodhouse if (!err && kvm_copy_to_gva(cs, arg, &ipi, sizeof(ipi))) { 982f5417856SDavid Woodhouse err = -EFAULT; 983f5417856SDavid Woodhouse } 984f5417856SDavid Woodhouse break; 985f5417856SDavid Woodhouse } 986cf7679abSDavid Woodhouse case EVTCHNOP_send: { 987cf7679abSDavid Woodhouse struct evtchn_send send; 988cf7679abSDavid Woodhouse 989cf7679abSDavid Woodhouse qemu_build_assert(sizeof(send) == 4); 990cf7679abSDavid Woodhouse if (kvm_copy_from_gva(cs, arg, &send, sizeof(send))) { 991cf7679abSDavid Woodhouse err = -EFAULT; 992cf7679abSDavid Woodhouse break; 993cf7679abSDavid Woodhouse } 994cf7679abSDavid Woodhouse 995cf7679abSDavid Woodhouse err = xen_evtchn_send_op(&send); 996cf7679abSDavid Woodhouse break; 997cf7679abSDavid Woodhouse } 998e1db61b8SDavid Woodhouse case EVTCHNOP_alloc_unbound: { 999e1db61b8SDavid Woodhouse struct evtchn_alloc_unbound alloc; 1000e1db61b8SDavid Woodhouse 1001e1db61b8SDavid Woodhouse qemu_build_assert(sizeof(alloc) == 8); 1002e1db61b8SDavid Woodhouse if (kvm_copy_from_gva(cs, arg, &alloc, sizeof(alloc))) { 1003e1db61b8SDavid Woodhouse err = -EFAULT; 1004e1db61b8SDavid Woodhouse break; 1005e1db61b8SDavid Woodhouse } 1006e1db61b8SDavid Woodhouse 1007e1db61b8SDavid Woodhouse err = xen_evtchn_alloc_unbound_op(&alloc); 1008e1db61b8SDavid Woodhouse if (!err && kvm_copy_to_gva(cs, arg, &alloc, sizeof(alloc))) { 1009e1db61b8SDavid Woodhouse err = -EFAULT; 1010e1db61b8SDavid Woodhouse } 1011e1db61b8SDavid Woodhouse break; 1012e1db61b8SDavid Woodhouse } 101384327881SDavid Woodhouse case EVTCHNOP_bind_interdomain: { 101484327881SDavid Woodhouse struct evtchn_bind_interdomain interdomain; 101584327881SDavid Woodhouse 101684327881SDavid Woodhouse qemu_build_assert(sizeof(interdomain) == 12); 101784327881SDavid Woodhouse if (kvm_copy_from_gva(cs, arg, &interdomain, sizeof(interdomain))) { 101884327881SDavid Woodhouse err = -EFAULT; 101984327881SDavid Woodhouse break; 102084327881SDavid Woodhouse } 102184327881SDavid Woodhouse 102284327881SDavid Woodhouse err = xen_evtchn_bind_interdomain_op(&interdomain); 102384327881SDavid Woodhouse if (!err && 102484327881SDavid Woodhouse kvm_copy_to_gva(cs, arg, &interdomain, sizeof(interdomain))) { 102584327881SDavid Woodhouse err = -EFAULT; 102684327881SDavid Woodhouse } 102784327881SDavid Woodhouse break; 102884327881SDavid Woodhouse } 102930667046SDavid Woodhouse case EVTCHNOP_bind_vcpu: { 103030667046SDavid Woodhouse struct evtchn_bind_vcpu vcpu; 103130667046SDavid Woodhouse 103230667046SDavid Woodhouse qemu_build_assert(sizeof(vcpu) == 8); 103330667046SDavid Woodhouse if (kvm_copy_from_gva(cs, arg, &vcpu, sizeof(vcpu))) { 103430667046SDavid Woodhouse err = -EFAULT; 103530667046SDavid Woodhouse break; 103630667046SDavid Woodhouse } 103730667046SDavid Woodhouse 103830667046SDavid Woodhouse err = xen_evtchn_bind_vcpu_op(&vcpu); 103930667046SDavid Woodhouse break; 104030667046SDavid Woodhouse } 1041a15b1097SDavid Woodhouse case EVTCHNOP_reset: { 1042a15b1097SDavid Woodhouse struct evtchn_reset reset; 1043a15b1097SDavid Woodhouse 1044a15b1097SDavid Woodhouse qemu_build_assert(sizeof(reset) == 2); 1045a15b1097SDavid Woodhouse if (kvm_copy_from_gva(cs, arg, &reset, sizeof(reset))) { 1046a15b1097SDavid Woodhouse err = -EFAULT; 1047a15b1097SDavid Woodhouse break; 1048a15b1097SDavid Woodhouse } 1049a15b1097SDavid Woodhouse 1050a15b1097SDavid Woodhouse err = xen_evtchn_reset_op(&reset); 1051a15b1097SDavid Woodhouse break; 1052a15b1097SDavid Woodhouse } 10533b06f29bSJoao Martins default: 10543b06f29bSJoao Martins return false; 10553b06f29bSJoao Martins } 10563b06f29bSJoao Martins 10573b06f29bSJoao Martins exit->u.hcall.result = err; 10583b06f29bSJoao Martins return true; 10593b06f29bSJoao Martins } 10603b06f29bSJoao Martins 106179b7067dSJoao Martins int kvm_xen_soft_reset(void) 106279b7067dSJoao Martins { 1063c345104cSJoao Martins CPUState *cpu; 1064fb0fd2ceSJoao Martins int err; 1065fb0fd2ceSJoao Martins 106679b7067dSJoao Martins assert(qemu_mutex_iothread_locked()); 106779b7067dSJoao Martins 106879b7067dSJoao Martins trace_kvm_xen_soft_reset(); 106979b7067dSJoao Martins 1070a15b1097SDavid Woodhouse err = xen_evtchn_soft_reset(); 1071a15b1097SDavid Woodhouse if (err) { 1072a15b1097SDavid Woodhouse return err; 1073a15b1097SDavid Woodhouse } 1074a15b1097SDavid Woodhouse 107591cce756SDavid Woodhouse /* 107691cce756SDavid Woodhouse * Zero is the reset/startup state for HVM_PARAM_CALLBACK_IRQ. Strictly, 107791cce756SDavid Woodhouse * it maps to HVM_PARAM_CALLBACK_TYPE_GSI with GSI#0, but Xen refuses to 107891cce756SDavid Woodhouse * to deliver to the timer interrupt and treats that as 'disabled'. 107991cce756SDavid Woodhouse */ 108091cce756SDavid Woodhouse err = xen_evtchn_set_callback_param(0); 108191cce756SDavid Woodhouse if (err) { 108291cce756SDavid Woodhouse return err; 108391cce756SDavid Woodhouse } 108491cce756SDavid Woodhouse 1085c345104cSJoao Martins CPU_FOREACH(cpu) { 1086c345104cSJoao Martins async_run_on_cpu(cpu, do_vcpu_soft_reset, RUN_ON_CPU_NULL); 1087c345104cSJoao Martins } 1088c345104cSJoao Martins 1089fb0fd2ceSJoao Martins err = xen_overlay_map_shinfo_page(INVALID_GFN); 1090fb0fd2ceSJoao Martins if (err) { 1091fb0fd2ceSJoao Martins return err; 1092fb0fd2ceSJoao Martins } 1093fb0fd2ceSJoao Martins 109479b7067dSJoao Martins return 0; 109579b7067dSJoao Martins } 109679b7067dSJoao Martins 109779b7067dSJoao Martins static int schedop_shutdown(CPUState *cs, uint64_t arg) 109879b7067dSJoao Martins { 109979b7067dSJoao Martins struct sched_shutdown shutdown; 110079b7067dSJoao Martins int ret = 0; 110179b7067dSJoao Martins 110279b7067dSJoao Martins /* No need for 32/64 compat handling */ 110379b7067dSJoao Martins qemu_build_assert(sizeof(shutdown) == 4); 110479b7067dSJoao Martins 110579b7067dSJoao Martins if (kvm_copy_from_gva(cs, arg, &shutdown, sizeof(shutdown))) { 110679b7067dSJoao Martins return -EFAULT; 110779b7067dSJoao Martins } 110879b7067dSJoao Martins 110979b7067dSJoao Martins switch (shutdown.reason) { 111079b7067dSJoao Martins case SHUTDOWN_crash: 111179b7067dSJoao Martins cpu_dump_state(cs, stderr, CPU_DUMP_CODE); 111279b7067dSJoao Martins qemu_system_guest_panicked(NULL); 111379b7067dSJoao Martins break; 111479b7067dSJoao Martins 111579b7067dSJoao Martins case SHUTDOWN_reboot: 111679b7067dSJoao Martins qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); 111779b7067dSJoao Martins break; 111879b7067dSJoao Martins 111979b7067dSJoao Martins case SHUTDOWN_poweroff: 112079b7067dSJoao Martins qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); 112179b7067dSJoao Martins break; 112279b7067dSJoao Martins 112379b7067dSJoao Martins case SHUTDOWN_soft_reset: 112479b7067dSJoao Martins qemu_mutex_lock_iothread(); 112579b7067dSJoao Martins ret = kvm_xen_soft_reset(); 112679b7067dSJoao Martins qemu_mutex_unlock_iothread(); 112779b7067dSJoao Martins break; 112879b7067dSJoao Martins 112979b7067dSJoao Martins default: 113079b7067dSJoao Martins ret = -EINVAL; 113179b7067dSJoao Martins break; 113279b7067dSJoao Martins } 113379b7067dSJoao Martins 113479b7067dSJoao Martins return ret; 113579b7067dSJoao Martins } 113679b7067dSJoao Martins 113779b7067dSJoao Martins static bool kvm_xen_hcall_sched_op(struct kvm_xen_exit *exit, X86CPU *cpu, 113879b7067dSJoao Martins int cmd, uint64_t arg) 113979b7067dSJoao Martins { 114079b7067dSJoao Martins CPUState *cs = CPU(cpu); 114179b7067dSJoao Martins int err = -ENOSYS; 114279b7067dSJoao Martins 114379b7067dSJoao Martins switch (cmd) { 114479b7067dSJoao Martins case SCHEDOP_shutdown: 114579b7067dSJoao Martins err = schedop_shutdown(cs, arg); 114679b7067dSJoao Martins break; 114779b7067dSJoao Martins 1148c789b9efSDavid Woodhouse case SCHEDOP_poll: 1149c789b9efSDavid Woodhouse /* 1150c789b9efSDavid Woodhouse * Linux will panic if this doesn't work. Just yield; it's not 1151c789b9efSDavid Woodhouse * worth overthinking it because with event channel handling 1152c789b9efSDavid Woodhouse * in KVM, the kernel will intercept this and it will never 1153c789b9efSDavid Woodhouse * reach QEMU anyway. The semantics of the hypercall explicltly 1154c789b9efSDavid Woodhouse * permit spurious wakeups. 1155c789b9efSDavid Woodhouse */ 1156c789b9efSDavid Woodhouse case SCHEDOP_yield: 1157c789b9efSDavid Woodhouse sched_yield(); 1158c789b9efSDavid Woodhouse err = 0; 1159c789b9efSDavid Woodhouse break; 1160c789b9efSDavid Woodhouse 116179b7067dSJoao Martins default: 116279b7067dSJoao Martins return false; 116379b7067dSJoao Martins } 116479b7067dSJoao Martins 116579b7067dSJoao Martins exit->u.hcall.result = err; 116679b7067dSJoao Martins return true; 116779b7067dSJoao Martins } 116879b7067dSJoao Martins 116955a3f666SJoao Martins static bool do_kvm_xen_handle_exit(X86CPU *cpu, struct kvm_xen_exit *exit) 117055a3f666SJoao Martins { 117155a3f666SJoao Martins uint16_t code = exit->u.hcall.input; 117255a3f666SJoao Martins 117355a3f666SJoao Martins if (exit->u.hcall.cpl > 0) { 117455a3f666SJoao Martins exit->u.hcall.result = -EPERM; 117555a3f666SJoao Martins return true; 117655a3f666SJoao Martins } 117755a3f666SJoao Martins 117855a3f666SJoao Martins switch (code) { 117979b7067dSJoao Martins case __HYPERVISOR_sched_op: 118079b7067dSJoao Martins return kvm_xen_hcall_sched_op(exit, cpu, exit->u.hcall.params[0], 118179b7067dSJoao Martins exit->u.hcall.params[1]); 11823b06f29bSJoao Martins case __HYPERVISOR_event_channel_op: 11834858ba20SDavid Woodhouse return kvm_xen_hcall_evtchn_op(exit, cpu, exit->u.hcall.params[0], 11843b06f29bSJoao Martins exit->u.hcall.params[1]); 1185d70bd6a4SJoao Martins case __HYPERVISOR_vcpu_op: 1186d70bd6a4SJoao Martins return kvm_xen_hcall_vcpu_op(exit, cpu, 1187d70bd6a4SJoao Martins exit->u.hcall.params[0], 1188d70bd6a4SJoao Martins exit->u.hcall.params[1], 1189d70bd6a4SJoao Martins exit->u.hcall.params[2]); 1190671bfdcdSJoao Martins case __HYPERVISOR_hvm_op: 1191671bfdcdSJoao Martins return kvm_xen_hcall_hvm_op(exit, cpu, exit->u.hcall.params[0], 1192671bfdcdSJoao Martins exit->u.hcall.params[1]); 1193fb0fd2ceSJoao Martins case __HYPERVISOR_memory_op: 1194fb0fd2ceSJoao Martins return kvm_xen_hcall_memory_op(exit, cpu, exit->u.hcall.params[0], 1195fb0fd2ceSJoao Martins exit->u.hcall.params[1]); 1196bedcc139SJoao Martins case __HYPERVISOR_xen_version: 1197bedcc139SJoao Martins return kvm_xen_hcall_xen_version(exit, cpu, exit->u.hcall.params[0], 1198bedcc139SJoao Martins exit->u.hcall.params[1]); 119955a3f666SJoao Martins default: 120055a3f666SJoao Martins return false; 120155a3f666SJoao Martins } 120255a3f666SJoao Martins } 120355a3f666SJoao Martins 120455a3f666SJoao Martins int kvm_xen_handle_exit(X86CPU *cpu, struct kvm_xen_exit *exit) 120555a3f666SJoao Martins { 120655a3f666SJoao Martins if (exit->type != KVM_EXIT_XEN_HCALL) { 120755a3f666SJoao Martins return -1; 120855a3f666SJoao Martins } 120955a3f666SJoao Martins 1210110a0ea5SDavid Woodhouse /* 1211110a0ea5SDavid Woodhouse * The kernel latches the guest 32/64 mode when the MSR is used to fill 1212110a0ea5SDavid Woodhouse * the hypercall page. So if we see a hypercall in a mode that doesn't 1213110a0ea5SDavid Woodhouse * match our own idea of the guest mode, fetch the kernel's idea of the 1214110a0ea5SDavid Woodhouse * "long mode" to remain in sync. 1215110a0ea5SDavid Woodhouse */ 1216110a0ea5SDavid Woodhouse if (exit->u.hcall.longmode != xen_is_long_mode()) { 1217110a0ea5SDavid Woodhouse xen_sync_long_mode(); 1218110a0ea5SDavid Woodhouse } 1219110a0ea5SDavid Woodhouse 122055a3f666SJoao Martins if (!do_kvm_xen_handle_exit(cpu, exit)) { 122155a3f666SJoao Martins /* 122255a3f666SJoao Martins * Some hypercalls will be deliberately "implemented" by returning 122355a3f666SJoao Martins * -ENOSYS. This case is for hypercalls which are unexpected. 122455a3f666SJoao Martins */ 122555a3f666SJoao Martins exit->u.hcall.result = -ENOSYS; 122655a3f666SJoao Martins qemu_log_mask(LOG_UNIMP, "Unimplemented Xen hypercall %" 122755a3f666SJoao Martins PRId64 " (0x%" PRIx64 " 0x%" PRIx64 " 0x%" PRIx64 ")\n", 122855a3f666SJoao Martins (uint64_t)exit->u.hcall.input, 122955a3f666SJoao Martins (uint64_t)exit->u.hcall.params[0], 123055a3f666SJoao Martins (uint64_t)exit->u.hcall.params[1], 123155a3f666SJoao Martins (uint64_t)exit->u.hcall.params[2]); 123255a3f666SJoao Martins } 123355a3f666SJoao Martins 123455a3f666SJoao Martins trace_kvm_xen_hypercall(CPU(cpu)->cpu_index, exit->u.hcall.cpl, 123555a3f666SJoao Martins exit->u.hcall.input, exit->u.hcall.params[0], 123655a3f666SJoao Martins exit->u.hcall.params[1], exit->u.hcall.params[2], 123755a3f666SJoao Martins exit->u.hcall.result); 123855a3f666SJoao Martins return 0; 123955a3f666SJoao Martins } 1240c345104cSJoao Martins 1241c345104cSJoao Martins int kvm_put_xen_state(CPUState *cs) 1242c345104cSJoao Martins { 1243c345104cSJoao Martins X86CPU *cpu = X86_CPU(cs); 1244c345104cSJoao Martins CPUX86State *env = &cpu->env; 1245c345104cSJoao Martins uint64_t gpa; 1246c345104cSJoao Martins int ret; 1247c345104cSJoao Martins 1248c345104cSJoao Martins gpa = env->xen_vcpu_info_gpa; 1249c345104cSJoao Martins if (gpa == INVALID_GPA) { 1250c345104cSJoao Martins gpa = env->xen_vcpu_info_default_gpa; 1251c345104cSJoao Martins } 1252c345104cSJoao Martins 1253c345104cSJoao Martins if (gpa != INVALID_GPA) { 125427d4075dSDavid Woodhouse ret = set_vcpu_info(cs, gpa); 1255c345104cSJoao Martins if (ret < 0) { 1256c345104cSJoao Martins return ret; 1257c345104cSJoao Martins } 1258c345104cSJoao Martins } 1259c345104cSJoao Martins 1260f0689302SJoao Martins gpa = env->xen_vcpu_time_info_gpa; 1261f0689302SJoao Martins if (gpa != INVALID_GPA) { 1262f0689302SJoao Martins ret = kvm_xen_set_vcpu_attr(cs, KVM_XEN_VCPU_ATTR_TYPE_VCPU_TIME_INFO, 1263f0689302SJoao Martins gpa); 1264f0689302SJoao Martins if (ret < 0) { 1265f0689302SJoao Martins return ret; 1266f0689302SJoao Martins } 1267f0689302SJoao Martins } 1268f0689302SJoao Martins 12695092db87SJoao Martins gpa = env->xen_vcpu_runstate_gpa; 12705092db87SJoao Martins if (gpa != INVALID_GPA) { 12715092db87SJoao Martins ret = kvm_xen_set_vcpu_attr(cs, KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADDR, 12725092db87SJoao Martins gpa); 12735092db87SJoao Martins if (ret < 0) { 12745092db87SJoao Martins return ret; 12755092db87SJoao Martins } 12765092db87SJoao Martins } 12775092db87SJoao Martins 1278105b47fdSAnkur Arora if (!kvm_xen_has_cap(EVTCHN_SEND)) { 1279105b47fdSAnkur Arora return 0; 1280105b47fdSAnkur Arora } 1281105b47fdSAnkur Arora 1282105b47fdSAnkur Arora if (env->xen_vcpu_callback_vector) { 1283105b47fdSAnkur Arora ret = kvm_xen_set_vcpu_callback_vector(cs); 1284105b47fdSAnkur Arora if (ret < 0) { 1285105b47fdSAnkur Arora return ret; 1286105b47fdSAnkur Arora } 1287105b47fdSAnkur Arora } 1288105b47fdSAnkur Arora 1289c723d4c1SDavid Woodhouse if (env->xen_virq[VIRQ_TIMER]) { 1290c723d4c1SDavid Woodhouse ret = kvm_xen_set_vcpu_timer(cs); 1291c723d4c1SDavid Woodhouse if (ret < 0) { 1292c723d4c1SDavid Woodhouse return ret; 1293c723d4c1SDavid Woodhouse } 1294c723d4c1SDavid Woodhouse } 1295c345104cSJoao Martins return 0; 1296c345104cSJoao Martins } 1297c345104cSJoao Martins 1298c345104cSJoao Martins int kvm_get_xen_state(CPUState *cs) 1299c345104cSJoao Martins { 1300c345104cSJoao Martins X86CPU *cpu = X86_CPU(cs); 1301c345104cSJoao Martins CPUX86State *env = &cpu->env; 1302c345104cSJoao Martins uint64_t gpa; 1303c723d4c1SDavid Woodhouse int ret; 1304c345104cSJoao Martins 1305c345104cSJoao Martins /* 1306c345104cSJoao Martins * The kernel does not mark vcpu_info as dirty when it delivers interrupts 1307c345104cSJoao Martins * to it. It's up to userspace to *assume* that any page shared thus is 1308c345104cSJoao Martins * always considered dirty. The shared_info page is different since it's 1309c345104cSJoao Martins * an overlay and migrated separately anyway. 1310c345104cSJoao Martins */ 1311c345104cSJoao Martins gpa = env->xen_vcpu_info_gpa; 1312c345104cSJoao Martins if (gpa == INVALID_GPA) { 1313c345104cSJoao Martins gpa = env->xen_vcpu_info_default_gpa; 1314c345104cSJoao Martins } 1315c345104cSJoao Martins if (gpa != INVALID_GPA) { 1316c345104cSJoao Martins MemoryRegionSection mrs = memory_region_find(get_system_memory(), 1317c345104cSJoao Martins gpa, 1318c345104cSJoao Martins sizeof(struct vcpu_info)); 1319c345104cSJoao Martins if (mrs.mr && 1320c345104cSJoao Martins !int128_lt(mrs.size, int128_make64(sizeof(struct vcpu_info)))) { 1321c345104cSJoao Martins memory_region_set_dirty(mrs.mr, mrs.offset_within_region, 1322c345104cSJoao Martins sizeof(struct vcpu_info)); 1323c345104cSJoao Martins } 1324c345104cSJoao Martins } 1325c345104cSJoao Martins 1326c723d4c1SDavid Woodhouse if (!kvm_xen_has_cap(EVTCHN_SEND)) { 1327c723d4c1SDavid Woodhouse return 0; 1328c723d4c1SDavid Woodhouse } 1329c723d4c1SDavid Woodhouse 1330c723d4c1SDavid Woodhouse /* 1331c723d4c1SDavid Woodhouse * If the kernel is accelerating timers, read out the current value of the 1332c723d4c1SDavid Woodhouse * singleshot timer deadline. 1333c723d4c1SDavid Woodhouse */ 1334c723d4c1SDavid Woodhouse if (env->xen_virq[VIRQ_TIMER]) { 1335c723d4c1SDavid Woodhouse struct kvm_xen_vcpu_attr va = { 1336c723d4c1SDavid Woodhouse .type = KVM_XEN_VCPU_ATTR_TYPE_TIMER, 1337c723d4c1SDavid Woodhouse }; 1338c723d4c1SDavid Woodhouse ret = kvm_vcpu_ioctl(cs, KVM_XEN_VCPU_GET_ATTR, &va); 1339c723d4c1SDavid Woodhouse if (ret < 0) { 1340c723d4c1SDavid Woodhouse return ret; 1341c723d4c1SDavid Woodhouse } 1342c723d4c1SDavid Woodhouse env->xen_singleshot_timer_ns = va.u.timer.expires_ns; 1343c723d4c1SDavid Woodhouse } 1344c723d4c1SDavid Woodhouse 1345c345104cSJoao Martins return 0; 1346c345104cSJoao Martins } 1347