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:
parent
5f7e4f019e
commit
69b88bf127
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
14
src/Kconfig
14
src/Kconfig
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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().
|
|
@ -20,6 +20,7 @@
|
|||
#ifndef __CBFSTOOL_COMMON_H
|
||||
#define __CBFSTOOL_COMMON_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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__*/
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include <valstr.h>
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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, "");
|
||||
}
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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 */
|
|
@ -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);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -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 */
|
|
@ -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;
|
||||
}
|
|
@ -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
|
Loading…
Reference in New Issue