cmd_dump_fmap.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529
  1. /*
  2. * Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
  3. * 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 <getopt.h>
  9. #include <inttypes.h>
  10. #include <stdint.h>
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include <sys/mman.h>
  15. #include <sys/stat.h>
  16. #include <sys/types.h>
  17. #include <unistd.h>
  18. #include "fmap.h"
  19. #include "futility.h"
  20. enum { FMT_NORMAL, FMT_PRETTY, FMT_FLASHROM, FMT_HUMAN };
  21. /* global variables */
  22. static int opt_extract;
  23. static int opt_format = FMT_NORMAL;
  24. static int opt_overlap;
  25. static void *base_of_rom;
  26. static size_t size_of_rom;
  27. static int opt_gaps;
  28. /* Return 0 if successful */
  29. static int normal_fmap(const FmapHeader *fmh, int argc, char *argv[])
  30. {
  31. int i, retval = 0;
  32. char buf[80]; /* DWR: magic number */
  33. const FmapAreaHeader *ah;
  34. ah = (const FmapAreaHeader *) (fmh + 1);
  35. char *extract_names[argc];
  36. char *outname = 0;
  37. memset(extract_names, 0, sizeof(extract_names));
  38. if (opt_extract) {
  39. /* prepare the filenames to write areas to */
  40. for (i = 0; i < argc; i++) {
  41. char *a = argv[i];
  42. char *f = strchr(a, ':');
  43. if (!f)
  44. continue;
  45. if (a == f || *(f+1) == '\0') {
  46. fprintf(stderr,
  47. "argument \"%s\" is bogus\n", a);
  48. retval = 1;
  49. continue;
  50. }
  51. *f++ = '\0';
  52. extract_names[i] = f;
  53. }
  54. if (retval)
  55. return retval;
  56. }
  57. if (FMT_NORMAL == opt_format) {
  58. snprintf(buf, FMAP_SIGNATURE_SIZE + 1, "%s",
  59. fmh->fmap_signature);
  60. printf("fmap_signature %s\n", buf);
  61. printf("fmap_version: %d.%d\n",
  62. fmh->fmap_ver_major, fmh->fmap_ver_minor);
  63. printf("fmap_base: 0x%" PRIx64 "\n", fmh->fmap_base);
  64. printf("fmap_size: 0x%08x (%d)\n", fmh->fmap_size,
  65. fmh->fmap_size);
  66. snprintf(buf, FMAP_NAMELEN + 1, "%s", fmh->fmap_name);
  67. printf("fmap_name: %s\n", buf);
  68. printf("fmap_nareas: %d\n", fmh->fmap_nareas);
  69. }
  70. for (i = 0; i < fmh->fmap_nareas; i++, ah++) {
  71. snprintf(buf, FMAP_NAMELEN + 1, "%s", ah->area_name);
  72. if (argc) {
  73. int j, found = 0;
  74. outname = NULL;
  75. for (j = 0; j < argc; j++)
  76. if (!strcmp(argv[j], buf)) {
  77. found = 1;
  78. outname = extract_names[j];
  79. break;
  80. }
  81. if (!found)
  82. continue;
  83. }
  84. switch (opt_format) {
  85. case FMT_PRETTY:
  86. printf("%s %d %d\n", buf, ah->area_offset,
  87. ah->area_size);
  88. break;
  89. case FMT_FLASHROM:
  90. if (ah->area_size)
  91. printf("0x%08x:0x%08x %s\n", ah->area_offset,
  92. ah->area_offset + ah->area_size - 1,
  93. buf);
  94. break;
  95. default:
  96. printf("area: %d\n", i + 1);
  97. printf("area_offset: 0x%08x\n", ah->area_offset);
  98. printf("area_size: 0x%08x (%d)\n", ah->area_size,
  99. ah->area_size);
  100. printf("area_name: %s\n", buf);
  101. }
  102. if (opt_extract) {
  103. char *s;
  104. if (!outname) {
  105. for (s = buf; *s; s++)
  106. if (*s == ' ')
  107. *s = '_';
  108. outname = buf;
  109. }
  110. FILE *fp = fopen(outname, "wb");
  111. if (!fp) {
  112. fprintf(stderr, "%s: can't open %s: %s\n",
  113. argv[0], outname, strerror(errno));
  114. retval = 1;
  115. } else if (!ah->area_size) {
  116. fprintf(stderr,
  117. "%s: section %s has zero size\n",
  118. argv[0], buf);
  119. } else if (ah->area_offset + ah->area_size >
  120. size_of_rom) {
  121. fprintf(stderr, "%s: section %s is larger"
  122. " than the image\n", argv[0], buf);
  123. retval = 1;
  124. } else if (1 != fwrite(base_of_rom + ah->area_offset,
  125. ah->area_size, 1, fp)) {
  126. fprintf(stderr, "%s: can't write %s: %s\n",
  127. argv[0], buf, strerror(errno));
  128. retval = 1;
  129. } else {
  130. if (FMT_NORMAL == opt_format)
  131. printf("saved as \"%s\"\n", outname);
  132. }
  133. if (fp)
  134. fclose(fp);
  135. }
  136. }
  137. return retval;
  138. }
  139. /****************************************************************************/
  140. /* Stuff for human-readable form */
  141. struct dup_s {
  142. char *name;
  143. struct dup_s *next;
  144. };
  145. struct node_s {
  146. char *name;
  147. uint32_t start;
  148. uint32_t size;
  149. uint32_t end;
  150. struct node_s *parent;
  151. int num_children;
  152. struct node_s **child;
  153. struct dup_s *alias;
  154. };
  155. static struct node_s *all_nodes;
  156. static void sort_nodes(int num, struct node_s *ary[])
  157. {
  158. int i, j;
  159. struct node_s *tmp;
  160. /* bubble-sort is quick enough with only a few entries */
  161. for (i = 0; i < num; i++) {
  162. for (j = i + 1; j < num; j++) {
  163. if (ary[j]->start > ary[i]->start) {
  164. tmp = ary[i];
  165. ary[i] = ary[j];
  166. ary[j] = tmp;
  167. }
  168. }
  169. }
  170. }
  171. static void line(int indent, char *name,
  172. uint32_t start, uint32_t end, uint32_t size, char *append)
  173. {
  174. int i;
  175. for (i = 0; i < indent; i++)
  176. printf(" ");
  177. printf("%-25s %08x %08x %08x%s\n", name, start, end, size,
  178. append ? append : "");
  179. }
  180. static int gapcount;
  181. static void empty(int indent, uint32_t start, uint32_t end, char *name)
  182. {
  183. char buf[80];
  184. if (opt_gaps) {
  185. sprintf(buf, " // gap in %s", name);
  186. line(indent + 1, "", start, end, end - start, buf);
  187. }
  188. gapcount++;
  189. }
  190. static void show(struct node_s *p, int indent, int show_first)
  191. {
  192. int i;
  193. struct dup_s *alias;
  194. if (show_first) {
  195. line(indent, p->name, p->start, p->end, p->size, 0);
  196. for (alias = p->alias; alias; alias = alias->next)
  197. line(indent, alias->name, p->start, p->end, p->size,
  198. " // DUPLICATE");
  199. }
  200. sort_nodes(p->num_children, p->child);
  201. for (i = 0; i < p->num_children; i++) {
  202. if (i == 0 && p->end != p->child[i]->end)
  203. empty(indent, p->child[i]->end, p->end, p->name);
  204. show(p->child[i], indent + show_first, 1);
  205. if (i < p->num_children - 1
  206. && p->child[i]->start != p->child[i + 1]->end)
  207. empty(indent, p->child[i + 1]->end, p->child[i]->start,
  208. p->name);
  209. if (i == p->num_children - 1 && p->child[i]->start != p->start)
  210. empty(indent, p->start, p->child[i]->start, p->name);
  211. }
  212. }
  213. static int overlaps(int i, int j)
  214. {
  215. struct node_s *a = all_nodes + i;
  216. struct node_s *b = all_nodes + j;
  217. return ((a->start < b->start) && (b->start < a->end) &&
  218. (b->start < a->end) && (a->end < b->end));
  219. }
  220. static int encloses(int i, int j)
  221. {
  222. struct node_s *a = all_nodes + i;
  223. struct node_s *b = all_nodes + j;
  224. return ((a->start <= b->start) && (a->end >= b->end));
  225. }
  226. static int duplicates(int i, int j)
  227. {
  228. struct node_s *a = all_nodes + i;
  229. struct node_s *b = all_nodes + j;
  230. return ((a->start == b->start) && (a->end == b->end));
  231. }
  232. static void add_dupe(int i, int j, int numnodes)
  233. {
  234. int k;
  235. struct dup_s *alias;
  236. alias = (struct dup_s *) malloc(sizeof(struct dup_s));
  237. alias->name = all_nodes[j].name;
  238. alias->next = all_nodes[i].alias;
  239. all_nodes[i].alias = alias;
  240. for (k = j; k < numnodes; k++)
  241. all_nodes[k] = all_nodes[k + 1];
  242. }
  243. static void add_child(struct node_s *p, int n)
  244. {
  245. int i;
  246. if (p->num_children && !p->child) {
  247. p->child =
  248. (struct node_s **)calloc(p->num_children,
  249. sizeof(struct node_s *));
  250. if (!p->child) {
  251. perror("calloc failed");
  252. exit(1);
  253. }
  254. }
  255. for (i = 0; i < p->num_children; i++)
  256. if (!p->child[i]) {
  257. p->child[i] = all_nodes + n;
  258. return;
  259. }
  260. }
  261. static int human_fmap(const FmapHeader *fmh)
  262. {
  263. FmapAreaHeader *ah;
  264. int i, j, errorcnt = 0;
  265. int numnodes;
  266. ah = (FmapAreaHeader *) (fmh + 1);
  267. /* The challenge here is to generate a directed graph from the
  268. * arbitrarily-ordered FMAP entries, and then to prune it until it's as
  269. * simple (and deep) as possible. Overlapping regions are not allowed.
  270. * Duplicate regions are okay, but may require special handling. */
  271. /* Convert the FMAP info into our format. */
  272. numnodes = fmh->fmap_nareas;
  273. /* plus one for the all-enclosing "root" */
  274. all_nodes = (struct node_s *) calloc(numnodes + 1,
  275. sizeof(struct node_s));
  276. if (!all_nodes) {
  277. perror("calloc failed");
  278. exit(1);
  279. }
  280. for (i = 0; i < numnodes; i++) {
  281. char buf[FMAP_NAMELEN + 1];
  282. strncpy(buf, ah[i].area_name, FMAP_NAMELEN);
  283. buf[FMAP_NAMELEN] = '\0';
  284. all_nodes[i].name = strdup(buf);
  285. if (!all_nodes[i].name) {
  286. perror("strdup failed");
  287. exit(1);
  288. }
  289. all_nodes[i].start = ah[i].area_offset;
  290. all_nodes[i].size = ah[i].area_size;
  291. all_nodes[i].end = ah[i].area_offset + ah[i].area_size;
  292. }
  293. /* Now add the root node */
  294. all_nodes[numnodes].name = strdup("-entire flash-");
  295. all_nodes[numnodes].start = fmh->fmap_base;
  296. all_nodes[numnodes].size = fmh->fmap_size;
  297. all_nodes[numnodes].end = fmh->fmap_base + fmh->fmap_size;
  298. /* First, coalesce any duplicates */
  299. for (i = 0; i < numnodes; i++) {
  300. for (j = i + 1; j < numnodes; j++) {
  301. if (duplicates(i, j)) {
  302. add_dupe(i, j, numnodes);
  303. numnodes--;
  304. }
  305. }
  306. }
  307. /* Each node should have at most one parent, which is the smallest
  308. * enclosing node. Duplicate nodes "enclose" each other, but if there's
  309. * already a relationship in one direction, we won't create another.
  310. */
  311. for (i = 0; i < numnodes; i++) {
  312. /* Find the smallest parent, which might be the root node. */
  313. int k = numnodes;
  314. for (j = 0; j < numnodes; j++) { /* full O(N^2) comparison */
  315. if (i == j)
  316. continue;
  317. if (overlaps(i, j)) {
  318. printf("ERROR: %s and %s overlap\n",
  319. all_nodes[i].name, all_nodes[j].name);
  320. printf(" %s: 0x%x - 0x%x\n", all_nodes[i].name,
  321. all_nodes[i].start, all_nodes[i].end);
  322. printf(" %s: 0x%x - 0x%x\n", all_nodes[j].name,
  323. all_nodes[j].start, all_nodes[j].end);
  324. if (opt_overlap < 2) {
  325. printf("Use more -h args to ignore"
  326. " this error\n");
  327. errorcnt++;
  328. }
  329. continue;
  330. }
  331. if (encloses(j, i)
  332. && all_nodes[j].size < all_nodes[k].size)
  333. k = j;
  334. }
  335. all_nodes[i].parent = all_nodes + k;
  336. }
  337. if (errorcnt)
  338. return 1;
  339. /* Force those deadbeat parents to recognize their children */
  340. for (i = 0; i < numnodes; i++) /* how many */
  341. if (all_nodes[i].parent)
  342. all_nodes[i].parent->num_children++;
  343. for (i = 0; i < numnodes; i++) /* here they are */
  344. if (all_nodes[i].parent)
  345. add_child(all_nodes[i].parent, i);
  346. /* Ready to go */
  347. printf("# name start end size\n");
  348. show(all_nodes + numnodes, 0, opt_gaps);
  349. if (gapcount && !opt_gaps)
  350. printf("\nWARNING: unused regions found. Use -H to see them\n");
  351. return 0;
  352. }
  353. /* End of human-reable stuff */
  354. /****************************************************************************/
  355. static const char usage[] =
  356. "\nUsage: " MYNAME " %s [OPTIONS] FLASHIMAGE [NAME...]\n\n"
  357. "Display (and extract) the FMAP components from a BIOS image.\n"
  358. "\n"
  359. "Options:\n"
  360. " -x Extract the named sections from the file\n"
  361. " -h Use a human-readable format\n"
  362. " -H With -h, display any gaps\n"
  363. " -p Use a format easy to parse by scripts\n"
  364. " -F Use the format expected by flashrom\n"
  365. "\n"
  366. "Specify one or more NAMEs to dump only those sections.\n"
  367. "\n";
  368. static void print_help(int argc, char *argv[])
  369. {
  370. printf(usage, argv[0]);
  371. }
  372. enum {
  373. OPT_HELP = 1000,
  374. };
  375. static const struct option long_opts[] = {
  376. {"help", 0, 0, OPT_HELP},
  377. {NULL, 0, 0, 0}
  378. };
  379. static int do_dump_fmap(int argc, char *argv[])
  380. {
  381. int c;
  382. int errorcnt = 0;
  383. struct stat sb;
  384. int fd;
  385. const FmapHeader *fmap;
  386. int retval = 1;
  387. opterr = 0; /* quiet, you */
  388. while ((c = getopt_long(argc, argv, ":xpFhH", long_opts, 0)) != -1) {
  389. switch (c) {
  390. case 'x':
  391. opt_extract = 1;
  392. break;
  393. case 'p':
  394. opt_format = FMT_PRETTY;
  395. break;
  396. case 'F':
  397. opt_format = FMT_FLASHROM;
  398. break;
  399. case 'H':
  400. opt_gaps = 1;
  401. /* fallthrough */
  402. case 'h':
  403. opt_format = FMT_HUMAN;
  404. opt_overlap++;
  405. break;
  406. case OPT_HELP:
  407. print_help(argc, argv);
  408. return 0;
  409. case '?':
  410. fprintf(stderr, "%s: unrecognized switch: -%c\n",
  411. argv[0], optopt);
  412. errorcnt++;
  413. break;
  414. case ':':
  415. fprintf(stderr, "%s: missing argument to -%c\n",
  416. argv[0], optopt);
  417. errorcnt++;
  418. break;
  419. default:
  420. errorcnt++;
  421. break;
  422. }
  423. }
  424. if (errorcnt || optind >= argc) {
  425. print_help(argc, argv);
  426. return 1;
  427. }
  428. fd = open(argv[optind], O_RDONLY);
  429. if (fd < 0) {
  430. fprintf(stderr, "%s: can't open %s: %s\n",
  431. argv[0], argv[optind], strerror(errno));
  432. return 1;
  433. }
  434. if (0 != fstat(fd, &sb)) {
  435. fprintf(stderr, "%s: can't stat %s: %s\n",
  436. argv[0], argv[optind], strerror(errno));
  437. close(fd);
  438. return 1;
  439. }
  440. base_of_rom =
  441. mmap(0, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
  442. if (base_of_rom == (char *)-1) {
  443. fprintf(stderr, "%s: can't mmap %s: %s\n",
  444. argv[0], argv[optind], strerror(errno));
  445. close(fd);
  446. return 1;
  447. }
  448. close(fd); /* done with this now */
  449. size_of_rom = sb.st_size;
  450. fmap = fmap_find(base_of_rom, size_of_rom);
  451. if (fmap) {
  452. switch (opt_format) {
  453. case FMT_HUMAN:
  454. retval = human_fmap(fmap);
  455. break;
  456. case FMT_NORMAL:
  457. printf("hit at 0x%08x\n",
  458. (uint32_t) ((char *)fmap - (char *)base_of_rom));
  459. /* fallthrough */
  460. default:
  461. retval = normal_fmap(fmap,
  462. argc - optind - 1,
  463. argv + optind + 1);
  464. }
  465. }
  466. if (0 != munmap(base_of_rom, sb.st_size)) {
  467. fprintf(stderr, "%s: can't munmap %s: %s\n",
  468. argv[0], argv[optind], strerror(errno));
  469. return 1;
  470. }
  471. return retval;
  472. }
  473. DECLARE_FUTIL_COMMAND(dump_fmap, do_dump_fmap, VBOOT_VERSION_ALL,
  474. "Display FMAP contents from a firmware image");