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 				/*
189 				 * We rely on the rule being always:
190 				 *   versioninfo plugindecl memreserves devicetree
191 				 * so $-1 is what we want (plugindecl)
192 				 */
193 				if ($<flags>-1 & DTSF_PLUGIN)
194 					add_orphan_node($1, $3, $2);
195 				else
196 					ERROR(&@2, "Label or path %s not found", $2);
197 			}
198 			$$ = $1;
199 		}
200 	| devicetree DT_DEL_NODE DT_REF ';'
201 		{
202 			struct node *target = get_node_by_ref($1, $3);
203 
204 			if (target)
205 				delete_node(target);
206 			else
207 				ERROR(&@3, "Label or path %s not found", $3);
208 
209 
210 			$$ = $1;
211 		}
212 	| /* empty */
213 		{
214 			/* build empty node */
215 			$$ = name_node(build_node(NULL, NULL), "");
216 		}
217 	;
218 
219 nodedef:
220 	  '{' proplist subnodes '}' ';'
221 		{
222 			$$ = build_node($2, $3);
223 		}
224 	;
225 
226 proplist:
227 	  /* empty */
228 		{
229 			$$ = NULL;
230 		}
231 	| proplist propdef
232 		{
233 			$$ = chain_property($2, $1);
234 		}
235 	;
236 
237 propdef:
238 	  DT_PROPNODENAME '=' propdata ';'
239 		{
240 			$$ = build_property($1, $3);
241 		}
242 	| DT_PROPNODENAME ';'
243 		{
244 			$$ = build_property($1, empty_data);
245 		}
246 	| DT_DEL_PROP DT_PROPNODENAME ';'
247 		{
248 			$$ = build_property_delete($2);
249 		}
250 	| DT_LABEL propdef
251 		{
252 			add_label(&$2->labels, $1);
253 			$$ = $2;
254 		}
255 	;
256 
257 propdata:
258 	  propdataprefix DT_STRING
259 		{
260 			$$ = data_merge($1, $2);
261 		}
262 	| propdataprefix arrayprefix '>'
263 		{
264 			$$ = data_merge($1, $2.data);
265 		}
266 	| propdataprefix '[' bytestring ']'
267 		{
268 			$$ = data_merge($1, $3);
269 		}
270 	| propdataprefix DT_REF
271 		{
272 			$$ = data_add_marker($1, REF_PATH, $2);
273 		}
274 	| propdataprefix DT_INCBIN '(' DT_STRING ',' integer_prim ',' integer_prim ')'
275 		{
276 			FILE *f = srcfile_relative_open($4.val, NULL);
277 			struct data d;
278 
279 			if ($6 != 0)
280 				if (fseek(f, $6, SEEK_SET) != 0)
281 					die("Couldn't seek to offset %llu in \"%s\": %s",
282 					    (unsigned long long)$6, $4.val,
283 					    strerror(errno));
284 
285 			d = data_copy_file(f, $8);
286 
287 			$$ = data_merge($1, d);
288 			fclose(f);
289 		}
290 	| propdataprefix DT_INCBIN '(' DT_STRING ')'
291 		{
292 			FILE *f = srcfile_relative_open($4.val, NULL);
293 			struct data d = empty_data;
294 
295 			d = data_copy_file(f, -1);
296 
297 			$$ = data_merge($1, d);
298 			fclose(f);
299 		}
300 	| propdata DT_LABEL
301 		{
302 			$$ = data_add_marker($1, LABEL, $2);
303 		}
304 	;
305 
306 propdataprefix:
307 	  /* empty */
308 		{
309 			$$ = empty_data;
310 		}
311 	| propdata ','
312 		{
313 			$$ = $1;
314 		}
315 	| propdataprefix DT_LABEL
316 		{
317 			$$ = data_add_marker($1, LABEL, $2);
318 		}
319 	;
320 
321 arrayprefix:
322 	DT_BITS DT_LITERAL '<'
323 		{
324 			unsigned long long bits;
325 
326 			bits = $2;
327 
328 			if ((bits !=  8) && (bits != 16) &&
329 			    (bits != 32) && (bits != 64)) {
330 				ERROR(&@2, "Array elements must be"
331 				      " 8, 16, 32 or 64-bits");
332 				bits = 32;
333 			}
334 
335 			$$.data = empty_data;
336 			$$.bits = bits;
337 		}
338 	| '<'
339 		{
340 			$$.data = empty_data;
341 			$$.bits = 32;
342 		}
343 	| arrayprefix integer_prim
344 		{
345 			if ($1.bits < 64) {
346 				uint64_t mask = (1ULL << $1.bits) - 1;
347 				/*
348 				 * Bits above mask must either be all zero
349 				 * (positive within range of mask) or all one
350 				 * (negative and sign-extended). The second
351 				 * condition is true if when we set all bits
352 				 * within the mask to one (i.e. | in the
353 				 * mask), all bits are one.
354 				 */
355 				if (($2 > mask) && (($2 | mask) != -1ULL))
356 					ERROR(&@2, "Value out of range for"
357 					      " %d-bit array element", $1.bits);
358 			}
359 
360 			$$.data = data_append_integer($1.data, $2, $1.bits);
361 		}
362 	| arrayprefix DT_REF
363 		{
364 			uint64_t val = ~0ULL >> (64 - $1.bits);
365 
366 			if ($1.bits == 32)
367 				$1.data = data_add_marker($1.data,
368 							  REF_PHANDLE,
369 							  $2);
370 			else
371 				ERROR(&@2, "References are only allowed in "
372 					    "arrays with 32-bit elements.");
373 
374 			$$.data = data_append_integer($1.data, val, $1.bits);
375 		}
376 	| arrayprefix DT_LABEL
377 		{
378 			$$.data = data_add_marker($1.data, LABEL, $2);
379 		}
380 	;
381 
382 integer_prim:
383 	  DT_LITERAL
384 	| DT_CHAR_LITERAL
385 	| '(' integer_expr ')'
386 		{
387 			$$ = $2;
388 		}
389 	;
390 
391 integer_expr:
392 	integer_trinary
393 	;
394 
395 integer_trinary:
396 	  integer_or
397 	| integer_or '?' integer_expr ':' integer_trinary { $$ = $1 ? $3 : $5; }
398 	;
399 
400 integer_or:
401 	  integer_and
402 	| integer_or DT_OR integer_and { $$ = $1 || $3; }
403 	;
404 
405 integer_and:
406 	  integer_bitor
407 	| integer_and DT_AND integer_bitor { $$ = $1 && $3; }
408 	;
409 
410 integer_bitor:
411 	  integer_bitxor
412 	| integer_bitor '|' integer_bitxor { $$ = $1 | $3; }
413 	;
414 
415 integer_bitxor:
416 	  integer_bitand
417 	| integer_bitxor '^' integer_bitand { $$ = $1 ^ $3; }
418 	;
419 
420 integer_bitand:
421 	  integer_eq
422 	| integer_bitand '&' integer_eq { $$ = $1 & $3; }
423 	;
424 
425 integer_eq:
426 	  integer_rela
427 	| integer_eq DT_EQ integer_rela { $$ = $1 == $3; }
428 	| integer_eq DT_NE integer_rela { $$ = $1 != $3; }
429 	;
430 
431 integer_rela:
432 	  integer_shift
433 	| integer_rela '<' integer_shift { $$ = $1 < $3; }
434 	| integer_rela '>' integer_shift { $$ = $1 > $3; }
435 	| integer_rela DT_LE integer_shift { $$ = $1 <= $3; }
436 	| integer_rela DT_GE integer_shift { $$ = $1 >= $3; }
437 	;
438 
439 integer_shift:
440 	  integer_shift DT_LSHIFT integer_add { $$ = $1 << $3; }
441 	| integer_shift DT_RSHIFT integer_add { $$ = $1 >> $3; }
442 	| integer_add
443 	;
444 
445 integer_add:
446 	  integer_add '+' integer_mul { $$ = $1 + $3; }
447 	| integer_add '-' integer_mul { $$ = $1 - $3; }
448 	| integer_mul
449 	;
450 
451 integer_mul:
452 	  integer_mul '*' integer_unary { $$ = $1 * $3; }
453 	| integer_mul '/' integer_unary
454 		{
455 			if ($3 != 0) {
456 				$$ = $1 / $3;
457 			} else {
458 				ERROR(&@$, "Division by zero");
459 				$$ = 0;
460 			}
461 		}
462 	| integer_mul '%' integer_unary
463 		{
464 			if ($3 != 0) {
465 				$$ = $1 % $3;
466 			} else {
467 				ERROR(&@$, "Division by zero");
468 				$$ = 0;
469 			}
470 		}
471 	| integer_unary
472 	;
473 
474 integer_unary:
475 	  integer_prim
476 	| '-' integer_unary { $$ = -$2; }
477 	| '~' integer_unary { $$ = ~$2; }
478 	| '!' integer_unary { $$ = !$2; }
479 	;
480 
481 bytestring:
482 	  /* empty */
483 		{
484 			$$ = empty_data;
485 		}
486 	| bytestring DT_BYTE
487 		{
488 			$$ = data_append_byte($1, $2);
489 		}
490 	| bytestring DT_LABEL
491 		{
492 			$$ = data_add_marker($1, LABEL, $2);
493 		}
494 	;
495 
496 subnodes:
497 	  /* empty */
498 		{
499 			$$ = NULL;
500 		}
501 	| subnode subnodes
502 		{
503 			$$ = chain_node($1, $2);
504 		}
505 	| subnode propdef
506 		{
507 			ERROR(&@2, "Properties must precede subnodes");
508 			YYERROR;
509 		}
510 	;
511 
512 subnode:
513 	  DT_PROPNODENAME nodedef
514 		{
515 			$$ = name_node($2, $1);
516 		}
517 	| DT_DEL_NODE DT_PROPNODENAME ';'
518 		{
519 			$$ = name_node(build_node_delete(), $2);
520 		}
521 	| DT_LABEL subnode
522 		{
523 			add_label(&$2->labels, $1);
524 			$$ = $2;
525 		}
526 	;
527 
528 %%
529 
530 void yyerror(char const *s)
531 {
532 	ERROR(&yylloc, "%s", s);
533 }
534