diff options
Diffstat (limited to 'scripts/dtc/livetree.c')
| -rw-r--r-- | scripts/dtc/livetree.c | 507 |
1 files changed, 441 insertions, 66 deletions
diff --git a/scripts/dtc/livetree.c b/scripts/dtc/livetree.c index b61465fb2f33..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; @@ -204,11 +211,13 @@ 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); } + 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); @@ -242,7 +282,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; } @@ -275,7 +315,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; } @@ -296,14 +336,34 @@ void delete_node(struct node *node) delete_labels(&node->labels); } +void append_to_property(struct node *node, + 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_add_marker(p->val, type, name); + d = data_append_data(d, data, len); + p->val = d; + } else { + 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); + } +} + struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size) { struct reserve_info *new = xmalloc(sizeof(*new)); memset(new, 0, sizeof(*new)); - new->re.address = address; - new->re.size = size; + new->address = address; + new->size = size; return new; } @@ -335,17 +395,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; } /* @@ -374,7 +436,13 @@ struct property *get_property(struct node *node, const char *propname) cell_t propval_cell(struct property *prop) { assert(prop->val.len == sizeof(cell_t)); - return fdt32_to_cpu(*((cell_t *)prop->val.val)); + 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, @@ -436,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; @@ -459,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; @@ -492,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) @@ -511,17 +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; + if (ref[0] == '/') - return get_node_by_path(tree, ref); + 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)) @@ -529,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 @@ -578,24 +685,24 @@ static int cmp_reserve_info(const void *ax, const void *bx) a = *((const struct reserve_info * const *)ax); b = *((const struct reserve_info * const *)bx); - if (a->re.address < b->re.address) + if (a->address < b->address) return -1; - else if (a->re.address > b->re.address) + else if (a->address > b->address) return 1; - else if (a->re.size < b->re.size) + else if (a->size < b->size) return -1; - else if (a->re.size > b->re.size) + else if (a->size > b->size) return 1; else 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++; @@ -605,14 +712,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; @@ -702,8 +809,276 @@ 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(dti); + sort_node(dti->dt); +} + +/* utility helper to avoid code duplication */ +static struct node *build_and_name_child_node(struct node *parent, const char *name) +{ + struct node *node; + + 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, const char *name) +{ + struct node *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, + an->name); + continue; + } + + /* insert it */ + p = build_property(l->label, + data_copy_escape_string(node->fullpath, + strlen(node->fullpath)), + NULL); + add_property(an, p); + } + + /* force allocation of a phandle for this node */ + if (allocph) + (void)get_node_phandle(dt, node); + } + + for_each_child(node, c) + generate_label_tree_internal(dti, an, c, allocph); +} + +static bool any_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; + } + } + + for_each_child(node, c) { + if (any_fixup_tree(dti, c)) + return true; + } + + 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); + + /* 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, TYPE_STRING); + + free(entry); +} + +static void generate_fixups_tree_internal(struct dt_info *dti, + struct node *fn, + struct node *node) +{ + 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); + } + } + + for_each_child(node, c) + generate_fixups_tree_internal(dti, fn, c); +} + +static bool any_local_fixup_tree(struct dt_info *dti, struct node *node) { - sort_reserve_entries(bi); - sort_node(bi->dt); + 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_local_fixup_tree(dti, c)) + return true; + } + + return false; +} + +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 */ + fdt32_t value_32; + char **compp; + int i, depth; + + /* walk back retrieving 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 = 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), TYPE_UINT32); +} + +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; + 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_local_fixup_entry(dti, lfn, node, prop, m, refnode); + } + } + + for_each_child(node, c) + generate_local_fixups_tree_internal(dti, lfn, c); +} + +void generate_label_tree(struct dt_info *dti, const 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, 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_and_name_child_node(dti->dt, name), + dti->dt); +} + +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_and_name_child_node(dti->dt, name), + dti->dt); } |
