Signed-off-by: Sascha Hauer <s.ha...@pengutronix.de>
---
 drivers/of/base.c |  160 +++++++++++++++++++++++++++++++++++++++++------------
 include/of.h      |    2 +-
 2 files changed, 127 insertions(+), 35 deletions(-)

diff --git a/drivers/of/base.c b/drivers/of/base.c
index 4dbe11e..8bb80e6 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -1025,92 +1025,184 @@ out:
        return dn;
 }
 
+static inline uint32_t dt_struct_advance(struct fdt_header *f, uint32_t dt, 
int size)
+{
+       dt += size;
+       dt = ALIGN(dt, 4);
+
+       if (dt > f->off_dt_struct + f->size_dt_struct)
+               return 0;
+
+       return dt;
+}
+
+static inline char *dt_string(struct fdt_header *f, char *strstart, uint32_t 
ofs)
+{
+       if (ofs > f->size_dt_strings)
+               return NULL;
+       else
+               return strstart + ofs;
+}
+
 /**
- * of_unflatten_dtb - unflatten a fdt blob
+ * of_unflatten_dtb - unflatten a dtb binary blob
  * @root - node in which the fdt blob should be merged into or NULL
- * @fdt - the fdt blob to unflatten
+ * @infdt - the fdt blob to unflatten
  *
  * Parse a flat device tree binary blob and return a pointer to the
  * unflattened tree.
  */
-struct device_node *of_unflatten_dtb(struct device_node *root, struct 
fdt_header *fdt)
+struct device_node *of_unflatten_dtb(struct device_node *root, void *infdt)
 {
        const void *nodep;      /* property node pointer */
-       int  nodeoffset;        /* node offset from libfdt */
-       int  nextoffset;        /* next node offset from libfdt */
        uint32_t tag;           /* tag */
        int  len;               /* length of the property */
        const struct fdt_property *fdt_prop;
-       const char *pathp;
+       const char *pathp, *name;
        struct device_node *node = NULL, *n;
        struct property *p;
-       int ret;
+       uint32_t dt_struct;
+       struct fdt_node_header *fnh;
+       void *dt_strings;
+       struct fdt_header f;
+       int ret, merge = 0;
+       unsigned int maxlen;
+       struct fdt_header *fdt = infdt;
+
+       if (fdt->magic != cpu_to_fdt32(FDT_MAGIC)) {
+               pr_err("bad magic: 0x%08x\n", fdt32_to_cpu(fdt->magic));
+               return ERR_PTR(-EINVAL);
+       }
 
-       nodeoffset = fdt_path_offset(fdt, "/");
-       if (nodeoffset < 0) {
-               /*
-                * Not found or something else bad happened.
-                */
-               printf ("libfdt fdt_path_offset() returned %s\n",
-                       fdt_strerror(nodeoffset));
+       if (fdt->version != cpu_to_fdt32(17)) {
+               pr_err("bad dt version: 0x%08x\n", fdt32_to_cpu(fdt->version));
                return ERR_PTR(-EINVAL);
        }
 
-       if (!root) {
+       f.totalsize = fdt32_to_cpu(fdt->totalsize);
+       f.off_dt_struct = fdt32_to_cpu(fdt->off_dt_struct);
+       f.size_dt_struct = fdt32_to_cpu(fdt->size_dt_struct);
+       f.off_dt_strings = fdt32_to_cpu(fdt->off_dt_strings);
+       f.size_dt_strings = fdt32_to_cpu(fdt->size_dt_strings);
+
+       if (f.off_dt_struct + f.size_dt_struct > f.totalsize) {
+               pr_err("unflatten: dt size exceeds total size\n");
+               return ERR_PTR(-ESPIPE);
+       }
+
+       if (f.off_dt_strings + f.size_dt_strings > f.totalsize) {
+               pr_err("unflatten: string size exceeds total size\n");
+               return ERR_PTR(-ESPIPE);
+       }
+
+       dt_struct = f.off_dt_struct;
+       dt_strings = (void *)fdt + f.off_dt_strings;
+
+       if (root) {
+               pr_debug("unflatten: merging into existing tree\n");
+               merge = 1;
+       } else {
                root = of_new_node(NULL, NULL);
                if (!root)
                        return ERR_PTR(-ENOMEM);
        }
 
        while (1) {
-               tag = fdt_next_tag(fdt, nodeoffset, &nextoffset);
+               tag = be32_to_cpu(*(uint32_t *)(infdt + dt_struct));
+
                switch (tag) {
                case FDT_BEGIN_NODE:
-                       pathp = fdt_get_name(fdt, nodeoffset, NULL);
+                       fnh = infdt + dt_struct;
+                       pathp = name = fnh->name;
+                       maxlen = (unsigned long)fdt + f.off_dt_struct +
+                               f.size_dt_struct - (unsigned long)name;
+
+                       len = strnlen(name, maxlen + 1);
+                       if (len > maxlen) {
+                               ret = -ESPIPE;
+                               goto err;
+                       }
 
-                       if (pathp == NULL)
-                               pathp = "/* NULL pointer error */";
+                       dt_struct = dt_struct_advance(&f, dt_struct,
+                                       sizeof(struct fdt_node_header) + len + 
1);
+                       if (!dt_struct) {
+                               ret = -ESPIPE;
+                               goto err;
+                       }
 
                        if (!node) {
                                node = root;
                        } else {
-                               if ((n = of_find_child_by_name(node, pathp))) {
+                               if (merge && (n = of_find_child_by_name(node, 
pathp)))
                                        node = n;
-                               } else {
+                               else
                                        node = of_new_node(node, pathp);
-                               }
                        }
+
                        break;
+
                case FDT_END_NODE:
+                       if (!node) {
+                               pr_err("unflatten: too many end nodes\n");
+                               ret = -EINVAL;
+                               goto err;
+                       }
+
                        node = node->parent;
+
+                       dt_struct = dt_struct_advance(&f, dt_struct, 
FDT_TAGSIZE);
+                       if (!dt_struct) {
+                               ret = -ESPIPE;
+                               goto err;
+                       }
+
                        break;
+
                case FDT_PROP:
-                       fdt_prop = fdt_offset_ptr(fdt, nodeoffset,
-                                       sizeof(*fdt_prop));
-                       pathp    = fdt_string(fdt,
-                                       fdt32_to_cpu(fdt_prop->nameoff));
-                       len      = fdt32_to_cpu(fdt_prop->len);
-                       nodep    = fdt_prop->data;
-
-                       p = of_find_property(node, pathp);
-                       if (p) {
+                       fdt_prop = infdt + dt_struct;
+                       len = fdt32_to_cpu(fdt_prop->len);
+                       nodep = fdt_prop->data;
+
+                       name = dt_string(&f, dt_strings, 
fdt32_to_cpu(fdt_prop->nameoff));
+                       if (!name) {
+                               ret = -ESPIPE;
+                               goto err;
+                       }
+
+                       dt_struct = dt_struct_advance(&f, dt_struct,
+                                       sizeof(struct fdt_property) + len);
+                       if (!dt_struct) {
+                               ret = -ESPIPE;
+                               goto err;
+                       }
+
+                       if (merge && (p = of_find_property(node, name))) {
                                free(p->value);
                                p->value = xzalloc(len);
                                memcpy(p->value, nodep, len);
                        } else {
-                               of_new_property(node, pathp, nodep, len);
+                               of_new_property(node, name, nodep, len);
                        }
+
                        break;
+
                case FDT_NOP:
+                       dt_struct = dt_struct_advance(&f, dt_struct, 
FDT_TAGSIZE);
+                       if (!dt_struct) {
+                               ret = -ESPIPE;
+                               goto err;
+                       }
+
                        break;
+
                case FDT_END:
                        return root;
+
                default:
-                       printf("Unknown tag 0x%08X\n", tag);
+                       pr_err("unflatten: Unknown tag 0x%08X\n", tag);
                        ret = -EINVAL;
                        goto err;
                }
-               nodeoffset = nextoffset;
        }
 err:
        of_free(root);
diff --git a/include/of.h b/include/of.h
index 1562f4e..4622b80 100644
--- a/include/of.h
+++ b/include/of.h
@@ -147,7 +147,7 @@ void of_print_nodes(struct device_node *node, int indent);
 int of_probe(void);
 int of_parse_dtb(struct fdt_header *fdt);
 void of_free(struct device_node *node);
-struct device_node *of_unflatten_dtb(struct device_node *root, struct 
fdt_header *fdt);
+struct device_node *of_unflatten_dtb(struct device_node *root, void *fdt);
 struct device_node *of_new_node(struct device_node *parent, const char *name);
 struct property *of_new_property(struct device_node *node, const char *name,
                const void *data, int len);
-- 
1.7.10.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

Reply via email to