diff options
Diffstat (limited to 'util/ifdtool')
-rw-r--r-- | util/ifdtool/ifdtool.c | 108 | ||||
-rw-r--r-- | util/ifdtool/ifdtool.h | 2 |
2 files changed, 105 insertions, 5 deletions
diff --git a/util/ifdtool/ifdtool.c b/util/ifdtool/ifdtool.c index c2dde3c289..625b4cf5ac 100644 --- a/util/ifdtool/ifdtool.c +++ b/util/ifdtool/ifdtool.c @@ -331,6 +331,7 @@ static struct region get_region(const struct frba *frba, unsigned int region_typ region.base = (flreg & base_mask) << 12; region.limit = ((flreg & limit_mask) >> 4) | 0xfff; region.size = region.limit - region.base + 1; + region.type = region_type; if (region.size < 0) region.size = 0; @@ -995,6 +996,91 @@ static void dump_fd(char *image, int size) } } +/* Takes an image containing an IFD and creates a Flashmap .fmd file template. + * This flashmap will contain all IFD regions except the BIOS region. + * The BIOS region is created by coreboot itself and 'should' match the IFD region + * anyway (CONFIG_VALIDATE_INTEL_DESCRIPTOR should make sure). coreboot built system will use + * this template to generate the final Flashmap file. + */ +static void create_fmap_template(char *image, int size, const char *layout_fname) +{ + const struct frba *frba = find_frba(image, size); + if (!frba) + exit(EXIT_FAILURE); + + int layout_fd = open(layout_fname, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (layout_fd == -1) { + perror("Could not open file"); + exit(EXIT_FAILURE); + } + + char *bbuf = "FLASH@##ROM_BASE## ##ROM_SIZE## {\n"; + if (write(layout_fd, bbuf, strlen(bbuf)) < 0) { + perror("Could not write to file"); + exit(EXIT_FAILURE); + } + + /* fmaptool requires regions in .fmd to be sorted. + * => We need to sort the regions by base address before writing them in .fmd File + */ + int count_regions = 0; + struct region sorted_regions[MAX_REGIONS] = { 0 }; + for (unsigned int i = 0; i < max_regions; i++) { + struct region region = get_region(frba, i); + /* is region invalid? */ + if (region.size < 1) + continue; + + /* Here we decide to use the coreboot generated FMAP BIOS region, instead of + * the one specified in the IFD. The case when IFD and FMAP BIOS region do not + * match cannot be caught here, therefore one should still validate IFD and + * FMAP via CONFIG_VALIDATE_INTEL_DESCRIPTOR + */ + if (i == REGION_BIOS) + continue; + + sorted_regions[count_regions] = region; + // basically insertion sort + for (int i = count_regions-1; i >= 0 ; i--) { + if (sorted_regions[i].base > sorted_regions[i+1].base) { + struct region tmp = sorted_regions[i]; + sorted_regions[i] = sorted_regions[i+1]; + sorted_regions[i+1] = tmp; + } + } + count_regions++; + } + + // Now write regions sorted by base address in the fmap file + for (int i = 0; i < count_regions; i++) { + struct region region = sorted_regions[i]; + char buf[LAYOUT_LINELEN]; + snprintf(buf, LAYOUT_LINELEN, "\t%s@0x%X 0x%X\n", region_names[region.type].fmapname, region.base, region.size); + if (write(layout_fd, buf, strlen(buf)) < 0) { + perror("Could not write to file"); + exit(EXIT_FAILURE); + } + } + + char *ebuf = "\tSI_BIOS@##BIOS_BASE## ##BIOS_SIZE## {\n" + "\t\t##CONSOLE_ENTRY##\n" + "\t\t##MRC_CACHE_ENTRY##\n" + "\t\t##SMMSTORE_ENTRY##\n" + "\t\t##SPD_CACHE_ENTRY##\n" + "\t\t##VPD_ENTRY##\n" + "\t\tFMAP@##FMAP_BASE## ##FMAP_SIZE##\n" + "\t\tCOREBOOT(CBFS)@##CBFS_BASE## ##CBFS_SIZE##\n" + "\t}\n" + "}\n"; + if (write(layout_fd, ebuf, strlen(ebuf)) < 0) { + perror("Could not write to file"); + exit(EXIT_FAILURE); + } + + close(layout_fd); + printf("Wrote layout to %s\n", layout_fname); +} + static void write_regions(char *image, int size) { unsigned int i; @@ -1689,6 +1775,7 @@ static void print_usage(const char *name) printf("\n" " -d | --dump: dump intel firmware descriptor\n" " -f | --layout <filename> dump regions into a flashrom layout file\n" + " -F | --fmap-layout <filename> dump IFD regions into a fmap layout template (.fmd) file\n" " -t | --validate Validate that the firmware descriptor layout matches the fmap layout\n" " -x | --extract: extract intel fd modules\n" " -i | --inject <region>:<module> inject file <module> into region <region>\n" @@ -1735,7 +1822,7 @@ int main(int argc, char *argv[]) int mode_dump = 0, mode_extract = 0, mode_inject = 0, mode_spifreq = 0; int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0, mode_validate = 0; int mode_layout = 0, mode_newlayout = 0, mode_density = 0, mode_setstrap = 0; - int mode_read = 0, mode_altmedisable = 0, altmedisable = 0; + int mode_read = 0, mode_altmedisable = 0, altmedisable = 0, mode_fmap_template = 0; char *region_type_string = NULL, *region_fname = NULL; const char *layout_fname = NULL; char *new_filename = NULL; @@ -1748,6 +1835,7 @@ int main(int argc, char *argv[]) static const struct option long_options[] = { {"dump", 0, NULL, 'd'}, {"layout", 1, NULL, 'f'}, + {"fmap-template", 1, NULL, 'F'}, {"extract", 0, NULL, 'x'}, {"inject", 1, NULL, 'i'}, {"newlayout", 1, NULL, 'n'}, @@ -1769,7 +1857,7 @@ int main(int argc, char *argv[]) {0, 0, 0, 0} }; - while ((opt = getopt_long(argc, argv, "S:V:df:D:C:M:xi:n:O:s:p:elruvth?", + while ((opt = getopt_long(argc, argv, "S:V:df:F:D:C:M:xi:n:O:s:p:elruvth?", long_options, &option_index)) != EOF) { switch (opt) { case 'd': @@ -1791,6 +1879,15 @@ int main(int argc, char *argv[]) exit(EXIT_FAILURE); } break; + case 'F': + mode_fmap_template = 1; + layout_fname = strdup(optarg); + if (!layout_fname) { + fprintf(stderr, "No layout file specified\n"); + fprintf(stderr, "run '%s -h' for usage\n", argv[0]); + exit(EXIT_FAILURE); + } + break; case 'x': mode_extract = 1; break; @@ -2013,7 +2110,7 @@ int main(int argc, char *argv[]) } } - if ((mode_dump + mode_layout + mode_extract + mode_inject + + if ((mode_dump + mode_layout + mode_fmap_template + mode_extract + mode_inject + mode_setstrap + mode_newlayout + (mode_spifreq | mode_em100 | mode_unlocked | mode_locked) + mode_altmedisable + mode_validate) > 1) { fprintf(stderr, "You may not specify more than one mode.\n\n"); @@ -2021,7 +2118,7 @@ int main(int argc, char *argv[]) exit(EXIT_FAILURE); } - if ((mode_dump + mode_layout + mode_extract + mode_inject + + if ((mode_dump + mode_layout + mode_fmap_template + mode_extract + mode_inject + mode_setstrap + mode_newlayout + mode_spifreq + mode_em100 + mode_locked + mode_unlocked + mode_density + mode_altmedisable + mode_validate) == 0) { fprintf(stderr, "You need to specify a mode.\n\n"); @@ -2086,6 +2183,9 @@ int main(int argc, char *argv[]) if (mode_layout) dump_flashrom_layout(image, size, layout_fname); + if (mode_fmap_template) + create_fmap_template(image, size, layout_fname); + if (mode_extract) write_regions(image, size); diff --git a/util/ifdtool/ifdtool.h b/util/ifdtool/ifdtool.h index 6029c66d5b..5717a0a87a 100644 --- a/util/ifdtool/ifdtool.h +++ b/util/ifdtool/ifdtool.h @@ -191,7 +191,7 @@ struct vtba { }; struct region { - int base, limit, size; + int base, limit, size, type; }; struct region_name { |