u-boot/scripts/dtc/dtc-parser.y

556 lines
10 KiB
Text
Raw Normal View History

/*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
%{
#include <stdio.h>
#include <inttypes.h>
#include "dtc.h"
#include "srcpos.h"
extern int yylex(void);
extern void yyerror(char const *s);
#define ERROR(loc, ...) \
do { \
srcpos_error((loc), "Error", __VA_ARGS__); \
treesource_error = true; \
} while (0)
extern struct dt_info *parser_output;
extern bool treesource_error;
%}
%union {
char *propnodename;
char *labelref;
uint8_t byte;
struct data data;
struct {
struct data data;
int bits;
} array;
struct property *prop;
struct property *proplist;
struct node *node;
struct node *nodelist;
struct reserve_info *re;
uint64_t integer;
unsigned int flags;
}
%token DT_V1
%token DT_PLUGIN
%token DT_MEMRESERVE
%token DT_LSHIFT DT_RSHIFT DT_LE DT_GE DT_EQ DT_NE DT_AND DT_OR
%token DT_BITS
%token DT_DEL_PROP
%token DT_DEL_NODE
dtc: add ability to make nodes conditional on them being referenced This is needed when importing mainline DTs into U-Boot, as some started using this /omit-if-no-ref/ tag, so won't compile with U-Boot's current dtc copy. This is just a cherry-pick of the patch introducing this feature. Original commit message from Maxime: ------------------ A number of platforms have a need to reduce the number of DT nodes, mostly because of two similar constraints: the size of the DT blob, and the time it takes to parse it. As the DT is used in more and more SoCs, and by more projects, some constraints start to appear in bootloaders running from SRAM with an order of magnitude of 10kB. A typical DT is in the same order of magnitude, so any effort to reduce the blob size is welcome in such an environment. Some platforms also want to reach very fast boot time, and the time it takes to parse a typical DT starts to be noticeable. Both of these issues can be mitigated by reducing the number of nodes in the DT. The biggest provider of nodes is usually the pin controller and its subnodes, usually one for each valid pin configuration in a given SoC. Obviously, a single, fixed, set of these nodes will be used by a given board, so we can introduce a node property that will tell the DT compiler to drop the nodes when they are not referenced in the tree, and as such wouldn't be useful in the targetted system. Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Reviewed-by: Rob Herring <robh@kernel.org> Signed-off-by: Andre Przywara <andre.przywara@arm.com> Reviewed-by: Simon Glass <sjg@chromium.org>
2020-01-21 10:23:17 +00:00
%token DT_OMIT_NO_REF
%token <propnodename> DT_PROPNODENAME
%token <integer> DT_LITERAL
%token <integer> DT_CHAR_LITERAL
%token <byte> DT_BYTE
%token <data> DT_STRING
%token <labelref> DT_LABEL
%token <labelref> DT_REF
%token DT_INCBIN
%type <data> propdata
%type <data> propdataprefix
%type <flags> header
%type <flags> headers
%type <re> memreserve
%type <re> memreserves
%type <array> arrayprefix
%type <data> bytestring
%type <prop> propdef
%type <proplist> proplist
%type <node> devicetree
%type <node> nodedef
%type <node> subnode
%type <nodelist> subnodes
%type <integer> integer_prim
%type <integer> integer_unary
%type <integer> integer_mul
%type <integer> integer_add
%type <integer> integer_shift
%type <integer> integer_rela
%type <integer> integer_eq
%type <integer> integer_bitand
%type <integer> integer_bitxor
%type <integer> integer_bitor
%type <integer> integer_and
%type <integer> integer_or
%type <integer> integer_trinary
%type <integer> integer_expr
%%
sourcefile:
headers memreserves devicetree
{
parser_output = build_dt_info($1, $2, $3,
guess_boot_cpuid($3));
}
;
header:
DT_V1 ';'
{
$$ = DTSF_V1;
}
| DT_V1 ';' DT_PLUGIN ';'
{
$$ = DTSF_V1 | DTSF_PLUGIN;
}
;
headers:
header
| header headers
{
if ($2 != $1)
ERROR(&@2, "Header flags don't match earlier ones");
$$ = $1;
}
;
memreserves:
/* empty */
{
$$ = NULL;
}
| memreserve memreserves
{
$$ = chain_reserve_entry($1, $2);
}
;
memreserve:
DT_MEMRESERVE integer_prim integer_prim ';'
{
$$ = build_reserve_entry($2, $3);
}
| DT_LABEL memreserve
{
add_label(&$2->labels, $1);
$$ = $2;
}
;
devicetree:
'/' nodedef
{
$$ = name_node($2, "");
}
| devicetree '/' nodedef
{
$$ = merge_nodes($1, $3);
}
scripts/dtc: Update to upstream version v1.4.6-9-gaadd0b65c987 This adds the following commits from upstream: aadd0b65c987 checks: centralize printing of property names in failure messages 88960e398907 checks: centralize printing of node path in check_msg f1879e1a50eb Add limited read-only support for older (V2 and V3) device tree to libfdt. 37dea76e9700 srcpos: drop special handling of tab 65893da4aee0 libfdt: overlay: Add missing license 962a45ca034d Avoid installing pylibfdt when dependencies are missing cd6ea1b2bea6 Makefile: Split INSTALL out into INSTALL_{PROGRAM,LIB,DATA,SCRIPT} 51b3a16338df Makefile.tests: Add LIBDL make(1) variable for portability sake 333d533a8f4d Attempt to auto-detect stat(1) being used if not given proper invocation e54388015af1 dtc: Bump version to v1.4.6 a1fe86f380cb fdtoverlay: Switch from using alloca to malloc c8d5472de3ff tests: Improve compatibility with other platforms c81d389a10cc checks: add chosen node checks e671852042a7 checks: add aliases node checks d0c44ebe3f42 checks: check for #{size,address}-cells without child nodes 18a3d84bb802 checks: add string list check for *-names properties 8fe94fd6f19f checks: add string list check 6c5730819604 checks: add a string check for 'label' property a384191eba09 checks: fix sound-dai phandle with arg property check b260c4f610c0 Fix ambiguous grammar for devicetree rule fe667e382bac tests: Add some basic tests for the pci_bridge checks 7975f6422260 Fix widespread incorrect use of strneq(), replace with new strprefixeq() fca296445eab Add strstarts() helper function cc392f089007 tests: Check non-matching cases for fdt_node_check_compatible() bba26a5291c8 livetree: avoid assertion of orphan phandles with overlays c8f8194d76cc implement strnlen for systems that need it c8b38f65fdec libfdt: Remove leading underscores from identifiers 3b62fdaebfe5 Remove leading underscores from identifiers 2d45d1c5c65e Replace FDT_VERSION() with stringify() 2e6fe5a107b5 Fix some errors in comments b0ae9e4b0ceb tests: Correct warning in sw_tree1.c Commit c8b38f65fdec upstream ("libfdt: Remove leading underscores from identifiers") changed the multiple inclusion define protection, so the kernel's libfdt_env.h needs the corresponding update. Signed-off-by: Rob Herring <robh@kernel.org> [ Linux commit: 9130ba884640328bb78aaa4840e5ddf06ccafb1c ] [erosca: - Fixup conflicts in include/linux/libfdt_env.h caused by v2018.03-rc4 commit b08c8c487083 ("libfdt: move headers to <linux/libfdt.h> and <linux/libfdt_env.h>") - Fix build errors in lib/libfdt/fdt_ro.c, tools/libfdt/fdt_rw.c by: - s/_fdt_mem_rsv/fdt_mem_rsv_/ - s/_fdt_offset_ptr/fdt_offset_ptr_/ - s/_fdt_check_node_offset/fdt_check_node_offset_/ - s/_fdt_check_prop_offset/fdt_check_prop_offset_/ - s/_fdt_find_add_string/fdt_find_add_string_/] Signed-off-by: Eugeniu Rosca <erosca@de.adit-jv.com> Reviewed-by: Simon Glass <sjg@chromium.org> Reviewed-by: Masahiro Yamada <yamada.masahiro@socionext.com>
2018-05-19 12:13:53 +00:00
| DT_REF nodedef
{
/*
* We rely on the rule being always:
* versioninfo plugindecl memreserves devicetree
* so $-1 is what we want (plugindecl)
*/
if (!($<flags>-1 & DTSF_PLUGIN))
ERROR(&@2, "Label or path %s not found", $1);
$$ = add_orphan_node(name_node(build_node(NULL, NULL), ""), $2, $1);
}
| devicetree DT_LABEL DT_REF nodedef
{
struct node *target = get_node_by_ref($1, $3);
if (target) {
add_label(&target->labels, $2);
merge_nodes(target, $4);
} else
ERROR(&@3, "Label or path %s not found", $3);
$$ = $1;
}
| devicetree DT_REF nodedef
{
struct node *target = get_node_by_ref($1, $2);
if (target) {
merge_nodes(target, $3);
} else {
/*
* We rely on the rule being always:
* versioninfo plugindecl memreserves devicetree
* so $-1 is what we want (plugindecl)
*/
if ($<flags>-1 & DTSF_PLUGIN)
add_orphan_node($1, $3, $2);
else
ERROR(&@2, "Label or path %s not found", $2);
}
$$ = $1;
}
| devicetree DT_DEL_NODE DT_REF ';'
{
struct node *target = get_node_by_ref($1, $3);
if (target)
delete_node(target);
else
ERROR(&@3, "Label or path %s not found", $3);
dtc: add ability to make nodes conditional on them being referenced This is needed when importing mainline DTs into U-Boot, as some started using this /omit-if-no-ref/ tag, so won't compile with U-Boot's current dtc copy. This is just a cherry-pick of the patch introducing this feature. Original commit message from Maxime: ------------------ A number of platforms have a need to reduce the number of DT nodes, mostly because of two similar constraints: the size of the DT blob, and the time it takes to parse it. As the DT is used in more and more SoCs, and by more projects, some constraints start to appear in bootloaders running from SRAM with an order of magnitude of 10kB. A typical DT is in the same order of magnitude, so any effort to reduce the blob size is welcome in such an environment. Some platforms also want to reach very fast boot time, and the time it takes to parse a typical DT starts to be noticeable. Both of these issues can be mitigated by reducing the number of nodes in the DT. The biggest provider of nodes is usually the pin controller and its subnodes, usually one for each valid pin configuration in a given SoC. Obviously, a single, fixed, set of these nodes will be used by a given board, so we can introduce a node property that will tell the DT compiler to drop the nodes when they are not referenced in the tree, and as such wouldn't be useful in the targetted system. Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Reviewed-by: Rob Herring <robh@kernel.org> Signed-off-by: Andre Przywara <andre.przywara@arm.com> Reviewed-by: Simon Glass <sjg@chromium.org>
2020-01-21 10:23:17 +00:00
$$ = $1;
}
| devicetree DT_OMIT_NO_REF DT_REF ';'
{
struct node *target = get_node_by_ref($1, $3);
if (target)
omit_node_if_unused(target);
else
ERROR(&@3, "Label or path %s not found", $3);
$$ = $1;
}
;
nodedef:
'{' proplist subnodes '}' ';'
{
$$ = build_node($2, $3);
}
;
proplist:
/* empty */
{
$$ = NULL;
}
| proplist propdef
{
$$ = chain_property($2, $1);
}
;
propdef:
DT_PROPNODENAME '=' propdata ';'
{
$$ = build_property($1, $3);
}
| DT_PROPNODENAME ';'
{
$$ = build_property($1, empty_data);
}
| DT_DEL_PROP DT_PROPNODENAME ';'
{
$$ = build_property_delete($2);
}
| DT_LABEL propdef
{
add_label(&$2->labels, $1);
$$ = $2;
}
;
propdata:
propdataprefix DT_STRING
{
$$ = data_merge($1, $2);
}
| propdataprefix arrayprefix '>'
{
$$ = data_merge($1, $2.data);
}
| propdataprefix '[' bytestring ']'
{
$$ = data_merge($1, $3);
}
| propdataprefix DT_REF
{
$$ = data_add_marker($1, REF_PATH, $2);
}
| propdataprefix DT_INCBIN '(' DT_STRING ',' integer_prim ',' integer_prim ')'
{
FILE *f = srcfile_relative_open($4.val, NULL);
struct data d;
if ($6 != 0)
if (fseek(f, $6, SEEK_SET) != 0)
die("Couldn't seek to offset %llu in \"%s\": %s",
(unsigned long long)$6, $4.val,
strerror(errno));
d = data_copy_file(f, $8);
$$ = data_merge($1, d);
fclose(f);
}
| propdataprefix DT_INCBIN '(' DT_STRING ')'
{
FILE *f = srcfile_relative_open($4.val, NULL);
struct data d = empty_data;
d = data_copy_file(f, -1);
$$ = data_merge($1, d);
fclose(f);
}
| propdata DT_LABEL
{
$$ = data_add_marker($1, LABEL, $2);
}
;
propdataprefix:
/* empty */
{
$$ = empty_data;
}
| propdata ','
{
$$ = $1;
}
| propdataprefix DT_LABEL
{
$$ = data_add_marker($1, LABEL, $2);
}
;
arrayprefix:
DT_BITS DT_LITERAL '<'
{
unsigned long long bits;
bits = $2;
if ((bits != 8) && (bits != 16) &&
(bits != 32) && (bits != 64)) {
ERROR(&@2, "Array elements must be"
" 8, 16, 32 or 64-bits");
bits = 32;
}
$$.data = empty_data;
$$.bits = bits;
}
| '<'
{
$$.data = empty_data;
$$.bits = 32;
}
| arrayprefix integer_prim
{
if ($1.bits < 64) {
uint64_t mask = (1ULL << $1.bits) - 1;
/*
* Bits above mask must either be all zero
* (positive within range of mask) or all one
* (negative and sign-extended). The second
* condition is true if when we set all bits
* within the mask to one (i.e. | in the
* mask), all bits are one.
*/
if (($2 > mask) && (($2 | mask) != -1ULL))
ERROR(&@2, "Value out of range for"
" %d-bit array element", $1.bits);
}
$$.data = data_append_integer($1.data, $2, $1.bits);
}
| arrayprefix DT_REF
{
uint64_t val = ~0ULL >> (64 - $1.bits);
if ($1.bits == 32)
$1.data = data_add_marker($1.data,
REF_PHANDLE,
$2);
else
ERROR(&@2, "References are only allowed in "
"arrays with 32-bit elements.");
$$.data = data_append_integer($1.data, val, $1.bits);
}
| arrayprefix DT_LABEL
{
$$.data = data_add_marker($1.data, LABEL, $2);
}
;
integer_prim:
DT_LITERAL
| DT_CHAR_LITERAL
| '(' integer_expr ')'
{
$$ = $2;
}
;
integer_expr:
integer_trinary
;
integer_trinary:
integer_or
| integer_or '?' integer_expr ':' integer_trinary { $$ = $1 ? $3 : $5; }
;
integer_or:
integer_and
| integer_or DT_OR integer_and { $$ = $1 || $3; }
;
integer_and:
integer_bitor
| integer_and DT_AND integer_bitor { $$ = $1 && $3; }
;
integer_bitor:
integer_bitxor
| integer_bitor '|' integer_bitxor { $$ = $1 | $3; }
;
integer_bitxor:
integer_bitand
| integer_bitxor '^' integer_bitand { $$ = $1 ^ $3; }
;
integer_bitand:
integer_eq
| integer_bitand '&' integer_eq { $$ = $1 & $3; }
;
integer_eq:
integer_rela
| integer_eq DT_EQ integer_rela { $$ = $1 == $3; }
| integer_eq DT_NE integer_rela { $$ = $1 != $3; }
;
integer_rela:
integer_shift
| integer_rela '<' integer_shift { $$ = $1 < $3; }
| integer_rela '>' integer_shift { $$ = $1 > $3; }
| integer_rela DT_LE integer_shift { $$ = $1 <= $3; }
| integer_rela DT_GE integer_shift { $$ = $1 >= $3; }
;
integer_shift:
integer_shift DT_LSHIFT integer_add { $$ = $1 << $3; }
| integer_shift DT_RSHIFT integer_add { $$ = $1 >> $3; }
| integer_add
;
integer_add:
integer_add '+' integer_mul { $$ = $1 + $3; }
| integer_add '-' integer_mul { $$ = $1 - $3; }
| integer_mul
;
integer_mul:
integer_mul '*' integer_unary { $$ = $1 * $3; }
| integer_mul '/' integer_unary
{
if ($3 != 0) {
$$ = $1 / $3;
} else {
ERROR(&@$, "Division by zero");
$$ = 0;
}
}
| integer_mul '%' integer_unary
{
if ($3 != 0) {
$$ = $1 % $3;
} else {
ERROR(&@$, "Division by zero");
$$ = 0;
}
}
| integer_unary
;
integer_unary:
integer_prim
| '-' integer_unary { $$ = -$2; }
| '~' integer_unary { $$ = ~$2; }
| '!' integer_unary { $$ = !$2; }
;
bytestring:
/* empty */
{
$$ = empty_data;
}
| bytestring DT_BYTE
{
$$ = data_append_byte($1, $2);
}
| bytestring DT_LABEL
{
$$ = data_add_marker($1, LABEL, $2);
}
;
subnodes:
/* empty */
{
$$ = NULL;
}
| subnode subnodes
{
$$ = chain_node($1, $2);
}
| subnode propdef
{
ERROR(&@2, "Properties must precede subnodes");
YYERROR;
}
;
subnode:
DT_PROPNODENAME nodedef
{
$$ = name_node($2, $1);
}
| DT_DEL_NODE DT_PROPNODENAME ';'
{
$$ = name_node(build_node_delete(), $2);
}
dtc: add ability to make nodes conditional on them being referenced This is needed when importing mainline DTs into U-Boot, as some started using this /omit-if-no-ref/ tag, so won't compile with U-Boot's current dtc copy. This is just a cherry-pick of the patch introducing this feature. Original commit message from Maxime: ------------------ A number of platforms have a need to reduce the number of DT nodes, mostly because of two similar constraints: the size of the DT blob, and the time it takes to parse it. As the DT is used in more and more SoCs, and by more projects, some constraints start to appear in bootloaders running from SRAM with an order of magnitude of 10kB. A typical DT is in the same order of magnitude, so any effort to reduce the blob size is welcome in such an environment. Some platforms also want to reach very fast boot time, and the time it takes to parse a typical DT starts to be noticeable. Both of these issues can be mitigated by reducing the number of nodes in the DT. The biggest provider of nodes is usually the pin controller and its subnodes, usually one for each valid pin configuration in a given SoC. Obviously, a single, fixed, set of these nodes will be used by a given board, so we can introduce a node property that will tell the DT compiler to drop the nodes when they are not referenced in the tree, and as such wouldn't be useful in the targetted system. Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Reviewed-by: Rob Herring <robh@kernel.org> Signed-off-by: Andre Przywara <andre.przywara@arm.com> Reviewed-by: Simon Glass <sjg@chromium.org>
2020-01-21 10:23:17 +00:00
| DT_OMIT_NO_REF subnode
{
$$ = omit_node_if_unused($2);
}
| DT_LABEL subnode
{
add_label(&$2->labels, $1);
$$ = $2;
}
;
%%
void yyerror(char const *s)
{
ERROR(&yylloc, "%s", s);
}