1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005. 4 */ 5 %locations 6 7 %{ 8 #include <stdio.h> 9 #include <inttypes.h> 10 11 #include "dtc.h" 12 #include "srcpos.h" 13 14 extern int yylex(void); 15 extern void yyerror(char const *s); 16 #define ERROR(loc, ...) \ 17 do { \ 18 srcpos_error((loc), "Error", __VA_ARGS__); \ 19 treesource_error = true; \ 20 } while (0) 21 22 #define YYERROR_CALL(msg) yyerror(msg) 23 24 extern struct dt_info *parser_output; 25 extern bool treesource_error; 26 27 static bool is_ref_relative(const char *ref) 28 { 29 return ref[0] != '/' && strchr(&ref[1], '/'); 30 } 31 32 %} 33 34 %union { 35 char *propnodename; 36 char *labelref; 37 uint8_t byte; 38 struct data data; 39 40 struct { 41 struct data data; 42 int bits; 43 } array; 44 45 struct property *prop; 46 struct property *proplist; 47 struct node *node; 48 struct node *nodelist; 49 struct reserve_info *re; 50 uint64_t integer; 51 unsigned int flags; 52 } 53 54 %token DT_V1 55 %token DT_PLUGIN 56 %token DT_MEMRESERVE 57 %token DT_LSHIFT DT_RSHIFT DT_LE DT_GE DT_EQ DT_NE DT_AND DT_OR 58 %token DT_BITS 59 %token DT_DEL_PROP 60 %token DT_DEL_NODE 61 %token DT_OMIT_NO_REF 62 %token <propnodename> DT_PROPNODENAME 63 %token <integer> DT_LITERAL 64 %token <integer> DT_CHAR_LITERAL 65 %token <byte> DT_BYTE 66 %token <data> DT_STRING 67 %token <labelref> DT_LABEL 68 %token <labelref> DT_LABEL_REF 69 %token <labelref> DT_PATH_REF 70 %token DT_INCBIN 71 72 %type <data> propdata 73 %type <data> propdataprefix 74 %type <flags> header 75 %type <flags> headers 76 %type <re> memreserve 77 %type <re> memreserves 78 %type <array> arrayprefix 79 %type <data> bytestring 80 %type <prop> propdef 81 %type <proplist> proplist 82 %type <labelref> dt_ref 83 84 %type <node> devicetree 85 %type <node> nodedef 86 %type <node> subnode 87 %type <nodelist> subnodes 88 89 %type <integer> integer_prim 90 %type <integer> integer_unary 91 %type <integer> integer_mul 92 %type <integer> integer_add 93 %type <integer> integer_shift 94 %type <integer> integer_rela 95 %type <integer> integer_eq 96 %type <integer> integer_bitand 97 %type <integer> integer_bitxor 98 %type <integer> integer_bitor 99 %type <integer> integer_and 100 %type <integer> integer_or 101 %type <integer> integer_trinary 102 %type <integer> integer_expr 103 104 %% 105 106 sourcefile: 107 headers memreserves devicetree 108 { 109 parser_output = build_dt_info($1, $2, $3, 110 guess_boot_cpuid($3)); 111 } 112 ; 113 114 header: 115 DT_V1 ';' 116 { 117 $$ = DTSF_V1; 118 } 119 | DT_V1 ';' DT_PLUGIN ';' 120 { 121 $$ = DTSF_V1 | DTSF_PLUGIN; 122 } 123 ; 124 125 headers: 126 header 127 | header headers 128 { 129 if ($2 != $1) 130 ERROR(&@2, "Header flags don't match earlier ones"); 131 $$ = $1; 132 } 133 ; 134 135 memreserves: 136 /* empty */ 137 { 138 $$ = NULL; 139 } 140 | memreserve memreserves 141 { 142 $$ = chain_reserve_entry($1, $2); 143 } 144 ; 145 146 memreserve: 147 DT_MEMRESERVE integer_prim integer_prim ';' 148 { 149 $$ = build_reserve_entry($2, $3); 150 } 151 | DT_LABEL memreserve 152 { 153 add_label(&$2->labels, $1); 154 $$ = $2; 155 } 156 ; 157 158 dt_ref: DT_LABEL_REF | DT_PATH_REF; 159 160 devicetree: 161 '/' nodedef 162 { 163 $$ = name_node($2, ""); 164 } 165 | devicetree '/' nodedef 166 { 167 $$ = merge_nodes($1, $3); 168 } 169 | dt_ref nodedef 170 { 171 /* 172 * We rely on the rule being always: 173 * versioninfo plugindecl memreserves devicetree 174 * so $-1 is what we want (plugindecl) 175 */ 176 if (!($<flags>-1 & DTSF_PLUGIN)) 177 ERROR(&@2, "Label or path %s not found", $1); 178 else if (is_ref_relative($1)) 179 ERROR(&@2, "Label-relative reference %s not supported in plugin", $1); 180 $$ = add_orphan_node( 181 name_node(build_node(NULL, NULL, NULL), 182 ""), 183 $2, $1); 184 } 185 | devicetree DT_LABEL dt_ref nodedef 186 { 187 struct node *target = get_node_by_ref($1, $3); 188 189 if (($<flags>-1 & DTSF_PLUGIN) && is_ref_relative($3)) 190 ERROR(&@2, "Label-relative reference %s not supported in plugin", $3); 191 192 if (target) { 193 add_label(&target->labels, $2); 194 merge_nodes(target, $4); 195 } else 196 ERROR(&@3, "Label or path %s not found", $3); 197 $$ = $1; 198 } 199 | devicetree DT_PATH_REF nodedef 200 { 201 /* 202 * We rely on the rule being always: 203 * versioninfo plugindecl memreserves devicetree 204 * so $-1 is what we want (plugindecl) 205 */ 206 if ($<flags>-1 & DTSF_PLUGIN) { 207 if (is_ref_relative($2)) 208 ERROR(&@2, "Label-relative reference %s not supported in plugin", $2); 209 add_orphan_node($1, $3, $2); 210 } else { 211 struct node *target = get_node_by_ref($1, $2); 212 213 if (target) 214 merge_nodes(target, $3); 215 else 216 ERROR(&@2, "Label or path %s not found", $2); 217 } 218 $$ = $1; 219 } 220 | devicetree DT_LABEL_REF nodedef 221 { 222 struct node *target = get_node_by_ref($1, $2); 223 224 if (target) { 225 merge_nodes(target, $3); 226 } else { 227 /* 228 * We rely on the rule being always: 229 * versioninfo plugindecl memreserves devicetree 230 * so $-1 is what we want (plugindecl) 231 */ 232 if ($<flags>-1 & DTSF_PLUGIN) 233 add_orphan_node($1, $3, $2); 234 else 235 ERROR(&@2, "Label or path %s not found", $2); 236 } 237 $$ = $1; 238 } 239 | devicetree DT_DEL_NODE dt_ref ';' 240 { 241 struct node *target = get_node_by_ref($1, $3); 242 243 if (target) 244 delete_node(target); 245 else 246 ERROR(&@3, "Label or path %s not found", $3); 247 248 249 $$ = $1; 250 } 251 | devicetree DT_OMIT_NO_REF dt_ref ';' 252 { 253 struct node *target = get_node_by_ref($1, $3); 254 255 if (target) 256 omit_node_if_unused(target); 257 else 258 ERROR(&@3, "Label or path %s not found", $3); 259 260 261 $$ = $1; 262 } 263 ; 264 265 nodedef: 266 '{' proplist subnodes '}' ';' 267 { 268 $$ = build_node($2, $3, &@$); 269 } 270 ; 271 272 proplist: 273 /* empty */ 274 { 275 $$ = NULL; 276 } 277 | proplist propdef 278 { 279 $$ = chain_property($2, $1); 280 } 281 ; 282 283 propdef: 284 DT_PROPNODENAME '=' propdata ';' 285 { 286 $$ = build_property($1, $3, &@$); 287 } 288 | DT_PROPNODENAME ';' 289 { 290 $$ = build_property($1, empty_data, &@$); 291 } 292 | DT_DEL_PROP DT_PROPNODENAME ';' 293 { 294 $$ = build_property_delete($2); 295 } 296 | DT_LABEL propdef 297 { 298 add_label(&$2->labels, $1); 299 $$ = $2; 300 } 301 ; 302 303 propdata: 304 propdataprefix DT_STRING 305 { 306 $$ = data_merge($1, $2); 307 } 308 | propdataprefix arrayprefix '>' 309 { 310 $$ = data_merge($1, $2.data); 311 } 312 | propdataprefix '[' bytestring ']' 313 { 314 $$ = data_merge($1, $3); 315 } 316 | propdataprefix dt_ref 317 { 318 $1 = data_add_marker($1, TYPE_STRING, $2); 319 $$ = data_add_marker($1, REF_PATH, $2); 320 } 321 | propdataprefix DT_INCBIN '(' DT_STRING ',' integer_prim ',' integer_prim ')' 322 { 323 FILE *f = srcfile_relative_open($4.val, NULL); 324 struct data d; 325 326 if ($6 != 0) 327 if (fseek(f, $6, SEEK_SET) != 0) 328 die("Couldn't seek to offset %llu in \"%s\": %s", 329 (unsigned long long)$6, $4.val, 330 strerror(errno)); 331 332 d = data_copy_file(f, $8); 333 334 $$ = data_merge($1, d); 335 fclose(f); 336 } 337 | propdataprefix DT_INCBIN '(' DT_STRING ')' 338 { 339 FILE *f = srcfile_relative_open($4.val, NULL); 340 struct data d = empty_data; 341 342 d = data_copy_file(f, -1); 343 344 $$ = data_merge($1, d); 345 fclose(f); 346 } 347 | propdata DT_LABEL 348 { 349 $$ = data_add_marker($1, LABEL, $2); 350 } 351 ; 352 353 propdataprefix: 354 /* empty */ 355 { 356 $$ = empty_data; 357 } 358 | propdata ',' 359 { 360 $$ = $1; 361 } 362 | propdataprefix DT_LABEL 363 { 364 $$ = data_add_marker($1, LABEL, $2); 365 } 366 ; 367 368 arrayprefix: 369 DT_BITS DT_LITERAL '<' 370 { 371 unsigned long long bits; 372 enum markertype type = TYPE_UINT32; 373 374 bits = $2; 375 376 switch (bits) { 377 case 8: type = TYPE_UINT8; break; 378 case 16: type = TYPE_UINT16; break; 379 case 32: type = TYPE_UINT32; break; 380 case 64: type = TYPE_UINT64; break; 381 default: 382 ERROR(&@2, "Array elements must be" 383 " 8, 16, 32 or 64-bits"); 384 bits = 32; 385 } 386 387 $$.data = data_add_marker(empty_data, type, NULL); 388 $$.bits = bits; 389 } 390 | '<' 391 { 392 $$.data = data_add_marker(empty_data, TYPE_UINT32, NULL); 393 $$.bits = 32; 394 } 395 | arrayprefix integer_prim 396 { 397 if ($1.bits < 64) { 398 uint64_t mask = (1ULL << $1.bits) - 1; 399 /* 400 * Bits above mask must either be all zero 401 * (positive within range of mask) or all one 402 * (negative and sign-extended). The second 403 * condition is true if when we set all bits 404 * within the mask to one (i.e. | in the 405 * mask), all bits are one. 406 */ 407 if (($2 > mask) && (($2 | mask) != -1ULL)) { 408 char *loc = srcpos_string(&@2); 409 fprintf(stderr, 410 "WARNING: %s: Value 0x%016" PRIx64 411 " truncated to 0x%0*" PRIx64 "\n", 412 loc, $2, $1.bits / 4, ($2 & mask)); 413 free(loc); 414 } 415 } 416 417 $$.data = data_append_integer($1.data, $2, $1.bits); 418 } 419 | arrayprefix dt_ref 420 { 421 uint64_t val = ~0ULL >> (64 - $1.bits); 422 423 if ($1.bits == 32) 424 $1.data = data_add_marker($1.data, 425 REF_PHANDLE, 426 $2); 427 else 428 ERROR(&@2, "References are only allowed in " 429 "arrays with 32-bit elements."); 430 431 $$.data = data_append_integer($1.data, val, $1.bits); 432 } 433 | arrayprefix DT_LABEL 434 { 435 $$.data = data_add_marker($1.data, LABEL, $2); 436 } 437 ; 438 439 integer_prim: 440 DT_LITERAL 441 | DT_CHAR_LITERAL 442 | '(' integer_expr ')' 443 { 444 $$ = $2; 445 } 446 ; 447 448 integer_expr: 449 integer_trinary 450 ; 451 452 integer_trinary: 453 integer_or 454 | integer_or '?' integer_expr ':' integer_trinary { $$ = $1 ? $3 : $5; } 455 ; 456 457 integer_or: 458 integer_and 459 | integer_or DT_OR integer_and { $$ = $1 || $3; } 460 ; 461 462 integer_and: 463 integer_bitor 464 | integer_and DT_AND integer_bitor { $$ = $1 && $3; } 465 ; 466 467 integer_bitor: 468 integer_bitxor 469 | integer_bitor '|' integer_bitxor { $$ = $1 | $3; } 470 ; 471 472 integer_bitxor: 473 integer_bitand 474 | integer_bitxor '^' integer_bitand { $$ = $1 ^ $3; } 475 ; 476 477 integer_bitand: 478 integer_eq 479 | integer_bitand '&' integer_eq { $$ = $1 & $3; } 480 ; 481 482 integer_eq: 483 integer_rela 484 | integer_eq DT_EQ integer_rela { $$ = $1 == $3; } 485 | integer_eq DT_NE integer_rela { $$ = $1 != $3; } 486 ; 487 488 integer_rela: 489 integer_shift 490 | integer_rela '<' integer_shift { $$ = $1 < $3; } 491 | integer_rela '>' integer_shift { $$ = $1 > $3; } 492 | integer_rela DT_LE integer_shift { $$ = $1 <= $3; } 493 | integer_rela DT_GE integer_shift { $$ = $1 >= $3; } 494 ; 495 496 integer_shift: 497 integer_shift DT_LSHIFT integer_add { $$ = ($3 < 64) ? ($1 << $3) : 0; } 498 | integer_shift DT_RSHIFT integer_add { $$ = ($3 < 64) ? ($1 >> $3) : 0; } 499 | integer_add 500 ; 501 502 integer_add: 503 integer_add '+' integer_mul { $$ = $1 + $3; } 504 | integer_add '-' integer_mul { $$ = $1 - $3; } 505 | integer_mul 506 ; 507 508 integer_mul: 509 integer_mul '*' integer_unary { $$ = $1 * $3; } 510 | integer_mul '/' integer_unary 511 { 512 if ($3 != 0) { 513 $$ = $1 / $3; 514 } else { 515 ERROR(&@$, "Division by zero"); 516 $$ = 0; 517 } 518 } 519 | integer_mul '%' integer_unary 520 { 521 if ($3 != 0) { 522 $$ = $1 % $3; 523 } else { 524 ERROR(&@$, "Division by zero"); 525 $$ = 0; 526 } 527 } 528 | integer_unary 529 ; 530 531 integer_unary: 532 integer_prim 533 | '-' integer_unary { $$ = -$2; } 534 | '~' integer_unary { $$ = ~$2; } 535 | '!' integer_unary { $$ = !$2; } 536 ; 537 538 bytestring: 539 /* empty */ 540 { 541 $$ = data_add_marker(empty_data, TYPE_UINT8, NULL); 542 } 543 | bytestring DT_BYTE 544 { 545 $$ = data_append_byte($1, $2); 546 } 547 | bytestring DT_LABEL 548 { 549 $$ = data_add_marker($1, LABEL, $2); 550 } 551 ; 552 553 subnodes: 554 /* empty */ 555 { 556 $$ = NULL; 557 } 558 | subnode subnodes 559 { 560 $$ = chain_node($1, $2); 561 } 562 | subnode propdef 563 { 564 ERROR(&@2, "Properties must precede subnodes"); 565 YYERROR; 566 } 567 ; 568 569 subnode: 570 DT_PROPNODENAME nodedef 571 { 572 $$ = name_node($2, $1); 573 } 574 | DT_DEL_NODE DT_PROPNODENAME ';' 575 { 576 $$ = name_node(build_node_delete(&@$), $2); 577 } 578 | DT_OMIT_NO_REF subnode 579 { 580 $$ = omit_node_if_unused($2); 581 } 582 | DT_LABEL subnode 583 { 584 add_label(&$2->labels, $1); 585 $$ = $2; 586 } 587 ; 588 589 %% 590 591 void yyerror(char const *s) 592 { 593 ERROR(&yylloc, "%s", s); 594 } 595