Arthur Heymans has uploaded this change for review. ( https://review.coreboot.org/23203
Change subject: [WIP]Add support to get layout from a binary fmap file ......................................................................
[WIP]Add support to get layout from a binary fmap file
Already seems to mostly work, but needs to be cleaned up.
Change-Id: I0e7fad38ed79a84d41358e1f175c36d255786c12 Signed-off-by: Arthur Heymans arthur@aheymans.xyz --- M Makefile M cli_classic.c A fmap.c A fmap.h M layout.c 5 files changed, 166 insertions(+), 6 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/03/23203/1
diff --git a/Makefile b/Makefile index 3370247..64f1f1e 100644 --- a/Makefile +++ b/Makefile @@ -524,7 +524,7 @@ ############################################################################### # Library code.
-LIB_OBJS = libflashrom.o layout.o flashrom.o udelay.o programmer.o helpers.o ich_descriptors.o +LIB_OBJS = libflashrom.o layout.o flashrom.o udelay.o programmer.o helpers.o ich_descriptors.o fmap.o
############################################################################### # Frontend related stuff. diff --git a/cli_classic.c b/cli_classic.c index 527bb9f..aa0ed02 100644 --- a/cli_classic.c +++ b/cli_classic.c @@ -29,6 +29,7 @@ #include <getopt.h> #include "flash.h" #include "flashchips.h" +#include "fmap.h" #include "programmer.h" #include "libflashrom.h"
@@ -124,6 +125,7 @@ {"force", 0, NULL, 'f'}, {"layout", 1, NULL, 'l'}, {"ifd", 0, NULL, 0x0100}, + {"fmap", 1, NULL, 0x0101}, {"image", 1, NULL, 'i'}, {"list-supported", 0, NULL, 'L'}, {"list-supported-wiki", 0, NULL, 'z'}, @@ -136,6 +138,7 @@
char *filename = NULL; char *layoutfile = NULL; + char *fmapfile = NULL; #ifndef STANDALONE char *logfile = NULL; #endif /* !STANDALONE */ @@ -221,19 +224,31 @@ "more than once. Aborting.\n"); cli_classic_abort_usage(); } - if (ifd) { - fprintf(stderr, "Error: --layout and --ifd both specified. Aborting.\n"); + if (ifd || fmapfile) { + fprintf(stderr, "Error: --layout and --ifd/--fmap both specified. Aborting.\n"); cli_classic_abort_usage(); } layoutfile = strdup(optarg); break; case 0x0100: - if (layoutfile) { - fprintf(stderr, "Error: --layout and --ifd both specified. Aborting.\n"); + if (layoutfile || fmapfile) { + fprintf(stderr, "Error: --ifd and --layout/--fmap both specified. Aborting.\n"); cli_classic_abort_usage(); } ifd = 1; break; + case 0x0101: + if (fmapfile) { + fprintf(stderr, "Error: --fmap specified " + "more than once. Aborting.\n"); + cli_classic_abort_usage(); + } + if (ifd || layoutfile) { + fprintf(stderr, "Error: --fmap and --ifd/--layout both specified. Aborting.\n"); + cli_classic_abort_usage(); + } + fmapfile = strdup(optarg); + break; case 'i': tempstr = strdup(optarg); if (register_include_arg(tempstr)) { @@ -388,6 +403,10 @@ ret = 1; goto out; } + if (fmapfile && read_fmapfile(fmapfile)) { + ret = 1; + goto out; + } if (!ifd && process_include_args(get_global_layout())) { ret = 1; goto out; @@ -541,7 +560,7 @@ goto out_shutdown; }
- if (layoutfile) { + if (layoutfile || fmapfile) { layout = get_global_layout(); } else if (ifd && (flashrom_layout_read_from_ifd(&layout, fill_flash, NULL, 0) || process_include_args(layout))) { diff --git a/fmap.c b/fmap.c new file mode 100644 index 0000000..c63a1fa --- /dev/null +++ b/fmap.c @@ -0,0 +1,74 @@ +#include <ctype.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include "fmap.h" +#include "flash.h" + +int is_valid_fmap(const struct fmap *fmap) +{ + if (memcmp(fmap, FMAP_SIGNATURE, strlen(FMAP_SIGNATURE)) != 0) + return 0; + /* strings containing the magic tend to fail here */ + if (fmap->ver_major != FMAP_VER_MAJOR) + return 0; + /* a basic consistency check: flash should be larger than fmap */ + if (fmap->size < + sizeof(*fmap) + fmap->nareas * sizeof(struct fmap_area)) + return 0; + + /* fmap-alikes along binary data tend to fail on having a valid, + * null-terminated string in the name field.*/ + int i = 0; + while (i < FMAP_STRLEN) { + if (fmap->name[i] == 0) + break; + if (!isgraph(fmap->name[i])) + return 0; + if (i == FMAP_STRLEN - 1) { + /* name is specified to be null terminated single-word string + * without spaces. We did not break in the 0 test, we know it + * is a printable spaceless string but we're seeing FMAP_STRLEN + * symbols, which is one too many. + */ + return 0; + } + i++; + } + return 1; + +} + +static uint64_t to_le(const uint8_t *const dump, const size_t len) +{ + int i; + uint64_t var = 0; + for (i = 0; i < len; i++) { + var |= ((uint64_t)dump[i] & 0xff) << (8 * i); + } + return var; +} + +#define READ_LE_DUMP_INCEASE_IDX(x, dump, i, le) x = to_le(dump, sizeof(x)); \ + i += sizeof(x); if (i > len) return 1; +#define READ_MEMCPY_DUMP_INCREASE_IDX(x, dump, i, len) memcpy(x, dump, sizeof(x)); \ + i += sizeof(x); if (i > len) return 1; + +int read_fmap_from_dump(const uint8_t *const dump, const size_t len, struct fmap *fmap) +{ + int i = 0, j; + READ_MEMCPY_DUMP_INCREASE_IDX(fmap->signature, &dump[i], i, len); + fmap->ver_major = dump[i++]; + fmap->ver_minor = dump[i++]; + READ_LE_DUMP_INCEASE_IDX(fmap->base, &dump[i], i, len); + READ_LE_DUMP_INCEASE_IDX(fmap->size, &dump[i], i, len); + READ_MEMCPY_DUMP_INCREASE_IDX(fmap->name, &dump[i], i, len); + READ_LE_DUMP_INCEASE_IDX(fmap->nareas, &dump[i], i, len); + for (j = 0; j < fmap->nareas; j++) { + READ_LE_DUMP_INCEASE_IDX(fmap->areas[j].offset, &dump[i], i, len); + READ_LE_DUMP_INCEASE_IDX(fmap->areas[j].size, &dump[i], i, len); + READ_MEMCPY_DUMP_INCREASE_IDX(fmap->areas[j].name, &dump[i], i, len); + READ_LE_DUMP_INCEASE_IDX(fmap->areas[j].flags, &dump[i], i, len); + } + return 0; +} diff --git a/fmap.h b/fmap.h new file mode 100644 index 0000000..513c4f9 --- /dev/null +++ b/fmap.h @@ -0,0 +1,32 @@ +#include <inttypes.h> +//#include <compiler.h> +//#include <valstr.h> + + +#define FMAP_SIGNATURE "__FMAP__" +#define FMAP_VER_MAJOR 1 /* this header's FMAP minor version */ +#define FMAP_VER_MINOR 1 /* this header's FMAP minor version */ +#define FMAP_STRLEN 32 /* maximum length for strings, */ + +struct fmap_area { + uint32_t offset; /* offset relative to base */ + uint32_t size; /* size in bytes */ + uint8_t name[FMAP_STRLEN]; /* descriptive name */ + uint16_t flags; /* flags for this area */ +} __attribute__((packed)); + +struct fmap { + uint8_t signature[8]; /* "__FMAP__" (0x5F5F464D41505F5F) */ + uint8_t ver_major; /* major version */ + uint8_t ver_minor; /* minor version */ + uint64_t base; /* address of the firmware binary */ + uint32_t size; /* size of firmware binary in bytes */ + uint8_t name[FMAP_STRLEN]; /* name of this firmware binary */ + uint16_t nareas; /* number of areas described by + fmap_areas[] below */ + struct fmap_area areas[]; +} __attribute__((packed)); + +int is_valid_fmap(const struct fmap *fmap); +int read_fmapfile(const char *filename); +int read_fmap_from_dump(const uint8_t *const dump, const size_t len, struct fmap *fmap); diff --git a/layout.c b/layout.c index a990adc..53c2bb4 100644 --- a/layout.c +++ b/layout.c @@ -23,7 +23,9 @@ #include <stdlib.h> #include <string.h> #include <limits.h> +#include <sys/stat.h> #include "flash.h" +#include "fmap.h" #include "programmer.h" #include "layout.h"
@@ -103,6 +105,39 @@
return 0; } + +int read_fmapfile(const char *filename) +{ + int i; + FILE *fmapfile; + struct fmap fmap; + uint8_t buffer[5000]; + struct stat st; + + stat(filename, &st); + size_t size = st.st_size; + + fmapfile = fopen(filename, "r"); + + if (!fmapfile) { + msg_gerr("ERROR: Could not open layout file (%s).\n", filename); + return -1; + } + + fread(buffer, size, 1, fmapfile); + if (read_fmap_from_dump(buffer, size, &fmap)) + return -1; + + layout.num_entries = fmap.nareas; + for (i = 0; i < fmap.nareas; i++) { + layout.entries[i].start = fmap.areas[i].offset; + layout.entries[i].end = fmap.areas[i].offset + fmap.areas[i].size - 1; + layout.entries[i].included = 0; + layout.entries[i].file = NULL; + memcpy(layout.entries[i].name, fmap.areas[i].name, sizeof(layout.entries[i].name)); + } + return 0; +} #endif
/* returns the index of the entry (or a negative value if it is not found) */