xref: /freebsd-12.1/contrib/dtc/dtc-parser.y (revision 4ad16323)
1 /*
2  * (C) Copyright David Gibson <[email protected]>, 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 YYLTYPE yylloc;
28 
29 extern int yylex(void);
30 extern 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 
37 extern struct dt_info *parser_output;
38 extern 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 
110 sourcefile:
111 	  headers memreserves devicetree
112 		{
113 			parser_output = build_dt_info($1, $2, $3,
114 			                              guess_boot_cpuid($3));
115 		}
116 	;
117 
118 header:
119 	  DT_V1 ';'
120 		{
121 			$$ = DTSF_V1;
122 		}
123 	| DT_V1 ';' DT_PLUGIN ';'
124 		{
125 			$$ = DTSF_V1 | DTSF_PLUGIN;
126 		}
127 	;
128 
129 headers:
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 
139 memreserves:
140 	  /* empty */
141 		{
142 			$$ = NULL;
143 		}
144 	| memreserve memreserves
145 		{
146 			$$ = chain_reserve_entry($1, $2);
147 		}
148 	;
149 
150 memreserve:
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 
162 devicetree:
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 
207 nodedef:
208 	  '{' proplist subnodes '}' ';'
209 		{
210 			$$ = build_node($2, $3);
211 		}
212 	;
213 
214 proplist:
215 	  /* empty */
216 		{
217 			$$ = NULL;
218 		}
219 	| proplist propdef
220 		{
221 			$$ = chain_property($2, $1);
222 		}
223 	;
224 
225 propdef:
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 
245 propdata:
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 
294 propdataprefix:
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 
309 arrayprefix:
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 
370 integer_prim:
371 	  DT_LITERAL
372 	| DT_CHAR_LITERAL
373 	| '(' integer_expr ')'
374 		{
375 			$$ = $2;
376 		}
377 	;
378 
379 integer_expr:
380 	integer_trinary
381 	;
382 
383 integer_trinary:
384 	  integer_or
385 	| integer_or '?' integer_expr ':' integer_trinary { $$ = $1 ? $3 : $5; }
386 	;
387 
388 integer_or:
389 	  integer_and
390 	| integer_or DT_OR integer_and { $$ = $1 || $3; }
391 	;
392 
393 integer_and:
394 	  integer_bitor
395 	| integer_and DT_AND integer_bitor { $$ = $1 && $3; }
396 	;
397 
398 integer_bitor:
399 	  integer_bitxor
400 	| integer_bitor '|' integer_bitxor { $$ = $1 | $3; }
401 	;
402 
403 integer_bitxor:
404 	  integer_bitand
405 	| integer_bitxor '^' integer_bitand { $$ = $1 ^ $3; }
406 	;
407 
408 integer_bitand:
409 	  integer_eq
410 	| integer_bitand '&' integer_eq { $$ = $1 & $3; }
411 	;
412 
413 integer_eq:
414 	  integer_rela
415 	| integer_eq DT_EQ integer_rela { $$ = $1 == $3; }
416 	| integer_eq DT_NE integer_rela { $$ = $1 != $3; }
417 	;
418 
419 integer_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 
427 integer_shift:
428 	  integer_shift DT_LSHIFT integer_add { $$ = $1 << $3; }
429 	| integer_shift DT_RSHIFT integer_add { $$ = $1 >> $3; }
430 	| integer_add
431 	;
432 
433 integer_add:
434 	  integer_add '+' integer_mul { $$ = $1 + $3; }
435 	| integer_add '-' integer_mul { $$ = $1 - $3; }
436 	| integer_mul
437 	;
438 
439 integer_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 
462 integer_unary:
463 	  integer_prim
464 	| '-' integer_unary { $$ = -$2; }
465 	| '~' integer_unary { $$ = ~$2; }
466 	| '!' integer_unary { $$ = !$2; }
467 	;
468 
469 bytestring:
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 
484 subnodes:
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 
500 subnode:
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 
518 void yyerror(char const *s)
519 {
520 	ERROR(&yylloc, "%s", s);
521 }
522