xref: /openbmc/linux/scripts/dtc/dtc-parser.y (revision 4800cd83)
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 
27 YYLTYPE yylloc;
28 
29 extern int yylex(void);
30 extern void print_error(char const *fmt, ...);
31 extern void yyerror(char const *s);
32 
33 extern struct boot_info *the_boot_info;
34 extern int treesource_error;
35 
36 static unsigned long long eval_literal(const char *s, int base, int bits);
37 %}
38 
39 %union {
40 	char *propnodename;
41 	char *literal;
42 	char *labelref;
43 	unsigned int cbase;
44 	uint8_t byte;
45 	struct data data;
46 
47 	uint64_t addr;
48 	cell_t cell;
49 	struct property *prop;
50 	struct property *proplist;
51 	struct node *node;
52 	struct node *nodelist;
53 	struct reserve_info *re;
54 }
55 
56 %token DT_V1
57 %token DT_MEMRESERVE
58 %token <propnodename> DT_PROPNODENAME
59 %token <literal> DT_LITERAL
60 %token <cbase> DT_BASE
61 %token <byte> DT_BYTE
62 %token <data> DT_STRING
63 %token <labelref> DT_LABEL
64 %token <labelref> DT_REF
65 %token DT_INCBIN
66 
67 %type <data> propdata
68 %type <data> propdataprefix
69 %type <re> memreserve
70 %type <re> memreserves
71 %type <addr> addr
72 %type <data> celllist
73 %type <cell> cellval
74 %type <data> bytestring
75 %type <prop> propdef
76 %type <proplist> proplist
77 
78 %type <node> devicetree
79 %type <node> nodedef
80 %type <node> subnode
81 %type <nodelist> subnodes
82 
83 %%
84 
85 sourcefile:
86 	  DT_V1 ';' memreserves devicetree
87 		{
88 			the_boot_info = build_boot_info($3, $4,
89 							guess_boot_cpuid($4));
90 		}
91 	;
92 
93 memreserves:
94 	  /* empty */
95 		{
96 			$$ = NULL;
97 		}
98 	| memreserve memreserves
99 		{
100 			$$ = chain_reserve_entry($1, $2);
101 		}
102 	;
103 
104 memreserve:
105 	  DT_MEMRESERVE addr addr ';'
106 		{
107 			$$ = build_reserve_entry($2, $3);
108 		}
109 	| DT_LABEL memreserve
110 		{
111 			add_label(&$2->labels, $1);
112 			$$ = $2;
113 		}
114 	;
115 
116 addr:
117 	  DT_LITERAL
118 		{
119 			$$ = eval_literal($1, 0, 64);
120 		}
121 	  ;
122 
123 devicetree:
124 	  '/' nodedef
125 		{
126 			$$ = name_node($2, "");
127 		}
128 	| devicetree '/' nodedef
129 		{
130 			$$ = merge_nodes($1, $3);
131 		}
132 	| devicetree DT_REF nodedef
133 		{
134 			struct node *target = get_node_by_ref($1, $2);
135 
136 			if (target)
137 				merge_nodes(target, $3);
138 			else
139 				print_error("label or path, '%s', not found", $2);
140 			$$ = $1;
141 		}
142 	;
143 
144 nodedef:
145 	  '{' proplist subnodes '}' ';'
146 		{
147 			$$ = build_node($2, $3);
148 		}
149 	;
150 
151 proplist:
152 	  /* empty */
153 		{
154 			$$ = NULL;
155 		}
156 	| proplist propdef
157 		{
158 			$$ = chain_property($2, $1);
159 		}
160 	;
161 
162 propdef:
163 	  DT_PROPNODENAME '=' propdata ';'
164 		{
165 			$$ = build_property($1, $3);
166 		}
167 	| DT_PROPNODENAME ';'
168 		{
169 			$$ = build_property($1, empty_data);
170 		}
171 	| DT_LABEL propdef
172 		{
173 			add_label(&$2->labels, $1);
174 			$$ = $2;
175 		}
176 	;
177 
178 propdata:
179 	  propdataprefix DT_STRING
180 		{
181 			$$ = data_merge($1, $2);
182 		}
183 	| propdataprefix '<' celllist '>'
184 		{
185 			$$ = data_merge($1, $3);
186 		}
187 	| propdataprefix '[' bytestring ']'
188 		{
189 			$$ = data_merge($1, $3);
190 		}
191 	| propdataprefix DT_REF
192 		{
193 			$$ = data_add_marker($1, REF_PATH, $2);
194 		}
195 	| propdataprefix DT_INCBIN '(' DT_STRING ',' addr ',' addr ')'
196 		{
197 			FILE *f = srcfile_relative_open($4.val, NULL);
198 			struct data d;
199 
200 			if ($6 != 0)
201 				if (fseek(f, $6, SEEK_SET) != 0)
202 					print_error("Couldn't seek to offset %llu in \"%s\": %s",
203 						     (unsigned long long)$6,
204 						     $4.val,
205 						     strerror(errno));
206 
207 			d = data_copy_file(f, $8);
208 
209 			$$ = data_merge($1, d);
210 			fclose(f);
211 		}
212 	| propdataprefix DT_INCBIN '(' DT_STRING ')'
213 		{
214 			FILE *f = srcfile_relative_open($4.val, NULL);
215 			struct data d = empty_data;
216 
217 			d = data_copy_file(f, -1);
218 
219 			$$ = data_merge($1, d);
220 			fclose(f);
221 		}
222 	| propdata DT_LABEL
223 		{
224 			$$ = data_add_marker($1, LABEL, $2);
225 		}
226 	;
227 
228 propdataprefix:
229 	  /* empty */
230 		{
231 			$$ = empty_data;
232 		}
233 	| propdata ','
234 		{
235 			$$ = $1;
236 		}
237 	| propdataprefix DT_LABEL
238 		{
239 			$$ = data_add_marker($1, LABEL, $2);
240 		}
241 	;
242 
243 celllist:
244 	  /* empty */
245 		{
246 			$$ = empty_data;
247 		}
248 	| celllist cellval
249 		{
250 			$$ = data_append_cell($1, $2);
251 		}
252 	| celllist DT_REF
253 		{
254 			$$ = data_append_cell(data_add_marker($1, REF_PHANDLE,
255 							      $2), -1);
256 		}
257 	| celllist DT_LABEL
258 		{
259 			$$ = data_add_marker($1, LABEL, $2);
260 		}
261 	;
262 
263 cellval:
264 	  DT_LITERAL
265 		{
266 			$$ = eval_literal($1, 0, 32);
267 		}
268 	;
269 
270 bytestring:
271 	  /* empty */
272 		{
273 			$$ = empty_data;
274 		}
275 	| bytestring DT_BYTE
276 		{
277 			$$ = data_append_byte($1, $2);
278 		}
279 	| bytestring DT_LABEL
280 		{
281 			$$ = data_add_marker($1, LABEL, $2);
282 		}
283 	;
284 
285 subnodes:
286 	  /* empty */
287 		{
288 			$$ = NULL;
289 		}
290 	| subnode subnodes
291 		{
292 			$$ = chain_node($1, $2);
293 		}
294 	| subnode propdef
295 		{
296 			print_error("syntax error: properties must precede subnodes");
297 			YYERROR;
298 		}
299 	;
300 
301 subnode:
302 	  DT_PROPNODENAME nodedef
303 		{
304 			$$ = name_node($2, $1);
305 		}
306 	| DT_LABEL subnode
307 		{
308 			add_label(&$2->labels, $1);
309 			$$ = $2;
310 		}
311 	;
312 
313 %%
314 
315 void print_error(char const *fmt, ...)
316 {
317 	va_list va;
318 
319 	va_start(va, fmt);
320 	srcpos_verror(&yylloc, fmt, va);
321 	va_end(va);
322 
323 	treesource_error = 1;
324 }
325 
326 void yyerror(char const *s) {
327 	print_error("%s", s);
328 }
329 
330 static unsigned long long eval_literal(const char *s, int base, int bits)
331 {
332 	unsigned long long val;
333 	char *e;
334 
335 	errno = 0;
336 	val = strtoull(s, &e, base);
337 	if (*e)
338 		print_error("bad characters in literal");
339 	else if ((errno == ERANGE)
340 		 || ((bits < 64) && (val >= (1ULL << bits))))
341 		print_error("literal out of range");
342 	else if (errno != 0)
343 		print_error("bad literal");
344 	return val;
345 }
346