Devicetree
 help / color / mirror / Atom feed
From: David Gibson <david@gibson.dropbear.id.au>
To: Herve Codina <herve.codina@bootlin.com>
Cc: Rob Herring <robh@kernel.org>,
	Krzysztof Kozlowski <krzk@kernel.org>,
	Conor Dooley <conor+dt@kernel.org>,
	Laurent Pinchart <laurent.pinchart@ideasonboard.com>,
	David Lechner <dlechner@baylibre.com>,
	Ayush Singh <ayush@beagleboard.org>,
	Geert Uytterhoeven <geert@linux-m68k.org>,
	devicetree-compiler@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, devicetree-spec@vger.kernel.org,
	Hui Pu <hui.pu@gehealthcare.com>,
	Ian Ray <ian.ray@gehealthcare.com>,
	Luca Ceresoli <luca.ceresoli@bootlin.com>,
	Thomas Petazzoni <thomas.petazzoni@bootlin.com>,
	Frank Li <Frank.Li@nxp.com>
Subject: Re: [PATCH v3 08/15] flattree: Handle unknown tags
Date: Tue, 15 Sep 2026 21:52:24 +1000	[thread overview]
Message-ID: <aqkxacdQHZuhhyxw@gractus.seuss> (raw)
In-Reply-To: <20260915121635.39f13d34@bootlin.com>

[-- Attachment #1: Type: text/plain, Size: 11763 bytes --]

On Tue, Sep 15, 2026 at 12:16:35PM +0200, Herve Codina wrote:
> Hi David,
> 
> On Mon, 14 Sep 2026 18:23:49 +1000
> David Gibson <david@gibson.dropbear.id.au> wrote:
> 
> > On Wed, Aug 26, 2026 at 10:31:39AM +0200, Herve Codina wrote:
> > > The structured tag value definition introduced recently gives the
> > > ability to ignore unknown tags without any error when they are read.
> > > 
> > > Handle those structured tag.
> > > 
> > > Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> > > Reviewed-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
> > > Reviewed-by: Frank Li <Frank.Li@nxp.com>
> > > ---
> > >  flattree.c                                 | 65 ++++++++++++++++++++--
> > >  tests/run_tests.sh                         |  5 ++
> > >  tests/unknown_tags_can_skip.dtb.dts.expect | 19 +++++++
> > >  3 files changed, 84 insertions(+), 5 deletions(-)
> > >  create mode 100644 tests/unknown_tags_can_skip.dtb.dts.expect
> > > 
> > > diff --git a/flattree.c b/flattree.c
> > > index f3b698c1..88dbfa7e 100644
> > > --- a/flattree.c
> > > +++ b/flattree.c
> > > @@ -579,7 +579,8 @@ static void flat_read_chunk(struct inbuf *inb, void *p, int len)
> > >  	if ((inb->ptr + len) > inb->limit)
> > >  		die("Premature end of data parsing flat device tree\n");
> > >  
> > > -	memcpy(p, inb->ptr, len);
> > > +	if (p)
> > > +		memcpy(p, inb->ptr, len);
> > >  
> > >  	inb->ptr += len;
> > >  }
> > > @@ -604,6 +605,61 @@ static void flat_realign(struct inbuf *inb, int align)
> > >  		die("Premature end of data parsing flat device tree\n");
> > >  }
> > >  
> > > +static bool flat_skip_unknown_tag(struct inbuf *inb, uint32_t tag)
> > > +{
> > > +	uint32_t lng;
> > > +
> > > +	if (!(tag & FDT_TAG_STRUCTURED) || !(tag & FDT_TAG_SKIP_SAFE))
> > > +		return false;
> > > +
> > > +	switch (tag & FDT_TAG_DATA_MASK) {
> > > +	case FDT_TAG_DATA_NONE:
> > > +		break;
> > > +
> > > +	case FDT_TAG_DATA_1CELL:
> > > +		flat_read_word(inb);
> > > +		break;
> > > +
> > > +	case FDT_TAG_DATA_2CELLS:
> > > +		flat_read_word(inb);
> > > +		flat_read_word(inb);
> > > +		break;
> > > +
> > > +	case FDT_TAG_DATA_VARLEN:
> > > +		/* Get the length */
> > > +		lng = flat_read_word(inb);  
> > 
> > I think it would be more natural to get the length as a single value,
> > then have a common flat_read_chunk() and flat_realign() to consume it.
> > That's for two reasons:
> >  * Assuming we keep this length encoding, getting the final tag size
> >    seems like it would make a useful helper function anyway.
> >  * Using flat_read_word() is misleading - it implies it's integer data
> >    where endianness matters.  In this case it's not - it's just some
> >    bytes we're skipping over, we don't know the internal structure.
> 
> Well, without the length for all tags (I mean keeping some size encoding
> in the tag value), we can avoid the flat_read_word().
> --- 8< ---
> 	switch (tag & FDT_TAG_DATA_MASK) {
> 	case FDT_TAG_DATA_NONE:
> 		lng = 0;
> 		break;
> 
> 	case FDT_TAG_DATA_1CELL:
> 		lng = sizeof(uint32_t);
> 		break;
> 
> 	case FDT_TAG_DATA_2CELLS:
> 		lng = 2 * sizeof(uint32_t);
> 		break;
> 
> 	case FDT_TAG_DATA_VARLEN:
> 		/* Get the length */
> 		lng = flat_read_word(inb)
> 		break;
>         }
> 
>         if (lng) {
> 		flat_read_chunk(inb, NULL, lng);
> 		flat_realign(inb, sizeof(uint32_t));
>         }
> ---- 8< ----

Right, that's exactly what I'm suggesting.

> Related to a helper, I have introduced one in the addon series where new tags
> are present and these new tags are no more "unknown" tags and flat_read_subbuf()
> has been introduced to parse them. You can see that in the patch 11/74 [0] or
> directly in the final code [1]
> 
> [0] https://lore.kernel.org/devicetree-compiler/20260826094950.1088288-12-herve.codina@bootlin.com/
> [1] https://github.com/bootlin/dtc/blob/c68038e0ff4cde5de37a21419df8a082032ef994/flattree.c#L1169
> 
> I can see to avoid some more code duplication between functions skipping "unknown" tags
> and function parsing new "known" tags.

Uh.. I don't quite see the relevance of that here.  I'm just
suggesting the length calculation alone be a helper function.


> > > +
> > > +		/* Skip the following length bytes */
> > > +		flat_read_chunk(inb, NULL, lng);
> > > +
> > > +		flat_realign(inb, sizeof(uint32_t));
> > > +		break;
> > > +	}
> > > +
> > > +	return true;
> > > +}
> > > +
> > > +static uint32_t flat_read_tag(struct inbuf *inb)
> > > +{
> > > +	uint32_t tag;
> > > +
> > > +	do {
> > > +		tag = flat_read_word(inb);
> > > +		switch (tag) {
> > > +		case FDT_BEGIN_NODE:
> > > +		case FDT_END_NODE:
> > > +		case FDT_PROP:
> > > +		case FDT_NOP:
> > > +		case FDT_END:
> > > +			return tag;
> > > +		default:
> > > +			break;
> > > +		}
> > > +	} while (flat_skip_unknown_tag(inb, tag));  
> > 
> > Having this as a separate function seems odd to me...
> 
> Well, this clearly decouples "known" tags from "unknown" tags and keeps the
> function small.
> 
> > 
> > > +	die("Cannot skip unknown tag 0x%08x\n", tag);
> > > +}
> > > +
> > >  static const char *flat_read_string(struct inbuf *inb)
> > >  {
> > >  	int len = 0;
> > > @@ -750,7 +806,7 @@ static struct node *unflatten_tree(struct inbuf *dtbuf,
> > >  		struct property *prop;
> > >  		struct node *child;
> > >  
> > > -		val = flat_read_word(dtbuf);
> > > +		val = flat_read_tag(dtbuf);
> > >  		switch (val) {  
> > 
> > 
> > .. rather than having handling unknown tags as part of the default:
> > case here.
> 
> Here and probably on some other part if we go in that direction.
> 
> Here you have already parsed a FDT_BEGIN_NODE to call unflatten_tree().
> 
> Unknown tags should be handle and skipped if possible at lower level to handle
> them everywhere and without code duplication.
> 
> flat_read_tag() is this lower level.
> 
> > 
> > >  		case FDT_PROP:
> > >  			if (node->children)
> > > @@ -905,14 +961,13 @@ struct dt_info *dt_from_blob(const char *fname)
> > >  
> > >  	reservelist = flat_read_mem_reserve(&memresvbuf);
> > >  
> > > -	val = flat_read_word(&dtbuf);
> > > -
> > > +	val = flat_read_tag(&dtbuf);
> > >  	if (val != FDT_BEGIN_NODE)
> > >  		die("Device tree blob doesn't begin with FDT_BEGIN_NODE (begins with 0x%08x)\n", val);  
> > 
> > Hmm.. doesn't this already need to be fixed to handle NOP tags before
> > the root node?  Logically that change would go before this one.
> 
> Oh yes, good catch. I missed that one.
> 
> Will be update in next iteration (in offset 0 vs real root node offset part)
> with 2 points:
>   - handle the case here with something like
>     --- 8< ---
>        /* Skip possible FDT_NOP available before the root node */
>        do {
> 	  val = flat_read_tag(&dtbuf);
>        } while (tag == FDT_NOP);
> 
>        if (val != FDT_BEGIN_NODE)
> 	  die("Device tree blob doesn't begin with FDT_BEGIN_NODE (begins with 0x%08x)\n", val);
>        ...
>     --- 8< ---
> 
>   - Add a test calling dtc with a "nopulated" dtb
>     This test is really missing. Only functions from libfdt are tested with
>     a nopulated dtb. DTC has to be tested too.

Sounds good.

> > 
> > >  
> > >  	tree = unflatten_tree(&dtbuf, &strbuf, "", flags);
> > >  
> > > -	val = flat_read_word(&dtbuf);
> > > +	val = flat_read_tag(&dtbuf);
> > >  	if (val != FDT_END)
> > >  		die("Device tree blob doesn't end with FDT_END\n");  
> > 
> > Likewise here for that matter, a NOP should be valid between the last
> > FDT_END_NODE and the FDT_END.
> 
> Yes, exactly and this will be taken into account in the next iteration.

Great.

> > > diff --git a/tests/run_tests.sh b/tests/run_tests.sh
> > > index f3647e63..8fc23cb7 100755
> > > --- a/tests/run_tests.sh
> > > +++ b/tests/run_tests.sh
> > > @@ -882,6 +882,11 @@ dtc_tests () {
> > >  
> > >      # Tests for overlay/plugin generation
> > >      dtc_overlay_tests
> > > +
> > > +    # Tests with "unknown tags"
> > > +    run_dtc_test -I dtb -O dts -o unknown_tags_can_skip.dtb.dts unknown_tags_can_skip.dtb
> > > +    base_run_test check_diff unknown_tags_can_skip.dtb.dts "$SRCDIR/unknown_tags_can_skip.dtb.dts.expect"  
> > 
> > It's best to avoid tests based on -O dts output unless we're
> > explicitly checking -O dts behaviour: because there are multiple ways
> > to format property values, the exact output isn't really guaranteed.
> 
> But at a give version dtc and a given dtb file, there is only one way
> to generate a dts.

Yes, but if we tweak our -Odts formatting decisions, we don't want to
have to churn tests that aren't specifically related to -Odts.

> If it change because of some modification in dtc, having some changes in
> tests expected value should not be a big deal.

It's not a huge deal, but it's still preferable to avoid.

> > What I'd suggest instead is to adjust treegen to generate two dtbs
> > that are identical _except_ for the skippable tag.  Then you can use
> > dtc -I dtb -O dtb, and compare the dtc output (which should strip the
> > tag) against the dtb which was constructed without it in the first
> > place.
> > 
> > Or, rather than explicitly creating two new trees, you could make your
> > skippable tag example identical to test_tree1, except for the
> > additional tag, and re-use one of the other instances of test_tree1 as
> > the "tagless" version.
> 
> Why not just one dtb generated to treegen with unknown tags (already available
> unknown_tags_can_skip.dtb)
> 
> dtc -I dtb -O dtb -o unknown_tags_can_skip.dtb.dtb unknown_tags_can_skip.dtb
> 
> And then
> 	base_run_test wrap_fdtdump unknown_tags_can_skip.dtb.dtb unknown_tags_can_skip.dtb.dtb.out
>     	# Remove unneeded comments
> 	sed -i '/^\/\/ [^U]/d' unknown_tags_can_skip.dtb.out
>     	base_run_test check_diff unknown_tags_can_skip.dtb.dtb.out "$SRCDIR/unknown_tags_can_skip.dtb.expect"

I don't like it - the output formatting of fdtdump is even less
guaranteed than -Odts.

> This avoid the need for 2 dtbs generated by treegen and also avoid to compare
> binary files which are difficult to analyze when the comparison detects a problem
> due to something broken by some modifications.

We _want_ to understand and test things at the binary byte level.
Debugging differences is a little trickier, but it's really not that
bad - -Odts or fdtdump or dtdiff can be used if/when there's a test
failure.  I really think doing the comparison in binary is preferable
- that's the level at which the behaviour is specified and should be
tested.

> > > +    run_wrap_error_test $DTC -I dtb -O dts -o unknown_tags_no_skip.dtb.dts unknown_tags_no_skip.dtb
> > >  }
> > >  
> > >  cmp_tests () {
> > > diff --git a/tests/unknown_tags_can_skip.dtb.dts.expect b/tests/unknown_tags_can_skip.dtb.dts.expect
> > > new file mode 100644
> > > index 00000000..2194025b
> > > --- /dev/null
> > > +++ b/tests/unknown_tags_can_skip.dtb.dts.expect
> > > @@ -0,0 +1,19 @@
> > > +/dts-v1/;
> > > +
> > > +/ {
> > > +	prop-int = <0x3201>;
> > > +	prop-str = "abcd";
> > > +
> > > +	subnode1 {
> > > +		prop-int = <0x6401 0x6402>;
> > > +	};
> > > +
> > > +	subnode2 {
> > > +		prop-int1 = <0x64020 0x64021>;
> > > +		prop-int2 = <0x32022>;
> > > +
> > > +		subsubnode {
> > > +			prop-bool;
> > > +		};
> > > +	};
> > > +};
> > > -- 
> > > 2.55.0
> > > 
> > >   
> > 
> 
> Best regards,
> Hervé
> 

-- 
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

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

  reply	other threads:[~2026-09-15 15:27 UTC|newest]

Thread overview: 82+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-26  8:31 [PATCH v3 00/15] Add support for structured tags and v18 dtb version Herve Codina
2026-08-26  8:31 ` [PATCH v3 01/15] fdtget: Use libfdt iterators instead of open coded loops Herve Codina
2026-08-27  3:55   ` David Gibson
2026-08-26  8:31 ` [PATCH v3 02/15] libfdt: Don't assume the root node is available at offset 0 Herve Codina
2026-08-30  3:21   ` David Gibson
2026-08-31 12:01     ` Herve Codina
2026-09-01  7:42       ` David Gibson
2026-09-01 12:18         ` Herve Codina
2026-09-02  7:06           ` David Gibson
2026-09-07 16:46             ` Herve Codina
2026-09-08  6:41               ` David Gibson
2026-09-08  8:08                 ` Herve Codina
2026-09-09  6:18                   ` David Gibson
2026-09-09  6:58                     ` Herve Codina
2026-09-09  7:02                       ` David Gibson
2026-08-26  8:31 ` [PATCH v3 03/15] tests: " Herve Codina
2026-09-01  8:03   ` David Gibson
2026-09-01 13:36     ` Herve Codina
2026-09-02  8:56       ` David Gibson
2026-08-26  8:31 ` [PATCH v3 04/15] tests/nopulate: Add a FDT_NOP before the root node Herve Codina
2026-09-01  8:05   ` David Gibson
2026-08-26  8:31 ` [PATCH v3 05/15] tests: treegen: Introduce emit_fdt_header_vers() Herve Codina
2026-09-09  6:38   ` David Gibson
2026-08-26  8:31 ` [PATCH v3 06/15] Introduce structured tag value definition Herve Codina
2026-09-10  4:51   ` David Gibson
     [not found]     ` <20260910094126.4bf4cae6@bootlin.com>
2026-09-10  9:32       ` David Gibson
2026-09-11  7:16         ` Herve Codina
2026-09-12  2:34           ` David Gibson
2026-09-14 10:19             ` Herve Codina
2026-09-16  5:21               ` David Gibson
2026-09-17  7:04                 ` Herve Codina
2026-09-18  4:41                   ` David Gibson
2026-09-18  8:16                     ` Herve Codina
2026-09-19  4:22                       ` David Gibson
2026-09-22  6:41                         ` Herve Codina
2026-09-24  3:49                           ` David Gibson
2026-09-25 10:48                             ` Herve Codina
2026-09-26  1:49                               ` David Gibson
2026-09-10  5:33   ` David Gibson
2026-09-10  7:58     ` Herve Codina
2026-09-10  9:41       ` David Gibson
2026-09-11  7:53         ` Herve Codina
2026-09-12  2:35           ` David Gibson
2026-09-17  8:56             ` Herve Codina
2026-08-26  8:31 ` [PATCH v3 07/15] fdtdump: Handle unknown tags Herve Codina
2026-09-10  5:25   ` David Gibson
2026-09-10  8:27     ` Herve Codina
2026-08-26  8:31 ` [PATCH v3 08/15] flattree: " Herve Codina
2026-09-14  8:23   ` David Gibson
2026-09-15 10:16     ` Herve Codina
2026-09-15 11:52       ` David Gibson [this message]
2026-09-16  6:31         ` Herve Codina
2026-09-16  8:27           ` David Gibson
2026-09-17  7:11             ` Herve Codina
2026-08-26  8:31 ` [PATCH v3 09/15] libfdt: Handle unknown tags in fdt_next_tag() Herve Codina
2026-09-16  9:10   ` David Gibson
2026-09-17  8:34     ` Herve Codina
2026-09-17  9:36       ` David Gibson
2026-09-17 17:28         ` Herve Codina
2026-09-19  4:46           ` David Gibson
2026-09-30 16:47             ` Herve Codina
2026-10-01  3:07               ` David Gibson
2026-08-26  8:31 ` [PATCH v3 10/15] libfdt: Introduce fdt_ptr_offset_() Herve Codina
2026-08-26  8:31 ` [PATCH v3 11/15] libfdt: Introduce fdt_getprop_by_offset_w() Herve Codina
2026-09-16  9:56   ` David Gibson
2026-09-16 10:42     ` Herve Codina
2026-09-17  4:52       ` David Gibson
2026-09-17  8:43         ` Herve Codina
2026-08-26  8:31 ` [PATCH v3 12/15] libfdt: Introduce fdt_getprop_offset_namelen() Herve Codina
2026-09-21  6:07   ` David Gibson
2026-09-22 16:25     ` Herve Codina
2026-08-26  8:31 ` [PATCH v3 13/15] tests: Add wip_func utility Herve Codina
2026-09-16 10:00   ` David Gibson
2026-09-16 17:27     ` Herve Codina
2026-08-26  8:31 ` [PATCH v3 14/15] libfdt: Handle unknown tags on dtb modifications Herve Codina
2026-09-21  6:06   ` David Gibson
2026-09-25 12:40     ` Herve Codina
2026-09-28  4:39       ` David Gibson
2026-09-28 14:54         ` Herve Codina
2026-08-26  8:31 ` [PATCH v3 15/15] Introduce v18 dtb version Herve Codina
2026-09-21  6:20   ` David Gibson
2026-09-25 13:21     ` Herve Codina

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=aqkxacdQHZuhhyxw@gractus.seuss \
    --to=david@gibson.dropbear.id.au \
    --cc=Frank.Li@nxp.com \
    --cc=ayush@beagleboard.org \
    --cc=conor+dt@kernel.org \
    --cc=devicetree-compiler@vger.kernel.org \
    --cc=devicetree-spec@vger.kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=dlechner@baylibre.com \
    --cc=geert@linux-m68k.org \
    --cc=herve.codina@bootlin.com \
    --cc=hui.pu@gehealthcare.com \
    --cc=ian.ray@gehealthcare.com \
    --cc=krzk@kernel.org \
    --cc=laurent.pinchart@ideasonboard.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=luca.ceresoli@bootlin.com \
    --cc=robh@kernel.org \
    --cc=thomas.petazzoni@bootlin.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox