From 2d1d87016133b6c2f38e4f6a5fca6be5b820653c Mon Sep 17 00:00:00 2001 From: Thanos Makatos Date: Fri, 4 Feb 2022 13:51:59 +0000 Subject: ignore writes to RO MSI-X registers (#642) Signed-off-by: Thanos Makatos Reviewed-by: John Levon --- test/py/libvfio_user.py | 9 +++++++ test/py/test_pci_caps.py | 67 ++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 74 insertions(+), 2 deletions(-) (limited to 'test') diff --git a/test/py/libvfio_user.py b/test/py/libvfio_user.py index 4b4a96a..6d71efd 100644 --- a/test/py/libvfio_user.py +++ b/test/py/libvfio_user.py @@ -63,6 +63,7 @@ PCI_CAP_LIST_NEXT = 1 PCI_CAP_ID_PM = 0x1 PCI_CAP_ID_VNDR = 0x9 +PCI_CAP_ID_MSIX = 0x11 PCI_CAP_ID_EXP = 0x10 PCI_EXP_DEVCTL2 = 40 @@ -75,6 +76,14 @@ PCI_EXT_CAP_DSN_SIZEOF = 12 PCI_EXT_CAP_VNDR_HDR_SIZEOF = 8 +# MSI-X registers +PCI_MSIX_FLAGS = 2 # Message Control +PCI_MSIX_TABLE = 4 # Table offset +PCI_MSIX_FLAGS_MASKALL = 0x4000 # Mask all vectors for this function +PCI_MSIX_FLAGS_ENABLE = 0x8000 # MSI-X enable +PCI_CAP_MSIX_SIZEOF = 12 # size of MSIX registers + + # from linux/vfio.h VFIO_DEVICE_FLAGS_RESET = (1 << 0) diff --git a/test/py/test_pci_caps.py b/test/py/test_pci_caps.py index effd6d3..b83c06c 100644 --- a/test/py/test_pci_caps.py +++ b/test/py/test_pci_caps.py @@ -349,9 +349,72 @@ def test_pci_cap_write_px(mock_quiesce, mock_reset): expect=errno.EINVAL) +def to_bytes_le(n, length=1): + return n.to_bytes(length, 'little') + + def test_pci_cap_write_msix(): - # FIXME - pass + setup_pci_dev(realize=True) + sock = connect_client(ctx) + + flags = PCI_MSIX_FLAGS_MASKALL | PCI_MSIX_FLAGS_ENABLE + pos = vfu_pci_add_capability(ctx, pos=0, flags=0, + data=struct.pack("ccHII", + to_byte(PCI_CAP_ID_MSIX), + b'\0', 0, 0, 0)) + assert pos == cap_offsets[0] + + offset = vfu_pci_find_capability(ctx, False, PCI_CAP_ID_MSIX) + + # write exactly to Message Control: mask all vectors and enable MSI-X + data = b'\xff\xff' + write_region(ctx, sock, VFU_PCI_DEV_CFG_REGION_IDX, + offset=offset + PCI_MSIX_FLAGS, + count=len(data), data=data) + data = b'\xff\xff' + to_bytes_le(flags, 2) + payload = read_region(ctx, sock, VFU_PCI_DEV_CFG_REGION_IDX, offset=offset, + count=len(data)) + expected = to_bytes_le(PCI_CAP_ID_MSIX) + b'\x00' + \ + to_bytes_le(PCI_MSIX_FLAGS_MASKALL | PCI_MSIX_FLAGS_ENABLE, 2) + assert expected == payload + + # reset + data = b'\x00\x00' + write_region(ctx, sock, VFU_PCI_DEV_CFG_REGION_IDX, + offset=offset + PCI_MSIX_FLAGS, + count=len(data), data=data) + expected = to_bytes_le(PCI_CAP_ID_MSIX) + b'\x00\x00' + payload = read_region(ctx, sock, VFU_PCI_DEV_CFG_REGION_IDX, offset=offset, + count=len(expected)) + assert expected == payload + + # write 2 bytes to Message Control + 1: mask all vectors and enable MSI-X + # This looks bizarre, but some versions of QEMU do this. + data = to_bytes_le(flags >> 8) + b'\xff' + write_region(ctx, sock, VFU_PCI_DEV_CFG_REGION_IDX, + offset=offset + PCI_MSIX_FLAGS + 1, + count=len(data), data=data) + # read back entire MSI-X + expected = to_bytes_le(PCI_CAP_ID_MSIX) + b'\x00' + \ + to_bytes_le(flags, 2) + b'\x00\x00\x00\x00' + b'\x00\x00\x00\x00' + payload = read_region(ctx, sock, VFU_PCI_DEV_CFG_REGION_IDX, offset=offset, + count=PCI_CAP_MSIX_SIZEOF) + assert expected == payload + + # reset with MSI-X enabled + data = to_bytes_le(PCI_MSIX_FLAGS_ENABLE, 2) + write_region(ctx, sock, VFU_PCI_DEV_CFG_REGION_IDX, + offset=offset + PCI_MSIX_FLAGS, + count=len(data), data=data) + + # write 1 byte past Message Control, MSI-X should still be enabled + data = b'\x00' + write_region(ctx, sock, VFU_PCI_DEV_CFG_REGION_IDX, + offset=offset + PCI_MSIX_TABLE, + count=len(data), data=data) + payload = read_region(ctx, sock, VFU_PCI_DEV_CFG_REGION_IDX, + offset=offset + PCI_MSIX_FLAGS, count=2) + assert payload == to_bytes_le(PCI_MSIX_FLAGS_ENABLE, 2) def test_pci_cap_write_pxdc2(): -- cgit v1.1