Update DTC to git d75b33af676d0beac8398651a7f09037555a550b.
Obtained from: git://git.jdl.com/software/dtc.git
This commit is contained in:
parent
cb591ed209
commit
b7b62f4139
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/vendor/dtc/dist/; revision=204433 svn path=/vendor/dtc/dtc-d75b33af/; revision=204434; tag=vendor/dtc/dtc-d75b33af
@ -19,6 +19,10 @@ II - The DT block format
|
||||
|
||||
III - libfdt
|
||||
|
||||
IV - Utility Tools
|
||||
1) convert-dtsv0 -- Conversion to Version 1
|
||||
1) ftdump
|
||||
|
||||
|
||||
I - "dtc", the device tree compiler
|
||||
===================================
|
||||
@ -28,7 +32,7 @@ I - "dtc", the device tree compiler
|
||||
Source code for the Device Tree Compiler can be found at jdl.com.
|
||||
The gitweb interface is:
|
||||
|
||||
http://www.jdl.com/git_repos/
|
||||
http://git.jdl.com/gitweb/
|
||||
|
||||
The repository is here:
|
||||
|
||||
@ -37,7 +41,7 @@ The repository is here:
|
||||
|
||||
Tarballs of the 1.0.0 and latest releases are here:
|
||||
|
||||
http://www.jdl.com/software/dtc-1.0.0.tgz
|
||||
http://www.jdl.com/software/dtc-v1.2.0.tgz
|
||||
http://www.jdl.com/software/dtc-latest.tgz
|
||||
|
||||
|
||||
@ -613,6 +617,36 @@ strings block.
|
||||
|
||||
|
||||
III - libfdt
|
||||
============
|
||||
|
||||
This library should be merged into dtc proper.
|
||||
This library should likely be worked into U-Boot and the kernel.
|
||||
|
||||
|
||||
IV - Utility Tools
|
||||
==================
|
||||
|
||||
1) convert-dtsv0 -- Conversion to Version 1
|
||||
|
||||
convert-dtsv0 is a small utility program which converts (DTS)
|
||||
Device Tree Source from the obsolete version 0 to version 1.
|
||||
|
||||
Version 1 DTS files are marked by line "/dts-v1/;" at the top of the file.
|
||||
|
||||
The syntax of the convert-dtsv0 command line is:
|
||||
|
||||
convert-dtsv0 [<input_filename ... >]
|
||||
|
||||
Each file passed will be converted to the new /dts-v1/ version by creating
|
||||
a new file with a "v1" appended the filename.
|
||||
|
||||
Comments, empty lines, etc. are preserved.
|
||||
|
||||
|
||||
2) ftdump -- Flat Tree dumping utility
|
||||
|
||||
The ftdump program prints a readable version of a flat device tree file.
|
||||
|
||||
The syntax of the ftdump command line is:
|
||||
|
||||
ftdump <DTB-file-name>
|
||||
|
96
Makefile
96
Makefile
@ -16,7 +16,7 @@ LOCAL_VERSION =
|
||||
CONFIG_LOCALVERSION =
|
||||
|
||||
CPPFLAGS = -I libfdt
|
||||
CFLAGS = -Wall -g -Os -Wpointer-arith -Wcast-qual
|
||||
CFLAGS = -Wall -g -Os -fPIC -Wpointer-arith -Wcast-qual
|
||||
|
||||
BISON = bison
|
||||
LEX = flex
|
||||
@ -28,6 +28,17 @@ BINDIR = $(PREFIX)/bin
|
||||
LIBDIR = $(PREFIX)/lib
|
||||
INCLUDEDIR = $(PREFIX)/include
|
||||
|
||||
HOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]' | \
|
||||
sed -e 's/\(cygwin\).*/cygwin/')
|
||||
|
||||
ifeq ($(HOSTOS),darwin)
|
||||
SHAREDLIB_EXT=dylib
|
||||
SHAREDLIB_LINK_OPTIONS=-dynamiclib -Wl,-install_name -Wl,
|
||||
else
|
||||
SHAREDLIB_EXT=so
|
||||
SHAREDLIB_LINK_OPTIONS=-shared -Wl,--version-script=$(LIBFDT_version) -Wl,-soname,
|
||||
endif
|
||||
|
||||
#
|
||||
# Overall rules
|
||||
#
|
||||
@ -46,17 +57,6 @@ else
|
||||
DEPTARGETS = $(filter-out $(NODEPTARGETS),$(MAKECMDGOALS))
|
||||
endif
|
||||
|
||||
all: dtc ftdump convert-dtsv0 libfdt
|
||||
|
||||
install: all
|
||||
@$(VECHO) INSTALL
|
||||
$(INSTALL) -d $(DESTDIR)$(BINDIR)
|
||||
$(INSTALL) -m 755 dtc $(DESTDIR)$(BINDIR)
|
||||
$(INSTALL) -d $(DESTDIR)$(LIBDIR)
|
||||
$(INSTALL) -m 644 $(LIBFDT_lib) $(DESTDIR)$(LIBDIR)
|
||||
$(INSTALL) -d $(DESTDIR)$(INCLUDEDIR)
|
||||
$(INSTALL) -m 644 $(LIBFDT_include) $(DESTDIR)$(INCLUDEDIR)
|
||||
|
||||
#
|
||||
# Rules for versioning
|
||||
#
|
||||
@ -100,63 +100,82 @@ define filechk
|
||||
fi;
|
||||
endef
|
||||
|
||||
$(VERSION_FILE): Makefile FORCE
|
||||
$(call filechk,version)
|
||||
|
||||
#
|
||||
# Rules for dtc proper
|
||||
#
|
||||
include Makefile.convert-dtsv0
|
||||
include Makefile.dtc
|
||||
include Makefile.ftdump
|
||||
|
||||
BIN += convert-dtsv0
|
||||
BIN += dtc
|
||||
BIN += ftdump
|
||||
|
||||
# This stops make from generating the lex and bison output during
|
||||
# auto-dependency computation, but throwing them away as an
|
||||
# intermediate target and building them again "for real"
|
||||
.SECONDARY: $(DTC_GEN_SRCS)
|
||||
|
||||
dtc: $(DTC_OBJS)
|
||||
all: $(BIN) libfdt
|
||||
|
||||
|
||||
ifneq ($(DEPTARGETS),)
|
||||
-include $(DTC_OBJS:%.o=%.d)
|
||||
-include $(CONVERT_OBJS:%.o=%.d)
|
||||
-include $(FTDUMP_OBJS:%.o=%.d)
|
||||
endif
|
||||
#
|
||||
# Rules for ftdump & convert-dtsv0
|
||||
#
|
||||
BIN += ftdump convert-dtsv0
|
||||
|
||||
ftdump: ftdump.o
|
||||
|
||||
convert-dtsv0: convert-dtsv0-lexer.lex.o srcpos.o
|
||||
@$(VECHO) LD $@
|
||||
$(LINK.c) -o $@ $^
|
||||
|
||||
ifneq ($(DEPTARGETS),)
|
||||
-include ftdump.d
|
||||
endif
|
||||
#
|
||||
# Rules for libfdt
|
||||
#
|
||||
LIBFDT_objdir = libfdt
|
||||
LIBFDT_srcdir = libfdt
|
||||
LIBFDT_lib = $(LIBFDT_objdir)/libfdt.a
|
||||
LIBFDT_archive = $(LIBFDT_objdir)/libfdt.a
|
||||
LIBFDT_lib = $(LIBFDT_objdir)/libfdt.$(SHAREDLIB_EXT)
|
||||
LIBFDT_include = $(addprefix $(LIBFDT_srcdir)/,$(LIBFDT_INCLUDES))
|
||||
LIBFDT_version = $(addprefix $(LIBFDT_srcdir)/,$(LIBFDT_VERSION))
|
||||
|
||||
include $(LIBFDT_srcdir)/Makefile.libfdt
|
||||
|
||||
.PHONY: libfdt
|
||||
libfdt: $(LIBFDT_lib)
|
||||
libfdt: $(LIBFDT_archive) $(LIBFDT_lib)
|
||||
|
||||
$(LIBFDT_archive): $(addprefix $(LIBFDT_objdir)/,$(LIBFDT_OBJS))
|
||||
$(LIBFDT_lib): $(addprefix $(LIBFDT_objdir)/,$(LIBFDT_OBJS))
|
||||
|
||||
libfdt_clean:
|
||||
@$(VECHO) CLEAN "(libfdt)"
|
||||
rm -f $(addprefix $(LIBFDT_objdir)/,$(STD_CLEANFILES))
|
||||
rm -f $(LIBFDT_objdir)/*.so
|
||||
|
||||
ifneq ($(DEPTARGETS),)
|
||||
-include $(LIBFDT_OBJS:%.o=$(LIBFDT_objdir)/%.d)
|
||||
endif
|
||||
|
||||
# This stops make from generating the lex and bison output during
|
||||
# auto-dependency computation, but throwing them away as an
|
||||
# intermediate target and building them again "for real"
|
||||
.SECONDARY: $(DTC_GEN_SRCS) $(CONVERT_GEN_SRCS)
|
||||
|
||||
install: all
|
||||
@$(VECHO) INSTALL
|
||||
$(INSTALL) -d $(DESTDIR)$(BINDIR)
|
||||
$(INSTALL) $(BIN) $(DESTDIR)$(BINDIR)
|
||||
$(INSTALL) -d $(DESTDIR)$(LIBDIR)
|
||||
$(INSTALL) $(LIBFDT_lib) $(DESTDIR)$(LIBDIR)
|
||||
$(INSTALL) -m 644 $(LIBFDT_archive) $(DESTDIR)$(LIBDIR)
|
||||
$(INSTALL) -d $(DESTDIR)$(INCLUDEDIR)
|
||||
$(INSTALL) -m 644 $(LIBFDT_include) $(DESTDIR)$(INCLUDEDIR)
|
||||
|
||||
$(VERSION_FILE): Makefile FORCE
|
||||
$(call filechk,version)
|
||||
|
||||
|
||||
dtc: $(DTC_OBJS)
|
||||
|
||||
convert-dtsv0: $(CONVERT_OBJS)
|
||||
@$(VECHO) LD $@
|
||||
$(LINK.c) -o $@ $^
|
||||
|
||||
ftdump: $(FTDUMP_OBJS)
|
||||
|
||||
|
||||
#
|
||||
# Testsuite rules
|
||||
#
|
||||
@ -166,7 +185,7 @@ include tests/Makefile.tests
|
||||
#
|
||||
# Clean rules
|
||||
#
|
||||
STD_CLEANFILES = *~ *.o *.d *.a *.i *.s core a.out vgcore.* \
|
||||
STD_CLEANFILES = *~ *.o *.so *.d *.a *.i *.s core a.out vgcore.* \
|
||||
*.tab.[ch] *.lex.c *.output
|
||||
|
||||
clean: libfdt_clean tests_clean
|
||||
@ -210,6 +229,11 @@ clean: libfdt_clean tests_clean
|
||||
@$(VECHO) AR $@
|
||||
$(AR) $(ARFLAGS) $@ $^
|
||||
|
||||
$(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)
|
||||
|
||||
%.lex.c: %.l
|
||||
@$(VECHO) LEX $@
|
||||
$(LEX) -o$@ $<
|
||||
|
13
Makefile.convert-dtsv0
Normal file
13
Makefile.convert-dtsv0
Normal file
@ -0,0 +1,13 @@
|
||||
#
|
||||
# This is not a complete Makefile of itself.
|
||||
# Instead, it is designed to be easily embeddable
|
||||
# into other systems of Makefiles.
|
||||
#
|
||||
|
||||
CONVERT_SRCS = \
|
||||
srcpos.c \
|
||||
util.c
|
||||
|
||||
CONVERT_GEN_SRCS = convert-dtsv0-lexer.lex.c
|
||||
|
||||
CONVERT_OBJS = $(CONVERT_SRCS:%.c=%.o) $(CONVERT_GEN_SRCS:%.c=%.o)
|
13
Makefile.dtc
13
Makefile.dtc
@ -3,7 +3,16 @@
|
||||
# This is not a complete Makefile of itself. Instead, it is designed to
|
||||
# be easily embeddable into other systems of Makefiles.
|
||||
#
|
||||
DTC_SRCS = dtc.c flattree.c fstree.c data.c livetree.c treesource.c srcpos.c \
|
||||
checks.c
|
||||
DTC_SRCS = \
|
||||
checks.c \
|
||||
data.c \
|
||||
dtc.c \
|
||||
flattree.c \
|
||||
fstree.c \
|
||||
livetree.c \
|
||||
srcpos.c \
|
||||
treesource.c \
|
||||
util.c
|
||||
|
||||
DTC_GEN_SRCS = dtc-lexer.lex.c dtc-parser.tab.c
|
||||
DTC_OBJS = $(DTC_SRCS:%.c=%.o) $(DTC_GEN_SRCS:%.c=%.o)
|
||||
|
12
Makefile.ftdump
Normal file
12
Makefile.ftdump
Normal file
@ -0,0 +1,12 @@
|
||||
#
|
||||
# This is not a complete Makefile of itself.
|
||||
# Instead, it is designed to be easily embeddable
|
||||
# into other systems of Makefiles.
|
||||
#
|
||||
|
||||
FTDUMP_SRCS = \
|
||||
ftdump.c
|
||||
|
||||
FTDUMP_GEN_SRCS =
|
||||
|
||||
FTDUMP_OBJS = $(FTDUMP_SRCS:%.c=%.o) $(FTDUMP_GEN_SRCS:%.c=%.o)
|
46
checks.c
46
checks.c
@ -279,31 +279,55 @@ static void check_property_name_chars(struct check *c, struct node *dt,
|
||||
PROP_CHECK(property_name_chars, PROPNODECHARS, ERROR);
|
||||
|
||||
static void check_explicit_phandles(struct check *c, struct node *root,
|
||||
struct node *node)
|
||||
struct node *node, struct property *prop)
|
||||
{
|
||||
struct property *prop;
|
||||
struct marker *m;
|
||||
struct node *other;
|
||||
cell_t phandle;
|
||||
|
||||
prop = get_property(node, "linux,phandle");
|
||||
if (! prop)
|
||||
return; /* No phandle, that's fine */
|
||||
if (!streq(prop->name, "phandle")
|
||||
&& !streq(prop->name, "linux,phandle"))
|
||||
return;
|
||||
|
||||
if (prop->val.len != sizeof(cell_t)) {
|
||||
FAIL(c, "%s has bad length (%d) linux,phandle property",
|
||||
node->fullpath, prop->val.len);
|
||||
FAIL(c, "%s has bad length (%d) %s property",
|
||||
node->fullpath, prop->val.len, prop->name);
|
||||
return;
|
||||
}
|
||||
|
||||
m = prop->val.markers;
|
||||
for_each_marker_of_type(m, REF_PHANDLE) {
|
||||
assert(m->offset == 0);
|
||||
if (node != get_node_by_ref(root, m->ref))
|
||||
/* "Set this node's phandle equal to some
|
||||
* other node's phandle". That's nonsensical
|
||||
* by construction. */ {
|
||||
FAIL(c, "%s in %s is a reference to another node",
|
||||
prop->name, node->fullpath);
|
||||
return;
|
||||
}
|
||||
/* But setting this node's phandle equal to its own
|
||||
* phandle is allowed - that means allocate a unique
|
||||
* phandle for this node, even if it's not otherwise
|
||||
* referenced. The value will be filled in later, so
|
||||
* no further checking for now. */
|
||||
return;
|
||||
}
|
||||
|
||||
phandle = propval_cell(prop);
|
||||
|
||||
if ((phandle == 0) || (phandle == -1)) {
|
||||
FAIL(c, "%s has invalid linux,phandle value 0x%x",
|
||||
node->fullpath, phandle);
|
||||
FAIL(c, "%s has bad value (0x%x) in %s property",
|
||||
node->fullpath, phandle, prop->name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (node->phandle && (node->phandle != phandle))
|
||||
FAIL(c, "%s has %s property which replaces existing phandle information",
|
||||
node->fullpath, prop->name);
|
||||
|
||||
other = get_node_by_phandle(root, phandle);
|
||||
if (other) {
|
||||
if (other && (other != node)) {
|
||||
FAIL(c, "%s has duplicated phandle 0x%x (seen before at %s)",
|
||||
node->fullpath, phandle, other->fullpath);
|
||||
return;
|
||||
@ -311,7 +335,7 @@ static void check_explicit_phandles(struct check *c, struct node *root,
|
||||
|
||||
node->phandle = phandle;
|
||||
}
|
||||
NODE_CHECK(explicit_phandles, NULL, ERROR);
|
||||
PROP_CHECK(explicit_phandles, NULL, ERROR);
|
||||
|
||||
static void check_name_properties(struct check *c, struct node *root,
|
||||
struct node *node)
|
||||
|
@ -17,7 +17,7 @@
|
||||
* USA
|
||||
*/
|
||||
|
||||
%option noyywrap nounput
|
||||
%option noyywrap nounput noinput
|
||||
|
||||
%x INCLUDE
|
||||
%x BYTESTRING
|
||||
@ -42,6 +42,7 @@ GAP ({WS}|{COMMENT}|{LINECOMMENT})*
|
||||
#include <fnmatch.h>
|
||||
|
||||
#include "srcpos.h"
|
||||
#include "util.h"
|
||||
|
||||
static int v1_tagged; /* = 0 */
|
||||
static int cbase = 16;
|
||||
@ -51,26 +52,6 @@ static char *last_name; /* = NULL */
|
||||
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
|
||||
static inline void __attribute__((noreturn)) die(char * str, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, str);
|
||||
fprintf(stderr, "FATAL ERROR: ");
|
||||
vfprintf(stderr, str, ap);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static inline void *xmalloc(size_t len)
|
||||
{
|
||||
void *new = malloc(len);
|
||||
|
||||
if (! new)
|
||||
die("malloc() failed\n");
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
const struct {
|
||||
const char *pattern;
|
||||
int obase, width;
|
||||
@ -185,7 +166,7 @@ const struct {
|
||||
|
||||
<PROPNODENAME>{PROPNODECHAR}+ {
|
||||
ECHO;
|
||||
last_name = strdup(yytext);
|
||||
last_name = xstrdup(yytext);
|
||||
BEGIN(INITIAL);
|
||||
}
|
||||
|
||||
|
2
data.c
2
data.c
@ -217,7 +217,7 @@ struct data data_insert_at_marker(struct data d, struct marker *m,
|
||||
return d;
|
||||
}
|
||||
|
||||
struct data data_append_markers(struct data d, struct marker *m)
|
||||
static struct data data_append_markers(struct data d, struct marker *m)
|
||||
{
|
||||
struct marker **mp = &d.markers;
|
||||
|
||||
|
82
dtc-lexer.l
82
dtc-lexer.l
@ -18,7 +18,7 @@
|
||||
* USA
|
||||
*/
|
||||
|
||||
%option noyywrap nounput yylineno
|
||||
%option noyywrap nounput noinput yylineno
|
||||
|
||||
%x INCLUDE
|
||||
%x BYTESTRING
|
||||
@ -38,6 +38,11 @@ LINECOMMENT "//".*\n
|
||||
#include "srcpos.h"
|
||||
#include "dtc-parser.tab.h"
|
||||
|
||||
#define YY_USER_ACTION \
|
||||
{ \
|
||||
yylloc.file = srcpos_file; \
|
||||
yylloc.first_line = yylineno; \
|
||||
}
|
||||
|
||||
/*#define LEXDEBUG 1*/
|
||||
|
||||
@ -47,15 +52,10 @@ LINECOMMENT "//".*\n
|
||||
#define DPRINT(fmt, ...) do { } while (0)
|
||||
#endif
|
||||
|
||||
static int dts_version; /* = 0 */
|
||||
static int dts_version = 1;
|
||||
|
||||
#define BEGIN_DEFAULT() if (dts_version == 0) { \
|
||||
DPRINT("<INITIAL>\n"); \
|
||||
BEGIN(INITIAL); \
|
||||
} else { \
|
||||
DPRINT("<V1>\n"); \
|
||||
#define BEGIN_DEFAULT() DPRINT("<V1>\n"); \
|
||||
BEGIN(V1); \
|
||||
}
|
||||
|
||||
static void push_input_file(const char *filename);
|
||||
static int pop_input_file(void);
|
||||
@ -75,18 +75,13 @@ static int pop_input_file(void);
|
||||
}
|
||||
|
||||
<*>{STRING} {
|
||||
yylloc.file = srcpos_file;
|
||||
yylloc.first_line = yylineno;
|
||||
DPRINT("String: %s\n", yytext);
|
||||
yylval.data = data_copy_escape_string(yytext+1,
|
||||
yyleng-2);
|
||||
yylloc.first_line = yylineno;
|
||||
return DT_STRING;
|
||||
}
|
||||
|
||||
<*>"/dts-v1/" {
|
||||
yylloc.file = srcpos_file;
|
||||
yylloc.first_line = yylineno;
|
||||
DPRINT("Keyword: /dts-v1/\n");
|
||||
dts_version = 1;
|
||||
BEGIN_DEFAULT();
|
||||
@ -94,106 +89,57 @@ static int pop_input_file(void);
|
||||
}
|
||||
|
||||
<*>"/memreserve/" {
|
||||
yylloc.file = srcpos_file;
|
||||
yylloc.first_line = yylineno;
|
||||
DPRINT("Keyword: /memreserve/\n");
|
||||
BEGIN_DEFAULT();
|
||||
return DT_MEMRESERVE;
|
||||
}
|
||||
|
||||
<*>{LABEL}: {
|
||||
yylloc.file = srcpos_file;
|
||||
yylloc.first_line = yylineno;
|
||||
DPRINT("Label: %s\n", yytext);
|
||||
yylval.labelref = strdup(yytext);
|
||||
yylval.labelref = xstrdup(yytext);
|
||||
yylval.labelref[yyleng-1] = '\0';
|
||||
return DT_LABEL;
|
||||
}
|
||||
|
||||
<INITIAL>[bodh]# {
|
||||
yylloc.file = srcpos_file;
|
||||
yylloc.first_line = yylineno;
|
||||
if (*yytext == 'b')
|
||||
yylval.cbase = 2;
|
||||
else if (*yytext == 'o')
|
||||
yylval.cbase = 8;
|
||||
else if (*yytext == 'd')
|
||||
yylval.cbase = 10;
|
||||
else
|
||||
yylval.cbase = 16;
|
||||
DPRINT("Base: %d\n", yylval.cbase);
|
||||
return DT_BASE;
|
||||
}
|
||||
|
||||
<INITIAL>[0-9a-fA-F]+ {
|
||||
yylloc.file = srcpos_file;
|
||||
yylloc.first_line = yylineno;
|
||||
yylval.literal = strdup(yytext);
|
||||
DPRINT("Literal: '%s'\n", yylval.literal);
|
||||
return DT_LEGACYLITERAL;
|
||||
}
|
||||
|
||||
<V1>[0-9]+|0[xX][0-9a-fA-F]+ {
|
||||
yylloc.file = srcpos_file;
|
||||
yylloc.first_line = yylineno;
|
||||
yylval.literal = strdup(yytext);
|
||||
yylval.literal = xstrdup(yytext);
|
||||
DPRINT("Literal: '%s'\n", yylval.literal);
|
||||
return DT_LITERAL;
|
||||
}
|
||||
|
||||
\&{LABEL} { /* label reference */
|
||||
yylloc.file = srcpos_file;
|
||||
yylloc.first_line = yylineno;
|
||||
DPRINT("Ref: %s\n", yytext+1);
|
||||
yylval.labelref = strdup(yytext+1);
|
||||
yylval.labelref = xstrdup(yytext+1);
|
||||
return DT_REF;
|
||||
}
|
||||
|
||||
"&{/"{PATHCHAR}+\} { /* new-style path reference */
|
||||
yylloc.file = srcpos_file;
|
||||
yylloc.first_line = yylineno;
|
||||
yytext[yyleng-1] = '\0';
|
||||
DPRINT("Ref: %s\n", yytext+2);
|
||||
yylval.labelref = strdup(yytext+2);
|
||||
return DT_REF;
|
||||
}
|
||||
|
||||
<INITIAL>"&/"{PATHCHAR}+ { /* old-style path reference */
|
||||
yylloc.file = srcpos_file;
|
||||
yylloc.first_line = yylineno;
|
||||
DPRINT("Ref: %s\n", yytext+1);
|
||||
yylval.labelref = strdup(yytext+1);
|
||||
yylval.labelref = xstrdup(yytext+2);
|
||||
return DT_REF;
|
||||
}
|
||||
|
||||
<BYTESTRING>[0-9a-fA-F]{2} {
|
||||
yylloc.file = srcpos_file;
|
||||
yylloc.first_line = yylineno;
|
||||
yylval.byte = strtol(yytext, NULL, 16);
|
||||
DPRINT("Byte: %02x\n", (int)yylval.byte);
|
||||
return DT_BYTE;
|
||||
}
|
||||
|
||||
<BYTESTRING>"]" {
|
||||
yylloc.file = srcpos_file;
|
||||
yylloc.first_line = yylineno;
|
||||
DPRINT("/BYTESTRING\n");
|
||||
BEGIN_DEFAULT();
|
||||
return ']';
|
||||
}
|
||||
|
||||
<PROPNODENAME>{PROPNODECHAR}+ {
|
||||
yylloc.file = srcpos_file;
|
||||
yylloc.first_line = yylineno;
|
||||
DPRINT("PropNodeName: %s\n", yytext);
|
||||
yylval.propnodename = strdup(yytext);
|
||||
yylval.propnodename = xstrdup(yytext);
|
||||
BEGIN_DEFAULT();
|
||||
return DT_PROPNODENAME;
|
||||
}
|
||||
|
||||
"/incbin/" {
|
||||
yylloc.file = srcpos_file;
|
||||
yylloc.first_line = yylineno;
|
||||
DPRINT("Binary Include\n");
|
||||
return DT_INCBIN;
|
||||
}
|
||||
@ -203,8 +149,6 @@ static int pop_input_file(void);
|
||||
<*>{LINECOMMENT}+ /* eat C++-style comments */
|
||||
|
||||
<*>. {
|
||||
yylloc.file = srcpos_file;
|
||||
yylloc.first_line = yylineno;
|
||||
DPRINT("Char: %c (\\x%02x)\n", yytext[0],
|
||||
(unsigned)yytext[0]);
|
||||
if (yytext[0] == '[') {
|
||||
|
75
dtc-parser.y
75
dtc-parser.y
@ -27,6 +27,7 @@
|
||||
#include "srcpos.h"
|
||||
|
||||
extern int yylex(void);
|
||||
extern void yyerror(char const *s);
|
||||
|
||||
extern struct boot_info *the_boot_info;
|
||||
extern int treesource_error;
|
||||
@ -55,7 +56,6 @@ static unsigned long long eval_literal(const char *s, int base, int bits);
|
||||
%token DT_MEMRESERVE
|
||||
%token <propnodename> DT_PROPNODENAME
|
||||
%token <literal> DT_LITERAL
|
||||
%token <literal> DT_LEGACYLITERAL
|
||||
%token <cbase> DT_BASE
|
||||
%token <byte> DT_BYTE
|
||||
%token <data> DT_STRING
|
||||
@ -67,11 +67,8 @@ static unsigned long long eval_literal(const char *s, int base, int bits);
|
||||
%type <data> propdataprefix
|
||||
%type <re> memreserve
|
||||
%type <re> memreserves
|
||||
%type <re> v0_memreserve
|
||||
%type <re> v0_memreserves
|
||||
%type <addr> addr
|
||||
%type <data> celllist
|
||||
%type <cbase> cellbase
|
||||
%type <cell> cellval
|
||||
%type <data> bytestring
|
||||
%type <prop> propdef
|
||||
@ -90,10 +87,6 @@ sourcefile:
|
||||
{
|
||||
the_boot_info = build_boot_info($3, $4, 0);
|
||||
}
|
||||
| v0_memreserves devicetree
|
||||
{
|
||||
the_boot_info = build_boot_info($1, $2, 0);
|
||||
}
|
||||
;
|
||||
|
||||
memreserves:
|
||||
@ -114,37 +107,11 @@ memreserve:
|
||||
}
|
||||
;
|
||||
|
||||
v0_memreserves:
|
||||
/* empty */
|
||||
{
|
||||
$$ = NULL;
|
||||
}
|
||||
| v0_memreserve v0_memreserves
|
||||
{
|
||||
$$ = chain_reserve_entry($1, $2);
|
||||
};
|
||||
;
|
||||
|
||||
v0_memreserve:
|
||||
memreserve
|
||||
{
|
||||
$$ = $1;
|
||||
}
|
||||
| label DT_MEMRESERVE addr '-' addr ';'
|
||||
{
|
||||
$$ = build_reserve_entry($3, $5 - $3 + 1, $1);
|
||||
}
|
||||
;
|
||||
|
||||
addr:
|
||||
DT_LITERAL
|
||||
{
|
||||
$$ = eval_literal($1, 0, 64);
|
||||
}
|
||||
| DT_LEGACYLITERAL
|
||||
{
|
||||
$$ = eval_literal($1, 16, 64);
|
||||
}
|
||||
;
|
||||
|
||||
devicetree:
|
||||
@ -208,9 +175,11 @@ propdata:
|
||||
|
||||
if ($6 != 0)
|
||||
if (fseek(file->file, $6, SEEK_SET) != 0)
|
||||
yyerrorf("Couldn't seek to offset %llu in \"%s\": %s",
|
||||
(unsigned long long)$6,
|
||||
$4.val, strerror(errno));
|
||||
srcpos_error(&yylloc,
|
||||
"Couldn't seek to offset %llu in \"%s\": %s",
|
||||
(unsigned long long)$6,
|
||||
$4.val,
|
||||
strerror(errno));
|
||||
|
||||
d = data_copy_file(file->file, $8);
|
||||
|
||||
@ -269,23 +238,11 @@ celllist:
|
||||
}
|
||||
;
|
||||
|
||||
cellbase:
|
||||
/* empty */
|
||||
{
|
||||
$$ = 16;
|
||||
}
|
||||
| DT_BASE
|
||||
;
|
||||
|
||||
cellval:
|
||||
DT_LITERAL
|
||||
{
|
||||
$$ = eval_literal($1, 0, 32);
|
||||
}
|
||||
| cellbase DT_LEGACYLITERAL
|
||||
{
|
||||
$$ = eval_literal($2, $1, 32);
|
||||
}
|
||||
;
|
||||
|
||||
bytestring:
|
||||
@ -339,26 +296,10 @@ label:
|
||||
|
||||
%%
|
||||
|
||||
void yyerrorf(char const *s, ...)
|
||||
void yyerror(char const *s)
|
||||
{
|
||||
const char *fname = srcpos_file ? srcpos_file->name : "<no-file>";
|
||||
va_list va;
|
||||
va_start(va, s);
|
||||
|
||||
if (strcmp(fname, "-") == 0)
|
||||
fname = "stdin";
|
||||
|
||||
fprintf(stderr, "%s:%d ", fname, yylloc.first_line);
|
||||
vfprintf(stderr, s, va);
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
srcpos_error(&yylloc, "%s", s);
|
||||
treesource_error = 1;
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
void yyerror (char const *s)
|
||||
{
|
||||
yyerrorf("%s", s);
|
||||
}
|
||||
|
||||
static unsigned long long eval_literal(const char *s, int base, int bits)
|
||||
|
23
dtc.c
23
dtc.c
@ -30,6 +30,7 @@ int quiet; /* Level of quietness */
|
||||
int reservenum; /* Number of memory reservation slots */
|
||||
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)
|
||||
{
|
||||
@ -106,6 +107,11 @@ static void __attribute__ ((noreturn)) usage(void)
|
||||
fprintf(stderr, "\t\tForce - try to produce output even if the input tree has errors\n");
|
||||
fprintf(stderr, "\t-v\n");
|
||||
fprintf(stderr, "\t\tPrint DTC version and exit\n");
|
||||
fprintf(stderr, "\t-H <phandle format>\n");
|
||||
fprintf(stderr, "\t\tphandle formats are:\n");
|
||||
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");
|
||||
exit(3);
|
||||
}
|
||||
|
||||
@ -127,7 +133,7 @@ int main(int argc, char *argv[])
|
||||
minsize = 0;
|
||||
padsize = 0;
|
||||
|
||||
while ((opt = getopt(argc, argv, "hI:O:o:V:R:S:p:fcqb:v")) != EOF) {
|
||||
while ((opt = getopt(argc, argv, "hI:O:o:V:R:S:p:fcqb:vH:")) != EOF) {
|
||||
switch (opt) {
|
||||
case 'I':
|
||||
inform = optarg;
|
||||
@ -165,6 +171,18 @@ int main(int argc, char *argv[])
|
||||
case 'v':
|
||||
printf("Version: %s\n", DTC_VERSION);
|
||||
exit(0);
|
||||
case 'H':
|
||||
if (streq(optarg, "legacy"))
|
||||
phandle_format = PHANDLE_LEGACY;
|
||||
else if (streq(optarg, "epapr"))
|
||||
phandle_format = PHANDLE_EPAPR;
|
||||
else if (streq(optarg, "both"))
|
||||
phandle_format = PHANDLE_BOTH;
|
||||
else
|
||||
die("Invalid argument \"%s\" to -H option\n",
|
||||
optarg);
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
default:
|
||||
usage();
|
||||
@ -182,6 +200,9 @@ int main(int argc, char *argv[])
|
||||
if (minsize && padsize)
|
||||
die("Can't set both -p and -S\n");
|
||||
|
||||
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);
|
||||
|
||||
|
43
dtc.h
43
dtc.h
@ -34,7 +34,17 @@
|
||||
#include <libfdt_env.h>
|
||||
#include <fdt.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
#define debug(fmt,args...) printf(fmt, ##args)
|
||||
#else
|
||||
#define debug(fmt,args...)
|
||||
#endif
|
||||
|
||||
|
||||
#define DEFAULT_FDT_VERSION 17
|
||||
|
||||
/*
|
||||
* Command line options
|
||||
*/
|
||||
@ -42,36 +52,11 @@ extern int quiet; /* Level of quietness */
|
||||
extern int reservenum; /* Number of memory reservation slots */
|
||||
extern int minsize; /* Minimum blob size */
|
||||
extern int padsize; /* Additional padding to blob */
|
||||
extern int phandle_format; /* Use linux,phandle or phandle properties */
|
||||
|
||||
static inline void __attribute__((noreturn)) die(char * str, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, str);
|
||||
fprintf(stderr, "FATAL ERROR: ");
|
||||
vfprintf(stderr, str, ap);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static inline void *xmalloc(size_t len)
|
||||
{
|
||||
void *new = malloc(len);
|
||||
|
||||
if (! new)
|
||||
die("malloc() failed\n");
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
static inline void *xrealloc(void *p, size_t len)
|
||||
{
|
||||
void *new = realloc(p, len);
|
||||
|
||||
if (! new)
|
||||
die("realloc() failed (len=%d)\n", len);
|
||||
|
||||
return new;
|
||||
}
|
||||
#define PHANDLE_LEGACY 0x1
|
||||
#define PHANDLE_EPAPR 0x2
|
||||
#define PHANDLE_BOTH 0x3
|
||||
|
||||
typedef uint32_t cell_t;
|
||||
|
||||
|
117
flattree.c
117
flattree.c
@ -127,11 +127,21 @@ static void emit_offset_label(FILE *f, const char *label, int offset)
|
||||
fprintf(f, "%s\t= . + %d\n", label, offset);
|
||||
}
|
||||
|
||||
#define ASM_EMIT_BELONG(f, fmt, ...) \
|
||||
{ \
|
||||
fprintf((f), "\t.byte\t((" fmt ") >> 24) & 0xff\n", __VA_ARGS__); \
|
||||
fprintf((f), "\t.byte\t((" fmt ") >> 16) & 0xff\n", __VA_ARGS__); \
|
||||
fprintf((f), "\t.byte\t((" fmt ") >> 8) & 0xff\n", __VA_ARGS__); \
|
||||
fprintf((f), "\t.byte\t(" fmt ") & 0xff\n", __VA_ARGS__); \
|
||||
}
|
||||
|
||||
static void asm_emit_cell(void *e, cell_t val)
|
||||
{
|
||||
FILE *f = e;
|
||||
|
||||
fprintf(f, "\t.long\t0x%x\n", val);
|
||||
fprintf(f, "\t.byte 0x%02x; .byte 0x%02x; .byte 0x%02x; .byte 0x%02x\n",
|
||||
(val >> 24) & 0xff, (val >> 16) & 0xff,
|
||||
(val >> 8) & 0xff, val & 0xff);
|
||||
}
|
||||
|
||||
static void asm_emit_string(void *e, char *str, int len)
|
||||
@ -156,7 +166,7 @@ static void asm_emit_align(void *e, int a)
|
||||
{
|
||||
FILE *f = e;
|
||||
|
||||
fprintf(f, "\t.balign\t%d\n", a);
|
||||
fprintf(f, "\t.balign\t%d, 0\n", a);
|
||||
}
|
||||
|
||||
static void asm_emit_data(void *e, struct data d)
|
||||
@ -169,8 +179,7 @@ static void asm_emit_data(void *e, struct data d)
|
||||
emit_offset_label(f, m->ref, m->offset);
|
||||
|
||||
while ((d.len - off) >= sizeof(uint32_t)) {
|
||||
fprintf(f, "\t.long\t0x%x\n",
|
||||
fdt32_to_cpu(*((uint32_t *)(d.val+off))));
|
||||
asm_emit_cell(e, fdt32_to_cpu(*((uint32_t *)(d.val+off))));
|
||||
off += sizeof(uint32_t);
|
||||
}
|
||||
|
||||
@ -190,14 +199,16 @@ static void asm_emit_beginnode(void *e, const char *label)
|
||||
fprintf(f, "\t.globl\t%s\n", label);
|
||||
fprintf(f, "%s:\n", label);
|
||||
}
|
||||
fprintf(f, "\t.long\tFDT_BEGIN_NODE\n");
|
||||
fprintf(f, "\t/* FDT_BEGIN_NODE */\n");
|
||||
asm_emit_cell(e, FDT_BEGIN_NODE);
|
||||
}
|
||||
|
||||
static void asm_emit_endnode(void *e, const char *label)
|
||||
{
|
||||
FILE *f = e;
|
||||
|
||||
fprintf(f, "\t.long\tFDT_END_NODE\n");
|
||||
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);
|
||||
@ -212,7 +223,8 @@ static void asm_emit_property(void *e, const char *label)
|
||||
fprintf(f, "\t.globl\t%s\n", label);
|
||||
fprintf(f, "%s:\n", label);
|
||||
}
|
||||
fprintf(f, "\t.long\tFDT_PROP\n");
|
||||
fprintf(f, "\t/* FDT_PROP */\n");
|
||||
asm_emit_cell(e, FDT_PROP);
|
||||
}
|
||||
|
||||
static struct emitter asm_emitter = {
|
||||
@ -413,10 +425,13 @@ void dt_to_blob(FILE *f, struct boot_info *bi, int version)
|
||||
if (padlen > 0)
|
||||
blob = data_append_zeroes(blob, padlen);
|
||||
|
||||
fwrite(blob.val, blob.len, 1, f);
|
||||
|
||||
if (ferror(f))
|
||||
die("Error writing device tree blob: %s\n", strerror(errno));
|
||||
if (fwrite(blob.val, blob.len, 1, f) != 1) {
|
||||
if (ferror(f))
|
||||
die("Error writing device tree blob: %s\n",
|
||||
strerror(errno));
|
||||
else
|
||||
die("Short write on device tree blob\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* data_merge() frees the right-hand element so only the blob
|
||||
@ -455,39 +470,44 @@ void dt_to_asm(FILE *f, struct boot_info *bi, int version)
|
||||
die("Unknown device tree blob version %d\n", version);
|
||||
|
||||
fprintf(f, "/* autogenerated by dtc, do not edit */\n\n");
|
||||
fprintf(f, "#define FDT_MAGIC 0x%x\n", FDT_MAGIC);
|
||||
fprintf(f, "#define FDT_BEGIN_NODE 0x%x\n", FDT_BEGIN_NODE);
|
||||
fprintf(f, "#define FDT_END_NODE 0x%x\n", FDT_END_NODE);
|
||||
fprintf(f, "#define FDT_PROP 0x%x\n", FDT_PROP);
|
||||
fprintf(f, "#define FDT_END 0x%x\n", FDT_END);
|
||||
fprintf(f, "\n");
|
||||
|
||||
emit_label(f, symprefix, "blob_start");
|
||||
emit_label(f, symprefix, "header");
|
||||
fprintf(f, "\t.long\tFDT_MAGIC\t\t\t\t/* magic */\n");
|
||||
fprintf(f, "\t.long\t_%s_blob_abs_end - _%s_blob_start\t/* totalsize */\n",
|
||||
symprefix, symprefix);
|
||||
fprintf(f, "\t.long\t_%s_struct_start - _%s_blob_start\t/* off_dt_struct */\n",
|
||||
symprefix, symprefix);
|
||||
fprintf(f, "\t.long\t_%s_strings_start - _%s_blob_start\t/* off_dt_strings */\n",
|
||||
symprefix, symprefix);
|
||||
fprintf(f, "\t.long\t_%s_reserve_map - _%s_blob_start\t/* off_dt_strings */\n",
|
||||
symprefix, symprefix);
|
||||
fprintf(f, "\t.long\t%d\t\t\t\t\t/* version */\n", vi->version);
|
||||
fprintf(f, "\t.long\t%d\t\t\t\t\t/* last_comp_version */\n",
|
||||
vi->last_comp_version);
|
||||
|
||||
if (vi->flags & FTF_BOOTCPUID)
|
||||
fprintf(f, "\t.long\t%i\t\t\t\t\t/* boot_cpuid_phys */\n",
|
||||
bi->boot_cpuid_phys);
|
||||
|
||||
if (vi->flags & FTF_STRTABSIZE)
|
||||
fprintf(f, "\t.long\t_%s_strings_end - _%s_strings_start\t/* size_dt_strings */\n",
|
||||
fprintf(f, "\t/* magic */\n");
|
||||
asm_emit_cell(f, FDT_MAGIC);
|
||||
fprintf(f, "\t/* totalsize */\n");
|
||||
ASM_EMIT_BELONG(f, "_%s_blob_abs_end - _%s_blob_start",
|
||||
symprefix, symprefix);
|
||||
fprintf(f, "\t/* off_dt_struct */\n");
|
||||
ASM_EMIT_BELONG(f, "_%s_struct_start - _%s_blob_start",
|
||||
symprefix, symprefix);
|
||||
fprintf(f, "\t/* off_dt_strings */\n");
|
||||
ASM_EMIT_BELONG(f, "_%s_strings_start - _%s_blob_start",
|
||||
symprefix, symprefix);
|
||||
fprintf(f, "\t/* off_mem_rsvmap */\n");
|
||||
ASM_EMIT_BELONG(f, "_%s_reserve_map - _%s_blob_start",
|
||||
symprefix, symprefix);
|
||||
fprintf(f, "\t/* version */\n");
|
||||
asm_emit_cell(f, vi->version);
|
||||
fprintf(f, "\t/* last_comp_version */\n");
|
||||
asm_emit_cell(f, vi->last_comp_version);
|
||||
|
||||
if (vi->flags & FTF_STRUCTSIZE)
|
||||
fprintf(f, "\t.long\t_%s_struct_end - _%s_struct_start\t/* size_dt_struct */\n",
|
||||
if (vi->flags & FTF_BOOTCPUID) {
|
||||
fprintf(f, "\t/* boot_cpuid_phys */\n");
|
||||
asm_emit_cell(f, bi->boot_cpuid_phys);
|
||||
}
|
||||
|
||||
if (vi->flags & FTF_STRTABSIZE) {
|
||||
fprintf(f, "\t/* size_dt_strings */\n");
|
||||
ASM_EMIT_BELONG(f, "_%s_strings_end - _%s_strings_start",
|
||||
symprefix, symprefix);
|
||||
}
|
||||
|
||||
if (vi->flags & FTF_STRUCTSIZE) {
|
||||
fprintf(f, "\t/* size_dt_struct */\n");
|
||||
ASM_EMIT_BELONG(f, "_%s_struct_end - _%s_struct_start",
|
||||
symprefix, symprefix);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reserve map entries.
|
||||
@ -509,12 +529,11 @@ void dt_to_asm(FILE *f, struct boot_info *bi, int version)
|
||||
fprintf(f, "\t.globl\t%s\n", re->label);
|
||||
fprintf(f, "%s:\n", re->label);
|
||||
}
|
||||
fprintf(f, "\t.long\t0x%08x, 0x%08x\n",
|
||||
(unsigned int)(re->re.address >> 32),
|
||||
(unsigned int)(re->re.address & 0xffffffff));
|
||||
fprintf(f, "\t.long\t0x%08x, 0x%08x\n",
|
||||
(unsigned int)(re->re.size >> 32),
|
||||
(unsigned int)(re->re.size & 0xffffffff));
|
||||
ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->re.address >> 32));
|
||||
ASM_EMIT_BELONG(f, "0x%08x",
|
||||
(unsigned int)(re->re.address & 0xffffffff));
|
||||
ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->re.size >> 32));
|
||||
ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->re.size & 0xffffffff));
|
||||
}
|
||||
for (i = 0; i < reservenum; i++) {
|
||||
fprintf(f, "\t.long\t0, 0\n\t.long\t0, 0\n");
|
||||
@ -524,7 +543,9 @@ void dt_to_asm(FILE *f, struct boot_info *bi, int version)
|
||||
|
||||
emit_label(f, symprefix, "struct_start");
|
||||
flatten_tree(bi->dt, &asm_emitter, f, &strbuf, vi);
|
||||
fprintf(f, "\t.long\tFDT_END\n");
|
||||
|
||||
fprintf(f, "\t/* FDT_END */\n");
|
||||
asm_emit_cell(f, FDT_END);
|
||||
emit_label(f, symprefix, "struct_end");
|
||||
|
||||
emit_label(f, symprefix, "strings_start");
|
||||
@ -601,7 +622,7 @@ static char *flat_read_string(struct inbuf *inb)
|
||||
len++;
|
||||
} while ((*p++) != '\0');
|
||||
|
||||
str = strdup(inb->ptr);
|
||||
str = xstrdup(inb->ptr);
|
||||
|
||||
inb->ptr += len;
|
||||
|
||||
@ -643,7 +664,7 @@ static char *flat_read_stringtable(struct inbuf *inb, int offset)
|
||||
p++;
|
||||
}
|
||||
|
||||
return strdup(inb->base + offset);
|
||||
return xstrdup(inb->base + offset);
|
||||
}
|
||||
|
||||
static struct property *flat_read_property(struct inbuf *dtbuf,
|
||||
@ -710,7 +731,7 @@ static char *nodename_from_path(const char *ppath, const char *cpath)
|
||||
if (!streq(ppath, "/"))
|
||||
plen++;
|
||||
|
||||
return strdup(cpath + plen);
|
||||
return xstrdup(cpath + plen);
|
||||
}
|
||||
|
||||
static struct node *unflatten_tree(struct inbuf *dtbuf,
|
||||
|
4
fstree.c
4
fstree.c
@ -58,7 +58,7 @@ static struct node *read_fstree(const char *dirname)
|
||||
"WARNING: Cannot open %s: %s\n",
|
||||
tmpnam, strerror(errno));
|
||||
} else {
|
||||
prop = build_property(strdup(de->d_name),
|
||||
prop = build_property(xstrdup(de->d_name),
|
||||
data_copy_file(pfile,
|
||||
st.st_size),
|
||||
NULL);
|
||||
@ -69,7 +69,7 @@ static struct node *read_fstree(const char *dirname)
|
||||
struct node *newchild;
|
||||
|
||||
newchild = read_fstree(tmpnam);
|
||||
newchild = name_node(newchild, strdup(de->d_name),
|
||||
newchild = name_node(newchild, xstrdup(de->d_name),
|
||||
NULL);
|
||||
add_child(tree, newchild);
|
||||
}
|
||||
|
47
ftdump.c
47
ftdump.c
@ -4,15 +4,18 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <fdt.h>
|
||||
#include <libfdt_env.h>
|
||||
|
||||
#define FTDUMP_BUF_SIZE 65536
|
||||
|
||||
#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
|
||||
#define PALIGN(p, a) ((void *)(ALIGN((unsigned long)(p), (a))))
|
||||
#define GET_CELL(p) (p += 4, *((uint32_t *)(p-4)))
|
||||
#define GET_CELL(p) (p += 4, *((const uint32_t *)(p-4)))
|
||||
|
||||
static int is_printable_string(const void *data, int len)
|
||||
{
|
||||
@ -38,10 +41,10 @@ static int is_printable_string(const void *data, int len)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void print_data(const void *data, int len)
|
||||
static void print_data(const char *data, int len)
|
||||
{
|
||||
int i;
|
||||
const uint8_t *s;
|
||||
const char *p = data;
|
||||
|
||||
/* no data, don't print */
|
||||
if (len == 0)
|
||||
@ -52,13 +55,13 @@ static void print_data(const void *data, int len)
|
||||
} else if ((len % 4) == 0) {
|
||||
printf(" = <");
|
||||
for (i = 0; i < len; i += 4)
|
||||
printf("%08x%s", *((const uint32_t *)data + i),
|
||||
printf("0x%08x%s", fdt32_to_cpu(GET_CELL(p)),
|
||||
i < (len - 4) ? " " : "");
|
||||
printf(">");
|
||||
} else {
|
||||
printf(" = [");
|
||||
for (i = 0, s = data; i < len; i++)
|
||||
printf("%02x%s", s[i], i < len - 1 ? " " : "");
|
||||
for (i = 0; i < len; i++)
|
||||
printf("%02x%s", *p++, i < len - 1 ? " " : "");
|
||||
printf("]");
|
||||
}
|
||||
}
|
||||
@ -71,13 +74,12 @@ static void dump_blob(void *blob)
|
||||
uint32_t off_str = fdt32_to_cpu(bph->off_dt_strings);
|
||||
struct fdt_reserve_entry *p_rsvmap =
|
||||
(struct fdt_reserve_entry *)((char *)blob + off_mem_rsvmap);
|
||||
char *p_struct = (char *)blob + off_dt;
|
||||
char *p_strings = (char *)blob + off_str;
|
||||
const char *p_struct = (const char *)blob + off_dt;
|
||||
const char *p_strings = (const char *)blob + off_str;
|
||||
uint32_t version = fdt32_to_cpu(bph->version);
|
||||
uint32_t totalsize = fdt32_to_cpu(bph->totalsize);
|
||||
uint32_t tag;
|
||||
char *p;
|
||||
char *s, *t;
|
||||
const char *p, *s, *t;
|
||||
int depth, sz, shift;
|
||||
int i;
|
||||
uint64_t addr, size;
|
||||
@ -85,6 +87,7 @@ static void dump_blob(void *blob)
|
||||
depth = 0;
|
||||
shift = 4;
|
||||
|
||||
printf("/dts-v1/;\n");
|
||||
printf("// magic:\t\t0x%x\n", fdt32_to_cpu(bph->magic));
|
||||
printf("// totalsize:\t\t0x%x (%d)\n", totalsize, totalsize);
|
||||
printf("// off_dt_struct:\t0x%x\n", off_dt);
|
||||
@ -167,7 +170,7 @@ static void dump_blob(void *blob)
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
FILE *fp;
|
||||
char buf[16384]; /* 16k max */
|
||||
char *buf;
|
||||
int size;
|
||||
|
||||
if (argc < 2) {
|
||||
@ -175,15 +178,25 @@ int main(int argc, char *argv[])
|
||||
return 5;
|
||||
}
|
||||
|
||||
fp = fopen(argv[1], "rb");
|
||||
if (fp == NULL) {
|
||||
fprintf(stderr, "unable to open %s\n", argv[1]);
|
||||
if (strcmp(argv[1], "-") == 0) {
|
||||
fp = stdin;
|
||||
} else {
|
||||
fp = fopen(argv[1], "rb");
|
||||
if (fp == NULL) {
|
||||
fprintf(stderr, "unable to open %s\n", argv[1]);
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
|
||||
buf = malloc(FTDUMP_BUF_SIZE);
|
||||
if (!buf) {
|
||||
fprintf(stderr, "Couldn't allocate %d byte buffer\n", FTDUMP_BUF_SIZE);
|
||||
return 10;
|
||||
}
|
||||
|
||||
size = fread(buf, 1, sizeof(buf), fp);
|
||||
if (size == sizeof(buf)) { /* too large */
|
||||
fprintf(stderr, "file too large\n");
|
||||
size = fread(buf, 1, FTDUMP_BUF_SIZE, fp);
|
||||
if (size == FTDUMP_BUF_SIZE) {
|
||||
fprintf(stderr, "file too large (maximum is %d bytes)\n", FTDUMP_BUF_SIZE);
|
||||
return 10;
|
||||
}
|
||||
|
||||
|
@ -4,5 +4,6 @@
|
||||
# be easily embeddable into other systems of Makefiles.
|
||||
#
|
||||
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_OBJS = $(LIBFDT_SRCS:%.c=%.o)
|
||||
|
52
libfdt/fdt.c
52
libfdt/fdt.c
@ -74,7 +74,7 @@ int fdt_check_header(const void *fdt)
|
||||
return 0;
|
||||
}
|
||||
|
||||
const void *fdt_offset_ptr(const void *fdt, int offset, int len)
|
||||
const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
|
||||
{
|
||||
const char *p;
|
||||
|
||||
@ -90,42 +90,53 @@ const void *fdt_offset_ptr(const void *fdt, int offset, int len)
|
||||
return p;
|
||||
}
|
||||
|
||||
uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset)
|
||||
uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
|
||||
{
|
||||
const uint32_t *tagp, *lenp;
|
||||
uint32_t tag;
|
||||
int offset = startoffset;
|
||||
const char *p;
|
||||
|
||||
if (offset % FDT_TAGSIZE)
|
||||
return -1;
|
||||
|
||||
*nextoffset = -FDT_ERR_TRUNCATED;
|
||||
tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
|
||||
if (! tagp)
|
||||
if (!tagp)
|
||||
return FDT_END; /* premature end */
|
||||
tag = fdt32_to_cpu(*tagp);
|
||||
offset += FDT_TAGSIZE;
|
||||
|
||||
*nextoffset = -FDT_ERR_BADSTRUCTURE;
|
||||
switch (tag) {
|
||||
case FDT_BEGIN_NODE:
|
||||
/* skip name */
|
||||
do {
|
||||
p = fdt_offset_ptr(fdt, offset++, 1);
|
||||
} while (p && (*p != '\0'));
|
||||
if (! p)
|
||||
return FDT_END;
|
||||
if (!p)
|
||||
return FDT_END; /* premature end */
|
||||
break;
|
||||
|
||||
case FDT_PROP:
|
||||
lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
|
||||
if (! lenp)
|
||||
return FDT_END;
|
||||
/* skip name offset, length and value */
|
||||
offset += 2*FDT_TAGSIZE + fdt32_to_cpu(*lenp);
|
||||
if (!lenp)
|
||||
return FDT_END; /* premature end */
|
||||
/* skip-name offset, length and value */
|
||||
offset += sizeof(struct fdt_property) - FDT_TAGSIZE
|
||||
+ fdt32_to_cpu(*lenp);
|
||||
break;
|
||||
|
||||
case FDT_END:
|
||||
case FDT_END_NODE:
|
||||
case FDT_NOP:
|
||||
break;
|
||||
|
||||
default:
|
||||
return FDT_END;
|
||||
}
|
||||
|
||||
if (nextoffset)
|
||||
*nextoffset = FDT_TAGALIGN(offset);
|
||||
if (!fdt_offset_ptr(fdt, startoffset, offset - startoffset))
|
||||
return FDT_END; /* premature end */
|
||||
|
||||
*nextoffset = FDT_TAGALIGN(offset);
|
||||
return tag;
|
||||
}
|
||||
|
||||
@ -162,15 +173,16 @@ int fdt_next_node(const void *fdt, int offset, int *depth)
|
||||
break;
|
||||
|
||||
case FDT_END_NODE:
|
||||
if (depth)
|
||||
(*depth)--;
|
||||
if (depth && ((--(*depth)) < 0))
|
||||
return nextoffset;
|
||||
break;
|
||||
|
||||
case FDT_END:
|
||||
return -FDT_ERR_NOTFOUND;
|
||||
|
||||
default:
|
||||
return -FDT_ERR_BADSTRUCTURE;
|
||||
if ((nextoffset >= 0)
|
||||
|| ((nextoffset == -FDT_ERR_TRUNCATED) && !depth))
|
||||
return -FDT_ERR_NOTFOUND;
|
||||
else
|
||||
return nextoffset;
|
||||
}
|
||||
} while (tag != FDT_BEGIN_NODE);
|
||||
|
||||
|
175
libfdt/fdt_ro.c
175
libfdt/fdt_ro.c
@ -80,6 +80,14 @@ const char *fdt_string(const void *fdt, int stroffset)
|
||||
return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
|
||||
}
|
||||
|
||||
static int _fdt_string_eq(const void *fdt, int stroffset,
|
||||
const char *s, int len)
|
||||
{
|
||||
const char *p = fdt_string(fdt, stroffset);
|
||||
|
||||
return (strlen(p) == len) && (memcmp(p, s, len) == 0);
|
||||
}
|
||||
|
||||
int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
|
||||
{
|
||||
FDT_CHECK_HEADER(fdt);
|
||||
@ -105,15 +113,14 @@ int fdt_subnode_offset_namelen(const void *fdt, int offset,
|
||||
FDT_CHECK_HEADER(fdt);
|
||||
|
||||
for (depth = 0;
|
||||
offset >= 0;
|
||||
offset = fdt_next_node(fdt, offset, &depth)) {
|
||||
if (depth < 0)
|
||||
return -FDT_ERR_NOTFOUND;
|
||||
else if ((depth == 1)
|
||||
&& _fdt_nodename_eq(fdt, offset, name, namelen))
|
||||
(offset >= 0) && (depth >= 0);
|
||||
offset = fdt_next_node(fdt, offset, &depth))
|
||||
if ((depth == 1)
|
||||
&& _fdt_nodename_eq(fdt, offset, name, namelen))
|
||||
return offset;
|
||||
}
|
||||
|
||||
if (depth < 0)
|
||||
return -FDT_ERR_NOTFOUND;
|
||||
return offset; /* error */
|
||||
}
|
||||
|
||||
@ -131,8 +138,20 @@ int fdt_path_offset(const void *fdt, const char *path)
|
||||
|
||||
FDT_CHECK_HEADER(fdt);
|
||||
|
||||
if (*path != '/')
|
||||
return -FDT_ERR_BADPATH;
|
||||
/* see if we have an alias */
|
||||
if (*path != '/') {
|
||||
const char *q = strchr(path, '/');
|
||||
|
||||
if (!q)
|
||||
q = end;
|
||||
|
||||
p = fdt_get_alias_namelen(fdt, p, q - p);
|
||||
if (!p)
|
||||
return -FDT_ERR_BADPATH;
|
||||
offset = fdt_path_offset(fdt, p);
|
||||
|
||||
p = q;
|
||||
}
|
||||
|
||||
while (*p) {
|
||||
const char *q;
|
||||
@ -175,13 +194,13 @@ const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct fdt_property *fdt_get_property(const void *fdt,
|
||||
int nodeoffset,
|
||||
const char *name, int *lenp)
|
||||
const struct fdt_property *fdt_get_property_namelen(const void *fdt,
|
||||
int nodeoffset,
|
||||
const char *name,
|
||||
int namelen, int *lenp)
|
||||
{
|
||||
uint32_t tag;
|
||||
const struct fdt_property *prop;
|
||||
int namestroff;
|
||||
int offset, nextoffset;
|
||||
int err;
|
||||
|
||||
@ -196,38 +215,24 @@ const struct fdt_property *fdt_get_property(const void *fdt,
|
||||
tag = fdt_next_tag(fdt, offset, &nextoffset);
|
||||
switch (tag) {
|
||||
case FDT_END:
|
||||
err = -FDT_ERR_TRUNCATED;
|
||||
if (nextoffset < 0)
|
||||
err = nextoffset;
|
||||
else
|
||||
/* FDT_END tag with unclosed nodes */
|
||||
err = -FDT_ERR_BADSTRUCTURE;
|
||||
goto fail;
|
||||
|
||||
case FDT_BEGIN_NODE:
|
||||
case FDT_END_NODE:
|
||||
case FDT_NOP:
|
||||
break;
|
||||
|
||||
case FDT_PROP:
|
||||
err = -FDT_ERR_BADSTRUCTURE;
|
||||
prop = fdt_offset_ptr(fdt, offset, sizeof(*prop));
|
||||
if (! prop)
|
||||
goto fail;
|
||||
namestroff = fdt32_to_cpu(prop->nameoff);
|
||||
if (strcmp(fdt_string(fdt, namestroff), name) == 0) {
|
||||
prop = _fdt_offset_ptr(fdt, offset);
|
||||
if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff),
|
||||
name, namelen)) {
|
||||
/* Found it! */
|
||||
int len = fdt32_to_cpu(prop->len);
|
||||
prop = fdt_offset_ptr(fdt, offset,
|
||||
sizeof(*prop)+len);
|
||||
if (! prop)
|
||||
goto fail;
|
||||
|
||||
if (lenp)
|
||||
*lenp = len;
|
||||
*lenp = fdt32_to_cpu(prop->len);
|
||||
|
||||
return prop;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
err = -FDT_ERR_BADSTRUCTURE;
|
||||
goto fail;
|
||||
}
|
||||
} while ((tag != FDT_BEGIN_NODE) && (tag != FDT_END_NODE));
|
||||
|
||||
@ -238,30 +243,66 @@ const struct fdt_property *fdt_get_property(const void *fdt,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const void *fdt_getprop(const void *fdt, int nodeoffset,
|
||||
const char *name, int *lenp)
|
||||
const struct fdt_property *fdt_get_property(const void *fdt,
|
||||
int nodeoffset,
|
||||
const char *name, int *lenp)
|
||||
{
|
||||
return fdt_get_property_namelen(fdt, nodeoffset, name,
|
||||
strlen(name), lenp);
|
||||
}
|
||||
|
||||
const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
|
||||
const char *name, int namelen, int *lenp)
|
||||
{
|
||||
const struct fdt_property *prop;
|
||||
|
||||
prop = fdt_get_property(fdt, nodeoffset, name, lenp);
|
||||
prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp);
|
||||
if (! prop)
|
||||
return NULL;
|
||||
|
||||
return prop->data;
|
||||
}
|
||||
|
||||
const void *fdt_getprop(const void *fdt, int nodeoffset,
|
||||
const char *name, int *lenp)
|
||||
{
|
||||
return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp);
|
||||
}
|
||||
|
||||
uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
|
||||
{
|
||||
const uint32_t *php;
|
||||
int len;
|
||||
|
||||
php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len);
|
||||
if (!php || (len != sizeof(*php)))
|
||||
return 0;
|
||||
/* FIXME: This is a bit sub-optimal, since we potentially scan
|
||||
* over all the properties twice. */
|
||||
php = fdt_getprop(fdt, nodeoffset, "phandle", &len);
|
||||
if (!php || (len != sizeof(*php))) {
|
||||
php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len);
|
||||
if (!php || (len != sizeof(*php)))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return fdt32_to_cpu(*php);
|
||||
}
|
||||
|
||||
const char *fdt_get_alias_namelen(const void *fdt,
|
||||
const char *name, int namelen)
|
||||
{
|
||||
int aliasoffset;
|
||||
|
||||
aliasoffset = fdt_path_offset(fdt, "/aliases");
|
||||
if (aliasoffset < 0)
|
||||
return NULL;
|
||||
|
||||
return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL);
|
||||
}
|
||||
|
||||
const char *fdt_get_alias(const void *fdt, const char *name)
|
||||
{
|
||||
return fdt_get_alias_namelen(fdt, name, strlen(name));
|
||||
}
|
||||
|
||||
int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
|
||||
{
|
||||
int pdepth = 0, p = 0;
|
||||
@ -276,9 +317,6 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
|
||||
for (offset = 0, depth = 0;
|
||||
(offset >= 0) && (offset <= nodeoffset);
|
||||
offset = fdt_next_node(fdt, offset, &depth)) {
|
||||
if (pdepth < depth)
|
||||
continue; /* overflowed buffer */
|
||||
|
||||
while (pdepth > depth) {
|
||||
do {
|
||||
p--;
|
||||
@ -286,14 +324,16 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
|
||||
pdepth--;
|
||||
}
|
||||
|
||||
name = fdt_get_name(fdt, offset, &namelen);
|
||||
if (!name)
|
||||
return namelen;
|
||||
if ((p + namelen + 1) <= buflen) {
|
||||
memcpy(buf + p, name, namelen);
|
||||
p += namelen;
|
||||
buf[p++] = '/';
|
||||
pdepth++;
|
||||
if (pdepth >= depth) {
|
||||
name = fdt_get_name(fdt, offset, &namelen);
|
||||
if (!name)
|
||||
return namelen;
|
||||
if ((p + namelen + 1) <= buflen) {
|
||||
memcpy(buf + p, name, namelen);
|
||||
p += namelen;
|
||||
buf[p++] = '/';
|
||||
pdepth++;
|
||||
}
|
||||
}
|
||||
|
||||
if (offset == nodeoffset) {
|
||||
@ -303,7 +343,7 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
|
||||
if (p > 1) /* special case so that root path is "/", not "" */
|
||||
p--;
|
||||
buf[p] = '\0';
|
||||
return p;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -401,14 +441,31 @@ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
|
||||
|
||||
int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
|
||||
{
|
||||
int offset;
|
||||
|
||||
if ((phandle == 0) || (phandle == -1))
|
||||
return -FDT_ERR_BADPHANDLE;
|
||||
phandle = cpu_to_fdt32(phandle);
|
||||
return fdt_node_offset_by_prop_value(fdt, -1, "linux,phandle",
|
||||
&phandle, sizeof(phandle));
|
||||
|
||||
FDT_CHECK_HEADER(fdt);
|
||||
|
||||
/* FIXME: The algorithm here is pretty horrible: we
|
||||
* potentially scan each property of a node in
|
||||
* fdt_get_phandle(), then if that didn't find what
|
||||
* we want, we scan over them again making our way to the next
|
||||
* node. Still it's the easiest to implement approach;
|
||||
* performance can come later. */
|
||||
for (offset = fdt_next_node(fdt, -1, NULL);
|
||||
offset >= 0;
|
||||
offset = fdt_next_node(fdt, offset, NULL)) {
|
||||
if (fdt_get_phandle(fdt, offset) == phandle)
|
||||
return offset;
|
||||
}
|
||||
|
||||
return offset; /* error from fdt_next_node() */
|
||||
}
|
||||
|
||||
int _stringlist_contains(const char *strlist, int listlen, const char *str)
|
||||
static int _fdt_stringlist_contains(const char *strlist, int listlen,
|
||||
const char *str)
|
||||
{
|
||||
int len = strlen(str);
|
||||
const char *p;
|
||||
@ -434,7 +491,7 @@ int fdt_node_check_compatible(const void *fdt, int nodeoffset,
|
||||
prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);
|
||||
if (!prop)
|
||||
return len;
|
||||
if (_stringlist_contains(prop, len, compatible))
|
||||
if (_fdt_stringlist_contains(prop, len, compatible))
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
|
@ -406,6 +406,8 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
|
||||
struct_size = 0;
|
||||
while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END)
|
||||
;
|
||||
if (struct_size < 0)
|
||||
return struct_size;
|
||||
}
|
||||
|
||||
if (!_fdt_blocks_misordered(fdt, mem_rsv_size, struct_size)) {
|
||||
|
@ -70,7 +70,7 @@ static int _fdt_sw_check_header(void *fdt)
|
||||
return err; \
|
||||
}
|
||||
|
||||
static void *_fdt_grab_space(void *fdt, int len)
|
||||
static void *_fdt_grab_space(void *fdt, size_t len)
|
||||
{
|
||||
int offset = fdt_size_dt_struct(fdt);
|
||||
int spaceleft;
|
||||
@ -82,7 +82,7 @@ static void *_fdt_grab_space(void *fdt, int len)
|
||||
return NULL;
|
||||
|
||||
fdt_set_size_dt_struct(fdt, offset + len);
|
||||
return fdt_offset_ptr_w(fdt, offset, len);
|
||||
return _fdt_offset_ptr_w(fdt, offset);
|
||||
}
|
||||
|
||||
int fdt_create(void *buf, int bufsize)
|
||||
@ -237,18 +237,17 @@ int fdt_finish(void *fdt)
|
||||
while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) {
|
||||
if (tag == FDT_PROP) {
|
||||
struct fdt_property *prop =
|
||||
fdt_offset_ptr_w(fdt, offset, sizeof(*prop));
|
||||
_fdt_offset_ptr_w(fdt, offset);
|
||||
int nameoff;
|
||||
|
||||
if (! prop)
|
||||
return -FDT_ERR_BADSTRUCTURE;
|
||||
|
||||
nameoff = fdt32_to_cpu(prop->nameoff);
|
||||
nameoff += fdt_size_dt_strings(fdt);
|
||||
prop->nameoff = cpu_to_fdt32(nameoff);
|
||||
}
|
||||
offset = nextoffset;
|
||||
}
|
||||
if (nextoffset < 0)
|
||||
return nextoffset;
|
||||
|
||||
/* Finally, adjust the header */
|
||||
fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt));
|
||||
|
@ -94,41 +94,14 @@ int fdt_nop_property(void *fdt, int nodeoffset, const char *name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _fdt_node_end_offset(void *fdt, int nodeoffset)
|
||||
int _fdt_node_end_offset(void *fdt, int offset)
|
||||
{
|
||||
int level = 0;
|
||||
uint32_t tag;
|
||||
int offset, nextoffset;
|
||||
int depth = 0;
|
||||
|
||||
tag = fdt_next_tag(fdt, nodeoffset, &nextoffset);
|
||||
if (tag != FDT_BEGIN_NODE)
|
||||
return -FDT_ERR_BADOFFSET;
|
||||
do {
|
||||
offset = nextoffset;
|
||||
tag = fdt_next_tag(fdt, offset, &nextoffset);
|
||||
while ((offset >= 0) && (depth >= 0))
|
||||
offset = fdt_next_node(fdt, offset, &depth);
|
||||
|
||||
switch (tag) {
|
||||
case FDT_END:
|
||||
return offset;
|
||||
|
||||
case FDT_BEGIN_NODE:
|
||||
level++;
|
||||
break;
|
||||
|
||||
case FDT_END_NODE:
|
||||
level--;
|
||||
break;
|
||||
|
||||
case FDT_PROP:
|
||||
case FDT_NOP:
|
||||
break;
|
||||
|
||||
default:
|
||||
return -FDT_ERR_BADSTRUCTURE;
|
||||
}
|
||||
} while (level >= 0);
|
||||
|
||||
return nextoffset;
|
||||
return offset;
|
||||
}
|
||||
|
||||
int fdt_nop_node(void *fdt, int nodeoffset)
|
||||
|
@ -122,7 +122,7 @@
|
||||
/* Low-level functions (you probably don't need these) */
|
||||
/**********************************************************************/
|
||||
|
||||
const void *fdt_offset_ptr(const void *fdt, int offset, int checklen);
|
||||
const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int checklen);
|
||||
static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen)
|
||||
{
|
||||
return (void *)(uintptr_t)fdt_offset_ptr(fdt, offset, checklen);
|
||||
@ -156,7 +156,7 @@ int fdt_next_node(const void *fdt, int offset, int *depth);
|
||||
#define __fdt_set_hdr(name) \
|
||||
static inline void fdt_set_##name(void *fdt, uint32_t val) \
|
||||
{ \
|
||||
struct fdt_header *fdth = fdt; \
|
||||
struct fdt_header *fdth = (struct fdt_header*)fdt; \
|
||||
fdth->name = cpu_to_fdt32(val); \
|
||||
}
|
||||
__fdt_set_hdr(magic);
|
||||
@ -342,6 +342,22 @@ int fdt_path_offset(const void *fdt, const char *path);
|
||||
*/
|
||||
const char *fdt_get_name(const void *fdt, int nodeoffset, int *lenp);
|
||||
|
||||
/**
|
||||
* fdt_get_property_namelen - find a property based on substring
|
||||
* @fdt: pointer to the device tree blob
|
||||
* @nodeoffset: offset of the node whose property to find
|
||||
* @name: name of the property to find
|
||||
* @namelen: number of characters of name to consider
|
||||
* @lenp: pointer to an integer variable (will be overwritten) or NULL
|
||||
*
|
||||
* Identical to fdt_get_property_namelen(), but only examine the first
|
||||
* namelen characters of name for matching the property name.
|
||||
*/
|
||||
const struct fdt_property *fdt_get_property_namelen(const void *fdt,
|
||||
int nodeoffset,
|
||||
const char *name,
|
||||
int namelen, int *lenp);
|
||||
|
||||
/**
|
||||
* fdt_get_property - find a given property in a given node
|
||||
* @fdt: pointer to the device tree blob
|
||||
@ -379,6 +395,20 @@ static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset,
|
||||
fdt_get_property(fdt, nodeoffset, name, lenp);
|
||||
}
|
||||
|
||||
/**
|
||||
* fdt_getprop_namelen - get property value based on substring
|
||||
* @fdt: pointer to the device tree blob
|
||||
* @nodeoffset: offset of the node whose property to find
|
||||
* @name: name of the property to find
|
||||
* @namelen: number of characters of name to consider
|
||||
* @lenp: pointer to an integer variable (will be overwritten) or NULL
|
||||
*
|
||||
* Identical to fdt_getprop(), but only examine the first namelen
|
||||
* characters of name for matching the property name.
|
||||
*/
|
||||
const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
|
||||
const char *name, int namelen, int *lenp);
|
||||
|
||||
/**
|
||||
* fdt_getprop - retrieve the value of a given property
|
||||
* @fdt: pointer to the device tree blob
|
||||
@ -428,6 +458,32 @@ static inline void *fdt_getprop_w(void *fdt, int nodeoffset,
|
||||
*/
|
||||
uint32_t fdt_get_phandle(const void *fdt, int nodeoffset);
|
||||
|
||||
/**
|
||||
* fdt_get_alias_namelen - get alias based on substring
|
||||
* @fdt: pointer to the device tree blob
|
||||
* @name: name of the alias th look up
|
||||
* @namelen: number of characters of name to consider
|
||||
*
|
||||
* Identical to fdt_get_alias(), but only examine the first namelen
|
||||
* characters of name for matching the alias name.
|
||||
*/
|
||||
const char *fdt_get_alias_namelen(const void *fdt,
|
||||
const char *name, int namelen);
|
||||
|
||||
/**
|
||||
* fdt_get_alias - retreive the path referenced by a given alias
|
||||
* @fdt: pointer to the device tree blob
|
||||
* @name: name of the alias th look up
|
||||
*
|
||||
* fdt_get_alias() retrieves the value of a given alias. That is, the
|
||||
* value of the property named 'name' in the node /aliases.
|
||||
*
|
||||
* returns:
|
||||
* a pointer to the expansion of the alias named 'name', of it exists
|
||||
* NULL, if the given alias or the /aliases node does not exist
|
||||
*/
|
||||
const char *fdt_get_alias(const void *fdt, const char *name);
|
||||
|
||||
/**
|
||||
* fdt_get_path - determine the full path of a node
|
||||
* @fdt: pointer to the device tree blob
|
||||
|
@ -62,7 +62,6 @@
|
||||
return err; \
|
||||
}
|
||||
|
||||
uint32_t _fdt_next_tag(const void *fdt, int startoffset, int *nextoffset);
|
||||
int _fdt_check_node_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);
|
||||
|
54
libfdt/version.lds
Normal file
54
libfdt/version.lds
Normal file
@ -0,0 +1,54 @@
|
||||
LIBFDT_1.2 {
|
||||
global:
|
||||
fdt_next_node;
|
||||
fdt_check_header;
|
||||
fdt_move;
|
||||
fdt_string;
|
||||
fdt_num_mem_rsv;
|
||||
fdt_get_mem_rsv;
|
||||
fdt_subnode_offset_namelen;
|
||||
fdt_subnode_offset;
|
||||
fdt_path_offset;
|
||||
fdt_get_name;
|
||||
fdt_get_property_namelen;
|
||||
fdt_get_property;
|
||||
fdt_getprop_namelen;
|
||||
fdt_getprop;
|
||||
fdt_get_phandle;
|
||||
fdt_get_alias_namelen;
|
||||
fdt_get_alias;
|
||||
fdt_get_path;
|
||||
fdt_supernode_atdepth_offset;
|
||||
fdt_node_depth;
|
||||
fdt_parent_offset;
|
||||
fdt_node_offset_by_prop_value;
|
||||
fdt_node_offset_by_phandle;
|
||||
fdt_node_check_compatible;
|
||||
fdt_node_offset_by_compatible;
|
||||
fdt_setprop_inplace;
|
||||
fdt_nop_property;
|
||||
fdt_nop_node;
|
||||
fdt_create;
|
||||
fdt_add_reservemap_entry;
|
||||
fdt_finish_reservemap;
|
||||
fdt_begin_node;
|
||||
fdt_property;
|
||||
fdt_end_node;
|
||||
fdt_finish;
|
||||
fdt_open_into;
|
||||
fdt_pack;
|
||||
fdt_add_mem_rsv;
|
||||
fdt_del_mem_rsv;
|
||||
fdt_set_name;
|
||||
fdt_setprop;
|
||||
fdt_delprop;
|
||||
fdt_add_subnode_namelen;
|
||||
fdt_add_subnode;
|
||||
fdt_del_node;
|
||||
fdt_strerror;
|
||||
fdt_offset_ptr;
|
||||
fdt_next_tag;
|
||||
|
||||
local:
|
||||
*;
|
||||
};
|
24
livetree.c
24
livetree.c
@ -293,16 +293,28 @@ cell_t get_node_phandle(struct node *root, struct node *node)
|
||||
if ((node->phandle != 0) && (node->phandle != -1))
|
||||
return node->phandle;
|
||||
|
||||
assert(! get_property(node, "linux,phandle"));
|
||||
|
||||
while (get_node_by_phandle(root, phandle))
|
||||
phandle++;
|
||||
|
||||
node->phandle = phandle;
|
||||
add_property(node,
|
||||
build_property("linux,phandle",
|
||||
data_append_cell(empty_data, phandle),
|
||||
NULL));
|
||||
|
||||
if (!get_property(node, "linux,phandle")
|
||||
&& (phandle_format & PHANDLE_LEGACY))
|
||||
add_property(node,
|
||||
build_property("linux,phandle",
|
||||
data_append_cell(empty_data, phandle),
|
||||
NULL));
|
||||
|
||||
if (!get_property(node, "phandle")
|
||||
&& (phandle_format & PHANDLE_EPAPR))
|
||||
add_property(node,
|
||||
build_property("phandle",
|
||||
data_append_cell(empty_data, phandle),
|
||||
NULL));
|
||||
|
||||
/* If the node *does* have a phandle property, we must
|
||||
* be dealing with a self-referencing phandle, which will be
|
||||
* fixed up momentarily in the caller */
|
||||
|
||||
return node->phandle;
|
||||
}
|
||||
|
148
srcpos.c
148
srcpos.c
@ -17,18 +17,40 @@
|
||||
* USA
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "dtc.h"
|
||||
#include "srcpos.h"
|
||||
|
||||
|
||||
/*
|
||||
* Like yylineno, this is the current open file pos.
|
||||
*/
|
||||
|
||||
struct dtc_file *srcpos_file;
|
||||
|
||||
static int dtc_open_one(struct dtc_file *file,
|
||||
const char *search,
|
||||
const char *fname)
|
||||
/*
|
||||
* The empty source position.
|
||||
*/
|
||||
|
||||
struct dtc_file dtc_empty_file = {
|
||||
.dir = NULL,
|
||||
.name = "<no file>",
|
||||
.file = NULL
|
||||
};
|
||||
|
||||
srcpos srcpos_empty = {
|
||||
.first_line = 0,
|
||||
.first_column = 0,
|
||||
.last_line = 0,
|
||||
.last_column = 0,
|
||||
.file = &dtc_empty_file
|
||||
};
|
||||
|
||||
|
||||
static int
|
||||
dtc_open_one(struct dtc_file *file, const char *search, const char *fname)
|
||||
{
|
||||
char *fullname;
|
||||
|
||||
@ -39,7 +61,7 @@ static int dtc_open_one(struct dtc_file *file,
|
||||
strcat(fullname, "/");
|
||||
strcat(fullname, fname);
|
||||
} else {
|
||||
fullname = strdup(fname);
|
||||
fullname = xstrdup(fname);
|
||||
}
|
||||
|
||||
file->file = fopen(fullname, "r");
|
||||
@ -53,8 +75,8 @@ static int dtc_open_one(struct dtc_file *file,
|
||||
}
|
||||
|
||||
|
||||
struct dtc_file *dtc_open_file(const char *fname,
|
||||
const struct search_path *search)
|
||||
struct dtc_file *
|
||||
dtc_open_file(const char *fname, const struct search_path *search)
|
||||
{
|
||||
static const struct search_path default_search = { NULL, NULL, NULL };
|
||||
|
||||
@ -85,7 +107,7 @@ struct dtc_file *dtc_open_file(const char *fname,
|
||||
if (!file->file)
|
||||
goto fail;
|
||||
|
||||
file->name = strdup(fname);
|
||||
file->name = xstrdup(fname);
|
||||
return file;
|
||||
}
|
||||
|
||||
@ -106,11 +128,113 @@ struct dtc_file *dtc_open_file(const char *fname,
|
||||
die("Couldn't open \"%s\": %s\n", fname, strerror(errno));
|
||||
}
|
||||
|
||||
void dtc_close_file(struct dtc_file *file)
|
||||
|
||||
void
|
||||
dtc_close_file(struct dtc_file *file)
|
||||
{
|
||||
if (fclose(file->file))
|
||||
die("Error closing \"%s\": %s\n", file->name, strerror(errno));
|
||||
|
||||
free(file->dir);
|
||||
free(file);
|
||||
}
|
||||
|
||||
|
||||
srcpos *
|
||||
srcpos_copy(srcpos *pos)
|
||||
{
|
||||
srcpos *pos_new;
|
||||
|
||||
pos_new = xmalloc(sizeof(srcpos));
|
||||
memcpy(pos_new, pos, sizeof(srcpos));
|
||||
|
||||
return pos_new;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
srcpos_dump(srcpos *pos)
|
||||
{
|
||||
printf("file : \"%s\"\n",
|
||||
pos->file ? (char *) pos->file : "<no file>");
|
||||
printf("first_line : %d\n", pos->first_line);
|
||||
printf("first_column: %d\n", pos->first_column);
|
||||
printf("last_line : %d\n", pos->last_line);
|
||||
printf("last_column : %d\n", pos->last_column);
|
||||
printf("file : %s\n", pos->file->name);
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
srcpos_string(srcpos *pos)
|
||||
{
|
||||
const char *fname;
|
||||
char col_buf[100];
|
||||
char *pos_str;
|
||||
|
||||
if (!pos) {
|
||||
fname = "<no-file>";
|
||||
} else if (pos->file->name) {
|
||||
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 (asprintf(&pos_str, "%s %s", fname, col_buf) == -1)
|
||||
return "<unknown source position?";
|
||||
|
||||
return pos_str;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
srcpos_error(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");
|
||||
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
srcpos_warn(srcpos *pos, char const *fmt, ...)
|
||||
{
|
||||
const char *srcstr;
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
|
||||
srcstr = srcpos_string(pos);
|
||||
|
||||
fprintf(stderr, "Warning: %s ", srcstr);
|
||||
vfprintf(stderr, fmt, va);
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
va_end(va);
|
||||
}
|
||||
|
23
srcpos.h
23
srcpos.h
@ -17,6 +17,9 @@
|
||||
* USA
|
||||
*/
|
||||
|
||||
#ifndef _SRCPOS_H_
|
||||
#define _SRCPOS_H_
|
||||
|
||||
/*
|
||||
* Augment the standard YYLTYPE with a filenum index into an
|
||||
* array of all opened filenames.
|
||||
@ -69,9 +72,14 @@ typedef struct YYLTYPE {
|
||||
while (YYID (0))
|
||||
|
||||
|
||||
typedef YYLTYPE srcpos;
|
||||
|
||||
extern void yyerror(char const *);
|
||||
extern void yyerrorf(char const *, ...) __attribute__((format(printf, 1, 2)));
|
||||
/*
|
||||
* 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 dtc_file *srcpos_file;
|
||||
|
||||
@ -83,3 +91,14 @@ struct search_path {
|
||||
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 *, ...)
|
||||
__attribute__((format(printf, 2, 3)));
|
||||
extern void srcpos_warn(srcpos *pos, char const *, ...)
|
||||
__attribute__((format(printf, 2, 3)));
|
||||
|
||||
#endif /* _SRCPOS_H_ */
|
||||
|
@ -4,20 +4,26 @@ LIB_TESTS_L = get_mem_rsv \
|
||||
get_path supernode_atdepth_offset parent_offset \
|
||||
node_offset_by_prop_value node_offset_by_phandle \
|
||||
node_check_compatible node_offset_by_compatible \
|
||||
get_alias \
|
||||
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 \
|
||||
string_escapes references path-references boot-cpuid incbin \
|
||||
string_escapes references path-references phandle_format \
|
||||
boot-cpuid incbin \
|
||||
extra-terminating-null \
|
||||
dtbs_equal_ordered \
|
||||
add_subnode_with_nops
|
||||
add_subnode_with_nops path_offset_aliases
|
||||
LIB_TESTS = $(LIB_TESTS_L:%=$(TESTS_PREFIX)%)
|
||||
|
||||
LIBTREE_TESTS_L = truncated_property
|
||||
LIBTREE_TESTS = $(LIBTREE_TESTS_L:%=$(TESTS_PREFIX)%)
|
||||
|
||||
TESTS = $(LIB_TESTS) $(LIBTREE_TESTS)
|
||||
DL_LIB_TESTS_L = asm_tree_dump value-labels
|
||||
DL_LIB_TESTS = $(DL_LIB_TESTS_L:%=$(TESTS_PREFIX)%)
|
||||
|
||||
TESTS = $(LIB_TESTS) $(LIBTREE_TESTS) $(DL_LIB_TESTS)
|
||||
|
||||
TESTS_TREES_L = test_tree1.dtb
|
||||
TESTS_TREES = $(TESTS_TREES_L:%=$(TESTS_PREFIX)%)
|
||||
@ -28,16 +34,19 @@ TESTS_DEPFILES = $(TESTS:%=%.d) \
|
||||
$(addprefix $(TESTS_PREFIX),testutils.d trees.d dumptrees.d)
|
||||
|
||||
TESTS_CLEANFILES_L = *.output vglog.* vgcore.* *.dtb *.test.dts *.dtsv1 tmp.*
|
||||
TESTS_CLEANFILES = $(TESTS_CLEANFILES_L:%=$(TESTS_PREFIX)%)
|
||||
|
||||
BIN += $(TESTS) $(TESTS_PREFIX)dumptrees
|
||||
TESTS_CLEANFILES_L += dumptrees
|
||||
TESTS_CLEANFILES = $(TESTS) $(TESTS_CLEANFILES_L:%=$(TESTS_PREFIX)%)
|
||||
|
||||
.PHONY: tests
|
||||
tests: $(TESTS) $(TESTS_TREES)
|
||||
|
||||
$(LIB_TESTS): %: $(TESTS_PREFIX)testutils.o $(LIBFDT_lib)
|
||||
$(LIB_TESTS): %: $(TESTS_PREFIX)testutils.o $(LIBFDT_archive)
|
||||
|
||||
$(LIBTREE_TESTS): %: $(TESTS_PREFIX)testutils.o $(TESTS_PREFIX)trees.o $(LIBFDT_lib)
|
||||
$(DL_LIB_TESTS): %: %.o $(TESTS_PREFIX)testutils.o $(LIBFDT_archive)
|
||||
@$(VECHO) LD [libdl] $@
|
||||
$(LINK.c) -o $@ $^ -ldl
|
||||
|
||||
$(LIBTREE_TESTS): %: $(TESTS_PREFIX)testutils.o $(TESTS_PREFIX)trees.o $(LIBFDT_archive)
|
||||
|
||||
$(TESTS_PREFIX)dumptrees: $(TESTS_PREFIX)trees.o
|
||||
|
||||
|
21
tests/aliases.dts
Normal file
21
tests/aliases.dts
Normal file
@ -0,0 +1,21 @@
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
aliases {
|
||||
s1 = &sub1;
|
||||
ss1 = &subsub1;
|
||||
sss1 = &subsubsub1;
|
||||
};
|
||||
|
||||
sub1: subnode@1 {
|
||||
compatible = "subnode1";
|
||||
|
||||
subsub1: subsubnode {
|
||||
compatible = "subsubnode1", "subsubnode";
|
||||
|
||||
subsubsub1: subsubsubnode {
|
||||
compatible = "subsubsubnode1", "subsubsubnode";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
62
tests/asm_tree_dump.c
Normal file
62
tests/asm_tree_dump.c
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Tests if an asm tree built into a shared object matches a given dtb
|
||||
* Copyright (C) 2008 David Gibson, IBM Corporation.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include <fdt.h>
|
||||
#include <libfdt.h>
|
||||
|
||||
#include "tests.h"
|
||||
#include "testdata.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
void *sohandle;
|
||||
void *fdt;
|
||||
int err;
|
||||
|
||||
test_init(argc, argv);
|
||||
if (argc != 3)
|
||||
CONFIG("Usage: %s <so file> <dtb file>", argv[0]);
|
||||
|
||||
sohandle = dlopen(argv[1], RTLD_NOW);
|
||||
if (!sohandle)
|
||||
FAIL("Couldn't dlopen() %s", argv[1]);
|
||||
|
||||
fdt = dlsym(sohandle, "dt_blob_start");
|
||||
if (!fdt)
|
||||
FAIL("Couldn't locate \"dt_blob_start\" symbol in %s",
|
||||
argv[1]);
|
||||
|
||||
err = fdt_check_header(fdt);
|
||||
if (err != 0)
|
||||
FAIL("%s contains invalid tree: %s", argv[1],
|
||||
fdt_strerror(err));
|
||||
|
||||
save_blob(argv[2], fdt);
|
||||
|
||||
PASS();
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
model = "SomeModel";
|
||||
compatible = "Nothing";
|
||||
@ -6,26 +8,26 @@
|
||||
|
||||
memory@0 {
|
||||
device_type = "memory";
|
||||
reg = <00000000 00000000 00000000 20000000>;
|
||||
reg = <0x00000000 0x00000000 0x00000000 0x20000000>;
|
||||
};
|
||||
|
||||
cpus {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
d10 = <d# 10>; // hex: 0xa
|
||||
d23 = <d# 23>; // hex: 0x17
|
||||
b101 = <b# 101>; // hex: 0x5
|
||||
o17 = <o# 17>; // hex: 0xf
|
||||
hd00d = <h# d00d>; // hex: 0xd00d
|
||||
d10 = < 10>; // hex: 0xa
|
||||
d23 = < 23>; // hex: 0x17
|
||||
b101 = < 0x5>; // hex: 0x5
|
||||
o17 = < 017>; // hex: 0xf
|
||||
hd00d = < 0xd00d>; // hex: 0xd00d
|
||||
|
||||
// hex: 0x4d2 0x163e 0x2334 0xd80
|
||||
stuff = <d# 1234 d# 5678 d# 9012 d# 3456>;
|
||||
stuff = < 1234 5678 9012 3456>;
|
||||
|
||||
|
||||
bad-d-1 = <d# abc123>; // Hrm. 0
|
||||
bad-d-2 = <d# 123456789012345>;
|
||||
bad-o-1 = <o# 891>;
|
||||
bad-o-2 = <o# 123456123456>;
|
||||
bad-d-1 = < 0>; // Hrm. 0
|
||||
bad-d-2 = < 123456789012345>;
|
||||
bad-o-1 = < 00>;
|
||||
bad-o-2 = < 0123456123456>;
|
||||
};
|
||||
|
||||
};
|
||||
|
3
tests/data.S
Normal file
3
tests/data.S
Normal file
@ -0,0 +1,3 @@
|
||||
/* Used in combination with dtc -Oasm output to embed
|
||||
* a device tree in the data section of a .o */
|
||||
.data
|
@ -29,7 +29,7 @@
|
||||
#include "tests.h"
|
||||
#include "testdata.h"
|
||||
|
||||
void compare_mem_rsv(const void *fdt1, const void *fdt2)
|
||||
static void compare_mem_rsv(const void *fdt1, const void *fdt2)
|
||||
{
|
||||
int i;
|
||||
uint64_t addr1, size1, addr2, size2;
|
||||
@ -56,7 +56,7 @@ void compare_mem_rsv(const void *fdt1, const void *fdt2)
|
||||
}
|
||||
}
|
||||
|
||||
void compare_structure(const void *fdt1, const void *fdt2)
|
||||
static void compare_structure(const void *fdt1, const void *fdt2)
|
||||
{
|
||||
int nextoffset1 = 0, nextoffset2 = 0;
|
||||
int offset1, offset2;
|
||||
|
@ -1,2 +1,4 @@
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
};
|
||||
|
@ -1,3 +1,5 @@
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
compatible = "test_string_escapes";
|
||||
escape-str = "nastystring: \a\b\t\n\v\f\r\\\"";
|
||||
|
59
tests/extra-terminating-null.c
Normal file
59
tests/extra-terminating-null.c
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Testcase for properties with more than one terminating null
|
||||
* Copyright (C) 2009 David Gibson, IBM Corporation.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <fdt.h>
|
||||
#include <libfdt.h>
|
||||
|
||||
#include "tests.h"
|
||||
#include "testdata.h"
|
||||
|
||||
void check_extranull(void *fdt, const char *prop, const char *str, int numnulls)
|
||||
{
|
||||
int len = strlen(str);
|
||||
char checkbuf[len+numnulls];
|
||||
|
||||
memset(checkbuf, 0, sizeof(checkbuf));
|
||||
memcpy(checkbuf, TEST_STRING_1, len);
|
||||
|
||||
check_getprop(fdt, 0, prop, len+numnulls, checkbuf);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
void *fdt;
|
||||
|
||||
test_init(argc, argv);
|
||||
|
||||
fdt = load_blob_arg(argc, argv);
|
||||
|
||||
check_extranull(fdt, "extranull0", TEST_STRING_1, 1);
|
||||
check_extranull(fdt, "extranull1,1", TEST_STRING_1, 2);
|
||||
check_extranull(fdt, "extranull1,2", TEST_STRING_1, 2);
|
||||
check_extranull(fdt, "extranull2,1", TEST_STRING_1, 3);
|
||||
check_extranull(fdt, "extranull2,2", TEST_STRING_1, 3);
|
||||
check_extranull(fdt, "extranull2,3", TEST_STRING_1, 3);
|
||||
check_extranull(fdt, "extranull2,4", TEST_STRING_1, 3);
|
||||
|
||||
PASS();
|
||||
}
|
11
tests/extra-terminating-null.dts
Normal file
11
tests/extra-terminating-null.dts
Normal file
@ -0,0 +1,11 @@
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
extranull0 = "hello world";
|
||||
extranull1,1 = "hello world\0";
|
||||
extranull1,2 = "hello world", "";
|
||||
extranull2,1 = "hello world\0\0";
|
||||
extranull2,2 = "hello world", "", "";
|
||||
extranull2,3 = "hello world\0", "";
|
||||
extranull2,4 = "hello world", "\0";
|
||||
};
|
58
tests/get_alias.c
Normal file
58
tests/get_alias.c
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Testcase for fdt_get_alias()
|
||||
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <fdt.h>
|
||||
#include <libfdt.h>
|
||||
|
||||
#include "tests.h"
|
||||
#include "testdata.h"
|
||||
|
||||
void check_alias(void *fdt, const char *path, const char *alias)
|
||||
{
|
||||
const char *aliaspath;
|
||||
|
||||
aliaspath = fdt_get_alias(fdt, alias);
|
||||
|
||||
if (path && !aliaspath)
|
||||
FAIL("fdt_get_alias(%s) failed\n", alias);
|
||||
|
||||
if (strcmp(aliaspath, path) != 0)
|
||||
FAIL("fdt_get_alias(%s) returned %s instead of %s\n",
|
||||
alias, aliaspath, path);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
void *fdt;
|
||||
|
||||
test_init(argc, argv);
|
||||
fdt = load_blob_arg(argc, argv);
|
||||
|
||||
check_alias(fdt, "/subnode@1", "s1");
|
||||
check_alias(fdt, "/subnode@1/subsubnode", "ss1");
|
||||
check_alias(fdt, "/subnode@1/subsubnode/subsubsubnode", "sss1");
|
||||
|
||||
PASS();
|
||||
}
|
@ -28,7 +28,7 @@
|
||||
#include "tests.h"
|
||||
#include "testdata.h"
|
||||
|
||||
void check_name(void *fdt, const char *path)
|
||||
static void check_name(void *fdt, const char *path)
|
||||
{
|
||||
int offset;
|
||||
const char *getname, *getname2, *checkname;
|
||||
|
@ -30,7 +30,7 @@
|
||||
|
||||
#define POISON ('\xff')
|
||||
|
||||
void check_path_buf(void *fdt, const char *path, int pathlen, int buflen)
|
||||
static void check_path_buf(void *fdt, const char *path, int pathlen, int buflen)
|
||||
{
|
||||
int offset;
|
||||
char buf[buflen+1];
|
||||
@ -43,6 +43,8 @@ void check_path_buf(void *fdt, const char *path, int pathlen, int buflen)
|
||||
memset(buf, POISON, sizeof(buf)); /* poison the buffer */
|
||||
|
||||
len = fdt_get_path(fdt, offset, buf, buflen);
|
||||
verbose_printf("get_path() %s -> %d -> %s\n", path, offset, buf);
|
||||
|
||||
if (buflen <= pathlen) {
|
||||
if (len != -FDT_ERR_NOSPACE)
|
||||
FAIL("fdt_get_path([%d bytes]) returns %d with "
|
||||
@ -51,9 +53,9 @@ void check_path_buf(void *fdt, const char *path, int pathlen, int buflen)
|
||||
if (len < 0)
|
||||
FAIL("fdt_get_path([%d bytes]): %s", buflen,
|
||||
fdt_strerror(len));
|
||||
if (len != pathlen)
|
||||
FAIL("fdt_get_path([%d bytes]) reports length %d "
|
||||
"instead of %d", buflen, len, pathlen);
|
||||
if (len != 0)
|
||||
FAIL("fdt_get_path([%d bytes]) returns %d "
|
||||
"instead of 0", buflen, len);
|
||||
if (strcmp(buf, path) != 0)
|
||||
FAIL("fdt_get_path([%d bytes]) returns \"%s\" "
|
||||
"instead of \"%s\"", buflen, buf, path);
|
||||
@ -63,13 +65,15 @@ void check_path_buf(void *fdt, const char *path, int pathlen, int buflen)
|
||||
FAIL("fdt_get_path([%d bytes]) overran buffer", buflen);
|
||||
}
|
||||
|
||||
void check_path(void *fdt, const char *path)
|
||||
static void check_path(void *fdt, const char *path)
|
||||
{
|
||||
int pathlen = strlen(path);
|
||||
|
||||
check_path_buf(fdt, path, pathlen, 1024);
|
||||
check_path_buf(fdt, path, pathlen, pathlen+1);
|
||||
check_path_buf(fdt, path, pathlen, pathlen);
|
||||
check_path_buf(fdt, path, pathlen, 0);
|
||||
check_path_buf(fdt, path, pathlen, 2);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
|
@ -28,7 +28,7 @@
|
||||
#include "tests.h"
|
||||
#include "testdata.h"
|
||||
|
||||
void check_phandle(void *fdt, const char *path, uint32_t checkhandle)
|
||||
static void check_phandle(void *fdt, const char *path, uint32_t checkhandle)
|
||||
{
|
||||
int offset;
|
||||
uint32_t phandle;
|
||||
|
@ -31,7 +31,7 @@
|
||||
|
||||
#define CHUNKSIZE 1024
|
||||
|
||||
char *load_file(const char *name, int *len)
|
||||
static char *load_file(const char *name, int *len)
|
||||
{
|
||||
FILE *f;
|
||||
char *buf = NULL;
|
||||
|
@ -15,9 +15,12 @@
|
||||
prop-int = <123456789>;
|
||||
|
||||
/include/ "include8.dts"
|
||||
linux,phandle = <0x2001>;
|
||||
phandle = <0x2001>;
|
||||
compatible = "subsubnode2", "subsubnode";
|
||||
prop-int = <0726746425>;
|
||||
};
|
||||
|
||||
ss2 {
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -6,4 +6,7 @@
|
||||
compatible = "subsubnode1", "subsubnode";
|
||||
prop-int = <0xdeadbeef>;
|
||||
};
|
||||
|
||||
ss1 {
|
||||
};
|
||||
};
|
||||
|
@ -1,6 +1,8 @@
|
||||
/memreserve/ 1000000000000000 0000000002000000;
|
||||
memrsv2: /memreserve/ 2000000000000000-20ffffffffffffff;
|
||||
/memreserve/ 0-13;
|
||||
/dts-v1/;
|
||||
|
||||
/memreserve/ 0x1000000000000000 0x0000000002000000;
|
||||
memrsv2: /memreserve/ 0x2000000000000000 0x0100000000000000;
|
||||
/memreserve/ 0x0000000000000000 0x0000000000000014;
|
||||
|
||||
/ {
|
||||
model = "MyBoardName";
|
||||
@ -9,28 +11,28 @@ memrsv2: /memreserve/ 2000000000000000-20ffffffffffffff;
|
||||
#size-cells = <2>;
|
||||
|
||||
cpus {
|
||||
linux,phandle = <1>;
|
||||
linux,phandle = <0x1>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
PowerPC,970@0 {
|
||||
name = "PowerPC,970";
|
||||
device_type = "cpu";
|
||||
reg = <0>;
|
||||
clock-frequency = <5f5e1000>;
|
||||
timebase-frequency = <1FCA055>;
|
||||
reg = <0x00000000>;
|
||||
clock-frequency = <1600000000>;
|
||||
timebase-frequency = <33333333>;
|
||||
linux,boot-cpu;
|
||||
i-cache-size = <10000>;
|
||||
d-cache-size = <8000>;
|
||||
i-cache-size = <65536>;
|
||||
d-cache-size = <32768>;
|
||||
};
|
||||
|
||||
PowerPC,970@1 {
|
||||
name = "PowerPC,970";
|
||||
device_type = "cpu";
|
||||
reg = <1>;
|
||||
clock-frequency = <5f5e1000>;
|
||||
timebase-frequency = <1FCA055>;
|
||||
i-cache-size = <10000>;
|
||||
d-cache-size = <8000>;
|
||||
reg = <0x00000001>;
|
||||
clock-frequency = <1600000000>;
|
||||
timebase-frequency = <33333333>;
|
||||
i-cache-size = <65536>;
|
||||
d-cache-size = <32768>;
|
||||
};
|
||||
|
||||
};
|
||||
@ -38,8 +40,8 @@ memrsv2: /memreserve/ 2000000000000000-20ffffffffffffff;
|
||||
node: randomnode {
|
||||
prop: string = str: "foo", str_mid: "stuffstuff\t\t\t\n\n\n" str_end: ;
|
||||
blob = [byte: 0a 0b 0c 0d byte_mid: de ea ad be ef byte_end: ];
|
||||
ref = < cell: &/memory@0 0 cell_mid: ffffffff cell_end: >;
|
||||
mixed = "abc", pre: [1234] post: , gap: < aligned: a b c>;
|
||||
ref = < cell: &{/memory@0} 0x0 cell_mid: 0xffffffff cell_end: >;
|
||||
mixed = "abc", pre: [1234] post: , gap: < aligned: 0xa 0xb 0xc>;
|
||||
tricky1 = [61 lt1: 62 63 00];
|
||||
subnode: child {
|
||||
};
|
||||
@ -49,12 +51,12 @@ memrsv2: /memreserve/ 2000000000000000-20ffffffffffffff;
|
||||
|
||||
memory@0 {
|
||||
device_type = "memory";
|
||||
memreg: reg = <00000000 00000000 00000000 20000000>;
|
||||
memreg: reg = <0x00000000 0x00000000 0x00000000 0x20000000>;
|
||||
};
|
||||
|
||||
chosen {
|
||||
bootargs = "root=/dev/sda2";
|
||||
linux,platform = <00000600>;
|
||||
linux,platform = <0x600>;
|
||||
};
|
||||
|
||||
};
|
||||
|
@ -35,7 +35,7 @@ struct bufstate {
|
||||
int size;
|
||||
};
|
||||
|
||||
void expand_buf(struct bufstate *buf, int newsize)
|
||||
static void expand_buf(struct bufstate *buf, int newsize)
|
||||
{
|
||||
buf->buf = realloc(buf->buf, newsize);
|
||||
if (!buf->buf)
|
||||
@ -43,7 +43,7 @@ void expand_buf(struct bufstate *buf, int newsize)
|
||||
buf->size = newsize;
|
||||
}
|
||||
|
||||
void new_header(struct bufstate *buf, int version, const void *fdt)
|
||||
static void new_header(struct bufstate *buf, int version, const void *fdt)
|
||||
{
|
||||
int hdrsize;
|
||||
|
||||
@ -63,7 +63,7 @@ void new_header(struct bufstate *buf, int version, const void *fdt)
|
||||
fdt_set_boot_cpuid_phys(buf->buf, fdt_boot_cpuid_phys(fdt));
|
||||
}
|
||||
|
||||
void add_block(struct bufstate *buf, int version, char block, const void *fdt)
|
||||
static void add_block(struct bufstate *buf, int version, char block, const void *fdt)
|
||||
{
|
||||
int align, size;
|
||||
const void *src;
|
||||
|
@ -29,7 +29,8 @@
|
||||
#include "tests.h"
|
||||
#include "testdata.h"
|
||||
|
||||
void check_compatible(const void *fdt, const char *path, const char *compat)
|
||||
static void check_compatible(const void *fdt, const char *path,
|
||||
const char *compat)
|
||||
{
|
||||
int offset, err;
|
||||
|
||||
|
@ -29,7 +29,7 @@
|
||||
#include "tests.h"
|
||||
#include "testdata.h"
|
||||
|
||||
void check_search(void *fdt, const char *compat, ...)
|
||||
static void check_search(void *fdt, const char *compat, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int offset = -1, target;
|
||||
|
@ -29,7 +29,7 @@
|
||||
#include "tests.h"
|
||||
#include "testdata.h"
|
||||
|
||||
void check_search(void *fdt, uint32_t phandle, int target)
|
||||
static void check_search(void *fdt, uint32_t phandle, int target)
|
||||
{
|
||||
int offset;
|
||||
|
||||
|
@ -29,7 +29,7 @@
|
||||
#include "tests.h"
|
||||
#include "testdata.h"
|
||||
|
||||
void vcheck_search(void *fdt, const char *propname, const void *propval,
|
||||
static void vcheck_search(void *fdt, const char *propname, const void *propval,
|
||||
int proplen, va_list ap)
|
||||
{
|
||||
int offset = -1, target;
|
||||
@ -48,7 +48,7 @@ void vcheck_search(void *fdt, const char *propname, const void *propval,
|
||||
} while (target >= 0);
|
||||
}
|
||||
|
||||
void check_search(void *fdt, const char *propname, const void *propval,
|
||||
static void check_search(void *fdt, const char *propname, const void *propval,
|
||||
int proplen, ...)
|
||||
{
|
||||
va_list ap;
|
||||
@ -58,7 +58,8 @@ void check_search(void *fdt, const char *propname, const void *propval,
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void check_search_str(void *fdt, const char *propname, const char *propval, ...)
|
||||
static void check_search_str(void *fdt, const char *propname,
|
||||
const char *propval, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
|
@ -30,7 +30,7 @@
|
||||
#include "tests.h"
|
||||
#include "testdata.h"
|
||||
|
||||
int nopulate_struct(char *buf, const char *fdt)
|
||||
static int nopulate_struct(char *buf, const char *fdt)
|
||||
{
|
||||
int offset, nextoffset = 0;
|
||||
uint32_t tag;
|
||||
|
@ -28,7 +28,7 @@
|
||||
#include "tests.h"
|
||||
#include "testdata.h"
|
||||
|
||||
void check_error(const char *s, int err)
|
||||
static void check_error(const char *s, int err)
|
||||
{
|
||||
if (err != -FDT_ERR_NOTFOUND)
|
||||
FAIL("%s return error %s instead of -FDT_ERR_NOTFOUND", s,
|
||||
|
@ -28,7 +28,7 @@
|
||||
#include "tests.h"
|
||||
#include "testdata.h"
|
||||
|
||||
int path_parent_len(const char *path)
|
||||
static int path_parent_len(const char *path)
|
||||
{
|
||||
const char *p = strrchr(path, '/');
|
||||
|
||||
@ -40,7 +40,7 @@ int path_parent_len(const char *path)
|
||||
return p - path;
|
||||
}
|
||||
|
||||
void check_path(struct fdt_header *fdt, const char *path)
|
||||
static void check_path(struct fdt_header *fdt, const char *path)
|
||||
{
|
||||
char *parentpath;
|
||||
int nodeoffset, parentoffset, parentpathoffset, pathparentlen;
|
||||
|
@ -28,7 +28,7 @@
|
||||
#include "tests.h"
|
||||
#include "testdata.h"
|
||||
|
||||
void check_ref(const void *fdt, int node, const char *checkpath)
|
||||
static void check_ref(const void *fdt, int node, const char *checkpath)
|
||||
{
|
||||
const char *p;
|
||||
int len;
|
||||
|
@ -28,7 +28,7 @@
|
||||
#include "tests.h"
|
||||
#include "testdata.h"
|
||||
|
||||
int check_subnode(void *fdt, int parent, const char *name)
|
||||
static int check_subnode(void *fdt, int parent, const char *name)
|
||||
{
|
||||
int offset;
|
||||
const struct fdt_node_header *nh;
|
||||
|
59
tests/path_offset_aliases.c
Normal file
59
tests/path_offset_aliases.c
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Testcase for fdt_path_offset()
|
||||
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||
* Copyright 2008 Kumar Gala, Freescale Semiconductor, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <fdt.h>
|
||||
#include <libfdt.h>
|
||||
|
||||
#include "tests.h"
|
||||
#include "testdata.h"
|
||||
|
||||
void check_alias(void *fdt, const char *full_path, const char *alias_path)
|
||||
{
|
||||
int offset, offset_a;
|
||||
|
||||
offset = fdt_path_offset(fdt, full_path);
|
||||
offset_a = fdt_path_offset(fdt, alias_path);
|
||||
|
||||
if (offset != offset_a)
|
||||
FAIL("Mismatch between %s path_offset (%d) and %s path_offset alias (%d)",
|
||||
full_path, offset, alias_path, offset_a);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
void *fdt;
|
||||
|
||||
test_init(argc, argv);
|
||||
fdt = load_blob_arg(argc, argv);
|
||||
|
||||
check_alias(fdt, "/subnode@1", "s1");
|
||||
check_alias(fdt, "/subnode@1/subsubnode", "ss1");
|
||||
check_alias(fdt, "/subnode@1/subsubnode", "s1/subsubnode");
|
||||
check_alias(fdt, "/subnode@1/subsubnode/subsubsubnode", "sss1");
|
||||
check_alias(fdt, "/subnode@1/subsubnode/subsubsubnode", "ss1/subsubsubnode");
|
||||
check_alias(fdt, "/subnode@1/subsubnode/subsubsubnode", "s1/subsubnode/subsubsubnode");
|
||||
|
||||
PASS();
|
||||
}
|
78
tests/phandle_format.c
Normal file
78
tests/phandle_format.c
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Testcase for phandle format options
|
||||
* Copyright (C) 2009 David Gibson, IBM Corporation.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <fdt.h>
|
||||
#include <libfdt.h>
|
||||
|
||||
#include "tests.h"
|
||||
#include "testdata.h"
|
||||
|
||||
#define PHANDLE_LEGACY 0x1
|
||||
#define PHANDLE_EPAPR 0x2
|
||||
#define PHANDLE_BOTH 0x3
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
void *fdt;
|
||||
int phandle_format;
|
||||
int n4;
|
||||
uint32_t h4;
|
||||
|
||||
if (argc != 3)
|
||||
CONFIG("Usage: %s <dtb file> <legacy|epapr|both>\n", argv[0]);
|
||||
|
||||
test_init(argc, argv);
|
||||
fdt = load_blob(argv[1]);
|
||||
|
||||
if (streq(argv[2], "legacy"))
|
||||
phandle_format = PHANDLE_LEGACY;
|
||||
else if (streq(argv[2], "epapr"))
|
||||
phandle_format = PHANDLE_EPAPR;
|
||||
else if (streq(argv[2], "both"))
|
||||
phandle_format = PHANDLE_BOTH;
|
||||
else
|
||||
CONFIG("Usage: %s <dtb file> <legacy|epapr|both>\n", argv[0]);
|
||||
|
||||
n4 = fdt_path_offset(fdt, "/node4");
|
||||
if (n4 < 0)
|
||||
FAIL("fdt_path_offset(/node4): %s", fdt_strerror(n4));
|
||||
|
||||
h4 = fdt_get_phandle(fdt, n4);
|
||||
if ((h4 == 0) || (h4 == -1))
|
||||
FAIL("/node4 has bad phandle 0x%x\n", h4);
|
||||
|
||||
if (phandle_format & PHANDLE_LEGACY)
|
||||
check_getprop_cell(fdt, n4, "linux,phandle", h4);
|
||||
else
|
||||
if (fdt_getprop(fdt, n4, "linux,phandle", NULL))
|
||||
FAIL("linux,phandle property present in non-legacy mode");
|
||||
|
||||
if (phandle_format & PHANDLE_EPAPR)
|
||||
check_getprop_cell(fdt, n4, "phandle", h4);
|
||||
else
|
||||
if (fdt_getprop(fdt, n4, "phandle", NULL))
|
||||
FAIL("phandle property present in legacy-only mode");
|
||||
|
||||
PASS();
|
||||
}
|
@ -28,7 +28,7 @@
|
||||
#include "tests.h"
|
||||
#include "testdata.h"
|
||||
|
||||
void check_ref(const void *fdt, int node, uint32_t checkref)
|
||||
static void check_ref(const void *fdt, int node, uint32_t checkref)
|
||||
{
|
||||
const uint32_t *p;
|
||||
uint32_t ref;
|
||||
@ -60,8 +60,8 @@ void check_ref(const void *fdt, int node, uint32_t checkref)
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
void *fdt;
|
||||
int n1, n2, n3, n4;
|
||||
uint32_t h1, h2, h4;
|
||||
int n1, n2, n3, n4, n5;
|
||||
uint32_t h1, h2, h4, h5;
|
||||
|
||||
test_init(argc, argv);
|
||||
fdt = load_blob_arg(argc, argv);
|
||||
@ -78,10 +78,14 @@ int main(int argc, char *argv[])
|
||||
n4 = fdt_path_offset(fdt, "/node4");
|
||||
if (n4 < 0)
|
||||
FAIL("fdt_path_offset(/node4): %s", fdt_strerror(n4));
|
||||
n5 = fdt_path_offset(fdt, "/node5");
|
||||
if (n5 < 0)
|
||||
FAIL("fdt_path_offset(/node5): %s", fdt_strerror(n5));
|
||||
|
||||
h1 = fdt_get_phandle(fdt, n1);
|
||||
h2 = fdt_get_phandle(fdt, n2);
|
||||
h4 = fdt_get_phandle(fdt, n4);
|
||||
h5 = fdt_get_phandle(fdt, n5);
|
||||
|
||||
if (h1 != 0x2000)
|
||||
FAIL("/node1 has wrong phandle, 0x%x instead of 0x%x",
|
||||
@ -92,6 +96,11 @@ int main(int argc, char *argv[])
|
||||
if ((h4 == 0x2000) || (h4 == 0x1) || (h4 == 0))
|
||||
FAIL("/node4 has bad phandle, 0x%x", h4);
|
||||
|
||||
if ((h5 == 0) || (h5 == -1))
|
||||
FAIL("/node5 has bad phandle, 0x%x", h5);
|
||||
if ((h5 == h4) || (h5 == h2) || (h5 == h1))
|
||||
FAIL("/node5 has duplicate phandle, 0x%x", h5);
|
||||
|
||||
check_ref(fdt, n1, h2);
|
||||
check_ref(fdt, n2, h1);
|
||||
check_ref(fdt, n3, h4);
|
||||
|
@ -8,7 +8,7 @@
|
||||
lref = <&n2>;
|
||||
};
|
||||
n2: node2 {
|
||||
linux,phandle = <0x1>;
|
||||
phandle = <0x1>;
|
||||
ref = <&{/node1}>; /* reference after target */
|
||||
lref = <&n1>;
|
||||
};
|
||||
@ -20,4 +20,15 @@
|
||||
};
|
||||
n4: node4 {
|
||||
};
|
||||
|
||||
/* Explicit phandle with implicit value */
|
||||
/* This self-reference is the standard way to tag a node as requiring
|
||||
* a phandle (perhaps for reference by nodes that will be dynamically
|
||||
* added) without explicitly allocating it a phandle.
|
||||
* The self-reference requires some special internal handling, though
|
||||
* so check it actually works */
|
||||
n5: node5 {
|
||||
linux,phandle = <&n5>;
|
||||
phandle = <&n5>;
|
||||
};
|
||||
};
|
||||
|
@ -1,21 +1,26 @@
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
/* Explicit phandles */
|
||||
n1: node1 {
|
||||
linux,phandle = <2000>;
|
||||
ref = <&/node2>; /* reference precedes target */
|
||||
linux,phandle = <0x2000>;
|
||||
ref = <&{/node2}>; /* reference precedes target */
|
||||
lref = <&n2>;
|
||||
};
|
||||
n2: node2 {
|
||||
linux,phandle = <1>;
|
||||
ref = <&/node1>; /* reference after target */
|
||||
linux,phandle = <0x1>;
|
||||
ref = <&{/node1}>; /* reference after target */
|
||||
lref = <&n1>;
|
||||
};
|
||||
|
||||
/* Implicit phandles */
|
||||
n3: node3 {
|
||||
ref = <&/node4>;
|
||||
ref = <&{/node4}>;
|
||||
lref = <&n4>;
|
||||
};
|
||||
n4: node4 {
|
||||
};
|
||||
n5: node5 {
|
||||
linux,phandle = <&n5>;
|
||||
};
|
||||
};
|
||||
|
@ -2,6 +2,10 @@
|
||||
|
||||
. ./tests.sh
|
||||
|
||||
if [ -z "$CC" ]; then
|
||||
CC=gcc
|
||||
fi
|
||||
|
||||
export QUIET_TEST=1
|
||||
|
||||
export VALGRIND=
|
||||
@ -71,11 +75,12 @@ run_dtc_test () {
|
||||
base_run_test wrap_test $VALGRIND $DTC "$@"
|
||||
}
|
||||
|
||||
CONVERT=../convert-dtsv0
|
||||
asm_to_so () {
|
||||
$CC -shared -o $1.test.so data.S $1.test.s
|
||||
}
|
||||
|
||||
run_convert_test () {
|
||||
echo -n "convert-dtsv0 $@: "
|
||||
base_run_test wrap_test $VALGRIND $CONVERT "$@"
|
||||
asm_to_so_test () {
|
||||
run_wrap_test asm_to_so "$@"
|
||||
}
|
||||
|
||||
tree1_tests () {
|
||||
@ -201,6 +206,9 @@ dtc_tests () {
|
||||
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_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
|
||||
|
||||
@ -210,10 +218,21 @@ dtc_tests () {
|
||||
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
|
||||
|
||||
run_test phandle_format dtc_references.test.dtb both
|
||||
for f in legacy epapr both; do
|
||||
run_dtc_test -I dts -O dtb -H $f -o dtc_references.test.$f.dtb references.dts
|
||||
run_test phandle_format dtc_references.test.$f.dtb $f
|
||||
done
|
||||
|
||||
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
|
||||
|
||||
# Check aliases support in fdt_path_offset
|
||||
run_dtc_test -I dts -O dtb -o aliases.dtb aliases.dts
|
||||
run_test get_alias aliases.dtb
|
||||
run_test path_offset_aliases aliases.dtb
|
||||
|
||||
# Check /include/ directive
|
||||
run_dtc_test -I dts -O dtb -o includes.test.dtb include0.dts
|
||||
run_test dtbs_equal_ordered includes.test.dtb test_tree1.dtb
|
||||
@ -230,8 +249,22 @@ dtc_tests () {
|
||||
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
|
||||
|
||||
# Check -Oasm mode
|
||||
for tree in test_tree1.dts escapes.dts references.dts path-references.dts \
|
||||
comments.dts aliases.dts include0.dts incbin.dts \
|
||||
value-labels.dts ; do
|
||||
run_dtc_test -I dts -O asm -o oasm_$tree.test.s $tree
|
||||
asm_to_so_test oasm_$tree
|
||||
run_dtc_test -I dts -O dtb -o $tree.test.dtb $tree
|
||||
run_test asm_tree_dump ./oasm_$tree.test.so oasm_$tree.test.dtb
|
||||
run_wrap_test cmp oasm_$tree.test.dtb $tree.test.dtb
|
||||
done
|
||||
|
||||
run_test value-labels ./oasm_value-labels.dts.test.so
|
||||
|
||||
# Check -Odts mode preserve all dtb information
|
||||
for tree in test_tree1.dtb dtc_tree1.test.dtb dtc_escapes.test.dtb ; do
|
||||
for tree in test_tree1.dtb dtc_tree1.test.dtb dtc_escapes.test.dtb \
|
||||
dtc_extra-terminating-null.test.dtb dtc_references.test.dtb; do
|
||||
run_dtc_test -I dtb -O dts -o odts_$tree.test.dts $tree
|
||||
run_dtc_test -I dts -O dtb -o odts_$tree.test.dtb odts_$tree.test.dts
|
||||
run_test dtbs_equal_ordered $tree odts_$tree.test.dtb
|
||||
@ -283,21 +316,6 @@ dtc_tests () {
|
||||
run_sh_test dtc-fatal.sh -I fs -O dtb nosuchfile
|
||||
}
|
||||
|
||||
convert_tests () {
|
||||
V0_DTS="test_tree1_dts0.dts references_dts0.dts empty.dts escapes.dts \
|
||||
test01.dts label01.dts"
|
||||
for dts in $V0_DTS; do
|
||||
run_dtc_test -I dts -O dtb -o cvtraw_$dts.test.dtb $dts
|
||||
run_dtc_test -I dts -O dts -o cvtdtc_$dts.test.dts $dts
|
||||
run_dtc_test -I dts -O dtb -o cvtdtc_$dts.test.dtb cvtdtc_$dts.test.dts
|
||||
run_convert_test $dts
|
||||
run_dtc_test -I dts -O dtb -o cvtcvt_$dts.test.dtb ${dts}v1
|
||||
|
||||
run_wrap_test cmp cvtraw_$dts.test.dtb cvtdtc_$dts.test.dtb
|
||||
run_wrap_test cmp cvtraw_$dts.test.dtb cvtcvt_$dts.test.dtb
|
||||
done
|
||||
}
|
||||
|
||||
while getopts "vt:m" ARG ; do
|
||||
case $ARG in
|
||||
"v")
|
||||
@ -313,7 +331,7 @@ while getopts "vt:m" ARG ; do
|
||||
done
|
||||
|
||||
if [ -z "$TESTSETS" ]; then
|
||||
TESTSETS="libfdt dtc convert"
|
||||
TESTSETS="libfdt dtc"
|
||||
fi
|
||||
|
||||
# Make sure we don't have stale blobs lying around
|
||||
@ -327,20 +345,17 @@ for set in $TESTSETS; do
|
||||
"dtc")
|
||||
dtc_tests
|
||||
;;
|
||||
"convert")
|
||||
convert_tests
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
echo -e "********** TEST SUMMARY"
|
||||
echo -e "* Total testcases: $tot_tests"
|
||||
echo -e "* PASS: $tot_pass"
|
||||
echo -e "* FAIL: $tot_fail"
|
||||
echo -e "* Bad configuration: $tot_config"
|
||||
echo "********** TEST SUMMARY"
|
||||
echo "* Total testcases: $tot_tests"
|
||||
echo "* PASS: $tot_pass"
|
||||
echo "* FAIL: $tot_fail"
|
||||
echo "* Bad configuration: $tot_config"
|
||||
if [ -n "$VALGRIND" ]; then
|
||||
echo -e "* valgrind errors: $tot_vg"
|
||||
echo "* valgrind errors: $tot_vg"
|
||||
fi
|
||||
echo -e "* Strange test result: $tot_strange"
|
||||
echo -e "**********"
|
||||
echo "* Strange test result: $tot_strange"
|
||||
echo "**********"
|
||||
|
||||
|
@ -50,7 +50,7 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
void *fdt;
|
||||
int err;
|
||||
int offset;
|
||||
int offset, s1, s2;
|
||||
|
||||
test_init(argc, argv);
|
||||
|
||||
@ -77,21 +77,25 @@ int main(int argc, char *argv[])
|
||||
CHECK(fdt_setprop_string(fdt, 0, "prop-str", TEST_STRING_1));
|
||||
|
||||
OFF_CHECK(offset, fdt_add_subnode(fdt, 0, "subnode@1"));
|
||||
CHECK(fdt_setprop_string(fdt, offset, "compatible", "subnode1"));
|
||||
CHECK(fdt_setprop_cell(fdt, offset, "prop-int", TEST_VALUE_1));
|
||||
OFF_CHECK(offset, fdt_add_subnode(fdt, offset, "subsubnode"));
|
||||
s1 = offset;
|
||||
CHECK(fdt_setprop_string(fdt, s1, "compatible", "subnode1"));
|
||||
CHECK(fdt_setprop_cell(fdt, s1, "prop-int", TEST_VALUE_1));
|
||||
OFF_CHECK(offset, fdt_add_subnode(fdt, s1, "subsubnode"));
|
||||
CHECK(fdt_setprop(fdt, offset, "compatible",
|
||||
"subsubnode1\0subsubnode", 23));
|
||||
CHECK(fdt_setprop_cell(fdt, offset, "prop-int", TEST_VALUE_1));
|
||||
OFF_CHECK(offset, fdt_add_subnode(fdt, s1, "ss1"));
|
||||
|
||||
OFF_CHECK(offset, fdt_add_subnode(fdt, 0, "subnode@2"));
|
||||
CHECK(fdt_setprop_cell(fdt, offset, "linux,phandle", PHANDLE_1));
|
||||
CHECK(fdt_setprop_cell(fdt, offset, "prop-int", TEST_VALUE_2));
|
||||
OFF_CHECK(offset, fdt_add_subnode(fdt, offset, "subsubnode@0"));
|
||||
s2 = offset;
|
||||
CHECK(fdt_setprop_cell(fdt, s2, "linux,phandle", PHANDLE_1));
|
||||
CHECK(fdt_setprop_cell(fdt, s2, "prop-int", TEST_VALUE_2));
|
||||
OFF_CHECK(offset, fdt_add_subnode(fdt, s2, "subsubnode@0"));
|
||||
CHECK(fdt_setprop_cell(fdt, offset, "linux,phandle", PHANDLE_2));
|
||||
CHECK(fdt_setprop(fdt, offset, "compatible",
|
||||
"subsubnode2\0subsubnode", 23));
|
||||
CHECK(fdt_setprop_cell(fdt, offset, "prop-int", TEST_VALUE_2));
|
||||
OFF_CHECK(offset, fdt_add_subnode(fdt, s2, "ss2"));
|
||||
|
||||
CHECK(fdt_pack(fdt));
|
||||
|
||||
|
@ -28,7 +28,7 @@
|
||||
#include "tests.h"
|
||||
#include "testdata.h"
|
||||
|
||||
void check_set_name(void *fdt, const char *path, const char *newname)
|
||||
static void check_set_name(void *fdt, const char *path, const char *newname)
|
||||
{
|
||||
int offset;
|
||||
const char *getname, *oldname;
|
||||
|
@ -28,7 +28,7 @@
|
||||
#include "tests.h"
|
||||
#include "testdata.h"
|
||||
|
||||
int check_subnode(struct fdt_header *fdt, int parent, const char *name)
|
||||
static int check_subnode(struct fdt_header *fdt, int parent, const char *name)
|
||||
{
|
||||
int offset;
|
||||
const struct fdt_node_header *nh;
|
||||
@ -60,6 +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;
|
||||
|
||||
test_init(argc, argv);
|
||||
fdt = load_blob_arg(argc, argv);
|
||||
@ -84,5 +85,15 @@ 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");
|
||||
ss21_off = fdt_subnode_offset(fdt, subnode2_offset, "ss1");
|
||||
if (ss21_off != -FDT_ERR_NOTFOUND)
|
||||
FAIL("Incorrectly found ss1 in subnode2");
|
||||
|
||||
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");
|
||||
|
||||
PASS();
|
||||
}
|
||||
|
@ -28,7 +28,7 @@
|
||||
#include "tests.h"
|
||||
#include "testdata.h"
|
||||
|
||||
int path_depth(const char *path)
|
||||
static int path_depth(const char *path)
|
||||
{
|
||||
const char *p;
|
||||
int depth = 0;
|
||||
@ -49,7 +49,7 @@ int path_depth(const char *path)
|
||||
return depth;
|
||||
}
|
||||
|
||||
int path_prefix(const char *path, int depth)
|
||||
static int path_prefix(const char *path, int depth)
|
||||
{
|
||||
const char *p;
|
||||
int i;
|
||||
@ -67,7 +67,7 @@ int path_prefix(const char *path, int depth)
|
||||
return p - path;
|
||||
}
|
||||
|
||||
void check_supernode_atdepth(struct fdt_header *fdt, const char *path,
|
||||
static void check_supernode_atdepth(struct fdt_header *fdt, const char *path,
|
||||
int depth)
|
||||
{
|
||||
int pdepth = path_depth(path);
|
||||
@ -106,7 +106,7 @@ void check_supernode_atdepth(struct fdt_header *fdt, const char *path,
|
||||
"instead of %d", nodedepth, pdepth);
|
||||
}
|
||||
|
||||
void check_supernode_overdepth(struct fdt_header *fdt, const char *path)
|
||||
static void check_supernode_overdepth(struct fdt_header *fdt, const char *path)
|
||||
{
|
||||
int pdepth = path_depth(path);
|
||||
int nodeoffset, err;
|
||||
@ -121,7 +121,7 @@ void check_supernode_overdepth(struct fdt_header *fdt, const char *path)
|
||||
"of FDT_ERR_NOTFOUND", path, pdepth+1, err);
|
||||
}
|
||||
|
||||
void check_path(struct fdt_header *fdt, const char *path)
|
||||
static void check_path(struct fdt_header *fdt, const char *path)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -66,17 +66,22 @@ int main(int argc, char *argv[])
|
||||
23));
|
||||
CHECK(fdt_property_cell(fdt, "prop-int", TEST_VALUE_1));
|
||||
CHECK(fdt_end_node(fdt));
|
||||
CHECK(fdt_begin_node(fdt, "ss1"));
|
||||
CHECK(fdt_end_node(fdt));
|
||||
CHECK(fdt_end_node(fdt));
|
||||
|
||||
CHECK(fdt_begin_node(fdt, "subnode@2"));
|
||||
CHECK(fdt_property_cell(fdt, "linux,phandle", PHANDLE_1));
|
||||
CHECK(fdt_property_cell(fdt, "prop-int", TEST_VALUE_2));
|
||||
CHECK(fdt_begin_node(fdt, "subsubnode@0"));
|
||||
CHECK(fdt_property_cell(fdt, "linux,phandle", PHANDLE_2));
|
||||
CHECK(fdt_property_cell(fdt, "phandle", PHANDLE_2));
|
||||
CHECK(fdt_property(fdt, "compatible", "subsubnode2\0subsubnode",
|
||||
23));
|
||||
CHECK(fdt_property_cell(fdt, "prop-int", TEST_VALUE_2));
|
||||
CHECK(fdt_end_node(fdt));
|
||||
CHECK(fdt_begin_node(fdt, "ss2"));
|
||||
CHECK(fdt_end_node(fdt));
|
||||
|
||||
CHECK(fdt_end_node(fdt));
|
||||
|
||||
CHECK(fdt_end_node(fdt));
|
||||
|
@ -1,6 +1,8 @@
|
||||
/memreserve/ 1000000000000000 0000000002000000;
|
||||
/memreserve/ 2000000000000000-20ffffffffffffff;
|
||||
/memreserve/ 0-13;
|
||||
/dts-v1/;
|
||||
|
||||
/memreserve/ 0x1000000000000000 0x0000000002000000;
|
||||
/memreserve/ 0x2000000000000000 0x0100000000000000;
|
||||
/memreserve/ 0x0000000000000000 0x0000000000000014;
|
||||
|
||||
/ {
|
||||
model = "MyBoardName";
|
||||
@ -9,28 +11,28 @@
|
||||
#size-cells = <2>;
|
||||
|
||||
cpus {
|
||||
linux,phandle = <1>;
|
||||
linux,phandle = <0x1>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
PowerPC,970@0 {
|
||||
name = "PowerPC,970";
|
||||
device_type = "cpu";
|
||||
reg = <0>;
|
||||
clock-frequency = <5f5e1000>;
|
||||
timebase-frequency = <1FCA055>;
|
||||
reg = <0x00000000>;
|
||||
clock-frequency = <1600000000>;
|
||||
timebase-frequency = <33333333>;
|
||||
linux,boot-cpu;
|
||||
i-cache-size = <10000>;
|
||||
d-cache-size = <8000>;
|
||||
i-cache-size = <65536>;
|
||||
d-cache-size = <32768>;
|
||||
};
|
||||
|
||||
PowerPC,970@1 {
|
||||
name = "PowerPC,970";
|
||||
device_type = "cpu";
|
||||
reg = <1>;
|
||||
clock-frequency = <5f5e1000>;
|
||||
timebase-frequency = <1FCA055>;
|
||||
i-cache-size = <10000>;
|
||||
d-cache-size = <8000>;
|
||||
reg = <0x00000001>;
|
||||
clock-frequency = <1600000000>;
|
||||
timebase-frequency = <33333333>;
|
||||
i-cache-size = <65536>;
|
||||
d-cache-size = <32768>;
|
||||
};
|
||||
|
||||
};
|
||||
@ -38,18 +40,18 @@
|
||||
randomnode {
|
||||
string = "\xff\0stuffstuff\t\t\t\n\n\n";
|
||||
blob = [0a 0b 0c 0d de ea ad be ef];
|
||||
ref = < &/memory@0 >;
|
||||
mixed = "abc", [1234], <a b c>;
|
||||
ref = < &{/memory@0} >;
|
||||
mixed = "abc", [1234], <0xa 0xb 0xc>;
|
||||
};
|
||||
|
||||
memory@0 {
|
||||
device_type = "memory";
|
||||
memreg: reg = <00000000 00000000 00000000 20000000>;
|
||||
memreg: reg = <0x00000000 0x00000000 0x00000000 0x20000000>;
|
||||
};
|
||||
|
||||
chosen {
|
||||
bootargs = "root=/dev/sda2";
|
||||
linux,platform = <00000600>;
|
||||
linux,platform = <0x600>;
|
||||
};
|
||||
|
||||
};
|
||||
|
@ -16,6 +16,9 @@
|
||||
compatible = "subsubnode1", "subsubnode";
|
||||
prop-int = <0xdeadbeef>;
|
||||
};
|
||||
|
||||
ss1 {
|
||||
};
|
||||
};
|
||||
|
||||
subnode@2 {
|
||||
@ -23,9 +26,12 @@
|
||||
prop-int = <123456789>;
|
||||
|
||||
subsubnode@0 {
|
||||
linux,phandle = <0x2001>;
|
||||
phandle = <0x2001>;
|
||||
compatible = "subsubnode2", "subsubnode";
|
||||
prop-int = <0726746425>;
|
||||
};
|
||||
|
||||
ss2 {
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -1,9 +1,11 @@
|
||||
/memreserve/ deadbeef00000000-deadbeef000fffff;
|
||||
/memreserve/ 75bcd15 1000;
|
||||
/dts-v1/;
|
||||
|
||||
/memreserve/ 0xdeadbeef00000000 0x0000000000100000;
|
||||
/memreserve/ 0x00000000075bcd15 0x0000000000001000;
|
||||
|
||||
/ {
|
||||
compatible = "test_tree1";
|
||||
prop-int = <deadbeef>;
|
||||
prop-int = <0xdeadbeef>;
|
||||
prop-str = "hello world";
|
||||
|
||||
subnode@1 {
|
||||
@ -12,18 +14,24 @@
|
||||
|
||||
subsubnode {
|
||||
compatible = "subsubnode1", "subsubnode";
|
||||
prop-int = <h# deadbeef>;
|
||||
prop-int = < 0xdeadbeef>;
|
||||
};
|
||||
|
||||
ss1 {
|
||||
};
|
||||
};
|
||||
|
||||
subnode@2 {
|
||||
linux,phandle = <2000>;
|
||||
prop-int = <d# 123456789>;
|
||||
linux,phandle = <0x2000>;
|
||||
prop-int = < 123456789>;
|
||||
|
||||
subsubnode@0 {
|
||||
linux,phandle = <2001>;
|
||||
linux,phandle = <0x2001>;
|
||||
compatible = "subsubnode2", "subsubnode";
|
||||
prop-int = <o# 0726746425>;
|
||||
prop-int = < 0726746425>;
|
||||
};
|
||||
|
||||
ss2 {
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -34,6 +34,7 @@ void test_init(int argc, char *argv[]);
|
||||
|
||||
#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
|
||||
#define PALIGN(p, a) ((void *)ALIGN((unsigned long)(p), (a)))
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
|
||||
#define streq(s1, s2) (strcmp((s1),(s2)) == 0)
|
||||
|
||||
|
@ -96,10 +96,14 @@ test_tree1_struct:
|
||||
PROP_STR(test_tree1, compatible, "subsubnode1\0subsubnode")
|
||||
PROP_INT(test_tree1, prop_int, TEST_VALUE_1)
|
||||
END_NODE
|
||||
|
||||
BEGIN_NODE("ss1")
|
||||
END_NODE
|
||||
|
||||
END_NODE
|
||||
|
||||
BEGIN_NODE("subnode@2")
|
||||
PROP_INT(test_tree1, phandle, PHANDLE_1)
|
||||
PROP_INT(test_tree1, linux_phandle, PHANDLE_1)
|
||||
PROP_INT(test_tree1, prop_int, TEST_VALUE_2)
|
||||
|
||||
BEGIN_NODE("subsubnode@0")
|
||||
@ -107,6 +111,10 @@ test_tree1_struct:
|
||||
PROP_STR(test_tree1, compatible, "subsubnode2\0subsubnode")
|
||||
PROP_INT(test_tree1, prop_int, TEST_VALUE_2)
|
||||
END_NODE
|
||||
|
||||
BEGIN_NODE("ss2")
|
||||
END_NODE
|
||||
|
||||
END_NODE
|
||||
|
||||
END_NODE
|
||||
@ -117,7 +125,8 @@ test_tree1_strings:
|
||||
STRING(test_tree1, compatible, "compatible")
|
||||
STRING(test_tree1, prop_int, "prop-int")
|
||||
STRING(test_tree1, prop_str, "prop-str")
|
||||
STRING(test_tree1, phandle, "linux,phandle")
|
||||
STRING(test_tree1, linux_phandle, "linux,phandle")
|
||||
STRING(test_tree1, phandle, "phandle")
|
||||
test_tree1_strings_end:
|
||||
test_tree1_end:
|
||||
|
||||
|
128
tests/value-labels.c
Normal file
128
tests/value-labels.c
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Test labels within values
|
||||
* Copyright (C) 2008 David Gibson, IBM Corporation.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include <fdt.h>
|
||||
#include <libfdt.h>
|
||||
|
||||
#include "tests.h"
|
||||
#include "testdata.h"
|
||||
|
||||
struct val_label {
|
||||
const char *labelname;
|
||||
int propoff;
|
||||
};
|
||||
|
||||
struct val_label labels1[] = {
|
||||
{ "start1", 0 },
|
||||
{ "mid1", 2 },
|
||||
{ "end1", -1 },
|
||||
};
|
||||
|
||||
struct val_label labels2[] = {
|
||||
{ "start2", 0 },
|
||||
{ "innerstart2", 0 },
|
||||
{ "innermid2", 4 },
|
||||
{ "innerend2", -1 },
|
||||
{ "end2", -1 },
|
||||
};
|
||||
|
||||
struct val_label labels3[] = {
|
||||
{ "start3", 0 },
|
||||
{ "innerstart3", 0 },
|
||||
{ "innermid3", 1 },
|
||||
{ "innerend3", -1 },
|
||||
{ "end3", -1 },
|
||||
};
|
||||
|
||||
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;
|
||||
int len;
|
||||
int i;
|
||||
|
||||
prop = fdt_get_property(fdt, 0, name, &len);
|
||||
if (!prop)
|
||||
FAIL("Couldn't locate property \"%s\"", name);
|
||||
|
||||
p = dlsym(sohandle, name);
|
||||
if (!p)
|
||||
FAIL("Couldn't locate label symbol \"%s\"", name);
|
||||
|
||||
if (p != (const char *)prop)
|
||||
FAIL("Label \"%s\" does not point to correct property", name);
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
int off = labels[i].propoff;
|
||||
|
||||
if (off == -1)
|
||||
off = len;
|
||||
|
||||
p = dlsym(sohandle, labels[i].labelname);
|
||||
if (!p)
|
||||
FAIL("Couldn't locate label symbol \"%s\"", name);
|
||||
|
||||
if ((p - prop->data) != off)
|
||||
FAIL("Label \"%s\" points to offset %ld instead of %d"
|
||||
"in property \"%s\"", labels[i].labelname,
|
||||
(long)(p - prop->data), off, name);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
void *sohandle;
|
||||
void *fdt;
|
||||
int err;
|
||||
|
||||
test_init(argc, argv);
|
||||
if (argc != 2)
|
||||
CONFIG("Usage: %s <so file>", argv[0]);
|
||||
|
||||
sohandle = dlopen(argv[1], RTLD_NOW);
|
||||
if (!sohandle)
|
||||
FAIL("Couldn't dlopen() %s", argv[1]);
|
||||
|
||||
fdt = dlsym(sohandle, "dt_blob_start");
|
||||
if (!fdt)
|
||||
FAIL("Couldn't locate \"dt_blob_start\" symbol in %s",
|
||||
argv[1]);
|
||||
|
||||
err = fdt_check_header(fdt);
|
||||
if (err != 0)
|
||||
FAIL("%s contains invalid tree: %s", argv[1],
|
||||
fdt_strerror(err));
|
||||
|
||||
|
||||
check_prop_labels(sohandle, fdt, "prop1", labels1, ARRAY_SIZE(labels1));
|
||||
check_prop_labels(sohandle, fdt, "prop2", labels2, ARRAY_SIZE(labels2));
|
||||
check_prop_labels(sohandle, fdt, "prop3", labels3, ARRAY_SIZE(labels3));
|
||||
|
||||
PASS();
|
||||
}
|
8
tests/value-labels.dts
Normal file
8
tests/value-labels.dts
Normal file
@ -0,0 +1,8 @@
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
prop1: prop1 = start1: "a", mid1: "b" end1:;
|
||||
prop2: prop2 = start2: < innerstart2: 0xdeadbeef innermid2: 0xabcd1234 innerend2: > end2:;
|
||||
prop3: prop3 = start3: [ innerstart3: ab innermid3: cd innerend3: ] end3:;
|
||||
};
|
||||
|
31
treesource.c
31
treesource.c
@ -52,7 +52,7 @@ static void write_prefix(FILE *f, int level)
|
||||
fputc('\t', f);
|
||||
}
|
||||
|
||||
int isstring(char c)
|
||||
static int isstring(char c)
|
||||
{
|
||||
return (isprint(c)
|
||||
|| (c == '\0')
|
||||
@ -63,26 +63,20 @@ static void write_propval_string(FILE *f, struct data val)
|
||||
{
|
||||
const char *str = val.val;
|
||||
int i;
|
||||
int newchunk = 1;
|
||||
struct marker *m = val.markers;
|
||||
|
||||
assert(str[val.len-1] == '\0');
|
||||
|
||||
while (m && (m->offset == 0)) {
|
||||
if (m->type == LABEL)
|
||||
fprintf(f, "%s: ", m->ref);
|
||||
m = m->next;
|
||||
}
|
||||
fprintf(f, "\"");
|
||||
|
||||
for (i = 0; i < (val.len-1); i++) {
|
||||
char c = str[i];
|
||||
|
||||
if (newchunk) {
|
||||
while (m && (m->offset <= i)) {
|
||||
if (m->type == LABEL) {
|
||||
assert(m->offset == i);
|
||||
fprintf(f, "%s: ", m->ref);
|
||||
}
|
||||
m = m->next;
|
||||
}
|
||||
fprintf(f, "\"");
|
||||
newchunk = 0;
|
||||
}
|
||||
|
||||
switch (c) {
|
||||
case '\a':
|
||||
fprintf(f, "\\a");
|
||||
@ -113,7 +107,14 @@ static void write_propval_string(FILE *f, struct data val)
|
||||
break;
|
||||
case '\0':
|
||||
fprintf(f, "\", ");
|
||||
newchunk = 1;
|
||||
while (m && (m->offset < i)) {
|
||||
if (m->type == LABEL) {
|
||||
assert(m->offset == (i+1));
|
||||
fprintf(f, "%s: ", m->ref);
|
||||
}
|
||||
m = m->next;
|
||||
}
|
||||
fprintf(f, "\"");
|
||||
break;
|
||||
default:
|
||||
if (isprint(c))
|
||||
|
30
util.c
Normal file
30
util.c
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2008 Jon Loeliger, Freescale Semiconductor, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*/
|
||||
|
||||
#include "dtc.h"
|
||||
|
||||
char *xstrdup(const char *s)
|
||||
{
|
||||
int len = strlen(s) + 1;
|
||||
char *dup = xmalloc(len);
|
||||
|
||||
memcpy(dup, s, len);
|
||||
|
||||
return dup;
|
||||
}
|
55
util.h
Normal file
55
util.h
Normal file
@ -0,0 +1,55 @@
|
||||
#ifndef _UTIL_H
|
||||
#define _UTIL_H
|
||||
|
||||
/*
|
||||
* Copyright 2008 Jon Loeliger, Freescale Semiconductor, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*/
|
||||
|
||||
static inline void __attribute__((noreturn)) die(char * str, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, str);
|
||||
fprintf(stderr, "FATAL ERROR: ");
|
||||
vfprintf(stderr, str, ap);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static inline void *xmalloc(size_t len)
|
||||
{
|
||||
void *new = malloc(len);
|
||||
|
||||
if (!new)
|
||||
die("malloc() failed\n");
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
static inline void *xrealloc(void *p, size_t len)
|
||||
{
|
||||
void *new = realloc(p, len);
|
||||
|
||||
if (!new)
|
||||
die("realloc() failed (len=%d)\n", len);
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
extern char *xstrdup(const char *s);
|
||||
|
||||
#endif /* _UTIL_H */
|
Loading…
Reference in New Issue
Block a user