[PATCH 12/29] of: make unflatten independent of libfdt
Sascha Hauer
s.hauer at pengutronix.de
Tue Feb 26 15:18:39 EST 2013
Signed-off-by: Sascha Hauer <s.hauer at 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 9f1f3cf..d6ca949 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -969,92 +969,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 89ce64c..f2fd84b 100644
--- a/include/of.h
+++ b/include/of.h
@@ -119,7 +119,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
More information about the barebox
mailing list