From: David Woodhouse <d...@amazon.co.uk> The kvm_xen_inject_vcpu_callback_vector() function will either deliver the per-vCPU local APIC vector (as an MSI), or just kick the vCPU out of the kernel to trigger KVM's automatic delivery of the global vector. Support for asserting the GSI/PCI_INTX callbacks will come later.
Also add kvm_xen_get_vcpu_info_hva() which returns the vcpu_info of a given vCPU. Signed-off-by: David Woodhouse <d...@amazon.co.uk> --- include/sysemu/kvm_xen.h | 2 ++ target/i386/kvm/xen-emu.c | 68 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/include/sysemu/kvm_xen.h b/include/sysemu/kvm_xen.h index 3e43cd7843..ee53294deb 100644 --- a/include/sysemu/kvm_xen.h +++ b/include/sysemu/kvm_xen.h @@ -17,6 +17,8 @@ #define INVALID_GFN UINT64_MAX uint32_t kvm_xen_get_caps(void); +void *kvm_xen_get_vcpu_info_hva(uint32_t vcpu_id); +void kvm_xen_inject_vcpu_callback_vector(uint32_t vcpu_id, int type); #define kvm_xen_has_cap(cap) (!!(kvm_xen_get_caps() & \ KVM_XEN_HVM_CONFIG_ ## cap)) diff --git a/target/i386/kvm/xen-emu.c b/target/i386/kvm/xen-emu.c index 87fcfc636c..11a6fe4164 100644 --- a/target/i386/kvm/xen-emu.c +++ b/target/i386/kvm/xen-emu.c @@ -22,6 +22,8 @@ #include "trace.h" #include "sysemu/runstate.h" +#include "hw/pci/msi.h" +#include "hw/i386/apic-msidef.h" #include "hw/i386/kvm/xen_overlay.h" #include "hw/i386/kvm/xen_evtchn.h" @@ -274,6 +276,72 @@ static void do_set_vcpu_info_gpa(CPUState *cs, run_on_cpu_data data) env->xen_vcpu_info_gpa); } +static void *gpa_to_hva(uint64_t gpa) +{ + MemoryRegionSection mrs; + + mrs = memory_region_find(get_system_memory(), gpa, 1); + return !mrs.mr ? NULL : qemu_map_ram_ptr(mrs.mr->ram_block, + mrs.offset_within_region); +} + +void *kvm_xen_get_vcpu_info_hva(uint32_t vcpu_id) +{ + CPUState *cs = qemu_get_cpu(vcpu_id); + CPUX86State *env; + uint64_t gpa; + + if (!cs) { + return NULL; + } + env = &X86_CPU(cs)->env; + + gpa = env->xen_vcpu_info_gpa; + if (gpa == INVALID_GPA) { + gpa = env->xen_vcpu_info_default_gpa; + } + if (gpa == INVALID_GPA) { + return NULL; + } + + return gpa_to_hva(gpa); +} + +void kvm_xen_inject_vcpu_callback_vector(uint32_t vcpu_id, int type) +{ + CPUState *cs = qemu_get_cpu(vcpu_id); + uint8_t vector; + + if (!cs) { + return; + } + + vector = X86_CPU(cs)->env.xen_vcpu_callback_vector; + if (vector) { + /* + * The per-vCPU callback vector injected via lapic. Just + * deliver it as an MSI. + */ + MSIMessage msg = { + .address = APIC_DEFAULT_ADDRESS | X86_CPU(cs)->apic_id, + .data = vector | (1UL << MSI_DATA_LEVEL_SHIFT), + }; + kvm_irqchip_send_msi(kvm_state, msg); + return; + } + + switch (type) { + case HVM_PARAM_CALLBACK_TYPE_VECTOR: + /* + * If the evtchn_upcall_pending field in the vcpu_info is set, then + * KVM will automatically deliver the vector on entering the vCPU + * so all we have to do is kick it out. + */ + qemu_cpu_kick(cs); + break; + } +} + static void do_set_vcpu_time_info_gpa(CPUState *cs, run_on_cpu_data data) { X86CPU *cpu = X86_CPU(cs); -- 2.35.3