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