Repository navigation
luban: aarch64 images (try, export --drive/--iso), tiny-musl on aarch64, and qemu resolving to a package that does not exist #657
Description
Summary
Luban environments already run on aarch64. These all work there today, and the host matrix checks them on ubuntu-22.04-arm and ubuntu-24.04-arm:
luban newfromluban-nano,luban-tiny,coreandagent-workspace;- the bwrap sandbox, using a static aarch64 bwrap from xim-pkgindex#953;
upgrade;- proxy-only networking.
Making and trying an image is still x86_64-only, and luban-tiny-musl is not offered on aarch64. This issue collects what is missing on both sides (xlings and xim-pkgindex), a proposed design, and how to test it. Nothing here is urgent.
It also covers a bug that affects x86_64 too: the tool table resolves qemu to a package that does not exist, so a qemu installed by xlings is never used.
1. Bug: qemu resolves to a package that does not exist (all architectures)
modules/subos/src/sandbox/tools.cpp:73-80:
{{"qemu-system-x86_64", "qemu"}, "xim-x-qemu", ...},
{{"qemu-system-aarch64", "qemu"}, "xim-x-qemu", ...},
{{"qemu-img", "qemu"}, "xim-x-qemu", ...},The index has no qemu package. It has:
qemu-x86:qemu-system-x86_64, payload dirxim-x-qemu-x86;qemu-arm:qemu-system-aarch64andqemu-system-arm, payload dirxim-x-qemu-arm, shipsshare/qemu/edk2-aarch64-code.fd;qemu-riscv.
What follows from that:
- The
Source::Payloadlookup never finds an installed qemu.luban tryonly works when the host has/usr/bin/qemu-system-*. - The printed remedy
xlings install qemufails with'qemu' matches more than one package. - CI hides both problems because it installs
qemu-system-x86andovmfwith apt (xlings-ci-linux.yml, the "Lane capabilities" step).tests/e2e/luban_image_test.shalso looks for OVMF under/usr/shareonly.
Fix: map each emulator to the package that ships it:
qemu-system-x86_64→qemu-x86/xim-x-qemu-x86;qemu-system-aarch64→qemu-arm/xim-x-qemu-arm.
Then either drop qemu-img or map it to a package that ships it. It is not used by try today. Add a unit test that every Entry with a package names a package present in the published index. That test could run in index acceptance, or as a static check against a snapshot.
Other entries without an index package, for the same audit:
xorriso,squashfs-tools: the host is the only real source today;xlings-vm: macOS-only, not in the index yet.
A remedy should not name a package that is not there. Either publish one or print the host package manager's name.
A leftover comment in the same file says "The host's clipboard (xlings clipboard; ...)". That command was replaced by the clipboard grants before #653 merged; reword it to the grant.
2. aarch64 images
What is already in place (index side)
| Need | Package | aarch64 |
|---|---|---|
| kernel for a VM | linux-kernel-virt 6.12 (virtio, EFI stub) through luban-boot-virt |
yes (xim-pkgindex#945) |
| UEFI loader | limine 12.9.3; the payload carries BOOTAA64.EFI and limine-uefi-cd.bin |
yes |
| emulator + firmware | qemu-arm (qemu-system-aarch64, edk2-aarch64-code.fd) |
yes |
| userland | busybox, bwrap, glibc |
yes |
| kernel for real hardware | linux-kernel through luban-boot-generic |
no (x86_64 only, and this is fine for now; see out of scope) |
What is x86_64-specific in xlings
-
luban try(luban/src/cli/cli.cpp,try_cmd_):- it refuses any machine that is not x86_64;
- it always runs
qemu-system-x86_64; - it boots the ISO with
-cdrom ... -boot d.
qemu's
virtmachine on aarch64 has no IDE/AHCI CD-ROM and no BIOS. It needs-M virt,-cpu host(KVM) or-cpu max(TCG), UEFI firmware (-bios edk2-aarch64-code.fd), and the disk as-drive if=virtio. -
export --drive(src/core/subos/root/root_cmd.cpp,write_drive_). The expected UEFI loader name depends on the architecture:BOOTX64.EFIon x86_64,BOOTAA64.EFIon aarch64. Today the code:- requires
BOOTX64.EFIand copies it toEFI/BOOT/BOOTX64.EFI; - always creates a 1 MiB "BIOS boot" partition;
- runs
limine bios-install.
On aarch64 none of the BIOS parts apply.
- requires
-
export --iso(root_cmd.cpp, the ISO stage):- it copies only
BOOTX64.EFI; - without xorriso, the in-process ISO writer produces a BIOS-only El Torito image (
ArchiveOptions{.boot = "boot/limine/limine-bios-cd.bin"}), which cannot boot on aarch64; - UEFI boot of the ISO depends on a host xorriso, and the index has no xorriso package.
- it copies only
-
limine_data_accepts a limine directory only if it haslimine-bios-cd.binandlimine-bios.sys. The limine payload ships them on every architecture, so this does not fail today. The check should still ask for what this architecture boots with: the UEFI loader for this architecture, plus the BIOS files only on x86_64. -
The "not a static build" hint suggests
mcpp build --target x86_64-linux-musl. It should name the machine's own triple.
Proposed design
-
The image's architecture is the root's architecture, which is the machine's. Cross-architecture images (an aarch64 image built or tried on x86_64) are out of scope.
-
One small per-architecture table in
root_cmd/luban.image, instead of scattered literals. It gives:- the UEFI loader file name (
BOOTX64.EFI/BOOTAA64.EFI); - whether BIOS boot applies (x86_64 only), which decides the BIOS boot partition and
bios-install; - the qemu program and its machine arguments;
- the firmware file name inside a qemu payload.
Use
platform::build_arch()or the root's recorded ABI, never/proc/sys/kernel/archin one place and a literal in another. - the UEFI loader file name (
-
--driveon aarch64:- GPT with only the FAT system partition (
EFI/BOOT/BOOTAA64.EFI, limine config, kernel, initramfs if any) and the ext4 root by PARTUUID; - no BIOS boot partition and no
bios-install; - everything is already written in-process (
luban.image), so no new host tool is needed.
- GPT with only the FAT system partition (
-
luban tryon aarch64 boots a drive image, not the ISO:qemu-system-aarch64 -M virt -cpu host|max -m <mem> -smp 2 -bios <edk2-aarch64-code.fd> -drive file=<img>,format=raw,if=virtio;- networking as today (
-nic user, orrestrict=on+ guestfwd with--proxy); - the default boot profile stays
virt.
The firmware is looked up the way limine's files are: the qemu payload's
share/qemu, then/usr/share/AAVMF,/usr/share/qemu-efi-aarch64,/usr/share/edk2/aarch64. Missing firmware is refused with the install hint.This avoids xorriso entirely, and also the
virtmachine's lack of a CD-ROM. -
--isoon aarch64. Two options:- (a) refuse with "an aarch64 ISO needs UEFI El Torito; use
--drive"; - (b) teach the in-process ISO writer a second El Torito entry, platform
0xEF(EFI), pointing atlimine-uefi-cd.bin. That would also give x86_64 ISOs UEFI boot without xorriso.
Proposed: (a) first, (b) as a follow-up, since (b) changes the x86_64 ISO too and needs its own BIOS + UEFI qemu tests.
- (a) refuse with "an aarch64 ISO needs UEFI El Torito; use
-
luban try <file>.isoon aarch64 is refused the same way.try <file>.img/.qcow2works.
3. luban-tiny-musl on aarch64 (index side, plus one xlings test)
luban-tiny-musl is archs = {"x86_64"}. Since 2026.10.11.2, an aarch64 machine refuses it before anything is made. This is checked by tests/host-matrix (#655). The only missing piece is musl itself: pkgs/m/musl.lua is x86_64-only.
Its comment gives two reasons: "matching glibc.lua", and "the build script's checks actually RUN the loader ... none of that can run here". Both are out of date:
- glibc ships aarch64, fixed in xim-pkgindex#956;
res-build.ymlbuilds on native aarch64 runners, so the checks can run for real.
Work (xim-pkgindex):
- Add
musltotools/res/build.shandres-build.yml. Build 1.2.5 natively on the arm runner, with the same relocatable layout as.agents/tools/build-musl.sh: the loader symlink under the prefix and relative, no RPATH. Run the checks there: run the loader, link and run a program. - Publish to xlings-res (GitHub), then fill GitCode with
gtc. Verify by content (GET + sha256). - In
musl.lua, add the aarch64 sha256 andloader = "lib/ld-musl-aarch64.so.1"for aarch64, andarchs += aarch64. The x86_64 payload is unchanged, sorevisiondoes not move. - Add
aarch64toluban-tiny-musl'sarchs. This is package metadata: the published 2026.10.11.1 manifest does not change, and it pinsxim:musl@1.2.5, which will then exist for aarch64. No new edition version is needed.
Work (xlings): turn the host-matrix aarch64 check for tiny-musl back from "refused" into "made, entered, and a musl program runs". The loader handling is meant to be architecture-neutral (ld-musl-* in elf_same_source, the loader path from the payload's data), but it has never run on aarch64. This test is what proves it.
4. Tests and CI
-
tests/e2e/luban_image_test.sh: run onubuntu-24.04-armtoo.- aarch64: export
--drivefrom tiny with--boot virt, boot it underqemu-system-aarch64 -M virtwith edk2, and wait for the console marker. - aarch64: check that
--isois refused as designed. - x86_64: keep the BIOS and UEFI legs as they are.
GitHub's arm runners have no
/dev/kvm, so the aarch64 leg runs under TCG. Give it its own, larger timeout; tiny with the virt kernel should still boot within a few minutes. - aarch64: export
-
Install qemu and firmware through xlings (
qemu-x86,qemu-arm) in the image lane instead of apt. That is the only way §1's fix stays fixed. Keep apt OVMF only ifqemu-x86turns out not to ship an x86_64 UEFI firmware; checkshare/qemu/edk2-x86_64-code.fdin its payload. -
luban try: a non-interactive smoke on both architectures, for exampletry --nographicwith a console marker and a timeout, asluban_image_test.shalready does for the ISO. -
Host matrix: flip the tiny-musl aarch64 assertion (§3).
-
Requirements: extend
LUBAN-DRIVE,LUBAN-TRYandLUBAN-BOOT-PROFILEcoverage to aarch64. Add a requirement for "the tool table names only packages that exist".
Acceptance criteria
- On an aarch64 Linux machine with no host qemu or firmware:
xlings install qemu-arm, thenluban new box luban-tiny, thenluban try boxboots to a shell;luban export box --drive box.imgproduces an image that boots underqemu-system-aarch64 -M virtwith edk2.
- On x86_64,
luban tryuses aqemu-x86installed by xlings when the host has none. The printed install hint is an installable package. luban new m luban-tiny-muslworks on aarch64, and a musl-linked program runs inside it.- CI covers all of the above on both architectures. The x86_64 ISO and drive legs are unchanged.
Out of scope / later
- aarch64 on real hardware (
luban-boot-genericwith an aarch64 kernel). Device tree vs ACPI and board-specific firmware make this a separate design;virtis the default on aarch64. - UEFI El Torito in the in-process ISO writer (§2, option b).
- Cross-architecture images and
try, such as an aarch64 image on x86_64 under TCG. - riscv64.
References
- Luban OS design part 2:
.agents/docs/2026-10-10-luban-os-design-part2.md(§4 boot profiles, §9 implementation record) - 2026.10.11.1: Luban OS part 2 -- editions that upgrade (never loosening), boot profiles, musl, isolation probed as policies need it, the host matrix #653, 2026.10.11.2: an edition's archs decide where it is made; the host matrix tests the published index #654, test(host-matrix): an edition not built for the host is checked as refused up front #655; xim-pkgindex #945, #953, #956, #957
Activity
2026.10.16.1: inside a Luban system, the Luban OS app, and what mcpp …