0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003 * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
0004 */
0005 %locations
0006
0007 %{
0008 #include <stdio.h>
0009 #include <inttypes.h>
0010
0011 #include "dtc.h"
0012 #include "srcpos.h"
0013
0014 extern int yylex(void);
0015 extern void yyerror(char const *s);
0016 #define ERROR(loc, ...) \
0017 do { \
0018 srcpos_error((loc), "Error", __VA_ARGS__); \
0019 treesource_error = true; \
0020 } while (0)
0021
0022 #define YYERROR_CALL(msg) yyerror(msg)
0023
0024 extern struct dt_info *parser_output;
0025 extern bool treesource_error;
0026 %}
0027
0028 %union {
0029 char *propnodename;
0030 char *labelref;
0031 uint8_t byte;
0032 struct data data;
0033
0034 struct {
0035 struct data data;
0036 int bits;
0037 } array;
0038
0039 struct property *prop;
0040 struct property *proplist;
0041 struct node *node;
0042 struct node *nodelist;
0043 struct reserve_info *re;
0044 uint64_t integer;
0045 unsigned int flags;
0046 }
0047
0048 %token DT_V1
0049 %token DT_PLUGIN
0050 %token DT_MEMRESERVE
0051 %token DT_LSHIFT DT_RSHIFT DT_LE DT_GE DT_EQ DT_NE DT_AND DT_OR
0052 %token DT_BITS
0053 %token DT_DEL_PROP
0054 %token DT_DEL_NODE
0055 %token DT_OMIT_NO_REF
0056 %token <propnodename> DT_PROPNODENAME
0057 %token <integer> DT_LITERAL
0058 %token <integer> DT_CHAR_LITERAL
0059 %token <byte> DT_BYTE
0060 %token <data> DT_STRING
0061 %token <labelref> DT_LABEL
0062 %token <labelref> DT_LABEL_REF
0063 %token <labelref> DT_PATH_REF
0064 %token DT_INCBIN
0065
0066 %type <data> propdata
0067 %type <data> propdataprefix
0068 %type <flags> header
0069 %type <flags> headers
0070 %type <re> memreserve
0071 %type <re> memreserves
0072 %type <array> arrayprefix
0073 %type <data> bytestring
0074 %type <prop> propdef
0075 %type <proplist> proplist
0076 %type <labelref> dt_ref
0077
0078 %type <node> devicetree
0079 %type <node> nodedef
0080 %type <node> subnode
0081 %type <nodelist> subnodes
0082
0083 %type <integer> integer_prim
0084 %type <integer> integer_unary
0085 %type <integer> integer_mul
0086 %type <integer> integer_add
0087 %type <integer> integer_shift
0088 %type <integer> integer_rela
0089 %type <integer> integer_eq
0090 %type <integer> integer_bitand
0091 %type <integer> integer_bitxor
0092 %type <integer> integer_bitor
0093 %type <integer> integer_and
0094 %type <integer> integer_or
0095 %type <integer> integer_trinary
0096 %type <integer> integer_expr
0097
0098 %%
0099
0100 sourcefile:
0101 headers memreserves devicetree
0102 {
0103 parser_output = build_dt_info($1, $2, $3,
0104 guess_boot_cpuid($3));
0105 }
0106 ;
0107
0108 header:
0109 DT_V1 ';'
0110 {
0111 $$ = DTSF_V1;
0112 }
0113 | DT_V1 ';' DT_PLUGIN ';'
0114 {
0115 $$ = DTSF_V1 | DTSF_PLUGIN;
0116 }
0117 ;
0118
0119 headers:
0120 header
0121 | header headers
0122 {
0123 if ($2 != $1)
0124 ERROR(&@2, "Header flags don't match earlier ones");
0125 $$ = $1;
0126 }
0127 ;
0128
0129 memreserves:
0130 /* empty */
0131 {
0132 $$ = NULL;
0133 }
0134 | memreserve memreserves
0135 {
0136 $$ = chain_reserve_entry($1, $2);
0137 }
0138 ;
0139
0140 memreserve:
0141 DT_MEMRESERVE integer_prim integer_prim ';'
0142 {
0143 $$ = build_reserve_entry($2, $3);
0144 }
0145 | DT_LABEL memreserve
0146 {
0147 add_label(&$2->labels, $1);
0148 $$ = $2;
0149 }
0150 ;
0151
0152 dt_ref: DT_LABEL_REF | DT_PATH_REF;
0153
0154 devicetree:
0155 '/' nodedef
0156 {
0157 $$ = name_node($2, "");
0158 }
0159 | devicetree '/' nodedef
0160 {
0161 $$ = merge_nodes($1, $3);
0162 }
0163 | dt_ref nodedef
0164 {
0165 /*
0166 * We rely on the rule being always:
0167 * versioninfo plugindecl memreserves devicetree
0168 * so $-1 is what we want (plugindecl)
0169 */
0170 if (!($<flags>-1 & DTSF_PLUGIN))
0171 ERROR(&@2, "Label or path %s not found", $1);
0172 $$ = add_orphan_node(
0173 name_node(build_node(NULL, NULL, NULL),
0174 ""),
0175 $2, $1);
0176 }
0177 | devicetree DT_LABEL dt_ref nodedef
0178 {
0179 struct node *target = get_node_by_ref($1, $3);
0180
0181 if (target) {
0182 add_label(&target->labels, $2);
0183 merge_nodes(target, $4);
0184 } else
0185 ERROR(&@3, "Label or path %s not found", $3);
0186 $$ = $1;
0187 }
0188 | devicetree DT_PATH_REF nodedef
0189 {
0190 /*
0191 * We rely on the rule being always:
0192 * versioninfo plugindecl memreserves devicetree
0193 * so $-1 is what we want (plugindecl)
0194 */
0195 if ($<flags>-1 & DTSF_PLUGIN) {
0196 add_orphan_node($1, $3, $2);
0197 } else {
0198 struct node *target = get_node_by_ref($1, $2);
0199
0200 if (target)
0201 merge_nodes(target, $3);
0202 else
0203 ERROR(&@2, "Label or path %s not found", $2);
0204 }
0205 $$ = $1;
0206 }
0207 | devicetree DT_LABEL_REF nodedef
0208 {
0209 struct node *target = get_node_by_ref($1, $2);
0210
0211 if (target) {
0212 merge_nodes(target, $3);
0213 } else {
0214 /*
0215 * We rely on the rule being always:
0216 * versioninfo plugindecl memreserves devicetree
0217 * so $-1 is what we want (plugindecl)
0218 */
0219 if ($<flags>-1 & DTSF_PLUGIN)
0220 add_orphan_node($1, $3, $2);
0221 else
0222 ERROR(&@2, "Label or path %s not found", $2);
0223 }
0224 $$ = $1;
0225 }
0226 | devicetree DT_DEL_NODE dt_ref ';'
0227 {
0228 struct node *target = get_node_by_ref($1, $3);
0229
0230 if (target)
0231 delete_node(target);
0232 else
0233 ERROR(&@3, "Label or path %s not found", $3);
0234
0235
0236 $$ = $1;
0237 }
0238 | devicetree DT_OMIT_NO_REF dt_ref ';'
0239 {
0240 struct node *target = get_node_by_ref($1, $3);
0241
0242 if (target)
0243 omit_node_if_unused(target);
0244 else
0245 ERROR(&@3, "Label or path %s not found", $3);
0246
0247
0248 $$ = $1;
0249 }
0250 ;
0251
0252 nodedef:
0253 '{' proplist subnodes '}' ';'
0254 {
0255 $$ = build_node($2, $3, &@$);
0256 }
0257 ;
0258
0259 proplist:
0260 /* empty */
0261 {
0262 $$ = NULL;
0263 }
0264 | proplist propdef
0265 {
0266 $$ = chain_property($2, $1);
0267 }
0268 ;
0269
0270 propdef:
0271 DT_PROPNODENAME '=' propdata ';'
0272 {
0273 $$ = build_property($1, $3, &@$);
0274 }
0275 | DT_PROPNODENAME ';'
0276 {
0277 $$ = build_property($1, empty_data, &@$);
0278 }
0279 | DT_DEL_PROP DT_PROPNODENAME ';'
0280 {
0281 $$ = build_property_delete($2);
0282 }
0283 | DT_LABEL propdef
0284 {
0285 add_label(&$2->labels, $1);
0286 $$ = $2;
0287 }
0288 ;
0289
0290 propdata:
0291 propdataprefix DT_STRING
0292 {
0293 $$ = data_merge($1, $2);
0294 }
0295 | propdataprefix arrayprefix '>'
0296 {
0297 $$ = data_merge($1, $2.data);
0298 }
0299 | propdataprefix '[' bytestring ']'
0300 {
0301 $$ = data_merge($1, $3);
0302 }
0303 | propdataprefix dt_ref
0304 {
0305 $1 = data_add_marker($1, TYPE_STRING, $2);
0306 $$ = data_add_marker($1, REF_PATH, $2);
0307 }
0308 | propdataprefix DT_INCBIN '(' DT_STRING ',' integer_prim ',' integer_prim ')'
0309 {
0310 FILE *f = srcfile_relative_open($4.val, NULL);
0311 struct data d;
0312
0313 if ($6 != 0)
0314 if (fseek(f, $6, SEEK_SET) != 0)
0315 die("Couldn't seek to offset %llu in \"%s\": %s",
0316 (unsigned long long)$6, $4.val,
0317 strerror(errno));
0318
0319 d = data_copy_file(f, $8);
0320
0321 $$ = data_merge($1, d);
0322 fclose(f);
0323 }
0324 | propdataprefix DT_INCBIN '(' DT_STRING ')'
0325 {
0326 FILE *f = srcfile_relative_open($4.val, NULL);
0327 struct data d = empty_data;
0328
0329 d = data_copy_file(f, -1);
0330
0331 $$ = data_merge($1, d);
0332 fclose(f);
0333 }
0334 | propdata DT_LABEL
0335 {
0336 $$ = data_add_marker($1, LABEL, $2);
0337 }
0338 ;
0339
0340 propdataprefix:
0341 /* empty */
0342 {
0343 $$ = empty_data;
0344 }
0345 | propdata ','
0346 {
0347 $$ = $1;
0348 }
0349 | propdataprefix DT_LABEL
0350 {
0351 $$ = data_add_marker($1, LABEL, $2);
0352 }
0353 ;
0354
0355 arrayprefix:
0356 DT_BITS DT_LITERAL '<'
0357 {
0358 unsigned long long bits;
0359 enum markertype type = TYPE_UINT32;
0360
0361 bits = $2;
0362
0363 switch (bits) {
0364 case 8: type = TYPE_UINT8; break;
0365 case 16: type = TYPE_UINT16; break;
0366 case 32: type = TYPE_UINT32; break;
0367 case 64: type = TYPE_UINT64; break;
0368 default:
0369 ERROR(&@2, "Array elements must be"
0370 " 8, 16, 32 or 64-bits");
0371 bits = 32;
0372 }
0373
0374 $$.data = data_add_marker(empty_data, type, NULL);
0375 $$.bits = bits;
0376 }
0377 | '<'
0378 {
0379 $$.data = data_add_marker(empty_data, TYPE_UINT32, NULL);
0380 $$.bits = 32;
0381 }
0382 | arrayprefix integer_prim
0383 {
0384 if ($1.bits < 64) {
0385 uint64_t mask = (1ULL << $1.bits) - 1;
0386 /*
0387 * Bits above mask must either be all zero
0388 * (positive within range of mask) or all one
0389 * (negative and sign-extended). The second
0390 * condition is true if when we set all bits
0391 * within the mask to one (i.e. | in the
0392 * mask), all bits are one.
0393 */
0394 if (($2 > mask) && (($2 | mask) != -1ULL))
0395 ERROR(&@2, "Value out of range for"
0396 " %d-bit array element", $1.bits);
0397 }
0398
0399 $$.data = data_append_integer($1.data, $2, $1.bits);
0400 }
0401 | arrayprefix dt_ref
0402 {
0403 uint64_t val = ~0ULL >> (64 - $1.bits);
0404
0405 if ($1.bits == 32)
0406 $1.data = data_add_marker($1.data,
0407 REF_PHANDLE,
0408 $2);
0409 else
0410 ERROR(&@2, "References are only allowed in "
0411 "arrays with 32-bit elements.");
0412
0413 $$.data = data_append_integer($1.data, val, $1.bits);
0414 }
0415 | arrayprefix DT_LABEL
0416 {
0417 $$.data = data_add_marker($1.data, LABEL, $2);
0418 }
0419 ;
0420
0421 integer_prim:
0422 DT_LITERAL
0423 | DT_CHAR_LITERAL
0424 | '(' integer_expr ')'
0425 {
0426 $$ = $2;
0427 }
0428 ;
0429
0430 integer_expr:
0431 integer_trinary
0432 ;
0433
0434 integer_trinary:
0435 integer_or
0436 | integer_or '?' integer_expr ':' integer_trinary { $$ = $1 ? $3 : $5; }
0437 ;
0438
0439 integer_or:
0440 integer_and
0441 | integer_or DT_OR integer_and { $$ = $1 || $3; }
0442 ;
0443
0444 integer_and:
0445 integer_bitor
0446 | integer_and DT_AND integer_bitor { $$ = $1 && $3; }
0447 ;
0448
0449 integer_bitor:
0450 integer_bitxor
0451 | integer_bitor '|' integer_bitxor { $$ = $1 | $3; }
0452 ;
0453
0454 integer_bitxor:
0455 integer_bitand
0456 | integer_bitxor '^' integer_bitand { $$ = $1 ^ $3; }
0457 ;
0458
0459 integer_bitand:
0460 integer_eq
0461 | integer_bitand '&' integer_eq { $$ = $1 & $3; }
0462 ;
0463
0464 integer_eq:
0465 integer_rela
0466 | integer_eq DT_EQ integer_rela { $$ = $1 == $3; }
0467 | integer_eq DT_NE integer_rela { $$ = $1 != $3; }
0468 ;
0469
0470 integer_rela:
0471 integer_shift
0472 | integer_rela '<' integer_shift { $$ = $1 < $3; }
0473 | integer_rela '>' integer_shift { $$ = $1 > $3; }
0474 | integer_rela DT_LE integer_shift { $$ = $1 <= $3; }
0475 | integer_rela DT_GE integer_shift { $$ = $1 >= $3; }
0476 ;
0477
0478 integer_shift:
0479 integer_shift DT_LSHIFT integer_add { $$ = ($3 < 64) ? ($1 << $3) : 0; }
0480 | integer_shift DT_RSHIFT integer_add { $$ = ($3 < 64) ? ($1 >> $3) : 0; }
0481 | integer_add
0482 ;
0483
0484 integer_add:
0485 integer_add '+' integer_mul { $$ = $1 + $3; }
0486 | integer_add '-' integer_mul { $$ = $1 - $3; }
0487 | integer_mul
0488 ;
0489
0490 integer_mul:
0491 integer_mul '*' integer_unary { $$ = $1 * $3; }
0492 | integer_mul '/' integer_unary
0493 {
0494 if ($3 != 0) {
0495 $$ = $1 / $3;
0496 } else {
0497 ERROR(&@$, "Division by zero");
0498 $$ = 0;
0499 }
0500 }
0501 | integer_mul '%' integer_unary
0502 {
0503 if ($3 != 0) {
0504 $$ = $1 % $3;
0505 } else {
0506 ERROR(&@$, "Division by zero");
0507 $$ = 0;
0508 }
0509 }
0510 | integer_unary
0511 ;
0512
0513 integer_unary:
0514 integer_prim
0515 | '-' integer_unary { $$ = -$2; }
0516 | '~' integer_unary { $$ = ~$2; }
0517 | '!' integer_unary { $$ = !$2; }
0518 ;
0519
0520 bytestring:
0521 /* empty */
0522 {
0523 $$ = data_add_marker(empty_data, TYPE_UINT8, NULL);
0524 }
0525 | bytestring DT_BYTE
0526 {
0527 $$ = data_append_byte($1, $2);
0528 }
0529 | bytestring DT_LABEL
0530 {
0531 $$ = data_add_marker($1, LABEL, $2);
0532 }
0533 ;
0534
0535 subnodes:
0536 /* empty */
0537 {
0538 $$ = NULL;
0539 }
0540 | subnode subnodes
0541 {
0542 $$ = chain_node($1, $2);
0543 }
0544 | subnode propdef
0545 {
0546 ERROR(&@2, "Properties must precede subnodes");
0547 YYERROR;
0548 }
0549 ;
0550
0551 subnode:
0552 DT_PROPNODENAME nodedef
0553 {
0554 $$ = name_node($2, $1);
0555 }
0556 | DT_DEL_NODE DT_PROPNODENAME ';'
0557 {
0558 $$ = name_node(build_node_delete(&@$), $2);
0559 }
0560 | DT_OMIT_NO_REF subnode
0561 {
0562 $$ = omit_node_if_unused($2);
0563 }
0564 | DT_LABEL subnode
0565 {
0566 add_label(&$2->labels, $1);
0567 $$ = $2;
0568 }
0569 ;
0570
0571 %%
0572
0573 void yyerror(char const *s)
0574 {
0575 ERROR(&yylloc, "%s", s);
0576 }