David Hendricks has uploaded this change for review.

View Change

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.

Gerrit-Project: flashrom
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: I83119528afeef7a864e7b774b7b7d60cb9750bb4
Gerrit-Change-Number: 27480
Gerrit-PatchSet: 1
Gerrit-Owner: David Hendricks <david.hendricks@gmail.com>