diff options
Diffstat (limited to 'test/py/test_pci_caps.py')
-rw-r--r-- | test/py/test_pci_caps.py | 156 |
1 files changed, 84 insertions, 72 deletions
diff --git a/test/py/test_pci_caps.py b/test/py/test_pci_caps.py index 5267246..effd6d3 100644 --- a/test/py/test_pci_caps.py +++ b/test/py/test_pci_caps.py @@ -27,6 +27,7 @@ # DAMAGE. # +from unittest.mock import patch from libvfio_user import * import ctypes as c import errno @@ -34,21 +35,37 @@ import errno ctx = None -def test_pci_cap_setup(): +def setup_function(function): global ctx ctx = vfu_create_ctx(flags=LIBVFIO_USER_FLAG_ATTACH_NB) assert ctx is not None - - ret = vfu_pci_init(ctx, pci_type=VFU_PCI_TYPE_CONVENTIONAL) + ret = vfu_setup_device_reset_cb(ctx) assert ret == 0 + vfu_setup_device_quiesce_cb(ctx) - ret = vfu_setup_region(ctx, index=VFU_PCI_DEV_CFG_REGION_IDX, - size=PCI_CFG_SPACE_SIZE, flags=VFU_REGION_FLAG_RW) + +def teardown_function(function): + vfu_destroy_ctx(ctx) + + +def setup_pci_dev(config_space=True, realize=False): + global ctx + ret = vfu_pci_init(ctx, pci_type=VFU_PCI_TYPE_CONVENTIONAL) assert ret == 0 + if config_space: + ret = vfu_setup_region(ctx, index=VFU_PCI_DEV_CFG_REGION_IDX, + size=PCI_CFG_SPACE_SIZE, + flags=VFU_REGION_FLAG_RW) + assert ret == 0 + if realize: + ret = vfu_realize_ctx(ctx) + assert ret == 0 def test_pci_cap_bad_flags(): + """Tests adding a PCI capability with bad VFU_CAP_FLAG_ flags.""" + setup_pci_dev() pos = vfu_pci_add_capability(ctx, pos=0, flags=999, data=struct.pack("ccHH", to_byte(PCI_CAP_ID_PM), b'\0', 0, 0)) assert pos == -1 @@ -56,6 +73,10 @@ def test_pci_cap_bad_flags(): def test_pci_cap_no_cb(): + """ + Tests adding a PCI capability VFU_CAP_FLAG_CALLBACK without a callback. + """ + setup_pci_dev(config_space=False) pos = vfu_pci_add_capability(ctx, pos=0, flags=VFU_CAP_FLAG_CALLBACK, data=struct.pack("ccHH", to_byte(PCI_CAP_ID_PM), b'\0', 0, 0)) assert pos == -1 @@ -63,6 +84,8 @@ def test_pci_cap_no_cb(): def test_pci_cap_unknown_cap(): + """Tests adding an unknown PCI capability.""" + setup_pci_dev() pos = vfu_pci_add_capability(ctx, pos=0, flags=0, data=struct.pack("ccHH", b'\x81', b'\0', 0, 0)) assert pos == -1 @@ -70,37 +93,21 @@ def test_pci_cap_unknown_cap(): def test_pci_cap_bad_pos(): + """Tests adding a PCI capability at an invalid position.""" + setup_pci_dev() pos = vfu_pci_add_capability(ctx, pos=PCI_CFG_SPACE_SIZE, flags=0, data=struct.pack("ccHH", to_byte(PCI_CAP_ID_PM), b'\0', 0, 0)) assert pos == -1 assert c.get_errno() == errno.EINVAL -@vfu_region_access_cb_t -def pci_region_cb(ctx, buf, count, offset, is_write): +def __pci_region_cb(ctx, buf, count, offset, is_write): if not is_write: return read_pci_cfg_space(ctx, buf, count, offset) return write_pci_cfg_space(ctx, buf, count, offset) -def test_pci_cap_setup_cb(): - global ctx - - vfu_destroy_ctx(ctx) - - ctx = vfu_create_ctx(flags=LIBVFIO_USER_FLAG_ATTACH_NB) - assert ctx is not None - - ret = vfu_pci_init(ctx, pci_type=VFU_PCI_TYPE_CONVENTIONAL) - assert ret == 0 - - ret = vfu_setup_region(ctx, index=VFU_PCI_DEV_CFG_REGION_IDX, - size=PCI_CFG_SPACE_SIZE, cb=pci_region_cb, - flags=VFU_REGION_FLAG_RW) - assert ret == 0 - - cap_offsets = ( PCI_STD_HEADER_SIZEOF, PCI_STD_HEADER_SIZEOF + PCI_PM_SIZEOF, @@ -112,7 +119,9 @@ cap_offsets = ( ) -def test_add_caps(): +@patch("libvfio_user.pci_region_cb", side_effect=__pci_region_cb) +def test_add_caps(mock_pci_region_cb): + setup_pci_dev() pos = vfu_pci_add_capability(ctx, pos=0, flags=0, data=struct.pack("ccHH", to_byte(PCI_CAP_ID_PM), b'\0', 0, 0)) assert pos == cap_offsets[0] @@ -142,8 +151,17 @@ def test_add_caps(): ret = vfu_realize_ctx(ctx) assert ret == 0 + __test_find_caps() -def test_find_caps(): + sock = connect_client(ctx) + + __test_pci_cap_write_hdr(sock) + __test_pci_cap_readonly(sock) + __test_pci_cap_callback(sock) + __test_pci_cap_write_pmcs(sock) + + +def __test_find_caps(): offset = vfu_pci_find_capability(ctx, False, PCI_CAP_ID_PM) assert offset == cap_offsets[0] @@ -202,21 +220,15 @@ def test_find_caps(): assert c.get_errno() == errno.ENOENT -def test_pci_cap_write_hdr(): - sock = connect_client(ctx) - +def __test_pci_cap_write_hdr(sock): # offset of struct cap_hdr offset = cap_offsets[0] data = b'\x01' write_region(ctx, sock, VFU_PCI_DEV_CFG_REGION_IDX, offset=offset, count=len(data), data=data, expect=errno.EPERM) - disconnect_client(ctx, sock) - - -def test_pci_cap_readonly(): - sock = connect_client(ctx) +def __test_pci_cap_readonly(sock): # start of vendor payload offset = cap_offsets[1] + 2 data = b'\x01' @@ -229,12 +241,8 @@ def test_pci_cap_readonly(): count=3) assert payload == b'abc' - disconnect_client(ctx, sock) - - -def test_pci_cap_callback(): - sock = connect_client(ctx) +def __test_pci_cap_callback(sock): # offsetof(struct vsc, data) offset = cap_offsets[2] + 3 data = b"Hello world." @@ -251,11 +259,8 @@ def test_pci_cap_callback(): count=len(data)) assert payload == data - disconnect_client(ctx, sock) - -def test_pci_cap_write_pmcs(): - sock = connect_client(ctx) +def __test_pci_cap_write_pmcs(sock): # struct pc @@ -305,40 +310,43 @@ def test_pci_cap_write_pmcs(): write_region(ctx, sock, VFU_PCI_DEV_CFG_REGION_IDX, offset=offset, count=len(data), data=data, expect=errno.ENOTSUP) - disconnect_client(ctx, sock) - - -reset_flag = -1 - - -@c.CFUNCTYPE(c.c_int, c.c_void_p, c.c_int) -def vfu_reset_cb(ctx, reset_type): - assert reset_type == VFU_RESET_PCI_FLR or reset_type == VFU_RESET_LOST_CONN - global reset_flag - reset_flag = reset_type - return 0 - - -def test_pci_cap_write_px(): - sock = connect_client(ctx) - ret = vfu_setup_device_reset_cb(ctx, vfu_reset_cb) - assert ret == 0 +def _setup_flrc(ctx): # flrc cap = struct.pack("ccHHcc52c", to_byte(PCI_CAP_ID_EXP), b'\0', 0, 0, b'\0', b'\x10', *[b'\0' for _ in range(52)]) - pos = vfu_pci_add_capability(ctx, pos=cap_offsets[5], flags=0, data=cap) - assert pos == cap_offsets[5] + # FIXME adding capability after we've realized the device only works + # because of bug #618. + pos = vfu_pci_add_capability(ctx, pos=0, flags=0, data=cap) + assert pos == PCI_STD_HEADER_SIZEOF + + +@patch("libvfio_user.reset_cb", return_value=0) +@patch('libvfio_user.quiesce_cb') +def test_pci_cap_write_px(mock_quiesce, mock_reset): + """ + Tests function level reset. + """ + setup_pci_dev(realize=True) + sock = connect_client(ctx) + + _setup_flrc(ctx) # iflr - offset = cap_offsets[5] + 8 + offset = PCI_STD_HEADER_SIZEOF + 8 data = b'\x00\x80' write_region(ctx, sock, VFU_PCI_DEV_CFG_REGION_IDX, offset=offset, count=len(data), data=data) - assert reset_flag == VFU_RESET_PCI_FLR - disconnect_client(ctx, sock) - assert reset_flag == VFU_RESET_LOST_CONN + mock_quiesce.assert_called_once_with(ctx) + mock_reset.assert_called_once_with(ctx, VFU_RESET_PCI_FLR) + + # bad access + for _off in (-1, +1): + for _len in (-1, +1): + write_region(ctx, sock, VFU_PCI_DEV_CFG_REGION_IDX, + offset=offset+_off, count=len(data)+_len, data=data, + expect=errno.EINVAL) def test_pci_cap_write_msix(): @@ -347,7 +355,12 @@ def test_pci_cap_write_msix(): def test_pci_cap_write_pxdc2(): + + setup_pci_dev(realize=True) sock = connect_client(ctx) + + _setup_flrc(ctx) + offset = (vfu_pci_find_capability(ctx, False, PCI_CAP_ID_EXP) + PCI_EXP_DEVCTL2) data = b'\xde\xad' @@ -356,10 +369,13 @@ def test_pci_cap_write_pxdc2(): payload = read_region(ctx, sock, VFU_PCI_DEV_CFG_REGION_IDX, offset=offset, count=len(data)) assert payload == data - disconnect_client(ctx, sock) def test_pci_cap_write_pxlc2(): + + setup_pci_dev(realize=True) + _setup_flrc(ctx) + sock = connect_client(ctx) offset = (vfu_pci_find_capability(ctx, False, PCI_CAP_ID_EXP) + PCI_EXP_LNKCTL2) @@ -369,10 +385,6 @@ def test_pci_cap_write_pxlc2(): payload = read_region(ctx, sock, VFU_PCI_DEV_CFG_REGION_IDX, offset=offset, count=len(data)) assert payload == data - disconnect_client(ctx, sock) - -def test_pci_cap_cleanup(): - vfu_destroy_ctx(ctx) # ex: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab: # |