January 24, 2022

Orange Pi 4 (Rockchip 3399) patching U-Boot env settings

Once again, why do this? I have a version of U-Boot that came on my Debian distribution on SD card, and it does work to boot debian, both from SD card and from emmc. But it has a problem: For whatever reason, the "debian u-boot" tries to do a saveenv to emmc, whether it is running from SD card or emmc. In particular, if there is no emmc, it still tries to do the saveenv to emmc when run from SD card.

For most people this would not matter in any event. U-boot works as shipped to boot linux and requires no fiddling with. However, for my purposes, I interrupt U-boot, change some enviroment variables, then do a saveenv to preserve my changes.

One option would be to rebuild U-boot from source and make any necessary changes. A person could change how saveenv works, or they could modify the initial values of the env variables. For me, this encounters other problems. Dealing with bl31 for one, and simply getting a scratch built U-boot onto an SD card for another. These are both things I intend to learn about -- some fine day, but right now I am looking for a quick way to get the U-boot setup I want onto an SD card soI can get busy with other things.

Patch the image

I did this once before for another project with good success. The concept is to examine the u-boot binary, find where the env variables are stores, then overwrite the whole mess with exactly what I want. I sounds ugly, but that is much of the charm of doing things that way. Given a little program I wrote for that other project, is is quite easy.

The snag comes when I install the image. Apparently there is some kind of header with a checksum, and my patched image gets rejected. So the game now becomes figuring out how to redo that header.

Fix the header

Looking at the mainline u-boot build process as a guide, we can learn how the header is generated. In short, the u-boot "mkimage" utility is used. The basic process seems to be: The dtb is appended in a straightforward way:
cat u-boot-nodtb.bin dts/dt.dtb > u-boot-dtb.bin
cp u-boot-dtb.bin u-boot.bin
The mkimage tool is run with a list of options, as follows:
./tools/mkimage -f auto -A arm -T firmware -C none -O u-boot -a 0x00200000 -e 0x00200000 -p 0x0
     -n "U-Boot 2022.01""-00450-g25711b07ca-dirty for evb_rk3399 board"
     -E  -b arch/arm/dts/rk3399-orangepi.dtb  -d u-boot-nodtb.bin u-boot-dtb.img
I see the following file sizes:
-rw-rw-r--   1 tom tom  711376 Jan 23 22:50 u-boot-dtb.bin
-rw-rw-r--   1 tom tom  712392 Jan 23 22:50 u-boot-dtb.img
The "img" file adds 1016 bytes. Examination of the files indicate this is all at the start of the file, so indeed simply a header is prepended. It is apparently only coincidence that it is nearly 1024 bytes. As just a note, the header can be removed as follows:
dd if=u-boot-dtb.img of=zzz bs=1 skip=1016
This was done, file sizes verified and cmp used to compare the contents.
Here are some notes on those mkimage options.
-f auto - input filename for FIT source
-A arm -- specify architecture
-T firmware -- set image type
-C none -- set compression
-O u-boot -- set operating system
-a 0x00200000 -- load address
-e 0x00200000 -- entry point
-p 0 -- place external data at static position
-n "..." -- set image name
-E -- place data outside the FIT structure
-b path -- ?? something involving the dtb
-d file -- use image data from file
An interesting note is the claim that "-l" will list header information from an existing image. Doing this on an image generated by the mainline u-boot sources yields a full screen of information. Doing this on the debian U-boot image yields only one line:
GP Header: Size 4c4f4144 LoadAddr 45522020
This, as it turns out, is simply the first 8 bytes of the file, which is the string "LOADER ". So, the debian u-boot image is something entirely different.

Have any comments? Questions? Drop me a line!

Tom's electronics pages / tom@mmto.org