* [RFC 01/15] scripts/dtc: fix most memory leaks in dtc
2013-09-24 16:52 [RFC 00/15] Device Tree schemas and validation Benoit Cousson
@ 2013-09-24 16:52 ` Benoit Cousson
[not found] ` <1380041541-17529-2-git-send-email-bcousson-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
2013-09-24 16:52 ` [RFC 04/15] scripts/dtc: add procedure to handle dts errors Benoit Cousson
` (9 subsequent siblings)
10 siblings, 1 reply; 36+ messages in thread
From: Benoit Cousson @ 2013-09-24 16:52 UTC (permalink / raw)
To: olof, devicetree, tomasz.figa, swarren, grant.likely, rob.herring
Cc: khilman, linux-omap, linux-arm-kernel, fparent, Benoit Cousson
From: Fabien Parent <fparent@baylibre.com>
There are a few memory leaks in dtc which until now were not that important
since they were all in the parser and only one instance of the parser was run
per instance of dtc. The following commits will add a validation of dts through
schema which have the same syntax as dts, i.e. the parser of dts will be reused
to parse schema. The consequence is that instead of having the parser running
only one time for an instance of the dtc process, the parser will run
many many times and thus the leak that were not important until now becomes
urgent to fix.
dtc-lexer: Do not duplicate the string which contains literals because the
string is directly converted afterward to an integer and is never used again.
livetree: Add a bunch of free helper functions to clean properly the dt.
Signed-off-by: Fabien Parent <fparent@baylibre.com>
Signed-off-by: Benoit Cousson <bcousson@baylibre.com>
---
scripts/dtc/dtc-lexer.l | 2 +-
scripts/dtc/dtc-lexer.lex.c_shipped | 2 +-
scripts/dtc/dtc.c | 1 +
scripts/dtc/dtc.h | 1 +
scripts/dtc/livetree.c | 108 +++++++++++++++++++++++++++++++++---
5 files changed, 105 insertions(+), 9 deletions(-)
diff --git a/scripts/dtc/dtc-lexer.l b/scripts/dtc/dtc-lexer.l
index 3b41bfc..4f63fbf 100644
--- a/scripts/dtc/dtc-lexer.l
+++ b/scripts/dtc/dtc-lexer.l
@@ -146,7 +146,7 @@ static int pop_input_file(void);
}
<V1>([0-9]+|0[xX][0-9a-fA-F]+)(U|L|UL|LL|ULL)? {
- yylval.literal = xstrdup(yytext);
+ yylval.literal = yytext;
DPRINT("Literal: '%s'\n", yylval.literal);
return DT_LITERAL;
}
diff --git a/scripts/dtc/dtc-lexer.lex.c_shipped b/scripts/dtc/dtc-lexer.lex.c_shipped
index 2d30f41..5c0d27c 100644
--- a/scripts/dtc/dtc-lexer.lex.c_shipped
+++ b/scripts/dtc/dtc-lexer.lex.c_shipped
@@ -1054,7 +1054,7 @@ case 10:
YY_RULE_SETUP
#line 148 "dtc-lexer.l"
{
- yylval.literal = xstrdup(yytext);
+ yylval.literal = yytext;
DPRINT("Literal: '%s'\n", yylval.literal);
return DT_LITERAL;
}
diff --git a/scripts/dtc/dtc.c b/scripts/dtc/dtc.c
index a375683..215ae92 100644
--- a/scripts/dtc/dtc.c
+++ b/scripts/dtc/dtc.c
@@ -256,5 +256,6 @@ int main(int argc, char *argv[])
die("Unknown output format \"%s\"\n", outform);
}
+ free_dt(bi);
exit(0);
}
diff --git a/scripts/dtc/dtc.h b/scripts/dtc/dtc.h
index 3e42a07..9c45fd2 100644
--- a/scripts/dtc/dtc.h
+++ b/scripts/dtc/dtc.h
@@ -245,6 +245,7 @@ struct boot_info {
struct boot_info *build_boot_info(struct reserve_info *reservelist,
struct node *tree, uint32_t boot_cpuid_phys);
void sort_tree(struct boot_info *bi);
+void free_dt(struct boot_info *bi);
/* Checks */
diff --git a/scripts/dtc/livetree.c b/scripts/dtc/livetree.c
index b61465f..5c8692c 100644
--- a/scripts/dtc/livetree.c
+++ b/scripts/dtc/livetree.c
@@ -20,6 +20,10 @@
#include "dtc.h"
+static void free_node_list(struct node *n);
+static void free_node(struct node *n);
+static void free_property(struct property *p);
+
/*
* Tree building functions
*/
@@ -144,7 +148,7 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node)
/* Add new node labels to old node */
for_each_label_withdel(new_node->labels, l)
- add_label(&old_node->labels, l->label);
+ add_label(&old_node->labels, xstrdup(l->label));
/* Move properties from the new node to the old node. If there
* is a collision, replace the old value with the new */
@@ -156,7 +160,7 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node)
if (new_prop->deleted) {
delete_property_by_name(old_node, new_prop->name);
- free(new_prop);
+ free_property(new_prop);
continue;
}
@@ -165,7 +169,7 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node)
if (streq(old_prop->name, new_prop->name)) {
/* Add new labels to old property */
for_each_label_withdel(new_prop->labels, l)
- add_label(&old_prop->labels, l->label);
+ add_label(&old_prop->labels, xstrdup(l->label));
old_prop->val = new_prop->val;
old_prop->deleted = 0;
@@ -191,7 +195,7 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node)
if (new_child->deleted) {
delete_node_by_name(old_node, new_child->name);
- free(new_child);
+ free_node(new_child);
continue;
}
@@ -211,7 +215,7 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node)
/* The new node contents are now merged into the old node. Free
* the new node. */
- free(new_node);
+ free_node(new_node);
return old_node;
}
@@ -532,13 +536,13 @@ cell_t get_node_phandle(struct node *root, struct node *node)
if (!get_property(node, "linux,phandle")
&& (phandle_format & PHANDLE_LEGACY))
add_property(node,
- build_property("linux,phandle",
+ build_property(xstrdup("linux,phandle"),
data_append_cell(empty_data, phandle)));
if (!get_property(node, "phandle")
&& (phandle_format & PHANDLE_EPAPR))
add_property(node,
- build_property("phandle",
+ build_property(xstrdup("phandle"),
data_append_cell(empty_data, phandle)));
/* If the node *does* have a phandle property, we must
@@ -707,3 +711,93 @@ void sort_tree(struct boot_info *bi)
sort_reserve_entries(bi);
sort_node(bi->dt);
}
+
+static void free_marker_list(struct marker *m)
+{
+ struct marker *marker, *marker_next;
+
+ if (!m)
+ return;
+
+ for (marker = m, marker_next = marker ? marker->next : NULL;
+ marker;
+ marker = marker_next, marker_next = marker ? marker->next : NULL) {
+ free(marker->ref);
+ free(marker);
+ }
+}
+
+static void free_label_list(struct label *l)
+{
+ struct label *label, *label_next;
+
+ if (!l)
+ return;
+
+ for (label = l, label_next = label ? label->next : NULL;
+ label;
+ label = label_next, label_next = label ? label->next : NULL) {
+ free(label->label);
+ free(label);
+ }
+}
+
+static void free_property(struct property *p)
+{
+ if (!p)
+ return;
+
+ free_label_list(p->labels);
+ free_marker_list(p->val.markers);
+ free(p->val.val);
+ free(p->name);
+ free(p);
+}
+
+static void free_property_list(struct property *p)
+{
+ struct property *next;
+
+ if (!p)
+ return;
+
+ for (next = p->next; p; p = next, next = p ? p->next : NULL)
+ free_property(p);
+}
+
+static void free_node(struct node *n)
+{
+ if (!n)
+ return;
+
+ free_node_list(n->children);
+ free_label_list(n->labels);
+ free_property_list(n->proplist);
+ free(n->fullpath);
+ if (n->name && *n->name)
+ free(n->name);
+ free(n);
+}
+
+static void free_node_list(struct node *n)
+{
+ struct node *next;
+
+ if (!n)
+ return;
+
+ for (next = n->next_sibling;
+ n;
+ n = next, next = n ? n->next_sibling : NULL) {
+ free_node(n);
+ }
+}
+
+void free_dt(struct boot_info *bi)
+{
+ if (!bi)
+ return;
+
+ free_node_list(bi->dt);
+ free(bi);
+}
--
1.8.1.2
^ permalink raw reply related [flat|nested] 36+ messages in thread
* [RFC 04/15] scripts/dtc: add procedure to handle dts errors
2013-09-24 16:52 [RFC 00/15] Device Tree schemas and validation Benoit Cousson
2013-09-24 16:52 ` [RFC 01/15] scripts/dtc: fix most memory leaks in dtc Benoit Cousson
@ 2013-09-24 16:52 ` Benoit Cousson
2013-09-24 16:52 ` [RFC 05/15] scripts/dtc: check type on properties Benoit Cousson
` (8 subsequent siblings)
10 siblings, 0 replies; 36+ messages in thread
From: Benoit Cousson @ 2013-09-24 16:52 UTC (permalink / raw)
To: olof, devicetree, tomasz.figa, swarren, grant.likely, rob.herring
Cc: khilman, linux-omap, linux-arm-kernel, fparent, Benoit Cousson
From: Fabien Parent <fparent@baylibre.com>
The parser was not keeping enough information to allow a good error reporting.
Source Location information has been added inside a property instance to be
able to precisely tell where an error happened when a property does not match
its constraints as specified inside a schema.
Add as well a routine to print error message using these informations in case
of validation error.
Signed-off-by: Fabien Parent <fparent@baylibre.com>
Signed-off-by: Benoit Cousson <bcousson@baylibre.com>
---
scripts/dtc/dtc-parser.tab.c_shipped | 595 +++++++++++++++--------------------
scripts/dtc/dtc-parser.y | 9 +
scripts/dtc/dtc.h | 7 +
scripts/dtc/schema.c | 69 ++++
4 files changed, 345 insertions(+), 335 deletions(-)
diff --git a/scripts/dtc/dtc-parser.tab.c_shipped b/scripts/dtc/dtc-parser.tab.c_shipped
index ee1d8c3..d6d800a 100644
--- a/scripts/dtc/dtc-parser.tab.c_shipped
+++ b/scripts/dtc/dtc-parser.tab.c_shipped
@@ -1,8 +1,8 @@
-/* A Bison parser, made by GNU Bison 2.5. */
+/* A Bison parser, made by GNU Bison 2.7.12-4996. */
/* Bison implementation for Yacc-like parsers in C
- Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc.
+ Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
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
@@ -44,7 +44,7 @@
#define YYBISON 1
/* Bison version. */
-#define YYBISON_VERSION "2.5"
+#define YYBISON_VERSION "2.7.12-4996"
/* Skeleton name. */
#define YYSKELETON_NAME "yacc.c"
@@ -58,14 +58,11 @@
/* Pull parsers. */
#define YYPULL 1
-/* Using locations. */
-#define YYLSP_NEEDED 0
/* Copy the first part of user declarations. */
-
-/* Line 268 of yacc.c */
+/* Line 371 of yacc.c */
#line 21 "dtc-parser.y"
#include <stdio.h>
@@ -85,14 +82,16 @@ extern int treesource_error;
static unsigned long long eval_literal(const char *s, int base, int bits);
static unsigned char eval_char_literal(const char *s);
+/* Line 371 of yacc.c */
+#line 87 "dtc-parser.tab.c"
-/* Line 268 of yacc.c */
-#line 91 "dtc-parser.tab.c"
-
-/* Enabling traces. */
-#ifndef YYDEBUG
-# define YYDEBUG 0
-#endif
+# ifndef YY_NULL
+# if defined __cplusplus && 201103L <= __cplusplus
+# define YY_NULL nullptr
+# else
+# define YY_NULL 0
+# endif
+# endif
/* Enabling verbose error messages. */
#ifdef YYERROR_VERBOSE
@@ -102,11 +101,14 @@ static unsigned char eval_char_literal(const char *s);
# define YYERROR_VERBOSE 0
#endif
-/* Enabling the token table. */
-#ifndef YYTOKEN_TABLE
-# define YYTOKEN_TABLE 0
-#endif
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int yydebug;
+#endif
/* Tokens. */
#ifndef YYTOKENTYPE
@@ -140,12 +142,10 @@ static unsigned char eval_char_literal(const char *s);
#endif
-
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef union YYSTYPE
{
-
-/* Line 293 of yacc.c */
+/* Line 387 of yacc.c */
#line 40 "dtc-parser.y"
char *propnodename;
@@ -168,21 +168,36 @@ typedef union YYSTYPE
uint64_t integer;
-
-/* Line 293 of yacc.c */
-#line 174 "dtc-parser.tab.c"
+/* Line 387 of yacc.c */
+#line 173 "dtc-parser.tab.c"
} YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1
#endif
+extern YYSTYPE yylval;
-/* Copy the second part of user declarations. */
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
-/* Line 343 of yacc.c */
-#line 186 "dtc-parser.tab.c"
+
+/* Copy the second part of user declarations. */
+
+/* Line 390 of yacc.c */
+#line 201 "dtc-parser.tab.c"
#ifdef short
# undef short
@@ -235,24 +250,33 @@ typedef short int yytype_int16;
# if defined YYENABLE_NLS && YYENABLE_NLS
# if ENABLE_NLS
# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
-# define YY_(msgid) dgettext ("bison-runtime", msgid)
+# define YY_(Msgid) dgettext ("bison-runtime", Msgid)
# endif
# endif
# ifndef YY_
-# define YY_(msgid) msgid
+# define YY_(Msgid) Msgid
+# endif
+#endif
+
+#ifndef __attribute__
+/* This feature is available in gcc versions 2.5 and later. */
+# if (! defined __GNUC__ || __GNUC__ < 2 \
+ || (__GNUC__ == 2 && __GNUC_MINOR__ < 5))
+# define __attribute__(Spec) /* empty */
# endif
#endif
/* Suppress unused-variable warnings by "using" E. */
#if ! defined lint || defined __GNUC__
-# define YYUSE(e) ((void) (e))
+# define YYUSE(E) ((void) (E))
#else
-# define YYUSE(e) /* empty */
+# define YYUSE(E) /* empty */
#endif
+
/* Identity function, used to suppress warnings about constant conditions. */
#ifndef lint
-# define YYID(n) (n)
+# define YYID(N) (N)
#else
#if (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
@@ -288,6 +312,7 @@ YYID (yyi)
# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+ /* Use EXIT_SUCCESS as a witness for stdlib.h. */
# ifndef EXIT_SUCCESS
# define EXIT_SUCCESS 0
# endif
@@ -379,20 +404,20 @@ union yyalloc
#endif
#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
-/* Copy COUNT objects from FROM to TO. The source and destination do
+/* Copy COUNT objects from SRC to DST. The source and destination do
not overlap. */
# ifndef YYCOPY
# if defined __GNUC__ && 1 < __GNUC__
-# define YYCOPY(To, From, Count) \
- __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+# define YYCOPY(Dst, Src, Count) \
+ __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src)))
# else
-# define YYCOPY(To, From, Count) \
- do \
- { \
- YYSIZE_T yyi; \
- for (yyi = 0; yyi < (Count); yyi++) \
- (To)[yyi] = (From)[yyi]; \
- } \
+# define YYCOPY(Dst, Src, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (Dst)[yyi] = (Src)[yyi]; \
+ } \
while (YYID (0))
# endif
# endif
@@ -503,17 +528,17 @@ static const yytype_int8 yyrhs[] =
static const yytype_uint16 yyrline[] =
{
0, 109, 109, 118, 121, 128, 132, 140, 144, 148,
- 158, 172, 180, 183, 190, 194, 198, 202, 210, 214,
- 218, 222, 226, 243, 253, 261, 264, 268, 275, 290,
- 295, 315, 329, 336, 340, 344, 351, 355, 356, 360,
- 361, 365, 366, 370, 371, 375, 376, 380, 381, 385,
- 386, 387, 391, 392, 393, 394, 395, 399, 400, 401,
- 405, 406, 407, 411, 412, 413, 414, 418, 419, 420,
- 421, 426, 429, 433, 441, 444, 448, 456, 460, 464
+ 158, 172, 180, 183, 190, 197, 204, 211, 219, 223,
+ 227, 231, 235, 252, 262, 270, 273, 277, 284, 299,
+ 304, 324, 338, 345, 349, 353, 360, 364, 365, 369,
+ 370, 374, 375, 379, 380, 384, 385, 389, 390, 394,
+ 395, 396, 400, 401, 402, 403, 404, 408, 409, 410,
+ 414, 415, 416, 420, 421, 422, 423, 427, 428, 429,
+ 430, 435, 438, 442, 450, 453, 457, 465, 469, 473
};
#endif
-#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+#if YYDEBUG || YYERROR_VERBOSE || 0
/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
First, the terminals, then, starting at YYNTOKENS, nonterminals. */
static const char *const yytname[] =
@@ -530,7 +555,7 @@ static const char *const yytname[] =
"integer_expr", "integer_trinary", "integer_or", "integer_and",
"integer_bitor", "integer_bitxor", "integer_bitand", "integer_eq",
"integer_rela", "integer_shift", "integer_add", "integer_mul",
- "integer_unary", "bytestring", "subnodes", "subnode", 0
+ "integer_unary", "bytestring", "subnodes", "subnode", YY_NULL
};
#endif
@@ -655,10 +680,10 @@ static const yytype_uint8 yytable[] =
137, 0, 73, 139
};
-#define yypact_value_is_default(yystate) \
- ((yystate) == (-78))
+#define yypact_value_is_default(Yystate) \
+ (!!((Yystate) == (-78)))
-#define yytable_value_is_error(yytable_value) \
+#define yytable_value_is_error(Yytable_value) \
YYID (0)
static const yytype_int16 yycheck[] =
@@ -727,62 +752,35 @@ static const yytype_uint8 yystos[] =
#define YYRECOVERING() (!!yyerrstatus)
-#define YYBACKUP(Token, Value) \
-do \
- if (yychar == YYEMPTY && yylen == 1) \
- { \
- yychar = (Token); \
- yylval = (Value); \
- YYPOPSTACK (1); \
- goto yybackup; \
- } \
- else \
- { \
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ YYPOPSTACK (yylen); \
+ yystate = *yyssp; \
+ goto yybackup; \
+ } \
+ else \
+ { \
yyerror (YY_("syntax error: cannot back up")); \
YYERROR; \
} \
while (YYID (0))
-
+/* Error token number */
#define YYTERROR 1
#define YYERRCODE 256
-/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
- If N is 0, then set CURRENT to the empty location which ends
- the previous symbol: RHS[0] (always defined). */
-
-#define YYRHSLOC(Rhs, K) ((Rhs)[K])
-#ifndef YYLLOC_DEFAULT
-# define YYLLOC_DEFAULT(Current, Rhs, N) \
- do \
- if (YYID (N)) \
- { \
- (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
- (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
- (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
- (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
- } \
- else \
- { \
- (Current).first_line = (Current).last_line = \
- YYRHSLOC (Rhs, 0).last_line; \
- (Current).first_column = (Current).last_column = \
- YYRHSLOC (Rhs, 0).last_column; \
- } \
- while (YYID (0))
-#endif
-
-
/* This macro is provided for backward compatibility. */
-
#ifndef YY_LOCATION_PRINT
# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
#endif
/* YYLEX -- calling `yylex' with the right arguments. */
-
#ifdef YYLEX_PARAM
# define YYLEX yylex (YYLEX_PARAM)
#else
@@ -832,6 +830,8 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep)
YYSTYPE const * const yyvaluep;
#endif
{
+ FILE *yyo = yyoutput;
+ YYUSE (yyo);
if (!yyvaluep)
return;
# ifdef YYPRINT
@@ -840,11 +840,7 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep)
# else
YYUSE (yyoutput);
# endif
- switch (yytype)
- {
- default:
- break;
- }
+ YYUSE (yytype);
}
@@ -1083,12 +1079,11 @@ static int
yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
yytype_int16 *yyssp, int yytoken)
{
- YYSIZE_T yysize0 = yytnamerr (0, yytname[yytoken]);
+ YYSIZE_T yysize0 = yytnamerr (YY_NULL, yytname[yytoken]);
YYSIZE_T yysize = yysize0;
- YYSIZE_T yysize1;
enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
/* Internationalized format string. */
- const char *yyformat = 0;
+ const char *yyformat = YY_NULL;
/* Arguments of yyformat. */
char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
/* Number of reported tokens (one for the "unexpected", one per
@@ -1148,11 +1143,13 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
break;
}
yyarg[yycount++] = yytname[yyx];
- yysize1 = yysize + yytnamerr (0, yytname[yyx]);
- if (! (yysize <= yysize1
- && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
- return 2;
- yysize = yysize1;
+ {
+ YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULL, yytname[yyx]);
+ if (! (yysize <= yysize1
+ && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+ }
}
}
}
@@ -1172,10 +1169,12 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
# undef YYCASE_
}
- yysize1 = yysize + yystrlen (yyformat);
- if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
- return 2;
- yysize = yysize1;
+ {
+ YYSIZE_T yysize1 = yysize + yystrlen (yyformat);
+ if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+ }
if (*yymsg_alloc < yysize)
{
@@ -1231,36 +1230,26 @@ yydestruct (yymsg, yytype, yyvaluep)
yymsg = "Deleting";
YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
- switch (yytype)
- {
-
- default:
- break;
- }
+ YYUSE (yytype);
}
-/* Prevent warnings from -Wmissing-prototypes. */
-#ifdef YYPARSE_PARAM
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void *YYPARSE_PARAM);
-#else
-int yyparse ();
-#endif
-#else /* ! YYPARSE_PARAM */
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void);
-#else
-int yyparse ();
-#endif
-#endif /* ! YYPARSE_PARAM */
/* The lookahead symbol. */
int yychar;
+
+#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END
+#endif
+#ifndef YY_INITIAL_VALUE
+# define YY_INITIAL_VALUE(Value) /* Nothing. */
+#endif
+
/* The semantic value of the lookahead symbol. */
-YYSTYPE yylval;
+YYSTYPE yylval YY_INITIAL_VALUE(yyval_default);
/* Number of syntax errors so far. */
int yynerrs;
@@ -1300,7 +1289,7 @@ yyparse ()
`yyss': related to states.
`yyvs': related to semantic values.
- Refer to the stacks thru separate pointers, to allow yyoverflow
+ Refer to the stacks through separate pointers, to allow yyoverflow
to reallocate them elsewhere. */
/* The state stack. */
@@ -1318,7 +1307,7 @@ yyparse ()
int yyn;
int yyresult;
/* Lookahead token as an internal (translated) token number. */
- int yytoken;
+ int yytoken = 0;
/* The variables used to return semantic value and location from the
action routines. */
YYSTYPE yyval;
@@ -1336,9 +1325,8 @@ yyparse ()
Keep to zero when no symbol should be popped. */
int yylen = 0;
- yytoken = 0;
- yyss = yyssa;
- yyvs = yyvsa;
+ yyssp = yyss = yyssa;
+ yyvsp = yyvs = yyvsa;
yystacksize = YYINITDEPTH;
YYDPRINTF ((stderr, "Starting parse\n"));
@@ -1347,14 +1335,6 @@ yyparse ()
yyerrstatus = 0;
yynerrs = 0;
yychar = YYEMPTY; /* Cause a token to be read. */
-
- /* Initialize stack pointers.
- Waste one element of value and location stack
- so that they stay on the same level as the state stack.
- The wasted elements are never initialized. */
- yyssp = yyss;
- yyvsp = yyvs;
-
goto yysetstate;
/*------------------------------------------------------------.
@@ -1495,7 +1475,9 @@ yybackup:
yychar = YYEMPTY;
yystate = yyn;
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
*++yyvsp = yylval;
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
goto yynewstate;
@@ -1532,8 +1514,7 @@ yyreduce:
switch (yyn)
{
case 2:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 110 "dtc-parser.y"
{
the_boot_info = build_boot_info((yyvsp[(3) - (4)].re), (yyvsp[(4) - (4)].node),
@@ -1542,8 +1523,7 @@ yyreduce:
break;
case 3:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 118 "dtc-parser.y"
{
(yyval.re) = NULL;
@@ -1551,8 +1531,7 @@ yyreduce:
break;
case 4:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 122 "dtc-parser.y"
{
(yyval.re) = chain_reserve_entry((yyvsp[(1) - (2)].re), (yyvsp[(2) - (2)].re));
@@ -1560,8 +1539,7 @@ yyreduce:
break;
case 5:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 129 "dtc-parser.y"
{
(yyval.re) = build_reserve_entry((yyvsp[(2) - (4)].integer), (yyvsp[(3) - (4)].integer));
@@ -1569,8 +1547,7 @@ yyreduce:
break;
case 6:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 133 "dtc-parser.y"
{
add_label(&(yyvsp[(2) - (2)].re)->labels, (yyvsp[(1) - (2)].labelref));
@@ -1579,8 +1556,7 @@ yyreduce:
break;
case 7:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 141 "dtc-parser.y"
{
(yyval.node) = name_node((yyvsp[(2) - (2)].node), "");
@@ -1588,8 +1564,7 @@ yyreduce:
break;
case 8:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 145 "dtc-parser.y"
{
(yyval.node) = merge_nodes((yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
@@ -1597,8 +1572,7 @@ yyreduce:
break;
case 9:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 149 "dtc-parser.y"
{
struct node *target = get_node_by_ref((yyvsp[(1) - (3)].node), (yyvsp[(2) - (3)].labelref));
@@ -1612,8 +1586,7 @@ yyreduce:
break;
case 10:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 159 "dtc-parser.y"
{
struct node *target = get_node_by_ref((yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].labelref));
@@ -1628,8 +1601,7 @@ yyreduce:
break;
case 11:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 173 "dtc-parser.y"
{
(yyval.node) = build_node((yyvsp[(2) - (5)].proplist), (yyvsp[(3) - (5)].nodelist));
@@ -1637,8 +1609,7 @@ yyreduce:
break;
case 12:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 180 "dtc-parser.y"
{
(yyval.proplist) = NULL;
@@ -1646,8 +1617,7 @@ yyreduce:
break;
case 13:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 184 "dtc-parser.y"
{
(yyval.proplist) = chain_property((yyvsp[(2) - (2)].prop), (yyvsp[(1) - (2)].proplist));
@@ -1655,36 +1625,41 @@ yyreduce:
break;
case 14:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 191 "dtc-parser.y"
{
(yyval.prop) = build_property((yyvsp[(1) - (4)].propnodename), (yyvsp[(3) - (4)].data));
+ (yyval.prop)->loc.line = yylloc.first_line;
+ (yyval.prop)->loc.col = yylloc.first_column;
+ (yyval.prop)->loc.file = yylloc.file->name;
}
break;
case 15:
-
-/* Line 1806 of yacc.c */
-#line 195 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 198 "dtc-parser.y"
{
(yyval.prop) = build_property((yyvsp[(1) - (2)].propnodename), empty_data);
+ (yyval.prop)->loc.line = yylloc.first_line;
+ (yyval.prop)->loc.col = yylloc.first_column;
+ (yyval.prop)->loc.file = yylloc.file->name;
}
break;
case 16:
-
-/* Line 1806 of yacc.c */
-#line 199 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 205 "dtc-parser.y"
{
(yyval.prop) = build_property_delete((yyvsp[(2) - (3)].propnodename));
+ (yyval.prop)->loc.line = yylloc.first_line;
+ (yyval.prop)->loc.col = yylloc.first_column;
+ (yyval.prop)->loc.file = yylloc.file->name;
}
break;
case 17:
-
-/* Line 1806 of yacc.c */
-#line 203 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 212 "dtc-parser.y"
{
add_label(&(yyvsp[(2) - (2)].prop)->labels, (yyvsp[(1) - (2)].labelref));
(yyval.prop) = (yyvsp[(2) - (2)].prop);
@@ -1692,45 +1667,40 @@ yyreduce:
break;
case 18:
-
-/* Line 1806 of yacc.c */
-#line 211 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 220 "dtc-parser.y"
{
(yyval.data) = data_merge((yyvsp[(1) - (2)].data), (yyvsp[(2) - (2)].data));
}
break;
case 19:
-
-/* Line 1806 of yacc.c */
-#line 215 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 224 "dtc-parser.y"
{
(yyval.data) = data_merge((yyvsp[(1) - (3)].data), (yyvsp[(2) - (3)].array).data);
}
break;
case 20:
-
-/* Line 1806 of yacc.c */
-#line 219 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 228 "dtc-parser.y"
{
(yyval.data) = data_merge((yyvsp[(1) - (4)].data), (yyvsp[(3) - (4)].data));
}
break;
case 21:
-
-/* Line 1806 of yacc.c */
-#line 223 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 232 "dtc-parser.y"
{
(yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), REF_PATH, (yyvsp[(2) - (2)].labelref));
}
break;
case 22:
-
-/* Line 1806 of yacc.c */
-#line 227 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 236 "dtc-parser.y"
{
FILE *f = srcfile_relative_open((yyvsp[(4) - (9)].data).val, NULL);
struct data d;
@@ -1750,9 +1720,8 @@ yyreduce:
break;
case 23:
-
-/* Line 1806 of yacc.c */
-#line 244 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 253 "dtc-parser.y"
{
FILE *f = srcfile_relative_open((yyvsp[(4) - (5)].data).val, NULL);
struct data d = empty_data;
@@ -1765,45 +1734,40 @@ yyreduce:
break;
case 24:
-
-/* Line 1806 of yacc.c */
-#line 254 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 263 "dtc-parser.y"
{
(yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref));
}
break;
case 25:
-
-/* Line 1806 of yacc.c */
-#line 261 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 270 "dtc-parser.y"
{
(yyval.data) = empty_data;
}
break;
case 26:
-
-/* Line 1806 of yacc.c */
-#line 265 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 274 "dtc-parser.y"
{
(yyval.data) = (yyvsp[(1) - (2)].data);
}
break;
case 27:
-
-/* Line 1806 of yacc.c */
-#line 269 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 278 "dtc-parser.y"
{
(yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref));
}
break;
case 28:
-
-/* Line 1806 of yacc.c */
-#line 276 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 285 "dtc-parser.y"
{
(yyval.array).data = empty_data;
(yyval.array).bits = eval_literal((yyvsp[(2) - (3)].literal), 0, 7);
@@ -1821,9 +1785,8 @@ yyreduce:
break;
case 29:
-
-/* Line 1806 of yacc.c */
-#line 291 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 300 "dtc-parser.y"
{
(yyval.array).data = empty_data;
(yyval.array).bits = 32;
@@ -1831,9 +1794,8 @@ yyreduce:
break;
case 30:
-
-/* Line 1806 of yacc.c */
-#line 296 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 305 "dtc-parser.y"
{
if ((yyvsp[(1) - (2)].array).bits < 64) {
uint64_t mask = (1ULL << (yyvsp[(1) - (2)].array).bits) - 1;
@@ -1856,9 +1818,8 @@ yyreduce:
break;
case 31:
-
-/* Line 1806 of yacc.c */
-#line 316 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 325 "dtc-parser.y"
{
uint64_t val = ~0ULL >> (64 - (yyvsp[(1) - (2)].array).bits);
@@ -1875,244 +1836,212 @@ yyreduce:
break;
case 32:
-
-/* Line 1806 of yacc.c */
-#line 330 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 339 "dtc-parser.y"
{
(yyval.array).data = data_add_marker((yyvsp[(1) - (2)].array).data, LABEL, (yyvsp[(2) - (2)].labelref));
}
break;
case 33:
-
-/* Line 1806 of yacc.c */
-#line 337 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 346 "dtc-parser.y"
{
(yyval.integer) = eval_literal((yyvsp[(1) - (1)].literal), 0, 64);
}
break;
case 34:
-
-/* Line 1806 of yacc.c */
-#line 341 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 350 "dtc-parser.y"
{
(yyval.integer) = eval_char_literal((yyvsp[(1) - (1)].literal));
}
break;
case 35:
-
-/* Line 1806 of yacc.c */
-#line 345 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 354 "dtc-parser.y"
{
(yyval.integer) = (yyvsp[(2) - (3)].integer);
}
break;
case 38:
-
-/* Line 1806 of yacc.c */
-#line 356 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 365 "dtc-parser.y"
{ (yyval.integer) = (yyvsp[(1) - (5)].integer) ? (yyvsp[(3) - (5)].integer) : (yyvsp[(5) - (5)].integer); }
break;
case 40:
-
-/* Line 1806 of yacc.c */
-#line 361 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 370 "dtc-parser.y"
{ (yyval.integer) = (yyvsp[(1) - (3)].integer) || (yyvsp[(3) - (3)].integer); }
break;
case 42:
-
-/* Line 1806 of yacc.c */
-#line 366 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 375 "dtc-parser.y"
{ (yyval.integer) = (yyvsp[(1) - (3)].integer) && (yyvsp[(3) - (3)].integer); }
break;
case 44:
-
-/* Line 1806 of yacc.c */
-#line 371 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 380 "dtc-parser.y"
{ (yyval.integer) = (yyvsp[(1) - (3)].integer) | (yyvsp[(3) - (3)].integer); }
break;
case 46:
-
-/* Line 1806 of yacc.c */
-#line 376 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 385 "dtc-parser.y"
{ (yyval.integer) = (yyvsp[(1) - (3)].integer) ^ (yyvsp[(3) - (3)].integer); }
break;
case 48:
-
-/* Line 1806 of yacc.c */
-#line 381 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 390 "dtc-parser.y"
{ (yyval.integer) = (yyvsp[(1) - (3)].integer) & (yyvsp[(3) - (3)].integer); }
break;
case 50:
-
-/* Line 1806 of yacc.c */
-#line 386 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 395 "dtc-parser.y"
{ (yyval.integer) = (yyvsp[(1) - (3)].integer) == (yyvsp[(3) - (3)].integer); }
break;
case 51:
-
-/* Line 1806 of yacc.c */
-#line 387 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 396 "dtc-parser.y"
{ (yyval.integer) = (yyvsp[(1) - (3)].integer) != (yyvsp[(3) - (3)].integer); }
break;
case 53:
-
-/* Line 1806 of yacc.c */
-#line 392 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 401 "dtc-parser.y"
{ (yyval.integer) = (yyvsp[(1) - (3)].integer) < (yyvsp[(3) - (3)].integer); }
break;
case 54:
-
-/* Line 1806 of yacc.c */
-#line 393 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 402 "dtc-parser.y"
{ (yyval.integer) = (yyvsp[(1) - (3)].integer) > (yyvsp[(3) - (3)].integer); }
break;
case 55:
-
-/* Line 1806 of yacc.c */
-#line 394 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 403 "dtc-parser.y"
{ (yyval.integer) = (yyvsp[(1) - (3)].integer) <= (yyvsp[(3) - (3)].integer); }
break;
case 56:
-
-/* Line 1806 of yacc.c */
-#line 395 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 404 "dtc-parser.y"
{ (yyval.integer) = (yyvsp[(1) - (3)].integer) >= (yyvsp[(3) - (3)].integer); }
break;
case 57:
-
-/* Line 1806 of yacc.c */
-#line 399 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 408 "dtc-parser.y"
{ (yyval.integer) = (yyvsp[(1) - (3)].integer) << (yyvsp[(3) - (3)].integer); }
break;
case 58:
-
-/* Line 1806 of yacc.c */
-#line 400 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 409 "dtc-parser.y"
{ (yyval.integer) = (yyvsp[(1) - (3)].integer) >> (yyvsp[(3) - (3)].integer); }
break;
case 60:
-
-/* Line 1806 of yacc.c */
-#line 405 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 414 "dtc-parser.y"
{ (yyval.integer) = (yyvsp[(1) - (3)].integer) + (yyvsp[(3) - (3)].integer); }
break;
case 61:
-
-/* Line 1806 of yacc.c */
-#line 406 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 415 "dtc-parser.y"
{ (yyval.integer) = (yyvsp[(1) - (3)].integer) - (yyvsp[(3) - (3)].integer); }
break;
case 63:
-
-/* Line 1806 of yacc.c */
-#line 411 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 420 "dtc-parser.y"
{ (yyval.integer) = (yyvsp[(1) - (3)].integer) * (yyvsp[(3) - (3)].integer); }
break;
case 64:
-
-/* Line 1806 of yacc.c */
-#line 412 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 421 "dtc-parser.y"
{ (yyval.integer) = (yyvsp[(1) - (3)].integer) / (yyvsp[(3) - (3)].integer); }
break;
case 65:
-
-/* Line 1806 of yacc.c */
-#line 413 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 422 "dtc-parser.y"
{ (yyval.integer) = (yyvsp[(1) - (3)].integer) % (yyvsp[(3) - (3)].integer); }
break;
case 68:
-
-/* Line 1806 of yacc.c */
-#line 419 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 428 "dtc-parser.y"
{ (yyval.integer) = -(yyvsp[(2) - (2)].integer); }
break;
case 69:
-
-/* Line 1806 of yacc.c */
-#line 420 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 429 "dtc-parser.y"
{ (yyval.integer) = ~(yyvsp[(2) - (2)].integer); }
break;
case 70:
-
-/* Line 1806 of yacc.c */
-#line 421 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 430 "dtc-parser.y"
{ (yyval.integer) = !(yyvsp[(2) - (2)].integer); }
break;
case 71:
-
-/* Line 1806 of yacc.c */
-#line 426 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 435 "dtc-parser.y"
{
(yyval.data) = empty_data;
}
break;
case 72:
-
-/* Line 1806 of yacc.c */
-#line 430 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 439 "dtc-parser.y"
{
(yyval.data) = data_append_byte((yyvsp[(1) - (2)].data), (yyvsp[(2) - (2)].byte));
}
break;
case 73:
-
-/* Line 1806 of yacc.c */
-#line 434 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 443 "dtc-parser.y"
{
(yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref));
}
break;
case 74:
-
-/* Line 1806 of yacc.c */
-#line 441 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 450 "dtc-parser.y"
{
(yyval.nodelist) = NULL;
}
break;
case 75:
-
-/* Line 1806 of yacc.c */
-#line 445 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 454 "dtc-parser.y"
{
(yyval.nodelist) = chain_node((yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].nodelist));
}
break;
case 76:
-
-/* Line 1806 of yacc.c */
-#line 449 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 458 "dtc-parser.y"
{
print_error("syntax error: properties must precede subnodes");
YYERROR;
@@ -2120,27 +2049,24 @@ yyreduce:
break;
case 77:
-
-/* Line 1806 of yacc.c */
-#line 457 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 466 "dtc-parser.y"
{
(yyval.node) = name_node((yyvsp[(2) - (2)].node), (yyvsp[(1) - (2)].propnodename));
}
break;
case 78:
-
-/* Line 1806 of yacc.c */
-#line 461 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 470 "dtc-parser.y"
{
(yyval.node) = name_node(build_node_delete(), (yyvsp[(2) - (3)].propnodename));
}
break;
case 79:
-
-/* Line 1806 of yacc.c */
-#line 465 "dtc-parser.y"
+/* Line 1787 of yacc.c */
+#line 474 "dtc-parser.y"
{
add_label(&(yyvsp[(2) - (2)].node)->labels, (yyvsp[(1) - (2)].labelref));
(yyval.node) = (yyvsp[(2) - (2)].node);
@@ -2148,9 +2074,8 @@ yyreduce:
break;
-
-/* Line 1806 of yacc.c */
-#line 2154 "dtc-parser.tab.c"
+/* Line 1787 of yacc.c */
+#line 2079 "dtc-parser.tab.c"
default: break;
}
/* User semantic actions sometimes alter yychar, and that requires
@@ -2313,7 +2238,9 @@ yyerrlab1:
YY_STACK_PRINT (yyss, yyssp);
}
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
*++yyvsp = yylval;
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
/* Shift the error token. */
@@ -2337,7 +2264,7 @@ yyabortlab:
yyresult = 1;
goto yyreturn;
-#if !defined(yyoverflow) || YYERROR_VERBOSE
+#if !defined yyoverflow || YYERROR_VERBOSE
/*-------------------------------------------------.
| yyexhaustedlab -- memory exhaustion comes here. |
`-------------------------------------------------*/
@@ -2379,9 +2306,8 @@ yyreturn:
}
-
-/* Line 2067 of yacc.c */
-#line 471 "dtc-parser.y"
+/* Line 2050 of yacc.c */
+#line 480 "dtc-parser.y"
void print_error(char const *fmt, ...)
@@ -2444,4 +2370,3 @@ static unsigned char eval_char_literal(const char *s)
return c;
}
-
diff --git a/scripts/dtc/dtc-parser.y b/scripts/dtc/dtc-parser.y
index f412460..af4329a 100644
--- a/scripts/dtc/dtc-parser.y
+++ b/scripts/dtc/dtc-parser.y
@@ -190,14 +190,23 @@ propdef:
DT_PROPNODENAME '=' propdata ';'
{
$$ = build_property($1, $3);
+ $$->loc.line = yylloc.first_line;
+ $$->loc.col = yylloc.first_column;
+ $$->loc.file = yylloc.file->name;
}
| DT_PROPNODENAME ';'
{
$$ = build_property($1, empty_data);
+ $$->loc.line = yylloc.first_line;
+ $$->loc.col = yylloc.first_column;
+ $$->loc.file = yylloc.file->name;
}
| DT_DEL_PROP DT_PROPNODENAME ';'
{
$$ = build_property_delete($2);
+ $$->loc.line = yylloc.first_line;
+ $$->loc.col = yylloc.first_column;
+ $$->loc.file = yylloc.file->name;
}
| DT_LABEL propdef
{
diff --git a/scripts/dtc/dtc.h b/scripts/dtc/dtc.h
index 2b14b3a..e61dde7 100644
--- a/scripts/dtc/dtc.h
+++ b/scripts/dtc/dtc.h
@@ -133,6 +133,12 @@ struct label {
struct label *next;
};
+struct srcloc {
+ int line;
+ int col;
+ const char *file;
+};
+
struct property {
int deleted;
char *name;
@@ -141,6 +147,7 @@ struct property {
struct property *next;
struct label *labels;
+ struct srcloc loc;
};
struct node {
diff --git a/scripts/dtc/schema.c b/scripts/dtc/schema.c
index a797821..b190241 100644
--- a/scripts/dtc/schema.c
+++ b/scripts/dtc/schema.c
@@ -4,6 +4,23 @@
#include <sys/types.h>
#include <dirent.h>
#include <pcre.h>
+#include <stdio.h>
+
+#define DT_ERROR(path, p, format, ...) \
+ do { \
+ dt_error(path, p, format, ##__VA_ARGS__); \
+ ret = 0; \
+ goto end; \
+ } while (0)
+
+#define DT_ERROR_IF(assertion, path, p, format, ...) \
+ do { \
+ if (!(assertion)) \
+ break; \
+ dt_error(path, p, format, ##__VA_ARGS__); \
+ ret = 0; \
+ goto end; \
+ } while (0)
static const char *const SCHEMA_EXT = ".schema";
static const char *const VALUE_PROPNAME = "value";
@@ -94,6 +111,22 @@ static struct property *get_property_matching_pattern(struct property **list,
return p;
}
+static char *build_path(struct node_list *path)
+{
+ char *str = xstrdup("");
+ char *p = NULL;
+
+ for (; path; path = path->next) {
+ assert(path->n);
+
+ assert(asprintf(&p, "%s/%s", path->n->name, str) != -1);
+
+ free(str);
+ str = p;
+ }
+ return str;
+}
+
static int is_prop_value(const char *p)
{
int is_value = 1;
@@ -110,6 +143,42 @@ static int is_prop_value(const char *p)
/** Schema Validation */
+static void dt_error(struct node_list *path,
+ struct property *p,
+ const char *format, ...)
+ __attribute__((format(printf, 3, 4)));
+
+static void dt_error(struct node_list *path,
+ struct property *p,
+ const char *format, ...)
+{
+ char *strpath;
+ va_list vl;
+ va_start(vl, format);
+
+ assert(format);
+
+ fprintf(stderr, "FATAL ERROR");
+ if (p) {
+ fprintf(stderr, " in %s:%d:%d",
+ p->loc.file, p->loc.line, p->loc.col);
+ }
+ fprintf(stderr, " | ");
+
+ if (path) {
+ strpath = build_path(path);
+ fprintf(stderr, "%s", strpath);
+ free(strpath);
+ }
+
+ fprintf(stderr, "%s: ", p ? p->name : "");
+ vfprintf(stderr, format, vl);
+
+ va_end(vl);
+ if (exit_on_failure)
+ exit(1);
+}
+
static void free_property_constraints(struct prop_constraints *pc)
{
if (!pc)
--
1.8.1.2
^ permalink raw reply related [flat|nested] 36+ messages in thread
* [RFC 05/15] scripts/dtc: check type on properties
2013-09-24 16:52 [RFC 00/15] Device Tree schemas and validation Benoit Cousson
2013-09-24 16:52 ` [RFC 01/15] scripts/dtc: fix most memory leaks in dtc Benoit Cousson
2013-09-24 16:52 ` [RFC 04/15] scripts/dtc: add procedure to handle dts errors Benoit Cousson
@ 2013-09-24 16:52 ` Benoit Cousson
2013-09-24 16:52 ` [RFC 07/15] scripts/dtc: can inherit properties Benoit Cousson
` (7 subsequent siblings)
10 siblings, 0 replies; 36+ messages in thread
From: Benoit Cousson @ 2013-09-24 16:52 UTC (permalink / raw)
To: olof, devicetree, tomasz.figa, swarren, grant.likely, rob.herring
Cc: khilman, linux-omap, linux-arm-kernel, fparent, Benoit Cousson
From: Fabien Parent <fparent@baylibre.com>
Add the ability to check if a property has the correct type. Right now dtc only
handles the two trivial types: integer array, string array. Since at the end
everything is an array of byte which may or may not be terminated by a null
byte this was enough.
A nice thing to add for the future would be to be able to specify the types
more precisely.
Add as well two test files for this feature.
/ {
compatible = "abc";
abc = <0xa 0xb 0xc>;
def = "def", gef;
};
To check that the property abc is an integer array and that the property def
is a string array for the dts above one can use the following schema:
/ {
compatible = "abc";
abc {
type = "integer";
};
def {
type = "string";
};
};
Signed-off-by: Fabien Parent <fparent@baylibre.com>
Signed-off-by: Benoit Cousson <bcousson@baylibre.com>
---
scripts/dtc/data.c | 22 ++++++++++++----
scripts/dtc/dtc.h | 9 +++++++
scripts/dtc/schema-test.c | 5 ++++
scripts/dtc/schema.c | 44 ++++++++++++++++++++++++++++++++
scripts/dtc/tests/schemas/types-1.schema | 12 +++++++++
scripts/dtc/tests/schemas/types-2.schema | 7 +++++
scripts/dtc/tests/test1.dts | 10 ++++++++
7 files changed, 104 insertions(+), 5 deletions(-)
create mode 100644 scripts/dtc/tests/schemas/types-1.schema
create mode 100644 scripts/dtc/tests/schemas/types-2.schema
create mode 100644 scripts/dtc/tests/test1.dts
diff --git a/scripts/dtc/data.c b/scripts/dtc/data.c
index 4a40c5b..9e03718 100644
--- a/scripts/dtc/data.c
+++ b/scripts/dtc/data.c
@@ -75,6 +75,7 @@ struct data data_copy_escape_string(const char *s, int len)
char *q;
d = data_grow_for(empty_data, strlen(s)+1);
+ d.type = STRING;
q = d.val;
while (i < len) {
@@ -93,6 +94,7 @@ struct data data_copy_escape_string(const char *s, int len)
struct data data_copy_file(FILE *f, size_t maxlen)
{
struct data d = empty_data;
+ d.type = STRING;
while (!feof(f) && (d.len < maxlen)) {
size_t chunksize, ret;
@@ -157,6 +159,7 @@ struct data data_merge(struct data d1, struct data d2)
struct marker *m2 = d2.markers;
d = data_append_markers(data_append_data(d1, d2.val, d2.len), m2);
+ d.type = d2.type ? d2.type : d1.type;
/* Adjust for the length of d1 */
for_each_marker(m2)
@@ -178,23 +181,30 @@ struct data data_append_integer(struct data d, uint64_t value, int bits)
switch (bits) {
case 8:
value_8 = value;
- return data_append_data(d, &value_8, 1);
+ d = data_append_data(d, &value_8, 1);
+ break;
case 16:
value_16 = cpu_to_fdt16(value);
- return data_append_data(d, &value_16, 2);
+ d = data_append_data(d, &value_16, 2);
+ break;
case 32:
value_32 = cpu_to_fdt32(value);
- return data_append_data(d, &value_32, 4);
+ d = data_append_data(d, &value_32, 4);
+ break;
case 64:
value_64 = cpu_to_fdt64(value);
- return data_append_data(d, &value_64, 8);
+ d = data_append_data(d, &value_64, 8);
+ break;
default:
die("Invalid literal size (%d)\n", bits);
}
+
+ d.type = INTEGER;
+ return d;
}
struct data data_append_re(struct data d, const struct fdt_reserve_entry *re)
@@ -219,7 +229,9 @@ struct data data_append_addr(struct data d, uint64_t addr)
struct data data_append_byte(struct data d, uint8_t byte)
{
- return data_append_data(d, &byte, 1);
+ d = data_append_data(d, &byte, 1);
+ d.type = INTEGER;
+ return d;
}
struct data data_append_zeroes(struct data d, int len)
diff --git a/scripts/dtc/dtc.h b/scripts/dtc/dtc.h
index e61dde7..a9b8602 100644
--- a/scripts/dtc/dtc.h
+++ b/scripts/dtc/dtc.h
@@ -82,10 +82,19 @@ struct marker {
struct marker *next;
};
+enum datatype {
+ UNDEFINED,
+ BOOLEAN,
+ INTEGER,
+ STRING,
+};
+
struct data {
int len;
char *val;
struct marker *markers;
+
+ enum datatype type;
};
diff --git a/scripts/dtc/schema-test.c b/scripts/dtc/schema-test.c
index 0eb2499..57c86d0 100644
--- a/scripts/dtc/schema-test.c
+++ b/scripts/dtc/schema-test.c
@@ -18,6 +18,11 @@ struct schema_test {
};
static struct schema_test tests[] = {
+ /* Types */
+ {"Types #1", "tests/test1.dts",
+ "tests/schemas/types-1.schema", 1},
+ {"Types #2", "tests/test1.dts",
+ "tests/schemas/types-2.schema", 0},
};
int main(void)
diff --git a/scripts/dtc/schema.c b/scripts/dtc/schema.c
index b190241..c01cdee 100644
--- a/scripts/dtc/schema.c
+++ b/scripts/dtc/schema.c
@@ -33,6 +33,7 @@ struct node_list {
struct prop_constraints {
const char *name;
+ char *type;
};
struct node_constraints {
@@ -202,9 +203,41 @@ load_property_constraints(struct node *schema)
if (p)
pc->name = p->val.val;
+ p = get_property(schema, "type");
+ if (p)
+ pc->type = p->val.val;
+
return pc;
}
+static int check_types(struct property *p, struct prop_constraints *pc)
+{
+ assert(p);
+ assert(pc);
+
+ if (!pc->type)
+ return 1;
+
+ switch (p->val.type) {
+ case BOOLEAN:
+ return !strcmp(pc->type, "bool");
+
+ case STRING:
+ return !strcmp(pc->type, "string");
+
+ case INTEGER:
+ return !strcmp(pc->type, "integer");
+
+ case UNDEFINED:
+ return 1;
+
+ default:
+ die("We shouldn't reach this point.");
+ };
+
+ return 0;
+}
+
static int validate_properties(struct node *n,
struct node *schema,
struct node_list *path);
@@ -222,6 +255,15 @@ static int validate_property(struct node *n,
assert(pc);
assert(path);
+ if (!p)
+ goto end;
+
+ if (!check_types(p, pc)) {
+ DT_ERROR(path, p, "Bad type for property, expecting a value of "
+ "the following type: '%s'\n", pc->type);
+ }
+
+end:
free_property_constraints(pc);
return ret;
}
@@ -319,6 +361,7 @@ static int for_each_compatible_validate(struct schema_db *db,
assert(db);
assert(node);
assert(p);
+ assert(p->val.type == STRING);
while (offset >= 0 && offset < p->val.len) {
i = 0;
@@ -455,6 +498,7 @@ static void add_to_schema_db_from_property(struct schema_db *db,
assert(db);
assert(file);
assert(p);
+ assert(p->val.type == STRING);
while (offset >= 0 && offset < p->val.len) {
add_compatible_to_schema_db(db, p->val.val + offset, file);
diff --git a/scripts/dtc/tests/schemas/types-1.schema b/scripts/dtc/tests/schemas/types-1.schema
new file mode 100644
index 0000000..71d09e7
--- /dev/null
+++ b/scripts/dtc/tests/schemas/types-1.schema
@@ -0,0 +1,12 @@
+/dts-v1/;
+/ {
+ compatible = "compat1";
+
+ mypropint {
+ type = "integer";
+ };
+
+ mypropstr {
+ type = "string";
+ };
+};
diff --git a/scripts/dtc/tests/schemas/types-2.schema b/scripts/dtc/tests/schemas/types-2.schema
new file mode 100644
index 0000000..f0779e1
--- /dev/null
+++ b/scripts/dtc/tests/schemas/types-2.schema
@@ -0,0 +1,7 @@
+/dts-v1/;
+/ {
+ compatible = "compat1";
+ mypropstr {
+ type = "integer";
+ };
+};
diff --git a/scripts/dtc/tests/test1.dts b/scripts/dtc/tests/test1.dts
new file mode 100644
index 0000000..9a950da
--- /dev/null
+++ b/scripts/dtc/tests/test1.dts
@@ -0,0 +1,10 @@
+/dts-v1/;
+/ {
+ compatible = "root", "node";
+
+ node1 {
+ compatible = "compat1";
+ mypropint = <0 2 4 6>;
+ mypropstr = "value0", "value1", "value2";
+ };
+};
--
1.8.1.2
^ permalink raw reply related [flat|nested] 36+ messages in thread
* [RFC 07/15] scripts/dtc: can inherit properties
2013-09-24 16:52 [RFC 00/15] Device Tree schemas and validation Benoit Cousson
` (2 preceding siblings ...)
2013-09-24 16:52 ` [RFC 05/15] scripts/dtc: check type on properties Benoit Cousson
@ 2013-09-24 16:52 ` Benoit Cousson
[not found] ` <1380041541-17529-1-git-send-email-bcousson-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
` (6 subsequent siblings)
10 siblings, 0 replies; 36+ messages in thread
From: Benoit Cousson @ 2013-09-24 16:52 UTC (permalink / raw)
To: olof, devicetree, tomasz.figa, swarren, grant.likely, rob.herring
Cc: khilman, linux-omap, linux-arm-kernel, fparent, Benoit Cousson
From: Fabien Parent <fparent@baylibre.com>
Sometimes one may want a property to be required but the property could be
defined in a particular node or it could be defined in any of its parents node.
The concept of property inheritence has been added to fill this need. One can
specify that a property must be present in a node or in any of its parents by
using the constraint 'can-be-inherited' in addition to 'is-required'.
Add as well two test files for this feature.
twl {
interrupt-controller;
rtc {
compatible = "ti,twl4030-rtc";
interrupts = <0xc>;
};
}
In the case of the rtc above the interrupt-controller is not present,
but it is present in its parent. If inheriting the property from the parent
makes senses like here one can specify in the schema that interrupt-controller
is required in the rtc node and that the property can be inherited
from a parent.
/dts-v1/;
/ {
compatible = "ti,twl[0-9]+-rtc";
interrupt-controller {
is-required;
can-be-inherited;
};
};
Signed-off-by: Fabien Parent <fparent@baylibre.com>
Signed-off-by: Benoit Cousson <bcousson@baylibre.com>
---
scripts/dtc/schema-test.c | 6 ++++++
scripts/dtc/schema.c | 15 +++++++++++++--
scripts/dtc/tests/schemas/inheritence-1.schema | 7 +++++++
scripts/dtc/tests/schemas/inheritence-2.schema | 8 ++++++++
scripts/dtc/tests/test1.dts | 4 ++++
5 files changed, 38 insertions(+), 2 deletions(-)
create mode 100644 scripts/dtc/tests/schemas/inheritence-1.schema
create mode 100644 scripts/dtc/tests/schemas/inheritence-2.schema
diff --git a/scripts/dtc/schema-test.c b/scripts/dtc/schema-test.c
index 8ac4f58..99a4142 100644
--- a/scripts/dtc/schema-test.c
+++ b/scripts/dtc/schema-test.c
@@ -24,6 +24,12 @@ static struct schema_test tests[] = {
{"Required Property #2", "tests/test1.dts",
"tests/schemas/required-property-2.schema", 1},
+ /* Inheritence */
+ {"Required Property Inheritence #1", "tests/test1.dts",
+ "tests/schemas/inheritence-1.schema", 0},
+ {"Required Property Inheritence #2", "tests/test1.dts",
+ "tests/schemas/inheritence-2.schema", 1},
+
/* Types */
{"Types #1", "tests/test1.dts",
"tests/schemas/types-1.schema", 1},
diff --git a/scripts/dtc/schema.c b/scripts/dtc/schema.c
index 97ea5b0..95fc44b 100644
--- a/scripts/dtc/schema.c
+++ b/scripts/dtc/schema.c
@@ -35,6 +35,7 @@ struct prop_constraints {
const char *name;
char *type;
int is_required;
+ int can_be_inherited;
};
struct node_constraints {
@@ -201,6 +202,7 @@ load_property_constraints(struct node *schema)
memset(pc, 0, sizeof(*pc));
pc->is_required = get_property(schema, "is-required") != NULL;
+ pc->can_be_inherited = get_property(schema, "can-be-inherited") != NULL;
p = get_property(schema, "name");
if (p)
@@ -258,8 +260,17 @@ static int validate_property(struct node *n,
assert(pc);
assert(path);
- if (pc->is_required && !p)
- DT_ERROR(path, NULL, "Missing property '%s'\n", schema->name);
+ if (pc->is_required && !p) {
+ if (pc->can_be_inherited && path->next) {
+ assert(path->next->n);
+ ret &= validate_properties(path->next->n,
+ schema,
+ path->next);
+ } else {
+ DT_ERROR(path, NULL, "Missing property '%s'\n",
+ schema->name);
+ }
+ }
if (!p)
goto end;
diff --git a/scripts/dtc/tests/schemas/inheritence-1.schema b/scripts/dtc/tests/schemas/inheritence-1.schema
new file mode 100644
index 0000000..2a64ea7
--- /dev/null
+++ b/scripts/dtc/tests/schemas/inheritence-1.schema
@@ -0,0 +1,7 @@
+/dts-v1/;
+/ {
+ compatible = "compat2";
+ mypropstr {
+ is-required;
+ };
+};
diff --git a/scripts/dtc/tests/schemas/inheritence-2.schema b/scripts/dtc/tests/schemas/inheritence-2.schema
new file mode 100644
index 0000000..3da0f64
--- /dev/null
+++ b/scripts/dtc/tests/schemas/inheritence-2.schema
@@ -0,0 +1,8 @@
+/dts-v1/;
+/ {
+ compatible = "compat2";
+ mypropstr {
+ is-required;
+ can-be-inherited;
+ };
+};
diff --git a/scripts/dtc/tests/test1.dts b/scripts/dtc/tests/test1.dts
index 9a950da..a296591 100644
--- a/scripts/dtc/tests/test1.dts
+++ b/scripts/dtc/tests/test1.dts
@@ -6,5 +6,9 @@
compatible = "compat1";
mypropint = <0 2 4 6>;
mypropstr = "value0", "value1", "value2";
+
+ subnode1 {
+ compatible = "compat2";
+ };
};
};
--
1.8.1.2
^ permalink raw reply related [flat|nested] 36+ messages in thread
[parent not found: <1380041541-17529-1-git-send-email-bcousson-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>]
* [RFC 02/15] scripts/dtc: build schema index for dts validation
[not found] ` <1380041541-17529-1-git-send-email-bcousson-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
@ 2013-09-24 16:52 ` Benoit Cousson
2013-09-24 16:52 ` [RFC 03/15] scripts/dtc: validate each nodes and properties Benoit Cousson
` (5 subsequent siblings)
6 siblings, 0 replies; 36+ messages in thread
From: Benoit Cousson @ 2013-09-24 16:52 UTC (permalink / raw)
To: olof-nZhT3qVonbNeoWH0uzbU5w, devicetree-u79uwXL29TY76Z2rM5mHXA,
tomasz.figa-Re5JQEeQqe8AvxtiuMwx3w,
swarren-3lzwWm7+Weoh9ZMKESR00Q,
grant.likely-s3s/WqlpOiPyB63q8FvJNQ,
rob.herring-bsGFqQB8/DxBDgjK7y7TUQ
Cc: khilman-QSEj5FYQhm4dnm+yROfE0A, linux-omap-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
fparent-rdvid1DuHRBWk0Htik3J/w, Benoit Cousson
From: Fabien Parent <fparent-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
Add the infrastructure for dts validation through schema. The code build
an index of all the schemas found in a path given by the user on the
command line. This index will be used for the validation of a dts, it will be
used to know if a schema exists for a particular node and where to find it.
The association between a node of a dts and a schema is made through the
compatible property of the former.
timer1: timer@4a318000 {
compatible = "ti,omap3430-timer";
reg = <0x4a318000 0x80>;
interrupts = <0x0 0x25 0x4>;
ti,hwmods = "timer1";
ti,timer-alwon;
};
A schema for this node would probably be something like this:
/dts-v1/;
/ {
compatible = "ti,omap3430-timer";
...
};
The compatible property in the schema is specified through a regular
expression so if the schema must validate timers for every omap device,
something like this would probably be more appropriate:
compatible = "ti,omap[0-9]+-timer";
It is possible to specify several compatible in a single schema like this:
compatible = "ti,omap3430-timer", "ti,omap4430-timer";
The following syntax is also available:
compatible {
description = "A small description";
value = "ti,omap4430-timer";
};
Signed-off-by: Fabien Parent <fparent-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
Signed-off-by: Benoit Cousson <bcousson-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
---
scripts/dtc/.gitignore | 2 +-
scripts/dtc/Makefile | 9 +-
scripts/dtc/dtc.c | 19 ++-
scripts/dtc/dtc.h | 11 ++
scripts/dtc/schema-test.c | 67 +++++++++++
scripts/dtc/schema.c | 288 ++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 390 insertions(+), 6 deletions(-)
create mode 100644 scripts/dtc/schema-test.c
create mode 100644 scripts/dtc/schema.c
diff --git a/scripts/dtc/.gitignore b/scripts/dtc/.gitignore
index 095acb4..ff556dd 100644
--- a/scripts/dtc/.gitignore
+++ b/scripts/dtc/.gitignore
@@ -2,4 +2,4 @@ dtc
dtc-lexer.lex.c
dtc-parser.tab.c
dtc-parser.tab.h
-
+schema-test
diff --git a/scripts/dtc/Makefile b/scripts/dtc/Makefile
index 2a48022..7da5209 100644
--- a/scripts/dtc/Makefile
+++ b/scripts/dtc/Makefile
@@ -1,15 +1,18 @@
# scripts/dtc makefile
-hostprogs-y := dtc
+hostprogs-y := dtc schema-test
always := $(hostprogs-y)
dtc-objs := dtc.o flattree.o fstree.o data.o livetree.o treesource.o \
- srcpos.o checks.o util.o
+ srcpos.o checks.o util.o schema.o
dtc-objs += dtc-lexer.lex.o dtc-parser.tab.o
+schema-test-objs := $(dtc-objs:dtc.o=) schema-test.o
+
# Source files need to get at the userspace version of libfdt_env.h to compile
HOSTCFLAGS_DTC := -I$(src) -I$(src)/libfdt
+HOST_LOADLIBES := -lpcre
HOSTCFLAGS_checks.o := $(HOSTCFLAGS_DTC)
HOSTCFLAGS_data.o := $(HOSTCFLAGS_DTC)
@@ -20,6 +23,8 @@ HOSTCFLAGS_livetree.o := $(HOSTCFLAGS_DTC)
HOSTCFLAGS_srcpos.o := $(HOSTCFLAGS_DTC)
HOSTCFLAGS_treesource.o := $(HOSTCFLAGS_DTC)
HOSTCFLAGS_util.o := $(HOSTCFLAGS_DTC)
+HOSTCFLAGS_schema.o := $(HOSTCFLAGS_DTC)
+HOSTCFLAGS_schema-test.o := $(HOSTCFLAGS_DTC)
HOSTCFLAGS_dtc-lexer.lex.o := $(HOSTCFLAGS_DTC)
HOSTCFLAGS_dtc-parser.tab.o := $(HOSTCFLAGS_DTC)
diff --git a/scripts/dtc/dtc.c b/scripts/dtc/dtc.c
index 215ae92..a7881f0 100644
--- a/scripts/dtc/dtc.c
+++ b/scripts/dtc/dtc.c
@@ -96,16 +96,21 @@ static void __attribute__ ((noreturn)) usage(void)
fprintf(stderr, "\t-W [no-]<checkname>\n");
fprintf(stderr, "\t-E [no-]<checkname>\n");
fprintf(stderr, "\t\t\tenable or disable warnings and errors\n");
+ fprintf(stderr, "\t-M <schema folder>");
+ fprintf(stderr,
+ "\t\tCheck the dts using schemas from the specified folder\n");
exit(3);
}
int main(int argc, char *argv[])
{
struct boot_info *bi;
+ struct schema_db *sdb;
const char *inform = "dts";
const char *outform = "dts";
const char *outname = "-";
const char *depname = NULL;
+ const char *schemadir = NULL;
int force = 0, sort = 0;
const char *arg;
int opt;
@@ -118,7 +123,7 @@ int main(int argc, char *argv[])
minsize = 0;
padsize = 0;
- while ((opt = getopt(argc, argv, "hI:O:o:V:d:R:S:p:fqb:i:vH:sW:E:"))
+ while ((opt = getopt(argc, argv, "hI:O:o:V:d:R:S:p:fqb:i:vH:sW:E:M:"))
!= EOF) {
switch (opt) {
case 'I':
@@ -130,6 +135,9 @@ int main(int argc, char *argv[])
case 'o':
outname = optarg;
break;
+ case 'M':
+ schemadir = optarg;
+ break;
case 'V':
outversion = strtol(optarg, NULL, 0);
break;
@@ -212,9 +220,14 @@ int main(int argc, char *argv[])
fprintf(depfile, "%s:", outname);
}
- if (streq(inform, "dts"))
+ if (streq(inform, "dts")) {
bi = dt_from_source(arg);
- else if (streq(inform, "fs"))
+ if (schemadir) {
+ sdb = build_schema_db(schemadir);
+ validate_dt(sdb, bi);
+ free_schema_db(sdb);
+ }
+ } else if (streq(inform, "fs"))
bi = dt_from_fs(arg);
else if(streq(inform, "dtb"))
bi = dt_from_blob(arg);
diff --git a/scripts/dtc/dtc.h b/scripts/dtc/dtc.h
index 9c45fd2..2b14b3a 100644
--- a/scripts/dtc/dtc.h
+++ b/scripts/dtc/dtc.h
@@ -268,4 +268,15 @@ struct boot_info *dt_from_source(const char *f);
struct boot_info *dt_from_fs(const char *dirname);
+/* Schemas */
+
+struct schema_db;
+
+int validate_dt(struct schema_db *db, struct boot_info *bi);
+struct schema_db *build_schema_db(const char *dir);
+void free_schema_db(struct schema_db *db);
+void exit_on_schema_validation_failure(int exit);
+void add_to_schema_db(struct schema_db *db, const char *file);
+struct schema_db *new_schema_db(void);
+
#endif /* _DTC_H */
diff --git a/scripts/dtc/schema-test.c b/scripts/dtc/schema-test.c
new file mode 100644
index 0000000..0eb2499
--- /dev/null
+++ b/scripts/dtc/schema-test.c
@@ -0,0 +1,67 @@
+#include "dtc.h"
+#include <stdio.h>
+#include <fcntl.h>
+
+#define SIZE_ARRAY(x) (sizeof(x)/sizeof((x)[0]))
+
+int quiet;
+int reservenum;
+int minsize;
+int padsize;
+int phandle_format = PHANDLE_BOTH;
+
+struct schema_test {
+ const char *name;
+ const char *dts;
+ const char *schema;
+ int expected_result;
+};
+
+static struct schema_test tests[] = {
+};
+
+int main(void)
+{
+ struct boot_info *bi;
+ struct schema_db *db;
+ int result = 0;
+ int devnull_fd;
+ int stderr_fd;
+
+ exit_on_schema_validation_failure(0);
+ devnull_fd = open("/dev/null", O_RDWR | O_SYNC);
+ stderr_fd = dup(STDERR_FILENO);
+
+ int i;
+ for (i = 0; i < SIZE_ARRAY(tests); i++) {
+ assert(tests[i].name);
+ assert(tests[i].dts);
+ assert(tests[i].schema);
+
+ bi = dt_from_source(tests[i].dts);
+ db = new_schema_db();
+ add_to_schema_db(db, tests[i].schema);
+
+ dup2(devnull_fd, STDERR_FILENO);
+ result = validate_dt(db, bi);
+ dup2(stderr_fd, STDERR_FILENO);
+
+ fprintf(stderr, "[%s] %s\n",
+ result == tests[i].expected_result ? "PASS" : "FAIL",
+ tests[i].name);
+
+ /*
+ * In case of error re-run the test without hiding the
+ * error messages
+ */
+ if (result != tests[i].expected_result) {
+ validate_dt(db, bi);
+ printf("\n");
+ }
+
+ free_dt(bi);
+ free_schema_db(db);
+ }
+
+ return 0;
+}
diff --git a/scripts/dtc/schema.c b/scripts/dtc/schema.c
new file mode 100644
index 0000000..dd134d6
--- /dev/null
+++ b/scripts/dtc/schema.c
@@ -0,0 +1,288 @@
+#define _GNU_SOURCE
+#include "dtc.h"
+
+#include <sys/types.h>
+#include <dirent.h>
+#include <pcre.h>
+
+static const char *const SCHEMA_EXT = ".schema";
+static const char *const VALUE_PROPNAME = "value";
+static int exit_on_failure = 0;
+
+struct node_constraints {
+ pcre *re_compat;
+ char *filepath;
+ const char *compatible;
+};
+
+struct schema_db {
+ size_t buffer_size;
+ size_t size;
+
+ struct node_constraints *buffer;
+};
+
+/** Utils **/
+
+static pcre *compile_pattern(const char *pattern)
+{
+ char *regex;
+ const char *error;
+ int erroffset;
+ pcre *re;
+
+ assert(pattern);
+
+ assert(asprintf(®ex, "^%s$", pattern) != -1);
+
+ re = pcre_compile(regex, 0, &error, &erroffset, 0);
+ free(regex);
+
+ return re;
+}
+
+static int get_next_string_offset(struct property *p, int offset)
+{
+ assert(p);
+ assert(offset >= 0);
+
+ while (offset < p->val.len && p->val.val[offset])
+ offset++;
+
+ if (++offset < p->val.len)
+ return offset;
+ return -1;
+}
+
+static int is_prop_value(const char *p)
+{
+ int is_value = 1;
+ const size_t propname_size = strlen(VALUE_PROPNAME);
+
+ assert(p);
+
+ is_value = is_value && strstr(p, VALUE_PROPNAME) == p;
+ is_value = is_value && (p[propname_size] == '@'
+ || p[propname_size] == '\0');
+
+ return is_value;
+}
+
+/** Schema Validation */
+
+int validate_dt(struct schema_db *db, struct boot_info *bi)
+{
+ assert(bi);
+ assert(db);
+
+ return 1;
+}
+
+void exit_on_schema_validation_failure(int exit)
+{
+ exit_on_failure = exit;
+}
+
+/* Schema DB */
+
+static int is_schema_file(const char *file)
+{
+ const char *str;
+
+ if (!file)
+ return 0;
+
+ str = strstr(file, SCHEMA_EXT);
+ return str && str[strlen(SCHEMA_EXT)] == '\0';
+}
+
+static void init_schema_db(struct schema_db *db)
+{
+ assert(db);
+ memset(db, 0, sizeof(*db));
+
+ /*
+ * Starts with a DB size of 50 and double its size when the DB is full
+ */
+ db->buffer_size = 50;
+ db->buffer = xmalloc(sizeof(db->buffer[0]) * db->buffer_size);
+ memset(db->buffer, 0, sizeof(db->buffer[0]) * db->buffer_size);
+}
+
+static struct node_constraints *add_new_entry_to_schema_db(struct schema_db *db)
+{
+ assert(db);
+
+ if (db->size == db->buffer_size) {
+ db->buffer_size *= 2;
+ db->buffer = realloc(db->buffer,
+ db->buffer_size * sizeof(db->buffer[0]));
+ assert(db->buffer);
+ }
+
+ return &db->buffer[db->size++];
+}
+
+static struct node_constraints*
+add_compatible_to_schema_db(struct schema_db *db,
+ const char *compatible,
+ const char *file)
+{
+ struct node_constraints *nc;
+
+ assert(db);
+ assert(compatible);
+ assert(file);
+
+ nc = add_new_entry_to_schema_db(db);
+
+ nc->compatible = compatible;
+ nc->re_compat = compile_pattern(compatible);
+ if (!nc->re_compat)
+ die("Invalid regex for compatible in %s\n", file);
+
+ nc->filepath = xstrdup(file);
+ return nc;
+}
+
+static void add_to_schema_db_from_property(struct schema_db *db,
+ const char *file,
+ struct property *p,
+ struct node *root)
+{
+ int offset = 0;
+
+ assert(db);
+ assert(file);
+ assert(p);
+
+ while (offset >= 0 && offset < p->val.len) {
+ add_compatible_to_schema_db(db, p->val.val + offset, file);
+ offset = get_next_string_offset(p, offset);
+ }
+}
+
+static void add_to_schema_db_from_node(struct schema_db *db,
+ const char *file,
+ struct node *n,
+ struct node *root)
+{
+
+ struct property *p;
+ struct node *iter;
+
+ assert(db);
+ assert(file);
+ assert(root);
+
+ if (!n)
+ return;
+
+ for (p = n->proplist; p; p = p->next) {
+ if (!is_prop_value(p->name))
+ continue;
+ add_to_schema_db_from_property(db, file, p, root);
+ }
+
+ for (iter = n->children; iter; iter = iter->next_sibling)
+ add_to_schema_db_from_node(db, file, iter, root);
+}
+
+void add_to_schema_db(struct schema_db *db, const char *file)
+{
+ struct boot_info *bi;
+ struct node *n;
+ struct property *p;
+
+ assert(db);
+ assert(file);
+
+ bi = dt_from_source(file);
+ if (!bi)
+ die("Unable to load schema: %s\n", file);
+
+ assert(bi->dt);
+
+ n = get_node_by_path(bi->dt, "/compatible");
+ p = get_property(bi->dt, "compatible");
+ if (n)
+ add_to_schema_db_from_node(db, file, n, bi->dt);
+ else if (p)
+ add_to_schema_db_from_property(db, file, p, bi->dt);
+ else
+ die("No 'compatible' found in schema '%s'\n", file);
+
+ free_dt(bi);
+}
+
+static void add_schemas_to_db_from_dir(struct schema_db *db, const char *dir)
+{
+ DIR *d;
+ struct dirent *de;
+ char *filepath;
+ int res;
+
+ assert(dir);
+ assert(db);
+
+ d = opendir(dir);
+ if (!d)
+ die("Cannot open schema directory '%s'\n", dir);
+
+ while ((de = readdir(d)) != NULL) {
+ res = asprintf(&filepath, "%s/%s", dir, de->d_name);
+ assert(res >= 0);
+
+ if (de->d_type == DT_DIR && de->d_name[0] != '.')
+ add_schemas_to_db_from_dir(db, filepath);
+ else if (de->d_type == DT_REG && is_schema_file(de->d_name))
+ add_to_schema_db(db, filepath);
+
+ free(filepath);
+ }
+
+ closedir(d);
+}
+
+struct schema_db *new_schema_db(void)
+{
+ struct schema_db *db;
+
+ db = xmalloc(sizeof(*db));
+ init_schema_db(db);
+
+ return db;
+}
+
+struct schema_db *build_schema_db(const char *dir)
+{
+ struct schema_db *db;
+
+ db = new_schema_db();
+ add_schemas_to_db_from_dir(db, dir);
+
+ return db;
+}
+
+static void free_node_constraints(struct node_constraints *nc)
+{
+ if (!nc)
+ return;
+
+ pcre_free(nc->re_compat);
+ free(nc->filepath);
+}
+
+void free_schema_db(struct schema_db *db)
+{
+ int i;
+
+ if (!db)
+ return;
+
+ for (i = 0; i < db->size; i++)
+ free_node_constraints(db->buffer + i);
+
+ free(db->buffer);
+ free(db);
+}
--
1.8.1.2
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 36+ messages in thread
* [RFC 03/15] scripts/dtc: validate each nodes and properties
[not found] ` <1380041541-17529-1-git-send-email-bcousson-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
2013-09-24 16:52 ` [RFC 02/15] scripts/dtc: build schema index for dts validation Benoit Cousson
@ 2013-09-24 16:52 ` Benoit Cousson
2013-09-24 16:52 ` [RFC 06/15] scripts/dtc: check for required properties Benoit Cousson
` (4 subsequent siblings)
6 siblings, 0 replies; 36+ messages in thread
From: Benoit Cousson @ 2013-09-24 16:52 UTC (permalink / raw)
To: olof-nZhT3qVonbNeoWH0uzbU5w, devicetree-u79uwXL29TY76Z2rM5mHXA,
tomasz.figa-Re5JQEeQqe8AvxtiuMwx3w,
swarren-3lzwWm7+Weoh9ZMKESR00Q,
grant.likely-s3s/WqlpOiPyB63q8FvJNQ,
rob.herring-bsGFqQB8/DxBDgjK7y7TUQ
Cc: khilman-QSEj5FYQhm4dnm+yROfE0A, linux-omap-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
fparent-rdvid1DuHRBWk0Htik3J/w, Benoit Cousson
From: Fabien Parent <fparent-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
Add support to navigate through the device tree and try to validate each node
which has an associated schema in the schema index. So far, only the framework
is added and no validation is really done yet.
Signed-off-by: Fabien Parent <fparent-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
Signed-off-by: Benoit Cousson <bcousson-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
---
scripts/dtc/schema.c | 234 ++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 233 insertions(+), 1 deletion(-)
diff --git a/scripts/dtc/schema.c b/scripts/dtc/schema.c
index dd134d6..a797821 100644
--- a/scripts/dtc/schema.c
+++ b/scripts/dtc/schema.c
@@ -9,9 +9,21 @@ static const char *const SCHEMA_EXT = ".schema";
static const char *const VALUE_PROPNAME = "value";
static int exit_on_failure = 0;
+struct node_list {
+ struct node *n;
+ struct node_list *next;
+};
+
+struct prop_constraints {
+ const char *name;
+};
+
struct node_constraints {
pcre *re_compat;
char *filepath;
+ struct boot_info *bi;
+ struct node *dt;
+
const char *compatible;
};
@@ -54,6 +66,34 @@ static int get_next_string_offset(struct property *p, int offset)
return -1;
}
+static struct property *get_property_matching_pattern(struct property **list,
+ const char *pattern)
+{
+ struct property *p;
+ pcre *re;
+ int is_matching;
+
+ assert(list);
+ assert(pattern);
+
+ re = compile_pattern(pattern);
+ if (!re)
+ die("Invalid pattern: %s\n", pattern);
+
+ for (p = *list; p; p = p->next) {
+ assert(p->name);
+ is_matching = pcre_exec(re, 0, p->name, strlen(p->name),
+ 0, 0, NULL, 0) >= 0;
+ if (is_matching) {
+ *list = p->next;
+ break;
+ }
+ }
+
+ pcre_free(re);
+ return p;
+}
+
static int is_prop_value(const char *p)
{
int is_value = 1;
@@ -70,12 +110,203 @@ static int is_prop_value(const char *p)
/** Schema Validation */
+static void free_property_constraints(struct prop_constraints *pc)
+{
+ if (!pc)
+ return;
+
+ free(pc);
+}
+
+static struct prop_constraints*
+load_property_constraints(struct node *schema)
+{
+ struct property *p;
+ struct prop_constraints *pc;
+
+ assert(schema);
+
+ pc = xmalloc(sizeof(*pc));
+ memset(pc, 0, sizeof(*pc));
+
+ p = get_property(schema, "name");
+ if (p)
+ pc->name = p->val.val;
+
+ return pc;
+}
+
+static int validate_properties(struct node *n,
+ struct node *schema,
+ struct node_list *path);
+
+static int validate_property(struct node *n,
+ struct property *p,
+ struct prop_constraints *pc,
+ struct node *schema,
+ struct node_list *path)
+{
+ int ret = 1;
+
+ assert(n);
+ assert(schema);
+ assert(pc);
+ assert(path);
+
+ free_property_constraints(pc);
+ return ret;
+}
+
+static int validate_properties(struct node *n,
+ struct node *schema,
+ struct node_list *path)
+{
+ struct property *p;
+ struct property *iter;
+ struct prop_constraints *pc;
+ int ret = 1;
+
+ assert(n);
+ assert(schema);
+ assert(path);
+
+ pc = load_property_constraints(schema);
+ assert(pc);
+
+ iter = n->proplist;
+ p = get_property_matching_pattern(&iter, pc->name ?: schema->name);
+ ret &= validate_property(n, p, pc, schema, path);
+
+ /* if other properties match the pattern */
+ while (iter && p) {
+ p = get_property_matching_pattern(&iter, schema->name);
+ if (p)
+ ret &= validate_property(n, p, pc, schema, path);
+ else
+ break;
+ }
+
+ return ret;
+}
+
+static int validate_node(struct node *n,
+ struct node_constraints *nc,
+ struct node_list *path)
+{
+ struct node *iter;
+ int ret = 1;
+
+ assert(n);
+ assert(path);
+ assert(nc);
+ assert(nc->dt);
+
+ for (iter = nc->dt->children; iter; iter = iter->next_sibling)
+ ret &= validate_properties(n, iter, path);
+
+ return ret;
+}
+
+static struct node_constraints *get_node_constraints_of(struct schema_db *db,
+ const char *compat,
+ int *i)
+{
+ int has_match;
+ struct node_constraints *n;
+
+ assert(db);
+ assert(compat);
+ assert(i);
+
+ for (; *i < db->size; (*i)++) {
+ n = &db->buffer[*i];
+
+ has_match = pcre_exec(n->re_compat, 0, compat,
+ strlen(compat), 0, 0, NULL, 0) >= 0;
+ if (!has_match)
+ continue;
+
+ if (!n->bi) {
+ n->bi = dt_from_source(n->filepath);
+ n->dt = n->bi->dt;
+ }
+ (*i)++;
+ return n;
+ }
+
+ return NULL;
+}
+
+static int for_each_compatible_validate(struct schema_db *db,
+ struct property *p,
+ struct node *node,
+ struct node_list *path)
+{
+ struct node_constraints *nc;
+ int i;
+ int offset = 0;
+ int ret = 1;
+
+ assert(db);
+ assert(node);
+ assert(p);
+
+ while (offset >= 0 && offset < p->val.len) {
+ i = 0;
+ while ((nc = get_node_constraints_of(db, p->val.val + offset,
+ &i)) != NULL) {
+ ret &= validate_node(node, nc, path);
+ }
+
+ offset = get_next_string_offset(p, offset);
+ }
+
+ return ret;
+}
+
+static int validate_nodes(struct schema_db *db,
+ struct node *n,
+ struct node_list *path)
+{
+ struct property *p;
+ struct node *iter;
+ struct node_list *head_path = NULL;
+ int ret = 1;
+
+ assert(db);
+
+ if (!n)
+ return ret;
+
+ head_path = xmalloc(sizeof(*iter));
+ head_path->next = path;
+
+ for (iter = n; iter; iter = iter->next_sibling) {
+ /* Build the path to this node */
+ head_path->n = iter;
+
+ /* Validate children nodes */
+ ret &= validate_nodes(db, iter->children, head_path);
+
+ p = get_property(iter, "compatible");
+ if (!p)
+ continue;
+
+ /* Validate node */
+ ret &= for_each_compatible_validate(db, p, iter, head_path);
+ }
+
+ free(head_path);
+ return ret;
+}
+
int validate_dt(struct schema_db *db, struct boot_info *bi)
{
assert(bi);
+ assert(bi->dt);
assert(db);
- return 1;
+ return validate_nodes(db, bi->dt, NULL);
}
void exit_on_schema_validation_failure(int exit)
@@ -270,6 +501,7 @@ static void free_node_constraints(struct node_constraints *nc)
return;
pcre_free(nc->re_compat);
+ free_dt(nc->bi);
free(nc->filepath);
}
--
1.8.1.2
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 36+ messages in thread
* [RFC 06/15] scripts/dtc: check for required properties
[not found] ` <1380041541-17529-1-git-send-email-bcousson-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
2013-09-24 16:52 ` [RFC 02/15] scripts/dtc: build schema index for dts validation Benoit Cousson
2013-09-24 16:52 ` [RFC 03/15] scripts/dtc: validate each nodes and properties Benoit Cousson
@ 2013-09-24 16:52 ` Benoit Cousson
2013-09-24 16:52 ` [RFC 08/15] scripts/dtc: check array size Benoit Cousson
` (3 subsequent siblings)
6 siblings, 0 replies; 36+ messages in thread
From: Benoit Cousson @ 2013-09-24 16:52 UTC (permalink / raw)
To: olof-nZhT3qVonbNeoWH0uzbU5w, devicetree-u79uwXL29TY76Z2rM5mHXA,
tomasz.figa-Re5JQEeQqe8AvxtiuMwx3w,
swarren-3lzwWm7+Weoh9ZMKESR00Q,
grant.likely-s3s/WqlpOiPyB63q8FvJNQ,
rob.herring-bsGFqQB8/DxBDgjK7y7TUQ
Cc: khilman-QSEj5FYQhm4dnm+yROfE0A, linux-omap-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
fparent-rdvid1DuHRBWk0Htik3J/w, Benoit Cousson
From: Fabien Parent <fparent-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
Add the ability to specify inside a schema that a property is required to be
present in the validated node. By default a property can be missing but one can
require its presence inside a node via the 'is-required' property.
Add as well two test files for this feature.
timer1: timer@4a318000 {
compatible = "ti,omap3430-timer";
reg = <0x4a318000 0x80>;
interrupts = <0x0 0x25 0x4>;
ti,hwmods = "timer1";
ti,timer-alwon;
};
To make the ti,hwmods a required property inside an omap timer, one can use the
following schema:
/dts-v1/;
/ {
compatible = "ti,omap[0-9]+-timer";
ti,hwmods {
is-required;
};
};
Signed-off-by: Fabien Parent <fparent-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
Signed-off-by: Benoit Cousson <bcousson-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
---
scripts/dtc/schema-test.c | 6 ++++++
scripts/dtc/schema.c | 6 ++++++
scripts/dtc/tests/schemas/required-property-1.schema | 7 +++++++
scripts/dtc/tests/schemas/required-property-2.schema | 7 +++++++
4 files changed, 26 insertions(+)
create mode 100644 scripts/dtc/tests/schemas/required-property-1.schema
create mode 100644 scripts/dtc/tests/schemas/required-property-2.schema
diff --git a/scripts/dtc/schema-test.c b/scripts/dtc/schema-test.c
index 57c86d0..8ac4f58 100644
--- a/scripts/dtc/schema-test.c
+++ b/scripts/dtc/schema-test.c
@@ -18,6 +18,12 @@ struct schema_test {
};
static struct schema_test tests[] = {
+ /* Required Properties */
+ {"Required Property #1", "tests/test1.dts",
+ "tests/schemas/required-property-1.schema", 0},
+ {"Required Property #2", "tests/test1.dts",
+ "tests/schemas/required-property-2.schema", 1},
+
/* Types */
{"Types #1", "tests/test1.dts",
"tests/schemas/types-1.schema", 1},
diff --git a/scripts/dtc/schema.c b/scripts/dtc/schema.c
index c01cdee..97ea5b0 100644
--- a/scripts/dtc/schema.c
+++ b/scripts/dtc/schema.c
@@ -34,6 +34,7 @@ struct node_list {
struct prop_constraints {
const char *name;
char *type;
+ int is_required;
};
struct node_constraints {
@@ -199,6 +200,8 @@ load_property_constraints(struct node *schema)
pc = xmalloc(sizeof(*pc));
memset(pc, 0, sizeof(*pc));
+ pc->is_required = get_property(schema, "is-required") != NULL;
+
p = get_property(schema, "name");
if (p)
pc->name = p->val.val;
@@ -255,6 +258,9 @@ static int validate_property(struct node *n,
assert(pc);
assert(path);
+ if (pc->is_required && !p)
+ DT_ERROR(path, NULL, "Missing property '%s'\n", schema->name);
+
if (!p)
goto end;
diff --git a/scripts/dtc/tests/schemas/required-property-1.schema b/scripts/dtc/tests/schemas/required-property-1.schema
new file mode 100644
index 0000000..469fa5b
--- /dev/null
+++ b/scripts/dtc/tests/schemas/required-property-1.schema
@@ -0,0 +1,7 @@
+/dts-v1/;
+/ {
+ compatible = "compat1";
+ abc {
+ is-required;
+ };
+};
diff --git a/scripts/dtc/tests/schemas/required-property-2.schema b/scripts/dtc/tests/schemas/required-property-2.schema
new file mode 100644
index 0000000..35bdde1
--- /dev/null
+++ b/scripts/dtc/tests/schemas/required-property-2.schema
@@ -0,0 +1,7 @@
+/dts-v1/;
+/ {
+ compatible = "compat1";
+ mypropstr {
+ is-required;
+ };
+};
--
1.8.1.2
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 36+ messages in thread
* [RFC 08/15] scripts/dtc: check array size
[not found] ` <1380041541-17529-1-git-send-email-bcousson-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
` (2 preceding siblings ...)
2013-09-24 16:52 ` [RFC 06/15] scripts/dtc: check for required properties Benoit Cousson
@ 2013-09-24 16:52 ` Benoit Cousson
2013-09-24 16:52 ` [RFC 09/15] scripts/dtc: check value of properties Benoit Cousson
` (2 subsequent siblings)
6 siblings, 0 replies; 36+ messages in thread
From: Benoit Cousson @ 2013-09-24 16:52 UTC (permalink / raw)
To: olof-nZhT3qVonbNeoWH0uzbU5w, devicetree-u79uwXL29TY76Z2rM5mHXA,
tomasz.figa-Re5JQEeQqe8AvxtiuMwx3w,
swarren-3lzwWm7+Weoh9ZMKESR00Q,
grant.likely-s3s/WqlpOiPyB63q8FvJNQ,
rob.herring-bsGFqQB8/DxBDgjK7y7TUQ
Cc: khilman-QSEj5FYQhm4dnm+yROfE0A, linux-omap-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
fparent-rdvid1DuHRBWk0Htik3J/w, Benoit Cousson
From: Fabien Parent <fparent-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
Add constraints on array size:
- length: specify the exact length that an array must have.
- min-length: specify the minimum number of elements an array must have.
- max-length: specify the maximum number of elements an array must have.
Add as well four test files for the feature.
Usage example:
node {
compatible = "array_size";
myarray = <0 1 2 3 4>;
};
Schema:
/dts-v1/;
/ {
compatible = "array_size";
myarray {
length = <5>;
};
};
Signed-off-by: Fabien Parent <fparent-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
Signed-off-by: Benoit Cousson <bcousson-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
---
scripts/dtc/data.c | 5 +++
scripts/dtc/dtc.h | 1 +
scripts/dtc/schema-test.c | 10 ++++++
scripts/dtc/schema.c | 52 +++++++++++++++++++++++++++
scripts/dtc/tests/schemas/array-size-1.schema | 13 +++++++
scripts/dtc/tests/schemas/array-size-2.schema | 8 +++++
scripts/dtc/tests/schemas/array-size-3.schema | 8 +++++
scripts/dtc/tests/schemas/array-size-4.schema | 8 +++++
8 files changed, 105 insertions(+)
create mode 100644 scripts/dtc/tests/schemas/array-size-1.schema
create mode 100644 scripts/dtc/tests/schemas/array-size-2.schema
create mode 100644 scripts/dtc/tests/schemas/array-size-3.schema
create mode 100644 scripts/dtc/tests/schemas/array-size-4.schema
diff --git a/scripts/dtc/data.c b/scripts/dtc/data.c
index 9e03718..5284936 100644
--- a/scripts/dtc/data.c
+++ b/scripts/dtc/data.c
@@ -76,6 +76,7 @@ struct data data_copy_escape_string(const char *s, int len)
d = data_grow_for(empty_data, strlen(s)+1);
d.type = STRING;
+ d.array_size++;
q = d.val;
while (i < len) {
@@ -95,6 +96,7 @@ struct data data_copy_file(FILE *f, size_t maxlen)
{
struct data d = empty_data;
d.type = STRING;
+ d.array_size++;
while (!feof(f) && (d.len < maxlen)) {
size_t chunksize, ret;
@@ -159,6 +161,7 @@ struct data data_merge(struct data d1, struct data d2)
struct marker *m2 = d2.markers;
d = data_append_markers(data_append_data(d1, d2.val, d2.len), m2);
+ d.array_size += d2.array_size;
d.type = d2.type ? d2.type : d1.type;
/* Adjust for the length of d1 */
@@ -204,6 +207,7 @@ struct data data_append_integer(struct data d, uint64_t value, int bits)
}
d.type = INTEGER;
+ d.array_size++;
return d;
}
@@ -231,6 +235,7 @@ struct data data_append_byte(struct data d, uint8_t byte)
{
d = data_append_data(d, &byte, 1);
d.type = INTEGER;
+ d.array_size++;
return d;
}
diff --git a/scripts/dtc/dtc.h b/scripts/dtc/dtc.h
index a9b8602..64fdc8a 100644
--- a/scripts/dtc/dtc.h
+++ b/scripts/dtc/dtc.h
@@ -95,6 +95,7 @@ struct data {
struct marker *markers;
enum datatype type;
+ size_t array_size;
};
diff --git a/scripts/dtc/schema-test.c b/scripts/dtc/schema-test.c
index 99a4142..bfc9e43 100644
--- a/scripts/dtc/schema-test.c
+++ b/scripts/dtc/schema-test.c
@@ -35,6 +35,16 @@ static struct schema_test tests[] = {
"tests/schemas/types-1.schema", 1},
{"Types #2", "tests/test1.dts",
"tests/schemas/types-2.schema", 0},
+
+ /* Array Size */
+ {"Array Size #1", "tests/test1.dts",
+ "tests/schemas/array-size-1.schema", 1},
+ {"Array Size #2", "tests/test1.dts",
+ "tests/schemas/array-size-2.schema", 0},
+ {"Array Size #3", "tests/test1.dts",
+ "tests/schemas/array-size-3.schema", 0},
+ {"Array Size #4", "tests/test1.dts",
+ "tests/schemas/array-size-4.schema", 0},
};
int main(void)
diff --git a/scripts/dtc/schema.c b/scripts/dtc/schema.c
index 95fc44b..95ad925 100644
--- a/scripts/dtc/schema.c
+++ b/scripts/dtc/schema.c
@@ -5,6 +5,7 @@
#include <dirent.h>
#include <pcre.h>
#include <stdio.h>
+#include <limits.h>
#define DT_ERROR(path, p, format, ...) \
do { \
@@ -36,6 +37,8 @@ struct prop_constraints {
char *type;
int is_required;
int can_be_inherited;
+ size_t min_length;
+ size_t max_length;
};
struct node_constraints {
@@ -73,6 +76,28 @@ static pcre *compile_pattern(const char *pattern)
return re;
}
+static uint32_t prop_val_to_uint32(struct property *p, int i)
+{
+ assert(p);
+ assert(i >= 0);
+
+ switch (p->val.len / p->val.array_size) {
+ case 1:
+ return ((uint8_t *) p->val.val)[i];
+
+ case 2:
+ return fdt16_to_cpu(((uint16_t *) p->val.val)[i]);
+
+ case 4:
+ return fdt32_to_cpu(((uint32_t *) p->val.val)[i]);
+
+ default:
+ die("reach unreachable.");
+ }
+
+ return 0;
+}
+
static int get_next_string_offset(struct property *p, int offset)
{
assert(p);
@@ -203,6 +228,7 @@ load_property_constraints(struct node *schema)
pc->is_required = get_property(schema, "is-required") != NULL;
pc->can_be_inherited = get_property(schema, "can-be-inherited") != NULL;
+ pc->max_length = ULONG_MAX;
p = get_property(schema, "name");
if (p)
@@ -212,6 +238,24 @@ load_property_constraints(struct node *schema)
if (p)
pc->type = p->val.val;
+ p = get_property(schema, "length");
+ if (p) {
+ assert(p->val.type == INTEGER);
+ pc->min_length = pc->max_length = prop_val_to_uint32(p, 0);
+ }
+
+ p = get_property(schema, "min-length");
+ if (p) {
+ assert(p->val.type == INTEGER);
+ pc->min_length = prop_val_to_uint32(p, 0);
+ }
+
+ p = get_property(schema, "max-length");
+ if (p) {
+ assert(p->val.type == INTEGER);
+ pc->max_length = prop_val_to_uint32(p, 0);
+ }
+
return pc;
}
@@ -280,6 +324,14 @@ static int validate_property(struct node *n,
"the following type: '%s'\n", pc->type);
}
+ if (p->val.array_size < pc->min_length
+ || p->val.array_size > pc->max_length) {
+ DT_ERROR(path, p, "Incorrect number of elements.\n"
+ "\tShould have between %zu and %zu "
+ "but has %zu elements.\n", pc->min_length,
+ pc->max_length, p->val.array_size);
+ }
+
end:
free_property_constraints(pc);
return ret;
diff --git a/scripts/dtc/tests/schemas/array-size-1.schema b/scripts/dtc/tests/schemas/array-size-1.schema
new file mode 100644
index 0000000..b495090
--- /dev/null
+++ b/scripts/dtc/tests/schemas/array-size-1.schema
@@ -0,0 +1,13 @@
+/dts-v1/;
+/ {
+ compatible = "compat1";
+
+ mypropstr {
+ length = <3>;
+ };
+
+ mypropstr {
+ min-length = <2>;
+ max-length = <3>;
+ };
+};
diff --git a/scripts/dtc/tests/schemas/array-size-2.schema b/scripts/dtc/tests/schemas/array-size-2.schema
new file mode 100644
index 0000000..cd49361
--- /dev/null
+++ b/scripts/dtc/tests/schemas/array-size-2.schema
@@ -0,0 +1,8 @@
+/dts-v1/;
+/ {
+ compatible = "compat1";
+
+ mypropstr {
+ length = <4>;
+ };
+};
diff --git a/scripts/dtc/tests/schemas/array-size-3.schema b/scripts/dtc/tests/schemas/array-size-3.schema
new file mode 100644
index 0000000..c9cf285
--- /dev/null
+++ b/scripts/dtc/tests/schemas/array-size-3.schema
@@ -0,0 +1,8 @@
+/dts-v1/;
+/ {
+ compatible = "compat1";
+
+ mypropint {
+ max-length = <2>;
+ };
+};
diff --git a/scripts/dtc/tests/schemas/array-size-4.schema b/scripts/dtc/tests/schemas/array-size-4.schema
new file mode 100644
index 0000000..e3a9775
--- /dev/null
+++ b/scripts/dtc/tests/schemas/array-size-4.schema
@@ -0,0 +1,8 @@
+/dts-v1/;
+/ {
+ compatible = "compat1";
+
+ mypropint {
+ min-length = <7>;
+ };
+};
--
1.8.1.2
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 36+ messages in thread
* [RFC 09/15] scripts/dtc: check value of properties
[not found] ` <1380041541-17529-1-git-send-email-bcousson-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
` (3 preceding siblings ...)
2013-09-24 16:52 ` [RFC 08/15] scripts/dtc: check array size Benoit Cousson
@ 2013-09-24 16:52 ` Benoit Cousson
2013-09-24 16:52 ` [RFC 10/15] scripts/dtc: add count limit on nodes Benoit Cousson
2013-10-01 22:22 ` [RFC 00/15] Device Tree schemas and validation Stephen Warren
6 siblings, 0 replies; 36+ messages in thread
From: Benoit Cousson @ 2013-09-24 16:52 UTC (permalink / raw)
To: olof-nZhT3qVonbNeoWH0uzbU5w, devicetree-u79uwXL29TY76Z2rM5mHXA,
tomasz.figa-Re5JQEeQqe8AvxtiuMwx3w,
swarren-3lzwWm7+Weoh9ZMKESR00Q,
grant.likely-s3s/WqlpOiPyB63q8FvJNQ,
rob.herring-bsGFqQB8/DxBDgjK7y7TUQ
Cc: khilman-QSEj5FYQhm4dnm+yROfE0A, linux-omap-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
fparent-rdvid1DuHRBWk0Htik3J/w, Benoit Cousson
From: Fabien Parent <fparent-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
Add the ability to check whether a property has a given value or not.
Add as well 7 test files for this feature.
abc {
prop1 = <0 1 2 3>;
prop2 = "value0", "value1", "value3";
};
====
To check whether an integer array contains value from a given range
use the following constraint:
prop1 {
type = "integer";
value = <0x0 0xF>;
};
To check whether a string array contains value that match a given pattern
use the following constraint:
prop2 {
type = "string";
value = "value[0-9]";
};
To check whether a particular element of an array has the correct value one
can use the following constraint:
prop1 {
type = "integer";
value@2 = <2>;
};
or
prop2 {
type = "string";
value@1 = "value1";
};
Signed-off-by: Fabien Parent <fparent-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
Signed-off-by: Benoit Cousson <bcousson-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
---
scripts/dtc/schema-test.c | 20 ++
scripts/dtc/schema.c | 288 +++++++++++++++++++++
scripts/dtc/tests/schemas/integer-array-1.schema | 16 ++
scripts/dtc/tests/schemas/integer-array-2.schema | 9 +
scripts/dtc/tests/schemas/integer-array-3.schema | 8 +
.../dtc/tests/schemas/pattern-matching-1.schema | 10 +
.../dtc/tests/schemas/pattern-matching-2.schema | 10 +
scripts/dtc/tests/schemas/string-array-1.schema | 20 ++
scripts/dtc/tests/schemas/string-array-2.schema | 9 +
scripts/dtc/tests/test1.dts | 4 +
10 files changed, 394 insertions(+)
create mode 100644 scripts/dtc/tests/schemas/integer-array-1.schema
create mode 100644 scripts/dtc/tests/schemas/integer-array-2.schema
create mode 100644 scripts/dtc/tests/schemas/integer-array-3.schema
create mode 100644 scripts/dtc/tests/schemas/pattern-matching-1.schema
create mode 100644 scripts/dtc/tests/schemas/pattern-matching-2.schema
create mode 100644 scripts/dtc/tests/schemas/string-array-1.schema
create mode 100644 scripts/dtc/tests/schemas/string-array-2.schema
diff --git a/scripts/dtc/schema-test.c b/scripts/dtc/schema-test.c
index bfc9e43..a8a5664 100644
--- a/scripts/dtc/schema-test.c
+++ b/scripts/dtc/schema-test.c
@@ -45,6 +45,26 @@ static struct schema_test tests[] = {
"tests/schemas/array-size-3.schema", 0},
{"Array Size #4", "tests/test1.dts",
"tests/schemas/array-size-4.schema", 0},
+
+ /* String Array */
+ {"String Array Values #1", "tests/test1.dts",
+ "tests/schemas/string-array-1.schema", 1},
+ {"String Array Values #2", "tests/test1.dts",
+ "tests/schemas/string-array-2.schema", 0},
+
+ /* Integer Array */
+ {"Integer Array Values #1", "tests/test1.dts",
+ "tests/schemas/integer-array-1.schema", 1},
+ {"Integer Array Values #2", "tests/test1.dts",
+ "tests/schemas/integer-array-2.schema", 0},
+ {"Integer Array Values #3", "tests/test1.dts",
+ "tests/schemas/integer-array-3.schema", 0},
+
+ /* Pattern Matching */
+ {"Pattern Matching #1", "tests/test1.dts",
+ "tests/schemas/pattern-matching-1.schema", 1},
+ {"Pattern Matching #2", "tests/test1.dts",
+ "tests/schemas/pattern-matching-2.schema", 0},
};
int main(void)
diff --git a/scripts/dtc/schema.c b/scripts/dtc/schema.c
index 95ad925..d96129f 100644
--- a/scripts/dtc/schema.c
+++ b/scripts/dtc/schema.c
@@ -7,6 +7,26 @@
#include <stdio.h>
#include <limits.h>
+#define sorted_list_add(x, e) \
+ do { \
+ typeof(x) prev, i; \
+ if (!x) {\
+ x = e; \
+ break; \
+ } \
+ for (prev = x, i = x->next; \
+ i && i->id < e->id; \
+ prev = i, i = i->next) \
+ ; \
+ e->next = i; \
+ prev->next = e; \
+ } while (0)
+
+#define for_each_safe(list, iter, iter_next) \
+ for (iter = list, iter_next = list ? list->next : NULL;\
+ iter; \
+ iter = iter_next, iter_next = iter_next ? iter_next->next : NULL)
+
#define DT_ERROR(path, p, format, ...) \
do { \
dt_error(path, p, format, ##__VA_ARGS__); \
@@ -32,6 +52,21 @@ struct node_list {
struct node_list *next;
};
+struct range {
+ uint32_t low;
+ uint32_t high;
+ int id;
+
+ struct range *next;
+};
+
+struct pattern {
+ const char *text;
+ int id;
+
+ struct pattern *next;
+};
+
struct prop_constraints {
const char *name;
char *type;
@@ -39,6 +74,12 @@ struct prop_constraints {
int can_be_inherited;
size_t min_length;
size_t max_length;
+
+ union {
+ struct pattern *patterns;
+ struct range *ranges;
+ } value;
+ enum datatype value_type;
};
struct node_constraints {
@@ -207,11 +248,139 @@ static void dt_error(struct node_list *path,
exit(1);
}
+static void load_property_value_constraints(struct prop_constraints *pc,
+ struct node *schema)
+{
+ struct property *p;
+ struct pattern *pattern;
+ struct range *r;
+ uint32_t low;
+ uint32_t high;
+ int offset;
+
+ assert(pc);
+ assert(schema);
+
+ p = get_property(schema, "value");
+ if (p) {
+ switch (p->val.type) {
+ case STRING:
+ pc->value.patterns = xmalloc(sizeof(*pattern));
+ memset(pc->value.patterns, 0,
+ sizeof(*pc->value.patterns));
+ pc->value.patterns->text = p->val.val;
+ pc->value.patterns->id = -1;
+ pc->value_type = STRING;
+ break;
+
+ case INTEGER:
+ /**
+ * Constraints:
+ * value = <0x0 0xFF>;
+ *
+ * The value for each element of the cells
+ * must be between 0x0 and 0xFF.
+ */
+ assert(p->val.array_size <= 2);
+
+ low = prop_val_to_uint32(p, 0);
+ high = p->val.array_size == 2
+ ? prop_val_to_uint32(p, 1)
+ : low;
+
+ pc->value.ranges = xmalloc(sizeof(*r));
+ memset(pc->value.ranges, 0, sizeof(*pc->value.ranges));
+ pc->value.ranges->low = low;
+ pc->value.ranges->high = high;
+ pc->value_type = INTEGER;
+ pc->value.ranges->id = -1;
+ break;
+
+ default:
+ die("Reach unreachable\n");
+ }
+ }
+
+ /**
+ * One can put a constraints on a specific cell without
+ * having to put this constraint on all the cells
+ *
+ * This can also be used to override a constraint that has
+ * been put on on cells.
+ *
+ * Ex:
+ * value = <0x0 0xFF>;
+ * value@1 = <0x24>;
+ *
+ * This will only accept cell that have a value between
+ * 0x0 and 0xFF, and will require that the second element
+ * to be equal to 0x24
+ * Ex:
+ * - This is valid: myprop = <0x13 0x24 0x6F 0x2D>;
+ * - This is invalid: myprop = <0x13 0xFE 0x6F 0x2D>;
+ */
+ for (p = schema->proplist; p; p = p->next) {
+ assert(p->name);
+
+ if (strstr(p->name, "value@") != p->name)
+ continue;
+
+ if (sscanf(p->name, "value@%u", &offset) != 1)
+ continue;
+
+ if (offset >= pc->max_length) {
+ die("Value offset must be lower to the "
+ "number of elements in the array.");
+ }
+
+ if (p->val.type == INTEGER) {
+ assert(pc->value_type == INTEGER
+ || pc->value_type == UNDEFINED);
+ assert(p->val.array_size <= 2);
+
+ pc->value_type = INTEGER;
+
+ low = prop_val_to_uint32(p, 0);
+ high = p->val.array_size == 2
+ ? prop_val_to_uint32(p, 1)
+ : low;
+
+ r = xmalloc(sizeof(*r));
+ memset(r, 0, sizeof(*r));
+ r->low = low;
+ r->high = high;
+ r->id = offset;
+ sorted_list_add(pc->value.ranges, r);
+ } else if (p->val.type == STRING) {
+ assert(pc->value_type == STRING
+ || pc->value_type == UNDEFINED);
+
+ pc->value_type = STRING;
+ pattern = xmalloc(sizeof(*pattern));
+ memset(pattern, 0, sizeof(*pattern));
+ pattern->text = p->val.val;
+ pattern->id = offset;
+ sorted_list_add(pc->value.patterns, pattern);
+ }
+ }
+}
+
static void free_property_constraints(struct prop_constraints *pc)
{
+ struct pattern *p, *p_next;
+ struct range *r, *r_next;
+
if (!pc)
return;
+ if (pc->value_type == STRING) {
+ for_each_safe(pc->value.patterns, p, p_next)
+ free(p);
+ } else if (pc->value_type == INTEGER) {
+ for_each_safe(pc->value.ranges, r, r_next)
+ free(r);
+ }
+
free(pc);
}
@@ -256,6 +425,7 @@ load_property_constraints(struct node *schema)
pc->max_length = prop_val_to_uint32(p, 0);
}
+ load_property_value_constraints(pc, schema);
return pc;
}
@@ -287,6 +457,121 @@ static int check_types(struct property *p, struct prop_constraints *pc)
return 0;
}
+static inline struct range*
+find_range_for_elem_num(struct prop_constraints *pc, int num)
+{
+ struct range *r;
+
+ assert(pc);
+ assert(pc->value_type == INTEGER);
+ assert(pc->value.ranges);
+
+ for (r = pc->value.ranges; r && r->id != num; r = r->next)
+ ;
+
+ if (!r && pc->value.ranges->id == -1)
+ r = pc->value.ranges;
+
+ return r;
+}
+
+static int check_integer_value(struct property *p, struct prop_constraints *pc)
+{
+ int i;
+ struct range *r;
+ uint32_t int_value;
+
+ assert(p);
+ assert(pc);
+ assert(p->val.type == INTEGER);
+ assert(pc->value_type == INTEGER);
+ assert(pc->value.ranges);
+
+ for (i = 0; i < p->val.array_size; i++, r = r->next) {
+ r = find_range_for_elem_num(pc, i);
+ if (!r)
+ break;
+
+ int_value = prop_val_to_uint32(p, i);
+ if (int_value < r->low || int_value > r->high)
+ return 0;
+ }
+
+ return 1;
+}
+
+static inline struct pattern*
+find_pattern_for_elem_num(struct prop_constraints *pc, int num)
+{
+ struct pattern *pattern;
+
+ assert(pc);
+ assert(pc->value_type == STRING);
+ assert(pc->value.patterns);
+
+ for (pattern = pc->value.patterns;
+ pattern && pattern->id != num;
+ pattern = pattern->next)
+ ;
+
+ if (!pattern && pc->value.patterns->id == -1)
+ pattern = pc->value.patterns;
+
+ return pattern;
+}
+
+static int check_string_value(struct property *p, struct prop_constraints *pc)
+{
+ pcre *re;
+ struct pattern *pattern;
+ int i;
+ int str_offset = 0;
+ int res;
+
+ assert(p);
+ assert(pc);
+ assert(p->val.type == STRING);
+
+ for (i = 0; i < p->val.array_size; i++) {
+ pattern = find_pattern_for_elem_num(pc, i);
+ if (!pattern)
+ break;
+
+ assert(pattern->text);
+ re = compile_pattern(pattern->text);
+ if (!re)
+ die("Invalid pattern '%s' in schema\n", pattern->text);
+
+ assert(str_offset >= 0);
+ res = pcre_exec(re, 0, p->val.val + str_offset,
+ strlen(p->val.val + str_offset),
+ 0, 0, NULL, 0) >= 0;
+ pcre_free(re);
+
+ str_offset = get_next_string_offset(p, str_offset);
+ if (!res)
+ return 0;
+ }
+
+ return 1;
+}
+
+static int check_value(struct property *p, struct prop_constraints *pc)
+{
+ assert(p);
+ assert(pc);
+
+ if (pc->value_type == UNDEFINED)
+ return 1;
+
+ if (p->val.type == STRING)
+ return check_string_value(p, pc);
+ else if (p->val.type == INTEGER)
+ return check_integer_value(p, pc);
+
+ return 1;
+}
+
static int validate_properties(struct node *n,
struct node *schema,
struct node_list *path);
@@ -332,6 +617,9 @@ static int validate_property(struct node *n,
pc->max_length, p->val.array_size);
}
+ if (!check_value(p, pc))
+ DT_ERROR(path, p, "Incorrect value.\n");
+
end:
free_property_constraints(pc);
return ret;
diff --git a/scripts/dtc/tests/schemas/integer-array-1.schema b/scripts/dtc/tests/schemas/integer-array-1.schema
new file mode 100644
index 0000000..b7de822
--- /dev/null
+++ b/scripts/dtc/tests/schemas/integer-array-1.schema
@@ -0,0 +1,16 @@
+/dts-v1/;
+/ {
+ compatible = "compat1";
+
+ mypropint {
+ type = "integer";
+ value@0 = <0>;
+ value@1 = <2>;
+ value@2 = <4>;
+ };
+
+ mypropint2 {
+ type = "integer";
+ value = <0 5>;
+ };
+};
diff --git a/scripts/dtc/tests/schemas/integer-array-2.schema b/scripts/dtc/tests/schemas/integer-array-2.schema
new file mode 100644
index 0000000..a6e7628
--- /dev/null
+++ b/scripts/dtc/tests/schemas/integer-array-2.schema
@@ -0,0 +1,9 @@
+/dts-v1/;
+/ {
+ compatible = "compat1";
+ mypropint {
+ type = "integer";
+ value@0 = <0>;
+ value@1 = <3>;
+ };
+};
diff --git a/scripts/dtc/tests/schemas/integer-array-3.schema b/scripts/dtc/tests/schemas/integer-array-3.schema
new file mode 100644
index 0000000..b9ccc1c
--- /dev/null
+++ b/scripts/dtc/tests/schemas/integer-array-3.schema
@@ -0,0 +1,8 @@
+/dts-v1/;
+/ {
+ compatible = "compat1";
+ mypropint {
+ type = "integer";
+ value = <0 3>;
+ };
+};
diff --git a/scripts/dtc/tests/schemas/pattern-matching-1.schema b/scripts/dtc/tests/schemas/pattern-matching-1.schema
new file mode 100644
index 0000000..093851e
--- /dev/null
+++ b/scripts/dtc/tests/schemas/pattern-matching-1.schema
@@ -0,0 +1,10 @@
+/dts-v1/;
+/ {
+ compatible = "compat[0-9]";
+
+ abc {
+ name = "every.+";
+ is-required;
+ can-be-inherited;
+ };
+};
diff --git a/scripts/dtc/tests/schemas/pattern-matching-2.schema b/scripts/dtc/tests/schemas/pattern-matching-2.schema
new file mode 100644
index 0000000..0d73a15
--- /dev/null
+++ b/scripts/dtc/tests/schemas/pattern-matching-2.schema
@@ -0,0 +1,10 @@
+/dts-v1/;
+/ {
+ compatible = "compat[0-9]";
+
+ abc {
+ name = "never.+";
+ is-required;
+ can-be-inherited;
+ };
+};
diff --git a/scripts/dtc/tests/schemas/string-array-1.schema b/scripts/dtc/tests/schemas/string-array-1.schema
new file mode 100644
index 0000000..3d753e2
--- /dev/null
+++ b/scripts/dtc/tests/schemas/string-array-1.schema
@@ -0,0 +1,20 @@
+/dts-v1/;
+/ {
+ compatible = "compat1";
+
+ mypropstr {
+ type = "string";
+ value = "value[0-9]+";
+ };
+
+ mypropstr2 {
+ type = "string";
+ value = "value[0-9]+";
+ value@1 = "test";
+ };
+
+ mypropstr3 {
+ type = "string";
+ value@0 = "test";
+ };
+};
diff --git a/scripts/dtc/tests/schemas/string-array-2.schema b/scripts/dtc/tests/schemas/string-array-2.schema
new file mode 100644
index 0000000..ee1f441
--- /dev/null
+++ b/scripts/dtc/tests/schemas/string-array-2.schema
@@ -0,0 +1,9 @@
+/dts-v1/;
+/ {
+ compatible = "compat1";
+
+ mypropstr2 {
+ type = "string";
+ value = "value[0-9]+";
+ };
+};
diff --git a/scripts/dtc/tests/test1.dts b/scripts/dtc/tests/test1.dts
index a296591..7d8d745 100644
--- a/scripts/dtc/tests/test1.dts
+++ b/scripts/dtc/tests/test1.dts
@@ -1,11 +1,15 @@
/dts-v1/;
/ {
compatible = "root", "node";
+ everywhere = <0xf 0xa 0xb>;
node1 {
compatible = "compat1";
mypropint = <0 2 4 6>;
+ mypropint2 = <1 2 3>;
mypropstr = "value0", "value1", "value2";
+ mypropstr2 = "value0", "test", "value2";
+ mypropstr3 = "test", "toto", "tata";
subnode1 {
compatible = "compat2";
--
1.8.1.2
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 36+ messages in thread
* [RFC 10/15] scripts/dtc: add count limit on nodes
[not found] ` <1380041541-17529-1-git-send-email-bcousson-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
` (4 preceding siblings ...)
2013-09-24 16:52 ` [RFC 09/15] scripts/dtc: check value of properties Benoit Cousson
@ 2013-09-24 16:52 ` Benoit Cousson
2013-10-01 22:22 ` [RFC 00/15] Device Tree schemas and validation Stephen Warren
6 siblings, 0 replies; 36+ messages in thread
From: Benoit Cousson @ 2013-09-24 16:52 UTC (permalink / raw)
To: olof-nZhT3qVonbNeoWH0uzbU5w, devicetree-u79uwXL29TY76Z2rM5mHXA,
tomasz.figa-Re5JQEeQqe8AvxtiuMwx3w,
swarren-3lzwWm7+Weoh9ZMKESR00Q,
grant.likely-s3s/WqlpOiPyB63q8FvJNQ,
rob.herring-bsGFqQB8/DxBDgjK7y7TUQ
Cc: khilman-QSEj5FYQhm4dnm+yROfE0A, linux-omap-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
fparent-rdvid1DuHRBWk0Htik3J/w, Benoit Cousson
From: Fabien Parent <fparent-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
Add the possibility to specify in a schema a count limit for the nodes matching
the schema:
- count: if there is a match between a dts and a schema then there must
be exactly X match between the dts and the schema at the end of the
validation process.
- max-count: if there is a match between a dts and a schema then there must
be at most X match between the dts and the schema at the end of the
validation process.
This can be used to check if a specific node appears the right amount of time
in the dts.
Add as well four test files for this feature.
/ {
timer1 {
compatible = "ti,omap-4430-timer";
...
};
timer2 {
compatible = "ti,omap-4430-timer";
...
};
};
If in the above dts there must be exactly two timer one can check this
constraints with the following schema:
/ {
compatible = "ti,omap-4430-timer";
count = <2>;
};
Note: If the dts doesn't specify any timer the dts will still be valid. To
ensure that the timer is really present 2 times one should might wants to
specify constraints on then children of a node, but this feature is not
yet available.
Signed-off-by: Fabien Parent <fparent-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
Signed-off-by: Benoit Cousson <bcousson-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
---
scripts/dtc/schema-test.c | 10 ++++
scripts/dtc/schema.c | 63 ++++++++++++++++++++++++--
scripts/dtc/tests/schemas/nodes-count-1.schema | 5 ++
scripts/dtc/tests/schemas/nodes-count-2.schema | 5 ++
scripts/dtc/tests/schemas/nodes-count-3.schema | 5 ++
scripts/dtc/tests/schemas/nodes-count-4.schema | 5 ++
6 files changed, 89 insertions(+), 4 deletions(-)
create mode 100644 scripts/dtc/tests/schemas/nodes-count-1.schema
create mode 100644 scripts/dtc/tests/schemas/nodes-count-2.schema
create mode 100644 scripts/dtc/tests/schemas/nodes-count-3.schema
create mode 100644 scripts/dtc/tests/schemas/nodes-count-4.schema
diff --git a/scripts/dtc/schema-test.c b/scripts/dtc/schema-test.c
index a8a5664..128a265 100644
--- a/scripts/dtc/schema-test.c
+++ b/scripts/dtc/schema-test.c
@@ -65,6 +65,16 @@ static struct schema_test tests[] = {
"tests/schemas/pattern-matching-1.schema", 1},
{"Pattern Matching #2", "tests/test1.dts",
"tests/schemas/pattern-matching-2.schema", 0},
+
+ /* Nodes Count */
+ {"Nodes Count #1", "tests/test1.dts",
+ "tests/schemas/nodes-count-1.schema", 1},
+ {"Nodes Count #2", "tests/test1.dts",
+ "tests/schemas/nodes-count-2.schema", 1},
+ {"Nodes Count #3", "tests/test1.dts",
+ "tests/schemas/nodes-count-3.schema", 0},
+ {"Nodes Count #4", "tests/test1.dts",
+ "tests/schemas/nodes-count-4.schema", 0},
};
int main(void)
diff --git a/scripts/dtc/schema.c b/scripts/dtc/schema.c
index d96129f..b7cfb37 100644
--- a/scripts/dtc/schema.c
+++ b/scripts/dtc/schema.c
@@ -88,7 +88,10 @@ struct node_constraints {
struct boot_info *bi;
struct node *dt;
- const char *compatible;
+ char *compatible;
+ uint32_t count_requested;
+ uint32_t count;
+ uint32_t max_count;
};
struct schema_db {
@@ -657,6 +660,23 @@ static int validate_properties(struct node *n,
return ret;
}
+static void load_node_constraints(struct node_constraints *nc,
+ struct node *n)
+{
+ struct property *p;
+
+ assert(n);
+ assert(nc);
+
+ nc->count = 0;
+
+ p = get_property(n, "count");
+ nc->count_requested = p ? prop_val_to_uint32(p, 0) : 0;
+
+ p = get_property(n, "max-count");
+ nc->max_count = p ? prop_val_to_uint32(p, 0) : ULONG_MAX;
+}
+
static int validate_node(struct node *n,
struct node_constraints *nc,
struct node_list *path)
@@ -698,6 +718,7 @@ static struct node_constraints *get_node_constraints_of(struct schema_db *db,
n->bi = dt_from_source(n->filepath);
n->dt = n->bi->dt;
}
+ n->count++;
(*i)++;
return n;
}
@@ -705,6 +726,33 @@ static struct node_constraints *get_node_constraints_of(struct schema_db *db,
return NULL;
}
+static int check_nodes_count(struct schema_db *db)
+{
+ int i;
+ int ret = 1;
+ struct node_constraints *n;
+
+ for (i = 0; i < db->size; i++) {
+ n = &db->buffer[i];
+
+ if (n->count_requested) {
+ DT_ERROR_IF(n->count != n->count_requested, NULL, NULL,
+ "There is %u instance of %s instead "
+ "of %u.\n",
+ n->count,
+ n->compatible,
+ n->count_requested);
+ } else {
+ DT_ERROR_IF(n->count > n->max_count, NULL, NULL,
+ "There is too much instance of %s.\n",
+ n->compatible);
+ }
+ }
+
+end:
+ return ret;
+}
+
static int for_each_compatible_validate(struct schema_db *db,
struct property *p,
struct node *node,
@@ -771,11 +819,15 @@ static int validate_nodes(struct schema_db *db,
int validate_dt(struct schema_db *db, struct boot_info *bi)
{
+ int ret = 1;
+
assert(bi);
assert(bi->dt);
assert(db);
- return validate_nodes(db, bi->dt, NULL);
+ ret &= validate_nodes(db, bi->dt, NULL);
+ ret &= check_nodes_count(db);
+ return ret;
}
void exit_on_schema_validation_failure(int exit)
@@ -836,7 +888,7 @@ add_compatible_to_schema_db(struct schema_db *db,
nc = add_new_entry_to_schema_db(db);
- nc->compatible = compatible;
+ nc->compatible = xstrdup(compatible);
nc->re_compat = compile_pattern(compatible);
if (!nc->re_compat)
die("Invalid regex for compatible in %s\n", file);
@@ -851,6 +903,7 @@ static void add_to_schema_db_from_property(struct schema_db *db,
struct node *root)
{
int offset = 0;
+ struct node_constraints *nc;
assert(db);
assert(file);
@@ -858,7 +911,8 @@ static void add_to_schema_db_from_property(struct schema_db *db,
assert(p->val.type == STRING);
while (offset >= 0 && offset < p->val.len) {
- add_compatible_to_schema_db(db, p->val.val + offset, file);
+ nc = add_compatible_to_schema_db(db, p->val.val + offset, file);
+ load_node_constraints(nc, root);
offset = get_next_string_offset(p, offset);
}
}
@@ -973,6 +1027,7 @@ static void free_node_constraints(struct node_constraints *nc)
pcre_free(nc->re_compat);
free_dt(nc->bi);
free(nc->filepath);
+ free(nc->compatible);
}
void free_schema_db(struct schema_db *db)
diff --git a/scripts/dtc/tests/schemas/nodes-count-1.schema b/scripts/dtc/tests/schemas/nodes-count-1.schema
new file mode 100644
index 0000000..2dc574f
--- /dev/null
+++ b/scripts/dtc/tests/schemas/nodes-count-1.schema
@@ -0,0 +1,5 @@
+/dts-v1/;
+/ {
+ compatible = "compat[1-2]";
+ count = <2>;
+};
diff --git a/scripts/dtc/tests/schemas/nodes-count-2.schema b/scripts/dtc/tests/schemas/nodes-count-2.schema
new file mode 100644
index 0000000..ca8bb4b
--- /dev/null
+++ b/scripts/dtc/tests/schemas/nodes-count-2.schema
@@ -0,0 +1,5 @@
+/dts-v1/;
+/ {
+ compatible = "compat[1-2]";
+ max-count = <5>;
+};
diff --git a/scripts/dtc/tests/schemas/nodes-count-3.schema b/scripts/dtc/tests/schemas/nodes-count-3.schema
new file mode 100644
index 0000000..bcbded0
--- /dev/null
+++ b/scripts/dtc/tests/schemas/nodes-count-3.schema
@@ -0,0 +1,5 @@
+/dts-v1/;
+/ {
+ compatible = "compat[1-2]";
+ count = <3>;
+};
diff --git a/scripts/dtc/tests/schemas/nodes-count-4.schema b/scripts/dtc/tests/schemas/nodes-count-4.schema
new file mode 100644
index 0000000..04408f9
--- /dev/null
+++ b/scripts/dtc/tests/schemas/nodes-count-4.schema
@@ -0,0 +1,5 @@
+/dts-v1/;
+/ {
+ compatible = "compat[1-2]";
+ max-count = <1>;
+};
--
1.8.1.2
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 36+ messages in thread
* Re: [RFC 00/15] Device Tree schemas and validation
[not found] ` <1380041541-17529-1-git-send-email-bcousson-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
` (5 preceding siblings ...)
2013-09-24 16:52 ` [RFC 10/15] scripts/dtc: add count limit on nodes Benoit Cousson
@ 2013-10-01 22:22 ` Stephen Warren
[not found] ` <524B4B20.4020002-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
2013-10-03 13:17 ` Benoit Cousson
6 siblings, 2 replies; 36+ messages in thread
From: Stephen Warren @ 2013-10-01 22:22 UTC (permalink / raw)
To: Benoit Cousson
Cc: olof-nZhT3qVonbNeoWH0uzbU5w, devicetree-u79uwXL29TY76Z2rM5mHXA,
tomasz.figa-Re5JQEeQqe8AvxtiuMwx3w,
grant.likely-s3s/WqlpOiPyB63q8FvJNQ,
rob.herring-bsGFqQB8/DxBDgjK7y7TUQ,
khilman-QSEj5FYQhm4dnm+yROfE0A, linux-omap-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
fparent-rdvid1DuHRBWk0Htik3J/w
On 09/24/2013 10:52 AM, Benoit Cousson wrote:
> Hi All,
>
> Following the discussion that happened during LCE-2013 and the email
> thread started by Tomasz few months ago [1], here is a first attempt
> to introduce:
> - a schema language to define the bindings accurately
> - DTS validation during device tree compilation in DTC itself
Sorry, this is probably going to sound a bit negative. Hopefully you
find it constructive though.
> The syntax for a schema is the same as the one for dts. This choice has
> been made to simplify its development, to maximize the code reuse and
> finally because the format is human-readable.
I'm not convinced that's a good decision.
DT is a language for representing data.
The validation checks described by schemas are rules, or code, and not
static data.
So, while I'm sure it's possible to shoe-horn at least some reasonable
subset of DT validation into DT syntax itself, I feel it's unlikely to
yield something that's scalable enough.
For example, it's easy to specify that a property must be 2 cells long.
What if it could be any multiple of two? That's a lot of numbers to
explicitly enumerate as data. Sure, you can then invent syntax to
represent that specific rule (parameterized by 2), but what about the
next similar-but-different rule? The only approach I can think of to
that is to allow the schema to contain arbitrary expressions, which
would likely need to morph into arbitary statements not just
expressions. Once you're there, I think the schema would be better
represented as a programming language rather than as a data structure
that could have code hooked into it.
> How to:
> * Associate a schema to one or several nodes
>
> As said earlier a schema can be used to validate one or several nodes
> from a dts. To do this the "compatible" properties from the nodes which
> should be validated must be present in the schema.
>
> timer1: timer@4a318000 {
> compatible = "ti,omap3430-timer";
...
> To write a schema which will validate OMAP Timers like the one above,
> one may write the following schema:
>
> /dts-v1/;
> / {
> compatible = "ti,omap[0-9]+-timer";
What about DT nodes that don't have a compatible value? We certainly
have some of those already like /memory and /chosen. We should be able
to validate their schema too. This probably doesn't invalidate being
able to look things up by compatible value though; it just means we need
some additional mechanisms too.
> * Define constraints on properties
>
> To define constraints on a property one has to create a node in a schema
> which has as name the name of the property that one want to validate.
>
> To specify constraints on the property "ti,hwmods" of OMAP Timers one
> can write this schema:
>
> /dts-v1/;
> / {
> compatible = "ti,omap[0-9]+-timer";
> ti,hwmods {
> ...
> };
compatible and ti,hwmods are both properties in the DT file. However, in
the schema above, one appears as a property, and one as a node. I don't
like that inconsistency. It'd be better if compatible was a node too.
> If one want to use a regular as property name one can write this schema:
>
> /dts-v1/;
> / {
> compatible = "abc";
> def {
> name = "def[0-9]";
Isn't it valid to have a property named "name" within the node itself?
How do you differentiate between specifying the node name and the name
property?
What if the node name needs more validation than just a regex. For
example, suppose we want to validate the
unit-name-must-match-reg-address rule. We need to write some complex
expression using data extracted from reg to calculate the unit address.
Equally, the node name perhaps has to exist in some global list of
acceptable node names. It would be extremely tricky if not impossible to
do that with a regex.
> ...
> };
> };
>
> Above one can see that the "name" property override the node name.
Override implies that dtc would change the node name during compilation.
I think s/override/validate/ or s/override/overrides the validation
rules for/?
> * Require the presence of a property inside a node or inside one of its
> parents
...
> /dts-v1/;
> / {
> compatible = "ti,twl[0-9]+-rtc";
> interrupt-controller {
> is-required;
> can-be-inherited;
interrupt-controller isn't a good example here, since it isn't a
property that would typically be inherited. Why not use interrupt-parent
instead?
> One can check if 'node' has the following subnode 'subnode1', 'subnode2',
> and 'abc' with the schema below:
>
> /dts-v1/;
> / {
> compatible = "comp";
> children = "abc", "subnode[0-9]";
> };
How is the schema for each sub-node specified?
What if some nodes are optional and some required? The conditions where
a sub-node is required might be complex, and I think we'd always want to
be able to represent them in whatever schema language we chose.
The most obvious way would be to make each sub-node's schema appear as a
sub-node within the main node's schema, but then how do you tell if a
schema node describes a property or a node?
Note that the following DT file is currently accepted by dtc even if it
may not be the best choice of property and node names:
==========
/dts-v1/;
/ {
foo = <1>;
foo {};
};
==========
> * Constraints on array size
>
> One can specify the following constraints on array size:
> - length: specify the exact length that an array must have.
> - min-length: specify the minimum number of elements an array must have.
> - max-length: specify the maximum number of elements an array must have.
This seems rather inflexible; it'll cover a lot of the simple cases, but
hit a wall pretty soon. For example, how would it validate a property
that is supposed to include 3 GPIO specifiers, where the GPIO specifiers
are going to have DT-specific lengths, since the length of each
specifier is defined by the node that the phandles reference?
Overall, I believe perhaps the single most important aspect of any DT
schema is schema inheritance or instancing, and this proposal doesn't
appear to address that issue at all.
Inheritance of schemas:
For example, any node that is addressed must contain a reg property. The
constraints on that property are identical in all bindings; it must
consist of #address-cells + #size-cells integer values (cells). We don't
want to have to cut/paste that rule into every single binding
definition. Rather, we should simply say something like "this binding
uses the reg property", and the schema validation tool will look up the
definition of "reg property", and hence know how to validate it.
Similarly, any binding that describes a GPIO controller will have some
similar requirements; the gpio-controller and #gpio-cells properties
must be present. The schema should simply say "I'm a GPIO controller",
and the schema tool should add some extra requirements to nodes of that
type.
Instancing of schemas:
Any binding that uses GPIOs should be able to say that a particular
property (e.g. "enable-gpios") is-a GPIO-specifier (with parameters
"enable" for the property name, min/max/expression length, etc.), and
then the schema validation tool would know to apply rules for a
specifier list to that property (and be able to check the property name).
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 36+ messages in thread
[parent not found: <524B4B20.4020002-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>]
* Re: [RFC 00/15] Device Tree schemas and validation
[not found] ` <524B4B20.4020002-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
@ 2013-10-02 14:29 ` David Gibson
[not found] ` <20131002142914.GI6506-RXTfZT5YzpxwFLYp8hBm2A@public.gmane.org>
0 siblings, 1 reply; 36+ messages in thread
From: David Gibson @ 2013-10-02 14:29 UTC (permalink / raw)
To: Stephen Warren
Cc: Benoit Cousson, olof-nZhT3qVonbNeoWH0uzbU5w,
devicetree-u79uwXL29TY76Z2rM5mHXA,
tomasz.figa-Re5JQEeQqe8AvxtiuMwx3w,
grant.likely-s3s/WqlpOiPyB63q8FvJNQ,
rob.herring-bsGFqQB8/DxBDgjK7y7TUQ,
khilman-QSEj5FYQhm4dnm+yROfE0A, linux-omap-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
fparent-rdvid1DuHRBWk0Htik3J/w
[-- Attachment #1: Type: text/plain, Size: 10481 bytes --]
On Tue, Oct 01, 2013 at 04:22:24PM -0600, Stephen Warren wrote:
> On 09/24/2013 10:52 AM, Benoit Cousson wrote:
> > Hi All,
> >
> > Following the discussion that happened during LCE-2013 and the email
> > thread started by Tomasz few months ago [1], here is a first attempt
> > to introduce:
> > - a schema language to define the bindings accurately
> > - DTS validation during device tree compilation in DTC itself
>
> Sorry, this is probably going to sound a bit negative. Hopefully you
> find it constructive though.
>
> > The syntax for a schema is the same as the one for dts. This choice has
> > been made to simplify its development, to maximize the code reuse and
> > finally because the format is human-readable.
>
> I'm not convinced that's a good decision.
>
> DT is a language for representing data.
>
> The validation checks described by schemas are rules, or code, and not
> static data.
>
> So, while I'm sure it's possible to shoe-horn at least some reasonable
> subset of DT validation into DT syntax itself, I feel it's unlikely to
> yield something that's scalable enough.
I tend to agree.
> For example, it's easy to specify that a property must be 2 cells long.
> What if it could be any multiple of two? That's a lot of numbers to
> explicitly enumerate as data. Sure, you can then invent syntax to
> represent that specific rule (parameterized by 2), but what about the
> next similar-but-different rule? The only approach I can think of to
> that is to allow the schema to contain arbitrary expressions, which
> would likely need to morph into arbitary statements not just
> expressions. Once you're there, I think the schema would be better
> represented as a programming language rather than as a data structure
> that could have code hooked into it.
>
> > How to:
> > * Associate a schema to one or several nodes
> >
> > As said earlier a schema can be used to validate one or several nodes
> > from a dts. To do this the "compatible" properties from the nodes which
> > should be validated must be present in the schema.
> >
> > timer1: timer@4a318000 {
> > compatible = "ti,omap3430-timer";
> ...
> > To write a schema which will validate OMAP Timers like the one above,
> > one may write the following schema:
> >
> > /dts-v1/;
> > / {
> > compatible = "ti,omap[0-9]+-timer";
>
> What about DT nodes that don't have a compatible value? We certainly
> have some of those already like /memory and /chosen. We should be able
> to validate their schema too. This probably doesn't invalidate being
> able to look things up by compatible value though; it just means we need
> some additional mechanisms too.
More to the point, what about the properties of a node whose format is
defined not by this node's binding but by some other nodes binding.
e.g. the exact format of reg and ranges is at least partially
determined by the parent bus's binding, and interrupts is defined
partially by the interrupt parent's binding. gpio properties are
defined by a combination of a global binding and the gpio parent,
IIRC.
> > * Define constraints on properties
> >
> > To define constraints on a property one has to create a node in a schema
> > which has as name the name of the property that one want to validate.
> >
> > To specify constraints on the property "ti,hwmods" of OMAP Timers one
> > can write this schema:
> >
> > /dts-v1/;
> > / {
> > compatible = "ti,omap[0-9]+-timer";
> > ti,hwmods {
> > ...
> > };
>
> compatible and ti,hwmods are both properties in the DT file. However, in
> the schema above, one appears as a property, and one as a node. I don't
> like that inconsistency. It'd be better if compatible was a node too.
Essentially what's going on here is that to describe the constraint on
a property, a node with corresponding name is defined to encode the
parameters of that constraint. It kind of works, but it's forced. It
also hits problems since nodes and properties are technically in
different namespaces, although they rarely collide in real cases.
> > If one want to use a regular as property name one can write this schema:
> >
> > /dts-v1/;
> > / {
> > compatible = "abc";
> > def {
> > name = "def[0-9]";
>
> Isn't it valid to have a property named "name" within the node itself?
> How do you differentiate between specifying the node name and the name
> property?
Or to look at it another way, how do you differentiate between nodes
representing encoded constraints for a property, and nodes
representing nodes directly.
> What if the node name needs more validation than just a regex. For
> example, suppose we want to validate the
> unit-name-must-match-reg-address rule. We need to write some complex
> expression using data extracted from reg to calculate the unit address.
> Equally, the node name perhaps has to exist in some global list of
> acceptable node names. It would be extremely tricky if not impossible to
> do that with a regex.
>
> > ...
> > };
> > };
> >
> > Above one can see that the "name" property override the node name.
>
> Override implies that dtc would change the node name during compilation.
> I think s/override/validate/ or s/override/overrides the validation
> rules for/?
Actually, dtc already contains checks that a "name" property (if
present) matches the unit name. Name properties vs. node names work a
bit differently in the flat-tree world versus traditional OF, and this
checks ensures that flat trees don't do (at least some) things which
would break the OF traditional approach.
> > * Require the presence of a property inside a node or inside one of its
> > parents
> ...
> > /dts-v1/;
> > / {
> > compatible = "ti,twl[0-9]+-rtc";
> > interrupt-controller {
> > is-required;
> > can-be-inherited;
>
> interrupt-controller isn't a good example here, since it isn't a
> property that would typically be inherited. Why not use interrupt-parent
> instead?
>
> > One can check if 'node' has the following subnode 'subnode1', 'subnode2',
> > and 'abc' with the schema below:
> >
> > /dts-v1/;
> > / {
> > compatible = "comp";
> > children = "abc", "subnode[0-9]";
> > };
>
> How is the schema for each sub-node specified?
>
> What if some nodes are optional and some required? The conditions where
> a sub-node is required might be complex, and I think we'd always want to
> be able to represent them in whatever schema language we chose.
>
> The most obvious way would be to make each sub-node's schema appear as a
> sub-node within the main node's schema, but then how do you tell if a
> schema node describes a property or a node?
>
> Note that the following DT file is currently accepted by dtc even if it
> may not be the best choice of property and node names:
>
> ==========
> /dts-v1/;
>
> / {
> foo = <1>;
> foo {};
> };
> ==========
Note that node / property name collisions are not entirely theoretical
either. They are permitted in IEEE1275 and there are real Apple
device trees in the wild which have them. It's rare and discouraged,
obviously.
> > * Constraints on array size
> >
> > One can specify the following constraints on array size:
> > - length: specify the exact length that an array must have.
> > - min-length: specify the minimum number of elements an array must have.
> > - max-length: specify the maximum number of elements an array must have.
>
> This seems rather inflexible; it'll cover a lot of the simple cases, but
> hit a wall pretty soon. For example, how would it validate a property
> that is supposed to include 3 GPIO specifiers, where the GPIO specifiers
> are going to have DT-specific lengths, since the length of each
> specifier is defined by the node that the phandles reference?
>
>
> Overall, I believe perhaps the single most important aspect of any DT
> schema is schema inheritance or instancing, and this proposal doesn't
> appear to address that issue at all.
>
> Inheritance of schemas:
>
> For example, any node that is addressed must contain a reg property. The
> constraints on that property are identical in all bindings; it must
> consist of #address-cells + #size-cells integer values (cells). We don't
> want to have to cut/paste that rule into every single binding
> definition. Rather, we should simply say something like "this binding
> uses the reg property", and the schema validation tool will look up the
> definition of "reg property", and hence know how to validate it.
>
> Similarly, any binding that describes a GPIO controller will have some
> similar requirements; the gpio-controller and #gpio-cells properties
> must be present. The schema should simply say "I'm a GPIO controller",
> and the schema tool should add some extra requirements to nodes of that
> type.
>
> Instancing of schemas:
>
> Any binding that uses GPIOs should be able to say that a particular
> property (e.g. "enable-gpios") is-a GPIO-specifier (with parameters
> "enable" for the property name, min/max/expression length, etc.), and
> then the schema validation tool would know to apply rules for a
> specifier list to that property (and be able to check the property name).
Yes, I agree both of those are important.
So, here's a counter-proposal of at least a rough outline of how I
think schemas could work, in a way that's still based generally on dt
syntax.
First, define the notion of dt "patterns" or "templates". A dt
pattern is to a dt node or subtree as a regex is to a string - it
provides a reasonably expressive way of defining a family of dt
nodes. These would be defined in an extension / superset of dt
syntax.
A schema would then be defined as a set of implications:
If node X matches pattern A, => it must also match pattern B
For example:
If a node has a compatible property with string "foodev"
=> it must have various foodev properties.
If a node has a "reg" property (at all)
=> it must have the format required by reg
If a node has an "interrupts" property
=> it must have either "interrupt-parent" or "interrupt-map"
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [RFC 00/15] Device Tree schemas and validation
2013-10-01 22:22 ` [RFC 00/15] Device Tree schemas and validation Stephen Warren
[not found] ` <524B4B20.4020002-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
@ 2013-10-03 13:17 ` Benoit Cousson
1 sibling, 0 replies; 36+ messages in thread
From: Benoit Cousson @ 2013-10-03 13:17 UTC (permalink / raw)
To: Stephen Warren
Cc: olof, devicetree, tomasz.figa, grant.likely, rob.herring, khilman,
linux-omap, linux-arm-kernel, fparent
Hi Stephen,
On 02/10/2013 00:22, Stephen Warren wrote:
> On 09/24/2013 10:52 AM, Benoit Cousson wrote:
>> Hi All,
>>
>> Following the discussion that happened during LCE-2013 and the email
>> thread started by Tomasz few months ago [1], here is a first attempt
>> to introduce:
>> - a schema language to define the bindings accurately
>> - DTS validation during device tree compilation in DTC itself
>
> Sorry, this is probably going to sound a bit negative. Hopefully you
> find it constructive though.
Well, I hope so too, let's see at the end of the email :-)
>> The syntax for a schema is the same as the one for dts. This choice has
>> been made to simplify its development, to maximize the code reuse and
>> finally because the format is human-readable.
>
> I'm not convinced that's a good decision.
Me neither :-), but I gave the current rational...
> DT is a language for representing data.
>
> The validation checks described by schemas are rules, or code, and not
> static data.
I will not be that strict with what DTS is supposed to do. In that
aspect DTS is just a way to represent information in a structured
hierarchical way.
It is for my point of view no different than XML. I know that everybody
hate XML, including me, but that shows at least what is doable with such
language. The fact that we like it or not is a different topic.
> So, while I'm sure it's possible to shoe-horn at least some reasonable
> subset of DT validation into DT syntax itself, I feel it's unlikely to
> yield something that's scalable enough.
I don't think we have any limit with such representation. My concern
will be more the readability.
To be honest, a language choice is by nature completely subjective, and
nobody will have the same taste. So we can spend weeks arguing about
that :-)
> For example, it's easy to specify that a property must be 2 cells long.
> What if it could be any multiple of two? That's a lot of numbers to
> explicitly enumerate as data. Sure, you can then invent syntax to
> represent that specific rule (parameterized by 2), but what about the
> next similar-but-different rule? The only approach I can think of to
> that is to allow the schema to contain arbitrary expressions, which
> would likely need to morph into arbitary statements not just
> expressions. Once you're there, I think the schema would be better
> represented as a programming language rather than as a data structure
> that could have code hooked into it.
Sure, but how many complex cases like that do we have? I guess, we can
handle all the use-cases required by Rob with the current syntax.
Let's assume we cover 99% of the use-cases with such language, do we
really want to have a super complex language just for the corner cases?
Potentially, writing a C extension to DTC is still possible for that
specific case.
Not ideal, I do agree, but we have to be pragmatic as well.
We really need to understand how scalable we have to be before deciding
that the current representation is not good enough.
>> How to:
>> * Associate a schema to one or several nodes
>>
>> As said earlier a schema can be used to validate one or several nodes
>> from a dts. To do this the "compatible" properties from the nodes which
>> should be validated must be present in the schema.
>>
>> timer1: timer@4a318000 {
>> compatible = "ti,omap3430-timer";
> ...
>> To write a schema which will validate OMAP Timers like the one above,
>> one may write the following schema:
>>
>> /dts-v1/;
>> / {
>> compatible = "ti,omap[0-9]+-timer";
>
> What about DT nodes that don't have a compatible value? We certainly
> have some of those already like /memory and /chosen. We should be able
> to validate their schema too. This probably doesn't invalidate being
> able to look things up by compatible value though; it just means we need
> some additional mechanisms too.
Yes, that's a good point and easy to add as well.
>> * Define constraints on properties
>>
>> To define constraints on a property one has to create a node in a schema
>> which has as name the name of the property that one want to validate.
>>
>> To specify constraints on the property "ti,hwmods" of OMAP Timers one
>> can write this schema:
>>
>> /dts-v1/;
>> / {
>> compatible = "ti,omap[0-9]+-timer";
>> ti,hwmods {
>> ...
>> };
>
> compatible and ti,hwmods are both properties in the DT file. However, in
> the schema above, one appears as a property, and one as a node. I don't
> like that inconsistency. It'd be better if compatible was a node too.
That's already possible, you can check the timer.schema. The point is to
simplify the representation for simple case and use a attribute instead
of a node. But that will make 2 different representation for the same
case, which might not be that good.
>> If one want to use a regular as property name one can write this schema:
>>
>> /dts-v1/;
>> / {
>> compatible = "abc";
>> def {
>> name = "def[0-9]";
>
> Isn't it valid to have a property named "name" within the node itself?
> How do you differentiate between specifying the node name and the name
> property?
You don't have to. In this case the attributes inside the node are
strictly the schema language keywords.
That being said, it might happen for some other casea, so maybe a prefix
like "schema,XXX" should be use to create a proper namespace.
> What if the node name needs more validation than just a regex. For
> example, suppose we want to validate the
> unit-name-must-match-reg-address rule. We need to write some complex
> expression using data extracted from reg to calculate the unit address.
> Equally, the node name perhaps has to exist in some global list of
> acceptable node names. It would be extremely tricky if not impossible to
> do that with a regex.
Sure, but again, do we have such cases already? How far do we want to go
in term of complexity for corner cases.
>> ...
>> };
>> };
>>
>> Above one can see that the "name" property override the node name.
>
> Override implies that dtc would change the node name during compilation.
> I think s/override/validate/ or s/override/overrides the validation
> rules for/?
OK
>> * Require the presence of a property inside a node or inside one of its
>> parents
> ...
>> /dts-v1/;
>> / {
>> compatible = "ti,twl[0-9]+-rtc";
>> interrupt-controller {
>> is-required;
>> can-be-inherited;
>
> interrupt-controller isn't a good example here, since it isn't a
> property that would typically be inherited. Why not use interrupt-parent
> instead?
Yeah, that's a mistake, it should have been interrupt-parent. It was
done for that attribute mainly.
>> One can check if 'node' has the following subnode 'subnode1', 'subnode2',
>> and 'abc' with the schema below:
>>
>> /dts-v1/;
>> / {
>> compatible = "comp";
>> children = "abc", "subnode[0-9]";
>> };
>
> How is the schema for each sub-node specified?
sub-node are handled like any other regular node. If needed you can set
constraints on parent node using the parents keyword.
> What if some nodes are optional and some required? The conditions where
> a sub-node is required might be complex, and I think we'd always want to
> be able to represent them in whatever schema language we chose.
>
> The most obvious way would be to make each sub-node's schema appear as a
> sub-node within the main node's schema, but then how do you tell if a
> schema node describes a property or a node?
I'm not sure about that. That was my first impression as well when we
started, but in fact I don't think this is really needed.
By doing that, you end up creating a schema that looks like your final
dts. So this become some kind of template more than a schema.
> Note that the following DT file is currently accepted by dtc even if it
> may not be the best choice of property and node names:
>
> ==========
> /dts-v1/;
>
> / {
> foo = <1>;
> foo {};
> };
> ==========
>
>> * Constraints on array size
>>
>> One can specify the following constraints on array size:
>> - length: specify the exact length that an array must have.
>> - min-length: specify the minimum number of elements an array must have.
>> - max-length: specify the maximum number of elements an array must have.
>
> This seems rather inflexible; it'll cover a lot of the simple cases, but
> hit a wall pretty soon. For example, how would it validate a property
> that is supposed to include 3 GPIO specifiers, where the GPIO specifiers
> are going to have DT-specific lengths, since the length of each
> specifier is defined by the node that the phandles reference?
sure, but that kind of check can be added.
> Overall, I believe perhaps the single most important aspect of any DT
> schema is schema inheritance or instancing, and this proposal doesn't
> appear to address that issue at all.
It does not handle inheritance completely, but that's not necessarily
needed for the cases you describe below.
> Inheritance of schemas:
>
> For example, any node that is addressed must contain a reg property. The
> constraints on that property are identical in all bindings; it must
> consist of #address-cells + #size-cells integer values (cells). We don't
> want to have to cut/paste that rule into every single binding
> definition. Rather, we should simply say something like "this binding
> uses the reg property", and the schema validation tool will look up the
> definition of "reg property", and hence know how to validate it.
That's almost doable with the current mechanism and part of the plan.
You can already add a generic rule that will apply to every nodes thanks
to a wildcard RE. Then later you can add a more specific rule that will
apply to few nodes only.
But I realized, we did not even used that in the example we did :-(
> Similarly, any binding that describes a GPIO controller will have some
> similar requirements; the gpio-controller and #gpio-cells properties
> must be present. The schema should simply say "I'm a GPIO controller",
> and the schema tool should add some extra requirements to nodes of that
> type.
Yes, agreed. Should be doable using previous mechanism. But will need
some improvement.
> Instancing of schemas:
>
> Any binding that uses GPIOs should be able to say that a particular
> property (e.g. "enable-gpios") is-a GPIO-specifier (with parameters
> "enable" for the property name, min/max/expression length, etc.), and
> then the schema validation tool would know to apply rules for a
> specifier list to that property (and be able to check the property name).
>
Thanks for your comments, that are indeed really good and constructive.
Benoit
^ permalink raw reply [flat|nested] 36+ messages in thread
* [RFC 11/15] scripts/dtc: check for children nodes
2013-09-24 16:52 [RFC 00/15] Device Tree schemas and validation Benoit Cousson
` (4 preceding siblings ...)
[not found] ` <1380041541-17529-1-git-send-email-bcousson-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
@ 2013-09-24 16:52 ` Benoit Cousson
2013-09-24 16:52 ` [RFC 12/15] scripts/dtc: check constraints on parents Benoit Cousson
` (4 subsequent siblings)
10 siblings, 0 replies; 36+ messages in thread
From: Benoit Cousson @ 2013-09-24 16:52 UTC (permalink / raw)
To: olof, devicetree, tomasz.figa, swarren, grant.likely, rob.herring
Cc: khilman, linux-omap, linux-arm-kernel, fparent, Benoit Cousson
From: Fabien Parent <fparent@baylibre.com>
Add the ability to check if a node has some required children nodes.
Add as well two test files for this feature.
node {
compatible = "comp";
subnode1 {
};
subnode2 {
};
abc {
};
};
One can check if 'node' has the following subnode 'subnode1', 'subnode2', and
'abc' with the schema below:
/dts-v1/;
/ {
compatible = "comp";
children = "abc", "subnode[0-9]";
};
Signed-off-by: Fabien Parent <fparent@baylibre.com>
Signed-off-by: Benoit Cousson <bcousson@baylibre.com>
---
scripts/dtc/schema-test.c | 6 +++
scripts/dtc/schema.c | 47 +++++++++++++++++++++++
scripts/dtc/tests/schemas/children-nodes-1.schema | 5 +++
scripts/dtc/tests/schemas/children-nodes-2.schema | 5 +++
scripts/dtc/tests/test1.dts | 4 ++
5 files changed, 67 insertions(+)
create mode 100644 scripts/dtc/tests/schemas/children-nodes-1.schema
create mode 100644 scripts/dtc/tests/schemas/children-nodes-2.schema
diff --git a/scripts/dtc/schema-test.c b/scripts/dtc/schema-test.c
index 128a265..9f1ce31 100644
--- a/scripts/dtc/schema-test.c
+++ b/scripts/dtc/schema-test.c
@@ -75,6 +75,12 @@ static struct schema_test tests[] = {
"tests/schemas/nodes-count-3.schema", 0},
{"Nodes Count #4", "tests/test1.dts",
"tests/schemas/nodes-count-4.schema", 0},
+
+ /* Children nodes */
+ {"Children Nodes #1", "tests/test1.dts",
+ "tests/schemas/children-nodes-1.schema", 1},
+ {"Children Nodes #2", "tests/test1.dts",
+ "tests/schemas/children-nodes-2.schema", 0},
};
int main(void)
diff --git a/scripts/dtc/schema.c b/scripts/dtc/schema.c
index b7cfb37..a454a19 100644
--- a/scripts/dtc/schema.c
+++ b/scripts/dtc/schema.c
@@ -47,6 +47,11 @@ static const char *const SCHEMA_EXT = ".schema";
static const char *const VALUE_PROPNAME = "value";
static int exit_on_failure = 0;
+struct str_list {
+ char *str;
+ struct str_list *next;
+};
+
struct node_list {
struct node *n;
struct node_list *next;
@@ -92,6 +97,7 @@ struct node_constraints {
uint32_t count_requested;
uint32_t count;
uint32_t max_count;
+ struct str_list *children;
};
struct schema_db {
@@ -664,6 +670,8 @@ static void load_node_constraints(struct node_constraints *nc,
struct node *n)
{
struct property *p;
+ int i = 0;
+ struct str_list *iter;
assert(n);
assert(nc);
@@ -675,6 +683,15 @@ static void load_node_constraints(struct node_constraints *nc,
p = get_property(n, "max-count");
nc->max_count = p ? prop_val_to_uint32(p, 0) : ULONG_MAX;
+
+ p = get_property(n, "children");
+ while (p && i < p->val.len && i >= 0) {
+ iter = xmalloc(sizeof(*iter));
+ iter->str = xstrdup(p->val.val + i);
+ iter->next = nc->children;
+ nc->children = iter;
+ i = get_next_string_offset(p, i);
+ }
}
static int validate_node(struct node *n,
@@ -682,7 +699,10 @@ static int validate_node(struct node *n,
struct node_list *path)
{
struct node *iter;
+ struct str_list *pattern;
int ret = 1;
+ pcre *re;
+ int has_child;
assert(n);
assert(path);
@@ -692,6 +712,27 @@ static int validate_node(struct node *n,
for (iter = nc->dt->children; iter; iter = iter->next_sibling)
ret &= validate_properties(n, iter, path);
+ /* Check whether the node has all the required children nodes */
+ for (pattern = nc->children;
+ pattern;
+ pattern = pattern->next) {
+ re = compile_pattern(pattern->str);
+ if (!re)
+ die("Invalid pattern: %s\n", pattern->str);
+
+ has_child = 0;
+ for (iter = n->children; iter; iter = iter->next_sibling) {
+ has_child |= pcre_exec(re, 0, iter->name,
+ strlen(iter->name), 0, 0,
+ NULL, 0) >= 0;
+ }
+
+ pcre_free(re);
+ DT_ERROR_IF(!has_child, path, NULL,
+ "Missing child node '%s'\n", pattern->str);
+ }
+
+end:
return ret;
}
@@ -1021,9 +1062,15 @@ struct schema_db *build_schema_db(const char *dir)
static void free_node_constraints(struct node_constraints *nc)
{
+ struct str_list *iter, *iter_next;
+
if (!nc)
return;
+ for_each_safe(nc->children, iter, iter_next) {
+ free(iter->str);
+ }
+
pcre_free(nc->re_compat);
free_dt(nc->bi);
free(nc->filepath);
diff --git a/scripts/dtc/tests/schemas/children-nodes-1.schema b/scripts/dtc/tests/schemas/children-nodes-1.schema
new file mode 100644
index 0000000..8f1cf9a
--- /dev/null
+++ b/scripts/dtc/tests/schemas/children-nodes-1.schema
@@ -0,0 +1,5 @@
+/dts-v1/;
+/ {
+ compatible = "node";
+ children = "node1", "node2";
+};
diff --git a/scripts/dtc/tests/schemas/children-nodes-2.schema b/scripts/dtc/tests/schemas/children-nodes-2.schema
new file mode 100644
index 0000000..f0ee2f2
--- /dev/null
+++ b/scripts/dtc/tests/schemas/children-nodes-2.schema
@@ -0,0 +1,5 @@
+/dts-v1/;
+/ {
+ compatible = "node";
+ children = "node3";
+};
diff --git a/scripts/dtc/tests/test1.dts b/scripts/dtc/tests/test1.dts
index 7d8d745..c390050 100644
--- a/scripts/dtc/tests/test1.dts
+++ b/scripts/dtc/tests/test1.dts
@@ -15,4 +15,8 @@
compatible = "compat2";
};
};
+
+ node2 {
+ compatible = "compat3";
+ };
};
--
1.8.1.2
^ permalink raw reply related [flat|nested] 36+ messages in thread
* [RFC 12/15] scripts/dtc: check constraints on parents
2013-09-24 16:52 [RFC 00/15] Device Tree schemas and validation Benoit Cousson
` (5 preceding siblings ...)
2013-09-24 16:52 ` [RFC 11/15] scripts/dtc: check for children nodes Benoit Cousson
@ 2013-09-24 16:52 ` Benoit Cousson
2013-09-24 16:52 ` [RFC 13/15] bindings: OMAP: add new schema files Benoit Cousson
` (3 subsequent siblings)
10 siblings, 0 replies; 36+ messages in thread
From: Benoit Cousson @ 2013-09-24 16:52 UTC (permalink / raw)
To: olof, devicetree, tomasz.figa, swarren, grant.likely, rob.herring
Cc: khilman, linux-omap, linux-arm-kernel, fparent, Benoit Cousson
From: Fabien Parent <fparent@baylibre.com>
Add the ability to specify constraints on the parents of a node.
Add as well seven test files for this feature.
node {
compatible = "abcomp";
abc = "abc";
subnode {
compatible = "comp";
abc = "def";
};
};
The schema below tests whether 'subnode' has a parent named 'node' and whether
it has a compatible property equal to "abcomp" and a 'abc' property equal to
"abc". In the case of the node above the constraints couldn't be check by
inheriting the properties via 'can-be-inherited' since they are overwritten
by the node 'subnode'.
/dts-v1/;
/ {
compatible = "comp";
parents {
node {
compatible {
type = "string";
value = "abcomp";
};
abc {
type = "string";
value = "abc";
};
};
};
};
It is possible to set conditional constraints on parents of the following form:
if (node_compatible == "compat1")
check_this_parent_constraints();
else if (node_compatible == "compat2")
check_that_parent_constraints();
To do this one should put the parent constraints at the same place as the
compatible definition in a schema file.
/dts-v1/;
/ {
compatible {
value@0 {
value = "compat1";
parents {
node {
myprop {
type = "int";
value@0 = <0xf>;
};
};
};
};
value@1 {
value = "compat2";
parents {
node {
myprop {
type = "int";
value@0 = <0xa>;
};
};
};
};
};
};
This schema will check that if the compatible of a node is "compat1" then it
must have a parent node "node" which has an integer array property "myprop"
which has as first element the value 0xf, otherwise if the node has the
compatible "compat2" then the first element of the same property must have the
value 0xa.
Signed-off-by: Fabien Parent <fparent@baylibre.com>
Signed-off-by: Benoit Cousson <bcousson@baylibre.com>
---
scripts/dtc/schema-test.c | 16 +++
scripts/dtc/schema.c | 126 +++++++++++++++++++++++-
scripts/dtc/tests/schemas/parent-nodes-1.schema | 23 +++++
scripts/dtc/tests/schemas/parent-nodes-2.schema | 12 +++
scripts/dtc/tests/schemas/parent-nodes-3.schema | 14 +++
scripts/dtc/tests/schemas/parent-nodes-4.schema | 27 +++++
scripts/dtc/tests/schemas/parent-nodes-5.schema | 15 +++
scripts/dtc/tests/schemas/parent-nodes-6.schema | 13 +++
scripts/dtc/tests/schemas/parent-nodes-7.schema | 13 +++
9 files changed, 257 insertions(+), 2 deletions(-)
create mode 100644 scripts/dtc/tests/schemas/parent-nodes-1.schema
create mode 100644 scripts/dtc/tests/schemas/parent-nodes-2.schema
create mode 100644 scripts/dtc/tests/schemas/parent-nodes-3.schema
create mode 100644 scripts/dtc/tests/schemas/parent-nodes-4.schema
create mode 100644 scripts/dtc/tests/schemas/parent-nodes-5.schema
create mode 100644 scripts/dtc/tests/schemas/parent-nodes-6.schema
create mode 100644 scripts/dtc/tests/schemas/parent-nodes-7.schema
diff --git a/scripts/dtc/schema-test.c b/scripts/dtc/schema-test.c
index 9f1ce31..5075c24 100644
--- a/scripts/dtc/schema-test.c
+++ b/scripts/dtc/schema-test.c
@@ -81,6 +81,22 @@ static struct schema_test tests[] = {
"tests/schemas/children-nodes-1.schema", 1},
{"Children Nodes #2", "tests/test1.dts",
"tests/schemas/children-nodes-2.schema", 0},
+
+ /* Parent nodes */
+ {"Parent Nodes #1", "tests/test1.dts",
+ "tests/schemas/parent-nodes-1.schema", 1},
+ {"Parent Nodes #2", "tests/test1.dts",
+ "tests/schemas/parent-nodes-2.schema", 0},
+ {"Parent Nodes #3", "tests/test1.dts",
+ "tests/schemas/parent-nodes-3.schema", 0},
+ {"Parent Nodes #4", "tests/test1.dts",
+ "tests/schemas/parent-nodes-4.schema", 1},
+ {"Parent Nodes #5", "tests/test1.dts",
+ "tests/schemas/parent-nodes-5.schema", 0},
+ {"Parent Nodes #6", "tests/test1.dts",
+ "tests/schemas/parent-nodes-6.schema", 0},
+ {"Parent Nodes #7", "tests/test1.dts",
+ "tests/schemas/parent-nodes-7.schema", 1},
};
int main(void)
diff --git a/scripts/dtc/schema.c b/scripts/dtc/schema.c
index a454a19..e349e01 100644
--- a/scripts/dtc/schema.c
+++ b/scripts/dtc/schema.c
@@ -694,6 +694,123 @@ static void load_node_constraints(struct node_constraints *nc,
}
}
+static struct node *find_parent_node(struct node *schema,
+ struct node_list *path)
+{
+ struct property *p;
+ char *name;
+
+ if (!path)
+ return NULL;
+
+ assert(schema);
+ assert(path->n);
+
+ p = get_property(schema, "name");
+ if (p) {
+ assert(p->val.type == STRING);
+ name = p->val.val;
+ } else {
+ name = schema->name;
+ }
+
+ if (!strcmp(name, path->n->name))
+ return path->n;
+ else
+ return find_parent_node(schema, path->next);
+}
+
+static int validate_node(struct node *n,
+ struct node_constraints *nc,
+ struct node_list *path);
+
+static void free_node_constraints(struct node_constraints *nc);
+
+static int validate_parents(struct node *schema,
+ struct node_list *path)
+{
+ struct node *n;
+ struct node_constraints *nc;
+ int ret = 1;
+
+ assert(schema);
+ assert(path);
+
+ nc = xmalloc(sizeof(*nc));
+
+ for (schema = schema->children; schema; schema = schema->next_sibling) {
+ n = find_parent_node(schema, path);
+ DT_ERROR_IF(!n, path, NULL,
+ "Missing parent node '%s'\n", schema->name);
+
+ memset(nc, 0, sizeof(*nc));
+ load_node_constraints(nc, schema);
+ nc->dt = schema;
+ ret &= validate_node(n, nc, path);
+ free_node_constraints(nc);
+ }
+
+end:
+ free(nc);
+ return ret;
+}
+
+static struct node *find_current_compatible_node(struct node_constraints *nc)
+{
+ pcre *re;
+ struct node *n;
+ struct property *p;
+
+ assert(nc);
+ assert(nc->compatible);
+ assert(nc->bi);
+ assert(nc->bi->dt);
+
+ n = get_subnode(nc->bi->dt, "compatible");
+ if (!n)
+ return NULL;
+
+ re = compile_pattern(nc->compatible);
+ assert(re);
+
+ for (n = n->children; n; n = n->next_sibling) {
+ if (!is_prop_value(n->name))
+ continue;
+
+ p = get_property(n, "value");
+ if (!p)
+ continue;
+
+ assert(p->val.type == STRING);
+ if (pcre_exec(re, 0, p->val.val, strlen(p->val.val),
+ 0, 0, NULL, 0) >= 0)
+ break;
+ }
+
+ pcre_free(re);
+ return n;
+}
+
+static int validate_compatible(struct node_constraints *nc,
+ struct node_list *path)
+{
+ int ret = 1;
+ struct node *n;
+
+ assert(nc);
+ assert(path);
+
+ n = find_current_compatible_node(nc);
+ if (!n)
+ return ret;
+
+ n = get_subnode(n, "parents");
+ if (!n)
+ return ret;
+
+ return ret & validate_parents(n, path);
+}
+
static int validate_node(struct node *n,
struct node_constraints *nc,
struct node_list *path)
@@ -709,8 +826,12 @@ static int validate_node(struct node *n,
assert(nc);
assert(nc->dt);
- for (iter = nc->dt->children; iter; iter = iter->next_sibling)
- ret &= validate_properties(n, iter, path);
+ for (iter = nc->dt->children; iter; iter = iter->next_sibling) {
+ if (!strcmp(iter->name, "parents"))
+ ret &= validate_parents(iter, path);
+ else
+ ret &= validate_properties(n, iter, path);
+ }
/* Check whether the node has all the required children nodes */
for (pattern = nc->children;
@@ -814,6 +935,7 @@ static int for_each_compatible_validate(struct schema_db *db,
while ((nc = get_node_constraints_of(db, p->val.val + offset,
&i)) != NULL) {
ret &= validate_node(node, nc, path);
+ ret &= validate_compatible(nc, path);
}
offset = get_next_string_offset(p, offset);
diff --git a/scripts/dtc/tests/schemas/parent-nodes-1.schema b/scripts/dtc/tests/schemas/parent-nodes-1.schema
new file mode 100644
index 0000000..95d3b50
--- /dev/null
+++ b/scripts/dtc/tests/schemas/parent-nodes-1.schema
@@ -0,0 +1,23 @@
+/dts-v1/;
+/ {
+ compatible = "compat2";
+
+ parents {
+ root {
+ name = "";
+ everywhere {
+ type = "integer";
+ value@0 = <0xf>;
+ value@1 = <0xa>;
+ value@2 = <0xb>;
+ };
+ };
+
+ node1 {
+ mypropstr {
+ type = "string";
+ value = "value[0-9]";
+ };
+ };
+ };
+};
diff --git a/scripts/dtc/tests/schemas/parent-nodes-2.schema b/scripts/dtc/tests/schemas/parent-nodes-2.schema
new file mode 100644
index 0000000..a2f2b80
--- /dev/null
+++ b/scripts/dtc/tests/schemas/parent-nodes-2.schema
@@ -0,0 +1,12 @@
+/dts-v1/;
+/ {
+ compatible = "compat2";
+
+ parents {
+ abc {
+ def {
+ type = "string";
+ };
+ };
+ };
+};
diff --git a/scripts/dtc/tests/schemas/parent-nodes-3.schema b/scripts/dtc/tests/schemas/parent-nodes-3.schema
new file mode 100644
index 0000000..11c327c
--- /dev/null
+++ b/scripts/dtc/tests/schemas/parent-nodes-3.schema
@@ -0,0 +1,14 @@
+/dts-v1/;
+/ {
+ compatible = "compat2";
+
+ parents {
+ root {
+ name = "";
+ abc {
+ type = "integer";
+ is-required;
+ };
+ };
+ };
+};
diff --git a/scripts/dtc/tests/schemas/parent-nodes-4.schema b/scripts/dtc/tests/schemas/parent-nodes-4.schema
new file mode 100644
index 0000000..ba67ae5
--- /dev/null
+++ b/scripts/dtc/tests/schemas/parent-nodes-4.schema
@@ -0,0 +1,27 @@
+/dts-v1/;
+/ {
+ compatible {
+ value@0 {
+ value = "compat1";
+ parents {
+ root {
+ name = "";
+ everywhere {
+ is-required;
+ };
+ };
+ };
+ };
+
+ value@1 {
+ value = "compat2";
+ parents {
+ node1 {
+ mypropstr {
+ is-required;
+ };
+ };
+ };
+ };
+ };
+};
diff --git a/scripts/dtc/tests/schemas/parent-nodes-5.schema b/scripts/dtc/tests/schemas/parent-nodes-5.schema
new file mode 100644
index 0000000..6e83ac5
--- /dev/null
+++ b/scripts/dtc/tests/schemas/parent-nodes-5.schema
@@ -0,0 +1,15 @@
+/dts-v1/;
+/ {
+ compatible {
+ value@0 {
+ value = "compat1";
+ parents {
+ root {
+ myprop {
+ is-required;
+ };
+ };
+ };
+ };
+ };
+};
diff --git a/scripts/dtc/tests/schemas/parent-nodes-6.schema b/scripts/dtc/tests/schemas/parent-nodes-6.schema
new file mode 100644
index 0000000..cc1531d
--- /dev/null
+++ b/scripts/dtc/tests/schemas/parent-nodes-6.schema
@@ -0,0 +1,13 @@
+/dts-v1/;
+/ {
+ compatible = "compat2";
+
+ parents {
+ node1 {
+ compatible {
+ type = "string";
+ value = "compat3";
+ };
+ };
+ };
+};
diff --git a/scripts/dtc/tests/schemas/parent-nodes-7.schema b/scripts/dtc/tests/schemas/parent-nodes-7.schema
new file mode 100644
index 0000000..0d45d09
--- /dev/null
+++ b/scripts/dtc/tests/schemas/parent-nodes-7.schema
@@ -0,0 +1,13 @@
+/dts-v1/;
+/ {
+ compatible = "compat2";
+
+ parents {
+ node1 {
+ compatible {
+ type = "string";
+ value = "compat1";
+ };
+ };
+ };
+};
--
1.8.1.2
^ permalink raw reply related [flat|nested] 36+ messages in thread
* [RFC 13/15] bindings: OMAP: add new schema files
2013-09-24 16:52 [RFC 00/15] Device Tree schemas and validation Benoit Cousson
` (6 preceding siblings ...)
2013-09-24 16:52 ` [RFC 12/15] scripts/dtc: check constraints on parents Benoit Cousson
@ 2013-09-24 16:52 ` Benoit Cousson
2013-09-24 16:52 ` [RFC 14/15] scripts/dtc: validate dts against schema bindings Benoit Cousson
` (2 subsequent siblings)
10 siblings, 0 replies; 36+ messages in thread
From: Benoit Cousson @ 2013-09-24 16:52 UTC (permalink / raw)
To: olof, devicetree, tomasz.figa, swarren, grant.likely, rob.herring
Cc: khilman, linux-omap, linux-arm-kernel, fparent, Benoit Cousson
From: Fabien Parent <fparent@baylibre.com>
Introduce a couple of real schema for OMAP DTS files. For the moment validate
only: MPU, DSP, INTC, IVA, TIME and COUNTER.
Signed-off-by: Fabien Parent <fparent@baylibre.com>
Signed-off-by: Benoit Cousson <bcousson@baylibre.com>
---
bindings/arm/omap/counter.schema | 28 +++++++++
bindings/arm/omap/dsp.schema | 18 ++++++
bindings/arm/omap/intc.schema | 48 +++++++++++++++
bindings/arm/omap/iva.schema | 38 ++++++++++++
bindings/arm/omap/l3-noc.schema | 38 ++++++++++++
bindings/arm/omap/mpu.schema | 19 ++++++
bindings/arm/omap/omap.schema | 62 ++++++++++++++++++++
bindings/arm/omap/timer.schema | 124 +++++++++++++++++++++++++++++++++++++++
8 files changed, 375 insertions(+)
create mode 100644 bindings/arm/omap/counter.schema
create mode 100644 bindings/arm/omap/dsp.schema
create mode 100644 bindings/arm/omap/intc.schema
create mode 100644 bindings/arm/omap/iva.schema
create mode 100644 bindings/arm/omap/l3-noc.schema
create mode 100644 bindings/arm/omap/mpu.schema
create mode 100644 bindings/arm/omap/omap.schema
create mode 100644 bindings/arm/omap/timer.schema
diff --git a/bindings/arm/omap/counter.schema b/bindings/arm/omap/counter.schema
new file mode 100644
index 0000000..63b0272
--- /dev/null
+++ b/bindings/arm/omap/counter.schema
@@ -0,0 +1,28 @@
+/**
+ * OMAP Counter-32K bindings
+ */
+
+/dts-v1/;
+
+/ {
+ compatible {
+ description = "Must be 'ti,omap-counter32k' for OMAP controllers.";
+ value = "ti,omap-counter32k";
+ };
+
+ reg {
+ description = "Contains timer register address range (base address
+ and length).";
+ is-required;
+ type = "integer";
+ length = <2>;
+ };
+
+ ti,hwmods {
+ description = "Name of the hwmod associated to the counter,
+ which is typically 'counter_32k'.";
+ is-required;
+ type = "string";
+ value = "counter_32k";
+ };
+};
diff --git a/bindings/arm/omap/dsp.schema b/bindings/arm/omap/dsp.schema
new file mode 100644
index 0000000..7087f60
--- /dev/null
+++ b/bindings/arm/omap/dsp.schema
@@ -0,0 +1,18 @@
+/**
+ * TI - DSP (Digital Signal Processor)
+ */
+
+/dts-v1/;
+
+/ {
+ compatible {
+ description = "Should be 'ti,omap3-c64' for OMAP3 & 4";
+ value = "ti,omap3-c64";
+ };
+
+ ti,hwmods {
+ is-required;
+ type = "string";
+ value = "dsp";
+ };
+};
diff --git a/bindings/arm/omap/intc.schema b/bindings/arm/omap/intc.schema
new file mode 100644
index 0000000..564c80e
--- /dev/null
+++ b/bindings/arm/omap/intc.schema
@@ -0,0 +1,48 @@
+/**
+ * OMAP Interrupt Controller
+ *
+ * OMAP2/3 are using a TI interrupt controller that can support several
+ * configurable number of interrupts.
+ */
+
+/dts-v1/;
+
+/ {
+ compatible {
+ description = "Must be 'ti,omap-counter32k' for OMAP controllers.";
+ value = "ti,omap2-intc";
+ };
+
+ interrupt-controller {
+ description = "Identifies the node as an interrupt controller";
+ is-required;
+ type = "bool";
+ };
+
+ #interrupt-cells {
+ description = "Specifies the number of cells needed to encode an
+ interrupt source. The type shall be a <u32>
+ and the value shall be 1.
+ The cell contains the interrupt number
+ in the range [0-128].";
+ is-required;
+ type = "integer";
+ value = <1>;
+ };
+
+ ti,intc-size {
+ description = "Number of interrupts handled
+ by the interrupt controller";
+ is-required;
+ type = "integer";
+ length = <1>;
+ };
+
+ reg {
+ description = "physical base address and size of the intc
+ registers map.";
+ is-required;
+ type = "integer";
+ length = <2>;
+ };
+};
diff --git a/bindings/arm/omap/iva.schema b/bindings/arm/omap/iva.schema
new file mode 100644
index 0000000..582c104
--- /dev/null
+++ b/bindings/arm/omap/iva.schema
@@ -0,0 +1,38 @@
+/**
+ * TI - IVA (Imaging and Video Accelerator) subsystem
+ *
+ * The IVA contain various audio, video or imaging HW accelerator
+ * depending of the version.
+ */
+
+/dts-v1/;
+
+/ {
+ compatible {
+ value@0 {
+ description = "for OMAP4";
+ value = "ti,ivahd";
+ };
+
+ value@1 {
+ description = "for OMAP3";
+ value = "ti,iva2.2";
+ };
+
+ value@2 {
+ description = "for OMAP2430";
+ value = "ti,iva2.1";
+ };
+
+ value@3 {
+ description = "for OMAP2420";
+ value = "ti,iva1";
+ };
+ };
+
+ ti,hwmods {
+ is-required;
+ type = "string";
+ value = "iva";
+ };
+};
diff --git a/bindings/arm/omap/l3-noc.schema b/bindings/arm/omap/l3-noc.schema
new file mode 100644
index 0000000..0611c4d
--- /dev/null
+++ b/bindings/arm/omap/l3-noc.schema
@@ -0,0 +1,38 @@
+/**
+ * TI - L3 Network On Chip (NoC)
+ *
+ * This version is an implementation of the generic NoC IP
+ * provided by Arteris.
+ */
+
+/dts-v1/;
+
+/ {
+ compatible {
+ description = "Must be 'ti,omap-counter32k' for OMAP controllers.";
+
+ value@0 {
+ description = "Should be 'ti,omap3-l3-smx' for OMAP3 family";
+ value = "ti,omap3-l3-smx";
+ };
+
+ value@1 {
+ description = "Should be 'ti,omap4-l3-noc' for OMAP4 family";
+ value = "ti,omap4-l3-noc";
+ };
+ };
+
+ reg {
+ description = "Contains L3 register address range
+ for each noc domain.";
+ is-required;
+ type = "integer";
+ };
+
+ ti,hwmods {
+ description = "'l3_main_1', ... One hwmod for each noc domain.";
+ is-required;
+ type = "string";
+ value = "l3_main_[0-9]+";
+ };
+};
diff --git a/bindings/arm/omap/mpu.schema b/bindings/arm/omap/mpu.schema
new file mode 100644
index 0000000..abf3337
--- /dev/null
+++ b/bindings/arm/omap/mpu.schema
@@ -0,0 +1,19 @@
+/**
+ * TI - MPU (Main Processor Unit) subsystem
+ *
+ * The MPU subsystem contain one or several ARM cores
+ * depending of the version.
+ * The MPU contain CPUs, GIC, L2 cache and a local PRCM.
+ */
+
+/dts-v1/;
+
+/ {
+ compatible = "ti,omap3-mpu", "ti,omap4-mpu";
+
+ ti,hwmods {
+ is-required;
+ type = "string";
+ value = "mpu";
+ };
+};
diff --git a/bindings/arm/omap/omap.schema b/bindings/arm/omap/omap.schema
new file mode 100644
index 0000000..4ed0634
--- /dev/null
+++ b/bindings/arm/omap/omap.schema
@@ -0,0 +1,62 @@
+/**
+ * Texas Instruments OMAP
+ *
+ * OMAP is currently using a static file per SoC family to describe the
+ * IPs present in the SoC.
+ * On top of that an omap_device is created to extend the platform_device
+ * capabilities and to allow binding with one or several hwmods.
+ * The hwmods will contain all the information to build the device:
+ * address range, irq lines, dma lines, interconnect, PRCM register,
+ * clock domain, input clocks.
+ * For the moment just point to the existing hwmod, the next step will be
+ * to move data from hwmod to device-tree representation.
+ *
+ *
+ * Boards:
+ *
+ * - OMAP3 BeagleBoard : Low cost community board
+ * compatible = "ti,omap3-beagle", "ti,omap3"
+ *
+ * - OMAP3 Tobi with Overo : Commercial expansion board with daughter board
+ * compatible = "ti,omap3-tobi", "ti,omap3-overo", "ti,omap3"
+ *
+ * - OMAP4 SDP : Software Development Board
+ * compatible = "ti,omap4-sdp", "ti,omap4430"
+ *
+ * - OMAP4 PandaBoard : Low cost community board
+ * compatible = "ti,omap4-panda", "ti,omap4430"
+ *
+ * - OMAP3 EVM : Software Development Board for OMAP35x, AM/DM37x
+ * compatible = "ti,omap3-evm", "ti,omap3"
+ *
+ * - AM335X EVM : Software Development Board for AM335x
+ * compatible = "ti,am335x-evm", "ti,am33xx", "ti,omap3"
+ *
+ * - AM335X Bone : Low cost community board
+ * compatible = "ti,am335x-bone", "ti,am33xx", "ti,omap3"
+ *
+ * - OMAP5 EVM : Evaluation Module
+ * compatible = "ti,omap5-evm", "ti,omap5"
+ *
+ * - AM43x EPOS EVM
+ * compatible = "ti,am43x-epos-evm", "ti,am4372", "ti,am43"
+ */
+
+/dts-v1/;
+
+/ {
+ compatible = "ti,omap.+";
+
+ ti,hwmods {
+ description = "list of hwmod names (ascii strings), that comes
+ from the OMAP HW documentation, attached to a
+ device. Must contain at least one hwmod.";
+ type = "string";
+ };
+
+ ti,no_idle_on_suspend {
+ description = "When present, it prevents the PM to idle the module
+ during suspend.";
+ type = "bool";
+ };
+};
diff --git a/bindings/arm/omap/timer.schema b/bindings/arm/omap/timer.schema
new file mode 100644
index 0000000..b9ae19e
--- /dev/null
+++ b/bindings/arm/omap/timer.schema
@@ -0,0 +1,124 @@
+/**
+ * OMAP Timer bindings
+ */
+
+/dts-v1/;
+
+/ {
+ compatible {
+ description = "Should be set to one of the below. Please note that
+ OMAP44xx devices have timer instances that are 100%
+ register compatible with OMAP3xxx devices as well as
+ newer timers that are not 100% register compatible.
+ So for OMAP44xx devices timer instances may use
+ different compatible strings.";
+
+ value@0 {
+ description = "Applicable to OMAP24xx devices";
+ value = "ti,omap2420-timer";
+ parents {
+ root {
+ name = "";
+ compatible = "ti,omap.+";
+ };
+ };
+ };
+
+ value@1 {
+ description = "Applicable to OMAP3xxx/44xx devices";
+ value = "ti,omap3430-timer";
+ parents {
+ root {
+ name = "";
+ compatible = "ti,omap.+";
+ };
+ };
+ };
+
+ value@2 {
+ description = "Applicable to OMAP44xx devices";
+ value = "ti,omap4430-timer";
+ parents {
+ root {
+ name = "";
+ compatible = "ti,omap.+";
+ };
+ };
+ };
+
+ value@3 {
+ description = "Applicable to OMAP543x devices";
+ value = "ti,omap5430-timer";
+ parents {
+ root {
+ name = "";
+ compatible = "ti,omap.+";
+ };
+ };
+ };
+
+ value@4 {
+ description = "Applicable to AM335x devices";
+ value = "ti,am335x-timer";
+ parents {
+ root {
+ name = "";
+ compatible = "ti,am.+";
+ };
+ };
+ };
+
+ value@5 {
+ description = "Applicable to AM335x devices";
+ value = "ti,am335x-timer-1ms";
+ parents {
+ root {
+ name = "";
+ compatible = "ti,am.+";
+ };
+ };
+ };
+ };
+
+ reg {
+ description = "Contains timer register address range (base address
+ and length).";
+ is-required;
+ type = "integer";
+ };
+
+ interrupts {
+ description = "Contains the interrupt information for the timer.
+ The format is being dependent on which interrupt
+ controller the OMAP device uses.";
+ is-required;
+ type = "integer";
+ };
+
+ ti,hwmods {
+ description = "Name of the hwmod associated to the timer, 'timer<X>',
+ where <X> is the instance number of the timer from the
+ HW spec.";
+ is-required;
+ type = "string";
+ value = "timer[0-9]+";
+ };
+
+ ti,timer-alwon {
+ description = "Indicates the timer is in an alway-on power domain.";
+ type = "bool";
+ };
+
+ ti,timer-dsp {
+ description = "Indicates the timer can interrupt the on-chip DSP in
+ addition to the ARM CPU.";
+ type = "bool";
+ };
+
+ ti,timer-secure {
+ description = "Indicates the timer is reserved on a secure
+ OMAP device and therefore cannot be used
+ by the kernel";
+ type = "bool";
+ };
+};
--
1.8.1.2
^ permalink raw reply related [flat|nested] 36+ messages in thread
* [RFC 14/15] scripts/dtc: validate dts against schema bindings
2013-09-24 16:52 [RFC 00/15] Device Tree schemas and validation Benoit Cousson
` (7 preceding siblings ...)
2013-09-24 16:52 ` [RFC 13/15] bindings: OMAP: add new schema files Benoit Cousson
@ 2013-09-24 16:52 ` Benoit Cousson
2013-09-24 16:52 ` [RFC 15/15] scripts/dtc: add verbose options Benoit Cousson
2013-10-01 8:06 ` [RFC 00/15] Device Tree schemas and validation Benoit Cousson
10 siblings, 0 replies; 36+ messages in thread
From: Benoit Cousson @ 2013-09-24 16:52 UTC (permalink / raw)
To: olof, devicetree, tomasz.figa, swarren, grant.likely, rob.herring
Cc: khilman, linux-omap, linux-arm-kernel, fparent, Benoit Cousson
From: Fabien Parent <fparent@baylibre.com>
Add the path of the bindings schema directory on the command line used
for compiling the dts files. The dts files will be validated against all the
matching schemas found.
Signed-off-by: Fabien Parent <fparent@baylibre.com>
Signed-off-by: Benoit Cousson <bcousson@baylibre.com>
---
scripts/Makefile.lib | 1 +
1 file changed, 1 insertion(+)
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 49392ec..358dd69 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -264,6 +264,7 @@ $(obj)/%.dtb.S: $(obj)/%.dtb
quiet_cmd_dtc = DTC $@
cmd_dtc = $(CPP) $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) $< ; \
$(objtree)/scripts/dtc/dtc -O dtb -o $@ -b 0 \
+ -M $(objtree)/bindings \
-i $(dir $<) $(DTC_FLAGS) \
-d $(depfile).dtc.tmp $(dtc-tmp) ; \
cat $(depfile).pre.tmp $(depfile).dtc.tmp > $(depfile)
--
1.8.1.2
^ permalink raw reply related [flat|nested] 36+ messages in thread
* [RFC 15/15] scripts/dtc: add verbose options
2013-09-24 16:52 [RFC 00/15] Device Tree schemas and validation Benoit Cousson
` (8 preceding siblings ...)
2013-09-24 16:52 ` [RFC 14/15] scripts/dtc: validate dts against schema bindings Benoit Cousson
@ 2013-09-24 16:52 ` Benoit Cousson
2013-10-01 8:06 ` [RFC 00/15] Device Tree schemas and validation Benoit Cousson
10 siblings, 0 replies; 36+ messages in thread
From: Benoit Cousson @ 2013-09-24 16:52 UTC (permalink / raw)
To: olof, devicetree, tomasz.figa, swarren, grant.likely, rob.herring
Cc: khilman, linux-omap, linux-arm-kernel, fparent, Benoit Cousson
From: Fabien Parent <fparent@baylibre.com>
The verbose option '-B' will show additional messages in addition
to all validation errors. Right now the level 0 prints every nodes
which don't have at least one schema associated to it. Level 1
prints every properties which were not validated due to missing
constraints.
Activate the verbose mode by default into the Makefile.
Usage example:
dtc -M ./bindings -B 1 file.dts
A count of errors found so far as also been added and is printed
on each error.
Signed-off-by: Fabien Parent <fparent@baylibre.com>
Signed-off-by: Benoit Cousson <bcousson@baylibre.com>
---
scripts/Makefile.lib | 2 +-
scripts/dtc/dtc.c | 11 ++++-
scripts/dtc/dtc.h | 1 +
scripts/dtc/schema.c | 124 ++++++++++++++++++++++++++++++++++++++++++++-------
4 files changed, 118 insertions(+), 20 deletions(-)
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 358dd69..ea1484e 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -264,7 +264,7 @@ $(obj)/%.dtb.S: $(obj)/%.dtb
quiet_cmd_dtc = DTC $@
cmd_dtc = $(CPP) $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) $< ; \
$(objtree)/scripts/dtc/dtc -O dtb -o $@ -b 0 \
- -M $(objtree)/bindings \
+ -M $(objtree)/bindings -B 1 \
-i $(dir $<) $(DTC_FLAGS) \
-d $(depfile).dtc.tmp $(dtc-tmp) ; \
cat $(depfile).pre.tmp $(depfile).dtc.tmp > $(depfile)
diff --git a/scripts/dtc/dtc.c b/scripts/dtc/dtc.c
index a7881f0..8fee7ca 100644
--- a/scripts/dtc/dtc.c
+++ b/scripts/dtc/dtc.c
@@ -99,6 +99,8 @@ static void __attribute__ ((noreturn)) usage(void)
fprintf(stderr, "\t-M <schema folder>");
fprintf(stderr,
"\t\tCheck the dts using schemas from the specified folder\n");
+ fprintf(stderr, "\t-B <number>\n");
+ fprintf(stderr, "\t\tLevel of verbosity from the schema validation\n");
exit(3);
}
@@ -111,7 +113,7 @@ int main(int argc, char *argv[])
const char *outname = "-";
const char *depname = NULL;
const char *schemadir = NULL;
- int force = 0, sort = 0;
+ int force = 0, sort = 0, verbose = 0;
const char *arg;
int opt;
FILE *outf = NULL;
@@ -123,7 +125,7 @@ int main(int argc, char *argv[])
minsize = 0;
padsize = 0;
- while ((opt = getopt(argc, argv, "hI:O:o:V:d:R:S:p:fqb:i:vH:sW:E:M:"))
+ while ((opt = getopt(argc, argv, "hI:O:o:V:d:R:S:p:fqb:i:vH:sW:E:M:B:"))
!= EOF) {
switch (opt) {
case 'I':
@@ -192,6 +194,10 @@ int main(int argc, char *argv[])
parse_checks_option(false, true, optarg);
break;
+ case 'B':
+ verbose = strtol(optarg, NULL, 0);
+ break;
+
case 'h':
default:
usage();
@@ -223,6 +229,7 @@ int main(int argc, char *argv[])
if (streq(inform, "dts")) {
bi = dt_from_source(arg);
if (schemadir) {
+ set_verbosity_level(verbose);
sdb = build_schema_db(schemadir);
validate_dt(sdb, bi);
free_schema_db(sdb);
diff --git a/scripts/dtc/dtc.h b/scripts/dtc/dtc.h
index 64fdc8a..a4731e0 100644
--- a/scripts/dtc/dtc.h
+++ b/scripts/dtc/dtc.h
@@ -293,6 +293,7 @@ int validate_dt(struct schema_db *db, struct boot_info *bi);
struct schema_db *build_schema_db(const char *dir);
void free_schema_db(struct schema_db *db);
void exit_on_schema_validation_failure(int exit);
+void set_verbosity_level(int verbosity);
void add_to_schema_db(struct schema_db *db, const char *file);
struct schema_db *new_schema_db(void);
diff --git a/scripts/dtc/schema.c b/scripts/dtc/schema.c
index e349e01..3a2f831 100644
--- a/scripts/dtc/schema.c
+++ b/scripts/dtc/schema.c
@@ -46,6 +46,8 @@
static const char *const SCHEMA_EXT = ".schema";
static const char *const VALUE_PROPNAME = "value";
static int exit_on_failure = 0;
+static int verbose;
+static int error_count;
struct str_list {
char *str;
@@ -57,6 +59,11 @@ struct node_list {
struct node_list *next;
};
+struct property_list {
+ struct property *property;
+ struct property_list *next;
+};
+
struct range {
uint32_t low;
uint32_t high;
@@ -236,7 +243,7 @@ static void dt_error(struct node_list *path,
assert(format);
- fprintf(stderr, "FATAL ERROR");
+ fprintf(stderr, "[%d] FATAL ERROR", ++error_count);
if (p) {
fprintf(stderr, " in %s:%d:%d",
p->loc.file, p->loc.line, p->loc.col);
@@ -581,15 +588,42 @@ static int check_value(struct property *p, struct prop_constraints *pc)
return 1;
}
+static void remove_from_property_list(struct property *p,
+ struct property_list **plist)
+{
+ struct property_list *iter;
+ struct property_list *next_iter;
+ struct property_list *prev_iter = NULL;
+
+ if (!plist || !*plist)
+ return;
+
+ iter = *plist;
+ for_each_safe(iter, iter, next_iter) {
+ if (strcmp(p->name, iter->property->name)) {
+ prev_iter = iter;
+ continue;
+ }
+
+ if (prev_iter)
+ prev_iter->next = iter->next;
+ else
+ *plist = iter->next;
+ free(iter);
+ }
+}
+
static int validate_properties(struct node *n,
struct node *schema,
- struct node_list *path);
+ struct node_list *path,
+ struct property_list **plist);
static int validate_property(struct node *n,
struct property *p,
struct prop_constraints *pc,
struct node *schema,
- struct node_list *path)
+ struct node_list *path,
+ struct property_list **plist)
{
int ret = 1;
@@ -598,12 +632,16 @@ static int validate_property(struct node *n,
assert(pc);
assert(path);
+ if (p && plist)
+ remove_from_property_list(p, plist);
+
if (pc->is_required && !p) {
if (pc->can_be_inherited && path->next) {
assert(path->next->n);
ret &= validate_properties(path->next->n,
schema,
- path->next);
+ path->next,
+ plist);
} else {
DT_ERROR(path, NULL, "Missing property '%s'\n",
schema->name);
@@ -636,7 +674,8 @@ end:
static int validate_properties(struct node *n,
struct node *schema,
- struct node_list *path)
+ struct node_list *path,
+ struct property_list **plist)
{
struct property *p;
struct property *iter;
@@ -652,13 +691,13 @@ static int validate_properties(struct node *n,
iter = n->proplist;
p = get_property_matching_pattern(&iter, pc->name ?: schema->name);
- ret &= validate_property(n, p, pc, schema, path);
+ ret &= validate_property(n, p, pc, schema, path, plist);
/* if other properties match the pattern */
while (iter && p) {
p = get_property_matching_pattern(&iter, schema->name);
if (p)
- ret &= validate_property(n, p, pc, schema, path);
+ ret &= validate_property(n, p, pc, schema, path, plist);
else
break;
}
@@ -722,12 +761,14 @@ static struct node *find_parent_node(struct node *schema,
static int validate_node(struct node *n,
struct node_constraints *nc,
- struct node_list *path);
+ struct node_list *path,
+ struct property_list **plist);
static void free_node_constraints(struct node_constraints *nc);
static int validate_parents(struct node *schema,
- struct node_list *path)
+ struct node_list *path,
+ struct property_list **plist)
{
struct node *n;
struct node_constraints *nc;
@@ -746,7 +787,7 @@ static int validate_parents(struct node *schema,
memset(nc, 0, sizeof(*nc));
load_node_constraints(nc, schema);
nc->dt = schema;
- ret &= validate_node(n, nc, path);
+ ret &= validate_node(n, nc, path, plist);
free_node_constraints(nc);
}
@@ -792,7 +833,8 @@ static struct node *find_current_compatible_node(struct node_constraints *nc)
}
static int validate_compatible(struct node_constraints *nc,
- struct node_list *path)
+ struct node_list *path,
+ struct property_list **plist)
{
int ret = 1;
struct node *n;
@@ -808,12 +850,13 @@ static int validate_compatible(struct node_constraints *nc,
if (!n)
return ret;
- return ret & validate_parents(n, path);
+ return ret & validate_parents(n, path, plist);
}
static int validate_node(struct node *n,
struct node_constraints *nc,
- struct node_list *path)
+ struct node_list *path,
+ struct property_list **plist)
{
struct node *iter;
struct str_list *pattern;
@@ -828,9 +871,9 @@ static int validate_node(struct node *n,
for (iter = nc->dt->children; iter; iter = iter->next_sibling) {
if (!strcmp(iter->name, "parents"))
- ret &= validate_parents(iter, path);
+ ret &= validate_parents(iter, path, plist);
else
- ret &= validate_properties(n, iter, path);
+ ret &= validate_properties(n, iter, path, plist);
}
/* Check whether the node has all the required children nodes */
@@ -915,6 +958,25 @@ end:
return ret;
}
+static struct property_list *build_proplist(struct node *node)
+{
+ struct property *p;
+ struct property_list *plist = NULL;
+ struct property_list *new_plist;
+
+ for (p = node->proplist; p; p = p->next) {
+ new_plist = xmalloc(sizeof(*new_plist));
+ memset(new_plist, 0, sizeof(*new_plist));
+
+ new_plist->next = plist;
+
+ plist = new_plist;
+ plist->property = p;
+ }
+
+ return plist;
+}
+
static int for_each_compatible_validate(struct schema_db *db,
struct property *p,
struct node *node,
@@ -924,23 +986,46 @@ static int for_each_compatible_validate(struct schema_db *db,
int i;
int offset = 0;
int ret = 1;
+ int has_compatible_in_db = 0;
+ struct property_list *plist;
+ struct property_list *plist_next;
+ char *path_str;
assert(db);
assert(node);
assert(p);
assert(p->val.type == STRING);
+ plist = build_proplist(node);
+
while (offset >= 0 && offset < p->val.len) {
i = 0;
+ has_compatible_in_db = 0;
while ((nc = get_node_constraints_of(db, p->val.val + offset,
&i)) != NULL) {
- ret &= validate_node(node, nc, path);
- ret &= validate_compatible(nc, path);
+ ret &= validate_node(node, nc, path, &plist);
+ ret &= validate_compatible(nc, path, &plist);
+ has_compatible_in_db = 1;
+ }
+
+ if (!has_compatible_in_db && verbose) {
+ fprintf(stderr, "[%d] No schema available for '%s'\n",
+ ++error_count, p->val.val + offset);
}
offset = get_next_string_offset(p, offset);
}
+ if (verbose > 1) {
+ for_each_safe(plist, plist, plist_next) {
+ path_str = build_path(path);
+ fprintf(stderr, "[%d] Property undefined: '%s%s'\n",
+ ++error_count, path_str, plist->property->name);
+ free(plist);
+ free(path_str);
+ }
+ }
+
return ret;
}
@@ -998,6 +1083,11 @@ void exit_on_schema_validation_failure(int exit)
exit_on_failure = exit;
}
+void set_verbosity_level(int verbosity)
+{
+ verbose = verbosity;
+}
+
/* Schema DB */
static int is_schema_file(const char *file)
--
1.8.1.2
^ permalink raw reply related [flat|nested] 36+ messages in thread
* Re: [RFC 00/15] Device Tree schemas and validation
2013-09-24 16:52 [RFC 00/15] Device Tree schemas and validation Benoit Cousson
` (9 preceding siblings ...)
2013-09-24 16:52 ` [RFC 15/15] scripts/dtc: add verbose options Benoit Cousson
@ 2013-10-01 8:06 ` Benoit Cousson
[not found] ` <524A8289.3050107-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
10 siblings, 1 reply; 36+ messages in thread
From: Benoit Cousson @ 2013-10-01 8:06 UTC (permalink / raw)
To: Mark Rutland, swarren, rob.herring, Pawel Moll, Ian Campbell
Cc: olof, devicetree, tomasz.figa, grant.likely, khilman, linux-omap,
linux-arm-kernel, fparent
+ more DT maintainers folks
Hi all,
I know this is mostly boring user space code, but I was expecting a
little bit of comments about at least the bindings syntax:-(
I'd like to know if this is the right direction and if it worth pursuing
in that direction.
The idea was to have at least some base for further discussion during
ARM KS 2013.
I feel alone :-(
If you have any comment, go ahead!
Thanks,
Benoit
On 24/09/2013 18:52, Benoit Cousson wrote:
> Hi All,
>
> Following the discussion that happened during LCE-2013 and the email
> thread started by Tomasz few months ago [1], here is a first attempt
> to introduce:
> - a schema language to define the bindings accurately
> - DTS validation during device tree compilation in DTC itself
>
> [1] http://www.spinics.net/lists/arm-kernel/msg262224.html
>
>
> === What it does? ===
>
> For now device-tree bindings are defined in a not standardized
> text-based format and thus any one can write the documentation for a
> binding as he wish. In addition to this there is no automated way to
> check if a dts is conform to the available bindings.
>
> The goal of this series of patch is to fix this situation by adding a
> well defined way to write bindings in a human-readable format. These
> bindings will be written through files called "schemas".
>
>
> === What is a schema? ===
>
> A schema is a file describing the constraints that one or several nodes
> of a dts must conform to. Schemas must use the file extension ".schema".
> A schema can check that:
> - A node has a given property
> - An array has a valid size
> - A node contains the required children.
> - A property has the correct type.
> - A property has the correct value.
>
> A schema can as well recursively check the constraints for parent nodes.
>
> The syntax for a schema is the same as the one for dts. This choice has
> been made to simplify its development, to maximize the code reuse and
> finally because the format is human-readable.
>
>
> === How to defined a schema? ===
>
> A binding directory has been added at the root of repository. Users can
> add schema files anywhere in it but a nice way would be to keep the same
> structure as the binding directory in the documentation.
>
> To demonstrate how to write a schema and its capability I will use the
> OMAP DTS schemas when applicable.
>
> How to:
> * Associate a schema to one or several nodes
>
> As said earlier a schema can be used to validate one or several nodes
> from a dts. To do this the "compatible" properties from the nodes which
> should be validated must be present in the schema.
>
> timer1: timer@4a318000 {
> compatible = "ti,omap3430-timer";
> reg = <0x4a318000 0x80>;
> interrupts = <0x0 0x25 0x4>;
> ti,hwmods = "timer1";
> ti,timer-alwon;
> };
>
> To write a schema which will validate OMAP Timers like the one above,
> one may write the following schema:
>
> /dts-v1/;
> / {
> compatible = "ti,omap[0-9]+-timer";
> ...
> };
>
> The schema above will be used to validate every node in a dts which has
> a compatible matching the following regular expression:
> "ti,omap[0-9]+-timer".
>
> It is possible to specify multiple compatible inside a schema using this
> syntax:
> compatible = "ti,omap[0-9]+-timer", "ti,am[0-9]+-timer";
>
> This time the schema will be application for both OMAP Timers and AM
> Timers.
>
>
> * Define constraints on properties
>
> To define constraints on a property one has to create a node in a schema
> which has as name the name of the property that one want to validate.
>
> To specify constraints on the property "ti,hwmods" of OMAP Timers one
> can write this schema:
>
> /dts-v1/;
> / {
> compatible = "ti,omap[0-9]+-timer";
> ti,hwmods {
> ...
> };
> };
>
> If one want to use a regular as property name one can write this schema:
>
> /dts-v1/;
> / {
> compatible = "abc";
> def {
> name = "def[0-9]";
> ...
> };
> };
>
> Above one can see that the "name" property override the node name.
>
>
> * Require the presence of a property
>
> One can require the presence of a property by using the "is-required"
> constraint.
>
> /dts-v1/;
> / {
> compatible = "ti,omap[0-9]+-timer";
> ti,hwmods {
> is-required;
> };
> };
>
> The "ti,hwmods" property above is set as required and its presence will
> be checked in every OMAP timer.
>
>
> * Require the presence of a property inside a node or inside one of its
> parents
>
> Sometimes a property required is not directly present inside a node but
> is present in one of its parents. To check this, one can use
> "can-be-inherited" in addition to "is-required".
>
> twl {
> interrupt-controller;
>
> rtc {
> compatible = "ti,twl4030-rtc";
> interrupts = <0xc>;
> };
> }
>
> In the case of the rtc above the interrupt-controller is not present,
> but it is present in its parent. If inheriting the property from the
> parent makes senses like here one can specify in the schema that
> interrupt-controller is required in the rtc node and that the property
> can be inherited from a parent.
>
> /dts-v1/;
> / {
> compatible = "ti,twl[0-9]+-rtc";
> interrupt-controller {
> is-required;
> can-be-inherited;
> };
> };
>
>
> * Require a node to contains a given list of children
>
> One may want to check if a node has some required children nodes.
>
> node {
> compatible = "comp";
>
> subnode1 {
> };
>
> subnode2 {
> };
>
> abc {
> };
> };
>
> One can check if 'node' has the following subnode 'subnode1', 'subnode2',
> and 'abc' with the schema below:
>
> /dts-v1/;
> / {
> compatible = "comp";
> children = "abc", "subnode[0-9]";
> };
>
>
> * Constraints on array size
>
> One can specify the following constraints on array size:
> - length: specify the exact length that an array must have.
> - min-length: specify the minimum number of elements an array must have.
> - max-length: specify the maximum number of elements an array must have.
>
> Usage example:
> node {
> compatible = "array_size";
> myarray = <0 1 2 3 4>;
> };
>
> Schema:
> /dts-v1/;
> / {
> compatible = "array_size";
>
> myarray {
> length = <5>;
> };
> };
>
>
> * Count limit on nodes
>
> One can specify a count limit for the nodes matching the schema:
> - count: if there is a match between a dts and a schema then there must
> be exactly X match between the dts and the schema at the end of the
> validation process.
> - max-count: if there is a match between a dts and a schema then there
> must be at most X match between the dts and the schema at the end of
> the validation process.
> This can be used to check if a specific node appears the right amount of
> time in the dts.
>
> / {
> timer1 {
> compatible = "ti,omap-4430-timer";
> ...
> };
>
> timer2 {
> compatible = "ti,omap-4430-timer";
> ...
> };
> };
>
> If in the above dts there must be exactly two timer one can check this
> constraints with the following schema:
>
> / {
> compatible = "ti,omap-4430-timer";
> count = <2>;
> };
>
>
> * Check that a property has the right type
>
> One can check if a property has the correct type. Right now dtc only
> handles the two trivial types: integer array, string array. Since at the
> end everything is an array of byte which may or may not be terminated by
> a null byte this was enough.
>
> / {
> compatible = "abc";
>
> abc = <0xa 0xb 0xc>;
> def = "def", gef;
> };
>
> To check that the property abc is an integer array and that the property
> def is a string array for the dts above one can use the following schema:
>
> / {
> compatible = "abc";
>
>
> abc {
> type = "integer";
> };
>
> def {
> type = "string";
> };
> };
>
>
> * Check the value of properties
>
> It is possible to check if a property has the expected value through the
> "value" constraint.
>
> abc {
> prop1 = <0 1 2 3>;
> prop2 = "value0", "value1", "value3";
> };
>
> To check whether an integer array contains value from a given range
> use the following constraint:
> prop1 {
> type = "integer";
> value = <0x0 0xF>;
> };
>
> To check whether a string array contains value that match a given
> pattern use the following constraint:
> prop2 {
> type = "string";
> value = "value[0-9]";
> };
>
> To check whether a particular element of an array has the correct value
> one can use the following constraint:
> prop1 {
> type = "integer";
> value@2 = <2>;
> };
>
> or
>
> prop2 {
> type = "string";
> value@1 = "value1";
> };
>
>
> * Check constraints on a parent node
>
> It is possible to set constraints on parents of a node.
>
> node {
> compatible = "abcomp";
> abc = "abc";
>
> subnode {
> compatible = "comp";
> abc = "def";
> };
> };
>
> The schema below tests whether 'subnode' has a parent named 'node' and
> whether it has a compatible property equal to "abcomp" and a 'abc'
> property equal to "abc". In the case of the node above the constraints
> couldn't be check by inheriting the properties via 'can-be-inherited'
> since they are overwritten by the node 'subnode'.
>
> /dts-v1/;
> / {
> compatible = "comp";
>
> parents {
> node {
> compatible {
> type = "string";
> value = "abcomp";
> };
>
> abc {
> type = "string";
> value = "abc";
> };
> };
> };
> };
>
> It is possible to set conditional constraints on parents of the
> following form:
> if (node_compatible == "compat1")
> check_this_parent_constraints();
> else if (node_compatible == "compat2")
> check_that_parent_constraints();
>
> To do this one should put the parent constraints at the same place as
> the compatible definition in a schema file.
>
> /dts-v1/;
> / {
> compatible {
> value@0 {
> value = "compat1";
> parents {
> node {
> myprop {
> type = "int";
> value@0 = <0xf>;
> };
> };
> };
> };
>
> value@1 {
> value = "compat2";
> parents {
> node {
> myprop {
> type = "int";
> value@0 = <0xa>;
> };
> };
> };
> };
> };
> };
>
> This schema will check that if the compatible of a node is "compat1"
> then it must have a parent node "node" which has an integer array
> property "myprop" which has as first element the value 0xf, otherwise
> if the node has the
> compatible "compat2" then the first element of the same property must
> have the value 0xa.
>
>
> === How is it working? ===
>
> When a user will try to compile a dts, dtc will parse the device-tree
> and will try to find schemas that will help to check the correctness of
> the dts. In order to accomplish that dtc maintain a small index of all
> the schemas available.
> Once dtc finds a schema which can be used to validate a particular node,
> it will loads it and starts performing all the check defined by it.
>
> A set of unit-tests has been added to test that each feature is working
> properly.
>
>
> === Usage ===
>
> Two extra options are added to handle validation into DTC:
> -M <schema-path> : path of the directoy containing the schemas
> -B <verbose-level> : Level of verbosity from the schema validation
>
> dtc -M ./bindings -B 1 file.dts
>
>
> === What could be done next? ===
>
> * Save the schema index to avoid to recompute it everytime.
> * The constraints capabilities for parents and children of a node is
> not equal right now. A nice thing would be to bring the same feature
> available for constraints on a parent for children nodes.
> * The type systems uses only the most trivial types. A nice thing would
> be to bring higher level types.
> * May be add conditional constraints based on property values.
> * Need more? Feel free to add any item :-)
>
> Dependency: Please note that libpcre *must* be installed in order to
> add the regular expression support into the schema validation process.
> I'm not sure how such dependency should be handled, since the scripts
> directory does not contain any dependency like that for the moment.
>
> The series, based on 3.12-rc2, is available here:
> http://git.baylibre.com/pub/bcousson/linux-omap dts_schema
>
> Regards,
> Fabien & Benoit
>
> ---
>
> Fabien Parent (15):
> scripts/dtc: fix most memory leaks in dtc
> scripts/dtc: build schema index for dts validation
> scripts/dtc: validate each nodes and properties
> scripts/dtc: add procedure to handle dts errors
> scripts/dtc: check type on properties
> scripts/dtc: check for required properties
> scripts/dtc: can inherit properties
> scripts/dtc: check array size
> scripts/dtc: check value of properties
> scripts/dtc: add count limit on nodes
> scripts/dtc: check for children nodes
> scripts/dtc: check constraints on parents
> bindings: OMAP: add new schema files
> scripts/dtc: validate dts against schema bindings
> scripts/dtc: add verbose options
>
> bindings/arm/omap/counter.schema | 28 +
> bindings/arm/omap/dsp.schema | 18 +
> bindings/arm/omap/intc.schema | 48 +
> bindings/arm/omap/iva.schema | 38 +
> bindings/arm/omap/l3-noc.schema | 38 +
> bindings/arm/omap/mpu.schema | 19 +
> bindings/arm/omap/omap.schema | 62 +
> bindings/arm/omap/timer.schema | 124 ++
> scripts/Makefile.lib | 1 +
> scripts/dtc/.gitignore | 2 +-
> scripts/dtc/Makefile | 9 +-
> scripts/dtc/data.c | 27 +-
> scripts/dtc/dtc-lexer.l | 2 +-
> scripts/dtc/dtc-lexer.lex.c_shipped | 2 +-
> scripts/dtc/dtc-parser.tab.c_shipped | 595 ++++-----
> scripts/dtc/dtc-parser.y | 9 +
> scripts/dtc/dtc.c | 29 +-
> scripts/dtc/dtc.h | 30 +
> scripts/dtc/livetree.c | 108 +-
> scripts/dtc/schema-test.c | 146 +++
> scripts/dtc/schema.c | 1304 ++++++++++++++++++++
> scripts/dtc/tests/schemas/array-size-1.schema | 13 +
> scripts/dtc/tests/schemas/array-size-2.schema | 8 +
> scripts/dtc/tests/schemas/array-size-3.schema | 8 +
> scripts/dtc/tests/schemas/array-size-4.schema | 8 +
> scripts/dtc/tests/schemas/children-nodes-1.schema | 5 +
> scripts/dtc/tests/schemas/children-nodes-2.schema | 5 +
> scripts/dtc/tests/schemas/inheritence-1.schema | 7 +
> scripts/dtc/tests/schemas/inheritence-2.schema | 8 +
> scripts/dtc/tests/schemas/integer-array-1.schema | 16 +
> scripts/dtc/tests/schemas/integer-array-2.schema | 9 +
> scripts/dtc/tests/schemas/integer-array-3.schema | 8 +
> scripts/dtc/tests/schemas/nodes-count-1.schema | 5 +
> scripts/dtc/tests/schemas/nodes-count-2.schema | 5 +
> scripts/dtc/tests/schemas/nodes-count-3.schema | 5 +
> scripts/dtc/tests/schemas/nodes-count-4.schema | 5 +
> scripts/dtc/tests/schemas/parent-nodes-1.schema | 23 +
> scripts/dtc/tests/schemas/parent-nodes-2.schema | 12 +
> scripts/dtc/tests/schemas/parent-nodes-3.schema | 14 +
> scripts/dtc/tests/schemas/parent-nodes-4.schema | 27 +
> scripts/dtc/tests/schemas/parent-nodes-5.schema | 15 +
> scripts/dtc/tests/schemas/parent-nodes-6.schema | 13 +
> scripts/dtc/tests/schemas/parent-nodes-7.schema | 13 +
> .../dtc/tests/schemas/pattern-matching-1.schema | 10 +
> .../dtc/tests/schemas/pattern-matching-2.schema | 10 +
> .../dtc/tests/schemas/required-property-1.schema | 7 +
> .../dtc/tests/schemas/required-property-2.schema | 7 +
> scripts/dtc/tests/schemas/string-array-1.schema | 20 +
> scripts/dtc/tests/schemas/string-array-2.schema | 9 +
> scripts/dtc/tests/schemas/types-1.schema | 12 +
> scripts/dtc/tests/schemas/types-2.schema | 7 +
> scripts/dtc/tests/test1.dts | 22 +
> 52 files changed, 2619 insertions(+), 356 deletions(-)
> create mode 100644 bindings/arm/omap/counter.schema
> create mode 100644 bindings/arm/omap/dsp.schema
> create mode 100644 bindings/arm/omap/intc.schema
> create mode 100644 bindings/arm/omap/iva.schema
> create mode 100644 bindings/arm/omap/l3-noc.schema
> create mode 100644 bindings/arm/omap/mpu.schema
> create mode 100644 bindings/arm/omap/omap.schema
> create mode 100644 bindings/arm/omap/timer.schema
> create mode 100644 scripts/dtc/schema-test.c
> create mode 100644 scripts/dtc/schema.c
> create mode 100644 scripts/dtc/tests/schemas/array-size-1.schema
> create mode 100644 scripts/dtc/tests/schemas/array-size-2.schema
> create mode 100644 scripts/dtc/tests/schemas/array-size-3.schema
> create mode 100644 scripts/dtc/tests/schemas/array-size-4.schema
> create mode 100644 scripts/dtc/tests/schemas/children-nodes-1.schema
> create mode 100644 scripts/dtc/tests/schemas/children-nodes-2.schema
> create mode 100644 scripts/dtc/tests/schemas/inheritence-1.schema
> create mode 100644 scripts/dtc/tests/schemas/inheritence-2.schema
> create mode 100644 scripts/dtc/tests/schemas/integer-array-1.schema
> create mode 100644 scripts/dtc/tests/schemas/integer-array-2.schema
> create mode 100644 scripts/dtc/tests/schemas/integer-array-3.schema
> create mode 100644 scripts/dtc/tests/schemas/nodes-count-1.schema
> create mode 100644 scripts/dtc/tests/schemas/nodes-count-2.schema
> create mode 100644 scripts/dtc/tests/schemas/nodes-count-3.schema
> create mode 100644 scripts/dtc/tests/schemas/nodes-count-4.schema
> create mode 100644 scripts/dtc/tests/schemas/parent-nodes-1.schema
> create mode 100644 scripts/dtc/tests/schemas/parent-nodes-2.schema
> create mode 100644 scripts/dtc/tests/schemas/parent-nodes-3.schema
> create mode 100644 scripts/dtc/tests/schemas/parent-nodes-4.schema
> create mode 100644 scripts/dtc/tests/schemas/parent-nodes-5.schema
> create mode 100644 scripts/dtc/tests/schemas/parent-nodes-6.schema
> create mode 100644 scripts/dtc/tests/schemas/parent-nodes-7.schema
> create mode 100644 scripts/dtc/tests/schemas/pattern-matching-1.schema
> create mode 100644 scripts/dtc/tests/schemas/pattern-matching-2.schema
> create mode 100644 scripts/dtc/tests/schemas/required-property-1.schema
> create mode 100644 scripts/dtc/tests/schemas/required-property-2.schema
> create mode 100644 scripts/dtc/tests/schemas/string-array-1.schema
> create mode 100644 scripts/dtc/tests/schemas/string-array-2.schema
> create mode 100644 scripts/dtc/tests/schemas/types-1.schema
> create mode 100644 scripts/dtc/tests/schemas/types-2.schema
> create mode 100644 scripts/dtc/tests/test1.dts
>
^ permalink raw reply [flat|nested] 36+ messages in thread