Raspberry Pi 4: Boot Ubuntu 20.04 via USB

For some time, the Raspberry Pi 4 also supports booting via USB to circumvent buggy SD card system media. Back in May, this feature was supplied as beta, since September it is considered as stable functionality.

Booting Raspberry Pi OS (former Raspbian) via USB works out of the box, but additional steps are required for the current Ubuntu LTS version 20.04.

Before booting Ubuntu via USB you will need to update the single-board computer's EEPROM using a Raspberry Pi OS installation. First, ensure having all available updates installed and reboot the device before altering the configuration file /etc/default/rpi-eeprom-update:

1FIRMWARE_RELEASE_STATUS="stable"
Note

The previous setting (critical) won't install the newest firmware!

Afterwards, update the firmware:

1# rpi-eeprom-update -d -f /lib/firmware/raspberrypi/bootloader/stable/pieeprom-2020-09-03.bin
Note

When writing this article, the latest firmware was released on 03.09.2020.

After another reboot the new firmware is enabled.

In the metantime, copy the Ubuntu 20.04 Raspberry Pi image on an USB device, e.g. using balenaEtcher or Win32DiskImager. Before the medium can be bootet, you will need to copy missing bootloader files. This can be done with the following command:

1$ wget $( wget -qO - https://github.com/raspberrypi/firmware/tree/master/boot | perl -nE 'chomp; next unless /[.](elf|dat)/; s/.*href="([^"]+)".*/$1/; s/blob/raw/; say qq{https://github.com$_}' )
Note

Kudos to Richard Tirtadji for this one-liner and the following script!

Afterwards, the downloaded *.dat and *.elf files need to be copied to the FAT partition on the USB device (will be mounted below /boot/firmware later).

This is also a good time to unpack the compressed kernel image as the firmware currently only supports booting uncompressed images:

1$ cd mountpoint
2$ zcat vmlinuz > vmlinux

In the same folder you will also need to alter the file config.txt to ensure that the image can be found. For my installation, the following lines were needed:

1[pi4]
2kernel=uboot_rpi_4.bin
3max_framebuffers=2
4dtoverlay=vc4-fkms-v3d
5boot_delay
6kernel=vmlinux
7initramfs initrd.img followkernel

Afterwards, a script (auto_decompress_kernel) is created - it will automatically decompress kernel images:

 1#!/bin/bash -e
 2
 3# set Variables
 4BTPATH=/boot/firmware
 5CKPATH=$BTPATH/vmlinuz
 6DKPATH=$BTPATH/vmlinux
 7
 8# check if compression needs to be done.
 9if [ -e $BTPATH/check.md5 ]; then
10  if md5sum --status --ignore-missing -c $BTPATH/check.md5; then
11    echo -e "\e[32mFiles have not changed, Decompression not needed\e[0m"
12    exit 0
13  else echo -e "\e[31mHash failed, kernel will be compressed\e[0m"
14  fi
15fi
16
17# backup the old decompressed kernel
18mv $DKPATH $DKPATH.bak
19
20if [ ! $? == 0 ]; then
21  echo -e "\e[31mDECOMPRESSED KERNEL BACKUP FAILED!\e[0m"
22  exit 1
23else echo -e "\e[32mDecompressed kernel backup was successful\e[0m"
24fi
25
26# decompress the new kernel
27echo "Decompressing kernel: "$CKPATH".............."
28
29zcat $CKPATH > $DKPATH
30
31if [ ! $? == 0 ]; then
32  echo -e "\e[31mKERNEL FAILED TO DECOMPRESS!\e[0m"
33  exit 1
34else echo -e "\e[32mKernel Decompressed Succesfully\e[0m"
35fi
36
37#hash the new kernel for checking
38md5sum $CKPATH $DKPATH > $BTPATH/check.md5
39
40if [ ! $? == 0 ]; then
41  echo -e "\e[31mMD5 GENERATION FAILED!\e[0m"
42else echo -e "\e[32mMD5 generated Succesfully\e[0m"
43fi
44
45# exit
46exit 0

Ensure changing the file permissions to make the script executable:

1$ chmod +x auto_decompress_kernel

It is a good idea to link the script after the first boot with apt package management to have it executed after installing kernel updates. For this, create the file  /etc/apt/apt.conf.d/999_decompress_rpi_kernel and make it executbale:

1$ cat /etc/apt/apt.conf.d/999_decompress_rpi_kernel
2# content 999_decompress_rpi_kernel
3DPkg::Post-Invoke {"/bin/bash /boot/firmware/auto_decompress_kernel"; };
4
5$ chmod +x $_

Afterwards, booting should never be a problem again.

Translations: