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