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:
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:
[...]
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: