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