From 939bdb9f6a0dad490702c3009bb8714579e1e765 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Mon, 27 Jan 2014 06:20:36 +0000 Subject: [PATCH] Import dtc git at 6a15eb2350426d285130e4c9d84c0bdb6575547a (last rev before bison became required) --- Documentation/manual.txt | 5 + Makefile | 14 ++- checks.c | 24 +++-- convert-dtsv0-lexer.l | 24 +++-- data.c | 10 +- dtc-lexer.l | 98 ++++++++++++++++--- dtc-parser.y | 110 ++++++++------------- dtc.c | 125 ++++++++++++------------ dtc.h | 33 +++++-- fdtdump.c | 133 +++++++++++++++++++------- fdtget.c | 60 ++++++------ fdtput.c | 135 ++++++++++++++++---------- flattree.c | 7 +- libfdt/Makefile.libfdt | 2 +- libfdt/fdt.c | 30 +++++- libfdt/fdt.h | 93 ++++++++++++++---- libfdt/fdt_ro.c | 7 +- libfdt/fdt_rw.c | 4 +- libfdt/fdt_sw.c | 36 ++++++- libfdt/fdt_wip.c | 2 +- libfdt/libfdt.h | 71 ++++++++++---- libfdt/libfdt_env.h | 104 +++++++++++++++++--- libfdt/version.lds | 6 ++ livetree.c | 126 +++++++++++++++++++++--- srcpos.c | 43 ++++----- srcpos.h | 17 ++-- tests/Makefile.tests | 5 +- tests/add_subnode_with_nops.c | 1 - tests/aliases.dts | 4 + tests/appendprop1.c | 1 - tests/appendprop2.c | 1 - tests/asm_tree_dump.c | 1 - tests/boot-cpuid.c | 1 - tests/char_literal.c | 1 - tests/del_node.c | 1 - tests/del_property.c | 1 - tests/dtb_reverse.c | 1 - tests/dtbs_equal_ordered.c | 1 - tests/dtbs_equal_unordered.c | 1 - tests/dumptrees.c | 2 - tests/extra-terminating-null.c | 1 - tests/fdtget-runtest.sh | 2 +- tests/find_property.c | 1 - tests/get_alias.c | 1 - tests/get_mem_rsv.c | 1 - tests/get_name.c | 1 - tests/get_path.c | 1 - tests/get_phandle.c | 1 - tests/getprop.c | 1 - tests/incbin.c | 1 - tests/include1.dts | 5 + tests/include7.dts | 1 + tests/include8.dts | 3 +- tests/integer-expressions.c | 1 - tests/mangle-layout.c | 1 - tests/move_and_save.c | 1 - tests/node_check_compatible.c | 1 - tests/node_offset_by_compatible.c | 1 - tests/node_offset_by_phandle.c | 1 - tests/node_offset_by_prop_value.c | 1 - tests/nop_node.c | 1 - tests/nop_property.c | 1 - tests/nopulate.c | 1 - tests/notfound.c | 1 - tests/open_pack.c | 1 - tests/parent_offset.c | 1 - tests/path-references.c | 1 - tests/path_offset.c | 1 - tests/path_offset_aliases.c | 1 - tests/phandle_format.c | 1 - tests/references.c | 1 - tests/root_node.c | 1 - tests/run_tests.sh | 45 +++++++-- tests/rw_tree1.c | 1 - tests/set_name.c | 1 - tests/setprop.c | 1 - tests/setprop_inplace.c | 1 - tests/sized_cells.c | 1 - tests/string_escapes.c | 1 - tests/subnode_offset.c | 1 - tests/supernode_atdepth_offset.c | 1 - tests/sw_tree1.c | 92 ++++++++++++++++-- tests/test_tree1.dts | 37 +------ tests/test_tree1_merge.dts | 7 ++ tests/test_tree1_merge_labelled.dts | 7 ++ tests/test_tree1_merge_path.dts | 7 ++ tests/test_tree1_wrong1.dts | 7 ++ tests/test_tree1_wrong2.dts | 7 ++ tests/test_tree1_wrong3.dts | 7 ++ tests/test_tree1_wrong4.dts | 7 ++ tests/test_tree1_wrong5.dts | 7 ++ tests/test_tree1_wrong6.dts | 7 ++ tests/test_tree1_wrong7.dts | 7 ++ tests/test_tree1_wrong8.dts | 7 ++ tests/test_tree1_wrong9.dts | 7 ++ tests/trees.S | 10 ++ tests/truncated_property.c | 1 - tests/utilfdt_test.c | 1 - tests/value-labels.c | 1 - treesource.c | 10 +- util.c | 143 +++++++++++++++++++++++++--- util.h | 110 +++++++++++++++++++-- 102 files changed, 1390 insertions(+), 532 deletions(-) diff --git a/Documentation/manual.txt b/Documentation/manual.txt index 989c5892e44..65c8540be71 100644 --- a/Documentation/manual.txt +++ b/Documentation/manual.txt @@ -3,6 +3,7 @@ Device Tree Compiler Manual I - "dtc", the device tree compiler 1) Obtaining Sources + 1.1) Submitting Patches 2) Description 3) Command Line 4) Source File @@ -44,6 +45,10 @@ Tarballs of the 1.0.0 and latest releases are here: http://www.jdl.com/software/dtc-v1.2.0.tgz http://www.jdl.com/software/dtc-latest.tgz +1.1) Submitting Patches + +Patches should be sent to jdl@jdl.com, and CC'ed to +devicetree-discuss@lists.ozlabs.org. 2) Description diff --git a/Makefile b/Makefile index 1169e6c02dc..70abf05d874 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ # CONFIG_LOCALVERSION from some future config system. # VERSION = 1 -PATCHLEVEL = 3 +PATCHLEVEL = 4 SUBLEVEL = 0 EXTRAVERSION = LOCAL_VERSION = @@ -160,18 +160,26 @@ endif # intermediate target and building them again "for real" .SECONDARY: $(DTC_GEN_SRCS) $(CONVERT_GEN_SRCS) -install: all $(SCRIPTS) - @$(VECHO) INSTALL +install-bin: all $(SCRIPTS) + @$(VECHO) INSTALL-BIN $(INSTALL) -d $(DESTDIR)$(BINDIR) $(INSTALL) $(BIN) $(SCRIPTS) $(DESTDIR)$(BINDIR) + +install-lib: all + @$(VECHO) INSTALL-LIB $(INSTALL) -d $(DESTDIR)$(LIBDIR) $(INSTALL) $(LIBFDT_lib) $(DESTDIR)$(LIBDIR) ln -sf $(notdir $(LIBFDT_lib)) $(DESTDIR)$(LIBDIR)/$(LIBFDT_soname) ln -sf $(LIBFDT_soname) $(DESTDIR)$(LIBDIR)/libfdt.$(SHAREDLIB_EXT) $(INSTALL) -m 644 $(LIBFDT_archive) $(DESTDIR)$(LIBDIR) + +install-includes: + @$(VECHO) INSTALL-INC $(INSTALL) -d $(DESTDIR)$(INCLUDEDIR) $(INSTALL) -m 644 $(LIBFDT_include) $(DESTDIR)$(INCLUDEDIR) +install: install-bin install-lib install-includes + $(VERSION_FILE): Makefile FORCE $(call filechk,version) diff --git a/checks.c b/checks.c index 9061237f1cc..11a40861e40 100644 --- a/checks.c +++ b/checks.c @@ -53,7 +53,7 @@ struct check { void *data; bool warn, error; enum checkstatus status; - int inprogress; + bool inprogress; int num_prereqs; struct check **prereq; }; @@ -141,9 +141,9 @@ static void check_nodes_props(struct check *c, struct node *dt, struct node *nod check_nodes_props(c, dt, child); } -static int run_check(struct check *c, struct node *dt) +static bool run_check(struct check *c, struct node *dt) { - int error = 0; + bool error = false; int i; assert(!c->inprogress); @@ -151,11 +151,11 @@ static int run_check(struct check *c, struct node *dt) if (c->status != UNCHECKED) goto out; - c->inprogress = 1; + c->inprogress = true; for (i = 0; i < c->num_prereqs; i++) { struct check *prq = c->prereq[i]; - error |= run_check(prq, dt); + error = error || run_check(prq, dt); if (prq->status != PASSED) { c->status = PREREQ; check_msg(c, "Failed prerequisite '%s'", @@ -177,9 +177,9 @@ static int run_check(struct check *c, struct node *dt) TRACE(c, "\tCompleted, status %d", c->status); out: - c->inprogress = 0; + c->inprogress = false; if ((c->status != PASSED) && (c->error)) - error = 1; + error = true; return error; } @@ -256,11 +256,15 @@ static void check_duplicate_property_names(struct check *c, struct node *dt, { struct property *prop, *prop2; - for_each_property(node, prop) - for (prop2 = prop->next; prop2; prop2 = prop2->next) + for_each_property(node, prop) { + for (prop2 = prop->next; prop2; prop2 = prop2->next) { + if (prop2->deleted) + continue; if (streq(prop->name, prop2->name)) FAIL(c, "Duplicate property name %s in %s", prop->name, node->fullpath); + } + } } NODE_ERROR(duplicate_property_names, NULL); @@ -729,7 +733,7 @@ void parse_checks_option(bool warn, bool error, const char *optarg) die("Unrecognized check name \"%s\"\n", name); } -void process_checks(int force, struct boot_info *bi) +void process_checks(bool force, struct boot_info *bi) { struct node *dt = bi->dt; int i; diff --git a/convert-dtsv0-lexer.l b/convert-dtsv0-lexer.l index 89d540a7f23..548e7199a0c 100644 --- a/convert-dtsv0-lexer.l +++ b/convert-dtsv0-lexer.l @@ -50,8 +50,6 @@ static int saw_hyphen; /* = 0 */ static unsigned long long last_val; static char *last_name; /* = NULL */ -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) - const struct { const char *pattern; int obase, width; @@ -194,11 +192,15 @@ const struct { } %% -static void usage(void) -{ - fprintf(stderr, "convert-dtsv0 ...\n"); - exit(3); -} +/* Usage related data. */ +static const char usage_synopsis[] = "convert-dtsv0 [options] ..."; +static const char usage_short_opts[] = "" USAGE_COMMON_SHORT_OPTS; +static struct option const usage_long_opts[] = { + USAGE_COMMON_LONG_OPTS +}; +static const char * const usage_opts_help[] = { + USAGE_COMMON_OPTS_HELP +}; static void convert_file(const char *fname) { @@ -226,10 +228,16 @@ static void convert_file(const char *fname) int main(int argc, char *argv[]) { + int opt; int i; + while ((opt = util_getopt_long()) != EOF) { + switch (opt) { + case_USAGE_COMMON_FLAGS + } + } if (argc < 2) - usage(); + usage("missing filename"); for (i = 1; i < argc; i++) { fprintf(stderr, "Converting %s from dts v0 to dts v1\n", argv[i]); diff --git a/data.c b/data.c index 4a40c5b9247..4c50b125955 100644 --- a/data.c +++ b/data.c @@ -250,20 +250,20 @@ struct data data_add_marker(struct data d, enum markertype type, char *ref) return data_append_markers(d, m); } -int data_is_one_string(struct data d) +bool data_is_one_string(struct data d) { int i; int len = d.len; if (len == 0) - return 0; + return false; for (i = 0; i < len-1; i++) if (d.val[i] == '\0') - return 0; + return false; if (d.val[len-1] != '\0') - return 0; + return false; - return 1; + return true; } diff --git a/dtc-lexer.l b/dtc-lexer.l index 4715f31544a..0821bde3124 100644 --- a/dtc-lexer.l +++ b/dtc-lexer.l @@ -40,6 +40,7 @@ LINECOMMENT "//".*\n #include "dtc-parser.tab.h" YYLTYPE yylloc; +extern bool treesource_error; /* CAUTION: this will stop working if we ever use yyless() or yyunput() */ #define YY_USER_ACTION \ @@ -61,7 +62,8 @@ static int dts_version = 1; BEGIN(V1); \ static void push_input_file(const char *filename); -static int pop_input_file(void); +static bool pop_input_file(void); +static void lexical_error(const char *fmt, ...); %} %% @@ -71,6 +73,27 @@ static int pop_input_file(void); push_input_file(name); } +<*>^"#"(line)?[ \t]+[0-9]+[ \t]+{STRING}([ \t]+[0-9]+)? { + char *line, *tmp, *fn; + /* skip text before line # */ + line = yytext; + while (!isdigit((unsigned char)*line)) + line++; + /* skip digits in line # */ + tmp = line; + while (!isspace((unsigned char)*tmp)) + tmp++; + /* "NULL"-terminate line # */ + *tmp = '\0'; + /* start of filename */ + fn = strchr(tmp + 1, '"') + 1; + /* strip trailing " from filename */ + tmp = strchr(fn, '"'); + *tmp = 0; + /* -1 since #line is the number of the next line */ + srcpos_set_line(xstrdup(fn), atoi(line) - 1); + } + <*><> { if (!pop_input_file()) { yyterminate(); @@ -103,6 +126,20 @@ static int pop_input_file(void); return DT_BITS; } +<*>"/delete-property/" { + DPRINT("Keyword: /delete-property/\n"); + DPRINT("\n"); + BEGIN(PROPNODENAME); + return DT_DEL_PROP; + } + +<*>"/delete-node/" { + DPRINT("Keyword: /delete-node/\n"); + DPRINT("\n"); + BEGIN(PROPNODENAME); + return DT_DEL_NODE; + } + <*>{LABEL}: { DPRINT("Label: %s\n", yytext); yylval.labelref = xstrdup(yytext); @@ -111,15 +148,42 @@ static int pop_input_file(void); } ([0-9]+|0[xX][0-9a-fA-F]+)(U|L|UL|LL|ULL)? { - yylval.literal = xstrdup(yytext); - DPRINT("Literal: '%s'\n", yylval.literal); + char *e; + DPRINT("Integer Literal: '%s'\n", yytext); + + errno = 0; + yylval.integer = strtoull(yytext, &e, 0); + + assert(!(*e) || !e[strspn(e, "UL")]); + + if (errno == ERANGE) + lexical_error("Integer literal '%s' out of range", + yytext); + else + /* ERANGE is the only strtoull error triggerable + * by strings matching the pattern */ + assert(errno == 0); return DT_LITERAL; } <*>{CHAR_LITERAL} { - yytext[yyleng-1] = '\0'; - yylval.literal = xstrdup(yytext+1); - DPRINT("Character literal: %s\n", yylval.literal); + struct data d; + DPRINT("Character literal: %s\n", yytext); + + d = data_copy_escape_string(yytext+1, yyleng-2); + if (d.len == 1) { + lexical_error("Empty character literal"); + yylval.integer = 0; + return DT_CHAR_LITERAL; + } + + yylval.integer = (unsigned char)d.val[0]; + + if (d.len > 2) + lexical_error("Character literal has %d" + " characters instead of 1", + d.len - 1); + return DT_CHAR_LITERAL; } @@ -148,9 +212,10 @@ static int pop_input_file(void); return ']'; } -{PROPNODECHAR}+ { +\\?{PROPNODECHAR}+ { DPRINT("PropNodeName: %s\n", yytext); - yylval.propnodename = xstrdup(yytext); + yylval.propnodename = xstrdup((yytext[0] == '\\') ? + yytext + 1 : yytext); BEGIN_DEFAULT(); return DT_PROPNODENAME; } @@ -202,13 +267,24 @@ static void push_input_file(const char *filename) } -static int pop_input_file(void) +static bool pop_input_file(void) { if (srcfile_pop() == 0) - return 0; + return false; yypop_buffer_state(); yyin = current_srcfile->f; - return 1; + return true; +} + +static void lexical_error(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + srcpos_verror(&yylloc, "Lexical error", fmt, ap); + va_end(ap); + + treesource_error = true; } diff --git a/dtc-parser.y b/dtc-parser.y index 6d5c2c2de6c..bed857e7279 100644 --- a/dtc-parser.y +++ b/dtc-parser.y @@ -31,15 +31,11 @@ extern void print_error(char const *fmt, ...); extern void yyerror(char const *s); extern struct boot_info *the_boot_info; -extern int treesource_error; - -static unsigned long long eval_literal(const char *s, int base, int bits); -static unsigned char eval_char_literal(const char *s); +extern bool treesource_error; %} %union { char *propnodename; - char *literal; char *labelref; unsigned int cbase; uint8_t byte; @@ -62,9 +58,11 @@ static unsigned char eval_char_literal(const char *s); %token DT_MEMRESERVE %token DT_LSHIFT DT_RSHIFT DT_LE DT_GE DT_EQ DT_NE DT_AND DT_OR %token DT_BITS +%token DT_DEL_PROP +%token DT_DEL_NODE %token DT_PROPNODENAME -%token DT_LITERAL -%token DT_CHAR_LITERAL +%token DT_LITERAL +%token DT_CHAR_LITERAL %token DT_BASE %token DT_BYTE %token DT_STRING @@ -153,6 +151,17 @@ devicetree: print_error("label or path, '%s', not found", $2); $$ = $1; } + | devicetree DT_DEL_NODE DT_REF ';' + { + struct node *target = get_node_by_ref($1, $3); + + if (!target) + print_error("label or path, '%s', not found", $3); + else + delete_node(target); + + $$ = $1; + } ; nodedef: @@ -182,6 +191,10 @@ propdef: { $$ = build_property($1, empty_data); } + | DT_DEL_PROP DT_PROPNODENAME ';' + { + $$ = build_property_delete($2); + } | DT_LABEL propdef { add_label(&$2->labels, $1); @@ -213,10 +226,9 @@ propdata: if ($6 != 0) if (fseek(f, $6, SEEK_SET) != 0) - print_error("Couldn't seek to offset %llu in \"%s\": %s", - (unsigned long long)$6, - $4.val, - strerror(errno)); + die("Couldn't seek to offset %llu in \"%s\": %s", + (unsigned long long)$6, $4.val, + strerror(errno)); d = data_copy_file(f, $8); @@ -257,18 +269,20 @@ propdataprefix: arrayprefix: DT_BITS DT_LITERAL '<' { - $$.data = empty_data; - $$.bits = eval_literal($2, 0, 7); + unsigned long long bits; - if (($$.bits != 8) && - ($$.bits != 16) && - ($$.bits != 32) && - ($$.bits != 64)) + bits = $2; + + if ((bits != 8) && (bits != 16) && + (bits != 32) && (bits != 64)) { print_error("Only 8, 16, 32 and 64-bit elements" " are currently supported"); - $$.bits = 32; + bits = 32; } + + $$.data = empty_data; + $$.bits = bits; } | '<' { @@ -317,13 +331,7 @@ arrayprefix: integer_prim: DT_LITERAL - { - $$ = eval_literal($1, 0, 64); - } | DT_CHAR_LITERAL - { - $$ = eval_char_literal($1); - } | '(' integer_expr ')' { $$ = $2; @@ -440,6 +448,10 @@ subnode: { $$ = name_node($2, $1); } + | DT_DEL_NODE DT_PROPNODENAME ';' + { + $$ = name_node(build_node_delete(), $2); + } | DT_LABEL subnode { add_label(&$2->labels, $1); @@ -454,58 +466,12 @@ void print_error(char const *fmt, ...) va_list va; va_start(va, fmt); - srcpos_verror(&yylloc, fmt, va); + srcpos_verror(&yylloc, "Error", fmt, va); va_end(va); - treesource_error = 1; + treesource_error = true; } void yyerror(char const *s) { print_error("%s", s); } - -static unsigned long long eval_literal(const char *s, int base, int bits) -{ - unsigned long long val; - char *e; - - errno = 0; - val = strtoull(s, &e, base); - if (*e) { - size_t uls = strspn(e, "UL"); - if (e[uls]) - print_error("bad characters in literal"); - } - if ((errno == ERANGE) - || ((bits < 64) && (val >= (1ULL << bits)))) - print_error("literal out of range"); - else if (errno != 0) - print_error("bad literal"); - return val; -} - -static unsigned char eval_char_literal(const char *s) -{ - int i = 1; - char c = s[0]; - - if (c == '\0') - { - print_error("empty character literal"); - return 0; - } - - /* - * If the first character in the character literal is a \ then process - * the remaining characters as an escape encoding. If the first - * character is neither an escape or a terminator it should be the only - * character in the literal and will be returned. - */ - if (c == '\\') - c = get_escape_char(s, &i); - - if (s[i] != '\0') - print_error("malformed character literal"); - - return c; -} diff --git a/dtc.c b/dtc.c index a375683c153..d36ccdc2176 100644 --- a/dtc.c +++ b/dtc.c @@ -21,8 +21,6 @@ #include "dtc.h" #include "srcpos.h" -#include "version_gen.h" - /* * Command line options */ @@ -49,55 +47,60 @@ static void fill_fullpaths(struct node *tree, const char *prefix) fill_fullpaths(child, tree->fullpath); } -static void __attribute__ ((noreturn)) usage(void) -{ - fprintf(stderr, "Usage:\n"); - fprintf(stderr, "\tdtc [options] \n"); - fprintf(stderr, "\nOptions:\n"); - fprintf(stderr, "\t-h\n"); - fprintf(stderr, "\t\tThis help text\n"); - fprintf(stderr, "\t-q\n"); - fprintf(stderr, "\t\tQuiet: -q suppress warnings, -qq errors, -qqq all\n"); - fprintf(stderr, "\t-I \n"); - fprintf(stderr, "\t\tInput formats are:\n"); - fprintf(stderr, "\t\t\tdts - device tree source text\n"); - fprintf(stderr, "\t\t\tdtb - device tree blob\n"); - fprintf(stderr, "\t\t\tfs - /proc/device-tree style directory\n"); - fprintf(stderr, "\t-o \n"); - fprintf(stderr, "\t-O \n"); - fprintf(stderr, "\t\tOutput formats are:\n"); - fprintf(stderr, "\t\t\tdts - device tree source text\n"); - fprintf(stderr, "\t\t\tdtb - device tree blob\n"); - fprintf(stderr, "\t\t\tasm - assembler source\n"); - fprintf(stderr, "\t-V \n"); - fprintf(stderr, "\t\tBlob version to produce, defaults to %d (relevant for dtb\n\t\tand asm output only)\n", DEFAULT_FDT_VERSION); - fprintf(stderr, "\t-d \n"); - fprintf(stderr, "\t-R \n"); - fprintf(stderr, "\t\tMake space for reserve map entries (relevant for \n\t\tdtb and asm output only)\n"); - fprintf(stderr, "\t-S \n"); - fprintf(stderr, "\t\tMake the blob at least long (extra space)\n"); - fprintf(stderr, "\t-p \n"); - fprintf(stderr, "\t\tAdd padding to the blob of long (extra space)\n"); - fprintf(stderr, "\t-b \n"); - fprintf(stderr, "\t\tSet the physical boot cpu\n"); - fprintf(stderr, "\t-f\n"); - fprintf(stderr, "\t\tForce - try to produce output even if the input tree has errors\n"); - fprintf(stderr, "\t-i\n"); - fprintf(stderr, "\t\tAdd a path to search for include files\n"); - fprintf(stderr, "\t-s\n"); - fprintf(stderr, "\t\tSort nodes and properties before outputting (only useful for\n\t\tcomparing trees)\n"); - fprintf(stderr, "\t-v\n"); - fprintf(stderr, "\t\tPrint DTC version and exit\n"); - fprintf(stderr, "\t-H \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"); - fprintf(stderr, "\t-W [no-]\n"); - fprintf(stderr, "\t-E [no-]\n"); - fprintf(stderr, "\t\t\tenable or disable warnings and errors\n"); - exit(3); -} +/* Usage related data. */ +static const char usage_synopsis[] = "dtc [options] "; +static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:fb:i:H:sW:E:hv"; +static struct option const usage_long_opts[] = { + {"quiet", no_argument, NULL, 'q'}, + {"in-format", a_argument, NULL, 'I'}, + {"out", a_argument, NULL, 'o'}, + {"out-format", a_argument, NULL, 'O'}, + {"out-version", a_argument, NULL, 'V'}, + {"out-dependency", a_argument, NULL, 'd'}, + {"reserve", a_argument, NULL, 'R'}, + {"space", a_argument, NULL, 'S'}, + {"pad", a_argument, NULL, 'p'}, + {"boot-cpu", a_argument, NULL, 'b'}, + {"force", no_argument, NULL, 'f'}, + {"include", a_argument, NULL, 'i'}, + {"sort", no_argument, NULL, 's'}, + {"phandle", a_argument, NULL, 'H'}, + {"warning", a_argument, NULL, 'W'}, + {"error", a_argument, NULL, 'E'}, + {"help", no_argument, NULL, 'h'}, + {"version", no_argument, NULL, 'v'}, + {NULL, no_argument, NULL, 0x0}, +}; +static const char * const usage_opts_help[] = { + "\n\tQuiet: -q suppress warnings, -qq errors, -qqq all", + "\n\tInput formats are:\n" + "\t\tdts - device tree source text\n" + "\t\tdtb - device tree blob\n" + "\t\tfs - /proc/device-tree style directory", + "\n\tOutput file", + "\n\tOutput formats are:\n" + "\t\tdts - device tree source text\n" + "\t\tdtb - device tree blob\n" + "\t\tasm - assembler source", + "\n\tBlob version to produce, defaults to %d (for dtb and asm output)", //, DEFAULT_FDT_VERSION); + "\n\tOutput dependency file", + "\n\ttMake space for reserve map entries (for dtb and asm output)", + "\n\tMake the blob at least long (extra space)", + "\n\tAdd padding to the blob of long (extra space)", + "\n\tSet the physical boot cpu", + "\n\tTry to produce output even if the input tree has errors", + "\n\tAdd a path to search for include files", + "\n\tSort nodes and properties before outputting (useful for comparing trees)", + "\n\tValid phandle formats are:\n" + "\t\tlegacy - \"linux,phandle\" properties only\n" + "\t\tepapr - \"phandle\" properties only\n" + "\t\tboth - Both \"linux,phandle\" and \"phandle\" properties", + "\n\tEnable/disable warnings (prefix with \"no-\")", + "\n\tEnable/disable errors (prefix with \"no-\")", + "\n\tPrint this help and exit", + "\n\tPrint version and exit", + NULL, +}; int main(int argc, char *argv[]) { @@ -106,7 +109,7 @@ int main(int argc, char *argv[]) const char *outform = "dts"; const char *outname = "-"; const char *depname = NULL; - int force = 0, sort = 0; + bool force = false, sort = false; const char *arg; int opt; FILE *outf = NULL; @@ -118,8 +121,7 @@ int main(int argc, char *argv[]) minsize = 0; padsize = 0; - while ((opt = getopt(argc, argv, "hI:O:o:V:d:R:S:p:fqb:i:vH:sW:E:")) - != EOF) { + while ((opt = util_getopt_long()) != EOF) { switch (opt) { case 'I': inform = optarg; @@ -146,7 +148,7 @@ int main(int argc, char *argv[]) padsize = strtol(optarg, NULL, 0); break; case 'f': - force = 1; + force = true; break; case 'q': quiet++; @@ -158,8 +160,7 @@ int main(int argc, char *argv[]) srcfile_add_search_path(optarg); break; case 'v': - printf("Version: %s\n", DTC_VERSION); - exit(0); + util_version(); case 'H': if (streq(optarg, "legacy")) phandle_format = PHANDLE_LEGACY; @@ -173,7 +174,7 @@ int main(int argc, char *argv[]) break; case 's': - sort = 1; + sort = true; break; case 'W': @@ -185,13 +186,14 @@ int main(int argc, char *argv[]) break; case 'h': + usage(NULL); default: - usage(); + usage("unknown option"); } } if (argc > (optind+1)) - usage(); + usage("missing files"); else if (argc < (optind+1)) arg = "-"; else @@ -201,9 +203,6 @@ 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"); - if (depname) { depfile = fopen(depname, "w"); if (!depfile) diff --git a/dtc.h b/dtc.h index 7ee2d544b67..20e4d5620cb 100644 --- a/dtc.h +++ b/dtc.h @@ -66,7 +66,6 @@ typedef uint32_t cell_t; #define strneq(a, b, n) (strncmp((a), (b), (n)) == 0) #define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) /* Data blobs */ enum markertype { @@ -119,7 +118,7 @@ struct data data_append_align(struct data d, int align); struct data data_add_marker(struct data d, enum markertype type, char *ref); -int data_is_one_string(struct data d); +bool data_is_one_string(struct data d); /* DT constraints */ @@ -128,11 +127,13 @@ int data_is_one_string(struct data d); /* Live trees */ struct label { + bool deleted; char *label; struct label *next; }; struct property { + bool deleted; char *name; struct data val; @@ -142,6 +143,7 @@ struct property { }; struct node { + bool deleted; char *name; struct property *proplist; struct node *children; @@ -158,28 +160,47 @@ struct node { struct label *labels; }; -#define for_each_label(l0, l) \ +#define for_each_label_withdel(l0, l) \ for ((l) = (l0); (l); (l) = (l)->next) -#define for_each_property(n, p) \ +#define for_each_label(l0, l) \ + for_each_label_withdel(l0, l) \ + if (!(l)->deleted) + +#define for_each_property_withdel(n, p) \ for ((p) = (n)->proplist; (p); (p) = (p)->next) -#define for_each_child(n, c) \ +#define for_each_property(n, p) \ + for_each_property_withdel(n, p) \ + if (!(p)->deleted) + +#define for_each_child_withdel(n, c) \ for ((c) = (n)->children; (c); (c) = (c)->next_sibling) +#define for_each_child(n, c) \ + for_each_child_withdel(n, c) \ + if (!(c)->deleted) + void add_label(struct label **labels, char *label); +void delete_labels(struct label **labels); struct property *build_property(char *name, struct data val); +struct property *build_property_delete(char *name); struct property *chain_property(struct property *first, struct property *list); struct property *reverse_properties(struct property *first); struct node *build_node(struct property *proplist, struct node *children); +struct node *build_node_delete(void); struct node *name_node(struct node *node, char *name); struct node *chain_node(struct node *first, struct node *list); struct node *merge_nodes(struct node *old_node, struct node *new_node); void add_property(struct node *node, struct property *prop); +void delete_property_by_name(struct node *node, char *name); +void delete_property(struct property *prop); void add_child(struct node *parent, struct node *child); +void delete_node_by_name(struct node *parent, char *name); +void delete_node(struct node *node); const char *get_unitname(struct node *node); struct property *get_property(struct node *node, const char *propname); @@ -227,7 +248,7 @@ void sort_tree(struct boot_info *bi); /* Checks */ void parse_checks_option(bool warn, bool error, const char *optarg); -void process_checks(int force, struct boot_info *bi); +void process_checks(bool force, struct boot_info *bi); /* Flattened trees */ diff --git a/fdtdump.c b/fdtdump.c index 207a46d6486..723770d6d33 100644 --- a/fdtdump.c +++ b/fdtdump.c @@ -2,14 +2,16 @@ * fdtdump.c - Contributed by Pantelis Antoniou */ +#include #include #include #include #include #include -#include +#include #include +#include #include "util.h" @@ -17,33 +19,29 @@ #define PALIGN(p, a) ((void *)(ALIGN((unsigned long)(p), (a)))) #define GET_CELL(p) (p += 4, *((const uint32_t *)(p-4))) -static void print_data(const char *data, int len) +static const char *tagname(uint32_t tag) { - int i; - const char *p = data; - - /* no data, don't print */ - if (len == 0) - return; - - if (util_is_printable_string(data, len)) { - printf(" = \"%s\"", (const char *)data); - } else if ((len % 4) == 0) { - printf(" = <"); - for (i = 0; i < len; i += 4) - printf("0x%08x%s", fdt32_to_cpu(GET_CELL(p)), - i < (len - 4) ? " " : ""); - printf(">"); - } else { - printf(" = ["); - for (i = 0; i < len; i++) - printf("%02x%s", *p++, i < len - 1 ? " " : ""); - printf("]"); - } + static const char * const names[] = { +#define TN(t) [t] #t + TN(FDT_BEGIN_NODE), + TN(FDT_END_NODE), + TN(FDT_PROP), + TN(FDT_NOP), + TN(FDT_END), +#undef TN + }; + if (tag < ARRAY_SIZE(names)) + if (names[tag]) + return names[tag]; + return "FDT_???"; } -static void dump_blob(void *blob) +#define dumpf(fmt, args...) \ + do { if (debug) printf("// " fmt, ## args); } while (0) + +static void dump_blob(void *blob, bool debug) { + uintptr_t blob_off = (uintptr_t)blob; struct fdt_header *bph = blob; uint32_t off_mem_rsvmap = fdt32_to_cpu(bph->off_mem_rsvmap); uint32_t off_dt = fdt32_to_cpu(bph->off_dt_struct); @@ -97,7 +95,8 @@ static void dump_blob(void *blob) p = p_struct; while ((tag = fdt32_to_cpu(GET_CELL(p))) != FDT_END) { - /* printf("tag: 0x%08x (%d)\n", tag, p - p_struct); */ + dumpf("%04zx: tag: 0x%08x (%s)\n", + (uintptr_t)p - blob_off - 4, tag, tagname(tag)); if (tag == FDT_BEGIN_NODE) { s = p; @@ -136,27 +135,93 @@ static void dump_blob(void *blob) p = PALIGN(p + sz, 4); + dumpf("%04zx: string: %s\n", (uintptr_t)s - blob_off, s); + dumpf("%04zx: value\n", (uintptr_t)t - blob_off); printf("%*s%s", depth * shift, "", s); - print_data(t, sz); + utilfdt_print_data(t, sz); printf(";\n"); } } +/* Usage related data. */ +static const char usage_synopsis[] = "fdtdump [options] "; +static const char usage_short_opts[] = "ds" USAGE_COMMON_SHORT_OPTS; +static struct option const usage_long_opts[] = { + {"debug", no_argument, NULL, 'd'}, + {"scan", no_argument, NULL, 's'}, + USAGE_COMMON_LONG_OPTS +}; +static const char * const usage_opts_help[] = { + "Dump debug information while decoding the file", + "Scan for an embedded fdt in file", + USAGE_COMMON_OPTS_HELP +}; int main(int argc, char *argv[]) { + int opt; + const char *file; char *buf; + bool debug = false; + bool scan = false; + off_t len; + + while ((opt = util_getopt_long()) != EOF) { + switch (opt) { + case_USAGE_COMMON_FLAGS - if (argc < 2) { - fprintf(stderr, "supply input filename\n"); - return 5; + case 'd': + debug = true; + break; + case 's': + scan = true; + break; + } + } + if (optind != argc - 1) + usage("missing input filename"); + file = argv[optind]; + + buf = utilfdt_read_len(file, &len); + if (!buf) + die("could not read: %s\n", file); + + /* try and locate an embedded fdt in a bigger blob */ + if (scan) { + unsigned char smagic[4]; + char *p = buf; + char *endp = buf + len; + + fdt_set_magic(smagic, FDT_MAGIC); + + /* poor man's memmem */ + while (true) { + p = memchr(p, smagic[0], endp - p - 4); + if (!p) + break; + if (fdt_magic(p) == FDT_MAGIC) { + /* try and validate the main struct */ + off_t this_len = endp - p; + fdt32_t max_version = 17; + if (fdt_version(p) <= max_version && + fdt_last_comp_version(p) < max_version && + fdt_totalsize(p) < this_len && + fdt_off_dt_struct(p) < this_len && + fdt_off_dt_strings(p) < this_len) + break; + if (debug) + printf("%s: skipping fdt magic at offset %#zx\n", + file, p - buf); + } + ++p; + } + if (!p) + die("%s: could not locate fdt magic\n", file); + printf("%s: found fdt at offset %#zx\n", file, p - buf); + buf = p; } - buf = utilfdt_read(argv[1]); - if (buf) - dump_blob(buf); - else - return 10; + dump_blob(buf, debug); return 0; } diff --git a/fdtget.c b/fdtget.c index c2fbab2a547..43774192241 100644 --- a/fdtget.c +++ b/fdtget.c @@ -277,33 +277,33 @@ static int do_fdtget(struct display_info *disp, const char *filename, return 0; } -static const char *usage_msg = - "fdtget - read values from device tree\n" - "\n" - "Each value is printed on a new line.\n\n" - "Usage:\n" +/* Usage related data. */ +static const char usage_synopsis[] = + "read values from device tree\n" " fdtget
[ ]...\n" " fdtget -p
[ ]...\n" - "Options:\n" - "\t-t \tType of data\n" - "\t-p\t\tList properties for each node\n" - "\t-l\t\tList subnodes for each node\n" - "\t-d\t\tDefault value to display when the property is " - "missing\n" - "\t-h\t\tPrint this help\n\n" + "\n" + "Each value is printed on a new line.\n" USAGE_TYPE_MSG; - -static void usage(const char *msg) -{ - if (msg) - fprintf(stderr, "Error: %s\n\n", msg); - - fprintf(stderr, "%s", usage_msg); - exit(2); -} +static const char usage_short_opts[] = "t:pld:" USAGE_COMMON_SHORT_OPTS; +static struct option const usage_long_opts[] = { + {"type", a_argument, NULL, 't'}, + {"properties", no_argument, NULL, 'p'}, + {"list", no_argument, NULL, 'l'}, + {"default", a_argument, NULL, 'd'}, + USAGE_COMMON_LONG_OPTS, +}; +static const char * const usage_opts_help[] = { + "Type of data", + "List properties for each node", + "List subnodes for each node", + "Default value to display when the property is missing", + USAGE_COMMON_OPTS_HELP +}; int main(int argc, char *argv[]) { + int opt; char *filename = NULL; struct display_info disp; int args_per_step = 2; @@ -312,20 +312,14 @@ int main(int argc, char *argv[]) memset(&disp, '\0', sizeof(disp)); disp.size = -1; disp.mode = MODE_SHOW_VALUE; - for (;;) { - int c = getopt(argc, argv, "d:hlpt:"); - if (c == -1) - break; - - switch (c) { - case 'h': - case '?': - usage(NULL); + while ((opt = util_getopt_long()) != EOF) { + switch (opt) { + case_USAGE_COMMON_FLAGS case 't': if (utilfdt_decode_type(optarg, &disp.type, &disp.size)) - usage("Invalid type string"); + usage("invalid type string"); break; case 'p': @@ -347,7 +341,7 @@ int main(int argc, char *argv[]) if (optind < argc) filename = argv[optind++]; if (!filename) - usage("Missing filename"); + usage("missing filename"); argv += optind; argc -= optind; @@ -358,7 +352,7 @@ int main(int argc, char *argv[]) /* Check for node, property arguments */ if (args_per_step == 2 && (argc % 2)) - usage("Must have an even number of arguments"); + usage("must have an even number of arguments"); if (do_fdtget(&disp, filename, argv, argc, args_per_step)) return 1; diff --git a/fdtput.c b/fdtput.c index f2197f51930..5226a4efd54 100644 --- a/fdtput.c +++ b/fdtput.c @@ -131,19 +131,59 @@ static int encode_value(struct display_info *disp, char **arg, int arg_count, return 0; } -static int store_key_value(void *blob, const char *node_name, +#define ALIGN(x) (((x) + (FDT_TAGSIZE) - 1) & ~((FDT_TAGSIZE) - 1)) + +static char *_realloc_fdt(char *fdt, int delta) +{ + int new_sz = fdt_totalsize(fdt) + delta; + fdt = xrealloc(fdt, new_sz); + fdt_open_into(fdt, fdt, new_sz); + return fdt; +} + +static char *realloc_node(char *fdt, const char *name) +{ + int delta; + /* FDT_BEGIN_NODE, node name in off_struct and FDT_END_NODE */ + delta = sizeof(struct fdt_node_header) + ALIGN(strlen(name) + 1) + + FDT_TAGSIZE; + return _realloc_fdt(fdt, delta); +} + +static char *realloc_property(char *fdt, int nodeoffset, + const char *name, int newlen) +{ + int delta = 0; + int oldlen = 0; + + if (!fdt_get_property(fdt, nodeoffset, name, &oldlen)) + /* strings + property header */ + delta = sizeof(struct fdt_property) + strlen(name) + 1; + + if (newlen > oldlen) + /* actual value in off_struct */ + delta += ALIGN(newlen) - ALIGN(oldlen); + + return _realloc_fdt(fdt, delta); +} + +static int store_key_value(char **blob, const char *node_name, const char *property, const char *buf, int len) { int node; int err; - node = fdt_path_offset(blob, node_name); + node = fdt_path_offset(*blob, node_name); if (node < 0) { report_error(node_name, -1, node); return -1; } - err = fdt_setprop(blob, node, property, buf, len); + err = fdt_setprop(*blob, node, property, buf, len); + if (err == -FDT_ERR_NOSPACE) { + *blob = realloc_property(*blob, node, property, len); + err = fdt_setprop(*blob, node, property, buf, len); + } if (err) { report_error(property, -1, err); return -1; @@ -161,7 +201,7 @@ static int store_key_value(void *blob, const char *node_name, * @param in_path Path to process * @return 0 if ok, -1 on error */ -static int create_paths(void *blob, const char *in_path) +static int create_paths(char **blob, const char *in_path) { const char *path = in_path; const char *sep; @@ -177,10 +217,11 @@ static int create_paths(void *blob, const char *in_path) if (!sep) sep = path + strlen(path); - node = fdt_subnode_offset_namelen(blob, offset, path, + node = fdt_subnode_offset_namelen(*blob, offset, path, sep - path); if (node == -FDT_ERR_NOTFOUND) { - node = fdt_add_subnode_namelen(blob, offset, path, + *blob = realloc_node(*blob, path); + node = fdt_add_subnode_namelen(*blob, offset, path, sep - path); } if (node < 0) { @@ -203,7 +244,7 @@ static int create_paths(void *blob, const char *in_path) * @param node_name Name of node to create * @return new node offset if found, or -1 on failure */ -static int create_node(void *blob, const char *node_name) +static int create_node(char **blob, const char *node_name) { int node = 0; char *p; @@ -215,15 +256,17 @@ static int create_node(void *blob, const char *node_name) } *p = '\0'; + *blob = realloc_node(*blob, p + 1); + if (p > node_name) { - node = fdt_path_offset(blob, node_name); + node = fdt_path_offset(*blob, node_name); if (node < 0) { report_error(node_name, -1, node); return -1; } } - node = fdt_add_subnode(blob, node, p + 1); + node = fdt_add_subnode(*blob, node, p + 1); if (node < 0) { report_error(p + 1, -1, node); return -1; @@ -250,66 +293,64 @@ static int do_fdtput(struct display_info *disp, const char *filename, * store them into the property. */ assert(arg_count >= 2); - if (disp->auto_path && create_paths(blob, *arg)) + if (disp->auto_path && create_paths(&blob, *arg)) return -1; if (encode_value(disp, arg + 2, arg_count - 2, &value, &len) || - store_key_value(blob, *arg, arg[1], value, len)) + store_key_value(&blob, *arg, arg[1], value, len)) ret = -1; break; case OPER_CREATE_NODE: for (; ret >= 0 && arg_count--; arg++) { if (disp->auto_path) - ret = create_paths(blob, *arg); + ret = create_paths(&blob, *arg); else - ret = create_node(blob, *arg); + ret = create_node(&blob, *arg); } break; } - if (ret >= 0) + if (ret >= 0) { + fdt_pack(blob); ret = utilfdt_write(filename, blob); + } free(blob); return ret; } -static const char *usage_msg = - "fdtput - write a property value to a device tree\n" - "\n" - "The command line arguments are joined together into a single value.\n" - "\n" - "Usage:\n" +/* Usage related data. */ +static const char usage_synopsis[] = + "write a property value to a device tree\n" " fdtput
[...]\n" " fdtput -c
[...]\n" - "Options:\n" - "\t-c\t\tCreate nodes if they don't already exist\n" - "\t-p\t\tAutomatically create nodes as needed for the node path\n" - "\t-t \tType of data\n" - "\t-v\t\tVerbose: display each value decoded from command line\n" - "\t-h\t\tPrint this help\n\n" + "\n" + "The command line arguments are joined together into a single value.\n" USAGE_TYPE_MSG; - -static void usage(const char *msg) -{ - if (msg) - fprintf(stderr, "Error: %s\n\n", msg); - - fprintf(stderr, "%s", usage_msg); - exit(2); -} +static const char usage_short_opts[] = "cpt:v" USAGE_COMMON_SHORT_OPTS; +static struct option const usage_long_opts[] = { + {"create", no_argument, NULL, 'c'}, + {"auto-path", no_argument, NULL, 'p'}, + {"type", a_argument, NULL, 't'}, + {"verbose", no_argument, NULL, 'v'}, + USAGE_COMMON_LONG_OPTS, +}; +static const char * const usage_opts_help[] = { + "Create nodes if they don't already exist", + "Automatically create nodes as needed for the node path", + "Type of data", + "Display each value decoded from command line", + USAGE_COMMON_OPTS_HELP +}; int main(int argc, char *argv[]) { + int opt; struct display_info disp; char *filename = NULL; memset(&disp, '\0', sizeof(disp)); disp.size = -1; disp.oper = OPER_WRITE_PROP; - for (;;) { - int c = getopt(argc, argv, "chpt:v"); - if (c == -1) - break; - + while ((opt = util_getopt_long()) != EOF) { /* * TODO: add options to: * - delete property @@ -317,15 +358,13 @@ int main(int argc, char *argv[]) * - rename node * - pack fdt before writing * - set amount of free space when writing - * - expand fdt if value doesn't fit */ - switch (c) { + switch (opt) { + case_USAGE_COMMON_FLAGS + case 'c': disp.oper = OPER_CREATE_NODE; break; - case 'h': - case '?': - usage(NULL); case 'p': disp.auto_path = 1; break; @@ -344,16 +383,16 @@ int main(int argc, char *argv[]) if (optind < argc) filename = argv[optind++]; if (!filename) - usage("Missing filename"); + usage("missing filename"); argv += optind; argc -= optind; if (disp.oper == OPER_WRITE_PROP) { if (argc < 1) - usage("Missing node"); + usage("missing node"); if (argc < 2) - usage("Missing property"); + usage("missing property"); } if (do_fdtput(&disp, filename, argv, argc)) diff --git a/flattree.c b/flattree.c index 28d0b2381df..bd99fa2d33b 100644 --- a/flattree.c +++ b/flattree.c @@ -261,7 +261,10 @@ static void flatten_tree(struct node *tree, struct emitter *emit, { struct property *prop; struct node *child; - int seen_name_prop = 0; + bool seen_name_prop = false; + + if (tree->deleted) + return; emit->beginnode(etarget, tree->labels); @@ -276,7 +279,7 @@ static void flatten_tree(struct node *tree, struct emitter *emit, int nameoff; if (streq(prop->name, "name")) - seen_name_prop = 1; + seen_name_prop = true; nameoff = stringtable_insert(strbuf, prop->name); diff --git a/libfdt/Makefile.libfdt b/libfdt/Makefile.libfdt index 4366627a552..91126c000a1 100644 --- a/libfdt/Makefile.libfdt +++ b/libfdt/Makefile.libfdt @@ -4,7 +4,7 @@ # be easily embeddable into other systems of Makefiles. # LIBFDT_soname = libfdt.$(SHAREDLIB_EXT).1 -LIBFDT_INCLUDES = fdt.h libfdt.h +LIBFDT_INCLUDES = fdt.h libfdt.h libfdt_env.h LIBFDT_VERSION = version.lds LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c fdt_empty_tree.c LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o) diff --git a/libfdt/fdt.c b/libfdt/fdt.c index e56833ae9b6..2ce6a44179d 100644 --- a/libfdt/fdt.c +++ b/libfdt/fdt.c @@ -92,7 +92,7 @@ const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len) uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) { - const uint32_t *tagp, *lenp; + const fdt32_t *tagp, *lenp; uint32_t tag; int offset = startoffset; const char *p; @@ -198,6 +198,34 @@ int fdt_next_node(const void *fdt, int offset, int *depth) return offset; } +int fdt_first_subnode(const void *fdt, int offset) +{ + int depth = 0; + + offset = fdt_next_node(fdt, offset, &depth); + if (offset < 0 || depth != 1) + return -FDT_ERR_NOTFOUND; + + return offset; +} + +int fdt_next_subnode(const void *fdt, int offset) +{ + int depth = 1; + + /* + * With respect to the parent, the depth of the next subnode will be + * the same as the last. + */ + do { + offset = fdt_next_node(fdt, offset, &depth); + if (offset < 0 || depth < 1) + return -FDT_ERR_NOTFOUND; + } while (depth > 1); + + return offset; +} + const char *_fdt_find_string(const char *strtab, int tabsize, const char *s) { int len = strlen(s) + 1; diff --git a/libfdt/fdt.h b/libfdt/fdt.h index 48ccfd91000..526aedb5155 100644 --- a/libfdt/fdt.h +++ b/libfdt/fdt.h @@ -1,48 +1,99 @@ #ifndef _FDT_H #define _FDT_H +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * Copyright 2012 Kim Phillips, Freescale Semiconductor. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ #ifndef __ASSEMBLY__ struct fdt_header { - uint32_t magic; /* magic word FDT_MAGIC */ - uint32_t totalsize; /* total size of DT block */ - uint32_t off_dt_struct; /* offset to structure */ - uint32_t off_dt_strings; /* offset to strings */ - uint32_t off_mem_rsvmap; /* offset to memory reserve map */ - uint32_t version; /* format version */ - uint32_t last_comp_version; /* last compatible version */ + fdt32_t magic; /* magic word FDT_MAGIC */ + fdt32_t totalsize; /* total size of DT block */ + fdt32_t off_dt_struct; /* offset to structure */ + fdt32_t off_dt_strings; /* offset to strings */ + fdt32_t off_mem_rsvmap; /* offset to memory reserve map */ + fdt32_t version; /* format version */ + fdt32_t last_comp_version; /* last compatible version */ /* version 2 fields below */ - uint32_t boot_cpuid_phys; /* Which physical CPU id we're + fdt32_t boot_cpuid_phys; /* Which physical CPU id we're booting on */ /* version 3 fields below */ - uint32_t size_dt_strings; /* size of the strings block */ + fdt32_t size_dt_strings; /* size of the strings block */ /* version 17 fields below */ - uint32_t size_dt_struct; /* size of the structure block */ + fdt32_t size_dt_struct; /* size of the structure block */ }; struct fdt_reserve_entry { - uint64_t address; - uint64_t size; + fdt64_t address; + fdt64_t size; }; struct fdt_node_header { - uint32_t tag; + fdt32_t tag; char name[0]; }; struct fdt_property { - uint32_t tag; - uint32_t len; - uint32_t nameoff; + fdt32_t tag; + fdt32_t len; + fdt32_t nameoff; char data[0]; }; #endif /* !__ASSEMBLY */ #define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */ -#define FDT_TAGSIZE sizeof(uint32_t) +#define FDT_TAGSIZE sizeof(fdt32_t) #define FDT_BEGIN_NODE 0x1 /* Start node: full name */ #define FDT_END_NODE 0x2 /* End node */ @@ -51,10 +102,10 @@ struct fdt_property { #define FDT_NOP 0x4 /* nop */ #define FDT_END 0x9 -#define FDT_V1_SIZE (7*sizeof(uint32_t)) -#define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(uint32_t)) -#define FDT_V3_SIZE (FDT_V2_SIZE + sizeof(uint32_t)) +#define FDT_V1_SIZE (7*sizeof(fdt32_t)) +#define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(fdt32_t)) +#define FDT_V3_SIZE (FDT_V2_SIZE + sizeof(fdt32_t)) #define FDT_V16_SIZE FDT_V3_SIZE -#define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(uint32_t)) +#define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(fdt32_t)) #endif /* _FDT_H */ diff --git a/libfdt/fdt_ro.c b/libfdt/fdt_ro.c index 02b6d687537..50007f61ce6 100644 --- a/libfdt/fdt_ro.c +++ b/libfdt/fdt_ro.c @@ -322,7 +322,7 @@ const void *fdt_getprop(const void *fdt, int nodeoffset, uint32_t fdt_get_phandle(const void *fdt, int nodeoffset) { - const uint32_t *php; + const fdt32_t *php; int len; /* FIXME: This is a bit sub-optimal, since we potentially scan @@ -515,8 +515,7 @@ int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle) return offset; /* error from fdt_next_node() */ } -static int _fdt_stringlist_contains(const char *strlist, int listlen, - const char *str) +int fdt_stringlist_contains(const char *strlist, int listlen, const char *str) { int len = strlen(str); const char *p; @@ -542,7 +541,7 @@ int fdt_node_check_compatible(const void *fdt, int nodeoffset, prop = fdt_getprop(fdt, nodeoffset, "compatible", &len); if (!prop) return len; - if (_fdt_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 24437dfc32b..fdba618f12a 100644 --- a/libfdt/fdt_rw.c +++ b/libfdt/fdt_rw.c @@ -339,7 +339,7 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset, int nodelen; int err; uint32_t tag; - uint32_t *endtag; + fdt32_t *endtag; FDT_RW_CHECK_HEADER(fdt); @@ -366,7 +366,7 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset, nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); memset(nh->name, 0, FDT_TAGALIGN(namelen+1)); memcpy(nh->name, name, namelen); - endtag = (uint32_t *)((char *)nh + nodelen - FDT_TAGSIZE); + endtag = (fdt32_t *)((char *)nh + nodelen - FDT_TAGSIZE); *endtag = cpu_to_fdt32(FDT_END_NODE); return offset; diff --git a/libfdt/fdt_sw.c b/libfdt/fdt_sw.c index 55ebebf1eb2..6a804859fd0 100644 --- a/libfdt/fdt_sw.c +++ b/libfdt/fdt_sw.c @@ -107,6 +107,38 @@ int fdt_create(void *buf, int bufsize) return 0; } +int fdt_resize(void *fdt, void *buf, int bufsize) +{ + size_t headsize, tailsize; + char *oldtail, *newtail; + + FDT_SW_CHECK_HEADER(fdt); + + headsize = fdt_off_dt_struct(fdt); + tailsize = fdt_size_dt_strings(fdt); + + if ((headsize + tailsize) > bufsize) + return -FDT_ERR_NOSPACE; + + oldtail = (char *)fdt + fdt_totalsize(fdt) - tailsize; + newtail = (char *)buf + bufsize - tailsize; + + /* Two cases to avoid clobbering data if the old and new + * buffers partially overlap */ + if (buf <= fdt) { + memmove(buf, fdt, headsize); + memmove(newtail, oldtail, tailsize); + } else { + memmove(newtail, oldtail, tailsize); + memmove(buf, fdt, headsize); + } + + fdt_set_off_dt_strings(buf, bufsize); + fdt_set_totalsize(buf, bufsize); + + return 0; +} + int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size) { struct fdt_reserve_entry *re; @@ -153,7 +185,7 @@ int fdt_begin_node(void *fdt, const char *name) int fdt_end_node(void *fdt) { - uint32_t *en; + fdt32_t *en; FDT_SW_CHECK_HEADER(fdt); @@ -213,7 +245,7 @@ int fdt_property(void *fdt, const char *name, const void *val, int len) int fdt_finish(void *fdt) { char *p = (char *)fdt; - uint32_t *end; + fdt32_t *end; int oldstroffset, newstroffset; uint32_t tag; int offset, nextoffset; diff --git a/libfdt/fdt_wip.c b/libfdt/fdt_wip.c index 6025fa1fe8f..c5bbb68d327 100644 --- a/libfdt/fdt_wip.c +++ b/libfdt/fdt_wip.c @@ -74,7 +74,7 @@ int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, static void _fdt_nop_region(void *start, int len) { - uint32_t *p; + fdt32_t *p; for (p = start; (char *)p < ((char *)start + len); p++) *p = cpu_to_fdt32(FDT_NOP); diff --git a/libfdt/libfdt.h b/libfdt/libfdt.h index 73f49759a5e..c4d5a9134bf 100644 --- a/libfdt/libfdt.h +++ b/libfdt/libfdt.h @@ -136,6 +136,28 @@ uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset); int fdt_next_node(const void *fdt, int offset, int *depth); +/** + * fdt_first_subnode() - get offset of first direct subnode + * + * @fdt: FDT blob + * @offset: Offset of node to check + * @return offset of first subnode, or -FDT_ERR_NOTFOUND if there is none + */ +int fdt_first_subnode(const void *fdt, int offset); + +/** + * fdt_next_subnode() - get offset of next direct subnode + * + * After first calling fdt_first_subnode(), call this function repeatedly to + * get direct subnodes of a parent node. + * + * @fdt: FDT blob + * @offset: Offset of previous subnode + * @return offset of next subnode, or -FDT_ERR_NOTFOUND if there are no more + * subnodes + */ +int fdt_next_subnode(const void *fdt, int offset); + /**********************************************************************/ /* General functions */ /**********************************************************************/ @@ -582,7 +604,7 @@ const char *fdt_get_alias_namelen(const void *fdt, * value of the property named 'name' in the node /aliases. * * returns: - * a pointer to the expansion of the alias named 'name', of it exists + * a pointer to the expansion of the alias named 'name', if 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); @@ -816,6 +838,20 @@ int fdt_node_check_compatible(const void *fdt, int nodeoffset, int fdt_node_offset_by_compatible(const void *fdt, int startoffset, const char *compatible); +/** + * fdt_stringlist_contains - check a string list property for a string + * @strlist: Property containing a list of strings to check + * @listlen: Length of property + * @str: String to search for + * + * This is a utility function provided for convenience. The list contains + * one or more strings, each terminated by \0, as is found in a device tree + * "compatible" property. + * + * @return: 1 if the string is found in the list, 0 not found, or invalid list + */ +int fdt_stringlist_contains(const char *strlist, int listlen, const char *str); + /**********************************************************************/ /* Write-in-place functions */ /**********************************************************************/ @@ -882,8 +918,8 @@ int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, static inline int fdt_setprop_inplace_u32(void *fdt, int nodeoffset, const char *name, uint32_t val) { - val = cpu_to_fdt32(val); - return fdt_setprop_inplace(fdt, nodeoffset, name, &val, sizeof(val)); + fdt32_t tmp = cpu_to_fdt32(val); + return fdt_setprop_inplace(fdt, nodeoffset, name, &tmp, sizeof(tmp)); } /** @@ -917,8 +953,8 @@ static inline int fdt_setprop_inplace_u32(void *fdt, int nodeoffset, static inline int fdt_setprop_inplace_u64(void *fdt, int nodeoffset, const char *name, uint64_t val) { - val = cpu_to_fdt64(val); - return fdt_setprop_inplace(fdt, nodeoffset, name, &val, sizeof(val)); + fdt64_t tmp = cpu_to_fdt64(val); + return fdt_setprop_inplace(fdt, nodeoffset, name, &tmp, sizeof(tmp)); } /** @@ -987,19 +1023,20 @@ int fdt_nop_node(void *fdt, int nodeoffset); /**********************************************************************/ int fdt_create(void *buf, int bufsize); +int fdt_resize(void *fdt, void *buf, int bufsize); int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size); int fdt_finish_reservemap(void *fdt); int fdt_begin_node(void *fdt, const char *name); int fdt_property(void *fdt, const char *name, const void *val, int len); static inline int fdt_property_u32(void *fdt, const char *name, uint32_t val) { - val = cpu_to_fdt32(val); - return fdt_property(fdt, name, &val, sizeof(val)); + fdt32_t tmp = cpu_to_fdt32(val); + return fdt_property(fdt, name, &tmp, sizeof(tmp)); } static inline int fdt_property_u64(void *fdt, const char *name, uint64_t val) { - val = cpu_to_fdt64(val); - return fdt_property(fdt, name, &val, sizeof(val)); + fdt64_t tmp = cpu_to_fdt64(val); + return fdt_property(fdt, name, &tmp, sizeof(tmp)); } static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val) { @@ -1154,8 +1191,8 @@ int fdt_setprop(void *fdt, int nodeoffset, const char *name, static inline int fdt_setprop_u32(void *fdt, int nodeoffset, const char *name, uint32_t val) { - val = cpu_to_fdt32(val); - return fdt_setprop(fdt, nodeoffset, name, &val, sizeof(val)); + fdt32_t tmp = cpu_to_fdt32(val); + return fdt_setprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); } /** @@ -1189,8 +1226,8 @@ static inline int fdt_setprop_u32(void *fdt, int nodeoffset, const char *name, static inline int fdt_setprop_u64(void *fdt, int nodeoffset, const char *name, uint64_t val) { - val = cpu_to_fdt64(val); - return fdt_setprop(fdt, nodeoffset, name, &val, sizeof(val)); + fdt64_t tmp = cpu_to_fdt64(val); + return fdt_setprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); } /** @@ -1296,8 +1333,8 @@ int fdt_appendprop(void *fdt, int nodeoffset, const char *name, static inline int fdt_appendprop_u32(void *fdt, int nodeoffset, const char *name, uint32_t val) { - val = cpu_to_fdt32(val); - return fdt_appendprop(fdt, nodeoffset, name, &val, sizeof(val)); + fdt32_t tmp = cpu_to_fdt32(val); + return fdt_appendprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); } /** @@ -1331,8 +1368,8 @@ static inline int fdt_appendprop_u32(void *fdt, int nodeoffset, static inline int fdt_appendprop_u64(void *fdt, int nodeoffset, const char *name, uint64_t val) { - val = cpu_to_fdt64(val); - return fdt_appendprop(fdt, nodeoffset, name, &val, sizeof(val)); + fdt64_t tmp = cpu_to_fdt64(val); + return fdt_appendprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); } /** diff --git a/libfdt/libfdt_env.h b/libfdt/libfdt_env.h index 213d7fb81c4..9dea97dfff8 100644 --- a/libfdt/libfdt_env.h +++ b/libfdt/libfdt_env.h @@ -1,29 +1,111 @@ #ifndef _LIBFDT_ENV_H #define _LIBFDT_ENV_H +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * Copyright 2012 Kim Phillips, Freescale Semiconductor. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ #include #include #include -#define EXTRACT_BYTE(n) ((unsigned long long)((uint8_t *)&x)[n]) -static inline uint16_t fdt16_to_cpu(uint16_t x) +#ifdef __CHECKER__ +#define __force __attribute__((force)) +#define __bitwise __attribute__((bitwise)) +#else +#define __force +#define __bitwise +#endif + +typedef uint16_t __bitwise fdt16_t; +typedef uint32_t __bitwise fdt32_t; +typedef uint64_t __bitwise fdt64_t; + +#define EXTRACT_BYTE(x, n) ((unsigned long long)((uint8_t *)&x)[n]) +#define CPU_TO_FDT16(x) ((EXTRACT_BYTE(x, 0) << 8) | EXTRACT_BYTE(x, 1)) +#define CPU_TO_FDT32(x) ((EXTRACT_BYTE(x, 0) << 24) | (EXTRACT_BYTE(x, 1) << 16) | \ + (EXTRACT_BYTE(x, 2) << 8) | EXTRACT_BYTE(x, 3)) +#define CPU_TO_FDT64(x) ((EXTRACT_BYTE(x, 0) << 56) | (EXTRACT_BYTE(x, 1) << 48) | \ + (EXTRACT_BYTE(x, 2) << 40) | (EXTRACT_BYTE(x, 3) << 32) | \ + (EXTRACT_BYTE(x, 4) << 24) | (EXTRACT_BYTE(x, 5) << 16) | \ + (EXTRACT_BYTE(x, 6) << 8) | EXTRACT_BYTE(x, 7)) + +static inline uint16_t fdt16_to_cpu(fdt16_t x) +{ + return (__force uint16_t)CPU_TO_FDT16(x); +} +static inline fdt16_t cpu_to_fdt16(uint16_t x) { - return (EXTRACT_BYTE(0) << 8) | EXTRACT_BYTE(1); + return (__force fdt16_t)CPU_TO_FDT16(x); } -#define cpu_to_fdt16(x) fdt16_to_cpu(x) -static inline uint32_t fdt32_to_cpu(uint32_t x) +static inline uint32_t fdt32_to_cpu(fdt32_t x) { - return (EXTRACT_BYTE(0) << 24) | (EXTRACT_BYTE(1) << 16) | (EXTRACT_BYTE(2) << 8) | EXTRACT_BYTE(3); + return (__force uint32_t)CPU_TO_FDT32(x); +} +static inline fdt32_t cpu_to_fdt32(uint32_t x) +{ + return (__force fdt32_t)CPU_TO_FDT32(x); } -#define cpu_to_fdt32(x) fdt32_to_cpu(x) -static inline uint64_t fdt64_to_cpu(uint64_t x) +static inline uint64_t fdt64_to_cpu(fdt64_t x) +{ + return (__force uint64_t)CPU_TO_FDT64(x); +} +static inline fdt64_t cpu_to_fdt64(uint64_t x) { - return (EXTRACT_BYTE(0) << 56) | (EXTRACT_BYTE(1) << 48) | (EXTRACT_BYTE(2) << 40) | (EXTRACT_BYTE(3) << 32) - | (EXTRACT_BYTE(4) << 24) | (EXTRACT_BYTE(5) << 16) | (EXTRACT_BYTE(6) << 8) | EXTRACT_BYTE(7); + return (__force fdt64_t)CPU_TO_FDT64(x); } -#define cpu_to_fdt64(x) fdt64_to_cpu(x) +#undef CPU_TO_FDT64 +#undef CPU_TO_FDT32 +#undef CPU_TO_FDT16 #undef EXTRACT_BYTE #endif /* _LIBFDT_ENV_H */ diff --git a/libfdt/version.lds b/libfdt/version.lds index 3c3994e27f7..80b322bed6b 100644 --- a/libfdt/version.lds +++ b/libfdt/version.lds @@ -48,6 +48,12 @@ LIBFDT_1.2 { fdt_strerror; fdt_offset_ptr; fdt_next_tag; + fdt_appendprop; + fdt_create_empty_tree; + fdt_first_property_offset; + fdt_get_property_by_offset; + fdt_getprop_by_offset; + fdt_next_property_offset; local: *; diff --git a/livetree.c b/livetree.c index c9209d5c999..b61465fb2f3 100644 --- a/livetree.c +++ b/livetree.c @@ -29,16 +29,27 @@ void add_label(struct label **labels, char *label) struct label *new; /* Make sure the label isn't already there */ - for_each_label(*labels, new) - if (streq(new->label, label)) + for_each_label_withdel(*labels, new) + if (streq(new->label, label)) { + new->deleted = 0; return; + } new = xmalloc(sizeof(*new)); + memset(new, 0, sizeof(*new)); new->label = label; new->next = *labels; *labels = new; } +void delete_labels(struct label **labels) +{ + struct label *label; + + for_each_label(*labels, label) + label->deleted = 1; +} + struct property *build_property(char *name, struct data val) { struct property *new = xmalloc(sizeof(*new)); @@ -51,6 +62,18 @@ struct property *build_property(char *name, struct data val) return new; } +struct property *build_property_delete(char *name) +{ + struct property *new = xmalloc(sizeof(*new)); + + memset(new, 0, sizeof(*new)); + + new->name = name; + new->deleted = 1; + + return new; +} + struct property *chain_property(struct property *first, struct property *list) { assert(first->next == NULL); @@ -91,6 +114,17 @@ struct node *build_node(struct property *proplist, struct node *children) return new; } +struct node *build_node_delete(void) +{ + struct node *new = xmalloc(sizeof(*new)); + + memset(new, 0, sizeof(*new)); + + new->deleted = 1; + + return new; +} + struct node *name_node(struct node *node, char *name) { assert(node->name == NULL); @@ -106,8 +140,10 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node) struct node *new_child, *old_child; struct label *l; + old_node->deleted = 0; + /* Add new node labels to old node */ - for_each_label(new_node->labels, l) + for_each_label_withdel(new_node->labels, l) add_label(&old_node->labels, l->label); /* Move properties from the new node to the old node. If there @@ -118,14 +154,21 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node) new_node->proplist = new_prop->next; new_prop->next = NULL; + if (new_prop->deleted) { + delete_property_by_name(old_node, new_prop->name); + free(new_prop); + continue; + } + /* Look for a collision, set new value if there is */ - for_each_property(old_node, old_prop) { + for_each_property_withdel(old_node, old_prop) { if (streq(old_prop->name, new_prop->name)) { /* Add new labels to old property */ - for_each_label(new_prop->labels, l) + for_each_label_withdel(new_prop->labels, l) add_label(&old_prop->labels, l->label); old_prop->val = new_prop->val; + old_prop->deleted = 0; free(new_prop); new_prop = NULL; break; @@ -146,8 +189,14 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node) new_child->parent = NULL; new_child->next_sibling = NULL; + if (new_child->deleted) { + delete_node_by_name(old_node, new_child->name); + free(new_child); + continue; + } + /* Search for a collision. Merge if there is */ - for_each_child(old_node, old_child) { + for_each_child_withdel(old_node, old_child) { if (streq(old_child->name, new_child->name)) { merge_nodes(old_child, new_child); new_child = NULL; @@ -188,6 +237,25 @@ void add_property(struct node *node, struct property *prop) *p = prop; } +void delete_property_by_name(struct node *node, char *name) +{ + struct property *prop = node->proplist; + + while (prop) { + if (!strcmp(prop->name, name)) { + delete_property(prop); + return; + } + prop = prop->next; + } +} + +void delete_property(struct property *prop) +{ + prop->deleted = 1; + delete_labels(&prop->labels); +} + void add_child(struct node *parent, struct node *child) { struct node **p; @@ -202,6 +270,32 @@ void add_child(struct node *parent, struct node *child) *p = child; } +void delete_node_by_name(struct node *parent, char *name) +{ + struct node *node = parent->children; + + while (node) { + if (!strcmp(node->name, name)) { + delete_node(node); + return; + } + node = node->next_sibling; + } +} + +void delete_node(struct node *node) +{ + struct property *prop; + struct node *child; + + node->deleted = 1; + for_each_child(node, child) + delete_node(child); + for_each_property(node, prop) + delete_property(prop); + delete_labels(&node->labels); +} + struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size) { struct reserve_info *new = xmalloc(sizeof(*new)); @@ -353,8 +447,11 @@ struct node *get_node_by_path(struct node *tree, const char *path) const char *p; struct node *child; - if (!path || ! (*path)) + if (!path || ! (*path)) { + if (tree->deleted) + return NULL; return tree; + } while (path[0] == '/') path++; @@ -397,8 +494,11 @@ struct node *get_node_by_phandle(struct node *tree, cell_t phandle) assert((phandle != 0) && (phandle != -1)); - if (tree->phandle == phandle) + if (tree->phandle == phandle) { + if (tree->deleted) + return NULL; return tree; + } for_each_child(tree, child) { node = get_node_by_phandle(child, phandle); @@ -535,7 +635,7 @@ static void sort_properties(struct node *node) int n = 0, i = 0; struct property *prop, **tbl; - for_each_property(node, prop) + for_each_property_withdel(node, prop) n++; if (n == 0) @@ -543,7 +643,7 @@ static void sort_properties(struct node *node) tbl = xmalloc(n * sizeof(*tbl)); - for_each_property(node, prop) + for_each_property_withdel(node, prop) tbl[i++] = prop; qsort(tbl, n, sizeof(*tbl), cmp_prop); @@ -571,7 +671,7 @@ static void sort_subnodes(struct node *node) int n = 0, i = 0; struct node *subnode, **tbl; - for_each_child(node, subnode) + for_each_child_withdel(node, subnode) n++; if (n == 0) @@ -579,7 +679,7 @@ static void sort_subnodes(struct node *node) tbl = xmalloc(n * sizeof(*tbl)); - for_each_child(node, subnode) + for_each_child_withdel(node, subnode) tbl[i++] = subnode; qsort(tbl, n, sizeof(*tbl), cmp_subnode); @@ -598,7 +698,7 @@ static void sort_node(struct node *node) sort_properties(node); sort_subnodes(node); - for_each_child(node, c) + for_each_child_withdel(node, c) sort_node(c); } diff --git a/srcpos.c b/srcpos.c index 3ee523d29af..399967549a6 100644 --- a/srcpos.c +++ b/srcpos.c @@ -159,7 +159,7 @@ void srcfile_push(const char *fname) current_srcfile = srcfile; } -int srcfile_pop(void) +bool srcfile_pop(void) { struct srcfile_state *srcfile = current_srcfile; @@ -177,7 +177,7 @@ int srcfile_pop(void) * fix this we could either allocate all the files from a * table, or use a pool allocator. */ - return current_srcfile ? 1 : 0; + return current_srcfile ? true : false; } void srcfile_add_search_path(const char *dirname) @@ -290,41 +290,32 @@ srcpos_string(struct srcpos *pos) return pos_str; } -void -srcpos_verror(struct srcpos *pos, char const *fmt, va_list va) +void srcpos_verror(struct srcpos *pos, const char *prefix, + const char *fmt, va_list va) { - const char *srcstr; + char *srcstr; + + srcstr = srcpos_string(pos); - srcstr = srcpos_string(pos); + fprintf(stderr, "%s: %s ", prefix, srcstr); + vfprintf(stderr, fmt, va); + fprintf(stderr, "\n"); - fprintf(stdout, "Error: %s ", srcstr); - vfprintf(stdout, fmt, va); - fprintf(stdout, "\n"); + free(srcstr); } -void -srcpos_error(struct srcpos *pos, char const *fmt, ...) +void srcpos_error(struct srcpos *pos, const char *prefix, + const char *fmt, ...) { va_list va; va_start(va, fmt); - srcpos_verror(pos, fmt, va); + srcpos_verror(pos, prefix, fmt, va); va_end(va); } - -void -srcpos_warn(struct srcpos *pos, char const *fmt, ...) +void srcpos_set_line(char *f, int l) { - const char *srcstr; - va_list va; - va_start(va, fmt); - - srcstr = srcpos_string(pos); - - fprintf(stderr, "Warning: %s ", srcstr); - vfprintf(stderr, fmt, va); - fprintf(stderr, "\n"); - - va_end(va); + current_srcfile->name = f; + current_srcfile->lineno = l; } diff --git a/srcpos.h b/srcpos.h index 5617916dcfc..f81827bd684 100644 --- a/srcpos.h +++ b/srcpos.h @@ -21,6 +21,7 @@ #define _SRCPOS_H_ #include +#include struct srcfile_state { FILE *f; @@ -55,7 +56,7 @@ extern struct srcfile_state *current_srcfile; /* = NULL */ FILE *srcfile_relative_open(const char *fname, char **fullnamep); void srcfile_push(const char *fname); -int srcfile_pop(void); +bool srcfile_pop(void); /** * Add a new directory to the search path for input files @@ -106,11 +107,13 @@ extern struct srcpos *srcpos_copy(struct srcpos *pos); extern char *srcpos_string(struct srcpos *pos); extern void srcpos_dump(struct srcpos *pos); -extern void srcpos_verror(struct srcpos *pos, char const *, va_list va) - __attribute__((format(printf, 2, 0))); -extern void srcpos_error(struct srcpos *pos, char const *, ...) - __attribute__((format(printf, 2, 3))); -extern void srcpos_warn(struct srcpos *pos, char const *, ...) - __attribute__((format(printf, 2, 3))); +extern void srcpos_verror(struct srcpos *pos, const char *prefix, + const char *fmt, va_list va) + __attribute__((format(printf, 3, 0))); +extern void srcpos_error(struct srcpos *pos, const char *prefix, + const char *fmt, ...) + __attribute__((format(printf, 3, 4))); + +extern void srcpos_set_line(char *f, int l); #endif /* _SRCPOS_H_ */ diff --git a/tests/Makefile.tests b/tests/Makefile.tests index 17954668361..dafb6184874 100644 --- a/tests/Makefile.tests +++ b/tests/Makefile.tests @@ -12,7 +12,7 @@ LIB_TESTS_L = get_mem_rsv \ sw_tree1 \ move_and_save mangle-layout nopulate \ open_pack rw_tree1 set_name setprop del_property del_node \ - appendprop1 appendprop2 \ + appendprop1 appendprop2 propname_escapes \ string_escapes references path-references phandle_format \ boot-cpuid incbin \ extra-terminating-null \ @@ -20,7 +20,8 @@ LIB_TESTS_L = get_mem_rsv \ dtb_reverse dtbs_equal_unordered \ add_subnode_with_nops path_offset_aliases \ utilfdt_test \ - integer-expressions + integer-expressions \ + subnode_iterate LIB_TESTS = $(LIB_TESTS_L:%=$(TESTS_PREFIX)%) LIBTREE_TESTS_L = truncated_property diff --git a/tests/add_subnode_with_nops.c b/tests/add_subnode_with_nops.c index 4fb8f024552..95ddf6a5928 100644 --- a/tests/add_subnode_with_nops.c +++ b/tests/add_subnode_with_nops.c @@ -24,7 +24,6 @@ #include #include -#include #include #include "tests.h" diff --git a/tests/aliases.dts b/tests/aliases.dts index 39d88ffc859..853479aee76 100644 --- a/tests/aliases.dts +++ b/tests/aliases.dts @@ -1,6 +1,9 @@ /dts-v1/; / { + #address-cells = <1>; + #size-cells = <0>; + aliases { s1 = &sub1; ss1 = &subsub1; @@ -9,6 +12,7 @@ sub1: subnode@1 { compatible = "subnode1"; + reg = <1>; subsub1: subsubnode { compatible = "subsubnode1", "subsubnode"; diff --git a/tests/appendprop1.c b/tests/appendprop1.c index d716f7afde6..9d6b3add9d4 100644 --- a/tests/appendprop1.c +++ b/tests/appendprop1.c @@ -24,7 +24,6 @@ #include #include -#include #include #include "tests.h" diff --git a/tests/appendprop2.c b/tests/appendprop2.c index 7eb243dfa36..ca1446c513b 100644 --- a/tests/appendprop2.c +++ b/tests/appendprop2.c @@ -24,7 +24,6 @@ #include #include -#include #include #include "tests.h" diff --git a/tests/asm_tree_dump.c b/tests/asm_tree_dump.c index 5ff50872c8e..bd12edaa880 100644 --- a/tests/asm_tree_dump.c +++ b/tests/asm_tree_dump.c @@ -26,7 +26,6 @@ #include -#include #include #include "tests.h" diff --git a/tests/boot-cpuid.c b/tests/boot-cpuid.c index 7b5433dbacb..ca39f4b6929 100644 --- a/tests/boot-cpuid.c +++ b/tests/boot-cpuid.c @@ -21,7 +21,6 @@ #include #include -#include #include #include "tests.h" diff --git a/tests/char_literal.c b/tests/char_literal.c index 150f2a0c148..d7a4773419a 100644 --- a/tests/char_literal.c +++ b/tests/char_literal.c @@ -23,7 +23,6 @@ #include #include -#include #include #include "tests.h" diff --git a/tests/del_node.c b/tests/del_node.c index afad5027b79..45cb06016dc 100644 --- a/tests/del_node.c +++ b/tests/del_node.c @@ -24,7 +24,6 @@ #include #include -#include #include #include "tests.h" diff --git a/tests/del_property.c b/tests/del_property.c index 449eca6150c..42fd7cb1c15 100644 --- a/tests/del_property.c +++ b/tests/del_property.c @@ -24,7 +24,6 @@ #include #include -#include #include #include "tests.h" diff --git a/tests/dtb_reverse.c b/tests/dtb_reverse.c index 25e1eef8177..527fd71336d 100644 --- a/tests/dtb_reverse.c +++ b/tests/dtb_reverse.c @@ -24,7 +24,6 @@ #include #include -#include #include #include "tests.h" diff --git a/tests/dtbs_equal_ordered.c b/tests/dtbs_equal_ordered.c index 1db25f45265..12495dea483 100644 --- a/tests/dtbs_equal_ordered.c +++ b/tests/dtbs_equal_ordered.c @@ -23,7 +23,6 @@ #include #include -#include #include #include "tests.h" diff --git a/tests/dtbs_equal_unordered.c b/tests/dtbs_equal_unordered.c index df5331883b1..20b4356f92f 100644 --- a/tests/dtbs_equal_unordered.c +++ b/tests/dtbs_equal_unordered.c @@ -24,7 +24,6 @@ #include #include -#include #include #include "tests.h" diff --git a/tests/dumptrees.c b/tests/dumptrees.c index fa1f5636841..bebf553c9bf 100644 --- a/tests/dumptrees.c +++ b/tests/dumptrees.c @@ -25,9 +25,7 @@ #include #include -#include #include -#include #include "testdata.h" diff --git a/tests/extra-terminating-null.c b/tests/extra-terminating-null.c index 8a2043f3dd7..dc1fe89ab05 100644 --- a/tests/extra-terminating-null.c +++ b/tests/extra-terminating-null.c @@ -22,7 +22,6 @@ #include #include -#include #include #include "tests.h" diff --git a/tests/fdtget-runtest.sh b/tests/fdtget-runtest.sh index c3a355951df..8d8b0587602 100755 --- a/tests/fdtget-runtest.sh +++ b/tests/fdtget-runtest.sh @@ -8,7 +8,7 @@ rm -f $LOG $EXPECT trap "rm -f $LOG $EXPECT" 0 expect="$1" -/bin/echo -e $expect >$EXPECT +printf '%b\n' "$expect" > $EXPECT shift verbose_run_log_check "$LOG" $VALGRIND $DTGET "$@" diff --git a/tests/find_property.c b/tests/find_property.c index 74a696587c3..4dc3030e37e 100644 --- a/tests/find_property.c +++ b/tests/find_property.c @@ -22,7 +22,6 @@ #include #include -#include #include #include "tests.h" diff --git a/tests/get_alias.c b/tests/get_alias.c index 1e0faf474fe..50607957515 100644 --- a/tests/get_alias.c +++ b/tests/get_alias.c @@ -23,7 +23,6 @@ #include #include -#include #include #include "tests.h" diff --git a/tests/get_mem_rsv.c b/tests/get_mem_rsv.c index 554c78868f9..18126393589 100644 --- a/tests/get_mem_rsv.c +++ b/tests/get_mem_rsv.c @@ -23,7 +23,6 @@ #include #include -#include #include #include "tests.h" diff --git a/tests/get_name.c b/tests/get_name.c index 0262a120d1f..c6ca9f9bbf8 100644 --- a/tests/get_name.c +++ b/tests/get_name.c @@ -22,7 +22,6 @@ #include #include -#include #include #include "tests.h" diff --git a/tests/get_path.c b/tests/get_path.c index 1e05f7c2116..73529765937 100644 --- a/tests/get_path.c +++ b/tests/get_path.c @@ -22,7 +22,6 @@ #include #include -#include #include #include "tests.h" diff --git a/tests/get_phandle.c b/tests/get_phandle.c index 5735733fadb..2079591d4c4 100644 --- a/tests/get_phandle.c +++ b/tests/get_phandle.c @@ -22,7 +22,6 @@ #include #include -#include #include #include "tests.h" diff --git a/tests/getprop.c b/tests/getprop.c index 239856e7c95..6255badb3fa 100644 --- a/tests/getprop.c +++ b/tests/getprop.c @@ -23,7 +23,6 @@ #include #include -#include #include #include "tests.h" diff --git a/tests/incbin.c b/tests/incbin.c index 76d86262644..4100ba02997 100644 --- a/tests/incbin.c +++ b/tests/incbin.c @@ -23,7 +23,6 @@ #include #include -#include #include #include "tests.h" diff --git a/tests/include1.dts b/tests/include1.dts index 893aaffe749..0b4b773e654 100644 --- a/tests/include1.dts +++ b/tests/include1.dts @@ -8,12 +8,17 @@ /include/ "include5.dts" = <0xdeadbeef>; prop-int64 /include/ "include5a.dts"; prop-str = /include/ "include6.dts"; + #address-cells = <1>; + #size-cells = <0>; /include/ "include7.dts" subnode@2 { + reg = <2>; linux,phandle = <0x2000>; prop-int = <123456789>; + #address-cells = <1>; + #size-cells = <0>; /include/ "include8.dts" phandle = <0x2001>; diff --git a/tests/include7.dts b/tests/include7.dts index dba5e470559..2f6eb890f1f 100644 --- a/tests/include7.dts +++ b/tests/include7.dts @@ -1,5 +1,6 @@ subnode@1 { compatible = "subnode1"; + reg = <1>; prop-int = [deadbeef]; subsubnode { diff --git a/tests/include8.dts b/tests/include8.dts index ec700643765..7532ef51d7e 100644 --- a/tests/include8.dts +++ b/tests/include8.dts @@ -1 +1,2 @@ -subsubnode@0 { \ No newline at end of file +subsubnode@0 { + reg = <0>; diff --git a/tests/integer-expressions.c b/tests/integer-expressions.c index 5ba1566ab8e..57e2ff670de 100644 --- a/tests/integer-expressions.c +++ b/tests/integer-expressions.c @@ -25,7 +25,6 @@ #include -#include #include #include "tests.h" diff --git a/tests/mangle-layout.c b/tests/mangle-layout.c index 3b19788bd72..a76e51e31b5 100644 --- a/tests/mangle-layout.c +++ b/tests/mangle-layout.c @@ -24,7 +24,6 @@ #include #include -#include #include #include "tests.h" diff --git a/tests/move_and_save.c b/tests/move_and_save.c index 410ccb3be71..393b60ac193 100644 --- a/tests/move_and_save.c +++ b/tests/move_and_save.c @@ -24,7 +24,6 @@ #include #include -#include #include #include "tests.h" diff --git a/tests/node_check_compatible.c b/tests/node_check_compatible.c index 23abbf529d9..4bdf09194c8 100644 --- a/tests/node_check_compatible.c +++ b/tests/node_check_compatible.c @@ -23,7 +23,6 @@ #include #include -#include #include #include "tests.h" diff --git a/tests/node_offset_by_compatible.c b/tests/node_offset_by_compatible.c index 23179300f01..f62b591ce24 100644 --- a/tests/node_offset_by_compatible.c +++ b/tests/node_offset_by_compatible.c @@ -23,7 +23,6 @@ #include #include -#include #include #include "tests.h" diff --git a/tests/node_offset_by_phandle.c b/tests/node_offset_by_phandle.c index a8442f15a6b..becff0fd5a1 100644 --- a/tests/node_offset_by_phandle.c +++ b/tests/node_offset_by_phandle.c @@ -23,7 +23,6 @@ #include #include -#include #include #include "tests.h" diff --git a/tests/node_offset_by_prop_value.c b/tests/node_offset_by_prop_value.c index 0f2a34512ae..9212a4efeff 100644 --- a/tests/node_offset_by_prop_value.c +++ b/tests/node_offset_by_prop_value.c @@ -23,7 +23,6 @@ #include #include -#include #include #include "tests.h" diff --git a/tests/nop_node.c b/tests/nop_node.c index ea3a18f6acb..c316444f6dc 100644 --- a/tests/nop_node.c +++ b/tests/nop_node.c @@ -24,7 +24,6 @@ #include #include -#include #include #include "tests.h" diff --git a/tests/nop_property.c b/tests/nop_property.c index e6ef4d97314..644b0a665e6 100644 --- a/tests/nop_property.c +++ b/tests/nop_property.c @@ -24,7 +24,6 @@ #include #include -#include #include #include "tests.h" diff --git a/tests/nopulate.c b/tests/nopulate.c index 3cbbe2113c7..cd79872bc4a 100644 --- a/tests/nopulate.c +++ b/tests/nopulate.c @@ -24,7 +24,6 @@ #include #include -#include #include #include "tests.h" diff --git a/tests/notfound.c b/tests/notfound.c index 4d55b886ba7..dc623d62467 100644 --- a/tests/notfound.c +++ b/tests/notfound.c @@ -22,7 +22,6 @@ #include #include -#include #include #include "tests.h" diff --git a/tests/open_pack.c b/tests/open_pack.c index 0a5a3fcc839..407ef6c542a 100644 --- a/tests/open_pack.c +++ b/tests/open_pack.c @@ -24,7 +24,6 @@ #include #include -#include #include #include "tests.h" diff --git a/tests/parent_offset.c b/tests/parent_offset.c index e7affcc39af..d4ab3cff305 100644 --- a/tests/parent_offset.c +++ b/tests/parent_offset.c @@ -22,7 +22,6 @@ #include #include -#include #include #include "tests.h" diff --git a/tests/path-references.c b/tests/path-references.c index 9f363b3af3c..0746b3f7e32 100644 --- a/tests/path-references.c +++ b/tests/path-references.c @@ -22,7 +22,6 @@ #include #include -#include #include #include "tests.h" diff --git a/tests/path_offset.c b/tests/path_offset.c index d3e1f8ebbac..4e5b7a11f70 100644 --- a/tests/path_offset.c +++ b/tests/path_offset.c @@ -22,7 +22,6 @@ #include #include -#include #include #include "tests.h" diff --git a/tests/path_offset_aliases.c b/tests/path_offset_aliases.c index 3682da489a8..78d5a46967c 100644 --- a/tests/path_offset_aliases.c +++ b/tests/path_offset_aliases.c @@ -23,7 +23,6 @@ #include #include -#include #include #include "tests.h" diff --git a/tests/phandle_format.c b/tests/phandle_format.c index 7e4d81630e0..5874ae79291 100644 --- a/tests/phandle_format.c +++ b/tests/phandle_format.c @@ -22,7 +22,6 @@ #include #include -#include #include #include "tests.h" diff --git a/tests/references.c b/tests/references.c index b20f21fdeca..c9d05a2f296 100644 --- a/tests/references.c +++ b/tests/references.c @@ -22,7 +22,6 @@ #include #include -#include #include #include "tests.h" diff --git a/tests/root_node.c b/tests/root_node.c index 3f478299f9c..58aebf6b48c 100644 --- a/tests/root_node.c +++ b/tests/root_node.c @@ -23,7 +23,6 @@ #include #include -#include #include #include "tests.h" diff --git a/tests/run_tests.sh b/tests/run_tests.sh index f5eebd6ffcf..97e016b1aef 100755 --- a/tests/run_tests.sh +++ b/tests/run_tests.sh @@ -7,6 +7,7 @@ if [ -z "$CC" ]; then fi export QUIET_TEST=1 +STOP_ON_FAIL=0 export VALGRIND= VGCODE=126 @@ -24,6 +25,9 @@ base_run_test() { tot_pass=$((tot_pass + 1)) else ret="$?" + if [ "$STOP_ON_FAIL" -eq 1 ]; then + exit 1 + fi if [ "$ret" -eq 1 ]; then tot_config=$((tot_config + 1)) elif [ "$ret" -eq 2 ]; then @@ -80,7 +84,7 @@ wrap_test () { } run_wrap_test () { - echo -n "$@: " + shorten_echo "$@: " base_run_test wrap_test "$@" } @@ -190,6 +194,14 @@ libfdt_tests () { tree1_tests unfinished_tree1.test.dtb run_test dtbs_equal_ordered test_tree1.dtb sw_tree1.test.dtb + # Resizing tests + for mode in resize realloc; do + run_test sw_tree1 $mode + tree1_tests sw_tree1.test.dtb + tree1_tests unfinished_tree1.test.dtb + run_test dtbs_equal_ordered test_tree1.dtb sw_tree1.test.dtb + done + # fdt_move tests for tree in test_tree1.dtb sw_tree1.test.dtb unfinished_tree1.test.dtb; do rm -f moved.$tree shunted.$tree deshunted.$tree @@ -241,6 +253,9 @@ libfdt_tests () { tree1_tests_rw noppy.$basetree done + run_dtc_test -I dts -O dtb -o subnode_iterate.dtb subnode_iterate.dts + run_test subnode_iterate subnode_iterate.dtb + # Tests for behaviour on various sorts of corrupted trees run_test truncated_property @@ -254,6 +269,11 @@ dtc_tests () { tree1_tests_rw dtc_tree1.test.dtb run_test dtbs_equal_ordered dtc_tree1.test.dtb test_tree1.dtb + run_dtc_test -I dts -O dtb -o dtc_escapes.test.dtb propname_escapes.dts + run_test propname_escapes dtc_escapes.test.dtb + + run_dtc_test -I dts -O dtb -o line_directives.test.dtb line_directives.dts + run_dtc_test -I dts -O dtb -o dtc_escapes.test.dtb escapes.dts run_test string_escapes dtc_escapes.test.dtb @@ -367,6 +387,13 @@ dtc_tests () { run_dtc_test -I dts -O dtb -o dtc_tree1_merge_path.test.dtb test_tree1_merge_path.dts tree1_tests dtc_tree1_merge_path.test.dtb test_tree1.dtb + # Check prop/node delete functionality + run_dtc_test -I dts -O dtb -o dtc_tree1_delete.test.dtb test_tree1_delete.dts + tree1_tests dtc_tree1_delete.test.dtb + + run_dtc_test -I dts -O dts -o delete_reinstate_multilabel.dts.test.dts delete_reinstate_multilabel.dts + run_wrap_test cmp delete_reinstate_multilabel.dts.test.dts delete_reinstate_multilabel_ref.dts + # Check some checks check_tests dup-nodename.dts duplicate_node_names check_tests dup-propname.dts duplicate_property_names @@ -486,9 +513,10 @@ fdtget_tests () { # run_fdtget_test [] run_fdtget_test "MyBoardName" $dtb / model + run_fdtget_test "MyBoardName MyBoardFamilyName" $dtb / compatible run_fdtget_test "77 121 66 111 \ 97 114 100 78 97 109 101 0 77 121 66 111 97 114 100 70 97 109 105 \ -108 121 78 97 109 101 0" $dtb / compatible +108 121 78 97 109 101 0" -t bu $dtb / compatible run_fdtget_test "MyBoardName MyBoardFamilyName" -t s $dtb / compatible run_fdtget_test 32768 $dtb /cpus/PowerPC,970@1 d-cache-size run_fdtget_test 8000 -tx $dtb /cpus/PowerPC,970@1 d-cache-size @@ -533,8 +561,8 @@ fdtput_tests () { -tx "a0b0c0d deeaae ef000000" run_fdtput_test "$(cat $text)" $dtb /randomnode blob -ts "$(cat $text)" - # This should be larger than available space in the fdt - run_wrap_error_test $DTPUT $dtb /randomnode blob -ts "$(cat $text $text)" + # Test expansion of the blob when insufficient room for property + run_fdtput_test "$(cat $text $text)" $dtb /randomnode blob -ts "$(cat $text $text)" # Start again with a fresh dtb run_dtc_test -O dtb -p $(stat -c %s $text) -o $dtb $dts @@ -556,7 +584,9 @@ fdtput_tests () { run_fdtput_test "fine wine" $dtb /blackadder/the-second/potato drink \ "-ts" "fine wine" run_wrap_test $DTPUT $dtb -p /you/are/drunk/sir/winston slurp -ts twice - run_wrap_error_test $DTPUT $dtb -cp "$(cat $text $text)/longish" + + # Test expansion of the blob when insufficent room for a new node + run_wrap_test $DTPUT $dtb -cp "$(cat $text $text)/longish" # Allowed to create an existing node with -p run_wrap_test $DTPUT $dtb -cp /chosen @@ -569,7 +599,7 @@ utilfdt_tests () { run_test utilfdt_test } -while getopts "vt:m" ARG ; do +while getopts "vt:me" ARG ; do case $ARG in "v") unset QUIET_TEST @@ -580,6 +610,9 @@ while getopts "vt:m" ARG ; do "m") VALGRIND="valgrind --tool=memcheck -q --error-exitcode=$VGCODE" ;; + "e") + STOP_ON_FAIL=1 + ;; esac done diff --git a/tests/rw_tree1.c b/tests/rw_tree1.c index 103a24d7769..efd471892f1 100644 --- a/tests/rw_tree1.c +++ b/tests/rw_tree1.c @@ -24,7 +24,6 @@ #include #include -#include #include #include "tests.h" diff --git a/tests/set_name.c b/tests/set_name.c index 5d1149e002c..986158733a5 100644 --- a/tests/set_name.c +++ b/tests/set_name.c @@ -22,7 +22,6 @@ #include #include -#include #include #include "tests.h" diff --git a/tests/setprop.c b/tests/setprop.c index 9f2bc883b25..d089f8d5ab5 100644 --- a/tests/setprop.c +++ b/tests/setprop.c @@ -24,7 +24,6 @@ #include #include -#include #include #include "tests.h" diff --git a/tests/setprop_inplace.c b/tests/setprop_inplace.c index 82d895138d5..daef182d0b2 100644 --- a/tests/setprop_inplace.c +++ b/tests/setprop_inplace.c @@ -25,7 +25,6 @@ #include #include -#include #include #include "tests.h" diff --git a/tests/sized_cells.c b/tests/sized_cells.c index 847ec96ba4a..94da03b8a07 100644 --- a/tests/sized_cells.c +++ b/tests/sized_cells.c @@ -23,7 +23,6 @@ #include #include -#include #include #include "tests.h" diff --git a/tests/string_escapes.c b/tests/string_escapes.c index 30eb6a8d3d4..8cdee4bb34f 100644 --- a/tests/string_escapes.c +++ b/tests/string_escapes.c @@ -22,7 +22,6 @@ #include #include -#include #include #include "tests.h" diff --git a/tests/subnode_offset.c b/tests/subnode_offset.c index e58c192f7ab..231fcb50a26 100644 --- a/tests/subnode_offset.c +++ b/tests/subnode_offset.c @@ -22,7 +22,6 @@ #include #include -#include #include #include "tests.h" diff --git a/tests/supernode_atdepth_offset.c b/tests/supernode_atdepth_offset.c index 73f41aecf93..43e120d79e4 100644 --- a/tests/supernode_atdepth_offset.c +++ b/tests/supernode_atdepth_offset.c @@ -22,7 +22,6 @@ #include #include -#include #include #include "tests.h" diff --git a/tests/sw_tree1.c b/tests/sw_tree1.c index 5c71414692a..6d4c5310296 100644 --- a/tests/sw_tree1.c +++ b/tests/sw_tree1.c @@ -24,7 +24,6 @@ #include #include -#include #include #include "tests.h" @@ -32,24 +31,92 @@ #define SPACE 65536 -#define CHECK(code) \ - { \ - err = (code); \ - if (err) \ - FAIL(#code ": %s", fdt_strerror(err)); \ +static enum { + FIXED = 0, + RESIZE, + REALLOC, +} alloc_mode; + +static void realloc_fdt(void **fdt, size_t *size, bool created) +{ + switch (alloc_mode) { + case FIXED: + if (!(*fdt)) + fdt = xmalloc(*size); + else + FAIL("Ran out of space"); + return; + + case RESIZE: + if (!(*fdt)) { + fdt = xmalloc(SPACE); + } else if (*size < SPACE) { + *size += 1; + fdt_resize(*fdt, *fdt, *size); + } else { + FAIL("Ran out of space"); + } + return; + + case REALLOC: + *size += 1; + *fdt = xrealloc(*fdt, *size); + if (created) + fdt_resize(*fdt, *fdt, *size); + return; + + default: + CONFIG("Bad allocation mode"); } +} + +#define CHECK(code) \ + do { \ + err = (code); \ + if (err == -FDT_ERR_NOSPACE) \ + realloc_fdt(&fdt, &size, created); \ + else if (err) \ + FAIL(#code ": %s", fdt_strerror(err)); \ + } while (err != 0) int main(int argc, char *argv[]) { - void *fdt; + void *fdt = NULL; + size_t size; int err; + bool created = false; test_init(argc, argv); - fdt = xmalloc(SPACE); - CHECK(fdt_create(fdt, SPACE)); + if (argc == 1) { + alloc_mode = FIXED; + size = SPACE; + } else if (argc == 2) { + if (streq(argv[1], "resize")) { + alloc_mode = REALLOC; + size = 0; + } else if (streq(argv[1], "realloc")) { + alloc_mode = REALLOC; + size = 0; + } else { + char *endp; + + size = strtoul(argv[1], &endp, 0); + if (*endp == '\0') + alloc_mode = FIXED; + else + CONFIG("Bad allocation mode \"%s\" specified", + argv[1]); + } + } + + fdt = xmalloc(size); + CHECK(fdt_create(fdt, size)); + + created = true; CHECK(fdt_add_reservemap_entry(fdt, TEST_ADDR_1, TEST_SIZE_1)); + CHECK(fdt_add_reservemap_entry(fdt, TEST_ADDR_2, TEST_SIZE_2)); CHECK(fdt_finish_reservemap(fdt)); @@ -58,9 +125,12 @@ int main(int argc, char *argv[]) CHECK(fdt_property_u32(fdt, "prop-int", TEST_VALUE_1)); CHECK(fdt_property_u64(fdt, "prop-int64", TEST_VALUE64_1)); CHECK(fdt_property_string(fdt, "prop-str", TEST_STRING_1)); + CHECK(fdt_property_u32(fdt, "#address-cells", 1)); + CHECK(fdt_property_u32(fdt, "#size-cells", 0)); CHECK(fdt_begin_node(fdt, "subnode@1")); CHECK(fdt_property_string(fdt, "compatible", "subnode1")); + CHECK(fdt_property_u32(fdt, "reg", 1)); CHECK(fdt_property_cell(fdt, "prop-int", TEST_VALUE_1)); CHECK(fdt_begin_node(fdt, "subsubnode")); CHECK(fdt_property(fdt, "compatible", "subsubnode1\0subsubnode", @@ -72,9 +142,13 @@ int main(int argc, char *argv[]) CHECK(fdt_end_node(fdt)); CHECK(fdt_begin_node(fdt, "subnode@2")); + CHECK(fdt_property_u32(fdt, "reg", 2)); CHECK(fdt_property_cell(fdt, "linux,phandle", PHANDLE_1)); CHECK(fdt_property_cell(fdt, "prop-int", TEST_VALUE_2)); + CHECK(fdt_property_u32(fdt, "#address-cells", 1)); + CHECK(fdt_property_u32(fdt, "#size-cells", 0)); CHECK(fdt_begin_node(fdt, "subsubnode@0")); + CHECK(fdt_property_u32(fdt, "reg", 0)); CHECK(fdt_property_cell(fdt, "phandle", PHANDLE_2)); CHECK(fdt_property(fdt, "compatible", "subsubnode2\0subsubnode", 23)); diff --git a/tests/test_tree1.dts b/tests/test_tree1.dts index cf530ce4ba0..c7b170c5af6 100644 --- a/tests/test_tree1.dts +++ b/tests/test_tree1.dts @@ -1,38 +1,3 @@ /dts-v1/; -/memreserve/ 0xdeadbeef00000000 0x100000; -/memreserve/ 123456789 010000; - -/ { - compatible = "test_tree1"; - prop-int = <0xdeadbeef>; - prop-int64 = /bits/ 64 <0xdeadbeef01abcdef>; - prop-str = "hello world"; - - subnode@1 { - compatible = "subnode1"; - prop-int = [deadbeef]; - - subsubnode { - compatible = "subsubnode1", "subsubnode"; - prop-int = <0xdeadbeef>; - }; - - ss1 { - }; - }; - - subnode@2 { - linux,phandle = <0x2000>; - prop-int = <123456789>; - - ssn0: subsubnode@0 { - phandle = <0x2001>; - compatible = "subsubnode2", "subsubnode"; - prop-int = <0726746425>; - }; - - ss2 { - }; - }; -}; +/include/ "test_tree1_body.dtsi" diff --git a/tests/test_tree1_merge.dts b/tests/test_tree1_merge.dts index ded08d87143..b100c12debb 100644 --- a/tests/test_tree1_merge.dts +++ b/tests/test_tree1_merge.dts @@ -6,9 +6,12 @@ compatible = "test_tree1"; prop-int = "wrong!"; prop-str = "hello world"; + #address-cells = <1>; + #size-cells = <0>; subnode@1 { compatible = "subnode1"; + reg = <1>; subsubnode { compatible = "subsubnode1", "subsubnode"; @@ -20,8 +23,11 @@ }; subnode@2 { + reg = <2>; linux,phandle = <0x2000>; prop-int = <123456789>; + #address-cells = <1>; + #size-cells = <0>; ss2 { }; @@ -36,6 +42,7 @@ }; subnode@2 { ssn0: subsubnode@0 { + reg = <0>; phandle = <0x2001>; compatible = "subsubnode2", "subsubnode"; prop-int = <0726746425>; diff --git a/tests/test_tree1_merge_labelled.dts b/tests/test_tree1_merge_labelled.dts index 29953b0aa1b..fcf5dc45aee 100644 --- a/tests/test_tree1_merge_labelled.dts +++ b/tests/test_tree1_merge_labelled.dts @@ -8,9 +8,12 @@ prop-int = <0xdeadbeef>; prop-int64 = /bits/ 64 <0xdeadbeef01abcdef>; prop-str = "hello world"; + #address-cells = <1>; + #size-cells = <0>; subnode@1 { compatible = "subnode1"; + reg = <1>; prop-int = [deadbeef]; subsubnode { @@ -23,10 +26,14 @@ }; subnode@2 { + reg = <2>; linux,phandle = <0x2000>; prop-int = <123456789>; + #address-cells = <1>; + #size-cells = <0>; ssn0: subsubnode@0 { + reg = <0>; phandle = <0x2001>; prop-int = <0xbad>; }; diff --git a/tests/test_tree1_merge_path.dts b/tests/test_tree1_merge_path.dts index 168d066fad0..c2ad829727d 100644 --- a/tests/test_tree1_merge_path.dts +++ b/tests/test_tree1_merge_path.dts @@ -8,9 +8,12 @@ prop-int = <0xdeadbeef>; prop-int64 = /bits/ 64 <0xdeadbeef01abcdef>; prop-str = "hello world"; + #address-cells = <1>; + #size-cells = <0>; subnode@1 { compatible = "subnode1"; + reg = <1>; prop-int = [deadbeef]; subsubnode { @@ -23,10 +26,14 @@ }; subnode@2 { + reg = <2>; linux,phandle = <0x2000>; prop-int = <123456789>; + #address-cells = <1>; + #size-cells = <0>; ssn0: subsubnode@0 { + reg = <0>; phandle = <0x2001>; prop-int = <0xbad>; }; diff --git a/tests/test_tree1_wrong1.dts b/tests/test_tree1_wrong1.dts index d71820a2386..900d3858291 100644 --- a/tests/test_tree1_wrong1.dts +++ b/tests/test_tree1_wrong1.dts @@ -6,9 +6,12 @@ compatible = "test_tree1"; prop-int = <0xdeadbeef>; prop-str = "hello world"; + #address-cells = <1>; + #size-cells = <0>; subnode@1 { compatible = "subnode1"; + reg = <1>; prop-int = [deadbeef]; subsubnode { @@ -21,10 +24,14 @@ }; subnode@2 { + reg = <2>; linux,phandle = <0x2000>; prop-int = <123456789>; + #address-cells = <1>; + #size-cells = <0>; subsubnode@0 { + reg = <0>; phandle = <0x2001>; compatible = "subsubnode2", "subsubnode"; prop-int = <0726746425>; diff --git a/tests/test_tree1_wrong2.dts b/tests/test_tree1_wrong2.dts index ac27023c3c9..099752b374a 100644 --- a/tests/test_tree1_wrong2.dts +++ b/tests/test_tree1_wrong2.dts @@ -6,9 +6,12 @@ / { compatible = "test_tree1"; prop-str = "hello world"; + #address-cells = <1>; + #size-cells = <0>; subnode@1 { compatible = "subnode1"; + reg = <1>; prop-int = [deadbeef]; subsubnode { @@ -21,10 +24,14 @@ }; subnode@2 { + reg = <2>; linux,phandle = <0x2000>; prop-int = <123456789>; + #address-cells = <1>; + #size-cells = <0>; subsubnode@0 { + reg = <0>; phandle = <0x2001>; compatible = "subsubnode2", "subsubnode"; prop-int = <0726746425>; diff --git a/tests/test_tree1_wrong3.dts b/tests/test_tree1_wrong3.dts index 80be2fac8f6..069353a9400 100644 --- a/tests/test_tree1_wrong3.dts +++ b/tests/test_tree1_wrong3.dts @@ -7,9 +7,12 @@ compatible = "test_tree1"; prop-int = <0xdeadbeef>; prop-str = "hello world"; + #address-cells = <1>; + #size-cells = <0>; subnode@1 { compatible = "subnode1"; + reg = <1>; subsubnode { compatible = "subsubnode1", "subsubnode"; @@ -21,10 +24,14 @@ }; subnode@2 { + reg = <2>; linux,phandle = <0x2000>; prop-int = <123456789>; + #address-cells = <1>; + #size-cells = <0>; subsubnode@0 { + reg = <0>; phandle = <0x2001>; compatible = "subsubnode2", "subsubnode"; prop-int = <0726746425>; diff --git a/tests/test_tree1_wrong4.dts b/tests/test_tree1_wrong4.dts index 09bb13b8cb8..2c5641618e4 100644 --- a/tests/test_tree1_wrong4.dts +++ b/tests/test_tree1_wrong4.dts @@ -7,9 +7,12 @@ compatible = "test_tree1"; prop-int = <0xdeadbeef>; prop-str = "hello world"; + #address-cells = <1>; + #size-cells = <0>; subnode@1 { compatible = "subnode1"; + reg = <1>; prop-int = [deadbeef]; subsubnode { @@ -22,10 +25,14 @@ }; subnode@2 { + reg = <2>; linux,phandle = <0x2000>; prop-int = <123456789>; + #address-cells = <1>; + #size-cells = <0>; subsubnode@0 { + reg = <0>; phandle = <0x2001>; compatible = "subsubnode2", "subsubnode"; prop-int = <0726746425>; diff --git a/tests/test_tree1_wrong5.dts b/tests/test_tree1_wrong5.dts index ef4c4f7b772..6ddd72d52e1 100644 --- a/tests/test_tree1_wrong5.dts +++ b/tests/test_tree1_wrong5.dts @@ -7,9 +7,12 @@ compatible = "test_tree1"; prop-int = <0xdeadbefe>; prop-str = "hello world"; + #address-cells = <1>; + #size-cells = <0>; subnode@1 { compatible = "subnode1"; + reg = <1>; prop-int = [deadbeef]; subsubnode { @@ -22,10 +25,14 @@ }; subnode@2 { + reg = <2>; linux,phandle = <0x2000>; prop-int = <123456789>; + #address-cells = <1>; + #size-cells = <0>; subsubnode@0 { + reg = <0>; phandle = <0x2001>; compatible = "subsubnode2", "subsubnode"; prop-int = <0726746425>; diff --git a/tests/test_tree1_wrong6.dts b/tests/test_tree1_wrong6.dts index 98d6eda7fb5..36b4e1f66fe 100644 --- a/tests/test_tree1_wrong6.dts +++ b/tests/test_tree1_wrong6.dts @@ -7,9 +7,12 @@ compatible = "test_tree1"; prop-int = <0xdeadbeef>; prop-str = "hello world"; + #address-cells = <1>; + #size-cells = <0>; subnode@1 { compatible = "subnode1"; + reg = <1>; prop-int = [deadbeef]; subsubnode { @@ -23,10 +26,14 @@ }; subnode@2 { + reg = <2>; linux,phandle = <0x2000>; prop-int = <123456789>; + #address-cells = <1>; + #size-cells = <0>; subsubnode@0 { + reg = <0>; phandle = <0x2001>; compatible = "subsubnode2", "subsubnode"; prop-int = <0726746425>; diff --git a/tests/test_tree1_wrong7.dts b/tests/test_tree1_wrong7.dts index f57ace09a30..54150e6d9fb 100644 --- a/tests/test_tree1_wrong7.dts +++ b/tests/test_tree1_wrong7.dts @@ -7,9 +7,12 @@ compatible = "test_tree1"; prop-int = <0xdeadbeef>; prop-str = "hello world"; + #address-cells = <1>; + #size-cells = <0>; subnode@1 { compatible = "subnode1"; + reg = <1>; prop-int = [deadbeef]; subsubnode { @@ -22,10 +25,14 @@ }; subnode@2 { + reg = <2>; linux,phandle = <0x2000>; prop-int = <123456789>; + #address-cells = <1>; + #size-cells = <0>; subsubnode@0 { + reg = <0>; phandle = <0x2001>; compatible = "subsubnode2", "subsubnode"; prop-int = <0726746425>; diff --git a/tests/test_tree1_wrong8.dts b/tests/test_tree1_wrong8.dts index 811ce6c0e53..7a28a9f2953 100644 --- a/tests/test_tree1_wrong8.dts +++ b/tests/test_tree1_wrong8.dts @@ -7,9 +7,12 @@ compatible = "test_tree1"; prop-int = <0xdeadbeef>; prop-str = "hello world"; + #address-cells = <1>; + #size-cells = <0>; subnode@1 { compatible = "subnode1"; + reg = <1>; prop-int = [deadbeef]; subsubnode { @@ -24,8 +27,12 @@ subnode@2 { linux,phandle = <0x2000>; prop-int = <123456789>; + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; subsubnode@0 { + reg = <0>; phandle = <0x2001>; compatible = "subsubnode2", "subsubnode"; prop-int = <0726746425>; diff --git a/tests/test_tree1_wrong9.dts b/tests/test_tree1_wrong9.dts index 6ff6fab22dd..f6486fa9337 100644 --- a/tests/test_tree1_wrong9.dts +++ b/tests/test_tree1_wrong9.dts @@ -8,9 +8,12 @@ compatible = "test_tree1"; prop-int = <0xdeadbeef>; prop-str = "hello world"; + #address-cells = <1>; + #size-cells = <0>; subnode@1 { compatible = "subnode1"; + reg = <1>; prop-int = [deadbeef]; subsubnode { @@ -23,10 +26,14 @@ }; subnode@2 { + reg = <2>; linux,phandle = <0x2000>; prop-int = <123456789>; + #address-cells = <1>; + #size-cells = <0>; subsubnode@0 { + reg = <0>; phandle = <0x2001>; compatible = "subsubnode2", "subsubnode"; prop-int = <0726746425>; diff --git a/tests/trees.S b/tests/trees.S index cae018760e5..2389cd37962 100644 --- a/tests/trees.S +++ b/tests/trees.S @@ -92,9 +92,12 @@ test_tree1_struct: PROP_INT(test_tree1, prop_int, TEST_VALUE_1) PROP_INT64(test_tree1, prop_int64, TEST_VALUE64_1) PROP_STR(test_tree1, prop_str, TEST_STRING_1) + PROP_INT(test_tree1, address_cells, 1) + PROP_INT(test_tree1, size_cells, 0) BEGIN_NODE("subnode@1") PROP_STR(test_tree1, compatible, "subnode1") + PROP_INT(test_tree1, reg, 1) PROP_INT(test_tree1, prop_int, TEST_VALUE_1) BEGIN_NODE("subsubnode") @@ -108,10 +111,14 @@ test_tree1_struct: END_NODE BEGIN_NODE("subnode@2") + PROP_INT(test_tree1, reg, 2) PROP_INT(test_tree1, linux_phandle, PHANDLE_1) PROP_INT(test_tree1, prop_int, TEST_VALUE_2) + PROP_INT(test_tree1, address_cells, 1) + PROP_INT(test_tree1, size_cells, 0) BEGIN_NODE("subsubnode@0") + PROP_INT(test_tree1, reg, 0) PROP_INT(test_tree1, phandle, PHANDLE_2) PROP_STR(test_tree1, compatible, "subsubnode2\0subsubnode") PROP_INT(test_tree1, prop_int, TEST_VALUE_2) @@ -133,6 +140,9 @@ test_tree1_strings: STRING(test_tree1, prop_str, "prop-str") STRING(test_tree1, linux_phandle, "linux,phandle") STRING(test_tree1, phandle, "phandle") + STRING(test_tree1, reg, "reg") + STRING(test_tree1, address_cells, "#address-cells") + STRING(test_tree1, size_cells, "#size-cells") test_tree1_strings_end: test_tree1_end: diff --git a/tests/truncated_property.c b/tests/truncated_property.c index 56daa2276be..f820d99e3f5 100644 --- a/tests/truncated_property.c +++ b/tests/truncated_property.c @@ -23,7 +23,6 @@ #include #include -#include #include #include "tests.h" diff --git a/tests/utilfdt_test.c b/tests/utilfdt_test.c index 36b4aa54de4..274c3d68e95 100644 --- a/tests/utilfdt_test.c +++ b/tests/utilfdt_test.c @@ -24,7 +24,6 @@ #include #include -#include #include #include diff --git a/tests/value-labels.c b/tests/value-labels.c index abe27216492..dcf20593d5c 100644 --- a/tests/value-labels.c +++ b/tests/value-labels.c @@ -26,7 +26,6 @@ #include -#include #include #include "tests.h" diff --git a/treesource.c b/treesource.c index 33eeba55fb4..bf7a626e18a 100644 --- a/treesource.c +++ b/treesource.c @@ -26,12 +26,12 @@ extern int yyparse(void); extern YYLTYPE yylloc; struct boot_info *the_boot_info; -int treesource_error; +bool treesource_error; struct boot_info *dt_from_source(const char *fname) { the_boot_info = NULL; - treesource_error = 0; + treesource_error = false; srcfile_push(fname); yyin = current_srcfile->f; @@ -54,9 +54,9 @@ static void write_prefix(FILE *f, int level) fputc('\t', f); } -static int isstring(char c) +static bool isstring(char c) { - return (isprint(c) + return (isprint((unsigned char)c) || (c == '\0') || strchr("\a\b\t\n\v\f\r", c)); } @@ -119,7 +119,7 @@ static void write_propval_string(FILE *f, struct data val) fprintf(f, "\""); break; default: - if (isprint(c)) + if (isprint((unsigned char)c)) fprintf(f, "%c", c); else fprintf(f, "\\x%02hhx", c); diff --git a/util.c b/util.c index 2422c34e11d..330b594b70b 100644 --- a/util.c +++ b/util.c @@ -34,6 +34,7 @@ #include "libfdt.h" #include "util.h" +#include "version_gen.h" char *xstrdup(const char *s) { @@ -69,10 +70,10 @@ char *join_path(const char *path, const char *name) return str; } -int util_is_printable_string(const void *data, int len) +bool util_is_printable_string(const void *data, int len) { const char *s = data; - const char *ss; + const char *ss, *se; /* zero length is not */ if (len == 0) @@ -82,13 +83,19 @@ int util_is_printable_string(const void *data, int len) if (s[len - 1] != '\0') return 0; - ss = s; - while (*s && isprint(*s)) - s++; + se = s + len; - /* not zero, or not done yet */ - if (*s != '\0' || (s + 1 - ss) < len) - return 0; + while (s < se) { + ss = s; + while (s < se && *s && isprint((unsigned char)*s)) + s++; + + /* not zero, or not done yet */ + if (*s != '\0' || s == ss) + return 0; + + s++; + } return 1; } @@ -191,7 +198,7 @@ char get_escape_char(const char *s, int *i) return val; } -int utilfdt_read_err(const char *filename, char **buffp) +int utilfdt_read_err_len(const char *filename, char **buffp, off_t *len) { int fd = 0; /* assume stdin */ char *buf = NULL; @@ -206,12 +213,12 @@ int utilfdt_read_err(const char *filename, char **buffp) } /* Loop until we have read everything */ - buf = malloc(bufsize); + buf = xmalloc(bufsize); do { /* Expand the buffer to hold the next chunk */ if (offset == bufsize) { bufsize *= 2; - buf = realloc(buf, bufsize); + buf = xrealloc(buf, bufsize); if (!buf) { ret = ENOMEM; break; @@ -232,13 +239,20 @@ int utilfdt_read_err(const char *filename, char **buffp) free(buf); else *buffp = buf; + *len = bufsize; return ret; } -char *utilfdt_read(const char *filename) +int utilfdt_read_err(const char *filename, char **buffp) +{ + off_t len; + return utilfdt_read_err_len(filename, buffp, &len); +} + +char *utilfdt_read_len(const char *filename, off_t *len) { char *buff; - int ret = utilfdt_read_err(filename, &buff); + int ret = utilfdt_read_err_len(filename, &buff, len); if (ret) { fprintf(stderr, "Couldn't open blob from '%s': %s\n", filename, @@ -249,6 +263,12 @@ char *utilfdt_read(const char *filename) return buff; } +char *utilfdt_read(const char *filename) +{ + off_t len; + return utilfdt_read_len(filename, &len); +} + int utilfdt_write_err(const char *filename, const void *blob) { int fd = 1; /* assume stdout */ @@ -329,3 +349,100 @@ int utilfdt_decode_type(const char *fmt, int *type, int *size) return -1; return 0; } + +void utilfdt_print_data(const char *data, int len) +{ + int i; + const char *p = data; + const char *s; + + /* no data, don't print */ + if (len == 0) + return; + + if (util_is_printable_string(data, len)) { + printf(" = "); + + s = data; + do { + printf("\"%s\"", s); + s += strlen(s) + 1; + if (s < data + len) + printf(", "); + } while (s < data + len); + + } else if ((len % 4) == 0) { + const uint32_t *cell = (const uint32_t *)data; + + printf(" = <"); + for (i = 0; i < len; i += 4) + printf("0x%08x%s", fdt32_to_cpu(cell[i / 4]), + i < (len - 4) ? " " : ""); + printf(">"); + } else { + printf(" = ["); + for (i = 0; i < len; i++) + printf("%02x%s", *p++, i < len - 1 ? " " : ""); + printf("]"); + } +} + +void util_version(void) +{ + printf("Version: %s\n", DTC_VERSION); + exit(0); +} + +void util_usage(const char *errmsg, const char *synopsis, + const char *short_opts, struct option const long_opts[], + const char * const opts_help[]) +{ + FILE *fp = errmsg ? stderr : stdout; + const char a_arg[] = ""; + size_t a_arg_len = strlen(a_arg) + 1; + size_t i; + int optlen; + + fprintf(fp, + "Usage: %s\n" + "\n" + "Options: -[%s]\n", synopsis, short_opts); + + /* prescan the --long opt length to auto-align */ + optlen = 0; + for (i = 0; long_opts[i].name; ++i) { + /* +1 is for space between --opt and help text */ + int l = strlen(long_opts[i].name) + 1; + if (long_opts[i].has_arg == a_argument) + l += a_arg_len; + if (optlen < l) + optlen = l; + } + + for (i = 0; long_opts[i].name; ++i) { + /* helps when adding new applets or options */ + assert(opts_help[i] != NULL); + + /* first output the short flag if it has one */ + if (long_opts[i].val > '~') + fprintf(fp, " "); + else + fprintf(fp, " -%c, ", long_opts[i].val); + + /* then the long flag */ + if (long_opts[i].has_arg == no_argument) + fprintf(fp, "--%-*s", optlen, long_opts[i].name); + else + fprintf(fp, "--%s %s%*s", long_opts[i].name, a_arg, + (int)(optlen - strlen(long_opts[i].name) - a_arg_len), ""); + + /* finally the help text */ + fprintf(fp, "%s\n", opts_help[i]); + } + + if (errmsg) { + fprintf(fp, "\nError: %s\n", errmsg); + exit(EXIT_FAILURE); + } else + exit(EXIT_SUCCESS); +} diff --git a/util.h b/util.h index c8eb45d9f04..ccfdf4b1243 100644 --- a/util.h +++ b/util.h @@ -2,6 +2,8 @@ #define _UTIL_H #include +#include +#include /* * Copyright 2011 The Chromium Authors, All Rights Reserved. @@ -23,7 +25,9 @@ * USA */ -static inline void __attribute__((noreturn)) die(char * str, ...) +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +static inline void __attribute__((noreturn)) die(const char *str, ...) { va_list ap; @@ -57,13 +61,15 @@ extern char *xstrdup(const char *s); extern char *join_path(const char *path, const char *name); /** - * Check a string of a given length to see if it is all printable and - * has a valid terminator. + * Check a property of a given length to see if it is all printable and + * has a valid terminator. The property can contain either a single string, + * or multiple strings each of non-zero length. * * @param data The string to check * @param len The string length including terminator - * @return 1 if a valid printable string, 0 if not */ -int util_is_printable_string(const void *data, int len); + * @return 1 if a valid printable string, 0 if not + */ +bool util_is_printable_string(const void *data, int len); /* * Parse an escaped character starting at index i in string s. The resulting @@ -82,6 +88,13 @@ char get_escape_char(const char *s, int *i); */ char *utilfdt_read(const char *filename); +/** + * Like utilfdt_read(), but also passes back the size of the file read. + * + * @param len If non-NULL, the amount of data we managed to read + */ +char *utilfdt_read_len(const char *filename, off_t *len); + /** * Read a device tree file into a buffer. Does not report errors, but only * returns them. The value returned can be passed to strerror() to obtain @@ -93,6 +106,12 @@ char *utilfdt_read(const char *filename); */ int utilfdt_read_err(const char *filename, char **buffp); +/** + * Like utilfdt_read_err(), but also passes back the size of the file read. + * + * @param len If non-NULL, the amount of data we managed to read + */ +int utilfdt_read_err_len(const char *filename, char **buffp, off_t *len); /** * Write a device tree buffer to a file. This will report any errors on @@ -148,6 +167,85 @@ int utilfdt_decode_type(const char *fmt, int *type, int *size); #define USAGE_TYPE_MSG \ "\ts=string, i=int, u=unsigned, x=hex\n" \ "\tOptional modifier prefix:\n" \ - "\t\thh or b=byte, h=2 byte, l=4 byte (default)\n"; + "\t\thh or b=byte, h=2 byte, l=4 byte (default)"; + +/** + * Print property data in a readable format to stdout + * + * Properties that look like strings will be printed as strings. Otherwise + * the data will be displayed either as cells (if len is a multiple of 4 + * bytes) or bytes. + * + * If len is 0 then this function does nothing. + * + * @param data Pointers to property data + * @param len Length of property data + */ +void utilfdt_print_data(const char *data, int len); + +/** + * Show source version and exit + */ +void util_version(void) __attribute__((noreturn)); + +/** + * Show usage and exit + * + * This helps standardize the output of various utils. You most likely want + * to use the usage() helper below rather than call this. + * + * @param errmsg If non-NULL, an error message to display + * @param synopsis The initial example usage text (and possible examples) + * @param short_opts The string of short options + * @param long_opts The structure of long options + * @param opts_help An array of help strings (should align with long_opts) + */ +void util_usage(const char *errmsg, const char *synopsis, + const char *short_opts, struct option const long_opts[], + const char * const opts_help[]) __attribute__((noreturn)); + +/** + * Show usage and exit + * + * If you name all your usage variables with usage_xxx, then you can call this + * help macro rather than expanding all arguments yourself. + * + * @param errmsg If non-NULL, an error message to display + */ +#define usage(errmsg) \ + util_usage(errmsg, usage_synopsis, usage_short_opts, \ + usage_long_opts, usage_opts_help) + +/** + * Call getopt_long() with standard options + * + * Since all util code runs getopt in the same way, provide a helper. + */ +#define util_getopt_long() getopt_long(argc, argv, usage_short_opts, \ + usage_long_opts, NULL) + +/* Helper for aligning long_opts array */ +#define a_argument required_argument + +/* Helper for usage_short_opts string constant */ +#define USAGE_COMMON_SHORT_OPTS "hV" + +/* Helper for usage_long_opts option array */ +#define USAGE_COMMON_LONG_OPTS \ + {"help", no_argument, NULL, 'h'}, \ + {"version", no_argument, NULL, 'V'}, \ + {NULL, no_argument, NULL, 0x0} + +/* Helper for usage_opts_help array */ +#define USAGE_COMMON_OPTS_HELP \ + "Print this help and exit", \ + "Print version and exit", \ + NULL + +/* Helper for getopt case statements */ +#define case_USAGE_COMMON_FLAGS \ + case 'h': usage(NULL); \ + case 'V': util_version(); \ + case '?': usage("unknown option"); #endif /* _UTIL_H */ -- 2.45.0