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.
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.
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.
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.
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.
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".
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).
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.
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.
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).
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.
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.
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).
- 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.
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.
--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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
--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.
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.
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.
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.
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.
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.
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).
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.
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.
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.
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.
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.
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.
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.
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).
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().
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.
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
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.