History

kvm: x86: hyperv: guest->host event signaling via eventfd

In Hyper-V, the fast guest->host notification mechanism is the SIGNAL_EVENT hypercall, with a single parameter of the connection ID to signal. Currently this hypercall incurs a user exit and requires the userspace to decode the parameters and trigger the notification of the potentially different I/O context. To avoid the costly user exit, process this hypercall and signal the corresponding eventfd in KVM, similar to ioeventfd. The association between the connection id and the eventfd is established via the newly introduced KVM_HYPERV_EVENTFD ioctl, and maintained in an (srcu-protected) IDR.

Roman Kagan committed 8 years ago

Commit faeb7831 parent cbc02367 files · +164 −1Browse files

Unified · Split

7 files
  1. Documentation/virtual/kvm/api.txt +32 −0
  2. arch/x86/include/asm/kvm_host.h +2 −0
  3. arch/x86/include/uapi/asm/hyperv.h +2 −0
  4. arch/x86/kvm/hyperv.c +102 −1
  5. arch/x86/kvm/hyperv.h +1 −0
  6. arch/x86/kvm/x86.c +10 −0
  7. include/uapi/linux/kvm.h +15 −0
Documentation/virtual/kvm/api.txt+32−0
@@ -3516,6 +3516,38 @@ Returns: 0 on success; -1 on error · 3515 unmodified lines
35163516 This ioctl can be used to unregister the guest memory region registered
35173517 with KVM_MEMORY_ENCRYPT_REG_REGION ioctl above.
35183518
3519+4.113 KVM_HYPERV_EVENTFD
3520+
3521+Capability: KVM_CAP_HYPERV_EVENTFD
3522+Architectures: x86
3523+Type: vm ioctl
3524+Parameters: struct kvm_hyperv_eventfd (in)
3525+
3526+This ioctl (un)registers an eventfd to receive notifications from the guest on
3527+the specified Hyper-V connection id through the SIGNAL_EVENT hypercall, without
3528+causing a user exit. SIGNAL_EVENT hypercall with non-zero event flag number
3529+(bits 24-31) still triggers a KVM_EXIT_HYPERV_HCALL user exit.
3530+
3531+struct kvm_hyperv_eventfd {
3532+ __u32 conn_id;
3533+ __s32 fd;
3534+ __u32 flags;
3535+ __u32 padding[3];
3536+};
3537+
3538+The conn_id field should fit within 24 bits:
3539+
3540+#define KVM_HYPERV_CONN_ID_MASK 0x00ffffff
3541+
3542+The acceptable values for the flags field are:
3543+
3544+#define KVM_HYPERV_EVENTFD_DEASSIGN (1 << 0)
3545+
3546+Returns: 0 on success,
3547+ -EINVAL if conn_id or flags is outside the allowed range
3548+ -ENOENT on deassign if the conn_id isn't registered
3549+ -EEXIST on assign if the conn_id is already registered
3550+
35193551
35203552 5. The kvm_run structure
35213553 ------------------------
arch/x86/include/asm/kvm_host.h+2−0
@@ -754,6 +754,8 @@ struct kvm_hv { · 753 unmodified lines
754754 u64 hv_crash_ctl;
755755
756756 HV_REFERENCE_TSC_PAGE tsc_ref;
757+
758+ struct idr conn_to_evt;
757759 };
758760
759761 enum kvm_irqchip_mode {
arch/x86/include/uapi/asm/hyperv.h+2−0
@@ -303,7 +303,9 @@ enum HV_GENERIC_SET_FORMAT { · 302 unmodified lines
303303 #define HV_STATUS_INVALID_HYPERCALL_CODE 2
304304 #define HV_STATUS_INVALID_HYPERCALL_INPUT 3
305305 #define HV_STATUS_INVALID_ALIGNMENT 4
306+#define HV_STATUS_INVALID_PARAMETER 5
306307 #define HV_STATUS_INSUFFICIENT_MEMORY 11
308+#define HV_STATUS_INVALID_PORT_ID 17
307309 #define HV_STATUS_INVALID_CONNECTION_ID 18
308310 #define HV_STATUS_INSUFFICIENT_BUFFERS 19
309311
arch/x86/kvm/hyperv.c+102−1
@@ -29,6 +29,7 @@ · 28 unmodified lines
2929 #include <linux/kvm_host.h>
3030 #include <linux/highmem.h>
3131 #include <linux/sched/cputime.h>
32+#include <linux/eventfd.h>
3233
3334 #include <asm/apicdef.h>
3435 #include <trace/events/kvm.h>
@@ -1226,6 +1227,43 @@ static int kvm_hv_hypercall_complete_userspace(struct kvm_vcpu *vcpu) · 1191 unmodified lines
12261227 return 1;
12271228 }
12281229
1230+static u16 kvm_hvcall_signal_event(struct kvm_vcpu *vcpu, bool fast, u64 param)
1231+{
1232+ struct eventfd_ctx *eventfd;
1233+
1234+ if (unlikely(!fast)) {
1235+ int ret;
1236+ gpa_t gpa = param;
1237+
1238+ if ((gpa & (__alignof__(param) - 1)) ||
1239+ offset_in_page(gpa) + sizeof(param) > PAGE_SIZE)
1240+ return HV_STATUS_INVALID_ALIGNMENT;
1241+
1242+ ret = kvm_vcpu_read_guest(vcpu, gpa, &param, sizeof(param));
1243+ if (ret < 0)
1244+ return HV_STATUS_INVALID_ALIGNMENT;
1245+ }
1246+
1247+ /*
1248+ * Per spec, bits 32-47 contain the extra "flag number". However, we
1249+ * have no use for it, and in all known usecases it is zero, so just
1250+ * report lookup failure if it isn't.
1251+ */
1252+ if (param & 0xffff00000000ULL)
1253+ return HV_STATUS_INVALID_PORT_ID;
1254+ /* remaining bits are reserved-zero */
1255+ if (param & ~KVM_HYPERV_CONN_ID_MASK)
1256+ return HV_STATUS_INVALID_HYPERCALL_INPUT;
1257+
1258+ /* conn_to_evt is protected by vcpu->kvm->srcu */
1259+ eventfd = idr_find(&vcpu->kvm->arch.hyperv.conn_to_evt, param);
1260+ if (!eventfd)
1261+ return HV_STATUS_INVALID_PORT_ID;
1262+
1263+ eventfd_signal(eventfd, 1);
1264+ return HV_STATUS_SUCCESS;
1265+}
1266+
12291267 int kvm_hv_hypercall(struct kvm_vcpu *vcpu)
12301268 {
12311269 u64 param, ingpa, outgpa, ret;
@@ -1276,8 +1314,12 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu) · 44 unmodified lines
12761314 case HVCALL_NOTIFY_LONG_SPIN_WAIT:
12771315 kvm_vcpu_on_spin(vcpu, true);
12781316 break;
1279− case HVCALL_POST_MESSAGE:
12801317 case HVCALL_SIGNAL_EVENT:
1318+ res = kvm_hvcall_signal_event(vcpu, fast, ingpa);
1319+ if (res != HV_STATUS_INVALID_PORT_ID)
1320+ break;
1321+ /* maybe userspace knows this conn_id: fall through */
1322+ case HVCALL_POST_MESSAGE:
12811323 /* don't bother userspace if it has no way to handle it */
12821324 if (!vcpu_to_synic(vcpu)->active) {
12831325 res = HV_STATUS_INVALID_HYPERCALL_CODE;
@@ -1305,8 +1347,67 @@ set_result: · 21 unmodified lines
13051347 void kvm_hv_init_vm(struct kvm *kvm)
13061348 {
13071349 mutex_init(&kvm->arch.hyperv.hv_lock);
1350+ idr_init(&kvm->arch.hyperv.conn_to_evt);
13081351 }
13091352
13101353 void kvm_hv_destroy_vm(struct kvm *kvm)
13111354 {
1355+ struct eventfd_ctx *eventfd;
1356+ int i;
1357+
1358+ idr_for_each_entry(&kvm->arch.hyperv.conn_to_evt, eventfd, i)
1359+ eventfd_ctx_put(eventfd);
1360+ idr_destroy(&kvm->arch.hyperv.conn_to_evt);
1361+}
1362+
1363+static int kvm_hv_eventfd_assign(struct kvm *kvm, u32 conn_id, int fd)
1364+{
1365+ struct kvm_hv *hv = &kvm->arch.hyperv;
1366+ struct eventfd_ctx *eventfd;
1367+ int ret;
1368+
1369+ eventfd = eventfd_ctx_fdget(fd);
1370+ if (IS_ERR(eventfd))
1371+ return PTR_ERR(eventfd);
1372+
1373+ mutex_lock(&hv->hv_lock);
1374+ ret = idr_alloc(&hv->conn_to_evt, eventfd, conn_id, conn_id + 1,
1375+ GFP_KERNEL);
1376+ mutex_unlock(&hv->hv_lock);
1377+
1378+ if (ret >= 0)
1379+ return 0;
1380+
1381+ if (ret == -ENOSPC)
1382+ ret = -EEXIST;
1383+ eventfd_ctx_put(eventfd);
1384+ return ret;
1385+}
1386+
1387+static int kvm_hv_eventfd_deassign(struct kvm *kvm, u32 conn_id)
1388+{
1389+ struct kvm_hv *hv = &kvm->arch.hyperv;
1390+ struct eventfd_ctx *eventfd;
1391+
1392+ mutex_lock(&hv->hv_lock);
1393+ eventfd = idr_remove(&hv->conn_to_evt, conn_id);
1394+ mutex_unlock(&hv->hv_lock);
1395+
1396+ if (!eventfd)
1397+ return -ENOENT;
1398+
1399+ synchronize_srcu(&kvm->srcu);
1400+ eventfd_ctx_put(eventfd);
1401+ return 0;
1402+}
1403+
1404+int kvm_vm_ioctl_hv_eventfd(struct kvm *kvm, struct kvm_hyperv_eventfd *args)
1405+{
1406+ if ((args->flags & ~KVM_HYPERV_EVENTFD_DEASSIGN) ||
1407+ (args->conn_id & ~KVM_HYPERV_CONN_ID_MASK))
1408+ return -EINVAL;
1409+
1410+ if (args->flags == KVM_HYPERV_EVENTFD_DEASSIGN)
1411+ return kvm_hv_eventfd_deassign(kvm, args->conn_id);
1412+ return kvm_hv_eventfd_assign(kvm, args->conn_id, args->fd);
13121413 }
arch/x86/kvm/hyperv.h+1−0
@@ -90,5 +90,6 @@ void kvm_hv_setup_tsc_page(struct kvm *kvm, · 89 unmodified lines
9090
9191 void kvm_hv_init_vm(struct kvm *kvm);
9292 void kvm_hv_destroy_vm(struct kvm *kvm);
93+int kvm_vm_ioctl_hv_eventfd(struct kvm *kvm, struct kvm_hyperv_eventfd *args);
9394
9495 #endif
arch/x86/kvm/x86.c+10−0
@@ -2809,6 +2809,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) · 2808 unmodified lines
28092809 case KVM_CAP_HYPERV_SYNIC:
28102810 case KVM_CAP_HYPERV_SYNIC2:
28112811 case KVM_CAP_HYPERV_VP_INDEX:
2812+ case KVM_CAP_HYPERV_EVENTFD:
28122813 case KVM_CAP_PCI_SEGMENT:
28132814 case KVM_CAP_DEBUGREGS:
28142815 case KVM_CAP_X86_ROBUST_SINGLESTEP:
@@ -4482,6 +4483,15 @@ set_identity_unlock: · 1667 unmodified lines
44824483 r = kvm_x86_ops->mem_enc_unreg_region(kvm, &region);
44834484 break;
44844485 }
4486+ case KVM_HYPERV_EVENTFD: {
4487+ struct kvm_hyperv_eventfd hvevfd;
4488+
4489+ r = -EFAULT;
4490+ if (copy_from_user(&hvevfd, argp, sizeof(hvevfd)))
4491+ goto out;
4492+ r = kvm_vm_ioctl_hv_eventfd(kvm, &hvevfd);
4493+ break;
4494+ }
44854495 default:
44864496 r = -ENOTTY;
44874497 }
include/uapi/linux/kvm.h+15−0
@@ -936,6 +936,7 @@ struct kvm_ppc_resize_hpt { · 935 unmodified lines
936936 #define KVM_CAP_PPC_GET_CPU_CHAR 151
937937 #define KVM_CAP_S390_BPB 152
938938 #define KVM_CAP_GET_MSR_FEATURES 153
939+#define KVM_CAP_HYPERV_EVENTFD 154
939940
940941 #ifdef KVM_CAP_IRQ_ROUTING
941942
@@ -1375,6 +1376,10 @@ struct kvm_enc_region { · 433 unmodified lines
13751376 #define KVM_MEMORY_ENCRYPT_REG_REGION _IOR(KVMIO, 0xbb, struct kvm_enc_region)
13761377 #define KVM_MEMORY_ENCRYPT_UNREG_REGION _IOR(KVMIO, 0xbc, struct kvm_enc_region)
13771378
1379+/* Available with KVM_CAP_HYPERV_EVENTFD */
1380+#define KVM_HYPERV_EVENTFD _IOW(KVMIO, 0xbd, struct kvm_hyperv_eventfd)
1381+
1382+
13781383 /* Secure Encrypted Virtualization command */
13791384 enum sev_cmd_id {
13801385 /* Guest initialization commands */
@@ -1515,4 +1520,14 @@ struct kvm_assigned_msix_entry { · 134 unmodified lines
15151520 #define KVM_ARM_DEV_EL1_PTIMER (1 << 1)
15161521 #define KVM_ARM_DEV_PMU (1 << 2)
15171522
1523+struct kvm_hyperv_eventfd {
1524+ __u32 conn_id;
1525+ __s32 fd;
1526+ __u32 flags;
1527+ __u32 padding[3];
1528+};
1529+
1530+#define KVM_HYPERV_CONN_ID_MASK 0x00ffffff
1531+#define KVM_HYPERV_EVENTFD_DEASSIGN (1 << 0)
1532+
15181533 #endif /* __LINUX_KVM_H */