coreboot: dynamic cbmem requirement

Dynamic cbmem is now a requirement for relocatable ramstage.
This patch replaces the reserve_* fields in the romstage_handoff
structure by using the dynamic cbmem library.

The haswell code is not moved over in this commit, but it should be
safe because there is a hard requirement for DYNAMIC_CBMEM when using
a reloctable ramstage.

Change-Id: I59ab4552c3ae8c2c3982df458cd81a4a9b712cc2
Signed-off-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/2849
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
This commit is contained in:
Aaron Durbin
2013-02-27 22:50:12 -06:00
committed by Stefan Reinauer
parent 24d1d4b472
commit dd4a6d2357
10 changed files with 94 additions and 133 deletions

View File

@@ -120,41 +120,48 @@ void *cbfs_load_optionrom(struct cbfs_media *media, uint16_t vendor,
#include <rmodule.h>
#include <romstage_handoff.h>
/* When CONFIG_RELOCATABLE_RAMSTAGE is enabled and this file is being compiled
* for the romstage, the rmodule loader is used. The ramstage is placed just
* below the cbmem location. */
* for the romstage, the rmodule loader is used. */
void __attribute__((weak))
cache_loaded_ramstage(struct romstage_handoff *handoff, void *ramstage_base,
uint32_t ramstage_size, void *entry_point)
cache_loaded_ramstage(struct romstage_handoff *handoff,
const struct cbmem_entry *ramstage, void *entry_point)
{
uint32_t ramstage_size;
const struct cbmem_entry *entry;
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;
ramstage_size = cbmem_entry_size(ramstage);
/* cbmem_entry_add() does a find() before add(). */
entry = cbmem_entry_add(CBMEM_ID_RAMSTAGE_CACHE, ramstage_size);
if (entry == NULL)
return;
/* Keep track of the entry point in the handoff structure. */
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;
memcpy(cbmem_entry_start(entry), cbmem_entry_start(ramstage),
ramstage_size);
}
void * __attribute__((weak))
load_cached_ramstage(struct romstage_handoff *handoff)
load_cached_ramstage(struct romstage_handoff *handoff,
const struct cbmem_entry *ramstage)
{
uint32_t ramstage_size;
const struct cbmem_entry *entry_cache;
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);
entry_cache = cbmem_entry_find(CBMEM_ID_RAMSTAGE_CACHE);
if (entry_cache == NULL)
return NULL;
/* Load the cached ramstage copy into the to-be-run region. */
memcpy(cbmem_entry_start(ramstage), cbmem_entry_start(entry_cache),
cbmem_entry_size(ramstage));
return (void *)handoff->ramstage_entry_point;
}
@@ -164,12 +171,12 @@ static void *load_stage_from_cbfs(struct cbfs_media *media, const char *name,
{
struct cbfs_stage *stage;
struct rmodule ramstage;
char *cbmem_base;
char *ramstage_base;
void *decompression_loc;
void *ramstage_loc;
void *entry_point;
uint32_t ramstage_size;
size_t region_size;
char *ramstage_region;
int rmodule_offset;
int load_offset;
const struct cbmem_entry *ramstage_entry;
stage = (struct cbfs_stage *)
cbfs_get_file_content(media, name, CBFS_TYPE_STAGE);
@@ -177,34 +184,34 @@ static void *load_stage_from_cbfs(struct cbfs_media *media, const char *name,
if (stage == NULL)
return (void *) -1;
cbmem_base = (void *)get_cbmem_toc();
if (cbmem_base == NULL)
rmodule_offset =
rmodule_calc_region(DYN_CBMEM_ALIGN_SIZE,
stage->memlen, &region_size, &load_offset);
ramstage_entry = cbmem_entry_add(CBMEM_ID_RAMSTAGE, region_size);
if (ramstage_entry == NULL)
return (void *) -1;
ramstage_base =
rmodule_find_region_below(cbmem_base, stage->memlen,
&ramstage_loc,
&decompression_loc);
ramstage_region = cbmem_entry_start(ramstage_entry);
LOG("Decompressing stage %s @ 0x%p (%d bytes)\n",
name, decompression_loc, stage->memlen);
name, &ramstage_region[rmodule_offset], stage->memlen);
if (cbfs_decompress(stage->compression, &stage[1],
decompression_loc, stage->len))
&ramstage_region[rmodule_offset], stage->len))
return (void *) -1;
if (rmodule_parse(decompression_loc, &ramstage))
if (rmodule_parse(&ramstage_region[rmodule_offset], &ramstage))
return (void *) -1;
/* The ramstage is responsible for clearing its own bss. */
if (rmodule_load(ramstage_loc, &ramstage))
if (rmodule_load(&ramstage_region[load_offset], &ramstage))
return (void *) -1;
entry_point = rmodule_entry(&ramstage);
ramstage_size = cbmem_base - ramstage_base;
cache_loaded_ramstage(handoff, ramstage_base, ramstage_size,
entry_point);
cache_loaded_ramstage(handoff, ramstage_entry, entry_point);
return entry_point;
}
@@ -212,6 +219,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;
const struct cbmem_entry *ramstage;
void *entry;
handoff = romstage_handoff_find_or_add();
@@ -222,9 +230,14 @@ void * cbfs_load_stage(struct cbfs_media *media, const char *name)
} else if (!handoff->s3_resume)
return load_stage_from_cbfs(media, name, handoff);
ramstage = cbmem_entry_find(CBMEM_ID_RAMSTAGE);
if (ramstage == NULL)
return load_stage_from_cbfs(name, handoff);
/* S3 resume path. Load a cached copy of the loaded ramstage. If
* return value is NULL load from cbfs. */
entry = load_cached_ramstage(handoff);
entry = load_cached_ramstage(handoff, ramstage);
if (entry == NULL)
return load_stage_from_cbfs(name, handoff);

View File

@@ -85,15 +85,6 @@ void hardwaremain(int boot_complete)
/* FIXME: Is there a better way to handle this? */
init_timer();
/* CONFIG_EARLY_CBMEM_INIT indicates that romstage initialized
* the cbmem area. Therefore the table location can be initialized
* early in ramstage if cbmem_get_table_location() is implemented.
*/
#if CONFIG_EARLY_CBMEM_INIT
if (cbmem_get_table_location != NULL &&
!cbmem_get_table_location(&high_tables_base, &high_tables_size))
cbmem_initialize();
#endif
init_cbmem_pre_device();
timestamp_stash(TS_DEVICE_ENUMERATE);

View File

@@ -16,6 +16,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
@@ -254,16 +255,22 @@ int rmodule_load(void *base, struct rmodule *module)
return 0;
}
void *rmodule_find_region_below(void *addr, size_t rmodule_size,
void **program_start, void **rmodule_start)
int rmodule_calc_region(unsigned int region_alignment, size_t rmodule_size,
size_t *region_size, int *load_offset)
{
unsigned long ceiling;
unsigned long program_base;
unsigned long placement_loc;
unsigned long program_begin;
/* region_alignment must be a power of 2. */
if (region_alignment & (region_alignment - 1))
BUG();
ceiling = (unsigned long)addr;
/* Place the rmodule just under the ceiling. The rmodule files
if (region_alignment < 4096)
region_alignment = 4096;
/* Sanity check rmodule_header size. The code below assumes it is less
* than the minimum alignment required. */
if (region_alignment < sizeof(struct rmodule_header))
BUG();
/* Place the rmodule according to alignment. The rmodule files
* themselves are packed as a header and a payload, however the rmodule
* itself is linked along with the header. The header starts at address
* 0. Immediately following the header in the file is the program,
@@ -273,13 +280,13 @@ void *rmodule_find_region_below(void *addr, size_t rmodule_size,
* to place the rmodule so that the program falls on the aligned
* address with the header just before it. Therefore, we need at least
* a page to account for the size of the header. */
program_base = ALIGN((ceiling - (rmodule_size + 4096)), 4096);
*region_size = ALIGN(rmodule_size + region_alignment, 4096);
/* The program starts immediately after the header. However,
* it needs to be aligned to a 4KiB boundary. Therefore, adjust the
* program location so that the program lands on a page boundary. The
* layout looks like the following:
*
* +--------------------------------+ ceiling
* +--------------------------------+ region_alignment + region_size
* | >= 0 bytes from alignment |
* +--------------------------------+ program end (4KiB aligned)
* | program size |
@@ -287,14 +294,9 @@ void *rmodule_find_region_below(void *addr, size_t rmodule_size,
* | sizeof(struct rmodule_header) |
* +--------------------------------+ rmodule header start
* | >= 0 bytes from alignment |
* +--------------------------------+ program_base (4KiB aligned)
* +--------------------------------+ region_alignment
*/
placement_loc = ALIGN(program_base + sizeof(struct rmodule_header),
4096) - sizeof(struct rmodule_header);
program_begin = placement_loc + sizeof(struct rmodule_header);
*load_offset = region_alignment;
*program_start = (void *)program_begin;
*rmodule_start = (void *)placement_loc;
return (void *)program_base;
return region_alignment - sizeof(struct rmodule_header);
}