aboutsummaryrefslogtreecommitdiff
path: root/livetree.c
diff options
context:
space:
mode:
Diffstat (limited to 'livetree.c')
-rw-r--r--livetree.c383
1 files changed, 225 insertions, 158 deletions
diff --git a/livetree.c b/livetree.c
index 1ef9fc4..36be9af 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);
}
@@ -216,34 +216,6 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node)
return old_node;
}
-void add_orphan_node(struct node *dt, struct node *new_node, char *ref)
-{
- static unsigned int next_orphan_fragment = 0;
- struct node *ovl = xmalloc(sizeof(*ovl));
- struct property *p;
- struct data d = empty_data;
- char *name;
- int ret;
-
- memset(ovl, 0, sizeof(*ovl));
-
- d = data_add_marker(d, REF_PHANDLE, ref);
- d = data_append_integer(d, 0xffffffff, 32);
-
- p = build_property("target", d);
- add_property(ovl, p);
-
- ret = asprintf(&name, "fragment@%u",
- next_orphan_fragment++);
- if (ret == -1)
- die("asprintf() failed\n");
- name_node(ovl, name);
- name_node(new_node, "__overlay__");
-
- add_child(dt, ovl);
- add_child(ovl, new_node);
-}
-
struct node *chain_node(struct node *first, struct node *list)
{
assert(first->next_sibling == NULL);
@@ -270,7 +242,7 @@ void delete_property_by_name(struct node *node, char *name)
struct property *prop = node->proplist;
while (prop) {
- if (!strcmp(prop->name, name)) {
+ if (streq(prop->name, name)) {
delete_property(prop);
return;
}
@@ -303,7 +275,7 @@ void delete_node_by_name(struct node *parent, char *name)
struct node *node = parent->children;
while (node) {
- if (!strcmp(node->name, name)) {
+ if (streq(node->name, name)) {
delete_node(node);
return;
}
@@ -324,6 +296,23 @@ void delete_node(struct node *node)
delete_labels(&node->labels);
}
+void append_to_property(struct node *node,
+ char *name, const void *data, int len)
+{
+ struct data d;
+ struct property *p;
+
+ p = get_property(node, name);
+ if (p) {
+ d = data_append_data(p->val, data, len);
+ p->val = d;
+ } else {
+ d = data_append_data(empty_data, data, len);
+ p = build_property(name, d);
+ add_property(node, p);
+ }
+}
+
struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size)
{
struct reserve_info *new = xmalloc(sizeof(*new));
@@ -363,17 +352,19 @@ struct reserve_info *add_reserve_entry(struct reserve_info *list,
return list;
}
-struct boot_info *build_boot_info(struct reserve_info *reservelist,
- struct node *tree, uint32_t boot_cpuid_phys)
+struct dt_info *build_dt_info(unsigned int dtsflags,
+ struct reserve_info *reservelist,
+ struct node *tree, uint32_t boot_cpuid_phys)
{
- struct boot_info *bi;
+ struct dt_info *dti;
- bi = xmalloc(sizeof(*bi));
- bi->reservelist = reservelist;
- bi->dt = tree;
- bi->boot_cpuid_phys = boot_cpuid_phys;
+ dti = xmalloc(sizeof(*dti));
+ dti->dtsflags = dtsflags;
+ dti->reservelist = reservelist;
+ dti->dt = tree;
+ dti->boot_cpuid_phys = boot_cpuid_phys;
- return bi;
+ return dti;
}
/*
@@ -620,12 +611,12 @@ static int cmp_reserve_info(const void *ax, const void *bx)
return 0;
}
-static void sort_reserve_entries(struct boot_info *bi)
+static void sort_reserve_entries(struct dt_info *dti)
{
struct reserve_info *ri, **tbl;
int n = 0, i = 0;
- for (ri = bi->reservelist;
+ for (ri = dti->reservelist;
ri;
ri = ri->next)
n++;
@@ -635,14 +626,14 @@ static void sort_reserve_entries(struct boot_info *bi)
tbl = xmalloc(n * sizeof(*tbl));
- for (ri = bi->reservelist;
+ for (ri = dti->reservelist;
ri;
ri = ri->next)
tbl[i++] = ri;
qsort(tbl, n, sizeof(*tbl), cmp_reserve_info);
- bi->reservelist = tbl[0];
+ dti->reservelist = tbl[0];
for (i = 0; i < (n-1); i++)
tbl[i]->next = tbl[i+1];
tbl[n-1]->next = NULL;
@@ -732,165 +723,220 @@ static void sort_node(struct node *node)
sort_node(c);
}
-void sort_tree(struct boot_info *bi)
+void sort_tree(struct dt_info *dti)
{
- sort_reserve_entries(bi);
- sort_node(bi->dt);
+ sort_reserve_entries(dti);
+ sort_node(dti->dt);
}
-void generate_label_node(struct node *node, struct node *dt)
+/* utility helper to avoid code duplication */
+static struct node *build_and_name_child_node(struct node *parent, char *name)
{
- struct node *c, *an;
- struct property *p;
- struct label *l;
- int has_label;
- char *gen_node_name;
+ struct node *node;
- if (auto_label_aliases)
- gen_node_name = "aliases";
- else
- gen_node_name = "__symbols__";
+ node = build_node(NULL, NULL);
+ name_node(node, xstrdup(name));
+ add_child(parent, node);
- /* Make sure the label isn't already there */
- has_label = 0;
- for_each_label(node->labels, l) {
- has_label = 1;
- break;
- }
+ return node;
+}
- if (has_label) {
+static struct node *build_root_node(struct node *dt, char *name)
+{
+ struct node *an;
- /* an is the aliases/__symbols__ node */
- an = get_subnode(dt, gen_node_name);
- /* if no node exists, create it */
- if (!an) {
- an = build_node(NULL, NULL);
- name_node(an, gen_node_name);
- add_child(dt, an);
- }
+ an = get_subnode(dt, name);
+ if (!an)
+ an = build_and_name_child_node(dt, name);
+
+ if (!an)
+ die("Could not build root node /%s\n", name);
+
+ return an;
+}
+
+static bool any_label_tree(struct dt_info *dti, struct node *node)
+{
+ struct node *c;
+
+ if (node->labels)
+ return true;
+
+ for_each_child(node, c)
+ if (any_label_tree(dti, c))
+ return true;
+
+ return false;
+}
+
+static void generate_label_tree_internal(struct dt_info *dti,
+ struct node *an, struct node *node,
+ bool allocph)
+{
+ struct node *dt = dti->dt;
+ struct node *c;
+ struct property *p;
+ struct label *l;
+
+ /* if there are labels */
+ if (node->labels) {
/* now add the label in the node */
for_each_label(node->labels, l) {
+
/* check whether the label already exists */
p = get_property(an, l->label);
if (p) {
fprintf(stderr, "WARNING: label %s already"
" exists in /%s", l->label,
- gen_node_name);
+ an->name);
continue;
}
/* insert it */
p = build_property(l->label,
- data_copy_escape_string(node->fullpath,
- strlen(node->fullpath)));
+ data_copy_mem(node->fullpath,
+ strlen(node->fullpath) + 1));
add_property(an, p);
}
/* force allocation of a phandle for this node */
- if (symbol_fixup_support)
+ if (allocph)
(void)get_node_phandle(dt, node);
}
for_each_child(node, c)
- generate_label_node(c, dt);
+ generate_label_tree_internal(dti, an, c, allocph);
}
-static void add_fixup_entry(struct node *dt, struct node *node,
- struct property *prop, struct marker *m)
+static bool any_fixup_tree(struct dt_info *dti, struct node *node)
{
- struct node *fn; /* local fixup node */
- struct property *p;
- char *fixups_name = "__fixups__";
- struct data d;
- char *entry;
- int ret;
-
- /* fn is the node we're putting entries in */
- fn = get_subnode(dt, fixups_name);
- /* if no node exists, create it */
- if (!fn) {
- fn = build_node(NULL, NULL);
- name_node(fn, fixups_name);
- add_child(dt, fn);
+ struct node *c;
+ struct property *prop;
+ struct marker *m;
+
+ for_each_property(node, prop) {
+ m = prop->val.markers;
+ for_each_marker_of_type(m, REF_PHANDLE) {
+ if (!get_node_by_ref(dti->dt, m->ref))
+ return true;
+ }
+ }
+
+ for_each_child(node, c) {
+ if (any_fixup_tree(dti, c))
+ return true;
}
- ret = asprintf(&entry, "%s:%s:%u",
+ return false;
+}
+
+static void add_fixup_entry(struct dt_info *dti, struct node *fn,
+ struct node *node, struct property *prop,
+ struct marker *m)
+{
+ char *entry;
+
+ /* m->ref can only be a REF_PHANDLE, but check anyway */
+ assert(m->type == REF_PHANDLE);
+
+ /* 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);
- if (ret == -1)
- die("asprintf() failed\n");
+ append_to_property(fn, m->ref, entry, strlen(entry) + 1);
- p = get_property(fn, m->ref);
- d = data_append_data(p ? p->val : empty_data, entry, strlen(entry) + 1);
- if (!p)
- add_property(fn, build_property(m->ref, d));
- else
- p->val = d;
+ free(entry);
}
-static void add_local_fixup_entry(struct node *dt, struct node *node,
- struct property *prop, struct marker *m,
- struct node *refnode)
+static void generate_fixups_tree_internal(struct dt_info *dti,
+ struct node *fn,
+ struct node *node)
{
- struct node *lfn, *wn, *nwn; /* local fixup node, walk node, new */
- struct property *p;
- struct data d;
- char *local_fixups_name = "__local_fixups__";
- char *s, *e, *comp;
- int len;
-
- /* fn is the node we're putting entries in */
- lfn = get_subnode(dt, local_fixups_name);
- /* if no node exists, create it */
- if (!lfn) {
- lfn = build_node(NULL, NULL);
- name_node(lfn, local_fixups_name);
- add_child(dt, lfn);
+ struct node *dt = dti->dt;
+ struct node *c;
+ struct property *prop;
+ struct marker *m;
+ struct node *refnode;
+
+ for_each_property(node, prop) {
+ m = prop->val.markers;
+ for_each_marker_of_type(m, REF_PHANDLE) {
+ refnode = get_node_by_ref(dt, m->ref);
+ if (!refnode)
+ add_fixup_entry(dti, fn, node, prop, m);
+ }
}
- /* walk the path components creating nodes if they don't exist */
- comp = NULL;
- /* start skipping the first / */
- s = node->fullpath + 1;
- wn = lfn;
- while (*s) {
- /* retrieve path component */
- e = strchr(s, '/');
- if (e == NULL)
- e = s + strlen(s);
- len = e - s;
- comp = xrealloc(comp, len + 1);
- memcpy(comp, s, len);
- comp[len] = '\0';
+ for_each_child(node, c)
+ generate_fixups_tree_internal(dti, fn, c);
+}
- /* if no node exists, create it */
- nwn = get_subnode(wn, comp);
- if (!nwn) {
- nwn = build_node(NULL, NULL);
- name_node(nwn, strdup(comp));
- add_child(wn, nwn);
+static bool any_local_fixup_tree(struct dt_info *dti, struct node *node)
+{
+ struct node *c;
+ struct property *prop;
+ struct marker *m;
+
+ for_each_property(node, prop) {
+ m = prop->val.markers;
+ for_each_marker_of_type(m, REF_PHANDLE) {
+ if (get_node_by_ref(dti->dt, m->ref))
+ return true;
}
- wn = nwn;
+ }
+
+ for_each_child(node, c) {
+ if (any_local_fixup_tree(dti, c))
+ return true;
+ }
- /* last path component */
- if (!*e)
- break;
+ return false;
+}
- /* next path component */
- s = e + 1;
+static void add_local_fixup_entry(struct dt_info *dti,
+ struct node *lfn, struct node *node,
+ struct property *prop, struct marker *m,
+ struct node *refnode)
+{
+ struct node *wn, *nwn; /* local fixup node, walk node, new */
+ uint32_t value_32;
+ char **compp;
+ int i, depth;
+
+ /* walk back retreiving depth */
+ depth = 0;
+ for (wn = node; wn; wn = wn->parent)
+ depth++;
+
+ /* allocate name array */
+ compp = xmalloc(sizeof(*compp) * depth);
+
+ /* store names in the array */
+ for (wn = node, i = depth - 1; wn; wn = wn->parent, i--)
+ compp[i] = wn->name;
+
+ /* 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]);
}
- free(comp);
- p = get_property(wn, prop->name);
- d = data_append_cell(p ? p->val : empty_data, (cell_t)m->offset);
- if (!p)
- add_property(wn, build_property(prop->name, d));
- else
- p->val = d;
+ free(compp);
+
+ value_32 = cpu_to_fdt32(m->offset);
+ append_to_property(wn, prop->name, &value_32, sizeof(value_32));
}
-void generate_fixups_node(struct node *node, struct node *dt)
+static void generate_local_fixups_tree_internal(struct dt_info *dti,
+ struct node *lfn,
+ struct node *node)
{
+ struct node *dt = dti->dt;
struct node *c;
struct property *prop;
struct marker *m;
@@ -900,14 +946,35 @@ void generate_fixups_node(struct node *node, struct node *dt)
m = prop->val.markers;
for_each_marker_of_type(m, REF_PHANDLE) {
refnode = get_node_by_ref(dt, m->ref);
- if (!refnode)
- add_fixup_entry(dt, node, prop, m);
- else
- add_local_fixup_entry(dt, node, prop, m,
- refnode);
+ if (refnode)
+ add_local_fixup_entry(dti, lfn, node, prop, m, refnode);
}
}
for_each_child(node, c)
- generate_fixups_node(c, dt);
+ generate_local_fixups_tree_internal(dti, lfn, c);
+}
+
+void generate_label_tree(struct dt_info *dti, char *name, bool allocph)
+{
+ if (!any_label_tree(dti, dti->dt))
+ return;
+ generate_label_tree_internal(dti, build_root_node(dti->dt, name),
+ dti->dt, allocph);
+}
+
+void generate_fixups_tree(struct dt_info *dti, char *name)
+{
+ if (!any_fixup_tree(dti, dti->dt))
+ return;
+ generate_fixups_tree_internal(dti, build_root_node(dti->dt, name),
+ dti->dt);
+}
+
+void generate_local_fixups_tree(struct dt_info *dti, char *name)
+{
+ if (!any_local_fixup_tree(dti, dti->dt))
+ return;
+ generate_local_fixups_tree_internal(dti, build_root_node(dti->dt, name),
+ dti->dt);
}