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