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