David Hendricks has uploaded this change for review.
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;
}
To view, visit change 27480. To unsubscribe, or for help writing mail filters, visit settings.