On Mon, Jan 12, 2026 at 03:19:10PM +0100, Herve Codina wrote: > The /export/ dts keyword is the keyword used to define an exported > symbol at a given node level. > > This keyword can be present in a node definition (after properties and > before subnodes) to export a symbol. If several symbols need to be > exported, several /export/ keywords are present. > > The syntax used is the following: > /export/ name: reference; > > with: > name: The name of the exported symbol > reference: The reference of a node the symbol is pointing to. > > For instance: > - Reference by label: > /export/ foo: &foo1; > > The exported symbol foo references the node identified by > the label foo1. > > - Reference by path: > /export/ foo: &{/path/to/foo@100}; > > The exported symbol foo references the node at /path/to/foo@100. > > Add support for /export/ dts keyword. > > Signed-off-by: Herve Codina > --- > dtc-lexer.l | 6 ++++ > dtc-parser.y | 53 ++++++++++++++++++++++++++++++++++ > dtc.h | 8 ++++++ > livetree.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++ > 4 files changed, 147 insertions(+) > > diff --git a/dtc-lexer.l b/dtc-lexer.l > index a4a8e0b..90fe70e 100644 > --- a/dtc-lexer.l > +++ b/dtc-lexer.l > @@ -149,6 +149,12 @@ static void PRINTF(1, 2) lexical_error(const char *fmt, ...); > return DT_OMIT_NO_REF; > } > > +<*>"/export/" { > + DPRINT("Keyword: /export/\n"); > + BEGIN_DEFAULT(); > + return DT_EXPORT; > + } > + > <*>{LABEL}: { > DPRINT("Label: %s\n", yytext); > yylval.labelref = xstrdup(yytext); > diff --git a/dtc-parser.y b/dtc-parser.y > index 9c93673..a0d0aef 100644 > --- a/dtc-parser.y > +++ b/dtc-parser.y > @@ -46,6 +46,8 @@ static bool is_ref_relative(const char *ref) > struct property *proplist; > struct node *node; > struct node *nodelist; > + struct symbol *symbol; > + struct symbol *exportlist; > struct reserve_info *re; > uint64_t integer; > unsigned int flags; > @@ -60,6 +62,7 @@ static bool is_ref_relative(const char *ref) > %token DT_DEL_PROP > %token DT_DEL_NODE > %token DT_OMIT_NO_REF > +%token DT_EXPORT > %token DT_PROPNODENAME > %token DT_LITERAL > %token DT_CHAR_LITERAL > @@ -80,6 +83,8 @@ static bool is_ref_relative(const char *ref) > %type bytestring > %type propdef > %type proplist > +%type exportdef > +%type exportlist > %type dt_ref > > %type devicetree > @@ -276,6 +281,49 @@ nodedef: > { > $$ = build_node(NULL, $2, NULL, &@$); > } > + | '{' proplist exportlist subnodes '}' ';' > + { > + /* > + * exportlist is created with chain_symbol() and so it > + * is created in reverse order. Reverse it now to have > + * it in correct order > + */ > + $$ = build_node($2, $4, reverse_symbol($3), &@$); > + } > + | '{' exportlist subnodes '}' ';' > + { > + /* > + * exportlist is created with chain_symbol() and so it > + * is created in reverse order. Reverse it now to have > + * it in correct order > + */ > + $$ = build_node(NULL, $3, reverse_symbol($2), &@$); > + } > + ; > + > +exportlist: > + exportdef > + { > + $$ = chain_symbol($1, NULL); > + } > + | exportlist exportdef > + { > + $$ = chain_symbol($2, $1); > + } > + | exportlist propdef > + { > + ERROR(&@2, "Properties must precede exports"); > + YYERROR; > + } > + ; > + > +exportdef: > + DT_EXPORT DT_LABEL dt_ref ';' > + { > + $$ = build_exportsym($2, $3, 0, &@$); > + free($2); > + free($3); I mostly don't bother with free()s in dtc, on the grounds that it's generally a short-lived process - essentially using the process context as a crude pool allocator. > + } > ; > > proplist: > @@ -576,6 +624,11 @@ subnodes: > ERROR(&@2, "Properties must precede subnodes"); > YYERROR; > } > + | subnode exportdef > + { > + ERROR(&@2, "Exports must precede subnodes"); > + YYERROR; > + } > ; > > subnode: > diff --git a/dtc.h b/dtc.h > index 6508694..0bf5ba5 100644 > --- a/dtc.h > +++ b/dtc.h > @@ -273,6 +273,9 @@ struct node { > for_each_child_withdel(n, c) \ > if (!(c)->deleted) > > +#define for_each_symbol(s0, s) \ > + for ((s) = (s0); (s); (s) = (s)->next) > + > void add_label(struct label **labels, char *label); > void delete_labels(struct label **labels); > > @@ -282,6 +285,11 @@ struct property *build_property_delete(const char *name); > struct property *chain_property(struct property *first, struct property *list); > struct property *reverse_properties(struct property *first); > > +struct symbol *build_exportsym(const char *name, const char *ref, cell_t phandle, > + struct srcpos *srcpos); > +struct symbol *chain_symbol(struct symbol *first, struct symbol *list); > +struct symbol *reverse_symbol(struct symbol *list); > + > struct node *build_node(struct property *proplist, struct node *children, > struct symbol *exportsymlist, struct srcpos *srcpos); > struct node *build_node_delete(struct srcpos *srcpos); > diff --git a/livetree.c b/livetree.c > index 0050492..4458437 100644 > --- a/livetree.c > +++ b/livetree.c > @@ -36,6 +36,57 @@ void delete_labels(struct label **labels) > label->deleted = 1; > } > > +struct symbol *build_exportsym(const char *name, const char *ref, cell_t phandle, > + struct srcpos *srcpos) > +{ > + struct symbol *new = xmalloc(sizeof(*new)); > + > + memset(new, 0, sizeof(*new)); > + > + new->name = xstrdup(name); > + new->ref = ref ? xstrdup(ref) : NULL; > + new->phandle = phandle; > + new->srcpos = srcpos_copy(srcpos); > + > + return new; > +} > + > +struct symbol *chain_symbol(struct symbol *first, struct symbol *list) > +{ > + assert(first->next == NULL); > + > + first->next = list; > + return first; > +} > + > +struct symbol *reverse_symbol(struct symbol *list) > +{ > + struct symbol *p = list; > + struct symbol *head = NULL; > + struct symbol *next; > + > + while (p) { > + next = p->next; > + p->next = head; > + head = p; > + p = next; > + } > + return head; > +} > + > +static void add_symbol(struct symbol **list, struct symbol *new) > +{ > + struct symbol **s; > + > + new->next = NULL; > + > + s = list; > + while (*s) > + s = &((*s)->next); > + > + *s = new; > +} > + > struct property *build_property(const char *name, struct data val, > struct srcpos *srcpos) > { > @@ -144,6 +195,7 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node) > { > struct property *new_prop, *old_prop; > struct node *new_child, *old_child; > + struct symbol *new_sym, *old_sym; > struct label *l; > > old_node->deleted = 0; > @@ -217,6 +269,34 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node) > add_child(old_node, new_child); > } > > + /* Merge exported symbols. If there is a collision, keep the new one */ > + while (new_node->exportsymlist) { > + /* Pop the symbol off the list */ > + new_sym = new_node->exportsymlist; > + new_node->exportsymlist = new_sym->next; > + new_sym->next = NULL; > + > + /* Look for a collision, set new value if there is */ > + for_each_symbol(old_node->exportsymlist, old_sym) { > + if (streq(old_sym->name, new_sym->name)) { > + old_sym->is_local = new_sym->is_local; > + free(old_sym->ref); > + old_sym->ref = new_sym->ref; > + old_sym->phandle = new_sym->phandle; > + old_sym->fullpath = new_sym->fullpath; > + srcpos_free(old_sym->srcpos); > + old_sym->srcpos = new_sym->srcpos; > + free(new_sym); > + new_sym = NULL; > + break; > + } > + } > + > + /* if no collision occurred, add symbol to the old node list. */ > + if (new_sym) > + add_symbol(&old_node->exportsymlist, new_sym); > + } > + > old_node->srcpos = srcpos_extend(old_node->srcpos, new_node->srcpos); > > /* The new node contents are now merged into the old node. Free > -- > 2.52.0 > > -- David Gibson (he or they) | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you, not the other way | around. http://www.ozlabs.org/~dgibson