[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[RFC PATCH-for-6.1 01/10] hw/misc: Add device to help managing aliased m
From: |
Philippe Mathieu-Daudé |
Subject: |
[RFC PATCH-for-6.1 01/10] hw/misc: Add device to help managing aliased memory regions |
Date: |
Fri, 26 Mar 2021 01:27:19 +0100 |
// TODO explain here how buses work? when some address lines are
// not bound we get memory aliasing, high addresses are masked.
// etc...
Add a helper to manage this use case easily.
For example a having @span_size = @region_size / 4 we get such mapping:
^-----------^
| |
| |
| +-------+ | +---------+ <--+
| | +---------+ |
| | | | |
| | +-----------> | alias#3 | |
| | | | | |
| | | +---------+ |
| | | +---------+ |
| | | | | |
| | | +-------> | alias#2 | |
| | | | | | |region
| container | | | +---------+ | size
| | | | +---------+ |
| | | | | | |
| | | | +----> | alias#1 | |
| | | | | | | |
| | | | | +---------+ <--+ |
| | +-+---+--+--+ +---------+ | |
| | | | | | |span |
| | | subregion +-> | alias#0 | |size |
offset | | | | | | | |
+----> | +-------+ | +-----------+ +---------+ <--+ <--+
| | |
| | |
| | |
| | |
| | |
| ^-----------^
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
---
include/hw/misc/aliased_region.h | 87 ++++++++++++++++++++
hw/misc/aliased_region.c | 133 +++++++++++++++++++++++++++++++
MAINTAINERS | 6 ++
hw/misc/Kconfig | 3 +
hw/misc/meson.build | 1 +
5 files changed, 230 insertions(+)
create mode 100644 include/hw/misc/aliased_region.h
create mode 100644 hw/misc/aliased_region.c
diff --git a/include/hw/misc/aliased_region.h b/include/hw/misc/aliased_region.h
new file mode 100644
index 00000000000..0ce0d5d1cef
--- /dev/null
+++ b/include/hw/misc/aliased_region.h
@@ -0,0 +1,87 @@
+/*
+ * Aliased memory regions
+ *
+ * Copyright (c) 2018 Philippe Mathieu-Daudé <f4bug@amsat.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HW_MISC_ALIASED_REGION_H
+#define HW_MISC_ALIASED_REGION_H
+
+#include "exec/memory.h"
+#include "hw/sysbus.h"
+
+#define TYPE_ALIASED_REGION "aliased-memory-region"
+OBJECT_DECLARE_SIMPLE_TYPE(AliasedRegionState, ALIASED_REGION)
+
+struct AliasedRegionState {
+ /*< private >*/
+ SysBusDevice parent_obj;
+
+ /*< public >*/
+ MemoryRegion container;
+ uint64_t region_size;
+ uint64_t span_size;
+ MemoryRegion *mr;
+
+ struct {
+ size_t count;
+ MemoryRegion *alias;
+ } mem;
+};
+
+/**
+ * memory_region_add_subregion_aliased:
+ * @container: the #MemoryRegion to contain the aliased subregions.
+ * @offset: the offset relative to @container where the aliased subregion
+ * are added.
+ * @region_size: size of the region containing the aliased subregions.
+ * @subregion: the subregion to be aliased.
+ * @span_size: size between each aliased subregion
+ *
+ * This utility function creates and maps an instance of aliased-memory-region,
+ * which is a dummy device of a single region which simply contains multiple
+ * aliases of the provided @subregion, spanned over the @region_size every
+ * @span_size. The device is mapped at @offset within @container.
+ *
+ * For example a having @span_size = @region_size / 4 we get such mapping:
+ *
+ * +-----------+
+ * | |
+ * | |
+ * | +-------+ | +---------+ <--+
+ * | | +---------+ |
+ * | | | | |
+ * | | +-----------> | alias#3 | |
+ * | | | | | |
+ * | | | +---------+ |
+ * | | | +---------+ |
+ * | | | | | |
+ * | | | +-------> | alias#2 | |
+ * | | | | | | |region
+ * | container | | | +---------+ | size
+ * | | | | +---------+ |
+ * | | | | | | |
+ * | | | | +----> | alias#1 | |
+ * | | | | | | | |
+ * | | | | | +---------+ <--+ |
+ * | | +-+---+--+--+ +---------+ | |
+ * | | | | | | |span |
+ * | | | subregion +-> | alias#0 | |size |
+ * offset | | | | | | | |
+ * +----> | +-------+ | +-----------+ +---------+ <--+ <--+
+ * | | |
+ * | | |
+ * | | |
+ * | | |
+ * | | |
+ * + +-----------+
+ */
+void memory_region_add_subregion_aliased(MemoryRegion *container,
+ hwaddr offset,
+ uint64_t region_size,
+ MemoryRegion *subregion,
+ uint64_t span_size);
+
+#endif
diff --git a/hw/misc/aliased_region.c b/hw/misc/aliased_region.c
new file mode 100644
index 00000000000..8fcc63f2648
--- /dev/null
+++ b/hw/misc/aliased_region.c
@@ -0,0 +1,133 @@
+/*
+ * Aliased memory regions
+ *
+ * Copyright (c) 2018 Philippe Mathieu-Daudé <f4bug@amsat.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/cutils.h"
+#include "qapi/error.h"
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "hw/misc/aliased_region.h"
+#include "hw/qdev-properties.h"
+
+static void aliased_mem_realize(AliasedRegionState *s, const char *mr_name)
+{
+ uint64_t subregion_size;
+ int subregion_bits;
+
+ memory_region_init(&s->container, OBJECT(s), mr_name, s->region_size);
+
+ subregion_bits = 64 - clz64(s->span_size - 1);
+ s->mem.count = s->region_size >> subregion_bits;
+ assert(s->mem.count > 1);
+ subregion_size = 1ULL << subregion_bits;
+
+ s->mem.alias = g_new(MemoryRegion, s->mem.count);
+ for (size_t i = 0; i < s->mem.count; i++) {
+ g_autofree char *name = g_strdup_printf("%s [#%zu/%zu]",
+ memory_region_name(s->mr),
+ i, s->mem.count);
+ memory_region_init_alias(&s->mem.alias[i], OBJECT(s), name,
+ s->mr, 0, s->span_size);
+ memory_region_add_subregion(&s->container, i * subregion_size,
+ &s->mem.alias[i]);
+ }
+}
+
+static void aliased_mr_realize(DeviceState *dev, Error **errp)
+{
+ AliasedRegionState *s = ALIASED_REGION(dev);
+ g_autofree char *name = NULL, *span = NULL;
+
+ if (s->region_size == 0) {
+ error_setg(errp, "property 'region-size' not specified or zero");
+ return;
+ }
+
+ if (s->mr == NULL) {
+ error_setg(errp, "property 'iomem' not specified");
+ return;
+ }
+
+ if (!s->span_size) {
+ s->span_size = pow2ceil(memory_region_size(s->mr));
+ } else if (!is_power_of_2(s->span_size)) {
+ error_setg(errp, "property 'span-size' must be a power of 2");
+ return;
+ }
+
+ span = size_to_str(s->span_size);
+ name = g_strdup_printf("masked %s [span of %s]",
+ memory_region_name(s->mr), span);
+ aliased_mem_realize(s, name);
+ sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->container);
+}
+
+static void aliased_mr_unrealize(DeviceState *dev)
+{
+ AliasedRegionState *s = ALIASED_REGION(dev);
+
+ g_free(s->mem.alias);
+}
+
+static Property aliased_mr_properties[] = {
+ DEFINE_PROP_UINT64("region-size", AliasedRegionState, region_size, 0),
+ DEFINE_PROP_UINT64("span-size", AliasedRegionState, span_size, 0),
+ DEFINE_PROP_LINK("iomem", AliasedRegionState, mr,
+ TYPE_MEMORY_REGION, MemoryRegion *),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void aliased_mr_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = aliased_mr_realize;
+ dc->unrealize = aliased_mr_unrealize;
+ /* Reason: needs to be wired up to work */
+ dc->user_creatable = false;
+ device_class_set_props(dc, aliased_mr_properties);
+}
+
+static const TypeInfo aliased_mr_info = {
+ .name = TYPE_ALIASED_REGION,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(AliasedRegionState),
+ .class_init = aliased_mr_class_init,
+};
+
+static void aliased_mr_register_types(void)
+{
+ type_register_static(&aliased_mr_info);
+}
+
+type_init(aliased_mr_register_types)
+
+void memory_region_add_subregion_aliased(MemoryRegion *container,
+ hwaddr offset,
+ uint64_t region_size,
+ MemoryRegion *subregion,
+ uint64_t span_size)
+{
+ DeviceState *dev;
+
+ if (!region_size) {
+ region_size = pow2ceil(memory_region_size(container));
+ } else {
+ assert(region_size <= memory_region_size(container));
+ }
+
+ dev = qdev_new(TYPE_ALIASED_REGION);
+ qdev_prop_set_uint64(dev, "region-size", region_size);
+ qdev_prop_set_uint64(dev, "span-size", span_size);
+ object_property_set_link(OBJECT(dev), "iomem", OBJECT(subregion),
+ &error_abort);
+ sysbus_realize(SYS_BUS_DEVICE(dev), &error_abort);
+
+ memory_region_add_subregion(container, offset,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(dev),
0));
+}
diff --git a/MAINTAINERS b/MAINTAINERS
index 554be84b321..f82ffd50a91 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2097,6 +2097,12 @@ S: Maintained
F: include/hw/misc/empty_slot.h
F: hw/misc/empty_slot.c
+Aliased memory region
+M: Philippe Mathieu-Daudé <f4bug@amsat.org>
+S: Maintained
+F: include/hw/misc/aliased_region.h
+F: hw/misc/aliased_region.c
+
Standard VGA
M: Gerd Hoffmann <kraxel@redhat.com>
S: Maintained
diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
index c71ed258204..ca51b99989e 100644
--- a/hw/misc/Kconfig
+++ b/hw/misc/Kconfig
@@ -151,6 +151,9 @@ config AUX
config UNIMP
bool
+config ALIASED_REGION
+ bool
+
config LED
bool
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
index 21034dc60a8..e65541b835f 100644
--- a/hw/misc/meson.build
+++ b/hw/misc/meson.build
@@ -12,6 +12,7 @@
softmmu_ss.add(when: 'CONFIG_EMC141X', if_true: files('emc141x.c'))
softmmu_ss.add(when: 'CONFIG_UNIMP', if_true: files('unimp.c'))
softmmu_ss.add(when: 'CONFIG_EMPTY_SLOT', if_true: files('empty_slot.c'))
+softmmu_ss.add(when: 'CONFIG_ALIASED_REGION', if_true:
files('aliased_region.c'))
softmmu_ss.add(when: 'CONFIG_LED', if_true: files('led.c'))
softmmu_ss.add(when: 'CONFIG_PVPANIC_COMMON', if_true: files('pvpanic.c'))
--
2.26.2
- [RFC PATCH-for-6.1 00/10] hw/misc: Add memory_region_add_subregion_aliased() helper, Philippe Mathieu-Daudé, 2021/03/25
- [RFC PATCH-for-6.1 01/10] hw/misc: Add device to help managing aliased memory regions,
Philippe Mathieu-Daudé <=
- [RFC PATCH-for-6.1 03/10] hw/arm/musicpal: Map flash using memory_region_add_subregion_aliased(), Philippe Mathieu-Daudé, 2021/03/25
- [PATCH-for-6.1 02/10] hw/arm/musicpal: Open-code pflash_cfi02_register() call, Philippe Mathieu-Daudé, 2021/03/25
- [PATCH-for-6.1 04/10] hw/arm/digic: Open-code pflash_cfi02_register() call, Philippe Mathieu-Daudé, 2021/03/25
- [RFC PATCH-for-6.1 05/10] hw/arm/digic: Map flash using memory_region_add_subregion_aliased(), Philippe Mathieu-Daudé, 2021/03/25
- [PATCH-for-6.1 06/10] hw/block/pflash_cfi02: Remove pflash_setup_mappings(), Philippe Mathieu-Daudé, 2021/03/25
- [PATCH-for-6.1 07/10] hw/block/pflash_cfi02: Simplify pflash_cfi02_register() prototype, Philippe Mathieu-Daudé, 2021/03/25
- [PATCH-for-6.1 09/10] hw/m68k/q800: Add MacIO container, Philippe Mathieu-Daudé, 2021/03/25