xref: /aosp_15_r20/external/vboot_reference/futility/cmd_gbb_utility.c (revision 8617a60d3594060b7ecbd21bc622a7c14f3cf2bc)
1 /* Copyright 2014 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 
6 #include <errno.h>
7 #include <getopt.h>
8 #include <inttypes.h>
9 #include <stddef.h>
10 #include <stdint.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <sys/stat.h>
15 #include <sys/types.h>
16 #include <unistd.h>
17 
18 #include "flash_helpers.h"
19 #include "futility.h"
20 #include "updater.h"
21 #include "updater_utils.h"
22 #include "2gbb_flags.h"
23 
24 #ifdef USE_FLASHROM
25 #define FLASH_ARG_HELP                                                         \
26 	"     --flash         \tRead from and write to flash"                  \
27 	", ignore file arguments.\n"
28 #define FLASH_MORE_HELP                                                        \
29 	"In GET and SET mode, the following options modify the "               \
30 	"behaviour of flashing. Presence of any of these implies "             \
31 	"--flash.\n"                                                           \
32 	SHARED_FLASH_ARGS_HELP                                                 \
33 	"\n"
34 #else
35 #define FLASH_ARG_HELP
36 #define FLASH_MORE_HELP
37 #endif /* USE_FLASHROM */
38 
print_help(int argc,char * argv[])39 static void print_help(int argc, char *argv[])
40 {
41 	printf("\n"
42 		"Usage:  " MYNAME " %s [-g|-s|-c] [OPTIONS] "
43 		"[image_file] [output_file]\n"
44 		"\n"
45 		"GET MODE:\n"
46 		"-g, --get   (default)\tGet (read) from image_file or flash, "
47 		"with following options:\n"
48 		FLASH_ARG_HELP
49 		"     --hwid          \tReport hardware id (default).\n"
50 		"     --flags         \tReport header flags.\n"
51 		"     --digest        \tReport digest of hwid (>= v1.2)\n"
52 		" -k, --rootkey=FILE  \tFile name to export Root Key.\n"
53 		" -b, --bmpfv=FILE    \tFile name to export Bitmap FV.\n"
54 		" -r  --recoverykey=FILE\tFile name to export Recovery Key.\n"
55 		" -e  --explicit      \tReport header flags by name.\n"
56 		"\n"
57 		"SET MODE:\n"
58 		"-s, --set            \tSet (write) to flash or file, "
59 		"with following options:\n"
60 		FLASH_ARG_HELP
61 		" -o, --output=FILE   \tNew file name for ouptput.\n"
62 		"     --hwid=HWID     \tThe new hardware id to be changed.\n"
63 		"     --flags=FLAGS   \tThe new (numeric) flags value or +/- diff value.\n"
64 		" -k, --rootkey=FILE  \tFile name of new Root Key.\n"
65 		" -b, --bmpfv=FILE    \tFile name of new Bitmap FV.\n"
66 		" -r  --recoverykey=FILE\tFile name of new Recovery Key.\n"
67 		"\n"
68 		"CREATE MODE:\n"
69 		"-c, --create=hwid_size,rootkey_size,bmpfv_size,"
70 		"recoverykey_size\n"
71 		"                     \tCreate a GBB blob by given size list.\n\n"
72 		FLASH_MORE_HELP
73 		"SAMPLE:\n"
74 		"  %s -g image.bin\n"
75 		"  %s --set --hwid='New Model' -k key.bin"
76 		" image.bin newimage.bin\n"
77 		"  %s -c 0x100,0x1000,0x03DE80,0x1000 gbb.blob\n\n"
78 		"GBB Flags:\n"
79 		" To get a developer-friendly device, try 0x18 (dev_mode boot_usb).\n"
80 		" For early bringup development, try 0x40b9.\n",
81 		argv[0], argv[0], argv[0], argv[0]);
82 	for (vb2_gbb_flags_t flag = 1; flag; flag <<= 1) {
83 		const char *name;
84 		const char *description;
85 		if (vb2_get_gbb_flag_description(flag, &name, &description) !=
86 		    VB2_SUCCESS)
87 			break;
88 		printf(" 0x%08x\t%s\n"
89 		       "                     \t%s\n",
90 		       flag, name, description);
91 	}
92 }
93 
94 enum {
95 	OPT_HWID = 0x1000,
96 	OPT_FLAGS,
97 	OPT_DIGEST,
98 	OPT_FLASH,
99 	OPT_HELP,
100 };
101 
102 /* Command line options */
103 static struct option long_opts[] = {
104 	SHARED_FLASH_ARGS_LONGOPTS
105 	/* name  has_arg *flag val */
106 	{"get", 0, NULL, 'g'},
107 	{"set", 0, NULL, 's'},
108 	{"create", 1, NULL, 'c'},
109 	{"output", 1, NULL, 'o'},
110 	{"rootkey", 1, NULL, 'k'},
111 	{"bmpfv", 1, NULL, 'b'},
112 	{"recoverykey", 1, NULL, 'r'},
113 	{"hwid", 0, NULL, OPT_HWID},
114 	{"flags", 0, NULL, OPT_FLAGS},
115 	{"explicit", 0, NULL, 'e'},
116 	{"digest", 0, NULL, OPT_DIGEST},
117 	{"flash", 0, NULL, OPT_FLASH},
118 	{"help", 0, NULL, OPT_HELP},
119 	{NULL, 0, NULL, 0},
120 };
121 
122 static const char *short_opts = ":gsc:o:k:b:r:e" SHARED_FLASH_ARGS_SHORTOPTS;
123 
124 /* Change the has_arg field of a long_opts entry */
opt_has_arg(const char * name,int val)125 static void opt_has_arg(const char *name, int val)
126 {
127 	for (struct option *p = long_opts; p->name; p++) {
128 		if (!strcmp(name, p->name)) {
129 			p->has_arg = val;
130 			break;
131 		}
132 	}
133 }
134 
135 #define GBB_SEARCH_STRIDE 4
FindGbbHeader(uint8_t * ptr,size_t size)136 static struct vb2_gbb_header *FindGbbHeader(uint8_t *ptr, size_t size)
137 {
138 	size_t i;
139 	struct vb2_gbb_header *tmp, *gbb_header = NULL;
140 	int count = 0;
141 
142 	for (i = 0; i <= size - GBB_SEARCH_STRIDE; i += GBB_SEARCH_STRIDE) {
143 		if (memcmp(ptr + i, VB2_GBB_SIGNATURE, VB2_GBB_SIGNATURE_SIZE))
144 			continue;
145 
146 		/* Found something. See if it's any good. */
147 		tmp = (struct vb2_gbb_header *) (ptr + i);
148 		if (futil_valid_gbb_header(tmp, size - i, NULL))
149 			if (!count++)
150 				gbb_header = tmp;
151 	}
152 
153 	switch (count) {
154 	case 0:
155 		return NULL;
156 	case 1:
157 		return gbb_header;
158 	default:
159 		ERROR("Multiple GBB headers found\n");
160 		return NULL;
161 	}
162 }
163 
create_gbb(const char * desc,off_t * sizeptr)164 static uint8_t *create_gbb(const char *desc, off_t *sizeptr)
165 {
166 	char *param, *e = NULL;
167 	size_t size = EXPECTED_VB2_GBB_HEADER_SIZE;
168 	int i = 0;
169 	/* Danger Will Robinson! four entries ==> four paramater blocks */
170 	uint32_t val[] = { 0, 0, 0, 0 };
171 
172 	char *sizes = strdup(desc);
173 	if (!sizes) {
174 		ERROR("strdup() failed: %s\n", strerror(errno));
175 		return NULL;
176 	}
177 
178 	for (char *str = sizes; (param = strtok(str, ", ")) != NULL; str = NULL) {
179 		val[i] = (uint32_t) strtoul(param, &e, 0);
180 		if (e && *e) {
181 			ERROR("Invalid creation parameter: \"%s\"\n", param);
182 			free(sizes);
183 			return NULL;
184 		}
185 		size += val[i++];
186 		if (i > ARRAY_SIZE(val))
187 			break;
188 	}
189 
190 	uint8_t *buf = (uint8_t *) calloc(1, size);
191 	if (!buf) {
192 		ERROR("Can't malloc %zu bytes: %s\n", size, strerror(errno));
193 		free(sizes);
194 		return NULL;
195 	}
196 	if (sizeptr)
197 		*sizeptr = size;
198 
199 	struct vb2_gbb_header *gbb = (struct vb2_gbb_header *) buf;
200 	memcpy(gbb->signature, VB2_GBB_SIGNATURE, VB2_GBB_SIGNATURE_SIZE);
201 	gbb->major_version = VB2_GBB_MAJOR_VER;
202 	gbb->minor_version = VB2_GBB_MINOR_VER;
203 	gbb->header_size = EXPECTED_VB2_GBB_HEADER_SIZE;
204 	gbb->flags = 0;
205 
206 	i = EXPECTED_VB2_GBB_HEADER_SIZE;
207 	gbb->hwid_offset = i;
208 	gbb->hwid_size = val[0];
209 	i += val[0];
210 
211 	gbb->rootkey_offset = i;
212 	gbb->rootkey_size = val[1];
213 	i += val[1];
214 
215 	gbb->bmpfv_offset = i;
216 	gbb->bmpfv_size = val[2];
217 	i += val[2];
218 
219 	gbb->recovery_key_offset = i;
220 	gbb->recovery_key_size = val[3];
221 	i += val[1];
222 
223 	free(sizes);
224 	return buf;
225 }
226 
read_entire_file(const char * filename,off_t * sizeptr)227 static uint8_t *read_entire_file(const char *filename, off_t *sizeptr)
228 {
229 	uint8_t *buf = NULL;
230 	struct stat sb;
231 
232 	FILE *fp = fopen(filename, "rb");
233 	if (!fp) {
234 		ERROR("Unable to open %s for reading: %s\n", filename,
235 		      strerror(errno));
236 		goto fail;
237 	}
238 
239 	if (fstat(fileno(fp), &sb)) {
240 		ERROR("Can't fstat %s: %s\n", filename, strerror(errno));
241 		goto fail;
242 	}
243 	if (sizeptr)
244 		*sizeptr = sb.st_size;
245 
246 	buf = (uint8_t *) malloc(sb.st_size);
247 	if (!buf) {
248 		ERROR("Can't malloc %" PRIi64 " bytes: %s\n", sb.st_size,
249 		      strerror(errno));
250 		goto fail;
251 	}
252 
253 	if (1 != fread(buf, sb.st_size, 1, fp)) {
254 		ERROR("Unable to read from %s: %s\n", filename,
255 		      strerror(errno));
256 		goto fail;
257 	}
258 
259 	if (fclose(fp)) {
260 		ERROR("Unable to close %s: %s\n", filename, strerror(errno));
261 		fp = NULL;  /* Don't try to close it again */
262 		goto fail;
263 	}
264 
265 	return buf;
266 
267 fail:
268 	if (buf)
269 		free(buf);
270 
271 	if (fp && fclose(fp))
272 		ERROR("Unable to close %s: %s\n", filename, strerror(errno));
273 	return NULL;
274 }
275 
read_from_file(const char * msg,const char * filename,uint8_t * start,uint32_t size)276 static int read_from_file(const char *msg, const char *filename,
277 			  uint8_t *start, uint32_t size)
278 {
279 	struct stat sb;
280 	size_t count;
281 	int r = 0;
282 
283 	FILE *fp = fopen(filename, "rb");
284 	if (!fp) {
285 		r = errno;
286 		ERROR("Unable to open %s for reading: %s\n", filename, strerror(r));
287 		return r;
288 	}
289 
290 	if (fstat(fileno(fp), &sb)) {
291 		r = errno;
292 		ERROR("Can't fstat %s: %s\n", filename, strerror(r));
293 		goto done_close;
294 	}
295 
296 	if (sb.st_size > size) {
297 		ERROR("File %s exceeds capacity (%" PRIu32 ")\n", filename, size);
298 		r = -1;
299 		goto done_close;
300 	}
301 
302 	/* Wipe existing data. */
303 	memset(start, 0, size);
304 
305 	/* It's okay if we read less than size. That's just the max. */
306 	count = fread(start, 1, size, fp);
307 	if (ferror(fp)) {
308 		r = errno;
309 		ERROR("Read %zu/%" PRIi64 " bytes from %s: %s\n", count,
310 		      sb.st_size, filename, strerror(r));
311 	}
312 
313 done_close:
314 	if (fclose(fp)) {
315 		int e = errno;
316 		ERROR("Unable to close %s: %s\n", filename, strerror(e));
317 		if (!r)
318 			r = e;
319 	}
320 
321 	if (!r && msg)
322 		printf(" - import %s from %s: success\n", msg, filename);
323 
324 	return r;
325 }
326 
327 /* Read firmware from flash. */
read_from_flash(struct updater_config * cfg,off_t * filesize)328 static uint8_t *read_from_flash(struct updater_config *cfg, off_t *filesize)
329 {
330 #ifdef USE_FLASHROM
331 	/*
332 	 * Read the FMAP region as well, so that a subsequet write won't
333 	 * require another read of FMAP.
334 	 */
335 	const char * const regions[] = {FMAP_RO_FMAP, FMAP_RO_GBB};
336 	if (flashrom_read_image(&cfg->image_current, regions,
337 				ARRAY_SIZE(regions), cfg->verbosity + 1))
338 		return NULL;
339 	uint8_t *ret = cfg->image_current.data;
340 	cfg->image_current.data = NULL;
341 	*filesize = cfg->image_current.size;
342 	cfg->image_current.size = 0;
343 	return ret;
344 #else
345 	return NULL;
346 #endif /* USE_FLASHROM */
347 }
348 
349 /* Write firmware to flash. Takes ownership of inbuf and outbuf data. */
write_to_flash(struct updater_config * cfg,uint8_t * outbuf,off_t filesize)350 static int write_to_flash(struct updater_config *cfg, uint8_t *outbuf,
351 			  off_t filesize)
352 {
353 #ifdef USE_FLASHROM
354 	if (is_ap_write_protection_enabled(cfg)) {
355 		ERROR("You must disable write protection before setting flags.\n");
356 		return -1;
357 	}
358 	cfg->image.data = outbuf;
359 	cfg->image.size = filesize;
360 
361 	const char *sections[] = {FMAP_RO_GBB};
362 	int ret = write_system_firmware(cfg, &cfg->image, sections,
363 					ARRAY_SIZE(sections));
364 
365 	cfg->image.data = NULL;
366 	cfg->image.size = 0;
367 	return ret;
368 #else
369 	return 1;
370 #endif /* USE_FLASHROM */
371 }
372 
parse_flag_value(const char * s,vb2_gbb_flags_t * val)373 static int parse_flag_value(const char *s, vb2_gbb_flags_t *val)
374 {
375 	int sign = 0;
376 
377 	if (!strlen(s))
378 		return -1;
379 
380 	if (s[0] == '+')
381 		sign = 1;
382 	else if (s[0] == '-')
383 		sign = 2;
384 
385 	const char *ss = !sign ? s : &s[1];
386 	char *e = NULL;
387 	*val = strtoul(ss, &e, 0);
388 	if (e && *e) {
389 		ERROR("Invalid flags value: %s\n", ss);
390 		return -1;
391 	}
392 
393 	return sign;
394 }
395 
do_gbb(int argc,char * argv[])396 static int do_gbb(int argc, char *argv[])
397 {
398 	enum do_what_now { DO_GET, DO_SET, DO_CREATE } mode = DO_GET;
399 	char *infile = NULL;
400 	char *outfile = NULL;
401 	char *opt_create = NULL;
402 	char *opt_rootkey = NULL;
403 	char *opt_bmpfv = NULL;
404 	char *opt_recoverykey = NULL;
405 	char *opt_hwid = NULL;
406 	char *opt_flags = NULL;
407 	bool sel_hwid = false;
408 	bool sel_digest = false;
409 	bool sel_flags = false;
410 	int explicit_flags = 0;
411 	uint8_t *inbuf = NULL;
412 	off_t filesize;
413 	uint8_t *outbuf = NULL;
414 	int i;
415 	struct updater_config *cfg = NULL;
416 	struct updater_config_arguments args = {0};
417 	int errorcnt = 0;
418 
419 
420 	opterr = 0;		/* quiet, you */
421 	while ((i = getopt_long(argc, argv, short_opts, long_opts, 0)) != -1) {
422 #ifdef USE_FLASHROM
423 		if (handle_flash_argument(&args, i, optarg))
424 			continue;
425 #endif
426 		switch (i) {
427 		case 'g':
428 			mode = DO_GET;
429 			opt_has_arg("flags", 0);
430 			opt_has_arg("hwid", 0);
431 			break;
432 		case 's':
433 			mode = DO_SET;
434 			opt_has_arg("flags", 1);
435 			opt_has_arg("hwid", 1);
436 			break;
437 		case 'c':
438 			mode = DO_CREATE;
439 			opt_create = optarg;
440 			break;
441 		case 'o':
442 			outfile = optarg;
443 			break;
444 		case 'k':
445 			opt_rootkey = optarg;
446 			break;
447 		case 'b':
448 			opt_bmpfv = optarg;
449 			break;
450 		case 'r':
451 			opt_recoverykey = optarg;
452 			break;
453 		case OPT_HWID:
454 			/* --hwid is optional: null might be okay */
455 			opt_hwid = optarg;
456 			sel_hwid = true;
457 			break;
458 		case OPT_FLAGS:
459 			/* --flags is optional: null might be okay */
460 			opt_flags = optarg;
461 			sel_flags = true;
462 			break;
463 		case 'e':
464 			sel_flags = true;
465 			explicit_flags = 1;
466 			break;
467 		case OPT_DIGEST:
468 			sel_digest = true;
469 			break;
470 		case OPT_FLASH:
471 #ifndef USE_FLASHROM
472 			ERROR("futility was built without flashrom support\n");
473 			return 1;
474 #endif
475 			args.use_flash = 1;
476 			break;
477 		case OPT_HELP:
478 			print_help(argc, argv);
479 			return !!errorcnt;
480 
481 		case '?':
482 			errorcnt++;
483 			if (optopt)
484 				ERROR("Unrecognized option: -%c\n", optopt);
485 			else if (argv[optind - 1])
486 				ERROR("Unrecognized option (possibly \"%s\")\n",
487 				      argv[optind - 1]);
488 			else
489 				ERROR("Unrecognized option\n");
490 			break;
491 		case ':':
492 			errorcnt++;
493 			if (argv[optind - 1])
494 				ERROR("Missing argument to -%c (%s)\n", optopt,
495 				      argv[optind - 1]);
496 			else
497 				ERROR("Missing argument to -%c\n", optopt);
498 			break;
499 		default:
500 			errorcnt++;
501 			ERROR("While parsing options\n");
502 		}
503 	}
504 
505 	/* Problems? */
506 	if (errorcnt) {
507 		print_help(argc, argv);
508 		return 1;
509 	}
510 
511 	if (args.use_flash) {
512 		if (setup_flash(&cfg, &args)) {
513 			ERROR("While preparing flash\n");
514 			return 1;
515 		}
516 	}
517 
518 	/* Now try to do something */
519 	switch (mode) {
520 	case DO_GET:
521 		if (args.use_flash) {
522 			inbuf = read_from_flash(cfg, &filesize);
523 		} else {
524 			if (argc - optind < 1) {
525 				ERROR("Missing input filename\n");
526 				print_help(argc, argv);
527 				errorcnt++;
528 				break;
529 			}
530 			infile = argv[optind++];
531 			inbuf = read_entire_file(infile, &filesize);
532 		}
533 		if (!inbuf) {
534 			errorcnt++;
535 			break;
536 		}
537 
538 		/* With no args, show the HWID */
539 		if (!opt_rootkey && !opt_bmpfv && !opt_recoverykey
540 		    && !sel_flags && !sel_digest)
541 			sel_hwid = true;
542 
543 		struct vb2_gbb_header *gbb = FindGbbHeader(inbuf, filesize);
544 		if (!gbb) {
545 			ERROR("No GBB found in %s\n", infile);
546 			errorcnt++;
547 			break;
548 		}
549 		uint8_t *gbb_base = (uint8_t *) gbb;
550 
551 		/* Get the stuff */
552 		if (sel_hwid)
553 			printf("hardware_id: %s\n",
554 			       gbb->hwid_size ? (char *)(gbb_base +
555 							 gbb->
556 							 hwid_offset) : "");
557 		if (sel_digest)
558 			print_hwid_digest(gbb, "digest: ");
559 
560 		if (sel_flags)
561 			printf("flags: 0x%08x\n", gbb->flags);
562 		if (opt_rootkey)
563 			if (write_to_file(" - exported root_key to file:",
564 					  opt_rootkey,
565 					  gbb_base + gbb->rootkey_offset,
566 					  gbb->rootkey_size)) {
567 				errorcnt++;
568 				break;
569 			}
570 		if (opt_bmpfv)
571 			if (write_to_file(
572 				    " - exported bmp_fv to file:", opt_bmpfv,
573 				    gbb_base + gbb->bmpfv_offset,
574 				    gbb->bmpfv_size)) {
575 				errorcnt++;
576 				break;
577 			}
578 		if (opt_recoverykey)
579 			if (write_to_file(" - exported recovery_key to file:",
580 					  opt_recoverykey,
581 					  gbb_base + gbb->recovery_key_offset,
582 					  gbb->recovery_key_size)) {
583 				errorcnt++;
584 				break;
585 			}
586 		if (explicit_flags) {
587 			vb2_gbb_flags_t remaining_flags = gbb->flags;
588 			while (remaining_flags) {
589 				vb2_gbb_flags_t lsb_flag =
590 					remaining_flags & -remaining_flags;
591 				remaining_flags &= ~lsb_flag;
592 				const char *name;
593 				const char *description;
594 				if (vb2_get_gbb_flag_description(
595 					    lsb_flag, &name, &description) ==
596 				    VB2_SUCCESS) {
597 					printf("%s\n", name);
598 				} else {
599 					printf("unknown set flag: 0x%08x\n",
600 					       lsb_flag);
601 				}
602 			}
603 		}
604 		break;
605 
606 	case DO_SET:
607 		if (args.use_flash) {
608 			inbuf = read_from_flash(cfg, &filesize);
609 		} else {
610 			if (argc - optind < 1) {
611 				ERROR("Missing input filename\n");
612 				print_help(argc, argv);
613 				errorcnt++;
614 				break;
615 			}
616 			infile = argv[optind++];
617 			inbuf = read_entire_file(infile, &filesize);
618 			if (!outfile)
619 				outfile = (argc - optind < 1) ? infile
620 							      : argv[optind++];
621 		}
622 		if (!inbuf) {
623 			errorcnt++;
624 			break;
625 		}
626 
627 		if (sel_hwid && !opt_hwid) {
628 			ERROR("Missing new HWID value\n");
629 			print_help(argc, argv);
630 			errorcnt++;
631 			break;
632 		}
633 		if (sel_flags && (!opt_flags || !*opt_flags)) {
634 			ERROR("Missing new flags value\n");
635 			print_help(argc, argv);
636 			errorcnt++;
637 			break;
638 		}
639 
640 		gbb = FindGbbHeader(inbuf, filesize);
641 		if (!gbb) {
642 			ERROR("No GBB found in %s\n", infile);
643 			errorcnt++;
644 			break;
645 		}
646 		gbb_base = (uint8_t *) gbb;
647 
648 		outbuf = (uint8_t *) malloc(filesize);
649 		if (!outbuf) {
650 			ERROR("Can't malloc %" PRIi64 " bytes: %s\n", filesize,
651 			      strerror(errno));
652 			errorcnt++;
653 			break;
654 		}
655 
656 		/* Switch pointers to outbuf */
657 		memcpy(outbuf, inbuf, filesize);
658 		gbb = FindGbbHeader(outbuf, filesize);
659 		if (!gbb) {
660 			ERROR("INTERNAL ERROR: No GBB found in outbuf\n");
661 			errorcnt++;
662 			break;
663 		}
664 		gbb_base = (uint8_t *) gbb;
665 
666 		if (opt_hwid) {
667 			if (strlen(opt_hwid) + 1 > gbb->hwid_size) {
668 				ERROR("null-terminated HWID exceeds capacity (%d)\n",
669 					gbb->hwid_size);
670 				errorcnt++;
671 				break;
672 			}
673 			/* Wipe data before writing new value. */
674 			memset(gbb_base + gbb->hwid_offset, 0,
675 				gbb->hwid_size);
676 			strcpy((char *)(gbb_base + gbb->hwid_offset),
677 				opt_hwid);
678 			update_hwid_digest(gbb);
679 		}
680 
681 		if (opt_flags) {
682 			vb2_gbb_flags_t val;
683 			const int flag_sign = parse_flag_value(opt_flags, &val);
684 			if (flag_sign < 0) {
685 				errorcnt++;
686 				break;
687 			}
688 			if (flag_sign > 0)
689 				/* flag_sign := 1 => +ve and flag_sign := 2 => -ve. */
690 				gbb->flags = flag_sign == 1 ? (gbb->flags | val) : (gbb->flags & ~val);
691 			else
692 				gbb->flags = val;
693 		}
694 
695 		if (opt_rootkey) {
696 			if (read_from_file("root_key", opt_rootkey,
697 					   gbb_base + gbb->rootkey_offset,
698 					   gbb->rootkey_size)) {
699 				errorcnt++;
700 				break;
701 			}
702 		}
703 		if (opt_bmpfv)
704 			if (read_from_file("bmp_fv", opt_bmpfv,
705 					   gbb_base + gbb->bmpfv_offset,
706 					   gbb->bmpfv_size)) {
707 				errorcnt++;
708 				break;
709 			}
710 		if (opt_recoverykey)
711 			if (read_from_file("recovery_key", opt_recoverykey,
712 					   gbb_base + gbb->recovery_key_offset,
713 					   gbb->recovery_key_size)) {
714 				errorcnt++;
715 				break;
716 			}
717 
718 		/* Write it out if there are no problems. */
719 		if (!errorcnt) {
720 			if (args.use_flash) {
721 				if (write_to_flash(cfg, outbuf, filesize)) {
722 					errorcnt++;
723 					break;
724 				}
725 			} else if (write_to_file(
726 					   "successfully saved new image to:",
727 					   outfile, outbuf, filesize)) {
728 				errorcnt++;
729 				break;
730 			}
731 		}
732 		break;
733 
734 	case DO_CREATE:
735 		if (!outfile) {
736 			if (argc - optind < 1) {
737 				ERROR("Missing output filename\n");
738 				print_help(argc, argv);
739 				errorcnt++;
740 				break;
741 			}
742 			outfile = argv[optind++];
743 		}
744 		/* Parse the creation args */
745 		outbuf = create_gbb(opt_create, &filesize);
746 		if (!outbuf) {
747 			ERROR("Unable to parse creation spec (%s)\n", opt_create);
748 			print_help(argc, argv);
749 			errorcnt++;
750 			break;
751 		}
752 		if (!errorcnt)
753 			if (write_to_file("successfully created new GBB to:",
754 					  outfile, outbuf, filesize)) {
755 				errorcnt++;
756 				break;
757 			}
758 		break;
759 	}
760 
761 	if (args.use_flash)
762 		teardown_flash(cfg);
763 	if (inbuf)
764 		free(inbuf);
765 	if (outbuf)
766 		free(outbuf);
767 	return !!errorcnt;
768 }
769 
770 DECLARE_FUTIL_COMMAND(gbb, do_gbb, VBOOT_VERSION_ALL,
771 		      "Manipulate the Google Binary Block (GBB)");
772 DECLARE_FUTIL_COMMAND(gbb_utility, do_gbb, VBOOT_VERSION_ALL,
773 		      "Legacy name for `gbb` command");
774