xref: /aosp_15_r20/external/flashrom/cli_classic.c (revision 0d6140be3aa665ecc836e8907834fcd3e3b018fc)
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(&registered_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 = &registered_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 = &registered_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