@@ -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);
+bool 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))
@@ -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,75 @@ 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);
+}
+
+bool 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 false;
+ }
+
+ 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 true;
+ }
+
+ 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);
+ return true;
+ }
+
+ /* Not handled here. */
+ return false;
+}
+
static void do_set_vcpu_time_info_gpa(CPUState *cs, run_on_cpu_data data)
{
X86CPU *cpu = X86_CPU(cs);