Page MenuHomeFreeBSD

D3180.id7245.diff
No OneTemporary

D3180.id7245.diff

Index: contrib/dtc/Documentation/dts-format.txt
===================================================================
--- contrib/dtc/Documentation/dts-format.txt
+++ contrib/dtc/Documentation/dts-format.txt
@@ -115,7 +115,14 @@
* 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>
Index: contrib/dtc/Documentation/manual.txt
===================================================================
--- contrib/dtc/Documentation/manual.txt
+++ contrib/dtc/Documentation/manual.txt
@@ -133,6 +133,14 @@
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
Index: contrib/dtc/checks.c
===================================================================
--- contrib/dtc/checks.c
+++ contrib/dtc/checks.c
@@ -457,22 +457,93 @@
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 @@
}
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 @@
&avoid_default_addr_size,
&obsolete_chosen_interrupt_controller,
+ &auto_label_phandles,
+
&always_fail,
};
Index: contrib/dtc/dtc-lexer.l
===================================================================
--- contrib/dtc/dtc-lexer.l
+++ contrib/dtc/dtc-lexer.l
@@ -118,6 +118,11 @@
return DT_V1;
}
+<*>"/plugin/" {
+ DPRINT("Keyword: /plugin/\n");
+ return DT_PLUGIN;
+ }
+
<*>"/memreserve/" {
DPRINT("Keyword: /memreserve/\n");
BEGIN_DEFAULT();
Index: contrib/dtc/dtc-parser.y
===================================================================
--- contrib/dtc/dtc-parser.y
+++ contrib/dtc/dtc-parser.y
@@ -20,6 +20,7 @@
%{
#include <stdio.h>
+#include <inttypes.h>
#include "dtc.h"
#include "srcpos.h"
@@ -52,9 +53,11 @@
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
@@ -72,6 +75,7 @@
%type <data> propdata
%type <data> propdataprefix
+%type <is_plugin> plugindecl
%type <re> memreserve
%type <re> memreserves
%type <array> arrayprefix
@@ -102,10 +106,23 @@
%%
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;
}
;
Index: contrib/dtc/dtc.h
===================================================================
--- contrib/dtc/dtc.h
+++ contrib/dtc/dtc.h
@@ -54,6 +54,7 @@
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 *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 {
bool deleted;
char *name;
@@ -158,6 +178,12 @@
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 @@
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);
Index: contrib/dtc/dtc.c
===================================================================
--- contrib/dtc/dtc.c
+++ contrib/dtc/dtc.c
@@ -29,6 +29,7 @@
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 @@
/* 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 @@
{"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 @@
"\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 @@
case 'E':
parse_checks_option(false, true, optarg);
break;
-
+ case '@':
+ symbol_fixup_support = 1;
+ break;
case 'h':
usage(NULL);
default:
Index: contrib/dtc/flattree.c
===================================================================
--- contrib/dtc/flattree.c
+++ contrib/dtc/flattree.c
@@ -262,6 +262,12 @@
struct property *prop;
struct node *child;
bool seen_name_prop = false;
+ 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 @@
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);
}
Index: sys/boot/fdt/Makefile
===================================================================
--- sys/boot/fdt/Makefile
+++ sys/boot/fdt/Makefile
@@ -10,7 +10,7 @@
fdt_empty_tree.c
# Loader's fdt commands extension sources.
-SRCS+= fdt_loader_cmd.c
+SRCS+= fdt_loader_cmd.c fdt_overlay.c
CFLAGS+= -I${.CURDIR}/../../contrib/libfdt/ -I${.CURDIR}/../common/
Index: sys/boot/fdt/fdt_loader_cmd.c
===================================================================
--- sys/boot/fdt/fdt_loader_cmd.c
+++ sys/boot/fdt/fdt_loader_cmd.c
@@ -39,6 +39,7 @@
#include "bootstrap.h"
#include "fdt_platform.h"
+#include "fdt_overlay.h"
#ifdef DEBUG
#define debugf(fmt, args...) do { printf("%s(): ", __func__); \
@@ -276,6 +277,128 @@
return (0);
}
+static int
+fdt_load_dtb_overlay(const char * filename)
+{
+ struct preloaded_file *bfp, *oldbfp;
+ struct fdt_header header;
+ int err;
+
+ debugf("fdt_load_dtb_overlay(%s)\n", filename);
+
+ oldbfp = file_findfile(filename, "dtbo");
+
+ /* Attempt to load and validate a new dtb from a file. */
+ if ((bfp = file_loadraw(filename, "dtbo", 1)) == NULL) {
+ printf("failed to load file '%s'\n", filename);
+ return (1);
+ }
+
+ COPYOUT(bfp->f_addr, &header, sizeof(header));
+ err = fdt_check_header(&header);
+
+ if (err < 0) {
+ file_discard(bfp);
+ if (err == -FDT_ERR_BADVERSION)
+ printf("incompatible blob version: %d, should be: %d\n",
+ fdt_version(fdtp), FDT_LAST_SUPPORTED_VERSION);
+
+ else
+ printf("error validating blob: %s\n",
+ fdt_strerror(err));
+ return (1);
+ }
+
+ /* A new dtb was validated, discard any previous file. */
+ if (oldbfp)
+ file_discard(oldbfp);
+
+ return (0);
+}
+
+int
+fdt_load_dtb_overlays(const char * filenames)
+{
+ char *names;
+ char *name;
+ char *comaptr;
+
+ debugf("fdt_load_dtb_overlay(%s)\n", filenames);
+
+ names = strdup(filenames);
+ if (names == NULL)
+ return (1);
+ name = names;
+ do {
+ comaptr = strchr(name, ',');
+ if (comaptr)
+ *comaptr = '\0';
+ fdt_load_dtb_overlay(name);
+ name = comaptr + 1;
+ } while(comaptr);
+
+ free(names);
+ return (0);
+}
+
+void
+fdt_apply_overlays()
+{
+ struct preloaded_file *fp;
+ size_t overlays_size, max_overlay_size, new_fdtp_size;
+ void *new_fdtp;
+ void *overlay;
+ int rv;
+
+ if ((fdtp == NULL) || (fdtp_size == 0))
+ return;
+
+ overlays_size = 0;
+ max_overlay_size = 0;
+ for (fp = file_findfile(NULL, "dtbo"); fp != NULL; fp = fp->f_next) {
+ if (max_overlay_size < fp->f_size)
+ max_overlay_size = fp->f_size;
+ overlays_size += fp->f_size;
+ }
+
+ /* Nothing to apply */
+ if (overlays_size == 0)
+ return;
+
+ /* It's actually more than enough */
+ new_fdtp_size = fdtp_size + overlays_size;
+ new_fdtp = malloc(new_fdtp_size);
+ if (new_fdtp == NULL) {
+ printf("failed to allocate memory for DTB blob with overlays\n");
+ return;
+ }
+
+ overlay = malloc(max_overlay_size);
+ if (overlay == NULL) {
+ printf("failed to allocate memory for DTB blob with overlays\n");
+ free(new_fdtp);
+ return;
+ }
+
+ rv = fdt_open_into(fdtp, new_fdtp, new_fdtp_size);
+ if (rv != 0) {
+ printf("failed to open DTB blob for applying overlays\n");
+ return;
+ }
+
+ for (fp = file_findfile(NULL, "dtbo"); fp != NULL; fp = fp->f_next) {
+ printf("applying DTB overlay '%s'\n", fp->f_name);
+ COPYOUT(fp->f_addr, overlay, fp->f_size);
+ fdt_overlay_apply(new_fdtp, overlay, fp->f_size);
+ }
+
+ free(fdtp);
+ fdtp = new_fdtp;
+ fdtp_size = new_fdtp_size;
+
+ free(overlay);
+}
+
int
fdt_setup_fdtp()
{
Index: sys/boot/fdt/fdt_overlay.h
===================================================================
--- /dev/null
+++ sys/boot/fdt/fdt_overlay.h
@@ -0,0 +1,34 @@
+/*-
+ * Copyright (c) 2015 Oleksandr Tymoshenko <gonzo@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef FDT_OVERLAY_H
+#define FDT_OVERLAY_H
+
+int fdt_overlay_apply(void *main_fdtp, void *overlay_fdtp, size_t overlay_length);
+
+#endif /* FDT_OVERLAY_H */
Index: sys/boot/fdt/fdt_overlay.c
===================================================================
--- /dev/null
+++ sys/boot/fdt/fdt_overlay.c
@@ -0,0 +1,441 @@
+/*-
+ * Copyright (c) 2015 Oleksandr Tymoshenko <gonzo@FreeBSD.org>
+ * All rights reserved.
+ *
+ * This software was developed by Semihalf under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stand.h>
+#include <libfdt.h>
+
+#include "fdt_overlay.h"
+
+/*
+ * Get max phandle
+ */
+static uint32_t
+fdt_max_phandle(void *fdtp)
+{
+ int o, depth;
+ uint32_t max_phandle, phandle;
+
+ depth = 1;
+ o = fdt_path_offset(fdtp, "/");
+ max_phandle = fdt_get_phandle(fdtp, o);
+ for (depth = 0; (o >= 0) && (depth >= 0); o = fdt_next_node(fdtp, o, &depth)) {
+ phandle = fdt_get_phandle(fdtp, o);
+ if (max_phandle < phandle)
+ max_phandle = phandle;
+ }
+
+ return max_phandle;
+}
+
+/*
+ * Returns exact memory location specified by fixup in format
+ * /path/to/node:property:offset
+ */
+static void *
+fdt_get_fixup_location(void *fdtp, const char *fixup)
+{
+ char *path, *prop, *offsetp, *endp;
+ int prop_offset, o, proplen;
+ void *result;
+
+ result = 0;
+
+ path = strdup(fixup);
+ prop = strchr(path, ':');
+ if (prop == NULL) {
+ printf("missing property part in \"%s\"\n", fixup);
+ result = NULL;
+ goto out;
+ }
+
+ *prop = 0;
+ prop++;
+
+ offsetp = strchr(prop, ':');
+ if (offsetp == NULL) {
+ printf("missing offset part in \"%s\"\n", fixup);
+ result = NULL;
+ goto out;
+ }
+
+ *offsetp = 0;
+ offsetp++;
+
+ prop_offset = strtoul(offsetp, &endp, 10);
+ if (*endp != '\0') {
+ printf("\"%s\" is not valid number\n", offsetp);
+ result = NULL;
+ goto out;
+ }
+
+ o = fdt_path_offset(fdtp, path);
+ if (o < 0) {
+ printf("path \"%s\" not found\n", path);
+ result = NULL;
+ goto out;
+ }
+
+ result = fdt_getprop_w(fdtp, o, prop, &proplen);
+ if (result == NULL){
+ printf("property \"%s\" not found in \"%s\" node\n", prop, path);
+ result = NULL;
+ goto out;
+ }
+
+ if (proplen < prop_offset + sizeof(uint32_t)) {
+ printf("%s: property length is too small for fixup\n", fixup);
+ result = NULL;
+ goto out;
+ }
+
+ result = (char*)result + prop_offset;
+
+out:
+ free(path);
+ return (result);
+}
+
+/*
+ * Process one entry in __fixups__ { } node
+ * @fixups is property value, array of NUL-terminated strings
+ * with fixup locations
+ * @fixups_len length of the fixups array in bytes
+ * @phandle is value for these locations
+ */
+static int
+fdt_do_one_fixup(void *fdtp, const char *fixups, int fixups_len, int phandle)
+{
+ void *fixup_pos;
+ uint32_t val;
+
+ val = cpu_to_fdt32(phandle);
+
+ while (fixups_len > 0) {
+ fixup_pos = fdt_get_fixup_location(fdtp, fixups);
+ if (fixup_pos != NULL)
+ memcpy(fixup_pos, &val, sizeof(val));
+
+ fixups_len -= strlen(fixups) + 1;
+ fixups += strlen(fixups) + 1;
+ }
+
+ return (0);
+}
+
+/*
+ * Increase u32 value at pos by offset
+ */
+static void
+fdt_increase_u32(void *pos, uint32_t offset)
+{
+ uint32_t val;
+
+ memcpy(&val, pos, sizeof(val));
+ val = cpu_to_fdt32(fdt32_to_cpu(val) + offset);
+ memcpy(pos, &val, sizeof(val));
+}
+
+/*
+ * Process local fixups
+ * @fixups is property value, array of NUL-terminated strings
+ * with fixup locations
+ * @fixups_len length of the fixups array in bytes
+ * @offset value these locations should be increased by
+ */
+static int
+fdt_do_local_fixup(void *fdtp, const char *fixups, int fixups_len, int offset)
+{
+ void *fixup_pos;
+
+ while (fixups_len > 0) {
+ fixup_pos = fdt_get_fixup_location(fdtp, fixups);
+ if (fixup_pos != NULL)
+ fdt_increase_u32(fixup_pos, offset);
+
+ fixups_len -= strlen(fixups) + 1;
+ fixups += strlen(fixups) + 1;
+ }
+
+ return (0);
+}
+
+/*
+ * Increase node phandle by phandle_offset
+ */
+static void
+fdt_increase_phandle(void *fdtp, int node_offset, uint32_t phandle_offset)
+{
+ int proplen;
+ void *phandle_pos, *node_pos;
+
+ node_pos = (char*)fdtp + node_offset;
+
+ phandle_pos = fdt_getprop_w(fdtp, node_offset, "phandle", &proplen);
+ if (phandle_pos)
+ fdt_increase_u32(phandle_pos, phandle_offset);
+ phandle_pos = fdt_getprop_w(fdtp, node_offset, "linux,phandle", &proplen);
+ if (phandle_pos)
+ fdt_increase_u32(phandle_pos, phandle_offset);
+}
+
+/*
+ * Increase all phandles by offset
+ */
+static void
+fdt_increase_phandles(void *fdtp, uint32_t offset)
+{
+ int o, depth;
+
+ o = fdt_path_offset(fdtp, "/");
+ for (depth = 0; (o >= 0) && (depth >= 0); o = fdt_next_node(fdtp, o, &depth)) {
+ fdt_increase_phandle(fdtp, o, offset);
+ }
+}
+
+/*
+ * Overlay one node deviced by <overlay_fdtp, overlay_o> over <main_fdtp, target_o>
+ */
+static void
+fdt_overlay_node(void *main_fdtp, int target_o, void *overlay_fdtp, int overlay_o)
+{
+ int len, o, depth;
+ const char *name;
+ const void *val;
+ int target_subnode_o;
+
+ /* Overlay properties */
+ for (o = fdt_first_property_offset(overlay_fdtp, overlay_o);
+ o >= 0; o = fdt_next_property_offset(overlay_fdtp, o)) {
+ val = fdt_getprop_by_offset(overlay_fdtp, o, &name, &len);
+ if (val)
+ fdt_setprop(main_fdtp, target_o, name, val, len);
+ }
+
+ /* Now overlay nodes */
+ o = overlay_o;
+ for (depth = 0; (o >= 0) && (depth >= 0);
+ o = fdt_next_node(overlay_fdtp, o, &depth)) {
+ if (depth != 1)
+ continue;
+ /* Check if there is node with the same name */
+ name = fdt_get_name(overlay_fdtp, o, NULL);
+ target_subnode_o = fdt_subnode_offset(main_fdtp, target_o, name);
+ if (target_subnode_o < 0) {
+ /* create new subnode and run merge recursively */
+ target_subnode_o = fdt_add_subnode(main_fdtp, target_o, name);
+ if (target_subnode_o < 0) {
+ printf("failed to create subnode \"%s\": %d\n",
+ name, target_subnode_o);
+ return;
+ }
+ }
+
+ fdt_overlay_node(main_fdtp, target_subnode_o,
+ overlay_fdtp, o);
+ }
+}
+
+/*
+ * Apply one overlay fragment
+ */
+static void
+fdt_apply_fragment(void *main_fdtp, void *overlay_fdtp, int fragment_o)
+{
+ uint32_t target;
+ const char *target_path;
+ const void *val;
+ int target_node_o, overlay_node_o;
+
+ target_node_o = -1;
+ val = fdt_getprop(overlay_fdtp, fragment_o, "target", NULL);
+ if (val) {
+ memcpy(&target, val, sizeof(target));
+ target = fdt32_to_cpu(target);
+ target_node_o = fdt_node_offset_by_phandle(main_fdtp, target);
+ if (target_node_o < 0) {
+ printf("failed to find target %04x\n", target);
+ return;
+ }
+ }
+
+ if (target_node_o < 0) {
+ target_path = fdt_getprop(overlay_fdtp, fragment_o, "target-path", NULL);
+ if (target_path == NULL)
+ return;
+
+ target_node_o = fdt_path_offset(main_fdtp, target_path);
+ if (target_node_o < 0) {
+ printf("failed to find target-path %s\n", target_path);
+ return;
+ }
+ }
+
+ if (target_node_o < 0)
+ return;
+
+ overlay_node_o = fdt_subnode_offset(overlay_fdtp, fragment_o, "__overlay__");
+ if (overlay_node_o < 0) {
+ printf("missing __overlay__ sub-node\n");
+ return;
+ }
+
+ fdt_overlay_node(main_fdtp, target_node_o, overlay_fdtp, overlay_node_o);
+}
+
+/*
+ * Handle __fixups__ node in overlay DTB
+ */
+static int
+fdt_overlay_do_fixups(void *main_fdtp, void *overlay_fdtp)
+{
+ int main_symbols_o, symbol_o, overlay_fixups_o;
+ int fixup_prop_o;
+ int len;
+ const char *fixups, *name;
+ const char *symbol_path;
+ uint32_t phandle;
+
+ main_symbols_o = fdt_path_offset(main_fdtp, "/__symbols__");
+ overlay_fixups_o = fdt_path_offset(overlay_fdtp, "/__fixups__");
+
+ if (main_symbols_o < 0)
+ return (-1);
+ if (overlay_fixups_o < 0)
+ return (-1);
+
+ for (fixup_prop_o = fdt_first_property_offset(overlay_fdtp, overlay_fixups_o);
+ fixup_prop_o >= 0;
+ fixup_prop_o = fdt_next_property_offset(overlay_fdtp, fixup_prop_o)) {
+ fixups = fdt_getprop_by_offset(overlay_fdtp, fixup_prop_o, &name, &len);
+ symbol_path = fdt_getprop(main_fdtp, main_symbols_o, name, NULL);
+ if (symbol_path == NULL) {
+ printf("couldn't find \"%s\" symbol in main dtb\n", name);
+ return (-1);
+ }
+ symbol_o = fdt_path_offset(main_fdtp, symbol_path);
+ if (symbol_o < 0) {
+ printf("couldn't find \"%s\" path in main dtb\n", symbol_path);
+ return (-1);
+ }
+ phandle = fdt_get_phandle(main_fdtp, symbol_o);
+ if (fdt_do_one_fixup(overlay_fdtp, fixups, len, phandle) < 0)
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * Handle __local_fixups__ node in overlay DTB
+ */
+static int
+fdt_overlay_do_local_fixups(void *main_fdtp, void *overlay_fdtp)
+{
+ int overlay_local_fixups_o;
+ int len;
+ const char *fixups;
+ uint32_t phandle_offset;
+
+ overlay_local_fixups_o = fdt_path_offset(overlay_fdtp, "/__local_fixups__");
+
+ if (overlay_local_fixups_o < 0)
+ return (-1);
+
+ phandle_offset = fdt_max_phandle(main_fdtp);
+ fdt_increase_phandles(overlay_fdtp, phandle_offset);
+ fixups = fdt_getprop_w(overlay_fdtp, overlay_local_fixups_o, "fixup", &len);
+ if (fixups) {
+ if (fdt_do_local_fixup(overlay_fdtp, fixups, len, phandle_offset) < 0)
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * Apply all fragments to main DTB
+ */
+static int
+fdt_overlay_apply_fragments(void *main_fdtp, void *overlay_fdtp)
+{
+ int o, depth;
+
+ o = fdt_path_offset(overlay_fdtp, "/");
+ for (depth = 0; (o >= 0) && (depth >= 0); o = fdt_next_node(overlay_fdtp, o, &depth)) {
+ if (depth != 1)
+ continue;
+
+ fdt_apply_fragment(main_fdtp, overlay_fdtp, o);
+ }
+
+ return (0);
+}
+
+int
+fdt_overlay_apply(void *main_fdtp, void *overlay_fdtp, size_t overlay_length)
+{
+ void *overlay_copy;
+ int rv;
+
+ rv = 0;
+
+ /* We modify overlay in-place, so we need writable copy */
+ overlay_copy = malloc(overlay_length);
+ if (overlay_copy == NULL) {
+ printf("failed to allocate memory for overlay copy\n");
+ return (-1);
+ }
+
+ memcpy(overlay_copy, overlay_fdtp, overlay_length);
+
+ if (fdt_overlay_do_fixups(main_fdtp, overlay_copy) < 0) {
+ printf("failed to perform fixups in overlay\n");
+ rv = -1;
+ goto out;
+ }
+
+ if (fdt_overlay_do_local_fixups(main_fdtp, overlay_copy) < 0) {
+ printf("failed to perform local fixups in overlay\n");
+ rv = -1;
+ goto out;
+ }
+
+ if (fdt_overlay_apply_fragments(main_fdtp, overlay_copy) < 0) {
+ printf("failed to apply fragments\n");
+ rv = -1;
+ }
+
+out:
+ free(overlay_copy);
+
+ return (rv);
+}
Index: sys/boot/fdt/fdt_platform.h
===================================================================
--- sys/boot/fdt/fdt_platform.h
+++ sys/boot/fdt/fdt_platform.h
@@ -43,8 +43,10 @@
void fdt_fixup_ethernet(const char *, char *, int);
void fdt_fixup_memory(struct fdt_mem_region *, size_t);
void fdt_fixup_stdout(const char *);
+void fdt_apply_overlays(void);
int fdt_load_dtb_addr(struct fdt_header *);
int fdt_load_dtb_file(const char *);
+int fdt_load_dtb_overlays(const char *);
int fdt_setup_fdtp(void);
/* The platform library needs to implement these functions */
Index: sys/boot/uboot/fdt/uboot_fdt.c
===================================================================
--- sys/boot/uboot/fdt/uboot_fdt.c
+++ sys/boot/uboot/fdt/uboot_fdt.c
@@ -45,6 +45,7 @@
struct fdt_header *hdr;
const char *s;
char *p;
+ int rv;
/*
* If the U-boot environment contains a variable giving the address of a
@@ -68,6 +69,8 @@
}
}
+ rv = 1;
+
/*
* If the U-boot environment contains a variable giving the name of a
* file, use it if we can load and validate it.
@@ -78,11 +81,21 @@
if (s != NULL && *s != '\0') {
if (fdt_load_dtb_file(s) == 0) {
printf("Loaded DTB from file '%s'.\n", s);
- return (0);
+ rv = 0;
}
}
- return (1);
+ if (rv == 0) {
+ s = getenv("fdt_overlays");
+ if (s == NULL)
+ s = ub_env_get("fdt_overlays");
+ if (s != NULL && *s != '\0') {
+ printf("Loading DTB overlays: '%s'\n", s);
+ fdt_load_dtb_overlays(s);
+ }
+ }
+
+ return (rv);
}
void
@@ -98,6 +111,9 @@
eth_no = 0;
ethstr = NULL;
+ /* Apply overlays before anything else */
+ fdt_apply_overlays();
+
/* Acquire sys_info */
si = ub_get_sys_info();
Index: sys/tools/fdt/make_dtb.sh
===================================================================
--- sys/tools/fdt/make_dtb.sh
+++ sys/tools/fdt/make_dtb.sh
@@ -20,5 +20,5 @@
dtb=${dtb_path}/`basename $d .dts`.dtb
echo "converting $d -> $dtb"
cpp -P -x assembler-with-cpp -I $S/gnu/dts/include -I $S/boot/fdt/dts/${MACHINE} -I $S/gnu/dts/${MACHINE} -include $d /dev/null |
- dtc -O dtb -o $dtb -b 0 -p 1024 -i $S/boot/fdt/dts/${MACHINE} -i $S/gnu/dts/${MACHINE}
+ dtc -O dtb -o $dtb -b 0 -@ -p 1024 -i $S/boot/fdt/dts/${MACHINE} -i $S/gnu/dts/${MACHINE}
done

File Metadata

Mime Type
text/plain
Expires
Wed, Apr 22, 11:19 AM (6 h, 32 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
31973400
Default Alt Text
D3180.id7245.diff (31 KB)

Event Timeline