NixOS on ARM/Raspberry Pi 5: Difference between revisions

From NixOS Wiki
m Fix formatting
Nmrose (talk | contribs)
m Remove the comment about NVME/USB not being supported, support was added in v0.3
 
(6 intermediate revisions by 2 users not shown)
Line 13: Line 13:
|-
|-
!Bootloader
!Bootloader
|Custom or UEFI
|Custom, UEFI or u-boot
|-
|-
!Boot order
!Boot order
Line 31: Line 31:
== Status ==
== Status ==


'''NixOS works on Raspberry Pi 5 but is currently experimental'''.
NixOS doesn't run out-of-box, but relies on several tweaks on the boot process that are maintained by different individuals and spread over multiple repositories.


The Raspberry Pi 5's boot process follows the [https://youtu.be/UvFG76qM6co?t=308 typical boot stages on embedded devices], and has the following boot loader steps by default:
  1. ROM -> 2. EEPROM -> Pi-custom Firmware/Kernel -> PiOS (custom Debian)
'''The pain points for NixOS support''' are the Pi's [https://github.com/raspberrypi/rpi-eeprom custom EEPROM boot bootloader], its  [https://github.com/raspberrypi/firmware proprietary, closed-source firmware] (code to use to hardware components) and [https://github.com/raspberrypi/linux its separately maintained Linux kernel], all of which we would need to '''update, build and test constantly and separately''' from the other NixOS Linux kernel variations, '''which is a large, unmaintainable burden for the NixOS community''' when the Pi 5 is not the only supported SoC; so we don't want that.


'''Support for the Raspberry Pi 5 is currently downstream and experimental'''.  
Instead our goal is to '''migrate towards the standard, generic boot process''' with UEFI:
It will not be fully supported until mature support exists in the upstream Linux kernel and
  1. ROM -> 2. EEPROM -> 3. UEFI boot loader -> 4. systemd-boot boot loader -> Generic Kernel -> NixOS
the [https://github.com/u-boot/u-boot U-Boot] boot loader, but using an '''UEFI bootloader already provides a workable solution'''.
We can't affect the ROM and EEPROM boot loaders as they come built-in into the hardware. However, [https://de.wikipedia.org/wiki/Unified_Extensible_Firmware_Interface UEFI] is also used for booting normal Intel/AMD computers, and the [https://www.freedesktop.org/software/systemd/man/latest/systemd-boot.html systemd-boot] boot loader is THE software that allows us to have and select from multiple NixOS generations on boot (and perform rollbacks if we messed up). '''The currently required manual steps are roughly listed further down below''' and require lots of Linux and NixOS understanding.


The Raspberry Pi 5's boot process follows the [https://youtu.be/UvFG76qM6co?si=e9O1s9mS3wpIpEl9&t=308 typical boot stages on embedded devices], some of which have to be adapted to work with NixOS. For that it's helpful to understand more about the stages:
Alternatively, '''if you want to get up-and-running quickly in the mean-time''' there's a setup that '''reuses lots of the pi-custom software''' (non-desired approach but works)
  1. ROM -> 2. EEPROM -> Pi-custom Firmware/Kernel -> NixOS
and creates a hard disk image that you can flash onto an SD card or NVMe SSD. The heavy lifting has been done and is maintained at https://github.com/tstat/raspberry-pi-nix (just follow the example and hints at https://github.com/tstat/raspberry-pi-nix/issues/13) and has the best out-of-the-box experience. You have to remote-build many Nix packages, probably the kernel as well, yourself (e.g. using the [https://wiki.nixos.org/wiki/Distributed_build Pi without NixOS as an intermediate remote builder]) and that can take several hours though.
 
It will also likely get [https://github.com/u-boot/u-boot U-Boot] support soon (likely only interesting for people that need more exotic hardware support like hats):
  1. ROM -> 2. EEPROM -> Pi-custom Firmware/Kernel -> U-Boot boot loader -> NixOS
 
== Raspberry Pi Boot stages ==
To understand the adaptions for NixOS better, it's helpful to understand more about the stages:


1. '''ROM boot loader''': The first-stage boot loader comes "burned in" on the Pi in a tiny
1. '''ROM boot loader''': The first-stage boot loader comes "burned in" on the Pi in a tiny
[https://de.wikipedia.org/wiki/One_Time_Programmable One-Time-Programmable memory (OTP)]
[[wikipedia:Programmable_ROM#One_time_programmable_memory|One-Time-Programmable memory (OTP)]]
so it cannot be changed anymore. It's '''only able to load the next second-stage boot loader below''', and reset it in case you have messed up.
so it cannot be changed anymore. It's '''only able to load the next second-stage boot loader below''', and reset it in case you have messed up.


Line 48: Line 61:




2. '''EEPROM boot loader''': The second-stage boot loader comes built-in on the Pi in a bit larger, rewriteable
2. '''EEPROM boot loader''': The second-stage boot loader comes built-in on the Pi in a larger, rewriteable
[[wikipedia:EEPROM|EEPROM]] memory
[[wikipedia:EEPROM|EEPROM]].
'''This loader is also very limited is only able to search for and start yet another, third-stage boot loader from other '''
'''This loader is also very limited and is only able to search for and start yet another, third-stage boot loader from other '''
storage hardware like an SD card, an NVME SSD''', an USB disk, or from the network.'''
storage hardware like an SD card, an NVMe SSD, a USB disk, or from the network.


This loader (as many other second-stage boot loaders of other devices) is so size-constraint that it only contains  
This loader (like many second-stage boot loaders of other devices) is so size-constrained that it only contains  
the bare mimum code to be able to read from an FAT formatted partition. That's why you see and want a separate small
the bare minimum code to be able to read from an FAT formatted partition. That's why you see and want a separate small
<code>/boot</code> partition on your SD card or SSD that is formatted "FAT" or "VFAT", while your main data is stored on a second
<code>/boot</code> partition on your SD card or SSD that is formatted "FAT" or "VFAT", while your main data is stored on a second
"rootfs" or <code>/</code> partition with fancy, newer partition types like "ext4", "ZFS" or "btrfs".
"rootfs" or <code>/</code> partition with fancy, newer partition types like "ext4", "ZFS" or "btrfs".
Line 64: Line 77:
(also [https://search.nixos.org/packages?channel=unstable&type=packages&query=raspberrypi-eeprom available in Nixpkgs])
(also [https://search.nixos.org/packages?channel=unstable&type=packages&query=raspberrypi-eeprom available in Nixpkgs])
and loads the binary images (the <code>firmware-2712/pieeprom-*.bin</code> files) from the
and loads the binary images (the <code>firmware-2712/pieeprom-*.bin</code> files) from the
[https://github.com/raspberrypi/rpi-eeprom/tree/master/firmware-2712 rpi-eeprom Github project].
[https://github.com/raspberrypi/rpi-eeprom/tree/master/firmware-2712 rpi-eeprom GitHub project].


Nothing to adapt here yet. However, there's a  
Nothing to adapt here yet. However, there's a  
[https://github.com/raspberrypi/firmware/issues/1857 feature request to support smaller
[https://github.com/raspberrypi/firmware/issues/1857 feature request to support smaller third-stage boot loaders in this second-stage].
third-stage boot loaders in this second-stage].


3. '''Firmware boot loader''': The third-stage boot loader is loaded from the first partition (usually called <code>/boot</code>)
3. '''Firmware boot loader''': The third-stage boot loader is loaded from the first partition (usually called <code>/boot</code>)
of an SD card, NVME SSD or other storage hardware described above.
of an SD card, NVME SSD or other storage hardware described above.
Because '''size is usually not an issue here anymore you can have large, fully-fledged boot loaders''' like  
Because '''size is usually not an issue here, you can have large, fully-fledged boot loaders''' like  
[https://www.freedesktop.org/software/systemd/man/latest/systemd-boot.html systemd-boot] (default with NixOS; requires UEFI), or full
[https://www.freedesktop.org/software/systemd/man/latest/systemd-boot.html systemd-boot] (default with NixOS; requires UEFI), or full
[https://github.com/u-boot/u-boot U-Boot] (popular with embedded devices like the Pi) or  
[https://github.com/u-boot/u-boot U-Boot] (popular with embedded devices like the Pi) or  
[https://www.gnu.org/software/grub/ GRUB] (generally popular with Linux Distros).
[https://www.gnu.org/software/grub/ GRUB] (generally popular among Linux distros).


However, '''the standard Pi 5 setup has no third-stage boot loader'''.  
However, '''the standard Pi 5 setup has no third-stage boot loader'''.  
The second stage EEPROM boot loader loads the firmware (code to control other hardware on the Pi 5; [https://en.wikipedia.org/wiki/Devicetree device tree  
The second stage EEPROM boot loader loads the firmware (code to control other hardware on the Pi 5; [https://en.wikipedia.org/wiki/Devicetree device tree files]
files] in compact binary format <code>*.dtb</code>), some settings (<code>cmdline.txt</code> on which partition to find the rest of the system;
in compact binary format <code>*.dtb</code>), some settings (<code>cmdline.txt</code> for kernel settings,
<code>config.txt</code> for general boot settings),
<code>config.txt</code> for firmware settings),
and directly the Linux kernel from a <code>/boot/firmware/</code> folder. On the Pi 5's default Debian image this is
and the Linux kernel itself from a <code>/boot/firmware/</code> folder. On the Pi 5's default Debian image this is
the <code>kernel2712.img</code> (specialized, more-performant kernel
the <code>kernel2712.img</code> (specialized, more-performant kernel
named after the Pi 5's Brodcom BCM2712 ARMv8 SoC chip) or as a fallback the <code>kernel8.img</code> (generic, slower ARMv8 kernel for the Pi 4 that
named after the Pi 5's Brodcom BCM2712 ARMv8 SoC chip) or as a fallback the <code>kernel8.img</code> (generic, slower ARMv8 kernel for the Pi 4 that
also works for Pi 5) that you find on the [https://github.com/raspberrypi/firmware/tree/master/boot Pi Firmware Github project].
also works for Pi 5) that you find on the [https://github.com/raspberrypi/firmware/tree/master/boot Pi firmware GitHub project].


See the [https://www.raspberrypi.com/documentation/computers/raspberry-pi.html#differences-on-raspberry-pi-5 official documentation].
See the
[https://www.raspberrypi.com/documentation/computers/raspberry-pi.html#differences-on-raspberry-pi-5 official documentation].


'''Adaptions for booting NixOS''':
== Setting up a generic UEFI NixOS ==
The task to get a generic NixOS setup requires a


In order to boot NixOS with it's default boot loader systemd-boot we need UEFI support, so replace the
# UEFI boot loader for Pi 5: There exists a WIP [https://github.com/worproject/rpi5-uefi EDK2 for Pi 5 Github project] but with a few limitations see the project for details.
  1. ROM -> 2. EEPROM -> Kernel -> NixOS
# systemd-boot boot loader: Works
workflow with third-stage and fourth-stage boot loaders (both as firmware on an SD card or NVME SSD etc.)
# generic Linux kernel that works for the Pi 5's ARM v8 processor and hardware: An almost generic Pi 5 compatible kernel exists [https://github.com/NixOS/nixos-hardware/blob/master/raspberry-pi/5/default.nix at the NixOS-hardware repository]; it's an adaption from a kernel for the Pi 4)
  1. ROM -> 2. EEPROM -> 3. EDK2 (UEFI boot loader) -> 4. systemd-boot -> Kernel -> NixOS
as follows:


1. '''Install EDK2''':
  1. ROM -> 2. EEPROM -> 3. UEFI boot loader (EDK2) -> 4. systemd-boot boot loader -> Pi 4/5-adapted NixOS Kernel -> NixOS
1. '''Install EDK2''' (UEFI firmware implementation):


We need the first partition of the SD card (or NVME SSD, etc.) again to be formatted as FAT
We need the first partition of the SD card (or NVMe SSD, etc.) again to be formatted as FAT
but labelled <code>ESP</code> (EFI System Partition) to conform to (U)EFI standards.
but marked as an ESP (EFI System Partition) to conform to (U)EFI standards.
Into this partition we need to place the EDK2 boot loader file <code>RPI_EFI.fd</code>
In this partition we need to place the EDK2 firmware file <code>RPI_EFI.fd</code>
and a <code>config.txt</code> file with a line <code>armstub=RPI_EFI.fd</code>
and a <code>config.txt</code> file with a line <code>armstub=RPI_EFI.fd</code>
which instructs the EEPROM boot loader to load our EDK2 boot loader instead.
which instructs the EEPROM boot loader to load EDK2 instead of a Linux loader stub.


See the [https://github.com/worproject/rpi5-uefi EDK2 for Pi 5 Github project]; the releases already contain both of these files.
See the [https://github.com/worproject/rpi5-uefi EDK2 for Pi 5 Github project]; the releases already contain both of these files.
Line 110: Line 123:
2. '''Install systemd-boot, kernel and NixOS''':
2. '''Install systemd-boot, kernel and NixOS''':


The rest is usual NixOS installation on a second partition with the caveat to '''select a Linux kernel that supports the Pi 5''';
The rest is a usual NixOS installation on a second partition with the caveat to '''select a Linux kernel that supports the Pi 5''' like the [https://github.com/NixOS/nixos-hardware/pull/927 Pi 5 compatible Linux kernel is available in nixos-hardware].
a suitable kernel can be created using [https://gitlab.com/vriska/nix-rpi5/-/blob/main/linux-rpi.nix leo60228's flake] until
that [https://github.com/NixOS/nixpkgs/pull/284391 Pi 5 compatible Linux kernel is available in Nixos-hardware].


Follow [https://github.com/NixOS/nixpkgs/issues/260754#issuecomment-1936211154 this guide] to build
Follow [https://github.com/NixOS/nixpkgs/issues/260754#issuecomment-1936211154 this guide] to build
Line 120: Line 131:
and the rest of the NixOS system into your second partition.
and the rest of the NixOS system into your second partition.


Note that building that NixOS system closure has to happen natively, e.g. on a similar aarch64/Arm64 system like newer Macs (fast), or with
== Alternative board-specific installation notes ==
the [https://docs.kernel.org/admin-guide/binfmt-misc.html binfmt] kernel feature
(enabled with setting <code>boot.binfmt.emulatedSystems = [ "aarch64-linux" ];</code>) using QEMU virtualization
on any NixOS computer(veeeeerry slow) 
 
Missing:
 
# How to do faster cross-compilation without binfmt.
# How to create a convenient SD card image to not install anything manually.
# How to install U-Boot instead of EDK2 and systemd-boot.
 
=== GPU ===
For the GPU drivers to work, <code>dtoverlay=vc4-kms-v3d-pi5</code> must be added to <code>/boot/config.txt</code>, and the vendor kernel must currently be used. Only Wayland-based compositors are supported. Note that Xwayland applications may produce broken graphics on KDE; the root cause of this issue has not yet been evaluated.
 
== Board-specific installation notes ==
 
First, install EDK2, following the [https://github.com/worproject/rpi5-uefi#getting-started instructions from the port README]. With EDK2 installed as the Platform Firmware, you can follow the [[NixOS_on_ARM/UEFI|standard instructions for UEFI on ARM]].
First, install EDK2, following the [https://github.com/worproject/rpi5-uefi#getting-started instructions from the port README]. With EDK2 installed as the Platform Firmware, you can follow the [[NixOS_on_ARM/UEFI|standard instructions for UEFI on ARM]].


Line 146: Line 142:
</nowiki>}}
</nowiki>}}


For the vendor kernel to boot properly, you must switch from ACPI to Device Tree in the UEFI settings (at Device Manager -> Raspberry Pi Configuration -> ACPI / Device Tree -> System Table Mode). When using the vendor kernel (which provides full power management support), you may additionally wish to remove <code>force_turbo=1</code> from <code>/boot/config.txt</code>.
For the vendor kernel to boot properly, you must switch from ACPI to Device Tree in the UEFI settings (at Device Manager Raspberry Pi Configuration ACPI / Device Tree System Table Mode). When using the vendor kernel (which provides full power management support), you may additionally wish to remove <code>force_turbo=1</code> from <code>/boot/config.txt</code>.


If you are using nixos-unstable, then you can also use the rpi4 kernel (this is supposed to be a generic aarch64 kernel for rpi 3,4,5). Although, due to a smaller page size, this will have slightly worse performance:
If you are using nixos-unstable, then you can also use the rpi4 kernel (which is a generic aarch64 kernel for Pi 3 and later models). Although, due to a smaller page size, this will have slightly worse performance:
{{file|/etc/nixos/configuration.nix|nix|<nowiki>
{{file|/etc/nixos/configuration.nix|nix|<nowiki>
{
{
Line 154: Line 150:
}
}
</nowiki>}}
</nowiki>}}
== Troubleshooting ==
=== GPU ===
For the GPU drivers to work, <code>dtoverlay=vc4-kms-v3d-pi5</code> must be added to <code>/boot/config.txt</code>, and the vendor kernel must currently be used. Only Wayland-based compositors are supported without additional configuration (see the nixos-hardware PR linked previously). Note that Xwayland applications may produce broken graphics on KDE; the root cause of this issue has not yet been evaluated.
The rpi5-uefi download does not include overlays. You can get them by copying the <code>boot/overlays</code> folder from [https://github.com/raspberrypi/firmware the firmware repository] to <code>/boot</code> (so that <code>/boot/overlays/vc4-kms-v3d-pi5.dtbo</code> is available).


=== Bluetooth ===
=== Bluetooth ===
If your bluetooth doesn't show up, and you are getting errors in dmesg regarding the serial port at 107050c00, add the following to your nixos configuration:{{file|/etc/nixos/configuration.nix|nix|<nowiki>
If your Bluetooth doesn't show up, and you are getting errors in dmesg regarding the serial port at 107050c00, add the following to your NixOS configuration:{{file|/etc/nixos/configuration.nix|nix|<nowiki>
{
{
   boot.kernelParams = [ "8250.nr_uarts=11" "console=ttyAMA10,9600" "console=tty0"];
   boot.kernelParams = [ "8250.nr_uarts=11" "console=ttyAMA10,9600" "console=tty0"];
}
}
</nowiki>}}
</nowiki>}}
== Using the Pi 5 as a remote builder to build native ARM packages for the Pi 5 ==
Building an NixOS system image that can be flashed to an SD card or NVMe SSD requires to '''build ARM binaries''', more specifically for the <code>"aarch64-linux"</code>platform. From a typical Intel/AMD computer we can either
* '''emulated native compile using QEMU''' virtualization by enabling the [https://docs.kernel.org/admin-guide/binfmt-misc.html binfmt] kernel feature on NixOS configuration setting <code>boot.binfmt.emulatedSystems = [ "aarch64-linux" ];</code>). This can be fast if everything is downloaded pre-compiled from the cache.nixos.org cache and only few packages really need local compilation. In reality it can be extremely slow, e.g. compiling a Linux kernel alone can take days.
* '''cross-compile''' to ARM using as to happen natively, but nothing will be cached from cache.nixos.org as this is not pre-build. So the compile itself is fast but there will be a lot more to compile locally. In practice it's quite fragile, because you may encounter packages that don't really support cross-compilation get stuck.
* '''native compile on an remote builder''' like the Pi 5 itself running its custom Debian Linux at the beginning or later NixOS. This is quite simple to setup and reasonably fast as most packages are pre-build and cached on cache.nixos.org, and building a remaining Linux kernel only takes 2-3h on the Pi 5.
'''Setting up the Pi 5 as a remote native builder''' can be done following the steps at [[Distributed build|https://wiki.nixos.org/wiki/Distributed_build]]. The rough steps are as follows:
# '''Install the Nix package manager''' on Pi 5 Debian OS the normal, multi-user way with <code>sh <(curl -L <nowiki>https://nixos.org/nix/install</nowiki>) --daemon</code>. If you already have NixOS running on the Pi 5, then you can skip this step.
# '''Setup a <code>ssh</code> connection''' from your local machine to the Pi, especially adding <code>SetEnv PATH=/nix/var/nix/profiles/default/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin</code> to the Pi's <code>/etc/ssh/sshd_config</code> file. If you already have NixOS running on the Pi 5, then you can skip this step.
# '''Make the remote Pi known to you local computer''' by adding it as a <code>nix.buildMachines</code> entry to your  <code>/etc/nix/configuration.nix</code> file and use connection protocol <code>ssh-ng</code>(!).
# You can then '''build, e.g. an NixOS sd card image''' with a call similar to  <code>nix build .\#nixosConfigurations.pi5.config.system.build.sdImage</code>
# '''flash that resulting image onto an SD card''' or NVMe SSD using a call similar to <code>zstdcat result/sd-image/nixos-sd-image-23.11.20230703.ea4c80b-aarch64-linux.img.zst | sudo dd of=/dev/mmcblk0 bs=100M status=progress</code> and place that card into the Pi 5.
Missing:
# How to do cross-compilation.
== Deploy and Update the Pi 5 NixOS system once it's running NixOS ==
Once the Pi 5 is running NixOS, you can update it with newer NixOS system configurations using e.g. the usual  <code>nix-rebuild</code> 
tool with a call similar to
<code>nixos-rebuild --flake .#pi5 --build-host piuser@pi5 --target-host piuser@pi5 --use-remote-sudo switch</code>
that uses the SSH connection from the remote builder section.
See [https://nixcademy.com/2023/08/10/nixos-rebuild-remote-deployment/ this guide] for a good explanation of this terminal call.

Latest revision as of 14:48, 24 August 2024

Raspberry Pi 5 Family
A Raspberry Pi 5.
Manufacturer Raspberry Pi Foundation
Architecture AArch64
Bootloader Custom, UEFI or u-boot
Boot order Configurable; SD, USB, Netboot
Maintainer leo60228
Raspberry Pi 5B
SoC BCM2712

The Raspberry Pi family of devices is a series of single-board computers made by the Raspberry Pi Foundation. They are all based on Broadcom System-on-a-chip (SoCs).

Status

NixOS works on Raspberry Pi 5 but is currently experimental. NixOS doesn't run out-of-box, but relies on several tweaks on the boot process that are maintained by different individuals and spread over multiple repositories.

The Raspberry Pi 5's boot process follows the typical boot stages on embedded devices, and has the following boot loader steps by default:

 1. ROM -> 2. EEPROM -> Pi-custom Firmware/Kernel -> PiOS (custom Debian)

The pain points for NixOS support are the Pi's custom EEPROM boot bootloader, its proprietary, closed-source firmware (code to use to hardware components) and its separately maintained Linux kernel, all of which we would need to update, build and test constantly and separately from the other NixOS Linux kernel variations, which is a large, unmaintainable burden for the NixOS community when the Pi 5 is not the only supported SoC; so we don't want that.

Instead our goal is to migrate towards the standard, generic boot process with UEFI:

 1. ROM -> 2. EEPROM -> 3. UEFI boot loader -> 4. systemd-boot boot loader -> Generic Kernel -> NixOS

We can't affect the ROM and EEPROM boot loaders as they come built-in into the hardware. However, UEFI is also used for booting normal Intel/AMD computers, and the systemd-boot boot loader is THE software that allows us to have and select from multiple NixOS generations on boot (and perform rollbacks if we messed up). The currently required manual steps are roughly listed further down below and require lots of Linux and NixOS understanding.

Alternatively, if you want to get up-and-running quickly in the mean-time there's a setup that reuses lots of the pi-custom software (non-desired approach but works)

 1. ROM -> 2. EEPROM -> Pi-custom Firmware/Kernel -> NixOS

and creates a hard disk image that you can flash onto an SD card or NVMe SSD. The heavy lifting has been done and is maintained at https://github.com/tstat/raspberry-pi-nix (just follow the example and hints at https://github.com/tstat/raspberry-pi-nix/issues/13) and has the best out-of-the-box experience. You have to remote-build many Nix packages, probably the kernel as well, yourself (e.g. using the Pi without NixOS as an intermediate remote builder) and that can take several hours though.

It will also likely get U-Boot support soon (likely only interesting for people that need more exotic hardware support like hats):

 1. ROM -> 2. EEPROM -> Pi-custom Firmware/Kernel -> U-Boot boot loader -> NixOS

Raspberry Pi Boot stages

To understand the adaptions for NixOS better, it's helpful to understand more about the stages:

1. ROM boot loader: The first-stage boot loader comes "burned in" on the Pi in a tiny One-Time-Programmable memory (OTP) so it cannot be changed anymore. It's only able to load the next second-stage boot loader below, and reset it in case you have messed up.

See the official documentation.

Nothing to adapt here.


2. EEPROM boot loader: The second-stage boot loader comes built-in on the Pi in a larger, rewriteable EEPROM. This loader is also very limited and is only able to search for and start yet another, third-stage boot loader from other storage hardware like an SD card, an NVMe SSD, a USB disk, or from the network.

This loader (like many second-stage boot loaders of other devices) is so size-constrained that it only contains the bare minimum code to be able to read from an FAT formatted partition. That's why you see and want a separate small /boot partition on your SD card or SSD that is formatted "FAT" or "VFAT", while your main data is stored on a second "rootfs" or / partition with fancy, newer partition types like "ext4", "ZFS" or "btrfs".

See the official documentation.

See EEPROM image releases for improved and wider hardware support. This boot loader can be updated via the rpi-eeprom-update terminal tool (also available in Nixpkgs) and loads the binary images (the firmware-2712/pieeprom-*.bin files) from the rpi-eeprom GitHub project.

Nothing to adapt here yet. However, there's a feature request to support smaller third-stage boot loaders in this second-stage.

3. Firmware boot loader: The third-stage boot loader is loaded from the first partition (usually called /boot) of an SD card, NVME SSD or other storage hardware described above. Because size is usually not an issue here, you can have large, fully-fledged boot loaders like systemd-boot (default with NixOS; requires UEFI), or full U-Boot (popular with embedded devices like the Pi) or GRUB (generally popular among Linux distros).

However, the standard Pi 5 setup has no third-stage boot loader. The second stage EEPROM boot loader loads the firmware (code to control other hardware on the Pi 5; device tree files in compact binary format *.dtb), some settings (cmdline.txt for kernel settings, config.txt for firmware settings), and the Linux kernel itself from a /boot/firmware/ folder. On the Pi 5's default Debian image this is the kernel2712.img (specialized, more-performant kernel named after the Pi 5's Brodcom BCM2712 ARMv8 SoC chip) or as a fallback the kernel8.img (generic, slower ARMv8 kernel for the Pi 4 that also works for Pi 5) that you find on the Pi firmware GitHub project.

See the official documentation.

Setting up a generic UEFI NixOS

The task to get a generic NixOS setup requires a

  1. UEFI boot loader for Pi 5: There exists a WIP EDK2 for Pi 5 Github project but with a few limitations see the project for details.
  2. systemd-boot boot loader: Works
  3. generic Linux kernel that works for the Pi 5's ARM v8 processor and hardware: An almost generic Pi 5 compatible kernel exists at the NixOS-hardware repository; it's an adaption from a kernel for the Pi 4)
 1. ROM -> 2. EEPROM -> 3. UEFI boot loader (EDK2) -> 4. systemd-boot boot loader -> Pi 4/5-adapted NixOS Kernel -> NixOS

1. Install EDK2 (UEFI firmware implementation):

We need the first partition of the SD card (or NVMe SSD, etc.) again to be formatted as FAT but marked as an ESP (EFI System Partition) to conform to (U)EFI standards. In this partition we need to place the EDK2 firmware file RPI_EFI.fd and a config.txt file with a line armstub=RPI_EFI.fd which instructs the EEPROM boot loader to load EDK2 instead of a Linux loader stub.

See the EDK2 for Pi 5 Github project; the releases already contain both of these files.

See a guide on how to setup partitions and these files.

2. Install systemd-boot, kernel and NixOS:

The rest is a usual NixOS installation on a second partition with the caveat to select a Linux kernel that supports the Pi 5 like the Pi 5 compatible Linux kernel is available in nixos-hardware.

Follow this guide to build a NixOS system closure that you can install manually onto the Pi with a nixos-install call. That install tool will install the systemd-boot loader at /boot/EFI/systemd/systemd-bootaa64.efi and the kernel files at /boot/EFI/nixos/*.efi onto your first ESP partition and the rest of the NixOS system into your second partition.

Alternative board-specific installation notes

First, install EDK2, following the instructions from the port README. With EDK2 installed as the Platform Firmware, you can follow the standard instructions for UEFI on ARM.

EDK2 enables booting a mainline kernel, but hardware support will be very limited. Notably, you'll need to perform the installation using Wi-Fi, as Ethernet is unsupported. Once the system is installed, you can switch to the vendor's modified kernel. This is not (yet?) available in Nixpkgs, so you'll need to get it from a flake. If you're not using flakes, you can simply add this to your configuration:

/etc/nixos/configuration.nix
{
  boot.kernelPackages = (import (builtins.fetchTarball https://gitlab.com/vriska/nix-rpi5/-/archive/main.tar.gz)).legacyPackages.aarch64-linux.linuxPackages_rpi5;
}

For the vendor kernel to boot properly, you must switch from ACPI to Device Tree in the UEFI settings (at Device Manager → Raspberry Pi Configuration → ACPI / Device Tree → System Table Mode). When using the vendor kernel (which provides full power management support), you may additionally wish to remove force_turbo=1 from /boot/config.txt.

If you are using nixos-unstable, then you can also use the rpi4 kernel (which is a generic aarch64 kernel for Pi 3 and later models). Although, due to a smaller page size, this will have slightly worse performance:

/etc/nixos/configuration.nix
{
  boot.kernelPackages = pkgs.linuxPackages_rpi4;
}

Troubleshooting

GPU

For the GPU drivers to work, dtoverlay=vc4-kms-v3d-pi5 must be added to /boot/config.txt, and the vendor kernel must currently be used. Only Wayland-based compositors are supported without additional configuration (see the nixos-hardware PR linked previously). Note that Xwayland applications may produce broken graphics on KDE; the root cause of this issue has not yet been evaluated.

The rpi5-uefi download does not include overlays. You can get them by copying the boot/overlays folder from the firmware repository to /boot (so that /boot/overlays/vc4-kms-v3d-pi5.dtbo is available).

Bluetooth

If your Bluetooth doesn't show up, and you are getting errors in dmesg regarding the serial port at 107050c00, add the following to your NixOS configuration:

/etc/nixos/configuration.nix
{
  boot.kernelParams = [ "8250.nr_uarts=11" "console=ttyAMA10,9600" "console=tty0"];
}

Using the Pi 5 as a remote builder to build native ARM packages for the Pi 5

Building an NixOS system image that can be flashed to an SD card or NVMe SSD requires to build ARM binaries, more specifically for the "aarch64-linux"platform. From a typical Intel/AMD computer we can either

  • emulated native compile using QEMU virtualization by enabling the binfmt kernel feature on NixOS configuration setting boot.binfmt.emulatedSystems = [ "aarch64-linux" ];). This can be fast if everything is downloaded pre-compiled from the cache.nixos.org cache and only few packages really need local compilation. In reality it can be extremely slow, e.g. compiling a Linux kernel alone can take days.
  • cross-compile to ARM using as to happen natively, but nothing will be cached from cache.nixos.org as this is not pre-build. So the compile itself is fast but there will be a lot more to compile locally. In practice it's quite fragile, because you may encounter packages that don't really support cross-compilation get stuck.
  • native compile on an remote builder like the Pi 5 itself running its custom Debian Linux at the beginning or later NixOS. This is quite simple to setup and reasonably fast as most packages are pre-build and cached on cache.nixos.org, and building a remaining Linux kernel only takes 2-3h on the Pi 5.

Setting up the Pi 5 as a remote native builder can be done following the steps at https://wiki.nixos.org/wiki/Distributed_build. The rough steps are as follows:

  1. Install the Nix package manager on Pi 5 Debian OS the normal, multi-user way with sh <(curl -L https://nixos.org/nix/install) --daemon. If you already have NixOS running on the Pi 5, then you can skip this step.
  2. Setup a ssh connection from your local machine to the Pi, especially adding SetEnv PATH=/nix/var/nix/profiles/default/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin to the Pi's /etc/ssh/sshd_config file. If you already have NixOS running on the Pi 5, then you can skip this step.
  3. Make the remote Pi known to you local computer by adding it as a nix.buildMachines entry to your /etc/nix/configuration.nix file and use connection protocol ssh-ng(!).
  4. You can then build, e.g. an NixOS sd card image with a call similar to nix build .\#nixosConfigurations.pi5.config.system.build.sdImage
  5. flash that resulting image onto an SD card or NVMe SSD using a call similar to zstdcat result/sd-image/nixos-sd-image-23.11.20230703.ea4c80b-aarch64-linux.img.zst | sudo dd of=/dev/mmcblk0 bs=100M status=progress and place that card into the Pi 5.

Missing:

  1. How to do cross-compilation.

Deploy and Update the Pi 5 NixOS system once it's running NixOS

Once the Pi 5 is running NixOS, you can update it with newer NixOS system configurations using e.g. the usual nix-rebuild

tool with a call similar to

nixos-rebuild --flake .#pi5 --build-host piuser@pi5 --target-host piuser@pi5 --use-remote-sudo switch

that uses the SSH connection from the remote builder section.

See this guide for a good explanation of this terminal call.