First using /delete-node/ and then creating the node again results in wrong ordering of subnodes
I've been working with U-Boot project's device tree source files, and i encountered a strange issue today when I wanted to override a node completely. U-Boot has their own outdated fork of dtc in their source tree, but I checked that the same issue is present even in the latest commit of the dtc's main-branch. (At the time of writing Commit 7f3184a.)
Here's overly simplified example which reproduces the issue: foo.dts:
/dts-v1/;
#include "bar.dtsi"
/* Try to Expand u-boot-spl to u-boot-spl-nodtb and u-boot-spl-pubkey-dtb while
* keeping them as first nodes in the list, by completely overriding the node
*/
&spl {
/delete-node/ images;
images {
u-boot-spl-nodtb {
align-end = <4>;
};
u-boot-spl-pubkey-dtb {
algo = "sha512,rsa4096";
required = "conf";
key-name-hint = "uboot";
align-end = <4>;
};
ddr1 {
filename = "ddr1.bin";
};
ddr2 {
filename = "ddr2.bin";
};
ddr3 {
filename = "ddr3.bin";
};
ddr4 {
filename = "ddr4.bin";
};
};
};
bar.dtsi:
/ {
binman: binman {
};
};
&binman {
spl: spl {
images {
u-boot-spl {
align-end = <4>;
};
ddr1 {
filename = "ddr1.bin";
};
ddr2 {
filename = "ddr2.bin";
};
ddr3 {
filename = "ddr3.bin";
};
ddr4 {
filename = "ddr4.bin";
};
};
};
};
Now if I run:
cpp -nostdinc -undef -x assembler-with-cpp foo.dts -o foo.preprocessed
dtc -I dts -O dtb -o foo.dtb foo.preprocessed
And then fdtdump foo.dtb, I get the subnodes under the images in a wrong order (which then results in a non-booting image in the U-Boot because the stuff gets in wrong order):
**** fdtdump is a low-level debugging tool, not meant for general use.
**** If you want to decompile a dtb, you probably want
**** dtc -I dtb -O dts <filename>
/dts-v1/;
// magic: 0xd00dfeed
// totalsize: 0x1e3 (483)
// off_dt_struct: 0x38
// off_dt_strings: 0x1b4
// off_mem_rsvmap: 0x28
// version: 17
// last_comp_version: 16
// boot_cpuid_phys: 0x0
// size_dt_strings: 0x2f
// size_dt_struct: 0x17c
/ {
binman {
spl {
images {
ddr1 {
filename = "ddr1.bin";
};
ddr2 {
filename = "ddr2.bin";
};
ddr3 {
filename = "ddr3.bin";
};
ddr4 {
filename = "ddr4.bin";
};
u-boot-spl-nodtb {
align-end = <0x00000004>;
};
u-boot-spl-pubkey-dtb {
algo = "sha512,rsa4096";
required = "conf";
key-name-hint = "uboot";
align-end = <0x00000004>;
};
};
};
};
};
Expected result: u-boot-spl-nodtb and u-boot-spl-pubkey-dtb nodes should be before ddrs.
Workaround:
However I was able to work around this, if before the #include "bar.dtsi" I specify this in foo.dts:
/ {
binman: binman {
spl: spl {
images {
u-boot-spl-nodtb {
};
u-boot-spl-pubkey-dtb {
};
};
};
};
};
/delete-node/ &binman;
#include "bar.dtsi"
...
Even though the binman-node is deleted, it still remembers the u-boot-spl-nodtb and u-boot-spl-pubkey-dtb were the first ones in the list.
After adding the workaround hack, the fdtdump now shows correct structure (the expected result):
**** fdtdump is a low-level debugging tool, not meant for general use.
**** If you want to decompile a dtb, you probably want
**** dtc -I dtb -O dts <filename>
/dts-v1/;
// magic: 0xd00dfeed
// totalsize: 0x1e3 (483)
// off_dt_struct: 0x38
// off_dt_strings: 0x1b4
// off_mem_rsvmap: 0x28
// version: 17
// last_comp_version: 16
// boot_cpuid_phys: 0x0
// size_dt_strings: 0x2f
// size_dt_struct: 0x17c
/ {
binman {
spl {
images {
u-boot-spl-nodtb {
align-end = <0x00000004>;
};
u-boot-spl-pubkey-dtb {
algo = "sha512,rsa4096";
required = "conf";
key-name-hint = "uboot";
align-end = <0x00000004>;
};
ddr1 {
filename = "ddr1.bin";
};
ddr2 {
filename = "ddr2.bin";
};
ddr3 {
filename = "ddr3.bin";
};
ddr4 {
filename = "ddr4.bin";
};
};
};
};
};
I briefly read the dtc source code livetree.c , and I suspect that the /delete-node/ does not actually delete the node and the subnodes, but only marks them as deleted, and if a node with a same name is added again later, it just marks the deleted node undeleted again, resulting in wrong order of the elements.
(This is just overly simplified example, the real code where this issue became visible is here: https://github.com/u-boot/u-boot/blob/master/arch/arm/dts/imx8mp-u-boot.dtsi#L101 )