summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/cbfs.c56
-rw-r--r--src/lib/rmodule.c80
2 files changed, 51 insertions, 85 deletions
diff --git a/src/lib/cbfs.c b/src/lib/cbfs.c
index a274551c33..fbf4531862 100644
--- a/src/lib/cbfs.c
+++ b/src/lib/cbfs.c
@@ -386,11 +386,6 @@ cb_err_t cbfs_prog_stage_load(struct prog *pstage)
{
union cbfs_mdata mdata;
struct region_device rdev;
- struct cbfs_stage stage;
- uint8_t *load;
- void *entry;
- size_t fsize;
- size_t foffset;
cb_err_t err;
prog_locate_hook(pstage);
@@ -401,50 +396,41 @@ cb_err_t cbfs_prog_stage_load(struct prog *pstage)
assert(be32toh(mdata.h.type) == CBFS_TYPE_STAGE);
pstage->cbfs_type = CBFS_TYPE_STAGE;
- if (rdev_readat(&rdev, &stage, 0, sizeof(stage)) != sizeof(stage))
- return CB_CBFS_IO;
-
- fsize = region_device_sz(&rdev);
- fsize -= sizeof(stage);
- foffset = 0;
- foffset += sizeof(stage);
-
- /* cbfs_stage fields are written in little endian despite the other
- cbfs data types being encoded in big endian. */
- stage.compression = read_le32(&stage.compression);
- stage.entry = read_le64(&stage.entry);
- stage.load = read_le64(&stage.load);
- stage.len = read_le32(&stage.len);
- stage.memlen = read_le32(&stage.memlen);
-
- assert(fsize == stage.len);
+ enum cbfs_compression compression = CBFS_COMPRESS_NONE;
+ const struct cbfs_file_attr_compression *cattr = cbfs_find_attr(&mdata,
+ CBFS_FILE_ATTR_TAG_COMPRESSION, sizeof(*cattr));
+ if (cattr)
+ compression = be32toh(cattr->compression);
- load = (void *)(uintptr_t)stage.load;
- entry = (void *)(uintptr_t)stage.entry;
+ const struct cbfs_file_attr_stageheader *sattr = cbfs_find_attr(&mdata,
+ CBFS_FILE_ATTR_TAG_STAGEHEADER, sizeof(*sattr));
+ if (!sattr)
+ return CB_ERR;
+ prog_set_area(pstage, (void *)(uintptr_t)be64toh(sattr->loadaddr),
+ be32toh(sattr->memlen));
+ prog_set_entry(pstage, prog_start(pstage) +
+ be32toh(sattr->entry_offset), NULL);
/* Hacky way to not load programs over read only media. The stages
* that would hit this path initialize themselves. */
if ((ENV_BOOTBLOCK || ENV_SEPARATE_VERSTAGE) &&
!CONFIG(NO_XIP_EARLY_STAGES) && CONFIG(BOOT_DEVICE_MEMORY_MAPPED)) {
- void *mapping = rdev_mmap(&rdev, foffset, fsize);
+ void *mapping = rdev_mmap_full(&rdev);
rdev_munmap(&rdev, mapping);
- if (mapping == load)
- goto out;
+ if (mapping == prog_start(pstage))
+ return CB_SUCCESS;
}
- fsize = cbfs_stage_load_and_decompress(&rdev, foffset, fsize, load,
- stage.memlen, stage.compression);
+ size_t fsize = cbfs_stage_load_and_decompress(&rdev, 0, region_device_sz(&rdev),
+ prog_start(pstage), prog_size(pstage), compression);
if (!fsize)
return CB_ERR;
/* Clear area not covered by file. */
- memset(&load[fsize], 0, stage.memlen - fsize);
-
- prog_segment_loaded((uintptr_t)load, stage.memlen, SEG_FINAL);
+ memset(prog_start(pstage) + fsize, 0, prog_size(pstage) - fsize);
-out:
- prog_set_area(pstage, load, stage.memlen);
- prog_set_entry(pstage, entry, NULL);
+ prog_segment_loaded((uintptr_t)prog_start(pstage), prog_size(pstage),
+ SEG_FINAL);
return CB_SUCCESS;
}
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, &region_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,