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