aboutsummaryrefslogtreecommitdiffstats
path: root/fw
diff options
context:
space:
mode:
authoruser <user@clank>2026-10-09 16:11:31 +0200
committeruser <user@clank>2026-10-09 16:11:31 +0200
commitbc43149d914325e15dc0490dee9d982e21287623 (patch)
treea632cf70de742d5a60d01c9c0d806bf5b9257538 /fw
parentGCP->ASD 0x403: ASD-internal chain PROVEN end-to-end in emulator (real handlers) (diff)
downloadamd-psp-re-main.tar.gz
amd-psp-re-main.tar.xz
amd-psp-re-main.zip
Record PSP security investigation artifacts and probesHEADmain
Diffstat (limited to 'fw')
-rw-r--r--fw/ATTEMPT-SYSDRV-53-LIVE-LOG-GATES-READONLY-FAULT.md21
-rw-r--r--fw/AUDIT-ASD-163-100-10B-FIRSTLEVEL.md21
-rw-r--r--fw/AUDIT-ASD-163-160-161-800-802-FIRSTLEVEL.md15
-rw-r--r--fw/AUDIT-ASD-163-161-LINK-STATUS-CALLBACKS.md33
-rw-r--r--fw/AUDIT-ASD-163-182-185-ASIC20-CALLBACK-OUTPUTS.md39
-rw-r--r--fw/AUDIT-ASD-163-18C-LINK-CALLBACK.md11
-rw-r--r--fw/AUDIT-ASD-163-1A2-1C0-JUMPTABLE.md32
-rw-r--r--fw/AUDIT-ASD-163-1A3-1A4-HDCP2-STATE-SETTERS.md52
-rw-r--r--fw/AUDIT-ASD-163-1A6-PEER-INDEX.md82
-rw-r--r--fw/AUDIT-ASD-163-1C0-CONNECTOR-CALLBACK-BOUND.md35
-rw-r--r--fw/AUDIT-ASD-163-200-20B-NESTED-POINTERS.md32
-rw-r--r--fw/AUDIT-ASD-163-200-ASIC20-OUTPUT.md36
-rw-r--r--fw/AUDIT-ASD-163-204-ASIC20-CALLBACK-OUTPUT.md34
-rw-r--r--fw/AUDIT-ASD-163-207-ASIC20-CALLBACK-OUTPUT.md54
-rw-r--r--fw/AUDIT-ASD-163-208-SYSDRV-1079-FORWARD.md41
-rw-r--r--fw/AUDIT-ASD-163-300-308-FIRSTLEVEL.md38
-rw-r--r--fw/AUDIT-ASD-402-FIXED-FABRIC-TOGGLE.md27
-rw-r--r--fw/AUDIT-ASD-405-CALLBACK-PROVENANCE.md54
-rw-r--r--fw/AUDIT-CROSS-CLIENT-CRYPTO-OBJECT-LIFETIME.md61
-rw-r--r--fw/AUDIT-DTM19-ASD100-TYPE1-PRODUCER.md33
-rw-r--r--fw/AUDIT-GCP-ASD-20B-PRIVATE-TARGET-PROVENANCE.md59
-rw-r--r--fw/AUDIT-GCP-ASD403-49007A00-TRANSFER-SLOTS.md35
-rw-r--r--fw/AUDIT-GCP-ASD403-FABRIC-DMA-PIVOT.md35
-rw-r--r--fw/AUDIT-GCP-ASD403-SCRATCH-CONSUMERS.md9
-rw-r--r--fw/AUDIT-GCP-FREE-SYSDRV-100A-OUTPUT-SPAN.md29
-rw-r--r--fw/AUDIT-GCP-FREE-SYSDRV-100D-KDF-OUTPUT.md26
-rw-r--r--fw/AUDIT-GCP-FREE-SYSDRV-1024.md65
-rw-r--r--fw/AUDIT-GCP-FREE-SYSDRV-1039-SOS6B-BLOCK.md30
-rw-r--r--fw/AUDIT-GCP-FREE-SYSDRV-1049-FIXED-REG-READ.md18
-rw-r--r--fw/AUDIT-GCP-FREE-SYSDRV-1054-PER-CALLER-CRYPTO-SPANS.md27
-rw-r--r--fw/AUDIT-GCP-FREE-SYSDRV-1056.md9
-rw-r--r--fw/AUDIT-GCP-FREE-SYSDRV-1071-1074-IDENTITY.md18
-rw-r--r--fw/AUDIT-GCP-FREE-SYSDRV-1081-ZLIB-OUTPUT-BOUND.md32
-rw-r--r--fw/AUDIT-GCP-FREE-SYSDRV-1085.md30
-rw-r--r--fw/AUDIT-GCP-FREE-SYSDRV-10A3-10A4-MAILBOX-STATUS.md33
-rw-r--r--fw/AUDIT-GCP-FREE-SYSDRV-4013-4015.md23
-rw-r--r--fw/AUDIT-GCP-HDCP-STACK-GUARD-VIA-EXISTING-LEAKS.md10
-rw-r--r--fw/AUDIT-GCP-ROP-ASD-SYSDRV-HISTORICAL-BUILDS.md43
-rw-r--r--fw/AUDIT-GCP-SYSDRV-1010-1015-DISPATCH-IS-NOT-STUB.md29
-rw-r--r--fw/AUDIT-GCP-SYSDRV-101F-SOS6B-6D-CLEANUP.md30
-rw-r--r--fw/AUDIT-GCP-SYSDRV-1027-SOS94-BLOCK.md28
-rw-r--r--fw/AUDIT-GCP-SYSDRV-102A-SOS59-RESOURCE.md25
-rw-r--r--fw/AUDIT-GCP-SYSDRV-102D-CRYPTO-MODE2.md36
-rw-r--r--fw/AUDIT-GCP-SYSDRV-1031-PRIVATE-MODE-QUERY.md29
-rw-r--r--fw/AUDIT-GCP-SYSDRV-1036-1040-1055-NONSTUB.md28
-rw-r--r--fw/AUDIT-GCP-SYSDRV-103B-103C-1082-NONSTUB.md36
-rw-r--r--fw/AUDIT-GCP-SYSDRV-1044-FIXED-RESOURCE-GATE.md32
-rw-r--r--fw/AUDIT-GCP-SYSDRV-107C-FIXED-DIAGNOSTIC-GATE.md28
-rw-r--r--fw/AUDIT-GCP-SYSDRV-1084-OUTPUT-SPAN-INLINE-METADATA.md33
-rw-r--r--fw/AUDIT-GCP-SYSDRV-5B-5E-STREAM-BOUNDS.md40
-rw-r--r--fw/AUDIT-GCP-SYSDRV-LOW-40-48-50-5E-FIRSTLEVEL.md14
-rw-r--r--fw/AUDIT-HDCP57-SYSDRV1087-MODE-GATE.md27
-rw-r--r--fw/AUDIT-OPM51-ASD301-AUTH-BOUNDARY.md60
-rw-r--r--fw/AUDIT-SOS54-B5-DECLARED-SPAN-WINDOWS.md31
-rw-r--r--fw/AUDIT-SOS54-RESOURCE0-SIGNED-BOOT-MODEL.md59
-rw-r--r--fw/AUDIT-SOS54-SERVICE-REGISTRY-4-15.md23
-rw-r--r--fw/AUDIT-SOS54-SVC76-8E-CAPABILITY-FLOW.md44
-rw-r--r--fw/AUDIT-SOS54-SYSDRV-3105-TA-LOAD.md58
-rw-r--r--fw/CANDIDATE-ASD-163-1A2-LAST-CHANNEL-SWEEP.md61
-rw-r--r--fw/CANDIDATE-ASD-163-1A9-SPARSE-ENUMERATION.md18
-rw-r--r--fw/CANDIDATE-ASD-163-1AA-DUPLICATE-DROPS-TAIL.md82
-rw-r--r--fw/CANDIDATE-ASD-163-SRM-MULTI-REVOCATION-BITMAP.md28
-rw-r--r--fw/CANDIDATE-GCP-ASD-100-ERROR-RETURN-ACTIVE-RECORD.md41
-rw-r--r--fw/CANDIDATE-GCP-ASD-101-OWNERLESS-RECORD-ERASE.md54
-rw-r--r--fw/CANDIDATE-GCP-ASD-160-SRM-REVOCATION-STATUS-BYPASS.md62
-rw-r--r--fw/CANDIDATE-GCP-ASD-18F-BITMAP-RELEASE-AUTHORITY.md17
-rw-r--r--fw/CANDIDATE-GCP-ASD-1A8-BITMAP-RELEASE-AUTHORITY.md21
-rw-r--r--fw/CANDIDATE-GCP-ASD-1AA-UNOWNED-REVOCATION-AND-FAILED-TEARDOWN.md45
-rw-r--r--fw/CANDIDATE-GCP-ASD-203-DIO-UNBOUND-RECORD-ACCESS.md60
-rw-r--r--fw/CANDIDATE-GCP-ASD-205-206-INVALID-MASK-SESSION-SIDE-EFFECT.md55
-rw-r--r--fw/CANDIDATE-GCP-ASD-20B-UNCHECKED-OUTPUT-STORE.md132
-rw-r--r--fw/CANDIDATE-GCP-SYSDRV-1001-SELECTED-IDENTITY-BULK-CLEANUP.md84
-rw-r--r--fw/CANDIDATE-GCP-SYSDRV-100B-NESTED-STRUCT-SPAN.md44
-rw-r--r--fw/CANDIDATE-GCP-SYSDRV-100C-OWNERLESS-SLOT-RELEASE.md44
-rw-r--r--fw/CANDIDATE-GCP-SYSDRV-100E-100F-SECOND-INPUT-SPAN.md88
-rw-r--r--fw/CANDIDATE-GCP-SYSDRV-1016-SHORT-INPUT.md24
-rw-r--r--fw/CANDIDATE-GCP-SYSDRV-1017-TWO-SHORT-OUTPUTS.md55
-rw-r--r--fw/CANDIDATE-GCP-SYSDRV-101C-WRAPPED-OUTPUT-NULL-SOURCE.md20
-rw-r--r--fw/CANDIDATE-GCP-SYSDRV-1023-SHORT-OUTPUT.md21
-rw-r--r--fw/CANDIDATE-GCP-SYSDRV-1030-FLASH-CLASS-GATE.md50
-rw-r--r--fw/CANDIDATE-GCP-SYSDRV-1032-ERROR-STATUS-FLAG.md31
-rw-r--r--fw/CANDIDATE-GCP-SYSDRV-1033-SHORT-INPUT.md21
-rw-r--r--fw/CANDIDATE-GCP-SYSDRV-1059-ERROR-RETURN-DESCRIPTOR-POISON.md71
-rw-r--r--fw/CANDIDATE-GCP-SYSDRV-105D-ZERO-LENGTH-TMR-RANGE.md59
-rw-r--r--fw/CANDIDATE-GCP-SYSDRV-105F-SHORT-INPUT-REG-PROGRAM.md49
-rw-r--r--fw/CANDIDATE-GCP-SYSDRV-1063-SHORT-OUTPUT.md43
-rw-r--r--fw/CANDIDATE-GCP-SYSDRV-1067-FAILED-LOCK-COUNT.md44
-rw-r--r--fw/CANDIDATE-GCP-SYSDRV-106A-SELECTOR2-SHORT-SPANS.md40
-rw-r--r--fw/CANDIDATE-GCP-SYSDRV-107B-SHORT-OUTPUT.md113
-rw-r--r--fw/CANDIDATE-GCP-SYSDRV-1094-CROSS-PARTITION-SPI-WRITE.md85
-rw-r--r--fw/CANDIDATE-GCP-SYSDRV-1098-SHORT-INPUT.md20
-rw-r--r--fw/CANDIDATE-GCP-SYSDRV-109D-LABEL-STRING-OVERREAD.md43
-rw-r--r--fw/CANDIDATE-GCP-SYSDRV-35-IGNORED-RNG-FAILURE.md43
-rw-r--r--fw/CANDIDATE-GCP-SYSDRV-53-LOG-STRING-PREVALIDATION.md21
-rw-r--r--fw/CANDIDATE-HDCP52-ALLOC-FAIL-SYSDRV-FATAL.md171
-rw-r--r--fw/CANDIDATE-HDCP57-ASD1A1-IGNORED-ENTROPY-FAILURE.md69
-rw-r--r--fw/CANDIDATE-SOS54-6C-ABSENT-RESOURCE-DEREF.md47
-rw-r--r--fw/CANDIDATE-SYSDRV-1002-CRYPTO-WORKSPACE-LENGTH.md71
-rw-r--r--fw/CANDIDATE-SYSDRV-1041-104F-CAPACITY-STATUS-POSITION.md44
-rw-r--r--fw/CANDIDATE-SYSDRV-104D-PROPERTY-KEY-PREFIX.md37
-rw-r--r--fw/EVAL-GCP-ASD403-MP1-PMI3-EVENT-QUEUE.md86
-rw-r--r--fw/FINDING-GCP-ASD-404-STACK-GUARD-DISCLOSURE.md80
-rw-r--r--fw/FINDING-GCP-SYSDRV-109A-STACK-GUARD-DISCLOSURE.md74
-rw-r--r--fw/LEAD-ASD-D397B0-DERIVED-KEY-LIFECYCLE.md119
-rw-r--r--fw/LEAD-GCP-ASD403-LSDMA6-PIO-COPY.md55
-rw-r--r--fw/LEAD-GCP-ASD403-MP1-UNSECURE-BAR.md7
-rw-r--r--fw/LEAD-GCP-PARAMS-VA-NONROP-DISCRIMINATOR.md24
-rw-r--r--fw/LEAD-GCP-SYSDRV-1010-1015-NESTED-SPANS.md37
-rw-r--r--fw/LEAD-GCP-SYSDRV-1018-MODE-GATED-STORAGE-READ.md65
-rw-r--r--fw/LEAD-GCP-SYSDRV-101A-BLOCK-COUNT-TRUNCATION.md42
-rw-r--r--fw/LEAD-GCP-SYSDRV-101D-NESTED-INPUT-GATE.md26
-rw-r--r--fw/LEAD-GCP-SYSDRV-101E-OWNER-BYPASS-TEARDOWN.md102
-rw-r--r--fw/LEAD-GCP-SYSDRV-1021-GLOBAL-BRINGUP-FLAGS.md48
-rw-r--r--fw/LEAD-GCP-SYSDRV-1026-REINIT-WITHOUT-STARTUP-GATE.md34
-rw-r--r--fw/LEAD-GCP-SYSDRV-1028-FIXED-CPU-WINDOW-WORD.md40
-rw-r--r--fw/LEAD-GCP-SYSDRV-1029-FIXED-MMIO-WORD.md28
-rw-r--r--fw/LEAD-GCP-SYSDRV-102C-LABEL-SPAN.md33
-rw-r--r--fw/LEAD-GCP-SYSDRV-102E-FIXED-CPU-WINDOW-WORD.md28
-rw-r--r--fw/LEAD-GCP-SYSDRV-102F-FIXED-SOURCE-128K-READ.md35
-rw-r--r--fw/LEAD-GCP-SYSDRV-1030-SELECTOR19-FABRIC-MODE.md34
-rw-r--r--fw/LEAD-GCP-SYSDRV-1034-ERROR-RETURN-CPU-WINDOW-STATUS.md40
-rw-r--r--fw/LEAD-GCP-SYSDRV-1037-UNBOUNDED-MAILBOX-WAIT.md39
-rw-r--r--fw/LEAD-GCP-SYSDRV-1038-LENGTH-DRIVEN-CRYPTO-LOOP.md31
-rw-r--r--fw/LEAD-GCP-SYSDRV-103E-1047-SHARED-KEY-STORE.md86
-rw-r--r--fw/LEAD-GCP-SYSDRV-1058-WRAPPED-FIRMWARE-LENGTH.md56
-rw-r--r--fw/LEAD-GCP-SYSDRV-105A-ERROR-RETURN-MODE-FLAG.md38
-rw-r--r--fw/LEAD-GCP-SYSDRV-106C-ZERO-ROUNDING-STATUS.md33
-rw-r--r--fw/LEAD-GCP-SYSDRV-1076-RAP-GLOBAL-STATE-RESET.md60
-rw-r--r--fw/LEAD-GCP-SYSDRV-1079-CHOSEN-FIXED-FABRIC-WORD.md104
-rw-r--r--fw/LEAD-GCP-SYSDRV-1097-GLOBAL-WAIT-MODE.md31
-rw-r--r--fw/LEAD-GCP-SYSDRV-10A2-LABEL-PREVALIDATION-READ.md38
-rw-r--r--fw/LEAD-OPM51-CMD11-GLOBAL-MODE-FLAG.md36
-rw-r--r--fw/LEAD-SYSDRV-107B-MULTI-RECORD-SNAPSHOT-LOSS.md34
-rw-r--r--fw/scan_rpc_opcode_immediates.py76
-rw-r--r--fw/scan_service_registrations.py60
-rw-r--r--fw/verify_gcp_loggates_fault.py43
-rw-r--r--fw/verify_gcp_loggates_memcpy_path.py118
-rw-r--r--fw/verify_gcp_params_nonrop_discriminator.py109
138 files changed, 6229 insertions, 0 deletions
diff --git a/fw/ATTEMPT-SYSDRV-53-LIVE-LOG-GATES-READONLY-FAULT.md b/fw/ATTEMPT-SYSDRV-53-LIVE-LOG-GATES-READONLY-FAULT.md
new file mode 100644
index 0000000..20a6f9b
--- /dev/null
+++ b/fw/ATTEMPT-SYSDRV-53-LIVE-LOG-GATES-READONLY-FAULT.md
@@ -0,0 +1,21 @@
+# Failed live read-only discriminator for SYS_DRV `.54` log gates
+
+**2026-10-09 UTC, dedicated RX 7900 XTX. No log gate value was obtained. Card recovered. Do not retry this chain without diagnosing the GCP-side fault.** This attempt was to improve the **conditional** `0x53` finding, not to invoke `0x53` on the card.
+
+Prepared a derivative of the previously used GCP→SYS_DRV `0x109A` read-only ROP at `/root/psp/hw/gcp_rop_sysdrv_loggates_readonly.py` (local `/tmp/gcp_rop_sysdrv_loggates_readonly.py`). It selected three `0x109A` requests: index 0 control, `0x3FFFB2D2` for SYS_DRV VA `0xE264E0` frontend byte, and `0x3FFFB33B` for SYS_DRV VA `0xE269CC` backend byte; `0xE60308 + 12*index` was checked modulo 2³² for both. It used service **1**, not ASD `0x403`; nevertheless the existing ROP setup contains a broad **GCP FE0A** bound, so it is not a purely bounded-host operation. GCP-owned payload assembly and signed client dispatch are distinct from the intended read-only SYS_DRV leaf.
+
+Before the attempt, no matching probe process was observed and host C2PMSG fault words 82–88 were all zero. `LOAD_ASD=0`, `LOAD GCP=0`, SID 2. The FE0A submission **timed out**; its output was untouched fill (`0xBBBBBBBB`), grace byte `0xBB`, and no valid `0x109A` return. The fault frame was
+
+```
+004055d8 25031016 004011d8 00000867 0042cfa0 00000000 8da7463d
+```
+
+A later FE07 timed out (`0xA5A5A5A5` untouched status); GCP unload timed out. These are **failure signals, not log-gate values**.
+
+**Later fault-frame correction (static, no repeat card request):** The earlier interpretation of `word0=0x4055D8` as the **faulting PC** was wrong. The independent GCP FE09/FE0A fault-frame calibration in `fw/FINDING-GCP-FE09-CONFIGINIT-HOST-OFFSET-WRITE.md` establishes that word0 is a **build-specific constant**; **word2 is the faulting PC**, word3 is DFSR/IFSR, and word4 is FAR. Signed GCP `.77` at **`0x4011D8`** is `STMMI R0!,{R3,R4}` inside the GCP memcpy implementation `sub_4011A4`. DFSR `0x867` indicates a **write translation fault** (`FS=7`, WnR set) at **`0x0042CFA0`**, outside the known mapped GCP stack/heap ranges in that calibration. The seventh frame word `0x8DA7463D` is seen in other unrelated faults; it is **not** evidence that GCP's guard pointer `R7` held this address. `0x4055D8` is the instruction following the ordinary GCP `.77` wrapper's `SVC 0xF2` for opcode `0x53`, but it is **not** the faulting instruction in this frame. That wrapper zeroes a local 256-byte string, formats with maximum 255 and declares 256 input bytes; this is **not** evidence of a naturally short-declared string. The store fault localizes to GCP's memcpy path, not to a SYS_DRV store or the `0x53` string logger. `python3 fw/verify_gcp_loggates_fault.py` independently decoded signed `.77` ELF bytes and the preserved frame, passing its instruction/FSR/FAR assertions. The identity of the memcpy caller, its corrupted destination/length, and whether any of the three intended `0x109A` requests ran remain **unresolved**.
+
+A diff against the earlier successful GCP→SYS_DRV guard-reader script `/tmp/gcp_rop_sysdrv_guard_read.py` shows the ROP layout and two planned memcpy destinations were unchanged; aside from cleanup code, the request difference was the two `0x109A` indices. The planned destinations (`0x00410000` for migration and `0x04027010` for dump) are neither `0x0042CFA0`, so this was not a planned landing address. This diff is **not** a proof that the indices caused the fault or that the chain reached its dump. A subsequent **offline** signed-instruction/ROP-literal check (`python3 fw/verify_gcp_loggates_memcpy_path.py`) further narrowed the failure: the two planned GCP memcpy calls have aligned `(dst,src,len)` of `(0x410000,0x4026200,0x900)` and `(0x4027010,0x410400,0x280)`. Both lengths are multiples of 16. The signed ARM memcpy route `0x40111C → 0x401154 → 0x4011A4` executes the conditional `STMMI` at fault PC `0x4011D8` only for a nonzero eight-byte tail after its `LSLS` at `0x4011C8`; an intact one of these two copies cannot reach that store. FAR `0x42CFA0` is outside either planned destination span as well. A stronger **fault-compatible caller** is now identifiable from the signed FE0A selector-4 code: at `0x404D44..0x404D4E`, its **first 8-byte chosen-write memcpy** targets `actual_params + 0x418 + *(params+0x840)` before the ROP pivot. The script computes this displacement using a hardcoded `PARAMS=0x04024000` and intended saved-slot destination `SLOT-0x1C=0x0041BFA0`. FAR `0x0042CFA0` is **exactly `0x11000` above** that nominal destination. A page-aligned command-buffer remap to `0x04035000` would therefore place the first chosen-write store at the recorded FAR, and an eight-byte copy can indeed execute `STMMI` at `0x4011D8`. The second chosen-write target `0x0041BFB8` would require a **non-page-aligned** `0x10FE8` shift to land at the same FAR. This is strong signed-code/arithmetic support for an out-of-date hardcoded command-buffer VA, **not** a measured value of live `R6`, `R0`, or the actual PSP mapping. Earlier GCP work measured `0x04024000` on two configurations and called that mapping fixed (`fw/FINDING-GCP-FE09-CONFIGINIT-HOST-OFFSET-WRITE.md`, Addendum 54); that evidence does **not** measure this later run after a different sequence of card loads/cycles. The archived `/root/psp/hw/sysdrv53_loggates_readonly.log` was read without issuing a command to the card: it contains the fault and untouched output but **no params-VA readback**. The remote executed script's SHA-256 matches `/tmp/gcp_rop_sysdrv_loggates_readonly.py` (`1bc36cd2c6c33a0d870bbb833540b40e2f6311edd332c48fd270929bbe3e31f5`). If that hypothesis is correct, the fault preceded the ROP pivot and **none of the intended `0x109A` requests ran**; the frame alone cannot prove that ordering. The exact caller/arguments and actual params VA still need independent verification, so **do not retry the card chain**. `fw/verify_gcp_loggates_memcpy_path.py` checks the signed instructions, planned-copy exclusion and displacement arithmetic offline.
+
+The remote original output is `/root/psp/hw/sysdrv53_loggates_readonly.log`. Ran only `/root/psp/hw/psp_atx_only_cycle.py` for recovery: ATX off → LTSSM `0x58`, 18-second drain → `0x00`, ATX on → link `0x78`. After power-up fault words 82–88 were all zero. Independently loaded ASD (ring 0), loaded GCP (ring 0, SID 1), invoked FE07 (ring 0, TA 0, nonzero handle), and unloaded GCP (ring 0): `/root/psp/hw/sysdrv53_loggates_recovery.log` and `/root/psp/hw/sysdrv53_post_recovery_sanity.log`. **No subsequent hardware probe was attempted.**
+
+The candidate remains signed-static plus synthetic-emulator evidence only. Read-only live gate measurement is unresolved; fault diagnosis must precede any further hardware ROP run. No ASD-private target or logging state was intentionally changed.
diff --git a/fw/AUDIT-ASD-163-100-10B-FIRSTLEVEL.md b/fw/AUDIT-ASD-163-100-10B-FIRSTLEVEL.md
new file mode 100644
index 0000000..2b726fd
--- /dev/null
+++ b/fw/AUDIT-ASD-163-100-10B-FIRSTLEVEL.md
@@ -0,0 +1,21 @@
+# ASD .163 service-2 `0x100..0x10B`: first-level routing and hidden labels
+
+Card-loaded signed image: `psp_out/versions_win/elf_all/asd_33.0.0.163_18debcc4.elf`. **Static first-level only.** No state-changing command was invoked on hardware in this pass.
+
+`asd_dispatch` (`0xD013B8`) uses `TBB [PC,R2]` at `0xD014F0`; the **byte** table at `0xD014F4` indexes opcodes `0x100..0x10B`. Hex-Rays incorrectly prints `abort()` for `0x10A` and `0x10B` even though the signed byte entries target `0xD015AE` and `0xD015B8`. They route to real leaves; a decompiler `abort()` here is **not** a demonstrated DoS. `0x106` is the actual shared invalid-status-4 case.
+
+| opcode | signed leaf | immediate validation and scope |
+|---|---|---|
+| `0x100` | `sub_D0B66C` | validates 64-byte caller descriptor and channel `<=31`, marks/updates an ASD channel and invokes ASIC callbacks; can change shared topology. Previously used in bounded GCP ROP staging; no clean bill for callbacks. |
+| `0x101` | `sub_D08C08` | bounds channel `<=31`, invokes two teardown helpers **without checking their returns**, then unconditionally zeroes its 92-byte record without owner/state check. Synthetic signed-dispatch controls confirm the erase despite failed helpers; no hardware victim was touched (`fw/CANDIDATE-GCP-ASD-101-OWNERLESS-RECORD-ERASE.md`). |
+| `0x102..0x105` | `sub_D08C70/D08D6C/D08D8C/D08C50` | each validates a four-byte caller output before a bounded **incoming-channel** query (`sub_D0BD50/BDC0/BE00/BD08`). `0x105` conditionally dereferences a **stored** peer index without rechecking it; identified setters remain bounded (`fw/AUDIT-ASD-163-1A6-PEER-INDEX.md`). |
+| `0x106` | shared invalid path | status 4. |
+| `0x107` | `sub_D08CAC` | channel `<=31`; validates eight-byte caller output, then writes exactly two dwords (including invalid-state result). |
+| `0x108` | `sub_D08C30` | validates four-byte output; enumerates up to 32 active channels in `sub_D0BCD4`. |
+| `0x109` | `sub_D08C90` | validates four-byte output; counts up to 32 active channels in `sub_D0BD90`. |
+| `0x10A` | `0xD015AE -> sub_D0B494` | requires nonnull/validated four-byte caller pointer, then indirect table slot 777 or status 7 if null. |
+| `0x10B` | `0xD015B8 -> sub_D0B4C4` | takes a **byte** scalar and three nonnull/validated two-byte caller pointers; then table slot 778 or status 7 if null. |
+
+For the signed ASIC-20/25 branch of `sub_D08DAC`, table slots 777/778 (builder offsets `fieldA0/fieldA4`) are initialized **zero**; the card's fresh-boot ASIC variant was measured as 20 in earlier read-only checks. A connected signed-dispatch *synthetic* trace, `python3 psp_emu/harness/probe_asd163_10a_10b_dispatch.py`, returned 7 for valid caller pointers at both `0x10A/B` with zero-initialized callback slots; private-pointer negatives returned 2 and actual invalid opcode `0x106` returned 4. This disproves `abort()` in the signed handler but does **not** measure live callback state. Do not invoke `0x10A`/`0x10B` on hardware on that prediction alone. GCP can access service 2, but there is no live `0x10A/B` effect measurement.
+
+The broader first-level mapping does not close downstream ASIC callbacks, peer-index corruption, or the cross-channel state consequences of `0x101`. See the independently verified pointer defect in `fw/CANDIDATE-GCP-ASD-20B-UNCHECKED-OUTPUT-STORE.md` and the separate hidden `0x1A2..0x1C0` table in `fw/AUDIT-ASD-163-1A2-1C0-JUMPTABLE.md`.
diff --git a/fw/AUDIT-ASD-163-160-161-800-802-FIRSTLEVEL.md b/fw/AUDIT-ASD-163-160-161-800-802-FIRSTLEVEL.md
new file mode 100644
index 0000000..43e8da8
--- /dev/null
+++ b/fw/AUDIT-ASD-163-160-161-800-802-FIRSTLEVEL.md
@@ -0,0 +1,15 @@
+# ASD .163 service-2 `0x160`/`0x161` and `0x800..0x802`: first level only
+
+Signed image: `psp_out/versions_win/elf_all/asd_33.0.0.163_18debcc4.elf`. This corrects older `asd2.elf`-based descriptions of the `0x800` group; it is **not** a full callback or hardware audit.
+
+| opcode | signed dispatcher (`asd_dispatch` `0xD013B8`) | relevant bound/effect |
+|---|---|---|
+| `0x160` | `0xD017D2 -> sub_D0B438` | caller channel `<=31`, active channel state; stores an unrestricted caller scalar to `+88` without owner binding. Both signed SRM revocation loops use that word as a cleanup predicate; a synthetic single-match bypass is in `fw/CANDIDATE-GCP-ASD-160-SRM-REVOCATION-STATUS-BYPASS.md`. No hardware invocation. |
+| `0x161` | `0xD017DC -> asd_get_link_status` (`0xD0B3E8`) | four output pointers each pass `asd_validate_ptr(ptr,4)`; nested routine bounds channel `<=31` and writes dwords only to those caller outputs. Scoped ASIC-20 callback provenance and another unchecked **stored** peer-index consumer are in `fw/AUDIT-ASD-163-161-LINK-STATUS-CALLBACKS.md`; complete peer writers, callback side effects, and other variants remain open. |
+| `0x800` | `0xD0141A -> 0xD0155E` | sets return register to zero; no callback executed on this exact path |
+| `0x801` | `0xD01422..0xD01434 -> sub_D0E7C8` **only when incoming dispatcher `R1 == 0`**; otherwise shared invalid status 4 | variant-gated, `arg1 <=1`, requires `arg2==0`; then traverses DIO entries and changes internal state/ASIC-global resources; no card invocation or restoration oracle |
+| `0x802` | no explicit match; shared `0xD015FC` | invalid status 4, not the old asd2 leaf |
+
+The `R1==0` comparison for `0x801` is the **incoming second dispatcher argument** at `0xD0142A`, not the message's `arg2`; `sub_D0E7C8` later separately checks the message's second word. Do not assume a GCP→sOS→ASD service call satisfies the `R1` gate without an intact connected trace. The older `fw/LEAD-ASD-SERVICE2-ATTACK-SURFACE.md` describes different addresses and a broader `0x800` dispatch from an earlier image; neither proves these `.163` paths.
+
+No `0x160`/`0x161`/`0x800..0x802` request was issued to hardware in this pass. In particular, `0x801` may change device/link state and has no independent restoration plan; a synthetic return or first-level check would not prove a safe live effect.
diff --git a/fw/AUDIT-ASD-163-161-LINK-STATUS-CALLBACKS.md b/fw/AUDIT-ASD-163-161-LINK-STATUS-CALLBACKS.md
new file mode 100644
index 0000000..8d09f5f
--- /dev/null
+++ b/fw/AUDIT-ASD-163-161-LINK-STATUS-CALLBACKS.md
@@ -0,0 +1,33 @@
+# ASD `.163` `0x161`: nested output widths and ASIC-20 callback provenance
+
+**Signed-static only.** No card request or callback execution. Extends the
+first-level `fw/AUDIT-ASD-163-160-161-800-802-FIRSTLEVEL.md` review; not a
+complete link-state/peer writer or ASIC-variant audit.
+
+`asd_get_link_status` (`0xD0B3E8`) independently checks each of four
+caller output pointers for **four bytes** with `asd_validate_ptr` before
+calling `asd_link_sub_113A0` (`0xD0BE28`). The nested routine initializes
+all four via four-byte stores, bounds the incoming channel to `<=31`, and
+thereafter writes these caller outputs only as whole dwords (`*a2`,
+`*a3`, `*a4`, `*a5`). ASIC callbacks receive a **channel-record pointer**
+or the address of a local four-byte temporary `v33`, not any caller output
+pointer. The ASIC-20 slot 766 callback `asd_query_link_config` writes only
+`*a2` to that local temporary. No direct caller-output size mismatch or
+unchecked nested caller-output pointer was identified on this path.
+
+For active type-5 channels the routine reads stored peer index from
+`base+92*channel+0x3C`, forms `base+92*peer` and checks its state **without
+rechecking peer `<32`**. This is another consumer of the field discussed
+in `fw/AUDIT-ASD-163-1A6-PEER-INDEX.md` (`0x188` and `0x1A6` were the
+others); the identified `0x180`/`0x1A0` setters write only bounded indices.
+Other initialization/callback writers remain unexcluded. Do not promote a
+synthetically corrupted private field into a GCP-reachable OOB proof.
+
+For ASIC family `0x14`, the signed `sub_D08DAC` case-20/25 table resolves
+slots 748/754/758/760/763/766/770/774 to link-training-status,
+register-read, pipe-lookup, link-ready, `sub_D06438`, query-link-config,
+`sub_D10A5C`, and link-query routines respectively (some through Thumb
+veneers). These read link/register/global state; slot 770's `sub_D10A5C`
+checks type 6 and can inspect separate global arrays. This does **not**
+establish harmless side effects or complete writer provenance for those
+globals, other variants, or naturally exercisable GCP link state.
diff --git a/fw/AUDIT-ASD-163-182-185-ASIC20-CALLBACK-OUTPUTS.md b/fw/AUDIT-ASD-163-182-185-ASIC20-CALLBACK-OUTPUTS.md
new file mode 100644
index 0000000..cbc63a3
--- /dev/null
+++ b/fw/AUDIT-ASD-163-182-185-ASIC20-CALLBACK-OUTPUTS.md
@@ -0,0 +1,39 @@
+# ASD `.163` opcodes `0x182..0x185`: link callback output widths
+
+**Scope:** signed dispatcher, direct leaves, four callback slots installed
+for ASIC family `0x14` by `sub_D08DAC` case 20/25, and a cross-case
+assignment inventory for those slots. Static only; no card request or
+callback emulation.
+Live read-only provenance previously measured family `0x14` on this card,
+but **not** these four live slot values; see
+`fw/AUDIT-ASD-163-18C-LINK-CALLBACK.md` for that narrower measurement.
+
+Each leaf requires channel `<=30`, active state, and validates both caller
+pointers before invoking a per-ASIC callback. The case-20 builder receives
+`base+2948`, so slot 742 is `field14`, slot 743 `field18`, slot 744
+`field1C`, slot 745 `field20`. Raw pointer literals and veneers resolve as:
+
+| opcode / leaf | validated per pointer | slot → signed case-20 target | caller-pointer behavior in resolved target |
+|---|---:|---|---|
+| `0x182` / `sub_D0AA28` | 1 byte | 744 → `0xD04E07` → `asd_reg_read_13B74_cfg3` | Zeroes then writes **one byte** to each output. |
+| `0x183` / `sub_D0AAB4` | 8 bytes | 742 → `0xD04E0F` → `asd_clear_link_outputs` | Clears/fills bytes `0..7` of each output, at most **eight** per pointer. |
+| `0x184` / `sub_D0AA6C` | 5 bytes | 743 → `0xD04E0B` → `asd_link_read_pair_regs` | Clears/fills bytes `0..4` of each output, at most **five** per pointer. |
+| `0x185` / `sub_D0AC10` | 5 bytes | 745 → `0xD04E1B` → `sub_D05E40` | No caller-buffer store observed; performs fixed/ASIC-table-selected fabric/register operations. Endpoint effects not evaluated. |
+
+**Cross-case builder check:** enumerating all assignments to each of
+`a1->field14`, `field18`, `field1C`, and `field20` in signed
+`sub_D08DAC`'s IDA pseudocode found **16 assignments per field** (the
+switch groups multiple ASIC IDs into each case). Resolving each assigned
+literal through its first Thumb veneer gave exactly the same four target
+functions shown above, respectively, with no alternate target in that
+assignment inventory. This extends the *direct callback write-width*
+observation beyond case 20 for the signed builder's assigned slots; it
+is not proof against runtime table mutation, an unreviewed initializer,
+or deeper callback/fabric side effects.
+
+All four immediate pointer checks match or exceed those direct
+caller-buffer stores; a `0x20B`-style unchecked ASD-private output pointer
+was **not** found in this group under the inventoried assignments. This
+is **not** a clean bill for link-state lifetime, other callback slots,
+indirection below the noted leaves, or the fabric writes. Do not call a
+stateful link command on hardware just to obtain a status code.
diff --git a/fw/AUDIT-ASD-163-18C-LINK-CALLBACK.md b/fw/AUDIT-ASD-163-18C-LINK-CALLBACK.md
new file mode 100644
index 0000000..2ff6818
--- /dev/null
+++ b/fw/AUDIT-ASD-163-18C-LINK-CALLBACK.md
@@ -0,0 +1,11 @@
+# ASD .163 `0x18C`: resolved live ASIC-20 link callback, not an invoked write
+
+Image: `psp_out/versions_win/elf_all/asd_33.0.0.163_18debcc4.elf`. Scope: dispatcher, first-level `0x18C`, callback-table initialization for ASIC variant 20, and its first two callback leaves. Not a review of all 32 variants or the entire link/SRM pipeline.
+
+* `asd_dispatch` (`0xD013B8`) routes `0x18C` to `sub_D0AC98`. It rejects channel indices above `0x1E`, lengths outside `1..0x27B`, and caller pointers failing `asd_validate_ptr(input,length)` or `asd_validate_ptr(other,20)`; it then requires channel state 1. It calls table slots 752, 753, and 754, and updates a channel state word depending on the final callback status. It does **not** itself issue a bulk caller-pointer write. Length zero is rejected by the unsigned `length-1` check; the byte reader at the tail of slot 753 uses index `length-1` within the validated region.
+* `sub_D0B458` zeros `0x1290` bytes of the table rooted at `0xD33510` and calls `sub_D08DAC(base+2948, variant, ...)`. Its signed startup caller is `sub_D02420`. The builder's cases 20/25 install slots 752/753/754 at offsets `base+0xBC0/0xBC4/0xBC8`: `0xD04E27` (veneer to `sub_D06038`), `0xD04E23` (veneer to `sub_D05F74`), and `0xD04DF3` (register-read veneer). Slot 747 maps through a veneer to `asd_program_link_by_signal`. Following veneers is essential: a direct-only call graph misses these targets.
+* `sub_D05F74` (`0xD05F74`) uses `LDRB [R9,R4]` at `0xD05FCC` and `LDRB [R9,R10]` at `0xD06000` to consume exactly the bounded `length` caller bytes, and executes `SVC 0x7C` at `0xD05FDA`/`0xD06010`, writing a masked value derived from each byte to an ASD-global-selected PSP-*fabric* endpoint. It also polls fixed registers via `sub_D0D5B0`. `sub_D06038` consumes the validated 20-byte argument's first dword and performs ASIC-global-selected register/fabric operations. A `SVC 0x7C` fabric address is **not** evidence of a CPU-MMU write; endpoint safety/effects are unassessed. Neither callback was invoked here.
+
+**Read-only hardware provenance:** `/root/psp/hw/asd163_link_callbacks_fresh.log`, script `/root/psp/hw/asd163_link_callbacks_readonly.py` (fresh ATX cycle logged in `/root/psp/hw/asd163_link_cycle_fresh.log`). GCP ROP made three ASD `0x404` index-9 width-4 reads: variant selector `0xD33434 = 0x14`, live slot 753 at `0xD340D4 = 0xD04E23`, and signed-handler code word `*(u32 *)0xD0AC98 = 0x43F8E92D`. The control and returned message headers matched; FE0A graceful status `0x240`, zero C2PMSG fault frame, final FE07 status 0 and GCP unload status 0. The live callback pointer agrees with signed ASIC-20 initialization; this is **not** a card invocation of `0x18C` and proves no fabric change.
+
+Separate `0x18F` global bitmap-release authority candidate: `fw/CANDIDATE-GCP-ASD-18F-BITMAP-RELEASE-AUTHORITY.md`. The first-level `0x180..0x18F` branch scan is not an exhaustive callback audit; no general clean bill for other variants or nested ops follows.
diff --git a/fw/AUDIT-ASD-163-1A2-1C0-JUMPTABLE.md b/fw/AUDIT-ASD-163-1A2-1C0-JUMPTABLE.md
new file mode 100644
index 0000000..f22656e
--- /dev/null
+++ b/fw/AUDIT-ASD-163-1A2-1C0-JUMPTABLE.md
@@ -0,0 +1,32 @@
+# ASD .163 service-2 `0x1A2..0x1C0`: raw jump-table correction and first-level audit
+
+**Build:** `psp_out/versions_win/elf_all/asd_33.0.0.163_18debcc4.elf`. This is a **first-level** signed-code pass, not a callback, hardware, or cross-build clean bill.
+
+## Why the decompiler is misleading
+
+`asd_dispatch` (`0xD013B8`) routes `0x180..0x1C0` via a 65-entry Thumb `TBH` at `0xD0143E`; entry address is `0xD01442 + 2*(opcode-0x180)`, and unsigned halfword `h` jumps to `0xD01442 + 2*h`. Hex-Rays prints `abort()` for all `0x1A2..0x1C0`, but **ten** of those labels have real handler entries. `0x18D`, `0x190..0x19F`, and `0x1AB..0x1BF` (38 labels in total) instead jump to `0xD015FC`, which returns status 4. The whole range has 27 handled labels, plus the shared invalid-status target. `abort()` is an artifact of incomplete switch recognition here; it does **not** show a remotely triggerable fatal path.
+
+| opcode | raw target | signed action (first level only) |
+|---|---|---|
+| `0x1A2` | `0xD0169C` | `sub_D0AEB0`: bounded selected channel/state; its conditional group sweep iterates only records 0..30 of a 32-slot table. Signed synthetic callback captures confirm that matching peer 31 is omitted (`fw/CANDIDATE-ASD-163-1A2-LAST-CHANNEL-SWEEP.md`); no live HDCP effect. |
+| `0x1A3` | `0xD016A4` | `sub_D0B2A8`: channel `<=31`, active state; store caller scalar at channel `+84`, no owner comparison; signed HDCP2 `.57` producer and synthetic selected-store test in `fw/AUDIT-ASD-163-1A3-1A4-HDCP2-STATE-SETTERS.md`. |
+| `0x1A4` | `0xD016AE` | `sub_D0B2C4`: same gate; store scalar at channel `+80`, consumed by `0x161` status logic; same scoped audit, no live impact proof. |
+| `0x1A5` | `0xD016B8` | `sub_D0B0F8`: channel bound, validates caller output for 32 bytes; loop at `0xD0B136..0xD0B16A` writes at most ten one-byte entries at output `+4..+13` (plus count), within that validation. |
+| `0x1A6` | `0xD016C2` | `sub_D0B07C`: bounds incoming channel, dereferences stored peer index **without rechecking peer bound**, then invokes callbacks. Identified `0x100`/`0x180`/`0x1A0` setters write only indices <=31; indirect writers/live peer provenance remain open (`fw/AUDIT-ASD-163-1A6-PEER-INDEX.md`). |
+| `0x1A7` | `0xD016CA` | `sub_D0AD2C`: allocator; bounded 160-byte input, count+requested `<=32`, 4-byte bitmap output; deeper dedup helper |
+| `0x1A8` | `0xD016D8` | `sub_D0B244`: four-byte caller bitmap release, **no channel-authority check**; separate candidate |
+| `0x1A9` | `0xD016E0` | `sub_D08CE8`: validates 160-byte output/one-byte count; **sparse-mask enumeration stops before live records** (connected synthetic trace) |
+| `0x1AA` | `0xD016EA` | `sub_D0B550`: dispatcher **zero-extends** count via `LDRB`; nonzero count + global count `<=32`, validates 160 bytes. **Deeper signed-dispatch test now shows a duplicate poisons a loop-wide flag and silently drops later unique IDs** (`fw/CANDIDATE-ASD-163-1AA-DUPLICATE-DROPS-TAIL.md`). |
+| `0x1C0` | `0xD016F4` | `sub_D083D8`: ASIC callback slots 775/776; signed ASIC-20 descendants bound the scalar as a lane index before fixed-table `SVC 0x7B/0x7C` (`fw/AUDIT-ASD-163-1C0-CONNECTOR-CALLBACK-BOUND.md`). No live callback value/effect or restoration oracle. |
+
+`0x1A0` and `0x1A1` are also handled (`0xD0168A/0xD01692`) and visible to Hex-Rays; they are not part of the ten missing labels. The previous `0x18F` audit documents a distinct unchecked 128-bit release routine. The signed dispatcher is reachable from GCP ROP at service-2 message granularity, but **opcode-specific live effects for this group have not been measured**.
+
+## Connected confirmation of the hidden path
+
+`python3 psp_emu/harness/probe_asd163_1a7_1a8_bitmap_release.py` enters the signed dispatcher twice: `0x1A7` allocates a synthetic channel-5 record, then `0x1A8` removes its global bitmap bit/count without checking the stored channel annotation. This disproves a universal `abort()` interpretation and demonstrates the bounded release defect under synthetic mappings. It is **not** a hardware allocation or evidence of a second real TA's live ownership. Details: `fw/CANDIDATE-GCP-ASD-1A8-BITMAP-RELEASE-AUTHORITY.md`. Normal allocation/release also exposes a distinct `0x1A9` sparse-enumeration/count mismatch (`psp_emu/harness/probe_asd163_1a9_sparse_enumeration.py`; `fw/CANDIDATE-ASD-163-1A9-SPARSE-ENUMERATION.md`).
+
+## Open boundaries
+
+* The per-ASIC callbacks, **complete** stored peer-index writer provenance in `0x1A6` (one bounded setter scoped separately), dedup helpers, and ownership semantics of the two global allocator tables remain unaudited beyond the first level.
+* A scalar channel number is not necessarily a caller/TA identity. No claim of cross-TA privilege violation is made without live owner and effect evidence.
+* No state-changing `0x1A*`/`0x1C0` command was issued to hardware, and no PSP-fabric address from the connector callback has been equated with CPU-MMU RAM.
diff --git a/fw/AUDIT-ASD-163-1A3-1A4-HDCP2-STATE-SETTERS.md b/fw/AUDIT-ASD-163-1A3-1A4-HDCP2-STATE-SETTERS.md
new file mode 100644
index 0000000..3256c4c
--- /dev/null
+++ b/fw/AUDIT-ASD-163-1A3-1A4-HDCP2-STATE-SETTERS.md
@@ -0,0 +1,52 @@
+# ASD `.163` `0x1A3`/`0x1A4`: selected channel-state stores and HDCP2 callers
+
+**Signed-static + synthetic dispatch only.** Neither opcode was invoked on
+the card; no live HDCP channel, cross-client effect, or register restoration
+oracle was established. Do not infer arbitrary fabric writes from a scalar
+stored in a private record.
+
+`0x1A3 → sub_D0B2A8` stores unrestricted `msg[2]` at channel `+84`;
+`0x1A4 → sub_D0B2C4` stores it at `+80`. Each checks `msg[1] <=31` and
+channel active flag at `+4 == 1`, but neither compares caller identity to a
+channel owner. The fields are in the shared table based at `0xD33510`.
+`python3 psp_emu/harness/probe_asd163_1a3_1a4_scalar_setters.py` passed
+signed dispatcher tests: channel 5 selected stores of `0xDEADBEEF` and
+`0xFFFFFFFF`, unchanged active channel 6, rejected channel 32 and inactive
+channel 5. These are **synthetic private records**, not other processes.
+
+Signed HDCP `.57` actually emits these opcodes via service-2 `SVC 0xF2`:
+wrappers `0x40452A`/`0x40454C` store `{opcode, channel, scalar}`. HDCP2
+session creation (`0x401E98`) and repeater ReceiverID handling (`0x402B64`)
+call `0x1A3`; HDCP2 certificate handling (`0x40246C`) calls `0x1A4`.
+This verifies **producer provenance**, not that `.57` is the active card
+client, that GCP knows a second client's channel, or that its state can
+safely be restored.
+
+`+80` is read as channel type/status by `asd_link_sub_113A0` (`0x161`):
+it returns that word to a checked four-byte caller output and branches on
+values 1/2, returning 7 for other values rather than using the arbitrary
+value as a pointer. It is also consumed by `sub_D0B320` and related link
+logic. `+84` is passed to link-control callback slots 755/757 on selected
+paths. `sub_D0AEB0` (free `0x1A2`) passes its selected record's `+84`
+to slot 755 for type-5 channels; `sub_D0B07C` (free `0x1A6`) passes the
+**stored peer's** `+84` to slot 755 only after its active/ASIC gates.
+For signed ASIC-20 assignments in `sub_D08DAC`, slot 755 is the
+`asd_pipe_enable` veneer (`0xD04E4B → 0xD07470`), and slot 757 is the
+`sub_D07534` veneer (`0xD04E4F`); the latter uses record/fixed-register
+state, not an arbitrary caller-selected fabric address. Raw slot-755
+descendant disassembly shows the saved scalar controlling **mode-2 bit
+selection**, not a chosen fabric address: `asd_reg_offsets_init_19600`
+(`0xD07134`) compares saved `R7` to 2 at `0xD07198/0xD071B8` and
+`0xD07226/0xD07244/0xD07266/0xD07284` to set or clear bit 5 or 21
+before signed fixed-register helper calls. `asd_scan_pipe_regs`
+(`0xD07350`) compares saved `R11` to 2 at `0xD07402` before a
+`sub_D114F0` register helper call. Signed `SVC 0x56` sites there are
+wait loops; this trace does **not** equate callback argument `+84` with
+a CPU-MMU pointer or PSP fabric address.
+
+This is a **conditional fixed-register mode-control lead**, not a
+hardware-confirmed change: an actual active other-client channel, its
+ASIC callback path and independent register-effect/restoration oracle are
+missing. Other ASIC variants and the complete helper/fabric side effects
+are not closed. No arbitrary register poke, HDCP bypass, or cross-client
+tamper impact is claimed.
diff --git a/fw/AUDIT-ASD-163-1A6-PEER-INDEX.md b/fw/AUDIT-ASD-163-1A6-PEER-INDEX.md
new file mode 100644
index 0000000..56c3966
--- /dev/null
+++ b/fw/AUDIT-ASD-163-1A6-PEER-INDEX.md
@@ -0,0 +1,82 @@
+# ASD `.163` `0x1A6` stored peer-index dereference: scoped provenance
+
+**Signed static only.** Build `asd_33.0.0.163_18debcc4.elf`; dispatcher
+`0xD013B8`. No card request, synthetic OOB target, or callback execution.
+This closes one first-level question in
+`fw/AUDIT-ASD-163-1A2-1C0-JUMPTABLE.md`, not the full writer graph.
+
+`0x1A6` calls `sub_D0B07C` (`0xD0B07C`). It checks incoming channel
+`<=0x1E`, `base+92*channel+4 == 1`, and type at `+0x40 == 5`, then loads
+**stored** peer index from `base+92*channel+0x3C` (`0xD0B09C`) and directly
+forms `base+92*peer` (`0xD0B09E`) without a fresh peer `<32` check. It
+reads the peer's active-state word before ASIC callback slots 758, 763,
+755, 757 and optional 759. If the peer field were corrupted/out of range,
+this would be a signed-code OOB read/callback-input candidate, **not** an
+established GCP-selected pointer or hardware effect. Earlier opcode `0x188`
+→ `sub_D0A8EC` also forms a record address using this unchecked stored peer
+index after bounding its incoming channel. `0x161`'s nested
+`asd_link_sub_113A0` (`0xD0BE28`) is a third such consumer
+(`fw/AUDIT-ASD-163-161-LINK-STATUS-CALLBACKS.md`). A further
+signed-code review found a **fourth**: `0x105 → sub_D08C50 →
+sub_D0BD08` validates a four-byte caller output and incoming channel
+`<=31`, then for an active type-5 record forms
+`base+92*record[+0x3C]` **without rechecking that stored peer**.
+After an active-state check it returns the peer's `+72` dword in
+the caller's bounded output. A fifth signed consumer is
+`0x1A1 → sub_D0AFB8 → sub_D0B320`: it follows the same unchecked
+stored peer for active type-5 records, reads peer state/type fields,
+and can pass the peer pointer to ASIC callbacks. This was found by
+rechecking all 49 signed functions with direct `0xD33510` literal
+references for `23*index+15` loads. An out-of-range peer would make
+`0x105` a conditional private-word read and `0x1A1` a conditional
+OOB callback-input path, but **no natural corrupted peer or card
+effect has been shown**. These consumers share the same
+stored-field provenance question.
+
+Three identified signed setters for that field are bounded. `0x1A0` →
+`sub_D0B1AC` requires caller index `<=31` (`0xD0B1AE..0xD0B1B0`); for
+active type-5 state, it writes **its bounded index** to its own peer field
+at `0xD0B1D4`, and its matching-peer loop iterates target indices **0–30**
+while writing that same bounded index at `0xD0B200`. Earlier opcode
+`0x180` → `sub_D0A96C` likewise requires incoming index `<=30` and has
+an analogous type-5 peer-link loop writing only that bounded index.
+The GCP-used `0x100` topology-update leaf `sub_D0B66C` is a **third**
+writer: it requires index `<=31`, copies caller descriptor fields into the
+record only through offset `+59`, then conditionally stores a matched loop
+index `0..30` or its own bounded index at `+60` (`v16 = &v5[23*a1+15]`).
+Even a caller-controlled 64-byte descriptor does **not** directly supply
+the stored peer index. None of these traced writers can manufacture an
+out-of-range peer. `0x1A1` performs region checks and ASIC callbacks **and consumes the stored peer in `sub_D0B320`**;
+`0x1A3/0x1A4` write different `+84/+80` fields.
+
+A signed-image literal scan found 23 aligned `0xD33510` words and 49
+functions with direct references to those literals. A scoped pseudocode
+search for field `+15`/byte `+60` in those functions recovered the three
+writers and several consumers, including `0x161` and an ASD event query.
+
+**Independent raw-store pass (signed `.163` code functions `0xD00000..0xD34000`):**
+19 `STR` instructions use an immediate `#0x3C` displacement. Sixteen
+are in configuration initializer `sub_D08DAC` (`0xD08DAC..0xD09C72`),
+called from `sub_D0B458` with `a1=0xD33510+2948`—**after** all
+32×92-byte channel records (`32×92=2944`), not a channel pointer.
+`sub_D0E10C`'s one such store at `0xD0E460` is called from
+`sub_D0E75C` with `a1=0xD397B0+36`, another unrelated configuration
+structure. The other two direct-offset stores are the bounded
+`0x180` writer at `0xD0A99E` and bounded `0x1A0` writer at
+`0xD0B1D4`. The `0x100` writer and `0x1A0` matching-peer stores
+form addresses indirectly and therefore **do not** appear in this
+immediate-displacement scan. `sub_D0B458` also clears a broader area
+containing the whole channel table during signed startup; this
+zeroing cannot introduce an out-of-range peer by itself.
+
+Neither scan proves a complete writer graph: callbacks, indirectly
+passed record pointers, dynamic offsets, bulk clears/copies after
+startup, and private-memory corruption can affect `+0x3C` without an
+explicit base literal or a `STR [reg,#0x3C]`. The `0x20B`
+GCP-owned hardware stores have not established an ASD-private state write.
+
+**Rating:** unchecked *stored* index with three bounded identified setters, not a
+new proven post-GCP OOB primitive. Next verification, if warranted, is a
+complete signed-write inventory for channel `+0x3C` and a safe read-only
+live-state oracle; no synthetic private-field planting should be promoted
+to live exploitability.
diff --git a/fw/AUDIT-ASD-163-1C0-CONNECTOR-CALLBACK-BOUND.md b/fw/AUDIT-ASD-163-1C0-CONNECTOR-CALLBACK-BOUND.md
new file mode 100644
index 0000000..18da778
--- /dev/null
+++ b/fw/AUDIT-ASD-163-1C0-CONNECTOR-CALLBACK-BOUND.md
@@ -0,0 +1,35 @@
+# ASD `.163` `0x1C0`: scoped ASIC-20 connector callback/index bounds
+
+**Signed-static only.** No `0x1C0` card invocation, selected endpoint effect,
+or exact restoration oracle. This follows the hidden jump-table first-level
+entry in `fw/AUDIT-ASD-163-1A2-1C0-JUMPTABLE.md` without claiming a
+complete per-ASIC or live register audit.
+
+`asd_dispatch` sends the caller's scalar `msg[1]` to `sub_D083D8`
+(`0xD083D8`), which calls callback slot 776 first. On a zero result it
+returns immediately; otherwise it calls slot 775 with the same scalar
+and, if successful, slot 776 again. Signed `sub_D08DAC`'s ASIC-family-20
+case (also case 25) installs slot 775 via `0xD0A074 → 0xD04DDB →
+asd_connector_enable` (`0xD053F4`) and slot 776 via `0xD0A078 →
+0xD04DD7 → asd_reg_read_13D24_cfg0` (`0xD053D8`). The latter uses a
+fixed register-table entry; the former tests a fixed link status and, on
+its success path, reads/writes a fixed connector-table entry. DTM `.19`
+GP command 5 / command ID 3 forwards a host request scalar through its
+service-2 `0x1C0` wrapper; that is signed client provenance, **not**
+proof of arbitrary unprivileged host access or active DTM build.
+
+This scalar is used as a **lane index**, not directly as a fabric address.
+The signed ASIC-20 descendants `sub_D0D508` and `asd_reg_read_13D24`
+check it as an unsigned value against different global bounds at
+`0xD291E8+8` and `+12` before issuing their `SVC 0x7B` reads.
+`asd_reg_write_19600` likewise checks `index < *(u32 *)(0xD291E8+12)`
+before `SVC 0x7C`, and constructs its address from the fixed table plus
+an optional lane-offset array (with an overflow branch). Thus a huge
+scalar is not, by itself, a proven chosen-address fabric write on the
+reviewed ASIC-20 path. The signed decompiler prints zero returns around
+inline SVC instructions; those are **not** hardware return-code or
+register-state measurements.
+
+Live callback-slot values, the runtime bounds and table entries, per-lane
+fabric semantics, other ASIC families, and whether the DTM host command
+is active remain open. No status-only state-changing probe is justified.
diff --git a/fw/AUDIT-ASD-163-200-20B-NESTED-POINTERS.md b/fw/AUDIT-ASD-163-200-20B-NESTED-POINTERS.md
new file mode 100644
index 0000000..fc1a72c
--- /dev/null
+++ b/fw/AUDIT-ASD-163-200-20B-NESTED-POINTERS.md
@@ -0,0 +1,32 @@
+# Signed ASD `.163` service-2 `0x200..0x20B` immediate-handler audit
+
+**Scoped static pass on signed `asd_33.0.0.163_18debcc4.elf`, not an
+exhaustive callback, crypto, state-machine or hardware-permission audit.**
+GCP ROP can supply service-2 messages with arbitrary opcodes; the normal
+GCP/host command set is not a coverage boundary. This pass checked the
+`0xD013B8` dispatcher-to-leaf argument flow and the first pointer/copy
+checks, using raw Thumb instructions where decompilation failed. It
+found the independently tested `0x20B` missing nested-pointer check,
+not a general assurance that other opcodes are safe.
+
+| Opcode | Immediate signed path | Pointer/size observations and limit |
+|---|---|---|
+| `0x200` | `sub_D0DFC4` → `sub_D0DFE0` | Validates `msg[1]` for `0x28` bytes before output and callback dispatch. Callback semantics not closed. |
+| `0x201` | `sub_D0EF60` | Validates `msg[1]` for 32 bytes and for `*(u32 *)msg[1]`; checked crypto length `*a1-32 <= 0x920`. This references private `0xD397B0` as a 16-byte secret attribute. Downstream crypto and TOCTOU are outside this pass. |
+| `0x202` | `asd_svc_op_202` | Validates input `(ptr,len)`, output-size word `(a4,4)`, and output `(ptr,*a4)` before SYS_DRV operations. **Do not mistake validation for confidentiality:** a prior separate canary-leak finding applies. |
+| `0x203` | `sub_D0E8F8` | Selector `<=3`, pointer/length16 validated. **Deeper signed raw/test:** two or more state bits select a checksum-gated 16-byte global-record **read into caller**; exactly one bit selects a caller→global copy followed by untested stateful callbacks. Free `0x205` can set two bits without owner binding (`fw/CANDIDATE-GCP-ASD-203-DIO-UNBOUND-RECORD-ACCESS.md`). No live cross-client content. |
+| `0x204` | `sub_D0E068` → `sub_D0E084` | Validates `msg[1]` for `0x20` bytes. Signed ASIC-20 `+56` callback writes only four dwords within that window after fixed `SVC 0x7B` reads; no nested pointer in that descendant (`fw/AUDIT-ASD-163-204-ASIC20-CALLBACK-OUTPUT.md`). Other ASICs/runtime fabric content open. |
+| `0x205`, `0x206` | `sub_D0DC34`, `sub_D0DC8C` | Helpers require `msg[1] <= 3` and one-bit `msg[2]` for a bounded state-word mutation. **Dispatcher still performs conditional session/deadline side effects on invalid bitmask/status 2** in signed synthetic controls (`fw/CANDIDATE-GCP-ASD-205-206-INVALID-MASK-SESSION-SIDE-EFFECT.md`). No nested caller pointer. |
+| `0x207` | `asd_svc_op_207` | Explicit `asd_validate_ptr(msg[1],4)` before a nullable callback. Signed ASIC-20 `+0x3C` descendant reads one dword through a separate ASD-private pointer and stores exactly four output bytes; synthetic control rejected ASD-private output and preserved the adjacent sentinel. Natural source-pointer provenance remains open (`fw/AUDIT-ASD-163-207-ASIC20-CALLBACK-OUTPUT.md`). |
+| `0x208` | `asd_log_event` → `asd_bzero_core_cfg2` | Packed scalar fields from `msg[1]`, not a caller pointer. **Deeper signed raw/connected model:** sends fixed service-1 opcode `0x1079` via `SVC 0xF2`, which conditionally requests a fixed-address fabric write of the packed word; no actual fabric effect (`fw/AUDIT-ASD-163-208-SYSDRV-1079-FORWARD.md`). |
+| `0x209` | `sub_D0EB3C` | No nested pointer; reads a state-indexed return table after unsigned `(state-20) <= 7` check. |
+| `0x20A` | `sub_D0E980` | Raw `0xD0E982..0xD0E996` requires pointer nonzero, length `0x10`, and `asd_validate_ptr(ptr,0x10)` before source-byte loads; later branch may copy 16 bytes to internal state. |
+| **`0x20B`** | `0xD0178A` → `asd_svc_op_20B` at `0xD0DC14` | **No nested pointer check:** stores Boolean directly to `*(u32 *)msg[1]`. Signed-dispatch emulator changes synthetic ASD-private RAM, while two fresh card runs with swapped GCP-owned targets prove the selected output store but **not** a live ASD-private write. See `fw/CANDIDATE-GCP-ASD-20B-UNCHECKED-OUTPUT-STORE.md`. |
+
+The transport's message-pointer validation cannot substitute for each
+handler's nested pointer/range check. Some decompiler renderings of the
+`0x201` and `0x202` cleanup flow are misleading; this pass did **not**
+revalidate their successful crypto or object lifetime. It does not cover
+`0x180..0x1C0`, `0x300`, `0x402..0x405`, signed startup, or indirect
+per-channel callbacks. The older statement that ASD's service-2 surface
+is "uniformly validated" is false in this signed build.
diff --git a/fw/AUDIT-ASD-163-200-ASIC20-OUTPUT.md b/fw/AUDIT-ASD-163-200-ASIC20-OUTPUT.md
new file mode 100644
index 0000000..867636d
--- /dev/null
+++ b/fw/AUDIT-ASD-163-200-ASIC20-OUTPUT.md
@@ -0,0 +1,36 @@
+# ASD `.163` `0x200`: signed ASIC-20 output footprint
+
+**Scoped signed-code audit plus synthetic controls.** `sub_D0DFC4`
+validates `msg[1]` for **40 bytes**. `sub_D0DFE0` writes one byte at
+`+0`, the variant dword at `+4`, and a constant dword at `+8`. With
+signed ASIC variant **20**, the switch handles `variant-1==19` without
+visiting the optional variant-specific callbacks in other cases. It
+then calls SYS_DRV service-1 `0x109B` through
+`sysdrv_get_chip_id_pair`. On a zero wrapper result it also zeroes the
+caller output's eight bytes at `+16..+23`; on a nonzero result it does
+not write those eight bytes. The handler returns zero in both modeled
+cases. No nested caller pointer was observed on this signed path.
+
+`python3 psp_emu/harness/probe_asd163_200_asic20_output.py` passes
+with signed dispatcher/handler and a directly seeded synthetic variant
+20. Only the SYS_DRV wrapper is intercepted with explicit results 0/1.
+The result-1 run recorded signed caller stores at byte `+0` and dwords
+`+4,+8`; result-0 additionally recorded dwords `+16,+20`. The final
+16 bytes of the validated 40-byte window remained marked in both.
+These **are not natural SYS_DRV statuses or chip-ID values**. The test
+neither initializes ASD from sOS nor exercises card hardware.
+
+**Signed-client control:** HDCP `.57` wrapper `hdcp_sysdrv_rpc_200`
+(`0x40466A`, despite its name) sends opcode `0x200` to **service 2**;
+its only direct caller found is `hdcp_cmd0B` (`0x402ED8`). Raw
+`0x402EE2..0x402EEE` zeros the entire 40-byte local result buffer
+**before** `0x402F34` calls the wrapper, and the caller branches on the
+RPC status before interpreting its variant field. Thus the synthetic
+nonzero-wrapper path's unchanged bytes do **not** constitute an
+uninitialized-buffer disclosure at that examined signed callsite.
+Other computed callers and active HDCP build remain open.
+
+The observed pattern is a bounded output, not a new overwrite or an
+independently established disclosure. The nonzero-wrapper branch
+returns success while leaving some caller-owned bytes unchanged; real
+SYS_DRV return semantics, ASIC variant and other callers remain open.
diff --git a/fw/AUDIT-ASD-163-204-ASIC20-CALLBACK-OUTPUT.md b/fw/AUDIT-ASD-163-204-ASIC20-CALLBACK-OUTPUT.md
new file mode 100644
index 0000000..7755769
--- /dev/null
+++ b/fw/AUDIT-ASD-163-204-ASIC20-CALLBACK-OUTPUT.md
@@ -0,0 +1,34 @@
+# ASD `.163` `0x204`: ASIC-20 callback writes four bounded result words
+
+**Scoped signed-static callback audit, not a hardware register audit.**
+The immediate `sub_D0E068` requires `asd_validate_ptr(msg[1],32)`;
+`sub_D0E084` checks the ASIC variant against a fixed mask and invokes
+callback slot `+56` in the ASD configuration at `0xD397B0`. Signed startup
+`sub_D0E75C` clears that `0x8C`-byte configuration and initializes its
+callback region starting at `+36` via `sub_D0E10C`. For ASIC variant 20,
+`sub_D0E10C` installs `0xD0E5D4 → sub_D0C5C4` (Thumb
+`0xD0C5C5`) at slot `+56`. Raw `sub_D0C5C4` begins `MOV R0,R1` and
+tail-branches to `asd_reg_read_12688` (`0xD0C824`), so the original
+validated 32-byte caller pointer is the callback's output pointer, not
+an unvalidated nested pointer. This callback performs three `SVC 0x7B`
+fixed-register reads (one may be skipped by a global flag) and writes
+only output dwords at offsets **0, 4, 8 and 12**; it has no direct
+`SVC 0x7C` write or further caller-pointer dereference. Two of the
+outputs are masked register-bit fields; their hardware significance is
+not established.
+
+`python3 psp_emu/harness/probe_asd163_204_asic20_output.py` passed on
+the signed dispatcher and callback: it seeds only the synthetic ASIC-20
+slot, explicitly models the three fixed-register `SVC 0x7B` reads,
+records exactly four caller dword stores at offsets 0/4/8/12, and
+checks the final 16 bytes of the validated 32-byte window remain
+unchanged. The harness does **not** execute signed startup or real
+fabric decode.
+
+This narrows a first-level open callback, but does not establish live
+slot value/variant, the actual PSP fabric register decode, contents,
+caller ownership or the behavior of other ASIC families. The `0xD397B0`
+first 16 bytes used by `0x201` are **distinct from this callback pointer
+at `+56`**: `sub_D0E10C` receives the configuration at `+36`; this
+callback assignment does not overwrite the first 16-byte buffer. No
+card request or raw key material was involved.
diff --git a/fw/AUDIT-ASD-163-207-ASIC20-CALLBACK-OUTPUT.md b/fw/AUDIT-ASD-163-207-ASIC20-CALLBACK-OUTPUT.md
new file mode 100644
index 0000000..8d7a9ab
--- /dev/null
+++ b/fw/AUDIT-ASD-163-207-ASIC20-CALLBACK-OUTPUT.md
@@ -0,0 +1,54 @@
+# ASD `.163` service-2 `0x207`: ASIC-20 callback stores one validated dword
+
+**Scoped signed callback audit and synthetic control, not a live
+private-pointer disclosure.** Immediate `asd_svc_op_207`
+(`0xD0DF9C`) validates exactly **four output bytes** at `msg[1]`,
+then calls callback slot `0xD397B0+0x3C` if nonnull. Signed startup
+`sub_D0E75C → sub_D0E10C` installs thunk `0xD0C351` at that slot
+for ASIC variant **20** (the variant measured on the card in
+separate read-only work). Its signed descendant
+`asd_get_pair_D49838` (`0xD0C440`) loads a pointer from ASD-private
+`0xD39848`, loads **one** dword from that pointer, and stores it at
+caller output offset **zero only**. The misleading `get_pair` name
+must not be used to infer an eight-byte output. The callback return
+is ignored by the leaf after the nonnull precheck.
+
+`psp_emu/harness/probe_asd163_207_asic20_output.py` passed on
+signed `.163` dispatch with a **planted synthetic** ASIC-20 slot and
+source pointer. A GCP-owned validated output received exactly four
+public marker bytes; its next 12 sentinel bytes were unchanged.
+An ASD-private output pointer was rejected with status 2 before
+callback invocation. Both config words were restored **only in
+emulator memory**. No natural ASD-private pointer content or
+hardware read was sampled.
+
+**Additional signed startup trace (no card read):** the original
+ELF has no IDA-mapped BSS beyond `0xD29100`, so a direct IDA xref
+to `0xD39848` is unavailable. Following code/data literals instead
+resolved `off_D0C47C = 0xD39848` and
+`dword_D0C438 = 0x030109EC`. The ASIC-20 branch of `sub_D0E10C`
+installs Thumb pointer `0xD0C355` (`sub_D0C354`) in the callback
+at `0xD397B0+0x24`. **Correction to the earlier scoped scan:**
+`sub_D0E75C` directly calls that callback as
+`v6 = *((... )v5+9); v6()` after successful variant setup;
+that indirect invocation was overlooked. `sub_D0C354 →
+asd_set_pair_D49838` sets private `0xD39848` to the **fixed**
+CPU-address value `0x030109EC` and the adjacent word to
+`0x03010AE8`. ASIC-20 `0x207` then dereferences the first fixed
+address and writes one dword into a validated caller buffer.
+The two pointers are not taken from the `0x207` request.
+Older local emulator notes already identified `0x030109EC` as
+**C2PMSG_59** (`psp_emu/pspemu/memmap.py`,
+`psp_out/FUZZING-EMULATED.md`); this startup trace resolves *how*
+that fixed source is installed in signed `.163`, not a newly
+identified arbitrary target. The register's live content and
+security meaning are not established by the emulator's label.
+
+This establishes a signed natural *writer path*, **conditional on
+startup succeeding through that callback**. It does not establish
+the live pointer value, the Navi31 meaning or permissions of those
+CPU-window addresses, a card `0x207` return, or confidentiality
+impact. Other variants and dynamic reinitialization remain open.
+The isolated synthetic source pointer is not proof of GCP control
+of an ASD-private read target. GCP's separate `0x404` read remains
+the established disclosure route. No card `0x207` request was made.
diff --git a/fw/AUDIT-ASD-163-208-SYSDRV-1079-FORWARD.md b/fw/AUDIT-ASD-163-208-SYSDRV-1079-FORWARD.md
new file mode 100644
index 0000000..7a6967d
--- /dev/null
+++ b/fw/AUDIT-ASD-163-208-SYSDRV-1079-FORWARD.md
@@ -0,0 +1,41 @@
+# ASD `.163` service-2 `0x208` forwards a packed event to SYS_DRV `0x1079`
+
+**Signed cross-service provenance; synthetic relay and captured fabric
+request only.** The prior first-level audit called `0x208` an event
+logger without following its callback. Raw signed
+`asd_log_event` (`0xD0ECD4`) packs the three scalars unpacked
+from `msg[1]`: `low8 << 24 | byte1 << 16 | high16`.
+`asd_bzero_core_cfg2` (`0xD01ACA`) places this word at request
+`msg[14]`, fixes opcode **`0x1079`** and service **1**, then invokes
+`SVC 0xF2`. It does not forward a caller-chosen nested pointer or
+SYS_DRV opcode. ASD returns **28** if the F2 request reports
+nonzero status; otherwise it returns zero.
+
+Signed SYS_DRV `.54` `0x1079 → sub_E1939C → sub_E154A0` is the
+fixed-address fabric-write path recorded in
+`fw/LEAD-GCP-SYSDRV-1079-CHOSEN-FIXED-FABRIC-WORD.md`. Its
+signed-image gate starts at `0xE26314=2`; it skips values whose
+top byte is `0xEE` or `0xEF`, and otherwise requests `SVC 0x7C`
+width 4 at fixed `0x03B30600`. **For ASD `0x208`, that top byte
+is the low byte of `msg[1]`**, not the original word's top byte.
+
+`psp_emu/harness/probe_asd163_208_sysdrv1079_forward.py` passed
+using signed `.163` ASD dispatch and signed `.54` SYS_DRV dispatch.
+It provided a **synthetic SVC F2 relay**, a restricted synthetic
+SVC76 mask `0x10`, and a **capture-only SVC7C**, not sOS service
+scheduling or real hardware. ASD input `0x11223344` produced SYS_DRV
+inline value `0x44331122` and requested
+`(0x03B30600,0x44331122,4)`; input `0x112233EE` produced
+`0xEE331122` and did not request a second fabric write. Both
+signed handlers returned zero. No card request or physical
+endpoint readback occurred.
+
+This identifies an intended signed producer of the free SYS_DRV
+opcode; it **does not** independently establish Navi31 register
+semantics, a security-relevant logging obligation, actual fabric
+acceptance, or a new authority boundary. GCP already has the
+separately modeled direct free `0x1079` route. Which active HDCP
+or other signed clients naturally call ASD `0x208`, and whether
+suppressed reserved-byte events matter to them, remain unproved.
+Do not program unknown fabric `0x03B30600` on the card for a
+return code.
diff --git a/fw/AUDIT-ASD-163-300-308-FIRSTLEVEL.md b/fw/AUDIT-ASD-163-300-308-FIRSTLEVEL.md
new file mode 100644
index 0000000..3c65cfa
--- /dev/null
+++ b/fw/AUDIT-ASD-163-300-308-FIRSTLEVEL.md
@@ -0,0 +1,38 @@
+# Signed ASD `.163` service-2 `0x300..0x308` first-level audit
+
+**Static handler-entry review only. No GCP/card invocation in this pass.**
+This complements `fw/AUDIT-ASD-163-200-20B-NESTED-POINTERS.md` and does
+not supersede the known signature-gated `0x308` defect in
+`psp_out/ASD-REACHABLE-AUDIT.md` / `psp_out/VULN-ASD-308-REACHABLE.md`.
+Source: signed `asd_33.0.0.163_18debcc4.elf`, dispatcher `0xD013B8`.
+The normal HDCP-issued opcode list is not a limit on what a GCP ROP
+service-2 request can ask ASD to dispatch.
+
+| Opcode | Signed leaf | Immediate checks and limits |
+|---|---|---|
+| `0x300` | `asd_srm_read` `0xD0CE70` | Validates `msg[1]`/`msg[3]` for four bytes and, if non-null, `msg[4]` for the requested `msg[2]` bytes. It copies stored SRM bytes to that output only when stored count `<= msg[2]`. A null output with nonzero requested length does not take the copy branch. The retained SRM state/provenance is separate. |
+| `0x301` | `asd_srm_op_301` `0xD0CED0` | Requires input count `a2` in `[48,0x1400]` via unsigned `(a2-48)<=0x13D0`, input pointer non-null and `asd_validate_ptr(ptr,a2)`. Copies into a zeroed `0x1400` stack buffer before a header check; a successful header check can update ASD's SRM state. No unsigned length over that local buffer is admitted at the entry gate. |
+| `0x302` | `sub_D0CD7C` `0xD0CD7C` | Requires non-null `msg[1]` and `asd_validate_ptr(ptr,5)` before `asd_srm_sub_13174`. The worker reorders the five caller bytes for the stored SRM's v8/v9 membership tests, returning 13 for a match; no direct caller-selected store was observed in this worker. Retained SRM bounds/provenance are not closed. |
+| `0x303` | `asd_srm_query` `0xD0CE04` | Same non-null five-byte pointer check before `asd_srm_sub_131F8`, which tests the five-byte candidate against the stored v8/v9 SRM, returning 23 for a match. Again this is not a proof that the retained SRM parser is safe. |
+| `0x304` | `asd_op_304` `0xD0C960` | Scalar state query; checks `asd_state_not_1()` and link-state words; no nested pointer at immediate leaf. |
+| `0x305` | `asd_op_305` `0xD0C9A4` | Accepts scalar selector 1–6, sets one of three internal state words, otherwise returns 4. **State-changing**, not a getter. |
+| `0x306` | `sub_D0C980` `0xD0C980` | Scalar query on two stored state words and a flag; no nested pointer at immediate leaf. |
+| `0x307` | `sub_D0D154` `0xD0D154` | Requires non-null `msg[1]` and `asd_validate_ptr(ptr,5)`, counts bits in five bytes and accepts exactly 20 set bits. |
+| `0x308` | `asd_srm_store` `0xD0CF68` | Requires unsigned input count in `[48,0x1400]`, non-null input, validates `(input,count)`, four-byte output and one-byte output. It snapshots caller bytes to a stack buffer before SRM/signature logic; downstream recomputation/copy is the previously documented **signature-gated candidate**, not cleared by these entry checks. No valid signature or live effect was reproduced here. |
+
+**Later deep signed-helper finding:** After a successful header/crypto check,
+`0x301` invokes `asd_srm_sub_12EC4`. Its final multi-revocation bitmap
+cleanup does not rewind the bitmap cursor for a second queued channel.
+A signed-helper emulator trace with an unsigned planted SRM executed both
+signed channel-state helper calls but stubbed the ASIC callback. It
+demonstrated the bookkeeping mismatch, **not** a valid signed update or live
+HDCP impact:
+`fw/CANDIDATE-ASD-163-SRM-MULTI-REVOCATION-BITMAP.md`.
+
+These are **first-level** observations, not an assurance that deep SRM
+parsing, callbacks, signature validation, internal state lifetime or
+concurrent host mutation are safe. Do not invoke `0x305`, `0x301` or
+`0x308` on the card merely to obtain a return code: they mutate
+sensitive ASD state when successful. No new `0x300`-range root cause was
+established in this pass; `0x20B` remains the newly found unchecked
+nested pointer in the adjacent group.
diff --git a/fw/AUDIT-ASD-402-FIXED-FABRIC-TOGGLE.md b/fw/AUDIT-ASD-402-FIXED-FABRIC-TOGGLE.md
new file mode 100644
index 0000000..19297c1
--- /dev/null
+++ b/fw/AUDIT-ASD-402-FIXED-FABRIC-TOGGLE.md
@@ -0,0 +1,27 @@
+# ASD `.163` opcode `0x402`: fixed fabric bit toggles, not a getter
+
+**Signed static path only; no card invocation or register-effect oracle.**
+GCP ROP could request ASD service-2 opcode `0x402`, but this case is a
+state-changing operation and should not be tested merely for its return.
+Source: signed `asd_33.0.0.163_18debcc4.elf`.
+
+At `asd_dispatch` `0xD0154C..0xD0155C`, case `0x402` invokes `SVC 0x8D`,
+ORs its **returned** `R0` with 1, and calls `asd_platform_op_402`
+(`0xD0FBA0`) with the low byte of `msg[1]` **only if the result equals
+3**. The generated decompilation erroneously renders the condition as
+`(rpc_id | 1) == 3`; raw instructions show the register comes from the
+SVC return, not the opcode constant. `SVC 0x8D`'s live return for this
+condition was not measured here. Do not infer it from ASD's separately
+sampled ASIC variant 20 without tracing their relationship.
+
+The leaf uses `SVC 0x7B` to read fixed PSP-fabric locations `0x1C840`
+and `0x1C844` into a four-byte stack scratch, then calls `SVC 0x7C`
+twice. If `LOBYTE(msg[1]) == 1`, it clears bit 0 of the first read word
+and bit 2 of the second; otherwise it sets those bits. It returns zero.
+The opcode supplies a **bit-toggle selection**, not an arbitrary address
+or word value. These fabric addresses are not established CPU-MMU physical
+addresses, and neither their Navi31 function nor their live write/readback
+has been confirmed. In particular, handler return zero would not prove a
+store. A safe hardware experiment would require documented register
+semantics, before/after host or ASD readback, and a restoration plan for
+both fixed locations; none is available. `0x402` was **not** invoked.
diff --git a/fw/AUDIT-ASD-405-CALLBACK-PROVENANCE.md b/fw/AUDIT-ASD-405-CALLBACK-PROVENANCE.md
new file mode 100644
index 0000000..8df1435
--- /dev/null
+++ b/fw/AUDIT-ASD-405-CALLBACK-PROVENANCE.md
@@ -0,0 +1,54 @@
+# ASD `.163` opcode `0x405`: callback provenance on the RX 7900 XTX
+
+**Result: the specific `0x405` callback lead is inactive on the sampled fresh
+boot.** This is signed-code data flow plus a read-only hardware observation,
+**not** an invocation of `0x405` or proof that other ASD handlers are inert.
+
+## Signed-code route
+
+In the card's signed ASD `33.0.0.163`, `sub_D013B8` dispatches service-2
+opcode `0x405` to `sub_D0D438`. That wrapper reads a function pointer from
+`*(u32 *)(0xD33434 + 36*4) = *(u32 *)0xD334C4`; if zero, it returns **7**
+without calling through it. The pointer is part of the ASIC hardware-ops
+struct, **not** an RPC argument.
+
+`asd_hw_ops_init` at `0xD021CC` clears the struct from `0xD33438` for
+`0xCC` bytes, stores the ASIC variant at `0xD33434`, and calls
+`asd_build_hw_ops` at `0xD01D6C`. The latter populates the relevant slot
+(`ops[35]`, because it receives `base+4`) with signed Thumb pointers for
+variants 5 (`0xD0F171`), 10 (`0xD0F1C1`), and 11/12 (`0xD0F215`);
+variants 6/8 leave this slot zero, and the default branch installs no
+callbacks. The three nonzero targets would request fixed `SVC 0x7B/0x7C`
+operations involving fabric addresses `0x5A504`, `0x5A510`, and `0x5A514`
+when invoked. Those addresses are **not** caller-selected. No such call or
+fabric write was performed in this audit. Their Navi31 register meaning and
+side effects are not established.
+
+## Live-card check (read only)
+
+After an ATX cold cycle reached `LINK UP`, signed ASD and GCP loaded with
+status zero, GCP session ID 1. Three GCP-ROP → ASD `0x404` index-9 reads
+returned, on the **same boot**:
+
+| ASD VA | Purpose | Observed word |
+| --- | --- | --- |
+| `0xD013B8` | signed-code control | `0x2800B57C` (expected) |
+| `0xD33434` | ASIC variant | `0x00000014` (20 decimal) |
+| `0xD334C4` | live `0x405` callback | `0x00000000` |
+
+FE0A status `0x240`, graceful marker `0x5A`, zero fault frame, and final
+FE07 return zero rule out treating an unexecuted/sentinel response as the
+read result. The live variant **20** takes the default branch of the signed
+builder, consistent with the zero callback. The original log's
+`expected-variant-callback=False` is a **probe checker omission**: its
+lookup table lacked variant 20, although the observed pair `(20, 0)` matches
+the signed default branch. The saved probe has since been corrected; its
+raw observations were not changed or rerun. Probe:
+`/root/psp/hw/gcp_rop_asd3_callback_provenance.py`; logs:
+`/root/psp/hw/asd405_callback_{fresh_cycle,fresh}.log`.
+
+Thus an immediate `0x405` request under the observed state is predicted by
+the signed wrapper to return 7; it is **not** a justified hardware write
+experiment. We did **not** invoke `0x405`, demonstrate its return on hardware,
+rule out future reinitialization, or audit other callback slots. This closes
+only the proposed *currently installed `0x405` callback* escalation route.
diff --git a/fw/AUDIT-CROSS-CLIENT-CRYPTO-OBJECT-LIFETIME.md b/fw/AUDIT-CROSS-CLIENT-CRYPTO-OBJECT-LIFETIME.md
new file mode 100644
index 0000000..68cef21
--- /dev/null
+++ b/fw/AUDIT-CROSS-CLIENT-CRYPTO-OBJECT-LIFETIME.md
@@ -0,0 +1,61 @@
+# Cross-client SYS_DRV crypto-object lifetime: three signed clients
+
+**Static signed-image audit only; no object was read on the card.** Purpose:
+find a real, *live*, non-GCP-owned SYS_DRV crypto object whose contents could
+be checked with the already-demonstrated GCP `0x109A` virtual read. Reading a
+stale/freed heap buffer or an attacker-created object is not equivalent to
+reading an honest second client's live key.
+
+| signed client | service-1 opcode `0x30` callsites | lifetime observed in signed code |
+| --- | --- | --- |
+| HDCP `23.0.0.52` (`hdcp_23.0.0.52_c6b25da3.elf`) | `0x403676`, `0x4041F8`, `0x404300`, `0x40447C` | Four containing routines `0x4035FC`, `0x404180`, `0x4042C4`, `0x4043E8` all conditionally free the local nonzero object handle (`0x31`) and operation handle (`0x02`) before normal return. One callsite **ignores allocation failure**; see `fw/CANDIDATE-HDCP52-ALLOC-FAIL-SYSDRV-FATAL.md`. |
+| OPM `25.0.0.51` (`opm_25.0.0.51_97f44863.elf`) | `0x401214`, `0x402330`, `0x402782` | Containing routines `0x4011D8`, `0x402300`, `0x4023EC` all release the local nonzero object handle (`0x31`) and operation handle (`0x02`) before normal return. |
+| MERIT `24.0.0.46` (`merit_24.0.0.46_4d02c1b9.elf`) | `0x401208`, `0x401392`, `0x401796` (one `0x30` SYS_DRV stub at `0x401DE4`) | Each checks opcode-`0x30` status before using its object. The routines beginning `0x4011D8`, `0x401348`, `0x401468` have matching `0x31` frees (`0x40129A`, `0x401442`, `0x401868`) on their local nonzero-handle cleanup paths. No stable cross-request object shown. |
+
+**Additional negative triage:** Signed DTM `18.0.4.19`
+(`dtm_18.0.4.19_376639d1.elf`) has only three encoded Thumb
+`SVC 0xF2` sites (`0x4010D8`, `0x4010F6`, `0x401112`) and no ARM
+`SVC 0xF2` encoding in its load image. Disassembly shows each sets
+`R0=2` (ASD service) before the call; despite misleading `dtm_sysdrv_rpc_*`
+function names, none requests SYS_DRV service 1 or opcode `0x30` in this
+signed build. This **does not** exclude other DTM versions or indirect
+service calls, but makes this image a poor retained SYS_DRV object source.
+
+Signed RAS `27.0.2.5` (`ras_27.0.2.5_db2ed53e.elf`) has twelve
+encoded Thumb `SVC 0xF2` sites and no ARM encoding in its load image.
+Its visible service-1 request opcodes are fixed (`0x109A`, `0x1067`,
+`0x1077`, `0x7001/2/6/7/8`, `1`, `0xD`, `2`, `0x42`); no opcode `0x30`
+object allocator is emitted at these sites. This excludes the **examined
+signed RAS image** as a direct ordinary retained-object producer, not every
+possible indirect or other-version route. Its `0x109A` wrapper accepts an
+index, but its sole direct signed caller passes zero through `0x403758`
+(`0x40385C` → `0x403758(0)`); this does not provide a standalone arbitrary
+index path from the observed call chain.
+
+Signed PowerPlay `34.0.0.12`
+(`powerplay_34.0.0.12_e6329cd6.elf`) has nine Thumb
+`SVC 0xF2` encodings and no ARM encoding in its load image. Its visible
+service-1 wrappers use `0x6001/2/3`, `0x109A`, `0x41`, or `0x53`;
+the ungrouped `0x402836` site explicitly uses `0x53`, not `0x30`.
+The other sites target service 2. The sole direct caller of its `0x109A`
+wrapper passes index zero at `0x403368`, not an attacker-chosen index.
+No direct `0x30` object allocation was found in this build; other versions
+and indirect routes remain open.
+
+All three versions have signed `.bin` containers on the test box, but this is
+**not** evidence they are the active versions in a particular boot. Calls
+within one TA invocation are synchronous; a later GCP ROP invocation cannot
+sample the middle of one of these ordinary routines without an independently
+established reentrancy/interleaving mechanism. None of these ten normal
+paths gives a stable, live second-client object suitable for a controlled
+`0x109A` disclosure test. This does **not** exclude other signed TAs, atypical
+error paths, nested calls, or handles intentionally retained across requests.
+
+Function boundaries missing from the IDBs were defined only on temporary
+copies `/tmp/hdcp52_lifetime.elf` and `/tmp/opm51_lifetime.elf` for decompilation;
+MERIT's three call/free sites were checked from signed `.46` disassembly
+without defining the two missing routine boundaries. The source signed
+images and original IDBs were not saved or patched. Next
+choose a *different* client with a demonstrably retained object and prove its
+content and lifetime before any card read; do not re-label freed heap residue
+as a live cross-client key.
diff --git a/fw/AUDIT-DTM19-ASD100-TYPE1-PRODUCER.md b/fw/AUDIT-DTM19-ASD100-TYPE1-PRODUCER.md
new file mode 100644
index 0000000..7a68cf1
--- /dev/null
+++ b/fw/AUDIT-DTM19-ASD100-TYPE1-PRODUCER.md
@@ -0,0 +1,33 @@
+# Signed DTM `.19` host commands 2/4 produce ASD `0x100` descriptors
+
+**Static signed-client provenance; no card command, accepted live
+channel, or demonstrated second-client effect.** DTM
+`dtm_18.0.4.19_376639d1.elf` command entry at `0x401058`
+requires a buffer size of at least `0x50` and dispatches command IDs
+2 and 4 to `0x40112E` and `0x40118C`. Both send service-2
+`SVC 0xF2`, opcode **`0x100`**, through signed wrapper
+`0x4010FC..0x401116`. The wrapper's name in some decompilation is
+`dtm_sysdrv_rpc_100`, but its **service ID is 2 (ASD), not SYS_DRV**.
+
+For either command, `req[1]!=0` selects the update path; `req[1]==0`
+selects ASD `0x101` removal. On update, DTM checks **only**
+`req[9] <= 0x17` before marshalling a local 64-byte descriptor.
+Raw cmd-2 instructions `0x401168..0x40117A` copy `req[2..6]`
+into the descriptor's first five dwords, `req[7..8]` to the next
+two dwords and bounded `req[9]` to the next field; the remainder
+is zeroed. Cmd 4 similarly copies `req[2..]` and normalizes
+`req[13]` to 0/1/2. In both, **descriptor word 0 comes from
+`req[2]`** and the channel from `req[0]`, forwarded to ASD.
+The ASD `0x100` leaf performs its own channel and pointer validation.
+This is a signed-client **producer of a caller-provided type-1
+(`req[2]==1`) descriptor**, not evidence that a real display/fabric
+accepts such a descriptor or that a driver sends this combination.
+
+This narrows provenance for
+`fw/CANDIDATE-GCP-ASD-100-ERROR-RETURN-ACTIVE-RECORD.md` and
+`fw/CANDIDATE-HDCP57-ASD1A1-IGNORED-ENTROPY-FAILURE.md`:
+a signed host-facing DTM path can request the syntactic type-1
+record, but the active build, legitimate host input, ASD callback
+status, slot-770 gate, hardware use and protected victim remain
+unverified. DTM's host-facing buffer gate is **not** an ASD field
+policy or a restoration oracle. No live command was sent.
diff --git a/fw/AUDIT-GCP-ASD-20B-PRIVATE-TARGET-PROVENANCE.md b/fw/AUDIT-GCP-ASD-20B-PRIVATE-TARGET-PROVENANCE.md
new file mode 100644
index 0000000..baf8b4f
--- /dev/null
+++ b/fw/AUDIT-GCP-ASD-20B-PRIVATE-TARGET-PROVENANCE.md
@@ -0,0 +1,59 @@
+# ASD `.163` `0x20B`: candidate private target and mapping limits
+
+**Read-only static/model follow-up, not a live ASD-private store.**
+The existing signed-code defect and two GCP-owned hardware target-swap
+controls are in `fw/CANDIDATE-GCP-ASD-20B-UNCHECKED-OUTPUT-STORE.md`.
+This follow-up asks whether the synthetic target `0xD4AF00` is a
+measured writable private word and whether the Boolean output has a
+restorable effect. The answer to both is **not yet established**.
+
+* `readelf -Wl` on the signed `.163` ELF shows one declared RWE LOAD
+ interval **`0xD00100..0xD29100`**, with equal file and memory sizes.
+ The Boolean source `0xD1BA28` and `0xD29080` lie inside it;
+ synthetic target **`0xD4AF00` lies outside it**. ELF flags do not
+ establish current card PTEs. A scan of exact-address literals in
+ the signed ASD image found no direct `0xD4AF00` reference; indirect
+ allocation/array access was not excluded. An emulator-planted word
+ there is not a known disposable ASD variable.
+* Raw signed `sub_D02664` (`0xD02664..0xD02686`) returns **1 for every
+ nonzero** value of `*0xD1BA28`. It only invokes the optional callback
+ when the value is `0xFF`; output 0 needs the state to become zero.
+ The earlier fresh-boot card read measured state **1**, hence the
+ tested `0x20B` call's output was **1** and the callback was skipped.
+ The request does not choose 0 versus 1. Calling `0x20B` again at
+ that observed state cannot restore a word changed from 0 to 1.
+ There is no established harmless ASD-private 0→1 target plus an
+ independent full-effect restoration oracle.
+* `python3 psp_emu/harness/probe_asd20b_model_pte.py` (full-system
+ signed sOS loader with ASD loaded before GCP; **no hardware**) exited
+ zero. At the first ASD block, a generic TTBR0 walk mapped
+ `0xD1BA28`, `0xD29080`, `0xD39834` and `0xD4AF00` with model
+ small-page AP=3/APX=0; `0xD4AF00` translated to model PA
+ `0x04299F00`. At the first GCP block the **same generic TTBR0**
+ still translated `0xD4AF00` to the **same** PA, while GCP's own
+ `0x41061C` acquired a separate translation. Thus this generic
+ emulator view **cannot establish cross-client isolation** and is
+ not a silicon PTE dump. A preliminary attempt to walk sOS `.54`
+ `sub_6D84 → sub_4350`'s process-indexed L2 pointer produced zero
+ for both sampled process indices (ASD 5 and GCP 6) at those hook
+ points; it did **not** validate actual process-specific permission
+ bits. Subsequent signed sOS `.54` analysis explains the missing
+ link: `sub_6D84` selects `sub_4350(pid)` for `0xD00000..0xDFFFFF`,
+ and `sub_4350` reads process record `+92` as its L2 pointer.
+ `sub_CA8` writes that field **only after** its mapping/setup
+ succeeds, via sOS `sub_59E8` case 103 (`SVC 0xB8`). A shared
+ generic TTBR0 walk cannot substitute for this indexed table;
+ the full-system sample did not capture a populated indexed L2.
+ Isolated TA emulation also leaves unrelated `SVC 0xB8`
+ unhandled/default-success, so it cannot establish the real
+ loader's mapping. No content of the candidate targets was printed.
+
+Current verdict: the missing-pointer validation is real, and the
+signed handler demonstrably stores at selected GCP-owned destinations
+on hardware. The modeled `0xD4AF00` page and ELF RWE metadata **do not**
+justify a hardware private-target attempt: its live mapping, owner,
+initial value, benign effect and exact restoration are unknown. No
+new card request or live private write was made. An actual read-only
+sOS/ASIC-specific mapping oracle, or a separately identified harmless
+ASD-private Boolean target and restoration protocol, is needed before
+any stronger claim.
diff --git a/fw/AUDIT-GCP-ASD403-49007A00-TRANSFER-SLOTS.md b/fw/AUDIT-GCP-ASD403-49007A00-TRANSFER-SLOTS.md
new file mode 100644
index 0000000..fe6282e
--- /dev/null
+++ b/fw/AUDIT-GCP-ASD403-49007A00-TRANSFER-SLOTS.md
@@ -0,0 +1,35 @@
+# Offline triage: could `0x403` write the PSP transfer-slot descriptors?
+
+**Status: signed-code target lead, not a live DMA or protection-bypass result. No new device request.** Do not write this block to test an opcode/status: it may hold *live* transfer/protection slots and there is no independent restoration oracle. The proven GCP→ASD `0x403` write is only established at two benign scratch addresses, not at this block.
+
+## A specific PSP-side target, unlike host-programmable LSDMA
+
+Signed SYS_DRV `.54` `sub_E218FC` computes `0x49007A00 + 24*slot + field`, checks the offset `<0x180`, and calls **`SVC 0x7C` width 4**. The matching `sub_E15EF0` calls **`SVC 0x7B` width 4** at the same indexed addresses. `sub_E1447C` calls `sub_E17EF4` to find/own a free slot, then writes start-page (`+0`), inclusive end-page (`+4`), mode/active bits (`+8`) and parameter (`+12`) for selected region classes. For class `0x31` it reaches all four writes. The owner/overlap table and slot index are **software gates** on the SYS_DRV route; GCP→ASD `0x403` does not invoke them. In sOS `.54`, `sub_6D20`'s address exclusions do **not** cover `0x49007A00`, but guard allowance is not proof of endpoint decode or requester acceptance.
+
+The signed `.54` class switch at `sub_E1447C:0xE1454E..0xE1462C` **does not put the caller's region ID or an arbitrary source pointer directly into descriptor `+12`**. Representative cases before the final `sub_E218FC(slot, 8, mode)` and `sub_E218FC(slot, 12, parameter)`:
+
+| region class | `+8` mode | `+12` parameter |
+| --- | --- | --- |
+| `0x31`, `0x32` | `0x37` | fixed `0x30038` |
+| `0x33` | `0x37` | fixed `0x200038` |
+| `0x53` | `0x37` | fixed `0x70038` |
+| `0x68` | `0x37` | fixed `0x3F0038` |
+| `0x54` | `0x35` | fixed `0x70038` |
+
+The class switch admits additional modes and two auxiliary fixed `SVC 0x7C` stores; this is not a complete instruction-to-class table. In the signed `.54` direct xrefs to the bounded slot reader `sub_E15EF0`, **all six callsites** in `sub_E17EF4` and `sub_E13ABC` select only offsets `+0`, `+4` or `+8`; the eight direct xrefs to writer `sub_E218FC` include **`+12` writes but no signed `+12` readback through that helper**. This is not an exhaustive survey of every possible register reader, but it leaves the descriptor parameter's preimage and exact restoration unresolved even if a slot index were known. **If** the hardware interprets `+12` as a source or access-domain selector, a direct chosen fabric write could escape this signed software fixed-value set. Its actual semantics, accepted encodings and side effects are unknown; the repeated `...0038` shape is not a proof that it is a PSP physical address. In fact the **Navi22-only** `~/nv22_a0_memmap.txt` calls numeric `0x00030038` `GC_CP.CP_NUM_PRIM_NEEDED_COUNT1_LO` (an aliased graphics counter), **not** a SPI source. That name cannot be projected onto Navi31 but rules out treating the number alone as proof of a source pointer. Do not program it for a status check.
+
+On a prior stock `.54` card, free SYS_DRV `0x105D` reached its leaf but returned `0xFFFF000F` before those descriptor writes (`fw/DIFF-SPIROM_XFER-51-VS-54-TMR-FIX-SCOPE.md`). Its allocator `sub_E17EF4` returns that value for either a failed `SVC 0x7B` read or no free slot. Signed sOS `.54`'s `SVC 0x7B` case validates the destination and calls `sub_4730`; for an admitted width-4 read `sub_4730` returns 0 after mapping and loading, while an unmapped bus target might instead fault/stall. A full 16-slot table is therefore plausible, **not measured**; do not reclassify the clean `0xFFFF000F` as proof of PSP hardware denial. Writing over an occupied slot could disrupt another active client.
+
+### Host-only readback is not an oracle for these slots
+
+A narrowly bounded **read-only host SMN-window** check (standard `PCIE_INDEX2/DATA2`, not a PSP or DMA-register write) queried slot-0 `+8` at `0x49007A08` twice and slot-3 `+8` at `0x49007A50` once. All returned their **byte-swapped address mirrors** (`0x087A0049` twice; `0x507A0049`), interleaved with bogus `0x0FEEDC00 → 0x00DCEE0F` and live MP0 control `0x03810ACC → 0x80000000` before/after. One DF IH message appeared after the run; it has not been causally attributed to a particular read. This establishes **no host-SMN slot value**, not a hardware-zero or a PSP-fabric denial. There is no independent host readback/restoration oracle for slot writes on this card; **do not broaden the host survey or write these addresses** on the strength of mirrors/status.
+
+## Correct a consequential `SVC 0xA1` label
+
+Both signed sOS `.51` (`sub_5A0C`, case 80) and `.54` (`sub_59E8`, case 80) implement `SVC 0xA1` as **three stores to sOS global range/bounds words** (`.54` xrefs via `off_6440`/`off_6444`, as scoped in `fw/LEAD-GCP-SYSDRV-101E-OWNER-BYPASS-TEARDOWN.md`). There is no DMA kick in either case. SYS_DRV `.54` `sub_E142A0` invokes `SVC 0xA1` only **after** successful `sub_E19118` calls have written the fixed descriptor block for several classes; its `sub_E1447C`/`0x105D` path does **not** invoke `0xA1`. Earlier prose in `fw/DIFF-SPIROM_XFER-51-VS-54-TMR-FIX-SCOPE.md` and `psp_out/VULN-CONFIRMED-TMR-RANGE-ROLLBACK.md` described `SVC 0xA1` as a DMA “commit” and inferred `0x105D` was inert because it lacked that SVC. **That rationale is wrong.** It does **not** follow that descriptor writes alone execute a copy: the signed code may stage a protection window, a command may be elsewhere, and the `.51` host-observed `0xFF` striped memory after SETUP_TMR does not isolate which instruction caused it. Retain the independent `.51` observation and the `.54` post-boot allocator failure; retract only the unsupported causal/negative inference.
+
+The `.54` SETUP_TMR `sub_E142A0` also calls `sub_E2136C` and `sub_E212DC` before slot writes. These are **range/overlap checks** (the latter wraps two fixed-range `sub_E0F2F0` checks), not a proven DMA commit. `sub_E19118` constructs the destination from its stored base plus offset and calls `sub_E1447C`; whether the peripheral acts when its control/parameter words are written is a **hardware-semantic unknown**.
+
+## Boundary to a useful effect
+
+To upgrade this from a target lead requires all of: (1) identify a *free* slot and the engine's operational state without destructively overwriting live entries; (2) show that ASD's width-4 fabric access with its window attribute (the demonstrated `R3=12`, encoded as `0xCC`) is accepted like SYS_DRV's access, rather than assuming equal requester/target permissions; (3) identify the actual copy trigger, source, and destination address domains; and (4) independently read back a benign target and exactly restore every touched slot. No such evidence exists. This is **not** an arbitrary PSP RAM write, a post-boot TMR bypass, or authorization for a card write.
diff --git a/fw/AUDIT-GCP-ASD403-FABRIC-DMA-PIVOT.md b/fw/AUDIT-GCP-ASD403-FABRIC-DMA-PIVOT.md
new file mode 100644
index 0000000..25876c9
--- /dev/null
+++ b/fw/AUDIT-GCP-ASD403-FABRIC-DMA-PIVOT.md
@@ -0,0 +1,35 @@
+# Could the proven GCP→ASD `0x403` fabric write program a useful DMA copy?
+
+**Status: offline scoping only; no DMA/fabric card request, no verified memory copy.** The known primitive is a chosen 32-bit target/value write at two independently read-back scratch fabric endpoints (`fw/EVAL-GCP-TO-ASD-0x403-KERNEL-WRITE.md`, Updates 13–14). The register namespace is not CPU-MMU RAM; even an address numerically equal to a translated CPU physical address did not produce a CPU-RAM readback change. The effective DMA engines, their address domains, decoded Navi31 registers and requester privileges are separate questions.
+
+## Candidate MPDMAC: the available map does not expose a copy descriptor
+
+The only locally available named map is `~/nv22_a0_memmap.txt`, **Navi22, not the Navi31 card**. Its entire `MP_MPDMAC` family is just **three** 32-bit entries:
+
+| NV22 fabric address | name |
+| --- | --- |
+| `0x03A71000` | `DMAC_ACC_VIOLATION_LOG_ADDR` |
+| `0x03A71004` | `DMAC_ACC_VIOLATION_LOG_STATUS` |
+| `0x03A71008` | `DMAC_MISC_CTRL` |
+
+There is **no documented source, destination, transfer length, descriptor-base or doorbell register** for `MP_MPDMAC` in this map. Thus calling `0x03A71000` a configurable *copy engine* was an over-inference from its block name. It is outside sOS `.54`'s three explicit protected ranges, but that says nothing about Navi31 decode, the fabric requester, actual register function, or safety. Host-side NV22-map probe notes report `0/16` decoded-looking MPDMAC reads (`psp_out/NV22-MEMMAP-MINED.md`); that does **not** establish PSP-side denial, nor license a PSP-side write. Do not target its control/status registers for a speculative effect.
+
+## New ASIC-specific lead: LSDMA 6.0.0 PIO copy
+
+Unlike the Navi22 MPDMAC guess, the healthy Navi31 card's recorded IP discovery table lists **LSDMA 6.0.0**. Upstream Linux's LSDMA6 driver contains an actual source/destination/length/command PIO-copy sequence, so this is a concrete **offline copy-engine candidate** (`fw/LEAD-GCP-ASD403-LSDMA6-PIO-COPY.md`). The preserved host-SMN survey script copies discovery LSDMA bases `[0x11400,0x2456800]`; Linux header offsets plus the first base yield BAR5 PIO source register **`0x451A4`**, command **`0x451B4`** and status **`0x450C8`**. These are *host BAR5* offsets, **not identified PSP-fabric addresses**. Later host-only reads confirmed twice-stable BAR5 LSDMA ID `1` at `0x450D0` and version `0x600` at `0x450D4`; standard host `PCIE_INDEX2/DATA2` SMN reads of **those same numeric addresses** matched after bogus-mirror and live-MP0 interleaved controls. No DMA command was read or written. A later attempted PSP-side read of the ID yielded **no ASD result**: GCP FE0A faulted at the same memcpy PC/FAR as the previously failed log-gate ROP chain; card ATX recovery and signed load/FE07/unload controls passed (`fw/LEAD-GCP-ASD403-LSDMA6-PIO-COPY.md`). Do **not** retry that chain without independently resolving its params-VA mapping. The old SMN survey tested raw discovery bases rather than these per-register byte addresses and returned mirror/alias/dead; **PSP-side** decode and PSP-memory reach remain unestablished. Do not program it on the card without a verified benign source, destination, readback and restoration plan.
+
+## PSP transfer-slot register candidate: `0x49007A00`
+
+Signed SYS_DRV `.54` accesses the 16-slot `0x49007A00 + 24*slot` block through sOS `SVC 0x7B/0x7C`. That is a more relevant *potential* PSP-requester-only target than LSDMA if its descriptor controls a copy and accepts ASD's requester. Its SYS_DRV allocator/owner check is not part of the GCP→ASD `0x403` write. But slots may be live, register acceptance and exact restore are unknown, and no direct endpoint effect was tested. Crucially, signed sOS `.51` and `.54` `SVC 0xA1` merely stores range/bounds globals: older prose saying `0x105D` is safe/inert because it lacks a DMA “commit” was wrong. Neither the actual trigger nor a benign free slot is known. See `fw/AUDIT-GCP-ASD403-49007A00-TRANSFER-SLOTS.md`; **do not write these descriptors on the card**.
+
+## A separately real descriptor path: SYS_DRV free `0x100E/0x100F`
+
+Signed SYS_DRV `.54` constructs engine-5 CCP PASSTHRU descriptors from two caller pointers translated by sOS `SVC 0x79` and a chosen output length. Signed dispatch only validates the *declared* input length and does not demand `input_declared >= output_length`. An isolated connected signed-dispatch **emulator CCP model** copied fully planted 64-byte input even when its declaration was 4 bytes (`fw/CANDIDATE-GCP-SYSDRV-100E-100F-SECOND-INPUT-SPAN.md`). This is a more concrete potential DMA-related primitive than guessing MPDMAC registers, **but it does not depend on the ASD fabric write**. There is no card-side cross-PTE copy, independent victim, or successful real CCP job in this record. sOS `.54` additionally excludes the CCP fabric register window `[0x0CB00000,0x0CB10000)` for the relevant caller type, so using ASD `SVC 0x7C` simply to reprogram those CCP MMIO registers is not supported (`psp_out/FINDING-SOS-CCP-WINDOW-FIXED-IN-54.md`).
+
+## Fabric attribute source is narrower than an arbitrary fourth parameter
+
+The signed ASD `.163` `0x403` leaf at `0xD022E0` sets `R3 = 12 * count` at `0xD02382..0xD02388` and does not overwrite it on the matched width-4 branch before `SVC 0x7C` at `0xD023D8`. In the **demonstrated index-82 alias setup**, `0x100(0)` marks topology record zero active, hence the aliased halfword count is **1**, and `R3=12`. Signed sOS `.54` `sub_6F3A` passes that fourth register to `sub_3D8C(..., slot=0, attr=R3, ...)`; `sub_56EC` masks a nonzero attribute to `(R3 & 0x3f) | 0xc0`, here `0xcc`, while programming the 1-MiB fabric window. An additional signed-ASD `.163` check of the topology writer `sub_D0B66C` shows it **stores literal 1** at record `+4` before copying the validated 0x40-byte caller descriptor into later record fields. Thus changing the descriptor, target dword, or width in the existing index-82 seed sequence does **not** by itself select a new count/attribute. The topology global `off_D0BFF4` has 15 direct data references in eight signed functions; other indirect state changes were not exhaustively excluded. This is *not* evidence that GCP can choose an independent requester identity or disable target-side privilege checks by changing the data word. The separate 64-MiB SMN aperture requester-tag mechanism in `psp_out/ARCH-SMN-APERTURE-PRIVILEGE.md` must not be assumed to be identical to this 1-MiB window attribute.
+
+## Verdict and next defensible dependency
+
+The fabric write could become a DMA-programming primitive **only if** a Navi31 DMA endpoint is first identified from a trustworthy register specification or signed firmware producer, its copy descriptors and physical-address type are traced, and a benign effect plus exact restoration oracle is available. Reaching *any* new GCP→ASD request on card also requires resolving the repeated FE0A params-VA/memcpy fault. Bounded non-ROP FE0A comparators have now read **two exact signed GCP code words**, one unique in the ELF, in fresh ASD-first/GCP-SID-1 boots, strongly supporting the old params-VA hypothesis **for that setup** (`fw/LEAD-GCP-PARAMS-VA-NONROP-DISCRIMINATOR.md`). The reject/diagnostic branches can emit fixed MP1 PMI3 events. The prior faulted **SID-2** chain, any altered load order and its chosen-write *destination* mapping are still not independently resolved; do not replay the quarantined ROP script. A *different*, previously successful SID-1 ROP layout was subsequently revalidated in two fresh boots with same-session codeword calibration and used for a matched ASD `0x403` **PMI3 event-port** control (`fw/EVAL-GCP-ASD403-MP1-PMI3-EVENT-QUEUE.md`). The non-scratch pointer effect is real, but the identical event is host-MMIO accessible, not a DMA pivot or PSP-only advantage. None is in the three-entry NV22 MPDMAC map. LSDMA6 supplies an actual producer and host BAR5 offsets but still lacks a verified PSP-fabric base and PSP-memory reach; its host-programmable copy would not inherently gain the PSP requester's authority merely because the PSP wrote its registers. The `0x49007A00` slots are a more PSP-specific signed-code lead but have no safe restoration oracle. Meanwhile `0x100E/0x100F` already offer a signed CCP descriptor construction path without fabric write; resolve *real* GCP process PTE adjacency, queue state, and independent observable behavior before claiming it can read or write another client's memory. Unknown DMA/CCP/MPDMAC writes or resource setup on the live card are not warranted by this offline survey.
diff --git a/fw/AUDIT-GCP-ASD403-SCRATCH-CONSUMERS.md b/fw/AUDIT-GCP-ASD403-SCRATCH-CONSUMERS.md
new file mode 100644
index 0000000..e7bd73d
--- /dev/null
+++ b/fw/AUDIT-GCP-ASD403-SCRATCH-CONSUMERS.md
@@ -0,0 +1,9 @@
+# Can the verified scratch writes cause a downstream privileged action?
+
+**Offline bounded negative survey; no new card activity or useful effect established.** `fw/EVAL-GCP-TO-ASD-0x403-KERNEL-WRITE.md` independently verified ASD `SVC 0x7C` writes to host-visible fabric scratch `0x16C` and `0x3824`, then restored them. A downstream security-sensitive consumer would make that effect more valuable than a standalone scratch marker; a name alone cannot establish one.
+
+The available **Navi22-only** `~/nv22_a0_memmap.txt` labels `0x16C` `NBIFMM.BIOS_SCRATCH_15` and `0x3824` `NBIFMM.BIF_SCRATCH1`, both also listed as GPUHOST aliases. This naming is not a Navi31 functional specification. Upstream Linux's `nbio_v4_3.c/.h` (Navi31 discovery reports NBIO/NBIF 4.3.0; `psp_out/SMN-MAP-HEALTHY-CARD.md`) contain no direct `BIOS_SCRATCH` or `BIF_SCRATCH` symbolic use.
+
+A signed-instruction IDA mnemonic scan of sOS `.54` (20,088 instructions) and SYS_DRV `.54` (56,092) for immediate/literal `0x16C` or `0x3824` found only three uses of **offset `0x16C` inside a nonzero-base software structure**: sOS `0x14EDA/0x14EE2` in `sub_14E88`, and SYS_DRV `0xE1BB06` in `sub_E1BAB0`. They are *not* reads of numeric fabric `0x16C`. A literal little-endian 32-bit value scan over 144 local `psp_out/elf/*.elf` and `psp_out/versions_win/elf_all/*.elf` found no standalone `0x0000016C` or `0x00003824` dword. These are deliberately narrow scans: a computed address, a table of halfwords, other firmware, host code outside NBIO v4.3 or a hardware consumer can be missed. No security-sensitive consumer was identified, not a proof that none exists.
+
+Since these two words are also independently host-visible and host-writable, even a discovered host-side consumer would require a separate incremental-authority argument: a host actor who can already set the word would not gain a new ability by writing it from ASD. Do not treat observed scratch readback, a BIOS label or a guessed boot effect as the goal's useful fabric-write abuse.
diff --git a/fw/AUDIT-GCP-FREE-SYSDRV-100A-OUTPUT-SPAN.md b/fw/AUDIT-GCP-FREE-SYSDRV-100A-OUTPUT-SPAN.md
new file mode 100644
index 0000000..526345f
--- /dev/null
+++ b/fw/AUDIT-GCP-FREE-SYSDRV-100A-OUTPUT-SPAN.md
@@ -0,0 +1,29 @@
+# SYS_DRV `.54` free `0x100A`: caller output span is checked before clearing
+
+**Signed-static scope, no card/crypto completion.** This closes the
+first-level `memcpy`-label concern, not every possible indirect helper
+or real kernel page mapping.
+
+The role row at `0xE25B5C` is `{0x100A,2,0,0,0}`: the `(msg[2],msg[3])`
+pair is output-role and the dispatcher validates its **declared length**.
+`sub_E105A8` calls `sub_E041D4(caller_context,msg[2],msg[3])`.
+That leaf rejects `msg[3]<0x140` before its stores. After an optional
+one-time `sub_E07A00` initialization (whose crypto/fabric effect is
+not characterized), the success path clears exactly `msg[3]` caller
+bytes, copies 32 internal bytes to `msg[2]+0x100`, and writes a dword
+at `msg[2]+20`. Both fixed stores fit inside the required `0x140`
+bytes: the 32-byte copy ends at `+0x11f`, below `0x140`. There is no
+separately declared, shorter second output pair on this path.
+
+`sub_E0DEF4`, the dispatcher's type-5 window checker, bounds the
+pointer to `<=0x40000000` and length to `<=0x10000000` before its
+unsigned `base+length` comparison with the sOS `SVC 0xB5` window.
+Those two caps prevent **32-bit sum wrap** on this examined role-2
+route. Signed sOS `.54` `SVC 0xB5` is `sub_59E8` switch case 100
+(`0xB5-81`) and supplies process-indexed window bounds through
+`sub_27F8`; these static bounds do not independently measure GCP's
+actual PTE adjacency or guarantee a real crypto success.
+
+No short-declared output or wrap bypass was found for the signed
+`0x100A` route. Do not interpret the emulator's default-success SVCs
+or the static checks as a safe oversized hardware-test authorization.
diff --git a/fw/AUDIT-GCP-FREE-SYSDRV-100D-KDF-OUTPUT.md b/fw/AUDIT-GCP-FREE-SYSDRV-100D-KDF-OUTPUT.md
new file mode 100644
index 0000000..98aca97
--- /dev/null
+++ b/fw/AUDIT-GCP-FREE-SYSDRV-100D-KDF-OUTPUT.md
@@ -0,0 +1,26 @@
+# SYS_DRV `.54` free `0x100D`: scoped output-copy bound
+
+**Signed-static audit only; no hardware or successful modeled crypto.**
+The role row at `0xE25B84` is `{0x100D,2,0,0,0}`, validating the
+caller output pair `(msg[2],msg[3])`. `sub_E105A8` calls
+`sub_E07910`, which supplies a fixed in-image label to `sub_E07A00`.
+The label is NUL-terminated after 45 bytes, within the later
+0x80-byte scratch bound. The helper uses a separate fixed 32-byte
+in-image source for crypto setup; **do not print or identify its bytes
+as a device key**. No live validity/key provenance was established.
+
+After its crypto setup, `sub_E07A80` receives `msg[2]` as output
+pointer and `msg[3]` as requested byte count. It rejects NULL pointer
+or zero count. In each successful derived-block iteration it chooses
+`min(remaining_count,32)` and copies exactly that many bytes from its
+local 32-byte block to the caller, then advances and subtracts the same
+number; it stops when the requested count reaches zero. The examined
+copy therefore cannot exceed the *declared* first-pair length solely
+because the KDF block is 32 bytes. The fixed label is subjected to a
+separate length check before its copy into scratch.
+
+This does not verify CCP behavior, actual GCP/sOS PTE permissions,
+or confidentiality of a hypothetical derived value. The 32-byte
+setup source is static to the signed image; the signed-code path does
+not by itself establish device-unique material or a new cross-client
+write. No card probe or synthetic hardware-success claim was made.
diff --git a/fw/AUDIT-GCP-FREE-SYSDRV-1024.md b/fw/AUDIT-GCP-FREE-SYSDRV-1024.md
new file mode 100644
index 0000000..50edfab
--- /dev/null
+++ b/fw/AUDIT-GCP-FREE-SYSDRV-1024.md
@@ -0,0 +1,65 @@
+# GCP-reachable SYS_DRV opcode `0x1024`: signed region-registration path
+
+**Signed `.54` static audit plus one read-only hardware state comparison.
+No `0x1024` or `0x1056` request was issued on the card.** This corrects the
+old classification of `0x1024` as an inert stub; it has a substantial,
+conditional body. No arbitrary mapping or caller-owned CPU-RAM write is
+established here.
+
+## Dispatch and constraints
+
+SYS_DRV `sub_E105A8` accepts opcode `0x1024` (`case 4132`), fills internal
+request words `msg[14] = msg[2]` and `msg[15] = msg[4]`, then calls
+`sub_E11E5C(msg+14)`. Before dispatch, each nonzero request pointer in
+`msg[2],msg[4],msg[6],msg[8]` passes opcode-/field-specific
+`sub_E0AB44` and `sub_E0DEF4` range/length checks. The nested input
+structure is still user-supplied, but its outer pointer is checked.
+
+`sub_E11E5C` reads nested input fields at offsets `+4,+8,+12,+16`; the
+last field must name region type **13 or 58**. It invokes `SVC 0x66` for
+caller identity, validates/maps input through `sub_E07910` and
+`sub_E086FC`, requires `(length & ~0xF) >= 0x100C`, then uses privileged
+`SVC 0x6D/0x6C`, crypto (`sub_E0C3B8`, `sub_E03E78`, `sub_E1C85C`), and
+conditional region registration via `sub_E19118` (which sets the
+`0xEA658C` flag only after `sub_E1447C` succeeds). The branch selection
+and successful registration depend on actual mapped resources and valid
+crypto data, not merely selecting an opcode. Do **not** infer that a
+crafted untrusted blob can simply register arbitrary regions.
+
+The per-type offset for type 13 includes the runtime word at
+`0xE2649C` (writer: `sub_E12C44`, reached by free opcode `0x1056`). Its
+secondary offset uses unsigned `0x100000 - v11`; **this subtraction alone is
+not a demonstrated underflow vulnerability**. `v11` also contains
+`sub_E0BA84(13)` (at least 1 MiB and dependent on another runtime field),
+and the next calculation adds the result back to `v11`, potentially
+placing a second region at a deliberate fixed offset. Overlap/resource
+checks and hardware mapping effects were not bypassed or tested.
+
+## Targeted hardware state
+
+After an ATX cold cycle, signed ASD and GCP loaded with status zero and
+GCP session ID 1. Three read-only GCP-ROP RPCs read known ASD code
+`0xD013B8 → 0x2800B57C` as a control and, through SYS_DRV opcode
+`0x109A`, the adjacent mapped SYS_DRV words:
+
+* `0xE2649C → 0x00000000` (runtime offset for type 13);
+* `0xE264A8 → 0x00300000` (low word of the base previously examined for
+ `0x101E`).
+
+FE0A `0x240`, graceful marker `0x5A`, zero fault frame and final FE07 zero
+confirm completed reads, **not** any state-changing effect. The zero
+additional offset does not determine `sub_E0BA84(13)`'s value or prove that
+`0x1024` can succeed on this boot. Logs:
+`/root/psp/hw/sysdrv_1024_offset_{fresh_cycle,fresh}.log`; probe:
+`/root/psp/hw/gcp_rop_sysdrv_1024_offset_state.py`.
+
+A separate first-pass signed `0x1056` trace established that its leaf's
+`*a5` output is the fixed `msg[18]`, **not** a caller-selected nested
+pointer. It also confirms conditional privileged state writes, without a
+live effect or restoration oracle: `fw/AUDIT-GCP-FREE-SYSDRV-1056.md`.
+
+Next: finish the signed type-13/58 crypto and range validation trace if an
+actual signed caller or controlled emulator state makes registration
+reachable. A live `0x1024`/`0x1056` experiment would modify privileged
+mappings and is **not** justified without an effect oracle and a safe
+restoration plan.
diff --git a/fw/AUDIT-GCP-FREE-SYSDRV-1039-SOS6B-BLOCK.md b/fw/AUDIT-GCP-FREE-SYSDRV-1039-SOS6B-BLOCK.md
new file mode 100644
index 0000000..9b09419
--- /dev/null
+++ b/fw/AUDIT-GCP-FREE-SYSDRV-1039-SOS6B-BLOCK.md
@@ -0,0 +1,30 @@
+# Free SYS_DRV `.54` `0x1039`: chosen map path blocked by signed sOS `SVC 0x6B`
+
+**Current signed-build negative gate, not a hardware register-read
+finding.** The dispatcher passes caller scalar `msg[14]` to
+`sub_E13658`. In one initialization branch, if the scalar is nonzero,
+the leaf constructs a value from its bits and calls `sub_E086FC`
+with 64-bit high word `0xFFFE`, low word containing `0x10000000`,
+length 4, and **`a7=0`**. If that mapping completed it would read
+part of the mapped word and condition later state on it. This is a
+source/sink lead, not proof of a GCP-chosen working MMIO read.
+
+The signed `sub_E086FC` chooses **`SVC 0x6B`** when `a7=0`. Signed
+sOS `.54` `sub_59E8` case `107-81=26` calls `sub_3A04` with its
+fifth argument **zero**. `sub_3A04 → sub_3A84` passes that zero to
+the per-segment branch: after descriptor checks the function selects
+signed `sub_3DD8`, which unconditionally returns **9**, rather than
+`sub_3880`. Thus this current-build 0x6B mapping cannot succeed;
+it can also fail earlier for descriptor/resource reasons. This is the
+same sOS barrier that closed the distinct `0x1016` short-input route
+(`fw/CANDIDATE-GCP-SYSDRV-1016-SHORT-INPUT.md`). The later
+`sub_E13658` register-consuming path and its second mapping use the
+same `a7=0` branch. sOS `SVC 0x8B` is a **different** stateful
+route and must not be conflated with 0x6B.
+
+`sub_E13658` also has **earlier** private-state/status branches
+before this mapping attempt, including private flag updates; this
+negative map result does not prove the whole opcode inert or
+restorable. Natural branch predicates, state effects and caller
+policy remain open. No hardware request or synthetic forced-success
+SVC was performed.
diff --git a/fw/AUDIT-GCP-FREE-SYSDRV-1049-FIXED-REG-READ.md b/fw/AUDIT-GCP-FREE-SYSDRV-1049-FIXED-REG-READ.md
new file mode 100644
index 0000000..b3c03f2
--- /dev/null
+++ b/fw/AUDIT-GCP-FREE-SYSDRV-1049-FIXED-REG-READ.md
@@ -0,0 +1,18 @@
+# Free SYS_DRV `.54` `0x1049`: fixed-register diagnostic getter
+
+**Signed first-level audit; no new chosen-register primitive.**
+`sub_E105A8` dispatches this opcode to `sub_E0850C`, which takes no
+caller pointer. Raw signed `sub_E087B4` reads **fixed fabric target
+`0x10140338`** through `SVC 0x7B` and returns the read value's bit 0.
+The decompiler's `return 0` is misleading because the SVC writes to
+a local stack word. Only when that bit is one does `sub_E0850C`
+read a second **fixed** target `0x3ECE4`. If the second 32-bit
+register has its sign bit set, the opcode returns its low five bits;
+otherwise it returns `0xFFFF`. There is no caller-supplied address,
+buffer pointer or length in this leaf and no signed fabric **write**
+on the examined path. These `SVC 0x7B` targets must not be assumed
+to be CPU-MMU physical addresses.
+
+The two fixed register values, live gating and consumer semantics
+are unmeasured; a return of `0xFFFF` in a model would not establish
+how the second register behaves on Navi31. No card request was made.
diff --git a/fw/AUDIT-GCP-FREE-SYSDRV-1054-PER-CALLER-CRYPTO-SPANS.md b/fw/AUDIT-GCP-FREE-SYSDRV-1054-PER-CALLER-CRYPTO-SPANS.md
new file mode 100644
index 0000000..637e52d
--- /dev/null
+++ b/fw/AUDIT-GCP-FREE-SYSDRV-1054-PER-CALLER-CRYPTO-SPANS.md
@@ -0,0 +1,27 @@
+# Scoped free SYS_DRV `.54` `0x1054` input/output and caller index
+
+**First-level signed-code audit, not CCP/hardware completion.** The
+signed dispatcher maps free `0x1054` to `sub_E2167C(msg[2],msg[3],
+msg[4],msg[5],caller_index)`. Its role row at `0xE25E54` is
+`{0x1054,1,2,0,0}`: the caller input and output pointer pairs are
+validated according to their declared spans. The caller index is the
+signed-dispatch `v57=a2` value supplied by sOS, not the caller's
+`msg[14]` scalar.
+
+`sub_E2167C` first calls `sub_E0E7B8(caller_index)`, which rejects
+indices `>=32`, checks that that index's record is active, and
+conditionally processes that record's crypto state (including a
+possible `record+65=1` update on successful internal crypto). **This
+routine runs before the exact output-length test**, so an otherwise
+invalid `msg[5]` need not imply no per-caller side effect; natural
+activation and crypto success have not been demonstrated. The leaf
+then requires **`msg[5]==32`** before calling `sub_E0C3B8` with the
+private per-index 32-byte input at `dword_E216C4 + 96*index + 16`;
+the request's validated `(msg[2],msg[3])` is forwarded as a *separate*
+crypto descriptor input with its actual declared length, and the
+request's `(msg[4],32)` is the output. There is no signed fixed
+32-byte read from the caller input when `msg[3]` is shorter than 32
+on this inspected path, nor a nested caller-selected index to address
+another TA's crypto slot. CCP engine completion, record activation and
+sOS type-5 PTE behavior remain outside this audit. No card request or
+modeled CCP success is claimed.
diff --git a/fw/AUDIT-GCP-FREE-SYSDRV-1056.md b/fw/AUDIT-GCP-FREE-SYSDRV-1056.md
new file mode 100644
index 0000000..c13465e
--- /dev/null
+++ b/fw/AUDIT-GCP-FREE-SYSDRV-1056.md
@@ -0,0 +1,9 @@
+# SYS_DRV `.54` free opcode `0x1056`: scoped registration-state trace
+
+**Signed static review only; not invoked on hardware or in a connected emulator.** This closes an incorrect shortcut from the leaf's `*a5` store to a claimed caller-selected arbitrary write. It does **not** establish that the remaining crypto/parser path is safe.
+
+`sub_E105A8` dispatches decimal case 4182 (`0x1056`) directly to `sub_E12C44(msg[14],msg[15],msg[16],msg[17],msg+18)` at `0xE12C44`. Therefore the leaf's `*a5 = ...` stores into the fixed message word **`msg[18]`**, not through a nested output pointer supplied as `msg[18]`. This is distinct from ASD `0x20B`'s unchecked nested pointer. The exact enclosing message mapping and sOS caller-window properties are separate from this leaf-level fact.
+
+The leaf requires `msg[16] > 0xFF`; calls `sub_E0850C`, then `sub_E086FC` for the supplied region (page rounding/overflow handling and an `SVC 0x8B` mapping path), and only on successful mapping/result enters `SVC 0x79` and `sub_E20D7C(..., msg[16], ...)`. Its successful path derives an aligned value, writes it to `msg[18]`, and conditionally calls `sub_E18F3C`, writes the runtime type-13 offset at `0xE2649C`, updates another SYS_DRV global, marks a state byte, and calls `sub_E0A644`. None of these state changes has an established live restoration oracle. The card's `0xE2649C` was previously observed as zero in a **read-only** fresh-boot comparison (`fw/AUDIT-GCP-FREE-SYSDRV-1024.md`); this does not prove `0x1056` success.
+
+The nested `sub_E20D7C` uses a 1024-byte aligned stack area for four 256-byte records. Its `sub_E0DFE4` loop caps the record index at four, and `sub_E0F9F0` checks parsed record lengths against its supplied bound with explicit carry checks. These *selected* bounds neither prove overall parser safety nor justify treating `msg[16]` as capped to a fixed small limit. The leaf's gating, parser, `SVC 0x79`, and conditional registration must be modeled together before any impact claim; no `0x1056` or `0x1024` hardware request is justified solely by this review.
diff --git a/fw/AUDIT-GCP-FREE-SYSDRV-1071-1074-IDENTITY.md b/fw/AUDIT-GCP-FREE-SYSDRV-1071-1074-IDENTITY.md
new file mode 100644
index 0000000..b868f02
--- /dev/null
+++ b/fw/AUDIT-GCP-FREE-SYSDRV-1071-1074-IDENTITY.md
@@ -0,0 +1,18 @@
+# SYS_DRV `.54` free `0x1071..0x1074`: bounded identity-table audit
+
+**Signed-code review only. No request on the card.** This traces the four related operations below the reachable high-opcode dispatcher, rather than treating a global table as proof of cross-client teardown. Live table occupancy, active consumers, and persistence remain unknown.
+
+`sub_E105A8` passes its second (sOS-supplied caller) argument `v57` to all four leaves. It hard-codes **type 2**, rather than allowing a request to choose type 1:
+
+| Opcode | Dispatch | Signed leaf and effect |
+|---|---|---|
+| `0x1071` | `sub_E199D8(v57,msg+14,0,2)` | Allocates an 8-byte table record and a 16-byte identity entry; writes the new record index to fixed `msg[14]` only after storage succeeds. Uses `SVC 0xA7` to obtain the identity for `v57`. |
+| `0x1072` | `sub_E198E0(v57,msg[14],0,msg+15,2)` | Requires index `<64`, active type 2, and a match between `SVC 0xA7` identity and the record's stored identity before returning its reference word to fixed `msg[15]`. |
+| `0x1073` | `sub_E1962C(v57,msg[14],0,msg[15],2)` | Adds an equality check on the request's reference word before updating that record. |
+| `0x1074` | `sub_E19408(v57,msg[14],0,2)` | Releases either one identity-matching record or, for index `0xFFFFFFFF`, all records for the **same** identity. This is state-changing; do not invoke merely for a status. |
+
+For the same signed sOS `.54` build, `SVC 0xA7` dispatches to `sub_2C0C` (`0x2C0C`): after checking that the requested process index is active (`sub_1978`), raw instructions at `0x2C1A..0x2C2C` copy **16 bytes from PCB base + `96*index+0x4C`** into SYS_DRV's output buffer. This is a *process-indexed identity*, not evidence of a secret or device-bound key. It does not itself ensure that the requested index equals the current caller; on this route SYS_DRV supplies the dispatcher-provided caller index. Changing that index via an unproven alternate route would change the analysis. No GCP/HDCP identity collision has been measured.
+
+The allocation table has a high-water count and capacity 64. `sub_E199D8` appends until the count reaches 64; at capacity it scans inactive records of the same type for reuse. Raw `0xE19A3C..0xE19A40` compares a fixed nonzero error constant (`0x80000A01`) against zero and branches to the error path if no slot is found; **it does not dereference slot 64 on the full/no-reuse path** despite misleading pseudocode. `sub_E195B4` used for bulk release lists records with matching stored identity, and the bulk loop acts on those indices. The type-2 identity table's high-water count is intentionally retained as slots become reusable; that alone is not exhaustion or an OOB access.
+
+**Residual questions:** the actual PCB identity population/uniqueness, whether signed clients create retained live type-2 records, storage failure atomicity, and whether any request path can substitute a foreign process index for `v57`. Nothing here establishes a cross-client deletion, an arbitrary read/write, or a restorable card experiment.
diff --git a/fw/AUDIT-GCP-FREE-SYSDRV-1081-ZLIB-OUTPUT-BOUND.md b/fw/AUDIT-GCP-FREE-SYSDRV-1081-ZLIB-OUTPUT-BOUND.md
new file mode 100644
index 0000000..24b89c7
--- /dev/null
+++ b/fw/AUDIT-GCP-FREE-SYSDRV-1081-ZLIB-OUTPUT-BOUND.md
@@ -0,0 +1,32 @@
+# SYS_DRV `.54` free `0x1081`: decompression limit is programmed from output declaration
+
+**Signed-static + emulator-model interpretation, not a successful live
+CCP operation.** The role row at `0xE25ECC` is `{0x1081,1,2,0,0}`:
+the caller's `(msg[2],msg[3])` is input and `(msg[4],msg[5])` is
+output, both subject to the dispatcher's declared-span checks.
+`sub_E105A8` calls `sub_E11B00` with those four fields and an inline
+`msg[14]` status destination.
+
+The signed leaf requires both pointers and output length to be
+32-byte aligned, translates the output then input pointer through
+`sOS SVC 0x79`, builds a 32-byte CCP descriptor with the **input
+length** from `msg[3]` (`sub_E03FC4` mode 9), and calls
+`sub_E05284(msg[5],0)` before enqueueing the job. `sub_E05284`
+writes `msg[5]` to SYS_DRV's CCP register block `+0x4020` and zero
+to `+0x4024`. The descriptor control value is `0x0260001A`, engine
+ID 6 by the existing model's bit-20..23 decoder; that model treats
+engine 6 as raw-DEFLATE **ZLIB decompression** and these registers as
+`Decompression0_Limit_Lo/Hi`. Its `_zlib` routine rejects decoded
+outputs larger than the programmed limit. The signed routine does
+**not** itself compare compressed input length with decompressed output
+length; for decompression that would not be a meaningful bound.
+
+Accordingly, a short-declared output is **not** evidence of an
+out-of-bounds write here: the signed code appears to program a
+hardware output limit from the same length the dispatcher validated.
+A claim of actual hardware containment still requires Navi31 register
+semantics and a real completion result; the emulator's register names
+were identified from a Navi22 map and are **not** a measurement of
+this card. The register block is process-local to SYS_DRV, and no
+second-client effect from a retained limit was established. No
+compressed-data hardware probe or oversize-mapping probe was made.
diff --git a/fw/AUDIT-GCP-FREE-SYSDRV-1085.md b/fw/AUDIT-GCP-FREE-SYSDRV-1085.md
new file mode 100644
index 0000000..dddda0f
--- /dev/null
+++ b/fw/AUDIT-GCP-FREE-SYSDRV-1085.md
@@ -0,0 +1,30 @@
+# SYS_DRV `.54` free `0x1085`: scoped 32-byte crypto-output path
+
+**Signed-static scope only.** This narrows a high-value `memcpy` row; it
+is not a successful crypto operation, hardware output, device-key claim,
+or assurance about unrelated modes.
+
+The signed role row at `0xE25EF4` is `{0x1085,2,0,0,0}`: the first
+caller pair is an output-role pointer and its **declared** size is
+validated at dispatch. `sub_E105A8` calls `sub_E12870(msg[2],msg[3])`.
+The leaf additionally requires nonnull output and **exactly 32 bytes**
+before its crypto attempt. It constructs eight input bytes from
+SYS_DRV-private state at `0xE5FA48+880`, obtains the signed sOS `SVC
+0x66` result, and calls `sub_E0C2B0` with fixed 8-byte input and
+32-byte local output. The latter drives SYS_DRV's normal object/session
+and opcode-`0xD` crypto routines at that fixed small count; this is
+**not** an attacker-selected opcode-`0xD` oversized length. Only after
+crypto returns zero does the examined path attempt to copy 32 local
+bytes to the checked caller output. `SVC 0x66` is signed sOS `.54`
+`sub_59E8` case 21 (`0x66-81`), which returns a sOS process-index byte
+from its current context, not a free caller-provided scalar.
+
+No short-declared 32-byte output is established on this route: a four-byte
+declaration passes the dispatcher pair check but fails the leaf's exact
+32-byte test before crypto/copy. The source data's provenance and the
+cryptographic hardware behavior are not established. Do not print
+possible key material, run it on the card solely for a return value, or
+infer that sOS process indices are controlled by GCP's message. This
+free path may expose a fixed-size derived result if successful, but the
+already hardware-verified free `0x109A` SYS_DRV-private guard read is a
+separate, stronger confidentiality primitive.
diff --git a/fw/AUDIT-GCP-FREE-SYSDRV-10A3-10A4-MAILBOX-STATUS.md b/fw/AUDIT-GCP-FREE-SYSDRV-10A3-10A4-MAILBOX-STATUS.md
new file mode 100644
index 0000000..c7dc9cb
--- /dev/null
+++ b/fw/AUDIT-GCP-FREE-SYSDRV-10A3-10A4-MAILBOX-STATUS.md
@@ -0,0 +1,33 @@
+# SYS_DRV `.54` free `0x10A3`/`0x10A4`: finite mailbox exchanges and error-state flag
+
+**Scoped signed dispatch + modeled map failure; no hardware mailbox
+request.** Both opcodes have inline outputs, not unvalidated caller
+output pointers. `0x10A3 → sub_E12670` zeroes its inline result bytes,
+then issues fixed mailbox command 29 through `sub_E18364` with a
+**finite `0x1388` timeout**. It sets the SYS_DRV-private byte
+`0xE25844` from response bit 1 **regardless of the mailbox status**;
+when the response is zero and the map fails, the prior value 1 is
+cleared although the function returns an error. If a successful
+response has bit 0 set, the leaf additionally calls `sub_E15DBE` to
+query a bounded status and update the inline result.
+
+`psp_emu/harness/probe_sysdrv_10a3_error_flag_clear.py` passed on
+signed `.54` dispatcher/leaf instructions: it planted **synthetic**
+`0xE25844=1`, modeled only `SVC 0x7D` returning NULL, reached
+`sub_E12670`, observed return `0xFFFF000C`, and read back the byte
+at zero. Default-success handlers for unrelated SYS_DRV initialization
+SVCs remain a material emulator limitation; no live flag or device
+response was measured.
+
+The only direct signed-image literals to `0xE25844` are this writer
+(`0xE126B4`) and `0x10A4 → sub_E11A2C`'s reader (`0xE11A64`).
+`0x10A4` writes an inline byte 1 and returns fixed `0xFFFF0000`
+unless that flag is nonzero; with the flag it also calls
+`sub_E0A288` and then sends fixed command 30 through
+`sub_E18364` using a **finite `0x3E8` timeout**. Clearing the flag
+on a failed command 29 therefore disables the examined command-30
+path, which may be deliberate **fail-closed** behavior, not an
+adversarial privilege gain. Exact live mailbox mapping, flag
+initialization, indirect consumers and any second-client effect
+remain unproven. Neither opcode should be invoked on the card just
+for a status code.
diff --git a/fw/AUDIT-GCP-FREE-SYSDRV-4013-4015.md b/fw/AUDIT-GCP-FREE-SYSDRV-4013-4015.md
new file mode 100644
index 0000000..5b28963
--- /dev/null
+++ b/fw/AUDIT-GCP-FREE-SYSDRV-4013-4015.md
@@ -0,0 +1,23 @@
+# Static follow-up: GCP-reachable SYS_DRV 0x4013–0x4015
+
+**Evidence level: signed SYS_DRV `.54` disassembly only. No hardware opcode
+0x4013/0x4014/0x4015 was invoked.** These three cases sit **outside** the
+ACL-gated `0x4000..0x400F` range in `sub_E105A8`, so a GCP TA with the
+existing `SVC 0xF2` service-1 foothold can dispatch them. Do not equate a
+free opcode with safe hardware side effects or with a demonstrated store.
+
+| opcode | signed dispatch / input | relevant effect |
+| --- | --- | --- |
+| `0x4013` | `sub_E07D9C()` | Finds one of 11 internal resource descriptors with flag `0x2000`, then `sub_E0E030` looks up a matching region and issues `SVC 0x87`. No caller-selected pointer is passed to this helper; a status is returned. Live descriptor/region contents are not established. |
+| `0x4014` | `sub_E12968()` (no caller arguments) | Calls `sub_E134A4`, then `sub_E135DC` and `sub_E100B0`. The signed assembly contains **fixed privileged PSP-fabric stores** (`SVC 0x7C`) and `SVC 0xA6` operations. `sub_E135DC` requests eight width-2 stores at `0x17F59E2E/0x17F79E2E/0x17F99E2E/0x17FB9E2E` (value `0x2001`) and `0x17F4E206/0x17F6E206/0x17F8E206/0x17FAE206` (value `0x60`). `sub_E100B0` also requests a width-4 `SVC 0x7C` at `0x11A00020` and touches `0x1A3402D8`, `0x17F18014`-derived addresses and `0x11A0005C` via `SVC 0xA6`. Decode/side effects on Navi31 are **unknown**. |
+| `0x4015` | `sub_E1FC38(request.byte[56])`; accepts byte 1 or 2 after checking internal state `*(0xE2500C) != -1` | Uses internal secure-store routine `sub_E1A830` to obtain 20 bytes into SYS_DRV globals `0xE27020` (selection 1) or `0xE27034` (selection 2), then `sub_E193BC` requests a width-4 selector store to fabric `0x00059CCC` (value `0x38`) and five 32-bit stores to **fixed** `0x00059CD0`. It does **not** expose a request-selected address; it may nevertheless program a security-relevant device. The inner SVC return is not a hardware-effect oracle. |
+
+`0x4014`/`0x4015` are *state-changing* paths, not inert stubs merely because
+their addresses are fixed. Software address guards, PSP fabric decode,
+requester permissions and device semantics still control whether these
+requested writes have an effect. We have neither a safe purpose nor an
+independent restorable before/after oracle for these endpoints. **Do not run
+either opcode, or read/write nearby guessed registers, solely to see what
+happens.** Further work needs platform register provenance and a bounded
+benign state/control plan. This is a coverage result and an impact lead, **not
+a new hardware-confirmed bug or proof of key extraction**.
diff --git a/fw/AUDIT-GCP-HDCP-STACK-GUARD-VIA-EXISTING-LEAKS.md b/fw/AUDIT-GCP-HDCP-STACK-GUARD-VIA-EXISTING-LEAKS.md
new file mode 100644
index 0000000..565d9c7
--- /dev/null
+++ b/fw/AUDIT-GCP-HDCP-STACK-GUARD-VIA-EXISTING-LEAKS.md
@@ -0,0 +1,10 @@
+# Can GCP ROP read HDCP's stack guard through ASD `0x404` or SYS_DRV `0x109A`?
+
+**Answer on the established evidence: no demonstrated path.** These leaks disclose the guard of the process whose memory the signed reader actually sees; a chosen *virtual address* does not choose a target process. No HDCP-guard read has been performed on the card.
+
+* Signed HDCP `.57` ELF LOAD is `0x400100..0x406100`; TA header `+0x20` points to its guard at **`0x4041F8`**. The `.52` image instead names `0x4045E8` and the older `.4.49` image `0x4045A8`. Use the *actual loaded image's* header, not a guard VA from another build. This is a **VA in HDCP's TA mapping**, not a universally addressed physical cell.
+* Signed sOS `.54` `sub_6D84` translates **`0x400000..0x7fffff` using `sub_4350(PCB+75)`**, the caller/process-specific L2 table pointer in that process's record `+92`. For `0xD00000..0xDfffff`, it instead uses the selected driver ID `PCB+76` (or its fallback). Signed `SVC 0xF2` handler `sub_22B4` captures caller ID from `PCB+75`, selects service 2's driver ID, and on the driver dispatch sets `PCB+76` to that ID; it does **not** select HDCP as the caller for a GCP-originating RPC. `sub_37DC` schedules the selected service. Hence an ASD index-9 `0x404` read of a `0x40xxxx` VA from GCP is not, solely by specifying HDCP's numeric VA, an HDCP-process read. The earlier read at GCP's `0x40614C` is consistent with this; it is not evidence of general access to all TA images at `0x40xxxx`.
+* ASD `0x404` index 9 executes a CPU load at the supplied VA in the service's current mapping. It returned ASD's **distinct** private guard at `0xD1160C` on card; an attempted SYS_DRV VA read faulted on a domain violation. These controls do not establish HDCP mapping. SYS_DRV `.54` `0x109A` can arithmetically select an aligned VA but executes the load in SYS_DRV's own service context; its verified target was SYS_DRV's guard `0xE01F20`, not an arbitrary process's physical memory. Neither RPC accepts a target PID, page table, or HDCP session selector.
+* Signed sOS `.54` loader `sub_15F24:0x1665A SVC 0xA2; 0x16664 STR guard` obtains a **fresh TRNG word on each TA load** (`psp_out/GUARD-INIT-CHAIN.md`). Hardware comparisons found different GCP/ASD and GCP/SYS_DRV runtime guards. An ASD or SYS_DRV guard cannot be substituted for HDCP's guard on the evidence available. Do not treat the on-disk `0x33333333` placeholder as the live cookie.
+
+**Open condition:** a new read that executes while HDCP's process mapping is selected, a genuine shared physical alias of HDCP's guard, or a separate HDCP-specific disclosure could change this result. None follows from the two confirmed GCP-originating RPC reads. To claim HDCP's guard was recovered would require the live HDCP build/guard VA, process-specific mapping provenance and an independent HDCP-side confirmation; a status-zero read of `0x4041F8` from GCP alone would be insufficient. No stateful or speculative card request is warranted just from the matching VA.
diff --git a/fw/AUDIT-GCP-ROP-ASD-SYSDRV-HISTORICAL-BUILDS.md b/fw/AUDIT-GCP-ROP-ASD-SYSDRV-HISTORICAL-BUILDS.md
new file mode 100644
index 0000000..52b7b84
--- /dev/null
+++ b/fw/AUDIT-GCP-ROP-ASD-SYSDRV-HISTORICAL-BUILDS.md
@@ -0,0 +1,43 @@
+# Historical ASD / SYS_DRV changes relevant to GCP ROP
+
+**Scope: offline signed-image comparison, not a new card test or an exhaustion claim.** The observed card pairing is ASD `33.0.0.163` and SYS_DRV `0.49.0.54`; later ASD files are not thereby shown loadable on that card. GCP ROP can invoke the already-established SYS_DRV service 1 and ASD service 2 via `SVC 0xF2`, subject to the actual sOS routing, capability checks, and runtime state. An opcode's presence is not proof that its side effects are attainable.
+
+## Survey and reproducible anchors
+
+* Compared the eight `psp_out/elf/sys_drv_0.49.0.{37,41,47,48,49,50,51,54}_*.elf` images. A byte search for the unique little-endian ACL row `(0x1100,0x11ff,0x200)` found **one** table in each image (file offsets `0x23664,0x23a34,0x23b10,0x23b1c,0x23b18,0x23b6c,0x23b9c,0x24298`, respectively). Unpacking eleven consecutive `<III` records yielded the **same rows, order, and masks** in all eight: `0x1100–11ff:0x200`, `0x2005:0x200`, `0x2000–20ff:0x40`, `0x3000–30ff:0x1000`, `0x3100–31ff:0xffff0`, `0x103d:0x400`, `0x103f:0x800`, `0x4000–400f:0x2000`, `0x6000–60ff:0x4000`, `0x7000–70ff:0x8000`, `0x8000–80ff:0x10000`. This is a **data-table** comparison, not a proof that the paired sOS grants identical process flags or that every dispatcher follows identical logic.
+* Inspected the IDA-decompiled high dispatchers in signed `.37` (`sub_E100E4`), `.41` (`sub_E10240`), `.47` (`sub_E102F8`), `.51` (`sub_E10374`), and `.54` (`sub_E105A8`). The 153 *direct* `0x1000–0x10a4` case labels in `.51` and `.54` are identical; this is not a complete opcode-inventory comparison because `0x1001` and other operations use nested arithmetic/branches. Addresses and decompiler case shape shift between images.
+* Inspected all **18** non-anonymous `fw/decomp/asd_*.c` generated bodies (excluding `reference_asd2.c`) for named `asd_platform_op_403`, `asd_platform_op_404`, and `asd_svc_op_20B`. The consecutive-pair diff reports in `fw/diffs/asd/` can contain decompiler artifacts; compare actual instructions and image-specific table contents before claiming a fix or a usable alias.
+
+## Changes and persistent candidates
+
+| Path | Observed history | Consequence **from a GCP ROP context** |
+| --- | --- | --- |
+| SYS_DRV ACL | Eleven static range/mask records unchanged across `.37`–`.54`. | No *static ACL-table* widening from a downgrade. GCP's effective sOS-granted flags and the ACL implementation still need build-specific verification; ACL-gated `0x31xx` is not made free merely by changing SYS_DRV images. |
+| SYS_DRV `0x1006` (SETUP_TMR) | `.54` added a protected-DRAM-overlap check absent in `.51`. Hardware accepted the same overlapping host request on `.51` and rejected it on `.54` (see `psp_out/VULN-CONFIRMED-TMR-RANGE-ROLLBACK.md`). | Genuine security hardening, but **not** a post-boot GCP-ROP bypass: the orchestrator is one-shot and its engine setup is private. Standalone free `0x105d` cannot supply that setup; see the correction in `fw/DIFF-SPIROM_XFER-51-VS-54-TMR-FIX-SCOPE.md`. Host-mediated cold-boot firmware substitution is a different prerequisite from GCP TA code execution; the historical accepted placement was assessed as DoS-class, not arbitrary code execution. |
+| SYS_DRV `0x10a3` / `0x10a4` | `.37` high dispatcher has neither direct case; `.41` has `0x10a3 → sub_E1230C`, but not `0x10a4`; `.47` has both (`sub_E123F8`, `sub_E11774`), as do `.51/.54`. The `.47` and `.54` leaves take **fixed** mailbox commands 29 and 30, not caller-selected command/address/data. See implementation trace below. | Real expansion of the **free high-band command inventory**, but not a demonstrated chosen-target primitive. The `0x10a3` response can change a private flag and gate the later `0x10a4` command; only synthetic error-path behavior is tested in `.54`. No independently verified card mailbox effect, cross-client victim, or privilege escalation. |
+| SYS_DRV `0x109a` | `.37` `sub_E11580` and `.51` `sub_E1183C` both index a private table as `base + 12 * *request` and return two words without a local index check; the corresponding `.54` behavior is documented in `fw/FINDING-GCP-SYSDRV-109A-STACK-GUARD-DISCLOSURE.md`. | Persistent signed-code disclosure class. Fresh-boot `.54` card disclosure is independently documented; **do not reuse `.54` table addresses/guard indices** on an older build without remeasuring. This is a read primitive, not a PSP write. |
+| SYS_DRV low `0x35` | `.37` low dispatcher `sub_E1D2A4` calls `sub_E1D7F8` then returns its initially zero `v3`; `.51` `sub_E1D638` likewise calls `sub_E1DB8C` and returns zero, discarding the entropy helper's status. The `.54` instance is described in `fw/CANDIDATE-GCP-SYSDRV-35-IGNORED-RNG-FAILURE.md`. | The ignored-status pattern is **not a newly introduced `.54` bug**. Natural RNG failure and a consequential signed HDCP/ASD session remain unproved; an emulator-injected error is not a real entropy failure. |
+| SYS_DRV `0x1001` | `.37` `sub_E09B6C` and `.51` `sub_E09CB8` both call three cleanup helpers then return zero for the caller-supplied identity byte; `.54` is analyzed in `fw/CANDIDATE-GCP-SYSDRV-1001-SELECTED-IDENTITY-BULK-CLEANUP.md`. | Ownerless-looking management behavior persists; **no** historical live victim or repeated-release kernel fault follows from this static comparison. Do not run a release as a status probe. |
+| SYS_DRV `0x1017` | `.37` direct case calls `sub_E19DDC → sub_E197B8`; after successful fixed command 131, the leaf makes two unconditional dword stores to supplied outputs. `.54` has the analogous conditional short-declared-output candidate in `fw/CANDIDATE-GCP-SYSDRV-1017-TWO-SHORT-OUTPUTS.md`. | The leaf's two stores predate `.54`. The historical **mode/backend/validation** gates, actual mapped output spans, neighboring ownership, and card effect are **not** established by matching stores. |
+| New GCP error-path `0x208` emission | The named `gcp_sysdrv_rpc_208` wrapper introduced by GCP `.62` is **misnamed**: `.77` instructions at `0x4062C4..0x4062DC` fix `msg[0]=0x208`, `R0=2` (ASD service ID), `msg[1]` bytes `E3, caller-code, caller-status16`, and issue `SVC 0xF2`. ASD `.163` `0x208` packs this event and invokes SYS_DRV service 1 **`0x1079`**, which requests a fixed-address fabric `SVC 0x7C` when its gate permits; `.195` ASD contains the same signed `0x208 → 0x1079` forwarding sequence. | The new signed GCP error path can request a **fixed** SYS_DRV fabric word even *without* ROP. This corrects the older description of it as an unresolved SYS_DRV `0x208` logging service. With ROP GCP already has the direct free `0x1079` route; no additional chosen address, demonstrated register effect, or privilege escalation is established. See implementation trace below. |
+| ASD `0x403` | In the 18 generated ASD bodies, the leaf computes its per-index table access using `a1+1` without a leaf-local index ceiling. The `.181 → .195` 266→268-byte change is specifically one `LDRH` widening to `LDRH.W` when the structure's count field moves from `+0x38` to `+0x40`; instruction count remains 106. No index guard was added. | The `.163` service-2 authority and alias **index 82** have current-build evidence; they must not be projected onto other builds, whose structures and callback tables changed. The extra two bytes are *not* a hardening fix or a new arbitrary CPU-MMU write. Fabric `SVC 0x7C` addresses and virtual addresses remain distinct. |
+| ASD `0x404` | Named leaf is 244 bytes in all sampled bodies. The `a1` ceiling is `0xD` in `.163/.173/.181` and certain earlier branch bodies, rising to `0xF` in `.195/.239` and other later branch bodies. **Implementation check:** `a1` selects only the direct CPU read at `9` versus the generic `SVC 0x7B` path; it does not select an address or register bank on that SVC path. See trace below. | This syntactic admission of 14–15 **does not enlarge the generic readable-address set**: an already accepted non-9 value such as `a1=0`, with the same address, width and `a2=4`, reaches the same SVC operands. No new GCP read or write authority follows from the ceiling change. Cross-branch version numbers do not define a single update chain. |
+| ASD `0x20b` | In each of the 18 named bodies the leaf remains the 14-byte `*a1 = asd_svc_sub_2794()` form. | The nested unchecked Boolean-output store is longstanding at the leaf. Its GCP-owned hardware control does **not** prove a live ASD-private target, process-specific mapping, or an out-of-bounds cross-client write; see `fw/AUDIT-GCP-ASD-20B-PRIVATE-TARGET-PROVENANCE.md`. |
+
+### What the changed handlers actually do
+
+**SYS_DRV `0x1006` SETUP_TMR (`.51` versus `.54`).** The `.51` orchestrator `sub_E14064` checks a stored 64-bit TMR base in its private state: once nonzero, a request with the same base returns success, while a different base returns an error. On an unset state it checks alignment/size, stores the requested base, and enters engine/region setup; there is **no protected-window check** before the region transfers. `.54` `sub_E142A0` retains those early one-shot checks and adds, *after storing the base but before region transfers*, `sub_E2136C(base,size)` (existing range-descriptor overlaps) followed by `sub_E212DC(...)`, which calls `sub_E0F2F0` for **two adjacent 8-MiB protected ranges**. Its nonzero status aborts before the later region transfer calls. The early latch and private setup ordering explain why free internal `0x105d` is not a standalone post-boot bypass; the hardware differential for host early-boot `0x1006` is independently recorded in `psp_out/VULN-CONFIRMED-TMR-RANGE-ROLLBACK.md`. This is a real implementation change, not a case-list inference. No downgrade or TMR request was issued in this review.
+
+**ASD `0x404` (`.181` versus `.195`).** The `.195` leaf at `0xD0223C` validates **both output pointers for four bytes**, requires width 4 or 8, rejects an address in its six-list denylist, and uses `a1 == 9` for the direct `*address`/`*(u64 *)address` branch. On every other permitted `a1`, raw instructions at `0xD0231A..0xD02320` put **`R0=address (a3)`, `R1=SP` (temporary output), `R2=width`** into `SVC 0x7B`; `a1` is not passed. Taking `a2=4` bypasses the earlier `a2<=3 && mode==12` subpath in *both* builds; `a1=0` was already permitted by the `.181` ceiling. The `.181/.195` decompiled leaves show the same index-9 versus SVC distinction. Thus the change `a1<=0xD` → `a1<=0xF` is **not a new address class**. It is not even a register-index argument to `SVC 0x7B`. The actual sOS service still determines which address requests succeed; no card read was made here.
+
+**ASD `0x403` (`.181` versus `.195`).** Disassembly of `0xD02328` and `0xD02330` has 106 instructions each. The sole instruction-width difference is `.181: 0xD023CA LDRH R0,[R0,#0x38]` versus `.195: 0xD023D2 LDRH.W R0,[R0,#0x40]`; moving the count field made the encoding two bytes longer. The loop then compares a table entry with the requested pointer and sends the chosen address/value/width through `SVC 0x7C` when `a1 != 9` (`0xD02420` versus `0xD0242A`). The structural table offsets and callback offsets change; therefore the old alias index is not portable. The leaf-local missing index check remains, but whole-path exploitability in another build is untested.
+
+**SYS_DRV `0x10a3/0x10a4` (`.41`, `.47`, `.54`).** The `.41` `0x10a3` leaf `sub_E1230C` and `.47` `sub_E123F8` / `.54` `sub_E12670` zero **inline response bytes**, send fixed command 29 with argument zero and a 5000-iteration bound via their mailbox helper, then set an inline bit-0 result and SYS_DRV-private bit-1 flag even on failure; only a successful bit-0 response calls a bounded status query. The `.47` `0x10a4` leaf `sub_E11774` and `.54` `sub_E11A2C` initialize an inline byte to 1, test that private flag, call a fixed-argument setup helper, then send fixed command 30 with argument 1 and a 1000-iteration bound and set the inline byte to 0. The `.54` mailbox helper `sub_E18364` maps its fixed transport through `SVC 0x7D`, waits with bounded polling and copies **one response word**; there is no caller-supplied destination, command number, payload buffer, or fabric address in these two leaf calls. This closes the proposed *chosen-target* escalation inference, **not** the possibility of a stateful device-specific effect from triggering command 29/30. The existing `.54` synthetic test stubs a map failure and cannot establish a real response or victim. The `.41` absent `0x10a4` direct arm and `.47` added arm were checked in their actual dispatcher branches, not inferred from total case counts.
+
+**New GCP `.62+` error emitter resolves to ASD, not an unknown SYS_DRV opcode.** The `.77` wrapper at `0x4062B4` initializes a 24-byte frame, stores opcode `0x208`, puts `E3` at the low byte of `msg[1]`, the caller's low-byte error code in the next byte, and its 16-bit status in the high half; `R0=2` is the **service**, not an RPC status. ASD `.195` raw `asd_log_event` at `0xD11508` packs `low8<<24 | byte1<<16 | high16`; its wrapper at `0xD01B24..0xD01B34` fixes `msg[0]=0x1079`, `service=1`, and invokes F2. ASD `.163` has the same chain (`fw/AUDIT-ASD-163-208-SYSDRV-1079-FORWARD.md`). Signed SYS_DRV `.37` `0x1079 → sub_E18DAC → sub_E14ED0` and `.51` `0x1079 → sub_E19150 → sub_E15254` both skip top bytes `EE/EF` and, with initial private gate **2**, issue width-4 `SVC 0x7C` at fixed `0x03B30600`. The GCP wrapper's top byte `E3` passes the filter. `.54`'s corresponding chain is `sub_E1939C → sub_E154A0` (same fixed address); its observed live endpoint behavior is **not** established by these instructions or the synthetic relay. This corrects the old `fw/diffs/SECURITY-REVIEW.md` note that the destination was unavailable and only reporting. A fixed diagnostic/control request is an observable *code path*, not evidence that the card accepted or acted on the fabric write, nor of teardown or privilege gain.
+
+**Do not infer removals from decompiler labels.** For example, `.37/.41` display `0x108f` as a switch case returning a private status word; `.47` lifts the same equality into a separate `if (*request == 4239)` branch. A raw case-label subtraction would falsely report the opcode removed. Likewise, direct-case equality between `.51`/`.54` does not imply identical instruction behavior (the `0x1006` fix is counterevidence).
+
+## Finding and limits
+
+The most material historical fix is the **`.51 → .54` SETUP_TMR guard**, which closes a host/early-boot protected-window placement, **not** an established route to escalate an already executing GCP TA on the stock `.54` card. The SYS_DRV ACL table stays constant; `0x10a3/0x10a4` add fixed stateful mailbox operations by `.47`, but no chosen target or live privilege gain is demonstrated. ASD `0x404`'s widened index comparison does **not** widen the effective generic read set. The newer GCP error emitter, formerly mistaken for SYS_DRV opcode `0x208`, actually calls ASD `0x208 →` the already free SYS_DRV `0x1079` fixed fabric request. Several ASD/SYS_DRV candidates persist across builds, but per-version aliases, callback installations, runtime mode gates, process mappings, and victim effects must be re-established before attributing hardware impact. This is a focused historical comparison, **not** an exhaustive control-flow diff of every signed image or an objective-wide attack-surface completion audit. No live requests or destructive probes were issued for this review.
diff --git a/fw/AUDIT-GCP-SYSDRV-1010-1015-DISPATCH-IS-NOT-STUB.md b/fw/AUDIT-GCP-SYSDRV-1010-1015-DISPATCH-IS-NOT-STUB.md
new file mode 100644
index 0000000..3288f07
--- /dev/null
+++ b/fw/AUDIT-GCP-SYSDRV-1010-1015-DISPATCH-IS-NOT-STUB.md
@@ -0,0 +1,29 @@
+# SYS_DRV `.54` free `0x1010..0x1015`: historical stub classification retracted
+
+This is a **dispatch correction, not a safety audit or vulnerability
+claim**. Signed `sub_E105A8` cases `0x1010..0x1015` all reach
+`sub_E11DC8(msg+14,opcode)`, which takes an `SVC 0x5E` lock and
+routes to six distinct signed crypto helpers:
+
+| opcode | leaf called by `sub_E11DC8` |
+|---|---|
+| `0x1010` | `sub_E09430(mode=1)` |
+| `0x1011` | `sub_E09430(mode=0)` |
+| `0x1012` | `sub_E094C8` |
+| `0x1013` | `sub_E09558` |
+| `0x1014` | `sub_E09624` |
+| `0x1015` | `sub_E096E8` |
+
+The signed role table has three input pairs and one output pair for
+`0x1010`, `0x1011`, `0x1013`, `0x1014`, `0x1015`; `0x1012` has two
+inputs and one output. The `0x1015` dispatcher additionally checks
+a 72-byte span through `sub_E0DEF4`. Exact leaf buffer widths,
+per-caller identities, crypto object lifetimes, CCP completion and
+hardware effects are **not** established by this first-level
+inventory. A subsequent first-level source/sink review found **conditional**
+caller `+68/+140` span questions behind the shared crypto workspace
+and lower-level gates; see
+`fw/LEAD-GCP-SYSDRV-1010-1015-NESTED-SPANS.md`. The older
+`fw/OVERVIEW-GCP-REACHABLE-SYSDRV-OPCODES.md` stub list has been
+corrected; do not treat an opcode's historical classification as
+exhaustive proof. No card request was issued.
diff --git a/fw/AUDIT-GCP-SYSDRV-101F-SOS6B-6D-CLEANUP.md b/fw/AUDIT-GCP-SYSDRV-101F-SOS6B-6D-CLEANUP.md
new file mode 100644
index 0000000..6b2ed5f
--- /dev/null
+++ b/fw/AUDIT-GCP-SYSDRV-101F-SOS6B-6D-CLEANUP.md
@@ -0,0 +1,30 @@
+# Free SYS_DRV `.54` `0x101F`: sOS resource cleanup after query failure
+
+**Paired signed SYS_DRV/sOS static audit only; no stateful card or
+emulator resource release.** SYS_DRV `sub_E105A8` case `0x101F`
+routes to `sub_E147D4 → sub_E0E8E0`. The latter sends sOS
+`SVC 0x6B` to create a resource, placing its ID byte in a local
+slot, then `SVC 0x6D` to query metadata into other locals. On
+`0x6D` error it calls `SVC 0x6C` once to release that ID before
+returning the error. The outer `sub_E147D4` has another `SVC 0x6C`
+in its failure cleanup, **but only if its queried output word is
+nonzero**. At first this looks like a double teardown.
+
+Raw SYS_DRV `0xE0E91C..0xE0E932` and `0xE1488C..0xE14894`
+show the order and the outer nonzero gate. Paired signed sOS `.54`
+SVC dispatch case 28 (`0x6D`) validates each nonnull output via
+`sub_178C` **before** calling `sub_28B4`; `sub_28B4` rejects an
+out-of-range resource ID **before** writing any output and writes
+the selected metadata only on its zero-status path. `SVC 0x6B`
+receives the ID-byte pointer, **not** that queried output word.
+Thus an ordinary `0x6D` error leaves the initially zero queried
+word zero: the inner release runs and the outer release is skipped.
+This **does not establish a double-`0x6C` primitive**.
+
+The sOS `sub_28B4` metadata helper itself dereferences an in-range
+resource descriptor without checking for null, but this `0x101F`
+route normally queries the ID it just allocated; an absent or
+asynchronously destroyed descriptor has not been established.
+Other `0x101F` errors after a successful `0x6D`, sOS allocator
+semantics, and live resource ownership remain unverified. Do not
+probe resource creation/release on the card for a status.
diff --git a/fw/AUDIT-GCP-SYSDRV-1027-SOS94-BLOCK.md b/fw/AUDIT-GCP-SYSDRV-1027-SOS94-BLOCK.md
new file mode 100644
index 0000000..2560af0
--- /dev/null
+++ b/fw/AUDIT-GCP-SYSDRV-1027-SOS94-BLOCK.md
@@ -0,0 +1,28 @@
+# Free SYS_DRV `.54` `0x1027`: diagnostic path blocked by signed sOS `SVC 0x94`
+
+**Current signed-build negative result; no chosen register access or
+hardware effect.** SYS_DRV `sub_E105A8` case 4135 calls
+`sub_E137D8(msg+14)`. It obtains three fixed descriptors from
+SYS_DRV-private `0xE7D600-24`, `0xE7D600` and `0xE7D600+24`, then
+calls `sub_E15EE4` on each. Raw `sub_E15EE4` invokes
+**`SVC 0x94`**; the leaf returns immediately on the first nonzero
+status, before combining any descriptor values or writing its
+Boolean inline output. No descriptor address or mask comes from the
+GCP request; this is not a caller-chosen `SVC 0x7B/0x7C` register
+read. The opcode itself has no mapped caller output pointer.
+
+Signed sOS `.54` `sub_59E8` case **67** (`SVC 0x94`, after the
+`-0x51` case adjustment) calls `sub_47BC`, which **unconditionally
+returns 9** on this build. Thus the first SYS_DRV lookup fails and
+its Boolean computation is unreachable under that exact sOS
+implementation. `psp_emu/harness/probe_sysdrv_1027_sos94_block.py`
+passed by connecting only this signed sOS return to the signed
+SYS_DRV dispatcher: status 9, one SVC94 call, original inline
+`msg[14]` unchanged. The emulator's default-success SVC handlers
+for unrelated initialization calls do not establish other live
+semantics. No card call was made.
+
+This closes the proposed diagnostic-leaf effect for the paired
+`.54` images, **not** for another sOS build or alternate SVC
+routing. Do not use an isolated emulator with SVC94's default
+success as proof of register reads or a GCP oracle.
diff --git a/fw/AUDIT-GCP-SYSDRV-102A-SOS59-RESOURCE.md b/fw/AUDIT-GCP-SYSDRV-102A-SOS59-RESOURCE.md
new file mode 100644
index 0000000..ac4dc2e
--- /dev/null
+++ b/fw/AUDIT-GCP-SYSDRV-102A-SOS59-RESOURCE.md
@@ -0,0 +1,25 @@
+# Free SYS_DRV `.54` `0x102A`: fixed sOS resource acquisition, not a getter
+
+**Signed static correction; no card allocation or resource impact.**
+Historical overview classifies `0x102A` as a tiny/query getter.
+Signed `sub_E105A8` case 4138 calls `sub_E13AA0(msg+14)`.
+Raw `0xE13AA4..E13AB6` requires inline `msg[14]==7`, sets
+**R0=`0x27`**, invokes **`SVC 0x59`**, stores the **SVC result**
+into `msg[15]`, then returns zero. Hex-Rays' `msg[15]=39` is an
+SVC decompilation artifact: the source constant 39 is the **request**,
+not necessarily the returned resource handle. Invalid selectors
+return `0xFFFF0006` before that SVC.
+
+Signed sOS `.54` `SVC 0x59` case 8 routes to `sub_47E4(39)`. That
+function consults a global byte table indexed by resource ID; on
+an unassigned sentinel `129`, it can call `sub_1C90(type=2,0)`
+to allocate/assign a resource and set ownership/class metadata.
+If already assigned it returns the existing byte. Thus this free
+SYS_DRV opcode may cause a **stateful sOS allocation**, not merely
+read status. `sysdrv_env` models `SVC 0x59` as an argument echo;
+that default handler does **not** implement sOS `sub_47E4` and
+cannot validate natural allocation or resource ownership.
+
+Active table state, sOS identity under SYS_DRV, signed consumers,
+allocation exhaustion/release policy and live cross-client effect
+remain open. Do **not** invoke it on the card just for a return code.
diff --git a/fw/AUDIT-GCP-SYSDRV-102D-CRYPTO-MODE2.md b/fw/AUDIT-GCP-SYSDRV-102D-CRYPTO-MODE2.md
new file mode 100644
index 0000000..8d6210a
--- /dev/null
+++ b/fw/AUDIT-GCP-SYSDRV-102D-CRYPTO-MODE2.md
@@ -0,0 +1,36 @@
+# Free SYS_DRV `.54` `0x102D`: crypto object initialization, mode 2
+
+**Signed static scope; no card call, generated object, or full crypto
+implementation audit.** SYS_DRV `sub_E105A8` case `0x102D`
+reuses `sub_E1E064`, also used by low crypto opcode `0x34`.
+Both look up the object through `sub_E0B0F4` with the
+sOS-supplied caller identity; high `0x102D` passes final argument
+**2**, whereas low `0x34` passes **0**. The leaf rejects objects
+with disallowed state flags and a requested size above the object's
+recorded capacity, then branches on its stored object type.
+
+For the examined key-generation-type branch (`sub_E0F640`), the
+requested size is restricted to the explicit set
+`{256,512,768,1024,1536,2048,3072,4096}` and checked again
+against object capacity. Mode 2 selects `sub_E07C80` to fill a
+local 32-byte entropy buffer before `sub_E15588`; mode 0 follows
+the null-entropy-input branch. The leaf stages work fields in the
+owned object **before** downstream operations; it assigns the final
+length/type fields and outer initialized bit on success. Failure
+cleanup/partial-state consumers are not closed by this review. Other type branches call
+`sub_E0F620`, `sub_E0F3B4`, or `sub_E0F4F0`. One apparent
+`sub_E0F3B4` stack risk is scoped: its 256-byte `v17` reverse-copy
+loop uses `v9[256]`, populated only after a successful
+`sub_E0621C(...,capacity=256,outlen=&v9[256])`; that helper
+rejects input length above capacity before storing the length.
+This does **not** close the other nested cryptographic effects,
+producer integrity or external CCP responses. The request's paired input is
+region-validated in the high dispatcher, but that alone is not a
+proof of all nested spans.
+
+This path does not establish a chosen-address read/write, cross-client
+object selection, or entropy disclosure. Do not treat emulator
+success for unrelated SVCs or generated synthetic objects as real
+hardware entropy/CCP evidence. Further work would require a
+specific object-type and consumer hypothesis, with non-secret
+markers and no card crypto operation merely to collect a status.
diff --git a/fw/AUDIT-GCP-SYSDRV-1031-PRIVATE-MODE-QUERY.md b/fw/AUDIT-GCP-SYSDRV-1031-PRIVATE-MODE-QUERY.md
new file mode 100644
index 0000000..d2445e2
--- /dev/null
+++ b/fw/AUDIT-GCP-SYSDRV-1031-PRIVATE-MODE-QUERY.md
@@ -0,0 +1,29 @@
+# Free SYS_DRV `.54` `0x1031` selector 15: read-only mode-byte oracle
+
+**Signed code plus isolated signed-dispatch control. No card request,
+ROP mapping assumption, or live mode value.** `sub_E105A8` case
+`0x1031` passes inline request word `msg[14]` to `sub_E12414`.
+Selector `0xF` loads **one byte** through signed literal
+`off_E124E0=0xE26259`, zero-extends it, and stores it to
+**inline `msg[15]`** before returning zero. No nested caller pointer,
+private-state setter or SVC appears in that selector's leaf.
+Unknown selector `0x19` returns an error without changing `msg[15]`.
+
+`python3 psp_emu/harness/probe_sysdrv_1031_mode_oracle.py`
+passed against the original signed `.54` dispatcher: the isolated
+post-init private mode byte **1** was returned, then a deliberately
+planted emulator-only **0** was returned; an invalid selector left
+an inline marker unchanged. The isolated initialization logs
+unrelated default-success SVC warnings, so this demonstrates the
+signed getter, **not** live capability or silicon mode.
+
+This provides a less stateful potential gate oracle for the
+conditional `0x1017` two-short-output defect
+(`fw/CANDIDATE-GCP-SYSDRV-1017-TWO-SHORT-OUTPUTS.md`), but **no
+GCP-ROP card chain was issued**: the failed log-gate memcpy mapping
+has not been repaired by this getter and must not be retried via
+displacement arithmetic. Any future card read requires an
+independently verified mapping and fault/unload/recovery controls.
+Other `0x1031` selectors expose various private scalars or bytes;
+this focused audit does not assign them confidentiality labels or
+claim full selector coverage.
diff --git a/fw/AUDIT-GCP-SYSDRV-1036-1040-1055-NONSTUB.md b/fw/AUDIT-GCP-SYSDRV-1036-1040-1055-NONSTUB.md
new file mode 100644
index 0000000..cb83f27
--- /dev/null
+++ b/fw/AUDIT-GCP-SYSDRV-1036-1040-1055-NONSTUB.md
@@ -0,0 +1,28 @@
+# SYS_DRV `.54` historical stub-list correction: `0x1036`, `0x1040`, `0x1055`
+
+**Signed static first-level inventory, not a hardware finding.** All
+three appear in the historical "stubs" line of
+`fw/OVERVIEW-GCP-REACHABLE-SYSDRV-OPCODES.md`, but the signed
+`sub_E105A8` dispatcher performs real work:
+
+* `0x1036` calls `sub_E0B910(msg+14)`, storing a 64-bit scaled
+ timer result inline in message words 14–15. `sub_E0B9F4` derives
+ it from the private pointer at `0xE257A0`; the available emulator
+ lacks the external backing at that pointer. This is not a
+ caller-chosen memory address or a proved clock-information leak.
+* `0x1040` calls `sub_E1F780(msg+14, sOS_caller_index)`, with role
+ `{0x1040,1,2,0,0}` at `0xE25DB4`. After a per-caller crypto-state
+ gate `sub_E0E7B8`, raw `0xE1F7A6` reads **`msg[2]+52`** without
+ requiring declared input `msg[3]>=56`; raw `0xE1F7B0` also reads
+ `+48`. This is a conditional nested-input width lead analogous
+ to (but not execution evidence for) `0x101D`; crypto/session gates
+ and real PTE ownership remain open. The source of the index is sOS,
+ not a caller-selected inline scalar.
+* `0x1055` reads two fixed SYS_DRV-private status words/bytes from
+ the structure rooted at signed `0xE5FA48`, and returns them
+ inline in words 14–15. It is a getter, not a return-constant stub
+ or a caller-selected-pointer dereference. Security significance of
+ the fields is unestablished.
+
+The inventory correction does **not** certify these paths safe or
+prove natural per-caller crypto state. No card request was issued.
diff --git a/fw/AUDIT-GCP-SYSDRV-103B-103C-1082-NONSTUB.md b/fw/AUDIT-GCP-SYSDRV-103B-103C-1082-NONSTUB.md
new file mode 100644
index 0000000..6c7b367
--- /dev/null
+++ b/fw/AUDIT-GCP-SYSDRV-103B-103C-1082-NONSTUB.md
@@ -0,0 +1,36 @@
+# SYS_DRV `.54` free `0x103B`, `0x103C`, `0x1082`: historical stub corrections
+
+**Signed static classification plus synthetic scalar roundtrip; no
+sensitive live disclosure.** These three entries in the historical
+stub list are not inert return-constant cases:
+
+- `0x103B` reaches the shared signed dispatch block that writes
+ **2** to inline `msg[14]` and returns zero. No private pointer or
+ state-changing leaf was observed on that case.
+- `0x103C` writes the signed-image constant **`0x00310036`**
+ (`dword_E116BC`) to inline `msg[14]` and returns zero. Neither
+ case is an arbitrary read.
+- `0x1082` writes the current SYS_DRV-private dword **`0xE2584C`**
+ to inline `msg[14]` and returns zero. Signed direct xrefs to that
+ dword found only this read and a setter in **high opcode `0x3133`**
+ that stores inline `msg[14]`. The signed-image and isolated
+ post-init value was zero. The high `0x3100..0x31FF` ACL entry
+ requests capability mask `0xFFFF0`, unlike the fallback `0x10`
+ requested for `0x1082`. Signed sOS `.54` `SVC 0x76` case 37
+ evaluates the requested mask against the current process caps;
+ the emulator's ordinary always-success `SVC 0x76` is **not** an
+ authentic GCP capability source. The same high-range mask covers
+ `0x3105`, previously ACL-rejected for direct GCP; signed sOS
+ `SVC 0x8E` grants rights only from a process whose record byte 0
+ equals 1 (`fw/AUDIT-SOS54-SVC76-8E-CAPABILITY-FLOW.md`).
+
+`psp_emu/harness/probe_sysdrv_1082_privileged_scalar.py` passed
+with explicit **synthetic** restricted (`0x10`) and privileged
+(`0xFFFF0`) SVC76 profiles. Restricted `0x3133` returned
+`0xFFFF0001`; synthetic privileged `0x3133` stored a public
+`0x12345678` marker, after which restricted `0x1082` returned the
+same inline marker. The signed setter restored the original zero
+**in emulator memory**. No card call, real privileged issuer,
+secret scalar, consumer beyond the getter, or security consequence
+was established. This is an ACL-asymmetric read interface, **not a
+proved information leak**.
diff --git a/fw/AUDIT-GCP-SYSDRV-1044-FIXED-RESOURCE-GATE.md b/fw/AUDIT-GCP-SYSDRV-1044-FIXED-RESOURCE-GATE.md
new file mode 100644
index 0000000..4fde0e9
--- /dev/null
+++ b/fw/AUDIT-GCP-SYSDRV-1044-FIXED-RESOURCE-GATE.md
@@ -0,0 +1,32 @@
+# Free SYS_DRV `.54` `0x1044`: fixed resource read behind absent isolated-init gate
+
+**Scoped signed read path; no natural mapped source or disclosure.**
+Signed `sub_E105A8` case 4164 passes inline outputs `msg[14]`
+and `msg[15]` to `sub_E126E4` with constant mode 1. It returns
+`0xFFFF0007` immediately if private `*0xE45AA0` is zero. Otherwise
+it derives a **fixed** resource offset from private
+`0xE264A8/0xE264AC` plus the descriptor's `+8` field, asks
+`sub_E086FC` to map one page with argument `a7=1`, and reads
+only mapped dwords `+0` and `+64` into the two inline results.
+The map helper's `a7=1` chooses stateful sOS **`SVC 0x8B`**,
+not the `SVC 0x6B` path blocked elsewhere on `.54`.
+It conditionally releases the mapped resource with `SVC 0x6C`.
+No pointer, length, tag or address for this mapping comes from
+the GCP request; the opaque private descriptor and its live
+source/ownership are unclassified.
+
+`psp_emu/harness/probe_sysdrv_1044_default_gate.py` passed on
+signed `.54` dispatch after isolated signed init. `*0xE45AA0`
+was zero, and a request returned `0xFFFF0007`, left both inline
+markers unchanged, and did **not** reach an explicitly forbidden
+`SVC 0x8B`. Initialization still uses default-success handlers
+for unrelated SVCs and supplies no real card resource. No
+resource pointer was planted and no card request was made.
+
+The signed-image code has other references to `0xE45AA0`, so a
+later valid firmware/resource setup may change this gate. That
+writer path, active card value, confidentiality policy for the
+mapped page, and safe observation/restoration remain open. This
+isolated-init rejection does **not** establish that live `0x1044`
+is universally inert or that the returned words are nonpublic.
+Do not invoke stateful `SVC 0x8B` for a return code.
diff --git a/fw/AUDIT-GCP-SYSDRV-107C-FIXED-DIAGNOSTIC-GATE.md b/fw/AUDIT-GCP-SYSDRV-107C-FIXED-DIAGNOSTIC-GATE.md
new file mode 100644
index 0000000..8699e4f
--- /dev/null
+++ b/fw/AUDIT-GCP-SYSDRV-107C-FIXED-DIAGNOSTIC-GATE.md
@@ -0,0 +1,28 @@
+# Free SYS_DRV `.54` `0x107C`: fixed diagnostic gate and bounded mode word
+
+**Signed static correction; no card request or new disclosure claim.**
+`sub_E105A8` case `0x107C` invokes `sub_E1828C(&msg[14])`.
+Signed `sub_E087B4` first requests a four-byte `SVC 0x7B` read
+from **fixed fabric address `0x10140338`** and returns its low bit.
+A zero bit returns `0xFFFF000A`; a set bit invokes `sub_E0850C`
+(the separately scoped fixed two-register diagnostic also used by
+free `0x1049`). Unless that helper returns `0xFFFF`, this leaf
+returns `0xFFFF0001`. Only when both gates pass does it copy
+SYS_DRV-private `0xE26478` to inline `msg[14]` and return zero.
+There is no GCP-chosen register address or nested caller pointer.
+
+The scoped direct signed xrefs for `0xE26478` are its getter
+`sub_E0B060`, this `0x107C` read, and setter `sub_E18C50`.
+The setter rejects values **greater than 15**, writes the word,
+then calls additional stateful helpers. Signed dispatcher
+`0x3124` invokes that setter, inside the `0x3100..0x31FF`
+capability-mask `0xFFFF0` range. The free `0x107C` requires only
+fallback mask `0x10`; direct GCP access to the high range was not
+established and the examined writer's scalar is bounded. This
+looks like a gated mode/diagnostic getter, **not** evidence of key
+material, a chosen-address MMIO read, or a new privilege escalation.
+
+Live register bits, other dynamic/indirect writers and exact private
+word value were not measured. This is a scoped negative control,
+not an objective-wide clean bill. The separate `0x1049` fixed-register
+audit is `fw/AUDIT-GCP-FREE-SYSDRV-1049-FIXED-REG-READ.md`.
diff --git a/fw/AUDIT-GCP-SYSDRV-1084-OUTPUT-SPAN-INLINE-METADATA.md b/fw/AUDIT-GCP-SYSDRV-1084-OUTPUT-SPAN-INLINE-METADATA.md
new file mode 100644
index 0000000..c72c04b
--- /dev/null
+++ b/fw/AUDIT-GCP-SYSDRV-1084-OUTPUT-SPAN-INLINE-METADATA.md
@@ -0,0 +1,33 @@
+# Free SYS_DRV `.54` `0x1084`: inline metadata precedes output-size rejection
+
+**Scoped signed-code/output-span audit, not a sensitive-data claim.**
+Signed `sub_E105A8` case 4228 calls `sub_E139C0` with two inline
+output words (`msg[14]`, `msg[15]`) and the caller output pointer
+and declared length (`msg[2]`, `msg[3]`). The leaf requires
+non-null pointers, then copies two SYS_DRV-private dwords at
+`0xE6027C` and `0xE60384` into those inline words **before**
+requiring declared output length `>=16`. If short, it returns
+`0xFFFF300F`; otherwise it copies exactly 16 bytes from private
+`0xE60280` into the validated caller output. The wrapper copies
+inline message fields back on this error path. These are CPU-RAM
+private fields; their writer, meaning and live values are unknown.
+
+`psp_emu/harness/probe_sysdrv_1084_short_output_inline.py` passed
+against signed `.54` dispatch. It planted **public synthetic**
+markers in those private words and 16 public source bytes, then
+restored them in emulator memory. A four-byte declared output
+returned `0xFFFF300F` and the markers inline without changing the
+caller output sentinel. A 16-byte declaration returned success,
+the same inline markers, and exactly the 16 synthetic source bytes;
+the adjacent sentinel remained intact. Other initialization SVCs
+use emulator default-success handlers. No card request or real
+private bytes were read.
+
+The same inline words are available on a valid 16-byte request, so
+the short-error behavior **alone does not bypass a demonstrated
+confidentiality policy**. No output write beyond the declared span
+was observed. A scoped signed-ELF scan found 94 functions directly
+referencing base `0xE5FA48`; only `sub_E139C0` used the explicit
+`+525/+526/+591` decompiler offsets. That does not exclude indirect
+writers or DMA. Live field provenance, exact PTE coverage, owner
+semantics and downstream consumers remain open.
diff --git a/fw/AUDIT-GCP-SYSDRV-5B-5E-STREAM-BOUNDS.md b/fw/AUDIT-GCP-SYSDRV-5B-5E-STREAM-BOUNDS.md
new file mode 100644
index 0000000..c9f06ad
--- /dev/null
+++ b/fw/AUDIT-GCP-SYSDRV-5B-5E-STREAM-BOUNDS.md
@@ -0,0 +1,40 @@
+# SYS_DRV `.54` low `0x5B..0x5E`: stream cursor and resize bounds
+
+**Signed-code, scoped negative result. No card requests and no
+artificially planted object.** Service-1 `sub_E1DC30` dispatches to
+`sub_E1EB48` (read), `sub_E1ED08` (write), `sub_E1EC80` (resize), and
+`sub_E1EC10` (seek). All first call `sub_E0B0F4` with the sOS-supplied
+caller ID to obtain an owned active object. **This is not proof that
+all object producers enforce the expected allocation invariant.**
+
+- Read (`0x5B`) requires the stream/read flags, compares cursor against
+ logical length, copies only `min(requested, length-cursor)` from
+ object data base `object+112+offset+cursor`, and advances cursor by
+ copied bytes. At or past EOF it writes zero to inline count.
+- Write (`0x5C`) requires stream/write flags. It checks carry on
+ `cursor+requested` and rejects an end past `0x2000` **before** copy.
+ If end exceeds logical length, signed `sub_E15F88` reallocates to
+ `object+112+offset+end` and updates length only on allocation
+ success. Raw instructions at `0xE1ED4A..0xE1ED52` retain the checked
+ end in `R1` for that helper (Hex-Rays omits this second argument
+ at the call). Then it copies the declared input count and attempts
+ serialization via `sub_E17CD4`.
+- Resize (`0x5D`) rejects lengths above `0x2000`, passes the chosen
+ length in `R1` to the same realloc helper (raw
+ `0xE1ECB6..0xE1ECBC`), then serializes. A successful shrink may
+ leave cursor beyond EOF; read returns zero and a later write must
+ still pass the bounded end check.
+- Seek (`0x5E`) interprets a signed offset and origin 0/1/2.
+ Positive results must be `<=0x2000`; negative movements clamp to
+ zero when their unsigned magnitude exceeds the selected base.
+ `-INT_MIN` remains a large unsigned magnitude in two's complement
+ and takes the clamp branch from valid cursor/length state; it is
+ **not** by itself an out-of-range cursor. Other origin values
+ return an error.
+
+This rules out a simple declared-count overflow or seek-to-OOB on
+**well-formed, owned stream objects** along the examined direct paths.
+The object-layout producers (`0x54..0x5A`), allocator integrity,
+serialization failure state, and possible inherited malformed objects
+need separate review before calling the wider stream subsystem safe.
+See `fw/AUDIT-GCP-SYSDRV-LOW-40-48-50-5E-FIRSTLEVEL.md`.
diff --git a/fw/AUDIT-GCP-SYSDRV-LOW-40-48-50-5E-FIRSTLEVEL.md b/fw/AUDIT-GCP-SYSDRV-LOW-40-48-50-5E-FIRSTLEVEL.md
new file mode 100644
index 0000000..af05c52
--- /dev/null
+++ b/fw/AUDIT-GCP-SYSDRV-LOW-40-48-50-5E-FIRSTLEVEL.md
@@ -0,0 +1,14 @@
+# SYS_DRV `.54` low opcodes `0x40..0x48`, `0x50..0x5E`: scoped first-level review
+
+**Signed static review, not a full crypto-object or callback audit. No card calls.** `sub_E1DC30` validates nonzero request pointer/length pairs via `sub_E0AB44`/`sub_E0DEF4` before this switch. These labels are among the corrected **53** low handled labels, not the old nine-case inventory. The dispatcher passes the sOS-supplied caller ID into helpers that need it; this does not make their nested effects automatically safe.
+
+| Group | Observed direct behavior / unresolved depth |
+|---|---|
+| `0x40`–`0x42` | `0x40` uses a `SVC 0x76` wrapper, `0x41` yields via `SVC 0x56`, `0x42` puts a pair of computed time words in fixed `msg[14:15]`. No caller-selected nested output pointer in these leaves. |
+| `0x43`–`0x46` | Property lookups pass through `sub_E0B380 → sub_E09D70`. The latter bounds caller property-name length to 128 and each matched property value length to 128 and checks the property-list upper address; this is a scoped parser observation, not a proof of full property-table provenance. `0x43` checks requested output capacity against its formatted value length before writing; `0x44` reports a required size for one type, `0x45` writes one Boolean in fixed request word, `0x46` returns a scalar. |
+| `0x47`–`0x48` | On the correct property type, `sub_E1E7F4` copies 16 bytes only if the selected output length is at least 16; `sub_E1E560` similarly copies 20 only after a 20-byte check. No short-declared output like high opcode `0x1023` is apparent at these immediate leaves. |
+| `0x50`–`0x53` | `0x50` returns zero, `0x51`/`0x52` are null helpers, and `0x53` calls a log helper **before** checking declared length/NUL. Deeper signed tracing and a synthetic-emulator test found a conditional logger read of up to 39 caller bytes despite a four-byte declaration. No card log state, PTE or out-of-process read was measured. See `fw/CANDIDATE-GCP-SYSDRV-53-LOG-STRING-PREVALIDATION.md`. |
+| `0x54`–`0x5A` | Stateful context/object management, SVC-backed creation and release, and property operations. Includes `0x57`'s 0x2000 bound on a caller length. These were not exhaustively checked for allocator-failure or reentrancy paths. |
+| `0x5B`–`0x5E` | Stream read/write/resize/seek via object lookup `sub_E0B0F4`, which rejects inactive handles or mismatched caller ID. `0x5B` caps copied output to the caller's size; `0x5C` caps total object size at 0x2000 and writes the declared caller input count; `0x5D` bounds size at 0x2000; `0x5E` updates cursor arithmetically. These direct lengths do not show another obvious 40-byte short-input mismatch. A deeper signed-code cursor/carry/realloc review found no simple stream seek-to-OOB for a well-formed owned object (`fw/AUDIT-GCP-SYSDRV-5B-5E-STREAM-BOUNDS.md`); error/fatal, producer integrity and object-lifetime behavior remain conditional. |
+
+In particular, `sub_E0B0F4`'s signed owner-byte check does **not** prove that an invalid handle is a harmless error: it can call `sub_E0F890` (fatal path). Do not invoke these stateful operations or a bad handle on the card simply to observe a return. Next deeper work: measure live logging gates **read-only** and inspect the real caller mapping before treating `0x53`'s synthetic edge as live; resolve any retained second-client object and the signed object-operation failure paths without manufacturing persistent state.
diff --git a/fw/AUDIT-HDCP57-SYSDRV1087-MODE-GATE.md b/fw/AUDIT-HDCP57-SYSDRV1087-MODE-GATE.md
new file mode 100644
index 0000000..7c5c172
--- /dev/null
+++ b/fw/AUDIT-HDCP57-SYSDRV1087-MODE-GATE.md
@@ -0,0 +1,27 @@
+# Signed HDCP `.57` cmd `0xB`: SYS_DRV `0x1087` byte gate
+
+**Signed-code correction, no card call or live protected-session claim.**
+Free SYS_DRV `.54` `0x1087 → sub_E12A50` writes an **inline
+`msg[14]`** flag. It reads private byte `0xE256F6` and, only when
+that byte is 35 or 53, reads bit `0x1000` at the signed global
+pointer rooted at `0xE257A0`; the result is 0 or 1. This leaf
+contains no caller-supplied pointer or address.
+
+HDCP `.57` signed wrapper `0x401360..0x401396` requests service 1,
+opcode `0x1087`, and only on a zero RPC status converts the
+inline dword into a **byte at its caller's output pointer**.
+The `hdcp_cmd0B` caller `0x402ED8` zero-initializes that byte on
+its stack. Raw signed instructions for message types `0x10` and
+`0x17` (`0x402FBC..0x402FD8` and `0x40300A..0x403024`)
+**read the returned byte** before selecting a message template.
+Hex-Rays' displayed `hdcp_cmd0B` pseudocode collapses these paths
+and misleadingly appears to branch only on the RPC status; the
+instruction-level byte read corrects that interpretation. Status
+`0xFFFF0009` takes separate fallback templates, not the successful
+byte-gated branch.
+
+This establishes a signed client consumer of a fixed private mode
+flag, **not** a bypass, arbitrary disclosure, or live mode value.
+The actual byte/pointer contents, mode-dependent policy and active
+build remain unmeasured; the earlier failed GCP log-gate ROP chain
+is not a safe way to read them.
diff --git a/fw/AUDIT-OPM51-ASD301-AUTH-BOUNDARY.md b/fw/AUDIT-OPM51-ASD301-AUTH-BOUNDARY.md
new file mode 100644
index 0000000..3dfd210
--- /dev/null
+++ b/fw/AUDIT-OPM51-ASD301-AUTH-BOUNDARY.md
@@ -0,0 +1,60 @@
+# Signed OPM `.51` cmd 8 → ASD `0x301`: prefix check versus SRM payload
+
+**Scope:** static signed OPM `.51` and ASD `.163`; no emulator authentication
+claim, card request, valid SRM, or active-build proof. This refines the older
+`fw/AUDIT-NEW-TAS-RE.md` host-data-route observation: reaching the emitter
+is **conditional on an OPM integrity/crypto comparison**. It does not follow
+that an arbitrary host can author the prefix that selects that path.
+
+## OPM byte ranges (raw Thumb at `0x401320..0x401544`)
+
+**New entry-span check:** Signed `opm_TA_InvokeCommandEntryPoint`
+(`0x402AE4`) first requires a nonnull param0 memref with low param-type
+nibble `7` and `*(u32 *)(param0+4) >= 0x3D54`, before dispatching
+host command 8 to `0x401320`. That declared minimum is larger than the
+cmd-8 prefix and payload-pointer fields through host `+0x101F`.
+Thus the fixed 0x1000-byte prefix copy is **not** an uncovered
+length check in OPM's signed entry. This does not prove that sOS maps
+or validates the whole declared memref: the host-to-sOS mapping boundary
+was not independently measured here.
+
+For cmd 8, `R7` is the host params pointer. OPM checks slot index
+`*(u32 *)(R7+0x10) <= 0x3f`, requires a slot state 3, then:
+
+- `0x401360..0x40136E`: set `R8=SP+0x10`, copy exactly `0x1000` bytes
+ from `R7+0x18` into that stack buffer. The copied host range is
+ **`[+0x18,+0x1018)`**.
+- `0x401380..0x401390`: call `sub_402300(index, R8+0x10, 0xff0, R8)`;
+ reject when it returns zero. Inside `sub_402300` the signed code obtains
+ a SYS_DRV crypto object, calls service-1 `0x10` on the `0xff0`-byte
+ `R8+0x10` portion, and compares the computed first 16 bytes with `R8`
+ via `sub_402EB8` (bytewise XOR/OR). It releases objects on examined
+ paths. The modeled availability of keys/CCP and any ability to produce
+ such an authenticated prefix are **not established**.
+- `0x40152C..0x401544`: require `*(u32 *)(SP+0x34)==4`. This corresponds
+ to copied host **`+0x3c`**. `R0=*(u32 *)(SP+0x38)` corresponds to copied
+ host **`+0x40`**. Both are within the compared prefix; describing them
+ as independently attacker-settable would overlook the earlier gate.
+ The `0x301` request length is read from host **`+0x1018`** and its input
+ pointer is host **`+0x101c`**. These two fields are *outside* the
+ `0x1000`-byte compared prefix. OPM only checks nonzero length here, but
+ ASD `.163` then bounds length to `[0x30,0x1400]` and validates the
+ caller mapping.
+
+ASD `.163` `asd_srm_op_301` (`0xD0CED0`) further checks a stored SRM
+version bound, and `asd_srm_header_check` (`0xD0D0D4`) requires the input
+SRM's big-endian header bytes `input[2..3]` to equal OPM's `R0` from the
+compared prefix. It then performs format and cryptographic checks before
+storing the SRM and entering `asd_srm_sub_12EC4`'s multi-revocation loop.
+Thus the uncovered OPM payload range is **not** a signature bypass.
+
+## Conclusion / boundary
+
+A verified prefix (if legitimately available) can select a host-supplied
+length and SRM payload after its own check, but the prefix controls the
+expected SRM header value and ASD checks the signed content independently.
+No accepted multi-match SRM, OPM `.51` card build, naturally satisfied
+prefix, or live downstream effect is demonstrated. This static OPM path
+improves provenance for the separate conditional bug in
+`fw/CANDIDATE-ASD-163-SRM-MULTI-REVOCATION-BITMAP.md`; it does not
+justify invoking `0x301` on the card.
diff --git a/fw/AUDIT-SOS54-B5-DECLARED-SPAN-WINDOWS.md b/fw/AUDIT-SOS54-B5-DECLARED-SPAN-WINDOWS.md
new file mode 100644
index 0000000..a5db1c5
--- /dev/null
+++ b/fw/AUDIT-SOS54-B5-DECLARED-SPAN-WINDOWS.md
@@ -0,0 +1,31 @@
+# Signed sOS `.54` `SVC 0xB5`: coarse process windows, not per-request PTE proof
+
+The signed SYS_DRV `.54` validation helper `sub_E0DEF4` at
+`0xE0DEF4..E0DF5C` checks a caller pointer `R0` and **declared**
+length `R1`. It caps length at `0x10000000`, base at `0x40000000`,
+requests window bounds via `SVC 0xB5`, and accepts if the computed
+end fits one returned window (or an additional fixed private range).
+The caps prevent 32-bit carry in base+length on this route. It does
+not pass the length the *leaf will actually read or write* to sOS.
+
+Signed sOS `.54` `sub_59E8` switch case `181-81=100` calls
+`sub_27F8(current_process_index, output_window_struct, selector)`
+after its request check. Raw `sub_27F8` tests the current PCB type
+and writes a small **process window descriptor**, without walking an
+individual pointer's PTEs. For type 5, its primary length is
+`0x800000`; selector 1 supplies primary base `0x400000`, while the
+other selector obtains the PCB base at `+0x18`. The optional second
+window has size `0xE00000` when a selected peer context exists, and
+otherwise is disabled; selector 1 uses base `0xD00000` when enabled,
+while the other uses the peer PCB base. Type 2 and types 4/6 take
+other coarse window branches. The sOS process index and peer selector
+come from signed context—not arbitrary caller bytes in the
+SYS_DRV leaf.
+
+**Consequence for short-span candidates:** `0x1063`, `0x106A`,
+`0x107B` and other SYS_DRV leaves may pass this coarse check using
+only a four-byte declared span, then access beyond it. This static
+observation does **not** establish that those later bytes are mapped
+on the RX 7900 XTX, belong to another client, or can be restored.
+Whole-span live sOS PTEs, actual GCP command-buffer VA and independent
+target-effect evidence remain open. No hardware request was issued.
diff --git a/fw/AUDIT-SOS54-RESOURCE0-SIGNED-BOOT-MODEL.md b/fw/AUDIT-SOS54-RESOURCE0-SIGNED-BOOT-MODEL.md
new file mode 100644
index 0000000..adbc27c
--- /dev/null
+++ b/fw/AUDIT-SOS54-RESOURCE0-SIGNED-BOOT-MODEL.md
@@ -0,0 +1,59 @@
+# sOS `.54` resource 0 at modeled ASD→GCP load order
+
+**Read-only full-system emulator observation; not a card resource-state
+measurement or a connected `SVC 0x6C` run.**
+`python3 psp_emu/harness/probe_sos54_resource0_model.py` booted signed
+sOS `.54`, loaded signed ASD `.163`, then GCP `.77` in the same modeled
+order used by earlier mapping scouts. sOS `sub_6870` reads its resource
+root through private word `0x8170`; after ring setup it held VA
+`0x113000`. A raw Unicorn `mem_read(0x113000)` failed because host
+reads bypass the modeled CPU MMU. Translating through the emulator's
+live TTBR0 gave **model PA `0x04050000`**, allowing a **read-only**
+inspection of the indexed descriptor-pointer presence without printing
+resource contents:
+
+| Sampling point | modeled table count | nonnull descriptor slots | ID 0 | ID 31 |
+|---|---:|---:|---|---|
+| after ring init | 1 | 1 | assigned | absent |
+| after ASD load | 3 | 2 | assigned | absent |
+| after GCP load | 4 | 3 | assigned | absent |
+
+A second read-only pass resolved ID 0's descriptor through the same
+modeled TTBR0 at each sample. It consistently contained **one
+segment of 4096 bytes**, descriptor second word `8192`
+(`sub_3A84` initializes it to 4096 then adds segment length),
+and descriptor `+12` owner byte **0**. The descriptor appeared with the 4096-byte
+host-supplied ring setup (`RING_SZ=0x1000` in
+`psp_emu/harness/boot_and_mailbox.py`) before ASD/GCP load, but its
+underlying page and consumer were **not independently matched** to
+the host ring: this is temporal/size evidence, not proof of ring
+ownership on the card. Signed sOS `sub_2F4C` initializes the
+resource table empty; SVC dispatch case 26 (preceding `SVC 0x6C`
+case 27) calls `sub_3A04 → sub_3A84`, which allocates the first free
+ID and records a descriptor. The read-only sample does not prove
+which signed caller created ID 0.
+
+All three signed load/ring steps returned normally in this model.
+The first version of the scout failed to read the **virtual** root
+through raw Unicorn memory; it produced **no** allocation conclusion.
+The corrected translation is an emulated PA, not a silicon PTE or
+memory snapshot. The table's count is not the same as its number of
+nonnull descriptor slots.
+
+**Effect on earlier candidate:** an *initially absent* resource-0
+assumption is **contradicted by this boot model**, though the card
+could differ. Separately, isolated signed SYS_DRV `.54` init had all
+16 private slot-owner bytes zero, so free `0x1001(0)` requested sixteen
+captured `SVC 0x6C(0)` calls; its test intercepted sOS and did not
+run kernel teardown. Signed sOS `.54` `sub_6828` drops a teardown
+status and `sub_6870` clears an allocated resource descriptor before
+return. If a real first `SVC 0x6C(0)` both reaches that leaf and
+successfully releases resource 0, later repeated requests could
+encounter the **absent-resource** dereference shown in the separate
+synthetic sOS test. This is a **conditional cross-model inference**,
+not a connected execution: successful first release, other kernel
+cleanup and card recovery are unverified. When resource 0 is
+allocated, the *first* release may itself be destructive; no such
+request was made on the card. See
+`fw/CANDIDATE-SOS54-6C-ABSENT-RESOURCE-DEREF.md` and
+`fw/CANDIDATE-GCP-SYSDRV-1001-SELECTED-IDENTITY-BULK-CLEANUP.md`.
diff --git a/fw/AUDIT-SOS54-SERVICE-REGISTRY-4-15.md b/fw/AUDIT-SOS54-SERVICE-REGISTRY-4-15.md
new file mode 100644
index 0000000..fff2aeb
--- /dev/null
+++ b/fw/AUDIT-SOS54-SERVICE-REGISTRY-4-15.md
@@ -0,0 +1,23 @@
+# sOS `.54` services 4–15: registration provenance in the available signed ELF corpus
+
+**Static scope, no new card probe.** This closes a *corpus-specific registration inventory*, not live-card service availability or all possible signed firmware images. In particular, an emulator table `[0,1,0,…]` previously observed at `0xE4A8` is **not** the card table: real GCP→ASD service-2 calls succeeded.
+
+## Signed sOS mechanism
+
+`sub_22B4` (`SVC 0xF2`) reads a byte from the 16-entry service table at `0xE4A8`: ID `>=16` is rejected (46), a zero entry is unregistered (47). Service 1 is permission-exempt. Other populated slots require caller cap bit `0x80`; service 3 additionally requires type 1. Thus a type-5 GCP caller could in principle address a *registered* service 4–15, subject to its message/stack-window and target process state. No evidence here grants GCP any new service.
+
+The sole signed writer found by xrefs to `0xE4A8` is `sub_47C0`, reached through `SVC 0x74` (sOS `sub_59E8` case 35). Raw code validates the target process with `sub_1978`, bounds service ID `<16`, and writes `table[service_id]=process_id`; it does not enumerate live registrations. In sOS `.54`, the two real `SVC 0x74` sites are loader `sub_15F24:0x167A0` (register) and unload `sub_17CA4:0x17D06` (R1 is zero; deregister). The loader derives the service ID through `sub_141AC`'s signed `amd.dr.driverID` property and registers it only on the driver-image path. Ordinary TA path sets the candidate driver ID to zero instead. Independently proving trust in signed metadata and the live set of loaded drivers requires separate evidence.
+
+## Reproducible signed-ELF survey
+
+`python3 fw/scan_service_registrations.py psp_out/elf psp_out/versions_win/elf_all` scanned **144** local ELF paths, halfword-aligned executable spans for the `SVC #0x74` bytes and strict 24-byte TLVs (`amd.dr.driverID\0`, type 1, 4-byte value) for declared driver IDs. Results:
+
+* **20** byte hits, all in **10 sOS ELF paths**, two per image. Both hits in signed sOS `.54` were verified as real instructions in loader/unload disassembly. A byte scan is not a CFG proof for every older build.
+* **30** driver-ID TLVs, all **value 2**, all in ASD ELF paths (including signed `asd_33.0.0.163_18debcc4.elf`, at file offset `0x177D`). No property for service ID 4–15 appears in these two extracted-ELF trees.
+* The signed SYS_DRV `.54` extracted ELF lacks this property; sOS's boot service-1 registration must not be inferred from the absence of an ELF TLV. The property scan does not inspect signed container metadata not present in an ELF or images outside these trees.
+
+A further **filesystem-only** survey on the test host (no GPU access) examined all **117** `/root/psp/contall/*.bin` signed containers for the same exact property TLV. It found **17** validated driver-ID TLVs, all value **2**, all in `asd_*` containers; no other `amd.dr.driverID` string, malformed match, or non-ASD validated TLV appeared. This is a second local corpus, not a runtime table dump.
+
+An **expanded, read-only repository inventory** scanned all **239** `psp_out/**/*.elf` paths with `python3 fw/scan_service_registrations.py psp_out`, plus all **421** `psp_out/**/*.bin` files with the same strict TLV header/value check (the 32 `.bin` paths elsewhere in this repository had no `amd.dr.driverID` string). The ELFs yielded **46** valid driver-ID property hits, all **value 2**, all ASD-named paths; every SVC-`0x74` byte candidate was in an sOS-named path (including copies and a `test_sos54.elf` of unverified provenance). The BINs yielded **57** valid hits, again all value **2**. The one generically named file, `psp_out/ta_raw.bin`, contains the identifying string `AMD-TEE ASD Driver`; the other valid hits are ASD-named files. Other sOS BINs contain the property *name* without its strict property header, consistent with their loader's lookup constant, not evidence that sOS declares itself driver ID 2. This extension checks file bytes, **not** image signatures, CFG for all builds, compressed/encrypted metadata, or the card's live registration table.
+
+Consequently **no additional 4–15 service implementation is identified in the available local extracted ELFs or BINs**. It is *not* a finding that the live table entries are zero: live registrations, containers outside these surveyed directories, loads/unloads, and any unextracted drivers remain open. The recent GCP ROP gate-read fault (`fw/ATTEMPT-SYSDRV-53-LIVE-LOG-GATES-READONLY-FAULT.md`) specifically argues against a speculative card registry sweep with the same chain. No unsafe service registration was invoked.
diff --git a/fw/AUDIT-SOS54-SVC76-8E-CAPABILITY-FLOW.md b/fw/AUDIT-SOS54-SVC76-8E-CAPABILITY-FLOW.md
new file mode 100644
index 0000000..48320e4
--- /dev/null
+++ b/fw/AUDIT-SOS54-SVC76-8E-CAPABILITY-FLOW.md
@@ -0,0 +1,44 @@
+# Signed sOS `.54` capability check/grant for SYS_DRV high opcodes
+
+**Signed static ACL provenance; no live GCP capability-mask read or
+capability change.** SYS_DRV `.54` `sub_E05A24` checks its signed
+11-row opcode-range table before dispatch. The `0x3100..0x31FF`
+row at `0xE23398` requires mask **`0xFFFF0`**; an opcode outside
+listed ranges, including free `0x1079` and `0x1082`, requests
+**`0x10`**. The leaf supplies that mask to **sOS `SVC 0x76`** and
+accepts only a nonzero result. Signed sOS `.54` `sub_59E8` case
+**37** (`0x76-0x51`) returns
+`(requested_mask & ~process_flags[process_index]) == 0`, where
+`process_flags` is the indexed word table at `0xCA24` and the
+index is taken from sOS process context, **not the SYS_DRV RPC
+message**. The emulator's ordinary always-success SVC76 handler
+is not evidence of real caller rights.
+
+The signed capability **grant** path is different: sOS `sub_59E8`
+case **61** (`SVC 0x8E`) first requires the current process
+record's byte 0 to equal **1**, then calls `sub_44EC` with a target
+process index and requested mask. Raw `sub_44EC` checks target
+validity and ORs **only `mask & 0xFFFF0`** into its flags word at
+`0xCA24+8*target`. This does not let a type-5 GCP RPC choose a
+target index through `SVC 0x76`; no GCP access to the gated
+`SVC 0x8E` issuer was demonstrated. Signed `sub_1D5C` creates a
+process slot by setting its active/type bits on the existing word;
+the examined normal teardown `sub_2150` zeros **both** slot words
+before reuse. An alternate teardown that left stale rights was
+not found here, but lifecycle exhaustiveness is **not** claimed.
+
+**Consequence for recent leads:** within this paired signed build,
+`0x3105`, `0x3131` (the `0x1079` gate setter) and `0x3133` (the
+`0x1082` scalar setter) have the **same range-mask requirement**.
+The established direct GCP `0x3105` ACL rejection therefore argues
+against direct GCP access to either setter through the same
+sOS/SYS_DRV route; the synthetic privileged profile used in the
+`0x1079`/`0x1082` harnesses is **not** a GCP identity. This does
+not measure the live process flags or exclude a separate trusted
+issuer (signed sOS itself issues `0x3105` during TA loading).
+One free opcode reading a word that a privileged opcode writes
+is not automatically a sensitive disclosure.
+
+Active process slot/capability assignment, alternate sOS builds,
+indirect issuance and role of the target private scalars remain
+outside this scope. No card operation was performed.
diff --git a/fw/AUDIT-SOS54-SYSDRV-3105-TA-LOAD.md b/fw/AUDIT-SOS54-SYSDRV-3105-TA-LOAD.md
new file mode 100644
index 0000000..0d0f28b
--- /dev/null
+++ b/fw/AUDIT-SOS54-SYSDRV-3105-TA-LOAD.md
@@ -0,0 +1,58 @@
+# sOS `.54` provisioner for SYS_DRV `0x3105` per-TA crypto state
+
+**Scope:** signed static path and synthetic emulator only. No new hardware
+request or private state read. This corrects the mistaken inference that GCP's
+inability to call `0x3105` directly leaves its SYS_DRV state uninitialized.
+
+## Signed path
+
+- `fw/scan_rpc_opcode_immediates.py --opcode 0x3105 --literals
+ psp_out/elf psp_out/versions_win/elf_all` rescans every *halfword* of executable
+ ELF segments for a four-byte immediate (the earlier linear decode stopped
+ too soon and gave a **false negative**). It finds `MOVW R0,#0x3105` in
+ sOS `.54` at `0x12AF6` and in versioned sOS siblings. The only aligned
+ `0x3105` word hits are SYS_DRV role-table words (e.g. `.54` `0xE25FA8`).
+ This is a candidate scan, not a proof that indirect callers do not exist.
+- In signed sOS `.54` `sub_15F24`, the new-TA path gives `SVC 0x64` the
+ address of a one-byte stack slot at `0x16222..0x16226`, then checks the
+ returned index `< 0x20` at `0x1622C..0x16236`. The byte is loaded at
+ `0x164FA`, passed as the fifth argument of `sub_12AE0` at `0x16508`.
+ The branch for TA type 4/6 at `0x164E6..0x164F8` adjusts flags; it does
+ **not** bypass the call for type 5 (GCP). A second `sub_12AE0` callsite
+ exists at `0x16A16` and was not analyzed as a GCP loader path.
+- `sub_12AE0` constructs SYS_DRV service-1 opcode `0x3105` at
+ `0x12AF6..0x12AFE`, checks `sub_13358` (which invokes service-1
+ `0x103B` on first use), stores the four buffer/size arguments and the
+ slot byte into `msg[2..5]` and `msg[18]`, and issues `SVC 0xF2` at
+ `0x12B18`. A failed preparatory check or dispatch can prevent setup.
+- SYS_DRV `.54` `sub_E0E74C` is the `0x3105` leaf: with sizes 32/16 and
+ index `< 32`, it copies the two inputs to `0xEB1280 + 66*index` and sets
+ byte `+64` to one, byte `+65` to zero. This is the *same* per-caller flag
+ tested by `sub_E0E7B8` before `0x101C`'s output-clear operation.
+ Direct GCP access to `0x3105` is ACL-rejected, but sOS is a distinct
+ trusted issuer during TA loading. Successful GCP load is consistent with
+ provisioned state; it does not itself measure this flag on the card.
+
+## Bounded synthetic check
+
+`python3 psp_emu/harness/probe_sysdrv_101c_state_gate.py` on signed SYS_DRV
+`.54` passed its assertions. Isolated SYS_DRV init left caller-2 state bytes
+`00 00`; its **unhooked** gate returned `0xFFFF000B`. A direct call to the
+signed `0x3105` leaf with **public synthetic bytes** and slot 2 returned zero
+and changed the bytes to `01 00`. The next unhooked `sub_E0E7B8(2)` reached
+modeled CCP but stopped at **`CCPError: unsupported SHA type 12`**. This
+model failure proves neither card crypto success nor failure. The check
+bypasses sOS/SVC ACL, does not recreate TA loading, and does not invoke the
+oversized `0x101C` request.
+
+## Consequence / outstanding gate
+
+The isolated-emulator zero flag is **not** evidence that GCP's live slot is
+uninitialized. sOS provisioning makes the `0x101C` crypto prerequisite more
+plausible, but live slot state, successful gate completion, real PTE boundary,
+and controlled cross-allocation effects are **not proven**. The conditional
+wrapped-output candidate remains `fw/CANDIDATE-GCP-SYSDRV-101C-WRAPPED-OUTPUT-NULL-SOURCE.md`;
+do **not** probe its stateful oversized NULL-source path on hardware under the
+separate opcode-`0xD` authorization. Further work should first address the
+CCP-model gap or find an independent read-only live state oracle; do not infer
+success from this static path alone.
diff --git a/fw/CANDIDATE-ASD-163-1A2-LAST-CHANNEL-SWEEP.md b/fw/CANDIDATE-ASD-163-1A2-LAST-CHANNEL-SWEEP.md
new file mode 100644
index 0000000..d7ba425
--- /dev/null
+++ b/fw/CANDIDATE-ASD-163-1A2-LAST-CHANNEL-SWEEP.md
@@ -0,0 +1,61 @@
+# ASD `.163` `0x1A2`: group sweep omits last of 32 channel records
+
+**Conditional off-by-one callback omission in signed code, shown with
+synthetic channel records; no live HDCP/security effect.** The signed
+`0x1A2` dispatcher entry reaches `sub_D0AEB0` with selected channel
+`0..31`. For an active selected record at `0xD33510+92*channel`
+with `+8 != 1`, `+64 == 5`, and stored `+60 == channel`, raw
+`0xD0AF04..0xD0AF32` starts at the **first** record, sets remaining
+count to **31**, and advances by 92 bytes each iteration. Its group
+match requires an active record, equal `+20` key, and `+64 == 5`.
+Matching records trigger callback entries at
+`0xD0AF40/0xD0AF4E`. Exactly indices **0..30** are checked;
+index 31 is not. The selected record also has a separate final
+callback path, so this is specifically an omission when record 31
+is a *peer* of a different selected channel, not proof that direct
+`0x1A2(31)` is inert.
+
+`python3 psp_emu/harness/probe_asd163_1a2_last_channel_sweep.py`
+passed through the signed `.163` dispatcher with only synthetic
+active records and **intercepted ASIC/link callback callsites**.
+For selected channel 0, a planted matching record 30 reached the
+first captured sweep callback. Replacing it with an otherwise
+identical matching record 31 left only selected record 0 in that
+capture; 31 never reached it. Both runs reached the selected-channel
+final callback site and returned zero under stubbed callback results.
+Neither the callbacks nor a real protected session were executed.
+
+This is distinguishable from the earlier `0x1A9` sparse enumeration,
+`0x1AA` duplicate handling, and SRM multi-revocation cursor bugs:
+this loop is the `0x1A2` group teardown/status path over a
+**32-slot channel table**, not the SRM bitmap. Signed caller-ID and
+actual ownership are not compared in the immediate handler, but
+global management may be intended. Signed HDCP `.57` supplies a real client path: its command-14
+entry (`hdcp_TA_InvokeCommandEntryPoint` at `0x4013B4`)
+passes the request's first two inline words at `req+0xC` to
+`hdcp2_create_session` (`0x401E28`). The routine stores the
+first word as session `+4` and sends it to ASD `0x1A0` via
+`0x4044EA`. Its later session-teardown paths load that same
+`+4` word into the `0x1A2` wrapper at `0x404464`. The examined
+client does not cap this word at 30 before ASD dispatch. Signed
+ASD `0x100` itself admits index 31 and marks the 92-byte record
+active **before** its ASIC callback. For the measured ASIC-20
+variant, `sub_D08DAC` installs `field08` thunk `0xD050D1` →
+`asd_program_link_by_signal`; that signed descendant can set record
+`+64` to 5, but only under descriptor/signal and sometimes fixed
+fabric-read predicates. Type-1 descriptor callback `field80` instead
+sets `+64=6`. These paths show 31 is not barred at the *first*
+ASD/index check; they do **not** prove real hardware accepts a
+valid class/port combination for index 31 or yields the specific
+paired state. ASD `0x1A0` still requires active `+64=5`, and no
+live channel-31 admission is shown. Whether natural signed HDCP
+clients create an active peer at 31, produce the required `+60/+64`
+state, and depend on the omitted callbacks for security or
+availability is open. **Counterweight:** the separately audited
+`0x1A0` matching-peer loop also iterates indices 0..30 and `0x180`
+limits its selected index to 30, while other setters admit index 31
+(`fw/AUDIT-ASD-163-1A6-PEER-INDEX.md`). Index 31 could be
+reserved or intentionally excluded from *peer-group* operations;
+without its natural role, this is a conditional omission, not a
+proven security bug. No card request was made; do not create or
+tear down channels on hardware for a return code.
diff --git a/fw/CANDIDATE-ASD-163-1A9-SPARSE-ENUMERATION.md b/fw/CANDIDATE-ASD-163-1A9-SPARSE-ENUMERATION.md
new file mode 100644
index 0000000..2a337f0
--- /dev/null
+++ b/fw/CANDIDATE-ASD-163-1A9-SPARSE-ENUMERATION.md
@@ -0,0 +1,18 @@
+# ASD .163 `0x1A9`: sparse allocation table reports entries it did not copy
+
+**Status:** reproducible signed-dispatch logic bug under synthetic state; no hardware request or demonstrated security consequence. The preceding `0x1A7`/`0x1A8` calls here use **normal allocation and release**, not an out-of-window pointer or an owner-bypass payload.
+
+## Defect
+
+Signed service-2 `asd_dispatch` (`0xD013B8`) routes `0x1A9` through the raw Thumb jump table (`0xD016E0`) to `sub_D08CE8` (`0xD08CE8`), despite Hex-Rays printing `abort()` for this opcode. It validates a 160-byte caller output and a one-byte caller count pointer. It loads the global 32-bit allocation mask at `0xD33510+0xDF4` and live count byte at `+0xDF8`. At `0xD08D2A..0xD08D48` it conditionally copies five bytes when the **current position's** bit is set. At `0xD08D4A..0xD08D4E` it advances the position and **decrements the remaining count on every position**, even if no bit was set. It stops when that count reaches zero (`0xD08D26..0xD08D28`), then reports the unchanged global live count to the caller (`0xD08D54..0xD08D58`). Thus a hole before a live bit causes an advertised count with fewer (or zero) copied records. Correct enumeration would scan all 32 positions or decrement the remaining count only after copying an occupied slot.
+
+## Connected signed execution
+
+`python3 psp_emu/harness/probe_asd163_1a9_sparse_enumeration.py` passes. The signed dispatcher:
+
+1. `0x1A7` allocates two distinct five-byte records for synthetic channel 5, setting bitmap `0b11` and count 2.
+2. `0x1A9` correctly returns count 2 and both records when slots 0 and 1 are contiguous (positive control).
+3. `0x1A8` releases only slot 0 through its ordinary bitmap API, leaving bitmap `0b10`, count 1, and a verified live `FGHIJ` record in slot 1.
+4. `0x1A9` returns status 0 and **count 1** but copies **no** bytes: all ten checked output bytes remain the caller's `0xA5` marker. The slot-1 record remains intact in ASD's synthetic table.
+
+This is a silent API inconsistency, not an ASD-private disclosure or memory corruption: untouched output is the caller's own buffer. Signed clients that trust the reported count may consume stale caller data or miss active records; no such client behavior, real card state, or security-policy effect has been verified. A scoped IDA immediate search of signed HDCP `.52`, `.57`, and `.59` found direct `0x1A7/0x1A8` opcode sites in each (`.52`: `0x4019A0/0x401A5E`; `.57`: `0x40444C/0x404518`; `.59`: `0x4044D4/0x4045A0`), but **no direct `0x1A9` immediate** in any of the three. A broader `fw/scan_rpc_opcode_immediates.py --opcode 0x1a9 --literals psp_out/elf psp_out/versions_win/elf_all` pass over **144 extracted ELFs** likewise produced no direct Thumb immediate or aligned 32-bit literal candidate. This resynchronizing byte scan is not control-flow analysis and cannot rule out indirect/synthesized opcodes, unaligned literals, containers outside the corpus, or a live consumer. It limits only the currently demonstrated downstream impact. No `0x1A7`/`0x1A8`/`0x1A9` opcode was invoked on hardware because the setup and release alter global link state without a safe restoration oracle. See the separate ownership candidate in `fw/CANDIDATE-GCP-ASD-1A8-BITMAP-RELEASE-AUTHORITY.md` and table mapping in `fw/AUDIT-ASD-163-1A2-1C0-JUMPTABLE.md`.
diff --git a/fw/CANDIDATE-ASD-163-1AA-DUPLICATE-DROPS-TAIL.md b/fw/CANDIDATE-ASD-163-1AA-DUPLICATE-DROPS-TAIL.md
new file mode 100644
index 0000000..06c0ad2
--- /dev/null
+++ b/fw/CANDIDATE-ASD-163-1AA-DUPLICATE-DROPS-TAIL.md
@@ -0,0 +1,82 @@
+# ASD `.163` `0x1AA`: first duplicate silently discards later unique IDs
+
+**Status:** signed-code logical defect with synthetic signed-dispatch controls.
+No accepted signed SRM, naturally routed signed client, live HDCP victim or
+hardware effect. The final stateful revocation sweep was stubbed in the
+test; do **not** invoke `0x1AA` on the card for a return code.
+
+`asd_dispatch` (`0xD013B8`) zero-extends `msg[2]` to an unsigned byte and
+calls `sub_D0B550(msg[1],count)` at `0xD016EA..0xD016EE`. The leaf rejects
+null/invalid pointers, zero count, or `global_count+count>32` and validates
+160 caller-input bytes. Its global five-byte ID list begins at
+`0xD33510+3284` with count byte at `+3577`. When that list is nonempty,
+`sub_D0B550` initializes `v13=1` **once, before the outer loop over all
+incoming IDs**. If an ID matches a pre-existing entry, the branch to
+`LABEL_15` sets `v13=0`. The flag is **not restored** before the next
+incoming ID, so every later non-matching ID skips the only append branch;
+status still returns zero. The compare loop also uses the **pre-call** `global_count` to decide how
+many existing entries to examine; newly appended IDs are omitted from
+comparisons later in the **same batch**. Thus an incoming batch containing
+the same new ID twice appends it twice and inflates the count. This is a
+second, separately controlled logical failure in the same signed loop.
+
+`python3 psp_emu/harness/probe_asd163_1aa_duplicate_tail.py` passed
+on the signed `.163` dispatcher/leaf. With an initial synthetic list
+`ABCDE`:
+
+| second request | returned / retained list |
+|---|---|
+| unique `FGHIJ` | 0 / `ABCDE,FGHIJ` (positive control) |
+| duplicate `ABCDE`, unique `FGHIJ` | 0 / **`ABCDE`** (unique silently lost) |
+| unique `FGHIJ`, duplicate `ABCDE`, unique `KLMNO` | 0 / **`ABCDE,FGHIJ`** (`KLMNO` silently lost) |
+| unique `FGHIJ`, repeated `FGHIJ` | 0 / **`ABCDE,FGHIJ,FGHIJ`** (duplicate counted twice) |
+
+A private-pointer negative returned 2 without modifying the list. Only
+`sub_D08404` (the final revocation sweep that can tear down existing
+channels) was stubbed in this **list-only** test; no ASIC/fabric state was
+exercised.
+
+A second **connected signed-flow** test,
+`python3 psp_emu/harness/probe_asd163_1aa_alloc_cleanup.py`, allocates a
+single synthetic channel-6 `FGHIJ` record via signed dispatcher `0x1A7`,
+seeds `ABCDE` through `0x1AA`, then lets the **signed `sub_D08404` sweep
+run**. With sole `FGHIJ` as the next input, its signed HDCP2 bitmap/count
+fall `1/1→0/0` and the teardown callback is visited once. With
+`ABCDE,FGHIJ`, signed `0x1AA` returns zero but retains only `ABCDE`; the
+same signed sweep visits **no** teardown callback and leaves bitmap/count
+`1/1`. This links the list bug to modeled allocation bookkeeping while
+stubbing only the stateful `sub_D0AEB0` teardown/ASIC effects (the stub
+returns failure 9; the signed sweep ignores it and still clears the bit
+in the positive control). The separate authority/error-order implications
+are in `fw/CANDIDATE-GCP-ASD-1AA-UNOWNED-REVOCATION-AND-FAILED-TEARDOWN.md`.
+Both the
+channel and list entries are synthetic; there is **no** signed-SRM
+acceptance or live authenticated HDCP session.
+
+The **signed allocator's own blacklist check** provides a second
+independent consumer. `0x1A7 → sub_D0AD2C` calls `sub_D0AE50`, which
+compares each requested five-byte ID to this `0x1AA`-maintained list and
+returns **23** on a match (then rolls back its output bitmap). A third
+connected test, `python3 psp_emu/harness/probe_asd163_1aa_allocator_blacklist.py`,
+started with `ABCDE`. Appending sole `FGHIJ` made a subsequent signed
+`0x1A7(FGHIJ)` return **23**, with allocation bitmap/count `0/0`.
+Appending `ABCDE,FGHIJ` instead returned zero from `0x1AA` while dropping
+`FGHIJ`, and the same signed `0x1A7(FGHIJ)` returned **0**, allocating
+bitmap/count `1/1`. Only the `0x1AA` sweep was stubbed in that test;
+this establishes a conditional **ID-admission mismatch** in signed
+emulation, not a valid SRM, natural trusted-client batch, live banned ID,
+or HDCP bypass. GCP could simply omit a chosen ID in its own malicious
+list request, so independent security impact requires a legitimate
+producer of duplicate-bearing batches or another enforced update source.
+
+A scoped
+halfword-resynchronizing scan across the extracted signed ELF corpus found
+no **direct** `MOVW/ADDW` candidate **or aligned executable literal** for
+`0x1AA` outside ASD (`fw/scan_rpc_opcode_immediates.py --opcode 0x1aa
+--literals`). This does not exclude computed opcodes, non-executable data
+references, unsearched images or a false-negative decoder, and does not
+prove natural caller provenance.
+GCP's access to service 2 is independently demonstrated for other
+opcodes, but this stateful opcode was not invoked on hardware. Actual ID source, active-client ownership, accepted SRM linkage and
+hardware/security impact remain open. This bug is distinct from `0x1A9` sparse enumeration and the
+signature-gated SRM multi-revocation cursor defects.
diff --git a/fw/CANDIDATE-ASD-163-SRM-MULTI-REVOCATION-BITMAP.md b/fw/CANDIDATE-ASD-163-SRM-MULTI-REVOCATION-BITMAP.md
new file mode 100644
index 0000000..4c539cd
--- /dev/null
+++ b/fw/CANDIDATE-ASD-163-SRM-MULTI-REVOCATION-BITMAP.md
@@ -0,0 +1,28 @@
+# ASD .163 SRM update: both HDCP1 and HDCP2 multi-revocation cleanup loops fail to rewind bitmap cursors
+
+**Status:** signed-code logic defect exercised under synthetic state with the ASIC link callback stubbed (the signed channel-state helper runs); **not a hardware trigger, valid signed SRM, or HDCP authorization bypass**. This is distinct from the `0x1A8` unchecked release and `0x1A9` sparse enumeration defects.
+
+## Reachability, conditional gate, and root cause
+
+Signed `.163` `asd_srm_op_301` (`0xD0CED0`) accepts `0x30..0x1400` caller bytes, checks the caller region, snapshots them to its stack, and calls `asd_srm_header_check` (`0xD0D0D4`). **Only on a zero header/crypto-check result** does it store the SRM and call `asd_srm_sub_12EC4` (`0xD0CB70`) at `0xD0CF42`. Opcode `0x308` has a separate signature-gated candidate but **does not call this helper**: IDA call xrefs to `0xD0CB70` show only `asd_srm_op_301` at `0xD0CF42`. The existing host-to-HDCP `0x308` route therefore does not establish a host route to this cleanup defect. Nothing here bypasses either cryptographic gate. No valid signed SRM or live accepted update was obtained.
+
+The update helper scans **two distinct** ASD-global link tables. The HDCP1/`0x18E` 128-slot bitmap and count are at `0xD33510+0xFFC/+0x100C`; its five-byte records start at `+0x100D`, and channel annotations at `+0xDFC`. The HDCP2/`0x1A7` 32-slot bitmap and count are at `+0xDF4/+0xDF8`; records start at `+0xC34`, and annotations at `+0xD74`. Both scans compare occupied five-byte records to the SRM, queue IDs whose channel state at `base+92*owner+88` is nonzero, and invoke their respective ASIC/link callbacks **before** bitmap cleanup.
+
+**Both cleanup loops have the same cursor defect.** In the HDCP1 128-slot loop, the mask for a bitmap word loads at `0xD0CC34` and slot cursor `R4`/bit cursor `R12` advance at `0xD0CC78..0xD0CC8A`; when `0xD0CC94` increments the queued-ID index `R6`, control returns to `0xD0CC3C` **without rewinding** the mask/cursors for that ID. The HDCP2 loop loads the mask into `R4` and initializes slot/bit cursors once (`0xD0CD06..0xD0CD1A`), advances them at `0xD0CD56..0xD0CD5A`, then increments queued-ID index at `0xD0CD66` without rewinding. A second queued revocation can therefore run its link callback and clear channel state while its record's allocation bit remains set. This is a state/bookkeeping mismatch, **not** a demonstrated persistence or secret disclosure.
+
+## Bounded connected synthetic evidence
+
+`python3 psp_emu/harness/probe_asd163_srm_multi_revocation.py` passes. It lets the **signed dispatcher** allocate distinct synthetic records for channels 5 and 6 through opcode `0x1A7`, producing bitmap `0b11` and count 2. It plants an **unsigned synthetic** SRM v9 record list directly in isolated ASD RAM (bypassing any acceptance/signature claim), and enters the signed `asd_srm_sub_12EC4` helper. It observes but **executes** the signed `sub_D0B438` state helper, verifying it clears the matched channel's `+88` field. It stubs only `sub_D0AEB0` *at entry* to avoid ASIC/fabric effects, recording visits. The signed record match and bitmap cleanup instructions run unmodified.
+
+* One match for slot 1: one signed state-helper call and one stubbed ASIC callback; returns with bitmap `0b01`, count 1. This positive control proves the helper can clear slot 1 when it is the sole match.
+* Two matches at slots 0 **and** 1: two signed state-helper calls clear both channel-state words and two ASIC callback entries are stubbed; returns with bitmap `0b10`, count 1. The second revoked ID was queued but its bit remained set.
+
+A separate `python3 psp_emu/harness/probe_asd163_srm_hdcp1_multi_revocation.py` check now passes for the **HDCP1** table. Signed `0x18E` allocates two records for synthetic channels 5/6 (bitmap `0b11`, count 2); the HDCP1 v9 matcher reverses their five-byte order in the planted **unsigned** SRM. A sole slot-1 match clears bit 1 (bitmap `0b01`, count 1). With both matches, **both** signed state-helper calls and **both** stubbed HDCP1 ASIC callback entries (`sub_D0A7A8`) occur, but cleanup leaves bitmap `0b10`, count 1. The earlier HDCP2 check stubs the different callback `sub_D0AEB0`. These controls show two distinct signed bookkeeping loops, not a single shared callback artifact.
+
+The stubbed ASIC callbacks and directly planted unsigned SRMs are important limits: real callbacks may change link or global state and a signed SRM must pass the gate before either helper path executes on hardware. An IDA scan found **no direct `0x301` opcode immediate** among signed HDCP `.52`, `.57`, or `.59` functions. A *broader corrected halfword scan* has now identified a **signed OPM `.51` producer and conditional host-data route**, described below. Signed HDCP `.52` also uses **`0x18E`** for HDCP1 session allocation and **`0x18F`** for teardown/close-all, establishing a real signed client for the newly exercised HDCP1 table (`fw/CANDIDATE-GCP-ASD-18F-BITMAP-RELEASE-AUTHORITY.md`). It is not an active-build or concurrent-card-session proof. No SRM update, `0x1A7`, or privileged write was sent to the card. A valid accepted multi-match SRM, active-build/host-route confirmation, live cross-client victim, and independent effect/restoration oracle are still required before impact or a card experiment can be justified.
+
+## Signed OPM `.51` host-data producer — new scoped correlation
+
+`fw/scan_rpc_opcode_immediates.py --opcode 0x301 --literals psp_out/elf psp_out/versions_win/elf_all` found direct opcode immediates in OPM `.51`, `.57`, `.60`, `.62`, `.63`, `.66`, `.69`, `.71`, `.81`, and `.4.47/.4.48` (plus an unrelated FP `ADDW` candidate). In IDA, OPM `.51` `opm_asd_rpc_301` at `0x402E5E` definitively stores `0x301` to `req[0]` and executes `SVC 0xF2` with service ID 2. Its only direct call is `0x401544` in the cmd-8 path. At `0x40152C..0x401544`, a status word must equal 4; nonzero length is loaded from `[R7+0x1018]`, and the data pointer is `R7+0x101C`. The existing `fw/AUDIT-NEW-TAS-RE.md` traced `R7` in this **separate** cmd-8 function (`0x401320`; IDA merges its boundary) to the host params page, and established an invoke-time `params_size >= 0x3D54` gate. Thus a signed OPM caller can forward host SRM bytes and a host-supplied length to ASD `0x301` **after prior OPM gates**; this corrects the earlier implication that only an unknown GCP/HDCP route could reach the opcode. Critically, OPM first compares a SYS_DRV-derived 16-byte result against a host prefix covering `params+0x18..+0x1017`: the status word at `+0x3C` and scalar at `+0x40` lie inside this compared block, while the `0x301` length at `+0x1018` and data at `+0x101C` lie outside it. A host able to submit arbitrary bytes cannot be assumed to satisfy the prefix comparison; ASD independently validates the signed SRM, including matching its header `input[2..3]` to that compared scalar. See `fw/AUDIT-OPM51-ASD301-AUTH-BOUNDARY.md`.
+
+This does **not** show that any naturally available prefix or supplied bytes satisfy OPM's first comparison and `.163` `asd_srm_header_check`'s signed/crypto gate, that any real SRM revokes two live records, or that OPM `.51` is the card's active build. The older OPM audit assessed the **bounded `0x1400` stack copy**, not this downstream multi-revocation bookkeeping fault. Newer OPM immediate hits have not had their host-flow or card-build compatibility independently verified. Neither this static route nor the unsigned synthetic SRM is an authorization to write a live SRM.
diff --git a/fw/CANDIDATE-GCP-ASD-100-ERROR-RETURN-ACTIVE-RECORD.md b/fw/CANDIDATE-GCP-ASD-100-ERROR-RETURN-ACTIVE-RECORD.md
new file mode 100644
index 0000000..e715582
--- /dev/null
+++ b/fw/CANDIDATE-GCP-ASD-100-ERROR-RETURN-ACTIVE-RECORD.md
@@ -0,0 +1,41 @@
+# ASD `.163` `0x100`: type-1 callback error leaves active type-6 record
+
+**Signed-code partial-state defect, reproduced in isolated signed
+dispatch with synthetic descriptor and installed ASIC-20/25 callback.
+No card session, accepted hardware link, or cross-client effect.**
+
+`0x100 → sub_D0B66C` bounds the channel to 0–31 and validates
+its 64-byte descriptor. It writes `record[+4]=1`, copies descriptor
+word 0 into `record[+8]` and copies other fields **before** invoking
+callback slot 769 if descriptor word 0 is 1. ASIC-20/25 startup
+`sub_D08DAC` installs slot 769 thunk `0xD10441 →
+asd_state_not_1_cfg0` (`0xD10FD4`). That signed callback writes
+record `+76=5`, `+64=6` and `+68=4` on a non-1 private startup
+predicate `*(u32 *)0xD29108`, then **returns 1**. If predicate is 1,
+it writes `+68=2` and returns 0. `sub_D0B66C` returns the callback
+result without clearing the active/type fields on error. This is a
+persistent *record state in the isolated model*, not a demonstrated
+live protected session.
+
+`python3 psp_emu/harness/probe_asd163_100_type1_error_record.py`
+passed through signed `0x100` dispatch. With a planted type-1
+descriptor and a synthetic installed signed slot-769 thunk,
+predicate 0 returned **1** but left
+`(+4,+8,+64,+68,+76)=(1,1,6,4,5)`; predicate 1 returned **0**
+and left `(1,1,6,2,5)`. There were no emulated faults. The test
+starts without a full ASIC boot or valid channel/fabric descriptor.
+A prior fresh-boot **card read** found the predicate
+`0xD29108==1` at that point, so predicate-0 is **not** the measured
+fresh-boot state; later transitions and other callback failures
+remain unverified. Signed DTM `.19` host commands 2/4 are an
+independent producer of ASD `0x100` with descriptor word 0 from
+the host request (`fw/AUDIT-DTM19-ASD100-TYPE1-PRODUCER.md`);
+this does **not** demonstrate that a live host supplies type 1
+when the failure predicate holds. No hardware command was issued for this test.
+
+Subsequent first-level `0x1A1` checks an active record and record
+`+8==1` before the ASIC status/callback gates. This does **not**
+show that an error-left-behind record passes slot 770, becomes a
+valid HDCP victim, reaches entropy generation, or harms a second
+client. Other `0x100` callback variants and record reuse are not
+closed. Do not create/fail live links merely for a status code.
diff --git a/fw/CANDIDATE-GCP-ASD-101-OWNERLESS-RECORD-ERASE.md b/fw/CANDIDATE-GCP-ASD-101-OWNERLESS-RECORD-ERASE.md
new file mode 100644
index 0000000..095ce67
--- /dev/null
+++ b/fw/CANDIDATE-GCP-ASD-101-OWNERLESS-RECORD-ERASE.md
@@ -0,0 +1,54 @@
+# ASD `.163` `0x101`: ownerless indexed channel-record erase
+
+**Status:** signed-code global-record destruction candidate, synthetic
+signed-dispatch proof. No victim channel on the card, independent hardware
+teardown effect, or exact restoration oracle. Do **not** invoke this
+stateful opcode on hardware merely for a return code.
+
+`asd_dispatch` (`0xD013B8`) routes service-2 `0x101` to `sub_D08C08`
+with just caller-selected `msg[1]` as its channel index. GCP→ASD service
+2 access has separately been demonstrated for other opcodes, but **this
+opcode was not invoked on the card**. The signed leaf checks only
+`index <=31` (`0xD08C08`), calls `sub_D0A7A8(index)` and
+`sub_D0AEB0(index)`, **ignores both results**, then zeroes exactly the
+selected 92-byte record at `0xD33510 + 92*index` via `bzero_core` and
+returns zero. There is no active-state, channel-owner, or requesting-TA
+identity check before the zero. The two helpers may change ASIC/link
+resources; this audit deliberately did not execute their real effects.
+A cleared channel may desynchronize other channels or global allocation
+tables, but that consequence was not demonstrated.
+
+`python3 psp_emu/harness/probe_asd163_101_ownerless_record_zero.py`
+compiled and passed using the signed `.163` dispatcher/leaf. It plants
+synthetic private records at channels 5 and 6 and intercepts only the two
+stateful helpers to return failure `0x1234`. Invoking channel 5 with
+synthetic caller scalar 2 returned zero, erased **all 92 marker bytes** in
+channel 5 despite both failed helpers, and left adjacent channel 6
+unchanged. Index 32 returned 5 with no helper visit or change. After
+replanting the synthetic record, caller scalar 7 produced the same erase.
+This proves the signed erase ordering and lack of caller binding at the
+reviewed leaf, **not** that either scalar corresponds to a real sOS
+service caller identity or that a live other-client record was hit.
+
+A **real signed DTM `.19` producer** confirms this opcode is used for
+topology removal, not merely a dispatch label. `dtm_sysdrv_rpc_101` at
+`0x4010DE` places `{0x101, channel}` on the stack and calls service 2
+through `SVC 0xF2` (`0x4010F2..0x4010F6`). DTM's signed `TA_InvokeCommandEntryPoint` (GP command 5) requires low
+paramTypes nibble 7, a nonnull buffer and declared size `>=0x50`; command
+IDs 2 and 4 route to `dtm_cmd_topology_update` and
+`dtm_cmd_topology_update_v2` with args at buffer `+16`. Both call the
+`0x101` wrapper with `req[0]` when `req[1]==0`
+(`0x40114A..0x40114C` and `0x4011A8..0x4011AA`); their nonzero
+`req[1]` branches issue `0x100` topology updates. This establishes a
+signed DTM invocation route, **not** a live build, arbitrary host access,
+or cross-process ownership proof. A
+global channel-erasure API may be intentional for a display manager;
+calling it from compromised GCP is not automatically a new ASD defect
+without a demonstrated boundary/impact distinction.
+
+Existing signed HDCP clients consume ASD channel state during link/auth
+operations, but a naturally active channel on the card, which process
+owns each index, and a safe victim readback/restoration procedure have not
+been established. The effect is a conditional cross-client integrity/DoS
+candidate, not a measured cross-client hardware fault. Do not infer
+arbitrary CPU-MMU writing or ASD code execution from an indexed zero.
diff --git a/fw/CANDIDATE-GCP-ASD-160-SRM-REVOCATION-STATUS-BYPASS.md b/fw/CANDIDATE-GCP-ASD-160-SRM-REVOCATION-STATUS-BYPASS.md
new file mode 100644
index 0000000..2c20690
--- /dev/null
+++ b/fw/CANDIDATE-GCP-ASD-160-SRM-REVOCATION-STATUS-BYPASS.md
@@ -0,0 +1,62 @@
+# ASD `.163` `0x160`: unowned link-state scalar gates both SRM revocation loops
+
+**Status:** signed-code cross-channel authority candidate plus synthetic
+signed-dispatch/SRM-helper evidence. Neither a signed accepted SRM nor
+another client's live channel, HDCP session, hardware revocation, or a safe
+restoration oracle has been established. Do **not** change a live channel
+on the card for a return code.
+
+`asd_dispatch` (`0xD013B8`) routes service-2 `0x160` to `sub_D0B438`
+(`0xD0B438`). It requires `msg[1] <=31` and an active record
+`*(u32 *)(0xD33510+92*msg[1]+4)==1`, then writes the **caller-supplied**
+`msg[2]` into that channel's `+88` word. It does not bind the record to
+the requesting TA or validate the scalar's semantics. GCP's access to
+ASD service 2 is established independently for other opcodes, not a
+hardware invocation of `0x160`.
+
+Signed SRM cleanup helper `asd_srm_sub_12EC4` (`0xD0CB70`) reads this
+same `+88` word after finding a revoked ID in either the HDCP1/`0x18E`
+128-slot table or HDCP2/`0x1A7` 32-slot table. **If it is zero, it skips**
+the channel-state helper, ASIC callback and bitmap/count cleanup for the
+matching entry. Thus an admitted caller able to set another active
+channel's word to zero can suppress cleanup for even a **single** matching
+ID. This is independent of the separate multi-match bitmap-cursor defect
+in `fw/CANDIDATE-ASD-163-SRM-MULTI-REVOCATION-BITMAP.md`. The meaning of
+`+88` as live HDCP/link state and whether earlier authenticators reject a
+zero state must be established before claiming an actual revoked session
+remains usable.
+
+A signed **HDCP `.57` producer** confirms that `0x160` is used by a real
+client rather than being only an ASD table label. Wrapper
+`0x40459C` stores `{0x160, channel, value}` on its stack and invokes
+`SVC 0xF2` with service ID 2. Direct calls at `0x40196E` and `0x40334A`
+use its session channel and value zero during teardown/close-all; at
+`0x401AB4`, `0x401AEE`, `0x401DDE`, `0x401E10`, and `0x402210` the value
+is also zero in HDCP1 authentication/error paths. This is **static client
+provenance**, not proof that `.57` is the live HDCP image or that the
+GCP-triggered setter reaches an HDCP-owned active record. The halfword
+opcode scan also found `.59` and later HDCP candidate immediates, but
+those other sites were not callsite-verified here. The same `.57` client
+also calls the `0x161` status-query wrapper (`0x40456E`) in HDCP1/HDCP2
+`get_encryption_status`. The signed `asd_link_sub_113A0` returns the
+`+88` word as its third output (for the examined type-1 branch, zero is
+returned directly), and these getters report encryption enabled only when
+that output is 3 and a further output is 1. **Clearing `+88` may therefore
+make the client report encryption *off***; this audit does not establish
+that protected traffic remains available or that revocation suppression
+is a practical content-protection bypass.
+
+`python3 psp_emu/harness/probe_asd163_160_srm_state_bypass.py` passed.
+For each table, it makes one allocation through the **signed** `0x18E`
+or `0x1A7` dispatcher, plants an **unsigned** single-ID match in synthetic
+ASD-private SRM RAM past the `0x301` signature gate, and stubs only the
+ASIC callback to avoid fabric effects. With synthetic active channel 5's
+`+88=1`, the signed cleanup helper calls that callback once and clears
+the bit/count (`1/1 -> 0/0`). With the same initial setup followed by a
+signed-dispatch `0x160(channel=5,value=0)`, the matcher leaves bit/count
+`1/1`, with **zero** callback visits. Both HDCP1 and HDCP2 controls passed;
+no planted victim was another live process.
+
+An accepted multi-client SRM, natural channel ownership, actual HDCP
+security outcome, and the live effect of `0x160` remain unresolved. This
+is a conditional revocation-integrity lead, not hardware-proven bypass.
diff --git a/fw/CANDIDATE-GCP-ASD-18F-BITMAP-RELEASE-AUTHORITY.md b/fw/CANDIDATE-GCP-ASD-18F-BITMAP-RELEASE-AUTHORITY.md
new file mode 100644
index 0000000..1859804
--- /dev/null
+++ b/fw/CANDIDATE-GCP-ASD-18F-BITMAP-RELEASE-AUTHORITY.md
@@ -0,0 +1,17 @@
+# ASD .163 service-2 `0x18F`: caller bitmap releases global link records without owner check
+
+**Status:** signed-code defect and connected synthetic dispatcher demonstration; **not invoked on hardware**. Cross-TA security impact, live allocations, and restoration are not established. This is a separate lead from the proven `0x20B` GCP-owned hardware store.
+
+## Signed path and missing authority check
+
+Image: `psp_out/versions_win/elf_all/asd_33.0.0.163_18debcc4.elf`. `asd_dispatch` (`0xD013B8`) routes opcode `0x18E` to allocator `sub_D0A634` and `0x18F` to release routine `sub_D0AAFC` (`0xD0AAFC`). The latter receives **only `req->arg1`**, a pointer to 16 caller bytes, not a channel id or allocation handle. It checks nonzero and `asd_validate_ptr(ptr, 0x10)` (`0xD0AB00..0xD0AB0E`). It uses all 128 caller-selected bitmap positions against the global allocation bitmap at `0xD33510+0xFFC..+0x1008`. When a global bit is set, instructions `0xD0AB48..0xD0AB5C` clear it and decrement global count at `base+0x100C`, without consulting the slot's stored channel id at `base+3580+4*index`. **Even when the global bit is unset**, `0xD0AB6A..0xD0AB7C` zero the corresponding five-byte record at `base+0x100D+5*index` (direct call to the five-byte zero helper); the global-bit check is *not* around this call. Thus the mask is an easily forged position, not a checked owner token.
+
+The signed `0x18E` allocator (`sub_D0A634`) accepts a channel index and stores that index at `base+3580+4*index`, allocates a bit, copies a five-byte record, and increments the global count. It validates its 640-byte input and 16-byte output and bounds the requested count to positive signed byte. The release routine does **not** read those owner entries. These are ASD-global link/resource records; their security significance and actual inter-client ownership policy need separate establishment. No CPU-MMU arbitrary write is implied: the destination is a fixed, bounded ASD table.
+
+## Connected signed-emulator evidence
+
+`python3 psp_emu/harness/probe_asd163_18f_cross_channel.py` passes. It first invokes **signed dispatcher `0x18E`**, allocating an actual table entry at index 0 for synthetic channel 5 with data `abcde`, then invokes signed `0x18F` using a caller-constructed `bit 0` mask: status 0, bit/count cleared, five bytes zeroed, while the stored channel id stays 5. An independent synthetic setup at index 7 (owner 5) shows the same effect with a different index and a neighboring-record control. An unset index 9 still has its five bytes zeroed by a forged bit; a private pointer in place of the 16-byte caller bitmap is rejected with status 2. This establishes signed handler behavior under **synthetic** caller-region and global-table mappings only. It does not prove a second live channel or card resource change.
+
+**Signed-client provenance, scoped to HDCP `.52`:** IDA confirms `hdcp_sysdrv_rpc_18F` (`0x4018DE`; despite its name it stores `req[0]=0x18F` and uses service **2**) is called in `hdcp_session_teardown` (`0x401D7C`), `hdcp1_first_part_authentication` cleanup (`0x401F48`), and `hdcp_close_all_sessions` (`0x403744`). The teardown and close-all callsites pass `session+0x40` as the 16-byte bitmap pointer. The signed `hdcp_TA_InvokeCommandEntryPoint` routes command **3** directly to HDCP1 first-part authentication (`0x40142E`) and command **`0x11`** to close-all (`0x4014B8`); valid session/setup prerequisites remain to be established. The companion `0x18E` wrapper (`0x4017B4`) is called by HDCP1 authentication (`0x401F7C`, `0x401FC2`, `0x4021C8`); at `0x401F7C` its R3 output pointer is likewise `session+0x40`. Thus this is **normal signed HDCP session bookkeeping**, not merely a planted synthetic table. It does not show an active `.52` build, a concurrent live session/bit index, or a security-policy consequence of invalidating a record. Caution: an unrelated `MOVW #0x20B` in HDCP `.52` is a 523-byte *message-length comparison*, not an ASD opcode; `fw/scan_rpc_opcode_immediates.py` reports candidates requiring IDA callsite verification.
+
+GCP ROP is already established to call service 2, but no `0x18E`/`0x18F` request was sent to the card: release changes global link state and lacks a safe live restoration oracle. A GCP attacker could name any bit position if that opcode reaches the same table on hardware; **cross-TA disruption remains a candidate**, not an observed effect. Do not attempt a live all-bits mask or release another client's slot without a known benign allocation, independent observation, and exact restoration.
diff --git a/fw/CANDIDATE-GCP-ASD-1A8-BITMAP-RELEASE-AUTHORITY.md b/fw/CANDIDATE-GCP-ASD-1A8-BITMAP-RELEASE-AUTHORITY.md
new file mode 100644
index 0000000..cc03e97
--- /dev/null
+++ b/fw/CANDIDATE-GCP-ASD-1A8-BITMAP-RELEASE-AUTHORITY.md
@@ -0,0 +1,21 @@
+# ASD .163 opcode `0x1A8`: a second unchecked global-bitmap release
+
+**Status:** signed-code behavior and connected **synthetic** dispatcher trace; not invoked on the card. Whether records are owned by distinct live TAs, and whether their loss changes live display/security state, remain unproven. This is a second global bitmap, separate from opcode `0x18F`'s 128-bit table.
+
+## Reachability and signed code
+
+The ASD `.163` `asd_dispatch` (`0xD013B8`) checks `rpc_id - 0x180 <= 0x40`, then dispatches via the signed `TBH [PC,R2,LSL#1]` at `0xD0143E`, table base `0xD01442`. For opcode `0x1A8`, table entry points to `0xD016D8`: it passes **only `msg[1]`** to `sub_D0B244` (`0xD0B244`). Hex-Rays' pseudocode for the dispatcher incorrectly shows `0x1A2..0x1C0` as `abort()`; raw table entries and the connected signed run below supersede that representation. See `fw/AUDIT-ASD-163-1A2-1C0-JUMPTABLE.md`.
+
+The sibling allocator, opcode `0x1A7` at `0xD016CA -> sub_D0AD2C`, accepts a channel index, a 160-byte caller record buffer, a byte count, and a 4-byte caller bitmap output. It checks index `<= 0x1F`, caller pointers, and global count + requested count `<= 32`. For an allocated position it sets the global mask at `0xD33510+0xDF4`, increments count at `+0xDF8`, writes a five-byte record at `+0xC34+5*index`, and stores the supplied channel index at `+0xD74+4*index` (`STR` at `0xD0AE04`).
+
+Release `sub_D0B244` rejects a null or non-caller-window pointer with `asd_validate_ptr(ptr,4)` at `0xD0B246..0xD0B250`, then uses **the caller's bitmap bits** to clear matching global mask bits and decrement count (`0xD0B266..0xD0B282`). It receives no channel index and does not consult the channel annotation at `+0xD74`. It clears selected bits in the caller bitmap even if already free. Unlike `0x18F`, it leaves the five-byte record and channel annotation intact. Thus a forged position can release bookkeeping for another channel and leave stale metadata; this is not an arbitrary CPU-RAM write.
+
+## Executed synthetic evidence
+
+`python3 psp_emu/harness/probe_asd163_1a7_1a8_bitmap_release.py` passes: the signed dispatcher first allocates a five-byte `abcde` entry for synthetic channel 5 with `0x1A7`, setting global mask and count to 1, output bit 0, and stored channel annotation to 5. It then dispatches `0x1A8` with a caller-writable bit-0 mask: status 0; global mask/count and caller mask become 0; record `abcde` and annotation 5 remain. A private bitmap pointer is rejected with status 2 as a negative validator control. The invocation proves the raw hidden table path runs; emulator global state and caller region are synthetic, not card observations.
+
+## Potential separate signed client
+
+Signed HDCP `.52` (`psp_out/versions_win/elf_all/hdcp_23.0.0.52_c6b25da3.elf`) contains real service-2 wrappers: `hdcp_sysdrv_rpc_1A7` at `0x401988` places opcode `0x1A7` and all four args in its message then executes `MOVS R0,#2; SVC 0xF2` at `0x4019B2..0x4019B4`; `hdcp_sysdrv_rpc_1A8` at `0x401A50` places opcode `0x1A8` and executes the same service call at `0x401A64..0x401A68`. Signed HDCP2 RX routines `hdcp2_rx_AKE_Send_Cert` and `hdcp2_rx_RepeaterAuth_ReceiverID_List` call the allocator while processing receiver IDs, and the latter and session teardown call the release wrapper. This establishes an independently signed **prospective producer** of these records, not a measured concurrent, retained HDCP object on the card or a proven HDCP authentication bypass. The active HDCP build, compatible ASD/HDCP pairing, actual host route, and inter-TA ownership policy remain unresolved.
+
+GCP ROP is proven to invoke ASD service 2, but neither `0x1A7` nor `0x1A8` was sent to hardware. Global allocation/release is stateful: no independent live owner/resource readback or exact restoration oracle exists. Do not try a live forged mask or all-bits release for a mere handler return. Compare the separate 128-bit, unconditional-record-clear case in `fw/CANDIDATE-GCP-ASD-18F-BITMAP-RELEASE-AUTHORITY.md`.
diff --git a/fw/CANDIDATE-GCP-ASD-1AA-UNOWNED-REVOCATION-AND-FAILED-TEARDOWN.md b/fw/CANDIDATE-GCP-ASD-1AA-UNOWNED-REVOCATION-AND-FAILED-TEARDOWN.md
new file mode 100644
index 0000000..4077af1
--- /dev/null
+++ b/fw/CANDIDATE-GCP-ASD-1AA-UNOWNED-REVOCATION-AND-FAILED-TEARDOWN.md
@@ -0,0 +1,45 @@
+# ASD `.163` `0x1AA`: global ID update can retire another channel's allocation
+
+**Status:** conditional authority/error-order candidate. Signed code and
+connected synthetic allocation/sweep evidence; no live second client,
+accepted signed SRM, natural `0x1AA` producer, ASIC effect, or hardware
+restoration oracle. **Do not** invoke this stateful opcode on the card
+merely to see a return value.
+
+The service-2 dispatcher routes `0x1AA` to `sub_D0B550(input160,count)`.
+Its checked caller pointer and `global_count+count<=32` gate do **not**
+include a channel/TA owner. On status success it invokes
+`sub_D08404`, which scans all IDs in the ASD-global `+3284` list against
+all occupied entries of the HDCP2/`0x1A7` global allocation table. For a
+matching ID whose selected channel `+88` state is nonzero, the signed
+sweep can zero that state, call the stateful `sub_D0AEB0(channel)` link
+teardown, and clear the global bitmap/count. It does not compare an
+originating TA identity to the stored channel annotation. `sub_D08404`
+also **does not check `sub_D0AEB0`'s return** before clearing the
+allocation bit/count: a failed link/ASIC teardown can leave bookkeeping
+claiming the entry is gone. That is an emulator-supported signed-code
+error-order discrepancy, not a measured hardware desynchronization.
+
+`python3 psp_emu/harness/probe_asd163_1aa_alloc_cleanup.py` passes with
+signed dispatcher `0x1A7` allocating synthetic channel 6 / ID `FGHIJ`
+under a synthetic caller scalar 2; signed `0x1AA` updates use scalar 7.
+When the input includes `FGHIJ`, the signed `sub_D08404` loop visits
+`sub_D0AEB0` and clears bitmap/count `1/1 → 0/0` despite the **only
+intercepted helper** returning modeled failure 9. A duplicate-first
+`ABCDE,FGHIJ` input triggers the separate `0x1AA` dedup bug: `FGHIJ` is
+dropped, so the sweep does not visit teardown and bitmap/count remain
+`1/1`. The caller scalars are synthetic register inputs, **not verified
+sOS caller identities**; the channel, ID and state word are synthetic.
+The distinction establishes signed handler ordering and selected global
+bookkeeping, not a real cross-process fault or authentication bypass.
+
+`0x1AA` is the only direct signed-image caller of `sub_D0B550` found in
+IDA; a scoped signed-ELF scan found no direct external opcode immediate
+or aligned executable literal. Computed/indirect callers and other
+images remain open. GCP's service-2 reach was demonstrated with other
+opcodes, not a hardware `0x1AA` invocation. The integrity/security
+meaning of an allocation bit after a failed real callback, actual ASIC
+register effects and an exact restoration oracle must be established
+before assigning practical impact. The duplicate-drop/ID-admission
+defects are documented separately in
+`fw/CANDIDATE-ASD-163-1AA-DUPLICATE-DROPS-TAIL.md`.
diff --git a/fw/CANDIDATE-GCP-ASD-203-DIO-UNBOUND-RECORD-ACCESS.md b/fw/CANDIDATE-GCP-ASD-203-DIO-UNBOUND-RECORD-ACCESS.md
new file mode 100644
index 0000000..74bfd52
--- /dev/null
+++ b/fw/CANDIDATE-GCP-ASD-203-DIO-UNBOUND-RECORD-ACCESS.md
@@ -0,0 +1,60 @@
+# ASD `.163` `0x203`: two-bit state selects ownerless DIO-record read
+
+**Status:** signed-code global-record access candidate and signed-dispatch
+synthetic control. No live second-client record, private-config content,
+card request, ASIC effect, or proven security disclosure. GCP already has
+a separately demonstrated ASD `0x404` read primitive after its forged
+allowlist setup; this is a distinct, narrower opcode, not an escalation
+beyond that primitive.
+
+Raw Thumb in `sub_D0E8F8` (`0xD0E8F8`) bounds `msg[1] <=3`, requires
+`msg[3]==16`, and validates `msg[2]` for 16 caller bytes. It sums those
+bytes, then counts bits in the selected global DIO state word at
+`0xD29080+16+20*index`:
+
+- **At least two bits:** if the caller's 16-byte checksum is nonzero,
+ raw `0xD0E948..0xD0E94E` calls `sub_D01058` with **destination =
+ caller pointer** and **source = global record payload** at
+ `0xD29080+20+20*index`. It returns zero without comparing TA/channel
+ identity. All-zero caller input skips the copy but still returns zero.
+- **Exactly one bit:** raw `0xD0E95A..0xD0E97C` copies the caller's
+ 16 bytes **into** the selected global payload, then invokes
+ `sub_D0BC80` and potentially `sub_D0DDDC`. Those later operations
+ can update display/link state and are **modeled in the write test
+ below**, not executed against real ASIC state. Zero bits
+ reject with status 2. The two directions are easy to reverse when
+ reading the decompiler; raw R0/R1 and an output readback control
+ established the direction above.
+
+Free `0x205` (`sub_D0DC34`) permits any caller to set an individual
+chosen bit in any index 0..3, without an owner check. Therefore two
+successful one-bit requests can select the `0x203` read branch even
+when a particular record started with zero state. This does **not**
+prove that another client's meaningful payload exists at that index.
+
+`python3 psp_emu/harness/probe_asd163_203_dio_config.py` passed on the
+signed `.163` dispatcher/leaves: it seeded a synthetic 16-byte record-0
+payload, sent `0x205(0,1)` and `0x205(0,2)`, then obtained those bytes
+in the caller buffer with `0x203(0,caller,16)`. An index-4 request
+returned 2 with its caller buffer unchanged, a zero-filled caller
+input skipped the read, and an adjacent record stayed unchanged. This read test intentionally avoids the one-bit write/ASIC callback
+branch. A separate
+`python3 psp_emu/harness/probe_asd163_203_dio_config_write.py`
+passed the one-bit branch: `0x205(0,1)` followed by
+`0x203(0,caller,16)` changed exactly a planted ASD-global 16-byte
+payload, leaving an adjacent synthetic record unchanged. A zero-bit
+negative returned 2 without changing it. The **only** interceptions
+were the two post-copy stateful helpers `sub_D0BC80` and
+`sub_D0DDDC`, each modeled as returning zero. Thus the signed
+pre-helper store and argument routing are shown, but neither a
+natural callback return nor a live link/register effect is shown.
+
+The signed variant-20 consumer `sub_D0EB84 → sub_D0BC80 →
+sub_D0E874 → asd_link_call_D49810_D49814` can feed selected global
+payloads to ASIC callbacks. The traced callback at
+`0xD10459 → 0xD11298` bounds a link index, reads four payload dwords,
+and calls `asd_reg_write_1981C` with register addresses loaded from a
+fixed ASIC table; the caller data are register **values**, not direct
+chosen addresses on that examined path. Natural scheduling, live
+ownership, real register semantics and an exact restoration oracle are
+open. Do not use a state-changing hardware probe merely to see a status.
diff --git a/fw/CANDIDATE-GCP-ASD-205-206-INVALID-MASK-SESSION-SIDE-EFFECT.md b/fw/CANDIDATE-GCP-ASD-205-206-INVALID-MASK-SESSION-SIDE-EFFECT.md
new file mode 100644
index 0000000..7a48fcb
--- /dev/null
+++ b/fw/CANDIDATE-GCP-ASD-205-206-INVALID-MASK-SESSION-SIDE-EFFECT.md
@@ -0,0 +1,55 @@
+# ASD `.163` `0x205`/`0x206`: invalid one-bit mask returns 2 after session side effect
+
+**Status:** signed-dispatch error-return/side-effect defect under a
+synthetic global state. No live card request, natural signed-client
+route, real kernel session behavior or cross-client impact. These are
+stateful paths; do not probe them on hardware solely for a return code.
+
+`asd_dispatch` (`0xD013B8`) calls `sub_D0DC34` for `0x205` and
+`sub_D0DC8C` for `0x206`. Each requires `arg1 <=3` and a **one-bit**
+`arg2`, returning **2** for zero/multi-bit masks. At raw
+`0xD01720..0xD01738` and `0xD0173E..0xD01760` respectively, the
+dispatcher saves that return in `R4` but **does not branch on it** before
+calling signed `sub_D0EB3C` and checking `arg1==1`:
+
+- `0x205` calls `asd_session_op57` even for an invalid mask if the
+ state-indexed predicate returns zero. Its signed `STR` first sets
+ global `0xD1BA24` to **1000**, then issues `SVC 0x57`.
+- `0x206`, when the same predicate is zero and the channel-1 state
+ bitmap is zero, calls `asd_session_timeout_disable`. Its signed store
+ sets `0xD1BA24` to **`0xFFFFFFFF`** even for an invalid mask. The ASD
+ event loop at `0xD0C934..0xD0C93C` loads this word into `R0` before
+ `SVC 0x56` (wait). Signed sOS `.54` `sub_59E8` **case 5** routes
+ `SVC 0x56` to `sub_662C → sub_B84`: `-1` writes a pair of
+ `0xFFFFFFFF` scheduler deadline words, while other values add the
+ supplied timeout to the scheduler clock. Thus the signed kernel does
+ distinguish no-timeout from 1000; scheduling and security effects on
+ the live card are unmeasured. `SVC 0x57` uses adjacent **case 6** and
+ `sub_553C`, not case 86 (the switch subtracts 81 from the SVC number). **Corrected address:**
+ the signed literals at `0xD083D4`/`0xD0B768` point to `0xD1BA24`,
+ not the stale IDA comment's `0xD25A3C`.
+
+`python3 psp_emu/harness/probe_asd163_205_206_invalid_side_effect.py`
+passed using signed `.163` dispatcher/leaves, synthetic status-table
+state 20 (whose signed entry is zero), synthetic channel-1 word and
+seeded deadline `0x12345678`:
+
+| request | signed return | channel-1 word | `0xD1BA24` after |
+|---|---:|---:|---:|
+| `0x206(1,0)`, invalid | **2** | `0 → 0` | `0xFFFFFFFF` |
+| `0x206(1,1)`, valid | 0 | `1 → 0` | `0xFFFFFFFF` |
+| `0x206(1,0)`, invalid, word 1 | **2** | `1 → 1` | unchanged |
+| `0x205(1,0)`, invalid | **2** | `0 → 0` | **1000** |
+| `0x205(1,1)`, valid | 0 | `0 → 1` | 1000 |
+
+Only `SVC 0x57` itself was explicitly skipped by the harness after
+the signed deadline store, not silently defaulted to success; the
+signed callsite was counted. `0x206` executes its signed store without
+an SVC stub. Successful mask-1 requests can already reach these
+side effects, so **this does not by itself add caller authority**:
+it demonstrates surprising state change on an error return, not a
+proven exploit. A scoped opcode-immediate/aligned-literal search found
+no direct `0x205/0x206` candidate in the extracted HDCP/OPM/DTM
+signed ELFs; other clients, computed callers and natural state remain
+open. The unbound GCP→ASD service-2 reach established for other opcodes
+is not a live invocation of these two commands.
diff --git a/fw/CANDIDATE-GCP-ASD-20B-UNCHECKED-OUTPUT-STORE.md b/fw/CANDIDATE-GCP-ASD-20B-UNCHECKED-OUTPUT-STORE.md
new file mode 100644
index 0000000..3513337
--- /dev/null
+++ b/fw/CANDIDATE-GCP-ASD-20B-UNCHECKED-OUTPUT-STORE.md
@@ -0,0 +1,132 @@
+# Candidate: GCP-reachable ASD `.163` opcode `0x20B` stores a Boolean through an unchecked pointer
+
+**New signed-code missing-pointer-validation defect; hardware confirms the
+Boolean store into GCP-owned memory, but not an ASD-private or
+out-of-caller-window write.** An isolated signed-ASD dispatcher test does exercise a private target
+under synthetic mapping. The signed ASD image is
+`psp_out/versions_win/elf_all/asd_33.0.0.163_18debcc4.elf`; the card-loaded
+container was independently identified as `asd_33-0-0-163_18debcc4.bin`.
+GCP code execution plus the existing ROP service-2 transport can supply an
+otherwise unused RPC opcode. A normal GCP command does not have to expose
+`0x20B` for the ROP caller to send it.
+
+## Signed request-to-store path
+
+* `asd_dispatch` at `0xD013B8` dispatches the `0x200..0x20B` group. For
+ opcode `0x20B`, signed code at `0xD0178A` loads `R0 = *(u32 *)(msg+4)` and
+ at `0xD0178C` calls `asd_svc_op_20B` (`0xD0DC14`). The surrounding
+ dispatcher checks that the **message pointer** is non-null and checks an
+ ASD global state word; it does not validate the `msg+4` **pointee**.
+* Raw signed leaf instructions: `PUSH {R4,LR}; MOV R4,R0;
+ BL asd_svc_sub_2794; STR R0,[R4]; MOVS R0,#0; POP {R4,PC}`.
+ There is **no null, range, alignment, or ownership check** before `STR`.
+ In contrast, the nearby `0x207` handler explicitly calls
+ `asd_validate_ptr(pointer,4)` before using an output pointer. That helper
+ admits configured caller ranges and rejects an ASD-private address.
+* `asd_svc_sub_2794` at `0xD02664` reads `*(u32 *)0xD1BA28`, initially
+ `0xFF` in the signed image. If it equals `0xFF`, it conditionally calls
+ a callback at `0xD39834`, then returns **Boolean 0 or 1**; if the
+ callback is absent it also returns 1. A later **read-only** fresh-boot
+ check found state 1 and a non-null callback (details below), so this
+ sampled state skips the callback. Its behavior on other states was not
+ dynamically tested. The store is therefore a
+ **single four-byte store of constrained content**, not a chosen-word
+ writer, and it may fault if the target VA is unmapped or read-only.
+
+The service-2 outer gate validates the RPC transport/message pointer, not
+all nested opcode-specific addresses; the absence of a handler-level check
+is the issue. A limited **static cross-version check** of generated ASD
+decompilations `.173`, `.181`, `.195` and `.239` also shows their `0x20B`
+dispatch cases passing `req->arg1` directly into the same unchecked Boolean
+store. Those builds were **not** emulated or exercised on this card; no
+claim about other variants or full compatibility follows. The separate
+ASD `0x404` read and `0x403` fabric-write results do not by themselves
+verify this opcode's effect.
+
+## Bounded signed-code test
+
+`python3 psp_emu/harness/probe_asd163_20b_private_store.py` loads the exact
+signed `.163` ELF into an isolated ASD `Component`, maps a **synthetic**
+GCP-sized caller-message interval, and executes the **actual signed
+`asd_dispatch`** with `(opcode, nested pointer)=(0x20B,0xD4AF00)`. This
+private address is emulator RAM, **not a measured hardware mapping**. With
+the Boolean source forced to 0 and separately 1 (to avoid any optional
+callback), the traced store was exactly `(address 0xD4AF00, width 4,
+value 0/1)`, and the planted private word changed accordingly; both calls
+returned zero with no emulator fault. An adjacent negative control calls
+signed opcode `0x207` with the **same** private pointer: both runs returned
+2 and left the planted word intact. The script asserts its image bytes
+match the signed ELF, but its synthetic memory/Boolean source and omitted
+sOS/GCP transport do **not** establish live memory permissions or a card
+write. In particular, emulator mappings are more permissive than PSP PTEs.
+
+## Fresh-boot read-only callback-state check
+
+On an ATX-cycled card, existing GCP ROP → ASD `0x404` index-9 reads
+measured `*(u32 *)0xD1BA28 = 1`, callback pointer
+`*(u32 *)0xD39834 = 0xD08295` (Thumb entry at signed `0xD08294`),
+and the exact signed `0x20B` handler word at `0xD0DC14` as `0x4604B510`.
+This read-only probe did **not** invoke `0x20B`; its signed
+`sub_D02664` would skip the callback while the status word is 1.
+It is **not** the distinct `0x405` ASIC callback previously measured null
+at `0xD334C4`. The observation alone is not proof of the `0x20B` write. The ASD and GCP load returned zero, GCP
+was session 1, FE0A status `0x240`, graceful marker `0x5A`, fault frame
+zero, signed-code control matched, and final FE07 returned zero. Log:
+`/root/psp/hw/asd20b_state_fresh.log`; script:
+`/root/psp/hw/gcp_rop_asd3_read_20b_callback.py` (SHA-256 prefix
+`8277665126875a1c`). The state/callback may differ across boots or later
+transitions.
+
+## Controlled hardware output test (GCP-owned only)
+
+On a **different fresh boot**, a single GCP-ROP sequence first used ASD
+`0x404` to read the Boolean source `0xD1BA28` as **1** and signed handler
+code `0xD0DC14` as `0x4604B510`. It then sent service-2 opcode `0x20B`
+with `msg[1]=0x41061C`, a **GCP-owned** dword at `msg+0x1C` initialized
+to `0xA5A5A5A5`. The ROP chain copied the three messages back into the
+host-visible GCP command buffer after the service call. Readback showed
+`msg[0]=0x20B`, unchanged pointer `0x41061C`, and the designated output
+word **1**; an untouched, separately planted same-offset control in
+message A remained `0xA5A5A5A5`. `0x20B` returned zero, FE0A `0x240`,
+grace `0x5A`, fault frame zero, final FE07 zero, and **GCP unload status
+zero**. The destination was confined to transient GCP-owned request RAM;
+unload retired it. See `/root/psp/hw/asd20b_owned_fresh.log` and
+`/root/psp/hw/gcp_rop_asd3_20b_owned_output.py` (SHA-256 prefix
+`7505c0760ad4c129`). No ASD-private destination,
+MMIO or protected memory was written. A handler return alone would not
+prove this effect; the after-call GCP-memory copy and unchanged control
+are the write evidence. A **third fresh-boot target-swap control** used the
+same signed-code and state checks but pointed opcode `0x20B` at the
+GCP-owned `msgA+0x1C` (`0x41041C`), instead of `msgC+0x1C`. The exfiltrated
+`msgA` word changed to 1 while the former `msgC` target **remained
+`0xA5A5A5A5`**; FE0A `0x240`, zero fault frame, final FE07 and GCP unload
+all passed. Log `/root/psp/hw/asd20b_swap_fresh.log`; probe
+`/root/psp/hw/gcp_rop_asd3_20b_owned_swap_control.py` (SHA-256 prefix
+`a50a44bf625ce0f7`). These two destinations moving with the supplied
+pointer distinguish the handler's chosen destination from a fixed GCP
+ROP/self-corruption offset. Neither test demonstrates the missing check's
+**higher-authority consequence** on the card.
+
+## Impact and next gate
+
+A separate read-only mapping/provenance follow-up
+(`fw/AUDIT-GCP-ASD-20B-PRIVATE-TARGET-PROVENANCE.md`) found that the
+synthetic `0xD4AF00` target lies **outside** the signed ELF LOAD range,
+and the full-system emulator's generic TTBR0 view maps it in **both**
+ASD and GCP contexts; this is not a live isolated writable target.
+The sampled Boolean source 1 also supplies no 0-value restoration via
+`0x20B`. Signed sOS `.54` uses per-process L2 tables through
+`sub_4350`/`SVC 0xB8`, which the sampled generic emulator TTBR0 view
+did not establish. These observations narrow, not upgrade, the live
+impact.
+
+The GCP-origin service-2 request **did** reach this signed handler and
+produced its Boolean output in GCP-owned RAM. If a selected address is also
+writable in ASD's context outside GCP's window, the absent check would
+allow a constrained-content ASD-authority store there; the isolated signed
+emulator demonstrates that only for **synthetic** ASD RAM. No live
+ASD-private modification, CPU-kernel mapping, code execution or persistence
+is established. Do not write to ASD guards, keys, callback pointers,
+registers or unknown BSS on the card. A live private-target test first
+needs a benign mapped word and an independent effect/readback plus exact
+restoration plan; otherwise stop at the current evidence.
diff --git a/fw/CANDIDATE-GCP-SYSDRV-1001-SELECTED-IDENTITY-BULK-CLEANUP.md b/fw/CANDIDATE-GCP-SYSDRV-1001-SELECTED-IDENTITY-BULK-CLEANUP.md
new file mode 100644
index 0000000..727212f
--- /dev/null
+++ b/fw/CANDIDATE-GCP-SYSDRV-1001-SELECTED-IDENTITY-BULK-CLEANUP.md
@@ -0,0 +1,84 @@
+# Free SYS_DRV `.54` `0x1001`: caller-selected identity bulk cleanup
+
+**Conditional cross-client resource-teardown and empty-slot hazard;
+signed SYS_DRV execution with synthetic records, NOT a live victim or
+kernel effect.** Signed dispatcher `sub_E105A8` passes the **low byte of
+inline `msg[14]`** to `sub_E09E34`. No process-identity comparison
+precedes its three signed cleanup calls:
+
+1. `sub_E05BE4` clears active entries matching that byte in a
+ 256×8 private table at `0xE58038` and releases matching entries
+ in a 256×16 table at `0xE58838` through `sub_E05DD0`.
+2. `sub_E05B9C` scans 32×84 records at `0xE575B8`; for active
+ records whose `+34` owner byte matches, `sub_E09E10` clears
+ indexed bookkeeping bytes and the record's owner/status bytes
+ are zeroed.
+3. `sub_E1BEF8` scans 16×8 sOS-resource slots at `0xE57538`;
+ every slot with `slot[0] == selected_byte` requests
+ `SVC 0x6C(slot[1])` and is unconditionally zeroed **regardless
+ of that syscall's result**. This scan does not check that a
+ slot is active. `sub_E09E34` always returns zero.
+
+A natural signed producer exists: sOS `.54` `sub_17CA4` bounds its
+process index below 32 and passes that index to `sub_12672` during
+TA teardown. Raw `sub_12672` places the index into SYS_DRV
+`0x1001` inline `msg[14]` and issues service-1 `SVC 0xF2`.
+This explains the intended **trusted process-cleanup** role but
+does not authenticate the same scalar when a GCP ROP issuer invokes
+the free SYS_DRV opcode. The policy under which sOS can select a
+victim for teardown was not fully audited here.
+
+`python3 psp_emu/harness/probe_sysdrv_1001_owner_cleanup.py` passed
+against signed SYS_DRV `.54` dispatch after isolated init:
+
+- All 16 slot owner bytes were **zero**. `0x1001(msg[14]=0)`
+ requested **sixteen `SVC 0x6C(0)` calls** despite each modeled
+ return being error 43, and returned zero. This is not an actual
+ sOS result: `SVC 0x6C` was explicitly intercepted.
+- Public **synthetic** identity-7 records in the 8-byte slot table,
+ 84-byte table and 8-byte auxiliary table were cleared; parallel
+ identity-8 records survived. The identity-7 slot requested
+ `SVC 0x6C(30)` and was cleared even with modeled error 43.
+ The separate 16-byte table was not seeded or proved clearable.
+ All planted bytes were restored in emulator memory.
+- A subsequent **signed consumer control** used
+ `sub_E0B148(handle,owner)`, which checks the 84-byte record's
+ active/owner bytes and calls `sub_E0F890` on failure. Signed
+ `sub_E1CD24` is a producer of those records: it writes active=1
+ and supplied owner to `+32/+34`. Before the synthetic cleanup,
+ handles 16/17 for identities 7/8 both resolved. Afterwards the
+ identity-7 lookup reached an explicitly **captured**
+ `sub_E0F890` entry, while identity-8 still resolved. The fatal
+ helper is signed `__noreturn` and loops after recording an error,
+ but the test deliberately intercepted it instead of running
+ that loop; no live client next operation or hardware hang was
+ observed. This adds a conditional consumer consequence, **not**
+ a proven live cross-client victim.
+
+The sOS `.54` `SVC 0x6C` case 27 routes to `sub_6828`. For resource
+IDs below 32, it calls `sub_6918` then `sub_6870` **without checking
+the former's result**; `sub_6870` dereferences a resource-table
+pointer for its requested ID. If ID 0 is absent, the empty-slot
+requests could fault sOS; whether live resource 0 is populated and
+whether this is recoverable is **unproved**. A separate signed sOS
+helper test with a **synthetic** absent resource and protected zero
+page did stop at `sub_6870+0x32`/PC `0x68A2` after modeled
+`sub_6918` error 43; this does not establish a live kernel fault
+(`fw/CANDIDATE-SOS54-6C-ABSENT-RESOURCE-DEREF.md`). Neither signed sOS
+teardown nor any live `0x1001`/`0x100C` cleanup was invoked in this
+test. This is a different bulk route to the global release behavior
+already observed for free `0x100C`, not an independently demonstrated
+cross-client exploit.
+
+A **read-only full-system signed-sOS emulator** sampled resource 0 as
+assigned after modeled ring, ASD and GCP load. This does not prove
+live resource state; repeated `0x1001(0)` ID-0 requests could first
+release a populated resource and then reach the absent-resource
+path, but no connected teardown was run
+(`fw/AUDIT-SOS54-RESOURCE0-SIGNED-BOOT-MODEL.md`).
+The natural 8/16-byte table producers, actual process identities,
+protected second-client ownership, live sOS resource state, and an
+exact restoration oracle remain open. Do not try a zero identity, a
+populated identity or an sOS resource release on the card merely
+for a return code. Emulator init has default-success unrelated
+SVCs, and modeled error 43 does not predict actual sOS behavior.
diff --git a/fw/CANDIDATE-GCP-SYSDRV-100B-NESTED-STRUCT-SPAN.md b/fw/CANDIDATE-GCP-SYSDRV-100B-NESTED-STRUCT-SPAN.md
new file mode 100644
index 0000000..4ea2bb1
--- /dev/null
+++ b/fw/CANDIDATE-GCP-SYSDRV-100B-NESTED-STRUCT-SPAN.md
@@ -0,0 +1,44 @@
+# Free SYS_DRV `.54` `0x100B`: nested structure read through a four-byte declaration
+
+**Reached signed-code prevalidation overread in a synthetic caller
+window; no live cross-client read or sOS allocation effect.** The
+historical stub classification is wrong. Its signed role row at
+`0xE25B70` is `{0x100B,2,1,0,0}`: `msg[2]/[3]` is validated as an
+output pair and `msg[4]/[5]` as an input pair. The dispatcher copies
+`msg[2]` to scratch `msg[14]`, then calls `sub_E1BB3C`. The leaf
+loads that **caller pointer** and unconditionally reads nested
+`u32` fields at **`+16`, `+20`, `+24`** as high/low mapping address
+and size at signed `0xE1BB80..E1BB86`. There is no requirement that
+`msg[3]>=28`; the second pointer pair does not validate these
+nested fields. A declared four-byte output therefore does not bound
+the leaf's input reads. Later, if a separately mapped header matches
+`0x9000` and `127`, the signed code calls stateful `SVC 0x90`, maps
+and copies a 4-KiB page, and runs further signed integrity checks.
+On that deeper path raw `0xE1BC26..E1BC30` compares **32 bytes** at
+the second caller pointer `msg[4]` without requiring declared
+`msg[5]>=32`; the success path at `0xE1BC76..E1BC94` stores a slot
+index at **`msg[2]+28`** without requiring `msg[3]>=32`. These
+additional span mismatches are **conditional on the mapped header,
+checks and resource availability**, not exercised by the harness.
+Neither a valid header nor a live allocation is demonstrated here.
+
+`psp_emu/harness/probe_sysdrv_100b_nested_span.py` passed on signed
+`.54` dispatch/leaf. With a four-byte declaration and a **synthetic
+contiguous caller buffer**, a hook on the signed mapping helper
+observed chosen `+16/+20/+24` values. A separate planted
+`SVC 0xB5` caller-window boundary placed four bytes at the end of
+the mapped scratch page: the four-byte declaration passed dispatch,
+then the leaf faulted at its **first** nested load PC `0xE1BB80`,
+FAR `0xFE0014`; a 28-byte declaration at the same artificial edge
+returned `0xFFFF000F` **before** the nested read. These are model
+windows, not card PTEs or another client's memory. A hook confirmed
+that none of these model controls reached the signed `SVC 0x90`
+callsite; no sOS resource effect is claimed.
+
+Signed sOS `.54` `SVC 0x90` case 63 routes through `sub_C04`, a
+stateful allocator, only after the mapped-header gate. The actual
+type-5 whole-span PTEs, whether the nested fields can address a
+valid mapped header, header provenance and any safe restoration
+oracle are open. A scoped extracted-client immediate/aligned-literal
+scan found no direct `0x100B` hit; computed calls and other builds are
+not excluded. No card request was issued.
diff --git a/fw/CANDIDATE-GCP-SYSDRV-100C-OWNERLESS-SLOT-RELEASE.md b/fw/CANDIDATE-GCP-SYSDRV-100C-OWNERLESS-SLOT-RELEASE.md
new file mode 100644
index 0000000..72fd103
--- /dev/null
+++ b/fw/CANDIDATE-GCP-SYSDRV-100C-OWNERLESS-SLOT-RELEASE.md
@@ -0,0 +1,44 @@
+# Free SYS_DRV `.54` `0x100C`: indexed global resource-slot release
+
+**Signed ownerless release and error-return metadata loss; synthetic
+record only, no live victim.** Historical inventory labels `0x100C`
+a tiny/query getter. Signed `sub_E105A8` case 4108 instead passes
+caller-controlled inline `msg[14]` to `sub_E1BEC8`, ignoring its
+result and returning zero. Indices **16..31** select one of 16
+private eight-byte slots at `0xE57538+8*(index-16)` under a SYS_DRV
+mutex. It reads byte `+1` as an sOS resource number, passes that
+byte to `SVC 0x6C`, then **unconditionally clears both dwords**,
+without checking the SVC result or the slot's owner/active state.
+Out-of-range indices silently do nothing and return zero.
+
+Signed sOS `.54` `SVC 0x6C` case 27 routes to `sub_6828` for
+resource IDs below 32; that routine invokes resource teardown
+helpers `sub_6918` and `sub_6870`. A separate signed-helper synthetic
+absent-resource test found that `sub_6828` discards the former's error
+and the latter dereferences a null descriptor under an artificially
+protected zero page; natural resource vacancy and hardware effect
+are still open (`fw/CANDIDATE-SOS54-6C-ABSENT-RESOURCE-DEREF.md`).
+This is not just a SYS_DRV private getter. The examined producer `sub_E1BB3C` (free opcode
+`0x100B`, after its separate mapped-header/integrity checks) finds
+an empty slot, copies its newly obtained sOS resource byte to
+slot `+1`, saves the associated pointer at `+4`, and stores the
+low byte of caller inline `msg[16]` at `+0`. That annotation is
+**caller supplied**, not demonstrated sOS ownership. The producer
+requires stateful `SVC 0x90` and was **not** exercised in this test;
+see `fw/CANDIDATE-GCP-SYSDRV-100B-NESTED-STRUCT-SPAN.md`.
+
+`psp_emu/harness/probe_sysdrv_100c_slot_release.py` passed on
+signed SYS_DRV dispatch. It planted only one **synthetic private
+record** for selected index 16; `SVC 0x6C` was replaced with an
+explicit error 43. The signed leaf sent the planted resource ID
+30, cleared the selected eight bytes **despite that modeled
+failure**, returned zero, and left adjacent slots unchanged.
+Indices 15/32 did not clear the slot. The record was restored **in
+emulator memory**. The kernel teardown was **not** executed; the
+emulator has unrelated default-success SVCs.
+
+Natural populated slots, real resource identities, whether
+cross-client release is authorized global management, a second
+client's security use, sOS teardown behavior and an exact card
+restoration oracle remain unknown. Do not call this release on the
+card merely to obtain a status or create artificial records.
diff --git a/fw/CANDIDATE-GCP-SYSDRV-100E-100F-SECOND-INPUT-SPAN.md b/fw/CANDIDATE-GCP-SYSDRV-100E-100F-SECOND-INPUT-SPAN.md
new file mode 100644
index 0000000..c07b8c1
--- /dev/null
+++ b/fw/CANDIDATE-GCP-SYSDRV-100E-100F-SECOND-INPUT-SPAN.md
@@ -0,0 +1,88 @@
+# SYS_DRV `.54` `0x100E`/`0x100F`: second caller buffer is validated short but submitted long
+
+**Status:** signed-code PASSTHRU descriptor-length mismatch, scoped signed
+emulation, a **separate** modeled CCP edge control, and a connected
+signed-dispatch/CCP-model completion on fully mapped synthetic input.
+No card command, real GCP PTE boundary, disclosure, or hardware fault. Do not run these stateful jobs on the card merely to obtain a status.
+
+`sub_E105A8` dispatches free opcode `0x100E` through `sub_E134DC` and
+`0x100F` through `sub_E13554`. Both signed role rows (respectively
+`0xE25B98` and `0xE25BAC`) are `{opcode,2,1,0,0}`. The first caller pair
+`(msg[2],msg[3])` is an output-role pointer and the second
+`(msg[4],msg[5])` is an input-role pointer; `sub_E0DEF4` uses each pair's
+**declared** length for its type-5 window check. There is no signed
+comparison requiring `msg[5] >= msg[3]`.
+
+Both leaves issue sOS `SVC 0x79` on each pointer. Signed sOS `.54`
+`sub_59E8` case 40 calls `sub_6D84`, which translates the **starting
+address** via one process-indexed PTE; it does not validate an entire
+requested byte span. For `0x100E`, signed `0xE1351A..0xE1352C` also asks
+`SVC 0x68` to perform cache operations on **both** caller buffers over
+`msg[3]` bytes. Signed sOS case 23's `sub_1054` is a cache-line loop,
+not an ownership/length check; SYS_DRV does not branch on its return.
+`0x100F` reaches the same descriptor construction for both `msg[14]`
+mode choices examined.
+
+`sub_E03E44` receives the two translated starting addresses and
+`msg[3]` as the **sole data span**. Its 32-byte PASSTHRU command has
+`dw1=msg[3]`, `dw2=translated(msg[4])` (source), and
+`dw4=translated(msg[2])` (destination); `dw3/dw5` select memory type 2,
+not the CCP local-storage block. `sub_E1C85C` passes the command into
+the SYS_DRV queue path. Thus four bytes of second input may pass caller
+validation while the signed command **requests a 64-byte source read**.
+This is a mismatch in the signed request construction, not a verified
+cross-page read by the real device. The other direct caller of
+`sub_E03E44` outside these two leaves is `sub_E119D4`, dispatched for
+`0x3104` in the GCP-rejected `0x3100..0x31FF` ACL range; it is not an
+additional free-opcode path.
+
+## Controls
+
+`python3 psp_emu/harness/probe_sysdrv_100e_100f_second_span.py` compiled
+and passed against the signed `.54` ELF. Its synthetic `SVC 0xB5`
+returns `[0x400000,0x800000)` for type-5 pointers; `SVC 0x79` echoes
+addresses rather than performing the signed sOS page walk, and
+`SVC 0x68` is an explicit success stub. It intercepts `sub_E04F1C`
+**before queue submission**, recording the signed descriptor without
+completing a job:
+
+* `0x100E`, `0x100F` mode 0 and `0x100F` mode 1: with output
+ `(0x401000,64)` and second input `(0x7FFFFC,4)`, all three reach the
+ job helper. The signed command has `dw1=64`, `dw2=0x7FFFFC`,
+ `dw4=0x401000`; controls with an in-window 64-byte source also reach it.
+ Mode 0 emits `0x50001A`, mode 1 emits `0x500018`, both engine-5
+ PASSTHRU. The intercepted return/status is **not** a natural job result.
+* Declaring 64 bytes at that same synthetic edge is rejected by the
+ dispatcher (`0xFFFF000F`) **before** the job helper, whereas declaring
+ four reaches it. This is a window-model control, not a real PTE test.
+* Independently feeding the captured signed `0x100E` command to the
+ emulator's CCP model copies 64 planted bytes from a fully mapped source.
+ After unmapping the page beyond the synthetic edge, the captured
+ 64-byte command raises a **modeled** IDMA source fault `0x13`; editing
+ only the isolated model command's length to four copies four edge bytes.
+ Unicorn host-side `mem_read` does not honor `UC_PROT_NONE`, so the page
+ was explicitly **unmapped after signed execution** for this check.
+ No signed continuation or hardware CCP completion is implied.
+
+A halfword-resynchronizing immediate scan of the **95**
+`psp_out/versions_win/elf_all` signed ELFs found no direct `0x100E` or
+`0x100F` candidate; computed/literal-pool opcodes and other corpora remain
+open. ## Connected signed queue completion on mapped input
+
+`python3 psp_emu/harness/probe_sysdrv_100e_100f_ccp_natural.py` also
+passes: it installs the emulator CCP queue **without hooking the signed
+job helper**, then issues `0x100E`, `0x100F` mode 0, and `0x100F` mode 1
+with a fully mapped 64-byte second buffer. For every command, both
+`msg[5]=64` and **`msg[5]=4`** returned signed-dispatch status **zero**,
+the modeled queue executed one engine-5 PASSTHRU descriptor with source
+length 64, and independent output readback matched all 64 planted bytes.
+This upgrades the *synthetic* feasibility evidence beyond a stubbed queue
+return; CCP MMIO, SYS_DRV initialization data, `SVC 0x79` identity
+translation, type-5 window, `SVC 0x68`, and several other SVC responses
+remain modeled/default-success. A mapped synthetic source does **not**
+establish a hardware out-of-bounds access.
+
+Live sOS translation/PTEs, PTE adjacency and client ownership, and whether
+any signed client issues these opcodes with short second lengths remain
+unresolved. The separate modeled IDMA edge fault is not a live DoS or
+independently demonstrated cross-client data read.
diff --git a/fw/CANDIDATE-GCP-SYSDRV-1016-SHORT-INPUT.md b/fw/CANDIDATE-GCP-SYSDRV-1016-SHORT-INPUT.md
new file mode 100644
index 0000000..dd2edd3
--- /dev/null
+++ b/fw/CANDIDATE-GCP-SYSDRV-1016-SHORT-INPUT.md
@@ -0,0 +1,24 @@
+# SYS_DRV `.54` free `0x1016`: short-input leaf mismatch, blocked by signed sOS `SVC 0x6B`
+
+**Status:** real signed SYS_DRV leaf defect under a **synthetic** success response for `SVC 0x6B`; subsequent cross-component signed sOS `.54` analysis finds that the real syscall takes a stubbed error path. **Not a demonstrated reachable card read, DoS, or write.** No `0x1016` hardware request was issued.
+
+## Root cause and reachability
+
+GCP ROP can request free SYS_DRV service-1 opcode `0x1016` (outside the measured ACL ranges). Signed `sub_E087E4` copies the 0x7C-byte request and enters `sub_E105A8`. That dispatcher validates nonzero pointer/length pairs at `msg[2:3]` and `msg[4:5]` using `sub_E0AB44` and `sub_E0DEF4`, then decimal case 4118 calls `sub_E19BD8` (`0xE19BD8`) with the first pointer `msg[2]`, second pointer `msg[4]`, and caller-supplied scalar fields `msg[14:16]`.
+
+The leaf requires its scalar input length in `[104,8192]` and `*(u64 *)msg[2] != 0`; successful `SVC 0x6B/0x6D` mapping then leads to **four fixed 24-byte copies** into SYS_DRV cache `0xE7D5D0`: one from `msg[2]`, and three from `msg[4]` at offsets `+24`, `+0`, and `+48`. In particular, it reads **72 bytes from `msg[4]`** even if the caller declared `msg[5]=4`. Neither the leaf nor its first-level validator compares these copy sizes to `msg[3]`/`msg[5]` on this path. This is an input-length/actual-read mismatch, not an unchecked nested output pointer. The cache may subsequently influence session configuration, but the test below returns an error *after* the copies; no successful session or privilege effect is claimed.
+
+## Signed sOS reachability gate — why this is not a current-build exploit
+
+The signed sOS `0.49.0.54` `SVC 0x6B` dispatcher (`sub_59E8` switch case 26, raw table entry `0x5A98 → 0x5FDE`) checks the request then calls `sub_3A04`. Its case-26 raw instructions at `0x5FEC..0x601E` pass argument 5 = **zero**; `sub_3A04 → sub_3A84` sends this mode to `sub_3DD8`, whose entire raw body at `0x3DD8` is `MOVS R0,#9; BX LR`. Earlier errors from `sub_3A84` also cannot give success. SYS_DRV `sub_E19BD8` checks the syscall's R0 immediately at `0xE19C30` and returns error (`0x80000703`) on nonzero, **before any of the four copies**. The leaf mismatch is therefore presently **blocked by this signed sOS `.54` syscall**, assuming the card executes these unmodified signed instructions; a synthetic successful SVC return is not a reachability proof. Other sOS builds or a separately justified syscall bypass would require new evidence.
+
+## Positive and negative controls (synthetic, not silicon)
+
+`python3 psp_emu/harness/probe_sysdrv_1016_short_input.py` compiled and passed with signed `sys_drv_0.49.0.54_18bd9d26.elf`. The harness runs the signed init, dispatcher, range validator and memcpy leaf unmodified; it supplies a **synthetic** `[0x400000,0x41C000)` caller descriptor through `SVC 0xB5`. The emulator also defaults unhandled `SVC 0x6B/0x6D` to successful zero returns: their real sOS mappings/gates are **not** modeled and must not be inferred from these runs.
+
+* Fully mapped second input, **declared 4 bytes**: reaches the leaf and independently reads back all 72 planted bytes in the internal SYS_DRV cache (in the leaf's chunk order), despite final handler status `0x80000702`.
+* Same request with the **signed sOS `.54` SVC-`0x6B` result 9 modeled**: the signed leaf returns `0x80000703` *before* any cache copy. This validates the placement of the blocking gate but is not an intact full-system execution.
+* Second input at synthetic window `end-4`, **declared 72 bytes**: signed request validation rejects before leaf with `0xFFFF000F`; cache is unchanged.
+* Same edge, **declared 4 bytes**: reaches the leaf and faults on a read at `0x41C014` beyond the synthetic window. This demonstrates a conditional edge fault under the model, **not** a card-side cross-process read.
+
+The synthetic `SVC 0x6B` response **contradicts the signed sOS `.54` mode-0 error path above**. A synthetic fault or copied cache therefore cannot establish a hardware disclosure or DoS, and the short-input leaf should not be ranked with actually reachable defects on this build. If a different sOS build or signed path is shown to return zero, then genuine caller windows, `SVC 0x6D`, downstream session changes, and restoration still require verification; do not issue a stateful hardware request on the strength of this emulator result.
diff --git a/fw/CANDIDATE-GCP-SYSDRV-1017-TWO-SHORT-OUTPUTS.md b/fw/CANDIDATE-GCP-SYSDRV-1017-TWO-SHORT-OUTPUTS.md
new file mode 100644
index 0000000..7d2e920
--- /dev/null
+++ b/fw/CANDIDATE-GCP-SYSDRV-1017-TWO-SHORT-OUTPUTS.md
@@ -0,0 +1,55 @@
+# Candidate: free SYS_DRV `.54` `0x1017` writes two dwords beyond one-byte declared outputs
+
+**Signed-dispatch emulator with planted transport state and intercepted
+response; no card invocation, actual backend response, PTE-boundary
+coverage, or cross-allocation victim.** The defect is conditional on
+SYS_DRV mode byte `0xE26259 == 0` and a successful command-`131`
+backend response. The isolated signed init used below leaves that
+byte at **1**, so the test deliberately plants zero; this is not
+proof that the card has the vulnerable mode enabled.
+
+SYS_DRV `sub_E105A8` case `0x1017` supplies two separate caller
+output pointers from request pairs `(msg[2],msg[3])` and
+`(msg[4],msg[5])` to `sub_E1A418 → sub_E19DF4`. The dispatcher
+validates each nonnull pointer over its **declared** length via
+`sub_E0DEF4`, but it does not demand length four for this opcode.
+`sub_E1A418` returns `0xFFFF000A` when private mode byte
+`0xE26259 != 0`; when zero it calls `sub_E19DF4`. After a nonzero
+transport-buffer/descriptor prerequisite, signed `sub_E19DF4`
+requests command `131` (`sub_E1F470`). On zero transport status
+and zero embedded reply status it executes **two unconditional
+four-byte stores**: `*out1=reply[6]`, `*out2=reply[8]`. There is no
+per-output capacity check between dispatch validation and stores.
+
+`python3 psp_emu/harness/probe_sysdrv_1017_short_outputs.py`
+passed on the original signed `.54` dispatcher: with **both** output
+lengths declared 1, GCP-owned sentinel buffers received four bytes
+apiece from a synthetic public reply. A second request after
+restoring mode byte 1 returned `0xFFFF000A` without invoking the
+intercepted transport and left both buffers unchanged. The test
+plants mode zero and the required transport globals, intercepts
+`sub_E1F470` before any real backend, and forces its response;
+`sysdrv_env` initialization and unrelated SVCs have modeled
+successes. Neither output target was a private or neighboring
+client allocation.
+
+**Natural gate provenance:** the sole scoped direct signed init
+caller of `sub_E168D4` at `sub_E0CA2C` passes mode **0** only if
+`(v43[499] & 9) == 8` after other init steps succeed; raw
+`0xE0CC34 LDRB.W [R5,#0x7CC]` shows this is a **byte** at
+`off_E0CDE4 (0xE5FA48)+0x7CC = 0xE60214`, not a dword
+as the pseudocode type suggests. The isolated init does not
+satisfy this predicate. A scoped signed-code instruction scan for
+immediate `#0x7CC` found this `LDRB` but no direct-offset `STR`;
+indirect or bulk producers were **not** excluded. Its **real card
+value and producer are not established**. A successful command-131 response also has
+not been demonstrated for GCP, nor have actual type-5 PTE spans,
+neighboring ownership or a safe restoration oracle been measured.
+Free `0x1031` selector `0xF` is a separate signed **read-only
+inline getter** for the mode byte; an isolated signed-dispatch
+control passed (`fw/AUDIT-GCP-SYSDRV-1031-PRIVATE-MODE-QUERY.md`).
+It has **not** measured the card value or repaired the failed ROP
+mapping. This is a conditional short-declared-output candidate,
+not a controlled four-byte cross-allocation write or
+confidentiality finding. Do not exercise a short output on the card
+merely for a return code.
diff --git a/fw/CANDIDATE-GCP-SYSDRV-101C-WRAPPED-OUTPUT-NULL-SOURCE.md b/fw/CANDIDATE-GCP-SYSDRV-101C-WRAPPED-OUTPUT-NULL-SOURCE.md
new file mode 100644
index 0000000..da72d14
--- /dev/null
+++ b/fw/CANDIDATE-GCP-SYSDRV-101C-WRAPPED-OUTPUT-NULL-SOURCE.md
@@ -0,0 +1,20 @@
+# SYS_DRV `.54` free `0x101C`: wrapped output guard after NULL input skips validation
+
+**Status:** **conditional signed defect with live GCP gate/boundary unproven**. Bounded emulator evidence requires a **forced crypto-state success**, synthetic caller descriptor and artificial protection edge. No card call, actual initialized GCP crypto state, cross-process write, or completed 4-GiB copy. The separate authorization for an oversized opcode-`0xD` NULL-source hardware test does **not** authorize hardware testing this opcode.
+
+## Signed path and necessary conditions
+
+`sub_E105A8` case 4124 (`0x101C`) forwards `msg[2:5]` to `sub_E215A8` as source pointer/size and destination pointer/declared size. Pointer-role table row `0xE25C88` is `{0x101C,1,2,0,0}`. The dispatcher validates **nonzero** pointer/length pairs; a **zero `msg[2]` skips the first-pair check regardless of `msg[3]`**. The nonzero `msg[4]` output is admitted using only its `msg[5]` declaration. In contrast, a *nonzero* input pointer declared at `0xFFFFFFC0` is rejected by `sub_E0DEF4`'s `0x10000000` input-length cap before the leaf. This is specifically a NULL-source bypass of that cap, not an oversized mapped-source result.
+
+The leaf first requires `sub_E0E7B8(caller_id)==0`, a **real crypto-state prerequisite** not established for the GCP caller. Its per-caller flag at `0xEB1280 + 66*caller_id + 64` was **zero in isolated SYS_DRV post-init emulation**, where no sOS TA loading occurs; an **unhooked** direct call to the signed prerequisite helper for caller 2 therefore returned `0xFFFF000B`. This is **not a live GCP-state measurement**. The signed setter `sub_E0E74C` is reached through high opcode **`0x3105`**, in the `0x3100` ACL range rejected from *direct GCP requests*. Crucially, signed sOS `.54` **does issue `0x3105` itself during TA loading**, potentially for GCP's assigned slot. A halfword-resynchronizing `fw/scan_rpc_opcode_immediates.py --opcode 0x3105 --literals psp_out/elf psp_out/versions_win/elf_all` scan of extracted ELFs found the direct `MOVW #0x3105` at sOS `0x12AF6` (plus versioned copies); 32-bit aligned literal hits were restricted to SYS_DRV images, including `.54`'s role table at `0xE25FA8`. The first linear decoder falsely missed sOS; that negative was retracted. The loader's actual success, per-slot state and crypto completion are not yet independently measured on the card. `psp_emu/harness/probe_sysdrv_101c_state_gate.py` set a **synthetic** caller-2 flag through the signed setter and entered the unhooked gate, but the CCP model stopped at `unsupported SHA type 12` before completion. Full source-to-slot trace and caveats: `fw/AUDIT-SOS54-SYSDRV-3105-TA-LOAD.md`. After this prerequisite, the leaf computes `pad = -msg[3] & 15` and compares **32-bit** `(msg[3] + pad + 80)` to `msg[5]` (raw `0xE215C6..0xE215DA`). With `msg[3]=0xFFFFFFC0`, `pad=0`, the sum wraps to **16**: an output declared as 16 bytes passes. It then clears **80 bytes** at `msg[4]` using signed `sub_E019E4` (`0xE215E4..0xE215EE`) and fills header words at offsets 48–59, **before** attempting the enormous `sub_E018A0(msg[4]+80, msg[2], msg[3])` at `0xE21612`. Thus the early signed stores exceed the declared output by **64 bytes** if the state prerequisite is met. The subsequent source-NULL, ~4-GiB copy was deliberately **not run**; do not infer its completion, controlled destination across allocations, or a hardware effect.
+
+## Isolated controls
+
+`python3 psp_emu/harness/probe_sysdrv_101c_wrapped_output.py` compiles and passes. It runs signed init/dispatch/guard/memset unmodified, confirms the modeled GCP state flag is **zero** and the unhooked gate rejects, then stubs **only `sub_E0E7B8` to return zero** and diverts execution to the signed error epilogue immediately **before** the huge source copy. It models a synthetic type-5 `[0x400000,0x800000)` `SVC 0xB5` descriptor and deliberately protects the next emulator page, whose real card PTE is unknown.
+
+* Normal nonnull input, length 4, output declared 16: signed guard returned `0xFFFF0010`; 128-byte GCP-owned output marker unchanged.
+* **Nonnull** input, length `0xFFFFFFC0`, output declared 16: pre-dispatch validator returned `0xFFFF000F` before the leaf; marker unchanged.
+* **NULL** input, same huge length, mapped GCP-owned output declared 16: signed leaf wrote bytes **0–79** (including expected wrapped-size/header values); bytes 80–127 remained the marker. Stopped before bulk source copy; returned signed error-epilogue status, not a successful crypto result.
+* At a **synthetically protected** output boundary, declaring 80 rejected before the leaf; declaring 16 reached the signed memset and faulted at the protection edge (the emulator's last fault address was `0x80000C`, with the first denied write recorded at `0x800000`). This is not a measured hardware boundary or another process's memory.
+
+Further connected work should determine whether sOS's loader `0x3105` initializes the live GCP slot and whether `sub_E0E7B8` completes naturally, then establish real caller-page boundaries. The GCP ACL rejection does **not** rule out trusted sOS initialization. Without live state/boundary proof, classify this as a conditional signed-code defect, **not** an independently demonstrated GCP overflow. **Do not probe this stateful oversized NULL-source path on the card** for a return code, and do not promote this conditional signed-code defect to a proven post-ROP write.
diff --git a/fw/CANDIDATE-GCP-SYSDRV-1023-SHORT-OUTPUT.md b/fw/CANDIDATE-GCP-SYSDRV-1023-SHORT-OUTPUT.md
new file mode 100644
index 0000000..7d21778
--- /dev/null
+++ b/fw/CANDIDATE-GCP-SYSDRV-1023-SHORT-OUTPUT.md
@@ -0,0 +1,21 @@
+# SYS_DRV `.54` free `0x1023`: caller-declared output can be shorter than crypto output
+
+**Status:** signed dispatcher/leaf, isolated synthetic-success control, **and signed crypto completion through the emulator's CCP model**. Neither emulator path establishes the real card's CCP result, live caller window, or a cross-process write. No `0x1023` card request was made.
+
+## Signed-code mismatch
+
+GCP ROP can request free SYS_DRV service-1 opcode `0x1023`. In `sub_E105A8`, case 4131 passes `msg[2]` with length `msg[3]` (input), `msg[4]` with length `msg[5]` (additional input), `msg[6]` with length `msg[7]`, and output pointer `msg[8]` to `sub_E05140` (`0xE05140`). The pre-dispatch pointer validator loops over all four pointer/length pairs; the signed opcode-specific row at `0xE25CC4` is `{0x1023,1,1,1,2}` (last slot is output). Each pair is checked against its **own declared** length, with no observed equality/ordering check tying `msg[9]` to `msg[3]`.
+
+The signed leaf bounds `msg[3]` and the additional-input length to at most `0x200`, constructs a crypto descriptor via `sub_E0404C`, performs cache-maintenance `SVC 0x68` and waits in `sub_E1C85C`. **On `sub_E1C85C == 0`, it copies `msg[3]` bytes into `msg[8]`**, without comparing that copy size against the output's declared `msg[9]`. Thus `msg[3]=64, msg[9]=4` asks the validator to admit a four-byte output region, then asks the successful leaf to write 64 bytes. The crypto completion is a genuine, separate conditional gate; the caller cannot infer a successful **hardware** operation from dispatcher acceptance or the emulator result alone.
+
+## Bounded signed-dispatch emulator controls
+
+`python3 psp_emu/harness/probe_sysdrv_1023_short_output.py` compiles and passes against signed `sys_drv_0.49.0.54_18bd9d26.elf`. It executes signed init, validation, dispatch, crypto-descriptor setup, and output-copy code unmodified, but supplies a **synthetic** `[0x400000,0x41C000)` caller descriptor through `SVC 0xB5` and stubs **only the final `sub_E1C85C` call to return success**. Other unmodeled init SVCs also use the standard emulator model. This does **not** prove real CCP completion, the live caller window, or any card effect.
+
+* Input length 64 and output declared 4 at a fully mapped synthetic address: the leaf returned zero, and independent readback showed **all 64 output bytes** changed, bytes 64–127 untouched.
+* Output at synthetic window `end-4`, declared **64**: signed validation returned `0xFFFF000F` before the leaf; the four mapped marker bytes stayed unchanged.
+* Same edge, declared **4**: validation admitted the pointer, the leaf reached the stubbed crypto completion, and the signed output loop faulted at synthetic address `0x41C000`.
+
+**Independent emulator-CCP control:** `python3 psp_emu/harness/probe_sysdrv_1023_ccp_natural.py` passes twice through the signed `sub_E1C85C` completion routine **without a crypto-completion hook**. With synthetic SYS_DRV init/configuration, synthetic SVC behavior and an emulator CCP/queue model, both a declared 64-byte output and a declared four-byte output returned zero and changed exactly bytes `0..63`; the 64-byte results were identical. This strengthens the conditional signed path beyond a forced-return hook, but is **not silicon**. In particular, the emulator reports multiple unhandled SVCs as success, including `0x56` during crypto wait; those SVCs and the live CCP must be checked before relying on this as a hardware-ready recipe.
+
+Unlike the separate `0x1016` short-input leaf, this path has **no identified signed sOS `SVC 0x6B` stub gate**: its `SVC 0x68` is the signed sOS `.54` cache-maintenance handler `sub_1054`, not a constant-error stub. The model result does not establish that `sub_E1C85C` can complete on the card with the chosen request, nor that an adjacent live mapping belongs to another process. A real target-effect or DoS claim requires intact GCP→sOS→SYS_DRV mapping/CCP behavior and independent hardware observations; do not issue a state-changing crypto request just to obtain a return code.
diff --git a/fw/CANDIDATE-GCP-SYSDRV-1030-FLASH-CLASS-GATE.md b/fw/CANDIDATE-GCP-SYSDRV-1030-FLASH-CLASS-GATE.md
new file mode 100644
index 0000000..50a3d05
--- /dev/null
+++ b/fw/CANDIDATE-GCP-SYSDRV-1030-FLASH-CLASS-GATE.md
@@ -0,0 +1,50 @@
+# Free SYS_DRV `.54` `0x1030`: caller-settable SPI class gate words
+
+**Conditional flash-authority/lifecycle lead.** The signed code and a
+synthetic table test establish that free `0x1030` can change the two
+SYS_DRV-private selector words used by the `0x1094` SPI-write lookup;
+this does **not** establish a live writable flash partition, a tag as a
+security ACL, a real SPI write or a restoration oracle. Do not issue
+these stateful opcodes on the card merely to obtain a return value.
+
+`sub_E105A8` dispatches free `0x1030` to `sub_E1411C(msg+14)`.
+Selector **5** stores the unrestricted `msg[15]` dword at `0xE257A8`;
+selector **13** stores it at `0xE257AC`. Those stores have no comparison
+against the invoking TA's identity or a current initialization phase.
+The leaf's `SVC 0x66` return is not used to authorize these two
+selectors. Other `0x1030` selectors write unrelated private state;
+selector `0x13` (hexadecimal) also invokes a keyed-store path and was
+**not** used in this test—our selector 13 is **decimal** (`0xD`).
+
+`sub_E0AE90`, reached from free `0x1094` on its initialized-mode SPI
+write branch, calls `SVC 0x66` **in SYS_DRV's context**, takes the
+returned process-index byte, and compares it to `0xE257A8` first.
+If it matches, requested class `msg[14]==0` selects tag **4**; if it
+matches but class is not 0, the helper **rejects without checking the
+second gate**. Otherwise it compares the same index with `0xE257AC`;
+a match plus class `msg[14]==5` selects tag **84**. Class 1 selects
+tag 34 without either comparison. The class scalar, gate value, and
+sOS process index are distinct: the observed emulator `SVC 0x66`
+identity is **0**, so setting gate-5 to 5 does *not* enable class 5.
+The live SYS_DRV process index is unmeasured.
+
+`psp_emu/harness/probe_sysdrv_1030_flash_class_gate.py` passed on the
+signed `.54` dispatcher and signed lookup helper. After initialization
+its two gates were `0xFF` in the emulator. It planted a **synthetic**
+three-row table (tags 34/4/84), confirmed classes 0 and 5 initially
+fail, used `0x1030(5,0)` to make tag 4 selectable, then used
+`0x1030(13,0)` to set the second gate. The first gate's precedence
+initially still rejected class 5; restoring gate 0 to `0xFF` enabled
+the tag-84 lookup. It restored both synthetic gate dwords and issued
+**no** SPI write. Emulator init uses unrelated default-success SVCs;
+the `$RA2` table was planted, not read from hardware or authenticated.
+A scoped 144-ELF immediate scan found no direct `0x1030` hit; this
+does not exclude computed callsites or establish no legitimate client.
+
+The separate `0x1094` tag/base-versus-final-row mismatch is in
+`fw/CANDIDATE-GCP-SYSDRV-1094-CROSS-PARTITION-SPI-WRITE.md`.
+Whether gates 0/5 are meant as process authorization, whether the
+live `$RA2` table contains matching tags, and whether any safe
+live observation/restoration exists remain open. Do not equate
+signed-dispatch setter success or a synthetic identity with a live
+GCP-to-flash effect.
diff --git a/fw/CANDIDATE-GCP-SYSDRV-1032-ERROR-STATUS-FLAG.md b/fw/CANDIDATE-GCP-SYSDRV-1032-ERROR-STATUS-FLAG.md
new file mode 100644
index 0000000..eb8b213
--- /dev/null
+++ b/fw/CANDIDATE-GCP-SYSDRV-1032-ERROR-STATUS-FLAG.md
@@ -0,0 +1,31 @@
+# SYS_DRV `.54` free `0x1032`: status flag set despite error return
+
+**Signed-dispatch/model side effect; hardware impact unknown.**
+`sub_E105A8` case `0x1032` calls `sub_E0280C` without using a caller
+pointer. Raw signed `0xE0280E..0xE02818` sets private byte
+`0xE26150=1` **before** its readiness check `sub_E0DEC8`, fixed
+register `SVC 0x7B`, and follow-on stateful helpers. It does not
+undo this store on the examined error path. Signed `0x1077 →
+sub_E0ABE0` returns this byte as status **inline at message offset
+`msg[14]+8`**, so the effect is separately observable through a
+signed getter; it is **not** a caller-selected output pointer. Signed
+`sub_E20570` can clear the same private byte on a management path,
+not a proven safe card restoration oracle.
+
+`psp_emu/harness/probe_sysdrv_1032_status_flag.py` passed on the
+signed `.54` dispatcher with modeled caller caps 2: default init
+started with flag 0 and signed `0x1077` status byte +8 equal to 0.
+A `0x1032` call returned **`0xFFFF0008`** yet left the private flag
+**1**; a second signed `0x1077` returned status byte +8 equal to 1.
+The test directly restored the byte **only in emulator memory**. Its
+fixed-register, logging and other initialization SVCs were not
+hardware-complete: in particular the emulator warned that
+`SVC 0x9A` was unhandled and returned default success. Neither the
+returned error nor modeled state is a card effect.
+
+The flag may intentionally mean "initialization attempted" rather
+than "completed"; signed reader semantics, later consumers, caller
+policy, real hardware register values and a card restoration oracle
+are open. Do **not** invoke `0x1032` on the card for a return code.
+This is a conditional state/consistency lead, not a demonstrated
+availability, cross-client, or privilege vulnerability.
diff --git a/fw/CANDIDATE-GCP-SYSDRV-1033-SHORT-INPUT.md b/fw/CANDIDATE-GCP-SYSDRV-1033-SHORT-INPUT.md
new file mode 100644
index 0000000..d92da31
--- /dev/null
+++ b/fw/CANDIDATE-GCP-SYSDRV-1033-SHORT-INPUT.md
@@ -0,0 +1,21 @@
+# SYS_DRV `.54` free `0x1033`: 40-byte input read after a four-byte declaration
+
+**Status:** signed request dispatcher/leaf plus isolated synthetic-caller-window tests. No card request, proven out-of-process read, or live fault. Unlike `0x1016`, there is no intervening signed sOS `SVC 0x6B` constant-error gate before this read. Successful continuation into this opcode's state-changing helper has **not** been tested on the card.
+
+## Signed-code path
+
+The GCP-accessible free service-1 opcode `0x1033` (decimal case 4147 of `sub_E105A8`) invokes `sub_E134B8(msg[14],msg[2])` at `0xE134B8`. The dispatcher first checks nonzero request pointer/length pairs at `msg[2:3]`, `msg[4:5]`, etc. The signed access row at `0xE25D64` is `{0x1033,1,0,0,0}`: slot 0 is an input, and the validator checks `msg[2]` only for the caller's declared `msg[3]` bytes.
+
+`sub_E134B8` **unconditionally copies 40 bytes from `msg[2]` to its stack** before calling `sub_E09E70(msg[14],stack40,0)`, then conditionally calls `sub_E0A494`. It never receives or checks `msg[3]`. Thus a four-byte declaration does not cover its actual source reads. This is an input-size mismatch; it is not a proven cross-TA read because the sOS/SYS_DRV page mappings may fault or bound the target at the caller's boundary.
+
+The signed sOS `.54` `SVC 0xB5` case 100 (`sub_27F8`) supplies the actual caller-window descriptor to SYS_DRV's `sub_E0DEF4`. For an active type-5 TA and access flag 1, it can report `0x400000..0x800000` as a window (additional ambient process-state windows are conditional). Raw SYS_DRV `sub_E0DEF4` at `0xE0DF2C..0xE0DF56` checks `pointer + **declared length**` against that descriptor or its other allowed interval; it has no knowledge of the leaf's 40-byte copy. This strengthens the *static* validator-mismatch finding. The current harness uses this main-window limit as its descriptor but **artificially removes read permission** on the page at `0x800000` (an unrelated synthetic flash mapping otherwise overlaps it). That forced emulator protection boundary does not establish the card's PTE or any neighboring process.
+
+## Narrow emulator controls
+
+`python3 psp_emu/harness/probe_sysdrv_1033_short_input.py` compiles and passes against signed `sys_drv_0.49.0.54_18bd9d26.elf`. Signed init/dispatcher/request validation and the entire 40-byte leaf copy run unmodified. The harness supplies a **synthetic** `[0x400000,0x800000)` type-5 main-window descriptor via `SVC 0xB5`, with a deliberately protected page beyond its end. It hooks **only the downstream `sub_E09E70` state-changing helper**, capturing its 40-byte stack input and returning an error before state mutation.
+
+* Fully mapped input, `msg[3]=4`: the signed helper's captured stack input equals all **40 planted bytes**, not merely the declared four.
+* Synthetic window `end-4`, declared **40**: validator rejects `0xFFFF000F` before reaching the leaf.
+* Same edge, declared **4**: validator admits the pointer; the signed copy faults at the **artificially protected** emulator address `0x800000` **before** the state-changing helper.
+
+The emulator's B5 descriptor, MMU mappings, init configuration and other SVC behavior are not the live card's. An edge fault here is not evidence of a hardware fault or neighboring-process disclosure. The leaf's downstream mutation lacks a restoration oracle; do not invoke `0x1033` on hardware just for a status. Next: verify actual sOS caller-region behavior and whether a benign, mapped GCP-owned 40-byte input can be used without entering unsafe state mutation, in a connected emulator before any silicon claim.
diff --git a/fw/CANDIDATE-GCP-SYSDRV-1059-ERROR-RETURN-DESCRIPTOR-POISON.md b/fw/CANDIDATE-GCP-SYSDRV-1059-ERROR-RETURN-DESCRIPTOR-POISON.md
new file mode 100644
index 0000000..4789afb
--- /dev/null
+++ b/fw/CANDIDATE-GCP-SYSDRV-1059-ERROR-RETURN-DESCRIPTOR-POISON.md
@@ -0,0 +1,71 @@
+# SYS_DRV `.54` `0x1059`: indexed descriptor bit set before error return
+
+**Status:** signed-code state-integrity candidate; synthetic signed-dispatch
+proof only. Do **not** invoke this opcode on the card merely for a return
+code. The backing table's live ownership, natural consumer effect and an
+exact hardware restoration oracle are unknown.
+
+The ACL-free SYS_DRV `0x1059` case in `sub_E105A8` calls
+`sub_E11980(msg+14, 0, caller_context)`. With `msg[16]==0`, that leaf
+calls `sub_E18B7C(msg[14], msg[15])` **before** returning fixed error
+`0xFFFF000A` whenever `msg[15]!=0xFFFF`. `sub_E18B7C` maps the selector
+`0xFFFF` to 15, rejects selectors `>15`, then **ORs 5** into the selected
+private descriptor word at `0xE45A20+8*selector` and copies its two dwords
+into SYS_DRV scratch at `0xE43B00+446*4`. Only **after these stores** does
+it request `SVC 0x8B` (and potentially `0x6D`/`0x6C`). No owner comparison
+precedes the stores. The outer fixed error hides a real state change on
+this branch. The separate `0x101E` teardown flag array is at `0xEA658C`;
+**these are not the same table** and this does not stage that teardown.
+
+`python3 psp_emu/harness/probe_sysdrv_1059_error_side_effect.py` passed
+on the signed `.54` dispatcher. In a synthetic SYS_DRV instance, slot 3
+started zero and slot 4 was a marker. A caller-2 request
+`{opcode=0x1059,msg[14]=0x1234,msg[15]=3,msg[16]=0}` returned
+`0xFFFF000A` yet changed slot 3 to `5`, leaving slot 4 unchanged. A
+modeled `SVC 0x8B` returned failure 9. Negative controls with `msg[16]=1`
+or selector 16 returned the same fixed error without the selected store.
+The private snapshot was restored in the emulator. SYS_DRV initialization
+used default-success handlers for several unrelated SVCs: neither that
+initialization nor the mocked `0x8B` establishes a live kernel mapping or
+return/effect behavior.
+
+A fresh exact-literal search of IDA's loaded signed SYS_DRV `.54` image for
+`0xE45A20` found **only** `0xE05C58` (bitmask-selected clears in
+`sub_E05C38`), `0xE12D70` (128-byte bulk zero in `sub_E12C44`),
+`0xE1316C` (bit OR in a later `sub_E12D80` path), and `0xE18C40`
+(this setter). Searches for the 15 other aligned slot addresses found
+no literal. These are **not** a proof against computed addresses or
+indirect aliases. The clear helper is reached via a tail branch from
+`sub_E1B468` in `sub_E1B48C`, which the dispatcher places at opcode
+`0x311A`—inside GCP's rejected `0x3100..0x31FF` ACL range. Its
+stateful unmap loop uses `SVC 0x89`/`0x8A` and cannot serve as a safe
+restoration oracle. Its signed `a1 >= 15` guard also **rejects slot 15**,
+whereas `0x1059`'s leaf accepts selected index 15. (The leaf also maps
+`0xFFFF` to 15, but `0x1059`'s outer path does not take that sentinel.)
+A targeted synthetic extension of
+`python3 psp_emu/harness/probe_sysdrv_1059_error_side_effect.py`
+confirmed `0x1059(index=15)` returns `0xFFFF000A` after storing 5,
+while the signed `sub_E1B48C(15)` early guard returns `0xFFFF0006`
+without clearing it. The test **does not** execute any accepted
+stateful unmap path, and its SYS_DRV initialization still has several
+unrelated default-success SVC stubs. Thus the examined per-slot clear
+path cannot undo a slot-15 bit set; it does not prove there are no
+indirect or global reset paths. The bulk zero in `sub_E12C44` also follows complex
+stateful work and does **not** provide a safe isolated restoration.
+`sub_E12D80` only ORs another selected bit on the examined path;
+`sub_E18B7C` reads the selected two words, ORs 5 and immediately copies
+them to scratch for its own `SVC 0x8B`. No separate later read-only
+consumer of the poisoned word has been established.
+
+Signed sOS `.54` `sub_59E8` case 58 handles `SVC 0x8B`: it first calls
+`sub_17C0` for address/class gating and, if that succeeds, calls
+`sub_3A04` with a descriptor from the SYS_DRV request, reaching process
+mapping/allocation helpers. This is a **stateful kernel path**, not a
+read-only status SVC. The private table's other signed writer
+`sub_E12D80` is issued by SYS_DRV `0x1007`'s loader branch; the bulk
+reset `sub_E12C44` is opcode `0x1056`. Neither connection shows a
+specific later **read** of the poisoned bits or a GCP-triggerable victim
+failure. Real `0x8B` acceptance, descriptor identity, natural consuming
+path after GCP, and cross-client impact have **not** been established.
+Error status is not a hardware-effect oracle; no state-changing card
+request was made.
diff --git a/fw/CANDIDATE-GCP-SYSDRV-105D-ZERO-LENGTH-TMR-RANGE.md b/fw/CANDIDATE-GCP-SYSDRV-105D-ZERO-LENGTH-TMR-RANGE.md
new file mode 100644
index 0000000..52ee1cc
--- /dev/null
+++ b/fw/CANDIDATE-GCP-SYSDRV-105D-ZERO-LENGTH-TMR-RANGE.md
@@ -0,0 +1,59 @@
+# Free SYS_DRV `.54` `0x105D`: zero-length TMR range underflows to all-one end register
+
+**Conditional signed-code descriptor defect; no card TMR effect or
+cross-client access demonstrated.** Signed high dispatch case `4189`
+passes inline `msg[14..]` and fixed mode **1** to `sub_E1447C`.
+The leaf checks address/length alignment and high-word limits, but
+has **no nonzero length check**. Mode 1 also skips its private
+limit-length comparison. After the mutex and 16-slot/ownership
+allocator `sub_E17EF4`, it writes a start page and an inclusive
+**`(start+length-1)>>16`** end page through `sub_E218FC` to fixed
+fabric descriptor registers. With aligned start **0** and length
+**0**, the 64-bit decrement produces an all-one end register rather
+than an empty range. Other aligned starts with zero length produce an
+end page below the start page. Accepted class **49 (`0x31`)** then
+writes the two descriptor control words; no source buffer or
+caller-selected fabric **address** is passed to `SVC 0x7C`.
+
+`psp_emu/harness/probe_sysdrv_105d_zero_length.py` passed on signed
+`.54` dispatch for three separate synthetic environments. It captures
+rather than executes the fixed-fabric `SVC 0x7C` writes:
+
+| inline start | inline length | modeled return | writes to `0x49007A00/+4/+8/+12` |
+|---:|---:|---:|---|
+| `0` | `0` | `0` | `0, 0xFFFFFFFF, 0x37, 0x30038` |
+| `0` | `0x10000` | `0` | `0, 0, 0x37, 0x30038` |
+| `0x10000` | `0` | `0` | `1, 0, 0x37, 0x30038` |
+
+This is **not a natural hardware completion**. Earlier independent
+card shots of standalone `0x105D` on stock `.54` returned
+`0xFFFF000F` inside `sub_E17EF4` even for several descriptors:
+the post-boot transfer-slot/setup state did **not** support
+reservation. Those shots did not test this zero-length descriptor.
+The correction and hardware limits are documented in
+`fw/DIFF-SPIROM_XFER-51-VS-54-TMR-FIX-SCOPE.md`. The real
+host-facing SETUP_TMR path is `0x1006`, which `.54` guards; the
+`.51` rollback finding is **not** a `.54` `0x105D` bypass.
+
+The emulator's
+external-timebase-dependent mutex helper `sub_E16210` was narrowly
+short-circuited to success; its other SVCs, including process-index
+`0x66`, fixed-register `0x7B`, and the descriptor fabric `0x7C`
+were not backed by live hardware. The modeled empty slot was 0; a
+natural busy table, sOS identity, TMR register acceptance, ASIC
+meaning of control `0x37`, and whether end `0xFFFFFFFF` means a
+large range versus invalid/sentinel are unmeasured. The modeled
+`0x105D` success does **not** prove a live broad-memory mapping,
+protection bypass or restoration oracle. Do not invoke this opcode
+on the card to get a return code.
+
+`sub_E218FC` bounds its register offset to `<0x180` and uses fixed
+base `0x49007A00`; raw `sub_E1447C` uses fixed auxiliary fabric
+writes for classes 13/58. Signed sOS `.54` `SVC 0x7C` case 43
+routes through `sub_6F3A → sub_3D8C`; its software exclusion
+`sub_6D20` does **not** reject the fixed `0x49007A00` range, which
+is above the `0xCB10000` cutoff. This is not hardware decode or
+successful card-write evidence. This candidate is an **unvalidated range
+length/descriptor semantics issue**, not arbitrary fabric-address
+selection. Its SYS_DRV-side `SVC 0x66` owner is the SYS_DRV process,
+not an independently demonstrated GCP or other-client identity.
diff --git a/fw/CANDIDATE-GCP-SYSDRV-105F-SHORT-INPUT-REG-PROGRAM.md b/fw/CANDIDATE-GCP-SYSDRV-105F-SHORT-INPUT-REG-PROGRAM.md
new file mode 100644
index 0000000..4fdde51
--- /dev/null
+++ b/fw/CANDIDATE-GCP-SYSDRV-105F-SHORT-INPUT-REG-PROGRAM.md
@@ -0,0 +1,49 @@
+# Free SYS_DRV `.54` `0x105F`: short declared input before indexed fixed-register programming
+
+**Reached signed-code input-span mismatch in a synthetic caller
+window; no live register or cross-client effect.** Role row at
+`0xE25E68` is `{0x105F,1,0,0,0}`: dispatch validates the
+`msg[2]` pointer against declared `msg[3]`, then passes it directly
+to `sub_E148E0`. The signed leaf's **first** read at `0xE148EA`
+is caller byte `+32`, followed by byte `+61`, without a requirement
+that the declaration cover either field. A four-byte declaration
+passes the role check, yet cannot bound these reads. The leaf later
+reads values at `+24/+28`, a Boolean at `+62`, and fields through
+`+60`; its two index bytes are bounded `<16` and `<18` before
+indexed fixed-table accesses. Nonzero caller fields can request
+`SVC 0x7C` writes to addresses selected from fixed signed-ELF
+register tables; this is **not** an arbitrary fabric address. A
+read-only before/after signed emulator-init check
+(`psp_emu/harness/probe_sysdrv_105f_reg_tables.py`) found all 148
+relevant entries nonzero and unchanged by the examined init. The
+16-entry indexed groups range through `0x69EAC..0x6A028`, with one
+16-entry group `0x69DD4..0x69E10`; the two 18-entry groups cover
+`0x69E1C..0x69EA8` in interleaved four-byte dwords. This is
+ELF-table provenance in the examined build, not measured Navi31
+register semantics or proof no later writer changes a table.
+
+`psp_emu/harness/probe_sysdrv_105f_short_input.py` passed on signed
+`.54` dispatch. A four-byte-declared **synthetic contiguous** input
+with all fields zero returned 0 and reached no fabric write. At an
+artificial scratch-page edge, the same four-byte declaration passed
+dispatch then faulted on the **first** leaf load, PC `0xE148EA`,
+FAR `0xFE001C` (`input+32`). A 63-byte declaration at that edge
+returned `0xFFFF000F` before the load. The model's `SVC 0xB5`
+caller window was planted for the edge controls; these are not live
+GCP PTEs or another client's allocation. The `SVC 0x7C` capture saw
+no write in those zero/edge controls. A **separate mapped
+GCP-owned** input then set `+24=0x13579BDF`,
+`+28=0x2468ACE0`, and index 0. Both four-byte and 64-byte
+**declared** requests returned 0 and produced identical six modeled
+fixed-address commands. The first two captured commands were
+`(0x69EAC,0x13579BDF,4)` and `(0x69EB0,0x2468ACE0,4)`; the
+remaining four targeted fixed `0x69F2C/0x69F30/0x69FAC/0x69FB0`
+with zero values. The harness only **captured** `SVC 0x7C`;
+there was no hardware register write or cross-client memory access.
+
+The live type-5 mapping and adjacent allocation owner, runtime
+table mutability, reachable write values, hardware effects, and a
+safe restoration oracle remain unproved. Do **not** invoke
+nonzero register-programming variants on the card merely for a
+return code. This is a signed span defect, not a proven cross-client
+read or independent hardware write primitive.
diff --git a/fw/CANDIDATE-GCP-SYSDRV-1063-SHORT-OUTPUT.md b/fw/CANDIDATE-GCP-SYSDRV-1063-SHORT-OUTPUT.md
new file mode 100644
index 0000000..09871a8
--- /dev/null
+++ b/fw/CANDIDATE-GCP-SYSDRV-1063-SHORT-OUTPUT.md
@@ -0,0 +1,43 @@
+# Free SYS_DRV `.54` `0x1063`: output stores through byte 171 after a four-byte declaration
+
+**Signed-code caller-span mismatch; no demonstrated live cross-allocation
+write.** `sub_E105A8` dispatches free `0x1063` to
+`sub_E0AF30(msg[2],msg+14)`. Its role row at `0xE25E7C` is
+`{0x1063,2,0,0,0}`: the dispatcher validates the output pointer
+against **declared** `msg[3]`, not against the separate scalar
+`msg[14]`. In the leaf, `*a2=msg[14] >=6` is the only width-like
+requirement. The function writes six sparse three-dword groups and
+other fields at the caller output; the final `a1[42]` store spans
+**bytes +168..+171**. It never requires `msg[3]>=172`. `msg[14]` is
+then set to 6. These values are not a selected arbitrary source
+address: the leaf gathers private status and two signed property
+queries; some property calls can fail without preventing the fixed
+stores. No possible key bytes are printed.
+
+`psp_emu/harness/probe_sysdrv_1063_short_output.py` passed on the
+signed `.54` dispatcher and leaf with a **synthetic GCP-owned mapped
+output region**. With `msg[3]=4,msg[14]=6`, the signed dispatcher
+returned success, changed bytes through `+171` (including `+168..171`),
+and did not change the sentinel from `+172` onward. A count-5 control
+returned an error without stores; a fully declared 172-byte control
+produced the same first 172 bytes. The emulator's unrelated init SVCs
+and property `SVC 0xA4` can default to success, so this does not
+establish genuine hardware property values. The output-region oracle
+is an artificial contiguous buffer, **not** another TA's allocation
+or a real sOS PTE boundary.
+
+A scoped immediate/aligned-literal scan of the available extracted
+signed-client ELFs found no direct `0x1063` hit. This does not exclude
+computed RPCs or other firmware sets, and the free GCP-ROP route does
+not require a signed client to call this opcode.
+
+Signed sOS `SVC 0xB5` supplies coarse type-5 process windows to the
+SYS_DRV declared-span checker, **not** a per-byte/PTE assertion for
+the leaf's later 172-byte write (`fw/AUDIT-SOS54-B5-DECLARED-SPAN-WINDOWS.md`).
+
+**Open:** actual live type-5 whole-span mapping, neighboring ownership,
+selected output address provenance, fault behavior, and an independent
+benign exactly restorable target. Do not claim cross-client corruption
+from a return value or synthetic adjacent bytes. No card request was
+issued. This is distinct from the `0x1076` and `0x107B` short-output
+candidates.
diff --git a/fw/CANDIDATE-GCP-SYSDRV-1067-FAILED-LOCK-COUNT.md b/fw/CANDIDATE-GCP-SYSDRV-1067-FAILED-LOCK-COUNT.md
new file mode 100644
index 0000000..a405fe0
--- /dev/null
+++ b/fw/CANDIDATE-GCP-SYSDRV-1067-FAILED-LOCK-COUNT.md
@@ -0,0 +1,44 @@
+# Free SYS_DRV `.54` `0x1067`: failed fabric-lock acquisition increments global count
+
+**Signed-code bookkeeping defect under modeled fixed-register failure;
+no live shared-lock effect.** Historical overview calls `0x1067` a
+tiny/query getter. Signed `sub_E105A8` case 4199 calls
+`sub_E140E0(selector=byte(msg[14]),timeout=msg[15])`. Selector
+zero enters `sub_E16210(timeout)` and nonzero enters
+`sub_E16278(timeout)`. Both use an sOS mutex and SYS_DRV-private
+byte **`0xE252D0`** as a lock nesting counter. On the zero-count
+acquire path, `sub_E16210` may poll fixed fabric `0x49005300` via
+`sub_E08048`, setting bit 5 with `SVC 0x7C` and returning
+`0x80000306` when its bounded poll of bit 0 times out. Raw signed
+`0xE16254..0xE1625C` **increments the private counter even when
+that call failed**. A subsequent acquire sees a nonzero counter,
+skips the fabric attempt and returns **success** while incrementing
+again. Release decrements; on reaching zero it can invoke signed
+`sub_E0981C → SVC 0xA6` for fixed address `0x49005300`, mask
+`0x20`, to clear the bit. Signed sOS `.54` SVC `0xA6` case 85
+performs a masked register update via `sub_465C`; it is not a
+modeled-only address selection.
+
+`psp_emu/harness/probe_sysdrv_1067_failed_lock_count.py` passed on
+signed `.54` dispatch with **only synthetic** fixed-register
+`SVC 0x7B/0x7C/0xA6` responses and a stubbed external-timebase
+one-step yield. With modeled contention and timeout **1**, the
+first acquire returned `0x80000306` but moved counter 0→1 and
+captured a bit-5 write request. The next acquire returned **0**
+and moved 1→2 **without another register read**. Two releases
+returned 0, moved 2→1→0 and captured the fixed `SVC 0xA6` bit-5
+clear request on the second. These are signed control-flow and
+synthetic state observations, **not** actual lock acquisition,
+hardware bit changes, or a victim.
+
+Raw `sub_E08048` compares a 32-bit loop counter to the caller
+`msg[15]`. `0xFFFFFFFF` can defer its timeout until wrap while
+repeatedly polling a nonclearing bit; an unbounded or long wait is
+a separate **conditional** availability lead, not a measured hang.
+Do **not** request that timeout on the card. The real fabric
+register/status, concurrency, other clients' lock use, natural
+failure feasibility, MMU/fabric mapping and exact recovery oracle
+remain open. The error-return count increment could be intentional
+bookkeeping if a failed poll still owns bit 5; whether that
+interpretation prevents false success or lock interference has not
+been demonstrated on hardware.
diff --git a/fw/CANDIDATE-GCP-SYSDRV-106A-SELECTOR2-SHORT-SPANS.md b/fw/CANDIDATE-GCP-SYSDRV-106A-SELECTOR2-SHORT-SPANS.md
new file mode 100644
index 0000000..d3d39f7
--- /dev/null
+++ b/fw/CANDIDATE-GCP-SYSDRV-106A-SELECTOR2-SHORT-SPANS.md
@@ -0,0 +1,40 @@
+# Free SYS_DRV `.54` `0x106A(2)`: input overread and output overrun relative to declarations
+
+**Conditional signed-code span mismatch; no live cross-allocation effect.**
+The signed dispatcher passes `msg[2]` and `msg[4]` to `sub_E14A10`.
+Its role row at `0xE25E90` is `{0x106A,1,2,0,0}`: the first input
+and second output pointer pairs are checked against their **declared**
+`msg[3]`/`msg[5]` lengths. The leaf first reads a byte at
+`input+12`, even if `msg[3]=4`; it then reads a selector dword at
+`input+4`. For selector 2, after a global gate at `0xE25010`, it
+writes two dwords at **`output+20..23` and `output+64..67`** without
+checking `msg[5]>=68`. A four-byte declared output suffices for the
+signed dispatcher's pointer check. The output values are derived from
+SYS_DRV state, not a caller-selected arbitrary source address.
+
+`psp_emu/harness/probe_sysdrv_106a_short_spans.py` passed on signed
+`.54` dispatch/leaf. Signed **default emulator init left `0xE25010=0`**
+and a selector-2 request returned `0x80000310` without stores. After
+**planting gate=1 in synthetic SYS_DRV-private memory**, an input
+and output both declared as four bytes returned success, read the
+selector at `input+4`/flag at `+12` from a deliberately contiguous
+synthetic input, and wrote through output byte `+67`. A control with
+16-byte input/68-byte output produced identical output through +67;
+bytes beyond +67 retained the sentinel. The harness restored the
+modeled gate. This does not demonstrate a live short-input read or a
+write to any other allocation.
+
+**Natural-gate provenance:** signed init `sub_E0CA2C → sub_E03C24`
+sets the gate only if `sub_E17C14` succeeds. That helper looks for
+descriptor ID **324** in a 16-entry private table and performs
+additional nonzero/bounds checks. The live descriptor and gate value
+are unknown. A scoped immediate/aligned-literal scan of extracted
+signed clients found no direct `0x106A` candidate; computed calls and
+other builds remain open. Other signed `0x106A` selectors run stateful routines;
+none was invoked on hardware. The emulator's unrelated initialization
+SVCs include default-success handlers. Signed sOS `SVC 0xB5`
+provides coarse process windows to the declared-span checker, not a
+PTE proof for the leaf's `+12/+64` accesses
+(`fw/AUDIT-SOS54-B5-DECLARED-SPAN-WINDOWS.md`). Do not infer live
+descriptor 324, whole-span PTE access, cross-client ownership or a
+safe restoration oracle from the planted-gate test.
diff --git a/fw/CANDIDATE-GCP-SYSDRV-107B-SHORT-OUTPUT.md b/fw/CANDIDATE-GCP-SYSDRV-107B-SHORT-OUTPUT.md
new file mode 100644
index 0000000..08225df
--- /dev/null
+++ b/fw/CANDIDATE-GCP-SYSDRV-107B-SHORT-OUTPUT.md
@@ -0,0 +1,113 @@
+# Candidate: free SYS_DRV `0x107B` writes through offset 51 of a shorter declared output
+
+**Signed `.54` dispatch and isolated signed-leaf emulator evidence. No card
+invocation, cross-process write, or live fault demonstrated.** Unlike gated
+`0x1002`, this opcode is in the GCP-ROP-reachable high-opcode set. The
+candidate defect is a mismatch between pointer-range validation and the
+callee's fixed output extent; clearing its internal table is a separate,
+possibly intended, side effect.
+
+## Signed request-to-store trace
+
+* `sub_E105A8` calls `sub_E05A24(opcode)` before dispatch. `0x107B`
+ (`4219`) does not fall in any of that ACL helper's eleven gated ranges;
+ its opcode/pointer table entry at `0xE25850 + 82*20` is
+ `{0x107B,2,0,0,0}`. Slot 0 uses caller-supplied
+ `(request[2],request[3])`: for a nonzero pointer the dispatcher calls
+ `sub_E0DEF4(request[2],request[3],2,caller_context)`. The validator's
+ signed instructions at `0xE0DF2C..0xE0DF58` compare
+ `pointer+declared_length` with the regions returned by `SVC 0xB5` (and
+ fallback SYS_DRV bounds); they do **not** impose a 52-byte minimum.
+ Its `case 4219` calls
+ `sub_E0AB74((u32 *)request[2])` and does not forward the size.
+* `sub_E0AB74` at `0xE0AB74` only checks the pointer against NULL. It
+ zeroes 24 bytes at `output+28..+51` (the signed `sub_E019E4` call), then
+ conditionally writes entry fields at offsets `+36,+40,+44,+48`, and
+ always writes words at `+28,+32`. Thus a valid output pointer with a
+ *declared four-byte range* can produce stores at offsets **+28..+51**,
+ beyond the declared range, with no subsequent size check.
+ These are writes to the caller buffer at its SYS_DRV-visible VA; they
+ are **not by themselves SYS_DRV-private or arbitrary CPU-RAM writes**.
+* After the output, the handler clears a 2048-byte SYS_DRV table at
+ `0xE6873C` and resets two counters at `0xE26170`. Signed producers
+ include `sub_E0D60C`. A **sibling same-class path** exists in free
+ opcode `0x1076` (table entry `0xE25EA4={0x1076,2,0,0,0}`): when
+ `*(u32 *)request[2]==1`, `sub_E2005C` also zeroes 24 bytes at
+ `output+28..+51` irrespective of slot-0 declared length, then
+ initializes/clears this table and invokes `SVC 0x7B`. This path is
+ **tested in a synthetic signed-dispatch emulator**, described below,
+ but not on hardware. The teardown cannot be treated as a demonstrated
+ security impact without identifying live table contents and a safe effect
+ oracle.
+
+## Bounded emulator observations
+
+`python3 psp_emu/harness/probe_sysdrv_107b_output_size.py` executes **the
+original signed SYS_DRV `.54` leaf** with a synthetic one-entry table.
+Its output buffer is allocated large enough for observation, but its
+*nominal* declared size is four bytes: bytes `+0..+3` remain unchanged,
+while signed code changes offsets `+28..+51`, returns zero, and clears the
+table. In a separate synthetic guard-page control, the first four output
+bytes are mapped and the next page is unmapped. The signed leaf faults at
+`0xEE3024` (inside that synthetic guard); it has not reached the table
+reset. The harness does **not** run GCP, sOS service transport, the high
+opcode ACL, or `sub_E0DEF4`. The four-byte declaration is an analytical
+input to the dispatcher trace, **not a length the leaf itself checks**.
+These results establish actual signed leaf stores, not a hardware fault.
+
+A second, **connected within SYS_DRV only**, emulator trace runs
+`python3 psp_emu/harness/probe_sysdrv_107b_dispatch.py`: after synthetic
+SYS_DRV initialization, it enters signed `sub_E087E4` with opcode `0x107B`,
+slot-0 length **4** (and separately **52**) and a mapped output. Both
+requests return zero, reach `sub_E0AB74` exactly once, change output offsets
+`+28..+51`, and clear the synthetic table. The emulator's `sys_drv.elf` was
+checked byte-identical to signed `.54` (SHA-256 prefix `3ea10d44`).
+**Crucial limit:** the emulator's `SVC 0xB5` is a permissive synthetic
+caller-region oracle, and its init uses synthetic firmware/hardware state
+and unhandled-SVC defaults; it does not model the live GCP/sOS argument
+window or prove a hardware request would pass. It does show that the
+*actual signed dispatcher and pointer validator code* do not reject four
+as the declared length under this synthetic oracle. A second control in the
+same script substitutes a **synthetic** `SVC 0xB5` region
+`[0x400000,0x41C000)` and maps only that GCP-sized interval. For a pointer
+at `0x41BFFC`, a declared **52** is rejected with `0xFFFF000F` before the
+leaf, whereas a declared **4** passes, reaches the signed leaf, then faults
+at `0x41C024` on its first out-of-region store; the table remains intact.
+This contrast verifies the size mismatch under a modeled caller-window
+boundary. It still is **not** a real sOS/GCP run or a measurement of the
+card's adjacent page; actual sOS window and SYS_DRV mapping must be checked
+before promoting it to hardware impact.
+
+A third bounded harness,
+`python3 psp_emu/harness/probe_sysdrv_1076_dispatch.py`, executes the
+same byte-checked signed `.54` dispatcher and validator with sibling free
+opcode `0x1076` and selector word **1**. With synthetic caller-region
+services, **4** and **52** as declared slot-0 lengths each returned zero,
+entered signed `sub_E2005C` once, left the first four input bytes intact,
+zeroed only output offsets **+28..+51**, and cleared a planted synthetic
+SYS_DRV table word. Under a **synthetic** GCP-sized caller window,
+length 52 returned `0xFFFF000F` without entering the leaf; length 4 entered
+it and faulted at `0x41C024` before table reset. The harness's SYS_DRV
+initialization has synthetic/unhandled SVC responses; the real `SVC 0x7B`
+register-read result and caller mapping are **not** reproduced. No card `0x1076` call
+was issued; this is a second code path to the same length-mismatch class,
+not a proven second live bug or hardware cross-process write.
+
+A GCP-ROP caller can construct an ordinary service-1 request for either
+free opcode, but the selected output address must still pass the
+caller-window validator. At an interior GCP-owned buffer, the extra stores may corrupt
+**GCP's own shared memory** (similar effects were previously misclassified
+as SYS_DRV hijack). A pointer near a mapped boundary could instead fault;
+the live adjacent PTE and any effect beyond the GCP region are unmeasured.
+Neither `0x107B` nor selector-1 `0x1076` was invoked on hardware: both
+clear SYS_DRV global state, and the latter additionally calls `SVC 0x7B`.
+Their table-reset effect/restoration plans remain unknown; `0x1076`'s
+`SVC 0x7B` read returns a synthetic zero in the harness.
+
+**Status:** GCP-reachable signed-code size-mismatch candidate with both
+isolated-leaf and synthetic SYS_DRV-dispatch execution, not a proven new
+hardware vulnerability or controlled kernel write. To advance it, trace
+full-system GCP → sOS → SYS_DRV with an exact short-length request and
+intact real caller-window rules; establish a safe effect/restoration oracle
+before even considering a card invocation. Do not use
+return codes alone as write evidence.
diff --git a/fw/CANDIDATE-GCP-SYSDRV-1094-CROSS-PARTITION-SPI-WRITE.md b/fw/CANDIDATE-GCP-SYSDRV-1094-CROSS-PARTITION-SPI-WRITE.md
new file mode 100644
index 0000000..478379c
--- /dev/null
+++ b/fw/CANDIDATE-GCP-SYSDRV-1094-CROSS-PARTITION-SPI-WRITE.md
@@ -0,0 +1,85 @@
+# SYS_DRV `.54` free `0x1094`: tag-relative offset can select a different flash-table row
+
+**Conditional signed-code partition-boundary candidate, not a card flash
+write.** `0x1094` was already classified as a free `spi_write`
+interface; the new observation is a split between *which* flash-table
+row supplies its base and *which* row later authorizes the resulting
+range. Do not issue this opcode or mutate flash on hardware solely to
+obtain a return code.
+
+The signed dispatcher sends `msg[14]` (region selector), `msg[15]`
+(page scalar), `msg[16]` (offset), caller pair `(msg[2],msg[3])`,
+byte at `msg+76`, and `msg[20]` to `sub_E1B19C`. The first caller pair
+has role row `{0x1094,2,0,0,0}`; that role checks the **declared caller
+span**, not the flash destination. In the default-initialized emulator
+state `0xE26259==1`, the leaf uses `sub_E0AE90` to resolve a flash
+address and `sub_E153C8` to write it via chunked `sub_E1AA14`. The
+other branch `sub_E1A0A4` depends on different runtime state and is
+not evidence for the same write path. No post-ROP card call was made.
+
+`sub_E0AE90` requires `msg[15]<32`, checks two addition carries,
+selects a table row by a tag (selector `msg[14]==1` requests tag
+**34**), and returns that row's **base + (page<<12) + offset**.
+It does **not** require `(page<<12)+offset` to fit the selected row's
+length. The next helper, `sub_E207A4`, checks that the **entire final
+address span** fits *some* row in the shared flash table at `0xE7904C`;
+it does not compare that row's tag to 34 or to the row chosen by
+`sub_E0AE90`. Its flag at `0xE26258` would bypass even this check if
+set to 1, but the signed default-init emulator measured it **zero**;
+`sub_E168D4`'s examined initializer passes zero, so no live override
+is claimed. `sub_E067F8` bounds parsed row count to 16, each row to
+`<=0x100000` within `0x08000000`, and forbids row overlap, but does
+not impose a tag-equivalence check between these helpers.
+
+`psp_emu/harness/probe_sysdrv_1094_cross_partition_helper.py` plants
+**unsigned, synthetic** `$RA2` metadata at `0xE5FA48+0x684` and drives
+the signed `sub_E067F8` row validator/copy before the **signed lookup and
+range-check helpers**. This is not a real firmware partition layout or
+SPI device: tag-34 row
+`[0x10000,0x11000)` and tag-4 row `[0x20000,0x21000)` (tag 4 is a second class recognized
+by `sub_E0AE90` for a different selector). The same
+tag-34 lookup with offset `0x10` resolves `0x10010` and passes the
+range check; offset `0x10010` resolves **`0x20010`**, which also passes
+because the checker finds tag 4. A gap target `0x18010` is rejected
+`0x80001004`. The signed parser accepts both nonoverlapping rows without filtering
+the tag classes, then the lookup/check results above follow. The test
+stops before `sub_E153C8` or any SPI operation; SYS_DRV emulator
+initialization includes unrelated default-success SVCs. Importantly,
+`sysdrv_env` has an **entry hook** that normally overwrites `$RA2` with
+an **empty** synthetic table at every `sub_E067F8` entry; this harness
+explicitly replants the two unsigned rows *after that fixture hook* for
+the isolated parser run. An ordinary default-init emulator run therefore
+cannot be cited as a natural two-row table. A raw `sub_E1A0A4` call must **not** be equated with this path:
+its apparent unused caller pointer in Hex-Rays is passed as a source
+to a `BLX sub_E018A0` copy in the signed Thumb instructions.
+
+**Provenance checks, not a live table:** The local
+`psp_out/flash_BIOS{1_STUCK,2_KNOWNGOOD}_20260917.bin` and
+`psp_out/spiflash.bin` files are only 2 MiB each, whereas signed
+`sub_E069B0` requests a page at flash address `0x7FB000`. Neither
+`$ROM` nor `$RA2` appeared as raw bytes in these three files; looking
+at `0x1FB000` as a possible 2-MiB alias also yielded zeros. These
+artifacts do **not** supply the runtime partition table or establish a
+flash address alias. A selected 144-ELF opcode-immediate scan found
+`0x1094` hits only in four later ASD `.235/.239` variants, not in the
+active `.163`. In sampled ASD `.239`, all four sites are **byte offsets
+into ASD state** in `sub_D0D87C`, `asd_hdcp1_teardown` and
+`asd_srm_sub_12EC4`, not service-1 RPC selectors. The other three
+variants and computed callsites remain open; no natural signed caller
+of this opcode was established by this scan.
+
+A separate signed free `0x1030` setter can rewrite the process-index
+comparison words that gate tag-4/tag-84 selection in `sub_E0AE90`;
+its synthetic test and the priority ordering of the two gates are in
+`fw/CANDIDATE-GCP-SYSDRV-1030-FLASH-CLASS-GATE.md`. This does not
+make a natural live tag-4/tag-84 row or SPI effect appear.
+
+This establishes a **tag confinement mismatch in signed helpers** with
+a conditional route from free `0x1094`. It does **not** establish that
+the live signed flash table has a reachable second row at a higher
+address, that tag 34 is an authorization boundary rather than a lookup
+convenience, that GCP's actual CPU-VA buffer maps as assumed, that
+`sub_E153C8`/hardware accepts the write, or that any victim flash
+state can be exactly restored. An independently observed live table,
+signed partition policy and safe restoration oracle are prerequisites
+to any stronger impact claim; no stateful card probe is justified here.
diff --git a/fw/CANDIDATE-GCP-SYSDRV-1098-SHORT-INPUT.md b/fw/CANDIDATE-GCP-SYSDRV-1098-SHORT-INPUT.md
new file mode 100644
index 0000000..14db020
--- /dev/null
+++ b/fw/CANDIDATE-GCP-SYSDRV-1098-SHORT-INPUT.md
@@ -0,0 +1,20 @@
+# SYS_DRV `.54` free `0x1098`: first 1024-byte read exceeds declared input
+
+**Status:** signed dispatcher and first-copy path plus synthetic-window emulator controls. No card `0x1098` request, signed-image acceptance, cross-process read, or hardware fault. Do not retry the recently faulting GCP hardware ROP chain for this lead.
+
+## Signed ordering and sOS gate
+
+`sub_E105A8` case 4248 (`0x1098`) admits the first request pair `(msg[2],msg[3])` by its role row at `0xE25F1C = {0x1098, 2, 0, 0, 0}`. For a nonzero GCP caller index, `sub_E0DEF4` validates this **output-role** pointer against a type-5 window using `SVC 0xB5` and the **declared** `msg[3]` length; it imposes no 1024-byte minimum. `msg[8]` must remain zero for this caller: its pointer role is 0, and making it nonzero fails before dispatch. Do not treat the leaf's conditional later `*msg[8]` store as a demonstrated GCP-controlled output.
+
+The opcode first issues `SVC 0x79` on `msg[2]` (signed sOS `.54` case 40, `sub_6D84`, an address translation); it does not branch on that return before invoking `sub_E1217C`. Raw instructions at `0xE11664..0xE11668` pass the original `msg[2]` in R3. At `0xE121A4..0xE121B2`, the leaf fixes R1 to `0x400` and calls `sub_E06548`; that helper's raw `0xE06564..0xE0656A` copies **1024 bytes from R3** into its SYS_DRV stack local via `sub_E018A0`, before `SVC 0x68`, image parsing, signature/crypto validation, and any output. A four-byte declaration therefore permits a 1024-byte first read if the address is otherwise admitted. This mismatch is independent of whether the supplied image can be verified.
+
+## Bounded emulator controls
+
+`python3 psp_emu/harness/probe_sysdrv_1098_short_input.py` compiles and passes against signed `sys_drv_0.49.0.54_18bd9d26.elf`. It runs signed init, validator, dispatcher, leaf and first memcpy unmodified, observing the destination **immediately after the signed copy**. It supplies a **synthetic** `[0x400000,0x800000)` type-5 descriptor via `SVC 0xB5` and deliberately removes read permission at `0x800000`, otherwise obscured by the emulator's unrelated synthetic flash mapping. Unhandled SVCs use emulator defaults, notably `SVC 0x79`; the signed sOS handler's return is ignored until after this copy.
+
+* Fully mapped non-image marker with `msg[3]=4`: independent readback of the leaf's stack buffer captured **all 1024 marker bytes**. The malformed-image parser subsequently returned `0xFFFF0008`; no accepted image or successful crypto path is claimed.
+* A nonzero `msg[8]` chosen-output pointer to mapped GCP-owned RAM, with four-byte input/output declarations, returned `0xFFFF000F` **before** the leaf. This independently confirms the role-0 restriction for a nonzero GCP caller; it is not an unchecked-write proof.
+* Four bytes at synthetic end `0x7FFFFC`, `msg[3]=1024`: pre-dispatch validator rejected (`0xFFFF000F`); no leaf entry.
+* Same edge, `msg[3]=4`: validation admitted it and the signed first-copy loop faulted at the **artificially protected** `0x800000`, before image parsing or crypto.
+
+The actual GCP caller PTEs, signed sOS `0xB5` descriptor contents, and adjacent ownership on the card are not measured; an emulator protection fault is not a hardware DoS or disclosure. A live request to a stateful signed-image verifier is not justified merely for a return code. The separate `0x1033` finding has a 40-byte first read; this `0x1098` path is a distinct 1024-byte signed-image-staging path.
diff --git a/fw/CANDIDATE-GCP-SYSDRV-109D-LABEL-STRING-OVERREAD.md b/fw/CANDIDATE-GCP-SYSDRV-109D-LABEL-STRING-OVERREAD.md
new file mode 100644
index 0000000..31f7f6e
--- /dev/null
+++ b/fw/CANDIDATE-GCP-SYSDRV-109D-LABEL-STRING-OVERREAD.md
@@ -0,0 +1,43 @@
+# Free SYS_DRV `.54` `0x109D`: caller label `strlen` reads beyond declared input
+
+**Signed-dispatch prevalidation read demonstrated in a synthetic
+GCP-owned buffer; live PTE/cross-client effect unproved.** The role
+row at `0xE25D14` is `{0x109D,1,1,1,2}`: `msg[2]/[3]` is a
+validated key input, `msg[4]/[5]` a validated label input,
+`msg[6]/[7]` a validated salt input, and `msg[8]/[9]` the output.
+The signed dispatcher copies the **label pointer `msg[4]`** to its
+scratch `msg[16]` but does not forward the declared `msg[5]` to the
+`sub_E07A80` label parameter. `sub_E11BC4` clears the declared
+output, then enters `sub_E07A80` directly. With required nonnull
+inputs, `sub_E07A80` calls `sub_E01864` (word-optimized `strlen`)
+on that label **before** enforcing `(strlen+5)<=0x80`. This
+walk has no four-byte declared-span bound. It is distinct from free
+`0x10A2`, where a prior crypto helper currently blocks unhooked
+emulation before reaching the same `strlen`.
+
+`psp_emu/harness/probe_sysdrv_109d_label_span.py` passed on signed
+`.54` dispatcher and leaves. It placed a NUL at synthetic GCP-owned
+`label+8`, declared **four** bytes, and observed the signed
+`sub_E07A80` post-`strlen` PC `0xE07AD0` with return length **8**.
+A nine-byte declaration returned the same observed length. Both
+requests subsequently faulted at `0xE01940`/FAR `0x680` in another
+signed crypto helper because the modeled shared crypto base
+`0xE257D8` was zero; that **later** synthetic fault neither causes
+nor invalidates the already-observed label read.
+
+A separate **artificial edge oracle** put four non-NUL label bytes at
+`0xFDFFFC`, directly before the emulator's unmapped `0xFE0000`
+page, and supplied a planted `SVC 0xB5` window ending at
+`0xFE0000`. A four-byte declaration passed signed dispatch and
+faulted at `0xFE0000` inside `sub_E01864`; a nine-byte declaration
+was rejected `0xFFFF000F` **before** `strlen`. These are modeled
+PTE/window conditions, not live sOS mappings or another TA's bytes.
+No derived key bytes were printed, and no successful KDF or card
+behavior is claimed. Emulator initialization uses unrelated
+default-success SVCs.
+
+Signed sOS `SVC 0xB5` validates coarse windows for the **declared**
+span, not the later `strlen` walk
+(`fw/AUDIT-SOS54-B5-DECLARED-SPAN-WINDOWS.md`). Real type-5 PTE
+coverage, neighboring ownership, fault behavior, and useful
+information flow remain open. No card request was issued.
diff --git a/fw/CANDIDATE-GCP-SYSDRV-35-IGNORED-RNG-FAILURE.md b/fw/CANDIDATE-GCP-SYSDRV-35-IGNORED-RNG-FAILURE.md
new file mode 100644
index 0000000..2f363c8
--- /dev/null
+++ b/fw/CANDIDATE-GCP-SYSDRV-35-IGNORED-RNG-FAILURE.md
@@ -0,0 +1,43 @@
+# SYS_DRV `.54` low `0x35`: entropy failure ignored by dispatcher
+
+**Signed-code error-propagation bug, demonstrated with modeled entropy;
+no natural card RNG failure or downstream security impact.** Low
+`sub_E1DC30` case **decimal 53 / hex `0x35`** calls
+`sub_E1E184(msg+2)` then **returns the caller-independent zero
+`v5`**, discarding the helper's status. This is not the separate
+hex-`0x53` logging opcode. The role row at `0xE25990` marks its
+`msg[2]/[3]` as a validated output pair. `sub_E1E184` returns
+`sub_E04F38(out,declared_length)`. That helper fills the output in
+four-byte chunks from `sub_E0BA34`; when entropy fails, it returns
+`0xFFFF000B`, potentially after writing some chunks. For an exact
+multiple of four bytes it also requests **one extra entropy word
+after the entire declared output was filled**, so even the helper's
+own result can fail after complete output. A zero-length request
+likewise attempts one entropy fetch. None of this implies an OOB
+store: the copy loop itself stays within the declared length.
+
+`psp_emu/harness/probe_sysdrv_35_ignored_rng_failure.py` passed on
+signed `.54` with only `sub_E0BA34` modeled (no real RNG bytes
+printed). Direct signed `sub_E04F38(out,4)` returned `0xFFFF000B`
+when the modeled first entropy fetch failed and left the synthetic
+marker untouched. The **signed dispatcher** returned **0** for that
+same first-fetch failure, still leaving the marker untouched. With
+one successful modeled word followed by a failed extra fetch, the
+entire four-byte output changed but dispatcher still returned 0;
+two successful words produced the same output and return. The
+emulator's signed default init left RNG-enable byte `0xE269B8=1`;
+no natural failed RNG request was reproduced or inferred from this
+model. Failure paths exist in signed `sub_E0BA34`: disabled gate,
+zero entropy sample, or status bit `0x20000000` set.
+
+A signed client consumer has since been identified: ASD `.163`
+`0x1A1` can call low `0x35` for a zero-initialized 16-byte buffer
+and, in a conditional ASIC-20/25 type-6 path, copy the result to
+a signed HDCP `.57` caller even if the underlying first entropy
+fetch failed (`fw/CANDIDATE-HDCP57-ASD1A1-IGNORED-ENTROPY-FAILURE.md`).
+The prefix was tested only with a modeled failed RPC and intercepted
+memcpy. A **real** failed condition, paired active clients,
+protected-session acceptance, live status, and cryptographic impact
+remain **unproved**. The four-byte marker was synthetic
+GCP-owned memory, not leaked RNG output or another client's buffer.
+No card request was made.
diff --git a/fw/CANDIDATE-GCP-SYSDRV-53-LOG-STRING-PREVALIDATION.md b/fw/CANDIDATE-GCP-SYSDRV-53-LOG-STRING-PREVALIDATION.md
new file mode 100644
index 0000000..a4afeeb
--- /dev/null
+++ b/fw/CANDIDATE-GCP-SYSDRV-53-LOG-STRING-PREVALIDATION.md
@@ -0,0 +1,21 @@
+# SYS_DRV `.54` low opcode `0x53`: logger reads caller string before declared-length/NUL check
+
+**Status:** signed helper path and isolated synthetic caller-window evidence; **not** a live cross-process disclosure, hardware DoS, or measured card log state. No deliberately crafted `0x53` request was sent to the card. A later **read-only `0x109A` logging-gate attempt faulted in GCP before producing any valid output**; see `fw/ATTEMPT-SYSDRV-53-LIVE-LOG-GATES-READONLY-FAULT.md`.
+
+## Signed ordering and conditional gate
+
+Free low opcode `0x53` (`sub_E1DC30`, case 83) passes the caller-controlled `(msg[2],msg[3])` pointer/declared length to `sub_E1DF4C`. The dispatcher first validates `msg[2]` for **only `msg[3]` bytes** using `sub_E0AB44`/`sub_E0DEF4`. In `sub_E1DF4C`, the call to `sub_E1F094(severity=msg[14], string=msg[2], caller_id)` occurs **before** the check that `msg[3]` is in `[1,256]` and `msg[2][msg[3]-1]` is NUL.
+
+When logging is enabled and the chosen severity passes its threshold, `sub_E1F094` reaches `sub_E22C30 → sub_E22CAC → sub_E2232C`. Raw `sub_E2232C` at `0xE22360..0xE22366` calls bounded-string helper `sub_E01A34(logbuf+16, caller_string, 39)`. The bound **39** is a fixed logging-buffer size, not `msg[3]`; a non-NUL four-byte declared input can therefore make the logger read up to 39 bytes before the outer handler rejects the missing NUL. The helper is bounded to its *own* 39-byte destination, so this is a source-length/window mismatch, not an asserted log-buffer overflow.
+
+Signed SYS_DRV init calls `sub_E1F000` at `0xE0CC7A`, which conditionally registers the log backend and sets its frontend flag; it reinitializes on a later branch. In the isolated emulator's successfully initialized state, frontend byte `0xE264E0=1`, level word `0xE264E4=3`, backend byte `0xE269CC=1`. **Those values are emulator observations**, not card measurements. The signed sOS `.54` `SVC 0xB5` type-5 main window can report `0x400000..0x800000`, but actual PTEs and extra ranges remain unmeasured. `SVC 0xB9/0xA7` in the emulator are unhandled success defaults; their signed sOS handlers and the real name/PCB state may affect log metadata, not yet a proven bypass of the string-read path.
+
+## Bounded emulator evidence
+
+`python3 psp_emu/harness/probe_sysdrv_53_log_prevalidate.py` compiles and passes against signed `sys_drv_0.49.0.54_18bd9d26.elf`. It runs signed init, dispatcher, logger and string copy. It supplies a **synthetic** type-5 descriptor `[0x400000,0x800000)` via `SVC 0xB5` and deliberately protects the page at `0x800000`; the initialization model would otherwise map unrelated synthetic flash across this boundary. This forced protection is not a card PTE measurement.
+
+* A fully mapped 40-byte **non-NUL** marker with only four bytes declared reached the signed logger. An observer immediately before its log drain independently captured **39 marker bytes** in the log staging buffer; outer status was zero (the later NUL condition simply did not append to the separate ring).
+* At the synthetic boundary `0x7FFFFC`, a 40-byte declaration returned validator status `0xFFFF000F` before the logger.
+* At the same boundary with a four-byte declaration, validation passed and the signed logger faulted at the **artificially protected** `0x800000` before the outer handler's NUL check or log drain.
+
+This is a conditional logged-string overread of the caller's *declared* span. A real adjacent mapping, process-crossing read, reportable confidentiality consequence or hardware fault is unproven. No hardware logging-state toggle or state-changing `0x53` invocation is justified merely to obtain a return code. A live log-gate read should **not be retried** using the faulting GCP ROP chain without diagnosis. Its frame has since been correctly localized to a GCP memcpy **store** at `0x4011D8`, FAR `0x42CFA0`, *not* the `0x4055D8` log-wrapper guard load; the memcpy argument corruption remains unexplained (`fw/ATTEMPT-SYSDRV-53-LIVE-LOG-GATES-READONLY-FAULT.md`). An intact connected sOS model of the GCP caller's mappings remains useful; neither real gates nor real PTEs have been supplied.
diff --git a/fw/CANDIDATE-HDCP52-ALLOC-FAIL-SYSDRV-FATAL.md b/fw/CANDIDATE-HDCP52-ALLOC-FAIL-SYSDRV-FATAL.md
new file mode 100644
index 0000000..13740b6
--- /dev/null
+++ b/fw/CANDIDATE-HDCP52-ALLOC-FAIL-SYSDRV-FATAL.md
@@ -0,0 +1,171 @@
+# Candidate: HDCP 23.0.0.52 ignores a crypto-object allocation failure
+
+**Evidence: signed HDCP/SYS_DRV code, two isolated traces, and one bounded
+connected *two-component bridge* trace. No hardware trigger, real allocation
+exhaustion, full-system sOS execution, or valid host transcript.** The
+bridge forces the **real** SYS_DRV opcode-`0x30` handler's slot search to
+return `-1`, forwards the next request from signed HDCP into the real
+SYS_DRV `0x33` handler, and stops
+before SYS_DRV's fatal routine executes. This is not a demonstrated
+host-only PSP denial of service. The test box has a signed
+`ta_23-0-0-52_c6b25da3.bin`, but this audit does not establish that it is
+automatically loaded or that a host can exhaust its SYS_DRV object pool.
+
+## Concrete chain
+
+The signed HDCP routine starting at `0x4042C4` initializes its local SYS_DRV
+object handle to zero. With a non-null input it calls `gp_object_allocate`
+(`0x401524`, SYS_DRV service-1 opcode `0x30`) at **`0x404300`**, with fixed
+object type `0xA0000004`, capacity `0x100`, and `&handle`. Unlike HDCP's
+other three object-allocate callsites, this routine **does not inspect the
+returned status** before invoking `gp_populate_transient_object` at
+`0x404312` (stub `0x40173A`, SYS_DRV opcode `0x33`) on that handle.
+The stub sends the handle without a local validity check.
+
+SYS_DRV `sub_E1CAD4` (opcode `0x30`) stores a new handle into its response
+**only on success**. Its shared object/handle allocator
+`sub_E0243C`/`sub_E0247C` searches 256 slots and can return an allocation
+failure. The HDCP stub at `0x40154C..0x401550` copies the returned handle
+to `&handle` only if the opcode succeeded, so on an error HDCP still sends
+handle **0** to opcode `0x33`. SYS_DRV opcode-`0x33` handler `sub_E1EA54`
+looks it up through `sub_E0B0F4`; handle 0 fails its `handle-16 <= 255`
+check in `sub_E0B0E8`, reaching `sub_E0F890`, a **noreturn fatal-error loop**.
+The handle-zero branch into that fatal routine is reached both in bounded
+SYS_DRV-only emulation and in the connected HDCP→SYS_DRV emulator bridge
+below; it has **not** been reproduced through sOS or on hardware. One static route to the routine is
+`hdcp2_process_auth_message_v2 (0x40252C)` →
+`hdcp2_build_tx_message (0x40246C)`, message ID 11 →
+`hdcp2_tx_SKE_Send_Eks (0x403E68)` → `0x4042C4`. Completing the HDCP
+authentication state required to take that route on this card is unverified.
+
+**Additional signed caller routes:** The same `0x4042C4` is called at
+`0x402B2E` by received-message handler `0x402938` and at `0x403112` by
+handler `0x402E14`, in addition to callers `0x403AB8` and `0x403E68`.
+The signed `TA_InvokeCommandEntryPoint` at `0x4013B4` checks the parameter
+shape and length (`paramTypes & 0xF == 7`, buffer length `>= 0x2818`), then
+routes host command `0xF` to `0x40252C`. There, a session slot `0..7`
+must have the expected state (`slot[2] == 1`, `slot[0] == 2`); its descriptor
+parser `0x402C9C` dispatches received message IDs **7** and **12** to
+`0x402938` and `0x402E14` respectively, both of which can call
+`0x4042C4` after their own message-specific checks. The transmitted
+message-ID-11 builder remains another route. These are **signed code
+paths**, not a demonstrated valid host transcript, sink-data provenance,
+or an unconstrained way to force failure: the session checks, ID matching,
+message lengths and crypto state still matter. The same transmit switch
+also routes ID **9** to `0x403AB8`, another caller of `0x4042C4`; it is
+likewise conditional, not runtime-proven.
+
+**Signed version cross-check (static only):** The corresponding routine
+in HDCP `.57` (`hdcp_23.0.0.57_94971234.elf`) at `0x403EF4` and `.59`
+(`hdcp_23.0.0.59_520f9e97.elf`) at `0x403F7C` also initializes a local
+handle to zero, requests type `0xA0000004` with capacity `0x100`, and
+calls `gp_populate_transient_object` at `0x403F0C` / `0x403F94` without
+checking the allocation status. Three other allocation sites in each
+of those images have an explicit nonzero-status branch before populate.
+The test box has signed `ta_23-0-0-57_94971234.bin` and
+`ta_23-0-0-59_520f9e97.bin` in addition to `.52`; **which build is active
+on the card remains unknown**. The connected emulator executes **only
+`.52`**, so no runtime conclusion transfers automatically to `.57/.59`.
+
+The other signed HDCP `.52` object-allocate sites at `0x403676`, `0x4041F8`
+and `0x40447C` check their statuses before consuming the handle. In all four
+examined high-level routines (`0x4035FC`, `0x404180`, `0x4042C4`, `0x4043E8`),
+object and operation handles are freed if nonzero before the routine returns.
+Thus these ordinary HDCP calls do **not** leave a *live* second-client SYS_DRV
+crypto object for a later GCP `0x109A` read. A GCP ROP request cannot simply
+interleave with their synchronous crypto operations on the same PSP core.
+This is a negative lifecycle result, not proof that no other client ever keeps
+an object alive.
+
+## Controlled signed-HDCP error-path execution
+
+`psp_emu/harness/probe_hdcp52_alloc_failure.py` loads the **signed `.52` ELF**
+explicitly and runs routine `0x4042C4` with a non-null, in-bounds input. A
+service-1 stub returns nonzero on `0x30` *without* writing an out-handle,
+then logs the next request. The **success control** instead stores handle
+`0x10` and returns zero on `0x30`. A narrow run with `timeout 15 python3
+psp_emu/harness/probe_hdcp52_alloc_failure.py` observed (the second field
+is the request at `+0x38`, object type on `0x30` and handle on `0x33`):
+
+```
+fail_allocate=True: (0x30,0xA0000004) -> (0x33,0x0)
+fail_allocate=False: (0x30,0xA0000004) -> (0x33,0x10) -> (0x31,0x10)
+```
+
+Both runs returned the stubbed `0x80000001` populate error with no Unicorn
+memory fault. This dynamically confirms **the HDCP caller sends zero as the
+`0x33` object handle only when `0x30` fails**, in this controlled model. It does *not*
+execute the real SYS_DRV handler: the stub returns an error for `0x33` and
+HDCP returns normally. The emulator injected failure directly; it has not shown an honest-client
+allocation failure, valid HDCP message-11 session, selected card build, or
+live PSP fault. No card command was sent.
+
+A **second**, independent bounded emulator harness,
+`psp_emu/harness/probe_sysdrv_33_zero_handle.py`, loads the original signed
+SYS_DRV `.54` ELF (byte-identical to `sys_drv2.elf`) and invokes real handler
+`0xE1EA54` with the same zero object handle in request field `+0x38`. It
+stops at the **first instruction** of the signed fatal routine, before its
+standalone-emulator globals or infinite loop are executed:
+
+```
+handler: 0xe1ea54 object_handle: 0x0
+fatal_entry_reached: ['0xe0f890']
+faults: []
+```
+
+Repro: `timeout 15 python3
+psp_emu/harness/probe_sysdrv_33_zero_handle.py`. This confirms the
+**signed SYS_DRV control-flow edge** for a zero handle in isolation. It does
+not show a full-system trace, an actual hardware fault, or the consequence
+of executing the fatal routine on this card.
+
+## Bounded connected two-component bridge
+
+`python3 psp_emu/harness/probe_hdcp52_connected_zero_handle.py` loads the
+**original signed** HDCP `.52` and SYS_DRV `.54` ELFs in separate Unicorn
+components. The Python service-1 bridge forwards HDCP's real `0x30`
+request to **signed SYS_DRV `sub_E1CAD4`**. A narrow hook forces its actual
+slot-search helper `sub_E0243C` to return `-1`, without fabricating an
+out-handle; the signed handler returns `0xFFFF000C`. The bridge returns
+that signed-handler status to HDCP and forwards the **subsequent signed
+HDCP-generated request** into SYS_DRV's real `sub_E1EA54`. One bounded
+run recorded:
+
+```
+bridge requests: [(0x30, 0xa0000004), (0x33, 0x0)]
+real SYS_DRV 0x30 handler: 0xe1cad4 forced no-slot helper: ['0xe0243c'] return: ['0xffff000c']
+real SYS_DRV 0x33 handler: 0xe1ea54 fatal entry (stopped): ['0xe0f890']
+```
+
+Both component fault lists were empty. The hook stops at the **first** fatal
+instruction and halts HDCP at the second RPC; neither process returns
+normally in this test. The allocator *failure* is injected **inside** real
+SYS_DRV slot search, not caused by honest object-pool exhaustion. The rest
+of both opcode handlers executes signed code; this establishes the signed
+caller→signed callee edge in a
+*single connected emulator run*, but it does **not** execute sOS service
+transport, session setup, host/sink authentication state, actual allocator
+failure, or hardware fatal-loop consequences. Do not call it full-system
+reproduction.
+
+## Preconditions and next verification
+
+* Confirm that the `.52` TA is the signed build selected on this card, and
+ whether a real host/sink transcript can reach **any** of the identified
+ received-message-7/12 or transmitted-message-9/11 calls with valid session
+ state and non-null input.
+* Show an **honest-client** allocation failure or another safe way to reach
+ opcode-`0x30` failure, then check that opcode `0x33` receives handle zero.
+ A compromised GCP can likely consume the shared 256-slot allocator, but
+ GCP ROP already affords simpler PSP DoS and exhaustion would be disruptive;
+ do not stage it on hardware just to demonstrate this error path.
+* If pursuing *end-to-end* runtime consequence, use a bounded full-system
+ sOS/HDCP/SYS_DRV emulation with a controlled allocation failure and an
+ instrumented fatal-error hook; the two-component bridge does not cover
+ that gate. Do not report hardware impact from any emulation.
+
+Static analysis used a temporary copy of the signed HDCP `.52` ELF at
+`/tmp/hdcp52_lifetime.elf` to define four missing function boundaries in IDA;
+the original signed ELF/IDB was not saved or patched. Both the isolated and
+connected emulator runs used the original signed ELFs; the connected run
+forced the SYS_DRV slot-search failure in memory only. No card probe was run.
diff --git a/fw/CANDIDATE-HDCP57-ASD1A1-IGNORED-ENTROPY-FAILURE.md b/fw/CANDIDATE-HDCP57-ASD1A1-IGNORED-ENTROPY-FAILURE.md
new file mode 100644
index 0000000..1b2c7ef
--- /dev/null
+++ b/fw/CANDIDATE-HDCP57-ASD1A1-IGNORED-ENTROPY-FAILURE.md
@@ -0,0 +1,69 @@
+# Conditional HDCP `.57` → ASD `.163` `0x1A1` zero-output entropy failure
+
+**Signed cross-client path plus an explicitly stubbed failure-prefix
+control. No natural failed RNG, live card request, accepted HDCP
+session, or protected-link impact.** This is a downstream consumer of
+the separately documented SYS_DRV low-`0x35` error-mask defect
+(`fw/CANDIDATE-GCP-SYSDRV-35-IGNORED-RNG-FAILURE.md`), not an
+independent proof of failed live entropy.
+
+* Signed HDCP `.57` at `0x4030F4` calls its `0x404484` service-2
+ `0x1A1` wrapper with the session channel, a 16-byte local value
+ derived by XOR, and an 8-byte local from session bytes. It checks
+ the RPC status before marking its session byte `+0x24D=1`.
+* Signed ASD `0x1A1 → sub_D0AFB8` bounds channel to 0–31 and
+ validates the two caller ranges for **16** and **8** bytes. For
+ active records with record `+8==1`, ASIC-20/25 setup
+ `sub_D0B458 → sub_D08DAC` places thunk `0xD102E9` at global
+ callback **slot 770** (status check), and `0xD102F3` at **771**.
+ Only if slot 770 returns 10 does it call slot 771 with both validated
+ pointers. The table starts at `0xD33510+0xB84`; slot 770 is
+ offset `0x84` from that start, **not** `0x88`.
+* Slot 771 branches to signed `0xD10BB8`. For a type-6 record,
+ if `asd_op_304` returns **nonzero**, signed instructions
+ `0xD10BCA..D10BD2` zero the 16-byte stack buffer,
+ `0xD10BEA` calls `asd_sysdrv_rpc_35(out,16)`, and
+ `0xD10BEE..D10BF4` **unconditionally copies those 16 bytes to
+ the caller's first output/input**, disregarding the RPC return.
+ The RPC wrapper `0xD01CE2..D01D0A` sends service 1, low opcode
+ `0x35`, with `(out,16)`. Signed SYS_DRV returns success despite a
+ failed initial entropy fetch, leaving its destination untouched.
+ Thus a first-fetch failure can replace the 16-byte HDCP local
+ value with **zeros** on a reported-success path. If
+ `asd_op_304` returns zero, this RNG call is skipped; the output
+ is **not** zeroed by this branch. Later ASD global-table/fabric
+ effects and protected-session acceptance remain untested.
+
+`python3 psp_emu/harness/probe_asd163_1a1_failed_rng_prefix.py`
+passed: a synthetic type-6 record, a modeled **no-output** failed
+RPC (return zero, as already verified in the separate signed SYS_DRV
+model), and an **intercepted** 16-byte memcpy converted an
+owned `K` marker to 16 zeros. The test stops **before** any ASD
+link-table/fabric action and does not prove the signed memcpy
+implementation or a full connected HDCP session. The independent
+SYS_DRV `0x35` harness previously demonstrated the failed first
+fetch and masked status using modeled entropy. Neither test supplies
+real key bytes or a natural hardware failure.
+
+**Type-6 provenance refinement:** signed ASD `0x100 → sub_D0B66C`
+copies descriptor word 0 into record `+8` and marks the record
+active **before** calling ASIC-20/25 slot 769 when that word is 1.
+Slot 769 thunk `0xD10441 → asd_state_not_1_cfg0` assigns record
+`+64=6` and `+76=5` before checking the startup state; it may
+return an error, and `0x100` does not roll the record back.
+An isolated signed-dispatch test reproduced this error-return
+active record (`fw/CANDIDATE-GCP-ASD-100-ERROR-RETURN-ACTIVE-RECORD.md`).
+Thus a planted type-1 descriptor can produce the two **syntactic**
+`0x1A1` branch fields, not proof of a valid live type-6 link.
+Signed DTM `.19` host commands 2/4 can produce ASD `0x100`
+with descriptor word 0 from `req[2]`, including a requested type 1
+(`fw/AUDIT-DTM19-ASD100-TYPE1-PRODUCER.md`). The examined signed
+HDCP `.57` `0x1A1` caller supplies a session channel but does not
+itself establish that descriptor, a valid link, or a paired
+active-build DTM producer.
+
+**Open gates:** actual HDCP `.57`/ASD `.163` pairing and active build,
+natural accepted type-6 record with `+8==1`, slot-770 status 10,
+`asd_op_304` nonzero in that state, realistic entropy failure,
+and downstream cryptographic acceptance/use. No session should be
+created or disturbed on-card merely to force a return status.
diff --git a/fw/CANDIDATE-SOS54-6C-ABSENT-RESOURCE-DEREF.md b/fw/CANDIDATE-SOS54-6C-ABSENT-RESOURCE-DEREF.md
new file mode 100644
index 0000000..a06ec88
--- /dev/null
+++ b/fw/CANDIDATE-SOS54-6C-ABSENT-RESOURCE-DEREF.md
@@ -0,0 +1,47 @@
+# sOS `.54` `SVC 0x6C`: absent resource is dereferenced after ignored error
+
+**Signed kernel defect under an absent-resource precondition; synthetic
+fault only.** The sOS `sub_59E8` dispatcher case 27 routes `SVC 0x6C`
+to `sub_6828(resource_byte)`. Raw `.54` `sub_6828` rejects indices
+`>=32` with 43, but for lower indices calls `sub_6918`, **discards
+its status**, calls `sub_6870(index)`, and returns zero.
+`sub_6870` takes the resource descriptor pointer from indexed table
+`*0x8170 + 12 + 4*index` at `0x688E`, then **unconditionally loads
+from that pointer** at `0x68A2`. The sOS `sub_6844` enumerator checks
+for a nonnull pointer before calling this teardown, but the direct
+`SVC 0x6C` branch does not.
+
+`python3 psp_emu/harness/probe_sos54_6c_missing_resource.py` passed
+against the exact signed sOS `.54` helper. With a **synthetic**
+resource table whose ID-0 pointer is zero, the prior `sub_6918`
+helper was explicitly replaced with its modeled not-found result 43
+and the zero page was artificially made unreadable. Signed
+`sub_6828(0)` continued past that failure and attempted a four-byte
+read from VA zero at PC `0x68A2`; the control `sub_6828(32)` returned
+43 without reaching the stub or the dereference. This test models an
+absent resource and the fault boundary: it neither runs natural
+`sub_6918` nor proves the card's zero-page permission or resource-0
+allocation state. If zero is readable, behavior could differ and
+remain unsafe; a live fault is **not** demonstrated.
+
+A GCP-reachable producer exists in signed SYS_DRV `.54`: free
+`0x1001(msg[14]=0)` scans all **16 empty owner-zero slots** after
+isolated init and requests `SVC 0x6C(0)` for each without an active
+check, even after modeled teardown failure. Free `0x100C` similarly
+releases its selected slot without an active check. Their synthetic
+producer evidence and distinct trust limits are at
+`fw/CANDIDATE-GCP-SYSDRV-1001-SELECTED-IDENTITY-BULK-CLEANUP.md`
+and `fw/CANDIDATE-GCP-SYSDRV-100C-OWNERLESS-SLOT-RELEASE.md`.
+A natural sOS producer, `sub_6844`, has its own nonnull guard.
+A later **read-only signed full-system emulator** boot found resource
+0 **assigned** after ring setup, ASD load and GCP load, which
+contradicts an initially absent-ID-0 premise **in that model**, not
+on silicon. Because isolated SYS_DRV `0x1001(0)` captures sixteen
+repeated ID-0 teardown requests, a successful first release could
+still leave subsequent requests facing an absent resource; this is
+only a conditional cross-model inference, not a connected run
+(`fw/AUDIT-SOS54-RESOURCE0-SIGNED-BOOT-MODEL.md`). No live
+resource-0 vacancy, GCP-triggered sOS fault, second-client victim,
+or recovery outcome was measured. **Do not issue SVC 0x6C
+through either free opcode on the card merely to test this
+condition:** it is a destructive resource release when populated.
diff --git a/fw/CANDIDATE-SYSDRV-1002-CRYPTO-WORKSPACE-LENGTH.md b/fw/CANDIDATE-SYSDRV-1002-CRYPTO-WORKSPACE-LENGTH.md
new file mode 100644
index 0000000..7574f53
--- /dev/null
+++ b/fw/CANDIDATE-SYSDRV-1002-CRYPTO-WORKSPACE-LENGTH.md
@@ -0,0 +1,71 @@
+# Candidate: SYS_DRV `0x1002` reverses a caller-sized buffer into fixed crypto workspace
+
+**Static signed `.54` finding, not a demonstrated post-GCP write or hardware
+fault.** Examined `psp_out/vdiff/sys_drv_0.49.0.54.elf` at its `0xE00100`
+load base. This is a distinct potential length-bounds defect, not the
+previously tested opcode-`0xD` count underflow.
+
+## Signed path
+
+* High dispatcher `sub_E105A8` first calls the opcode ACL
+ `sub_E05A24(*request)` and checks the nonzero pointer/length pairs with
+ `sub_E0AB44`/`sub_E0DEF4`. For opcode `4098` (`0x1002`), it routes
+ subcommand 1 to `sub_E116CC(request+0x38)` after writing
+ `request[16] = 8 * request[3]`. A special pointer-check skip for slot 0
+ occurs **only when `request[15]==1`**, the scalar-input mode; the
+ reverse-copy path below requires mode zero. Do not confuse the skip with
+ an unconditional unvalidated source pointer.
+* `sub_E116CC` at `0xE11704..0xE11730` computes
+ `count = *(u32 *)(arg+8) >> 3`. In mode zero (`*(u32 *)(arg+4)==0`),
+ it reads `count` bytes backward from the caller's source and writes them
+ forward to `*(u32 *)0xE257D8 + 0x200 + i`. The loop is bounded only by
+ `count`; there is **no comparison with the workspace length before the
+ `STRB.W` at `0xE1172A`**. Mode nonzero writes one dword at `+0x200`
+ instead. Crypto setup/validation (`sub_E04AF8`, `sub_E044AC`,
+ `sub_E02158`) occurs **after** this copy, so a downstream error cannot
+ undo its stores.
+* `sub_E04A28` obtains the pointer at `0xE257D8` and a separate byte size
+ via `SVC 0x78`; it requires size `>=0x11FC` but does not save a per-copy
+ bound used by `sub_E116CC`. A prior signed full-system emulator run of
+ `psp_emu/harness/measure_sysdrv_svc78.py` measured base `0xECC000`, size
+ `0x2000`, and the next page unmapped **in that emulator**. At that size,
+ `count > 0x1E00` reaches outside the returned workspace; actual hardware
+ size and adjacent PTEs were not measured. Smaller lengths can overlap
+ other internal scratch partitions without crossing the workspace boundary.
+
+The mode-zero source range still faces the dispatcher's caller-window and
+pointer validation; neither that validation nor `SVC 0x79` on the later
+request fields supplies an observed `count <= workspace_size-0x200` bound.
+Signed ASD `.163` calls `0x1002` during its startup derivation with **fixed
+small lengths**, not this oversized source: the three direct call references
+to its two wrapper variants (`0xD0183C` and `0xD018A0`) are all inside
+`sub_D07E24` (`0xD0801C`, `0xD08040`, `0xD08056`). The three signed
+calls set `a3` to `0x100`, `0x100`, and `0x80` **bits** respectively
+(32, 32, and 16 bytes); the mode-zero call is the last one.
+This does not exclude
+other clients, indirect calls, or additional upstream length policy.
+A targeted Thumb-`MOVW #0x1002`/literal-word scan of eight **selected**
+signed TA ELFs (`ASD .163`, `HDCP .52`, `DTM .19`, `GCP .53`, `OPM .51`,
+`MERIT .46`, `PowerPlay .12`, `RAS .5`) recovered the expected ASD wrapper
+instructions at `0xD01854` and `0xD018B8` and **no hits in the other seven**.
+This is a positive-control-checked direct-constant scan, not an exhaustive
+call-graph result: synthesized opcodes, indirect calls, other builds and
+sOS/SYS_DRV-origin requests are not ruled out.
+
+## Reachability and evidence limits
+
+**GCP ROP cannot simply send this opcode as a free SYS_DRV request.**
+`0x1002` lies in the gated `0x1000..0x1009` range; `sub_E105A8` executes
+`sub_E05A24` before entering the handler. The demonstrated GCP type-5
+caller has not passed this gate. No attacker-controllable, permitted
+second-client path to a sufficiently large mode-zero request has been
+shown; neither a direct hardware probe nor an oversized emulator request
+has been run. Thus this is a **signed-code candidate for a permitted caller**,
+not a proven GCP-reachable overflow, CPU-memory write, or escalation.
+
+Next: identify an allowed caller and its maximum controllable length, then
+run a **bounded isolated emulator** test with a byte-level workspace
+boundary oracle before contemplating any card probe. Do not infer a target
+allocation or writable next page solely from `SVC 0x78`'s base address, and
+do not use the earlier authorization for an opcode-`0xD` NULL-source test
+as authorization for this path.
diff --git a/fw/CANDIDATE-SYSDRV-1041-104F-CAPACITY-STATUS-POSITION.md b/fw/CANDIDATE-SYSDRV-1041-104F-CAPACITY-STATUS-POSITION.md
new file mode 100644
index 0000000..08e19de
--- /dev/null
+++ b/fw/CANDIDATE-SYSDRV-1041-104F-CAPACITY-STATUS-POSITION.md
@@ -0,0 +1,44 @@
+# Free SYS_DRV `.54` `0x1041`/`0x104F`: exact-capacity success depends on index placement
+
+**Signed-code logic defect under synthetic 64-active-entry state; live
+feasibility/security impact unproved.** Both free opcodes enumerate the
+same 97-byte SYS_DRV-private activity table at `0xE60A48+1..+97`.
+`0x1041 → sub_E125C0` pairs each active index with a dword from
+`0xE60BB0`; `0x104F → sub_E12618` uses `0xE60D38`. Their dispatcher
+role rows require an output pair, and both leaves require declared
+length `>=0x204`: four bytes for the count and 64×8 bytes for entries.
+The last possible store ends at byte `+515`, within that declaration.
+No short-output write follows from this loop.
+
+The signed loop adds a matching record, increments the index counter,
+checks whether **all 97 slots have been visited**, and only then checks
+whether the accumulated record count is `>=64`. With exactly 64 active
+entries at the **front** (indices 1..64), the function has not reached
+slot 97 and returns `0x80000309` despite a fully populated 64-entry
+output. With exactly 64 active entries at the **tail** (34..97), the
+last-iteration `97 slots visited` break skips the capacity-error test
+and returns 0. Both report the same count 64. This is an inconsistent
+error contract, not an out-of-bounds copy; at 65 or more active
+entries early truncation/error is expected.
+
+`psp_emu/harness/probe_sysdrv_1041_104f_count_boundary.py` passed on
+signed `.54` dispatcher/leaves with **planted** private flags and
+values. For each opcode its 63-front control returned zero/count 63,
+64-front returned `0x80000309`/count 64, and 64-tail returned
+zero/count 64. A sentinel immediately beyond the declared 516-byte
+output remained unchanged. The emulator's unrelated initialization
+SVCs include default-success handlers.
+
+**Producer feasibility is open, not arithmetically impossible:** signed
+`sub_E16304` is called from `sub_E12D80` (firmware-load flow) and
+`sub_E21040`. Its switch has **60** direct-accept case labels between
+1 and 97 plus ten special case labels, and the shared success path
+marks `0xE60A48[index]=1`. Some special paths can return early or
+depend on hardware/callback results, and simultaneous residency of
+64 IDs was not observed. These case labels are *potential firmware
+resource IDs*, not 70 demonstrated active card clients. No live
+client created 64 active entries, no natural meaning/security use of
+the enumerated dwords was established, and the card was not queried
+or modified. GCP cannot inferably choose another client's live
+activity flags merely because these free getters can enumerate them
+after ROP.
diff --git a/fw/CANDIDATE-SYSDRV-104D-PROPERTY-KEY-PREFIX.md b/fw/CANDIDATE-SYSDRV-104D-PROPERTY-KEY-PREFIX.md
new file mode 100644
index 0000000..5a5d10b
--- /dev/null
+++ b/fw/CANDIDATE-SYSDRV-104D-PROPERTY-KEY-PREFIX.md
@@ -0,0 +1,37 @@
+# Free SYS_DRV `.54` `0x104D`: property lookup accepts a shorter key prefix
+
+**Signed-code lookup semantic defect, no demonstrated security impact.**
+The free dispatcher passes a role-validated input pair `(msg[2],msg[3])`
+and selector `msg[14]` through `sub_E1E7A4 → sub_E0B380 → sub_E09D70`.
+Selector `-3` chooses SYS_DRV's **signed ELF-embedded** property table
+at `0xE00100`, not an ASD/other-client private property table. Selector
+`-1` uses an `SVC 0x81`-derived context subject to a separate zero
+argument gate; it was not emulated. Signed sOS `.54` `sub_59E8`
+case `129-81=48` sends its **current process index** (loaded from
+`*(_DWORD *)*off_5DE0`) to `sub_2A34`, which checks the process slot
+via `sub_1978` and returns that process image's 1-MiB-aligned base.
+Thus the `-1` path's `base+0x100` is not an arbitrary
+GCP-selected other-TA property base on this inspected route. The
+real sOS process descriptor and natural property bytes are unmeasured.
+
+`sub_E09D70` bounds request length at `0x80` and verifies stored
+record lengths and the table's end, but compares exactly **the caller's
+length**, not the stored key length (`record[2]`). It never requires
+`caller_length == record[2]`. Therefore a prefix of a property name
+can select its record. The wrapper returns only the first four bytes
+of a result if its record type is **1**, and returns an error for
+other types. Its local output scratch reserves `0x84` bytes for the
+bounded copy; this is not evidence of a stack overwrite. The embedded
+first `gpd.tee.deviceID` record is type 4, **not** a type-1 value
+returned by this path; no device-ID value is reproduced here.
+
+`psp_emu/harness/probe_sysdrv_104d_property_prefix.py` passed on the
+signed `.54` dispatcher: both the complete embedded type-1 property
+name `gpd.tee.systemTime.protectionLevel` plus NUL and its shorter
+`gpd.tee.systemTime.` prefix returned success and identical **redacted**
+four-byte outputs. An unknown name and an empty prefix failed. This
+uses an ELF-embedded property, synthetic caller descriptor, and
+emulator default-success init SVCs, with no card request. It proves a
+prefix-match behavior, not that a sensitive property is disclosed or a
+signed client uses such a partial key. The role's declared input span
+is respected; output is inline at `msg[15]`.
diff --git a/fw/EVAL-GCP-ASD403-MP1-PMI3-EVENT-QUEUE.md b/fw/EVAL-GCP-ASD403-MP1-PMI3-EVENT-QUEUE.md
new file mode 100644
index 0000000..26b527a
--- /dev/null
+++ b/fw/EVAL-GCP-ASD403-MP1-PMI3-EVENT-QUEUE.md
@@ -0,0 +1,86 @@
+# GCP→ASD `.163` `0x403` on Navi31 MP1 PMI3: an observed event-queue effect
+
+**Result: functional non-scratch fabric effect, but no demonstrated PSP-only or
+protected-memory advantage.** This is stronger than a scratch marker or
+handler status: a matched width-zero control versus width-four write caused
+one additional `+8` advance of a separate decoded host-SMN write pointer.
+The identical diagnostic word is also accepted from host SMN, and the signed
+GCP error path already emits it. SMU consumption, event content readback and
+security consequence are unproved. Do **not** equate this with arbitrary PSP
+RAM access, kernel modification or a protected copy.
+
+## Endpoint and prerequisites
+
+- The Navi31 SMU13 Xtensa firmware includes literal `0x03B30600` alongside
+ MP1 mailbox addresses (`fw/LEAD-GCP-SYSDRV-1079-CHOSEN-FIXED-FABRIC-WORD.md`).
+ Navi22 names `0x03B30600` `MP1_PMI_3`, with status/read/write-pointer
+ neighbors `+4/+8/+12`; only the numeric values are directly tested here.
+- Host `PCIE_INDEX2/DATA2` reads give decoded candidate status `0`, read
+ pointer `0x40000`, and a write pointer in `0x40000..0x40400`. A bogus
+ address reads its byte-swapped mirror `0x00DCEE0F`; live MP0 reads
+ `0x80000000`. No host read of PMI3's *data register* was attempted.
+- `hw/gcp_pmi3_signed_event_control.py` issued one ordinary signed GCP FE0A
+ selector-11 diagnostic. Its host PMI3 write pointer moved **`0x40448` →
+ `0x40470` (+`0x28`)**, between FE09 and GCP unload. This associates the
+ signed event path with the endpoint, but does not isolate individual
+ ASD `0x208` → SYS_DRV `0x1079` inner writes.
+- The earlier quarantined **SID-2** LSDMA ROP is **not** retried here. The
+ matched probe uses the separately hardware-proven SID-1 scratch ROP layout
+ and gates it in the *same GCP load* by two new **non-ROP** FE0A comparisons
+ against the unique signed GCP word at `0x404A78`: counter `0x4604A120`
+ accepts and `0x4604A121` rejects. Unexpected results stop before ROP.
+
+## Matched two-boot experiment
+
+Source `hw/gcp_rop_asd5_pmi3_event.py`; deployed copy SHA-256
+`48f1f61d58a6583cdc8eea85da2a4879e91e78f10c2f2673b5d1d1ea42cade41`.
+Each mode is guarded one-shot and was run in a **separate fresh ATX boot**,
+ASD first, GCP SID 1. Both use ASD `0x100(0)`/`0x100(1)` to set alias index
+**82**, ASD `0x404` read-before/after on *benign* scratch `0x16C` (not
+PMI3's input data register), and ASD `0x403` descriptor target
+`0x03B30600` with dword **`0xE3030100`**. That word is known from signed GCP
+diagnostics; no speculative flash/fuse/MMU-state value was used.
+
+Only the requested `0x403` width changes: **0** (no-write control, expected
+handler 2) versus **4** (write, expected handler 0). The rest of the ROP
+chain, signed FE0A return, GCP FE07 postflight and host controls match.
+Both fresh boots' host preimage was **exactly** `(status=0, rptr=0x40000,
+wptr=0x403B0)` after FE0C/FE08/FE09 and before ROP. All fault frame
+words 82–88 were zero; both FE0A calls returned `0x240`, grace marker
+`0x5A`, ASD SVC7B scratch before/after zero, final GCP FE07 zero,
+and GCP unload zero.
+
+| mode | ASD 0x403 status | host write pointer before → after | delta | log |
+| --- | --- | --- | --- | --- |
+| width 0 | `2` | `0x403B0 → 0x403D8` | `+0x28` | `/root/psp/hw/gcp_rop_asd5_pmi3_control.log` |
+| width 4 | `0` | `0x403B0 → 0x403E0` | **`+0x30`** | `/root/psp/hw/gcp_rop_asd5_pmi3_write.log` |
+
+Thus the **additional `+8`** is associated specifically with the ASD
+`0x403` fabric store, above the shared `+0x28` signed FE0A error/return
+side effect. MP0 and bogus-address controls were stable before/after in both
+boots, and the candidate status/rptr remained `0`/`0x40000`. This is
+independently observed **hardware event-queue progression**, not just the
+ASD handler reporting success. It does not independently show what event
+payload SMU read, whether SMU acted on it, or a privilege boundary over host.
+
+## Host equivalence and limit
+
+A first one-shot host control failed closed **before any data write** when
+wptr reached `0x40400` (candidate queue end); see
+`/root/psp/hw/mp1_pmi3_host_event_control.log`. After a fresh ATX cycle,
+`hw/mp1_pmi3_host_event_control_fresh.py` observed a stable decoded baseline
+`(0, 0x40000, 0x402A0)` twice with live MP0 and bogus mirrors. A single
+ordinary **host** PCIE_INDEX2/DATA2 write of **the same `0xE3030100`** to
+`0x03B30600` moved the pointer **`0x402A0 → 0x402A8` (+`8`)**; see
+`/root/psp/hw/mp1_pmi3_host_event_control_fresh.log`. Host-only postflight
+MP0 C2PMSG115=`0x80000000`, fault words 82–88 all zero, LSDMA ID/version
+`1`/`0x600`. Therefore the chosen GCP→ASD write reached a real non-scratch
+function, **but this tested event is also accessible to privileged host
+MMIO**. The signed GCP error path can emit the same word without `0x403`.
+No unique privilege gain or useful downstream SMU action is established.
+
+**Next discriminatory question:** identify a downstream SMU consumer or a
+register whose PSP-origin event has an effect unavailable through ordinary
+host MMIO; test with a matched no-write control and independent observation.
+The event pointer alone is not proof of protected-memory access. Avoid a
+blind PMI3 payload sweep or claiming completion from queue occupancy.
diff --git a/fw/FINDING-GCP-ASD-404-STACK-GUARD-DISCLOSURE.md b/fw/FINDING-GCP-ASD-404-STACK-GUARD-DISCLOSURE.md
new file mode 100644
index 0000000..62d3efc
--- /dev/null
+++ b/fw/FINDING-GCP-ASD-404-STACK-GUARD-DISCLOSURE.md
@@ -0,0 +1,80 @@
+# GCP ROP -> ASD opcode 0x404 reads ASD's *distinct runtime stack guard*
+
+**Status: hardware-confirmed targeted ASD-private information disclosure on RX 7900 XTX.**
+Prerequisite: code execution/ROP inside the GCP TA (the separately demonstrated
+FE0A selector-4 foothold). This is **not** direct unauthenticated host access,
+ASD code execution, a device-key leak, or a way to write ASD RAM.
+
+## Signed card build and mechanism
+
+The card loads signed `asd_33-0-0-163_18debcc4.bin`. Its dispatcher
+`sub_D013B8` forwards service-2 opcode `0x404` to `sub_D021EC`. The request
+fields are `word[0]=0x404`, `byte[4]=9` (index), `byte[5]=0`, `word[8]=VA`,
+`byte[20]=4`. With index 9, the signed ARM instruction at `0xD022C0`
+dereferences the supplied **virtual address in ASD's context**, places the
+32-bit word in request `word[12]`, and returns 0. Unlike the other branch,
+it does not use the privileged fabric-read `SVC 0x7B`. The six address-exclusion
+entries in the handler can still deny an individual VA; access also depends on
+the live CPU page/domain mapping. A previous SYS_DRV VA attempt faulted on a
+domain violation; this is **not** a cross-domain universal read.
+
+ASD's signed image contains a stack-guard word at **VA `0xD1160C`**, with
+on-disk placeholder `0x33333333`. For example, signed `sub_D0CF68` loads
+`[0xD1160C]` into its stack frame on entry and compares it with the same
+word on return before invoking the stack-failure path. GCP's analogous own
+signed guard is VA `0x40614C`, also `0x33333333` on disk. Both are initialized
+at runtime. The values are not the same across these two TAs.
+
+GCP ROP can already issue `SVC 0xF2` to ASD service 2. Sending the request
+above with `VA=0xD1160C` requires **no forged `0x403` allowlist entry** and
+causes ASD itself to return its private runtime guard to GCP. The second,
+read-only three-RPC chain below used only `0x404`, no `0x100` seeding or
+fabric writes.
+
+## Hardware evidence (distinguish failed attempt from completed reads)
+
+* An initial local runner omitted `MODE=read` and exited on its own assertion
+ **before any ROP request** (`asd_guard_read.log`). A retry without a fresh
+ boot loaded more TA sessions, faulted in GCP at PC `0x4055D8`, left the
+ exfiltration fields at sentinels, and wedged the ring
+ (`asd_guard_read_retry.log`). **This is not an ASD read result.** A power-only
+ ATX cycle restored `LINK UP` (`asd_guard_read_recover.log`).
+* After that fresh boot, signed ASD and GCP loaded with status 0, GCP session
+ ID 1. A `0x404` index-9 read of `0xD1160C` returned **`0x9D3A0BB2`**
+ (status 0). FE0A reached its grace marker, fault registers were zero and
+ final FE07 returned 0 (`asd_guard_read_fresh.log`). This first chain also
+ sent the already-established `0x100(0)/(1)` messages; they were not needed
+ for `0x404`.
+* A second power-only cycle restored `LINK UP`, then a **read-only** GCP ROP
+ sequence sent three `0x404` requests on the newly booted card:
+
+ | VA / purpose | returned value |
+ | --- | --- |
+ | `0x40614C`, caller GCP's own guard | `0x59553154` |
+ | `0xD1160C`, ASD's guard | **`0x5F9D56B8`** |
+ | `0xD013B8`, known signed ASD code control | `0x2800B57C` (exact signed word) |
+
+ ASD status for the third request was 0; grace marker `0x5A`, all fault-frame
+ words zero, final FE07 0 (`asd_guard_compare_boot2.log`). The two guards
+ are **different in the same boot**, and ASD's value also differs between
+ boots and from the signed placeholder. No `0x403` or `SVC 0x7C` request was
+ issued in this second chain.
+
+Logs and executable probe scripts live under `/root/psp/hw/` on the test box:
+`gcp_rop_asd3_guard_read.py`, `gcp_rop_asd3_compare_guards.py`,
+`asd_guard_read_fresh.log`, `asd_guard_read_boot2_cycle.log`, and
+`asd_guard_compare_boot2.log`. The card/ring was responsive after the second
+run; no probe was left running. Earlier general `0x404` read controls are in
+`fw/EVAL-GCP-TO-ASD-0x403-KERNEL-WRITE.md` (Update 8).
+
+## Impact and bounds
+
+This is a **TA-to-driver confidentiality-boundary violation**: a compromised
+GCP TA learns the live guard used by the signed ASD driver, even though its
+own distinct per-TA guard is already readable to it. The disclosure removes
+ASD's stack-canary secrecy as one mitigation against a *separate* ASD memory
+corruption. It does not itself provide such a corruption, ASD code execution,
+SYS_DRV/sOS memory access, OTP contents, device keys, or persistent compromise.
+It is also not proof that every ASD-private VA is readable or that a specific
+ASD key buffer is populated. Further sensitive targets need signed-code
+provenance, controlled lifetime and targeted read-only verification.
diff --git a/fw/FINDING-GCP-SYSDRV-109A-STACK-GUARD-DISCLOSURE.md b/fw/FINDING-GCP-SYSDRV-109A-STACK-GUARD-DISCLOSURE.md
new file mode 100644
index 0000000..dfa65c6
--- /dev/null
+++ b/fw/FINDING-GCP-SYSDRV-109A-STACK-GUARD-DISCLOSURE.md
@@ -0,0 +1,74 @@
+# GCP ROP -> SYS_DRV opcode 0x109A discloses SYS_DRV's distinct runtime stack guard
+
+**Status: hardware-confirmed targeted SYS_DRV-private information disclosure
+on RX 7900 XTX.** Prerequisite: code execution/ROP in the GCP TA via the
+separately demonstrated FE0A foothold. This is an impact of the existing
+unbounded-index defect in `feature_mask_get`; it is not a second independent
+root cause. It is not direct unauthenticated host access, SYS_DRV code
+execution, a device-key read or a CPU-RAM write.
+
+## Signed-code path and chosen address
+
+GCP ROP can issue `SVC 0xF2` to SYS_DRV service 1 with the ACL-free opcode
+`0x109A`. Signed `.54` SYS_DRV handler `sub_E11A78` takes request dword 14 as
+an unchecked 32-bit index and reads the first word at
+`(0xE60308 + 12 * index) mod 2^32`. It returns that word in request dword 15;
+dword 16 is an **AND of the next two source words**, not two raw words. As
+`gcd(12, 2^32) = 4`, each word-aligned *arithmetic address* is selectable,
+but the read still requires a live SYS_DRV-domain mapping and permissions.
+The earlier hardware read of `0xE257D0` in
+`psp_out/FINDING-FEATURE-MASK-GET-UNBOUNDED-INDEX.md` established the route.
+
+The signed SYS_DRV image places a stack-guard word at **VA `0xE01F20`**,
+containing placeholder `0x33333333` on disk. In signed `sub_E041D4`, the
+prologue `LDR R0, =0xE01F20; LDR R4, [R0]` saves it on the stack; the
+return path at `0xE04244..0xE0424A` compares it and calls the stack-failure
+path on mismatch. The adjacent signed ARM instruction at `0xE01F24` is
+`0xE59F0004`, an exact-word read control.
+
+The calculated indices, independently checked modulo 32 bits, are:
+
+| request index | selected SYS_DRV VA | role |
+| ---: | ---: | --- |
+| `0x2AAA2D02` | `0xE01F20` | live SYS_DRV stack guard |
+| `0x1554D7AD` | `0xE01F24` | signed instruction `0xE59F0004` |
+
+## Hardware observations
+
+1. After a fresh **power-only** ATX cycle (`sysdrv_guard_cycle.log`,
+ `LINK UP`), signed ASD and GCP loaded successfully, GCP session ID 1.
+ Three read-only SYS_DRV `0x109A` requests read index 0 (control
+ `0x00000006`/`0x0000003F`), the guard
+ **`0x53399B88`**, then exact signed code `0xE59F0004`.
+ FE0A reached grace `0x5A`, all fault-frame words were zero, the final
+ SYS_DRV handler status and GCP FE07 were both 0 (`sysdrv_guard_read.log`).
+2. Following another power-only cycle (`sysdrv_guard_compare_cycle.log`,
+ `LINK UP`), a read-only three-RPC GCP ROP chain first asked ASD service 2
+ opcode `0x404` index 9 for the *caller's own* GCP guard at `0x40614C`,
+ then asked SYS_DRV service 1 `0x109A` for its guard and for the signed-code
+ control. In that **same boot**, GCP's guard was **`0xB713D5B0`** and
+ SYS_DRV's guard was **`0xF9D3D645`**; the signed code returned
+ `0xE59F0004` exactly. FE0A reached grace `0x5A`, the entire fault frame
+ was zero, the third handler status was 0, and final FE07 was 0
+ (`sysdrv_guard_compare.log`). Neither returned guard equals the signed
+ placeholder. The two SYS_DRV readings differ across fresh boots.
+
+All scripts and full logs are under `/root/psp/hw/` on the test box:
+`gcp_rop_sysdrv_guard_read.py`, `gcp_rop_sysdrv_compare_guard.py`,
+`sysdrv_guard_{cycle,read,compare_cycle,compare}.log`. No TSU, SPI flash,
+MMIO writes, oversized opcode `0xD`, or guessed address sweep was used.
+The test-box ring remained responsive and no probe was left running.
+
+## Impact and limits
+
+The compromised GCP TA can recover a **different process's live stack
+canary**, defeating that mitigation's secrecy for SYS_DRV despite GCP's own
+separate canary being readable to GCP already. This is a direct confidentiality
+breach across the GCP/SYS_DRV boundary, and is distinct from ASD opcode
+`0x404`'s separately confirmed ASD-private canary disclosure
+(`fw/FINDING-GCP-ASD-404-STACK-GUARD-DISCLOSURE.md`). Exploiting the guard
+still needs an *independent* SYS_DRV memory-corruption bug; this read alone
+provides neither SYS_DRV control flow nor access to arbitrary other process
+pages. Other mapped SYS_DRV secrets, including live second-client crypto
+objects, remain to be identified and verified with provenance and lifecycle
+controls.
diff --git a/fw/LEAD-ASD-D397B0-DERIVED-KEY-LIFECYCLE.md b/fw/LEAD-ASD-D397B0-DERIVED-KEY-LIFECYCLE.md
new file mode 100644
index 0000000..2f188a6
--- /dev/null
+++ b/fw/LEAD-ASD-D397B0-DERIVED-KEY-LIFECYCLE.md
@@ -0,0 +1,119 @@
+# Targeted lead: signed ASD `.163` derived buffer at `0xD397B0`
+
+**Signed-code provenance plus targeted, redacted hardware reads of the full
+16-byte runtime buffer. Its writer execution, validity as a key, and
+device-bound origin are NOT demonstrated.** Signed ASD
+`asd_33.0.0.163_18debcc4.elf` uses a 16-byte runtime buffer at
+`0xD397B0..0xD397BF` as `TEE_ATTR_SECRET_VALUE` in the ASD service-2
+`0x201` crypto path. This is separate from the **adjacent** 16-byte key at
+`0xD397C0..0xD397CF` used by `0x202` / GetObfKey, previously described in
+`fw/FINDING-GCP-FE09-CONFIGINIT-HOST-OFFSET-WRITE.md` Addendum 45. The candidate buffer's full 16 bytes were read from a single boot **only
+inside the probe process**; no raw material or hash was printed or retained
+in the evidence log. Its cryptographic validity and provenance remain open.
+The adjacent `0xD397C0` buffer has **not** been read in this pass.
+
+## Writer and lifetime conditions
+
+* **Correction to earlier state-address inference:** During ASD's
+ `0xFFFF0002` start callback, `sub_D02420` calls `sub_D0E75C`. It first
+ zeroes `0x8C` bytes **starting at `0xD397B0`**, including the candidate
+ 16-byte buffer, then calls `sub_D07E24` only when link initialization
+ succeeds and `asd_state_not_1()` is **false**. Raw signed instructions at
+ `0xD0DA18` load the literal `0xD29104` and then `[R0,#4]`: the predicate
+ is **`*(u32 *)0xD29108 == 1`**, not `0xD33054`. The existing IDA comments
+ naming `D33054` on this routine and its producers are misleading.
+ `asd_start_link_task` clears `0xD29108`; `asd_probe_power_state` uses
+ SYS_DRV `0x1021` verb 6 to set it to 1 on success (2 if reply=3, 0 on
+ failure), and `asd_full_reset` can clear it again. A post-load read may
+ differ from the value during the startup call. The true predicate has
+ **not** yet been measured on the live card.
+* `sub_D07E24` chooses two 32-byte in-image data sources by hardware/config
+ state, calls SYS_DRV service-1 opcode `0x1002` twice through `sub_D018A0`,
+ then invokes `sub_D0183C` and XORs the resulting stack words. Its signed
+ instructions at `0xD08070..0xD08080` store four result words to
+ `0xD397B0..0xD397BF`. SYS_DRV opcode `0x1002` dispatches to
+ `sub_E116CC`; it uses `SVC 0x79`, crypto helpers and `SVC 0x68`. The exact
+ hardware key source/cryptographic semantics are **not yet established**:
+ do not assert that this value is device-unique just because it lies outside
+ the ASD ELF.
+* A separate startup callback initializer `sub_D0E10C` receives the
+ configuration at **`0xD397B0+36`**. The signed ASIC-20 `0x204` callback
+ slot is at **`+56`**, not within the first 16 bytes; its assignment
+ does not explain or overwrite the measured candidate buffer. This is
+ scoped to that direct callback assignment, not an exhaustive writer
+ graph (`fw/AUDIT-ASD-163-204-ASIC20-CALLBACK-OUTPUT.md`).
+* ASD opcode `0x201` handler `sub_D0EF60` loads the literal
+ `0xD397B0` as a **16-byte** secret-value attribute passed to SYS_DRV
+ `gp_populate_transient_object` (service 1, opcode `0x33`), then operates on
+ the client's buffer. The signed disassembly at `0xD0EFFA..0xD0F006`
+ confirms local object and operation handles are freed before normal return;
+ the decompiler's early returns alone misleadingly omit this cleanup.
+* The buffer is outside the static ELF image (`0xD00100..0xD29100`). Static
+ references and the startup writer suggest ASD runtime memory, but the
+ live mapping has now been confirmed by targeted reads. On subsequent
+ fresh boots the *post-load* predicate at `0xD29108` was measured as 1;
+ this supports but does **not prove** successful writer execution during
+ startup (nor a device-bound source).
+
+## Controlled read-only test status
+
+The existing GCP ROP → ASD service-2 `0x404` index-9 read can in principle
+read a targeted ASD virtual word; a separate successful test disclosed ASD's
+live stack guard at `0xD1160C`. A *non-fresh-boot* attempt to read an address **then believed** to be the
+state predicate (`0xD33054`) used three read-only RPCs (GCP guard, that
+address, signed ASD code). It loaded GCP as session **3**, returned FE0A `0x262`, and
+left the response fields at `0xBBBBBBBB` with no graceful-return marker.
+Fault frame was all zero and final FE07 returned zero. **No RPC value was
+obtained**: the sentinel is not the state. Contrast earlier clean comparisons
+on fresh boot with session **1** and FE0A `0x240`. Log:
+`/root/psp/hw/asd_derived_state.log`.
+
+A dedicated bridge-ATX cold cycle, with no flash/TSU access, restored `LINK
+UP` (`/root/psp/hw/asd_derived_state_fresh_cycle.log`). On that fresh boot,
+the GCP load was session **1** and three read-only ASD `0x404` RPCs completed
+with FE0A `0x240`, graceful marker `0x5A`, all-zero fault frame and responsive
+FE07. The signed-code control returned `0xD013B8 → 0x2800B57C`; targeted
+reads returned **`*(u32 *)0xD33054 = 0`** (now known to be **unrelated** to
+`asd_state_not_1`) and a **nonzero, non-sentinel** word at ASD-private
+`0xD397B0`. The candidate buffer word was deliberately
+redacted in the log. See `/root/psp/hw/asd_derived_word_fresh.log` and
+`/root/psp/hw/gcp_rop_asd3_read_derived_word.py`.
+
+This proves the address is currently readable and nonzero; it does **not**
+prove that the `sub_D07E24` derivation path ran (the earlier zero was at
+the **wrong address**), that the entire 16-byte value is valid, or that it
+is device-unique/secret.
+## Corrected-predicate and full-buffer checks
+
+Raw signed ARM code for `asd_state_not_1` at `0xD0DA18` loads the literal
+`0xD29104` and dereferences offset `+4`. On a new ATX cold boot, three
+read-only ASD `0x404` index-9 RPCs measured `0xD29108 → 1`, a **redacted,
+nonzero** word at `0xD397B0`, and signed-code control
+`0xD013B8 → 0x2800B57C`. GCP loaded as session 1; FE0A status `0x240`,
+grace `0x5A`, zero fault frame and final FE07 zero. Log:
+`/root/psp/hw/asd_true_predicate_fresh.log`; probe:
+`/root/psp/hw/gcp_rop_asd3_read_true_predicate.py`.
+
+On **another** cold boot, a three-RPC read-only sequence sampled the same
+post-load predicate (`1`) and the **entire known 16-byte buffer on that
+same boot** using two disjoint ASD `0x404` width-8 reads at `0xD397B0` and
+`0xD397B8`. Signed `asd_platform_op_404` performs an 8-byte load at index
+9 for width 8. Both 8-byte halves were nonzero, response headers/widths
+matched, FE0A `0x240`, grace `0x5A`, fault frame all zero and FE07 zero.
+The probe recorded only validity/nonzero booleans and `[redacted 8 bytes]`
+for each half; **no raw bytes or digest** were written to the log. This
+boot did *not* repeat the signed-code read, which matched on the prior
+fresh boot. Logs:
+`/root/psp/hw/asd_derived16_{fresh_cycle,fresh}.log`; probe:
+`/root/psp/hw/gcp_rop_asd3_read_derived16_redacted.py`.
+
+Signed startup `sub_D0E75C` first clears the buffer, and the known
+`sub_D07E24` path writes all four result words only after its conditional
+SYS_DRV operations succeed. The measured state `1` is **post-load**, not a
+trace of that writer; other indirect writers and later state transitions
+are not exhaustively ruled out. Signed opcode `0x201` references these 16
+bytes as a secret-value attribute, but its successful use/validity and the
+value's device-bound provenance were not confirmed at runtime. This is an
+additional **scope/impact observation of the already known ASD `0x404`
+read defect**, not a newly established root cause or a proven device-key
+finding. No wider ASD address sweep or writes are justified.
diff --git a/fw/LEAD-GCP-ASD403-LSDMA6-PIO-COPY.md b/fw/LEAD-GCP-ASD403-LSDMA6-PIO-COPY.md
new file mode 100644
index 0000000..3a816e5
--- /dev/null
+++ b/fw/LEAD-GCP-ASD403-LSDMA6-PIO-COPY.md
@@ -0,0 +1,55 @@
+# New offline DMA target: Navi31 LSDMA 6.0.0 PIO copy
+
+**Status: host BAR5/SMN identity read confirmed; PSP fabric reach and memory-copy effect unmeasured. A later GCP-ROP attempt faulted in GCP memcpy with no valid ASD result. No DMA-register write occurred.** This is distinct from the Navi22-named `MP_MPDMAC` three-register block and from SYS_DRV's free CCP PASSTHRU path.
+
+## ASIC-specific presence versus Linux's register-level producer
+
+`psp_out/SMN-MAP-HEALTHY-CARD.md` records the healthy card's own IP discovery table via `ip_map.py`: **LSDMA 6.0.0**, alongside SDMA0/1 6.0.0, MP0/MP1 13.0.0, etc. The same survey says host SMN reads at discovered LSDMA bases returned mirror/alias/dead classifications, **not usable readback**; that does not prove a PSP-requester fabric window cannot reach the block. Its full original `/tmp/ipmap.txt` dump is not currently present, **but** the preserved survey script `psp_out/smn_ipbases.py` explicitly copies the discovery output's LSDMA base list as **`[0x11400, 0x2456800]`**. This is script provenance, not an independently re-read card table. Its `smn(b)` tests read the **raw base as an SMN address**, not the BAR5 register addresses calculated below, so do not call those tests a negative BAR5 register probe. `psp_out/FIRMWARE-COVERAGE-MATRIX.md`'s wording that LSDMA is "not on this ASIC" concerns the DCN4 DMCUB/LSDMA firmware findings and conflicts if read as a claim that the **hardware LSDMA IP** is absent. Do not equate those.
+
+Upstream Linux's `drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c` maps an IP-discovered LSDMA 6.0.0–6.0.3 block to `lsdma_v6_0_funcs`; `lsdma_v6_0.c` implements a real **programmed-I/O memory copy**. Sources (retrieved without card activity):
+
+- <https://github.com/torvalds/linux/blob/master/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c>
+- <https://github.com/torvalds/linux/blob/master/drivers/gpu/drm/amd/amdgpu/lsdma_v6_0.c>
+- <https://github.com/torvalds/linux/blob/master/drivers/gpu/drm/amd/include/asic_reg/lsdma/lsdma_6_0_0_offset.h>
+
+The Linux copy routine writes six PIO registers in sequence: 64-bit source at `regLSDMA_PIO_SRC_ADDR_LO/HI` (register offsets `0x69/0x6a`), 64-bit destination at `regLSDMA_PIO_DST_ADDR_LO/HI` (`0x6b/0x6c`), control `0` at `regLSDMA_PIO_CONTROL` (`0x6f`), then reads/modifies/writes `regLSDMA_PIO_COMMAND` (`0x6d`) to set a byte count, location/inc/overlap/constant-fill fields and start the operation; it waits on `regLSDMA_PIO_STATUS` (`0x32`). These are **block-relative register indices**, *not* verified PSP fabric addresses. The driver headers assign each PIO register `BASE_IDX=0`, selecting the copied discovery list's first base, `0x11400`. Register offsets and discovered bases are **dword indices** for BAR5: `(0x11400 + 0x69) * 4 = 0x451A4` (source low), then `0x451A8` (source high), `0x451AC/0x451B0` (destination), `0x451B4` (command), `0x451BC` (control), and `0x450C8` (status). A local cross-check: discovery MP0 base `0x16000` plus upstream `regMP0_SMN_C2PMSG_64=0x80` gives BAR5 offset `0x58200` for message 64. Adding the 51-word mailbox index delta for message 115 yields **`0x582CC`**, matching the project's documented live C2PMSG_115 BAR5 address (`psp_out/SMN-MAP-HEALTHY-CARD.md`). **BAR5 offsets still are not PSP-fabric addresses or host-SMN addresses.** The Linux implementation's `SRC_LOCATION=0` and `DST_LOCATION=0` have no established translation to protected PSP CPU RAM. A separate fill path exists; it is also stateful. **Additional upstream header scoping:** `lsdma_6_0_0_sh_mask.h` defines `LSDMA_PIO_CONTROL` as `VMID` bits **[3:0]**, `GPA` bit 4, `SYS` bit 5, `GCC` bit 6 and `SNOOP` bit 7; Linux writes that entire control register as **zero** before its PIO copy. Its status exposes `ERROR_VM_HOLE` bit 8 and read/write `NACK_PRT` bits 18/17. This supports a GPUVM/protection-domain *question*, not an inferred PSP-memory privilege: the register header does not define which VMIDs or memory types can access PSP-secure data or whether Navi31 accepts nonzero controls from ASD's PSP fabric requester. The host driver programs the same PIO register by ordinary MMIO, so a nonzero control would not itself be authority GCP gains uniquely via the fabric write; a demonstrated host-versus-PSP difference or otherwise inaccessible victim domain remains necessary. The same generated header contains `LSDMA_UTCL1_PAGE__TMZ_ENABLE` (bit 5; UTCL1_PAGE block-relative index `0x48`), **not a PIO_CONTROL bit**. No Linux producer here writes that register, and a named page-status/attribute bit is not evidence of a writable switch that disables trusted-memory protection. Do not target it. **Incremental-authority check:** this Linux routine programs LSDMA through ordinary host MMIO writes. A copy the host can already arrange in host-accessible GPU memory would not become a new PSP-memory primitive just because GCP made ASD program the same engine. The DMA transaction's requester is the *engine*, not automatically the CPU that wrote its MMIO registers. A fabric-specific benefit would require evidence of a PSP-only register view, different write permissions or a protected memory address domain accessible to LSDMA but not to ordinary host programming; none has been shown.
+
+### Narrow host-only hardware check
+
+Using `ssh root@192.168.1.200`, `/root/psp/env.sh` and `$PSP_PY`, a read-only tinygrad `adev.rreg(offset/4)` check returned twice-stable independent BAR5 values:
+
+| host BAR5 offset | documented/control role | two reads |
+| --- | --- | --- |
+| `0x16C` | previously verified shared scratch control | `0`, `0` |
+| `0x582CC` | live MP0 C2PMSG_115 control | `0x80000000`, `0x80000000` |
+| `0x450D0` | Linux LSDMA6 `regLSDMA_ID` (`0x11400 + 0x34`) | **`1`, `1`** |
+| `0x450D4` | Linux LSDMA6 `regLSDMA_VERSION` (`0x11400 + 0x35`) | **`0x600`, `0x600`** |
+
+A second **host-only, read-only SMN-window check** used the standard host `PCIE_INDEX2` selector (BAR5 dword 14) followed by `PCIE_DATA2` (dword 15); it did not touch LSDMA's data/control/command registers. `SMN 0x450D0` returned **`1`** twice, with an intervening bogus address `0x0FEEDC00` correctly returning its byte-swapped mirror `0x00DCEE0F`. `SMN 0x450D4` returned **`0x600`**. Same-run MP0 mailbox control `SMN 0x03810ACC` returned `0x80000000` before/after, and same-run BAR5 LSDMA ID/version independently matched `1`/`0x600`. So these particular LSDMA ID registers decode at **both host BAR5 offsets and numerically equal host-SMN addresses**; the old survey's raw discovery-base mirror is not a denial of this indexed path. This is still **not a PSP-requester read**, much less proof that an ASD `SVC 0x7C` store would be accepted by LSDMA's control registers.
+
+Earlier `fw/EVAL-GCP-TO-ASD-0x403-KERNEL-WRITE.md` independently confirmed PSP-fabric-to-host sharing at **low scratch offsets** `0x16C` and `0x3824`, but a requested fabric write at the host MP0 mailbox candidate `0x03810A60` produced no host-visible effect. Thus the low-offset identity examples do **not** establish a general BAR5→fabric transform for LSDMA. No LSDMA status, source, destination, control or command was read or written. No TA was loaded, so there is no FE07/unload/fault-frame result from this host-only check; no register needed restoration. Before the check the remote process list showed no active `psp`/`tinygrad`/`amdgpu`/`atx` work. Do not turn `0x450D0` into an assumed safe PSP `SVC 0x7B/0x7C` address merely because the host BAR5 register reads correctly: a prior PSP read of an unrelated unverified address `0x215C0` stalled the ring.
+
+A further **literal-only** scan of the 144 local `psp_out/elf/*.elf` and `psp_out/versions_win/elf_all/*.elf` files found **zero little-endian dword occurrences** of discovery base `0x11400` or `0x2456800`, dword-index source `0x11469`, or the computed **host BAR5** ID/source/control/command/status offsets `0x450D0`, `0x451A4`, `0x451BC`, `0x451B4`, `0x450C8`. This is *not* a firmware reachability census: signed code could compute addresses, use a discovery table, store halfwords, use a different PSP-fabric address, or be outside these 144 images. It provides **no signed PSP-side LSDMA producer or BAR5→fabric transform** and does not justify substituting a numeric host offset into `SVC 0x7C`.
+
+The upstream `mp_13_0_0_offset.h` register header contains **no `DMAC` entries**, nor do the five other fetched `mp_13_0_*_offset.h` variants. These public driver headers are not a complete PSP-private register map. They neither refute the Navi22 `MP_MPDMAC` name nor locate a Navi31 private MPDMAC controller; the **independently present LSDMA6 PIO path** is a better-specified new copy-engine candidate.
+
+### Failed PSP-side read attempt — no LSDMA requester result
+
+A single subsequent attempt to read the known ID address `0x450D0` through GCP→ASD signed `0x404` **produced no valid service result**. Its local script was derived from the earlier scratch-reader and made its three intended ASD calls read-only `0x404` (two signed-code controls and one physical-read request); nevertheless it reused the FE0A chosen-write/pivot setup with hardcoded `PARAMS=0x04024000`. The initial signed ASD and GCP loads succeeded (`0`, `0`, GCP SID 2), but FE0A timed out. Output status stayed `0xBBBBBBBB`, grace stayed `0xBB`, and the frame was **identical** to the independently diagnosed failed SYS_DRV log-gate ROP attempt (`fw/ATTEMPT-SYSDRV-53-LIVE-LOG-GATES-READONLY-FAULT.md`):
+
+```
+004055d8 25031016 004011d8 00000867 0042cfa0 00000000 8da7463d
+```
+
+Here word2 `0x4011D8` is GCP signed memcpy's `STMMI R0!,{R3,R4}`, DFSR `0x867` is a write translation fault, and FAR `0x42CFA0` fits the **pre-pivot FE0A chosen-write** using a shifted live params VA, not the planned read. The offline signed-instruction/literal verifier `python3 fw/verify_gcp_loggates_memcpy_path.py --probe /tmp/gcp_rop_asd3_lsdma_id_read.py` passed: intact planned copies cannot execute that conditional eight-byte-tail store, while the first FE0A chosen-write nominal destination `0x41BFA0` is exactly `0x11000` below FAR. It does not prove the actual faulting caller or live params VA; **no ASD result, PSP-fabric read, or LSDMA permission result was observed**. Subsequent FE07 and GCP unload timed out. Original log: `/root/psp/hw/gcp_rop_asd3_lsdma_id_read.log`; remote script was subsequently replaced with a **fail-fast quarantined** copy (local `/tmp/gcp_rop_asd3_lsdma_id_read.py`, SHA-256 `9333b8dd6ebc18e208513ac0bc99accc19016e883bb812e9ab7a378d7598ff81`). The original *executed* script hash, prior to quarantine, was `69df05204247d6a964404813052e99e421958dd9c3dbe22b7b673322da0c337b`.
+
+**This repeated an unresolved GCP FE0A memcpy-mapping failure despite the earlier caution not to retry its equivalent chain. Do not replay the quarantined GCP hardware ROP read/write.** Later *non-ROP* signed-code comparators measured two exact GCP code words (one unique in the ELF) in fresh ASD-first **SID-1** sessions and favor the old params base **in that configuration** (`fw/LEAD-GCP-PARAMS-VA-NONROP-DISCRIMINATOR.md`). They did not reproduce the failed **SID-2** mapping or independently validate an OOB chosen-write destination. No LSDMA PSP-side read result was obtained; this failed probe was not a LSDMA denial or a DMA command. The card was cold-cycled with `/root/psp/hw/psp_atx_only_cycle.py` (LTSSM `0x58` → `0x00` after drain → `0x78`), then signed ASD load, GCP load, FE07 and GCP unload all returned ring/TA status 0; post-recovery fault words 82–88 were all zero, MP0 C2PMSG115 was `0x80000000`, and host BAR5 LSDMA ID/version remained `1`/`0x600`. The failed session itself could not be unloaded before ATX.
+
+## What would be necessary to turn the GCP→ASD `0x403` write into impact
+
+1. Obtain an independently re-readable copy of the **LSDMA instance-0 IP-discovery base** if necessary; its prior value `0x11400` is preserved in `psp_out/smn_ipbases.py` and the resulting **host BAR5** PIO register offsets are derived above. Determine separately how (or whether) those register accesses map into **PSP fabric** space. Neither BAR5 `0x451A4` nor the raw discovery index `0x11469` may be used as an assumed `SVC 0x7C` fabric address. The prior host-SMN mirror test does not answer PSP-side decode.
+2. Establish PSP-requester permission and how LSDMA's `SRC_LOCATION`/`DST_LOCATION` and 64-bit addresses are interpreted. GPU VRAM/MC addresses, host physical addresses, PSP fabric addresses, and PSP CPU-MMU VAs must stay separate. Nothing so far shows a copy **from or to protected PSP memory** or another TA's mapping.
+3. Account for interaction with Linux's active LSDMA use, reset/ownership, command status and timeouts. The ASD `0x403` path issues one chosen width-4 fabric write per request and may change a shared PSP window; configuring a copy would require multiple stateful writes plus a final command. Do not perform these on an active card for a status code.
+4. Only then define a known benign source and destination, independent destination readback and exact restore for a specifically authorized hardware test. A copied marker inside GPU-owned scratch would still prove only that bounded effect, not arbitrary PSP-memory access.
+
+**Bottom line:** a *real ASIC-reported, host-BAR5- and host-SMN-decoded block with a source/destination/length/command producer* has replaced the earlier MPDMAC-name-only speculation. The bridge from GCP's proven fabric write to the block's decoded register file, and the memory boundary worth abusing, remain unproved. No completion claim.
diff --git a/fw/LEAD-GCP-ASD403-MP1-UNSECURE-BAR.md b/fw/LEAD-GCP-ASD403-MP1-UNSECURE-BAR.md
new file mode 100644
index 0000000..a2328e8
--- /dev/null
+++ b/fw/LEAD-GCP-ASD403-MP1-UNSECURE-BAR.md
@@ -0,0 +1,7 @@
+# Offline-only lead: MP1 SRAM unsecure-range control beyond sOS's exclusions
+
+**Hypothesis, not a Navi31 register identification or demonstrated effect. Do not write this security-state register.** The only locally named register map, `~/nv22_a0_memmap.txt` (Navi22, *not* this RX 7900 XTX), lists `MP_MP1MMU.MP1_MMU_SRAM_UNSECURE_BAR` at numeric SMN `0x03A10060`, between MP1 access-error logs at `0x03A10050..5C` and scratch words at `0x03A10064..80`. The analogous MP0 control `MP0_MMU_SRAM_UNSECURE_BAR` is `0x03710018`, inside sOS `.54`'s excluded `[0x03700000,0x03800000)` range. The MP1 numeric candidate instead lies **above** the excluded MP1 private-memory interval `[0x03900000,0x03A00000)` and below CCP `[0x0CB00000,0x0CB10000)`: signed sOS `.54` `sub_6D20(addr,8)`'s listed software checks would *permit* that numeric address for ASD type 4. This says nothing about hardware decode, requester authorization, a register's reset state, or whether changing it would expose memory.
+
+Upstream Linux's `mp_13_0_0_offset.h` and `_sh_mask.h` contain **no `UNSECURE`, `MMU_SRAM`, `JTAG` or `MPDMAC` names**. They do not supply a Navi31 location or the unsecure BAR's bit meanings. Earlier host-only SMN survey found mirror-like results in the MP1CRU `0x03A00000` sample, **not a measured read at this MP1MMU word**; even a host mirror would not settle ASD's requester access. Unlike the two restored BIOS/BIF scratch endpoints, there is currently **no independent readback or restoration oracle** for `0x03A10060`, and a security-state write could be irreversible or disrupt MP1. No PSP request or card read/write was made here.
+
+A useful pivot would require **Navi31-specific** evidence for the register's location and reset/access semantics, a safe way to determine and restore its preimage, and independent observation that a harmless change alters another actor's MP1-SRAM access. Neither a sOS gate pass nor a Navi22 name is that evidence. Until these requirements are met, this is an offline prioritization lead, **not a permissible live `0x403` test** or a completion claim.
diff --git a/fw/LEAD-GCP-PARAMS-VA-NONROP-DISCRIMINATOR.md b/fw/LEAD-GCP-PARAMS-VA-NONROP-DISCRIMINATOR.md
new file mode 100644
index 0000000..3a46b29
--- /dev/null
+++ b/fw/LEAD-GCP-PARAMS-VA-NONROP-DISCRIMINATOR.md
@@ -0,0 +1,24 @@
+# Non-ROP FE0A codeword discriminator for GCP command-buffer VA hypotheses
+
+**Status: signed-code derivation and bounded card codeword observations; no independent live params-VA/destination mapping or fabric-pivot effect.** After two GCP FE0A chosen-write chains faulted at PC `0x4011D8` / FAR `0x42CFA0`, the earlier presumed params VA `0x04024000` cannot be carried into another ROP request. `fw/ATTEMPT-SYSDRV-53-LIVE-LOG-GATES-READONLY-FAULT.md` and `fw/LEAD-GCP-ASD403-LSDMA6-PIO-COPY.md` document the failures, quarantine and ATX recovery. A nominal chosen-write destination `0x41BFA0` differs from FAR by `0x11000`, making `0x04035000` a **fault-compatible inference**, not a measured live VA.
+
+The signed GCP `.77` FE0A **pre-selector** code (`0x40483A..0x404890`) reads a dword at `params + 0x14 + *(params+0x824)` and compares it against the session counter. Using only initialized bytes from its signed ELF LOAD (`0x400100..0x416100`):
+
+| if params VA | fixed displacement `0xFC3E0A60` reads | signed value | comparison to `0x40000000` |
+| --- | --- | --- | --- |
+| old `0x04024000` | code prologue at `0x404A74` | `0x460DB5B0` (`PUSH {R4,R5,R7,LR}`) | greater: ACCEPT, under the signed gates |
+| shifted `0x04035000` | initialized zero at `0x415A74` | `0` | lower: REJECT, under the signed gates |
+
+`python3 fw/verify_gcp_params_nonrop_discriminator.py` passes the signed-instruction, ELF LOAD, target and inequality checks. **Necessary correction:** signed FE0A `0x4048F4..0x4048FC` rejects this negative displacement **before** comparison if ordinary declared input length is `0x1000`. A non-ROP comparator must declare `0xFFFFFFFF` and choose diagnostic selector **11**, which returns without entering the accepted-branch huge memcpy. The declared length is *not* actual allocated memory. This avoids repeating the quarantined FE0A selector-4 ROP path, but a third unmapped base can still fault. FE09's seed `0x40000001` makes the modeled counter `0x40000000`.
+
+## Bounded card discriminator (new)
+
+Under the operator's explicitly relaxed tolerance for resettable volatile effects, `hw/gcp_fe0a_params_va_nonrop.py` was run **once** from a fresh boot with ASD `.163` loaded first and GCP `.77` session id 1; remote log `/root/psp/hw/gcp_fe0a_params_va_nonrop.log`. CMAC self-test, signed ASD/GCP loads, FE07, FE08 and FE09 all passed. An in-buffer selector-11 control with the same huge declared length returned `0x241`. The **single** out-of-buffer comparator at displacement `0xFC3E0A60`, counter `0x40000000`, returned `0x241`, not `0x100`; GCP unload returned zero. Host-only postflight MP0 C2PMSG115 was `0x80000000`, fault words 82–88 zero and LSDMA ID/version remained `1`/`0x600`. **No ROP chain was retried or any LSDMA/MP1 security control written.**
+
+A second fresh boot (ATX LTSSM `0x78→0x58→0x00→0x78`) ran `hw/gcp_fe0a_params_va_exact.py` once; remote log `/root/psp/hw/gcp_fe0a_params_va_exact.log`. Its in-buffer control returned `0x241`, and two independent auth sessions probing the *same OOB dword* returned `0x241` at counter `0x460DB5AF` then **`0x100` at counter `0x460DB5B0`**. Thus the signed FE0A handler read a value exactly **`0x460DB5B0`** in that boot, matching the signed ELF word at `0x404A74`. FE07/08/09 and GCP unload all returned zero. That dword appears at **three** signed-ELF positions, so equality alone does not prove a unique live params VA.
+
+A third fresh boot used `hw/gcp_fe0a_params_va_adjacent.py` once (`/root/psp/hw/gcp_fe0a_params_va_adjacent.log`): in-buffer control `0x241`; OOB displacement `0xFC3E0A64` returned `0x241` at counter `0x4604A120` and **`0x100` at `0x4604A121`**; signed FE07/08/09 and GCP unload zero. That pins the read dword exactly to **`0x4604A121`**, which occurs **once** in the signed `.77` ELF, at VA `0x404A78`, and is zero at `0x415A78`. For these fresh-boot GCP SID-1 test configurations, the observations strongly support the **old params-VA hypothesis `0x04024000`**, rather than the fault-compatible shifted hypothesis `0x04035000`. These are code-word reads, not an independent CPU-MMU page-table dump or a measurement of the chosen-write *destination* mapping.
+
+An attempted SID-2 check without ATX did **not** reach its probe: session IDs were **reused**. `hw/gcp_fe0a_params_va_sid2.py` loaded GCP as **SID 1** after the previous SID-1 unload, then fail-fast stopped *before FE07/08/09 or FE0A*. Remote log `/root/psp/hw/gcp_fe0a_params_va_sid2.log`; this script's one-shot guard prevents rerun. A separate GCP SID-1 unload returned zero, host MP0 C2PMSG115 was `0x80000000`, and fault words 82–88 were zero. **No SID-2 params VA was measured.** The old SID-2 GCP memcpy faults and their inferred `+0x11000` shift therefore remain unresolved; the successful fresh SID-1 source reads do not authorize replaying the quarantined ROP chain. A live ROP would also need independent destination-offset validation in its own session and meaningful target-effect controls.
+
+**Crucial safety correction:** The FE0A **REJECT** branch at `0x40490A..0x404924` calls signed GCP error wrapper `sub_4062B4` three times. That wrapper emits ASD service-2 `0x208`, which forwards to SYS_DRV `0x1079`; with its signed private gate and nonreserved top byte, SYS_DRV can request a width-4 fabric store at fixed `0x03B30600` (`fw/AUDIT-ASD-163-208-SYSDRV-1079-FORWARD.md`). The exact three **requested** words derived from the signed GCP/ASD packing are `0xE303F000`, `0xE3030000` and `0xE3030100` (verified by the offline script). None has a filtered `0xEE/0xEF` top byte. **A Navi22 map, not Navi31 hardware evidence**, names numeric `0x03B30600` `MP_MP1MMU.MP1_PMI_3` with adjacent `_STATUS`, `_READ_POINTER`, `_WRITE_POINTER` at `+4/+8/+12`; that suggests a mailbox/log data register rather than a generic memory-copy controller, but its Navi31 decode and target semantics remain unknown. The target's card-side effect and restoration are unknown. **Thus the proposed comparator is not a read-only or automatically benign hardware discriminator.** Previous historical binary searches do not establish that these error notifications had no effect. The two bounded non-ROP hardware runs above were undertaken under the updated risk tolerance; they measured comparator results, **not** the PMI3 target effect or an exact live destination mapping. Further card work must keep those facts separate. Do not re-run the quarantined ROP chain on the strength of these source reads alone.
diff --git a/fw/LEAD-GCP-SYSDRV-1010-1015-NESTED-SPANS.md b/fw/LEAD-GCP-SYSDRV-1010-1015-NESTED-SPANS.md
new file mode 100644
index 0000000..6a5666f
--- /dev/null
+++ b/fw/LEAD-GCP-SYSDRV-1010-1015-NESTED-SPANS.md
@@ -0,0 +1,37 @@
+# SYS_DRV `.54` `0x1010..0x1015`: conditional nested buffer-width gaps
+
+**Signed-code conditional leads, not reached overreads/writes.** These
+six free opcodes reach `sub_E11DC8` and crypto helpers, **not** stubs.
+Their dispatcher roles validate caller pointer pairs to their
+*declared* lengths; no examined first-level check requires those
+input declarations to cover each helper's nested fields. The
+signed helpers first clear a private shared crypto workspace through
+`*0xE257D8` and then access nested dwords. For example,
+`0x1010/0x1011 → sub_E09430` raw `0xE09458` reads
+`msg[6]+0x44` (offset **68**) from a role-1 input pair even
+if its declared `msg[7]` is four bytes. Other helpers
+`sub_E094C8/sub_E09558/sub_E09624/sub_E096E8` also read caller
+nested `+68` fields, and `sub_E096E8` uses a `+140` field on one
+input. The `0x1015` dispatcher explicitly bounds its separate
+`msg[14]` pointer to 72 bytes; that is **not** a general check of
+all its other input pairs.
+
+After signed crypto/helper success, several leaves also store
+metadata at caller output **`+68`**, and some at **`+140`**,
+without an obvious check that the corresponding role-2 declared
+output length covers those offsets. The leaves' lower-level
+`sub_E09274/sub_E09300/sub_E0933E/sub_E09362/sub_E093D8`,
+`sub_E04000` and `sub_E1C85C` gates, success reachability and
+exact field provenance are **not** cleared by this scoped audit.
+Do not claim that a four-byte output actually receives a store on
+the card or that any caller can forge the crypto state.
+
+`psp_emu/harness/probe_sysdrv_1010_nested_gate.py` passed with four
+synthetic declared bytes for all input/output pairs. Signed dispatch
+entered `sub_E09430`, but default emulator init left the shared
+crypto base zero: its private clear faulted at `0xE019F8`, FAR
+`0x113C`, **before** the caller `+68` read. This is a modeled
+initialization blocker, not evidence of a live GPU fault or of the
+conditional read. Unrelated init SVCs may default to success. A
+natural active crypto workspace, lower-level validations, real PTEs
+and cross-client impact remain open; no card request was issued.
diff --git a/fw/LEAD-GCP-SYSDRV-1018-MODE-GATED-STORAGE-READ.md b/fw/LEAD-GCP-SYSDRV-1018-MODE-GATED-STORAGE-READ.md
new file mode 100644
index 0000000..2f7b893
--- /dev/null
+++ b/fw/LEAD-GCP-SYSDRV-1018-MODE-GATED-STORAGE-READ.md
@@ -0,0 +1,65 @@
+# Free SYS_DRV `.54` `0x1018`: selector/page/offset storage read, not a direct MMIO write
+
+**Signed static tracing only. No card request, flash read, backend success,
+or cross-partition effect.** SYS_DRV `sub_E105A8` case `0x1018`
+passes caller inline selector `msg[14]`, index `msg[15]`, offset
+`msg[16]`, output length `msg[3]`, and output pointer `msg[2]` to
+`sub_E1AC2C`. It is outside the range-ACL masks but remains subject
+to the normal sOS message/window checks.
+
+If private mode byte `0xE26259` is zero, `sub_E1AC2C` uses
+`sub_E19E80` and a fixed command-`132` transport. When nonzero, it
+uses `sub_E0AE90` to calculate a storage address, then
+`sub_E15234(2, address, output_ptr, output_length)`:
+
+- index must be `<32`; the addition `offset+(index<<12)` and its
+ later addition to a **class-table-derived base** are checked for
+ 32-bit wrap;
+- selector is accepted only as class `1`, or `0`/`5` when
+ corresponding signed-private bytes match. The class-to-base table
+ lives under private root `0xE7904C` and is not a caller-provided
+ pointer;
+- `sub_E15234` limits a request to nonzero length `<=0x1000`
+ and an address at or below private global upper word `0xE7905C`,
+ with `address+length <= upper`. It does **not** visibly impose a
+ separate `<4096` bound on the inline offset or an individual
+ class/partition end. Whether crossing one is unauthorized requires
+ actual table/region policy and accepted backend data, not just
+ this arithmetic;
+- it chunks to at most 64 output bytes and calls
+ `sub_E1AAB4`. Raw code `0xE1AAD2..0xE1AAEC` passes the byte-swapped
+ address as a *command-header word*, a **caller output pointer** in
+ `R3`, and a chunk length on stack into `sub_E184C0`. The latter
+ issues `sub_E1A268` and, only on success, copies returned bytes into
+ that caller output. It is **not** a CPU store at the selected
+ storage address or an observed fabric write.
+
+**Descriptor provenance:** both the class table in `sub_E0AE90`
+and the global upper word used by `sub_E15234` are fields under the
+same private root `0xE7904C`. Signed `sub_E069B0` first clears that
+root, obtains a fixed 4096-byte descriptor through `sub_E062F8`,
+then parses/places size and region fields; `sub_E207A4` elsewhere
+checks addresses against parsed region rows, but `sub_E15234`
+does not call that row checker. We have not recovered natural
+signed descriptor contents or proved that crossing a class boundary
+would yield an accepted read.
+
+`python3 psp_emu/harness/probe_sysdrv_1018_synthetic_range.py`
+passed a **signed dispatcher / planted-table** control after isolated
+init. With mode 1, a synthetic class-34 row at base `0x2000`, and
+upper word `0xE7905C=0x10000`, both `(page=0,offset=0x1000)` and
+`(page=1,offset=0)` reached a **captured, success-stubbed** backend
+read for the same logical address `0x3000`. An address-at-upper
+four-byte negative stopped before the backend. This demonstrates
+that the signed path does not enforce an offset `<0x1000`; it does
+**not** show a natural row boundary, a device response, or a real
+cross-partition read. The isolated init emitted default-success
+warnings for unrelated SVCs (including `0x66`); their generic
+success does not establish real device capabilities.
+
+The mode selector, live class bases/global upper word, backend
+acceptance, actual storage contents, and whether the GCP caller is
+allowed to see another class remain unverified. There was no
+`0x1018` card test. In particular, the local flash dumps do not
+cover the signed `0x7FB000` area, and this trace cannot stand in for
+an independently verified natural `$RA2` row or authorization rule.
diff --git a/fw/LEAD-GCP-SYSDRV-101A-BLOCK-COUNT-TRUNCATION.md b/fw/LEAD-GCP-SYSDRV-101A-BLOCK-COUNT-TRUNCATION.md
new file mode 100644
index 0000000..1661f1f
--- /dev/null
+++ b/fw/LEAD-GCP-SYSDRV-101A-BLOCK-COUNT-TRUNCATION.md
@@ -0,0 +1,42 @@
+# Free SYS_DRV `.54` `0x101A`: high block-count bits discarded before range checks
+
+**Signed 32-bit count-truncation lead; synthetic lookup and sink only,
+no flash operation or security impact.** Signed `sub_E105A8` case
+4122 forwards caller inline `msg[16]` through `sub_E1A30C`. On its
+post-init-active byte gate `0xE26259 != 0`, the leaf first calls
+`sub_E0AE90` to resolve a class/tag-derived image address, then at
+raw `0xE1A326` computes **`msg[16] << 12` in a 32-bit register**
+before calling `sub_E15074(type=2, resolved_addr, length, flag)`.
+It never checks that the original block count fits 20 bits. Thus
+counts differing by `0x100000` blocks send the **same length**
+downstream. In particular, 16 and `0x100010` both send `0x10000`
+bytes; `0x100000` sends zero, which the downstream helper rejects.
+
+Raw `sub_E15074` uses **arithmetic** `ASR #19` on signed constant
+`0x80001003` to build mask `0xFFFF0000` for its address/length
+checks. Do **not** interpret its decompiler's apparent unsigned
+`>>19` as mask `0x1000`. It requires a nonzero, suitably aligned
+**already-truncated** length and then calls signed `sub_E207A4`
+for table-range validation on type 2 before any fixed-source
+operation. This does not establish permission for an oversized
+physical write or a bypass of the actual range check.
+
+`psp_emu/harness/probe_sysdrv_101a_count_wrap.py` passed with
+signed `.54` dispatch. Isolated init left `0xE26259=1` but has no
+natural populated flash table. The test replaced **only**
+`sub_E0AE90` with a synthetic aligned lookup and **replaced the
+sink `sub_E15074`** with an argument-capture/error hook; it
+confirmed lengths `0x10000`, `0x10000`, zero for counts 16,
+`0x100010`, `0x100000`. No signed downstream check, table row,
+physical read/write or SPI flash effect ran. The available local
+2-MiB flash dumps do not supply natural signed `$RA2` rows at the
+relevant offset.
+
+No trusted signed caller expecting rejection of high count bits,
+nonpublic row reachable by this alias, accepted live table,
+Navi31 hardware consequence, or safe restoration oracle is
+established. Do not exercise the stateful flash/image route on the
+card to obtain a return code. See separate tag-row confinement
+candidate `fw/CANDIDATE-GCP-SYSDRV-1094-CROSS-PARTITION-SPI-WRITE.md`;
+this observation does **not** prove that finding's natural metadata
+or impact.
diff --git a/fw/LEAD-GCP-SYSDRV-101D-NESTED-INPUT-GATE.md b/fw/LEAD-GCP-SYSDRV-101D-NESTED-INPUT-GATE.md
new file mode 100644
index 0000000..9108f0a
--- /dev/null
+++ b/fw/LEAD-GCP-SYSDRV-101D-NESTED-INPUT-GATE.md
@@ -0,0 +1,26 @@
+# Free SYS_DRV `.54` `0x101D`: nested input fields beyond declared span, behind per-caller gate
+
+**Conditional signed-code overread lead; no reached or live effect.**
+Contrary to the historical stub list, the dispatcher calls
+`sub_E1F6C4` with `msg[2]` as its nested input pointer and the
+sOS-supplied caller index. Its role row at `0xE25C9C` is
+`{0x101D,1,2,0,0}`: `msg[2]/[3]` is declared input and
+`msg[4]/[5]` declared output. After `sub_E0E7B8(caller_index)`
+succeeds, raw signed `0xE1F6EA` reads a **dword at `input+52`** and
+compares it with declared output length `msg[5]`, but does not check
+that declared input length `msg[3]` reaches `+55`. The subsequent
+`0xE1F6F4` reads `input+48` and passes a derived length to crypto
+helpers. A four-byte input declaration can pass the dispatcher role
+check without bounding these nested reads, **conditional on a valid
+per-caller crypto state**. The crypto record is selected by sOS's
+caller index, not a caller-chosen index in `msg[14]`.
+
+`psp_emu/harness/probe_sysdrv_101d_nested_gate.py` passed on signed
+`.54` dispatch with a synthetic four-byte declaration. Default
+emulator init returned `0xFFFF000B` from the per-caller gate **before**
+reaching the `input+52` read. That is a negative execution control,
+not proof the branch is naturally satisfiable, and no artificial
+crypto session was planted. The signed code establishes the
+conditional missing span bound; live active-session feasibility,
+whole-span PTEs, crypto completion and other-client impact are open.
+No card request was issued.
diff --git a/fw/LEAD-GCP-SYSDRV-101E-OWNER-BYPASS-TEARDOWN.md b/fw/LEAD-GCP-SYSDRV-101E-OWNER-BYPASS-TEARDOWN.md
new file mode 100644
index 0000000..d4cc738
--- /dev/null
+++ b/fw/LEAD-GCP-SYSDRV-101E-OWNER-BYPASS-TEARDOWN.md
@@ -0,0 +1,102 @@
+# Static lead: free SYS_DRV `0x101E` reaches owner-bypassing region teardown
+
+**Evidence level: signed `.54` disassembly plus targeted read-only hardware
+checks of SYS_DRV state/flags. Neither `0x101E` nor `0x105E`/`0x105F` was
+invoked on hardware for this audit.** Potential impact requires a successful
+privileged teardown and verified device effect; neither has been measured.
+This is **not** a confirmed cross-client DoS or kernel permission change.
+
+## Contrasting the direct and indirect teardown paths
+
+* SYS_DRV dispatcher `sub_E105A8`, opcode `0x105E` (decimal 4190), calls
+ `sub_E13ABC(msg[14], msg[15], **1**)`. Index must be `<16`, and slot must
+ have the active flag in fabric table `0x49007A00+24*index+8`. The signed
+ **ARM instructions** at `0xE13B16..0xE13B22` call `SVC 0x66`, load the
+ stored owner from SYS_DRV table `0xEA650C+8*index`, compare them, and branch
+ away on mismatch. When the flag and owner match, the function can request
+ `SVC 0x89` (for a nonzero flag), clear four fabric region words via
+ `sub_E218FC`/`SVC 0x7C`, retire the owner (`255`), and call `SVC 0x8A`
+ conditionally. The signed `sub_E17EF4` allocation path obtains that owner
+ from the same `SVC 0x66` at `0xE17F06..0xE17F0A`. The older description
+ “bounded index, therefore safe” missed this *real owner check*: directly
+ targeting another client's region through `0x105E` is **blocked** by signed
+ code, not proved possible.
+* The very same free dispatcher accepts opcode `0x101E` (decimal 4126),
+ returning `sub_E11C9C(1)`. It lies outside all 11 listed ACL ranges in
+ `sub_E05A24`. `sub_E11C9C` first requires its global state at
+ `0xE26488+32..+39` to be nonzero. It loops region indexes **1..15** for
+ which `*(u8 *)(0xEA658C+index)` is nonzero, calling
+ `sub_E13ABC(index, 1, **0**)`. In `sub_E13ABC`, `a3=0` takes the branch
+ at `0xE13B16` **past** the `SVC 0x66` owner comparison. On successful
+ per-slot teardown it clears the flag. Regardless of whether any flags were
+ set, the outer cleanup clears its SYS_DRV state and calls `SVC 0xA1` with
+ **R0=R1=R2=0** (`0xE11D14..0xE11D44`).
+* The 16-byte flag array is zeroed during SYS_DRV initialization
+ (`sub_E0CA2C`) and set after region allocation in `sub_E19118`, reached
+ by the `0x1006` and `0x1024` workflows. That is a *selected internal
+ set*, not an arbitrary caller index or proof that any victim flag is live
+ on this card. `0x1024` includes signed-image and resource checks; simply
+ naming it free does not make it a usable marker-staging primitive.
+
+The sOS `.54` handler for `SVC 0xA1` is `sub_59E8` case 80 (opcode
+`81+80=0xA1`). It stores the three supplied words in sOS globals
+`0x8190..0x819B`. With the signed SYS_DRV caller's zero arguments, this
+**requests a sOS-global bounds reset**. sOS `sub_6CB0` later reads these
+same globals to exclude two reserved physical ranges before `sub_3880`
+maps physical memory for `SVC 0x89`; with a zero base the optional range
+check is skipped and the other range is relocated to low physical memory.
+This is signed-code data flow, **not** a demonstrated mapping of protected
+RAM or a live hardware write/readback. Other gate and MMU constraints may
+still reject such a mapping.
+
+This is a **distinct static authorization discrepancy**: the direct region
+release checks owner, while an ungated global cleanup routes through the
+same helper with its owner check disabled and also requests a kernel-global
+bounds reset, even when no per-slot flag is live. It might be intentional
+administrative cleanup; whether unprivileged GCP can invoke it while a
+protected range is active on this card, and what actually changes, are open.
+`0x105E` and `0x101E` return values alone cannot prove fabric or CPU-MMU
+changes. Do **not** invoke `0x101E` on the card merely to see whether TMR,
+firmware, or display protection disappears: it requests global teardown and
+there is no understood, safely restorable oracle yet.
+
+## Targeted read-only hardware precondition check
+
+After a controlled ATX cold boot (bridge `LINK UP`), signed ASD and GCP
+loaded with status zero and GCP session ID **1**. GCP ROP issued three
+read-only `SVC 0xF2` calls: known ASD code `0xD013B8` as a control, then
+SYS_DRV `0x109A` for `0xE264A8` and `0xE264AC`. The code control matched
+`0x2800B57C`; the SYS_DRV words were **`0x00300000`** and
+**`0x00000080`**, making the early-return qword
+`*(u64 *)0xE264A8 = 0x0000008000300000` **nonzero** on this boot. FE0A
+`0x240`, graceful marker `0x5A`, zero fault frame, final FE07 zero. The
+The qword check alone does not establish flagged victim slots or any effect.
+Log: `/root/psp/hw/sysdrv_101e_state_fresh.log`; probe:
+`/root/psp/hw/gcp_rop_sysdrv_101e_state.py`.
+
+On **another** fresh boot, with the same ASD code control, zero fault frame,
+FE0A `0x240`, graceful return and clean FE07, two read-only `0x109A`
+queries returned flag dwords `0xEA658C → 0x01000000` and
+`0xEA6590 → 0x01010101`. In little-endian byte order, selected SYS_DRV
+region slots **3, 4, 5, 6, 7** were marked `1`; only slots 0..7 were read.
+A **third** fresh boot paired flag slot 3 (`1`) with its SYS_DRV owner-table
+word `0xEA650C + 8*3 = 0xEA6524 → 0`. Both runs had the same clean controls
+and responsive ring. Logs:
+`/root/psp/hw/sysdrv_101e_{bitmap,owner3}_fresh.log`; probes:
+`/root/psp/hw/gcp_rop_sysdrv_101e_{bitmap,owner3}.py`. These tests did not
+invoke the cleanup or read the fabric active bit at
+`0x49007A00+24*3+8`. Owner **0** is a stored SYS_DRV table value, **not**
+by itself proof of the GCP process ID or of a different client's live secret.
+The qword, multi-slot bitmap and slot-3 owner were not all measured on a
+single boot; do not assert simultaneous hardware state from separate runs.
+
+Static producers of the flags are `sub_E19118`, reached from `0x1006`
+SETUP_TMR and `0x1024` signed-image workflow. Hardware establishes that
+selected flag slots actually occur on fresh boots, but **not which** signed
+client established them, whether the associated fabric entries remain
+active, whether `0x101E` would successfully retire them, or whether
+sOS-global bounds can then be exploited. Do **not** invoke `0x101E` just
+because its early-return qword and selected flag slots were observed:
+resetting sOS physical-range bounds and device mappings has no understood,
+safely restorable oracle yet. No TSU/SPI-flash or speculative mapped-source
+experiment is justified.
diff --git a/fw/LEAD-GCP-SYSDRV-1021-GLOBAL-BRINGUP-FLAGS.md b/fw/LEAD-GCP-SYSDRV-1021-GLOBAL-BRINGUP-FLAGS.md
new file mode 100644
index 0000000..779946b
--- /dev/null
+++ b/fw/LEAD-GCP-SYSDRV-1021-GLOBAL-BRINGUP-FLAGS.md
@@ -0,0 +1,48 @@
+# SYS_DRV `.54` free `0x1021`: caller-selected shared bringup flags
+
+**Status:** signed global-state authority lead plus synthetic signed-dispatch
+stores. No post-GCP natural bringup trigger, card before/after, restoration
+oracle or demonstrated cross-client fault. Do **not** issue these stateful
+modes on hardware merely for return codes.
+
+`sub_E105A8` dispatches free opcode `0x1021` (role row `0xE25CB0 =
+{0x1021,2,0,0,0}`) to `sub_E07524(msg[14], (u8)msg[15], msg[2])`.
+The first pointer is an output-role caller buffer validated with declared
+`msg[3]`; a NULL `msg[2]` returns `0xFFFF0006` before mutation. Given
+an admitted pointer, the signed leaf writes an acknowledgment word there.
+Raw stores at `0xE07544..0xE07556` modify shared SYS_DRV bytes
+`0xE252D8..0xE252DA` depending on the **caller-selected** scalar mode:
+
+| `msg[14]` | signed store |
+|---|---|
+| 0 | `E252D8 = (u8)msg[15]`; `E252D9 = 1` |
+| 1 | `E252DA = 0` |
+| 2 | `E252DA = 1` |
+| 5 | `E252D9 = 0` |
+| 6 | query; writes 2 or 3 to caller output, no flag store |
+
+The relevant downstream consumer is `sub_E09B60`, which tests
+`E252D9`, clears `E252DA`, issues `SVC 0x57`, and either returns
+`E252D8` when nonzero or waits up to its bound for `E252DA` to change.
+`sub_E083D4` calls that helper with bound 100 and can take a failure path
+if it returns nonzero. The direct signed chain is
+`sub_E07584 → sub_E05528 → sub_E1BCFC → sub_E083D4`;
+`sub_E07584` has no direct call xref and its indirect scheduling and
+post-GCP reachability are **unresolved**. Multiple hardware/config gates
+precede the consumer. A writable shared flag is not by itself a live DoS.
+
+`python3 psp_emu/harness/probe_sysdrv_1021_global_flags.py` passes
+against signed `.54` dispatcher and leaf, using a **synthetic** type-5
+window from `SVC 0xB5`. The isolated signed init left bytes `ff0000`;
+mode 0 with byte `0x41` gave `410100`, mode 1 `410100`, mode 2
+`410101`, and mode 5 `410001`, all returning zero and setting the
+GCP-owned acknowledgment word to 1. The script restores its synthetic
+three-byte snapshot; this is **not** an independent live restoration
+oracle. A preliminary NULL-output request returned `0xFFFF0006` with
+no store, so return-code-only probes without the required output pointer
+would not have tested this effect.
+
+Next steps: identify the indirect `sub_E07584` registration/scheduling,
+measure actual later consumer execution without altering card state, and
+establish a non-destructive exact restoration oracle before any hardware
+mode change. No card request was made for this audit.
diff --git a/fw/LEAD-GCP-SYSDRV-1026-REINIT-WITHOUT-STARTUP-GATE.md b/fw/LEAD-GCP-SYSDRV-1026-REINIT-WITHOUT-STARTUP-GATE.md
new file mode 100644
index 0000000..83bc82c
--- /dev/null
+++ b/fw/LEAD-GCP-SYSDRV-1026-REINIT-WITHOUT-STARTUP-GATE.md
@@ -0,0 +1,34 @@
+# Free SYS_DRV `.54` `0x1026`: re-enters initialization without its signed startup predicate
+
+**Conditional lifecycle/availability lead, signed-static only. Do not
+invoke on the card merely to get a status.** The free high dispatcher
+`sub_E105A8` case `0x1026` calls `sub_E025D0` directly. Its nominal
+request scalar is unused by this leaf, and no owner/current-phase check
+precedes the initial writes.
+
+Signed Thumb `0xE025D0..0xE025E0` first sets the SYS_DRV-private
+status word `0xE26154` to **0** and `0xE257BC` to **2**, before
+`sub_E0B490` chooses a hardware branch or later initialization calls
+can fail. The variant-`0x100` branch sets `0xE26154` to 1 again only
+after that selector; other paths call `sub_E16160`, `sub_E0DB94`,
+`sub_E167F0`, `sub_E02A38` and related stateful helpers. Two direct
+readers of the `0xE26154` status include `sub_E0ABE0` and
+`sub_E20108`; `0xE257BC` is also referenced by multiple signed
+leaves, including the `0x1076` path. This is not a read-only getter
+or a return-code-only operation.
+
+The only other direct signed callsite of `sub_E025D0` found was
+`sub_E0C9AC` during SYS_DRV's normal management path. There it is
+conditioned on `BYTE1(*((_DWORD *)*off_E0C9E4+693))==1`, under an
+sOS mutex, before updating the manager's completion word. Direct free
+`0x1026` bypasses **that particular callsite's** pending-request
+predicate; it is not established that the predicate is meant as a
+security ACL or that every authorized reinitialization must use it.
+There may be later hardware-side gates and indirect callsites.
+
+No live pre-call values, concurrent RAP/other-client ownership,
+recovery behavior, safe restoration oracle, or hardware reinitialization
+effect are established. The initial two stores and control-flow gap
+are signed-code observations, **not** proof of a live cross-client reset
+or broader privilege escalation. A modeled init with default-success
+SVCs would not supply a hardware oracle for these stateful effects.
diff --git a/fw/LEAD-GCP-SYSDRV-1028-FIXED-CPU-WINDOW-WORD.md b/fw/LEAD-GCP-SYSDRV-1028-FIXED-CPU-WINDOW-WORD.md
new file mode 100644
index 0000000..14f0eb4
--- /dev/null
+++ b/fw/LEAD-GCP-SYSDRV-1028-FIXED-CPU-WINDOW-WORD.md
@@ -0,0 +1,40 @@
+# Free SYS_DRV `.54` `0x1028`: caller-chosen dword in indexed CPU window
+
+**Signed-code fixed-window write capability, synthetic target only; no
+live other-client/security effect.** Historical inventory called
+`0x1028` a tiny/query getter, but signed `sub_E105A8` case 4136
+calls `sub_E13A2C(msg+14)`. It bounds inline `msg[14]` to **0..15**.
+When `msg[16] != 0`, it copies a word from
+`*(u32 *)(*0xE2579C + 0x500 + 4*index)` to inline `msg[15]`;
+when `msg[16] == 0`, it writes the **caller-chosen `msg[15]`** to
+that same fixed indexed word. There is no per-caller owner/record
+comparison in this leaf. This is a **CPU-MMU virtual-address dereference
+through a SYS_DRV-private pointer**, not `SVC 0x7C` and not an
+arbitrary PSP virtual or fabric address.
+
+`psp_emu/harness/probe_sysdrv_1028_base_readonly.py` found signed
+modeled init sets `*0xE2579C` from 0 to **`0x03010000`**, placing
+the indexed window at `0x03010500..0x0301053F`; the emulator maps
+that region through its generic `MMIO_BASE=0x03010000` window
+(`psp_emu/pspemu/memmap.py`). It **did not read any word contents**.
+Model MMIO backing is not proof of the real card's PTE attributes,
+other-client ownership, register meanings or exact live pointer.
+
+`psp_emu/harness/probe_sysdrv_1028_synthetic_window.py` passed on
+signed dispatch with modeled caller caps 2. It temporarily swapped
+`*0xE2579C` to a fresh **synthetic owned buffer**, wrote
+`0x2468ACE0` at selected index 3, read it back through signed
+`0x1028`, and verified adjacent words stayed zero. Index 16
+returned `0xFFFF0006` without a store. The pointer was restored in
+**emulator memory**; the original `0x03010000` window was never
+read or written. This proves a signed selected-word store in the
+swapped model, not a card CPU-MMU/MMIO effect or cross-client victim.
+
+A scoped signed-image direct-base-reference survey found no
+other explicit `+0x500` field access among the 31 functions that
+refer directly to `0xE2579C`; indirect pointers and hardware
+consumers remain unexamined. The signed setter of the pointer,
+natural users of the 16 fields, live values, effective MMU mappings and an exact hardware restoration
+oracle remain open. Do **not** write to this window on the card merely
+for readback/return status. Calling this an arbitrary RAM write or
+security bypass would overstate the evidence.
diff --git a/fw/LEAD-GCP-SYSDRV-1029-FIXED-MMIO-WORD.md b/fw/LEAD-GCP-SYSDRV-1029-FIXED-MMIO-WORD.md
new file mode 100644
index 0000000..254de75
--- /dev/null
+++ b/fw/LEAD-GCP-SYSDRV-1029-FIXED-MMIO-WORD.md
@@ -0,0 +1,28 @@
+# Free SYS_DRV `.54` `0x1029`: fixed CPU-window word set to all ones
+
+**Signed-code fixed-word state change, synthetic target only; no live
+register meaning or impact.** Historical overview lists `0x1029`
+as a tiny/query getter. Signed `sub_E105A8` case 4137 instead calls
+`sub_E12984`, which unconditionally stores **`0xFFFFFFFF`** at
+`*0xE2579C + 423*4` (**offset `0x69C`**) and returns; dispatch then
+returns zero. There is no caller-chosen value, index or owner test
+in this leaf. This is a SYS_DRV CPU-MMU store, **not** a
+caller-chosen fabric `SVC 0x7C` address. Its private pointer is the
+same one used by the separate indexed `0x1028` getter/setter.
+
+Signed emulator init set the pointer to **`0x03010000`**, so its
+modeled target is `0x0301069C` within the generic emulator MMIO
+window; no word there was read or written. An extension to
+`psp_emu/harness/probe_sysdrv_1028_synthetic_window.py` instead
+swapped the private pointer to an owned synthetic buffer and ran
+signed `0x1029`: status was zero, the buffer's `+0x69C` became
+`0xFFFFFFFF`, and adjacent words stayed zero. It restored the
+pointer **in emulator memory only**; the original CPU window was
+untouched. The synthetic store does not show real Navi31 register
+acceptance, a second-client effect, or a card restoration oracle.
+
+Do not call this opcode on the card merely for a return code. A
+read-only examination of the real pointer/PTE and independently
+identified register semantics would be needed before claiming a
+security consequence. See also
+`fw/LEAD-GCP-SYSDRV-1028-FIXED-CPU-WINDOW-WORD.md`.
diff --git a/fw/LEAD-GCP-SYSDRV-102C-LABEL-SPAN.md b/fw/LEAD-GCP-SYSDRV-102C-LABEL-SPAN.md
new file mode 100644
index 0000000..9d3ca7b
--- /dev/null
+++ b/fw/LEAD-GCP-SYSDRV-102C-LABEL-SPAN.md
@@ -0,0 +1,33 @@
+# Free SYS_DRV `.54` `0x102C`: caller label length is lost before gated KDF
+
+**Conditional source-to-read lead, not a reached overread.** Contrary
+to the historical stub list, signed dispatcher case `0x102C` calls
+`sub_E12A88`. Its role row at `0xE25CEC` is
+`{0x102C,1,2,0,0}`: `msg[2]/[3]` is a declared caller input,
+`msg[4]/[5]` a declared caller output. The dispatcher copies the
+caller **label pointer** `msg[2]` to scratch `msg[15]`, but does not
+pass `msg[3]` to `sub_E12A88 → sub_E07A00` as a label bound. If the
+preceding signed `sub_E116CC` crypto helper succeeds,
+`sub_E07A00 → sub_E07A80 → sub_E01864` calls unbounded `strlen`
+on that label before testing `(strlen+5)<=0x80`. Signed sOS
+`SVC 0xB5` checks the **declared** input span against coarse
+process windows, not the later string walk.
+
+`psp_emu/harness/probe_sysdrv_102c_label_reach.py` tried the signed
+`.54` dispatch with a four-byte declaration and NUL at synthetic
+label `+8`. Unhooked emulation first faulted at signed
+`sub_E116CC` PC `0xE11712`, FAR `0x200`, because modeled shared
+crypto base `0xE257D8` was zero; label `strlen` was **not** reached.
+Planting a synthetic aligned shared base for `0xE257D8/0xE257DC`
+then moved the model to another copy fault at `0xE01940`, FAR 0,
+still before the label read. The original modeled pointers were
+restored and no derived crypto bytes printed. This is not natural
+CCP success, a live GPU fault, or a proof that a caller can read
+beyond its live mapped window.
+
+Free `0x109D` does reach the same `strlen` *before* its later
+synthetic crypto-base fault and has its own signed-dispatch boundary
+controls (`fw/CANDIDATE-GCP-SYSDRV-109D-LABEL-STRING-OVERREAD.md`).
+Do not transfer that execution evidence to `0x102C`. Actual signed
+crypto-base initialization, intermediate helper completion and PTE
+coverage remain open. No card request was issued.
diff --git a/fw/LEAD-GCP-SYSDRV-102E-FIXED-CPU-WINDOW-WORD.md b/fw/LEAD-GCP-SYSDRV-102E-FIXED-CPU-WINDOW-WORD.md
new file mode 100644
index 0000000..41cc04b
--- /dev/null
+++ b/fw/LEAD-GCP-SYSDRV-102E-FIXED-CPU-WINDOW-WORD.md
@@ -0,0 +1,28 @@
+# Free SYS_DRV `.54` `0x102E`: caller-chosen word at a fixed second CPU window
+
+**Signed fixed-word setter/getter; only a swapped synthetic buffer was
+modified.** Historical overview lists `0x102E` as a tiny getter.
+Signed `sub_E105A8` case 4142 calls `sub_E13A60(msg+14)`.
+When inline `msg[15]==0`, it writes the **caller-chosen `msg[14]`**
+to `*(u32 *)(*0xE257A0 + 0xD8)`; otherwise it returns that word
+in inline `msg[14]`. The leaf has no owner or current-phase check.
+This is a single fixed **CPU-MMU** dereference, not caller-chosen
+arbitrary PSP memory and not an `SVC 0x7C` fabric-address write.
+
+The signed-model initialization sets `*0xE257A0=0x03200000`, giving
+an arithmetic target of `0x032000D8`. This is **different** from
+`0x1028/0x1029`'s base `*0xE2579C=0x03010000`. The emulator does
+not provide faithful live backing/clock-register semantics for the
+second aperture (another signed user of `*0xE257A0` faults on an
+unmapped `0x032001E0` access). The exact card PTE and hardware
+register meaning are unverified.
+
+An extension to `psp_emu/harness/probe_sysdrv_1028_synthetic_window.py`
+passed on signed `.54` dispatch: it temporarily swapped **both**
+private base pointers to a fresh buffer, then `0x102E` stored
+`0x13579BDF` at buffer `+0xD8` and returned it on the getter path.
+Adjacent words stayed zero. Both pointers were restored **only in
+emulator memory**; neither original CPU window was read or written.
+No second-client record, hardware effect, or safe card restoration
+oracle is established. Do not invoke the setter on the card for
+readback or a return code.
diff --git a/fw/LEAD-GCP-SYSDRV-102F-FIXED-SOURCE-128K-READ.md b/fw/LEAD-GCP-SYSDRV-102F-FIXED-SOURCE-128K-READ.md
new file mode 100644
index 0000000..d3b7ca7
--- /dev/null
+++ b/fw/LEAD-GCP-SYSDRV-102F-FIXED-SOURCE-128K-READ.md
@@ -0,0 +1,35 @@
+# Free SYS_DRV `.54` `0x102F`: fixed-base 128-KiB mapped-source copy
+
+**Signed data-transfer path, not a demonstrated confidential-data
+leak.** Contrary to the historical stub list, free `0x102F`
+dispatches to `sub_E13A00`. Its role row at `0xE25D50` is
+`{0x102F,2,0,0,0}`: the caller output pointer/declared length is
+validated. The leaf requires `msg[3]>=0x20000` before a tail call to
+`sub_E062F8` with fixed source offset **`0x7B0000`**, length
+**`0x20000`**, and caller output pointer `msg[2]`. Raw signed
+`0xE06314..E06352` obtains a base via `SVC 0x73`, adds `0x7B0000`,
+then loops 32 times: `SVC 0x88` maps a 4-KiB source page,
+`sub_E018A0` copies it to `msg[2]+4096*i`, `SVC 0x63` releases the
+map, and `SVC 0x68` finishes. The copied span fits the declared
+minimum. Signed sOS `.54` `SVC 0x88` case 55 rejects a direct type-5
+caller but permits SYS_DRV's type-2 context under its other checks;
+`SVC 0x73` case 34 returns a runtime word at `0x80E4`, zero in the
+static image. The live base, backing device and data classification
+are **not** known merely from the `0x7B0000` offset.
+
+`psp_emu/harness/probe_sysdrv_102f_fixed_map.py` passed on signed
+`.54` dispatch/leaf. A 131071-byte declared output returned
+`0xFFFF0010` without mapping or stores; a 131072-byte declaration
+looped through 32 modeled `SVC 0x88` maps and 32 signed page copies,
+returned zero, changed the synthetic output within the declaration,
+and left a 16-byte tail untouched. **This is not a flash dump.** The
+`sysdrv_env` model implements `SVC 0x88` as identity mapping and
+repeats a local signed ELF's first 4 KiB on each modeled page in
+`0x780000..0x7F0000`; it also plants unsigned config overlays for
+init. The copied content was not printed or attributed to the card.
+
+Actual type-5 output PTE coverage for 128 KiB, signed sOS runtime
+base, the real mapped source's confidentiality and independent card
+effect remain open. No card request was issued. The signed API may
+be intended to expose public firmware bytes; reachability and a
+successful model return do not establish a new security bug.
diff --git a/fw/LEAD-GCP-SYSDRV-1030-SELECTOR19-FABRIC-MODE.md b/fw/LEAD-GCP-SYSDRV-1030-SELECTOR19-FABRIC-MODE.md
new file mode 100644
index 0000000..9a28ec2
--- /dev/null
+++ b/fw/LEAD-GCP-SYSDRV-1030-SELECTOR19-FABRIC-MODE.md
@@ -0,0 +1,34 @@
+# Free SYS_DRV `.54` `0x1030(0x19)`: one-way private mode bit before fixed fabric path
+
+**Conditional state/fabric-mode lead, not a demonstrated register effect.**
+Do not issue this opcode on hardware merely to inspect a status: a
+signed restoration path for this bit is not identified.
+
+Free dispatcher case `0x1030` calls `sub_E1411C(msg+14)`. Its inner
+selector **`0x19` (decimal 25)** unconditionally writes byte **1** to
+SYS_DRV-private `0xE2663D`, ignoring the request's value and with no
+owner comparison. `psp_emu/harness/probe_sysdrv_1030_fixed_mode_flag.py`
+passed on the signed `.54` dispatcher: in default **synthetic** init it
+observed this byte `0→1` and restored it by a direct emulator memory
+snapshot—not through a signed opcode. Unrelated init SVCs default to
+success. This is distinct from decimal selector 13 (`0xD`), which
+sets the SPI class gate `0xE257AC` in
+`fw/CANDIDATE-GCP-SYSDRV-1030-FLASH-CLASS-GATE.md`.
+
+The only exact signed literal to `0xE2663D` is in `sub_E0C914`, which
+feeds its nonzero predicate into `sub_E14B98` after several fixed
+`SVC 0x7B/0x7C` operations. `sub_E14B98` also maps a resource returned by
+`sub_E0BCE0` and issues more `SVC 0x7C` writes. The direct signed call chain is
+`sub_E12D80 → sub_E0E940(type 68) → sub_E10234(68) →
+sub_E0C988 → sub_E0C914 → sub_E14B98`; `sub_E105A8` can enter
+`sub_E12D80` through free firmware-load opcode `0x1007`, but its
+image header, length, signature/resource gates and actual type-68
+availability are **not** satisfied by the flag-set test. This chain
+does not prove a GCP-selected fabric address or successful write.
+
+A scan of exact address literals did not identify a post-init setter
+back to zero; an indirect clear, process reset or other writer is not
+excluded. The live flag value, callback scheduling, endpoint decode,
+accepted signed type-68 image, effect and exact restoration oracle are
+unmeasured. Treat the synthetic byte store and static call chain as
+separate evidence from any hypothetical live effect.
diff --git a/fw/LEAD-GCP-SYSDRV-1034-ERROR-RETURN-CPU-WINDOW-STATUS.md b/fw/LEAD-GCP-SYSDRV-1034-ERROR-RETURN-CPU-WINDOW-STATUS.md
new file mode 100644
index 0000000..d32601e
--- /dev/null
+++ b/fw/LEAD-GCP-SYSDRV-1034-ERROR-RETURN-CPU-WINDOW-STATUS.md
@@ -0,0 +1,40 @@
+# Free SYS_DRV `.54` `0x1034`: conditional error-return fixed CPU-window status store
+
+**Signed stateful configuration path and synthetic target-swapped
+error side effect; no live register effect or privilege impact.**
+The historical overview groups `0x1034` with small memcpy helpers,
+but signed `sub_E105A8` case 4148 calls `sub_E12AD4(msg[14])`.
+That leaf queries configuration through `sub_E0A352`, packs
+caller-controlled scalar fields into a local descriptor, optionally
+issues a type-2 reset when bit `0x40000` is set, and calls
+`sub_E09E70(type=1,descriptor,1)`. On **successful** configuration
+it calls `sub_E0A494` to refresh status. No caller-supplied pointer
+is passed to that final store.
+
+Signed `sub_E0A494` initializes local fields to zero, tries
+`sub_E0A352` and several other status getters in sequence, but
+**regardless of getter error** stores a packed word to
+`*(u32 *)(*0xE2579C + 0x994)` before returning the getter's
+status. This is the same SYS_DRV-private CPU-window base used by
+`0x1028` and `0x1029`, at a **different fixed offset**. Isolated
+model init sets `*0xE2579C=0x03010000`; the arithmetic target
+would be `0x03010994` in that model. Actual CPU PTE/register
+meaning and live original contents were not read.
+
+`psp_emu/harness/probe_sysdrv_1034_failed_status_store.py` passed
+on signed dispatch. It swapped the private base to a fresh
+**synthetic** buffer; stubbed initial `sub_E0A352` success and
+`sub_E09E70` success (no real crypto/hardware configuration); then
+stubbed the **second** `sub_E0A352`, within `sub_E0A494`, to fail
+with 9. Signed `0x1034` returned 9 while clearing the planted
+buffer word at `+0x994` from `0xA5A5A5A5` to zero; neighboring
+words stayed intact. The original base was restored **in emulator
+memory** and untouched. The experiment does not establish natural
+CCP/config success, a natural status failure, hardware acceptance,
+or ownership of that fixed register. The clear might be intentional
+fail-closed stale-status handling.
+
+Do not call `0x1034` or write/read the real fixed CPU window on the
+card merely to obtain status. A legitimate register specification,
+independent readback and exact restoration oracle are needed before
+claiming a security-relevant device-state effect.
diff --git a/fw/LEAD-GCP-SYSDRV-1037-UNBOUNDED-MAILBOX-WAIT.md b/fw/LEAD-GCP-SYSDRV-1037-UNBOUNDED-MAILBOX-WAIT.md
new file mode 100644
index 0000000..5293faf
--- /dev/null
+++ b/fw/LEAD-GCP-SYSDRV-1037-UNBOUNDED-MAILBOX-WAIT.md
@@ -0,0 +1,39 @@
+# Free SYS_DRV `.54` `0x1037`: caller-selected indefinite mailbox wait
+
+**Conditional availability/lock-contention lead; signed-static only.**
+No hardware request, live mapped register observation or second-client
+failure has been made. An indefinite caller-selected timeout may be an
+intentional management API, rather than a separate memory-safety bug.
+
+`sub_E105A8` dispatches free `0x1037` with `msg[14]` and `msg[15]`
+as mailbox payload scalars, `msg[16]` as timeout, and a result at
+`msg[17]` to `sub_E18364`. The leaf issues `SVC 0x5E` with the
+SYS_DRV-private lock ID at `0xE25774` (zero in the signed initial
+image), maps **fixed fabric address `0x3B10700`** for `0x20` bytes
+with `SVC 0x7D`, and polls a mapped status word. Signed sOS `.54`
+`sub_59E8` cases 13 and 14 route `SVC 0x5E` and `SVC 0x5F` to its
+mutex acquire/release handlers `sub_A38` and `sub_4860`; the SYS_DRV
+code does not examine the acquire result. The mapped status, fabric
+semantics and runtime lock ID are not measured.
+
+At `0xE183A6..0xE183B0`, each zero-status poll computes
+`timeout+1`; `timeout==0xFFFFFFFF` skips its timeout comparison and
+repeats through `SVC 0x56` without a finite limit. If the first status
+allows a request, the leaf writes the payload to the mapped fabric
+window and has a second zero-status poll at `0xE183F2..0xE183FC`
+with the **same** `timeout+1==0` bypass. The intervening 101-call
+`sub_E1ECEE(10)` loop at `0xE183CE..0xE183E4` is bounded but does
+not bound the subsequent poll. `SVC 0x5F` and unmap occur only on
+exit at `0xE18420..0xE1842C`; a permanently zero status with
+unlimited timeout would remain inside the function. A finite timeout
+has an error-exit branch (`0x80000306`).
+
+A scoped opcode-immediate scan of the selected signed ELF corpus found
+no direct `0x1037` hit, but it misses computed callsites. GCP ROP
+has demonstrated service-1 access to other free opcodes; this does
+not prove that the fixed fabric mapping succeeds, that a status is
+zero long enough, that this lock is shared with a victim, or that a
+real request will hang. The prior NULL-source opcode-`0xD` test already
+established a recoverable post-ROP DoS by a **different** mechanism.
+Do not issue `0x1037` with an unlimited timeout or mutate the mapped
+mailbox on hardware merely to obtain a return code.
diff --git a/fw/LEAD-GCP-SYSDRV-1038-LENGTH-DRIVEN-CRYPTO-LOOP.md b/fw/LEAD-GCP-SYSDRV-1038-LENGTH-DRIVEN-CRYPTO-LOOP.md
new file mode 100644
index 0000000..351f998
--- /dev/null
+++ b/fw/LEAD-GCP-SYSDRV-1038-LENGTH-DRIVEN-CRYPTO-LOOP.md
@@ -0,0 +1,31 @@
+# Free SYS_DRV `.54` `0x1038`: declared output length drives crypto loop
+
+**Conditional work-amplification lead, not a demonstrated hang or
+cross-client fault.** The historical stub list was incorrect: signed
+dispatch case `0x1038` calls `sub_E11C90 → sub_E07C80` with the
+role-2 output pointer `msg[2]`, its declared length `msg[3]`, and a
+caller selector byte from request scratch `msg[16]`. `sub_E07C80`
+requires selector 1, 2 or 3, nonnull pointer and
+`(msg[3]<<28)==0` (a 16-byte multiple), but **only tests the
+pointer for nonzero**: it does not write that caller buffer. After
+a fixed signed crypto setup, it loops `msg[3] >> 4` times, doing
+crypto helper work per iteration. Thus a caller-declared size is a
+work count rather than evidence of a correspondingly sized output
+write. The signed sOS `SVC 0xB5` role checker uses coarse type-5
+windows (primary length `0x800000`); actual PTE coverage and the
+maximum acceptable live request depend on the process descriptor.
+An 8-MiB modeled declaration corresponds to **524288** iterations
+if *every* preceding helper succeeds. A finite but large count may
+be intentional API semantics.
+
+`psp_emu/harness/probe_sysdrv_1038_length_gate.py` passed on signed
+`.54` dispatch and leaf-entry hooks. Selector zero did not enter the
+crypto helper; selector 1 with declared lengths 16 and `0x800000`
+reached it. The emulator's **permissive synthetic `SVC 0xB5` window**
+accepted the large declaration even though only a small synthetic
+buffer existed. Both valid-selector calls faulted immediately in the
+first crypto setup because emulator shared crypto base `0xE257D8`
+was zero; **no long loop, natural CCP completion, live contention or
+card hang** was demonstrated. This model acceptance cannot prove the
+same VA/width would pass the actual signed sOS type-5 window or PTEs.
+No card request was issued.
diff --git a/fw/LEAD-GCP-SYSDRV-103E-1047-SHARED-KEY-STORE.md b/fw/LEAD-GCP-SYSDRV-103E-1047-SHARED-KEY-STORE.md
new file mode 100644
index 0000000..8626afc
--- /dev/null
+++ b/fw/LEAD-GCP-SYSDRV-103E-1047-SHARED-KEY-STORE.md
@@ -0,0 +1,86 @@
+# SYS_DRV `.54` free `0x103E` / `0x1047`: shared keyed-store authority lead
+
+**Status: signed dispatcher and leaf in a modeled shared mapping; no card
+or independently demonstrated cross-client effect.** Do not fill or alter
+this state on hardware merely for a return code.
+
+`sub_E105A8` cases 4158 (`0x103E`) and 4167 (`0x1047`) pass
+`(msg[14], msg[2], msg[3])` to the same `sub_E01FF8` with mode 2 and
+mode 1 respectively. Their signed role rows at `0xE25DA0` and
+`0xE25DF0` are `{opcode,1,0,0,0}`: the first caller-pointer pair is
+subject to its **declared** length validation; no role checks the scalar
+key in `msg[14]`. The leaf restricts mode 2 to keys with the high bit set,
+mode 1 to keys with the high bit clear. GCP can select either free opcode,
+so this split is not an owner check.
+
+`sub_E0ECB0` requests a fixed `SVC 0x7D` mapping (R0=`0x55FFF`,
+R1=`0x2A000`); `sub_E01FF8` checks header magic `0x50535024` at
+mapping+`0x29FF0`, count `<=255`, requested size `<=0x2A000`, and
+bounds for existing/new records. It looks up records solely by the
+32-bit key, checks an existing record's stored length equals the requested
+length, then copies exactly that length from `msg[2]` to the record.
+It does not compare the initiating caller to a record owner. On a new
+key it appends a 16-byte metadata entry and increases the record count,
+subject to the overall space/count checks; it releases the mapping via
+`SVC 0x7E`.
+
+**Signed sOS `.54` mapping provenance:** `sub_59E8` dispatches SVC `0x7D`
+(case `125-81=44`) to `sub_3CFC(0x55FFF,0x2A000)`. The latter bounds the
+length, runs `sub_6D20`'s software exclusion check and maps the page(s)
+containing the **fixed input address**, returning a PSP virtual address
+with its within-megabyte offset. For this low fixed range,
+`sub_6D20`'s exclusion predicate accepts the requested range at the
+software level (its end lies below `0xCB00000`); mapping resources or live
+PTEs may still prevent success. There is no service-request caller index
+in this mapping request: it runs in SYS_DRV context. SVC `0x7E` (case 45)
+routes to `sub_6AA8` and the inspected `sub_56AC` decrement of mapping
+refcounts, not a wipe of the source bytes. This establishes a fixed
+signed-code backing address across requests when the mapping succeeds;
+it does **not** independently prove live card contents, that the address
+is CPU-visible host RAM, lifetime across boots, or a security-relevant
+consumer. A PSP `SVC 0x7D` address must not be conflated with `SVC 0x7C`
+fabric endpoints.
+
+One signed *internal* producer, `sub_E1411C` case `0x13`, invokes this
+leaf in mode 1 for key `0x28` with a one-byte internal value. The synthetic
+four-byte key-`0x28` example below does **not** reproduce that existing
+one-byte record's format; it demonstrates the same-key rule only. A signed
+SYS_DRV `.54` disassembly search found one other occurrence of the
+`0x50535024` magic in `sub_E0F950`, but its caller `sub_E16964` uses it
+to parse signed image sections, **not** the fixed mapped pool; this is not
+a consumer of the key-store record. A raw-literal scan of the same **95** extracted signed-client ELFs found
+neither the little-endian `0x55FFF` word nor the `0x50535024` word;
+computed addresses, packed constants, and other images are not excluded.
+No natural victim read or signed sOS/SYS_DRV initializer for the **mapped
+pool header** was found in this scoped survey. The signed-image parser's
+same magic is unrelated. This is not evidence that a GCP overwrite
+survives an internal writer, changes a consumer's behavior, or has
+cross-client impact. A scoped
+halfword-resynchronizing immediate scan of **95** files in
+`psp_out/versions_win/elf_all` found no direct `0x103E` or `0x1047`
+candidate; computed RPCs, literals, and other corpora remain open.
+
+## Bounded modeled-map trace
+
+`python3 psp_emu/harness/probe_sysdrv_103e_1047_key_store.py` passes
+against the signed `.54` ELF. It replaces the emulator's misleading
+`SVC 0x7D` **0x40-byte fresh allocation stub** with one persistent
+**synthetic** `0x2A000`-byte mapping, seeds only the required header, and
+supplies a synthetic type-5 caller window through `SVC 0xB5`.
+The unmodified signed dispatcher/leaf create low-key `0x28` from caller
+index 2 with four `A` bytes; a second request from synthetic index 3
+with the same key and length changes those bytes to four `B` bytes while
+record count stays 1. A wrong-length replacement returns `0x80000308`
+without changing the bytes. Calling `0x103E` with a low key or `0x1047`
+with a high key returns `0xFFFF0006` without changing the record.
+Independent reads of the modeled pool verified each before/after value.
+Initialization reports several **unhandled default-success SVCs**, and
+the modeled bytes, caller-index descriptor, and initialization are
+**not** observations from the card. The signed sOS mapping path separately
+supports fixed-address backing and non-wiping unmap; this is still not a
+live victim or meaningful trusted-value proof.
+
+**Next evidence:** identify signed consumers of backing address `0x55FFF`,
+measure (read-only) actual type-5 caller descriptors and the live pool's
+status without reviving the faulting GCP log-gate chain, then seek a
+non-destructive independent effect/restoration oracle. No hardware request or synthetic-state exhaustion test was run.
diff --git a/fw/LEAD-GCP-SYSDRV-1058-WRAPPED-FIRMWARE-LENGTH.md b/fw/LEAD-GCP-SYSDRV-1058-WRAPPED-FIRMWARE-LENGTH.md
new file mode 100644
index 0000000..092db0b
--- /dev/null
+++ b/fw/LEAD-GCP-SYSDRV-1058-WRAPPED-FIRMWARE-LENGTH.md
@@ -0,0 +1,56 @@
+# SYS_DRV `.54` free `0x1058`: conditional wrapped source-length guard
+
+**Static candidate only; neither reachability to the data nor live effect
+established. No card probe is authorized by this report.** The signed
+`sub_E105A8` dispatcher routes free opcode `0x1058` to `sub_E13170`.
+That leaf first rejects state byte `0xE256F6==24` or
+`0xE256F1==0`, then `sub_E09CB8` scans a SYS_DRV-private array
+starting at `0xEA85C0+0x100` for a marked descriptor. It selects a
+record offset `<0x8000`, computes `source=record+0x100`, and reads a
+32-bit `length` at `record+20`.
+
+The ARM instructions `0xE131A0..0xE131B0` perform **32-bit**
+`source+length` and compare only that result with `0xEB05C0`
+(the `0xEA85C0+0x8000` limit). There is no preceding
+`length<=limit-source` or carry test. A near-`2^32` length could
+therefore wrap below the limit. On the taken branch the leaf maps
+**fixed fabric address `0x177D0`** for eight bytes through `SVC 0x7D`,
+writes `0xC000` to the first mapped word, and calls signed
+`sub_E0E64C(source,mapped+4,length)`. That helper reads a halfword,
+writes it to the **same** 32-bit mapped word, and increments its
+unsigned loop counter by two until it reaches `length`. A huge length
+would entail out-of-record reads, prolonged execution/fault or many
+fixed-endpoint writes; these are **predictions, not observed effects**.
+The address is fabric, not established CPU-MMU RAM. No chosen fabric
+address or arbitrary write follows from this path.
+
+Critical gates/unknowns:
+
+- Signed `.54` initialized data at `0xE256F1` is zero; a scan for the
+ exact byte-address literal found only this reader. The aligned
+ `0xE256F0` flag is written as **1** by `sub_E0D2D0` and separately
+ initialized through the structure in `sub_E0CA2C`; `1` sets byte
+ `+0`, **not** this gate at `+1`. This does not exclude indirect
+ writes or measure the live gate. The signed-dispatch default-init
+ control in `psp_emu/harness/probe_sysdrv_1058_default_gate.py`
+ observed `+1==0` and `0x1058` returning `0xFFFF0007` before
+ `SVC 0x7D`; unrelated initialization SVCs default to success in
+ that emulator. On that measured synthetic state the wrapped check
+ is **not reached**.
+- `0xEA85C0` is outside the ELF's loaded file image; an exact-literal
+ search found `0xEA85C0` only in `sub_E09CB8`. The provenance,
+ ownership, allowable lengths and initialization of that private
+ descriptor array are unproven. GCP's ROP access to service 1 is not
+ evidence that GCP can set its `record+20` to a wrapping length.
+- `sub_E09CB8` returns the **first** marked descriptor, not an
+ attacker-selected index inferred from the dispatch scalar. Neither
+ natural selection nor a second client's descriptor has been shown.
+- The fixed fabric endpoint, live mapping, state restoration, and
+ recovery behavior have no safe independent oracle. Do not mutate
+ this state or issue oversized lengths on the card.
+
+Thus the missing carry check is a dormant signed-code defect **if
+both the unmeasured runtime gate and an untrusted/unbounded private
+length can reach it**. The signed default-init test instead returns
+before the check; it is not a proven GCP-triggerable overflow, live
+MMIO effect or privilege escalation.
diff --git a/fw/LEAD-GCP-SYSDRV-105A-ERROR-RETURN-MODE-FLAG.md b/fw/LEAD-GCP-SYSDRV-105A-ERROR-RETURN-MODE-FLAG.md
new file mode 100644
index 0000000..15445de
--- /dev/null
+++ b/fw/LEAD-GCP-SYSDRV-105A-ERROR-RETURN-MODE-FLAG.md
@@ -0,0 +1,38 @@
+# Free SYS_DRV `.54` `0x105A(3)`: failed fixed-register command sets a global mode bit
+
+**Conditional signed error-return state change, gated off in isolated
+signed initialization; no card fabric effect.** Historical overview
+calls `0x105A` a tiny/query getter. Signed case 4186 routes the
+inline selector to `sub_E02524`. That helper first checks
+`sub_E0B490()` (private dword `0xE26164`); selector 3 then calls
+`sub_E02A38(command=528)` and **ORs bit 3 into `0xE26154`
+regardless of the command's result**. On command failure it returns
+that error after a logging path, leaving the bit set. `sub_E02A38`
+may emit a table of **fixed** `SVC 0x7C` commands; it is not a
+caller-selected fabric address.
+
+`psp_emu/harness/probe_sysdrv_105a_error_flag.py` passed against
+signed `.54` dispatch. Post-init gate `0xE26164` was **`0x100`**;
+`0x105A(3)` returned `0xFFFF000A` before the command and left the
+flag zero. The harness then **planted gate zero in emulator memory**
+and stubbed only the fixed-register command helper to return
+`0x80000306`. Signed dispatch propagated that error while changing
+`0xE26154` from zero to **8**. The helper and gate were restored in
+emulator memory; no fixed-register command was executed. The
+synthetic error is not a natural ASIC failure.
+
+There is a signed downstream consumer: `sub_E2005C` chooses
+`sub_E20108` rather than `sub_E20570` only when the same gate is
+**not `0x100`**. Its type-4 / command-528 branch tests bit 3 of
+`0xE26154`; if clear it returns without calling `sub_E201BC`, and
+if set it can call that helper. A direct signed-helper synthetic
+control before/after the failed `0x105A(3)` call reached a **stubbed**
+`sub_E201BC` only after the bit was set. It did not execute a natural
+`0x1076`/RAP caller, the real consumer action, or any hardware.
+
+Signed `sub_E0E538` can derive `0xE26164` from a loaded image field
+at `+272`; its accepted live image/source and state transition have
+not been established. Isolated init's `0x100` gate blocks the
+finding. No real command failure, active consumer, cross-client
+impact or exact card restoration oracle is shown. Do not force
+SYS_DRV bringup/firmware mode on the card for a status code.
diff --git a/fw/LEAD-GCP-SYSDRV-106C-ZERO-ROUNDING-STATUS.md b/fw/LEAD-GCP-SYSDRV-106C-ZERO-ROUNDING-STATUS.md
new file mode 100644
index 0000000..d03ce4c
--- /dev/null
+++ b/fw/LEAD-GCP-SYSDRV-106C-ZERO-ROUNDING-STATUS.md
@@ -0,0 +1,33 @@
+# Free SYS_DRV `.54` `0x106C`: wrapped length is the only successful zero-used branch
+
+**Signed arithmetic/semantics lead, not a claimed memory allocation or
+live security impact.** The dispatcher calls `sub_E024C8(msg+14,
+msg+15,msg[16])`. The raw signed instructions at `0xE024DA..F2`
+compute `rounded = ((msg[16]+0xFFF)&~0xFFF)+0x1000` in **32 bits**,
+then branch to an error if `(used+rounded)|rounded` is nonzero.
+Accordingly, with a nonzero private pool base at `0xE5FE84/88`,
+that success branch requires both `rounded==0` and the private
+`0xE25790` used counter to be zero. The wrapped-zero input interval
+is `0xFFFFE001..0xFFFFF000` inclusive. Ordinary small nonzero lengths
+return `0xFFFF000C`; inputs immediately below/above that interval
+also return `0xFFFF000C` under the same state. On success the leaf
+returns two inline address words and adds **zero** to the used counter.
+Two identical requests can therefore return the same output with no
+reservation progress. Calling this an allocator that has allocated
+4 GiB or a controlled write would be incorrect; a special sentinel
+protocol is not ruled out.
+
+`psp_emu/harness/probe_sysdrv_106c_length_wrap.py` passed against the
+signed `.54` dispatcher/leaf. Default emulator init provided a nonzero
+base and zero used counter and returned success for the wrapped
+`0xFFFFF000` length; unrelated init SVCs default to success, so those
+values are **not live-card measurements**. The test separately planted
+and restored a private pool base/counter, verified ordinary and two
+boundary-error controls, and observed repeated same-result/zero-used
+success for wrapped requests. Setting the synthetic used counter to 1
+made the wrapped request fail. It did not map or write a host address.
+
+A scoped extracted-client immediate/aligned-literal scan found no
+direct `0x106C` callsite. Computed clients, intended sentinel
+semantics, actual card pool provenance, and impact remain unverified.
+No hardware request was made.
diff --git a/fw/LEAD-GCP-SYSDRV-1076-RAP-GLOBAL-STATE-RESET.md b/fw/LEAD-GCP-SYSDRV-1076-RAP-GLOBAL-STATE-RESET.md
new file mode 100644
index 0000000..b6926ba
--- /dev/null
+++ b/fw/LEAD-GCP-SYSDRV-1076-RAP-GLOBAL-STATE-RESET.md
@@ -0,0 +1,60 @@
+# Free SYS_DRV `.54` `0x1076(1)`: global RAP-record reset, not just short output
+
+**Conditional cross-client integrity/availability lead.** Signed code and
+an existing synthetic-dispatch test show table clearing; signed RAP
+`.19` is a natural client of this service. There is no live concurrent
+RAP record, active-build proof, host-triggered victim effect or exact
+restoration oracle. **Do not** issue this reset on hardware merely for
+a return value.
+
+`sub_E105A8` dispatches free `0x1076` to `sub_E2005C(msg[2])`. When the
+first dword of that caller buffer is **1**, the signed leaf zeros 24
+caller-output bytes at `+28..+51`, then clears **2048 bytes** of the
+SYS_DRV-private 128×16-byte table at `0xE6873C`; it resets adjacent
+bookkeeping halfwords and updates a global status via `sub_E1A22C`.
+There is no owner or RAP-caller comparison before these changes. The
+caller pointer still faces a declared-length role check; that role is
+**not** an owner check. The separate short-output mismatch for a
+four-byte declaration is demonstrated in
+`psp_emu/harness/probe_sysdrv_1076_dispatch.py`; its signed synthetic
+run also planted a table entry and observed it cleared on mode 1.
+Emulator initialization used several unrelated default-success SVCs.
+
+The exact signed-image references to the table base `0xE6873C` include:
+
+- `sub_E0D60C`: adds or updates 16-byte records indexed by a 32-bit key
+ at entry `+4` (128 slots, tracks high index).
+- `sub_E16128`: removes records by that key.
+- `sub_E0AB74` (free `0x107B`): copies record fields to its caller,
+ then clears the entire table and counters. This is a separate
+ stateful clear and has its own short-output candidate. Its signed
+ multi-record output overwrites the same four output fields on each
+ entry, returning only the last; whether that is intentional summary
+ semantics remains open (`fw/LEAD-SYSDRV-107B-MULTI-RECORD-SNAPSHOT-LOSS.md`).
+- `sub_E2005C`: the mode-1 reset above.
+
+The first two helpers are called from deeper `0x1076` selector handlers,
+so a blanket statement that the cleared bytes have no consumer is
+incorrect. This exact-base inventory does not exclude aliases or
+indirect consumers.
+
+**Signed-client provenance:** RAP `.19` wrapper
+`rap_sysdrv_rpc_1076` (`0x4010AC`) constructs a service-**1**
+`SVC 0xF2` request with opcode `0x1076`, a 52-byte caller buffer, and
+returns its result. `rap_cmd02` (`0x40160C`) calls that wrapper after
+placing selector **1** in its local request at `0x40162E..0x401634`,
+then issues selector 10 and later other selectors/`0x107B` on gated
+paths. `rap_TA_InvokeCommandEntryPoint` passes its host command ID into
+`rap_dispatch`, which routes several command/state combinations through
+`rap_cmd02`. The selector-1 call requires RAP's own flag at
+`0x403000` nonzero and incoming argument `R1==1`; host feasibility and
+live build/ownership remain unmeasured. An older fault-oracle sweep
+reported **RAP cmd 2** hanging for malformed host `+4=0xFFFFFFFF`;
+that does not authenticate or justify reproducing a normal selector-1
+sequence on the card.
+
+GCP's service-1 RPC access is demonstrated with other opcodes, not a
+live `0x1076` reset. The table may be RAP-specific management state,
+so cross-client *impact* requires an independently observed live RAP
+record and safe, exact restoration—not a synthetic caller identity or
+return code.
diff --git a/fw/LEAD-GCP-SYSDRV-1079-CHOSEN-FIXED-FABRIC-WORD.md b/fw/LEAD-GCP-SYSDRV-1079-CHOSEN-FIXED-FABRIC-WORD.md
new file mode 100644
index 0000000..de402b0
--- /dev/null
+++ b/fw/LEAD-GCP-SYSDRV-1079-CHOSEN-FIXED-FABRIC-WORD.md
@@ -0,0 +1,104 @@
+# Free SYS_DRV `.54` `0x1079`: chosen value to fixed fabric address
+
+**Signed conditional fabric-write path; a matched card experiment now
+shows ASD `0x403` adds a separately observed `+8` to the PMI3 write
+pointer. Host MMIO produces the same `+8`, so no incremental authority or
+security consequence is established.** The
+historical overview calls `0x1079` a tiny/query getter. Signed
+`sub_E105A8` case 4217 passes inline `msg[14]` to `sub_E1939C`
+and returns zero without using the helper result. Raw
+`0xE1939C..E193B4` excludes values whose **top byte is `0xEE` or
+`0xEF`**, then passes the remaining caller-chosen 32-bit value as
+R1 with fixed R0=`0x03B30600` to `sub_E154A0`. If private
+dword **`0xE26314`** is nonzero, this helper invokes
+**`SVC 0x7C` with width 4**. This is a fixed fabric address,
+not an arbitrary CPU-MMU write or caller-selected fabric address.
+The signed ELF initializes the gate word to **2**; isolated signed
+SYS_DRV init preserved that value. Its identified direct setter is
+high opcode `0x3131`, a separate privileged ACL range.
+
+`psp_emu/harness/probe_sysdrv_1079_fixed_write_gate.py` passed.
+It replaces **SVC 0x7C with capture**, not a hardware write; it also
+uses **synthetic** SVC `0x76` capability profiles. With restricted
+mask `0x10` and the **unplanted** post-init gate 2, signed `0x1079`
+with `0x12345678` requested `(0x03B30600,0x12345678,4)` and
+returned zero. Top-byte `0xEE`/`0xEF` requests did not reach the
+SVC. The same restricted profile rejected signed `0x3131` with
+`0xFFFF0001`; a *synthetic privileged* `0xFFFF0` profile could
+set the gate to zero, suppress the free path, then restore the
+original 2. The emulator's ordinary `SVC 0x76` handler always
+claims success and **cannot establish GCP's real `0x3131` rights**.
+Signed sOS `.54` `SVC 0x76` case 37 checks the supplied mask
+against a per-process capability table, while SYS_DRV's signed ACL
+requires mask `0xFFFF0` for `0x3100..0x31FF` (including `0x3131`)
+versus its fallback `0x10` for `0x1079`. The signed SVC `0x8E`
+grant route additionally requires the current process descriptor
+byte to equal 1, not a GCP-selected RPC scalar. Shared `0x31xx`
+mask and prior direct GCP `0x3105` rejection argue against direct
+GCP `0x3131` setter access; see
+`fw/AUDIT-SOS54-SVC76-8E-CAPABILITY-FLOW.md`.
+
+**Signed producer now identified:** ASD `.163` service-2 `0x208`
+packs `msg[1]` into a fixed service-1 `0x1079` request via
+`SVC 0xF2`. A connected signed-dispatch model captured the packed
+request and fixed `SVC 0x7C` endpoint without executing fabric;
+the top-byte `0xEE/0xEF` filter corresponds to the **low byte** of
+ASD's input word. See
+`fw/AUDIT-ASD-163-208-SYSDRV-1079-FORWARD.md`. This supports an
+intended event/log producer, not an arbitrary-address primitive or
+independent GCP authority gain.
+
+A Navi22 register list (`~/nv22_a0_memmap.txt`) calls numeric
+`0x03B30600` `MP_MP1MMU.MP1_PMI_3`, with `PMI_3_STATUS`,
+`PMI_3_READ_POINTER` and `PMI_3_WRITE_POINTER` at `+4/+8/+12`.
+**New Navi31-specific corroboration:** the signed SMU13 Xtensa runtime ELF
+`psp_out/smu_fw/smu_13_0_0_xtensa.elf` contains exact dword
+`0x03B30600` at mapped VA `0x9950` (file offset `0xA950`) in a
+four-address table with `0x03B10A0C`, `0x03B10A4C` and `0x03B10A6C`.
+The Navi22 list names those neighbors `MP1_C2PMSG_67/83/91`, matching an
+MP1 mailbox/event configuration; an unannotated Xtensa IDB showed no
+xref to the table, so the runtime consumer and exact Navi31 PMI3 register
+semantics remain unresolved. This supports a Navi31 numeric-address
+identity far better than the Navi22 name alone, **not evidence of a
+copy-engine command or useful target effect**. The FE0A comparator
+REJECT path's three fixed GCP error words, after signed ASD packing,
+would request `0xE303F000`, `0xE3030000`, `0xE3030100` here when the
+gates hold; see `fw/LEAD-GCP-PARAMS-VA-NONROP-DISCRIMINATOR.md`.
+
+**Bounded host-only readback on the RX 7900 XTX (new):** standard
+`PCIE_INDEX2/DATA2` host-SMN reads of the three proposed *adjacent*
+registers gave `0x03B30604` **status 0** twice,
+`0x03B30608` **`0x00040000`** and `0x03B3060C` **`0x00040400`**.
+Interleaved bogus `0x0FEEDC00` gave the expected mirror `0x00DCEE0F`
+before/after, while live MP0 `0x03810ACC` gave `0x80000000` before/after.
+This establishes a host readback for *adjacent numeric words*, not their
+full Navi31 field semantics. The value register `0x03B30600` was **not**
+read or written from the host.
+
+**Signed diagnostic positive control (card, not ASD `0x403`):**
+`hw/gcp_pmi3_signed_event_control.py` was run once with ASD already loaded
+(`/root/psp/hw/gcp_pmi3_signed_event_control.log`). GCP `.77` load, FE07,
+FE08, FE09, accepted in-buffer FE0A selector **11** (`0x241`), and GCP unload
+all returned zero. After FE09 and immediately **before** FE0A, independent
+host-SMN reads showed candidate status/rptr/wptr
+`(0, 0x00040000, 0x00040448)`; immediately **after** FE0A and *before*
+unload they were `(0, 0x00040000, 0x00040470)`—**wptr advanced by
+`0x28`**. MP0 live control remained `0x80000000` and bogus-address mirror
+`0x00DCEE0F` before/after. The signed FE0A error path routes three
+ASD `0x208` → SYS_DRV `0x1079` requests to this numeric endpoint;
+this experiment correlates the signed event with a decoded adjacent
+hardware change. It does **not** isolate which inner request advanced
+wptr, prove SMU consumed the events or show any `0x403` effect.
+
+**Follow-up `0x403` experiment:** see
+`fw/EVAL-GCP-ASD403-MP1-PMI3-EVENT-QUEUE.md`. With a fresh-boot,
+source-word-calibrated SID-1 GCP→ASD ROP, matched width-zero and width-four
+runs used the same natural `0xE3030100` word and identical host preimage
+wptr `0x403B0`: width 0 returned ASD status 2 and advanced the independent
+host-SMN wptr **`+0x28`**; width 4 returned ASD status 0 and advanced it
+**`+0x30`**. The extra **`+8`** is a non-scratch hardware effect associated
+with the ASD fabric store. A later fresh-boot *host* SMN write of this word
+also advanced wptr **`+8`**, disproving a PSP-only advantage for this
+specific event. The SMU consumer, event payload, chosen-word difference and
+security consequence remain unknown. Do not infer impact from handler
+status or pointer occupancy alone.
diff --git a/fw/LEAD-GCP-SYSDRV-1097-GLOBAL-WAIT-MODE.md b/fw/LEAD-GCP-SYSDRV-1097-GLOBAL-WAIT-MODE.md
new file mode 100644
index 0000000..546537f
--- /dev/null
+++ b/fw/LEAD-GCP-SYSDRV-1097-GLOBAL-WAIT-MODE.md
@@ -0,0 +1,31 @@
+# Free SYS_DRV `.54` `0x1097`: caller-settable global wait-mode flag
+
+**Signed global-state authority lead; no live other-client delay or
+security impact demonstrated.** Free dispatcher case `0x1097`
+passes `msg[14]` to `sub_E18CE0`, which stores the unrestricted dword
+at SYS_DRV-private `0xE26648` and returns zero. There is no caller
+identity comparison in the examined setter, and another `0x1097`
+request can set the value back to zero (assuming the same signed path
+and live accessibility). **Free `0x1096 → sub_E0B480` reads the exact
+same dword into inline `msg[14]`.**
+`psp_emu/harness/probe_sysdrv_1097_wait_flag.py` passed on signed
+`.54` dispatch: default emulator init left the flag zero; signed
+`0x1096` observed the initial value, values 1 and `0xFFFFFFFF` after
+signed `0x1097` writes, and the original value after restoration via
+signed `0x1097`. It also checked the modeled private dword. Unrelated
+initialization SVCs may default to success. This supplies a **signed
+software getter and modeled restoration check**, not a verified
+live-card restoration oracle or independently measured scheduler
+effect.
+
+Two signed consumers use the **Boolean nonzero** state. In
+`sub_E19D14`, raw instructions `0xE19DB2..E19DC2` select `SVC 0x56`
+argument `0x32` instead of `0x0A` after a completed transfer step.
+`sub_E1A0A4` also issues an extra `SVC 0x56` in a successful
+nonterminal transfer iteration if the flag is nonzero. Signed sOS
+`.54` routes `SVC 0x56` (case `86-81=5`) through the scheduler
+handlers, but units, concurrency and any aggregate latency were not
+measured. Both consumers act on shared SYS_DRV state; this does not
+establish another client is simultaneously waiting or that a timing
+option is an unintended authority bypass. No real mailbox/flash
+transfer, unlimited wait, or card request was performed.
diff --git a/fw/LEAD-GCP-SYSDRV-10A2-LABEL-PREVALIDATION-READ.md b/fw/LEAD-GCP-SYSDRV-10A2-LABEL-PREVALIDATION-READ.md
new file mode 100644
index 0000000..c8f1f7b
--- /dev/null
+++ b/fw/LEAD-GCP-SYSDRV-10A2-LABEL-PREVALIDATION-READ.md
@@ -0,0 +1,38 @@
+# Free SYS_DRV `.54` `0x10A2`: caller label strlen beyond declared input span, behind crypto gate
+
+**Conditional signed-code span lead, not a live disclosure or reached
+signed-dispatch overread.** The role row `{0x10A2,1,1,2,0}` at
+`0xE25D28` validates request `(msg[2],msg[3])` as input,
+`(msg[4],msg[5])` as a second input and `(msg[6],msg[7])` as output.
+The signed dispatcher copies the **pointer** `msg[2]` into its
+`msg[15]` scratch slot, then calls `sub_E11C20(msg+14)`. After
+`sub_E07B80` succeeds, `sub_E11C20` calls `sub_E07A80` with that
+pointer as its optional label. `sub_E07A80` calls signed
+`sub_E01864` (unbounded word-optimized `strlen`) on it **before**
+checking `(strlen+5)<=0x80`; it does not receive or enforce the
+original declared `msg[3]`. A four-byte declaration therefore does
+not bound this string read if the crypto gate is satisfiable. Unlike
+the fixed signed label in free `0x100D`, this label is caller-provided.
+The KDF's later output loop is separately bounded by its declared
+length; this lead concerns the input string read only.
+
+`psp_emu/harness/probe_sysdrv_10a2_label_reach.py` attempted a
+signed-dispatch request with a four-byte declared label and a NUL at
+synthetic `label+8`. **Unhooked emulation faulted first** at signed
+copy PC `0xE01940`, FAR `0x680`, before reaching label `strlen`. A raw-copy
+entry hook captured caller LR `0xE146E5`, source `0xE23050` and
+32-byte destination `0x680` (advanced source `0xE23060` at fault). Signed `sub_E146A0` at `0xE146DA..E0`
+loads the shared crypto base from `0xE257D8`, adds `0x680` and calls
+`sub_E018A0`; the emulator base is zero at this point. Thus the
+fault belongs to **synthetic missing crypto-base initialization**, not
+the caller label. It is not evidence of a live GPU fault, of a label
+overread, or of a successful CCP/KDF operation; emulator initialization
+has unrelated default-success SVCs. No crypto bytes were printed. The
+signed-helper data flow and raw `strlen` establish the conditional
+source-to-read gap, while natural gate completion, real PTEs and any
+security effect remain open. No card request was issued.
+
+A historical overview incorrectly grouped `0x109C..0x10A2` as
+stubs. `0x10A2` is a real crypto wrapper; `0x109C`, `0x109D` and
+`0x109E` also dispatch real leaves. The inventory has been corrected
+without claiming those other paths are exhaustively safe.
diff --git a/fw/LEAD-OPM51-CMD11-GLOBAL-MODE-FLAG.md b/fw/LEAD-OPM51-CMD11-GLOBAL-MODE-FLAG.md
new file mode 100644
index 0000000..4130bde
--- /dev/null
+++ b/fw/LEAD-OPM51-CMD11-GLOBAL-MODE-FLAG.md
@@ -0,0 +1,36 @@
+# Signed OPM `.51` host cmd 11 sets a global mode before ASD status gate
+
+**Status:** signed host-command/state lead, not an established
+post-GCP cross-client exploit. Do **not** invoke cmd 11 on hardware:
+`fw/REPORT-TA-FAULT-ORACLE-SWEEP.md` reports an OPM cmd-11 hang for
+one host profile, with ring timeout requiring recovery. No live flag
+readback or exact restoration oracle exists.
+
+`opm_TA_InvokeCommandEntryPoint` (`0x402AE4`) requires param0 type-7,
+a nonnull host buffer, and declared length `>=0x3D54`. For cmd ID 11,
+raw `0x402B06..0x402B12` copies host buffer dword `+0x10` to OPM-global
+`0x418F84` and returns success **without** taking the adjacent
+`opm_asd_rpc_304` status check applied to other command IDs. This is
+an unbounded scalar *value* store to a fixed OPM-private dword, not an
+arbitrary-address write. The entry's output/status fields are also
+written in the normal completion path.
+
+`python3 psp_emu/harness/probe_opm51_cmd11_global_flag.py` executes the
+signed `.51` entry with a **synthetic** OPM TA map/host memref. A
+`0x3D53` declared length returned `0xFFFF0010` without changing a
+seeded global; a `0x3D54` length copied host scalar `0x12345678` to
+`0x418F84` and returned zero. No ASD/SYS_DRV service call, ASIC,
+card, or real OPM loader was exercised.
+
+The only exact signed-image base-literal references to `0x418F84` are
+this writer and a read at `0x401BFC` in
+`opm_TA_InvokeCommandEntryPoint__h3` (`0x401910`). The reader checks
+this global only in a branch that **already** passed
+`opm_asd_rpc_102()==0` and `(a1.unk00 & 2)!=0`, where it ORs
+`0x28` instead of `0x08` into an output word. That narrows the
+potential effect: the cmd-11 flag does **not** independently make the
+ASD `0x102` check succeed on this examined path. Whether cmd 11 is
+intended host-controlled configuration, whether those output bits
+influence protected content/session policy, active OPM build, and any
+post-GCP path to that host command remain open. Do not classify this
+as an authentication bypass or new hardware impact.
diff --git a/fw/LEAD-SYSDRV-107B-MULTI-RECORD-SNAPSHOT-LOSS.md b/fw/LEAD-SYSDRV-107B-MULTI-RECORD-SNAPSHOT-LOSS.md
new file mode 100644
index 0000000..c322cb4
--- /dev/null
+++ b/fw/LEAD-SYSDRV-107B-MULTI-RECORD-SNAPSHOT-LOSS.md
@@ -0,0 +1,34 @@
+# SYS_DRV `.54` `0x107B`: multi-record snapshot is lossy
+
+**Signed-code behavior, not yet a vulnerability claim.** `sub_E0AB74`
+loops through the populated high-water index of the 128×16-byte
+table at `0xE6873C`. For every entry with nonzero key at `+4`, it
+overwrites the *same four* caller-output dwords `+36..+48`. After
+writing a total count at `+28` and a remaining count at `+32`, it
+clears all 2048 table bytes and bookkeeping. Thus, if two entries
+exist, only the last record's four fields survive in the 52-byte
+caller buffer; there is no subsequent retrieval of the first record
+from that cleared table.
+
+`psp_emu/harness/probe_sysdrv_107b_multi_record_loss.py` invokes the
+unchanged signed `.54` dispatcher with a full 52-byte declaration.
+Synthetic one-record and two-record controls call the **signed**
+`sub_E0D60C` insertion helper with synthetic keys and values, set the
+header's count as its natural callers do, then invoke signed `0x107B`.
+Both return zero and clear the table; the two-record output reports
+count 2 / remaining 0 but contains only the second record's key and
+fields. This does not run the natural RAP/ASIC producers; SYS_DRV
+initialization uses default-success handlers for unrelated SVCs. It neither proves naturally concurrent
+entries nor models a real sOS/GCP call.
+
+Signed RAP `.19` invokes service-1 `0x107B` from `rap_cmd02` at
+`0x4016B6`, then copies the returned summary onward. Deeper signed
+`0x1076` selectors call `sub_E0D60C` to add/update table records by
+key and `sub_E16128` to remove them; some of these helpers collect
+register-operation results. A count plus final entry **may be an
+intentional aggregate report**, rather than a request to enumerate all
+entries. The RAP protocol's expected semantics, occurrence of multiple
+simultaneous keys, loss of a meaningful failure, active build and live
+victim remain open. The independently observed short-output mismatch
+for `0x107B` is in `fw/CANDIDATE-GCP-SYSDRV-107B-SHORT-OUTPUT.md`.
+No state-changing hardware test is warranted on this evidence.
diff --git a/fw/scan_rpc_opcode_immediates.py b/fw/scan_rpc_opcode_immediates.py
new file mode 100644
index 0000000..1a1ce12
--- /dev/null
+++ b/fw/scan_rpc_opcode_immediates.py
@@ -0,0 +1,76 @@
+#!/usr/bin/env python3
+"""Candidate direct service-RPC opcode immediates in extracted signed ELF code.
+
+This halfword-resynchronizing Thumb-2 candidate scan is NOT a control-flow
+proof: inline data and instruction interiors can yield false positives, and
+computed opcodes or literal-pool loads can be missed. Immediate hits are
+NOT necessarily opcodes: HDCP .52 has `MOVW #0x20B` for a 523-byte message
+length comparison at 0x402798, not an ASD RPC. Inspect reported sites in
+IDA and trace requests before assigning producer/caller provenance.
+"""
+from __future__ import annotations
+
+import argparse
+import struct
+from pathlib import Path
+
+from capstone import CS_ARCH_ARM, CS_MODE_THUMB, Cs
+from capstone.arm import ARM_OP_IMM
+
+DEFAULT_OPCODE = 0x3105
+
+
+def executable_spans(path: Path):
+ image = path.read_bytes()
+ if len(image) < 52 or image[:5] != b'\x7fELF\x01' or image[5] != 1:
+ return []
+ phoff = struct.unpack_from('<I', image, 28)[0]
+ entsize, count = struct.unpack_from('<HH', image, 42)
+ spans = []
+ for i in range(count):
+ at = phoff + i * entsize
+ if at + 32 > len(image):
+ break
+ kind, off, va, _, filesz, _, flags, _ = struct.unpack_from('<8I', image, at)
+ if kind == 1 and flags & 1 and off + filesz <= len(image):
+ spans.append((va, image[off:off+filesz]))
+ return spans
+
+
+def main() -> int:
+ ap = argparse.ArgumentParser(description=__doc__)
+ ap.add_argument('paths', type=Path, nargs='+')
+ ap.add_argument('--opcode', type=lambda v: int(v, 0), default=DEFAULT_OPCODE,
+ help='unsigned 32-bit opcode (default 0x3105)')
+ ap.add_argument('--literals', action='store_true',
+ help='also list aligned executable-span words equal to opcode')
+ args = ap.parse_args()
+ opcode = args.opcode
+ if not (0x100 <= opcode <= 0xffffffff):
+ ap.error('opcode must fit 32 bits and exceed a Thumb movs immediate')
+ files = sorted({f for p in args.paths for f in ([p] if p.is_file() else p.rglob('*.elf'))})
+ md = Cs(CS_ARCH_ARM, CS_MODE_THUMB)
+ md.detail = True
+ for file in files:
+ for va, data in executable_spans(file):
+ # These opcodes cannot fit a 16-bit Thumb mov-imm. Try 32-bit
+ # prefixes at *each* halfword, so invalid instructions
+ # cannot truncate the scan. Candidate alignment still needs IDA.
+ for off in range((-va) & 1, len(data) - 3, 2):
+ if data[off+1] < 0xE8:
+ continue
+ ins = next(md.disasm(data[off:off+4], va+off, count=1), None)
+ if ins and ins.size == 4 and ins.mnemonic in (
+ 'mov', 'movs', 'movw', 'mvn', 'addw', 'subw'
+ ) and any(o.type == ARM_OP_IMM and (o.imm & 0xffffffff) == opcode
+ for o in ins.operands):
+ print(f'{file}\t0x{ins.address:x}\t{ins.mnemonic} {ins.op_str}')
+ if args.literals:
+ for off in range((-va) & 3, len(data) - 3, 4):
+ if struct.unpack_from('<I', data, off)[0] == opcode:
+ print(f'{file}\t0x{va+off:x}\taligned literal 0x{opcode:x} (xref unverified)')
+ return 0
+
+
+if __name__ == '__main__':
+ raise SystemExit(main())
diff --git a/fw/scan_service_registrations.py b/fw/scan_service_registrations.py
new file mode 100644
index 0000000..1aeaeb1
--- /dev/null
+++ b/fw/scan_service_registrations.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python3
+"""List SVC #0x74 candidates and driver-ID property TLVs in signed ELFs.
+
+The SVC scan is limited to halfword-aligned executable ELF segments but is
+NOT a CFG disassembly: Thumb-2 second halfwords and data can collide. Validate
+every hit in disassembly before attributing service slots. Property TLVs are
+matched by the exact short header (length/type/name length/value length).
+"""
+from __future__ import annotations
+
+import argparse
+import struct
+from pathlib import Path
+
+SVC74 = b'\x74\xdf'
+DRIVER_PROP = b'amd.dr.driverID\0'
+DRIVER_HEADER = bytes((4 + len(DRIVER_PROP) + 4, 1, len(DRIVER_PROP), 4))
+
+
+def load_spans(path: Path):
+ image = path.read_bytes()
+ if len(image) < 52 or image[:5] != b'\x7fELF\x01' or image[5] != 1:
+ return []
+ phoff = struct.unpack_from('<I', image, 28)[0]
+ entsize, count = struct.unpack_from('<HH', image, 42)
+ spans = []
+ for i in range(count):
+ pos = phoff + entsize * i
+ if pos + 32 > len(image):
+ break
+ kind, offset, va, _, filesz, _, flags, _ = struct.unpack_from('<8I', image, pos)
+ if kind != 1 or not flags & 1 or offset + filesz > len(image):
+ continue
+ spans.append((va, offset, image[offset:offset + filesz]))
+ return spans
+
+
+def main() -> int:
+ ap = argparse.ArgumentParser(description=__doc__)
+ ap.add_argument('paths', type=Path, nargs='+', help='ELF files or trees')
+ args = ap.parse_args()
+ paths = sorted({f for p in args.paths for f in ([p] if p.is_file() else p.rglob('*.elf'))})
+ for path in paths:
+ image = path.read_bytes()
+ for va, file_off, data in load_spans(path):
+ for i in range((-va) & 1, len(data) - 1, 2):
+ if data[i:i+2] == SVC74:
+ print(f'{path}\tsvc74-candidate va=0x{va+i:x}\tfile_off=0x{file_off+i:x}')
+ pos = image.find(DRIVER_PROP)
+ while pos >= 0:
+ end = pos + len(DRIVER_PROP)
+ if image[pos-4:pos] == DRIVER_HEADER and end + 4 <= len(image):
+ value = struct.unpack_from('<I', image, end)[0]
+ print(f'{path}\tdriver-id={value}\tfile_off=0x{pos:x}')
+ pos = image.find(DRIVER_PROP, pos + 1)
+ return 0
+
+
+if __name__ == '__main__':
+ raise SystemExit(main())
diff --git a/fw/verify_gcp_loggates_fault.py b/fw/verify_gcp_loggates_fault.py
new file mode 100644
index 0000000..05a376e
--- /dev/null
+++ b/fw/verify_gcp_loggates_fault.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python3
+"""Offline check of preserved log-gate fault frame against signed GCP .77.
+
+No hardware access. This identifies word2 as the faulting instruction; word0
+is a known build-specific constant, not the program counter of this fault.
+"""
+from pathlib import Path
+import struct
+
+from capstone import CS_ARCH_ARM, CS_MODE_ARM, Cs
+
+ELF = Path(__file__).resolve().parents[1] / 'psp_out/versions_win/elf_all/gcp_22.0.0.77_7c426e7f.elf'
+FRAME = (0x4055D8, 0x25031016, 0x4011D8, 0x867, 0x42CFA0, 0, 0x8DA7463D)
+
+
+def file_offset(image: bytes, va: int) -> int:
+ assert image[:6] == b'\x7fELF\x01\x01'
+ phoff = struct.unpack_from('<I', image, 28)[0]
+ size, count = struct.unpack_from('<HH', image, 42)
+ for i in range(count):
+ typ, off, base, _, length, _, flags, _ = struct.unpack_from(
+ '<8I', image, phoff + size * i)
+ if typ == 1 and flags & 1 and base <= va < base + length:
+ return off + va - base
+ raise ValueError(f'VA 0x{va:x} is not in an executable file-backed PT_LOAD')
+
+
+def main() -> None:
+ image = ELF.read_bytes()
+ pc, fsr, far = FRAME[2:5]
+ off = file_offset(image, pc)
+ ins = next(Cs(CS_ARCH_ARM, CS_MODE_ARM).disasm(image[off:off+4], pc, count=1))
+ assert (ins.address, ins.mnemonic, ins.op_str) == (
+ pc, 'stmmi', 'r0!, {r3, r4}'), (hex(ins.address), ins.mnemonic, ins.op_str)
+ status = (fsr & 0xf) | (((fsr >> 10) & 1) << 4)
+ assert status == 7 and fsr & (1 << 11) and far == 0x42CFA0
+ print(f'word2=0x{pc:08x}: {ins.mnemonic} {ins.op_str}; '
+ f'DFSR FS={status} (translation), write=1, FAR=0x{far:08x}')
+ print(f'word0=0x{FRAME[0]:08x}: build constant, NOT this faulting PC')
+
+
+if __name__ == '__main__':
+ main()
diff --git a/fw/verify_gcp_loggates_memcpy_path.py b/fw/verify_gcp_loggates_memcpy_path.py
new file mode 100644
index 0000000..aee47a4
--- /dev/null
+++ b/fw/verify_gcp_loggates_memcpy_path.py
@@ -0,0 +1,118 @@
+#!/usr/bin/env python3
+"""Offline constraint on the GCP .77 memcpy fault in the log-gate attempt.
+
+Checks signed ARM instructions and the two literal planned copy spans. This
+EXCLUDES an intact planned copy from the observed conditional store, but does
+NOT reconstruct the actual caller/registers or authorize a hardware retry.
+"""
+from __future__ import annotations
+
+import ast
+import argparse
+import struct
+from pathlib import Path
+
+from capstone import Cs, CS_ARCH_ARM, CS_MODE_ARM, CS_MODE_THUMB
+
+ELF = Path(__file__).resolve().parents[1] / 'psp_out/versions_win/elf_all/gcp_22.0.0.77_7c426e7f.elf'
+FRAME_PC, FRAME_FAR = 0x4011D8, 0x42CFA0
+
+
+def executable_offset(data: bytes, va: int) -> int:
+ assert data[:6] == b'\x7fELF\x01\x01'
+ phoff = struct.unpack_from('<I', data, 28)[0]
+ entsize, count = struct.unpack_from('<HH', data, 42)
+ for i in range(count):
+ typ, off, base, _, size, _, flags, _ = struct.unpack_from('<8I', data, phoff+entsize*i)
+ if typ == 1 and flags & 1 and base <= va < base+size:
+ return off+va-base
+ raise ValueError(hex(va))
+
+
+def literals(path: Path) -> dict[str, int]:
+ # AST only: NEVER import/execute the host/card probe.
+ body = ast.parse(path.read_text()).body
+ out: dict[str, int] = {}
+ def value(node: ast.expr) -> int:
+ if isinstance(node, ast.Constant) and type(node.value) is int:
+ return node.value
+ if isinstance(node, ast.Name):
+ return out[node.id]
+ if isinstance(node, ast.BinOp) and isinstance(node.op, ast.Add):
+ return value(node.left)+value(node.right)
+ if isinstance(node, ast.BinOp) and isinstance(node.op, ast.Sub):
+ return value(node.left)-value(node.right)
+ raise ValueError(f'unsupported literal expression: {ast.dump(node)}')
+ wanted = {'PARAMS','STACK_DST','SRC_OFF','MLEN','DUMPDST','DUMPLEN','DUMP_OFF','MSGA_OFF','SLOT'}
+ for node in body:
+ if isinstance(node, ast.Assign) and len(node.targets)==1:
+ target=node.targets[0]
+ if isinstance(target, ast.Name) and target.id in wanted:
+ out[target.id] = value(node.value)
+ assert wanted <= out.keys(), wanted-out.keys()
+ # Bind the claimed two offsets to the actual top-level qcs invocation,
+ # not merely to constants with similar names elsewhere in the script.
+ qcs_def=next(n for n in body if isinstance(n,ast.FunctionDef) and n.name=='qcs')
+ calls=[n for n in ast.walk(ast.Module(body=body,type_ignores=[]))
+ if isinstance(n,ast.Call) and isinstance(n.func,ast.Name) and n.func.id=='qcs']
+ assert len(calls)==1
+ args=calls[0].args
+ assert len(args)==3
+ for pos,expected in ((1,out['SLOT']-0x1c),(2,out['SLOT']-4)):
+ expr=args[pos]
+ assert isinstance(expr,ast.Call) and isinstance(expr.func,ast.Name) and expr.func.id=='disp'
+ assert value(expr.args[0])==expected
+ writes={}
+ for n in ast.walk(qcs_def):
+ if isinstance(n,ast.Call) and isinstance(n.func,ast.Attribute) and n.func.attr=='pack_into':
+ if len(n.args)>3 and isinstance(n.args[2],ast.Constant):
+ writes[n.args[2].value]=n.args[3]
+ assert 'dA' in ast.unparse(writes[0x840]) and 'dB' in ast.unparse(writes[0x838])
+ assert value(writes[0x81c])==0x40 # eight-byte selector-4 copies
+ return out
+
+
+def main() -> None:
+ ap=argparse.ArgumentParser(description=__doc__)
+ ap.add_argument('--probe',type=Path,default=Path('/tmp/gcp_rop_sysdrv_loggates_readonly.py'))
+ v=literals(ap.parse_args().probe)
+ image=ELF.read_bytes()
+ md=Cs(CS_ARCH_ARM, CS_MODE_ARM)
+ for ea,mnem in ((0x40111C,'cmp'),(0x401154,'beq'),(0x4011A8,'subs'),
+ (0x4011C8,'lsls'),(FRAME_PC,'stmmi')):
+ off=executable_offset(image,ea)
+ ins=next(md.disasm(image[off:off+4],ea,count=1))
+ assert ins.address==ea and ins.mnemonic==mnem,(hex(ea),ins.mnemonic)
+ planned=((v['STACK_DST'],v['PARAMS']+v['SRC_OFF'],v['MLEN']),
+ (v['DUMPDST'],v['STACK_DST']+v['DUMP_OFF'],v['DUMPLEN']))
+ for dest,src,length in planned:
+ assert dest%16==src%16==length%16==0,(hex(dest),hex(src),hex(length))
+ assert not (dest <= FRAME_FAR < dest+length)
+ print(f'planned copy dst=0x{dest:x} src=0x{src:x} len=0x{length:x}: '
+ 'aligned/16-multiple; cannot execute STMMI tail with intact arguments')
+ # FE0A selector 4 performs TWO 8-byte copies to a host-displaced R0.
+ # The first's nominal destination, unlike the two ROP copies above,
+ # differs from FAR by exactly a page-aligned 0x11000. At this length,
+ # ARM 0x40111C can enter 0x4011A4 and execute the STMMI tail.
+ thumb=Cs(CS_ARCH_ARM,CS_MODE_THUMB)
+ for ea,mnem in ((0x404D44,'add.w'),(0x404D4E,'blx'),
+ (0x404D52,'add.w'),(0x404D5C,'blx')):
+ off=executable_offset(image,ea)
+ ins=next(thumb.disasm(image[off:off+4],ea,count=1))
+ assert ins.address==ea and ins.mnemonic==mnem,(hex(ea),ins.mnemonic)
+ first=v['SLOT']-0x1C
+ second=v['SLOT']-4
+ delta=(FRAME_FAR-first)&0xffffffff
+ assert delta==0x11000 and (FRAME_FAR-second)&0xfff != 0
+ inferred_base=(v['PARAMS']+delta)&0xffffffff
+ print(f'selector-4 first 8-byte chosen-write nominal dst=0x{first:x}; '
+ f'FAR=0x{FRAME_FAR:x} implies params VA=0x{inferred_base:x} '
+ f'(old assumed 0x{v["PARAMS"]:x} + 0x{delta:x}).')
+ print('Second chosen-write would need a non-page-aligned base shift; '
+ 'first is a strong MATCH, not measured R0/R6 or proof of caller.')
+ print('The actual command-buffer VA must be verified independently; '
+ 'NO hardware retry authorized by this offline inference.')
+
+
+if __name__=='__main__':
+ main()
diff --git a/fw/verify_gcp_params_nonrop_discriminator.py b/fw/verify_gcp_params_nonrop_discriminator.py
new file mode 100644
index 0000000..a40b41d
--- /dev/null
+++ b/fw/verify_gcp_params_nonrop_discriminator.py
@@ -0,0 +1,109 @@
+#!/usr/bin/env python3
+"""Offline-only FE0A comparator discriminator for two proposed GCP params VAs.
+
+This DOES NOT measure a live command-buffer VA and MUST NOT be treated as
+permission to retry a hardware ROP chain. FE0A comparator REJECT (and
+accepted diagnostic selector 11) call an ASD→SYS_DRV fixed-fabric-write
+event path; this is NOT a read-only card probe.
+No device requests or keys are used.
+"""
+from __future__ import annotations
+
+import struct
+from pathlib import Path
+
+from capstone import Cs, CS_ARCH_ARM, CS_MODE_THUMB
+
+ELF = Path(__file__).resolve().parents[1] / 'psp_out/versions_win/elf_all/gcp_22.0.0.77_7c426e7f.elf'
+OLD_BASE = 0x04024000
+SHIFTED_BASE = 0x04035000 # fault-compatible HYPOTHESIS, not measured
+CODE_VA = 0x00404A74 # signed Thumb function prologue
+SECOND_CODE_VA = 0x00404A78 # unique follow-up word in signed ELF LOAD
+ZERO_VA = 0x00415A74 # zero bytes inside signed ELF LOAD
+COUNTER = 0x40000000
+
+
+def load_bytes(image: bytes, va: int, size: int) -> bytes:
+ assert image[:6] == b'\x7fELF\x01\x01'
+ phoff = struct.unpack_from('<I', image, 28)[0]
+ entsize, count = struct.unpack_from('<HH', image, 42)
+ for i in range(count):
+ typ, off, base, _, filesz, memsz, flags, _ = struct.unpack_from('<8I', image, phoff + entsize * i)
+ if typ == 1 and flags & 1 and base <= va and va + size <= base + filesz:
+ assert va + size <= base + memsz
+ return image[off + va - base:off + va - base + size]
+ raise ValueError(f'{va:#x} is not four initialized bytes in an executable LOAD')
+
+
+def main() -> None:
+ image = ELF.read_bytes()
+ thumb = Cs(CS_ARCH_ARM, CS_MODE_THUMB)
+ # FE0A pre-selector comparator: R1=params+0x10, R2=*(params+0x824),
+ # ADD R1,R2 then LDRB [R1,#4]! => target=params+0x14+R2.
+ for va, mnemonic in ((0x40483A, 'ldr.w'), (0x40484C, 'ldm.w'),
+ (0x40486E, 'add'), (0x404870, 'ldrb.w'),
+ (0x404886, 'ldrd.w'), (0x40488A, 'subs'),
+ (0x404890, 'bhs')):
+ ins = next(thumb.disasm(load_bytes(image, va, 4), va, count=1))
+ assert ins.address == va and ins.mnemonic.split('.')[0] == mnemonic.split('.')[0], (hex(va), ins.mnemonic)
+ # FE0A REJECT is not passive: GCP invokes its signed error emitter 3x.
+ # That wrapper's ASD 0x208 → SYS_DRV 0x1079 path can request a fixed
+ # fabric write at 0x03B30600; no card-side endpoint effect is known.
+ for va, mnemonic in ((0x40490A, 'ldr'), (0x404912, 'blx'),
+ (0x404918, 'blx'), (0x404924, 'blx')):
+ ins = next(thumb.disasm(load_bytes(image, va, 4), va, count=1))
+ assert ins.address == va and ins.mnemonic == mnemonic, (hex(va), ins.mnemonic)
+ prologue = next(thumb.disasm(load_bytes(image, CODE_VA, 4), CODE_VA, count=1))
+ assert prologue.mnemonic == 'push'
+ code_word = struct.unpack('<I', load_bytes(image, CODE_VA, 4))[0]
+ zero_word = struct.unpack('<I', load_bytes(image, ZERO_VA, 4))[0]
+ second = struct.unpack('<I', load_bytes(image, SECOND_CODE_VA, 4))[0]
+ assert code_word == 0x460DB5B0 and second == 0x4604A121 and zero_word == 0
+ assert image.count(struct.pack('<I', second)) == 1, 'second word must identify one ELF position'
+ assert load_bytes(image, ZERO_VA + 4, 4) == bytes(4)
+ assert zero_word < COUNTER < code_word
+ disp = (CODE_VA - OLD_BASE - 0x14) & 0xffffffff
+ assert (OLD_BASE + 0x14 + disp) & 0xffffffff == CODE_VA
+ assert (SHIFTED_BASE + 0x14 + disp) & 0xffffffff == ZERO_VA
+ assert (OLD_BASE + 0x14 + disp + 4) & 0xffffffff == SECOND_CODE_VA
+ assert (SHIFTED_BASE + 0x14 + disp + 4) & 0xffffffff == ZERO_VA + 4
+ # Correct a crucial missing prerequisite: ordinary input_len=0x1000
+ # fails FE0A's signed 0x4048F4..FC bounds check BEFORE the comparator.
+ # Selectors 11..13 jump directly to diagnostic status 0x241 instead of
+ # entering FE0A's potentially huge memcpy on comparator ACCEPT. Even
+ # then, a live probe can fault for any third params-VA hypothesis.
+ input_len = 0xFFFFFFFF
+ assert disp + 4 <= input_len and not disp + 4 <= 0x1000
+ for va, mnemonic in ((0x4048F4, 'ldr'), (0x4048FA, 'cmp'),
+ (0x404938, 'b'), (0x4049D8, 'ldr')):
+ ins = next(thumb.disasm(load_bytes(image, va, 4), va, count=1))
+ assert ins.address == va and ins.mnemonic.split('.')[0] == mnemonic, (hex(va), ins.mnemonic)
+ print(f'signed .77 ELF: both targets are initialized mapped LOAD bytes; '
+ f'old={CODE_VA:#x} ({prologue.mnemonic}), shifted={ZERO_VA:#x} (zero)')
+ print(f'FE0A displacement={disp:#x}; counter={COUNTER:#x}, FE09 seed would be {COUNTER + 1:#x}')
+ print(f'adjacent unique ELF dword={second:#x} at {SECOND_CODE_VA:#x}; '
+ f'follow-up displacement={(disp+4)&0xffffffff:#x}')
+ print('A declared input_len=0xffffffff is REQUIRED to reach the comparator; '
+ 'selector 11 avoids FE0A accepted-branch memcpy.')
+ print('If the signed FE07/08/09 gates and counter hold: '
+ 'old params base -> ACCEPT status 0x241; shifted base -> REJECT 0x100.')
+ # GCP .77 sub_4062B4 puts E3, caller-code 3 and the passed 16-bit
+ # status into ASD 0x208 msg[1]. ASD .163 reorders the three parts and
+ # SYS_DRV 0x1079 filters only top bytes EE/EF (signed reports cited below).
+ forwarded = []
+ for status in (0xF000, 0, 0x100):
+ v = (status << 16) | (3 << 8) | 0xE3
+ packed = ((v & 0xff) << 24) | (((v >> 8) & 0xff) << 16) | ((v >> 16) & 0xffff)
+ assert packed >> 24 == 0xE3 and packed >> 24 not in (0xEE, 0xEF)
+ forwarded.append(packed)
+ print('CAUTION: FE0A REJECT can request three SYS_DRV 0x1079 fixed-fabric writes '
+ 'at 0x03B30600, words '+', '.join(hex(v) for v in forwarded))
+ print('ACCEPT with selector 11 also emits three error RPCs (final status 0x241); '
+ 'both paths may touch the same fixed endpoint.')
+ print('This is NOT a passive live read; the private gate and target effect are unmeasured.')
+ print('This offline script alone cannot measure other bases or the live destination mapping; '
+ 'bounded non-ROP hardware observations are documented separately, not ROP authorization.')
+
+
+if __name__ == '__main__':
+ main()