Skip to main content
The scripts/cm5-setup.sh script creates a complete, bootable Arch Linux aarch64 disk image for the RPi5 / CM5 Exaviz carrier. It handles partitioning, formatting, bootstrapping, initramfs generation, UEFI firmware deployment, and GRUB installation in a single run.

Prerequisites

The script must run as root on an x86_64 Linux host with QEMU user-space emulation installed. Required tools:
ToolPackage (Arch/Debian)
partedparted
mkfs.fatdosfstools
mkfs.btrfsbtrfs-progs
losetuputil-linux
btrfsbtrfs-progs
wgetwget
unzipunzip
arch-chrootarch-install-scripts
pacstraparch-install-scripts
qemu-aarch64-staticqemu-user-static
# Arch Linux host
sudo pacman -S parted dosfstools btrfs-progs util-linux wget unzip arch-install-scripts qemu-user-static

# Debian/Ubuntu host
sudo apt install parted dosfstools btrfs-progs util-linux wget unzip arch-install-scripts qemu-user-static
You also need an aarch64 pacman configuration at /etc/qemu-archstrap/pacman-aarch64.conf. This is provided by the qemu-archstrap tool referenced in the repository root.

Script arguments

IMG
string
Output image filename. Default: rpi5-arch.img
IMG_SIZE
string
Total image size passed to truncate. Default: 16G
SWAP_SIZE
string
Size of the swap.img file created inside the @swap subvolume. Default: 4G
Environment variable:
DROPBEAR_AUTHKEYS
string
Path to an SSH public key to inject as /etc/dropbear/authorized_keys for early SSH rescue. Defaults to ~/.ssh/id_ed25519.pub.
# Basic usage — creates rpi5-arch.img (16 GB image, 4 GB swap)
sudo bash scripts/cm5-setup.sh

# Custom image name and sizes
sudo bash scripts/cm5-setup.sh my-cm5.img 32G 8G

# Inject a specific SSH public key for early SSH
DROPBEAR_AUTHKEYS=/path/to/id_ed25519.pub sudo bash scripts/cm5-setup.sh
Set DROPBEAR_AUTHKEYS before running. If the file is not found, an empty authorized_keys is written and early SSH rescue will not work.

What the script does

1

Create and partition the image

Creates a sparse image file with truncate, then uses parted to write a GPT partition table with two partitions:
PartitionTypeRangeLabel
p1 (ESP)FAT321 MiB – 257 MiBRPI5-EFI
p2 (ROOT)Btrfs257 MiB – 100%ARCH-ROOT
The image is attached as a loop device with losetup --find --partscan.
2

Format filesystems

Formats p1 as FAT32 (mkfs.fat -F32 -n RPI5-EFI) and p2 as Btrfs (mkfs.btrfs -L ARCH-ROOT).
3

Create Btrfs subvolumes

Mounts the root partition and creates six subvolumes:
SubvolumeMount pointNotes
@/Root filesystem
@boot/bootKernel and initramfs
@swap/swapswap.img with nodatacow
@snapshots/.snapshotsSnapper snapshots
@var_log/var/logLog isolation
@home/homeUser home directories
All subvolumes are mounted with compress=zstd,space_cache=v2,noatime.
4

Create swap.img

Creates /swap/swap.img (default 4 GB) with nodatacow disabled via chattr +C before creating the file. This is required for Btrfs swap support.
5

Bootstrap with pacstrap

Bootstraps an aarch64 Arch Linux environment using QEMU transparent emulation:
pacstrap -C /etc/qemu-archstrap/pacman-aarch64.conf -K /mnt/rpi5-root \
    base base-devel \
    linux-rpi linux-rpi-headers linux-firmware \
    btrfs-progs \
    grub efibootmgr \
    dracut \
    dropbear \
    networkmanager \
    openssh \
    sudo \
    rpi-eeprom \
    snapper \
    vim \
    curl wget git
6

Write fstab, hostname, locale, timezone

Writes /etc/fstab with UUID-based mounts for all subvolumes and the ESP. Sets hostname to archlinux-cm5, locale to en_US.UTF-8, timezone to UTC.
7

Configure dracut

Writes /etc/dracut.conf.d/rpi5.conf enabling the btrfs, dropbear, and network modules. See Dracut Initramfs for details.
8

Set up Dropbear SSH keys

Generates RSA (4096-bit) and ECDSA host keys inside the chroot, then copies the DROPBEAR_AUTHKEYS public key to /etc/dropbear/authorized_keys.
9

Build initramfs

Runs dracut twice — once with --hostonly for the primary image and once with --no-hostonly for the fallback image.
10

Deploy RPi5 UEFI firmware

Downloads worproject/rpi5-uefi v0.3 and copies RPI_EFI.fd and supporting files to the ESP. Writes config.txt to the ESP. See Boot Configuration.
11

Install GRUB arm64-efi

grub-install \
    --target=arm64-efi \
    --efi-directory=/boot/efi \
    --bootloader-id=ARCH \
    --removable \
    --recheck
12

Write grub.cfg

Generates a GRUB menu with two entries: the primary Btrfs @ boot and a fallback initrd entry, plus a UEFI firmware settings entry.
13

Configure Snapper

Creates a Snapper configuration for the root subvolume with timeline snapshots. See Btrfs Snapshots.
14

Enable services

Enables NetworkManager, sshd, and fstrim.timer (for periodic TRIM on eMMC/NVMe).

Build output

When the script completes successfully, it prints a summary:
── CM5/RPi5 Image Ready ──────────────────────────────────────────
  Image       : rpi5-arch.img  (16G)
  Btrfs layout: @ @boot @swap @snapshots @var_log @home
  Swap        : /swap/swap.img  (4G)
  Boot chain  : RPi EEPROM → RPI_EFI.fd → grubaa64.efi → linux-rpi
  Initramfs   : dracut + btrfs + dropbear
  Early SSH   : ssh -p 222 root@<ip>  (set authorized_keys first)

  Flash:
    dd if=rpi5-arch.img of=/dev/sdX bs=4M status=progress conv=fsync
    bmaptool copy rpi5-arch.img /dev/sdX   # faster if available
Root password is not set by the script. After flashing, re-enter the chroot and run passwd.

Next steps

Flash the image

Write the built image to your CM5 eMMC or storage device.

Boot configuration

Understand the boot chain and config.txt options.

Build docs developers (and LLMs) love