sandbox: Allow reading/writing of RAM buffer

It is useful to be able to save and restore the RAM contents of sandbox
U-Boot either for setting up tests, for later analysys, or for chaining
together multiple tests which need to keep the same memory contents.

Add a function to provide a memory file for U-Boot. This is read on
start-up and written when shutting down. If the file does not exist
on start-up, it will be created when shutting down.

Signed-off-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Simon Glass <sjg@chromium.org>
diff --git a/arch/sandbox/cpu/cpu.c b/arch/sandbox/cpu/cpu.c
index bc7641a..38019e0 100644
--- a/arch/sandbox/cpu/cpu.c
+++ b/arch/sandbox/cpu/cpu.c
@@ -5,11 +5,15 @@
 
 #include <common.h>
 #include <os.h>
+#include <asm/state.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
 void reset_cpu(ulong ignored)
 {
+	if (state_uninit())
+		os_exit(2);
+
 	/* This is considered normal termination for now */
 	os_exit(0);
 }
diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c
index ef6a651..725b505 100644
--- a/arch/sandbox/cpu/os.c
+++ b/arch/sandbox/cpu/os.c
@@ -399,3 +399,42 @@
 	while (*str)
 		os_putc(*str++);
 }
+
+int os_write_ram_buf(const char *fname)
+{
+	struct sandbox_state *state = state_get_current();
+	int fd, ret;
+
+	fd = open(fname, O_CREAT | O_WRONLY, 0777);
+	if (fd < 0)
+		return -ENOENT;
+	ret = write(fd, state->ram_buf, state->ram_size);
+	close(fd);
+	if (ret != state->ram_size)
+		return -EIO;
+
+	return 0;
+}
+
+int os_read_ram_buf(const char *fname)
+{
+	struct sandbox_state *state = state_get_current();
+	int fd, ret;
+	int size;
+
+	size = os_get_filesize(fname);
+	if (size < 0)
+		return -ENOENT;
+	if (size != state->ram_size)
+		return -ENOSPC;
+	fd = open(fname, O_RDONLY);
+	if (fd < 0)
+		return -ENOENT;
+
+	ret = read(fd, state->ram_buf, state->ram_size);
+	close(fd);
+	if (ret != state->ram_size)
+		return -EIO;
+
+	return 0;
+}
diff --git a/arch/sandbox/cpu/start.c b/arch/sandbox/cpu/start.c
index 579ece4..452f2a9 100644
--- a/arch/sandbox/cpu/start.c
+++ b/arch/sandbox/cpu/start.c
@@ -4,12 +4,11 @@
  */
 
 #include <common.h>
+#include <os.h>
 #include <asm/getopt.h>
 #include <asm/sections.h>
 #include <asm/state.h>
 
-#include <os.h>
-
 DECLARE_GLOBAL_DATA_PTR;
 
 int sandbox_early_getopt_check(void)
@@ -108,6 +107,25 @@
 
 SANDBOX_CMDLINE_OPT_SHORT(interactive, 'i', 0, "Enter interactive mode");
 
+static int sandbox_cmdline_cb_memory(struct sandbox_state *state,
+				     const char *arg)
+{
+	int err;
+
+	/* For now assume we always want to write it */
+	state->write_ram_buf = true;
+	state->ram_buf_fname = arg;
+
+	if (os_read_ram_buf(arg)) {
+		printf("Failed to read RAM buffer\n");
+		return err;
+	}
+
+	return 0;
+}
+SANDBOX_CMDLINE_OPT_SHORT(memory, 'm', 1,
+			  "Read/write ram_buf memory contents from file");
+
 int main(int argc, char *argv[])
 {
 	struct sandbox_state *state;
diff --git a/arch/sandbox/cpu/state.c b/arch/sandbox/cpu/state.c
index 56d5041..0380fe2 100644
--- a/arch/sandbox/cpu/state.c
+++ b/arch/sandbox/cpu/state.c
@@ -4,6 +4,7 @@
  */
 
 #include <common.h>
+#include <os.h>
 #include <asm/state.h>
 
 /* Main state record for the sandbox */
@@ -25,6 +26,10 @@
 {
 	state = &main_state;
 
+	state->ram_size = CONFIG_SYS_SDRAM_SIZE;
+	state->ram_buf = os_malloc(state->ram_size);
+	assert(state->ram_buf);
+
 	/*
 	 * Example of how to use GPIOs:
 	 *
@@ -33,3 +38,20 @@
 	 */
 	return 0;
 }
+
+int state_uninit(void)
+{
+	int err;
+
+	state = &main_state;
+
+	if (state->write_ram_buf) {
+		err = os_write_ram_buf(state->ram_buf_fname);
+		if (err) {
+			printf("Failed to write RAM buffer\n");
+			return err;
+		}
+	}
+
+	return 0;
+}
diff --git a/arch/sandbox/include/asm/global_data.h b/arch/sandbox/include/asm/global_data.h
index d70532a..b2e9b48 100644
--- a/arch/sandbox/include/asm/global_data.h
+++ b/arch/sandbox/include/asm/global_data.h
@@ -12,7 +12,7 @@
 
 /* Architecture-specific global data */
 struct arch_global_data {
-	u8		*ram_buf;	/* emulated RAM buffer */
+	uint8_t		*ram_buf;	/* emulated RAM buffer */
 };
 
 #include <asm-generic/global_data.h>
diff --git a/arch/sandbox/include/asm/state.h b/arch/sandbox/include/asm/state.h
index df196b79..e4b4c72 100644
--- a/arch/sandbox/include/asm/state.h
+++ b/arch/sandbox/include/asm/state.h
@@ -30,6 +30,10 @@
 	const char *parse_err;		/* Error to report from parsing */
 	int argc;			/* Program arguments */
 	char **argv;
+	uint8_t *ram_buf;		/* Emulated RAM buffer */
+	unsigned int ram_size;		/* Size of RAM buffer */
+	const char *ram_buf_fname;	/* Filename to use for RAM buffer */
+	bool write_ram_buf;		/* Write RAM buffer on exit */
 
 	/* Pointer to information for each SPI bus/cs */
 	struct sandbox_spi_info spi[CONFIG_SANDBOX_SPI_MAX_BUS]
@@ -55,4 +59,12 @@
  */
 int state_init(void);
 
+/**
+ * Uninitialize the test system state, writing out state if configured to
+ * do so.
+ *
+ * @return 0 if OK, -ve on error
+ */
+int state_uninit(void);
+
 #endif