U-Boot on the RaspberryPi

The installation of u-boot for RaspberryPi boards is rather simple. This guide will focus on installing U-Boot for the Raspberry Pi 3 Model B+ and is inspired by this blog post: https://www.thegoodpenguin.co.uk/blog/build-boot-linux-on-raspberry-pi-3-model-b/.

Getting the toolchain

The RPI 3B+ has an ARMv8 CPU, so we need a toolchain that builds 64bit ARMv8 binaries:

wget https://releases.linaro.org/components/toolchain/binaries/latest-7/aarch64-linux-gnu/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu.tar.xz
tar -xf gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu.tar.xz -C ~/tools
export PATH=~/tools/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin:$PATH

Getting U-Boot

After the toolchain is in PATH, the U-Boot sources can be cloned and built:

git clone git://git.denx.de/u-boot.git # v2021.01-rc2-121-g5b8991c667f7
cd u-boot
make ARCH=arm CROSS_COMPILE=aarch64-linux-gnu- rpi_3_b_plus_defconfig
make ARCH=arm CROSS_COMPILE=aarch64-linux-gnu--j$(nproc)
cd ..

Kernel Image

After U-Boot is done building, grab the latest mainline kernel and configure it. In this scenario we are building an Image binary:

git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git # v5.10-rc4-368-g27bba9c532a8
cd linux
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- defconfig
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j$(nproc)
cd ..

RootFS

Fast forwarding after building the Kernel, the Pi also needs a Rootfs. To get a quick Rootfs, head to the Rootfs Section from this journal.

Preparing the SD Card Image

Now that everything is set up to build the SD Card image, we need to define the partition table of the target sd card. sfdisk can help building the partition table onto a device. The sfdisk config file can look like this:

Listing 1 sfdisk config
1label: dos
2label-id: 0x85baa6c1
3device: /dev/sda
4unit: sectors
5
6/dev/sda1 : start=        2048, size=      524288, type=c, bootable
7/dev/sda2 : start=      526336, size=    29726687, type=83

The first partition starts at an offset of 2048 sectors (default) and gets the bootable flag. The second partition will be the rootfs, having the 83 or Linux partition type.

To flash this layout (rpilayout) onto the sd card (in this example /dev/sda), use the sfdisk command:

sudo sfdisk /dev/sda < rpilayout

This only creates the partition table, the partitions have to be formatted aswell:

sudo mkfs.vfat /dev/sda1 # Format the first partition vfat

If your rootfs is a .ext4 file, you can just use dd to flash it onto the target:

sudo dd if=${YOUR_ROOTFS_EXT4} of=/dev/sda2 bs=4M conv=fsync status=progress

Otherwise, format the seconds partition ext4 and copy your files there manually:

sudo mkfs.ext4 -L rootfs /dev/sda2
sudo mount --mkdir /dev/sda2 rpi_rootfs
sudo cp -rT ${YOUR_ROOTFS_DIR} rpi_rootfs
sync
sudo umount rpi_rootfs

Then all the other components can be copied onto the SD Card:

sudo mount --mkdir /dev/sda1 rpi_boot
cp u-boot/u-boot.bin rpi_boot/kernel8.img
cp linux/arch/arm64/boot/Image rpi_boot/
cp linux/arch/arm64/boot/dts/broadcom/bcm2837-rpi-3-b-plus.dtb rpi_boot/

The RaspberryPi also needs closed-source firmware, such as the GPU firmware (start.elf) and the second-stage bootloader (bootcode.bin) to start the CPU and load our Bootloader and Kernel Images:

wget https://github.com/raspberrypi/firmware/archive/master.zip
unzip master.zip
cp firmware-master/boot/{fixup.dat,start.elf,bootcode.bin} rpi_boot/

The start.elf firmware is configured by the config.txt file on the FAT partition. Configuring this file will enable UART to communicate with the device and enable 64 bit support:

Listing 2 config.txt
[...]
enable_uart=1
kernel=kernel8.bin
arm_64bit=1

Last Steps in Configuing U-Boot on the Target

Now the SD Card can be ejected and used for the RaspberryPi. Setup a UART connection to the Pi and boot it. When U-Boot is active, there will be a prompt like this:

Hit any key to stop autoboot

When this occurs, hit any key and the U-Boot shell will present itself. Here we need to set a few variables:

setenv bootcmd 'fatload mmc 0 ${kernel_addr_r} Image ; fatload mmc 0 ${fdt_addr_r} bcm2837-rpi-3-b-plus.dtb ; booti ${kernel_addr_r} - ${fdt_addr_r}'
setenv bootargs 'console=ttyS1,115200n8 rootwait root=/dev/mmcblk0p2'
saveenv

And that’s it!

sources: