Re: [RFC 00/15] Device Tree schemas and validation

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




+ 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


--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]
  Powered by Linux