From: John G Johnson <john.g.john...@oracle.com> Send VFIO_REGION_READ and VFIO_REGION_WRITE commands.
Signed-off-by: Elena Ufimtseva <elena.ufimts...@oracle.com> Signed-off-by: John G Johnson <john.g.john...@oracle.com> Signed-off-by: Jagannathan Raman <jag.ra...@oracle.com> --- hw/vfio/user.h | 16 ++++++++++++++++ hw/vfio/common.c | 17 +++++++++++++++-- hw/vfio/pci.c | 13 +++++++++++++ hw/vfio/user.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 89 insertions(+), 2 deletions(-) diff --git a/hw/vfio/user.h b/hw/vfio/user.h index 9f51e14c7c..17c4d90ef1 100644 --- a/hw/vfio/user.h +++ b/hw/vfio/user.h @@ -147,6 +147,18 @@ struct vfio_user_irq_info { uint32_t count; }; +/* + * VFIO_USER_REGION_READ + * VFIO_USER_REGION_WRITE + */ +struct vfio_user_region_rw { + vfio_user_hdr_t hdr; + uint64_t offset; + uint32_t region; + uint32_t count; + char data[]; +}; + void vfio_user_recv(void *opaque); void vfio_user_send_reply(VFIOProxy *proxy, char *buf, int ret); VFIOProxy *vfio_user_connect_dev(char *sockname, Error **errp); @@ -154,4 +166,8 @@ void vfio_user_disconnect(VFIOProxy *proxy); int vfio_user_validate_version(VFIODevice *vbasedev, Error **errp); int vfio_user_get_info(VFIODevice *vbasedev); int vfio_user_get_irq_info(VFIODevice *vbasedev, struct vfio_irq_info *info); +int vfio_user_region_read(VFIODevice *vbasedev, uint32_t index, uint64_t offset, + uint32_t count, void *data); +int vfio_user_region_write(VFIODevice *vbasedev, uint32_t index, + uint64_t offset, uint32_t count, void *data); #endif /* VFIO_USER_H */ diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 45acdeeb46..74041cc438 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -40,6 +40,7 @@ #include "trace.h" #include "qapi/error.h" #include "migration/migration.h" +#include "hw/vfio/user.h" VFIOGroupList vfio_group_list = QLIST_HEAD_INITIALIZER(vfio_group_list); @@ -214,6 +215,7 @@ void vfio_region_write(void *opaque, hwaddr addr, uint32_t dword; uint64_t qword; } buf; + int ret; switch (size) { case 1: @@ -233,7 +235,12 @@ void vfio_region_write(void *opaque, hwaddr addr, break; } - if (pwrite(vbasedev->fd, &buf, size, region->fd_offset + addr) != size) { + if (vbasedev->proxy != NULL) { + ret = vfio_user_region_write(vbasedev, region->nr, addr, size, &data); + } else { + ret = pwrite(vbasedev->fd, &buf, size, region->fd_offset + addr); + } + if (ret != size) { error_report("%s(%s:region%d+0x%"HWADDR_PRIx", 0x%"PRIx64 ",%d) failed: %m", __func__, vbasedev->name, region->nr, @@ -265,8 +272,14 @@ uint64_t vfio_region_read(void *opaque, uint64_t qword; } buf; uint64_t data = 0; + int ret; - if (pread(vbasedev->fd, &buf, size, region->fd_offset + addr) != size) { + if (vbasedev->proxy != NULL) { + ret = vfio_user_region_read(vbasedev, region->nr, addr, size, &buf); + } else { + ret = pread(vbasedev->fd, &buf, size, region->fd_offset + addr); + } + if (ret != size) { error_report("%s(%s:region%d+0x%"HWADDR_PRIx", %d) failed: %m", __func__, vbasedev->name, region->nr, addr, size); diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index 029a191bcb..1054978e5e 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -3424,6 +3424,19 @@ static void vfio_user_pci_realize(PCIDevice *pdev, Error **errp) error_propagate(errp, err); goto error; } + /* Get a copy of config space */ + ret = vfio_user_region_read(vbasedev, VFIO_PCI_CONFIG_REGION_INDEX, 0, + MIN(pci_config_size(pdev), vdev->config_size), + pdev->config); + if (ret < 0) { + goto error; + } + + /* vfio emulates a lot for us, but some bits need extra love */ + vdev->emulated_config_bits = g_malloc0(vdev->config_size); + + /* QEMU can also add or extend BARs */ + memset(vdev->emulated_config_bits + PCI_BASE_ADDRESS_0, 0xff, 6 * 4); return; diff --git a/hw/vfio/user.c b/hw/vfio/user.c index a282b7b7b8..2bb6f8650e 100644 --- a/hw/vfio/user.c +++ b/hw/vfio/user.c @@ -634,3 +634,48 @@ int vfio_user_get_irq_info(VFIODevice *vbasedev, struct vfio_irq_info *info) memcpy(info, &msg.argsz, sizeof(*info)); return 0; } + +int vfio_user_region_read(VFIODevice *vbasedev, uint32_t index, uint64_t offset, + uint32_t count, void *data) +{ + g_autofree struct vfio_user_region_rw *msgp = NULL; + int size = sizeof(*msgp) + count; + + /* most reads are just registers, only allocate for larger ones */ + msgp = g_malloc0(size); + vfio_user_request_msg(&msgp->hdr, VFIO_USER_REGION_READ, sizeof(*msgp), 0); + msgp->offset = offset; + msgp->region = index; + msgp->count = count; + + vfio_user_send_recv(vbasedev->proxy, &msgp->hdr, NULL, size); + if (msgp->hdr.flags & VFIO_USER_ERROR) { + return -msgp->hdr.error_reply; + } else if (msgp->count > count) { + return -E2BIG; + } else { + memcpy(data, &msgp->data, msgp->count); + } + + return msgp->count; +} + +int vfio_user_region_write(VFIODevice *vbasedev, uint32_t index, + uint64_t offset, uint32_t count, void *data) +{ + g_autofree struct vfio_user_region_rw *msgp = NULL; + int size = sizeof(*msgp) + count; + + /* most writes are just registers, only allocate for larger ones */ + msgp = g_malloc0(size); + vfio_user_request_msg(&msgp->hdr, VFIO_USER_REGION_WRITE, size, + VFIO_USER_NO_REPLY); + msgp->offset = offset; + msgp->region = index; + msgp->count = count; + memcpy(&msgp->data, data, count); + + vfio_user_send(vbasedev->proxy, &msgp->hdr, NULL); + + return count; +} -- 2.25.1