January 19, 2025

Antminer S9 board - further examination of the U-boot SPL

After the U-boot build finishes, we can look inside the "spl" directory and find a host of products. We then wonder which is which and what to do with them. Here is a list sorted in time order, which should arrange them in the order produced by the "make" process.
-rw-r--r--  1 tom tom     876 Jan 19 22:15 u-boot-spl.lds
-rw-r--r--  1 tom tom  339990 Jan 19 22:15 u-boot-spl.map
-rwxr-xr-x  1 tom tom 1672848 Jan 19 22:15 u-boot-spl
-rwxr-xr-x  1 tom tom  131256 Jan 19 22:15 u-boot-spl-nodtb.bin
-rw-r--r--  1 tom tom    1988 Jan 19 22:15 u-boot-spl.dtb
-rw-r--r--  1 tom tom  133244 Jan 19 22:15 u-boot-spl-dtb.bin
-rw-r--r--  1 tom tom  133244 Jan 19 22:15 u-boot-spl.bin
-rw-r--r--  1 tom tom   49566 Jan 19 22:15 u-boot-spl.sym
-rw-r--r--  1 tom tom  133244 Jan 19 22:15 u-boot-spl-align.bin
-rw-r--r--  1 tom tom  135484 Jan 19 22:15 boot.bin
Wow, what is all of this? The first two are fairly easy.
u-boot-spl.lds -- the linker script used to control the link process
u-boot-spl.map -- produced during the link by the -Map option to "ld"

The next two files are also pretty easy, and important.

Next we have the ELF file produced by the link, namely "u-boot-spl"

u-boot-spl           -- the ELF file produced by the link
u-boot-spl-nodtb.bin -- binary image extracted from the above

Notice how big the ELF file is. From here things get more interesting.

u-boot-spl.dtb     - device tree binary
u-boot-spl-dtb.bin - SPL combined with the above
u-boot-spl.bin     - identical to the above
u-boot-spl.sym     - symbols for the above
The commands to produce these are simple enough:
cp spl/dts/dt-spl.dtb spl/u-boot-spl.dtb
cat spl/u-boot-spl-nodtb.bin spl/u-boot-spl.dtb > spl/u-boot-spl-dtb.bin
cp spl/u-boot-spl-dtb.bin spl/u-boot-spl.bin
arm-none-eabi-objdump -t spl/u-boot-spl > spl/u-boot-spl.sym
The "dtb" file itself is made by these commands. This is a whole business that I have no intention of digging into now. What is worthy of note is that a device tree is expected by the SPL, and that it is simply concatenated onto the end of the binary image.
make -f ./scripts/Makefile.build obj=spl/dts spl_dtbs
mkdir -p spl/dts/
./tools/fdtgrep -b bootph-all -b bootph-pre-ram -b u-boot,dm-pre-reloc -b u-boot,dm-spl -RT dts/dt.dtb -n /chosen -n /config -O dtb | ./tools/fdtgrep -r -O dtb - -o spl/dts/dt-spl.dtb -P bootph-all -P bootph-pre-ram -P bootph-pre-sram -P bootph-verify -P u-boot,dm-pre-reloc -P u-boot,dm-spl -P u-boot,dm-tpl -P u-boot,dm-vpl -P pinctrl-0 -P pinctrl-names -P interrupt-parent -P interrupts
cp spl/dts/dt-spl.dtb spl/u-boot-spl.dtb
This leaves us with just two last files to ponder:
-rw-r--r--  1 tom tom  133244 Jan 19 22:15 u-boot-spl-align.bin
-rw-r--r--  1 tom tom  135484 Jan 19 22:15 boot.bin
It turns out this "align" file is identical to u-boot-spl.bin, which is identical to u-boot-spl-dtb.bin. Perhaps this is just coincidence and in some cases the align file would have had padding adding to meet some alignment requirement.
Here is the command that produces this, as well as the last file "boot.bin":
./tools/mkimage -T zynqimage -R ./"" -d spl/u-boot-spl-align.bin spl/boot.bin >/dev/null  && cat /dev/null
The file "boot.bin" is something we are quite familiar with. In this case it is the "binary image of interest" packaged with a zynq bootrom header in front of it. The software item "tools/mkimage" will need to be examined to understand what is going on. It gets used in the next line of the build to do even fancier things:
./tools/mkimage -f auto -A arm -T firmware -C none -O u-boot -a 0x4000000 -e 0x4000000 -p 0x0 -n "U-Boot 2024.01-dirty for zynq board" -E
-b arch/arm/dts/zynq-zc702.dtb -b arch/arm/dts/zynq-zc706.dtb -b arch/arm/dts/zynq-zc770-xm010.dtb -b arch/arm/dts/zynq-zc770-xm011.dtb
-b arch/arm/dts/zynq-zc770-xm011-x16.dtb -b arch/arm/dts/zynq-zc770-xm012.dtb -b arch/arm/dts/zynq-zc770-xm013.dtb
-b arch/arm/dts/zynq-cc108.dtb -b arch/arm/dts/zynq-microzed.dtb -b arch/arm/dts/zynq-minized.dtb -b arch/arm/dts/zynq-picozed.dtb
-b arch/arm/dts/zynq-zed.dtb -b arch/arm/dts/zynq-zturn.dtb -b arch/arm/dts/zynq-zturn-v5.dtb -b arch/arm/dts/zynq-zybo.dtb
-b arch/arm/dts/zynq-zybo-z7.dtb -b arch/arm/dts/zynq-dlc20-rev1.0.dtb
-d u-boot-nodtb.bin u-boot.img >/dev/null  && cat /dev/null

What is going on here? We have "dtb" (device table) files for every zynq board know to man. How do we specify which one to use, or do we? Also remember that the original defconfig file had a list of boards in it. All the device table source files are in "arch/arm/dts" and are worth looking at and comparing.

Remember that the Makefile runs in the U-boot root directory, not in the "spl" directory, as you examine the above. The above is "bloated" by the long list of "-b xyz.dtb" arguments in the middle of it, so look at the following where I condense all of those:

./tools/mkimage -f auto -A arm -T firmware -C none -O u-boot -a 0x4000000 -e 0x4000000
-p 0x0 -n "U-Boot 2024.01-dirty for zynq board" -E
-b XXX
-d u-boot-nodtb.bin u-boot.img >/dev/null  && cat /dev/null

Feedback? Questions? Drop me a line!

Tom's Computer Info / tom@mmto.org