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