Commit | Line | Data |
---|---|---|
a4da2e3e DG |
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 | ||
a4da2e3e | 21 | %{ |
ed95d745 DG |
22 | #include <stdio.h> |
23 | ||
a4da2e3e DG |
24 | #include "dtc.h" |
25 | #include "srcpos.h" | |
26 | ||
658f29a5 JB |
27 | YYLTYPE yylloc; |
28 | ||
ed95d745 | 29 | extern int yylex(void); |
658f29a5 JB |
30 | extern void print_error(char const *fmt, ...); |
31 | extern void yyerror(char const *s); | |
a4da2e3e DG |
32 | |
33 | extern struct boot_info *the_boot_info; | |
ed95d745 | 34 | extern int treesource_error; |
a4da2e3e | 35 | |
ed95d745 | 36 | static unsigned long long eval_literal(const char *s, int base, int bits); |
a4da2e3e DG |
37 | %} |
38 | ||
39 | %union { | |
40 | char *propnodename; | |
41 | char *literal; | |
42 | char *labelref; | |
43 | unsigned int cbase; | |
ed95d745 | 44 | uint8_t byte; |
a4da2e3e DG |
45 | struct data data; |
46 | ||
ed95d745 | 47 | uint64_t addr; |
a4da2e3e DG |
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 | |
a4da2e3e DG |
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 | |
ed95d745 | 65 | %token DT_INCBIN |
a4da2e3e DG |
66 | |
67 | %type <data> propdata | |
68 | %type <data> propdataprefix | |
69 | %type <re> memreserve | |
70 | %type <re> memreserves | |
a4da2e3e DG |
71 | %type <addr> addr |
72 | %type <data> celllist | |
a4da2e3e DG |
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 | |
a4da2e3e DG |
82 | |
83 | %% | |
84 | ||
85 | sourcefile: | |
86 | DT_V1 ';' memreserves devicetree | |
87 | { | |
658f29a5 JB |
88 | the_boot_info = build_boot_info($3, $4, |
89 | guess_boot_cpuid($4)); | |
a4da2e3e DG |
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: | |
658f29a5 | 105 | DT_MEMRESERVE addr addr ';' |
a4da2e3e | 106 | { |
658f29a5 | 107 | $$ = build_reserve_entry($2, $3); |
a4da2e3e | 108 | } |
658f29a5 | 109 | | DT_LABEL memreserve |
a4da2e3e | 110 | { |
658f29a5 JB |
111 | add_label(&$2->labels, $1); |
112 | $$ = $2; | |
a4da2e3e DG |
113 | } |
114 | ; | |
115 | ||
116 | addr: | |
117 | DT_LITERAL | |
118 | { | |
119 | $$ = eval_literal($1, 0, 64); | |
120 | } | |
a4da2e3e DG |
121 | ; |
122 | ||
123 | devicetree: | |
124 | '/' nodedef | |
125 | { | |
658f29a5 JB |
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; | |
a4da2e3e DG |
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: | |
658f29a5 JB |
163 | DT_PROPNODENAME '=' propdata ';' |
164 | { | |
165 | $$ = build_property($1, $3); | |
166 | } | |
167 | | DT_PROPNODENAME ';' | |
a4da2e3e | 168 | { |
658f29a5 | 169 | $$ = build_property($1, empty_data); |
a4da2e3e | 170 | } |
658f29a5 | 171 | | DT_LABEL propdef |
a4da2e3e | 172 | { |
658f29a5 JB |
173 | add_label(&$2->labels, $1); |
174 | $$ = $2; | |
a4da2e3e DG |
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 | } | |
ed95d745 DG |
195 | | propdataprefix DT_INCBIN '(' DT_STRING ',' addr ',' addr ')' |
196 | { | |
658f29a5 JB |
197 | FILE *f = srcfile_relative_open($4.val, NULL); |
198 | struct data d; | |
ed95d745 DG |
199 | |
200 | if ($6 != 0) | |
658f29a5 JB |
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)); | |
ed95d745 | 206 | |
658f29a5 | 207 | d = data_copy_file(f, $8); |
ed95d745 DG |
208 | |
209 | $$ = data_merge($1, d); | |
658f29a5 | 210 | fclose(f); |
ed95d745 DG |
211 | } |
212 | | propdataprefix DT_INCBIN '(' DT_STRING ')' | |
213 | { | |
658f29a5 | 214 | FILE *f = srcfile_relative_open($4.val, NULL); |
ed95d745 DG |
215 | struct data d = empty_data; |
216 | ||
658f29a5 | 217 | d = data_copy_file(f, -1); |
ed95d745 DG |
218 | |
219 | $$ = data_merge($1, d); | |
658f29a5 | 220 | fclose(f); |
ed95d745 | 221 | } |
a4da2e3e DG |
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 | ||
a4da2e3e DG |
263 | cellval: |
264 | DT_LITERAL | |
265 | { | |
266 | $$ = eval_literal($1, 0, 32); | |
267 | } | |
a4da2e3e DG |
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 | } | |
658f29a5 | 290 | | subnode subnodes |
a4da2e3e DG |
291 | { |
292 | $$ = chain_node($1, $2); | |
293 | } | |
294 | | subnode propdef | |
295 | { | |
658f29a5 | 296 | print_error("syntax error: properties must precede subnodes"); |
a4da2e3e DG |
297 | YYERROR; |
298 | } | |
299 | ; | |
300 | ||
301 | subnode: | |
658f29a5 | 302 | DT_PROPNODENAME nodedef |
a4da2e3e | 303 | { |
658f29a5 | 304 | $$ = name_node($2, $1); |
a4da2e3e | 305 | } |
658f29a5 | 306 | | DT_LABEL subnode |
a4da2e3e | 307 | { |
658f29a5 JB |
308 | add_label(&$2->labels, $1); |
309 | $$ = $2; | |
a4da2e3e DG |
310 | } |
311 | ; | |
312 | ||
313 | %% | |
314 | ||
658f29a5 | 315 | void print_error(char const *fmt, ...) |
a4da2e3e | 316 | { |
ed95d745 | 317 | va_list va; |
a4da2e3e | 318 | |
658f29a5 JB |
319 | va_start(va, fmt); |
320 | srcpos_verror(&yylloc, fmt, va); | |
321 | va_end(va); | |
ed95d745 DG |
322 | |
323 | treesource_error = 1; | |
ed95d745 DG |
324 | } |
325 | ||
658f29a5 JB |
326 | void yyerror(char const *s) { |
327 | print_error("%s", s); | |
a4da2e3e DG |
328 | } |
329 | ||
ed95d745 | 330 | static unsigned long long eval_literal(const char *s, int base, int bits) |
a4da2e3e DG |
331 | { |
332 | unsigned long long val; | |
333 | char *e; | |
334 | ||
335 | errno = 0; | |
336 | val = strtoull(s, &e, base); | |
337 | if (*e) | |
658f29a5 | 338 | print_error("bad characters in literal"); |
a4da2e3e DG |
339 | else if ((errno == ERANGE) |
340 | || ((bits < 64) && (val >= (1ULL << bits)))) | |
658f29a5 | 341 | print_error("literal out of range"); |
a4da2e3e | 342 | else if (errno != 0) |
658f29a5 | 343 | print_error("bad literal"); |
a4da2e3e DG |
344 | return val; |
345 | } |