A fork of sebanc/brunch-unstable that adds support for Intel Lunar Lake (Core Ultra 200V, Xe2 graphics) laptops.
Upstream brunch ships kernels 6.6 / 6.12 and the graphics userspace that comes inside
the ChromeOS recovery image. Neither knows about Lunar Lake: the ChromeOS image carries
Mesa < 25.2.0 (iris has no I915_FORMAT_MOD_4_TILED_LNL_CCS, minigbm has no xe
backend), and the brunch kernel configs disable the Intel IOMMU, which these machines
cannot boot without. This fork adds a 7.1 kernel and a Mesa 25.3.6 userspace override
that fill both gaps, plus the ARCVM and audio fixes that fall out of them.
Everything here is additive: the 6.6 / 6.12 kernels and their patches are still in the tree, upstream behaviour on them is unchanged (with one exception: the external drivers were brought forward so they also build on 7.1 — see External drivers — and the 6.6 / 6.12 builds compile the updated driver sources too), and every patch added here checks the iGPU PCI id before it does anything. Releases, however, only ship the 7.1 kernel: the upstream kernels cannot boot a Lunar Lake machine (their configs disable the IOMMU), so building them here would only spend CI time on kernels this fork's audience cannot use; a full multi-kernel build remains one environment variable away (see Building).
Two later Intel generations get a piece of this as well: Meteor Lake and Arrow Lake need the same Intel SOF firmware overlay — no ChromeOS image carries usable IPC4 firmware for them either — and the same SoundWire UCM profiles, but nothing else, since their graphics run on i915 with the Mesa the ChromeOS image already ships. See Meteor Lake and Arrow Lake. Everyone else is still better served by upstream brunch.
Status: it works. OOBE, login, reboot, re-login, Play Store, Android apps and games, Crostini, audio and suspend all run on the reference machine. See Known limitations before you rely on it.
Developed and tested on an HP OmniBook X Flip, Core Ultra 9 288V, Xe2 8086:64A0,
against the ChromeOS R149, R150 and R151 volteer recovery images. Other Lunar Lake
machines should work — the Lunar Lake patches key off the iGPU PCI id (8086:6420,
8086:64a0, 8086:64b0), not off the laptop model — but nothing else has been tried.
No ChromiumOS 7.1 branch exists, so this kernel is built from a vanilla kernel.org
tree. prepare_kernels.sh learned to fetch one and to build its config from a vendored
distro baseline (kernel-patches/7.1_base_config, Arch Linux's) plus brunch's
brunch_configs and the Lunar Lake additions in 7.1_extra_configs, instead of the
flex/CrOS assembly.
The brunch patch set was forward-ported, plus four ChromeOS kernel behaviours that ChromeOS userspace depends on and vanilla does not have:
| patch | why |
|---|---|
mglru_sysfs_admin.patch |
ChromeOS vm_concierge writes the CrOS-private MGLRU sysfs admin interface. Without it concierge dies at startup, no VM starts at all, and chrome takes a SIGSEGV at login. |
dm_verity_chromeos_table.patch |
imageloader mounts DLCs with a CrOS-private dm-verity table format (payload=/hashtree=/alg=/…). Vanilla dm-verity only parses upstream positional arguments, so every DLC mount fails — Crostini reports "error downloading", cras noise cancellation retries forever. |
drm_master_relax.patch |
ChromeOS relies on relaxed DRM master handover between frecon and chrome. |
kvm_honor_guest_pat.patch |
See ARCVM graphics below. |
Config highlights (kernel-patches/7.1_extra_configs, all commented in place): the
Intel IOMMU is re-enabled over the upstream brunch_configs disable — Lunar Lake
firmware hands the CPU over in locked-x2APIC mode and the kernel panics before any
console exists without DMAR interrupt remapping — and the boot console uses
sysfb/simpledrm rather than efifb, which on these machines maps the GOP framebuffer
uncached and takes seconds per printk line.
Upstream brunch builds its 13 out-of-tree modules (Realtek Wi-Fi, broadcom-wl,
acpi_call, ipts, ithc) only for kernels 6.6 / 6.12, so on 7.1 they were skipped
entirely. This fork ports all of them to the vanilla 7.1 tree. The recurring breakage:
kbuild dropped EXTRA_CFLAGS, the del_timer* / from_timer removals, the 6.14
link_id and 6.17 radio_idx cfg80211 arguments, 7.1 passing struct wireless_dev *
to the cfg80211 key/station ops, and 7.1 hiding the pppoe flexible-array members from
kernel code. Where an active upstream already carried the fixes, the vendored copy was
synced to it (rtl8192eu → Mange, rtl8812au / rtl8821cu → morrownr, rtl885xxx →
morrownr/rtw89); the rest is version-guarded compat, with per-change provenance in the
commit messages. All changes are kernel-version-guarded or version-neutral, so the
6.6 / 6.12 builds keep working — but since the default build went 7.1-only, CI no
longer exercises them; verify with a BRUNCH_KERNELS="6.6 6.12 7.1" build before
sending any of this upstream. On 7.1 the in-tree rtw89 already
covers the rtl885xxx hardware; the external copy is kept so every kernel ships the
same module set.
Replaces libgallium (iris), libEGL, libvulkan_intel (ANV) and libgbm in the running
image. libgbm is the awkward one: on ChromeOS libgbm.so.1 is minigbm, and Chrome,
crosvm, virglrenderer and libcros_camera are all compiled against minigbm's gbm.h,
which is not ABI-compatible with Mesa's. mesa-patches/ carries the shim that bridges
that, and mesa-patches/README.md documents each patch, the
bug it fixes and how it was measured.
The package rebuilds from the six patches plus brunch_minigbm_compat.c against a
pristine mesa-25.3.6.tar.xz; diff -rq against the tree it was built from reports no
differences.
Three separate bugs had to be fixed before Android apps rendered correctly. All three are upstream bugs, not brunch ones:
- venus fences never complete → SurfaceFlinger hangs, Play Store restart-loops.
KVM's
KVM_X86_QUIRK_IGNORE_GUEST_PATforces write-back and the guest's write-combining mappings never see host fence writes. QEMU has-accel kvm,honor-guest-pat=on; crosvm has no such switch, so this is a kernel patch (kvm_honor_guest_pat.patch). - Stray geometry drawn over an otherwise correct frame — on Xe2, ANV silently drops
HOST_CACHEDfor any exportable bo and hands out an uncached scanout PAT entry, while the importer maps the same memory type write-back. Every buffer venus gives a guest is exportable. (mesa-patches/0002) - Every ARC window rendered as vertical stripe noise — ANV placing bos in
compressed PAT memory, which is broken under an ARCVM guest. (
mesa-patches/0006)
87-arcvm_seccomp.sh additionally neutralizes the crosvm seccomp filters. The ChromeOS
crosvm binary embeds pre-compiled seccomp BPFs built for the volteer image; they lag
crosvm's own tube code and SIGSYS-kill the virtio-fs/gpu device workers on
recvfrom/recvmsg, tearing ARCVM down before the Play Store can start.
The same stale filters also kill termina/Crostini: its virtio-wl worker dies on
recvfrom the moment a GUI app connects through sommelier, taking the whole VM down
(the terminal is unaffected because vsh runs over vsock, never touching virtio-wl).
--seccomp-policy-dir does not override these embedded filters for the device workers
in the shipped build, so the patch preloads a small shim (arcvm-noseccomp/) into
crosvm for concierge-managed VMs (ARCVM and termina) that no-ops the seccomp filter
installation while leaving every other minijail jailing — namespaces, ugid map, caps,
rlimits — intact.
build_brunch.sh assembles brunch's firmware package from a linux-firmware checkout
plus the lib/firmware/intel/sof* directories of the ChromeOS rootfs it builds against.
linux-firmware no longer carries any Intel SOF firmware (its WHENCE lists none), so the
Intel SOF files in packages/firmwares.tar.gz come from the ChromeOS rootfs alone:
- CI builds use the ChromeOS Flex (reven) rootfs, which ships an IPC4 set, but an old
one: SOF 2.12 (March 2025) as of R150, with a thinner topology set (no
sof-lnl-dmic-*,sof-sdca-*,sof-ptl-*, ...). - A build against a Chromebook recovery image (volteer etc.) gets IPC3 only
(
intel/sof,intel/sof-tplg): nointel/sof-ipc4at all, and Lunar Lake has no sound. - A build against a Meteor Lake Chromebook image (rex) does not fix this either.
ChromeOS keeps its firmware in per-model directories
(
intel/sof-ipc4/mtl/{community,karis}/sof-mtl.ri, not theintel/sof-ipc4/mtl/sof-mtl.ripci-mtl.casks for), keeps its topologies inintel/sof-ace-tplgrather thanintel/sof-ipc4-tplg, and ships only the four topologies that board itself uses.build_brunch.shcopies those paths verbatim.
86-intel_sof_fw.sh therefore overlays a current sof-bin release, after
50-add_generic_firmwares.sh so its files replace the rootfs copy:
intel/sof-ipc4/{lnl,mtl,arl,arl-s}, intel/sof-ipc4-lib/lnl and the whole
intel/sof-ipc4-tplg
directory of sof-bin v2025.12.2
(SOF 2.14.1), uncompressed and byte-for-byte as released — that release has no
sof-ipc4-lib for anything but lnl, and its arl / arl-s firmware is mostly
symlinks into mtl. The patch triggers on Lunar Lake, Meteor Lake and Arrow Lake iGPU
ids; the topology directory covers PTL / WCL as well, but no firmware for those is
shipped, since their graphics do not work here yet. To regenerate the package from a
sof-bin release:
curl -LO https://github.com/thesofproject/sof-bin/releases/download/v2025.12.2/sof-bin-2025.12.2.tar.gz
tar xzf sof-bin-2025.12.2.tar.gz
mkdir -p stage/lib/firmware/intel/sof-ipc4 stage/lib/firmware/intel/sof-ipc4-lib
for p in lnl mtl arl arl-s; do
cp -a sof-bin-2025.12.2/sof-ipc4/"$p" stage/lib/firmware/intel/sof-ipc4/
done
cp -a sof-bin-2025.12.2/sof-ipc4-lib/lnl stage/lib/firmware/intel/sof-ipc4-lib/
cp -a sof-bin-2025.12.2/sof-ipc4-tplg stage/lib/firmware/intel/
tar -C stage --sort=name -czf packages/intel-sof-fw.tar.gz lib --owner=0 --group=0Most Lunar Lake laptops (and the Meteor/Arrow Lake Dell XPS line) do not use an HDA
codec: audio is a SoundWire cs42l43 headset codec plus cs35l56 amplifiers,
registered by the kernel as the sof-soundwire card. The card probes fine and still
produces no sound, because the alsa-ucm-conf release brunch has to ship (1.2.8, the
one ChromeOS's alsa-lib can parse) has no profile for these codecs — the UCM fails to
load, and without one cras guesses nodes from mixer control names, which are all
prefixed on these codecs, so it ends up with a phantom "Speaker" on the headphone PCM.
The overlay adds cras-specific profiles (fully specified PCM numbers, jack input
devices, amplifier switches) for the Cirrus SoundWire combinations and for every Realtek
SoundWire part in the 7.1 Intel machine tables (rt711, rt712, rt713, rt721, rt722, the
rt1308 / rt1316 / rt1318 / rt1320 amplifiers, the rt715 / rt1712 / rt1713 microphone
parts), written against the 7.1 kernel drivers and the upstream alsa-ucm-conf 1.2.16
profiles and parse-tested against alsa-lib 1.2.8. Anything else keeps the upstream 1.2.8
behaviour.
See alsa-ucm-conf/ucm2/sof-soundwire/cras/README.md.
Meteor Lake (Core Ultra 100) and Arrow Lake (Core Ultra 200H / U / S) need far less than
Lunar Lake does, because unlike Lunar Lake they are generations ChromeOS itself supports.
Both run on i915, not xe — 7.1's xe driver still marks them
require_force_probe, and brunch's kernel configs set CONFIG_DRM_I915_FORCE_PROBE="*"
— and the Mesa 24.2.3 inside the ChromeOS image already knows them: the
libgallium_dri.so of a volteer R149 image carries the Intel(R) Arc(tm) Graphics (MTL)
and Intel(R) Graphics (ARL) device entries. The Mesa override in this fork therefore
does not apply and does not switch on — 85-mesa_lnl.sh checks for a Lunar Lake iGPU id
first. Do not force it on with lnl_mesa: the minigbm ABI shim and the chrome flags in
that package were built and measured for Xe2 alone.
What does carry over is audio, for exactly the reason it does on Lunar Lake:
- SOF firmware. MTL and ARL are IPC4-only, and
snd-intel-dspcfgpicks SOF over the legacy HDA driver whenever the machine has digital mics or SoundWire links (FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,sound/hda/core/intel-dsp-config.c) — nearly every laptop. With nointel/sof-ipc4in the image, SOF has nothing to load and the machine is silent.86-intel_sof_fw.shinstalls the firmware for these platforms too and triggers on their iGPU ids. - SoundWire UCM profiles. They were written from the 7.1 Intel machine tables, which
cover Meteor / Lunar / Arrow / Panther Lake, and
50-add_generic_firmwares.shinstalls them unconditionally — no PCI id gate at all.
Three things worth knowing before trying it:
- The Intel IOMMU is enabled in this kernel. Upstream brunch's configs disable it,
and a machine whose firmware hands the CPU over in locked x2APIC mode cannot boot
without DMAR interrupt remapping. That is a firmware property rather than a
generational one — it is universal on Lunar Lake, and some Meteor / Arrow Lake laptops
are in the same position.
sudo rdmsr 0xBD(msr-tools, from any Linux) answers it: bit 0 set means legacy xAPIC is disabled, so the IOMMU is required. This fork's kernel enables it either way. - ARCVM may need the
arcvm_seccompoption. The stale crosvm seccomp filters are a property of the ChromeOS image, not of the CPU, but they have only been observed here on Lunar Lake, so87-arcvm_seccomp.shstill gates on Lunar Lake ids. If ARCVM hangs at "Starting Play Store..." or Crostini dies the moment a GUI app opens, addarcvm_seccompto force the shim on. - If there is still no sound, there is a one-line fallback: add
snd_intel_dspcfg.dsp_driver=1to the kernel command line in GRUB. That forces the legacy HDA driver, which needs no firmware at all; on a machine with an analog HDA codec speakers and headphones come back, at the cost of everything that goes through the DSP (the digital mic array). Machines whose audio is SoundWire-only have nothing to fall back to.
None of this has been tried on Meteor or Arrow Lake hardware — there is none here. What
is verified is only that the right firmware and topologies now ship, and which iGPU ids
switch the patch on (86-intel_sof_fw.sh).
Same as upstream:
./prepare_kernels.sh # downloads and patches the kernel trees
./build_kernels.sh # or ./build_kernels.sh 7.1 for just this one
sudo bash build_brunch.sh <recovery_image.bin>prepare_kernels.sh prepares only 7.1 by default — the kernel this fork is about.
Run BRUNCH_KERNELS="6.6 6.12 6.18 7.1" ./prepare_kernels.sh for a full upstream-style
build; 6.6 / 6.12 support has not been removed, it is just not built by default.
GitHub Actions builds on push (.github/workflows/build.yml); its kernel matrix comes
from whatever prepare_kernels.sh prepared, so CI and releases are 7.1-only too.
Release kernels are signed with this fork's own key (see Secure
Boot below); a fork without the BRUNCH_PRIV / BRUNCH_PEM secrets set will produce
unsigned kernels, which boot fine but cannot be used with Secure Boot.
Pick 7.1 in brunch-setup at install time — in a 7.1-only build it is the only
entry and already preselected, since the menu is generated from the kernels the build
actually ships. The patches then activate on their own; no_lnl_mesa,
no_sof_firmware and no_arcvm_seccomp turn them off individually (no_lnl_audio_fw,
the name the firmware patch used while it only covered Lunar Lake, still works).
The boot chain is: Microsoft-signed Debian shim (bootx64.efi) → GRUB, signed by
upstream brunch's key → kernel, signed by this fork's key (upstream cannot share its
private key, so forks sign kernels themselves). Two certificates therefore have to be
enrolled in MOK, and both ship at the root of the EFI partition:
brunch.der— upstream brunch's certificate, verifies GRUBbrunch-lnl.der— this fork's certificate, verifies the kernels
Enroll them either from a Linux system:
sudo mokutil --import brunch.der
sudo mokutil --import brunch-lnl.deror directly at the blue "Verification failed" screen on the first Secure Boot boot:
OK → Enroll key from disk → EFI-SYSTEM → select each .der in turn → Continue, reboot.
With Secure Boot disabled none of this matters — unsigned or differently-signed kernels boot normally.
- "Sign in with your Android phone" does not work at OOBE. Sign in with a password instead. Not chased down, and not established as Lunar Lake specific.
- ARCVM Play Store can crash once after suspend/resume. The VM survives (crosvm keeps running); a venus GPU context can enter a fatal state on the first resume and the Android app using it is dropped, so re-opening it recovers. Timing-dependent and not reliably reproducible. Same family as the ARCVM graphics bugs above (venus/ANV on Xe2 under a VM).
- One machine. Verified on a single laptop model. The 7.1 kernel config comes from an Arch baseline, so hardware Arch does not enable is not covered.
- Meteor Lake and Arrow Lake are untested. The SOF firmware for them ships and the
iGPU id gate was tested against a synthetic
/systree, but no such machine has run this. See Meteor Lake and Arrow Lake. - The SoundWire audio profiles are untested on hardware. The reference laptop has an
HDA codec; the
sof-soundwirecras profiles were written from the kernel driver and upstream UCM sources and only parse-tested. Reports from cs42l43 / cs35l56 and Realtek SoundWire machines (crasmessages in/var/log/messages,amixer -c0 controls) are what they need. mesa-patches/0003and0004de-advertise the Xe2 CCS DRM modifiers to any importer. They are not what fixed the stripe-noise bug (0006was), but they are kept: any consumer using a minigbm older than Lunar Lake cannot interpret those modifiers.- Cosmetic leftovers seen in logs and not chased down:
unknown rutabaga pathfrom crosvm, ~60 virglrendererGL error (1282)lines during ARCVM startup, and NV12 128×128bo_createfailures believed to come from the ARC camera stack.
Worth reporting, and worth knowing about if you hit them elsewhere:
- Mesa/ANV —
HOST_CACHEDdropped for exportable bos on Xe2 (0002). - Mesa/ANV — bos in compressed PAT memory are corrupt inside a VM guest (
0006). Only the location is established, not the mechanism: on the host, compression round trips cleanly in every test. - Mesa/ANV and Mesa/iris — both advertise the Xe2 CCS modifiers to importers that
cannot decode them, and each has its own independent modifier filter, so a fix to the
shared ISL code reaches only ANV (
0003,0004). - brunch —
brunch-patches/82-features.sh:31writes--enable-hardware-overlays="single-fullscreen,single-on-top"; the quotes end up inside the flag value, so Chrome rejects both strategies (overlay_strategy.cc) and hardware overlays are silently off. Left as upstream wrote it, so this fork stays comparable.
All of brunch is sebanc's work; this fork only adds a platform. Please send general brunch issues and pull requests upstream — file things here only if they are Lunar Lake specific.
The releases in this repository are experimental. Use at your own risk.