The virt machine creates its VirtIO MMIO transports one at a time. Each transport maps its register region while the board is still being initialized, publishing intermediate memory topology updates.
Enclose the transport creation loop in a memory region transaction so that its mappings are published together at commit. Keep each transport's creation, address and interrupt connection unchanged. The transaction is committed before initializing the following board devices and before any guest execution. Add a QTest case that checks all eight transport register windows, the attached RNG device and guest RAM access. Verify the transport registers again after system reset. Exercise both legacy and modern transports with one, two and four vCPUs. --- MAINTAINERS | 2 + hw/riscv/virt.c | 3 ++ tests/qtest/meson.build | 3 ++ tests/qtest/riscv-virt-mmio-test.c | 65 ++++++++++++++++++++++++++++++ 4 files changed, 73 insertions(+) create mode 100644 tests/qtest/riscv-virt-mmio-test.c diff --git a/MAINTAINERS b/MAINTAINERS index 70e9fed776..a6a2c027eb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -387,6 +387,7 @@ F: tests/functional/riscv64 F: tests/tcg/riscv32/ F: tests/tcg/riscv64/ F: tests/qtest/iommu-riscv-test.c +F: tests/qtest/riscv-virt-mmio-test.c RISC-V XThead* extensions M: Christoph Muellner <[email protected]> @@ -3755,6 +3756,7 @@ F: scripts/qom-cast-macro-clean-cocci-gen.py F: qom/ F: stubs/qom-compat-properties.c F: tests/unit/check-qom-interface.c +F: tests/unit/check-qom-enumeration.c F: tests/unit/check-qom-proplist.c F: tests/qtest/qom-test.c diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index de1c92463a..c4f06bcdcf 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -898,11 +898,14 @@ static void virt_machine_init(MachineState *machine) sifive_test_create(s->memmap[VIRT_TEST].base); /* VirtIO MMIO devices */ + /* Publish the transport mappings together before any guest execution. */ + memory_region_transaction_begin(); for (i = 0; i < VIRTIO_COUNT; i++) { sysbus_create_simple("virtio-mmio", s->memmap[VIRT_VIRTIO].base + i * s->memmap[VIRT_VIRTIO].size, qdev_get_gpio_in(virtio_irqchip, VIRTIO_IRQ + i)); } + memory_region_transaction_commit(); riscv_gpex_pcie_init(system_memory, pcie_irqchip, &s->memmap[VIRT_PCIE_ECAM], &s->memmap[VIRT_PCIE_MMIO], diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index 46d4fc1d2b..2cc4fe71cd 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -313,6 +313,9 @@ qtests_riscv32 = \ (config_all_devices.has_key('CONFIG_SIFIVE_E_AON') ? ['sifive-e-aon-watchdog-test'] : []) qtests_riscv64 = ['riscv-csr-test'] + \ + (config_all_devices.has_key('CONFIG_RISCV_VIRT') and + config_all_devices.has_key('CONFIG_VIRTIO_RNG') ? + ['riscv-virt-mmio-test'] : []) + \ (unpack_edk2_blobs ? ['bios-tables-test'] : []) + \ (config_all_devices.has_key('CONFIG_IOMMU_TESTDEV') and config_all_devices.has_key('CONFIG_RISCV_IOMMU') ? diff --git a/tests/qtest/riscv-virt-mmio-test.c b/tests/qtest/riscv-virt-mmio-test.c new file mode 100644 index 0000000000..3c55b37f51 --- /dev/null +++ b/tests/qtest/riscv-virt-mmio-test.c @@ -0,0 +1,65 @@ +/* + * Check RISC-V virt MMIO transports before and after reset. + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "libqtest.h" + +#define VIRTIO_BASE 0x10001000 +#define VIRTIO_STRIDE 0x1000 +#define VIRTIO_TRANSPORTS 8 + +static void check_transports(QTestState *qts, bool modern) +{ + unsigned attached = 0; + + for (unsigned i = 0; i < VIRTIO_TRANSPORTS; i++) { + uint64_t base = VIRTIO_BASE + i * VIRTIO_STRIDE; + uint32_t device = qtest_readl(qts, base + 8); + + g_assert_cmphex(qtest_readl(qts, base), ==, 0x74726976); + g_assert_cmpuint(qtest_readl(qts, base + 4), ==, modern ? 2 : 1); + g_assert_cmpuint(qtest_readl(qts, base + 0x70), ==, 0); + if (device) { + g_assert_cmpuint(device, ==, 4); + attached++; + } + } + g_assert_cmpuint(attached, ==, 1); +} + +static void test_transports(gconstpointer opaque) +{ + unsigned setting = GPOINTER_TO_UINT(opaque); + unsigned cpus = 1U << (setting / 2); + bool modern = setting % 2; + QTestState *qts = qtest_initf( + "-machine virt -bios none -m 64M -smp %u -nodefaults " + "-global virtio-mmio.force-legacy=%s -device virtio-rng-device", + cpus, modern ? "false" : "true"); + + check_transports(qts, modern); + qtest_writel(qts, 0x80001000, 0x12345678); + g_assert_cmphex(qtest_readl(qts, 0x80001000), ==, 0x12345678); + qtest_system_reset(qts); + check_transports(qts, modern); + qtest_quit(qts); +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + + if (qtest_has_machine("virt")) { + for (unsigned setting = 0; setting < 6; setting++) { + g_autofree char *name = g_strdup_printf( + "/riscv/virt/mmio/%u-cpus/%s", 1U << (setting / 2), + setting % 2 ? "modern" : "legacy"); + + qtest_add_data_func(name, GUINT_TO_POINTER(setting), + test_transports); + } + } + return g_test_run(); +} -- 2.47.0.windows.1
