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