[PATCH 03/13] sandbox: Support memory-mapped I/O

Simon Glass sjg at chromium.org
Wed May 27 18:10:13 CEST 2026


Add a way for calls to readl()/writel() etc. to be picked up by a driver
in order to implement MMIO.

This works by registering some functions, which are then called when
accesses occur.

Add comments to sandbox_read() and sandbox_write() while we are here.

Signed-off-by: Simon Glass <sjg at chromium.org>
---

 arch/sandbox/cpu/mem.c           | 49 +++++++++++++++++++++++
 arch/sandbox/cpu/state.c         |  2 +
 arch/sandbox/include/asm/io.h    | 15 +++++++
 arch/sandbox/include/asm/state.h | 67 ++++++++++++++++++++++++++++++++
 4 files changed, 133 insertions(+)

diff --git a/arch/sandbox/cpu/mem.c b/arch/sandbox/cpu/mem.c
index 54a55c1558c..010dc9c16a0 100644
--- a/arch/sandbox/cpu/mem.c
+++ b/arch/sandbox/cpu/mem.c
@@ -6,6 +6,7 @@
 
 #define LOG_CATEGORY	LOGC_SANDBOX
 
+#include <alist.h>
 #include <errno.h>
 #include <log.h>
 #include <malloc.h>
@@ -231,9 +232,20 @@ void sandbox_map_list(void)
 	}
 }
 
+static bool in_range(const struct sandbox_mmio *mmio, const void *addr)
+{
+	return addr >= mmio->base && addr < mmio->base + mmio->size;
+}
+
 unsigned long sandbox_read(const void *addr, enum sandboxio_size_t size)
 {
 	struct sandbox_state *state = state_get_current();
+	const struct sandbox_mmio *mmio;
+
+	alist_for_each(mmio, &state->mmio) {
+		if (in_range(mmio, addr))
+			return mmio->h_read(mmio->ctx, addr, size);
+	}
 
 	if (!state->allow_memio)
 		return 0;
@@ -255,6 +267,14 @@ unsigned long sandbox_read(const void *addr, enum sandboxio_size_t size)
 void sandbox_write(void *addr, unsigned int val, enum sandboxio_size_t size)
 {
 	struct sandbox_state *state = state_get_current();
+	const struct sandbox_mmio *mmio;
+
+	alist_for_each(mmio, &state->mmio) {
+		if (in_range(mmio, addr)) {
+			mmio->h_write(mmio->ctx, addr, val, size);
+			return;
+		}
+	}
 
 	if (!state->allow_memio)
 		return;
@@ -286,3 +306,32 @@ void sandbox_set_enable_pci_map(int enable)
 {
 	enable_pci_map = enable;
 }
+
+int sandbox_mmio_add(void *base, ulong size, sandbox_mmio_read_func h_read,
+		     sandbox_mmio_write_func h_write, void *ctx)
+{
+	struct sandbox_state *state = state_get_current();
+	struct sandbox_mmio mmio;
+
+	mmio.base = base;
+	mmio.size = size;
+	mmio.h_read = h_read;
+	mmio.h_write = h_write;
+	mmio.ctx = ctx;
+	if (!alist_add(&state->mmio, mmio))
+		return -ENOMEM;
+
+	return 0;
+}
+
+void sandbox_mmio_remove(void *ctx)
+{
+	struct sandbox_state *state = state_get_current();
+	struct sandbox_mmio *from, *to;
+
+	alist_for_each_filter(from, to, &state->mmio) {
+		if (from->ctx != ctx)
+			*to++ = *from;
+	}
+	alist_update_end(&state->mmio, to);
+}
diff --git a/arch/sandbox/cpu/state.c b/arch/sandbox/cpu/state.c
index 6a15c8b0a18..01742b63d05 100644
--- a/arch/sandbox/cpu/state.c
+++ b/arch/sandbox/cpu/state.c
@@ -3,6 +3,7 @@
  * Copyright (c) 2011-2012 The Chromium OS Authors.
  */
 
+#include <alist.h>
 #include <bloblist.h>
 #include <config.h>
 #include <errno.h>
@@ -487,6 +488,7 @@ int state_init(void)
 		printf("Out of memory\n");
 		os_exit(1);
 	}
+	alist_init_struct(&state->mmio, struct sandbox_mmio);
 
 	state_reset_for_test(state);
 	/*
diff --git a/arch/sandbox/include/asm/io.h b/arch/sandbox/include/asm/io.h
index e3034b9c703..99702532bc7 100644
--- a/arch/sandbox/include/asm/io.h
+++ b/arch/sandbox/include/asm/io.h
@@ -41,7 +41,22 @@ void unmap_physmem(const void *vaddr, unsigned long flags);
 /* Map from a pointer to our RAM buffer */
 phys_addr_t map_to_sysmem(const void *ptr);
 
+/**
+ * sandbox_read() - Perform a memory read
+ *
+ * @addr: Pointer to read from
+ * @size: Access size of read
+ * Return: Value obtained
+ */
 unsigned long sandbox_read(const void *addr, enum sandboxio_size_t size);
+
+/**
+ * sandbox_write() - Perform a memory write
+ *
+ * @addr: Pointer to write to
+ * @val: Value to write
+ * @size: Access size of write
+ */
 void sandbox_write(void *addr, unsigned int val, enum sandboxio_size_t size);
 
 #define readb(addr) ({ u8 __v = sandbox_read((const void *)addr, SB_SIZE_8); __v; })
diff --git a/arch/sandbox/include/asm/state.h b/arch/sandbox/include/asm/state.h
index 9dea0980bfc..582d8fa21a5 100644
--- a/arch/sandbox/include/asm/state.h
+++ b/arch/sandbox/include/asm/state.h
@@ -6,11 +6,14 @@
 #ifndef __SANDBOX_STATE_H
 #define __SANDBOX_STATE_H
 
+#include <alist.h>
 #include <sysreset.h>
 #include <stdbool.h>
 #include <linux/list.h>
 #include <linux/stringify.h>
 
+enum sandboxio_size_t;
+
 /**
  * Selects the behavior of the serial terminal.
  *
@@ -64,6 +67,69 @@ struct sandbox_mapmem_entry {
 	struct list_head sibling_node;
 };
 
+/**
+ * sandbox_read() - Read function for sandbox_mmio
+ *
+ * @addr: Pointer to read from
+ * @size: Access size of read
+ * Return: Value obtained
+ */
+typedef long (*sandbox_mmio_read_func)(void *ctx, const void *addr,
+				       enum sandboxio_size_t size);
+
+/**
+ * sandbox_write() - Write function for sandbox_mmio
+ *
+ * @addr: Pointer to write to
+ * @val: Value to write
+ * @size: Access size of write
+ */
+typedef void (*sandbox_mmio_write_func)(void *ctx, void *addr, unsigned int val,
+					enum sandboxio_size_t size);
+
+/**
+ * sandbox_mmio_add() - Add a new MMIO region
+ *
+ * Register a new set of read/write functions to be called for a particular
+ *	memory region
+ *
+ * @base: Base pointer for region
+ * @size: Size of region
+ * @h_read: Read handler
+ * @h_write: Write handler
+ * @ctx: Context pointer to passed to read/write functions
+ */
+int sandbox_mmio_add(void *base, ulong size, sandbox_mmio_read_func h_read,
+		     sandbox_mmio_write_func h_write, void *ctx);
+
+/**
+ * sandbox_mmio_remove() - Remove an MMIO region
+ *
+ * All regions with the given @ctx are removed
+ *
+ * @ctx: Context to search for
+ */
+void sandbox_mmio_remove(void *ctx);
+
+/**
+ * struct sandbox_mmio - defines a region of memory-mapped I/O
+ *
+ * This allows accesses to a region of memory to go through provided functions
+ *
+ * @base: Base pointer of region
+ * @size: Size of region
+ * @h_read: Read handler
+ * @h_write: Write handler
+ * @ctx: Context pointer provided when registering
+ */
+struct sandbox_mmio {
+	void *base;
+	ulong size;
+	sandbox_mmio_read_func h_read;
+	sandbox_mmio_write_func h_write;
+	void *ctx;
+};
+
 /* The complete state of the test system */
 struct sandbox_state {
 	const char *cmd;		/* Command to execute */
@@ -119,6 +185,7 @@ struct sandbox_state {
 	void *other_fdt_buf;		/* 'other' FDT blob used by tests */
 	int other_size;			/* size of other FDT blob */
 
+	struct alist mmio;		/* list of struct sandbox_mmio */
 	/*
 	 * This struct is getting large.
 	 *
-- 
2.43.0



More information about the U-Boot mailing list