diff options
Diffstat (limited to 'src/lib/rmodule.c')
-rw-r--r-- | src/lib/rmodule.c | 80 |
1 files changed, 30 insertions, 50 deletions
diff --git a/src/lib/rmodule.c b/src/lib/rmodule.c index 6ea9db724b..ac9eb0b306 100644 --- a/src/lib/rmodule.c +++ b/src/lib/rmodule.c @@ -2,7 +2,6 @@ #include <assert.h> #include <cbmem.h> #include <cbfs.h> -#include <cbfs_private.h> #include <stdint.h> #include <stdlib.h> #include <string.h> @@ -13,6 +12,8 @@ /* Change this define to get more verbose debugging for module loading. */ #define PK_ADJ_LEVEL BIOS_NEVER +const size_t region_alignment = MIN_UNSAFE(DYN_CBMEM_ALIGN_SIZE, 4096); + static inline int rmodule_is_loaded(const struct rmodule *module) { return module->location != NULL; @@ -190,20 +191,26 @@ int rmodule_load(void *base, struct rmodule *module) return 0; } -int rmodule_calc_region(unsigned int region_alignment, size_t rmodule_size, - size_t *region_size, int *load_offset) +static void *rmodule_cbfs_allocator(void *rsl_arg, size_t unused, + union cbfs_mdata *mdata) { - /* region_alignment must be a power of 2. */ - if (region_alignment & (region_alignment - 1)) - BUG(); - - if (region_alignment < 4096) - region_alignment = 4096; + struct rmod_stage_load *rsl = rsl_arg; + + assert(IS_POWER_OF_2(region_alignment) && + region_alignment >= sizeof(struct rmodule_header)); + + /* The CBFS core just passes us the decompressed size of the file, but + we need to know the memlen of the binary image. We need to find and + parse the stage header explicitly. */ + const struct cbfs_file_attr_stageheader *sattr = cbfs_find_attr(mdata, + CBFS_FILE_ATTR_TAG_STAGEHEADER, sizeof(*sattr)); + if (!sattr) { + printk(BIOS_ERR, "rmodule '%s' has no stage header!\n", + rsl->prog->name); + return NULL; + } - /* 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(); + const size_t memlen = be32toh(sattr->memlen); /* Place the rmodule according to alignment. The rmodule files * themselves are packed as a header and a payload, however the rmodule @@ -215,7 +222,7 @@ int rmodule_calc_region(unsigned int region_alignment, 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. */ - *region_size = ALIGN(rmodule_size + region_alignment, 4096); + size_t region_size = ALIGN(memlen + 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 @@ -231,22 +238,17 @@ int rmodule_calc_region(unsigned int region_alignment, size_t rmodule_size, * | >= 0 bytes from alignment | * +--------------------------------+ region_alignment */ - *load_offset = region_alignment; - return region_alignment - sizeof(struct rmodule_header); + uint8_t *stage_region = cbmem_add(rsl->cbmem_id, region_size); + if (stage_region == NULL) + return NULL; + + return stage_region + region_alignment - sizeof(struct rmodule_header); } int rmodule_stage_load(struct rmod_stage_load *rsl) { struct rmodule rmod_stage; - size_t region_size; - char *stage_region; - int rmodule_offset; - int load_offset; - struct cbfs_stage stage; - void *rmod_loc; - struct region_device rdev; - union cbfs_mdata mdata; if (rsl->prog == NULL || prog_name(rsl->prog) == NULL) return -1; @@ -254,37 +256,15 @@ int rmodule_stage_load(struct rmod_stage_load *rsl) if (prog_locate_hook(rsl->prog)) return -1; - if (cbfs_boot_lookup(prog_name(rsl->prog), false, &mdata, &rdev) != CB_SUCCESS) - return -1; - - assert(be32toh(mdata.h.type) == CBFS_TYPE_STAGE); - rsl->prog->cbfs_type = CBFS_TYPE_STAGE; - - if (rdev_readat(&rdev, &stage, 0, sizeof(stage)) != sizeof(stage)) - return -1; - - rmodule_offset = - rmodule_calc_region(DYN_CBMEM_ALIGN_SIZE, - stage.memlen, ®ion_size, &load_offset); - - stage_region = cbmem_add(rsl->cbmem_id, region_size); - - if (stage_region == NULL) - return -1; - - rmod_loc = &stage_region[rmodule_offset]; - - printk(BIOS_INFO, "Decompressing stage %s @ %p (%d bytes)\n", - prog_name(rsl->prog), rmod_loc, stage.memlen); - - if (!cbfs_load_and_decompress(&rdev, sizeof(stage), stage.len, rmod_loc, - stage.memlen, stage.compression)) + void *rmod_loc = cbfs_alloc(prog_name(rsl->prog), + rmodule_cbfs_allocator, rsl, NULL); + if (!rmod_loc) return -1; if (rmodule_parse(rmod_loc, &rmod_stage)) return -1; - if (rmodule_load(&stage_region[load_offset], &rmod_stage)) + if (rmodule_load(rmod_loc + sizeof(struct rmodule_header), &rmod_stage)) return -1; prog_set_area(rsl->prog, rmod_stage.location, |