program loading: introduce struct prog
The struct prog serves as way to consolidate program loading. This abstraction can be used to perform more complicated execution paths such as running a program on a separate CPU after it has been loaded. Currently t124 and t132 need to do that in the boot path. Follow on patches will allow the platform to decide how to execute a particular program. Note: the vboot path is largely untouched because it's already broken in the coreboot.org tree. After getting all the necessary patches pushed then vboot will be fixed. Change-Id: Ic6e6fe28c5660fb41edee5fd8661eaf58222f883 Signed-off-by: Aaron Durbin <adurbin@chromium.org> Reviewed-on: http://review.coreboot.org/8839 Tested-by: build bot (Jenkins) Tested-by: Raptor Engineering Automated Test Stand <noreply@raptorengineeringinc.com> Reviewed-by: Marc Jones <marc.jones@se-eng.com>
This commit is contained in:
parent
3b631615f6
commit
3948e5392b
|
@ -18,17 +18,14 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <arch/cache.h>
|
#include <arch/cache.h>
|
||||||
#include <arch/stages.h>
|
|
||||||
#include <cbmem.h>
|
|
||||||
#include <console/console.h>
|
|
||||||
#include <program_loading.h>
|
#include <program_loading.h>
|
||||||
|
|
||||||
void arch_payload_run(const struct payload *payload)
|
void arch_payload_run(const struct payload *payload)
|
||||||
{
|
{
|
||||||
void (*doit)(void *) = payload->entry;
|
void (*doit)(void *);
|
||||||
void *cb_tables = cbmem_find(CBMEM_ID_CBTABLE);
|
|
||||||
|
|
||||||
printk(BIOS_SPEW, "entry = %p\n", payload->entry);
|
|
||||||
cache_sync_instructions();
|
cache_sync_instructions();
|
||||||
doit(cb_tables);
|
|
||||||
|
doit = prog_entry(&payload->prog);
|
||||||
|
doit(prog_entry_arg(&payload->prog));
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,21 +23,23 @@
|
||||||
#include <arch/stages.h>
|
#include <arch/stages.h>
|
||||||
#include <arch/spintable.h>
|
#include <arch/spintable.h>
|
||||||
#include <arch/transition.h>
|
#include <arch/transition.h>
|
||||||
#include <cbmem.h>
|
|
||||||
#include <console/console.h>
|
#include <console/console.h>
|
||||||
#include <program_loading.h>
|
#include <program_loading.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
void arch_payload_run(const struct payload *payload)
|
void arch_payload_run(const struct payload *payload)
|
||||||
{
|
{
|
||||||
void (*payload_entry)(void *) = payload->entry;
|
void (*doit)(void *);
|
||||||
|
void *arg;
|
||||||
|
|
||||||
|
doit = prog_entry(&payload->prog);
|
||||||
|
arg = prog_entry_arg(&payload->prog);
|
||||||
|
|
||||||
void *cb_tables = cbmem_find(CBMEM_ID_CBTABLE);
|
|
||||||
uint8_t current_el = get_current_el();
|
uint8_t current_el = get_current_el();
|
||||||
|
|
||||||
printk(BIOS_SPEW, "entry = %p\n", payload->entry);
|
printk(BIOS_SPEW, "entry = %p\n", doit);
|
||||||
|
|
||||||
secmon_run(payload_entry, cb_tables);
|
secmon_run(doit, arg);
|
||||||
|
|
||||||
/* Start the other CPUs spinning. */
|
/* Start the other CPUs spinning. */
|
||||||
spintable_start();
|
spintable_start();
|
||||||
|
@ -46,7 +48,7 @@ void arch_payload_run(const struct payload *payload)
|
||||||
if (current_el != EL3) {
|
if (current_el != EL3) {
|
||||||
cache_sync_instructions();
|
cache_sync_instructions();
|
||||||
/* Point of no-return */
|
/* Point of no-return */
|
||||||
payload_entry(cb_tables);
|
doit(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If current EL is EL3, we transition to payload in EL2. */
|
/* If current EL is EL3, we transition to payload in EL2. */
|
||||||
|
@ -57,5 +59,5 @@ void arch_payload_run(const struct payload *payload)
|
||||||
exc_state.elx.spsr = get_eret_el(EL2, SPSR_USE_L);
|
exc_state.elx.spsr = get_eret_el(EL2, SPSR_USE_L);
|
||||||
|
|
||||||
cache_sync_instructions();
|
cache_sync_instructions();
|
||||||
transition_with_entry(payload->entry, cb_tables, &exc_state);
|
transition_with_entry(doit, arg, &exc_state);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,12 +17,10 @@
|
||||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <console/console.h>
|
|
||||||
#include <arch/stages.h>
|
#include <arch/stages.h>
|
||||||
#include <program_loading.h>
|
#include <program_loading.h>
|
||||||
|
|
||||||
void arch_payload_run(const struct payload *payload)
|
void arch_payload_run(const struct payload *payload)
|
||||||
{
|
{
|
||||||
printk(BIOS_SPEW, "entry = %p\n", payload->entry);
|
stage_exit(prog_entry(&payload->prog));
|
||||||
stage_exit(payload->entry);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,14 +17,11 @@
|
||||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <console/console.h>
|
|
||||||
#include <arch/stages.h>
|
#include <arch/stages.h>
|
||||||
#include <program_loading.h>
|
#include <program_loading.h>
|
||||||
#include <console/uart.h>
|
|
||||||
|
|
||||||
void arch_payload_run(const struct payload *payload)
|
void arch_payload_run(const struct payload *payload)
|
||||||
{
|
{
|
||||||
printk(BIOS_SPEW, "entry = %p\n", payload->entry);
|
|
||||||
// uart_rx_byte(0);
|
// uart_rx_byte(0);
|
||||||
stage_exit(payload->entry);
|
stage_exit(prog_entry(&payload->prog));
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,8 +126,9 @@ static void jmp_payload(void *entry, unsigned long buffer, unsigned long size)
|
||||||
void arch_payload_run(const struct payload *payload)
|
void arch_payload_run(const struct payload *payload)
|
||||||
{
|
{
|
||||||
if (IS_ENABLED(CONFIG_RELOCATABLE_RAMSTAGE))
|
if (IS_ENABLED(CONFIG_RELOCATABLE_RAMSTAGE))
|
||||||
jmp_payload_no_bounce_buffer(payload->entry);
|
jmp_payload_no_bounce_buffer(prog_entry(&payload->prog));
|
||||||
else
|
else
|
||||||
jmp_payload(payload->entry, (uintptr_t)payload->bounce.data,
|
jmp_payload(prog_entry(&payload->prog),
|
||||||
|
(uintptr_t)payload->bounce.data,
|
||||||
payload->bounce.size);
|
payload->bounce.size);
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,6 +57,9 @@ void *cbfs_load_optionrom(struct cbfs_media *media, uint16_t vendor,
|
||||||
uint16_t device, void * dest);
|
uint16_t device, void * dest);
|
||||||
void *cbfs_load_stage(struct cbfs_media *media, const char *name);
|
void *cbfs_load_stage(struct cbfs_media *media, const char *name);
|
||||||
void *cbfs_load_stage_by_offset(struct cbfs_media *media, ssize_t offset);
|
void *cbfs_load_stage_by_offset(struct cbfs_media *media, ssize_t offset);
|
||||||
|
/* Load a stage from a prog structure. Returns < 0 on error. 0 on success. */
|
||||||
|
struct prog;
|
||||||
|
int cbfs_load_prog_stage(struct cbfs_media *media, struct prog *prog);
|
||||||
|
|
||||||
/* Simple buffer for streaming media. */
|
/* Simple buffer for streaming media. */
|
||||||
struct cbfs_simple_buffer {
|
struct cbfs_simple_buffer {
|
||||||
|
|
|
@ -29,10 +29,67 @@ enum {
|
||||||
SEG_FINAL = 1 << 0,
|
SEG_FINAL = 1 << 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Called for each segment of a program loaded. The PROG_FLAG_FINAL will be
|
/* Called for each segment of a program loaded. The SEG_FINAL flag will be
|
||||||
* set on the last segment loaded. */
|
* set on the last segment loaded. */
|
||||||
void arch_segment_loaded(uintptr_t start, size_t size, int flags);
|
void arch_segment_loaded(uintptr_t start, size_t size, int flags);
|
||||||
|
|
||||||
|
struct buffer_area {
|
||||||
|
void *data;
|
||||||
|
size_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum prog_type {
|
||||||
|
PROG_ROMSTAGE,
|
||||||
|
PROG_RAMSTAGE,
|
||||||
|
PROG_PAYLOAD,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Representation of a program. */
|
||||||
|
struct prog {
|
||||||
|
enum prog_type type;
|
||||||
|
const char *name;
|
||||||
|
/* The area can mean different things depending on what type the
|
||||||
|
* program is. e.g. a payload prog uses this field for the backing
|
||||||
|
* store of the payload_segments and data. */
|
||||||
|
struct buffer_area area;
|
||||||
|
/* Entry to program with optional argument. It's up to the architecture
|
||||||
|
* to decide if argument is passed. */
|
||||||
|
void (*entry)(void *);
|
||||||
|
void *arg;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline size_t prog_size(const struct prog *prog)
|
||||||
|
{
|
||||||
|
return prog->area.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void *prog_start(const struct prog *prog)
|
||||||
|
{
|
||||||
|
return prog->area.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void *prog_entry(const struct prog *prog)
|
||||||
|
{
|
||||||
|
return prog->entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void *prog_entry_arg(const struct prog *prog)
|
||||||
|
{
|
||||||
|
return prog->arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void prog_set_area(struct prog *prog, void *start, size_t size)
|
||||||
|
{
|
||||||
|
prog->area.data = start;
|
||||||
|
prog->area.size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void prog_set_entry(struct prog *prog, void *e, void *arg)
|
||||||
|
{
|
||||||
|
prog->entry = e;
|
||||||
|
prog->arg = arg;
|
||||||
|
}
|
||||||
|
|
||||||
/************************
|
/************************
|
||||||
* ROMSTAGE LOADING *
|
* ROMSTAGE LOADING *
|
||||||
************************/
|
************************/
|
||||||
|
@ -45,67 +102,35 @@ void run_romstage(void);
|
||||||
************************/
|
************************/
|
||||||
|
|
||||||
struct romstage_handoff;
|
struct romstage_handoff;
|
||||||
struct cbmem_entry;
|
#if IS_ENABLED(CONFIG_RELOCATABLE_RAMSTAGE)
|
||||||
|
/* Cache the loaded ramstage described by prog. */
|
||||||
#if defined(__PRE_RAM__)
|
void cache_loaded_ramstage(struct romstage_handoff *, struct prog *p);
|
||||||
#if CONFIG_RELOCATABLE_RAMSTAGE
|
/* Load ramstage from cache filling in struct prog. */
|
||||||
/* The cache_loaded_ramstage() and load_cached_ramstage() functions are defined
|
void load_cached_ramstage(struct romstage_handoff *h, struct prog *p);
|
||||||
* to be weak so that board and chipset code may override them. Their job is to
|
#else
|
||||||
* cache and load the ramstage for quick S3 resume. By default a copy of the
|
static inline void cache_loaded_ramstage(struct romstage_handoff *h,
|
||||||
* relocated ramstage is saved using the cbmem infrastructure. These
|
struct prog *p) {}
|
||||||
* functions are only valid during romstage. */
|
static inline void load_cached_ramstage(struct romstage_handoff *h,
|
||||||
|
struct prog *p) {}
|
||||||
/* The implementer of cache_loaded_ramstage() may use the romstage_handoff
|
#endif
|
||||||
* structure to store information, but note that the handoff variable can be
|
|
||||||
* NULL. The ramstage cbmem_entry represents the region occupied by the loaded
|
|
||||||
* ramstage. */
|
|
||||||
void cache_loaded_ramstage(struct romstage_handoff *handoff,
|
|
||||||
const struct cbmem_entry *ramstage, void *entry_point);
|
|
||||||
/* Return NULL on error or entry point on success. The ramstage cbmem_entry is
|
|
||||||
* the region where to load the cached contents to. */
|
|
||||||
void * load_cached_ramstage(struct romstage_handoff *handoff,
|
|
||||||
const struct cbmem_entry *ramstage);
|
|
||||||
#else /* CONFIG_RELOCATABLE_RAMSTAGE */
|
|
||||||
|
|
||||||
static inline void cache_loaded_ramstage(struct romstage_handoff *handoff,
|
|
||||||
const struct cbmem_entry *ramstage, void *entry_point)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void *
|
|
||||||
load_cached_ramstage(struct romstage_handoff *handoff,
|
|
||||||
const struct cbmem_entry *ramstage)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* CONFIG_RELOCATABLE_RAMSTAGE */
|
|
||||||
#endif /* defined(__PRE_RAM__) */
|
|
||||||
|
|
||||||
/* Run ramstage from romstage. */
|
/* Run ramstage from romstage. */
|
||||||
void run_ramstage(void);
|
void run_ramstage(void);
|
||||||
|
|
||||||
struct ramstage_loader_ops {
|
struct ramstage_loader_ops {
|
||||||
const char *name;
|
const char *name;
|
||||||
void *(*load)(uint32_t cbmem_id, const char *name,
|
/* Returns 0 on succes. < 0 on error. */
|
||||||
const struct cbmem_entry **cbmem_entry);
|
int (*load)(struct prog *ramstage);
|
||||||
};
|
};
|
||||||
|
|
||||||
/***********************
|
/***********************
|
||||||
* PAYLOAD LOADING *
|
* PAYLOAD LOADING *
|
||||||
***********************/
|
***********************/
|
||||||
|
|
||||||
struct buffer_area {
|
|
||||||
void *data;
|
|
||||||
size_t size;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct payload {
|
struct payload {
|
||||||
const char *name;
|
struct prog prog;
|
||||||
struct buffer_area backing_store;
|
|
||||||
/* Used when payload wants memory coreboot ramstage is running at. */
|
/* Used when payload wants memory coreboot ramstage is running at. */
|
||||||
struct buffer_area bounce;
|
struct buffer_area bounce;
|
||||||
void *entry;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Load payload into memory in preparation to run. */
|
/* Load payload into memory in preparation to run. */
|
||||||
|
|
|
@ -26,4 +26,3 @@ void __attribute__ ((weak)) arch_segment_loaded(uintptr_t start, size_t size,
|
||||||
{
|
{
|
||||||
/* do nothing */
|
/* do nothing */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -74,17 +74,18 @@ void *cbfs_load_optionrom(struct cbfs_media *media, uint16_t vendor,
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *cbfs_load_stage_by_offset(struct cbfs_media *media, ssize_t offset)
|
static int cbfs_load_prog_stage_by_offset(struct cbfs_media *media,
|
||||||
|
struct prog *prog, ssize_t offset)
|
||||||
{
|
{
|
||||||
struct cbfs_stage stage;
|
struct cbfs_stage stage;
|
||||||
struct cbfs_media backing_store;
|
struct cbfs_media backing_store;
|
||||||
|
|
||||||
if (init_backing_media(&media, &backing_store))
|
if (init_backing_media(&media, &backing_store))
|
||||||
return (void *)-1;
|
return -1;
|
||||||
|
|
||||||
if (cbfs_read(media, &stage, offset, sizeof(stage)) != sizeof(stage)) {
|
if (cbfs_read(media, &stage, offset, sizeof(stage)) != sizeof(stage)) {
|
||||||
ERROR("ERROR: failed to read stage header\n");
|
ERROR("ERROR: failed to read stage header\n");
|
||||||
return (void *)-1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG("loading stage @ 0x%llx (%d bytes), entry @ 0x%llx\n",
|
LOG("loading stage @ 0x%llx (%d bytes), entry @ 0x%llx\n",
|
||||||
|
@ -97,41 +98,71 @@ void *cbfs_load_stage_by_offset(struct cbfs_media *media, ssize_t offset)
|
||||||
if (cbfs_read(media, (void *)(uintptr_t)stage.load,
|
if (cbfs_read(media, (void *)(uintptr_t)stage.load,
|
||||||
offset + sizeof(stage), stage.len) != stage.len) {
|
offset + sizeof(stage), stage.len) != stage.len) {
|
||||||
ERROR("ERROR: Reading stage failed.\n");
|
ERROR("ERROR: Reading stage failed.\n");
|
||||||
return (void *)-1;
|
return -1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
void *data = media->map(media, offset + sizeof(stage),
|
void *data = media->map(media, offset + sizeof(stage),
|
||||||
stage.len);
|
stage.len);
|
||||||
if (data == CBFS_MEDIA_INVALID_MAP_ADDRESS) {
|
if (data == CBFS_MEDIA_INVALID_MAP_ADDRESS) {
|
||||||
ERROR("ERROR: Mapping stage failed.\n");
|
ERROR("ERROR: Mapping stage failed.\n");
|
||||||
return (void *)-1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (!cbfs_decompress(stage.compression, data,
|
if (!cbfs_decompress(stage.compression, data,
|
||||||
(void *)(uintptr_t)stage.load, stage.len))
|
(void *)(uintptr_t)stage.load, stage.len))
|
||||||
return (void *)-1;
|
return -1;
|
||||||
media->unmap(media, data);
|
media->unmap(media, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
arch_segment_loaded(stage.load, stage.memlen, SEG_FINAL);
|
arch_segment_loaded(stage.load, stage.memlen, SEG_FINAL);
|
||||||
DEBUG("stage loaded\n");
|
DEBUG("stage loaded\n");
|
||||||
|
|
||||||
return (void *)(uintptr_t)stage.entry;
|
prog_set_area(prog, (void *)(uintptr_t)stage.load, stage.memlen);
|
||||||
|
prog_set_entry(prog, (void *)(uintptr_t)stage.entry, NULL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *cbfs_load_stage(struct cbfs_media *media, const char *name)
|
int cbfs_load_prog_stage(struct cbfs_media *media, struct prog *prog)
|
||||||
{
|
{
|
||||||
struct cbfs_file file;
|
struct cbfs_file file;
|
||||||
ssize_t offset;
|
ssize_t offset;
|
||||||
struct cbfs_media backing_store;
|
struct cbfs_media backing_store;
|
||||||
|
|
||||||
if (init_backing_media(&media, &backing_store))
|
if (init_backing_media(&media, &backing_store))
|
||||||
return (void *)-1;
|
return -1;
|
||||||
|
|
||||||
offset = cbfs_locate_file(media, &file, name);
|
offset = cbfs_locate_file(media, &file, prog->name);
|
||||||
if (offset < 0 || file.type != CBFS_TYPE_STAGE)
|
if (offset < 0 || file.type != CBFS_TYPE_STAGE)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (cbfs_load_prog_stage_by_offset(media, prog, offset) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *cbfs_load_stage_by_offset(struct cbfs_media *media, ssize_t offset)
|
||||||
|
{
|
||||||
|
struct prog prog = {
|
||||||
|
.name = NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (cbfs_load_prog_stage_by_offset(media, &prog, offset) < 0)
|
||||||
return (void *)-1;
|
return (void *)-1;
|
||||||
|
|
||||||
return cbfs_load_stage_by_offset(media, offset);
|
return prog_entry(&prog);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *cbfs_load_stage(struct cbfs_media *media, const char *name)
|
||||||
|
{
|
||||||
|
struct prog prog = {
|
||||||
|
.name = name,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (cbfs_load_prog_stage(media, &prog) < 0)
|
||||||
|
return (void *)-1;
|
||||||
|
|
||||||
|
return prog_entry(&prog);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Simple buffer */
|
/* Simple buffer */
|
||||||
|
|
|
@ -26,14 +26,13 @@ static int cbfs_locate_payload(struct payload *payload)
|
||||||
size_t size;
|
size_t size;
|
||||||
const int type = CBFS_TYPE_PAYLOAD;
|
const int type = CBFS_TYPE_PAYLOAD;
|
||||||
|
|
||||||
buffer = cbfs_get_file_content(CBFS_DEFAULT_MEDIA, payload->name,
|
buffer = cbfs_get_file_content(CBFS_DEFAULT_MEDIA, payload->prog.name,
|
||||||
type, &size);
|
type, &size);
|
||||||
|
|
||||||
if (buffer == NULL)
|
if (buffer == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
payload->backing_store.data = buffer;
|
prog_set_area(&payload->prog, buffer, size);
|
||||||
payload->backing_store.size = size;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,44 +19,37 @@
|
||||||
*/
|
*/
|
||||||
#include <console/console.h>
|
#include <console/console.h>
|
||||||
#include <cbfs.h>
|
#include <cbfs.h>
|
||||||
#include <arch/stages.h>
|
|
||||||
#include <program_loading.h>
|
#include <program_loading.h>
|
||||||
#include <timestamp.h>
|
|
||||||
|
|
||||||
#if CONFIG_RELOCATABLE_RAMSTAGE
|
#if CONFIG_RELOCATABLE_RAMSTAGE
|
||||||
#include <rmodule.h>
|
#include <rmodule.h>
|
||||||
|
#include <cbmem.h>
|
||||||
|
|
||||||
static void *cbfs_load_ramstage(uint32_t cbmem_id, const char *name,
|
static int cbfs_load_ramstage(struct prog *ramstage)
|
||||||
const struct cbmem_entry **cbmem_entry)
|
|
||||||
{
|
{
|
||||||
struct rmod_stage_load rmod_ram = {
|
struct rmod_stage_load rmod_ram = {
|
||||||
.cbmem_id = cbmem_id,
|
.cbmem_id = CBMEM_ID_RAMSTAGE,
|
||||||
.name = name,
|
.name = ramstage->name,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (rmodule_stage_load_from_cbfs(&rmod_ram)) {
|
if (rmodule_stage_load_from_cbfs(&rmod_ram)) {
|
||||||
printk(BIOS_DEBUG, "Could not load ramstage.\n");
|
printk(BIOS_DEBUG, "Could not load ramstage.\n");
|
||||||
return NULL;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
*cbmem_entry = rmod_ram.cbmem_entry;
|
prog_set_area(ramstage, cbmem_entry_start(rmod_ram.cbmem_entry),
|
||||||
|
cbmem_entry_size(rmod_ram.cbmem_entry));
|
||||||
|
prog_set_entry(ramstage, rmod_ram.entry, NULL);
|
||||||
|
|
||||||
return rmod_ram.entry;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else /* CONFIG_RELOCATABLE_RAMSTAGE */
|
#else /* CONFIG_RELOCATABLE_RAMSTAGE */
|
||||||
|
|
||||||
static void *cbfs_load_ramstage(uint32_t cbmem_id, const char *name,
|
static int cbfs_load_ramstage(struct prog *ramstage)
|
||||||
const struct cbmem_entry **cbmem_entry)
|
|
||||||
{
|
{
|
||||||
void *entry;
|
return cbfs_load_prog_stage(CBFS_DEFAULT_MEDIA, ramstage);
|
||||||
|
|
||||||
entry = cbfs_load_stage(CBFS_DEFAULT_MEDIA, name);
|
|
||||||
|
|
||||||
if ((void *)entry == (void *) -1)
|
|
||||||
entry = NULL;
|
|
||||||
|
|
||||||
return entry;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_RELOCATABLE_RAMSTAGE */
|
#endif /* CONFIG_RELOCATABLE_RAMSTAGE */
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <cbmem.h>
|
||||||
#include <console/console.h>
|
#include <console/console.h>
|
||||||
#include <fallback.h>
|
#include <fallback.h>
|
||||||
#include <lib.h>
|
#include <lib.h>
|
||||||
|
@ -36,7 +37,10 @@ static const struct payload_loader_ops *payload_ops[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct payload global_payload = {
|
static struct payload global_payload = {
|
||||||
|
.prog = {
|
||||||
.name = CONFIG_CBFS_PREFIX "/payload",
|
.name = CONFIG_CBFS_PREFIX "/payload",
|
||||||
|
.type = PROG_PAYLOAD,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
void __attribute__((weak)) mirror_payload(struct payload *payload)
|
void __attribute__((weak)) mirror_payload(struct payload *payload)
|
||||||
|
@ -47,9 +51,9 @@ void __attribute__((weak)) mirror_payload(struct payload *payload)
|
||||||
void payload_load(void)
|
void payload_load(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
void *entry;
|
|
||||||
const struct payload_loader_ops *ops;
|
const struct payload_loader_ops *ops;
|
||||||
struct payload *payload = &global_payload;
|
struct payload *payload = &global_payload;
|
||||||
|
struct prog * prog = &payload->prog;
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(payload_ops); i++) {
|
for (i = 0; i < ARRAY_SIZE(payload_ops); i++) {
|
||||||
ops = payload_ops[i];
|
ops = payload_ops[i];
|
||||||
|
@ -59,8 +63,7 @@ void payload_load(void)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
printk(BIOS_DEBUG, "%s: located payload @ %p, %zu bytes.\n",
|
printk(BIOS_DEBUG, "%s: located payload @ %p, %zu bytes.\n",
|
||||||
ops->name, payload->backing_store.data,
|
ops->name, prog_start(prog), prog_size(prog));
|
||||||
payload->backing_store.size);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,12 +72,12 @@ void payload_load(void)
|
||||||
|
|
||||||
mirror_payload(payload);
|
mirror_payload(payload);
|
||||||
|
|
||||||
entry = selfload(payload);
|
/* Pass cbtables to payload if architecture desires it. */
|
||||||
|
prog_set_entry(&payload->prog, selfload(payload),
|
||||||
payload->entry = entry;
|
cbmem_find(CBMEM_ID_CBTABLE));
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (payload->entry == NULL)
|
if (prog_entry(&payload->prog) == NULL)
|
||||||
die("Payload not loaded.\n");
|
die("Payload not loaded.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,7 +88,8 @@ void payload_run(void)
|
||||||
/* Reset to booting from this image as late as possible */
|
/* Reset to booting from this image as late as possible */
|
||||||
boot_successful();
|
boot_successful();
|
||||||
|
|
||||||
printk(BIOS_DEBUG, "Jumping to boot code at %p\n", payload->entry);
|
printk(BIOS_DEBUG, "Jumping to boot code at %p(%p)\n",
|
||||||
|
prog_entry(&payload->prog), prog_entry_arg(&payload->prog));
|
||||||
post_code(POST_ENTER_ELF_BOOT);
|
post_code(POST_ENTER_ELF_BOOT);
|
||||||
|
|
||||||
timestamp_add_now(TS_SELFBOOT_JUMP);
|
timestamp_add_now(TS_SELFBOOT_JUMP);
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
#include <console/console.h>
|
#include <console/console.h>
|
||||||
#include <arch/stages.h>
|
#include <arch/stages.h>
|
||||||
#include <cbfs.h>
|
#include <cbfs.h>
|
||||||
#include <cbmem.h>
|
|
||||||
#include <program_loading.h>
|
#include <program_loading.h>
|
||||||
#include <romstage_handoff.h>
|
#include <romstage_handoff.h>
|
||||||
#include <timestamp.h>
|
#include <timestamp.h>
|
||||||
|
@ -36,46 +35,32 @@ static const struct ramstage_loader_ops *loaders[] = {
|
||||||
&cbfs_ramstage_loader,
|
&cbfs_ramstage_loader,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *ramstage_name = CONFIG_CBFS_PREFIX "/ramstage";
|
|
||||||
static const uint32_t ramstage_id = CBMEM_ID_RAMSTAGE;
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
load_ramstage(const struct ramstage_loader_ops *ops, struct romstage_handoff *handoff)
|
load_ramstage(const struct ramstage_loader_ops *ops,
|
||||||
|
struct romstage_handoff *handoff, struct prog *ramstage)
|
||||||
{
|
{
|
||||||
const struct cbmem_entry *cbmem_entry;
|
|
||||||
void *entry_point;
|
|
||||||
|
|
||||||
timestamp_add_now(TS_START_COPYRAM);
|
timestamp_add_now(TS_START_COPYRAM);
|
||||||
entry_point = ops->load(ramstage_id, ramstage_name, &cbmem_entry);
|
|
||||||
|
|
||||||
if (entry_point == NULL)
|
if (ops->load(ramstage))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
cache_loaded_ramstage(handoff, cbmem_entry, entry_point);
|
cache_loaded_ramstage(handoff, ramstage);
|
||||||
|
|
||||||
timestamp_add_now(TS_END_COPYRAM);
|
timestamp_add_now(TS_END_COPYRAM);
|
||||||
|
|
||||||
stage_exit(entry_point);
|
stage_exit(prog_entry(ramstage));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void run_ramstage_from_resume(struct romstage_handoff *handoff)
|
static void run_ramstage_from_resume(struct romstage_handoff *handoff,
|
||||||
|
struct prog *ramstage)
|
||||||
{
|
{
|
||||||
void *entry;
|
|
||||||
const struct cbmem_entry *cbmem_entry;
|
|
||||||
|
|
||||||
if (handoff != NULL && handoff->s3_resume) {
|
if (handoff != NULL && handoff->s3_resume) {
|
||||||
cbmem_entry = cbmem_entry_find(ramstage_id);
|
|
||||||
|
|
||||||
/* No place to load ramstage. */
|
|
||||||
if (cbmem_entry == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Load the cached ramstage to runtime location. */
|
/* Load the cached ramstage to runtime location. */
|
||||||
entry = load_cached_ramstage(handoff, cbmem_entry);
|
load_cached_ramstage(handoff, ramstage);
|
||||||
|
|
||||||
if (entry != NULL) {
|
if (prog_entry(ramstage) != NULL) {
|
||||||
printk(BIOS_DEBUG, "Jumping to image.\n");
|
printk(BIOS_DEBUG, "Jumping to image.\n");
|
||||||
stage_exit(entry);
|
stage_exit(prog_entry(ramstage));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,15 +70,19 @@ void run_ramstage(void)
|
||||||
struct romstage_handoff *handoff;
|
struct romstage_handoff *handoff;
|
||||||
const struct ramstage_loader_ops *ops;
|
const struct ramstage_loader_ops *ops;
|
||||||
int i;
|
int i;
|
||||||
|
struct prog ramstage = {
|
||||||
|
.name = CONFIG_CBFS_PREFIX "/ramstage",
|
||||||
|
.type = PROG_RAMSTAGE,
|
||||||
|
};
|
||||||
|
|
||||||
handoff = romstage_handoff_find_or_add();
|
handoff = romstage_handoff_find_or_add();
|
||||||
|
|
||||||
run_ramstage_from_resume(handoff);
|
run_ramstage_from_resume(handoff, &ramstage);
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(loaders); i++) {
|
for (i = 0; i < ARRAY_SIZE(loaders); i++) {
|
||||||
ops = loaders[i];
|
ops = loaders[i];
|
||||||
printk(BIOS_DEBUG, "Trying %s ramstage loader.\n", ops->name);
|
printk(BIOS_DEBUG, "Trying %s ramstage loader.\n", ops->name);
|
||||||
load_ramstage(ops, handoff);
|
load_ramstage(ops, handoff, &ramstage);
|
||||||
}
|
}
|
||||||
|
|
||||||
die("Ramstage was not loaded!\n");
|
die("Ramstage was not loaded!\n");
|
||||||
|
|
|
@ -27,16 +27,16 @@
|
||||||
|
|
||||||
void run_romstage(void)
|
void run_romstage(void)
|
||||||
{
|
{
|
||||||
void *entry;
|
struct prog romstage = {
|
||||||
|
.name = CONFIG_CBFS_PREFIX "/romstage",
|
||||||
|
.type = PROG_ROMSTAGE,
|
||||||
|
};
|
||||||
|
|
||||||
entry = cbfs_load_stage(CBFS_DEFAULT_MEDIA,
|
if (cbfs_load_prog_stage(CBFS_DEFAULT_MEDIA, &romstage) < 0) {
|
||||||
CONFIG_CBFS_PREFIX "/romstage");
|
|
||||||
|
|
||||||
if (entry == (void *)-1) {
|
|
||||||
if (IS_ENABLED(CONFIG_BOOTBLOCK_CONSOLE))
|
if (IS_ENABLED(CONFIG_BOOTBLOCK_CONSOLE))
|
||||||
die("Couldn't load romstage.\n");
|
die("Couldn't load romstage.\n");
|
||||||
halt();
|
halt();
|
||||||
}
|
}
|
||||||
|
|
||||||
stage_exit(entry);
|
stage_exit(prog_entry(&romstage));
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,8 +27,7 @@
|
||||||
#if CONFIG_CACHE_RELOCATED_RAMSTAGE_OUTSIDE_CBMEM
|
#if CONFIG_CACHE_RELOCATED_RAMSTAGE_OUTSIDE_CBMEM
|
||||||
|
|
||||||
void cache_loaded_ramstage(struct romstage_handoff *handoff,
|
void cache_loaded_ramstage(struct romstage_handoff *handoff,
|
||||||
const struct cbmem_entry *ramstage,
|
struct prog *ramstage)
|
||||||
void *entry_point)
|
|
||||||
{
|
{
|
||||||
struct ramstage_cache *cache;
|
struct ramstage_cache *cache;
|
||||||
uint32_t total_size;
|
uint32_t total_size;
|
||||||
|
@ -36,8 +35,8 @@ void cache_loaded_ramstage(struct romstage_handoff *handoff,
|
||||||
void *ramstage_base;
|
void *ramstage_base;
|
||||||
long cache_size = 0;
|
long cache_size = 0;
|
||||||
|
|
||||||
ramstage_size = cbmem_entry_size(ramstage);
|
ramstage_size = prog_size(ramstage);
|
||||||
ramstage_base = cbmem_entry_start(ramstage);
|
ramstage_base = prog_start(ramstage);
|
||||||
|
|
||||||
cache = ramstage_cache_location(&cache_size);
|
cache = ramstage_cache_location(&cache_size);
|
||||||
|
|
||||||
|
@ -56,7 +55,7 @@ void cache_loaded_ramstage(struct romstage_handoff *handoff,
|
||||||
}
|
}
|
||||||
|
|
||||||
cache->magic = RAMSTAGE_CACHE_MAGIC;
|
cache->magic = RAMSTAGE_CACHE_MAGIC;
|
||||||
cache->entry_point = (uint32_t)entry_point;
|
cache->entry_point = (uint32_t)prog_entry(ramstage);
|
||||||
cache->load_address = (uint32_t)ramstage_base;
|
cache->load_address = (uint32_t)ramstage_base;
|
||||||
cache->size = ramstage_size;
|
cache->size = ramstage_size;
|
||||||
|
|
||||||
|
@ -68,11 +67,11 @@ void cache_loaded_ramstage(struct romstage_handoff *handoff,
|
||||||
if (handoff == NULL)
|
if (handoff == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
handoff->ramstage_entry_point = (uint32_t)entry_point;
|
handoff->ramstage_entry_point = cache->entry_point;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *load_cached_ramstage(struct romstage_handoff *handoff,
|
void load_cached_ramstage(struct romstage_handoff *handoff,
|
||||||
const struct cbmem_entry *ramstage)
|
struct prog *ramstage)
|
||||||
{
|
{
|
||||||
struct ramstage_cache *cache;
|
struct ramstage_cache *cache;
|
||||||
long size = 0;
|
long size = 0;
|
||||||
|
@ -82,14 +81,15 @@ void *load_cached_ramstage(struct romstage_handoff *handoff,
|
||||||
if (!ramstage_cache_is_valid(cache)) {
|
if (!ramstage_cache_is_valid(cache)) {
|
||||||
printk(BIOS_DEBUG, "Invalid ramstage cache found.\n");
|
printk(BIOS_DEBUG, "Invalid ramstage cache found.\n");
|
||||||
ramstage_cache_invalid(cache);
|
ramstage_cache_invalid(cache);
|
||||||
return NULL;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
printk(BIOS_DEBUG, "Loading ramstage from %p.\n", cache);
|
printk(BIOS_DEBUG, "Loading ramstage from %p.\n", cache);
|
||||||
|
|
||||||
memcpy((void *)cache->load_address, &cache->program[0], cache->size);
|
prog_set_area(ramstage, (void *)cache->load_address, cache->size);
|
||||||
|
prog_set_entry(ramstage, (void *)cache->entry_point, NULL);
|
||||||
|
|
||||||
return (void *)cache->entry_point;
|
memcpy((void *)cache->load_address, &cache->program[0], cache->size);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
@ -97,7 +97,7 @@ void *load_cached_ramstage(struct romstage_handoff *handoff,
|
||||||
/* Cache relocated ramstage in CBMEM. */
|
/* Cache relocated ramstage in CBMEM. */
|
||||||
|
|
||||||
void cache_loaded_ramstage(struct romstage_handoff *handoff,
|
void cache_loaded_ramstage(struct romstage_handoff *handoff,
|
||||||
const struct cbmem_entry *ramstage, void *entry_point)
|
struct prog *ramstage)
|
||||||
{
|
{
|
||||||
uint32_t ramstage_size;
|
uint32_t ramstage_size;
|
||||||
const struct cbmem_entry *entry;
|
const struct cbmem_entry *entry;
|
||||||
|
@ -105,7 +105,7 @@ void cache_loaded_ramstage(struct romstage_handoff *handoff,
|
||||||
if (handoff == NULL)
|
if (handoff == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ramstage_size = cbmem_entry_size(ramstage);
|
ramstage_size = prog_size(ramstage);
|
||||||
/* cbmem_entry_add() does a find() before add(). */
|
/* cbmem_entry_add() does a find() before add(). */
|
||||||
entry = cbmem_entry_add(CBMEM_ID_RAMSTAGE_CACHE, ramstage_size);
|
entry = cbmem_entry_add(CBMEM_ID_RAMSTAGE_CACHE, ramstage_size);
|
||||||
|
|
||||||
|
@ -113,30 +113,37 @@ void cache_loaded_ramstage(struct romstage_handoff *handoff,
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Keep track of the entry point in the handoff structure. */
|
/* Keep track of the entry point in the handoff structure. */
|
||||||
handoff->ramstage_entry_point = (uint32_t)entry_point;
|
handoff->ramstage_entry_point = (uint32_t)prog_entry(ramstage);
|
||||||
|
|
||||||
memcpy(cbmem_entry_start(entry), cbmem_entry_start(ramstage),
|
memcpy(cbmem_entry_start(entry), prog_start(ramstage), ramstage_size);
|
||||||
ramstage_size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void *load_cached_ramstage(struct romstage_handoff *handoff,
|
void load_cached_ramstage(struct romstage_handoff *handoff,
|
||||||
const struct cbmem_entry *ramstage)
|
struct prog *ramstage)
|
||||||
{
|
{
|
||||||
const struct cbmem_entry *entry_cache;
|
const struct cbmem_entry *entry_cache;
|
||||||
|
const struct cbmem_entry *entry_dest;
|
||||||
|
|
||||||
if (handoff == NULL)
|
if (handoff == NULL)
|
||||||
return NULL;
|
return;
|
||||||
|
|
||||||
entry_cache = cbmem_entry_find(CBMEM_ID_RAMSTAGE_CACHE);
|
entry_cache = cbmem_entry_find(CBMEM_ID_RAMSTAGE_CACHE);
|
||||||
|
|
||||||
if (entry_cache == NULL)
|
if (entry_cache == NULL)
|
||||||
return NULL;
|
return;
|
||||||
|
|
||||||
|
entry_dest = cbmem_entry_find(CBMEM_ID_RAMSTAGE);
|
||||||
|
|
||||||
|
if (entry_dest == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
prog_set_area(ramstage, cbmem_entry_start(entry_dest),
|
||||||
|
cbmem_entry_size(entry_dest));
|
||||||
|
prog_set_entry(ramstage, (void *)handoff->ramstage_entry_point, NULL);
|
||||||
|
|
||||||
/* Load the cached ramstage copy into the to-be-run region. */
|
/* Load the cached ramstage copy into the to-be-run region. */
|
||||||
memcpy(cbmem_entry_start(ramstage), cbmem_entry_start(entry_cache),
|
memcpy(prog_start(ramstage), cbmem_entry_start(entry_cache),
|
||||||
cbmem_entry_size(ramstage));
|
prog_size(ramstage));
|
||||||
|
|
||||||
return (void *)handoff->ramstage_entry_point;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -220,7 +220,7 @@ static int build_self_segment_list(
|
||||||
struct segment *ptr;
|
struct segment *ptr;
|
||||||
struct cbfs_payload_segment *segment, *first_segment;
|
struct cbfs_payload_segment *segment, *first_segment;
|
||||||
struct cbfs_payload *cbfs_payload;
|
struct cbfs_payload *cbfs_payload;
|
||||||
cbfs_payload = payload->backing_store.data;
|
cbfs_payload = prog_start(&payload->prog);
|
||||||
memset(head, 0, sizeof(*head));
|
memset(head, 0, sizeof(*head));
|
||||||
head->next = head->prev = head;
|
head->next = head->prev = head;
|
||||||
first_segment = segment = &cbfs_payload->segments;
|
first_segment = segment = &cbfs_payload->segments;
|
||||||
|
|
Loading…
Reference in New Issue