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