xref: /openbmc/u-boot/scripts/dtc/dtc-parser.y (revision c68c03f5)
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