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" 1361491cf4SDavid Woodhouse #include "sysemu/kvm_int.h" 1461491cf4SDavid Woodhouse #include "sysemu/kvm_xen.h" 1561491cf4SDavid Woodhouse #include "kvm/kvm_i386.h" 1661491cf4SDavid Woodhouse #include "xen-emu.h" 1761491cf4SDavid Woodhouse 18f66b8a83SJoao Martins int kvm_xen_init(KVMState *s, uint32_t hypercall_msr) 1961491cf4SDavid Woodhouse { 2061491cf4SDavid Woodhouse const int required_caps = KVM_XEN_HVM_CONFIG_HYPERCALL_MSR | 2161491cf4SDavid Woodhouse KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL | KVM_XEN_HVM_CONFIG_SHARED_INFO; 2261491cf4SDavid Woodhouse struct kvm_xen_hvm_config cfg = { 23f66b8a83SJoao Martins .msr = hypercall_msr, 2461491cf4SDavid Woodhouse .flags = KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL, 2561491cf4SDavid Woodhouse }; 2661491cf4SDavid Woodhouse int xen_caps, ret; 2761491cf4SDavid Woodhouse 2861491cf4SDavid Woodhouse xen_caps = kvm_check_extension(s, KVM_CAP_XEN_HVM); 2961491cf4SDavid Woodhouse if (required_caps & ~xen_caps) { 3061491cf4SDavid Woodhouse error_report("kvm: Xen HVM guest support not present or insufficient"); 3161491cf4SDavid Woodhouse return -ENOSYS; 3261491cf4SDavid Woodhouse } 3361491cf4SDavid Woodhouse 3461491cf4SDavid Woodhouse if (xen_caps & KVM_XEN_HVM_CONFIG_EVTCHN_SEND) { 3561491cf4SDavid Woodhouse struct kvm_xen_hvm_attr ha = { 3661491cf4SDavid Woodhouse .type = KVM_XEN_ATTR_TYPE_XEN_VERSION, 3761491cf4SDavid Woodhouse .u.xen_version = s->xen_version, 3861491cf4SDavid Woodhouse }; 3961491cf4SDavid Woodhouse (void)kvm_vm_ioctl(s, KVM_XEN_HVM_SET_ATTR, &ha); 4061491cf4SDavid Woodhouse 4161491cf4SDavid Woodhouse cfg.flags |= KVM_XEN_HVM_CONFIG_EVTCHN_SEND; 4261491cf4SDavid Woodhouse } 4361491cf4SDavid Woodhouse 4461491cf4SDavid Woodhouse ret = kvm_vm_ioctl(s, KVM_XEN_HVM_CONFIG, &cfg); 4561491cf4SDavid Woodhouse if (ret < 0) { 4661491cf4SDavid Woodhouse error_report("kvm: Failed to enable Xen HVM support: %s", 4761491cf4SDavid Woodhouse strerror(-ret)); 4861491cf4SDavid Woodhouse return ret; 4961491cf4SDavid Woodhouse } 5061491cf4SDavid Woodhouse 5161491cf4SDavid Woodhouse s->xen_caps = xen_caps; 5261491cf4SDavid Woodhouse return 0; 5361491cf4SDavid Woodhouse } 5461491cf4SDavid Woodhouse 55*5e691a95SDavid Woodhouse int kvm_xen_init_vcpu(CPUState *cs) 56*5e691a95SDavid Woodhouse { 57*5e691a95SDavid Woodhouse int err; 58*5e691a95SDavid Woodhouse 59*5e691a95SDavid Woodhouse /* 60*5e691a95SDavid Woodhouse * The kernel needs to know the Xen/ACPI vCPU ID because that's 61*5e691a95SDavid Woodhouse * what the guest uses in hypercalls such as timers. It doesn't 62*5e691a95SDavid Woodhouse * match the APIC ID which is generally used for talking to the 63*5e691a95SDavid Woodhouse * kernel about vCPUs. And if vCPU threads race with creating 64*5e691a95SDavid Woodhouse * their KVM vCPUs out of order, it doesn't necessarily match 65*5e691a95SDavid Woodhouse * with the kernel's internal vCPU indices either. 66*5e691a95SDavid Woodhouse */ 67*5e691a95SDavid Woodhouse if (kvm_xen_has_cap(EVTCHN_SEND)) { 68*5e691a95SDavid Woodhouse struct kvm_xen_vcpu_attr va = { 69*5e691a95SDavid Woodhouse .type = KVM_XEN_VCPU_ATTR_TYPE_VCPU_ID, 70*5e691a95SDavid Woodhouse .u.vcpu_id = cs->cpu_index, 71*5e691a95SDavid Woodhouse }; 72*5e691a95SDavid Woodhouse err = kvm_vcpu_ioctl(cs, KVM_XEN_VCPU_SET_ATTR, &va); 73*5e691a95SDavid Woodhouse if (err) { 74*5e691a95SDavid Woodhouse error_report("kvm: Failed to set Xen vCPU ID attribute: %s", 75*5e691a95SDavid Woodhouse strerror(-err)); 76*5e691a95SDavid Woodhouse return err; 77*5e691a95SDavid Woodhouse } 78*5e691a95SDavid Woodhouse } 79*5e691a95SDavid Woodhouse 80*5e691a95SDavid Woodhouse return 0; 81*5e691a95SDavid Woodhouse } 82*5e691a95SDavid Woodhouse 8361491cf4SDavid Woodhouse uint32_t kvm_xen_get_caps(void) 8461491cf4SDavid Woodhouse { 8561491cf4SDavid Woodhouse return kvm_state->xen_caps; 8661491cf4SDavid Woodhouse } 87