From 53bf130b1cdd7f6262eedd5e1b224c18bf7f1498 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 12 Feb 2016 14:45:12 +0900 Subject: [PATCH 01/71] libfdt: simplify fdt_node_check_compatible() Because fdt_stringlist_contains() returns 1 or 0, fdt_node_check_compatible() can just return the inverted value. Signed-off-by: Masahiro Yamada Signed-off-by: David Gibson --- libfdt/fdt_ro.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/libfdt/fdt_ro.c b/libfdt/fdt_ro.c index e5b3136..50cce86 100644 --- a/libfdt/fdt_ro.c +++ b/libfdt/fdt_ro.c @@ -647,10 +647,8 @@ int fdt_node_check_compatible(const void *fdt, int nodeoffset, prop = fdt_getprop(fdt, nodeoffset, "compatible", &len); if (!prop) return len; - if (fdt_stringlist_contains(prop, len, compatible)) - return 0; - else - return 1; + + return !fdt_stringlist_contains(prop, len, compatible); } int fdt_node_offset_by_compatible(const void *fdt, int startoffset, From b0dbceafd49a421c493e2a6ed596a12ad840fc56 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 6 Mar 2016 20:12:46 -0700 Subject: [PATCH 02/71] Correct space-after-tab in libfdt.h There are a few places with a space before a tab in this file. Fix them. Signed-off-by: Simon Glass Signed-off-by: David Gibson --- libfdt/libfdt.h | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/libfdt/libfdt.h b/libfdt/libfdt.h index 78adb12..25311cb 100644 --- a/libfdt/libfdt.h +++ b/libfdt/libfdt.h @@ -174,15 +174,15 @@ int fdt_next_subnode(const void *fdt, int offset); #define fdt_get_header(fdt, field) \ (fdt32_to_cpu(((const struct fdt_header *)(fdt))->field)) -#define fdt_magic(fdt) (fdt_get_header(fdt, magic)) +#define fdt_magic(fdt) (fdt_get_header(fdt, magic)) #define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize)) #define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct)) #define fdt_off_dt_strings(fdt) (fdt_get_header(fdt, off_dt_strings)) #define fdt_off_mem_rsvmap(fdt) (fdt_get_header(fdt, off_mem_rsvmap)) #define fdt_version(fdt) (fdt_get_header(fdt, version)) -#define fdt_last_comp_version(fdt) (fdt_get_header(fdt, last_comp_version)) -#define fdt_boot_cpuid_phys(fdt) (fdt_get_header(fdt, boot_cpuid_phys)) -#define fdt_size_dt_strings(fdt) (fdt_get_header(fdt, size_dt_strings)) +#define fdt_last_comp_version(fdt) (fdt_get_header(fdt, last_comp_version)) +#define fdt_boot_cpuid_phys(fdt) (fdt_get_header(fdt, boot_cpuid_phys)) +#define fdt_size_dt_strings(fdt) (fdt_get_header(fdt, size_dt_strings)) #define fdt_size_dt_struct(fdt) (fdt_get_header(fdt, size_dt_struct)) #define __fdt_set_hdr(name) \ @@ -647,7 +647,7 @@ const char *fdt_get_alias(const void *fdt, const char *name); * 0, on success * buf contains the absolute path of the node at * nodeoffset, as a NUL-terminated string. - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag * -FDT_ERR_NOSPACE, the path of the given node is longer than (bufsize-1) * characters and will not fit in the given buffer. * -FDT_ERR_BADMAGIC, @@ -677,11 +677,10 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen); * structure from the start to nodeoffset. * * returns: - * structure block offset of the node at node offset's ancestor * of depth supernodedepth (>=0), on success - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag -* -FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of nodeoffset + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of nodeoffset * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, @@ -703,7 +702,7 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, * * returns: * depth of the node at nodeoffset (>=0), on success - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, @@ -726,7 +725,7 @@ int fdt_node_depth(const void *fdt, int nodeoffset); * returns: * structure block offset of the parent of the node at nodeoffset * (>=0), on success - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, @@ -766,7 +765,7 @@ int fdt_parent_offset(const void *fdt, int nodeoffset); * on success * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the * tree after startoffset - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, @@ -813,7 +812,7 @@ int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle); * 1, if the node has a 'compatible' property, but it does not list * the given string * -FDT_ERR_NOTFOUND, if the given node has no 'compatible' property - * -FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, @@ -850,7 +849,7 @@ int fdt_node_check_compatible(const void *fdt, int nodeoffset, * on success * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the * tree after startoffset - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, From 68d43cec125334f45bda39f819375072d4b4aea4 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 6 Mar 2016 20:12:47 -0700 Subject: [PATCH 03/71] Correct line lengths in libfdt.h There are a few lines that are over 80 columns. Fix these. Signed-off-by: Simon Glass Signed-off-by: David Gibson --- libfdt/libfdt.h | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/libfdt/libfdt.h b/libfdt/libfdt.h index 25311cb..2c7b4e8 100644 --- a/libfdt/libfdt.h +++ b/libfdt/libfdt.h @@ -318,8 +318,9 @@ int fdt_subnode_offset_namelen(const void *fdt, int parentoffset, * returns: * structure block offset of the requested subnode (>=0), on success * -FDT_ERR_NOTFOUND, if the requested subnode does not exist - * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE + * tag + * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, @@ -351,7 +352,8 @@ int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen); * address). * * returns: - * structure block offset of the node with the requested path (>=0), on success + * structure block offset of the node with the requested path (>=0), on + * success * -FDT_ERR_BADPATH, given path does not begin with '/' or is invalid * -FDT_ERR_NOTFOUND, if the requested node does not exist * -FDT_ERR_BADMAGIC, @@ -375,10 +377,12 @@ int fdt_path_offset(const void *fdt, const char *path); * * returns: * pointer to the node's name, on success - * If lenp is non-NULL, *lenp contains the length of that name (>=0) + * If lenp is non-NULL, *lenp contains the length of that name + * (>=0) * NULL, on error * if lenp is non-NULL *lenp contains an error code (<0): - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE + * tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, standard meanings @@ -490,7 +494,8 @@ const struct fdt_property *fdt_get_property_namelen(const void *fdt, * NULL, on error * if lenp is non-NULL, *lenp contains an error code (<0): * -FDT_ERR_NOTFOUND, node does not have named property - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE + * tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, @@ -575,7 +580,8 @@ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, * NULL, on error * if lenp is non-NULL, *lenp contains an error code (<0): * -FDT_ERR_NOTFOUND, node does not have named property - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE + * tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, @@ -680,7 +686,8 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen); * structure block offset of the node at node offset's ancestor * of depth supernodedepth (>=0), on success * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag - * -FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of nodeoffset + * -FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of + * nodeoffset * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, @@ -959,7 +966,8 @@ const char *fdt_stringlist_get(const void *fdt, int nodeoffset, * returns: * 0 <= n < FDT_MAX_NCELLS, on success * 2, if the node has no #address-cells property - * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid #address-cells property + * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid + * #address-cells property * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, @@ -979,7 +987,8 @@ int fdt_address_cells(const void *fdt, int nodeoffset); * returns: * 0 <= n < FDT_MAX_NCELLS, on success * 2, if the node has no #address-cells property - * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid #size-cells property + * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid + * #size-cells property * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, @@ -1603,9 +1612,11 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset, * change the offsets of some existing nodes. * returns: - * structure block offset of the created nodeequested subnode (>=0), on success + * structure block offset of the created nodeequested subnode (>=0), on + * success * -FDT_ERR_NOTFOUND, if the requested subnode does not exist - * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag + * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE + * tag * -FDT_ERR_EXISTS, if the node at parentoffset already has a subnode of * the given name * -FDT_ERR_NOSPACE, if there is insufficient free space in the From beef80b8b55f32e5d3338ac13429382336e38ead Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 6 Mar 2016 20:12:48 -0700 Subject: [PATCH 04/71] Correct a missing space in a fdt_header cast The code style here is slightly incorrect. Fix it. Signed-off-by: Simon Glass Signed-off-by: David Gibson --- libfdt/libfdt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libfdt/libfdt.h b/libfdt/libfdt.h index 2c7b4e8..36222fd 100644 --- a/libfdt/libfdt.h +++ b/libfdt/libfdt.h @@ -188,7 +188,7 @@ int fdt_next_subnode(const void *fdt, int offset); #define __fdt_set_hdr(name) \ static inline void fdt_set_##name(void *fdt, uint32_t val) \ { \ - struct fdt_header *fdth = (struct fdt_header*)fdt; \ + struct fdt_header *fdth = (struct fdt_header *)fdt; \ fdth->name = cpu_to_fdt32(val); \ } __fdt_set_hdr(magic); From 9dc404958e9c91f33f75450f69b690a5e676af04 Mon Sep 17 00:00:00 2001 From: Pantelis Antoniou Date: Tue, 24 May 2016 20:50:35 +0300 Subject: [PATCH 05/71] util: Add xasprintf portable asprintf variant Include a portable asprintf variant that works on any C99 conforming platform. Signed-off-by: Pantelis Antoniou Signed-off-by: David Gibson --- util.c | 30 ++++++++++++++++++++++++++++++ util.h | 1 + 2 files changed, 31 insertions(+) diff --git a/util.c b/util.c index fb124ee..3550f86 100644 --- a/util.c +++ b/util.c @@ -46,6 +46,36 @@ char *xstrdup(const char *s) return d; } +/* based in part from (3) vsnprintf */ +int xasprintf(char **strp, const char *fmt, ...) +{ + int n, size = 128; /* start with 128 bytes */ + char *p; + va_list ap; + + /* initial pointer is NULL making the fist realloc to be malloc */ + p = NULL; + while (1) { + p = xrealloc(p, size); + + /* Try to print in the allocated space. */ + va_start(ap, fmt); + n = vsnprintf(p, size, fmt, ap); + va_end(ap); + + /* If that worked, return the string. */ + if (n > -1 && n < size) + break; + /* Else try again with more space. */ + if (n > -1) /* glibc 2.1 */ + size = n + 1; /* precisely what is needed */ + else /* glibc 2.0 */ + size *= 2; /* twice the old size */ + } + *strp = p; + return strlen(p); +} + char *join_path(const char *path, const char *name) { int lenp = strlen(path); diff --git a/util.h b/util.h index f800b60..f5c4f1b 100644 --- a/util.h +++ b/util.h @@ -59,6 +59,7 @@ static inline void *xrealloc(void *p, size_t len) } extern char *xstrdup(const char *s); +extern int xasprintf(char **strp, const char *fmt, ...); extern char *join_path(const char *path, const char *name); /** From d71d25d76012896521f937bf0c69f27b1a37cdc2 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 25 May 2016 15:15:36 +1000 Subject: [PATCH 06/71] Use xasprintf() in srcpos Now that we have an xasprintf() helper function, use it to simplify the srcpos_string() implementation. Signed-off-by: David Gibson --- srcpos.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/srcpos.c b/srcpos.c index f534c22..af7fb3c 100644 --- a/srcpos.c +++ b/srcpos.c @@ -266,26 +266,22 @@ srcpos_string(struct srcpos *pos) { const char *fname = ""; char *pos_str; - int rc; if (pos) fname = pos->file->name; if (pos->first_line != pos->last_line) - rc = asprintf(&pos_str, "%s:%d.%d-%d.%d", fname, - pos->first_line, pos->first_column, - pos->last_line, pos->last_column); + xasprintf(&pos_str, "%s:%d.%d-%d.%d", fname, + pos->first_line, pos->first_column, + pos->last_line, pos->last_column); else if (pos->first_column != pos->last_column) - rc = asprintf(&pos_str, "%s:%d.%d-%d", fname, - pos->first_line, pos->first_column, - pos->last_column); + xasprintf(&pos_str, "%s:%d.%d-%d", fname, + pos->first_line, pos->first_column, + pos->last_column); else - rc = asprintf(&pos_str, "%s:%d.%d", fname, - pos->first_line, pos->first_column); - - if (rc == -1) - die("Couldn't allocate in srcpos string"); + xasprintf(&pos_str, "%s:%d.%d", fname, + pos->first_line, pos->first_column); return pos_str; } From c4cb12e193e314226991deb468c1b397296dea53 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Mon, 2 Jun 2014 15:23:40 +1000 Subject: [PATCH 07/71] Alter grammar to allow multiple /dts-v1/ tags This patch allows dtc to accept multiple /dts-v1/ tags (provided they're all at the beginning of the input), rather than giving a syntax error. This makes it more convenient to include one .dts file from another without having to be careful that the /dts-v1/ tag is in exactly one of them. We a couple of existing testcases to take advantage of this, which simplifies them slightly. Signed-off-by: David Gibson --- dtc-parser.y | 11 +++++++--- tests/test_tree1.dts | 44 ++++++++++++++++++++++++++++++++++++- tests/test_tree1_body.dtsi | 43 ------------------------------------ tests/test_tree1_delete.dts | 2 +- 4 files changed, 52 insertions(+), 48 deletions(-) delete mode 100644 tests/test_tree1_body.dtsi diff --git a/dtc-parser.y b/dtc-parser.y index 000873f..14aaf2e 100644 --- a/dtc-parser.y +++ b/dtc-parser.y @@ -101,13 +101,18 @@ extern bool treesource_error; %% sourcefile: - DT_V1 ';' memreserves devicetree + v1tag memreserves devicetree { - the_boot_info = build_boot_info($3, $4, - guess_boot_cpuid($4)); + the_boot_info = build_boot_info($2, $3, + guess_boot_cpuid($3)); } ; +v1tag: + DT_V1 ';' + | DT_V1 ';' v1tag + ; + memreserves: /* empty */ { diff --git a/tests/test_tree1.dts b/tests/test_tree1.dts index c7b170c..67ecfd0 100644 --- a/tests/test_tree1.dts +++ b/tests/test_tree1.dts @@ -1,3 +1,45 @@ /dts-v1/; -/include/ "test_tree1_body.dtsi" +/memreserve/ 0xdeadbeef00000000 0x100000; +/memreserve/ 123456789 010000; + +/ { + compatible = "test_tree1"; + prop-int = <0xdeadbeef>; + prop-int64 = /bits/ 64 <0xdeadbeef01abcdef>; + prop-str = "hello world"; + #address-cells = <1>; + #size-cells = <0>; + + subnode@1 { + compatible = "subnode1"; + reg = <1>; + prop-int = [deadbeef]; + + subsubnode { + compatible = "subsubnode1", "subsubnode"; + prop-int = <0xdeadbeef>; + }; + + ss1 { + }; + }; + + subnode@2 { + reg = <2>; + linux,phandle = <0x2000>; + prop-int = <123456789>; + #address-cells = <1>; + #size-cells = <0>; + + ssn0: subsubnode@0 { + reg = <0>; + phandle = <0x2001>; + compatible = "subsubnode2", "subsubnode"; + prop-int = <0726746425>; + }; + + ss2 { + }; + }; +}; diff --git a/tests/test_tree1_body.dtsi b/tests/test_tree1_body.dtsi deleted file mode 100644 index 24a5e1e..0000000 --- a/tests/test_tree1_body.dtsi +++ /dev/null @@ -1,43 +0,0 @@ -/memreserve/ 0xdeadbeef00000000 0x100000; -/memreserve/ 123456789 010000; - -/ { - compatible = "test_tree1"; - prop-int = <0xdeadbeef>; - prop-int64 = /bits/ 64 <0xdeadbeef01abcdef>; - prop-str = "hello world"; - #address-cells = <1>; - #size-cells = <0>; - - subnode@1 { - compatible = "subnode1"; - reg = <1>; - prop-int = [deadbeef]; - - subsubnode { - compatible = "subsubnode1", "subsubnode"; - prop-int = <0xdeadbeef>; - }; - - ss1 { - }; - }; - - subnode@2 { - reg = <2>; - linux,phandle = <0x2000>; - prop-int = <123456789>; - #address-cells = <1>; - #size-cells = <0>; - - ssn0: subsubnode@0 { - reg = <0>; - phandle = <0x2001>; - compatible = "subsubnode2", "subsubnode"; - prop-int = <0726746425>; - }; - - ss2 { - }; - }; -}; diff --git a/tests/test_tree1_delete.dts b/tests/test_tree1_delete.dts index a2f1bfd..b95ef1e 100644 --- a/tests/test_tree1_delete.dts +++ b/tests/test_tree1_delete.dts @@ -1,6 +1,6 @@ /dts-v1/; -/include/ "test_tree1_body.dtsi" +/include/ "test_tree1.dts" / { nonexistant-property = <0xdeadbeef>; From 2e709d158e11f0adf897d2eb8cd1fd7a145a4c1f Mon Sep 17 00:00:00 2001 From: David Gibson Date: Sun, 27 Oct 2013 19:18:06 +1100 Subject: [PATCH 08/71] Remove tree check functions The tree check functions from the checking infrastructure aren't very useful. There were only two examples using them, and they're basically equivalent to a node check which is applied only to the root node, so those are easily replaced. Signed-off-by: David Gibson --- checks.c | 67 ++++++++++++++++++++++++++------------------------------ 1 file changed, 31 insertions(+), 36 deletions(-) diff --git a/checks.c b/checks.c index 386f956..6026884 100644 --- a/checks.c +++ b/checks.c @@ -40,14 +40,12 @@ enum checkstatus { struct check; -typedef void (*tree_check_fn)(struct check *c, struct node *dt); typedef void (*node_check_fn)(struct check *c, struct node *dt, struct node *node); typedef void (*prop_check_fn)(struct check *c, struct node *dt, struct node *node, struct property *prop); struct check { const char *name; - tree_check_fn tree_fn; node_check_fn node_fn; prop_check_fn prop_fn; void *data; @@ -58,11 +56,10 @@ struct check { struct check **prereq; }; -#define CHECK_ENTRY(nm, tfn, nfn, pfn, d, w, e, ...) \ +#define CHECK_ENTRY(nm, nfn, pfn, d, w, e, ...) \ static struct check *nm##_prereqs[] = { __VA_ARGS__ }; \ static struct check nm = { \ .name = #nm, \ - .tree_fn = (tfn), \ .node_fn = (nfn), \ .prop_fn = (pfn), \ .data = (d), \ @@ -72,31 +69,25 @@ struct check { .num_prereqs = ARRAY_SIZE(nm##_prereqs), \ .prereq = nm##_prereqs, \ }; -#define WARNING(nm, tfn, nfn, pfn, d, ...) \ - CHECK_ENTRY(nm, tfn, nfn, pfn, d, true, false, __VA_ARGS__) -#define ERROR(nm, tfn, nfn, pfn, d, ...) \ - CHECK_ENTRY(nm, tfn, nfn, pfn, d, false, true, __VA_ARGS__) -#define CHECK(nm, tfn, nfn, pfn, d, ...) \ - CHECK_ENTRY(nm, tfn, nfn, pfn, d, false, false, __VA_ARGS__) +#define WARNING(nm, nfn, pfn, d, ...) \ + CHECK_ENTRY(nm, nfn, pfn, d, true, false, __VA_ARGS__) +#define ERROR(nm, nfn, pfn, d, ...) \ + CHECK_ENTRY(nm, nfn, pfn, d, false, true, __VA_ARGS__) +#define CHECK(nm, nfn, pfn, d, ...) \ + CHECK_ENTRY(nm, nfn, pfn, d, false, false, __VA_ARGS__) -#define TREE_WARNING(nm, d, ...) \ - WARNING(nm, check_##nm, NULL, NULL, d, __VA_ARGS__) -#define TREE_ERROR(nm, d, ...) \ - ERROR(nm, check_##nm, NULL, NULL, d, __VA_ARGS__) -#define TREE_CHECK(nm, d, ...) \ - CHECK(nm, check_##nm, NULL, NULL, d, __VA_ARGS__) #define NODE_WARNING(nm, d, ...) \ - WARNING(nm, NULL, check_##nm, NULL, d, __VA_ARGS__) + WARNING(nm, check_##nm, NULL, d, __VA_ARGS__) #define NODE_ERROR(nm, d, ...) \ - ERROR(nm, NULL, check_##nm, NULL, d, __VA_ARGS__) + ERROR(nm, check_##nm, NULL, d, __VA_ARGS__) #define NODE_CHECK(nm, d, ...) \ - CHECK(nm, NULL, check_##nm, NULL, d, __VA_ARGS__) + CHECK(nm, check_##nm, NULL, d, __VA_ARGS__) #define PROP_WARNING(nm, d, ...) \ - WARNING(nm, NULL, NULL, check_##nm, d, __VA_ARGS__) + WARNING(nm, NULL, check_##nm, d, __VA_ARGS__) #define PROP_ERROR(nm, d, ...) \ - ERROR(nm, NULL, NULL, check_##nm, d, __VA_ARGS__) + ERROR(nm, NULL, check_##nm, d, __VA_ARGS__) #define PROP_CHECK(nm, d, ...) \ - CHECK(nm, NULL, NULL, check_##nm, d, __VA_ARGS__) + CHECK(nm, NULL, check_##nm, d, __VA_ARGS__) #ifdef __GNUC__ static inline void check_msg(struct check *c, const char *fmt, ...) __attribute__((format (printf, 2, 3))); @@ -170,8 +161,6 @@ static bool run_check(struct check *c, struct node *dt) if (c->node_fn || c->prop_fn) check_nodes_props(c, dt, dt); - if (c->tree_fn) - c->tree_fn(c, dt); if (c->status == UNCHECKED) c->status = PASSED; @@ -189,11 +178,12 @@ out: */ /* A check which always fails, for testing purposes only */ -static inline void check_always_fail(struct check *c, struct node *dt) +static inline void check_always_fail(struct check *c, struct node *dt, + struct node *node) { FAIL(c, "always_fail check"); } -TREE_CHECK(always_fail, NULL); +NODE_CHECK(always_fail, NULL); static void check_is_string(struct check *c, struct node *root, struct node *node) @@ -210,9 +200,9 @@ static void check_is_string(struct check *c, struct node *root, propname, node->fullpath); } #define WARNING_IF_NOT_STRING(nm, propname) \ - WARNING(nm, NULL, check_is_string, NULL, (propname)) + WARNING(nm, check_is_string, NULL, (propname)) #define ERROR_IF_NOT_STRING(nm, propname) \ - ERROR(nm, NULL, check_is_string, NULL, (propname)) + ERROR(nm, check_is_string, NULL, (propname)) static void check_is_cell(struct check *c, struct node *root, struct node *node) @@ -229,9 +219,9 @@ static void check_is_cell(struct check *c, struct node *root, propname, node->fullpath); } #define WARNING_IF_NOT_CELL(nm, propname) \ - WARNING(nm, NULL, check_is_cell, NULL, (propname)) + WARNING(nm, check_is_cell, NULL, (propname)) #define ERROR_IF_NOT_CELL(nm, propname) \ - ERROR(nm, NULL, check_is_cell, NULL, (propname)) + ERROR(nm, check_is_cell, NULL, (propname)) /* * Structural check functions @@ -382,7 +372,7 @@ static void check_duplicate_label_prop(struct check *c, struct node *dt, for_each_marker_of_type(m, LABEL) check_duplicate_label(c, dt, m->ref, node, prop, m); } -ERROR(duplicate_label, NULL, check_duplicate_label_node, +ERROR(duplicate_label, check_duplicate_label_node, check_duplicate_label_prop, NULL); static void check_explicit_phandles(struct check *c, struct node *root, @@ -499,7 +489,7 @@ static void fixup_phandle_references(struct check *c, struct node *dt, *((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle); } } -ERROR(phandle_references, NULL, NULL, fixup_phandle_references, NULL, +ERROR(phandle_references, NULL, fixup_phandle_references, NULL, &duplicate_node_names, &explicit_phandles); static void fixup_path_references(struct check *c, struct node *dt, @@ -524,7 +514,7 @@ static void fixup_path_references(struct check *c, struct node *dt, strlen(path) + 1); } } -ERROR(path_references, NULL, NULL, fixup_path_references, NULL, +ERROR(path_references, NULL, fixup_path_references, NULL, &duplicate_node_names); /* @@ -554,7 +544,7 @@ static void fixup_addr_size_cells(struct check *c, struct node *dt, if (prop) node->size_cells = propval_cell(prop); } -WARNING(addr_size_cells, NULL, fixup_addr_size_cells, NULL, NULL, +WARNING(addr_size_cells, fixup_addr_size_cells, NULL, NULL, &address_cells_is_cell, &size_cells_is_cell); #define node_addr_cells(n) \ @@ -660,11 +650,16 @@ static void check_avoid_default_addr_size(struct check *c, struct node *dt, NODE_WARNING(avoid_default_addr_size, NULL, &addr_size_cells); static void check_obsolete_chosen_interrupt_controller(struct check *c, - struct node *dt) + struct node *dt, + struct node *node) { struct node *chosen; struct property *prop; + if (node != dt) + return; + + chosen = get_node_by_path(dt, "/chosen"); if (!chosen) return; @@ -674,7 +669,7 @@ static void check_obsolete_chosen_interrupt_controller(struct check *c, FAIL(c, "/chosen has obsolete \"interrupt-controller\" " "property"); } -TREE_WARNING(obsolete_chosen_interrupt_controller, NULL); +NODE_WARNING(obsolete_chosen_interrupt_controller, NULL); static struct check *check_table[] = { &duplicate_node_names, &duplicate_property_names, From 9d97527a8621bb6f4a8c18a523ebb05a2a9b3a7e Mon Sep 17 00:00:00 2001 From: David Gibson Date: Sun, 27 Oct 2013 22:23:45 +1100 Subject: [PATCH 09/71] Remove property check functions Property checking functions aren't particularly useful. They're used only in a handful of cases, and most of those really only check a small handful of specific properties. This patches converts the few cases to node check functions and removes property check functions entirely. Signed-off-by: David Gibson --- checks.c | 216 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 115 insertions(+), 101 deletions(-) diff --git a/checks.c b/checks.c index 6026884..40110a1 100644 --- a/checks.c +++ b/checks.c @@ -41,13 +41,10 @@ enum checkstatus { struct check; typedef void (*node_check_fn)(struct check *c, struct node *dt, struct node *node); -typedef void (*prop_check_fn)(struct check *c, struct node *dt, - struct node *node, struct property *prop); struct check { const char *name; node_check_fn node_fn; - prop_check_fn prop_fn; void *data; bool warn, error; enum checkstatus status; @@ -56,12 +53,11 @@ struct check { struct check **prereq; }; -#define CHECK_ENTRY(nm, nfn, pfn, d, w, e, ...) \ +#define CHECK_ENTRY(nm, nfn, d, w, e, ...) \ static struct check *nm##_prereqs[] = { __VA_ARGS__ }; \ static struct check nm = { \ .name = #nm, \ .node_fn = (nfn), \ - .prop_fn = (pfn), \ .data = (d), \ .warn = (w), \ .error = (e), \ @@ -69,25 +65,19 @@ struct check { .num_prereqs = ARRAY_SIZE(nm##_prereqs), \ .prereq = nm##_prereqs, \ }; -#define WARNING(nm, nfn, pfn, d, ...) \ - CHECK_ENTRY(nm, nfn, pfn, d, true, false, __VA_ARGS__) -#define ERROR(nm, nfn, pfn, d, ...) \ - CHECK_ENTRY(nm, nfn, pfn, d, false, true, __VA_ARGS__) -#define CHECK(nm, nfn, pfn, d, ...) \ - CHECK_ENTRY(nm, nfn, pfn, d, false, false, __VA_ARGS__) +#define WARNING(nm, nfn, d, ...) \ + CHECK_ENTRY(nm, nfn, d, true, false, __VA_ARGS__) +#define ERROR(nm, nfn, d, ...) \ + CHECK_ENTRY(nm, nfn, d, false, true, __VA_ARGS__) +#define CHECK(nm, nfn, d, ...) \ + CHECK_ENTRY(nm, nfn, d, false, false, __VA_ARGS__) #define NODE_WARNING(nm, d, ...) \ - WARNING(nm, check_##nm, NULL, d, __VA_ARGS__) + WARNING(nm, check_##nm, d, __VA_ARGS__) #define NODE_ERROR(nm, d, ...) \ - ERROR(nm, check_##nm, NULL, d, __VA_ARGS__) + ERROR(nm, check_##nm, d, __VA_ARGS__) #define NODE_CHECK(nm, d, ...) \ - CHECK(nm, check_##nm, NULL, d, __VA_ARGS__) -#define PROP_WARNING(nm, d, ...) \ - WARNING(nm, NULL, check_##nm, d, __VA_ARGS__) -#define PROP_ERROR(nm, d, ...) \ - ERROR(nm, NULL, check_##nm, d, __VA_ARGS__) -#define PROP_CHECK(nm, d, ...) \ - CHECK(nm, NULL, check_##nm, d, __VA_ARGS__) + CHECK(nm, check_##nm, d, __VA_ARGS__) #ifdef __GNUC__ static inline void check_msg(struct check *c, const char *fmt, ...) __attribute__((format (printf, 2, 3))); @@ -117,18 +107,11 @@ static inline void check_msg(struct check *c, const char *fmt, ...) static void check_nodes_props(struct check *c, struct node *dt, struct node *node) { struct node *child; - struct property *prop; TRACE(c, "%s", node->fullpath); if (c->node_fn) c->node_fn(c, dt, node); - if (c->prop_fn) - for_each_property(node, prop) { - TRACE(c, "%s\t'%s'", node->fullpath, prop->name); - c->prop_fn(c, dt, node, prop); - } - for_each_child(node, child) check_nodes_props(c, dt, child); } @@ -158,7 +141,7 @@ static bool run_check(struct check *c, struct node *dt) if (c->status != UNCHECKED) goto out; - if (c->node_fn || c->prop_fn) + if (c->node_fn) check_nodes_props(c, dt, dt); if (c->status == UNCHECKED) @@ -200,9 +183,9 @@ static void check_is_string(struct check *c, struct node *root, propname, node->fullpath); } #define WARNING_IF_NOT_STRING(nm, propname) \ - WARNING(nm, check_is_string, NULL, (propname)) + WARNING(nm, check_is_string, (propname)) #define ERROR_IF_NOT_STRING(nm, propname) \ - ERROR(nm, check_is_string, NULL, (propname)) + ERROR(nm, check_is_string, (propname)) static void check_is_cell(struct check *c, struct node *root, struct node *node) @@ -219,9 +202,9 @@ static void check_is_cell(struct check *c, struct node *root, propname, node->fullpath); } #define WARNING_IF_NOT_CELL(nm, propname) \ - WARNING(nm, check_is_cell, NULL, (propname)) + WARNING(nm, check_is_cell, (propname)) #define ERROR_IF_NOT_CELL(nm, propname) \ - ERROR(nm, check_is_cell, NULL, (propname)) + ERROR(nm, check_is_cell, (propname)) /* * Structural check functions @@ -309,15 +292,19 @@ static void check_unit_address_vs_reg(struct check *c, struct node *dt, NODE_WARNING(unit_address_vs_reg, NULL); static void check_property_name_chars(struct check *c, struct node *dt, - struct node *node, struct property *prop) + struct node *node) { - int n = strspn(prop->name, c->data); + struct property *prop; - if (n < strlen(prop->name)) - FAIL(c, "Bad character '%c' in property name \"%s\", node %s", - prop->name[n], prop->name, node->fullpath); + for_each_property(node, prop) { + int n = strspn(prop->name, c->data); + + if (n < strlen(prop->name)) + FAIL(c, "Bad character '%c' in property name \"%s\", node %s", + prop->name[n], prop->name, node->fullpath); + } } -PROP_ERROR(property_name_chars, PROPNODECHARS); +NODE_ERROR(property_name_chars, PROPNODECHARS); #define DESCLABEL_FMT "%s%s%s%s%s" #define DESCLABEL_ARGS(node,prop,mark) \ @@ -356,40 +343,38 @@ static void check_duplicate_label_node(struct check *c, struct node *dt, struct node *node) { struct label *l; + struct property *prop; for_each_label(node->labels, l) check_duplicate_label(c, dt, l->label, node, NULL, NULL); + + for_each_property(node, prop) { + struct marker *m = prop->val.markers; + + for_each_label(prop->labels, l) + check_duplicate_label(c, dt, l->label, node, prop, NULL); + + for_each_marker_of_type(m, LABEL) + check_duplicate_label(c, dt, m->ref, node, prop, m); + } } -static void check_duplicate_label_prop(struct check *c, struct node *dt, - struct node *node, struct property *prop) -{ - struct marker *m = prop->val.markers; - struct label *l; - - for_each_label(prop->labels, l) - check_duplicate_label(c, dt, l->label, node, prop, NULL); - - for_each_marker_of_type(m, LABEL) - check_duplicate_label(c, dt, m->ref, node, prop, m); -} -ERROR(duplicate_label, check_duplicate_label_node, - check_duplicate_label_prop, NULL); - -static void check_explicit_phandles(struct check *c, struct node *root, - struct node *node, struct property *prop) +ERROR(duplicate_label, check_duplicate_label_node, NULL); + +static cell_t check_phandle_prop(struct check *c, struct node *root, + struct node *node, const char *propname) { + struct property *prop; struct marker *m; - struct node *other; cell_t phandle; - if (!streq(prop->name, "phandle") - && !streq(prop->name, "linux,phandle")) - return; + prop = get_property(node, propname); + if (!prop) + return 0; if (prop->val.len != sizeof(cell_t)) { FAIL(c, "%s has bad length (%d) %s property", node->fullpath, prop->val.len, prop->name); - return; + return 0; } m = prop->val.markers; @@ -401,14 +386,13 @@ static void check_explicit_phandles(struct check *c, struct node *root, * by construction. */ { FAIL(c, "%s in %s is a reference to another node", prop->name, node->fullpath); - return; } /* But setting this node's phandle equal to its own * phandle is allowed - that means allocate a unique * phandle for this node, even if it's not otherwise * referenced. The value will be filled in later, so - * no further checking for now. */ - return; + * we treat it as having no phandle data for now. */ + return 0; } phandle = propval_cell(prop); @@ -416,12 +400,35 @@ static void check_explicit_phandles(struct check *c, struct node *root, if ((phandle == 0) || (phandle == -1)) { FAIL(c, "%s has bad value (0x%x) in %s property", node->fullpath, phandle, prop->name); - return; + return 0; } - if (node->phandle && (node->phandle != phandle)) - FAIL(c, "%s has %s property which replaces existing phandle information", - node->fullpath, prop->name); + return phandle; +} + +static void check_explicit_phandles(struct check *c, struct node *root, + struct node *node) +{ + struct node *other; + cell_t phandle, linux_phandle; + + /* Nothing should have assigned phandles yet */ + assert(!node->phandle); + + phandle = check_phandle_prop(c, root, node, "phandle"); + + linux_phandle = check_phandle_prop(c, root, node, "linux,phandle"); + + if (!phandle && !linux_phandle) + /* No valid phandles; nothing further to check */ + return; + + if (linux_phandle && phandle && (phandle != linux_phandle)) + FAIL(c, "%s has mismatching 'phandle' and 'linux,phandle'" + " properties", node->fullpath); + + if (linux_phandle && !phandle) + phandle = linux_phandle; other = get_node_by_phandle(root, phandle); if (other && (other != node)) { @@ -432,7 +439,7 @@ static void check_explicit_phandles(struct check *c, struct node *root, node->phandle = phandle; } -PROP_ERROR(explicit_phandles, NULL); +NODE_ERROR(explicit_phandles, NULL); static void check_name_properties(struct check *c, struct node *root, struct node *node) @@ -469,53 +476,60 @@ NODE_ERROR(name_properties, NULL, &name_is_string); */ static void fixup_phandle_references(struct check *c, struct node *dt, - struct node *node, struct property *prop) + struct node *node) { - struct marker *m = prop->val.markers; - struct node *refnode; - cell_t phandle; + struct property *prop; - for_each_marker_of_type(m, REF_PHANDLE) { - assert(m->offset + sizeof(cell_t) <= prop->val.len); + for_each_property(node, prop) { + struct marker *m = prop->val.markers; + struct node *refnode; + cell_t phandle; - refnode = get_node_by_ref(dt, m->ref); - if (! refnode) { - FAIL(c, "Reference to non-existent node or label \"%s\"\n", - m->ref); - continue; + for_each_marker_of_type(m, REF_PHANDLE) { + assert(m->offset + sizeof(cell_t) <= prop->val.len); + + refnode = get_node_by_ref(dt, m->ref); + if (! refnode) { + FAIL(c, "Reference to non-existent node or label \"%s\"\n", + m->ref); + continue; + } + + phandle = get_node_phandle(dt, refnode); + *((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle); } - - phandle = get_node_phandle(dt, refnode); - *((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle); } } -ERROR(phandle_references, NULL, fixup_phandle_references, NULL, +ERROR(phandle_references, fixup_phandle_references, NULL, &duplicate_node_names, &explicit_phandles); static void fixup_path_references(struct check *c, struct node *dt, - struct node *node, struct property *prop) + struct node *node) { - struct marker *m = prop->val.markers; - struct node *refnode; - char *path; + struct property *prop; - for_each_marker_of_type(m, REF_PATH) { - assert(m->offset <= prop->val.len); + for_each_property(node, prop) { + struct marker *m = prop->val.markers; + struct node *refnode; + char *path; - refnode = get_node_by_ref(dt, m->ref); - if (!refnode) { - FAIL(c, "Reference to non-existent node or label \"%s\"\n", - m->ref); - continue; + for_each_marker_of_type(m, REF_PATH) { + assert(m->offset <= prop->val.len); + + refnode = get_node_by_ref(dt, m->ref); + if (!refnode) { + FAIL(c, "Reference to non-existent node or label \"%s\"\n", + m->ref); + continue; + } + + path = refnode->fullpath; + prop->val = data_insert_at_marker(prop->val, m, path, + strlen(path) + 1); } - - path = refnode->fullpath; - prop->val = data_insert_at_marker(prop->val, m, path, - strlen(path) + 1); } } -ERROR(path_references, NULL, fixup_path_references, NULL, - &duplicate_node_names); +ERROR(path_references, fixup_path_references, NULL, &duplicate_node_names); /* * Semantic checks @@ -544,7 +558,7 @@ static void fixup_addr_size_cells(struct check *c, struct node *dt, if (prop) node->size_cells = propval_cell(prop); } -WARNING(addr_size_cells, fixup_addr_size_cells, NULL, NULL, +WARNING(addr_size_cells, fixup_addr_size_cells, NULL, &address_cells_is_cell, &size_cells_is_cell); #define node_addr_cells(n) \ From 1ee0ae24ea0985589364a755d33b0159a8b0eee1 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Fri, 1 Nov 2013 23:57:17 +1100 Subject: [PATCH 10/71] Simplify check field and macro names Now that "node" checks are the only type of checks, simplify some names accordingly. Signed-off-by: David Gibson --- checks.c | 78 ++++++++++++++++++++++++++------------------------------ 1 file changed, 36 insertions(+), 42 deletions(-) diff --git a/checks.c b/checks.c index 40110a1..0381c98 100644 --- a/checks.c +++ b/checks.c @@ -40,11 +40,11 @@ enum checkstatus { struct check; -typedef void (*node_check_fn)(struct check *c, struct node *dt, struct node *node); +typedef void (*check_fn)(struct check *c, struct node *dt, struct node *node); struct check { const char *name; - node_check_fn node_fn; + check_fn fn; void *data; bool warn, error; enum checkstatus status; @@ -53,31 +53,24 @@ struct check { struct check **prereq; }; -#define CHECK_ENTRY(nm, nfn, d, w, e, ...) \ - static struct check *nm##_prereqs[] = { __VA_ARGS__ }; \ - static struct check nm = { \ - .name = #nm, \ - .node_fn = (nfn), \ - .data = (d), \ - .warn = (w), \ - .error = (e), \ +#define CHECK_ENTRY(_nm, _fn, _d, _w, _e, ...) \ + static struct check *_nm##_prereqs[] = { __VA_ARGS__ }; \ + static struct check _nm = { \ + .name = #_nm, \ + .fn = (_fn), \ + .data = (_d), \ + .warn = (_w), \ + .error = (_e), \ .status = UNCHECKED, \ - .num_prereqs = ARRAY_SIZE(nm##_prereqs), \ - .prereq = nm##_prereqs, \ + .num_prereqs = ARRAY_SIZE(_nm##_prereqs), \ + .prereq = _nm##_prereqs, \ }; -#define WARNING(nm, nfn, d, ...) \ - CHECK_ENTRY(nm, nfn, d, true, false, __VA_ARGS__) -#define ERROR(nm, nfn, d, ...) \ - CHECK_ENTRY(nm, nfn, d, false, true, __VA_ARGS__) -#define CHECK(nm, nfn, d, ...) \ - CHECK_ENTRY(nm, nfn, d, false, false, __VA_ARGS__) - -#define NODE_WARNING(nm, d, ...) \ - WARNING(nm, check_##nm, d, __VA_ARGS__) -#define NODE_ERROR(nm, d, ...) \ - ERROR(nm, check_##nm, d, __VA_ARGS__) -#define NODE_CHECK(nm, d, ...) \ - CHECK(nm, check_##nm, d, __VA_ARGS__) +#define WARNING(_nm, _fn, _d, ...) \ + CHECK_ENTRY(_nm, _fn, _d, true, false, __VA_ARGS__) +#define ERROR(_nm, _fn, _d, ...) \ + CHECK_ENTRY(_nm, _fn, _d, false, true, __VA_ARGS__) +#define CHECK(_nm, _fn, _d, ...) \ + CHECK_ENTRY(_nm, _fn, _d, false, false, __VA_ARGS__) #ifdef __GNUC__ static inline void check_msg(struct check *c, const char *fmt, ...) __attribute__((format (printf, 2, 3))); @@ -109,8 +102,8 @@ static void check_nodes_props(struct check *c, struct node *dt, struct node *nod struct node *child; TRACE(c, "%s", node->fullpath); - if (c->node_fn) - c->node_fn(c, dt, node); + if (c->fn) + c->fn(c, dt, node); for_each_child(node, child) check_nodes_props(c, dt, child); @@ -141,8 +134,7 @@ static bool run_check(struct check *c, struct node *dt) if (c->status != UNCHECKED) goto out; - if (c->node_fn) - check_nodes_props(c, dt, dt); + check_nodes_props(c, dt, dt); if (c->status == UNCHECKED) c->status = PASSED; @@ -166,7 +158,7 @@ static inline void check_always_fail(struct check *c, struct node *dt, { FAIL(c, "always_fail check"); } -NODE_CHECK(always_fail, NULL); +CHECK(always_fail, check_always_fail, NULL); static void check_is_string(struct check *c, struct node *root, struct node *node) @@ -223,7 +215,7 @@ static void check_duplicate_node_names(struct check *c, struct node *dt, FAIL(c, "Duplicate node name %s", child->fullpath); } -NODE_ERROR(duplicate_node_names, NULL); +ERROR(duplicate_node_names, check_duplicate_node_names, NULL); static void check_duplicate_property_names(struct check *c, struct node *dt, struct node *node) @@ -240,7 +232,7 @@ static void check_duplicate_property_names(struct check *c, struct node *dt, } } } -NODE_ERROR(duplicate_property_names, NULL); +ERROR(duplicate_property_names, check_duplicate_property_names, NULL); #define LOWERCASE "abcdefghijklmnopqrstuvwxyz" #define UPPERCASE "ABCDEFGHIJKLMNOPQRSTUVWXYZ" @@ -256,7 +248,7 @@ static void check_node_name_chars(struct check *c, struct node *dt, FAIL(c, "Bad character '%c' in node %s", node->name[n], node->fullpath); } -NODE_ERROR(node_name_chars, PROPNODECHARS "@"); +ERROR(node_name_chars, check_node_name_chars, PROPNODECHARS "@"); static void check_node_name_format(struct check *c, struct node *dt, struct node *node) @@ -265,7 +257,7 @@ static void check_node_name_format(struct check *c, struct node *dt, FAIL(c, "Node %s has multiple '@' characters in name", node->fullpath); } -NODE_ERROR(node_name_format, NULL, &node_name_chars); +ERROR(node_name_format, check_node_name_format, NULL, &node_name_chars); static void check_unit_address_vs_reg(struct check *c, struct node *dt, struct node *node) @@ -289,7 +281,7 @@ static void check_unit_address_vs_reg(struct check *c, struct node *dt, node->fullpath); } } -NODE_WARNING(unit_address_vs_reg, NULL); +WARNING(unit_address_vs_reg, check_unit_address_vs_reg, NULL); static void check_property_name_chars(struct check *c, struct node *dt, struct node *node) @@ -304,7 +296,7 @@ static void check_property_name_chars(struct check *c, struct node *dt, prop->name[n], prop->name, node->fullpath); } } -NODE_ERROR(property_name_chars, PROPNODECHARS); +ERROR(property_name_chars, check_property_name_chars, PROPNODECHARS); #define DESCLABEL_FMT "%s%s%s%s%s" #define DESCLABEL_ARGS(node,prop,mark) \ @@ -439,7 +431,7 @@ static void check_explicit_phandles(struct check *c, struct node *root, node->phandle = phandle; } -NODE_ERROR(explicit_phandles, NULL); +ERROR(explicit_phandles, check_explicit_phandles, NULL); static void check_name_properties(struct check *c, struct node *root, struct node *node) @@ -469,7 +461,7 @@ static void check_name_properties(struct check *c, struct node *root, } } ERROR_IF_NOT_STRING(name_is_string, "name"); -NODE_ERROR(name_properties, NULL, &name_is_string); +ERROR(name_properties, check_name_properties, NULL, &name_is_string); /* * Reference fixup functions @@ -593,7 +585,7 @@ static void check_reg_format(struct check *c, struct node *dt, "(#address-cells == %d, #size-cells == %d)", node->fullpath, prop->val.len, addr_cells, size_cells); } -NODE_WARNING(reg_format, NULL, &addr_size_cells); +WARNING(reg_format, check_reg_format, NULL, &addr_size_cells); static void check_ranges_format(struct check *c, struct node *dt, struct node *node) @@ -634,7 +626,7 @@ static void check_ranges_format(struct check *c, struct node *dt, p_addr_cells, c_addr_cells, c_size_cells); } } -NODE_WARNING(ranges_format, NULL, &addr_size_cells); +WARNING(ranges_format, check_ranges_format, NULL, &addr_size_cells); /* * Style checks @@ -661,7 +653,8 @@ static void check_avoid_default_addr_size(struct check *c, struct node *dt, FAIL(c, "Relying on default #size-cells value for %s", node->fullpath); } -NODE_WARNING(avoid_default_addr_size, NULL, &addr_size_cells); +WARNING(avoid_default_addr_size, check_avoid_default_addr_size, NULL, + &addr_size_cells); static void check_obsolete_chosen_interrupt_controller(struct check *c, struct node *dt, @@ -683,7 +676,8 @@ static void check_obsolete_chosen_interrupt_controller(struct check *c, FAIL(c, "/chosen has obsolete \"interrupt-controller\" " "property"); } -NODE_WARNING(obsolete_chosen_interrupt_controller, NULL); +WARNING(obsolete_chosen_interrupt_controller, + check_obsolete_chosen_interrupt_controller, NULL); static struct check *check_table[] = { &duplicate_node_names, &duplicate_property_names, From cb9241ae345378b7193b3d7c9621e8abe657faa6 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Dubois Date: Mon, 11 Jul 2016 00:16:52 +0200 Subject: [PATCH 11/71] DTC: Fix memory leak on flatname. If flatname was not referenced by the "node" structure, the reference to the allocated string is lost at function exit. We need to free it if is not used by "node". Signed-off-by: Jean-Christophe Dubois Signed-off-by: David Gibson --- flattree.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/flattree.c b/flattree.c index ec14954..089b976 100644 --- a/flattree.c +++ b/flattree.c @@ -797,6 +797,10 @@ static struct node *unflatten_tree(struct inbuf *dtbuf, } } while (val != FDT_END_NODE); + if (node->name != flatname) { + free(flatname); + } + return node; } From 44a59713cf0518382cb8fe705f59fd974a1ac030 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 13 Jul 2016 00:44:53 +1000 Subject: [PATCH 12/71] Remove unused srcpos_dump() function srcpos_dump() has no current users, and I have no plans to use it. So remove it. Signed-off-by: David Gibson --- srcpos.c | 15 --------------- srcpos.h | 1 - 2 files changed, 16 deletions(-) diff --git a/srcpos.c b/srcpos.c index af7fb3c..aa3aad0 100644 --- a/srcpos.c +++ b/srcpos.c @@ -246,21 +246,6 @@ srcpos_copy(struct srcpos *pos) return pos_new; } - - -void -srcpos_dump(struct srcpos *pos) -{ - printf("file : \"%s\"\n", - pos->file ? (char *) pos->file : ""); - printf("first_line : %d\n", pos->first_line); - printf("first_column: %d\n", pos->first_column); - printf("last_line : %d\n", pos->last_line); - printf("last_column : %d\n", pos->last_column); - printf("file : %s\n", pos->file->name); -} - - char * srcpos_string(struct srcpos *pos) { diff --git a/srcpos.h b/srcpos.h index f81827b..2cdfcd8 100644 --- a/srcpos.h +++ b/srcpos.h @@ -105,7 +105,6 @@ extern struct srcpos srcpos_empty; extern void srcpos_update(struct srcpos *pos, const char *text, int len); extern struct srcpos *srcpos_copy(struct srcpos *pos); extern char *srcpos_string(struct srcpos *pos); -extern void srcpos_dump(struct srcpos *pos); extern void srcpos_verror(struct srcpos *pos, const char *prefix, const char *fmt, va_list va) From e24d39a024e608476ffc896c5d02afa117a54cd7 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Dubois Date: Wed, 13 Jul 2016 02:31:13 +0200 Subject: [PATCH 13/71] fdtdump.c: make sure size_t argument to memchr is always unsigned. CID 132817 (#1 of 1): Integer overflowed argument (INTEGER_OVERFLOW) 15. overflow_sink: Overflowed or truncated value (or a value computed from an overflowed or truncated value) endp - p - 4L used as critical argument to function. Signed-off-by: Jean-Christophe Dubois Signed-off-by: David Gibson --- fdtdump.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/fdtdump.c b/fdtdump.c index 95a6a20..a9a2484 100644 --- a/fdtdump.c +++ b/fdtdump.c @@ -15,6 +15,8 @@ #include "util.h" +#define FDT_MAGIC_SIZE 4 + #define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1)) #define PALIGN(p, a) ((void *)(ALIGN((unsigned long)(p), (a)))) #define GET_CELL(p) (p += 4, *((const uint32_t *)(p-4))) @@ -188,15 +190,15 @@ int main(int argc, char *argv[]) /* try and locate an embedded fdt in a bigger blob */ if (scan) { - unsigned char smagic[4]; + unsigned char smagic[FDT_MAGIC_SIZE]; char *p = buf; char *endp = buf + len; fdt_set_magic(smagic, FDT_MAGIC); /* poor man's memmem */ - while (true) { - p = memchr(p, smagic[0], endp - p - 4); + while ((endp - p) >= FDT_MAGIC_SIZE) { + p = memchr(p, smagic[0], endp - p - FDT_MAGIC_SIZE); if (!p) break; if (fdt_magic(p) == FDT_MAGIC) { @@ -215,7 +217,7 @@ int main(int argc, char *argv[]) } ++p; } - if (!p) + if (!p || ((endp - p) < FDT_MAGIC_SIZE)) die("%s: could not locate fdt magic\n", file); printf("%s: found fdt at offset %#zx\n", file, p - buf); buf = p; From 1074ee54b63f85603e0fc91614eebda9d7409035 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Sun, 24 Jul 2016 00:50:30 +1000 Subject: [PATCH 14/71] convert-dtsv0-lexer.l: fix memory leak CID 132822 (#1 of 1): Resource leak (RESOURCE_LEAK) 9. leaked_storage: Variable newname going out of scope leaks the storage it points to Signed-off-by: Jean-Christophe Dubois [dwg: Removed unnecessary hunk] Signed-off-by: David Gibson --- convert-dtsv0-lexer.l | 2 ++ 1 file changed, 2 insertions(+) diff --git a/convert-dtsv0-lexer.l b/convert-dtsv0-lexer.l index 259e527..aa32dc8 100644 --- a/convert-dtsv0-lexer.l +++ b/convert-dtsv0-lexer.l @@ -223,6 +223,8 @@ static void convert_file(const char *fname) while(yylex()) ; + + free(newname); } int main(int argc, char *argv[]) From f79ddb83e18505b522700476e546591bae6a9d4f Mon Sep 17 00:00:00 2001 From: Jean-Christophe Dubois Date: Wed, 13 Jul 2016 00:36:08 +0200 Subject: [PATCH 15/71] fdtget.c: Fix memory leak CID 132823 (#1 of 1): Resource leak (RESOURCE_LEAK) 5. leaked_storage: Variable blob going out of scope leaks the storage it points to. Signed-off-by: Jean-Christophe Dubois Signed-off-by: David Gibson --- fdtget.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/fdtget.c b/fdtget.c index 4377419..fb9d0e1 100644 --- a/fdtget.c +++ b/fdtget.c @@ -266,14 +266,20 @@ static int do_fdtget(struct display_info *disp, const char *filename, continue; } else { report_error(arg[i], node); + free(blob); return -1; } } prop = args_per_step == 1 ? NULL : arg[i + 1]; - if (show_data_for_item(blob, disp, node, prop)) + if (show_data_for_item(blob, disp, node, prop)) { + free(blob); return -1; + } } + + free(blob); + return 0; } From c539075ba8ba61fffbf7e005ce2e834868a9e0ab Mon Sep 17 00:00:00 2001 From: Jean-Christophe Dubois Date: Wed, 13 Jul 2016 00:36:21 +0200 Subject: [PATCH 16/71] fdtput.c: Fix memory leak. CID 132821 (#1 of 1): Resource leak (RESOURCE_LEAK) 12. leaked_storage: Variable value going out of scope leaks the storage it points to. Signed-off-by: Jean-Christophe Dubois Signed-off-by: David Gibson --- fdtput.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fdtput.c b/fdtput.c index 9b15c53..db65e96 100644 --- a/fdtput.c +++ b/fdtput.c @@ -328,7 +328,7 @@ static int delete_node(char *blob, const char *node_name) static int do_fdtput(struct display_info *disp, const char *filename, char **arg, int arg_count) { - char *value; + char *value = NULL; char *blob; char *node; int len, ret = 0; @@ -374,6 +374,11 @@ static int do_fdtput(struct display_info *disp, const char *filename, } free(blob); + + if (value) { + free(value); + } + return ret; } From 902d0f0953d0074b329a2780a4b637fae0d776da Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 27 Jul 2016 14:55:53 +0200 Subject: [PATCH 17/71] libfdt: Add a subnodes iterator macro The fdt_for_each_subnode() iterator macro provided by this patch can be used to iterate over a device tree node's subnodes. At each iteration a loop variable will be set to the next subnode. Signed-off-by: Thierry Reding Signed-off-by: Maxime Ripard Signed-off-by: David Gibson --- libfdt/libfdt.h | 28 ++++++++++++++++++++++++++++ tests/subnode_iterate.c | 8 ++------ 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/libfdt/libfdt.h b/libfdt/libfdt.h index 36222fd..911e548 100644 --- a/libfdt/libfdt.h +++ b/libfdt/libfdt.h @@ -168,6 +168,34 @@ int fdt_first_subnode(const void *fdt, int offset); */ int fdt_next_subnode(const void *fdt, int offset); +/** + * fdt_for_each_subnode - iterate over all subnodes of a parent + * + * @node: child node (int, lvalue) + * @fdt: FDT blob (const void *) + * @parent: parent node (int) + * + * This is actually a wrapper around a for loop and would be used like so: + * + * fdt_for_each_subnode(node, fdt, parent) { + * Use node + * ... + * } + * + * if ((node < 0) && (node != -FDT_ERR_NOT_FOUND)) { + * Error handling + * } + * + * Note that this is implemented as a macro and @node is used as + * iterator in the loop. The parent variable be constant or even a + * literal. + * + */ +#define fdt_for_each_subnode(node, fdt, parent) \ + for (node = fdt_first_subnode(fdt, parent); \ + node >= 0; \ + node = fdt_next_subnode(fdt, node)) + /**********************************************************************/ /* General functions */ /**********************************************************************/ diff --git a/tests/subnode_iterate.c b/tests/subnode_iterate.c index b9f379d..0fb5c90 100644 --- a/tests/subnode_iterate.c +++ b/tests/subnode_iterate.c @@ -48,9 +48,7 @@ static void test_node(void *fdt, int parent_offset) subnodes = cpu_to_fdt32(*prop); count = 0; - for (offset = fdt_first_subnode(fdt, parent_offset); - offset >= 0; - offset = fdt_next_subnode(fdt, offset)) + fdt_for_each_subnode(offset, fdt, parent_offset) count++; if (count != subnodes) { @@ -65,9 +63,7 @@ static void check_fdt_next_subnode(void *fdt) int offset; int count = 0; - for (offset = fdt_first_subnode(fdt, 0); - offset >= 0; - offset = fdt_next_subnode(fdt, offset)) { + fdt_for_each_subnode(offset, fdt, 0) { test_node(fdt, offset); count++; } From d29126c90acb0d705d695b2be07162f38ee48d69 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 27 Jul 2016 14:55:54 +0200 Subject: [PATCH 18/71] libfdt: Add iterator over properties Implement a macro based on fdt_first_property_offset and fdt_next_property_offset that provides a convenience to iterate over all the properties of a given node. Signed-off-by: Maxime Ripard Acked-by: Simon Glass [dwg: Removed a stray trailing blank line] Signed-off-by: David Gibson --- libfdt/libfdt.h | 27 +++++++++++ tests/.gitignore | 1 + tests/Makefile.tests | 1 + tests/property_iterate.c | 97 ++++++++++++++++++++++++++++++++++++++ tests/property_iterate.dts | 23 +++++++++ tests/run_tests.sh | 3 ++ 6 files changed, 152 insertions(+) create mode 100644 tests/property_iterate.c create mode 100644 tests/property_iterate.dts diff --git a/libfdt/libfdt.h b/libfdt/libfdt.h index 911e548..be109a8 100644 --- a/libfdt/libfdt.h +++ b/libfdt/libfdt.h @@ -458,6 +458,33 @@ int fdt_first_property_offset(const void *fdt, int nodeoffset); */ int fdt_next_property_offset(const void *fdt, int offset); +/** + * fdt_for_each_property_offset - iterate over all properties of a node + * + * @property_offset: property offset (int, lvalue) + * @fdt: FDT blob (const void *) + * @node: node offset (int) + * + * This is actually a wrapper around a for loop and would be used like so: + * + * fdt_for_each_property_offset(property, fdt, node) { + * Use property + * ... + * } + * + * if ((property < 0) && (property != -FDT_ERR_NOT_FOUND)) { + * Error handling + * } + * + * Note that this is implemented as a macro and property is used as + * iterator in the loop. The node variable can be constant or even a + * literal. + */ +#define fdt_for_each_property_offset(property, fdt, node) \ + for (property = fdt_first_property_offset(fdt, node); \ + property >= 0; \ + property = fdt_next_property_offset(fdt, property)) + /** * fdt_get_property_by_offset - retrieve the property at a given offset * @fdt: pointer to the device tree blob diff --git a/tests/.gitignore b/tests/.gitignore index e4532da..fa4616b 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -40,6 +40,7 @@ tmp.* /path_offset /path_offset_aliases /phandle_format +/property_iterate /propname_escapes /references /root_node diff --git a/tests/Makefile.tests b/tests/Makefile.tests index f7c3a4b..196518c 100644 --- a/tests/Makefile.tests +++ b/tests/Makefile.tests @@ -23,6 +23,7 @@ LIB_TESTS_L = get_mem_rsv \ add_subnode_with_nops path_offset_aliases \ utilfdt_test \ integer-expressions \ + property_iterate \ subnode_iterate LIB_TESTS = $(LIB_TESTS_L:%=$(TESTS_PREFIX)%) diff --git a/tests/property_iterate.c b/tests/property_iterate.c new file mode 100644 index 0000000..0f3959c --- /dev/null +++ b/tests/property_iterate.c @@ -0,0 +1,97 @@ +/* + * libfdt - Flat Device Tree manipulation + * Tests that fdt_next_subnode() works as expected + * + * Copyright (C) 2013 Google, Inc + * + * Copyright (C) 2007 David Gibson, IBM Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include + +#include + +#include "tests.h" +#include "testdata.h" + +static void test_node(void *fdt, int parent_offset) +{ + fdt32_t properties; + const fdt32_t *prop; + int offset, property; + int count; + int len; + + /* + * This property indicates the number of properties in our + * test node to expect + */ + prop = fdt_getprop(fdt, parent_offset, "test-properties", &len); + if (!prop || len != sizeof(fdt32_t)) { + FAIL("Missing/invalid test-properties property at '%s'", + fdt_get_name(fdt, parent_offset, NULL)); + } + properties = cpu_to_fdt32(*prop); + + count = 0; + offset = fdt_first_subnode(fdt, parent_offset); + if (offset < 0) + FAIL("Missing test node\n"); + + fdt_for_each_property_offset(property, fdt, offset) + count++; + + if (count != properties) { + FAIL("Node '%s': Expected %d properties, got %d\n", + fdt_get_name(fdt, parent_offset, NULL), properties, + count); + } +} + +static void check_fdt_next_subnode(void *fdt) +{ + int offset; + int count = 0; + + fdt_for_each_subnode(offset, fdt, 0) { + test_node(fdt, offset); + count++; + } + + if (count != 2) + FAIL("Expected %d tests, got %d\n", 2, count); +} + +int main(int argc, char *argv[]) +{ + void *fdt; + + test_init(argc, argv); + if (argc != 2) + CONFIG("Usage: %s ", argv[0]); + + fdt = load_blob(argv[1]); + if (!fdt) + FAIL("No device tree available"); + + check_fdt_next_subnode(fdt); + + PASS(); +} diff --git a/tests/property_iterate.dts b/tests/property_iterate.dts new file mode 100644 index 0000000..e8f5f8f --- /dev/null +++ b/tests/property_iterate.dts @@ -0,0 +1,23 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <0>; + + test1 { + test-properties = <3>; + + test { + linux,phandle = <0x1>; + #address-cells = <1>; + #size-cells = <0>; + }; + }; + + test2 { + test-properties = <0>; + + test { + }; + }; +}; diff --git a/tests/run_tests.sh b/tests/run_tests.sh index 7eb9b3d..6a2662b 100755 --- a/tests/run_tests.sh +++ b/tests/run_tests.sh @@ -269,6 +269,9 @@ libfdt_tests () { run_dtc_test -I dts -O dtb -o subnode_iterate.dtb subnode_iterate.dts run_test subnode_iterate subnode_iterate.dtb + run_dtc_test -I dts -O dtb -o property_iterate.dtb property_iterate.dts + run_test property_iterate property_iterate.dtb + # Tests for behaviour on various sorts of corrupted trees run_test truncated_property From 84e0e1346c68ed85050177c0aef6bc365b77541d Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 27 Jul 2016 14:55:55 +0200 Subject: [PATCH 19/71] libfdt: Add max phandle retrieval function Add a function to retrieve the highest phandle in a given device tree. Acked-by: Simon Glass Reviewed-by: Stefan Agner Reviewed-by: David Gibson Signed-off-by: Maxime Ripard Signed-off-by: David Gibson --- libfdt/fdt_ro.c | 26 ++++++++++++++++++++++++++ libfdt/libfdt.h | 15 +++++++++++++++ tests/get_phandle.c | 6 ++++++ 3 files changed, 47 insertions(+) diff --git a/libfdt/fdt_ro.c b/libfdt/fdt_ro.c index 50cce86..0459098 100644 --- a/libfdt/fdt_ro.c +++ b/libfdt/fdt_ro.c @@ -88,6 +88,32 @@ static int _fdt_string_eq(const void *fdt, int stroffset, return (strlen(p) == len) && (memcmp(p, s, len) == 0); } +uint32_t fdt_get_max_phandle(const void *fdt) +{ + uint32_t max_phandle = 0; + int offset; + + for (offset = fdt_next_node(fdt, -1, NULL);; + offset = fdt_next_node(fdt, offset, NULL)) { + uint32_t phandle; + + if (offset == -FDT_ERR_NOTFOUND) + return max_phandle; + + if (offset < 0) + return (uint32_t)-1; + + phandle = fdt_get_phandle(fdt, offset); + if (phandle == (uint32_t)-1) + continue; + + if (phandle > max_phandle) + max_phandle = phandle; + } + + return 0; +} + int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) { FDT_CHECK_HEADER(fdt); diff --git a/libfdt/libfdt.h b/libfdt/libfdt.h index be109a8..06b84cc 100644 --- a/libfdt/libfdt.h +++ b/libfdt/libfdt.h @@ -286,6 +286,21 @@ int fdt_move(const void *fdt, void *buf, int bufsize); */ const char *fdt_string(const void *fdt, int stroffset); +/** + * fdt_get_max_phandle - retrieves the highest phandle in a tree + * @fdt: pointer to the device tree blob + * + * fdt_get_max_phandle retrieves the highest phandle in the given + * device tree. This will ignore badly formatted phandles, or phandles + * with a value of 0 or -1. + * + * returns: + * the highest phandle on success + * 0, if no phandle was found in the device tree + * -1, if an error occurred + */ +uint32_t fdt_get_max_phandle(const void *fdt); + /** * fdt_num_mem_rsv - retrieve the number of memory reserve map entries * @fdt: pointer to the device tree blob diff --git a/tests/get_phandle.c b/tests/get_phandle.c index 2079591..22bd7b8 100644 --- a/tests/get_phandle.c +++ b/tests/get_phandle.c @@ -44,6 +44,7 @@ static void check_phandle(void *fdt, const char *path, uint32_t checkhandle) int main(int argc, char *argv[]) { + uint32_t max; void *fdt; test_init(argc, argv); @@ -53,5 +54,10 @@ int main(int argc, char *argv[]) check_phandle(fdt, "/subnode@2", PHANDLE_1); check_phandle(fdt, "/subnode@2/subsubnode@0", PHANDLE_2); + max = fdt_get_max_phandle(fdt); + if (max != PHANDLE_2) + FAIL("fdt_get_max_phandle returned 0x%x instead of 0x%x\n", + max, PHANDLE_2); + PASS(); } From 3e9037aaad44de3008ad77e4549962473ed71c6d Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 27 Jul 2016 14:55:56 +0200 Subject: [PATCH 20/71] libfdt: Add fdt_getprop_namelen_w Add a function to retrieve a writeable property only by the first characters of its name. Reviewed-by: David Gibson Signed-off-by: Maxime Ripard Signed-off-by: David Gibson --- libfdt/libfdt.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libfdt/libfdt.h b/libfdt/libfdt.h index 06b84cc..0189350 100644 --- a/libfdt/libfdt.h +++ b/libfdt/libfdt.h @@ -629,6 +629,13 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset, */ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, const char *name, int namelen, int *lenp); +static inline void *fdt_getprop_namelen_w(void *fdt, int nodeoffset, + const char *name, int namelen, + int *lenp) +{ + return (void *)(uintptr_t)fdt_getprop_namelen(fdt, nodeoffset, name, + namelen, lenp); +} /** * fdt_getprop - retrieve the value of a given property From d877364e4a0f405ef24df7f4d50065c586207f5b Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 29 Jul 2016 11:55:48 +0200 Subject: [PATCH 21/71] libfdt: Add fdt_setprop_inplace_namelen_partial Add a function to modify inplace only a portion of a property.. This is especially useful when the property is an array of values, and you want to update one of them without changing the DT size. Acked-by: Simon Glass Reviewed-by: David Gibson Signed-off-by: Maxime Ripard [dwg: Remove unnecessary unsigned qualifier, correct a comment] Signed-off-by: David Gibson --- libfdt/fdt_wip.c | 31 ++++++++++++++++++++++++++----- libfdt/libfdt.h | 21 +++++++++++++++++++++ tests/setprop_inplace.c | 10 ++++++++++ tests/testdata.h | 3 +++ 4 files changed, 60 insertions(+), 5 deletions(-) diff --git a/libfdt/fdt_wip.c b/libfdt/fdt_wip.c index c5bbb68..6aaab39 100644 --- a/libfdt/fdt_wip.c +++ b/libfdt/fdt_wip.c @@ -55,21 +55,42 @@ #include "libfdt_internal.h" -int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, - const void *val, int len) +int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset, + const char *name, int namelen, + uint32_t idx, const void *val, + int len) { void *propval; int proplen; - propval = fdt_getprop_w(fdt, nodeoffset, name, &proplen); + propval = fdt_getprop_namelen_w(fdt, nodeoffset, name, namelen, + &proplen); + if (!propval) + return proplen; + + if (proplen < (len + idx)) + return -FDT_ERR_NOSPACE; + + memcpy((char *)propval + idx, val, len); + return 0; +} + +int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, + const void *val, int len) +{ + const void *propval; + int proplen; + + propval = fdt_getprop(fdt, nodeoffset, name, &proplen); if (! propval) return proplen; if (proplen != len) return -FDT_ERR_NOSPACE; - memcpy(propval, val, len); - return 0; + return fdt_setprop_inplace_namelen_partial(fdt, nodeoffset, name, + strlen(name), 0, + val, len); } static void _fdt_nop_region(void *start, int len) diff --git a/libfdt/libfdt.h b/libfdt/libfdt.h index 0189350..376e628 100644 --- a/libfdt/libfdt.h +++ b/libfdt/libfdt.h @@ -1079,6 +1079,27 @@ int fdt_size_cells(const void *fdt, int nodeoffset); /* Write-in-place functions */ /**********************************************************************/ +/** + * fdt_setprop_inplace_namelen_partial - change a property's value, + * but not its size + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @namelen: number of characters of name to consider + * @idx: index of the property to change in the array + * @val: pointer to data to replace the property value with + * @len: length of the property value + * + * Identical to fdt_setprop_inplace(), but modifies the given property + * starting from the given index, and using only the first characters + * of the name. It is useful when you want to manipulate only one value of + * an array and you have a string that doesn't end with \0. + */ +int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset, + const char *name, int namelen, + uint32_t idx, const void *val, + int len); + /** * fdt_setprop_inplace - change a property's value, but not its size * @fdt: pointer to the device tree blob diff --git a/tests/setprop_inplace.c b/tests/setprop_inplace.c index daef182..80447a0 100644 --- a/tests/setprop_inplace.c +++ b/tests/setprop_inplace.c @@ -83,5 +83,15 @@ int main(int argc, char *argv[]) strp = check_getprop(fdt, 0, "prop-str", xlen+1, xstr); verbose_printf("New string value is \"%s\"\n", strp); + err = fdt_setprop_inplace_namelen_partial(fdt, 0, "compatible", + strlen("compatible"), 4, + TEST_STRING_4_PARTIAL, + strlen(TEST_STRING_4_PARTIAL)); + if (err) + FAIL("Failed to set \"compatible\": %s\n", fdt_strerror(err)); + + check_getprop(fdt, 0, "compatible", strlen(TEST_STRING_4_RESULT) + 1, + TEST_STRING_4_RESULT); + PASS(); } diff --git a/tests/testdata.h b/tests/testdata.h index 576974d..3588778 100644 --- a/tests/testdata.h +++ b/tests/testdata.h @@ -21,6 +21,9 @@ #define TEST_STRING_2 "nastystring: \a\b\t\n\v\f\r\\\"" #define TEST_STRING_3 "\xde\xad\xbe\xef" +#define TEST_STRING_4_PARTIAL "foobar" +#define TEST_STRING_4_RESULT "testfoobar" + #define TEST_CHAR1 '\r' #define TEST_CHAR2 'b' #define TEST_CHAR3 '\0' From 36fd7331fb11276c09a6affc0d8cd4977f2fe100 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 22 Aug 2016 18:55:49 +0900 Subject: [PATCH 22/71] libfdt: simplify fdt_del_mem_rsv() The variable "err" is unneeded. Signed-off-by: Masahiro Yamada Signed-off-by: David Gibson --- libfdt/fdt_rw.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/libfdt/fdt_rw.c b/libfdt/fdt_rw.c index 8be02b1..2eed4f5 100644 --- a/libfdt/fdt_rw.c +++ b/libfdt/fdt_rw.c @@ -191,17 +191,13 @@ int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size) int fdt_del_mem_rsv(void *fdt, int n) { struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n); - int err; FDT_RW_CHECK_HEADER(fdt); if (n >= fdt_num_mem_rsv(fdt)) return -FDT_ERR_NOTFOUND; - err = _fdt_splice_mem_rsv(fdt, re, 1, 0); - if (err) - return err; - return 0; + return _fdt_splice_mem_rsv(fdt, re, 1, 0); } static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name, From 1ed45d40a137299671b8d0c924e87f9c080899d7 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Sat, 3 Sep 2016 16:28:07 +1000 Subject: [PATCH 23/71] dtc: Bump version to 1.4.2 Bump version in preparation for a new release. Signed-off-by: David Gibson --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 078ecf6..ee8e3b2 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ # VERSION = 1 PATCHLEVEL = 4 -SUBLEVEL = 1 +SUBLEVEL = 2 EXTRAVERSION = LOCAL_VERSION = CONFIG_LOCALVERSION = From ec02b34c05be04f249ffaaca4b666f5246877dea Mon Sep 17 00:00:00 2001 From: David Gibson Date: Sat, 3 Sep 2016 21:02:30 +1000 Subject: [PATCH 24/71] dtc: Makefile improvements for release uploading This has some fixes to the make dist target, and a new make kup target for maintainer convenience uploading new releases. Signed-off-by: David Gibson --- Makefile | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index ee8e3b2..32dcfcf 100644 --- a/Makefile +++ b/Makefile @@ -197,10 +197,26 @@ fdtget: $(FDTGET_OBJS) $(LIBFDT_archive) fdtput: $(FDTPUT_OBJS) $(LIBFDT_archive) dist: - git archive --format=tar --prefix=dtc-v$(dtc_version)/ HEAD \ - > ../dtc-v$(dtc_version).tar - cat ../dtc-v$(dtc_version).tar | \ - gzip -9 > ../dtc-v$(dtc_version).tgz + git archive --format=tar --prefix=dtc-$(dtc_version)/ HEAD \ + > ../dtc-$(dtc_version).tar + cat ../dtc-$(dtc_version).tar | \ + gzip -9 > ../dtc-$(dtc_version).tar.gz + +# +# Release signing and uploading +# This is for maintainer convenience, don't try this at home. +# +ifeq ($(MAINTAINER),y) +GPG = gpg2 +KUP = kup +KUPDIR = /pub/software/utils/dtc + +kup: dist + $(GPG) --detach-sign --armor -o ../dtc-$(dtc_version).tar.sign \ + ../dtc-$(dtc_version).tar + $(KUP) put ../dtc-$(dtc_version).tar.gz ../dtc-$(dtc_version).tar.sign \ + $(KUPDIR)/dtc-$(dtc_version).tar.gz +endif # # Testsuite rules From 874f40588d3eb7e406521117c6e24d5a3376a77e Mon Sep 17 00:00:00 2001 From: Tim Wang Date: Mon, 18 Jul 2016 15:56:53 +0800 Subject: [PATCH 25/71] Implement the -a option to pad dtb aligned There is one condition that need cat the dtb files into one dtb.img which can support several boards use same SoC platform. And the original dtb file size is not aligned to any base. This may cause "Synchronous Abort" when load from a unligned address on some SoC machine, such as ARM. So this patch implement the -a option to pad zero at the end of dtb files and make the dtb size aligned to . Then, the aligned dtbs can cat together and load without "Synchronous Abort". Signed-off-by: Tim Wang Signed-off-by: David Gibson --- dtc.c | 17 ++++++++++++++++- dtc.h | 1 + flattree.c | 17 +++++++++++++---- tests/run_tests.sh | 28 ++++++++++++++++++++++++++++ 4 files changed, 58 insertions(+), 5 deletions(-) diff --git a/dtc.c b/dtc.c index 5fa23c4..9dcf640 100644 --- a/dtc.c +++ b/dtc.c @@ -30,8 +30,14 @@ int quiet; /* Level of quietness */ int reservenum; /* Number of memory reservation slots */ int minsize; /* Minimum blob size */ int padsize; /* Additional padding to blob */ +int alignsize; /* Additional padding to blob accroding to the alignsize */ int phandle_format = PHANDLE_BOTH; /* Use linux,phandle or phandle properties */ +static int is_power_of_2(int x) +{ + return (x > 0) && ((x & (x - 1)) == 0); +} + static void fill_fullpaths(struct node *tree, const char *prefix) { struct node *child; @@ -53,7 +59,7 @@ static void fill_fullpaths(struct node *tree, const char *prefix) #define FDT_VERSION(version) _FDT_VERSION(version) #define _FDT_VERSION(version) #version static const char usage_synopsis[] = "dtc [options] "; -static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:fb:i:H:sW:E:hv"; +static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:a:fb:i:H:sW:E:hv"; static struct option const usage_long_opts[] = { {"quiet", no_argument, NULL, 'q'}, {"in-format", a_argument, NULL, 'I'}, @@ -64,6 +70,7 @@ static struct option const usage_long_opts[] = { {"reserve", a_argument, NULL, 'R'}, {"space", a_argument, NULL, 'S'}, {"pad", a_argument, NULL, 'p'}, + {"align", a_argument, NULL, 'a'}, {"boot-cpu", a_argument, NULL, 'b'}, {"force", no_argument, NULL, 'f'}, {"include", a_argument, NULL, 'i'}, @@ -91,6 +98,7 @@ static const char * const usage_opts_help[] = { "\n\tMake space for reserve map entries (for dtb and asm output)", "\n\tMake the blob at least long (extra space)", "\n\tAdd padding to the blob of long (extra space)", + "\n\tMake the blob align to the (extra space)", "\n\tSet the physical boot cpu", "\n\tTry to produce output even if the input tree has errors", "\n\tAdd a path to search for include files", @@ -169,6 +177,7 @@ int main(int argc, char *argv[]) reservenum = 0; minsize = 0; padsize = 0; + alignsize = 0; while ((opt = util_getopt_long()) != EOF) { switch (opt) { @@ -196,6 +205,12 @@ int main(int argc, char *argv[]) case 'p': padsize = strtol(optarg, NULL, 0); break; + case 'a': + alignsize = strtol(optarg, NULL, 0); + if (!is_power_of_2(alignsize)) + die("Invalid argument \"%d\" to -a option\n", + optarg); + break; case 'f': force = true; break; diff --git a/dtc.h b/dtc.h index 56212c8..32009bc 100644 --- a/dtc.h +++ b/dtc.h @@ -53,6 +53,7 @@ extern int quiet; /* Level of quietness */ extern int reservenum; /* Number of memory reservation slots */ extern int minsize; /* Minimum blob size */ extern int padsize; /* Additional padding to blob */ +extern int alignsize; /* Additional padding to blob accroding to the alignsize */ extern int phandle_format; /* Use linux,phandle or phandle properties */ #define PHANDLE_LEGACY 0x1 diff --git a/flattree.c b/flattree.c index 089b976..a9d9520 100644 --- a/flattree.c +++ b/flattree.c @@ -398,15 +398,22 @@ void dt_to_blob(FILE *f, struct boot_info *bi, int version) */ if (minsize > 0) { padlen = minsize - fdt32_to_cpu(fdt.totalsize); - if ((padlen < 0) && (quiet < 1)) - fprintf(stderr, - "Warning: blob size %d >= minimum size %d\n", - fdt32_to_cpu(fdt.totalsize), minsize); + if (padlen < 0) { + padlen = 0; + if (quiet < 1) + fprintf(stderr, + "Warning: blob size %d >= minimum size %d\n", + fdt32_to_cpu(fdt.totalsize), minsize); + } } if (padsize > 0) padlen = padsize; + if (alignsize > 0) + padlen = ALIGN(fdt32_to_cpu(fdt.totalsize) + padlen, alignsize) + - fdt32_to_cpu(fdt.totalsize); + if (padlen > 0) { int tsize = fdt32_to_cpu(fdt.totalsize); tsize += padlen; @@ -572,6 +579,8 @@ void dt_to_asm(FILE *f, struct boot_info *bi, int version) if (padsize > 0) { fprintf(f, "\t.space\t%d, 0\n", padsize); } + if (alignsize > 0) + asm_emit_align(f, alignsize); emit_label(f, symprefix, "blob_abs_end"); data_free(strbuf); diff --git a/tests/run_tests.sh b/tests/run_tests.sh index 6a2662b..a71909c 100755 --- a/tests/run_tests.sh +++ b/tests/run_tests.sh @@ -62,6 +62,11 @@ run_test () { base_run_test $VALGRIND $VGSUPP "./$@" } +run_local_test () { + printf "$*: " + base_run_test "$@" +} + run_sh_test () { printf "$*: " base_run_test sh "$@" @@ -110,6 +115,20 @@ run_wrap_error_test () { base_run_test wrap_error "$@" } +# $1: dtb file +# $2: align base +align_test () { + local size=`stat -c %s $1` + local mod=$(($size%$2)) + ( + if [ $mod -eq 0 ] ;then + PASS + else + FAIL + fi + ) +} + run_dtc_test () { printf "dtc $*: " base_run_test wrap_test $VALGRIND $DTC "$@" @@ -503,6 +522,15 @@ dtc_tests () { -o search_paths_b.dtb search_paths_b.dts run_dtc_test -I dts -O dtb -o search_paths_subdir.dtb \ search_dir_b/search_paths_subdir.dts + + # Check -a option + local alignbase=64 + # -p -a + run_dtc_test -O dtb -p 1000 -a $alignbase -o align0.dtb subnode_iterate.dts + run_local_test align_test align0.dtb alignbase + # -S -a + run_dtc_test -O dtb -S 1999 -a $alignbase -o align1.dtb subnode_iterate.dts + run_local_test align_test align1.dtb alignbase } cmp_tests () { From a34bb721caca10964cb7d22b9d9322b0424c9042 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 22 Sep 2016 14:42:42 +1000 Subject: [PATCH 26/71] dtc: Fix assorted problems in the testcases for the -a option We just added the -a option to allow padding of the output dtb's size to a specified alignment. Unfortunately the test cases for this had several bugs: * Didn't actually test anything since "alignbase" instead of $alignbase was passed to the checker function * Introduced an unnecessary run_local_test wrapper * Didn't provide very helpful output on failure * Only attempted to check one alignment value This patch fixes up these problems. Signed-off-by: David Gibson --- tests/run_tests.sh | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/tests/run_tests.sh b/tests/run_tests.sh index a71909c..f4b32e4 100755 --- a/tests/run_tests.sh +++ b/tests/run_tests.sh @@ -62,11 +62,6 @@ run_test () { base_run_test $VALGRIND $VGSUPP "./$@" } -run_local_test () { - printf "$*: " - base_run_test "$@" -} - run_sh_test () { printf "$*: " base_run_test sh "$@" @@ -117,14 +112,15 @@ run_wrap_error_test () { # $1: dtb file # $2: align base -align_test () { - local size=`stat -c %s $1` - local mod=$(($size%$2)) +check_align () { + shorten_echo "check_align $@: " + local size=$(stat -c %s "$1") + local align="$2" ( - if [ $mod -eq 0 ] ;then + if [ $(($size % $align)) -eq 0 ] ;then PASS else - FAIL + FAIL "Output size $size is not $align-byte aligned" fi ) } @@ -524,13 +520,14 @@ dtc_tests () { search_dir_b/search_paths_subdir.dts # Check -a option - local alignbase=64 - # -p -a - run_dtc_test -O dtb -p 1000 -a $alignbase -o align0.dtb subnode_iterate.dts - run_local_test align_test align0.dtb alignbase - # -S -a - run_dtc_test -O dtb -S 1999 -a $alignbase -o align1.dtb subnode_iterate.dts - run_local_test align_test align1.dtb alignbase + for align in 2 4 8 16 32 64; do + # -p -a + run_dtc_test -O dtb -p 1000 -a $align -o align0.dtb subnode_iterate.dts + check_align align0.dtb $align + # -S -a + run_dtc_test -O dtb -S 1999 -a $align -o align1.dtb subnode_iterate.dts + check_align align1.dtb $align + done } cmp_tests () { From 45fd440a956112c78dc3b602e3a618f22f495db2 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 26 Sep 2016 18:12:26 +0200 Subject: [PATCH 27/71] Fix some typing errors in libfdt.h and livetree.c Correct some typos discovered with the codespell utility. Signed-off-by: Thomas Huth Signed-off-by: David Gibson --- libfdt/libfdt.h | 4 ++-- livetree.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libfdt/libfdt.h b/libfdt/libfdt.h index 376e628..ecb11fc 100644 --- a/libfdt/libfdt.h +++ b/libfdt/libfdt.h @@ -61,7 +61,7 @@ #define FDT_ERR_NOTFOUND 1 /* FDT_ERR_NOTFOUND: The requested node or property does not exist */ #define FDT_ERR_EXISTS 2 - /* FDT_ERR_EXISTS: Attemped to create a node or property which + /* FDT_ERR_EXISTS: Attempted to create a node or property which * already exists */ #define FDT_ERR_NOSPACE 3 /* FDT_ERR_NOSPACE: Operation needed to expand the device @@ -700,7 +700,7 @@ const char *fdt_get_alias_namelen(const void *fdt, const char *name, int namelen); /** - * fdt_get_alias - retreive the path referenced by a given alias + * fdt_get_alias - retrieve the path referenced by a given alias * @fdt: pointer to the device tree blob * @name: name of the alias th look up * diff --git a/livetree.c b/livetree.c index e229b84..3dc7559 100644 --- a/livetree.c +++ b/livetree.c @@ -204,7 +204,7 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node) } } - /* if no collision occured, add child to the old node. */ + /* if no collision occurred, add child to the old node. */ if (new_child) add_child(old_node, new_child); } From 6d1832c9e64bc464d08c62bbd082ba06986476cb Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 28 Sep 2016 11:29:07 +1000 Subject: [PATCH 28/71] dtc: Remove "home page" link The supposed home page hasn't existed for some time. We don't really have anything else, so remove the link from the README. Signed-off-by: David Gibson --- README | 4 ---- 1 file changed, 4 deletions(-) diff --git a/README b/README index 979974a..f92008f 100644 --- a/README +++ b/README @@ -14,7 +14,3 @@ mailto:devicetree-compiler@vger.kernel.org Core device tree bindings are discussed on the devicetree-spec list: mailto:devicetree-spec@vger.kernel.org - -Home Page ---------- -http://devicetree.org/Device_Tree_Compiler From 4aa3a6f5e6d92179099d466422c450ebc12e5b1a Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 30 Sep 2016 15:57:14 +0200 Subject: [PATCH 29/71] libfdt: Add new errors for the overlay code Add a few new error codes to report the failure conditions we might encounter in the overlay application code: - FDT_ERR_BADOVERLAY, when an overlay cannot be parsed, even though its structure is correct - FDT_ERR_NOPHANDLES, when we ran out of available phandles and we cannot use a new phandle without either using an invalid one (-1 or 0), or one already used. Signed-off-by: Maxime Ripard Signed-off-by: David Gibson --- libfdt/fdt_strerror.c | 3 +++ libfdt/libfdt.h | 11 ++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/libfdt/fdt_strerror.c b/libfdt/fdt_strerror.c index e6c3cee..3cb357f 100644 --- a/libfdt/fdt_strerror.c +++ b/libfdt/fdt_strerror.c @@ -76,6 +76,9 @@ static struct fdt_errtabent fdt_errtable[] = { FDT_ERRTABENT(FDT_ERR_BADVERSION), FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE), FDT_ERRTABENT(FDT_ERR_BADLAYOUT), + FDT_ERRTABENT(FDT_ERR_BADOVERLAY), + FDT_ERRTABENT(FDT_ERR_BADOVERLAY), + FDT_ERRTABENT(FDT_ERR_NOPHANDLES), }; #define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0])) diff --git a/libfdt/libfdt.h b/libfdt/libfdt.h index ecb11fc..361cc6c 100644 --- a/libfdt/libfdt.h +++ b/libfdt/libfdt.h @@ -126,7 +126,16 @@ * value. For example: a property expected to contain a string list * is not NUL-terminated within the length of its value. */ -#define FDT_ERR_MAX 15 +#define FDT_ERR_BADOVERLAY 16 + /* FDT_ERR_BADOVERLAY: The device tree overlay, while + * correctly structured, cannot be applied due to some + * unexpected or missing value, property or node. */ + +#define FDT_ERR_NOPHANDLES 17 + /* FDT_ERR_NOPHANDLES: The device tree doesn't have any + * phandle available anymore without causing an overflow */ + +#define FDT_ERR_MAX 17 /**********************************************************************/ /* Low-level functions (you probably don't need these) */ From 39240cc865cfbd4aecf86e33a72156f7fc043df3 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 30 Sep 2016 15:57:15 +0200 Subject: [PATCH 30/71] libfdt: Extend the reach of FDT_ERR_BADPHANDLE So far, the BADPHANDLE error was only used for incorrect phandle values. Extend that meaning to an improperly formatted phandle property. Signed-off-by: Maxime Ripard Signed-off-by: David Gibson --- libfdt/libfdt.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libfdt/libfdt.h b/libfdt/libfdt.h index 361cc6c..d2e5e03 100644 --- a/libfdt/libfdt.h +++ b/libfdt/libfdt.h @@ -79,8 +79,10 @@ * (e.g. missing a leading / for a function which requires an * absolute path) */ #define FDT_ERR_BADPHANDLE 6 - /* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle - * value. phandle values of 0 and -1 are not permitted. */ + /* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle. + * This can be caused either by an invalid phandle property + * length, or the phandle value was either 0 or -1, which are + * not permitted. */ #define FDT_ERR_BADSTATE 7 /* FDT_ERR_BADSTATE: Function was passed an incomplete device * tree created by the sequential-write functions, which is From 0cdd06c5135bd9f46853c2f58ad2ac91b0fa87f3 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 30 Sep 2016 15:57:16 +0200 Subject: [PATCH 31/71] libfdt: Add overlay application function The device tree overlays are a good way to deal with user-modifyable boards or boards with some kind of an expansion mechanism where we can easily plug new board in (like the BBB, the Raspberry Pi or the CHIP). Add a new function to merge overlays with a base device tree. Signed-off-by: Maxime Ripard Signed-off-by: David Gibson --- libfdt/Makefile.libfdt | 2 +- libfdt/fdt_overlay.c | 670 +++++++++++++++++++++++++++++++++++++++++ libfdt/libfdt.h | 31 ++ libfdt/libfdt_env.h | 1 + 4 files changed, 703 insertions(+), 1 deletion(-) create mode 100644 libfdt/fdt_overlay.c diff --git a/libfdt/Makefile.libfdt b/libfdt/Makefile.libfdt index 09c322e..098b3f3 100644 --- a/libfdt/Makefile.libfdt +++ b/libfdt/Makefile.libfdt @@ -7,5 +7,5 @@ LIBFDT_soname = libfdt.$(SHAREDLIB_EXT).1 LIBFDT_INCLUDES = fdt.h libfdt.h libfdt_env.h LIBFDT_VERSION = version.lds LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c fdt_empty_tree.c \ - fdt_addresses.c + fdt_addresses.c fdt_overlay.c LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o) diff --git a/libfdt/fdt_overlay.c b/libfdt/fdt_overlay.c new file mode 100644 index 0000000..c7e5508 --- /dev/null +++ b/libfdt/fdt_overlay.c @@ -0,0 +1,670 @@ +#include "libfdt_env.h" + +#include +#include + +#include "libfdt_internal.h" + +/** + * overlay_get_target_phandle - retrieves the target phandle of a fragment + * @fdto: pointer to the device tree overlay blob + * @fragment: node offset of the fragment in the overlay + * + * overlay_get_target_phandle() retrieves the target phandle of an + * overlay fragment when that fragment uses a phandle (target + * property) instead of a path (target-path property). + * + * returns: + * the phandle pointed by the target property + * 0, if the phandle was not found + * -1, if the phandle was malformed + */ +static uint32_t overlay_get_target_phandle(const void *fdto, int fragment) +{ + const uint32_t *val; + int len; + + val = fdt_getprop(fdto, fragment, "target", &len); + if (!val) + return 0; + + if ((len != sizeof(*val)) || (*val == (uint32_t)-1)) + return (uint32_t)-1; + + return fdt32_to_cpu(*val); +} + +/** + * overlay_get_target - retrieves the offset of a fragment's target + * @fdt: Base device tree blob + * @fdto: Device tree overlay blob + * @fragment: node offset of the fragment in the overlay + * + * overlay_get_target() retrieves the target offset in the base + * device tree of a fragment, no matter how the actual targetting is + * done (through a phandle or a path) + * + * returns: + * the targetted node offset in the base device tree + * Negative error code on error + */ +static int overlay_get_target(const void *fdt, const void *fdto, + int fragment) +{ + uint32_t phandle; + const char *path; + int path_len; + + /* Try first to do a phandle based lookup */ + phandle = overlay_get_target_phandle(fdto, fragment); + if (phandle == (uint32_t)-1) + return -FDT_ERR_BADPHANDLE; + + if (phandle) + return fdt_node_offset_by_phandle(fdt, phandle); + + /* And then a path based lookup */ + path = fdt_getprop(fdto, fragment, "target-path", &path_len); + if (!path) { + /* + * If we haven't found either a target or a + * target-path property in a node that contains a + * __overlay__ subnode (we wouldn't be called + * otherwise), consider it a improperly written + * overlay + */ + if (path_len == -FDT_ERR_NOTFOUND) + return -FDT_ERR_BADOVERLAY; + + return path_len; + } + + return fdt_path_offset(fdt, path); +} + +/** + * overlay_phandle_add_offset - Increases a phandle by an offset + * @fdt: Base device tree blob + * @node: Device tree overlay blob + * @name: Name of the property to modify (phandle or linux,phandle) + * @delta: offset to apply + * + * overlay_phandle_add_offset() increments a node phandle by a given + * offset. + * + * returns: + * 0 on success. + * Negative error code on error + */ +static int overlay_phandle_add_offset(void *fdt, int node, + const char *name, uint32_t delta) +{ + const uint32_t *val; + uint32_t adj_val; + int len; + + val = fdt_getprop(fdt, node, name, &len); + if (!val) + return len; + + if (len != sizeof(*val)) + return -FDT_ERR_BADPHANDLE; + + adj_val = fdt32_to_cpu(*val); + if ((adj_val + delta) < adj_val) + return -FDT_ERR_NOPHANDLES; + + adj_val += delta; + if (adj_val == (uint32_t)-1) + return -FDT_ERR_NOPHANDLES; + + return fdt_setprop_inplace_u32(fdt, node, name, adj_val); +} + +/** + * overlay_adjust_node_phandles - Offsets the phandles of a node + * @fdto: Device tree overlay blob + * @node: Offset of the node we want to adjust + * @delta: Offset to shift the phandles of + * + * overlay_adjust_node_phandles() adds a constant to all the phandles + * of a given node. This is mainly use as part of the overlay + * application process, when we want to update all the overlay + * phandles to not conflict with the overlays of the base device tree. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_adjust_node_phandles(void *fdto, int node, + uint32_t delta) +{ + int child; + int ret; + + ret = overlay_phandle_add_offset(fdto, node, "phandle", delta); + if (ret && ret != -FDT_ERR_NOTFOUND) + return ret; + + ret = overlay_phandle_add_offset(fdto, node, "linux,phandle", delta); + if (ret && ret != -FDT_ERR_NOTFOUND) + return ret; + + fdt_for_each_subnode(child, fdto, node) { + ret = overlay_adjust_node_phandles(fdto, child, delta); + if (ret) + return ret; + } + + return 0; +} + +/** + * overlay_adjust_local_phandles - Adjust the phandles of a whole overlay + * @fdto: Device tree overlay blob + * @delta: Offset to shift the phandles of + * + * overlay_adjust_local_phandles() adds a constant to all the + * phandles of an overlay. This is mainly use as part of the overlay + * application process, when we want to update all the overlay + * phandles to not conflict with the overlays of the base device tree. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_adjust_local_phandles(void *fdto, uint32_t delta) +{ + /* + * Start adjusting the phandles from the overlay root + */ + return overlay_adjust_node_phandles(fdto, 0, delta); +} + +/** + * overlay_update_local_node_references - Adjust the overlay references + * @fdto: Device tree overlay blob + * @tree_node: Node offset of the node to operate on + * @fixup_node: Node offset of the matching local fixups node + * @delta: Offset to shift the phandles of + * + * overlay_update_local_nodes_references() update the phandles + * pointing to a node within the device tree overlay by adding a + * constant delta. + * + * This is mainly used as part of a device tree application process, + * where you want the device tree overlays phandles to not conflict + * with the ones from the base device tree before merging them. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_update_local_node_references(void *fdto, + int tree_node, + int fixup_node, + uint32_t delta) +{ + int fixup_prop; + int fixup_child; + int ret; + + fdt_for_each_property_offset(fixup_prop, fdto, fixup_node) { + const uint32_t *fixup_val; + const char *tree_val; + const char *name; + int fixup_len; + int tree_len; + int i; + + fixup_val = fdt_getprop_by_offset(fdto, fixup_prop, + &name, &fixup_len); + if (!fixup_val) + return fixup_len; + + if (fixup_len % sizeof(uint32_t)) + return -FDT_ERR_BADOVERLAY; + + tree_val = fdt_getprop(fdto, tree_node, name, &tree_len); + if (!tree_val) { + if (tree_len == -FDT_ERR_NOTFOUND) + return -FDT_ERR_BADOVERLAY; + + return tree_len; + } + + for (i = 0; i < (fixup_len / sizeof(uint32_t)); i++) { + uint32_t adj_val, index; + + index = fdt32_to_cpu(fixup_val[i]); + + /* + * phandles to fixup can be unaligned. + * + * Use a memcpy for the architectures that do + * not support unaligned accesses. + */ + memcpy(&adj_val, tree_val + index, sizeof(adj_val)); + + adj_val = fdt32_to_cpu(adj_val); + adj_val += delta; + adj_val = cpu_to_fdt32(adj_val); + + ret = fdt_setprop_inplace_namelen_partial(fdto, + tree_node, + name, + strlen(name), + index, + &adj_val, + sizeof(adj_val)); + if (ret == -FDT_ERR_NOSPACE) + return -FDT_ERR_BADOVERLAY; + + if (ret) + return ret; + } + } + + fdt_for_each_subnode(fixup_child, fdto, fixup_node) { + const char *fixup_child_name = fdt_get_name(fdto, fixup_child, + NULL); + int tree_child; + + tree_child = fdt_subnode_offset(fdto, tree_node, + fixup_child_name); + if (tree_child < 0) + return tree_child; + + ret = overlay_update_local_node_references(fdto, + tree_child, + fixup_child, + delta); + if (ret) + return ret; + } + + return 0; +} + +/** + * overlay_update_local_references - Adjust the overlay references + * @fdto: Device tree overlay blob + * @delta: Offset to shift the phandles of + * + * overlay_update_local_references() update all the phandles pointing + * to a node within the device tree overlay by adding a constant + * delta to not conflict with the base overlay. + * + * This is mainly used as part of a device tree application process, + * where you want the device tree overlays phandles to not conflict + * with the ones from the base device tree before merging them. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_update_local_references(void *fdto, uint32_t delta) +{ + int fixups; + + fixups = fdt_path_offset(fdto, "/__local_fixups__"); + if (fixups < 0) { + /* There's no local phandles to adjust, bail out */ + if (fixups == -FDT_ERR_NOTFOUND) + return 0; + + return fixups; + } + + /* + * Update our local references from the root of the tree + */ + return overlay_update_local_node_references(fdto, 0, fixups, + delta); +} + +/** + * overlay_fixup_one_phandle - Set an overlay phandle to the base one + * @fdt: Base Device Tree blob + * @fdto: Device tree overlay blob + * @symbols_off: Node offset of the symbols node in the base device tree + * @path: Path to a node holding a phandle in the overlay + * @path_len: number of path characters to consider + * @name: Name of the property holding the phandle reference in the overlay + * @name_len: number of name characters to consider + * @index: Index in the overlay property where the phandle is stored + * @label: Label of the node referenced by the phandle + * + * overlay_fixup_one_phandle() resolves an overlay phandle pointing to + * a node in the base device tree. + * + * This is part of the device tree overlay application process, when + * you want all the phandles in the overlay to point to the actual + * base dt nodes. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_fixup_one_phandle(void *fdt, void *fdto, + int symbols_off, + const char *path, uint32_t path_len, + const char *name, uint32_t name_len, + int index, const char *label) +{ + const char *symbol_path; + uint32_t phandle; + int symbol_off, fixup_off; + int prop_len; + + symbol_path = fdt_getprop(fdt, symbols_off, label, + &prop_len); + if (!symbol_path) + return prop_len; + + symbol_off = fdt_path_offset(fdt, symbol_path); + if (symbol_off < 0) + return symbol_off; + + phandle = fdt_get_phandle(fdt, symbol_off); + if (!phandle) + return -FDT_ERR_NOTFOUND; + + fixup_off = fdt_path_offset_namelen(fdto, path, path_len); + if (fixup_off == -FDT_ERR_NOTFOUND) + return -FDT_ERR_BADOVERLAY; + if (fixup_off < 0) + return fixup_off; + + phandle = cpu_to_fdt32(phandle); + return fdt_setprop_inplace_namelen_partial(fdto, fixup_off, + name, name_len, index, + &phandle, sizeof(phandle)); +}; + +/** + * overlay_fixup_phandle - Set an overlay phandle to the base one + * @fdt: Base Device Tree blob + * @fdto: Device tree overlay blob + * @symbols_off: Node offset of the symbols node in the base device tree + * @property: Property offset in the overlay holding the list of fixups + * + * overlay_fixup_phandle() resolves all the overlay phandles pointed + * to in a __fixups__ property, and updates them to match the phandles + * in use in the base device tree. + * + * This is part of the device tree overlay application process, when + * you want all the phandles in the overlay to point to the actual + * base dt nodes. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off, + int property) +{ + const char *value; + const char *label; + int len; + + value = fdt_getprop_by_offset(fdto, property, + &label, &len); + if (!value) { + if (len == -FDT_ERR_NOTFOUND) + return -FDT_ERR_INTERNAL; + + return len; + } + + do { + const char *path, *name, *fixup_end; + const char *fixup_str = value; + uint32_t path_len, name_len; + uint32_t fixup_len; + char *sep, *endptr; + int index, ret; + + fixup_end = memchr(value, '\0', len); + if (!fixup_end) + return -FDT_ERR_BADOVERLAY; + fixup_len = fixup_end - fixup_str; + + len -= fixup_len + 1; + value += fixup_len + 1; + + path = fixup_str; + sep = memchr(fixup_str, ':', fixup_len); + if (!sep || *sep != ':') + return -FDT_ERR_BADOVERLAY; + + path_len = sep - path; + if (path_len == (fixup_len - 1)) + return -FDT_ERR_BADOVERLAY; + + fixup_len -= path_len + 1; + name = sep + 1; + sep = memchr(name, ':', fixup_len); + if (!sep || *sep != ':') + return -FDT_ERR_BADOVERLAY; + + name_len = sep - name; + if (!name_len) + return -FDT_ERR_BADOVERLAY; + + index = strtoul(sep + 1, &endptr, 10); + if ((*endptr != '\0') || (endptr <= (sep + 1))) + return -FDT_ERR_BADOVERLAY; + + ret = overlay_fixup_one_phandle(fdt, fdto, symbols_off, + path, path_len, name, name_len, + index, label); + if (ret) + return ret; + } while (len > 0); + + return 0; +} + +/** + * overlay_fixup_phandles - Resolve the overlay phandles to the base + * device tree + * @fdt: Base Device Tree blob + * @fdto: Device tree overlay blob + * + * overlay_fixup_phandles() resolves all the overlay phandles pointing + * to nodes in the base device tree. + * + * This is one of the steps of the device tree overlay application + * process, when you want all the phandles in the overlay to point to + * the actual base dt nodes. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_fixup_phandles(void *fdt, void *fdto) +{ + int fixups_off, symbols_off; + int property; + + /* We can have overlays without any fixups */ + fixups_off = fdt_path_offset(fdto, "/__fixups__"); + if (fixups_off == -FDT_ERR_NOTFOUND) + return 0; + if (fixups_off < 0) + return fixups_off; + + symbols_off = fdt_path_offset(fdt, "/__symbols__"); + if (symbols_off < 0) + return symbols_off; + + fdt_for_each_property_offset(property, fdto, fixups_off) { + int ret; + + ret = overlay_fixup_phandle(fdt, fdto, symbols_off, property); + if (ret) + return ret; + } + + return 0; +} + +/** + * overlay_apply_node - Merges a node into the base device tree + * @fdt: Base Device Tree blob + * @target: Node offset in the base device tree to apply the fragment to + * @fdto: Device tree overlay blob + * @node: Node offset in the overlay holding the changes to merge + * + * overlay_apply_node() merges a node into a target base device tree + * node pointed. + * + * This is part of the final step in the device tree overlay + * application process, when all the phandles have been adjusted and + * resolved and you just have to merge overlay into the base device + * tree. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_apply_node(void *fdt, int target, + void *fdto, int node) +{ + int property; + int subnode; + + fdt_for_each_property_offset(property, fdto, node) { + const char *name; + const void *prop; + int prop_len; + int ret; + + prop = fdt_getprop_by_offset(fdto, property, &name, + &prop_len); + if (prop_len == -FDT_ERR_NOTFOUND) + return -FDT_ERR_INTERNAL; + if (prop_len < 0) + return prop_len; + + ret = fdt_setprop(fdt, target, name, prop, prop_len); + if (ret) + return ret; + } + + fdt_for_each_subnode(subnode, fdto, node) { + const char *name = fdt_get_name(fdto, subnode, NULL); + int nnode; + int ret; + + nnode = fdt_add_subnode(fdt, target, name); + if (nnode == -FDT_ERR_EXISTS) { + nnode = fdt_subnode_offset(fdt, target, name); + if (nnode == -FDT_ERR_NOTFOUND) + return -FDT_ERR_INTERNAL; + } + + if (nnode < 0) + return nnode; + + ret = overlay_apply_node(fdt, nnode, fdto, subnode); + if (ret) + return ret; + } + + return 0; +} + +/** + * overlay_merge - Merge an overlay into its base device tree + * @fdt: Base Device Tree blob + * @fdto: Device tree overlay blob + * + * overlay_merge() merges an overlay into its base device tree. + * + * This is the final step in the device tree overlay application + * process, when all the phandles have been adjusted and resolved and + * you just have to merge overlay into the base device tree. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_merge(void *fdt, void *fdto) +{ + int fragment; + + fdt_for_each_subnode(fragment, fdto, 0) { + int overlay; + int target; + int ret; + + /* + * Each fragments will have an __overlay__ node. If + * they don't, it's not supposed to be merged + */ + overlay = fdt_subnode_offset(fdto, fragment, "__overlay__"); + if (overlay == -FDT_ERR_NOTFOUND) + continue; + + if (overlay < 0) + return overlay; + + target = overlay_get_target(fdt, fdto, fragment); + if (target < 0) + return target; + + ret = overlay_apply_node(fdt, target, fdto, overlay); + if (ret) + return ret; + } + + return 0; +} + +int fdt_overlay_apply(void *fdt, void *fdto) +{ + uint32_t delta = fdt_get_max_phandle(fdt); + int ret; + + FDT_CHECK_HEADER(fdt); + FDT_CHECK_HEADER(fdto); + + ret = overlay_adjust_local_phandles(fdto, delta); + if (ret) + goto err; + + ret = overlay_update_local_references(fdto, delta); + if (ret) + goto err; + + ret = overlay_fixup_phandles(fdt, fdto); + if (ret) + goto err; + + ret = overlay_merge(fdt, fdto); + if (ret) + goto err; + + /* + * The overlay has been damaged, erase its magic. + */ + fdt_set_magic(fdto, ~0); + + return 0; + +err: + /* + * The overlay might have been damaged, erase its magic. + */ + fdt_set_magic(fdto, ~0); + + /* + * The base device tree might have been damaged, erase its + * magic. + */ + fdt_set_magic(fdt, ~0); + + return ret; +} diff --git a/libfdt/libfdt.h b/libfdt/libfdt.h index d2e5e03..c69e918 100644 --- a/libfdt/libfdt.h +++ b/libfdt/libfdt.h @@ -1763,6 +1763,37 @@ int fdt_add_subnode(void *fdt, int parentoffset, const char *name); */ int fdt_del_node(void *fdt, int nodeoffset); +/** + * fdt_overlay_apply - Applies a DT overlay on a base DT + * @fdt: pointer to the base device tree blob + * @fdto: pointer to the device tree overlay blob + * + * fdt_overlay_apply() will apply the given device tree overlay on the + * given base device tree. + * + * Expect the base device tree to be modified, even if the function + * returns an error. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there's not enough space in the base device tree + * -FDT_ERR_NOTFOUND, the overlay points to some inexistant nodes or + * properties in the base DT + * -FDT_ERR_BADPHANDLE, + * -FDT_ERR_BADOVERLAY, + * -FDT_ERR_NOPHANDLES, + * -FDT_ERR_INTERNAL, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADOFFSET, + * -FDT_ERR_BADPATH, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_overlay_apply(void *fdt, void *fdto); + /**********************************************************************/ /* Debugging / informational functions */ /**********************************************************************/ diff --git a/libfdt/libfdt_env.h b/libfdt/libfdt_env.h index 9dea97d..99f936d 100644 --- a/libfdt/libfdt_env.h +++ b/libfdt/libfdt_env.h @@ -54,6 +54,7 @@ #include #include +#include #include #ifdef __CHECKER__ From aea8860d831ed05a147a1896c15e1312a9a66917 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 30 Sep 2016 15:57:17 +0200 Subject: [PATCH 32/71] tests: Add tests cases for the overlay code Add some test infrastructure to test that the overlay can be merged, but also that poorly formatted fixups would fail as expected. Signed-off-by: Maxime Ripard [dwg: Don't execute bad overlay tests without overlay aware dtc] Signed-off-by: David Gibson --- tests/.gitignore | 2 + tests/Makefile.tests | 3 +- tests/overlay.c | 232 ++++++++++++++++++++ tests/overlay_bad_fixup.c | 70 ++++++ tests/overlay_bad_fixup_bad_index.dts | 14 ++ tests/overlay_bad_fixup_base.dtsi | 18 ++ tests/overlay_bad_fixup_empty.dts | 14 ++ tests/overlay_bad_fixup_empty_index.dts | 14 ++ tests/overlay_bad_fixup_index_trailing.dts | 14 ++ tests/overlay_bad_fixup_path_empty_prop.dts | 14 ++ tests/overlay_bad_fixup_path_only.dts | 14 ++ tests/overlay_bad_fixup_path_only_sep.dts | 14 ++ tests/overlay_bad_fixup_path_prop.dts | 14 ++ tests/overlay_base.dts | 21 ++ tests/overlay_overlay_dtc.dts | 85 +++++++ tests/overlay_overlay_nodtc.dts | 82 +++++++ tests/run_tests.sh | 32 +++ 17 files changed, 656 insertions(+), 1 deletion(-) create mode 100644 tests/overlay.c create mode 100644 tests/overlay_bad_fixup.c create mode 100644 tests/overlay_bad_fixup_bad_index.dts create mode 100644 tests/overlay_bad_fixup_base.dtsi create mode 100644 tests/overlay_bad_fixup_empty.dts create mode 100644 tests/overlay_bad_fixup_empty_index.dts create mode 100644 tests/overlay_bad_fixup_index_trailing.dts create mode 100644 tests/overlay_bad_fixup_path_empty_prop.dts create mode 100644 tests/overlay_bad_fixup_path_only.dts create mode 100644 tests/overlay_bad_fixup_path_only_sep.dts create mode 100644 tests/overlay_bad_fixup_path_prop.dts create mode 100644 tests/overlay_base.dts create mode 100644 tests/overlay_overlay_dtc.dts create mode 100644 tests/overlay_overlay_nodtc.dts diff --git a/tests/.gitignore b/tests/.gitignore index fa4616b..354b565 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -35,6 +35,8 @@ tmp.* /nopulate /notfound /open_pack +/overlay +/overlay_bad_fixup /parent_offset /path-references /path_offset diff --git a/tests/Makefile.tests b/tests/Makefile.tests index 196518c..eb039c5 100644 --- a/tests/Makefile.tests +++ b/tests/Makefile.tests @@ -24,7 +24,8 @@ LIB_TESTS_L = get_mem_rsv \ utilfdt_test \ integer-expressions \ property_iterate \ - subnode_iterate + subnode_iterate \ + overlay overlay_bad_fixup LIB_TESTS = $(LIB_TESTS_L:%=$(TESTS_PREFIX)%) LIBTREE_TESTS_L = truncated_property diff --git a/tests/overlay.c b/tests/overlay.c new file mode 100644 index 0000000..e467b03 --- /dev/null +++ b/tests/overlay.c @@ -0,0 +1,232 @@ +/* + * libfdt - Flat Device Tree manipulation + * Testcase for DT overlays() + * Copyright (C) 2016 Free Electrons + * Copyright (C) 2016 NextThing Co. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include + +#include "tests.h" + +#define CHECK(code) \ + { \ + if (code) \ + FAIL(#code ": %s", fdt_strerror(code)); \ + } + +/* 4k ought to be enough for anybody */ +#define FDT_COPY_SIZE (4 * 1024) + +static int fdt_getprop_u32_by_index(void *fdt, const char *path, + const char *name, int index, + unsigned long *out) +{ + const fdt32_t *val; + int node_off; + int len; + + node_off = fdt_path_offset(fdt, path); + if (node_off < 0) + return node_off; + + val = fdt_getprop(fdt, node_off, name, &len); + if (!val || (len < (sizeof(uint32_t) * (index + 1)))) + return -FDT_ERR_NOTFOUND; + + *out = fdt32_to_cpu(*(val + index)); + + return 0; +} + +static int check_getprop_string_by_name(void *fdt, const char *path, + const char *name, const char *val) +{ + int node_off; + + node_off = fdt_path_offset(fdt, path); + if (node_off < 0) + return node_off; + + check_getprop_string(fdt, node_off, name, val); + + return 0; +} + +static int check_getprop_u32_by_name(void *fdt, const char *path, + const char *name, uint32_t val) +{ + int node_off; + + node_off = fdt_path_offset(fdt, path); + CHECK(node_off < 0); + + check_getprop_cell(fdt, node_off, name, val); + + return 0; +} + +static int check_getprop_null_by_name(void *fdt, const char *path, + const char *name) +{ + int node_off; + + node_off = fdt_path_offset(fdt, path); + CHECK(node_off < 0); + + check_property(fdt, node_off, name, 0, NULL); + + return 0; +} + +static int fdt_overlay_change_int_property(void *fdt) +{ + return check_getprop_u32_by_name(fdt, "/test-node", "test-int-property", + 43); +} + +static int fdt_overlay_change_str_property(void *fdt) +{ + return check_getprop_string_by_name(fdt, "/test-node", + "test-str-property", "foobar"); +} + +static int fdt_overlay_add_str_property(void *fdt) +{ + return check_getprop_string_by_name(fdt, "/test-node", + "test-str-property-2", "foobar2"); +} + +static int fdt_overlay_add_node(void *fdt) +{ + return check_getprop_null_by_name(fdt, "/test-node/new-node", + "new-property"); +} + +static int fdt_overlay_add_subnode_property(void *fdt) +{ + check_getprop_null_by_name(fdt, "/test-node/sub-test-node", + "sub-test-property"); + check_getprop_null_by_name(fdt, "/test-node/sub-test-node", + "new-sub-test-property"); + + return 0; +} + +static int fdt_overlay_local_phandle(void *fdt) +{ + uint32_t local_phandle; + unsigned long val = 0; + int off; + + off = fdt_path_offset(fdt, "/test-node/new-local-node"); + CHECK(off < 0); + + local_phandle = fdt_get_phandle(fdt, off); + CHECK(!local_phandle); + + CHECK(fdt_getprop_u32_by_index(fdt, "/test-node", + "test-several-phandle", + 0, &val)); + CHECK(val != local_phandle); + + CHECK(fdt_getprop_u32_by_index(fdt, "/test-node", + "test-several-phandle", + 1, &val)); + CHECK(val != local_phandle); + + return 0; +} + +static int fdt_overlay_local_phandles(void *fdt) +{ + uint32_t local_phandle, test_phandle; + unsigned long val = 0; + int off; + + off = fdt_path_offset(fdt, "/test-node/new-local-node"); + CHECK(off < 0); + + local_phandle = fdt_get_phandle(fdt, off); + CHECK(!local_phandle); + + off = fdt_path_offset(fdt, "/test-node"); + CHECK(off < 0); + + test_phandle = fdt_get_phandle(fdt, off); + CHECK(!test_phandle); + + CHECK(fdt_getprop_u32_by_index(fdt, "/test-node", + "test-phandle", 0, &val)); + CHECK(test_phandle != val); + + CHECK(fdt_getprop_u32_by_index(fdt, "/test-node", + "test-phandle", 1, &val)); + CHECK(local_phandle != val); + + return 0; +} + +static void *open_dt(char *path) +{ + void *dt, *copy; + + dt = load_blob(path); + copy = xmalloc(FDT_COPY_SIZE); + + /* + * Resize our DTs to 4k so that we have room to operate on + */ + CHECK(fdt_open_into(dt, copy, FDT_COPY_SIZE)); + + return copy; +} + +int main(int argc, char *argv[]) +{ + void *fdt_base, *fdt_overlay; + + test_init(argc, argv); + if (argc != 3) + CONFIG("Usage: %s ", argv[0]); + + fdt_base = open_dt(argv[1]); + fdt_overlay = open_dt(argv[2]); + + /* Apply the overlay */ + CHECK(fdt_overlay_apply(fdt_base, fdt_overlay)); + + fdt_overlay_change_int_property(fdt_base); + fdt_overlay_change_str_property(fdt_base); + fdt_overlay_add_str_property(fdt_base); + fdt_overlay_add_node(fdt_base); + fdt_overlay_add_subnode_property(fdt_base); + + /* + * If the base tree has a __symbols__ node, do the tests that + * are only successful with a proper phandle support, and thus + * dtc -@ + */ + if (fdt_path_offset(fdt_base, "/__symbols__") >= 0) { + fdt_overlay_local_phandle(fdt_base); + fdt_overlay_local_phandles(fdt_base); + } + + PASS(); +} diff --git a/tests/overlay_bad_fixup.c b/tests/overlay_bad_fixup.c new file mode 100644 index 0000000..5014f5e --- /dev/null +++ b/tests/overlay_bad_fixup.c @@ -0,0 +1,70 @@ +/* + * libfdt - Flat Device Tree manipulation + * Testcase for DT overlays() + * Copyright (C) 2016 Free Electrons + * Copyright (C) 2016 NextThing Co. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include + +#include "tests.h" + +#define CHECK(code, expected) \ + { \ + err = (code); \ + if (err != expected) \ + FAIL(#code ": %s", fdt_strerror(err)); \ + } + +/* 4k ought to be enough for anybody */ +#define FDT_COPY_SIZE (4 * 1024) + +static void *open_dt(char *path) +{ + void *dt, *copy; + int err; + + dt = load_blob(path); + copy = xmalloc(FDT_COPY_SIZE); + + /* + * Resize our DTs to 4k so that we have room to operate on + */ + CHECK(fdt_open_into(dt, copy, FDT_COPY_SIZE), 0); + + return copy; +} + +int main(int argc, char *argv[]) +{ + void *fdt_base, *fdt_overlay; + int err; + + test_init(argc, argv); + if (argc != 3) + CONFIG("Usage: %s ", argv[0]); + + fdt_base = open_dt(argv[1]); + fdt_overlay = open_dt(argv[2]); + + /* Apply the overlay */ + CHECK(fdt_overlay_apply(fdt_base, fdt_overlay), -FDT_ERR_BADOVERLAY); + + PASS(); +} diff --git a/tests/overlay_bad_fixup_bad_index.dts b/tests/overlay_bad_fixup_bad_index.dts new file mode 100644 index 0000000..b5cf131 --- /dev/null +++ b/tests/overlay_bad_fixup_bad_index.dts @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2016 NextThing Co + * Copyright (c) 2016 Free Electrons + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/include/ "overlay_bad_fixup_base.dtsi" + +/ { + __fixups__ { + test = "/fragment@0:target:ab"; + }; +}; diff --git a/tests/overlay_bad_fixup_base.dtsi b/tests/overlay_bad_fixup_base.dtsi new file mode 100644 index 0000000..216bcab --- /dev/null +++ b/tests/overlay_bad_fixup_base.dtsi @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2016 NextThing Co + * Copyright (c) 2016 Free Electrons + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/dts-v1/; + +/ { + fragment@0 { + target = <0xffffffff>; + + __overlay__ { + test-property; + }; + }; +}; diff --git a/tests/overlay_bad_fixup_empty.dts b/tests/overlay_bad_fixup_empty.dts new file mode 100644 index 0000000..e111db4 --- /dev/null +++ b/tests/overlay_bad_fixup_empty.dts @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2016 NextThing Co + * Copyright (c) 2016 Free Electrons + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/include/ "overlay_bad_fixup_base.dtsi" + +/ { + __fixups__ { + test = ""; + }; +}; diff --git a/tests/overlay_bad_fixup_empty_index.dts b/tests/overlay_bad_fixup_empty_index.dts new file mode 100644 index 0000000..9e12e21 --- /dev/null +++ b/tests/overlay_bad_fixup_empty_index.dts @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2016 NextThing Co + * Copyright (c) 2016 Free Electrons + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/include/ "overlay_bad_fixup_base.dtsi" + +/ { + __fixups__ { + test = "/fragment@0:target:"; + }; +}; diff --git a/tests/overlay_bad_fixup_index_trailing.dts b/tests/overlay_bad_fixup_index_trailing.dts new file mode 100644 index 0000000..f586bef --- /dev/null +++ b/tests/overlay_bad_fixup_index_trailing.dts @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2016 NextThing Co + * Copyright (c) 2016 Free Electrons + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/include/ "overlay_bad_fixup_base.dtsi" + +/ { + __fixups__ { + test = "/fragment@0:target:0a"; + }; +}; diff --git a/tests/overlay_bad_fixup_path_empty_prop.dts b/tests/overlay_bad_fixup_path_empty_prop.dts new file mode 100644 index 0000000..608b5f9 --- /dev/null +++ b/tests/overlay_bad_fixup_path_empty_prop.dts @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2016 NextThing Co + * Copyright (c) 2016 Free Electrons + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/include/ "overlay_bad_fixup_base.dtsi" + +/ { + __fixups__ { + test = "/fragment@0::"; + }; +}; diff --git a/tests/overlay_bad_fixup_path_only.dts b/tests/overlay_bad_fixup_path_only.dts new file mode 100644 index 0000000..2485dd9 --- /dev/null +++ b/tests/overlay_bad_fixup_path_only.dts @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2016 NextThing Co + * Copyright (c) 2016 Free Electrons + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/include/ "overlay_bad_fixup_base.dtsi" + +/ { + __fixups__ { + test = "/fragment@0"; + }; +}; diff --git a/tests/overlay_bad_fixup_path_only_sep.dts b/tests/overlay_bad_fixup_path_only_sep.dts new file mode 100644 index 0000000..3cbf6c4 --- /dev/null +++ b/tests/overlay_bad_fixup_path_only_sep.dts @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2016 NextThing Co + * Copyright (c) 2016 Free Electrons + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/include/ "overlay_bad_fixup_base.dtsi" + +/ { + __fixups__ { + test = "/fragment@0:"; + }; +}; diff --git a/tests/overlay_bad_fixup_path_prop.dts b/tests/overlay_bad_fixup_path_prop.dts new file mode 100644 index 0000000..ca79b52 --- /dev/null +++ b/tests/overlay_bad_fixup_path_prop.dts @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2016 NextThing Co + * Copyright (c) 2016 Free Electrons + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/include/ "overlay_bad_fixup_base.dtsi" + +/ { + __fixups__ { + test = "/fragment@0:target"; + }; +}; diff --git a/tests/overlay_base.dts b/tests/overlay_base.dts new file mode 100644 index 0000000..2603adb --- /dev/null +++ b/tests/overlay_base.dts @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2016 NextThing Co + * Copyright (c) 2016 Free Electrons + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/dts-v1/; + +/ { + test: test-node { + test-int-property = <42>; + test-str-property = "foo"; + + subtest: sub-test-node { + sub-test-property; + }; + }; +}; + + diff --git a/tests/overlay_overlay_dtc.dts b/tests/overlay_overlay_dtc.dts new file mode 100644 index 0000000..30d2362 --- /dev/null +++ b/tests/overlay_overlay_dtc.dts @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2016 NextThing Co + * Copyright (c) 2016 Free Electrons + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/dts-v1/; +/plugin/; + +/ { + /* Test that we can change an int by another */ + fragment@0 { + target = <&test>; + + __overlay__ { + test-int-property = <43>; + }; + }; + + /* Test that we can replace a string by a longer one */ + fragment@1 { + target = <&test>; + + __overlay__ { + test-str-property = "foobar"; + }; + }; + + /* Test that we add a new property */ + fragment@2 { + target = <&test>; + + __overlay__ { + test-str-property-2 = "foobar2"; + }; + }; + + /* Test that we add a new node (by phandle) */ + fragment@3 { + target = <&test>; + + __overlay__ { + new-node { + new-property; + }; + }; + }; + + fragment@5 { + target = <&test>; + + __overlay__ { + local: new-local-node { + new-property; + }; + }; + }; + + fragment@6 { + target = <&test>; + + __overlay__ { + test-phandle = <&test>, <&local>; + }; + }; + + fragment@7 { + target = <&test>; + + __overlay__ { + test-several-phandle = <&local>, <&local>; + }; + }; + + fragment@8 { + target = <&test>; + + __overlay__ { + sub-test-node { + new-sub-test-property; + }; + }; + }; +}; diff --git a/tests/overlay_overlay_nodtc.dts b/tests/overlay_overlay_nodtc.dts new file mode 100644 index 0000000..e8d0f96 --- /dev/null +++ b/tests/overlay_overlay_nodtc.dts @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2016 NextThing Co + * Copyright (c) 2016 Free Electrons + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/dts-v1/; + +/ { + fragment@0 { + target-path = "/test-node"; + + __overlay__ { + test-int-property = <43>; + }; + }; + + /* Test that we can replace a string by a longer one */ + fragment@1 { + target-path = "/test-node"; + + __overlay__ { + test-str-property = "foobar"; + }; + }; + + /* Test that we add a new property */ + fragment@2 { + target-path = "/test-node"; + + __overlay__ { + test-str-property-2 = "foobar2"; + }; + }; + + fragment@3 { + target-path = "/test-node"; + + __overlay__ { + new-node { + new-property; + }; + }; + }; + + fragment@4 { + target-path = "/"; + + __overlay__ { + local: new-local-node { + new-property; + }; + }; + }; + + fragment@5 { + target-path = "/"; + + __overlay__ { + test-several-phandle = <&local>, <&local>; + }; + }; + + fragment@6 { + target-path = "/test-node"; + + __overlay__ { + sub-test-node { + new-sub-test-property; + }; + }; + }; + + __local_fixups__ { + fragment@5 { + __overlay__ { + test-several-phandle = <0 4>; + }; + }; + }; +}; diff --git a/tests/run_tests.sh b/tests/run_tests.sh index f4b32e4..10b41bc 100755 --- a/tests/run_tests.sh +++ b/tests/run_tests.sh @@ -160,6 +160,37 @@ run_fdtdump_test() { base_run_test sh fdtdump-runtest.sh "$file" } +BAD_FIXUP_TREES="bad_index \ + empty \ + empty_index \ + index_trailing \ + path_empty_prop \ + path_only \ + path_only_sep \ + path_prop" + +overlay_tests () { + # Overlay tests that don't require overlay support in dtc + run_dtc_test -I dts -O dtb -o overlay_base.dtb overlay_base.dts + run_dtc_test -I dts -O dtb -o overlay_overlay.dtb overlay_overlay_nodtc.dts + run_test overlay overlay_base.dtb overlay_overlay.dtb + + # Overlay tests that requires overlay support in dtc + echo "/dts-v1/; / {};" | $DTC -@ > /dev/null 2>&1 + if [ $? -eq 0 ]; then + run_dtc_test -@ -I dts -O dtb -o overlay_base.dtb overlay_base.dts + run_dtc_test -@ -I dts -O dtb -o overlay_overlay.dtb overlay_overlay_dtc.dts + run_test overlay overlay_base.dtb overlay_overlay.dtb + + # Bad fixup tests + for test in $BAD_FIXUP_TREES; do + tree="overlay_bad_fixup_$test" + run_dtc_test -I dts -O dtb -o $tree.dtb $tree.dts + run_test overlay_bad_fixup overlay_base.dtb $tree.dtb + done + fi +} + tree1_tests () { TREE=$1 @@ -273,6 +304,7 @@ libfdt_tests () { run_test appendprop2 appendprop1.test.dtb run_dtc_test -I dts -O dtb -o appendprop.test.dtb appendprop.dts run_test dtbs_equal_ordered appendprop2.test.dtb appendprop.test.dtb + overlay_tests for basetree in test_tree1.dtb sw_tree1.test.dtb rw_tree1.test.dtb; do run_test nopulate $basetree From 7b7a6be9ba159125a8e11b7ccc86233d17109187 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 6 Oct 2016 20:45:14 +1100 Subject: [PATCH 33/71] libfdt: Don't use 'index' as a local variable name Using 'index' as a local variable name shadows the standard library index() function. This causes warnings on at least some compiler versions. The recently added overlay code has a number of instances of this. This patch replaces 'index' with 'poffset', since 'index' is being used to mean "offset within a property value" in these cases. Signed-off-by: David Gibson --- libfdt/fdt_overlay.c | 20 ++++++++++---------- tests/overlay.c | 30 +++++++++++++++--------------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/libfdt/fdt_overlay.c b/libfdt/fdt_overlay.c index c7e5508..322e7ad 100644 --- a/libfdt/fdt_overlay.c +++ b/libfdt/fdt_overlay.c @@ -234,9 +234,9 @@ static int overlay_update_local_node_references(void *fdto, } for (i = 0; i < (fixup_len / sizeof(uint32_t)); i++) { - uint32_t adj_val, index; + uint32_t adj_val, poffset; - index = fdt32_to_cpu(fixup_val[i]); + poffset = fdt32_to_cpu(fixup_val[i]); /* * phandles to fixup can be unaligned. @@ -244,7 +244,7 @@ static int overlay_update_local_node_references(void *fdto, * Use a memcpy for the architectures that do * not support unaligned accesses. */ - memcpy(&adj_val, tree_val + index, sizeof(adj_val)); + memcpy(&adj_val, tree_val + poffset, sizeof(adj_val)); adj_val = fdt32_to_cpu(adj_val); adj_val += delta; @@ -254,7 +254,7 @@ static int overlay_update_local_node_references(void *fdto, tree_node, name, strlen(name), - index, + poffset, &adj_val, sizeof(adj_val)); if (ret == -FDT_ERR_NOSPACE) @@ -332,7 +332,7 @@ static int overlay_update_local_references(void *fdto, uint32_t delta) * @path_len: number of path characters to consider * @name: Name of the property holding the phandle reference in the overlay * @name_len: number of name characters to consider - * @index: Index in the overlay property where the phandle is stored + * @poffset: Offset within the overlay property where the phandle is stored * @label: Label of the node referenced by the phandle * * overlay_fixup_one_phandle() resolves an overlay phandle pointing to @@ -350,7 +350,7 @@ static int overlay_fixup_one_phandle(void *fdt, void *fdto, int symbols_off, const char *path, uint32_t path_len, const char *name, uint32_t name_len, - int index, const char *label) + int poffset, const char *label) { const char *symbol_path; uint32_t phandle; @@ -378,7 +378,7 @@ static int overlay_fixup_one_phandle(void *fdt, void *fdto, phandle = cpu_to_fdt32(phandle); return fdt_setprop_inplace_namelen_partial(fdto, fixup_off, - name, name_len, index, + name, name_len, poffset, &phandle, sizeof(phandle)); }; @@ -423,7 +423,7 @@ static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off, uint32_t path_len, name_len; uint32_t fixup_len; char *sep, *endptr; - int index, ret; + int poffset, ret; fixup_end = memchr(value, '\0', len); if (!fixup_end) @@ -452,13 +452,13 @@ static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off, if (!name_len) return -FDT_ERR_BADOVERLAY; - index = strtoul(sep + 1, &endptr, 10); + poffset = strtoul(sep + 1, &endptr, 10); if ((*endptr != '\0') || (endptr <= (sep + 1))) return -FDT_ERR_BADOVERLAY; ret = overlay_fixup_one_phandle(fdt, fdto, symbols_off, path, path_len, name, name_len, - index, label); + poffset, label); if (ret) return ret; } while (len > 0); diff --git a/tests/overlay.c b/tests/overlay.c index e467b03..961ed60 100644 --- a/tests/overlay.c +++ b/tests/overlay.c @@ -34,9 +34,9 @@ /* 4k ought to be enough for anybody */ #define FDT_COPY_SIZE (4 * 1024) -static int fdt_getprop_u32_by_index(void *fdt, const char *path, - const char *name, int index, - unsigned long *out) +static int fdt_getprop_u32_by_poffset(void *fdt, const char *path, + const char *name, int poffset, + unsigned long *out) { const fdt32_t *val; int node_off; @@ -47,10 +47,10 @@ static int fdt_getprop_u32_by_index(void *fdt, const char *path, return node_off; val = fdt_getprop(fdt, node_off, name, &len); - if (!val || (len < (sizeof(uint32_t) * (index + 1)))) + if (!val || (len < (sizeof(uint32_t) * (poffset + 1)))) return -FDT_ERR_NOTFOUND; - *out = fdt32_to_cpu(*(val + index)); + *out = fdt32_to_cpu(*(val + poffset)); return 0; } @@ -141,14 +141,14 @@ static int fdt_overlay_local_phandle(void *fdt) local_phandle = fdt_get_phandle(fdt, off); CHECK(!local_phandle); - CHECK(fdt_getprop_u32_by_index(fdt, "/test-node", - "test-several-phandle", - 0, &val)); + CHECK(fdt_getprop_u32_by_poffset(fdt, "/test-node", + "test-several-phandle", + 0, &val)); CHECK(val != local_phandle); - CHECK(fdt_getprop_u32_by_index(fdt, "/test-node", - "test-several-phandle", - 1, &val)); + CHECK(fdt_getprop_u32_by_poffset(fdt, "/test-node", + "test-several-phandle", + 1, &val)); CHECK(val != local_phandle); return 0; @@ -172,12 +172,12 @@ static int fdt_overlay_local_phandles(void *fdt) test_phandle = fdt_get_phandle(fdt, off); CHECK(!test_phandle); - CHECK(fdt_getprop_u32_by_index(fdt, "/test-node", - "test-phandle", 0, &val)); + CHECK(fdt_getprop_u32_by_poffset(fdt, "/test-node", + "test-phandle", 0, &val)); CHECK(test_phandle != val); - CHECK(fdt_getprop_u32_by_index(fdt, "/test-node", - "test-phandle", 1, &val)); + CHECK(fdt_getprop_u32_by_poffset(fdt, "/test-node", + "test-phandle", 1, &val)); CHECK(local_phandle != val); return 0; From deb0a5c1aeaa34130305d765251bbb76e888f4e7 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 6 Oct 2016 13:39:56 +0200 Subject: [PATCH 34/71] libfdt: Add BADPHANDLE error string The BADPHANDLE error was missing a string, leading to an string being returned if you were to call fdt_strerror. Signed-off-by: Maxime Ripard Signed-off-by: David Gibson --- libfdt/fdt_strerror.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libfdt/fdt_strerror.c b/libfdt/fdt_strerror.c index 3cb357f..e00fcb1 100644 --- a/libfdt/fdt_strerror.c +++ b/libfdt/fdt_strerror.c @@ -69,6 +69,7 @@ static struct fdt_errtabent fdt_errtable[] = { FDT_ERRTABENT(FDT_ERR_BADOFFSET), FDT_ERRTABENT(FDT_ERR_BADPATH), + FDT_ERRTABENT(FDT_ERR_BADPHANDLE), FDT_ERRTABENT(FDT_ERR_BADSTATE), FDT_ERRTABENT(FDT_ERR_TRUNCATED), From cabbaa972cddb193dbe170f3797825a5d4ca66fa Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 6 Oct 2016 13:39:57 +0200 Subject: [PATCH 35/71] libfdt: overlay: Report a bad overlay for mismatching local fixups The __local_fixups__ node as a structure that mimics the structure of the main overlay part. This means that if we have a child node somewhere in the local fixups sub-tree and if that node is not present in the main tree, the overlay is poorly formatted, and we should report it as such. Signed-off-by: Maxime Ripard Signed-off-by: David Gibson --- libfdt/fdt_overlay.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libfdt/fdt_overlay.c b/libfdt/fdt_overlay.c index 322e7ad..2f306e4 100644 --- a/libfdt/fdt_overlay.c +++ b/libfdt/fdt_overlay.c @@ -272,6 +272,8 @@ static int overlay_update_local_node_references(void *fdto, tree_child = fdt_subnode_offset(fdto, tree_node, fixup_child_name); + if (ret == -FDT_ERR_NOTFOUND) + return -FDT_ERR_BADOVERLAY; if (tree_child < 0) return tree_child; From 7a72d89d3f8112c1f4065d43e636aa572278f42e Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 6 Oct 2016 13:39:58 +0200 Subject: [PATCH 36/71] libfdt: overlay: Fix symbols and fixups nodes condition Some base device tree might not have any __symbols__ nodes, since they might not have any phandle at all. Similarly, if an overlay doesn't use any base device tree phandles, its __fixups__ node will be empty. In such cases, we don't want to stop the phandle parsing, but rather just ignore the error reported about the missing node. If it's actually an issue for the overlay we're trying to apply on a given base device tree, it will be caught later on, but we cannot make the assumption that early in the application process. Signed-off-by: Maxime Ripard Signed-off-by: David Gibson --- libfdt/fdt_overlay.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/libfdt/fdt_overlay.c b/libfdt/fdt_overlay.c index 2f306e4..bb41404 100644 --- a/libfdt/fdt_overlay.c +++ b/libfdt/fdt_overlay.c @@ -492,13 +492,12 @@ static int overlay_fixup_phandles(void *fdt, void *fdto) /* We can have overlays without any fixups */ fixups_off = fdt_path_offset(fdto, "/__fixups__"); - if (fixups_off == -FDT_ERR_NOTFOUND) - return 0; - if (fixups_off < 0) + if ((fixups_off < 0 && (fixups_off != -FDT_ERR_NOTFOUND))) return fixups_off; + /* And base DTs without symbols */ symbols_off = fdt_path_offset(fdt, "/__symbols__"); - if (symbols_off < 0) + if ((symbols_off < 0 && (symbols_off != -FDT_ERR_NOTFOUND))) return symbols_off; fdt_for_each_property_offset(property, fdto, fixups_off) { From e8c3a1a493fa96153badd4b8a831edfb96d5bdc7 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 6 Oct 2016 13:39:59 +0200 Subject: [PATCH 37/71] tests: overlay: Move back the bad fixup tests The bad fixups tests were meant to be usable even for a non-overlay-enabled dtc. Move them out of that check. Signed-off-by: Maxime Ripard Signed-off-by: David Gibson --- tests/run_tests.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/run_tests.sh b/tests/run_tests.sh index 10b41bc..dc19f80 100755 --- a/tests/run_tests.sh +++ b/tests/run_tests.sh @@ -181,14 +181,14 @@ overlay_tests () { run_dtc_test -@ -I dts -O dtb -o overlay_base.dtb overlay_base.dts run_dtc_test -@ -I dts -O dtb -o overlay_overlay.dtb overlay_overlay_dtc.dts run_test overlay overlay_base.dtb overlay_overlay.dtb - - # Bad fixup tests - for test in $BAD_FIXUP_TREES; do - tree="overlay_bad_fixup_$test" - run_dtc_test -I dts -O dtb -o $tree.dtb $tree.dts - run_test overlay_bad_fixup overlay_base.dtb $tree.dtb - done fi + + # Bad fixup tests + for test in $BAD_FIXUP_TREES; do + tree="overlay_bad_fixup_$test" + run_dtc_test -I dts -O dtb -o $tree.dtb $tree.dts + run_test overlay_bad_fixup overlay_base.dtb $tree.dtb + done } tree1_tests () { From 804a9db90ad284d2c2e24978d68ca40ec638a15f Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 11 Oct 2016 10:10:31 +0200 Subject: [PATCH 38/71] fdt: strerr: Remove spurious BADOVERLAY There's one FDT_ERR_BADOVERLAY too many in the fdt error table. Signed-off-by: Maxime Ripard Signed-off-by: David Gibson --- libfdt/fdt_strerror.c | 1 - 1 file changed, 1 deletion(-) diff --git a/libfdt/fdt_strerror.c b/libfdt/fdt_strerror.c index e00fcb1..4ab3eb7 100644 --- a/libfdt/fdt_strerror.c +++ b/libfdt/fdt_strerror.c @@ -78,7 +78,6 @@ static struct fdt_errtabent fdt_errtable[] = { FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE), FDT_ERRTABENT(FDT_ERR_BADLAYOUT), FDT_ERRTABENT(FDT_ERR_BADOVERLAY), - FDT_ERRTABENT(FDT_ERR_BADOVERLAY), FDT_ERRTABENT(FDT_ERR_NOPHANDLES), }; #define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0])) From 5ce8634733b70c2051a2a88fd7255f1a5b1a0903 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 11 Oct 2016 10:10:32 +0200 Subject: [PATCH 39/71] libfdt: Add fdt_overlay_apply to the exported symbols fdt_overlay_apply was not usable in the shared library. Export it to allow its use. Signed-off-by: Maxime Ripard Signed-off-by: David Gibson --- libfdt/version.lds | 1 + 1 file changed, 1 insertion(+) diff --git a/libfdt/version.lds b/libfdt/version.lds index 1f4e1ea..cff0358 100644 --- a/libfdt/version.lds +++ b/libfdt/version.lds @@ -61,6 +61,7 @@ LIBFDT_1.2 { fdt_size_cells; fdt_stringlist_contains; fdt_resize; + fdt_overlay_apply; local: *; From 96162d2bd9cbea74c57a523b3145b8abbfd32c8d Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 11 Oct 2016 10:10:33 +0200 Subject: [PATCH 40/71] tests: overlay: Add test suffix to the compiled blobs The compiled blobs in the overlay tests do not have the test suffix which is usually used to clean up and ignore the test artifacts. Let's add that suffix. Signed-off-by: Maxime Ripard Signed-off-by: David Gibson --- tests/run_tests.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/run_tests.sh b/tests/run_tests.sh index dc19f80..b49fa62 100755 --- a/tests/run_tests.sh +++ b/tests/run_tests.sh @@ -171,23 +171,23 @@ BAD_FIXUP_TREES="bad_index \ overlay_tests () { # Overlay tests that don't require overlay support in dtc - run_dtc_test -I dts -O dtb -o overlay_base.dtb overlay_base.dts - run_dtc_test -I dts -O dtb -o overlay_overlay.dtb overlay_overlay_nodtc.dts - run_test overlay overlay_base.dtb overlay_overlay.dtb + run_dtc_test -I dts -O dtb -o overlay_base.test.dtb overlay_base.dts + run_dtc_test -I dts -O dtb -o overlay_overlay.test.dtb overlay_overlay_nodtc.dts + run_test overlay overlay_base.test.dtb overlay_overlay.test.dtb # Overlay tests that requires overlay support in dtc echo "/dts-v1/; / {};" | $DTC -@ > /dev/null 2>&1 if [ $? -eq 0 ]; then - run_dtc_test -@ -I dts -O dtb -o overlay_base.dtb overlay_base.dts - run_dtc_test -@ -I dts -O dtb -o overlay_overlay.dtb overlay_overlay_dtc.dts - run_test overlay overlay_base.dtb overlay_overlay.dtb + run_dtc_test -@ -I dts -O dtb -o overlay_base.test.dtb overlay_base.dts + run_dtc_test -@ -I dts -O dtb -o overlay_overlay.test.dtb overlay_overlay_dtc.dts + run_test overlay overlay_base.test.dtb overlay_overlay.test.dtb fi # Bad fixup tests for test in $BAD_FIXUP_TREES; do tree="overlay_bad_fixup_$test" - run_dtc_test -I dts -O dtb -o $tree.dtb $tree.dts - run_test overlay_bad_fixup overlay_base.dtb $tree.dtb + run_dtc_test -I dts -O dtb -o $tree.test.dtb $tree.dts + run_test overlay_bad_fixup overlay_base.test.dtb $tree.test.dtb done } From ae97c7722840148b636ac8fde2de3d0a24c04cfc Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 11 Oct 2016 16:44:07 +0200 Subject: [PATCH 41/71] tests: overlay: Rename the device tree blobs to be more explicit Rename the blobs to have a more explicit output that will give us a clearer idea about whether a DT (and the test) has been compiled using a dtc with our without overlays support. Signed-off-by: Maxime Ripard Signed-off-by: David Gibson --- tests/run_tests.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/run_tests.sh b/tests/run_tests.sh index b49fa62..e4139dd 100755 --- a/tests/run_tests.sh +++ b/tests/run_tests.sh @@ -171,23 +171,23 @@ BAD_FIXUP_TREES="bad_index \ overlay_tests () { # Overlay tests that don't require overlay support in dtc - run_dtc_test -I dts -O dtb -o overlay_base.test.dtb overlay_base.dts - run_dtc_test -I dts -O dtb -o overlay_overlay.test.dtb overlay_overlay_nodtc.dts - run_test overlay overlay_base.test.dtb overlay_overlay.test.dtb + run_dtc_test -I dts -O dtb -o overlay_base_no_symbols.test.dtb overlay_base.dts + run_dtc_test -I dts -O dtb -o overlay_overlay_no_symbols.test.dtb overlay_overlay_nodtc.dts + run_test overlay overlay_base_no_symbols.test.dtb overlay_overlay_no_symbols.test.dtb # Overlay tests that requires overlay support in dtc echo "/dts-v1/; / {};" | $DTC -@ > /dev/null 2>&1 if [ $? -eq 0 ]; then - run_dtc_test -@ -I dts -O dtb -o overlay_base.test.dtb overlay_base.dts - run_dtc_test -@ -I dts -O dtb -o overlay_overlay.test.dtb overlay_overlay_dtc.dts - run_test overlay overlay_base.test.dtb overlay_overlay.test.dtb + run_dtc_test -@ -I dts -O dtb -o overlay_base_with_symbols.test.dtb overlay_base.dts + run_dtc_test -@ -I dts -O dtb -o overlay_overlay_with_symbols.test.dtb overlay_overlay_dtc.dts + run_test overlay overlay_base_with_symbols.test.dtb overlay_overlay_with_symbols.test.dtb fi # Bad fixup tests for test in $BAD_FIXUP_TREES; do tree="overlay_bad_fixup_$test" run_dtc_test -I dts -O dtb -o $tree.test.dtb $tree.dts - run_test overlay_bad_fixup overlay_base.test.dtb $tree.test.dtb + run_test overlay_bad_fixup overlay_base_no_symbols.test.dtb $tree.test.dtb done } From e28eff5b787adb3f461d1653598818b2f1f25a73 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 17 Oct 2016 15:08:23 +0900 Subject: [PATCH 42/71] libfdt: fix fdt_stringlist_count() If fdt_getprop() fails, negative error code should be returned. Signed-off-by: Masahiro Yamada Signed-off-by: David Gibson --- libfdt/fdt_ro.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libfdt/fdt_ro.c b/libfdt/fdt_ro.c index 0459098..db8d10f 100644 --- a/libfdt/fdt_ro.c +++ b/libfdt/fdt_ro.c @@ -571,7 +571,7 @@ int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property) list = fdt_getprop(fdt, nodeoffset, property, &length); if (!list) - return -length; + return length; end = list + length; From daa75e8fa5942caa8e97931aed3a1ee0b7edd74b Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 17 Oct 2016 15:08:24 +0900 Subject: [PATCH 43/71] libfdt: fix fdt_stringlist_search() If fdt_getprop() fails, negative error code should be returned. Signed-off-by: Masahiro Yamada Signed-off-by: David Gibson --- libfdt/fdt_ro.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libfdt/fdt_ro.c b/libfdt/fdt_ro.c index db8d10f..3d00d2e 100644 --- a/libfdt/fdt_ro.c +++ b/libfdt/fdt_ro.c @@ -597,7 +597,7 @@ int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property, list = fdt_getprop(fdt, nodeoffset, property, &length); if (!list) - return -length; + return length; len = strlen(string) + 1; end = list + length; From ea10f953878feea45ccdae846dbd3382e79e7f7e Mon Sep 17 00:00:00 2001 From: Benjamin Fair Date: Thu, 3 Nov 2016 10:47:42 -0500 Subject: [PATCH 44/71] libfdt: add missing errors to fdt_strerror() Some error values were missing from the table which meant that they could not be translated by fdt_strerror(). Signed-off-by: Benjamin Fair Signed-off-by: David Gibson --- libfdt/fdt_strerror.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libfdt/fdt_strerror.c b/libfdt/fdt_strerror.c index 4ab3eb7..9677a18 100644 --- a/libfdt/fdt_strerror.c +++ b/libfdt/fdt_strerror.c @@ -77,6 +77,9 @@ static struct fdt_errtabent fdt_errtable[] = { FDT_ERRTABENT(FDT_ERR_BADVERSION), FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE), FDT_ERRTABENT(FDT_ERR_BADLAYOUT), + FDT_ERRTABENT(FDT_ERR_INTERNAL), + FDT_ERRTABENT(FDT_ERR_BADNCELLS), + FDT_ERRTABENT(FDT_ERR_BADVALUE), FDT_ERRTABENT(FDT_ERR_BADOVERLAY), FDT_ERRTABENT(FDT_ERR_NOPHANDLES), }; From 8f70ac39801d9bb388e2aaebbc9fe9d2a438a151 Mon Sep 17 00:00:00 2001 From: Pantelis Antoniou Date: Fri, 25 Nov 2016 14:32:08 +0200 Subject: [PATCH 45/71] checks: Pass boot_info instead of root node As preparation for overlay support we need to pass the boot info parameter instead of the root node to each check method. The root node can be retrieved by accessing boot info's dt member. No other functional changes are made. Signed-off-by: Pantelis Antoniou Signed-off-by: David Gibson --- checks.c | 78 ++++++++++++++++++++++++++++++-------------------------- 1 file changed, 42 insertions(+), 36 deletions(-) diff --git a/checks.c b/checks.c index 0381c98..2bd27a4 100644 --- a/checks.c +++ b/checks.c @@ -40,7 +40,7 @@ enum checkstatus { struct check; -typedef void (*check_fn)(struct check *c, struct node *dt, struct node *node); +typedef void (*check_fn)(struct check *c, struct boot_info *bi, struct node *node); struct check { const char *name; @@ -97,20 +97,21 @@ static inline void check_msg(struct check *c, const char *fmt, ...) check_msg((c), __VA_ARGS__); \ } while (0) -static void check_nodes_props(struct check *c, struct node *dt, struct node *node) +static void check_nodes_props(struct check *c, struct boot_info *bi, struct node *node) { struct node *child; TRACE(c, "%s", node->fullpath); if (c->fn) - c->fn(c, dt, node); + c->fn(c, bi, node); for_each_child(node, child) - check_nodes_props(c, dt, child); + check_nodes_props(c, bi, child); } -static bool run_check(struct check *c, struct node *dt) +static bool run_check(struct check *c, struct boot_info *bi) { + struct node *dt = bi->dt; bool error = false; int i; @@ -123,7 +124,7 @@ static bool run_check(struct check *c, struct node *dt) for (i = 0; i < c->num_prereqs; i++) { struct check *prq = c->prereq[i]; - error = error || run_check(prq, dt); + error = error || run_check(prq, bi); if (prq->status != PASSED) { c->status = PREREQ; check_msg(c, "Failed prerequisite '%s'", @@ -134,7 +135,7 @@ static bool run_check(struct check *c, struct node *dt) if (c->status != UNCHECKED) goto out; - check_nodes_props(c, dt, dt); + check_nodes_props(c, bi, dt); if (c->status == UNCHECKED) c->status = PASSED; @@ -153,14 +154,14 @@ out: */ /* A check which always fails, for testing purposes only */ -static inline void check_always_fail(struct check *c, struct node *dt, +static inline void check_always_fail(struct check *c, struct boot_info *bi, struct node *node) { FAIL(c, "always_fail check"); } CHECK(always_fail, check_always_fail, NULL); -static void check_is_string(struct check *c, struct node *root, +static void check_is_string(struct check *c, struct boot_info *bi, struct node *node) { struct property *prop; @@ -179,7 +180,7 @@ static void check_is_string(struct check *c, struct node *root, #define ERROR_IF_NOT_STRING(nm, propname) \ ERROR(nm, check_is_string, (propname)) -static void check_is_cell(struct check *c, struct node *root, +static void check_is_cell(struct check *c, struct boot_info *bi, struct node *node) { struct property *prop; @@ -202,7 +203,7 @@ static void check_is_cell(struct check *c, struct node *root, * Structural check functions */ -static void check_duplicate_node_names(struct check *c, struct node *dt, +static void check_duplicate_node_names(struct check *c, struct boot_info *bi, struct node *node) { struct node *child, *child2; @@ -217,7 +218,7 @@ static void check_duplicate_node_names(struct check *c, struct node *dt, } ERROR(duplicate_node_names, check_duplicate_node_names, NULL); -static void check_duplicate_property_names(struct check *c, struct node *dt, +static void check_duplicate_property_names(struct check *c, struct boot_info *bi, struct node *node) { struct property *prop, *prop2; @@ -239,7 +240,7 @@ ERROR(duplicate_property_names, check_duplicate_property_names, NULL); #define DIGITS "0123456789" #define PROPNODECHARS LOWERCASE UPPERCASE DIGITS ",._+*#?-" -static void check_node_name_chars(struct check *c, struct node *dt, +static void check_node_name_chars(struct check *c, struct boot_info *bi, struct node *node) { int n = strspn(node->name, c->data); @@ -250,7 +251,7 @@ static void check_node_name_chars(struct check *c, struct node *dt, } ERROR(node_name_chars, check_node_name_chars, PROPNODECHARS "@"); -static void check_node_name_format(struct check *c, struct node *dt, +static void check_node_name_format(struct check *c, struct boot_info *bi, struct node *node) { if (strchr(get_unitname(node), '@')) @@ -259,8 +260,8 @@ static void check_node_name_format(struct check *c, struct node *dt, } ERROR(node_name_format, check_node_name_format, NULL, &node_name_chars); -static void check_unit_address_vs_reg(struct check *c, struct node *dt, - struct node *node) +static void check_unit_address_vs_reg(struct check *c, struct boot_info *bi, + struct node *node) { const char *unitname = get_unitname(node); struct property *prop = get_property(node, "reg"); @@ -283,7 +284,7 @@ static void check_unit_address_vs_reg(struct check *c, struct node *dt, } WARNING(unit_address_vs_reg, check_unit_address_vs_reg, NULL); -static void check_property_name_chars(struct check *c, struct node *dt, +static void check_property_name_chars(struct check *c, struct boot_info *bi, struct node *node) { struct property *prop; @@ -305,10 +306,11 @@ ERROR(property_name_chars, check_property_name_chars, PROPNODECHARS); ((prop) ? (prop)->name : ""), \ ((prop) ? "' in " : ""), (node)->fullpath -static void check_duplicate_label(struct check *c, struct node *dt, +static void check_duplicate_label(struct check *c, struct boot_info *bi, const char *label, struct node *node, struct property *prop, struct marker *mark) { + struct node *dt = bi->dt; struct node *othernode = NULL; struct property *otherprop = NULL; struct marker *othermark = NULL; @@ -331,30 +333,31 @@ static void check_duplicate_label(struct check *c, struct node *dt, DESCLABEL_ARGS(othernode, otherprop, othermark)); } -static void check_duplicate_label_node(struct check *c, struct node *dt, +static void check_duplicate_label_node(struct check *c, struct boot_info *bi, struct node *node) { struct label *l; struct property *prop; for_each_label(node->labels, l) - check_duplicate_label(c, dt, l->label, node, NULL, NULL); + check_duplicate_label(c, bi, l->label, node, NULL, NULL); for_each_property(node, prop) { struct marker *m = prop->val.markers; for_each_label(prop->labels, l) - check_duplicate_label(c, dt, l->label, node, prop, NULL); + check_duplicate_label(c, bi, l->label, node, prop, NULL); for_each_marker_of_type(m, LABEL) - check_duplicate_label(c, dt, m->ref, node, prop, m); + check_duplicate_label(c, bi, m->ref, node, prop, m); } } ERROR(duplicate_label, check_duplicate_label_node, NULL); -static cell_t check_phandle_prop(struct check *c, struct node *root, +static cell_t check_phandle_prop(struct check *c, struct boot_info *bi, struct node *node, const char *propname) { + struct node *root = bi->dt; struct property *prop; struct marker *m; cell_t phandle; @@ -398,18 +401,19 @@ static cell_t check_phandle_prop(struct check *c, struct node *root, return phandle; } -static void check_explicit_phandles(struct check *c, struct node *root, +static void check_explicit_phandles(struct check *c, struct boot_info *bi, struct node *node) { + struct node *root = bi->dt; struct node *other; cell_t phandle, linux_phandle; /* Nothing should have assigned phandles yet */ assert(!node->phandle); - phandle = check_phandle_prop(c, root, node, "phandle"); + phandle = check_phandle_prop(c, bi, node, "phandle"); - linux_phandle = check_phandle_prop(c, root, node, "linux,phandle"); + linux_phandle = check_phandle_prop(c, bi, node, "linux,phandle"); if (!phandle && !linux_phandle) /* No valid phandles; nothing further to check */ @@ -433,7 +437,7 @@ static void check_explicit_phandles(struct check *c, struct node *root, } ERROR(explicit_phandles, check_explicit_phandles, NULL); -static void check_name_properties(struct check *c, struct node *root, +static void check_name_properties(struct check *c, struct boot_info *bi, struct node *node) { struct property **pp, *prop = NULL; @@ -467,9 +471,10 @@ ERROR(name_properties, check_name_properties, NULL, &name_is_string); * Reference fixup functions */ -static void fixup_phandle_references(struct check *c, struct node *dt, +static void fixup_phandle_references(struct check *c, struct boot_info *bi, struct node *node) { + struct node *dt = bi->dt; struct property *prop; for_each_property(node, prop) { @@ -495,9 +500,10 @@ static void fixup_phandle_references(struct check *c, struct node *dt, ERROR(phandle_references, fixup_phandle_references, NULL, &duplicate_node_names, &explicit_phandles); -static void fixup_path_references(struct check *c, struct node *dt, +static void fixup_path_references(struct check *c, struct boot_info *bi, struct node *node) { + struct node *dt = bi->dt; struct property *prop; for_each_property(node, prop) { @@ -534,7 +540,7 @@ WARNING_IF_NOT_STRING(device_type_is_string, "device_type"); WARNING_IF_NOT_STRING(model_is_string, "model"); WARNING_IF_NOT_STRING(status_is_string, "status"); -static void fixup_addr_size_cells(struct check *c, struct node *dt, +static void fixup_addr_size_cells(struct check *c, struct boot_info *bi, struct node *node) { struct property *prop; @@ -558,7 +564,7 @@ WARNING(addr_size_cells, fixup_addr_size_cells, NULL, #define node_size_cells(n) \ (((n)->size_cells == -1) ? 1 : (n)->size_cells) -static void check_reg_format(struct check *c, struct node *dt, +static void check_reg_format(struct check *c, struct boot_info *bi, struct node *node) { struct property *prop; @@ -587,7 +593,7 @@ static void check_reg_format(struct check *c, struct node *dt, } WARNING(reg_format, check_reg_format, NULL, &addr_size_cells); -static void check_ranges_format(struct check *c, struct node *dt, +static void check_ranges_format(struct check *c, struct boot_info *bi, struct node *node) { struct property *prop; @@ -631,7 +637,7 @@ WARNING(ranges_format, check_ranges_format, NULL, &addr_size_cells); /* * Style checks */ -static void check_avoid_default_addr_size(struct check *c, struct node *dt, +static void check_avoid_default_addr_size(struct check *c, struct boot_info *bi, struct node *node) { struct property *reg, *ranges; @@ -657,9 +663,10 @@ WARNING(avoid_default_addr_size, check_avoid_default_addr_size, NULL, &addr_size_cells); static void check_obsolete_chosen_interrupt_controller(struct check *c, - struct node *dt, + struct boot_info *bi, struct node *node) { + struct node *dt = bi->dt; struct node *chosen; struct property *prop; @@ -765,7 +772,6 @@ void parse_checks_option(bool warn, bool error, const char *arg) void process_checks(bool force, struct boot_info *bi) { - struct node *dt = bi->dt; int i; int error = 0; @@ -773,7 +779,7 @@ void process_checks(bool force, struct boot_info *bi) struct check *c = check_table[i]; if (c->warn || c->error) - error = error || run_check(c, dt); + error = error || run_check(c, bi); } if (error) { From a2c92cac53f806e6c1936c1c522a6c24a5ec7199 Mon Sep 17 00:00:00 2001 From: Pantelis Antoniou Date: Wed, 7 Dec 2016 14:48:17 +0200 Subject: [PATCH 46/71] dtc: Document the dynamic plugin internals Provides the document explaining the internal mechanics of plugins and options. Signed-off-by: Pantelis Antoniou Signed-off-by: David Gibson --- Documentation/dt-object-internal.txt | 310 +++++++++++++++++++++++++++ 1 file changed, 310 insertions(+) create mode 100644 Documentation/dt-object-internal.txt diff --git a/Documentation/dt-object-internal.txt b/Documentation/dt-object-internal.txt new file mode 100644 index 0000000..51d68ab --- /dev/null +++ b/Documentation/dt-object-internal.txt @@ -0,0 +1,310 @@ +Device Tree Dynamic Object format internals +------------------------------------------- + +The Device Tree for most platforms is a static representation of +the hardware capabilities. This is insufficient for platforms +that need to dynamically insert Device Tree fragments into the +live tree. + +This document explains the the Device Tree object format and +modifications made to the Device Tree compiler, which make it possible. + +1. Simplified Problem Definition +-------------------------------- + +Assume we have a platform which boots using following simplified Device Tree. + +---- foo.dts ----------------------------------------------------------------- + /* FOO platform */ + / { + compatible = "corp,foo"; + + /* shared resources */ + res: res { + }; + + /* On chip peripherals */ + ocp: ocp { + /* peripherals that are always instantiated */ + peripheral1 { ... }; + }; + }; +---- foo.dts ----------------------------------------------------------------- + +We have a number of peripherals that after probing (using some undefined method) +should result in different Device Tree configuration. + +We cannot boot with this static tree because due to the configuration of the +foo platform there exist multiple conficting peripherals DT fragments. + +So for the bar peripheral we would have this: + +---- foo+bar.dts ------------------------------------------------------------- + /* FOO platform + bar peripheral */ + / { + compatible = "corp,foo"; + + /* shared resources */ + res: res { + }; + + /* On chip peripherals */ + ocp: ocp { + /* peripherals that are always instantiated */ + peripheral1 { ... }; + + /* bar peripheral */ + bar { + compatible = "corp,bar"; + ... /* various properties and child nodes */ + }; + }; + }; +---- foo+bar.dts ------------------------------------------------------------- + +While for the baz peripheral we would have this: + +---- foo+baz.dts ------------------------------------------------------------- + /* FOO platform + baz peripheral */ + / { + compatible = "corp,foo"; + + /* shared resources */ + res: res { + /* baz resources */ + baz_res: res_baz { ... }; + }; + + /* On chip peripherals */ + ocp: ocp { + /* peripherals that are always instantiated */ + peripheral1 { ... }; + + /* baz peripheral */ + baz { + compatible = "corp,baz"; + /* reference to another point in the tree */ + ref-to-res = <&baz_res>; + ... /* various properties and child nodes */ + }; + }; + }; +---- foo+baz.dts ------------------------------------------------------------- + +We note that the baz case is more complicated, since the baz peripheral needs to +reference another node in the DT tree. + +2. Device Tree Object Format Requirements +----------------------------------------- + +Since the Device Tree is used for booting a number of very different hardware +platforms it is imperative that we tread very carefully. + +2.a) No changes to the Device Tree binary format for the base tree. We cannot +modify the tree format at all and all the information we require should be +encoded using Device Tree itself. We can add nodes that can be safely ignored +by both bootloaders and the kernel. The plugin dtbs are optionally tagged +with a different magic number in the header but otherwise they're simple +blobs. + +2.b) Changes to the DTS source format should be absolutely minimal, and should +only be needed for the DT fragment definitions, and not the base boot DT. + +2.c) An explicit option should be used to instruct DTC to generate the required +information needed for object resolution. Platforms that don't use the +dynamic object format can safely ignore it. + +2.d) Finally, DT syntax changes should be kept to a minimum. It should be +possible to express everything using the existing DT syntax. + +3. Implementation +----------------- + +The basic unit of addressing in Device Tree is the phandle. Turns out it's +relatively simple to extend the way phandles are generated and referenced +so that it's possible to dynamically convert symbolic references (labels) +to phandle values. This is a valid assumption as long as the author uses +reference syntax and does not assign phandle values manually (which might +be a problem with decompiled source files). + +We can roughly divide the operation into two steps. + +3.a) Compilation of the base board DTS file using the '-@' option +generates a valid DT blob with an added __symbols__ node at the root node, +containing a list of all nodes that are marked with a label. + +Using the foo.dts file above the following node will be generated; + +$ dtc -@ -O dtb -o foo.dtb -b 0 foo.dts +$ fdtdump foo.dtb +... +/ { + ... + res { + ... + phandle = <0x00000001>; + ... + }; + ocp { + ... + phandle = <0x00000002>; + ... + }; + __symbols__ { + res="/res"; + ocp="/ocp"; + }; +}; + +Notice that all the nodes that had a label have been recorded, and that +phandles have been generated for them. + +This blob can be used to boot the board normally, the __symbols__ node will +be safely ignored both by the bootloader and the kernel (the only loss will +be a few bytes of memory and disk space). + +We generate a __symbols__ node to record nodes that had labels in the base +tree (or subsequent loaded overlays) so that they can be matched up with +references made to them in Device Tree objects. + +3.b) The Device Tree fragments must be compiled with the same option but they +must also have a tag (/plugin/) that allows undefined references to nodes +that are not present at compilation time to be recorded so that the runtime +loader can fix them. + +So the bar peripheral's DTS format would be of the form: + +/dts-v1/; +/plugin/; /* allow undefined references and record them */ +/ { + .... /* various properties for loader use; i.e. part id etc. */ + fragment@0 { + target = <&ocp>; + __overlay__ { + /* bar peripheral */ + bar { + compatible = "corp,bar"; + ... /* various properties and child nodes */ + } + }; + }; +}; + +Note that there's a target property that specifies the location where the +contents of the overlay node will be placed, and it references the node +in the foo.dts file. + +$ dtc -@ -O dtb -o bar.dtbo -b 0 bar.dts +$ fdtdump bar.dtbo +... +/ { + ... /* properties */ + fragment@0 { + target = <0xffffffff>; + __overlay__ { + bar { + compatible = "corp,bar"; + ... /* various properties and child nodes */ + } + }; + }; + __fixups__ { + ocp = "/fragment@0:target:0"; + }; +}; + +No __symbols__ node has been generated (no label in bar.dts). +Note that the target's ocp label is undefined, so the phandle +value is filled with the illegal value '0xffffffff', while a __fixups__ +node has been generated, which marks the location in the tree where +the label lookup should store the runtime phandle value of the ocp node. + +The format of the __fixups__ node entry is + +