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>
This commit is contained in:
Raul E Rangel 2021-07-02 17:07:05 -06:00 committed by Martin Roth
parent 61f44127f0
commit 67798cfd80
4 changed files with 71 additions and 6 deletions

View File

@ -154,6 +154,13 @@ void run_ramstage(void);
int payload_arch_usable_ram_quirk(uint64_t start, uint64_t size); 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. */ /* Load payload into memory in preparation to run. */
void payload_load(void); void payload_load(void);

View File

@ -52,6 +52,7 @@ DECLARE_REGION(asan_shadow)
/* Regions for execution units. */ /* Regions for execution units. */
DECLARE_REGION(payload_preload_cache)
DECLARE_REGION(payload) DECLARE_REGION(payload)
/* "program" always refers to the current execution unit. */ /* "program" always refers to the current execution unit. */
DECLARE_REGION(program) DECLARE_REGION(program)

View File

@ -98,3 +98,14 @@ config NO_CBFS_MCACHE
the associated CAR/SRAM size. In that case every single CBFS file 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 lookup must re-read the same CBFS directory entries from flash to find
the respective file. 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.

View File

@ -13,6 +13,7 @@
#include <rmodule.h> #include <rmodule.h>
#include <stage_cache.h> #include <stage_cache.h>
#include <symbols.h> #include <symbols.h>
#include <thread.h>
#include <timestamp.h> #include <timestamp.h>
#include <security/vboot/vboot_common.h> #include <security/vboot/vboot_common.h>
@ -126,27 +127,71 @@ fail:
static struct prog global_payload = static struct prog global_payload =
PROG_INIT(PROG_PAYLOAD, CONFIG_CBFS_PREFIX "/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) void payload_load(void)
{ {
struct prog *payload = &global_payload; struct prog *payload = &global_payload;
struct thread_handle *handle = &payload_preload_handle;
void *mapping = NULL;
void *buffer;
timestamp_add_now(TS_LOAD_PAYLOAD); timestamp_add_now(TS_LOAD_PAYLOAD);
if (prog_locate_hook(payload)) if (prog_locate_hook(payload))
goto out; goto out;
if (CONFIG(PAYLOAD_PRELOAD) && thread_join(handle) == CB_SUCCESS) {
buffer = _payload_preload_cache;
} else {
payload->cbfs_type = CBFS_TYPE_QUERY; payload->cbfs_type = CBFS_TYPE_QUERY;
void *mapping = cbfs_type_map(prog_name(payload), NULL, &payload->cbfs_type); mapping = cbfs_type_map(prog_name(payload), NULL, &payload->cbfs_type);
if (!mapping) buffer = mapping;
}
if (!buffer)
goto out; goto out;
switch (prog_cbfs_type(payload)) { switch (prog_cbfs_type(payload)) {
case CBFS_TYPE_SELF: /* Simple ELF */ case CBFS_TYPE_SELF: /* Simple ELF */
selfload_mapped(payload, mapping, BM_MEM_RAM); selfload_mapped(payload, buffer, BM_MEM_RAM);
break; break;
case CBFS_TYPE_FIT: /* Flattened image tree */ case CBFS_TYPE_FIT: /* Flattened image tree */
if (CONFIG(PAYLOAD_FIT_SUPPORT)) { if (CONFIG(PAYLOAD_FIT_SUPPORT)) {
fit_payload(payload, mapping); fit_payload(payload, buffer);
break; break;
} /* else fall-through */ } /* else fall-through */
default: default:
@ -155,6 +200,7 @@ void payload_load(void)
break; break;
} }
if (mapping)
cbfs_unmap(mapping); cbfs_unmap(mapping);
out: out:
if (prog_entry(payload) == NULL) if (prog_entry(payload) == NULL)