coreboot: unify infrastructure for loading payloads

A payload can be loaded either from a vboot region or from cbfs.
Provide a common place for choosing where the payload is loaded
from. Additionally, place the logic in the 'loaders' directory
similarly to the ramstage loader infrastructure.

Change-Id: I6b0034ea5ebd04a3d058151819ac77a126a6bfe2
Signed-off-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/5296
Tested-by: build bot (Jenkins)
Reviewed-by: Alexandru Gagniuc <mr.nuke.me@gmail.com>
Reviewed-by: Edward O'Callaghan <eocallaghan@alterapraxis.com>
Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net>
diff --git a/src/lib/cbfs.c b/src/lib/cbfs.c
index 99eeac8..dc08937 100644
--- a/src/lib/cbfs.c
+++ b/src/lib/cbfs.c
@@ -65,12 +65,6 @@
 
 #include "cbfs_core.c"
 
-#if CONFIG_VBOOT_VERIFY_FIRMWARE
-#include <vendorcode/google/chromeos/chromeos.h>
-#else
-static inline void *vboot_get_payload(int *len) { return NULL; }
-#endif
-
 #ifndef __SMM__
 static inline int tohex4(unsigned int c)
 {
@@ -160,19 +154,6 @@
 	return (void *) entry;
 }
 
-void *cbfs_load_payload(struct cbfs_media *media, const char *name)
-{
-	struct cbfs_payload *payload;
-
-	payload = vboot_get_payload(NULL);
-	if (payload != NULL)
-		return payload;
-
-	payload = (struct cbfs_payload *)cbfs_get_file_content(
-		media, name, CBFS_TYPE_PAYLOAD, NULL);
-	return payload;
-}
-
 /* Simple buffer */
 
 void *cbfs_simple_buffer_map(struct cbfs_simple_buffer *buffer,
diff --git a/src/lib/hardwaremain.c b/src/lib/hardwaremain.c
index fed153b..d90e0f6 100644
--- a/src/lib/hardwaremain.c
+++ b/src/lib/hardwaremain.c
@@ -32,7 +32,7 @@
 #include <stdlib.h>
 #include <reset.h>
 #include <boot/tables.h>
-#include <cbfs.h>
+#include <payload_loader.h>
 #include <lib.h>
 #if CONFIG_HAVE_ACPI_RESUME
 #include <arch/acpi.h>
@@ -226,30 +226,26 @@
 
 static boot_state_t bs_payload_load(void *arg)
 {
-	void *payload;
-	void *entry;
+	struct payload *payload;
 
 	timestamp_add_now(TS_LOAD_PAYLOAD);
 
-	payload = cbfs_load_payload(CBFS_DEFAULT_MEDIA,
-				    CONFIG_CBFS_PREFIX "/payload");
+	payload = payload_load();
+
 	if (! payload)
-		die("Could not find a payload\n");
-
-	entry = selfload(get_lb_mem(), payload);
-
-	if (! entry)
 		die("Could not load payload\n");
 
 	/* Pass the payload to the next state. */
-	boot_states[BS_PAYLOAD_BOOT].arg = entry;
+	boot_states[BS_PAYLOAD_BOOT].arg = payload;
 
 	return BS_PAYLOAD_BOOT;
 }
 
-static boot_state_t bs_payload_boot(void *entry)
+static boot_state_t bs_payload_boot(void *arg)
 {
-	selfboot(entry);
+	struct payload *payload = arg;
+
+	payload_run(payload);
 
 	printk(BIOS_EMERG, "Boot failed");
 	/* Returning from this state will fail because the following signals
diff --git a/src/lib/loaders/Makefile.inc b/src/lib/loaders/Makefile.inc
index eceaa00..356e47e 100644
--- a/src/lib/loaders/Makefile.inc
+++ b/src/lib/loaders/Makefile.inc
@@ -19,3 +19,5 @@
 
 romstage-y += cbfs_ramstage_loader.c
 romstage-y += load_and_run_ramstage.c
+ramstage-y += cbfs_payload_loader.c
+ramstage-y += load_and_run_payload.c
diff --git a/src/lib/loaders/cbfs_payload_loader.c b/src/lib/loaders/cbfs_payload_loader.c
new file mode 100644
index 0000000..2c1d179
--- /dev/null
+++ b/src/lib/loaders/cbfs_payload_loader.c
@@ -0,0 +1,44 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <cbfs.h>
+#include <payload_loader.h>
+
+static int cbfs_locate_payload(struct payload *payload)
+{
+	void *buffer;
+	size_t size;
+	const int type = CBFS_TYPE_PAYLOAD;
+
+	buffer = cbfs_get_file_content(CBFS_DEFAULT_MEDIA, payload->name,
+					type, &size);
+
+	if (buffer == NULL)
+		return -1;
+
+	payload->backing_store.data = buffer;
+	payload->backing_store.size = size;
+
+	return 0;
+}
+
+const struct payload_loader_ops cbfs_payload_loader = {
+	.name = "CBFS",
+	.locate = cbfs_locate_payload,
+};
diff --git a/src/lib/loaders/load_and_run_payload.c b/src/lib/loaders/load_and_run_payload.c
new file mode 100644
index 0000000..46db93c
--- /dev/null
+++ b/src/lib/loaders/load_and_run_payload.c
@@ -0,0 +1,81 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <console/console.h>
+#include <boot/coreboot_tables.h>
+#include <payload_loader.h>
+
+extern const struct payload_loader_ops vboot_payload_loader;
+extern const struct payload_loader_ops cbfs_payload_loader;
+
+static const struct payload_loader_ops *payload_ops[] = {
+#if CONFIG_VBOOT_VERIFY_FIRMWARE
+	&vboot_payload_loader,
+#endif
+	&cbfs_payload_loader,
+};
+
+static struct payload global_payload = {
+	.name = CONFIG_CBFS_PREFIX "/payload",
+};
+
+struct payload *payload_load(void)
+{
+	int i;
+	void *entry;
+	struct lb_memory *mem;
+	const struct payload_loader_ops *ops;
+	struct payload *payload = &global_payload;
+
+	for (i = 0; i < ARRAY_SIZE(payload_ops); i++) {
+		ops = payload_ops[i];
+		if (ops->locate(payload) < 0) {
+			printk(BIOS_DEBUG, "%s: could not locate payload.\n",
+				ops->name);
+			continue;
+		}
+		printk(BIOS_DEBUG, "%s: located payload @ %p, %zu bytes.\n",
+			ops->name, payload->backing_store.data,
+			payload->backing_store.size);
+		break;
+	}
+
+	if (i == ARRAY_SIZE(payload_ops))
+		return NULL;
+
+	mem = get_lb_mem();
+	entry = selfload(mem, payload->backing_store.data);
+
+	if (entry == NULL)
+		return NULL;
+
+	payload->entry = entry;
+
+	return payload;
+}
+
+void payload_run(const struct payload *payload)
+{
+	if (payload == NULL)
+		return;
+
+	selfboot(payload->entry);
+}
diff --git a/src/lib/selfboot.c b/src/lib/selfboot.c
index 222eae2..c0986d1 100644
--- a/src/lib/selfboot.c
+++ b/src/lib/selfboot.c
@@ -32,6 +32,7 @@
 #if CONFIG_COLLECT_TIMESTAMPS
 #include <timestamp.h>
 #endif
+#include <payload_loader.h>
 
 /* Maximum physical address we can use for the coreboot bounce buffer. */
 #ifndef MAX_ADDR