[coreboot-gerrit] Patch set updated for coreboot: 1663924 fmaptool: Add listing of annotated CBFS sections and generate header

Sol Boucher (solb@chromium.org) gerrit at coreboot.org
Fri May 8 04:43:31 CEST 2015


Sol Boucher (solb at chromium.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/9967

-gerrit

commit 166392432a2c2c208be254ea800678a89d7af0bc
Author: Sol Boucher <solb at chromium.org>
Date:   Wed Mar 18 10:13:48 2015 -0700

    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 at chromium.org>
    Original-Commit-Id: 9227698adecf675770b2983380eb570676c2b5d2
    Original-Change-Id: I8b32f6ef19cabe2f6760106e676683c4565bbaad
    Original-Signed-off-by: Sol Boucher <solb at chromium.org>
    Original-Reviewed-on: https://chromium-review.googlesource.com/262956
    Original-Reviewed-by: Duncan Laurie <dlaurie at chromium.org>
    Original-Reviewed-by: Julius Werner <jwerner at chromium.org>
---
 util/cbfstool/Makefile        |   3 +-
 util/cbfstool/Makefile.inc    |   1 +
 util/cbfstool/cbfs_sections.c | 122 ++++++++++++++++++++++++++++
 util/cbfstool/cbfs_sections.h |  59 ++++++++++++++
 util/cbfstool/fmaptool.c      | 181 +++++++++++++++++++++++++++++++++++-------
 5 files changed, 337 insertions(+), 29 deletions(-)

diff --git a/util/cbfstool/Makefile b/util/cbfstool/Makefile
index 2c63e05..1edb092 100644
--- a/util/cbfstool/Makefile
+++ b/util/cbfstool/Makefile
@@ -22,7 +22,8 @@ CBFSTOOL_COMMON+=lzma/C/LzFind.o  lzma/C/LzmaDec.o  lzma/C/LzmaEnc.o
 CBFSTOOL_COMMON:=$(addprefix $(obj)/,$(CBFSTOOL_COMMON))
 
 FMAPTOOL_BINARY:=$(obj)/fmaptool
-FMAPTOOL_COMMON:=fmap_from_fmd.o fmd.o fmd_parser.o fmd_scanner.o
+FMAPTOOL_COMMON:=cbfs_sections.o fmap_from_fmd.o
+FMAPTOOL_COMMON+=fmd.o fmd_parser.o fmd_scanner.o
 # FMAP
 FMAPTOOL_COMMON+=flashmap/fmap.o
 FMAPTOOL_COMMON+=flashmap/kv_pair.o flashmap/valstr.o
diff --git a/util/cbfstool/Makefile.inc b/util/cbfstool/Makefile.inc
index 7fba6be..bf7e1b8 100644
--- a/util/cbfstool/Makefile.inc
+++ b/util/cbfstool/Makefile.inc
@@ -19,6 +19,7 @@ cbfsobj += cbfs-payload-linux.o
 
 fmapobj :=
 fmapobj += fmaptool.o
+fmapobj += cbfs_sections.o
 fmapobj += fmap_from_fmd.o
 fmapobj += fmd.o
 fmapobj += fmd_parser.o
diff --git a/util/cbfstool/cbfs_sections.c b/util/cbfstool/cbfs_sections.c
new file mode 100644
index 0000000..81912d5
--- /dev/null
+++ b/util/cbfstool/cbfs_sections.c
@@ -0,0 +1,122 @@
+/*
+ * fmap_sections.c, track which sections of the image will contain CBFSes
+ *
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ */
+
+#include "cbfs_sections.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct descriptor_node {
+	const struct flashmap_descriptor *val;
+	struct descriptor_node *next;
+};
+
+static struct descriptor_list {
+	struct descriptor_node *head;
+	struct descriptor_node *tail;
+} cbfs_sections;
+
+static bool seen_primary_section = false;
+
+static void descriptor_list_prepend(struct descriptor_list *list,
+					struct descriptor_node *new_head)
+{
+	assert(list);
+	assert(new_head);
+
+	new_head->next = list->head;
+	list->head = new_head;
+	if (!list->tail)
+		list->tail = new_head;
+}
+
+static void descriptor_list_append(struct descriptor_list *list,
+					struct descriptor_node *new_tail)
+{
+	assert(list);
+	assert(new_tail);
+
+	if (list->tail)
+		list->tail->next = new_tail;
+	list->tail = new_tail;
+	if (!list->head)
+		list->head = new_tail;
+}
+
+/* Implementation of cbfs module's callback; invoked during fmd file parsing */
+bool fmd_process_annotation_impl(const struct flashmap_descriptor *node,
+							const char *annotation)
+{
+	if (strcmp(annotation, SECTION_ANNOTATION_CBFS) == 0 &&
+							node->list_len == 0) {
+		struct descriptor_node *list_node = malloc(sizeof(*list_node));
+		list_node->val = node;
+		list_node->next = NULL;
+
+		if (strcmp(node->name, SECTION_NAME_PRIMARY_CBFS) == 0) {
+			descriptor_list_prepend(&cbfs_sections, list_node);
+			seen_primary_section = true;
+		} else {
+			descriptor_list_append(&cbfs_sections, list_node);
+		}
+
+		return true;
+	}
+
+	return false;
+}
+
+cbfs_section_iterator_t cbfs_sections_iterator(void)
+{
+	return cbfs_sections.head;
+}
+
+bool cbfs_sections_iterator_advance(cbfs_section_iterator_t *it)
+{
+	assert(it);
+	if (!*it)
+		return false;
+
+	*it = (*it)->next;
+	return true;
+}
+
+const struct flashmap_descriptor *cbfs_sections_iterator_deref(
+						cbfs_section_iterator_t it)
+{
+	assert(it);
+	return it->val;
+}
+
+bool cbfs_sections_primary_cbfs_accounted_for(void)
+{
+	return seen_primary_section;
+}
+
+void cbfs_sections_cleanup(void)
+{
+	for (struct descriptor_node *cur = cbfs_sections.head, *next = NULL;
+							cur; cur = next) {
+		next = cur->next;
+		free(cur);
+	}
+	cbfs_sections.head = NULL;
+	cbfs_sections.tail = NULL;
+}
diff --git a/util/cbfstool/cbfs_sections.h b/util/cbfstool/cbfs_sections.h
new file mode 100644
index 0000000..5a23899
--- /dev/null
+++ b/util/cbfstool/cbfs_sections.h
@@ -0,0 +1,59 @@
+/*
+ * fmap_sections.h, track which sections of the image will contain CBFSes
+ *
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ */
+
+#ifndef CBFS_SECTIONS_H_
+#define CBFS_SECTIONS_H_
+
+#include "fmd.h"
+
+#include <stdbool.h>
+
+#define SECTION_NAME_FMAP		"FMAP"
+#define SECTION_NAME_PRIMARY_CBFS	"COREBOOT"
+
+#define SECTION_ANNOTATION_CBFS		"CBFS"
+
+typedef const struct descriptor_node *cbfs_section_iterator_t;
+
+/** @return Iterator pointing to first CBFS section, or NULL if none exist */
+cbfs_section_iterator_t cbfs_sections_iterator(void);
+
+/**
+ * Advance iterator to point to the next CBFS section.
+ * If it was already pointing to the last such section, it will be set to NULL.
+ *
+ * @param it (Non-NULL) pointer to (possibly NULL) iterator to be updated
+ * @return   Whether it was successfully advanced (wasn't already NULL)
+ */
+bool cbfs_sections_iterator_advance(cbfs_section_iterator_t *it);
+
+/**
+ * @param it Iterator, which must currently be non-NULL
+ * @return   Section to which it points
+ */
+const struct flashmap_descriptor *cbfs_sections_iterator_deref(
+						cbfs_section_iterator_t it);
+
+/** @return Whether a section named SECTION_NAME_PRIMARY_CBFS is in the list. */
+bool cbfs_sections_primary_cbfs_accounted_for(void);
+
+/** Reclaim the space used to store knowledge of which sections are CBFSes. */
+void cbfs_sections_cleanup(void);
+
+#endif
diff --git a/util/cbfstool/fmaptool.c b/util/cbfstool/fmaptool.c
index 961e9dc..09b68d2 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;
 }



More information about the coreboot-gerrit mailing list