diff options
Diffstat (limited to 'utility/dump_fmap.c')
-rw-r--r-- | utility/dump_fmap.c | 152 |
1 files changed, 124 insertions, 28 deletions
diff --git a/utility/dump_fmap.c b/utility/dump_fmap.c index d4a3eb1c..2f2ff93c 100644 --- a/utility/dump_fmap.c +++ b/utility/dump_fmap.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 The Chromium OS Authors. All rights reserved. + * Copyright (c) 2012 The Chromium OS Authors. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ @@ -17,21 +17,22 @@ #include "fmap.h" -enum { FMT_NORMAL, FMT_PRETTY, FMT_FLASHROM }; +enum { FMT_NORMAL, FMT_PRETTY, FMT_FLASHROM, FMT_HUMAN }; /* global variables */ static int opt_extract = 0; static int opt_format = FMT_NORMAL; -static char* progname; -static void* base_of_rom; +static char *progname; +static void *base_of_rom; /* Return 0 if successful */ -static int dump_fmap(const void* ptr, int argc, char *argv[]) { +static int dump_fmap(const void *ptr, int argc, char *argv[]) +{ int i, retval = 0; char buf[80]; // DWR: magic number - const FmapHeader* fmh = (const FmapHeader*) ptr; - const FmapAreaHeader* ah = (const FmapAreaHeader*) (ptr + sizeof(FmapHeader)); + const FmapHeader *fmh = (const FmapHeader*)ptr; + const FmapAreaHeader *ah = (const FmapAreaHeader*)(ptr + sizeof(FmapHeader)); if (FMT_NORMAL == opt_format) { snprintf(buf, FMAP_SIGNATURE_SIZE+1, "%s", fmh->fmap_signature); @@ -45,30 +46,29 @@ static int dump_fmap(const void* ptr, int argc, char *argv[]) { printf("fmap_nareas: %d\n", fmh->fmap_nareas); } - for (i=0; i<fmh->fmap_nareas; i++, ah++) { + for (i = 0; i < fmh->fmap_nareas; i++, ah++) { snprintf(buf, FMAP_NAMELEN+1, "%s", ah->area_name); if (argc) { int j, found=0; - for (j=0; j<argc; j++) + for (j = 0; j < argc; j++) if (!strcmp(argv[j], buf)) { - found = 1; - break; - } + found = 1; + break; + } if (!found) { continue; } } - switch(opt_format) - { + switch (opt_format) { case FMT_PRETTY: printf("%s %d %d\n", buf, ah->area_offset, ah->area_size); break; case FMT_FLASHROM: if (ah->area_size) printf("0x%08x:0x%08x %s\n", ah->area_offset, - ah->area_offset + ah->area_size - 1, buf); + ah->area_offset + ah->area_size - 1, buf); break; default: printf("area: %d\n", i+1); @@ -78,11 +78,11 @@ static int dump_fmap(const void* ptr, int argc, char *argv[]) { } if (opt_extract) { - char* s; - for (s=buf;* s; s++) + char *s; + for (s = buf; *s; s++) if (*s == ' ') *s = '_'; - FILE* fp = fopen(buf,"wb"); + FILE *fp = fopen(buf,"wb"); if (!fp) { fprintf(stderr, "%s: can't open %s: %s\n", progname, buf, strerror(errno)); @@ -106,12 +106,97 @@ static int dump_fmap(const void* ptr, int argc, char *argv[]) { } -int main(int argc, char* argv[]) { +/* Sort by start, then size, then name */ +static int by_start(FmapAreaHeader *a, FmapAreaHeader *b) +{ + if (a->area_offset == b->area_offset) { + + if (a->area_size == b->area_size ) + return strncmp(a->area_name, b->area_name, FMAP_NAMELEN) < 0; + + return a->area_size < b->area_size; + } + + return a->area_offset > b->area_offset; +} + + + +static void isort(FmapAreaHeader *ary, int num, + int (*lessthan)(FmapAreaHeader *a, FmapAreaHeader *b)) +{ + int i, j; + FmapAreaHeader tmp; + + for (i = 1; i < num; i++) { + tmp = ary[i]; + for (j = i; j && lessthan(ary+j-1, &tmp); j--) + ary[j] = ary[j-1]; + ary[j] = tmp; + } +} + +/* Return 0 if successful */ +static int human_fmap(void *ptr) +{ + int i, j; + uint32_t end_i; + FmapHeader *fmh = (FmapHeader *)ptr; + FmapAreaHeader *ah = (FmapAreaHeader *)(fmh + 1); + FmapAreaHeader tmp; + + /* We're using mmap() with MAP_PRIVATE, so we can freely fiddle with the fmap + * data. We'll sort the areas, reusing the flags field for indentation. */ + for (i = 0; i < fmh->fmap_nareas; i++) + ah[i].area_flags = 0; + + /* First, sort by start and size. */ + isort(ah, fmh->fmap_nareas, by_start); + + /* Now figure out indentation. */ + for (i = 0; i < fmh->fmap_nareas - 1; i++) { + end_i = ah[i].area_offset + ah[i].area_size; + for (j = i+1; (j < fmh->fmap_nareas && + ah[j].area_offset + ah[j].area_size <= end_i && + /* Don't double-indent identical blocks. */ + !(ah[i].area_offset == ah[j].area_offset && + ah[i].area_size == ah[j].area_size)); j++) + ah[j].area_flags++; + } + + /* Rearrange nested blocks */ + for (i = 0; i < fmh->fmap_nareas - 1; i++) { + tmp = ah[i]; + for (j = i+1; (j < fmh->fmap_nareas && + tmp.area_flags < ah[j].area_flags); j++) + ah[j-1] = ah[j]; + ah[j-1] = tmp; + } + + /* Print the results. */ + printf("%-20s %8s %8s %6s\n", "# name", "start", "end", "size"); + for (i = fmh->fmap_nareas - 1; i>= 0; i--) { + for (j = 0; j < ah[i].area_flags; j++) + printf(" "); + printf("%-*s", 20 - ah[i].area_flags * 2, ah[i].area_name); + printf(" %*s%0*x", ah[i].area_flags, "", + 8 - ah[i].area_flags, ah[i].area_offset); + printf(" %*s%0*x", ah[i].area_flags, "", + 8 - ah[i].area_flags, ah[i].area_offset + ah[i].area_size); + printf(" %6x\n", ah[i].area_size); + } + + return 0; +} + + +int main(int argc, char *argv[]) +{ int c; int errorcnt = 0; struct stat sb; int fd; - const char* fmap; + const char *fmap; int retval = 1; progname = strrchr(argv[0], '/'); @@ -120,10 +205,9 @@ int main(int argc, char* argv[]) { else progname = argv[0]; - opterr = 0; /* quiet, you */ - while ((c=getopt(argc, argv, ":xpf")) != -1) { - switch (c) - { + opterr = 0; /* quiet, you */ + while ((c = getopt(argc, argv, ":xpfh")) != -1) { + switch (c) { case 'x': opt_extract = 1; break; @@ -133,6 +217,9 @@ int main(int argc, char* argv[]) { case 'f': opt_format = FMT_FLASHROM; break; + case 'h': + opt_format = FMT_HUMAN; + break; case '?': fprintf(stderr, "%s: unrecognized switch: -%c\n", progname, optopt); @@ -151,12 +238,14 @@ int main(int argc, char* argv[]) { if (errorcnt || optind >= argc) { fprintf(stderr, - "\nUsage: %s [-x] [-p|-f] FLASHIMAGE [NAME...]\n\n" + "\nUsage: %s [-x] [-p|-f|-h] FLASHIMAGE [NAME...]\n\n" "Display (and extract with -x) the FMAP components from a BIOS image.\n" "The -p option makes the output easier to parse by scripts.\n" "The -f option emits the FMAP in the format used by flashrom.\n" "\n" "Specify one or more NAMEs to only print sections that exactly match.\n" + "\n" + "The -h option shows the whole FMAP in human-readable form.\n" "\n", progname); return 1; @@ -181,7 +270,7 @@ int main(int argc, char* argv[]) { if (FMT_NORMAL == opt_format) printf("opened %s\n", argv[optind]); - base_of_rom = mmap(0, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + base_of_rom = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); if (base_of_rom == (char*)-1) { fprintf(stderr, "%s: can't mmap %s: %s\n", progname, @@ -194,9 +283,16 @@ int main(int argc, char* argv[]) { fmap = FmapFind((char*) base_of_rom, sb.st_size); if (fmap) { - if (FMT_NORMAL == opt_format) + switch (opt_format) { + case FMT_HUMAN: + retval = human_fmap((void *)fmap); + break; + case FMT_NORMAL: printf("hit at 0x%08x\n", (uint32_t) (fmap - (char*) base_of_rom)); - retval = dump_fmap(fmap, argc-optind-1, argv+optind+1); + /* fallthrough */ + default: + retval = dump_fmap(fmap, argc-optind-1, argv+optind+1); + } } if (0 != munmap(base_of_rom, sb.st_size)) { |