NixOS on ARM
The support level for ARM overall varies depending on the architecture and the specific ecosystems and boards.
The way the ARM integration is built into NixOS is by making generic builds the first-class citizens. This means that as soon as there is upstream support for the board in the kernel and platform firmware, NixOS should work once those are updated.
It is still possible, when needed, to build and use a customized platform firmware and kernel for specific boards[reference needed].
At this moment in time (early 2024) only AArch64 has full support upstream. With that said, neither armv6l or armv7l are being ignored, fixes are worked on and approved as needed. What's missing is support and builds being maintained in binary form. At the time of writing, no publicly available caches for armv6l or armv7l are available.
For images links, including UEFI install, skip to the Installation section.
Supported devices
Table legend:
- SoC - https://en.wikipedia.org/wiki/System_on_a_chip
- ISA - https://en.wikipedia.org/wiki/Instruction_set_architecture
Upstream (NixOS) supported devices
NixOS has support for these boards using AArch64 architecture on the nixpkgs-unstable and stable channel.
Support for those board assumes as much is supported as Mainline Linux supports.
Manufacturer | Board | SoC | ISA | CPU | RAM | Storage |
---|---|---|---|---|---|---|
Raspberry Pi Foundation | Raspberry Pi 3 | Broadcom BCM2837 | AArch64 / ARMv7 | 4× Cortex-A53 @ 1.2 - 1.4 GHz | 1 GB | SD/microSD |
Raspberry Pi Foundation | Raspberry Pi 4 | Broadcom BCM2711 | AArch64 / ARMv7 | 4× Cortex-A72 @ 1.5 - 1.8 GHz | 1-8 GB | microSD, eMMC |
Community supported devices
These boards are not routinely verified as working.
The baseline support level expected is “Just as much as mainline Linux and U-Boot supports them”, except if specified otherwise.
Manufacturer | Board | SoC | ISA | CPU | RAM | Storage |
---|---|---|---|---|---|---|
Apple | Apple Silicon Macs | M1/M1 Pro/M1 Max | AArch64 | — | — | NVMe |
ASUS | Tinker Board | Rockchip RK3288 | ARMv7 | 4× Cortex-A17 | 2 GB | microSD |
Banana Pi | Banana Pi | Allwinner A20 | ARMv7 | 2× Cortex-A7 | 1 GB | SD, SATA |
Banana Pi M64 | Banana Pi M64 | Allwinner A64 | ARMv8 | 4× Cortex-A53 | 2 GB | microSD, 8GB eMMc |
Banana Pi BPI-M5 | Banana Pi BPI-M5 | Amlogic S905X3 | ARMv8.2 | 4× Cortex-A55 | 4 GB LPDDR4 | microSD, 16G eMMC |
BeagleBoard.org | BeagleBone Black | TI AM335x (src) | ARMv7 | 1× Cortex-A8 @ 1 GHz | 512 MB | 4 GB eMMC, microSD |
Firefly | AIO-3399C | Rockchip RK3399 | AArch64 | 2× Cortex-A72 @ 2.0 GHz, 4× Cortex-A53 @ 1.5 Ghz | 2/4 GB | 8/16 GB eMMC, microSD |
FriendlyElec | NanoPC-T4 | Rockchip RK3399 | AArch64 | 2× Cortex-A72 @ 2.0 GHz, 4× Cortex-A53 @ 1.5 Ghz | 4 GB | 16 GB eMMC, microSD, NVMe |
FriendlyElec | NanoPi-M4 | Rockchip RK3399 | AArch64 | 2× Cortex-A72 @ 2.0 GHz, 4× Cortex-A53 @ 1.5 Ghz | 4 GB | optional eMMC, microSD |
FriendlyElec | NanoPi-R6C | Rockchip RK3588S | AArch64 | 4× ARM Cortex-A76 @ 2.4 GHz, 4× Cortex-A55 @ 1.8 Ghz | 4 GB / 8 GB | optional eMMC, microSD, NVMe |
Hardkernel | ODROID-HC1 & ODROID-HC2 | Samsung Exynos 5422 | ARMv7 | 4× Cortex-A15 @ 2GHz, 4× Cortex-A7 @ 1.4GHz | 2 GB | microSD |
Hardkernel | ODROID-C2 | Amlogic S905 | AArch64 | 4× Cortex-A53 @ 1.5GHz | 2 GB | eMMC, microSD |
Hardkernel | ODROID-HC4 | Amlogic S905X3 | AArch64 | 4× Cortex-A55 @ 1.8GHz | 4 GB | microSD, SATA |
Kosagi | Kosagi Novena | i.MX6 | ARMv7 | 4× Cortex-A9 @ 1.2 GHz | 4 GB | microSD, SATA |
Libre Computer | ROC-RK3399-PC | Rockchip RK3399 | AArch64 | 2× Cortex-A72 @ 2.0 GHz, 4× Cortex-A53 @ 1.5 Ghz | 4 GB | eMMC, microSD, NVMe |
Libre Computer | ROC-RK3328-CC | Rockchip RK3328 | AArch64 | 4× Cortex-A53 @ 1.4GHz | 4 GB | eMMC, microSD |
Libre Computer | AML-S905X-CC-V2 | Amlogic S905X | AArch64 | 4× Cortex-A53 @ 1.512 GHz | 1/2GB | eMMC, microSD |
Linksprite | pcDuino3 Nano | Allwinner A20 | ARMv7 | 2× Cortex-A7 @ 1 GHz | 1 GB | 4 GB NAND, microSD, SATA |
NVIDIA | Jetson TK1 | Tegra K1/T124 | ARMv7 | 4× Cortex-A15 @ 2.3 GHz | 2 GB | 16 GB eMMC, SD, SATA |
NXP | i.MX 8M Plus EVK | i.MX 8M Plus | AArch64 | 4× Cortex-A53 @ 1.8 Ghz | 6 GB | 32 GB eMMC, microSD |
NXP | i.MX 8M Quad EVK | i.MX 8M Quad | AArch64 | 4× Cortex-A53 @ 1.5 Ghz + 1× Cortex-M4 | 3 GB | 16 GB eMMC, microSD |
OLIMEX | Teres-A64 | AllWinner A64 | AArch64 | 4× Cortex-A53 @ 1.1 GHz | 2GB | 16 GB eMMC, microSD |
Orange Pi | Orange Pi One | Allwinner H3 | ARMv7 | 4× Cortex-A7 @ 1.2 GHz | 512 MB | microSD |
Orange Pi | Orange Pi PC | Allwinner H3 | ARMv7 | 4× Cortex-A7 @ 1.6 GHz | 1 GB | SD/microSD |
Orange Pi | Orange Pi Zero Plus2 (H5) | Allwinner H5 | AArch64 | 4× Cortex-A53 @ 1.2 GHz | 1 GB | SD/microSD + 8GB eMMC |
Orange Pi | Orange Pi Zero2 (H616) | Allwinner H616 | AArch64 | 4× Cortex-A53 @ 1.2 GHz | 1 GB | SD/microSD + 2MB SPI Flash |
Orange Pi | Orange Pi R1 Plus LTS | Rockchip RK3328 | AArch64 | 4× Cortex-A53 @ 1.5 GHz | 1 GB | microSD |
Orange Pi | Orange Pi 5 | Rockchip RK3588s | AArch64 | 4× Cortex-A76 @ 2.4GHz, 4×Cortex-A55 @ 1.8 GHz | 4/8/16 GB | microSD, NVMe |
Orange Pi | Orange Pi 5 Plus | Rockchip RK3588 | AArch64 | 4× Cortex-A76 @ 2.4GHz, 4×Cortex-A55 @ 1.8 GHz | 4/8/16 GB | eMMC, microSD, NVMe |
PINE64 | PINE A64-LTS | Allwinner R18 | AArch64 | 4× Cortex-A53 @ ? GHz | 2 GB | microSD & eMMC |
PINE64 | Pinebook | Allwinner A64 | AArch64 | 4× Cortex-A53 @ ? Ghz | 2 GB | microSD & eMMC |
PINE64 | Pinebook Pro | Rockchip RK3399 | AArch64 | 2× Cortex-A72 @ 2.0 GHz, 4× Cortex-A53 @ 1.5 Ghz | 4 GB | microSD & eMMC |
PINE64 | ROCK64 | Rockchip RK3328 | AArch64 | 4× Cortex-A53 @ 1.5 GHz | 1/2/4 GB | microSD/eMMC |
PINE64 | ROCKPro64 | Rockchip RK3399 | AArch64 | 2× Cortex-A72 @ 2.0 GHz, 4× Cortex-A53 @ 1.5 Ghz | 2/4 GB | microSD/eMMC |
Clockworkpi | uConsole A06 | Rockchip RK3399 | AArch64 | 2× Cortex-A72 @ 2.0 GHz, 4× Cortex-A53 @ 1.5 Ghz | 4 GB | microSD |
Radxa | ROCK5 Model B | Rockchip RK3588 | AArch64 | 4× Cortex-A76 @ 2.4GHz, 4×Cortex-A55 @ 1.8 GHz | 4/8/16 GB | eMMC, microSD, NVMe |
Radxa | ROCK5 Model A | Rockchip RK3588s | AArch64 | 4× Cortex-A76 @ 2.4GHz, 4×Cortex-A55 @ 1.8 GHz | 4/8/16 GB | eMMC, microSD, NVMe |
Raspberry Pi Foundation | Raspberry Pi | Broadcom BCM2835 | ARMv6 | 1 × ARM1176 @ 700 MHz | 256 MB / 512 MB | SD/microSD |
Raspberry Pi Foundation | Raspberry Pi 2 | Broadcom BCM2836 | ARMv7 | 4× Cortex-A7 @ 900 MHz | 1 GB | SD/microSD |
Raspberry Pi Foundation | Raspberry Pi 3 | Broadcom BCM2837 | AArch64 / ARMv7 | 4× Cortex-A53 @ 1.2 GHz | 1 GB | SD/microSD |
Raspberry Pi Foundation | Raspberry Pi 4 | Broadcom BCM2711 | AArch64 / ARMv7 | 4× Cortex-A53 @ 1.5 GHz | 1-8 GB | microSD |
Raspberry Pi Foundation | Raspberry Pi 5 | Broadcom BCM2712 | AArch64 | 4× Cortex-A76 @ 2.4 GHz | 4-8 GB | microSD |
Toshiba | AC100 (mini laptop) | Tegra 2 250 (T20) | ARMv7 | 2× Cortex-A9 @ 1 GHz | 512 MB | 8–32 GB eMMC, SD |
Wandboard | Wandboard Solo/Dual/Quad | Freescale i.MX6 | ARMv7 | 1×/2×/4× Cortex-A9 @ 1000 MHz | 512 MB / 1 GB / 2 GB | microSD, SATA |
Special Devices
It is possible to emulate an ARM platform with QEMU.
Manufacturer | Board | SoC | ISA | CPU | RAM | Storage |
---|---|---|---|---|---|---|
QEMU | QEMU | — | ARMv7 | up to 8 | up to 2 GB | Anything QEMU supports |
Installation
Getting the installer
UEFI iso
Continue to the UEFI page.
SD card images (SBCs and similar platforms)
For AArch64
it is possible to download images from Hydra.
On the page click on the latest successful build to get a download link under build products.
If the image has the extension .zst
, it will need to be decompressed before writing to installation device. Use nix-shell -p zstd --run "unzstd <img-name>.img.zst"
to decompress the image.
Installation steps
The .img files can be directly written to a microSD/SD card (minimal recommended size: 4 GB) using dd, once uncompressed from the ZSTD container. The SD card needs to be unmounted first.
Once the NixOS image file is downloaded, run the following command to install the image onto the SD Card, replace /dev/mmcblk0
with the path to the SD card (use dmesg
to find it out).
sudo dd if=nixos-sd-image-23.05pre482417.9c7cc804254-aarch64-linux.img of=/dev/mmcblk0
This should be enough to get you started, you may now boot your device for the first time.
The base images are configured to boot up with a serial TTY ( RX/TX UART ) @ 115200 Baud. That way you not necessarily have to have a HDMI Display and keyboard.
Continue with #NixOS installation & configuration.
Binary cache
AArch64
The official NixOS Hydra instance builds a full set of binaries (available on https://cache.nixos.org) for the AArch64 architecture on the nixpkgs-unstable and stable channels.
armv6l and armv7l
Some users have provided best effort caches for 32 bit ARM, but none are currently available.
Installer image with custom U-Boot
The Mic92/nixos-aarch64-images repository provides a mechanism to modify the official NixOS installer to embed the board-specific U-Boot firmware required for different boards. This method does not require QEMU or native ARM builds since the existing Hydra-built U-Boot binaries are used.
Enable UART
If you try to use UART to log on NixOS, you might hang on the line "Starting kernel ...". To enable UART, you will need to add at the end of the line that contains loglevel4
in the file /extlinux/extlinux.conf
the text:
/extlinux/extlinux.conf
console=ttyAMA0,115200n8
/extlinux/extlinux.conf
console=ttyS0,115200n8
The actual device (ttyAMA0
, ttyS0
, ttyS1
) will depend on the hardware.
NixOS installation & configuration
The installation image is actually a MBR partition table plus two partitions; a FAT16 /boot and a ext4 root filesystem. The image is designed such that it's possible to directly reuse the SD image's partition layout and "install" NixOS on the very same SD card by simply replacing the default configuration.nix and running nixos-rebuild. Using this installation method is strongly recommended, though if you know exactly what you're doing and how U-Boot on your board works, you can use nixos-install as usual. To help with the SD card installation method, the boot scripts on the image automatically resize the rootfs partition to fit the SD card on the first boot.
- To generate a default
/etc/nixos/configuration.nix
file, runsudo nixos-generate-config
.
- You can also use an existing template:
/etc/nixos/configuration.nix
{ config, pkgs, lib, ... }:
{
# NixOS wants to enable GRUB by default
boot.loader.grub.enable = false;
# Enables the generation of /boot/extlinux/extlinux.conf
boot.loader.generic-extlinux-compatible.enable = true;
# !!! If your board is a Raspberry Pi 1, select this:
boot.kernelPackages = pkgs.linuxPackages_rpi;
# On other boards, pick a different kernel, note that on most boards with good mainline support, default, latest and hardened should all work
# Others might need a BSP kernel, which should be noted in their respective wiki entries
# !!! This is only for ARMv6 / ARMv7. Don't enable this on AArch64, cache.nixos.org works there.
nix.binaryCaches = lib.mkForce [ "https://cache.armv7l.xyz" ];
nix.binaryCachePublicKeys = [ "cache.armv7l.xyz-1:kBY/eGnBAYiqYfg0fy0inWhshUo+pGFM3Pj7kIkmlBk=" ];
# nixos-generate-config should normally set up file systems correctly
imports = [ ./hardware-configuration.nix ];
# If not, you can set them up manually as shown below
/*
fileSystems = {
# Prior to 19.09, the boot partition was hosted on the smaller first partition
# Starting with 19.09, the /boot folder is on the main bigger partition.
# The following is to be used only with older images. Note such old images should not be considered supported anymore whatsoever, but if you installed back then, this might be needed
/*
"/boot" = {
device = "/dev/disk/by-label/NIXOS_BOOT";
fsType = "vfat";
};
*/
"/" = {
device = "/dev/disk/by-label/NIXOS_SD";
fsType = "ext4";
};
};
*/
# !!! Adding a swap file is optional, but recommended if you use RAM-intensive applications that might OOM otherwise.
# Size is in MiB, set to whatever you want (though note a larger value will use more disk space).
# swapDevices = [ { device = "/swapfile"; size = 1024; } ];
}
Note: the default configuration.nix will contain something like imports = [ <nixos/modules/installer/sd-card/sd-image-armv7l-multiplatform.nix> ];
do not include that in your final installation or you will experience interesting problems. It is only for building the installation image!
First rebuild on ARMv6 and ARMv7
To rebuild your system, run: sudo nixos-rebuild switch
Details about the boot process
NixOS can be booted through UEFI on ARM too. The semantics are generally the same as on other architectures. Do note that the common use of Device Tree instead of ACPI in consumer-class hardware may make this a bit more awkward.
Otherwise, in SBC-class hardware, it is common that boards are generally expected to use U-Boot as the platform firmware and bootloader. See the section about using NixOS with U-Boot.
Porting NixOS to new boards
The easiest way
Assuming upstream U-Boot supports the board through a defconfig, it is possible possible to build U-Boot using the cross-compiling architecture from an x86_64 host. Here's a sample use.
# Assuming you're in a recent nixpkgs checkout
$ nix-shell \
-I "nixpkgs=$PWD" \
-p 'let plat = pkgsCross.aarch64-multiplatform; in plat.buildUBoot{defconfig = "orangepi_zero_plus2_defconfig"; extraMeta.platforms = ["aarch64-linux"]; BL31 = "${plat.armTrustedFirmwareAllwinner}/bl31.bin"; filesToInstall = ["u-boot-sunxi-with-spl.bin"];}'
For armv7 and armv6 pkgsCross.arm-embedded
should work, this is available in the unstable channel (19.03 and following) by setting -I "nixpkgs=/path/to/new-nixpkgs-checkout
.
This should build whatever is needed for, and then build U-Boot for the desired defconfig, then open a shell with the build in $buildInputs
. Do note that this particular invocation may need more changes than only the defconfig if built for other than allwinner boards.
Here's an example command, for allwinner boards, on how to write to an SD card.
$ sudo dd if=$buildInputs/u-boot-sunxi-with-spl.bin of=/dev/sdX bs=1024 seek=8
The easy way
(if you're lucky)
If your board is an ARMv7 board supported by multi_v7_defconfig and you have access to U-Boot on the board, getting sd-image-armv7l-linux.img
to boot is the easiest option:
- If you're lucky and your U-Boot build comes with the extlinux.conf support built in, the image boots out-of-the-box. This is the case for all (upstream) Allwinner and Tegra U-Boots, for instance.
- Otherwise, you can get the boot information (path to kernel zImage, initrd, DTB, command line arguments) by extracting
extlinux.conf
from the boot partition of the image, and then attempt to boot it via the U-Boot shell, or some other mechanism that your board's distro uses (e.g.uEnv.txt
).
Building U-Boot from your NixOS PC
Assuming
- Your board is supported upstream by U-Boot or there is a recent enough fork with
extlinux.conf
support. - You do not have nix setup on an ARM device
- Your nix isn't setup for cross-compilation
It is still possible to build U-Boot using tools provided by NixOS.
In the following terminal session, replace orangepi_pc_defconfig
with the appropriate board from the configs folder of U-Boot.
$ nix-shell -E 'with import <nixpkgs> {}; stdenv.mkDerivation { name = "arm-shell"; buildInputs = [git gnumake gcc gcc-arm-embedded dtc]; }' $ git clone git://git.denx.de/u-boot.git $ cd u-boot # We're checking out a version from before the use of `binman`. # The dtc package is 1.4.2, which does not include `pylibftd`. # Furthermore, I do not know how to package the library so it would be # available in the python interpreter, making binman happy. $ git checkout v2017.03 $ make -j4 CROSS_COMPILE=arm-none-eabi- orangepi_pc_defconfig $ make -j4 CROSS_COMPILE=arm-none-eabi-
The name of the final file will change depending on the board. For this specific build, and most Allwinner builds, the file will be named u-boot-sunxi-with-spl.bin
.
You can flash this file to boot device with
dd if=u-boot-sunxi-with-spl.bin of=/dev/sdX bs=1024 seek=8
Note: This mailing list contains a patch which may help some builds: https://lists.denx.de/pipermail/u-boot/2016-December/275664.html
The hard way
Alternatively/if all else fails, you can do it the hard way and bootstrap NixOS from an existing ARM Linux installation.
Contributing new boards to nixpkgs
- Add a new derivation for your board's U-Boot configuration, see for example ubootPine64LTS in
all-packages.nix
. - If your board's U-Boot configuration doesn't use the
extlinux.conf
format by default, create a patch to enable it. Some C hacking skills & U-Boot knowledge might be required. For some pointers, see this patch to enable it on the Versatile Express. - Make a pull request, also containing the board-specific instructions.
Getting Support
There is a dedicated room for the upstream NixOS effort on Matrix, #nixos-on-arm:nixos.org.
Don't hesitate to ask questions. Note that reply times may vary greatly, depending on the provided information.
Resources
See also
- U-Boot, as it is often paired with SBC-class hardware.
- Mobile NixOS, which provides enhanced semantic around some non-standard boot semantics.
Subpages
The following is a list of all sub-pages of the NixOS on ARM topic.
- Adding support for new boards
- Allwinner/GPT Installation
- Apple Silicon Macs
- ASUS Tinker Board
- Banana Pi
- Banana Pi BPI-M5
- Banana Pi M64
- BeagleBone Black
- Building Images
- Clockworkpi A06 uConsole
- en
- Firefly AIO-3399C
- fr
- Initial Configuration
- Installation
- Jetson TK1
- Kosagi Novena
- Libre Computer AML-S905X-CC-V2
- Libre Computer ROC-RK3328-CC
- Libre Computer ROC-RK3399-PC
- LS1046A
- NanoPC-T4
- NanoPi-R6C
- ODROID-C2
- ODROID-HC1
- ODROID-HC4
- OLIMEX Teres-A64
- Orange Pi 5
- Orange Pi 5 Plus
- Orange Pi One
- Orange Pi PC
- Orange Pi Zero2 H616
- Orange Pi Zero Plus2 H5
- PcDuino3 Nano
- PINE64 Pinebook
- PINE64 Pinebook Pro
- PINE64 ROCK64
- PINE64 ROCKPro64
- PINE A64-LTS
- QEMU
- Radxa ROCK 4
- Radxa ROCK5 Model A
- Radxa ROCK5 Model B
- Raspberry Pi
- Raspberry Pi 3
- Raspberry Pi 4
- Raspberry Pi 5
- ru
- Scaleway C1
- Toshiba AC100
- UEFI
- UEFI/en
- UEFI/fr
- UEFI/ru
- Wandboard