Browse Source

dtc: Allow multiple labels on nodes and properties

At present, both the grammar and our internal data structures mean
that there can be only one label on a node or property.  This is a
fairly arbitrary constraint, given that any number of value labels can
appear at the same point, and that in C you can have any number of
labels on the same statement.

This is pretty much a non-issue now, but it may become important with
some of the extensions that Grant and I have in mind.  It's not that
hard to change, so this patch does so, allowing an arbitrary number of
labels on any given node or property.  As usual a testcase is added
too.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Acked-by: Grant Likely <grant.likely@secretlab.ca>
main
David Gibson 15 years ago committed by Jon Loeliger
parent
commit
05898c67c1
  1. 11
      checks.c
  2. 41
      dtc-parser.y
  3. 22
      dtc.h
  4. 57
      flattree.c
  5. 8
      fstree.c
  6. 45
      livetree.c
  7. 38
      tests/multilabel.dts
  8. 3
      tests/run_tests.sh
  9. 15
      treesource.c

11
checks.c

@ -314,16 +314,19 @@ static void check_duplicate_label(struct check *c, struct node *dt,
static void check_duplicate_label_node(struct check *c, struct node *dt, static void check_duplicate_label_node(struct check *c, struct node *dt,
struct node *node) struct node *node)
{ {
if (node->label) struct label *l;
check_duplicate_label(c, dt, node->label, node, NULL, NULL);
for_each_label(node->labels, l)
check_duplicate_label(c, dt, l->label, node, NULL, NULL);
} }
static void check_duplicate_label_prop(struct check *c, struct node *dt, static void check_duplicate_label_prop(struct check *c, struct node *dt,
struct node *node, struct property *prop) struct node *node, struct property *prop)
{ {
struct marker *m = prop->val.markers; struct marker *m = prop->val.markers;
struct label *l;


if (prop->label) for_each_label(prop->labels, l)
check_duplicate_label(c, dt, prop->label, node, prop, NULL); check_duplicate_label(c, dt, l->label, node, prop, NULL);


for_each_marker_of_type(m, LABEL) for_each_marker_of_type(m, LABEL)
check_duplicate_label(c, dt, m->ref, node, prop, m); check_duplicate_label(c, dt, m->ref, node, prop, m);

41
dtc-parser.y

@ -78,7 +78,6 @@ static unsigned long long eval_literal(const char *s, int base, int bits);
%type <node> nodedef %type <node> nodedef
%type <node> subnode %type <node> subnode
%type <nodelist> subnodes %type <nodelist> subnodes
%type <labelref> label


%% %%


@ -102,9 +101,14 @@ memreserves:
; ;


memreserve: memreserve:
label DT_MEMRESERVE addr addr ';' DT_MEMRESERVE addr addr ';'
{ {
$$ = build_reserve_entry($3, $4, $1); $$ = build_reserve_entry($2, $3);
}
| DT_LABEL memreserve
{
add_label(&$2->labels, $1);
$$ = $2;
} }
; ;


@ -118,7 +122,7 @@ addr:
devicetree: devicetree:
'/' nodedef '/' nodedef
{ {
$$ = name_node($2, "", NULL); $$ = name_node($2, "");
} }
; ;


@ -141,13 +145,18 @@ proplist:
; ;


propdef: propdef:
label DT_PROPNODENAME '=' propdata ';' DT_PROPNODENAME '=' propdata ';'
{
$$ = build_property($1, $3);
}
| DT_PROPNODENAME ';'
{ {
$$ = build_property($2, $4, $1); $$ = build_property($1, empty_data);
} }
| label DT_PROPNODENAME ';' | DT_LABEL propdef
{ {
$$ = build_property($2, empty_data, $1); add_label(&$2->labels, $1);
$$ = $2;
} }
; ;


@ -276,20 +285,14 @@ subnodes:
; ;


subnode: subnode:
label DT_PROPNODENAME nodedef DT_PROPNODENAME nodedef
{ {
$$ = name_node($3, $2, $1); $$ = name_node($2, $1);
} }
; | DT_LABEL subnode

label:
/* empty */
{ {
$$ = NULL; add_label(&$2->labels, $1);
} $$ = $2;
| DT_LABEL
{
$$ = $1;
} }
; ;



22
dtc.h

@ -125,13 +125,18 @@ int data_is_one_string(struct data d);
#define MAX_NODENAME_LEN 31 #define MAX_NODENAME_LEN 31


/* Live trees */ /* Live trees */
struct label {
char *label;
struct label *next;
};

struct property { struct property {
char *name; char *name;
struct data val; struct data val;


struct property *next; struct property *next;


char *label; struct label *labels;
}; };


struct node { struct node {
@ -148,21 +153,26 @@ struct node {
cell_t phandle; cell_t phandle;
int addr_cells, size_cells; int addr_cells, size_cells;


char *label; struct label *labels;
}; };


#define for_each_label(l0, l) \
for ((l) = (l0); (l); (l) = (l)->next)

#define for_each_property(n, p) \ #define for_each_property(n, p) \
for ((p) = (n)->proplist; (p); (p) = (p)->next) for ((p) = (n)->proplist; (p); (p) = (p)->next)


#define for_each_child(n, c) \ #define for_each_child(n, c) \
for ((c) = (n)->children; (c); (c) = (c)->next_sibling) for ((c) = (n)->children; (c); (c) = (c)->next_sibling)


struct property *build_property(char *name, struct data val, char *label); void add_label(struct label **labels, char *label);

struct property *build_property(char *name, struct data val);
struct property *chain_property(struct property *first, struct property *list); struct property *chain_property(struct property *first, struct property *list);
struct property *reverse_properties(struct property *first); struct property *reverse_properties(struct property *first);


struct node *build_node(struct property *proplist, struct node *children); struct node *build_node(struct property *proplist, struct node *children);
struct node *name_node(struct node *node, char *name, char *label); struct node *name_node(struct node *node, char *name);
struct node *chain_node(struct node *first, struct node *list); struct node *chain_node(struct node *first, struct node *list);


void add_property(struct node *node, struct property *prop); void add_property(struct node *node, struct property *prop);
@ -191,10 +201,10 @@ struct reserve_info {


struct reserve_info *next; struct reserve_info *next;


char *label; struct label *labels;
}; };


struct reserve_info *build_reserve_entry(uint64_t start, uint64_t len, char *label); struct reserve_info *build_reserve_entry(uint64_t start, uint64_t len);
struct reserve_info *chain_reserve_entry(struct reserve_info *first, struct reserve_info *chain_reserve_entry(struct reserve_info *first,
struct reserve_info *list); struct reserve_info *list);
struct reserve_info *add_reserve_entry(struct reserve_info *list, struct reserve_info *add_reserve_entry(struct reserve_info *list,

57
flattree.c

@ -52,9 +52,9 @@ struct emitter {
void (*string)(void *, char *, int); void (*string)(void *, char *, int);
void (*align)(void *, int); void (*align)(void *, int);
void (*data)(void *, struct data); void (*data)(void *, struct data);
void (*beginnode)(void *, const char *); void (*beginnode)(void *, struct label *labels);
void (*endnode)(void *, const char *); void (*endnode)(void *, struct label *labels);
void (*property)(void *, const char *); void (*property)(void *, struct label *labels);
}; };


static void bin_emit_cell(void *e, cell_t val) static void bin_emit_cell(void *e, cell_t val)
@ -89,17 +89,17 @@ static void bin_emit_data(void *e, struct data d)
*dtbuf = data_append_data(*dtbuf, d.val, d.len); *dtbuf = data_append_data(*dtbuf, d.val, d.len);
} }


static void bin_emit_beginnode(void *e, const char *label) static void bin_emit_beginnode(void *e, struct label *labels)
{ {
bin_emit_cell(e, FDT_BEGIN_NODE); bin_emit_cell(e, FDT_BEGIN_NODE);
} }


static void bin_emit_endnode(void *e, const char *label) static void bin_emit_endnode(void *e, struct label *labels)
{ {
bin_emit_cell(e, FDT_END_NODE); bin_emit_cell(e, FDT_END_NODE);
} }


static void bin_emit_property(void *e, const char *label) static void bin_emit_property(void *e, struct label *labels)
{ {
bin_emit_cell(e, FDT_PROP); bin_emit_cell(e, FDT_PROP);
} }
@ -191,37 +191,40 @@ static void asm_emit_data(void *e, struct data d)
assert(off == d.len); assert(off == d.len);
} }


static void asm_emit_beginnode(void *e, const char *label) static void asm_emit_beginnode(void *e, struct label *labels)
{ {
FILE *f = e; FILE *f = e;
struct label *l;


if (label) { for_each_label(labels, l) {
fprintf(f, "\t.globl\t%s\n", label); fprintf(f, "\t.globl\t%s\n", l->label);
fprintf(f, "%s:\n", label); fprintf(f, "%s:\n", l->label);
} }
fprintf(f, "\t/* FDT_BEGIN_NODE */\n"); fprintf(f, "\t/* FDT_BEGIN_NODE */\n");
asm_emit_cell(e, FDT_BEGIN_NODE); asm_emit_cell(e, FDT_BEGIN_NODE);
} }


static void asm_emit_endnode(void *e, const char *label) static void asm_emit_endnode(void *e, struct label *labels)
{ {
FILE *f = e; FILE *f = e;
struct label *l;


fprintf(f, "\t/* FDT_END_NODE */\n"); fprintf(f, "\t/* FDT_END_NODE */\n");
asm_emit_cell(e, FDT_END_NODE); asm_emit_cell(e, FDT_END_NODE);
if (label) { for_each_label(labels, l) {
fprintf(f, "\t.globl\t%s_end\n", label); fprintf(f, "\t.globl\t%s_end\n", l->label);
fprintf(f, "%s_end:\n", label); fprintf(f, "%s_end:\n", l->label);
} }
} }


static void asm_emit_property(void *e, const char *label) static void asm_emit_property(void *e, struct label *labels)
{ {
FILE *f = e; FILE *f = e;
struct label *l;


if (label) { for_each_label(labels, l) {
fprintf(f, "\t.globl\t%s\n", label); fprintf(f, "\t.globl\t%s\n", l->label);
fprintf(f, "%s:\n", label); fprintf(f, "%s:\n", l->label);
} }
fprintf(f, "\t/* FDT_PROP */\n"); fprintf(f, "\t/* FDT_PROP */\n");
asm_emit_cell(e, FDT_PROP); asm_emit_cell(e, FDT_PROP);
@ -260,7 +263,7 @@ static void flatten_tree(struct node *tree, struct emitter *emit,
struct node *child; struct node *child;
int seen_name_prop = 0; int seen_name_prop = 0;


emit->beginnode(etarget, tree->label); emit->beginnode(etarget, tree->labels);


if (vi->flags & FTF_FULLPATH) if (vi->flags & FTF_FULLPATH)
emit->string(etarget, tree->fullpath, 0); emit->string(etarget, tree->fullpath, 0);
@ -277,7 +280,7 @@ static void flatten_tree(struct node *tree, struct emitter *emit,


nameoff = stringtable_insert(strbuf, prop->name); nameoff = stringtable_insert(strbuf, prop->name);


emit->property(etarget, prop->label); emit->property(etarget, prop->labels);
emit->cell(etarget, prop->val.len); emit->cell(etarget, prop->val.len);
emit->cell(etarget, nameoff); emit->cell(etarget, nameoff);


@ -304,7 +307,7 @@ static void flatten_tree(struct node *tree, struct emitter *emit,
flatten_tree(child, emit, etarget, strbuf, vi); flatten_tree(child, emit, etarget, strbuf, vi);
} }


emit->endnode(etarget, tree->label); emit->endnode(etarget, tree->labels);
} }


static struct data flatten_reserve_list(struct reserve_info *reservelist, static struct data flatten_reserve_list(struct reserve_info *reservelist,
@ -525,9 +528,11 @@ void dt_to_asm(FILE *f, struct boot_info *bi, int version)
* as it appears .quad isn't available in some assemblers. * as it appears .quad isn't available in some assemblers.
*/ */
for (re = bi->reservelist; re; re = re->next) { for (re = bi->reservelist; re; re = re->next) {
if (re->label) { struct label *l;
fprintf(f, "\t.globl\t%s\n", re->label);
fprintf(f, "%s:\n", re->label); for_each_label(re->labels, l) {
fprintf(f, "\t.globl\t%s\n", l->label);
fprintf(f, "%s:\n", l->label);
} }
ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->re.address >> 32)); ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->re.address >> 32));
ASM_EMIT_BELONG(f, "0x%08x", ASM_EMIT_BELONG(f, "0x%08x",
@ -684,7 +689,7 @@ static struct property *flat_read_property(struct inbuf *dtbuf,


val = flat_read_data(dtbuf, proplen); val = flat_read_data(dtbuf, proplen);


return build_property(name, val, NULL); return build_property(name, val);
} }




@ -709,7 +714,7 @@ static struct reserve_info *flat_read_mem_reserve(struct inbuf *inb)
if (re.size == 0) if (re.size == 0)
break; break;


new = build_reserve_entry(re.address, re.size, NULL); new = build_reserve_entry(re.address, re.size);
reservelist = add_reserve_entry(reservelist, new); reservelist = add_reserve_entry(reservelist, new);
} }



8
fstree.c

@ -60,8 +60,7 @@ static struct node *read_fstree(const char *dirname)
} else { } else {
prop = build_property(xstrdup(de->d_name), prop = build_property(xstrdup(de->d_name),
data_copy_file(pfile, data_copy_file(pfile,
st.st_size), st.st_size));
NULL);
add_property(tree, prop); add_property(tree, prop);
fclose(pfile); fclose(pfile);
} }
@ -69,8 +68,7 @@ static struct node *read_fstree(const char *dirname)
struct node *newchild; struct node *newchild;


newchild = read_fstree(tmpnam); newchild = read_fstree(tmpnam);
newchild = name_node(newchild, xstrdup(de->d_name), newchild = name_node(newchild, xstrdup(de->d_name));
NULL);
add_child(tree, newchild); add_child(tree, newchild);
} }


@ -85,7 +83,7 @@ struct boot_info *dt_from_fs(const char *dirname)
struct node *tree; struct node *tree;


tree = read_fstree(dirname); tree = read_fstree(dirname);
tree = name_node(tree, "", NULL); tree = name_node(tree, "");


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

45
livetree.c

@ -24,17 +24,24 @@
* Tree building functions * Tree building functions
*/ */


struct property *build_property(char *name, struct data val, char *label) void add_label(struct label **labels, char *label)
{
struct label *new = xmalloc(sizeof(*new));

new->label = label;
new->next = *labels;
*labels = new;
}

struct property *build_property(char *name, struct data val)
{ {
struct property *new = xmalloc(sizeof(*new)); struct property *new = xmalloc(sizeof(*new));


memset(new, 0, sizeof(*new));

new->name = name; new->name = name;
new->val = val; new->val = val;


new->next = NULL;

new->label = label;

return new; return new;
} }


@ -78,14 +85,12 @@ struct node *build_node(struct property *proplist, struct node *children)
return new; return new;
} }


struct node *name_node(struct node *node, char *name, char * label) struct node *name_node(struct node *node, char *name)
{ {
assert(node->name == NULL); assert(node->name == NULL);


node->name = name; node->name = name;


node->label = label;

return node; return node;
} }


@ -124,18 +129,15 @@ void add_child(struct node *parent, struct node *child)
*p = child; *p = child;
} }


struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size, struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size)
char *label)
{ {
struct reserve_info *new = xmalloc(sizeof(*new)); struct reserve_info *new = xmalloc(sizeof(*new));


memset(new, 0, sizeof(*new));

new->re.address = address; new->re.address = address;
new->re.size = size; new->re.size = size;


new->next = NULL;

new->label = label;

return new; return new;
} }


@ -217,7 +219,10 @@ struct property *get_property_by_label(struct node *tree, const char *label,
*node = tree; *node = tree;


for_each_property(tree, prop) { for_each_property(tree, prop) {
if (prop->label && streq(prop->label, label)) struct label *l;

for_each_label(prop->labels, l)
if (streq(l->label, label))
return prop; return prop;
} }


@ -296,10 +301,12 @@ struct node *get_node_by_path(struct node *tree, const char *path)
struct node *get_node_by_label(struct node *tree, const char *label) struct node *get_node_by_label(struct node *tree, const char *label)
{ {
struct node *child, *node; struct node *child, *node;
struct label *l;


assert(label && (strlen(label) > 0)); assert(label && (strlen(label) > 0));


if (tree->label && streq(tree->label, label)) for_each_label(tree->labels, l)
if (streq(l->label, label))
return tree; return tree;


for_each_child(tree, child) { for_each_child(tree, child) {
@ -353,15 +360,13 @@ cell_t get_node_phandle(struct node *root, struct node *node)
&& (phandle_format & PHANDLE_LEGACY)) && (phandle_format & PHANDLE_LEGACY))
add_property(node, add_property(node,
build_property("linux,phandle", build_property("linux,phandle",
data_append_cell(empty_data, phandle), data_append_cell(empty_data, phandle)));
NULL));


if (!get_property(node, "phandle") if (!get_property(node, "phandle")
&& (phandle_format & PHANDLE_EPAPR)) && (phandle_format & PHANDLE_EPAPR))
add_property(node, add_property(node,
build_property("phandle", build_property("phandle",
data_append_cell(empty_data, phandle), data_append_cell(empty_data, phandle)));
NULL));


/* If the node *does* have a phandle property, we must /* If the node *does* have a phandle property, we must
* be dealing with a self-referencing phandle, which will be * be dealing with a self-referencing phandle, which will be

38
tests/multilabel.dts

@ -0,0 +1,38 @@
/dts-v1/;

m1: mq: /memreserve/ 0 0x1000;

/ {
p1: px: prop = "foo";

/* Explicit phandles */
n1: nx: node1 {
linux,phandle = <0x2000>;
ref = <&{/node2}>; /* reference precedes target */
lref = <&ny>;
};
ny: n2: node2 {
phandle = <0x1>;
ref = <&{/node1}>; /* reference after target */
lref = <&nx>;
};

/* Implicit phandles */
n3: node3 {
ref = <&{/node4}>;
lref = <&n4>;
};
n4: node4 {
};

/* Explicit phandle with implicit value */
/* This self-reference is the standard way to tag a node as requiring
* a phandle (perhaps for reference by nodes that will be dynamically
* added) without explicitly allocating it a phandle.
* The self-reference requires some special internal handling, though
* so check it actually works */
n5: nz: node5 {
linux,phandle = <&n5>;
phandle = <&nz>;
};
};

3
tests/run_tests.sh

@ -221,6 +221,9 @@ dtc_tests () {
run_test phandle_format dtc_references.test.$f.dtb $f run_test phandle_format dtc_references.test.$f.dtb $f
done done


run_dtc_test -I dts -O dtb -o multilabel.test.dtb multilabel.dts
run_test references multilabel.test.dtb

run_dtc_test -I dts -O dtb -o dtc_comments.test.dtb comments.dts run_dtc_test -I dts -O dtb -o dtc_comments.test.dtb comments.dts
run_dtc_test -I dts -O dtb -o dtc_comments-cmp.test.dtb comments-cmp.dts run_dtc_test -I dts -O dtb -o dtc_comments-cmp.test.dtb comments-cmp.dts
run_test dtbs_equal_ordered dtc_comments.test.dtb dtc_comments-cmp.test.dtb run_test dtbs_equal_ordered dtc_comments.test.dtb dtc_comments-cmp.test.dtb

15
treesource.c

@ -235,10 +235,11 @@ static void write_tree_source_node(FILE *f, struct node *tree, int level)
{ {
struct property *prop; struct property *prop;
struct node *child; struct node *child;
struct label *l;


write_prefix(f, level); write_prefix(f, level);
if (tree->label) for_each_label(tree->labels, l)
fprintf(f, "%s: ", tree->label); fprintf(f, "%s: ", l->label);
if (tree->name && (*tree->name)) if (tree->name && (*tree->name))
fprintf(f, "%s {\n", tree->name); fprintf(f, "%s {\n", tree->name);
else else
@ -246,8 +247,8 @@ static void write_tree_source_node(FILE *f, struct node *tree, int level)


for_each_property(tree, prop) { for_each_property(tree, prop) {
write_prefix(f, level+1); write_prefix(f, level+1);
if (prop->label) for_each_label(prop->labels, l)
fprintf(f, "%s: ", prop->label); fprintf(f, "%s: ", l->label);
fprintf(f, "%s", prop->name); fprintf(f, "%s", prop->name);
write_propval(f, prop); write_propval(f, prop);
} }
@ -267,8 +268,10 @@ void dt_to_source(FILE *f, struct boot_info *bi)
fprintf(f, "/dts-v1/;\n\n"); fprintf(f, "/dts-v1/;\n\n");


for (re = bi->reservelist; re; re = re->next) { for (re = bi->reservelist; re; re = re->next) {
if (re->label) struct label *l;
fprintf(f, "%s: ", re->label);
for_each_label(re->labels, l)
fprintf(f, "%s: ", l->label);
fprintf(f, "/memreserve/\t0x%016llx 0x%016llx;\n", fprintf(f, "/memreserve/\t0x%016llx 0x%016llx;\n",
(unsigned long long)re->re.address, (unsigned long long)re->re.address,
(unsigned long long)re->re.size); (unsigned long long)re->re.size);

Loading…
Cancel
Save