diff options
76 files changed, 1626 insertions, 608 deletions
diff --git a/Documentation/manual.txt b/Documentation/manual.txt index b957662..f8a8a7b 100644 --- a/Documentation/manual.txt +++ b/Documentation/manual.txt @@ -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> @@ -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$@ $< diff --git a/Makefile.convert-dtsv0 b/Makefile.convert-dtsv0 new file mode 100644 index 0000000..08ea40a --- /dev/null +++ b/Makefile.convert-dtsv0 @@ -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) diff --git a/Makefile.dtc b/Makefile.dtc index 6ddf9ec..bece49b 100644 --- a/Makefile.dtc +++ b/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) diff --git a/Makefile.ftdump b/Makefile.ftdump new file mode 100644 index 0000000..b70905a --- /dev/null +++ b/Makefile.ftdump @@ -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) @@ -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) diff --git a/convert-dtsv0-lexer.l b/convert-dtsv0-lexer.l index 12b45ea..59137f1 100644 --- a/convert-dtsv0-lexer.l +++ b/convert-dtsv0-lexer.l @@ -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); } @@ -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; diff --git a/dtc-lexer.l b/dtc-lexer.l index 44dbfd3..d142de5 100644 --- a/dtc-lexer.l +++ b/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] == '[') { diff --git a/dtc-parser.y b/dtc-parser.y index b2ab562..31c14d7 100644 --- a/dtc-parser.y +++ b/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) @@ -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); @@ -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; @@ -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", + 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.long\t_%s_strings_start - _%s_blob_start\t/* off_dt_strings */\n", + fprintf(f, "\t/* off_dt_strings */\n"); + ASM_EMIT_BELONG(f, "_%s_strings_start - _%s_blob_start", symprefix, symprefix); - fprintf(f, "\t.long\t_%s_reserve_map - _%s_blob_start\t/* off_dt_strings */\n", + fprintf(f, "\t/* off_mem_rsvmap */\n"); + ASM_EMIT_BELONG(f, "_%s_reserve_map - _%s_blob_start", 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); + 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_BOOTCPUID) { + fprintf(f, "\t/* boot_cpuid_phys */\n"); + asm_emit_cell(f, 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", - symprefix, symprefix); + 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.long\t_%s_struct_end - _%s_struct_start\t/* size_dt_struct */\n", + 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, @@ -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); } @@ -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; } diff --git a/libfdt/Makefile.libfdt b/libfdt/Makefile.libfdt index 6c42acf..341c803 100644 --- a/libfdt/Makefile.libfdt +++ b/libfdt/Makefile.libfdt @@ -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) diff --git a/libfdt/fdt.c b/libfdt/fdt.c index 2acaec5..b1130c2 100644 --- a/libfdt/fdt.c +++ b/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); diff --git a/libfdt/fdt_ro.c b/libfdt/fdt_ro.c index 129b532..951cc74 100644 --- a/libfdt/fdt_ro.c +++ b/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; diff --git a/libfdt/fdt_rw.c b/libfdt/fdt_rw.c index 8e7ec4c..994037b 100644 --- a/libfdt/fdt_rw.c +++ b/libfdt/fdt_rw.c @@ -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)) { diff --git a/libfdt/fdt_sw.c b/libfdt/fdt_sw.c index 698329e..55ebebf 100644 --- a/libfdt/fdt_sw.c +++ b/libfdt/fdt_sw.c @@ -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)); diff --git a/libfdt/fdt_wip.c b/libfdt/fdt_wip.c index a4652c6..6025fa1 100644 --- a/libfdt/fdt_wip.c +++ b/libfdt/fdt_wip.c @@ -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; - - 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); - - 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; + int depth = 0; + + while ((offset >= 0) && (depth >= 0)) + offset = fdt_next_node(fdt, offset, &depth); + + return offset; } int fdt_nop_node(void *fdt, int nodeoffset) diff --git a/libfdt/libfdt.h b/libfdt/libfdt.h index ce80e4f..18de52b 100644 --- a/libfdt/libfdt.h +++ b/libfdt/libfdt.h @@ -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); @@ -343,6 +343,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 * @nodeoffset: offset of the node whose property to find @@ -380,6 +396,20 @@ static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset, } /** + * 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 * @nodeoffset: offset of the node whose property to find @@ -429,6 +459,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 * @nodeoffset: offset of the node whose path to find diff --git a/libfdt/libfdt_internal.h b/libfdt/libfdt_internal.h index 46eb93e..d2dcbd6 100644 --- a/libfdt/libfdt_internal.h +++ b/libfdt/libfdt_internal.h @@ -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); diff --git a/libfdt/version.lds b/libfdt/version.lds new file mode 100644 index 0000000..3c3994e --- /dev/null +++ b/libfdt/version.lds @@ -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: + *; +}; @@ -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; } @@ -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 @@ fail: 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)); +} + + +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"); - free(file->dir); - free(file); + va_end(va); } @@ -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_ */ diff --git a/tests/Makefile.tests b/tests/Makefile.tests index 704c95d..ac21ade 100644 --- a/tests/Makefile.tests +++ b/tests/Makefile.tests @@ -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) + +$(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_lib) +$(LIBTREE_TESTS): %: $(TESTS_PREFIX)testutils.o $(TESTS_PREFIX)trees.o $(LIBFDT_archive) $(TESTS_PREFIX)dumptrees: $(TESTS_PREFIX)trees.o diff --git a/tests/aliases.dts b/tests/aliases.dts new file mode 100644 index 0000000..39d88ff --- /dev/null +++ b/tests/aliases.dts @@ -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"; + }; + }; + }; +}; diff --git a/tests/asm_tree_dump.c b/tests/asm_tree_dump.c new file mode 100644 index 0000000..5ff5087 --- /dev/null +++ b/tests/asm_tree_dump.c @@ -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(); +} diff --git a/tests/base01.dts b/tests/base01.dts index f84bc49..97a5dd5 100644 --- a/tests/base01.dts +++ b/tests/base01.dts @@ -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>; }; }; diff --git a/tests/data.S b/tests/data.S new file mode 100644 index 0000000..86ad539 --- /dev/null +++ b/tests/data.S @@ -0,0 +1,3 @@ +/* Used in combination with dtc -Oasm output to embed + * a device tree in the data section of a .o */ + .data diff --git a/tests/dtbs_equal_ordered.c b/tests/dtbs_equal_ordered.c index a0b42ae..ed9278c 100644 --- a/tests/dtbs_equal_ordered.c +++ b/tests/dtbs_equal_ordered.c @@ -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; diff --git a/tests/empty.dts b/tests/empty.dts index 336d7a2..e160dad 100644 --- a/tests/empty.dts +++ b/tests/empty.dts @@ -1,2 +1,4 @@ +/dts-v1/; + / { }; diff --git a/tests/escapes.dts b/tests/escapes.dts index f1b8dbc..e05ab46 100644 --- a/tests/escapes.dts +++ b/tests/escapes.dts @@ -1,3 +1,5 @@ +/dts-v1/; + / { compatible = "test_string_escapes"; escape-str = "nastystring: \a\b\t\n\v\f\r\\\""; diff --git a/tests/extra-terminating-null.c b/tests/extra-terminating-null.c new file mode 100644 index 0000000..bb71b1a --- /dev/null +++ b/tests/extra-terminating-null.c @@ -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(); +} diff --git a/tests/extra-terminating-null.dts b/tests/extra-terminating-null.dts new file mode 100644 index 0000000..b6cc19c --- /dev/null +++ b/tests/extra-terminating-null.dts @@ -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"; +}; diff --git a/tests/get_alias.c b/tests/get_alias.c new file mode 100644 index 0000000..8eeaee4 --- /dev/null +++ b/tests/get_alias.c @@ -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(); +} diff --git a/tests/get_name.c b/tests/get_name.c index 22003b4..0262a12 100644 --- a/tests/get_name.c +++ b/tests/get_name.c @@ -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; diff --git a/tests/get_path.c b/tests/get_path.c index 0d208bb..1e05f7c 100644 --- a/tests/get_path.c +++ b/tests/get_path.c @@ -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[]) diff --git a/tests/get_phandle.c b/tests/get_phandle.c index f7650b8..5735733 100644 --- a/tests/get_phandle.c +++ b/tests/get_phandle.c @@ -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; diff --git a/tests/incbin.c b/tests/incbin.c index 5ab3508..76d8626 100644 --- a/tests/incbin.c +++ b/tests/incbin.c @@ -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; diff --git a/tests/include1.dts b/tests/include1.dts index 0c7f42e..5d59d83 100644 --- a/tests/include1.dts +++ b/tests/include1.dts @@ -15,9 +15,12 @@ prop-int = <123456789>; /include/ "include8.dts" - linux,phandle = <0x2001>; + phandle = <0x2001>; compatible = "subsubnode2", "subsubnode"; prop-int = <0726746425>; }; + + ss2 { + }; }; }; diff --git a/tests/include7.dts b/tests/include7.dts index fa726f9..dba5e47 100644 --- a/tests/include7.dts +++ b/tests/include7.dts @@ -6,4 +6,7 @@ compatible = "subsubnode1", "subsubnode"; prop-int = <0xdeadbeef>; }; + + ss1 { + }; }; diff --git a/tests/label01.dts b/tests/label01.dts index 372b17a..a895803 100644 --- a/tests/label01.dts +++ b/tests/label01.dts @@ -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>; }; }; diff --git a/tests/mangle-layout.c b/tests/mangle-layout.c index bd6ac40..5be28b9 100644 --- a/tests/mangle-layout.c +++ b/tests/mangle-layout.c @@ -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; diff --git a/tests/node_check_compatible.c b/tests/node_check_compatible.c index 04b6b40..23abbf5 100644 --- a/tests/node_check_compatible.c +++ b/tests/node_check_compatible.c @@ -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; diff --git a/tests/node_offset_by_compatible.c b/tests/node_offset_by_compatible.c index 02e9874..2317930 100644 --- a/tests/node_offset_by_compatible.c +++ b/tests/node_offset_by_compatible.c @@ -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; diff --git a/tests/node_offset_by_phandle.c b/tests/node_offset_by_phandle.c index e9fd939..a8442f1 100644 --- a/tests/node_offset_by_phandle.c +++ b/tests/node_offset_by_phandle.c @@ -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; diff --git a/tests/node_offset_by_prop_value.c b/tests/node_offset_by_prop_value.c index c55110a..0f2a345 100644 --- a/tests/node_offset_by_prop_value.c +++ b/tests/node_offset_by_prop_value.c @@ -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; diff --git a/tests/nopulate.c b/tests/nopulate.c index e56839a..3cbbe21 100644 --- a/tests/nopulate.c +++ b/tests/nopulate.c @@ -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; diff --git a/tests/notfound.c b/tests/notfound.c index ae28c44..38918ad 100644 --- a/tests/notfound.c +++ b/tests/notfound.c @@ -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, diff --git a/tests/parent_offset.c b/tests/parent_offset.c index 8336c72..e7affcc 100644 --- a/tests/parent_offset.c +++ b/tests/parent_offset.c @@ -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; diff --git a/tests/path-references.c b/tests/path-references.c index b96c5b2..9f363b3 100644 --- a/tests/path-references.c +++ b/tests/path-references.c @@ -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; diff --git a/tests/path_offset.c b/tests/path_offset.c index 4b014ac..bb092f1 100644 --- a/tests/path_offset.c +++ b/tests/path_offset.c @@ -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; diff --git a/tests/path_offset_aliases.c b/tests/path_offset_aliases.c new file mode 100644 index 0000000..191edd2 --- /dev/null +++ b/tests/path_offset_aliases.c @@ -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(); +} diff --git a/tests/phandle_format.c b/tests/phandle_format.c new file mode 100644 index 0000000..7e4d816 --- /dev/null +++ b/tests/phandle_format.c @@ -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(); +} diff --git a/tests/references.c b/tests/references.c index e98d450..b20f21f 100644 --- a/tests/references.c +++ b/tests/references.c @@ -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); diff --git a/tests/references.dts b/tests/references.dts index 36b6f51..640c931 100644 --- a/tests/references.dts +++ b/tests/references.dts @@ -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>; + }; }; diff --git a/tests/references_dts0.dts b/tests/references_dts0.dts index df82c23..d34dbb2 100644 --- a/tests/references_dts0.dts +++ b/tests/references_dts0.dts @@ -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>; + }; }; diff --git a/tests/run_tests.sh b/tests/run_tests.sh index 7bfc399..c532030 100755 --- a/tests/run_tests.sh +++ b/tests/run_tests.sh @@ -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 "**********" diff --git a/tests/rw_tree1.c b/tests/rw_tree1.c index 8f335c9..f0bce88 100644 --- a/tests/rw_tree1.c +++ b/tests/rw_tree1.c @@ -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)); diff --git a/tests/set_name.c b/tests/set_name.c index 49817a9..5d1149e 100644 --- a/tests/set_name.c +++ b/tests/set_name.c @@ -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; diff --git a/tests/subnode_offset.c b/tests/subnode_offset.c index ac2f32e..b961070 100644 --- a/tests/subnode_offset.c +++ b/tests/subnode_offset.c @@ -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(); } diff --git a/tests/supernode_atdepth_offset.c b/tests/supernode_atdepth_offset.c index 1245813..73f41ae 100644 --- a/tests/supernode_atdepth_offset.c +++ b/tests/supernode_atdepth_offset.c @@ -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; diff --git a/tests/sw_tree1.c b/tests/sw_tree1.c index 2a94b63..f2c430a 100644 --- a/tests/sw_tree1.c +++ b/tests/sw_tree1.c @@ -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)); diff --git a/tests/test01.dts b/tests/test01.dts index ed2b178..f9fd165 100644 --- a/tests/test01.dts +++ b/tests/test01.dts @@ -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>; }; }; diff --git a/tests/test_tree1.dts b/tests/test_tree1.dts index 27602af..218c382 100644 --- a/tests/test_tree1.dts +++ b/tests/test_tree1.dts @@ -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 { + }; }; }; diff --git a/tests/test_tree1_dts0.dts b/tests/test_tree1_dts0.dts index bc65819..032d540 100644 --- a/tests/test_tree1_dts0.dts +++ b/tests/test_tree1_dts0.dts @@ -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 { }; }; }; diff --git a/tests/tests.h b/tests/tests.h index c273f3c..fcb2b2a 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -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) diff --git a/tests/trees.S b/tests/trees.S index cedf5f9..66adf3f 100644 --- a/tests/trees.S +++ b/tests/trees.S @@ -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: diff --git a/tests/value-labels.c b/tests/value-labels.c new file mode 100644 index 0000000..c5aea8f --- /dev/null +++ b/tests/value-labels.c @@ -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(); +} diff --git a/tests/value-labels.dts b/tests/value-labels.dts new file mode 100644 index 0000000..490c609 --- /dev/null +++ b/tests/value-labels.dts @@ -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:; +}; + diff --git a/treesource.c b/treesource.c index ebeb6eb..cc1751d 100644 --- a/treesource.c +++ b/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)) @@ -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; +} @@ -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 */ |