feat(hardware): xe-aware GuC, class-based NPU detect, latestKernel + VM test

Harden the hardware-enablement broad seed for newer hardware:

- xe vs i915: intel.guc emits the i915 param (i915.enable_guc=3), which the
  newer `xe` driver (Lunar Lake / Battlemage / Panther Lake, recent Xe GPUs)
  ignores — it enables GuC by default. hardware-db.sh now reads the in-use
  GPU driver (lspci -k) and writes `intel.guc = false` on xe hardware, so the
  toggle isn't a misleading no-op there.

- NPU detection by PCI accelerator class [1200] (+ keywords), attributing the
  vendor, instead of a fixed device-ID list — so new NPUs (e.g. Panther Lake)
  are caught without a code change. Known IDs kept as a fallback/reference.

- Kernel awareness: a nomarchy.hardware.latestKernel escape hatch
  (linuxPackages_latest) for very-new hardware whose drivers only just landed,
  and a build-time warning when npu.enable predates the shipped kernel
  (amdxdna needs 6.14+, intel_vpu wants recent). Downstream default is 6.18,
  which already carries amd-pstate + amdxdna; the reference host pins latest.

- VM test (checks.hardware-toggles, pkgs.testers.runNixOSTest): boots a
  minimal VM with the toggles on and asserts the config landed — amd_pstate
  + i915.enable_guc in /proc/cmdline, fprintd.service present, pam_fprintd in
  /etc/pam.d/sudo. Passing. (Hardware behaviour still needs bare metal.)

Docs: README + template note latestKernel; ROADMAP records the hardening.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Bernardo Magri
2026-06-18 20:13:31 +01:00
parent c57d26864e
commit bdf20f2d8e
7 changed files with 102 additions and 16 deletions

View File

@@ -226,6 +226,7 @@ examples: **[docs/OVERRIDES.md](docs/OVERRIDES.md)**.
| `nomarchy.hardware.fingerprint.enable` | `false` | fprintd for a detected fingerprint reader (installer-set); enroll with `fprintd-enroll` |
| `nomarchy.hardware.fingerprint.pam` | `false` | Opt-in: use the fingerprint for login + sudo (PAM) |
| `nomarchy.hardware.npu.enable` | `false` | Opt-in/experimental: load the on-die NPU driver (`amdxdna`/`intel_vpu`); userspace runtime is BYO |
| `nomarchy.hardware.latestKernel` | `false` | Opt-in: ship `linuxPackages_latest` instead of the default kernel — for very new hardware whose drivers landed recently |
| `nomarchy.services.tailscale.enable` | `false` | Opt-in: Tailscale mesh VPN (then `sudo tailscale up`) |
| `nomarchy.services.syncthing.enable` | `false` | Opt-in: Syncthing file sync as the login user (GUI at `127.0.0.1:8384`) |
| `nomarchy.services.podman.enable` | `false` | Opt-in: rootless Podman (`docker` aliased to it) |

View File

@@ -279,6 +279,15 @@ how to override it. Items marked ✓ are shipped.
**Remaining: on-hardware verification of the runtime bits (AMD/NPU/Intel
GPU-compute) — none are testable in CI or on the Intel Latitudes for the
AMD paths.** SSD TRIM is intentionally left to `common-pc-ssd`.
-**Hardening (driver-gen + kernel awareness):** `intel.guc` emits the
*i915* param, so the installer turns it off when the GPU is on the newer
`xe` driver (Lunar Lake / Battlemage / Panther Lake — GuC is default-on
there); the NPU detector matches the PCI *accelerator class* (not just a
device-ID list) so new gens are caught without a code change; and a
`nomarchy.hardware.latestKernel` escape hatch (+ a build-time warning when
`npu.enable` predates the shipped kernel) covers very-new hardware whose
drivers only just landed. A config-assertion VM test guards the wiring
(`checks.hardware-toggles`: kernel cmdline + fprintd + PAM, booted in a VM).
Worked example — ThinkPad T14s (Ryzen 7 PRO 7840U + Radeon 780M):
- **GPU compute — ROCm:** the 780M is an RDNA3 iGPU (gfx1103) ROCm doesn't
officially list, so it needs `HSA_OVERRIDE_GFX_VERSION=11.0.0`. Multi-GB

View File

@@ -134,6 +134,31 @@
downstream.nixosConfigurations.default.config.system.build.toplevel;
downstream-template-home =
downstream.homeConfigurations.me.activationPackage;
# Config-level VM assertions for the nomarchy.hardware.* toggles —
# what they SET (kernel cmdline, fprintd, PAM). Real hardware
# behaviour (firmware/driver/device) needs bare metal and is out of
# scope here. Imports only hardware.nix, so the VM stays minimal.
hardware-toggles = pkgs.testers.runNixOSTest {
name = "nomarchy-hardware-toggles";
nodes.machine = { ... }: {
imports = [ ./modules/nixos/hardware.nix ];
nomarchy.hardware = {
intel.enable = true;
amd.enable = true;
fingerprint = { enable = true; pam = true; };
npu.enable = true;
};
};
testScript = ''
machine.wait_for_unit("multi-user.target")
cmdline = machine.succeed("cat /proc/cmdline")
assert "amd_pstate=active" in cmdline, cmdline
assert "i915.enable_guc=3" in cmdline, cmdline
machine.succeed("systemctl cat fprintd.service")
machine.succeed("grep -q pam_fprintd /etc/pam.d/sudo")
'';
};
};
# ─── Reference host ────────────────────────────────────────────

View File

@@ -28,9 +28,12 @@ in
default = cfg.intel.enable;
defaultText = lib.literalExpression "config.nomarchy.hardware.intel.enable";
description = ''
Load the GPU's GuC/HuC firmware (i915.enable_guc=3) better power
management and HuC-accelerated media on Gen11+ (Xe) iGPUs. On by
default with intel.enable; safe on modern Intel graphics.
Load the GPU's GuC/HuC firmware via the i915 param
(i915.enable_guc=3) better power management and HuC-accelerated
media. On by default with intel.enable. NOTE: this is the *i915*
driver's param; the newer `xe` driver (Lunar Lake / Battlemage /
Panther Lake and other recent Xe GPUs) enables GuC by default and
ignores it, so the installer turns this off on xe-driver hardware.
'';
};
@@ -98,7 +101,14 @@ in
the on-die NPU (AI accelerator) kernel driver amdxdna on AMD (Ryzen
AI), intel_vpu on Intel (Core Ultra and newer). Opt-in and experimental:
this loads the in-kernel driver only; the userspace runtime (AMD XRT /
oneAPI Level Zero NPU) is yours to add'';
oneAPI Level Zero NPU) is yours to add. Needs a recent kernel (see
latestKernel)'';
latestKernel = lib.mkEnableOption ''
the latest mainline kernel (pkgs.linuxPackages_latest) instead of the
distro default for very new hardware whose drivers (a fresh NPU, the
`xe` GPU driver, new-platform enablement) only landed recently. Off by
default; the default kernel already carries amd-pstate and amdxdna (6.14+)'';
};
config = lib.mkMerge [
@@ -136,12 +146,32 @@ in
security.pam.services.sudo.fprintAuth = true;
})
# ── Newest kernel for very-new hardware (opt-in escape hatch) ──────
(lib.mkIf cfg.latestKernel {
boot.kernelPackages = lib.mkDefault pkgs.linuxPackages_latest;
})
# ── NPU (in-kernel driver only; userspace runtime is BYO) ──────────
# The driver has to actually be in the running kernel — warn (don't fail)
# when it predates the shipped one, pointing at latestKernel.
(lib.mkIf (cfg.npu.enable && cfg.amd.enable) {
boot.kernelModules = [ "amdxdna" ];
warnings = lib.optional
(!lib.versionAtLeast config.boot.kernelPackages.kernel.version "6.14")
''
nomarchy.hardware.npu: the amdxdna driver needs kernel >= 6.14, but
this config ships ${config.boot.kernelPackages.kernel.version}. Set
nomarchy.hardware.latestKernel = true.'';
})
(lib.mkIf (cfg.npu.enable && cfg.intel.enable) {
boot.kernelModules = [ "intel_vpu" ];
warnings = lib.optional
(!lib.versionAtLeast config.boot.kernelPackages.kernel.version "6.11")
''
nomarchy.hardware.npu: the intel_vpu driver (especially for newer
NPUs) wants a recent kernel, but this config ships
${config.boot.kernelPackages.kernel.version}. Consider
nomarchy.hardware.latestKernel = true.'';
})
# ── Sanity ─────────────────────────────────────────────────────────

View File

@@ -149,6 +149,13 @@ nomarchy_detect_hw() {
if [[ "$cpu_vendor" == "GenuineIntel" || $intelgpu -eq 1 ]]; then
echo "NOMARCHY hardware.intel.enable=true"
echo "DETAIL nomarchy.hardware.intel: GuC/HuC on; GPU-compute runtime opt-in"
# i915.enable_guc applies to the i915 driver only. The newer `xe` driver
# (Lunar Lake / Battlemage / Panther Lake, recent Xe GPUs) enables GuC by
# default and ignores the param — so turn the toggle off when xe is bound.
if lspci -k 2>/dev/null | grep -qiE 'driver in use: xe\b'; then
echo "NOMARCHY hardware.intel.guc=false"
echo "DETAIL Intel GPU on the xe driver → GuC default-on (i915 param skipped)"
fi
fi
if [[ "$cpu_vendor" == "AuthenticAMD" || $amdgpu -eq 1 ]]; then
echo "NOMARCHY hardware.amd.enable=true"
@@ -177,16 +184,22 @@ nomarchy_detect_hw() {
echo "DETAIL fingerprint reader detected → fprintd (PAM login/sudo opt-in)"
fi
# NPU (detect-only → a commented, experimental opt-in). Intel VPU /
# AMD XDNA PCI IDs; best-effort across recent gens.
# NPU (detect-only → a commented, experimental opt-in). Match the PCI
# "Processing accelerators" class [1200] (or accelerator keywords) and
# attribute by vendor — future-proof vs a per-device-ID list, so new gens
# (e.g. Panther Lake) are caught without a code change. Known IDs kept for
# reference: Intel VPU 8086:{7d1d,643e,ad1d,b03e}, AMD XDNA 1022:1502.
if command -v lspci >/dev/null 2>&1; then
if lspci -nn 2>/dev/null | grep -qiE '\[8086:(7d1d|643e|ad1d|b03e)\]'; then
echo "NOMARCHY-NPU intel"
echo "DETAIL Intel NPU detected (opt-in, experimental)"
elif lspci -nn 2>/dev/null | grep -qiE '\[1022:1502\]'; then
echo "NOMARCHY-NPU amd"
echo "DETAIL AMD XDNA NPU detected (opt-in, experimental)"
fi
local npu_line
npu_line=$(lspci -nn 2>/dev/null \
| grep -iE '\[1200\]|processing accelerat|neural|\[8086:(7d1d|643e|ad1d|b03e)\]|\[1022:1502\]' \
| head -1)
case "$npu_line" in
*"[8086:"*|*Intel*)
echo "NOMARCHY-NPU intel"; echo "DETAIL Intel NPU detected (opt-in, experimental)" ;;
*"[1022:"*|*"Advanced Micro Devices"*|*AMD*)
echo "NOMARCHY-NPU amd"; echo "DETAIL AMD XDNA NPU detected (opt-in, experimental)" ;;
esac
fi
# Chassis (glob test, not compgen — nixpkgs' non-interactive bash

View File

@@ -437,11 +437,12 @@ fi
# experimental opt-ins written commented for the user to flip on.
HARDWARE_CONFIG=""
if [[ ${#HW_NOMARCHY[@]} -gt 0 || -n "$NPU_VENDOR" ]]; then
has_intel=0; has_amd=0; has_fp=0
has_intel=0; has_amd=0; has_fp=0; intel_guc_off=0
if [[ ${#HW_NOMARCHY[@]} -gt 0 ]]; then
for nm in "${HW_NOMARCHY[@]}"; do
case "$nm" in
hardware.intel.enable=true) has_intel=1 ;;
hardware.intel.guc=false) intel_guc_off=1 ;;
hardware.amd.enable=true) has_amd=1 ;;
hardware.fingerprint.enable=true) has_fp=1 ;;
esac
@@ -451,7 +452,12 @@ if [[ ${#HW_NOMARCHY[@]} -gt 0 || -n "$NPU_VENDOR" ]]; then
# the heavier opt-ins are commented — uncomment to turn them on."
if [[ $has_intel -eq 1 ]]; then
hw_lines+="
nomarchy.hardware.intel.enable = true; # GuC/HuC firmware (i915.enable_guc=3)
nomarchy.hardware.intel.enable = true; # GuC/HuC firmware (i915.enable_guc=3)"
if [[ $intel_guc_off -eq 1 ]]; then
hw_lines+="
nomarchy.hardware.intel.guc = false; # GPU on the xe driver → GuC is default-on"
fi
hw_lines+="
# nomarchy.hardware.intel.computeRuntime = true; # OpenCL/oneVPL GPU compute (opt-in)"
fi
if [[ $has_amd -eq 1 ]]; then
@@ -467,7 +473,8 @@ if [[ ${#HW_NOMARCHY[@]} -gt 0 || -n "$NPU_VENDOR" ]]; then
fi
if [[ -n "$NPU_VENDOR" ]]; then
hw_lines+="
# nomarchy.hardware.npu.enable = true; # $NPU_VENDOR NPU driver (experimental; userspace runtime BYO)"
# nomarchy.hardware.npu.enable = true; # $NPU_VENDOR NPU driver (experimental; userspace runtime BYO)
# nomarchy.hardware.latestKernel = true; # newest kernel if the NPU driver isn't in the shipped one"
fi
HARDWARE_CONFIG=$(cat <<NIX

View File

@@ -40,6 +40,7 @@
# fingerprint.enable = true; # fprintd; installer-set when a reader is detected
# fingerprint.pam = true; # use the fingerprint for login + sudo
# npu.enable = true; # on-die NPU driver (experimental; userspace runtime BYO)
# latestKernel = true; # newest kernel for very-new hardware (drivers not yet in the default)
# };
#
# nomarchy.services.tailscale.enable = true; # mesh VPN — then `sudo tailscale up`