From: Ruslan Ruslichenko <Ruslan_Ruslichenko@epam.com>
Introduce a unified 'MemoryTransaction' structure to encapsulate all
parameters of a memory access, including address, data, size, and
attributes.
The logic in memory_region_dispatch_read/write is updated to prioritize
the new 'access' callback when available.
This change simplifies the integration of transaction-based subsystems,
such as the Remote Port, by providing a standard container for memory
access metadata.
Signed-off-by: Edgar E. Iglesias <edgar.iglesias@amd.com>
Signed-off-by: Takahiro Nakata <takahiro.nakata.wr@renesas.com>
Signed-off-by: Ruslan Ruslichenko <Ruslan_Ruslichenko@epam.com>
---
include/system/memory.h | 23 ++++++++++++++
system/memory.c | 66 +++++++++++++++++++++++++++++++++++++++--
2 files changed, 87 insertions(+), 2 deletions(-)
diff --git a/include/system/memory.h b/include/system/memory.h
index 0562af3136..e1fb82608d 100644
--- a/include/system/memory.h
+++ b/include/system/memory.h
@@ -84,6 +84,28 @@ extern unsigned int global_dirty_tracking;
typedef struct MemoryRegionOps MemoryRegionOps;
+typedef struct MemoryTransaction {
+ union {
+ /*
+ * Data is passed by values up to 64bit sizes. Beyond
+ * that, a pointer is passed in p8.
+ *
+ * Note that p8 has no alignment restrictions.
+ */
+ uint8_t *p8;
+ uint64_t u64;
+ uint32_t u32;
+ uint16_t u16;
+ uint8_t u8;
+ } data;
+ bool rw;
+ hwaddr addr;
+ unsigned int size;
+ MemTxAttrs attr;
+ void *opaque;
+} MemoryTransaction;
+
+
struct ReservedRegion {
Range range;
unsigned type;
@@ -298,6 +320,7 @@ static inline void iommu_notifier_init(IOMMUNotifier *n, IOMMUNotify fn,
* Memory region callbacks
*/
struct MemoryRegionOps {
+ MemTxResult (*access)(MemoryTransaction *tr);
/* Read from the memory region. @addr is relative to @mr; @size is
* in bytes. */
uint64_t (*read)(void *opaque,
diff --git a/system/memory.c b/system/memory.c
index 0b1462f028..4f62796cd3 100644
--- a/system/memory.c
+++ b/system/memory.c
@@ -431,6 +431,31 @@ static int get_cpu_index(void)
return -1;
}
+static MemTxResult memory_region_read_accessor_attr(MemoryRegion *mr,
+ hwaddr addr,
+ uint64_t *value,
+ unsigned size,
+ signed shift,
+ uint64_t mask,
+ MemTxAttrs attrs)
+{
+ MemoryTransaction tr = { { 0 } };
+ MemTxResult ret;
+
+ if (mr->flush_coalesced_mmio) {
+ qemu_flush_coalesced_mmio_buffer();
+ }
+
+ tr.opaque = mr->opaque;
+ tr.addr = addr;
+ tr.size = size;
+ tr.attr = attrs;
+ ret = mr->ops->access(&tr);
+ *value |= (tr.data.u64 & mask) << shift;
+
+ return ret;
+}
+
static MemTxResult memory_region_read_accessor(MemoryRegion *mr,
hwaddr addr,
uint64_t *value,
@@ -476,6 +501,31 @@ static MemTxResult memory_region_read_with_attrs_accessor(MemoryRegion *mr,
return r;
}
+static MemTxResult memory_region_write_accessor_attr(MemoryRegion *mr,
+ hwaddr addr,
+ uint64_t *value,
+ unsigned size,
+ signed shift,
+ uint64_t mask,
+ MemTxAttrs attrs)
+{
+ MemoryTransaction tr = { { 0 } };
+
+ if (mr->flush_coalesced_mmio) {
+ qemu_flush_coalesced_mmio_buffer();
+ }
+
+ tr.opaque = mr->opaque;
+ tr.rw = true;
+ tr.addr = addr;
+ tr.size = size;
+ tr.attr = attrs;
+ tr.data.u64 = (*value >> shift) & mask;
+ trace_memory_region_ops_write(get_cpu_index(), mr, tr.addr, tr.data.u64,
+ tr.size, memory_region_name(mr));
+ return mr->ops->access(&tr);
+}
+
static MemTxResult memory_region_write_accessor(MemoryRegion *mr,
hwaddr addr,
uint64_t *value,
@@ -1603,7 +1653,13 @@ static MemTxResult memory_region_dispatch_read1(MemoryRegion *mr,
{
*pval = 0;
- if (mr->ops->read) {
+ if (mr->ops->access) {
+ return access_with_adjusted_size(addr, pval, size,
+ mr->ops->impl.min_access_size,
+ mr->ops->impl.max_access_size,
+ memory_region_read_accessor_attr,
+ mr, attrs);
+ } else if (mr->ops->read) {
return access_with_adjusted_size(addr, pval, size,
mr->ops->impl.min_access_size,
mr->ops->impl.max_access_size,
@@ -1698,7 +1754,13 @@ MemTxResult memory_region_dispatch_write(MemoryRegion *mr,
return MEMTX_OK;
}
- if (mr->ops->write) {
+ if (mr->ops->access) {
+ return access_with_adjusted_size(addr, &data, size,
+ mr->ops->impl.min_access_size,
+ mr->ops->impl.max_access_size,
+ memory_region_write_accessor_attr,
+ mr, attrs);
+ } else if (mr->ops->write) {
return access_with_adjusted_size(addr, &data, size,
mr->ops->impl.min_access_size,
mr->ops->impl.max_access_size,
--
2.43.0