Created
July 4, 2022 10:09
-
-
Save tmakatos/57755d2a37a6d53c9ff392e7c34470f6 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From fd6fe7ecca5ca14e0814bb7d49c41e9251c5c095 Mon Sep 17 00:00:00 2001 | |
From: Thanos Makatos <thanos.makatos@nutanix.com> | |
Date: Tue, 31 May 2022 09:41:48 -0400 | |
Subject: [PATCH] FIXME support for shadow ioeventfd | |
Signed-off-by: Thanos Makatos <thanos.makatos@nutanix.com> | |
Change-Id: Ic19b0d92ad9e7948ec48be8f79dddb7492cfd122 | |
--- | |
hw/vfio/pci.c | 44 ++++++++++++++++++++++++++++++ | |
hw/vfio/trace-events | 3 +++ | |
hw/vfio/user-protocol.h | 21 +++++++++++++++ | |
hw/vfio/user.c | 51 ++++++++++++++++++++++++++++++++++- | |
include/hw/vfio/vfio-common.h | 12 +++++++++ | |
linux-headers/linux/kvm.h | 5 +++- | |
6 files changed, 134 insertions(+), 2 deletions(-) | |
diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c | |
index 7191074a35..c805fec2dd 100644 | |
--- a/hw/vfio/pci.c | |
+++ b/hw/vfio/pci.c | |
@@ -1777,6 +1777,33 @@ static void vfio_bars_prepare(VFIOPCIDevice *vdev) | |
} | |
} | |
+static int configure_ioeventfd(uint64_t addr, uint32_t len, int fd, | |
+ void *foo) | |
+{ | |
+ int ret; | |
+ struct kvm_ioeventfd iofd = { | |
+ .datamatch = 0, | |
+ .addr = addr, | |
+ .len = len, | |
+ .flags = KVM_IOEVENTFD_FLAG_COMMIT_WRITE, | |
+ .fd = fd, | |
+ .vaddr = (__u64)foo, | |
+ }; | |
+ | |
+ assert(kvm_enabled()); | |
+ | |
+ ret = kvm_vm_ioctl(kvm_state, KVM_IOEVENTFD, &iofd); | |
+ | |
+ if (ret < 0) { | |
+ ret = -errno; | |
+ error_report("XXX %m\n"); | |
+ return ret; | |
+ } | |
+ | |
+ return 0; | |
+ | |
+} | |
+ | |
static void vfio_bar_register(VFIOPCIDevice *vdev, int nr) | |
{ | |
VFIOBAR *bar = &vdev->bars[nr]; | |
@@ -1798,6 +1825,23 @@ static void vfio_bar_register(VFIOPCIDevice *vdev, int nr) | |
error_report("Failed to mmap %s BAR %d. Performance may be slow", | |
vdev->vbasedev.name, nr); | |
} | |
+ | |
+ if (nr == 0 && vdev->vbasedev.ioeventfd.size > 0) { // FIXME | |
+#if 0 | |
+ void memory_region_add_eventfd(bar->mr, 0, bar->size, false, 0); | |
+ EventNotifier *e) | |
+#endif | |
+ void *vaddr = mmap(NULL, vdev->vbasedev.ioeventfd.size, PROT_READ | PROT_WRITE, MAP_SHARED, vdev->vbasedev.data_fd, vdev->vbasedev.ioeventfd.offset); | |
+ assert(vaddr != MAP_FAILED); | |
+ /* FIXME we can get the GPA from the PCI config space, offset 0x10-0x28 */ | |
+ int size = 4; | |
+ assert(vdev->vbasedev.ioeventfd.size % size == 0); | |
+ for (int i = 0; i < vdev->vbasedev.ioeventfd.size / size; i++) { | |
+ int ret = configure_ioeventfd(0xfebd1000 + i, size, vdev->vbasedev.eventfd, vaddr + i); | |
+ assert(ret == 0); | |
+ } | |
+ error_report("XXX configured ioeventfd %d\n", vdev->vbasedev.eventfd); | |
+ } | |
} | |
pci_register_bar(&vdev->pdev, nr, bar->type, bar->mr); | |
diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events | |
index b1ef55a33f..11d9f47017 100644 | |
--- a/hw/vfio/trace-events | |
+++ b/hw/vfio/trace-events | |
@@ -142,3 +142,6 @@ vfio_display_edid_link_up(void) "" | |
vfio_display_edid_link_down(void) "" | |
vfio_display_edid_update(uint32_t prefx, uint32_t prefy) "%ux%u" | |
vfio_display_edid_write_error(void) "" | |
+ | |
+# region I/O FDs | |
+vfio_user_get_region_io_fds(const char *name, uint32_t index) " (%s) region %d: no region I/O FDs" | |
diff --git a/hw/vfio/user-protocol.h b/hw/vfio/user-protocol.h | |
index bad067a570..252a418308 100644 | |
--- a/hw/vfio/user-protocol.h | |
+++ b/hw/vfio/user-protocol.h | |
@@ -134,6 +134,27 @@ typedef struct { | |
uint64_t offset; | |
} VFIOUserRegionInfo; | |
+/* | |
+ * VFIO_USER_DEVICE_GET_REGION_IO_FDS | |
+ */ | |
+typedef struct { | |
+ VFIOUserHdr hdr; | |
+ uint32_t argsz; | |
+ uint32_t flags; | |
+ uint32_t index; | |
+ uint32_t count; | |
+} VFIOUserRegionIOFDs; | |
+ | |
+typedef struct vfio_user_sub_region_ioeventfd { | |
+ uint64_t offset; | |
+ uint64_t size; | |
+ uint32_t fd_index; | |
+ uint32_t type; | |
+ uint32_t flags; | |
+ uint32_t padding; | |
+ uint64_t datamatch; | |
+} __attribute__((packed)) vfio_user_sub_region_ioeventfd_t; | |
+ | |
/* | |
* VFIO_USER_DEVICE_GET_IRQ_INFO | |
* imported from struct vfio_irq_info | |
diff --git a/hw/vfio/user.c b/hw/vfio/user.c | |
index 584a278c7a..a49358fd02 100644 | |
--- a/hw/vfio/user.c | |
+++ b/hw/vfio/user.c | |
@@ -29,6 +29,7 @@ | |
#include "qapi/qmp/qstring.h" | |
#include "qapi/qmp/qnum.h" | |
#include "user.h" | |
+#include "trace.h" | |
static uint64_t max_xfer_size = VFIO_USER_DEF_MAX_XFER; | |
static uint64_t max_send_fds = VFIO_USER_DEF_MAX_FDS; | |
@@ -284,7 +285,8 @@ static int vfio_user_recv_one(VFIOProxy *proxy) | |
if (isreply) { | |
if (hdr.size > msg->rsize) { | |
error_setg(&local_err, | |
- "vfio_user_recv reply larger than recv buffer"); | |
+ "vfio_user_recv reply (%u) larger than recv buffer (%u)", | |
+ hdr.size, msg->rsize); | |
goto err; | |
} | |
*msg->hdr = hdr; | |
@@ -1210,6 +1212,45 @@ static int vfio_user_get_region_info(VFIOProxy *proxy, | |
return 0; | |
} | |
+static int vfio_user_get_region_io_fds(VFIODevice *vbasedev, int index) | |
+{ | |
+ g_autofree VFIOUserRegionIOFDs *msgp = NULL; | |
+ vfio_user_sub_region_ioeventfd_t *ioeventfds; | |
+ uint32_t size; | |
+ int _fds[2]; | |
+ VFIOUserFDs fds = { 0, 2, _fds }; | |
+ | |
+ size = sizeof(VFIOUserRegionIOFDs) + sizeof(vfio_user_sub_region_ioeventfd_t); | |
+ msgp = g_malloc0(size); | |
+ | |
+ vfio_user_request_msg(&msgp->hdr, VFIO_USER_DEVICE_GET_REGION_IO_FDS, | |
+ sizeof(*msgp), 0); | |
+ msgp->argsz = size; | |
+ msgp->index = index; | |
+ | |
+ vfio_user_send_wait(vbasedev->proxy, &msgp->hdr, &fds, size, false); | |
+ if (msgp->hdr.flags & VFIO_USER_ERROR) { | |
+ return -msgp->hdr.error_reply; | |
+ } | |
+ | |
+ if (!msgp->count) { | |
+ trace_vfio_user_get_region_io_fds(vbasedev->name, index); | |
+ return 0; | |
+ } | |
+ assert(msgp->count == 1); | |
+ assert(index == 0); | |
+ error_printf("XXX region %d: argsz=%u flags=%x index=%u count=%u\n", | |
+ index, msgp->argsz, msgp->flags, msgp->index, msgp->count); | |
+ ioeventfds = (vfio_user_sub_region_ioeventfd_t*)(msgp + 1); | |
+ error_printf("XXX offset=%lu size=%lu fd_index=%u type=%u flags=%x padding=%u datamatch=%lu\n", | |
+ ioeventfds->offset, ioeventfds->size, ioeventfds->fd_index, ioeventfds->type, ioeventfds->flags, ioeventfds->padding, ioeventfds->datamatch); | |
+ assert(_fds[1] != -1); | |
+ vbasedev->ioeventfd = *ioeventfds; | |
+ vbasedev->eventfd = _fds[0]; | |
+ vbasedev->data_fd = _fds[1]; | |
+ return 0; | |
+} | |
+ | |
static int vfio_user_get_irq_info(VFIOProxy *proxy, | |
struct vfio_irq_info *info) | |
{ | |
@@ -1414,6 +1455,14 @@ static int vfio_user_io_get_region_info(VFIODevice *vbasedev, | |
return ret; | |
} | |
+ if (info->index == 0 && info->size > 0 && info->flags != 0) { | |
+ ret = vfio_user_get_region_io_fds(vbasedev, info->index); | |
+ if (ret) { | |
+ assert(false); | |
+ return ret; | |
+ } | |
+ } | |
+ | |
return VDEV_VALID_REGION_INFO(vbasedev, info, fd); | |
} | |
diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h | |
index f32ea3b5b0..afdae9ab92 100644 | |
--- a/include/hw/vfio/vfio-common.h | |
+++ b/include/hw/vfio/vfio-common.h | |
@@ -31,6 +31,7 @@ | |
#endif | |
#include "sysemu/runstate.h" | |
+#include "hw/vfio/user-protocol.h" | |
#define VFIO_MSG_PREFIX "vfio %s: " | |
enum { | |
@@ -117,6 +118,12 @@ typedef struct VFIODeviceOps VFIODeviceOps; | |
typedef struct VFIODevIO VFIODevIO; | |
typedef struct VFIOValidOps VFIOValidOps; | |
+struct ioregionfds { | |
+ struct iovec *areas; | |
+ int nr_areas; | |
+ int *fds; | |
+}; | |
+ | |
typedef struct VFIODevice { | |
QLIST_ENTRY(VFIODevice) next; | |
struct VFIOGroup *group; | |
@@ -144,6 +151,11 @@ typedef struct VFIODevice { | |
VFIOProxy *proxy; | |
struct vfio_region_info **regions; | |
int *regfds; | |
+ | |
+ /* FIXME */ | |
+ vfio_user_sub_region_ioeventfd_t ioeventfd; | |
+ int eventfd; | |
+ int data_fd; | |
} VFIODevice; | |
struct VFIODeviceOps { | |
diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h | |
index 6bba4ec136..d61e195224 100644 | |
--- a/linux-headers/linux/kvm.h | |
+++ b/linux-headers/linux/kvm.h | |
@@ -681,6 +681,7 @@ enum { | |
kvm_ioeventfd_flag_nr_deassign, | |
kvm_ioeventfd_flag_nr_virtio_ccw_notify, | |
kvm_ioeventfd_flag_nr_fast_mmio, | |
+ kvm_ioevetnfd_flag_nr_commit_write, | |
kvm_ioeventfd_flag_nr_max, | |
}; | |
@@ -689,6 +690,7 @@ enum { | |
#define KVM_IOEVENTFD_FLAG_DEASSIGN (1 << kvm_ioeventfd_flag_nr_deassign) | |
#define KVM_IOEVENTFD_FLAG_VIRTIO_CCW_NOTIFY \ | |
(1 << kvm_ioeventfd_flag_nr_virtio_ccw_notify) | |
+#define KVM_IOEVENTFD_FLAG_COMMIT_WRITE (1 << kvm_ioevetnfd_flag_nr_commit_write) | |
#define KVM_IOEVENTFD_VALID_FLAG_MASK ((1 << kvm_ioeventfd_flag_nr_max) - 1) | |
@@ -698,7 +700,8 @@ struct kvm_ioeventfd { | |
__u32 len; /* 1, 2, 4, or 8 bytes; or 0 to ignore length */ | |
__s32 fd; | |
__u32 flags; | |
- __u8 pad[36]; | |
+ __u64 vaddr; | |
+ __u8 pad[28]; | |
}; | |
#define KVM_X86_DISABLE_EXITS_MWAIT (1 << 0) | |
-- | |
2.22.3 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment