From: Jishnu Warrier <jishnuvw@linux.ibm.com>
To: qemu-devel@nongnu.org
Cc: npiggin@gmail.com, philmd@linaro.org, farosas@suse.de,
akihiko.odaki@daynix.com, mst@redhat.com,
marcel.apfelbaum@gmail.com, david@gibson.dropbear.id.au,
adityag@linux.ibm.com, harshpb@linux.ibm.com,
amachhiw@linux.ibm.com
Subject: [PATCH v6 08/10] qtest/libqos/pci: Enforce balanced iomap/unmap
Date: Tue, 18 Aug 2026 00:25:38 +0530 [thread overview]
Message-ID: <20260817185539.376740-9-jishnuvw@linux.ibm.com> (raw)
In-Reply-To: <20260817185539.376740-1-jishnuvw@linux.ibm.com>
From: Nicholas Piggin <npiggin@gmail.com>
Add assertions to ensure a BAR is not mapped twice, and that only
previously mapped BARs are unmapped. This can help catch bugs and
fragile coding.
Cc: Michael S. Tsirkin <mst@redhat.com>
Cc: Marcel Apfelbaum <marcel.apfelbaum@gmail.com>
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Reviewed-by: Fabiano Rosas <farosas@suse.de>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
tests/qtest/libqos/pci.c | 75 ++++++++++++++++++++++++++++++++--------
tests/qtest/libqos/pci.h | 10 ++++++
2 files changed, 70 insertions(+), 15 deletions(-)
diff --git a/tests/qtest/libqos/pci.c b/tests/qtest/libqos/pci.c
index cda3c56c..3d953d23 100644
--- a/tests/qtest/libqos/pci.c
+++ b/tests/qtest/libqos/pci.c
@@ -79,12 +79,17 @@ QPCIDevice *qpci_device_find(QPCIBus *bus, int devfn)
void qpci_device_init(QPCIDevice *dev, QPCIBus *bus, QPCIAddress *addr)
{
uint16_t vendor_id, device_id;
+ int i;
qpci_device_set(dev, bus, addr->devfn);
vendor_id = qpci_config_readw(dev, PCI_VENDOR_ID);
device_id = qpci_config_readw(dev, PCI_DEVICE_ID);
g_assert(!addr->vendor_id || vendor_id == addr->vendor_id);
g_assert(!addr->device_id || device_id == addr->device_id);
+
+ for (i = 0; i < QPCI_NUM_REGIONS; i++) {
+ g_assert(!dev->bars_mapped[i]);
+ }
}
static uint8_t qpci_find_resource_reserve_capability(QPCIDevice *dev)
@@ -338,21 +343,21 @@ bool qpci_msix_masked(QPCIDevice *dev, uint16_t entry)
}
/**
- * qpci_msix_test_interrupt - test whether msix interrupt has been raised
+ * qpci_msix_test_interrupt - test whether MSI-X interrupt has been raised
* @dev: PCI device
- * @msix_entry: msix entry to test
- * @msix_addr: address of msix message
- * @msix_data: expected msix message payload
+ * @msix_entry: MSI-X entry to test
+ * @msix_addr: address of MSI-X message
+ * @msix_data: expected MSI-X message payload
*
- * This tests whether the msix source has raised an interrupt. If the msix
+ * This tests whether the MSI-X source has raised an interrupt. If the MSI-X
* entry is masked, it tests the pending bit array for a pending message
* and @msix_addr and @msix_data need not be supplied. If the entry is not
* masked, it tests the address for corresponding data to see if the interrupt
* fired.
*
* Note that this does not lower the interrupt, however it does clear the
- * msix message address to 0 if it is found set. This must be called with
- * the msix address memory containing either 0 or the value of data, otherwise
+ * MSI-X message address to 0 if it is found set. This must be called with
+ * the MSI-X address memory containing either 0 or the value of data, otherwise
* it will assert on incorrect message.
*/
bool qpci_msix_test_interrupt(QPCIDevice *dev, uint32_t msix_entry,
@@ -376,8 +381,8 @@ bool qpci_msix_test_interrupt(QPCIDevice *dev, uint32_t msix_entry,
g_assert_cmpint(msix_addr, !=, 0);
g_assert_cmpint(msix_data, !=, 0);
- /* msix payload is written in little-endian format */
- qtest_memread(dev->bus->qts, msix_addr, &data, 4);
+ /* MSI-X payload is written in little-endian format */
+ qtest_memread(dev->bus->qts, msix_addr, &data, sizeof(data));
data = le32_to_cpu(data);
if (data == 0) {
return false;
@@ -385,7 +390,7 @@ bool qpci_msix_test_interrupt(QPCIDevice *dev, uint32_t msix_entry,
/* got a message, ensure it matches expected value then clear it. */
g_assert_cmphex(data, ==, msix_data);
- qtest_memset(dev->bus->qts, msix_addr, 0, 4);
+ qtest_memset(dev->bus->qts, msix_addr, 0, sizeof(data));
return true;
}
@@ -554,21 +559,31 @@ void qpci_memwrite(QPCIDevice *dev, QPCIBar token, uint64_t off,
dev->bus->memwrite(dev->bus, token.addr + off, buf, len);
}
-QPCIBar qpci_iomap(QPCIDevice *dev, int barno, uint64_t *sizeptr)
+static uint8_t qpci_bar_reg(int barno)
{
- QPCIBus *bus = dev->bus;
static const int bar_reg_map[] = {
PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1, PCI_BASE_ADDRESS_2,
PCI_BASE_ADDRESS_3, PCI_BASE_ADDRESS_4, PCI_BASE_ADDRESS_5,
};
+
+ g_assert(barno >= 0 && barno < QPCI_NUM_REGIONS);
+
+ return bar_reg_map[barno];
+}
+
+QPCIBar qpci_iomap(QPCIDevice *dev, int barno, uint64_t *sizeptr)
+{
+ QPCIBus *bus = dev->bus;
QPCIBar bar;
int bar_reg;
uint32_t addr, size;
uint32_t io_type;
uint64_t loc;
- g_assert(barno >= 0 && barno <= 5);
- bar_reg = bar_reg_map[barno];
+ g_assert(barno >= 0 && barno < QPCI_NUM_REGIONS);
+ g_assert(!dev->bars_mapped[barno]);
+
+ bar_reg = qpci_bar_reg(barno);
qpci_config_writel(dev, bar_reg, 0xFFFFFFFF);
addr = qpci_config_readl(dev, bar_reg);
@@ -611,12 +626,38 @@ QPCIBar qpci_iomap(QPCIDevice *dev, int barno, uint64_t *sizeptr)
}
bar.addr = loc;
+ bar.mapped = true;
+
+ dev->bars_mapped[barno] = true;
+ dev->bars[barno] = bar;
+
return bar;
}
void qpci_iounmap(QPCIDevice *dev, QPCIBar bar)
{
- /* FIXME */
+ int bar_reg;
+ int i;
+
+ if (!bar.mapped) {
+ return; /* bar was never mapped; no-op */
+ }
+
+ for (i = 0; i < QPCI_NUM_REGIONS; i++) {
+ if (!dev->bars_mapped[i]) {
+ continue;
+ }
+ if (dev->bars[i].addr == bar.addr) {
+ dev->bars_mapped[i] = false;
+ dev->bars[i].mapped = false;
+ bar_reg = qpci_bar_reg(i);
+ qpci_config_writel(dev, bar_reg, 0xFFFFFFFF);
+ /* FIXME: the address space is leaked */
+ return;
+ }
+ }
+ /* bar was not iomap()ed; treat as no-op for callers that may
+ * call iounmap unconditionally during cleanup paths. */
}
QPCIBar qpci_legacy_iomap(QPCIDevice *dev, uint16_t addr)
@@ -627,6 +668,10 @@ QPCIBar qpci_legacy_iomap(QPCIDevice *dev, uint16_t addr)
void qpci_migrate_fixup(QPCIDevice *to, QPCIDevice *from)
{
+ memcpy(to->bars_mapped, from->bars_mapped, sizeof(from->bars_mapped));
+ memset(from->bars_mapped, 0, sizeof(from->bars_mapped));
+ memcpy(to->bars, from->bars, sizeof(from->bars));
+ memset(from->bars, 0, sizeof(from->bars));
}
void add_qpci_address(QOSGraphEdgeOptions *opts, QPCIAddress *addr)
diff --git a/tests/qtest/libqos/pci.h b/tests/qtest/libqos/pci.h
index 19f1dd13..73739afe 100644
--- a/tests/qtest/libqos/pci.h
+++ b/tests/qtest/libqos/pci.h
@@ -58,12 +58,22 @@ struct QPCIBus {
struct QPCIBar {
uint64_t addr;
bool is_io;
+ bool mapped;
};
+/*
+ * hw/pci permits 7 (PCI_NUM_REGIONS) regions, the last for PCI_ROM_SLOT.
+ * libqos does not implement PCI_ROM_SLOT at the moment, and as such it
+ * permits 6.
+ */
+#define QPCI_NUM_REGIONS 6
+
struct QPCIDevice
{
QPCIBus *bus;
int devfn;
+ bool bars_mapped[QPCI_NUM_REGIONS];
+ QPCIBar bars[QPCI_NUM_REGIONS];
bool msix_enabled;
QPCIBar msix_table_bar, msix_pba_bar;
uint64_t msix_table_off, msix_pba_off;
--
2.55.0
next prev parent reply other threads:[~2026-08-17 18:57 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-17 18:55 [PATCH v6 00/10] tests/qtest: pci and MSI-X fixes Jishnu Warrier
2026-08-17 18:55 ` [PATCH v6 01/10] tests/qtest: Enforce zero for the "un-fired" msix message value Jishnu Warrier
2026-08-17 18:55 ` [PATCH v6 02/10] tests/qtest: Fix virtio msix message endianness Jishnu Warrier
2026-08-17 18:55 ` [PATCH v6 03/10] tests/qtest: Add libqos function for testing msix interrupt status Jishnu Warrier
2026-08-17 18:55 ` [PATCH v6 04/10] tests/qtest: Enable spapr dma with linear iommu map Jishnu Warrier
2026-08-18 19:50 ` Fabiano Rosas
2026-08-17 18:55 ` [PATCH v6 05/10] tests/qtest/ahci: unmap pci bar before reusing device Jishnu Warrier
2026-08-17 18:55 ` [PATCH v6 06/10] tests/qtest/ahci: don't unmap pci bar if it wasn't mapped Jishnu Warrier
2026-08-17 18:55 ` [PATCH v6 07/10] tests/qtest/libquos/pci: Add migration fixup helper for pci devices Jishnu Warrier
2026-08-17 18:55 ` Jishnu Warrier [this message]
2026-08-17 18:55 ` [PATCH v6 09/10] qtest/libqos/pci: Fix qpci_msix_enable sharing bar0 Jishnu Warrier
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260817185539.376740-9-jishnuvw@linux.ibm.com \
--to=jishnuvw@linux.ibm.com \
--cc=adityag@linux.ibm.com \
--cc=akihiko.odaki@daynix.com \
--cc=amachhiw@linux.ibm.com \
--cc=david@gibson.dropbear.id.au \
--cc=farosas@suse.de \
--cc=harshpb@linux.ibm.com \
--cc=marcel.apfelbaum@gmail.com \
--cc=mst@redhat.com \
--cc=npiggin@gmail.com \
--cc=philmd@linaro.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.