lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20260112142009.1006236-55-herve.codina@bootlin.com>
Date: Mon, 12 Jan 2026 15:19:44 +0100
From: Herve Codina <herve.codina@...tlin.com>
To: David Gibson <david@...son.dropbear.id.au>,
	Rob Herring <robh@...nel.org>,
	Krzysztof Kozlowski <krzk@...nel.org>,
	Conor Dooley <conor+dt@...nel.org>
Cc: Ayush Singh <ayush@...gleboard.org>,
	Geert Uytterhoeven <geert@...ux-m68k.org>,
	devicetree-compiler@...r.kernel.org,
	devicetree@...r.kernel.org,
	linux-kernel@...r.kernel.org,
	devicetree-spec@...r.kernel.org,
	Hui Pu <hui.pu@...ealthcare.com>,
	Ian Ray <ian.ray@...ealthcare.com>,
	Luca Ceresoli <luca.ceresoli@...tlin.com>,
	Thomas Petazzoni <thomas.petazzoni@...tlin.com>,
	Herve Codina <herve.codina@...tlin.com>
Subject: [RFC PATCH 54/77] dtc: Add basic support for addon orphan nodes dts parsing

Orphan nodes are nodes without a parent. The root device-tree node is a
particular orphan node and is not part of those 'orphan' nodes group.

The orphan nodes group is related to nodes identified by a reference in
addons or plugins device-trees. For instance, int the following snippet,
foo is an orphan node:
   --- 8< ---
   /addon/

   &foo {
       subnode {
           prop  = <1>;
       };
   };
   --- 8< ---

The foo referenced node described has no parent. Indeed, it is not
a child of the root node.

This kind of node is legit in addons device-tree in order to perform
modification on existing node when the addon dtb is applied.

Add support for addon orphan node in dts parsing.

Compared to plugin (overlay) orphan node parsing, the orphan node parsed
in the addon context do not lead to any change in the device-tree
structure. '/fragment@..._overlay__' or similar kind of structure is not
needed for addons.

Signed-off-by: Herve Codina <herve.codina@...tlin.com>
---
 checks.c     | 14 ++++++++++--
 dtc-parser.y | 60 +++++++++++++++++++++++++++++++++++-----------------
 dtc.h        |  4 ++++
 livetree.c   | 30 ++++++++++++++++++++++++++
 treesource.c |  2 ++
 5 files changed, 89 insertions(+), 21 deletions(-)

diff --git a/checks.c b/checks.c
index 3ed3a0c..83a0f6e 100644
--- a/checks.c
+++ b/checks.c
@@ -317,7 +317,12 @@ ERROR(duplicate_property_names, check_duplicate_property_names, NULL);
 static void check_node_name_chars(struct check *c, struct dt_info *dti,
 				  struct node *node)
 {
-	size_t n = strspn(node->name, c->data);
+	size_t n;
+
+	if ((dti->dtsflags & DTSF_ADDON) && node->ref)
+		return; /* Checking name doesn't make sense for an orphan node */
+
+	n = strspn(node->name, c->data);
 
 	if (n < strlen(node->name))
 		FAIL(c, dti, node, "Bad character '%c' in node name",
@@ -328,7 +333,12 @@ ERROR(node_name_chars, check_node_name_chars, NODECHARS);
 static void check_node_name_chars_strict(struct check *c, struct dt_info *dti,
 					 struct node *node)
 {
-	size_t n = strspn(node->name, c->data);
+	size_t n;
+
+	if ((dti->dtsflags & DTSF_ADDON) && node->ref)
+		return; /* Checking name doesn't make sense for an orphan node */
+
+	n = strspn(node->name, c->data);
 
 	if (n < node->basenamelen)
 		FAIL(c, dti, node, "Character '%c' not recommended in node name",
diff --git a/dtc-parser.y b/dtc-parser.y
index 2b5b3c4..10ca6d4 100644
--- a/dtc-parser.y
+++ b/dtc-parser.y
@@ -23,6 +23,7 @@ extern void yyerror(char const *s);
 
 extern struct dt_info *parser_output;
 extern bool treesource_error;
+extern struct node *parser_orphanlist;
 
 unsigned int last_header_flags;
 
@@ -31,7 +32,8 @@ static bool is_ref_relative(const char *ref)
 	return ref[0] != '/' && strchr(&ref[1], '/');
 }
 
-static struct node *parser_get_node_by_ref(struct node *dt, const char *ref)
+static struct node *parser_get_node_by_ref(struct node *dt, struct node *orphanlist,
+					   const char *ref)
 {
 	/*
 	 * Use a temporary dt_info in order to use dti_get_node_by_ref()
@@ -39,6 +41,7 @@ static struct node *parser_get_node_by_ref(struct node *dt, const char *ref)
 	struct dt_info dti = {};
 
 	dti.dt = dt;
+	dti.orphanlist = orphanlist;
 
 	return dti_get_node_by_ref(&dti, ref);
 }
@@ -132,7 +135,7 @@ sourcefile:
 		{
 			parser_output = build_dt_info($1, $2, $3,
 			                              guess_boot_cpuid($3),
-						      NULL, NULL);
+						      NULL, parser_orphanlist);
 		}
 	|  headers memreserves importlist devicetree
 		{
@@ -143,7 +146,8 @@ sourcefile:
 			 */
 			parser_output = build_dt_info($1, $2, $4,
 			                              $4 ? guess_boot_cpuid($4) : 0,
-			                              reverse_symbol($3), NULL);
+			                              reverse_symbol($3),
+						      parser_orphanlist);
 		}
 	;
 
@@ -241,21 +245,28 @@ devicetree:
 		}
 	| dt_ref nodedef
 		{
-			if (!(last_header_flags & DTSF_PLUGIN))
+			if (!(last_header_flags & (DTSF_PLUGIN | DTSF_ADDON)))
 				ERROR(&@2, "Label or path %s not found", $1);
 			else if (is_ref_relative($1))
-				ERROR(&@2, "Label-relative reference %s not supported in plugin", $1);
-			$$ = plugin_add_orphan_node(
-					name_node(build_node(NULL, NULL, NULL, NULL),
-						  ""),
-					$2, $1);
+				ERROR(&@2, "Label-relative reference %s not supported in plugin nor addon", $1);
+
+			if (last_header_flags & DTSF_PLUGIN) {
+				$$ = plugin_add_orphan_node(
+						name_node(build_node(NULL, NULL, NULL, NULL),
+							  ""),
+						$2, $1);
+			} else {
+				ERROR(&@2, "Orphan node %s without a root node not yet supported", $1);
+				YYERROR;
+			}
 		}
 	| devicetree DT_LABEL dt_ref nodedef
 		{
-			struct node *target = parser_get_node_by_ref($1, $3);
+			struct node *target = parser_get_node_by_ref(
+						$1, parser_orphanlist, $3);
 
-			if ((last_header_flags & DTSF_PLUGIN) && is_ref_relative($3))
-				ERROR(&@2, "Label-relative reference %s not supported in plugin", $3);
+			if ((last_header_flags & (DTSF_PLUGIN | DTSF_ADDON)) && is_ref_relative($3))
+				ERROR(&@2, "Label-relative reference %s not supported in plugin nor addon", $3);
 
 			if (target) {
 				add_label(&target->labels, $2);
@@ -266,12 +277,17 @@ devicetree:
 		}
 	| devicetree DT_PATH_REF nodedef
 		{
-			if (last_header_flags & DTSF_PLUGIN) {
+			if (last_header_flags & (DTSF_PLUGIN | DTSF_ADDON)) {
 				if (is_ref_relative($2))
-					ERROR(&@2, "Label-relative reference %s not supported in plugin", $2);
-				plugin_add_orphan_node($1, $3, $2);
+					ERROR(&@2, "Label-relative reference %s not supported in plugin nor addon", $2);
+				if(last_header_flags & DTSF_PLUGIN)
+					plugin_add_orphan_node($1, $3, $2);
+				else
+					addon_add_orphan_node(&parser_orphanlist,
+							      orphan_node($3, $2));
 			} else {
-				struct node *target = parser_get_node_by_ref($1, $2);
+				struct node *target = parser_get_node_by_ref(
+							$1, parser_orphanlist, $2);
 
 				if (target)
 					merge_nodes(target, $3);
@@ -282,13 +298,17 @@ devicetree:
 		}
 	| devicetree DT_LABEL_REF nodedef
 		{
-			struct node *target = parser_get_node_by_ref($1, $2);
+			struct node *target = parser_get_node_by_ref(
+						$1, parser_orphanlist, $2);
 
 			if (target) {
 				merge_nodes(target, $3);
 			} else {
 				if (last_header_flags & DTSF_PLUGIN)
 					plugin_add_orphan_node($1, $3, $2);
+				else if (last_header_flags & DTSF_ADDON)
+					addon_add_orphan_node(&parser_orphanlist,
+							      orphan_node($3, $2));
 				else
 					ERROR(&@2, "Label or path %s not found", $2);
 			}
@@ -296,7 +316,8 @@ devicetree:
 		}
 	| devicetree DT_DEL_NODE dt_ref ';'
 		{
-			struct node *target = parser_get_node_by_ref($1, $3);
+			struct node *target = parser_get_node_by_ref(
+						$1, parser_orphanlist, $3);
 
 			if (target)
 				delete_node(target);
@@ -308,7 +329,8 @@ devicetree:
 		}
 	| devicetree DT_OMIT_NO_REF dt_ref ';'
 		{
-			struct node *target = parser_get_node_by_ref($1, $3);
+			struct node *target = parser_get_node_by_ref(
+						$1, parser_orphanlist, $3);
 
 			if (target)
 				omit_node_if_unused(target);
diff --git a/dtc.h b/dtc.h
index e463756..a3e29a6 100644
--- a/dtc.h
+++ b/dtc.h
@@ -250,6 +250,8 @@ struct node {
 	const struct bus_type *bus;
 	struct srcpos *srcpos;
 
+	const char *ref; /* Use only for orphan nodes */
+
 	bool omit_if_unused, is_referenced;
 };
 
@@ -307,6 +309,8 @@ struct node *chain_node(struct node *first, struct node *list);
 struct node *merge_nodes(struct node *old_node, struct node *new_node);
 struct node *plugin_add_orphan_node(struct node *old_node, struct node *new_node,
 				    char *ref);
+struct node *orphan_node(struct node *node, const char *ref);
+void addon_add_orphan_node(struct node **dt_orphan, struct node *new_orphan);
 
 void add_property(struct node *node, struct property *prop);
 void delete_property_by_name(struct node *node, char *name);
diff --git a/livetree.c b/livetree.c
index a21dfc1..eaface5 100644
--- a/livetree.c
+++ b/livetree.c
@@ -351,6 +351,36 @@ struct node *plugin_add_orphan_node(struct node *dt, struct node *new_node,
 	return dt;
 }
 
+struct node *orphan_node(struct node *node, const char *ref)
+{
+	node->ref = xstrdup(ref);
+
+	return node;
+}
+
+void addon_add_orphan_node(struct node **dt_orphan, struct node *new_orphan)
+{
+	struct node **last_orphan;
+	char *name;
+
+	/*
+	 * For addon orphan node, the node name is set to '&reference'
+	 * This ease the dts file generation and the usage of existing code
+	 */
+	xasprintf(&name, "&%s", new_orphan->ref);
+
+	name_node(new_orphan, name);
+	free(name);
+
+	new_orphan->next_sibling = NULL;
+
+	last_orphan = dt_orphan;
+	while (*last_orphan)
+		last_orphan = &((*last_orphan)->next_sibling);
+
+	*last_orphan = new_orphan;
+}
+
 struct node *chain_node(struct node *first, struct node *list)
 {
 	assert(first->next_sibling == NULL);
diff --git a/treesource.c b/treesource.c
index 04f65bb..77ff4fb 100644
--- a/treesource.c
+++ b/treesource.c
@@ -12,11 +12,13 @@ extern YYLTYPE yylloc;
 
 struct dt_info *parser_output;
 bool treesource_error;
+struct node *parser_orphanlist;
 
 struct dt_info *dt_from_source(const char *fname)
 {
 	parser_output = NULL;
 	treesource_error = false;
+	parser_orphanlist = NULL;
 
 	srcfile_push(fname);
 	yyin = current_srcfile->f;
-- 
2.52.0


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ