Merge branch 'master' of git://git.denx.de/u-boot-sh
diff --git a/arch/sandbox/cpu/cpu.c b/arch/sandbox/cpu/cpu.c
index cfc1fda..38019e0 100644
--- a/arch/sandbox/cpu/cpu.c
+++ b/arch/sandbox/cpu/cpu.c
@@ -5,13 +5,23 @@
 
 #include <common.h>
 #include <os.h>
+#include <asm/state.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
-int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+void reset_cpu(ulong ignored)
 {
+	if (state_uninit())
+		os_exit(2);
+
 	/* This is considered normal termination for now */
 	os_exit(0);
+}
+
+int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	reset_cpu(0);
+
 	return 0;
 }
 
@@ -28,7 +38,14 @@
 
 int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
 {
-	return -1;
+	if (flag & (BOOTM_STATE_OS_GO | BOOTM_STATE_OS_FAKE_GO)) {
+		bootstage_mark(BOOTSTAGE_ID_RUN_OS);
+		printf("## Transferring control to Linux (at address %08lx)...\n",
+		       images->ep);
+		reset_cpu(0);
+	}
+
+	return 0;
 }
 
 int cleanup_before_linux(void)
diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c
index 26f44cb..725b505 100644
--- a/arch/sandbox/cpu/os.c
+++ b/arch/sandbox/cpu/os.c
@@ -27,6 +27,10 @@
 
 /* Operating System Interface */
 
+struct os_mem_hdr {
+	size_t length;		/* number of bytes in the block */
+};
+
 ssize_t os_read(int fd, void *buf, size_t count)
 {
 	return read(fd, buf, count);
@@ -128,8 +132,45 @@
 
 void *os_malloc(size_t length)
 {
-	return mmap(NULL, length, PROT_READ | PROT_WRITE,
-			MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+	struct os_mem_hdr *hdr;
+
+	hdr = mmap(NULL, length + sizeof(*hdr), PROT_READ | PROT_WRITE,
+		   MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+	if (hdr == MAP_FAILED)
+		return NULL;
+	hdr->length = length;
+
+	return hdr + 1;
+}
+
+void *os_free(void *ptr)
+{
+	struct os_mem_hdr *hdr = ptr;
+
+	hdr--;
+	if (ptr)
+		munmap(hdr, hdr->length + sizeof(*hdr));
+}
+
+void *os_realloc(void *ptr, size_t length)
+{
+	struct os_mem_hdr *hdr = ptr;
+	void *buf = NULL;
+
+	hdr--;
+	if (length != 0) {
+		buf = os_malloc(length);
+		if (!buf)
+			return buf;
+		if (ptr) {
+			if (length > hdr->length)
+				length = hdr->length;
+			memcpy(buf, ptr, length);
+		}
+	}
+	os_free(ptr);
+
+	return buf;
 }
 
 void os_usleep(unsigned long usec)
@@ -347,3 +388,53 @@
 		return ret;
 	return buf.st_size;
 }
+
+void os_putc(int ch)
+{
+	putchar(ch);
+}
+
+void os_puts(const char *str)
+{
+	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 1b15454..1df21d4 100644
--- a/arch/sandbox/cpu/start.c
+++ b/arch/sandbox/cpu/start.c
@@ -4,11 +4,12 @@
  */
 
 #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)
 {
@@ -50,9 +51,9 @@
 
 		/* then the long flag */
 		if (opt->has_arg)
-			printf("--%-*s", max_noarg_len, opt->flag);
-		else
 			printf("--%-*s <arg> ", max_arg_len, opt->flag);
+		else
+			printf("--%-*s", max_noarg_len, opt->flag);
 
 		/* finally the help text */
 		printf("  %s\n", opt->help);
@@ -75,7 +76,8 @@
 	/* Execute command if required */
 	if (state->cmd) {
 		run_command_list(state->cmd, -1, 0);
-		os_exit(state->exit_type);
+		if (!state->interactive)
+			os_exit(state->exit_type);
 	}
 
 	return 0;
@@ -96,25 +98,93 @@
 }
 SANDBOX_CMDLINE_OPT_SHORT(fdt, 'd', 1, "Specify U-Boot's control FDT");
 
+static int sandbox_cmdline_cb_interactive(struct sandbox_state *state,
+					  const char *arg)
+{
+	state->interactive = true;
+	return 0;
+}
+
+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");
+
+static int sandbox_cmdline_cb_state(struct sandbox_state *state,
+				    const char *arg)
+{
+	state->state_fname = arg;
+	return 0;
+}
+SANDBOX_CMDLINE_OPT_SHORT(state, 's', 1, "Specify the sandbox state FDT");
+
+static int sandbox_cmdline_cb_read(struct sandbox_state *state,
+				   const char *arg)
+{
+	state->read_state = true;
+	return 0;
+}
+SANDBOX_CMDLINE_OPT_SHORT(read, 'r', 0, "Read the state FDT on startup");
+
+static int sandbox_cmdline_cb_write(struct sandbox_state *state,
+				    const char *arg)
+{
+	state->write_state = true;
+	return 0;
+}
+SANDBOX_CMDLINE_OPT_SHORT(write, 'w', 0, "Write state FDT on exit");
+
+static int sandbox_cmdline_cb_ignore_missing(struct sandbox_state *state,
+					     const char *arg)
+{
+	state->ignore_missing_state_on_read = true;
+	return 0;
+}
+SANDBOX_CMDLINE_OPT_SHORT(ignore_missing, 'n', 0,
+			  "Ignore missing state on read");
+
 int main(int argc, char *argv[])
 {
 	struct sandbox_state *state;
-	int err;
+	int ret;
 
-	err = state_init();
-	if (err)
-		return err;
+	ret = state_init();
+	if (ret)
+		goto err;
 
 	state = state_get_current();
 	if (os_parse_args(state, argc, argv))
 		return 1;
 
-	/*
-	 * Do pre- and post-relocation init, then start up U-Boot. This will
-	 * never return.
-	 */
+	ret = sandbox_read_state(state, state->state_fname);
+	if (ret)
+		goto err;
+
+	/* Do pre- and post-relocation init */
 	board_init_f(0);
 
-	/* NOTREACHED - board_init_f() does not return */
+	board_init_r(gd->new_gd, 0);
+
+	/* NOTREACHED - board_init_r() does not return */
 	return 0;
+
+err:
+	printf("Error %d\n", ret);
+	return 1;
 }
diff --git a/arch/sandbox/cpu/state.c b/arch/sandbox/cpu/state.c
index 56d5041..a145808 100644
--- a/arch/sandbox/cpu/state.c
+++ b/arch/sandbox/cpu/state.c
@@ -4,6 +4,9 @@
  */
 
 #include <common.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <os.h>
 #include <asm/state.h>
 
 /* Main state record for the sandbox */
@@ -15,6 +18,324 @@
 	state->exit_type = exit_type;
 }
 
+static int state_ensure_space(int extra_size)
+{
+	void *blob = state->state_fdt;
+	int used, size, free;
+	void *buf;
+	int ret;
+
+	used = fdt_off_dt_strings(blob) + fdt_size_dt_strings(blob);
+	size = fdt_totalsize(blob);
+	free = size - used;
+	if (free > extra_size)
+		return 0;
+
+	size = used + extra_size;
+	buf = os_malloc(size);
+	if (!buf)
+		return -ENOMEM;
+
+	ret = fdt_open_into(blob, buf, size);
+	if (ret) {
+		os_free(buf);
+		return -EIO;
+	}
+
+	os_free(blob);
+	state->state_fdt = buf;
+	return 0;
+}
+
+static int state_read_file(struct sandbox_state *state, const char *fname)
+{
+	int size;
+	int ret;
+	int fd;
+
+	size = os_get_filesize(fname);
+	if (size < 0) {
+		printf("Cannot find sandbox state file '%s'\n", fname);
+		return -ENOENT;
+	}
+	state->state_fdt = os_malloc(size);
+	if (!state->state_fdt) {
+		puts("No memory to read sandbox state\n");
+		return -ENOMEM;
+	}
+	fd = os_open(fname, OS_O_RDONLY);
+	if (fd < 0) {
+		printf("Cannot open sandbox state file '%s'\n", fname);
+		ret = -EPERM;
+		goto err_open;
+	}
+	if (os_read(fd, state->state_fdt, size) != size) {
+		printf("Cannot read sandbox state file '%s'\n", fname);
+		ret = -EIO;
+		goto err_read;
+	}
+	os_close(fd);
+
+	return 0;
+err_read:
+	os_close(fd);
+err_open:
+	os_free(state->state_fdt);
+	state->state_fdt = NULL;
+
+	return ret;
+}
+
+/***
+ * sandbox_read_state_nodes() - Read state associated with a driver
+ *
+ * This looks through all compatible nodes and calls the read function on
+ * each one, to read in the state.
+ *
+ * If nothing is found, it still calls the read function once, to set up a
+ * single global state for that driver.
+ *
+ * @state: Sandbox state
+ * @io: Method to use for reading state
+ * @blob: FDT containing state
+ * @return 0 if OK, -EINVAL if the read function returned failure
+ */
+int sandbox_read_state_nodes(struct sandbox_state *state,
+			     struct sandbox_state_io *io, const void *blob)
+{
+	int count;
+	int node;
+	int ret;
+
+	debug("   - read %s\n", io->name);
+	if (!io->read)
+		return 0;
+
+	node = -1;
+	count = 0;
+	while (blob) {
+		node = fdt_node_offset_by_compatible(blob, node, io->compat);
+		if (node < 0)
+			return 0;	/* No more */
+		debug("   - read node '%s'\n", fdt_get_name(blob, node, NULL));
+		ret = io->read(blob, node);
+		if (ret) {
+			printf("Unable to read state for '%s'\n", io->compat);
+			return -EINVAL;
+		}
+		count++;
+	}
+
+	/*
+	 * If we got no saved state, call the read function once without a
+	 * node, to set up the global state.
+	 */
+	if (count == 0) {
+		debug("   - read global\n");
+		ret = io->read(NULL, -1);
+		if (ret) {
+			printf("Unable to read global state for '%s'\n",
+			       io->name);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+int sandbox_read_state(struct sandbox_state *state, const char *fname)
+{
+	struct sandbox_state_io *io;
+	const void *blob;
+	bool got_err;
+	int ret;
+
+	if (state->read_state && fname) {
+		ret = state_read_file(state, fname);
+		if (ret == -ENOENT && state->ignore_missing_state_on_read)
+			ret = 0;
+		if (ret)
+			return ret;
+	}
+
+	/* Call all the state read funtcions */
+	got_err = false;
+	blob = state->state_fdt;
+	io = ll_entry_start(struct sandbox_state_io, state_io);
+	for (; io < ll_entry_end(struct sandbox_state_io, state_io); io++) {
+		ret = sandbox_read_state_nodes(state, io, blob);
+		if (ret < 0)
+			got_err = true;
+	}
+
+	if (state->read_state && fname) {
+		debug("Read sandbox state from '%s'%s\n", fname,
+		      got_err ? " (with errors)" : "");
+	}
+
+	return got_err ? -1 : 0;
+}
+
+/***
+ * sandbox_write_state_node() - Write state associated with a driver
+ *
+ * This calls the write function to write out global state for that driver.
+ *
+ * TODO(sjg@chromium.org): Support writing out state from multiple drivers
+ * of the same time. We don't need this yet,and it will be much easier to
+ * do when driver model is available.
+ *
+ * @state: Sandbox state
+ * @io: Method to use for writing state
+ * @return 0 if OK, -EIO if there is a fatal error (such as out of space
+ * for adding the data), -EINVAL if the write function failed.
+ */
+int sandbox_write_state_node(struct sandbox_state *state,
+			     struct sandbox_state_io *io)
+{
+	void *blob;
+	int node;
+	int ret;
+
+	if (!io->write)
+		return 0;
+
+	ret = state_ensure_space(SANDBOX_STATE_MIN_SPACE);
+	if (ret) {
+		printf("Failed to add more space for state\n");
+		return -EIO;
+	}
+
+	/* The blob location can change when the size increases */
+	blob = state->state_fdt;
+	node = fdt_node_offset_by_compatible(blob, -1, io->compat);
+	if (node == -FDT_ERR_NOTFOUND) {
+		node = fdt_add_subnode(blob, 0, io->name);
+		if (node < 0) {
+			printf("Cannot create node '%s': %s\n", io->name,
+			       fdt_strerror(node));
+			return -EIO;
+		}
+
+		if (fdt_setprop_string(blob, node, "compatible", io->compat)) {
+			puts("Cannot set compatible\n");
+			return -EIO;
+		}
+	} else if (node < 0) {
+		printf("Cannot access node '%s': %s\n", io->name,
+		       fdt_strerror(node));
+		return -EIO;
+	}
+	debug("Write state for '%s' to node %d\n", io->compat, node);
+	ret = io->write(blob, node);
+	if (ret) {
+		printf("Unable to write state for '%s'\n", io->compat);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int sandbox_write_state(struct sandbox_state *state, const char *fname)
+{
+	struct sandbox_state_io *io;
+	bool got_err;
+	int size;
+	int ret;
+	int fd;
+
+	/* Create a state FDT if we don't have one */
+	if (!state->state_fdt) {
+		size = 0x4000;
+		state->state_fdt = os_malloc(size);
+		if (!state->state_fdt) {
+			puts("No memory to create FDT\n");
+			return -ENOMEM;
+		}
+		ret = fdt_create_empty_tree(state->state_fdt, size);
+		if (ret < 0) {
+			printf("Cannot create empty state FDT: %s\n",
+			       fdt_strerror(ret));
+			ret = -EIO;
+			goto err_create;
+		}
+	}
+
+	/* Call all the state write funtcions */
+	got_err = false;
+	io = ll_entry_start(struct sandbox_state_io, state_io);
+	ret = 0;
+	for (; io < ll_entry_end(struct sandbox_state_io, state_io); io++) {
+		ret = sandbox_write_state_node(state, io);
+		if (ret == -EIO)
+			break;
+		else if (ret)
+			got_err = true;
+	}
+
+	if (ret == -EIO) {
+		printf("Could not write sandbox state\n");
+		goto err_create;
+	}
+
+	ret = fdt_pack(state->state_fdt);
+	if (ret < 0) {
+		printf("Cannot pack state FDT: %s\n", fdt_strerror(ret));
+		ret = -EINVAL;
+		goto err_create;
+	}
+	size = fdt_totalsize(state->state_fdt);
+	fd = os_open(fname, OS_O_WRONLY | OS_O_CREAT);
+	if (fd < 0) {
+		printf("Cannot open sandbox state file '%s'\n", fname);
+		ret = -EIO;
+		goto err_create;
+	}
+	if (os_write(fd, state->state_fdt, size) != size) {
+		printf("Cannot write sandbox state file '%s'\n", fname);
+		ret = -EIO;
+		goto err_write;
+	}
+	os_close(fd);
+
+	debug("Wrote sandbox state to '%s'%s\n", fname,
+	      got_err ? " (with errors)" : "");
+
+	return 0;
+err_write:
+	os_close(fd);
+err_create:
+	os_free(state->state_fdt);
+
+	return ret;
+}
+
+int state_setprop(int node, const char *prop_name, const void *data, int size)
+{
+	void *blob;
+	int len;
+	int ret;
+
+	fdt_getprop(state->state_fdt, node, prop_name, &len);
+
+	/* Add space for the new property, its name and some overhead */
+	ret = state_ensure_space(size - len + strlen(prop_name) + 32);
+	if (ret)
+		return ret;
+
+	/* This should succeed, barring a mutiny */
+	blob = state->state_fdt;
+	ret = fdt_setprop(blob, node, prop_name, data, size);
+	if (ret) {
+		printf("%s: Unable to set property '%s' in node '%s': %s\n",
+		       __func__, prop_name, fdt_get_name(blob, node, NULL),
+			fdt_strerror(ret));
+		return -ENOSPC;
+	}
+
+	return 0;
+}
+
 struct sandbox_state *state_get_current(void)
 {
 	assert(state);
@@ -25,6 +346,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 +358,31 @@
 	 */
 	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;
+		}
+	}
+
+	if (state->write_state) {
+		if (sandbox_write_state(state, state->state_fname)) {
+			printf("Failed to write sandbox state\n");
+			return -1;
+		}
+	}
+
+	if (state->state_fdt)
+		os_free(state->state_fdt);
+	memset(state, '\0', sizeof(*state));
+
+	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 a38820b..e8e4fea 100644
--- a/arch/sandbox/include/asm/state.h
+++ b/arch/sandbox/include/asm/state.h
@@ -7,6 +7,8 @@
 #define __SANDBOX_STATE_H
 
 #include <config.h>
+#include <stdbool.h>
+#include <linux/stringify.h>
 
 /* How we exited U-Boot */
 enum exit_type_id {
@@ -23,17 +25,92 @@
 /* The complete state of the test system */
 struct sandbox_state {
 	const char *cmd;		/* Command to execute */
+	bool interactive;		/* Enable cmdline after execute */
 	const char *fdt_fname;		/* Filename of FDT binary */
 	enum exit_type_id exit_type;	/* How we exited U-Boot */
 	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 */
+	const char *state_fname;	/* File containing sandbox state */
+	void *state_fdt;		/* Holds saved state for sandbox */
+	bool read_state;		/* Read sandbox state on startup */
+	bool write_state;		/* Write sandbox state on exit */
+	bool ignore_missing_state_on_read;	/* No error if state missing */
 
 	/* Pointer to information for each SPI bus/cs */
 	struct sandbox_spi_info spi[CONFIG_SANDBOX_SPI_MAX_BUS]
 					[CONFIG_SANDBOX_SPI_MAX_CS];
 };
 
+/* Minimum space we guarantee in the state FDT when calling read/write*/
+#define SANDBOX_STATE_MIN_SPACE		0x1000
+
+/**
+ * struct sandbox_state_io - methods to saved/restore sandbox state
+ * @name: Name of of the device tree node, also the name of the variable
+ *	holding this data so it should be an identifier (use underscore
+ *	instead of minus)
+ * @compat: Compatible string for the node containing this state
+ *
+ * @read: Function to read state from FDT
+ *	If data is available, then blob and node will provide access to it. If
+ *	not (blob == NULL and node == -1) this function should set up an empty
+ *	data set for start-of-day.
+ *	@param blob: Pointer to device tree blob, or NULL if no data to read
+ *	@param node: Node offset to read from
+ *	@return 0 if OK, -ve on error
+ *
+ * @write: Function to write state to FDT
+ *	The caller will ensure that there is a node ready for the state. The
+ *	node may already contain the old state, in which case it should be
+ *	overridden. There is guaranteed to be SANDBOX_STATE_MIN_SPACE bytes
+ *	of free space, so error checking is not required for fdt_setprop...()
+ *	calls which add up to less than this much space.
+ *
+ *	For adding larger properties, use state_setprop().
+ *
+ * @param blob: Device tree blob holding state
+ * @param node: Node to write our state into
+ *
+ * Note that it is possible to save data as large blobs or as individual
+ * hierarchical properties. However, unless you intend to keep state files
+ * around for a long time and be able to run an old state file on a new
+ * sandbox, it might not be worth using individual properties for everything.
+ * This is certainly supported, it is just a matter of the effort you wish
+ * to put into the state read/write feature.
+ */
+struct sandbox_state_io {
+	const char *name;
+	const char *compat;
+	int (*write)(void *blob, int node);
+	int (*read)(const void *blob, int node);
+};
+
+/**
+ * SANDBOX_STATE_IO - Declare sandbox state to read/write
+ *
+ * Sandbox permits saving state from one run and restoring it in another. This
+ * allows the test system to retain state between runs and thus better
+ * emulate a real system. Examples of state that might be useful to save are
+ * the emulated GPIOs pin settings, flash memory contents and TPM private
+ * data. U-Boot memory contents is dealth with separately since it is large
+ * and it is not normally useful to save it (since a normal system does not
+ * preserve DRAM between runs). See the '-m' option for this.
+ *
+ * See struct sandbox_state_io above for member documentation.
+ */
+#define SANDBOX_STATE_IO(_name, _compat, _read, _write) \
+	ll_entry_declare(struct sandbox_state_io, _name, state_io) = { \
+		.name = __stringify(_name), \
+		.read = _read, \
+		.write = _write, \
+		.compat = _compat, \
+	}
+
 /**
  * Record the exit type to be reported by the test program.
  *
@@ -49,8 +126,59 @@
 struct sandbox_state *state_get_current(void);
 
 /**
+ * Read the sandbox state from the supplied device tree file
+ *
+ * This calls all registered state handlers to read in the sandbox state
+ * from a previous test run.
+ *
+ * @param state		Sandbox state to update
+ * @param fname		Filename of device tree file to read from
+ * @return 0 if OK, -ve on error
+ */
+int sandbox_read_state(struct sandbox_state *state, const char *fname);
+
+/**
+ * Write the sandbox state to the supplied device tree file
+ *
+ * This calls all registered state handlers to write out the sandbox state
+ * so that it can be preserved for a future test run.
+ *
+ * If the file exists it is overwritten.
+ *
+ * @param state		Sandbox state to update
+ * @param fname		Filename of device tree file to write to
+ * @return 0 if OK, -ve on error
+ */
+int sandbox_write_state(struct sandbox_state *state, const char *fname);
+
+/**
+ * Add a property to a sandbox state node
+ *
+ * This is equivalent to fdt_setprop except that it automatically enlarges
+ * the device tree if necessary. That means it is safe to write any amount
+ * of data here.
+ *
+ * This function can only be called from within struct sandbox_state_io's
+ * ->write method, i.e. within state I/O drivers.
+ *
+ * @param node		Device tree node to write to
+ * @param prop_name	Property to write
+ * @param data		Data to write into property
+ * @param size		Size of data to write into property
+ */
+int state_setprop(int node, const char *prop_name, const void *data, int size);
+
+/**
  * Initialize the test system state
  */
 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
diff --git a/arch/sandbox/include/asm/u-boot-sandbox.h b/arch/sandbox/include/asm/u-boot-sandbox.h
index bed720c..5707c27 100644
--- a/arch/sandbox/include/asm/u-boot-sandbox.h
+++ b/arch/sandbox/include/asm/u-boot-sandbox.h
@@ -23,4 +23,6 @@
 int sandbox_early_getopt_check(void);
 int sandbox_main_loop_init(void);
 
+int cleanup_before_linux(void);
+
 #endif	/* _U_BOOT_SANDBOX_H_ */
diff --git a/common/board_f.c b/common/board_f.c
index fcfd713..c2f47bc 100644
--- a/common/board_f.c
+++ b/common/board_f.c
@@ -347,9 +347,10 @@
 #ifdef CONFIG_SANDBOX
 static int setup_ram_buf(void)
 {
-	gd->arch.ram_buf = os_malloc(CONFIG_SYS_SDRAM_SIZE);
-	assert(gd->arch.ram_buf);
-	gd->ram_size = CONFIG_SYS_SDRAM_SIZE;
+	struct sandbox_state *state = state_get_current();
+
+	gd->arch.ram_buf = state->ram_buf;
+	gd->ram_size = state->ram_size;
 
 	return 0;
 }
@@ -772,7 +773,7 @@
 }
 
 /* ARM calls relocate_code from its crt0.S */
-#if !defined(CONFIG_ARM)
+#if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX)
 
 static int jump_to_copy(void)
 {
@@ -792,8 +793,6 @@
 	 * (CPU cache)
 	 */
 	board_init_f_r_trampoline(gd->start_addr_sp);
-#elif defined(CONFIG_SANDBOX)
-	board_init_r(gd->new_gd, 0);
 #else
 	relocate_code(gd->start_addr_sp, gd->new_gd, gd->relocaddr);
 #endif
@@ -995,7 +994,7 @@
 	INIT_FUNC_WATCHDOG_RESET
 	reloc_fdt,
 	setup_reloc,
-#ifndef CONFIG_ARM
+#if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX)
 	jump_to_copy,
 #endif
 	NULL,
@@ -1015,7 +1014,7 @@
 	if (initcall_run_list(init_sequence_f))
 		hang();
 
-#ifndef CONFIG_ARM
+#if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX)
 	/* NOTREACHED - jump_to_copy() does not return */
 	hang();
 #endif
diff --git a/common/cmd_sandbox.c b/common/cmd_sandbox.c
index 8d59364..00982b1 100644
--- a/common/cmd_sandbox.c
+++ b/common/cmd_sandbox.c
@@ -6,6 +6,9 @@
 
 #include <common.h>
 #include <fs.h>
+#include <part.h>
+#include <sandboxblockdev.h>
+#include <asm/errno.h>
 
 static int do_sandbox_load(cmd_tbl_t *cmdtp, int flag, int argc,
 			   char * const argv[])
@@ -25,10 +28,69 @@
 	return do_save(cmdtp, flag, argc, argv, FS_TYPE_SANDBOX);
 }
 
+static int do_sandbox_bind(cmd_tbl_t *cmdtp, int flag, int argc,
+			   char * const argv[])
+{
+	if (argc < 2 || argc > 3)
+		return CMD_RET_USAGE;
+	char *ep;
+	char *dev_str = argv[1];
+	char *file = argc >= 3 ? argv[2] : NULL;
+	int dev = simple_strtoul(dev_str, &ep, 16);
+	if (*ep) {
+		printf("** Bad device specification %s **\n", dev_str);
+		return CMD_RET_USAGE;
+	}
+	return host_dev_bind(dev, file);
+}
+
+static int do_sandbox_info(cmd_tbl_t *cmdtp, int flag, int argc,
+			   char * const argv[])
+{
+	if (argc < 1 || argc > 2)
+		return CMD_RET_USAGE;
+	int min_dev = 0;
+	int max_dev = CONFIG_HOST_MAX_DEVICES - 1;
+	if (argc >= 2) {
+		char *ep;
+		char *dev_str = argv[1];
+		int dev = simple_strtoul(dev_str, &ep, 16);
+		if (*ep) {
+			printf("** Bad device specification %s **\n", dev_str);
+			return CMD_RET_USAGE;
+		}
+		min_dev = dev;
+		max_dev = dev;
+	}
+	int dev;
+	printf("%3s %12s %s\n", "dev", "blocks", "path");
+	for (dev = min_dev; dev <= max_dev; dev++) {
+		block_dev_desc_t *blk_dev;
+		int ret;
+
+		printf("%3d ", dev);
+		ret = host_get_dev_err(dev, &blk_dev);
+		if (ret) {
+			if (ret == -ENOENT)
+				puts("Not bound to a backing file\n");
+			else if (ret == -ENODEV)
+				puts("Invalid host device number\n");
+
+			continue;
+		}
+		struct host_block_dev *host_dev = blk_dev->priv;
+		printf("%12lu %s\n", (unsigned long)blk_dev->lba,
+		       host_dev->filename);
+	}
+	return 0;
+}
+
 static cmd_tbl_t cmd_sandbox_sub[] = {
 	U_BOOT_CMD_MKENT(load, 7, 0, do_sandbox_load, "", ""),
 	U_BOOT_CMD_MKENT(ls, 3, 0, do_sandbox_ls, "", ""),
 	U_BOOT_CMD_MKENT(save, 6, 0, do_sandbox_save, "", ""),
+	U_BOOT_CMD_MKENT(bind, 3, 0, do_sandbox_bind, "", ""),
+	U_BOOT_CMD_MKENT(info, 3, 0, do_sandbox_info, "", ""),
 };
 
 static int do_sandbox(cmd_tbl_t *cmdtp, int flag, int argc,
@@ -57,4 +119,6 @@
 	"sb ls host <filename>                      - list files on host\n"
 	"sb save host <dev> <filename> <addr> <bytes> [<offset>] - "
 		"save a file to host\n"
+	"sb bind <dev> [<filename>] - bind \"host\" device to file\n"
+	"sb info [<dev>]            - show device binding & info"
 );
diff --git a/common/console.c b/common/console.c
index cc55068..2dfb788 100644
--- a/common/console.c
+++ b/common/console.c
@@ -8,6 +8,7 @@
 #include <common.h>
 #include <stdarg.h>
 #include <malloc.h>
+#include <os.h>
 #include <serial.h>
 #include <stdio_dev.h>
 #include <exports.h>
@@ -415,6 +416,12 @@
 
 void putc(const char c)
 {
+#ifdef CONFIG_SANDBOX
+	if (!gd) {
+		os_putc(c);
+		return;
+	}
+#endif
 #ifdef CONFIG_SILENT_CONSOLE
 	if (gd->flags & GD_FLG_SILENT)
 		return;
@@ -439,6 +446,13 @@
 
 void puts(const char *s)
 {
+#ifdef CONFIG_SANDBOX
+	if (!gd) {
+		os_puts(s);
+		return;
+	}
+#endif
+
 #ifdef CONFIG_SILENT_CONSOLE
 	if (gd->flags & GD_FLG_SILENT)
 		return;
@@ -467,7 +481,7 @@
 	uint i;
 	char printbuffer[CONFIG_SYS_PBSIZE];
 
-#ifndef CONFIG_PRE_CONSOLE_BUFFER
+#if !defined(CONFIG_SANDBOX) && !defined(CONFIG_PRE_CONSOLE_BUFFER)
 	if (!gd->have_console)
 		return 0;
 #endif
diff --git a/disk/part.c b/disk/part.c
index d2e34cf..6941033 100644
--- a/disk/part.c
+++ b/disk/part.c
@@ -43,6 +43,9 @@
 #if defined(CONFIG_SYSTEMACE)
 	{ .name = "ace", .get_dev = systemace_get_dev, },
 #endif
+#if defined(CONFIG_SANDBOX)
+	{ .name = "host", .get_dev = host_get_dev, },
+#endif
 	{ },
 };
 
@@ -286,6 +289,9 @@
 	case IF_TYPE_MMC:
 		puts ("MMC");
 		break;
+	case IF_TYPE_HOST:
+		puts("HOST");
+		break;
 	default:
 		puts ("UNKNOWN");
 		break;
diff --git a/drivers/block/Makefile b/drivers/block/Makefile
index 4e94378..8697da4 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -18,5 +18,6 @@
 obj-$(CONFIG_SATA_SIL3114) += sata_sil3114.o
 obj-$(CONFIG_SATA_SIL) += sata_sil.o
 obj-$(CONFIG_IDE_SIL680) += sil680.o
+obj-$(CONFIG_SANDBOX) += sandbox.o
 obj-$(CONFIG_SCSI_SYM53C8XX) += sym53c8xx.o
 obj-$(CONFIG_SYSTEMACE) += systemace.o
diff --git a/drivers/block/sandbox.c b/drivers/block/sandbox.c
new file mode 100644
index 0000000..73f4c4a
--- /dev/null
+++ b/drivers/block/sandbox.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2013 Henrik Nordstrom <henrik@henriknordstrom.net>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <config.h>
+#include <common.h>
+#include <part.h>
+#include <os.h>
+#include <malloc.h>
+#include <sandboxblockdev.h>
+#include <asm/errno.h>
+
+static struct host_block_dev host_devices[CONFIG_HOST_MAX_DEVICES];
+
+static struct host_block_dev *find_host_device(int dev)
+{
+	if (dev >= 0 && dev < CONFIG_HOST_MAX_DEVICES)
+		return &host_devices[dev];
+
+	return NULL;
+}
+
+static unsigned long host_block_read(int dev, unsigned long start,
+				     lbaint_t blkcnt, void *buffer)
+{
+	struct host_block_dev *host_dev = find_host_device(dev);
+
+	if (!host_dev)
+		return -1;
+	if (os_lseek(host_dev->fd,
+		     start * host_dev->blk_dev.blksz,
+		     OS_SEEK_SET) == -1) {
+		printf("ERROR: Invalid position\n");
+		return -1;
+	}
+	ssize_t len = os_read(host_dev->fd, buffer,
+			      blkcnt * host_dev->blk_dev.blksz);
+	if (len >= 0)
+		return len / host_dev->blk_dev.blksz;
+	return -1;
+}
+
+static unsigned long host_block_write(int dev, unsigned long start,
+				      lbaint_t blkcnt, const void *buffer)
+{
+	struct host_block_dev *host_dev = find_host_device(dev);
+	if (os_lseek(host_dev->fd,
+		     start * host_dev->blk_dev.blksz,
+		     OS_SEEK_SET) == -1) {
+		printf("ERROR: Invalid position\n");
+		return -1;
+	}
+	ssize_t len = os_write(host_dev->fd, buffer, blkcnt *
+			       host_dev->blk_dev.blksz);
+	if (len >= 0)
+		return len / host_dev->blk_dev.blksz;
+	return -1;
+}
+
+int host_dev_bind(int dev, char *filename)
+{
+	struct host_block_dev *host_dev = find_host_device(dev);
+
+	if (!host_dev)
+		return -1;
+	if (host_dev->blk_dev.priv) {
+		os_close(host_dev->fd);
+		host_dev->blk_dev.priv = NULL;
+	}
+	if (host_dev->filename)
+		free(host_dev->filename);
+	if (filename && *filename) {
+		host_dev->filename = strdup(filename);
+	} else {
+		host_dev->filename = NULL;
+		return 0;
+	}
+
+	host_dev->fd = os_open(host_dev->filename, OS_O_RDWR);
+	if (host_dev->fd == -1) {
+		printf("Failed to access host backing file '%s'\n",
+		       host_dev->filename);
+		return 1;
+	}
+
+	block_dev_desc_t *blk_dev = &host_dev->blk_dev;
+	blk_dev->if_type = IF_TYPE_HOST;
+	blk_dev->priv = host_dev;
+	blk_dev->blksz = 512;
+	blk_dev->lba = os_lseek(host_dev->fd, 0, OS_SEEK_END) / blk_dev->blksz;
+	blk_dev->block_read = host_block_read;
+	blk_dev->block_write = host_block_write;
+	blk_dev->dev = dev;
+	blk_dev->part_type = PART_TYPE_UNKNOWN;
+	init_part(blk_dev);
+
+	return 0;
+}
+
+int host_get_dev_err(int dev, block_dev_desc_t **blk_devp)
+{
+	struct host_block_dev *host_dev = find_host_device(dev);
+
+	if (!host_dev)
+		return -ENODEV;
+
+	if (!host_dev->blk_dev.priv)
+		return -ENOENT;
+
+	*blk_devp = &host_dev->blk_dev;
+	return 0;
+}
+
+block_dev_desc_t *host_get_dev(int dev)
+{
+	block_dev_desc_t *blk_dev;
+
+	if (host_get_dev_err(dev, &blk_dev))
+		return NULL;
+
+	return blk_dev;
+}
diff --git a/drivers/tpm/Makefile b/drivers/tpm/Makefile
index 2f2353f..150570e 100644
--- a/drivers/tpm/Makefile
+++ b/drivers/tpm/Makefile
@@ -8,3 +8,4 @@
 obj-$(CONFIG_TPM_TIS_I2C) += tpm.o
 obj-$(CONFIG_TPM_TIS_I2C) += tpm_tis_i2c.o
 obj-$(CONFIG_TPM_TIS_LPC) += tpm_tis_lpc.o
+obj-$(CONFIG_TPM_TIS_SANDBOX) += tpm_tis_sandbox.o
diff --git a/drivers/tpm/tpm_tis_sandbox.c b/drivers/tpm/tpm_tis_sandbox.c
new file mode 100644
index 0000000..ed4b039
--- /dev/null
+++ b/drivers/tpm/tpm_tis_sandbox.c
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2013 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/state.h>
+#include <asm/unaligned.h>
+#include <linux/crc8.h>
+
+/* TPM NVRAM location indices. */
+#define FIRMWARE_NV_INDEX		0x1007
+#define KERNEL_NV_INDEX			0x1008
+
+#define NV_DATA_PUBLIC_PERMISSIONS_OFFSET	60
+
+/* Kernel TPM space - KERNEL_NV_INDEX, locked with physical presence */
+#define ROLLBACK_SPACE_KERNEL_VERSION	2
+#define ROLLBACK_SPACE_KERNEL_UID	0x4752574C  /* 'GRWL' */
+
+struct rollback_space_kernel {
+	/* Struct version, for backwards compatibility */
+	uint8_t struct_version;
+	/* Unique ID to detect space redefinition */
+	uint32_t uid;
+	/* Kernel versions */
+	uint32_t kernel_versions;
+	/* Reserved for future expansion */
+	uint8_t reserved[3];
+	/* Checksum (v2 and later only) */
+	uint8_t crc8;
+} __packed rollback_space_kernel;
+
+/*
+ * These numbers derive from adding the sizes of command fields as shown in
+ * the TPM commands manual.
+ */
+#define TPM_REQUEST_HEADER_LENGTH	10
+#define TPM_RESPONSE_HEADER_LENGTH	10
+
+/* These are the different non-volatile spaces that we emulate */
+enum {
+	NV_GLOBAL_LOCK,
+	NV_SEQ_FIRMWARE,
+	NV_SEQ_KERNEL,
+	NV_SEQ_COUNT,
+};
+
+/* Size of each non-volatile space */
+#define NV_DATA_SIZE		0x20
+
+/*
+ * Information about our TPM emulation. This is preserved in the sandbox
+ * state file if enabled.
+ */
+static struct tpm_state {
+	uint8_t nvdata[NV_SEQ_COUNT][NV_DATA_SIZE];
+} state;
+
+/**
+ * sandbox_tpm_read_state() - read the sandbox EC state from the state file
+ *
+ * If data is available, then blob and node will provide access to it. If
+ * not this function sets up an empty TPM.
+ *
+ * @blob: Pointer to device tree blob, or NULL if no data to read
+ * @node: Node offset to read from
+ */
+static int sandbox_tpm_read_state(const void *blob, int node)
+{
+	const char *prop;
+	int len;
+	int i;
+
+	if (!blob)
+		return 0;
+
+	for (i = 0; i < NV_SEQ_COUNT; i++) {
+		char prop_name[20];
+
+		sprintf(prop_name, "nvdata%d", i);
+		prop = fdt_getprop(blob, node, prop_name, &len);
+		if (prop && len == NV_DATA_SIZE)
+			memcpy(state.nvdata[i], prop, NV_DATA_SIZE);
+	}
+
+	return 0;
+}
+
+/**
+ * cros_ec_write_state() - Write out our state to the state file
+ *
+ * The caller will ensure that there is a node ready for the state. The node
+ * may already contain the old state, in which case it is overridden.
+ *
+ * @blob: Device tree blob holding state
+ * @node: Node to write our state into
+ */
+static int sandbox_tpm_write_state(void *blob, int node)
+{
+	int i;
+
+	/*
+	 * We are guaranteed enough space to write basic properties.
+	 * We could use fdt_add_subnode() to put each set of data in its
+	 * own node - perhaps useful if we add access informaiton to each.
+	 */
+	for (i = 0; i < NV_SEQ_COUNT; i++) {
+		char prop_name[20];
+
+		sprintf(prop_name, "nvdata%d", i);
+		fdt_setprop(blob, node, prop_name, state.nvdata[i],
+			    NV_DATA_SIZE);
+	}
+
+	return 0;
+}
+
+SANDBOX_STATE_IO(sandbox_tpm, "google,sandbox-tpm", sandbox_tpm_read_state,
+		 sandbox_tpm_write_state);
+
+static int index_to_seq(uint32_t index)
+{
+	switch (index) {
+	case FIRMWARE_NV_INDEX:
+		return NV_SEQ_FIRMWARE;
+	case KERNEL_NV_INDEX:
+		return NV_SEQ_KERNEL;
+	case 0:
+		return NV_GLOBAL_LOCK;
+	}
+
+	printf("Invalid nv index %#x\n", index);
+	return -1;
+}
+
+int tis_sendrecv(const u8 *sendbuf, size_t send_size,
+		 u8 *recvbuf, size_t *recv_len)
+{
+	struct tpm_state *tpm = &state;
+	uint32_t code, index, length, type;
+	uint8_t *data;
+	int seq;
+
+	code = get_unaligned_be32(sendbuf + sizeof(uint16_t) +
+				  sizeof(uint32_t));
+	printf("tpm: %zd bytes, recv_len %zd, cmd = %x\n", send_size,
+	       *recv_len, code);
+	print_buffer(0, sendbuf, 1, send_size, 0);
+	switch (code) {
+	case 0x65: /* get flags */
+		type = get_unaligned_be32(sendbuf + 14);
+		switch (type) {
+		case 4:
+			index = get_unaligned_be32(sendbuf + 18);
+			printf("Get flags index %#02x\n", index);
+			*recv_len = 22;
+			memset(recvbuf, '\0', *recv_len);
+			put_unaligned_be32(22, recvbuf +
+					   TPM_RESPONSE_HEADER_LENGTH);
+			data = recvbuf + TPM_RESPONSE_HEADER_LENGTH +
+					sizeof(uint32_t);
+			switch (index) {
+			case FIRMWARE_NV_INDEX:
+				break;
+			case KERNEL_NV_INDEX:
+				/* TPM_NV_PER_PPWRITE */
+				put_unaligned_be32(1, data +
+					NV_DATA_PUBLIC_PERMISSIONS_OFFSET);
+				break;
+			}
+			break;
+		case 0x11: /* TPM_CAP_NV_INDEX */
+			index = get_unaligned_be32(sendbuf + 18);
+			printf("Get cap nv index %#02x\n", index);
+			put_unaligned_be32(22, recvbuf +
+					   TPM_RESPONSE_HEADER_LENGTH);
+			break;
+		default:
+			printf("   ** Unknown 0x65 command type %#02x\n",
+			       type);
+			return -1;
+		}
+		break;
+	case 0xcd: /* nvwrite */
+		index = get_unaligned_be32(sendbuf + 10);
+		length = get_unaligned_be32(sendbuf + 18);
+		seq = index_to_seq(index);
+		if (seq < 0)
+			return -1;
+		printf("tpm: nvwrite index=%#02x, len=%#02x\n", index, length);
+		memcpy(&tpm->nvdata[seq], sendbuf + 22, length);
+		*recv_len = 12;
+		memset(recvbuf, '\0', *recv_len);
+		break;
+	case 0xcf: /* nvread */
+		index = get_unaligned_be32(sendbuf + 10);
+		length = get_unaligned_be32(sendbuf + 18);
+		seq = index_to_seq(index);
+		if (seq < 0)
+			return -1;
+		printf("tpm: nvread index=%#02x, len=%#02x\n", index, length);
+		*recv_len = TPM_RESPONSE_HEADER_LENGTH + sizeof(uint32_t) +
+					length;
+		memset(recvbuf, '\0', *recv_len);
+		put_unaligned_be32(length, recvbuf +
+				   TPM_RESPONSE_HEADER_LENGTH);
+		if (seq == NV_SEQ_KERNEL) {
+			struct rollback_space_kernel rsk;
+
+			data = recvbuf + TPM_RESPONSE_HEADER_LENGTH +
+					sizeof(uint32_t);
+			rsk.struct_version = 2;
+			rsk.uid = ROLLBACK_SPACE_KERNEL_UID;
+			rsk.kernel_versions = 0;
+			rsk.crc8 = crc8((unsigned char *)&rsk,
+					offsetof(struct rollback_space_kernel,
+						 crc8));
+			memcpy(data, &rsk, sizeof(rsk));
+		} else {
+			memcpy(recvbuf + TPM_RESPONSE_HEADER_LENGTH +
+			       sizeof(uint32_t), &tpm->nvdata[seq], length);
+		}
+		break;
+	case 0x14: /* tpm extend */
+	case 0x15: /* pcr read */
+	case 0x5d: /* force clear */
+	case 0x6f: /* physical enable */
+	case 0x72: /* physical set deactivated */
+	case 0x99: /* startup */
+	case 0x4000000a:  /* assert physical presence */
+		*recv_len = 12;
+		memset(recvbuf, '\0', *recv_len);
+		break;
+	default:
+		printf("Unknown tpm command %02x\n", code);
+		return -1;
+	}
+
+	return 0;
+}
+
+int tis_open(void)
+{
+	printf("%s\n", __func__);
+	return 0;
+}
+
+int tis_close(void)
+{
+	printf("%s\n", __func__);
+	return 0;
+}
+
+int tis_init(void)
+{
+	printf("%s\n", __func__);
+	return 0;
+}
diff --git a/include/config_fallbacks.h b/include/config_fallbacks.h
index 3633b09..d8339b2 100644
--- a/include/config_fallbacks.h
+++ b/include/config_fallbacks.h
@@ -50,7 +50,8 @@
 	defined(CONFIG_CMD_PART) || \
 	defined(CONFIG_CMD_GPT) || \
 	defined(CONFIG_MMC) || \
-	defined(CONFIG_SYSTEMACE)
+	defined(CONFIG_SYSTEMACE) || \
+	defined(CONFIG_SANDBOX)
 #define HAVE_BLOCK_DEVICE
 #endif
 
diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h
index 7e78a23..a6d5582 100644
--- a/include/configs/sandbox.h
+++ b/include/configs/sandbox.h
@@ -39,6 +39,9 @@
 #define CONFIG_CMD_FAT
 #define CONFIG_CMD_EXT4
 #define CONFIG_CMD_EXT4_WRITE
+#define CONFIG_CMD_PART
+#define CONFIG_DOS_PARTITION
+#define CONFIG_HOST_MAX_DEVICES 4
 
 #define CONFIG_SYS_VSNPRINTF
 
@@ -126,4 +129,6 @@
 #define CONFIG_LZO
 #define CONFIG_LZMA
 
+#define CONFIG_TPM_TIS_SANDBOX
+
 #endif
diff --git a/include/linux/crc8.h b/include/linux/crc8.h
new file mode 100644
index 0000000..b5fd2ac
--- /dev/null
+++ b/include/linux/crc8.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2013 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+
+#ifndef __linux_crc8_h
+#define __linux_crc8_h
+
+/**
+ * crc8() - Calculate and return CRC-8 of the data
+ *
+ * This uses an x^8 + x^2 + x + 1 polynomial.  A table-based algorithm would
+ * be faster, but for only a few bytes it isn't worth the code size
+ *
+ * @vptr: Buffer to checksum
+ * @len: Length of buffer in bytes
+ * @return CRC8 checksum
+ */
+unsigned int crc8(const unsigned char *vptr, int len);
+
+#endif
diff --git a/include/os.h b/include/os.h
index 950433d..b65fba4 100644
--- a/include/os.h
+++ b/include/os.h
@@ -107,6 +107,35 @@
 void *os_malloc(size_t length);
 
 /**
+ * Free memory previous allocated with os_malloc()/os_realloc()
+ *
+ * This returns the memory to the OS.
+ *
+ * \param ptr		Pointer to memory block to free
+ */
+void *os_free(void *ptr);
+
+/**
+ * Reallocate previously-allocated memory to increase/decrease space
+ *
+ * This works in a similar way to the C library realloc() function. If
+ * length is 0, then ptr is freed. Otherwise the space used by ptr is
+ * expanded or reduced depending on whether length is larger or smaller
+ * than before.
+ *
+ * If ptr is NULL, then this is similar to calling os_malloc().
+ *
+ * This function may need to move the memory block to make room for any
+ * extra space, in which case the new pointer is returned.
+ *
+ * \param ptr		Pointer to memory block to reallocate
+ * \param length	New length for memory block
+ * \return pointer to new memory block, or NULL on failure or if length
+ *	is 0.
+ */
+void *os_realloc(void *ptr, size_t length);
+
+/**
  * Access to the usleep function of the os
  *
  * \param usec Time to sleep in micro seconds
@@ -180,4 +209,40 @@
  */
 ssize_t os_get_filesize(const char *fname);
 
+/**
+ * Write a character to the controlling OS terminal
+ *
+ * This bypasses the U-Boot console support and writes directly to the OS
+ * stdout file descriptor.
+ *
+ * @param ch	Character to write
+ */
+void os_putc(int ch);
+
+/**
+ * Write a string to the controlling OS terminal
+ *
+ * This bypasses the U-Boot console support and writes directly to the OS
+ * stdout file descriptor.
+ *
+ * @param str	String to write (note that \n is not appended)
+ */
+void os_puts(const char *str);
+
+/**
+ * Write the sandbox RAM buffer to a existing file
+ *
+ * @param fname		Filename to write memory to (simple binary format)
+ * @return 0 if OK, -ve on error
+ */
+int os_write_ram_buf(const char *fname);
+
+/**
+ * Read the sandbox RAM buffer from an existing file
+ *
+ * @param fname		Filename containing memory (simple binary format)
+ * @return 0 if OK, -ve on error
+ */
+int os_read_ram_buf(const char *fname);
+
 #endif
diff --git a/include/part.h b/include/part.h
index ce840bd..4beb6db 100644
--- a/include/part.h
+++ b/include/part.h
@@ -58,6 +58,8 @@
 #define IF_TYPE_MMC		6
 #define IF_TYPE_SD		7
 #define IF_TYPE_SATA		8
+#define IF_TYPE_HOST		9
+#define IF_TYPE_MAX		10	/* Max number of IF_TYPE_* supported */
 
 /* Part types */
 #define PART_TYPE_UNKNOWN	0x00
@@ -102,6 +104,8 @@
 block_dev_desc_t* mmc_get_dev(int dev);
 block_dev_desc_t* systemace_get_dev(int dev);
 block_dev_desc_t* mg_disk_get_dev(int dev);
+block_dev_desc_t *host_get_dev(int dev);
+int host_get_dev_err(int dev, block_dev_desc_t **blk_devp);
 
 /* disk/part.c */
 int get_partition_info (block_dev_desc_t * dev_desc, int part, disk_partition_t *info);
@@ -123,6 +127,7 @@
 static inline block_dev_desc_t* mmc_get_dev(int dev) { return NULL; }
 static inline block_dev_desc_t* systemace_get_dev(int dev) { return NULL; }
 static inline block_dev_desc_t* mg_disk_get_dev(int dev) { return NULL; }
+static inline block_dev_desc_t *host_get_dev(int dev) { return NULL; }
 
 static inline int get_partition_info (block_dev_desc_t * dev_desc, int part,
 	disk_partition_t *info) { return -1; }
diff --git a/include/sandboxblockdev.h b/include/sandboxblockdev.h
new file mode 100644
index 0000000..627787a
--- /dev/null
+++ b/include/sandboxblockdev.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2013, Henrik Nordstrom <henrik@henriknordstrom.net>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __SANDBOX_BLOCK_DEV__
+#define __SANDBOX_BLOCK_DEV__
+
+struct host_block_dev {
+	block_dev_desc_t blk_dev;
+	char *filename;
+	int fd;
+};
+
+int host_dev_bind(int dev, char *filename);
+
+#endif
diff --git a/lib/Makefile b/lib/Makefile
index e787f77..760340f 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -21,6 +21,7 @@
 obj-$(CONFIG_BZIP2) += bzlib_huffman.o
 obj-$(CONFIG_USB_TTY) += circbuf.o
 obj-y += crc7.o
+obj-y += crc8.o
 obj-y += crc16.o
 obj-$(CONFIG_OF_CONTROL) += fdtdec.o
 obj-$(CONFIG_TEST_FDTDEC) += fdtdec_test.o
diff --git a/lib/crc8.c b/lib/crc8.c
new file mode 100644
index 0000000..8b68a29
--- /dev/null
+++ b/lib/crc8.c
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2013 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include "linux/crc8.h"
+
+unsigned int crc8(const unsigned char *vptr, int len)
+{
+	const unsigned char *data = vptr;
+	unsigned int crc = 0;
+	int i, j;
+
+	for (j = len; j; j--, data++) {
+		crc ^= (*data << 8);
+		for (i = 8; i; i--) {
+			if (crc & 0x8000)
+				crc ^= (0x1070 << 3);
+			crc <<= 1;
+		}
+	}
+
+	return (crc >> 8) & 0xff;
+}