coreboot: add caching loaded ramstage interface

Instead of hard coding the policy for how a relocated ramstage
image is saved add an interface. The interface consists of two
functions.  cache_loaded_ramstage() and load_cached_ramstage()
are the functions to cache and load the relocated ramstage,
respectively. There are default implementations which cache and
load the relocated ramstage just below where the ramstage runs.

Change-Id: I4346e873d8543e7eee4c1cd484847d846f297bb0
Signed-off-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/2805
Tested-by: build bot (Jenkins)
Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
This commit is contained in:
Aaron Durbin 2013-02-15 23:26:52 -06:00 committed by Ronald G. Minnich
parent 8ce667e506
commit de1f890186
2 changed files with 71 additions and 27 deletions

View File

@ -83,5 +83,26 @@ int selfboot(struct lb_memory *mem, struct cbfs_payload *payload);
/* Defined in individual arch / board implementation. */
int init_default_cbfs_media(struct cbfs_media *media);
#if CONFIG_RELOCATABLE_RAMSTAGE && defined(__PRE_RAM__)
/* The cache_loaded_ramstage() and load_cached_ramstage() functions are defined
* to be weak so that board and chipset code may override them. Their job is to
* cache and load the ramstage for quick S3 resume. By default a copy of the
* relocated ramstage is saved just below the running ramstage region. These
* functions are only valid during romstage. */
struct romstage_handoff;
/* The implementer of cache_loaded_ramstage() needs to ensure that the
* reserve_* fields in in romstage_handoff reflect the memory footprint of the
* ramstage (including cached region). Note that the handoff variable can be
* NULL. */
void __attribute__((weak))
cache_loaded_ramstage(struct romstage_handoff *handoff, void *ramstage_base,
uint32_t ramstage_size, void *entry_point);
/* Return NULL on error or entry point on success. */
void * __attribute__((weak))
load_cached_ramstage(struct romstage_handoff *handoff);
#endif /* CONFIG_RELOCATABLE_RAMSTAGE */
#endif

View File

@ -123,16 +123,53 @@ void *cbfs_load_optionrom(struct cbfs_media *media, uint16_t vendor,
* for the romstage, the rmodule loader is used. The ramstage is placed just
* below the cbmem location. */
void __attribute__((weak))
cache_loaded_ramstage(struct romstage_handoff *handoff, void *ramstage_base,
uint32_t ramstage_size, void *entry_point)
{
if (handoff == NULL)
return;
/* Cache the loaded ramstage just below the to-be-run ramstage. Then
* save the base, size, and entry point in the handoff area. */
handoff->reserve_base = (uint32_t)ramstage_base - ramstage_size;
handoff->reserve_size = ramstage_size;
handoff->ramstage_entry_point = (uint32_t)entry_point;
memcpy((void *)handoff->reserve_base, ramstage_base, ramstage_size);
/* Update the reserve region by 2x in order to store the cached copy. */
handoff->reserve_size += handoff->reserve_size;
}
void * __attribute__((weak))
load_cached_ramstage(struct romstage_handoff *handoff)
{
uint32_t ramstage_size;
if (handoff == NULL)
return NULL;
/* Load the cached ramstage copy into the to-be-run region. It is just
* above the cached copy. */
ramstage_size = handoff->reserve_size / 2;
memcpy((void *)(handoff->reserve_base + ramstage_size),
(void *)handoff->reserve_base, ramstage_size);
return (void *)handoff->ramstage_entry_point;
}
static void *load_stage_from_cbfs(struct cbfs_media *media, const char *name,
struct romstage_handoff *handoff)
{
struct cbfs_stage *stage;
struct rmodule ramstage;
void *cbmem_base;
void *ramstage_base;
char *cbmem_base;
char *ramstage_base;
void *decompression_loc;
void *ramstage_loc;
void *entry_point;
uint32_t ramstage_size;
stage = (struct cbfs_stage *)
cbfs_get_file_content(media, name, CBFS_TYPE_STAGE);
@ -140,7 +177,7 @@ static void *load_stage_from_cbfs(struct cbfs_media *media, const char *name,
if (stage == NULL)
return (void *) -1;
cbmem_base = get_cbmem_toc();
cbmem_base = (void *)get_cbmem_toc();
if (cbmem_base == NULL)
return (void *) -1;
@ -165,24 +202,9 @@ static void *load_stage_from_cbfs(struct cbfs_media *media, const char *name,
entry_point = rmodule_entry(&ramstage);
if (handoff) {
handoff->reserve_base = (uint32_t)ramstage_base;
handoff->reserve_size = (uint32_t)cbmem_base -
(uint32_t)ramstage_base;
/* Save an entire copy in RAM of the relocated ramstage for
* the S3 resume path. The size of the saved relocated ramstage
* is larger than necessary. It could be optimized by saving
* just the text/data segment of the ramstage. The rmodule
* API would need to be modified to expose these details. For
* the time being, just save the entire used region. */
memcpy((void *)(handoff->reserve_base - handoff->reserve_size),
(void *)handoff->reserve_base, handoff->reserve_size);
/* Update the size and base of the reserve region. */
handoff->reserve_base -= handoff->reserve_size;
handoff->reserve_size += handoff->reserve_size;
/* Save the entry point in the handoff area. */
handoff->ramstage_entry_point = (uint32_t)entry_point;
}
ramstage_size = cbmem_base - ramstage_base;
cache_loaded_ramstage(handoff, ramstage_base, ramstage_size,
entry_point);
return entry_point;
}
@ -190,6 +212,7 @@ static void *load_stage_from_cbfs(struct cbfs_media *media, const char *name,
void * cbfs_load_stage(struct cbfs_media *media, const char *name)
{
struct romstage_handoff *handoff;
void *entry;
handoff = romstage_handoff_find_or_add();
@ -199,13 +222,13 @@ void * cbfs_load_stage(struct cbfs_media *media, const char *name)
} else if (!handoff->s3_resume)
return load_stage_from_cbfs(media, name, handoff);
/* S3 resume path. Copy from the saved relocated program buffer to
* the running location. load_stage_from_cbfs() keeps a copy of the
* relocated program just below the relocated program. */
memcpy((void *)(handoff->reserve_base + (handoff->reserve_size / 2)),
(void *)handoff->reserve_base, handoff->reserve_size / 2);
/* S3 resume path. Load a cached copy of the loaded ramstage. If
* return value is NULL load from cbfs. */
entry = load_cached_ramstage(handoff);
if (entry == NULL)
return load_stage_from_cbfs(name, handoff);
return (void *)handoff->ramstage_entry_point;
return entry;
}
#else