lib/prog_loaders: Add payload_preload
This method will allow the SoC code to start loading the payload before
it is required.
BUG=b:177909625
TEST=Boot guybrush and see read/decompress drop by 23 ms.
Signed-off-by: Raul E Rangel <rrangel@chromium.org>
Change-Id: Ifa8f30a0f4f931ece803c2e8e022e4d33d3fe581
Reviewed-on: https://review.coreboot.org/c/coreboot/+/56051
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Martin Roth <martinroth@google.com>
diff --git a/src/include/program_loading.h b/src/include/program_loading.h
index 65a36b9..5b9a94d 100644
--- a/src/include/program_loading.h
+++ b/src/include/program_loading.h
@@ -154,6 +154,13 @@
int payload_arch_usable_ram_quirk(uint64_t start, uint64_t size);
+/*
+ * Asynchronously preloads the payload.
+ *
+ * This should be called early on to allow the payload to load before
+ * `payload_load` is called.
+ */
+void payload_preload(void);
/* Load payload into memory in preparation to run. */
void payload_load(void);
diff --git a/src/include/symbols.h b/src/include/symbols.h
index 3e4694b..52624d4 100644
--- a/src/include/symbols.h
+++ b/src/include/symbols.h
@@ -52,6 +52,7 @@
/* Regions for execution units. */
+DECLARE_REGION(payload_preload_cache)
DECLARE_REGION(payload)
/* "program" always refers to the current execution unit. */
DECLARE_REGION(program)
diff --git a/src/lib/Kconfig b/src/lib/Kconfig
index 239f613..0f651b3 100644
--- a/src/lib/Kconfig
+++ b/src/lib/Kconfig
@@ -98,3 +98,14 @@
the associated CAR/SRAM size. In that case every single CBFS file
lookup must re-read the same CBFS directory entries from flash to find
the respective file.
+
+config PAYLOAD_PRELOAD
+ bool
+ depends on COOP_MULTITASKING
+ help
+ On some systems with SPI DMA controllers, it is possible to preload
+ the payload while ramstage is executing. This can be selected by the
+ SoC to enable payload preloading.
+
+ The SoC needs to define a payload_preload_cache region where the
+ raw payload can be placed.
diff --git a/src/lib/prog_loaders.c b/src/lib/prog_loaders.c
index 40f51eb..1a361ea 100644
--- a/src/lib/prog_loaders.c
+++ b/src/lib/prog_loaders.c
@@ -13,6 +13,7 @@
#include <rmodule.h>
#include <stage_cache.h>
#include <symbols.h>
+#include <thread.h>
#include <timestamp.h>
#include <security/vboot/vboot_common.h>
@@ -126,27 +127,71 @@
static struct prog global_payload =
PROG_INIT(PROG_PAYLOAD, CONFIG_CBFS_PREFIX "/payload");
+static struct thread_handle payload_preload_handle;
+
+static enum cb_err payload_preload_thread_entry(void *arg)
+{
+ size_t size;
+ struct prog *payload = &global_payload;
+
+ printk(BIOS_DEBUG, "Preloading payload\n");
+
+ payload->cbfs_type = CBFS_TYPE_QUERY;
+
+ size = cbfs_type_load(prog_name(payload), _payload_preload_cache,
+ REGION_SIZE(payload_preload_cache), &payload->cbfs_type);
+
+ if (!size) {
+ printk(BIOS_ERR, "ERROR: Preloading payload failed\n");
+ return CB_ERR;
+ }
+
+ printk(BIOS_DEBUG, "Preloading payload complete\n");
+
+ return CB_SUCCESS;
+}
+
+void payload_preload(void)
+{
+ struct thread_handle *handle = &payload_preload_handle;
+
+ if (!CONFIG(PAYLOAD_PRELOAD))
+ return;
+
+ if (thread_run(handle, payload_preload_thread_entry, NULL))
+ printk(BIOS_ERR, "ERROR: Failed to start payload preload thread\n");
+}
+
void payload_load(void)
{
struct prog *payload = &global_payload;
+ struct thread_handle *handle = &payload_preload_handle;
+ void *mapping = NULL;
+ void *buffer;
timestamp_add_now(TS_LOAD_PAYLOAD);
if (prog_locate_hook(payload))
goto out;
- payload->cbfs_type = CBFS_TYPE_QUERY;
- void *mapping = cbfs_type_map(prog_name(payload), NULL, &payload->cbfs_type);
- if (!mapping)
+ if (CONFIG(PAYLOAD_PRELOAD) && thread_join(handle) == CB_SUCCESS) {
+ buffer = _payload_preload_cache;
+ } else {
+ payload->cbfs_type = CBFS_TYPE_QUERY;
+ mapping = cbfs_type_map(prog_name(payload), NULL, &payload->cbfs_type);
+ buffer = mapping;
+ }
+
+ if (!buffer)
goto out;
switch (prog_cbfs_type(payload)) {
case CBFS_TYPE_SELF: /* Simple ELF */
- selfload_mapped(payload, mapping, BM_MEM_RAM);
+ selfload_mapped(payload, buffer, BM_MEM_RAM);
break;
case CBFS_TYPE_FIT: /* Flattened image tree */
if (CONFIG(PAYLOAD_FIT_SUPPORT)) {
- fit_payload(payload, mapping);
+ fit_payload(payload, buffer);
break;
} /* else fall-through */
default:
@@ -155,7 +200,8 @@
break;
}
- cbfs_unmap(mapping);
+ if (mapping)
+ cbfs_unmap(mapping);
out:
if (prog_entry(payload) == NULL)
die_with_post_code(POST_INVALID_ROM, "Payload not loaded.\n");