diff options
Diffstat (limited to 'scripts/dtc/dtc-parser.y')
-rw-r--r-- | scripts/dtc/dtc-parser.y | 255 |
1 files changed, 221 insertions, 34 deletions
diff --git a/scripts/dtc/dtc-parser.y b/scripts/dtc/dtc-parser.y index 5e84a67fc1d..f412460f94d 100644 --- a/scripts/dtc/dtc-parser.y +++ b/scripts/dtc/dtc-parser.y @@ -34,6 +34,7 @@ extern struct boot_info *the_boot_info; extern int treesource_error; static unsigned long long eval_literal(const char *s, int base, int bits); +static unsigned char eval_char_literal(const char *s); %} %union { @@ -44,19 +45,28 @@ static unsigned long long eval_literal(const char *s, int base, int bits); uint8_t byte; struct data data; - uint64_t addr; - cell_t cell; + struct { + struct data data; + int bits; + } array; + struct property *prop; struct property *proplist; struct node *node; struct node *nodelist; struct reserve_info *re; + uint64_t integer; } %token DT_V1 %token DT_MEMRESERVE +%token DT_LSHIFT DT_RSHIFT DT_LE DT_GE DT_EQ DT_NE DT_AND DT_OR +%token DT_BITS +%token DT_DEL_PROP +%token DT_DEL_NODE %token <propnodename> DT_PROPNODENAME %token <literal> DT_LITERAL +%token <literal> DT_CHAR_LITERAL %token <cbase> DT_BASE %token <byte> DT_BYTE %token <data> DT_STRING @@ -68,9 +78,7 @@ static unsigned long long eval_literal(const char *s, int base, int bits); %type <data> propdataprefix %type <re> memreserve %type <re> memreserves -%type <addr> addr -%type <data> celllist -%type <cell> cellval +%type <array> arrayprefix %type <data> bytestring %type <prop> propdef %type <proplist> proplist @@ -80,6 +88,21 @@ static unsigned long long eval_literal(const char *s, int base, int bits); %type <node> subnode %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: @@ -102,7 +125,7 @@ memreserves: ; memreserve: - DT_MEMRESERVE addr addr ';' + DT_MEMRESERVE integer_prim integer_prim ';' { $$ = build_reserve_entry($2, $3); } @@ -113,13 +136,6 @@ memreserve: } ; -addr: - DT_LITERAL - { - $$ = eval_literal($1, 0, 64); - } - ; - devicetree: '/' nodedef { @@ -139,6 +155,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: @@ -168,6 +195,10 @@ propdef: { $$ = build_property($1, empty_data); } + | DT_DEL_PROP DT_PROPNODENAME ';' + { + $$ = build_property_delete($2); + } | DT_LABEL propdef { add_label(&$2->labels, $1); @@ -180,9 +211,9 @@ propdata: { $$ = data_merge($1, $2); } - | propdataprefix '<' celllist '>' + | propdataprefix arrayprefix '>' { - $$ = data_merge($1, $3); + $$ = data_merge($1, $2.data); } | propdataprefix '[' bytestring ']' { @@ -192,7 +223,7 @@ propdata: { $$ = 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); struct data d; @@ -240,31 +271,154 @@ propdataprefix: } ; -celllist: - /* empty */ +arrayprefix: + DT_BITS DT_LITERAL '<' + { + $$.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; + } + } + | '<' + { + $$.data = empty_data; + $$.bits = 32; + } + | arrayprefix integer_prim + { + if ($1.bits < 64) { + uint64_t mask = (1ULL << $1.bits) - 1; + /* + * Bits above mask must either be all zero + * (positive within range of mask) or all one + * (negative and sign-extended). The second + * condition is true if when we set all bits + * within the mask to one (i.e. | in the + * mask), all bits are one. + */ + if (($2 > mask) && (($2 | mask) != -1ULL)) + print_error( + "integer value out of range " + "%016lx (%d bits)", $1.bits); + } + + $$.data = data_append_integer($1.data, $2, $1.bits); + } + | arrayprefix DT_REF + { + 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 { - $$ = empty_data; + $$.data = data_add_marker($1.data, LABEL, $2); } - | celllist cellval + ; + +integer_prim: + DT_LITERAL { - $$ = data_append_cell($1, $2); + $$ = eval_literal($1, 0, 64); } - | celllist DT_REF + | DT_CHAR_LITERAL { - $$ = data_append_cell(data_add_marker($1, REF_PHANDLE, - $2), -1); + $$ = eval_char_literal($1); } - | celllist DT_LABEL + | '(' integer_expr ')' { - $$ = data_add_marker($1, LABEL, $2); + $$ = $2; } ; -cellval: - DT_LITERAL - { - $$ = eval_literal($1, 0, 32); - } +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: @@ -303,6 +457,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); @@ -334,12 +492,41 @@ static unsigned long long eval_literal(const char *s, int base, int bits) errno = 0; val = strtoull(s, &e, base); - if (*e) - print_error("bad characters in literal"); - else if ((errno == ERANGE) + if (*e) { + size_t uls = strspn(e, "UL"); + if (e[uls]) + print_error("bad characters in literal"); + } + if ((errno == ERANGE) || ((bits < 64) && (val >= (1ULL << bits)))) 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; +} |