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