xref: /aosp_15_r20/external/vboot_reference/host/lib/flashrom_drv.c (revision 8617a60d3594060b7ecbd21bc622a7c14f3cf2bc)
1 /* Copyright 2021 The ChromiumOS Authors
2  * Use of this source code is governed by a BSD-style license that can be
3  * found in the LICENSE file.
4  *
5  * The utility functions for firmware updater.
6  */
7 
8 #include <libflashrom.h>
9 
10 #include "2common.h"
11 #include "crossystem.h"
12 #include "host_misc.h"
13 #include "util_misc.h"
14 //#include "updater.h"
15 #include "../../futility/futility.h"
16 #include "flashrom.h"
17 
18 // global to allow verbosity level to be injected into callback.
19 static enum flashrom_log_level g_verbose_screen = FLASHROM_MSG_INFO;
20 
flashrom_print_cb(enum flashrom_log_level level,const char * fmt,va_list ap)21 static int flashrom_print_cb(enum flashrom_log_level level, const char *fmt,
22 			     va_list ap)
23 {
24 	int ret = 0;
25 	FILE *output_type = (level < FLASHROM_MSG_INFO) ? stderr : stdout;
26 
27 	if (level > g_verbose_screen)
28 		return ret;
29 
30 	ret = vfprintf(output_type, fmt, ap);
31 	/* msg_*spew often happens inside chip accessors
32 	 * in possibly time-critical operations.
33 	 * Don't slow them down by flushing.
34 	 */
35 	if (level != FLASHROM_MSG_SPEW)
36 		fflush(output_type);
37 
38 	return ret;
39 }
40 
flashrom_extract_params(const char * str,char ** prog,char ** params)41 static char *flashrom_extract_params(const char *str, char **prog, char **params)
42 {
43 	char *tmp = strdup(str);
44 	*prog = strtok(tmp, ":");
45 	*params = strtok(NULL, "");
46 	return tmp;
47 }
48 
49 /*
50  * NOTE: When `regions` contains multiple regions, `region_start` and
51  * `region_len` will be filled with the data of the first region.
52  */
flashrom_read_image_impl(struct firmware_image * image,const char * const regions[],const size_t regions_len,unsigned int * region_start,unsigned int * region_len,int verbosity)53 static int flashrom_read_image_impl(struct firmware_image *image,
54 				    const char * const regions[],
55 						const size_t regions_len,
56 				    unsigned int *region_start,
57 				    unsigned int *region_len, int verbosity)
58 {
59 	int r = 0;
60 	size_t len = 0;
61 	*region_start = 0;
62 	*region_len = 0;
63 
64 	g_verbose_screen = (verbosity == -1) ? FLASHROM_MSG_INFO : verbosity;
65 
66 	char *programmer, *params;
67 	char *tmp = flashrom_extract_params(image->programmer, &programmer, &params);
68 
69 	struct flashrom_programmer *prog = NULL;
70 	struct flashrom_flashctx *flashctx = NULL;
71 	struct flashrom_layout *layout = NULL;
72 
73 	flashrom_set_log_callback((flashrom_log_callback *)&flashrom_print_cb);
74 
75 	if (flashrom_init(1)
76 		|| flashrom_programmer_init(&prog, programmer, params)) {
77 		r = -1;
78 		goto err_init;
79 	}
80 	if (flashrom_flash_probe(&flashctx, prog, NULL)) {
81 		r = -1;
82 		goto err_probe;
83 	}
84 
85 	len = flashrom_flash_getsize(flashctx);
86 	if (!len) {
87 		ERROR("Chip found had zero length, probing probably failed.\n");
88 		r = -1;
89 		goto err_probe;
90 	}
91 
92 	flashrom_flag_set(flashctx, FLASHROM_FLAG_SKIP_UNREADABLE_REGIONS, true);
93 
94 	if (regions_len) {
95 		int i;
96 		r = flashrom_layout_read_fmap_from_rom(
97 			&layout, flashctx, 0, len);
98 		if (r > 0) {
99 			ERROR("could not read fmap from rom, r=%d\n", r);
100 			r = -1;
101 			goto err_cleanup;
102 		}
103 		for (i = 0; i < regions_len; i++) {
104 			// empty region causes seg fault in API.
105 			r |= flashrom_layout_include_region(layout, regions[i]);
106 			if (r > 0) {
107 				ERROR("could not include region = '%s'\n",
108 				      regions[i]);
109 				r = -1;
110 				goto err_cleanup;
111 			}
112 		}
113 		flashrom_layout_set(flashctx, layout);
114 	}
115 
116 	image->data = calloc(1, len);
117 	image->size = len;
118 	image->file_name = strdup("<sys-flash>");
119 
120 	r |= flashrom_image_read(flashctx, image->data, len);
121 
122 	if (r == 0 && regions_len)
123 		r |= flashrom_layout_get_region_range(layout, regions[0],
124 						      region_start, region_len);
125 
126 err_cleanup:
127 	flashrom_layout_release(layout);
128 	flashrom_flash_release(flashctx);
129 
130 err_probe:
131 	r |= flashrom_programmer_shutdown(prog);
132 
133 err_init:
134 	free(tmp);
135 	return r;
136 }
137 
flashrom_read_image(struct firmware_image * image,const char * const regions[],const size_t regions_len,int verbosity)138 int flashrom_read_image(struct firmware_image *image,
139 			const char * const regions[],
140 			const size_t regions_len,
141 			int verbosity)
142 {
143 	unsigned int start, len;
144 	return flashrom_read_image_impl(image, regions, regions_len, &start,
145 					&len, verbosity);
146 }
147 
flashrom_read_region(struct firmware_image * image,const char * region,int verbosity)148 int flashrom_read_region(struct firmware_image *image, const char *region,
149 			 int verbosity)
150 {
151 	const char * const regions[] = {region};
152 	unsigned int start, len;
153 	int r = flashrom_read_image_impl(image, regions, ARRAY_SIZE(regions),
154 					 &start, &len, verbosity);
155 	if (r != 0)
156 		return r;
157 
158 	memmove(image->data, image->data + start, len);
159 	image->size = len;
160 	return 0;
161 }
162 
flashrom_write_image(const struct firmware_image * image,const char * const regions[],const size_t regions_len,const struct firmware_image * diff_image,int do_verify,int verbosity)163 int flashrom_write_image(const struct firmware_image *image,
164 			const char * const regions[],
165 			const size_t regions_len,
166 			const struct firmware_image *diff_image,
167 			int do_verify, int verbosity)
168 {
169 	int r = 0;
170 	size_t len = 0;
171 
172 	g_verbose_screen = (verbosity == -1) ? FLASHROM_MSG_INFO : verbosity;
173 
174 	char *programmer, *params;
175 	char *tmp = flashrom_extract_params(image->programmer, &programmer, &params);
176 
177 	struct flashrom_programmer *prog = NULL;
178 	struct flashrom_flashctx *flashctx = NULL;
179 	struct flashrom_layout *layout = NULL;
180 
181 	flashrom_set_log_callback((flashrom_log_callback *)&flashrom_print_cb);
182 
183 	if (flashrom_init(1)
184 		|| flashrom_programmer_init(&prog, programmer, params)) {
185 		r = -1;
186 		goto err_init;
187 	}
188 	if (flashrom_flash_probe(&flashctx, prog, NULL)) {
189 		r = -1;
190 		goto err_probe;
191 	}
192 
193 	len = flashrom_flash_getsize(flashctx);
194 	if (!len) {
195 		ERROR("Chip found had zero length, probing probably failed.\n");
196 		r = -1;
197 		goto err_cleanup;
198 	}
199 
200 	if (diff_image) {
201 		if (diff_image->size != image->size) {
202 			ERROR("diff_image->size != image->size");
203 			r = -1;
204 			goto err_cleanup;
205 		}
206 	}
207 
208 	/* Must occur before attempting to read FMAP from SPI flash. */
209 	flashrom_flag_set(flashctx, FLASHROM_FLAG_SKIP_UNREADABLE_REGIONS, true);
210 
211 	if (regions_len) {
212 		int i;
213 		r = flashrom_layout_read_fmap_from_buffer(
214 			&layout, flashctx, (const uint8_t *)image->data,
215 			image->size);
216 		if (r > 0) {
217 			WARN("could not read fmap from image, r=%d, "
218 				"falling back to read from rom\n", r);
219 			r = flashrom_layout_read_fmap_from_rom(
220 				&layout, flashctx, 0, len);
221 			if (r > 0) {
222 				ERROR("could not read fmap from rom, r=%d\n", r);
223 				r = -1;
224 				goto err_cleanup;
225 			}
226 		}
227 		for (i = 0; i < regions_len; i++) {
228 			INFO(" including region '%s'\n", regions[i]);
229 			// empty region causes seg fault in API.
230 			r |= flashrom_layout_include_region(layout, regions[i]);
231 			if (r > 0) {
232 				ERROR("could not include region = '%s'\n",
233 				      regions[i]);
234 				r = -1;
235 				goto err_cleanup;
236 			}
237 		}
238 		flashrom_layout_set(flashctx, layout);
239 	} else if (image->size != len) {
240 		r = -1;
241 		goto err_cleanup;
242 	}
243 
244 	flashrom_flag_set(flashctx, FLASHROM_FLAG_SKIP_UNWRITABLE_REGIONS, true);
245 	flashrom_flag_set(flashctx, FLASHROM_FLAG_VERIFY_WHOLE_CHIP, false);
246 	flashrom_flag_set(flashctx, FLASHROM_FLAG_VERIFY_AFTER_WRITE,
247 			  do_verify);
248 
249 	r |= flashrom_image_write(flashctx, image->data, image->size,
250 				  diff_image ? diff_image->data : NULL);
251 
252 err_cleanup:
253 	flashrom_layout_release(layout);
254 	flashrom_flash_release(flashctx);
255 
256 err_probe:
257 	r |= flashrom_programmer_shutdown(prog);
258 
259 err_init:
260 	free(tmp);
261 	return r;
262 }
263 
flashrom_get_wp(const char * prog_with_params,bool * wp_mode,uint32_t * wp_start,uint32_t * wp_len,int verbosity)264 int flashrom_get_wp(const char *prog_with_params, bool *wp_mode,
265 		    uint32_t *wp_start, uint32_t *wp_len, int verbosity)
266 {
267 	int ret = -1;
268 
269 	g_verbose_screen = (verbosity == -1) ? FLASHROM_MSG_INFO : verbosity;
270 
271 	struct flashrom_programmer *prog = NULL;
272 	struct flashrom_flashctx *flashctx = NULL;
273 
274 	struct flashrom_wp_cfg *cfg = NULL;
275 
276 	char *programmer, *params;
277 	char *tmp = flashrom_extract_params(prog_with_params, &programmer,
278 					    &params);
279 
280 	flashrom_set_log_callback((flashrom_log_callback *)&flashrom_print_cb);
281 
282 	if (flashrom_init(1)
283 		|| flashrom_programmer_init(&prog, programmer, params))
284 		goto err_init;
285 
286 	if (flashrom_flash_probe(&flashctx, prog, NULL))
287 		goto err_probe;
288 
289 	if (flashrom_wp_cfg_new(&cfg) != FLASHROM_WP_OK)
290 		goto err_cleanup;
291 
292 	if (flashrom_wp_read_cfg(cfg, flashctx) != FLASHROM_WP_OK)
293 		goto err_read_cfg;
294 
295 	/* size_t tmp variables for libflashrom compatibility */
296 	size_t tmp_wp_start, tmp_wp_len;
297 	flashrom_wp_get_range(&tmp_wp_start, &tmp_wp_len, cfg);
298 
299 	if (wp_start != NULL)
300 		*wp_start = tmp_wp_start;
301 	if (wp_start != NULL)
302 		*wp_len = tmp_wp_len;
303 	if (wp_mode != NULL)
304 		*wp_mode = flashrom_wp_get_mode(cfg) != FLASHROM_WP_MODE_DISABLED;
305 
306 	ret = 0;
307 
308 err_read_cfg:
309 	flashrom_wp_cfg_release(cfg);
310 
311 err_cleanup:
312 	flashrom_flash_release(flashctx);
313 
314 err_probe:
315 	if (flashrom_programmer_shutdown(prog))
316 		ret = -1;
317 
318 err_init:
319 	free(tmp);
320 
321 	return ret;
322 }
323 
flashrom_set_wp(const char * prog_with_params,bool wp_mode,uint32_t wp_start,uint32_t wp_len,int verbosity)324 int flashrom_set_wp(const char *prog_with_params, bool wp_mode,
325 		    uint32_t wp_start, uint32_t wp_len, int verbosity)
326 {
327 	int ret = 1;
328 
329 	g_verbose_screen = (verbosity == -1) ? FLASHROM_MSG_INFO : verbosity;
330 
331 	struct flashrom_programmer *prog = NULL;
332 	struct flashrom_flashctx *flashctx = NULL;
333 
334 	struct flashrom_wp_cfg *cfg = NULL;
335 
336 	char *programmer, *params;
337 	char *tmp = flashrom_extract_params(prog_with_params, &programmer,
338 					    &params);
339 
340 	flashrom_set_log_callback((flashrom_log_callback *)&flashrom_print_cb);
341 
342 	if (flashrom_init(1)
343 		|| flashrom_programmer_init(&prog, programmer, params))
344 		goto err_init;
345 
346 	if (flashrom_flash_probe(&flashctx, prog, NULL))
347 		goto err_probe;
348 
349 	if (flashrom_wp_cfg_new(&cfg) != FLASHROM_WP_OK)
350 		goto err_cleanup;
351 
352 	enum flashrom_wp_mode mode = wp_mode ?
353 			FLASHROM_WP_MODE_HARDWARE : FLASHROM_WP_MODE_DISABLED;
354 	flashrom_wp_set_mode(cfg, mode);
355 	flashrom_wp_set_range(cfg, wp_start, wp_len);
356 
357 	if (flashrom_wp_write_cfg(flashctx, cfg) != FLASHROM_WP_OK)
358 		goto err_write_cfg;
359 
360 	ret = 0;
361 
362 err_write_cfg:
363 	flashrom_wp_cfg_release(cfg);
364 
365 err_cleanup:
366 	flashrom_flash_release(flashctx);
367 
368 err_probe:
369 	if (flashrom_programmer_shutdown(prog))
370 		ret = 1;
371 
372 err_init:
373 	free(tmp);
374 
375 	return ret;
376 }
377 
flashrom_get_info(const char * prog_with_params,char ** vendor,char ** name,uint32_t * vid,uint32_t * pid,uint32_t * flash_len,int verbosity)378 int flashrom_get_info(const char *prog_with_params,
379 		      char **vendor, char **name,
380 		      uint32_t *vid, uint32_t *pid,
381 		      uint32_t *flash_len, int verbosity)
382 {
383 	int r = 0;
384 
385 	g_verbose_screen = (verbosity == -1) ? FLASHROM_MSG_INFO : verbosity;
386 
387 	char *programmer, *params;
388 	char *tmp = flashrom_extract_params(prog_with_params,
389 					    &programmer, &params);
390 
391 	struct flashrom_programmer *prog = NULL;
392 	struct flashrom_flashctx *flashctx = NULL;
393 
394 	flashrom_set_log_callback((flashrom_log_callback *)&flashrom_print_cb);
395 
396 	if (flashrom_init(1) ||
397 	    flashrom_programmer_init(&prog, programmer, params)) {
398 		r = -1;
399 		goto err_init;
400 	}
401 	if (flashrom_flash_probe(&flashctx, prog, NULL)) {
402 		r = -1;
403 		goto err_probe;
404 	}
405 
406 	struct flashrom_flashchip_info info;
407 	flashrom_flash_getinfo(flashctx, &info);
408 
409 	*vendor = strdup(info.vendor);
410 	*name = strdup(info.name);
411 	*vid = info.manufacture_id;
412 	*pid = info.model_id;
413 	*flash_len = info.total_size * 1024;
414 
415 	flashrom_flash_release(flashctx);
416 
417 err_probe:
418 	r |= flashrom_programmer_shutdown(prog);
419 
420 err_init:
421 	free(tmp);
422 	return r;
423 }
424 
flashrom_get_size(const char * prog_with_params,uint32_t * flash_len,int verbosity)425 int flashrom_get_size(const char *prog_with_params,
426 		      uint32_t *flash_len, int verbosity)
427 {
428 	int r = 0;
429 
430 	g_verbose_screen = (verbosity == -1) ? FLASHROM_MSG_INFO : verbosity;
431 
432 	char *programmer, *params;
433 	char *tmp = flashrom_extract_params(prog_with_params,
434 					    &programmer, &params);
435 
436 	struct flashrom_programmer *prog = NULL;
437 	struct flashrom_flashctx *flashctx = NULL;
438 
439 	flashrom_set_log_callback((flashrom_log_callback *)&flashrom_print_cb);
440 
441 	if (flashrom_init(1) ||
442 	    flashrom_programmer_init(&prog, programmer, params)) {
443 		r = -1;
444 		goto err_init;
445 	}
446 	if (flashrom_flash_probe(&flashctx, prog, NULL)) {
447 		r = -1;
448 		goto err_probe;
449 	}
450 
451 	*flash_len = flashrom_flash_getsize(flashctx);
452 
453 	flashrom_flash_release(flashctx);
454 
455 err_probe:
456 	r |= flashrom_programmer_shutdown(prog);
457 
458 err_init:
459 	free(tmp);
460 	return r;
461 }
462