David Hendricks has uploaded this change for review. ( https://review.coreboot.org/27480
Change subject: Add ability to read fmap from ROM ......................................................................
Add ability to read fmap from ROM
This adds logic to search the ROM for the flashmap.
It also changes the fmap-related CLI options so that --fmap will cause flashrom to search the ROM for the fmap, while --fmap-file <filename> will look in <filename>.
Signed-off-by: David Hendricks dhendricks@fb.com Change-Id: I83119528afeef7a864e7b774b7b7d60cb9750bb4 --- M cli_classic.c M fmap.c M fmap.h M libflashrom.c 4 files changed, 139 insertions(+), 29 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/80/27480/1
diff --git a/cli_classic.c b/cli_classic.c index 4b1999f..9d9f3e1 100644 --- a/cli_classic.c +++ b/cli_classic.c @@ -99,7 +99,7 @@ struct flashctx *fill_flash; const char *name; int namelen, opt, i, j; - int startchip = -1, chipcount = 0, option_index = 0, force = 0, ifd = 0; + int startchip = -1, chipcount = 0, option_index = 0, force = 0, ifd = 0, fmap = 0; #if CONFIG_PRINT_WIKI == 1 int list_supported_wiki = 0; #endif @@ -109,7 +109,8 @@ enum programmer prog = PROGRAMMER_INVALID; enum { OPTION_IFD = 0x0100, - OPTION_FMAP = 0x0101, + OPTION_FMAP, + OPTION_FMAP_FILE, OPTION_FLASH_CONTENTS, }; int ret = 0; @@ -127,7 +128,8 @@ {"force", 0, NULL, 'f'}, {"layout", 1, NULL, 'l'}, {"ifd", 0, NULL, OPTION_IFD}, - {"fmap", 1, NULL, OPTION_FMAP}, + {"fmap", 0, NULL, OPTION_FMAP}, + {"fmap-file", 1, NULL, OPTION_FMAP_FILE}, {"image", 1, NULL, 'i'}, {"flash-contents", 1, NULL, OPTION_FLASH_CONTENTS}, {"list-supported", 0, NULL, 'L'}, @@ -244,9 +246,13 @@ } ifd = 1; break; + case OPTION_FMAP_FILE: + if (optarg) + fmapfile = strdup(optarg); + /* fall through */ case OPTION_FMAP: if (fmapfile) { - fprintf(stderr, "Error: --fmap specified " + fprintf(stderr, "Error: --fmap or --fmap-file specified " "more than once. Aborting.\n"); cli_classic_abort_usage(); } @@ -254,7 +260,7 @@ fprintf(stderr, "Error: --fmap and --ifd both specified. Aborting.\n"); cli_classic_abort_usage(); } - fmapfile = strdup(optarg); + fmap = 1; break; case 'i': tempstr = strdup(optarg); @@ -420,7 +426,7 @@ goto out; }
- if (!ifd && !fmapfile && process_include_args(get_global_layout())) { + if (!ifd && !fmap && process_include_args(get_global_layout())) { ret = 1; goto out; } @@ -579,7 +585,7 @@ process_include_args(layout))) { ret = 1; goto out_shutdown; - } else if (fmapfile && (flashrom_layout_read_from_fmap(&layout, fill_flash, fmapfile) || + } else if (fmap && (flashrom_layout_read_from_fmap(&layout, fill_flash, fmapfile) || process_include_args(layout))) { ret = 1; goto out_shutdown; diff --git a/fmap.c b/fmap.c index d915d2d..992ae44 100644 --- a/fmap.c +++ b/fmap.c @@ -5,7 +5,7 @@ #include "fmap.h" #include "flash.h"
-static int is_valid_fmap(const struct fmap *fmap) +int is_valid_fmap(const struct fmap *fmap) { if (memcmp(fmap, FMAP_SIGNATURE, strlen(FMAP_SIGNATURE)) != 0) return 0; diff --git a/fmap.h b/fmap.h index ee4c16f..fa6ace2 100644 --- a/fmap.h +++ b/fmap.h @@ -25,4 +25,5 @@ struct fmap_area areas[]; } __attribute__((packed));
+int is_valid_fmap(const struct fmap *fmap); long int fmap_find(const uint8_t *image, unsigned int image_len); diff --git a/libflashrom.c b/libflashrom.c index 28e1999..ba04135 100644 --- a/libflashrom.c +++ b/libflashrom.c @@ -384,22 +384,9 @@ #endif }
-/** - * @brief Read a layout from flashmap (fmap) from a file. - * - * @param[out] layout Points to a struct flashrom_layout pointer that - * gets set if the fmap is read and parsed successfully. - * @param[in] flashctx Flash context - * - * @return 0 on success, - * 3 if the fmap in file couldn't be parsed, - * 2 if the fmap in file couldn't be read, - * 1 on any other error. - */ -int flashrom_layout_read_from_fmap(struct flashrom_layout **const layout, struct flashctx *const flashctx, - const char *filename) +static int read_fmap_from_file(struct fmap **fmap_out, const char *filename) { - int i; + int ret = 0; FILE *fmapfile; struct stat st;
@@ -408,24 +395,141 @@ uint8_t *buff = malloc(filesize);
fmapfile = fopen(filename, "r"); - if (!fmapfile) { msg_gerr("ERROR: Could not open fmap file (%s).\n", filename); - return 1; + ret = 1; + goto out; }
if (!fread(buff, filesize, 1, fmapfile)) { msg_gerr("ERROR: Cannot read fmap file (%s).\n", filename); - return 1; + ret = 1; + goto out; }
unsigned long int offset = fmap_find(buff, filesize); if (offset < 0) { msg_gerr("ERROR: Invalid fmap file (%s).\n", filename); - return 2; + ret = 2; + goto out; }
const struct fmap *fmap = (const struct fmap *)(buff + offset); + size_t len = sizeof(struct fmap) + sizeof(struct fmap_area) * fmap->nareas; + *fmap_out = malloc(len); + if (!fmap_out) { + msg_gerr("Out of memory.\n"); + ret = 1; + goto out; + } + memcpy(*fmap_out, fmap, len); + +out: + (void)fclose(fmapfile); + return ret; +} + +static int read_fmap_from_chip(struct fmap **fmap_out, struct flashctx *const flashctx) +{ + size_t stride, fmap_len = 0; + int ret = 1; + struct fmap *fmap; + unsigned int chip_size = flashctx->chip->total_size * 1024; + uint8_t signature[strlen(FMAP_SIGNATURE)]; + + if (!flashctx || !flashctx->chip) + return 1; + + if (prepare_flash_access(flashctx, true, false, false, false)) + return 1; + + /* FIXME: This duplicates the logic in fmap_bsearch(). We should + * refactor that function to be more generic. */ + for (stride = chip_size / 2; stride >= 16; stride /= 2) { + int fmap_found = 0; + unsigned int offset; + + for (offset = 0; + offset < chip_size - sizeof(struct fmap); + offset += stride) { + if ((offset % (stride * 2) == 0) && (offset != 0)) + continue; + + if (flashctx->chip->read(flashctx, signature, offset, strlen(FMAP_SIGNATURE))) { + msg_cerr("Cannot read %zu bytes at offset %u\n", strlen(FMAP_SIGNATURE), offset); + break; + } + + if (memcmp(signature, FMAP_SIGNATURE, strlen(FMAP_SIGNATURE)) != 0) + continue; + + if (chip_size - offset < sizeof(struct fmap)) { + msg_gerr("Flashmap is truncated, aborting.\n"); + ret = 2; + break; + } + + fmap = malloc(sizeof(struct fmap)); + if (flashctx->chip->read(flashctx, (uint8_t *)fmap, offset, sizeof(*fmap))) { + msg_cerr("Cannot read %zu bytes at offset %06x\n", sizeof(*fmap), offset); + break; + } + + fmap_len = sizeof(struct fmap) + sizeof(struct fmap_area) * fmap->nareas; + fmap = realloc(fmap, fmap_len); + + if (flashctx->chip->read(flashctx, (uint8_t *)fmap, offset, fmap_len)) { + msg_cerr("Cannot read %zu bytes at offset %06x\n", fmap_len, offset); + break; + } + + if (is_valid_fmap(fmap)) { + fmap_found = 1; + *fmap_out = fmap; + ret = 0; + msg_gdbg("Flashmap found at offset 0x%06x\n", offset); + } else { + ret = 2; + msg_gdbg("Flashmap is invalid.\n"); + } + break; + } + + if (fmap_found) + break; + } + + return ret; +} + +/** + * @brief Read a layout from flashmap (fmap) from a file. + * + * @param[out] layout Points to a struct flashrom_layout pointer that + * gets set if the fmap is read and parsed successfully. + * @param[in] flashctx Flash context + * @param[in] filename (Optional) Name of file containing flashmap. If NULL, + * flashmap will be read from contents on chip. + * + * @return 0 on success, + * 2 if the fmap couldn't be read, + * 1 on any other error. + */ +int flashrom_layout_read_from_fmap(struct flashrom_layout **const layout, struct flashctx *const flashctx, + const char *filename) +{ + int i, ret; + struct fmap *fmap = NULL; + + if (filename) { + msg_gdbg("Attempting to read fmap from file %s.\n", filename); + ret = read_fmap_from_file(&fmap, filename); + } else { + msg_gdbg("Attempting to read fmap from ROM content.\n"); + ret = read_fmap_from_chip(&fmap, flashctx); + } + if (ret) + return ret;
struct flashrom_layout *l = get_global_layout(); for (i = 0; i < fmap->nareas; i++) { @@ -441,8 +545,7 @@ l->num_entries++; }
- free(buff); - (void)fclose(fmapfile); + free(fmap); *layout = l; return 0; }