2 * cbfstool, CLI utility for CBFS file manipulation
4 * Copyright (C) 2009 coresystems GmbH
5 * written by Patrick Georgi <patrick.georgi@coresystems.de>
6 * Copyright (C) 2012 Google, Inc.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; version 2 of the License.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
30 #include "cbfs_image.h"
35 const char *optstring
;
36 int (*function
) (void);
47 uint32_t baseaddress_assigned
;
49 uint32_t headeroffset
;
50 uint32_t headeroffset_assigned
;
58 int fit_empty_entries
;
60 /* for linux payloads */
64 /* All variables not listed are initialized as zero. */
65 .arch
= CBFS_ARCHITECTURE_UNKNOWN
,
66 .algo
= CBFS_COMPRESS_NONE
,
69 typedef int (*convert_buffer_t
)(struct buffer
*buffer
, uint32_t *offset
);
71 static int cbfs_add_integer_component(const char *cbfs_name
,
75 struct cbfs_image image
;
80 ERROR("You need to specify -n/--name.\n");
84 if (buffer_create(&buffer
, 8, name
) != 0)
87 for (i
= 0; i
< 8; i
++)
88 buffer
.data
[i
] = (u64val
>> i
*8) & 0xff;
90 if (cbfs_image_from_file(&image
, cbfs_name
) != 0) {
91 ERROR("Could not load ROM image '%s'.\n", cbfs_name
);
92 buffer_delete(&buffer
);
96 if (cbfs_get_entry(&image
, name
)) {
97 ERROR("'%s' already in ROM image.\n", name
);
101 if (cbfs_add_entry(&image
, &buffer
, name
, CBFS_COMPONENT_RAW
, param
.baseaddress
) != 0) {
102 ERROR("Failed to add %llu into ROM image as '%s'.\n", (long long unsigned)u64val
, name
);
106 if (cbfs_image_write_file(&image
, cbfs_name
) == 0)
110 buffer_delete(&buffer
);
111 cbfs_image_delete(&image
);
115 static int cbfs_add_component(const char *cbfs_name
,
116 const char *filename
,
120 convert_buffer_t convert
) {
121 struct cbfs_image image
;
122 struct buffer buffer
;
125 ERROR("You need to specify -f/--filename.\n");
130 ERROR("You need to specify -n/--name.\n");
135 ERROR("You need to specify a valid -t/--type.\n");
139 if (buffer_from_file(&buffer
, filename
) != 0) {
140 ERROR("Could not load file '%s'.\n", filename
);
144 if (convert
&& convert(&buffer
, &offset
) != 0) {
145 ERROR("Failed to parse file '%s'.\n", filename
);
146 buffer_delete(&buffer
);
150 if (cbfs_image_from_file(&image
, cbfs_name
) != 0) {
151 ERROR("Could not load ROM image '%s'.\n", cbfs_name
);
152 buffer_delete(&buffer
);
156 if (cbfs_get_entry(&image
, name
)) {
157 ERROR("'%s' already in ROM image.\n", name
);
158 buffer_delete(&buffer
);
159 cbfs_image_delete(&image
);
163 if (cbfs_add_entry(&image
, &buffer
, name
, type
, offset
) != 0) {
164 ERROR("Failed to add '%s' into ROM image.\n", filename
);
165 buffer_delete(&buffer
);
166 cbfs_image_delete(&image
);
170 if (cbfs_image_write_file(&image
, cbfs_name
) != 0) {
171 buffer_delete(&buffer
);
172 cbfs_image_delete(&image
);
176 buffer_delete(&buffer
);
177 cbfs_image_delete(&image
);
181 static int cbfstool_convert_mkstage(struct buffer
*buffer
, uint32_t *offset
)
183 struct buffer output
;
185 ret
= parse_elf_to_stage(buffer
, &output
, param
.arch
, param
.algo
,
189 buffer_delete(buffer
);
190 // direct assign, no dupe.
191 memcpy(buffer
, &output
, sizeof(*buffer
));
195 static int cbfstool_convert_mkpayload(struct buffer
*buffer
, uint32_t *offset
) {
196 struct buffer output
;
198 /* per default, try and see if payload is an ELF binary */
199 ret
= parse_elf_to_payload(buffer
, &output
, param
.arch
, param
.algo
);
201 /* If it's not an ELF, see if it's a UEFI FV */
203 ret
= parse_fv_to_payload(buffer
, &output
, param
.algo
);
205 /* If it's neither ELF nor UEFI Fv, try bzImage */
207 ret
= parse_bzImage_to_payload(buffer
, &output
,
208 param
.initrd
, param
.cmdline
, param
.algo
);
210 /* Not a supported payload type */
212 ERROR("Not a supported payload type (ELF / FV).\n");
216 buffer_delete(buffer
);
217 // direct assign, no dupe.
218 memcpy(buffer
, &output
, sizeof(*buffer
));
222 static int cbfstool_convert_mkflatpayload(struct buffer
*buffer
,
224 struct buffer output
;
225 if (parse_flat_binary_to_payload(buffer
, &output
,
231 buffer_delete(buffer
);
232 // direct assign, no dupe.
233 memcpy(buffer
, &output
, sizeof(*buffer
));
238 static int cbfs_add(void)
240 return cbfs_add_component(param
.cbfs_name
,
248 static int cbfs_add_stage(void)
250 return cbfs_add_component(param
.cbfs_name
,
253 CBFS_COMPONENT_STAGE
,
255 cbfstool_convert_mkstage
);
258 static int cbfs_add_payload(void)
260 return cbfs_add_component(param
.cbfs_name
,
263 CBFS_COMPONENT_PAYLOAD
,
265 cbfstool_convert_mkpayload
);
268 static int cbfs_add_flat_binary(void)
270 if (param
.loadaddress
== 0) {
271 ERROR("You need to specify a valid "
272 "-l/--load-address.\n");
275 if (param
.entrypoint
== 0) {
276 ERROR("You need to specify a valid "
277 "-e/--entry-point.\n");
280 return cbfs_add_component(param
.cbfs_name
,
283 CBFS_COMPONENT_PAYLOAD
,
285 cbfstool_convert_mkflatpayload
);
288 static int cbfs_add_integer(void)
290 return cbfs_add_integer_component(param
.cbfs_name
,
296 static int cbfs_remove(void)
298 struct cbfs_image image
;
301 ERROR("You need to specify -n/--name.\n");
305 if (cbfs_image_from_file(&image
, param
.cbfs_name
) != 0) {
306 ERROR("Could not load ROM image '%s'.\n",
311 if (cbfs_remove_entry(&image
, param
.name
) != 0) {
312 ERROR("Removing file '%s' failed.\n",
314 cbfs_image_delete(&image
);
317 if (cbfs_image_write_file(&image
, param
.cbfs_name
) != 0) {
318 cbfs_image_delete(&image
);
322 cbfs_image_delete(&image
);
326 static int cbfs_create(void)
328 struct cbfs_image image
;
329 struct buffer bootblock
;
331 if (param
.size
== 0) {
332 ERROR("You need to specify a valid -s/--size.\n");
336 if (!param
.bootblock
) {
337 ERROR("You need to specify -B/--bootblock.\n");
341 if (param
.arch
== CBFS_ARCHITECTURE_UNKNOWN
) {
342 ERROR("You need to specify -m/--machine arch.\n");
346 if (buffer_from_file(&bootblock
, param
.bootblock
) != 0) {
350 // Setup default boot offset and header offset.
351 if (!param
.baseaddress_assigned
) {
352 // put boot block before end of ROM.
353 param
.baseaddress
= param
.size
- bootblock
.size
;
354 DEBUG("bootblock in end of ROM.\n");
356 if (!param
.headeroffset_assigned
) {
357 // Put header before bootblock, and make a reference in end of
359 param
.headeroffset
= (
361 sizeof(struct cbfs_header
));
362 if (bootblock
.size
>= sizeof(uint32_t)) {
363 // TODO this only works for 32b top-aligned system now...
364 uint32_t ptr
= param
.headeroffset
- param
.size
;
365 uint32_t *sig
= (uint32_t *)(bootblock
.data
+
369 DEBUG("CBFS header reference in end of bootblock.\n");
373 if (cbfs_image_create(&image
,
380 param
.offset
) != 0) {
381 ERROR("Failed to create %s.\n", param
.cbfs_name
);
384 buffer_delete(&bootblock
);
386 if (cbfs_image_write_file(&image
, param
.cbfs_name
) != 0) {
387 ERROR("Failed to write %s.\n", param
.cbfs_name
);
388 cbfs_image_delete(&image
);
391 cbfs_image_delete(&image
);
395 static int cbfs_locate(void)
397 struct cbfs_image image
;
398 struct buffer buffer
;
401 if (!param
.filename
) {
402 ERROR("You need to specify -f/--filename.\n");
407 ERROR("You need to specify -n/--name.\n");
411 if (cbfs_image_from_file(&image
, param
.cbfs_name
) != 0) {
412 ERROR("Failed to load %s.\n", param
.cbfs_name
);
416 if (cbfs_get_entry(&image
, param
.name
))
417 WARN("'%s' already in CBFS.\n", param
.name
);
419 if (buffer_from_file(&buffer
, param
.filename
) != 0) {
420 ERROR("Cannot load %s.\n", param
.filename
);
421 cbfs_image_delete(&image
);
425 address
= cbfs_locate_entry(&image
, param
.name
, buffer
.size
,
426 param
.pagesize
, param
.alignment
);
427 buffer_delete(&buffer
);
430 ERROR("'%s' can't fit in CBFS for page-size %#x, align %#x.\n",
431 param
.name
, param
.pagesize
, param
.alignment
);
432 cbfs_image_delete(&image
);
436 if (param
.top_aligned
)
437 address
= address
- image
.header
->romsize
;
439 cbfs_image_delete(&image
);
440 printf("0x%x\n", address
);
444 static int cbfs_print(void)
446 struct cbfs_image image
;
447 if (cbfs_image_from_file(&image
, param
.cbfs_name
) != 0) {
448 ERROR("Could not load ROM image '%s'.\n",
452 cbfs_print_directory(&image
);
453 cbfs_image_delete(&image
);
457 static int cbfs_extract(void)
460 struct cbfs_image image
;
462 if (!param
.filename
) {
463 ERROR("You need to specify -f/--filename.\n");
468 ERROR("You need to specify -n/--name.\n");
472 if (cbfs_image_from_file(&image
, param
.cbfs_name
) != 0) {
473 ERROR("Could not load ROM image '%s'.\n",
476 } else if (cbfs_export_entry(&image
, param
.name
,
477 param
.filename
) != 0) {
481 cbfs_image_delete(&image
);
485 static int cbfs_update_fit(void)
488 struct cbfs_image image
;
491 ERROR("You need to specify -n/--name.\n");
495 if (param
.fit_empty_entries
<= 0) {
496 ERROR("Invalid number of fit entries "
497 "(-x/--empty-fits): %d\n", param
.fit_empty_entries
);
501 if (cbfs_image_from_file(&image
, param
.cbfs_name
) != 0) {
502 ERROR("Could not load ROM image '%s'.\n",
507 ret
= fit_update_table(&image
, param
.fit_empty_entries
, param
.name
);
509 ret
= cbfs_image_write_file(&image
, param
.cbfs_name
);
511 cbfs_image_delete(&image
);
515 static const struct command commands
[] = {
516 {"add", "f:n:t:b:vh?", cbfs_add
},
517 {"add-payload", "f:n:t:c:b:vh?C:I:", cbfs_add_payload
},
518 {"add-stage", "f:n:t:c:b:vh?", cbfs_add_stage
},
519 {"add-flat-binary", "f:n:l:e:c:b:vh?", cbfs_add_flat_binary
},
520 {"add-int", "i:n:b:vh?", cbfs_add_integer
},
521 {"remove", "n:vh?", cbfs_remove
},
522 {"create", "s:B:b:H:a:o:m:vh?", cbfs_create
},
523 {"locate", "f:n:P:a:Tvh?", cbfs_locate
},
524 {"print", "vh?", cbfs_print
},
525 {"extract", "n:f:vh?", cbfs_extract
},
526 {"update-fit", "n:x:vh?", cbfs_update_fit
},
529 static struct option long_options
[] = {
530 {"name", required_argument
, 0, 'n' },
531 {"type", required_argument
, 0, 't' },
532 {"compression", required_argument
, 0, 'c' },
533 {"base-address", required_argument
, 0, 'b' },
534 {"load-address", required_argument
, 0, 'l' },
535 {"top-aligned", required_argument
, 0, 'T' },
536 {"entry-point", required_argument
, 0, 'e' },
537 {"size", required_argument
, 0, 's' },
538 {"bootblock", required_argument
, 0, 'B' },
539 {"alignment", required_argument
, 0, 'a' },
540 {"page-size", required_argument
, 0, 'P' },
541 {"offset", required_argument
, 0, 'o' },
542 {"file", required_argument
, 0, 'f' },
543 {"int", required_argument
, 0, 'i' },
544 {"machine", required_argument
, 0, 'm' },
545 {"empty-fits", required_argument
, 0, 'x' },
546 {"initrd", required_argument
, 0, 'I' },
547 {"cmdline", required_argument
, 0, 'C' },
548 {"verbose", no_argument
, 0, 'v' },
549 {"help", no_argument
, 0, 'h' },
553 static void usage(char *name
)
556 ("cbfstool: Management utility for CBFS formatted ROM images\n\n"
557 "USAGE:\n" " %s [-h]\n"
558 " %s FILE COMMAND [-v] [PARAMETERS]...\n\n" "OPTIONs:\n"
559 " -T Output top-aligned memory address\n"
560 " -v Provide verbose output\n"
561 " -h Display this help message\n\n"
563 " add -f FILE -n NAME -t TYPE [-b base-address] "
565 " add-payload -f FILE -n NAME [-c compression] [-b base] "
566 "Add a payload to the ROM\n"
567 " (linux specific: [-C cmdline] [-I initrd])\n"
568 " add-stage -f FILE -n NAME [-c compression] [-b base] "
569 "Add a stage to the ROM\n"
570 " add-flat-binary -f FILE -n NAME -l load-address \\\n"
571 " -e entry-point [-c compression] [-b base] "
572 "Add a 32bit flat mode binary\n"
573 " add-int -i INTEGER -n NAME [-b base] "
574 "Add a raw 64-bit integer value\n"
576 "Remove a component\n"
577 " create -s size -B bootblock -m ARCH [-a align] [-o offset] "
578 "Create a ROM file\n"
579 " locate -f FILE -n NAME [-P page-size] [-a align] [-T] "
580 "Find a place for a file of that size\n"
582 "Show the contents of the ROM\n"
583 " extract -n NAME -f FILE "
584 "Extracts a raw payload from ROM\n"
585 " update-fit -n MICROCODE_BLOB_NAME -x EMTPY_FIT_ENTRIES\n "
586 "Updates the FIT table with microcode entries\n"
590 "TYPEs:\n", name
, name
592 print_supported_filetypes();
595 int main(int argc
, char **argv
)
605 param
.cbfs_name
= argv
[1];
609 for (i
= 0; i
< ARRAY_SIZE(commands
); i
++) {
610 if (strcmp(cmd
, commands
[i
].name
) != 0)
615 int option_index
= 0;
617 c
= getopt_long(argc
, argv
, commands
[i
].optstring
,
618 long_options
, &option_index
);
622 /* filter out illegal long options */
623 if (strchr(commands
[i
].optstring
, c
) == NULL
) {
624 /* TODO maybe print actual long option instead */
625 ERROR("%s: invalid option -- '%c'\n",
635 if (intfiletype(optarg
) != ((uint64_t) - 1))
636 param
.type
= intfiletype(optarg
);
638 param
.type
= strtoul(optarg
, NULL
, 0);
640 WARN("Unknown type '%s' ignored\n",
644 if (!strncasecmp(optarg
, "lzma", 5))
645 param
.algo
= CBFS_COMPRESS_LZMA
;
646 else if (!strncasecmp(optarg
, "none", 5))
647 param
.algo
= CBFS_COMPRESS_NONE
;
649 WARN("Unknown compression '%s'"
650 " ignored.\n", optarg
);
653 param
.baseaddress
= strtoul(optarg
, NULL
, 0);
654 // baseaddress may be zero on non-x86, so we
655 // need an explicit "baseaddress_assigned".
656 param
.baseaddress
= strtoul(optarg
, NULL
, 0);
657 param
.baseaddress_assigned
= 1;
660 param
.loadaddress
= strtoul(optarg
, NULL
, 0);
664 param
.entrypoint
= strtoul(optarg
, NULL
, 0);
667 param
.size
= strtoul(optarg
, &suffix
, 0);
668 if (tolower(suffix
[0])=='k') {
671 if (tolower(suffix
[0])=='m') {
672 param
.size
*= 1024 * 1024;
676 param
.bootblock
= optarg
;
679 param
.headeroffset
= strtoul(
681 param
.headeroffset_assigned
= 1;
684 param
.alignment
= strtoul(optarg
, NULL
, 0);
687 param
.pagesize
= strtoul(optarg
, NULL
, 0);
690 param
.offset
= strtoul(optarg
, NULL
, 0);
693 param
.filename
= optarg
;
696 param
.u64val
= strtoull(optarg
, NULL
, 0);
699 param
.top_aligned
= 1;
702 param
.fit_empty_entries
= strtol(optarg
, NULL
, 0);
708 param
.arch
= string_to_arch(optarg
);
711 param
.initrd
= optarg
;
714 param
.cmdline
= optarg
;
725 return commands
[i
].function();
728 ERROR("Unknown command '%s'.\n", cmd
);