]> 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>
Tue, 8 Feb 2022 10:06:49 +0000 (10:06 +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.

Also, for SCHEDOP_poll we need to wake a polling vCPU when a given port
is triggered, even when it's masked — and we want to implement that in
the kernel, for efficiency. So we want the kernel to know that it has
sole ownership of event channel delivery. Thus, we allow userspace to
make the 'promise' by setting the corresponding feature bit in its
KVM_XEN_HVM_CONFIG call. As we implement SCHEDOP_poll bypass later,
we will do so only if that promise has been made by userspace.

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

index a4267104db50a490b481729e282017e7f453754c..d6c7baf051753c9ebd2578b91dfdd0e0b42b084c 100644 (file)
@@ -988,12 +988,22 @@ memory.
        __u8 pad2[30];
   };
 
-If the KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL flag is returned from the
-KVM_CAP_XEN_HVM check, it may be set in the flags field of this ioctl.
-This requests KVM to generate the contents of the hypercall page
-automatically; hypercalls will be intercepted and passed to userspace
-through KVM_EXIT_XEN.  In this case, all of the blob size and address
-fields must be zero.
+If certain flags are returned from the KVM_CAP_XEN_HVM check, they may
+be set in the flags field of this ioctl:
+
+The KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL flag requests KVM to generate
+the contents of the hypercall page automatically; hypercalls will be
+intercepted and passed to userspace through KVM_EXIT_XEN.  In this
+ase, all of the blob size and address fields must be zero.
+
+The KVM_XEN_HVM_CONFIG_EVTCHN_SEND flag indicates to KVM that userspace
+will always use the KVM_XEN_HVM_EVTCHN_SEND to deliver event channel
+interrupts rather than manipulating the guest's shared_info structures
+directly. This, in turn, may allow KVM to enable features such as
+intercepting the SCHEDOP_poll hypercall to accelerate PV spinlock
+operation for the guest. Userspace may still use KVM_XEN_HVM_EVTCHN_SEND
+ioctl, if it was advertised, even if userspace does not send this
+indication that it will always do so.
 
 No other flags are currently valid in the struct kvm_xen_hvm_config.
 
@@ -5574,6 +5584,25 @@ enabled with ``arch_prctl()``, but this may change in the future.
 The offsets of the state save areas in struct kvm_xsave follow the contents
 of CPUID leaf 0xD on the host.
 
+4.135 KVM_XEN_HVM_EVTCHN_SEND
+-----------------------------
+
+:Capability: KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_EVTCHN_SEND
+:Architectures: x86
+:Type: vm ioctl
+:Parameters: struct kvm_irq_routing_xen_evtchn
+:Returns: 0 on success, < 0 on error
+
+
+::
+
+   struct kvm_irq_routing_xen_evtchn {
+       __u32 port;
+       __u32 vcpu;
+       __u32 priority;
+   };
+
+This ioctl injects an event channel interrupt directly to the guest vCPU.
 
 5. The kvm_run structure
 ========================
@@ -7472,8 +7501,9 @@ PVHVM guests. Valid flags are::
   #define KVM_XEN_HVM_CONFIG_HYPERCALL_MSR     (1 << 0)
   #define KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL   (1 << 1)
   #define KVM_XEN_HVM_CONFIG_SHARED_INFO       (1 << 2)
-  #define KVM_XEN_HVM_CONFIG_RUNSTATE          (1 << 2)
-  #define KVM_XEN_HVM_CONFIG_EVTCHN_2LEVEL     (1 << 3)
+  #define KVM_XEN_HVM_CONFIG_RUNSTATE          (1 << 3)
+  #define KVM_XEN_HVM_CONFIG_EVTCHN_2LEVEL     (1 << 4)
+  #define KVM_XEN_HVM_CONFIG_EVTCHN_SEND       (1 << 5)
 
 The KVM_XEN_HVM_CONFIG_HYPERCALL_MSR flag indicates that the KVM_XEN_HVM_CONFIG
 ioctl is available, for the guest to set its hypercall page.
@@ -7497,6 +7527,10 @@ The KVM_XEN_HVM_CONFIG_EVTCHN_2LEVEL flag indicates that IRQ routing entries
 of the type KVM_IRQ_ROUTING_XEN_EVTCHN are supported, with the priority
 field set to indicate 2 level event channel delivery.
 
+The KVM_XEN_HVM_CONFIG_EVTCHN_SEND flag indicates that KVM supports
+injecting event channel events directly into the guest with the
+KVM_XEN_HVM_EVTCHN_SEND ioctl.
+
 8.31 KVM_CAP_PPC_MULTITCE
 -------------------------
 
index 74b53a16f38a72062a123dd6ce04abd84a8c7264..2da4ff7c5e6f8244054cb187c3be42f475a2f478 100644 (file)
@@ -4243,7 +4243,8 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
                r = KVM_XEN_HVM_CONFIG_HYPERCALL_MSR |
                    KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL |
                    KVM_XEN_HVM_CONFIG_SHARED_INFO |
-                   KVM_XEN_HVM_CONFIG_EVTCHN_2LEVEL;
+                   KVM_XEN_HVM_CONFIG_EVTCHN_2LEVEL |
+                   KVM_XEN_HVM_CONFIG_EVTCHN_SEND;
                if (sched_info_on())
                        r |= KVM_XEN_HVM_CONFIG_RUNSTATE;
                break;
@@ -6449,6 +6450,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 635cbcd3eade8bb1817d9354d2f67a6b75467fd5..ba1ec7bb4da06a2ce70bba99888afbd00679f5ef 100644 (file)
@@ -740,7 +740,11 @@ 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)
 {
-       if (xhc->flags & ~KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL)
+       /* Only some feature flags need to be *enabled* by userspace */
+       u32 permitted_flags = KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL |
+               KVM_XEN_HVM_CONFIG_EVTCHN_SEND;
+
+       if (xhc->flags & ~permitted_flags)
                return -EINVAL;
 
        /*
@@ -1053,3 +1057,32 @@ int kvm_xen_setup_evtchn(struct kvm *kvm,
 
        return 0;
 }
+
+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;
+}
index 6656afda00d6745efd81bb414efd8127d94a1001..66a830e7d55af7bab1100259142fd8971b92abde 100644 (file)
@@ -19,6 +19,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 b46bcdb0cab1a3695f552434d34aff3f70b4c700..5beb7c49223dd23cb817b38f7c2c22d1650bd9bb 100644 (file)
@@ -1222,6 +1222,7 @@ struct kvm_x86_mce {
 #define KVM_XEN_HVM_CONFIG_SHARED_INFO         (1 << 2)
 #define KVM_XEN_HVM_CONFIG_RUNSTATE            (1 << 3)
 #define KVM_XEN_HVM_CONFIG_EVTCHN_2LEVEL       (1 << 4)
+#define KVM_XEN_HVM_CONFIG_EVTCHN_SEND         (1 << 5)
 
 struct kvm_xen_hvm_config {
        __u32 flags;
@@ -1692,6 +1693,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)