new file mode 100644
@@ -0,0 +1,15 @@
+/*
+ * QEMU MMIO test device
+ *
+ * Copyright (C) 2020 Philippe Mathieu-Daudé <f4bug@amsat.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HW_MISC_TESTDEV_H
+#define HW_MISC_TESTDEV_H
+
+#define TYPE_MMIO_TESTDEV "mmio-testdev"
+
+#endif
+
new file mode 100644
@@ -0,0 +1,146 @@
+/*
+ * QEMU MMIO test device
+ *
+ * Copyright (C) 2020 Philippe Mathieu-Daudé <f4bug@amsat.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+/*
+ * This device is mostly used to test QEMU internal MMIO devices.
+ * Accesses using CPU core are not allowed.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qapi/error.h"
+#include "hw/qdev-properties.h"
+#include "hw/sysbus.h"
+#include "exec/address-spaces.h"
+#include "hw/misc/testdev.h"
+#include "hw/misc/interleaver.h"
+
+/*
+ * Device Memory Map:
+ *
+ * offset size description
+ * ---------- ---------- --------------------
+ * 0x00000000 [ 2 KiB] SRAM (8 banks of 256B)
+ * 0x10000000 [ 128 MiB] interleaved-container
+ * 0x11608000 [ 4 KiB] interleaved-16x8 (each device interleaves the sram)
+ * 0x13208000 [ 8 KiB] interleaved-32x8 "
+ * 0x13216000 [ 4 KiB] interleaved-32x16 "
+ * 0x16408000 [ 16 KiB] interleaved-64x8 "
+ * 0x16416000 [ 8 KiB] interleaved-64x16 "
+ * 0x16432000 [ 4 KiB] interleaved-64x32 "
+ * 0x20000000 [ 256 MiB] container
+ *
+ * All gap regions are reserved.
+ */
+
+typedef struct MmioTestDevice {
+ /*< private >*/
+ SysBusDevice parent_obj;
+ /*< public >*/
+
+ MemoryRegion container;
+ MemoryRegion sram;
+ MemoryRegion sram_alias[8];
+ MemoryRegion interleaver_container;
+ MemoryRegion iomem;
+
+ uint64_t base;
+} MmioTestDevice;
+
+#define TESTDEV(obj) \
+ OBJECT_CHECK(MmioTestDevice, (obj), TYPE_MMIO_TESTDEV)
+
+static void mmio_testdev_realize(DeviceState *dev, Error **errp)
+{
+ static const unsigned bhexs[] = {
+ [8] = 0x8, [16] = 0x16, [32] = 0x32, [64] = 0x64,
+ };
+ static const struct {
+ unsigned in, out;
+ const char *typename;
+ } cfg[] = {
+ {16, 8, TYPE_INTERLEAVER_16X8_DEVICE},
+ {32, 8, TYPE_INTERLEAVER_32X8_DEVICE},
+ {32, 16, TYPE_INTERLEAVER_32X16_DEVICE},
+ {64, 8, TYPE_INTERLEAVER_64X8_DEVICE},
+ {64, 16, TYPE_INTERLEAVER_64X16_DEVICE},
+ {64, 32, TYPE_INTERLEAVER_64X32_DEVICE},
+ };
+ MmioTestDevice *s = TESTDEV(dev);
+ DeviceState *interleaver;
+
+ if (s->base == UINT64_MAX) {
+ error_setg(errp, "property 'address' not specified or zero");
+ return;
+ }
+
+ memory_region_init(&s->container, OBJECT(s), "testdev", 0x20000000);
+
+ memory_region_init_ram(&s->sram, OBJECT(s), "testdev-sram",
+ 0x800, &error_fatal);
+ memory_region_add_subregion(&s->container, 0x000000, &s->sram);
+
+ /* interleaved memory */
+ memory_region_init(&s->interleaver_container, OBJECT(s),
+ "interleaver-container", 0x8000000);
+ memory_region_add_subregion(&s->container, 0x10000000,
+ &s->interleaver_container);
+ for (unsigned i = 0; i < 8; i++) {
+ g_autofree char *name = g_strdup_printf("sram-p%u", i);
+ /* Each alias access a 256B region of the SRAM */
+ memory_region_init_alias(&s->sram_alias[i], OBJECT(s), name,
+ &s->sram, i * 0x100, 0x100);
+ }
+ for (size_t i = 0; i < ARRAY_SIZE(cfg); i++) {
+ unsigned count = cfg[i].in / cfg[i].out;
+
+ interleaver = qdev_new(cfg[i].typename);
+ qdev_prop_set_uint64(interleaver, "size", count * 0x100);
+ /* Map 256B SRAM regions on interleaver banks */
+ for (unsigned c = 0; c < count; c++) {
+ g_autofree char *prop_name = g_strdup_printf("mr%u", c);
+ object_property_set_link(OBJECT(interleaver), prop_name,
+ OBJECT(&s->sram_alias[c]), &error_abort);
+ }
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(interleaver), &error_fatal);
+ memory_region_add_subregion(&s->interleaver_container,
+ (bhexs[cfg[i].in] << 20) | (bhexs[cfg[i].out] << 12),
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(interleaver), 0));
+ }
+
+ memory_region_add_subregion(get_system_memory(), s->base, &s->container);
+}
+
+static Property mmio_testdev_properties[] = {
+ DEFINE_PROP_UINT64("address", MmioTestDevice, base, UINT64_MAX),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void mmio_testdev_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = mmio_testdev_realize;
+ dc->user_creatable = true;
+ device_class_set_props(dc, mmio_testdev_properties);
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+}
+
+static const TypeInfo mmio_testdev_info = {
+ .name = TYPE_MMIO_TESTDEV,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(MmioTestDevice),
+ .class_init = mmio_testdev_class_init,
+};
+
+static void mmio_testdev_register_types(void)
+{
+ type_register_static(&mmio_testdev_info);
+}
+
+type_init(mmio_testdev_register_types)
@@ -1966,6 +1966,8 @@ M: Philippe Mathieu-Daudé <f4bug@amsat.org>
S: Maintained
F: include/hw/misc/interleaver.h
F: hw/misc/interleaver.c
+F: hw/misc/mmio-testdev.c
+F: include/hw/misc/testdev.h
Standard VGA
M: Gerd Hoffmann <kraxel@redhat.com>
@@ -30,6 +30,11 @@ config ISA_TESTDEV
default y if TEST_DEVICES
depends on ISA_BUS
+config MMIO_TESTDEV
+ bool
+ default y if TEST_DEVICES
+ depends on INTERLEAVER
+
config PCI_TESTDEV
bool
default y if TEST_DEVICES
@@ -5,6 +5,7 @@ common-obj-$(CONFIG_TMP421) += tmp421.o
common-obj-$(CONFIG_ISA_DEBUG) += debugexit.o
common-obj-$(CONFIG_SGA) += sga.o
common-obj-$(CONFIG_ISA_TESTDEV) += pc-testdev.o
+common-obj-$(CONFIG_MMIO_TESTDEV) += mmio-testdev.o
common-obj-$(CONFIG_PCI_TESTDEV) += pci-testdev.o
common-obj-$(CONFIG_EDU) += edu.o
common-obj-$(CONFIG_PCA9552) += pca9552.o
Add a MMIO test device handy to test QEMU internal devices via MMIO accesses. This device is meant to be run by the 'none' machine, thus no CPU is required. So far it is only useful to test the interleaver device. A SRAM region is split into 256B subregions, and these subregions are mapped at different addresses in an interleaved setup. All the following (INPUT x OUTPUT) configurations can be tested: 16x8, 32x8, 32x16, 64x8, 64x16 and 64x32. Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org> --- include/hw/misc/testdev.h | 15 ++++ hw/misc/mmio-testdev.c | 146 ++++++++++++++++++++++++++++++++++++++ MAINTAINERS | 2 + hw/misc/Kconfig | 5 ++ hw/misc/Makefile.objs | 1 + 5 files changed, 169 insertions(+) create mode 100644 include/hw/misc/testdev.h create mode 100644 hw/misc/mmio-testdev.c