devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC 00/15] Device Tree schemas and validation
@ 2013-09-24 16:52 Benoit Cousson
  2013-09-24 16:52 ` [RFC 01/15] scripts/dtc: fix most memory leaks in dtc Benoit Cousson
                   ` (10 more replies)
  0 siblings, 11 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

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

-- 
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	[flat|nested] 36+ messages in thread

* [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 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(&regex, "^%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 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 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 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

* [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

* [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

* Re: [RFC 00/15] Device Tree schemas and validation
       [not found]   ` <524A8289.3050107-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
@ 2013-10-01 13:17     ` Rob Herring
       [not found]       ` <524ACB76.1010001-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
  0 siblings, 1 reply; 36+ messages in thread
From: Rob Herring @ 2013-10-01 13:17 UTC (permalink / raw)
  To: Benoit Cousson
  Cc: Mark Rutland, swarren-3lzwWm7+Weoh9ZMKESR00Q, Pawel Moll,
	Ian Campbell, olof-nZhT3qVonbNeoWH0uzbU5w,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	tomasz.figa-Re5JQEeQqe8AvxtiuMwx3w,
	grant.likely-s3s/WqlpOiPyB63q8FvJNQ,
	khilman-QSEj5FYQhm4dnm+yROfE0A, linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	fparent-rdvid1DuHRBWk0Htik3J/w

On 10/01/2013 03:06 AM, Benoit Cousson wrote:
> + 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 for taking this on!

This is interesting approach using the dts syntax, but I worry that the
validation will only be as good as the schema written and the review of
the schema. I think the schema needs to define the binding rather than
define the checks. Then the schema can feed the validation checks. This
format does not seem to me as easily being able to generate
documentation from the schema which I believe is one of the goals. I for
one don't care to review the documentation and the schema for every binding.

I would like to ensure we can start with the basics and have some
generic rules. Some examples:

- flag compatible strings in dts files that are not documented
- check required properties
- check properties against cell sizes
- a node with reg property must have a unit address
- flag properties with "_"
- check properties are the correct data type

Rob

> 
> 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
>>
> 

--
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

* Re: [RFC 00/15] Device Tree schemas and validation
       [not found]       ` <524ACB76.1010001-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
@ 2013-10-01 15:06         ` Benoit Cousson
  2013-10-01 15:17           ` Jon Loeliger
       [not found]           ` <524AE4FB.4080906-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
  2013-10-02 13:52         ` David Gibson
  1 sibling, 2 replies; 36+ messages in thread
From: Benoit Cousson @ 2013-10-01 15:06 UTC (permalink / raw)
  To: Rob Herring
  Cc: Mark Rutland, swarren-3lzwWm7+Weoh9ZMKESR00Q, Pawel Moll,
	Ian Campbell, olof-nZhT3qVonbNeoWH0uzbU5w,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	tomasz.figa-Re5JQEeQqe8AvxtiuMwx3w,
	grant.likely-s3s/WqlpOiPyB63q8FvJNQ,
	khilman-QSEj5FYQhm4dnm+yROfE0A, linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	fparent-rdvid1DuHRBWk0Htik3J/w

Hi Rob,

On 01/10/2013 15:17, Rob Herring wrote:
> On 10/01/2013 03:06 AM, Benoit Cousson wrote:
>> + 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 for taking this on!
>
> This is interesting approach using the dts syntax,

Well, this was discussed a little bit on the list, and it has the big 
advantage of re-using the parser already included in DTC for free.
In term or readability, it avoids to re-defining a brand new syntax for 
people who are already familiar with the DTS one.

> but I worry that the
> validation will only be as good as the schema written and the review of
> the schema.

Well, sure, but unfortunately, that will always be the case :-(
The bindings definition being quite open, there is no easy way to ensure 
proper schema / bindings without careful review of the schema. There is 
no such thing as a free beer... Unfortunately :-)

> I think the schema needs to define the binding rather than
> define the checks. Then the schema can feed the validation checks.

> This format does not seem to me as easily being able to generate
> documentation from the schema which I believe is one of the goals.

Indeed, but I think is it easy to generate any kind of readable format 
for the documentation purpose if needed from the actual format.
Otherwise, we should consider a schema format based on kerneldoc type of 
syntax to improve readability. I'm just afraid it will become harder 
then to define complex schema.

BTW, what kind of documentation are you expecting here? Is is a text 
that can be added on top of each schema?

> I for
> one don't care to review the documentation and the schema for every binding.
>
> I would like to ensure we can start with the basics and have some
> generic rules. Some examples:
>
> - flag compatible strings in dts files that are not documented

This is almost done with the last patch of the series. Nodes are already 
checked, properties are missing.

> - check required properties

Done as well.

> - check properties against cell sizes

Yeah, that one is still to be done.

> - a node with reg property must have a unit address

Easy to add.

> - flag properties with "_"

Easy to add as well.

> - check properties are the correct data type

Already done for a couple of data type.

Thanks for your comments. Being the very first one, you might get a free 
beer... meaning there might be such thing as a free beer :-)

Thanks,
Benoit


>> 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
>>>
>>
>

--
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

* Re: [RFC 00/15] Device Tree schemas and validation
  2013-10-01 15:06         ` Benoit Cousson
@ 2013-10-01 15:17           ` Jon Loeliger
  2013-10-02  8:24             ` David Gibson
  2013-10-02  9:25             ` Benoit Cousson
       [not found]           ` <524AE4FB.4080906-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
  1 sibling, 2 replies; 36+ messages in thread
From: Jon Loeliger @ 2013-10-01 15:17 UTC (permalink / raw)
  To: Benoit Cousson
  Cc: Rob Herring, Mark Rutland, swarren, Pawel Moll, Ian Campbell,
	olof, devicetree, tomasz.figa, grant.likely, khilman, linux-omap,
	linux-arm-kernel, fparent

> Hi Rob,
> 
> On 01/10/2013 15:17, Rob Herring wrote:
> > On 10/01/2013 03:06 AM, Benoit Cousson wrote:
> >> + 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!


Benoit,

Sorry, I meant to ask earlier but forgot.
Shouldn't this development be based on the
upstream DTC repository and not the in-kernel
copy of the DTC?

Thanks,
jdl

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [RFC 00/15] Device Tree schemas and validation
       [not found]           ` <524AE4FB.4080906-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
@ 2013-10-01 20:54             ` Rob Herring
       [not found]               ` <CAL_JsqJ31TGFJCSeSOqgee=OLVfSUTAYdF4nSn7X2DiCequVAw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  0 siblings, 1 reply; 36+ messages in thread
From: Rob Herring @ 2013-10-01 20:54 UTC (permalink / raw)
  To: Benoit Cousson
  Cc: Mark Rutland, Stephen Warren, Pawel Moll, Ian Campbell,
	Olof Johansson,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Tomasz Figa,
	Grant Likely, Kevin Hilman, linux-omap,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
	fparent-rdvid1DuHRBWk0Htik3J/w

On Tue, Oct 1, 2013 at 10:06 AM, Benoit Cousson <bcousson-rdvid1DuHRBWk0Htik3J/w@public.gmane.org> wrote:
> Hi Rob,
>
>
> On 01/10/2013 15:17, Rob Herring wrote:
>>
>> On 10/01/2013 03:06 AM, Benoit Cousson wrote:
>>>
>>> + 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 for taking this on!
>>
>> This is interesting approach using the dts syntax,
>
>
> Well, this was discussed a little bit on the list, and it has the big
> advantage of re-using the parser already included in DTC for free.
> In term or readability, it avoids to re-defining a brand new syntax for
> people who are already familiar with the DTS one.
>
>
>> but I worry that the
>> validation will only be as good as the schema written and the review of
>> the schema.
>
>
> Well, sure, but unfortunately, that will always be the case :-(
> The bindings definition being quite open, there is no easy way to ensure
> proper schema / bindings without careful review of the schema. There is no
> such thing as a free beer... Unfortunately :-)
>
>
>> I think the schema needs to define the binding rather than
>> define the checks. Then the schema can feed the validation checks.
>
>
>> This format does not seem to me as easily being able to generate
>> documentation from the schema which I believe is one of the goals.
>
>
> Indeed, but I think is it easy to generate any kind of readable format for
> the documentation purpose if needed from the actual format.
> Otherwise, we should consider a schema format based on kerneldoc type of
> syntax to improve readability. I'm just afraid it will become harder then to
> define complex schema.
>
> BTW, what kind of documentation are you expecting here? Is is a text that
> can be added on top of each schema?

I would expect the schema to replace
Documentation/devicetree/bindings/* over time. I think the thing that
needs to be worked out here is how to add free form multi-line text.

>> I for
>> one don't care to review the documentation and the schema for every
>> binding.
>>
>> I would like to ensure we can start with the basics and have some
>> generic rules. Some examples:
>>
>> - flag compatible strings in dts files that are not documented
>
>
> This is almost done with the last patch of the series. Nodes are already
> checked, properties are missing.
>
>> - check required properties
>
>
> Done as well.
>
>
>> - check properties against cell sizes
>
>
> Yeah, that one is still to be done.
>
>
>> - a node with reg property must have a unit address
>
>
> Easy to add.
>
>
>> - flag properties with "_"
>
>
> Easy to add as well.
>
>
>> - check properties are the correct data type
>
>
> Already done for a couple of data type.

Good to know. It wasn't really clear what common items are checked. An
example schema for clocks or gpio (or any other common) binding would
be nice.

Do you have a run with all the warnings found?

> Thanks for your comments. Being the very first one, you might get a free
> beer... meaning there might be such thing as a free beer :-)

In that case, it all looks perfect. :)

Rob
--
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

* 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

* Re: [RFC 00/15] Device Tree schemas and validation
  2013-10-01 15:17           ` Jon Loeliger
@ 2013-10-02  8:24             ` David Gibson
  2013-10-02  9:25             ` Benoit Cousson
  1 sibling, 0 replies; 36+ messages in thread
From: David Gibson @ 2013-10-02  8:24 UTC (permalink / raw)
  To: Jon Loeliger
  Cc: Benoit Cousson, Rob Herring, Mark Rutland, swarren, Pawel Moll,
	Ian Campbell, olof, devicetree, tomasz.figa, grant.likely,
	khilman, linux-omap, linux-arm-kernel, fparent

[-- Attachment #1: Type: text/plain, Size: 1129 bytes --]

On Tue, Oct 01, 2013 at 10:17:53AM -0500, Jon Loeliger wrote:
> > Hi Rob,
> > 
> > On 01/10/2013 15:17, Rob Herring wrote:
> > > On 10/01/2013 03:06 AM, Benoit Cousson wrote:
> > >> + 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!
> 
> 
> Benoit,
> 
> Sorry, I meant to ask earlier but forgot.
> Shouldn't this development be based on the
> upstream DTC repository and not the in-kernel
> copy of the DTC?

Absolutely.  Please work against upstream dtc.

-- 
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 15:17           ` Jon Loeliger
  2013-10-02  8:24             ` David Gibson
@ 2013-10-02  9:25             ` Benoit Cousson
       [not found]               ` <524BE66D.7060308-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
  1 sibling, 1 reply; 36+ messages in thread
From: Benoit Cousson @ 2013-10-02  9:25 UTC (permalink / raw)
  To: Jon Loeliger
  Cc: Rob Herring, Mark Rutland, swarren, Pawel Moll, Ian Campbell,
	olof, devicetree, tomasz.figa, grant.likely, khilman, linux-omap,
	linux-arm-kernel, fparent

Hi Jon,

On 01/10/2013 17:17, Jon Loeliger wrote:
>> Hi Rob,
>>
>> On 01/10/2013 15:17, Rob Herring wrote:
>>> On 10/01/2013 03:06 AM, Benoit Cousson wrote:
>>>> + 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!
>
>
> Benoit,
>
> Sorry, I meant to ask earlier but forgot.
> Shouldn't this development be based on the
> upstream DTC repository and not the in-kernel
> copy of the DTC?

Eventually, yes, but here the main point is to discuss the schema that 
will be used to defined bindings.
In that case, the DTC patches code are mostly a proof of concept using 
the Linux kernel as example.

Regards,
Benoit


^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [RFC 01/15] scripts/dtc: fix most memory leaks in dtc
       [not found]   ` <1380041541-17529-2-git-send-email-bcousson-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
@ 2013-10-02 12:59     ` David Gibson
       [not found]       ` <CAOwMV_zAZG3vvWS6pkyK-FbOEg_32KRO-k1SmFSh-pc9+0JiPA@mail.gmail.com>
  0 siblings, 1 reply; 36+ messages in thread
From: David Gibson @ 2013-10-02 12:59 UTC (permalink / raw)
  To: Benoit Cousson
  Cc: olof-nZhT3qVonbNeoWH0uzbU5w, devicetree-u79uwXL29TY76Z2rM5mHXA,
	tomasz.figa-Re5JQEeQqe8AvxtiuMwx3w,
	swarren-3lzwWm7+Weoh9ZMKESR00Q,
	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: 9048 bytes --]

On Tue, Sep 24, 2013 at 06:52:07PM +0200, Benoit Cousson wrote:
> From: Fabien Parent <fparent-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>

As noted elsewhere, please write patches against upstream dtc, not the
version in the kernel.  git://git.kernel.org/pub/scm/utils/dtc/dtc.git

> 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.

Hrm, yeah.  I'm aware that I haven't been very careful with memory
leaks within the parser.  Essentially, I've been treating the process
as a pool allocator with exactly one pool - I've even considered
getting rid of those free()s we do have.

If the parser's going to be invoked repeatedly, then, yes, that
certainly needs fixing.  Whether individually fixing each leak or
using a explicit pool allocator is a better option is less clear.

> 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.

This is no good.  Making this assumption is a layering violation - if
the parser was changed so that this literal wasn't converted until
after another token was read, the yytext value copied in here would no
longer be valid and would break horribly.

> 
> Signed-off-by: Fabien Parent <fparent-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
> Signed-off-by: Benoit Cousson <bcousson-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
> ---
>  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) {

Rather hard to read version of safe-against-free list iteration.

> +		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)

*n->name .. so, the name can (and must) be statically allocated if
it's exactly "".  Not a useful optimization, I think.

> +		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);
> +}

-- 
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
       [not found]               ` <524BE66D.7060308-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
@ 2013-10-02 13:22                 ` Jon Loeliger
  0 siblings, 0 replies; 36+ messages in thread
From: Jon Loeliger @ 2013-10-02 13:22 UTC (permalink / raw)
  To: Benoit Cousson
  Cc: Rob Herring, Mark Rutland, swarren-3lzwWm7+Weoh9ZMKESR00Q,
	Pawel Moll, Ian Campbell, olof-nZhT3qVonbNeoWH0uzbU5w,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	tomasz.figa-Re5JQEeQqe8AvxtiuMwx3w,
	grant.likely-s3s/WqlpOiPyB63q8FvJNQ,
	khilman-QSEj5FYQhm4dnm+yROfE0A, linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	fparent-rdvid1DuHRBWk0Htik3J/w

> >
> > Benoit,
> >
> > Sorry, I meant to ask earlier but forgot.
> > Shouldn't this development be based on the
> > upstream DTC repository and not the in-kernel
> > copy of the DTC?
> 
> Eventually, yes,

We should *start* there, though.

> but here the main point is to discuss the schema that 
> will be used to defined bindings.
> In that case, the DTC patches code are mostly a proof of concept

Sure; all that is fine.

> using the Linux kernel as example.

Example?(*)  We shouldn't churn the kernel.

jdl

(*) In the sense that *this* Universe is just
    one example from all known Universes? :-)
--
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

* Re: [RFC 00/15] Device Tree schemas and validation
       [not found]       ` <524ACB76.1010001-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
  2013-10-01 15:06         ` Benoit Cousson
@ 2013-10-02 13:52         ` David Gibson
  1 sibling, 0 replies; 36+ messages in thread
From: David Gibson @ 2013-10-02 13:52 UTC (permalink / raw)
  To: Rob Herring
  Cc: Benoit Cousson, Mark Rutland, swarren-3lzwWm7+Weoh9ZMKESR00Q,
	Pawel Moll, Ian Campbell, olof-nZhT3qVonbNeoWH0uzbU5w,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	tomasz.figa-Re5JQEeQqe8AvxtiuMwx3w,
	grant.likely-s3s/WqlpOiPyB63q8FvJNQ,
	khilman-QSEj5FYQhm4dnm+yROfE0A, linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	fparent-rdvid1DuHRBWk0Htik3J/w

[-- Attachment #1: Type: text/plain, Size: 1718 bytes --]

On Tue, Oct 01, 2013 at 08:17:42AM -0500, Rob Herring wrote:
> On 10/01/2013 03:06 AM, Benoit Cousson wrote:
> > + 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 for taking this on!
> 
> This is interesting approach using the dts syntax, but I worry that the
> validation will only be as good as the schema written and the review of
> the schema. I think the schema needs to define the binding rather than
> define the checks. Then the schema can feed the validation checks. This
> format does not seem to me as easily being able to generate
> documentation from the schema which I believe is one of the goals. I for
> one don't care to review the documentation and the schema for every binding.

Hrm.  I'm less optimistic about entirely replacing human-readable
bindings with machine-readable schemas.  But I do think the schema
language needs to be substantially more flexible than the draft
presented here.

While I think a schema syntax which mirrors dts syntax makes a lot of
sense, actually defining schemas as "device" trees doesn't seem quite
right to me.

-- 
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
       [not found]               ` <CAL_JsqJ31TGFJCSeSOqgee=OLVfSUTAYdF4nSn7X2DiCequVAw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2013-10-02 13:54                 ` David Gibson
  2013-10-02 18:08                   ` Mark Brown
  2013-10-03  6:52                   ` Benoit Cousson
  0 siblings, 2 replies; 36+ messages in thread
From: David Gibson @ 2013-10-02 13:54 UTC (permalink / raw)
  To: Rob Herring
  Cc: Benoit Cousson, Mark Rutland, Stephen Warren, Pawel Moll,
	Ian Campbell, Olof Johansson,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Tomasz Figa,
	Grant Likely, Kevin Hilman, linux-omap,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
	fparent-rdvid1DuHRBWk0Htik3J/w

[-- Attachment #1: Type: text/plain, Size: 3090 bytes --]

On Tue, Oct 01, 2013 at 03:54:20PM -0500, Rob Herring wrote:
> On Tue, Oct 1, 2013 at 10:06 AM, Benoit Cousson <bcousson-rdvid1DuHRBWk0Htik3J/w@public.gmane.org> wrote:
> > Hi Rob,
> >
> >
> > On 01/10/2013 15:17, Rob Herring wrote:
> >>
> >> On 10/01/2013 03:06 AM, Benoit Cousson wrote:
> >>>
> >>> + 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 for taking this on!
> >>
> >> This is interesting approach using the dts syntax,
> >
> >
> > Well, this was discussed a little bit on the list, and it has the big
> > advantage of re-using the parser already included in DTC for free.
> > In term or readability, it avoids to re-defining a brand new syntax for
> > people who are already familiar with the DTS one.
> >
> >
> >> but I worry that the
> >> validation will only be as good as the schema written and the review of
> >> the schema.
> >
> >
> > Well, sure, but unfortunately, that will always be the case :-(
> > The bindings definition being quite open, there is no easy way to ensure
> > proper schema / bindings without careful review of the schema. There is no
> > such thing as a free beer... Unfortunately :-)
> >
> >
> >> I think the schema needs to define the binding rather than
> >> define the checks. Then the schema can feed the validation checks.
> >
> >
> >> This format does not seem to me as easily being able to generate
> >> documentation from the schema which I believe is one of the goals.
> >
> >
> > Indeed, but I think is it easy to generate any kind of readable format for
> > the documentation purpose if needed from the actual format.
> > Otherwise, we should consider a schema format based on kerneldoc type of
> > syntax to improve readability. I'm just afraid it will become harder then to
> > define complex schema.
> >
> > BTW, what kind of documentation are you expecting here? Is is a text that
> > can be added on top of each schema?
> 
> I would expect the schema to replace
> Documentation/devicetree/bindings/* over time. I think the thing that
> needs to be worked out here is how to add free form multi-line text.

I'm not convinced that's a realistic goal.  As I see it, the
fundamental difference between a binding document and a formal schema
is that a binding defines both the syntax required of a node, and its
semantics, whereas a schema defines only syntax - the semantics still
need to be defined somewhere.

-- 
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
       [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-02 13:54                 ` David Gibson
@ 2013-10-02 18:08                   ` Mark Brown
  2013-10-02 23:38                     ` David Gibson
  2013-10-03  6:52                   ` Benoit Cousson
  1 sibling, 1 reply; 36+ messages in thread
From: Mark Brown @ 2013-10-02 18:08 UTC (permalink / raw)
  To: David Gibson
  Cc: Rob Herring, Mark Rutland, devicetree@vger.kernel.org,
	Kevin Hilman, Pawel Moll, Ian Campbell, Stephen Warren,
	Tomasz Figa, Grant Likely, fparent, Benoit Cousson,
	Olof Johansson, linux-omap, linux-arm-kernel@lists.infradead.org

[-- Attachment #1: Type: text/plain, Size: 787 bytes --]

On Wed, Oct 02, 2013 at 11:54:50PM +1000, David Gibson wrote:
> On Tue, Oct 01, 2013 at 03:54:20PM -0500, Rob Herring wrote:

> > I would expect the schema to replace
> > Documentation/devicetree/bindings/* over time. I think the thing that
> > needs to be worked out here is how to add free form multi-line text.

> I'm not convinced that's a realistic goal.  As I see it, the
> fundamental difference between a binding document and a formal schema
> is that a binding defines both the syntax required of a node, and its
> semantics, whereas a schema defines only syntax - the semantics still
> need to be defined somewhere.

So long as the schema lets you include free form text to define the
semantics I'm not sure there's an incompatibility there - the same
document can cover both.

[-- Attachment #2: Digital signature --]
[-- 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-02 18:08                   ` Mark Brown
@ 2013-10-02 23:38                     ` David Gibson
  0 siblings, 0 replies; 36+ messages in thread
From: David Gibson @ 2013-10-02 23:38 UTC (permalink / raw)
  To: Mark Brown
  Cc: Rob Herring, Mark Rutland, devicetree@vger.kernel.org,
	Kevin Hilman, Pawel Moll, Ian Campbell, Stephen Warren,
	Tomasz Figa, Grant Likely, fparent, Benoit Cousson,
	Olof Johansson, linux-omap, linux-arm-kernel@lists.infradead.org

[-- Attachment #1: Type: text/plain, Size: 1218 bytes --]

On Wed, Oct 02, 2013 at 07:08:41PM +0100, Mark Brown wrote:
> On Wed, Oct 02, 2013 at 11:54:50PM +1000, David Gibson wrote:
> > On Tue, Oct 01, 2013 at 03:54:20PM -0500, Rob Herring wrote:
> 
> > > I would expect the schema to replace
> > > Documentation/devicetree/bindings/* over time. I think the thing that
> > > needs to be worked out here is how to add free form multi-line text.
> 
> > I'm not convinced that's a realistic goal.  As I see it, the
> > fundamental difference between a binding document and a formal schema
> > is that a binding defines both the syntax required of a node, and its
> > semantics, whereas a schema defines only syntax - the semantics still
> > need to be defined somewhere.
> 
> So long as the schema lets you include free form text to define the
> semantics I'm not sure there's an incompatibility there - the same
> document can cover both.

True, there's no reason the machine-readable schema and human-readable
documentation can't be contained in the same file.

-- 
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-02 13:54                 ` David Gibson
  2013-10-02 18:08                   ` Mark Brown
@ 2013-10-03  6:52                   ` Benoit Cousson
  1 sibling, 0 replies; 36+ messages in thread
From: Benoit Cousson @ 2013-10-03  6:52 UTC (permalink / raw)
  To: David Gibson
  Cc: Rob Herring, Mark Rutland, Stephen Warren, Pawel Moll,
	Ian Campbell, Olof Johansson, devicetree@vger.kernel.org,
	Tomasz Figa, Grant Likely, Kevin Hilman, linux-omap,
	linux-arm-kernel@lists.infradead.org, fparent

On 02/10/2013 15:54, David Gibson wrote:
> On Tue, Oct 01, 2013 at 03:54:20PM -0500, Rob Herring wrote:
>> On Tue, Oct 1, 2013 at 10:06 AM, Benoit Cousson <bcousson@baylibre.com> wrote:
>>> Hi Rob,
>>>
>>>
>>> On 01/10/2013 15:17, Rob Herring wrote:
>>>>
>>>> On 10/01/2013 03:06 AM, Benoit Cousson wrote:
>>>>>
>>>>> + 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 for taking this on!
>>>>
>>>> This is interesting approach using the dts syntax,
>>>
>>>
>>> Well, this was discussed a little bit on the list, and it has the big
>>> advantage of re-using the parser already included in DTC for free.
>>> In term or readability, it avoids to re-defining a brand new syntax for
>>> people who are already familiar with the DTS one.
>>>
>>>
>>>> but I worry that the
>>>> validation will only be as good as the schema written and the review of
>>>> the schema.
>>>
>>>
>>> Well, sure, but unfortunately, that will always be the case :-(
>>> The bindings definition being quite open, there is no easy way to ensure
>>> proper schema / bindings without careful review of the schema. There is no
>>> such thing as a free beer... Unfortunately :-)
>>>
>>>
>>>> I think the schema needs to define the binding rather than
>>>> define the checks. Then the schema can feed the validation checks.
>>>
>>>
>>>> This format does not seem to me as easily being able to generate
>>>> documentation from the schema which I believe is one of the goals.
>>>
>>>
>>> Indeed, but I think is it easy to generate any kind of readable format for
>>> the documentation purpose if needed from the actual format.
>>> Otherwise, we should consider a schema format based on kerneldoc type of
>>> syntax to improve readability. I'm just afraid it will become harder then to
>>> define complex schema.
>>>
>>> BTW, what kind of documentation are you expecting here? Is is a text that
>>> can be added on top of each schema?
>>
>> I would expect the schema to replace
>> Documentation/devicetree/bindings/* over time. I think the thing that
>> needs to be worked out here is how to add free form multi-line text.
>
> I'm not convinced that's a realistic goal.  As I see it, the
> fundamental difference between a binding document and a formal schema
> is that a binding defines both the syntax required of a node, and its
> semantics, whereas a schema defines only syntax - the semantics still
> need to be defined somewhere.
>

Mmm, I do not really understand what is missing in the following schema 
in term of semantic compared to the original interrupt-controller bindings?

     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>;
     };

As soon as you have a description you can keep the content of the 
original binding. But on top of that, you do have the schema validation 
information.

I'm not sure to understand your point. Could you elaborate?

Regards,
Benoit

^ 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

* Re: [RFC 00/15] Device Tree schemas and validation
       [not found]         ` <20131002142914.GI6506-RXTfZT5YzpxwFLYp8hBm2A@public.gmane.org>
@ 2013-10-03 13:53           ` Benoit Cousson
  2013-10-06  3:02             ` Chaiken, Alison
  0 siblings, 1 reply; 36+ messages in thread
From: Benoit Cousson @ 2013-10-03 13:53 UTC (permalink / raw)
  To: David Gibson
  Cc: Stephen Warren, 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

Hi David,

On 02/10/2013 16:29, David Gibson wrote:
> 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.

Yeah, that's a general concern that Stephen raised several time as well.
We need to figure out some way to handle that.

>>>   * 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.

OK, so would you suggest keeping mapping between node / attribute in DTS 
and in the schema?

>>> 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.

That seems to be well aligned with what we tried to achieve, so I'm not 
considering that as a counter-proposal but as a refinement. :-)

> 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.

OK, make sense. Are you considering a syntax similar to xpath in order 
to match any node in the path, using the full path information instead 
of the individual node?

I'm a little bit rusty on xpath but AFAIR it could be something like that.

match any node containing reg:

"//reg/.."

match only node containing reg for ti,omap4-gpio compatible

"//*[@compatible='ti,omap4-gpio']/reg/.."

match only node containing reg below the ocp parent node

"//ocp/*/reg/.."


> 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"
>

That's part is similar to what we had in mind. So we just need to find 
how to express it properly using the DTS syntax.

Thanks,
Benoit

--
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

* Re: [RFC 01/15] scripts/dtc: fix most memory leaks in dtc
       [not found]       ` <CAOwMV_zAZG3vvWS6pkyK-FbOEg_32KRO-k1SmFSh-pc9+0JiPA@mail.gmail.com>
@ 2013-10-03 14:26         ` Fabien Parent
  0 siblings, 0 replies; 36+ messages in thread
From: Fabien Parent @ 2013-10-03 14:26 UTC (permalink / raw)
  Cc: devicetree, linux-omap, linux-arm-kernel

Looping back the mailing-lists.

On Thu, Oct 3, 2013 at 4:23 PM, Fabien Parent <fparent@baylibre.com> wrote:
>
> Hi David,
>
>
> On Wed, Oct 2, 2013 at 2:59 PM, David Gibson <david@gibson.dropbear.id.au> wrote:
>>
>> On Tue, Sep 24, 2013 at 06:52:07PM +0200, Benoit Cousson wrote:
>> > From: Fabien Parent <fparent@baylibre.com>
>>
>> As noted elsewhere, please write patches against upstream dtc, not the
>> version in the kernel.  git://git.kernel.org/pub/scm/utils/dtc/dtc.git
>>
>> > 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.
>>
>> Hrm, yeah.  I'm aware that I haven't been very careful with memory
>> leaks within the parser.  Essentially, I've been treating the process
>> as a pool allocator with exactly one pool - I've even considered
>> getting rid of those free()s we do have.
>>
>> If the parser's going to be invoked repeatedly, then, yes, that
>> certainly needs fixing.  Whether individually fixing each leak or
>> using a explicit pool allocator is a better option is less clear.
>
>
> I've chosen the path of using free()s since it was removing most (all?) memory leaks from
> the parser and wasn't adding much more complexity to it. I don't think a pool allocator would
> be useful to DTC in its current state, but it's true that with schemas which are using
> the DTS syntax it could make a lot of sense to switch to a pool allocator.
>
> I guess I will wait until the discussion about this proposal has progressed and see
> whether this patch should be rewritten using a pool allocator or not.
>
>>
>> > 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.
>>
>> This is no good.  Making this assumption is a layering violation - if
>> the parser was changed so that this literal wasn't converted until
>> after another token was read, the yytext value copied in here would no
>> longer be valid and would break horribly.
>>
>
> Right, I've been lazy on this one and I took the easy road.
>
>
>>
>> >
>> > 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) {
>>
>> Rather hard to read version of safe-against-free list iteration.
>>
>
> Agreed.
>
>>
>> > +             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)
>>
>> *n->name .. so, the name can (and must) be statically allocated if
>> it's exactly "".  Not a useful optimization, I think.
>
>
> True.
>
>>
>>
>> > +             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);
>> > +}
>>
>> --
>> 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
>
>

^ permalink raw reply	[flat|nested] 36+ messages in thread

* RE: [RFC 00/15] Device Tree schemas and validation
  2013-10-03 13:53           ` Benoit Cousson
@ 2013-10-06  3:02             ` Chaiken, Alison
  0 siblings, 0 replies; 36+ messages in thread
From: Chaiken, Alison @ 2013-10-06  3:02 UTC (permalink / raw)
  To: Benoit Cousson, David Gibson
  Cc: Stephen Warren, olof@lixom.net, devicetree@vger.kernel.org,
	tomasz.figa@gmail.com, grant.likely@secretlab.ca,
	rob.herring@calxeda.com, khilman@linaro.org,
	linux-omap@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
	fparent@baylibre.com

Rob Herring in devicetree/msg06598.html
> This is interesting approach using the dts syntax,

Benoit Cousson in devicetree/msg06617.html
> it has the big advantage of re-using the parser already included in DTC for
> free. In term or readability, it avoids to re-defining a brand new syntax for
> people who are already familiar with the DTS one.

Stephen Warren wrote in devicetree/msg06676.html:
> DT is a language for representing data.
> The validation checks described by schemas are rules, or code, and not static
> data.

The syntax of the existing device-tree source is strikingly similar to that of
the widely used JavaScript Object Notation, better known as JSON.  JSON has many
parsers, validators and schemata already in existence.  Assuredly as many coders
know how to program JSON as know C.

JSON makes some sense for representation of device-trees, because, as the
authoritative json.org explains, "JSON is a text format that is completely
language independent but uses conventions that are familiar to programmers of
the C-family of languages . . . JSON is a natural representation of data for the
C family of programming languages."

Benoit Cousson remarks in devicetree/msg06617.html:
> The bindings definition being quite open, there is no easy way to
> ensure proper schema / bindings without careful review of the
> schema.

Stephen Warren continues in devicetree/msg06676.html:
> Overall, I believe perhaps the single most important aspect of any DT
> schema is schema inheritance or instancing,

David Gibson comments in devicetree/msg06725.html:
> 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.

I violently agree with Stephen and David and believe that inheritance
offers a partial solution to the problem Benoit describes.  What about
improving compliance by explicitly making use of inheritance with
device-tree include files?  Suppose we consider supplementing the ARM
tree's skeleton.dtsi tree-root with board.dtsi, cpu.dtsi,
daughtercard.dtsi . . .  Suppose then we require board-level dts files
to include board.dtsi, and furthermore that the CPU node for the board
to be described in a DTSI file that must itself include cpu.dtsi.
Then the dtc itself could in effect check perform some constraint
checking.  Device vendors could offer <arch>.dtsi and <particular
chip>.dtsi that users of those products would be required to include.

A related question: what DTS files will a validator compare against a schema?
Assuredly given the existing ability of nodes and properties in a
hierarchy of include files to override and modify one another, the
post C-preprocessed and compiled single-file is the one wanted, that
is, the output from

	       $CC $CPP_FLAGS -o foo.tmp foo.dts
	       dtc -O dts -i arch/arm/boot/dts foo.tmp

Some other suggestions:

   Let's not make the documentation derived from schemata and DTS files
tree-structured.    Otherwise we end up with GNU info, ahem.

   Stephen Warren previously contributed a useful bindings checklist.  We should
try to roll that checklist into any validator.

Benoit promises in  devicetree/msg06617.html:
> Being the very first one, you might get a free beer... meaning there
> might be such thing as a free beer :-)

I'm presenting a talk about device-tree for Embedded Linux Conference
Europe, http://sched.co/17ozhPE, and hope that some of you come flame
me in person there.  If so, I will actually buy you a free beer, but
not until after the second seminar I must give that afternoon!

-- 
Alison Chaiken
Mentor Embedded Software Division
Fremont, CA
GMT-8

^ permalink raw reply	[flat|nested] 36+ messages in thread

end of thread, other threads:[~2013-10-06  3:02 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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
     [not found]   ` <1380041541-17529-2-git-send-email-bcousson-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
2013-10-02 12:59     ` David Gibson
     [not found]       ` <CAOwMV_zAZG3vvWS6pkyK-FbOEg_32KRO-k1SmFSh-pc9+0JiPA@mail.gmail.com>
2013-10-03 14:26         ` Fabien Parent
2013-09-24 16:52 ` [RFC 04/15] scripts/dtc: add procedure to handle dts errors Benoit Cousson
2013-09-24 16:52 ` [RFC 05/15] scripts/dtc: check type on properties Benoit Cousson
2013-09-24 16:52 ` [RFC 07/15] scripts/dtc: can inherit properties Benoit Cousson
     [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   ` [RFC 06/15] scripts/dtc: check for required properties Benoit Cousson
2013-09-24 16:52   ` [RFC 08/15] scripts/dtc: check array size Benoit Cousson
2013-09-24 16:52   ` [RFC 09/15] scripts/dtc: check value of properties 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
     [not found]     ` <524B4B20.4020002-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
2013-10-02 14:29       ` David Gibson
     [not found]         ` <20131002142914.GI6506-RXTfZT5YzpxwFLYp8hBm2A@public.gmane.org>
2013-10-03 13:53           ` Benoit Cousson
2013-10-06  3:02             ` Chaiken, Alison
2013-10-03 13:17     ` Benoit Cousson
2013-09-24 16:52 ` [RFC 11/15] scripts/dtc: check for children nodes Benoit Cousson
2013-09-24 16:52 ` [RFC 12/15] scripts/dtc: check constraints on parents Benoit Cousson
2013-09-24 16:52 ` [RFC 13/15] bindings: OMAP: add new schema files Benoit Cousson
2013-09-24 16:52 ` [RFC 14/15] scripts/dtc: validate dts against schema bindings 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
     [not found]   ` <524A8289.3050107-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
2013-10-01 13:17     ` Rob Herring
     [not found]       ` <524ACB76.1010001-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2013-10-01 15:06         ` Benoit Cousson
2013-10-01 15:17           ` Jon Loeliger
2013-10-02  8:24             ` David Gibson
2013-10-02  9:25             ` Benoit Cousson
     [not found]               ` <524BE66D.7060308-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
2013-10-02 13:22                 ` Jon Loeliger
     [not found]           ` <524AE4FB.4080906-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
2013-10-01 20:54             ` Rob Herring
     [not found]               ` <CAL_JsqJ31TGFJCSeSOqgee=OLVfSUTAYdF4nSn7X2DiCequVAw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2013-10-02 13:54                 ` David Gibson
2013-10-02 18:08                   ` Mark Brown
2013-10-02 23:38                     ` David Gibson
2013-10-03  6:52                   ` Benoit Cousson
2013-10-02 13:52         ` David Gibson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).