Update to latest git version of dtc to get new dtsv2 support,
including the include directive. Fix minor build issue corrected by converting yypush_buffer_state and yypop_buffer_state to yy_set_buffer_state and a hard-coded 100-deep stack. It was easier to fix it here than to import that support into our flex. The new tools and test hardness remain unsupported at the moment.
This commit is contained in:
commit
52baf267be
@ -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>
|
||||
|
@ -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 $@
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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,12 +39,16 @@ LINECOMMENT "//".*\n
|
||||
#include "srcpos.h"
|
||||
#include "dtc-parser.tab.h"
|
||||
|
||||
#define MAX_INCLUDE_NESTING 100
|
||||
YY_BUFFER_STATE include_stack[MAX_INCLUDE_NESTING];
|
||||
int include_stack_pointer = 0;
|
||||
|
||||
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*/
|
||||
@ -96,6 +101,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);
|
||||
@ -103,19 +114,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);
|
||||
@ -150,6 +168,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]);
|
||||
@ -167,100 +194,34 @@ 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");
|
||||
assert(include_stack_pointer >= MAX_INCLUDE_NESTING);
|
||||
|
||||
if (srcpos_file) {
|
||||
search.dir = srcpos_file->dir;
|
||||
search.next = NULL;
|
||||
search.prev = NULL;
|
||||
searchptr = &search;
|
||||
}
|
||||
srcfile_push(filename);
|
||||
|
||||
newfile = dtc_open_file(filename, searchptr);
|
||||
yyin = current_srcfile->f;
|
||||
|
||||
incl_file = xmalloc(sizeof(struct incl_file));
|
||||
include_stack[include_stack_pointer++] = YY_CURRENT_BUFFER;
|
||||
|
||||
/*
|
||||
* 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));
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
assert(include_stack_pointer > 0);
|
||||
|
||||
/*
|
||||
* Pop.
|
||||
*/
|
||||
--incl_depth;
|
||||
incl_file = incl_file_stack;
|
||||
incl_file_stack = incl_file->prev;
|
||||
yy_delete_buffer( YY_CURRENT_BUFFER );
|
||||
|
||||
/*
|
||||
* 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;
|
||||
yy_switch_to_buffer( include_stack[--include_stack_pointer] );
|
||||
|
||||
/*
|
||||
* Free old state.
|
||||
*/
|
||||
free(incl_file);
|
||||
yyin = current_srcfile->f;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -18,7 +18,6 @@
|
||||
* USA
|
||||
*/
|
||||
|
||||
|
||||
%{
|
||||
#include <stdio.h>
|
||||
|
||||
@ -28,12 +27,14 @@
|
||||
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 {
|
||||
@ -44,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
|
||||
@ -68,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
|
||||
@ -79,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));
|
||||
}
|
||||
;
|
||||
|
||||
@ -102,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;
|
||||
}
|
||||
;
|
||||
|
||||
@ -141,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;
|
||||
}
|
||||
;
|
||||
|
||||
@ -156,9 +194,9 @@ propdata:
|
||||
{
|
||||
$$ = data_merge($1, $2);
|
||||
}
|
||||
| propdataprefix '<' celllist '>'
|
||||
| propdataprefix arrayprefix '>'
|
||||
{
|
||||
$$ = data_merge($1, $3);
|
||||
$$ = data_merge($1, $2.data);
|
||||
}
|
||||
| propdataprefix '[' bytestring ']'
|
||||
{
|
||||
@ -168,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
|
||||
{
|
||||
@ -219,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:
|
||||
@ -266,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;
|
||||
@ -310,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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
38
contrib/dtc/dtdiff
Normal file
38
contrib/dtc/dtdiff
Normal file
@ -0,0 +1,38 @@
|
||||
#! /bin/bash
|
||||
|
||||
# This script uses the bash <(...) extension.
|
||||
# If you want to change this to work with a generic /bin/sh, make sure
|
||||
# you fix that.
|
||||
|
||||
|
||||
DTC=dtc
|
||||
|
||||
source_and_sort () {
|
||||
DT="$1"
|
||||
if [ -d "$DT" ]; then
|
||||
IFORMAT=fs
|
||||
elif [ -f "$DT" ]; then
|
||||
case "$DT" in
|
||||
*.dts)
|
||||
IFORMAT=dts
|
||||
;;
|
||||
*.dtb)
|
||||
IFORMAT=dtb
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if [ -z "$IFORMAT" ]; then
|
||||
echo "Unrecognized format for $DT" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
$DTC -I $IFORMAT -O dts -qq -f -s -o - "$DT"
|
||||
}
|
||||
|
||||
if [ $# != 2 ]; then
|
||||
echo "Usage: dtdiff <device tree> <device tree>" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
diff -u <(source_and_sort "$1") <(source_and_sort "$2")
|
162
contrib/dtc/fdtdump.c
Normal file
162
contrib/dtc/fdtdump.c
Normal file
@ -0,0 +1,162 @@
|
||||
/*
|
||||
* fdtdump.c - Contributed by Pantelis Antoniou <pantelis.antoniou AT gmail.com>
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <fdt.h>
|
||||
#include <libfdt_env.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
|
||||
#define PALIGN(p, a) ((void *)(ALIGN((unsigned long)(p), (a))))
|
||||
#define GET_CELL(p) (p += 4, *((const uint32_t *)(p-4)))
|
||||
|
||||
static void print_data(const char *data, int len)
|
||||
{
|
||||
int i;
|
||||
const char *p = data;
|
||||
|
||||
/* no data, don't print */
|
||||
if (len == 0)
|
||||
return;
|
||||
|
||||
if (util_is_printable_string(data, len)) {
|
||||
printf(" = \"%s\"", (const char *)data);
|
||||
} else if ((len % 4) == 0) {
|
||||
printf(" = <");
|
||||
for (i = 0; i < len; i += 4)
|
||||
printf("0x%08x%s", fdt32_to_cpu(GET_CELL(p)),
|
||||
i < (len - 4) ? " " : "");
|
||||
printf(">");
|
||||
} else {
|
||||
printf(" = [");
|
||||
for (i = 0; i < len; i++)
|
||||
printf("%02x%s", *p++, i < len - 1 ? " " : "");
|
||||
printf("]");
|
||||
}
|
||||
}
|
||||
|
||||
static void dump_blob(void *blob)
|
||||
{
|
||||
struct fdt_header *bph = blob;
|
||||
uint32_t off_mem_rsvmap = fdt32_to_cpu(bph->off_mem_rsvmap);
|
||||
uint32_t off_dt = fdt32_to_cpu(bph->off_dt_struct);
|
||||
uint32_t off_str = fdt32_to_cpu(bph->off_dt_strings);
|
||||
struct fdt_reserve_entry *p_rsvmap =
|
||||
(struct fdt_reserve_entry *)((char *)blob + off_mem_rsvmap);
|
||||
const char *p_struct = (const char *)blob + off_dt;
|
||||
const char *p_strings = (const char *)blob + off_str;
|
||||
uint32_t version = fdt32_to_cpu(bph->version);
|
||||
uint32_t totalsize = fdt32_to_cpu(bph->totalsize);
|
||||
uint32_t tag;
|
||||
const char *p, *s, *t;
|
||||
int depth, sz, shift;
|
||||
int i;
|
||||
uint64_t addr, size;
|
||||
|
||||
depth = 0;
|
||||
shift = 4;
|
||||
|
||||
printf("/dts-v1/;\n");
|
||||
printf("// magic:\t\t0x%x\n", fdt32_to_cpu(bph->magic));
|
||||
printf("// totalsize:\t\t0x%x (%d)\n", totalsize, totalsize);
|
||||
printf("// off_dt_struct:\t0x%x\n", off_dt);
|
||||
printf("// off_dt_strings:\t0x%x\n", off_str);
|
||||
printf("// off_mem_rsvmap:\t0x%x\n", off_mem_rsvmap);
|
||||
printf("// version:\t\t%d\n", version);
|
||||
printf("// last_comp_version:\t%d\n",
|
||||
fdt32_to_cpu(bph->last_comp_version));
|
||||
if (version >= 2)
|
||||
printf("// boot_cpuid_phys:\t0x%x\n",
|
||||
fdt32_to_cpu(bph->boot_cpuid_phys));
|
||||
|
||||
if (version >= 3)
|
||||
printf("// size_dt_strings:\t0x%x\n",
|
||||
fdt32_to_cpu(bph->size_dt_strings));
|
||||
if (version >= 17)
|
||||
printf("// size_dt_struct:\t0x%x\n",
|
||||
fdt32_to_cpu(bph->size_dt_struct));
|
||||
printf("\n");
|
||||
|
||||
for (i = 0; ; i++) {
|
||||
addr = fdt64_to_cpu(p_rsvmap[i].address);
|
||||
size = fdt64_to_cpu(p_rsvmap[i].size);
|
||||
if (addr == 0 && size == 0)
|
||||
break;
|
||||
|
||||
printf("/memreserve/ %llx %llx;\n",
|
||||
(unsigned long long)addr, (unsigned long long)size);
|
||||
}
|
||||
|
||||
p = p_struct;
|
||||
while ((tag = fdt32_to_cpu(GET_CELL(p))) != FDT_END) {
|
||||
|
||||
/* printf("tag: 0x%08x (%d)\n", tag, p - p_struct); */
|
||||
|
||||
if (tag == FDT_BEGIN_NODE) {
|
||||
s = p;
|
||||
p = PALIGN(p + strlen(s) + 1, 4);
|
||||
|
||||
if (*s == '\0')
|
||||
s = "/";
|
||||
|
||||
printf("%*s%s {\n", depth * shift, "", s);
|
||||
|
||||
depth++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tag == FDT_END_NODE) {
|
||||
depth--;
|
||||
|
||||
printf("%*s};\n", depth * shift, "");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tag == FDT_NOP) {
|
||||
printf("%*s// [NOP]\n", depth * shift, "");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tag != FDT_PROP) {
|
||||
fprintf(stderr, "%*s ** Unknown tag 0x%08x\n", depth * shift, "", tag);
|
||||
break;
|
||||
}
|
||||
sz = fdt32_to_cpu(GET_CELL(p));
|
||||
s = p_strings + fdt32_to_cpu(GET_CELL(p));
|
||||
if (version < 16 && sz >= 8)
|
||||
p = PALIGN(p, 8);
|
||||
t = p;
|
||||
|
||||
p = PALIGN(p + sz, 4);
|
||||
|
||||
printf("%*s%s", depth * shift, "", s);
|
||||
print_data(t, sz);
|
||||
printf(";\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *buf;
|
||||
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "supply input filename\n");
|
||||
return 5;
|
||||
}
|
||||
|
||||
buf = utilfdt_read(argv[1]);
|
||||
if (buf)
|
||||
dump_blob(buf);
|
||||
else
|
||||
return 10;
|
||||
|
||||
return 0;
|
||||
}
|
366
contrib/dtc/fdtget.c
Normal file
366
contrib/dtc/fdtget.c
Normal file
@ -0,0 +1,366 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
|
||||
*
|
||||
* Portions from U-Boot cmd_fdt.c (C) Copyright 2007
|
||||
* Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com
|
||||
* Based on code written by:
|
||||
* Pantelis Antoniou <pantelis.antoniou@gmail.com> and
|
||||
* Matthew McClintock <msm@freescale.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 License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <getopt.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libfdt.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
enum display_mode {
|
||||
MODE_SHOW_VALUE, /* show values for node properties */
|
||||
MODE_LIST_PROPS, /* list the properties for a node */
|
||||
MODE_LIST_SUBNODES, /* list the subnodes of a node */
|
||||
};
|
||||
|
||||
/* Holds information which controls our output and options */
|
||||
struct display_info {
|
||||
int type; /* data type (s/i/u/x or 0 for default) */
|
||||
int size; /* data size (1/2/4) */
|
||||
enum display_mode mode; /* display mode that we are using */
|
||||
const char *default_val; /* default value if node/property not found */
|
||||
};
|
||||
|
||||
static void report_error(const char *where, int err)
|
||||
{
|
||||
fprintf(stderr, "Error at '%s': %s\n", where, fdt_strerror(err));
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays data of a given length according to selected options
|
||||
*
|
||||
* If a specific data type is provided in disp, then this is used. Otherwise
|
||||
* we try to guess the data type / size from the contents.
|
||||
*
|
||||
* @param disp Display information / options
|
||||
* @param data Data to display
|
||||
* @param len Maximum length of buffer
|
||||
* @return 0 if ok, -1 if data does not match format
|
||||
*/
|
||||
static int show_data(struct display_info *disp, const char *data, int len)
|
||||
{
|
||||
int i, size;
|
||||
const uint8_t *p = (const uint8_t *)data;
|
||||
const char *s;
|
||||
int value;
|
||||
int is_string;
|
||||
char fmt[3];
|
||||
|
||||
/* no data, don't print */
|
||||
if (len == 0)
|
||||
return 0;
|
||||
|
||||
is_string = (disp->type) == 's' ||
|
||||
(!disp->type && util_is_printable_string(data, len));
|
||||
if (is_string) {
|
||||
if (data[len - 1] != '\0') {
|
||||
fprintf(stderr, "Unterminated string\n");
|
||||
return -1;
|
||||
}
|
||||
for (s = data; s - data < len; s += strlen(s) + 1) {
|
||||
if (s != data)
|
||||
printf(" ");
|
||||
printf("%s", (const char *)s);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
size = disp->size;
|
||||
if (size == -1) {
|
||||
size = (len % 4) == 0 ? 4 : 1;
|
||||
} else if (len % size) {
|
||||
fprintf(stderr, "Property length must be a multiple of "
|
||||
"selected data size\n");
|
||||
return -1;
|
||||
}
|
||||
fmt[0] = '%';
|
||||
fmt[1] = disp->type ? disp->type : 'd';
|
||||
fmt[2] = '\0';
|
||||
for (i = 0; i < len; i += size, p += size) {
|
||||
if (i)
|
||||
printf(" ");
|
||||
value = size == 4 ? fdt32_to_cpu(*(const uint32_t *)p) :
|
||||
size == 2 ? (*p << 8) | p[1] : *p;
|
||||
printf(fmt, value);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* List all properties in a node, one per line.
|
||||
*
|
||||
* @param blob FDT blob
|
||||
* @param node Node to display
|
||||
* @return 0 if ok, or FDT_ERR... if not.
|
||||
*/
|
||||
static int list_properties(const void *blob, int node)
|
||||
{
|
||||
const struct fdt_property *data;
|
||||
const char *name;
|
||||
int prop;
|
||||
|
||||
prop = fdt_first_property_offset(blob, node);
|
||||
do {
|
||||
/* Stop silently when there are no more properties */
|
||||
if (prop < 0)
|
||||
return prop == -FDT_ERR_NOTFOUND ? 0 : prop;
|
||||
data = fdt_get_property_by_offset(blob, prop, NULL);
|
||||
name = fdt_string(blob, fdt32_to_cpu(data->nameoff));
|
||||
if (name)
|
||||
puts(name);
|
||||
prop = fdt_next_property_offset(blob, prop);
|
||||
} while (1);
|
||||
}
|
||||
|
||||
#define MAX_LEVEL 32 /* how deeply nested we will go */
|
||||
|
||||
/**
|
||||
* List all subnodes in a node, one per line
|
||||
*
|
||||
* @param blob FDT blob
|
||||
* @param node Node to display
|
||||
* @return 0 if ok, or FDT_ERR... if not.
|
||||
*/
|
||||
static int list_subnodes(const void *blob, int node)
|
||||
{
|
||||
int nextoffset; /* next node offset from libfdt */
|
||||
uint32_t tag; /* current tag */
|
||||
int level = 0; /* keep track of nesting level */
|
||||
const char *pathp;
|
||||
int depth = 1; /* the assumed depth of this node */
|
||||
|
||||
while (level >= 0) {
|
||||
tag = fdt_next_tag(blob, node, &nextoffset);
|
||||
switch (tag) {
|
||||
case FDT_BEGIN_NODE:
|
||||
pathp = fdt_get_name(blob, node, NULL);
|
||||
if (level <= depth) {
|
||||
if (pathp == NULL)
|
||||
pathp = "/* NULL pointer error */";
|
||||
if (*pathp == '\0')
|
||||
pathp = "/"; /* root is nameless */
|
||||
if (level == 1)
|
||||
puts(pathp);
|
||||
}
|
||||
level++;
|
||||
if (level >= MAX_LEVEL) {
|
||||
printf("Nested too deep, aborting.\n");
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case FDT_END_NODE:
|
||||
level--;
|
||||
if (level == 0)
|
||||
level = -1; /* exit the loop */
|
||||
break;
|
||||
case FDT_END:
|
||||
return 1;
|
||||
case FDT_PROP:
|
||||
break;
|
||||
default:
|
||||
if (level <= depth)
|
||||
printf("Unknown tag 0x%08X\n", tag);
|
||||
return 1;
|
||||
}
|
||||
node = nextoffset;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the data for a given node (and perhaps property) according to the
|
||||
* display option provided.
|
||||
*
|
||||
* @param blob FDT blob
|
||||
* @param disp Display information / options
|
||||
* @param node Node to display
|
||||
* @param property Name of property to display, or NULL if none
|
||||
* @return 0 if ok, -ve on error
|
||||
*/
|
||||
static int show_data_for_item(const void *blob, struct display_info *disp,
|
||||
int node, const char *property)
|
||||
{
|
||||
const void *value = NULL;
|
||||
int len, err = 0;
|
||||
|
||||
switch (disp->mode) {
|
||||
case MODE_LIST_PROPS:
|
||||
err = list_properties(blob, node);
|
||||
break;
|
||||
|
||||
case MODE_LIST_SUBNODES:
|
||||
err = list_subnodes(blob, node);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(property);
|
||||
value = fdt_getprop(blob, node, property, &len);
|
||||
if (value) {
|
||||
if (show_data(disp, value, len))
|
||||
err = -1;
|
||||
else
|
||||
printf("\n");
|
||||
} else if (disp->default_val) {
|
||||
puts(disp->default_val);
|
||||
} else {
|
||||
report_error(property, len);
|
||||
err = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the main fdtget operation, given a filename and valid arguments
|
||||
*
|
||||
* @param disp Display information / options
|
||||
* @param filename Filename of blob file
|
||||
* @param arg List of arguments to process
|
||||
* @param arg_count Number of arguments
|
||||
* @param return 0 if ok, -ve on error
|
||||
*/
|
||||
static int do_fdtget(struct display_info *disp, const char *filename,
|
||||
char **arg, int arg_count, int args_per_step)
|
||||
{
|
||||
char *blob;
|
||||
const char *prop;
|
||||
int i, node;
|
||||
|
||||
blob = utilfdt_read(filename);
|
||||
if (!blob)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i + args_per_step <= arg_count; i += args_per_step) {
|
||||
node = fdt_path_offset(blob, arg[i]);
|
||||
if (node < 0) {
|
||||
if (disp->default_val) {
|
||||
puts(disp->default_val);
|
||||
continue;
|
||||
} else {
|
||||
report_error(arg[i], node);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
prop = args_per_step == 1 ? NULL : arg[i + 1];
|
||||
|
||||
if (show_data_for_item(blob, disp, node, prop))
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *usage_msg =
|
||||
"fdtget - read values from device tree\n"
|
||||
"\n"
|
||||
"Each value is printed on a new line.\n\n"
|
||||
"Usage:\n"
|
||||
" fdtget <options> <dt file> [<node> <property>]...\n"
|
||||
" fdtget -p <options> <dt file> [<node> ]...\n"
|
||||
"Options:\n"
|
||||
"\t-t <type>\tType of data\n"
|
||||
"\t-p\t\tList properties for each node\n"
|
||||
"\t-l\t\tList subnodes for each node\n"
|
||||
"\t-d\t\tDefault value to display when the property is "
|
||||
"missing\n"
|
||||
"\t-h\t\tPrint this help\n\n"
|
||||
USAGE_TYPE_MSG;
|
||||
|
||||
static void usage(const char *msg)
|
||||
{
|
||||
if (msg)
|
||||
fprintf(stderr, "Error: %s\n\n", msg);
|
||||
|
||||
fprintf(stderr, "%s", usage_msg);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *filename = NULL;
|
||||
struct display_info disp;
|
||||
int args_per_step = 2;
|
||||
|
||||
/* set defaults */
|
||||
memset(&disp, '\0', sizeof(disp));
|
||||
disp.size = -1;
|
||||
disp.mode = MODE_SHOW_VALUE;
|
||||
for (;;) {
|
||||
int c = getopt(argc, argv, "d:hlpt:");
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
switch (c) {
|
||||
case 'h':
|
||||
case '?':
|
||||
usage(NULL);
|
||||
|
||||
case 't':
|
||||
if (utilfdt_decode_type(optarg, &disp.type,
|
||||
&disp.size))
|
||||
usage("Invalid type string");
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
disp.mode = MODE_LIST_PROPS;
|
||||
args_per_step = 1;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
disp.mode = MODE_LIST_SUBNODES;
|
||||
args_per_step = 1;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
disp.default_val = optarg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (optind < argc)
|
||||
filename = argv[optind++];
|
||||
if (!filename)
|
||||
usage("Missing filename");
|
||||
|
||||
argv += optind;
|
||||
argc -= optind;
|
||||
|
||||
/* Allow no arguments, and silently succeed */
|
||||
if (!argc)
|
||||
return 0;
|
||||
|
||||
/* Check for node, property arguments */
|
||||
if (args_per_step == 2 && (argc % 2))
|
||||
usage("Must have an even number of arguments");
|
||||
|
||||
if (do_fdtget(&disp, filename, argv, argc, args_per_step))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
362
contrib/dtc/fdtput.c
Normal file
362
contrib/dtc/fdtput.c
Normal file
@ -0,0 +1,362 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
|
||||
*
|
||||
* 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 License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <getopt.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libfdt.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
/* These are the operations we support */
|
||||
enum oper_type {
|
||||
OPER_WRITE_PROP, /* Write a property in a node */
|
||||
OPER_CREATE_NODE, /* Create a new node */
|
||||
};
|
||||
|
||||
struct display_info {
|
||||
enum oper_type oper; /* operation to perform */
|
||||
int type; /* data type (s/i/u/x or 0 for default) */
|
||||
int size; /* data size (1/2/4) */
|
||||
int verbose; /* verbose output */
|
||||
int auto_path; /* automatically create all path components */
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Report an error with a particular node.
|
||||
*
|
||||
* @param name Node name to report error on
|
||||
* @param namelen Length of node name, or -1 to use entire string
|
||||
* @param err Error number to report (-FDT_ERR_...)
|
||||
*/
|
||||
static void report_error(const char *name, int namelen, int err)
|
||||
{
|
||||
if (namelen == -1)
|
||||
namelen = strlen(name);
|
||||
fprintf(stderr, "Error at '%1.*s': %s\n", namelen, name,
|
||||
fdt_strerror(err));
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode a series of arguments in a property value.
|
||||
*
|
||||
* @param disp Display information / options
|
||||
* @param arg List of arguments from command line
|
||||
* @param arg_count Number of arguments (may be 0)
|
||||
* @param valuep Returns buffer containing value
|
||||
* @param *value_len Returns length of value encoded
|
||||
*/
|
||||
static int encode_value(struct display_info *disp, char **arg, int arg_count,
|
||||
char **valuep, int *value_len)
|
||||
{
|
||||
char *value = NULL; /* holding area for value */
|
||||
int value_size = 0; /* size of holding area */
|
||||
char *ptr; /* pointer to current value position */
|
||||
int len; /* length of this cell/string/byte */
|
||||
int ival;
|
||||
int upto; /* the number of bytes we have written to buf */
|
||||
char fmt[3];
|
||||
|
||||
upto = 0;
|
||||
|
||||
if (disp->verbose)
|
||||
fprintf(stderr, "Decoding value:\n");
|
||||
|
||||
fmt[0] = '%';
|
||||
fmt[1] = disp->type ? disp->type : 'd';
|
||||
fmt[2] = '\0';
|
||||
for (; arg_count > 0; arg++, arg_count--, upto += len) {
|
||||
/* assume integer unless told otherwise */
|
||||
if (disp->type == 's')
|
||||
len = strlen(*arg) + 1;
|
||||
else
|
||||
len = disp->size == -1 ? 4 : disp->size;
|
||||
|
||||
/* enlarge our value buffer by a suitable margin if needed */
|
||||
if (upto + len > value_size) {
|
||||
value_size = (upto + len) + 500;
|
||||
value = realloc(value, value_size);
|
||||
if (!value) {
|
||||
fprintf(stderr, "Out of mmory: cannot alloc "
|
||||
"%d bytes\n", value_size);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
ptr = value + upto;
|
||||
if (disp->type == 's') {
|
||||
memcpy(ptr, *arg, len);
|
||||
if (disp->verbose)
|
||||
fprintf(stderr, "\tstring: '%s'\n", ptr);
|
||||
} else {
|
||||
int *iptr = (int *)ptr;
|
||||
sscanf(*arg, fmt, &ival);
|
||||
if (len == 4)
|
||||
*iptr = cpu_to_fdt32(ival);
|
||||
else
|
||||
*ptr = (uint8_t)ival;
|
||||
if (disp->verbose) {
|
||||
fprintf(stderr, "\t%s: %d\n",
|
||||
disp->size == 1 ? "byte" :
|
||||
disp->size == 2 ? "short" : "int",
|
||||
ival);
|
||||
}
|
||||
}
|
||||
}
|
||||
*value_len = upto;
|
||||
*valuep = value;
|
||||
if (disp->verbose)
|
||||
fprintf(stderr, "Value size %d\n", upto);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int store_key_value(void *blob, const char *node_name,
|
||||
const char *property, const char *buf, int len)
|
||||
{
|
||||
int node;
|
||||
int err;
|
||||
|
||||
node = fdt_path_offset(blob, node_name);
|
||||
if (node < 0) {
|
||||
report_error(node_name, -1, node);
|
||||
return -1;
|
||||
}
|
||||
|
||||
err = fdt_setprop(blob, node, property, buf, len);
|
||||
if (err) {
|
||||
report_error(property, -1, err);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create paths as needed for all components of a path
|
||||
*
|
||||
* Any components of the path that do not exist are created. Errors are
|
||||
* reported.
|
||||
*
|
||||
* @param blob FDT blob to write into
|
||||
* @param in_path Path to process
|
||||
* @return 0 if ok, -1 on error
|
||||
*/
|
||||
static int create_paths(void *blob, const char *in_path)
|
||||
{
|
||||
const char *path = in_path;
|
||||
const char *sep;
|
||||
int node, offset = 0;
|
||||
|
||||
/* skip leading '/' */
|
||||
while (*path == '/')
|
||||
path++;
|
||||
|
||||
for (sep = path; *sep; path = sep + 1, offset = node) {
|
||||
/* equivalent to strchrnul(), but it requires _GNU_SOURCE */
|
||||
sep = strchr(path, '/');
|
||||
if (!sep)
|
||||
sep = path + strlen(path);
|
||||
|
||||
node = fdt_subnode_offset_namelen(blob, offset, path,
|
||||
sep - path);
|
||||
if (node == -FDT_ERR_NOTFOUND) {
|
||||
node = fdt_add_subnode_namelen(blob, offset, path,
|
||||
sep - path);
|
||||
}
|
||||
if (node < 0) {
|
||||
report_error(path, sep - path, node);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new node in the fdt.
|
||||
*
|
||||
* This will overwrite the node_name string. Any error is reported.
|
||||
*
|
||||
* TODO: Perhaps create fdt_path_offset_namelen() so we don't need to do this.
|
||||
*
|
||||
* @param blob FDT blob to write into
|
||||
* @param node_name Name of node to create
|
||||
* @return new node offset if found, or -1 on failure
|
||||
*/
|
||||
static int create_node(void *blob, const char *node_name)
|
||||
{
|
||||
int node = 0;
|
||||
char *p;
|
||||
|
||||
p = strrchr(node_name, '/');
|
||||
if (!p) {
|
||||
report_error(node_name, -1, -FDT_ERR_BADPATH);
|
||||
return -1;
|
||||
}
|
||||
*p = '\0';
|
||||
|
||||
if (p > node_name) {
|
||||
node = fdt_path_offset(blob, node_name);
|
||||
if (node < 0) {
|
||||
report_error(node_name, -1, node);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
node = fdt_add_subnode(blob, node, p + 1);
|
||||
if (node < 0) {
|
||||
report_error(p + 1, -1, node);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_fdtput(struct display_info *disp, const char *filename,
|
||||
char **arg, int arg_count)
|
||||
{
|
||||
char *value;
|
||||
char *blob;
|
||||
int len, ret = 0;
|
||||
|
||||
blob = utilfdt_read(filename);
|
||||
if (!blob)
|
||||
return -1;
|
||||
|
||||
switch (disp->oper) {
|
||||
case OPER_WRITE_PROP:
|
||||
/*
|
||||
* Convert the arguments into a single binary value, then
|
||||
* store them into the property.
|
||||
*/
|
||||
assert(arg_count >= 2);
|
||||
if (disp->auto_path && create_paths(blob, *arg))
|
||||
return -1;
|
||||
if (encode_value(disp, arg + 2, arg_count - 2, &value, &len) ||
|
||||
store_key_value(blob, *arg, arg[1], value, len))
|
||||
ret = -1;
|
||||
break;
|
||||
case OPER_CREATE_NODE:
|
||||
for (; ret >= 0 && arg_count--; arg++) {
|
||||
if (disp->auto_path)
|
||||
ret = create_paths(blob, *arg);
|
||||
else
|
||||
ret = create_node(blob, *arg);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (ret >= 0)
|
||||
ret = utilfdt_write(filename, blob);
|
||||
|
||||
free(blob);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const char *usage_msg =
|
||||
"fdtput - write a property value to a device tree\n"
|
||||
"\n"
|
||||
"The command line arguments are joined together into a single value.\n"
|
||||
"\n"
|
||||
"Usage:\n"
|
||||
" fdtput <options> <dt file> <node> <property> [<value>...]\n"
|
||||
" fdtput -c <options> <dt file> [<node>...]\n"
|
||||
"Options:\n"
|
||||
"\t-c\t\tCreate nodes if they don't already exist\n"
|
||||
"\t-p\t\tAutomatically create nodes as needed for the node path\n"
|
||||
"\t-t <type>\tType of data\n"
|
||||
"\t-v\t\tVerbose: display each value decoded from command line\n"
|
||||
"\t-h\t\tPrint this help\n\n"
|
||||
USAGE_TYPE_MSG;
|
||||
|
||||
static void usage(const char *msg)
|
||||
{
|
||||
if (msg)
|
||||
fprintf(stderr, "Error: %s\n\n", msg);
|
||||
|
||||
fprintf(stderr, "%s", usage_msg);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct display_info disp;
|
||||
char *filename = NULL;
|
||||
|
||||
memset(&disp, '\0', sizeof(disp));
|
||||
disp.size = -1;
|
||||
disp.oper = OPER_WRITE_PROP;
|
||||
for (;;) {
|
||||
int c = getopt(argc, argv, "chpt:v");
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
/*
|
||||
* TODO: add options to:
|
||||
* - delete property
|
||||
* - delete node (optionally recursively)
|
||||
* - rename node
|
||||
* - pack fdt before writing
|
||||
* - set amount of free space when writing
|
||||
* - expand fdt if value doesn't fit
|
||||
*/
|
||||
switch (c) {
|
||||
case 'c':
|
||||
disp.oper = OPER_CREATE_NODE;
|
||||
break;
|
||||
case 'h':
|
||||
case '?':
|
||||
usage(NULL);
|
||||
case 'p':
|
||||
disp.auto_path = 1;
|
||||
break;
|
||||
case 't':
|
||||
if (utilfdt_decode_type(optarg, &disp.type,
|
||||
&disp.size))
|
||||
usage("Invalid type string");
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
disp.verbose = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (optind < argc)
|
||||
filename = argv[optind++];
|
||||
if (!filename)
|
||||
usage("Missing filename");
|
||||
|
||||
argv += optind;
|
||||
argc -= optind;
|
||||
|
||||
if (disp.oper == OPER_WRITE_PROP) {
|
||||
if (argc < 1)
|
||||
usage("Missing node");
|
||||
if (argc < 2)
|
||||
usage("Missing property");
|
||||
}
|
||||
|
||||
if (do_fdtput(&disp, filename, argv, argc))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
84
contrib/dtc/libfdt/fdt_empty_tree.c
Normal file
84
contrib/dtc/libfdt/fdt_empty_tree.c
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Copyright (C) 2012 David Gibson, IBM Corporation.
|
||||
*
|
||||
* libfdt is dual licensed: you can use it either under the terms of
|
||||
* the GPL, or the BSD license, at your option.
|
||||
*
|
||||
* a) This library 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
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*
|
||||
* Alternatively,
|
||||
*
|
||||
* b) Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "libfdt_env.h"
|
||||
|
||||
#include <fdt.h>
|
||||
#include <libfdt.h>
|
||||
|
||||
#include "libfdt_internal.h"
|
||||
|
||||
int fdt_create_empty_tree(void *buf, int bufsize)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = fdt_create(buf, bufsize);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = fdt_finish_reservemap(buf);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = fdt_begin_node(buf, "");
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = fdt_end_node(buf);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = fdt_finish(buf);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return fdt_open_into(buf, buf, bufsize);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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_ */
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
84
sys/contrib/libfdt/fdt_empty_tree.c
Normal file
84
sys/contrib/libfdt/fdt_empty_tree.c
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Copyright (C) 2012 David Gibson, IBM Corporation.
|
||||
*
|
||||
* libfdt is dual licensed: you can use it either under the terms of
|
||||
* the GPL, or the BSD license, at your option.
|
||||
*
|
||||
* a) This library 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
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*
|
||||
* Alternatively,
|
||||
*
|
||||
* b) Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "libfdt_env.h"
|
||||
|
||||
#include <fdt.h>
|
||||
#include <libfdt.h>
|
||||
|
||||
#include "libfdt_internal.h"
|
||||
|
||||
int fdt_create_empty_tree(void *buf, int bufsize)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = fdt_create(buf, bufsize);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = fdt_finish_reservemap(buf);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = fdt_begin_node(buf, "");
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = fdt_end_node(buf);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = fdt_finish(buf);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return fdt_open_into(buf, buf, bufsize);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -13,19 +13,25 @@
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user