summaryrefslogtreecommitdiff
path: root/scripts/dtc/livetree.c
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/dtc/livetree.c')
-rw-r--r--scripts/dtc/livetree.c230
1 files changed, 167 insertions, 63 deletions
diff --git a/scripts/dtc/livetree.c b/scripts/dtc/livetree.c
index 3673de07e4e5..d51d05830b18 100644
--- a/scripts/dtc/livetree.c
+++ b/scripts/dtc/livetree.c
@@ -1,24 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program 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
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
*/
#include "dtc.h"
+#include "srcpos.h"
/*
* Tree building functions
@@ -50,25 +36,27 @@ void delete_labels(struct label **labels)
label->deleted = 1;
}
-struct property *build_property(char *name, struct data val)
+struct property *build_property(const char *name, struct data val,
+ struct srcpos *srcpos)
{
struct property *new = xmalloc(sizeof(*new));
memset(new, 0, sizeof(*new));
- new->name = name;
+ new->name = xstrdup(name);
new->val = val;
+ new->srcpos = srcpos_copy(srcpos);
return new;
}
-struct property *build_property_delete(char *name)
+struct property *build_property_delete(const char *name)
{
struct property *new = xmalloc(sizeof(*new));
memset(new, 0, sizeof(*new));
- new->name = name;
+ new->name = xstrdup(name);
new->deleted = 1;
return new;
@@ -97,7 +85,8 @@ struct property *reverse_properties(struct property *first)
return head;
}
-struct node *build_node(struct property *proplist, struct node *children)
+struct node *build_node(struct property *proplist, struct node *children,
+ struct srcpos *srcpos)
{
struct node *new = xmalloc(sizeof(*new));
struct node *child;
@@ -106,6 +95,7 @@ struct node *build_node(struct property *proplist, struct node *children)
new->proplist = reverse_properties(proplist);
new->children = children;
+ new->srcpos = srcpos_copy(srcpos);
for_each_child(new, child) {
child->parent = new;
@@ -114,22 +104,37 @@ struct node *build_node(struct property *proplist, struct node *children)
return new;
}
-struct node *build_node_delete(void)
+struct node *build_node_delete(struct srcpos *srcpos)
{
struct node *new = xmalloc(sizeof(*new));
memset(new, 0, sizeof(*new));
new->deleted = 1;
+ new->srcpos = srcpos_copy(srcpos);
return new;
}
-struct node *name_node(struct node *node, char *name)
+struct node *name_node(struct node *node, const char *name)
{
assert(node->name == NULL);
- node->name = name;
+ node->name = xstrdup(name);
+
+ return node;
+}
+
+struct node *omit_node_if_unused(struct node *node)
+{
+ node->omit_if_unused = 1;
+
+ return node;
+}
+
+struct node *reference_node(struct node *node)
+{
+ node->is_referenced = 1;
return node;
}
@@ -169,6 +174,8 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node)
old_prop->val = new_prop->val;
old_prop->deleted = 0;
+ srcpos_free(old_prop->srcpos);
+ old_prop->srcpos = new_prop->srcpos;
free(new_prop);
new_prop = NULL;
break;
@@ -209,6 +216,8 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node)
add_child(old_node, new_child);
}
+ old_node->srcpos = srcpos_extend(old_node->srcpos, new_node->srcpos);
+
/* The new node contents are now merged into the old node. Free
* the new node. */
free(new_node);
@@ -216,6 +225,37 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node)
return old_node;
}
+struct node * add_orphan_node(struct node *dt, struct node *new_node, char *ref)
+{
+ static unsigned int next_orphan_fragment = 0;
+ struct node *node;
+ struct property *p;
+ struct data d = empty_data;
+ char *name;
+
+ if (ref[0] == '/') {
+ d = data_add_marker(d, TYPE_STRING, ref);
+ d = data_append_data(d, ref, strlen(ref) + 1);
+
+ p = build_property("target-path", d, NULL);
+ } else {
+ d = data_add_marker(d, REF_PHANDLE, ref);
+ d = data_append_integer(d, 0xffffffff, 32);
+
+ p = build_property("target", d, NULL);
+ }
+
+ xasprintf(&name, "fragment@%u",
+ next_orphan_fragment++);
+ name_node(new_node, "__overlay__");
+ node = build_node(p, new_node, NULL);
+ name_node(node, name);
+ free(name);
+
+ add_child(dt, node);
+ return dt;
+}
+
struct node *chain_node(struct node *first, struct node *list)
{
assert(first->next_sibling == NULL);
@@ -297,18 +337,21 @@ void delete_node(struct node *node)
}
void append_to_property(struct node *node,
- char *name, const void *data, int len)
+ char *name, const void *data, int len,
+ enum markertype type)
{
struct data d;
struct property *p;
p = get_property(node, name);
if (p) {
- d = data_append_data(p->val, data, len);
+ d = data_add_marker(p->val, type, name);
+ d = data_append_data(d, data, len);
p->val = d;
} else {
- d = data_append_data(empty_data, data, len);
- p = build_property(name, d);
+ d = data_add_marker(empty_data, type, name);
+ d = data_append_data(d, data, len);
+ p = build_property(name, d, NULL);
add_property(node, p);
}
}
@@ -396,6 +439,12 @@ cell_t propval_cell(struct property *prop)
return fdt32_to_cpu(*((fdt32_t *)prop->val.val));
}
+cell_t propval_cell_n(struct property *prop, unsigned int n)
+{
+ assert(prop->val.len / sizeof(cell_t) > n);
+ return fdt32_to_cpu(*((fdt32_t *)prop->val.val + n));
+}
+
struct property *get_property_by_label(struct node *tree, const char *label,
struct node **node)
{
@@ -455,7 +504,7 @@ struct node *get_subnode(struct node *node, const char *nodename)
struct node *child;
for_each_child(node, child)
- if (streq(child->name, nodename))
+ if (streq(child->name, nodename) && !child->deleted)
return child;
return NULL;
@@ -478,7 +527,7 @@ struct node *get_node_by_path(struct node *tree, const char *path)
p = strchr(path, '/');
for_each_child(tree, child) {
- if (p && strneq(path, child->name, p-path))
+ if (p && strprefixeq(path, (size_t)(p - path), child->name))
return get_node_by_path(child, p+1);
else if (!p && streq(path, child->name))
return child;
@@ -511,7 +560,10 @@ struct node *get_node_by_phandle(struct node *tree, cell_t phandle)
{
struct node *child, *node;
- assert((phandle != 0) && (phandle != -1));
+ if (!phandle_is_valid(phandle)) {
+ assert(generate_fixups);
+ return NULL;
+ }
if (tree->phandle == phandle) {
if (tree->deleted)
@@ -530,19 +582,62 @@ struct node *get_node_by_phandle(struct node *tree, cell_t phandle)
struct node *get_node_by_ref(struct node *tree, const char *ref)
{
+ struct node *target = tree;
+ const char *label = NULL, *path = NULL;
+
if (streq(ref, "/"))
return tree;
- else if (ref[0] == '/')
- return get_node_by_path(tree, ref);
+
+ if (ref[0] == '/')
+ path = ref;
else
- return get_node_by_label(tree, ref);
+ label = ref;
+
+ if (label) {
+ const char *slash = strchr(label, '/');
+ char *buf = NULL;
+
+ if (slash) {
+ buf = xstrndup(label, slash - label);
+ label = buf;
+ path = slash + 1;
+ }
+
+ target = get_node_by_label(tree, label);
+
+ free(buf);
+
+ if (!target)
+ return NULL;
+ }
+
+ if (path)
+ target = get_node_by_path(target, path);
+
+ return target;
+}
+
+static void add_phandle_property(struct node *node,
+ const char *name, int format)
+{
+ struct data d;
+
+ if (!(phandle_format & format))
+ return;
+ if (get_property(node, name))
+ return;
+
+ d = data_add_marker(empty_data, TYPE_UINT32, NULL);
+ d = data_append_cell(d, node->phandle);
+
+ add_property(node, build_property(name, d, NULL));
}
cell_t get_node_phandle(struct node *root, struct node *node)
{
static cell_t phandle = 1; /* FIXME: ick, static local */
- if ((node->phandle != 0) && (node->phandle != -1))
+ if (phandle_is_valid(node->phandle))
return node->phandle;
while (get_node_by_phandle(root, phandle))
@@ -550,17 +645,8 @@ cell_t get_node_phandle(struct node *root, struct node *node)
node->phandle = phandle;
- if (!get_property(node, "linux,phandle")
- && (phandle_format & PHANDLE_LEGACY))
- add_property(node,
- build_property("linux,phandle",
- data_append_cell(empty_data, phandle)));
-
- if (!get_property(node, "phandle")
- && (phandle_format & PHANDLE_EPAPR))
- add_property(node,
- build_property("phandle",
- data_append_cell(empty_data, phandle)));
+ add_phandle_property(node, "linux,phandle", PHANDLE_LEGACY);
+ add_phandle_property(node, "phandle", PHANDLE_EPAPR);
/* If the node *does* have a phandle property, we must
* be dealing with a self-referencing phandle, which will be
@@ -730,18 +816,18 @@ void sort_tree(struct dt_info *dti)
}
/* utility helper to avoid code duplication */
-static struct node *build_and_name_child_node(struct node *parent, char *name)
+static struct node *build_and_name_child_node(struct node *parent, const char *name)
{
struct node *node;
- node = build_node(NULL, NULL);
- name_node(node, xstrdup(name));
+ node = build_node(NULL, NULL, NULL);
+ name_node(node, name);
add_child(parent, node);
return node;
}
-static struct node *build_root_node(struct node *dt, char *name)
+static struct node *build_root_node(struct node *dt, const char *name)
{
struct node *an;
@@ -795,8 +881,9 @@ static void generate_label_tree_internal(struct dt_info *dti,
/* insert it */
p = build_property(l->label,
- data_copy_mem(node->fullpath,
- strlen(node->fullpath) + 1));
+ data_copy_escape_string(node->fullpath,
+ strlen(node->fullpath)),
+ NULL);
add_property(an, p);
}
@@ -840,13 +927,19 @@ static void add_fixup_entry(struct dt_info *dti, struct node *fn,
/* m->ref can only be a REF_PHANDLE, but check anyway */
assert(m->type == REF_PHANDLE);
+ /* The format only permits fixups for references to label, not
+ * references to path */
+ if (strchr(m->ref, '/'))
+ die("Can't generate fixup for reference to path &{%s}\n",
+ m->ref);
+
/* there shouldn't be any ':' in the arguments */
if (strchr(node->fullpath, ':') || strchr(prop->name, ':'))
die("arguments should not contain ':'\n");
xasprintf(&entry, "%s:%s:%u",
node->fullpath, prop->name, m->offset);
- append_to_property(fn, m->ref, entry, strlen(entry) + 1);
+ append_to_property(fn, m->ref, entry, strlen(entry) + 1, TYPE_STRING);
free(entry);
}
@@ -906,7 +999,7 @@ static void add_local_fixup_entry(struct dt_info *dti,
char **compp;
int i, depth;
- /* walk back retreiving depth */
+ /* walk back retrieving depth */
depth = 0;
for (wn = node; wn; wn = wn->parent)
depth++;
@@ -921,15 +1014,13 @@ static void add_local_fixup_entry(struct dt_info *dti,
/* walk the path components creating nodes if they don't exist */
for (wn = lfn, i = 1; i < depth; i++, wn = nwn) {
/* if no node exists, create it */
- nwn = get_subnode(wn, compp[i]);
- if (!nwn)
- nwn = build_and_name_child_node(wn, compp[i]);
+ nwn = build_root_node(wn, compp[i]);
}
free(compp);
value_32 = cpu_to_fdt32(m->offset);
- append_to_property(wn, prop->name, &value_32, sizeof(value_32));
+ append_to_property(wn, prop->name, &value_32, sizeof(value_32), TYPE_UINT32);
}
static void generate_local_fixups_tree_internal(struct dt_info *dti,
@@ -955,7 +1046,7 @@ static void generate_local_fixups_tree_internal(struct dt_info *dti,
generate_local_fixups_tree_internal(dti, lfn, c);
}
-void generate_label_tree(struct dt_info *dti, char *name, bool allocph)
+void generate_label_tree(struct dt_info *dti, const char *name, bool allocph)
{
if (!any_label_tree(dti, dti->dt))
return;
@@ -963,18 +1054,31 @@ void generate_label_tree(struct dt_info *dti, char *name, bool allocph)
dti->dt, allocph);
}
-void generate_fixups_tree(struct dt_info *dti, char *name)
+void generate_fixups_tree(struct dt_info *dti, const char *name)
{
+ struct node *n = get_subnode(dti->dt, name);
+
+ /* Start with an empty __fixups__ node to not get duplicates */
+ if (n)
+ n->deleted = true;
+
if (!any_fixup_tree(dti, dti->dt))
return;
- generate_fixups_tree_internal(dti, build_root_node(dti->dt, name),
+ generate_fixups_tree_internal(dti,
+ build_and_name_child_node(dti->dt, name),
dti->dt);
}
-void generate_local_fixups_tree(struct dt_info *dti, char *name)
+void generate_local_fixups_tree(struct dt_info *dti, const char *name)
{
+ struct node *n = get_subnode(dti->dt, name);
+
+ /* Start with an empty __local_fixups__ node to not get duplicates */
+ if (n)
+ n->deleted = true;
if (!any_local_fixup_tree(dti, dti->dt))
return;
- generate_local_fixups_tree_internal(dti, build_root_node(dti->dt, name),
+ generate_local_fixups_tree_internal(dti,
+ build_and_name_child_node(dti->dt, name),
dti->dt);
}