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