mirror of
https://github.com/archlinuxarm/PKGBUILDs.git
synced 2024-11-08 22:45:43 +00:00
alarm/dtc-overlay to 1.4.1-1
This commit is contained in:
parent
e6014debe7
commit
747967bff5
5 changed files with 1061 additions and 599 deletions
|
@ -0,0 +1,402 @@
|
|||
From 78077bd72707579bffab6b1d3e7f1a8f5b2b127f Mon Sep 17 00:00:00 2001
|
||||
From: Pantelis Antoniou
|
||||
<pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
|
||||
Date: Tue, 21 Oct 2014 22:39:57 +0300
|
||||
Subject: [PATCH 1/3] dtc: Symbol and local fixup generation support
|
||||
|
||||
Enable the generation of symbols & local fixup information
|
||||
for trees compiled with the -@ (--symbols) option.
|
||||
|
||||
Using this patch labels in the tree and their users emit information
|
||||
in __symbols__ and __local_fixups__ nodes. Using this information
|
||||
it is possible to implement run time dynamic tree loading.
|
||||
|
||||
Signed-off-by: Pantelis Antoniou <pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
|
||||
---
|
||||
Documentation/manual.txt | 5 ++
|
||||
checks.c | 61 +++++++++++++++++++++
|
||||
dtc.c | 9 ++-
|
||||
dtc.h | 28 ++++++++++
|
||||
flattree.c | 139 +++++++++++++++++++++++++++++++++++++++++++++++
|
||||
5 files changed, 240 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/Documentation/manual.txt b/Documentation/manual.txt
|
||||
index 398de32..4359958 100644
|
||||
--- a/Documentation/manual.txt
|
||||
+++ b/Documentation/manual.txt
|
||||
@@ -119,6 +119,11 @@ Options:
|
||||
Make space for <number> reserve map entries
|
||||
Relevant for dtb and asm output only.
|
||||
|
||||
+ -@
|
||||
+ Generates a __symbols__ node at the root node of the resulting blob
|
||||
+ for any node labels used, and for any local references using phandles
|
||||
+ it also generates a __local_fixups__ node that tracks them.
|
||||
+
|
||||
-S <bytes>
|
||||
Ensure the blob at least <bytes> long, adding additional
|
||||
space if needed.
|
||||
diff --git a/checks.c b/checks.c
|
||||
index 3bf0fa4..f203986 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_entry *fe, **fep;
|
||||
struct node *refnode;
|
||||
cell_t phandle;
|
||||
|
||||
@@ -470,9 +471,28 @@ static void fixup_phandle_references(struct check *c, struct node *dt,
|
||||
continue;
|
||||
}
|
||||
|
||||
+ /* if it's a local reference, we need to record it */
|
||||
+ if (symbol_fixup_support) {
|
||||
+
|
||||
+ /* allocate a new local fixup entry */
|
||||
+ fe = xmalloc(sizeof(*fe));
|
||||
+
|
||||
+ fe->node = node;
|
||||
+ fe->prop = prop;
|
||||
+ fe->offset = m->offset;
|
||||
+ fe->next = NULL;
|
||||
+
|
||||
+ /* append it to the local fixups */
|
||||
+ fep = &dt->local_fixups;
|
||||
+ while (*fep)
|
||||
+ fep = &(*fep)->next;
|
||||
+ *fep = fe;
|
||||
+ }
|
||||
+
|
||||
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 +671,45 @@ 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;
|
||||
+
|
||||
+ if (!symbol_fixup_support)
|
||||
+ return;
|
||||
+
|
||||
+ 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 +728,8 @@ static struct check *check_table[] = {
|
||||
&avoid_default_addr_size,
|
||||
&obsolete_chosen_interrupt_controller,
|
||||
|
||||
+ &auto_label_phandles,
|
||||
+
|
||||
&always_fail,
|
||||
};
|
||||
|
||||
diff --git a/dtc.c b/dtc.c
|
||||
index 8c4add6..91e91e7 100644
|
||||
--- a/dtc.c
|
||||
+++ b/dtc.c
|
||||
@@ -29,6 +29,7 @@ int reservenum; /* Number of memory reservation slots */
|
||||
int minsize; /* Minimum blob size */
|
||||
int padsize; /* Additional padding to blob */
|
||||
int phandle_format = PHANDLE_BOTH; /* Use linux,phandle or phandle properties */
|
||||
+int symbol_fixup_support = 0;
|
||||
|
||||
static void fill_fullpaths(struct node *tree, const char *prefix)
|
||||
{
|
||||
@@ -51,7 +52,7 @@ static void fill_fullpaths(struct node *tree, const char *prefix)
|
||||
#define FDT_VERSION(version) _FDT_VERSION(version)
|
||||
#define _FDT_VERSION(version) #version
|
||||
static const char usage_synopsis[] = "dtc [options] <input file>";
|
||||
-static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:fb:i:H:sW:E:hv";
|
||||
+static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:fb:i:H:sW:E:@hv";
|
||||
static struct option const usage_long_opts[] = {
|
||||
{"quiet", no_argument, NULL, 'q'},
|
||||
{"in-format", a_argument, NULL, 'I'},
|
||||
@@ -69,6 +70,7 @@ static struct option const usage_long_opts[] = {
|
||||
{"phandle", a_argument, NULL, 'H'},
|
||||
{"warning", a_argument, NULL, 'W'},
|
||||
{"error", a_argument, NULL, 'E'},
|
||||
+ {"symbols", no_argument, NULL, '@'},
|
||||
{"help", no_argument, NULL, 'h'},
|
||||
{"version", no_argument, NULL, 'v'},
|
||||
{NULL, no_argument, NULL, 0x0},
|
||||
@@ -99,6 +101,7 @@ static const char * const usage_opts_help[] = {
|
||||
"\t\tboth - Both \"linux,phandle\" and \"phandle\" properties",
|
||||
"\n\tEnable/disable warnings (prefix with \"no-\")",
|
||||
"\n\tEnable/disable errors (prefix with \"no-\")",
|
||||
+ "\n\tEnable symbols/fixup support",
|
||||
"\n\tPrint this help and exit",
|
||||
"\n\tPrint version and exit",
|
||||
NULL,
|
||||
@@ -186,7 +189,9 @@ int main(int argc, char *argv[])
|
||||
case 'E':
|
||||
parse_checks_option(false, true, optarg);
|
||||
break;
|
||||
-
|
||||
+ case '@':
|
||||
+ symbol_fixup_support = 1;
|
||||
+ break;
|
||||
case 'h':
|
||||
usage(NULL);
|
||||
default:
|
||||
diff --git a/dtc.h b/dtc.h
|
||||
index 56212c8..16354fa 100644
|
||||
--- a/dtc.h
|
||||
+++ b/dtc.h
|
||||
@@ -54,6 +54,7 @@ extern int reservenum; /* Number of memory reservation slots */
|
||||
extern int minsize; /* Minimum blob size */
|
||||
extern int padsize; /* Additional padding to blob */
|
||||
extern int phandle_format; /* Use linux,phandle or phandle properties */
|
||||
+extern int symbol_fixup_support;/* enable symbols & fixup support */
|
||||
|
||||
#define PHANDLE_LEGACY 0x1
|
||||
#define PHANDLE_EPAPR 0x2
|
||||
@@ -132,6 +133,20 @@ struct label {
|
||||
struct label *next;
|
||||
};
|
||||
|
||||
+struct fixup_entry {
|
||||
+ int offset;
|
||||
+ struct node *node;
|
||||
+ struct property *prop;
|
||||
+ struct fixup_entry *next;
|
||||
+ bool local_fixup_generated;
|
||||
+};
|
||||
+
|
||||
+struct symbol {
|
||||
+ struct label *label;
|
||||
+ struct node *node;
|
||||
+ struct symbol *next;
|
||||
+};
|
||||
+
|
||||
struct property {
|
||||
bool deleted;
|
||||
char *name;
|
||||
@@ -158,6 +173,10 @@ struct node {
|
||||
int addr_cells, size_cells;
|
||||
|
||||
struct label *labels;
|
||||
+
|
||||
+ struct symbol *symbols;
|
||||
+ struct fixup_entry *local_fixups;
|
||||
+ bool emit_local_fixup_node;
|
||||
};
|
||||
|
||||
#define for_each_label_withdel(l0, l) \
|
||||
@@ -181,6 +200,15 @@ struct node {
|
||||
for_each_child_withdel(n, c) \
|
||||
if (!(c)->deleted)
|
||||
|
||||
+#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)
|
||||
+
|
||||
+#define for_each_local_fixup_entry(n, fe) \
|
||||
+ for ((fe) = (n)->local_fixups; (fe); (fe) = (fe)->next)
|
||||
+
|
||||
void add_label(struct label **labels, char *label);
|
||||
void delete_labels(struct label **labels);
|
||||
|
||||
diff --git a/flattree.c b/flattree.c
|
||||
index bd99fa2..3a58949 100644
|
||||
--- a/flattree.c
|
||||
+++ b/flattree.c
|
||||
@@ -255,6 +255,142 @@ static int stringtable_insert(struct data *d, const char *str)
|
||||
return i;
|
||||
}
|
||||
|
||||
+static void emit_local_fixups(struct node *tree, struct emitter *emit,
|
||||
+ void *etarget, struct data *strbuf, struct version_info *vi,
|
||||
+ struct node *node)
|
||||
+{
|
||||
+ struct fixup_entry *fe, *fen;
|
||||
+ struct node *child;
|
||||
+ int nameoff, count;
|
||||
+ cell_t *buf;
|
||||
+ struct data d;
|
||||
+
|
||||
+ if (node->emit_local_fixup_node) {
|
||||
+
|
||||
+ /* emit the external fixups (do not emit /) */
|
||||
+ if (node != tree) {
|
||||
+ emit->beginnode(etarget, NULL);
|
||||
+ emit->string(etarget, node->name, 0);
|
||||
+ emit->align(etarget, sizeof(cell_t));
|
||||
+ }
|
||||
+
|
||||
+ for_each_local_fixup_entry(tree, fe) {
|
||||
+ if (fe->node != node || fe->local_fixup_generated)
|
||||
+ continue;
|
||||
+
|
||||
+ /* count the number of fixup entries */
|
||||
+ count = 0;
|
||||
+ for_each_local_fixup_entry(tree, fen) {
|
||||
+ if (fen->prop != fe->prop)
|
||||
+ continue;
|
||||
+ fen->local_fixup_generated = true;
|
||||
+ count++;
|
||||
+ }
|
||||
+
|
||||
+ /* allocate buffer */
|
||||
+ buf = xmalloc(count * sizeof(cell_t));
|
||||
+
|
||||
+ /* collect all the offsets in buffer */
|
||||
+ count = 0;
|
||||
+ for_each_local_fixup_entry(tree, fen) {
|
||||
+ if (fen->prop != fe->prop)
|
||||
+ continue;
|
||||
+ fen->local_fixup_generated = true;
|
||||
+ buf[count++] = cpu_to_fdt32(fen->offset);
|
||||
+ }
|
||||
+ d = empty_data;
|
||||
+ d.len = count * sizeof(cell_t);
|
||||
+ d.val = (char *)buf;
|
||||
+
|
||||
+ nameoff = stringtable_insert(strbuf, fe->prop->name);
|
||||
+ emit->property(etarget, fe->prop->labels);
|
||||
+ emit->cell(etarget, count * sizeof(cell_t));
|
||||
+ emit->cell(etarget, nameoff);
|
||||
+
|
||||
+ if ((vi->flags & FTF_VARALIGN) &&
|
||||
+ (count * sizeof(cell_t)) >= 8)
|
||||
+ emit->align(etarget, 8);
|
||||
+
|
||||
+ emit->data(etarget, d);
|
||||
+ emit->align(etarget, sizeof(cell_t));
|
||||
+
|
||||
+ free(buf);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ for_each_child(node, child)
|
||||
+ emit_local_fixups(tree, emit, etarget, strbuf, vi, child);
|
||||
+
|
||||
+ if (node->emit_local_fixup_node && node != tree)
|
||||
+ emit->endnode(etarget, tree->labels);
|
||||
+}
|
||||
+
|
||||
+static void emit_symbols_node(struct node *tree, struct emitter *emit,
|
||||
+ void *etarget, struct data *strbuf,
|
||||
+ struct version_info *vi)
|
||||
+{
|
||||
+ struct symbol *sym;
|
||||
+ int nameoff, vallen;
|
||||
+
|
||||
+ /* do nothing if no symbols */
|
||||
+ if (!tree->symbols)
|
||||
+ return;
|
||||
+
|
||||
+ emit->beginnode(etarget, NULL);
|
||||
+ emit->string(etarget, "__symbols__", 0);
|
||||
+ emit->align(etarget, sizeof(cell_t));
|
||||
+
|
||||
+ for_each_symbol(tree, sym) {
|
||||
+
|
||||
+ vallen = strlen(sym->node->fullpath);
|
||||
+
|
||||
+ nameoff = stringtable_insert(strbuf, sym->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, sym->node->fullpath,
|
||||
+ strlen(sym->node->fullpath));
|
||||
+ emit->align(etarget, sizeof(cell_t));
|
||||
+ }
|
||||
+
|
||||
+ emit->endnode(etarget, NULL);
|
||||
+}
|
||||
+
|
||||
+static void emit_local_fixups_node(struct node *tree, struct emitter *emit,
|
||||
+ void *etarget, struct data *strbuf,
|
||||
+ struct version_info *vi)
|
||||
+{
|
||||
+ struct fixup_entry *fe;
|
||||
+ struct node *node;
|
||||
+
|
||||
+ /* do nothing if no local fixups */
|
||||
+ if (!tree->local_fixups)
|
||||
+ return;
|
||||
+
|
||||
+ /* mark all nodes that need a local fixup generated (and parents) */
|
||||
+ for_each_local_fixup_entry(tree, fe) {
|
||||
+ node = fe->node;
|
||||
+ while (node != NULL && !node->emit_local_fixup_node) {
|
||||
+ node->emit_local_fixup_node = true;
|
||||
+ node = node->parent;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* emit the local fixups node now */
|
||||
+ emit->beginnode(etarget, NULL);
|
||||
+ emit->string(etarget, "__local_fixups__", 0);
|
||||
+ emit->align(etarget, sizeof(cell_t));
|
||||
+
|
||||
+ emit_local_fixups(tree, emit, etarget, strbuf, vi, tree);
|
||||
+
|
||||
+ emit->endnode(etarget, tree->labels);
|
||||
+}
|
||||
+
|
||||
static void flatten_tree(struct node *tree, struct emitter *emit,
|
||||
void *etarget, struct data *strbuf,
|
||||
struct version_info *vi)
|
||||
@@ -310,6 +446,9 @@ static void flatten_tree(struct node *tree, struct emitter *emit,
|
||||
flatten_tree(child, emit, etarget, strbuf, vi);
|
||||
}
|
||||
|
||||
+ emit_symbols_node(tree, emit, etarget, strbuf, vi);
|
||||
+ emit_local_fixups_node(tree, emit, etarget, strbuf, vi);
|
||||
+
|
||||
emit->endnode(etarget, tree->labels);
|
||||
}
|
||||
|
||||
--
|
||||
2.2.2
|
||||
|
|
@ -0,0 +1,304 @@
|
|||
From b29e0699719c15866ce92af0598b2d61418fe89b Mon Sep 17 00:00:00 2001
|
||||
From: Pantelis Antoniou
|
||||
<pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
|
||||
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 <pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
|
||||
---
|
||||
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 <bytes>
|
||||
Ensure the blob at least <bytes> 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 <stdio.h>
|
||||
+#include <inttypes.h>
|
||||
|
||||
#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 <data> propdata
|
||||
%type <data> propdataprefix
|
||||
+%type <is_plugin> plugindecl
|
||||
%type <re> memreserve
|
||||
%type <re> memreserves
|
||||
%type <array> 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 :<number> + '\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
|
||||
|
|
@ -0,0 +1,325 @@
|
|||
From 4225e23356d58e574f97803387562cf53c72476a Mon Sep 17 00:00:00 2001
|
||||
From: Pantelis Antoniou
|
||||
<pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
|
||||
Date: Tue, 21 Oct 2014 22:39:59 +0300
|
||||
Subject: [PATCH 3/3] dtc: Document the dynamic plugin internals
|
||||
|
||||
Provides the document explaining the internal mechanics of
|
||||
plugins and options.
|
||||
|
||||
Signed-off-by: Pantelis Antoniou <pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
|
||||
---
|
||||
Documentation/dt-object-internal.txt | 301 +++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 301 insertions(+)
|
||||
create mode 100644 Documentation/dt-object-internal.txt
|
||||
|
||||
diff --git a/Documentation/dt-object-internal.txt b/Documentation/dt-object-internal.txt
|
||||
new file mode 100644
|
||||
index 0000000..b5ce9b4
|
||||
--- /dev/null
|
||||
+++ b/Documentation/dt-object-internal.txt
|
||||
@@ -0,0 +1,301 @@
|
||||
+Device Tree Dynamic Object format internals
|
||||
+-------------------------------------------
|
||||
+
|
||||
+The Device Tree for most platforms is a static representation of
|
||||
+the hardware capabilities. This is insufficient for many platforms
|
||||
+that need to dynamically insert device tree fragments to the
|
||||
+running kernel's live tree.
|
||||
+
|
||||
+This document explains the the device tree object format and the
|
||||
+modifications made to the device tree compiler, which make it possible.
|
||||
+
|
||||
+1. Simplified Problem Definition
|
||||
+--------------------------------
|
||||
+
|
||||
+Assume we have a platform which boots using following simplified device tree.
|
||||
+
|
||||
+---- foo.dts -----------------------------------------------------------------
|
||||
+ /* FOO platform */
|
||||
+ / {
|
||||
+ compatible = "corp,foo";
|
||||
+
|
||||
+ /* shared resources */
|
||||
+ res: res {
|
||||
+ };
|
||||
+
|
||||
+ /* On chip peripherals */
|
||||
+ ocp: ocp {
|
||||
+ /* peripherals that are always instantiated */
|
||||
+ peripheral1 { ... };
|
||||
+ }
|
||||
+ };
|
||||
+---- foo.dts -----------------------------------------------------------------
|
||||
+
|
||||
+We have a number of peripherals that after probing (using some undefined method)
|
||||
+should result in different device tree configuration.
|
||||
+
|
||||
+We cannot boot with this static tree because due to the configuration of the
|
||||
+foo platform there exist multiple conficting peripherals DT fragments.
|
||||
+
|
||||
+So for the bar peripheral we would have this:
|
||||
+
|
||||
+---- foo+bar.dts -------------------------------------------------------------
|
||||
+ /* FOO platform + bar peripheral */
|
||||
+ / {
|
||||
+ compatible = "corp,foo";
|
||||
+
|
||||
+ /* shared resources */
|
||||
+ res: res {
|
||||
+ };
|
||||
+
|
||||
+ /* On chip peripherals */
|
||||
+ ocp: ocp {
|
||||
+ /* peripherals that are always instantiated */
|
||||
+ peripheral1 { ... };
|
||||
+
|
||||
+ /* bar peripheral */
|
||||
+ bar {
|
||||
+ compatible = "corp,bar";
|
||||
+ ... /* various properties and child nodes */
|
||||
+ }
|
||||
+ }
|
||||
+ };
|
||||
+---- foo+bar.dts -------------------------------------------------------------
|
||||
+
|
||||
+While for the baz peripheral we would have this:
|
||||
+
|
||||
+---- foo+baz.dts -------------------------------------------------------------
|
||||
+ /* FOO platform + baz peripheral */
|
||||
+ / {
|
||||
+ compatible = "corp,foo";
|
||||
+
|
||||
+ /* shared resources */
|
||||
+ res: res {
|
||||
+ /* baz resources */
|
||||
+ baz_res: res_baz { ... };
|
||||
+ };
|
||||
+
|
||||
+ /* On chip peripherals */
|
||||
+ ocp: ocp {
|
||||
+ /* peripherals that are always instantiated */
|
||||
+ peripheral1 { ... };
|
||||
+
|
||||
+ /* baz peripheral */
|
||||
+ baz {
|
||||
+ compatible = "corp,baz";
|
||||
+ /* reference to another point in the tree */
|
||||
+ ref-to-res = <&baz_res>;
|
||||
+ ... /* various properties and child nodes */
|
||||
+ }
|
||||
+ }
|
||||
+ };
|
||||
+---- foo+baz.dts -------------------------------------------------------------
|
||||
+
|
||||
+We note that the baz case is more complicated, since the baz peripheral needs to
|
||||
+reference another node in the DT tree.
|
||||
+
|
||||
+2. Device Tree Object Format Requirements
|
||||
+-----------------------------------------
|
||||
+
|
||||
+Since the device tree is used for booting a number of very different hardware
|
||||
+platforms it is imperative that we tread very carefully.
|
||||
+
|
||||
+2.a) No changes to the Device Tree binary format. We cannot modify the tree
|
||||
+format at all and all the information we require should be encoded using device
|
||||
+tree itself. We can add nodes that can be safely ignored by both bootloaders and
|
||||
+the kernel.
|
||||
+
|
||||
+2.b) Changes to the DTS source format should be absolutely minimal, and should
|
||||
+only be needed for the DT fragment definitions, and not the base boot DT.
|
||||
+
|
||||
+2.c) An explicit option should be used to instruct DTC to generate the required
|
||||
+information needed for object resolution. Platforms that don't use the
|
||||
+dynamic object format can safely ignore it.
|
||||
+
|
||||
+2.d) Finally, DT syntax changes should be kept to a minimum. It should be
|
||||
+possible to express everything using the existing DT syntax.
|
||||
+
|
||||
+3. Implementation
|
||||
+-----------------
|
||||
+
|
||||
+The basic unit of addressing in Device Tree is the phandle. Turns out it's
|
||||
+relatively simple to extend the way phandles are generated and referenced
|
||||
+so that it's possible to dynamically convert symbolic references (labels)
|
||||
+to phandle values.
|
||||
+
|
||||
+We can roughly divide the operation into two steps.
|
||||
+
|
||||
+3.a) Compilation of the base board DTS file using the '-@' option
|
||||
+generates a valid DT blob with an added __symbols__ node at the root node,
|
||||
+containing a list of all nodes that are marked with a label.
|
||||
+
|
||||
+Using the foo.dts file above the following node will be generated;
|
||||
+
|
||||
+$ dtc -@ -O dtb -o foo.dtb -b 0 foo.dts
|
||||
+$ fdtdump foo.dtb
|
||||
+...
|
||||
+/ {
|
||||
+ ...
|
||||
+ res {
|
||||
+ ...
|
||||
+ linux,phandle = <0x00000001>;
|
||||
+ phandle = <0x00000001>;
|
||||
+ ...
|
||||
+ };
|
||||
+ ocp {
|
||||
+ ...
|
||||
+ linux,phandle = <0x00000002>;
|
||||
+ phandle = <0x00000002>;
|
||||
+ ...
|
||||
+ };
|
||||
+ __symbols__ {
|
||||
+ res="/res";
|
||||
+ ocp="/ocp";
|
||||
+ };
|
||||
+};
|
||||
+
|
||||
+Notice that all the nodes that had a label have been recorded, and that
|
||||
+phandles have been generated for them.
|
||||
+
|
||||
+This blob can be used to boot the board normally, the __symbols__ node will
|
||||
+be safely ignored both by the bootloader and the kernel (the only loss will
|
||||
+be a few bytes of memory and disk space).
|
||||
+
|
||||
+3.b) The Device Tree fragments must be compiled with the same option but they
|
||||
+must also have a tag (/plugin/) that allows undefined references to labels
|
||||
+that are not present at compilation time to be recorded so that the runtime
|
||||
+loader can fix them.
|
||||
+
|
||||
+So the bar peripheral's DTS format would be of the form:
|
||||
+
|
||||
+/plugin/; /* allow undefined label references and record them */
|
||||
+/ {
|
||||
+ .... /* various properties for loader use; i.e. part id etc. */
|
||||
+ fragment@0 {
|
||||
+ target = <&ocp>;
|
||||
+ __overlay__ {
|
||||
+ /* bar peripheral */
|
||||
+ bar {
|
||||
+ compatible = "corp,bar";
|
||||
+ ... /* various properties and child nodes */
|
||||
+ }
|
||||
+ };
|
||||
+ };
|
||||
+};
|
||||
+
|
||||
+Note that there's a target property that specifies the location where the
|
||||
+contents of the overlay node will be placed, and it references the label
|
||||
+in the foo.dts file.
|
||||
+
|
||||
+$ dtc -@ -O dtb -o bar.dtbo -b 0 bar.dts
|
||||
+$ fdtdump bar.dtbo
|
||||
+...
|
||||
+/ {
|
||||
+ ... /* properties */
|
||||
+ fragment@0 {
|
||||
+ target = <0xdeadbeef>;
|
||||
+ __overlay__ {
|
||||
+ bar {
|
||||
+ compatible = "corp,bar";
|
||||
+ ... /* various properties and child nodes */
|
||||
+ }
|
||||
+ };
|
||||
+ };
|
||||
+ __fixups__ {
|
||||
+ ocp = "/fragment@0:target:0";
|
||||
+ };
|
||||
+};
|
||||
+
|
||||
+No __symbols__ has been generated (no label in bar.dts).
|
||||
+Note that the target's ocp label is undefined, so the phandle handle
|
||||
+value is filled with the illegal value '0xdeadbeef', while a __fixups__
|
||||
+node has been generated, which marks the location in the tree where
|
||||
+the label lookup should store the runtime phandle value of the ocp node.
|
||||
+
|
||||
+The format of the __fixups__ node entry is
|
||||
+
|
||||
+ <label> = "<local-full-path>:<property-name>:<offset>";
|
||||
+
|
||||
+<label> Is the label we're referring
|
||||
+<local-full-path> Is the full path of the node the reference is
|
||||
+<property-name> Is the name of the property containing the
|
||||
+ reference
|
||||
+<offset> The offset (in bytes) of where the property's
|
||||
+ phandle value is located.
|
||||
+
|
||||
+Doing the same with the baz peripheral's DTS format is a little bit more
|
||||
+involved, since baz contains references to local labels which require
|
||||
+local fixups.
|
||||
+
|
||||
+/plugin/; /* allow undefined label references and record them */
|
||||
+/ {
|
||||
+ .... /* various properties for loader use; i.e. part id etc. */
|
||||
+ fragment@0 {
|
||||
+ target = <&res>;
|
||||
+ __overlay__ {
|
||||
+ /* baz resources */
|
||||
+ baz_res: res_baz { ... };
|
||||
+ };
|
||||
+ };
|
||||
+ fragment@1 {
|
||||
+ target = <&ocp>;
|
||||
+ __overlay__ {
|
||||
+ /* baz peripheral */
|
||||
+ baz {
|
||||
+ compatible = "corp,baz";
|
||||
+ /* reference to another point in the tree */
|
||||
+ ref-to-res = <&baz_res>;
|
||||
+ ... /* various properties and child nodes */
|
||||
+ }
|
||||
+ };
|
||||
+ };
|
||||
+};
|
||||
+
|
||||
+Note that &bar_res reference.
|
||||
+
|
||||
+$ dtc -@ -O dtb -o baz.dtbo -b 0 baz.dts
|
||||
+$ fdtdump baz.dtbo
|
||||
+...
|
||||
+/ {
|
||||
+ ... /* properties */
|
||||
+ fragment@0 {
|
||||
+ target = <0xdeadbeef>;
|
||||
+ __overlay__ {
|
||||
+ res_baz {
|
||||
+ ....
|
||||
+ linux,phandle = <0x00000001>;
|
||||
+ phandle = <0x00000001>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+ fragment@1 {
|
||||
+ target = <0xdeadbeef>;
|
||||
+ __overlay__ {
|
||||
+ baz {
|
||||
+ compatible = "corp,baz";
|
||||
+ ... /* various properties and child nodes */
|
||||
+ ref-to-res = <0x00000001>;
|
||||
+ }
|
||||
+ };
|
||||
+ };
|
||||
+ __fixups__ {
|
||||
+ res = "/fragment@0:target:0";
|
||||
+ ocp = "/fragment@1:target:0";
|
||||
+ };
|
||||
+ __local_fixups__ {
|
||||
+ fragment@1 {
|
||||
+ __overlay__ {
|
||||
+ baz {
|
||||
+ ref-to-res = <0>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+};
|
||||
+
|
||||
+This is similar to the bar case, but the reference of a local label by the
|
||||
+baz node generates a __local_fixups__ entry that records the place that the
|
||||
+local reference is being made. Since phandles are allocated starting at 1
|
||||
+the run time loader must apply an offset to each phandle in every dynamic
|
||||
+DT object loaded. The __local_fixups__ node records the place of every
|
||||
+local reference so that the loader can apply the offset.
|
||||
--
|
||||
2.2.2
|
||||
|
|
@ -1,33 +1,42 @@
|
|||
# Maintainer: Stefan Agner <stefan@agner.ch>
|
||||
# Maintainer: Kevin Mihelich <kevin@archlinuxarm.org>
|
||||
# Contributor: Anatol Pomozov
|
||||
# Contributor: Frederic Bezies <fredbezies at gmail dot com>
|
||||
|
||||
pkgname=dtc-overlay
|
||||
_gitname=dtc
|
||||
pkgver=1.4.0
|
||||
pkgver=1.4.1
|
||||
pkgrel=1
|
||||
pkgdesc="Device Tree Compiler with device tree overlay (Symbols and Fixup) support"
|
||||
url="http://jdl.com/software/"
|
||||
conflicts=('dtc', 'dtc-git')
|
||||
makedepends=('git')
|
||||
arch=('armv7h')
|
||||
license=('GPL2')
|
||||
source=('git+http://jdl.com/software/dtc.git#tag=v1.4.0'
|
||||
'dtc-dynamic-symbols-fixup-support.patch')
|
||||
md5sums=('SKIP'
|
||||
'6f0baf8509b56755643e9d62d94ec7bf')
|
||||
pkgdesc='Device Tree Compiler with device tree overlay support'
|
||||
url='http://www.devicetree.org/Device_Tree_Compiler'
|
||||
conflicts=('dtc')
|
||||
arch=(i686 x86_64)
|
||||
license=(GPL2)
|
||||
source=(https://www.kernel.org/pub/software/utils/dtc/dtc-$pkgver.tar.xz
|
||||
0001-dtc-Symbol-and-local-fixup-generation-support.patch
|
||||
0002-dtc-Plugin-object-device-tree-support.patch
|
||||
0003-dtc-Document-the-dynamic-plugin-internals.patch)
|
||||
sha256sums=('77992ad8eac7b68f553d0ba58e5b51604ac803d126196c99e3ae38aaae28bb94'
|
||||
'6efdc127acdc2f5ff4942c1f8e10e3fef30e6d6774a4d2dd6796d78e083bd74b'
|
||||
'9e67c8d5b7a7a7da7783167897aab38c0641732f9e0aa3dc6672fd7b13858c13'
|
||||
'bee82cf8ae70a9d3036e8b95a529f0d73c5209e1d2e209001bf888cd24df5f8b')
|
||||
|
||||
prepare() {
|
||||
cd ${_gitname}
|
||||
git apply ${srcdir}/dtc-dynamic-symbols-fixup-support.patch
|
||||
cd dtc-$pkgver
|
||||
patch -p1 -i ../0001-dtc-Symbol-and-local-fixup-generation-support.patch
|
||||
patch -p1 -i ../0002-dtc-Plugin-object-device-tree-support.patch
|
||||
patch -p1 -i ../0003-dtc-Document-the-dynamic-plugin-internals.patch
|
||||
}
|
||||
|
||||
build() {
|
||||
cd ${_gitname}
|
||||
make || return 1
|
||||
cd dtc-$pkgver
|
||||
make
|
||||
}
|
||||
|
||||
check() {
|
||||
cd dtc-$pkgver
|
||||
make check
|
||||
}
|
||||
|
||||
package() {
|
||||
cd ${_gitname}
|
||||
|
||||
make INSTALL=$(which install) DESTDIR=${pkgdir} PREFIX=/usr install || return 1
|
||||
cd dtc-$pkgver
|
||||
make DESTDIR="$pkgdir" PREFIX=/usr install
|
||||
}
|
||||
|
||||
|
|
|
@ -1,578 +0,0 @@
|
|||
From 61c5cdfd8e611d3a34497394098555b0b8644a31 Mon Sep 17 00:00:00 2001
|
||||
From: Pantelis Antoniou <panto@antoniou-consulting.com>
|
||||
Date: Fri, 4 Jan 2013 21:16:21 +0200
|
||||
Subject: [PATCH] dtc: Dynamic symbols & fixup support
|
||||
|
||||
Enable the generation of symbol & fixup information for
|
||||
usage with dynamic DT loading.
|
||||
|
||||
Passing the -@ option generates a __symbols__ node at the
|
||||
root node of the resulting blob for any node labels used.
|
||||
|
||||
When using the /plugin/ tag all unresolved label references
|
||||
be tracked in the __fixups__ node, while all local phandle
|
||||
references will the tracked in the __local_fixups__ node.
|
||||
|
||||
This is sufficient to implement a dynamic DT object loader.
|
||||
|
||||
Signed-off-by: Pantelis Antoniou <panto@antoniou-consulting.com>
|
||||
Signed-off-by: Stefan Agner <stefan@agner.ch>
|
||||
---
|
||||
Documentation/dts-format.txt | 7 +++
|
||||
Documentation/manual.txt | 8 +++
|
||||
checks.c | 120 +++++++++++++++++++++++++++++++++++--
|
||||
dtc-lexer.l | 5 ++
|
||||
dtc-parser.y | 23 ++++++-
|
||||
dtc.c | 9 ++-
|
||||
dtc.h | 38 ++++++++++++
|
||||
flattree.c | 139 +++++++++++++++++++++++++++++++++++++++++++
|
||||
8 files changed, 340 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/Documentation/dts-format.txt b/Documentation/dts-format.txt
|
||||
index 41741df..4da515c 100644
|
||||
--- a/Documentation/dts-format.txt
|
||||
+++ b/Documentation/dts-format.txt
|
||||
@@ -115,7 +115,14 @@ Version 1 DTS files have the overall layout:
|
||||
|
||||
* C style (/* ... */) and C++ style (// ...) comments are supported.
|
||||
|
||||
+Device Tree Objects
|
||||
+-------------------
|
||||
|
||||
+Using the plugin tag enables dynamic tree objects.
|
||||
+
|
||||
+ /plugin/;
|
||||
+
|
||||
+For the full details please see Documentation/dt-object-internal.txt
|
||||
|
||||
-- David Gibson <david@gibson.dropbear.id.au>
|
||||
-- Yoder Stuart <stuart.yoder@freescale.com>
|
||||
diff --git a/Documentation/manual.txt b/Documentation/manual.txt
|
||||
index 65c8540..d313715 100644
|
||||
--- a/Documentation/manual.txt
|
||||
+++ b/Documentation/manual.txt
|
||||
@@ -133,6 +133,14 @@ Options:
|
||||
By default the most recent version is generated.
|
||||
Relevant for dtb and asm output only.
|
||||
|
||||
+ -@
|
||||
+ Dynamic resolution mode. For non /plugin/ compilations generate
|
||||
+ a __symbols__ node containing a list of all nodes with a label.
|
||||
+ When /plugin/ is used, unresolved references are recorded in
|
||||
+ a __fixups__ node, while local phandle references are recorded
|
||||
+ in a __local_fixups__ node.
|
||||
+ See Documentation/dt-object-internal.txt
|
||||
+
|
||||
|
||||
The <output_version> defines what version of the "blob" format will be
|
||||
generated. Supported versions are 1, 2, 3, 16 and 17. The default is
|
||||
diff --git a/checks.c b/checks.c
|
||||
index ee96a25..970c0a3 100644
|
||||
--- a/checks.c
|
||||
+++ b/checks.c
|
||||
@@ -457,22 +457,93 @@ 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;
|
||||
+ 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 && !symbol_fixup_support) {
|
||||
FAIL(c, "Reference to non-existent node or label \"%s\"\n",
|
||||
- m->ref);
|
||||
+ m->ref);
|
||||
continue;
|
||||
}
|
||||
|
||||
- phandle = get_node_phandle(dt, refnode);
|
||||
- *((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle);
|
||||
+ if (!refnode) {
|
||||
+ /* 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);
|
||||
+
|
||||
+ /* if it's a plugin, we need to record it */
|
||||
+ if (symbol_fixup_support && dt->is_plugin) {
|
||||
+
|
||||
+ /* allocate a new local fixup entry */
|
||||
+ fe = xmalloc(sizeof(*fe));
|
||||
+
|
||||
+ fe->node = node;
|
||||
+ fe->prop = prop;
|
||||
+ fe->offset = m->offset;
|
||||
+ fe->next = NULL;
|
||||
+
|
||||
+ /* append it to the local fixups */
|
||||
+ fep = &dt->local_fixups;
|
||||
+ while (*fep)
|
||||
+ fep = &(*fep)->next;
|
||||
+ *fep = fe;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ *((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 +722,45 @@ 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;
|
||||
+
|
||||
+ if (!symbol_fixup_support)
|
||||
+ return;
|
||||
+
|
||||
+ 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 +779,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 3b41bfc..78d5132 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 <stdio.h>
|
||||
+#include <inttypes.h>
|
||||
|
||||
#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 <data> propdata
|
||||
%type <data> propdataprefix
|
||||
+%type <is_plugin> plugindecl
|
||||
%type <re> memreserve
|
||||
%type <re> memreserves
|
||||
%type <array> 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.c b/dtc.c
|
||||
index e3c9653..d2f9647 100644
|
||||
--- a/dtc.c
|
||||
+++ b/dtc.c
|
||||
@@ -29,6 +29,7 @@ int reservenum; /* Number of memory reservation slots */
|
||||
int minsize; /* Minimum blob size */
|
||||
int padsize; /* Additional padding to blob */
|
||||
int phandle_format = PHANDLE_BOTH; /* Use linux,phandle or phandle properties */
|
||||
+int symbol_fixup_support = 0;
|
||||
|
||||
static void fill_fullpaths(struct node *tree, const char *prefix)
|
||||
{
|
||||
@@ -49,7 +50,7 @@ static void fill_fullpaths(struct node *tree, const char *prefix)
|
||||
|
||||
/* Usage related data. */
|
||||
static const char usage_synopsis[] = "dtc [options] <input file>";
|
||||
-static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:fb:i:H:sW:E:hv";
|
||||
+static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:fb:i:H:sW:E:hv:@";
|
||||
static struct option const usage_long_opts[] = {
|
||||
{"quiet", no_argument, NULL, 'q'},
|
||||
{"in-format", a_argument, NULL, 'I'},
|
||||
@@ -67,6 +68,7 @@ static struct option const usage_long_opts[] = {
|
||||
{"phandle", a_argument, NULL, 'H'},
|
||||
{"warning", a_argument, NULL, 'W'},
|
||||
{"error", a_argument, NULL, 'E'},
|
||||
+ {"symbols", a_argument, NULL, '@'},
|
||||
{"help", no_argument, NULL, 'h'},
|
||||
{"version", no_argument, NULL, 'v'},
|
||||
{NULL, no_argument, NULL, 0x0},
|
||||
@@ -97,6 +99,7 @@ static const char * const usage_opts_help[] = {
|
||||
"\t\tboth - Both \"linux,phandle\" and \"phandle\" properties",
|
||||
"\n\tEnable/disable warnings (prefix with \"no-\")",
|
||||
"\n\tEnable/disable errors (prefix with \"no-\")",
|
||||
+ "\n\tSymbols and Fixups support",
|
||||
"\n\tPrint this help and exit",
|
||||
"\n\tPrint version and exit",
|
||||
NULL,
|
||||
@@ -184,7 +187,9 @@ int main(int argc, char *argv[])
|
||||
case 'E':
|
||||
parse_checks_option(false, true, optarg);
|
||||
break;
|
||||
-
|
||||
+ case '@':
|
||||
+ symbol_fixup_support = 1;
|
||||
+ break;
|
||||
case 'h':
|
||||
usage(NULL);
|
||||
default:
|
||||
diff --git a/dtc.h b/dtc.h
|
||||
index 264a20c..8c9059b 100644
|
||||
--- a/dtc.h
|
||||
+++ b/dtc.h
|
||||
@@ -54,6 +54,7 @@ extern int reservenum; /* Number of memory reservation slots */
|
||||
extern int minsize; /* Minimum blob size */
|
||||
extern int padsize; /* Additional padding to blob */
|
||||
extern int phandle_format; /* Use linux,phandle or phandle properties */
|
||||
+extern int symbol_fixup_support;/* enable symbols & fixup support */
|
||||
|
||||
#define PHANDLE_LEGACY 0x1
|
||||
#define PHANDLE_EPAPR 0x2
|
||||
@@ -132,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;
|
||||
@@ -158,6 +178,12 @@ struct node {
|
||||
int addr_cells, size_cells;
|
||||
|
||||
struct label *labels;
|
||||
+
|
||||
+ int is_root;
|
||||
+ int is_plugin;
|
||||
+ struct fixup *fixups;
|
||||
+ struct symbol *symbols;
|
||||
+ struct fixup_entry *local_fixups;
|
||||
};
|
||||
|
||||
#define for_each_label_withdel(l0, l) \
|
||||
@@ -181,6 +207,18 @@ 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)
|
||||
+
|
||||
+#define for_each_local_fixup_entry(n, fe) \
|
||||
+ for ((fe) = (n)->local_fixups; (fe); (fe) = (fe)->next)
|
||||
+
|
||||
void add_label(struct label **labels, char *label);
|
||||
void delete_labels(struct label **labels);
|
||||
|
||||
diff --git a/flattree.c b/flattree.c
|
||||
index 665dad7..6237715 100644
|
||||
--- a/flattree.c
|
||||
+++ b/flattree.c
|
||||
@@ -262,6 +262,12 @@ static void flatten_tree(struct node *tree, struct emitter *emit,
|
||||
struct property *prop;
|
||||
struct node *child;
|
||||
int seen_name_prop = 0;
|
||||
+ struct symbol *sym;
|
||||
+ struct fixup *f;
|
||||
+ struct fixup_entry *fe;
|
||||
+ char *name, *s;
|
||||
+ const char *fullpath;
|
||||
+ int namesz, nameoff, vallen;
|
||||
|
||||
if (tree->deleted)
|
||||
return;
|
||||
@@ -310,6 +316,139 @@ static void flatten_tree(struct node *tree, struct emitter *emit,
|
||||
flatten_tree(child, emit, etarget, strbuf, vi);
|
||||
}
|
||||
|
||||
+ if (!symbol_fixup_support)
|
||||
+ goto no_symbols;
|
||||
+
|
||||
+ /* add the symbol nodes (if any) */
|
||||
+ if (tree->symbols) {
|
||||
+
|
||||
+ emit->beginnode(etarget, NULL);
|
||||
+ emit->string(etarget, "__symbols__", 0);
|
||||
+ emit->align(etarget, sizeof(cell_t));
|
||||
+
|
||||
+ for_each_symbol(tree, sym) {
|
||||
+
|
||||
+ vallen = strlen(sym->node->fullpath);
|
||||
+
|
||||
+ nameoff = stringtable_insert(strbuf, sym->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, sym->node->fullpath,
|
||||
+ strlen(sym->node->fullpath));
|
||||
+ emit->align(etarget, sizeof(cell_t));
|
||||
+ }
|
||||
+
|
||||
+ emit->endnode(etarget, NULL);
|
||||
+ }
|
||||
+
|
||||
+ /* add the fixup nodes */
|
||||
+ if (tree->fixups) {
|
||||
+
|
||||
+ /* 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 :<number> + '\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);
|
||||
+ }
|
||||
+
|
||||
+ /* add the local fixup property */
|
||||
+ if (tree->local_fixups) {
|
||||
+
|
||||
+ /* emit the external fixups */
|
||||
+ emit->beginnode(etarget, NULL);
|
||||
+ emit->string(etarget, "__local_fixups__", 0);
|
||||
+ emit->align(etarget, sizeof(cell_t));
|
||||
+
|
||||
+ namesz = 0;
|
||||
+ for_each_local_fixup_entry(tree, fe) {
|
||||
+ fullpath = fe->node->fullpath;
|
||||
+ if (fullpath[0] == '\0')
|
||||
+ fullpath = "/";
|
||||
+ namesz += strlen(fullpath) + 1;
|
||||
+ namesz += strlen(fe->prop->name) + 1;
|
||||
+ namesz += 32; /* space for :<number> + '\0' */
|
||||
+ }
|
||||
+
|
||||
+ name = xmalloc(namesz);
|
||||
+
|
||||
+ s = name;
|
||||
+ for_each_local_fixup_entry(tree, 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, "fixup");
|
||||
+ 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);
|
||||
+ }
|
||||
+
|
||||
+no_symbols:
|
||||
emit->endnode(etarget, tree->labels);
|
||||
}
|
||||
|
||||
--
|
||||
1.8.3.1
|
||||
|
Loading…
Reference in a new issue