layout.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910
  1. /*
  2. * This file is part of the flashrom project.
  3. *
  4. * Copyright (C) 2005-2008 coresystems GmbH
  5. * (Written by Stefan Reinauer <stepan@coresystems.de> for coresystems GmbH)
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; version 2 of the License.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  19. */
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22. #include <string.h>
  23. #include <ctype.h>
  24. #include <limits.h>
  25. #include <errno.h>
  26. #include <sys/stat.h>
  27. #include "flash.h"
  28. #include "fdtmap.h"
  29. #include "fmap.h"
  30. #include "libfdt.h"
  31. #include "layout.h"
  32. #include "programmer.h"
  33. #include "search.h"
  34. #if CONFIG_INTERNAL == 1
  35. char *mainboard_vendor = NULL;
  36. char *mainboard_part = NULL;
  37. #endif
  38. static int romimages = 0;
  39. #define MAX_ROMLAYOUT 64
  40. /*
  41. * include_args lists arguments specified at the command line with -i. They
  42. * must be processed at some point so that desired regions are marked as
  43. * "included" in the master rom_entries list.
  44. */
  45. static char *include_args[MAX_ROMLAYOUT];
  46. static int num_include_args = 0; /* the number of valid entries. */
  47. static romlayout_t rom_entries[MAX_ROMLAYOUT];
  48. #if CONFIG_INTERNAL == 1 /* FIXME: Move the whole block to cbtable.c? */
  49. static char *def_name = "DEFAULT";
  50. /* Return TRUE if user specifies any -i argument. */
  51. int specified_partition() {
  52. return num_include_args != 0;
  53. }
  54. int show_id(uint8_t *bios, int size, int force)
  55. {
  56. unsigned int *walk;
  57. unsigned int mb_part_offset, mb_vendor_offset;
  58. char *mb_part, *mb_vendor;
  59. mainboard_vendor = def_name;
  60. mainboard_part = def_name;
  61. walk = (unsigned int *)(bios + size - 0x10);
  62. walk--;
  63. if ((*walk) == 0 || ((*walk) & 0x3ff) != 0) {
  64. /* We might have an NVIDIA chipset BIOS which stores the ID
  65. * information at a different location.
  66. */
  67. walk = (unsigned int *)(bios + size - 0x80);
  68. walk--;
  69. }
  70. /*
  71. * Check if coreboot last image size is 0 or not a multiple of 1k or
  72. * bigger than the chip or if the pointers to vendor ID or mainboard ID
  73. * are outside the image of if the start of ID strings are nonsensical
  74. * (nonprintable and not \0).
  75. */
  76. mb_part_offset = *(walk - 1);
  77. mb_vendor_offset = *(walk - 2);
  78. if ((*walk) == 0 || ((*walk) & 0x3ff) != 0 || (*walk) > size ||
  79. mb_part_offset > size || mb_vendor_offset > size) {
  80. msg_pdbg("Flash image seems to be a legacy BIOS. "
  81. "Disabling coreboot-related checks.\n");
  82. return 0;
  83. }
  84. mb_part = (char *)(bios + size - mb_part_offset);
  85. mb_vendor = (char *)(bios + size - mb_vendor_offset);
  86. if (!isprint((unsigned char)*mb_part) ||
  87. !isprint((unsigned char)*mb_vendor)) {
  88. msg_pdbg("Flash image seems to have garbage in the ID location."
  89. " Disabling checks.\n");
  90. return 0;
  91. }
  92. msg_pdbg("coreboot last image size "
  93. "(not ROM size) is %d bytes.\n", *walk);
  94. mainboard_part = strdup(mb_part);
  95. mainboard_vendor = strdup(mb_vendor);
  96. msg_pdbg("Manufacturer: %s\n", mainboard_vendor);
  97. msg_pdbg("Mainboard ID: %s\n", mainboard_part);
  98. /*
  99. * If lb_vendor is not set, the coreboot table was
  100. * not found. Nor was -p internal:mainboard=VENDOR:PART specified.
  101. */
  102. if (!lb_vendor || !lb_part) {
  103. msg_pdbg("Note: If the following flash access fails, try"
  104. "-p internal:mainboard= <vendor>:<mainboard>.\n");
  105. return 0;
  106. }
  107. /* These comparisons are case insensitive to make things
  108. * a little less user error prone.
  109. */
  110. if (!strcasecmp(mainboard_vendor, lb_vendor) &&
  111. !strcasecmp(mainboard_part, lb_part)) {
  112. msg_pdbg("This firmware image matches this mainboard.\n");
  113. } else {
  114. if (force_boardmismatch) {
  115. msg_pinfo("WARNING: This firmware image does not "
  116. "seem to fit to this machine - forcing it.\n");
  117. } else {
  118. msg_pinfo("ERROR: Your firmware image (%s:%s) does not "
  119. "appear to\n"
  120. " be correct for the detected "
  121. "mainboard (%s:%s)\n\n"
  122. "Override with -p internal:boardmismatch="
  123. "force to ignore the board name in the\n"
  124. "firmware image or override the detected "
  125. "mainboard with\n"
  126. "-p internal:mainboard=<vendor>:<mainboard>."
  127. "\n\n",
  128. mainboard_vendor, mainboard_part, lb_vendor,
  129. lb_part);
  130. exit(1);
  131. }
  132. }
  133. return 0;
  134. }
  135. #endif
  136. #ifndef __LIBPAYLOAD__
  137. int read_romlayout(char *name)
  138. {
  139. FILE *romlayout;
  140. char tempstr[256];
  141. int i;
  142. romlayout = fopen(name, "r");
  143. if (!romlayout) {
  144. msg_gerr("ERROR: Could not open ROM layout (%s).\n",
  145. name);
  146. return -1;
  147. }
  148. while (!feof(romlayout)) {
  149. char *tstr1, *tstr2;
  150. if (romimages >= MAX_ROMLAYOUT) {
  151. msg_gerr("Maximum number of ROM images (%i) in layout "
  152. "file reached before end of layout file.\n",
  153. MAX_ROMLAYOUT);
  154. msg_gerr("Ignoring the rest of the layout file.\n");
  155. break;
  156. }
  157. if (2 != fscanf(romlayout, "%255s %255s\n", tempstr, rom_entries[romimages].name))
  158. continue;
  159. #if 0
  160. // fscanf does not like arbitrary comments like that :( later
  161. if (tempstr[0] == '#') {
  162. continue;
  163. }
  164. #endif
  165. tstr1 = strtok(tempstr, ":");
  166. tstr2 = strtok(NULL, ":");
  167. if (!tstr1 || !tstr2) {
  168. msg_gerr("Error parsing layout file.\n");
  169. fclose(romlayout);
  170. return 1;
  171. }
  172. rom_entries[romimages].start = strtol(tstr1, (char **)NULL, 16);
  173. rom_entries[romimages].end = strtol(tstr2, (char **)NULL, 16);
  174. rom_entries[romimages].included = 0;
  175. strcpy(rom_entries[romimages].file, "");
  176. romimages++;
  177. }
  178. for (i = 0; i < romimages; i++) {
  179. msg_gdbg("romlayout %08x - %08x named %s\n",
  180. rom_entries[i].start,
  181. rom_entries[i].end, rom_entries[i].name);
  182. }
  183. fclose(romlayout);
  184. return 0;
  185. }
  186. #endif
  187. /*
  188. * Invoke crossystem and parse the returned string to produce an offset
  189. * @search: Search information
  190. * @offset: Place to put offset
  191. * @return 0 if offset found, -1 if not
  192. */
  193. static int get_crossystem_fmap_base(struct search_info *search, off_t *offset)
  194. {
  195. char cmd[] = "crossystem fmap_base";
  196. FILE *fp;
  197. int n;
  198. char buf[16];
  199. unsigned long fmap_base;
  200. unsigned long from_top;
  201. if (!(fp = popen(cmd, "r")))
  202. return -1;
  203. n = fread(buf, 1, sizeof(buf) - 1, fp);
  204. fclose(fp);
  205. if (n < 0)
  206. return -1;
  207. buf[n] = '\0';
  208. if (strlen(buf) == 0)
  209. return -1;
  210. /*
  211. * There are 2 kinds of fmap_base returned from crossystem.
  212. *
  213. * 1. Shadow ROM/BIOS area (x86), such as 0xFFxxxxxx.
  214. * 2. Offset to start of flash, such as 0x00xxxxxx.
  215. *
  216. * The shadow ROM is a cached copy of the BIOS ROM which resides below
  217. * 4GB host/CPU memory address space on x86. The top of BIOS address
  218. * aligns to the last byte of address space, 0xFFFFFFFF. So to obtain
  219. * the ROM offset when shadow ROM is used, we subtract the fmap_base
  220. * from 4G minus 1.
  221. *
  222. * CPU address flash address
  223. * space p space
  224. * 0xFFFFFFFF +-------+ --- +-------+ 0x400000
  225. * | | ^ | | ^
  226. * | 4MB | | | | | from_top
  227. * | | v | | v
  228. * fmap_base--> | -fmap | ------|--fmap-|-- the offset we need.
  229. * ^ | | | |
  230. * | +-------+-------+-------+ 0x000000
  231. * | | |
  232. * | | |
  233. * | | |
  234. * | | |
  235. * 0x00000000 +-------+
  236. *
  237. * We'll use bit 31 to determine if the shadow BIOS area is being used.
  238. * This is sort of a hack, but allows us to perform sanity checking for
  239. * older x86-based Chrome OS platforms.
  240. */
  241. fmap_base = (unsigned long)strtoll(buf, (char **) NULL, 0);
  242. msg_gdbg("%s: fmap_base: %#lx, ROM size: 0x%x\n",
  243. __func__, fmap_base, search->flash->total_size * 1024);
  244. if (fmap_base & (1 << 31)) {
  245. from_top = 0xFFFFFFFF - fmap_base + 1;
  246. msg_gdbg("%s: fmap is located in shadow ROM, from_top: %#lx\n",
  247. __func__, from_top);
  248. if (from_top > search->flash->total_size * 1024)
  249. return -1;
  250. *offset = (search->flash->total_size * 1024) - from_top;
  251. } else {
  252. msg_gdbg("%s: fmap is located in physical ROM\n", __func__);
  253. if (fmap_base > search->flash->total_size * 1024)
  254. return -1;
  255. *offset = fmap_base;
  256. }
  257. msg_gdbg("%s: ROM offset: %#lx\n", __func__, *offset);
  258. return 0;
  259. }
  260. static int add_fmap_entries_from_buf(struct flashctx *flash,
  261. const uint8_t *buf)
  262. {
  263. struct fmap *fmap;
  264. int i;
  265. fmap = (struct fmap *)(buf);
  266. for (i = 0; i < fmap->nareas; i++) {
  267. if (romimages >= MAX_ROMLAYOUT) {
  268. msg_gerr("ROM image contains too many regions\n");
  269. return -1;
  270. }
  271. rom_entries[romimages].start = fmap->areas[i].offset;
  272. /*
  273. * Flashrom rom entries use absolute addresses. So for non-zero
  274. * length entries, we need to subtract 1 from offset + size to
  275. * determine the end address.
  276. */
  277. rom_entries[romimages].end = fmap->areas[i].offset +
  278. fmap->areas[i].size;
  279. if (fmap->areas[i].size)
  280. rom_entries[romimages].end--;
  281. memset(rom_entries[romimages].name, 0,
  282. sizeof(rom_entries[romimages].name));
  283. memcpy(rom_entries[romimages].name, fmap->areas[i].name,
  284. min(sizeof(rom_entries[romimages].name),
  285. sizeof(fmap->areas[i].name)));
  286. rom_entries[romimages].included = 0;
  287. strcpy(rom_entries[romimages].file, "");
  288. msg_gdbg("added fmap region \"%s\" (file=\"%s\") as %sincluded,"
  289. " start: 0x%08x, end: 0x%08x\n",
  290. rom_entries[romimages].name,
  291. rom_entries[romimages].file,
  292. rom_entries[romimages].included ? "" : "not ",
  293. rom_entries[romimages].start,
  294. rom_entries[romimages].end);
  295. romimages++;
  296. }
  297. return romimages;
  298. }
  299. enum found_t {
  300. FOUND_NONE,
  301. FOUND_FMAP,
  302. FOUND_FDTMAP,
  303. };
  304. /* returns the number of entries added, or <0 to indicate error */
  305. int add_fmap_entries(struct flashctx *flash)
  306. {
  307. enum found_t found = FOUND_NONE;
  308. int ret = -1;
  309. struct search_info search;
  310. union {
  311. struct fdtmap_hdr fdtmap;
  312. struct fmap fmap;
  313. } hdr;
  314. uint8_t *buf = NULL;
  315. off_t offset;
  316. search_init(&search, flash, sizeof(hdr));
  317. search.handler = get_crossystem_fmap_base;
  318. while (found == FOUND_NONE && !search_find_next(&search, &offset)) {
  319. if (search.image)
  320. memcpy(&hdr, search.image + offset, sizeof(hdr));
  321. else if (read_flash(flash, (uint8_t *)&hdr, offset,
  322. sizeof(hdr))) {
  323. msg_gdbg("[L%d] failed to read flash at offset %#lx\n",
  324. __LINE__, offset);
  325. return -1;
  326. }
  327. ret = fmap_find(flash, &hdr.fmap, offset, &buf);
  328. if (ret == 1) {
  329. found = FOUND_FMAP;
  330. }
  331. #ifdef CONFIG_FDTMAP
  332. if (ret == 0) {
  333. ret = fdtmap_find(flash, &hdr.fdtmap, offset, &buf);
  334. if (ret == 1)
  335. found = FOUND_FDTMAP;
  336. }
  337. #endif
  338. if (ret < 0)
  339. return ret;
  340. }
  341. switch (found) {
  342. #ifdef CONFIG_FDTMAP
  343. case FOUND_FDTMAP:
  344. /* It looks valid, so use it */
  345. romimages = fdtmap_add_entries_from_buf(buf, rom_entries,
  346. MAX_ROMLAYOUT);
  347. break;
  348. #endif
  349. case FOUND_FMAP:
  350. romimages = add_fmap_entries_from_buf(flash, buf);
  351. break;
  352. default:
  353. msg_gdbg("%s: no fmap present\n", __func__);
  354. }
  355. if (buf)
  356. free(buf);
  357. search_free(&search);
  358. return romimages;
  359. }
  360. int get_num_include_args(void) {
  361. return num_include_args;
  362. }
  363. /* register an include argument (-i) for later processing */
  364. int register_include_arg(char *name)
  365. {
  366. if (num_include_args >= MAX_ROMLAYOUT) {
  367. msg_gerr("too many regions included\n");
  368. return -1;
  369. }
  370. include_args[num_include_args] = name;
  371. num_include_args++;
  372. return num_include_args;
  373. }
  374. int find_romentry(char *name)
  375. {
  376. int i;
  377. char *file = NULL;
  378. char *has_colon;
  379. if (!romimages)
  380. return -1;
  381. /* -i <image>[:<file>] */
  382. has_colon = strchr(name, ':');
  383. if (strtok(name, ":")) {
  384. file = strtok(NULL, "");
  385. if (has_colon && file == NULL) {
  386. msg_gerr("Missing filename parameter in %s\n", name);
  387. return -1;
  388. }
  389. }
  390. msg_gdbg("Looking for \"%s\" (file=\"%s\")... ",
  391. name, file ? file : "<not specified>");
  392. for (i = 0; i < romimages; i++) {
  393. if (!strcmp(rom_entries[i].name, name)) {
  394. rom_entries[i].included = 1;
  395. snprintf(rom_entries[i].file,
  396. sizeof(rom_entries[i].file),
  397. "%s", file ? file : "");
  398. msg_gdbg("found.\n");
  399. return i;
  400. }
  401. }
  402. msg_gdbg("not found.\n"); // Not found. Error.
  403. return -1;
  404. }
  405. int fill_romentry(romlayout_t *entry, int n)
  406. {
  407. if (!entry)
  408. return 1;
  409. memcpy(entry, &rom_entries[n], sizeof(*entry));
  410. return 0;
  411. }
  412. /*
  413. * num_include_files - count filenames used with -i args
  414. *
  415. * This function is intended to help command syntax parser determine if
  416. * operations such as read and write require a file as an argument. This can
  417. * be used with get_num_include_args() to determine if all -i args have
  418. * filenames.
  419. *
  420. * returns number of filenames supplied with -i args
  421. */
  422. int num_include_files(void)
  423. {
  424. int i, count = 0;
  425. for (i = 0; i < get_num_include_args(); i++) {
  426. if (strchr(include_args[i], ':'))
  427. count++;
  428. }
  429. return count;
  430. }
  431. /*
  432. * process_include_args - process -i arguments
  433. *
  434. * returns 0 to indicate success, <0 to indicate failure
  435. */
  436. int process_include_args() {
  437. int i;
  438. for (i = 0; i < num_include_args; i++) {
  439. if (include_args[i]) {
  440. /* User has specified the area name, but no layout file
  441. * is loaded, and no fmap is stored in BIOS.
  442. * Return error. */
  443. if (!romimages) {
  444. msg_gerr("No layout info is available.\n");
  445. return -1;
  446. }
  447. if (find_romentry(include_args[i]) < 0) {
  448. msg_gerr("Invalid entry specified: %s\n",
  449. include_args[i]);
  450. return -1;
  451. }
  452. } else {
  453. break;
  454. }
  455. }
  456. return 0;
  457. }
  458. romlayout_t *get_next_included_romentry(unsigned int start)
  459. {
  460. int i;
  461. unsigned int best_start = UINT_MAX;
  462. romlayout_t *best_entry = NULL;
  463. romlayout_t *cur;
  464. /* First come, first serve for overlapping regions. */
  465. for (i = 0; i < romimages; i++) {
  466. cur = &rom_entries[i];
  467. if (!cur->included)
  468. continue;
  469. /* Already past the current entry? */
  470. if (start > cur->end)
  471. continue;
  472. /* Inside the current entry? */
  473. if (start >= cur->start)
  474. return cur;
  475. /* Entry begins after start. */
  476. if (best_start > cur->start) {
  477. best_start = cur->start;
  478. best_entry = cur;
  479. }
  480. }
  481. return best_entry;
  482. }
  483. /* returns boolean 1 if regions overlap, 0 otherwise */
  484. int included_regions_overlap()
  485. {
  486. int i;
  487. int overlap_detected = 0;
  488. for (i = 0; i < romimages; i++) {
  489. int j;
  490. if (!rom_entries[i].included)
  491. continue;
  492. for (j = 0; j < romimages; j++) {
  493. if (!rom_entries[j].included)
  494. continue;
  495. if (i == j)
  496. continue;
  497. if (rom_entries[i].start > rom_entries[j].end)
  498. continue;
  499. if (rom_entries[i].end < rom_entries[j].start)
  500. continue;
  501. msg_gdbg("Regions %s [0x%08x-0x%08x] and "
  502. "%s [0x%08x-0x%08x] overlap\n",
  503. rom_entries[i].name, rom_entries[i].start,
  504. rom_entries[i].end, rom_entries[j].name,
  505. rom_entries[j].start, rom_entries[j].end);
  506. overlap_detected = 1;
  507. goto out;
  508. }
  509. }
  510. out:
  511. return overlap_detected;
  512. }
  513. static int read_content_from_file(romlayout_t *entry, uint8_t *newcontents) {
  514. char *file;
  515. FILE *fp;
  516. int len;
  517. /* If file name is specified for this partition, read file
  518. * content to overwrite. */
  519. file = entry->file;
  520. len = entry->end - entry->start + 1;
  521. if (file[0]) {
  522. int numbytes;
  523. struct stat s;
  524. if (stat(file, &s) < 0) {
  525. msg_gerr("Cannot stat file %s: %s.\n",
  526. file, strerror(errno));
  527. return -1;
  528. }
  529. if (s.st_size > len) {
  530. msg_gerr("File %s is %d bytes, region %s is %d bytes.\n"
  531. , file, (int)s.st_size,
  532. entry->name, len);
  533. return -1;
  534. }
  535. if ((fp = fopen(file, "rb")) == NULL) {
  536. perror(file);
  537. return -1;
  538. }
  539. numbytes = fread(newcontents + entry->start,
  540. 1, s.st_size, fp);
  541. fclose(fp);
  542. if (numbytes == -1) {
  543. perror(file);
  544. return -1;
  545. }
  546. }
  547. return 0;
  548. }
  549. int handle_romentries(struct flashctx *flash, uint8_t *oldcontents, uint8_t *newcontents)
  550. {
  551. unsigned int start = 0;
  552. romlayout_t *entry;
  553. unsigned int size = flash->total_size * 1024;
  554. /* If no regions were specified for inclusion, assume
  555. * that the user wants to write the complete new image.
  556. */
  557. if (num_include_args == 0)
  558. return 0;
  559. /* Non-included romentries are ignored.
  560. * The union of all included romentries is used from the new image.
  561. */
  562. while (start < size) {
  563. entry = get_next_included_romentry(start);
  564. /* No more romentries for remaining region? */
  565. if (!entry) {
  566. memcpy(newcontents + start, oldcontents + start,
  567. size - start);
  568. break;
  569. }
  570. if (entry->start > size) {
  571. msg_gerr("Layout entry \"%s\" begins beyond ROM size.\n",
  572. entry->name);
  573. return 1;
  574. } else if (entry->end > (size - 1)) {
  575. msg_gerr("Layout entry \"%s\" ends beyond ROM size.\n",
  576. entry->name);
  577. return 1;
  578. }
  579. if (entry->start > entry->end) {
  580. msg_gerr("Layout entry \"%s\" has an invalid range.\n",
  581. entry->name);
  582. return 1;
  583. }
  584. /* For non-included region, copy from old content. */
  585. if (entry->start > start)
  586. memcpy(newcontents + start, oldcontents + start,
  587. entry->start - start);
  588. /* For included region, copy from file if specified. */
  589. if (read_content_from_file(entry, newcontents) < 0) return -1;
  590. /* Skip to location after current romentry. */
  591. start = entry->end + 1;
  592. /* Catch overflow. */
  593. if (!start)
  594. break;
  595. }
  596. return 0;
  597. }
  598. static int write_content_to_file(romlayout_t *entry, uint8_t *buf) {
  599. char *file;
  600. FILE *fp;
  601. int len = entry->end - entry->start + 1;
  602. file = entry->file;
  603. if (file[0]) { /* save to file if name is specified. */
  604. int numbytes;
  605. if ((fp = fopen(file, "wb")) == NULL) {
  606. perror(file);
  607. return -1;
  608. }
  609. numbytes = fwrite(buf + entry->start, 1, len, fp);
  610. fclose(fp);
  611. if (numbytes != len) {
  612. perror(file);
  613. return -1;
  614. }
  615. }
  616. return 0;
  617. }
  618. /* sets required_erase_size (global variable), returns 0 if successful */
  619. static int set_required_erase_size(struct flashctx *flash)
  620. {
  621. int i, erase_size_found = 0;
  622. /*
  623. * Find eraseable block size for read alignment.
  624. * FIXME: This assumes the smallest block erase size is useable
  625. * by erase_and_write_flash().
  626. */
  627. required_erase_size = ~0;
  628. for (i = 0; i < NUM_ERASEFUNCTIONS; i++) {
  629. struct block_eraser eraser = flash->block_erasers[i];
  630. int j;
  631. for (j = 0; j < NUM_ERASEREGIONS; j++) {
  632. unsigned int size = eraser.eraseblocks[j].size;
  633. if (size && (size < required_erase_size)) {
  634. required_erase_size = size;
  635. erase_size_found = 1;
  636. }
  637. }
  638. }
  639. /* likely an error in flashchips[] */
  640. if (!erase_size_found) {
  641. msg_cerr("%s: No usable erase size found.\n", __func__);
  642. return -1;
  643. }
  644. return 0;
  645. }
  646. /* Reads flash content specified with -i argument into *buf. */
  647. int handle_partial_read(
  648. struct flashctx *flash,
  649. uint8_t *buf,
  650. int (*read) (struct flashctx *flash, uint8_t *buf,
  651. unsigned int start, unsigned int len),
  652. int write_to_file) {
  653. int i, count = 0;
  654. /* If no regions were specified for inclusion, assume
  655. * that the user wants to read the complete image.
  656. */
  657. if (num_include_args == 0)
  658. return 0;
  659. if (set_required_erase_size(flash))
  660. return -1;
  661. for (i = 0; i < romimages; i++) {
  662. unsigned int start, len, start_align, len_align;
  663. if (!rom_entries[i].included)
  664. continue;
  665. /* round down to nearest eraseable block boundary */
  666. start_align = rom_entries[i].start % required_erase_size;
  667. start = rom_entries[i].start - start_align;
  668. /* round up to nearest eraseable block boundary */
  669. len = rom_entries[i].end - start + 1;
  670. len_align = len % required_erase_size;
  671. if (len_align)
  672. len = len + required_erase_size - len_align;
  673. if (start_align || len_align) {
  674. msg_gdbg("\n%s: Re-aligned partial read due to "
  675. "eraseable block size requirement:\n"
  676. "\trom_entries[%d].start: 0x%06x, len: 0x%06x, "
  677. "aligned start: 0x%06x, len: 0x%06x\n",
  678. __func__, i, rom_entries[i].start,
  679. rom_entries[i].end - rom_entries[i].start + 1,
  680. start, len);
  681. }
  682. if (read(flash, buf + start, start, len)) {
  683. msg_perr("flash partial read failed.");
  684. return -1;
  685. }
  686. /* If file is specified, write this partition to file. */
  687. if (write_to_file) {
  688. if (write_content_to_file(&rom_entries[i], buf) < 0)
  689. return -1;
  690. }
  691. count++;
  692. }
  693. return count;
  694. }
  695. /* Instead of verifying the whole chip, this functions only verifies those
  696. * content in specified partitions (-i).
  697. */
  698. int handle_partial_verify(
  699. struct flashctx *flash,
  700. uint8_t *buf,
  701. int (*verify) (struct flashctx *flash, uint8_t *buf,
  702. unsigned int start, unsigned int len, const char *message)) {
  703. int i;
  704. /* If no regions were specified for inclusion, assume
  705. * that the user wants to read the complete image.
  706. */
  707. if (num_include_args == 0)
  708. return 0;
  709. if (set_required_erase_size(flash))
  710. return -1;
  711. /* Walk through the table and write content to file for those included
  712. * partition. */
  713. for (i = 0; i < romimages; i++) {
  714. unsigned int start, len, start_align, len_align;
  715. if (!rom_entries[i].included)
  716. continue;
  717. /* round down to nearest eraseable block boundary */
  718. start_align = rom_entries[i].start % required_erase_size;
  719. start = rom_entries[i].start - start_align;
  720. /* round up to nearest eraseable block boundary */
  721. len = rom_entries[i].end - start + 1;
  722. len_align = len % required_erase_size;
  723. if (len_align)
  724. len = len + required_erase_size - len_align;
  725. if (start_align || len_align) {
  726. msg_gdbg("\n%s: Re-aligned partial verify due to "
  727. "eraseable block size requirement:\n"
  728. "\trom_entries[%d].start: 0x%06x, len: 0x%06x, "
  729. "aligned start: 0x%06x, len: 0x%06x\n",
  730. __func__, i, rom_entries[i].start,
  731. rom_entries[i].end -
  732. rom_entries[i].start + 1,
  733. start, len);
  734. }
  735. /* read content from flash. */
  736. if (verify(flash, buf + start, start, len, NULL)) {
  737. msg_perr("flash partial verify failed.");
  738. return -1;
  739. }
  740. }
  741. return 0;
  742. }
  743. int extract_regions(struct flashctx *flash)
  744. {
  745. unsigned long size = flash->total_size * 1024;
  746. unsigned char *buf = calloc(size, sizeof(char));
  747. int i, ret = 0;
  748. if (!buf) {
  749. msg_gerr("Memory allocation failed!\n");
  750. msg_cinfo("FAILED.\n");
  751. return 1;
  752. }
  753. msg_cinfo("Reading flash... ");
  754. if (read_flash(flash, buf, 0, size)) {
  755. msg_cerr("Read operation failed!\n");
  756. ret = 1;
  757. goto out_free;
  758. }
  759. msg_gdbg("Extracting %d images\n", romimages);
  760. for (i = 0; !ret && i < romimages; i++) {
  761. romlayout_t *region = &rom_entries[i];
  762. char fname[256];
  763. char *from, *to;
  764. unsigned long region_size;
  765. for (to = fname, from = region->name; *from; from++, to++) {
  766. if (*from == ' ')
  767. *to = '_';
  768. else
  769. *to = *from;
  770. }
  771. *to = '\0';
  772. msg_gdbg("dumping region %s to %s\n", region->name,
  773. fname);
  774. region_size = region->end - region->start + 1;
  775. ret = write_buf_to_file(buf + region->start, region_size,
  776. fname);
  777. }
  778. out_free:
  779. free(buf);
  780. if (ret)
  781. msg_cerr("FAILED.");
  782. else
  783. msg_cdbg("done.");
  784. return ret;
  785. }