From b29e0699719c15866ce92af0598b2d61418fe89b Mon Sep 17 00:00:00 2001 From: Pantelis Antoniou Date: Tue, 21 Oct 2014 22:39:58 +0300 Subject: [PATCH 2/3] dtc: Plugin (object) device tree support. Enables the generation of a __fixups__ node for trees compiled using the -@ option that are using the /plugin/ tag. The __fixups__ node make possible the dynamic resolution of phandle references which are present in the plugin tree but lie in the tree that are applying the overlay against. Signed-off-by: Pantelis Antoniou --- Documentation/manual.txt | 5 ++++ checks.c | 45 ++++++++++++++++++++++++++++++++-- dtc-lexer.l | 5 ++++ dtc-parser.y | 22 ++++++++++++++--- dtc.h | 12 +++++++++ flattree.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 147 insertions(+), 5 deletions(-) diff --git a/Documentation/manual.txt b/Documentation/manual.txt index 4359958..18d1333 100644 --- a/Documentation/manual.txt +++ b/Documentation/manual.txt @@ -124,6 +124,9 @@ Options: for any node labels used, and for any local references using phandles it also generates a __local_fixups__ node that tracks them. + When using the /plugin/ tag all unresolved label references to + be tracked in the __fixups__ node, making dynamic resolution possible. + -S Ensure the blob at least long, adding additional space if needed. @@ -158,6 +161,8 @@ Here is a very rough overview of the layout of a DTS source file: devicetree: '/' nodedef + plugindecl: '/' 'plugin' '/' ';' + nodedef: '{' list_of_property list_of_subnode '}' ';' property: label PROPNAME '=' propdata ';' diff --git a/checks.c b/checks.c index f203986..2778e89 100644 --- a/checks.c +++ b/checks.c @@ -457,6 +457,7 @@ static void fixup_phandle_references(struct check *c, struct node *dt, struct node *node, struct property *prop) { struct marker *m = prop->val.markers; + struct fixup *f, **fp; struct fixup_entry *fe, **fep; struct node *refnode; cell_t phandle; @@ -466,8 +467,48 @@ static void fixup_phandle_references(struct check *c, struct node *dt, refnode = get_node_by_ref(dt, m->ref); if (! refnode) { - FAIL(c, "Reference to non-existent node or label \"%s\"\n", - m->ref); + if (!dt->is_plugin) { + FAIL(c, "Reference to non-existent node or label \"%s\"\n", + m->ref); + continue; + } + + /* 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 */ + *((cell_t *)(prop->val.val + m->offset)) = + cpu_to_fdt32(0xdeadbeef); continue; } diff --git a/dtc-lexer.l b/dtc-lexer.l index 0ee1caf..dd44ba2 100644 --- a/dtc-lexer.l +++ b/dtc-lexer.l @@ -113,6 +113,11 @@ static void lexical_error(const char *fmt, ...); 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 ea57e0a..776fdd5 100644 --- a/dtc-parser.y +++ b/dtc-parser.y @@ -19,6 +19,7 @@ */ %{ #include +#include #include "dtc.h" #include "srcpos.h" @@ -52,9 +53,11 @@ extern bool treesource_error; struct node *nodelist; struct reserve_info *re; uint64_t integer; + bool 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 @@ -71,6 +74,7 @@ extern bool treesource_error; %type propdata %type propdataprefix +%type plugindecl %type memreserve %type memreserves %type arrayprefix @@ -101,10 +105,22 @@ extern bool treesource_error; %% 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; + the_boot_info = build_boot_info($4, $5, + guess_boot_cpuid($5)); + } + ; + +plugindecl: + /* empty */ + { + $$ = false; + } + | DT_PLUGIN ';' + { + $$ = true; } ; diff --git a/dtc.h b/dtc.h index 16354fa..f163b22 100644 --- a/dtc.h +++ b/dtc.h @@ -141,6 +141,12 @@ struct fixup_entry { bool local_fixup_generated; }; +struct fixup { + char *ref; + struct fixup_entry *entries; + struct fixup *next; +}; + struct symbol { struct label *label; struct node *node; @@ -177,6 +183,9 @@ struct node { struct symbol *symbols; struct fixup_entry *local_fixups; bool emit_local_fixup_node; + + bool is_plugin; + struct fixup *fixups; }; #define for_each_label_withdel(l0, l) \ @@ -200,6 +209,9 @@ 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) diff --git a/flattree.c b/flattree.c index 3a58949..2385137 100644 --- a/flattree.c +++ b/flattree.c @@ -391,6 +391,68 @@ static void emit_local_fixups_node(struct node *tree, struct emitter *emit, emit->endnode(etarget, tree->labels); } +static void emit_fixups_node(struct node *tree, struct emitter *emit, + void *etarget, struct data *strbuf, + struct version_info *vi) +{ + struct fixup *f; + struct fixup_entry *fe; + char *name, *s; + const char *fullpath; + int namesz, nameoff, vallen; + + /* do nothing if no fixups */ + if (!tree->fixups) + return; + + /* emit the external fixups */ + 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) { + fullpath = fe->node->fullpath; + if (fullpath[0] == '\0') + fullpath = "/"; + namesz += strlen(fullpath) + 1; + namesz += strlen(fe->prop->name) + 1; + namesz += 32; /* space for : + '\0' */ + } + + name = xmalloc(namesz); + + s = name; + for_each_fixup_entry(f, fe) { + fullpath = fe->node->fullpath; + if (fullpath[0] == '\0') + fullpath = "/"; + snprintf(s, name + namesz - s, "%s:%s:%d", fullpath, + fe->prop->name, fe->offset); + s += strlen(s) + 1; + } + + nameoff = stringtable_insert(strbuf, f->ref); + vallen = s - name - 1; + + 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, name, vallen); + emit->align(etarget, sizeof(cell_t)); + + free(name); + } + + emit->endnode(etarget, tree->labels); +} + static void flatten_tree(struct node *tree, struct emitter *emit, void *etarget, struct data *strbuf, struct version_info *vi) @@ -448,6 +510,7 @@ static void flatten_tree(struct node *tree, struct emitter *emit, emit_symbols_node(tree, emit, etarget, strbuf, vi); emit_local_fixups_node(tree, emit, etarget, strbuf, vi); + emit_fixups_node(tree, emit, etarget, strbuf, vi); emit->endnode(etarget, tree->labels); } -- 2.2.2