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 344 bits = $2; 345 346 if ((bits != 8) && (bits != 16) && 347 (bits != 32) && (bits != 64)) { 348 ERROR(&@2, "Array elements must be" 349 " 8, 16, 32 or 64-bits"); 350 bits = 32; 351 } 352 353 $$.data = empty_data; 354 $$.bits = bits; 355 } 356 | '<' 357 { 358 $$.data = empty_data; 359 $$.bits = 32; 360 } 361 | arrayprefix integer_prim 362 { 363 if ($1.bits < 64) { 364 uint64_t mask = (1ULL << $1.bits) - 1; 365 /* 366 * Bits above mask must either be all zero 367 * (positive within range of mask) or all one 368 * (negative and sign-extended). The second 369 * condition is true if when we set all bits 370 * within the mask to one (i.e. | in the 371 * mask), all bits are one. 372 */ 373 if (($2 > mask) && (($2 | mask) != -1ULL)) 374 ERROR(&@2, "Value out of range for" 375 " %d-bit array element", $1.bits); 376 } 377 378 $$.data = data_append_integer($1.data, $2, $1.bits); 379 } 380 | arrayprefix DT_REF 381 { 382 uint64_t val = ~0ULL >> (64 - $1.bits); 383 384 if ($1.bits == 32) 385 $1.data = data_add_marker($1.data, 386 REF_PHANDLE, 387 $2); 388 else 389 ERROR(&@2, "References are only allowed in " 390 "arrays with 32-bit elements."); 391 392 $$.data = data_append_integer($1.data, val, $1.bits); 393 } 394 | arrayprefix DT_LABEL 395 { 396 $$.data = data_add_marker($1.data, LABEL, $2); 397 } 398 ; 399 400 integer_prim: 401 DT_LITERAL 402 | DT_CHAR_LITERAL 403 | '(' integer_expr ')' 404 { 405 $$ = $2; 406 } 407 ; 408 409 integer_expr: 410 integer_trinary 411 ; 412 413 integer_trinary: 414 integer_or 415 | integer_or '?' integer_expr ':' integer_trinary { $$ = $1 ? $3 : $5; } 416 ; 417 418 integer_or: 419 integer_and 420 | integer_or DT_OR integer_and { $$ = $1 || $3; } 421 ; 422 423 integer_and: 424 integer_bitor 425 | integer_and DT_AND integer_bitor { $$ = $1 && $3; } 426 ; 427 428 integer_bitor: 429 integer_bitxor 430 | integer_bitor '|' integer_bitxor { $$ = $1 | $3; } 431 ; 432 433 integer_bitxor: 434 integer_bitand 435 | integer_bitxor '^' integer_bitand { $$ = $1 ^ $3; } 436 ; 437 438 integer_bitand: 439 integer_eq 440 | integer_bitand '&' integer_eq { $$ = $1 & $3; } 441 ; 442 443 integer_eq: 444 integer_rela 445 | integer_eq DT_EQ integer_rela { $$ = $1 == $3; } 446 | integer_eq DT_NE integer_rela { $$ = $1 != $3; } 447 ; 448 449 integer_rela: 450 integer_shift 451 | integer_rela '<' integer_shift { $$ = $1 < $3; } 452 | integer_rela '>' integer_shift { $$ = $1 > $3; } 453 | integer_rela DT_LE integer_shift { $$ = $1 <= $3; } 454 | integer_rela DT_GE integer_shift { $$ = $1 >= $3; } 455 ; 456 457 integer_shift: 458 integer_shift DT_LSHIFT integer_add { $$ = $1 << $3; } 459 | integer_shift DT_RSHIFT integer_add { $$ = $1 >> $3; } 460 | integer_add 461 ; 462 463 integer_add: 464 integer_add '+' integer_mul { $$ = $1 + $3; } 465 | integer_add '-' integer_mul { $$ = $1 - $3; } 466 | integer_mul 467 ; 468 469 integer_mul: 470 integer_mul '*' integer_unary { $$ = $1 * $3; } 471 | integer_mul '/' integer_unary 472 { 473 if ($3 != 0) { 474 $$ = $1 / $3; 475 } else { 476 ERROR(&@$, "Division by zero"); 477 $$ = 0; 478 } 479 } 480 | integer_mul '%' integer_unary 481 { 482 if ($3 != 0) { 483 $$ = $1 % $3; 484 } else { 485 ERROR(&@$, "Division by zero"); 486 $$ = 0; 487 } 488 } 489 | integer_unary 490 ; 491 492 integer_unary: 493 integer_prim 494 | '-' integer_unary { $$ = -$2; } 495 | '~' integer_unary { $$ = ~$2; } 496 | '!' integer_unary { $$ = !$2; } 497 ; 498 499 bytestring: 500 /* empty */ 501 { 502 $$ = empty_data; 503 } 504 | bytestring DT_BYTE 505 { 506 $$ = data_append_byte($1, $2); 507 } 508 | bytestring DT_LABEL 509 { 510 $$ = data_add_marker($1, LABEL, $2); 511 } 512 ; 513 514 subnodes: 515 /* empty */ 516 { 517 $$ = NULL; 518 } 519 | subnode subnodes 520 { 521 $$ = chain_node($1, $2); 522 } 523 | subnode propdef 524 { 525 ERROR(&@2, "Properties must precede subnodes"); 526 YYERROR; 527 } 528 ; 529 530 subnode: 531 DT_PROPNODENAME nodedef 532 { 533 $$ = name_node($2, $1); 534 } 535 | DT_DEL_NODE DT_PROPNODENAME ';' 536 { 537 $$ = name_node(build_node_delete(), $2); 538 } 539 | DT_OMIT_NO_REF subnode 540 { 541 $$ = omit_node_if_unused($2); 542 } 543 | DT_LABEL subnode 544 { 545 add_label(&$2->labels, $1); 546 $$ = $2; 547 } 548 ; 549 550 %% 551 552 void yyerror(char const *s) 553 { 554 ERROR(&yylloc, "%s", s); 555 } 556