Skip to content

Instantly share code, notes, and snippets.

@tmakatos
Created July 4, 2022 10:09
Show Gist options
  • Save tmakatos/57755d2a37a6d53c9ff392e7c34470f6 to your computer and use it in GitHub Desktop.
Save tmakatos/57755d2a37a6d53c9ff392e7c34470f6 to your computer and use it in GitHub Desktop.
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