aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/libvfio-user.h3
-rw-r--r--lib/libvfio-user.c11
-rw-r--r--test/py/libvfio_user.py1
-rw-r--r--test/py/test_setup_region.py35
4 files changed, 48 insertions, 2 deletions
diff --git a/include/libvfio-user.h b/include/libvfio-user.h
index 75de04e..4b08c22 100644
--- a/include/libvfio-user.h
+++ b/include/libvfio-user.h
@@ -221,6 +221,7 @@ typedef ssize_t (vfu_region_access_cb_t)(vfu_ctx_t *vfu_ctx, char *buf,
#define VFU_REGION_FLAG_WRITE (1 << 1)
#define VFU_REGION_FLAG_RW (VFU_REGION_FLAG_READ | VFU_REGION_FLAG_WRITE)
#define VFU_REGION_FLAG_MEM (1 << 2) // if unset, bar is IO
+#define VFU_REGION_FLAG_ALWAYS_CB (1 << 3)
/**
* Set up a device region.
@@ -262,6 +263,8 @@ typedef ssize_t (vfu_region_access_cb_t)(vfu_ctx_t *vfu_ctx, char *buf,
* - if no callback is provided, reads to other areas are a simple memcpy(),
* and writes are an error
* - otherwise, the callback is expected to handle the access
+ * - if VFU_REGION_FLAG_ALWAYS_CB flag is set, all accesses to the config
+ * space are forwarded to the callback
*
* Regions VFU_PCI_DEV_MIGR_REGION_IDX and VFU_GENERIC_DEV_MIGR_REG_IDX,
* corresponding to the migration region, enable live migration support for
diff --git a/lib/libvfio-user.c b/lib/libvfio-user.c
index a90d9c2..1ee4026 100644
--- a/lib/libvfio-user.c
+++ b/lib/libvfio-user.c
@@ -208,7 +208,8 @@ region_access(vfu_ctx_t *vfu_ctx, size_t region_index, char *buf,
dump_buffer("buffer write", buf, count);
}
- if (region_index == VFU_PCI_DEV_CFG_REGION_IDX) {
+ if ((region_index == VFU_PCI_DEV_CFG_REGION_IDX) &&
+ !(vfu_ctx->reg_info[region_index].flags & VFU_REGION_FLAG_ALWAYS_CB)) {
ret = pci_config_space_access(vfu_ctx, buf, count, offset, is_write);
if (ret == -1) {
return ret;
@@ -1445,7 +1446,13 @@ vfu_setup_region(vfu_ctx_t *vfu_ctx, int region_idx, size_t size,
* PCI config space is never mappable or of type mem.
*/
if (region_idx == VFU_PCI_DEV_CFG_REGION_IDX &&
- flags != VFU_REGION_FLAG_RW) {
+ (((flags & VFU_REGION_FLAG_RW) != VFU_REGION_FLAG_RW) ||
+ (flags & VFU_REGION_FLAG_MEM))) {
+ return ERROR_INT(EINVAL);
+ }
+
+ if ((flags & VFU_REGION_FLAG_ALWAYS_CB) && (cb == NULL)) {
+ vfu_log(vfu_ctx, LOG_ERR, "VFU_REGION_FLAG_ALWAYS_CB needs callback");
return ERROR_INT(EINVAL);
}
diff --git a/test/py/libvfio_user.py b/test/py/libvfio_user.py
index 70986fa..ff5c1cd 100644
--- a/test/py/libvfio_user.py
+++ b/test/py/libvfio_user.py
@@ -156,6 +156,7 @@ VFU_REGION_FLAG_READ = 1
VFU_REGION_FLAG_WRITE = 2
VFU_REGION_FLAG_RW = (VFU_REGION_FLAG_READ | VFU_REGION_FLAG_WRITE)
VFU_REGION_FLAG_MEM = 4
+VFU_REGION_FLAG_ALWAYS_CB = 8
VFIO_USER_F_DMA_REGION_READ = (1 << 0)
VFIO_USER_F_DMA_REGION_WRITE = (1 << 1)
diff --git a/test/py/test_setup_region.py b/test/py/test_setup_region.py
index 0bf120d..c42100f 100644
--- a/test/py/test_setup_region.py
+++ b/test/py/test_setup_region.py
@@ -114,5 +114,40 @@ def test_setup_region_bad_migr():
assert ret == -1
assert c.get_errno() == errno.EINVAL
+def test_setup_region_cfg_always_cb_nocb():
+ ret = vfu_setup_region(ctx, index=VFU_PCI_DEV_CFG_REGION_IDX,
+ size=PCI_CFG_SPACE_EXP_SIZE, cb=None,
+ flags=(VFU_REGION_FLAG_RW |
+ VFU_REGION_FLAG_ALWAYS_CB))
+ assert ret == -1
+ assert c.get_errno() == errno.EINVAL
+
+@vfu_region_access_cb_t
+def pci_cfg_region_cb(ctx, buf, count, offset, is_write):
+ if not is_write:
+ for i in range(count):
+ buf[i] = 0xcc
+
+ return count
+
+def test_setup_region_cfg_always_cb():
+ global ctx
+
+ ret = vfu_setup_region(ctx, index=VFU_PCI_DEV_CFG_REGION_IDX,
+ size=PCI_CFG_SPACE_EXP_SIZE, cb=pci_cfg_region_cb,
+ flags=(VFU_REGION_FLAG_RW |
+ VFU_REGION_FLAG_ALWAYS_CB))
+ assert ret == 0
+
+ ret = vfu_realize_ctx(ctx)
+ assert ret == 0
+
+ sock = connect_client(ctx)
+
+ payload = read_region(ctx, sock, VFU_PCI_DEV_CFG_REGION_IDX, offset=0, count=2)
+ assert payload == b'\xcc\xcc'
+
+ disconnect_client(ctx, sock)
+
def test_setup_region_cleanup():
vfu_destroy_ctx(ctx)