1 /*
2 * This file is part of the flashrom project.
3 *
4 * Copyright (C) 2000 Silicon Integrated System Corporation
5 * Copyright (C) 2004 Tyan Corp <[email protected]>
6 * Copyright (C) 2005-2008 coresystems GmbH
7 * Copyright (C) 2008,2009,2010 Carl-Daniel Hailfinger
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 */
19
20 #include <errno.h>
21 #include <stdio.h>
22 #include <fcntl.h>
23 #include <sys/stat.h>
24 #include <string.h>
25 #include <stdbool.h>
26 #include <stdlib.h>
27 #include <cli_classic.h>
28 #include "flash.h"
29 #include "flashchips.h"
30 #include "fmap.h"
31 #include "programmer.h"
32
33 #include "libflashrom.h"
34
35 enum {
36 OPTION_IFD = 0x0100,
37 OPTION_FMAP,
38 OPTION_FMAP_FILE,
39 OPTION_FLASH_CONTENTS,
40 OPTION_FLASH_NAME,
41 OPTION_FLASH_SIZE,
42 OPTION_WP_STATUS,
43 OPTION_WP_SET_RANGE,
44 OPTION_WP_SET_REGION,
45 OPTION_WP_ENABLE,
46 OPTION_WP_DISABLE,
47 OPTION_WP_LIST,
48 OPTION_PROGRESS,
49 };
50
51 struct cli_options {
52 bool read_it, extract_it, write_it, erase_it, verify_it;
53 bool dont_verify_it, dont_verify_all;
54 bool list_supported;
55 #if CONFIG_PRINT_WIKI == 1
56 bool list_supported_wiki;
57 #endif
58 char *filename;
59
60 const struct programmer_entry *prog;
61 char *pparam;
62
63 bool ifd, fmap;
64 struct flashrom_layout *layout;
65 struct layout_include_args *include_args;
66 char *layoutfile;
67 char *fmapfile;
68
69 unsigned int wp_start, wp_len;
70 bool enable_wp, disable_wp, print_wp_status;
71 bool set_wp_range, set_wp_region, print_wp_ranges;
72 char *wp_region;
73
74 bool force;
75 bool flash_name, flash_size;
76 bool show_progress;
77 char *logfile;
78 char *referencefile;
79 const char *chip_to_probe;
80 };
81
cli_classic_usage(const char * name)82 static void cli_classic_usage(const char *name)
83 {
84 printf("Usage: %s [-h|-R|-L|"
85 #if CONFIG_PRINT_WIKI == 1
86 "-z|"
87 #endif
88 "\n\t-p <programmername>[:<parameters>] [-c <chipname>]\n"
89 "\t\t(--flash-name|--flash-size|\n"
90 "\t\t [-E|-x|(-r|-w|-v) [<file>]]\n"
91 "\t\t [(-l <layoutfile>|--ifd|--fmap|--fmap-file <fmapfile>) [-i <region>[:<file>]]...]\n"
92 "\t\t [-n] [-N] [-f])]\n"
93 "\t[-V[V[V]]] [-o <logfile>]\n\n", name);
94
95 printf(" -h | --help print this help text\n"
96 " -R | --version print version (release)\n"
97 " -r | --read [<file>] read flash and save to <file>\n"
98 " -w | --write [<file>|-] write <file> or the content provided\n"
99 " on the standard input to flash\n"
100 " -v | --verify [<file>|-] verify flash against <file>\n"
101 " or the content provided on the standard input\n"
102 " -E | --erase erase flash memory\n"
103 " -V | --verbose more verbose output\n"
104 " -c | --chip <chipname> probe only for specified flash chip\n"
105 " -f | --force force specific operations (see man page)\n"
106 " -n | --noverify don't auto-verify\n"
107 " -N | --noverify-all verify included regions only (cf. -i)\n"
108 " -x | --extract extract regions to files\n"
109 " -l | --layout <layoutfile> read ROM layout from <layoutfile>\n"
110 " --wp-disable disable write protection\n"
111 " --wp-enable enable write protection\n"
112 " --wp-list list supported write protection ranges\n"
113 " --wp-status show write protection status\n"
114 " --wp-range=<start>,<len> set write protection range (use --wp-range=0,0\n"
115 " to unprotect the entire flash)\n"
116 " --wp-region <region> set write protection region\n"
117 " --flash-name read out the detected flash name\n"
118 " --flash-size read out the detected flash size\n"
119 " --fmap read ROM layout from fmap embedded in ROM\n"
120 " --fmap-file <fmapfile> read ROM layout from fmap in <fmapfile>\n"
121 " --ifd read layout from an Intel Firmware Descriptor\n"
122 " -i | --include <region>[:<file>] only read/write image <region> from layout\n"
123 " (optionally with data from <file>)\n"
124 " --image <region>[:<file>] deprecated, please use --include\n"
125 " -o | --output <logfile> log output to <logfile>\n"
126 " --flash-contents <ref-file> assume flash contents to be <ref-file>\n"
127 " -L | --list-supported print supported devices\n"
128 #if CONFIG_PRINT_WIKI == 1
129 " -z | --list-supported-wiki print supported devices in wiki syntax\n"
130 #endif
131 " --progress show progress percentage on the standard output\n"
132 " -p | --programmer <name>[:<param>] specify the programmer device. One of\n");
133 list_programmers_linebreak(4, 80, 0);
134 printf(".\n\nYou can specify one of -h, -R, -L, "
135 #if CONFIG_PRINT_WIKI == 1
136 "-z, "
137 #endif
138 "-E, -r, -w, -v or no operation.\n"
139 "If no operation is specified, flashrom will only probe for flash chips.\n");
140 }
141
cli_classic_abort_usage(const char * msg)142 static void cli_classic_abort_usage(const char *msg)
143 {
144 if (msg)
145 fprintf(stderr, "%s", msg);
146 printf("Please run \"flashrom --help\" for usage info.\n");
147 exit(1);
148 }
149
cli_classic_validate_singleop(int * operation_specified)150 static void cli_classic_validate_singleop(int *operation_specified)
151 {
152 if (++(*operation_specified) > 1) {
153 cli_classic_abort_usage("More than one operation specified. Aborting.\n");
154 }
155 }
156
check_filename(char * filename,const char * type)157 static int check_filename(char *filename, const char *type)
158 {
159 if (!filename || (filename[0] == '\0')) {
160 fprintf(stderr, "Error: No %s file specified.\n", type);
161 return 1;
162 }
163 /* Not an error, but maybe the user intended to specify a CLI option instead of a file name. */
164 if (filename[0] == '-' && filename[1] != '\0')
165 fprintf(stderr, "Warning: Supplied %s file name starts with -\n", type);
166 return 0;
167 }
168
169 /* Ensure a file is open by means of fstat */
check_file(FILE * file)170 static bool check_file(FILE *file)
171 {
172 struct stat statbuf;
173
174 if (fstat(fileno(file), &statbuf) < 0)
175 return false;
176 return true;
177 }
178
parse_wp_range(unsigned int * start,unsigned int * len)179 static int parse_wp_range(unsigned int *start, unsigned int *len)
180 {
181 char *endptr = NULL, *token = NULL;
182
183 if (!optarg) {
184 msg_gerr("Error: No wp-range values provided\n");
185 return -1;
186 }
187
188 token = strtok(optarg, ",");
189 if (!token) {
190 msg_gerr("Error: Invalid wp-range argument format\n");
191 return -1;
192 }
193 *start = strtoul(token, &endptr, 0);
194
195 token = strtok(NULL, ",");
196 if (!token) {
197 msg_gerr("Error: Invalid wp-range argument format\n");
198 return -1;
199 }
200 *len = strtoul(token, &endptr, 0);
201
202 return 0;
203 }
204
print_wp_range(struct flashrom_flashctx * flash,size_t start,size_t len)205 static int print_wp_range(struct flashrom_flashctx *flash, size_t start, size_t len)
206 {
207 /* Start address and length */
208 msg_ginfo("start=0x%08zx length=0x%08zx ", start, len);
209
210 /* Easily readable description like 'none' or 'lower 1/8' */
211 size_t chip_len = flashrom_flash_getsize(flash);
212
213 if (len == 0) {
214 msg_ginfo("(none)");
215 } else if (len == chip_len) {
216 msg_ginfo("(all)");
217 } else {
218 const char *location = "";
219 if (start == 0)
220 location = "lower ";
221 if (start == chip_len - len)
222 location = "upper ";
223
224 /* Remove common factors of 2 to simplify */
225 /* the (range_len/chip_len) fraction. */
226 while ((chip_len % 2) == 0 && (len % 2) == 0) {
227 chip_len /= 2;
228 len /= 2;
229 }
230
231 msg_ginfo("(%s%zu/%zu)", location, len, chip_len);
232 }
233
234 return 0;
235 }
236
get_wp_error_str(int err)237 static const char *get_wp_error_str(int err)
238 {
239 switch (err) {
240 case FLASHROM_WP_ERR_CHIP_UNSUPPORTED:
241 return "WP operations are not implemented for this chip";
242 case FLASHROM_WP_ERR_READ_FAILED:
243 return "failed to read the current WP configuration";
244 case FLASHROM_WP_ERR_WRITE_FAILED:
245 return "failed to write the new WP configuration";
246 case FLASHROM_WP_ERR_VERIFY_FAILED:
247 return "unexpected WP configuration read back from chip";
248 case FLASHROM_WP_ERR_MODE_UNSUPPORTED:
249 return "the requested protection mode is not supported";
250 case FLASHROM_WP_ERR_RANGE_UNSUPPORTED:
251 return "the requested protection range is not supported";
252 case FLASHROM_WP_ERR_RANGE_LIST_UNAVAILABLE:
253 return "could not determine what protection ranges are available";
254 case FLASHROM_WP_ERR_UNSUPPORTED_STATE:
255 return "can't operate on current WP configuration of the chip";
256 }
257 return "unknown WP error";
258 }
259
wp_cli(struct flashctx * flash,bool enable_wp,bool disable_wp,bool print_wp_status,bool print_wp_ranges,bool set_wp_range,uint32_t wp_start,uint32_t wp_len)260 static int wp_cli(
261 struct flashctx *flash,
262 bool enable_wp,
263 bool disable_wp,
264 bool print_wp_status,
265 bool print_wp_ranges,
266 bool set_wp_range,
267 uint32_t wp_start,
268 uint32_t wp_len)
269 {
270 if (print_wp_ranges) {
271 struct flashrom_wp_ranges *list;
272 enum flashrom_wp_result ret = flashrom_wp_get_available_ranges(&list, flash);
273 if (ret != FLASHROM_WP_OK) {
274 msg_gerr("Failed to get list of protection ranges: %s\n",
275 get_wp_error_str(ret));
276 return 1;
277 }
278 size_t count = flashrom_wp_ranges_get_count(list);
279
280 msg_ginfo("Available protection ranges:\n");
281 for (size_t i = 0; i < count; i++) {
282 size_t start, len;
283
284 flashrom_wp_ranges_get_range(&start, &len, list, i);
285 msg_ginfo("\t");
286 print_wp_range(flash, start, len);
287 msg_ginfo("\n");
288 }
289
290 flashrom_wp_ranges_release(list);
291 }
292
293 if (set_wp_range || disable_wp || enable_wp) {
294 enum flashrom_wp_mode old_mode = FLASHROM_WP_MODE_DISABLED;
295 struct flashrom_wp_cfg *cfg = NULL;
296 enum flashrom_wp_result ret = flashrom_wp_cfg_new(&cfg);
297
298 if (ret == FLASHROM_WP_OK)
299 ret = flashrom_wp_read_cfg(cfg, flash);
300
301 if (ret == FLASHROM_WP_OK) {
302 /* Store current WP mode for printing help text if */
303 /* changing the cfg fails. */
304 old_mode = flashrom_wp_get_mode(cfg);
305
306 if (set_wp_range)
307 flashrom_wp_set_range(cfg, wp_start, wp_len);
308
309 if (disable_wp)
310 flashrom_wp_set_mode(cfg, FLASHROM_WP_MODE_DISABLED);
311
312 if (enable_wp)
313 flashrom_wp_set_mode(cfg, FLASHROM_WP_MODE_HARDWARE);
314
315 ret = flashrom_wp_write_cfg(flash, cfg);
316 }
317
318 flashrom_wp_cfg_release(cfg);
319
320 if (ret != FLASHROM_WP_OK) {
321 msg_gerr("Failed to apply new WP settings: %s\n",
322 get_wp_error_str(ret));
323
324 /* Warn user if active WP is likely to have caused failure */
325 if (ret == FLASHROM_WP_ERR_VERIFY_FAILED) {
326 switch (old_mode) {
327 case FLASHROM_WP_MODE_HARDWARE:
328 msg_gerr("Note: hardware status register protection is enabled. "
329 "The chip's WP# pin must be set to an inactive voltage "
330 "level to be able to change the WP settings.\n");
331 break;
332 case FLASHROM_WP_MODE_POWER_CYCLE:
333 msg_gerr("Note: power-cycle status register protection is enabled. "
334 "A power-off, power-on cycle is usually required to change "
335 "the chip's WP settings.\n");
336 break;
337 case FLASHROM_WP_MODE_PERMANENT:
338 msg_gerr("Note: permanent status register protection is enabled. "
339 "The chip's WP settings cannot be modified.\n");
340 break;
341 default:
342 break;
343 }
344 }
345
346 return 1;
347 }
348
349 if (disable_wp)
350 msg_ginfo("Disabled hardware protection\n");
351
352 if (enable_wp)
353 msg_ginfo("Enabled hardware protection\n");
354
355 if (set_wp_range) {
356 msg_ginfo("Activated protection range: ");
357 print_wp_range(flash, wp_start, wp_len);
358 msg_ginfo("\n");
359 }
360 }
361
362 if (print_wp_status) {
363 size_t start, len;
364 enum flashrom_wp_mode mode;
365 struct flashrom_wp_cfg *cfg = NULL;
366 enum flashrom_wp_result ret = flashrom_wp_cfg_new(&cfg);
367
368 if (ret == FLASHROM_WP_OK)
369 ret = flashrom_wp_read_cfg(cfg, flash);
370
371 if (ret != FLASHROM_WP_OK) {
372 msg_gerr("Failed to get WP status: %s\n",
373 get_wp_error_str(ret));
374
375 flashrom_wp_cfg_release(cfg);
376 return 1;
377 }
378
379 flashrom_wp_get_range(&start, &len, cfg);
380 mode = flashrom_wp_get_mode(cfg);
381 flashrom_wp_cfg_release(cfg);
382
383 msg_ginfo("Protection range: ");
384 print_wp_range(flash, start, len);
385 msg_ginfo("\n");
386
387 msg_ginfo("Protection mode: ");
388 switch (mode) {
389 case FLASHROM_WP_MODE_DISABLED:
390 msg_ginfo("disabled");
391 break;
392 case FLASHROM_WP_MODE_HARDWARE:
393 msg_ginfo("hardware");
394 break;
395 case FLASHROM_WP_MODE_POWER_CYCLE:
396 msg_ginfo("power_cycle");
397 break;
398 case FLASHROM_WP_MODE_PERMANENT:
399 msg_ginfo("permanent");
400 break;
401 default:
402 msg_ginfo("unknown");
403 break;
404 }
405 msg_ginfo("\n");
406 }
407
408 return 0;
409 }
410
get_optional_filename(char * argv[])411 static char *get_optional_filename(char *argv[])
412 {
413 char *filename = NULL;
414
415 /* filename was supplied in optarg (i.e. -rfilename) */
416 if (optarg != NULL)
417 filename = strdup(optarg);
418 /* filename is on optind if it is not another flag (i.e. -r filename)
419 * - is treated as stdin, so we still strdup in this case
420 */
421 else if (optarg == NULL && argv[optind] != NULL &&
422 (argv[optind][0] != '-' || argv[optind][1] == '\0'))
423 filename = strdup(argv[optind++]);
424
425 return filename;
426 }
427
flashrom_layout_read_fmap_from_file(struct flashrom_layout ** layout,struct flashrom_flashctx * flashctx,const char * fmapfile)428 static int flashrom_layout_read_fmap_from_file(struct flashrom_layout **layout,
429 struct flashrom_flashctx *flashctx, const char *fmapfile)
430 {
431 int ret = 1;
432 struct stat s;
433 if (stat(fmapfile, &s) != 0) {
434 return ret;
435 }
436
437 size_t fmapfile_size = s.st_size;
438 uint8_t *fmapfile_buffer = malloc(fmapfile_size);
439 if (!fmapfile_buffer) {
440 return ret;
441 }
442
443 if (read_buf_from_file(fmapfile_buffer, fmapfile_size, fmapfile)) {
444 goto out;
445 }
446
447 ret = flashrom_layout_read_fmap_from_buffer(layout, flashctx, fmapfile_buffer, fmapfile_size);
448 out:
449 free(fmapfile_buffer);
450 return ret;
451 }
452
453 /**
454 * @brief Reads content to buffer from one or more files.
455 *
456 * Reads content to supplied buffer from files. If a filename is specified for
457 * individual regions using the partial read syntax ('-i <region>[:<filename>]')
458 * then this will read file data into the corresponding region in the
459 * supplied buffer.
460 *
461 * @param layout The layout to be used.
462 * @param buf Chip-sized buffer to write data to
463 * @return 0 on success
464 */
read_buf_from_include_args(const struct flashrom_layout * const layout,unsigned char * buf)465 static int read_buf_from_include_args(const struct flashrom_layout *const layout, unsigned char *buf)
466 {
467 const struct romentry *entry = NULL;
468
469 /*
470 * Content will be read from -i args, so they must not overlap since
471 * we need to know exactly what content to write to the ROM.
472 */
473 if (included_regions_overlap(layout)) {
474 msg_gerr("Error: Included regions must not overlap when writing.\n");
475 return 1;
476 }
477
478 while ((entry = layout_next_included(layout, entry))) {
479 if (!entry->file)
480 continue;
481 const struct flash_region *region = &entry->region;
482 if (read_buf_from_file(buf + region->start,
483 region->end - region->start + 1, entry->file))
484 return 1;
485 }
486 return 0;
487 }
488
489 /**
490 * @brief Writes content from buffer to one or more files.
491 *
492 * Writes content from supplied buffer to files. If a filename is specified for
493 * individual regions using the partial read syntax ('-i <region>[:<filename>]')
494 * then this will write files using data from the corresponding region in the
495 * supplied buffer.
496 *
497 * @param layout The layout to be used.
498 * @param buf Chip-sized buffer to read data from
499 * @return 0 on success
500 */
write_buf_to_include_args(const struct flashrom_layout * const layout,unsigned char * buf)501 static int write_buf_to_include_args(const struct flashrom_layout *const layout, unsigned char *buf)
502 {
503 const struct romentry *entry = NULL;
504
505 while ((entry = layout_next_included(layout, entry))) {
506 if (!entry->file)
507 continue;
508 const struct flash_region *region = &entry->region;
509 if (write_buf_to_file(buf + region->start,
510 region->end - region->start + 1, entry->file))
511 return 1;
512 }
513
514 return 0;
515 }
516
do_read(struct flashctx * const flash,const char * const filename)517 static int do_read(struct flashctx *const flash, const char *const filename)
518 {
519 int ret;
520
521 unsigned long size = flashrom_flash_getsize(flash);
522 unsigned char *buf = calloc(size, sizeof(unsigned char));
523 if (!buf) {
524 msg_gerr("Memory allocation failed!\n");
525 return 1;
526 }
527
528 ret = flashrom_image_read(flash, buf, size);
529 if (ret > 0)
530 goto free_out;
531
532 if (write_buf_to_include_args(get_layout(flash), buf)) {
533 ret = 1;
534 goto free_out;
535 }
536 if (filename)
537 ret = write_buf_to_file(buf, size, filename);
538
539 free_out:
540 free(buf);
541 return ret;
542 }
543
do_extract(struct flashctx * const flash)544 static int do_extract(struct flashctx *const flash)
545 {
546 prepare_layout_for_extraction(flash);
547 return do_read(flash, NULL);
548 }
549
do_write(struct flashctx * const flash,const char * const filename,const char * const referencefile)550 static int do_write(struct flashctx *const flash, const char *const filename, const char *const referencefile)
551 {
552 const size_t flash_size = flashrom_flash_getsize(flash);
553 int ret = 1;
554
555 uint8_t *const newcontents = malloc(flash_size);
556 uint8_t *const refcontents = referencefile ? malloc(flash_size) : NULL;
557
558 if (!newcontents || (referencefile && !refcontents)) {
559 msg_gerr("Out of memory!\n");
560 goto _free_ret;
561 }
562
563 /* Read '-w' argument first... */
564 if (filename) {
565 if (read_buf_from_file(newcontents, flash_size, filename))
566 goto _free_ret;
567 }
568 /*
569 * ... then update newcontents with contents from files provided to '-i'
570 * args if needed.
571 */
572 if (read_buf_from_include_args(get_layout(flash), newcontents))
573 goto _free_ret;
574
575 if (referencefile) {
576 if (read_buf_from_file(refcontents, flash_size, referencefile))
577 goto _free_ret;
578 }
579
580 ret = flashrom_image_write(flash, newcontents, flash_size, refcontents);
581
582 _free_ret:
583 free(refcontents);
584 free(newcontents);
585 return ret;
586 }
587
do_verify(struct flashctx * const flash,const char * const filename)588 static int do_verify(struct flashctx *const flash, const char *const filename)
589 {
590 const size_t flash_size = flashrom_flash_getsize(flash);
591 int ret = 1;
592
593 uint8_t *const newcontents = malloc(flash_size);
594 if (!newcontents) {
595 msg_gerr("Out of memory!\n");
596 goto _free_ret;
597 }
598
599 /* Read '-v' argument first... */
600 if (filename) {
601 if (read_buf_from_file(newcontents, flash_size, filename))
602 goto _free_ret;
603 }
604 /*
605 * ... then update newcontents with contents from files provided to '-i'
606 * args if needed.
607 */
608 if (read_buf_from_include_args(get_layout(flash), newcontents))
609 goto _free_ret;
610
611 ret = flashrom_image_verify(flash, newcontents, flash_size);
612
613 _free_ret:
614 free(newcontents);
615 return ret;
616 }
617
618 /* Returns the number of buses commonly supported by the current programmer and flash chip where the latter
619 * can not be completely accessed due to size/address limits of the programmer. */
count_max_decode_exceedings(const struct flashctx * flash,const struct decode_sizes * max_rom_decode_)620 static unsigned int count_max_decode_exceedings(const struct flashctx *flash,
621 const struct decode_sizes *max_rom_decode_)
622 {
623 unsigned int limitexceeded = 0;
624 uint32_t size = flash->chip->total_size * 1024;
625 enum chipbustype buses = flash->mst->buses_supported & flash->chip->bustype;
626
627 if ((buses & BUS_PARALLEL) && (max_rom_decode_->parallel < size)) {
628 limitexceeded++;
629 msg_pdbg("Chip size %"PRIu32" kB is bigger than supported "
630 "size %"PRIu32" kB of chipset/board/programmer "
631 "for %s interface, "
632 "probe/read/erase/write may fail. ", size / 1024,
633 max_rom_decode_->parallel / 1024, "Parallel");
634 }
635 if ((buses & BUS_LPC) && (max_rom_decode_->lpc < size)) {
636 limitexceeded++;
637 msg_pdbg("Chip size %"PRIu32" kB is bigger than supported "
638 "size %"PRIu32" kB of chipset/board/programmer "
639 "for %s interface, "
640 "probe/read/erase/write may fail. ", size / 1024,
641 max_rom_decode_->lpc / 1024, "LPC");
642 }
643 if ((buses & BUS_FWH) && (max_rom_decode_->fwh < size)) {
644 limitexceeded++;
645 msg_pdbg("Chip size %"PRIu32" kB is bigger than supported "
646 "size %"PRIu32" kB of chipset/board/programmer "
647 "for %s interface, "
648 "probe/read/erase/write may fail. ", size / 1024,
649 max_rom_decode_->fwh / 1024, "FWH");
650 }
651 if ((buses & BUS_SPI) && (max_rom_decode_->spi < size)) {
652 limitexceeded++;
653 msg_pdbg("Chip size %"PRIu32" kB is bigger than supported "
654 "size %"PRIu32" kB of chipset/board/programmer "
655 "for %s interface, "
656 "probe/read/erase/write may fail. ", size / 1024,
657 max_rom_decode_->spi / 1024, "SPI");
658 }
659 return limitexceeded;
660 }
661
parse_options(int argc,char ** argv,const char * optstring,const struct option * long_options,struct cli_options * options)662 static void parse_options(int argc, char **argv, const char *optstring,
663 const struct option *long_options,
664 struct cli_options *options)
665 {
666 const char *name;
667 int namelen, opt;
668 int option_index = 0, operation_specified = 0;
669
670 /* FIXME: Delay all operation_specified checks until after command
671 * line parsing to allow --help overriding everything else.
672 */
673 while ((opt = getopt_long(argc, argv, optstring,
674 long_options, &option_index)) != EOF) {
675 switch (opt) {
676 case 'r':
677 cli_classic_validate_singleop(&operation_specified);
678 options->filename = get_optional_filename(argv);
679 options->read_it = true;
680 break;
681 case 'w':
682 cli_classic_validate_singleop(&operation_specified);
683 options->filename = get_optional_filename(argv);
684 options->write_it = true;
685 break;
686 case 'v':
687 //FIXME: gracefully handle superfluous -v
688 cli_classic_validate_singleop(&operation_specified);
689 if (options->dont_verify_it) {
690 cli_classic_abort_usage("--verify and --noverify are mutually exclusive. Aborting.\n");
691 }
692 options->filename = get_optional_filename(argv);
693 options->verify_it = true;
694 break;
695 case 'n':
696 if (options->verify_it) {
697 cli_classic_abort_usage("--verify and --noverify are mutually exclusive. Aborting.\n");
698 }
699 options->dont_verify_it = true;
700 break;
701 case 'N':
702 options->dont_verify_all = true;
703 break;
704 case 'x':
705 cli_classic_validate_singleop(&operation_specified);
706 options->extract_it = true;
707 break;
708 case 'c':
709 options->chip_to_probe = strdup(optarg);
710 break;
711 case 'V':
712 verbose_screen++;
713 if (verbose_screen > FLASHROM_MSG_DEBUG2)
714 verbose_logfile = verbose_screen;
715 break;
716 case 'E':
717 cli_classic_validate_singleop(&operation_specified);
718 options->erase_it = true;
719 break;
720 case 'f':
721 options->force = true;
722 break;
723 case 'l':
724 if (options->layoutfile)
725 cli_classic_abort_usage("Error: --layout specified more than once. Aborting.\n");
726 if (options->ifd)
727 cli_classic_abort_usage("Error: --layout and --ifd both specified. Aborting.\n");
728 if (options->fmap)
729 cli_classic_abort_usage("Error: --layout and --fmap-file both specified. Aborting.\n");
730 options->layoutfile = strdup(optarg);
731 break;
732 case OPTION_IFD:
733 if (options->layoutfile)
734 cli_classic_abort_usage("Error: --layout and --ifd both specified. Aborting.\n");
735 if (options->fmap)
736 cli_classic_abort_usage("Error: --fmap-file and --ifd both specified. Aborting.\n");
737 options->ifd = true;
738 break;
739 case OPTION_FMAP_FILE:
740 if (options->fmap)
741 cli_classic_abort_usage("Error: --fmap or --fmap-file specified "
742 "more than once. Aborting.\n");
743 if (options->ifd)
744 cli_classic_abort_usage("Error: --fmap-file and --ifd both specified. Aborting.\n");
745 if (options->layoutfile)
746 cli_classic_abort_usage("Error: --fmap-file and --layout both specified. Aborting.\n");
747 options->fmapfile = strdup(optarg);
748 options->fmap = true;
749 break;
750 case OPTION_FMAP:
751 if (options->fmap)
752 cli_classic_abort_usage("Error: --fmap or --fmap-file specified "
753 "more than once. Aborting.\n");
754 if (options->ifd)
755 cli_classic_abort_usage("Error: --fmap and --ifd both specified. Aborting.\n");
756 if (options->layoutfile)
757 cli_classic_abort_usage("Error: --layout and --fmap both specified. Aborting.\n");
758 options->fmap = true;
759 break;
760 case 'i':
761 if (register_include_arg(&options->include_args, optarg))
762 cli_classic_abort_usage(NULL);
763 break;
764 case OPTION_FLASH_CONTENTS:
765 if (options->referencefile)
766 cli_classic_abort_usage("Error: --flash-contents specified more than once."
767 "Aborting.\n");
768 options->referencefile = strdup(optarg);
769 break;
770 case OPTION_FLASH_NAME:
771 cli_classic_validate_singleop(&operation_specified);
772 options->flash_name = true;
773 break;
774 case OPTION_FLASH_SIZE:
775 cli_classic_validate_singleop(&operation_specified);
776 options->flash_size = true;
777 break;
778 case OPTION_WP_STATUS:
779 options->print_wp_status = true;
780 break;
781 case OPTION_WP_LIST:
782 options->print_wp_ranges = true;
783 break;
784 case OPTION_WP_SET_RANGE:
785 if (parse_wp_range(&options->wp_start, &options->wp_len) < 0)
786 cli_classic_abort_usage("Incorrect wp-range arguments provided.\n");
787
788 options->set_wp_range = true;
789 break;
790 case OPTION_WP_SET_REGION:
791 options->set_wp_region = true;
792 options->wp_region = strdup(optarg);
793 break;
794 case OPTION_WP_ENABLE:
795 options->enable_wp = true;
796 break;
797 case OPTION_WP_DISABLE:
798 options->disable_wp = true;
799 break;
800 case 'L':
801 cli_classic_validate_singleop(&operation_specified);
802 options->list_supported = true;
803 break;
804 case 'z':
805 #if CONFIG_PRINT_WIKI == 1
806 cli_classic_validate_singleop(&operation_specified);
807 options->list_supported_wiki = true;
808 #else
809 cli_classic_abort_usage("Error: Wiki output was not "
810 "compiled in. Aborting.\n");
811 #endif
812 break;
813 case 'p':
814 if (options->prog != NULL) {
815 cli_classic_abort_usage("Error: --programmer specified "
816 "more than once. You can separate "
817 "multiple\nparameters for a programmer "
818 "with \",\". Please see the man page "
819 "for details.\n");
820 }
821 size_t p;
822 for (p = 0; p < programmer_table_size; p++) {
823 name = programmer_table[p]->name;
824 namelen = strlen(name);
825 if (strncmp(optarg, name, namelen) == 0) {
826 switch (optarg[namelen]) {
827 case ':':
828 options->pparam = strdup(optarg + namelen + 1);
829 if (!strlen(options->pparam)) {
830 free(options->pparam);
831 options->pparam = NULL;
832 }
833 options->prog = programmer_table[p];
834 break;
835 case '\0':
836 options->prog = programmer_table[p];
837 break;
838 default:
839 /* The continue refers to the
840 * for loop. It is here to be
841 * able to differentiate between
842 * foo and foobar.
843 */
844 continue;
845 }
846 break;
847 }
848 }
849 if (options->prog == NULL) {
850 fprintf(stderr, "Error: Unknown programmer \"%s\". Valid choices are:\n",
851 optarg);
852 list_programmers_linebreak(0, 80, 0);
853 msg_ginfo(".\n");
854 cli_classic_abort_usage(NULL);
855 }
856 break;
857 case 'R':
858 /* print_version() is always called during startup. */
859 cli_classic_validate_singleop(&operation_specified);
860 exit(0);
861 break;
862 case 'h':
863 cli_classic_validate_singleop(&operation_specified);
864 cli_classic_usage(argv[0]);
865 exit(0);
866 break;
867 case 'o':
868 if (options->logfile) {
869 fprintf(stderr, "Warning: -o/--output specified multiple times.\n");
870 free(options->logfile);
871 }
872
873 options->logfile = strdup(optarg);
874 if (options->logfile[0] == '\0') {
875 cli_classic_abort_usage("No log filename specified.\n");
876 }
877 break;
878 case OPTION_PROGRESS:
879 options->show_progress = true;
880 break;
881 default:
882 cli_classic_abort_usage(NULL);
883 break;
884 }
885 }
886
887 if (optind < argc)
888 cli_classic_abort_usage("Error: Extra parameter found.\n");
889 }
890
free_options(struct cli_options * options)891 static void free_options(struct cli_options *options)
892 {
893 cleanup_include_args(&options->include_args);
894 free(options->filename);
895 free(options->fmapfile);
896 free(options->referencefile);
897 free(options->layoutfile);
898 free(options->pparam);
899 free(options->wp_region);
900 free(options->logfile);
901 free((char *)options->chip_to_probe);
902 }
903
main(int argc,char * argv[])904 int main(int argc, char *argv[])
905 {
906 const struct flashchip *chip = NULL;
907 /* Probe for up to eight flash chips. */
908 struct flashctx flashes[8] = {{0}};
909 struct flashctx *fill_flash;
910 char *tempstr = NULL;
911 int startchip = -1, chipcount = 0;
912 int i, j;
913 int ret = 0;
914
915 struct cli_options options = { 0 };
916 static const char optstring[] = "r::Rw::v::nNVEfc:l:i:p:Lzho:x";
917 static const struct option long_options[] = {
918 {"read", 2, NULL, 'r'},
919 {"write", 2, NULL, 'w'},
920 {"erase", 0, NULL, 'E'},
921 {"verify", 2, NULL, 'v'},
922 {"noverify", 0, NULL, 'n'},
923 {"noverify-all", 0, NULL, 'N'},
924 {"extract", 0, NULL, 'x'},
925 {"chip", 1, NULL, 'c'},
926 {"verbose", 0, NULL, 'V'},
927 {"force", 0, NULL, 'f'},
928 {"layout", 1, NULL, 'l'},
929 {"ifd", 0, NULL, OPTION_IFD},
930 {"fmap", 0, NULL, OPTION_FMAP},
931 {"fmap-file", 1, NULL, OPTION_FMAP_FILE},
932 {"image", 1, NULL, 'i'}, // (deprecated): back compatibility.
933 {"include", 1, NULL, 'i'},
934 {"flash-contents", 1, NULL, OPTION_FLASH_CONTENTS},
935 {"flash-name", 0, NULL, OPTION_FLASH_NAME},
936 {"flash-size", 0, NULL, OPTION_FLASH_SIZE},
937 {"get-size", 0, NULL, OPTION_FLASH_SIZE}, // (deprecated): back compatibility.
938 {"wp-status", 0, NULL, OPTION_WP_STATUS},
939 {"wp-list", 0, NULL, OPTION_WP_LIST},
940 {"wp-range", 1, NULL, OPTION_WP_SET_RANGE},
941 {"wp-region", 1, NULL, OPTION_WP_SET_REGION},
942 {"wp-enable", 0, NULL, OPTION_WP_ENABLE},
943 {"wp-disable", 0, NULL, OPTION_WP_DISABLE},
944 {"list-supported", 0, NULL, 'L'},
945 {"list-supported-wiki", 0, NULL, 'z'},
946 {"programmer", 1, NULL, 'p'},
947 {"help", 0, NULL, 'h'},
948 {"version", 0, NULL, 'R'},
949 {"output", 1, NULL, 'o'},
950 {"progress", 0, NULL, OPTION_PROGRESS},
951 {NULL, 0, NULL, 0},
952 };
953
954 /*
955 * Safety-guard against a user who has (mistakenly) closed
956 * stdout or stderr before exec'ing flashrom. We disable
957 * logging in this case to prevent writing log data to a flash
958 * chip when a flash device gets opened with fd 1 or 2.
959 */
960 if (check_file(stdout) && check_file(stderr)) {
961 flashrom_set_log_callback(&flashrom_print_cb);
962 }
963
964 print_version();
965 print_banner();
966
967 setbuf(stdout, NULL);
968
969 parse_options(argc, argv, optstring, long_options, &options);
970
971 if (options.filename && check_filename(options.filename, "image"))
972 cli_classic_abort_usage(NULL);
973 if (options.layoutfile && check_filename(options.layoutfile, "layout"))
974 cli_classic_abort_usage(NULL);
975 if (options.fmapfile && check_filename(options.fmapfile, "fmap"))
976 cli_classic_abort_usage(NULL);
977 if (options.referencefile && check_filename(options.referencefile, "reference"))
978 cli_classic_abort_usage(NULL);
979 if (options.logfile && check_filename(options.logfile, "log"))
980 cli_classic_abort_usage(NULL);
981 if (options.logfile && open_logfile(options.logfile))
982 cli_classic_abort_usage(NULL);
983
984 #if CONFIG_PRINT_WIKI == 1
985 if (options.list_supported_wiki) {
986 print_supported_wiki();
987 goto out;
988 }
989 #endif
990
991 if (options.list_supported) {
992 if (print_supported())
993 ret = 1;
994 goto out;
995 }
996
997 start_logging();
998
999 print_buildinfo();
1000 msg_gdbg("Command line (%i args):", argc - 1);
1001 for (i = 0; i < argc; i++) {
1002 msg_gdbg(" %s", argv[i]);
1003 }
1004 msg_gdbg("\n");
1005
1006 if (options.layoutfile && layout_from_file(&options.layout, options.layoutfile)) {
1007 ret = 1;
1008 goto out;
1009 }
1010
1011 /* If the user specifies a -i argument and no layout, then we do fmap
1012 * parsing. */
1013 if ((options.include_args || options.extract_it) && !options.layoutfile && !options.ifd) {
1014 msg_gdbg("-i argument specified, set fmap.\n");
1015 options.fmap = 1;
1016 }
1017
1018 if (!options.ifd && !options.fmap && process_include_args(options.layout, options.include_args)) {
1019 ret = 1;
1020 goto out;
1021 }
1022 /* Does a chip with the requested name exist in the flashchips array? */
1023 if (options.chip_to_probe) {
1024 for (chip = flashchips; chip && chip->name; chip++)
1025 if (!strcmp(chip->name, options.chip_to_probe))
1026 break;
1027 if (!chip || !chip->name) {
1028 msg_cerr("Error: Unknown chip '%s' specified.\n", options.chip_to_probe);
1029 msg_gerr("Run flashrom -L to view the hardware supported in this flashrom version.\n");
1030 ret = 1;
1031 goto out;
1032 }
1033 /* Keep chip around for later usage in case a forced read is requested. */
1034 }
1035
1036 if (options.prog == NULL) {
1037 const struct programmer_entry *const default_programmer = CONFIG_DEFAULT_PROGRAMMER_NAME;
1038
1039 if (default_programmer) {
1040 options.prog = default_programmer;
1041 /* We need to strdup here because we free(pparam) unconditionally later. */
1042 options.pparam = strdup(CONFIG_DEFAULT_PROGRAMMER_ARGS);
1043 msg_pinfo("Using default programmer \"%s\" with arguments \"%s\".\n",
1044 default_programmer->name, options.pparam);
1045 } else {
1046 msg_perr("Please select a programmer with the --programmer parameter.\n"
1047 #if CONFIG_INTERNAL == 1
1048 "To choose the mainboard of this computer use 'internal'. "
1049 #endif
1050 "Valid choices are:\n");
1051 list_programmers_linebreak(0, 80, 0);
1052 msg_ginfo(".\n");
1053 ret = 1;
1054 goto out;
1055 }
1056 }
1057
1058 /* FIXME: Delay calibration should happen in programmer code. */
1059 if (flashrom_init(1))
1060 exit(1);
1061
1062 if (programmer_init(options.prog, options.pparam)) {
1063 msg_perr("Error: Programmer initialization failed.\n");
1064 ret = 1;
1065 goto out_shutdown;
1066 }
1067 tempstr = flashbuses_to_text(get_buses_supported());
1068 msg_pdbg("The following protocols are supported: %s.\n", tempstr ? tempstr : "?");
1069 free(tempstr);
1070 tempstr = NULL;
1071
1072 for (j = 0; j < registered_master_count; j++) {
1073 startchip = 0;
1074 while (chipcount < (int)ARRAY_SIZE(flashes)) {
1075 startchip = probe_flash(®istered_masters[j], startchip, &flashes[chipcount], 0, options.chip_to_probe);
1076 if (startchip == -1)
1077 break;
1078 chipcount++;
1079 startchip++;
1080 }
1081 }
1082
1083 if (chipcount > 1) {
1084 msg_cinfo("Multiple flash chip definitions match the detected chip(s): \"%s\"",
1085 flashes[0].chip->name);
1086 for (i = 1; i < chipcount; i++)
1087 msg_cinfo(", \"%s\"", flashes[i].chip->name);
1088 msg_cinfo("\nPlease specify which chip definition to use with the -c <chipname> option.\n");
1089 ret = 1;
1090 goto out_shutdown;
1091 } else if (!chipcount) {
1092 msg_cinfo("No EEPROM/flash device found.\n");
1093 if (!options.force || !options.chip_to_probe) {
1094 msg_cinfo("Note: flashrom can never write if the flash chip isn't found "
1095 "automatically.\n");
1096 }
1097 if (options.force && options.read_it && options.chip_to_probe) {
1098 struct registered_master *mst;
1099 int compatible_masters = 0;
1100 msg_cinfo("Force read (-f -r -c) requested, pretending the chip is there:\n");
1101 /* This loop just counts compatible controllers. */
1102 for (j = 0; j < registered_master_count; j++) {
1103 mst = ®istered_masters[j];
1104 /* chip is still set from the chip_to_probe earlier in this function. */
1105 if (mst->buses_supported & chip->bustype)
1106 compatible_masters++;
1107 }
1108 if (!compatible_masters) {
1109 msg_cinfo("No compatible controller found for the requested flash chip.\n");
1110 ret = 1;
1111 goto out_shutdown;
1112 }
1113 if (compatible_masters > 1)
1114 msg_cinfo("More than one compatible controller found for the requested flash "
1115 "chip, using the first one.\n");
1116 for (j = 0; j < registered_master_count; j++) {
1117 mst = ®istered_masters[j];
1118 startchip = probe_flash(mst, 0, &flashes[0], 1, options.chip_to_probe);
1119 if (startchip != -1)
1120 break;
1121 }
1122 if (startchip == -1) {
1123 // FIXME: This should never happen! Ask for a bug report?
1124 msg_cinfo("Probing for flash chip '%s' failed.\n", options.chip_to_probe);
1125 ret = 1;
1126 goto out_shutdown;
1127 }
1128 msg_cinfo("Please note that forced reads most likely contain garbage.\n");
1129 flashrom_flag_set(&flashes[0], FLASHROM_FLAG_FORCE, options.force);
1130 ret = do_read(&flashes[0], options.filename);
1131 free(flashes[0].chip);
1132 goto out_shutdown;
1133 }
1134 ret = 1;
1135 goto out_shutdown;
1136 } else if (!options.chip_to_probe) {
1137 /* repeat for convenience when looking at foreign logs */
1138 tempstr = flashbuses_to_text(flashes[0].chip->bustype);
1139 msg_gdbg("Found %s flash chip \"%s\" (%d kB, %s).\n",
1140 flashes[0].chip->vendor, flashes[0].chip->name, flashes[0].chip->total_size,
1141 tempstr ? tempstr : "?");
1142 free(tempstr);
1143 }
1144
1145 fill_flash = &flashes[0];
1146
1147 unsigned int progress_user_data[FLASHROM_PROGRESS_NR];
1148 struct flashrom_progress progress_state = {
1149 .user_data = progress_user_data
1150 };
1151 if (options.show_progress)
1152 flashrom_set_progress_callback(fill_flash, &flashrom_progress_cb, &progress_state);
1153
1154 print_chip_support_status(fill_flash->chip);
1155
1156 unsigned int limitexceeded = count_max_decode_exceedings(fill_flash, &max_rom_decode);
1157 if (limitexceeded > 0 && !options.force) {
1158 enum chipbustype commonbuses = fill_flash->mst->buses_supported & fill_flash->chip->bustype;
1159
1160 /* Sometimes chip and programmer have more than one bus in common,
1161 * and the limit is not exceeded on all buses. Tell the user. */
1162 if ((bitcount(commonbuses) > limitexceeded)) {
1163 msg_pdbg("There is at least one interface available which could support the size of\n"
1164 "the selected flash chip.\n");
1165 }
1166 msg_cerr("This flash chip is too big for this programmer (--verbose/-V gives details).\n"
1167 "Use --force/-f to override at your own risk.\n");
1168 ret = 1;
1169 goto out_shutdown;
1170 }
1171
1172 const bool any_wp_op =
1173 options.set_wp_range || options.set_wp_region || options.enable_wp ||
1174 options.disable_wp || options.print_wp_status || options.print_wp_ranges;
1175
1176 const bool any_op = options.read_it || options.write_it || options.verify_it ||
1177 options.erase_it || options.flash_name || options.flash_size ||
1178 options.extract_it || any_wp_op;
1179
1180 if (!any_op) {
1181 msg_ginfo("No operations were specified.\n");
1182 goto out_shutdown;
1183 }
1184
1185 if (options.enable_wp && options.disable_wp) {
1186 msg_ginfo("Error: --wp-enable and --wp-disable are mutually exclusive\n");
1187 ret = 1;
1188 goto out_shutdown;
1189 }
1190 if (options.set_wp_range && options.set_wp_region) {
1191 msg_gerr("Error: Cannot use both --wp-range and --wp-region simultaneously.\n");
1192 ret = 1;
1193 goto out_shutdown;
1194 }
1195
1196 /*
1197 * Common rules for -r/-w/-v syntax parsing:
1198 * - If no filename is specified at all, quit.
1199 * - If no filename is specified for -r/-w/-v, but files are specified
1200 * for -i, then the number of file arguments for -i options must be
1201 * equal to the total number of -i options.
1202 *
1203 * Rules for reading:
1204 * - If files are specified for -i args but not -r, do partial reads for
1205 * each -i arg, creating a new file for each region. Each -i option
1206 * must specify a filename.
1207 * - If filenames are specified for -r and -i args, then:
1208 * - Do partial read for each -i arg, creating a new file for
1209 * each region where a filename is provided (-i region:filename).
1210 * - Create a ROM-sized file with partially filled content. For each
1211 * -i arg, fill the corresponding offset with content from ROM.
1212 *
1213 * Rules for writing and verifying:
1214 * - If files are specified for both -w/-v and -i args, -i files take
1215 * priority.
1216 * - If file is specified for -w/-v and no files are specified with -i
1217 * args, then the file is to be used for writing/verifying the entire
1218 * ROM.
1219 * - If files are specified for -i args but not -w, do partial writes
1220 * for each -i arg. Likewise for -v and -i args. All -i args must
1221 * supply a filename. Any omission is considered ambiguous.
1222 * - Regions with a filename associated must not overlap. This is also
1223 * considered ambiguous. Note: This is checked later since it requires
1224 * processing the layout/fmap first.
1225 */
1226 if ((options.read_it | options.write_it | options.verify_it) && !options.filename) {
1227 if (!options.include_args) {
1228 msg_gerr("Error: No image file specified.\n");
1229 ret = 1;
1230 goto out_shutdown;
1231 }
1232
1233 if (check_include_args_filename(options.include_args)) {
1234 ret = 1;
1235 goto out_shutdown;
1236 }
1237 }
1238
1239 if (options.flash_name) {
1240 if (fill_flash->chip->vendor && fill_flash->chip->name) {
1241 printf("vendor=\"%s\" name=\"%s\"\n",
1242 fill_flash->chip->vendor,
1243 fill_flash->chip->name);
1244 } else {
1245 ret = -1;
1246 }
1247 goto out_shutdown;
1248 }
1249
1250 if (options.flash_size) {
1251 printf("%zu\n", flashrom_flash_getsize(fill_flash));
1252 goto out_shutdown;
1253 }
1254
1255 /*
1256 * FIXME: Align with upstream, maybe add build flag for this. Always
1257 * skip unreadable and unwritable regions in cros flashrom. Various
1258 * flashrom users (e.g. Tast tests, flashrom_tester) try to read or
1259 * write the entire flash and will fail on Intel platforms if the ME
1260 * regions are not automatically skipped.
1261 */
1262 flashrom_flag_set(fill_flash, FLASHROM_FLAG_SKIP_UNWRITABLE_REGIONS, true);
1263 flashrom_flag_set(fill_flash, FLASHROM_FLAG_SKIP_UNREADABLE_REGIONS, true);
1264
1265 if (options.ifd && (flashrom_layout_read_from_ifd(&options.layout, fill_flash, NULL, 0) ||
1266 process_include_args(options.layout, options.include_args))) {
1267 ret = 1;
1268 goto out_shutdown;
1269 } else if (options.fmap && options.fmapfile &&
1270 (flashrom_layout_read_fmap_from_file(&options.layout, fill_flash, options.fmapfile) ||
1271 process_include_args(options.layout, options.include_args))) {
1272 ret = 1;
1273 goto out_shutdown;
1274 } else if (!options.ifd && options.fmap &&
1275 ((flashrom_layout_read_fmap_from_file(&options.layout, fill_flash, options.filename) &&
1276 flashrom_layout_read_fmap_from_rom(&options.layout, fill_flash, 0,
1277 flashrom_flash_getsize(fill_flash))) ||
1278 process_include_args(options.layout, options.include_args))) {
1279 ret = 1;
1280 goto out_shutdown;
1281 }
1282 flashrom_layout_set(fill_flash, options.layout);
1283
1284 if (any_wp_op) {
1285 if (options.set_wp_region && options.wp_region) {
1286 if (!options.layout) {
1287 msg_gerr("Error: A flash layout must be specified to use --wp-region.\n");
1288 ret = 1;
1289 goto out_release;
1290 }
1291
1292 ret = flashrom_layout_get_region_range(options.layout, options.wp_region, &options.wp_start, &options.wp_len);
1293 if (ret) {
1294 msg_gerr("Error: Region %s not found in flash layout.\n", options.wp_region);
1295 goto out_release;
1296 }
1297 options.set_wp_range = true;
1298 }
1299 ret = wp_cli(
1300 fill_flash,
1301 options.enable_wp,
1302 options.disable_wp,
1303 options.print_wp_status,
1304 options.print_wp_ranges,
1305 options.set_wp_range,
1306 options.wp_start,
1307 options.wp_len
1308 );
1309 if (ret)
1310 goto out_release;
1311 }
1312
1313 flashrom_flag_set(fill_flash, FLASHROM_FLAG_FORCE, options.force);
1314 #if CONFIG_INTERNAL == 1
1315 flashrom_flag_set(fill_flash, FLASHROM_FLAG_FORCE_BOARDMISMATCH, force_boardmismatch);
1316 #endif
1317 flashrom_flag_set(fill_flash, FLASHROM_FLAG_VERIFY_AFTER_WRITE, !options.dont_verify_it);
1318 flashrom_flag_set(fill_flash, FLASHROM_FLAG_VERIFY_WHOLE_CHIP, !options.dont_verify_all);
1319
1320 /* FIXME: We should issue an unconditional chip reset here. This can be
1321 * done once we have a .reset function in struct flashchip.
1322 * Give the chip time to settle.
1323 */
1324 programmer_delay(fill_flash, 100000);
1325 if (options.read_it)
1326 ret = do_read(fill_flash, options.filename);
1327 else if (options.extract_it)
1328 ret = do_extract(fill_flash);
1329 else if (options.erase_it) {
1330 ret = flashrom_flash_erase(fill_flash);
1331 /*
1332 * FIXME: Do we really want the scary warning if erase failed?
1333 * After all, after erase the chip is either blank or partially
1334 * blank or it has the old contents. A blank chip won't boot,
1335 * so if the user wanted erase and reboots afterwards, the user
1336 * knows very well that booting won't work.
1337 */
1338 if (ret)
1339 emergency_help_message();
1340 }
1341 else if (options.write_it)
1342 ret = do_write(fill_flash, options.filename, options.referencefile);
1343 else if (options.verify_it)
1344 ret = do_verify(fill_flash, options.filename);
1345
1346 msg_ginfo("%s\n", ret ? "FAILED" : "SUCCESS");
1347
1348 out_release:
1349 flashrom_layout_release(options.layout);
1350 out_shutdown:
1351 flashrom_programmer_shutdown(NULL);
1352 out:
1353
1354 for (i = 0; i < chipcount; i++) {
1355 flashrom_layout_release(flashes[i].default_layout);
1356 free(flashes[i].chip);
1357 }
1358
1359 free_options(&options);
1360 ret |= close_logfile();
1361 return ret;
1362 }
1363