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 $1 = data_add_marker($1, TYPE_STRING, $2); 291 $$ = data_add_marker($1, REF_PATH, $2); 292 } 293 | propdataprefix DT_INCBIN '(' DT_STRING ',' integer_prim ',' integer_prim ')' 294 { 295 FILE *f = srcfile_relative_open($4.val, NULL); 296 struct data d; 297 298 if ($6 != 0) 299 if (fseek(f, $6, SEEK_SET) != 0) 300 die("Couldn't seek to offset %llu in \"%s\": %s", 301 (unsigned long long)$6, $4.val, 302 strerror(errno)); 303 304 d = data_copy_file(f, $8); 305 306 $$ = data_merge($1, d); 307 fclose(f); 308 } 309 | propdataprefix DT_INCBIN '(' DT_STRING ')' 310 { 311 FILE *f = srcfile_relative_open($4.val, NULL); 312 struct data d = empty_data; 313 314 d = data_copy_file(f, -1); 315 316 $$ = data_merge($1, d); 317 fclose(f); 318 } 319 | propdata DT_LABEL 320 { 321 $$ = data_add_marker($1, LABEL, $2); 322 } 323 ; 324 325 propdataprefix: 326 /* empty */ 327 { 328 $$ = empty_data; 329 } 330 | propdata ',' 331 { 332 $$ = $1; 333 } 334 | propdataprefix DT_LABEL 335 { 336 $$ = data_add_marker($1, LABEL, $2); 337 } 338 ; 339 340 arrayprefix: 341 DT_BITS DT_LITERAL '<' 342 { 343 unsigned long long bits; 344 enum markertype type = TYPE_UINT32; 345 346 bits = $2; 347 348 switch (bits) { 349 case 8: type = TYPE_UINT8; break; 350 case 16: type = TYPE_UINT16; break; 351 case 32: type = TYPE_UINT32; break; 352 case 64: type = TYPE_UINT64; break; 353 default: 354 ERROR(&@2, "Array elements must be" 355 " 8, 16, 32 or 64-bits"); 356 bits = 32; 357 } 358 359 $$.data = data_add_marker(empty_data, type, NULL); 360 $$.bits = bits; 361 } 362 | '<' 363 { 364 $$.data = data_add_marker(empty_data, TYPE_UINT32, NULL); 365 $$.bits = 32; 366 } 367 | arrayprefix integer_prim 368 { 369 if ($1.bits < 64) { 370 uint64_t mask = (1ULL << $1.bits) - 1; 371 /* 372 * Bits above mask must either be all zero 373 * (positive within range of mask) or all one 374 * (negative and sign-extended). The second 375 * condition is true if when we set all bits 376 * within the mask to one (i.e. | in the 377 * mask), all bits are one. 378 */ 379 if (($2 > mask) && (($2 | mask) != -1ULL)) 380 ERROR(&@2, "Value out of range for" 381 " %d-bit array element", $1.bits); 382 } 383 384 $$.data = data_append_integer($1.data, $2, $1.bits); 385 } 386 | arrayprefix DT_REF 387 { 388 uint64_t val = ~0ULL >> (64 - $1.bits); 389 390 if ($1.bits == 32) 391 $1.data = data_add_marker($1.data, 392 REF_PHANDLE, 393 $2); 394 else 395 ERROR(&@2, "References are only allowed in " 396 "arrays with 32-bit elements."); 397 398 $$.data = data_append_integer($1.data, val, $1.bits); 399 } 400 | arrayprefix DT_LABEL 401 { 402 $$.data = data_add_marker($1.data, LABEL, $2); 403 } 404 ; 405 406 integer_prim: 407 DT_LITERAL 408 | DT_CHAR_LITERAL 409 | '(' integer_expr ')' 410 { 411 $$ = $2; 412 } 413 ; 414 415 integer_expr: 416 integer_trinary 417 ; 418 419 integer_trinary: 420 integer_or 421 | integer_or '?' integer_expr ':' integer_trinary { $$ = $1 ? $3 : $5; } 422 ; 423 424 integer_or: 425 integer_and 426 | integer_or DT_OR integer_and { $$ = $1 || $3; } 427 ; 428 429 integer_and: 430 integer_bitor 431 | integer_and DT_AND integer_bitor { $$ = $1 && $3; } 432 ; 433 434 integer_bitor: 435 integer_bitxor 436 | integer_bitor '|' integer_bitxor { $$ = $1 | $3; } 437 ; 438 439 integer_bitxor: 440 integer_bitand 441 | integer_bitxor '^' integer_bitand { $$ = $1 ^ $3; } 442 ; 443 444 integer_bitand: 445 integer_eq 446 | integer_bitand '&' integer_eq { $$ = $1 & $3; } 447 ; 448 449 integer_eq: 450 integer_rela 451 | integer_eq DT_EQ integer_rela { $$ = $1 == $3; } 452 | integer_eq DT_NE integer_rela { $$ = $1 != $3; } 453 ; 454 455 integer_rela: 456 integer_shift 457 | integer_rela '<' integer_shift { $$ = $1 < $3; } 458 | integer_rela '>' integer_shift { $$ = $1 > $3; } 459 | integer_rela DT_LE integer_shift { $$ = $1 <= $3; } 460 | integer_rela DT_GE integer_shift { $$ = $1 >= $3; } 461 ; 462 463 integer_shift: 464 integer_shift DT_LSHIFT integer_add { $$ = $1 << $3; } 465 | integer_shift DT_RSHIFT integer_add { $$ = $1 >> $3; } 466 | integer_add 467 ; 468 469 integer_add: 470 integer_add '+' integer_mul { $$ = $1 + $3; } 471 | integer_add '-' integer_mul { $$ = $1 - $3; } 472 | integer_mul 473 ; 474 475 integer_mul: 476 integer_mul '*' integer_unary { $$ = $1 * $3; } 477 | integer_mul '/' integer_unary 478 { 479 if ($3 != 0) { 480 $$ = $1 / $3; 481 } else { 482 ERROR(&@$, "Division by zero"); 483 $$ = 0; 484 } 485 } 486 | integer_mul '%' integer_unary 487 { 488 if ($3 != 0) { 489 $$ = $1 % $3; 490 } else { 491 ERROR(&@$, "Division by zero"); 492 $$ = 0; 493 } 494 } 495 | integer_unary 496 ; 497 498 integer_unary: 499 integer_prim 500 | '-' integer_unary { $$ = -$2; } 501 | '~' integer_unary { $$ = ~$2; } 502 | '!' integer_unary { $$ = !$2; } 503 ; 504 505 bytestring: 506 /* empty */ 507 { 508 $$ = data_add_marker(empty_data, TYPE_UINT8, NULL); 509 } 510 | bytestring DT_BYTE 511 { 512 $$ = data_append_byte($1, $2); 513 } 514 | bytestring DT_LABEL 515 { 516 $$ = data_add_marker($1, LABEL, $2); 517 } 518 ; 519 520 subnodes: 521 /* empty */ 522 { 523 $$ = NULL; 524 } 525 | subnode subnodes 526 { 527 $$ = chain_node($1, $2); 528 } 529 | subnode propdef 530 { 531 ERROR(&@2, "Properties must precede subnodes"); 532 YYERROR; 533 } 534 ; 535 536 subnode: 537 DT_PROPNODENAME nodedef 538 { 539 $$ = name_node($2, $1); 540 } 541 | DT_DEL_NODE DT_PROPNODENAME ';' 542 { 543 $$ = name_node(build_node_delete(), $2); 544 } 545 | DT_OMIT_NO_REF subnode 546 { 547 $$ = omit_node_if_unused($2); 548 } 549 | DT_LABEL subnode 550 { 551 add_label(&$2->labels, $1); 552 $$ = $2; 553 } 554 ; 555 556 %% 557 558 void yyerror(char const *s) 559 { 560 ERROR(&yylloc, "%s", s); 561 } 562