95 Commits
Author SHA1 Message Date
Acelogic 940eeb95ba docs: run the gadget-NCM link with Q1N1_UDP_RETRIES 2026-10-25 00:18:35 -04:00
Acelogic 78e648cc60 tools: let the control guard journal recovered write losses
On q1n1's gadget-NCM link one lost datagram in a memory write surfaces
as a transport read timeout; with Q1N1_UDP_RETRIES the q1n1 Link then
resynchronises (filler, drain, NOP round trip) and repeats the write.
The guard froze the session on that first inner timeout, so the
recovery could never run under the launcher (next3g).

Inside link.writemem on a datagram transport whose Link recovers
losses, and with no native call unresolved, a transport timeout is now
journaled (transport_loss, transport_loss_recovered) instead of
freezing. A write that still fails freezes the session as before; P_
requests, reads and everything else are unchanged.

replay-a16-control-guard.py adds four datagram-loss cases (recovered,
retries off, lost on every attempt, resync NOP lost); the recovered
case fails against the previous guard.
2026-10-25 00:18:35 -04:00
Acelogic 83b600d98e cycle: bind installed-fresh boots to the gadget-NCM stage too
next3c refused at the loader (exit 2): the native Image4 path binds the resident q1n1 stage to its ELF (probes/stagebind.py), and the launch named only q1n1's build/uefi, while the A16 ran the gadget-NCM stage that tools/a16-link-rearm.py arms after a reset without a replug (q1n1 build/uefi-gadget-ncm, Q1N1_GADGET_NCM). SNAP_STAGE_BUILDS now also lists that build when it exists; each stage still binds only to its own ELF.
2026-10-24 22:55:38 -04:00
Acelogic dbd816aa6a cycle: pin the early-done AuxKC for --edp-backlight runs with --gpu-coherent or --present-early-done
early-done-20261025 (9aff1d3e), linked from 822226c with KEXT_PROFILE=desktop-early-done I2C_PROFILE=desktop-fnkeys: the coherent backlight build (swap brightness, head rule, IOMFB trace, CS samplers) plus ADRENO_PRESENT_EARLY_DONE.
2026-10-24 21:59:45 -04:00
Acelogic 822226cfed repo: merge the 60 fps present batch (perf-60)
Busy desktop windows ran at ~50 copies/s because WindowServer, holding at most two swaps, got one refresh per frame while the kext completed each swap a tick after its copy, and the kext's per-IB cache maintenance (3.4 ms over ~98 MiB) sat on WindowServer's path. The GPU is not the limit: 94% of the time at 1700 MHz, ~7% busy. ADRENO_PRESENT_EARLY_DONE (--present-early-done, adaptive mode 2) completes a layer-0 swap at its scanout copy after a late frame; the desktop-early-done profile adds it to the coherent backlight build so --gpu-coherent can drop the maintenance. Replay: busy 49.8 -> 56.3 copies/s, 57.9 with coherent.
2026-10-24 21:59:20 -04:00
Acelogic b2f1fa031f tools: replay next2c's sporadic frames with coherent maintenance
The quiet desktop's sporadic heavy frames (next2c: 3 IBs a second,
57.9 copies/s) with b12v23's coherent maintenance: the kext time per
IB falls from 13 ms to 6.5-8.5 ms (the preparation stays), and the
model then delivers every refresh (59.5 copies/s) in every mode, so
the adaptive mode never engages there.
2026-10-24 21:56:03 -04:00
Acelogic 00cecdf061 tools: summarize a run's present pacing windows
tools/summarize-present-pacing.py reduces a console's AdrenoDisplay
perf windows to busy and quiet groups: copies per second, the copy
interval buckets, ready / missed / true-miss ticks, per-IB GPU,
submission, cache and preparation time, the copy, tick lateness and
q, the perf done line's early completions and arrival histograms,
and with --report the GPU's time per clock (DVFSREP1). Its host test
runs it on a synthetic console.
2026-10-24 21:54:41 -04:00
Acelogic 63d237b6bb tests: cover early swap completion and its cycle flags
tools/test-adreno-early-done.c unit-tests AdrenoDisplayEarlyDone.h
(modes, arrival bins, late frames and what is not one, adaptive
engagement, renewal and expiry, windows, the perf done line at its
caps). tools/test-present-early-done.py runs it, requires it to fail
on eight mutants of the header, checks that the kext touches the
feature only under ADRENO_PRESENT_EARLY_DONE, that desktop-early-done
differs from desktop-backlight only in AdrenoDisplay.o, the cycle
flags, refusals and AuxKC choice, and the replay (earlier outputs
unchanged by the define, no failure or cost failure in
early-done.json).
2026-10-24 21:54:41 -04:00
Acelogic 6605245ba5 cycle: add --present-early-done and its AuxKC slot
--present-early-done MODE (needs --edp-backlight and its chain) adds
the guest boot-arg adreno_present_early_done=MODE and
--present-early-hold-ms (mode 2 only) adreno_present_early_hold_ms;
both are refused with --present-hold on. --edp-backlight with
--present-early-done or --gpu-coherent now takes the collection
pinned as INPUT_AUXKC_DESKTOP_EARLY_DONE (SnapAdreno
desktop-early-done: the coherent desktop kext with the backlight
service and early completion) instead of the nocoherent
INPUT_AUXKC_DESKTOP_BACKLIGHT, and is refused until that collection
is linked and pinned. Without the new flags the boot arguments, the
AuxKC and the monitor are unchanged: the next3 argument list still
builds monitor 97be2b80 (459,904 bytes).
2026-10-24 21:54:41 -04:00
Acelogic 1fffff784d tools: replay early swap completion in the pacing world
With -DADRENO_PRESENT_EARLY_DONE=1 the presentation replay mirrors
AdrenoDisplayEarlyDone.h step for step (the completion at the copy
in l_present, arrivals in l_swap_begin, the tick state in l_tick) and
runs early_done_scenarios (early-done.json): the 2026-10-24 busy
desktop (org2's 117 windows: 49.8 copies/s with a SLOT WindowServer
of 5-9 ms frames, 20% of them 14-30 ms), the same with b12v23's
coherent maintenance, a FREE WindowServer, a quiet cursor desktop and
next2c's sporadic heavy frames, each with the mode off, always and
adaptive, under the deployed switches (relatch, urgent polling,
EP1/EP2, no EP3 assist).

Every earlier output (beam, damage, latency, pacing, pipeline,
presentation, presentsync, relatch, vsync .json) is byte for byte the
define-off build's, and the define-off build's equal the previous
tree's. Busy SLOT: 49.8 -> 56.3 copies/s (coherent 51.8 -> 57.9),
input latency mean +7 ms; quiet: unchanged in adaptive mode, +14 ms
always; sporadic: 56.5 -> 58.1 adaptive, 59.4 always.
2026-10-24 21:54:41 -04:00
Acelogic c77dd9974e repo: move SnapAdreno to early swap completion
SnapAdreno a2d43d0: ADRENO_PRESENT_EARLY_DONE in AdrenoDisplay
(src/AdrenoDisplayEarlyDone.h, boot-arg adreno_present_early_done)
and the desktop-early-done profile (desktop-backlight plus the
define). Define off, the desktop-next profile still builds the
deployed swap-path-20261024 AdrenoX2 section for section.
2026-10-24 21:54:41 -04:00
Acelogic 06333e0680 cycle: pin the swap-path AuxKC for --edp-backlight runs
swap-path-20261024 (9e916a41), built by the backlight-path work from 8f9eeb5 / SnapAdreno e1cf072 / SnapI2CHID f0b7984 with KEXT_PROFILE=desktop-next I2C_PROFILE=desktop-fnkeys: AdrenoBacklight takes the brightness from the swap record instead of a brightness-nits write WindowServer's sandbox refuses. next2-20261024 (cc07dfd3) stays as the rollback.
2026-10-24 20:22:21 -04:00
Acelogic 5e7b890849 repo: merge the icon pixel probe and the CS table fix set (icon-pixels-next)
The on-device CoreImage pixel test (tools/run-icon-pixels.py, compare-icon-pixels.py, SnapMetal harness/icon-pixels) and SnapMetal 8fe64cb's ADRENO_CS_TABLES=1 build (SP_CS_CONFIG NTEX equal to NSAMP, as Mesa programs every stage), trusted and deployable as metal-stage-iconfix-20261024 (AdrenoMetal ba3a3fd6, CDHash 11d5ff9a; the icon-pixels tool 25f07e86). next1/next1b showed partial System Settings icons with no plug-in or kext refusal.
2026-10-24 20:21:48 -04:00
Acelogic 6e634e62e5 repo: merge the swap brightness path (backlight-path)
next2c showed WindowServer bind the panel to AdrenoBacklight but its sandbox refuse every brightness-nits write (iokit-set-properties is allowed only on AppleARMBacklight). The brightness now comes from the swap record IOMobileFramebufferSwapSetBrightness fills (+0x354 present, +0x35e nits as a double): AdrenoDisplay overrides swap_submit and hands the value to AdrenoBacklight as source swap, at most one monitor call per 33 ms. force-brightness-control is no longer published (SnapAdreno e1cf072).
2026-10-24 20:21:48 -04:00
Acelogic 8f9eeb5ba2 docs: say --edp-backlight brightness arrives in the swaps
RUNNING.md no longer says BrightnessControl writes brightness-nits to
the service (WindowServer's sandbox refuses that): the service lets
WindowServer bind the panel's framebuffer, CoreBrightness's nits
arrive in the swaps as on a DCP Mac, and the kext logs "SET <level>
from swap".
2026-10-24 20:19:43 -04:00
Acelogic 774f13dfc8 tests: check the swap brightness path of AdrenoBacklight
test-edp-backlight.py follows the kext's move from BrightnessControl
writes to the swap record:
- Wiring: AdrenoDisplay overrides swap_submit, reads the record at the
  expected offsets through edp_bl_double_to_q16, returns the family's
  answer and hands the value on as source "swap" from
  swap_begin_gated, all under ADRENO_BACKLIGHT; the service no longer
  publishes force-brightness-control.
- UserspaceContract (26A428 host with ipsw, else SKIP): besides the
  BrightnessControl names the IOMFB bind needs, IOMobileFramebuffer
  exports IOMobileFramebufferSwapSetBrightness, QuartzCore has
  IOMFBDisplay::swap_brightness, and the framework's setter and swap
  submit still use the kext's record offsets and size.
- Kext (--kext-reference): both backlight profiles override
  swap_submit, the default kext does not.
check-iomfb-vtable.py's help names the new override.
2026-10-24 20:19:43 -04:00
Acelogic 463c4036c5 repo: point SnapAdreno at the swap brightness path
SnapAdreno e1cf072 (branch backlight-path, not pushed): AdrenoDisplay
overrides swap_submit and hands the brightness each swap carries to
AdrenoBacklight as source "swap"; AdrenoBacklight no longer publishes
force-brightness-control, whose writes WindowServer's sandbox refused
in run next2c. The default kext is section for section unchanged.
2026-10-24 20:19:28 -04:00
Acelogic 3c995cc8d8 compat: convert a swap record's brightness to 16.16 nits
The A16 kext now takes the panel brightness from the swap record
IOMobileFramebufferSwapSetBrightness fills: an IEEE double in nits,
unaligned, straight from a client. edp_bl_double_to_q16 turns its bits
into 16.16 nits in integer arithmetic, rounded to nearest and capped,
refuses NaN, infinities and negative values (which name no
brightness), and maps zero and subnormals to 0 (the darkest request).

The model test checks it bit-exact against the host's double
arithmetic for chosen values and for every exponent with a spread of
mantissas, and four mutations (NaN or negative accepted, truncation,
no cap) must fail it. Header-only and unused by the monitor: the
SNAP_EDP_BACKLIGHT monitors built with run next1b's flags, with and
without the define, are byte-identical to org next's.
2026-10-24 20:19:14 -04:00
Acelogic b66e1d0e2b cycle: trust and deploy the iconfix plug-in set
The next installed run boots with the settings-icons executable
378ff525 installed and replaces it from single-user mode with SnapMetal
icon-pixels-next built the same way (lenient, ADRENO_PIPELINE,
ADRENO_SETTINGS_ICONS, runtime v7) plus ADRENO_CS_TABLES=1: AdrenoMetal
ba3a3fd6, CDHash 11d5ff9a. CoreImage's compute kernels then get
SP_CS_CONFIG NTEX = NSAMP = their T#/S# count and NUAV = their UAV
count; a process started with ADRENO_CS_TABLES=0 keeps the
settings-icons counts, so icon-pixels can compare both in one boot.

installed_fresh: the trust additions become the iconfix set's (the
settings-icons set's 47 rows plus 11d5ff9a and the icon-pixels probe
25f07e86: 501a90b6, payload 7857aabc); the settings-icons set stays as
ADDITIONS_SETTINGSICONS for rollback, and every earlier CDHash stays
trusted, so --restore (back to 378ff525) still boots. deploy-guest-
plugin: the executable's base is the settings-icons 378ff525 and its
payload the 27,627-byte AdrenoMetal-378ff525.bsdiff; the runtime and
CodeResources are already the installed ones and are skipped.

The probe's row: the guest's TXM service reports the code-signing
monitor disabled and answers only static trust-cache lookups
(compat/txm.h), so code outside the cache is left to in-kernel AMFI,
whose ad-hoc handling has never been observed in the guest; every
executable of ours that ran there (metal-triangle-probe,
metal-clear-probe) had its CDHash in the trust additions. The row costs
nothing and follows that pattern.

The set, build/current-assets/metal-stage-iconfix-20261024, is a local
(ignored) input: AdrenoMetal, AdrenoMetal-378ff525.bsdiff,
trust-additions.json, trustcache.payload and SET.json.

Evidence: the prepare-time trust check (configure_guest, then
trust_cache_spec(ADDITIONS).load(FIRMWARE) against TRUST_PAYLOAD and
TRUST_SHA) passes for the installed, -input and -input-touchpad
profiles, for this set and the settings-icons rollback; the payload
holds 11d5ff9a, 25f07e86, c76a4677 and runtime v7's ab4ccbd4;
tools/test-deploy-guest-plugin.py PASS 21 checks (install, again,
restore, refuse) over the console stand-in with 3% loss.
2026-10-24 20:03:11 -04:00
Acelogic bad2b992dc repo: merge the ADRENO_CS_TABLES candidate (icon-pixels-fix)
The --cs-tables expectations of test-adreno-settings-ci-encoding.py,
and SnapMetal at icon-pixels-next (8fe64cb): ADRENO_CS_TABLES (51d07a1,
ef0c80a) merged with the icon-pixels probe (713dab1, 263dd47).
2026-10-24 19:55:32 -04:00
Acelogic 88fac86a26 repo: merge the icon-pixels pixel test (icon-pixels)
icon-pixels (SnapMetal harness/icon-pixels*.m) and the tools that
build it, run it in the guest over the console and compare its lines
with this Mac's reference; docs/RUNNING.md describes the check.
2026-10-24 19:55:22 -04:00
Acelogic 7e8bf82b3a cycle: pin the next2 AuxKC for --edp-backlight runs
next2-20261024 (cc07dfd3), built from fbed1ca with KEXT_PROFILE=desktop-next I2C_PROFILE=desktop-fnkeys: AdrenoX2 d88a2620 now publishes force-brightness-control and maps nits proportionally (SnapAdreno 9cc1e92). SnapI2CHID's code sections are identical to next-20261024's. next-20261024 (57965a84) stays as the rollback.
2026-10-24 19:52:33 -04:00
Acelogic fbed1cad82 repo: merge the brightness path (backlight-path)
BrightnessControl writes brightness-nits only to a backlight service that carries force-brightness-control; AdrenoBacklight now publishes it (SnapAdreno 9cc1e92), so CoreBrightness's slider and keys reach the panel instead of dimming in software (next1b: RequestsNits 0). The floor drops from 10% to 2% (level 41 of 2047) and nits map proportionally onto levels.
2026-10-24 19:50:41 -04:00
Acelogic 07839e46f7 tools: run icon-pixels a second time with --ab-env
The synth-ab step runs the synthetic cases again with one VAR=VALUE in
the tool's environment, into synth-ab.txt, compared with the same
reference. With a plug-in that has a per-process switch installed (the
ADRENO_CS_TABLES candidate honours ADRENO_CS_TABLES=0), one boot then
measures both encodings on the GPU. test-icon-pixels.py runs it over
the console stand-in (55 checks pass).
2026-10-24 19:48:11 -04:00
Acelogic 15336488b9 docs: describe how --edp-backlight brightness reaches the panel
RUNNING.md now gives the 2% floor, how CoreBrightness's nits reach
AdrenoBacklight (WindowServer's BrightnessControl, enabled by the
service's force-brightness-control) and the two boot-args that move
the nits-to-level curve. It no longer names the pinned collection's
folder, which the next pin will change.
2026-10-24 19:47:13 -04:00
Acelogic 1421e52e29 repo: point SnapMetal at the per-process ADRENO_CS_TABLES opt-out
SnapMetal ef0c80a lets a process started with ADRENO_CS_TABLES=0 keep the
old compute counts, so icon-pixels can compare both encodings in one
boot with the candidate installed.
2026-10-24 19:47:06 -04:00
Acelogic e273ff6475 tests: check AdrenoBacklight's BrightnessControl path
test-edp-backlight.py gains three checks for the path SnapAdreno's
AdrenoBacklight.h describes:
- Wiring: the service publishes force-brightness-control as data with
  a nonzero first byte, backlight-control and IODisplayParameters,
  takes brightness-nits, and maps every request through the one curve
  with the configured minimum.
- UserspaceContract: on a 26A428 host (the guest's userspace) with
  ipsw, the dyld cache's BrightnessControl and IOMobileFramebuffer
  still carry the names the path relies on; SKIP elsewhere.
- Kext (--kext-reference): desktop-next builds too, both backlight
  profiles carry force-brightness-control, the default kext does not.
2026-10-24 19:47:06 -04:00
Acelogic 8351bc0674 repo: point SnapAdreno at its backlight-path branch
SnapAdreno 9cc1e92 (branch backlight-path, not pushed): AdrenoBacklight
maps nits proportionally onto levels with the compat helpers of the
previous commit, publishes force-brightness-control so WindowServer's
BrightnessControl writes brightness-nits to it, and publishes its
DPCD700 diagnostic as 64 bits. The default kext is section for section
the base commit's.
2026-10-24 19:46:45 -04:00
Acelogic b8e2e042f2 compat: lower the eDP backlight floor and map nits linearly
The monitor's floor was 10% of full scale (level 205 of 2047) and the
kext's helpers mapped [min_nits, max_nits] affinely onto [floor, max].
If the panel's DPCD level is linear in luminance, the darkest macOS
request was ~50 nits: ten times the 5-nit minimum the A16's panel
table gives Windows (BrightnessRangeLevel0 5000..500000 millinits,
BrightnessRangeLowOffset 10000).

EDP_BL_FLOOR_PERMILLE is now 20: level 41, ~10 nits under the linear
model (the table's low offset), very dark but never off if the TCON
applied a 2.2 power law instead. Nothing has measured the panel's
curve; the header says so and the hardware run must check the bottom
of the slider. The helpers now model luminance proportional to level
(edp_bl_nits_to_level/edp_bl_level_to_nits with the top level at
max_nits) and edp_bl_min_nits_q16 raises the darkest request to the
floor's luminance; the slider helpers take 16.16 bounds.

The SNAP_EDP_BACKLIGHT=1 monitor built with run next1b's flags differs
from next1b's qualified one in one byte (same size, 200 bytes of code
budget left); without the define the monitor is byte-identical. The
model test checks the floor and the curve, and four new mutations (no
floor change back to 10%, an affine curve, a top short of max, a
minimum below the floor) must fail it.

The SnapAdreno kext with ADRENO_BACKLIGHT uses the new signatures; it
builds once the submodule pointer moves (next commit). The default
kext does not include this header.
2026-10-24 19:46:34 -04:00
Acelogic bc5846fb4e repo: point SnapMetal at icon-pixels without --bundle
SnapMetal 263dd47 removes icon-pixels' second-plug-in mode, which
cannot work in the guest (Metal's device list loads the installed
plug-in first).
2026-10-24 19:42:46 -04:00
Acelogic b5da7dd434 tests: expect Mesa's CS state counts with --cs-tables
test-adreno-settings-ci-encoding.py pins the single and two-input
packages' T#/sampler units, TSIZE and SP_CS_CONFIG NTEX/NSAMP/NUAV.
--cs-tables expects a plug-in built with ADRENO_CS_TABLES: NTEX 2 /
NSAMP 2 / NUAV 1 for the single shape, 3 / 3 / 1 and a zero third
sampler entry for the two-input one; units and TSIZE are unchanged.

ADRENO_CS_TABLES build: PASS 352 checks (production and CS-sampler
validators). Unchanged build with --cs-tables --expect-before: fails
27 checks, as it must. Unchanged build without the flag: PASS 351.
2026-10-24 19:40:25 -04:00
Acelogic 9e64bbb125 repo: point SnapMetal at the ADRENO_CS_TABLES candidate
SnapMetal 51d07a1 adds ADRENO_CS_TABLES (default off): CoreImage's
compute kernels get SP_CS_CONFIG NTEX = NSAMP = their T#/S# count and
NUAV = their UAV count, as Mesa programs every stage. A candidate for
the partial Settings icons, to be decided by the icon-pixels check.
2026-10-24 19:40:25 -04:00
Acelogic b3e916a6bb docs: describe the icon-pixels check in RUNNING.md
How to run icon-pixels in the guest, what it compares, where the
references come from and which offline test covers it.
2026-10-24 19:31:58 -04:00
Acelogic d43df34e40 tools: add the icon-pixels guest pixel test
The A16 showed partial System Settings icons while neither the plug-in
nor the kext refused anything, so the GPU ran the icon kernels and some
produced wrong or empty pixels; the encoding tests cannot see that.

build-icon-pixels.py builds and ad-hoc signs SnapMetal's icon-pixels
for arm64e and records its size, SHA-256 and CDHash (and the trust
row the guest would need if its AMFI refused an ad-hoc executable).

run-icon-pixels.py runs it in the guest from the root console shell:
pushes it with deploy-guest-plugin.py's checked chunk transfer, checks
that it executes, runs the synthetic CoreImage cases as root and the
system icons both in-process (root) and through NSWorkspace as the
console user (launchctl asuser + sudo -u), fetches every output file
three CRC-checked lines per command, optionally renames the icon
caches aside and restarts iconservicesd, iconservicesagent, the Dock
and System Settings (multi-user), collects the plug-in's per-process
and unified-log diagnostics, and compares. Offline it refuses the
steps that would act on this Mac's own processes.

compare-icon-pixels.py compares the guest's lines with this Mac's
within a tolerance and names the first matching explanation per case:
unwritten or partial output, readback or repeat differences, black or
transparent output, swapped red/blue, an extra or missing sRGB decode,
the missing or foreign input of a multi-input kernel (with its Metal
texture index), a broken blend band, otherwise the channels and tiles
that are off; for icons empty, black, partial, wrong colour or shape.
--census-only compares the dispatched kernels and formats of an
intercepted plug-in run.

icon-pixels-reference-synth.txt is this Mac's synthetic reference
(generated inputs only; M3 Max, 26A428, capabilities answered like the
deployed plug-in 378ff525). The icons reference summarises Apple's
icons and is not committed.

test-icon-pixels.py: the reference reproduces exactly on this Mac;
the plug-in device (commits intercepted) dispatches the same kernels
and formats with 8 CS sampler units and drops the multi-input ones
without; 20 injected faults are each diagnosed and a within-tolerance
perturbation passes; the whole console procedure runs over the
console stand-in with loss and noise and fetches lines identical to a
direct run.
2026-10-24 19:31:58 -04:00
Acelogic 2986fc3ba9 repo: point SnapMetal at the icon-pixels probe
SnapMetal 713dab1 adds harness/icon-pixels*.m, the on-device pixel
probe of the CoreImage kernels behind the System Settings icons.
2026-10-24 19:31:58 -04:00
Acelogic ee727e83c3 cycle: add --watchdog and --session for two-hour desktop runs
--watchdog SECONDS sets the run's watchdog from 1800 (the default, unchanged) to 7200 s; above 1800 the boot
preflight requires the A16 on AC. --session (with --console) leaves the guest trigger out of SNAP_EARLY_STOP, so the
kext never requests its first-present stop and a desktop session lasts until the watchdog, the thermal guard or
tools/request-stop.py. --early-stop-delay is checked against the run's watchdog. tools/test-session-watchdog.py
covers the default, the bounds, the delay check and the session's triggers.
2026-10-24 19:22:49 -04:00
Acelogic 80da17a462 repo: merge the kernel view pool reclaim (view-reclaim)
A 256-table kernel view pool with lazy reclaim of copies that no longer hold a protected leaf, behind --view-reclaim (SNAP_VIEW_RECLAIM); CODE_AT moves down 16 KiB so the monitor keeps 15 KiB of headroom with --edp-backlight; the pool's count, high-water mark and reclaims are reported as VIEWRCL1. next1 stopped at 1104 s when the 128-table pool was full (exit 7, ROZONE RETYPE refused).
2026-10-24 19:05:41 -04:00
Acelogic 49ccf6bf9b tests: cover kernel view reclaim and the 256-table pool
tools/test-view-reclaim.c drives a monitor-shaped kernel tree (one root,
one level 1, four level 2, 512 level 3) the way the retypes do: prepare,
detach, commit, refresh, with kernel_views_quiesce's steps as the
quiesce. After every step, independently of the library: each CPU's
walk of all 16,384 leaves gives the canonical descriptor or, for
selector2/4, its translation under that CPU's PPERM; no reachable page
holds an unpublished store; copies are distinct and never sources; no
store reaches a retired page before the TLBI after its unlinking.
Scenarios: fill to 256, a full pool and a one-slot-short path refuse
with no change, release and reclaim (TXM import, the level-2 ancestor),
reuse of the retired pages before any allocation, reclaim down to the
root, the restart of a two-frame change, read failure, nothing to
retire, unconfigured views and a failed quiesce. A quiesce without its
TLBI and a dropped protected table are caught (harness self-checks).

tools/test-view-reclaim.py runs it, nine weakened sprr-view.c copies
(each must fail: all do), test-kernel-pperm-variants.c with and without
the define, the wiring (default off, guarded uses, cycle, report place
and decoder) and, with --build, the monitor identities.
test-kernel-pperm-variants.c gains reclaim steps under the define:
positions move under the reuse snapshot, publication rows and variant
columns while both machines keep agreeing.

Tests that hard-coded the 128-table shape now derive it from
SPRR_VIEW_TABLES / USER_PUBLISH_MAX (test-tpro-view.c's RAM,
test-user-prepare-fused.c, test-user-fused-compare.c,
test-user-publish.c, test-user-tree-memo.c); define-off they check
exactly what they did.

Results on this tree (host, ASan/UBSan):
  python3 tools/test-view-reclaim.py              PASS (model 20,578
      checks; 9/9 mutants caught; consumers; wiring)
  python3 tools/test-view-reclaim.py --build --qualification
      .../installed-fresh-desktop-20261024-next1/qualification.json
                                                  PASS (absent == =0 ==
      86bb02ea9e03...; =1 459,904 bytes, 15,232 headroom)
  the 26 C suites linking sprr-view.c, with and without
      -DSNAP_VIEW_RECLAIM=1                      PASS (define-off check
      counts equal the base commit's)
Hardware: not run.
2026-10-24 18:53:55 -04:00
Acelogic 7b729890ef cycle: add --view-reclaim
installed-fresh --view-reclaim appends -DSNAP_VIEW_RECLAIM=1 after every
other monitor define. It is a monitor define only: no AuxKC, boot-arg
or loader change. docs/RUNNING.md describes it.
tools/test-edp-backlight.py's "appended last" check now lets this newer
define follow its own.

With next1's qualification flags plus the define the monitor is 459,904
bytes, 15,232 under the 464 KiB reservation; without it the monitor is
byte-identical to next1's (458,552 bytes, 16,584 under).
Hardware: not run.
2026-10-24 18:53:24 -04:00
Acelogic 411e17fd1b probes: report the kernel view pool as VIEWRCL1
With SNAP_VIEW_RECLAIM the report carries, behind "VIEWRCL1" and a word
of value bytes << 32, the kernel views' count, its high-water mark, the
reclaims that retired tables and how many, the refusals that found
nothing to retire, and the capacity. The record sits at a fixed place
just below the IB async slot (used or not); every chained record is
asserted to end before it. tools/perf_counters.py decode_view_reclaim
reads it (refusing a record whose counts disagree), decode_report adds
it as view_reclaim, the speed/installed-fresh summary keeps it, and
probes/run.py prints one line. 88 bytes of monitor code.
Hardware: not run.

probes/run.py's reservation note now gives the reclaim's exact cost with
this record: 1,352 bytes.
2026-10-24 18:53:18 -04:00
Acelogic b69884f31a probes: lower CODE_AT for a 464 KiB monitor reservation
With --edp-backlight the next1 monitor left 200 bytes of the 448 KiB
reservation, and SNAP_VIEW_RECLAIM adds about 1.3 KiB.

OUT_AT cannot rise: the report ends exactly at heap+0x480000, where the
stopped-probe scratch begins (tools/probe-a16-cpus.py, code at 0x480000,
output at 0x490000), and tools/secondary-runtime.py collect runs that
probe after the monitor returns and before probes/run.py reads the
report, so a higher report would lose its tail (the thermal and DVFS
records). CODE_AT moves down 16 KiB instead. Nothing in q1n1's heap
below CODE_AT is used during a run; the only other user of that range
is tools/qualify-txm-image4-native.py (heap+0x100000, 3 MiB), which
requires a fresh stage. q1n1 does not know these offsets, every tool
reads run.CODE_AT, and the monitor is position independent.

tools/test-monitor-reservation.py checks the new order (code, report,
stopped-probe scratch, SMP page, work locator), that the two stopped
probes use the scratch after the report, and the fresh-stage tool's
workspace. tools/test-reuse-match-mapped.py's budget follows.
Hardware: not run.
2026-10-24 18:53:06 -04:00
Acelogic e128ca1abe shadow: reclaim kernel view copies in a 256-table pool
installed-fresh-desktop-20261024-next1 stopped after 1,104 s with exit
7: a RETYPE to ROZONE was refused because sprr_views_prepare found the
kernel views at SPRR_VIEW_TABLES (128). Its context.bin shows that 114
of the 118 level-3 copies still held selector2 leaves (122 ROZONE
protects, 3 releases): each RO-zone frame lands in its own 2 MiB table,
so the live set itself reached the pool. In the 86 preserved runs of
6 minutes or more, releases stayed at 2 to 8.

SNAP_VIEW_RECLAIM (opt-in, default 0):

- SPRR_VIEW_TABLES becomes 256. struct sprr_views grows by 8,192 bytes
  and 65 of them precede pauth_bank, so PAUTH_BANK_CONTEXT moves under
  the define (still asserted). The publication rows, the row-empty
  checks (sprr_publish_row_empty) and USER_PUBLISH_MAX follow the
  capacity. Context +1.0 MiB, root_ext +1.5 MiB of the arena.
- sprr_views_reclaim retires every copied table no CPU needs: a level-3
  table without a valid selector2/4/9 leaf, an upper table none of
  whose entries leads to a needed copy, never the root. It reads every
  source before changing anything, compacts the metadata (kept tables
  in order, retired sets parked past count at SPRR_VIEW_RETIRED), then
  calls quiesce. kernel_views_quiesce drops the reuse snapshot and the
  publication rows, and shadow_tlb_sync syncs all six views (a retired
  table's parent entry names its canonical source again, an identical
  translation), publishes them and runs TLBI ALLE1IS. Only after that
  may add() reuse the six pages at that position; after a failed
  quiesce they stay unusable.

The trigger is lazy: kernel_views_prepare_change, used by the ROZONE
and TXM-default retypes, reclaims only when a prepare is refused with
fewer than three free slots, then prepares the whole change again,
because the reclaim also retires paths an earlier leaf of the change
prepared (not protected until the commit). prepare_path refuses a path
that does not fit before adding any of it. Nothing runs before the pool
is full: the refresh, PPERM and sync paths are unchanged.

Off, the monitor is byte-identical: next1's flags give 458,552 bytes,
sha256 86bb02ea9e03...; so does the build without SNAP_EDP_BACKLIGHT
and the define-free one. On, the code grows by about 1.3 KiB, which
needs the code reservation of the next commit. kernel_sync_view's
frame grows from 2,336 to 4,528 bytes (64 KiB EL2 stacks; worst
direct-call chain 13.2 KiB, unchanged).

The mirrored multipage_close in tools/test-multipage-fast.c and the
source check in tools/test-kernel-ops-perf-source.py follow the row
helper. Hardware: not run.
2026-10-24 18:52:53 -04:00
Acelogic 67013604d7 cycle: pin the next AuxKC for --edp-backlight runs
INPUT_AUXKC_DESKTOP_BACKLIGHT, the collection --edp-backlight selects
(the only route the next1 run's flags reach), becomes next-20261024:
KEXT_PROFILE=desktop-next I2C_PROFILE=desktop-fnkeys
tools/build-auxkc-desktop.sh at umbrella 78920c5, SnapAdreno b5bfcb4,
SnapI2CHID f0b7984 (sources.txt, no uncommitted changes).

  adreno-input.kc      57965a84916986eed68988b174d699eba06050207945af742c6dd57f616cbd82
  adreno-input.raw.kc  444b0cd1c732071075ca19668a16ca800cd0b752f6c84d072739251eb7e99f40
  AdrenoX2             3202fd6f (desktop-next)
  SnapI2CHID           4a81f74e (desktop-fnkeys)

The brightness branch named this pin for a PROFILE=desktop-backlight
AdrenoX2, which adds the service to desktop (coherent maintenance
skipping, for --gpu-coherent). The run has no --gpu-coherent, so the
pin holds desktop-next instead: desktop-nocoherent plus the service,
with the head rule, the IOMFB trace and the CS sampler opt-in. The
SnapI2CHID in it carries the Fn-key layer, so --input-fnkeys needs no
pin of its own. Both kexts are section-identical (12 of 12) to
separate builds of those profiles from the same tree.

Runs without --edp-backlight keep the latch collection
org-desktop-nocoherent-20261023 (ccf0c8f4, 353756d), which is also
the rollback. docs/RUNNING.md says which profile the pin holds.
tools/test-edp-backlight.py test_cycle now takes its pinned branch
and passes.
2026-10-24 04:14:34 -04:00
Acelogic 78920c59b6 docs: describe --input-fnkeys with the input flags
The fn-keys branch added installed-fresh --input-fnkeys and the
desktop-fnkeys SnapI2CHID profile but left docs/RUNNING.md without
them. List the flag in the Input row and say what it adds, which
SnapI2CHID build reads it, what its bits do and which test covers it.
2026-10-24 04:10:05 -04:00
Acelogic b78c12e1f2 repo: point the submodules at their next branches
SnapAdreno f54b9ec..b5bfcb4 (next):
  adreno-kext: add the desktop-next build profile
  (desktop-nocoherent plus ADRENO_BACKLIGHT in AdrenoDisplay.o, the
  kext of an --edp-backlight run without --gpu-coherent)
SnapMetal 936d51b..7bc40ef (next): the --no-ff merge of
  feature/settings-icons onto migrate-private 40a1864 (same tree as
  936d51b)
SnapI2CHID 816aad8..f0b7984 (next): the merge of feature/fn-keys
  (abaa501 Fn-key layer, 7c0a059 desktop-fnkeys profile). fn-keys made
  no pointer commit, so this is the first one that carries it; the
  umbrella's tests and build-auxkc-desktop.sh I2C_PROFILE need it.

Default builds stay section-identical to migrate-private
(tools/macho-sections.py, ZERO_AR_DATE=1): AdrenoX2 default 12 of 12,
SnapI2CHID default and desktop 12 of 12 each.
2026-10-24 03:58:07 -04:00
Acelogic fb02fa99c2 tests: check --edp-backlight and --input-fnkeys reach the boot-args
Both options already add their guest boot-args; the tests only called
boot_addition with hand-built namespaces. Parse real command lines
with cycle.py's parser and check the addition:

- test-edp-backlight.py test_cycle: no adreno_backlight=1 without the
  flag, adreno_backlight=1 with --edp-backlight (and no mode word),
  and both words, in order, with --edp-backlight-mode;
- test-input-fnkeys.py: --input-fnkeys 0x3, 3, 0x13 and 0b111 each
  give exactly one snap_i2c_fnkeys=<decimal value>, none without it.

For the next1 run's arguments (org2's plus --single-user,
--edp-backlight, --input-fnkeys 0x3, --adreno-cs-samplers) the
addition carries adreno_cs_samplers=1, adreno_backlight=1 and
snap_i2c_fnkeys=3.
2026-10-24 03:49:44 -04:00
Acelogic cf01e689d7 cycle: add --adreno-cs-samplers for the CS sampler opt-in
installed-fresh --adreno-cs-samplers appends the guest boot-arg
adreno_cs_samplers=1, the run-time half of SnapAdreno's
ADRENO_IB_CS_SAMPLERS: the IB validator admits CS sampler loads of up
to 8 units and AdrenoX2 publishes AdrenoIBComputeSamplers, so the
ADRENO_SETTINGS_ICONS plug-in encodes CoreImage's multi-input kernels.
An AdrenoX2 built without the define ignores the boot-arg. Without the
option the boot-argument addition is unchanged.

tools/test-adreno-cs-samplers.py: the default addition is unchanged,
the flag adds the boot-arg once (also beside --edp-backlight,
--input-fnkeys and --single-user), cycle.py's parser reaches the
namespace, AdrenoX2 reads exactly this name under the define, and the
desktop, desktop-nocoherent, desktop-backlight and desktop-next
profiles build AdrenoX2 and adreno-ib-command with it. A misspelt
boot-arg in installed_fresh.py fails it. docs/RUNNING.md lists the
flag and drops "no option yet".
2026-10-24 03:48:50 -04:00
Acelogic a254f01fc9 repo: merge the Settings pane icons (settings-icons)
Merge feature/settings-icons (b9c12cb..22aad4b). docs/RUNNING.md and
tools/cycle_lib/installed_fresh.py merge without conflict: the
settings-icons trust set (ADDITIONS/TRUST_PAYLOAD, mirror-slab kept as
ADDITIONS_MIRRORSLAB for rollback) sits beside the brightness and
fn-keys options.

gpu/adreno-kext/kext: SnapAdreno next f54b9ec, the merge of all three
SnapAdreno feature branches; gpu/adreno-kext/plugin: SnapMetal 936d51b
(feature/settings-icons).
2026-10-24 03:46:49 -04:00
Acelogic c993f8151f repo: merge the Fn-key layer tools (fn-keys) 2026-10-24 03:46:39 -04:00
Acelogic 5b35148492 repo: merge the eDP panel brightness (brightness)
Merge feature/brightness (7da9adf..f189da7) onto the display-modes
merge.

tools/check-iomfb-vtable.py: both branches added an AdrenoDisplay
define option (display-modes --display-define, applied to
AdrenoDisplay.cpp only; brightness --define, applied to every .cpp).
Keep one implementation: --display-define, with --define as an alias
of the same list, compiles AdrenoDisplay.cpp alone with the defines,
which is what both branches' help text promises and what
test-adreno-display-trace.py passes.

gpu/adreno-kext/kext: SnapAdreno next 53c0054, the merge of
feature/display-modes and feature/brightness.
2026-10-24 03:46:35 -04:00
Acelogic 39a39dba90 repo: merge the head rule and IOMFB trace (display-modes) 2026-10-24 03:45:45 -04:00
Acelogic 22aad4b906 docs: document the settings-icons switches and icon caches
BUILDING.md: the plug-in's ADRENO_PIPELINE and ADRENO_SETTINGS_ICONS
build switches (0 or 1; unset or 0 leaves the build unchanged) and the
suites that test the latter. RUNNING.md: a plug-in that changes icon
rendering needs IconServices' store, the user icon caches and the
Dock's icon cache renamed aside from the single-user shell before the
boot continues, and the order that does it with deploy-guest-plugin.py
and guest-console.py under one owner; ADRENO_IB_CS_SAMPLERS stays off
without the boot-arg adreno_cs_samplers=1, which cycle.py cannot add
yet.
2026-10-24 03:35:46 -04:00
Acelogic 8856849ef7 repo: point SnapMetal and SnapAdreno at the settings-icons work
SnapMetal 40a1864..936d51b (branch feature/settings-icons):
  adreno-metal: let build.sh pass ADRENO_PIPELINE
  adreno-metal: encode the CoreImage kernels of Settings pane icons
  adreno-metal: add the Settings pane icon harnesses
SnapAdreno 79de60e..e7b1d3c (branch feature/settings-icons):
  adreno-kext: opt in to multi-unit CS sampler loads (adreno_cs_samplers)
  adreno-kext: build the desktop profiles with ADRENO_IB_CS_SAMPLERS

Both features stay behind their defines. With ADRENO_SETTINGS_ICONS
unset or 0 the plug-in builds byte for byte as at 40a1864 (strict,
lenient, and with ADRENO_PIPELINE); without ADRENO_IB_CS_SAMPLERS the
default and desktop-profile kexts are byte-identical to 79de60e's. The
profiles now carry ADRENO_IB_CS_SAMPLERS, inert unless the guest boots
with adreno_cs_samplers=1. SnapAdreno's AdrenoX2 calls this
repository's adreno_ib_set_cs_sampler_units (compat, b9c12cb).
2026-10-24 03:35:46 -04:00
Acelogic d44fa698d2 cycle: trust and deploy the settings-icons plug-in set
The next installed run boots with the mirror-slab executable 758535d9
installed and must replace it with SnapMetal's ADRENO_SETTINGS_ICONS
build (lenient, ADRENO_PIPELINE, runtime v7: AdrenoMetal 378ff525,
CDHash c76a4677) from single-user mode.

installed_fresh: the trust additions become the settings-icons set's
(the mirror-slab set's 46 rows plus c76a4677: cdc784df, payload
247598bc); the mirror-slab set stays as ADDITIONS_MIRRORSLAB for
rollback, and every earlier CDHash stays trusted, so --restore still
boots. deploy-guest-plugin: the executable's base is the mirror-slab
758535d9 and its payload the 36,670-byte AdrenoMetal-758535d9.bsdiff;
the runtime and CodeResources are already the installed (wsabort) ones
and are skipped.

The set, build/current-assets/metal-stage-settingsicons-20261024, is a
local (ignored) input: AdrenoMetal, AdrenoMetal-758535d9.bsdiff,
trust-additions.json, trustcache.payload and SET.json.

Evidence: the prepare-time trust check (configure_guest, then
trust_cache_spec(ADDITIONS).load(FIRMWARE) against TRUST_PAYLOAD and
TRUST_SHA) passes for the installed, -input and -input-touchpad
profiles, for this set and the mirror-slab rollback;
tools/test-deploy-guest-plugin.py PASS 21 checks (install, again,
restore, refuse) over the console stand-in with 3% loss.
2026-10-24 03:33:06 -04:00
Acelogic 40556de8cd tools: add the System Settings icon suites
test-adreno-settings-icons.py: 261 cases (52 Settings extension icons,
34 type icons at 20 pt and 4 at 64 pt, 67 app icons, 87 named images
of the extensions' asset catalogs, 3 MonitorPanel previews, 14 SF
Symbols) through iconservicesagent's generation entry, the client's CPU
redraw and a CARenderer, on this Mac's GPU answering like the plug-in
(the reference, with pixels) and on the plug-in device. Per case: a
valid reference image, the same image size, nothing omitted or failed,
the same CoreImage kernels as the reference, and every package admitted
by the kext validator. --expect-before requires the unchanged plug-in
to fail. --cs-samplers N stands in for a kext publishing
AdrenoIBComputeSamplers, --cs-samplers-validator replays through this
tree's validator built with ADRENO_IB_CS_SAMPLERS and opted in,
--allow-kext-gated reports the kernels waiting for the property.
Replays run in parallel (--jobs), --cases selects by name.

test-adreno-settings-ci-encoding.py decodes the CS T#, sampler, TSIZE
and SP_CS_CONFIG state of one CoreImage kernel per sampled format (13)
and of a two-input srcOver, with and without the property, checks a
replaceRegion/getBytes round trip of each format against this Mac's
GPU, and requires the production validator to refuse the 2-unit sampler
load that the opted-in validator admits.

Ported from agents/settings-ui (the scratch tree's --kext-tree and
--validator-tree proposal replaced by --cs-samplers-validator, replays
parallelised). Results on this Mac (26A428) in the handoff: the
unchanged plug-in fails 24 of 2873 icon checks and 27 of 126 encoding
checks; ADRENO_SETTINGS_ICONS passes 4713/4714 and 351.
2026-10-24 03:19:47 -04:00
Acelogic b9c12cb158 compat: let the IB validator admit opted-in CS sampler units
CoreImage's multi-input kernels (the folder, document and Safari icons
inside System Settings panes) load one S# per sampled input. The
validator admits exactly one CS sampler unit per LOAD_STATE.

ADRENO_IB_CS_SAMPLERS (default off) adds adreno_ib_set_cs_sampler_units:
1 (the default, as without the define) up to
ADRENO_IB_CS_SAMPLER_UNITS_MAX (8), any other value meaning 1. An S#
holds no address and the load stays bounded by its package relocation
(NUM_UNIT * 16 bytes), as an FS sampler load is; DST_OFF is still
refused. SnapAdreno's AdrenoX2 calls it once, from configureDevice,
only with the boot-arg adreno_cs_samplers=1.

tools/test-adreno-ib-command.c gains test_ib_cs_samplers: one unit
admitted, two refused (E_PACKET) and DST_OFF refused in every build;
with the define, after the opt-in, 2 and 8 units admitted, 9 refused
(E_PACKET), 3 units over a 2-entry table refused (E_BOUNDS), and the
limit back to one for 0 and 9. -DIB_REPLAY_CS_SAMPLER_UNITS=N makes
--replay validate as an opted-in kext (the settings-icons suites).

Evidence: self test (ASan/UBSan) PASS 47286 IB command checks without
the define (46714 before), 47286 with it 0, 48982 with it 1; three
validator mutants (opt-in ignored, two units without the define, no
clamp) each fail it. Without the define the AdrenoX2 kexts (default,
desktop-nocoherent, desktop) are byte-identical to the unchanged
tree's (ZERO_AR_DATE=1, same OUT path).
2026-10-24 03:19:35 -04:00
Acelogic 981b1d399e tests: cover the head rule glue and the IOMFB trace
- test-adreno-residency.py HeadOffset:
  - scenario 33 is built with re-pin only (org2's refusal reproduced)
    and with the head rule (admitted and mapped);
  - nine weakened head rules each fail;
  - the kext glue calls the rule, under its define, after the wire;
  - the desktop profiles build the define in every unit.
- test-adreno-display-present.c geometry runs
  adreno_display_swap_geometry over the panel's mode, macOS's scaled
  resolutions of a 2880x1800 panel, placement, cropping, negative
  rectangles and an unknown surface.
- test-adreno-display-trace.py:
  - four weakened geometry rules each fail;
  - every traced IOMFB method forwards its arguments unchanged and
    returns the family's result;
  - every trace identifier is behind its define;
  - check-iomfb-vtable.py with the desktop profile's display defines
    keeps all 483 slots. That check is SKIP without the KDK and the
    J700 kernelcache.
2026-10-24 01:46:09 -04:00
Acelogic 40a150a538 repo: move SnapAdreno to the head rule and IOMFB trace
SnapAdreno feature/display-modes (c1b4ad5):
- moves the re-pin refusal report into an ordered part;
- adds ADRENO_RESIDENT_HEAD_OFFSET: page-unaligned client buffers are
  mapped in whole pages, using compat/adreno-resource-tail.h;
- adds ADRENO_DISPLAY_TRACE_MODES: the IOMFB call and swap geometry
  trace;
- builds both in the desktop profiles.
With the defines off, the default build and both profiles are
section-identical to SnapAdreno 79de60e.
2026-10-24 01:46:09 -04:00
Acelogic 19c38ed641 tools: let check-iomfb-vtable build AdrenoDisplay with defines
--display-define NAME[=VALUE] (repeatable) adds a -D to the
AdrenoDisplay.cpp compile only. The checker can then verify a
profile's display object, including option-only overrides such as
the IOMFB call trace, slot by slot against the kernelcache. Without
the option it builds exactly as before.
2026-10-24 01:46:09 -04:00
Acelogic 6276284067 compat: add the head rule for page-unaligned client buffers
IOGPU sizes a client buffer's memory as round_page(page offset +
length) (IOGPUSysMemory::withClientBuffer). A buffer at a
page-unaligned address gets a map one page past what the tail rule
admits, so it is refused -83. In b12v23 and org2 one such WindowServer
buffer was a 16 KiB descriptor under a 32 KiB map. It was refused at
the onset of the Displays-pane glitch. Every composite that listed it
then failed its preparation (-115), until the run ended.

The rules, header-only beside the tail rule:
- admission: the map is exactly the pages that [head, head + bytes)
  touches;
- segments: the first run starts at its page, and the last one runs to
  its page end;
- cache: only the descriptor's lines, with partial first and last
  lines cleaned and invalidated;
- ranges: a client offset lands at head + offset, inside the
  descriptor's bytes.
With head 0 every function gives the tail rule's answer.

tools/test-adreno-residency.c models the descriptor's head.
- Scenario 33 is org2's buffer at seven heads. With re-pin only it is
  refused cleanly (E_PIN) every round. With the head rule it is
  admitted, the GPU reads each client byte where the CPU wrote it, and
  it survives unwire, eviction and a replaced descriptor.
- Scenario 34 checks what is still refused: a map a page too long or
  too short, and boot-arg adreno_head_offset=0. It also checks head-0
  equivalence with the tail rule over every byte count up to three
  pages, and misplaced segments.
All parts of the model pass in four builds: base, re-pin, re-pin plus
head rule, and that with the arena and VA reclaim.
2026-10-24 01:46:09 -04:00
Acelogic 58bc2aee86 cycle: create q1n1's build/a16-gpu before the first GPU step log
A fresh q1n1 checkout has no build/ tree, so the org1 boot was refused when
a16gpu() opened its first step log. The record directory is now created first.
2026-10-24 00:38:34 -04:00
Acelogic 353756d561 cycle: pin the org-built non-coherent desktop AuxKC
Built by tools/build-auxkc-desktop.sh with KEXT_PROFILE=desktop-nocoherent at
SnapAdreno 79de60e, which includes the re-pin log fix. SnapI2CHID is
section-identical to the deployed d90e0199; AdrenoX2 differs from the deployed
981e0b88 only by the removed raw-offset task lookup. --gpu-coherent stays off
until the display path handles coherent surfaces.
2026-10-23 21:12:59 -04:00
Acelogic 030c66596b cycle: pin this tree's launcher and persistence tool hashes
pins.example.json pinned the integration tree's
tools/run-sks-transport-candidate.py (52fe215a) and
tools/capture-apfs-persistence.py (4d59b3df). This repository's copies
differ from those only in the SPDX line the public release added, so
installed_fresh's launcher_steps refused every --prepare from a
pins.json copied from the example ("... changed"), and storage's
pinned_tool refused the persistence capture. Pin this tree's bytes
(c967ab84, f2d49308); the STEPS the launcher yields are unchanged.

The observers pinned under build/ (panel/GUI collectors and captures,
the stopped-run helper, the installed snapshot) are run scripts that
were never exported; those pins stay as examples for a local pins.json.
2026-10-23 21:04:35 -04:00
Acelogic 230f8b3a9b cycle: pin the q1n1 stage pair the org q1n1 builds
pins.example.json pinned q1n1-stage.bin 752b4ab7 and q1n1-stage-alt.bin
e6276e5a, which no current q1n1 build produces, so `cycle.py retire`
(stage_pair) refused every checkout started from the example. `make
uefi` in the Snapintosh q1n1 repository at 7872398 (migrate-private)
builds 56f57510 / 5d6f7df0, the same bytes as the integration tree's
q1n1 build; b12v23 recorded running that q1n1-stage.bin. A
stages_source entry says where the pair comes from. The per-machine
pins.json stays local and untracked.
2026-10-23 21:04:23 -04:00
Acelogic 3a07fba3cb compat: regenerate the recover table against the org q1n1
compat/adreno-recover-table.h recorded the sha256 of sme-batch12's q1n1
a16gpu_stage3.py and adreno_x2.py, so installed_fresh's
recover_table_check refused a --gpu-recover reset prepare against the
Snapintosh q1n1 repository (branch migrate-private, 7872398), whose
files differ (adreno_x2.py moved its GPL-2.0-only tables, among them
X285_NONCTXT that hw_init writes, into adreno_x2_protect.py).

tools/gen-adreno-recover-table.py now also records
adreno_x2_protect.py when the q1n1 checkout has it, since hw_init's
non-context writes come from there. Regenerated from that q1n1, only
ADRENO_RECOVER_TABLE_INPUTS changes: every replayed operation, the
CP_ME_INIT words and the SECVID ops are the same. The macro is read
only by the prepare check, so no monitor binary changes.

tools/test-gen-adreno-recover-table.py passes against that q1n1 (it
failed before). compat/adreno-ib-tables.h already records
adreno_x2_protect.py, and its generator reports it fresh against the
same q1n1 and the pinned Mesa.
2026-10-23 21:03:00 -04:00
Acelogic 5ff9d30407 docs: document the desktop build profiles and coherency flags
BUILDING.md: the SnapAdreno and SnapI2CHID PROFILE builds, how to
compare one with a deployed kext, and tools/build-auxkc-desktop.sh.
RUNNING.md: --gpu-coherent and --resident-mib in the GPU flag group,
what b12v20 and b12v23 add to the listed desktop configuration, what
--gpu-coherent requires (--gpu-va-wide, --root-cache-wide, the
desktop-profile kext and a q1n1 with `a16gpu adopt --coherent`) and
that --gpu-coherent-force is a debug build.
2026-10-23 21:00:53 -04:00
Acelogic be64b7055a cycle: pin the coherent-v3 desktop AuxKC
The --present-latch desktop collection the A16 boots since b12v23:
AdrenoX2 c66edb6b (re-pin, aligned live copies and IO-coherent
maintenance skipping; SnapAdreno PROFILE=desktop at its profiles
commit) and SnapI2CHID d90e0199 (PROFILE=desktop), AuxKC bd057773.
The previous pin, latch2-pipe2-recover-nosparse 2cb7b6cc (b12v17), is
four collections back; the history comment lists each step.

The collection itself stays a local, never-committed input under
build/current-assets/. tools/build-auxkc-desktop.sh rebuilds one from
this checkout and prints the pin lines; its bytes differ from
bd057773 (kext UUIDs, staging paths), so a rebuilt collection needs
its own pin.
2026-10-23 21:00:13 -04:00
Acelogic 284506d407 tools: say what keeps a desktop AuxKC from reproducing byte for byte
The previous commit said a rebuilt collection differs from a deployed
one only in UUID-derived bytes. It also differs in each kext's
_PrelinkBundlePath: build-auxkc-user.py stages the kexts in a randomly
named temporary folder and kmutil records that path in the prelink
info. Comparing bd057773 and 43bed810 with collections rebuilt from
the profiles commit, the differing bytes are exactly: the collection
UUID, both kexts' LC_UUID, the receipt's digests, the OSBundleUUID and
_PrelinkKCID strings, and the two staging paths. Document this in the
script header. Comment only.
2026-10-23 20:59:47 -04:00
Acelogic 80bc1af75a tools: add build-auxkc-desktop.sh
Build the A16 desktop AuxKC from this checkout: AdrenoX2 with
SnapAdreno's PROFILE=desktop (KEXT_PROFILE=desktop-nocoherent for a
monitor without --gpu-coherent) and SnapI2CHID with its desktop
profile, then link them the way the deployed collections were linked:
tools/build-auxkc-user.py, tools/auxkc-autoload.py (both bundles,
packaging.json) and build/build-auxkc.py pin for the installed desktop
guest profile. It writes build/current-assets/NAME/ (refusing an
existing one), records the source revisions and per-unit define sets
beside the collection, prints every output's sha256 and the two
installed_fresh.py lines that pin it, and with REFERENCE compares both
kexts section for section with a deployed collection's.

ZERO_AR_DATE=1 is exported unless set, so two builds in one checkout
give the same kext bytes. A collection built elsewhere still differs
from a deployed one in the kexts' UUIDs and what derives from them
(the collection UUID, the receipt's per-kext hashes and the prelink
info's UUID strings).

Checked in a copy of this branch with the J700 downloads: with
SnapAdreno at its profiles commit, desktop and desktop-nocoherent give
AdrenoX2 12 of 12 sections equal to c66edb6b and 981e0b88 and
SnapI2CHID 12 of 12 equal to d90e0199; the collections are the size of
bd057773 and 43bed810 and differ only in those UUID-derived bytes.
2026-10-23 20:59:19 -04:00
Acelogic e5bb36ea2c repo: point SnapAdreno and SnapI2CHID at their desktop profiles
SnapAdreno 3985c26..79de60e (branch migrate-private):
  adreno-kext: re-prepare evicted maps (ADRENO_RESIDENT_REPIN)
  adreno-kext: skip write-back maintenance once coherency is verified
  adreno-kext: add desktop build profiles
  adreno-kext: drop the raw-offset task lookup from the re-pin log
  adreno-kext: say which commit the desktop profiles reproduce
SnapI2CHID 9cd36f4..816aad8 (branch migrate-private):
  input: add a desktop build profile

Every new kext feature stays behind its define; the default builds of
both kexts are unchanged section for section. The re-pin and coherent
kext code uses this repository's compat/adreno-resource-tail.h and
compat/adreno-coherent-skip.h.
2026-10-23 20:57:24 -04:00
Acelogic 399ee928d7 compat: add the kext's IO-coherent maintenance-skip rules
compat/adreno-coherent-skip.h (only with -DADRENO_COHERENT_SKIP_MAINT=1)
decides, per map and per kernel command, how an AdrenoX2 maintains CPU
caches once the monitor's ADRENO_GUEST_COHERENT QUERY answers ON:
- PLAIN: today's ADRENO_GUEST_CACHE when there is no ON answer (older
  monitor, failed self-test, boot-arg absent, or a forced ON the kext
  was not told to accept) or the backing's declared cache mode is not
  write-back;
- CALL: ADRENO_GUEST_CACHE with ADRENO_CACHE_COHERENT, where the
  monitor maintains only the frames the CPU does not map write-back;
  a whole-map pass that needed none records a verdict at the current
  CPU attribute epoch;
- SKIP: no call, only while that verdict's epoch is still current.

tools/test-adreno-coherent-kext.c drives these rules the way
AdrenoMemoryMap's cacheSubmission and cacheRange do against a model of
the CPU data cache, per-frame attributes and the monitor's answers,
including epoch changes, forced answers and malformed replies.
2026-10-23 20:49:44 -04:00
Acelogic 73397243cf compat: add the re-pin tail rule and its residency model
compat/adreno-resource-tail.h is the rule an ADRENO_RESIDENT_REPIN
AdrenoX2 uses for a backing descriptor shorter than its GPU map by less
than one page (IOGPU page-rounds a client buffer's memory length): pin
and map whole pages, keep the descriptor's last byte as the end of
every physical segment it hands out, and stop cache maintenance at the
descriptor's last line, cleaning (never invalidating) a partial one.
Nothing includes it unless ADRENO_RESIDENT_REPIN is defined.

tools/test-adreno-residency.c models the kext side with the define:
a cleanly refused commit is reported committed and remembered, the map
stays unadmitted and retries its pin at its own preparation, and
scenarios 30-32 (`repin`) cover evict -> re-prepare -> submit, b12v17's
3-page + 0x1010-byte buffer under a 4-page map, and one refused map
among several maps of the same memory. Without the define the model
and its expectations are unchanged.
2026-10-23 20:47:30 -04:00
Acelogic b113e7e816 cycle: add --gpu-coherent and --gpu-coherent-force
--gpu-coherent appends -DSNAP_ADRENO_COHERENT=1 after every earlier
flag, refuses to run without --gpu-va-wide (the self-test's scratch is
the q1n1 arena's Stage 4 pool region) and --root-cache-wide (its state
is in root_ext), adds the guest boot-arg adreno_coherent=1, and asks
q1n1 `adopt --coherent` to prove CB0 MAIR0/CBAR read-only before the
monitor relies on them.

--gpu-coherent-force (debug only, needs --gpu-coherent) appends
-DSNAP_ADRENO_COHERENT_FORCE=1 and the boot-arg adreno_coherent_force=1.

Without the options nothing changes. b12v20's argv reproduces its
qualification's flags, environment and boot-args, and b12v23's argv
(--gpu-coherent) reproduces its own.
2026-10-23 20:45:49 -04:00
Acelogic f2bbd16a82 compat: add opt-in IO-coherent GPU mappings with a bounded self-test
SNAP_ADRENO_COHERENT (off by default; needs SNAP_ROOT_CACHE_WIDE). At
GPU prepare, before the guest exists and while CB0's mirror holds no
guest leaf, compat/adreno-coherent.c runs a bounded self-test through
the ring: CP_MEMCPY jobs of at most 1 MiB in both directions, with
non-coherent controls first and a PMU refill witness. Only if every
iteration passes do the mirror leaves become IO-coherent (AttrIndx 1,
SH inner shareable; MAIR0 index 1 is re-read before use and before
every IB). Any other outcome keeps today's leaves and maintenance.

The guest learns the outcome through ADRENO_GUEST_COHERENT (QUERY:
state, detail, the CPU attribute epoch, iterations passed), and may
then ask ADRENO_GUEST_CACHE with ADRENO_CACHE_COHERENT, which keeps the
plain call's validation and refusals and maintains only frames whose
live CPU attribute is not Normal write-back. A monitor without the
define refuses QUERY, so a kext falls back to full maintenance.
SNAP_ADRENO_COHERENT_FORCE is a debug build that reports ON without the
self-test and says FORCED in EV_GPU_COHERENT.

probes/run.py links compat/adreno-coherent.c only when the define is in
FLAGS (OPTIONAL), after MULTI's objects, and decodes EV_GPU_COHERENT
(59); tools/monitor_build_offline.py follows the same rule. With the
define off the monitor objects and ELF are unchanged: b12v20's flags
rebuild its xnuboot.bin/.elf byte for byte, and b12v23's flags (with
the define) rebuild its xnuboot.bin/.elf byte for byte.

Tests: tools/test-adreno-coherent.c (async, sync and forced builds),
and the existing Adreno, ring and SPTM-DART harnesses with the define
on and off.
2026-10-23 20:45:24 -04:00
Acelogic 80b48fbbb4 cycle: add --resident-mib
Pass the AdrenoX2 resident-map budget to the guest as the boot-arg
adreno_resident_mib=MIB (0 disables residency, at most 4096). An
ADRENO_RESIDENT_REPIN kext reads it; older kexts ignore the boot-arg.
Without the option the boot-args are unchanged.

The A16 desktop runs since b12v19r pass --resident-mib 1536. With this
option b12v20's argv reproduces its qualification's
boot_argument_addition exactly.
2026-10-23 20:41:43 -04:00
Acelogic 2c60b47a95 repo: move the components to their split sources
SnapI2CHID 9cd36f4, SnapQCC2072 244d5c7, SnapAdreno 3985c26, SnapMetal 40a1864
and air2ir3 55865cc split their large files into ordered parts that compile
as one translation unit each. Object code is unchanged in every component.
2026-10-23 04:06:57 -04:00
Acelogic fe5a18d09d tools: drop duplicate source_text imports left by the merge 2026-10-23 04:05:11 -04:00
Acelogic 65cb50d0c7 tools: hash air2ir3's split source parts in runtime builds
build-adreno-compiler-runtime.py records the SHA-256 of every air2ir3
compiler source it compiles (compiler_id.SRC). air2ir3 now keeps
src/air2ir3.cpp as ordered parts in src/air2ir3/ that the main file
#includes, so hashing only the listed files would leave most of the
compiled code out of the record. Hash each listed file followed by its
parts, using tools/source_text.source_files. For an air2ir3 checkout
without parts the recorded inputs are the same as before.
2026-10-23 04:04:50 -04:00
Acelogic 984f03937b tools: read AdrenoDrawCommands.m with its split parts
SnapMetal moves AdrenoDrawCommands.m's code into ordered parts under
AdrenoMetal/AdrenoDrawCommands/, #included by the main file. Tools that
read that file as text or hash the plug-in's sources must see the whole
unit:

- test-adreno-staging-arenas.py: the A4 lock check reads the unit with
  read_source(). On the main file alone it would find no lock at all
  and fail; its line numbers now refer to the expanded unit.
- qualify-gen57-windowserver-cause.py: binds every file of the unit
  (source_files) and searches read_source(). An unsplit tree binds and
  reads exactly what it did before.
- check-adreno-resource-encoding.py: hashes AdrenoMetal/ recursively,
  so the qualification record covers the parts.

Evidence: py_compile of the three tools; the A4 check finds the same 6
locked regions in the unsplit file and in read_source() of the split
unit (none in the main file alone), and flags a release inserted inside
one of them.
2026-10-23 04:04:50 -04:00
Acelogic 4b83aba2d2 tools: read split AdrenoDisplay and AdrenoX2 units whole
SnapAdreno now keeps AdrenoDisplay.cpp and AdrenoX2.cpp as a main
file plus ordered parts in src/AdrenoDisplay/ and src/AdrenoX2/. Tools
that read or hash those files by name saw only the main file.

- test-adreno-residency.py: VAKext reads AdrenoDisplay.cpp through
  read_source. On the main file alone its #if ADRENO_VA_RECLAIM guard
  check would see 1 of the 4 guarded lines and still pass.
- build-panel-mode-candidate.py, qualify-adreno-gui-components.py,
  qualify-adreno-ib-command.py, qualify-adreno-resource-kext.py: record
  the hash of every file of the unit (source_files), not the main only.
- bind-ca-metal-components.py, bind-composite-metal-components.py:
  compare the display unit with the accepted checkout's file by file.

On an unsplit checkout source_files returns the main file alone, so
records of older trees bind what they bound before.

Left as they are: qualify-early-stop-kext.py and qualify-display8-kext.py
(their file lists are one historical change set; their rglob binding
already covers the parts), check-iomfb-vtable.py and
build-deployed-b12.sh (they compile the main file, which includes the
parts).

test-adreno-residency.py passes on the split tree and on the base tree.
The other six need historical build trees and were not run end to end;
each loads with source_text and its changed expression lists the
unit's files (smoke check).
2026-10-23 04:04:50 -04:00
Acelogic 4c07284535 tools: read SnapI2CHID.cpp through read_source in its checks
SnapI2CHID.cpp now #includes its implementation from ordered parts
under drivers/snap-i2c-hid/src/SnapI2CHID/. The checks that read it as
text would see only the main file: test-i2c-input.py's node-property
names, and in test-snap-i2c-hid-kext.py the MMIO contract (test_5) and
the mutations of test_7 and test_8, whose targets now sit in the parts.
They read the whole unit through source_text.read_source. Each mutant is
written as that expanded unit, so it compiles without the parts.

Harnesses that compile the drivers by path need no change: quoted
includes resolve next to the including file. On an unsplit file
read_source returns the text unchanged, so the checks pass on either
tree.

Evidence (host, macOS 27 26A428, each under a 300 s timeout):
- test-snap-i2c-hid-kext.py, one process per test (test_1 to test_8):
  PASS on the split tree and on the tree before it.
- test-i2c-input.py: PASS (9 ok, 3 skipped by design) on both trees.
- The previous checks against the split tree: test_5, test_7, test_8
  and test_property_names_fit FAIL, so the change is needed.
2026-10-23 04:04:50 -04:00
Acelogic 31dd19d4f8 compat: split ans.c into ordered parts
Move compat/ans.c's top-level ranges verbatim into
compat/ans/{nvme_model,sptm_dma}.c and #include them from ans.c in
their original order. ans.c keeps its header comment, include, layout
assertions, the ANS_ORDER barrier and the NVMe register and status
macros. Cuts fall only between top-level definitions; every part has
balanced conditionals.

No tool reads ans.c as text: tools/test-nvme-async.py compiles and
preprocesses it, which follows the includes, and the tools that pin
monitor sources already hash every part (first commit of this series).

Verification (base 84dd208 vs this commit):
- clang -c with the qualification flags (no -flto) and with
  probes/run.py FLAGS, each plus -I shadow -I q1n1/platform/uefi:
  compat/ans.c objects byte-identical (cmp). PASS
- Qualification flags with -flto: llvm-dis output equal; the full IR
  differs only in 2 inline-asm !srcloc source-location cookies (the
  ANS_ORDER barrier). PASS
- probes/run.py build('xnuboot') with the qualification flags:
  xnuboot.bin unchanged (sha256 0d8b9ec3...). PASS
- tools/test-ans.c host harness (ASan/UBSan, -DANS_HOST) on both trees:
  "402324 checks, 0 failures". PASS
- Reconstruction from the parts reproduces ans.c exactly.
- Host subset (23 commands, including test-nvme-async), 300 s limit:
  every outcome equal to base 84dd208. No new failure.
- wc -l: ans.c 34, parts 472 and 508 lines.
2026-10-23 04:04:44 -04:00
Acelogic 3946f848c2 compat: split txm.c into ordered parts
Move compat/txm.c's top-level ranges verbatim into
compat/txm/{trust_cache,image4_aspace}.c and #include them from txm.c
in their original order; txm.c keeps only its includes. Cuts fall only
between top-level definitions; every part has balanced conditionals.

tools/test-txm-aspace-wide.py reads txm.c through read_source(), so its
mutants find their anchors and are written out as the whole unit. The
other readers (test-descriptor-stores, test-token-costs) already read
whole units since the sptm-user split.

Verification (base 84dd208 vs this commit):
- clang -c with the qualification flags (no -flto) and with
  probes/run.py FLAGS, each plus -I shadow -I q1n1/platform/uefi:
  compat/txm.c objects byte-identical (cmp). PASS
- Qualification flags with -flto: llvm-dis output identical and the
  bitcode byte-identical. PASS
- probes/run.py build('xnuboot') with the qualification flags:
  xnuboot.bin unchanged (sha256 0d8b9ec3...). PASS
- Reconstruction from the parts reproduces txm.c exactly.
- Host subset (50 commands: the standard battery and every test or
  tool that names txm.c or builds the SPTM/TXM core), 300 s limit:
  every outcome equal to base 84dd208. No new failure.
- wc -l: txm.c 9, parts 501 and 519 lines.
2026-10-23 04:04:44 -04:00
Acelogic ba76bf2712 compat: split adreno-ib-command.c into ordered parts
Move compat/adreno-ib-command.c's top-level ranges verbatim into
compat/adreno-ib-command/{stage_relocate,validate,submit}.c and
#include them from adreno-ib-command.c in their original order. The
main file keeps its header comment, the register-table define, its
includes (AdrenoA8xxRegs.h and the GPL-2.0-only adreno-ib-tables.h stay
included here, unchanged) and its macros. The parts carry no GPL text.
Cuts fall only between top-level definitions; every part has balanced
conditionals.

The kext build (gpu/adreno-kext/kext/build.sh) and the host harnesses
compile adreno-ib-command.c directly, and the quoted part includes
resolve beside it, so their commands are unchanged. No tool reads the
file as text; the qualification tools that pin it
(qualify-adreno-ib-command, qualify-a8xx-compute-admission,
qualify-adreno-blit-admission, replay-ca-renderer-copy) now also hash
its parts through source_files().

Verification (base 84dd208 vs this commit):
- clang -c with the qualification flags (no -flto) and with
  probes/run.py FLAGS, each plus -I shadow -I q1n1/platform/uefi:
  compat/adreno-ib-command.c objects byte-identical (cmp). PASS
- Qualification flags with -flto: llvm-dis output identical and the
  bitcode byte-identical. PASS
- build.sh's kext COMMON flags (arm64e, -mkernel): object
  byte-identical without -g; with -g the disassembly and symbol table
  are identical (only DWARF file names differ). PASS
- tools/test-adreno-ib-command.c host self-test (ASan/UBSan) built
  and run on both trees: identical output, "46714 IB command checks".
  PASS
- Reconstruction from the parts reproduces adreno-ib-command.c
  exactly.
- Host subset (30 commands, 300 s limit): every outcome equal to base
  84dd208; the qualification tools fail identically on both trees for
  want of their captures and pre-change refs. No new failure.
- wc -l: adreno-ib-command.c 21, parts 248 to 482 lines.
2026-10-23 04:04:44 -04:00
Acelogic 4f4afd1c5c compat: split sptm-root.c into ordered parts
Move compat/sptm-root.c's top-level ranges verbatim into
compat/sptm-root/{views,view_updates,linked_switch}.c and #include them
from sptm-root.c in their original order. Cuts fall only between
top-level definitions; every part has balanced conditionals.

sptm-root.c keeps its includes and MASK, and also its final
#if SNAP_FINE_SWITCH block (93 lines): that block includes
fine-lock.h, which resolves only beside sptm-root.c (the monitor build
has no -Icompat), and fine-lock.h itself carries a guarded
#define SNAP_FINE_SWITCH, so the block is not split into two
conditionals either.

Tools that read sptm-root.c as text now read the whole unit through
read_source(): test-descriptor-stores, test-el0-memo (the four
active-root stores), test-root-miss and test-user-hw-walk (source text
and mutants), and the mutant copies of test-root-miss, test-root-wide
and test-fine-locks.

Verification (base 84dd208 vs this commit):
- clang -c with the qualification flags (no -flto) and with
  probes/run.py FLAGS, each plus -I shadow -I q1n1/platform/uefi:
  compat/sptm-root.c objects byte-identical (cmp). PASS
- Qualification flags with -flto: llvm-dis output identical and the
  bitcode byte-identical. PASS
- probes/run.py build('xnuboot') with the qualification flags:
  xnuboot.bin unchanged (sha256 0d8b9ec3...). PASS
- Reconstruction from the parts reproduces sptm-root.c exactly.
- Host subset (59 commands, 300 s limit), against base 84dd208 with
  base's host-load timeouts rerun: every outcome equal except
  test-fine-locks --quick, which adds test_unfair_mutants_fail. That
  fairness mutant check depends on thread timing: rerun three times
  on base it failed twice the same way (a surviving unfair mutant in
  compat/fine-lock.h or service-lock.c, which this change does not
  touch) and passed once; on this tree it passed once and timed out
  twice. Not a new failure.
- wc -l: sptm-root.c 108, parts 359 to 540 lines.
2026-10-23 04:04:44 -04:00
Acelogic cf681c6fa8 compat: split sptm-user.c into ordered parts
Move compat/sptm-user.c's top-level ranges verbatim into
compat/sptm-user/{walk_nest,table_map,region_update}.c and #include
them from sptm-user.c in their original order. sptm-user.c keeps its
includes and its two address macros. Cuts fall only between top-level
definitions; every part has balanced conditionals.

Tools that read sptm-user.c as text now read the whole unit through
read_source(): test-shared-compressed and test-unmap-mixed (engine
text and mutant anchors), test-descriptor-stores (the 8-byte helper
checks over every model file), and the mutant-tree builders of
test-token-costs and test-unnest-4k-fast (copies and anchors), so a
mutated unit is written out whole.

Verification (base 84dd208 vs this commit):
- clang -c with the qualification flags (no -flto) and with
  probes/run.py FLAGS, each plus -I shadow -I q1n1/platform/uefi:
  compat/sptm-user.c objects byte-identical (cmp). PASS
- Qualification flags with -flto: llvm-dis output identical and the
  bitcode byte-identical. PASS
- probes/run.py build('xnuboot') with the qualification flags:
  xnuboot.bin unchanged (sha256 0d8b9ec3...). PASS
- Reconstruction from the parts reproduces sptm-user.c exactly.
- Host subset (58 commands: the standard battery, the gcc SPTM suites
  that compile sptm-user.c, and every test or tool that names it or
  builds the SPTM core), 300 s limit: 54 outcomes equal to base
  84dd208 on the first pass; the other four differed only by host-load
  timeouts and on rerun PASS on both trees (test-sptm-fine,
  test-token-costs Unit and Mutants, test-unnest-4k-fast Unit). No new
  failure.
- wc -l: sptm-user.c 17, parts 379 to 717 lines.
2026-10-23 04:04:44 -04:00
Acelogic edf7cf9f14 compat: split device.c into ordered parts
Move compat/device.c's top-level ranges verbatim into
compat/device/*.c (device_core, device_rtc, device_dock_dart,
device_asc, device_i2c, device_pmgr, device_power, device_state) and
#include them from device.c in their original order. device.c keeps
its includes, the layout assertion and the forward declarations. Cuts
fall only between top-level definitions; every part has balanced
conditionals.

Phase 1 moves code without reordering it, so device_asc.c starts with
the I2C status bits that device_i2c.c uses, and device_state.c holds
the 899-line device_model_access_state.

Tools: tools/test-fast-timer-irq.py reads device.c through
read_source(), and tools/test-kernel-pperm-fast.py's scan of
compat/*.c for map_shadow sizes reads each whole unit. The hashing
tools already add every part of each .c they pin (previous commit).

Verification (base 84dd208 vs this commit):
- clang -c with the qualification flags (no -flto) and with
  probes/run.py FLAGS, each plus -I shadow -I q1n1/platform/uefi:
  compat/device.c objects byte-identical (cmp). PASS
- Qualification flags with -flto: llvm-dis output identical and the
  bitcode itself byte-identical. PASS
- probes/run.py build('xnuboot') with the qualification flags:
  xnuboot.bin unchanged (sha256 0d8b9ec3...). PASS
- Reconstruction from the parts reproduces device.c exactly.
- Host subset (30 commands: the standard battery, every test or tool
  that names device.c, scans compat/*.c or pins monitor sources),
  300 s limit: every outcome equal to base 84dd208; no new failure.
- wc -l: device.c 25, parts 106 to 921 lines.
2026-10-23 04:04:44 -04:00
Acelogic f47befb905 probes: split xnuboot.c into ordered parts
Phase 1 of decomposing the 15,770-line monitor unit: move contiguous
top-level ranges verbatim into probes/xnuboot/*.c, and have
probes/xnuboot.c #include them in their original order. The compiler
still sees one translation unit. Every #include of a header stays in
probes/xnuboot.c, because quoted includes resolve beside the including
file and the monitor build has no -Icompat.

Cuts fall only between top-level declarations; no function, struct,
initializer or conditional is split, and every part has balanced
#if/#endif. Two exceptions are recorded for phase 2:
- monitor_call_impl is 1,318 lines on its own, so
  probes/xnuboot/sptm_dispatch.c is 1,370 lines.
- The 1,894-line #if SNAP_FINE_LOCKS region is split into three
  consecutive identical #if SNAP_FINE_LOCKS blocks (fine_locks_*.c).
  SNAP_FINE_LOCKS is not defined or undefined inside the region, and
  nothing inside it includes a header.
The parts that carry the m1n1-derived SPTM endpoint numbers and return
codes (report_layout.c, sptm_dispatch.c) keep the file's notice.

Tools that read xnuboot.c as text now read the whole unit through
tools/source_text.py read_source(); tools that hash or pin monitor
sources add every part through source_files() (generic over each .c
in their lists, so later splits are covered the same way).

Verification (base 84dd208 vs this commit, clang 23.1.3):
- clang -c, qualification flags (b12v20 qualification.json, no -flto)
  plus -I shadow -I q1n1/platform/uefi: probes/xnuboot.c objects
  byte-identical (cmp). PASS
- clang -c, probes/run.py FLAGS plus the same -I: byte-identical. PASS
- Qualification flags with -flto: llvm-dis output equal; the full IR
  differs only in 468 inline-asm !srcloc source-location cookies. PASS
- probes/run.py build('xnuboot'), every unit linked: xnuboot.bin and
  xnuboot.elf byte-identical with the qualification flags (LTO,
  bin sha256 0d8b9ec3...) and with run.py FLAGS (2b5d5f6b...). PASS
- Reconstruction: expanding the includes and dropping the part headers
  and the duplicated #if/#endif lines reproduces xnuboot.c exactly.
- Host battery (63 commands: the two gcc SPTM suites, test-idregs,
  test-audit-sptm-refs and every tools/test-*.py that reads these
  sources, plus the edited tools), 300 s limit, base vs split:
  no new failure. 76 of 78 outcomes equal; test-audit-sparse and
  test-monitor-perf timed out (NOT RUN) on split under host load and
  on rerun match base (PASS; FAIL with the same record). Per-class
  reruns of the long suites (21 commands) equal on both trees.
  Pre-existing failures (missing private inputs or stale checks) are
  unchanged.
- wc -l: xnuboot.c 918, every part under 1,000 except sptm_dispatch.c
  (1,370).
2026-10-23 04:04:44 -04:00
Acelogic 84dd2080e8 tools: add a reader for source files split into ordered parts
Large translation units will be split into ordered part files that the main
file #includes, so the compiler still sees one unit. Tools that inspect
source text read the whole unit through read_source().
2026-10-23 01:44:33 -04:00
Acelogic bc7c3a8d83 repo: update SnapI2CHID to keep its original ignore rules 2026-10-23 01:38:51 -04:00
Acelogic 031f072c43 docs: point links at the Snapintosh organization 2026-10-23 01:38:07 -04:00
Acelogic 3720495a69 repo: move drivers and GPU components into submodules
The Adreno kext, the Metal plug-in, air2ir3, SnapI2CHID and SnapQCC2072 now
live in their own repositories in the Snapintosh organization, split with
their history (git filter-repo --subdirectory-filter). They are mounted
back at their old paths, so relative build paths in build.sh, the tools
and the includes are unchanged. The EL2 monitor, tools and docs stay in
this repository.

Validation: see the follow-up verification on a fresh recursive clone.
2026-10-23 01:38:07 -04:00
Acelogic 28663c30f0 display: keep live scanout copies naturally aligned
The live scanout is mapped as Device memory, where an unaligned access
is an alignment fault and therefore a kernel panic. Cursor spans start
at an arbitrary x, so they are only 4-byte aligned. For long spans
(the enlarged shake-to-locate cursor, about 1.4 KiB per row) the kernel
memcpy issues 16-byte stores that end up unaligned, and the guest
panicked with "Unaligned kernel data abort" in
AdrenoDisplay::presentGated.

ADRENO_PRESENT_LIVE_ALIGNED routes every copy that reads or writes the
scanout through adreno_display_live_copy. It keeps memcpy when both
ends and the length are 16-byte aligned (whole rows) and otherwise uses
naturally aligned 8- and 4-byte accesses. The gate defaults to 0;
build.sh enables it because the faulting copy is also in the baseline
cursor path.

Validation:
PASS  tools/test-adreno-live-copy.c: 7616 offset/length cases match
      memcpy
PASS  gpu/adreno-kext/kext/build.sh, with locally generated 26A428
      headers
PASS  with the gate off, the deployed kext configuration links
      section-identical to the previous kext (12/12 sections)
OBSERVED  A16, macOS 26A428: with the gate on, the shake-to-locate
      cursor no longer panics. The same gesture panicked without it.
NOT RUN  full host suite; frame-time measurement
2026-10-22 02:36:49 -04:00
Acelogic bc34e8f130 Add AGENTS.md: project rules and how to rebuild the inputs that are not distributed 2026-10-21 21:45:13 -04:00
Acelogic 1510d8c6ce Snapintosh public release
An EL2 monitor/hypervisor and toolchain that boots macOS 27 on the ASUS A16
(Snapdragon X2 Elite), with an Adreno Metal plug-in and IOGPU kext, and
air2ir3, an AIR to Mesa ir3 shader compiler.

MIT, with GPL-2.0 components listed in LICENSE and THIRD_PARTY_NOTICES.md.
No Apple, Qualcomm, ASUS or Microsoft binaries are included.
2026-10-21 21:26:36 -04:00