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