sandbox: Support obtaining the next phase from an image

At present sandbox runs the next phase from discrete executables, so for
example u-boot-tpl runs u-boot-vpl to get to the next phase.

In some cases the phases are all built into a single firmware image, as is
done for real boards. Add support for this to sandbox.

Make it higher priority so that it takes precedence over the existing
method.

Signed-off-by: Simon Glass <sjg@chromium.org>
diff --git a/arch/sandbox/cpu/spl.c b/arch/sandbox/cpu/spl.c
index 2678370..75f4601 100644
--- a/arch/sandbox/cpu/spl.c
+++ b/arch/sandbox/cpu/spl.c
@@ -78,7 +78,48 @@
 
 	return 0;
 }
-SPL_LOAD_IMAGE_METHOD("sandbox", 9, BOOT_DEVICE_BOARD, spl_board_load_file);
+SPL_LOAD_IMAGE_METHOD("sandbox_file", 9, BOOT_DEVICE_BOARD,
+		      spl_board_load_file);
+
+static int load_from_image(struct spl_image_info *spl_image,
+			   struct spl_boot_device *bootdev)
+{
+	struct sandbox_state *state = state_get_current();
+	enum u_boot_phase next_phase;
+	const char *fname;
+	ulong pos, size;
+	int full_size;
+	void *buf;
+	int ret;
+
+	if (!IS_ENABLED(CONFIG_SANDBOX_VPL))
+		return -ENOENT;
+
+	next_phase = spl_next_phase();
+	pos = spl_get_image_pos();
+	size = spl_get_image_size();
+	if (pos == BINMAN_SYM_MISSING || size == BINMAN_SYM_MISSING) {
+		log_debug("No image found\n");
+		return -ENOENT;
+	}
+	log_info("Reading from pos %lx size %lx\n", pos, size);
+
+	/*
+	 * Set up spl_image to boot from jump_to_image_no_args(). Allocate this
+	 * outside the RAM buffer (i.e. don't use strdup()).
+	 */
+	fname = state->prog_fname ? state->prog_fname : state->argv[0];
+	ret = os_read_file(fname, &buf, &full_size);
+	if (ret)
+		return log_msg_ret("rd", -ENOMEM);
+	spl_image->flags = SPL_SANDBOXF_ARG_IS_BUF;
+	spl_image->arg = buf;
+	spl_image->offset = pos;
+	spl_image->size = size;
+
+	return 0;
+}
+SPL_LOAD_IMAGE_METHOD("sandbox_image", 7, BOOT_DEVICE_BOARD, load_from_image);
 
 void spl_board_init(void)
 {
@@ -109,6 +150,15 @@
 		}
 		break;
 	}
+	case SPL_SANDBOXF_ARG_IS_BUF: {
+		int ret;
+
+		ret = os_jump_to_image(spl_image->arg + spl_image->offset,
+				       spl_image->size);
+		if (ret)
+			log_err("Failed to load image\n");
+		break;
+	}
 	default:
 		log_err("Invalid flags\n");
 		break;