summaryrefslogtreecommitdiff
path: root/util/cbfstool/fmaptool.c
diff options
context:
space:
mode:
authorSol Boucher <solb@chromium.org>2015-03-18 10:13:48 -0700
committerStefan Reinauer <stefan.reinauer@coreboot.org>2015-05-08 20:33:47 +0200
commit023e8294236d3bd7e39b7af0a4929137c30f089d (patch)
tree4c8904a900d43d86927d8cfb0053727b42d89b63 /util/cbfstool/fmaptool.c
parentb974081c13ad203a78fcdb28021706f55eaa5010 (diff)
fmaptool: Add listing of annotated CBFS sections and generate header
The fmd compiler now processes "(CBFS)" annotations, distilling them into a comma-separated list of the names of sections containing CBFSes. This list is the only thing printed to standard output to enable easy capture and machine consumption by other tools. Additionally, the ability to generate a tiny header with a define for the primary CBFS's size is implemented and can be requested via a new command-line switch. Here's an example of how to use the new features: $ ./fmaptool -h layout.h layout_arm_8192.fmd layout.fmap 2>/dev/null FW_MAIN_A,FW_MAIN_B,COREBOOT The hypothetical fmd file contains three sections annotated as (CBFS), the names of which are printed to standard output. As before, a binary FMAP file named layout.fmap is created; however, because the command was invoked with -h, a header #define ing the offset of its FMAP section (i.e. where it will be relative to the base of flash once the boot image is assembled) is also generated. BUG=chromium:470407 TEST=Verify that fmd files without a "COREBOOT" section or with one that isn't annotated as "(CBFS)" are not accepted. Ensure that the list of CBFS sections matches the descriptor file's annotations and is led by the "COREBOOT" section. Invoke with the header generation switch and check that output file for reasonableness. BRANCH=None Change-Id: I496dd937f69467bfd9233c28df59c7608e89538f Signed-off-by: Sol Boucher <solb@chromium.org> Original-Commit-Id: 9227698adecf675770b2983380eb570676c2b5d2 Original-Change-Id: I8b32f6ef19cabe2f6760106e676683c4565bbaad Original-Signed-off-by: Sol Boucher <solb@chromium.org> Original-Reviewed-on: https://chromium-review.googlesource.com/262956 Original-Reviewed-by: Duncan Laurie <dlaurie@chromium.org> Original-Reviewed-by: Julius Werner <jwerner@chromium.org> Reviewed-on: http://review.coreboot.org/9967 Tested-by: build bot (Jenkins) Reviewed-by: Patrick Georgi <pgeorgi@google.com>
Diffstat (limited to 'util/cbfstool/fmaptool.c')
-rw-r--r--util/cbfstool/fmaptool.c181
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;
}