Skip to content

Build the ISO for the host architecture, adding aarch64 support - #121

Open
oceanapplications wants to merge 11 commits into
omacom:quattrofrom
oceanapplications:aarch64-build-system
Open

Build the ISO for the host architecture, adding aarch64 support#121
oceanapplications wants to merge 11 commits into
omacom:quattrofrom
oceanapplications:aarch64-build-system

Conversation

@oceanapplications

@oceanapplications oceanapplications commented Aug 24, 2026

Copy link
Copy Markdown

Important

Depends on two things outside this repository.

  1. A limine-mkinitcpio-hook release that finds kernels without a pkgbase marker.
    Arch Linux ARM's linux-aarch64 omits usr/lib/modules/<ver>/pkgbase, and
    limine-mkinitcpio-hook replaces the distribution's 90-mkinitcpio-install.hook with one
    that enumerates kernels by that file and silently returns 0 when it is absent. Stock ALARM
    generates its initramfs fine; installing Limine turns that into nothing at all, so the
    installer completes and writes no boot entries. The fix, a fallback to package ownership
    of the module tree, is merged upstream as
    Zesko/limine-entry-tool!64
    (2026-08-27) but not yet in a tagged release; the newest tag is still 1.37.1, which is
    what omarchy-pkgs pins. Once a release ships and limine-mkinitcpio-hook is bumped there,
    nothing further is needed here. Verified below with the package built from that commit.
  2. An aarch64 tree at pkgs.omarchy.org, Publish an aarch64 tree at pkgs.omarchy.org omarchy-pkgs#199. Without one the
    build has nowhere to fetch [omarchy] packages from.

Neither is something to work around here.

Adds aarch64 support to the ISO build. Everything is derived from uname -m; on x86_64 every
selector resolves to the value it has today, and the files x86 reads — grub.cfg, the pacman
configs, linux-t2.preset — are byte-identical to quattro.

Four commits, each a self-contained layer:

Commit What
builder: architecture selection, host portability, package filtering
configs: drop x86-only repositories on aarch64
boot: profile, GRUB and live mkinitcpio
installer: the phases that assume an x86 target

builder

One case sets ISO_ARCH / ISO_NODE_ARCH / ISO_KERNEL. Node needs its own mapping because
it names builds linux-x64 / linux-arm64 rather than by uname; phases_impl.py derives the
same suffix so the two ends cannot disagree.

Two host-portability fixes that are not architecture-specific:

  • Prefer the archiso package, fall back to the vendored submodule. Not every repository
    carries archiso; Arch Linux ARM has none. Installing from source skips the package's
    dependency closure, so squashfs-tools dosfstools mtools libisoburn erofs-utils arch-install-scripts e2fsprogs are requested explicitly on that path only.
  • Match both .pkg.tar.zst and .pkg.tar.xz when indexing the offline mirror. Arch ships
    zstd, Arch Linux ARM still ships xz. Matching only zstd makes repo-add index almost nothing,
    and it fails silently — repo-add succeeds, the db exists, pacman -Sy succeeds, and only
    the resolve reports error: target not found: base for everything.
    The package files are enumerated before being handed to repo-add: an inline glob that
    matches nothing is passed literally, and repo-add treats that as a missing file, which
    under set -e would have aborted every zstd-only x86_64 build.

OMARCHY_ARCH_DROP filters packages with no aarch64 build (pacman -Syw aborts the whole
transaction on the first missing target). It is applied to all four independently-read
lists — the live environment's packages.$ISO_ARCH, both shipped Omarchy lists, and
archinstall.packages. Missing any one of them fails late and confusingly; missing the live
list fails at Failed to install packages to new root.

configs

[multilib] is 32-bit x86 libraries and no ARM mirror carries it; [arch-mact2] is an Apple T2
repository. Rather than edit the checked-in configs, a filtered copy is staged for aarch64 and
x86_64 keeps reading the originals.

core/extra's explicit Server line points at Omarchy's x86_64-only mirror of Arch. Both
sections already Include the mirrorlist, so the line is dropped rather than replaced —
substituting another URL would not work, since Arch Linux ARM lays its tree out as
$arch/$repo rather than Arch's $repo/os/$arch. plans/aarch64-support.md §8 assumes that
placeholder adapts automatically; it does not.

boot

  • arch, bootmodes and the airootfs compression are selected per architecture. ARM has no
    legacy BIOS, so aarch64 drops bios.syslinux.

  • SquashFS compression. Arch Linux ARM builds its kernel without CONFIG_SQUASHFS_ZSTD
    (ZLIB, LZ4 and XZ only), so a zstd airootfs builds correctly and then cannot be mounted by the
    very kernel on the ISO: fsconfig() failed: Filesystem uses "zstd" compression. aarch64 uses
    xz -Xbcj arm; x86_64 keeps zstd, so the measured rationale in the existing comment stands.
    Worth noting that comment credits the zstd switch with removing an aarch64 blocker — on ALARM
    it is the blocker.

  • grub.cfg is unchanged; it hardcodes the kernel filename, which follows the live kernel
    package, so build-iso.sh substitutes it from ISO_KERNEL when staging (a no-op on x86_64).

  • The live mkinitcpio overrides live in configs/aarch64/ rather than configs/airootfs/, and
    are installed into the airootfs only on that architecture. They must exist before pacstrap
    runs mkinitcpio's pacman hook. zz-aarch64-live.conf is the important one:
    omarchy_hooks.conf describes an installed system and sorts after archiso.conf, so
    without it the live initramfs has no archiso hook and the ISO panics with
    Failed to mount '' on real root.

    The plan says the T2 preset "simply does not ship" on aarch64 and that releng's linux.preset
    covers the stock kernel. That only holds if you boot linux — on ALARM the kernel is
    linux-aarch64, so nothing supplies the preset, and the preset is what sets archiso_config=
    and thereby bypasses /etc/mkinitcpio.conf.d entirely. Dropping linux-t2.preset without a
    replacement looks harmless and is not.

installer

  • The orchestrator does its own EFI install and hardcodes x64 in nine places across
    phases_impl.py, context.py and configurator. This is the one to review first. The
    Arch limine package ships every architecture's binary, so BOOTX64.EFI exists on ARM and
    the copy succeeds: the installer writes an x86-64 PE binary to the ESP, registers it with
    efibootmgr, and validate_boot() then confirms limine_x64.efi is present, because it is.
    The install reports success and the machine drops to UEFI setup. It also writes a pacman hook
    that re-copies the x86 binary on every limine upgrade, so it cannot self-heal.
  • detect_kernel() returns linux; Arch Linux ARM has no bare linux package.
  • The configurator hands archinstall three custom mirror servers, which it prepends to the
    target's mirrorlist. All three are Arch x86_64 mirrors laid out as $repo/os/$arch, so on
    aarch64 every pacman -Sy walked through a dozen 404s before reaching the mirror ALARM's
    own pacman-mirrorlist installed. aarch64 now passes an empty list so that mirrorlist is
    left alone; the x86_64 rendering is byte-identical.

Testing

Built from this branch as pushed, on Arch Linux ARM aarch64 (kernel 7.2.0-2-aarch64-ARCH),
natively rather than under QEMU. The only delta from the branch was the [omarchy] Server
line pointed at a locally built repository, since pkgs.omarchy.org has no aarch64 tree; that
repository carried limine-mkinitcpio-hook built from upstream master plus the pkgbase
fallback described above.

The resulting 3.4 GB ISO boots (GRUB reports Skipping GRUB module(s) not built for arm64-efi: at_keyboard keylayouts usb usbserial_common usbserial_ftdi usbserial_pl2303 usbserial_usbdebug
during the build), runs the installer to Installed Omarchy in 2m 2s on an encrypted target,
and that target boots unattended into the desktop. On the installed system:

/usr/lib/modules/7.2.0-2-aarch64-ARCH/pkgbase     absent (ALARM does not ship it)
/boot/EFI/Linux/omarchy_linux-aarch64.efi         present
/boot/EFI/limine/limine_aa64.efi                  present
Boot0005* Limine  ...\EFI\limine\limine_aa64.efi

The kernel-upgrade path was exercised too: deleting the UKI and running the hook with
usr/lib/initcpio/<ver> on stdin, as pacman does on a kernel upgrade, regenerated it
byte-identical to the original.

A second install from this branch, with omacom/omarchy#8039's pacman.sh in the bundled
omarchy package, checked the package manager on the result: the mirrorlist is ALARM's, and
pacman -Sy syncs core, extra, alarm and aur cleanly. The only failure is
[omarchy], which 404s until omacom/omarchy-pkgs#199 publishes an aarch64 tree.

x86_64 has not been rebuilt. The x86 path is unchanged by inspection — every selector
resolves to its previous literal and the files x86 reads are byte-identical — but that is
inspection, not a build.

Out of scope

Both gaps that used to sit outside this repository are now handled inside it:

  1. GRUB module listat_keyboard, keylayouts, usb and usbserial_* are not built for
    arm64-efi, so grub-mkstandalone aborts. The fix belongs in archiso, so it is carried as
    builder/patches/archiso-grubmodules.patch against the vendored copy and applied with
    --forward, making it a no-op once the submodule is bumped past a release containing it.
    A post-install check confirms the mkarchiso actually in use can build for this platform.
  2. releng ships no packages.aarch64 — this PR ships its own; mkarchiso reads
    packages.$arch from the profile directory, so no archiso change is needed.

pkgs.omarchy.org has no aarch64 tree (omacom/omarchy-pkgs#199), so an aarch64 build
currently needs a locally built repository substituted for [omarchy]. That is a publishing
question, so the real URL is left untouched here.

Finally, configs/efiboot/loader/entries/01-archiso-x86_64-linux.conf is dead in this profile —
only uefi.systemd-boot reads it, and neither architecture uses that bootmode.

@oceanapplications
oceanapplications marked this pull request as draft August 24, 2026 12:43
@greptile-apps

greptile-apps Bot commented Aug 24, 2026

Copy link
Copy Markdown

Greptile Summary

This PR makes ISO construction and installation derive architecture-specific behavior from the build host, adding an aarch64 path while retaining the existing x86_64 selections.

  • Selects architecture-specific kernels, Node archives, package lists, repositories, Archiso boot modes, and root-filesystem compression.
  • Adds aarch64 live-kernel and initramfs preparation and rewrites both direct and loopback GRUB entries to use the selected kernel.
  • Derives Limine EFI binaries and target mirror configuration from the running architecture.
  • Supports both zstd- and xz-compressed package archives when preparing the offline repository.

Confidence Score: 5/5

The PR appears safe to merge because no blocking failure remains in the previously reported architecture, boot-path, initramfs, or archive-enumeration fixes.

No blocking failure remains.

Important Files Changed

Filename Overview
builder/build-iso.sh Centralizes host-architecture selection, stages matching profile and boot inputs, filters unsupported ARM packages, and safely indexes both supported package archive formats.
configs/profiledef.sh Selects the Archiso architecture, firmware boot modes, and SquashFS compression appropriate to the host architecture.
configs/aarch64/customize_airootfs.sh Adapts ALARM kernel naming, creates the live preset and initramfs, and now stops assembly when the required initramfs is absent or empty.
configs/airootfs/root/configurator Emits architecture-correct Limine and mirror settings and selects the ALARM kernel on aarch64.
configs/airootfs/usr/share/omarchy-iso/orchestrator/context.py Makes legacy/default boot intent use the architecture-correct Limine EFI filename.
configs/airootfs/usr/share/omarchy-iso/orchestrator/phases_impl.py Copies, registers, refreshes, and validates the Limine EFI binary appropriate to the installed architecture.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  H[Build host architecture] --> S{uname -m}
  S -->|x86_64| X[linux-t2 / Node x64 / zstd]
  S -->|aarch64| A[linux-aarch64 / Node arm64 / xz]
  X --> P[Stage Archiso profile]
  A --> P
  P --> G[Rewrite active GRUB kernel paths]
  P --> M[Resolve and index offline package mirror]
  G --> I[Build bootable ISO]
  M --> I
  I --> C[Live installer configuration]
  C --> L[Install matching Limine EFI binary]
  L --> T[Bootable target system]
Loading

Reviews (9): Last reviewed commit: "builder: enumerate offline mirror packag..." | Re-trigger Greptile

Comment thread builder/build-iso.sh Outdated
@oceanapplications oceanapplications changed the title builder: aarch64 build support, and stop assuming an x86 Arch build host builder: build for the host architecture instead of hardcoding x86_64 Aug 24, 2026
@oceanapplications
oceanapplications marked this pull request as ready for review August 24, 2026 12:52
Comment thread builder/build-iso.sh Outdated
@oceanapplications
oceanapplications marked this pull request as draft August 24, 2026 13:29
builder/build-iso.sh hardcodes x86_64 in the places that pick a kernel, a Node
tarball and a package list, and assumes the archiso package is installable.
Derive all of them instead, so the same script builds for either architecture.

Architecture selection:

  - one case statement sets ISO_ARCH / ISO_NODE_ARCH / ISO_KERNEL from uname -m;
    everything downstream uses those rather than a literal
  - packages.$ISO_ARCH for the live environment's own package list
  - the Node tarball follows ISO_NODE_ARCH, since Node names its builds
    linux-x64 / linux-arm64 rather than by uname
  - phases_impl.py, which consumes that tarball during the install, derives the
    same suffix from platform.machine(). Both ends have to agree or the
    installer aborts with "no bundled Node tarball in /opt/packages" after the
    build has already bundled the right file.
  - on x86_64 every one of these resolves to exactly the previous value:
    linux-t2, packages.x86_64, linux-x64.tar.gz

Host portability, not architecture-specific:

  - prefer the archiso package, and fall back to the vendored submodule when the
    repository has no archiso (Arch Linux ARM does not). Installing from source
    skips the package's dependency closure, so squashfs-tools, dosfstools,
    mtools, libisoburn, erofs-utils, arch-install-scripts and e2fsprogs are
    requested explicitly on that path. Use install-scripts and install-profiles
    rather than the default install target, which runs rst2man for man pages
    this build does not use.

  - match both .pkg.tar.zst and .pkg.tar.xz when indexing the offline mirror.
    Arch ships zstd, Arch Linux ARM still ships xz, and matching only zstd makes
    repo-add index almost nothing. It fails silently: repo-add succeeds, the db
    exists, pacman -Sy succeeds, and only the resolve reports "target not found"
    for everything including base. Both extensions are enumerated rather than
    globbed so .sig files are not swept in.

aarch64 package selection, gated on uname -m:

  - OMARCHY_ARCH_DROP plus a filter, since pacman -Syw aborts the whole
    transaction on the first missing target. Applied to every consumed list, not
    just the mirror's download set: filtering only that one produces an ISO that
    builds cleanly and then fails partway through a real install.
  - quickshell-git and mise substituted for their packaged equivalents.

Verified by building an aarch64 ISO end to end on Arch Linux ARM natively.
@oceanapplications oceanapplications changed the title builder: build for the host architecture instead of hardcoding x86_64 Build the ISO for the host architecture, adding aarch64 support Aug 24, 2026
@oceanapplications
oceanapplications marked this pull request as ready for review August 24, 2026 13:59
@oceanapplications
oceanapplications marked this pull request as draft August 24, 2026 14:02
Comment thread builder/build-iso.sh Outdated
@oceanapplications
oceanapplications force-pushed the aarch64-build-system branch 2 times, most recently from 8348de7 to 6197891 Compare August 24, 2026 14:26
mkarchiso reads packages.$arch from the profile directory. The build seeds the
profile from archiso's releng configs, which ship only packages.x86_64, so an
aarch64 build had no live package list of its own and would pacstrap only the
handful of names appended by build-iso.sh.

Derived from releng's packages.x86_64 with the entries that do not exist for
aarch64 removed, each checked against the Arch Linux ARM repositories rather
than by inspection.
Comment thread configs/aarch64/customize_airootfs.sh
customize_airootfs.sh removed the existing initramfs and then downgraded both
mkinitcpio failing and the image being absent to log messages, so an aarch64 ISO
could build cleanly and be unbootable -- the GRUB entries load
initramfs-linux-aarch64.img by name.

mkinitcpio's exit status cannot be used directly here: it exits non-zero on this
platform even when it produces a complete image, because archiso's memdisk hook
wants the phram module and the memdiskfind binary and neither exists for
aarch64 (memdiskfind ships in syslinux, which is x86-only). So the check is on
the artefact instead -- a missing or empty image now exits 1, which mkarchiso
propagates since it runs under set -e.

The same applies to the kernel image the preset points at: if neither
/boot/Image nor /boot/vmlinuz-linux-aarch64 exists, say so rather than letting
mkinitcpio fail confusingly further down.
@oceanapplications
oceanapplications marked this pull request as draft August 24, 2026 15:35
The script read as though it hand-rolls initramfs generation for aarch64. It
does not, and should not: on Arch that is automatic, because the kernel package
installs usr/lib/modules/<ver>/{vmlinuz,pkgbase}, 90-mkinitcpio-install.hook
triggers on the former and the alpm script reads the latter for the kernel name.
Arch Linux ARM installs neither, which is proposed upstream as
archlinuxarm/PKGBUILDs#2215.

With that applied the hook does fire, verified by staging both files into a
pacstrapped root and installing them: the initramfs is generated automatically.
Two naming gaps remain, and closing those is this script's actual job:

  - ALARM's preset writes /boot/initramfs-linux.img while the GRUB entries load
    initramfs-linux-aarch64.img
  - nothing creates /boot/vmlinuz-*, which is the glob mkarchiso copies the
    kernel from

Also records why the deprecated customize_airootfs.sh hook is used at all: the
work has to happen inside the chroot after packages install, since the kernel
image does not exist before that, and shipping the preset through airootfs/ does
not work because the overlay is copied before pacstrap and linux-aarch64's own
preset overwrites it.

Comments only; no behaviour change.
archiso hardcodes a GRUB module list taken from an x86 bug report. at_keyboard
is PS/2, and keylayouts, usb and the four usbserial_* drivers are x86-oriented,
so none of them are built for arm64-efi and grub-mkstandalone aborts on the
first one it cannot find. Without this an aarch64 ISO cannot be built at all.

The fix belongs in archiso rather than here, so it is carried as a patch
against the vendored copy and applied where the submodule is staged for
installation. It uses --forward, so it becomes a no-op once the submodule is
bumped past a release containing the change.

A check after installation confirms the mkarchiso actually in use can build for
this platform, whether it came from the submodule or from a distro package.
Failing there with an explanation is better than failing several minutes later
inside grub-mkstandalone.

The seven modules were confirmed absent by installing grub in an aarch64
container and testing each path under /usr/lib/grub/arm64-efi/.
build-iso.sh checks the installed mkarchiso for _filter_grubmodules before
building, but the patch inlined its filtering and never defined that name,
so an aarch64 build failed at the guard every time.

Move the filtering into a _filter_grubmodules helper that build-iso.sh can
find. Its diagnostic goes to stderr, since stdout carries the module list.
@oceanapplications
oceanapplications marked this pull request as ready for review August 26, 2026 08:11
The configurator hands archinstall three custom mirror servers, which it
prepends to the target's /etc/pacman.d/mirrorlist. All three are Arch x86_64
mirrors laid out as $repo/os/$arch. Arch Linux ARM lays its tree out as
$arch/$repo on different hosts, so on aarch64 every one of them 404s ahead
of the mirror the distribution's own pacman-mirrorlist package installed, and
each pacman -Sy walks through a dozen failures before reaching it.

Pass an empty list on aarch64 so archinstall leaves the mirrorlist alone.
The x86_64 rendering is byte-identical to before.
Comment thread builder/build-iso.sh Outdated
repo-add was handed both *.pkg.tar.zst and *.pkg.tar.xz as inline globs. A
mirror holding only one format, which is every x86_64 build, leaves the other
pattern unmatched; bash passes it to repo-add literally, repo-add reports the
file as not found, and set -e aborts the build.

Collect the existing files first, as build-omarchy-packages.sh already does,
and fail with a clear message if there are none.
@greptile-apps

greptile-apps Bot commented Aug 26, 2026

Copy link
Copy Markdown

Want your agent to iterate on Greptile's feedback? Try greploops.

@HurlyDesousa

Copy link
Copy Markdown

Hardware note from an ASUS Vivobook S 15 S5507QA (Snapdragon X Elite X1E-78-100) that is running Omarchy aarch64 today.

The aarch64 pitfalls this PR documents match what we hit:

  • ALARM-style kernels omit usr/lib/modules/<ver>/pkgbase, so stock limine-mkinitcpio-hook (still 1.37.1 in omarchy-pkgs) writes no boot entries until the pkgbase fallback from limine-entry-tool !64 is in a tagged release.
  • Copying BOOTX64.EFI / limine_x64.efi on ARM succeeds, then the machine drops to the UEFI menu. The installed ESP has to be limine_aa64.efi / BOOTAA64.EFI.
  • aarch64 live squashfs cannot be zstd on stock ALARM (CONFIG_SQUASHFS_ZSTD missing).
  • [omarchy] 404s until pkgs.omarchy.org has an aarch64 tree (omarchy-pkgs#199).

121 alone does not boot this Snapdragon laptop. We still need the Snapdragon DTB/UKI path (PR 129) and a device kernel (linux-aarch64-vivobook). Installed layout here: LUKS2 + Btrfs + Limine aa64, with a stock linux-aarch64 Limine fallback.

Happy to boot a 121+129 ISO on this machine once the aarch64 [omarchy] repo exists, and to report back.

— Grokbot (agent)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants