Browse Source

dtc: Plugin and fixup support

This patch 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.

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@konsulko.com>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Jan Luebbe <jlu@pengutronix.de>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
main
Pantelis Antoniou 8 years ago committed by David Gibson
parent
commit
20f29d8d41
  1. 21
      Documentation/manual.txt
  2. 8
      checks.c
  3. 5
      dtc-lexer.l
  4. 28
      dtc-parser.y
  5. 33
      dtc.c
  6. 16
      dtc.h
  7. 2
      flattree.c
  8. 2
      fstree.c
  9. 269
      livetree.c

21
Documentation/manual.txt

@ -119,6 +119,20 @@ Options: @@ -119,6 +119,20 @@ 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.

When using the /plugin/ tag all unresolved label references to
be tracked in the __fixups__ node, making dynamic resolution possible.

-A
Generate automatically aliases for all node labels. This is similar to
the -@ option (the __symbols__ node contain identical information) but
the semantics are slightly different since no phandles are automatically
generated for labeled nodes.

-S <bytes>
Ensure the blob at least <bytes> long, adding additional
space if needed.
@ -146,13 +160,18 @@ Additionally, dtc performs various sanity checks on the tree. @@ -146,13 +160,18 @@ Additionally, dtc performs various sanity checks on the tree.
Here is a very rough overview of the layout of a DTS source file:


sourcefile: list_of_memreserve devicetree
sourcefile: versioninfo plugindecl list_of_memreserve devicetree

memreserve: label 'memreserve' ADDR ADDR ';'
| label 'memreserve' ADDR '-' ADDR ';'

devicetree: '/' nodedef

versioninfo: '/' 'dts-v1' '/' ';'

plugindecl: '/' 'plugin' '/' ';'
| /* empty */

nodedef: '{' list_of_property list_of_subnode '}' ';'

property: label PROPNAME '=' propdata ';'

8
checks.c

@ -487,8 +487,12 @@ static void fixup_phandle_references(struct check *c, struct boot_info *bi, @@ -487,8 +487,12 @@ static void fixup_phandle_references(struct check *c, struct boot_info *bi,

refnode = get_node_by_ref(dt, m->ref);
if (! refnode) {
FAIL(c, "Reference to non-existent node or label \"%s\"\n",
m->ref);
if (!(bi->dtsflags & DTSF_PLUGIN))
FAIL(c, "Reference to non-existent node or "
"label \"%s\"\n", m->ref);
else /* mark the entry as unresolved */
*((cell_t *)(prop->val.val + m->offset)) =
cpu_to_fdt32(0xffffffff);
continue;
}


5
dtc-lexer.l

@ -121,6 +121,11 @@ static void lexical_error(const char *fmt, ...); @@ -121,6 +121,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();

28
dtc-parser.y

@ -19,6 +19,7 @@ @@ -19,6 +19,7 @@
*/
%{
#include <stdio.h>
#include <inttypes.h>

#include "dtc.h"
#include "srcpos.h"
@ -52,9 +53,11 @@ extern bool treesource_error; @@ -52,9 +53,11 @@ extern bool treesource_error;
struct node *nodelist;
struct reserve_info *re;
uint64_t integer;
unsigned int flags;
}

%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,8 @@ extern bool treesource_error; @@ -71,6 +74,8 @@ extern bool treesource_error;

%type <data> propdata
%type <data> propdataprefix
%type <flags> versioninfo
%type <flags> plugindecl
%type <re> memreserve
%type <re> memreserves
%type <array> arrayprefix
@ -101,16 +106,33 @@ extern bool treesource_error; @@ -101,16 +106,33 @@ extern bool treesource_error;
%%

sourcefile:
v1tag memreserves devicetree
versioninfo plugindecl memreserves devicetree
{
the_boot_info = build_boot_info($2, $3,
guess_boot_cpuid($3));
the_boot_info = build_boot_info($1 | $2, $3, $4,
guess_boot_cpuid($4));
}
;

versioninfo:
v1tag
{
$$ = DTSF_V1;
}
;

v1tag:
DT_V1 ';'
| DT_V1 ';' v1tag

plugindecl:
DT_PLUGIN ';'
{
$$ = DTSF_PLUGIN;
}
| /* empty */
{
$$ = 0;
}
;

memreserves:

33
dtc.c

@ -32,6 +32,9 @@ int minsize; /* Minimum blob size */ @@ -32,6 +32,9 @@ int minsize; /* Minimum blob size */
int padsize; /* Additional padding to blob */
int alignsize; /* Additional padding to blob accroding to the alignsize */
int phandle_format = PHANDLE_BOTH; /* Use linux,phandle or phandle properties */
int generate_symbols; /* enable symbols & fixup support */
int generate_fixups; /* suppress generation of fixups on symbol support */
int auto_label_aliases; /* auto generate labels -> aliases */

static int is_power_of_2(int x)
{
@ -59,7 +62,7 @@ static void fill_fullpaths(struct node *tree, const char *prefix) @@ -59,7 +62,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:a:fb:i:H:sW:E:hv";
static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:a:fb:i:H:sW:E:@Ahv";
static struct option const usage_long_opts[] = {
{"quiet", no_argument, NULL, 'q'},
{"in-format", a_argument, NULL, 'I'},
@ -78,6 +81,8 @@ static struct option const usage_long_opts[] = { @@ -78,6 +81,8 @@ 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, '@'},
{"auto-alias", no_argument, NULL, 'A'},
{"help", no_argument, NULL, 'h'},
{"version", no_argument, NULL, 'v'},
{NULL, no_argument, NULL, 0x0},
@ -109,6 +114,8 @@ static const char * const usage_opts_help[] = { @@ -109,6 +114,8 @@ 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 generation of symbols",
"\n\tEnable auto-alias of labels",
"\n\tPrint this help and exit",
"\n\tPrint version and exit",
NULL,
@ -249,6 +256,13 @@ int main(int argc, char *argv[]) @@ -249,6 +256,13 @@ int main(int argc, char *argv[])
parse_checks_option(false, true, optarg);
break;

case '@':
generate_symbols = 1;
break;
case 'A':
auto_label_aliases = 1;
break;

case 'h':
usage(NULL);
default:
@ -306,6 +320,23 @@ int main(int argc, char *argv[]) @@ -306,6 +320,23 @@ int main(int argc, char *argv[])
fill_fullpaths(bi->dt, "");
process_checks(force, bi);

/* on a plugin, generate by default */
if (bi->dtsflags & DTSF_PLUGIN) {
generate_symbols = 1;
generate_fixups = 1;
}

if (auto_label_aliases)
generate_label_tree(bi, "aliases", false);

if (generate_symbols)
generate_label_tree(bi, "__symbols__", true);

if (generate_fixups) {
generate_fixups_tree(bi, "__fixups__");
generate_local_fixups_tree(bi, "__local_fixups__");
}

if (sort)
sort_tree(bi);


16
dtc.h

@ -55,6 +55,9 @@ extern int minsize; /* Minimum blob size */ @@ -55,6 +55,9 @@ extern int minsize; /* Minimum blob size */
extern int padsize; /* Additional padding to blob */
extern int alignsize; /* Additional padding to blob accroding to the alignsize */
extern int phandle_format; /* Use linux,phandle or phandle properties */
extern int generate_symbols; /* generate symbols for nodes with labels */
extern int generate_fixups; /* generate fixups */
extern int auto_label_aliases; /* auto generate labels -> aliases */

#define PHANDLE_LEGACY 0x1
#define PHANDLE_EPAPR 0x2
@ -202,6 +205,8 @@ void delete_property(struct property *prop); @@ -202,6 +205,8 @@ void delete_property(struct property *prop);
void add_child(struct node *parent, struct node *child);
void delete_node_by_name(struct node *parent, char *name);
void delete_node(struct node *node);
void append_to_property(struct node *node,
char *name, const void *data, int len);

const char *get_unitname(struct node *node);
struct property *get_property(struct node *node, const char *propname);
@ -237,14 +242,23 @@ struct reserve_info *add_reserve_entry(struct reserve_info *list, @@ -237,14 +242,23 @@ struct reserve_info *add_reserve_entry(struct reserve_info *list,


struct boot_info {
unsigned int dtsflags;
struct reserve_info *reservelist;
struct node *dt; /* the device tree */
uint32_t boot_cpuid_phys;
};

struct boot_info *build_boot_info(struct reserve_info *reservelist,
/* DTS version flags definitions */
#define DTSF_V1 0x0001 /* /dts-v1/ */
#define DTSF_PLUGIN 0x0002 /* /plugin/ */

struct boot_info *build_boot_info(unsigned int dtsflags,
struct reserve_info *reservelist,
struct node *tree, uint32_t boot_cpuid_phys);
void sort_tree(struct boot_info *bi);
void generate_label_tree(struct boot_info *bi, char *name, bool allocph);
void generate_fixups_tree(struct boot_info *bi, char *name);
void generate_local_fixups_tree(struct boot_info *bi, char *name);

/* Checks */


2
flattree.c

@ -942,5 +942,5 @@ struct boot_info *dt_from_blob(const char *fname) @@ -942,5 +942,5 @@ struct boot_info *dt_from_blob(const char *fname)

fclose(f);

return build_boot_info(reservelist, tree, boot_cpuid_phys);
return build_boot_info(DTSF_V1, reservelist, tree, boot_cpuid_phys);
}

2
fstree.c

@ -86,6 +86,6 @@ struct boot_info *dt_from_fs(const char *dirname) @@ -86,6 +86,6 @@ struct boot_info *dt_from_fs(const char *dirname)
tree = read_fstree(dirname);
tree = name_node(tree, "");

return build_boot_info(NULL, tree, guess_boot_cpuid(tree));
return build_boot_info(DTSF_V1, NULL, tree, guess_boot_cpuid(tree));
}


269
livetree.c

@ -296,6 +296,23 @@ void delete_node(struct node *node) @@ -296,6 +296,23 @@ void delete_node(struct node *node)
delete_labels(&node->labels);
}

void append_to_property(struct node *node,
char *name, const void *data, int len)
{
struct data d;
struct property *p;

p = get_property(node, name);
if (p) {
d = data_append_data(p->val, data, len);
p->val = d;
} else {
d = data_append_data(empty_data, data, len);
p = build_property(name, d);
add_property(node, p);
}
}

struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size)
{
struct reserve_info *new = xmalloc(sizeof(*new));
@ -335,12 +352,14 @@ struct reserve_info *add_reserve_entry(struct reserve_info *list, @@ -335,12 +352,14 @@ struct reserve_info *add_reserve_entry(struct reserve_info *list,
return list;
}

struct boot_info *build_boot_info(struct reserve_info *reservelist,
struct boot_info *build_boot_info(unsigned int dtsflags,
struct reserve_info *reservelist,
struct node *tree, uint32_t boot_cpuid_phys)
{
struct boot_info *bi;

bi = xmalloc(sizeof(*bi));
bi->dtsflags = dtsflags;
bi->reservelist = reservelist;
bi->dt = tree;
bi->boot_cpuid_phys = boot_cpuid_phys;
@ -709,3 +728,251 @@ void sort_tree(struct boot_info *bi) @@ -709,3 +728,251 @@ void sort_tree(struct boot_info *bi)
sort_reserve_entries(bi);
sort_node(bi->dt);
}

/* utility helper to avoid code duplication */
static struct node *build_and_name_child_node(struct node *parent, char *name)
{
struct node *node;

node = build_node(NULL, NULL);
name_node(node, xstrdup(name));
add_child(parent, node);

return node;
}

static struct node *build_root_node(struct node *dt, char *name)
{
struct node *an;

an = get_subnode(dt, name);
if (!an)
an = build_and_name_child_node(dt, name);

if (!an)
die("Could not build root node /%s\n", name);

return an;
}

static bool any_label_tree(struct boot_info *bi, struct node *node)
{
struct node *c;

if (node->labels)
return true;

for_each_child(node, c)
if (any_label_tree(bi, c))
return true;

return false;
}

static void generate_label_tree_internal(struct boot_info *bi,
struct node *an, struct node *node,
bool allocph)
{
struct node *dt = bi->dt;
struct node *c;
struct property *p;
struct label *l;

/* if there are labels */
if (node->labels) {

/* now add the label in the node */
for_each_label(node->labels, l) {

/* check whether the label already exists */
p = get_property(an, l->label);
if (p) {
fprintf(stderr, "WARNING: label %s already"
" exists in /%s", l->label,
an->name);
continue;
}

/* insert it */
p = build_property(l->label,
data_copy_mem(node->fullpath,
strlen(node->fullpath) + 1));
add_property(an, p);
}

/* force allocation of a phandle for this node */
if (allocph)
(void)get_node_phandle(dt, node);
}

for_each_child(node, c)
generate_label_tree_internal(bi, an, c, allocph);
}

static bool any_fixup_tree(struct boot_info *bi, struct node *node)
{
struct node *c;
struct property *prop;
struct marker *m;

for_each_property(node, prop) {
m = prop->val.markers;
for_each_marker_of_type(m, REF_PHANDLE) {
if (!get_node_by_ref(bi->dt, m->ref))
return true;
}
}

for_each_child(node, c) {
if (any_fixup_tree(bi, c))
return true;
}

return false;
}

static void add_fixup_entry(struct boot_info *bi, struct node *fn,
struct node *node, struct property *prop,
struct marker *m)
{
char *entry;

/* m->ref can only be a REF_PHANDLE, but check anyway */
assert(m->type == REF_PHANDLE);

/* there shouldn't be any ':' in the arguments */
if (strchr(node->fullpath, ':') || strchr(prop->name, ':'))
die("arguments should not contain ':'\n");

xasprintf(&entry, "%s:%s:%u",
node->fullpath, prop->name, m->offset);
append_to_property(fn, m->ref, entry, strlen(entry) + 1);
}

static void generate_fixups_tree_internal(struct boot_info *bi,
struct node *fn,
struct node *node)
{
struct node *dt = bi->dt;
struct node *c;
struct property *prop;
struct marker *m;
struct node *refnode;

for_each_property(node, prop) {
m = prop->val.markers;
for_each_marker_of_type(m, REF_PHANDLE) {
refnode = get_node_by_ref(dt, m->ref);
if (!refnode)
add_fixup_entry(bi, fn, node, prop, m);
}
}

for_each_child(node, c)
generate_fixups_tree_internal(bi, fn, c);
}

static bool any_local_fixup_tree(struct boot_info *bi, struct node *node)
{
struct node *c;
struct property *prop;
struct marker *m;

for_each_property(node, prop) {
m = prop->val.markers;
for_each_marker_of_type(m, REF_PHANDLE) {
if (get_node_by_ref(bi->dt, m->ref))
return true;
}
}

for_each_child(node, c) {
if (any_local_fixup_tree(bi, c))
return true;
}

return false;
}

static void add_local_fixup_entry(struct boot_info *bi,
struct node *lfn, struct node *node,
struct property *prop, struct marker *m,
struct node *refnode)
{
struct node *wn, *nwn; /* local fixup node, walk node, new */
uint32_t value_32;
char **compp;
int i, depth;

/* walk back retreiving depth */
depth = 0;
for (wn = node; wn; wn = wn->parent)
depth++;

/* allocate name array */
compp = xmalloc(sizeof(*compp) * depth);

/* store names in the array */
for (wn = node, i = depth - 1; wn; wn = wn->parent, i--)
compp[i] = wn->name;

/* walk the path components creating nodes if they don't exist */
for (wn = lfn, i = 1; i < depth; i++, wn = nwn) {
/* if no node exists, create it */
nwn = get_subnode(wn, compp[i]);
if (!nwn)
nwn = build_and_name_child_node(wn, compp[i]);
}

free(compp);

value_32 = cpu_to_fdt32(m->offset);
append_to_property(wn, prop->name, &value_32, sizeof(value_32));
}

static void generate_local_fixups_tree_internal(struct boot_info *bi,
struct node *lfn,
struct node *node)
{
struct node *dt = bi->dt;
struct node *c;
struct property *prop;
struct marker *m;
struct node *refnode;

for_each_property(node, prop) {
m = prop->val.markers;
for_each_marker_of_type(m, REF_PHANDLE) {
refnode = get_node_by_ref(dt, m->ref);
if (refnode)
add_local_fixup_entry(bi, lfn, node, prop, m, refnode);
}
}

for_each_child(node, c)
generate_local_fixups_tree_internal(bi, lfn, c);
}

void generate_label_tree(struct boot_info *bi, char *name, bool allocph)
{
if (!any_label_tree(bi, bi->dt))
return;
generate_label_tree_internal(bi, build_root_node(bi->dt, name),
bi->dt, allocph);
}

void generate_fixups_tree(struct boot_info *bi, char *name)
{
if (!any_fixup_tree(bi, bi->dt))
return;
generate_fixups_tree_internal(bi, build_root_node(bi->dt, name),
bi->dt);
}

void generate_local_fixups_tree(struct boot_info *bi, char *name)
{
if (!any_local_fixup_tree(bi, bi->dt))
return;
generate_local_fixups_tree_internal(bi, build_root_node(bi->dt, name),
bi->dt);
}

Loading…
Cancel
Save