Import dtc from git://git.jdl.com/software/dtc
hash f807af192828222dee7a5c9f94d999673bb4d8a1
This commit is contained in:
parent
b7b62f4139
commit
bae61446cf
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/vendor/dtc/dist/; revision=238733
@ -29,18 +29,28 @@ except for properties with empty (zero length) value which have the
|
||||
form:
|
||||
[label:] property-name;
|
||||
|
||||
Property values may be defined as an array of 32-bit integer cells, as
|
||||
NUL-terminated strings, as bytestrings or a combination of these.
|
||||
Property values may be defined as an array of 8, 16, 32, or 64-bit integer
|
||||
elements, as NUL-terminated strings, as bytestrings or a combination of these.
|
||||
|
||||
* Arrays of cells are represented by angle brackets surrounding a
|
||||
space separated list of C-style integers
|
||||
* Arrays are represented by angle brackets surrounding a space separated list
|
||||
of C-style integers or character literals. Array elements default to 32-bits
|
||||
in size. An array of 32-bit elements is also known as a cell list or a list
|
||||
of cells. A cell being an unsigned 32-bit integer.
|
||||
|
||||
e.g. interrupts = <17 0xc>;
|
||||
|
||||
* A 64-bit value is represented with two 32-bit cells.
|
||||
* A 64-bit value can be represented with two 32-bit elements.
|
||||
|
||||
e.g. clock-frequency = <0x00000001 0x00000000>;
|
||||
|
||||
* The storage size of an element can be changed using the /bits/ prefix. The
|
||||
/bits/ prefix allows for the creation of 8, 16, 32, and 64-bit elements.
|
||||
The resulting array will not be padded to a multiple of the default 32-bit
|
||||
element size.
|
||||
|
||||
e.g. interrupts = /bits/ 8 <17 0xc>;
|
||||
e.g. clock-frequency = /bits/ 64 <0x0000000100000000>;
|
||||
|
||||
* A NUL-terminated string value is represented using double quotes
|
||||
(the property value is considered to include the terminating NUL
|
||||
character).
|
||||
@ -59,19 +69,20 @@ NUL-terminated strings, as bytestrings or a combination of these.
|
||||
e.g. compatible = "ns16550", "ns8250";
|
||||
example = <0xf00f0000 19>, "a strange property format";
|
||||
|
||||
* In a cell array a reference to another node will be expanded to that
|
||||
node's phandle. References may by '&' followed by a node's label:
|
||||
* In an array a reference to another node will be expanded to that node's
|
||||
phandle. References may by '&' followed by a node's label:
|
||||
e.g. interrupt-parent = < &mpic >;
|
||||
or they may be '&' followed by a node's full path in braces:
|
||||
e.g. interrupt-parent = < &{/soc/interrupt-controller@40000} >;
|
||||
References are only permitted in arrays that have an element size of
|
||||
32-bits.
|
||||
|
||||
* Outside a cell array, a reference to another node will be expanded
|
||||
to that node's full path.
|
||||
* Outside an array, a reference to another node will be expanded to that
|
||||
node's full path.
|
||||
e.g. ethernet0 = &EMAC0;
|
||||
|
||||
* Labels may also appear before or after any component of a property
|
||||
value, or between cells of a cell array, or between bytes of a
|
||||
bytestring.
|
||||
value, or between elements of an array, or between bytes of a bytestring.
|
||||
e.g. reg = reglabel: <0 sizelabel: 0x1000000>;
|
||||
e.g. prop = [ab cd ef byte4: 00 ff fe];
|
||||
e.g. str = start: "string value" end: ;
|
||||
@ -108,3 +119,4 @@ Version 1 DTS files have the overall layout:
|
||||
|
||||
-- David Gibson <david@gibson.dropbear.id.au>
|
||||
-- Yoder Stuart <stuart.yoder@freescale.com>
|
||||
-- Anton Staaf <robotboy@chromium.org>
|
||||
|
@ -21,7 +21,7 @@ III - libfdt
|
||||
|
||||
IV - Utility Tools
|
||||
1) convert-dtsv0 -- Conversion to Version 1
|
||||
1) ftdump
|
||||
1) fdtdump
|
||||
|
||||
|
||||
I - "dtc", the device tree compiler
|
||||
@ -106,6 +106,9 @@ Options:
|
||||
-O <output_format>
|
||||
The generated output format, as listed above.
|
||||
|
||||
-d <dependency_filename>
|
||||
Generate a dependency file during compilation.
|
||||
|
||||
-q
|
||||
Quiet: -q suppress warnings, -qq errors, -qqq all
|
||||
|
||||
@ -643,10 +646,10 @@ a new file with a "v1" appended the filename.
|
||||
Comments, empty lines, etc. are preserved.
|
||||
|
||||
|
||||
2) ftdump -- Flat Tree dumping utility
|
||||
2) fdtdump -- Flat Device Tree dumping utility
|
||||
|
||||
The ftdump program prints a readable version of a flat device tree file.
|
||||
The fdtdump program prints a readable version of a flat device tree file.
|
||||
|
||||
The syntax of the ftdump command line is:
|
||||
The syntax of the fdtdump command line is:
|
||||
|
||||
ftdump <DTB-file-name>
|
||||
fdtdump <DTB-file-name>
|
||||
|
44
Makefile
44
Makefile
@ -9,14 +9,16 @@
|
||||
# CONFIG_LOCALVERSION from some future config system.
|
||||
#
|
||||
VERSION = 1
|
||||
PATCHLEVEL = 2
|
||||
PATCHLEVEL = 3
|
||||
SUBLEVEL = 0
|
||||
EXTRAVERSION =
|
||||
LOCAL_VERSION =
|
||||
CONFIG_LOCALVERSION =
|
||||
|
||||
CPPFLAGS = -I libfdt
|
||||
CFLAGS = -Wall -g -Os -fPIC -Wpointer-arith -Wcast-qual
|
||||
CPPFLAGS = -I libfdt -I .
|
||||
WARNINGS = -Werror -Wall -Wpointer-arith -Wcast-qual -Wnested-externs \
|
||||
-Wstrict-prototypes -Wmissing-prototypes -Wredundant-decls
|
||||
CFLAGS = -g -Os -fPIC -Werror $(WARNINGS)
|
||||
|
||||
BISON = bison
|
||||
LEX = flex
|
||||
@ -103,12 +105,15 @@ endef
|
||||
|
||||
include Makefile.convert-dtsv0
|
||||
include Makefile.dtc
|
||||
include Makefile.ftdump
|
||||
include Makefile.utils
|
||||
|
||||
BIN += convert-dtsv0
|
||||
BIN += dtc
|
||||
BIN += ftdump
|
||||
BIN += fdtdump
|
||||
BIN += fdtget
|
||||
BIN += fdtput
|
||||
|
||||
SCRIPTS = dtdiff
|
||||
|
||||
all: $(BIN) libfdt
|
||||
|
||||
@ -116,7 +121,9 @@ all: $(BIN) libfdt
|
||||
ifneq ($(DEPTARGETS),)
|
||||
-include $(DTC_OBJS:%.o=%.d)
|
||||
-include $(CONVERT_OBJS:%.o=%.d)
|
||||
-include $(FTDUMP_OBJS:%.o=%.d)
|
||||
-include $(FDTDUMP_OBJS:%.o=%.d)
|
||||
-include $(FDTGET_OBJS:%.o=%.d)
|
||||
-include $(FDTPUT_OBJS:%.o=%.d)
|
||||
endif
|
||||
|
||||
|
||||
@ -127,7 +134,7 @@ endif
|
||||
LIBFDT_objdir = libfdt
|
||||
LIBFDT_srcdir = libfdt
|
||||
LIBFDT_archive = $(LIBFDT_objdir)/libfdt.a
|
||||
LIBFDT_lib = $(LIBFDT_objdir)/libfdt.$(SHAREDLIB_EXT)
|
||||
LIBFDT_lib = $(LIBFDT_objdir)/libfdt-$(DTC_VERSION).$(SHAREDLIB_EXT)
|
||||
LIBFDT_include = $(addprefix $(LIBFDT_srcdir)/,$(LIBFDT_INCLUDES))
|
||||
LIBFDT_version = $(addprefix $(LIBFDT_srcdir)/,$(LIBFDT_VERSION))
|
||||
|
||||
@ -153,12 +160,14 @@ endif
|
||||
# intermediate target and building them again "for real"
|
||||
.SECONDARY: $(DTC_GEN_SRCS) $(CONVERT_GEN_SRCS)
|
||||
|
||||
install: all
|
||||
install: all $(SCRIPTS)
|
||||
@$(VECHO) INSTALL
|
||||
$(INSTALL) -d $(DESTDIR)$(BINDIR)
|
||||
$(INSTALL) $(BIN) $(DESTDIR)$(BINDIR)
|
||||
$(INSTALL) $(BIN) $(SCRIPTS) $(DESTDIR)$(BINDIR)
|
||||
$(INSTALL) -d $(DESTDIR)$(LIBDIR)
|
||||
$(INSTALL) $(LIBFDT_lib) $(DESTDIR)$(LIBDIR)
|
||||
ln -sf $(notdir $(LIBFDT_lib)) $(DESTDIR)$(LIBDIR)/$(LIBFDT_soname)
|
||||
ln -sf $(LIBFDT_soname) $(DESTDIR)$(LIBDIR)/libfdt.$(SHAREDLIB_EXT)
|
||||
$(INSTALL) -m 644 $(LIBFDT_archive) $(DESTDIR)$(LIBDIR)
|
||||
$(INSTALL) -d $(DESTDIR)$(INCLUDEDIR)
|
||||
$(INSTALL) -m 644 $(LIBFDT_include) $(DESTDIR)$(INCLUDEDIR)
|
||||
@ -173,19 +182,29 @@ convert-dtsv0: $(CONVERT_OBJS)
|
||||
@$(VECHO) LD $@
|
||||
$(LINK.c) -o $@ $^
|
||||
|
||||
ftdump: $(FTDUMP_OBJS)
|
||||
fdtdump: $(FDTDUMP_OBJS)
|
||||
|
||||
fdtget: $(FDTGET_OBJS) $(LIBFDT_archive)
|
||||
|
||||
fdtput: $(FDTPUT_OBJS) $(LIBFDT_archive)
|
||||
|
||||
|
||||
#
|
||||
# Testsuite rules
|
||||
#
|
||||
TESTS_PREFIX=tests/
|
||||
|
||||
TESTS_BIN += dtc
|
||||
TESTS_BIN += convert-dtsv0
|
||||
TESTS_BIN += fdtput
|
||||
TESTS_BIN += fdtget
|
||||
|
||||
include tests/Makefile.tests
|
||||
|
||||
#
|
||||
# Clean rules
|
||||
#
|
||||
STD_CLEANFILES = *~ *.o *.so *.d *.a *.i *.s core a.out vgcore.* \
|
||||
STD_CLEANFILES = *~ *.o *.$(SHAREDLIB_EXT) *.d *.a *.i *.s core a.out vgcore.* \
|
||||
*.tab.[ch] *.lex.c *.output
|
||||
|
||||
clean: libfdt_clean tests_clean
|
||||
@ -231,8 +250,7 @@ clean: libfdt_clean tests_clean
|
||||
|
||||
$(LIBFDT_lib):
|
||||
@$(VECHO) LD $@
|
||||
$(CC) $(LDFLAGS) -fPIC $(SHAREDLIB_LINK_OPTIONS)$(notdir $@) -o $(LIBFDT_objdir)/libfdt-$(DTC_VERSION).$(SHAREDLIB_EXT) $^
|
||||
ln -sf libfdt-$(DTC_VERSION).$(SHAREDLIB_EXT) $(LIBFDT_objdir)/libfdt.$(SHAREDLIB_EXT)
|
||||
$(CC) $(LDFLAGS) -fPIC $(SHAREDLIB_LINK_OPTIONS)$(LIBFDT_soname) -o $(LIBFDT_lib) $^
|
||||
|
||||
%.lex.c: %.l
|
||||
@$(VECHO) LEX $@
|
||||
|
248
checks.c
248
checks.c
@ -31,12 +31,6 @@
|
||||
#define TRACE(c, fmt, ...) do { } while (0)
|
||||
#endif
|
||||
|
||||
enum checklevel {
|
||||
IGNORE = 0,
|
||||
WARN = 1,
|
||||
ERROR = 2,
|
||||
};
|
||||
|
||||
enum checkstatus {
|
||||
UNCHECKED = 0,
|
||||
PREREQ,
|
||||
@ -57,14 +51,14 @@ struct check {
|
||||
node_check_fn node_fn;
|
||||
prop_check_fn prop_fn;
|
||||
void *data;
|
||||
enum checklevel level;
|
||||
bool warn, error;
|
||||
enum checkstatus status;
|
||||
int inprogress;
|
||||
int num_prereqs;
|
||||
struct check **prereq;
|
||||
};
|
||||
|
||||
#define CHECK(nm, tfn, nfn, pfn, d, lvl, ...) \
|
||||
#define CHECK_ENTRY(nm, tfn, nfn, pfn, d, w, e, ...) \
|
||||
static struct check *nm##_prereqs[] = { __VA_ARGS__ }; \
|
||||
static struct check nm = { \
|
||||
.name = #nm, \
|
||||
@ -72,20 +66,37 @@ struct check {
|
||||
.node_fn = (nfn), \
|
||||
.prop_fn = (pfn), \
|
||||
.data = (d), \
|
||||
.level = (lvl), \
|
||||
.warn = (w), \
|
||||
.error = (e), \
|
||||
.status = UNCHECKED, \
|
||||
.num_prereqs = ARRAY_SIZE(nm##_prereqs), \
|
||||
.prereq = nm##_prereqs, \
|
||||
};
|
||||
#define WARNING(nm, tfn, nfn, pfn, d, ...) \
|
||||
CHECK_ENTRY(nm, tfn, nfn, pfn, d, true, false, __VA_ARGS__)
|
||||
#define ERROR(nm, tfn, nfn, pfn, d, ...) \
|
||||
CHECK_ENTRY(nm, tfn, nfn, pfn, d, false, true, __VA_ARGS__)
|
||||
#define CHECK(nm, tfn, nfn, pfn, d, ...) \
|
||||
CHECK_ENTRY(nm, tfn, nfn, pfn, d, false, false, __VA_ARGS__)
|
||||
|
||||
#define TREE_CHECK(nm, d, lvl, ...) \
|
||||
CHECK(nm, check_##nm, NULL, NULL, d, lvl, __VA_ARGS__)
|
||||
#define NODE_CHECK(nm, d, lvl, ...) \
|
||||
CHECK(nm, NULL, check_##nm, NULL, d, lvl, __VA_ARGS__)
|
||||
#define PROP_CHECK(nm, d, lvl, ...) \
|
||||
CHECK(nm, NULL, NULL, check_##nm, d, lvl, __VA_ARGS__)
|
||||
#define BATCH_CHECK(nm, lvl, ...) \
|
||||
CHECK(nm, NULL, NULL, NULL, NULL, lvl, __VA_ARGS__)
|
||||
#define TREE_WARNING(nm, d, ...) \
|
||||
WARNING(nm, check_##nm, NULL, NULL, d, __VA_ARGS__)
|
||||
#define TREE_ERROR(nm, d, ...) \
|
||||
ERROR(nm, check_##nm, NULL, NULL, d, __VA_ARGS__)
|
||||
#define TREE_CHECK(nm, d, ...) \
|
||||
CHECK(nm, check_##nm, NULL, NULL, d, __VA_ARGS__)
|
||||
#define NODE_WARNING(nm, d, ...) \
|
||||
WARNING(nm, NULL, check_##nm, NULL, d, __VA_ARGS__)
|
||||
#define NODE_ERROR(nm, d, ...) \
|
||||
ERROR(nm, NULL, check_##nm, NULL, d, __VA_ARGS__)
|
||||
#define NODE_CHECK(nm, d, ...) \
|
||||
CHECK(nm, NULL, check_##nm, NULL, d, __VA_ARGS__)
|
||||
#define PROP_WARNING(nm, d, ...) \
|
||||
WARNING(nm, NULL, NULL, check_##nm, d, __VA_ARGS__)
|
||||
#define PROP_ERROR(nm, d, ...) \
|
||||
ERROR(nm, NULL, NULL, check_##nm, d, __VA_ARGS__)
|
||||
#define PROP_CHECK(nm, d, ...) \
|
||||
CHECK(nm, NULL, NULL, check_##nm, d, __VA_ARGS__)
|
||||
|
||||
#ifdef __GNUC__
|
||||
static inline void check_msg(struct check *c, const char *fmt, ...) __attribute__((format (printf, 2, 3)));
|
||||
@ -95,13 +106,13 @@ static inline void check_msg(struct check *c, const char *fmt, ...)
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
|
||||
if ((c->level < WARN) || (c->level <= quiet))
|
||||
return; /* Suppress message */
|
||||
|
||||
fprintf(stderr, "%s (%s): ",
|
||||
(c->level == ERROR) ? "ERROR" : "Warning", c->name);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fprintf(stderr, "\n");
|
||||
if ((c->warn && (quiet < 1))
|
||||
|| (c->error && (quiet < 2))) {
|
||||
fprintf(stderr, "%s (%s): ",
|
||||
(c->error) ? "ERROR" : "Warning", c->name);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
#define FAIL(c, ...) \
|
||||
@ -167,7 +178,7 @@ static int run_check(struct check *c, struct node *dt)
|
||||
|
||||
out:
|
||||
c->inprogress = 0;
|
||||
if ((c->status != PASSED) && (c->level == ERROR))
|
||||
if ((c->status != PASSED) && (c->error))
|
||||
error = 1;
|
||||
return error;
|
||||
}
|
||||
@ -176,6 +187,13 @@ static int run_check(struct check *c, struct node *dt)
|
||||
* Utility check functions
|
||||
*/
|
||||
|
||||
/* A check which always fails, for testing purposes only */
|
||||
static inline void check_always_fail(struct check *c, struct node *dt)
|
||||
{
|
||||
FAIL(c, "always_fail check");
|
||||
}
|
||||
TREE_CHECK(always_fail, NULL);
|
||||
|
||||
static void check_is_string(struct check *c, struct node *root,
|
||||
struct node *node)
|
||||
{
|
||||
@ -190,8 +208,10 @@ static void check_is_string(struct check *c, struct node *root,
|
||||
FAIL(c, "\"%s\" property in %s is not a string",
|
||||
propname, node->fullpath);
|
||||
}
|
||||
#define CHECK_IS_STRING(nm, propname, lvl) \
|
||||
CHECK(nm, NULL, check_is_string, NULL, (propname), (lvl))
|
||||
#define WARNING_IF_NOT_STRING(nm, propname) \
|
||||
WARNING(nm, NULL, check_is_string, NULL, (propname))
|
||||
#define ERROR_IF_NOT_STRING(nm, propname) \
|
||||
ERROR(nm, NULL, check_is_string, NULL, (propname))
|
||||
|
||||
static void check_is_cell(struct check *c, struct node *root,
|
||||
struct node *node)
|
||||
@ -207,8 +227,10 @@ static void check_is_cell(struct check *c, struct node *root,
|
||||
FAIL(c, "\"%s\" property in %s is not a single cell",
|
||||
propname, node->fullpath);
|
||||
}
|
||||
#define CHECK_IS_CELL(nm, propname, lvl) \
|
||||
CHECK(nm, NULL, check_is_cell, NULL, (propname), (lvl))
|
||||
#define WARNING_IF_NOT_CELL(nm, propname) \
|
||||
WARNING(nm, NULL, check_is_cell, NULL, (propname))
|
||||
#define ERROR_IF_NOT_CELL(nm, propname) \
|
||||
ERROR(nm, NULL, check_is_cell, NULL, (propname))
|
||||
|
||||
/*
|
||||
* Structural check functions
|
||||
@ -227,7 +249,7 @@ static void check_duplicate_node_names(struct check *c, struct node *dt,
|
||||
FAIL(c, "Duplicate node name %s",
|
||||
child->fullpath);
|
||||
}
|
||||
NODE_CHECK(duplicate_node_names, NULL, ERROR);
|
||||
NODE_ERROR(duplicate_node_names, NULL);
|
||||
|
||||
static void check_duplicate_property_names(struct check *c, struct node *dt,
|
||||
struct node *node)
|
||||
@ -240,7 +262,7 @@ static void check_duplicate_property_names(struct check *c, struct node *dt,
|
||||
FAIL(c, "Duplicate property name %s in %s",
|
||||
prop->name, node->fullpath);
|
||||
}
|
||||
NODE_CHECK(duplicate_property_names, NULL, ERROR);
|
||||
NODE_ERROR(duplicate_property_names, NULL);
|
||||
|
||||
#define LOWERCASE "abcdefghijklmnopqrstuvwxyz"
|
||||
#define UPPERCASE "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
@ -256,7 +278,7 @@ static void check_node_name_chars(struct check *c, struct node *dt,
|
||||
FAIL(c, "Bad character '%c' in node %s",
|
||||
node->name[n], node->fullpath);
|
||||
}
|
||||
NODE_CHECK(node_name_chars, PROPNODECHARS "@", ERROR);
|
||||
NODE_ERROR(node_name_chars, PROPNODECHARS "@");
|
||||
|
||||
static void check_node_name_format(struct check *c, struct node *dt,
|
||||
struct node *node)
|
||||
@ -265,7 +287,7 @@ static void check_node_name_format(struct check *c, struct node *dt,
|
||||
FAIL(c, "Node %s has multiple '@' characters in name",
|
||||
node->fullpath);
|
||||
}
|
||||
NODE_CHECK(node_name_format, NULL, ERROR, &node_name_chars);
|
||||
NODE_ERROR(node_name_format, NULL, &node_name_chars);
|
||||
|
||||
static void check_property_name_chars(struct check *c, struct node *dt,
|
||||
struct node *node, struct property *prop)
|
||||
@ -276,7 +298,63 @@ static void check_property_name_chars(struct check *c, struct node *dt,
|
||||
FAIL(c, "Bad character '%c' in property name \"%s\", node %s",
|
||||
prop->name[n], prop->name, node->fullpath);
|
||||
}
|
||||
PROP_CHECK(property_name_chars, PROPNODECHARS, ERROR);
|
||||
PROP_ERROR(property_name_chars, PROPNODECHARS);
|
||||
|
||||
#define DESCLABEL_FMT "%s%s%s%s%s"
|
||||
#define DESCLABEL_ARGS(node,prop,mark) \
|
||||
((mark) ? "value of " : ""), \
|
||||
((prop) ? "'" : ""), \
|
||||
((prop) ? (prop)->name : ""), \
|
||||
((prop) ? "' in " : ""), (node)->fullpath
|
||||
|
||||
static void check_duplicate_label(struct check *c, struct node *dt,
|
||||
const char *label, struct node *node,
|
||||
struct property *prop, struct marker *mark)
|
||||
{
|
||||
struct node *othernode = NULL;
|
||||
struct property *otherprop = NULL;
|
||||
struct marker *othermark = NULL;
|
||||
|
||||
othernode = get_node_by_label(dt, label);
|
||||
|
||||
if (!othernode)
|
||||
otherprop = get_property_by_label(dt, label, &othernode);
|
||||
if (!othernode)
|
||||
othermark = get_marker_label(dt, label, &othernode,
|
||||
&otherprop);
|
||||
|
||||
if (!othernode)
|
||||
return;
|
||||
|
||||
if ((othernode != node) || (otherprop != prop) || (othermark != mark))
|
||||
FAIL(c, "Duplicate label '%s' on " DESCLABEL_FMT
|
||||
" and " DESCLABEL_FMT,
|
||||
label, DESCLABEL_ARGS(node, prop, mark),
|
||||
DESCLABEL_ARGS(othernode, otherprop, othermark));
|
||||
}
|
||||
|
||||
static void check_duplicate_label_node(struct check *c, struct node *dt,
|
||||
struct node *node)
|
||||
{
|
||||
struct label *l;
|
||||
|
||||
for_each_label(node->labels, l)
|
||||
check_duplicate_label(c, dt, l->label, node, NULL, NULL);
|
||||
}
|
||||
static void check_duplicate_label_prop(struct check *c, struct node *dt,
|
||||
struct node *node, struct property *prop)
|
||||
{
|
||||
struct marker *m = prop->val.markers;
|
||||
struct label *l;
|
||||
|
||||
for_each_label(prop->labels, l)
|
||||
check_duplicate_label(c, dt, l->label, node, prop, NULL);
|
||||
|
||||
for_each_marker_of_type(m, LABEL)
|
||||
check_duplicate_label(c, dt, m->ref, node, prop, m);
|
||||
}
|
||||
ERROR(duplicate_label, NULL, check_duplicate_label_node,
|
||||
check_duplicate_label_prop, NULL);
|
||||
|
||||
static void check_explicit_phandles(struct check *c, struct node *root,
|
||||
struct node *node, struct property *prop)
|
||||
@ -335,7 +413,7 @@ static void check_explicit_phandles(struct check *c, struct node *root,
|
||||
|
||||
node->phandle = phandle;
|
||||
}
|
||||
PROP_CHECK(explicit_phandles, NULL, ERROR);
|
||||
PROP_ERROR(explicit_phandles, NULL);
|
||||
|
||||
static void check_name_properties(struct check *c, struct node *root,
|
||||
struct node *node)
|
||||
@ -364,8 +442,8 @@ static void check_name_properties(struct check *c, struct node *root,
|
||||
free(prop);
|
||||
}
|
||||
}
|
||||
CHECK_IS_STRING(name_is_string, "name", ERROR);
|
||||
NODE_CHECK(name_properties, NULL, ERROR, &name_is_string);
|
||||
ERROR_IF_NOT_STRING(name_is_string, "name");
|
||||
NODE_ERROR(name_properties, NULL, &name_is_string);
|
||||
|
||||
/*
|
||||
* Reference fixup functions
|
||||
@ -392,7 +470,7 @@ static void fixup_phandle_references(struct check *c, struct node *dt,
|
||||
*((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle);
|
||||
}
|
||||
}
|
||||
CHECK(phandle_references, NULL, NULL, fixup_phandle_references, NULL, ERROR,
|
||||
ERROR(phandle_references, NULL, NULL, fixup_phandle_references, NULL,
|
||||
&duplicate_node_names, &explicit_phandles);
|
||||
|
||||
static void fixup_path_references(struct check *c, struct node *dt,
|
||||
@ -417,19 +495,19 @@ static void fixup_path_references(struct check *c, struct node *dt,
|
||||
strlen(path) + 1);
|
||||
}
|
||||
}
|
||||
CHECK(path_references, NULL, NULL, fixup_path_references, NULL, ERROR,
|
||||
ERROR(path_references, NULL, NULL, fixup_path_references, NULL,
|
||||
&duplicate_node_names);
|
||||
|
||||
/*
|
||||
* Semantic checks
|
||||
*/
|
||||
CHECK_IS_CELL(address_cells_is_cell, "#address-cells", WARN);
|
||||
CHECK_IS_CELL(size_cells_is_cell, "#size-cells", WARN);
|
||||
CHECK_IS_CELL(interrupt_cells_is_cell, "#interrupt-cells", WARN);
|
||||
WARNING_IF_NOT_CELL(address_cells_is_cell, "#address-cells");
|
||||
WARNING_IF_NOT_CELL(size_cells_is_cell, "#size-cells");
|
||||
WARNING_IF_NOT_CELL(interrupt_cells_is_cell, "#interrupt-cells");
|
||||
|
||||
CHECK_IS_STRING(device_type_is_string, "device_type", WARN);
|
||||
CHECK_IS_STRING(model_is_string, "model", WARN);
|
||||
CHECK_IS_STRING(status_is_string, "status", WARN);
|
||||
WARNING_IF_NOT_STRING(device_type_is_string, "device_type");
|
||||
WARNING_IF_NOT_STRING(model_is_string, "model");
|
||||
WARNING_IF_NOT_STRING(status_is_string, "status");
|
||||
|
||||
static void fixup_addr_size_cells(struct check *c, struct node *dt,
|
||||
struct node *node)
|
||||
@ -447,8 +525,8 @@ static void fixup_addr_size_cells(struct check *c, struct node *dt,
|
||||
if (prop)
|
||||
node->size_cells = propval_cell(prop);
|
||||
}
|
||||
CHECK(addr_size_cells, NULL, fixup_addr_size_cells, NULL, NULL, WARN,
|
||||
&address_cells_is_cell, &size_cells_is_cell);
|
||||
WARNING(addr_size_cells, NULL, fixup_addr_size_cells, NULL, NULL,
|
||||
&address_cells_is_cell, &size_cells_is_cell);
|
||||
|
||||
#define node_addr_cells(n) \
|
||||
(((n)->addr_cells == -1) ? 2 : (n)->addr_cells)
|
||||
@ -482,7 +560,7 @@ static void check_reg_format(struct check *c, struct node *dt,
|
||||
"(#address-cells == %d, #size-cells == %d)",
|
||||
node->fullpath, prop->val.len, addr_cells, size_cells);
|
||||
}
|
||||
NODE_CHECK(reg_format, NULL, WARN, &addr_size_cells);
|
||||
NODE_WARNING(reg_format, NULL, &addr_size_cells);
|
||||
|
||||
static void check_ranges_format(struct check *c, struct node *dt,
|
||||
struct node *node)
|
||||
@ -523,7 +601,7 @@ static void check_ranges_format(struct check *c, struct node *dt,
|
||||
p_addr_cells, c_addr_cells, c_size_cells);
|
||||
}
|
||||
}
|
||||
NODE_CHECK(ranges_format, NULL, WARN, &addr_size_cells);
|
||||
NODE_WARNING(ranges_format, NULL, &addr_size_cells);
|
||||
|
||||
/*
|
||||
* Style checks
|
||||
@ -550,7 +628,7 @@ static void check_avoid_default_addr_size(struct check *c, struct node *dt,
|
||||
FAIL(c, "Relying on default #size-cells value for %s",
|
||||
node->fullpath);
|
||||
}
|
||||
NODE_CHECK(avoid_default_addr_size, NULL, WARN, &addr_size_cells);
|
||||
NODE_WARNING(avoid_default_addr_size, NULL, &addr_size_cells);
|
||||
|
||||
static void check_obsolete_chosen_interrupt_controller(struct check *c,
|
||||
struct node *dt)
|
||||
@ -567,12 +645,15 @@ static void check_obsolete_chosen_interrupt_controller(struct check *c,
|
||||
FAIL(c, "/chosen has obsolete \"interrupt-controller\" "
|
||||
"property");
|
||||
}
|
||||
TREE_CHECK(obsolete_chosen_interrupt_controller, NULL, WARN);
|
||||
TREE_WARNING(obsolete_chosen_interrupt_controller, NULL);
|
||||
|
||||
static struct check *check_table[] = {
|
||||
&duplicate_node_names, &duplicate_property_names,
|
||||
&node_name_chars, &node_name_format, &property_name_chars,
|
||||
&name_is_string, &name_properties,
|
||||
|
||||
&duplicate_label,
|
||||
|
||||
&explicit_phandles,
|
||||
&phandle_references, &path_references,
|
||||
|
||||
@ -583,8 +664,71 @@ static struct check *check_table[] = {
|
||||
|
||||
&avoid_default_addr_size,
|
||||
&obsolete_chosen_interrupt_controller,
|
||||
|
||||
&always_fail,
|
||||
};
|
||||
|
||||
static void enable_warning_error(struct check *c, bool warn, bool error)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Raising level, also raise it for prereqs */
|
||||
if ((warn && !c->warn) || (error && !c->error))
|
||||
for (i = 0; i < c->num_prereqs; i++)
|
||||
enable_warning_error(c->prereq[i], warn, error);
|
||||
|
||||
c->warn = c->warn || warn;
|
||||
c->error = c->error || error;
|
||||
}
|
||||
|
||||
static void disable_warning_error(struct check *c, bool warn, bool error)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Lowering level, also lower it for things this is the prereq
|
||||
* for */
|
||||
if ((warn && c->warn) || (error && c->error)) {
|
||||
for (i = 0; i < ARRAY_SIZE(check_table); i++) {
|
||||
struct check *cc = check_table[i];
|
||||
int j;
|
||||
|
||||
for (j = 0; j < cc->num_prereqs; j++)
|
||||
if (cc->prereq[j] == c)
|
||||
disable_warning_error(cc, warn, error);
|
||||
}
|
||||
}
|
||||
|
||||
c->warn = c->warn && !warn;
|
||||
c->error = c->error && !error;
|
||||
}
|
||||
|
||||
void parse_checks_option(bool warn, bool error, const char *optarg)
|
||||
{
|
||||
int i;
|
||||
const char *name = optarg;
|
||||
bool enable = true;
|
||||
|
||||
if ((strncmp(optarg, "no-", 3) == 0)
|
||||
|| (strncmp(optarg, "no_", 3) == 0)) {
|
||||
name = optarg + 3;
|
||||
enable = false;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(check_table); i++) {
|
||||
struct check *c = check_table[i];
|
||||
|
||||
if (streq(c->name, name)) {
|
||||
if (enable)
|
||||
enable_warning_error(c, warn, error);
|
||||
else
|
||||
disable_warning_error(c, warn, error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
die("Unrecognized check name \"%s\"\n", name);
|
||||
}
|
||||
|
||||
void process_checks(int force, struct boot_info *bi)
|
||||
{
|
||||
struct node *dt = bi->dt;
|
||||
@ -594,7 +738,7 @@ void process_checks(int force, struct boot_info *bi)
|
||||
for (i = 0; i < ARRAY_SIZE(check_table); i++) {
|
||||
struct check *c = check_table[i];
|
||||
|
||||
if (c->level != IGNORE)
|
||||
if (c->warn || c->error)
|
||||
error = error || run_check(c, dt);
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
* USA
|
||||
*/
|
||||
|
||||
%option noyywrap nounput noinput
|
||||
%option noyywrap nounput noinput never-interactive
|
||||
|
||||
%x INCLUDE
|
||||
%x BYTESTRING
|
||||
@ -210,8 +210,10 @@ static void convert_file(const char *fname)
|
||||
memcpy(newname, fname, len);
|
||||
memcpy(newname + len, suffix, sizeof(suffix));
|
||||
|
||||
srcpos_file = dtc_open_file(fname, NULL);
|
||||
yyin = srcpos_file->file;
|
||||
yyin = fopen(fname, "r");
|
||||
if (!yyin)
|
||||
die("Couldn't open input file %s: %s\n",
|
||||
fname, strerror(errno));
|
||||
|
||||
yyout = fopen(newname, "w");
|
||||
if (!yyout)
|
||||
|
120
data.c
120
data.c
@ -68,40 +68,6 @@ struct data data_copy_mem(const char *mem, int len)
|
||||
return d;
|
||||
}
|
||||
|
||||
static char get_oct_char(const char *s, int *i)
|
||||
{
|
||||
char x[4];
|
||||
char *endx;
|
||||
long val;
|
||||
|
||||
x[3] = '\0';
|
||||
strncpy(x, s + *i, 3);
|
||||
|
||||
val = strtol(x, &endx, 8);
|
||||
|
||||
assert(endx > x);
|
||||
|
||||
(*i) += endx - x;
|
||||
return val;
|
||||
}
|
||||
|
||||
static char get_hex_char(const char *s, int *i)
|
||||
{
|
||||
char x[3];
|
||||
char *endx;
|
||||
long val;
|
||||
|
||||
x[2] = '\0';
|
||||
strncpy(x, s + *i, 2);
|
||||
|
||||
val = strtol(x, &endx, 16);
|
||||
if (!(endx > x))
|
||||
die("\\x used with no following hex digits\n");
|
||||
|
||||
(*i) += endx - x;
|
||||
return val;
|
||||
}
|
||||
|
||||
struct data data_copy_escape_string(const char *s, int len)
|
||||
{
|
||||
int i = 0;
|
||||
@ -114,53 +80,10 @@ struct data data_copy_escape_string(const char *s, int len)
|
||||
while (i < len) {
|
||||
char c = s[i++];
|
||||
|
||||
if (c != '\\') {
|
||||
q[d.len++] = c;
|
||||
continue;
|
||||
}
|
||||
if (c == '\\')
|
||||
c = get_escape_char(s, &i);
|
||||
|
||||
c = s[i++];
|
||||
assert(c);
|
||||
switch (c) {
|
||||
case 'a':
|
||||
q[d.len++] = '\a';
|
||||
break;
|
||||
case 'b':
|
||||
q[d.len++] = '\b';
|
||||
break;
|
||||
case 't':
|
||||
q[d.len++] = '\t';
|
||||
break;
|
||||
case 'n':
|
||||
q[d.len++] = '\n';
|
||||
break;
|
||||
case 'v':
|
||||
q[d.len++] = '\v';
|
||||
break;
|
||||
case 'f':
|
||||
q[d.len++] = '\f';
|
||||
break;
|
||||
case 'r':
|
||||
q[d.len++] = '\r';
|
||||
break;
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
i--; /* need to re-read the first digit as
|
||||
* part of the octal value */
|
||||
q[d.len++] = get_oct_char(s, &i);
|
||||
break;
|
||||
case 'x':
|
||||
q[d.len++] = get_hex_char(s, &i);
|
||||
break;
|
||||
default:
|
||||
q[d.len++] = c;
|
||||
}
|
||||
q[d.len++] = c;
|
||||
}
|
||||
|
||||
q[d.len++] = '\0';
|
||||
@ -245,11 +168,33 @@ struct data data_merge(struct data d1, struct data d2)
|
||||
return d;
|
||||
}
|
||||
|
||||
struct data data_append_cell(struct data d, cell_t word)
|
||||
struct data data_append_integer(struct data d, uint64_t value, int bits)
|
||||
{
|
||||
cell_t beword = cpu_to_fdt32(word);
|
||||
uint8_t value_8;
|
||||
uint16_t value_16;
|
||||
uint32_t value_32;
|
||||
uint64_t value_64;
|
||||
|
||||
return data_append_data(d, &beword, sizeof(beword));
|
||||
switch (bits) {
|
||||
case 8:
|
||||
value_8 = value;
|
||||
return data_append_data(d, &value_8, 1);
|
||||
|
||||
case 16:
|
||||
value_16 = cpu_to_fdt16(value);
|
||||
return data_append_data(d, &value_16, 2);
|
||||
|
||||
case 32:
|
||||
value_32 = cpu_to_fdt32(value);
|
||||
return data_append_data(d, &value_32, 4);
|
||||
|
||||
case 64:
|
||||
value_64 = cpu_to_fdt64(value);
|
||||
return data_append_data(d, &value_64, 8);
|
||||
|
||||
default:
|
||||
die("Invalid literal size (%d)\n", bits);
|
||||
}
|
||||
}
|
||||
|
||||
struct data data_append_re(struct data d, const struct fdt_reserve_entry *re)
|
||||
@ -262,11 +207,14 @@ struct data data_append_re(struct data d, const struct fdt_reserve_entry *re)
|
||||
return data_append_data(d, &bere, sizeof(bere));
|
||||
}
|
||||
|
||||
struct data data_append_cell(struct data d, cell_t word)
|
||||
{
|
||||
return data_append_integer(d, word, sizeof(word) * 8);
|
||||
}
|
||||
|
||||
struct data data_append_addr(struct data d, uint64_t addr)
|
||||
{
|
||||
uint64_t beaddr = cpu_to_fdt64(addr);
|
||||
|
||||
return data_append_data(d, &beaddr, sizeof(beaddr));
|
||||
return data_append_integer(d, addr, sizeof(addr) * 8);
|
||||
}
|
||||
|
||||
struct data data_append_byte(struct data d, uint8_t byte)
|
||||
|
124
dtc-lexer.l
124
dtc-lexer.l
@ -18,7 +18,7 @@
|
||||
* USA
|
||||
*/
|
||||
|
||||
%option noyywrap nounput noinput yylineno
|
||||
%option noyywrap nounput noinput never-interactive
|
||||
|
||||
%x INCLUDE
|
||||
%x BYTESTRING
|
||||
@ -29,6 +29,7 @@ PROPNODECHAR [a-zA-Z0-9,._+*#?@-]
|
||||
PATHCHAR ({PROPNODECHAR}|[/])
|
||||
LABEL [a-zA-Z_][a-zA-Z0-9_]*
|
||||
STRING \"([^\\"]|\\.)*\"
|
||||
CHAR_LITERAL '([^']|\\')*'
|
||||
WS [[:space:]]
|
||||
COMMENT "/*"([^*]|\*+[^*/])*\*+"/"
|
||||
LINECOMMENT "//".*\n
|
||||
@ -38,10 +39,12 @@ LINECOMMENT "//".*\n
|
||||
#include "srcpos.h"
|
||||
#include "dtc-parser.tab.h"
|
||||
|
||||
YYLTYPE yylloc;
|
||||
|
||||
/* CAUTION: this will stop working if we ever use yyless() or yyunput() */
|
||||
#define YY_USER_ACTION \
|
||||
{ \
|
||||
yylloc.file = srcpos_file; \
|
||||
yylloc.first_line = yylineno; \
|
||||
srcpos_update(&yylloc, yytext, yyleng); \
|
||||
}
|
||||
|
||||
/*#define LEXDEBUG 1*/
|
||||
@ -94,6 +97,12 @@ static int pop_input_file(void);
|
||||
return DT_MEMRESERVE;
|
||||
}
|
||||
|
||||
<*>"/bits/" {
|
||||
DPRINT("Keyword: /bits/\n");
|
||||
BEGIN_DEFAULT();
|
||||
return DT_BITS;
|
||||
}
|
||||
|
||||
<*>{LABEL}: {
|
||||
DPRINT("Label: %s\n", yytext);
|
||||
yylval.labelref = xstrdup(yytext);
|
||||
@ -101,19 +110,26 @@ static int pop_input_file(void);
|
||||
return DT_LABEL;
|
||||
}
|
||||
|
||||
<V1>[0-9]+|0[xX][0-9a-fA-F]+ {
|
||||
<V1>([0-9]+|0[xX][0-9a-fA-F]+)(U|L|UL|LL|ULL)? {
|
||||
yylval.literal = xstrdup(yytext);
|
||||
DPRINT("Literal: '%s'\n", yylval.literal);
|
||||
return DT_LITERAL;
|
||||
}
|
||||
|
||||
\&{LABEL} { /* label reference */
|
||||
<*>{CHAR_LITERAL} {
|
||||
yytext[yyleng-1] = '\0';
|
||||
yylval.literal = xstrdup(yytext+1);
|
||||
DPRINT("Character literal: %s\n", yylval.literal);
|
||||
return DT_CHAR_LITERAL;
|
||||
}
|
||||
|
||||
<*>\&{LABEL} { /* label reference */
|
||||
DPRINT("Ref: %s\n", yytext+1);
|
||||
yylval.labelref = xstrdup(yytext+1);
|
||||
return DT_REF;
|
||||
}
|
||||
|
||||
"&{/"{PATHCHAR}+\} { /* new-style path reference */
|
||||
<*>"&{/"{PATHCHAR}+\} { /* new-style path reference */
|
||||
yytext[yyleng-1] = '\0';
|
||||
DPRINT("Ref: %s\n", yytext+2);
|
||||
yylval.labelref = xstrdup(yytext+2);
|
||||
@ -148,6 +164,15 @@ static int pop_input_file(void);
|
||||
<*>{COMMENT}+ /* eat C-style comments */
|
||||
<*>{LINECOMMENT}+ /* eat C++-style comments */
|
||||
|
||||
<*>"<<" { return DT_LSHIFT; };
|
||||
<*>">>" { return DT_RSHIFT; };
|
||||
<*>"<=" { return DT_LE; };
|
||||
<*>">=" { return DT_GE; };
|
||||
<*>"==" { return DT_EQ; };
|
||||
<*>"!=" { return DT_NE; };
|
||||
<*>"&&" { return DT_AND; };
|
||||
<*>"||" { return DT_OR; };
|
||||
|
||||
<*>. {
|
||||
DPRINT("Char: %c (\\x%02x)\n", yytext[0],
|
||||
(unsigned)yytext[0]);
|
||||
@ -165,100 +190,25 @@ static int pop_input_file(void);
|
||||
|
||||
%%
|
||||
|
||||
|
||||
/*
|
||||
* Stack of nested include file contexts.
|
||||
*/
|
||||
|
||||
struct incl_file {
|
||||
struct dtc_file *file;
|
||||
YY_BUFFER_STATE yy_prev_buf;
|
||||
int yy_prev_lineno;
|
||||
struct incl_file *prev;
|
||||
};
|
||||
|
||||
static struct incl_file *incl_file_stack;
|
||||
|
||||
|
||||
/*
|
||||
* Detect infinite include recursion.
|
||||
*/
|
||||
#define MAX_INCLUDE_DEPTH (100)
|
||||
|
||||
static int incl_depth = 0;
|
||||
|
||||
|
||||
static void push_input_file(const char *filename)
|
||||
{
|
||||
struct incl_file *incl_file;
|
||||
struct dtc_file *newfile;
|
||||
struct search_path search, *searchptr = NULL;
|
||||
|
||||
assert(filename);
|
||||
|
||||
if (incl_depth++ >= MAX_INCLUDE_DEPTH)
|
||||
die("Includes nested too deeply");
|
||||
srcfile_push(filename);
|
||||
|
||||
if (srcpos_file) {
|
||||
search.dir = srcpos_file->dir;
|
||||
search.next = NULL;
|
||||
search.prev = NULL;
|
||||
searchptr = &search;
|
||||
}
|
||||
yyin = current_srcfile->f;
|
||||
|
||||
newfile = dtc_open_file(filename, searchptr);
|
||||
|
||||
incl_file = xmalloc(sizeof(struct incl_file));
|
||||
|
||||
/*
|
||||
* Save current context.
|
||||
*/
|
||||
incl_file->yy_prev_buf = YY_CURRENT_BUFFER;
|
||||
incl_file->yy_prev_lineno = yylineno;
|
||||
incl_file->file = srcpos_file;
|
||||
incl_file->prev = incl_file_stack;
|
||||
|
||||
incl_file_stack = incl_file;
|
||||
|
||||
/*
|
||||
* Establish new context.
|
||||
*/
|
||||
srcpos_file = newfile;
|
||||
yylineno = 1;
|
||||
yyin = newfile->file;
|
||||
yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
|
||||
yypush_buffer_state(yy_create_buffer(yyin, YY_BUF_SIZE));
|
||||
}
|
||||
|
||||
|
||||
static int pop_input_file(void)
|
||||
{
|
||||
struct incl_file *incl_file;
|
||||
|
||||
if (incl_file_stack == 0)
|
||||
if (srcfile_pop() == 0)
|
||||
return 0;
|
||||
|
||||
dtc_close_file(srcpos_file);
|
||||
|
||||
/*
|
||||
* Pop.
|
||||
*/
|
||||
--incl_depth;
|
||||
incl_file = incl_file_stack;
|
||||
incl_file_stack = incl_file->prev;
|
||||
|
||||
/*
|
||||
* Recover old context.
|
||||
*/
|
||||
yy_delete_buffer(YY_CURRENT_BUFFER);
|
||||
yy_switch_to_buffer(incl_file->yy_prev_buf);
|
||||
yylineno = incl_file->yy_prev_lineno;
|
||||
srcpos_file = incl_file->file;
|
||||
yyin = incl_file->file ? incl_file->file->file : NULL;
|
||||
|
||||
/*
|
||||
* Free old state.
|
||||
*/
|
||||
free(incl_file);
|
||||
yypop_buffer_state();
|
||||
yyin = current_srcfile->f;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
331
dtc-parser.y
331
dtc-parser.y
@ -18,21 +18,23 @@
|
||||
* USA
|
||||
*/
|
||||
|
||||
%locations
|
||||
|
||||
%{
|
||||
#include <stdio.h>
|
||||
|
||||
#include "dtc.h"
|
||||
#include "srcpos.h"
|
||||
|
||||
YYLTYPE yylloc;
|
||||
|
||||
extern int yylex(void);
|
||||
extern void print_error(char const *fmt, ...);
|
||||
extern void yyerror(char const *s);
|
||||
|
||||
extern struct boot_info *the_boot_info;
|
||||
extern int treesource_error;
|
||||
|
||||
static unsigned long long eval_literal(const char *s, int base, int bits);
|
||||
static unsigned char eval_char_literal(const char *s);
|
||||
%}
|
||||
|
||||
%union {
|
||||
@ -43,19 +45,26 @@ static unsigned long long eval_literal(const char *s, int base, int bits);
|
||||
uint8_t byte;
|
||||
struct data data;
|
||||
|
||||
uint64_t addr;
|
||||
cell_t cell;
|
||||
struct {
|
||||
struct data data;
|
||||
int bits;
|
||||
} array;
|
||||
|
||||
struct property *prop;
|
||||
struct property *proplist;
|
||||
struct node *node;
|
||||
struct node *nodelist;
|
||||
struct reserve_info *re;
|
||||
uint64_t integer;
|
||||
}
|
||||
|
||||
%token DT_V1
|
||||
%token DT_MEMRESERVE
|
||||
%token DT_LSHIFT DT_RSHIFT DT_LE DT_GE DT_EQ DT_NE DT_AND DT_OR
|
||||
%token DT_BITS
|
||||
%token <propnodename> DT_PROPNODENAME
|
||||
%token <literal> DT_LITERAL
|
||||
%token <literal> DT_CHAR_LITERAL
|
||||
%token <cbase> DT_BASE
|
||||
%token <byte> DT_BYTE
|
||||
%token <data> DT_STRING
|
||||
@ -67,9 +76,7 @@ static unsigned long long eval_literal(const char *s, int base, int bits);
|
||||
%type <data> propdataprefix
|
||||
%type <re> memreserve
|
||||
%type <re> memreserves
|
||||
%type <addr> addr
|
||||
%type <data> celllist
|
||||
%type <cell> cellval
|
||||
%type <array> arrayprefix
|
||||
%type <data> bytestring
|
||||
%type <prop> propdef
|
||||
%type <proplist> proplist
|
||||
@ -78,14 +85,29 @@ static unsigned long long eval_literal(const char *s, int base, int bits);
|
||||
%type <node> nodedef
|
||||
%type <node> subnode
|
||||
%type <nodelist> subnodes
|
||||
%type <labelref> label
|
||||
|
||||
%type <integer> integer_prim
|
||||
%type <integer> integer_unary
|
||||
%type <integer> integer_mul
|
||||
%type <integer> integer_add
|
||||
%type <integer> integer_shift
|
||||
%type <integer> integer_rela
|
||||
%type <integer> integer_eq
|
||||
%type <integer> integer_bitand
|
||||
%type <integer> integer_bitxor
|
||||
%type <integer> integer_bitor
|
||||
%type <integer> integer_and
|
||||
%type <integer> integer_or
|
||||
%type <integer> integer_trinary
|
||||
%type <integer> integer_expr
|
||||
|
||||
%%
|
||||
|
||||
sourcefile:
|
||||
DT_V1 ';' memreserves devicetree
|
||||
{
|
||||
the_boot_info = build_boot_info($3, $4, 0);
|
||||
the_boot_info = build_boot_info($3, $4,
|
||||
guess_boot_cpuid($4));
|
||||
}
|
||||
;
|
||||
|
||||
@ -101,23 +123,35 @@ memreserves:
|
||||
;
|
||||
|
||||
memreserve:
|
||||
label DT_MEMRESERVE addr addr ';'
|
||||
DT_MEMRESERVE integer_prim integer_prim ';'
|
||||
{
|
||||
$$ = build_reserve_entry($3, $4, $1);
|
||||
$$ = build_reserve_entry($2, $3);
|
||||
}
|
||||
| DT_LABEL memreserve
|
||||
{
|
||||
add_label(&$2->labels, $1);
|
||||
$$ = $2;
|
||||
}
|
||||
;
|
||||
|
||||
addr:
|
||||
DT_LITERAL
|
||||
{
|
||||
$$ = eval_literal($1, 0, 64);
|
||||
}
|
||||
;
|
||||
|
||||
devicetree:
|
||||
'/' nodedef
|
||||
{
|
||||
$$ = name_node($2, "", NULL);
|
||||
$$ = name_node($2, "");
|
||||
}
|
||||
| devicetree '/' nodedef
|
||||
{
|
||||
$$ = merge_nodes($1, $3);
|
||||
}
|
||||
| devicetree DT_REF nodedef
|
||||
{
|
||||
struct node *target = get_node_by_ref($1, $2);
|
||||
|
||||
if (target)
|
||||
merge_nodes(target, $3);
|
||||
else
|
||||
print_error("label or path, '%s', not found", $2);
|
||||
$$ = $1;
|
||||
}
|
||||
;
|
||||
|
||||
@ -140,13 +174,18 @@ proplist:
|
||||
;
|
||||
|
||||
propdef:
|
||||
label DT_PROPNODENAME '=' propdata ';'
|
||||
DT_PROPNODENAME '=' propdata ';'
|
||||
{
|
||||
$$ = build_property($2, $4, $1);
|
||||
$$ = build_property($1, $3);
|
||||
}
|
||||
| label DT_PROPNODENAME ';'
|
||||
| DT_PROPNODENAME ';'
|
||||
{
|
||||
$$ = build_property($2, empty_data, $1);
|
||||
$$ = build_property($1, empty_data);
|
||||
}
|
||||
| DT_LABEL propdef
|
||||
{
|
||||
add_label(&$2->labels, $1);
|
||||
$$ = $2;
|
||||
}
|
||||
;
|
||||
|
||||
@ -155,9 +194,9 @@ propdata:
|
||||
{
|
||||
$$ = data_merge($1, $2);
|
||||
}
|
||||
| propdataprefix '<' celllist '>'
|
||||
| propdataprefix arrayprefix '>'
|
||||
{
|
||||
$$ = data_merge($1, $3);
|
||||
$$ = data_merge($1, $2.data);
|
||||
}
|
||||
| propdataprefix '[' bytestring ']'
|
||||
{
|
||||
@ -167,35 +206,32 @@ propdata:
|
||||
{
|
||||
$$ = data_add_marker($1, REF_PATH, $2);
|
||||
}
|
||||
| propdataprefix DT_INCBIN '(' DT_STRING ',' addr ',' addr ')'
|
||||
| propdataprefix DT_INCBIN '(' DT_STRING ',' integer_prim ',' integer_prim ')'
|
||||
{
|
||||
struct search_path path = { srcpos_file->dir, NULL, NULL };
|
||||
struct dtc_file *file = dtc_open_file($4.val, &path);
|
||||
struct data d = empty_data;
|
||||
FILE *f = srcfile_relative_open($4.val, NULL);
|
||||
struct data d;
|
||||
|
||||
if ($6 != 0)
|
||||
if (fseek(file->file, $6, SEEK_SET) != 0)
|
||||
srcpos_error(&yylloc,
|
||||
"Couldn't seek to offset %llu in \"%s\": %s",
|
||||
if (fseek(f, $6, SEEK_SET) != 0)
|
||||
print_error("Couldn't seek to offset %llu in \"%s\": %s",
|
||||
(unsigned long long)$6,
|
||||
$4.val,
|
||||
strerror(errno));
|
||||
|
||||
d = data_copy_file(file->file, $8);
|
||||
d = data_copy_file(f, $8);
|
||||
|
||||
$$ = data_merge($1, d);
|
||||
dtc_close_file(file);
|
||||
fclose(f);
|
||||
}
|
||||
| propdataprefix DT_INCBIN '(' DT_STRING ')'
|
||||
{
|
||||
struct search_path path = { srcpos_file->dir, NULL, NULL };
|
||||
struct dtc_file *file = dtc_open_file($4.val, &path);
|
||||
FILE *f = srcfile_relative_open($4.val, NULL);
|
||||
struct data d = empty_data;
|
||||
|
||||
d = data_copy_file(file->file, -1);
|
||||
d = data_copy_file(f, -1);
|
||||
|
||||
$$ = data_merge($1, d);
|
||||
dtc_close_file(file);
|
||||
fclose(f);
|
||||
}
|
||||
| propdata DT_LABEL
|
||||
{
|
||||
@ -218,31 +254,154 @@ propdataprefix:
|
||||
}
|
||||
;
|
||||
|
||||
celllist:
|
||||
/* empty */
|
||||
arrayprefix:
|
||||
DT_BITS DT_LITERAL '<'
|
||||
{
|
||||
$$ = empty_data;
|
||||
$$.data = empty_data;
|
||||
$$.bits = eval_literal($2, 0, 7);
|
||||
|
||||
if (($$.bits != 8) &&
|
||||
($$.bits != 16) &&
|
||||
($$.bits != 32) &&
|
||||
($$.bits != 64))
|
||||
{
|
||||
print_error("Only 8, 16, 32 and 64-bit elements"
|
||||
" are currently supported");
|
||||
$$.bits = 32;
|
||||
}
|
||||
}
|
||||
| celllist cellval
|
||||
| '<'
|
||||
{
|
||||
$$ = data_append_cell($1, $2);
|
||||
$$.data = empty_data;
|
||||
$$.bits = 32;
|
||||
}
|
||||
| celllist DT_REF
|
||||
| arrayprefix integer_prim
|
||||
{
|
||||
$$ = data_append_cell(data_add_marker($1, REF_PHANDLE,
|
||||
$2), -1);
|
||||
if ($1.bits < 64) {
|
||||
uint64_t mask = (1ULL << $1.bits) - 1;
|
||||
/*
|
||||
* Bits above mask must either be all zero
|
||||
* (positive within range of mask) or all one
|
||||
* (negative and sign-extended). The second
|
||||
* condition is true if when we set all bits
|
||||
* within the mask to one (i.e. | in the
|
||||
* mask), all bits are one.
|
||||
*/
|
||||
if (($2 > mask) && (($2 | mask) != -1ULL))
|
||||
print_error(
|
||||
"integer value out of range "
|
||||
"%016lx (%d bits)", $1.bits);
|
||||
}
|
||||
|
||||
$$.data = data_append_integer($1.data, $2, $1.bits);
|
||||
}
|
||||
| celllist DT_LABEL
|
||||
| arrayprefix DT_REF
|
||||
{
|
||||
$$ = data_add_marker($1, LABEL, $2);
|
||||
uint64_t val = ~0ULL >> (64 - $1.bits);
|
||||
|
||||
if ($1.bits == 32)
|
||||
$1.data = data_add_marker($1.data,
|
||||
REF_PHANDLE,
|
||||
$2);
|
||||
else
|
||||
print_error("References are only allowed in "
|
||||
"arrays with 32-bit elements.");
|
||||
|
||||
$$.data = data_append_integer($1.data, val, $1.bits);
|
||||
}
|
||||
| arrayprefix DT_LABEL
|
||||
{
|
||||
$$.data = data_add_marker($1.data, LABEL, $2);
|
||||
}
|
||||
;
|
||||
|
||||
cellval:
|
||||
integer_prim:
|
||||
DT_LITERAL
|
||||
{
|
||||
$$ = eval_literal($1, 0, 32);
|
||||
$$ = eval_literal($1, 0, 64);
|
||||
}
|
||||
| DT_CHAR_LITERAL
|
||||
{
|
||||
$$ = eval_char_literal($1);
|
||||
}
|
||||
| '(' integer_expr ')'
|
||||
{
|
||||
$$ = $2;
|
||||
}
|
||||
;
|
||||
|
||||
integer_expr:
|
||||
integer_trinary
|
||||
;
|
||||
|
||||
integer_trinary:
|
||||
integer_or
|
||||
| integer_or '?' integer_expr ':' integer_trinary { $$ = $1 ? $3 : $5; }
|
||||
;
|
||||
|
||||
integer_or:
|
||||
integer_and
|
||||
| integer_or DT_OR integer_and { $$ = $1 || $3; }
|
||||
;
|
||||
|
||||
integer_and:
|
||||
integer_bitor
|
||||
| integer_and DT_AND integer_bitor { $$ = $1 && $3; }
|
||||
;
|
||||
|
||||
integer_bitor:
|
||||
integer_bitxor
|
||||
| integer_bitor '|' integer_bitxor { $$ = $1 | $3; }
|
||||
;
|
||||
|
||||
integer_bitxor:
|
||||
integer_bitand
|
||||
| integer_bitxor '^' integer_bitand { $$ = $1 ^ $3; }
|
||||
;
|
||||
|
||||
integer_bitand:
|
||||
integer_eq
|
||||
| integer_bitand '&' integer_eq { $$ = $1 & $3; }
|
||||
;
|
||||
|
||||
integer_eq:
|
||||
integer_rela
|
||||
| integer_eq DT_EQ integer_rela { $$ = $1 == $3; }
|
||||
| integer_eq DT_NE integer_rela { $$ = $1 != $3; }
|
||||
;
|
||||
|
||||
integer_rela:
|
||||
integer_shift
|
||||
| integer_rela '<' integer_shift { $$ = $1 < $3; }
|
||||
| integer_rela '>' integer_shift { $$ = $1 > $3; }
|
||||
| integer_rela DT_LE integer_shift { $$ = $1 <= $3; }
|
||||
| integer_rela DT_GE integer_shift { $$ = $1 >= $3; }
|
||||
;
|
||||
|
||||
integer_shift:
|
||||
integer_shift DT_LSHIFT integer_add { $$ = $1 << $3; }
|
||||
| integer_shift DT_RSHIFT integer_add { $$ = $1 >> $3; }
|
||||
| integer_add
|
||||
;
|
||||
|
||||
integer_add:
|
||||
integer_add '+' integer_mul { $$ = $1 + $3; }
|
||||
| integer_add '-' integer_mul { $$ = $1 - $3; }
|
||||
| integer_mul
|
||||
;
|
||||
|
||||
integer_mul:
|
||||
integer_mul '*' integer_unary { $$ = $1 * $3; }
|
||||
| integer_mul '/' integer_unary { $$ = $1 / $3; }
|
||||
| integer_mul '%' integer_unary { $$ = $1 % $3; }
|
||||
| integer_unary
|
||||
;
|
||||
|
||||
integer_unary:
|
||||
integer_prim
|
||||
| '-' integer_unary { $$ = -$2; }
|
||||
| '~' integer_unary { $$ = ~$2; }
|
||||
| '!' integer_unary { $$ = !$2; }
|
||||
;
|
||||
|
||||
bytestring:
|
||||
@ -265,43 +424,46 @@ subnodes:
|
||||
{
|
||||
$$ = NULL;
|
||||
}
|
||||
| subnode subnodes
|
||||
| subnode subnodes
|
||||
{
|
||||
$$ = chain_node($1, $2);
|
||||
}
|
||||
| subnode propdef
|
||||
{
|
||||
yyerror("syntax error: properties must precede subnodes");
|
||||
print_error("syntax error: properties must precede subnodes");
|
||||
YYERROR;
|
||||
}
|
||||
;
|
||||
|
||||
subnode:
|
||||
label DT_PROPNODENAME nodedef
|
||||
DT_PROPNODENAME nodedef
|
||||
{
|
||||
$$ = name_node($3, $2, $1);
|
||||
$$ = name_node($2, $1);
|
||||
}
|
||||
;
|
||||
|
||||
label:
|
||||
/* empty */
|
||||
| DT_LABEL subnode
|
||||
{
|
||||
$$ = NULL;
|
||||
}
|
||||
| DT_LABEL
|
||||
{
|
||||
$$ = $1;
|
||||
add_label(&$2->labels, $1);
|
||||
$$ = $2;
|
||||
}
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
void yyerror(char const *s)
|
||||
void print_error(char const *fmt, ...)
|
||||
{
|
||||
srcpos_error(&yylloc, "%s", s);
|
||||
va_list va;
|
||||
|
||||
va_start(va, fmt);
|
||||
srcpos_verror(&yylloc, fmt, va);
|
||||
va_end(va);
|
||||
|
||||
treesource_error = 1;
|
||||
}
|
||||
|
||||
void yyerror(char const *s) {
|
||||
print_error("%s", s);
|
||||
}
|
||||
|
||||
static unsigned long long eval_literal(const char *s, int base, int bits)
|
||||
{
|
||||
unsigned long long val;
|
||||
@ -309,12 +471,41 @@ static unsigned long long eval_literal(const char *s, int base, int bits)
|
||||
|
||||
errno = 0;
|
||||
val = strtoull(s, &e, base);
|
||||
if (*e)
|
||||
yyerror("bad characters in literal");
|
||||
else if ((errno == ERANGE)
|
||||
if (*e) {
|
||||
size_t uls = strspn(e, "UL");
|
||||
if (e[uls])
|
||||
print_error("bad characters in literal");
|
||||
}
|
||||
if ((errno == ERANGE)
|
||||
|| ((bits < 64) && (val >= (1ULL << bits))))
|
||||
yyerror("literal out of range");
|
||||
print_error("literal out of range");
|
||||
else if (errno != 0)
|
||||
yyerror("bad literal");
|
||||
print_error("bad literal");
|
||||
return val;
|
||||
}
|
||||
|
||||
static unsigned char eval_char_literal(const char *s)
|
||||
{
|
||||
int i = 1;
|
||||
char c = s[0];
|
||||
|
||||
if (c == '\0')
|
||||
{
|
||||
print_error("empty character literal");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the first character in the character literal is a \ then process
|
||||
* the remaining characters as an escape encoding. If the first
|
||||
* character is neither an escape or a terminator it should be the only
|
||||
* character in the literal and will be returned.
|
||||
*/
|
||||
if (c == '\\')
|
||||
c = get_escape_char(s, &i);
|
||||
|
||||
if (s[i] != '\0')
|
||||
print_error("malformed character literal");
|
||||
|
||||
return c;
|
||||
}
|
||||
|
75
dtc.c
75
dtc.c
@ -32,30 +32,6 @@ int minsize; /* Minimum blob size */
|
||||
int padsize; /* Additional padding to blob */
|
||||
int phandle_format = PHANDLE_BOTH; /* Use linux,phandle or phandle properties */
|
||||
|
||||
char *join_path(const char *path, const char *name)
|
||||
{
|
||||
int lenp = strlen(path);
|
||||
int lenn = strlen(name);
|
||||
int len;
|
||||
int needslash = 1;
|
||||
char *str;
|
||||
|
||||
len = lenp + lenn + 2;
|
||||
if ((lenp > 0) && (path[lenp-1] == '/')) {
|
||||
needslash = 0;
|
||||
len--;
|
||||
}
|
||||
|
||||
str = xmalloc(len);
|
||||
memcpy(str, path, lenp);
|
||||
if (needslash) {
|
||||
str[lenp] = '/';
|
||||
lenp++;
|
||||
}
|
||||
memcpy(str+lenp, name, lenn+1);
|
||||
return str;
|
||||
}
|
||||
|
||||
static void fill_fullpaths(struct node *tree, const char *prefix)
|
||||
{
|
||||
struct node *child;
|
||||
@ -95,6 +71,7 @@ static void __attribute__ ((noreturn)) usage(void)
|
||||
fprintf(stderr, "\t\t\tasm - assembler source\n");
|
||||
fprintf(stderr, "\t-V <output version>\n");
|
||||
fprintf(stderr, "\t\tBlob version to produce, defaults to %d (relevant for dtb\n\t\tand asm output only)\n", DEFAULT_FDT_VERSION);
|
||||
fprintf(stderr, "\t-d <output dependency file>\n");
|
||||
fprintf(stderr, "\t-R <number>\n");
|
||||
fprintf(stderr, "\t\tMake space for <number> reserve map entries (relevant for \n\t\tdtb and asm output only)\n");
|
||||
fprintf(stderr, "\t-S <bytes>\n");
|
||||
@ -105,6 +82,10 @@ static void __attribute__ ((noreturn)) usage(void)
|
||||
fprintf(stderr, "\t\tSet the physical boot cpu\n");
|
||||
fprintf(stderr, "\t-f\n");
|
||||
fprintf(stderr, "\t\tForce - try to produce output even if the input tree has errors\n");
|
||||
fprintf(stderr, "\t-i\n");
|
||||
fprintf(stderr, "\t\tAdd a path to search for include files\n");
|
||||
fprintf(stderr, "\t-s\n");
|
||||
fprintf(stderr, "\t\tSort nodes and properties before outputting (only useful for\n\t\tcomparing trees)\n");
|
||||
fprintf(stderr, "\t-v\n");
|
||||
fprintf(stderr, "\t\tPrint DTC version and exit\n");
|
||||
fprintf(stderr, "\t-H <phandle format>\n");
|
||||
@ -112,6 +93,9 @@ static void __attribute__ ((noreturn)) usage(void)
|
||||
fprintf(stderr, "\t\t\tlegacy - \"linux,phandle\" properties only\n");
|
||||
fprintf(stderr, "\t\t\tepapr - \"phandle\" properties only\n");
|
||||
fprintf(stderr, "\t\t\tboth - Both \"linux,phandle\" and \"phandle\" properties\n");
|
||||
fprintf(stderr, "\t-W [no-]<checkname>\n");
|
||||
fprintf(stderr, "\t-E [no-]<checkname>\n");
|
||||
fprintf(stderr, "\t\t\tenable or disable warnings and errors\n");
|
||||
exit(3);
|
||||
}
|
||||
|
||||
@ -121,7 +105,8 @@ int main(int argc, char *argv[])
|
||||
const char *inform = "dts";
|
||||
const char *outform = "dts";
|
||||
const char *outname = "-";
|
||||
int force = 0, check = 0;
|
||||
const char *depname = NULL;
|
||||
int force = 0, sort = 0;
|
||||
const char *arg;
|
||||
int opt;
|
||||
FILE *outf = NULL;
|
||||
@ -133,7 +118,8 @@ int main(int argc, char *argv[])
|
||||
minsize = 0;
|
||||
padsize = 0;
|
||||
|
||||
while ((opt = getopt(argc, argv, "hI:O:o:V:R:S:p:fcqb:vH:")) != EOF) {
|
||||
while ((opt = getopt(argc, argv, "hI:O:o:V:d:R:S:p:fqb:i:vH:sW:E:"))
|
||||
!= EOF) {
|
||||
switch (opt) {
|
||||
case 'I':
|
||||
inform = optarg;
|
||||
@ -147,6 +133,9 @@ int main(int argc, char *argv[])
|
||||
case 'V':
|
||||
outversion = strtol(optarg, NULL, 0);
|
||||
break;
|
||||
case 'd':
|
||||
depname = optarg;
|
||||
break;
|
||||
case 'R':
|
||||
reservenum = strtol(optarg, NULL, 0);
|
||||
break;
|
||||
@ -159,15 +148,15 @@ int main(int argc, char *argv[])
|
||||
case 'f':
|
||||
force = 1;
|
||||
break;
|
||||
case 'c':
|
||||
check = 1;
|
||||
break;
|
||||
case 'q':
|
||||
quiet++;
|
||||
break;
|
||||
case 'b':
|
||||
cmdline_boot_cpuid = strtoll(optarg, NULL, 0);
|
||||
break;
|
||||
case 'i':
|
||||
srcfile_add_search_path(optarg);
|
||||
break;
|
||||
case 'v':
|
||||
printf("Version: %s\n", DTC_VERSION);
|
||||
exit(0);
|
||||
@ -183,6 +172,18 @@ int main(int argc, char *argv[])
|
||||
optarg);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
sort = 1;
|
||||
break;
|
||||
|
||||
case 'W':
|
||||
parse_checks_option(true, false, optarg);
|
||||
break;
|
||||
|
||||
case 'E':
|
||||
parse_checks_option(false, true, optarg);
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
default:
|
||||
usage();
|
||||
@ -203,8 +204,13 @@ int main(int argc, char *argv[])
|
||||
if (minsize)
|
||||
fprintf(stderr, "DTC: Use of \"-S\" is deprecated; it will be removed soon, use \"-p\" instead\n");
|
||||
|
||||
fprintf(stderr, "DTC: %s->%s on file \"%s\"\n",
|
||||
inform, outform, arg);
|
||||
if (depname) {
|
||||
depfile = fopen(depname, "w");
|
||||
if (!depfile)
|
||||
die("Couldn't open dependency file %s: %s\n", depname,
|
||||
strerror(errno));
|
||||
fprintf(depfile, "%s:", outname);
|
||||
}
|
||||
|
||||
if (streq(inform, "dts"))
|
||||
bi = dt_from_source(arg);
|
||||
@ -215,12 +221,19 @@ int main(int argc, char *argv[])
|
||||
else
|
||||
die("Unknown input format \"%s\"\n", inform);
|
||||
|
||||
if (depfile) {
|
||||
fputc('\n', depfile);
|
||||
fclose(depfile);
|
||||
}
|
||||
|
||||
if (cmdline_boot_cpuid != -1)
|
||||
bi->boot_cpuid_phys = cmdline_boot_cpuid;
|
||||
|
||||
fill_fullpaths(bi->dt, "");
|
||||
process_checks(force, bi);
|
||||
|
||||
if (sort)
|
||||
sort_tree(bi);
|
||||
|
||||
if (streq(outname, "-")) {
|
||||
outf = stdout;
|
||||
|
37
dtc.h
37
dtc.h
@ -25,6 +25,7 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdarg.h>
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
@ -109,6 +110,7 @@ struct data data_insert_at_marker(struct data d, struct marker *m,
|
||||
const void *p, int len);
|
||||
struct data data_merge(struct data d1, struct data d2);
|
||||
struct data data_append_cell(struct data d, cell_t word);
|
||||
struct data data_append_integer(struct data d, uint64_t word, int bits);
|
||||
struct data data_append_re(struct data d, const struct fdt_reserve_entry *re);
|
||||
struct data data_append_addr(struct data d, uint64_t addr);
|
||||
struct data data_append_byte(struct data d, uint8_t byte);
|
||||
@ -125,13 +127,18 @@ int data_is_one_string(struct data d);
|
||||
#define MAX_NODENAME_LEN 31
|
||||
|
||||
/* Live trees */
|
||||
struct label {
|
||||
char *label;
|
||||
struct label *next;
|
||||
};
|
||||
|
||||
struct property {
|
||||
char *name;
|
||||
struct data val;
|
||||
|
||||
struct property *next;
|
||||
|
||||
char *label;
|
||||
struct label *labels;
|
||||
};
|
||||
|
||||
struct node {
|
||||
@ -148,22 +155,28 @@ struct node {
|
||||
cell_t phandle;
|
||||
int addr_cells, size_cells;
|
||||
|
||||
char *label;
|
||||
struct label *labels;
|
||||
};
|
||||
|
||||
#define for_each_label(l0, l) \
|
||||
for ((l) = (l0); (l); (l) = (l)->next)
|
||||
|
||||
#define for_each_property(n, p) \
|
||||
for ((p) = (n)->proplist; (p); (p) = (p)->next)
|
||||
|
||||
#define for_each_child(n, c) \
|
||||
for ((c) = (n)->children; (c); (c) = (c)->next_sibling)
|
||||
|
||||
struct property *build_property(char *name, struct data val, char *label);
|
||||
void add_label(struct label **labels, char *label);
|
||||
|
||||
struct property *build_property(char *name, struct data val);
|
||||
struct property *chain_property(struct property *first, struct property *list);
|
||||
struct property *reverse_properties(struct property *first);
|
||||
|
||||
struct node *build_node(struct property *proplist, struct node *children);
|
||||
struct node *name_node(struct node *node, char *name, char *label);
|
||||
struct node *name_node(struct node *node, char *name);
|
||||
struct node *chain_node(struct node *first, struct node *list);
|
||||
struct node *merge_nodes(struct node *old_node, struct node *new_node);
|
||||
|
||||
void add_property(struct node *node, struct property *prop);
|
||||
void add_child(struct node *parent, struct node *child);
|
||||
@ -171,6 +184,10 @@ void add_child(struct node *parent, struct node *child);
|
||||
const char *get_unitname(struct node *node);
|
||||
struct property *get_property(struct node *node, const char *propname);
|
||||
cell_t propval_cell(struct property *prop);
|
||||
struct property *get_property_by_label(struct node *tree, const char *label,
|
||||
struct node **node);
|
||||
struct marker *get_marker_label(struct node *tree, const char *label,
|
||||
struct node **node, struct property **prop);
|
||||
struct node *get_subnode(struct node *node, const char *nodename);
|
||||
struct node *get_node_by_path(struct node *tree, const char *path);
|
||||
struct node *get_node_by_label(struct node *tree, const char *label);
|
||||
@ -178,6 +195,8 @@ struct node *get_node_by_phandle(struct node *tree, cell_t phandle);
|
||||
struct node *get_node_by_ref(struct node *tree, const char *ref);
|
||||
cell_t get_node_phandle(struct node *root, struct node *node);
|
||||
|
||||
uint32_t guess_boot_cpuid(struct node *tree);
|
||||
|
||||
/* Boot info (tree plus memreserve information */
|
||||
|
||||
struct reserve_info {
|
||||
@ -185,10 +204,10 @@ struct reserve_info {
|
||||
|
||||
struct reserve_info *next;
|
||||
|
||||
char *label;
|
||||
struct label *labels;
|
||||
};
|
||||
|
||||
struct reserve_info *build_reserve_entry(uint64_t start, uint64_t len, char *label);
|
||||
struct reserve_info *build_reserve_entry(uint64_t start, uint64_t len);
|
||||
struct reserve_info *chain_reserve_entry(struct reserve_info *first,
|
||||
struct reserve_info *list);
|
||||
struct reserve_info *add_reserve_entry(struct reserve_info *list,
|
||||
@ -203,9 +222,11 @@ struct boot_info {
|
||||
|
||||
struct boot_info *build_boot_info(struct reserve_info *reservelist,
|
||||
struct node *tree, uint32_t boot_cpuid_phys);
|
||||
void sort_tree(struct boot_info *bi);
|
||||
|
||||
/* Checks */
|
||||
|
||||
void parse_checks_option(bool warn, bool error, const char *optarg);
|
||||
void process_checks(int force, struct boot_info *bi);
|
||||
|
||||
/* Flattened trees */
|
||||
@ -224,8 +245,4 @@ struct boot_info *dt_from_source(const char *f);
|
||||
|
||||
struct boot_info *dt_from_fs(const char *dirname);
|
||||
|
||||
/* misc */
|
||||
|
||||
char *join_path(const char *path, const char *name);
|
||||
|
||||
#endif /* _DTC_H */
|
||||
|
83
flattree.c
83
flattree.c
@ -52,9 +52,9 @@ struct emitter {
|
||||
void (*string)(void *, char *, int);
|
||||
void (*align)(void *, int);
|
||||
void (*data)(void *, struct data);
|
||||
void (*beginnode)(void *, const char *);
|
||||
void (*endnode)(void *, const char *);
|
||||
void (*property)(void *, const char *);
|
||||
void (*beginnode)(void *, struct label *labels);
|
||||
void (*endnode)(void *, struct label *labels);
|
||||
void (*property)(void *, struct label *labels);
|
||||
};
|
||||
|
||||
static void bin_emit_cell(void *e, cell_t val)
|
||||
@ -89,17 +89,17 @@ static void bin_emit_data(void *e, struct data d)
|
||||
*dtbuf = data_append_data(*dtbuf, d.val, d.len);
|
||||
}
|
||||
|
||||
static void bin_emit_beginnode(void *e, const char *label)
|
||||
static void bin_emit_beginnode(void *e, struct label *labels)
|
||||
{
|
||||
bin_emit_cell(e, FDT_BEGIN_NODE);
|
||||
}
|
||||
|
||||
static void bin_emit_endnode(void *e, const char *label)
|
||||
static void bin_emit_endnode(void *e, struct label *labels)
|
||||
{
|
||||
bin_emit_cell(e, FDT_END_NODE);
|
||||
}
|
||||
|
||||
static void bin_emit_property(void *e, const char *label)
|
||||
static void bin_emit_property(void *e, struct label *labels)
|
||||
{
|
||||
bin_emit_cell(e, FDT_PROP);
|
||||
}
|
||||
@ -191,37 +191,40 @@ static void asm_emit_data(void *e, struct data d)
|
||||
assert(off == d.len);
|
||||
}
|
||||
|
||||
static void asm_emit_beginnode(void *e, const char *label)
|
||||
static void asm_emit_beginnode(void *e, struct label *labels)
|
||||
{
|
||||
FILE *f = e;
|
||||
struct label *l;
|
||||
|
||||
if (label) {
|
||||
fprintf(f, "\t.globl\t%s\n", label);
|
||||
fprintf(f, "%s:\n", label);
|
||||
for_each_label(labels, l) {
|
||||
fprintf(f, "\t.globl\t%s\n", l->label);
|
||||
fprintf(f, "%s:\n", l->label);
|
||||
}
|
||||
fprintf(f, "\t/* FDT_BEGIN_NODE */\n");
|
||||
asm_emit_cell(e, FDT_BEGIN_NODE);
|
||||
}
|
||||
|
||||
static void asm_emit_endnode(void *e, const char *label)
|
||||
static void asm_emit_endnode(void *e, struct label *labels)
|
||||
{
|
||||
FILE *f = e;
|
||||
struct label *l;
|
||||
|
||||
fprintf(f, "\t/* FDT_END_NODE */\n");
|
||||
asm_emit_cell(e, FDT_END_NODE);
|
||||
if (label) {
|
||||
fprintf(f, "\t.globl\t%s_end\n", label);
|
||||
fprintf(f, "%s_end:\n", label);
|
||||
for_each_label(labels, l) {
|
||||
fprintf(f, "\t.globl\t%s_end\n", l->label);
|
||||
fprintf(f, "%s_end:\n", l->label);
|
||||
}
|
||||
}
|
||||
|
||||
static void asm_emit_property(void *e, const char *label)
|
||||
static void asm_emit_property(void *e, struct label *labels)
|
||||
{
|
||||
FILE *f = e;
|
||||
struct label *l;
|
||||
|
||||
if (label) {
|
||||
fprintf(f, "\t.globl\t%s\n", label);
|
||||
fprintf(f, "%s:\n", label);
|
||||
for_each_label(labels, l) {
|
||||
fprintf(f, "\t.globl\t%s\n", l->label);
|
||||
fprintf(f, "%s:\n", l->label);
|
||||
}
|
||||
fprintf(f, "\t/* FDT_PROP */\n");
|
||||
asm_emit_cell(e, FDT_PROP);
|
||||
@ -260,7 +263,7 @@ static void flatten_tree(struct node *tree, struct emitter *emit,
|
||||
struct node *child;
|
||||
int seen_name_prop = 0;
|
||||
|
||||
emit->beginnode(etarget, tree->label);
|
||||
emit->beginnode(etarget, tree->labels);
|
||||
|
||||
if (vi->flags & FTF_FULLPATH)
|
||||
emit->string(etarget, tree->fullpath, 0);
|
||||
@ -277,7 +280,7 @@ static void flatten_tree(struct node *tree, struct emitter *emit,
|
||||
|
||||
nameoff = stringtable_insert(strbuf, prop->name);
|
||||
|
||||
emit->property(etarget, prop->label);
|
||||
emit->property(etarget, prop->labels);
|
||||
emit->cell(etarget, prop->val.len);
|
||||
emit->cell(etarget, nameoff);
|
||||
|
||||
@ -304,7 +307,7 @@ static void flatten_tree(struct node *tree, struct emitter *emit,
|
||||
flatten_tree(child, emit, etarget, strbuf, vi);
|
||||
}
|
||||
|
||||
emit->endnode(etarget, tree->label);
|
||||
emit->endnode(etarget, tree->labels);
|
||||
}
|
||||
|
||||
static struct data flatten_reserve_list(struct reserve_info *reservelist,
|
||||
@ -525,9 +528,11 @@ void dt_to_asm(FILE *f, struct boot_info *bi, int version)
|
||||
* as it appears .quad isn't available in some assemblers.
|
||||
*/
|
||||
for (re = bi->reservelist; re; re = re->next) {
|
||||
if (re->label) {
|
||||
fprintf(f, "\t.globl\t%s\n", re->label);
|
||||
fprintf(f, "%s:\n", re->label);
|
||||
struct label *l;
|
||||
|
||||
for_each_label(re->labels, l) {
|
||||
fprintf(f, "\t.globl\t%s\n", l->label);
|
||||
fprintf(f, "%s:\n", l->label);
|
||||
}
|
||||
ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->re.address >> 32));
|
||||
ASM_EMIT_BELONG(f, "0x%08x",
|
||||
@ -684,7 +689,7 @@ static struct property *flat_read_property(struct inbuf *dtbuf,
|
||||
|
||||
val = flat_read_data(dtbuf, proplen);
|
||||
|
||||
return build_property(name, val, NULL);
|
||||
return build_property(name, val);
|
||||
}
|
||||
|
||||
|
||||
@ -692,7 +697,6 @@ static struct reserve_info *flat_read_mem_reserve(struct inbuf *inb)
|
||||
{
|
||||
struct reserve_info *reservelist = NULL;
|
||||
struct reserve_info *new;
|
||||
const char *p;
|
||||
struct fdt_reserve_entry re;
|
||||
|
||||
/*
|
||||
@ -701,7 +705,6 @@ static struct reserve_info *flat_read_mem_reserve(struct inbuf *inb)
|
||||
*
|
||||
* First pass, count entries.
|
||||
*/
|
||||
p = inb->ptr;
|
||||
while (1) {
|
||||
flat_read_chunk(inb, &re, sizeof(re));
|
||||
re.address = fdt64_to_cpu(re.address);
|
||||
@ -709,7 +712,7 @@ static struct reserve_info *flat_read_mem_reserve(struct inbuf *inb)
|
||||
if (re.size == 0)
|
||||
break;
|
||||
|
||||
new = build_reserve_entry(re.address, re.size, NULL);
|
||||
new = build_reserve_entry(re.address, re.size);
|
||||
reservelist = add_reserve_entry(reservelist, new);
|
||||
}
|
||||
|
||||
@ -797,7 +800,7 @@ static struct node *unflatten_tree(struct inbuf *dtbuf,
|
||||
|
||||
struct boot_info *dt_from_blob(const char *fname)
|
||||
{
|
||||
struct dtc_file *dtcf;
|
||||
FILE *f;
|
||||
uint32_t magic, totalsize, version, size_dt, boot_cpuid_phys;
|
||||
uint32_t off_dt, off_str, off_mem_rsvmap;
|
||||
int rc;
|
||||
@ -812,14 +815,14 @@ struct boot_info *dt_from_blob(const char *fname)
|
||||
uint32_t val;
|
||||
int flags = 0;
|
||||
|
||||
dtcf = dtc_open_file(fname, NULL);
|
||||
f = srcfile_relative_open(fname, NULL);
|
||||
|
||||
rc = fread(&magic, sizeof(magic), 1, dtcf->file);
|
||||
if (ferror(dtcf->file))
|
||||
rc = fread(&magic, sizeof(magic), 1, f);
|
||||
if (ferror(f))
|
||||
die("Error reading DT blob magic number: %s\n",
|
||||
strerror(errno));
|
||||
if (rc < 1) {
|
||||
if (feof(dtcf->file))
|
||||
if (feof(f))
|
||||
die("EOF reading DT blob magic number\n");
|
||||
else
|
||||
die("Mysterious short read reading magic number\n");
|
||||
@ -829,11 +832,11 @@ struct boot_info *dt_from_blob(const char *fname)
|
||||
if (magic != FDT_MAGIC)
|
||||
die("Blob has incorrect magic number\n");
|
||||
|
||||
rc = fread(&totalsize, sizeof(totalsize), 1, dtcf->file);
|
||||
if (ferror(dtcf->file))
|
||||
rc = fread(&totalsize, sizeof(totalsize), 1, f);
|
||||
if (ferror(f))
|
||||
die("Error reading DT blob size: %s\n", strerror(errno));
|
||||
if (rc < 1) {
|
||||
if (feof(dtcf->file))
|
||||
if (feof(f))
|
||||
die("EOF reading DT blob size\n");
|
||||
else
|
||||
die("Mysterious short read reading blob size\n");
|
||||
@ -853,12 +856,12 @@ struct boot_info *dt_from_blob(const char *fname)
|
||||
p = blob + sizeof(magic) + sizeof(totalsize);
|
||||
|
||||
while (sizeleft) {
|
||||
if (feof(dtcf->file))
|
||||
if (feof(f))
|
||||
die("EOF before reading %d bytes of DT blob\n",
|
||||
totalsize);
|
||||
|
||||
rc = fread(p, 1, sizeleft, dtcf->file);
|
||||
if (ferror(dtcf->file))
|
||||
rc = fread(p, 1, sizeleft, f);
|
||||
if (ferror(f))
|
||||
die("Error reading DT blob: %s\n",
|
||||
strerror(errno));
|
||||
|
||||
@ -921,7 +924,7 @@ struct boot_info *dt_from_blob(const char *fname)
|
||||
|
||||
free(blob);
|
||||
|
||||
dtc_close_file(dtcf);
|
||||
fclose(f);
|
||||
|
||||
return build_boot_info(reservelist, tree, boot_cpuid_phys);
|
||||
}
|
||||
|
11
fstree.c
11
fstree.c
@ -60,8 +60,7 @@ static struct node *read_fstree(const char *dirname)
|
||||
} else {
|
||||
prop = build_property(xstrdup(de->d_name),
|
||||
data_copy_file(pfile,
|
||||
st.st_size),
|
||||
NULL);
|
||||
st.st_size));
|
||||
add_property(tree, prop);
|
||||
fclose(pfile);
|
||||
}
|
||||
@ -69,14 +68,14 @@ static struct node *read_fstree(const char *dirname)
|
||||
struct node *newchild;
|
||||
|
||||
newchild = read_fstree(tmpnam);
|
||||
newchild = name_node(newchild, xstrdup(de->d_name),
|
||||
NULL);
|
||||
newchild = name_node(newchild, xstrdup(de->d_name));
|
||||
add_child(tree, newchild);
|
||||
}
|
||||
|
||||
free(tmpnam);
|
||||
}
|
||||
|
||||
closedir(d);
|
||||
return tree;
|
||||
}
|
||||
|
||||
@ -85,8 +84,8 @@ struct boot_info *dt_from_fs(const char *dirname)
|
||||
struct node *tree;
|
||||
|
||||
tree = read_fstree(dirname);
|
||||
tree = name_node(tree, "", NULL);
|
||||
tree = name_node(tree, "");
|
||||
|
||||
return build_boot_info(NULL, tree, 0);
|
||||
return build_boot_info(NULL, tree, guess_boot_cpuid(tree));
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,8 @@
|
||||
# This is not a complete Makefile of itself. Instead, it is designed to
|
||||
# be easily embeddable into other systems of Makefiles.
|
||||
#
|
||||
LIBFDT_soname = libfdt.$(SHAREDLIB_EXT).1
|
||||
LIBFDT_INCLUDES = fdt.h libfdt.h
|
||||
LIBFDT_VERSION = version.lds
|
||||
LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c
|
||||
LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c fdt_empty_tree.c
|
||||
LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o)
|
||||
|
@ -149,6 +149,15 @@ int _fdt_check_node_offset(const void *fdt, int offset)
|
||||
return offset;
|
||||
}
|
||||
|
||||
int _fdt_check_prop_offset(const void *fdt, int offset)
|
||||
{
|
||||
if ((offset < 0) || (offset % FDT_TAGSIZE)
|
||||
|| (fdt_next_tag(fdt, offset, &offset) != FDT_PROP))
|
||||
return -FDT_ERR_BADOFFSET;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
int fdt_next_node(const void *fdt, int offset, int *depth)
|
||||
{
|
||||
int nextoffset = 0;
|
||||
|
125
libfdt/fdt_ro.c
125
libfdt/fdt_ro.c
@ -105,6 +105,30 @@ int fdt_num_mem_rsv(const void *fdt)
|
||||
return i;
|
||||
}
|
||||
|
||||
static int _nextprop(const void *fdt, int offset)
|
||||
{
|
||||
uint32_t tag;
|
||||
int nextoffset;
|
||||
|
||||
do {
|
||||
tag = fdt_next_tag(fdt, offset, &nextoffset);
|
||||
|
||||
switch (tag) {
|
||||
case FDT_END:
|
||||
if (nextoffset >= 0)
|
||||
return -FDT_ERR_BADSTRUCTURE;
|
||||
else
|
||||
return nextoffset;
|
||||
|
||||
case FDT_PROP:
|
||||
return offset;
|
||||
}
|
||||
offset = nextoffset;
|
||||
} while (tag == FDT_NOP);
|
||||
|
||||
return -FDT_ERR_NOTFOUND;
|
||||
}
|
||||
|
||||
int fdt_subnode_offset_namelen(const void *fdt, int offset,
|
||||
const char *name, int namelen)
|
||||
{
|
||||
@ -194,52 +218,66 @@ const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int fdt_first_property_offset(const void *fdt, int nodeoffset)
|
||||
{
|
||||
int offset;
|
||||
|
||||
if ((offset = _fdt_check_node_offset(fdt, nodeoffset)) < 0)
|
||||
return offset;
|
||||
|
||||
return _nextprop(fdt, offset);
|
||||
}
|
||||
|
||||
int fdt_next_property_offset(const void *fdt, int offset)
|
||||
{
|
||||
if ((offset = _fdt_check_prop_offset(fdt, offset)) < 0)
|
||||
return offset;
|
||||
|
||||
return _nextprop(fdt, offset);
|
||||
}
|
||||
|
||||
const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
|
||||
int offset,
|
||||
int *lenp)
|
||||
{
|
||||
int err;
|
||||
const struct fdt_property *prop;
|
||||
|
||||
if ((err = _fdt_check_prop_offset(fdt, offset)) < 0) {
|
||||
if (lenp)
|
||||
*lenp = err;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
prop = _fdt_offset_ptr(fdt, offset);
|
||||
|
||||
if (lenp)
|
||||
*lenp = fdt32_to_cpu(prop->len);
|
||||
|
||||
return prop;
|
||||
}
|
||||
|
||||
const struct fdt_property *fdt_get_property_namelen(const void *fdt,
|
||||
int nodeoffset,
|
||||
int offset,
|
||||
const char *name,
|
||||
int namelen, int *lenp)
|
||||
{
|
||||
uint32_t tag;
|
||||
const struct fdt_property *prop;
|
||||
int offset, nextoffset;
|
||||
int err;
|
||||
for (offset = fdt_first_property_offset(fdt, offset);
|
||||
(offset >= 0);
|
||||
(offset = fdt_next_property_offset(fdt, offset))) {
|
||||
const struct fdt_property *prop;
|
||||
|
||||
if (((err = fdt_check_header(fdt)) != 0)
|
||||
|| ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0))
|
||||
goto fail;
|
||||
|
||||
nextoffset = err;
|
||||
do {
|
||||
offset = nextoffset;
|
||||
|
||||
tag = fdt_next_tag(fdt, offset, &nextoffset);
|
||||
switch (tag) {
|
||||
case FDT_END:
|
||||
if (nextoffset < 0)
|
||||
err = nextoffset;
|
||||
else
|
||||
/* FDT_END tag with unclosed nodes */
|
||||
err = -FDT_ERR_BADSTRUCTURE;
|
||||
goto fail;
|
||||
|
||||
case FDT_PROP:
|
||||
prop = _fdt_offset_ptr(fdt, offset);
|
||||
if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff),
|
||||
name, namelen)) {
|
||||
/* Found it! */
|
||||
if (lenp)
|
||||
*lenp = fdt32_to_cpu(prop->len);
|
||||
|
||||
return prop;
|
||||
}
|
||||
if (!(prop = fdt_get_property_by_offset(fdt, offset, lenp))) {
|
||||
offset = -FDT_ERR_INTERNAL;
|
||||
break;
|
||||
}
|
||||
} while ((tag != FDT_BEGIN_NODE) && (tag != FDT_END_NODE));
|
||||
if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff),
|
||||
name, namelen))
|
||||
return prop;
|
||||
}
|
||||
|
||||
err = -FDT_ERR_NOTFOUND;
|
||||
fail:
|
||||
if (lenp)
|
||||
*lenp = err;
|
||||
*lenp = offset;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -263,6 +301,19 @@ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
|
||||
return prop->data;
|
||||
}
|
||||
|
||||
const void *fdt_getprop_by_offset(const void *fdt, int offset,
|
||||
const char **namep, int *lenp)
|
||||
{
|
||||
const struct fdt_property *prop;
|
||||
|
||||
prop = fdt_get_property_by_offset(fdt, offset, lenp);
|
||||
if (!prop)
|
||||
return NULL;
|
||||
if (namep)
|
||||
*namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
|
||||
return prop->data;
|
||||
}
|
||||
|
||||
const void *fdt_getprop(const void *fdt, int nodeoffset,
|
||||
const char *name, int *lenp)
|
||||
{
|
||||
|
@ -289,6 +289,33 @@ int fdt_setprop(void *fdt, int nodeoffset, const char *name,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_appendprop(void *fdt, int nodeoffset, const char *name,
|
||||
const void *val, int len)
|
||||
{
|
||||
struct fdt_property *prop;
|
||||
int err, oldlen, newlen;
|
||||
|
||||
FDT_RW_CHECK_HEADER(fdt);
|
||||
|
||||
prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
|
||||
if (prop) {
|
||||
newlen = len + oldlen;
|
||||
err = _fdt_splice_struct(fdt, prop->data,
|
||||
FDT_TAGALIGN(oldlen),
|
||||
FDT_TAGALIGN(newlen));
|
||||
if (err)
|
||||
return err;
|
||||
prop->len = cpu_to_fdt32(newlen);
|
||||
memcpy(prop->data + oldlen, val, len);
|
||||
} else {
|
||||
err = _fdt_add_property(fdt, nodeoffset, name, len, &prop);
|
||||
if (err)
|
||||
return err;
|
||||
memcpy(prop->data, val, len);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_delprop(void *fdt, int nodeoffset, const char *name)
|
||||
{
|
||||
struct fdt_property *prop;
|
||||
|
378
libfdt/libfdt.h
378
libfdt/libfdt.h
@ -342,6 +342,75 @@ int fdt_path_offset(const void *fdt, const char *path);
|
||||
*/
|
||||
const char *fdt_get_name(const void *fdt, int nodeoffset, int *lenp);
|
||||
|
||||
/**
|
||||
* fdt_first_property_offset - find the offset of a node's first property
|
||||
* @fdt: pointer to the device tree blob
|
||||
* @nodeoffset: structure block offset of a node
|
||||
*
|
||||
* fdt_first_property_offset() finds the first property of the node at
|
||||
* the given structure block offset.
|
||||
*
|
||||
* returns:
|
||||
* structure block offset of the property (>=0), on success
|
||||
* -FDT_ERR_NOTFOUND, if the requested node has no properties
|
||||
* -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_BEGIN_NODE tag
|
||||
* -FDT_ERR_BADMAGIC,
|
||||
* -FDT_ERR_BADVERSION,
|
||||
* -FDT_ERR_BADSTATE,
|
||||
* -FDT_ERR_BADSTRUCTURE,
|
||||
* -FDT_ERR_TRUNCATED, standard meanings.
|
||||
*/
|
||||
int fdt_first_property_offset(const void *fdt, int nodeoffset);
|
||||
|
||||
/**
|
||||
* fdt_next_property_offset - step through a node's properties
|
||||
* @fdt: pointer to the device tree blob
|
||||
* @offset: structure block offset of a property
|
||||
*
|
||||
* fdt_next_property_offset() finds the property immediately after the
|
||||
* one at the given structure block offset. This will be a property
|
||||
* of the same node as the given property.
|
||||
*
|
||||
* returns:
|
||||
* structure block offset of the next property (>=0), on success
|
||||
* -FDT_ERR_NOTFOUND, if the given property is the last in its node
|
||||
* -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_PROP tag
|
||||
* -FDT_ERR_BADMAGIC,
|
||||
* -FDT_ERR_BADVERSION,
|
||||
* -FDT_ERR_BADSTATE,
|
||||
* -FDT_ERR_BADSTRUCTURE,
|
||||
* -FDT_ERR_TRUNCATED, standard meanings.
|
||||
*/
|
||||
int fdt_next_property_offset(const void *fdt, int offset);
|
||||
|
||||
/**
|
||||
* fdt_get_property_by_offset - retrieve the property at a given offset
|
||||
* @fdt: pointer to the device tree blob
|
||||
* @offset: offset of the property to retrieve
|
||||
* @lenp: pointer to an integer variable (will be overwritten) or NULL
|
||||
*
|
||||
* fdt_get_property_by_offset() retrieves a pointer to the
|
||||
* fdt_property structure within the device tree blob at the given
|
||||
* offset. If lenp is non-NULL, the length of the property value is
|
||||
* also returned, in the integer pointed to by lenp.
|
||||
*
|
||||
* returns:
|
||||
* pointer to the structure representing the property
|
||||
* if lenp is non-NULL, *lenp contains the length of the property
|
||||
* value (>=0)
|
||||
* NULL, on error
|
||||
* if lenp is non-NULL, *lenp contains an error code (<0):
|
||||
* -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag
|
||||
* -FDT_ERR_BADMAGIC,
|
||||
* -FDT_ERR_BADVERSION,
|
||||
* -FDT_ERR_BADSTATE,
|
||||
* -FDT_ERR_BADSTRUCTURE,
|
||||
* -FDT_ERR_TRUNCATED, standard meanings
|
||||
*/
|
||||
const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
|
||||
int offset,
|
||||
int *lenp);
|
||||
|
||||
/**
|
||||
* fdt_get_property_namelen - find a property based on substring
|
||||
* @fdt: pointer to the device tree blob
|
||||
@ -395,6 +464,40 @@ static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset,
|
||||
fdt_get_property(fdt, nodeoffset, name, lenp);
|
||||
}
|
||||
|
||||
/**
|
||||
* fdt_getprop_by_offset - retrieve the value of a property at a given offset
|
||||
* @fdt: pointer to the device tree blob
|
||||
* @ffset: offset of the property to read
|
||||
* @namep: pointer to a string variable (will be overwritten) or NULL
|
||||
* @lenp: pointer to an integer variable (will be overwritten) or NULL
|
||||
*
|
||||
* fdt_getprop_by_offset() retrieves a pointer to the value of the
|
||||
* property at structure block offset 'offset' (this will be a pointer
|
||||
* to within the device blob itself, not a copy of the value). If
|
||||
* lenp is non-NULL, the length of the property value is also
|
||||
* returned, in the integer pointed to by lenp. If namep is non-NULL,
|
||||
* the property's namne will also be returned in the char * pointed to
|
||||
* by namep (this will be a pointer to within the device tree's string
|
||||
* block, not a new copy of the name).
|
||||
*
|
||||
* returns:
|
||||
* pointer to the property's value
|
||||
* if lenp is non-NULL, *lenp contains the length of the property
|
||||
* value (>=0)
|
||||
* if namep is non-NULL *namep contiains a pointer to the property
|
||||
* name.
|
||||
* NULL, on error
|
||||
* if lenp is non-NULL, *lenp contains an error code (<0):
|
||||
* -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag
|
||||
* -FDT_ERR_BADMAGIC,
|
||||
* -FDT_ERR_BADVERSION,
|
||||
* -FDT_ERR_BADSTATE,
|
||||
* -FDT_ERR_BADSTRUCTURE,
|
||||
* -FDT_ERR_TRUNCATED, standard meanings
|
||||
*/
|
||||
const void *fdt_getprop_by_offset(const void *fdt, int offset,
|
||||
const char **namep, int *lenp);
|
||||
|
||||
/**
|
||||
* fdt_getprop_namelen - get property value based on substring
|
||||
* @fdt: pointer to the device tree blob
|
||||
@ -749,17 +852,17 @@ int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
|
||||
const void *val, int len);
|
||||
|
||||
/**
|
||||
* fdt_setprop_inplace_cell - change the value of a single-cell property
|
||||
* fdt_setprop_inplace_u32 - change the value of a 32-bit integer property
|
||||
* @fdt: pointer to the device tree blob
|
||||
* @nodeoffset: offset of the node whose property to change
|
||||
* @name: name of the property to change
|
||||
* @val: cell (32-bit integer) value to replace the property with
|
||||
* @val: 32-bit integer value to replace the property with
|
||||
*
|
||||
* fdt_setprop_inplace_cell() replaces the value of a given property
|
||||
* with the 32-bit integer cell value in val, converting val to
|
||||
* big-endian if necessary. This function cannot change the size of a
|
||||
* property, and so will only work if the property already exists and
|
||||
* has length 4.
|
||||
* fdt_setprop_inplace_u32() replaces the value of a given property
|
||||
* with the 32-bit integer value in val, converting val to big-endian
|
||||
* if necessary. This function cannot change the size of a property,
|
||||
* and so will only work if the property already exists and has length
|
||||
* 4.
|
||||
*
|
||||
* This function will alter only the bytes in the blob which contain
|
||||
* the given property value, and will not alter or move any other part
|
||||
@ -768,7 +871,7 @@ int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
|
||||
* returns:
|
||||
* 0, on success
|
||||
* -FDT_ERR_NOSPACE, if the property's length is not equal to 4
|
||||
* -FDT_ERR_NOTFOUND, node does not have the named property
|
||||
* -FDT_ERR_NOTFOUND, node does not have the named property
|
||||
* -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
|
||||
* -FDT_ERR_BADMAGIC,
|
||||
* -FDT_ERR_BADVERSION,
|
||||
@ -776,13 +879,59 @@ int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
|
||||
* -FDT_ERR_BADSTRUCTURE,
|
||||
* -FDT_ERR_TRUNCATED, standard meanings
|
||||
*/
|
||||
static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset,
|
||||
const char *name, uint32_t val)
|
||||
static inline int fdt_setprop_inplace_u32(void *fdt, int nodeoffset,
|
||||
const char *name, uint32_t val)
|
||||
{
|
||||
val = cpu_to_fdt32(val);
|
||||
return fdt_setprop_inplace(fdt, nodeoffset, name, &val, sizeof(val));
|
||||
}
|
||||
|
||||
/**
|
||||
* fdt_setprop_inplace_u64 - change the value of a 64-bit integer property
|
||||
* @fdt: pointer to the device tree blob
|
||||
* @nodeoffset: offset of the node whose property to change
|
||||
* @name: name of the property to change
|
||||
* @val: 64-bit integer value to replace the property with
|
||||
*
|
||||
* fdt_setprop_inplace_u64() replaces the value of a given property
|
||||
* with the 64-bit integer value in val, converting val to big-endian
|
||||
* if necessary. This function cannot change the size of a property,
|
||||
* and so will only work if the property already exists and has length
|
||||
* 8.
|
||||
*
|
||||
* This function will alter only the bytes in the blob which contain
|
||||
* the given property value, and will not alter or move any other part
|
||||
* of the tree.
|
||||
*
|
||||
* returns:
|
||||
* 0, on success
|
||||
* -FDT_ERR_NOSPACE, if the property's length is not equal to 8
|
||||
* -FDT_ERR_NOTFOUND, node does not have the named property
|
||||
* -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
|
||||
* -FDT_ERR_BADMAGIC,
|
||||
* -FDT_ERR_BADVERSION,
|
||||
* -FDT_ERR_BADSTATE,
|
||||
* -FDT_ERR_BADSTRUCTURE,
|
||||
* -FDT_ERR_TRUNCATED, standard meanings
|
||||
*/
|
||||
static inline int fdt_setprop_inplace_u64(void *fdt, int nodeoffset,
|
||||
const char *name, uint64_t val)
|
||||
{
|
||||
val = cpu_to_fdt64(val);
|
||||
return fdt_setprop_inplace(fdt, nodeoffset, name, &val, sizeof(val));
|
||||
}
|
||||
|
||||
/**
|
||||
* fdt_setprop_inplace_cell - change the value of a single-cell property
|
||||
*
|
||||
* This is an alternative name for fdt_setprop_inplace_u32()
|
||||
*/
|
||||
static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset,
|
||||
const char *name, uint32_t val)
|
||||
{
|
||||
return fdt_setprop_inplace_u32(fdt, nodeoffset, name, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* fdt_nop_property - replace a property with nop tags
|
||||
* @fdt: pointer to the device tree blob
|
||||
@ -842,11 +991,20 @@ int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size);
|
||||
int fdt_finish_reservemap(void *fdt);
|
||||
int fdt_begin_node(void *fdt, const char *name);
|
||||
int fdt_property(void *fdt, const char *name, const void *val, int len);
|
||||
static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val)
|
||||
static inline int fdt_property_u32(void *fdt, const char *name, uint32_t val)
|
||||
{
|
||||
val = cpu_to_fdt32(val);
|
||||
return fdt_property(fdt, name, &val, sizeof(val));
|
||||
}
|
||||
static inline int fdt_property_u64(void *fdt, const char *name, uint64_t val)
|
||||
{
|
||||
val = cpu_to_fdt64(val);
|
||||
return fdt_property(fdt, name, &val, sizeof(val));
|
||||
}
|
||||
static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val)
|
||||
{
|
||||
return fdt_property_u32(fdt, name, val);
|
||||
}
|
||||
#define fdt_property_string(fdt, name, str) \
|
||||
fdt_property(fdt, name, str, strlen(str)+1)
|
||||
int fdt_end_node(void *fdt);
|
||||
@ -856,6 +1014,7 @@ int fdt_finish(void *fdt);
|
||||
/* Read-write functions */
|
||||
/**********************************************************************/
|
||||
|
||||
int fdt_create_empty_tree(void *buf, int bufsize);
|
||||
int fdt_open_into(const void *fdt, void *buf, int bufsize);
|
||||
int fdt_pack(void *fdt);
|
||||
|
||||
@ -965,14 +1124,14 @@ int fdt_setprop(void *fdt, int nodeoffset, const char *name,
|
||||
const void *val, int len);
|
||||
|
||||
/**
|
||||
* fdt_setprop_cell - set a property to a single cell value
|
||||
* fdt_setprop_u32 - set a property to a 32-bit integer
|
||||
* @fdt: pointer to the device tree blob
|
||||
* @nodeoffset: offset of the node whose property to change
|
||||
* @name: name of the property to change
|
||||
* @val: 32-bit integer value for the property (native endian)
|
||||
*
|
||||
* fdt_setprop_cell() sets the value of the named property in the
|
||||
* given node to the given cell value (converting to big-endian if
|
||||
* fdt_setprop_u32() sets the value of the named property in the given
|
||||
* node to the given 32-bit integer value (converting to big-endian if
|
||||
* necessary), or creates a new property with that value if it does
|
||||
* not already exist.
|
||||
*
|
||||
@ -992,13 +1151,59 @@ int fdt_setprop(void *fdt, int nodeoffset, const char *name,
|
||||
* -FDT_ERR_BADLAYOUT,
|
||||
* -FDT_ERR_TRUNCATED, standard meanings
|
||||
*/
|
||||
static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name,
|
||||
uint32_t val)
|
||||
static inline int fdt_setprop_u32(void *fdt, int nodeoffset, const char *name,
|
||||
uint32_t val)
|
||||
{
|
||||
val = cpu_to_fdt32(val);
|
||||
return fdt_setprop(fdt, nodeoffset, name, &val, sizeof(val));
|
||||
}
|
||||
|
||||
/**
|
||||
* fdt_setprop_u64 - set a property to a 64-bit integer
|
||||
* @fdt: pointer to the device tree blob
|
||||
* @nodeoffset: offset of the node whose property to change
|
||||
* @name: name of the property to change
|
||||
* @val: 64-bit integer value for the property (native endian)
|
||||
*
|
||||
* fdt_setprop_u64() sets the value of the named property in the given
|
||||
* node to the given 64-bit integer value (converting to big-endian if
|
||||
* necessary), or creates a new property with that value if it does
|
||||
* not already exist.
|
||||
*
|
||||
* This function may insert or delete data from the blob, and will
|
||||
* therefore change the offsets of some existing nodes.
|
||||
*
|
||||
* returns:
|
||||
* 0, on success
|
||||
* -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
|
||||
* contain the new property value
|
||||
* -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
|
||||
* -FDT_ERR_BADLAYOUT,
|
||||
* -FDT_ERR_BADMAGIC,
|
||||
* -FDT_ERR_BADVERSION,
|
||||
* -FDT_ERR_BADSTATE,
|
||||
* -FDT_ERR_BADSTRUCTURE,
|
||||
* -FDT_ERR_BADLAYOUT,
|
||||
* -FDT_ERR_TRUNCATED, standard meanings
|
||||
*/
|
||||
static inline int fdt_setprop_u64(void *fdt, int nodeoffset, const char *name,
|
||||
uint64_t val)
|
||||
{
|
||||
val = cpu_to_fdt64(val);
|
||||
return fdt_setprop(fdt, nodeoffset, name, &val, sizeof(val));
|
||||
}
|
||||
|
||||
/**
|
||||
* fdt_setprop_cell - set a property to a single cell value
|
||||
*
|
||||
* This is an alternative name for fdt_setprop_u32()
|
||||
*/
|
||||
static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name,
|
||||
uint32_t val)
|
||||
{
|
||||
return fdt_setprop_u32(fdt, nodeoffset, name, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* fdt_setprop_string - set a property to a string value
|
||||
* @fdt: pointer to the device tree blob
|
||||
@ -1030,6 +1235,147 @@ static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name,
|
||||
#define fdt_setprop_string(fdt, nodeoffset, name, str) \
|
||||
fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1)
|
||||
|
||||
/**
|
||||
* fdt_appendprop - append to or create a property
|
||||
* @fdt: pointer to the device tree blob
|
||||
* @nodeoffset: offset of the node whose property to change
|
||||
* @name: name of the property to append to
|
||||
* @val: pointer to data to append to the property value
|
||||
* @len: length of the data to append to the property value
|
||||
*
|
||||
* fdt_appendprop() appends the value to the named property in the
|
||||
* given node, creating the property if it does not already exist.
|
||||
*
|
||||
* This function may insert data into the blob, and will therefore
|
||||
* change the offsets of some existing nodes.
|
||||
*
|
||||
* returns:
|
||||
* 0, on success
|
||||
* -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
|
||||
* contain the new property value
|
||||
* -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
|
||||
* -FDT_ERR_BADLAYOUT,
|
||||
* -FDT_ERR_BADMAGIC,
|
||||
* -FDT_ERR_BADVERSION,
|
||||
* -FDT_ERR_BADSTATE,
|
||||
* -FDT_ERR_BADSTRUCTURE,
|
||||
* -FDT_ERR_BADLAYOUT,
|
||||
* -FDT_ERR_TRUNCATED, standard meanings
|
||||
*/
|
||||
int fdt_appendprop(void *fdt, int nodeoffset, const char *name,
|
||||
const void *val, int len);
|
||||
|
||||
/**
|
||||
* fdt_appendprop_u32 - append a 32-bit integer value to a property
|
||||
* @fdt: pointer to the device tree blob
|
||||
* @nodeoffset: offset of the node whose property to change
|
||||
* @name: name of the property to change
|
||||
* @val: 32-bit integer value to append to the property (native endian)
|
||||
*
|
||||
* fdt_appendprop_u32() appends the given 32-bit integer value
|
||||
* (converting to big-endian if necessary) to the value of the named
|
||||
* property in the given node, or creates a new property with that
|
||||
* value if it does not already exist.
|
||||
*
|
||||
* This function may insert data into the blob, and will therefore
|
||||
* change the offsets of some existing nodes.
|
||||
*
|
||||
* returns:
|
||||
* 0, on success
|
||||
* -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
|
||||
* contain the new property value
|
||||
* -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
|
||||
* -FDT_ERR_BADLAYOUT,
|
||||
* -FDT_ERR_BADMAGIC,
|
||||
* -FDT_ERR_BADVERSION,
|
||||
* -FDT_ERR_BADSTATE,
|
||||
* -FDT_ERR_BADSTRUCTURE,
|
||||
* -FDT_ERR_BADLAYOUT,
|
||||
* -FDT_ERR_TRUNCATED, standard meanings
|
||||
*/
|
||||
static inline int fdt_appendprop_u32(void *fdt, int nodeoffset,
|
||||
const char *name, uint32_t val)
|
||||
{
|
||||
val = cpu_to_fdt32(val);
|
||||
return fdt_appendprop(fdt, nodeoffset, name, &val, sizeof(val));
|
||||
}
|
||||
|
||||
/**
|
||||
* fdt_appendprop_u64 - append a 64-bit integer value to a property
|
||||
* @fdt: pointer to the device tree blob
|
||||
* @nodeoffset: offset of the node whose property to change
|
||||
* @name: name of the property to change
|
||||
* @val: 64-bit integer value to append to the property (native endian)
|
||||
*
|
||||
* fdt_appendprop_u64() appends the given 64-bit integer value
|
||||
* (converting to big-endian if necessary) to the value of the named
|
||||
* property in the given node, or creates a new property with that
|
||||
* value if it does not already exist.
|
||||
*
|
||||
* This function may insert data into the blob, and will therefore
|
||||
* change the offsets of some existing nodes.
|
||||
*
|
||||
* returns:
|
||||
* 0, on success
|
||||
* -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
|
||||
* contain the new property value
|
||||
* -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
|
||||
* -FDT_ERR_BADLAYOUT,
|
||||
* -FDT_ERR_BADMAGIC,
|
||||
* -FDT_ERR_BADVERSION,
|
||||
* -FDT_ERR_BADSTATE,
|
||||
* -FDT_ERR_BADSTRUCTURE,
|
||||
* -FDT_ERR_BADLAYOUT,
|
||||
* -FDT_ERR_TRUNCATED, standard meanings
|
||||
*/
|
||||
static inline int fdt_appendprop_u64(void *fdt, int nodeoffset,
|
||||
const char *name, uint64_t val)
|
||||
{
|
||||
val = cpu_to_fdt64(val);
|
||||
return fdt_appendprop(fdt, nodeoffset, name, &val, sizeof(val));
|
||||
}
|
||||
|
||||
/**
|
||||
* fdt_appendprop_cell - append a single cell value to a property
|
||||
*
|
||||
* This is an alternative name for fdt_appendprop_u32()
|
||||
*/
|
||||
static inline int fdt_appendprop_cell(void *fdt, int nodeoffset,
|
||||
const char *name, uint32_t val)
|
||||
{
|
||||
return fdt_appendprop_u32(fdt, nodeoffset, name, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* fdt_appendprop_string - append a string to a property
|
||||
* @fdt: pointer to the device tree blob
|
||||
* @nodeoffset: offset of the node whose property to change
|
||||
* @name: name of the property to change
|
||||
* @str: string value to append to the property
|
||||
*
|
||||
* fdt_appendprop_string() appends the given string to the value of
|
||||
* the named property in the given node, or creates a new property
|
||||
* with that value if it does not already exist.
|
||||
*
|
||||
* This function may insert data into the blob, and will therefore
|
||||
* change the offsets of some existing nodes.
|
||||
*
|
||||
* returns:
|
||||
* 0, on success
|
||||
* -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
|
||||
* contain the new property value
|
||||
* -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
|
||||
* -FDT_ERR_BADLAYOUT,
|
||||
* -FDT_ERR_BADMAGIC,
|
||||
* -FDT_ERR_BADVERSION,
|
||||
* -FDT_ERR_BADSTATE,
|
||||
* -FDT_ERR_BADSTRUCTURE,
|
||||
* -FDT_ERR_BADLAYOUT,
|
||||
* -FDT_ERR_TRUNCATED, standard meanings
|
||||
*/
|
||||
#define fdt_appendprop_string(fdt, nodeoffset, name, str) \
|
||||
fdt_appendprop((fdt), (nodeoffset), (name), (str), strlen(str)+1)
|
||||
|
||||
/**
|
||||
* fdt_delprop - delete a property
|
||||
* @fdt: pointer to the device tree blob
|
||||
|
@ -5,19 +5,25 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#define _B(n) ((unsigned long long)((uint8_t *)&x)[n])
|
||||
#define EXTRACT_BYTE(n) ((unsigned long long)((uint8_t *)&x)[n])
|
||||
static inline uint16_t fdt16_to_cpu(uint16_t x)
|
||||
{
|
||||
return (EXTRACT_BYTE(0) << 8) | EXTRACT_BYTE(1);
|
||||
}
|
||||
#define cpu_to_fdt16(x) fdt16_to_cpu(x)
|
||||
|
||||
static inline uint32_t fdt32_to_cpu(uint32_t x)
|
||||
{
|
||||
return (_B(0) << 24) | (_B(1) << 16) | (_B(2) << 8) | _B(3);
|
||||
return (EXTRACT_BYTE(0) << 24) | (EXTRACT_BYTE(1) << 16) | (EXTRACT_BYTE(2) << 8) | EXTRACT_BYTE(3);
|
||||
}
|
||||
#define cpu_to_fdt32(x) fdt32_to_cpu(x)
|
||||
|
||||
static inline uint64_t fdt64_to_cpu(uint64_t x)
|
||||
{
|
||||
return (_B(0) << 56) | (_B(1) << 48) | (_B(2) << 40) | (_B(3) << 32)
|
||||
| (_B(4) << 24) | (_B(5) << 16) | (_B(6) << 8) | _B(7);
|
||||
return (EXTRACT_BYTE(0) << 56) | (EXTRACT_BYTE(1) << 48) | (EXTRACT_BYTE(2) << 40) | (EXTRACT_BYTE(3) << 32)
|
||||
| (EXTRACT_BYTE(4) << 24) | (EXTRACT_BYTE(5) << 16) | (EXTRACT_BYTE(6) << 8) | EXTRACT_BYTE(7);
|
||||
}
|
||||
#define cpu_to_fdt64(x) fdt64_to_cpu(x)
|
||||
#undef _B
|
||||
#undef EXTRACT_BYTE
|
||||
|
||||
#endif /* _LIBFDT_ENV_H */
|
||||
|
@ -63,6 +63,7 @@
|
||||
}
|
||||
|
||||
int _fdt_check_node_offset(const void *fdt, int offset);
|
||||
int _fdt_check_prop_offset(const void *fdt, int offset);
|
||||
const char *_fdt_find_string(const char *strtab, int tabsize, const char *s);
|
||||
int _fdt_node_end_offset(void *fdt, int nodeoffset);
|
||||
|
||||
|
329
livetree.c
329
livetree.c
@ -24,17 +24,30 @@
|
||||
* Tree building functions
|
||||
*/
|
||||
|
||||
struct property *build_property(char *name, struct data val, char *label)
|
||||
void add_label(struct label **labels, char *label)
|
||||
{
|
||||
struct label *new;
|
||||
|
||||
/* Make sure the label isn't already there */
|
||||
for_each_label(*labels, new)
|
||||
if (streq(new->label, label))
|
||||
return;
|
||||
|
||||
new = xmalloc(sizeof(*new));
|
||||
new->label = label;
|
||||
new->next = *labels;
|
||||
*labels = new;
|
||||
}
|
||||
|
||||
struct property *build_property(char *name, struct data val)
|
||||
{
|
||||
struct property *new = xmalloc(sizeof(*new));
|
||||
|
||||
memset(new, 0, sizeof(*new));
|
||||
|
||||
new->name = name;
|
||||
new->val = val;
|
||||
|
||||
new->next = NULL;
|
||||
|
||||
new->label = label;
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
@ -78,17 +91,82 @@ struct node *build_node(struct property *proplist, struct node *children)
|
||||
return new;
|
||||
}
|
||||
|
||||
struct node *name_node(struct node *node, char *name, char * label)
|
||||
struct node *name_node(struct node *node, char *name)
|
||||
{
|
||||
assert(node->name == NULL);
|
||||
|
||||
node->name = name;
|
||||
|
||||
node->label = label;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
struct node *merge_nodes(struct node *old_node, struct node *new_node)
|
||||
{
|
||||
struct property *new_prop, *old_prop;
|
||||
struct node *new_child, *old_child;
|
||||
struct label *l;
|
||||
|
||||
/* Add new node labels to old node */
|
||||
for_each_label(new_node->labels, l)
|
||||
add_label(&old_node->labels, l->label);
|
||||
|
||||
/* Move properties from the new node to the old node. If there
|
||||
* is a collision, replace the old value with the new */
|
||||
while (new_node->proplist) {
|
||||
/* Pop the property off the list */
|
||||
new_prop = new_node->proplist;
|
||||
new_node->proplist = new_prop->next;
|
||||
new_prop->next = NULL;
|
||||
|
||||
/* Look for a collision, set new value if there is */
|
||||
for_each_property(old_node, old_prop) {
|
||||
if (streq(old_prop->name, new_prop->name)) {
|
||||
/* Add new labels to old property */
|
||||
for_each_label(new_prop->labels, l)
|
||||
add_label(&old_prop->labels, l->label);
|
||||
|
||||
old_prop->val = new_prop->val;
|
||||
free(new_prop);
|
||||
new_prop = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* if no collision occurred, add property to the old node. */
|
||||
if (new_prop)
|
||||
add_property(old_node, new_prop);
|
||||
}
|
||||
|
||||
/* Move the override child nodes into the primary node. If
|
||||
* there is a collision, then merge the nodes. */
|
||||
while (new_node->children) {
|
||||
/* Pop the child node off the list */
|
||||
new_child = new_node->children;
|
||||
new_node->children = new_child->next_sibling;
|
||||
new_child->parent = NULL;
|
||||
new_child->next_sibling = NULL;
|
||||
|
||||
/* Search for a collision. Merge if there is */
|
||||
for_each_child(old_node, old_child) {
|
||||
if (streq(old_child->name, new_child->name)) {
|
||||
merge_nodes(old_child, new_child);
|
||||
new_child = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* if no collision occured, add child to the old node. */
|
||||
if (new_child)
|
||||
add_child(old_node, new_child);
|
||||
}
|
||||
|
||||
/* The new node contents are now merged into the old node. Free
|
||||
* the new node. */
|
||||
free(new_node);
|
||||
|
||||
return old_node;
|
||||
}
|
||||
|
||||
struct node *chain_node(struct node *first, struct node *list)
|
||||
{
|
||||
assert(first->next_sibling == NULL);
|
||||
@ -124,18 +202,15 @@ void add_child(struct node *parent, struct node *child)
|
||||
*p = child;
|
||||
}
|
||||
|
||||
struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size,
|
||||
char *label)
|
||||
struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size)
|
||||
{
|
||||
struct reserve_info *new = xmalloc(sizeof(*new));
|
||||
|
||||
memset(new, 0, sizeof(*new));
|
||||
|
||||
new->re.address = address;
|
||||
new->re.size = size;
|
||||
|
||||
new->next = NULL;
|
||||
|
||||
new->label = label;
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
@ -208,6 +283,60 @@ cell_t propval_cell(struct property *prop)
|
||||
return fdt32_to_cpu(*((cell_t *)prop->val.val));
|
||||
}
|
||||
|
||||
struct property *get_property_by_label(struct node *tree, const char *label,
|
||||
struct node **node)
|
||||
{
|
||||
struct property *prop;
|
||||
struct node *c;
|
||||
|
||||
*node = tree;
|
||||
|
||||
for_each_property(tree, prop) {
|
||||
struct label *l;
|
||||
|
||||
for_each_label(prop->labels, l)
|
||||
if (streq(l->label, label))
|
||||
return prop;
|
||||
}
|
||||
|
||||
for_each_child(tree, c) {
|
||||
prop = get_property_by_label(c, label, node);
|
||||
if (prop)
|
||||
return prop;
|
||||
}
|
||||
|
||||
*node = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct marker *get_marker_label(struct node *tree, const char *label,
|
||||
struct node **node, struct property **prop)
|
||||
{
|
||||
struct marker *m;
|
||||
struct property *p;
|
||||
struct node *c;
|
||||
|
||||
*node = tree;
|
||||
|
||||
for_each_property(tree, p) {
|
||||
*prop = p;
|
||||
m = p->val.markers;
|
||||
for_each_marker_of_type(m, LABEL)
|
||||
if (streq(m->ref, label))
|
||||
return m;
|
||||
}
|
||||
|
||||
for_each_child(tree, c) {
|
||||
m = get_marker_label(c, label, node, prop);
|
||||
if (m)
|
||||
return m;
|
||||
}
|
||||
|
||||
*prop = NULL;
|
||||
*node = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct node *get_subnode(struct node *node, const char *nodename)
|
||||
{
|
||||
struct node *child;
|
||||
@ -245,11 +374,13 @@ struct node *get_node_by_path(struct node *tree, const char *path)
|
||||
struct node *get_node_by_label(struct node *tree, const char *label)
|
||||
{
|
||||
struct node *child, *node;
|
||||
struct label *l;
|
||||
|
||||
assert(label && (strlen(label) > 0));
|
||||
|
||||
if (tree->label && streq(tree->label, label))
|
||||
return tree;
|
||||
for_each_label(tree->labels, l)
|
||||
if (streq(l->label, label))
|
||||
return tree;
|
||||
|
||||
for_each_child(tree, child) {
|
||||
node = get_node_by_label(child, label);
|
||||
@ -302,15 +433,13 @@ cell_t get_node_phandle(struct node *root, struct node *node)
|
||||
&& (phandle_format & PHANDLE_LEGACY))
|
||||
add_property(node,
|
||||
build_property("linux,phandle",
|
||||
data_append_cell(empty_data, phandle),
|
||||
NULL));
|
||||
data_append_cell(empty_data, phandle)));
|
||||
|
||||
if (!get_property(node, "phandle")
|
||||
&& (phandle_format & PHANDLE_EPAPR))
|
||||
add_property(node,
|
||||
build_property("phandle",
|
||||
data_append_cell(empty_data, phandle),
|
||||
NULL));
|
||||
data_append_cell(empty_data, phandle)));
|
||||
|
||||
/* If the node *does* have a phandle property, we must
|
||||
* be dealing with a self-referencing phandle, which will be
|
||||
@ -318,3 +447,163 @@ cell_t get_node_phandle(struct node *root, struct node *node)
|
||||
|
||||
return node->phandle;
|
||||
}
|
||||
|
||||
uint32_t guess_boot_cpuid(struct node *tree)
|
||||
{
|
||||
struct node *cpus, *bootcpu;
|
||||
struct property *reg;
|
||||
|
||||
cpus = get_node_by_path(tree, "/cpus");
|
||||
if (!cpus)
|
||||
return 0;
|
||||
|
||||
|
||||
bootcpu = cpus->children;
|
||||
if (!bootcpu)
|
||||
return 0;
|
||||
|
||||
reg = get_property(bootcpu, "reg");
|
||||
if (!reg || (reg->val.len != sizeof(uint32_t)))
|
||||
return 0;
|
||||
|
||||
/* FIXME: Sanity check node? */
|
||||
|
||||
return propval_cell(reg);
|
||||
}
|
||||
|
||||
static int cmp_reserve_info(const void *ax, const void *bx)
|
||||
{
|
||||
const struct reserve_info *a, *b;
|
||||
|
||||
a = *((const struct reserve_info * const *)ax);
|
||||
b = *((const struct reserve_info * const *)bx);
|
||||
|
||||
if (a->re.address < b->re.address)
|
||||
return -1;
|
||||
else if (a->re.address > b->re.address)
|
||||
return 1;
|
||||
else if (a->re.size < b->re.size)
|
||||
return -1;
|
||||
else if (a->re.size > b->re.size)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sort_reserve_entries(struct boot_info *bi)
|
||||
{
|
||||
struct reserve_info *ri, **tbl;
|
||||
int n = 0, i = 0;
|
||||
|
||||
for (ri = bi->reservelist;
|
||||
ri;
|
||||
ri = ri->next)
|
||||
n++;
|
||||
|
||||
if (n == 0)
|
||||
return;
|
||||
|
||||
tbl = xmalloc(n * sizeof(*tbl));
|
||||
|
||||
for (ri = bi->reservelist;
|
||||
ri;
|
||||
ri = ri->next)
|
||||
tbl[i++] = ri;
|
||||
|
||||
qsort(tbl, n, sizeof(*tbl), cmp_reserve_info);
|
||||
|
||||
bi->reservelist = tbl[0];
|
||||
for (i = 0; i < (n-1); i++)
|
||||
tbl[i]->next = tbl[i+1];
|
||||
tbl[n-1]->next = NULL;
|
||||
|
||||
free(tbl);
|
||||
}
|
||||
|
||||
static int cmp_prop(const void *ax, const void *bx)
|
||||
{
|
||||
const struct property *a, *b;
|
||||
|
||||
a = *((const struct property * const *)ax);
|
||||
b = *((const struct property * const *)bx);
|
||||
|
||||
return strcmp(a->name, b->name);
|
||||
}
|
||||
|
||||
static void sort_properties(struct node *node)
|
||||
{
|
||||
int n = 0, i = 0;
|
||||
struct property *prop, **tbl;
|
||||
|
||||
for_each_property(node, prop)
|
||||
n++;
|
||||
|
||||
if (n == 0)
|
||||
return;
|
||||
|
||||
tbl = xmalloc(n * sizeof(*tbl));
|
||||
|
||||
for_each_property(node, prop)
|
||||
tbl[i++] = prop;
|
||||
|
||||
qsort(tbl, n, sizeof(*tbl), cmp_prop);
|
||||
|
||||
node->proplist = tbl[0];
|
||||
for (i = 0; i < (n-1); i++)
|
||||
tbl[i]->next = tbl[i+1];
|
||||
tbl[n-1]->next = NULL;
|
||||
|
||||
free(tbl);
|
||||
}
|
||||
|
||||
static int cmp_subnode(const void *ax, const void *bx)
|
||||
{
|
||||
const struct node *a, *b;
|
||||
|
||||
a = *((const struct node * const *)ax);
|
||||
b = *((const struct node * const *)bx);
|
||||
|
||||
return strcmp(a->name, b->name);
|
||||
}
|
||||
|
||||
static void sort_subnodes(struct node *node)
|
||||
{
|
||||
int n = 0, i = 0;
|
||||
struct node *subnode, **tbl;
|
||||
|
||||
for_each_child(node, subnode)
|
||||
n++;
|
||||
|
||||
if (n == 0)
|
||||
return;
|
||||
|
||||
tbl = xmalloc(n * sizeof(*tbl));
|
||||
|
||||
for_each_child(node, subnode)
|
||||
tbl[i++] = subnode;
|
||||
|
||||
qsort(tbl, n, sizeof(*tbl), cmp_subnode);
|
||||
|
||||
node->children = tbl[0];
|
||||
for (i = 0; i < (n-1); i++)
|
||||
tbl[i]->next_sibling = tbl[i+1];
|
||||
tbl[n-1]->next_sibling = NULL;
|
||||
|
||||
free(tbl);
|
||||
}
|
||||
|
||||
static void sort_node(struct node *node)
|
||||
{
|
||||
struct node *c;
|
||||
|
||||
sort_properties(node);
|
||||
sort_subnodes(node);
|
||||
for_each_child(node, c)
|
||||
sort_node(c);
|
||||
}
|
||||
|
||||
void sort_tree(struct boot_info *bi)
|
||||
{
|
||||
sort_reserve_entries(bi);
|
||||
sort_node(bi->dt);
|
||||
}
|
||||
|
366
srcpos.c
366
srcpos.c
@ -24,126 +24,224 @@
|
||||
#include "dtc.h"
|
||||
#include "srcpos.h"
|
||||
|
||||
/* A node in our list of directories to search for source/include files */
|
||||
struct search_path {
|
||||
struct search_path *next; /* next node in list, NULL for end */
|
||||
const char *dirname; /* name of directory to search */
|
||||
};
|
||||
|
||||
/*
|
||||
* Like yylineno, this is the current open file pos.
|
||||
/* This is the list of directories that we search for source files */
|
||||
static struct search_path *search_path_head, **search_path_tail;
|
||||
|
||||
|
||||
static char *dirname(const char *path)
|
||||
{
|
||||
const char *slash = strrchr(path, '/');
|
||||
|
||||
if (slash) {
|
||||
int len = slash - path;
|
||||
char *dir = xmalloc(len + 1);
|
||||
|
||||
memcpy(dir, path, len);
|
||||
dir[len] = '\0';
|
||||
return dir;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FILE *depfile; /* = NULL */
|
||||
struct srcfile_state *current_srcfile; /* = NULL */
|
||||
|
||||
/* Detect infinite include recursion. */
|
||||
#define MAX_SRCFILE_DEPTH (100)
|
||||
static int srcfile_depth; /* = 0 */
|
||||
|
||||
|
||||
/**
|
||||
* Try to open a file in a given directory.
|
||||
*
|
||||
* If the filename is an absolute path, then dirname is ignored. If it is a
|
||||
* relative path, then we look in that directory for the file.
|
||||
*
|
||||
* @param dirname Directory to look in, or NULL for none
|
||||
* @param fname Filename to look for
|
||||
* @param fp Set to NULL if file did not open
|
||||
* @return allocated filename on success (caller must free), NULL on failure
|
||||
*/
|
||||
struct dtc_file *srcpos_file;
|
||||
static char *try_open(const char *dirname, const char *fname, FILE **fp)
|
||||
{
|
||||
char *fullname;
|
||||
|
||||
if (!dirname || fname[0] == '/')
|
||||
fullname = xstrdup(fname);
|
||||
else
|
||||
fullname = join_path(dirname, fname);
|
||||
|
||||
*fp = fopen(fullname, "r");
|
||||
if (!*fp) {
|
||||
free(fullname);
|
||||
fullname = NULL;
|
||||
}
|
||||
|
||||
return fullname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a file for read access
|
||||
*
|
||||
* If it is a relative filename, we search the full search path for it.
|
||||
*
|
||||
* @param fname Filename to open
|
||||
* @param fp Returns pointer to opened FILE, or NULL on failure
|
||||
* @return pointer to allocated filename, which caller must free
|
||||
*/
|
||||
static char *fopen_any_on_path(const char *fname, FILE **fp)
|
||||
{
|
||||
const char *cur_dir = NULL;
|
||||
struct search_path *node;
|
||||
char *fullname;
|
||||
|
||||
/* Try current directory first */
|
||||
assert(fp);
|
||||
if (current_srcfile)
|
||||
cur_dir = current_srcfile->dir;
|
||||
fullname = try_open(cur_dir, fname, fp);
|
||||
|
||||
/* Failing that, try each search path in turn */
|
||||
for (node = search_path_head; !*fp && node; node = node->next)
|
||||
fullname = try_open(node->dirname, fname, fp);
|
||||
|
||||
return fullname;
|
||||
}
|
||||
|
||||
FILE *srcfile_relative_open(const char *fname, char **fullnamep)
|
||||
{
|
||||
FILE *f;
|
||||
char *fullname;
|
||||
|
||||
if (streq(fname, "-")) {
|
||||
f = stdin;
|
||||
fullname = xstrdup("<stdin>");
|
||||
} else {
|
||||
fullname = fopen_any_on_path(fname, &f);
|
||||
if (!f)
|
||||
die("Couldn't open \"%s\": %s\n", fname,
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
if (depfile)
|
||||
fprintf(depfile, " %s", fullname);
|
||||
|
||||
if (fullnamep)
|
||||
*fullnamep = fullname;
|
||||
else
|
||||
free(fullname);
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
void srcfile_push(const char *fname)
|
||||
{
|
||||
struct srcfile_state *srcfile;
|
||||
|
||||
if (srcfile_depth++ >= MAX_SRCFILE_DEPTH)
|
||||
die("Includes nested too deeply");
|
||||
|
||||
srcfile = xmalloc(sizeof(*srcfile));
|
||||
|
||||
srcfile->f = srcfile_relative_open(fname, &srcfile->name);
|
||||
srcfile->dir = dirname(srcfile->name);
|
||||
srcfile->prev = current_srcfile;
|
||||
|
||||
srcfile->lineno = 1;
|
||||
srcfile->colno = 1;
|
||||
|
||||
current_srcfile = srcfile;
|
||||
}
|
||||
|
||||
int srcfile_pop(void)
|
||||
{
|
||||
struct srcfile_state *srcfile = current_srcfile;
|
||||
|
||||
assert(srcfile);
|
||||
|
||||
current_srcfile = srcfile->prev;
|
||||
|
||||
if (fclose(srcfile->f))
|
||||
die("Error closing \"%s\": %s\n", srcfile->name,
|
||||
strerror(errno));
|
||||
|
||||
/* FIXME: We allow the srcfile_state structure to leak,
|
||||
* because it could still be referenced from a location
|
||||
* variable being carried through the parser somewhere. To
|
||||
* fix this we could either allocate all the files from a
|
||||
* table, or use a pool allocator. */
|
||||
|
||||
return current_srcfile ? 1 : 0;
|
||||
}
|
||||
|
||||
void srcfile_add_search_path(const char *dirname)
|
||||
{
|
||||
struct search_path *node;
|
||||
|
||||
/* Create the node */
|
||||
node = xmalloc(sizeof(*node));
|
||||
node->next = NULL;
|
||||
node->dirname = xstrdup(dirname);
|
||||
|
||||
/* Add to the end of our list */
|
||||
if (search_path_tail)
|
||||
*search_path_tail = node;
|
||||
else
|
||||
search_path_head = node;
|
||||
search_path_tail = &node->next;
|
||||
}
|
||||
|
||||
/*
|
||||
* The empty source position.
|
||||
*/
|
||||
|
||||
struct dtc_file dtc_empty_file = {
|
||||
.dir = NULL,
|
||||
.name = "<no file>",
|
||||
.file = NULL
|
||||
};
|
||||
|
||||
srcpos srcpos_empty = {
|
||||
struct srcpos srcpos_empty = {
|
||||
.first_line = 0,
|
||||
.first_column = 0,
|
||||
.last_line = 0,
|
||||
.last_column = 0,
|
||||
.file = &dtc_empty_file
|
||||
.file = NULL,
|
||||
};
|
||||
|
||||
#define TAB_SIZE 8
|
||||
|
||||
static int
|
||||
dtc_open_one(struct dtc_file *file, const char *search, const char *fname)
|
||||
void srcpos_update(struct srcpos *pos, const char *text, int len)
|
||||
{
|
||||
char *fullname;
|
||||
int i;
|
||||
|
||||
if (search) {
|
||||
fullname = xmalloc(strlen(search) + strlen(fname) + 2);
|
||||
pos->file = current_srcfile;
|
||||
|
||||
strcpy(fullname, search);
|
||||
strcat(fullname, "/");
|
||||
strcat(fullname, fname);
|
||||
} else {
|
||||
fullname = xstrdup(fname);
|
||||
}
|
||||
pos->first_line = current_srcfile->lineno;
|
||||
pos->first_column = current_srcfile->colno;
|
||||
|
||||
file->file = fopen(fullname, "r");
|
||||
if (!file->file) {
|
||||
free(fullname);
|
||||
return 0;
|
||||
}
|
||||
for (i = 0; i < len; i++)
|
||||
if (text[i] == '\n') {
|
||||
current_srcfile->lineno++;
|
||||
current_srcfile->colno = 1;
|
||||
} else if (text[i] == '\t') {
|
||||
current_srcfile->colno =
|
||||
ALIGN(current_srcfile->colno, TAB_SIZE);
|
||||
} else {
|
||||
current_srcfile->colno++;
|
||||
}
|
||||
|
||||
file->name = fullname;
|
||||
return 1;
|
||||
pos->last_line = current_srcfile->lineno;
|
||||
pos->last_column = current_srcfile->colno;
|
||||
}
|
||||
|
||||
|
||||
struct dtc_file *
|
||||
dtc_open_file(const char *fname, const struct search_path *search)
|
||||
struct srcpos *
|
||||
srcpos_copy(struct srcpos *pos)
|
||||
{
|
||||
static const struct search_path default_search = { NULL, NULL, NULL };
|
||||
struct srcpos *pos_new;
|
||||
|
||||
struct dtc_file *file;
|
||||
const char *slash;
|
||||
|
||||
file = xmalloc(sizeof(struct dtc_file));
|
||||
|
||||
slash = strrchr(fname, '/');
|
||||
if (slash) {
|
||||
char *dir = xmalloc(slash - fname + 1);
|
||||
|
||||
memcpy(dir, fname, slash - fname);
|
||||
dir[slash - fname] = 0;
|
||||
file->dir = dir;
|
||||
} else {
|
||||
file->dir = NULL;
|
||||
}
|
||||
|
||||
if (streq(fname, "-")) {
|
||||
file->name = "stdin";
|
||||
file->file = stdin;
|
||||
return file;
|
||||
}
|
||||
|
||||
if (fname[0] == '/') {
|
||||
file->file = fopen(fname, "r");
|
||||
if (!file->file)
|
||||
goto fail;
|
||||
|
||||
file->name = xstrdup(fname);
|
||||
return file;
|
||||
}
|
||||
|
||||
if (!search)
|
||||
search = &default_search;
|
||||
|
||||
while (search) {
|
||||
if (dtc_open_one(file, search->dir, fname))
|
||||
return file;
|
||||
|
||||
if (errno != ENOENT)
|
||||
goto fail;
|
||||
|
||||
search = search->next;
|
||||
}
|
||||
|
||||
fail:
|
||||
die("Couldn't open \"%s\": %s\n", fname, strerror(errno));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
dtc_close_file(struct dtc_file *file)
|
||||
{
|
||||
if (fclose(file->file))
|
||||
die("Error closing \"%s\": %s\n", file->name, strerror(errno));
|
||||
}
|
||||
|
||||
|
||||
srcpos *
|
||||
srcpos_copy(srcpos *pos)
|
||||
{
|
||||
srcpos *pos_new;
|
||||
|
||||
pos_new = xmalloc(sizeof(srcpos));
|
||||
memcpy(pos_new, pos, sizeof(srcpos));
|
||||
pos_new = xmalloc(sizeof(struct srcpos));
|
||||
memcpy(pos_new, pos, sizeof(struct srcpos));
|
||||
|
||||
return pos_new;
|
||||
}
|
||||
@ -151,7 +249,7 @@ srcpos_copy(srcpos *pos)
|
||||
|
||||
|
||||
void
|
||||
srcpos_dump(srcpos *pos)
|
||||
srcpos_dump(struct srcpos *pos)
|
||||
{
|
||||
printf("file : \"%s\"\n",
|
||||
pos->file ? (char *) pos->file : "<no file>");
|
||||
@ -164,67 +262,59 @@ srcpos_dump(srcpos *pos)
|
||||
|
||||
|
||||
char *
|
||||
srcpos_string(srcpos *pos)
|
||||
srcpos_string(struct srcpos *pos)
|
||||
{
|
||||
const char *fname;
|
||||
char col_buf[100];
|
||||
const char *fname = "<no-file>";
|
||||
char *pos_str;
|
||||
int rc;
|
||||
|
||||
if (!pos) {
|
||||
fname = "<no-file>";
|
||||
} else if (pos->file->name) {
|
||||
if (pos)
|
||||
fname = pos->file->name;
|
||||
if (strcmp(fname, "-") == 0)
|
||||
fname = "stdin";
|
||||
} else {
|
||||
fname = "<no-file>";
|
||||
}
|
||||
|
||||
if (pos->first_line == pos->last_line) {
|
||||
if (pos->first_column == pos->last_column) {
|
||||
snprintf(col_buf, sizeof(col_buf),
|
||||
"%d:%d",
|
||||
pos->first_line, pos->first_column);
|
||||
} else {
|
||||
snprintf(col_buf, sizeof(col_buf),
|
||||
"%d:%d-%d",
|
||||
pos->first_line,
|
||||
pos->first_column, pos->last_column);
|
||||
}
|
||||
|
||||
} else {
|
||||
snprintf(col_buf, sizeof(col_buf),
|
||||
"%d:%d - %d:%d",
|
||||
pos->first_line, pos->first_column,
|
||||
pos->last_line, pos->last_column);
|
||||
}
|
||||
if (pos->first_line != pos->last_line)
|
||||
rc = asprintf(&pos_str, "%s:%d.%d-%d.%d", fname,
|
||||
pos->first_line, pos->first_column,
|
||||
pos->last_line, pos->last_column);
|
||||
else if (pos->first_column != pos->last_column)
|
||||
rc = asprintf(&pos_str, "%s:%d.%d-%d", fname,
|
||||
pos->first_line, pos->first_column,
|
||||
pos->last_column);
|
||||
else
|
||||
rc = asprintf(&pos_str, "%s:%d.%d", fname,
|
||||
pos->first_line, pos->first_column);
|
||||
|
||||
if (asprintf(&pos_str, "%s %s", fname, col_buf) == -1)
|
||||
return "<unknown source position?";
|
||||
if (rc == -1)
|
||||
die("Couldn't allocate in srcpos string");
|
||||
|
||||
return pos_str;
|
||||
}
|
||||
|
||||
void
|
||||
srcpos_verror(struct srcpos *pos, char const *fmt, va_list va)
|
||||
{
|
||||
const char *srcstr;
|
||||
|
||||
srcstr = srcpos_string(pos);
|
||||
|
||||
fprintf(stdout, "Error: %s ", srcstr);
|
||||
vfprintf(stdout, fmt, va);
|
||||
fprintf(stdout, "\n");
|
||||
}
|
||||
|
||||
void
|
||||
srcpos_error(srcpos *pos, char const *fmt, ...)
|
||||
srcpos_error(struct srcpos *pos, char const *fmt, ...)
|
||||
{
|
||||
const char *srcstr;
|
||||
va_list va;
|
||||
|
||||
va_start(va, fmt);
|
||||
|
||||
srcstr = srcpos_string(pos);
|
||||
|
||||
fprintf(stderr, "Error: %s ", srcstr);
|
||||
vfprintf(stderr, fmt, va);
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
srcpos_verror(pos, fmt, va);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
srcpos_warn(srcpos *pos, char const *fmt, ...)
|
||||
srcpos_warn(struct srcpos *pos, char const *fmt, ...)
|
||||
{
|
||||
const char *srcstr;
|
||||
va_list va;
|
||||
|
128
srcpos.h
128
srcpos.h
@ -20,85 +20,97 @@
|
||||
#ifndef _SRCPOS_H_
|
||||
#define _SRCPOS_H_
|
||||
|
||||
/*
|
||||
* Augment the standard YYLTYPE with a filenum index into an
|
||||
* array of all opened filenames.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
struct dtc_file {
|
||||
struct srcfile_state {
|
||||
FILE *f;
|
||||
char *name;
|
||||
char *dir;
|
||||
const char *name;
|
||||
FILE *file;
|
||||
int lineno, colno;
|
||||
struct srcfile_state *prev;
|
||||
};
|
||||
|
||||
#if ! defined(YYLTYPE) && ! defined(YYLTYPE_IS_DECLARED)
|
||||
typedef struct YYLTYPE {
|
||||
extern FILE *depfile; /* = NULL */
|
||||
extern struct srcfile_state *current_srcfile; /* = NULL */
|
||||
|
||||
/**
|
||||
* Open a source file.
|
||||
*
|
||||
* If the source file is a relative pathname, then it is searched for in the
|
||||
* current directory (the directory of the last source file read) and after
|
||||
* that in the search path.
|
||||
*
|
||||
* We work through the search path in order from the first path specified to
|
||||
* the last.
|
||||
*
|
||||
* If the file is not found, then this function does not return, but calls
|
||||
* die().
|
||||
*
|
||||
* @param fname Filename to search
|
||||
* @param fullnamep If non-NULL, it is set to the allocated filename of the
|
||||
* file that was opened. The caller is then responsible
|
||||
* for freeing the pointer.
|
||||
* @return pointer to opened FILE
|
||||
*/
|
||||
FILE *srcfile_relative_open(const char *fname, char **fullnamep);
|
||||
|
||||
void srcfile_push(const char *fname);
|
||||
int srcfile_pop(void);
|
||||
|
||||
/**
|
||||
* Add a new directory to the search path for input files
|
||||
*
|
||||
* The new path is added at the end of the list.
|
||||
*
|
||||
* @param dirname Directory to add
|
||||
*/
|
||||
void srcfile_add_search_path(const char *dirname);
|
||||
|
||||
struct srcpos {
|
||||
int first_line;
|
||||
int first_column;
|
||||
int last_line;
|
||||
int last_column;
|
||||
struct dtc_file *file;
|
||||
} YYLTYPE;
|
||||
struct srcfile_state *file;
|
||||
};
|
||||
|
||||
#define YYLTYPE_IS_DECLARED 1
|
||||
#define YYLTYPE_IS_TRIVIAL 1
|
||||
#endif
|
||||
#define YYLTYPE struct srcpos
|
||||
|
||||
/* Cater to old parser templates. */
|
||||
#ifndef YYID
|
||||
#define YYID(n) (n)
|
||||
#endif
|
||||
#define YYLLOC_DEFAULT(Current, Rhs, N) \
|
||||
do { \
|
||||
if (N) { \
|
||||
(Current).first_line = YYRHSLOC(Rhs, 1).first_line; \
|
||||
(Current).first_column = YYRHSLOC(Rhs, 1).first_column; \
|
||||
(Current).last_line = YYRHSLOC(Rhs, N).last_line; \
|
||||
(Current).last_column = YYRHSLOC (Rhs, N).last_column; \
|
||||
(Current).file = YYRHSLOC(Rhs, N).file; \
|
||||
} else { \
|
||||
(Current).first_line = (Current).last_line = \
|
||||
YYRHSLOC(Rhs, 0).last_line; \
|
||||
(Current).first_column = (Current).last_column = \
|
||||
YYRHSLOC(Rhs, 0).last_column; \
|
||||
(Current).file = YYRHSLOC (Rhs, 0).file; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define YYLLOC_DEFAULT(Current, Rhs, N) \
|
||||
do \
|
||||
if (YYID (N)) \
|
||||
{ \
|
||||
(Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
|
||||
(Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
|
||||
(Current).last_line = YYRHSLOC (Rhs, N).last_line; \
|
||||
(Current).last_column = YYRHSLOC (Rhs, N).last_column; \
|
||||
(Current).file = YYRHSLOC (Rhs, N).file; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
(Current).first_line = (Current).last_line = \
|
||||
YYRHSLOC (Rhs, 0).last_line; \
|
||||
(Current).first_column = (Current).last_column = \
|
||||
YYRHSLOC (Rhs, 0).last_column; \
|
||||
(Current).file = YYRHSLOC (Rhs, 0).file; \
|
||||
} \
|
||||
while (YYID (0))
|
||||
|
||||
|
||||
typedef YYLTYPE srcpos;
|
||||
|
||||
/*
|
||||
* Fictional source position used for IR nodes that are
|
||||
* created without otherwise knowing a true source position.
|
||||
* For example,constant definitions from the command line.
|
||||
*/
|
||||
extern srcpos srcpos_empty;
|
||||
extern struct srcpos srcpos_empty;
|
||||
|
||||
extern struct dtc_file *srcpos_file;
|
||||
extern void srcpos_update(struct srcpos *pos, const char *text, int len);
|
||||
extern struct srcpos *srcpos_copy(struct srcpos *pos);
|
||||
extern char *srcpos_string(struct srcpos *pos);
|
||||
extern void srcpos_dump(struct srcpos *pos);
|
||||
|
||||
struct search_path {
|
||||
const char *dir; /* NULL for current directory */
|
||||
struct search_path *prev, *next;
|
||||
};
|
||||
|
||||
extern struct dtc_file *dtc_open_file(const char *fname,
|
||||
const struct search_path *search);
|
||||
extern void dtc_close_file(struct dtc_file *file);
|
||||
|
||||
extern srcpos *srcpos_copy(srcpos *pos);
|
||||
extern char *srcpos_string(srcpos *pos);
|
||||
extern void srcpos_dump(srcpos *pos);
|
||||
|
||||
extern void srcpos_error(srcpos *pos, char const *, ...)
|
||||
extern void srcpos_verror(struct srcpos *pos, char const *, va_list va)
|
||||
__attribute__((format(printf, 2, 0)));
|
||||
extern void srcpos_error(struct srcpos *pos, char const *, ...)
|
||||
__attribute__((format(printf, 2, 3)));
|
||||
extern void srcpos_warn(srcpos *pos, char const *, ...)
|
||||
extern void srcpos_warn(struct srcpos *pos, char const *, ...)
|
||||
__attribute__((format(printf, 2, 3)));
|
||||
|
||||
#endif /* _SRCPOS_H_ */
|
||||
|
@ -5,16 +5,22 @@ LIB_TESTS_L = get_mem_rsv \
|
||||
node_offset_by_prop_value node_offset_by_phandle \
|
||||
node_check_compatible node_offset_by_compatible \
|
||||
get_alias \
|
||||
char_literal \
|
||||
sized_cells \
|
||||
notfound \
|
||||
setprop_inplace nop_property nop_node \
|
||||
sw_tree1 \
|
||||
move_and_save mangle-layout nopulate \
|
||||
open_pack rw_tree1 set_name setprop del_property del_node \
|
||||
appendprop1 appendprop2 \
|
||||
string_escapes references path-references phandle_format \
|
||||
boot-cpuid incbin \
|
||||
extra-terminating-null \
|
||||
dtbs_equal_ordered \
|
||||
add_subnode_with_nops path_offset_aliases
|
||||
dtb_reverse dtbs_equal_unordered \
|
||||
add_subnode_with_nops path_offset_aliases \
|
||||
utilfdt_test \
|
||||
integer-expressions
|
||||
LIB_TESTS = $(LIB_TESTS_L:%=$(TESTS_PREFIX)%)
|
||||
|
||||
LIBTREE_TESTS_L = truncated_property
|
||||
@ -40,13 +46,14 @@ TESTS_CLEANFILES = $(TESTS) $(TESTS_CLEANFILES_L:%=$(TESTS_PREFIX)%)
|
||||
.PHONY: tests
|
||||
tests: $(TESTS) $(TESTS_TREES)
|
||||
|
||||
$(LIB_TESTS): %: $(TESTS_PREFIX)testutils.o $(LIBFDT_archive)
|
||||
$(LIB_TESTS): %: $(TESTS_PREFIX)testutils.o util.o $(LIBFDT_archive)
|
||||
|
||||
$(DL_LIB_TESTS): %: %.o $(TESTS_PREFIX)testutils.o $(LIBFDT_archive)
|
||||
$(DL_LIB_TESTS): %: %.o $(TESTS_PREFIX)testutils.o util.o $(LIBFDT_archive)
|
||||
@$(VECHO) LD [libdl] $@
|
||||
$(LINK.c) -o $@ $^ -ldl
|
||||
|
||||
$(LIBTREE_TESTS): %: $(TESTS_PREFIX)testutils.o $(TESTS_PREFIX)trees.o $(LIBFDT_archive)
|
||||
$(LIBTREE_TESTS): %: $(TESTS_PREFIX)testutils.o $(TESTS_PREFIX)trees.o \
|
||||
util.o $(LIBFDT_archive)
|
||||
|
||||
$(TESTS_PREFIX)dumptrees: $(TESTS_PREFIX)trees.o
|
||||
|
||||
@ -59,13 +66,13 @@ tests_clean:
|
||||
rm -f $(STD_CLEANFILES:%=$(TESTS_PREFIX)%)
|
||||
rm -f $(TESTS_CLEANFILES)
|
||||
|
||||
check: tests dtc convert-dtsv0
|
||||
check: tests ${TESTS_BIN}
|
||||
cd $(TESTS_PREFIX); ./run_tests.sh
|
||||
|
||||
checkm: tests dtc convert-dtsv0
|
||||
checkm: tests ${TESTS_BIN}
|
||||
cd $(TESTS_PREFIX); ./run_tests.sh -m 2>&1 | tee vglog.$$$$
|
||||
|
||||
checkv: tests dtc convert-dtsv0
|
||||
checkv: tests ${TESTS_BIN}
|
||||
cd $(TESTS_PREFIX); ./run_tests.sh -v
|
||||
|
||||
ifneq ($(DEPTARGETS),)
|
||||
|
@ -29,6 +29,31 @@
|
||||
#include "tests.h"
|
||||
#include "testdata.h"
|
||||
|
||||
int notequal; /* = 0 */
|
||||
|
||||
#define MISMATCH(fmt, ...) \
|
||||
do { \
|
||||
if (notequal) \
|
||||
PASS(); \
|
||||
else \
|
||||
FAIL(fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define MATCH() \
|
||||
do { \
|
||||
if (!notequal) \
|
||||
PASS(); \
|
||||
else \
|
||||
FAIL("Trees match which shouldn't"); \
|
||||
} while (0)
|
||||
|
||||
#define CHECK(code) \
|
||||
{ \
|
||||
err = (code); \
|
||||
if (err) \
|
||||
FAIL(#code ": %s", fdt_strerror(err)); \
|
||||
}
|
||||
|
||||
static void compare_mem_rsv(const void *fdt1, const void *fdt2)
|
||||
{
|
||||
int i;
|
||||
@ -36,23 +61,18 @@ static void compare_mem_rsv(const void *fdt1, const void *fdt2)
|
||||
int err;
|
||||
|
||||
if (fdt_num_mem_rsv(fdt1) != fdt_num_mem_rsv(fdt2))
|
||||
FAIL("Trees have different number of reserve entries");
|
||||
MISMATCH("Trees have different number of reserve entries");
|
||||
for (i = 0; i < fdt_num_mem_rsv(fdt1); i++) {
|
||||
err = fdt_get_mem_rsv(fdt1, i, &addr1, &size1);
|
||||
if (err)
|
||||
FAIL("fdt_get_mem_rsv(fdt1, %d, ...): %s", i,
|
||||
fdt_strerror(err));
|
||||
err = fdt_get_mem_rsv(fdt2, i, &addr2, &size2);
|
||||
if (err)
|
||||
FAIL("fdt_get_mem_rsv(fdt2, %d, ...): %s", i,
|
||||
fdt_strerror(err));
|
||||
CHECK(fdt_get_mem_rsv(fdt1, i, &addr1, &size1));
|
||||
CHECK(fdt_get_mem_rsv(fdt2, i, &addr2, &size2));
|
||||
|
||||
if ((addr1 != addr2) || (size1 != size2))
|
||||
FAIL("Mismatch in reserve entry %d: "
|
||||
"(0x%llx, 0x%llx) != (0x%llx, 0x%llx)", i,
|
||||
(unsigned long long)addr1,
|
||||
(unsigned long long)size1,
|
||||
(unsigned long long)addr2,
|
||||
(unsigned long long)size2);
|
||||
MISMATCH("Mismatch in reserve entry %d: "
|
||||
"(0x%llx, 0x%llx) != (0x%llx, 0x%llx)", i,
|
||||
(unsigned long long)addr1,
|
||||
(unsigned long long)size1,
|
||||
(unsigned long long)addr2,
|
||||
(unsigned long long)size2);
|
||||
}
|
||||
}
|
||||
|
||||
@ -77,7 +97,7 @@ static void compare_structure(const void *fdt1, const void *fdt2)
|
||||
} while (tag2 == FDT_NOP);
|
||||
|
||||
if (tag1 != tag2)
|
||||
FAIL("Tag mismatch (%d != %d) at (%d, %d)",
|
||||
MISMATCH("Tag mismatch (%d != %d) at (%d, %d)",
|
||||
tag1, tag2, offset1, offset2);
|
||||
|
||||
switch (tag1) {
|
||||
@ -90,9 +110,10 @@ static void compare_structure(const void *fdt1, const void *fdt2)
|
||||
if (!name2)
|
||||
FAIL("fdt_get_name(fdt2, %d, ..): %s",
|
||||
offset2, fdt_strerror(err));
|
||||
|
||||
if (!streq(name1, name2))
|
||||
FAIL("Name mismatch (\"%s\" != \"%s\") at (%d, %d)",
|
||||
name1, name2, offset1, offset2);
|
||||
MISMATCH("Name mismatch (\"%s\" != \"%s\") at (%d, %d)",
|
||||
name1, name2, offset1, offset2);
|
||||
break;
|
||||
|
||||
case FDT_PROP:
|
||||
@ -106,17 +127,17 @@ static void compare_structure(const void *fdt1, const void *fdt2)
|
||||
name1 = fdt_string(fdt1, fdt32_to_cpu(prop1->nameoff));
|
||||
name2 = fdt_string(fdt2, fdt32_to_cpu(prop2->nameoff));
|
||||
if (!streq(name1, name2))
|
||||
FAIL("Property name mismatch \"%s\" != \"%s\" "
|
||||
"at (%d, %d)", name1, name2, offset1, offset2);
|
||||
MISMATCH("Property name mismatch \"%s\" != \"%s\" "
|
||||
"at (%d, %d)", name1, name2, offset1, offset2);
|
||||
len1 = fdt32_to_cpu(prop1->len);
|
||||
len2 = fdt32_to_cpu(prop2->len);
|
||||
if (len1 != len2)
|
||||
FAIL("Property length mismatch %u != %u "
|
||||
"at (%d, %d)", len1, len2, offset1, offset2);
|
||||
MISMATCH("Property length mismatch %u != %u "
|
||||
"at (%d, %d)", len1, len2, offset1, offset2);
|
||||
|
||||
if (memcmp(prop1->data, prop2->data, len1) != 0)
|
||||
FAIL("Property value mismatch at (%d, %d)",
|
||||
offset1, offset2);
|
||||
MISMATCH("Property value mismatch at (%d, %d)",
|
||||
offset1, offset2);
|
||||
break;
|
||||
|
||||
case FDT_END:
|
||||
@ -131,10 +152,14 @@ int main(int argc, char *argv[])
|
||||
uint32_t cpuid1, cpuid2;
|
||||
|
||||
test_init(argc, argv);
|
||||
if (argc != 3)
|
||||
CONFIG("Usage: %s <dtb file> <dtb file>", argv[0]);
|
||||
fdt1 = load_blob(argv[1]);
|
||||
fdt2 = load_blob(argv[2]);
|
||||
if ((argc != 3)
|
||||
&& ((argc != 4) || !streq(argv[1], "-n")))
|
||||
CONFIG("Usage: %s [-n] <dtb file> <dtb file>", argv[0]);
|
||||
if (argc == 4)
|
||||
notequal = 1;
|
||||
|
||||
fdt1 = load_blob(argv[argc-2]);
|
||||
fdt2 = load_blob(argv[argc-1]);
|
||||
|
||||
compare_mem_rsv(fdt1, fdt2);
|
||||
compare_structure(fdt1, fdt2);
|
||||
@ -142,8 +167,8 @@ int main(int argc, char *argv[])
|
||||
cpuid1 = fdt_boot_cpuid_phys(fdt1);
|
||||
cpuid2 = fdt_boot_cpuid_phys(fdt2);
|
||||
if (cpuid1 != cpuid2)
|
||||
FAIL("boot_cpuid_phys mismatch 0x%x != 0x%x",
|
||||
cpuid1, cpuid2);
|
||||
MISMATCH("boot_cpuid_phys mismatch 0x%x != 0x%x",
|
||||
cpuid1, cpuid2);
|
||||
|
||||
PASS();
|
||||
MATCH();
|
||||
}
|
||||
|
@ -4,30 +4,41 @@
|
||||
|
||||
for x; do
|
||||
shift
|
||||
if [ "$x" = "-n" ]; then
|
||||
for x; do
|
||||
shift
|
||||
if [ "$x" = "--" ]; then
|
||||
break;
|
||||
fi
|
||||
NOCHECKS="$NOCHECKS $x"
|
||||
done
|
||||
break;
|
||||
fi
|
||||
if [ "$x" = "--" ]; then
|
||||
break;
|
||||
fi
|
||||
CHECKS="$CHECKS $x"
|
||||
YESCHECKS="$YESCHECKS $x"
|
||||
done
|
||||
|
||||
LOG="tmp.log.$$"
|
||||
|
||||
rm -f $TMPFILE $LOG
|
||||
LOG=tmp.log.$$
|
||||
rm -f $LOG
|
||||
trap "rm -f $LOG" 0
|
||||
|
||||
verbose_run_log "$LOG" $VALGRIND "$DTC" -o /dev/null "$@"
|
||||
ret="$?"
|
||||
|
||||
if [ "$ret" -gt 127 ]; then
|
||||
signame=$(kill -l $[ret - 128])
|
||||
FAIL "Killed by SIG$signame"
|
||||
fi
|
||||
FAIL_IF_SIGNAL $ret
|
||||
|
||||
for c in $CHECKS; do
|
||||
for c in $YESCHECKS; do
|
||||
if ! grep -E "^(ERROR)|(Warning) \($c\):" $LOG > /dev/null; then
|
||||
FAIL "Failed to trigger check \"$c\""
|
||||
fi
|
||||
done
|
||||
|
||||
rm -f $LOG
|
||||
for c in $NOCHECKS; do
|
||||
if grep -E "^(ERROR)|(Warning) \($c\):" $LOG > /dev/null; then
|
||||
FAIL "Incorrectly triggered check \"$c\""
|
||||
fi
|
||||
done
|
||||
|
||||
PASS
|
||||
|
@ -28,7 +28,7 @@
|
||||
#include "tests.h"
|
||||
#include "testdata.h"
|
||||
|
||||
void check_extranull(void *fdt, const char *prop, const char *str, int numnulls)
|
||||
static void check_extranull(void *fdt, const char *prop, const char *str, int numnulls)
|
||||
{
|
||||
int len = strlen(str);
|
||||
char checkbuf[len+numnulls];
|
||||
|
@ -29,7 +29,7 @@
|
||||
#include "tests.h"
|
||||
#include "testdata.h"
|
||||
|
||||
void check_alias(void *fdt, const char *path, const char *alias)
|
||||
static void check_alias(void *fdt, const char *path, const char *alias)
|
||||
{
|
||||
const char *aliaspath;
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
/ {
|
||||
/include/ "include4.dts"
|
||||
/include/ "include5.dts" = <0xdeadbeef>;
|
||||
prop-int64 /include/ "include5a.dts";
|
||||
prop-str = /include/ "include6.dts";
|
||||
|
||||
/include/ "include7.dts"
|
||||
|
@ -65,7 +65,7 @@ static void new_header(struct bufstate *buf, int version, const void *fdt)
|
||||
|
||||
static void add_block(struct bufstate *buf, int version, char block, const void *fdt)
|
||||
{
|
||||
int align, size;
|
||||
int align, size, oldsize;
|
||||
const void *src;
|
||||
int offset;
|
||||
|
||||
@ -95,9 +95,10 @@ static void add_block(struct bufstate *buf, int version, char block, const void
|
||||
CONFIG("Bad block '%c'", block);
|
||||
}
|
||||
|
||||
offset = ALIGN(buf->size, align);
|
||||
|
||||
oldsize = buf->size;
|
||||
offset = ALIGN(oldsize, align);
|
||||
expand_buf(buf, offset+size);
|
||||
memset(buf->buf + oldsize, 0, offset - oldsize);
|
||||
|
||||
memcpy(buf->buf + offset, src, size);
|
||||
|
||||
|
@ -37,27 +37,25 @@ static void check_error(const char *s, int err)
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
const struct fdt_property *prop;
|
||||
void *fdt;
|
||||
int offset;
|
||||
int subnode1_offset;
|
||||
const void *val;
|
||||
int lenerr;
|
||||
|
||||
test_init(argc, argv);
|
||||
fdt = load_blob_arg(argc, argv);
|
||||
|
||||
prop = fdt_get_property(fdt, 0, "nonexistant-property", &lenerr);
|
||||
fdt_get_property(fdt, 0, "nonexistant-property", &lenerr);
|
||||
check_error("fdt_get_property(\"nonexistant-property\")", lenerr);
|
||||
|
||||
val = fdt_getprop(fdt, 0, "nonexistant-property", &lenerr);
|
||||
fdt_getprop(fdt, 0, "nonexistant-property", &lenerr);
|
||||
check_error("fdt_getprop(\"nonexistant-property\"", lenerr);
|
||||
|
||||
subnode1_offset = fdt_subnode_offset(fdt, 0, "subnode@1");
|
||||
if (subnode1_offset < 0)
|
||||
FAIL("Couldn't find subnode1: %s", fdt_strerror(subnode1_offset));
|
||||
|
||||
val = fdt_getprop(fdt, subnode1_offset, "prop-str", &lenerr);
|
||||
fdt_getprop(fdt, subnode1_offset, "prop-str", &lenerr);
|
||||
check_error("fdt_getprop(\"prop-str\")", lenerr);
|
||||
|
||||
offset = fdt_subnode_offset(fdt, 0, "nonexistant-subnode");
|
||||
|
@ -48,6 +48,8 @@ int main(int argc, char *argv[])
|
||||
bufsize = oldsize * 2;
|
||||
|
||||
buf = xmalloc(bufsize);
|
||||
/* don't leak uninitialized memory into our output */
|
||||
memset(buf, 0, bufsize);
|
||||
|
||||
fdt1 = buf;
|
||||
err = fdt_open_into(fdt, fdt1, bufsize);
|
||||
|
@ -104,5 +104,9 @@ int main(int argc, char *argv[])
|
||||
FAIL("Mismatch between subnode_offset (%d) and path_offset (%d)",
|
||||
subsubnode2_offset, subsubnode2_offset_p);
|
||||
|
||||
if (subsubnode2_offset2 != subsubnode2_offset2_p)
|
||||
FAIL("Mismatch between subnode_offset (%d) and path_offset (%d)",
|
||||
subsubnode2_offset2, subsubnode2_offset2_p);
|
||||
|
||||
PASS();
|
||||
}
|
||||
|
@ -29,7 +29,7 @@
|
||||
#include "tests.h"
|
||||
#include "testdata.h"
|
||||
|
||||
void check_alias(void *fdt, const char *full_path, const char *alias_path)
|
||||
static void check_alias(void *fdt, const char *full_path, const char *alias_path)
|
||||
{
|
||||
int offset, offset_a;
|
||||
|
||||
|
@ -24,11 +24,11 @@ base_run_test() {
|
||||
tot_pass=$((tot_pass + 1))
|
||||
else
|
||||
ret="$?"
|
||||
if [ "$ret" == "1" ]; then
|
||||
if [ "$ret" -eq 1 ]; then
|
||||
tot_config=$((tot_config + 1))
|
||||
elif [ "$ret" == "2" ]; then
|
||||
elif [ "$ret" -eq 2 ]; then
|
||||
tot_fail=$((tot_fail + 1))
|
||||
elif [ "$ret" == "$VGCODE" ]; then
|
||||
elif [ "$ret" -eq $VGCODE ]; then
|
||||
tot_vg=$((tot_vg + 1))
|
||||
else
|
||||
tot_strange=$((tot_strange + 1))
|
||||
@ -36,6 +36,20 @@ base_run_test() {
|
||||
fi
|
||||
}
|
||||
|
||||
shorten_echo () {
|
||||
limit=32
|
||||
echo -n "$1"
|
||||
shift
|
||||
for x; do
|
||||
if [ ${#x} -le $limit ]; then
|
||||
echo -n " $x"
|
||||
else
|
||||
short=$(echo "$x" | head -c$limit)
|
||||
echo -n " \"$short\"...<${#x} bytes>"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
run_test () {
|
||||
echo -n "$@: "
|
||||
if [ -n "$VALGRIND" -a -f $1.supp ]; then
|
||||
@ -70,6 +84,28 @@ run_wrap_test () {
|
||||
base_run_test wrap_test "$@"
|
||||
}
|
||||
|
||||
wrap_error () {
|
||||
(
|
||||
if verbose_run "$@"; then
|
||||
FAIL "Expected non-zero return code"
|
||||
else
|
||||
ret="$?"
|
||||
if [ "$ret" -gt 127 ]; then
|
||||
signame=$(kill -l $((ret - 128)))
|
||||
FAIL "Killed by SIG$signame"
|
||||
else
|
||||
PASS
|
||||
fi
|
||||
fi
|
||||
)
|
||||
}
|
||||
|
||||
run_wrap_error_test () {
|
||||
shorten_echo "$@"
|
||||
echo -n " {!= 0}: "
|
||||
base_run_test wrap_error "$@"
|
||||
}
|
||||
|
||||
run_dtc_test () {
|
||||
echo -n "dtc $@: "
|
||||
base_run_test wrap_test $VALGRIND $DTC "$@"
|
||||
@ -83,6 +119,21 @@ asm_to_so_test () {
|
||||
run_wrap_test asm_to_so "$@"
|
||||
}
|
||||
|
||||
run_fdtget_test () {
|
||||
expect="$1"
|
||||
shift
|
||||
echo -n "fdtget-runtest.sh "$expect" $@: "
|
||||
base_run_test sh fdtget-runtest.sh "$expect" "$@"
|
||||
}
|
||||
|
||||
run_fdtput_test () {
|
||||
expect="$1"
|
||||
shift
|
||||
shorten_echo fdtput-runtest.sh "$expect" "$@"
|
||||
echo -n ": "
|
||||
base_run_test sh fdtput-runtest.sh "$expect" "$@"
|
||||
}
|
||||
|
||||
tree1_tests () {
|
||||
TREE=$1
|
||||
|
||||
@ -178,6 +229,10 @@ libfdt_tests () {
|
||||
run_test rw_tree1
|
||||
tree1_tests rw_tree1.test.dtb
|
||||
tree1_tests_rw rw_tree1.test.dtb
|
||||
run_test appendprop1
|
||||
run_test appendprop2 appendprop1.test.dtb
|
||||
run_dtc_test -I dts -O dtb -o appendprop.test.dtb appendprop.dts
|
||||
run_test dtbs_equal_ordered appendprop2.test.dtb appendprop.test.dtb
|
||||
|
||||
for basetree in test_tree1.dtb sw_tree1.test.dtb rw_tree1.test.dtb; do
|
||||
run_test nopulate $basetree
|
||||
@ -199,22 +254,21 @@ dtc_tests () {
|
||||
tree1_tests_rw dtc_tree1.test.dtb
|
||||
run_test dtbs_equal_ordered dtc_tree1.test.dtb test_tree1.dtb
|
||||
|
||||
run_dtc_test -I dts -O dtb -o dtc_tree1_dts0.test.dtb test_tree1_dts0.dts
|
||||
tree1_tests dtc_tree1_dts0.test.dtb
|
||||
tree1_tests_rw dtc_tree1_dts0.test.dtb
|
||||
|
||||
run_dtc_test -I dts -O dtb -o dtc_escapes.test.dtb escapes.dts
|
||||
run_test string_escapes dtc_escapes.test.dtb
|
||||
|
||||
run_dtc_test -I dts -O dtb -o dtc_char_literal.test.dtb char_literal.dts
|
||||
run_test char_literal dtc_char_literal.test.dtb
|
||||
|
||||
run_dtc_test -I dts -O dtb -o dtc_sized_cells.test.dtb sized_cells.dts
|
||||
run_test sized_cells dtc_sized_cells.test.dtb
|
||||
|
||||
run_dtc_test -I dts -O dtb -o dtc_extra-terminating-null.test.dtb extra-terminating-null.dts
|
||||
run_test extra-terminating-null dtc_extra-terminating-null.test.dtb
|
||||
|
||||
run_dtc_test -I dts -O dtb -o dtc_references.test.dtb references.dts
|
||||
run_test references dtc_references.test.dtb
|
||||
|
||||
run_dtc_test -I dts -O dtb -o dtc_references_dts0.test.dtb references_dts0.dts
|
||||
run_test references dtc_references_dts0.test.dtb
|
||||
|
||||
run_dtc_test -I dts -O dtb -o dtc_path-references.test.dtb path-references.dts
|
||||
run_test path-references dtc_path-references.test.dtb
|
||||
|
||||
@ -224,6 +278,11 @@ dtc_tests () {
|
||||
run_test phandle_format dtc_references.test.$f.dtb $f
|
||||
done
|
||||
|
||||
run_dtc_test -I dts -O dtb -o multilabel.test.dtb multilabel.dts
|
||||
run_test references multilabel.test.dtb
|
||||
|
||||
run_dtc_test -I dts -O dtb -o label_repeated.test.dtb label_repeated.dts
|
||||
|
||||
run_dtc_test -I dts -O dtb -o dtc_comments.test.dtb comments.dts
|
||||
run_dtc_test -I dts -O dtb -o dtc_comments-cmp.test.dtb comments-cmp.dts
|
||||
run_test dtbs_equal_ordered dtc_comments.test.dtb dtc_comments-cmp.test.dtb
|
||||
@ -242,12 +301,26 @@ dtc_tests () {
|
||||
run_test incbin incbin.test.dtb
|
||||
|
||||
# Check boot_cpuid_phys handling
|
||||
run_dtc_test -I dts -O dtb -b 17 -o boot_cpuid.test.dtb empty.dts
|
||||
run_test boot-cpuid boot_cpuid.test.dtb 17
|
||||
run_dtc_test -I dtb -O dtb -b 17 -o boot_cpuid_test_tree1.test.dtb test_tree1.dtb
|
||||
run_test boot-cpuid boot_cpuid_test_tree1.test.dtb 17
|
||||
run_dtc_test -I dtb -O dtb -o boot_cpuid_preserved_test_tree1.test.dtb boot_cpuid_test_tree1.test.dtb
|
||||
run_test dtbs_equal_ordered boot_cpuid_preserved_test_tree1.test.dtb boot_cpuid_test_tree1.test.dtb
|
||||
run_dtc_test -I dts -O dtb -o boot_cpuid.test.dtb boot-cpuid.dts
|
||||
run_test boot-cpuid boot_cpuid.test.dtb 16
|
||||
|
||||
run_dtc_test -I dts -O dtb -b 17 -o boot_cpuid_17.test.dtb boot-cpuid.dts
|
||||
run_test boot-cpuid boot_cpuid_17.test.dtb 17
|
||||
|
||||
run_dtc_test -I dtb -O dtb -o preserve_boot_cpuid.test.dtb boot_cpuid.test.dtb
|
||||
run_test boot-cpuid preserve_boot_cpuid.test.dtb 16
|
||||
run_test dtbs_equal_ordered preserve_boot_cpuid.test.dtb boot_cpuid.test.dtb
|
||||
|
||||
run_dtc_test -I dtb -O dtb -o preserve_boot_cpuid_17.test.dtb boot_cpuid_17.test.dtb
|
||||
run_test boot-cpuid preserve_boot_cpuid_17.test.dtb 17
|
||||
run_test dtbs_equal_ordered preserve_boot_cpuid_17.test.dtb boot_cpuid_17.test.dtb
|
||||
|
||||
run_dtc_test -I dtb -O dtb -b17 -o override17_boot_cpuid.test.dtb boot_cpuid.test.dtb
|
||||
run_test boot-cpuid override17_boot_cpuid.test.dtb 17
|
||||
|
||||
run_dtc_test -I dtb -O dtb -b0 -o override0_boot_cpuid_17.test.dtb boot_cpuid_17.test.dtb
|
||||
run_test boot-cpuid override0_boot_cpuid_17.test.dtb 0
|
||||
|
||||
|
||||
# Check -Oasm mode
|
||||
for tree in test_tree1.dts escapes.dts references.dts path-references.dts \
|
||||
@ -283,6 +356,17 @@ dtc_tests () {
|
||||
done
|
||||
done
|
||||
|
||||
# Check merge/overlay functionality
|
||||
run_dtc_test -I dts -O dtb -o dtc_tree1_merge.test.dtb test_tree1_merge.dts
|
||||
tree1_tests dtc_tree1_merge.test.dtb test_tree1.dtb
|
||||
run_dtc_test -I dts -O dtb -o dtc_tree1_merge_labelled.test.dtb test_tree1_merge_labelled.dts
|
||||
tree1_tests dtc_tree1_merge_labelled.test.dtb test_tree1.dtb
|
||||
run_dtc_test -I dts -O dtb -o multilabel_merge.test.dtb multilabel_merge.dts
|
||||
run_test references multilabel.test.dtb
|
||||
run_test dtbs_equal_ordered multilabel.test.dtb multilabel_merge.test.dtb
|
||||
run_dtc_test -I dts -O dtb -o dtc_tree1_merge_path.test.dtb test_tree1_merge_path.dts
|
||||
tree1_tests dtc_tree1_merge_path.test.dtb test_tree1.dtb
|
||||
|
||||
# Check some checks
|
||||
check_tests dup-nodename.dts duplicate_node_names
|
||||
check_tests dup-propname.dts duplicate_property_names
|
||||
@ -291,6 +375,7 @@ dtc_tests () {
|
||||
check_tests minusone-phandle.dts explicit_phandles
|
||||
run_sh_test dtc-checkfails.sh phandle_references -- -I dts -O dtb nonexist-node-ref.dts
|
||||
run_sh_test dtc-checkfails.sh phandle_references -- -I dts -O dtb nonexist-label-ref.dts
|
||||
run_sh_test dtc-fatal.sh -I dts -O dtb nonexist-node-ref2.dts
|
||||
check_tests bad-name-property.dts name_properties
|
||||
|
||||
check_tests bad-ncells.dts address_cells_is_cell size_cells_is_cell interrupt_cells_is_cell
|
||||
@ -304,16 +389,184 @@ dtc_tests () {
|
||||
run_sh_test dtc-checkfails.sh node_name_format -- -I dtb -O dtb bad_node_format.dtb
|
||||
run_sh_test dtc-checkfails.sh prop_name_chars -- -I dtb -O dtb bad_prop_char.dtb
|
||||
|
||||
run_sh_test dtc-checkfails.sh duplicate_label -- -I dts -O dtb reuse-label1.dts
|
||||
run_sh_test dtc-checkfails.sh duplicate_label -- -I dts -O dtb reuse-label2.dts
|
||||
run_sh_test dtc-checkfails.sh duplicate_label -- -I dts -O dtb reuse-label3.dts
|
||||
run_sh_test dtc-checkfails.sh duplicate_label -- -I dts -O dtb reuse-label4.dts
|
||||
run_sh_test dtc-checkfails.sh duplicate_label -- -I dts -O dtb reuse-label5.dts
|
||||
run_sh_test dtc-checkfails.sh duplicate_label -- -I dts -O dtb reuse-label6.dts
|
||||
|
||||
# Check warning options
|
||||
run_sh_test dtc-checkfails.sh address_cells_is_cell interrupt_cells_is_cell -n size_cells_is_cell -- -Wno_size_cells_is_cell -I dts -O dtb bad-ncells.dts
|
||||
run_sh_test dtc-fails.sh -n test-warn-output.test.dtb -I dts -O dtb bad-ncells.dts
|
||||
run_sh_test dtc-fails.sh test-error-output.test.dtb -I dts -O dtb bad-ncells.dts -Esize_cells_is_cell
|
||||
run_sh_test dtc-checkfails.sh always_fail -- -Walways_fail -I dts -O dtb test_tree1.dts
|
||||
run_sh_test dtc-checkfails.sh -n always_fail -- -Walways_fail -Wno_always_fail -I dts -O dtb test_tree1.dts
|
||||
run_sh_test dtc-fails.sh test-negation-1.test.dtb -Ealways_fail -I dts -O dtb test_tree1.dts
|
||||
run_sh_test dtc-fails.sh -n test-negation-2.test.dtb -Ealways_fail -Eno_always_fail -I dts -O dtb test_tree1.dts
|
||||
run_sh_test dtc-fails.sh test-negation-3.test.dtb -Ealways_fail -Wno_always_fail -I dts -O dtb test_tree1.dts
|
||||
run_sh_test dtc-fails.sh -n test-negation-4.test.dtb -Esize_cells_is_cell -Eno_size_cells_is_cell -I dts -O dtb bad-ncells.dts
|
||||
run_sh_test dtc-checkfails.sh size_cells_is_cell -- -Esize_cells_is_cell -Eno_size_cells_is_cell -I dts -O dtb bad-ncells.dts
|
||||
|
||||
# Check for proper behaviour reading from stdin
|
||||
run_dtc_test -I dts -O dtb -o stdin_dtc_tree1.test.dtb - < test_tree1.dts
|
||||
run_wrap_test cmp stdin_dtc_tree1.test.dtb dtc_tree1.test.dtb
|
||||
run_dtc_test -I dtb -O dts -o stdin_odts_test_tree1.dtb.test.dts - < test_tree1.dtb
|
||||
run_wrap_test cmp stdin_odts_test_tree1.dtb.test.dts odts_test_tree1.dtb.test.dts
|
||||
|
||||
# Check integer expresisons
|
||||
run_test integer-expressions -g integer-expressions.test.dts
|
||||
run_dtc_test -I dts -O dtb -o integer-expressions.test.dtb integer-expressions.test.dts
|
||||
run_test integer-expressions integer-expressions.test.dtb
|
||||
|
||||
# Check for graceful failure in some error conditions
|
||||
run_sh_test dtc-fatal.sh -I dts -O dtb nosuchfile.dts
|
||||
run_sh_test dtc-fatal.sh -I dtb -O dtb nosuchfile.dtb
|
||||
run_sh_test dtc-fatal.sh -I fs -O dtb nosuchfile
|
||||
|
||||
# Dependencies
|
||||
run_dtc_test -I dts -O dtb -o dependencies.test.dtb -d dependencies.test.d dependencies.dts
|
||||
run_wrap_test cmp dependencies.test.d dependencies.cmp
|
||||
|
||||
# Search paths
|
||||
run_wrap_error_test $DTC -I dts -O dtb -o search_paths.dtb search_paths.dts
|
||||
run_dtc_test -i search_dir -I dts -O dtb -o search_paths.dtb \
|
||||
search_paths.dts
|
||||
run_wrap_error_test $DTC -i search_dir_b -I dts -O dtb \
|
||||
-o search_paths_b.dtb search_paths_b.dts
|
||||
run_dtc_test -i search_dir_b -i search_dir -I dts -O dtb \
|
||||
-o search_paths_b.dtb search_paths_b.dts
|
||||
run_dtc_test -I dts -O dtb -o search_paths_subdir.dtb \
|
||||
search_dir_b/search_paths_subdir.dts
|
||||
}
|
||||
|
||||
cmp_tests () {
|
||||
basetree="$1"
|
||||
shift
|
||||
wrongtrees="$@"
|
||||
|
||||
run_test dtb_reverse $basetree
|
||||
|
||||
# First dtbs_equal_ordered
|
||||
run_test dtbs_equal_ordered $basetree $basetree
|
||||
run_test dtbs_equal_ordered -n $basetree $basetree.reversed.test.dtb
|
||||
for tree in $wrongtrees; do
|
||||
run_test dtbs_equal_ordered -n $basetree $tree
|
||||
done
|
||||
|
||||
# now unordered
|
||||
run_test dtbs_equal_unordered $basetree $basetree
|
||||
run_test dtbs_equal_unordered $basetree $basetree.reversed.test.dtb
|
||||
run_test dtbs_equal_unordered $basetree.reversed.test.dtb $basetree
|
||||
for tree in $wrongtrees; do
|
||||
run_test dtbs_equal_unordered -n $basetree $tree
|
||||
done
|
||||
|
||||
# now dtc --sort
|
||||
run_dtc_test -I dtb -O dtb -s -o $basetree.sorted.test.dtb $basetree
|
||||
run_test dtbs_equal_unordered $basetree $basetree.sorted.test.dtb
|
||||
run_dtc_test -I dtb -O dtb -s -o $basetree.reversed.sorted.test.dtb $basetree.reversed.test.dtb
|
||||
run_test dtbs_equal_unordered $basetree.reversed.test.dtb $basetree.reversed.sorted.test.dtb
|
||||
run_test dtbs_equal_ordered $basetree.sorted.test.dtb $basetree.reversed.sorted.test.dtb
|
||||
}
|
||||
|
||||
dtbs_equal_tests () {
|
||||
WRONG_TREE1=""
|
||||
for x in 1 2 3 4 5 6 7 8 9; do
|
||||
run_dtc_test -I dts -O dtb -o test_tree1_wrong$x.test.dtb test_tree1_wrong$x.dts
|
||||
WRONG_TREE1="$WRONG_TREE1 test_tree1_wrong$x.test.dtb"
|
||||
done
|
||||
cmp_tests test_tree1.dtb $WRONG_TREE1
|
||||
}
|
||||
|
||||
fdtget_tests () {
|
||||
dts=label01.dts
|
||||
dtb=$dts.fdtget.test.dtb
|
||||
run_dtc_test -O dtb -o $dtb $dts
|
||||
|
||||
# run_fdtget_test <expected-result> [<flags>] <file> <node> <property>
|
||||
run_fdtget_test "MyBoardName" $dtb / model
|
||||
run_fdtget_test "77 121 66 111 \
|
||||
97 114 100 78 97 109 101 0 77 121 66 111 97 114 100 70 97 109 105 \
|
||||
108 121 78 97 109 101 0" $dtb / compatible
|
||||
run_fdtget_test "MyBoardName MyBoardFamilyName" -t s $dtb / compatible
|
||||
run_fdtget_test 32768 $dtb /cpus/PowerPC,970@1 d-cache-size
|
||||
run_fdtget_test 8000 -tx $dtb /cpus/PowerPC,970@1 d-cache-size
|
||||
run_fdtget_test "61 62 63 0" -tbx $dtb /randomnode tricky1
|
||||
run_fdtget_test "a b c d de ea ad be ef" -tbx $dtb /randomnode blob
|
||||
|
||||
# Here the property size is not a multiple of 4 bytes, so it should fail
|
||||
run_wrap_error_test $DTGET -tlx $dtb /randomnode mixed
|
||||
run_fdtget_test "6162 6300 1234 0 a 0 b 0 c" -thx $dtb /randomnode mixed
|
||||
run_fdtget_test "61 62 63 0 12 34 0 0 0 a 0 0 0 b 0 0 0 c" \
|
||||
-thhx $dtb /randomnode mixed
|
||||
run_wrap_error_test $DTGET -ts $dtb /randomnode doctor-who
|
||||
|
||||
# Test multiple arguments
|
||||
run_fdtget_test "MyBoardName\nmemory" -ts $dtb / model /memory device_type
|
||||
|
||||
# Test defaults
|
||||
run_wrap_error_test $DTGET -tx $dtb /randomnode doctor-who
|
||||
run_fdtget_test "<the dead silence>" -tx \
|
||||
-d "<the dead silence>" $dtb /randomnode doctor-who
|
||||
run_fdtget_test "<blink>" -tx -d "<blink>" $dtb /memory doctor-who
|
||||
}
|
||||
|
||||
fdtput_tests () {
|
||||
dts=label01.dts
|
||||
dtb=$dts.fdtput.test.dtb
|
||||
text=lorem.txt
|
||||
|
||||
# Allow just enough space for $text
|
||||
run_dtc_test -O dtb -p $(stat -c %s $text) -o $dtb $dts
|
||||
|
||||
# run_fdtput_test <expected-result> <file> <node> <property> <flags> <value>
|
||||
run_fdtput_test "a_model" $dtb / model -ts "a_model"
|
||||
run_fdtput_test "board1 board2" $dtb / compatible -ts board1 board2
|
||||
run_fdtput_test "board1 board2" $dtb / compatible -ts "board1 board2"
|
||||
run_fdtput_test "32768" $dtb /cpus/PowerPC,970@1 d-cache-size "" "32768"
|
||||
run_fdtput_test "8001" $dtb /cpus/PowerPC,970@1 d-cache-size -tx 0x8001
|
||||
run_fdtput_test "2 3 12" $dtb /randomnode tricky1 -tbi "02 003 12"
|
||||
run_fdtput_test "a b c ea ad be ef" $dtb /randomnode blob \
|
||||
-tbx "a b c ea ad be ef"
|
||||
run_fdtput_test "a0b0c0d deeaae ef000000" $dtb /randomnode blob \
|
||||
-tx "a0b0c0d deeaae ef000000"
|
||||
run_fdtput_test "$(cat $text)" $dtb /randomnode blob -ts "$(cat $text)"
|
||||
|
||||
# This should be larger than available space in the fdt
|
||||
run_wrap_error_test $DTPUT $dtb /randomnode blob -ts "$(cat $text $text)"
|
||||
|
||||
# Start again with a fresh dtb
|
||||
run_dtc_test -O dtb -p $(stat -c %s $text) -o $dtb $dts
|
||||
|
||||
# Node creation
|
||||
run_wrap_error_test $DTPUT $dtb -c /baldrick sod
|
||||
run_wrap_test $DTPUT $dtb -c /chosen/son /chosen/daughter
|
||||
run_fdtput_test "eva" $dtb /chosen/daughter name "" -ts "eva"
|
||||
run_fdtput_test "adam" $dtb /chosen/son name "" -ts "adam"
|
||||
|
||||
# Not allowed to create an existing node
|
||||
run_wrap_error_test $DTPUT $dtb -c /chosen
|
||||
run_wrap_error_test $DTPUT $dtb -c /chosen/son
|
||||
|
||||
# Automatic node creation
|
||||
run_wrap_test $DTPUT $dtb -cp /blackadder/the-second/turnip \
|
||||
/blackadder/the-second/potato
|
||||
run_fdtput_test 1000 $dtb /blackadder/the-second/turnip cost "" 1000
|
||||
run_fdtput_test "fine wine" $dtb /blackadder/the-second/potato drink \
|
||||
"-ts" "fine wine"
|
||||
run_wrap_test $DTPUT $dtb -p /you/are/drunk/sir/winston slurp -ts twice
|
||||
run_wrap_error_test $DTPUT $dtb -cp "$(cat $text $text)/longish"
|
||||
|
||||
# Allowed to create an existing node with -p
|
||||
run_wrap_test $DTPUT $dtb -cp /chosen
|
||||
run_wrap_test $DTPUT $dtb -cp /chosen/son
|
||||
|
||||
# TODO: Add tests for verbose mode?
|
||||
}
|
||||
|
||||
utilfdt_tests () {
|
||||
run_test utilfdt_test
|
||||
}
|
||||
|
||||
while getopts "vt:m" ARG ; do
|
||||
@ -331,7 +584,7 @@ while getopts "vt:m" ARG ; do
|
||||
done
|
||||
|
||||
if [ -z "$TESTSETS" ]; then
|
||||
TESTSETS="libfdt dtc"
|
||||
TESTSETS="libfdt utilfdt dtc dtbs_equal fdtget fdtput"
|
||||
fi
|
||||
|
||||
# Make sure we don't have stale blobs lying around
|
||||
@ -342,9 +595,21 @@ for set in $TESTSETS; do
|
||||
"libfdt")
|
||||
libfdt_tests
|
||||
;;
|
||||
"utilfdt")
|
||||
utilfdt_tests
|
||||
;;
|
||||
"dtc")
|
||||
dtc_tests
|
||||
;;
|
||||
"dtbs_equal")
|
||||
dtbs_equal_tests
|
||||
;;
|
||||
"fdtget")
|
||||
fdtget_tests
|
||||
;;
|
||||
"fdtput")
|
||||
fdtput_tests
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
|
@ -57,23 +57,14 @@ int main(int argc, char *argv[])
|
||||
fdt = xmalloc(SPACE);
|
||||
|
||||
/* First create empty tree with SW */
|
||||
CHECK(fdt_create(fdt, SPACE));
|
||||
|
||||
CHECK(fdt_finish_reservemap(fdt));
|
||||
CHECK(fdt_begin_node(fdt, ""));
|
||||
CHECK(fdt_end_node(fdt));
|
||||
CHECK(fdt_finish(fdt));
|
||||
|
||||
verbose_printf("Built empty tree, totalsize = %d\n",
|
||||
fdt_totalsize(fdt));
|
||||
|
||||
CHECK(fdt_open_into(fdt, fdt, SPACE));
|
||||
CHECK(fdt_create_empty_tree(fdt, SPACE));
|
||||
|
||||
CHECK(fdt_add_mem_rsv(fdt, TEST_ADDR_1, TEST_SIZE_1));
|
||||
CHECK(fdt_add_mem_rsv(fdt, TEST_ADDR_2, TEST_SIZE_2));
|
||||
|
||||
CHECK(fdt_setprop_string(fdt, 0, "compatible", "test_tree1"));
|
||||
CHECK(fdt_setprop_cell(fdt, 0, "prop-int", TEST_VALUE_1));
|
||||
CHECK(fdt_setprop_u32(fdt, 0, "prop-int", TEST_VALUE_1));
|
||||
CHECK(fdt_setprop_u64(fdt, 0, "prop-int64", TEST_VALUE64_1));
|
||||
CHECK(fdt_setprop_string(fdt, 0, "prop-str", TEST_STRING_1));
|
||||
|
||||
OFF_CHECK(offset, fdt_add_subnode(fdt, 0, "subnode@1"));
|
||||
|
@ -74,5 +74,23 @@ int main(int argc, char *argv[])
|
||||
|
||||
check_getprop(fdt, 0, "prop-str", 0, NULL);
|
||||
|
||||
err = fdt_setprop_u32(fdt, 0, "prop-u32", TEST_VALUE_2);
|
||||
if (err)
|
||||
FAIL("Failed to set \"prop-u32\" to 0x%08x: %s",
|
||||
TEST_VALUE_2, fdt_strerror(err));
|
||||
check_getprop_cell(fdt, 0, "prop-u32", TEST_VALUE_2);
|
||||
|
||||
err = fdt_setprop_cell(fdt, 0, "prop-cell", TEST_VALUE_2);
|
||||
if (err)
|
||||
FAIL("Failed to set \"prop-cell\" to 0x%08x: %s",
|
||||
TEST_VALUE_2, fdt_strerror(err));
|
||||
check_getprop_cell(fdt, 0, "prop-cell", TEST_VALUE_2);
|
||||
|
||||
err = fdt_setprop_u64(fdt, 0, "prop-u64", TEST_VALUE64_1);
|
||||
if (err)
|
||||
FAIL("Failed to set \"prop-u64\" to 0x%016llx: %s",
|
||||
TEST_VALUE64_1, fdt_strerror(err));
|
||||
check_getprop_64(fdt, 0, "prop-u64", TEST_VALUE64_1);
|
||||
|
||||
PASS();
|
||||
}
|
||||
|
@ -18,6 +18,7 @@
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@ -34,6 +35,7 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
void *fdt;
|
||||
const uint32_t *intp;
|
||||
const uint64_t *int64p;
|
||||
const char *strp;
|
||||
char *xstr;
|
||||
int xlen, i;
|
||||
@ -47,11 +49,25 @@ int main(int argc, char *argv[])
|
||||
verbose_printf("Old int value was 0x%08x\n", *intp);
|
||||
err = fdt_setprop_inplace_cell(fdt, 0, "prop-int", ~TEST_VALUE_1);
|
||||
if (err)
|
||||
FAIL("Failed to set \"prop-int\" to 0x08%x: %s",
|
||||
FAIL("Failed to set \"prop-int\" to 0x%08x: %s",
|
||||
~TEST_VALUE_1, fdt_strerror(err));
|
||||
intp = check_getprop_cell(fdt, 0, "prop-int", ~TEST_VALUE_1);
|
||||
verbose_printf("New int value is 0x%08x\n", *intp);
|
||||
|
||||
strp = check_getprop(fdt, 0, "prop-str", strlen(TEST_STRING_1)+1,
|
||||
TEST_STRING_1);
|
||||
|
||||
|
||||
int64p = check_getprop_64(fdt, 0, "prop-int64", TEST_VALUE64_1);
|
||||
|
||||
verbose_printf("Old int64 value was 0x%016" PRIx64 "\n", *int64p);
|
||||
err = fdt_setprop_inplace_u64(fdt, 0, "prop-int64", ~TEST_VALUE64_1);
|
||||
if (err)
|
||||
FAIL("Failed to set \"prop-int64\" to 0x%016llx: %s",
|
||||
~TEST_VALUE64_1, fdt_strerror(err));
|
||||
int64p = check_getprop_64(fdt, 0, "prop-int64", ~TEST_VALUE64_1);
|
||||
verbose_printf("New int64 value is 0x%016" PRIx64 "\n", *int64p);
|
||||
|
||||
strp = check_getprop(fdt, 0, "prop-str", strlen(TEST_STRING_1)+1,
|
||||
TEST_STRING_1);
|
||||
|
||||
|
@ -60,7 +60,7 @@ int main(int argc, char *argv[])
|
||||
void *fdt;
|
||||
int subnode1_offset, subnode2_offset;
|
||||
int subsubnode1_offset, subsubnode2_offset, subsubnode2_offset2;
|
||||
int ss11_off, ss12_off, ss21_off, ss22_off;
|
||||
int ss12_off, ss21_off;
|
||||
|
||||
test_init(argc, argv);
|
||||
fdt = load_blob_arg(argc, argv);
|
||||
@ -85,7 +85,7 @@ int main(int argc, char *argv[])
|
||||
if (subsubnode2_offset != subsubnode2_offset2)
|
||||
FAIL("Different offsets with and without unit address");
|
||||
|
||||
ss11_off = check_subnode(fdt, subnode1_offset, "ss1");
|
||||
check_subnode(fdt, subnode1_offset, "ss1");
|
||||
ss21_off = fdt_subnode_offset(fdt, subnode2_offset, "ss1");
|
||||
if (ss21_off != -FDT_ERR_NOTFOUND)
|
||||
FAIL("Incorrectly found ss1 in subnode2");
|
||||
@ -93,7 +93,7 @@ int main(int argc, char *argv[])
|
||||
ss12_off = fdt_subnode_offset(fdt, subnode1_offset, "ss2");
|
||||
if (ss12_off != -FDT_ERR_NOTFOUND)
|
||||
FAIL("Incorrectly found ss2 in subnode1");
|
||||
ss22_off = check_subnode(fdt, subnode2_offset, "ss2");
|
||||
check_subnode(fdt, subnode2_offset, "ss2");
|
||||
|
||||
PASS();
|
||||
}
|
||||
|
@ -55,7 +55,8 @@ int main(int argc, char *argv[])
|
||||
|
||||
CHECK(fdt_begin_node(fdt, ""));
|
||||
CHECK(fdt_property_string(fdt, "compatible", "test_tree1"));
|
||||
CHECK(fdt_property_cell(fdt, "prop-int", TEST_VALUE_1));
|
||||
CHECK(fdt_property_u32(fdt, "prop-int", TEST_VALUE_1));
|
||||
CHECK(fdt_property_u64(fdt, "prop-int64", TEST_VALUE64_1));
|
||||
CHECK(fdt_property_string(fdt, "prop-str", TEST_STRING_1));
|
||||
|
||||
CHECK(fdt_begin_node(fdt, "subnode@1"));
|
||||
|
@ -6,6 +6,7 @@
|
||||
/ {
|
||||
compatible = "test_tree1";
|
||||
prop-int = <0xdeadbeef>;
|
||||
prop-int64 = /bits/ 64 <0xdeadbeef01abcdef>;
|
||||
prop-str = "hello world";
|
||||
|
||||
subnode@1 {
|
||||
@ -25,7 +26,7 @@
|
||||
linux,phandle = <0x2000>;
|
||||
prop-int = <123456789>;
|
||||
|
||||
subsubnode@0 {
|
||||
ssn0: subsubnode@0 {
|
||||
phandle = <0x2001>;
|
||||
compatible = "subsubnode2", "subsubnode";
|
||||
prop-int = <0726746425>;
|
||||
|
@ -12,6 +12,8 @@
|
||||
#define TEST_VALUE_1 0xdeadbeef
|
||||
#define TEST_VALUE_2 123456789
|
||||
|
||||
#define TEST_VALUE64_1 ASM_CONST_LL(0xdeadbeef01abcdef)
|
||||
|
||||
#define PHANDLE_1 0x2000
|
||||
#define PHANDLE_2 0x2001
|
||||
|
||||
@ -19,6 +21,12 @@
|
||||
#define TEST_STRING_2 "nastystring: \a\b\t\n\v\f\r\\\""
|
||||
#define TEST_STRING_3 "\xde\xad\xbe\xef"
|
||||
|
||||
#define TEST_CHAR1 '\r'
|
||||
#define TEST_CHAR2 'b'
|
||||
#define TEST_CHAR3 '\0'
|
||||
#define TEST_CHAR4 '\''
|
||||
#define TEST_CHAR5 '\xff'
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
extern struct fdt_header _test_tree1;
|
||||
extern struct fdt_header _truncated_property;
|
||||
|
@ -93,22 +93,6 @@ void cleanup(void);
|
||||
exit(RC_BUG); \
|
||||
} while (0)
|
||||
|
||||
static inline void *xmalloc(size_t size)
|
||||
{
|
||||
void *p = malloc(size);
|
||||
if (! p)
|
||||
FAIL("malloc() failure");
|
||||
return p;
|
||||
}
|
||||
|
||||
static inline void *xrealloc(void *p, size_t size)
|
||||
{
|
||||
p = realloc(p, size);
|
||||
if (! p)
|
||||
FAIL("realloc() failure");
|
||||
return p;
|
||||
}
|
||||
|
||||
void check_mem_rsv(void *fdt, int n, uint64_t addr, uint64_t size);
|
||||
|
||||
void check_property(void *fdt, int nodeoffset, const char *name,
|
||||
@ -127,6 +111,11 @@ const void *check_getprop(void *fdt, int nodeoffset, const char *name,
|
||||
uint32_t x = cpu_to_fdt32(val); \
|
||||
check_getprop(fdt, nodeoffset, name, sizeof(x), &x); \
|
||||
})
|
||||
#define check_getprop_64(fdt, nodeoffset, name, val) \
|
||||
({ \
|
||||
uint64_t x = cpu_to_fdt64(val); \
|
||||
check_getprop(fdt, nodeoffset, name, sizeof(x), &x); \
|
||||
})
|
||||
#define check_getprop_string(fdt, nodeoffset, name, s) \
|
||||
check_getprop((fdt), (nodeoffset), (name), strlen(s)+1, (s))
|
||||
int nodename_eq(const char *s1, const char *s2);
|
||||
@ -135,4 +124,6 @@ void *load_blob_arg(int argc, char *argv[]);
|
||||
void save_blob(const char *filename, void *blob);
|
||||
void *open_blob_rw(void *blob);
|
||||
|
||||
#include "util.h"
|
||||
|
||||
#endif /* _TESTS_H */
|
||||
|
@ -10,7 +10,17 @@ FAIL () {
|
||||
exit 2
|
||||
}
|
||||
|
||||
FAIL_IF_SIGNAL () {
|
||||
ret="$1"
|
||||
if [ "$ret" -gt 127 ]; then
|
||||
signame=$(kill -l $((ret - 128)))
|
||||
FAIL "Killed by SIG$signame"
|
||||
fi
|
||||
}
|
||||
|
||||
DTC=../dtc
|
||||
DTGET=../fdtget
|
||||
DTPUT=../fdtput
|
||||
|
||||
verbose_run () {
|
||||
if [ -z "$QUIET_TEST" ]; then
|
||||
@ -20,6 +30,15 @@ verbose_run () {
|
||||
fi
|
||||
}
|
||||
|
||||
verbose_run_check () {
|
||||
verbose_run "$@"
|
||||
ret="$?"
|
||||
FAIL_IF_SIGNAL $ret
|
||||
if [ $ret != 0 ]; then
|
||||
FAIL "Returned error code $ret"
|
||||
fi
|
||||
}
|
||||
|
||||
verbose_run_log () {
|
||||
LOG="$1"
|
||||
shift
|
||||
@ -30,3 +49,13 @@ verbose_run_log () {
|
||||
fi
|
||||
return $ret
|
||||
}
|
||||
|
||||
verbose_run_log_check () {
|
||||
verbose_run_log "$@"
|
||||
ret="$?"
|
||||
FAIL_IF_SIGNAL $ret
|
||||
if [ $ret != 0 ]; then
|
||||
FAIL "Returned error code $ret"
|
||||
fi
|
||||
}
|
||||
|
||||
|
@ -159,33 +159,13 @@ int nodename_eq(const char *s1, const char *s2)
|
||||
|
||||
void *load_blob(const char *filename)
|
||||
{
|
||||
int fd;
|
||||
int offset = 0;
|
||||
int bufsize = 1024;
|
||||
char *p = NULL;
|
||||
int ret;
|
||||
char *blob;
|
||||
int ret = utilfdt_read_err(filename, &blob);
|
||||
|
||||
fd = open(filename, O_RDONLY);
|
||||
if (fd < 0)
|
||||
if (ret)
|
||||
CONFIG("Couldn't open blob from \"%s\": %s", filename,
|
||||
strerror(errno));
|
||||
|
||||
p = xmalloc(bufsize);
|
||||
do {
|
||||
if (offset == bufsize) {
|
||||
bufsize *= 2;
|
||||
p = xrealloc(p, bufsize);
|
||||
}
|
||||
|
||||
ret = read(fd, &p[offset], bufsize - offset);
|
||||
if (ret < 0)
|
||||
CONFIG("Couldn't read from \"%s\": %s", filename,
|
||||
strerror(errno));
|
||||
|
||||
offset += ret;
|
||||
} while (ret != 0);
|
||||
|
||||
return p;
|
||||
strerror(ret));
|
||||
return blob;
|
||||
}
|
||||
|
||||
void *load_blob_arg(int argc, char *argv[])
|
||||
@ -197,28 +177,11 @@ void *load_blob_arg(int argc, char *argv[])
|
||||
|
||||
void save_blob(const char *filename, void *fdt)
|
||||
{
|
||||
int fd;
|
||||
int totalsize;
|
||||
int offset;
|
||||
char *p;
|
||||
int ret;
|
||||
int ret = utilfdt_write_err(filename, fdt);
|
||||
|
||||
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
|
||||
if (fd < 0)
|
||||
CONFIG("Couldn't open \"%s\" to write blob: %s", filename,
|
||||
strerror(errno));
|
||||
|
||||
totalsize = fdt_totalsize(fdt);
|
||||
offset = 0;
|
||||
p = fdt;
|
||||
|
||||
while (offset < totalsize) {
|
||||
ret = write(fd, p + offset, totalsize - offset);
|
||||
if (ret < 0)
|
||||
CONFIG("Couldn't write to \"%s\": %s", filename,
|
||||
strerror(errno));
|
||||
offset += ret;
|
||||
}
|
||||
if (ret)
|
||||
CONFIG("Couldn't write blob to \"%s\": %s", filename,
|
||||
strerror(ret));
|
||||
}
|
||||
|
||||
void *open_blob_rw(void *blob)
|
||||
|
@ -52,6 +52,10 @@ tree##_rsvmap_end: ;
|
||||
PROPHDR(tree, name, 4) \
|
||||
FDTLONG(val) ;
|
||||
|
||||
#define PROP_INT64(tree, name, val) \
|
||||
PROPHDR(tree, name, 8) \
|
||||
FDTQUAD(val) ;
|
||||
|
||||
#define PROP_STR(tree, name, str) \
|
||||
PROPHDR(tree, name, 55f - 54f) \
|
||||
54: \
|
||||
@ -86,6 +90,7 @@ test_tree1_struct:
|
||||
BEGIN_NODE("")
|
||||
PROP_STR(test_tree1, compatible, "test_tree1")
|
||||
PROP_INT(test_tree1, prop_int, TEST_VALUE_1)
|
||||
PROP_INT64(test_tree1, prop_int64, TEST_VALUE64_1)
|
||||
PROP_STR(test_tree1, prop_str, TEST_STRING_1)
|
||||
|
||||
BEGIN_NODE("subnode@1")
|
||||
@ -124,6 +129,7 @@ test_tree1_struct_end:
|
||||
test_tree1_strings:
|
||||
STRING(test_tree1, compatible, "compatible")
|
||||
STRING(test_tree1, prop_int, "prop-int")
|
||||
STRING(test_tree1, prop_int64, "prop-int64")
|
||||
STRING(test_tree1, prop_str, "prop-str")
|
||||
STRING(test_tree1, linux_phandle, "linux,phandle")
|
||||
STRING(test_tree1, phandle, "phandle")
|
||||
|
@ -59,8 +59,8 @@ struct val_label labels3[] = {
|
||||
{ "end3", -1 },
|
||||
};
|
||||
|
||||
void check_prop_labels(void *sohandle, void *fdt, const char *name,
|
||||
const struct val_label* labels, int n)
|
||||
static void check_prop_labels(void *sohandle, void *fdt, const char *name,
|
||||
const struct val_label* labels, int n)
|
||||
{
|
||||
const struct fdt_property *prop;
|
||||
const char *p;
|
||||
|
21
treesource.c
21
treesource.c
@ -23,6 +23,7 @@
|
||||
|
||||
extern FILE *yyin;
|
||||
extern int yyparse(void);
|
||||
extern YYLTYPE yylloc;
|
||||
|
||||
struct boot_info *the_boot_info;
|
||||
int treesource_error;
|
||||
@ -32,8 +33,9 @@ struct boot_info *dt_from_source(const char *fname)
|
||||
the_boot_info = NULL;
|
||||
treesource_error = 0;
|
||||
|
||||
srcpos_file = dtc_open_file(fname, NULL);
|
||||
yyin = srcpos_file->file;
|
||||
srcfile_push(fname);
|
||||
yyin = current_srcfile->f;
|
||||
yylloc.file = current_srcfile;
|
||||
|
||||
if (yyparse() != 0)
|
||||
die("Unable to parse input tree\n");
|
||||
@ -235,10 +237,11 @@ static void write_tree_source_node(FILE *f, struct node *tree, int level)
|
||||
{
|
||||
struct property *prop;
|
||||
struct node *child;
|
||||
struct label *l;
|
||||
|
||||
write_prefix(f, level);
|
||||
if (tree->label)
|
||||
fprintf(f, "%s: ", tree->label);
|
||||
for_each_label(tree->labels, l)
|
||||
fprintf(f, "%s: ", l->label);
|
||||
if (tree->name && (*tree->name))
|
||||
fprintf(f, "%s {\n", tree->name);
|
||||
else
|
||||
@ -246,8 +249,8 @@ static void write_tree_source_node(FILE *f, struct node *tree, int level)
|
||||
|
||||
for_each_property(tree, prop) {
|
||||
write_prefix(f, level+1);
|
||||
if (prop->label)
|
||||
fprintf(f, "%s: ", prop->label);
|
||||
for_each_label(prop->labels, l)
|
||||
fprintf(f, "%s: ", l->label);
|
||||
fprintf(f, "%s", prop->name);
|
||||
write_propval(f, prop);
|
||||
}
|
||||
@ -267,8 +270,10 @@ void dt_to_source(FILE *f, struct boot_info *bi)
|
||||
fprintf(f, "/dts-v1/;\n\n");
|
||||
|
||||
for (re = bi->reservelist; re; re = re->next) {
|
||||
if (re->label)
|
||||
fprintf(f, "%s: ", re->label);
|
||||
struct label *l;
|
||||
|
||||
for_each_label(re->labels, l)
|
||||
fprintf(f, "%s: ", l->label);
|
||||
fprintf(f, "/memreserve/\t0x%016llx 0x%016llx;\n",
|
||||
(unsigned long long)re->re.address,
|
||||
(unsigned long long)re->re.size);
|
||||
|
303
util.c
303
util.c
@ -1,6 +1,10 @@
|
||||
/*
|
||||
* Copyright 2011 The Chromium Authors, All Rights Reserved.
|
||||
* Copyright 2008 Jon Loeliger, Freescale Semiconductor, Inc.
|
||||
*
|
||||
* util_is_printable_string contributed by
|
||||
* Pantelis Antoniou <pantelis.antoniou AT gmail.com>
|
||||
*
|
||||
* 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 2 of the
|
||||
@ -17,7 +21,19 @@
|
||||
* USA
|
||||
*/
|
||||
|
||||
#include "dtc.h"
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "libfdt.h"
|
||||
#include "util.h"
|
||||
|
||||
char *xstrdup(const char *s)
|
||||
{
|
||||
@ -28,3 +44,288 @@ char *xstrdup(const char *s)
|
||||
|
||||
return dup;
|
||||
}
|
||||
|
||||
char *join_path(const char *path, const char *name)
|
||||
{
|
||||
int lenp = strlen(path);
|
||||
int lenn = strlen(name);
|
||||
int len;
|
||||
int needslash = 1;
|
||||
char *str;
|
||||
|
||||
len = lenp + lenn + 2;
|
||||
if ((lenp > 0) && (path[lenp-1] == '/')) {
|
||||
needslash = 0;
|
||||
len--;
|
||||
}
|
||||
|
||||
str = xmalloc(len);
|
||||
memcpy(str, path, lenp);
|
||||
if (needslash) {
|
||||
str[lenp] = '/';
|
||||
lenp++;
|
||||
}
|
||||
memcpy(str+lenp, name, lenn+1);
|
||||
return str;
|
||||
}
|
||||
|
||||
int util_is_printable_string(const void *data, int len)
|
||||
{
|
||||
const char *s = data;
|
||||
const char *ss;
|
||||
|
||||
/* zero length is not */
|
||||
if (len == 0)
|
||||
return 0;
|
||||
|
||||
/* must terminate with zero */
|
||||
if (s[len - 1] != '\0')
|
||||
return 0;
|
||||
|
||||
ss = s;
|
||||
while (*s && isprint(*s))
|
||||
s++;
|
||||
|
||||
/* not zero, or not done yet */
|
||||
if (*s != '\0' || (s + 1 - ss) < len)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse a octal encoded character starting at index i in string s. The
|
||||
* resulting character will be returned and the index i will be updated to
|
||||
* point at the character directly after the end of the encoding, this may be
|
||||
* the '\0' terminator of the string.
|
||||
*/
|
||||
static char get_oct_char(const char *s, int *i)
|
||||
{
|
||||
char x[4];
|
||||
char *endx;
|
||||
long val;
|
||||
|
||||
x[3] = '\0';
|
||||
strncpy(x, s + *i, 3);
|
||||
|
||||
val = strtol(x, &endx, 8);
|
||||
|
||||
assert(endx > x);
|
||||
|
||||
(*i) += endx - x;
|
||||
return val;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse a hexadecimal encoded character starting at index i in string s. The
|
||||
* resulting character will be returned and the index i will be updated to
|
||||
* point at the character directly after the end of the encoding, this may be
|
||||
* the '\0' terminator of the string.
|
||||
*/
|
||||
static char get_hex_char(const char *s, int *i)
|
||||
{
|
||||
char x[3];
|
||||
char *endx;
|
||||
long val;
|
||||
|
||||
x[2] = '\0';
|
||||
strncpy(x, s + *i, 2);
|
||||
|
||||
val = strtol(x, &endx, 16);
|
||||
if (!(endx > x))
|
||||
die("\\x used with no following hex digits\n");
|
||||
|
||||
(*i) += endx - x;
|
||||
return val;
|
||||
}
|
||||
|
||||
char get_escape_char(const char *s, int *i)
|
||||
{
|
||||
char c = s[*i];
|
||||
int j = *i + 1;
|
||||
char val;
|
||||
|
||||
assert(c);
|
||||
switch (c) {
|
||||
case 'a':
|
||||
val = '\a';
|
||||
break;
|
||||
case 'b':
|
||||
val = '\b';
|
||||
break;
|
||||
case 't':
|
||||
val = '\t';
|
||||
break;
|
||||
case 'n':
|
||||
val = '\n';
|
||||
break;
|
||||
case 'v':
|
||||
val = '\v';
|
||||
break;
|
||||
case 'f':
|
||||
val = '\f';
|
||||
break;
|
||||
case 'r':
|
||||
val = '\r';
|
||||
break;
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
j--; /* need to re-read the first digit as
|
||||
* part of the octal value */
|
||||
val = get_oct_char(s, &j);
|
||||
break;
|
||||
case 'x':
|
||||
val = get_hex_char(s, &j);
|
||||
break;
|
||||
default:
|
||||
val = c;
|
||||
}
|
||||
|
||||
(*i) = j;
|
||||
return val;
|
||||
}
|
||||
|
||||
int utilfdt_read_err(const char *filename, char **buffp)
|
||||
{
|
||||
int fd = 0; /* assume stdin */
|
||||
char *buf = NULL;
|
||||
off_t bufsize = 1024, offset = 0;
|
||||
int ret = 0;
|
||||
|
||||
*buffp = NULL;
|
||||
if (strcmp(filename, "-") != 0) {
|
||||
fd = open(filename, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return errno;
|
||||
}
|
||||
|
||||
/* Loop until we have read everything */
|
||||
buf = malloc(bufsize);
|
||||
do {
|
||||
/* Expand the buffer to hold the next chunk */
|
||||
if (offset == bufsize) {
|
||||
bufsize *= 2;
|
||||
buf = realloc(buf, bufsize);
|
||||
if (!buf) {
|
||||
ret = ENOMEM;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ret = read(fd, &buf[offset], bufsize - offset);
|
||||
if (ret < 0) {
|
||||
ret = errno;
|
||||
break;
|
||||
}
|
||||
offset += ret;
|
||||
} while (ret != 0);
|
||||
|
||||
/* Clean up, including closing stdin; return errno on error */
|
||||
close(fd);
|
||||
if (ret)
|
||||
free(buf);
|
||||
else
|
||||
*buffp = buf;
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *utilfdt_read(const char *filename)
|
||||
{
|
||||
char *buff;
|
||||
int ret = utilfdt_read_err(filename, &buff);
|
||||
|
||||
if (ret) {
|
||||
fprintf(stderr, "Couldn't open blob from '%s': %s\n", filename,
|
||||
strerror(ret));
|
||||
return NULL;
|
||||
}
|
||||
/* Successful read */
|
||||
return buff;
|
||||
}
|
||||
|
||||
int utilfdt_write_err(const char *filename, const void *blob)
|
||||
{
|
||||
int fd = 1; /* assume stdout */
|
||||
int totalsize;
|
||||
int offset;
|
||||
int ret = 0;
|
||||
const char *ptr = blob;
|
||||
|
||||
if (strcmp(filename, "-") != 0) {
|
||||
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
|
||||
if (fd < 0)
|
||||
return errno;
|
||||
}
|
||||
|
||||
totalsize = fdt_totalsize(blob);
|
||||
offset = 0;
|
||||
|
||||
while (offset < totalsize) {
|
||||
ret = write(fd, ptr + offset, totalsize - offset);
|
||||
if (ret < 0) {
|
||||
ret = -errno;
|
||||
break;
|
||||
}
|
||||
offset += ret;
|
||||
}
|
||||
/* Close the file/stdin; return errno on error */
|
||||
if (fd != 1)
|
||||
close(fd);
|
||||
return ret < 0 ? -ret : 0;
|
||||
}
|
||||
|
||||
|
||||
int utilfdt_write(const char *filename, const void *blob)
|
||||
{
|
||||
int ret = utilfdt_write_err(filename, blob);
|
||||
|
||||
if (ret) {
|
||||
fprintf(stderr, "Couldn't write blob to '%s': %s\n", filename,
|
||||
strerror(ret));
|
||||
}
|
||||
return ret ? -1 : 0;
|
||||
}
|
||||
|
||||
int utilfdt_decode_type(const char *fmt, int *type, int *size)
|
||||
{
|
||||
int qualifier = 0;
|
||||
|
||||
if (!*fmt)
|
||||
return -1;
|
||||
|
||||
/* get the conversion qualifier */
|
||||
*size = -1;
|
||||
if (strchr("hlLb", *fmt)) {
|
||||
qualifier = *fmt++;
|
||||
if (qualifier == *fmt) {
|
||||
switch (*fmt++) {
|
||||
/* TODO: case 'l': qualifier = 'L'; break;*/
|
||||
case 'h':
|
||||
qualifier = 'b';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* we should now have a type */
|
||||
if ((*fmt == '\0') || !strchr("iuxs", *fmt))
|
||||
return -1;
|
||||
|
||||
/* convert qualifier (bhL) to byte size */
|
||||
if (*fmt != 's')
|
||||
*size = qualifier == 'b' ? 1 :
|
||||
qualifier == 'h' ? 2 :
|
||||
qualifier == 'l' ? 4 : -1;
|
||||
*type = *fmt++;
|
||||
|
||||
/* that should be it! */
|
||||
if (*fmt)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
98
util.h
98
util.h
@ -1,7 +1,10 @@
|
||||
#ifndef _UTIL_H
|
||||
#define _UTIL_H
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
/*
|
||||
* Copyright 2011 The Chromium Authors, All Rights Reserved.
|
||||
* Copyright 2008 Jon Loeliger, Freescale Semiconductor, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
@ -51,5 +54,100 @@ static inline void *xrealloc(void *p, size_t len)
|
||||
}
|
||||
|
||||
extern char *xstrdup(const char *s);
|
||||
extern char *join_path(const char *path, const char *name);
|
||||
|
||||
/**
|
||||
* Check a string of a given length to see if it is all printable and
|
||||
* has a valid terminator.
|
||||
*
|
||||
* @param data The string to check
|
||||
* @param len The string length including terminator
|
||||
* @return 1 if a valid printable string, 0 if not */
|
||||
int util_is_printable_string(const void *data, int len);
|
||||
|
||||
/*
|
||||
* Parse an escaped character starting at index i in string s. The resulting
|
||||
* character will be returned and the index i will be updated to point at the
|
||||
* character directly after the end of the encoding, this may be the '\0'
|
||||
* terminator of the string.
|
||||
*/
|
||||
char get_escape_char(const char *s, int *i);
|
||||
|
||||
/**
|
||||
* Read a device tree file into a buffer. This will report any errors on
|
||||
* stderr.
|
||||
*
|
||||
* @param filename The filename to read, or - for stdin
|
||||
* @return Pointer to allocated buffer containing fdt, or NULL on error
|
||||
*/
|
||||
char *utilfdt_read(const char *filename);
|
||||
|
||||
/**
|
||||
* Read a device tree file into a buffer. Does not report errors, but only
|
||||
* returns them. The value returned can be passed to strerror() to obtain
|
||||
* an error message for the user.
|
||||
*
|
||||
* @param filename The filename to read, or - for stdin
|
||||
* @param buffp Returns pointer to buffer containing fdt
|
||||
* @return 0 if ok, else an errno value representing the error
|
||||
*/
|
||||
int utilfdt_read_err(const char *filename, char **buffp);
|
||||
|
||||
|
||||
/**
|
||||
* Write a device tree buffer to a file. This will report any errors on
|
||||
* stderr.
|
||||
*
|
||||
* @param filename The filename to write, or - for stdout
|
||||
* @param blob Poiner to buffer containing fdt
|
||||
* @return 0 if ok, -1 on error
|
||||
*/
|
||||
int utilfdt_write(const char *filename, const void *blob);
|
||||
|
||||
/**
|
||||
* Write a device tree buffer to a file. Does not report errors, but only
|
||||
* returns them. The value returned can be passed to strerror() to obtain
|
||||
* an error message for the user.
|
||||
*
|
||||
* @param filename The filename to write, or - for stdout
|
||||
* @param blob Poiner to buffer containing fdt
|
||||
* @return 0 if ok, else an errno value representing the error
|
||||
*/
|
||||
int utilfdt_write_err(const char *filename, const void *blob);
|
||||
|
||||
/**
|
||||
* Decode a data type string. The purpose of this string
|
||||
*
|
||||
* The string consists of an optional character followed by the type:
|
||||
* Modifier characters:
|
||||
* hh or b 1 byte
|
||||
* h 2 byte
|
||||
* l 4 byte, default
|
||||
*
|
||||
* Type character:
|
||||
* s string
|
||||
* i signed integer
|
||||
* u unsigned integer
|
||||
* x hex
|
||||
*
|
||||
* TODO: Implement ll modifier (8 bytes)
|
||||
* TODO: Implement o type (octal)
|
||||
*
|
||||
* @param fmt Format string to process
|
||||
* @param type Returns type found(s/d/u/x), or 0 if none
|
||||
* @param size Returns size found(1,2,4,8) or 4 if none
|
||||
* @return 0 if ok, -1 on error (no type given, or other invalid format)
|
||||
*/
|
||||
int utilfdt_decode_type(const char *fmt, int *type, int *size);
|
||||
|
||||
/*
|
||||
* This is a usage message fragment for the -t option. It is the format
|
||||
* supported by utilfdt_decode_type.
|
||||
*/
|
||||
|
||||
#define USAGE_TYPE_MSG \
|
||||
"<type>\ts=string, i=int, u=unsigned, x=hex\n" \
|
||||
"\tOptional modifier prefix:\n" \
|
||||
"\t\thh or b=byte, h=2 byte, l=4 byte (default)\n";
|
||||
|
||||
#endif /* _UTIL_H */
|
||||
|
Loading…
Reference in New Issue
Block a user