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