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