From 5b022dc99655b4f65bc170a2d1daa065878a5040 Mon Sep 17 00:00:00 2001 From: Joao Martins Date: Mon, 3 Sep 2018 14:38:03 -0400 Subject: [PATCH] i386/xen: handle PV IPI in hypervisor Uses XEN_EVENTFD ioctl to assign a eventfd to an ipi port and therefore notify the guest. This allows offloading PV IPIs to hypervisor instead of through Qemu. Signed-off-by: Joao Martins --- linux-headers/linux/kvm.h | 22 +++++++++++++++++++++ target/i386/trace-events | 1 + target/i386/xen_evtchn.c | 41 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+) diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index 364a15b9da..8a9a648c8c 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -1003,6 +1003,7 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_MANUAL_DIRTY_LOG_PROTECT 166 #define KVM_CAP_HYPERV_CPUID 167 #define KVM_CAP_XEN_HVM_GUEST 168 +#define KVM_CAP_XEN_HVM_EVTCHN 169 #ifdef KVM_CAP_IRQ_ROUTING @@ -1478,6 +1479,25 @@ struct kvm_xen_hvm_attr { __u32 vcpu; __u64 gpa; } vcpu_attr; + struct kvm_xen_eventfd { + +#define XEN_EVTCHN_TYPE_VIRQ 0 +#define XEN_EVTCHN_TYPE_IPI 1 + __u32 type; + __u32 port; + __u32 vcpu; + __s32 fd; + +#define KVM_XEN_EVENTFD_DEASSIGN (1 << 0) +#define KVM_XEN_EVENTFD_UPDATE (1 << 1) + __u32 flags; + union { + struct { + __u8 type; + } virq; + __u32 padding[2]; + }; + } evtchn; } u; }; @@ -1486,6 +1506,8 @@ struct kvm_xen_hvm_attr { #define KVM_XEN_ATTR_TYPE_VCPU_INFO 0x1 #define KVM_XEN_ATTR_TYPE_VCPU_TIME_INFO 0x2 #define KVM_XEN_ATTR_TYPE_VCPU_RUNSTATE 0x3 +/* Available with KVM_CAP_XEN_HVM_EVTCHN */ +#define KVM_XEN_ATTR_TYPE_EVTCHN 0x4 /* Secure Encrypted Virtualization command */ enum sev_cmd_id { diff --git a/target/i386/trace-events b/target/i386/trace-events index d2aaafeba9..f7c4779027 100644 --- a/target/i386/trace-events +++ b/target/i386/trace-events @@ -21,4 +21,5 @@ kvm_xen_hypercall(int cpu, uint64_t input, uint64_t a0, uint64_t a1, uint64_t a2 kvm_xen_set_shared_info(uint64_t gfn) "shared info at gfn 0x%" PRIx64 kvm_xen_set_vcpu_attr(int cpu, int type, uint64_t gpa) "vcpu attr cpu %d type %d gpa 0x%" PRIu64 kvm_xen_set_callback(int cpu, int virq, int vector, int via) "callback vcpu %d virq %d vector %d via %d" +kvm_xen_evtchn_set(int flags, unsigned int port, int port_type) "flags 0x%x port %u port_type %d" kvm_xen_evtchn_send(int cpu, int dest, unsigned int port) "cpu %d notify_cpu %d port %u" diff --git a/target/i386/xen_evtchn.c b/target/i386/xen_evtchn.c index 2187f38d7c..e058a9aba2 100644 --- a/target/i386/xen_evtchn.c +++ b/target/i386/xen_evtchn.c @@ -232,6 +232,44 @@ static void xen_vcpu_set_evtchn(CPUState *cpu, run_on_cpu_data data) xen_vcpu->virq_to_evtchn[evtchn->virq] = evtchn; } +static int __kvm_set_xen_event(KVMState *s, XenEvtChn *e, + EventNotifier *n, unsigned int flags) +{ + struct kvm_xen_eventfd xenevfd = { + .port = e->port, + .vcpu = e->notify_vcpu_id, + .type = e->type, + .fd = n ? event_notifier_get_fd(n) : -1, + .flags = flags, + }; + struct kvm_xen_hvm_attr xha; + int r; + + if (!kvm_check_extension(s, KVM_CAP_XEN_HVM_EVTCHN)) { + return -ENOSYS; + } + + if (e->type == XEN_EVTCHN_TYPE_VIRQ) { + xenevfd.virq.type = e->virq; + } + + xha.type = KVM_XEN_ATTR_TYPE_EVTCHN; + xha.u.evtchn = xenevfd; + r = kvm_vm_ioctl(s, KVM_XEN_HVM_SET_ATTR, &xha); + trace_kvm_xen_evtchn_set(flags, xenevfd.port, xenevfd.type); + return r; +} + +static int kvm_set_xen_event(KVMState *s, XenEvtChn *e, EventNotifier *n) +{ + return __kvm_set_xen_event(s, e, n, 0); +} + +static int kvm_clear_xen_event(KVMState *s, XenEvtChn *e) +{ + return __kvm_set_xen_event(s, e, NULL, KVM_XEN_EVENTFD_DEASSIGN); +} + int kvm_xen_evtchn_bind_ipi(X86CPU *cpu, void *arg) { struct evtchn_bind_ipi *out = arg; @@ -254,6 +292,8 @@ int kvm_xen_evtchn_bind_ipi(X86CPU *cpu, void *arg) evtchn->type = XEN_EVTCHN_TYPE_IPI; evtchn->notify_vcpu_id = bind_ipi.vcpu; + kvm_set_xen_event(dest->kvm_state, evtchn, NULL); + out->port = evtchn->port; return 0; @@ -308,6 +348,7 @@ int kvm_xen_evtchn_close(X86CPU *cpu, void *arg) } evtchn_2l_clear_pending(cpu, evtchn); + kvm_clear_xen_event(CPU(cpu)->kvm_state, evtchn); evtchn->state = XEN_EVTCHN_STATE_FREE; evtchn->notify_vcpu_id = 0; -- 2.50.1