Commit cd296721 authored by Stephen Warren's avatar Stephen Warren Committed by Rob Herring

dtc: import latest upstream dtc

This updates scripts/dtc to commit 317a5d9 "dtc: zero out new label
objects" from git://git.jdl.com/software/dtc.git.

This adds features such as:
* /bits/ syntax for cell data.
* Math expressions within cell data.
* The ability to delete properties or nodes.
* Support for #line directives in the input file, which allows the use of
  cpp on *.dts.
* -i command-line option (/include/ path)
* -W/-E command-line options for error/warning control.
* Removal of spew to STDOUT containing the filename being compiled.
* Many additions to the libfdt API.
Signed-off-by: default avatarStephen Warren <swarren@nvidia.com>
Acked-by: default avatarJon Loeliger <jdl@jdl.com>
Signed-off-by: default avatarRob Herring <rob.herring@calxeda.com>
parent acc20979
...@@ -3,7 +3,16 @@ ...@@ -3,7 +3,16 @@
# This is not a complete Makefile of itself. Instead, it is designed to # This is not a complete Makefile of itself. Instead, it is designed to
# be easily embeddable into other systems of Makefiles. # be easily embeddable into other systems of Makefiles.
# #
DTC_SRCS = dtc.c flattree.c fstree.c data.c livetree.c treesource.c srcpos.c \ DTC_SRCS = \
checks.c checks.c \
data.c \
dtc.c \
flattree.c \
fstree.c \
livetree.c \
srcpos.c \
treesource.c \
util.c
DTC_GEN_SRCS = dtc-lexer.lex.c dtc-parser.tab.c DTC_GEN_SRCS = dtc-lexer.lex.c dtc-parser.tab.c
DTC_OBJS = $(DTC_SRCS:%.c=%.o) $(DTC_GEN_SRCS:%.c=%.o) DTC_OBJS = $(DTC_SRCS:%.c=%.o) $(DTC_GEN_SRCS:%.c=%.o)
This diff is collapsed.
...@@ -68,40 +68,6 @@ struct data data_copy_mem(const char *mem, int len) ...@@ -68,40 +68,6 @@ struct data data_copy_mem(const char *mem, int len)
return d; return d;
} }
static char get_oct_char(const char *s, int *i)
{
char x[4];
char *endx;
long val;
x[3] = '\0';
strncpy(x, s + *i, 3);
val = strtol(x, &endx, 8);
assert(endx > x);
(*i) += endx - x;
return val;
}
static char get_hex_char(const char *s, int *i)
{
char x[3];
char *endx;
long val;
x[2] = '\0';
strncpy(x, s + *i, 2);
val = strtol(x, &endx, 16);
if (!(endx > x))
die("\\x used with no following hex digits\n");
(*i) += endx - x;
return val;
}
struct data data_copy_escape_string(const char *s, int len) struct data data_copy_escape_string(const char *s, int len)
{ {
int i = 0; int i = 0;
...@@ -114,54 +80,11 @@ struct data data_copy_escape_string(const char *s, int len) ...@@ -114,54 +80,11 @@ struct data data_copy_escape_string(const char *s, int len)
while (i < len) { while (i < len) {
char c = s[i++]; char c = s[i++];
if (c != '\\') { if (c == '\\')
q[d.len++] = c; c = get_escape_char(s, &i);
continue;
}
c = s[i++];
assert(c);
switch (c) {
case 'a':
q[d.len++] = '\a';
break;
case 'b':
q[d.len++] = '\b';
break;
case 't':
q[d.len++] = '\t';
break;
case 'n':
q[d.len++] = '\n';
break;
case 'v':
q[d.len++] = '\v';
break;
case 'f':
q[d.len++] = '\f';
break;
case 'r':
q[d.len++] = '\r';
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
i--; /* need to re-read the first digit as
* part of the octal value */
q[d.len++] = get_oct_char(s, &i);
break;
case 'x':
q[d.len++] = get_hex_char(s, &i);
break;
default:
q[d.len++] = c; q[d.len++] = c;
} }
}
q[d.len++] = '\0'; q[d.len++] = '\0';
return d; return d;
...@@ -245,11 +168,33 @@ struct data data_merge(struct data d1, struct data d2) ...@@ -245,11 +168,33 @@ struct data data_merge(struct data d1, struct data d2)
return d; return d;
} }
struct data data_append_cell(struct data d, cell_t word) struct data data_append_integer(struct data d, uint64_t value, int bits)
{ {
cell_t beword = cpu_to_fdt32(word); uint8_t value_8;
uint16_t value_16;
uint32_t value_32;
uint64_t value_64;
switch (bits) {
case 8:
value_8 = value;
return data_append_data(d, &value_8, 1);
case 16:
value_16 = cpu_to_fdt16(value);
return data_append_data(d, &value_16, 2);
case 32:
value_32 = cpu_to_fdt32(value);
return data_append_data(d, &value_32, 4);
case 64:
value_64 = cpu_to_fdt64(value);
return data_append_data(d, &value_64, 8);
return data_append_data(d, &beword, sizeof(beword)); default:
die("Invalid literal size (%d)\n", bits);
}
} }
struct data data_append_re(struct data d, const struct fdt_reserve_entry *re) struct data data_append_re(struct data d, const struct fdt_reserve_entry *re)
...@@ -262,11 +207,14 @@ struct data data_append_re(struct data d, const struct fdt_reserve_entry *re) ...@@ -262,11 +207,14 @@ struct data data_append_re(struct data d, const struct fdt_reserve_entry *re)
return data_append_data(d, &bere, sizeof(bere)); return data_append_data(d, &bere, sizeof(bere));
} }
struct data data_append_addr(struct data d, uint64_t addr) struct data data_append_cell(struct data d, cell_t word)
{ {
uint64_t beaddr = cpu_to_fdt64(addr); return data_append_integer(d, word, sizeof(word) * 8);
}
return data_append_data(d, &beaddr, sizeof(beaddr)); struct data data_append_addr(struct data d, uint64_t addr)
{
return data_append_integer(d, addr, sizeof(addr) * 8);
} }
struct data data_append_byte(struct data d, uint8_t byte) struct data data_append_byte(struct data d, uint8_t byte)
......
...@@ -29,6 +29,7 @@ PROPNODECHAR [a-zA-Z0-9,._+*#?@-] ...@@ -29,6 +29,7 @@ PROPNODECHAR [a-zA-Z0-9,._+*#?@-]
PATHCHAR ({PROPNODECHAR}|[/]) PATHCHAR ({PROPNODECHAR}|[/])
LABEL [a-zA-Z_][a-zA-Z0-9_]* LABEL [a-zA-Z_][a-zA-Z0-9_]*
STRING \"([^\\"]|\\.)*\" STRING \"([^\\"]|\\.)*\"
CHAR_LITERAL '([^']|\\')*'
WS [[:space:]] WS [[:space:]]
COMMENT "/*"([^*]|\*+[^*/])*\*+"/" COMMENT "/*"([^*]|\*+[^*/])*\*+"/"
LINECOMMENT "//".*\n LINECOMMENT "//".*\n
...@@ -70,6 +71,27 @@ static int pop_input_file(void); ...@@ -70,6 +71,27 @@ static int pop_input_file(void);
push_input_file(name); push_input_file(name);
} }
<*>^"#"(line)?{WS}+[0-9]+{WS}+{STRING}({WS}+[0-9]+)? {
char *line, *tmp, *fn;
/* skip text before line # */
line = yytext;
while (!isdigit(*line))
line++;
/* skip digits in line # */
tmp = line;
while (!isspace(*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);
}
<*><<EOF>> { <*><<EOF>> {
if (!pop_input_file()) { if (!pop_input_file()) {
yyterminate(); yyterminate();
...@@ -96,6 +118,26 @@ static int pop_input_file(void); ...@@ -96,6 +118,26 @@ static int pop_input_file(void);
return DT_MEMRESERVE; return DT_MEMRESERVE;
} }
<*>"/bits/" {
DPRINT("Keyword: /bits/\n");
BEGIN_DEFAULT();
return DT_BITS;
}
<*>"/delete-property/" {
DPRINT("Keyword: /delete-property/\n");
DPRINT("<PROPNODENAME>\n");
BEGIN(PROPNODENAME);
return DT_DEL_PROP;
}
<*>"/delete-node/" {
DPRINT("Keyword: /delete-node/\n");
DPRINT("<PROPNODENAME>\n");
BEGIN(PROPNODENAME);
return DT_DEL_NODE;
}
<*>{LABEL}: { <*>{LABEL}: {
DPRINT("Label: %s\n", yytext); DPRINT("Label: %s\n", yytext);
yylval.labelref = xstrdup(yytext); yylval.labelref = xstrdup(yytext);
...@@ -103,12 +145,19 @@ static int pop_input_file(void); ...@@ -103,12 +145,19 @@ static int pop_input_file(void);
return DT_LABEL; return DT_LABEL;
} }
<V1>[0-9]+|0[xX][0-9a-fA-F]+ { <V1>([0-9]+|0[xX][0-9a-fA-F]+)(U|L|UL|LL|ULL)? {
yylval.literal = xstrdup(yytext); yylval.literal = xstrdup(yytext);
DPRINT("Literal: '%s'\n", yylval.literal); DPRINT("Literal: '%s'\n", yylval.literal);
return DT_LITERAL; return DT_LITERAL;
} }
<*>{CHAR_LITERAL} {
yytext[yyleng-1] = '\0';
yylval.literal = xstrdup(yytext+1);
DPRINT("Character literal: %s\n", yylval.literal);
return DT_CHAR_LITERAL;
}
<*>\&{LABEL} { /* label reference */ <*>\&{LABEL} { /* label reference */
DPRINT("Ref: %s\n", yytext+1); DPRINT("Ref: %s\n", yytext+1);
yylval.labelref = xstrdup(yytext+1); yylval.labelref = xstrdup(yytext+1);
...@@ -134,9 +183,10 @@ static int pop_input_file(void); ...@@ -134,9 +183,10 @@ static int pop_input_file(void);
return ']'; return ']';
} }
<PROPNODENAME>{PROPNODECHAR}+ { <PROPNODENAME>\\?{PROPNODECHAR}+ {
DPRINT("PropNodeName: %s\n", yytext); DPRINT("PropNodeName: %s\n", yytext);
yylval.propnodename = xstrdup(yytext); yylval.propnodename = xstrdup((yytext[0] == '\\') ?
yytext + 1 : yytext);
BEGIN_DEFAULT(); BEGIN_DEFAULT();
return DT_PROPNODENAME; return DT_PROPNODENAME;
} }
...@@ -150,6 +200,15 @@ static int pop_input_file(void); ...@@ -150,6 +200,15 @@ static int pop_input_file(void);
<*>{COMMENT}+ /* eat C-style comments */ <*>{COMMENT}+ /* eat C-style comments */
<*>{LINECOMMENT}+ /* eat C++-style comments */ <*>{LINECOMMENT}+ /* eat C++-style comments */
<*>"<<" { return DT_LSHIFT; };
<*>">>" { return DT_RSHIFT; };
<*>"<=" { return DT_LE; };
<*>">=" { return DT_GE; };
<*>"==" { return DT_EQ; };
<*>"!=" { return DT_NE; };
<*>"&&" { return DT_AND; };
<*>"||" { return DT_OR; };
<*>. { <*>. {
DPRINT("Char: %c (\\x%02x)\n", yytext[0], DPRINT("Char: %c (\\x%02x)\n", yytext[0],
(unsigned)yytext[0]); (unsigned)yytext[0]);
......
This diff is collapsed.
This diff is collapsed.
/* A Bison parser, made by GNU Bison 2.4.3. */
/* A Bison parser, made by GNU Bison 2.4.1. */
/* Skeleton interface for Bison's Yacc-like parsers in C /* Skeleton interface for Bison's Yacc-like parsers in C
Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006, Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
2009, 2010 Free Software Foundation, Inc. Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
...@@ -40,14 +41,26 @@ ...@@ -40,14 +41,26 @@
enum yytokentype { enum yytokentype {
DT_V1 = 258, DT_V1 = 258,
DT_MEMRESERVE = 259, DT_MEMRESERVE = 259,
DT_PROPNODENAME = 260, DT_LSHIFT = 260,
DT_LITERAL = 261, DT_RSHIFT = 261,
DT_BASE = 262, DT_LE = 262,
DT_BYTE = 263, DT_GE = 263,
DT_STRING = 264, DT_EQ = 264,
DT_LABEL = 265, DT_NE = 265,
DT_REF = 266, DT_AND = 266,
DT_INCBIN = 267 DT_OR = 267,
DT_BITS = 268,
DT_DEL_PROP = 269,
DT_DEL_NODE = 270,
DT_PROPNODENAME = 271,
DT_LITERAL = 272,
DT_CHAR_LITERAL = 273,
DT_BASE = 274,
DT_BYTE = 275,
DT_STRING = 276,
DT_LABEL = 277,
DT_REF = 278,
DT_INCBIN = 279
}; };
#endif #endif
...@@ -57,6 +70,8 @@ ...@@ -57,6 +70,8 @@
typedef union YYSTYPE typedef union YYSTYPE
{ {
/* Line 1676 of yacc.c */
#line 40 "dtc-parser.y"
char *propnodename; char *propnodename;
char *literal; char *literal;
...@@ -65,16 +80,22 @@ typedef union YYSTYPE ...@@ -65,16 +80,22 @@ typedef union YYSTYPE
uint8_t byte; uint8_t byte;
struct data data; struct data data;
uint64_t addr; struct {
cell_t cell; struct data data;
int bits;
} array;
struct property *prop; struct property *prop;
struct property *proplist; struct property *proplist;
struct node *node; struct node *node;
struct node *nodelist; struct node *nodelist;
struct reserve_info *re; struct reserve_info *re;
uint64_t integer;
/* Line 1676 of yacc.c */
#line 99 "dtc-parser.tab.h"
} YYSTYPE; } YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_TRIVIAL 1
# define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define yystype YYSTYPE /* obsolescent; will be withdrawn */
......
...@@ -34,6 +34,7 @@ extern struct boot_info *the_boot_info; ...@@ -34,6 +34,7 @@ extern struct boot_info *the_boot_info;
extern int treesource_error; extern int treesource_error;
static unsigned long long eval_literal(const char *s, int base, int bits); static unsigned long long eval_literal(const char *s, int base, int bits);
static unsigned char eval_char_literal(const char *s);
%} %}
%union { %union {
...@@ -44,19 +45,28 @@ static unsigned long long eval_literal(const char *s, int base, int bits); ...@@ -44,19 +45,28 @@ static unsigned long long eval_literal(const char *s, int base, int bits);
uint8_t byte; uint8_t byte;
struct data data; struct data data;
uint64_t addr; struct {
cell_t cell; struct data data;
int bits;
} array;
struct property *prop; struct property *prop;
struct property *proplist; struct property *proplist;
struct node *node; struct node *node;
struct node *nodelist; struct node *nodelist;
struct reserve_info *re; struct reserve_info *re;
uint64_t integer;
} }
%token DT_V1 %token DT_V1
%token DT_MEMRESERVE %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 <propnodename> DT_PROPNODENAME %token <propnodename> DT_PROPNODENAME
%token <literal> DT_LITERAL %token <literal> DT_LITERAL
%token <literal> DT_CHAR_LITERAL
%token <cbase> DT_BASE %token <cbase> DT_BASE
%token <byte> DT_BYTE %token <byte> DT_BYTE
%token <data> DT_STRING %token <data> DT_STRING
...@@ -68,9 +78,7 @@ static unsigned long long eval_literal(const char *s, int base, int bits); ...@@ -68,9 +78,7 @@ static unsigned long long eval_literal(const char *s, int base, int bits);
%type <data> propdataprefix %type <data> propdataprefix
%type <re> memreserve %type <re> memreserve
%type <re> memreserves %type <re> memreserves
%type <addr> addr %type <array> arrayprefix
%type <data> celllist
%type <cell> cellval
%type <data> bytestring %type <data> bytestring
%type <prop> propdef %type <prop> propdef
%type <proplist> proplist %type <proplist> proplist
...@@ -80,6 +88,21 @@ static unsigned long long eval_literal(const char *s, int base, int bits); ...@@ -80,6 +88,21 @@ static unsigned long long eval_literal(const char *s, int base, int bits);
%type <node> subnode %type <node> subnode
%type <nodelist> subnodes %type <nodelist> subnodes
%type <integer> integer_prim
%type <integer> integer_unary
%type <integer> integer_mul
%type <integer> integer_add
%type <integer> integer_shift
%type <integer> integer_rela
%type <integer> integer_eq
%type <integer> integer_bitand
%type <integer> integer_bitxor
%type <integer> integer_bitor
%type <integer> integer_and
%type <integer> integer_or
%type <integer> integer_trinary
%type <integer> integer_expr
%% %%
sourcefile: sourcefile:
...@@ -102,7 +125,7 @@ memreserves: ...@@ -102,7 +125,7 @@ memreserves:
; ;
memreserve: memreserve:
DT_MEMRESERVE addr addr ';' DT_MEMRESERVE integer_prim integer_prim ';'
{ {
$$ = build_reserve_entry($2, $3); $$ = build_reserve_entry($2, $3);
} }
...@@ -113,13 +136,6 @@ memreserve: ...@@ -113,13 +136,6 @@ memreserve:
} }
; ;
addr:
DT_LITERAL
{
$$ = eval_literal($1, 0, 64);
}
;
devicetree: devicetree:
'/' nodedef '/' nodedef
{ {
...@@ -139,6 +155,17 @@ devicetree: ...@@ -139,6 +155,17 @@ devicetree:
print_error("label or path, '%s', not found", $2); print_error("label or path, '%s', not found", $2);
$$ = $1; $$ = $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: nodedef:
...@@ -168,6 +195,10 @@ propdef: ...@@ -168,6 +195,10 @@ propdef:
{ {
$$ = build_property($1, empty_data); $$ = build_property($1, empty_data);
} }
| DT_DEL_PROP DT_PROPNODENAME ';'
{
$$ = build_property_delete($2);
}
| DT_LABEL propdef | DT_LABEL propdef
{ {
add_label(&$2->labels, $1); add_label(&$2->labels, $1);
...@@ -180,9 +211,9 @@ propdata: ...@@ -180,9 +211,9 @@ propdata:
{ {
$$ = data_merge($1, $2); $$ = data_merge($1, $2);
} }
| propdataprefix '<' celllist '>' | propdataprefix arrayprefix '>'
{ {
$$ = data_merge($1, $3); $$ = data_merge($1, $2.data);
} }
| propdataprefix '[' bytestring ']' | propdataprefix '[' bytestring ']'
{ {
...@@ -192,7 +223,7 @@ propdata: ...@@ -192,7 +223,7 @@ propdata:
{ {
$$ = data_add_marker($1, REF_PATH, $2); $$ = data_add_marker($1, REF_PATH, $2);
} }
| propdataprefix DT_INCBIN '(' DT_STRING ',' addr ',' addr ')' | propdataprefix DT_INCBIN '(' DT_STRING ',' integer_prim ',' integer_prim ')'
{ {
FILE *f = srcfile_relative_open($4.val, NULL); FILE *f = srcfile_relative_open($4.val, NULL);
struct data d; struct data d;
...@@ -240,33 +271,156 @@ propdataprefix: ...@@ -240,33 +271,156 @@ propdataprefix:
} }
; ;
celllist: arrayprefix:
/* empty */ DT_BITS DT_LITERAL '<'
{ {
$$ = empty_data; $$.data = empty_data;
$$.bits = eval_literal($2, 0, 7);
if (($$.bits != 8) &&
($$.bits != 16) &&
($$.bits != 32) &&
($$.bits != 64))
{
print_error("Only 8, 16, 32 and 64-bit elements"
" are currently supported");
$$.bits = 32;
}
} }
| celllist cellval | '<'
{ {
$$ = data_append_cell($1, $2); $$.data = empty_data;
$$.bits = 32;
} }
| celllist DT_REF | arrayprefix integer_prim
{ {
$$ = data_append_cell(data_add_marker($1, REF_PHANDLE, if ($1.bits < 64) {
$2), -1); uint64_t mask = (1ULL << $1.bits) - 1;
/*
* Bits above mask must either be all zero
* (positive within range of mask) or all one
* (negative and sign-extended). The second
* condition is true if when we set all bits
* within the mask to one (i.e. | in the
* mask), all bits are one.
*/
if (($2 > mask) && (($2 | mask) != -1ULL))
print_error(
"integer value out of range "
"%016lx (%d bits)", $1.bits);
}
$$.data = data_append_integer($1.data, $2, $1.bits);
} }
| celllist DT_LABEL | arrayprefix DT_REF
{ {
$$ = data_add_marker($1, LABEL, $2); uint64_t val = ~0ULL >> (64 - $1.bits);
if ($1.bits == 32)
$1.data = data_add_marker($1.data,
REF_PHANDLE,
$2);
else
print_error("References are only allowed in "
"arrays with 32-bit elements.");
$$.data = data_append_integer($1.data, val, $1.bits);
}
| arrayprefix DT_LABEL
{
$$.data = data_add_marker($1.data, LABEL, $2);
} }
; ;
cellval: integer_prim:
DT_LITERAL DT_LITERAL
{ {
$$ = eval_literal($1, 0, 32); $$ = eval_literal($1, 0, 64);
}
| DT_CHAR_LITERAL
{
$$ = eval_char_literal($1);
}
| '(' integer_expr ')'
{
$$ = $2;
} }
; ;
integer_expr:
integer_trinary
;
integer_trinary:
integer_or
| integer_or '?' integer_expr ':' integer_trinary { $$ = $1 ? $3 : $5; }
;
integer_or:
integer_and
| integer_or DT_OR integer_and { $$ = $1 || $3; }
;
integer_and:
integer_bitor
| integer_and DT_AND integer_bitor { $$ = $1 && $3; }
;
integer_bitor:
integer_bitxor
| integer_bitor '|' integer_bitxor { $$ = $1 | $3; }
;
integer_bitxor:
integer_bitand
| integer_bitxor '^' integer_bitand { $$ = $1 ^ $3; }
;
integer_bitand:
integer_eq
| integer_bitand '&' integer_eq { $$ = $1 & $3; }
;
integer_eq:
integer_rela
| integer_eq DT_EQ integer_rela { $$ = $1 == $3; }
| integer_eq DT_NE integer_rela { $$ = $1 != $3; }
;
integer_rela:
integer_shift
| integer_rela '<' integer_shift { $$ = $1 < $3; }
| integer_rela '>' integer_shift { $$ = $1 > $3; }
| integer_rela DT_LE integer_shift { $$ = $1 <= $3; }
| integer_rela DT_GE integer_shift { $$ = $1 >= $3; }
;
integer_shift:
integer_shift DT_LSHIFT integer_add { $$ = $1 << $3; }
| integer_shift DT_RSHIFT integer_add { $$ = $1 >> $3; }
| integer_add
;
integer_add:
integer_add '+' integer_mul { $$ = $1 + $3; }
| integer_add '-' integer_mul { $$ = $1 - $3; }
| integer_mul
;
integer_mul:
integer_mul '*' integer_unary { $$ = $1 * $3; }
| integer_mul '/' integer_unary { $$ = $1 / $3; }
| integer_mul '%' integer_unary { $$ = $1 % $3; }
| integer_unary
;
integer_unary:
integer_prim
| '-' integer_unary { $$ = -$2; }
| '~' integer_unary { $$ = ~$2; }
| '!' integer_unary { $$ = !$2; }
;
bytestring: bytestring:
/* empty */ /* empty */
{ {
...@@ -303,6 +457,10 @@ subnode: ...@@ -303,6 +457,10 @@ subnode:
{ {
$$ = name_node($2, $1); $$ = name_node($2, $1);
} }
| DT_DEL_NODE DT_PROPNODENAME ';'
{
$$ = name_node(build_node_delete(), $2);
}
| DT_LABEL subnode | DT_LABEL subnode
{ {
add_label(&$2->labels, $1); add_label(&$2->labels, $1);
...@@ -334,12 +492,41 @@ static unsigned long long eval_literal(const char *s, int base, int bits) ...@@ -334,12 +492,41 @@ static unsigned long long eval_literal(const char *s, int base, int bits)
errno = 0; errno = 0;
val = strtoull(s, &e, base); val = strtoull(s, &e, base);
if (*e) if (*e) {
size_t uls = strspn(e, "UL");
if (e[uls])
print_error("bad characters in literal"); print_error("bad characters in literal");
else if ((errno == ERANGE) }
if ((errno == ERANGE)
|| ((bits < 64) && (val >= (1ULL << bits)))) || ((bits < 64) && (val >= (1ULL << bits))))
print_error("literal out of range"); print_error("literal out of range");
else if (errno != 0) else if (errno != 0)
print_error("bad literal"); print_error("bad literal");
return val; 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;
}
...@@ -82,6 +82,8 @@ static void __attribute__ ((noreturn)) usage(void) ...@@ -82,6 +82,8 @@ static void __attribute__ ((noreturn)) usage(void)
fprintf(stderr, "\t\tSet the physical boot cpu\n"); fprintf(stderr, "\t\tSet the physical boot cpu\n");
fprintf(stderr, "\t-f\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\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-s\n");
fprintf(stderr, "\t\tSort nodes and properties before outputting (only useful for\n\t\tcomparing trees)\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-v\n");
...@@ -91,6 +93,9 @@ static void __attribute__ ((noreturn)) usage(void) ...@@ -91,6 +93,9 @@ static void __attribute__ ((noreturn)) usage(void)
fprintf(stderr, "\t\t\tlegacy - \"linux,phandle\" properties only\n"); fprintf(stderr, "\t\t\tlegacy - \"linux,phandle\" properties only\n");
fprintf(stderr, "\t\t\tepapr - \"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\t\tboth - Both \"linux,phandle\" and \"phandle\" properties\n");
fprintf(stderr, "\t-W [no-]<checkname>\n");
fprintf(stderr, "\t-E [no-]<checkname>\n");
fprintf(stderr, "\t\t\tenable or disable warnings and errors\n");
exit(3); exit(3);
} }
...@@ -113,7 +118,7 @@ int main(int argc, char *argv[]) ...@@ -113,7 +118,7 @@ int main(int argc, char *argv[])
minsize = 0; minsize = 0;
padsize = 0; padsize = 0;
while ((opt = getopt(argc, argv, "hI:O:o:V:d:R:S:p:fcqb:vH:s")) while ((opt = getopt(argc, argv, "hI:O:o:V:d:R:S:p:fqb:i:vH:sW:E:"))
!= EOF) { != EOF) {
switch (opt) { switch (opt) {
case 'I': case 'I':
...@@ -149,6 +154,9 @@ int main(int argc, char *argv[]) ...@@ -149,6 +154,9 @@ int main(int argc, char *argv[])
case 'b': case 'b':
cmdline_boot_cpuid = strtoll(optarg, NULL, 0); cmdline_boot_cpuid = strtoll(optarg, NULL, 0);
break; break;
case 'i':
srcfile_add_search_path(optarg);
break;
case 'v': case 'v':
printf("Version: %s\n", DTC_VERSION); printf("Version: %s\n", DTC_VERSION);
exit(0); exit(0);
...@@ -168,6 +176,14 @@ int main(int argc, char *argv[]) ...@@ -168,6 +176,14 @@ int main(int argc, char *argv[])
sort = 1; sort = 1;
break; break;
case 'W':
parse_checks_option(true, false, optarg);
break;
case 'E':
parse_checks_option(false, true, optarg);
break;
case 'h': case 'h':
default: default:
usage(); usage();
...@@ -188,9 +204,6 @@ int main(int argc, char *argv[]) ...@@ -188,9 +204,6 @@ int main(int argc, char *argv[])
if (minsize) if (minsize)
fprintf(stderr, "DTC: Use of \"-S\" is deprecated; it will be removed soon, use \"-p\" instead\n"); fprintf(stderr, "DTC: Use of \"-S\" is deprecated; it will be removed soon, use \"-p\" instead\n");
fprintf(stderr, "DTC: %s->%s on file \"%s\"\n",
inform, outform, arg);
if (depname) { if (depname) {
depfile = fopen(depname, "w"); depfile = fopen(depname, "w");
if (!depfile) if (!depfile)
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include <stdbool.h>
#include <stdarg.h> #include <stdarg.h>
#include <assert.h> #include <assert.h>
#include <ctype.h> #include <ctype.h>
...@@ -109,6 +110,7 @@ struct data data_insert_at_marker(struct data d, struct marker *m, ...@@ -109,6 +110,7 @@ struct data data_insert_at_marker(struct data d, struct marker *m,
const void *p, int len); const void *p, int len);
struct data data_merge(struct data d1, struct data d2); struct data data_merge(struct data d1, struct data d2);
struct data data_append_cell(struct data d, cell_t word); struct data data_append_cell(struct data d, cell_t word);
struct data data_append_integer(struct data d, uint64_t word, int bits);
struct data data_append_re(struct data d, const struct fdt_reserve_entry *re); struct data data_append_re(struct data d, const struct fdt_reserve_entry *re);
struct data data_append_addr(struct data d, uint64_t addr); struct data data_append_addr(struct data d, uint64_t addr);
struct data data_append_byte(struct data d, uint8_t byte); struct data data_append_byte(struct data d, uint8_t byte);
...@@ -126,11 +128,13 @@ int data_is_one_string(struct data d); ...@@ -126,11 +128,13 @@ int data_is_one_string(struct data d);
/* Live trees */ /* Live trees */
struct label { struct label {
int deleted;
char *label; char *label;
struct label *next; struct label *next;
}; };
struct property { struct property {
int deleted;
char *name; char *name;
struct data val; struct data val;
...@@ -140,6 +144,7 @@ struct property { ...@@ -140,6 +144,7 @@ struct property {
}; };
struct node { struct node {
int deleted;
char *name; char *name;
struct property *proplist; struct property *proplist;
struct node *children; struct node *children;
...@@ -156,28 +161,71 @@ struct node { ...@@ -156,28 +161,71 @@ struct node {
struct label *labels; struct label *labels;
}; };
static inline struct label *for_each_label_next(struct label *l)
{
do {
l = l->next;
} while (l && l->deleted);
return l;
}
#define for_each_label(l0, l) \ #define for_each_label(l0, l) \
for ((l) = (l0); (l); (l) = for_each_label_next(l))
#define for_each_label_withdel(l0, l) \
for ((l) = (l0); (l); (l) = (l)->next) for ((l) = (l0); (l); (l) = (l)->next)
static inline struct property *for_each_property_next(struct property *p)
{
do {
p = p->next;
} while (p && p->deleted);
return p;
}
#define for_each_property(n, p) \ #define for_each_property(n, p) \
for ((p) = (n)->proplist; (p); (p) = for_each_property_next(p))
#define for_each_property_withdel(n, p) \
for ((p) = (n)->proplist; (p); (p) = (p)->next) for ((p) = (n)->proplist; (p); (p) = (p)->next)
static inline struct node *for_each_child_next(struct node *c)
{
do {
c = c->next_sibling;
} while (c && c->deleted);
return c;
}
#define for_each_child(n, c) \ #define for_each_child(n, c) \
for ((c) = (n)->children; (c); (c) = for_each_child_next(c))
#define for_each_child_withdel(n, c) \
for ((c) = (n)->children; (c); (c) = (c)->next_sibling) for ((c) = (n)->children; (c); (c) = (c)->next_sibling)
void add_label(struct label **labels, char *label); 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(char *name, struct data val);
struct property *build_property_delete(char *name);
struct property *chain_property(struct property *first, struct property *list); struct property *chain_property(struct property *first, struct property *list);
struct property *reverse_properties(struct property *first); struct property *reverse_properties(struct property *first);
struct node *build_node(struct property *proplist, struct node *children); 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 *name_node(struct node *node, char *name);
struct node *chain_node(struct node *first, struct node *list); struct node *chain_node(struct node *first, struct node *list);
struct node *merge_nodes(struct node *old_node, struct node *new_node); struct node *merge_nodes(struct node *old_node, struct node *new_node);
void add_property(struct node *node, struct property *prop); 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 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); const char *get_unitname(struct node *node);
struct property *get_property(struct node *node, const char *propname); struct property *get_property(struct node *node, const char *propname);
...@@ -224,6 +272,7 @@ void sort_tree(struct boot_info *bi); ...@@ -224,6 +272,7 @@ void sort_tree(struct boot_info *bi);
/* Checks */ /* Checks */
void parse_checks_option(bool warn, bool error, const char *optarg);
void process_checks(int force, struct boot_info *bi); void process_checks(int force, struct boot_info *bi);
/* Flattened trees */ /* Flattened trees */
......
/*
* fdtdump.c - Contributed by Pantelis Antoniou <pantelis.antoniou AT gmail.com>
*/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <fdt.h>
#include <libfdt_env.h>
#include "util.h"
#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
#define PALIGN(p, a) ((void *)(ALIGN((unsigned long)(p), (a))))
#define GET_CELL(p) (p += 4, *((const uint32_t *)(p-4)))
static void print_data(const char *data, int len)
{
int i;
const char *p = data;
/* no data, don't print */
if (len == 0)
return;
if (util_is_printable_string(data, len)) {
printf(" = \"%s\"", (const char *)data);
} else if ((len % 4) == 0) {
printf(" = <");
for (i = 0; i < len; i += 4)
printf("0x%08x%s", fdt32_to_cpu(GET_CELL(p)),
i < (len - 4) ? " " : "");
printf(">");
} else {
printf(" = [");
for (i = 0; i < len; i++)
printf("%02x%s", *p++, i < len - 1 ? " " : "");
printf("]");
}
}
static void dump_blob(void *blob)
{
struct fdt_header *bph = blob;
uint32_t off_mem_rsvmap = fdt32_to_cpu(bph->off_mem_rsvmap);
uint32_t off_dt = fdt32_to_cpu(bph->off_dt_struct);
uint32_t off_str = fdt32_to_cpu(bph->off_dt_strings);
struct fdt_reserve_entry *p_rsvmap =
(struct fdt_reserve_entry *)((char *)blob + off_mem_rsvmap);
const char *p_struct = (const char *)blob + off_dt;
const char *p_strings = (const char *)blob + off_str;
uint32_t version = fdt32_to_cpu(bph->version);
uint32_t totalsize = fdt32_to_cpu(bph->totalsize);
uint32_t tag;
const char *p, *s, *t;
int depth, sz, shift;
int i;
uint64_t addr, size;
depth = 0;
shift = 4;
printf("/dts-v1/;\n");
printf("// magic:\t\t0x%x\n", fdt32_to_cpu(bph->magic));
printf("// totalsize:\t\t0x%x (%d)\n", totalsize, totalsize);
printf("// off_dt_struct:\t0x%x\n", off_dt);
printf("// off_dt_strings:\t0x%x\n", off_str);
printf("// off_mem_rsvmap:\t0x%x\n", off_mem_rsvmap);
printf("// version:\t\t%d\n", version);
printf("// last_comp_version:\t%d\n",
fdt32_to_cpu(bph->last_comp_version));
if (version >= 2)
printf("// boot_cpuid_phys:\t0x%x\n",
fdt32_to_cpu(bph->boot_cpuid_phys));
if (version >= 3)
printf("// size_dt_strings:\t0x%x\n",
fdt32_to_cpu(bph->size_dt_strings));
if (version >= 17)
printf("// size_dt_struct:\t0x%x\n",
fdt32_to_cpu(bph->size_dt_struct));
printf("\n");
for (i = 0; ; i++) {
addr = fdt64_to_cpu(p_rsvmap[i].address);
size = fdt64_to_cpu(p_rsvmap[i].size);
if (addr == 0 && size == 0)
break;
printf("/memreserve/ %llx %llx;\n",
(unsigned long long)addr, (unsigned long long)size);
}
p = p_struct;
while ((tag = fdt32_to_cpu(GET_CELL(p))) != FDT_END) {
/* printf("tag: 0x%08x (%d)\n", tag, p - p_struct); */
if (tag == FDT_BEGIN_NODE) {
s = p;
p = PALIGN(p + strlen(s) + 1, 4);
if (*s == '\0')
s = "/";
printf("%*s%s {\n", depth * shift, "", s);
depth++;
continue;
}
if (tag == FDT_END_NODE) {
depth--;
printf("%*s};\n", depth * shift, "");
continue;
}
if (tag == FDT_NOP) {
printf("%*s// [NOP]\n", depth * shift, "");
continue;
}
if (tag != FDT_PROP) {
fprintf(stderr, "%*s ** Unknown tag 0x%08x\n", depth * shift, "", tag);
break;
}
sz = fdt32_to_cpu(GET_CELL(p));
s = p_strings + fdt32_to_cpu(GET_CELL(p));
if (version < 16 && sz >= 8)
p = PALIGN(p, 8);
t = p;
p = PALIGN(p + sz, 4);
printf("%*s%s", depth * shift, "", s);
print_data(t, sz);
printf(";\n");
}
}
int main(int argc, char *argv[])
{
char *buf;
if (argc < 2) {
fprintf(stderr, "supply input filename\n");
return 5;
}
buf = utilfdt_read(argv[1]);
if (buf)
dump_blob(buf);
else
return 10;
return 0;
}
/*
* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
*
* Portions from U-Boot cmd_fdt.c (C) Copyright 2007
* Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com
* Based on code written by:
* Pantelis Antoniou <pantelis.antoniou@gmail.com> and
* Matthew McClintock <msm@freescale.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <assert.h>
#include <ctype.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libfdt.h>
#include "util.h"
enum display_mode {
MODE_SHOW_VALUE, /* show values for node properties */
MODE_LIST_PROPS, /* list the properties for a node */
MODE_LIST_SUBNODES, /* list the subnodes of a node */
};
/* Holds information which controls our output and options */
struct display_info {
int type; /* data type (s/i/u/x or 0 for default) */
int size; /* data size (1/2/4) */
enum display_mode mode; /* display mode that we are using */
const char *default_val; /* default value if node/property not found */
};
static void report_error(const char *where, int err)
{
fprintf(stderr, "Error at '%s': %s\n", where, fdt_strerror(err));
}
/**
* Displays data of a given length according to selected options
*
* If a specific data type is provided in disp, then this is used. Otherwise
* we try to guess the data type / size from the contents.
*
* @param disp Display information / options
* @param data Data to display
* @param len Maximum length of buffer
* @return 0 if ok, -1 if data does not match format
*/
static int show_data(struct display_info *disp, const char *data, int len)
{
int i, size;
const uint8_t *p = (const uint8_t *)data;
const char *s;
int value;
int is_string;
char fmt[3];
/* no data, don't print */
if (len == 0)
return 0;
is_string = (disp->type) == 's' ||
(!disp->type && util_is_printable_string(data, len));
if (is_string) {
if (data[len - 1] != '\0') {
fprintf(stderr, "Unterminated string\n");
return -1;
}
for (s = data; s - data < len; s += strlen(s) + 1) {
if (s != data)
printf(" ");
printf("%s", (const char *)s);
}
return 0;
}
size = disp->size;
if (size == -1) {
size = (len % 4) == 0 ? 4 : 1;
} else if (len % size) {
fprintf(stderr, "Property length must be a multiple of "
"selected data size\n");
return -1;
}
fmt[0] = '%';
fmt[1] = disp->type ? disp->type : 'd';
fmt[2] = '\0';
for (i = 0; i < len; i += size, p += size) {
if (i)
printf(" ");
value = size == 4 ? fdt32_to_cpu(*(const uint32_t *)p) :
size == 2 ? (*p << 8) | p[1] : *p;
printf(fmt, value);
}
return 0;
}
/**
* List all properties in a node, one per line.
*
* @param blob FDT blob
* @param node Node to display
* @return 0 if ok, or FDT_ERR... if not.
*/
static int list_properties(const void *blob, int node)
{
const struct fdt_property *data;
const char *name;
int prop;
prop = fdt_first_property_offset(blob, node);
do {
/* Stop silently when there are no more properties */
if (prop < 0)
return prop == -FDT_ERR_NOTFOUND ? 0 : prop;
data = fdt_get_property_by_offset(blob, prop, NULL);
name = fdt_string(blob, fdt32_to_cpu(data->nameoff));
if (name)
puts(name);
prop = fdt_next_property_offset(blob, prop);
} while (1);
}
#define MAX_LEVEL 32 /* how deeply nested we will go */
/**
* List all subnodes in a node, one per line
*
* @param blob FDT blob
* @param node Node to display
* @return 0 if ok, or FDT_ERR... if not.
*/
static int list_subnodes(const void *blob, int node)
{
int nextoffset; /* next node offset from libfdt */
uint32_t tag; /* current tag */
int level = 0; /* keep track of nesting level */
const char *pathp;
int depth = 1; /* the assumed depth of this node */
while (level >= 0) {
tag = fdt_next_tag(blob, node, &nextoffset);
switch (tag) {
case FDT_BEGIN_NODE:
pathp = fdt_get_name(blob, node, NULL);
if (level <= depth) {
if (pathp == NULL)
pathp = "/* NULL pointer error */";
if (*pathp == '\0')
pathp = "/"; /* root is nameless */
if (level == 1)
puts(pathp);
}
level++;
if (level >= MAX_LEVEL) {
printf("Nested too deep, aborting.\n");
return 1;
}
break;
case FDT_END_NODE:
level--;
if (level == 0)
level = -1; /* exit the loop */
break;
case FDT_END:
return 1;
case FDT_PROP:
break;
default:
if (level <= depth)
printf("Unknown tag 0x%08X\n", tag);
return 1;
}
node = nextoffset;
}
return 0;
}
/**
* Show the data for a given node (and perhaps property) according to the
* display option provided.
*
* @param blob FDT blob
* @param disp Display information / options
* @param node Node to display
* @param property Name of property to display, or NULL if none
* @return 0 if ok, -ve on error
*/
static int show_data_for_item(const void *blob, struct display_info *disp,
int node, const char *property)
{
const void *value = NULL;
int len, err = 0;
switch (disp->mode) {
case MODE_LIST_PROPS:
err = list_properties(blob, node);
break;
case MODE_LIST_SUBNODES:
err = list_subnodes(blob, node);
break;
default:
assert(property);
value = fdt_getprop(blob, node, property, &len);
if (value) {
if (show_data(disp, value, len))
err = -1;
else
printf("\n");
} else if (disp->default_val) {
puts(disp->default_val);
} else {
report_error(property, len);
err = -1;
}
break;
}
return err;
}
/**
* Run the main fdtget operation, given a filename and valid arguments
*
* @param disp Display information / options
* @param filename Filename of blob file
* @param arg List of arguments to process
* @param arg_count Number of arguments
* @param return 0 if ok, -ve on error
*/
static int do_fdtget(struct display_info *disp, const char *filename,
char **arg, int arg_count, int args_per_step)
{
char *blob;
const char *prop;
int i, node;
blob = utilfdt_read(filename);
if (!blob)
return -1;
for (i = 0; i + args_per_step <= arg_count; i += args_per_step) {
node = fdt_path_offset(blob, arg[i]);
if (node < 0) {
if (disp->default_val) {
puts(disp->default_val);
continue;
} else {
report_error(arg[i], node);
return -1;
}
}
prop = args_per_step == 1 ? NULL : arg[i + 1];
if (show_data_for_item(blob, disp, node, prop))
return -1;
}
return 0;
}
static const char *usage_msg =
"fdtget - read values from device tree\n"
"\n"
"Each value is printed on a new line.\n\n"
"Usage:\n"
" fdtget <options> <dt file> [<node> <property>]...\n"
" fdtget -p <options> <dt file> [<node> ]...\n"
"Options:\n"
"\t-t <type>\tType of data\n"
"\t-p\t\tList properties for each node\n"
"\t-l\t\tList subnodes for each node\n"
"\t-d\t\tDefault value to display when the property is "
"missing\n"
"\t-h\t\tPrint this help\n\n"
USAGE_TYPE_MSG;
static void usage(const char *msg)
{
if (msg)
fprintf(stderr, "Error: %s\n\n", msg);
fprintf(stderr, "%s", usage_msg);
exit(2);
}
int main(int argc, char *argv[])
{
char *filename = NULL;
struct display_info disp;
int args_per_step = 2;
/* set defaults */
memset(&disp, '\0', sizeof(disp));
disp.size = -1;
disp.mode = MODE_SHOW_VALUE;
for (;;) {
int c = getopt(argc, argv, "d:hlpt:");
if (c == -1)
break;
switch (c) {
case 'h':
case '?':
usage(NULL);
case 't':
if (utilfdt_decode_type(optarg, &disp.type,
&disp.size))
usage("Invalid type string");
break;
case 'p':
disp.mode = MODE_LIST_PROPS;
args_per_step = 1;
break;
case 'l':
disp.mode = MODE_LIST_SUBNODES;
args_per_step = 1;
break;
case 'd':
disp.default_val = optarg;
break;
}
}
if (optind < argc)
filename = argv[optind++];
if (!filename)
usage("Missing filename");
argv += optind;
argc -= optind;
/* Allow no arguments, and silently succeed */
if (!argc)
return 0;
/* Check for node, property arguments */
if (args_per_step == 2 && (argc % 2))
usage("Must have an even number of arguments");
if (do_fdtget(&disp, filename, argv, argc, args_per_step))
return 1;
return 0;
}
/*
* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <assert.h>
#include <ctype.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libfdt.h>
#include "util.h"
/* These are the operations we support */
enum oper_type {
OPER_WRITE_PROP, /* Write a property in a node */
OPER_CREATE_NODE, /* Create a new node */
};
struct display_info {
enum oper_type oper; /* operation to perform */
int type; /* data type (s/i/u/x or 0 for default) */
int size; /* data size (1/2/4) */
int verbose; /* verbose output */
int auto_path; /* automatically create all path components */
};
/**
* Report an error with a particular node.
*
* @param name Node name to report error on
* @param namelen Length of node name, or -1 to use entire string
* @param err Error number to report (-FDT_ERR_...)
*/
static void report_error(const char *name, int namelen, int err)
{
if (namelen == -1)
namelen = strlen(name);
fprintf(stderr, "Error at '%1.*s': %s\n", namelen, name,
fdt_strerror(err));
}
/**
* Encode a series of arguments in a property value.
*
* @param disp Display information / options
* @param arg List of arguments from command line
* @param arg_count Number of arguments (may be 0)
* @param valuep Returns buffer containing value
* @param *value_len Returns length of value encoded
*/
static int encode_value(struct display_info *disp, char **arg, int arg_count,
char **valuep, int *value_len)
{
char *value = NULL; /* holding area for value */
int value_size = 0; /* size of holding area */
char *ptr; /* pointer to current value position */
int len; /* length of this cell/string/byte */
int ival;
int upto; /* the number of bytes we have written to buf */
char fmt[3];
upto = 0;
if (disp->verbose)
fprintf(stderr, "Decoding value:\n");
fmt[0] = '%';
fmt[1] = disp->type ? disp->type : 'd';
fmt[2] = '\0';
for (; arg_count > 0; arg++, arg_count--, upto += len) {
/* assume integer unless told otherwise */
if (disp->type == 's')
len = strlen(*arg) + 1;
else
len = disp->size == -1 ? 4 : disp->size;
/* enlarge our value buffer by a suitable margin if needed */
if (upto + len > value_size) {
value_size = (upto + len) + 500;
value = realloc(value, value_size);
if (!value) {
fprintf(stderr, "Out of mmory: cannot alloc "
"%d bytes\n", value_size);
return -1;
}
}
ptr = value + upto;
if (disp->type == 's') {
memcpy(ptr, *arg, len);
if (disp->verbose)
fprintf(stderr, "\tstring: '%s'\n", ptr);
} else {
int *iptr = (int *)ptr;
sscanf(*arg, fmt, &ival);
if (len == 4)
*iptr = cpu_to_fdt32(ival);
else
*ptr = (uint8_t)ival;
if (disp->verbose) {
fprintf(stderr, "\t%s: %d\n",
disp->size == 1 ? "byte" :
disp->size == 2 ? "short" : "int",
ival);
}
}
}
*value_len = upto;
*valuep = value;
if (disp->verbose)
fprintf(stderr, "Value size %d\n", upto);
return 0;
}
static int store_key_value(void *blob, const char *node_name,
const char *property, const char *buf, int len)
{
int node;
int err;
node = fdt_path_offset(blob, node_name);
if (node < 0) {
report_error(node_name, -1, node);
return -1;
}
err = fdt_setprop(blob, node, property, buf, len);
if (err) {
report_error(property, -1, err);
return -1;
}
return 0;
}
/**
* Create paths as needed for all components of a path
*
* Any components of the path that do not exist are created. Errors are
* reported.
*
* @param blob FDT blob to write into
* @param in_path Path to process
* @return 0 if ok, -1 on error
*/
static int create_paths(void *blob, const char *in_path)
{
const char *path = in_path;
const char *sep;
int node, offset = 0;
/* skip leading '/' */
while (*path == '/')
path++;
for (sep = path; *sep; path = sep + 1, offset = node) {
/* equivalent to strchrnul(), but it requires _GNU_SOURCE */
sep = strchr(path, '/');
if (!sep)
sep = path + strlen(path);
node = fdt_subnode_offset_namelen(blob, offset, path,
sep - path);
if (node == -FDT_ERR_NOTFOUND) {
node = fdt_add_subnode_namelen(blob, offset, path,
sep - path);
}
if (node < 0) {
report_error(path, sep - path, node);
return -1;
}
}
return 0;
}
/**
* Create a new node in the fdt.
*
* This will overwrite the node_name string. Any error is reported.
*
* TODO: Perhaps create fdt_path_offset_namelen() so we don't need to do this.
*
* @param blob FDT blob to write into
* @param node_name Name of node to create
* @return new node offset if found, or -1 on failure
*/
static int create_node(void *blob, const char *node_name)
{
int node = 0;
char *p;
p = strrchr(node_name, '/');
if (!p) {
report_error(node_name, -1, -FDT_ERR_BADPATH);
return -1;
}
*p = '\0';
if (p > node_name) {
node = fdt_path_offset(blob, node_name);
if (node < 0) {
report_error(node_name, -1, node);
return -1;
}
}
node = fdt_add_subnode(blob, node, p + 1);
if (node < 0) {
report_error(p + 1, -1, node);
return -1;
}
return 0;
}
static int do_fdtput(struct display_info *disp, const char *filename,
char **arg, int arg_count)
{
char *value;
char *blob;
int len, ret = 0;
blob = utilfdt_read(filename);
if (!blob)
return -1;
switch (disp->oper) {
case OPER_WRITE_PROP:
/*
* Convert the arguments into a single binary value, then
* store them into the property.
*/
assert(arg_count >= 2);
if (disp->auto_path && create_paths(blob, *arg))
return -1;
if (encode_value(disp, arg + 2, arg_count - 2, &value, &len) ||
store_key_value(blob, *arg, arg[1], value, len))
ret = -1;
break;
case OPER_CREATE_NODE:
for (; ret >= 0 && arg_count--; arg++) {
if (disp->auto_path)
ret = create_paths(blob, *arg);
else
ret = create_node(blob, *arg);
}
break;
}
if (ret >= 0)
ret = utilfdt_write(filename, blob);
free(blob);
return ret;
}
static const char *usage_msg =
"fdtput - write a property value to a device tree\n"
"\n"
"The command line arguments are joined together into a single value.\n"
"\n"
"Usage:\n"
" fdtput <options> <dt file> <node> <property> [<value>...]\n"
" fdtput -c <options> <dt file> [<node>...]\n"
"Options:\n"
"\t-c\t\tCreate nodes if they don't already exist\n"
"\t-p\t\tAutomatically create nodes as needed for the node path\n"
"\t-t <type>\tType of data\n"
"\t-v\t\tVerbose: display each value decoded from command line\n"
"\t-h\t\tPrint this help\n\n"
USAGE_TYPE_MSG;
static void usage(const char *msg)
{
if (msg)
fprintf(stderr, "Error: %s\n\n", msg);
fprintf(stderr, "%s", usage_msg);
exit(2);
}
int main(int argc, char *argv[])
{
struct display_info disp;
char *filename = NULL;
memset(&disp, '\0', sizeof(disp));
disp.size = -1;
disp.oper = OPER_WRITE_PROP;
for (;;) {
int c = getopt(argc, argv, "chpt:v");
if (c == -1)
break;
/*
* TODO: add options to:
* - delete property
* - delete node (optionally recursively)
* - rename node
* - pack fdt before writing
* - set amount of free space when writing
* - expand fdt if value doesn't fit
*/
switch (c) {
case 'c':
disp.oper = OPER_CREATE_NODE;
break;
case 'h':
case '?':
usage(NULL);
case 'p':
disp.auto_path = 1;
break;
case 't':
if (utilfdt_decode_type(optarg, &disp.type,
&disp.size))
usage("Invalid type string");
break;
case 'v':
disp.verbose = 1;
break;
}
}
if (optind < argc)
filename = argv[optind++];
if (!filename)
usage("Missing filename");
argv += optind;
argc -= optind;
if (disp.oper == OPER_WRITE_PROP) {
if (argc < 1)
usage("Missing node");
if (argc < 2)
usage("Missing property");
}
if (do_fdtput(&disp, filename, argv, argc))
return 1;
return 0;
}
...@@ -263,6 +263,9 @@ static void flatten_tree(struct node *tree, struct emitter *emit, ...@@ -263,6 +263,9 @@ static void flatten_tree(struct node *tree, struct emitter *emit,
struct node *child; struct node *child;
int seen_name_prop = 0; int seen_name_prop = 0;
if (tree->deleted)
return;
emit->beginnode(etarget, tree->labels); emit->beginnode(etarget, tree->labels);
if (vi->flags & FTF_FULLPATH) if (vi->flags & FTF_FULLPATH)
......
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
# This is not a complete Makefile of itself. Instead, it is designed to # This is not a complete Makefile of itself. Instead, it is designed to
# be easily embeddable into other systems of Makefiles. # be easily embeddable into other systems of Makefiles.
# #
LIBFDT_INCLUDES = fdt.h libfdt.h LIBFDT_soname = libfdt.$(SHAREDLIB_EXT).1
LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c 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) LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o)
...@@ -74,7 +74,7 @@ int fdt_check_header(const void *fdt) ...@@ -74,7 +74,7 @@ int fdt_check_header(const void *fdt)
return 0; return 0;
} }
const void *fdt_offset_ptr(const void *fdt, int offset, int len) const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
{ {
const char *p; const char *p;
...@@ -90,42 +90,53 @@ const void *fdt_offset_ptr(const void *fdt, int offset, int len) ...@@ -90,42 +90,53 @@ const void *fdt_offset_ptr(const void *fdt, int offset, int len)
return p; return p;
} }
uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset) uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
{ {
const uint32_t *tagp, *lenp; const uint32_t *tagp, *lenp;
uint32_t tag; uint32_t tag;
int offset = startoffset;
const char *p; const char *p;
if (offset % FDT_TAGSIZE) *nextoffset = -FDT_ERR_TRUNCATED;
return -1;
tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE); tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
if (! tagp) if (!tagp)
return FDT_END; /* premature end */ return FDT_END; /* premature end */
tag = fdt32_to_cpu(*tagp); tag = fdt32_to_cpu(*tagp);
offset += FDT_TAGSIZE; offset += FDT_TAGSIZE;
*nextoffset = -FDT_ERR_BADSTRUCTURE;
switch (tag) { switch (tag) {
case FDT_BEGIN_NODE: case FDT_BEGIN_NODE:
/* skip name */ /* skip name */
do { do {
p = fdt_offset_ptr(fdt, offset++, 1); p = fdt_offset_ptr(fdt, offset++, 1);
} while (p && (*p != '\0')); } while (p && (*p != '\0'));
if (! p) if (!p)
return FDT_END; return FDT_END; /* premature end */
break; break;
case FDT_PROP: case FDT_PROP:
lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp)); lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
if (! lenp) if (!lenp)
return FDT_END; return FDT_END; /* premature end */
/* skip name offset, length and value */ /* skip-name offset, length and value */
offset += 2*FDT_TAGSIZE + fdt32_to_cpu(*lenp); offset += sizeof(struct fdt_property) - FDT_TAGSIZE
+ fdt32_to_cpu(*lenp);
break; break;
case FDT_END:
case FDT_END_NODE:
case FDT_NOP:
break;
default:
return FDT_END;
} }
if (nextoffset) if (!fdt_offset_ptr(fdt, startoffset, offset - startoffset))
*nextoffset = FDT_TAGALIGN(offset); return FDT_END; /* premature end */
*nextoffset = FDT_TAGALIGN(offset);
return tag; return tag;
} }
...@@ -138,6 +149,15 @@ int _fdt_check_node_offset(const void *fdt, int offset) ...@@ -138,6 +149,15 @@ int _fdt_check_node_offset(const void *fdt, int offset)
return offset; return offset;
} }
int _fdt_check_prop_offset(const void *fdt, int offset)
{
if ((offset < 0) || (offset % FDT_TAGSIZE)
|| (fdt_next_tag(fdt, offset, &offset) != FDT_PROP))
return -FDT_ERR_BADOFFSET;
return offset;
}
int fdt_next_node(const void *fdt, int offset, int *depth) int fdt_next_node(const void *fdt, int offset, int *depth)
{ {
int nextoffset = 0; int nextoffset = 0;
...@@ -162,15 +182,16 @@ int fdt_next_node(const void *fdt, int offset, int *depth) ...@@ -162,15 +182,16 @@ int fdt_next_node(const void *fdt, int offset, int *depth)
break; break;
case FDT_END_NODE: case FDT_END_NODE:
if (depth) if (depth && ((--(*depth)) < 0))
(*depth)--; return nextoffset;
break; break;
case FDT_END: case FDT_END:
if ((nextoffset >= 0)
|| ((nextoffset == -FDT_ERR_TRUNCATED) && !depth))
return -FDT_ERR_NOTFOUND; return -FDT_ERR_NOTFOUND;
else
default: return nextoffset;
return -FDT_ERR_BADSTRUCTURE;
} }
} while (tag != FDT_BEGIN_NODE); } while (tag != FDT_BEGIN_NODE);
......
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2012 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libfdt_env.h"
#include <fdt.h>
#include <libfdt.h>
#include "libfdt_internal.h"
int fdt_create_empty_tree(void *buf, int bufsize)
{
int err;
err = fdt_create(buf, bufsize);
if (err)
return err;
err = fdt_finish_reservemap(buf);
if (err)
return err;
err = fdt_begin_node(buf, "");
if (err)
return err;
err = fdt_end_node(buf);
if (err)
return err;
err = fdt_finish(buf);
if (err)
return err;
return fdt_open_into(buf, buf, bufsize);
}
...@@ -80,6 +80,14 @@ const char *fdt_string(const void *fdt, int stroffset) ...@@ -80,6 +80,14 @@ const char *fdt_string(const void *fdt, int stroffset)
return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset; return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
} }
static int _fdt_string_eq(const void *fdt, int stroffset,
const char *s, int len)
{
const char *p = fdt_string(fdt, stroffset);
return (strlen(p) == len) && (memcmp(p, s, len) == 0);
}
int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
{ {
FDT_CHECK_HEADER(fdt); FDT_CHECK_HEADER(fdt);
...@@ -97,6 +105,30 @@ int fdt_num_mem_rsv(const void *fdt) ...@@ -97,6 +105,30 @@ int fdt_num_mem_rsv(const void *fdt)
return i; return i;
} }
static int _nextprop(const void *fdt, int offset)
{
uint32_t tag;
int nextoffset;
do {
tag = fdt_next_tag(fdt, offset, &nextoffset);
switch (tag) {
case FDT_END:
if (nextoffset >= 0)
return -FDT_ERR_BADSTRUCTURE;
else
return nextoffset;
case FDT_PROP:
return offset;
}
offset = nextoffset;
} while (tag == FDT_NOP);
return -FDT_ERR_NOTFOUND;
}
int fdt_subnode_offset_namelen(const void *fdt, int offset, int fdt_subnode_offset_namelen(const void *fdt, int offset,
const char *name, int namelen) const char *name, int namelen)
{ {
...@@ -104,20 +136,16 @@ int fdt_subnode_offset_namelen(const void *fdt, int offset, ...@@ -104,20 +136,16 @@ int fdt_subnode_offset_namelen(const void *fdt, int offset,
FDT_CHECK_HEADER(fdt); FDT_CHECK_HEADER(fdt);
for (depth = 0, offset = fdt_next_node(fdt, offset, &depth); for (depth = 0;
(offset >= 0) && (depth > 0); (offset >= 0) && (depth >= 0);
offset = fdt_next_node(fdt, offset, &depth)) { offset = fdt_next_node(fdt, offset, &depth))
if (depth < 0) if ((depth == 1)
return -FDT_ERR_NOTFOUND;
else if ((depth == 1)
&& _fdt_nodename_eq(fdt, offset, name, namelen)) && _fdt_nodename_eq(fdt, offset, name, namelen))
return offset; return offset;
}
if (offset < 0) if (depth < 0)
return offset; /* error */
else
return -FDT_ERR_NOTFOUND; return -FDT_ERR_NOTFOUND;
return offset; /* error */
} }
int fdt_subnode_offset(const void *fdt, int parentoffset, int fdt_subnode_offset(const void *fdt, int parentoffset,
...@@ -134,8 +162,20 @@ int fdt_path_offset(const void *fdt, const char *path) ...@@ -134,8 +162,20 @@ int fdt_path_offset(const void *fdt, const char *path)
FDT_CHECK_HEADER(fdt); FDT_CHECK_HEADER(fdt);
if (*path != '/') /* see if we have an alias */
if (*path != '/') {
const char *q = strchr(path, '/');
if (!q)
q = end;
p = fdt_get_alias_namelen(fdt, p, q - p);
if (!p)
return -FDT_ERR_BADPATH; return -FDT_ERR_BADPATH;
offset = fdt_path_offset(fdt, p);
p = q;
}
while (*p) { while (*p) {
const char *q; const char *q;
...@@ -178,93 +218,142 @@ const char *fdt_get_name(const void *fdt, int nodeoffset, int *len) ...@@ -178,93 +218,142 @@ const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
return NULL; return NULL;
} }
const struct fdt_property *fdt_get_property(const void *fdt, int fdt_first_property_offset(const void *fdt, int nodeoffset)
int nodeoffset,
const char *name, int *lenp)
{ {
uint32_t tag; int offset;
const struct fdt_property *prop;
int namestroff;
int offset, nextoffset;
int err;
if (((err = fdt_check_header(fdt)) != 0) if ((offset = _fdt_check_node_offset(fdt, nodeoffset)) < 0)
|| ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0)) return offset;
goto fail;
nextoffset = err; return _nextprop(fdt, offset);
do { }
offset = nextoffset;
tag = fdt_next_tag(fdt, offset, &nextoffset); int fdt_next_property_offset(const void *fdt, int offset)
switch (tag) { {
case FDT_END: if ((offset = _fdt_check_prop_offset(fdt, offset)) < 0)
err = -FDT_ERR_TRUNCATED; return offset;
goto fail;
case FDT_BEGIN_NODE: return _nextprop(fdt, offset);
case FDT_END_NODE: }
case FDT_NOP:
break;
case FDT_PROP: const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
err = -FDT_ERR_BADSTRUCTURE; int offset,
prop = fdt_offset_ptr(fdt, offset, sizeof(*prop)); int *lenp)
if (! prop) {
goto fail; int err;
namestroff = fdt32_to_cpu(prop->nameoff); const struct fdt_property *prop;
if (strcmp(fdt_string(fdt, namestroff), name) == 0) {
/* Found it! */
int len = fdt32_to_cpu(prop->len);
prop = fdt_offset_ptr(fdt, offset,
sizeof(*prop)+len);
if (! prop)
goto fail;
if ((err = _fdt_check_prop_offset(fdt, offset)) < 0) {
if (lenp) if (lenp)
*lenp = len; *lenp = err;
return NULL;
}
prop = _fdt_offset_ptr(fdt, offset);
if (lenp)
*lenp = fdt32_to_cpu(prop->len);
return prop; return prop;
} }
break;
default: const struct fdt_property *fdt_get_property_namelen(const void *fdt,
err = -FDT_ERR_BADSTRUCTURE; int offset,
goto fail; const char *name,
int namelen, int *lenp)
{
for (offset = fdt_first_property_offset(fdt, offset);
(offset >= 0);
(offset = fdt_next_property_offset(fdt, offset))) {
const struct fdt_property *prop;
if (!(prop = fdt_get_property_by_offset(fdt, offset, lenp))) {
offset = -FDT_ERR_INTERNAL;
break;
}
if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff),
name, namelen))
return prop;
} }
} while ((tag != FDT_BEGIN_NODE) && (tag != FDT_END_NODE));
err = -FDT_ERR_NOTFOUND;
fail:
if (lenp) if (lenp)
*lenp = err; *lenp = offset;
return NULL; return NULL;
} }
const void *fdt_getprop(const void *fdt, int nodeoffset, const struct fdt_property *fdt_get_property(const void *fdt,
int nodeoffset,
const char *name, int *lenp) const char *name, int *lenp)
{
return fdt_get_property_namelen(fdt, nodeoffset, name,
strlen(name), lenp);
}
const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
const char *name, int namelen, int *lenp)
{ {
const struct fdt_property *prop; const struct fdt_property *prop;
prop = fdt_get_property(fdt, nodeoffset, name, lenp); prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp);
if (! prop) if (! prop)
return NULL; return NULL;
return prop->data; return prop->data;
} }
const void *fdt_getprop_by_offset(const void *fdt, int offset,
const char **namep, int *lenp)
{
const struct fdt_property *prop;
prop = fdt_get_property_by_offset(fdt, offset, lenp);
if (!prop)
return NULL;
if (namep)
*namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
return prop->data;
}
const void *fdt_getprop(const void *fdt, int nodeoffset,
const char *name, int *lenp)
{
return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp);
}
uint32_t fdt_get_phandle(const void *fdt, int nodeoffset) uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
{ {
const uint32_t *php; const uint32_t *php;
int len; int len;
/* FIXME: This is a bit sub-optimal, since we potentially scan
* over all the properties twice. */
php = fdt_getprop(fdt, nodeoffset, "phandle", &len);
if (!php || (len != sizeof(*php))) {
php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len); php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len);
if (!php || (len != sizeof(*php))) if (!php || (len != sizeof(*php)))
return 0; return 0;
}
return fdt32_to_cpu(*php); return fdt32_to_cpu(*php);
} }
const char *fdt_get_alias_namelen(const void *fdt,
const char *name, int namelen)
{
int aliasoffset;
aliasoffset = fdt_path_offset(fdt, "/aliases");
if (aliasoffset < 0)
return NULL;
return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL);
}
const char *fdt_get_alias(const void *fdt, const char *name)
{
return fdt_get_alias_namelen(fdt, name, strlen(name));
}
int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
{ {
int pdepth = 0, p = 0; int pdepth = 0, p = 0;
...@@ -279,9 +368,6 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) ...@@ -279,9 +368,6 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
for (offset = 0, depth = 0; for (offset = 0, depth = 0;
(offset >= 0) && (offset <= nodeoffset); (offset >= 0) && (offset <= nodeoffset);
offset = fdt_next_node(fdt, offset, &depth)) { offset = fdt_next_node(fdt, offset, &depth)) {
if (pdepth < depth)
continue; /* overflowed buffer */
while (pdepth > depth) { while (pdepth > depth) {
do { do {
p--; p--;
...@@ -289,6 +375,7 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) ...@@ -289,6 +375,7 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
pdepth--; pdepth--;
} }
if (pdepth >= depth) {
name = fdt_get_name(fdt, offset, &namelen); name = fdt_get_name(fdt, offset, &namelen);
if (!name) if (!name)
return namelen; return namelen;
...@@ -298,6 +385,7 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) ...@@ -298,6 +385,7 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
buf[p++] = '/'; buf[p++] = '/';
pdepth++; pdepth++;
} }
}
if (offset == nodeoffset) { if (offset == nodeoffset) {
if (pdepth < (depth + 1)) if (pdepth < (depth + 1))
...@@ -306,7 +394,7 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) ...@@ -306,7 +394,7 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
if (p > 1) /* special case so that root path is "/", not "" */ if (p > 1) /* special case so that root path is "/", not "" */
p--; p--;
buf[p] = '\0'; buf[p] = '\0';
return p; return 0;
} }
} }
...@@ -404,14 +492,31 @@ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, ...@@ -404,14 +492,31 @@ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle) int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
{ {
int offset;
if ((phandle == 0) || (phandle == -1)) if ((phandle == 0) || (phandle == -1))
return -FDT_ERR_BADPHANDLE; return -FDT_ERR_BADPHANDLE;
phandle = cpu_to_fdt32(phandle);
return fdt_node_offset_by_prop_value(fdt, -1, "linux,phandle", FDT_CHECK_HEADER(fdt);
&phandle, sizeof(phandle));
/* FIXME: The algorithm here is pretty horrible: we
* potentially scan each property of a node in
* fdt_get_phandle(), then if that didn't find what
* we want, we scan over them again making our way to the next
* node. Still it's the easiest to implement approach;
* performance can come later. */
for (offset = fdt_next_node(fdt, -1, NULL);
offset >= 0;
offset = fdt_next_node(fdt, offset, NULL)) {
if (fdt_get_phandle(fdt, offset) == phandle)
return offset;
}
return offset; /* error from fdt_next_node() */
} }
static int _stringlist_contains(const char *strlist, int listlen, const char *str) static int _fdt_stringlist_contains(const char *strlist, int listlen,
const char *str)
{ {
int len = strlen(str); int len = strlen(str);
const char *p; const char *p;
...@@ -437,7 +542,7 @@ int fdt_node_check_compatible(const void *fdt, int nodeoffset, ...@@ -437,7 +542,7 @@ int fdt_node_check_compatible(const void *fdt, int nodeoffset,
prop = fdt_getprop(fdt, nodeoffset, "compatible", &len); prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);
if (!prop) if (!prop)
return len; return len;
if (_stringlist_contains(prop, len, compatible)) if (_fdt_stringlist_contains(prop, len, compatible))
return 0; return 0;
else else
return 1; return 1;
......
...@@ -289,6 +289,33 @@ int fdt_setprop(void *fdt, int nodeoffset, const char *name, ...@@ -289,6 +289,33 @@ int fdt_setprop(void *fdt, int nodeoffset, const char *name,
return 0; return 0;
} }
int fdt_appendprop(void *fdt, int nodeoffset, const char *name,
const void *val, int len)
{
struct fdt_property *prop;
int err, oldlen, newlen;
FDT_RW_CHECK_HEADER(fdt);
prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
if (prop) {
newlen = len + oldlen;
err = _fdt_splice_struct(fdt, prop->data,
FDT_TAGALIGN(oldlen),
FDT_TAGALIGN(newlen));
if (err)
return err;
prop->len = cpu_to_fdt32(newlen);
memcpy(prop->data + oldlen, val, len);
} else {
err = _fdt_add_property(fdt, nodeoffset, name, len, &prop);
if (err)
return err;
memcpy(prop->data, val, len);
}
return 0;
}
int fdt_delprop(void *fdt, int nodeoffset, const char *name) int fdt_delprop(void *fdt, int nodeoffset, const char *name)
{ {
struct fdt_property *prop; struct fdt_property *prop;
...@@ -406,6 +433,8 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize) ...@@ -406,6 +433,8 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
struct_size = 0; struct_size = 0;
while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END) while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END)
; ;
if (struct_size < 0)
return struct_size;
} }
if (!_fdt_blocks_misordered(fdt, mem_rsv_size, struct_size)) { if (!_fdt_blocks_misordered(fdt, mem_rsv_size, struct_size)) {
......
...@@ -70,7 +70,7 @@ static int _fdt_sw_check_header(void *fdt) ...@@ -70,7 +70,7 @@ static int _fdt_sw_check_header(void *fdt)
return err; \ return err; \
} }
static void *_fdt_grab_space(void *fdt, int len) static void *_fdt_grab_space(void *fdt, size_t len)
{ {
int offset = fdt_size_dt_struct(fdt); int offset = fdt_size_dt_struct(fdt);
int spaceleft; int spaceleft;
...@@ -82,7 +82,7 @@ static void *_fdt_grab_space(void *fdt, int len) ...@@ -82,7 +82,7 @@ static void *_fdt_grab_space(void *fdt, int len)
return NULL; return NULL;
fdt_set_size_dt_struct(fdt, offset + len); fdt_set_size_dt_struct(fdt, offset + len);
return fdt_offset_ptr_w(fdt, offset, len); return _fdt_offset_ptr_w(fdt, offset);
} }
int fdt_create(void *buf, int bufsize) int fdt_create(void *buf, int bufsize)
...@@ -237,18 +237,17 @@ int fdt_finish(void *fdt) ...@@ -237,18 +237,17 @@ int fdt_finish(void *fdt)
while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) { while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) {
if (tag == FDT_PROP) { if (tag == FDT_PROP) {
struct fdt_property *prop = struct fdt_property *prop =
fdt_offset_ptr_w(fdt, offset, sizeof(*prop)); _fdt_offset_ptr_w(fdt, offset);
int nameoff; int nameoff;
if (! prop)
return -FDT_ERR_BADSTRUCTURE;
nameoff = fdt32_to_cpu(prop->nameoff); nameoff = fdt32_to_cpu(prop->nameoff);
nameoff += fdt_size_dt_strings(fdt); nameoff += fdt_size_dt_strings(fdt);
prop->nameoff = cpu_to_fdt32(nameoff); prop->nameoff = cpu_to_fdt32(nameoff);
} }
offset = nextoffset; offset = nextoffset;
} }
if (nextoffset < 0)
return nextoffset;
/* Finally, adjust the header */ /* Finally, adjust the header */
fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt)); fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt));
......
...@@ -94,41 +94,14 @@ int fdt_nop_property(void *fdt, int nodeoffset, const char *name) ...@@ -94,41 +94,14 @@ int fdt_nop_property(void *fdt, int nodeoffset, const char *name)
return 0; return 0;
} }
int _fdt_node_end_offset(void *fdt, int nodeoffset) int _fdt_node_end_offset(void *fdt, int offset)
{ {
int level = 0; int depth = 0;
uint32_t tag;
int offset, nextoffset;
tag = fdt_next_tag(fdt, nodeoffset, &nextoffset);
if (tag != FDT_BEGIN_NODE)
return -FDT_ERR_BADOFFSET;
do {
offset = nextoffset;
tag = fdt_next_tag(fdt, offset, &nextoffset);
switch (tag) {
case FDT_END:
return offset;
case FDT_BEGIN_NODE:
level++;
break;
case FDT_END_NODE:
level--;
break;
case FDT_PROP: while ((offset >= 0) && (depth >= 0))
case FDT_NOP: offset = fdt_next_node(fdt, offset, &depth);
break;
default: return offset;
return -FDT_ERR_BADSTRUCTURE;
}
} while (level >= 0);
return nextoffset;
} }
int fdt_nop_node(void *fdt, int nodeoffset) int fdt_nop_node(void *fdt, int nodeoffset)
......
This diff is collapsed.
...@@ -5,19 +5,25 @@ ...@@ -5,19 +5,25 @@
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#define _B(n) ((unsigned long long)((uint8_t *)&x)[n]) #define EXTRACT_BYTE(n) ((unsigned long long)((uint8_t *)&x)[n])
static inline uint16_t fdt16_to_cpu(uint16_t x)
{
return (EXTRACT_BYTE(0) << 8) | EXTRACT_BYTE(1);
}
#define cpu_to_fdt16(x) fdt16_to_cpu(x)
static inline uint32_t fdt32_to_cpu(uint32_t x) static inline uint32_t fdt32_to_cpu(uint32_t x)
{ {
return (_B(0) << 24) | (_B(1) << 16) | (_B(2) << 8) | _B(3); return (EXTRACT_BYTE(0) << 24) | (EXTRACT_BYTE(1) << 16) | (EXTRACT_BYTE(2) << 8) | EXTRACT_BYTE(3);
} }
#define cpu_to_fdt32(x) fdt32_to_cpu(x) #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(uint64_t x)
{ {
return (_B(0) << 56) | (_B(1) << 48) | (_B(2) << 40) | (_B(3) << 32) return (EXTRACT_BYTE(0) << 56) | (EXTRACT_BYTE(1) << 48) | (EXTRACT_BYTE(2) << 40) | (EXTRACT_BYTE(3) << 32)
| (_B(4) << 24) | (_B(5) << 16) | (_B(6) << 8) | _B(7); | (EXTRACT_BYTE(4) << 24) | (EXTRACT_BYTE(5) << 16) | (EXTRACT_BYTE(6) << 8) | EXTRACT_BYTE(7);
} }
#define cpu_to_fdt64(x) fdt64_to_cpu(x) #define cpu_to_fdt64(x) fdt64_to_cpu(x)
#undef _B #undef EXTRACT_BYTE
#endif /* _LIBFDT_ENV_H */ #endif /* _LIBFDT_ENV_H */
...@@ -62,8 +62,8 @@ ...@@ -62,8 +62,8 @@
return err; \ return err; \
} }
uint32_t _fdt_next_tag(const void *fdt, int startoffset, int *nextoffset);
int _fdt_check_node_offset(const void *fdt, int offset); int _fdt_check_node_offset(const void *fdt, int offset);
int _fdt_check_prop_offset(const void *fdt, int offset);
const char *_fdt_find_string(const char *strtab, int tabsize, const char *s); const char *_fdt_find_string(const char *strtab, int tabsize, const char *s);
int _fdt_node_end_offset(void *fdt, int nodeoffset); int _fdt_node_end_offset(void *fdt, int nodeoffset);
......
This diff is collapsed.
This diff is collapsed.
...@@ -33,10 +33,39 @@ struct srcfile_state { ...@@ -33,10 +33,39 @@ struct srcfile_state {
extern FILE *depfile; /* = NULL */ extern FILE *depfile; /* = NULL */
extern struct srcfile_state *current_srcfile; /* = NULL */ extern struct srcfile_state *current_srcfile; /* = NULL */
/**
* Open a source file.
*
* If the source file is a relative pathname, then it is searched for in the
* current directory (the directory of the last source file read) and after
* that in the search path.
*
* We work through the search path in order from the first path specified to
* the last.
*
* If the file is not found, then this function does not return, but calls
* die().
*
* @param fname Filename to search
* @param fullnamep If non-NULL, it is set to the allocated filename of the
* file that was opened. The caller is then responsible
* for freeing the pointer.
* @return pointer to opened FILE
*/
FILE *srcfile_relative_open(const char *fname, char **fullnamep); FILE *srcfile_relative_open(const char *fname, char **fullnamep);
void srcfile_push(const char *fname); void srcfile_push(const char *fname);
int srcfile_pop(void); int srcfile_pop(void);
/**
* Add a new directory to the search path for input files
*
* The new path is added at the end of the list.
*
* @param dirname Directory to add
*/
void srcfile_add_search_path(const char *dirname);
struct srcpos { struct srcpos {
int first_line; int first_line;
int first_column; int first_column;
...@@ -84,4 +113,6 @@ extern void srcpos_error(struct srcpos *pos, char const *, ...) ...@@ -84,4 +113,6 @@ extern void srcpos_error(struct srcpos *pos, char const *, ...)
extern void srcpos_warn(struct srcpos *pos, char const *, ...) extern void srcpos_warn(struct srcpos *pos, char const *, ...)
__attribute__((format(printf, 2, 3))); __attribute__((format(printf, 2, 3)));
extern void srcpos_set_line(char *f, int l);
#endif /* _SRCPOS_H_ */ #endif /* _SRCPOS_H_ */
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
extern FILE *yyin; extern FILE *yyin;
extern int yyparse(void); extern int yyparse(void);
extern YYLTYPE yylloc;
struct boot_info *the_boot_info; struct boot_info *the_boot_info;
int treesource_error; int treesource_error;
...@@ -34,6 +35,7 @@ struct boot_info *dt_from_source(const char *fname) ...@@ -34,6 +35,7 @@ struct boot_info *dt_from_source(const char *fname)
srcfile_push(fname); srcfile_push(fname);
yyin = current_srcfile->f; yyin = current_srcfile->f;
yylloc.file = current_srcfile;
if (yyparse() != 0) if (yyparse() != 0)
die("Unable to parse input tree\n"); die("Unable to parse input tree\n");
......
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment