Import dtc from git://git.jdl.com/software/dtc

hash f807af192828222dee7a5c9f94d999673bb4d8a1
This commit is contained in:
Warner Losh 2012-07-24 02:58:10 +00:00
parent b7b62f4139
commit bae61446cf
49 changed files with 2730 additions and 856 deletions

View File

@ -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>

View File

@ -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>

View File

@ -9,14 +9,16 @@
# CONFIG_LOCALVERSION from some future config system.
#
VERSION = 1
PATCHLEVEL = 2
PATCHLEVEL = 3
SUBLEVEL = 0
EXTRAVERSION =
LOCAL_VERSION =
CONFIG_LOCALVERSION =
CPPFLAGS = -I libfdt
CFLAGS = -Wall -g -Os -fPIC -Wpointer-arith -Wcast-qual
CPPFLAGS = -I libfdt -I .
WARNINGS = -Werror -Wall -Wpointer-arith -Wcast-qual -Wnested-externs \
-Wstrict-prototypes -Wmissing-prototypes -Wredundant-decls
CFLAGS = -g -Os -fPIC -Werror $(WARNINGS)
BISON = bison
LEX = flex
@ -103,12 +105,15 @@ endef
include Makefile.convert-dtsv0
include Makefile.dtc
include Makefile.ftdump
include Makefile.utils
BIN += convert-dtsv0
BIN += dtc
BIN += ftdump
BIN += fdtdump
BIN += fdtget
BIN += fdtput
SCRIPTS = dtdiff
all: $(BIN) libfdt
@ -116,7 +121,9 @@ all: $(BIN) libfdt
ifneq ($(DEPTARGETS),)
-include $(DTC_OBJS:%.o=%.d)
-include $(CONVERT_OBJS:%.o=%.d)
-include $(FTDUMP_OBJS:%.o=%.d)
-include $(FDTDUMP_OBJS:%.o=%.d)
-include $(FDTGET_OBJS:%.o=%.d)
-include $(FDTPUT_OBJS:%.o=%.d)
endif
@ -127,7 +134,7 @@ endif
LIBFDT_objdir = libfdt
LIBFDT_srcdir = libfdt
LIBFDT_archive = $(LIBFDT_objdir)/libfdt.a
LIBFDT_lib = $(LIBFDT_objdir)/libfdt.$(SHAREDLIB_EXT)
LIBFDT_lib = $(LIBFDT_objdir)/libfdt-$(DTC_VERSION).$(SHAREDLIB_EXT)
LIBFDT_include = $(addprefix $(LIBFDT_srcdir)/,$(LIBFDT_INCLUDES))
LIBFDT_version = $(addprefix $(LIBFDT_srcdir)/,$(LIBFDT_VERSION))
@ -153,12 +160,14 @@ endif
# intermediate target and building them again "for real"
.SECONDARY: $(DTC_GEN_SRCS) $(CONVERT_GEN_SRCS)
install: all
install: all $(SCRIPTS)
@$(VECHO) INSTALL
$(INSTALL) -d $(DESTDIR)$(BINDIR)
$(INSTALL) $(BIN) $(DESTDIR)$(BINDIR)
$(INSTALL) $(BIN) $(SCRIPTS) $(DESTDIR)$(BINDIR)
$(INSTALL) -d $(DESTDIR)$(LIBDIR)
$(INSTALL) $(LIBFDT_lib) $(DESTDIR)$(LIBDIR)
ln -sf $(notdir $(LIBFDT_lib)) $(DESTDIR)$(LIBDIR)/$(LIBFDT_soname)
ln -sf $(LIBFDT_soname) $(DESTDIR)$(LIBDIR)/libfdt.$(SHAREDLIB_EXT)
$(INSTALL) -m 644 $(LIBFDT_archive) $(DESTDIR)$(LIBDIR)
$(INSTALL) -d $(DESTDIR)$(INCLUDEDIR)
$(INSTALL) -m 644 $(LIBFDT_include) $(DESTDIR)$(INCLUDEDIR)
@ -173,19 +182,29 @@ convert-dtsv0: $(CONVERT_OBJS)
@$(VECHO) LD $@
$(LINK.c) -o $@ $^
ftdump: $(FTDUMP_OBJS)
fdtdump: $(FDTDUMP_OBJS)
fdtget: $(FDTGET_OBJS) $(LIBFDT_archive)
fdtput: $(FDTPUT_OBJS) $(LIBFDT_archive)
#
# Testsuite rules
#
TESTS_PREFIX=tests/
TESTS_BIN += dtc
TESTS_BIN += convert-dtsv0
TESTS_BIN += fdtput
TESTS_BIN += fdtget
include tests/Makefile.tests
#
# Clean rules
#
STD_CLEANFILES = *~ *.o *.so *.d *.a *.i *.s core a.out vgcore.* \
STD_CLEANFILES = *~ *.o *.$(SHAREDLIB_EXT) *.d *.a *.i *.s core a.out vgcore.* \
*.tab.[ch] *.lex.c *.output
clean: libfdt_clean tests_clean
@ -231,8 +250,7 @@ clean: libfdt_clean tests_clean
$(LIBFDT_lib):
@$(VECHO) LD $@
$(CC) $(LDFLAGS) -fPIC $(SHAREDLIB_LINK_OPTIONS)$(notdir $@) -o $(LIBFDT_objdir)/libfdt-$(DTC_VERSION).$(SHAREDLIB_EXT) $^
ln -sf libfdt-$(DTC_VERSION).$(SHAREDLIB_EXT) $(LIBFDT_objdir)/libfdt.$(SHAREDLIB_EXT)
$(CC) $(LDFLAGS) -fPIC $(SHAREDLIB_LINK_OPTIONS)$(LIBFDT_soname) -o $(LIBFDT_lib) $^
%.lex.c: %.l
@$(VECHO) LEX $@

248
checks.c
View File

@ -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);
}

View File

@ -17,7 +17,7 @@
* USA
*/
%option noyywrap nounput noinput
%option noyywrap nounput noinput never-interactive
%x INCLUDE
%x BYTESTRING
@ -210,8 +210,10 @@ static void convert_file(const char *fname)
memcpy(newname, fname, len);
memcpy(newname + len, suffix, sizeof(suffix));
srcpos_file = dtc_open_file(fname, NULL);
yyin = srcpos_file->file;
yyin = fopen(fname, "r");
if (!yyin)
die("Couldn't open input file %s: %s\n",
fname, strerror(errno));
yyout = fopen(newname, "w");
if (!yyout)

120
data.c
View File

@ -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)

View File

@ -18,7 +18,7 @@
* USA
*/
%option noyywrap nounput noinput yylineno
%option noyywrap nounput noinput never-interactive
%x INCLUDE
%x BYTESTRING
@ -29,6 +29,7 @@ PROPNODECHAR [a-zA-Z0-9,._+*#?@-]
PATHCHAR ({PROPNODECHAR}|[/])
LABEL [a-zA-Z_][a-zA-Z0-9_]*
STRING \"([^\\"]|\\.)*\"
CHAR_LITERAL '([^']|\\')*'
WS [[:space:]]
COMMENT "/*"([^*]|\*+[^*/])*\*+"/"
LINECOMMENT "//".*\n
@ -38,10 +39,12 @@ LINECOMMENT "//".*\n
#include "srcpos.h"
#include "dtc-parser.tab.h"
YYLTYPE yylloc;
/* CAUTION: this will stop working if we ever use yyless() or yyunput() */
#define YY_USER_ACTION \
{ \
yylloc.file = srcpos_file; \
yylloc.first_line = yylineno; \
srcpos_update(&yylloc, yytext, yyleng); \
}
/*#define LEXDEBUG 1*/
@ -94,6 +97,12 @@ static int pop_input_file(void);
return DT_MEMRESERVE;
}
<*>"/bits/" {
DPRINT("Keyword: /bits/\n");
BEGIN_DEFAULT();
return DT_BITS;
}
<*>{LABEL}: {
DPRINT("Label: %s\n", yytext);
yylval.labelref = xstrdup(yytext);
@ -101,19 +110,26 @@ static int pop_input_file(void);
return DT_LABEL;
}
<V1>[0-9]+|0[xX][0-9a-fA-F]+ {
<V1>([0-9]+|0[xX][0-9a-fA-F]+)(U|L|UL|LL|ULL)? {
yylval.literal = xstrdup(yytext);
DPRINT("Literal: '%s'\n", yylval.literal);
return DT_LITERAL;
}
\&{LABEL} { /* label reference */
<*>{CHAR_LITERAL} {
yytext[yyleng-1] = '\0';
yylval.literal = xstrdup(yytext+1);
DPRINT("Character literal: %s\n", yylval.literal);
return DT_CHAR_LITERAL;
}
<*>\&{LABEL} { /* label reference */
DPRINT("Ref: %s\n", yytext+1);
yylval.labelref = xstrdup(yytext+1);
return DT_REF;
}
"&{/"{PATHCHAR}+\} { /* new-style path reference */
<*>"&{/"{PATHCHAR}+\} { /* new-style path reference */
yytext[yyleng-1] = '\0';
DPRINT("Ref: %s\n", yytext+2);
yylval.labelref = xstrdup(yytext+2);
@ -148,6 +164,15 @@ static int pop_input_file(void);
<*>{COMMENT}+ /* eat C-style comments */
<*>{LINECOMMENT}+ /* eat C++-style comments */
<*>"<<" { return DT_LSHIFT; };
<*>">>" { return DT_RSHIFT; };
<*>"<=" { return DT_LE; };
<*>">=" { return DT_GE; };
<*>"==" { return DT_EQ; };
<*>"!=" { return DT_NE; };
<*>"&&" { return DT_AND; };
<*>"||" { return DT_OR; };
<*>. {
DPRINT("Char: %c (\\x%02x)\n", yytext[0],
(unsigned)yytext[0]);
@ -165,100 +190,25 @@ static int pop_input_file(void);
%%
/*
* Stack of nested include file contexts.
*/
struct incl_file {
struct dtc_file *file;
YY_BUFFER_STATE yy_prev_buf;
int yy_prev_lineno;
struct incl_file *prev;
};
static struct incl_file *incl_file_stack;
/*
* Detect infinite include recursion.
*/
#define MAX_INCLUDE_DEPTH (100)
static int incl_depth = 0;
static void push_input_file(const char *filename)
{
struct incl_file *incl_file;
struct dtc_file *newfile;
struct search_path search, *searchptr = NULL;
assert(filename);
if (incl_depth++ >= MAX_INCLUDE_DEPTH)
die("Includes nested too deeply");
srcfile_push(filename);
if (srcpos_file) {
search.dir = srcpos_file->dir;
search.next = NULL;
search.prev = NULL;
searchptr = &search;
}
yyin = current_srcfile->f;
newfile = dtc_open_file(filename, searchptr);
incl_file = xmalloc(sizeof(struct incl_file));
/*
* Save current context.
*/
incl_file->yy_prev_buf = YY_CURRENT_BUFFER;
incl_file->yy_prev_lineno = yylineno;
incl_file->file = srcpos_file;
incl_file->prev = incl_file_stack;
incl_file_stack = incl_file;
/*
* Establish new context.
*/
srcpos_file = newfile;
yylineno = 1;
yyin = newfile->file;
yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
yypush_buffer_state(yy_create_buffer(yyin, YY_BUF_SIZE));
}
static int pop_input_file(void)
{
struct incl_file *incl_file;
if (incl_file_stack == 0)
if (srcfile_pop() == 0)
return 0;
dtc_close_file(srcpos_file);
/*
* Pop.
*/
--incl_depth;
incl_file = incl_file_stack;
incl_file_stack = incl_file->prev;
/*
* Recover old context.
*/
yy_delete_buffer(YY_CURRENT_BUFFER);
yy_switch_to_buffer(incl_file->yy_prev_buf);
yylineno = incl_file->yy_prev_lineno;
srcpos_file = incl_file->file;
yyin = incl_file->file ? incl_file->file->file : NULL;
/*
* Free old state.
*/
free(incl_file);
yypop_buffer_state();
yyin = current_srcfile->f;
return 1;
}

View File

@ -18,21 +18,23 @@
* USA
*/
%locations
%{
#include <stdio.h>
#include "dtc.h"
#include "srcpos.h"
YYLTYPE yylloc;
extern int yylex(void);
extern void print_error(char const *fmt, ...);
extern void yyerror(char const *s);
extern struct boot_info *the_boot_info;
extern int treesource_error;
static unsigned long long eval_literal(const char *s, int base, int bits);
static unsigned char eval_char_literal(const char *s);
%}
%union {
@ -43,19 +45,26 @@ static unsigned long long eval_literal(const char *s, int base, int bits);
uint8_t byte;
struct data data;
uint64_t addr;
cell_t cell;
struct {
struct data data;
int bits;
} array;
struct property *prop;
struct property *proplist;
struct node *node;
struct node *nodelist;
struct reserve_info *re;
uint64_t integer;
}
%token DT_V1
%token DT_MEMRESERVE
%token DT_LSHIFT DT_RSHIFT DT_LE DT_GE DT_EQ DT_NE DT_AND DT_OR
%token DT_BITS
%token <propnodename> DT_PROPNODENAME
%token <literal> DT_LITERAL
%token <literal> DT_CHAR_LITERAL
%token <cbase> DT_BASE
%token <byte> DT_BYTE
%token <data> DT_STRING
@ -67,9 +76,7 @@ static unsigned long long eval_literal(const char *s, int base, int bits);
%type <data> propdataprefix
%type <re> memreserve
%type <re> memreserves
%type <addr> addr
%type <data> celllist
%type <cell> cellval
%type <array> arrayprefix
%type <data> bytestring
%type <prop> propdef
%type <proplist> proplist
@ -78,14 +85,29 @@ static unsigned long long eval_literal(const char *s, int base, int bits);
%type <node> nodedef
%type <node> subnode
%type <nodelist> subnodes
%type <labelref> label
%type <integer> integer_prim
%type <integer> integer_unary
%type <integer> integer_mul
%type <integer> integer_add
%type <integer> integer_shift
%type <integer> integer_rela
%type <integer> integer_eq
%type <integer> integer_bitand
%type <integer> integer_bitxor
%type <integer> integer_bitor
%type <integer> integer_and
%type <integer> integer_or
%type <integer> integer_trinary
%type <integer> integer_expr
%%
sourcefile:
DT_V1 ';' memreserves devicetree
{
the_boot_info = build_boot_info($3, $4, 0);
the_boot_info = build_boot_info($3, $4,
guess_boot_cpuid($4));
}
;
@ -101,23 +123,35 @@ memreserves:
;
memreserve:
label DT_MEMRESERVE addr addr ';'
DT_MEMRESERVE integer_prim integer_prim ';'
{
$$ = build_reserve_entry($3, $4, $1);
$$ = build_reserve_entry($2, $3);
}
| DT_LABEL memreserve
{
add_label(&$2->labels, $1);
$$ = $2;
}
;
addr:
DT_LITERAL
{
$$ = eval_literal($1, 0, 64);
}
;
devicetree:
'/' nodedef
{
$$ = name_node($2, "", NULL);
$$ = name_node($2, "");
}
| devicetree '/' nodedef
{
$$ = merge_nodes($1, $3);
}
| devicetree DT_REF nodedef
{
struct node *target = get_node_by_ref($1, $2);
if (target)
merge_nodes(target, $3);
else
print_error("label or path, '%s', not found", $2);
$$ = $1;
}
;
@ -140,13 +174,18 @@ proplist:
;
propdef:
label DT_PROPNODENAME '=' propdata ';'
DT_PROPNODENAME '=' propdata ';'
{
$$ = build_property($2, $4, $1);
$$ = build_property($1, $3);
}
| label DT_PROPNODENAME ';'
| DT_PROPNODENAME ';'
{
$$ = build_property($2, empty_data, $1);
$$ = build_property($1, empty_data);
}
| DT_LABEL propdef
{
add_label(&$2->labels, $1);
$$ = $2;
}
;
@ -155,9 +194,9 @@ propdata:
{
$$ = data_merge($1, $2);
}
| propdataprefix '<' celllist '>'
| propdataprefix arrayprefix '>'
{
$$ = data_merge($1, $3);
$$ = data_merge($1, $2.data);
}
| propdataprefix '[' bytestring ']'
{
@ -167,35 +206,32 @@ propdata:
{
$$ = data_add_marker($1, REF_PATH, $2);
}
| propdataprefix DT_INCBIN '(' DT_STRING ',' addr ',' addr ')'
| propdataprefix DT_INCBIN '(' DT_STRING ',' integer_prim ',' integer_prim ')'
{
struct search_path path = { srcpos_file->dir, NULL, NULL };
struct dtc_file *file = dtc_open_file($4.val, &path);
struct data d = empty_data;
FILE *f = srcfile_relative_open($4.val, NULL);
struct data d;
if ($6 != 0)
if (fseek(file->file, $6, SEEK_SET) != 0)
srcpos_error(&yylloc,
"Couldn't seek to offset %llu in \"%s\": %s",
if (fseek(f, $6, SEEK_SET) != 0)
print_error("Couldn't seek to offset %llu in \"%s\": %s",
(unsigned long long)$6,
$4.val,
strerror(errno));
d = data_copy_file(file->file, $8);
d = data_copy_file(f, $8);
$$ = data_merge($1, d);
dtc_close_file(file);
fclose(f);
}
| propdataprefix DT_INCBIN '(' DT_STRING ')'
{
struct search_path path = { srcpos_file->dir, NULL, NULL };
struct dtc_file *file = dtc_open_file($4.val, &path);
FILE *f = srcfile_relative_open($4.val, NULL);
struct data d = empty_data;
d = data_copy_file(file->file, -1);
d = data_copy_file(f, -1);
$$ = data_merge($1, d);
dtc_close_file(file);
fclose(f);
}
| propdata DT_LABEL
{
@ -218,31 +254,154 @@ propdataprefix:
}
;
celllist:
/* empty */
arrayprefix:
DT_BITS DT_LITERAL '<'
{
$$ = empty_data;
$$.data = empty_data;
$$.bits = eval_literal($2, 0, 7);
if (($$.bits != 8) &&
($$.bits != 16) &&
($$.bits != 32) &&
($$.bits != 64))
{
print_error("Only 8, 16, 32 and 64-bit elements"
" are currently supported");
$$.bits = 32;
}
}
| celllist cellval
| '<'
{
$$ = data_append_cell($1, $2);
$$.data = empty_data;
$$.bits = 32;
}
| celllist DT_REF
| arrayprefix integer_prim
{
$$ = data_append_cell(data_add_marker($1, REF_PHANDLE,
$2), -1);
if ($1.bits < 64) {
uint64_t mask = (1ULL << $1.bits) - 1;
/*
* Bits above mask must either be all zero
* (positive within range of mask) or all one
* (negative and sign-extended). The second
* condition is true if when we set all bits
* within the mask to one (i.e. | in the
* mask), all bits are one.
*/
if (($2 > mask) && (($2 | mask) != -1ULL))
print_error(
"integer value out of range "
"%016lx (%d bits)", $1.bits);
}
$$.data = data_append_integer($1.data, $2, $1.bits);
}
| celllist DT_LABEL
| arrayprefix DT_REF
{
$$ = data_add_marker($1, LABEL, $2);
uint64_t val = ~0ULL >> (64 - $1.bits);
if ($1.bits == 32)
$1.data = data_add_marker($1.data,
REF_PHANDLE,
$2);
else
print_error("References are only allowed in "
"arrays with 32-bit elements.");
$$.data = data_append_integer($1.data, val, $1.bits);
}
| arrayprefix DT_LABEL
{
$$.data = data_add_marker($1.data, LABEL, $2);
}
;
cellval:
integer_prim:
DT_LITERAL
{
$$ = eval_literal($1, 0, 32);
$$ = eval_literal($1, 0, 64);
}
| DT_CHAR_LITERAL
{
$$ = eval_char_literal($1);
}
| '(' integer_expr ')'
{
$$ = $2;
}
;
integer_expr:
integer_trinary
;
integer_trinary:
integer_or
| integer_or '?' integer_expr ':' integer_trinary { $$ = $1 ? $3 : $5; }
;
integer_or:
integer_and
| integer_or DT_OR integer_and { $$ = $1 || $3; }
;
integer_and:
integer_bitor
| integer_and DT_AND integer_bitor { $$ = $1 && $3; }
;
integer_bitor:
integer_bitxor
| integer_bitor '|' integer_bitxor { $$ = $1 | $3; }
;
integer_bitxor:
integer_bitand
| integer_bitxor '^' integer_bitand { $$ = $1 ^ $3; }
;
integer_bitand:
integer_eq
| integer_bitand '&' integer_eq { $$ = $1 & $3; }
;
integer_eq:
integer_rela
| integer_eq DT_EQ integer_rela { $$ = $1 == $3; }
| integer_eq DT_NE integer_rela { $$ = $1 != $3; }
;
integer_rela:
integer_shift
| integer_rela '<' integer_shift { $$ = $1 < $3; }
| integer_rela '>' integer_shift { $$ = $1 > $3; }
| integer_rela DT_LE integer_shift { $$ = $1 <= $3; }
| integer_rela DT_GE integer_shift { $$ = $1 >= $3; }
;
integer_shift:
integer_shift DT_LSHIFT integer_add { $$ = $1 << $3; }
| integer_shift DT_RSHIFT integer_add { $$ = $1 >> $3; }
| integer_add
;
integer_add:
integer_add '+' integer_mul { $$ = $1 + $3; }
| integer_add '-' integer_mul { $$ = $1 - $3; }
| integer_mul
;
integer_mul:
integer_mul '*' integer_unary { $$ = $1 * $3; }
| integer_mul '/' integer_unary { $$ = $1 / $3; }
| integer_mul '%' integer_unary { $$ = $1 % $3; }
| integer_unary
;
integer_unary:
integer_prim
| '-' integer_unary { $$ = -$2; }
| '~' integer_unary { $$ = ~$2; }
| '!' integer_unary { $$ = !$2; }
;
bytestring:
@ -265,43 +424,46 @@ subnodes:
{
$$ = NULL;
}
| subnode subnodes
| subnode subnodes
{
$$ = chain_node($1, $2);
}
| subnode propdef
{
yyerror("syntax error: properties must precede subnodes");
print_error("syntax error: properties must precede subnodes");
YYERROR;
}
;
subnode:
label DT_PROPNODENAME nodedef
DT_PROPNODENAME nodedef
{
$$ = name_node($3, $2, $1);
$$ = name_node($2, $1);
}
;
label:
/* empty */
| DT_LABEL subnode
{
$$ = NULL;
}
| DT_LABEL
{
$$ = $1;
add_label(&$2->labels, $1);
$$ = $2;
}
;
%%
void yyerror(char const *s)
void print_error(char const *fmt, ...)
{
srcpos_error(&yylloc, "%s", s);
va_list va;
va_start(va, fmt);
srcpos_verror(&yylloc, fmt, va);
va_end(va);
treesource_error = 1;
}
void yyerror(char const *s) {
print_error("%s", s);
}
static unsigned long long eval_literal(const char *s, int base, int bits)
{
unsigned long long val;
@ -309,12 +471,41 @@ static unsigned long long eval_literal(const char *s, int base, int bits)
errno = 0;
val = strtoull(s, &e, base);
if (*e)
yyerror("bad characters in literal");
else if ((errno == ERANGE)
if (*e) {
size_t uls = strspn(e, "UL");
if (e[uls])
print_error("bad characters in literal");
}
if ((errno == ERANGE)
|| ((bits < 64) && (val >= (1ULL << bits))))
yyerror("literal out of range");
print_error("literal out of range");
else if (errno != 0)
yyerror("bad literal");
print_error("bad literal");
return val;
}
static unsigned char eval_char_literal(const char *s)
{
int i = 1;
char c = s[0];
if (c == '\0')
{
print_error("empty character literal");
return 0;
}
/*
* If the first character in the character literal is a \ then process
* the remaining characters as an escape encoding. If the first
* character is neither an escape or a terminator it should be the only
* character in the literal and will be returned.
*/
if (c == '\\')
c = get_escape_char(s, &i);
if (s[i] != '\0')
print_error("malformed character literal");
return c;
}

75
dtc.c
View File

@ -32,30 +32,6 @@ int minsize; /* Minimum blob size */
int padsize; /* Additional padding to blob */
int phandle_format = PHANDLE_BOTH; /* Use linux,phandle or phandle properties */
char *join_path(const char *path, const char *name)
{
int lenp = strlen(path);
int lenn = strlen(name);
int len;
int needslash = 1;
char *str;
len = lenp + lenn + 2;
if ((lenp > 0) && (path[lenp-1] == '/')) {
needslash = 0;
len--;
}
str = xmalloc(len);
memcpy(str, path, lenp);
if (needslash) {
str[lenp] = '/';
lenp++;
}
memcpy(str+lenp, name, lenn+1);
return str;
}
static void fill_fullpaths(struct node *tree, const char *prefix)
{
struct node *child;
@ -95,6 +71,7 @@ static void __attribute__ ((noreturn)) usage(void)
fprintf(stderr, "\t\t\tasm - assembler source\n");
fprintf(stderr, "\t-V <output version>\n");
fprintf(stderr, "\t\tBlob version to produce, defaults to %d (relevant for dtb\n\t\tand asm output only)\n", DEFAULT_FDT_VERSION);
fprintf(stderr, "\t-d <output dependency file>\n");
fprintf(stderr, "\t-R <number>\n");
fprintf(stderr, "\t\tMake space for <number> reserve map entries (relevant for \n\t\tdtb and asm output only)\n");
fprintf(stderr, "\t-S <bytes>\n");
@ -105,6 +82,10 @@ static void __attribute__ ((noreturn)) usage(void)
fprintf(stderr, "\t\tSet the physical boot cpu\n");
fprintf(stderr, "\t-f\n");
fprintf(stderr, "\t\tForce - try to produce output even if the input tree has errors\n");
fprintf(stderr, "\t-i\n");
fprintf(stderr, "\t\tAdd a path to search for include files\n");
fprintf(stderr, "\t-s\n");
fprintf(stderr, "\t\tSort nodes and properties before outputting (only useful for\n\t\tcomparing trees)\n");
fprintf(stderr, "\t-v\n");
fprintf(stderr, "\t\tPrint DTC version and exit\n");
fprintf(stderr, "\t-H <phandle format>\n");
@ -112,6 +93,9 @@ static void __attribute__ ((noreturn)) usage(void)
fprintf(stderr, "\t\t\tlegacy - \"linux,phandle\" properties only\n");
fprintf(stderr, "\t\t\tepapr - \"phandle\" properties only\n");
fprintf(stderr, "\t\t\tboth - Both \"linux,phandle\" and \"phandle\" properties\n");
fprintf(stderr, "\t-W [no-]<checkname>\n");
fprintf(stderr, "\t-E [no-]<checkname>\n");
fprintf(stderr, "\t\t\tenable or disable warnings and errors\n");
exit(3);
}
@ -121,7 +105,8 @@ int main(int argc, char *argv[])
const char *inform = "dts";
const char *outform = "dts";
const char *outname = "-";
int force = 0, check = 0;
const char *depname = NULL;
int force = 0, sort = 0;
const char *arg;
int opt;
FILE *outf = NULL;
@ -133,7 +118,8 @@ int main(int argc, char *argv[])
minsize = 0;
padsize = 0;
while ((opt = getopt(argc, argv, "hI:O:o:V:R:S:p:fcqb:vH:")) != EOF) {
while ((opt = getopt(argc, argv, "hI:O:o:V:d:R:S:p:fqb:i:vH:sW:E:"))
!= EOF) {
switch (opt) {
case 'I':
inform = optarg;
@ -147,6 +133,9 @@ int main(int argc, char *argv[])
case 'V':
outversion = strtol(optarg, NULL, 0);
break;
case 'd':
depname = optarg;
break;
case 'R':
reservenum = strtol(optarg, NULL, 0);
break;
@ -159,15 +148,15 @@ int main(int argc, char *argv[])
case 'f':
force = 1;
break;
case 'c':
check = 1;
break;
case 'q':
quiet++;
break;
case 'b':
cmdline_boot_cpuid = strtoll(optarg, NULL, 0);
break;
case 'i':
srcfile_add_search_path(optarg);
break;
case 'v':
printf("Version: %s\n", DTC_VERSION);
exit(0);
@ -183,6 +172,18 @@ int main(int argc, char *argv[])
optarg);
break;
case 's':
sort = 1;
break;
case 'W':
parse_checks_option(true, false, optarg);
break;
case 'E':
parse_checks_option(false, true, optarg);
break;
case 'h':
default:
usage();
@ -203,8 +204,13 @@ int main(int argc, char *argv[])
if (minsize)
fprintf(stderr, "DTC: Use of \"-S\" is deprecated; it will be removed soon, use \"-p\" instead\n");
fprintf(stderr, "DTC: %s->%s on file \"%s\"\n",
inform, outform, arg);
if (depname) {
depfile = fopen(depname, "w");
if (!depfile)
die("Couldn't open dependency file %s: %s\n", depname,
strerror(errno));
fprintf(depfile, "%s:", outname);
}
if (streq(inform, "dts"))
bi = dt_from_source(arg);
@ -215,12 +221,19 @@ int main(int argc, char *argv[])
else
die("Unknown input format \"%s\"\n", inform);
if (depfile) {
fputc('\n', depfile);
fclose(depfile);
}
if (cmdline_boot_cpuid != -1)
bi->boot_cpuid_phys = cmdline_boot_cpuid;
fill_fullpaths(bi->dt, "");
process_checks(force, bi);
if (sort)
sort_tree(bi);
if (streq(outname, "-")) {
outf = stdout;

37
dtc.h
View File

@ -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 */

View File

@ -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);
}

View File

@ -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));
}

View File

@ -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)

View File

@ -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;

View File

@ -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)
{

View File

@ -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;

View File

@ -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

View File

@ -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 */

View File

@ -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);

View File

@ -24,17 +24,30 @@
* Tree building functions
*/
struct property *build_property(char *name, struct data val, char *label)
void add_label(struct label **labels, char *label)
{
struct label *new;
/* Make sure the label isn't already there */
for_each_label(*labels, new)
if (streq(new->label, label))
return;
new = xmalloc(sizeof(*new));
new->label = label;
new->next = *labels;
*labels = new;
}
struct property *build_property(char *name, struct data val)
{
struct property *new = xmalloc(sizeof(*new));
memset(new, 0, sizeof(*new));
new->name = name;
new->val = val;
new->next = NULL;
new->label = label;
return new;
}
@ -78,17 +91,82 @@ struct node *build_node(struct property *proplist, struct node *children)
return new;
}
struct node *name_node(struct node *node, char *name, char * label)
struct node *name_node(struct node *node, char *name)
{
assert(node->name == NULL);
node->name = name;
node->label = label;
return node;
}
struct node *merge_nodes(struct node *old_node, struct node *new_node)
{
struct property *new_prop, *old_prop;
struct node *new_child, *old_child;
struct label *l;
/* Add new node labels to old node */
for_each_label(new_node->labels, l)
add_label(&old_node->labels, l->label);
/* Move properties from the new node to the old node. If there
* is a collision, replace the old value with the new */
while (new_node->proplist) {
/* Pop the property off the list */
new_prop = new_node->proplist;
new_node->proplist = new_prop->next;
new_prop->next = NULL;
/* Look for a collision, set new value if there is */
for_each_property(old_node, old_prop) {
if (streq(old_prop->name, new_prop->name)) {
/* Add new labels to old property */
for_each_label(new_prop->labels, l)
add_label(&old_prop->labels, l->label);
old_prop->val = new_prop->val;
free(new_prop);
new_prop = NULL;
break;
}
}
/* if no collision occurred, add property to the old node. */
if (new_prop)
add_property(old_node, new_prop);
}
/* Move the override child nodes into the primary node. If
* there is a collision, then merge the nodes. */
while (new_node->children) {
/* Pop the child node off the list */
new_child = new_node->children;
new_node->children = new_child->next_sibling;
new_child->parent = NULL;
new_child->next_sibling = NULL;
/* Search for a collision. Merge if there is */
for_each_child(old_node, old_child) {
if (streq(old_child->name, new_child->name)) {
merge_nodes(old_child, new_child);
new_child = NULL;
break;
}
}
/* if no collision occured, add child to the old node. */
if (new_child)
add_child(old_node, new_child);
}
/* The new node contents are now merged into the old node. Free
* the new node. */
free(new_node);
return old_node;
}
struct node *chain_node(struct node *first, struct node *list)
{
assert(first->next_sibling == NULL);
@ -124,18 +202,15 @@ void add_child(struct node *parent, struct node *child)
*p = child;
}
struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size,
char *label)
struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size)
{
struct reserve_info *new = xmalloc(sizeof(*new));
memset(new, 0, sizeof(*new));
new->re.address = address;
new->re.size = size;
new->next = NULL;
new->label = label;
return new;
}
@ -208,6 +283,60 @@ cell_t propval_cell(struct property *prop)
return fdt32_to_cpu(*((cell_t *)prop->val.val));
}
struct property *get_property_by_label(struct node *tree, const char *label,
struct node **node)
{
struct property *prop;
struct node *c;
*node = tree;
for_each_property(tree, prop) {
struct label *l;
for_each_label(prop->labels, l)
if (streq(l->label, label))
return prop;
}
for_each_child(tree, c) {
prop = get_property_by_label(c, label, node);
if (prop)
return prop;
}
*node = NULL;
return NULL;
}
struct marker *get_marker_label(struct node *tree, const char *label,
struct node **node, struct property **prop)
{
struct marker *m;
struct property *p;
struct node *c;
*node = tree;
for_each_property(tree, p) {
*prop = p;
m = p->val.markers;
for_each_marker_of_type(m, LABEL)
if (streq(m->ref, label))
return m;
}
for_each_child(tree, c) {
m = get_marker_label(c, label, node, prop);
if (m)
return m;
}
*prop = NULL;
*node = NULL;
return NULL;
}
struct node *get_subnode(struct node *node, const char *nodename)
{
struct node *child;
@ -245,11 +374,13 @@ struct node *get_node_by_path(struct node *tree, const char *path)
struct node *get_node_by_label(struct node *tree, const char *label)
{
struct node *child, *node;
struct label *l;
assert(label && (strlen(label) > 0));
if (tree->label && streq(tree->label, label))
return tree;
for_each_label(tree->labels, l)
if (streq(l->label, label))
return tree;
for_each_child(tree, child) {
node = get_node_by_label(child, label);
@ -302,15 +433,13 @@ cell_t get_node_phandle(struct node *root, struct node *node)
&& (phandle_format & PHANDLE_LEGACY))
add_property(node,
build_property("linux,phandle",
data_append_cell(empty_data, phandle),
NULL));
data_append_cell(empty_data, phandle)));
if (!get_property(node, "phandle")
&& (phandle_format & PHANDLE_EPAPR))
add_property(node,
build_property("phandle",
data_append_cell(empty_data, phandle),
NULL));
data_append_cell(empty_data, phandle)));
/* If the node *does* have a phandle property, we must
* be dealing with a self-referencing phandle, which will be
@ -318,3 +447,163 @@ cell_t get_node_phandle(struct node *root, struct node *node)
return node->phandle;
}
uint32_t guess_boot_cpuid(struct node *tree)
{
struct node *cpus, *bootcpu;
struct property *reg;
cpus = get_node_by_path(tree, "/cpus");
if (!cpus)
return 0;
bootcpu = cpus->children;
if (!bootcpu)
return 0;
reg = get_property(bootcpu, "reg");
if (!reg || (reg->val.len != sizeof(uint32_t)))
return 0;
/* FIXME: Sanity check node? */
return propval_cell(reg);
}
static int cmp_reserve_info(const void *ax, const void *bx)
{
const struct reserve_info *a, *b;
a = *((const struct reserve_info * const *)ax);
b = *((const struct reserve_info * const *)bx);
if (a->re.address < b->re.address)
return -1;
else if (a->re.address > b->re.address)
return 1;
else if (a->re.size < b->re.size)
return -1;
else if (a->re.size > b->re.size)
return 1;
else
return 0;
}
static void sort_reserve_entries(struct boot_info *bi)
{
struct reserve_info *ri, **tbl;
int n = 0, i = 0;
for (ri = bi->reservelist;
ri;
ri = ri->next)
n++;
if (n == 0)
return;
tbl = xmalloc(n * sizeof(*tbl));
for (ri = bi->reservelist;
ri;
ri = ri->next)
tbl[i++] = ri;
qsort(tbl, n, sizeof(*tbl), cmp_reserve_info);
bi->reservelist = tbl[0];
for (i = 0; i < (n-1); i++)
tbl[i]->next = tbl[i+1];
tbl[n-1]->next = NULL;
free(tbl);
}
static int cmp_prop(const void *ax, const void *bx)
{
const struct property *a, *b;
a = *((const struct property * const *)ax);
b = *((const struct property * const *)bx);
return strcmp(a->name, b->name);
}
static void sort_properties(struct node *node)
{
int n = 0, i = 0;
struct property *prop, **tbl;
for_each_property(node, prop)
n++;
if (n == 0)
return;
tbl = xmalloc(n * sizeof(*tbl));
for_each_property(node, prop)
tbl[i++] = prop;
qsort(tbl, n, sizeof(*tbl), cmp_prop);
node->proplist = tbl[0];
for (i = 0; i < (n-1); i++)
tbl[i]->next = tbl[i+1];
tbl[n-1]->next = NULL;
free(tbl);
}
static int cmp_subnode(const void *ax, const void *bx)
{
const struct node *a, *b;
a = *((const struct node * const *)ax);
b = *((const struct node * const *)bx);
return strcmp(a->name, b->name);
}
static void sort_subnodes(struct node *node)
{
int n = 0, i = 0;
struct node *subnode, **tbl;
for_each_child(node, subnode)
n++;
if (n == 0)
return;
tbl = xmalloc(n * sizeof(*tbl));
for_each_child(node, subnode)
tbl[i++] = subnode;
qsort(tbl, n, sizeof(*tbl), cmp_subnode);
node->children = tbl[0];
for (i = 0; i < (n-1); i++)
tbl[i]->next_sibling = tbl[i+1];
tbl[n-1]->next_sibling = NULL;
free(tbl);
}
static void sort_node(struct node *node)
{
struct node *c;
sort_properties(node);
sort_subnodes(node);
for_each_child(node, c)
sort_node(c);
}
void sort_tree(struct boot_info *bi)
{
sort_reserve_entries(bi);
sort_node(bi->dt);
}

366
srcpos.c
View File

@ -24,126 +24,224 @@
#include "dtc.h"
#include "srcpos.h"
/* A node in our list of directories to search for source/include files */
struct search_path {
struct search_path *next; /* next node in list, NULL for end */
const char *dirname; /* name of directory to search */
};
/*
* Like yylineno, this is the current open file pos.
/* This is the list of directories that we search for source files */
static struct search_path *search_path_head, **search_path_tail;
static char *dirname(const char *path)
{
const char *slash = strrchr(path, '/');
if (slash) {
int len = slash - path;
char *dir = xmalloc(len + 1);
memcpy(dir, path, len);
dir[len] = '\0';
return dir;
}
return NULL;
}
FILE *depfile; /* = NULL */
struct srcfile_state *current_srcfile; /* = NULL */
/* Detect infinite include recursion. */
#define MAX_SRCFILE_DEPTH (100)
static int srcfile_depth; /* = 0 */
/**
* Try to open a file in a given directory.
*
* If the filename is an absolute path, then dirname is ignored. If it is a
* relative path, then we look in that directory for the file.
*
* @param dirname Directory to look in, or NULL for none
* @param fname Filename to look for
* @param fp Set to NULL if file did not open
* @return allocated filename on success (caller must free), NULL on failure
*/
struct dtc_file *srcpos_file;
static char *try_open(const char *dirname, const char *fname, FILE **fp)
{
char *fullname;
if (!dirname || fname[0] == '/')
fullname = xstrdup(fname);
else
fullname = join_path(dirname, fname);
*fp = fopen(fullname, "r");
if (!*fp) {
free(fullname);
fullname = NULL;
}
return fullname;
}
/**
* Open a file for read access
*
* If it is a relative filename, we search the full search path for it.
*
* @param fname Filename to open
* @param fp Returns pointer to opened FILE, or NULL on failure
* @return pointer to allocated filename, which caller must free
*/
static char *fopen_any_on_path(const char *fname, FILE **fp)
{
const char *cur_dir = NULL;
struct search_path *node;
char *fullname;
/* Try current directory first */
assert(fp);
if (current_srcfile)
cur_dir = current_srcfile->dir;
fullname = try_open(cur_dir, fname, fp);
/* Failing that, try each search path in turn */
for (node = search_path_head; !*fp && node; node = node->next)
fullname = try_open(node->dirname, fname, fp);
return fullname;
}
FILE *srcfile_relative_open(const char *fname, char **fullnamep)
{
FILE *f;
char *fullname;
if (streq(fname, "-")) {
f = stdin;
fullname = xstrdup("<stdin>");
} else {
fullname = fopen_any_on_path(fname, &f);
if (!f)
die("Couldn't open \"%s\": %s\n", fname,
strerror(errno));
}
if (depfile)
fprintf(depfile, " %s", fullname);
if (fullnamep)
*fullnamep = fullname;
else
free(fullname);
return f;
}
void srcfile_push(const char *fname)
{
struct srcfile_state *srcfile;
if (srcfile_depth++ >= MAX_SRCFILE_DEPTH)
die("Includes nested too deeply");
srcfile = xmalloc(sizeof(*srcfile));
srcfile->f = srcfile_relative_open(fname, &srcfile->name);
srcfile->dir = dirname(srcfile->name);
srcfile->prev = current_srcfile;
srcfile->lineno = 1;
srcfile->colno = 1;
current_srcfile = srcfile;
}
int srcfile_pop(void)
{
struct srcfile_state *srcfile = current_srcfile;
assert(srcfile);
current_srcfile = srcfile->prev;
if (fclose(srcfile->f))
die("Error closing \"%s\": %s\n", srcfile->name,
strerror(errno));
/* FIXME: We allow the srcfile_state structure to leak,
* because it could still be referenced from a location
* variable being carried through the parser somewhere. To
* fix this we could either allocate all the files from a
* table, or use a pool allocator. */
return current_srcfile ? 1 : 0;
}
void srcfile_add_search_path(const char *dirname)
{
struct search_path *node;
/* Create the node */
node = xmalloc(sizeof(*node));
node->next = NULL;
node->dirname = xstrdup(dirname);
/* Add to the end of our list */
if (search_path_tail)
*search_path_tail = node;
else
search_path_head = node;
search_path_tail = &node->next;
}
/*
* The empty source position.
*/
struct dtc_file dtc_empty_file = {
.dir = NULL,
.name = "<no file>",
.file = NULL
};
srcpos srcpos_empty = {
struct srcpos srcpos_empty = {
.first_line = 0,
.first_column = 0,
.last_line = 0,
.last_column = 0,
.file = &dtc_empty_file
.file = NULL,
};
#define TAB_SIZE 8
static int
dtc_open_one(struct dtc_file *file, const char *search, const char *fname)
void srcpos_update(struct srcpos *pos, const char *text, int len)
{
char *fullname;
int i;
if (search) {
fullname = xmalloc(strlen(search) + strlen(fname) + 2);
pos->file = current_srcfile;
strcpy(fullname, search);
strcat(fullname, "/");
strcat(fullname, fname);
} else {
fullname = xstrdup(fname);
}
pos->first_line = current_srcfile->lineno;
pos->first_column = current_srcfile->colno;
file->file = fopen(fullname, "r");
if (!file->file) {
free(fullname);
return 0;
}
for (i = 0; i < len; i++)
if (text[i] == '\n') {
current_srcfile->lineno++;
current_srcfile->colno = 1;
} else if (text[i] == '\t') {
current_srcfile->colno =
ALIGN(current_srcfile->colno, TAB_SIZE);
} else {
current_srcfile->colno++;
}
file->name = fullname;
return 1;
pos->last_line = current_srcfile->lineno;
pos->last_column = current_srcfile->colno;
}
struct dtc_file *
dtc_open_file(const char *fname, const struct search_path *search)
struct srcpos *
srcpos_copy(struct srcpos *pos)
{
static const struct search_path default_search = { NULL, NULL, NULL };
struct srcpos *pos_new;
struct dtc_file *file;
const char *slash;
file = xmalloc(sizeof(struct dtc_file));
slash = strrchr(fname, '/');
if (slash) {
char *dir = xmalloc(slash - fname + 1);
memcpy(dir, fname, slash - fname);
dir[slash - fname] = 0;
file->dir = dir;
} else {
file->dir = NULL;
}
if (streq(fname, "-")) {
file->name = "stdin";
file->file = stdin;
return file;
}
if (fname[0] == '/') {
file->file = fopen(fname, "r");
if (!file->file)
goto fail;
file->name = xstrdup(fname);
return file;
}
if (!search)
search = &default_search;
while (search) {
if (dtc_open_one(file, search->dir, fname))
return file;
if (errno != ENOENT)
goto fail;
search = search->next;
}
fail:
die("Couldn't open \"%s\": %s\n", fname, strerror(errno));
}
void
dtc_close_file(struct dtc_file *file)
{
if (fclose(file->file))
die("Error closing \"%s\": %s\n", file->name, strerror(errno));
}
srcpos *
srcpos_copy(srcpos *pos)
{
srcpos *pos_new;
pos_new = xmalloc(sizeof(srcpos));
memcpy(pos_new, pos, sizeof(srcpos));
pos_new = xmalloc(sizeof(struct srcpos));
memcpy(pos_new, pos, sizeof(struct srcpos));
return pos_new;
}
@ -151,7 +249,7 @@ srcpos_copy(srcpos *pos)
void
srcpos_dump(srcpos *pos)
srcpos_dump(struct srcpos *pos)
{
printf("file : \"%s\"\n",
pos->file ? (char *) pos->file : "<no file>");
@ -164,67 +262,59 @@ srcpos_dump(srcpos *pos)
char *
srcpos_string(srcpos *pos)
srcpos_string(struct srcpos *pos)
{
const char *fname;
char col_buf[100];
const char *fname = "<no-file>";
char *pos_str;
int rc;
if (!pos) {
fname = "<no-file>";
} else if (pos->file->name) {
if (pos)
fname = pos->file->name;
if (strcmp(fname, "-") == 0)
fname = "stdin";
} else {
fname = "<no-file>";
}
if (pos->first_line == pos->last_line) {
if (pos->first_column == pos->last_column) {
snprintf(col_buf, sizeof(col_buf),
"%d:%d",
pos->first_line, pos->first_column);
} else {
snprintf(col_buf, sizeof(col_buf),
"%d:%d-%d",
pos->first_line,
pos->first_column, pos->last_column);
}
} else {
snprintf(col_buf, sizeof(col_buf),
"%d:%d - %d:%d",
pos->first_line, pos->first_column,
pos->last_line, pos->last_column);
}
if (pos->first_line != pos->last_line)
rc = asprintf(&pos_str, "%s:%d.%d-%d.%d", fname,
pos->first_line, pos->first_column,
pos->last_line, pos->last_column);
else if (pos->first_column != pos->last_column)
rc = asprintf(&pos_str, "%s:%d.%d-%d", fname,
pos->first_line, pos->first_column,
pos->last_column);
else
rc = asprintf(&pos_str, "%s:%d.%d", fname,
pos->first_line, pos->first_column);
if (asprintf(&pos_str, "%s %s", fname, col_buf) == -1)
return "<unknown source position?";
if (rc == -1)
die("Couldn't allocate in srcpos string");
return pos_str;
}
void
srcpos_verror(struct srcpos *pos, char const *fmt, va_list va)
{
const char *srcstr;
srcstr = srcpos_string(pos);
fprintf(stdout, "Error: %s ", srcstr);
vfprintf(stdout, fmt, va);
fprintf(stdout, "\n");
}
void
srcpos_error(srcpos *pos, char const *fmt, ...)
srcpos_error(struct srcpos *pos, char const *fmt, ...)
{
const char *srcstr;
va_list va;
va_start(va, fmt);
srcstr = srcpos_string(pos);
fprintf(stderr, "Error: %s ", srcstr);
vfprintf(stderr, fmt, va);
fprintf(stderr, "\n");
srcpos_verror(pos, fmt, va);
va_end(va);
}
void
srcpos_warn(srcpos *pos, char const *fmt, ...)
srcpos_warn(struct srcpos *pos, char const *fmt, ...)
{
const char *srcstr;
va_list va;

128
srcpos.h
View File

@ -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_ */

View File

@ -5,16 +5,22 @@ LIB_TESTS_L = get_mem_rsv \
node_offset_by_prop_value node_offset_by_phandle \
node_check_compatible node_offset_by_compatible \
get_alias \
char_literal \
sized_cells \
notfound \
setprop_inplace nop_property nop_node \
sw_tree1 \
move_and_save mangle-layout nopulate \
open_pack rw_tree1 set_name setprop del_property del_node \
appendprop1 appendprop2 \
string_escapes references path-references phandle_format \
boot-cpuid incbin \
extra-terminating-null \
dtbs_equal_ordered \
add_subnode_with_nops path_offset_aliases
dtb_reverse dtbs_equal_unordered \
add_subnode_with_nops path_offset_aliases \
utilfdt_test \
integer-expressions
LIB_TESTS = $(LIB_TESTS_L:%=$(TESTS_PREFIX)%)
LIBTREE_TESTS_L = truncated_property
@ -40,13 +46,14 @@ TESTS_CLEANFILES = $(TESTS) $(TESTS_CLEANFILES_L:%=$(TESTS_PREFIX)%)
.PHONY: tests
tests: $(TESTS) $(TESTS_TREES)
$(LIB_TESTS): %: $(TESTS_PREFIX)testutils.o $(LIBFDT_archive)
$(LIB_TESTS): %: $(TESTS_PREFIX)testutils.o util.o $(LIBFDT_archive)
$(DL_LIB_TESTS): %: %.o $(TESTS_PREFIX)testutils.o $(LIBFDT_archive)
$(DL_LIB_TESTS): %: %.o $(TESTS_PREFIX)testutils.o util.o $(LIBFDT_archive)
@$(VECHO) LD [libdl] $@
$(LINK.c) -o $@ $^ -ldl
$(LIBTREE_TESTS): %: $(TESTS_PREFIX)testutils.o $(TESTS_PREFIX)trees.o $(LIBFDT_archive)
$(LIBTREE_TESTS): %: $(TESTS_PREFIX)testutils.o $(TESTS_PREFIX)trees.o \
util.o $(LIBFDT_archive)
$(TESTS_PREFIX)dumptrees: $(TESTS_PREFIX)trees.o
@ -59,13 +66,13 @@ tests_clean:
rm -f $(STD_CLEANFILES:%=$(TESTS_PREFIX)%)
rm -f $(TESTS_CLEANFILES)
check: tests dtc convert-dtsv0
check: tests ${TESTS_BIN}
cd $(TESTS_PREFIX); ./run_tests.sh
checkm: tests dtc convert-dtsv0
checkm: tests ${TESTS_BIN}
cd $(TESTS_PREFIX); ./run_tests.sh -m 2>&1 | tee vglog.$$$$
checkv: tests dtc convert-dtsv0
checkv: tests ${TESTS_BIN}
cd $(TESTS_PREFIX); ./run_tests.sh -v
ifneq ($(DEPTARGETS),)

View File

@ -29,6 +29,31 @@
#include "tests.h"
#include "testdata.h"
int notequal; /* = 0 */
#define MISMATCH(fmt, ...) \
do { \
if (notequal) \
PASS(); \
else \
FAIL(fmt, ##__VA_ARGS__); \
} while (0)
#define MATCH() \
do { \
if (!notequal) \
PASS(); \
else \
FAIL("Trees match which shouldn't"); \
} while (0)
#define CHECK(code) \
{ \
err = (code); \
if (err) \
FAIL(#code ": %s", fdt_strerror(err)); \
}
static void compare_mem_rsv(const void *fdt1, const void *fdt2)
{
int i;
@ -36,23 +61,18 @@ static void compare_mem_rsv(const void *fdt1, const void *fdt2)
int err;
if (fdt_num_mem_rsv(fdt1) != fdt_num_mem_rsv(fdt2))
FAIL("Trees have different number of reserve entries");
MISMATCH("Trees have different number of reserve entries");
for (i = 0; i < fdt_num_mem_rsv(fdt1); i++) {
err = fdt_get_mem_rsv(fdt1, i, &addr1, &size1);
if (err)
FAIL("fdt_get_mem_rsv(fdt1, %d, ...): %s", i,
fdt_strerror(err));
err = fdt_get_mem_rsv(fdt2, i, &addr2, &size2);
if (err)
FAIL("fdt_get_mem_rsv(fdt2, %d, ...): %s", i,
fdt_strerror(err));
CHECK(fdt_get_mem_rsv(fdt1, i, &addr1, &size1));
CHECK(fdt_get_mem_rsv(fdt2, i, &addr2, &size2));
if ((addr1 != addr2) || (size1 != size2))
FAIL("Mismatch in reserve entry %d: "
"(0x%llx, 0x%llx) != (0x%llx, 0x%llx)", i,
(unsigned long long)addr1,
(unsigned long long)size1,
(unsigned long long)addr2,
(unsigned long long)size2);
MISMATCH("Mismatch in reserve entry %d: "
"(0x%llx, 0x%llx) != (0x%llx, 0x%llx)", i,
(unsigned long long)addr1,
(unsigned long long)size1,
(unsigned long long)addr2,
(unsigned long long)size2);
}
}
@ -77,7 +97,7 @@ static void compare_structure(const void *fdt1, const void *fdt2)
} while (tag2 == FDT_NOP);
if (tag1 != tag2)
FAIL("Tag mismatch (%d != %d) at (%d, %d)",
MISMATCH("Tag mismatch (%d != %d) at (%d, %d)",
tag1, tag2, offset1, offset2);
switch (tag1) {
@ -90,9 +110,10 @@ static void compare_structure(const void *fdt1, const void *fdt2)
if (!name2)
FAIL("fdt_get_name(fdt2, %d, ..): %s",
offset2, fdt_strerror(err));
if (!streq(name1, name2))
FAIL("Name mismatch (\"%s\" != \"%s\") at (%d, %d)",
name1, name2, offset1, offset2);
MISMATCH("Name mismatch (\"%s\" != \"%s\") at (%d, %d)",
name1, name2, offset1, offset2);
break;
case FDT_PROP:
@ -106,17 +127,17 @@ static void compare_structure(const void *fdt1, const void *fdt2)
name1 = fdt_string(fdt1, fdt32_to_cpu(prop1->nameoff));
name2 = fdt_string(fdt2, fdt32_to_cpu(prop2->nameoff));
if (!streq(name1, name2))
FAIL("Property name mismatch \"%s\" != \"%s\" "
"at (%d, %d)", name1, name2, offset1, offset2);
MISMATCH("Property name mismatch \"%s\" != \"%s\" "
"at (%d, %d)", name1, name2, offset1, offset2);
len1 = fdt32_to_cpu(prop1->len);
len2 = fdt32_to_cpu(prop2->len);
if (len1 != len2)
FAIL("Property length mismatch %u != %u "
"at (%d, %d)", len1, len2, offset1, offset2);
MISMATCH("Property length mismatch %u != %u "
"at (%d, %d)", len1, len2, offset1, offset2);
if (memcmp(prop1->data, prop2->data, len1) != 0)
FAIL("Property value mismatch at (%d, %d)",
offset1, offset2);
MISMATCH("Property value mismatch at (%d, %d)",
offset1, offset2);
break;
case FDT_END:
@ -131,10 +152,14 @@ int main(int argc, char *argv[])
uint32_t cpuid1, cpuid2;
test_init(argc, argv);
if (argc != 3)
CONFIG("Usage: %s <dtb file> <dtb file>", argv[0]);
fdt1 = load_blob(argv[1]);
fdt2 = load_blob(argv[2]);
if ((argc != 3)
&& ((argc != 4) || !streq(argv[1], "-n")))
CONFIG("Usage: %s [-n] <dtb file> <dtb file>", argv[0]);
if (argc == 4)
notequal = 1;
fdt1 = load_blob(argv[argc-2]);
fdt2 = load_blob(argv[argc-1]);
compare_mem_rsv(fdt1, fdt2);
compare_structure(fdt1, fdt2);
@ -142,8 +167,8 @@ int main(int argc, char *argv[])
cpuid1 = fdt_boot_cpuid_phys(fdt1);
cpuid2 = fdt_boot_cpuid_phys(fdt2);
if (cpuid1 != cpuid2)
FAIL("boot_cpuid_phys mismatch 0x%x != 0x%x",
cpuid1, cpuid2);
MISMATCH("boot_cpuid_phys mismatch 0x%x != 0x%x",
cpuid1, cpuid2);
PASS();
MATCH();
}

View File

@ -4,30 +4,41 @@
for x; do
shift
if [ "$x" = "-n" ]; then
for x; do
shift
if [ "$x" = "--" ]; then
break;
fi
NOCHECKS="$NOCHECKS $x"
done
break;
fi
if [ "$x" = "--" ]; then
break;
fi
CHECKS="$CHECKS $x"
YESCHECKS="$YESCHECKS $x"
done
LOG="tmp.log.$$"
rm -f $TMPFILE $LOG
LOG=tmp.log.$$
rm -f $LOG
trap "rm -f $LOG" 0
verbose_run_log "$LOG" $VALGRIND "$DTC" -o /dev/null "$@"
ret="$?"
if [ "$ret" -gt 127 ]; then
signame=$(kill -l $[ret - 128])
FAIL "Killed by SIG$signame"
fi
FAIL_IF_SIGNAL $ret
for c in $CHECKS; do
for c in $YESCHECKS; do
if ! grep -E "^(ERROR)|(Warning) \($c\):" $LOG > /dev/null; then
FAIL "Failed to trigger check \"$c\""
fi
done
rm -f $LOG
for c in $NOCHECKS; do
if grep -E "^(ERROR)|(Warning) \($c\):" $LOG > /dev/null; then
FAIL "Incorrectly triggered check \"$c\""
fi
done
PASS

View File

@ -28,7 +28,7 @@
#include "tests.h"
#include "testdata.h"
void check_extranull(void *fdt, const char *prop, const char *str, int numnulls)
static void check_extranull(void *fdt, const char *prop, const char *str, int numnulls)
{
int len = strlen(str);
char checkbuf[len+numnulls];

View File

@ -29,7 +29,7 @@
#include "tests.h"
#include "testdata.h"
void check_alias(void *fdt, const char *path, const char *alias)
static void check_alias(void *fdt, const char *path, const char *alias)
{
const char *aliaspath;

View File

@ -6,6 +6,7 @@
/ {
/include/ "include4.dts"
/include/ "include5.dts" = <0xdeadbeef>;
prop-int64 /include/ "include5a.dts";
prop-str = /include/ "include6.dts";
/include/ "include7.dts"

View File

@ -65,7 +65,7 @@ static void new_header(struct bufstate *buf, int version, const void *fdt)
static void add_block(struct bufstate *buf, int version, char block, const void *fdt)
{
int align, size;
int align, size, oldsize;
const void *src;
int offset;
@ -95,9 +95,10 @@ static void add_block(struct bufstate *buf, int version, char block, const void
CONFIG("Bad block '%c'", block);
}
offset = ALIGN(buf->size, align);
oldsize = buf->size;
offset = ALIGN(oldsize, align);
expand_buf(buf, offset+size);
memset(buf->buf + oldsize, 0, offset - oldsize);
memcpy(buf->buf + offset, src, size);

View File

@ -37,27 +37,25 @@ static void check_error(const char *s, int err)
int main(int argc, char *argv[])
{
const struct fdt_property *prop;
void *fdt;
int offset;
int subnode1_offset;
const void *val;
int lenerr;
test_init(argc, argv);
fdt = load_blob_arg(argc, argv);
prop = fdt_get_property(fdt, 0, "nonexistant-property", &lenerr);
fdt_get_property(fdt, 0, "nonexistant-property", &lenerr);
check_error("fdt_get_property(\"nonexistant-property\")", lenerr);
val = fdt_getprop(fdt, 0, "nonexistant-property", &lenerr);
fdt_getprop(fdt, 0, "nonexistant-property", &lenerr);
check_error("fdt_getprop(\"nonexistant-property\"", lenerr);
subnode1_offset = fdt_subnode_offset(fdt, 0, "subnode@1");
if (subnode1_offset < 0)
FAIL("Couldn't find subnode1: %s", fdt_strerror(subnode1_offset));
val = fdt_getprop(fdt, subnode1_offset, "prop-str", &lenerr);
fdt_getprop(fdt, subnode1_offset, "prop-str", &lenerr);
check_error("fdt_getprop(\"prop-str\")", lenerr);
offset = fdt_subnode_offset(fdt, 0, "nonexistant-subnode");

View File

@ -48,6 +48,8 @@ int main(int argc, char *argv[])
bufsize = oldsize * 2;
buf = xmalloc(bufsize);
/* don't leak uninitialized memory into our output */
memset(buf, 0, bufsize);
fdt1 = buf;
err = fdt_open_into(fdt, fdt1, bufsize);

View File

@ -104,5 +104,9 @@ int main(int argc, char *argv[])
FAIL("Mismatch between subnode_offset (%d) and path_offset (%d)",
subsubnode2_offset, subsubnode2_offset_p);
if (subsubnode2_offset2 != subsubnode2_offset2_p)
FAIL("Mismatch between subnode_offset (%d) and path_offset (%d)",
subsubnode2_offset2, subsubnode2_offset2_p);
PASS();
}

View File

@ -29,7 +29,7 @@
#include "tests.h"
#include "testdata.h"
void check_alias(void *fdt, const char *full_path, const char *alias_path)
static void check_alias(void *fdt, const char *full_path, const char *alias_path)
{
int offset, offset_a;

View File

@ -24,11 +24,11 @@ base_run_test() {
tot_pass=$((tot_pass + 1))
else
ret="$?"
if [ "$ret" == "1" ]; then
if [ "$ret" -eq 1 ]; then
tot_config=$((tot_config + 1))
elif [ "$ret" == "2" ]; then
elif [ "$ret" -eq 2 ]; then
tot_fail=$((tot_fail + 1))
elif [ "$ret" == "$VGCODE" ]; then
elif [ "$ret" -eq $VGCODE ]; then
tot_vg=$((tot_vg + 1))
else
tot_strange=$((tot_strange + 1))
@ -36,6 +36,20 @@ base_run_test() {
fi
}
shorten_echo () {
limit=32
echo -n "$1"
shift
for x; do
if [ ${#x} -le $limit ]; then
echo -n " $x"
else
short=$(echo "$x" | head -c$limit)
echo -n " \"$short\"...<${#x} bytes>"
fi
done
}
run_test () {
echo -n "$@: "
if [ -n "$VALGRIND" -a -f $1.supp ]; then
@ -70,6 +84,28 @@ run_wrap_test () {
base_run_test wrap_test "$@"
}
wrap_error () {
(
if verbose_run "$@"; then
FAIL "Expected non-zero return code"
else
ret="$?"
if [ "$ret" -gt 127 ]; then
signame=$(kill -l $((ret - 128)))
FAIL "Killed by SIG$signame"
else
PASS
fi
fi
)
}
run_wrap_error_test () {
shorten_echo "$@"
echo -n " {!= 0}: "
base_run_test wrap_error "$@"
}
run_dtc_test () {
echo -n "dtc $@: "
base_run_test wrap_test $VALGRIND $DTC "$@"
@ -83,6 +119,21 @@ asm_to_so_test () {
run_wrap_test asm_to_so "$@"
}
run_fdtget_test () {
expect="$1"
shift
echo -n "fdtget-runtest.sh "$expect" $@: "
base_run_test sh fdtget-runtest.sh "$expect" "$@"
}
run_fdtput_test () {
expect="$1"
shift
shorten_echo fdtput-runtest.sh "$expect" "$@"
echo -n ": "
base_run_test sh fdtput-runtest.sh "$expect" "$@"
}
tree1_tests () {
TREE=$1
@ -178,6 +229,10 @@ libfdt_tests () {
run_test rw_tree1
tree1_tests rw_tree1.test.dtb
tree1_tests_rw rw_tree1.test.dtb
run_test appendprop1
run_test appendprop2 appendprop1.test.dtb
run_dtc_test -I dts -O dtb -o appendprop.test.dtb appendprop.dts
run_test dtbs_equal_ordered appendprop2.test.dtb appendprop.test.dtb
for basetree in test_tree1.dtb sw_tree1.test.dtb rw_tree1.test.dtb; do
run_test nopulate $basetree
@ -199,22 +254,21 @@ dtc_tests () {
tree1_tests_rw dtc_tree1.test.dtb
run_test dtbs_equal_ordered dtc_tree1.test.dtb test_tree1.dtb
run_dtc_test -I dts -O dtb -o dtc_tree1_dts0.test.dtb test_tree1_dts0.dts
tree1_tests dtc_tree1_dts0.test.dtb
tree1_tests_rw dtc_tree1_dts0.test.dtb
run_dtc_test -I dts -O dtb -o dtc_escapes.test.dtb escapes.dts
run_test string_escapes dtc_escapes.test.dtb
run_dtc_test -I dts -O dtb -o dtc_char_literal.test.dtb char_literal.dts
run_test char_literal dtc_char_literal.test.dtb
run_dtc_test -I dts -O dtb -o dtc_sized_cells.test.dtb sized_cells.dts
run_test sized_cells dtc_sized_cells.test.dtb
run_dtc_test -I dts -O dtb -o dtc_extra-terminating-null.test.dtb extra-terminating-null.dts
run_test extra-terminating-null dtc_extra-terminating-null.test.dtb
run_dtc_test -I dts -O dtb -o dtc_references.test.dtb references.dts
run_test references dtc_references.test.dtb
run_dtc_test -I dts -O dtb -o dtc_references_dts0.test.dtb references_dts0.dts
run_test references dtc_references_dts0.test.dtb
run_dtc_test -I dts -O dtb -o dtc_path-references.test.dtb path-references.dts
run_test path-references dtc_path-references.test.dtb
@ -224,6 +278,11 @@ dtc_tests () {
run_test phandle_format dtc_references.test.$f.dtb $f
done
run_dtc_test -I dts -O dtb -o multilabel.test.dtb multilabel.dts
run_test references multilabel.test.dtb
run_dtc_test -I dts -O dtb -o label_repeated.test.dtb label_repeated.dts
run_dtc_test -I dts -O dtb -o dtc_comments.test.dtb comments.dts
run_dtc_test -I dts -O dtb -o dtc_comments-cmp.test.dtb comments-cmp.dts
run_test dtbs_equal_ordered dtc_comments.test.dtb dtc_comments-cmp.test.dtb
@ -242,12 +301,26 @@ dtc_tests () {
run_test incbin incbin.test.dtb
# Check boot_cpuid_phys handling
run_dtc_test -I dts -O dtb -b 17 -o boot_cpuid.test.dtb empty.dts
run_test boot-cpuid boot_cpuid.test.dtb 17
run_dtc_test -I dtb -O dtb -b 17 -o boot_cpuid_test_tree1.test.dtb test_tree1.dtb
run_test boot-cpuid boot_cpuid_test_tree1.test.dtb 17
run_dtc_test -I dtb -O dtb -o boot_cpuid_preserved_test_tree1.test.dtb boot_cpuid_test_tree1.test.dtb
run_test dtbs_equal_ordered boot_cpuid_preserved_test_tree1.test.dtb boot_cpuid_test_tree1.test.dtb
run_dtc_test -I dts -O dtb -o boot_cpuid.test.dtb boot-cpuid.dts
run_test boot-cpuid boot_cpuid.test.dtb 16
run_dtc_test -I dts -O dtb -b 17 -o boot_cpuid_17.test.dtb boot-cpuid.dts
run_test boot-cpuid boot_cpuid_17.test.dtb 17
run_dtc_test -I dtb -O dtb -o preserve_boot_cpuid.test.dtb boot_cpuid.test.dtb
run_test boot-cpuid preserve_boot_cpuid.test.dtb 16
run_test dtbs_equal_ordered preserve_boot_cpuid.test.dtb boot_cpuid.test.dtb
run_dtc_test -I dtb -O dtb -o preserve_boot_cpuid_17.test.dtb boot_cpuid_17.test.dtb
run_test boot-cpuid preserve_boot_cpuid_17.test.dtb 17
run_test dtbs_equal_ordered preserve_boot_cpuid_17.test.dtb boot_cpuid_17.test.dtb
run_dtc_test -I dtb -O dtb -b17 -o override17_boot_cpuid.test.dtb boot_cpuid.test.dtb
run_test boot-cpuid override17_boot_cpuid.test.dtb 17
run_dtc_test -I dtb -O dtb -b0 -o override0_boot_cpuid_17.test.dtb boot_cpuid_17.test.dtb
run_test boot-cpuid override0_boot_cpuid_17.test.dtb 0
# Check -Oasm mode
for tree in test_tree1.dts escapes.dts references.dts path-references.dts \
@ -283,6 +356,17 @@ dtc_tests () {
done
done
# Check merge/overlay functionality
run_dtc_test -I dts -O dtb -o dtc_tree1_merge.test.dtb test_tree1_merge.dts
tree1_tests dtc_tree1_merge.test.dtb test_tree1.dtb
run_dtc_test -I dts -O dtb -o dtc_tree1_merge_labelled.test.dtb test_tree1_merge_labelled.dts
tree1_tests dtc_tree1_merge_labelled.test.dtb test_tree1.dtb
run_dtc_test -I dts -O dtb -o multilabel_merge.test.dtb multilabel_merge.dts
run_test references multilabel.test.dtb
run_test dtbs_equal_ordered multilabel.test.dtb multilabel_merge.test.dtb
run_dtc_test -I dts -O dtb -o dtc_tree1_merge_path.test.dtb test_tree1_merge_path.dts
tree1_tests dtc_tree1_merge_path.test.dtb test_tree1.dtb
# Check some checks
check_tests dup-nodename.dts duplicate_node_names
check_tests dup-propname.dts duplicate_property_names
@ -291,6 +375,7 @@ dtc_tests () {
check_tests minusone-phandle.dts explicit_phandles
run_sh_test dtc-checkfails.sh phandle_references -- -I dts -O dtb nonexist-node-ref.dts
run_sh_test dtc-checkfails.sh phandle_references -- -I dts -O dtb nonexist-label-ref.dts
run_sh_test dtc-fatal.sh -I dts -O dtb nonexist-node-ref2.dts
check_tests bad-name-property.dts name_properties
check_tests bad-ncells.dts address_cells_is_cell size_cells_is_cell interrupt_cells_is_cell
@ -304,16 +389,184 @@ dtc_tests () {
run_sh_test dtc-checkfails.sh node_name_format -- -I dtb -O dtb bad_node_format.dtb
run_sh_test dtc-checkfails.sh prop_name_chars -- -I dtb -O dtb bad_prop_char.dtb
run_sh_test dtc-checkfails.sh duplicate_label -- -I dts -O dtb reuse-label1.dts
run_sh_test dtc-checkfails.sh duplicate_label -- -I dts -O dtb reuse-label2.dts
run_sh_test dtc-checkfails.sh duplicate_label -- -I dts -O dtb reuse-label3.dts
run_sh_test dtc-checkfails.sh duplicate_label -- -I dts -O dtb reuse-label4.dts
run_sh_test dtc-checkfails.sh duplicate_label -- -I dts -O dtb reuse-label5.dts
run_sh_test dtc-checkfails.sh duplicate_label -- -I dts -O dtb reuse-label6.dts
# Check warning options
run_sh_test dtc-checkfails.sh address_cells_is_cell interrupt_cells_is_cell -n size_cells_is_cell -- -Wno_size_cells_is_cell -I dts -O dtb bad-ncells.dts
run_sh_test dtc-fails.sh -n test-warn-output.test.dtb -I dts -O dtb bad-ncells.dts
run_sh_test dtc-fails.sh test-error-output.test.dtb -I dts -O dtb bad-ncells.dts -Esize_cells_is_cell
run_sh_test dtc-checkfails.sh always_fail -- -Walways_fail -I dts -O dtb test_tree1.dts
run_sh_test dtc-checkfails.sh -n always_fail -- -Walways_fail -Wno_always_fail -I dts -O dtb test_tree1.dts
run_sh_test dtc-fails.sh test-negation-1.test.dtb -Ealways_fail -I dts -O dtb test_tree1.dts
run_sh_test dtc-fails.sh -n test-negation-2.test.dtb -Ealways_fail -Eno_always_fail -I dts -O dtb test_tree1.dts
run_sh_test dtc-fails.sh test-negation-3.test.dtb -Ealways_fail -Wno_always_fail -I dts -O dtb test_tree1.dts
run_sh_test dtc-fails.sh -n test-negation-4.test.dtb -Esize_cells_is_cell -Eno_size_cells_is_cell -I dts -O dtb bad-ncells.dts
run_sh_test dtc-checkfails.sh size_cells_is_cell -- -Esize_cells_is_cell -Eno_size_cells_is_cell -I dts -O dtb bad-ncells.dts
# Check for proper behaviour reading from stdin
run_dtc_test -I dts -O dtb -o stdin_dtc_tree1.test.dtb - < test_tree1.dts
run_wrap_test cmp stdin_dtc_tree1.test.dtb dtc_tree1.test.dtb
run_dtc_test -I dtb -O dts -o stdin_odts_test_tree1.dtb.test.dts - < test_tree1.dtb
run_wrap_test cmp stdin_odts_test_tree1.dtb.test.dts odts_test_tree1.dtb.test.dts
# Check integer expresisons
run_test integer-expressions -g integer-expressions.test.dts
run_dtc_test -I dts -O dtb -o integer-expressions.test.dtb integer-expressions.test.dts
run_test integer-expressions integer-expressions.test.dtb
# Check for graceful failure in some error conditions
run_sh_test dtc-fatal.sh -I dts -O dtb nosuchfile.dts
run_sh_test dtc-fatal.sh -I dtb -O dtb nosuchfile.dtb
run_sh_test dtc-fatal.sh -I fs -O dtb nosuchfile
# Dependencies
run_dtc_test -I dts -O dtb -o dependencies.test.dtb -d dependencies.test.d dependencies.dts
run_wrap_test cmp dependencies.test.d dependencies.cmp
# Search paths
run_wrap_error_test $DTC -I dts -O dtb -o search_paths.dtb search_paths.dts
run_dtc_test -i search_dir -I dts -O dtb -o search_paths.dtb \
search_paths.dts
run_wrap_error_test $DTC -i search_dir_b -I dts -O dtb \
-o search_paths_b.dtb search_paths_b.dts
run_dtc_test -i search_dir_b -i search_dir -I dts -O dtb \
-o search_paths_b.dtb search_paths_b.dts
run_dtc_test -I dts -O dtb -o search_paths_subdir.dtb \
search_dir_b/search_paths_subdir.dts
}
cmp_tests () {
basetree="$1"
shift
wrongtrees="$@"
run_test dtb_reverse $basetree
# First dtbs_equal_ordered
run_test dtbs_equal_ordered $basetree $basetree
run_test dtbs_equal_ordered -n $basetree $basetree.reversed.test.dtb
for tree in $wrongtrees; do
run_test dtbs_equal_ordered -n $basetree $tree
done
# now unordered
run_test dtbs_equal_unordered $basetree $basetree
run_test dtbs_equal_unordered $basetree $basetree.reversed.test.dtb
run_test dtbs_equal_unordered $basetree.reversed.test.dtb $basetree
for tree in $wrongtrees; do
run_test dtbs_equal_unordered -n $basetree $tree
done
# now dtc --sort
run_dtc_test -I dtb -O dtb -s -o $basetree.sorted.test.dtb $basetree
run_test dtbs_equal_unordered $basetree $basetree.sorted.test.dtb
run_dtc_test -I dtb -O dtb -s -o $basetree.reversed.sorted.test.dtb $basetree.reversed.test.dtb
run_test dtbs_equal_unordered $basetree.reversed.test.dtb $basetree.reversed.sorted.test.dtb
run_test dtbs_equal_ordered $basetree.sorted.test.dtb $basetree.reversed.sorted.test.dtb
}
dtbs_equal_tests () {
WRONG_TREE1=""
for x in 1 2 3 4 5 6 7 8 9; do
run_dtc_test -I dts -O dtb -o test_tree1_wrong$x.test.dtb test_tree1_wrong$x.dts
WRONG_TREE1="$WRONG_TREE1 test_tree1_wrong$x.test.dtb"
done
cmp_tests test_tree1.dtb $WRONG_TREE1
}
fdtget_tests () {
dts=label01.dts
dtb=$dts.fdtget.test.dtb
run_dtc_test -O dtb -o $dtb $dts
# run_fdtget_test <expected-result> [<flags>] <file> <node> <property>
run_fdtget_test "MyBoardName" $dtb / model
run_fdtget_test "77 121 66 111 \
97 114 100 78 97 109 101 0 77 121 66 111 97 114 100 70 97 109 105 \
108 121 78 97 109 101 0" $dtb / compatible
run_fdtget_test "MyBoardName MyBoardFamilyName" -t s $dtb / compatible
run_fdtget_test 32768 $dtb /cpus/PowerPC,970@1 d-cache-size
run_fdtget_test 8000 -tx $dtb /cpus/PowerPC,970@1 d-cache-size
run_fdtget_test "61 62 63 0" -tbx $dtb /randomnode tricky1
run_fdtget_test "a b c d de ea ad be ef" -tbx $dtb /randomnode blob
# Here the property size is not a multiple of 4 bytes, so it should fail
run_wrap_error_test $DTGET -tlx $dtb /randomnode mixed
run_fdtget_test "6162 6300 1234 0 a 0 b 0 c" -thx $dtb /randomnode mixed
run_fdtget_test "61 62 63 0 12 34 0 0 0 a 0 0 0 b 0 0 0 c" \
-thhx $dtb /randomnode mixed
run_wrap_error_test $DTGET -ts $dtb /randomnode doctor-who
# Test multiple arguments
run_fdtget_test "MyBoardName\nmemory" -ts $dtb / model /memory device_type
# Test defaults
run_wrap_error_test $DTGET -tx $dtb /randomnode doctor-who
run_fdtget_test "<the dead silence>" -tx \
-d "<the dead silence>" $dtb /randomnode doctor-who
run_fdtget_test "<blink>" -tx -d "<blink>" $dtb /memory doctor-who
}
fdtput_tests () {
dts=label01.dts
dtb=$dts.fdtput.test.dtb
text=lorem.txt
# Allow just enough space for $text
run_dtc_test -O dtb -p $(stat -c %s $text) -o $dtb $dts
# run_fdtput_test <expected-result> <file> <node> <property> <flags> <value>
run_fdtput_test "a_model" $dtb / model -ts "a_model"
run_fdtput_test "board1 board2" $dtb / compatible -ts board1 board2
run_fdtput_test "board1 board2" $dtb / compatible -ts "board1 board2"
run_fdtput_test "32768" $dtb /cpus/PowerPC,970@1 d-cache-size "" "32768"
run_fdtput_test "8001" $dtb /cpus/PowerPC,970@1 d-cache-size -tx 0x8001
run_fdtput_test "2 3 12" $dtb /randomnode tricky1 -tbi "02 003 12"
run_fdtput_test "a b c ea ad be ef" $dtb /randomnode blob \
-tbx "a b c ea ad be ef"
run_fdtput_test "a0b0c0d deeaae ef000000" $dtb /randomnode blob \
-tx "a0b0c0d deeaae ef000000"
run_fdtput_test "$(cat $text)" $dtb /randomnode blob -ts "$(cat $text)"
# This should be larger than available space in the fdt
run_wrap_error_test $DTPUT $dtb /randomnode blob -ts "$(cat $text $text)"
# Start again with a fresh dtb
run_dtc_test -O dtb -p $(stat -c %s $text) -o $dtb $dts
# Node creation
run_wrap_error_test $DTPUT $dtb -c /baldrick sod
run_wrap_test $DTPUT $dtb -c /chosen/son /chosen/daughter
run_fdtput_test "eva" $dtb /chosen/daughter name "" -ts "eva"
run_fdtput_test "adam" $dtb /chosen/son name "" -ts "adam"
# Not allowed to create an existing node
run_wrap_error_test $DTPUT $dtb -c /chosen
run_wrap_error_test $DTPUT $dtb -c /chosen/son
# Automatic node creation
run_wrap_test $DTPUT $dtb -cp /blackadder/the-second/turnip \
/blackadder/the-second/potato
run_fdtput_test 1000 $dtb /blackadder/the-second/turnip cost "" 1000
run_fdtput_test "fine wine" $dtb /blackadder/the-second/potato drink \
"-ts" "fine wine"
run_wrap_test $DTPUT $dtb -p /you/are/drunk/sir/winston slurp -ts twice
run_wrap_error_test $DTPUT $dtb -cp "$(cat $text $text)/longish"
# Allowed to create an existing node with -p
run_wrap_test $DTPUT $dtb -cp /chosen
run_wrap_test $DTPUT $dtb -cp /chosen/son
# TODO: Add tests for verbose mode?
}
utilfdt_tests () {
run_test utilfdt_test
}
while getopts "vt:m" ARG ; do
@ -331,7 +584,7 @@ while getopts "vt:m" ARG ; do
done
if [ -z "$TESTSETS" ]; then
TESTSETS="libfdt dtc"
TESTSETS="libfdt utilfdt dtc dtbs_equal fdtget fdtput"
fi
# Make sure we don't have stale blobs lying around
@ -342,9 +595,21 @@ for set in $TESTSETS; do
"libfdt")
libfdt_tests
;;
"utilfdt")
utilfdt_tests
;;
"dtc")
dtc_tests
;;
"dtbs_equal")
dtbs_equal_tests
;;
"fdtget")
fdtget_tests
;;
"fdtput")
fdtput_tests
;;
esac
done

View File

@ -57,23 +57,14 @@ int main(int argc, char *argv[])
fdt = xmalloc(SPACE);
/* First create empty tree with SW */
CHECK(fdt_create(fdt, SPACE));
CHECK(fdt_finish_reservemap(fdt));
CHECK(fdt_begin_node(fdt, ""));
CHECK(fdt_end_node(fdt));
CHECK(fdt_finish(fdt));
verbose_printf("Built empty tree, totalsize = %d\n",
fdt_totalsize(fdt));
CHECK(fdt_open_into(fdt, fdt, SPACE));
CHECK(fdt_create_empty_tree(fdt, SPACE));
CHECK(fdt_add_mem_rsv(fdt, TEST_ADDR_1, TEST_SIZE_1));
CHECK(fdt_add_mem_rsv(fdt, TEST_ADDR_2, TEST_SIZE_2));
CHECK(fdt_setprop_string(fdt, 0, "compatible", "test_tree1"));
CHECK(fdt_setprop_cell(fdt, 0, "prop-int", TEST_VALUE_1));
CHECK(fdt_setprop_u32(fdt, 0, "prop-int", TEST_VALUE_1));
CHECK(fdt_setprop_u64(fdt, 0, "prop-int64", TEST_VALUE64_1));
CHECK(fdt_setprop_string(fdt, 0, "prop-str", TEST_STRING_1));
OFF_CHECK(offset, fdt_add_subnode(fdt, 0, "subnode@1"));

View File

@ -74,5 +74,23 @@ int main(int argc, char *argv[])
check_getprop(fdt, 0, "prop-str", 0, NULL);
err = fdt_setprop_u32(fdt, 0, "prop-u32", TEST_VALUE_2);
if (err)
FAIL("Failed to set \"prop-u32\" to 0x%08x: %s",
TEST_VALUE_2, fdt_strerror(err));
check_getprop_cell(fdt, 0, "prop-u32", TEST_VALUE_2);
err = fdt_setprop_cell(fdt, 0, "prop-cell", TEST_VALUE_2);
if (err)
FAIL("Failed to set \"prop-cell\" to 0x%08x: %s",
TEST_VALUE_2, fdt_strerror(err));
check_getprop_cell(fdt, 0, "prop-cell", TEST_VALUE_2);
err = fdt_setprop_u64(fdt, 0, "prop-u64", TEST_VALUE64_1);
if (err)
FAIL("Failed to set \"prop-u64\" to 0x%016llx: %s",
TEST_VALUE64_1, fdt_strerror(err));
check_getprop_64(fdt, 0, "prop-u64", TEST_VALUE64_1);
PASS();
}

View File

@ -18,6 +18,7 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <inttypes.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@ -34,6 +35,7 @@ int main(int argc, char *argv[])
{
void *fdt;
const uint32_t *intp;
const uint64_t *int64p;
const char *strp;
char *xstr;
int xlen, i;
@ -47,11 +49,25 @@ int main(int argc, char *argv[])
verbose_printf("Old int value was 0x%08x\n", *intp);
err = fdt_setprop_inplace_cell(fdt, 0, "prop-int", ~TEST_VALUE_1);
if (err)
FAIL("Failed to set \"prop-int\" to 0x08%x: %s",
FAIL("Failed to set \"prop-int\" to 0x%08x: %s",
~TEST_VALUE_1, fdt_strerror(err));
intp = check_getprop_cell(fdt, 0, "prop-int", ~TEST_VALUE_1);
verbose_printf("New int value is 0x%08x\n", *intp);
strp = check_getprop(fdt, 0, "prop-str", strlen(TEST_STRING_1)+1,
TEST_STRING_1);
int64p = check_getprop_64(fdt, 0, "prop-int64", TEST_VALUE64_1);
verbose_printf("Old int64 value was 0x%016" PRIx64 "\n", *int64p);
err = fdt_setprop_inplace_u64(fdt, 0, "prop-int64", ~TEST_VALUE64_1);
if (err)
FAIL("Failed to set \"prop-int64\" to 0x%016llx: %s",
~TEST_VALUE64_1, fdt_strerror(err));
int64p = check_getprop_64(fdt, 0, "prop-int64", ~TEST_VALUE64_1);
verbose_printf("New int64 value is 0x%016" PRIx64 "\n", *int64p);
strp = check_getprop(fdt, 0, "prop-str", strlen(TEST_STRING_1)+1,
TEST_STRING_1);

View File

@ -60,7 +60,7 @@ int main(int argc, char *argv[])
void *fdt;
int subnode1_offset, subnode2_offset;
int subsubnode1_offset, subsubnode2_offset, subsubnode2_offset2;
int ss11_off, ss12_off, ss21_off, ss22_off;
int ss12_off, ss21_off;
test_init(argc, argv);
fdt = load_blob_arg(argc, argv);
@ -85,7 +85,7 @@ int main(int argc, char *argv[])
if (subsubnode2_offset != subsubnode2_offset2)
FAIL("Different offsets with and without unit address");
ss11_off = check_subnode(fdt, subnode1_offset, "ss1");
check_subnode(fdt, subnode1_offset, "ss1");
ss21_off = fdt_subnode_offset(fdt, subnode2_offset, "ss1");
if (ss21_off != -FDT_ERR_NOTFOUND)
FAIL("Incorrectly found ss1 in subnode2");
@ -93,7 +93,7 @@ int main(int argc, char *argv[])
ss12_off = fdt_subnode_offset(fdt, subnode1_offset, "ss2");
if (ss12_off != -FDT_ERR_NOTFOUND)
FAIL("Incorrectly found ss2 in subnode1");
ss22_off = check_subnode(fdt, subnode2_offset, "ss2");
check_subnode(fdt, subnode2_offset, "ss2");
PASS();
}

View File

@ -55,7 +55,8 @@ int main(int argc, char *argv[])
CHECK(fdt_begin_node(fdt, ""));
CHECK(fdt_property_string(fdt, "compatible", "test_tree1"));
CHECK(fdt_property_cell(fdt, "prop-int", TEST_VALUE_1));
CHECK(fdt_property_u32(fdt, "prop-int", TEST_VALUE_1));
CHECK(fdt_property_u64(fdt, "prop-int64", TEST_VALUE64_1));
CHECK(fdt_property_string(fdt, "prop-str", TEST_STRING_1));
CHECK(fdt_begin_node(fdt, "subnode@1"));

View File

@ -6,6 +6,7 @@
/ {
compatible = "test_tree1";
prop-int = <0xdeadbeef>;
prop-int64 = /bits/ 64 <0xdeadbeef01abcdef>;
prop-str = "hello world";
subnode@1 {
@ -25,7 +26,7 @@
linux,phandle = <0x2000>;
prop-int = <123456789>;
subsubnode@0 {
ssn0: subsubnode@0 {
phandle = <0x2001>;
compatible = "subsubnode2", "subsubnode";
prop-int = <0726746425>;

View File

@ -12,6 +12,8 @@
#define TEST_VALUE_1 0xdeadbeef
#define TEST_VALUE_2 123456789
#define TEST_VALUE64_1 ASM_CONST_LL(0xdeadbeef01abcdef)
#define PHANDLE_1 0x2000
#define PHANDLE_2 0x2001
@ -19,6 +21,12 @@
#define TEST_STRING_2 "nastystring: \a\b\t\n\v\f\r\\\""
#define TEST_STRING_3 "\xde\xad\xbe\xef"
#define TEST_CHAR1 '\r'
#define TEST_CHAR2 'b'
#define TEST_CHAR3 '\0'
#define TEST_CHAR4 '\''
#define TEST_CHAR5 '\xff'
#ifndef __ASSEMBLY__
extern struct fdt_header _test_tree1;
extern struct fdt_header _truncated_property;

View File

@ -93,22 +93,6 @@ void cleanup(void);
exit(RC_BUG); \
} while (0)
static inline void *xmalloc(size_t size)
{
void *p = malloc(size);
if (! p)
FAIL("malloc() failure");
return p;
}
static inline void *xrealloc(void *p, size_t size)
{
p = realloc(p, size);
if (! p)
FAIL("realloc() failure");
return p;
}
void check_mem_rsv(void *fdt, int n, uint64_t addr, uint64_t size);
void check_property(void *fdt, int nodeoffset, const char *name,
@ -127,6 +111,11 @@ const void *check_getprop(void *fdt, int nodeoffset, const char *name,
uint32_t x = cpu_to_fdt32(val); \
check_getprop(fdt, nodeoffset, name, sizeof(x), &x); \
})
#define check_getprop_64(fdt, nodeoffset, name, val) \
({ \
uint64_t x = cpu_to_fdt64(val); \
check_getprop(fdt, nodeoffset, name, sizeof(x), &x); \
})
#define check_getprop_string(fdt, nodeoffset, name, s) \
check_getprop((fdt), (nodeoffset), (name), strlen(s)+1, (s))
int nodename_eq(const char *s1, const char *s2);
@ -135,4 +124,6 @@ void *load_blob_arg(int argc, char *argv[]);
void save_blob(const char *filename, void *blob);
void *open_blob_rw(void *blob);
#include "util.h"
#endif /* _TESTS_H */

View File

@ -10,7 +10,17 @@ FAIL () {
exit 2
}
FAIL_IF_SIGNAL () {
ret="$1"
if [ "$ret" -gt 127 ]; then
signame=$(kill -l $((ret - 128)))
FAIL "Killed by SIG$signame"
fi
}
DTC=../dtc
DTGET=../fdtget
DTPUT=../fdtput
verbose_run () {
if [ -z "$QUIET_TEST" ]; then
@ -20,6 +30,15 @@ verbose_run () {
fi
}
verbose_run_check () {
verbose_run "$@"
ret="$?"
FAIL_IF_SIGNAL $ret
if [ $ret != 0 ]; then
FAIL "Returned error code $ret"
fi
}
verbose_run_log () {
LOG="$1"
shift
@ -30,3 +49,13 @@ verbose_run_log () {
fi
return $ret
}
verbose_run_log_check () {
verbose_run_log "$@"
ret="$?"
FAIL_IF_SIGNAL $ret
if [ $ret != 0 ]; then
FAIL "Returned error code $ret"
fi
}

View File

@ -159,33 +159,13 @@ int nodename_eq(const char *s1, const char *s2)
void *load_blob(const char *filename)
{
int fd;
int offset = 0;
int bufsize = 1024;
char *p = NULL;
int ret;
char *blob;
int ret = utilfdt_read_err(filename, &blob);
fd = open(filename, O_RDONLY);
if (fd < 0)
if (ret)
CONFIG("Couldn't open blob from \"%s\": %s", filename,
strerror(errno));
p = xmalloc(bufsize);
do {
if (offset == bufsize) {
bufsize *= 2;
p = xrealloc(p, bufsize);
}
ret = read(fd, &p[offset], bufsize - offset);
if (ret < 0)
CONFIG("Couldn't read from \"%s\": %s", filename,
strerror(errno));
offset += ret;
} while (ret != 0);
return p;
strerror(ret));
return blob;
}
void *load_blob_arg(int argc, char *argv[])
@ -197,28 +177,11 @@ void *load_blob_arg(int argc, char *argv[])
void save_blob(const char *filename, void *fdt)
{
int fd;
int totalsize;
int offset;
char *p;
int ret;
int ret = utilfdt_write_err(filename, fdt);
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd < 0)
CONFIG("Couldn't open \"%s\" to write blob: %s", filename,
strerror(errno));
totalsize = fdt_totalsize(fdt);
offset = 0;
p = fdt;
while (offset < totalsize) {
ret = write(fd, p + offset, totalsize - offset);
if (ret < 0)
CONFIG("Couldn't write to \"%s\": %s", filename,
strerror(errno));
offset += ret;
}
if (ret)
CONFIG("Couldn't write blob to \"%s\": %s", filename,
strerror(ret));
}
void *open_blob_rw(void *blob)

View File

@ -52,6 +52,10 @@ tree##_rsvmap_end: ;
PROPHDR(tree, name, 4) \
FDTLONG(val) ;
#define PROP_INT64(tree, name, val) \
PROPHDR(tree, name, 8) \
FDTQUAD(val) ;
#define PROP_STR(tree, name, str) \
PROPHDR(tree, name, 55f - 54f) \
54: \
@ -86,6 +90,7 @@ test_tree1_struct:
BEGIN_NODE("")
PROP_STR(test_tree1, compatible, "test_tree1")
PROP_INT(test_tree1, prop_int, TEST_VALUE_1)
PROP_INT64(test_tree1, prop_int64, TEST_VALUE64_1)
PROP_STR(test_tree1, prop_str, TEST_STRING_1)
BEGIN_NODE("subnode@1")
@ -124,6 +129,7 @@ test_tree1_struct_end:
test_tree1_strings:
STRING(test_tree1, compatible, "compatible")
STRING(test_tree1, prop_int, "prop-int")
STRING(test_tree1, prop_int64, "prop-int64")
STRING(test_tree1, prop_str, "prop-str")
STRING(test_tree1, linux_phandle, "linux,phandle")
STRING(test_tree1, phandle, "phandle")

View File

@ -59,8 +59,8 @@ struct val_label labels3[] = {
{ "end3", -1 },
};
void check_prop_labels(void *sohandle, void *fdt, const char *name,
const struct val_label* labels, int n)
static void check_prop_labels(void *sohandle, void *fdt, const char *name,
const struct val_label* labels, int n)
{
const struct fdt_property *prop;
const char *p;

View File

@ -23,6 +23,7 @@
extern FILE *yyin;
extern int yyparse(void);
extern YYLTYPE yylloc;
struct boot_info *the_boot_info;
int treesource_error;
@ -32,8 +33,9 @@ struct boot_info *dt_from_source(const char *fname)
the_boot_info = NULL;
treesource_error = 0;
srcpos_file = dtc_open_file(fname, NULL);
yyin = srcpos_file->file;
srcfile_push(fname);
yyin = current_srcfile->f;
yylloc.file = current_srcfile;
if (yyparse() != 0)
die("Unable to parse input tree\n");
@ -235,10 +237,11 @@ static void write_tree_source_node(FILE *f, struct node *tree, int level)
{
struct property *prop;
struct node *child;
struct label *l;
write_prefix(f, level);
if (tree->label)
fprintf(f, "%s: ", tree->label);
for_each_label(tree->labels, l)
fprintf(f, "%s: ", l->label);
if (tree->name && (*tree->name))
fprintf(f, "%s {\n", tree->name);
else
@ -246,8 +249,8 @@ static void write_tree_source_node(FILE *f, struct node *tree, int level)
for_each_property(tree, prop) {
write_prefix(f, level+1);
if (prop->label)
fprintf(f, "%s: ", prop->label);
for_each_label(prop->labels, l)
fprintf(f, "%s: ", l->label);
fprintf(f, "%s", prop->name);
write_propval(f, prop);
}
@ -267,8 +270,10 @@ void dt_to_source(FILE *f, struct boot_info *bi)
fprintf(f, "/dts-v1/;\n\n");
for (re = bi->reservelist; re; re = re->next) {
if (re->label)
fprintf(f, "%s: ", re->label);
struct label *l;
for_each_label(re->labels, l)
fprintf(f, "%s: ", l->label);
fprintf(f, "/memreserve/\t0x%016llx 0x%016llx;\n",
(unsigned long long)re->re.address,
(unsigned long long)re->re.size);

303
util.c
View File

@ -1,6 +1,10 @@
/*
* Copyright 2011 The Chromium Authors, All Rights Reserved.
* Copyright 2008 Jon Loeliger, Freescale Semiconductor, Inc.
*
* util_is_printable_string contributed by
* Pantelis Antoniou <pantelis.antoniou AT gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
@ -17,7 +21,19 @@
* USA
*/
#include "dtc.h"
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include "libfdt.h"
#include "util.h"
char *xstrdup(const char *s)
{
@ -28,3 +44,288 @@ char *xstrdup(const char *s)
return dup;
}
char *join_path(const char *path, const char *name)
{
int lenp = strlen(path);
int lenn = strlen(name);
int len;
int needslash = 1;
char *str;
len = lenp + lenn + 2;
if ((lenp > 0) && (path[lenp-1] == '/')) {
needslash = 0;
len--;
}
str = xmalloc(len);
memcpy(str, path, lenp);
if (needslash) {
str[lenp] = '/';
lenp++;
}
memcpy(str+lenp, name, lenn+1);
return str;
}
int util_is_printable_string(const void *data, int len)
{
const char *s = data;
const char *ss;
/* zero length is not */
if (len == 0)
return 0;
/* must terminate with zero */
if (s[len - 1] != '\0')
return 0;
ss = s;
while (*s && isprint(*s))
s++;
/* not zero, or not done yet */
if (*s != '\0' || (s + 1 - ss) < len)
return 0;
return 1;
}
/*
* Parse a octal encoded character starting at index i in string s. The
* resulting character will be returned and the index i will be updated to
* point at the character directly after the end of the encoding, this may be
* the '\0' terminator of the string.
*/
static char get_oct_char(const char *s, int *i)
{
char x[4];
char *endx;
long val;
x[3] = '\0';
strncpy(x, s + *i, 3);
val = strtol(x, &endx, 8);
assert(endx > x);
(*i) += endx - x;
return val;
}
/*
* Parse a hexadecimal encoded character starting at index i in string s. The
* resulting character will be returned and the index i will be updated to
* point at the character directly after the end of the encoding, this may be
* the '\0' terminator of the string.
*/
static char get_hex_char(const char *s, int *i)
{
char x[3];
char *endx;
long val;
x[2] = '\0';
strncpy(x, s + *i, 2);
val = strtol(x, &endx, 16);
if (!(endx > x))
die("\\x used with no following hex digits\n");
(*i) += endx - x;
return val;
}
char get_escape_char(const char *s, int *i)
{
char c = s[*i];
int j = *i + 1;
char val;
assert(c);
switch (c) {
case 'a':
val = '\a';
break;
case 'b':
val = '\b';
break;
case 't':
val = '\t';
break;
case 'n':
val = '\n';
break;
case 'v':
val = '\v';
break;
case 'f':
val = '\f';
break;
case 'r':
val = '\r';
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
j--; /* need to re-read the first digit as
* part of the octal value */
val = get_oct_char(s, &j);
break;
case 'x':
val = get_hex_char(s, &j);
break;
default:
val = c;
}
(*i) = j;
return val;
}
int utilfdt_read_err(const char *filename, char **buffp)
{
int fd = 0; /* assume stdin */
char *buf = NULL;
off_t bufsize = 1024, offset = 0;
int ret = 0;
*buffp = NULL;
if (strcmp(filename, "-") != 0) {
fd = open(filename, O_RDONLY);
if (fd < 0)
return errno;
}
/* Loop until we have read everything */
buf = malloc(bufsize);
do {
/* Expand the buffer to hold the next chunk */
if (offset == bufsize) {
bufsize *= 2;
buf = realloc(buf, bufsize);
if (!buf) {
ret = ENOMEM;
break;
}
}
ret = read(fd, &buf[offset], bufsize - offset);
if (ret < 0) {
ret = errno;
break;
}
offset += ret;
} while (ret != 0);
/* Clean up, including closing stdin; return errno on error */
close(fd);
if (ret)
free(buf);
else
*buffp = buf;
return ret;
}
char *utilfdt_read(const char *filename)
{
char *buff;
int ret = utilfdt_read_err(filename, &buff);
if (ret) {
fprintf(stderr, "Couldn't open blob from '%s': %s\n", filename,
strerror(ret));
return NULL;
}
/* Successful read */
return buff;
}
int utilfdt_write_err(const char *filename, const void *blob)
{
int fd = 1; /* assume stdout */
int totalsize;
int offset;
int ret = 0;
const char *ptr = blob;
if (strcmp(filename, "-") != 0) {
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd < 0)
return errno;
}
totalsize = fdt_totalsize(blob);
offset = 0;
while (offset < totalsize) {
ret = write(fd, ptr + offset, totalsize - offset);
if (ret < 0) {
ret = -errno;
break;
}
offset += ret;
}
/* Close the file/stdin; return errno on error */
if (fd != 1)
close(fd);
return ret < 0 ? -ret : 0;
}
int utilfdt_write(const char *filename, const void *blob)
{
int ret = utilfdt_write_err(filename, blob);
if (ret) {
fprintf(stderr, "Couldn't write blob to '%s': %s\n", filename,
strerror(ret));
}
return ret ? -1 : 0;
}
int utilfdt_decode_type(const char *fmt, int *type, int *size)
{
int qualifier = 0;
if (!*fmt)
return -1;
/* get the conversion qualifier */
*size = -1;
if (strchr("hlLb", *fmt)) {
qualifier = *fmt++;
if (qualifier == *fmt) {
switch (*fmt++) {
/* TODO: case 'l': qualifier = 'L'; break;*/
case 'h':
qualifier = 'b';
break;
}
}
}
/* we should now have a type */
if ((*fmt == '\0') || !strchr("iuxs", *fmt))
return -1;
/* convert qualifier (bhL) to byte size */
if (*fmt != 's')
*size = qualifier == 'b' ? 1 :
qualifier == 'h' ? 2 :
qualifier == 'l' ? 4 : -1;
*type = *fmt++;
/* that should be it! */
if (*fmt)
return -1;
return 0;
}

98
util.h
View File

@ -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 */