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
3516This ioctl can be used to unregister the guest memory region registered3516This ioctl can be used to unregister the guest memory region registered
3517with KVM_MEMORY_ENCRYPT_REG_REGION ioctl above.3517with KVM_MEMORY_ENCRYPT_REG_REGION ioctl above.
3518 3518
35194.113 KVM_HYPERV_EVENTFD
3520
3521Capability: KVM_CAP_HYPERV_EVENTFD
3522Architectures: x86
3523Type: vm ioctl
3524Parameters: struct kvm_hyperv_eventfd (in)
3525
3526This ioctl (un)registers an eventfd to receive notifications from the guest on
3527the specified Hyper-V connection id through the SIGNAL_EVENT hypercall, without
3528causing 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
3531struct kvm_hyperv_eventfd {
3532 __u32 conn_id;
3533 __s32 fd;
3534 __u32 flags;
3535 __u32 padding[3];
3536};
3537
3538The conn_id field should fit within 24 bits:
3539
3540#define KVM_HYPERV_CONN_ID_MASK 0x00ffffff
3541
3542The acceptable values for the flags field are:
3543
3544#define KVM_HYPERV_EVENTFD_DEASSIGN (1 << 0)
3545
3546Returns: 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
3519 3551
35205. The kvm_run structure35525. The kvm_run structure
3521------------------------3553------------------------
arch/x86/include/asm/kvm_host.h+2−0
@@ -754,6 +754,8 @@ struct kvm_hv { · 753 unmodified lines
754 u64 hv_crash_ctl;754 u64 hv_crash_ctl;
755 755
756 HV_REFERENCE_TSC_PAGE tsc_ref;756 HV_REFERENCE_TSC_PAGE tsc_ref;
757
758 struct idr conn_to_evt;
757};759};
758 760
759enum kvm_irqchip_mode {761enum kvm_irqchip_mode {
arch/x86/include/uapi/asm/hyperv.h+2−0
@@ -303,7 +303,9 @@ enum HV_GENERIC_SET_FORMAT { · 302 unmodified lines
303#define HV_STATUS_INVALID_HYPERCALL_CODE 2303#define HV_STATUS_INVALID_HYPERCALL_CODE 2
304#define HV_STATUS_INVALID_HYPERCALL_INPUT 3304#define HV_STATUS_INVALID_HYPERCALL_INPUT 3
305#define HV_STATUS_INVALID_ALIGNMENT 4305#define HV_STATUS_INVALID_ALIGNMENT 4
306#define HV_STATUS_INVALID_PARAMETER 5
306#define HV_STATUS_INSUFFICIENT_MEMORY 11307#define HV_STATUS_INSUFFICIENT_MEMORY 11
308#define HV_STATUS_INVALID_PORT_ID 17
307#define HV_STATUS_INVALID_CONNECTION_ID 18309#define HV_STATUS_INVALID_CONNECTION_ID 18
308#define HV_STATUS_INSUFFICIENT_BUFFERS 19310#define HV_STATUS_INSUFFICIENT_BUFFERS 19
309 311
arch/x86/kvm/hyperv.c+102−1
@@ -29,6 +29,7 @@ · 28 unmodified lines
29#include <linux/kvm_host.h>29#include <linux/kvm_host.h>
30#include <linux/highmem.h>30#include <linux/highmem.h>
31#include <linux/sched/cputime.h>31#include <linux/sched/cputime.h>
32#include <linux/eventfd.h>
32 33
33#include <asm/apicdef.h>34#include <asm/apicdef.h>
34#include <trace/events/kvm.h>35#include <trace/events/kvm.h>
@@ -1226,6 +1227,43 @@ static int kvm_hv_hypercall_complete_userspace(struct kvm_vcpu *vcpu) · 1191 unmodified lines
1226 return 1;1227 return 1;
1227}1228}
1228 1229
1230static 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
1229int kvm_hv_hypercall(struct kvm_vcpu *vcpu)1267int kvm_hv_hypercall(struct kvm_vcpu *vcpu)
1230{1268{
1231 u64 param, ingpa, outgpa, ret;1269 u64 param, ingpa, outgpa, ret;
@@ -1276,8 +1314,12 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu) · 44 unmodified lines
1276 case HVCALL_NOTIFY_LONG_SPIN_WAIT:1314 case HVCALL_NOTIFY_LONG_SPIN_WAIT:
1277 kvm_vcpu_on_spin(vcpu, true);1315 kvm_vcpu_on_spin(vcpu, true);
1278 break;1316 break;
1279 case HVCALL_POST_MESSAGE:
1280 case HVCALL_SIGNAL_EVENT:1317 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:
1281 /* don't bother userspace if it has no way to handle it */1323 /* don't bother userspace if it has no way to handle it */
1282 if (!vcpu_to_synic(vcpu)->active) {1324 if (!vcpu_to_synic(vcpu)->active) {
1283 res = HV_STATUS_INVALID_HYPERCALL_CODE;1325 res = HV_STATUS_INVALID_HYPERCALL_CODE;
@@ -1305,8 +1347,67 @@ set_result: · 21 unmodified lines
1305void kvm_hv_init_vm(struct kvm *kvm)1347void kvm_hv_init_vm(struct kvm *kvm)
1306{1348{
1307 mutex_init(&kvm->arch.hyperv.hv_lock);1349 mutex_init(&kvm->arch.hyperv.hv_lock);
1350 idr_init(&kvm->arch.hyperv.conn_to_evt);
1308}1351}
1309 1352
1310void kvm_hv_destroy_vm(struct kvm *kvm)1353void kvm_hv_destroy_vm(struct kvm *kvm)
1311{1354{
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
1363static 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
1387static 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
1404int 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);
1312}1413}
arch/x86/kvm/hyperv.h+1−0
@@ -90,5 +90,6 @@ void kvm_hv_setup_tsc_page(struct kvm *kvm, · 89 unmodified lines
90 90
91void kvm_hv_init_vm(struct kvm *kvm);91void kvm_hv_init_vm(struct kvm *kvm);
92void kvm_hv_destroy_vm(struct kvm *kvm);92void kvm_hv_destroy_vm(struct kvm *kvm);
93int kvm_vm_ioctl_hv_eventfd(struct kvm *kvm, struct kvm_hyperv_eventfd *args);
93 94
94#endif95#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
2809 case KVM_CAP_HYPERV_SYNIC:2809 case KVM_CAP_HYPERV_SYNIC:
2810 case KVM_CAP_HYPERV_SYNIC2:2810 case KVM_CAP_HYPERV_SYNIC2:
2811 case KVM_CAP_HYPERV_VP_INDEX:2811 case KVM_CAP_HYPERV_VP_INDEX:
2812 case KVM_CAP_HYPERV_EVENTFD:
2812 case KVM_CAP_PCI_SEGMENT:2813 case KVM_CAP_PCI_SEGMENT:
2813 case KVM_CAP_DEBUGREGS:2814 case KVM_CAP_DEBUGREGS:
2814 case KVM_CAP_X86_ROBUST_SINGLESTEP:2815 case KVM_CAP_X86_ROBUST_SINGLESTEP:
@@ -4482,6 +4483,15 @@ set_identity_unlock: · 1667 unmodified lines
4482 r = kvm_x86_ops->mem_enc_unreg_region(kvm, &region);4483 r = kvm_x86_ops->mem_enc_unreg_region(kvm, &region);
4483 break;4484 break;
4484 }4485 }
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 }
4485 default:4495 default:
4486 r = -ENOTTY;4496 r = -ENOTTY;
4487 }4497 }
include/uapi/linux/kvm.h+15−0
@@ -936,6 +936,7 @@ struct kvm_ppc_resize_hpt { · 935 unmodified lines
936#define KVM_CAP_PPC_GET_CPU_CHAR 151936#define KVM_CAP_PPC_GET_CPU_CHAR 151
937#define KVM_CAP_S390_BPB 152937#define KVM_CAP_S390_BPB 152
938#define KVM_CAP_GET_MSR_FEATURES 153938#define KVM_CAP_GET_MSR_FEATURES 153
939#define KVM_CAP_HYPERV_EVENTFD 154
939 940
940#ifdef KVM_CAP_IRQ_ROUTING941#ifdef KVM_CAP_IRQ_ROUTING
941 942
@@ -1375,6 +1376,10 @@ struct kvm_enc_region { · 433 unmodified lines
1375#define KVM_MEMORY_ENCRYPT_REG_REGION _IOR(KVMIO, 0xbb, struct kvm_enc_region)1376#define KVM_MEMORY_ENCRYPT_REG_REGION _IOR(KVMIO, 0xbb, struct kvm_enc_region)
1376#define KVM_MEMORY_ENCRYPT_UNREG_REGION _IOR(KVMIO, 0xbc, struct kvm_enc_region)1377#define KVM_MEMORY_ENCRYPT_UNREG_REGION _IOR(KVMIO, 0xbc, struct kvm_enc_region)
1377 1378
1379/* Available with KVM_CAP_HYPERV_EVENTFD */
1380#define KVM_HYPERV_EVENTFD _IOW(KVMIO, 0xbd, struct kvm_hyperv_eventfd)
1381
1382
1378/* Secure Encrypted Virtualization command */1383/* Secure Encrypted Virtualization command */
1379enum sev_cmd_id {1384enum sev_cmd_id {
1380 /* Guest initialization commands */1385 /* Guest initialization commands */
@@ -1515,4 +1520,14 @@ struct kvm_assigned_msix_entry { · 134 unmodified lines
1515#define KVM_ARM_DEV_EL1_PTIMER (1 << 1)1520#define KVM_ARM_DEV_EL1_PTIMER (1 << 1)
1516#define KVM_ARM_DEV_PMU (1 << 2)1521#define KVM_ARM_DEV_PMU (1 << 2)
1517 1522
1523struct 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
1518#endif /* __LINUX_KVM_H */1533#endif /* __LINUX_KVM_H */