Archlinux for aarch64 and installing it on a Pi
About
Archlinux has builds for aarch64 including a pre-packed ArchLinuxARM-aarch64-latest.tar.gz
which can be directly extracted into freshly MBR-partitioned storage device with vvat+ext4 boot/root partitions mounted for getting started immediately. But why rely on a tarball at all?
pacstrapping a new AArch64 installation for the Pi 4
Given my machines already run Archlinux (x86_64) I figured it would only be fitting to pacstrap
the Raspberry Pi 4's USB stick manually. Here are some instructions to get started:
Partitioning
Use fdisk to create a new MBR table with part1 being (200M) and part2 with the remainder of the space.
Or something small like >4GB for working with virtual storage such as a ZVOL for easily fitting this prepared image onto storage of various sizes.
Make sure to set the first partition's type to c
which is W95 FAT32 (LBA)
so the Pi's bootloader firmware knows where to look.
Formatting
Format them as vfat
and ext4
:
sudo mkfs.vfat /dev/disk/by-id/usb-TheDrive-0\:0-part1
sudo mkfs.ext4 /dev/disk/by-id/usb-TheDrive-0\:0-part2
Mounting
Mount both in order with something like
sudo mount /dev/disk/by-id/usb-TheDrive-0\:0-part2 /mnt
sudo mkdir -p /mnt/boot
sudo mount /dev/disk/by-id/usb-TheDrive-0\:0-part1 /mnt/boot/
Pacstrapping
The host needs to trust the Archlinux ARM build servers for installing packages. This can be done by downloading it from the repository into pacman's keydir and then importing then signing the key. The installation itself comes with this file already.
sudo wget https://raw.githubusercontent.com/archlinuxarm/archlinuxarm-keyring/master/archlinuxarm.gpg
sudo pacman-key --populate archlinuxarm
sudo pacman-key --lsign-key archlinuxarm
We must also create a replica of the expected Archlinux AArch64 pacman.conf for our host's instance to use. It can be short and cut-down as below with a single mirror for the various repos:
echo '[options]
HoldPkg = pacman glibc
Architecture = aarch64
CheckSpace
SigLevel = Required DatabaseOptional
LocalFileSigLevel = Optional
[core]
Server = http://mirror.archlinuxarm.org/$arch/$repo
[extra]
Server = http://mirror.archlinuxarm.org/$arch/$repo
[community]
Server = http://mirror.archlinuxarm.org/$arch/$repo
[alarm]
Server = http://mirror.archlinuxarm.org/$arch/$repo
[aur]
Server = http://mirror.archlinuxarm.org/$arch/$repo
' > ~/pacman.aarch64.conf
Now we can pacstrap
into the Pi's new rootfs referencing this config and some good starter packages:
sudo pacstrap -M -K -C ~/pacman.aarch64.conf /mnt archlinuxarm-keyring base chrony openssh raspberrypi-bootloader vim networkmanager linux-rpi
We use these flags to avoid using anything from the host in this process:
-M
(Avoid copying the host’s mirrorlist to the target.)-K
(Initialize an empty pacman keyring in the target (implies -G).)-C
(Use an alternate config file for pacman.)
Chrooting into different architectures
Its difficult to chroot
/arch-chroot
into a rootfs of a differing architecture as none of its binaries will run. Luckily QEMU provides a solution for user-mode emulation which leverages binfmt
to invoke qemu-aarch64-static
for running those binaries instead of trying to execute it natively ourselves.
Fetch the relevant packages with:
pacman -S qemu-user-static-binfmt qemu-user-static
Activate it by copying its configuration into binfmt.d's working area:
sudo cp /usr/lib/binfmt.d/qemu-aarch64-static.conf /etc/binfmt.d/
You can verify it's active with: ls -lah /proc/sys/fs/binfmt_misc/qemu-aarch64
Now we need to copy it into the raspberry-pi's rootfs for chroot to find:
sudo cp $(which qemu-aarch64-static) /mnt/usr/bin
We can now chroot into the rootfs for this Pi.
Configuring the inside
Chroot into the Pi's rootfs with sudo arch-chroot /mnt qemu-aarch64-static /bin/bash
and configure the last bits and pieces:
systemctl enable NetworkManager sshd chronyd # Enable some critical networking and remote-access services.
pacman-key --init ; pacman-key --populate archlinuxarm # Initialize pacman's keyring and add archlinuxarm's keys.
passwd # Set a root password.
vim /etc/hostname # to set a hostname.
vim /etc/fstab # Or use `genfstab /mnt | sudo tee /mnt/etc/fstab` on the host and verify.
vim /boot/cmdline.txt # Don't forget to change root= to either a root=UUID=YourRootfsUUID or /dev/sda
Its advisable to use UUID=xxx for /mnt/etc/fstab to avoid device path changes from potentially borking the boot. genfstab /mnt | sudo tee /mnt/etc/fstab
will create the entries for you but you will still have to uncomment the UUID lines and use them at the start of the other lines instead of the disk dev path.
You can place some ssh keys in /root/.ssh/authorized_keys
or add new users.
Password authentication for root
is only possible after setting PermitRootLogin yes
in /etc/ssh/sshd_config
either in the chroot session or outside.
You can then set it up like any other Archlinux box. At a minimum you should probably uncomment your desired locale in /etc/locale.gen
, run locale-gen
and set it in /etc/locale.conf
as LANG=xxx_yyy-zzz
Finishing up
Finally leave the chroot. You can expand the partition if needed and sync
the USB before pulling it out (I can never trust USB device writes), remove the SD card or USB stick and boot the Pi.
Keep in mind Pi's (For some reason of choice) cannot USB-boot without being told to do so earlier in their life. This creates a bootstrap paradox requiring the Pi to be booted into some distro and enabling USB-booting before trying to use a USB stick.
Extra goodies
Serial over USB-C
Thanks to DWC2, the various available Pi drivers and the USB ports of the Pi being wired directly to the CPU - The USB-C port used for powering the device it can be configured to present as various Human Input Devices (HIDs) over a data cable while receiving power. It can even present as multiple of them at once and most usefully in this context an ethernet or serial interface.
To enable serial create /etc/modules-load.d/usb-c_serial.conf
with the below lines (drivers):
dwc2
g_serial
You also need to append dtoverlay=dwc2
to your /boot/config.txt
for this feature.
Finally, enable agetty to present a serial login console on the serial interface to-be: systemctl enable getty@ttyGS0.service
.
You can now reboot to load those two modules and start shelling in over USB-C. Well, when there's enough power delivery which most desktop and laptop USB-C ports won't do. Single cable for the win.