fmaptool: Introduce the fmd ("flashmap descriptor") language and compiler

This adds a compiler for a language whose textual representation of flashmap
regions will be used to describe the layout of flash chips that contain more
than just a single CBFS. Direct integration with cbfstool (via a new
command-line switch for the create action) is forthcoming but will be added
separately.

BUG=chromium:461875
TEST=Use Chromium OS's cros_bundle_firmware script on the fmap.dts file for
panther. Using the latter file as a reference, write a corresponding
fmap.fmd file and feed it through fmaptool. Run both binary output files
though the flashmap project's own flashmap_decode utility. Observe only
the expected differences.
BRANCH=None

Change-Id: I06b32d138dbef0a4e5ed43c81bd31c796fd5d669
Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Commit-Id: 005ab67eb594e21489cf31036aedaea87e0c7142
Original-Change-Id: Ia08f28688efdbbfc70c255916b8eb7eb0eb07fb2
Original-Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/255031
Original-Reviewed-by: Julius Werner <jwerner@chromium.org>
Original-Reviewed-by: Stefan Reinauer <reinauer@chromium.org>
Reviewed-on: http://review.coreboot.org/9942
Tested-by: build bot (Jenkins)
Reviewed-by: Patrick Georgi <pgeorgi@google.com>
This commit is contained in:
Sol Boucher 2015-02-26 11:47:19 -08:00 committed by Patrick Georgi
parent 5f7e4f019e
commit 69b88bf127
25 changed files with 5259 additions and 164 deletions

1
.gitignore vendored
View File

@ -60,6 +60,7 @@ util/*/.dependencies
util/*/.test
util/board_status/board-status
util/cbfstool/cbfstool
util/cbfstool/fmaptool
util/cbfstool/rmodtool
util/cbmem/.dependencies
util/cbmem/cbmem

View File

@ -285,11 +285,15 @@ build-dirs:
#######################################################################
# Build the tools
CBFSTOOL:=$(objutil)/cbfstool/cbfstool
FMAPTOOL:=$(objutil)/cbfstool/fmaptool
RMODTOOL:=$(objutil)/cbfstool/rmodtool
$(obj)/cbfstool: $(CBFSTOOL)
cp $< $@
$(obj)/fmaptool: $(FMAPTOOL)
cp $< $@
$(obj)/rmodtool: $(RMODTOOL)
cp $< $@
@ -473,7 +477,7 @@ crosstools-riscv: clean-for-update
crossgcc-clean: clean-for-update
$(MAKE) -C util/crossgcc clean
tools: $(objutil)/kconfig/conf $(objutil)/cbfstool/cbfstool $(objutil)/cbfstool/rmodtool $(objutil)/nvramtool/nvramtool $(ROMCC_BIN) $(objutil)/sconfig/sconfig $(IFDTOOL) $(IFDFAKE) $(CBOOTIMAGE)
tools: $(objutil)/kconfig/conf $(CBFSTOOL) $(FMAPTOOL) $(RMODTOOL) $(objutil)/nvramtool/nvramtool $(ROMCC_BIN) $(objutil)/sconfig/sconfig $(IFDTOOL) $(IFDFAKE) $(CBOOTIMAGE)
###########################################################################
# Common recipes for all stages
@ -544,7 +548,7 @@ prebuild-files = \
$(cbfs-add-cmd) $(if $(call extract_nth,5,$(file)),-b $(call extract_nth,5,$(file))) &&))
prebuilt-files = $(foreach file,$(cbfs-files), $(call extract_nth,1,$(file)))
$(obj)/coreboot.pre1: $(objcbfs)/bootblock.bin $$(prebuilt-files) $(CBFSTOOL) $$(cpu_ucode_cbfs_file)
$(obj)/coreboot.pre1: $(objcbfs)/bootblock.bin $$(prebuilt-files) $(FMAPTOOL) $(CBFSTOOL) $$(cpu_ucode_cbfs_file)
$(CBFSTOOL) $@.tmp create \
-B $(objcbfs)/bootblock.bin -a 64 \
$(CBFSTOOL_PRE1_OPTS)

View File

@ -108,15 +108,25 @@ config CCACHE
For details see https://ccache.samba.org.
config FMD_GENPARSER
bool "Generate flashmap descriptor parser using flex and bison"
default n
depends on EXPERT
help
Enable this option if you are working on the flashmap descriptor
parser and made changes to fmd_scanner.l or fmd_parser.y.
Otherwise, say N to use the provided pregenerated scanner/parser.
config SCONFIG_GENPARSER
bool "Generate SCONFIG parser using flex and bison"
default n
depends on EXPERT
help
Enable this option if you are working on the sconfig device tree
parser and made changes to sconfig.l and sconfig.y.
parser and made changes to sconfig.l or sconfig.y.
Otherwise, say N.
Otherwise, say N to use the provided pregenerated scanner/parser.
config USE_OPTION_TABLE
bool "Use CMOS for configuration values"

View File

@ -6,7 +6,9 @@ CFLAGS += -g3
CFLAGS += -std=c99 -Werror -Wall -Wextra
CFLAGS += -Wcast-qual -Wmissing-prototypes -Wredundant-decls -Wshadow
CFLAGS += -Wstrict-prototypes -Wwrite-strings
CPPFLAGS += -D_DEFAULT_SOURCE # memccpy() from string.h
CPPFLAGS += -D_POSIX_C_SOURCE=200809L # strdup() from string.h
CPPFLAGS += -Iflashmap
LDFLAGS += -g3
CBFSTOOL_BINARY:=$(obj)/cbfstool
@ -19,14 +21,28 @@ 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
# FMAP
FMAPTOOL_COMMON+=flashmap/fmap.o
FMAPTOOL_COMMON+=flashmap/kv_pair.o flashmap/valstr.o
FMAPTOOL_COMMON:=$(addprefix $(obj)/,$(FMAPTOOL_COMMON))
RMODTOOL_BINARY:=$(obj)/rmodtool
RMODTOOL_COMMON:=rmodule.o common.o elfheaders.o xdr.o
RMODTOOL_COMMON:=$(addprefix $(obj)/,$(RMODTOOL_COMMON))
FMAPTESTS_BINARY:=$(obj)/flashmap_tests
FMAPTESTS_COMMON:=flashmap/fmap.o flashmap/valstr.o flashmap/kv_pair.o
FMAPTESTS_COMMON:=$(addprefix $(obj)/,$(FMAPTESTS_COMMON))
GENERATED:=fmd_parser.c fmd_parser.h fmd_scanner.c fmd_scanner.h
.PHONY: all
all: .dependencies $(CBFSTOOL_BINARY) $(RMODTOOL_BINARY)
all: .dependencies $(CBFSTOOL_BINARY) $(FMAPTOOL_BINARY) $(RMODTOOL_BINARY)
$(obj)/%: $(obj)/%.o
mkdir -p $(dir $@)
@ -34,27 +50,47 @@ $(obj)/%: $(obj)/%.o
$(obj)/%.o: %.c
mkdir -p $(dir $@)
$(HOSTCC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $<
%.c %.h: %.l
$(LEX) $(LFLAGS) -t --header-file=$*.h $< >$*.c
%.c %.h: %.y
$(YACC) $(YFLAGS) -d $<
mv -f y.tab.c $*.c
mv -f y.tab.h $*.h
.PHONY: clean
clean:
$(RM) $(CBFSTOOL_COMMON) $(CBFSTOOL_BINARY).o $(CBFSTOOL_BINARY)
$(RM) $(FMAPTOOL_COMMON) $(FMAPTOOL_BINARY).o $(FMAPTOOL_BINARY)
$(RM) $(RMODTOOL_COMMON) $(RMODTOOL_BINARY).o $(RMODTOOL_BINARY)
$(RM) $(FMAPTESTS_COMMON) $(FMAPTESTS_BINARY).o $(FMAPTESTS_BINARY)
.PHONY: distclean
distclean: clean
$(RM) .dependencies
.PHONY: maintainer-clean
maintainer-clean: distclean
$(RM) $(GENERATED)
tags:
tags: $(GENERATED)
ctags *.[ch]
.dependencies:
.dependencies: $(GENERATED)
@$(HOSTCC) $(CPPFLAGS) $(CFLAGS) -MM -MG *.c > $@
@$(HOSTCC) $(CPPFLAGS) $(CFLAGS) -MM flashmap/*.c >> $@
@$(HOSTCC) $(CPPFLAGS) $(CFLAGS) -MM lzma/*.c >> $@
@$(HOSTCC) $(CPPFLAGS) $(CFLAGS) -MM lzma/C/*.c >> $@
@sed -i 's|.*:.*|$$(obj)/&|' $@
$(CBFSTOOL_BINARY): $(CBFSTOOL_COMMON)
$(FMAPTOOL_BINARY): $(FMAPTOOL_COMMON)
$(RMODTOOL_BINARY): $(RMODTOOL_COMMON)
# This target must be built manually
$(FMAPTESTS_BINARY): $(FMAPTESTS_COMMON)
# Yacc source is superset of header
$(obj)/fmd_parser.o: CFLAGS += -Wno-redundant-decls
# Lex generates unneeded functions
$(obj)/fmd_scanner.o: CFLAGS += -Wno-unused-function
# Tolerate lzma sdk warnings
$(obj)/lzma/C/LzmaEnc.o: CFLAGS += -Wno-sign-compare -Wno-cast-qual

View File

@ -17,6 +17,17 @@ cbfsobj += LzmaEnc.o
cbfsobj += linux_trampoline.o
cbfsobj += cbfs-payload-linux.o
fmapobj :=
fmapobj += fmaptool.o
fmapobj += fmap_from_fmd.o
fmapobj += fmd.o
fmapobj += fmd_parser.o
fmapobj += fmd_scanner.o
# FMAP
fmapobj += fmap.o
fmapobj += kv_pair.o
fmapobj += valstr.o
rmodobj :=
rmodobj += rmodtool.o
rmodobj += rmodule.o
@ -27,7 +38,9 @@ rmodobj += xdr.o
TOOLCFLAGS ?= -std=c99 -Werror -Wall -Wextra
TOOLCFLAGS += -Wcast-qual -Wmissing-prototypes -Wredundant-decls -Wshadow
TOOLCFLAGS += -Wstrict-prototypes -Wwrite-strings
TOOLCPPFLAGS ?= -D_POSIX_C_SOURCE=200809L # strdup() from string.h
TOOLCPPFLAGS ?= -D_DEFAULT_SOURCE # memccpy() from string.h
TOOLCPPFLAGS += -D_POSIX_C_SOURCE=200809L # strdup() from string.h
TOOLCPPFLAGS += -I$(top)/util/cbfstool/flashmap
TOOLLDFLAGS ?=
ifeq ($(shell uname -s | cut -c-7 2>/dev/null), MINGW32)
@ -38,6 +51,10 @@ $(objutil)/cbfstool/%.o: $(top)/util/cbfstool/%.c
printf " HOSTCC $(subst $(objutil)/,,$(@))\n"
$(HOSTCC) $(TOOLCPPFLAGS) $(TOOLCFLAGS) $(HOSTCFLAGS) -c -o $@ $<
$(objutil)/cbfstool/%.o: $(top)/util/cbfstool/flashmap/%.c
printf " HOSTCC $(subst $(objutil)/,,$(@))\n"
$(HOSTCC) $(TOOLCPPFLAGS) $(TOOLCFLAGS) $(HOSTCFLAGS) -c -o $@ $<
$(objutil)/cbfstool/%.o: $(top)/util/cbfstool/lzma/%.c
printf " HOSTCC $(subst $(objutil)/,,$(@))\n"
$(HOSTCC) $(TOOLCPPFLAGS) $(TOOLCFLAGS) $(HOSTCFLAGS) -c -o $@ $<
@ -50,9 +67,35 @@ $(objutil)/cbfstool/cbfstool: $(addprefix $(objutil)/cbfstool/,$(cbfsobj))
printf " HOSTCC $(subst $(objutil)/,,$(@)) (link)\n"
$(HOSTCC) $(TOOLLDFLAGS) -o $@ $(addprefix $(objutil)/cbfstool/,$(cbfsobj))
$(objutil)/cbfstool/fmaptool: $(addprefix $(objutil)/cbfstool/,$(fmapobj))
printf " HOSTCC $(subst $(objutil)/,,$(@)) (link)\n"
$(HOSTCC) $(TOOLLDFLAGS) -o $@ $(addprefix $(objutil)/cbfstool/,$(fmapobj))
$(objutil)/cbfstool/rmodtool: $(addprefix $(objutil)/cbfstool/,$(rmodobj))
printf " HOSTCC $(subst $(objutil)/,,$(@)) (link)\n"
$(HOSTCC) $(TOOLLDFLAGS) -o $@ $(addprefix $(objutil)/cbfstool/,$(rmodobj))
# Yacc source is superset of header
$(objutil)/cbfstool/fmd_parser.o: TOOLCFLAGS += -Wno-redundant-decls
# Lex generates unneeded functions
$(objutil)/cbfstool/fmd_scanner.o: TOOLCFLAGS += -Wno-unused-function
# Tolerate lzma sdk warnings
$(objutil)/cbfstool/LzmaEnc.o: TOOLCFLAGS += -Wno-sign-compare -Wno-cast-qual
ifeq ($(CONFIG_FMD_GENPARSER),y)
TOOLLEX := lex
TOOLYACC := yacc
$(objutil)/cbfstool/fmd.o: $(top)/util/cbfstool/fmd_parser.c
$(objutil)/cbfstool/fmd.o: $(top)/util/cbfstool/fmd_scanner.c
$(objutil)/cbfstool/fmd_parser.o: $(objutil)/cbfstool/fmd.o
$(objutil)/cbfstool/fmd_scanner.o: $(objutil)/cbfstool/fmd.o
$(top)/util/cbfstool/fmd_scanner.c $(top)/util/cbfstool/fmd_scanner.h: $(top)/util/cbfstool/fmd_scanner.l
echo " LEX util/cbfstool/fmd_scanner.[ch]"
$(TOOLLEX) -t --header-file=$(top)/util/cbfstool/fmd_scanner.h $< >$(top)/util/cbfstool/fmd_scanner.c
$(top)/util/cbfstool/fmd_parser.c $(top)/util/cbfstool/fmd_parser.h: $(top)/util/cbfstool/fmd_parser.y
echo " YACC util/cbfstool/fmd_parser.[ch]"
$(TOOLYACC) -d $<
mv -f y.tab.c $(top)/util/cbfstool/fmd_parser.c
mv -f y.tab.h $(top)/util/cbfstool/fmd_parser.h
endif

View File

@ -0,0 +1,67 @@
Flashmap descriptors in coreboot
================================
Flashmap (https://code.google.com/p/flashmap) is a binary format for representing the layout of
flash chips. Since coreboot is starting to use a "partition" of this format to describe the flash
chip layout---both at runtime and when flashing a new image onto a chip---, the project needed a
reasonably expressive plaintext format for representing such sections in the source tree. Our
solution is the fmd ("flashmap descriptor") language, and the files in this directory contain a
scanner, parser, semantic analyser, and flashmap converter. Here's an informal language description:
# <line comment>
<image name>[@<memory-mapped address>] <image size> {
<section name>[@<offset from start of image>] [<section size>] [{
<subsection name>[@<offset from start of parent section>] [<subsection size>] [{
# Sections can be nested as deeply as desired
<subsubsection name>[(CBFS)][@...] [...] [{...}]
}]
[<subsection name>[(CBFS)][@...] [...] [{...}]]
# There can be many subsections at each level of nesting: they will be inserted
# sequentially, and although gaps are allowed, any provided offsets are always
# relative to the closest parent node's and must be strictly increasing with neither
# overlapping nor degenerate-size sections.
}]
}
Note that the above example contains a few symbols that are actually metasyntax, and therefore have
neither meaning nor place in a real file. The <.*> s indicate placeholders for parameters:
- The names are strings, which are provided as single-word---no whitespace---groups of
syntactically unimportant symbols (i.e. everything except @, {, and }): they are not surrounded
by quotes or any other form of delimiter.
- The other fields are nonnegative integers, which may be given as decimal or hexadecimal; in
either case, a K, M, or G may be appended---without intermediate whitespace---as a multiplier.
- Comments consist of anything one manages to enter, provided it doesn't start a new line.
The [.*] s indicate that a portion of the file could be omitted altogether:
- Just because something is noted as optional doesn't mean it is in every case: the answer might
actually depend on which other information is---or isn't---provided.
- In particular, it is only legal to place a (CBFS) annotation on a leaf section; that is, choosing
to add child sections excludes the possibility of putting a CBFS in their parent. Such
annotations are only used to decide where CBFS empty file headers should be created, and do not
result in the storage of any additional metadata in the resulting FMAP section.
Additionally, it's important to note these properties of the overall file and its values:
- Other than within would-be strings and numbers, whitespace is ignored. It goes without saying
that such power comes with responsibility, which is why this sentence is here.
- Although the .*section names must be globally unique, one of them may---but is not required to---
match the image name.
- It is a syntax error to supply a number---besides 0---that begins with the character 0, as there
is no intention of adding octals to the mix.
- The image's memory address should be present on---and only on---layouts for memory-mapped chips.
- Although it may be evident from above, all .*section offsets are relative only to the immediate
parent. There is no way to include an absolute offset (i.e. from the beginning of flash), which
means that it is "safe" to reorder the .*section s within a particular level of nesting, as long
as the change doesn't cause their positions and sizes to necessitate overlap or zero sizes.
- A .*section with omitted offset is assumed to start at as low a position as possible---with no
consideration of alignment---and one with omitted size is assumed to fill the remaining space
until the next sibling or before the end of its parent.
- It's fine to omit any .*section 's offset, size, or both, provided its position and size are
still unambiguous in the context of its *sibling* sections and its parent's *size*. In
particular, knowledge of one .*section 's children or the .*section s' common parent's siblings
will not be used for this purpose.
- Although .*section s are not required to have children, the flash chip as a whole must have at
least one.
- Though the braces after .*section s may be omitted for those that have no children, if they are
present, they must contain at least one child.
PL people and sympathizers may wish to examine the formal abstract syntax and context-free grammar,
which are located in fmd_scanner.l and fmd_scanner.y, respectively. Those interested in the
algorithm used to infer omitted values will feel at home in fmd.c, particularly near the definition
of validate_and_complete_info().

View File

@ -20,6 +20,7 @@
#ifndef __CBFSTOOL_COMMON_H
#define __CBFSTOOL_COMMON_H
#include <stddef.h>
#include <stdint.h>
#include <assert.h>

View File

@ -1,4 +1,4 @@
/* Copyright 2010, Google Inc.
/* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -49,7 +49,6 @@
#include <valstr.h>
#include "kv_pair.h"
#include "mincrypt/sha.h"
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
@ -60,7 +59,7 @@ const struct valstr flag_lut[] = {
};
/* returns size of fmap data structure if successful, <0 to indicate error */
int fmap_size(struct fmap *fmap)
int fmap_size(const struct fmap *fmap)
{
if (!fmap)
return -1;
@ -71,7 +70,7 @@ int fmap_size(struct fmap *fmap)
/* brute force linear search */
static long int fmap_lsearch(const uint8_t *image, size_t len)
{
long int offset;
unsigned long int offset;
int fmap_found = 0;
for (offset = 0; offset < len - strlen(FMAP_SIGNATURE); offset++) {
@ -86,7 +85,7 @@ static long int fmap_lsearch(const uint8_t *image, size_t len)
if (!fmap_found)
return -1;
if (offset + fmap_size((struct fmap *)&image[offset]) > len)
if (offset + fmap_size((const struct fmap *)&image[offset]) > len)
return -1;
return offset;
@ -95,7 +94,7 @@ static long int fmap_lsearch(const uint8_t *image, size_t len)
/* if image length is a power of 2, use binary search */
static long int fmap_bsearch(const uint8_t *image, size_t len)
{
long int offset = -1;
unsigned long int offset = -1;
int fmap_found = 0, stride;
/*
@ -125,7 +124,7 @@ static long int fmap_bsearch(const uint8_t *image, size_t len)
if (!fmap_found)
return -1;
if (offset + fmap_size((struct fmap *)&image[offset]) > len)
if (offset + fmap_size((const struct fmap *)&image[offset]) > len)
return -1;
return offset;
@ -183,86 +182,42 @@ int fmap_print(const struct fmap *fmap)
kv_pair_free(kv);
for (i = 0; i < fmap->nareas; i++) {
struct kv_pair *kv;
struct kv_pair *pair;
uint16_t flags;
char *str;
kv = kv_pair_new();
if (!kv)
pair = kv_pair_new();
if (!pair)
return -1;
kv_pair_fmt(kv, "area_offset", "0x%08x",
kv_pair_fmt(pair, "area_offset", "0x%08x",
fmap->areas[i].offset);
kv_pair_fmt(kv, "area_size", "0x%08x",
kv_pair_fmt(pair, "area_size", "0x%08x",
fmap->areas[i].size);
kv_pair_fmt(kv, "area_name", "%s",
kv_pair_fmt(pair, "area_name", "%s",
fmap->areas[i].name);
kv_pair_fmt(kv, "area_flags_raw", "0x%02x",
kv_pair_fmt(pair, "area_flags_raw", "0x%02x",
fmap->areas[i].flags);
/* Print descriptive strings for flags rather than the field */
flags = fmap->areas[i].flags;
if ((str = fmap_flags_to_string(flags)) == NULL)
return -1;
kv_pair_fmt(kv, "area_flags", "%s", str );
kv_pair_fmt(pair, "area_flags", "%s", str);
free(str);
kv_pair_print(kv);
kv_pair_free(kv);
kv_pair_print(pair);
kv_pair_free(pair);
}
return 0;
}
/* get SHA1 sum of all static regions described by the flashmap and copy into
*digest (which will be allocated and must be freed by the caller), */
int fmap_get_csum(const uint8_t *image, unsigned int image_len, uint8_t **digest)
{
int i;
struct fmap *fmap;
int fmap_offset;
SHA_CTX ctx;
if ((image == NULL))
return -1;
if ((fmap_offset = fmap_find(image, image_len)) < 0)
return -1;
fmap = (struct fmap *)(image + fmap_offset);
SHA_init(&ctx);
/* Iterate through flash map and calculate the checksum piece-wise. */
for (i = 0; i < fmap->nareas; i++) {
/* skip non-static areas */
if (!(fmap->areas[i].flags & FMAP_AREA_STATIC))
continue;
/* sanity check the offset */
if (fmap->areas[i].size + fmap->areas[i].offset > image_len) {
fprintf(stderr,
"(%s) invalid parameter detected in area %d\n",
__func__, i);
return -1;
}
SHA_update(&ctx,
image + fmap->areas[i].offset,
fmap->areas[i].size);
}
SHA_final(&ctx);
*digest = malloc(SHA_DIGEST_SIZE);
memcpy(*digest, ctx.buf, SHA_DIGEST_SIZE);
return SHA_DIGEST_SIZE;
}
/* convert raw flags field to user-friendly string */
char *fmap_flags_to_string(uint16_t flags)
{
char *str = NULL;
int i, total_size;
unsigned int i, total_size;
str = malloc(1);
str[0] = '\0';
@ -302,8 +257,8 @@ struct fmap *fmap_create(uint64_t base, uint32_t size, uint8_t *name)
memset(fmap, 0, sizeof(*fmap));
memcpy(&fmap->signature, FMAP_SIGNATURE, strlen(FMAP_SIGNATURE));
fmap->ver_major = VERSION_MAJOR;
fmap->ver_minor = VERSION_MINOR;
fmap->ver_major = FMAP_VER_MAJOR;
fmap->ver_minor = FMAP_VER_MINOR;
fmap->base = base;
fmap->size = size;
memccpy(&fmap->name, name, '\0', FMAP_STRLEN);
@ -390,8 +345,8 @@ static struct fmap *fmap_create_test(void)
goto fmap_create_test_exit;
}
if ((fmap->ver_major != VERSION_MAJOR) ||
(fmap->ver_minor != VERSION_MINOR)) {
if ((fmap->ver_major != FMAP_VER_MAJOR) ||
(fmap->ver_minor != FMAP_VER_MINOR)) {
printf("FAILURE: version is incorrect\n");
goto fmap_create_test_exit;
}
@ -431,44 +386,7 @@ static int fmap_print_test(struct fmap *fmap)
return fmap_print(fmap);
}
static int fmap_get_csum_test(struct fmap *fmap)
{
uint8_t *digest = NULL, *image = NULL;
/* assume 0x100-0x10100 is marked "static" and is filled with 0x00 */
int image_size = 0x20000;
uint8_t csum[SHA_DIGEST_SIZE] = {
0x1a, 0xdc, 0x95, 0xbe, 0xbe, 0x9e, 0xea, 0x8c,
0x11, 0x2d, 0x40, 0xcd, 0x04, 0xab, 0x7a, 0x8d,
0x75, 0xc4, 0xf9, 0x61 };
status = fail;
if ((fmap_get_csum(NULL, image_size, &digest) >= 0) ||
(fmap_get_csum(image, image_size, NULL) >= 0)) {
printf("failed to abort on NULL pointer input\n");
goto fmap_get_csum_test_exit;
}
image = calloc(image_size, 1);
memcpy(image, fmap, fmap_size(fmap));
if (fmap_get_csum(image, image_size, &digest) != SHA_DIGEST_SIZE) {
printf("FAILURE: failed to calculate checksum\n");
goto fmap_get_csum_test_exit;
}
if (memcmp(digest, csum, SHA_DIGEST_SIZE)) {
printf("FAILURE: checksum is incorrect\n");
goto fmap_get_csum_test_exit;
}
status = pass;
fmap_get_csum_test_exit:
free(image);
free(digest);
return status;
}
static int fmap_size_test(struct fmap *fmap)
static int fmap_size_test(void)
{
status = fail;
@ -553,10 +471,10 @@ fmap_find_area_test_exit:
return status;
}
static int fmap_flags_to_string_test()
static int fmap_flags_to_string_test(void)
{
char *str, *my_str;
int i;
unsigned int i;
uint16_t flags;
status = fail;
@ -646,11 +564,11 @@ static int fmap_find_test(struct fmap *fmap)
offset = (total_size / 2) + 1;
memcpy(&buf[offset], fmap, fmap_size(fmap));
if (fmap_find(buf, total_size - 1) != offset) {
if ((unsigned)fmap_find(buf, total_size - 1) != offset) {
printf("FAILURE: lsearch failed to find fmap\n");
goto fmap_find_test_exit;
}
if (fmap_find(buf, total_size) != offset) {
if ((unsigned)fmap_find(buf, total_size) != offset) {
printf("FAILURE: bsearch failed to find fmap\n");
goto fmap_find_test_exit;
}
@ -659,7 +577,7 @@ static int fmap_find_test(struct fmap *fmap)
offset = 0;
memset(buf, 0, total_size);
memcpy(buf, fmap, fmap_size(fmap));
if (fmap_find(buf, total_size) != offset) {
if ((unsigned)fmap_find(buf, total_size) != offset) {
printf("FAILURE: bsearch failed to find fmap at offset 0\n");
goto fmap_find_test_exit;
}
@ -684,7 +602,7 @@ fmap_find_test_exit:
return status;
}
int fmap_test()
int fmap_test(void)
{
int rc = EXIT_SUCCESS;
struct fmap *my_fmap;
@ -713,8 +631,7 @@ int fmap_test()
}
rc |= fmap_find_area_test(my_fmap);
rc |= fmap_get_csum_test(my_fmap);
rc |= fmap_size_test(my_fmap);
rc |= fmap_size_test();
rc |= fmap_flags_to_string_test();
rc |= fmap_print_test(my_fmap);

View File

@ -1,5 +1,5 @@
/*
* Copyright 2010, Google Inc.
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -96,24 +96,6 @@ extern long int fmap_find(const uint8_t *image, unsigned int len);
*/
extern int fmap_print(const struct fmap *map);
/*
* fmap_get_csum - get the checksum of static regions of an image
*
* @image: image to checksum
* @len: length of image
* @digest: double-pointer to store location of first byte of digest
*
* fmap_get_csum() will reset, write, and finalize the digest.
* The location of the final digest will start at the location pointed to
* by digest, which will be allocated and must be freed by the caller.
*
* returns digest length if successful
* returns <0 to indicate error
*/
extern int fmap_get_csum(const uint8_t *image,
unsigned int image_len, uint8_t **digest);
/*
* fmap_flags_to_string - convert raw flags field into user-friendly string
*
@ -157,7 +139,7 @@ extern void fmap_destroy(struct fmap *fmap);
* returns size of fmap structure if successful
* returns <0 to indicate failure
*/
extern int fmap_size(struct fmap *fmap);
extern int fmap_size(const struct fmap *fmap);
/*
* fmap_append_area - realloc an existing flashmap and append an area
@ -187,6 +169,6 @@ extern int fmap_append_area(struct fmap **fmap,
extern struct fmap_area *fmap_find_area(struct fmap *fmap, const char *name);
/* unit testing stuff */
extern int fmap_test();
extern int fmap_test(void);
#endif /* FLASHMAP_LIB_FMAP_H__*/

View File

@ -47,7 +47,7 @@ void kv_pair_set_style(enum kv_pair_style style)
_style = style;
}
enum kv_pair_style kv_pair_get_style()
enum kv_pair_style kv_pair_get_style(void)
{
return _style;
}
@ -63,18 +63,6 @@ struct kv_pair *kv_pair_new(void)
return kv;
}
struct kv_pair **kv_pair_new_array(size_t size)
{
struct kv_pair **kv;
size_t i;
kv = (struct kv_pair **) calloc(0, sizeof(kv) * size);
for (i = 0; i < size; ++i) {
kv[i] = kv_pair_new();
}
return kv;
}
struct kv_pair *kv_pair_add(struct kv_pair *kv_list,
const char *key, const char *value)
{
@ -163,15 +151,6 @@ void kv_pair_free(struct kv_pair *kv_list)
}
}
void kv_pair_free_array(struct kv_pair **kv_array, size_t size)
{
size_t i;
for (i = 0; i < size; ++i) {
kv_pair_free(kv_array[i]);
}
free(kv_array);
}
void kv_pair_print_to_file(FILE* fp, struct kv_pair *kv_list,
enum kv_pair_style style)
{

View File

@ -56,7 +56,7 @@ struct kv_pair {
struct kv_pair *next;
};
extern enum kv_pair_style kv_pair_get_style();
extern enum kv_pair_style kv_pair_get_style(void);
extern void kv_pair_set_style(enum kv_pair_style style);

View File

@ -31,6 +31,7 @@
#include <inttypes.h>
#include <string.h>
#include <strings.h>
#include <valstr.h>

View File

@ -0,0 +1,37 @@
/*
* fmap_from_fmd.c, simple launcher for fmap library unit test suite
*
* 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 "flashmap/fmap.h"
#include <stdio.h>
int main(void)
{
int result = fmap_test();
puts("");
puts("===");
puts("");
if (!result)
puts("RESULT: All unit tests PASSED.");
else
puts("RESULT: One or more tests FAILED!");
return result;
}

View File

@ -0,0 +1,83 @@
/*
* fmap_from_fmd.c, tool to distill flashmap descriptors into raw FMAP sections
*
* 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 "fmap_from_fmd.h"
#include "common.h"
#include <assert.h>
#include <string.h>
static bool fmap_append_fmd_node(struct fmap **flashmap,
const struct flashmap_descriptor *section,
unsigned absolute_watermark) {
if (strlen(section->name) >= FMAP_STRLEN) {
fprintf(stderr,
"ERROR: Section name ('%s') exceeds %d character FMAP format limit\n",
section->name, FMAP_STRLEN - 1);
return false;
}
absolute_watermark += section->offset;
if (fmap_append_area(flashmap, absolute_watermark, section->size,
(uint8_t *)section->name, 0) < 0) {
fprintf(stderr,
"ERROR: Failed to insert section '%s' into FMAP\n",
section->name);
return false;
}
fmd_foreach_child(subsection, section) {
if (!fmap_append_fmd_node(flashmap, subsection,
absolute_watermark))
return false;
}
return true;
}
struct fmap *fmap_from_fmd(const struct flashmap_descriptor *desc)
{
assert(desc);
assert(desc->size_known);
if (strlen(desc->name) >= FMAP_STRLEN) {
fprintf(stderr,
"ERROR: Image name ('%s') exceeds %d character FMAP header limit\n",
desc->name, FMAP_STRLEN - 1);
return NULL;
}
struct fmap *fmap = fmap_create(desc->offset_known ? desc->offset : 0,
desc->size, (uint8_t *)desc->name);
if (!fmap) {
fputs("ERROR: Failed to allocate FMAP header\n", stderr);
return fmap;
}
fmd_foreach_child(real_section, desc) {
if (!fmap_append_fmd_node(&fmap, real_section, 0)) {
fmap_destroy(fmap);
return NULL;
}
}
return fmap;
}

View File

@ -0,0 +1,33 @@
/*
* fmap_from_fmd.h, tool to distill flashmap descriptors into raw FMAP sections
*
* 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 FMAP_FROM_FMD_H_
#define FMAP_FROM_FMD_H_
#include "flashmap/fmap.h"
#include "fmd.h"
/**
* @param desc The descriptor tree serving as a data source
* @return The FMAP section, which is also owned by the caller and must
* later be released with a call to fmap_destroy()
*/
struct fmap *fmap_from_fmd(const struct flashmap_descriptor *desc);
#endif

119
util/cbfstool/fmaptool.c Normal file
View File

@ -0,0 +1,119 @@
/*
* fmaptool, CLI utility for converting plaintext fmd files into fmap blobs
*
* 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 "common.h"
#include "fmap_from_fmd.h"
#include <stdio.h>
#include <string.h>
#define STDIN_FILENAME_SENTINEL "-"
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_FAILED_FMAP_CONVERSION,
FMAPTOOL_EXIT_UNKNOWN_FMAP_SIZE,
FMAPTOOL_EXIT_FAILED_WRITING_FILE,
};
bool fmd_process_annotation_impl(unused const struct flashmap_descriptor *node,
unused const char *annotation)
{
// We always accept annotations, but never act on them.
return true;
}
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);
return FMAPTOOL_EXIT_BAD_ARGS;
}
const char *fmd_filename = argv[1];
const char *fmap_filename = argv[2];
FILE *fmd_file = stdin;
if (strcmp(fmd_filename, STDIN_FILENAME_SENTINEL) != 0) {
fmd_file = fopen(fmd_filename, "r");
if (!fmd_file) {
fprintf(stderr, "FATAL: Unable to open file '%s'\n",
fmd_filename);
return FMAPTOOL_EXIT_BAD_INPUT_PATH;
}
}
struct flashmap_descriptor *descriptor = fmd_create(fmd_file);
fclose(fmd_file);
if (!descriptor) {
fputs("FATAL: Failed while processing provided descriptor\n",
stderr);
return FMAPTOOL_EXIT_FAILED_DESCRIPTOR;
}
struct fmap *flashmap = fmap_from_fmd(descriptor);
if (!flashmap) {
fputs("FATAL: Failed while constructing FMAP section\n",
stderr);
fmd_cleanup(descriptor);
return FMAPTOOL_EXIT_FAILED_FMAP_CONVERSION;
}
int size = fmap_size(flashmap);
if (size < 0) {
fputs("FATAL: Failed to determine FMAP section size\n",
stderr);
fmap_destroy(flashmap);
fmd_cleanup(descriptor);
return FMAPTOOL_EXIT_UNKNOWN_FMAP_SIZE;
}
FILE *fmap_file = fopen(fmap_filename, "wb");
if (!fmap_file) {
fprintf(stderr, "FATAL: Unable to open file '%s' for writing\n",
fmap_filename);
fmap_destroy(flashmap);
fmd_cleanup(descriptor);
return FMAPTOOL_EXIT_BAD_OUTPUT_PATH;
}
if (!fwrite(flashmap, size, 1, fmap_file)) {
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;
}
fclose(fmap_file);
printf("SUCCESS: Wrote %d bytes to file '%s'\n", size, fmap_filename);
fmap_destroy(flashmap);
fmd_cleanup(descriptor);
return FMAPTOOL_EXIT_SUCCESS;
}

401
util/cbfstool/fmd.c Normal file
View File

@ -0,0 +1,401 @@
/*
* fmd.c, parser frontend and utility functions for flashmap descriptor language
*
* 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 "fmd.h"
#include "fmd_parser.h"
#include "fmd_scanner.h"
#include "option.h"
#include <assert.h>
#include <search.h>
#include <string.h>
/*
* Validate the given flashmap descriptor node's properties. In particular:
* - Ensure its name is globally unique.
* - Ensure its offset, if known, isn't located before the end of the previous
* section, if this can be determined.
* - Ensure its offset, if known, isn't located after the beginning of the next
* section or off the end of its parent section, if this can be determined.
* - Ensure its size is nonzero.
* - Ensure that the combination of its size and offset, if they are both
* known, doesn't place its end after the beginning of the next section or
* off the end of its parent section, if this can be determined.
* In the case of a validation error, the particular problem is reported to
* standard error and this function returns false. It should be noted that this
* function makes no claim that the members of the node's child list are valid:
* under no circumstances is any recursive validation performed.
*
* @param node The flashmap descriptor node to be validated
* @param start Optional minimum permissible base of the section to be
* validated, to be provided if known
* @param end Optional maximum permissible offset to the end of the section to
* be validated, to be provided if known
* @return Whether the node is valid
*/
static bool validate_descriptor_node(const struct flashmap_descriptor *node,
struct unsigned_option start, struct unsigned_option end) {
assert(node);
ENTRY search_key = {node->name, NULL};
if (hsearch(search_key, FIND)) {
fprintf(stderr, "ERROR: Multiple sections with name '%s'\n",
node->name);
return false;
}
if (!hsearch(search_key, ENTER))
assert(false);
if (node->offset_known) {
if (start.val_known && node->offset < start.val) {
fprintf(stderr, "ERROR: Section '%s' starts too low\n",
node->name);
return false;
} else if (end.val_known && node->offset > end.val) {
fprintf(stderr, "ERROR: Section '%s' starts too high\n",
node->name);
return false;
}
}
if (node->size_known) {
if (node->size == 0) {
fprintf(stderr, "ERROR: Section '%s' given no space\n",
node->name);
return false;
} else if (node->offset_known) {
unsigned node_end = node->offset + node->size;
if (end.val_known && node_end > end.val) {
fprintf(stderr, "ERROR: Section '%s' too big\n",
node->name);
return false;
}
}
}
return true;
}
/*
* Performs reverse lateral processing of sibling nodes, as described by the
* documentation of its caller, validate_and_complete_info(). If it encounters
* a node that is invalid in a way that couldn't have been discovered earlier,
* it explains the problem to standard output and returns false.
*
* @param first_incomplete_it First node whose offset or size couldn't be
* determined during forward processing
* @param cur_incomplete_it Last node whose offset or size is unknown
* @param end_watermark Offset to the end of the unresolved region
* @return Whether all completed nodes were still valid
*/
static bool complete_missing_info_backward(
flashmap_descriptor_iterator_t first_incomplete_it,
flashmap_descriptor_iterator_t cur_incomplete_it,
unsigned end_watermark)
{
assert(first_incomplete_it);
assert(cur_incomplete_it);
assert(cur_incomplete_it >= first_incomplete_it);
do {
struct flashmap_descriptor *cur = *cur_incomplete_it;
assert(cur->offset_known || cur->size_known);
if (!cur->offset_known) {
if (cur->size > end_watermark) {
fprintf(stderr, "ERROR: Section '%s' too big\n",
cur->name);
return false;
}
cur->offset_known = true;
cur->offset = end_watermark -= cur->size;
} else if (!cur->size_known) {
if (cur->offset > end_watermark) {
fprintf(stderr,
"ERROR: Section '%s' starts too high\n",
cur->name);
return false;
}
cur->size_known = true;
cur->size = end_watermark - cur->offset;
end_watermark = cur->offset;
}
} while (--cur_incomplete_it >= first_incomplete_it);
return true;
}
/*
* Recursively examine each descendant of the provided flashmap descriptor node
* to ensure its position and size are known, attempt to infer them otherwise,
* and validate their values once they've been populated.
* This processes nodes according to the following algorithm:
* - At each level of the tree, it moves laterally between siblings, keeping
* a watermark of its current offset relative to the previous section, which
* it uses to fill in any unknown offsets it encounters along the way.
* - The first time it encounters a sibling with unknown size, it loses track
* of the watermark, and is therefore unable to complete further offsets;
* instead, if the watermark was known before, it marks the current node as
* the first that couldn't be completed in the initial pass.
* - If the current watermark is unknown (i.e. a node has been marked as the
* first incomplete one) and one with a fixed offset is encountered, a
* reverse lateral traversal is dispatched that uses that provided offset as
* a reverse watermark to complete all unknown fields until it finishes with
* the node marked as the first incomplete one: at this point, that flag is
* cleared, the watermark is updated, and forward processing resumes from
* where it left off.
* - If the watermark is unknown (i.e. node(s) are incomplete) after traversing
* all children of a particular parent node, reverse processing is employed
* as described above, except that the reverse watermark is initialized to
* the parent node's size instead of the (nonexistent) next node's offset.
* - Once all of a node's children have been processed, the algorithm applies
* itself recursively to each of the child nodes; thus, lower levels of the
* tree are processed only after their containing levels are finished.
* This approach can fail in two possible ways (in which case the problem is
* reported to standard output and this function returns false):
* - Processing reveals that some node's provided value is invalid in some way.
* - Processing determines that one or more provided values require an omitted
* field to take a nonsensical value.
* - Processing determines that it is impossible to determine a group of
* omitted values. This state is detected when a node whose offset *and*
* value are omitted is encountered during forward processing and while the
* current watermark is unknown: in such a case, neither can be known without
* being provided with either the other or more context.
* The function notably performs neither validation nor completion on the parent
* node it is passed; thus, it is important to ensure that that node is valid.
* (At the very least, it must have a valid size field in order for the
* algorithm to work on its children.)
*
* @param cur_level Parent node, which must minimally already have a valid size
* @return Whether completing and validating the children succeeded
*/
static bool validate_and_complete_info(struct flashmap_descriptor *cur_level)
{
assert(cur_level);
assert(cur_level->size_known);
// Our watermark is only known when first_incomplete_it is NULL.
flashmap_descriptor_iterator_t first_incomplete_it = NULL;
unsigned watermark = 0;
fmd_foreach_child_iterator(cur_it, cur_level) {
struct flashmap_descriptor *cur_section = *cur_it;
if (first_incomplete_it) {
if (cur_section->offset_known) {
if (complete_missing_info_backward(
first_incomplete_it, cur_it - 1,
cur_section->offset)) {
first_incomplete_it = NULL;
watermark = cur_section->offset;
} else {
return false;
}
}
// Otherwise, we can't go back until a provided offset.
} else if (!cur_section->offset_known) {
cur_section->offset_known = true;
cur_section->offset = watermark;
}
assert(cur_level->size_known);
struct unsigned_option max_endpoint = {true, cur_level->size};
if (cur_it != cur_level->list + cur_level->list_len - 1) {
struct flashmap_descriptor *next_section = cur_it[1];
max_endpoint.val_known = next_section->offset_known;
max_endpoint.val = next_section->offset;
}
if (!validate_descriptor_node(cur_section,
(struct unsigned_option)
{!first_incomplete_it, watermark},
max_endpoint))
return false;
if (!cur_section->size_known) {
if (!cur_section->offset_known) {
fprintf(stderr,
"ERROR: Cannot determine either offset or size of section '%s'\n",
cur_section->name);
return false;
} else if (!first_incomplete_it) {
first_incomplete_it = cur_it;
} else {
// We shouldn't find an unknown size within an
// incomplete region because the backward
// traversal at the beginning of this node's
// processing should have concluded said region.
assert(!first_incomplete_it);
}
} else if (!first_incomplete_it) {
watermark = cur_section->offset + cur_section->size;
}
}
if (first_incomplete_it &&
!complete_missing_info_backward(first_incomplete_it,
cur_level->list + cur_level->list_len - 1,
cur_level->size))
return false;
fmd_foreach_child(cur_section, cur_level) {
assert(cur_section->offset_known);
assert(cur_section->size_known);
if (!validate_and_complete_info(cur_section))
return false;
}
return true;
}
static void print_with_prefix(const struct flashmap_descriptor *tree,
const char *pre)
{
assert(tree);
assert(pre);
printf("%ssection '%s' has ", pre, tree->name);
if (tree->offset_known)
printf("offset %uB, ", tree->offset);
else
fputs("unknown offset, ", stdout);
if (tree->size_known)
printf("size %uB, ", tree->size);
else
fputs("unknown size, ", stdout);
printf("and %zu subsections", tree->list_len);
if (tree->list_len) {
puts(":");
char child_prefix[strlen(pre) + 1];
strcpy(child_prefix, pre);
strcat(child_prefix, "\t");
fmd_foreach_child(each, tree)
print_with_prefix(each, child_prefix);
} else {
puts("");
}
}
struct flashmap_descriptor *fmd_create(FILE *stream)
{
assert(stream);
yyin = stream;
struct flashmap_descriptor *ret = NULL;
if (yyparse() == 0)
ret = res;
yylex_destroy();
yyin = NULL;
res = NULL;
if (ret) {
// This hash table is used to store the declared name of each
// section and ensure that each is globally unique.
if (!hcreate(fmd_count_nodes(ret))) {
perror("ERROR: While initializing hashtable");
fmd_cleanup(ret);
return NULL;
}
// Even though we haven't checked that the root node (ret) has
// a size field as required by this function, the parser
// warrants that it does because the grammar requires it.
if (!validate_and_complete_info(ret)) {
hdestroy();
fmd_cleanup(ret);
return NULL;
}
hdestroy();
}
return ret;
}
void fmd_cleanup(struct flashmap_descriptor *victim)
{
if (!victim)
return;
free(victim->name);
for (unsigned idx = 0; idx < victim->list_len; ++idx)
fmd_cleanup(victim->list[idx]);
free(victim->list);
free(victim);
}
size_t fmd_count_nodes(const struct flashmap_descriptor *tree)
{
assert(tree);
if (!tree->list_len)
return 1;
unsigned count = 1;
fmd_foreach_child(lower, tree)
count += fmd_count_nodes(lower);
return count;
}
const struct flashmap_descriptor *fmd_find_node(
const struct flashmap_descriptor *root, const char *name)
{
assert(root);
assert(name);
if (strcmp(root->name, name) == 0)
return root;
fmd_foreach_child(descendant, root) {
const struct flashmap_descriptor *match =
fmd_find_node(descendant, name);
if (match)
return match;
}
return NULL;
}
unsigned fmd_calc_absolute_offset(const struct flashmap_descriptor *root,
const char *name)
{
assert(root);
assert(name);
if (strcmp(root->name, name) == 0)
return 0;
fmd_foreach_child(descendant, root) {
unsigned subtotal = fmd_calc_absolute_offset(descendant, name);
if (subtotal != FMD_NOTFOUND)
return descendant->offset + subtotal;
}
return FMD_NOTFOUND;
}
void fmd_print(const struct flashmap_descriptor *tree)
{
print_with_prefix(tree, "");
}

143
util/cbfstool/fmd.h Normal file
View File

@ -0,0 +1,143 @@
/*
* fmd.h, parser frontend and utility functions for flashmap descriptor language
*
* 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 FMD_H_
#define FMD_H_
#include <limits.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#define FMD_NOTFOUND UINT_MAX
struct flashmap_descriptor {
char *name;
bool offset_known;
/**
* Offset relative to that of the parent node.
* Exception: for the root node in the descriptor tree, it is optional.
* In this case, if absent, it indicates that the flash chip will not be
* memory mapped at runtime; otherwise, its value indicates the base
* address of the flash chip in the virtual address space rather than
* representing an offset into the flash image itself.
* It is an error to read this field unless offset_known is set.
*/
unsigned offset;
bool size_known;
/** It is an error to read this field unless size_known is set. */
unsigned size;
size_t list_len;
/** It is an error to dereference this array if list_len is 0. */
struct flashmap_descriptor **list;
};
/**
* **Client-defined** callback.
* This call is used to notify client code that the user has annotated the given
* section node by accompanying it with a string enclosed in parentheses. It is
* only invoked for nodes that have annotations, and then only once per node.
* The annotations' syntactic validity and semantic meaning are not determined
* by the compiler; rather, implementations of this function should use their
* return type to tell the compiler whether the annotation was valid syntax, as
* well as perform whatever actions are necessary given the particular
* annotation. It's worth reiterating that this is only called on section nodes,
* and will never be called with the final, complete flashmap_descriptor because
* it is impossible to annotate the image as a whole. Note that, although the
* node received by this function will be preserved in memory as part of the
* ultimate flashmap_descriptor, the annotation string will only persist during
* this function call: if the implementation needs it longer, it must copy it.
*
* @param flashmap_descriptor The section node carrying the annotation
* @param annotation What the user wrote (only valid during callback)
* @return Whether this annotation represented valid syntax
*/
bool fmd_process_annotation_impl(const struct flashmap_descriptor *node,
const char *annotation);
/**
* Parse and validate a flashmap descriptor from the specified stream.
* As part of this process, any fields that were omitted in the input are
* inferred from whatever information is known, if possible. The result is a
* tree with all its offset and size fields filled, except possibly the former
* part of the root node in the case of non--memory mapped flash. If a syntax
* error causes the parser to fail, or if there is not enough information given
* in the input file to determine any single missing value, the specific error
* is reported to standard error and this function returns NULL.
*
* @param stream File from which to read the (partial) flashmap descriptor
* @return Populated flashmap descriptor tree, or NULL on failure
*/
struct flashmap_descriptor *fmd_create(FILE *stream);
/** @param victim Valid descriptor tree to be cleaned up, or NULL for no-op */
void fmd_cleanup(struct flashmap_descriptor *victim);
/**
* @param tree Must be non-NULL
* @return The number of nodes in the tree, including the root
*/
size_t fmd_count_nodes(const struct flashmap_descriptor *tree);
/**
* @param root The flashmap descriptor to search
* @param name The name of the sought-after section
* @return The desired section node, or NULL if none was found
*/
const struct flashmap_descriptor *fmd_find_node(
const struct flashmap_descriptor *root, const char *name);
/**
* @param root Parent node to whose start the "absolute" offset will be relative
* @param name The name of the node whose offset to determine
* @return The "absolute" offset, or FMD_NOTFOUND if the node wasn't found
*/
unsigned fmd_calc_absolute_offset(const struct flashmap_descriptor *root,
const char *name);
/** @param tree Must be non-NULL */
void fmd_print(const struct flashmap_descriptor *tree);
typedef struct flashmap_descriptor **flashmap_descriptor_iterator_t;
/*
* Run the subsequent statement once on each descendant of the specified node.
*
* @param iterator A flashmap_descriptor_iterator_t (automatically declared)
* @param parent The parent node of those over which the loop should iterate
*/
#define fmd_foreach_child_iterator(iterator, parent) \
for (flashmap_descriptor_iterator_t iterator = parent->list; \
iterator < parent->list + parent->list_len; ++iterator)
/*
* Run the subsequent statement once on each descendant of the specified node.
*
* @param child A struct flashmap_descriptor * (automatically declared)
* @param parent The parent node of those over which the loop should iterate
*/
#define fmd_foreach_child(child, parent) \
for (struct flashmap_descriptor **fmd_foreach_child_iterator_ = \
parent->list, *child = NULL; \
fmd_foreach_child_iterator_ < \
parent->list + parent->list_len && \
(child = *fmd_foreach_child_iterator_); \
++fmd_foreach_child_iterator_)
#endif

1647
util/cbfstool/fmd_parser.c Normal file

File diff suppressed because it is too large Load Diff

109
util/cbfstool/fmd_parser.h Normal file
View File

@ -0,0 +1,109 @@
/* A Bison parser, made by GNU Bison 3.0.2. */
/* Bison interface for Yacc-like parsers in C
Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, 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, either version 3 of the License, or
(at your option) any later version.
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, see <http://www.gnu.org/licenses/>. */
/* As a special exception, you may create a larger work that contains
part or all of the Bison parser skeleton and distribute that work
under terms of your choice, so long as that work isn't itself a
parser generator using the skeleton or a modified version thereof
as a parser skeleton. Alternatively, if you modify or redistribute
the parser skeleton itself, you may (at your option) remove this
special exception, which will cause the skeleton and the resulting
Bison output files to be licensed under the GNU General Public
License without this special exception.
This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */
#ifndef YY_YY_Y_TAB_H_INCLUDED
# define YY_YY_Y_TAB_H_INCLUDED
/* Debug traces. */
#ifndef YYDEBUG
# define YYDEBUG 0
#endif
#if YYDEBUG
extern int yydebug;
#endif
/* "%code requires" blocks. */
#line 36 "fmd_parser.y" /* yacc.c:1909 */
#include "fmd.h"
#include "option.h"
#include <stdbool.h>
struct descriptor_node {
struct flashmap_descriptor *val;
struct descriptor_node *next;
};
struct descriptor_list {
size_t len;
struct descriptor_node *head;
struct descriptor_node *tail;
};
extern struct flashmap_descriptor *res;
struct flashmap_descriptor *parse_descriptor(char *name,
struct unsigned_option offset, struct unsigned_option size,
struct descriptor_list children);
void yyerror(const char *s);
#line 69 "y.tab.h" /* yacc.c:1909 */
/* Token type. */
#ifndef YYTOKENTYPE
# define YYTOKENTYPE
enum yytokentype
{
INTEGER = 258,
OCTAL = 259,
STRING = 260
};
#endif
/* Tokens. */
#define INTEGER 258
#define OCTAL 259
#define STRING 260
/* Value type. */
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef union YYSTYPE YYSTYPE;
union YYSTYPE
{
#line 28 "fmd_parser.y" /* yacc.c:1909 */
unsigned intval;
char *strval;
struct unsigned_option maybe_intval;
struct flashmap_descriptor *region_ptr;
struct descriptor_list region_listhdr;
#line 99 "y.tab.h" /* yacc.c:1909 */
};
# define YYSTYPE_IS_TRIVIAL 1
# define YYSTYPE_IS_DECLARED 1
#endif
extern YYSTYPE yylval;
int yyparse (void);
#endif /* !YY_YY_Y_TAB_H_INCLUDED */

190
util/cbfstool/fmd_parser.y Normal file
View File

@ -0,0 +1,190 @@
/*
* fmd_parser.y, parser generator for flashmap descriptor language
*
* 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 "fmd_scanner.h"
#include <stdlib.h>
struct flashmap_descriptor *res = NULL;
%}
%union {
unsigned intval;
char *strval;
struct unsigned_option maybe_intval;
struct flashmap_descriptor *region_ptr;
struct descriptor_list region_listhdr;
}
%code requires {
#include "fmd.h"
#include "option.h"
#include <stdbool.h>
struct descriptor_node {
struct flashmap_descriptor *val;
struct descriptor_node *next;
};
struct descriptor_list {
size_t len;
struct descriptor_node *head;
struct descriptor_node *tail;
};
extern struct flashmap_descriptor *res;
struct flashmap_descriptor *parse_descriptor(char *name,
struct unsigned_option offset, struct unsigned_option size,
struct descriptor_list children);
void yyerror(const char *s);
}
%token <intval> INTEGER
%token OCTAL
%token <strval> STRING
%type <region_ptr> flash_region
%type <strval> region_name
%type <strval> region_annotation_opt
%type <strval> region_annotation
%type <maybe_intval> region_offset_opt
%type <maybe_intval> region_offset
%type <maybe_intval> region_size_opt
%type <maybe_intval> region_size
%type <region_listhdr> region_list_opt
%type <region_listhdr> region_list
%type <region_listhdr> region_list_entries
%%
flash_chip: region_name region_offset_opt region_size region_list
{
if (!(res = parse_descriptor($1, $2, $3, $4)))
YYABORT;
};
flash_region: region_name region_annotation_opt region_offset_opt
region_size_opt region_list_opt
{
struct flashmap_descriptor *node = parse_descriptor($1, $3, $4, $5);
if (!node)
YYABORT;
char *annotation = $2;
if (annotation && !fmd_process_annotation_impl(node, annotation)) {
fprintf(stderr, "ERROR: Section '%s' has unexpected annotation '(%s)'\n",
node->name, annotation);
YYABORT;
}
free(annotation);
$$ = node;
};
region_name: STRING
{
if (!$1) {
perror("ERROR: While allocating section name");
YYABORT;
}
};
region_annotation_opt: { $$ = NULL; }
| region_annotation;
region_annotation: '(' STRING ')' { $$ = $2; };
region_offset_opt: { $$ = (struct unsigned_option){false, 0}; }
| region_offset;
region_offset: '@' INTEGER { $$ = (struct unsigned_option){true, $2}; };
region_size_opt: { $$ = (struct unsigned_option){false, 0}; }
| region_size;
region_size: INTEGER { $$ = (struct unsigned_option){true, $1}; };
region_list_opt:
{
$$ = (struct descriptor_list)
{.len = 0, .head = NULL, .tail = NULL};
}
| region_list;
region_list: '{' region_list_entries '}' { $$ = $2; };
region_list_entries: flash_region
{
struct descriptor_node *node = malloc(sizeof(*node));
if (!node) {
perror("ERROR: While allocating linked list node");
YYABORT;
}
node->val = $1;
node->next = NULL;
$$ = (struct descriptor_list){.len = 1, .head = node, .tail = node};
}
| region_list_entries flash_region
{
struct descriptor_node *node = malloc(sizeof(*node));
if (!node) {
perror("ERROR: While allocating linked list node");
YYABORT;
}
node->val = $2;
node->next = NULL;
$1.tail->next = node;
$$ = (struct descriptor_list)
{.len = $1.len + 1, .head = $1.head, .tail = node};
};
%%
struct flashmap_descriptor *parse_descriptor(char *name,
struct unsigned_option offset, struct unsigned_option size,
struct descriptor_list children)
{
struct flashmap_descriptor *region = malloc(sizeof(*region));
if (!region) {
perror("ERROR: While allocating descriptor section");
return NULL;
}
region->name = name;
region->offset_known = offset.val_known;
region->offset = offset.val;
region->size_known = size.val_known;
region->size = size.val;
region->list_len = children.len;
if (region->list_len) {
region->list = malloc(region->list_len * sizeof(*region->list));
if (!region->list) {
perror("ERROR: While allocating node children array");
return NULL;
}
struct descriptor_node *cur_node = children.head;
for (unsigned idx = 0; idx < region->list_len; ++idx) {
region->list[idx] = cur_node->val;
struct descriptor_node *next_node = cur_node->next;
free(cur_node);
cur_node = next_node;
}
} else {
region->list = NULL;
}
return region;
}
void yyerror(const char *s)
{
fprintf(stderr, "%s\n", s);
}

1852
util/cbfstool/fmd_scanner.c Normal file

File diff suppressed because it is too large Load Diff

333
util/cbfstool/fmd_scanner.h Normal file
View File

@ -0,0 +1,333 @@
#ifndef yyHEADER_H
#define yyHEADER_H 1
#define yyIN_HEADER 1
#line 6 "fmd_scanner.h"
#define YY_INT_ALIGNED short int
/* A lexical scanner generated by flex */
#define FLEX_SCANNER
#define YY_FLEX_MAJOR_VERSION 2
#define YY_FLEX_MINOR_VERSION 5
#define YY_FLEX_SUBMINOR_VERSION 39
#if YY_FLEX_SUBMINOR_VERSION > 0
#define FLEX_BETA
#endif
/* First, we deal with platform-specific or compiler-specific issues. */
/* begin standard C headers. */
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
/* end standard C headers. */
/* flex integer type definitions */
#ifndef FLEXINT_H
#define FLEXINT_H
/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
* if you want the limit (max/min) macros for int types.
*/
#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS 1
#endif
#include <inttypes.h>
typedef int8_t flex_int8_t;
typedef uint8_t flex_uint8_t;
typedef int16_t flex_int16_t;
typedef uint16_t flex_uint16_t;
typedef int32_t flex_int32_t;
typedef uint32_t flex_uint32_t;
#else
typedef signed char flex_int8_t;
typedef short int flex_int16_t;
typedef int flex_int32_t;
typedef unsigned char flex_uint8_t;
typedef unsigned short int flex_uint16_t;
typedef unsigned int flex_uint32_t;
/* Limits of integral types. */
#ifndef INT8_MIN
#define INT8_MIN (-128)
#endif
#ifndef INT16_MIN
#define INT16_MIN (-32767-1)
#endif
#ifndef INT32_MIN
#define INT32_MIN (-2147483647-1)
#endif
#ifndef INT8_MAX
#define INT8_MAX (127)
#endif
#ifndef INT16_MAX
#define INT16_MAX (32767)
#endif
#ifndef INT32_MAX
#define INT32_MAX (2147483647)
#endif
#ifndef UINT8_MAX
#define UINT8_MAX (255U)
#endif
#ifndef UINT16_MAX
#define UINT16_MAX (65535U)
#endif
#ifndef UINT32_MAX
#define UINT32_MAX (4294967295U)
#endif
#endif /* ! C99 */
#endif /* ! FLEXINT_H */
#ifdef __cplusplus
/* The "const" storage-class-modifier is valid. */
#define YY_USE_CONST
#else /* ! __cplusplus */
/* C99 requires __STDC__ to be defined as 1. */
#if defined (__STDC__)
#define YY_USE_CONST
#endif /* defined (__STDC__) */
#endif /* ! __cplusplus */
#ifdef YY_USE_CONST
#define yyconst const
#else
#define yyconst
#endif
/* Size of default input buffer. */
#ifndef YY_BUF_SIZE
#ifdef __ia64__
/* On IA-64, the buffer size is 16k, not 8k.
* Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
* Ditto for the __ia64__ case accordingly.
*/
#define YY_BUF_SIZE 32768
#else
#define YY_BUF_SIZE 16384
#endif /* __ia64__ */
#endif
#ifndef YY_TYPEDEF_YY_BUFFER_STATE
#define YY_TYPEDEF_YY_BUFFER_STATE
typedef struct yy_buffer_state *YY_BUFFER_STATE;
#endif
#ifndef YY_TYPEDEF_YY_SIZE_T
#define YY_TYPEDEF_YY_SIZE_T
typedef size_t yy_size_t;
#endif
extern yy_size_t yyleng;
extern FILE *yyin, *yyout;
#ifndef YY_STRUCT_YY_BUFFER_STATE
#define YY_STRUCT_YY_BUFFER_STATE
struct yy_buffer_state
{
FILE *yy_input_file;
char *yy_ch_buf; /* input buffer */
char *yy_buf_pos; /* current position in input buffer */
/* Size of input buffer in bytes, not including room for EOB
* characters.
*/
yy_size_t yy_buf_size;
/* Number of characters read into yy_ch_buf, not including EOB
* characters.
*/
yy_size_t yy_n_chars;
/* Whether we "own" the buffer - i.e., we know we created it,
* and can realloc() it to grow it, and should free() it to
* delete it.
*/
int yy_is_our_buffer;
/* Whether this is an "interactive" input source; if so, and
* if we're using stdio for input, then we want to use getc()
* instead of fread(), to make sure we stop fetching input after
* each newline.
*/
int yy_is_interactive;
/* Whether we're considered to be at the beginning of a line.
* If so, '^' rules will be active on the next match, otherwise
* not.
*/
int yy_at_bol;
int yy_bs_lineno; /**< The line count. */
int yy_bs_column; /**< The column count. */
/* Whether to try to fill the input buffer when we reach the
* end of it.
*/
int yy_fill_buffer;
int yy_buffer_status;
};
#endif /* !YY_STRUCT_YY_BUFFER_STATE */
void yyrestart (FILE *input_file );
void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer );
YY_BUFFER_STATE yy_create_buffer (FILE *file,int size );
void yy_delete_buffer (YY_BUFFER_STATE b );
void yy_flush_buffer (YY_BUFFER_STATE b );
void yypush_buffer_state (YY_BUFFER_STATE new_buffer );
void yypop_buffer_state (void );
YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size );
YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str );
YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,yy_size_t len );
void *yyalloc (yy_size_t );
void *yyrealloc (void *,yy_size_t );
void yyfree (void * );
/* Begin user sect3 */
#define yywrap() 1
#define YY_SKIP_YYWRAP
extern int yylineno;
extern char *yytext;
#define yytext_ptr yytext
#ifdef YY_HEADER_EXPORT_START_CONDITIONS
#define INITIAL 0
#endif
#ifndef YY_NO_UNISTD_H
/* Special case for "unistd.h", since it is non-ANSI. We include it way
* down here because we want the user's section 1 to have been scanned first.
* The user has a chance to override it with an option.
*/
#include <unistd.h>
#endif
#ifndef YY_EXTRA_TYPE
#define YY_EXTRA_TYPE void *
#endif
/* Accessor methods to globals.
These are made visible to non-reentrant scanners for convenience. */
int yylex_destroy (void );
int yyget_debug (void );
void yyset_debug (int debug_flag );
YY_EXTRA_TYPE yyget_extra (void );
void yyset_extra (YY_EXTRA_TYPE user_defined );
FILE *yyget_in (void );
void yyset_in (FILE * in_str );
FILE *yyget_out (void );
void yyset_out (FILE * out_str );
yy_size_t yyget_leng (void );
char *yyget_text (void );
int yyget_lineno (void );
void yyset_lineno (int line_number );
/* Macros after this point can all be overridden by user definitions in
* section 1.
*/
#ifndef YY_SKIP_YYWRAP
#ifdef __cplusplus
extern "C" int yywrap (void );
#else
extern int yywrap (void );
#endif
#endif
#ifndef yytext_ptr
static void yy_flex_strncpy (char *,yyconst char *,int );
#endif
#ifdef YY_NEED_STRLEN
static int yy_flex_strlen (yyconst char * );
#endif
#ifndef YY_NO_INPUT
#endif
/* Amount of stuff to slurp up with each read. */
#ifndef YY_READ_BUF_SIZE
#ifdef __ia64__
/* On IA-64, the buffer size is 16k, not 8k */
#define YY_READ_BUF_SIZE 16384
#else
#define YY_READ_BUF_SIZE 8192
#endif /* __ia64__ */
#endif
/* Number of entries by which start-condition stack grows. */
#ifndef YY_START_STACK_INCR
#define YY_START_STACK_INCR 25
#endif
/* Default declaration of generated scanner - a define so the user can
* easily add parameters.
*/
#ifndef YY_DECL
#define YY_DECL_IS_OURS 1
extern int yylex (void);
#define YY_DECL int yylex (void)
#endif /* !YY_DECL */
/* yy_get_previous_state - get the state just before the EOB char was reached */
#undef YY_NEW_FILE
#undef YY_FLUSH_BUFFER
#undef yy_set_bol
#undef yy_new_buffer
#undef yy_set_interactive
#undef YY_DO_BEFORE_ACTION
#ifdef YY_DECL_IS_OURS
#undef YY_DECL_IS_OURS
#undef YY_DECL
#endif
#line 44 "fmd_scanner.l"
#line 332 "fmd_scanner.h"
#undef yyIN_HEADER
#endif /* yyHEADER_H */

View File

@ -0,0 +1,78 @@
/*
* fmd_scanner.l, scanner generator for flashmap descriptor language
*
* 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 "fmd_parser.h"
#include <assert.h>
#include <string.h>
int parse_integer(char *input, int base);
int copy_string(const char *input);
%}
%option noyywrap
MULTIPLIER [KMG]
%%
[[:space:]]+ /* Eat whitespace. */
#.*$ /* Eat comments. */
0{MULTIPLIER}? |
[1-9][0-9]*{MULTIPLIER}? return parse_integer(yytext, 10);
0[0-9]+{MULTIPLIER}? return OCTAL;
0[xX][0-9a-f]+{MULTIPLIER}? return parse_integer(yytext + 2, 16);
[^#@{}()[:space:]]* return copy_string(yytext);
. return *yytext;
%%
int parse_integer(char *input, int base)
{
char *multiplier = NULL;
unsigned val = strtoul(input, &multiplier, base);
if (*multiplier) {
switch(*multiplier) {
case 'K':
val *= 1024;
break;
case 'M':
val *= 1024*1024;
break;
case 'G':
val *= 1024*1024*1024;
break;
default:
// If we ever get here, the MULTIPLIER regex is allowing
// multiplier suffixes not handled by this code.
assert(false);
}
}
yylval.intval = val;
return INTEGER;
}
int copy_string(const char *input)
{
yylval.strval = strdup(input);
return STRING;
}

29
util/cbfstool/option.h Normal file
View File

@ -0,0 +1,29 @@
/*
* option.h, unsigned OPTION type
*
* 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 OPTION_H_
#define OPTION_H_
struct unsigned_option {
bool val_known;
/** It is an error to read this field unless val_known is set. */
unsigned val;
};
#endif