Skip to content

Test the N1x install on what Omarchy reads from an N1x's firmware - #294

Merged
emirb merged 6 commits into
quattrofrom
arm/n1x-real-detection
Oct 19, 2026
Merged

emirb merged 6 commits into
quattrofrom
arm/n1x-real-detection

Conversation

@emirb

@emirb emirb commented Oct 19, 2026

Copy link
Copy Markdown
Contributor

Every aarch64 install test, and the aarch64 nightly, has failed its N1x pass since Oct 18: the installer took the plain aarch64 default set and no NVIDIA module was built.

The N1x pass made the live ISO believe it was an N1x by replacing its omarchy-hw-platform through cloud-init's write_files, and the test reached the live system as root with a key cloud-init installed. Since systemd 262.1 reached the ARM mirror, cloud-init no longer runs on the live ISO at all: its generator looks for the CIDATA volume once, at 2.92 s on a held runner, and the USB stick's disk attached at 3.235 s, so it turned cloud-init off for the boot. Even before that, the faked detector only reached the live ISO. In the installed system omarchy-hw-platform saw a QEMU board, so install/hardware/n1x.sh and fix-n1x-gpu-memory.sh ran and did nothing, and no check looked.

This makes the N1x pass's VM look like an N1x to Omarchy's own detector, and drops cloud-init from the test:

  • The install test boots with ACPI, as an N1x does (acpi=off had come in with its=off for an ITS problem; the machine keeps gic-version=3,msi=gicv2m). test/arm64-live-boot still boots with the device tree, so both stay covered.
  • test/arm64-n1x builds a small UEFI driver that the firmware runs from a PCI option ROM before it boots anything. It adds an SSDT declaring \_SB.I2C0 with _HID NVDA0200 through the firmware's ACPI table protocol, and creates EXPOSED_DISP_FRM as N1x firmware ships it. QEMU's virt machine refuses -acpitable, and a PCI 10de:2e06 GPU can't be faked without vfio.
  • The N1x pass checks the installed system's detector names the platform, so a VM that isn't seen as an N1x fails instead of passing on the live ISO's say-so.
  • The test watches the installer's screen for a halted install, as the x86_64 test does, instead of SSH into the live system. CIDATA carries only the installer's own inputs, read by omarchy-cidata-load.

On a Namespace arm64 runner, the N1x pass held all twelve checks: the installed system's detector says aarch64-n1x, n1x.sh logged "Detected NVIDIA N1x platform", the GPU memory reservation was set to 4 GiB, the installed system booted the N1x kernel command line, and the NVIDIA DKMS module was built for the running kernel. The generic pass holds all nine checks under ACPI. Real N1x installs are unaffected; they never relied on cloud-init.

This unblocks the aarch64 nightly and the aarch64 check on #293.

emirb added 6 commits October 19, 2026 23:01
An NVIDIA N1x laptop boots with ACPI and no device tree, as GB10
desktops and Arm servers do, and Omarchy tells an N1x by a device its
ACPI tables describe. The install test's machine had acpi=off. That
came in with its=off in 95ce390, for a reason that was about the ITS:
under nested KVM on Namespace's Apple-backed runners an ITS loses MSIs.

The machine keeps gic-version=3 and msi=gicv2m and turns ACPI on, so
the firmware hands what it boots QEMU's ACPI tables and no device tree.
QEMU 11.1.2 describes the GICv2m in the MADT as a GIC MSI frame
whenever msi=gicv2m (hw/arm/virt-acpi-build.c), and Linux's GICv3
driver, finding no LPIs without an ITS, registers that frame for PCI
MSIs (drivers/irqchip/irq-gic-v3.c, irq-gic-v2m.c).
test/arm64-live-boot still boots the ISO with the device tree, so both
ways in stay covered.

On the Apple-backed runner the live ISO booted under ACPI, installed,
and the installed system came up through Limine and held all nine
checks of the generic pass, on SSH 175 s after QEMU started.
The N1x pass replaced the live ISO's copy of omarchy-hw-platform with
one that printed aarch64-n1x, through cloud-init's write_files, and
that is all it changed. The install's own N1x steps run in the target,
where omarchy-hw-platform reads the hardware: it saw a QEMU board, so
install/hardware/n1x.sh and fix-n1x-gpu-memory.sh did nothing and the
installed system booted none of the N1x's settings. A passing N1x run
from Oct 19 shows it: the N1x default set in the install log, both
scripts started and completed with no output, a plain kernel command
line. No check looked.

Since Oct 18 cloud-init has not run on the live ISO at all. Its
generator looks for the CIDATA volume once; on a held runner it looked
at 2.92 s and the USB stick's disk attached at 3.235 s, so it turned
cloud-init off for the boot and the pass took the plain default set.

Ask the installed system what it is: omarchy-hw-platform there has to
name $PLATFORM, and the check says what it named. The N1x pass fails
it here, as it should: the VM is not an N1x yet.
Omarchy knows an N1x by its firmware. omarchy-hw-platform names it
aarch64-n1x when ACPI describes an NVDA0200 device (its MediaTek I2C
controllers) or the GPU is PCI 10de:2e06. The install then sizes the
GPU's memory reservation through EXPOSED_DISP_FRM, the EFI variable
every N1x firmware has: omarchy-apply-n1x-gpu-memory exits 1 without
it, and omarchy-apply-hardware, which runs the N1x steps under set -e,
stops there.

The N1x pass's VM now has both. test/arm64-n1x builds a UEFI driver
with gnu-efi that adds an SSDT declaring \_SB.I2C0 with _HID NVDA0200
through the firmware's own ACPI table protocol, and creates
EXPOSED_DISP_FRM as an N1x ships it (62.5 GiB, the bytes omarchy's own
test uses) when the variable is not there yet. QEMU's virt machine
refuses -acpitable ("Option not supported for this target"; only x86
and LoongArch take user tables), so the driver rides in a PCI option
ROM on the VM's RNG and the firmware runs it while it enumerates PCI,
before it boots anything. Nothing on the ISO or the installed system
changes, and the cloud-init write_files that faked the detector goes.

The device has no resources, so linux-omarchy's i2c-mt65xx, which
binds NVDA0200, gives up at its first register window. A PCI 10de:2e06
GPU is no option: only QEMU's vfio devices take another device's IDs,
and the NVIDIA driver would try to run it.

Firmware and the edge kernel (7.2.8-14) under TCG, with omarchy's
detector: without the ROM it said aarch64 and there was no variable;
with it, /sys/bus/acpi/devices/NVDA0200:00 (\_SB_.I2C0), aarch64-n1x,
and EXPOSED_DISP_FRM byte for byte as omarchy's test has it. On the
Apple-backed runner the N1x pass held all twelve checks: the installed
system's detector says aarch64-n1x, n1x.sh logged "Detected NVIDIA N1x
platform" and "GPU drives the panel", fix-n1x-gpu-memory set the
reservation to 4 GiB, and the installed system booted the N1x's kernel
command line (mem_sleep_default=s2idle, pci=hpbussize=0x20,
initcall_blacklist=simpledrm_platform_driver_init) with no unit failed
and Hyprland up. The container installs acpica, gnu-efi, gcc and
binutils only for a PLATFORM pass.
The test logged in to the live system as root, with a key cloud-init
installed from the CIDATA volume, to see whether the installer had
stopped and to read its log. Since Oct 18 cloud-init has not run on the
live ISO, so that way in was gone: on the run where the install
stopped at mise-work.sh ("bundled Node.js tarball missing"), the test
waited its whole 1500 s and said the live system gave no installer
log.

When the installer stops, its dashboard says so on the screen, with
the failed phase and the last lines of its log, and the x86_64 test
reads that screen. So does this one now, from the screenshots it takes
every 20 s anyway, and it keeps the screen as shots/halted.png. Nothing
reads cloud-init's user-data any more, and CIDATA carries only the
installer's own inputs, read by omarchy-cidata-load.

Run against that run's 71 screenshots, the new check matched every one
from 0139.png on and none of the six before it: the test would have
stopped at 139 s and printed the failed phase and "Error: bundled
Node.js tarball missing from /opt/packages".
The ROM's PCI data structure named class 0x000000. UEFI's recommended
driver layout (UEFI 2.10 table 14.18) takes the class code from the
controller the ROM is on, and QEMU's virtio-rng-pci reports 0x00ff00.
edk2 does not read the field, so nothing behaved differently, but the
ROM now describes the device it rides on. The comments also cited UEFI
14.4.2 for the expansion ROM header, which is PollMem(); the header is
14.4.21, table 14.16. EFI_ACPI_TABLE_PROTOCOL is 20.1, not 20.2.

Rebuilt in the CI's Arch Linux ARM image and booted with the edge
kernel under TCG, as before: the kernel found NVDA0200:00 at
\_SB_.I2C0, omarchy-hw-platform said aarch64-n1x, and
EXPOSED_DISP_FRM held the shipped bytes.
The option ROM's driver took every GetVariable answer other than
EFI_NOT_FOUND to mean EXPOSED_DISP_FRM was there, a device error or a
security violation included. Now EFI_SUCCESS and EFI_BUFFER_TOO_SMALL
mean it is there and it is left as it is, EFI_NOT_FOUND creates it,
and any other answer is returned as the driver's status with nothing
written. The comment on the ROM's layout now names sections 14.4.21
to 14.4.23 of UEFI 2.10, where tables 14.16 and 14.18 are.

Rebuilt in the CI's Arch Linux ARM image and booted with the edge
kernel under TCG: without the ROM omarchy-hw-platform said aarch64 and
there was no variable; with it NVDA0200:00 was at \_SB_.I2C0, the
detector said aarch64-n1x, and EXPOSED_DISP_FRM held the bytes
omarchy's own test ships with, byte for byte.
@github-actions

Copy link
Copy Markdown

Install test passed

x86_64 vs quattro aarch64 vs quattro
Result ✅ passed ✅ passed
Build the ISO 149.0 s +11.0 s 281.0 s −13.0 s
Install 84.9 s +1.2 s 120.0 s −0.0 s
First boot 14.4 s −1.4 s 6.3 s +0.0 s
Everyday boot 14.4 s −0.3 s 5.0 s −0.1 s

Boots are loader, kernel and userspace, without the VM's firmware.

Install phases, x86_64
Phase This PR quattro
Preparing live environment 0.2 s 0.1 s
Preparing install target 0 s 0 s
Installing Arch + Omarchy 69.7 s 69.2 s
Configuring hibernation 0.3 s 0.2 s
Configuring system 2.4 s 2.4 s
Staging provisioning 0.2 s 0.2 s
Finalizing Limine boot 8.6 s 7.9 s
Finalizing user 3.2 s 3.2 s
Configuring login 0.1 s 0.1 s
Configuring SSH access 0.2 s 0.2 s
Configuring Tailscale 0 s 0 s
Configuring DNS resolver 0 s 0 s
Validating boot setup 0 s 0 s
Creating factory snapshot 0 s 0 s
Install phases, aarch64
Phase This PR quattro
Preparing live environment 0.1 s 0.1 s
Preparing install target 0 s 0 s
Installing Arch + Omarchy 103.7 s 105 s
Configuring hibernation 0 s 0 s
Configuring system 4.3 s 4.8 s
Staging provisioning 0.1 s 0.1 s
Finalizing Limine boot 7.4 s 6.7 s
Finalizing user 3.9 s 2.9 s
Configuring login 0.1 s 0.1 s
Configuring SSH access 0.1 s 0.1 s
Configuring Tailscale 0 s 0 s
Configuring DNS resolver 0 s 0 s
Validating boot setup 0.1 s 0.1 s
Creating factory snapshot 0.1 s 0.2 s

Run · cbfab40

@emirb
emirb merged commit e1bf72b into quattro Oct 19, 2026
8 checks passed
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.

1 participant