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 linux-omap" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html