]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
KVM: x86/xen: Support direct injection of event channel events
authorDavid Woodhouse <dwmw@amazon.co.uk>
Mon, 7 Feb 2022 14:15:31 +0000 (14:15 +0000)
committerDavid Woodhouse <dwmw@amazon.co.uk>
Thu, 24 Feb 2022 10:10:06 +0000 (10:10 +0000)
This adds a KVM_XEN_HVM_EVTCHN_SEND ioctl which allows direct injection
of events given an explicit { vcpu, port, priority } in precisely the
same form that those fields are given in the IRQ routing table.

Userspace is currently able to inject 2-level events purely by setting
the bits in the shared_info and vcpu_info, but FIFO event channels are
harder to deal with; we will need the kernel to take sole ownership of
delivery when we support those.

A patch advertising this feature with a new bit in the KVM_CAP_XEN_HVM
ioctl will be added in a subsequent patch.

Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
arch/x86/kvm/x86.c
arch/x86/kvm/xen.c
arch/x86/kvm/xen.h
include/uapi/linux/kvm.h

index 5a00b65f8da08d6cbbb5da1dc0e306a14e2cf079..1e19c54a63c1b20104a9c6f047ca74e4cc564d53 100644 (file)
@@ -6466,6 +6466,15 @@ set_pit2_out:
                r = kvm_xen_hvm_set_attr(kvm, &xha);
                break;
        }
+       case KVM_XEN_HVM_EVTCHN_SEND: {
+               struct kvm_irq_routing_xen_evtchn uxe;
+
+               r = -EFAULT;
+               if (copy_from_user(&uxe, argp, sizeof(uxe)))
+                       goto out;
+               r = kvm_xen_hvm_evtchn_send(kvm, &uxe);
+               break;
+       }
 #endif
        case KVM_SET_CLOCK:
                r = kvm_vm_ioctl_set_clock(kvm, argp);
index 9d1b04a8ddf046501f46749b436561a6029ace97..15ae237131d58b9c91fc89e42a06d1e831887e33 100644 (file)
@@ -1092,6 +1092,38 @@ int kvm_xen_setup_evtchn(struct kvm *kvm,
        return 0;
 }
 
+/*
+ * Explicit event sending from userspace with KVM_XEN_HVM_EVTCHN_SEND ioctl.
+ */
+int kvm_xen_hvm_evtchn_send(struct kvm *kvm, struct kvm_irq_routing_xen_evtchn *uxe)
+{
+       struct kvm_xen_evtchn e;
+       int ret;
+
+       if (!uxe->port || uxe->port >= max_evtchn_port(kvm))
+               return -EINVAL;
+
+       /* We only support 2 level event channels for now */
+       if (uxe->priority != KVM_IRQ_ROUTING_XEN_EVTCHN_PRIO_2LEVEL)
+               return -EINVAL;
+
+       e.port = uxe->port;
+       e.vcpu_id = uxe->vcpu;
+       e.vcpu_idx = -1;
+       e.priority = uxe->priority;
+
+       ret = kvm_xen_set_evtchn(&e, kvm);
+
+       /*
+        * None of that 'return 1 if it actually got delivered' nonsense.
+        * We don't care if it was masked (-ENOTCONN) either.
+        */
+       if (ret > 0 || ret == -ENOTCONN)
+               ret = 0;
+
+       return ret;
+}
+
 void kvm_xen_destroy_vcpu(struct kvm_vcpu *vcpu)
 {
        kvm_gfn_to_pfn_cache_destroy(vcpu->kvm,
index e28feb32add6414b6a9aaf6488a9008211e88383..852286de574e50b0798f4b498b89c79e817bd300 100644 (file)
@@ -20,6 +20,7 @@ int kvm_xen_vcpu_set_attr(struct kvm_vcpu *vcpu, struct kvm_xen_vcpu_attr *data)
 int kvm_xen_vcpu_get_attr(struct kvm_vcpu *vcpu, struct kvm_xen_vcpu_attr *data);
 int kvm_xen_hvm_set_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data);
 int kvm_xen_hvm_get_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data);
+int kvm_xen_hvm_evtchn_send(struct kvm *kvm, struct kvm_irq_routing_xen_evtchn *evt);
 int kvm_xen_write_hypercall_page(struct kvm_vcpu *vcpu, u64 data);
 int kvm_xen_hvm_config(struct kvm *kvm, struct kvm_xen_hvm_config *xhc);
 void kvm_xen_init_vm(struct kvm *kvm);
index 5191b57e156220bd7fc6d85940c301e16cc1645a..5b10e43e294cef505dd17bba778cda553827bef4 100644 (file)
@@ -1689,6 +1689,9 @@ struct kvm_xen_hvm_attr {
 #define KVM_XEN_VCPU_GET_ATTR  _IOWR(KVMIO, 0xca, struct kvm_xen_vcpu_attr)
 #define KVM_XEN_VCPU_SET_ATTR  _IOW(KVMIO,  0xcb, struct kvm_xen_vcpu_attr)
 
+/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_EVTCHN_SEND */
+#define KVM_XEN_HVM_EVTCHN_SEND        _IOW(KVMIO,  0xd0, struct kvm_irq_routing_xen_evtchn)
+
 #define KVM_GET_SREGS2             _IOR(KVMIO,  0xcc, struct kvm_sregs2)
 #define KVM_SET_SREGS2             _IOW(KVMIO,  0xcd, struct kvm_sregs2)