NixOS on ARM/Allwinner/GPT Installation

From NixOS Wiki

This guide is intended to demonstrate how to install NixOS on an Allwinner target device, using u-boot, allowing for use of the GPT partition scheme.

The main advantage of going this way is the ability to boot using a UEFI-based bootloader from u-boot, on one single storage.

This guide uses holey, a script intended to make this easier. A manual method using cgpt and gdisk will be described at the end.

What will this do?

This will create a GPT partitioned disk with a hole between the Primary GPT header and the Primary GPT Table. The location where the Allwinner SoC looks for the bootloader falls within that hole, and this is where u-boot will be installed. Without that hole, the u-boot bootloader would be installed over the end of the Primary GPT table.

On a MBR partitioned disk, this location is at the beginning of the disk. As long as care is taken not to add a partition over it, there should be no clash.

By using a hole in the GPT, the installed firmware is more resilient to re-partitioning, as long as the GPT table is not cleared and written anew. There is no risk of overwriting the bootloader by manipulating partitions.


You will need to boot the installation media from a different storage than the target storage (where you will install). On some, if not most, Allwinner systems, it is possible to boot from USB as long as you can boot u-boot in some manner. This means that you could flash the u-boot bootloader to an empty SD card, and boot from a USB drive containing either the UEFI iso or the SD image installer. Alternatively, some platforms will have multiple storage, and will boot from SD card before booting from the internal storage.

This is needed because the target storage will be erased, while the usual SD image from NixOS expects the user to re-use the partitions from the booted system.

Alternatively, it should be possible to install to a smaller storage, and dd it to the internal storage and resize the partitions. Though it is untested. Finally, it is possible to install on a USB connected storage, e.g. to another SD card in a USB SD reader, or a specialized eMMC USB adapter.


Once booted to the installer system, you will need to get the holey tool.

nix-shell -p 'import (fetchTarball {}'

This will drop you in a shell with holey available.

Create a new GPT partition table on the target drive. By default it will leave a 2MiB gap which is plenty for the default u-boot builds, with spare space for further increase in size if needed.

 $ holey /dev/$DISK init

You can verify that it worked.

 $ holey /dev/$DISK check
Holey GPT looks fine!
       start        size    part  contents
           0           1          PMBR (Boot GUID: FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF)
           1           1          Pri GPT header
        4100          32          Pri GPT table
    61071327          32          Sec GPT table
    61071359           1          Sec GPT header

At that point, the GPT has been split, there is a gap between the header and the table.

You can continue either by using holey to add partitions, or partition like you want using tools like cfdisk, fdisk or gdisk.

The next commands will prepare an ESP (EFI System Partition) and a root partition for the system. For the size of the ESP, 512MiB has been chosen, keep in mind that on ARM platforms the kernel is not compressed, and can be around 2-3 times bigger than on x86_64.

holey /dev/$DISK add esp 512
holey /dev/$DISK add linux

The last call will make the partition as big as it can fit.

Installing u-boot

This is done as usually is done.

dd if=result/u-boot-sunxi-with-spl.bin of=/dev/$DISK bs=1024 seek=8 oflag=sync

This is also how an update to u-boot would be installed.


From here, the installation process is as usual with NixOS.

Using other tools

Create the hole using gdisk

Follows the transcript, starting from an empty disk.

 $ gdisk /dev/$DISK
GPT fdisk (gdisk) version 1.0.4

Partition table scan:
  MBR: not present
  BSD: not present
  APM: not present
  GPT: not present

Creating new GPT entries in memory.

Command (? for help): o
This option deletes all partitions and creates a new protective MBR.
Proceed? (Y/N): y

Command (? for help): x

Expert command (? for help): j
Currently, main partition table begins at sector 2 and ends at sector 33
Enter new starting location (2 to 18446744073709551583; default is 2; 1 to abort): 4100

Expert command (? for help): m

Command (? for help): w

Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING

Do you want to proceed? (Y/N): y
OK; writing new GUID partition table (GPT) to disk.img.
Warning: The kernel is still using the old partition table.
The new table will be used at the next reboot or after you
run partprobe(8) or kpartx(8)
The operation has completed successfully.

Create the hole using cgpt

cgpt is a GPT manipulation tool. We start by zeroing the GPT and continue by creating a new partition table, then add the protective MBR. Adding that PMBR is what is needed for the kernel and tools to see and understand the GPT properly.

# Zeroes the GPTs, if it makes sense
cgpt create -z /dev/$DISK

# Creates new GPTs with space for the bootloader
cgpt create -p 4100 /dev/$DISK

# Creates the PMBR; also makes the GPT show up in most tools.
cgpt boot -p /dev/$DISK