blob: 1c233fda9969f160aef14a667002643343ea64ab [file] [log] [blame]
Bill Richardson60bcbe32010-09-09 14:53:56 -07001/*
Bill Richardson20807b62013-04-09 10:15:26 -07002 * Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
Bill Richardson60bcbe32010-09-09 14:53:56 -07003 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6#include <errno.h>
7#include <fcntl.h>
8#include <inttypes.h>
9#include <stdint.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <sys/mman.h>
14#include <sys/stat.h>
15#include <sys/types.h>
16#include <unistd.h>
17
Che-Liang Chiou305e9e52011-02-17 17:56:16 +080018#include "fmap.h"
Bill Richardson20807b62013-04-09 10:15:26 -070019#include "futility.h"
Che-Liang Chiou305e9e52011-02-17 17:56:16 +080020
Bill Richardson9429f882012-07-26 13:10:59 -070021enum { FMT_NORMAL, FMT_PRETTY, FMT_FLASHROM, FMT_HUMAN };
Bill Richardson77c02432011-07-29 13:05:58 -070022
Bill Richardson60bcbe32010-09-09 14:53:56 -070023/* global variables */
Bill Richardson779796f2014-09-23 11:47:40 -070024static int opt_extract;
Bill Richardson77c02432011-07-29 13:05:58 -070025static int opt_format = FMT_NORMAL;
Bill Richardson779796f2014-09-23 11:47:40 -070026static int opt_overlap;
Bill Richardson9429f882012-07-26 13:10:59 -070027static char *progname;
28static void *base_of_rom;
Bill Richardsond4621012014-07-09 23:31:13 -070029static size_t size_of_rom;
Bill Richardson779796f2014-09-23 11:47:40 -070030static int opt_gaps;
Bill Richardson60bcbe32010-09-09 14:53:56 -070031
Bill Richardson60bcbe32010-09-09 14:53:56 -070032/* Return 0 if successful */
Bill Richardsonc0777be2014-08-27 15:42:24 -070033static int dump_fmap(const FmapHeader *fmh, int argc, char *argv[])
Bill Richardson9429f882012-07-26 13:10:59 -070034{
Bill Richardson31d95c22014-08-24 22:07:17 -070035 int i, retval = 0;
36 char buf[80]; /* DWR: magic number */
Bill Richardsonc0777be2014-08-27 15:42:24 -070037 const FmapAreaHeader *ah;
38 ah = (const FmapAreaHeader *) (fmh + 1);
Bill Richardsond5aa5bd2014-09-23 13:49:14 -070039 char *extract_names[argc];
40 char *outname = 0;
41
42 if (opt_extract) {
43 /* prepare the filenames to write areas to */
44 memset(extract_names, 0, sizeof(extract_names));
45 for (i = 0; i < argc; i++) {
46 char *a = argv[i];
47 char *f = strchr(a, ':');
48 if (!f)
49 continue;
50 if (a == f || *(f+1) == '\0') {
51 fprintf(stderr,
52 "argument \"%s\" is bogus\n", a);
53 retval = 1;
54 continue;
55 }
56 *f++ = '\0';
57 extract_names[i] = f;
58 }
59 if (retval)
60 return retval;
61 }
Bill Richardson60bcbe32010-09-09 14:53:56 -070062
Bill Richardson31d95c22014-08-24 22:07:17 -070063 if (FMT_NORMAL == opt_format) {
64 snprintf(buf, FMAP_SIGNATURE_SIZE + 1, "%s",
65 fmh->fmap_signature);
66 printf("fmap_signature %s\n", buf);
67 printf("fmap_version: %d.%d\n",
68 fmh->fmap_ver_major, fmh->fmap_ver_minor);
69 printf("fmap_base: 0x%" PRIx64 "\n", fmh->fmap_base);
70 printf("fmap_size: 0x%08x (%d)\n", fmh->fmap_size,
71 fmh->fmap_size);
72 snprintf(buf, FMAP_NAMELEN + 1, "%s", fmh->fmap_name);
73 printf("fmap_name: %s\n", buf);
74 printf("fmap_nareas: %d\n", fmh->fmap_nareas);
75 }
Bill Richardson60bcbe32010-09-09 14:53:56 -070076
Bill Richardson31d95c22014-08-24 22:07:17 -070077 for (i = 0; i < fmh->fmap_nareas; i++, ah++) {
78 snprintf(buf, FMAP_NAMELEN + 1, "%s", ah->area_name);
Bill Richardsone7e8ecd2012-03-01 11:05:29 -080079
Bill Richardson31d95c22014-08-24 22:07:17 -070080 if (argc) {
81 int j, found = 0;
Bill Richardsond5aa5bd2014-09-23 13:49:14 -070082 outname = NULL;
Bill Richardson31d95c22014-08-24 22:07:17 -070083 for (j = 0; j < argc; j++)
84 if (!strcmp(argv[j], buf)) {
85 found = 1;
Bill Richardsond5aa5bd2014-09-23 13:49:14 -070086 outname = extract_names[j];
Bill Richardson31d95c22014-08-24 22:07:17 -070087 break;
88 }
Bill Richardson779796f2014-09-23 11:47:40 -070089 if (!found)
Bill Richardson31d95c22014-08-24 22:07:17 -070090 continue;
Bill Richardson31d95c22014-08-24 22:07:17 -070091 }
Bill Richardsone7e8ecd2012-03-01 11:05:29 -080092
Bill Richardson31d95c22014-08-24 22:07:17 -070093 switch (opt_format) {
94 case FMT_PRETTY:
95 printf("%s %d %d\n", buf, ah->area_offset,
96 ah->area_size);
97 break;
98 case FMT_FLASHROM:
99 if (ah->area_size)
100 printf("0x%08x:0x%08x %s\n", ah->area_offset,
101 ah->area_offset + ah->area_size - 1,
102 buf);
103 break;
104 default:
105 printf("area: %d\n", i + 1);
106 printf("area_offset: 0x%08x\n", ah->area_offset);
107 printf("area_size: 0x%08x (%d)\n", ah->area_size,
108 ah->area_size);
109 printf("area_name: %s\n", buf);
110 }
Simon Glassabd06d12013-07-15 17:03:30 -0600111
Bill Richardson31d95c22014-08-24 22:07:17 -0700112 if (opt_extract) {
113 char *s;
Bill Richardsond5aa5bd2014-09-23 13:49:14 -0700114 if (!outname) {
115 for (s = buf; *s; s++)
116 if (*s == ' ')
117 *s = '_';
118 outname = buf;
119 }
120 FILE *fp = fopen(outname, "wb");
Bill Richardson31d95c22014-08-24 22:07:17 -0700121 if (!fp) {
122 fprintf(stderr, "%s: can't open %s: %s\n",
Bill Richardsond5aa5bd2014-09-23 13:49:14 -0700123 progname, outname, strerror(errno));
Bill Richardson31d95c22014-08-24 22:07:17 -0700124 retval = 1;
125 } else if (!ah->area_size) {
126 fprintf(stderr,
127 "%s: section %s has zero size\n",
128 progname, buf);
129 } else if (ah->area_offset + ah->area_size >
130 size_of_rom) {
131 fprintf(stderr, "%s: section %s is larger"
132 " than the image\n", progname, buf);
133 retval = 1;
134 } else if (1 != fwrite(base_of_rom + ah->area_offset,
135 ah->area_size, 1, fp)) {
136 fprintf(stderr, "%s: can't write %s: %s\n",
137 progname, buf, strerror(errno));
138 retval = 1;
139 } else {
140 if (FMT_NORMAL == opt_format)
Bill Richardsond5aa5bd2014-09-23 13:49:14 -0700141 printf("saved as \"%s\"\n", outname);
Bill Richardson31d95c22014-08-24 22:07:17 -0700142 }
143 fclose(fp);
144 }
145 }
Bill Richardson60bcbe32010-09-09 14:53:56 -0700146
Bill Richardson31d95c22014-08-24 22:07:17 -0700147 return retval;
Bill Richardson60bcbe32010-09-09 14:53:56 -0700148}
149
Bill Richardsonae98bf02012-08-17 16:16:50 -0700150/****************************************************************************/
151/* Stuff for human-readable form */
152
Bill Richardson779796f2014-09-23 11:47:40 -0700153struct dup_s {
Bill Richardson31d95c22014-08-24 22:07:17 -0700154 char *name;
155 struct dup_s *next;
Bill Richardson779796f2014-09-23 11:47:40 -0700156};
Bill Richardsonae98bf02012-08-17 16:16:50 -0700157
Bill Richardson779796f2014-09-23 11:47:40 -0700158struct node_s {
Bill Richardson31d95c22014-08-24 22:07:17 -0700159 char *name;
160 uint32_t start;
161 uint32_t size;
162 uint32_t end;
163 struct node_s *parent;
164 int num_children;
165 struct node_s **child;
Bill Richardson779796f2014-09-23 11:47:40 -0700166 struct dup_s *alias;
167};
Bill Richardsonae98bf02012-08-17 16:16:50 -0700168
Bill Richardson779796f2014-09-23 11:47:40 -0700169static struct node_s *all_nodes;
Bill Richardsonae98bf02012-08-17 16:16:50 -0700170
Bill Richardson779796f2014-09-23 11:47:40 -0700171static void sort_nodes(int num, struct node_s *ary[])
Bill Richardson9429f882012-07-26 13:10:59 -0700172{
Bill Richardson31d95c22014-08-24 22:07:17 -0700173 int i, j;
Bill Richardson779796f2014-09-23 11:47:40 -0700174 struct node_s *tmp;
Bill Richardson9429f882012-07-26 13:10:59 -0700175
Bill Richardson31d95c22014-08-24 22:07:17 -0700176 /* bubble-sort is quick enough with only a few entries */
177 for (i = 0; i < num; i++) {
178 for (j = i + 1; j < num; j++) {
179 if (ary[j]->start > ary[i]->start) {
180 tmp = ary[i];
181 ary[i] = ary[j];
182 ary[j] = tmp;
183 }
184 }
185 }
Bill Richardson9429f882012-07-26 13:10:59 -0700186}
187
Bill Richardsonae98bf02012-08-17 16:16:50 -0700188static void line(int indent, char *name,
Bill Richardson31d95c22014-08-24 22:07:17 -0700189 uint32_t start, uint32_t end, uint32_t size, char *append)
Bill Richardson9429f882012-07-26 13:10:59 -0700190{
Bill Richardson31d95c22014-08-24 22:07:17 -0700191 int i;
192 for (i = 0; i < indent; i++)
193 printf(" ");
194 printf("%-25s %08x %08x %08x%s\n", name, start, end, size,
195 append ? append : "");
Bill Richardsonae98bf02012-08-17 16:16:50 -0700196}
Bill Richardson9429f882012-07-26 13:10:59 -0700197
Bill Richardsonae98bf02012-08-17 16:16:50 -0700198static int gapcount;
199static void empty(int indent, uint32_t start, uint32_t end, char *name)
200{
Bill Richardson31d95c22014-08-24 22:07:17 -0700201 char buf[80];
202 if (opt_gaps) {
203 sprintf(buf, " // gap in %s", name);
204 line(indent + 1, "", start, end, end - start, buf);
205 }
206 gapcount++;
Bill Richardsonae98bf02012-08-17 16:16:50 -0700207}
208
Bill Richardson779796f2014-09-23 11:47:40 -0700209static void show(struct node_s *p, int indent, int show_first)
Bill Richardsonae98bf02012-08-17 16:16:50 -0700210{
Bill Richardson31d95c22014-08-24 22:07:17 -0700211 int i;
Bill Richardson779796f2014-09-23 11:47:40 -0700212 struct dup_s *alias;
Bill Richardson31d95c22014-08-24 22:07:17 -0700213 if (show_first) {
214 line(indent, p->name, p->start, p->end, p->size, 0);
215 for (alias = p->alias; alias; alias = alias->next)
216 line(indent, alias->name, p->start, p->end, p->size,
217 " // DUPLICATE");
218 }
219 sort_nodes(p->num_children, p->child);
220 for (i = 0; i < p->num_children; i++) {
221 if (i == 0 && p->end != p->child[i]->end)
222 empty(indent, p->child[i]->end, p->end, p->name);
223 show(p->child[i], indent + show_first, 1);
224 if (i < p->num_children - 1
225 && p->child[i]->start != p->child[i + 1]->end)
226 empty(indent, p->child[i + 1]->end, p->child[i]->start,
227 p->name);
228 if (i == p->num_children - 1 && p->child[i]->start != p->start)
229 empty(indent, p->start, p->child[i]->start, p->name);
230 }
Bill Richardson9429f882012-07-26 13:10:59 -0700231}
232
Bill Richardsonae98bf02012-08-17 16:16:50 -0700233static int overlaps(int i, int j)
Bill Richardson9429f882012-07-26 13:10:59 -0700234{
Bill Richardson779796f2014-09-23 11:47:40 -0700235 struct node_s *a = all_nodes + i;
236 struct node_s *b = all_nodes + j;
Bill Richardson9429f882012-07-26 13:10:59 -0700237
Bill Richardson31d95c22014-08-24 22:07:17 -0700238 return ((a->start < b->start) && (b->start < a->end) &&
239 (b->start < a->end) && (a->end < b->end));
Bill Richardsonae98bf02012-08-17 16:16:50 -0700240}
Bill Richardson9429f882012-07-26 13:10:59 -0700241
Bill Richardsonae98bf02012-08-17 16:16:50 -0700242static int encloses(int i, int j)
243{
Bill Richardson779796f2014-09-23 11:47:40 -0700244 struct node_s *a = all_nodes + i;
245 struct node_s *b = all_nodes + j;
Bill Richardson9429f882012-07-26 13:10:59 -0700246
Bill Richardson31d95c22014-08-24 22:07:17 -0700247 return ((a->start <= b->start) && (a->end >= b->end));
Bill Richardsonae98bf02012-08-17 16:16:50 -0700248}
249
250static int duplicates(int i, int j)
251{
Bill Richardson779796f2014-09-23 11:47:40 -0700252 struct node_s *a = all_nodes + i;
253 struct node_s *b = all_nodes + j;
Bill Richardsonae98bf02012-08-17 16:16:50 -0700254
Bill Richardson31d95c22014-08-24 22:07:17 -0700255 return ((a->start == b->start) && (a->end == b->end));
Bill Richardsonae98bf02012-08-17 16:16:50 -0700256}
257
258static void add_dupe(int i, int j, int numnodes)
259{
Bill Richardson31d95c22014-08-24 22:07:17 -0700260 int k;
Bill Richardson779796f2014-09-23 11:47:40 -0700261 struct dup_s *alias;
Bill Richardsonae98bf02012-08-17 16:16:50 -0700262
Bill Richardson779796f2014-09-23 11:47:40 -0700263 alias = (struct dup_s *) malloc(sizeof(struct dup_s));
Bill Richardson31d95c22014-08-24 22:07:17 -0700264 alias->name = all_nodes[j].name;
265 alias->next = all_nodes[i].alias;
266 all_nodes[i].alias = alias;
267 for (k = j; k < numnodes; k++)
268 all_nodes[k] = all_nodes[k + 1];
Bill Richardsonae98bf02012-08-17 16:16:50 -0700269}
270
Bill Richardson779796f2014-09-23 11:47:40 -0700271static void add_child(struct node_s *p, int n)
Bill Richardsonae98bf02012-08-17 16:16:50 -0700272{
Bill Richardson31d95c22014-08-24 22:07:17 -0700273 int i;
274 if (p->num_children && !p->child) {
275 p->child =
Bill Richardson779796f2014-09-23 11:47:40 -0700276 (struct node_s **)calloc(p->num_children,
277 sizeof(struct node_s *));
Bill Richardson31d95c22014-08-24 22:07:17 -0700278 if (!p->child) {
279 perror("calloc failed");
280 exit(1);
281 }
282 }
283 for (i = 0; i < p->num_children; i++)
284 if (!p->child[i]) {
285 p->child[i] = all_nodes + n;
286 return;
287 }
Bill Richardsonae98bf02012-08-17 16:16:50 -0700288}
289
Bill Richardsonc0777be2014-08-27 15:42:24 -0700290static int human_fmap(const FmapHeader *fmh)
Bill Richardsonae98bf02012-08-17 16:16:50 -0700291{
Bill Richardson31d95c22014-08-24 22:07:17 -0700292 FmapAreaHeader *ah;
293 int i, j, errorcnt = 0;
294 int numnodes;
Bill Richardsonae98bf02012-08-17 16:16:50 -0700295
Bill Richardson31d95c22014-08-24 22:07:17 -0700296 ah = (FmapAreaHeader *) (fmh + 1);
Bill Richardsonae98bf02012-08-17 16:16:50 -0700297
Bill Richardson31d95c22014-08-24 22:07:17 -0700298 /* The challenge here is to generate a directed graph from the
299 * arbitrarily-ordered FMAP entries, and then to prune it until it's as
300 * simple (and deep) as possible. Overlapping regions are not allowed.
301 * Duplicate regions are okay, but may require special handling. */
Bill Richardsonae98bf02012-08-17 16:16:50 -0700302
Bill Richardson31d95c22014-08-24 22:07:17 -0700303 /* Convert the FMAP info into our format. */
304 numnodes = fmh->fmap_nareas;
Bill Richardsonae98bf02012-08-17 16:16:50 -0700305
Bill Richardson31d95c22014-08-24 22:07:17 -0700306 /* plus one for the all-enclosing "root" */
Bill Richardson779796f2014-09-23 11:47:40 -0700307 all_nodes = (struct node_s *) calloc(numnodes + 1,
308 sizeof(struct node_s));
Bill Richardson31d95c22014-08-24 22:07:17 -0700309 if (!all_nodes) {
310 perror("calloc failed");
311 exit(1);
312 }
313 for (i = 0; i < numnodes; i++) {
314 char buf[FMAP_NAMELEN + 1];
315 strncpy(buf, ah[i].area_name, FMAP_NAMELEN);
316 buf[FMAP_NAMELEN] = '\0';
Bill Richardson779796f2014-09-23 11:47:40 -0700317 all_nodes[i].name = strdup(buf);
318 if (!all_nodes[i].name) {
Bill Richardson31d95c22014-08-24 22:07:17 -0700319 perror("strdup failed");
320 exit(1);
321 }
322 all_nodes[i].start = ah[i].area_offset;
323 all_nodes[i].size = ah[i].area_size;
324 all_nodes[i].end = ah[i].area_offset + ah[i].area_size;
325 }
326 /* Now add the root node */
327 all_nodes[numnodes].name = strdup("-entire flash-");
328 all_nodes[numnodes].start = fmh->fmap_base;
329 all_nodes[numnodes].size = fmh->fmap_size;
330 all_nodes[numnodes].end = fmh->fmap_base + fmh->fmap_size;
Bill Richardsonae98bf02012-08-17 16:16:50 -0700331
Bill Richardson31d95c22014-08-24 22:07:17 -0700332 /* First, coalesce any duplicates */
333 for (i = 0; i < numnodes; i++) {
334 for (j = i + 1; j < numnodes; j++) {
335 if (duplicates(i, j)) {
336 add_dupe(i, j, numnodes);
337 numnodes--;
338 }
339 }
340 }
Bill Richardsonae98bf02012-08-17 16:16:50 -0700341
Bill Richardson31d95c22014-08-24 22:07:17 -0700342 /* Each node should have at most one parent, which is the smallest
343 * enclosing node. Duplicate nodes "enclose" each other, but if there's
344 * already a relationship in one direction, we won't create another.
345 */
346 for (i = 0; i < numnodes; i++) {
347 /* Find the smallest parent, which might be the root node. */
348 int k = numnodes;
349 for (j = 0; j < numnodes; j++) { /* full O(N^2) comparison */
350 if (i == j)
351 continue;
352 if (overlaps(i, j)) {
353 printf("ERROR: %s and %s overlap\n",
354 all_nodes[i].name, all_nodes[j].name);
355 printf(" %s: 0x%x - 0x%x\n", all_nodes[i].name,
356 all_nodes[i].start, all_nodes[i].end);
357 printf(" %s: 0x%x - 0x%x\n", all_nodes[j].name,
358 all_nodes[j].start, all_nodes[j].end);
359 if (opt_overlap < 2) {
360 printf("Use more -h args to ignore"
361 " this error\n");
362 errorcnt++;
363 }
364 continue;
365 }
366 if (encloses(j, i)
367 && all_nodes[j].size < all_nodes[k].size)
368 k = j;
369 }
370 all_nodes[i].parent = all_nodes + k;
371 }
372 if (errorcnt)
373 return 1;
Bill Richardson9429f882012-07-26 13:10:59 -0700374
Bill Richardson31d95c22014-08-24 22:07:17 -0700375 /* Force those deadbeat parents to recognize their children */
376 for (i = 0; i < numnodes; i++) /* how many */
377 if (all_nodes[i].parent)
378 all_nodes[i].parent->num_children++;
379 for (i = 0; i < numnodes; i++) /* here they are */
380 if (all_nodes[i].parent)
381 add_child(all_nodes[i].parent, i);
Bill Richardson9429f882012-07-26 13:10:59 -0700382
Bill Richardson31d95c22014-08-24 22:07:17 -0700383 /* Ready to go */
384 printf("# name start end size\n");
385 show(all_nodes + numnodes, 0, opt_gaps);
Bill Richardsonae98bf02012-08-17 16:16:50 -0700386
Bill Richardson31d95c22014-08-24 22:07:17 -0700387 if (gapcount && !opt_gaps)
388 printf("\nWARNING: unused regions found. Use -H to see them\n");
Bill Richardsonae98bf02012-08-17 16:16:50 -0700389
Bill Richardson31d95c22014-08-24 22:07:17 -0700390 return 0;
Bill Richardson9429f882012-07-26 13:10:59 -0700391}
392
Bill Richardsonae98bf02012-08-17 16:16:50 -0700393/* End of human-reable stuff */
394/****************************************************************************/
Bill Richardson9429f882012-07-26 13:10:59 -0700395
Bill Richardson31d95c22014-08-24 22:07:17 -0700396static const char usage[] =
Bill Richardson779796f2014-09-23 11:47:40 -0700397 "\nUsage: " MYNAME " %s [OPTIONS] FLASHIMAGE [NAME...]\n\n"
398 "Display (and extract) the FMAP components from a BIOS image.\n"
Bill Richardson31d95c22014-08-24 22:07:17 -0700399 "\n"
Bill Richardson779796f2014-09-23 11:47:40 -0700400 "Options:\n"
Bill Richardson1eae8732015-02-05 12:36:15 -0800401 " -x Extract the named sections from the file\n"
Bill Richardson779796f2014-09-23 11:47:40 -0700402 " -h Use a human-readable format\n"
403 " -H With -h, display any gaps\n"
Bill Richardson1eae8732015-02-05 12:36:15 -0800404 " -p Use a format easy to parse by scripts\n"
405 " -F Use the format expected by flashrom\n"
Bill Richardson31d95c22014-08-24 22:07:17 -0700406 "\n"
Bill Richardson779796f2014-09-23 11:47:40 -0700407 "Specify one or more NAMEs to dump only those sections.\n"
Bill Richardson31d95c22014-08-24 22:07:17 -0700408 "\n";
409
Bill Richardson779796f2014-09-23 11:47:40 -0700410static void print_help(const char *name)
411{
412 printf(usage, name);
413}
414
Bill Richardson20807b62013-04-09 10:15:26 -0700415static int do_dump_fmap(int argc, char *argv[])
Bill Richardson9429f882012-07-26 13:10:59 -0700416{
Bill Richardson31d95c22014-08-24 22:07:17 -0700417 int c;
418 int errorcnt = 0;
419 struct stat sb;
420 int fd;
Bill Richardsonc0777be2014-08-27 15:42:24 -0700421 const FmapHeader *fmap;
Bill Richardson31d95c22014-08-24 22:07:17 -0700422 int retval = 1;
Bill Richardson60bcbe32010-09-09 14:53:56 -0700423
Bill Richardson779796f2014-09-23 11:47:40 -0700424 progname = argv[0];
Bill Richardson60bcbe32010-09-09 14:53:56 -0700425
Bill Richardson31d95c22014-08-24 22:07:17 -0700426 opterr = 0; /* quiet, you */
Bill Richardson1eae8732015-02-05 12:36:15 -0800427 while ((c = getopt(argc, argv, ":xpFhH")) != -1) {
Bill Richardson31d95c22014-08-24 22:07:17 -0700428 switch (c) {
429 case 'x':
430 opt_extract = 1;
431 break;
432 case 'p':
433 opt_format = FMT_PRETTY;
434 break;
Bill Richardson1eae8732015-02-05 12:36:15 -0800435 case 'F':
Bill Richardson31d95c22014-08-24 22:07:17 -0700436 opt_format = FMT_FLASHROM;
437 break;
438 case 'H':
439 opt_gaps = 1;
440 /* fallthrough */
441 case 'h':
442 opt_format = FMT_HUMAN;
443 opt_overlap++;
444 break;
445 case '?':
446 fprintf(stderr, "%s: unrecognized switch: -%c\n",
447 progname, optopt);
448 errorcnt++;
449 break;
450 case ':':
451 fprintf(stderr, "%s: missing argument to -%c\n",
452 progname, optopt);
453 errorcnt++;
454 break;
455 default:
456 errorcnt++;
457 break;
458 }
459 }
Bill Richardson60bcbe32010-09-09 14:53:56 -0700460
Bill Richardson31d95c22014-08-24 22:07:17 -0700461 if (errorcnt || optind >= argc) {
Bill Richardson779796f2014-09-23 11:47:40 -0700462 print_help(progname);
Bill Richardson31d95c22014-08-24 22:07:17 -0700463 return 1;
464 }
Bill Richardson60bcbe32010-09-09 14:53:56 -0700465
Bill Richardson31d95c22014-08-24 22:07:17 -0700466 if (0 != stat(argv[optind], &sb)) {
467 fprintf(stderr, "%s: can't stat %s: %s\n",
468 progname, argv[optind], strerror(errno));
469 return 1;
470 }
Bill Richardson60bcbe32010-09-09 14:53:56 -0700471
Bill Richardson31d95c22014-08-24 22:07:17 -0700472 fd = open(argv[optind], O_RDONLY);
473 if (fd < 0) {
474 fprintf(stderr, "%s: can't open %s: %s\n",
475 progname, argv[optind], strerror(errno));
476 return 1;
477 }
Bill Richardson60bcbe32010-09-09 14:53:56 -0700478
Bill Richardson31d95c22014-08-24 22:07:17 -0700479 base_of_rom =
480 mmap(0, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
481 if (base_of_rom == (char *)-1) {
482 fprintf(stderr, "%s: can't mmap %s: %s\n",
483 progname, argv[optind], strerror(errno));
484 close(fd);
485 return 1;
486 }
487 close(fd); /* done with this now */
488 size_of_rom = sb.st_size;
Bill Richardson60bcbe32010-09-09 14:53:56 -0700489
Bill Richardsonc0777be2014-08-27 15:42:24 -0700490 fmap = fmap_find(base_of_rom, size_of_rom);
Bill Richardson31d95c22014-08-24 22:07:17 -0700491 if (fmap) {
492 switch (opt_format) {
493 case FMT_HUMAN:
Bill Richardsonc0777be2014-08-27 15:42:24 -0700494 retval = human_fmap(fmap);
Bill Richardson31d95c22014-08-24 22:07:17 -0700495 break;
496 case FMT_NORMAL:
497 printf("hit at 0x%08x\n",
Bill Richardsonc0777be2014-08-27 15:42:24 -0700498 (uint32_t) ((char *)fmap - (char *)base_of_rom));
Bill Richardson31d95c22014-08-24 22:07:17 -0700499 /* fallthrough */
500 default:
501 retval =
502 dump_fmap(fmap, argc - optind - 1,
503 argv + optind + 1);
504 }
505 }
Bill Richardson60bcbe32010-09-09 14:53:56 -0700506
Bill Richardson31d95c22014-08-24 22:07:17 -0700507 if (0 != munmap(base_of_rom, sb.st_size)) {
508 fprintf(stderr, "%s: can't munmap %s: %s\n",
509 progname, argv[optind], strerror(errno));
510 return 1;
511 }
Bill Richardson60bcbe32010-09-09 14:53:56 -0700512
Bill Richardson31d95c22014-08-24 22:07:17 -0700513 return retval;
Bill Richardson60bcbe32010-09-09 14:53:56 -0700514}
Bill Richardson20807b62013-04-09 10:15:26 -0700515
516DECLARE_FUTIL_COMMAND(dump_fmap, do_dump_fmap,
Bill Richardson1eae8732015-02-05 12:36:15 -0800517 VBOOT_VERSION_ALL,
Bill Richardson779796f2014-09-23 11:47:40 -0700518 "Display FMAP contents from a firmware image",
519 print_help);