Raspberry Pi 4 UEFI Booting

I bought a Raspberry Pi 4 with 8GB of RAM and I wanted to try out UEFI on it. I’m happy to say it works and this excites me!

My exact steps:

  1. Connect an FTDI 3.3V logic cable to my Raspberry Pi 4 header, pin 6 is ground (black FTDI wire), 8 is Tx from the RPi (yellow FTDI wire), and 10 is Rx from the RPi (orange FTDI wire). Connect to the FTDI serial port using picocom with baud rate 115200 8n1.
  2. Update the EEPROM by writing the EEPROM updater tool to a micro SD card from GitHub - raspberrypi/rpi-eeprom: Installation scripts and binaries for the closed sourced Raspberry Pi 4 EEPROMs (I used the rpi-boot-eeprom-recovery-2021-04-29-vl805-000138a1-disk-images tag). Boot this and wait until the green LED on the side of the board flashes fast, indicating it’s done.
  3. Using a PC, partition a USB thumb drive to use GPT and create a EFI System Partition (ESP) as the first partition. Format this as vfat, mount it, and unzip the UEFI contents from GitHub - pftf/RPi4: Raspberry Pi 4 UEFI Firmware Images (I used the v1.32 tag). Unmount the USB thumb drive and stick it in your Raspberry Pi 4.
  4. Power up the Raspberry Pi 4 and watch it boot into UEFI!

Console log here: https://gist.githubusercontent.com/bradfa/ef0352ffe5df83447120abf172b15dcf/raw/67fc67f05d0d48a2afdbfb39baecf6bd561cc02a/rpi4-uefi-serial.log

I don’t yet have any OS configured on the USB thumb drive but that’s next. Apparently I’ll need a rather recent Linux kernel (>=v5.7 I believe) in order for all the ACPI things to work enough to be usable (due to past Raspberry Pi support all leveraging device tree).

The only changes I made in the UEFI config menus were to enable the UART as the default console instead of the HDMI outputs and to unblock the 3GB memory limit, since my Raspberry Pi 4 has 8GB of RAM and I want to try using it.

2 Likes

My next steps will be to use debos (GitHub - go-debos/debos: Debian OS builder) to build a full Debian disk image including the UEFI. Then I hope to setup the EDKII development environment and build that myself, too.

Being able to use UEFI and ACPI on ARM is not new to me (it’s part of my day-job), but being able to use it on a low cost off the shelf board so that I can learn more should be fun. :slight_smile:

2 Likes

Neat! I’ve not used UEFI on ARM yet. What advantages does EFI bring over the classical u-boot (or whatever bootloader) + kernel approach?

The main advantage is you don’t need to doink around with bootloaders. Using UEFI and ACPI makes an ARM board behave just like an x86 desktop or server. You can just take an off the shelf RHEL, Debian, or Ubuntu installer and it’ll just work. UEFI also enables a single disk image to be bootable across many different systems, as long as the kernel has drivers for all those things (distro kernels usually have a tremendous number of modules enabled for this use-case). You don’t need a device tree for each board you want to boot on, ACPI takes care of that as there’s actually a spec and interface format that doesn’t change (unlike device tree).

I’d argue that for a typical embedded product development flow, UEFI and ACPI don’t bring anything to the table over u-boot and device tree. But for things which the customer will treat like a server or desktop, it’s by and far the right way to go, if for no other reason than that’s how everything else does it and people know how to use it.

Unfortunately, the way the Raspberry Pi 4 UEFI works, you have to still stick a bunch of files into the ESP (EFI System Partition) which allow the ROM to properly fetch and execute the UEFI. So the disk itself has to have support for the Raspberry Pi, which is not normal. On a typical UEFI system the ROM support and UEFI itself would live on a separate SPI flash so you can blow away your disk or boot with no disk and still have your UEFI. So the Raspberry Pi UEFI method still has some drawbacks as compared to a normal server or desktop.

1 Like

Thanks, that helps.

Putting the bootloader in SPI flash makes a lot of sense I think for about any system. Then you could have a consistent experience in bootstrapping a system, rather than messing around with every fussy SOC ROM bootloader, special host tools, SD card formats, etc. A SPI flash device is very low cost, so why not …

1 Like

I noticed when my Quickemu machines boot, they are using TianoCore, which appears to be a UEFI implementation.

1 Like

This readme has a list of platforms tianocore EDK supports:

Seems to be mostly high-end devices – not many embedded CPUs I’m familiar with using like TI AMxxxx, or NXP i.MX.

@bradfa Looks a interesting experience, how is the support for multimedia applications (display, video drivers)?

Thanks!

I’m not really sure, sorry. I’ve read that it’s getting better but I expect it won’t work as well as running real Raspbian (or what ever it’s called now).

My use-case for my Raspberry pi is satisfied with a UART console, Ethernet, and USB. I don’t connect the HDMI outputs to anything unless I absolutely have to. My main use case is just to have a quiet armv8 board for Debian packaging work (day-job has loud (for a small office) armv8 boards I support).

Noticed some EFI stuff in u-boot when booting recent Yoe images on the BBB:

U-Boot 2021.01-g316948e851 (Oct 20 2021 - 16:47:40 +0000)

CPU  : AM335X-GP rev 2.0
Model: TI AM335x BeagleBone Black
DRAM:  512 MiB
WDT:   Started with servicing (60s timeout)
NAND:  0 MiB
MMC:   OMAP SD/MMC: 0, OMAP SD/MMC: 1
Loading Environment from FAT... <ethaddr> not set. Validating first E-fuse MAC
Net:   eth2: ethernet@4a100000, eth3: usb_ether
Hit any key to stop autoboot:  0
switch to partitions #0, OK
mmc1(part 0) is current device
Scanning mmc 1:1...
93418 bytes read in 11 ms (8.1 MiB/s)
Scanning disk mmc@48060000.blk...
Disk mmc@48060000.blk not ready
Scanning disk mmc@481d8000.blk...
Found 4 disks
No EFI system partition
BootOrder not defined
EFI boot manager: Cannot load any image
switch to partitions #0, OK
mmc1(part 0) is current device
SD/MMC found on device 1
7361024 bytes read in 488 ms (14.4 MiB/s)
** Bad device specification 1:2 uuid **
93418 bytes read in 10 ms (8.9 MiB/s)
## Flattened Device Tree blob at 88000000
   Booting using the fdt blob at 0x88000000
   Loading Device Tree to 8ffe6000, end 8ffffce9 ... OK
1 Like

Hey . Im new to this and wanted to try the same on RPi , GitHub - pftf/RPi4: Raspberry Pi 4 UEFI Firmware Images this link helped me get to EFI shell but I am unable to get any source to move to the OS , were you able to make this work ? If so can you help me do this ?
P.S : Im very new to UEFI aand ACPI

1 Like

Yep, that’s the right link for the Raspi 4 UEFI. If you can get a UEFI shell then you’re most of the way there. You just need to stick an EFI executable into the β€œremovable” boot location, which for ARM is within the ESP (EFI system partition) on a fat filesystem on a GPT formatted disk at the path EFI/BOOT/BOOTAA64.EFI

Normally Linux distros will mount the ESP within /boot/efi/ so the full path to the location where you need to stick the EFI executable is /boot/efi/EFI/BOOT/BOOTAA64.EFI

1 Like

Hello, can you tell me how to enable ACPI on ARM?

Hello, can you tell me ACPI is enable in which platform ARM ?

If you use the official Raspberry Pi 4 UEFI binaries from GitHub - pftf/RPi4: Raspberry Pi 4 UEFI Firmware Images then everything is already enabled for UEFI and ACPI on that hardware. There’s no need to do anything special.

1 Like

@bradfa Can you format the disk where the UEFI Firmware Image is at to include the correct EFI directories? If so, do you perform that via a partition (i.e., one for UEFI, one for the bootable FAT32 partition, one for the OS ext4)

Yes! :slight_smile:

Although if you’re booting at least the Raspi 4 (and probably the Raspi 5, but I don’t own one yet) you don’t need the normal bootable FAT32 partition, you just need an EFI system partition (ESP) and then an unencrypted partition where the EFI bootloader (like grub or systemd-boot) can grab the kernel and initrd from. Normally on my Raspi 4 I just have a big giant rootfs (/) partition which includes the /boot/ directory where the kernels live (and if you’re using systemd-boot on Debian then your kernels also live in the ESP itself; they’re in /boot/ too because of historical and packaging reasons but this is a bit of a tangent).

For an example of how I do this with debos (Debian disk image builder tool: GitHub - go-debos/debos: Debian OS builder), have a look here: debos-configs/raspberrypi4-uefi-bookworm.yaml at master Β· bradfa/debos-configs Β· GitHub

In that example, I’m using systemd-boot and the Raspi 4 UEFI. Downloading and extracting the UEFI files into the ESP is done here: debos-configs/raspberrypi4-uefi-bookworm.yaml at master Β· bradfa/debos-configs Β· GitHub

Thanks @bradfa - I’ve got a system disk that includes the partitions required by using the debos tool along with the Raspberry Pi 4 config. However, I’m still not getting the UEFI bootloader.

The Pi has the latest firmware (Dec - 2024).

The disk looks like this:

sudo fdisk -l /dev/sdb
Disk /dev/sdb: 29.73 GiB, 31927042048 bytes, 62357504 sectors
Disk model: MassStorageClass
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 9E3AF451-A1FE-434D-AA49-70CDE4BD70EB

Device        Start      End  Sectors  Size Type
/dev/sdb1        34  7812500  7812467  3.7G EFI System
/dev/sdb2   7812501 15625000  7812500  3.7G Linux swap
/dev/sdb3  15625001 31328287 15703287  7.5G Linux root (ARM-64)

sdb1 looks like this

drwxr-xr-x 5 root root 4096 Dec 31  1969 .
drwxr-xr-x 5 root root 4096 Jan 15 13:01 ..
drwxr-xr-x 5 root root 4096 Jan 14 18:01 EFI
drwxr-xr-x 3 root root 4096 Jan 14 18:01 fe191f250b5e4b30881bc8d11e825ad2
drwxr-xr-x 3 root root 4096 Jan 14 18:02 loader

sdb2 is the swap file

sdb3 looks like this

total 48
drwxr-xr-x 1 root root  206 Jan 14 17:43 .
drwxr-xr-x 5 root root 4096 Jan 15 13:01 ..
lrwxrwxrwx 1 root root    7 Jan 14 17:36 bin -> usr/bin
drwxr-xr-x 1 root root  192 Jan 14 18:01 boot
drwxr-xr-x 1 root root  128 Jan 14 17:36 dev
drwxr-xr-x 1 root root 2164 Jan 14 18:02 etc
drwxr-xr-x 1 root root    0 Dec 31 05:25 home
lrwxrwxrwx 1 root root   30 Jan 14 17:43 initrd.img -> boot/initrd.img-6.1.0-30-arm64
lrwxrwxrwx 1 root root   30 Jan 14 17:43 initrd.img.old -> boot/initrd.img-6.1.0-30-arm64
lrwxrwxrwx 1 root root    7 Jan 14 17:36 lib -> usr/lib
drwxr-xr-x 1 root root    0 Jan 14 17:36 media
drwxr-xr-x 1 root root    0 Jan 14 17:36 mnt
drwxr-xr-x 1 root root    0 Jan 14 17:36 opt
drwxr-xr-x 1 root root    0 Dec 31 05:25 proc
drwx------ 1 root root   38 Jan 14 17:38 root
drwxr-xr-x 1 root root   96 Jan 14 17:40 run
lrwxrwxrwx 1 root root    8 Jan 14 17:36 sbin -> usr/sbin
drwxr-xr-x 1 root root    0 Jan 14 17:36 srv
drwxr-xr-x 1 root root    0 Dec 31 05:25 sys
drwxrwxrwt 1 root root    0 Jan 14 17:40 tmp
drwxr-xr-x 1 root root   84 Jan 14 17:36 usr
drwxr-xr-x 1 root root   90 Jan 14 17:36 var
lrwxrwxrwx 1 root root   27 Jan 14 17:43 vmlinuz -> boot/vmlinuz-6.1.0-30-arm64
lrwxrwxrwx 1 root root   27 Jan 14 17:43 vmlinuz.old -> boot/vmlinuz-6.1.0-30-arm64

So, everything looks correct – but it appears the bootloader wants a FAT32 partition. Am I understanding this correctly?

In your EFI system partition, did you download and extract the UEFI firmware files correctly?

The tree view within the EFI system partition should look something like this:

β”œβ”€β”€ 47e6da00cb9d444aab858e342f889b99
β”‚   └── 6.1.0-30-arm64
β”‚       β”œβ”€β”€ initrd.img-6.1.0-30-arm64
β”‚       └── linux
β”œβ”€β”€ bcm2711-rpi-400.dtb
β”œβ”€β”€ bcm2711-rpi-4-b.dtb
β”œβ”€β”€ bcm2711-rpi-cm4.dtb
β”œβ”€β”€ config.txt
β”œβ”€β”€ EFI
β”‚   β”œβ”€β”€ BOOT
β”‚   β”‚   └── BOOTAA64.EFI
β”‚   β”œβ”€β”€ Linux
β”‚   └── systemd
β”‚       └── systemd-bootaa64.efi
β”œβ”€β”€ firmware
β”‚   β”œβ”€β”€ brcm
β”‚   β”‚   β”œβ”€β”€ brcmfmac43455-sdio.bin
β”‚   β”‚   β”œβ”€β”€ brcmfmac43455-sdio.clm_blob
β”‚   β”‚   β”œβ”€β”€ brcmfmac43455-sdio.Raspberry
β”‚   β”‚   └── brcmfmac43455-sdio.txt
β”‚   β”œβ”€β”€ LICENCE.txt
β”‚   └── Readme.txt
β”œβ”€β”€ fixup4.dat
β”œβ”€β”€ loader
β”‚   β”œβ”€β”€ entries
β”‚   β”‚   └── 47e6da00cb9d444aab858e342f889b99-6.1.0-30-arm64.conf
β”‚   β”œβ”€β”€ entries.srel
β”‚   β”œβ”€β”€ loader.conf
β”‚   └── random-seed
β”œβ”€β”€ overlays
β”‚   β”œβ”€β”€ miniuart-bt.dtbo
β”‚   └── upstream-pi4.dtbo
β”œβ”€β”€ Readme.md
β”œβ”€β”€ RPI_EFI.fd
└── start4.elf

12 directories, 24 files

Your output seems to be missing pretty much all of the raspi UEFI firmware files and just have the normal data which one would find in an EFI system partition if the UEFI was stored in a SPI flash, like on a normal x86 box.

Raspi doesn’t have such a SPI flash, so sticks the actual UEFI itself in the EFI system partition, hence the variety of firmware binary blobs and device tree files.