HOWTO cross-compile u-boot for Amlogic 64-bit SoC's

Introduction

First, a warning: compiling mainline u-boot for any 64-bit Amlogic SoC is not a simple task. Unfortunately, Amlogic has decided to include some closed-source, encrypted blobs in the bootloader code. To generate these blobs and integrate them with the mainline u-boot source requires the use of an outdated 32-bit version of the gcc compiler, that has to be downloaded from the Linaro archives, and preferably executed in a separate environment, i.e. a chroot, container or virtual machine running Linux.

So, compiling u-boot for the "La Frite" is a three-step process:

  1. Setting up a separate virtual environment on your development workstation (here we use Ubuntu 18.04; if you are using another distribution the steps will be slightly different but on the whole very similar) inside of which we'll compile mainline u-boot, assemble the binary blobs and generate the final u-boot image.
  2. Compiling the mainline u-boot code.
  3. Assembling the binary blobs and combining them with our mainline u-boot code.

Installing and testing u-boot on your "La Frite" will be covered in a separate document.

The mainline u-boot build "cheat sheet"

Note: I have listed all the commands below in this "cheat sheet" from which they can be copy-pasted in a terminal.

Note 2: There is also an experimental build using a much more recent x86-64 compiler for the blobs (avoids having to setup a 32-bit environment) described in this experimental "cheat sheet" .

Setting up a container to compile u-boot

We'll use a container because containers are very easy to create and manage under Ubuntu 18.04, and essentially they run as fast as the bare metal.
Note that the container temporarily requires approximately 1GB of free disk space, for our purposes.
Follow the instructions here to create the container: https://www.cyberciti.biz/faq/install-lxd-pure-container-hypervisor-on-ubuntu-18-04-lts/

I answered all the defaults to install and setup lxd, then I created and launched a Ubuntu 18.04 amd64 container named ubuntu-uboot-compilation on my old and trusty Thinkpad T420 laptop, using the following command:

> lxc launch images:ubuntu/bionic/amd64 ubuntu-uboot-compilation

Once the container is created we can directly run a bash shell as root inside it:

andrew@andrew-ThinkPad-T420:~$ lxc exec ubuntu-uboot-compilation bash

root@ubuntu-uboot-compilation:~# apt-get update
Get:1 http://security.ubuntu.com/ubuntu bionic-security InRelease [88.7 kB]
Hit:2 http://archive.ubuntu.com/ubuntu bionic InRelease                              
Get:3 http://archive.ubuntu.com/ubuntu bionic-updates InRelease [88.7 kB]            
Get:4 http://security.ubuntu.com/ubuntu bionic-security/main amd64 Packages [270 kB]          
Get:5 http://archive.ubuntu.com/ubuntu bionic-updates/main amd64 Packages [527 kB]
Fetched 974 kB in 1s (1480 kB/s)                        
Reading package lists... Done
root@ubuntu-uboot-compilation:~# apt-get upgrade
Reading package lists... Done
Building dependency tree       
Reading state information... Done
Calculating upgrade... Done
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
root@ubuntu-uboot-compilation:~#

We install the required packages to compile u-boot:

> apt install bc nano mc build-essential autoconf libtool cmake pkg-config git python-dev swig3.0 libpcre3-dev nodejs-dev gawk wget diffstat bison flex device-tree-compiler libncurses5-dev gcc-aarch64-linux-gnu g++-aarch64-linux-gnu binfmt-support

We create a u-boot_dev directory under which we are going to do all our development work:
> mkdir u-boot_dev
> cd u-boot_dev

We now git (shallow, to save time) clone the u-boot mainline master branch:

root@ubuntu-uboot-compilation:~/u-boot_dev# git clone --depth 1 https://github.com/u-boot/u-boot -b master

At this stage it is necessary to read some docs that contain instructions to build the closed source blobs for Amlogic SoC's, but don't worry, they are not too long:

  • To compile u-boot for the S905, read u-boot/board/amlogic/odroid-c2/README.odroid-c2
  • To compile u-boot for the S905X, read u-boot/board/amlogic/p212/README.p212 (or README.libretech-cc in our case)
  • To compile u-boot for the S912, read u-boot/board/amlogic/q200/README.q200

Now the container is practically ready for use, so we continue with the next step, that is compiling mainline u-boot. Note that since the S805X SoC is almost identical to the S905X SoC, we are going to follow the instructions to compile u-boot for the S905X-based "Le Potato" in this example. Hopefully this u-boot will work fine on the "La Frite".

Cross-compiling mainline u-boot for the "La Frite"

Building mainline u-boot itself is actually quite simple and takes at most a couple of minutes:

> cd u-boot
> export ARCH=arm
> export CROSS_COMPILE=aarch64-linux-gnu-
> make libretech-cc_defconfig
> make menuconfig (optional, in case you want to customize u-boot to your taste)
> make

Generating and integrating the closed-source blobs

Now comes the complicated part: we have to build the u-boot binary image by combining the u-boot executable we just compiled with closed source blobs from Amlogic. To do this, we follow exactly the steps listed in the "Image creation" section of the README's listed above, in this case, the README.libretech-cc document.

> cd ..
> mkdir blobs
> cd blobs

Also note that beforehand we have to prepare our 64-bit container to be able to run 32-bit executables:

> dpkg --add-architecture i386
> apt update
> apt install libc6:i386 libncurses5:i386 libstdc++6:i386 lib32z1

============ copied from instructions in README ==============

Amlogic doesn't provide sources for the firmware and for tools needed
to create the bootloader image, so it is necessary to obtain them from
the git tree published by the board vendor:

> wget https://releases.linaro.org/archive/13.11/components/toolchain/binaries/gcc-linaro-aarch64-none-elf-4.8-2013.11_linux.tar.xz
> wget https://releases.linaro.org/archive/13.11/components/toolchain/binaries/gcc-linaro-arm-none-eabi-4.8-2013.11_linux.tar.xz
> tar xvfJ gcc-linaro-aarch64-none-elf-4.8-2013.11_linux.tar.xz
> tar xvfJ gcc-linaro-arm-none-eabi-4.8-2013.11_linux.tar.xz
> export PATH=$PWD/gcc-linaro-aarch64-none-elf-4.8-2013.11_linux/bin:$PWD/gcc-linaro-arm-none-eabi-4.8-2013.11_linux/bin:$PATH
> git clone https://github.com/BayLibre/u-boot.git -b libretech-cc amlogic-u-boot
> cd amlogic-u-boot
> sed -i 's/aarch64-linux-gnu-/aarch64-none-elf-/' Makefile
> sed -i 's/arm-linux-/arm-none-eabi-/' arch/arm/cpu/armv8/gxb/firmware/scp_task/Makefile
> make libretech_cc_defconfig
> make
> export FIPDIR=$PWD/fip

(note that at this point we have compiled all the various blobs in the FIP directory, the rest of the instructions deal with integrating them with our mainline u-boot code)

Go back to mainline U-Boot source tree then :

(note that you should be in /root/u-boot_dev/blobs/amlogic-u-boot; to go back to mainline U-Boot source tree, just cd ../../u-boot )

> mkdir fip

> cp $FIPDIR/gxl/bl2.bin fip/
> cp $FIPDIR/gxl/acs.bin fip/
> cp $FIPDIR/gxl/bl21.bin fip/
> cp $FIPDIR/gxl/bl30.bin fip/
> cp $FIPDIR/gxl/bl301.bin fip/
> cp $FIPDIR/gxl/bl31.img fip/
> cp u-boot.bin fip/bl33.bin (in case you didn't notice, we just copied our mainline u-boot.bin into the fip directory)

> $FIPDIR/blx_fix.sh fip/bl30.bin fip/zero_tmp fip/bl30_zero.bin fip/bl301.bin fip/bl301_zero.bin fip/bl30_new.bin bl30

(note that you may need to call the python interpreter to run the acs_tool.pyc byte-compiled program in the following line, so "python $FIPDIR/acs_tool.pyc …")

> $FIPDIR/acs_tool.pyc fip/bl2.bin fip/bl2_acs.bin fip/acs.bin 0

> $FIPDIR/blx_fix.sh fip/bl2_acs.bin fip/zero_tmp fip/bl2_zero.bin fip/bl21.bin fip/bl21_zero.bin fip/bl2_new.bin bl2

> $FIPDIR/gxl/aml_encrypt_gxl --bl3enc --input fip/bl30_new.bin
> $FIPDIR/gxl/aml_encrypt_gxl --bl3enc --input fip/bl31.img
> $FIPDIR/gxl/aml_encrypt_gxl --bl3enc --input fip/bl33.bin
> $FIPDIR/gxl/aml_encrypt_gxl --bl2sig --input fip/bl2_new.bin --output fip/bl2.n.bin.sig
> $FIPDIR/gxl/aml_encrypt_gxl --bootmk --output fip/u-boot.bin --bl2 fip/bl2.n.bin.sig --bl30 fip/bl30_new.bin.enc --bl31 fip/bl31.img.enc --bl33 fip/bl33.bin.enc

(the final u-boot binary image is fip/u-boot.bin.sd.bin)

Cleanup

To exit the container:

root@ubuntu-uboot-compilation:~/u-boot# exit
exit
andrew@andrew-ThinkPad-T420:~$

Finally copy the u-boot binary image from the container, and delete the container:
> lxc file pull ubuntu-uboot-compilation/root/u-boot_dev/u-boot/fip/u-boot.bin.sd.bin .
> lxc stop ubuntu-uboot-compilation
> lxc delete ubuntu-uboot-compilation

References