diff options
Diffstat (limited to 'util/cbfstool/fmaptool.c')
-rw-r--r-- | util/cbfstool/fmaptool.c | 181 |
1 files changed, 153 insertions, 28 deletions
diff --git a/util/cbfstool/fmaptool.c b/util/cbfstool/fmaptool.c index 961e9dc918..09b68d23bf 100644 --- a/util/cbfstool/fmaptool.c +++ b/util/cbfstool/fmaptool.c @@ -18,53 +18,149 @@ */ #include "common.h" +#include "cbfs_sections.h" #include "fmap_from_fmd.h" #include <stdio.h> #include <string.h> +#include <unistd.h> #define STDIN_FILENAME_SENTINEL "-" +#define HEADER_FMAP_OFFSET "FMAP_OFFSET" + enum fmaptool_return { FMAPTOOL_EXIT_SUCCESS = 0, FMAPTOOL_EXIT_BAD_ARGS, FMAPTOOL_EXIT_BAD_INPUT_PATH, FMAPTOOL_EXIT_BAD_OUTPUT_PATH, FMAPTOOL_EXIT_FAILED_DESCRIPTOR, + FMAPTOOL_EXIT_MISSING_FMAP_SECTION, + FMAPTOOL_EXIT_MISSING_PRIMARY_CBFS, FMAPTOOL_EXIT_FAILED_FMAP_CONVERSION, FMAPTOOL_EXIT_UNKNOWN_FMAP_SIZE, - FMAPTOOL_EXIT_FAILED_WRITING_FILE, + FMAPTOOL_EXIT_FAILED_WRITING_OUTPUT, + FMAPTOOL_EXIT_FAILED_WRITING_HEADER, }; -bool fmd_process_annotation_impl(unused const struct flashmap_descriptor *node, - unused const char *annotation) +static void usage(const char *invoked_as) { - // We always accept annotations, but never act on them. + fputs("fmaptool: Compiler for fmd (flashmap descriptor) files\n", + stderr); + fputs("\nUSAGE:\n", stderr); + fprintf(stderr, + "\t%s [-h <header output file>] <fmd input file> <binary output file>\n", + invoked_as); + fputs("\nMANDATORY ARGUMENTS:\n", stderr); + fprintf(stderr, + "<fmd input file> may be '%s' to read from standard input\n", + STDIN_FILENAME_SENTINEL); + fputs("<binary output file> must be a regular file\n", stderr); + fputs("\nOPTIONAL SWITCHES:\n", stderr); + fprintf(stderr, + "-h\tAlso produce a C header defining %s to the FMAP section's flash offset.\n", + HEADER_FMAP_OFFSET); + fputs("\nOUTPUT:\n", stderr); + fputs("A successful invocation prints a summary of work done to standard error, and a comma-separated list\n", + stderr); + fputs("of those sections that contain CBFSes, starting with the primary such section, to standard output.\n", + stderr); +} + +static void list_cbfs_section_names(void) +{ + cbfs_section_iterator_t cbfs_it = cbfs_sections_iterator(); + assert(cbfs_it); + + bool subsequent = false; + while (cbfs_it) { + const char *cur_name = + cbfs_sections_iterator_deref(cbfs_it)->name; + if (cbfs_sections_iterator_advance(&cbfs_it) && subsequent) + putchar(','); + fputs(cur_name, stdout); + subsequent = true; + } + putchar('\n'); +} + +static bool write_header(const char *out_fname, + const struct flashmap_descriptor *root) +{ + assert(out_fname); + + FILE *header = fopen(out_fname, "w"); + if (!header) { + fprintf(stderr, "FATAL: Unable to open file '%s' for writing\n", + out_fname); + return false; + } + + unsigned fmap_offset = + fmd_calc_absolute_offset(root, SECTION_NAME_FMAP); + assert(fmap_offset != FMD_NOTFOUND); + + fputs("#ifndef FMAPTOOL_GENERATED_HEADER_H_\n", header); + fputs("#define FMAPTOOL_GENERATED_HEADER_H_\n\n", header); + fprintf(header, "#define %s %#x\n\n", HEADER_FMAP_OFFSET, fmap_offset); + fputs("#endif\n", header); + + fclose(header); return true; } +static void full_fmd_cleanup(struct flashmap_descriptor **victim) +{ + assert(victim); + + cbfs_sections_cleanup(); + fmd_cleanup(*victim); + *victim = NULL; +} + int main(int argc, char **argv) { - if (argc != 3) { - fputs("Convert a human-readable flashmap descriptor (fmd) file into the binary FMAP format for use in firmware images\n", - stderr); - fprintf(stderr, - "USAGE: %s <fmd input file> <binary output file>\n", - argv[0]); - fprintf(stderr, - "To read from standard input, provide '%s' as the input filename.\n", - STDIN_FILENAME_SENTINEL); + struct { + // Mandatory + const char *fmd_filename; + const char *fmap_filename; + + // Optional + const char *header_filename; + } args = {NULL, NULL, NULL}; + + bool show_usage = false; + int each_arg; + while (!show_usage && (each_arg = getopt(argc, argv, ":h:")) != -1) { + switch (each_arg) { + case 'h': + args.header_filename = optarg; + break; + case ':': + fprintf(stderr, "-%c: Expected an accompanying value\n", + optopt); + show_usage = true; + break; + default: + fprintf(stderr, "-%c: Unexpected command-line switch\n", + optopt); + show_usage = true; + } + } + + if (show_usage || argc - optind != 2) { + usage(argv[0]); return FMAPTOOL_EXIT_BAD_ARGS; } - const char *fmd_filename = argv[1]; - const char *fmap_filename = argv[2]; + args.fmd_filename = argv[optind]; + args.fmap_filename = argv[optind + 1]; FILE *fmd_file = stdin; - if (strcmp(fmd_filename, STDIN_FILENAME_SENTINEL) != 0) { - fmd_file = fopen(fmd_filename, "r"); + if (strcmp(args.fmd_filename, STDIN_FILENAME_SENTINEL) != 0) { + fmd_file = fopen(args.fmd_filename, "r"); if (!fmd_file) { fprintf(stderr, "FATAL: Unable to open file '%s'\n", - fmd_filename); + args.fmd_filename); return FMAPTOOL_EXIT_BAD_INPUT_PATH; } } @@ -74,14 +170,32 @@ int main(int argc, char **argv) if (!descriptor) { fputs("FATAL: Failed while processing provided descriptor\n", stderr); + full_fmd_cleanup(&descriptor); return FMAPTOOL_EXIT_FAILED_DESCRIPTOR; } + if (!fmd_find_node(descriptor, SECTION_NAME_FMAP)) { + fprintf(stderr, + "FATAL: Flashmap descriptor must have an '%s' section\n", + SECTION_NAME_FMAP); + full_fmd_cleanup(&descriptor); + return FMAPTOOL_EXIT_MISSING_FMAP_SECTION; + } + + if (!cbfs_sections_primary_cbfs_accounted_for()) { + fprintf(stderr, + "FATAL: Flashmap descriptor must have a '%s' section that is annotated with '(%s)'\n", + SECTION_NAME_PRIMARY_CBFS, + SECTION_ANNOTATION_CBFS); + full_fmd_cleanup(&descriptor); + return FMAPTOOL_EXIT_MISSING_PRIMARY_CBFS; + } + struct fmap *flashmap = fmap_from_fmd(descriptor); if (!flashmap) { fputs("FATAL: Failed while constructing FMAP section\n", stderr); - fmd_cleanup(descriptor); + full_fmd_cleanup(&descriptor); return FMAPTOOL_EXIT_FAILED_FMAP_CONVERSION; } @@ -90,16 +204,16 @@ int main(int argc, char **argv) fputs("FATAL: Failed to determine FMAP section size\n", stderr); fmap_destroy(flashmap); - fmd_cleanup(descriptor); + full_fmd_cleanup(&descriptor); return FMAPTOOL_EXIT_UNKNOWN_FMAP_SIZE; } - FILE *fmap_file = fopen(fmap_filename, "wb"); + FILE *fmap_file = fopen(args.fmap_filename, "wb"); if (!fmap_file) { fprintf(stderr, "FATAL: Unable to open file '%s' for writing\n", - fmap_filename); + args.fmap_filename); fmap_destroy(flashmap); - fmd_cleanup(descriptor); + full_fmd_cleanup(&descriptor); return FMAPTOOL_EXIT_BAD_OUTPUT_PATH; } @@ -107,13 +221,24 @@ int main(int argc, char **argv) fputs("FATAL: Failed to write final FMAP to file\n", stderr); fclose(fmap_file); fmap_destroy(flashmap); - fmd_cleanup(descriptor); - return FMAPTOOL_EXIT_FAILED_WRITING_FILE; + full_fmd_cleanup(&descriptor); + return FMAPTOOL_EXIT_FAILED_WRITING_OUTPUT; } fclose(fmap_file); - printf("SUCCESS: Wrote %d bytes to file '%s'\n", size, fmap_filename); - fmap_destroy(flashmap); - fmd_cleanup(descriptor); + + if (args.header_filename && + !write_header(args.header_filename, descriptor)) { + full_fmd_cleanup(&descriptor); + return FMAPTOOL_EXIT_FAILED_WRITING_HEADER; + } + + fprintf(stderr, "SUCCESS: Wrote %d bytes to file '%s'%s\n", size, + args.fmap_filename, + args.header_filename ? " (and generated header)" : ""); + fputs("The sections containing CBFSes are: ", stderr); + list_cbfs_section_names(); + + full_fmd_cleanup(&descriptor); return FMAPTOOL_EXIT_SUCCESS; } |