From e8c866ad45d80de768c9422474449e171d133575 Mon Sep 17 00:00:00 2001 From: Aaron Durbin Date: Fri, 8 Feb 2013 17:05:36 -0600 Subject: 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 Reviewed-on: http://review.coreboot.org/2788 Tested-by: build bot (Jenkins) Reviewed-by: Ronald G. Minnich --- src/lib/rmodule.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) (limited to 'src/lib') diff --git a/src/lib/rmodule.c b/src/lib/rmodule.c index 56d7c6d646..81e9ef10ed 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 +#include #include #include #include @@ -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); } @@ -243,3 +250,47 @@ int rmodule_load(void *base, struct rmodule *module) return rmodule_relocate(module); } +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 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); + /* 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; +} -- cgit v1.2.3