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