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: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20260112142009.1006236-36-herve.codina@bootlin.com>
Date: Mon, 12 Jan 2026 15:19:25 +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 35/77] Add support for FDT_IMPORT_SYM dtb tag

The FDT_IMPORT_SYM dtb tag is a meta-data tag defining an imported
symbol. It can be present globally in an addon dtb (i.e. outside nodes
definition) meaning that this symbol needs to be resolved when the dtb
is applied.

The tag is followed by two values and possible alignment paddings:
  - name (string including \0)
      The import symbol name. I.e. the name used to reference this
      imported symbol.
  - padding:
      Padding (0x00) added to have the next value aligned on 32bit.
  - compatible (string including \0)
      The compatible string that can be used for symbol resolution.
      This string can be an empty string if it is not relevant.
  - padding:
      Padding (0x00) added to have the next value aligned on 32bit.

Example:
  FDT_IMPORT_SYM 'foo1' 0x00 0x00 0x00 'bar,foo'

  This means that 'foo1' is an imported symbol and it is 'bar,foo'
  compatible.

  This is what is encoded in the dtb when the related dts has the
  following imported symbol defined:
    /import/ foo1: "bar,foo";

If several symbols are imported, several FDT_IMPORT_SYM are present.
Each of them defining one imported symbol. For instance, importing
'foo1' ("bar,foo" compatible) and 'baz1' ("bar,baz" compatible) leads
to the following sequence:
  FDT_IMPORT_SYM 'foo1' 0x00 0x00 0x00 'bar,foo'
  FDT_IMPORT_SYM 'baz1' 0x00 0x00 0x00 'bar,baz'

If FDT_IMPORT_SYM tags are present in the dtb, they are present after
the root node definition (i.e. after the FDT_END_NODE related to the
first FDT_BEGIN_NODE).

Add support for this new dtb tag.

Signed-off-by: Herve Codina <herve.codina@...tlin.com>
---
 fdtdump.c    | 11 +++++++++
 flattree.c   | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 libfdt/fdt.c | 28 ++++++++++++++++++++++
 libfdt/fdt.h |  1 +
 4 files changed, 107 insertions(+), 1 deletion(-)

diff --git a/fdtdump.c b/fdtdump.c
index 8baadc4..04e6e38 100644
--- a/fdtdump.c
+++ b/fdtdump.c
@@ -198,6 +198,17 @@ static void dump_blob(void *blob, bool debug)
 			continue;
 		}
 
+		if (tag == FDT_IMPORT_SYM) {
+			s = p;
+			p = PALIGN(p + strlen(s) + 1, 4);
+			t = p;
+			p = PALIGN(p + strlen(t) + 1, 4);
+
+			printf("%*s// [FDT_IMPORT_SYM] '%s' (%s)\n", depth * shift, "",
+				s, t);
+			continue;
+		}
+
 		fprintf(stderr, "%*s ** Unknown tag 0x%08"PRIx32"\n", depth * shift, "", tag);
 		break;
 	}
diff --git a/flattree.c b/flattree.c
index 47a289f..add02f0 100644
--- a/flattree.c
+++ b/flattree.c
@@ -50,6 +50,7 @@ struct emitter {
 	void (*ref_phandle)(void *);
 	void (*export_sym)(void *);
 	void (*export_sym_ref)(void *);
+	void (*import_sym)(void *);
 };
 
 static void bin_emit_cell(void *e, cell_t val)
@@ -119,6 +120,11 @@ static void bin_emit_export_sym_ref(void *e)
 	bin_emit_cell(e, FDT_EXPORT_SYM_REF);
 }
 
+static void bin_emit_import_sym(void *e)
+{
+	bin_emit_cell(e, FDT_IMPORT_SYM);
+}
+
 static struct emitter bin_emitter = {
 	.cell = bin_emit_cell,
 	.string = bin_emit_string,
@@ -131,6 +137,7 @@ static struct emitter bin_emitter = {
 	.ref_phandle = bin_emit_ref_phandle,
 	.export_sym = bin_emit_export_sym,
 	.export_sym_ref = bin_emit_export_sym_ref,
+	.import_sym = bin_emit_import_sym,
 };
 
 static void emit_label(FILE *f, const char *prefix, const char *label)
@@ -274,6 +281,17 @@ static void asm_emit_export_sym_ref(void *e)
 	asm_emit_cell(e, FDT_EXPORT_SYM_REF);
 }
 
+static void asm_emit_import_sym(void *e)
+{
+	/*
+	 * Import symbols are an feature introduced for addons.
+	 * Addons device-tree blob have to reason to be in the asm format.
+	 *
+	 * Need to be implemented if really needed.
+	 */
+	die("FDT_IMPORT_SYM not supported in asm output\n");
+}
+
 static struct emitter asm_emitter = {
 	.cell = asm_emit_cell,
 	.string = asm_emit_string,
@@ -286,6 +304,7 @@ static struct emitter asm_emitter = {
 	.ref_phandle = asm_emit_ref_phandle,
 	.export_sym = asm_emit_export_sym,
 	.export_sym = asm_emit_export_sym_ref,
+	.import_sym = asm_emit_import_sym,
 };
 
 static int stringtable_insert(struct data *d, const char *str)
@@ -461,6 +480,26 @@ static void make_fdt_header(struct fdt_header *fdt,
 		fdt->dt_flags = cpu_to_fdt32(dt_flags);
 }
 
+static void flatten_imports(struct symbol *importsymlist, struct emitter *emit,
+			 void *etarget, struct version_info *vi, uint32_t dt_flags)
+{
+	struct symbol *importsym;
+
+	if (!(vi->flags & FTF_EXPORT_IMPORT_SYM))
+		return;
+
+	if (!(dt_flags & FDT_FLAG_ADDON) && importsymlist)
+		die("Only addons can have an import list\n");
+
+	for_each_symbol(importsymlist, importsym) {
+		emit->import_sym(etarget);
+		emit->string(etarget, importsym->name, 0);
+		emit->align(etarget, sizeof(cell_t));
+		emit->string(etarget, importsym->compatible, 0);
+		emit->align(etarget, sizeof(cell_t));
+	}
+}
+
 void dt_to_blob(FILE *f, struct dt_info *dti, int version)
 {
 	struct version_info *vi = NULL;
@@ -483,6 +522,7 @@ void dt_to_blob(FILE *f, struct dt_info *dti, int version)
 	dt_flags |= dti->dtsflags & DTSF_ADDON ? FDT_FLAG_ADDON : 0;
 
 	flatten_tree(dti->dt, &bin_emitter, &dtbuf, &strbuf, vi);
+	flatten_imports(dti->importsymlist, &bin_emitter, &dtbuf, vi, dt_flags);
 	bin_emit_cell(&dtbuf, FDT_END);
 
 	reservebuf = flatten_reserve_list(dti->reservelist, vi);
@@ -574,6 +614,9 @@ void dt_to_asm(FILE *f, struct dt_info *dti, int version)
 	const char *symprefix = "dt";
 	uint32_t dt_flags = 0;
 
+	if (dti->importsymlist)
+		die("Import symbols not supported in asm format\n");
+
 	for (i = 0; i < ARRAY_SIZE(version_table); i++) {
 		if (version_table[i].version == version)
 			vi = &version_table[i];
@@ -810,6 +853,16 @@ static struct property *flat_read_property(struct inbuf *dtbuf,
 	return build_property(name, val, NULL);
 }
 
+static struct symbol *flat_read_importsym(struct inbuf *inb)
+{
+	const char *name;
+	const char *compatible;
+
+	name = flat_read_string(inb);
+	compatible =  flat_read_string(inb);
+
+	return build_importsym(name, compatible, NULL);
+}
 
 static struct reserve_info *flat_read_mem_reserve(struct inbuf *inb)
 {
@@ -984,6 +1037,8 @@ struct dt_info *dt_from_blob(const char *fname)
 	int sizeleft;
 	struct reserve_info *reservelist;
 	struct node *tree;
+	struct symbol *importsymlist = NULL;
+	struct symbol *importsym;
 	uint32_t val;
 	int flags = 0;
 	unsigned int dtsflags = 0;
@@ -1098,6 +1153,17 @@ struct dt_info *dt_from_blob(const char *fname)
 	tree = unflatten_tree(&dtbuf, &strbuf, "", flags);
 
 	val = flat_read_word(&dtbuf);
+
+	if (dtsflags & DTSF_ADDON) {
+		if (flags & FTF_EXPORT_IMPORT_SYM) {
+			while (val == FDT_IMPORT_SYM) {
+				importsym = flat_read_importsym(&dtbuf);
+				add_symbol(&importsymlist, importsym);
+				val = flat_read_word(&dtbuf);
+			}
+		}
+	}
+
 	if (val != FDT_END)
 		die("Device tree blob doesn't end with FDT_END\n");
 
@@ -1105,5 +1171,5 @@ struct dt_info *dt_from_blob(const char *fname)
 
 	fclose(f);
 
-	return build_dt_info(DTSF_V1 | dtsflags, reservelist, tree, boot_cpuid_phys, NULL);
+	return build_dt_info(DTSF_V1 | dtsflags, reservelist, tree, boot_cpuid_phys, importsymlist);
 }
diff --git a/libfdt/fdt.c b/libfdt/fdt.c
index febfa71..c169dd9 100644
--- a/libfdt/fdt.c
+++ b/libfdt/fdt.c
@@ -271,6 +271,23 @@ uint32_t fdt_next_tag_full(const void *fdt, int startoffset, int *nextoffset)
 			return FDT_END; /* premature end */
 		break;
 
+	case FDT_IMPORT_SYM:
+		/* Skip name */
+		do {
+			p = fdt_offset_ptr(fdt, offset++, 1);
+		} while (p && (*p != '\0'));
+		if (!can_assume(VALID_DTB) && !p)
+			return FDT_END; /* premature end */
+		offset = FDT_CELLALIGN(offset);
+
+		/* Skip compatible */
+		do {
+			p = fdt_offset_ptr(fdt, offset++, 1);
+		} while (p && (*p != '\0'));
+		if (!can_assume(VALID_DTB) && !p)
+			return FDT_END; /* premature end */
+		break;
+
 	default:
 		return FDT_END;
 	}
@@ -286,6 +303,7 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
 {
 	uint32_t tag, tmp_tag;
 	int tmp_offset, tmp_next;
+	int is_skip_to_end = 0;
 
 	/* Retrieve next tag */
 	tag = fdt_next_tag_full(fdt, startoffset, nextoffset);
@@ -300,6 +318,9 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
 		case FDT_END_NODE:
 		case FDT_PROP:
 		case FDT_NOP:
+			if (is_skip_to_end)
+				break;
+
 		case FDT_END:
 			/*
 			 * Next tag is not a meta-data tag -> Ok this next tag
@@ -320,6 +341,13 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
 			 */
 			break;
 
+		case FDT_IMPORT_SYM:
+			/* Those tags are available at the root level, after the
+			 * root node -> Skip everything until FDT_END
+			 */
+			is_skip_to_end = 1;
+			break;
+
 		default:
 			break;
 		}
diff --git a/libfdt/fdt.h b/libfdt/fdt.h
index c23723b..b6c23ef 100644
--- a/libfdt/fdt.h
+++ b/libfdt/fdt.h
@@ -67,6 +67,7 @@ struct fdt_property {
 #define FDT_EXPORT_SYM	0xa		/* export symbol: name, phandle value */
 #define FDT_EXPORT_SYM_REF 0xb		/* export symbol: name, phandle value (maybe
 					   unresolved), external label */
+#define FDT_IMPORT_SYM	0xc		/* import symbol: name, compatible */
 
 #define FDT_V1_SIZE	(7*sizeof(fdt32_t))
 #define FDT_V2_SIZE	(FDT_V1_SIZE + sizeof(fdt32_t))
-- 
2.52.0


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ