Hello Aaron Durbin,
I'd like you to do a code review. Please visit
https://review.coreboot.org/c/coreboot/+/46484
to review the following change.
Change subject: cbfs: Move stage header into a CBFS attribute ......................................................................
cbfs: Move stage header into a CBFS attribute
The CBFS stage header is part of the file data (not the header) from CBFS's point of view, which is problematic for verification: in pre-RAM environments, there's usually not enough scratch space in CBFS_CACHE to load the full stage into memory, so it must be directly loaded into its final destination. However, that destination is decided from reading the stage header. There's no way we can verify the stage header without loading the whole file and we can't load the file without trusting the information in the stage header.
To solve this problem, this patch changes the CBFS stage format to move the stage header out of the file contents and into a separate CBFS attribute. Attributes are part of the metadata, so they have already been verified before the file is loaded.
Since CBFS stages are generally only meant to be used by coreboot itself and the coreboot build system builds cbfstool and all stages together in one go, maintaining backwards-compatibility should not be necessary. An older version of coreboot will build the old version of cbfstool and a newer version of coreboot will build the new version of cbfstool before using it to add stages to the final image, thus cbfstool and coreboot's stage loader should stay in sync. This only causes problems when someone stashes away a copy of cbfstool somewhere and later uses it to try to extract stages from a coreboot image built from a different revision... a debugging use-case that is hopefully rare enough that affected users can manually deal with finding a matching version of cbfstool.
The SELF (payload) format, on the other hand, is designed to be used for binaries outside of coreboot that may use independent build systems and are more likely to be added with a potentially stale copy of cbfstool, so it would be more problematic to make a similar change for SELFs. It is not necessary for verification either, since they're usually only used in post-RAM environments and selfload() already maps SELFs to CBFS_CACHE before loading them to their final destination anyway (so they can be hashed at that time).
Signed-off-by: Julius Werner jwerner@chromium.org Change-Id: I8471ad7494b07599e24e82b81e507fcafbad808a --- M src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h M src/include/program_loading.h M src/lib/cbfs.c M src/lib/prog_loaders.c M src/lib/rmodule.c M src/security/vboot/vboot_loader.c M src/soc/amd/common/block/pi/refcode_loader.c M util/cbfstool/cbfs-mkstage.c M util/cbfstool/cbfs_image.c M util/cbfstool/cbfstool.c M util/cbfstool/common.h 11 files changed, 210 insertions(+), 314 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/84/46484/1
diff --git a/src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h b/src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h index ac4b38f..c31d995 100644 --- a/src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h +++ b/src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h @@ -17,7 +17,8 @@ CBFS_TYPE_NULL = 0xffffffff, CBFS_TYPE_BOOTBLOCK = 0x01, CBFS_TYPE_CBFSHEADER = 0x02, - CBFS_TYPE_STAGE = 0x10, + CBFS_TYPE_LEGACY_STAGE = 0x10, + CBFS_TYPE_STAGE = 0x11, CBFS_TYPE_SELF = 0x20, CBFS_TYPE_FIT = 0x21, CBFS_TYPE_OPTIONROM = 0x30, @@ -125,6 +126,7 @@ CBFS_FILE_ATTR_TAG_ALIGNMENT = 0x42434c41, /* BE: 'BCLA' */ CBFS_FILE_ATTR_TAG_IBB = 0x32494242, /* BE: '2IBB' */ CBFS_FILE_ATTR_TAG_PADDING = 0x47444150, /* BE: 'GNDP' */ + CBFS_FILE_ATTR_TAG_STAGEHEADER = 0x53746748, /* BE: 'StgH' */ };
struct cbfs_file_attr_compression { @@ -154,22 +156,20 @@ uint32_t alignment; } __packed;
+struct cbfs_file_attr_stageheader { + uint32_t tag; + uint32_t len; + uint64_t loadaddr; /* Memory address to load the code to. */ + uint32_t entry_offset; /* Offset of entry point from loadaddr. */ + uint32_t memlen; /* Total length (including BSS) in memory. */ +} __packed; + + /*** Component sub-headers ***/
/* Following are component sub-headers for the "standard" component types */
-/** This is the sub-header for stage components. Stages are - loaded by coreboot during the normal boot process */ - -struct cbfs_stage { - uint32_t compression; /** Compression type */ - uint64_t entry; /** entry point */ - uint64_t load; /** Where to load in memory */ - uint32_t len; /** length of data to load */ - uint32_t memlen; /** total length of object in memory */ -} __packed; - /** this is the sub-header for payload components. Payloads are loaded by coreboot at the end of the boot process */
diff --git a/src/include/program_loading.h b/src/include/program_loading.h index e26792e..57efd7b 100644 --- a/src/include/program_loading.h +++ b/src/include/program_loading.h @@ -4,6 +4,7 @@
#include <assert.h> #include <bootmem.h> +#include <commonlib/bsd/cbfs_serialized.h> #include <commonlib/region.h> #include <types.h>
@@ -41,7 +42,8 @@ /* Representation of a program. */ struct prog { enum prog_type type; - uint32_t cbfs_type; + enum cbfs_type cbfs_type; + enum cbfs_compression compression; /* Only used for CBFS_TYPE_STAGE. */ const char *name; struct region_device load_rdev; /* Source for loading (e.g. flash). */ void *start; /* Program start in memory after loading. */ @@ -66,11 +68,16 @@ return prog->type; }
-static inline uint32_t prog_cbfs_type(const struct prog *prog) +static inline enum cbfs_type prog_cbfs_type(const struct prog *prog) { return prog->cbfs_type; }
+static inline enum cbfs_compression prog_compression(const struct prog *prog) +{ + return prog->compression; +} + static inline struct region_device *prog_rdev(struct prog *prog) { return &prog->load_rdev; @@ -118,6 +125,8 @@
static inline void prog_set_entry(struct prog *prog, void *e, void *arg) { + if (prog->cbfs_type == CBFS_TYPE_STAGE) + assert(e >= prog->start && e - prog->start < prog->size); prog->entry = e; prog->arg = arg; } diff --git a/src/lib/cbfs.c b/src/lib/cbfs.c index a6f0e69..452dce4 100644 --- a/src/lib/cbfs.c +++ b/src/lib/cbfs.c @@ -338,57 +338,30 @@
int cbfs_prog_stage_load(struct prog *pstage) { - struct cbfs_stage stage; - uint8_t *load; - void *entry; + struct region_device *rdev = prog_rdev(pstage); size_t fsize; - size_t foffset; - const struct region_device *fh = prog_rdev(pstage); - - if (rdev_readat(fh, &stage, 0, sizeof(stage)) != sizeof(stage)) - return -1; - - fsize = region_device_sz(fh); - 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); - - load = (void *)(uintptr_t)stage.load; - entry = (void *)(uintptr_t)stage.entry;
/* 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(fh, foffset, fsize); - rdev_munmap(fh, mapping); - if (mapping == load) - goto out; + void *mapping = rdev_mmap_full(rdev); + rdev_munmap(rdev, mapping); + if (mapping == prog_start(pstage)) + return 0; }
- fsize = cbfs_stage_load_and_decompress(fh, foffset, fsize, load, - stage.memlen, stage.compression); + fsize = cbfs_stage_load_and_decompress(rdev, 0, region_device_sz(rdev), + prog_start(pstage), prog_size(pstage), + prog_compression(pstage)); if (!fsize) return -1;
/* Clear area not covered by file. */ - memset(&load[fsize], 0, stage.memlen - fsize); + memset(prog_start(pstage) + fsize, 0, prog_size(pstage) - fsize);
- prog_segment_loaded((uintptr_t)load, stage.memlen, SEG_FINAL); - -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 0; } diff --git a/src/lib/prog_loaders.c b/src/lib/prog_loaders.c index 4fae5d2..f75f2ee 100644 --- a/src/lib/prog_loaders.c +++ b/src/lib/prog_loaders.c @@ -36,6 +36,26 @@ return err;
prog->cbfs_type = be32toh(mdata.h.type); + + const struct cbfs_file_attr_compression *compr = cbfs_find_attr(&mdata, + CBFS_FILE_ATTR_TAG_COMPRESSION, sizeof(*compr)); + if (compr) + prog->compression = be32toh(compr->compression); + else + prog->compression = CBFS_COMPRESS_NONE; + + if (prog->cbfs_type == CBFS_TYPE_STAGE) { + const struct cbfs_file_attr_stageheader *stgh = + cbfs_find_attr(&mdata, CBFS_FILE_ATTR_TAG_STAGEHEADER, + sizeof(*stgh)); + if (!stgh) + return CB_ERR; + prog_set_area(prog, (void *)(uintptr_t)be64toh(stgh->loadaddr), + be32toh(stgh->memlen)); + prog_set_entry(prog, prog_start(prog) + + be32toh(stgh->entry_offset), NULL); + } + return CB_SUCCESS; }
diff --git a/src/lib/rmodule.c b/src/lib/rmodule.c index 7944535..c68fe20 100644 --- a/src/lib/rmodule.c +++ b/src/lib/rmodule.c @@ -242,21 +242,15 @@ char *stage_region; int rmodule_offset; int load_offset; - struct cbfs_stage stage; void *rmod_loc; - struct region_device *fh;
- if (rsl->prog == NULL || prog_name(rsl->prog) == NULL) - return -1; - - fh = prog_rdev(rsl->prog); - - if (rdev_readat(fh, &stage, 0, sizeof(stage)) != sizeof(stage)) + struct prog *prog = rsl->prog; + if (prog == NULL || prog_name(prog) == NULL) return -1;
rmodule_offset = - rmodule_calc_region(DYN_CBMEM_ALIGN_SIZE, - stage.memlen, ®ion_size, &load_offset); + rmodule_calc_region(DYN_CBMEM_ALIGN_SIZE, prog_size(prog), + ®ion_size, &load_offset);
stage_region = cbmem_add(rsl->cbmem_id, region_size);
@@ -266,10 +260,11 @@ rmod_loc = &stage_region[rmodule_offset];
printk(BIOS_INFO, "Decompressing stage %s @ %p (%d bytes)\n", - prog_name(rsl->prog), rmod_loc, stage.memlen); + prog_name(rsl->prog), rmod_loc, prog_size(prog));
- if (!cbfs_load_and_decompress(fh, sizeof(stage), stage.len, rmod_loc, - stage.memlen, stage.compression)) + if (!cbfs_load_and_decompress(prog_rdev(prog), 0, + region_device_sz(prog_rdev(prog)), rmod_loc, + prog_size(prog), prog_compression(prog))) return -1;
if (rmodule_parse(rmod_loc, &rmod_stage)) @@ -278,13 +273,13 @@ if (rmodule_load(&stage_region[load_offset], &rmod_stage)) return -1;
- prog_set_area(rsl->prog, rmod_stage.location, + prog_set_area(prog, rmod_stage.location, rmodule_memory_size(&rmod_stage));
/* Allow caller to pick up parameters, if available. */ rsl->params = rmodule_parameters(&rmod_stage);
- prog_set_entry(rsl->prog, rmodule_entry(&rmod_stage), rsl->params); + prog_set_entry(prog, rmodule_entry(&rmod_stage), rsl->params);
return 0; } diff --git a/src/security/vboot/vboot_loader.c b/src/security/vboot/vboot_loader.c index 56a0664..d8b42f8 100644 --- a/src/security/vboot/vboot_loader.c +++ b/src/security/vboot/vboot_loader.c @@ -45,7 +45,6 @@ verstage_main(); after_verstage(); } else if (verstage_should_load()) { - struct cbfsf file; struct prog verstage = PROG_INIT(PROG_VERSTAGE, CONFIG_CBFS_PREFIX "/verstage"); @@ -53,10 +52,8 @@ printk(BIOS_DEBUG, "VBOOT: Loading verstage.\n");
/* load verstage from RO */ - if (cbfs_boot_locate(&file, prog_name(&verstage), NULL)) - die("failed to load verstage"); - - cbfs_file_data(prog_rdev(&verstage), &file); + if (prog_locate(&verstage)) + die("failed to locate verstage");
if (cbfs_prog_stage_load(&verstage)) die("failed to load verstage"); diff --git a/src/soc/amd/common/block/pi/refcode_loader.c b/src/soc/amd/common/block/pi/refcode_loader.c index bedd847..9be2079 100644 --- a/src/soc/amd/common/block/pi/refcode_loader.c +++ b/src/soc/amd/common/block/pi/refcode_loader.c @@ -29,14 +29,8 @@ static int agesa_locate_stage_file_early(const char *name, struct region_device *rdev) { - const size_t metadata_sz = sizeof(struct cbfs_stage); - if (agesa_locate_file(name, rdev, CBFS_TYPE_STAGE)) return -1; - - /* Peel off the cbfs stage metadata. */ - return rdev_chain(rdev, rdev, metadata_sz, - region_device_sz(rdev) - metadata_sz); }
static int agesa_locate_stage_file_ramstage(const char *name, diff --git a/util/cbfstool/cbfs-mkstage.c b/util/cbfstool/cbfs-mkstage.c index bfe7bf8..935bca0 100644 --- a/util/cbfstool/cbfs-mkstage.c +++ b/util/cbfstool/cbfs-mkstage.c @@ -10,8 +10,6 @@ #include "cbfs.h" #include "rmodule.h"
-#include <commonlib/bsd/compression.h> - /* Checks if program segment contains the ignored section */ static int is_phdr_ignored(Elf64_Phdr *phdr, Elf64_Shdr *shdr) { @@ -73,19 +71,20 @@ return NULL; }
-static void fill_cbfs_stage(struct buffer *outheader, enum cbfs_compression algo, - uint64_t entry, uint64_t loadaddr, - uint32_t filesize, uint32_t memsize) +static int fill_cbfs_stageheader(struct cbfs_file_attr_stageheader *stageheader, + uint64_t entry, uint64_t loadaddr, + uint32_t memsize) { - /* N.B. The original plan was that SELF data was B.E. - * but: this is all L.E. - * Maybe we should just change the spec. - */ - xdr_le.put32(outheader, algo); - xdr_le.put64(outheader, entry); - xdr_le.put64(outheader, loadaddr); - xdr_le.put32(outheader, filesize); - xdr_le.put32(outheader, memsize); + if (entry - loadaddr >= memsize) { + ERROR("stage entry point out of bounds!\n"); + return -1; + } + + stageheader->loadaddr = htonll(loadaddr); + stageheader->memlen = htonl(memsize); + stageheader->entry_offset = htonl(entry - loadaddr); + + return 0; }
/* returns size of result, or -1 if error. @@ -93,26 +92,20 @@ * works for all elf files, not just the restricted set. */ int parse_elf_to_stage(const struct buffer *input, struct buffer *output, - enum cbfs_compression algo, uint32_t *location, - const char *ignore_section) + uint32_t *location, const char *ignore_section, + struct cbfs_file_attr_stageheader *stageheader) { struct parsed_elf pelf; Elf64_Phdr *phdr; Elf64_Ehdr *ehdr; Elf64_Shdr *shdr_ignored; Elf64_Addr virt_to_phys; - char *buffer; - struct buffer outheader; int ret = -1;
int headers; - int i, outlen; + int i; uint64_t data_start, data_end, mem_end;
- comp_func_ptr compress = compression_function(algo); - if (!compress) - return -1; - DEBUG("start: parse_elf_to_stage(location=0x%x)\n", *location);
int flags = ELF_PARSE_PHDR | ELF_PARSE_SHDR | ELF_PARSE_STRTAB; @@ -185,15 +178,13 @@ exit(1); }
- /* allocate an intermediate buffer for the data */ - buffer = calloc(data_end - data_start, 1); - - if (buffer == NULL) { + if (buffer_create(output, data_end - data_start, input->name) != 0) { ERROR("Unable to allocate memory: %m\n"); goto err; } + memset(output->data, 0, output->size);
- /* Copy the file data into the buffer */ + /* Copy the file data into the output buffer */
for (i = 0; i < headers; i++) { uint64_t l_start, l_offset = 0; @@ -222,92 +213,17 @@ ERROR("Underflow copying out the segment." "File has %zu bytes left, segment end is %zu\n", input->size, (size_t)(phdr[i].p_offset + phdr[i].p_filesz)); - free(buffer); goto err; } - memcpy(buffer + (l_start - data_start), + memcpy(&output->data[l_start - data_start], &input->data[phdr[i].p_offset + l_offset], phdr[i].p_filesz - l_offset); }
- /* Now make the output buffer */ - if (buffer_create(output, sizeof(struct cbfs_stage) + data_end - data_start, - input->name) != 0) { - ERROR("Unable to allocate memory: %m\n"); - free(buffer); - goto err; - } - memset(output->data, 0, output->size); - - /* Compress the data, at which point we'll know information - * to fill out the header. This seems backward but it works because - * - the output header is a known size (not always true in many xdr's) - * - we do need to know the compressed output size first - * If compression fails or makes the data bigger, we'll warn about it - * and use the original data. - */ - if (compress(buffer, data_end - data_start, - (output->data + sizeof(struct cbfs_stage)), - &outlen) < 0 || (unsigned)outlen > data_end - data_start) { - WARN("Compression failed or would make the data bigger " - "- disabled.\n"); - memcpy(output->data + sizeof(struct cbfs_stage), - buffer, data_end - data_start); - outlen = data_end - data_start; - algo = CBFS_COMPRESS_NONE; - } - - /* Check for enough BSS scratch space to decompress LZ4 in-place. */ - if (algo == CBFS_COMPRESS_LZ4) { - size_t result; - size_t memlen = mem_end - data_start; - size_t compressed_size = outlen; - char *compare_buffer = malloc(memlen); - char *start = compare_buffer + memlen - compressed_size; - - if (compare_buffer == NULL) { - ERROR("Can't allocate memory!\n"); - free(buffer); - goto err; - } - - memcpy(start, output->data + sizeof(struct cbfs_stage), - compressed_size); - result = ulz4fn(start, compressed_size, compare_buffer, memlen); - - if (result == 0) { - ERROR("Not enough scratch space to decompress LZ4 in-place -- increase BSS size or disable compression!\n"); - free(compare_buffer); - free(buffer); - goto err; - } - if (result != data_end - data_start || - memcmp(compare_buffer, buffer, data_end - data_start)) { - ERROR("LZ4 compression BUG! Report to mailing list.\n"); - free(compare_buffer); - free(buffer); - goto err; - } - free(compare_buffer); - } - - free(buffer); - - /* Set up for output marshaling. */ - outheader.data = output->data; - outheader.size = 0; - /* coreboot expects entry point to be physical address. Thus, adjust the - * entry point accordingly. - */ - fill_cbfs_stage(&outheader, algo, ehdr->e_entry + virt_to_phys, - data_start, outlen, mem_end - data_start); - - if (*location) - *location -= sizeof(struct cbfs_stage); - output->size = sizeof(struct cbfs_stage) + outlen; - ret = 0; - + entry point accordingly. */ + ret = fill_cbfs_stageheader(stageheader, ehdr->e_entry + virt_to_phys, + data_start, mem_end - data_start); err: parsed_elf_destroy(&pelf); return ret; @@ -358,13 +274,13 @@ }
int parse_elf_to_xip_stage(const struct buffer *input, struct buffer *output, - uint32_t *location, const char *ignore_section) + uint32_t *location, const char *ignore_section, + struct cbfs_file_attr_stageheader *stageheader) { struct xip_context xipctx; struct rmod_context *rmodctx; struct reloc_filter filter; struct parsed_elf *pelf; - size_t output_sz; uint32_t adjustment; struct buffer binput; struct buffer boutput; @@ -398,13 +314,12 @@ if (rmodule_collect_relocations(rmodctx, &filter)) goto out;
- output_sz = sizeof(struct cbfs_stage) + pelf->phdr->p_filesz; - if (buffer_create(output, output_sz, input->name) != 0) { + if (buffer_create(output, pelf->phdr->p_filesz, input->name) != 0) { ERROR("Unable to allocate memory: %m\n"); goto out; } buffer_clone(&boutput, output); - memset(buffer_get(&boutput), 0, output_sz); + memset(buffer_get(&boutput), 0, pelf->phdr->p_filesz); buffer_set_size(&boutput, 0);
/* Single loadable segment. The entire segment moves to final @@ -412,17 +327,16 @@ adjustment = *location - pelf->phdr->p_vaddr; DEBUG("Relocation adjustment: %08x\n", adjustment);
- fill_cbfs_stage(&boutput, CBFS_COMPRESS_NONE, - (uint32_t)pelf->ehdr.e_entry + adjustment, - (uint32_t)pelf->phdr->p_vaddr + adjustment, - pelf->phdr->p_filesz, pelf->phdr->p_memsz); + fill_cbfs_stageheader(stageheader, + (uint32_t)pelf->ehdr.e_entry + adjustment, + (uint32_t)pelf->phdr->p_vaddr + adjustment, + pelf->phdr->p_memsz); /* Need an adjustable buffer. */ buffer_clone(&binput, input); buffer_seek(&binput, pelf->phdr->p_offset); bputs(&boutput, buffer_get(&binput), pelf->phdr->p_filesz);
buffer_clone(&boutput, output); - buffer_seek(&boutput, sizeof(struct cbfs_stage));
/* Make adjustments to all the relocations within the program. */ for (i = 0; i < rmodctx->nrelocs; i++) { @@ -448,8 +362,6 @@ xdr_le.put32(&out, val + adjustment); }
- /* Need to back up the location to include cbfs stage metadata. */ - *location -= sizeof(struct cbfs_stage); ret = 0;
out: diff --git a/util/cbfstool/cbfs_image.c b/util/cbfstool/cbfs_image.c index 05fdc8a..a51f941 100644 --- a/util/cbfstool/cbfs_image.c +++ b/util/cbfstool/cbfs_image.c @@ -823,69 +823,6 @@ return NULL; }
-static int cbfs_stage_decompress(struct cbfs_stage *stage, struct buffer *buff) -{ - struct buffer reader; - char *orig_buffer; - char *new_buffer; - size_t new_buff_sz; - decomp_func_ptr decompress; - - buffer_clone(&reader, buff); - - /* The stage metadata is in little endian. */ - stage->compression = xdr_le.get32(&reader); - stage->entry = xdr_le.get64(&reader); - stage->load = xdr_le.get64(&reader); - stage->len = xdr_le.get32(&reader); - stage->memlen = xdr_le.get32(&reader); - - /* Create a buffer just with the uncompressed program now that the - * struct cbfs_stage has been peeled off. */ - if (stage->compression == CBFS_COMPRESS_NONE) { - new_buff_sz = buffer_size(buff) - sizeof(struct cbfs_stage); - - orig_buffer = buffer_get(buff); - new_buffer = calloc(1, new_buff_sz); - memcpy(new_buffer, orig_buffer + sizeof(struct cbfs_stage), - new_buff_sz); - buffer_init(buff, buff->name, new_buffer, new_buff_sz); - free(orig_buffer); - return 0; - } - - decompress = decompression_function(stage->compression); - if (decompress == NULL) - return -1; - - orig_buffer = buffer_get(buff); - - /* This can be too big of a buffer needed, but there's no current - * field indicating decompressed size of data. */ - new_buff_sz = stage->memlen; - new_buffer = calloc(1, new_buff_sz); - - if (decompress(orig_buffer + sizeof(struct cbfs_stage), - (int)(buffer_size(buff) - sizeof(struct cbfs_stage)), - new_buffer, (int)new_buff_sz, &new_buff_sz)) { - ERROR("Couldn't decompress stage.\n"); - free(new_buffer); - return -1; - } - - /* Include correct size for full stage info. */ - buffer_init(buff, buff->name, new_buffer, new_buff_sz); - - /* True decompressed size is just the data size -- no metadata. */ - stage->len = new_buff_sz; - /* Stage is not compressed. */ - stage->compression = CBFS_COMPRESS_NONE; - - free(orig_buffer); - - return 0; -} - static int cbfs_payload_decompress(struct cbfs_payload_segment *segments, struct buffer *buff, int num_seg) { @@ -1019,11 +956,11 @@ return 0; }
-static int cbfs_stage_make_elf(struct buffer *buff, uint32_t arch) +static int cbfs_stage_make_elf(struct buffer *buff, uint32_t arch, + struct cbfs_file *entry) { Elf64_Ehdr ehdr; Elf64_Shdr shdr; - struct cbfs_stage stage; struct elf_writer *ew; struct buffer elf_out; size_t empty_sz; @@ -1034,16 +971,23 @@ return -1; }
- if (cbfs_stage_decompress(&stage, buff)) { - ERROR("Failed to decompress stage.\n"); + struct cbfs_file_attr_stageheader *stage = NULL; + for (struct cbfs_file_attribute *attr = cbfs_file_first_attr(entry); + attr != NULL; attr = cbfs_file_next_attr(entry, attr)) { + if (ntohl(attr->tag) == CBFS_FILE_ATTR_TAG_STAGEHEADER) { + stage = (struct cbfs_file_attr_stageheader *)attr; + break; + } + } + + if (stage == NULL) { + ERROR("Stage header not found for %s\n", entry->filename); return -1; }
if (init_elf_from_arch(&ehdr, arch)) return -1;
- ehdr.e_entry = stage.entry; - /* Attempt rmodule translation first. */ rmod_ret = rmodule_stage_to_elf(&ehdr, buff);
@@ -1055,6 +999,8 @@
/* Rmodule couldn't do anything with the data. Continue on with SELF. */
+ ehdr.e_entry = ntohll(stage->loadaddr) + ntohl(stage->entry_offset); + ew = elf_writer_init(&ehdr); if (ew == NULL) { ERROR("Unable to init ELF writer.\n"); @@ -1064,9 +1010,9 @@ memset(&shdr, 0, sizeof(shdr)); shdr.sh_type = SHT_PROGBITS; shdr.sh_flags = SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR; - shdr.sh_addr = stage.load; - shdr.sh_size = stage.len; - empty_sz = stage.memlen - stage.len; + shdr.sh_addr = ntohll(stage->loadaddr); + shdr.sh_size = buffer_size(buff); + empty_sz = ntohl(stage->memlen) - buffer_size(buff);
if (elf_writer_add_section(ew, &shdr, buff, ".program")) { ERROR("Unable to add ELF section: .program\n"); @@ -1081,7 +1027,7 @@ memset(&shdr, 0, sizeof(shdr)); shdr.sh_type = SHT_NOBITS; shdr.sh_flags = SHF_WRITE | SHF_ALLOC; - shdr.sh_addr = stage.load + stage.len; + shdr.sh_addr = ntohl(stage->loadaddr) + buffer_size(buff); shdr.sh_size = empty_sz; if (elf_writer_add_section(ew, &shdr, &b, ".empty")) { ERROR("Unable to add ELF section: .empty\n"); @@ -1105,7 +1051,8 @@ return 0; }
-static int cbfs_payload_make_elf(struct buffer *buff, uint32_t arch) +static int cbfs_payload_make_elf(struct buffer *buff, uint32_t arch, + unused struct cbfs_file *entry) { Elf64_Ehdr ehdr; Elf64_Shdr shdr; @@ -1257,7 +1204,7 @@ }
if (elf_writer_serialize(ew, &elf_out)) { - ERROR("Unable to create ELF file from stage.\n"); + ERROR("Unable to create ELF file from payload.\n"); goto out; }
@@ -1319,13 +1266,13 @@ }
/* - * The stage metadata is never compressed proper for cbfs_stage - * files. The contents of the stage data can be though. Therefore - * one has to do a second pass for stages to potentially decompress - * the stage data to make it more meaningful. + * We want to export stages and payloads as ELFs, not with coreboot's + * custom stage/SELF binary formats, so we need to do extra processing + * to turn them back into an ELF. */ if (do_processing) { - int (*make_elf)(struct buffer *, uint32_t) = NULL; + int (*make_elf)(struct buffer *, uint32_t, + struct cbfs_file *) = NULL; switch (ntohl(entry->type)) { case CBFS_TYPE_STAGE: make_elf = cbfs_stage_make_elf; @@ -1334,7 +1281,7 @@ make_elf = cbfs_payload_make_elf; break; } - if (make_elf && make_elf(&buffer, arch)) { + if (make_elf && make_elf(&buffer, arch, entry)) { ERROR("Failed to write %s into %s.\n", entry_name, filename); buffer_delete(&buffer); @@ -1386,17 +1333,29 @@ return 0; }
-static int cbfs_print_stage_info(struct cbfs_stage *stage, FILE* fp) +static int cbfs_print_stage_info(struct cbfs_file *entry, FILE* fp) { + + struct cbfs_file_attr_stageheader *stage = NULL; + for (struct cbfs_file_attribute *attr = cbfs_file_first_attr(entry); + attr != NULL; attr = cbfs_file_next_attr(entry, attr)) { + if (ntohl(attr->tag) == CBFS_FILE_ATTR_TAG_STAGEHEADER) { + stage = (struct cbfs_file_attr_stageheader *)attr; + break; + } + } + + if (stage == NULL) { + fprintf(fp, " ERROR: stage header not found!\n"); + return -1; + } + fprintf(fp, - " %s compression, entry: 0x%" PRIx64 ", load: 0x%" PRIx64 ", " - "length: %d/%d\n", - lookup_name_by_type(types_cbfs_compression, - stage->compression, "(unknown)"), - stage->entry, - stage->load, - stage->len, - stage->memlen); + " entry: 0x%" PRIx64 ", load: 0x%" PRIx64 ", " + "memlen: %d\n", + ntohll(stage->loadaddr) + ntohl(stage->entry_offset), + ntohll(stage->loadaddr), + ntohl(stage->memlen)); return 0; }
@@ -1518,8 +1477,7 @@ /* note the components of the subheader may be in host order ... */ switch (ntohl(entry->type)) { case CBFS_TYPE_STAGE: - cbfs_print_stage_info((struct cbfs_stage *) - CBFS_SUBHEADER(entry), fp); + cbfs_print_stage_info(entry, fp); break;
case CBFS_TYPE_SELF: diff --git a/util/cbfstool/cbfstool.c b/util/cbfstool/cbfstool.c index 454aff9..d4d9829 100644 --- a/util/cbfstool/cbfstool.c +++ b/util/cbfstool/cbfstool.c @@ -14,7 +14,9 @@ #include "cbfs_sections.h" #include "elfparsing.h" #include "partitioned_file.h" +#include "lz4/lib/xxhash.h" #include <commonlib/bsd/cbfs_private.h> +#include <commonlib/bsd/compression.h> #include <commonlib/bsd/metadata_hash.h> #include <commonlib/fsp.h> #include <commonlib/endian.h> @@ -681,18 +683,7 @@ sizeof(struct cbfs_file_attr_position)); if (attrs == NULL) return -1; - /* If we add a stage or a payload, we need to take */ - /* care about the additional metadata that is added */ - /* to the cbfs file and therefore set the position */ - /* the real beginning of the data. */ - if (type == CBFS_TYPE_STAGE) - attrs->position = htonl(offset + - sizeof(struct cbfs_stage)); - else if (type == CBFS_TYPE_SELF) - attrs->position = htonl(offset + - sizeof(struct cbfs_payload)); - else - attrs->position = htonl(offset); + attrs->position = htonl(offset); } /* Add alignment attribute if used */ if (param.alignment) { @@ -872,6 +863,12 @@ struct buffer output; int ret;
+ struct cbfs_file_attr_stageheader *stageheader = (void *) + cbfs_add_file_attr(header, CBFS_FILE_ATTR_TAG_STAGEHEADER, + sizeof(struct cbfs_file_attr_stageheader)); + if (!stageheader) + return -1; + if (param.stage_xip) { int32_t address; size_t data_size; @@ -881,8 +878,9 @@ return 1; }
- if (do_cbfs_locate(&address, sizeof(struct cbfs_stage), - data_size)) { + if (do_cbfs_locate(&address, + sizeof(struct cbfs_file_attr_stageheader), + data_size)) { ERROR("Could not find location for XIP stage.\n"); return 1; } @@ -897,18 +895,57 @@ *offset = address;
ret = parse_elf_to_xip_stage(buffer, &output, offset, - param.ignore_section); - } else - ret = parse_elf_to_stage(buffer, &output, param.compression, - offset, param.ignore_section); - + param.ignore_section, + stageheader); + } else { + ret = parse_elf_to_stage(buffer, &output, offset, + param.ignore_section, stageheader); + } if (ret != 0) return -1; + + /* Store a hash of original uncompressed stage to compare later. */ + size_t decmp_size = buffer_size(&output); + uint32_t decmp_hash = XXH32(buffer_get(&output), decmp_size, 0); + + /* Chain to base conversion routine to handle compression. */ + ret = cbfstool_convert_raw(&output, offset, header); + if (ret != 0) + goto fail; + + /* Special care must be taken for LZ4-compressed stages that the BSS is + large enough to provide scratch space for in-place decompression. */ + if (!param.precompression && param.compression == CBFS_COMPRESS_LZ4) { + size_t memlen = ntohl(stageheader->memlen); + size_t compressed_size = buffer_size(&output); + uint8_t *compare_buffer = malloc(memlen); + uint8_t *start = compare_buffer + memlen - compressed_size; + if (!compare_buffer) { + ERROR("Out of memory\n"); + goto fail; + } + memcpy(start, buffer_get(&output), compressed_size); + ret = ulz4fn(start, compressed_size, compare_buffer, memlen); + if (ret == 0) { + ERROR("Not enough scratch space to decompress LZ4 in-place -- increase BSS size or disable compression!\n"); + free(compare_buffer); + goto fail; + } else if (ret != (int)decmp_size || + decmp_hash != XXH32(compare_buffer, decmp_size, 0)) { + ERROR("LZ4 compression BUG! Report to mailing list.\n"); + free(compare_buffer); + goto fail; + } + free(compare_buffer); + } + buffer_delete(buffer); - // Direct assign, no dupe. - memcpy(buffer, &output, sizeof(*buffer)); - header->len = htonl(output.size); + buffer_clone(buffer, &output); return 0; + +fail: + buffer_delete(&output); + return -1; }
static int cbfstool_convert_mkpayload(struct buffer *buffer, diff --git a/util/cbfstool/common.h b/util/cbfstool/common.h index f1287e2..7c3539a 100644 --- a/util/cbfstool/common.h +++ b/util/cbfstool/common.h @@ -169,11 +169,12 @@ enum cbfs_compression algo); /* cbfs-mkstage.c */ int parse_elf_to_stage(const struct buffer *input, struct buffer *output, - enum cbfs_compression algo, uint32_t *location, - const char *ignore_section); + uint32_t *location, const char *ignore_section, + struct cbfs_file_attr_stageheader *stageheader); /* location is TOP aligned. */ int parse_elf_to_xip_stage(const struct buffer *input, struct buffer *output, - uint32_t *location, const char *ignore_section); + uint32_t *location, const char *ignore_section, + struct cbfs_file_attr_stageheader *stageheader);
void print_supported_architectures(void); void print_supported_filetypes(void);
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/46484 )
Change subject: cbfs: Move stage header into a CBFS attribute ......................................................................
Patch Set 1:
(2 comments)
https://review.coreboot.org/c/coreboot/+/46484/1/util/cbfstool/cbfs_image.c File util/cbfstool/cbfs_image.c:
https://review.coreboot.org/c/coreboot/+/46484/1/util/cbfstool/cbfs_image.c@... PS1, Line 1336: static int cbfs_print_stage_info(struct cbfs_file *entry, FILE* fp) "foo* bar" should be "foo *bar"
https://review.coreboot.org/c/coreboot/+/46484/1/util/cbfstool/cbfstool.c File util/cbfstool/cbfstool.c:
https://review.coreboot.org/c/coreboot/+/46484/1/util/cbfstool/cbfstool.c@93... PS1, Line 930: ERROR("Not enough scratch space to decompress LZ4 in-place -- increase BSS size or disable compression!\n"); line over 96 characters
Hello build bot (Jenkins), Aaron Durbin,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/46484
to look at the new patch set (#2).
Change subject: cbfs: Move stage header into a CBFS attribute ......................................................................
cbfs: Move stage header into a CBFS attribute
The CBFS stage header is part of the file data (not the header) from CBFS's point of view, which is problematic for verification: in pre-RAM environments, there's usually not enough scratch space in CBFS_CACHE to load the full stage into memory, so it must be directly loaded into its final destination. However, that destination is decided from reading the stage header. There's no way we can verify the stage header without loading the whole file and we can't load the file without trusting the information in the stage header.
To solve this problem, this patch changes the CBFS stage format to move the stage header out of the file contents and into a separate CBFS attribute. Attributes are part of the metadata, so they have already been verified before the file is loaded.
Since CBFS stages are generally only meant to be used by coreboot itself and the coreboot build system builds cbfstool and all stages together in one go, maintaining backwards-compatibility should not be necessary. An older version of coreboot will build the old version of cbfstool and a newer version of coreboot will build the new version of cbfstool before using it to add stages to the final image, thus cbfstool and coreboot's stage loader should stay in sync. This only causes problems when someone stashes away a copy of cbfstool somewhere and later uses it to try to extract stages from a coreboot image built from a different revision... a debugging use-case that is hopefully rare enough that affected users can manually deal with finding a matching version of cbfstool.
The SELF (payload) format, on the other hand, is designed to be used for binaries outside of coreboot that may use independent build systems and are more likely to be added with a potentially stale copy of cbfstool, so it would be more problematic to make a similar change for SELFs. It is not necessary for verification either, since they're usually only used in post-RAM environments and selfload() already maps SELFs to CBFS_CACHE before loading them to their final destination anyway (so they can be hashed at that time).
Signed-off-by: Julius Werner jwerner@chromium.org Change-Id: I8471ad7494b07599e24e82b81e507fcafbad808a --- M src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h M src/include/program_loading.h M src/lib/cbfs.c M src/lib/prog_loaders.c M src/lib/rmodule.c M src/security/vboot/vboot_loader.c M src/soc/amd/common/block/pi/refcode_loader.c M util/cbfstool/cbfs-mkstage.c M util/cbfstool/cbfs_image.c M util/cbfstool/cbfstool.c M util/cbfstool/common.h M util/cbfstool/rmodule.c 12 files changed, 213 insertions(+), 316 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/84/46484/2
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/46484 )
Change subject: cbfs: Move stage header into a CBFS attribute ......................................................................
Patch Set 2:
(2 comments)
https://review.coreboot.org/c/coreboot/+/46484/2/util/cbfstool/cbfs_image.c File util/cbfstool/cbfs_image.c:
https://review.coreboot.org/c/coreboot/+/46484/2/util/cbfstool/cbfs_image.c@... PS2, Line 1336: static int cbfs_print_stage_info(struct cbfs_file *entry, FILE* fp) "foo* bar" should be "foo *bar"
https://review.coreboot.org/c/coreboot/+/46484/2/util/cbfstool/cbfstool.c File util/cbfstool/cbfstool.c:
https://review.coreboot.org/c/coreboot/+/46484/2/util/cbfstool/cbfstool.c@93... PS2, Line 930: ERROR("Not enough scratch space to decompress LZ4 in-place -- increase BSS size or disable compression!\n"); line over 96 characters
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/46484 )
Change subject: cbfs: Move stage header into a CBFS attribute ......................................................................
Patch Set 3:
(2 comments)
https://review.coreboot.org/c/coreboot/+/46484/3/util/cbfstool/cbfs_image.c File util/cbfstool/cbfs_image.c:
https://review.coreboot.org/c/coreboot/+/46484/3/util/cbfstool/cbfs_image.c@... PS3, Line 1336: static int cbfs_print_stage_info(struct cbfs_file *entry, FILE* fp) "foo* bar" should be "foo *bar"
https://review.coreboot.org/c/coreboot/+/46484/3/util/cbfstool/cbfstool.c File util/cbfstool/cbfstool.c:
https://review.coreboot.org/c/coreboot/+/46484/3/util/cbfstool/cbfstool.c@93... PS3, Line 934: ERROR("Not enough scratch space to decompress LZ4 in-place -- increase BSS size or disable compression!\n"); line over 96 characters
Paul Menzel has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/46484 )
Change subject: cbfs: Move stage header into a CBFS attribute ......................................................................
Patch Set 3:
If the change is agreed upon, it should be documented in the release notes.
A request for comments was sent to the mailing list [1].
[1]: https://mail.coreboot.org/hyperkitty/list/coreboot@coreboot.org/thread/GIQDF... "[RFC] Change in CBFS "stage" binary format"
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/46484 )
Change subject: cbfs: Move stage header into a CBFS attribute ......................................................................
Patch Set 4:
(2 comments)
https://review.coreboot.org/c/coreboot/+/46484/4/util/cbfstool/cbfs_image.c File util/cbfstool/cbfs_image.c:
https://review.coreboot.org/c/coreboot/+/46484/4/util/cbfstool/cbfs_image.c@... PS4, Line 1336: static int cbfs_print_stage_info(struct cbfs_file *entry, FILE* fp) "foo* bar" should be "foo *bar"
https://review.coreboot.org/c/coreboot/+/46484/4/util/cbfstool/cbfstool.c File util/cbfstool/cbfstool.c:
https://review.coreboot.org/c/coreboot/+/46484/4/util/cbfstool/cbfstool.c@93... PS4, Line 934: ERROR("Not enough scratch space to decompress LZ4 in-place -- increase BSS size or disable compression!\n"); line over 96 characters
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/46484 )
Change subject: cbfs: Move stage header into a CBFS attribute ......................................................................
Patch Set 5:
(2 comments)
https://review.coreboot.org/c/coreboot/+/46484/5/util/cbfstool/cbfs_image.c File util/cbfstool/cbfs_image.c:
https://review.coreboot.org/c/coreboot/+/46484/5/util/cbfstool/cbfs_image.c@... PS5, Line 1336: static int cbfs_print_stage_info(struct cbfs_file *entry, FILE* fp) "foo* bar" should be "foo *bar"
https://review.coreboot.org/c/coreboot/+/46484/5/util/cbfstool/cbfstool.c File util/cbfstool/cbfstool.c:
https://review.coreboot.org/c/coreboot/+/46484/5/util/cbfstool/cbfstool.c@93... PS5, Line 934: ERROR("Not enough scratch space to decompress LZ4 in-place -- increase BSS size or disable compression!\n"); line over 96 characters
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/46484 )
Change subject: cbfs: Move stage header into a CBFS attribute ......................................................................
Patch Set 6:
(2 comments)
https://review.coreboot.org/c/coreboot/+/46484/6/util/cbfstool/cbfs_image.c File util/cbfstool/cbfs_image.c:
https://review.coreboot.org/c/coreboot/+/46484/6/util/cbfstool/cbfs_image.c@... PS6, Line 1336: static int cbfs_print_stage_info(struct cbfs_file *entry, FILE* fp) "foo* bar" should be "foo *bar"
https://review.coreboot.org/c/coreboot/+/46484/6/util/cbfstool/cbfstool.c File util/cbfstool/cbfstool.c:
https://review.coreboot.org/c/coreboot/+/46484/6/util/cbfstool/cbfstool.c@93... PS6, Line 934: ERROR("Not enough scratch space to decompress LZ4 in-place -- increase BSS size or disable compression!\n"); line over 96 characters
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/46484 )
Change subject: cbfs: Move stage header into a CBFS attribute ......................................................................
Patch Set 7:
(2 comments)
https://review.coreboot.org/c/coreboot/+/46484/7/util/cbfstool/cbfs_image.c File util/cbfstool/cbfs_image.c:
https://review.coreboot.org/c/coreboot/+/46484/7/util/cbfstool/cbfs_image.c@... PS7, Line 1336: static int cbfs_print_stage_info(struct cbfs_file *entry, FILE* fp) "foo* bar" should be "foo *bar"
https://review.coreboot.org/c/coreboot/+/46484/7/util/cbfstool/cbfstool.c File util/cbfstool/cbfstool.c:
https://review.coreboot.org/c/coreboot/+/46484/7/util/cbfstool/cbfstool.c@95... PS7, Line 952: ERROR("Not enough scratch space to decompress LZ4 in-place -- increase BSS size or disable compression!\n"); line over 96 characters
Hello build bot (Jenkins), Aaron Durbin,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/46484
to look at the new patch set (#8).
Change subject: cbfs: Move stage header into a CBFS attribute ......................................................................
cbfs: Move stage header into a CBFS attribute
The CBFS stage header is part of the file data (not the header) from CBFS's point of view, which is problematic for verification: in pre-RAM environments, there's usually not enough scratch space in CBFS_CACHE to load the full stage into memory, so it must be directly loaded into its final destination. However, that destination is decided from reading the stage header. There's no way we can verify the stage header without loading the whole file and we can't load the file without trusting the information in the stage header.
To solve this problem, this patch changes the CBFS stage format to move the stage header out of the file contents and into a separate CBFS attribute. Attributes are part of the metadata, so they have already been verified before the file is loaded.
Since CBFS stages are generally only meant to be used by coreboot itself and the coreboot build system builds cbfstool and all stages together in one go, maintaining backwards-compatibility should not be necessary. An older version of coreboot will build the old version of cbfstool and a newer version of coreboot will build the new version of cbfstool before using it to add stages to the final image, thus cbfstool and coreboot's stage loader should stay in sync. This only causes problems when someone stashes away a copy of cbfstool somewhere and later uses it to try to extract stages from a coreboot image built from a different revision... a debugging use-case that is hopefully rare enough that affected users can manually deal with finding a matching version of cbfstool.
The SELF (payload) format, on the other hand, is designed to be used for binaries outside of coreboot that may use independent build systems and are more likely to be added with a potentially stale copy of cbfstool, so it would be more problematic to make a similar change for SELFs. It is not necessary for verification either, since they're usually only used in post-RAM environments and selfload() already maps SELFs to CBFS_CACHE before loading them to their final destination anyway (so they can be hashed at that time).
Signed-off-by: Julius Werner jwerner@chromium.org Change-Id: I8471ad7494b07599e24e82b81e507fcafbad808a --- M src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h M src/include/program_loading.h M src/lib/cbfs.c M src/lib/prog_loaders.c M src/lib/rmodule.c M src/security/vboot/vboot_loader.c M src/soc/amd/common/block/pi/refcode_loader.c M util/cbfstool/cbfs-mkstage.c M util/cbfstool/cbfs_image.c M util/cbfstool/cbfstool.c M util/cbfstool/common.h M util/cbfstool/rmodule.c 12 files changed, 213 insertions(+), 316 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/84/46484/8
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/46484 )
Change subject: cbfs: Move stage header into a CBFS attribute ......................................................................
Patch Set 8:
(2 comments)
https://review.coreboot.org/c/coreboot/+/46484/8/util/cbfstool/cbfs_image.c File util/cbfstool/cbfs_image.c:
https://review.coreboot.org/c/coreboot/+/46484/8/util/cbfstool/cbfs_image.c@... PS8, Line 1336: static int cbfs_print_stage_info(struct cbfs_file *entry, FILE* fp) "foo* bar" should be "foo *bar"
https://review.coreboot.org/c/coreboot/+/46484/8/util/cbfstool/cbfstool.c File util/cbfstool/cbfstool.c:
https://review.coreboot.org/c/coreboot/+/46484/8/util/cbfstool/cbfstool.c@95... PS8, Line 952: ERROR("Not enough scratch space to decompress LZ4 in-place -- increase BSS size or disable compression!\n"); line over 96 characters
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/46484 )
Change subject: cbfs: Move stage header into a CBFS attribute ......................................................................
Patch Set 10:
(2 comments)
https://review.coreboot.org/c/coreboot/+/46484/10/util/cbfstool/cbfs_image.c File util/cbfstool/cbfs_image.c:
https://review.coreboot.org/c/coreboot/+/46484/10/util/cbfstool/cbfs_image.c... PS10, Line 1336: static int cbfs_print_stage_info(struct cbfs_file *entry, FILE* fp) "foo* bar" should be "foo *bar"
https://review.coreboot.org/c/coreboot/+/46484/10/util/cbfstool/cbfstool.c File util/cbfstool/cbfstool.c:
https://review.coreboot.org/c/coreboot/+/46484/10/util/cbfstool/cbfstool.c@9... PS10, Line 952: ERROR("Not enough scratch space to decompress LZ4 in-place -- increase BSS size or disable compression!\n"); line over 96 characters
Hello build bot (Jenkins), Aaron Durbin,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/46484
to look at the new patch set (#11).
Change subject: cbfs: Move stage header into a CBFS attribute ......................................................................
cbfs: Move stage header into a CBFS attribute
The CBFS stage header is part of the file data (not the header) from CBFS's point of view, which is problematic for verification: in pre-RAM environments, there's usually not enough scratch space in CBFS_CACHE to load the full stage into memory, so it must be directly loaded into its final destination. However, that destination is decided from reading the stage header. There's no way we can verify the stage header without loading the whole file and we can't load the file without trusting the information in the stage header.
To solve this problem, this patch changes the CBFS stage format to move the stage header out of the file contents and into a separate CBFS attribute. Attributes are part of the metadata, so they have already been verified before the file is loaded.
Since CBFS stages are generally only meant to be used by coreboot itself and the coreboot build system builds cbfstool and all stages together in one go, maintaining backwards-compatibility should not be necessary. An older version of coreboot will build the old version of cbfstool and a newer version of coreboot will build the new version of cbfstool before using it to add stages to the final image, thus cbfstool and coreboot's stage loader should stay in sync. This only causes problems when someone stashes away a copy of cbfstool somewhere and later uses it to try to extract stages from a coreboot image built from a different revision... a debugging use-case that is hopefully rare enough that affected users can manually deal with finding a matching version of cbfstool.
The SELF (payload) format, on the other hand, is designed to be used for binaries outside of coreboot that may use independent build systems and are more likely to be added with a potentially stale copy of cbfstool, so it would be more problematic to make a similar change for SELFs. It is not necessary for verification either, since they're usually only used in post-RAM environments and selfload() already maps SELFs to CBFS_CACHE before loading them to their final destination anyway (so they can be hashed at that time).
Signed-off-by: Julius Werner jwerner@chromium.org Change-Id: I8471ad7494b07599e24e82b81e507fcafbad808a --- M src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h M src/include/program_loading.h M src/lib/cbfs.c M src/lib/prog_loaders.c M src/lib/rmodule.c M src/security/vboot/vboot_loader.c M src/soc/amd/common/block/pi/refcode_loader.c M util/cbfstool/cbfs-mkstage.c M util/cbfstool/cbfs_image.c M util/cbfstool/cbfstool.c M util/cbfstool/common.h M util/cbfstool/rmodule.c 12 files changed, 213 insertions(+), 314 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/84/46484/11
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/46484 )
Change subject: cbfs: Move stage header into a CBFS attribute ......................................................................
Patch Set 11:
(2 comments)
https://review.coreboot.org/c/coreboot/+/46484/11/util/cbfstool/cbfs_image.c File util/cbfstool/cbfs_image.c:
https://review.coreboot.org/c/coreboot/+/46484/11/util/cbfstool/cbfs_image.c... PS11, Line 1328: static int cbfs_print_stage_info(struct cbfs_file *entry, FILE* fp) "foo* bar" should be "foo *bar"
https://review.coreboot.org/c/coreboot/+/46484/11/util/cbfstool/cbfstool.c File util/cbfstool/cbfstool.c:
https://review.coreboot.org/c/coreboot/+/46484/11/util/cbfstool/cbfstool.c@1... PS11, Line 1147: ERROR("Not enough scratch space to decompress LZ4 in-place -- increase BSS size or disable compression!\n"); line over 96 characters
Attention is currently required from: Furquan Shaikh. Hello build bot (Jenkins), Jason Glenesk, Furquan Shaikh, Marshall Dawson, Aaron Durbin, Felix Held,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/46484
to look at the new patch set (#12).
Change subject: cbfs: Move stage header into a CBFS attribute ......................................................................
cbfs: Move stage header into a CBFS attribute
The CBFS stage header is part of the file data (not the header) from CBFS's point of view, which is problematic for verification: in pre-RAM environments, there's usually not enough scratch space in CBFS_CACHE to load the full stage into memory, so it must be directly loaded into its final destination. However, that destination is decided from reading the stage header. There's no way we can verify the stage header without loading the whole file and we can't load the file without trusting the information in the stage header.
To solve this problem, this patch changes the CBFS stage format to move the stage header out of the file contents and into a separate CBFS attribute. Attributes are part of the metadata, so they have already been verified before the file is loaded.
Since CBFS stages are generally only meant to be used by coreboot itself and the coreboot build system builds cbfstool and all stages together in one go, maintaining backwards-compatibility should not be necessary. An older version of coreboot will build the old version of cbfstool and a newer version of coreboot will build the new version of cbfstool before using it to add stages to the final image, thus cbfstool and coreboot's stage loader should stay in sync. This only causes problems when someone stashes away a copy of cbfstool somewhere and later uses it to try to extract stages from a coreboot image built from a different revision... a debugging use-case that is hopefully rare enough that affected users can manually deal with finding a matching version of cbfstool.
The SELF (payload) format, on the other hand, is designed to be used for binaries outside of coreboot that may use independent build systems and are more likely to be added with a potentially stale copy of cbfstool, so it would be more problematic to make a similar change for SELFs. It is not necessary for verification either, since they're usually only used in post-RAM environments and selfload() already maps SELFs to CBFS_CACHE before loading them to their final destination anyway (so they can be hashed at that time).
Signed-off-by: Julius Werner jwerner@chromium.org Change-Id: I8471ad7494b07599e24e82b81e507fcafbad808a --- M src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h M src/include/program_loading.h M src/lib/cbfs.c M src/lib/rmodule.c M src/soc/amd/common/block/pi/refcode_loader.c M util/cbfstool/cbfs-mkstage.c M util/cbfstool/cbfs_image.c M util/cbfstool/cbfstool.c M util/cbfstool/common.h M util/cbfstool/rmodule.c 10 files changed, 196 insertions(+), 338 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/84/46484/12
Attention is currently required from: Furquan Shaikh. build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/46484 )
Change subject: cbfs: Move stage header into a CBFS attribute ......................................................................
Patch Set 12:
(2 comments)
File util/cbfstool/cbfs_image.c:
https://review.coreboot.org/c/coreboot/+/46484/comment/300f89cb_03d5137c PS12, Line 1337: static int cbfs_print_stage_info(struct cbfs_file *entry, FILE* fp) "foo* bar" should be "foo *bar"
File util/cbfstool/cbfstool.c:
https://review.coreboot.org/c/coreboot/+/46484/comment/b9ab92af_f2bf6ea9 PS12, Line 1159: ERROR("Not enough scratch space to decompress LZ4 in-place -- increase BSS size or disable compression!\n"); line over 96 characters
Attention is currently required from: Furquan Shaikh. Hello build bot (Jenkins), Jason Glenesk, Furquan Shaikh, Marshall Dawson, Aaron Durbin, Felix Held,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/46484
to look at the new patch set (#13).
Change subject: cbfs: Move stage header into a CBFS attribute ......................................................................
cbfs: Move stage header into a CBFS attribute
The CBFS stage header is part of the file data (not the header) from CBFS's point of view, which is problematic for verification: in pre-RAM environments, there's usually not enough scratch space in CBFS_CACHE to load the full stage into memory, so it must be directly loaded into its final destination. However, that destination is decided from reading the stage header. There's no way we can verify the stage header without loading the whole file and we can't load the file without trusting the information in the stage header.
To solve this problem, this patch changes the CBFS stage format to move the stage header out of the file contents and into a separate CBFS attribute. Attributes are part of the metadata, so they have already been verified before the file is loaded.
Since CBFS stages are generally only meant to be used by coreboot itself and the coreboot build system builds cbfstool and all stages together in one go, maintaining backwards-compatibility should not be necessary. An older version of coreboot will build the old version of cbfstool and a newer version of coreboot will build the new version of cbfstool before using it to add stages to the final image, thus cbfstool and coreboot's stage loader should stay in sync. This only causes problems when someone stashes away a copy of cbfstool somewhere and later uses it to try to extract stages from a coreboot image built from a different revision... a debugging use-case that is hopefully rare enough that affected users can manually deal with finding a matching version of cbfstool.
The SELF (payload) format, on the other hand, is designed to be used for binaries outside of coreboot that may use independent build systems and are more likely to be added with a potentially stale copy of cbfstool, so it would be more problematic to make a similar change for SELFs. It is not necessary for verification either, since they're usually only used in post-RAM environments and selfload() already maps SELFs to CBFS_CACHE before loading them to their final destination anyway (so they can be hashed at that time).
Signed-off-by: Julius Werner jwerner@chromium.org Change-Id: I8471ad7494b07599e24e82b81e507fcafbad808a --- M src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h M src/lib/cbfs.c M src/lib/rmodule.c M src/soc/amd/common/block/pi/refcode_loader.c M util/cbfstool/cbfs-mkstage.c M util/cbfstool/cbfs_image.c M util/cbfstool/cbfstool.c M util/cbfstool/common.h M util/cbfstool/rmodule.c 9 files changed, 192 insertions(+), 332 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/84/46484/13
Attention is currently required from: Furquan Shaikh. build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/46484 )
Change subject: cbfs: Move stage header into a CBFS attribute ......................................................................
Patch Set 13:
(2 comments)
File util/cbfstool/cbfs_image.c:
https://review.coreboot.org/c/coreboot/+/46484/comment/ecc569fa_31571ca0 PS13, Line 1337: static int cbfs_print_stage_info(struct cbfs_file *entry, FILE* fp) "foo* bar" should be "foo *bar"
File util/cbfstool/cbfstool.c:
https://review.coreboot.org/c/coreboot/+/46484/comment/e7011f84_bbaffd94 PS13, Line 1164: ERROR("Not enough scratch space to decompress LZ4 in-place -- increase BSS size or disable compression!\n"); line over 96 characters
Attention is currently required from: Furquan Shaikh. build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/46484 )
Change subject: cbfs: Move stage header into a CBFS attribute ......................................................................
Patch Set 14:
(2 comments)
File util/cbfstool/cbfs_image.c:
https://review.coreboot.org/c/coreboot/+/46484/comment/3d8cd4bd_c75ab12e PS14, Line 1337: static int cbfs_print_stage_info(struct cbfs_file *entry, FILE* fp) "foo* bar" should be "foo *bar"
File util/cbfstool/cbfstool.c:
https://review.coreboot.org/c/coreboot/+/46484/comment/2eeb1995_81d76002 PS14, Line 1167: ERROR("Not enough scratch space to decompress LZ4 in-place -- increase BSS size or disable compression!\n"); line over 96 characters
Attention is currently required from: Furquan Shaikh. build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/46484 )
Change subject: cbfs: Move stage header into a CBFS attribute ......................................................................
Patch Set 15:
(2 comments)
File util/cbfstool/cbfs_image.c:
https://review.coreboot.org/c/coreboot/+/46484/comment/f6ac057e_1e9afb2d PS15, Line 1337: static int cbfs_print_stage_info(struct cbfs_file *entry, FILE* fp) "foo* bar" should be "foo *bar"
File util/cbfstool/cbfstool.c:
https://review.coreboot.org/c/coreboot/+/46484/comment/6fb3150b_1d38cdbb PS15, Line 1167: ERROR("Not enough scratch space to decompress LZ4 in-place -- increase BSS size or disable compression!\n"); line over 96 characters
Attention is currently required from: Furquan Shaikh, Julius Werner. Julius Werner has removed a vote from this change. ( https://review.coreboot.org/c/coreboot/+/46484 )
Change subject: cbfs: Move stage header into a CBFS attribute ......................................................................
Removed Verified-1 by build bot (Jenkins) no-reply@coreboot.org
Attention is currently required from: Furquan Shaikh. build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/46484 )
Change subject: cbfs: Move stage header into a CBFS attribute ......................................................................
Patch Set 17:
(2 comments)
File util/cbfstool/cbfs_image.c:
https://review.coreboot.org/c/coreboot/+/46484/comment/b7799aa9_872a622b PS17, Line 1337: static int cbfs_print_stage_info(struct cbfs_file *entry, FILE* fp) "foo* bar" should be "foo *bar"
File util/cbfstool/cbfstool.c:
https://review.coreboot.org/c/coreboot/+/46484/comment/80d2f0b0_1f9a5243 PS17, Line 1167: ERROR("Not enough scratch space to decompress LZ4 in-place -- increase BSS size or disable compression!\n"); line over 96 characters
Attention is currently required from: Raul Rangel, Furquan Shaikh. build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/46484 )
Change subject: cbfs: Move stage header into a CBFS attribute ......................................................................
Patch Set 18:
(2 comments)
File util/cbfstool/cbfs_image.c:
https://review.coreboot.org/c/coreboot/+/46484/comment/03063a79_e1778d61 PS18, Line 1337: static int cbfs_print_stage_info(struct cbfs_file *entry, FILE* fp) "foo* bar" should be "foo *bar"
File util/cbfstool/cbfstool.c:
https://review.coreboot.org/c/coreboot/+/46484/comment/a2296e7f_f04b42ec PS18, Line 1166: ERROR("Not enough scratch space to decompress LZ4 in-place -- increase BSS size or disable compression!\n"); line over 96 characters
Attention is currently required from: Raul Rangel, Furquan Shaikh, Julius Werner. Aaron Durbin has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/46484 )
Change subject: cbfs: Move stage header into a CBFS attribute ......................................................................
Patch Set 18: Code-Review+2
Attention is currently required from: Raul Rangel, Furquan Shaikh. build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/46484 )
Change subject: cbfs: Move stage header into a CBFS attribute ......................................................................
Patch Set 19:
(2 comments)
File util/cbfstool/cbfs_image.c:
https://review.coreboot.org/c/coreboot/+/46484/comment/b169495f_57a624b2 PS19, Line 1337: static int cbfs_print_stage_info(struct cbfs_file *entry, FILE* fp) "foo* bar" should be "foo *bar"
File util/cbfstool/cbfstool.c:
https://review.coreboot.org/c/coreboot/+/46484/comment/712c3078_f0414c0a PS19, Line 1166: ERROR("Not enough scratch space to decompress LZ4 in-place -- increase BSS size or disable compression!\n"); line over 96 characters
Attention is currently required from: Raul Rangel, Furquan Shaikh. build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/46484 )
Change subject: cbfs: Move stage header into a CBFS attribute ......................................................................
Patch Set 20:
(2 comments)
File util/cbfstool/cbfs_image.c:
https://review.coreboot.org/c/coreboot/+/46484/comment/e5ac3242_bbd7bf32 PS20, Line 1337: static int cbfs_print_stage_info(struct cbfs_file *entry, FILE* fp) "foo* bar" should be "foo *bar"
File util/cbfstool/cbfstool.c:
https://review.coreboot.org/c/coreboot/+/46484/comment/118742cc_126f9662 PS20, Line 1166: ERROR("Not enough scratch space to decompress LZ4 in-place -- increase BSS size or disable compression!\n"); line over 96 characters
Attention is currently required from: Raul Rangel, Furquan Shaikh, Julius Werner. build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/46484 )
Change subject: cbfs: Move stage header into a CBFS attribute ......................................................................
Patch Set 22:
(2 comments)
File util/cbfstool/cbfs_image.c:
https://review.coreboot.org/c/coreboot/+/46484/comment/99bb1ceb_8c93fd02 PS22, Line 1337: static int cbfs_print_stage_info(struct cbfs_file *entry, FILE* fp) "foo* bar" should be "foo *bar"
File util/cbfstool/cbfstool.c:
https://review.coreboot.org/c/coreboot/+/46484/comment/23a7420a_a05fca09 PS22, Line 1166: ERROR("Not enough scratch space to decompress LZ4 in-place -- increase BSS size or disable compression!\n"); line over 96 characters
Attention is currently required from: Raul Rangel, Furquan Shaikh, Julius Werner. build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/46484 )
Change subject: cbfs: Move stage header into a CBFS attribute ......................................................................
Patch Set 24:
(2 comments)
File util/cbfstool/cbfs_image.c:
https://review.coreboot.org/c/coreboot/+/46484/comment/de867825_7a0c2615 PS24, Line 1337: static int cbfs_print_stage_info(struct cbfs_file *entry, FILE* fp) "foo* bar" should be "foo *bar"
File util/cbfstool/cbfstool.c:
https://review.coreboot.org/c/coreboot/+/46484/comment/8a3486ef_6bcab77c PS24, Line 1167: ERROR("Not enough scratch space to decompress LZ4 in-place -- increase BSS size or disable compression!\n"); line over 96 characters
Attention is currently required from: Raul Rangel, Furquan Shaikh, Julius Werner. Hello build bot (Jenkins), Jason Glenesk, Raul Rangel, Furquan Shaikh, Marshall Dawson, Aaron Durbin, Felix Held,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/46484
to look at the new patch set (#25).
Change subject: cbfs: Move stage header into a CBFS attribute ......................................................................
cbfs: Move stage header into a CBFS attribute
The CBFS stage header is part of the file data (not the header) from CBFS's point of view, which is problematic for verification: in pre-RAM environments, there's usually not enough scratch space in CBFS_CACHE to load the full stage into memory, so it must be directly loaded into its final destination. However, that destination is decided from reading the stage header. There's no way we can verify the stage header without loading the whole file and we can't load the file without trusting the information in the stage header.
To solve this problem, this patch changes the CBFS stage format to move the stage header out of the file contents and into a separate CBFS attribute. Attributes are part of the metadata, so they have already been verified before the file is loaded.
Since CBFS stages are generally only meant to be used by coreboot itself and the coreboot build system builds cbfstool and all stages together in one go, maintaining backwards-compatibility should not be necessary. An older version of coreboot will build the old version of cbfstool and a newer version of coreboot will build the new version of cbfstool before using it to add stages to the final image, thus cbfstool and coreboot's stage loader should stay in sync. This only causes problems when someone stashes away a copy of cbfstool somewhere and later uses it to try to extract stages from a coreboot image built from a different revision... a debugging use-case that is hopefully rare enough that affected users can manually deal with finding a matching version of cbfstool.
The SELF (payload) format, on the other hand, is designed to be used for binaries outside of coreboot that may use independent build systems and are more likely to be added with a potentially stale copy of cbfstool, so it would be more problematic to make a similar change for SELFs. It is not necessary for verification either, since they're usually only used in post-RAM environments and selfload() already maps SELFs to CBFS_CACHE before loading them to their final destination anyway (so they can be hashed at that time).
Signed-off-by: Julius Werner jwerner@chromium.org Change-Id: I8471ad7494b07599e24e82b81e507fcafbad808a --- M src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h M src/lib/cbfs.c M src/lib/rmodule.c M src/soc/amd/common/block/pi/refcode_loader.c M util/cbfstool/cbfs-mkstage.c M util/cbfstool/cbfs_image.c M util/cbfstool/cbfstool.c M util/cbfstool/common.h M util/cbfstool/rmodule.c 9 files changed, 205 insertions(+), 331 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/84/46484/25
Attention is currently required from: Raul Rangel, Furquan Shaikh. build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/46484 )
Change subject: cbfs: Move stage header into a CBFS attribute ......................................................................
Patch Set 25:
(2 comments)
File util/cbfstool/cbfs_image.c:
https://review.coreboot.org/c/coreboot/+/46484/comment/37f41d1c_976f8b3b PS25, Line 1337: static int cbfs_print_stage_info(struct cbfs_file *entry, FILE* fp) "foo* bar" should be "foo *bar"
File util/cbfstool/cbfstool.c:
https://review.coreboot.org/c/coreboot/+/46484/comment/7022ba2e_f90e63da PS25, Line 1167: ERROR("Not enough scratch space to decompress LZ4 in-place -- increase BSS size or disable compression!\n"); line over 96 characters
Attention is currently required from: Raul Rangel, Furquan Shaikh, Julius Werner. Aaron Durbin has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/46484 )
Change subject: cbfs: Move stage header into a CBFS attribute ......................................................................
Patch Set 25: Code-Review+2
Attention is currently required from: Raul Rangel, Furquan Shaikh. build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/46484 )
Change subject: cbfs: Move stage header into a CBFS attribute ......................................................................
Patch Set 26:
(2 comments)
File util/cbfstool/cbfs_image.c:
https://review.coreboot.org/c/coreboot/+/46484/comment/5a92d526_b2d776ce PS26, Line 1337: static int cbfs_print_stage_info(struct cbfs_file *entry, FILE* fp) "foo* bar" should be "foo *bar"
File util/cbfstool/cbfstool.c:
https://review.coreboot.org/c/coreboot/+/46484/comment/a6bbd609_4822a41c PS26, Line 1167: ERROR("Not enough scratch space to decompress LZ4 in-place -- increase BSS size or disable compression!\n"); line over 96 characters
Attention is currently required from: Raul Rangel, Furquan Shaikh. build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/46484 )
Change subject: cbfs: Move stage header into a CBFS attribute ......................................................................
Patch Set 27:
(2 comments)
File util/cbfstool/cbfs_image.c:
https://review.coreboot.org/c/coreboot/+/46484/comment/ced352d1_3dbf48ca PS27, Line 1337: static int cbfs_print_stage_info(struct cbfs_file *entry, FILE* fp) "foo* bar" should be "foo *bar"
File util/cbfstool/cbfstool.c:
https://review.coreboot.org/c/coreboot/+/46484/comment/0c20c972_75bcb1f2 PS27, Line 1167: ERROR("Not enough scratch space to decompress LZ4 in-place -- increase BSS size or disable compression!\n"); line over 96 characters
Attention is currently required from: Raul Rangel, Furquan Shaikh. build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/46484 )
Change subject: cbfs: Move stage header into a CBFS attribute ......................................................................
Patch Set 28:
(2 comments)
File util/cbfstool/cbfs_image.c:
https://review.coreboot.org/c/coreboot/+/46484/comment/91aa976d_7391fd0c PS28, Line 1337: static int cbfs_print_stage_info(struct cbfs_file *entry, FILE* fp) "foo* bar" should be "foo *bar"
File util/cbfstool/cbfstool.c:
https://review.coreboot.org/c/coreboot/+/46484/comment/2a619c51_37f06976 PS28, Line 1167: ERROR("Not enough scratch space to decompress LZ4 in-place -- increase BSS size or disable compression!\n"); line over 96 characters
Attention is currently required from: Raul Rangel, Furquan Shaikh. Hello build bot (Jenkins), Jason Glenesk, Raul Rangel, Furquan Shaikh, Marshall Dawson, Aaron Durbin, Felix Held,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/46484
to look at the new patch set (#29).
Change subject: cbfs: Move stage header into a CBFS attribute ......................................................................
cbfs: Move stage header into a CBFS attribute
The CBFS stage header is part of the file data (not the header) from CBFS's point of view, which is problematic for verification: in pre-RAM environments, there's usually not enough scratch space in CBFS_CACHE to load the full stage into memory, so it must be directly loaded into its final destination. However, that destination is decided from reading the stage header. There's no way we can verify the stage header without loading the whole file and we can't load the file without trusting the information in the stage header.
To solve this problem, this patch changes the CBFS stage format to move the stage header out of the file contents and into a separate CBFS attribute. Attributes are part of the metadata, so they have already been verified before the file is loaded.
Since CBFS stages are generally only meant to be used by coreboot itself and the coreboot build system builds cbfstool and all stages together in one go, maintaining backwards-compatibility should not be necessary. An older version of coreboot will build the old version of cbfstool and a newer version of coreboot will build the new version of cbfstool before using it to add stages to the final image, thus cbfstool and coreboot's stage loader should stay in sync. This only causes problems when someone stashes away a copy of cbfstool somewhere and later uses it to try to extract stages from a coreboot image built from a different revision... a debugging use-case that is hopefully rare enough that affected users can manually deal with finding a matching version of cbfstool.
The SELF (payload) format, on the other hand, is designed to be used for binaries outside of coreboot that may use independent build systems and are more likely to be added with a potentially stale copy of cbfstool, so it would be more problematic to make a similar change for SELFs. It is not necessary for verification either, since they're usually only used in post-RAM environments and selfload() already maps SELFs to CBFS_CACHE before loading them to their final destination anyway (so they can be hashed at that time).
Signed-off-by: Julius Werner jwerner@chromium.org Change-Id: I8471ad7494b07599e24e82b81e507fcafbad808a --- M src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h M src/lib/cbfs.c M src/lib/rmodule.c M src/soc/amd/common/block/pi/refcode_loader.c M util/cbfstool/cbfs-mkstage.c M util/cbfstool/cbfs_image.c M util/cbfstool/cbfstool.c M util/cbfstool/common.h M util/cbfstool/rmodule.c 9 files changed, 205 insertions(+), 331 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/84/46484/29
Attention is currently required from: Raul Rangel, Furquan Shaikh. build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/46484 )
Change subject: cbfs: Move stage header into a CBFS attribute ......................................................................
Patch Set 29:
(2 comments)
File util/cbfstool/cbfs_image.c:
https://review.coreboot.org/c/coreboot/+/46484/comment/a5b51963_928b8ad4 PS29, Line 1337: static int cbfs_print_stage_info(struct cbfs_file *entry, FILE* fp) "foo* bar" should be "foo *bar"
File util/cbfstool/cbfstool.c:
https://review.coreboot.org/c/coreboot/+/46484/comment/9bd67e26_3e8170a9 PS29, Line 1167: ERROR("Not enough scratch space to decompress LZ4 in-place -- increase BSS size or disable compression!\n"); line over 96 characters
Patrick Georgi has submitted this change. ( https://review.coreboot.org/c/coreboot/+/46484 )
Change subject: cbfs: Move stage header into a CBFS attribute ......................................................................
cbfs: Move stage header into a CBFS attribute
The CBFS stage header is part of the file data (not the header) from CBFS's point of view, which is problematic for verification: in pre-RAM environments, there's usually not enough scratch space in CBFS_CACHE to load the full stage into memory, so it must be directly loaded into its final destination. However, that destination is decided from reading the stage header. There's no way we can verify the stage header without loading the whole file and we can't load the file without trusting the information in the stage header.
To solve this problem, this patch changes the CBFS stage format to move the stage header out of the file contents and into a separate CBFS attribute. Attributes are part of the metadata, so they have already been verified before the file is loaded.
Since CBFS stages are generally only meant to be used by coreboot itself and the coreboot build system builds cbfstool and all stages together in one go, maintaining backwards-compatibility should not be necessary. An older version of coreboot will build the old version of cbfstool and a newer version of coreboot will build the new version of cbfstool before using it to add stages to the final image, thus cbfstool and coreboot's stage loader should stay in sync. This only causes problems when someone stashes away a copy of cbfstool somewhere and later uses it to try to extract stages from a coreboot image built from a different revision... a debugging use-case that is hopefully rare enough that affected users can manually deal with finding a matching version of cbfstool.
The SELF (payload) format, on the other hand, is designed to be used for binaries outside of coreboot that may use independent build systems and are more likely to be added with a potentially stale copy of cbfstool, so it would be more problematic to make a similar change for SELFs. It is not necessary for verification either, since they're usually only used in post-RAM environments and selfload() already maps SELFs to CBFS_CACHE before loading them to their final destination anyway (so they can be hashed at that time).
Signed-off-by: Julius Werner jwerner@chromium.org Change-Id: I8471ad7494b07599e24e82b81e507fcafbad808a Reviewed-on: https://review.coreboot.org/c/coreboot/+/46484 Tested-by: build bot (Jenkins) no-reply@coreboot.org Reviewed-by: Aaron Durbin adurbin@chromium.org --- M src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h M src/lib/cbfs.c M src/lib/rmodule.c M src/soc/amd/common/block/pi/refcode_loader.c M util/cbfstool/cbfs-mkstage.c M util/cbfstool/cbfs_image.c M util/cbfstool/cbfstool.c M util/cbfstool/common.h M util/cbfstool/rmodule.c 9 files changed, 205 insertions(+), 331 deletions(-)
Approvals: build bot (Jenkins): Verified Aaron Durbin: Looks good to me, approved
diff --git a/src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h b/src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h index dc14cd5..dc80ed0 100644 --- a/src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h +++ b/src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h @@ -20,7 +20,8 @@ CBFS_TYPE_NULL = 0xffffffff, CBFS_TYPE_BOOTBLOCK = 0x01, CBFS_TYPE_CBFSHEADER = 0x02, - CBFS_TYPE_STAGE = 0x10, + CBFS_TYPE_LEGACY_STAGE = 0x10, + CBFS_TYPE_STAGE = 0x11, CBFS_TYPE_SELF = 0x20, CBFS_TYPE_FIT = 0x21, CBFS_TYPE_OPTIONROM = 0x30, @@ -131,6 +132,7 @@ CBFS_FILE_ATTR_TAG_ALIGNMENT = 0x42434c41, /* BE: 'BCLA' */ CBFS_FILE_ATTR_TAG_IBB = 0x32494242, /* BE: '2IBB' */ CBFS_FILE_ATTR_TAG_PADDING = 0x47444150, /* BE: 'GNDP' */ + CBFS_FILE_ATTR_TAG_STAGEHEADER = 0x53746748, /* BE: 'StgH' */ };
struct cbfs_file_attr_compression { @@ -160,22 +162,20 @@ uint32_t alignment; } __packed;
+struct cbfs_file_attr_stageheader { + uint32_t tag; + uint32_t len; + uint64_t loadaddr; /* Memory address to load the code to. */ + uint32_t entry_offset; /* Offset of entry point from loadaddr. */ + uint32_t memlen; /* Total length (including BSS) in memory. */ +} __packed; + + /*** Component sub-headers ***/
/* Following are component sub-headers for the "standard" component types */
-/** This is the sub-header for stage components. Stages are - loaded by coreboot during the normal boot process */ - -struct cbfs_stage { - uint32_t compression; /** Compression type */ - uint64_t entry; /** entry point */ - uint64_t load; /** Where to load in memory */ - uint32_t len; /** length of data to load */ - uint32_t memlen; /** total length of object in memory */ -} __packed; - /** this is the sub-header for payload components. Payloads are loaded by coreboot at the end of the boot process */
diff --git a/src/lib/cbfs.c b/src/lib/cbfs.c index a274551..fbf4531 100644 --- a/src/lib/cbfs.c +++ b/src/lib/cbfs.c @@ -386,11 +386,6 @@ { 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 @@ 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; + 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);
- 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); - - 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); + memset(prog_start(pstage) + fsize, 0, prog_size(pstage) - fsize);
- prog_segment_loaded((uintptr_t)load, stage.memlen, SEG_FINAL); - -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 6ea9db7..ac9eb0b 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 @@ 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(); + struct rmod_stage_load *rsl = rsl_arg;
- if (region_alignment < 4096) - region_alignment = 4096; + assert(IS_POWER_OF_2(region_alignment) && + region_alignment >= sizeof(struct rmodule_header));
- /* 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(); + /* 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; + } + + 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 @@ * 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 @@ * | >= 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 @@ 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, diff --git a/src/soc/amd/common/block/pi/refcode_loader.c b/src/soc/amd/common/block/pi/refcode_loader.c index fe2df5b..70cedb3 100644 --- a/src/soc/amd/common/block/pi/refcode_loader.c +++ b/src/soc/amd/common/block/pi/refcode_loader.c @@ -29,14 +29,8 @@ static int agesa_locate_stage_file_early(const char *name, struct region_device *rdev) { - const size_t metadata_sz = sizeof(struct cbfs_stage); - if (agesa_locate_file(name, rdev, CBFS_TYPE_STAGE)) return -1; - - /* Peel off the cbfs stage metadata. */ - return rdev_chain(rdev, rdev, metadata_sz, - region_device_sz(rdev) - metadata_sz); }
static int agesa_locate_stage_file_ramstage(const char *name, diff --git a/util/cbfstool/cbfs-mkstage.c b/util/cbfstool/cbfs-mkstage.c index bd1cf54..68eb641 100644 --- a/util/cbfstool/cbfs-mkstage.c +++ b/util/cbfstool/cbfs-mkstage.c @@ -10,8 +10,6 @@ #include "cbfs.h" #include "rmodule.h"
-#include <commonlib/bsd/compression.h> - /* Checks if program segment contains the ignored section */ static int is_phdr_ignored(Elf64_Phdr *phdr, Elf64_Shdr *shdr) { @@ -73,19 +71,20 @@ return NULL; }
-static void fill_cbfs_stage(struct buffer *outheader, enum cbfs_compression algo, - uint64_t entry, uint64_t loadaddr, - uint32_t filesize, uint32_t memsize) +static int fill_cbfs_stageheader(struct cbfs_file_attr_stageheader *stageheader, + uint64_t entry, uint64_t loadaddr, + uint32_t memsize) { - /* N.B. The original plan was that SELF data was B.E. - * but: this is all L.E. - * Maybe we should just change the spec. - */ - xdr_le.put32(outheader, algo); - xdr_le.put64(outheader, entry); - xdr_le.put64(outheader, loadaddr); - xdr_le.put32(outheader, filesize); - xdr_le.put32(outheader, memsize); + if (entry - loadaddr >= memsize) { + ERROR("stage entry point out of bounds!\n"); + return -1; + } + + stageheader->loadaddr = htonll(loadaddr); + stageheader->memlen = htonl(memsize); + stageheader->entry_offset = htonl(entry - loadaddr); + + return 0; }
/* returns size of result, or -1 if error. @@ -93,25 +92,20 @@ * works for all elf files, not just the restricted set. */ int parse_elf_to_stage(const struct buffer *input, struct buffer *output, - enum cbfs_compression algo, const char *ignore_section) + const char *ignore_section, + struct cbfs_file_attr_stageheader *stageheader) { struct parsed_elf pelf; Elf64_Phdr *phdr; Elf64_Ehdr *ehdr; Elf64_Shdr *shdr_ignored; Elf64_Addr virt_to_phys; - char *buffer; - struct buffer outheader; int ret = -1;
int headers; - int i, outlen; + int i; uint64_t data_start, data_end, mem_end;
- comp_func_ptr compress = compression_function(algo); - if (!compress) - return -1; - int flags = ELF_PARSE_PHDR | ELF_PARSE_SHDR | ELF_PARSE_STRTAB;
if (parse_elf(input, &pelf, flags)) { @@ -178,15 +172,13 @@ exit(1); }
- /* allocate an intermediate buffer for the data */ - buffer = calloc(data_end - data_start, 1); - - if (buffer == NULL) { + if (buffer_create(output, data_end - data_start, input->name) != 0) { ERROR("Unable to allocate memory: %m\n"); goto err; } + memset(output->data, 0, output->size);
- /* Copy the file data into the buffer */ + /* Copy the file data into the output buffer */
for (i = 0; i < headers; i++) { if (phdr[i].p_type != PT_LOAD) @@ -207,90 +199,17 @@ ERROR("Underflow copying out the segment." "File has %zu bytes left, segment end is %zu\n", input->size, (size_t)(phdr[i].p_offset + phdr[i].p_filesz)); - free(buffer); goto err; } - memcpy(buffer + (phdr[i].p_paddr - data_start), + memcpy(&output->data[phdr[i].p_paddr - data_start], &input->data[phdr[i].p_offset], phdr[i].p_filesz); }
- /* Now make the output buffer */ - if (buffer_create(output, sizeof(struct cbfs_stage) + data_end - data_start, - input->name) != 0) { - ERROR("Unable to allocate memory: %m\n"); - free(buffer); - goto err; - } - memset(output->data, 0, output->size); - - /* Compress the data, at which point we'll know information - * to fill out the header. This seems backward but it works because - * - the output header is a known size (not always true in many xdr's) - * - we do need to know the compressed output size first - * If compression fails or makes the data bigger, we'll warn about it - * and use the original data. - */ - if (compress(buffer, data_end - data_start, - (output->data + sizeof(struct cbfs_stage)), - &outlen) < 0 || (unsigned)outlen > data_end - data_start) { - WARN("Compression failed or would make the data bigger " - "- disabled.\n"); - memcpy(output->data + sizeof(struct cbfs_stage), - buffer, data_end - data_start); - outlen = data_end - data_start; - algo = CBFS_COMPRESS_NONE; - } - - /* Check for enough BSS scratch space to decompress LZ4 in-place. */ - if (algo == CBFS_COMPRESS_LZ4) { - size_t result; - size_t memlen = mem_end - data_start; - size_t compressed_size = outlen; - char *compare_buffer = malloc(memlen); - char *start = compare_buffer + memlen - compressed_size; - - if (compare_buffer == NULL) { - ERROR("Can't allocate memory!\n"); - free(buffer); - goto err; - } - - memcpy(start, output->data + sizeof(struct cbfs_stage), - compressed_size); - result = ulz4fn(start, compressed_size, compare_buffer, memlen); - - if (result == 0) { - ERROR("Not enough scratch space to decompress LZ4 in-place -- increase BSS size or disable compression!\n"); - free(compare_buffer); - free(buffer); - goto err; - } - if (result != data_end - data_start || - memcmp(compare_buffer, buffer, data_end - data_start)) { - ERROR("LZ4 compression BUG! Report to mailing list.\n"); - free(compare_buffer); - free(buffer); - goto err; - } - free(compare_buffer); - } - - free(buffer); - - /* Set up for output marshaling. */ - outheader.data = output->data; - outheader.size = 0; - /* coreboot expects entry point to be physical address. Thus, adjust the - * entry point accordingly. - */ - fill_cbfs_stage(&outheader, algo, ehdr->e_entry + virt_to_phys, - data_start, outlen, mem_end - data_start); - - output->size = sizeof(struct cbfs_stage) + outlen; - ret = 0; - + entry point accordingly. */ + ret = fill_cbfs_stageheader(stageheader, ehdr->e_entry + virt_to_phys, + data_start, mem_end - data_start); err: parsed_elf_destroy(&pelf); return ret; @@ -341,13 +260,13 @@ }
int parse_elf_to_xip_stage(const struct buffer *input, struct buffer *output, - uint32_t *location, const char *ignore_section) + uint32_t *location, const char *ignore_section, + struct cbfs_file_attr_stageheader *stageheader) { struct xip_context xipctx; struct rmod_context *rmodctx; struct reloc_filter filter; struct parsed_elf *pelf; - size_t output_sz; uint32_t adjustment; struct buffer binput; struct buffer boutput; @@ -381,13 +300,12 @@ if (rmodule_collect_relocations(rmodctx, &filter)) goto out;
- output_sz = sizeof(struct cbfs_stage) + pelf->phdr->p_filesz; - if (buffer_create(output, output_sz, input->name) != 0) { + if (buffer_create(output, pelf->phdr->p_filesz, input->name) != 0) { ERROR("Unable to allocate memory: %m\n"); goto out; } buffer_clone(&boutput, output); - memset(buffer_get(&boutput), 0, output_sz); + memset(buffer_get(&boutput), 0, pelf->phdr->p_filesz); buffer_set_size(&boutput, 0);
/* Single loadable segment. The entire segment moves to final @@ -395,17 +313,16 @@ adjustment = *location - pelf->phdr->p_vaddr; DEBUG("Relocation adjustment: %08x\n", adjustment);
- fill_cbfs_stage(&boutput, CBFS_COMPRESS_NONE, - (uint32_t)pelf->ehdr.e_entry + adjustment, - (uint32_t)pelf->phdr->p_vaddr + adjustment, - pelf->phdr->p_filesz, pelf->phdr->p_memsz); + fill_cbfs_stageheader(stageheader, + (uint32_t)pelf->ehdr.e_entry + adjustment, + (uint32_t)pelf->phdr->p_vaddr + adjustment, + pelf->phdr->p_memsz); /* Need an adjustable buffer. */ buffer_clone(&binput, input); buffer_seek(&binput, pelf->phdr->p_offset); bputs(&boutput, buffer_get(&binput), pelf->phdr->p_filesz);
buffer_clone(&boutput, output); - buffer_seek(&boutput, sizeof(struct cbfs_stage));
/* Make adjustments to all the relocations within the program. */ for (i = 0; i < rmodctx->nrelocs; i++) { @@ -431,8 +348,6 @@ xdr_le.put32(&out, val + adjustment); }
- /* Need to back up the location to include cbfs stage metadata. */ - *location -= sizeof(struct cbfs_stage); ret = 0;
out: diff --git a/util/cbfstool/cbfs_image.c b/util/cbfstool/cbfs_image.c index d3c6c94..1fb19ba 100644 --- a/util/cbfstool/cbfs_image.c +++ b/util/cbfstool/cbfs_image.c @@ -824,69 +824,6 @@ return NULL; }
-static int cbfs_stage_decompress(struct cbfs_stage *stage, struct buffer *buff) -{ - struct buffer reader; - char *orig_buffer; - char *new_buffer; - size_t new_buff_sz; - decomp_func_ptr decompress; - - buffer_clone(&reader, buff); - - /* The stage metadata is in little endian. */ - stage->compression = xdr_le.get32(&reader); - stage->entry = xdr_le.get64(&reader); - stage->load = xdr_le.get64(&reader); - stage->len = xdr_le.get32(&reader); - stage->memlen = xdr_le.get32(&reader); - - /* Create a buffer just with the uncompressed program now that the - * struct cbfs_stage has been peeled off. */ - if (stage->compression == CBFS_COMPRESS_NONE) { - new_buff_sz = buffer_size(buff) - sizeof(struct cbfs_stage); - - orig_buffer = buffer_get(buff); - new_buffer = calloc(1, new_buff_sz); - memcpy(new_buffer, orig_buffer + sizeof(struct cbfs_stage), - new_buff_sz); - buffer_init(buff, buff->name, new_buffer, new_buff_sz); - free(orig_buffer); - return 0; - } - - decompress = decompression_function(stage->compression); - if (decompress == NULL) - return -1; - - orig_buffer = buffer_get(buff); - - /* This can be too big of a buffer needed, but there's no current - * field indicating decompressed size of data. */ - new_buff_sz = stage->memlen; - new_buffer = calloc(1, new_buff_sz); - - if (decompress(orig_buffer + sizeof(struct cbfs_stage), - (int)(buffer_size(buff) - sizeof(struct cbfs_stage)), - new_buffer, (int)new_buff_sz, &new_buff_sz)) { - ERROR("Couldn't decompress stage.\n"); - free(new_buffer); - return -1; - } - - /* Include correct size for full stage info. */ - buffer_init(buff, buff->name, new_buffer, new_buff_sz); - - /* True decompressed size is just the data size -- no metadata. */ - stage->len = new_buff_sz; - /* Stage is not compressed. */ - stage->compression = CBFS_COMPRESS_NONE; - - free(orig_buffer); - - return 0; -} - static int cbfs_payload_decompress(struct cbfs_payload_segment *segments, struct buffer *buff, int num_seg) { @@ -1020,11 +957,11 @@ return 0; }
-static int cbfs_stage_make_elf(struct buffer *buff, uint32_t arch) +static int cbfs_stage_make_elf(struct buffer *buff, uint32_t arch, + struct cbfs_file *entry) { Elf64_Ehdr ehdr; Elf64_Shdr shdr; - struct cbfs_stage stage; struct elf_writer *ew; struct buffer elf_out; size_t empty_sz; @@ -1035,16 +972,23 @@ return -1; }
- if (cbfs_stage_decompress(&stage, buff)) { - ERROR("Failed to decompress stage.\n"); + struct cbfs_file_attr_stageheader *stage = NULL; + for (struct cbfs_file_attribute *attr = cbfs_file_first_attr(entry); + attr != NULL; attr = cbfs_file_next_attr(entry, attr)) { + if (ntohl(attr->tag) == CBFS_FILE_ATTR_TAG_STAGEHEADER) { + stage = (struct cbfs_file_attr_stageheader *)attr; + break; + } + } + + if (stage == NULL) { + ERROR("Stage header not found for %s\n", entry->filename); return -1; }
if (init_elf_from_arch(&ehdr, arch)) return -1;
- ehdr.e_entry = stage.entry; - /* Attempt rmodule translation first. */ rmod_ret = rmodule_stage_to_elf(&ehdr, buff);
@@ -1056,6 +1000,8 @@
/* Rmodule couldn't do anything with the data. Continue on with SELF. */
+ ehdr.e_entry = ntohll(stage->loadaddr) + ntohl(stage->entry_offset); + ew = elf_writer_init(&ehdr); if (ew == NULL) { ERROR("Unable to init ELF writer.\n"); @@ -1065,9 +1011,9 @@ memset(&shdr, 0, sizeof(shdr)); shdr.sh_type = SHT_PROGBITS; shdr.sh_flags = SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR; - shdr.sh_addr = stage.load; - shdr.sh_size = stage.len; - empty_sz = stage.memlen - stage.len; + shdr.sh_addr = ntohll(stage->loadaddr); + shdr.sh_size = buffer_size(buff); + empty_sz = ntohl(stage->memlen) - buffer_size(buff);
if (elf_writer_add_section(ew, &shdr, buff, ".program")) { ERROR("Unable to add ELF section: .program\n"); @@ -1082,7 +1028,7 @@ memset(&shdr, 0, sizeof(shdr)); shdr.sh_type = SHT_NOBITS; shdr.sh_flags = SHF_WRITE | SHF_ALLOC; - shdr.sh_addr = stage.load + stage.len; + shdr.sh_addr = ntohl(stage->loadaddr) + buffer_size(buff); shdr.sh_size = empty_sz; if (elf_writer_add_section(ew, &shdr, &b, ".empty")) { ERROR("Unable to add ELF section: .empty\n"); @@ -1106,7 +1052,8 @@ return 0; }
-static int cbfs_payload_make_elf(struct buffer *buff, uint32_t arch) +static int cbfs_payload_make_elf(struct buffer *buff, uint32_t arch, + unused struct cbfs_file *entry) { Elf64_Ehdr ehdr; Elf64_Shdr shdr; @@ -1258,7 +1205,7 @@ }
if (elf_writer_serialize(ew, &elf_out)) { - ERROR("Unable to create ELF file from stage.\n"); + ERROR("Unable to create ELF file from payload.\n"); goto out; }
@@ -1320,13 +1267,13 @@ }
/* - * The stage metadata is never compressed proper for cbfs_stage - * files. The contents of the stage data can be though. Therefore - * one has to do a second pass for stages to potentially decompress - * the stage data to make it more meaningful. + * We want to export stages and payloads as ELFs, not with coreboot's + * custom stage/SELF binary formats, so we need to do extra processing + * to turn them back into an ELF. */ if (do_processing) { - int (*make_elf)(struct buffer *, uint32_t) = NULL; + int (*make_elf)(struct buffer *, uint32_t, + struct cbfs_file *) = NULL; switch (ntohl(entry->type)) { case CBFS_TYPE_STAGE: make_elf = cbfs_stage_make_elf; @@ -1335,7 +1282,7 @@ make_elf = cbfs_payload_make_elf; break; } - if (make_elf && make_elf(&buffer, arch)) { + if (make_elf && make_elf(&buffer, arch, entry)) { ERROR("Failed to write %s into %s.\n", entry_name, filename); buffer_delete(&buffer); @@ -1387,17 +1334,29 @@ return 0; }
-static int cbfs_print_stage_info(struct cbfs_stage *stage, FILE* fp) +static int cbfs_print_stage_info(struct cbfs_file *entry, FILE* fp) { + + struct cbfs_file_attr_stageheader *stage = NULL; + for (struct cbfs_file_attribute *attr = cbfs_file_first_attr(entry); + attr != NULL; attr = cbfs_file_next_attr(entry, attr)) { + if (ntohl(attr->tag) == CBFS_FILE_ATTR_TAG_STAGEHEADER) { + stage = (struct cbfs_file_attr_stageheader *)attr; + break; + } + } + + if (stage == NULL) { + fprintf(fp, " ERROR: stage header not found!\n"); + return -1; + } + fprintf(fp, - " %s compression, entry: 0x%" PRIx64 ", load: 0x%" PRIx64 ", " - "length: %d/%d\n", - lookup_name_by_type(types_cbfs_compression, - stage->compression, "(unknown)"), - stage->entry, - stage->load, - stage->len, - stage->memlen); + " entry: 0x%" PRIx64 ", load: 0x%" PRIx64 ", " + "memlen: %d\n", + ntohll(stage->loadaddr) + ntohl(stage->entry_offset), + ntohll(stage->loadaddr), + ntohl(stage->memlen)); return 0; }
@@ -1519,8 +1478,7 @@ /* note the components of the subheader may be in host order ... */ switch (ntohl(entry->type)) { case CBFS_TYPE_STAGE: - cbfs_print_stage_info((struct cbfs_stage *) - CBFS_SUBHEADER(entry), fp); + cbfs_print_stage_info(entry, fp); break;
case CBFS_TYPE_SELF: diff --git a/util/cbfstool/cbfstool.c b/util/cbfstool/cbfstool.c index 3e80712..6133536 100644 --- a/util/cbfstool/cbfstool.c +++ b/util/cbfstool/cbfstool.c @@ -14,7 +14,9 @@ #include "cbfs_sections.h" #include "elfparsing.h" #include "partitioned_file.h" +#include "lz4/lib/xxhash.h" #include <commonlib/bsd/cbfs_private.h> +#include <commonlib/bsd/compression.h> #include <commonlib/bsd/metadata_hash.h> #include <commonlib/fsp.h> #include <commonlib/endian.h> @@ -911,16 +913,7 @@ sizeof(struct cbfs_file_attr_position)); if (attrs == NULL) goto error; - /* If we add a stage or a payload, we need to take */ - /* care about the additional metadata that is added */ - /* to the cbfs file and therefore set the position */ - /* the real beginning of the data. */ - if (type == CBFS_TYPE_STAGE) - attrs->position = htonl(offset - sizeof(struct cbfs_stage)); - else if (type == CBFS_TYPE_SELF) - attrs->position = htonl(offset - sizeof(struct cbfs_payload)); - else - attrs->position = htonl(offset); + attrs->position = htonl(offset); } /* Add alignment attribute if used */ if (param.alignment) { @@ -1118,11 +1111,18 @@ * stages that would actually fit once compressed. */ if ((param.alignment || param.stage_xip) && - do_cbfs_locate(offset, sizeof(struct cbfs_stage), data_size)) { + do_cbfs_locate(offset, sizeof(struct cbfs_file_attr_stageheader), + data_size)) { ERROR("Could not find location for stage.\n"); return 1; }
+ struct cbfs_file_attr_stageheader *stageheader = (void *) + cbfs_add_file_attr(header, CBFS_FILE_ATTR_TAG_STAGEHEADER, + sizeof(struct cbfs_file_attr_stageheader)); + if (!stageheader) + return -1; + if (param.stage_xip) { /* * Ensure the address is a memory mapped one. This assumes @@ -1132,19 +1132,57 @@ *offset = convert_addr_space(param.image_region, *offset);
ret = parse_elf_to_xip_stage(buffer, &output, offset, - param.ignore_section); + param.ignore_section, + stageheader); } else { - ret = parse_elf_to_stage(buffer, &output, param.compression, - param.ignore_section); + ret = parse_elf_to_stage(buffer, &output, param.ignore_section, + stageheader); } - if (ret != 0) return -1; + + /* Store a hash of original uncompressed stage to compare later. */ + size_t decmp_size = buffer_size(&output); + uint32_t decmp_hash = XXH32(buffer_get(&output), decmp_size, 0); + + /* Chain to base conversion routine to handle compression. */ + ret = cbfstool_convert_raw(&output, offset, header); + if (ret != 0) + goto fail; + + /* Special care must be taken for LZ4-compressed stages that the BSS is + large enough to provide scratch space for in-place decompression. */ + if (!param.precompression && param.compression == CBFS_COMPRESS_LZ4) { + size_t memlen = ntohl(stageheader->memlen); + size_t compressed_size = buffer_size(&output); + uint8_t *compare_buffer = malloc(memlen); + uint8_t *start = compare_buffer + memlen - compressed_size; + if (!compare_buffer) { + ERROR("Out of memory\n"); + goto fail; + } + memcpy(start, buffer_get(&output), compressed_size); + ret = ulz4fn(start, compressed_size, compare_buffer, memlen); + if (ret == 0) { + ERROR("Not enough scratch space to decompress LZ4 in-place -- increase BSS size or disable compression!\n"); + free(compare_buffer); + goto fail; + } else if (ret != (int)decmp_size || + decmp_hash != XXH32(compare_buffer, decmp_size, 0)) { + ERROR("LZ4 compression BUG! Report to mailing list.\n"); + free(compare_buffer); + goto fail; + } + free(compare_buffer); + } + buffer_delete(buffer); - // Direct assign, no dupe. - memcpy(buffer, &output, sizeof(*buffer)); - header->len = htonl(output.size); + buffer_clone(buffer, &output); return 0; + +fail: + buffer_delete(&output); + return -1; }
static int cbfstool_convert_mkpayload(struct buffer *buffer, diff --git a/util/cbfstool/common.h b/util/cbfstool/common.h index db9c7e7..479fd713 100644 --- a/util/cbfstool/common.h +++ b/util/cbfstool/common.h @@ -174,10 +174,12 @@ enum cbfs_compression algo); /* cbfs-mkstage.c */ int parse_elf_to_stage(const struct buffer *input, struct buffer *output, - enum cbfs_compression algo, const char *ignore_section); + const char *ignore_section, + struct cbfs_file_attr_stageheader *stageheader); /* location is TOP aligned. */ int parse_elf_to_xip_stage(const struct buffer *input, struct buffer *output, - uint32_t *location, const char *ignore_section); + uint32_t *location, const char *ignore_section, + struct cbfs_file_attr_stageheader *stageheader);
void print_supported_architectures(void); void print_supported_filetypes(void); diff --git a/util/cbfstool/rmodule.c b/util/cbfstool/rmodule.c index 258a4d8..4ac2951 100644 --- a/util/cbfstool/rmodule.c +++ b/util/cbfstool/rmodule.c @@ -498,8 +498,9 @@ /* Program contents. */ buffer_splice(&program, in, ctx->phdr->p_offset, ctx->phdr->p_filesz);
- /* Create ELF writer with modified entry point. */ + /* Create ELF writer. Set entry point to 0 to match section offsets. */ memcpy(&ehdr, &ctx->pelf.ehdr, sizeof(ehdr)); + ehdr.e_entry = 0; ew = elf_writer_init(&ehdr);
if (ew == NULL) {
Patrick Georgi has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/46484 )
Change subject: cbfs: Move stage header into a CBFS attribute ......................................................................
Patch Set 30:
(1 comment)
Patchset:
PS30:
Patch Set 3:
If the change is agreed upon, it should be documented in the release notes.
A request for comments was sent to the mailing list [1].
Added an entry for the release notes: https://review.coreboot.org/c/coreboot/+/51562