Skip to content

soc: apple: sep: boot the enclave on every Mac (fixes the M1/M2 microphones, #141) - #180

Open
ludagoo wants to merge 3 commits into
omacom:integration/aurorafrom
ludagoo:fix/sep-boot-microphones
Open

ludagoo wants to merge 3 commits into
omacom:integration/aurorafrom
ludagoo:fix/sep-boot-microphones

Conversation

@ludagoo

@ludagoo ludagoo commented Oct 22, 2026 •

Copy link
Copy Markdown

Fixes #141.

Summary

The built-in microphones of the M1 and M2 laptops only work once the Secure Enclave has been booted: it sits in the path of the microphone data lines (Asahi Linux, 6.14 progress report: "If SEP is unhappy, you don't get mic access"). Since the SEP driver was replaced by the Touch ID driver, the enclave is no longer booted on a plain install: the driver fails its probe at the xART store when it is built in and probes early, and as a module it exports no alias (36ebdee), so only the aurora-touchid loader units load it. Omarchy does not ship those units. The AOP's PDM capture then runs on a constant input and every recording is a null stream.

This is also what blocks Touch ID on Omarchy Mac: omacom/omarchy-mac-pkgs#12 (draft) lists "a kernel whose apple_sep binds on a normal boot: built in, it probes before the iBoot partition link exists and fails" and "the owner's agreement before the driver is loaded or bound: with its defaults it provisions a keybag ... so this package does not load it" as its first two open items. The commits below address those points, and a later commit corrects the "changes nothing" claim.

soc: apple: sep: boot the SEP even when the xART store is unavailable: an unavailable or invalid store no longer aborts the probe; the enclave is booted and the xARM path keeps refusing its store requests (Touch ID and trusted keys stay off for that boot). No xART write happens.

soc: apple: sep: autoload the driver and wait for the iBoot container: the module alias is exported again; a cold boot whose store open fails with ENODEV waits for the container's partition link (500 ms steps, up to 30 s) before booting; xart_writes and provision_keybag default to 0, and aurora-touchid ships /usr/lib/modprobe.d/apple-sep.conf enabling both. A load the owner did not ask for does not write xART or provision a keybag. It does create /var/lib/aurora-sep-host-state.bin (2359296 bytes) the first time that Linux-only store is opened. The existing apple-sep.service/.path stay harmless where the device tree already enables the SEP node.

Machine and build

  • MacBook Air 13" (M1, 2020), board apple,j313, SoC apple,t8103, Omarchy Mac (Arch Linux ARM)
  • Last known good: linux-aurora 7.1.12.aurora2-12 (7.1.12-2-12-ARCH, aurora-silicon/linux 2439016d, CONFIG_APPLE_SEP=y with the earlier stub driver that only boots the enclave).
  • Broken: 7.1.12.aurora7-2 (issue J313 (MacBook Air M1): built-in mic capture returns a fixed looping pattern instead of audio #141), the Oct 8 release build 7.1.12.aurora2-12.6 (CONFIG_APPLE_SEP=m, no alias), 7.1.12.aurora8-1 (CONFIG_APPLE_SEP=y, probe fails at the xART store at 0.55 s), 7.2.10.aurora1-2 (7.2.10-1-2-ARCH, 1b4997b, =m, no alias, module never loaded).
  • m1n1-aurora 1.6.1.aurora1-3, uboot-asahi 2026.07.asahi2-4, omarchy-mac-boot 20261020-2, asahi-audio 4.1-1, alsa-ucm-conf-asahi 10-1, pipewire 1.6.9, wireplumber 0.5.18
  • asahi,os-fw-version: 13.5 (22G74). No Touch ID units or aurora-touchid package installed.

Reproduction, expected result, actual result

  1. Boot a broken build. The AOP card AppleJ313HPAI is present and PipeWire can open it. lsmod shows no apple_sep, or (aurora8) dmesg shows apple_sep 242400000.sep: xART gigalocker in the iBoot container is unavailable or invalid: ENODEV and nothing after it.
  2. arecord -D hw:AppleJ313HPAI,0 -f FLOAT_LE -c 3 -r 48000 -d 3 -t raw cap.raw while talking.

Expected: three live channels (rms about 5e-4, half the samples negative).

Actual on every broken build, every capture, every boot: the capture completes at the right rate but, after a power-on ramp, every word is 0 or at the float flush-to-zero floor (exponent 1 to 2), none negative, channel 0 bit-identical to channel 1: a constant PDM input. asahi-audio's effect_output.j313-mic and omarchy-mac's omarchy_asahi_mic carry silence.

Confirmation that the SEP boot is the missing piece, on the same boot of 7.1.12.aurora2-12.6 rebuilt with the Oct 8 tree (7.1.12-2-12.7-bisect1-ARCH):

$ arecord ... -> null stream (as above)
$ sudo modprobe apple_sep
apple_sep 242400000.sep: SEP platform profile: T8103/J313
apple_sep 242400000.sep: xART: APFS-resolved .gl extent (base 0x4d4000); 170 slots, 13 live records, max revision 28288, 0 malformed, 0 duplicate, 0 repaired; writes ENABLED
apple_sep 242400000.sep: boot: first TZ0 acknowledgement
apple_sep 242400000.sep: boot: TZ0 accepted; handing over firmware and shared memory
apple_sep 242400000.sep: boot: IMG4 acknowledged; the SEP owns the shared-memory table
apple_sep 242400000.sep: attach: 7 endpoints advertised in 20 messages
$ arecord ... -> live audio, rms 4.6e-4 on all three channels

The AOP's own log is identical on working and broken boots (PDMDev<pdm0> off ->xi0 , 0->2400000 AP state 1, ===( AOP IS READY )===); no ADMAC, DART or aop_audio error. Excluded by tests before the cause was found: the device tree (SPI2/Mesa and ANE overlays), the AOP core rewrite (the Oct 8 tree rebuilt with the earlier aop.rs is still silent), the ADMAC DMA mask, and the audio DMA path (the captured stream is real-time paced and starts with the same power-on ramp as a live capture).

Test of the earlier commits

linux-aurora 7.2.10.aurora1-3 test build = 1b4997b (the Omarchy 7.2.10 pin; its SEP sources are identical to the current integration/aurora head) + the two commits, Omarchy configuration, clang 22 / rustc 1.93.1. No loader units installed. Three boots so far, all the same:

$ lsmod | grep apple_sep
apple_sep             360448  0
$ modinfo apple-sep | grep alias
alias:          of:N*T*Capple,sep
alias:          of:N*T*Capple,sepC*
[   17.185856] apple_sep 242400000.sep: SEP platform profile: T8103/J313
[   17.189722] apple_sep 242400000.sep: xART: APFS-resolved .gl extent (base 0x4d4000); 170 slots, 14 live records, max revision 28303, 0 malformed, 0 duplicate, 0 repaired; writes disabled
[   17.196928] apple_sep 242400000.sep: trusted-keys: registering "trusted" key type backed by the SEP ref-key seal
[   17.200690] apple_sep 242400000.sep: boot: first TZ0 acknowledgement
[   17.227897] apple_sep 242400000.sep: boot: TZ0 accepted; handing over firmware and shared memory
[   17.306010] apple_sep 242400000.sep: boot: IMG4 acknowledged; the SEP owns the shared-memory table
[   17.920448] apple_sep 242400000.sep: attach: 7 endpoints advertised in 20 messages
[   20.624112] apple_sep 242400000.sep: sks: capability word 2, IPC header version 2
[   21.057123] apple_sep 242400000.sep: hwrng: registered after ready-phase survey (attempt 1)

On this boot udev loaded the driver after the partition link existed, so the store opened at probe (read-only, the new default) and the wait path was not exercised; the wait path is what the earlier built-in configuration (aurora8, probe at 0.55 s, ENODEV) would take.

  • arecord -D hw:AppleJ313HPAI,0 -f FLOAT_LE -c 3 -r 48000 -d 3: live audio on all three channels (rms 4.4e-5 to 4.8e-5 in a quiet room, 48 % negative samples, no flush-to-zero words). About 106 AOP ADMAC interrupts per 3 s capture, as on the last good build.
  • PipeWire: pw-record --target omarchy_asahi_mic (omarchy-mac's mapped mic, fed by asahi-audio's effect_output.j313-mic): live signal, rms 9e-4, peaks 5e-2 while speaking.
  • The only kernel warning of the boot (WARNING: drivers/clk/clk-devres.c:316 at devm_clk_match, dcp_comp_unbind of 271c00000.dcp in appledrm) is the T8103 display DMA-window regression of J313: oversized T8103 external display DMA windows force simpledrm fallback #178 / arm64: dts: apple: constrain T8103 external display DMA windows #179, also present on stock 7.2.10.aurora1-2 and unrelated to this change.

Session build on the running kernel

Monday 26 Oct 2026 05:02 PM -03: linux-aurora 7.2.11-6-2-ARCH (package 7.2.11.aurora6-2), branch local/j313-test at 7638df0. makepkg exited 0. rustc 1.85.0, LLVM/clang 18.1.8. This machine is running that kernel. The two stacked commits compiled in were 56fa018 (boot the SEP even when the xART store is unavailable) and 90fbe1e (autoload the driver and wait for the iBoot container). This pull request's earlier head commits are c1c1299 and 0dfa5ae, which are not the commits that were built.

lsmod shows apple_sep loaded. On the previous kernel, 7.2.11-6-1-ARCH, effect_output.j313-mic recorded a peak of 0. On this kernel that source peaked at 12779 on the 18:46 boot and 1451 on the 19:23 boot. omarchy_asahi_mic peaked at 23831 and 2058 on those same boots. The raw three-channel arecord check was not repeated on this kernel.

Follow-up, not hardware-tested

21d2c815fef977ca73ca23afdbab5f4e59ba87fc (soc: apple: sep: refresh deferred boot and drop a failed keybag):

  • Kconfig asks for a module so modprobe.d options reach the driver. Built-in, xart_writes and provision_keybag arrive only on the kernel command line. In-tree release16, release18, and release19 configs are already CONFIG_APPLE_SEP=m. The Omarchy packaging files kernel-fixes/pkg/config and kernel-fixes/pkg/recipe/config are also CONFIG_APPLE_SEP=m. They are not in this repository, so they are not part of this pull request.
  • After the iBoot container opens late, the cached xART diag facts are refreshed before attach. Settle is armed after that deferred attach. The store-wait work is joined after shutdown starts and before the mailbox is dropped. A tick blocked in the store open does not attach or publish the boot marker once shutdown has started.
  • A keybag create that is not sent, or that the enclave answers with a non-zero status, removes the 52-byte uncommitted /var/lib/aurora-sep-keybag.bin header. A create that was sent and not answered keeps the intent. A committed bag is left in place.
  • The README says the loader is no longer required only where the device tree already enables the SEP node (M1 family and J700). M2, M2 Pro/Max, and M3 Air nodes stay disabled in the device tree and are enabled by module init, so those machines still need the loader. A default load, including xart_writes=0, still creates the 2359296-byte host-state file. That is not an xART write.
  • load-driver writes /usr/lib/modprobe.d/apple-sep.conf only when that file is absent, then modprobes without inline options so the file applies. If apple_sep is already loaded without xart_writes=1 and provision_keybag=1, the script exits and asks for a reboot. An existing conf is not overwritten.

This commit was not compiled here. The SEP checkout does not include include/ or fs/, so store_shim.c was not built. It is not hardware-tested.

What was not tested

  • Touch ID enrol/verify with the new defaults (no aurora-touchid here; this board has no Touch ID support under Linux yet), the MacBook Neo (T8140) warm-attach profile, M2/M3 boards, and the microphone under macOS on this unit.
  • The 30 s wait path itself (udev created the partition link before the driver loaded on the earlier test boots); suspend/resume with the autoloaded driver.
  • The deferred-attach diag refresh, the shutdown join, the keybag unlink, and the module-option path in 21d2c815fef9.

@greptile-apps

greptile-apps Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileConfidence Score: 4/5

[Medium impact] The change reaches SEP startup and related services across supported Apple Silicon Macs.

Fix the documented manual loader setup before merging; automatic loading can leave those users without working Touch ID.

Findings

  1. P1 Service options arrive too late ▶
  2. P2 Store status stays stale ▶

Summary

Boots the SEP without a usable xART store so microphones can work without Touch ID setup.

  • Apple Silicon microphones get an automatically started Secure Enclave.
  • Shared xART writes now require an explicit Touch ID opt-in.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Driver probe] --> B{Open xART store}
  B -->|Success| C[Attach SEP]
  B -->|ENODEV| D[Wait 500 ms]
  D --> E{Retry store open}
  E -->|ENODEV and fewer than 60 tries| D
  E -->|Success| C
  E -->|Other error or limit reached| F[Attach without store]
  B -->|Other error| F
  C --> G[Serve store requests]
  F --> H[Refuse store requests]
Loading

Reviews (1) · Last reviewed commit: "soc: apple: sep: autoload the driver and..." · Reviewed by Greptile

Comment thread drivers/soc/apple/sep.rs
Comment on lines +2713 to +2718
kernel::of_device_table!(
OF_TABLE,
MODULE_OF_TABLE,
(),
[(of::DeviceId::new(c"apple,sep"), ())]
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Service options arrive too late

If udev loads apple_sep before the documented aurora-sep.service setup runs, the driver keeps its new read-only defaults. That setup supplies xart_writes=1 provision_keybag=1 through load-driver, not a configuration file. A later modprobe does not change the already-loaded module's options, so Touch ID cannot save its state and first-boot provisioning stays off.

Install those options before automatic loading for this supported setup, or update its installation steps to require the configuration and a reboot.

Comment thread drivers/soc/apple/sep.rs Outdated
let steps = this.store_wait_steps.load(Relaxed) + 1;
this.store_wait_steps.store(steps, Relaxed);
match Self::open_xart_store(&this.dev, this.profile) {
Ok(store) => *this.store.lock() = Some(store),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Store status stays stale

When the delayed open succeeds with writes enabled, the diagnostics still report writes as disabled and matching as blocked. diag::register cached those values while the store was absent, and this branch installs the store without refreshing them. The driver can then write while its diagnostics say it cannot; aurora-sep-ready also uses the stale matching value to reject readiness.

Refresh the reported write and guard settings when the delayed open succeeds.

scottjones added a commit to omacom/omarchy-mac-pkgs that referenced this pull request Oct 23, 2026
Turning Touch ID on now also writes /etc/modprobe.d/omarchy-mac-touchid.conf
with "options apple_sep xart_writes=1 provision_keybag=1" before the driver
loads, and a failure or turning it off removes it with the agreement record.
A Mac turned on before this gets the file the next time setup finds it
ready.

Today's kernels already default to both, so this changes nothing yet. It
starts the path omacom/linux-aurora#180 needs: there apple_sep autoloads on
every Mac read-only by default, for the M1 and M2 microphones, and these
options are what lets Touch ID enrol and match. A driver already running
keeps the options it loaded with, so when one loaded before the options
existed doesn't become ready, the agreement stands and the owner is told
Touch ID turns on after a restart, instead of the agreement being taken
back on every attempt.

This doesn't yet cover #180 fully. Its read-only driver always reports
matching as blocked, and the activation reads that wherever a key store
exists, so a Mac with a key store but no options file, including one whose
owner turned Touch ID off, records blocked and isn't offered Touch ID; and
the backfill above never runs there, since such a Mac never reads ready.
The README names both, to close once #180 lands.

The options file sorts after apple-sep.conf, so it wins over any
apple-sep.conf; apple_sep.xart_writes=0 on the kernel command line still
wins over both.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
scottjones added a commit to omacom/omarchy-mac-pkgs that referenced this pull request Oct 23, 2026
…ngs it

Answers Greptile's review of #12:
- The pacman hook starts the status unit before the activation. On the
  update that first installs the package, the boot-time status hasn't
  run and the activation skips without /dev/sep-bio, so nothing offered
  Touch ID until a reboot.
- disable-fingerprint fails when it can't remove the agreement, and
  touchid-enable and enable-fingerprint fail when they can't record it or
  write the driver's options, instead of reporting success.
- The options and the carved calibration are written to .new and renamed,
  so a failed write never leaves a partial file under the real name. A
  truncated options file would load a read-only driver at every boot on a
  kernel with omacom/linux-aurora#180.
- The wait unit follows the boot-time load, so it never looks for the
  device before the driver has one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
scottjones added a commit to omacom/omarchy-mac-pkgs that referenced this pull request Oct 23, 2026
…artition

Answers the maintainer review of #12:
- enable-fingerprint lets the setup go on wherever Touch ID can't be set
  up, so a USB reader enrols on a Mac mini, a Studio or an M1 Mac. A Mac
  without a sensor writes no status, and a status service can fail, so a
  missing status is worked out again. An owner who agreed already is never
  asked again: the Mac gets any missing driver options and, unless Touch ID
  is ready, is told to restart.
- The load unit waits for the iBoot System Container's link with udevadm
  once its condition holds, instead of depending on the device: systemd
  waits for a unit's devices before checking its condition, so every boot
  waited on the partition, agreed or not, and a machine without one held
  the greeter until the device timed out.
- The activation runs only on the owner's agreement, so on a kernel that
  loads the driver itself (omacom/linux-aurora#180) a Mac whose owner
  hasn't agreed keeps being offered Touch ID.
- The consent text drops a reassurance nobody can check.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
scottjones added a commit to omacom/omarchy-mac-pkgs that referenced this pull request Oct 23, 2026
A MacBook Neo's Touch ID needs its device-private sensor root key. Instead
of an installer copying it before anyone has agreed, and Linux keeping it,
touchid-root-key rebuilds it only after the owner says yes, from this Mac's
factory records in asahi/all_firmware.tar.gz, which asahi-installer writes
to the ESP on every install. It rebuilds the key as the installer's
factory_root_key() does on macOS, checks its envelope, and refuses records
that aren't all found byte for byte in this Mac's own iBoot System
Container, so another Mac's archive, or one swapped on the ESP, gives no
key. It writes the key root-only, to a temporary name it created itself,
synced and renamed.

- Eligibility needs an installed key, or the archive and python.
- The boot status no longer moves a staged key, and nothing is kept in
  /var/lib/omarchy-mac; a yes that then fails takes the rebuilt key back.
- Turning Touch ID off deletes the key; the next yes rebuilds it.
- A factory reset carries no key: the ESP survives it, so the next owner's
  yes rebuilds it. factory-reset.sh is back to its state before 104c496.
- Neos installed before the installer staged anything are covered too.

The README also notes that fprintd opens /dev/sep-bio when it probes, so
a kernel that loads apple_sep on its own (omacom/linux-aurora#180) needs
fprintd's allowance gated on the agreement as well.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@claytonfaria

Copy link
Copy Markdown

Additional confirmation on a MacBook Air M1 (2020), J313, running linux-aurora 7.2.11.aurora1-1.

apple_sep was initially unloaded. Loading the installed module with xart_writes=0 provision_keybag=0 successfully booted SEP; the kernel logged writes disabled.

We also found a separate userspace issue: aurora-audio 4.1.aurora3-1 references the Triforce LV2 plugin, but triforce-lv2 was missing. WirePlumber failed to create the microphone filter until we installed it and restarted WirePlumber.

After both changes, omarchy_asahi_mic provides live audio and Superwhisper works. A three-second capture measured RMS 0.00199 and peak 0.01247.

This supports the SEP startup diagnosis and read-only operation. We tested the existing kernel with a manual module load, not this PR’s patched kernel.

@joshuaswarren

Copy link
Copy Markdown

Lab laptop qualification of this PR at head 5a80718.

What was built: a hand-built linux-aurora package (no pacman signature; sha256 checked before install), release 7.2.11-pr180-ARCH+, made from the PR 187 tree plus this PR's sep.rs and Kconfig hunk, so the build also contains the PR 187 GPU port. It was installed as a one-shot Limine entry on each laptop, and each laptop returned to its stock kernel afterwards. The boot ids below are the stock boot, the candidate boot and the stock return boot.

Laptop (model) | boots (stock -> candidate -> stock) | result
13-inch M1 MacBook Pro | 69486439 (7.1.12-2-20261013.18-sep-ARCH) -> d9a1370a (7.2.11-pr180-ARCH+) -> bf356a6a (7.1.12-2-20261013.18-sep-ARCH) | PASS. Smoke 7 PASS, 2 FAIL, 1 SKIP (the same two FAILs as its own stock baseline); SEP booted the enclave; microphone not measurable in that laptop's login session (UNKNOWN)
16-inch M1 Max MacBook Pro | 415bfc0e (7.1.12-2-12.6-sep-ARCH) -> 304241ab (7.2.11-pr180-ARCH+) -> 22ccf6cc (7.1.12-2-12.6-sep-ARCH) | PASS. Smoke 11 PASS, 1 FAIL, 2 SKIP; SEP booted the enclave; mic band moves with the tone
14-inch M2 Max MacBook Pro | 2cfa8fa6 (candidate) -> b52dbe75 (stock) | PASS. Smoke 8 PASS; SEP up; mic alive

Smoke detail on the 16-inch M1 Max: 11 PASS (boot, wifi, input, input-errors, display, audio, ane, battery, gpu-dmesg, audio-card, gpu-vulkan), 1 FAIL (the gpu check that looks for a Vulkan device or a renderD node, which fails the same way on the stock baseline of that laptop), 2 SKIP (suspend not requested, mlx-omarchy not installed). glmark2 built on the candidate scored 4308 against 2399 on the stock baseline of the same laptop.

Smoke detail on the 13-inch M1: 7 PASS (boot, wifi, input, input-errors, display, ane, battery), 2 FAIL (audio: the seat-less login session sees no ALSA card; gpu: no Vulkan device or renderD node), 1 SKIP (suspend). Both failures are identical on that laptop's stock baseline, and the root-level check in the same run finds 3 ALSA playback devices. The Honeykrisp compute check passes on both boots with the same max absolute error, 0.000595.

SEP on the candidate: apple_sep is loaded and the kernel log shows the enclave actually booting - on the 16-inch M1 Max "SEP platform profile: T6000/J316s", on the 13-inch M1 "SEP platform profile: T8103/J313", then "boot: TZ0 accepted; handing over firmware and shared memory" and "boot: IMG4 acknowledged; the SEP owns the shared-memory table", followed by endpoint discovery.

Microphone: on the 16-inch M1 Max the raw hw:0,0 capture shows the 1 kHz band rising from about -20 dB with the room silent to about -14 dB while a 1 kHz tone plays, and the raw capture behaves the same on the stock kernel of that laptop, so the microphone is live on the candidate and this is a no-regression result, not a microphone fix. The band move is about 5.5 dB, smaller than the roughly 13 dB reference measured on the 14-inch M2 Max. The processed omarchy_asahi_mic source differs between the two kernels on that laptop (stock: rms rises 15 dB with the tone but the 1 kHz fraction drops, -19.1 -> -28.7 dB; candidate: rms flat and the 1 kHz fraction rises, -18.5 -> -11.4 dB). Reporting that as an observation, since this PR changes the SEP boot path.

On the 13-inch M1 the microphone could not be measured at all: that laptop's login session exposes no ALSA card (the same "no soundcards" failure appears on its stock baseline), a direct raw capture returns 150 bytes where 1,152,000 are expected, and the processed source returns no data in both the silent and the tone case - identically on the stock boot and on the candidate. The microphone is therefore UNKNOWN on that laptop, not confirmed.

CI on this head: 1 check is reported (Greptile Review, pass). No kernel CI jobs are attached to this pull request's head, unlike #182 which carries the kernel CI.

Regressions: none found. Three notes for the author:

  • One message class appears on the candidates and not on the 7.1.12 stock baselines: tas2764_i2c_probe: Failed to parse devicetree - 30 times on the 16-inch M1 Max (6 I2C addresses x 5 retries) and 6 times on the 13-inch M1 (one per address). The same message is present in the earlier 7.2.11 candidate logs on the 16-inch M1 Max (3 times for the PR 187 build, 2 times for 7.2.11-1-1) and 0 times on 7.1.12, so it arrives with the 7.2.11 base tree rather than with this PR. The audio codec cs42l84 probes successfully right after it, audio playback passes and the microphone is live on the 16-inch M1 Max.
  • On the 13-inch M1 the candidate also shows 4 PCI resource warnings (xhci_hcd/pcieport ...: of_irq_parse_pci: failed with rc=-N) that its 7.1.12 baseline does not - that baseline's dmesg error list was empty. These come with the newer kernel base.
  • Known flakes, present on the stock baselines as well, not regressions: apple-dcp .dcp: Failed to get dp-xbar: -517 and a brcmf roam message that differs from case to case.

What this does not test:

  • These laptops load apple_sep through apple-sep.service, so the module alias autoload path is UNKNOWN here. The alias itself is present in the module (of:N*T*Capple,sep).
  • On the 16-inch M1 Max and the 14-inch M2 Max the microphone already works on stock, so those runs show no regression rather than a fix; on the 13-inch M1 it could not be measured at all, so it is UNKNOWN there.
  • The build also contains the PR 187 GPU port, so a failure in the GPU area here would belong to that PR, not to this one.
  • No laptop in this fleet runs without the loader units, so the loader-unit-free path is not covered.

@maralcbr maralcbr left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @ludagoo. The diagnosis matches what we see: on the release pin (CONFIG_APPLE_SEP=y), the probe runs before the iBoot container's link exists, returns the store error and is never retried. The cold-boot M1s never get their enclave booted, so the mics record the null stream from #141. Booting without the store and exporting the alias is the right fix, and read-only by default is the safer default.

I'd ship this with CONFIG_APPLE_SEP=m in the Omarchy package, not =y. With the alias, udev then loads it only where the device tree enables the SEP node: the M1 family, which needs it for the mics. M2, M2 Pro/Max and M3 Air keep disabled nodes, so nothing changes there unless the owner turns Touch ID on, and our loader reads the options from modprobe.d after the container's link exists. Built in, every one of those Macs would attach the SEP on every boot, and the options could only come from the kernel command line.

Before merge (all small, no hardware needed):

  1. Refresh the diag facts when the late open succeeds (Greptile's P2). diag::register cached xart_writable=false and no guard at probe, and store_wait_tick only swaps the store in. Our touchid-activate refuses matching=blocked, so on that path Touch ID never reports ready. Please update both the Rust facts and the C-side write/guard fields before the attach can generate traffic.
  2. Arm the settle timer after a deferred attach. The probe arms it only when the attach ran synchronously. After store_wait_tick attaches, only RX re-arms it, so a silent warm attach never hits the first-response failure path and diag stays pending. A failed deferred attach should also be marked failed rather than only logged.
  3. Serialise the deferred attach against remove(). remove() clears the mailbox before it cancels the wait work, and store_wait_tick checks shutting_down only on entry. A tick blocked in the store open can resume, write the warm registration marker and then fail to ring, after which the next probe returns EBUSY with no handoff done. Join the wait work before tearing down the mailbox, and make the attach and marker publication respect shutdown.
  4. Kconfig help: with the alias design, recommend M (also the existing default) rather than "Say Y".
  5. Greptile's P1 (load-driver passes the options too late once udev autoloads): have the service install a modprobe.d file before the first load and say a reboot is needed when the driver is already up. In the README, "no longer required" holds only for the M1 family: disabled warm-attach nodes still need an explicit loader.

Not needed here: 8eb00bb from #7. The tree deliberately keeps suspending after the drain timeout, and that's a separate call.

Hardware before we pin it (packaged =m build, no loader units):

  • J313 and one M1 Pro/Max: the driver autoloads with writes disabled; raw and processed mic are live; 3× suspend/resume; idle and s2idle power vs today's kernel, since the enclave now runs on every M1 boot.
  • One M1 iMac (J456/J457): autoload and mic smoke.
  • M2 Air and M3 Air (J613): apple_sep not loaded without Touch ID. With Touch ID on (M2 Air): writes enabled after restart, enrol, verify, reboot persistence.
  • On one cold and one warm Mac: a delayed link, an absent link, and remove() during the wait.

Comment thread drivers/soc/apple/sep.rs Outdated
let steps = this.store_wait_steps.load(Relaxed) + 1;
this.store_wait_steps.store(steps, Relaxed);
match Self::open_xart_store(&this.dev, this.profile) {
Ok(store) => *this.store.lock() = Some(store),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The late open installs the store, but diag::register cached xart_writable=false and no guard at probe, so diag keeps reporting writes off and matching=blocked (Omarchy's touchid-activate refuses that). Please refresh the Rust facts and the C-side write/guard fields here, before the attach below.

Comment thread drivers/soc/apple/sep.rs
dev_err!(this.dev, "the SEP node is gone; not booting the SEP\n");
return;
};
if let Err(e) = this.attach(&sep_node) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The probe arms settle only for a synchronous attach. After a deferred one, only RX re-arms it, so a silent warm attach never reaches the first-response failure path. Arm it here, and mark a failed attach as failed in diag rather than only logging it.

Comment thread drivers/soc/apple/sep.rs
@@ -2385,7 +2471,7 @@ impl SepData {

*self.mbox.lock() = None;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mailbox goes before the wait work is cancelled, and store_wait_tick checks shutting_down only on entry. A tick blocked in the store open can still write the warm registration marker, after which the next probe returns EBUSY. Join store_wait_work first and serialise the attach and marker against shutdown.

Comment thread drivers/soc/apple/Kconfig Outdated
still attaches, but refuses Touch ID enrol and verify: the enclave
saves anti-replay state after every match.

Say Y here if you have an Apple silicon Mac.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the alias design this wants M (also the default here); built in, modprobe.d options never reach the driver.

Comment thread tools/aurora-sep/README.md Outdated
microphones only work once it runs. If udev loads the driver before the iBoot
system container's partition link exists, the boot waits up to 30 s for it and
then runs without the xART store (Touch ID and trusted keys stay unavailable
until the next boot). The service above remains harmless and is no longer

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"No longer required" is true only where the DT enables the SEP node (M1 family, J700). The M2, M2 Pro/Max and M3 Air nodes are enabled by module init, so they still need the loader. load-driver should also install its options before the first load (Greptile P1).

Lucas Goossen and others added 2 commits October 26, 2026 15:16
The driver refused to probe when the xART gigalocker could not be opened
from the iBoot system container, so the SEP was never booted. On the M1
and M2 laptops the Secure Enclave sits in the path of the microphone
data lines: without the boot, the AOP's PDM capture runs on a constant
input and every recording is a null stream (omacom#141).

This is what broke the built-in microphones between 7.1.12.aurora2-12
(CONFIG_APPLE_SEP=y with the earlier stub driver, which only booted the
enclave) and every later build: the rewritten driver either failed its
probe at the xART store before udev had created the partition-label
link (CONFIG_APPLE_SEP=y, 7.1.12.aurora8-1), or was a module that is
never loaded without the Touch ID loader units (7.2.10.aurora1-2).

Treat an unavailable or invalid store like xart_writes=0 taken one step
further: warn, keep `store` empty and boot the enclave anyway. The xARM
path already answers the enclave's requests with a failure when there
is no store, so Touch ID and trusted keys stay unavailable until a boot
where the store opens; nothing is written.

Verified on a MacBook Air (M1, 2020) J313 / t8103, macOS 13.5 firmware,
on 7.1.12.aurora2-12.6: with the driver loaded by hand after boot the
microphones record live audio; with no SEP driver running the capture
is the null stream.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The built-in microphones of the M1 and M2 laptops depend on a booted
Secure Enclave, so the SEP driver has to run on every such Mac, not only
where the Touch ID loader units are installed. Export the OF table as a
module alias again, so udev loads the driver on every board whose device
tree enables the SEP, and resolve the two problems that made commit
36ebdee ("soc: apple: sep: Do not autoload the driver through a
module alias") remove the alias:

 - A udev load runs before udev has created the iBoot system container's
   partition-label link, through which the xART store is opened, and
   nothing retried the open. Now a cold boot whose store open fails with
   ENODEV waits for the link in 500 ms steps, up to 30 s, opens the store
   once it exists and boots the enclave then; after the last step it boots
   without the store. The boot never waits forever: the microphones
   depend on it.

 - A load the owner did not ask for provisioned an identity keybag and
   wrote to the shared xART store. xart_writes and provision_keybag now
   default to 0: read-only operation boots the enclave and refuses Touch
   ID enrol and verify, as before. The aurora-touchid package, installed
   when the owner opts in, carries a modprobe.d file that enables both;
   a --read-only install overrides it from /etc/modprobe.d. Its
   apple-sep.service and .path stay harmless (modprobe of a loaded
   module).

The diag sysfs group keeps the xART facts seen at probe; when the store
is opened later its "writable" value stays at probe's.

Verified on a MacBook Air (M1, 2020) J313 / t8103: the driver autoloads
at boot, the TZ0 handshake completes, the store opens with writes
disabled, and the microphones record live audio.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@ludagoo
ludagoo force-pushed the fix/sep-boot-microphones branch from 5a80718 to 0dfa5ae Compare October 26, 2026 18:16
@malik-na

Copy link
Copy Markdown
Member

Tested on a J313 (M1 Air), merged with #223 on 937b727ef9a3 (#180's own files only; no conflicts):

without this PR (7.2.11-6-1-ARCH) with this PR
apple_sep loaded at boot no yes, via udev
enclave boot – TZ0 accepted, IMG4 acknowledged, 7 endpoints
3 s capture from omarchy_asahi_mic, peak 77, then 0 4931
xART writes at default options – writes disabled

The microphone fix works on M1. Two notes:

  1. A default (read-only) load isn't quite "changes nothing on the Mac". It created /var/lib/aurora-sep-host-state.bin (2,359,296 bytes, created a new host-state store) on the Linux root. That's harmless, but now every M1/M2 install gets it on first boot, which the Kconfig help and README don't mention.
  2. With xart_writes=1 provision_keybag=1, keybag provisioning on M1 fails at the xART guard (see soc: apple: sep: keep a held J313 patch and its data-ready line #223). It leaves a 52-byte /var/lib/aurora-sep-keybag.bin that holds only the APPLE-SEP-KBAG01 header and zeros. A failed provisioning probably shouldn't leave a keybag file behind.

A default load still creates /var/lib/aurora-sep-host-state.bin
(2359296 bytes). That is a Linux-only file, not an xART write.

After the iBoot container opens late, refresh the cached xART diag
facts before attach. Arm settle after that attach. Cold boot sets
registered only on the IMG4 ack, so the timer is not gated on it.
Join the store wait before dropping the mailbox, and do not publish
the boot marker once shutdown has started.

A keybag create that is not sent, or that the enclave answers with a
non-zero status, removes the 52-byte uncommitted header. A create
that was sent and not answered keeps the intent. A committed bag is
left in place.

Kconfig asks for a module so modprobe.d options reach the driver.
load-driver writes /usr/lib/modprobe.d/apple-sep.conf only when that
file is absent. The loader is no longer required only where the
device tree enables the SEP node: the M1 family and J700.

Signed-off-by: Lucas Goossen <lucas.goossen@hey.com>
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.

J313 (MacBook Air M1): built-in mic capture returns a fixed looping pattern instead of audio

5 participants