Stefan Reinauer (stefan.reinauer@coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/2788
-gerrit
commit 073a197607a06c585c92393bf20ee4bd482b5836 Author: Aaron Durbin adurbin@chromium.org Date: Fri Feb 8 17:05:36 2013 -0600
rmodule: add ability to calculate module placement
There is a need to calculate the proper placement for an rmodule in memory. e.g. loading a compressed rmodule from flash into ram can be an issue. Determining the placement is hard since the header is not readable until it is decompressed so choosing the wrong location may require a memmove() after decompression. This patch provides a function to perform this calculation by finding region below a given address while making an assumption on the size of the rmodule header..
Change-Id: I2703438f58ae847ed6e80b58063ff820fbcfcbc0 Signed-off-by: Aaron Durbin adurbin@chromium.org --- src/include/rmodule.h | 8 ++++++++ src/lib/rmodule.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+)
diff --git a/src/include/rmodule.h b/src/include/rmodule.h index 89310c9..e8e7636 100644 --- a/src/include/rmodule.h +++ b/src/include/rmodule.h @@ -20,6 +20,7 @@ #define RMODULE_H
#include <stdint.h> +#include <stddef.h>
#define RMODULE_MAGIC 0xf8fe #define RMODULE_VERSION_1 1 @@ -41,6 +42,13 @@ int rmodule_memory_size(const struct rmodule *m); int rmodule_load(void *loc, struct rmodule *m); int rmodule_load_no_clear_bss(void *base, struct rmodule *m); int rmodule_load_alignment(const struct rmodule *m); +/* Returns the an aligned pointer that reflects a region used below addr + * based on the rmodule_size. i.e. the returned pointer up to addr is memory + * that may be utilized by the rmodule. program_start and rmodule_start + * are pointers updated to reflect where the rmodule program starts and where + * the rmodule (including header) should be placed respectively. */ +void *rmodule_find_region_below(void *addr, size_t rmodule_size, + void **program_start, void **rmodule_start);
#define FIELD_ENTRY(x_) ((u32)&x_) #define RMODULE_HEADER(entry_, type_) \ diff --git a/src/lib/rmodule.c b/src/lib/rmodule.c index 6da7a6e..60c89f0 100644 --- a/src/lib/rmodule.c +++ b/src/lib/rmodule.c @@ -17,6 +17,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <stdint.h> +#include <stdlib.h> #include <string.h> #include <console/console.h> #include <rmodule.h> @@ -165,6 +166,12 @@ static void rmodule_copy_payload(const struct rmodule *module) "filesize: 0x%x memsize: 0x%x\n", module->location, rmodule_entry(module), module->payload_size, rmodule_memory_size(module)); + + /* No need to copy the payload if the load location and the + * payload location are the same. */ + if (module->location == module->payload) + return; + memcpy(module->location, module->payload, module->payload_size); }
@@ -253,3 +260,48 @@ int rmodule_load_no_clear_bss(void *base, struct rmodule *module) { return __rmodule_load(base, module, 0); } + +void *rmodule_find_region_below(void *addr, size_t rmodule_size, + void **program_start, void **rmodule_start) +{ + unsigned long ceiling; + unsigned long program_base; + unsigned long placement_loc; + unsigned long program_begin; + + ceiling = (unsigned long)addr; + /* Place the rmodule just under the ceiling. 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, + * however its starting address is determined by the rmodule linker + * script. In short, sizeof(struct rmodule_header) can be less than + * or equal to the linked address of the program. Therefore we want + * to place the rmodule so that the prgoram 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); + /* 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 + * | >= 0 bytes from alignment | + * +--------------------------------+ program end (4KiB aligned) + * | program size | + * +--------------------------------+ program_begin (4KiB aligned) + * | sizeof(struct rmodule_header) | + * +--------------------------------+ rmodule header start + * | >= 0 bytes from alignment | + * +--------------------------------+ program_base (4KiB aligned) + */ + placement_loc = ALIGN(program_base + sizeof(struct rmodule_header), + 4096) - sizeof(struct rmodule_header); + program_begin = placement_loc + sizeof(struct rmodule_header); + + *program_start = (void *)program_begin; + *rmodule_start = (void *)placement_loc; + + return (void *)program_base; +}