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, ¶ms);
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, ¶ms);
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 ¶ms);
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 ¶ms);
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, ¶ms);
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, ¶ms);
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