[RFC 09/15] scripts/dtc: check value of properties

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

 




From: Fabien Parent <fparent@xxxxxxxxxxxx>

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@xxxxxxxxxxxx>
Signed-off-by: Benoit Cousson <bcousson@xxxxxxxxxxxx>
---
 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@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