diff options
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/Makefile.inc | 1 | ||||
-rw-r--r-- | src/lib/cbfs.c | 61 | ||||
-rw-r--r-- | src/lib/selfboot.c | 16 |
3 files changed, 78 insertions, 0 deletions
diff --git a/src/lib/Makefile.inc b/src/lib/Makefile.inc index d08ee7a4e0..97baaa2be0 100644 --- a/src/lib/Makefile.inc +++ b/src/lib/Makefile.inc @@ -110,6 +110,7 @@ $(obj)/lib/uart8250.smm.o : $(OPTION_TABLE_H) ifeq ($(CONFIG_RELOCATABLE_MODULES),y) ramstage-y += rmodule.c +romstage-$(CONFIG_RELOCATABLE_RAMSTAGE) += rmodule.c RMODULE_LDSCRIPT := $(src)/lib/rmodule.ld RMODULE_LDFLAGS := -nostartfiles -shared -z defs -nostdlib -Bsymbolic -T $(RMODULE_LDSCRIPT) diff --git a/src/lib/cbfs.c b/src/lib/cbfs.c index c56f550e17..4dac4bb5c2 100644 --- a/src/lib/cbfs.c +++ b/src/lib/cbfs.c @@ -36,6 +36,7 @@ #include <cbfs.h> #include <string.h> +#include <cbmem.h> #ifdef LIBPAYLOAD # include <stdio.h> @@ -114,6 +115,65 @@ void *cbfs_load_optionrom(struct cbfs_media *media, uint16_t vendor, return dest; } +#if CONFIG_RELOCATABLE_RAMSTAGE && defined(__PRE_RAM__) + +#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 cbemem location. */ + +void * cbfs_load_stage(struct cbfs_media *media, const char *name) +{ + struct cbfs_stage *stage; + struct rmodule ramstage; + void *cbmem_base; + void *ramstage_base; + void *decompression_loc; + void *ramstage_loc; + struct romstage_handoff *handoff; + + stage = (struct cbfs_stage *) + cbfs_get_file_content(media, name, CBFS_TYPE_STAGE); + + if (stage == NULL) + return (void *) -1; + + cbmem_base = get_cbmem_toc(); + if (cbmem_base == NULL) + return (void *) -1; + + ramstage_base = rmodule_find_region_below(cbmem_base, stage->memlen, + &ramstage_loc, + &decompression_loc); + + LOG("Decompressing stage %s @ 0x%p (%d bytes)\n", + name, decompression_loc, stage->memlen); + + if (cbfs_decompress(stage->compression, &stage[1], + decompression_loc, stage->len)) + return (void *) -1; + + if (rmodule_parse(decompression_loc, &ramstage)) + return (void *) -1; + + /* The ramstage is responsible for clearing its own bss. */ + if (rmodule_load(ramstage_loc, &ramstage)) + return (void *) -1; + + handoff = cbmem_add(CBMEM_ID_ROMSTAGE_INFO, sizeof(*handoff)); + if (handoff) { + handoff->reserve_base = (uint32_t)ramstage_base; + handoff->reserve_size = (uint32_t)cbmem_base - + (uint32_t)ramstage_base; + } else + LOG("Couldn't allocate romstage handoff.\n"); + + return rmodule_entry(&ramstage); +} + +#else + void * cbfs_load_stage(struct cbfs_media *media, const char *name) { struct cbfs_stage *stage = (struct cbfs_stage *) @@ -146,6 +206,7 @@ void * cbfs_load_stage(struct cbfs_media *media, const char *name) return (void *) entry; } +#endif /* CONFIG_RELOCATABLE_RAMSTAGE */ int cbfs_execute_stage(struct cbfs_media *media, const char *name) { diff --git a/src/lib/selfboot.c b/src/lib/selfboot.c index f32bb814fb..f933142144 100644 --- a/src/lib/selfboot.c +++ b/src/lib/selfboot.c @@ -78,6 +78,16 @@ struct segment { static unsigned long bounce_size, bounce_buffer; +#if CONFIG_RELOCATABLE_RAMSTAGE +static void get_bounce_buffer(struct lb_memory *mem, unsigned long req_size) +{ + /* When the ramstage is relocatable there is no need for a bounce + * buffer. All payloads should not overlap the ramstage. + */ + bounce_buffer = ~0UL; + bounce_size = 0; +} +#else static void get_bounce_buffer(struct lb_memory *mem, unsigned long req_size) { unsigned long lb_size; @@ -114,6 +124,7 @@ static void get_bounce_buffer(struct lb_memory *mem, unsigned long req_size) bounce_buffer = buffer; bounce_size = req_size; } +#endif /* CONFIG_RELOCATABLE_RAMSTAGE */ static int valid_area(struct lb_memory *mem, unsigned long buffer, unsigned long start, unsigned long len) @@ -394,8 +405,13 @@ static int load_self_segments( for(ptr = head->next; ptr != head; ptr = ptr->next) { if (!overlaps_coreboot(ptr)) continue; +#if CONFIG_RELOCATABLE_RAMSTAGE + /* payloads are required to not overlap ramstage. */ + return 0; +#else if (ptr->s_dstaddr + ptr->s_memsz > bounce_high) bounce_high = ptr->s_dstaddr + ptr->s_memsz; +#endif } get_bounce_buffer(mem, bounce_high - lb_start); if (!bounce_buffer) { |