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