commit 874ee3c0dceaf2735ebb82b4ad117108b6d2125b Author: Pantelis Antoniou Date: Wed Nov 14 23:40:59 2012 +0200 Implement fixups and symbols Introduce symbols and a fixup nodes in the root tree. diff --git a/checks.c b/checks.c index ee96a25..b1b87ed 100644 --- a/checks.c +++ b/checks.c @@ -459,20 +459,73 @@ static void fixup_phandle_references(struct check *c, struct node *dt, struct marker *m = prop->val.markers; struct node *refnode; cell_t phandle; + int has_phandle_refs; + + has_phandle_refs = 0; + for_each_marker_of_type(m, REF_PHANDLE) { + has_phandle_refs = 1; + break; + } + + if (!has_phandle_refs) + return; for_each_marker_of_type(m, REF_PHANDLE) { assert(m->offset + sizeof(cell_t) <= prop->val.len); refnode = get_node_by_ref(dt, m->ref); - if (! refnode) { + if (! refnode && !dt->is_plugin) { FAIL(c, "Reference to non-existent node or label \"%s\"\n", - m->ref); + m->ref); continue; } - phandle = get_node_phandle(dt, refnode); + if (! refnode) { + struct fixup *f, **fp; + struct fixup_entry *fe, **fep; + + /* allocate fixup entry */ + fe = xmalloc(sizeof(*fe)); + + fe->node = node; + fe->prop = prop; + fe->offset = m->offset; + fe->next = NULL; + + /* search for an already existing fixup */ + for_each_fixup(dt, f) + if (strcmp(f->ref, m->ref) == 0) + break; + + /* no fixup found, add new */ + if (f == NULL) { + f = xmalloc(sizeof(*f)); + f->ref = m->ref; + f->entries = NULL; + f->next = NULL; + + /* add it to the tree */ + fp = &dt->fixups; + while (*fp) + fp = &((*fp)->next); + *fp = f; + } + + /* and now append fixup entry */ + fep = &f->entries; + while (*fep) + fep = &((*fep)->next); + *fep = fe; + + /* mark the entry as unresolved */ + phandle = 0xdeadbeef; + } else { + phandle = get_node_phandle(dt, refnode); + } + *((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle); } + } ERROR(phandle_references, NULL, NULL, fixup_phandle_references, NULL, &duplicate_node_names, &explicit_phandles); @@ -651,6 +704,42 @@ static void check_obsolete_chosen_interrupt_controller(struct check *c, } TREE_WARNING(obsolete_chosen_interrupt_controller, NULL); +static void check_auto_label_phandles(struct check *c, struct node *dt, + struct node *node) +{ + struct label *l; + struct symbol *s, **sp; + int has_label; + + has_label = 0; + for_each_label(node->labels, l) { + has_label = 1; + break; + } + + if (!has_label) + return; + + /* force allocation of a phandle for this node */ + (void)get_node_phandle(dt, node); + + /* add the symbol */ + for_each_label(node->labels, l) { + + s = xmalloc(sizeof(*s)); + s->label = l; + s->node = node; + s->next = NULL; + + /* add it to the symbols list */ + sp = &dt->symbols; + while (*sp) + sp = &((*sp)->next); + *sp = s; + } +} +NODE_WARNING(auto_label_phandles, NULL); + static struct check *check_table[] = { &duplicate_node_names, &duplicate_property_names, &node_name_chars, &node_name_format, &property_name_chars, @@ -669,6 +758,8 @@ static struct check *check_table[] = { &avoid_default_addr_size, &obsolete_chosen_interrupt_controller, + &auto_label_phandles, + &always_fail, }; diff --git a/dtc-lexer.l b/dtc-lexer.l index 254d5af..2cef406 100644 --- a/dtc-lexer.l +++ b/dtc-lexer.l @@ -112,6 +112,11 @@ static int pop_input_file(void); return DT_V1; } +<*>"/plugin/" { + DPRINT("Keyword: /plugin/\n"); + return DT_PLUGIN; + } + <*>"/memreserve/" { DPRINT("Keyword: /memreserve/\n"); BEGIN_DEFAULT(); diff --git a/dtc-parser.y b/dtc-parser.y index f412460..e444acf 100644 --- a/dtc-parser.y +++ b/dtc-parser.y @@ -20,6 +20,7 @@ %{ #include +#include #include "dtc.h" #include "srcpos.h" @@ -56,9 +57,11 @@ static unsigned char eval_char_literal(const char *s); struct node *nodelist; struct reserve_info *re; uint64_t integer; + int is_plugin; } %token DT_V1 +%token DT_PLUGIN %token DT_MEMRESERVE %token DT_LSHIFT DT_RSHIFT DT_LE DT_GE DT_EQ DT_NE DT_AND DT_OR %token DT_BITS @@ -76,6 +79,7 @@ static unsigned char eval_char_literal(const char *s); %type propdata %type propdataprefix +%type plugindecl %type memreserve %type memreserves %type arrayprefix @@ -106,10 +110,23 @@ static unsigned char eval_char_literal(const char *s); %% sourcefile: - DT_V1 ';' memreserves devicetree + DT_V1 ';' plugindecl memreserves devicetree { - the_boot_info = build_boot_info($3, $4, - guess_boot_cpuid($4)); + $5->is_plugin = $3; + $5->is_root = 1; + the_boot_info = build_boot_info($4, $5, + guess_boot_cpuid($5)); + } + ; + +plugindecl: + /* empty */ + { + $$ = 0; + } + | DT_PLUGIN ';' + { + $$ = 1; } ; diff --git a/dtc.h b/dtc.h index 3e42a07..2659142 100644 --- a/dtc.h +++ b/dtc.h @@ -133,6 +133,25 @@ struct label { struct label *next; }; +struct fixup_entry { + int offset; + struct node *node; + struct property *prop; + struct fixup_entry *next; +}; + +struct fixup { + char *ref; + struct fixup_entry *entries; + struct fixup *next; +}; + +struct symbol { + struct label *label; + struct node *node; + struct symbol *next; +}; + struct property { int deleted; char *name; @@ -159,6 +178,11 @@ struct node { int addr_cells, size_cells; struct label *labels; + + int is_root; + int is_plugin; + struct fixup *fixups; + struct symbol *symbols; }; #define for_each_label_withdel(l0, l) \ @@ -182,6 +206,15 @@ struct node { for_each_child_withdel(n, c) \ if (!(c)->deleted) +#define for_each_fixup(n, f) \ + for ((f) = (n)->fixups; (f); (f) = (f)->next) + +#define for_each_fixup_entry(f, fe) \ + for ((fe) = (f)->entries; (fe); (fe) = (fe)->next) + +#define for_each_symbol(n, s) \ + for ((s) = (n)->symbols; (s); (s) = (s)->next) + void add_label(struct label **labels, char *label); void delete_labels(struct label **labels); diff --git a/fdtdump.c b/fdtdump.c index 207a46d..d4fa6d7 100644 --- a/fdtdump.c +++ b/fdtdump.c @@ -21,13 +21,23 @@ static void print_data(const char *data, int len) { int i; const char *p = data; + const char *s; /* no data, don't print */ if (len == 0) return; if (util_is_printable_string(data, len)) { - printf(" = \"%s\"", (const char *)data); + printf(" = "); + + s = data; + do { + printf("\"%s\"", s); + s += strlen(s) + 1; + if (s < data + len) + printf(", "); + } while (s < data + len); + } else if ((len % 4) == 0) { printf(" = <"); for (i = 0; i < len; i += 4) diff --git a/flattree.c b/flattree.c index 665dad7..f250672 100644 --- a/flattree.c +++ b/flattree.c @@ -310,6 +310,81 @@ static void flatten_tree(struct node *tree, struct emitter *emit, flatten_tree(child, emit, etarget, strbuf, vi); } + /* add the symbol nodes */ + if (tree->is_root) { + struct symbol *s; + int nameoff, vallen; + + emit->beginnode(etarget, NULL); + emit->string(etarget, "@symbols@", 0); + emit->align(etarget, sizeof(cell_t)); + + for_each_symbol(tree, s) { + + vallen = strlen(s->node->fullpath); + + nameoff = stringtable_insert(strbuf, s->label->label); + + emit->property(etarget, NULL); + emit->cell(etarget, vallen + 1); + emit->cell(etarget, nameoff); + + if ((vi->flags & FTF_VARALIGN) && vallen >= 8) + emit->align(etarget, 8); + + emit->string(etarget, s->node->fullpath, strlen(s->node->fullpath)); + emit->align(etarget, sizeof(cell_t)); + } + + emit->endnode(etarget, NULL); + } + + /* add the fixup nodes */ + if (tree->is_root && tree->is_plugin) { + struct fixup *f; + struct fixup_entry *fe; + char *name, *s; + int namesz, nameoff, vallen; + + emit->beginnode(etarget, NULL); + emit->string(etarget, "@fixups@", 0); + emit->align(etarget, sizeof(cell_t)); + + for_each_fixup(tree, f) { + + namesz = 0; + for_each_fixup_entry(f, fe) + namesz += strlen(fe->node->fullpath) + 1 + + strlen(fe->prop->name) + 1 + 32; + + name = xmalloc(namesz); + + s = name; + for_each_fixup_entry(f, fe) { + snprintf(s, name + namesz - s, "%s:%s:%d", + fe->node->fullpath, fe->prop->name, fe->offset); + s += strlen(s) + 1; + } + + nameoff = stringtable_insert(strbuf, f->ref); + vallen = s - name; + + emit->property(etarget, NULL); + emit->cell(etarget, vallen); + emit->cell(etarget, nameoff); + + if ((vi->flags & FTF_VARALIGN) && vallen >= 8) + emit->align(etarget, 8); + + emit->string(etarget, name, vallen); + emit->align(etarget, sizeof(cell_t)); + + free(name); + } + + emit->endnode(etarget, tree->labels); + } + emit->endnode(etarget, tree->labels); }