From 405304aca34b3dab949e616486bb60a52fd5dae0 Mon Sep 17 00:00:00 2001 From: Furquan Shaikh Date: Thu, 30 Oct 2014 11:44:20 -0700 Subject: [PATCH] cbfstool: Add option to ignore section in add-stage Allow add-stage to have an optional parameter for ignoring any section. This is required to ensure proper operation of elf_to_stage in case of loadable segments with zero filesize. Change-Id: I49ad62c2a4260ab9cec173c80c0f16923fc66c79 Signed-off-by: Furquan Shaikh Reviewed-on: http://review.coreboot.org/7304 Tested-by: build bot (Jenkins) Reviewed-by: Edward O'Callaghan --- util/cbfstool/cbfs-mkstage.c | 77 +++++++++++++++++++++++++++++++++++- util/cbfstool/cbfstool.c | 12 ++++-- util/cbfstool/common.h | 3 +- 3 files changed, 87 insertions(+), 5 deletions(-) diff --git a/util/cbfstool/cbfs-mkstage.c b/util/cbfstool/cbfs-mkstage.c index 3da0836536..845933487f 100644 --- a/util/cbfstool/cbfs-mkstage.c +++ b/util/cbfstool/cbfs-mkstage.c @@ -28,16 +28,79 @@ #include "common.h" #include "cbfs.h" +/* Checks if program segment contains the ignored section */ +static int is_phdr_ignored(Elf64_Phdr *phdr, Elf64_Shdr *shdr) +{ + /* If no ignored section, return false. */ + if (shdr == NULL) + return 0; + + Elf64_Addr sh_start = shdr->sh_addr; + Elf64_Addr sh_end = shdr->sh_addr + shdr->sh_size; + Elf64_Addr ph_start = phdr->p_vaddr; + Elf64_Addr ph_end = phdr->p_vaddr + phdr->p_memsz; + + /* Return true only if section occupies whole of segment. */ + if ((sh_start == ph_start) && (sh_end == ph_end)) { + DEBUG("Ignoring program segment at %p\n", (void *)ph_start); + return 1; + } + + /* If shdr intersects phdr at all, its a conflict */ + if (((sh_start >= ph_start) && (sh_start <= ph_end)) || + ((sh_end >= ph_start) && (sh_end <= ph_end))) { + ERROR("Conflicting sections in segment\n"); + exit(1); + } + + /* Program header doesn't need to be ignored. */ + return 0; +} + +/* Find section header based on ignored section name */ +static Elf64_Shdr *find_ignored_section_header(struct parsed_elf *pelf, + const char *ignore_section) +{ + int i; + const char *shstrtab; + + /* No section needs to be ignored */ + if (ignore_section == NULL) + return NULL; + + DEBUG("Section to be ignored: %s\n", ignore_section); + + /* Get pointer to string table */ + shstrtab = buffer_get(pelf->strtabs[pelf->ehdr.e_shstrndx]); + + for (i = 0; i < pelf->ehdr.e_shnum; i++) { + Elf64_Shdr *shdr; + const char *section_name; + + shdr = &pelf->shdr[i]; + section_name = &shstrtab[shdr->sh_name]; + + /* If section name matches ignored string, return shdr */ + if (strcmp(section_name, ignore_section) == 0) + return shdr; + } + + /* No section matches ignore string */ + return NULL; +} + /* returns size of result, or -1 if error. * Note that, with the new code, this function * works for all elf files, not just the restricted set. */ int parse_elf_to_stage(const struct buffer *input, struct buffer *output, - uint32_t arch, comp_algo algo, uint32_t *location) + uint32_t arch, comp_algo algo, uint32_t *location, + const char *ignore_section) { struct parsed_elf pelf; Elf64_Phdr *phdr; Elf64_Ehdr *ehdr; + Elf64_Shdr *shdr_ignored; char *buffer; struct buffer outheader; int ret = -1; @@ -62,8 +125,20 @@ int parse_elf_to_stage(const struct buffer *input, struct buffer *output, ehdr = &pelf.ehdr; phdr = &pelf.phdr[0]; + /* Find the section header corresponding to ignored-section */ + shdr_ignored = find_ignored_section_header(&pelf, ignore_section); + + if (ignore_section && (shdr_ignored == NULL)) + WARN("Ignore section not found\n"); + headers = ehdr->e_phnum; + /* Ignore the program header containing ignored section */ + for (i = 0; i < headers; i++) { + if (is_phdr_ignored(&phdr[i], shdr_ignored)) + phdr[i].p_type = PT_NULL; + } + data_start = ~0; data_end = 0; mem_end = 0; diff --git a/util/cbfstool/cbfstool.c b/util/cbfstool/cbfstool.c index ca02ca6dcb..66c425bd7c 100644 --- a/util/cbfstool/cbfstool.c +++ b/util/cbfstool/cbfstool.c @@ -41,6 +41,7 @@ static struct param { char *name; char *filename; char *bootblock; + char *ignore_section; uint64_t u64val; uint32_t type; uint32_t baseaddress; @@ -184,7 +185,7 @@ static int cbfstool_convert_mkstage(struct buffer *buffer, uint32_t *offset) struct buffer output; int ret; ret = parse_elf_to_stage(buffer, &output, param.arch, param.algo, - offset); + offset, param.ignore_section); if (ret != 0) return -1; buffer_delete(buffer); @@ -516,7 +517,7 @@ static int cbfs_update_fit(void) static const struct command commands[] = { {"add", "f:n:t:b:vh?", cbfs_add}, {"add-payload", "f:n:t:c:b:vh?C:I:", cbfs_add_payload}, - {"add-stage", "f:n:t:c:b:vh?", cbfs_add_stage}, + {"add-stage", "f:n:t:c:b:S:vh?", cbfs_add_stage}, {"add-flat-binary", "f:n:l:e:c:b:vh?", cbfs_add_flat_binary}, {"add-int", "i:n:b:vh?", cbfs_add_integer}, {"remove", "n:vh?", cbfs_remove}, @@ -546,6 +547,7 @@ static struct option long_options[] = { {"empty-fits", required_argument, 0, 'x' }, {"initrd", required_argument, 0, 'I' }, {"cmdline", required_argument, 0, 'C' }, + {"ignore-sec", required_argument, 0, 'S' }, {"verbose", no_argument, 0, 'v' }, {"help", no_argument, 0, 'h' }, {NULL, 0, 0, 0 } @@ -566,7 +568,8 @@ static void usage(char *name) " add-payload -f FILE -n NAME [-c compression] [-b base] " "Add a payload to the ROM\n" " (linux specific: [-C cmdline] [-I initrd])\n" - " add-stage -f FILE -n NAME [-c compression] [-b base] " + " add-stage -f FILE -n NAME [-c compression] [-b base] \\\n" + " [-S section-to-ignore] " "Add a stage to the ROM\n" " add-flat-binary -f FILE -n NAME -l load-address \\\n" " -e entry-point [-c compression] [-b base] " @@ -714,6 +717,9 @@ int main(int argc, char **argv) case 'C': param.cmdline = optarg; break; + case 'S': + param.ignore_section = optarg; + break; case 'h': case '?': usage(argv[0]); diff --git a/util/cbfstool/common.h b/util/cbfstool/common.h index 02a088b98d..41659a268e 100644 --- a/util/cbfstool/common.h +++ b/util/cbfstool/common.h @@ -139,7 +139,8 @@ int parse_flat_binary_to_payload(const struct buffer *input, comp_algo algo); /* cbfs-mkstage.c */ int parse_elf_to_stage(const struct buffer *input, struct buffer *output, - uint32_t arch, comp_algo algo, uint32_t *location); + uint32_t arch, comp_algo algo, uint32_t *location, + const char *ignore_section); void print_supported_filetypes(void);