blob: b3b9c83873d7b7158c8f786be575e8e3055ce74a [file] [log] [blame]
Tom Rinibd391732017-09-23 12:52:44 -04001/*
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#include <stdio.h>
22#include <inttypes.h>
23
24#include "dtc.h"
25#include "srcpos.h"
26
27extern int yylex(void);
28extern void yyerror(char const *s);
29#define ERROR(loc, ...) \
30 do { \
31 srcpos_error((loc), "Error", __VA_ARGS__); \
32 treesource_error = true; \
33 } while (0)
34
35extern struct dt_info *parser_output;
36extern bool treesource_error;
Patrice Chotard00a7b772025-03-28 17:31:15 +010037
38static bool is_ref_relative(const char *ref)
39{
40 return ref[0] != '/' && strchr(&ref[1], '/');
41}
42
Tom Rinibd391732017-09-23 12:52:44 -040043%}
44
45%union {
46 char *propnodename;
47 char *labelref;
48 uint8_t byte;
49 struct data data;
50
51 struct {
52 struct data data;
53 int bits;
54 } array;
55
56 struct property *prop;
57 struct property *proplist;
58 struct node *node;
59 struct node *nodelist;
60 struct reserve_info *re;
61 uint64_t integer;
62 unsigned int flags;
63}
64
65%token DT_V1
66%token DT_PLUGIN
67%token DT_MEMRESERVE
68%token DT_LSHIFT DT_RSHIFT DT_LE DT_GE DT_EQ DT_NE DT_AND DT_OR
69%token DT_BITS
70%token DT_DEL_PROP
71%token DT_DEL_NODE
Maxime Riparda96fe172020-01-21 10:23:17 +000072%token DT_OMIT_NO_REF
Tom Rinibd391732017-09-23 12:52:44 -040073%token <propnodename> DT_PROPNODENAME
74%token <integer> DT_LITERAL
75%token <integer> DT_CHAR_LITERAL
76%token <byte> DT_BYTE
77%token <data> DT_STRING
78%token <labelref> DT_LABEL
79%token <labelref> DT_REF
80%token DT_INCBIN
81
82%type <data> propdata
83%type <data> propdataprefix
84%type <flags> header
85%type <flags> headers
86%type <re> memreserve
87%type <re> memreserves
88%type <array> arrayprefix
89%type <data> bytestring
90%type <prop> propdef
91%type <proplist> proplist
92
93%type <node> devicetree
94%type <node> nodedef
95%type <node> subnode
96%type <nodelist> subnodes
97
98%type <integer> integer_prim
99%type <integer> integer_unary
100%type <integer> integer_mul
101%type <integer> integer_add
102%type <integer> integer_shift
103%type <integer> integer_rela
104%type <integer> integer_eq
105%type <integer> integer_bitand
106%type <integer> integer_bitxor
107%type <integer> integer_bitor
108%type <integer> integer_and
109%type <integer> integer_or
110%type <integer> integer_trinary
111%type <integer> integer_expr
112
113%%
114
115sourcefile:
116 headers memreserves devicetree
117 {
118 parser_output = build_dt_info($1, $2, $3,
119 guess_boot_cpuid($3));
120 }
121 ;
122
123header:
124 DT_V1 ';'
125 {
126 $$ = DTSF_V1;
127 }
128 | DT_V1 ';' DT_PLUGIN ';'
129 {
130 $$ = DTSF_V1 | DTSF_PLUGIN;
131 }
132 ;
133
134headers:
135 header
136 | header headers
137 {
138 if ($2 != $1)
139 ERROR(&@2, "Header flags don't match earlier ones");
140 $$ = $1;
141 }
142 ;
143
144memreserves:
145 /* empty */
146 {
147 $$ = NULL;
148 }
149 | memreserve memreserves
150 {
151 $$ = chain_reserve_entry($1, $2);
152 }
153 ;
154
155memreserve:
156 DT_MEMRESERVE integer_prim integer_prim ';'
157 {
158 $$ = build_reserve_entry($2, $3);
159 }
160 | DT_LABEL memreserve
161 {
162 add_label(&$2->labels, $1);
163 $$ = $2;
164 }
165 ;
166
167devicetree:
168 '/' nodedef
169 {
170 $$ = name_node($2, "");
171 }
172 | devicetree '/' nodedef
173 {
174 $$ = merge_nodes($1, $3);
175 }
Rob Herringcd5f70d2018-05-19 14:13:53 +0200176 | DT_REF nodedef
177 {
178 /*
179 * We rely on the rule being always:
180 * versioninfo plugindecl memreserves devicetree
181 * so $-1 is what we want (plugindecl)
182 */
183 if (!($<flags>-1 & DTSF_PLUGIN))
184 ERROR(&@2, "Label or path %s not found", $1);
Patrice Chotard00a7b772025-03-28 17:31:15 +0100185 else if (is_ref_relative($1))
186 ERROR(&@2, "Label-relative reference %s not supported in plugin", $1);
Rob Herringcd5f70d2018-05-19 14:13:53 +0200187 $$ = add_orphan_node(name_node(build_node(NULL, NULL), ""), $2, $1);
188 }
Tom Rinibd391732017-09-23 12:52:44 -0400189 | devicetree DT_LABEL DT_REF nodedef
190 {
191 struct node *target = get_node_by_ref($1, $3);
192
Patrice Chotard00a7b772025-03-28 17:31:15 +0100193 if (($<flags>-1 & DTSF_PLUGIN) && is_ref_relative($3))
194 ERROR(&@2, "Label-relative reference %s not supported in plugin", $3);
195
Tom Rinibd391732017-09-23 12:52:44 -0400196 if (target) {
197 add_label(&target->labels, $2);
198 merge_nodes(target, $4);
199 } else
200 ERROR(&@3, "Label or path %s not found", $3);
201 $$ = $1;
202 }
203 | devicetree DT_REF nodedef
204 {
Rob Herring3f8ede92020-03-11 18:11:16 -0400205 /*
206 * We rely on the rule being always:
207 * versioninfo plugindecl memreserves devicetree
208 * so $-1 is what we want (plugindecl)
209 */
210 if ($<flags>-1 & DTSF_PLUGIN) {
Patrice Chotard00a7b772025-03-28 17:31:15 +0100211 if (is_ref_relative($2))
212 ERROR(&@2, "Label-relative reference %s not supported in plugin", $2);
Rob Herring3f8ede92020-03-11 18:11:16 -0400213 add_orphan_node($1, $3, $2);
Masahiro Yamada09a9dca2017-10-17 13:42:42 +0900214 } else {
Rob Herring3f8ede92020-03-11 18:11:16 -0400215 struct node *target = get_node_by_ref($1, $2);
216
217 if (target)
218 merge_nodes(target, $3);
Masahiro Yamada09a9dca2017-10-17 13:42:42 +0900219 else
220 ERROR(&@2, "Label or path %s not found", $2);
221 }
Tom Rinibd391732017-09-23 12:52:44 -0400222 $$ = $1;
223 }
224 | devicetree DT_DEL_NODE DT_REF ';'
225 {
226 struct node *target = get_node_by_ref($1, $3);
227
228 if (target)
229 delete_node(target);
230 else
231 ERROR(&@3, "Label or path %s not found", $3);
232
233
234 $$ = $1;
235 }
Maxime Riparda96fe172020-01-21 10:23:17 +0000236 | devicetree DT_OMIT_NO_REF DT_REF ';'
237 {
238 struct node *target = get_node_by_ref($1, $3);
239
240 if (target)
241 omit_node_if_unused(target);
242 else
243 ERROR(&@3, "Label or path %s not found", $3);
244
245
246 $$ = $1;
247 }
Tom Rinibd391732017-09-23 12:52:44 -0400248 ;
249
250nodedef:
251 '{' proplist subnodes '}' ';'
252 {
253 $$ = build_node($2, $3);
254 }
255 ;
256
257proplist:
258 /* empty */
259 {
260 $$ = NULL;
261 }
262 | proplist propdef
263 {
264 $$ = chain_property($2, $1);
265 }
266 ;
267
268propdef:
269 DT_PROPNODENAME '=' propdata ';'
270 {
271 $$ = build_property($1, $3);
272 }
273 | DT_PROPNODENAME ';'
274 {
275 $$ = build_property($1, empty_data);
276 }
277 | DT_DEL_PROP DT_PROPNODENAME ';'
278 {
279 $$ = build_property_delete($2);
280 }
281 | DT_LABEL propdef
282 {
283 add_label(&$2->labels, $1);
284 $$ = $2;
285 }
286 ;
287
288propdata:
289 propdataprefix DT_STRING
290 {
291 $$ = data_merge($1, $2);
292 }
293 | propdataprefix arrayprefix '>'
294 {
295 $$ = data_merge($1, $2.data);
296 }
297 | propdataprefix '[' bytestring ']'
298 {
299 $$ = data_merge($1, $3);
300 }
301 | propdataprefix DT_REF
302 {
303 $$ = data_add_marker($1, REF_PATH, $2);
304 }
305 | propdataprefix DT_INCBIN '(' DT_STRING ',' integer_prim ',' integer_prim ')'
306 {
307 FILE *f = srcfile_relative_open($4.val, NULL);
308 struct data d;
309
310 if ($6 != 0)
311 if (fseek(f, $6, SEEK_SET) != 0)
312 die("Couldn't seek to offset %llu in \"%s\": %s",
313 (unsigned long long)$6, $4.val,
314 strerror(errno));
315
316 d = data_copy_file(f, $8);
317
318 $$ = data_merge($1, d);
319 fclose(f);
320 }
321 | propdataprefix DT_INCBIN '(' DT_STRING ')'
322 {
323 FILE *f = srcfile_relative_open($4.val, NULL);
324 struct data d = empty_data;
325
326 d = data_copy_file(f, -1);
327
328 $$ = data_merge($1, d);
329 fclose(f);
330 }
331 | propdata DT_LABEL
332 {
333 $$ = data_add_marker($1, LABEL, $2);
334 }
335 ;
336
337propdataprefix:
338 /* empty */
339 {
340 $$ = empty_data;
341 }
342 | propdata ','
343 {
344 $$ = $1;
345 }
346 | propdataprefix DT_LABEL
347 {
348 $$ = data_add_marker($1, LABEL, $2);
349 }
350 ;
351
352arrayprefix:
353 DT_BITS DT_LITERAL '<'
354 {
355 unsigned long long bits;
356
357 bits = $2;
358
359 if ((bits != 8) && (bits != 16) &&
360 (bits != 32) && (bits != 64)) {
361 ERROR(&@2, "Array elements must be"
362 " 8, 16, 32 or 64-bits");
363 bits = 32;
364 }
365
366 $$.data = empty_data;
367 $$.bits = bits;
368 }
369 | '<'
370 {
371 $$.data = empty_data;
372 $$.bits = 32;
373 }
374 | arrayprefix integer_prim
375 {
376 if ($1.bits < 64) {
377 uint64_t mask = (1ULL << $1.bits) - 1;
378 /*
379 * Bits above mask must either be all zero
380 * (positive within range of mask) or all one
381 * (negative and sign-extended). The second
382 * condition is true if when we set all bits
383 * within the mask to one (i.e. | in the
384 * mask), all bits are one.
385 */
386 if (($2 > mask) && (($2 | mask) != -1ULL))
387 ERROR(&@2, "Value out of range for"
388 " %d-bit array element", $1.bits);
389 }
390
391 $$.data = data_append_integer($1.data, $2, $1.bits);
392 }
393 | arrayprefix DT_REF
394 {
395 uint64_t val = ~0ULL >> (64 - $1.bits);
396
397 if ($1.bits == 32)
398 $1.data = data_add_marker($1.data,
399 REF_PHANDLE,
400 $2);
401 else
402 ERROR(&@2, "References are only allowed in "
403 "arrays with 32-bit elements.");
404
405 $$.data = data_append_integer($1.data, val, $1.bits);
406 }
407 | arrayprefix DT_LABEL
408 {
409 $$.data = data_add_marker($1.data, LABEL, $2);
410 }
411 ;
412
413integer_prim:
414 DT_LITERAL
415 | DT_CHAR_LITERAL
416 | '(' integer_expr ')'
417 {
418 $$ = $2;
419 }
420 ;
421
422integer_expr:
423 integer_trinary
424 ;
425
426integer_trinary:
427 integer_or
428 | integer_or '?' integer_expr ':' integer_trinary { $$ = $1 ? $3 : $5; }
429 ;
430
431integer_or:
432 integer_and
433 | integer_or DT_OR integer_and { $$ = $1 || $3; }
434 ;
435
436integer_and:
437 integer_bitor
438 | integer_and DT_AND integer_bitor { $$ = $1 && $3; }
439 ;
440
441integer_bitor:
442 integer_bitxor
443 | integer_bitor '|' integer_bitxor { $$ = $1 | $3; }
444 ;
445
446integer_bitxor:
447 integer_bitand
448 | integer_bitxor '^' integer_bitand { $$ = $1 ^ $3; }
449 ;
450
451integer_bitand:
452 integer_eq
453 | integer_bitand '&' integer_eq { $$ = $1 & $3; }
454 ;
455
456integer_eq:
457 integer_rela
458 | integer_eq DT_EQ integer_rela { $$ = $1 == $3; }
459 | integer_eq DT_NE integer_rela { $$ = $1 != $3; }
460 ;
461
462integer_rela:
463 integer_shift
464 | integer_rela '<' integer_shift { $$ = $1 < $3; }
465 | integer_rela '>' integer_shift { $$ = $1 > $3; }
466 | integer_rela DT_LE integer_shift { $$ = $1 <= $3; }
467 | integer_rela DT_GE integer_shift { $$ = $1 >= $3; }
468 ;
469
470integer_shift:
471 integer_shift DT_LSHIFT integer_add { $$ = $1 << $3; }
472 | integer_shift DT_RSHIFT integer_add { $$ = $1 >> $3; }
473 | integer_add
474 ;
475
476integer_add:
477 integer_add '+' integer_mul { $$ = $1 + $3; }
478 | integer_add '-' integer_mul { $$ = $1 - $3; }
479 | integer_mul
480 ;
481
482integer_mul:
483 integer_mul '*' integer_unary { $$ = $1 * $3; }
484 | integer_mul '/' integer_unary
485 {
486 if ($3 != 0) {
487 $$ = $1 / $3;
488 } else {
489 ERROR(&@$, "Division by zero");
490 $$ = 0;
491 }
492 }
493 | integer_mul '%' integer_unary
494 {
495 if ($3 != 0) {
496 $$ = $1 % $3;
497 } else {
498 ERROR(&@$, "Division by zero");
499 $$ = 0;
500 }
501 }
502 | integer_unary
503 ;
504
505integer_unary:
506 integer_prim
507 | '-' integer_unary { $$ = -$2; }
508 | '~' integer_unary { $$ = ~$2; }
509 | '!' integer_unary { $$ = !$2; }
510 ;
511
512bytestring:
513 /* empty */
514 {
515 $$ = empty_data;
516 }
517 | bytestring DT_BYTE
518 {
519 $$ = data_append_byte($1, $2);
520 }
521 | bytestring DT_LABEL
522 {
523 $$ = data_add_marker($1, LABEL, $2);
524 }
525 ;
526
527subnodes:
528 /* empty */
529 {
530 $$ = NULL;
531 }
532 | subnode subnodes
533 {
534 $$ = chain_node($1, $2);
535 }
536 | subnode propdef
537 {
538 ERROR(&@2, "Properties must precede subnodes");
539 YYERROR;
540 }
541 ;
542
543subnode:
544 DT_PROPNODENAME nodedef
545 {
546 $$ = name_node($2, $1);
547 }
548 | DT_DEL_NODE DT_PROPNODENAME ';'
549 {
550 $$ = name_node(build_node_delete(), $2);
551 }
Maxime Riparda96fe172020-01-21 10:23:17 +0000552 | DT_OMIT_NO_REF subnode
553 {
554 $$ = omit_node_if_unused($2);
555 }
Tom Rinibd391732017-09-23 12:52:44 -0400556 | DT_LABEL subnode
557 {
558 add_label(&$2->labels, $1);
559 $$ = $2;
560 }
561 ;
562
563%%
564
565void yyerror(char const *s)
566{
567 ERROR(&yylloc, "%s", s);
568}