1204431Sraj/*
2204431Sraj * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005.
3204431Sraj *
4204431Sraj *
5204431Sraj * This program is free software; you can redistribute it and/or
6204431Sraj * modify it under the terms of the GNU General Public License as
7204431Sraj * published by the Free Software Foundation; either version 2 of the
8204431Sraj * License, or (at your option) any later version.
9204431Sraj *
10204431Sraj *  This program is distributed in the hope that it will be useful,
11204431Sraj *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12204431Sraj *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13204431Sraj *  General Public License for more details.
14204431Sraj *
15204431Sraj *  You should have received a copy of the GNU General Public License
16204431Sraj *  along with this program; if not, write to the Free Software
17204431Sraj *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
18204431Sraj *                                                                   USA
19204431Sraj */
20204431Sraj
21204431Sraj%{
22204431Sraj#include <stdio.h>
23204431Sraj
24204431Sraj#include "dtc.h"
25204431Sraj#include "srcpos.h"
26204431Sraj
27204489SrajYYLTYPE yylloc;
28204489Sraj
29204431Srajextern int yylex(void);
30238742Simpextern void print_error(char const *fmt, ...);
31204433Srajextern void yyerror(char const *s);
32204431Sraj
33204431Srajextern struct boot_info *the_boot_info;
34266130Sianextern bool treesource_error;
35204431Sraj%}
36204431Sraj
37204431Sraj%union {
38204431Sraj	char *propnodename;
39204431Sraj	char *labelref;
40204431Sraj	unsigned int cbase;
41204431Sraj	uint8_t byte;
42204431Sraj	struct data data;
43204431Sraj
44238742Simp	struct {
45238742Simp		struct data	data;
46238742Simp		int		bits;
47238742Simp	} array;
48238742Simp
49204431Sraj	struct property *prop;
50204431Sraj	struct property *proplist;
51204431Sraj	struct node *node;
52204431Sraj	struct node *nodelist;
53204431Sraj	struct reserve_info *re;
54238742Simp	uint64_t integer;
55204431Sraj}
56204431Sraj
57204431Sraj%token DT_V1
58204431Sraj%token DT_MEMRESERVE
59238742Simp%token DT_LSHIFT DT_RSHIFT DT_LE DT_GE DT_EQ DT_NE DT_AND DT_OR
60238742Simp%token DT_BITS
61266130Sian%token DT_DEL_PROP
62266130Sian%token DT_DEL_NODE
63204431Sraj%token <propnodename> DT_PROPNODENAME
64266130Sian%token <integer> DT_LITERAL
65266130Sian%token <integer> DT_CHAR_LITERAL
66204431Sraj%token <cbase> DT_BASE
67204431Sraj%token <byte> DT_BYTE
68204431Sraj%token <data> DT_STRING
69204431Sraj%token <labelref> DT_LABEL
70204431Sraj%token <labelref> DT_REF
71204431Sraj%token DT_INCBIN
72204431Sraj
73204431Sraj%type <data> propdata
74204431Sraj%type <data> propdataprefix
75204431Sraj%type <re> memreserve
76204431Sraj%type <re> memreserves
77238742Simp%type <array> arrayprefix
78204431Sraj%type <data> bytestring
79204431Sraj%type <prop> propdef
80204431Sraj%type <proplist> proplist
81204431Sraj
82204431Sraj%type <node> devicetree
83204431Sraj%type <node> nodedef
84204431Sraj%type <node> subnode
85204431Sraj%type <nodelist> subnodes
86204431Sraj
87238742Simp%type <integer> integer_prim
88238742Simp%type <integer> integer_unary
89238742Simp%type <integer> integer_mul
90238742Simp%type <integer> integer_add
91238742Simp%type <integer> integer_shift
92238742Simp%type <integer> integer_rela
93238742Simp%type <integer> integer_eq
94238742Simp%type <integer> integer_bitand
95238742Simp%type <integer> integer_bitxor
96238742Simp%type <integer> integer_bitor
97238742Simp%type <integer> integer_and
98238742Simp%type <integer> integer_or
99238742Simp%type <integer> integer_trinary
100238742Simp%type <integer> integer_expr
101238742Simp
102204431Sraj%%
103204431Sraj
104204431Srajsourcefile:
105204431Sraj	  DT_V1 ';' memreserves devicetree
106204431Sraj		{
107238742Simp			the_boot_info = build_boot_info($3, $4,
108238742Simp							guess_boot_cpuid($4));
109204431Sraj		}
110204431Sraj	;
111204431Sraj
112204431Srajmemreserves:
113204431Sraj	  /* empty */
114204431Sraj		{
115204431Sraj			$$ = NULL;
116204431Sraj		}
117204431Sraj	| memreserve memreserves
118204431Sraj		{
119204431Sraj			$$ = chain_reserve_entry($1, $2);
120204431Sraj		}
121204431Sraj	;
122204431Sraj
123204431Srajmemreserve:
124238742Simp	  DT_MEMRESERVE integer_prim integer_prim ';'
125204431Sraj		{
126238742Simp			$$ = build_reserve_entry($2, $3);
127204431Sraj		}
128238742Simp	| DT_LABEL memreserve
129204431Sraj		{
130238742Simp			add_label(&$2->labels, $1);
131238742Simp			$$ = $2;
132204431Sraj		}
133238742Simp	;
134204431Sraj
135204431Srajdevicetree:
136204431Sraj	  '/' nodedef
137204431Sraj		{
138238742Simp			$$ = name_node($2, "");
139204431Sraj		}
140238742Simp	| devicetree '/' nodedef
141238742Simp		{
142238742Simp			$$ = merge_nodes($1, $3);
143238742Simp		}
144238742Simp	| devicetree DT_REF nodedef
145238742Simp		{
146238742Simp			struct node *target = get_node_by_ref($1, $2);
147238742Simp
148238742Simp			if (target)
149238742Simp				merge_nodes(target, $3);
150238742Simp			else
151238742Simp				print_error("label or path, '%s', not found", $2);
152238742Simp			$$ = $1;
153238742Simp		}
154266130Sian	| devicetree DT_DEL_NODE DT_REF ';'
155266130Sian		{
156266130Sian			struct node *target = get_node_by_ref($1, $3);
157266130Sian
158266130Sian			if (!target)
159266130Sian				print_error("label or path, '%s', not found", $3);
160266130Sian			else
161266130Sian				delete_node(target);
162266130Sian
163266130Sian			$$ = $1;
164266130Sian		}
165204431Sraj	;
166204431Sraj
167204431Srajnodedef:
168204431Sraj	  '{' proplist subnodes '}' ';'
169204431Sraj		{
170204431Sraj			$$ = build_node($2, $3);
171204431Sraj		}
172204431Sraj	;
173204431Sraj
174204431Srajproplist:
175204431Sraj	  /* empty */
176204431Sraj		{
177204431Sraj			$$ = NULL;
178204431Sraj		}
179204431Sraj	| proplist propdef
180204431Sraj		{
181204431Sraj			$$ = chain_property($2, $1);
182204431Sraj		}
183204431Sraj	;
184204431Sraj
185204431Srajpropdef:
186238742Simp	  DT_PROPNODENAME '=' propdata ';'
187204431Sraj		{
188238742Simp			$$ = build_property($1, $3);
189204431Sraj		}
190238742Simp	| DT_PROPNODENAME ';'
191204431Sraj		{
192238742Simp			$$ = build_property($1, empty_data);
193204431Sraj		}
194266130Sian	| DT_DEL_PROP DT_PROPNODENAME ';'
195266130Sian		{
196266130Sian			$$ = build_property_delete($2);
197266130Sian		}
198238742Simp	| DT_LABEL propdef
199238742Simp		{
200238742Simp			add_label(&$2->labels, $1);
201238742Simp			$$ = $2;
202238742Simp		}
203204431Sraj	;
204204431Sraj
205204431Srajpropdata:
206204431Sraj	  propdataprefix DT_STRING
207204431Sraj		{
208204431Sraj			$$ = data_merge($1, $2);
209204431Sraj		}
210238742Simp	| propdataprefix arrayprefix '>'
211204431Sraj		{
212238742Simp			$$ = data_merge($1, $2.data);
213204431Sraj		}
214204431Sraj	| propdataprefix '[' bytestring ']'
215204431Sraj		{
216204431Sraj			$$ = data_merge($1, $3);
217204431Sraj		}
218204431Sraj	| propdataprefix DT_REF
219204431Sraj		{
220204431Sraj			$$ = data_add_marker($1, REF_PATH, $2);
221204431Sraj		}
222238742Simp	| propdataprefix DT_INCBIN '(' DT_STRING ',' integer_prim ',' integer_prim ')'
223204431Sraj		{
224238742Simp			FILE *f = srcfile_relative_open($4.val, NULL);
225238742Simp			struct data d;
226204431Sraj
227204431Sraj			if ($6 != 0)
228238742Simp				if (fseek(f, $6, SEEK_SET) != 0)
229266130Sian					die("Couldn't seek to offset %llu in \"%s\": %s",
230266130Sian					    (unsigned long long)$6, $4.val,
231266130Sian					    strerror(errno));
232204431Sraj
233238742Simp			d = data_copy_file(f, $8);
234204431Sraj
235204431Sraj			$$ = data_merge($1, d);
236238742Simp			fclose(f);
237204431Sraj		}
238204431Sraj	| propdataprefix DT_INCBIN '(' DT_STRING ')'
239204431Sraj		{
240238742Simp			FILE *f = srcfile_relative_open($4.val, NULL);
241204431Sraj			struct data d = empty_data;
242204431Sraj
243238742Simp			d = data_copy_file(f, -1);
244204431Sraj
245204431Sraj			$$ = data_merge($1, d);
246238742Simp			fclose(f);
247204431Sraj		}
248204431Sraj	| propdata DT_LABEL
249204431Sraj		{
250204431Sraj			$$ = data_add_marker($1, LABEL, $2);
251204431Sraj		}
252204431Sraj	;
253204431Sraj
254204431Srajpropdataprefix:
255204431Sraj	  /* empty */
256204431Sraj		{
257204431Sraj			$$ = empty_data;
258204431Sraj		}
259204431Sraj	| propdata ','
260204431Sraj		{
261204431Sraj			$$ = $1;
262204431Sraj		}
263204431Sraj	| propdataprefix DT_LABEL
264204431Sraj		{
265204431Sraj			$$ = data_add_marker($1, LABEL, $2);
266204431Sraj		}
267204431Sraj	;
268204431Sraj
269238742Simparrayprefix:
270238742Simp	DT_BITS DT_LITERAL '<'
271204431Sraj		{
272266130Sian			unsigned long long bits;
273238742Simp
274266130Sian			bits = $2;
275266130Sian
276266130Sian			if ((bits !=  8) && (bits != 16) &&
277266130Sian			    (bits != 32) && (bits != 64))
278238742Simp			{
279238742Simp				print_error("Only 8, 16, 32 and 64-bit elements"
280238742Simp					    " are currently supported");
281266130Sian				bits = 32;
282238742Simp			}
283266130Sian
284266130Sian			$$.data = empty_data;
285266130Sian			$$.bits = bits;
286204431Sraj		}
287238742Simp	| '<'
288204431Sraj		{
289238742Simp			$$.data = empty_data;
290238742Simp			$$.bits = 32;
291204431Sraj		}
292238742Simp	| arrayprefix integer_prim
293204431Sraj		{
294238742Simp			if ($1.bits < 64) {
295238742Simp				uint64_t mask = (1ULL << $1.bits) - 1;
296238742Simp				/*
297238742Simp				 * Bits above mask must either be all zero
298238742Simp				 * (positive within range of mask) or all one
299238742Simp				 * (negative and sign-extended). The second
300238742Simp				 * condition is true if when we set all bits
301238742Simp				 * within the mask to one (i.e. | in the
302238742Simp				 * mask), all bits are one.
303238742Simp				 */
304238742Simp				if (($2 > mask) && (($2 | mask) != -1ULL))
305238742Simp					print_error(
306238742Simp						"integer value out of range "
307238742Simp						"%016lx (%d bits)", $1.bits);
308238742Simp			}
309238742Simp
310238742Simp			$$.data = data_append_integer($1.data, $2, $1.bits);
311204431Sraj		}
312238742Simp	| arrayprefix DT_REF
313204431Sraj		{
314238742Simp			uint64_t val = ~0ULL >> (64 - $1.bits);
315238742Simp
316238742Simp			if ($1.bits == 32)
317238742Simp				$1.data = data_add_marker($1.data,
318238742Simp							  REF_PHANDLE,
319238742Simp							  $2);
320238742Simp			else
321238742Simp				print_error("References are only allowed in "
322238742Simp					    "arrays with 32-bit elements.");
323238742Simp
324238742Simp			$$.data = data_append_integer($1.data, val, $1.bits);
325204431Sraj		}
326238742Simp	| arrayprefix DT_LABEL
327238742Simp		{
328238742Simp			$$.data = data_add_marker($1.data, LABEL, $2);
329238742Simp		}
330204431Sraj	;
331204431Sraj
332238742Simpinteger_prim:
333204431Sraj	  DT_LITERAL
334238742Simp	| DT_CHAR_LITERAL
335238742Simp	| '(' integer_expr ')'
336238742Simp		{
337238742Simp			$$ = $2;
338238742Simp		}
339204431Sraj	;
340204431Sraj
341238742Simpinteger_expr:
342238742Simp	integer_trinary
343238742Simp	;
344238742Simp
345238742Simpinteger_trinary:
346238742Simp	  integer_or
347238742Simp	| integer_or '?' integer_expr ':' integer_trinary { $$ = $1 ? $3 : $5; }
348238742Simp	;
349238742Simp
350238742Simpinteger_or:
351238742Simp	  integer_and
352238742Simp	| integer_or DT_OR integer_and { $$ = $1 || $3; }
353238742Simp	;
354238742Simp
355238742Simpinteger_and:
356238742Simp	  integer_bitor
357238742Simp	| integer_and DT_AND integer_bitor { $$ = $1 && $3; }
358238742Simp	;
359238742Simp
360238742Simpinteger_bitor:
361238742Simp	  integer_bitxor
362238742Simp	| integer_bitor '|' integer_bitxor { $$ = $1 | $3; }
363238742Simp	;
364238742Simp
365238742Simpinteger_bitxor:
366238742Simp	  integer_bitand
367238742Simp	| integer_bitxor '^' integer_bitand { $$ = $1 ^ $3; }
368238742Simp	;
369238742Simp
370238742Simpinteger_bitand:
371238742Simp	  integer_eq
372238742Simp	| integer_bitand '&' integer_eq { $$ = $1 & $3; }
373238742Simp	;
374238742Simp
375238742Simpinteger_eq:
376238742Simp	  integer_rela
377238742Simp	| integer_eq DT_EQ integer_rela { $$ = $1 == $3; }
378238742Simp	| integer_eq DT_NE integer_rela { $$ = $1 != $3; }
379238742Simp	;
380238742Simp
381238742Simpinteger_rela:
382238742Simp	  integer_shift
383238742Simp	| integer_rela '<' integer_shift { $$ = $1 < $3; }
384238742Simp	| integer_rela '>' integer_shift { $$ = $1 > $3; }
385238742Simp	| integer_rela DT_LE integer_shift { $$ = $1 <= $3; }
386238742Simp	| integer_rela DT_GE integer_shift { $$ = $1 >= $3; }
387238742Simp	;
388238742Simp
389238742Simpinteger_shift:
390238742Simp	  integer_shift DT_LSHIFT integer_add { $$ = $1 << $3; }
391238742Simp	| integer_shift DT_RSHIFT integer_add { $$ = $1 >> $3; }
392238742Simp	| integer_add
393238742Simp	;
394238742Simp
395238742Simpinteger_add:
396238742Simp	  integer_add '+' integer_mul { $$ = $1 + $3; }
397238742Simp	| integer_add '-' integer_mul { $$ = $1 - $3; }
398238742Simp	| integer_mul
399238742Simp	;
400238742Simp
401238742Simpinteger_mul:
402238742Simp	  integer_mul '*' integer_unary { $$ = $1 * $3; }
403238742Simp	| integer_mul '/' integer_unary { $$ = $1 / $3; }
404238742Simp	| integer_mul '%' integer_unary { $$ = $1 % $3; }
405238742Simp	| integer_unary
406238742Simp	;
407238742Simp
408238742Simpinteger_unary:
409238742Simp	  integer_prim
410238742Simp	| '-' integer_unary { $$ = -$2; }
411238742Simp	| '~' integer_unary { $$ = ~$2; }
412238742Simp	| '!' integer_unary { $$ = !$2; }
413238742Simp	;
414238742Simp
415204431Srajbytestring:
416204431Sraj	  /* empty */
417204431Sraj		{
418204431Sraj			$$ = empty_data;
419204431Sraj		}
420204431Sraj	| bytestring DT_BYTE
421204431Sraj		{
422204431Sraj			$$ = data_append_byte($1, $2);
423204431Sraj		}
424204431Sraj	| bytestring DT_LABEL
425204431Sraj		{
426204431Sraj			$$ = data_add_marker($1, LABEL, $2);
427204431Sraj		}
428204431Sraj	;
429204431Sraj
430204431Srajsubnodes:
431204431Sraj	  /* empty */
432204431Sraj		{
433204431Sraj			$$ = NULL;
434204431Sraj		}
435238742Simp	| subnode subnodes
436204431Sraj		{
437204431Sraj			$$ = chain_node($1, $2);
438204431Sraj		}
439204431Sraj	| subnode propdef
440204431Sraj		{
441238742Simp			print_error("syntax error: properties must precede subnodes");
442204431Sraj			YYERROR;
443204431Sraj		}
444204431Sraj	;
445204431Sraj
446204431Srajsubnode:
447238742Simp	  DT_PROPNODENAME nodedef
448204431Sraj		{
449238742Simp			$$ = name_node($2, $1);
450204431Sraj		}
451266130Sian	| DT_DEL_NODE DT_PROPNODENAME ';'
452266130Sian		{
453266130Sian			$$ = name_node(build_node_delete(), $2);
454266130Sian		}
455238742Simp	| DT_LABEL subnode
456204431Sraj		{
457238742Simp			add_label(&$2->labels, $1);
458238742Simp			$$ = $2;
459204431Sraj		}
460204431Sraj	;
461204431Sraj
462204431Sraj%%
463204431Sraj
464238742Simpvoid print_error(char const *fmt, ...)
465204431Sraj{
466238742Simp	va_list va;
467238742Simp
468238742Simp	va_start(va, fmt);
469266130Sian	srcpos_verror(&yylloc, "Error", fmt, va);
470238742Simp	va_end(va);
471238742Simp
472266130Sian	treesource_error = true;
473204431Sraj}
474204431Sraj
475238742Simpvoid yyerror(char const *s) {
476238742Simp	print_error("%s", s);
477238742Simp}
478