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/*/.test
|
||||||
util/board_status/board-status
|
util/board_status/board-status
|
||||||
util/cbfstool/cbfstool
|
util/cbfstool/cbfstool
|
||||||
|
util/cbfstool/fmaptool
|
||||||
util/cbfstool/rmodtool
|
util/cbfstool/rmodtool
|
||||||
util/cbmem/.dependencies
|
util/cbmem/.dependencies
|
||||||
util/cbmem/cbmem
|
util/cbmem/cbmem
|
||||||
|
|
|
@ -285,11 +285,15 @@ build-dirs:
|
||||||
#######################################################################
|
#######################################################################
|
||||||
# Build the tools
|
# Build the tools
|
||||||
CBFSTOOL:=$(objutil)/cbfstool/cbfstool
|
CBFSTOOL:=$(objutil)/cbfstool/cbfstool
|
||||||
|
FMAPTOOL:=$(objutil)/cbfstool/fmaptool
|
||||||
RMODTOOL:=$(objutil)/cbfstool/rmodtool
|
RMODTOOL:=$(objutil)/cbfstool/rmodtool
|
||||||
|
|
||||||
$(obj)/cbfstool: $(CBFSTOOL)
|
$(obj)/cbfstool: $(CBFSTOOL)
|
||||||
cp $< $@
|
cp $< $@
|
||||||
|
|
||||||
|
$(obj)/fmaptool: $(FMAPTOOL)
|
||||||
|
cp $< $@
|
||||||
|
|
||||||
$(obj)/rmodtool: $(RMODTOOL)
|
$(obj)/rmodtool: $(RMODTOOL)
|
||||||
cp $< $@
|
cp $< $@
|
||||||
|
|
||||||
|
@ -473,7 +477,7 @@ crosstools-riscv: clean-for-update
|
||||||
crossgcc-clean: clean-for-update
|
crossgcc-clean: clean-for-update
|
||||||
$(MAKE) -C util/crossgcc clean
|
$(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
|
# 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))) &&))
|
$(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)))
|
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 \
|
$(CBFSTOOL) $@.tmp create \
|
||||||
-B $(objcbfs)/bootblock.bin -a 64 \
|
-B $(objcbfs)/bootblock.bin -a 64 \
|
||||||
$(CBFSTOOL_PRE1_OPTS)
|
$(CBFSTOOL_PRE1_OPTS)
|
||||||
|
|
14
src/Kconfig
14
src/Kconfig
|
@ -108,15 +108,25 @@ config CCACHE
|
||||||
|
|
||||||
For details see https://ccache.samba.org.
|
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
|
config SCONFIG_GENPARSER
|
||||||
bool "Generate SCONFIG parser using flex and bison"
|
bool "Generate SCONFIG parser using flex and bison"
|
||||||
default n
|
default n
|
||||||
depends on EXPERT
|
depends on EXPERT
|
||||||
help
|
help
|
||||||
Enable this option if you are working on the sconfig device tree
|
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
|
config USE_OPTION_TABLE
|
||||||
bool "Use CMOS for configuration values"
|
bool "Use CMOS for configuration values"
|
||||||
|
|
|
@ -6,7 +6,9 @@ CFLAGS += -g3
|
||||||
CFLAGS += -std=c99 -Werror -Wall -Wextra
|
CFLAGS += -std=c99 -Werror -Wall -Wextra
|
||||||
CFLAGS += -Wcast-qual -Wmissing-prototypes -Wredundant-decls -Wshadow
|
CFLAGS += -Wcast-qual -Wmissing-prototypes -Wredundant-decls -Wshadow
|
||||||
CFLAGS += -Wstrict-prototypes -Wwrite-strings
|
CFLAGS += -Wstrict-prototypes -Wwrite-strings
|
||||||
|
CPPFLAGS += -D_DEFAULT_SOURCE # memccpy() from string.h
|
||||||
CPPFLAGS += -D_POSIX_C_SOURCE=200809L # strdup() from string.h
|
CPPFLAGS += -D_POSIX_C_SOURCE=200809L # strdup() from string.h
|
||||||
|
CPPFLAGS += -Iflashmap
|
||||||
LDFLAGS += -g3
|
LDFLAGS += -g3
|
||||||
|
|
||||||
CBFSTOOL_BINARY:=$(obj)/cbfstool
|
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))
|
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_BINARY:=$(obj)/rmodtool
|
||||||
RMODTOOL_COMMON:=rmodule.o common.o elfheaders.o xdr.o
|
RMODTOOL_COMMON:=rmodule.o common.o elfheaders.o xdr.o
|
||||||
|
|
||||||
RMODTOOL_COMMON:=$(addprefix $(obj)/,$(RMODTOOL_COMMON))
|
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
|
.PHONY: all
|
||||||
all: .dependencies $(CBFSTOOL_BINARY) $(RMODTOOL_BINARY)
|
all: .dependencies $(CBFSTOOL_BINARY) $(FMAPTOOL_BINARY) $(RMODTOOL_BINARY)
|
||||||
|
|
||||||
$(obj)/%: $(obj)/%.o
|
$(obj)/%: $(obj)/%.o
|
||||||
mkdir -p $(dir $@)
|
mkdir -p $(dir $@)
|
||||||
|
@ -34,27 +50,47 @@ $(obj)/%: $(obj)/%.o
|
||||||
$(obj)/%.o: %.c
|
$(obj)/%.o: %.c
|
||||||
mkdir -p $(dir $@)
|
mkdir -p $(dir $@)
|
||||||
$(HOSTCC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $<
|
$(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
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
$(RM) $(CBFSTOOL_COMMON) $(CBFSTOOL_BINARY).o $(CBFSTOOL_BINARY)
|
$(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) $(RMODTOOL_COMMON) $(RMODTOOL_BINARY).o $(RMODTOOL_BINARY)
|
||||||
|
$(RM) $(FMAPTESTS_COMMON) $(FMAPTESTS_BINARY).o $(FMAPTESTS_BINARY)
|
||||||
.PHONY: distclean
|
.PHONY: distclean
|
||||||
distclean: clean
|
distclean: clean
|
||||||
$(RM) .dependencies
|
$(RM) .dependencies
|
||||||
|
.PHONY: maintainer-clean
|
||||||
|
maintainer-clean: distclean
|
||||||
|
$(RM) $(GENERATED)
|
||||||
|
|
||||||
tags:
|
tags: $(GENERATED)
|
||||||
ctags *.[ch]
|
ctags *.[ch]
|
||||||
|
|
||||||
.dependencies:
|
.dependencies: $(GENERATED)
|
||||||
@$(HOSTCC) $(CPPFLAGS) $(CFLAGS) -MM -MG *.c > $@
|
@$(HOSTCC) $(CPPFLAGS) $(CFLAGS) -MM -MG *.c > $@
|
||||||
|
@$(HOSTCC) $(CPPFLAGS) $(CFLAGS) -MM flashmap/*.c >> $@
|
||||||
@$(HOSTCC) $(CPPFLAGS) $(CFLAGS) -MM lzma/*.c >> $@
|
@$(HOSTCC) $(CPPFLAGS) $(CFLAGS) -MM lzma/*.c >> $@
|
||||||
@$(HOSTCC) $(CPPFLAGS) $(CFLAGS) -MM lzma/C/*.c >> $@
|
@$(HOSTCC) $(CPPFLAGS) $(CFLAGS) -MM lzma/C/*.c >> $@
|
||||||
@sed -i 's|.*:.*|$$(obj)/&|' $@
|
@sed -i 's|.*:.*|$$(obj)/&|' $@
|
||||||
|
|
||||||
$(CBFSTOOL_BINARY): $(CBFSTOOL_COMMON)
|
$(CBFSTOOL_BINARY): $(CBFSTOOL_COMMON)
|
||||||
|
$(FMAPTOOL_BINARY): $(FMAPTOOL_COMMON)
|
||||||
$(RMODTOOL_BINARY): $(RMODTOOL_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
|
# Tolerate lzma sdk warnings
|
||||||
$(obj)/lzma/C/LzmaEnc.o: CFLAGS += -Wno-sign-compare -Wno-cast-qual
|
$(obj)/lzma/C/LzmaEnc.o: CFLAGS += -Wno-sign-compare -Wno-cast-qual
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,17 @@ cbfsobj += LzmaEnc.o
|
||||||
cbfsobj += linux_trampoline.o
|
cbfsobj += linux_trampoline.o
|
||||||
cbfsobj += cbfs-payload-linux.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 :=
|
||||||
rmodobj += rmodtool.o
|
rmodobj += rmodtool.o
|
||||||
rmodobj += rmodule.o
|
rmodobj += rmodule.o
|
||||||
|
@ -27,7 +38,9 @@ rmodobj += xdr.o
|
||||||
TOOLCFLAGS ?= -std=c99 -Werror -Wall -Wextra
|
TOOLCFLAGS ?= -std=c99 -Werror -Wall -Wextra
|
||||||
TOOLCFLAGS += -Wcast-qual -Wmissing-prototypes -Wredundant-decls -Wshadow
|
TOOLCFLAGS += -Wcast-qual -Wmissing-prototypes -Wredundant-decls -Wshadow
|
||||||
TOOLCFLAGS += -Wstrict-prototypes -Wwrite-strings
|
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 ?=
|
TOOLLDFLAGS ?=
|
||||||
|
|
||||||
ifeq ($(shell uname -s | cut -c-7 2>/dev/null), MINGW32)
|
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"
|
printf " HOSTCC $(subst $(objutil)/,,$(@))\n"
|
||||||
$(HOSTCC) $(TOOLCPPFLAGS) $(TOOLCFLAGS) $(HOSTCFLAGS) -c -o $@ $<
|
$(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
|
$(objutil)/cbfstool/%.o: $(top)/util/cbfstool/lzma/%.c
|
||||||
printf " HOSTCC $(subst $(objutil)/,,$(@))\n"
|
printf " HOSTCC $(subst $(objutil)/,,$(@))\n"
|
||||||
$(HOSTCC) $(TOOLCPPFLAGS) $(TOOLCFLAGS) $(HOSTCFLAGS) -c -o $@ $<
|
$(HOSTCC) $(TOOLCPPFLAGS) $(TOOLCFLAGS) $(HOSTCFLAGS) -c -o $@ $<
|
||||||
|
@ -50,9 +67,35 @@ $(objutil)/cbfstool/cbfstool: $(addprefix $(objutil)/cbfstool/,$(cbfsobj))
|
||||||
printf " HOSTCC $(subst $(objutil)/,,$(@)) (link)\n"
|
printf " HOSTCC $(subst $(objutil)/,,$(@)) (link)\n"
|
||||||
$(HOSTCC) $(TOOLLDFLAGS) -o $@ $(addprefix $(objutil)/cbfstool/,$(cbfsobj))
|
$(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))
|
$(objutil)/cbfstool/rmodtool: $(addprefix $(objutil)/cbfstool/,$(rmodobj))
|
||||||
printf " HOSTCC $(subst $(objutil)/,,$(@)) (link)\n"
|
printf " HOSTCC $(subst $(objutil)/,,$(@)) (link)\n"
|
||||||
$(HOSTCC) $(TOOLLDFLAGS) -o $@ $(addprefix $(objutil)/cbfstool/,$(rmodobj))
|
$(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
|
# Tolerate lzma sdk warnings
|
||||||
$(objutil)/cbfstool/LzmaEnc.o: TOOLCFLAGS += -Wno-sign-compare -Wno-cast-qual
|
$(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
|
#ifndef __CBFSTOOL_COMMON_H
|
||||||
#define __CBFSTOOL_COMMON_H
|
#define __CBFSTOOL_COMMON_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* Copyright 2010, Google Inc.
|
/* Copyright 2015, Google Inc.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
@ -49,7 +49,6 @@
|
||||||
#include <valstr.h>
|
#include <valstr.h>
|
||||||
|
|
||||||
#include "kv_pair.h"
|
#include "kv_pair.h"
|
||||||
#include "mincrypt/sha.h"
|
|
||||||
|
|
||||||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
#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 */
|
/* 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)
|
if (!fmap)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -71,7 +70,7 @@ int fmap_size(struct fmap *fmap)
|
||||||
/* brute force linear search */
|
/* brute force linear search */
|
||||||
static long int fmap_lsearch(const uint8_t *image, size_t len)
|
static long int fmap_lsearch(const uint8_t *image, size_t len)
|
||||||
{
|
{
|
||||||
long int offset;
|
unsigned long int offset;
|
||||||
int fmap_found = 0;
|
int fmap_found = 0;
|
||||||
|
|
||||||
for (offset = 0; offset < len - strlen(FMAP_SIGNATURE); offset++) {
|
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)
|
if (!fmap_found)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (offset + fmap_size((struct fmap *)&image[offset]) > len)
|
if (offset + fmap_size((const struct fmap *)&image[offset]) > len)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return offset;
|
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 */
|
/* if image length is a power of 2, use binary search */
|
||||||
static long int fmap_bsearch(const uint8_t *image, size_t len)
|
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;
|
int fmap_found = 0, stride;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -125,7 +124,7 @@ static long int fmap_bsearch(const uint8_t *image, size_t len)
|
||||||
if (!fmap_found)
|
if (!fmap_found)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (offset + fmap_size((struct fmap *)&image[offset]) > len)
|
if (offset + fmap_size((const struct fmap *)&image[offset]) > len)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return offset;
|
return offset;
|
||||||
|
@ -183,86 +182,42 @@ int fmap_print(const struct fmap *fmap)
|
||||||
kv_pair_free(kv);
|
kv_pair_free(kv);
|
||||||
|
|
||||||
for (i = 0; i < fmap->nareas; i++) {
|
for (i = 0; i < fmap->nareas; i++) {
|
||||||
struct kv_pair *kv;
|
struct kv_pair *pair;
|
||||||
uint16_t flags;
|
uint16_t flags;
|
||||||
char *str;
|
char *str;
|
||||||
|
|
||||||
kv = kv_pair_new();
|
pair = kv_pair_new();
|
||||||
if (!kv)
|
if (!pair)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
kv_pair_fmt(kv, "area_offset", "0x%08x",
|
kv_pair_fmt(pair, "area_offset", "0x%08x",
|
||||||
fmap->areas[i].offset);
|
fmap->areas[i].offset);
|
||||||
kv_pair_fmt(kv, "area_size", "0x%08x",
|
kv_pair_fmt(pair, "area_size", "0x%08x",
|
||||||
fmap->areas[i].size);
|
fmap->areas[i].size);
|
||||||
kv_pair_fmt(kv, "area_name", "%s",
|
kv_pair_fmt(pair, "area_name", "%s",
|
||||||
fmap->areas[i].name);
|
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);
|
fmap->areas[i].flags);
|
||||||
|
|
||||||
/* Print descriptive strings for flags rather than the field */
|
/* Print descriptive strings for flags rather than the field */
|
||||||
flags = fmap->areas[i].flags;
|
flags = fmap->areas[i].flags;
|
||||||
if ((str = fmap_flags_to_string(flags)) == NULL)
|
if ((str = fmap_flags_to_string(flags)) == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
kv_pair_fmt(kv, "area_flags", "%s", str );
|
kv_pair_fmt(pair, "area_flags", "%s", str);
|
||||||
free(str);
|
free(str);
|
||||||
|
|
||||||
kv_pair_print(kv);
|
kv_pair_print(pair);
|
||||||
kv_pair_free(kv);
|
kv_pair_free(pair);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
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 */
|
/* convert raw flags field to user-friendly string */
|
||||||
char *fmap_flags_to_string(uint16_t flags)
|
char *fmap_flags_to_string(uint16_t flags)
|
||||||
{
|
{
|
||||||
char *str = NULL;
|
char *str = NULL;
|
||||||
int i, total_size;
|
unsigned int i, total_size;
|
||||||
|
|
||||||
str = malloc(1);
|
str = malloc(1);
|
||||||
str[0] = '\0';
|
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));
|
memset(fmap, 0, sizeof(*fmap));
|
||||||
memcpy(&fmap->signature, FMAP_SIGNATURE, strlen(FMAP_SIGNATURE));
|
memcpy(&fmap->signature, FMAP_SIGNATURE, strlen(FMAP_SIGNATURE));
|
||||||
fmap->ver_major = VERSION_MAJOR;
|
fmap->ver_major = FMAP_VER_MAJOR;
|
||||||
fmap->ver_minor = VERSION_MINOR;
|
fmap->ver_minor = FMAP_VER_MINOR;
|
||||||
fmap->base = base;
|
fmap->base = base;
|
||||||
fmap->size = size;
|
fmap->size = size;
|
||||||
memccpy(&fmap->name, name, '\0', FMAP_STRLEN);
|
memccpy(&fmap->name, name, '\0', FMAP_STRLEN);
|
||||||
|
@ -390,8 +345,8 @@ static struct fmap *fmap_create_test(void)
|
||||||
goto fmap_create_test_exit;
|
goto fmap_create_test_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((fmap->ver_major != VERSION_MAJOR) ||
|
if ((fmap->ver_major != FMAP_VER_MAJOR) ||
|
||||||
(fmap->ver_minor != VERSION_MINOR)) {
|
(fmap->ver_minor != FMAP_VER_MINOR)) {
|
||||||
printf("FAILURE: version is incorrect\n");
|
printf("FAILURE: version is incorrect\n");
|
||||||
goto fmap_create_test_exit;
|
goto fmap_create_test_exit;
|
||||||
}
|
}
|
||||||
|
@ -431,44 +386,7 @@ static int fmap_print_test(struct fmap *fmap)
|
||||||
return fmap_print(fmap);
|
return fmap_print(fmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fmap_get_csum_test(struct fmap *fmap)
|
static int fmap_size_test(void)
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
status = fail;
|
status = fail;
|
||||||
|
|
||||||
|
@ -553,10 +471,10 @@ fmap_find_area_test_exit:
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fmap_flags_to_string_test()
|
static int fmap_flags_to_string_test(void)
|
||||||
{
|
{
|
||||||
char *str, *my_str;
|
char *str, *my_str;
|
||||||
int i;
|
unsigned int i;
|
||||||
uint16_t flags;
|
uint16_t flags;
|
||||||
|
|
||||||
status = fail;
|
status = fail;
|
||||||
|
@ -646,11 +564,11 @@ static int fmap_find_test(struct fmap *fmap)
|
||||||
offset = (total_size / 2) + 1;
|
offset = (total_size / 2) + 1;
|
||||||
memcpy(&buf[offset], fmap, fmap_size(fmap));
|
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");
|
printf("FAILURE: lsearch failed to find fmap\n");
|
||||||
goto fmap_find_test_exit;
|
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");
|
printf("FAILURE: bsearch failed to find fmap\n");
|
||||||
goto fmap_find_test_exit;
|
goto fmap_find_test_exit;
|
||||||
}
|
}
|
||||||
|
@ -659,7 +577,7 @@ static int fmap_find_test(struct fmap *fmap)
|
||||||
offset = 0;
|
offset = 0;
|
||||||
memset(buf, 0, total_size);
|
memset(buf, 0, total_size);
|
||||||
memcpy(buf, fmap, fmap_size(fmap));
|
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");
|
printf("FAILURE: bsearch failed to find fmap at offset 0\n");
|
||||||
goto fmap_find_test_exit;
|
goto fmap_find_test_exit;
|
||||||
}
|
}
|
||||||
|
@ -684,7 +602,7 @@ fmap_find_test_exit:
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fmap_test()
|
int fmap_test(void)
|
||||||
{
|
{
|
||||||
int rc = EXIT_SUCCESS;
|
int rc = EXIT_SUCCESS;
|
||||||
struct fmap *my_fmap;
|
struct fmap *my_fmap;
|
||||||
|
@ -713,8 +631,7 @@ int fmap_test()
|
||||||
}
|
}
|
||||||
|
|
||||||
rc |= fmap_find_area_test(my_fmap);
|
rc |= fmap_find_area_test(my_fmap);
|
||||||
rc |= fmap_get_csum_test(my_fmap);
|
rc |= fmap_size_test();
|
||||||
rc |= fmap_size_test(my_fmap);
|
|
||||||
rc |= fmap_flags_to_string_test();
|
rc |= fmap_flags_to_string_test();
|
||||||
rc |= fmap_print_test(my_fmap);
|
rc |= fmap_print_test(my_fmap);
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2010, Google Inc.
|
* Copyright 2015, Google Inc.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* 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);
|
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
|
* 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 size of fmap structure if successful
|
||||||
* returns <0 to indicate failure
|
* 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
|
* 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);
|
extern struct fmap_area *fmap_find_area(struct fmap *fmap, const char *name);
|
||||||
|
|
||||||
/* unit testing stuff */
|
/* unit testing stuff */
|
||||||
extern int fmap_test();
|
extern int fmap_test(void);
|
||||||
|
|
||||||
#endif /* FLASHMAP_LIB_FMAP_H__*/
|
#endif /* FLASHMAP_LIB_FMAP_H__*/
|
||||||
|
|
|
@ -47,7 +47,7 @@ void kv_pair_set_style(enum kv_pair_style style)
|
||||||
_style = style;
|
_style = style;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum kv_pair_style kv_pair_get_style()
|
enum kv_pair_style kv_pair_get_style(void)
|
||||||
{
|
{
|
||||||
return _style;
|
return _style;
|
||||||
}
|
}
|
||||||
|
@ -63,18 +63,6 @@ struct kv_pair *kv_pair_new(void)
|
||||||
return kv;
|
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,
|
struct kv_pair *kv_pair_add(struct kv_pair *kv_list,
|
||||||
const char *key, const char *value)
|
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,
|
void kv_pair_print_to_file(FILE* fp, struct kv_pair *kv_list,
|
||||||
enum kv_pair_style style)
|
enum kv_pair_style style)
|
||||||
{
|
{
|
||||||
|
|
|
@ -56,7 +56,7 @@ struct kv_pair {
|
||||||
struct kv_pair *next;
|
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);
|
extern void kv_pair_set_style(enum kv_pair_style style);
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <strings.h>
|
||||||
|
|
||||||
#include <valstr.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