# Route C's write window identified: PSP-internal physical space, deliberately unguarded `VULN-LOADIPFW-UNSIGNED-REGWRITE.md` has carried "capability real, **impact unestablished**" because nobody could say what `[0x21500, 0x21B78]` actually is. A VCN reading was proposed and refuted on hardware (`RERATE-ROUTEC-TARGET-MAY-BE-VCN.md`). This settles it from the firmware. ## The mechanism Route C's writes go through `SVC 0x7C`, which resolves addresses via sOS's `vawin_map_fixed` (FA 0x3D8C). That function splits its address argument: r1 = (addr >> 16) & 0xFFF0 ; programmed into a VA-window register r5 = addr & 0xFFFFF ; 20-bit offset within a 1 MB granule So the address is a **PSP-internal physical address**, mapped a megabyte at a time into the caller's VA — not a host SMN address, which is why every attempt to read `0x21xxx` over the host SMN aperture mirrored. ## The access control, and what it does not cover `vawin_map_fixed` gates every request through `sos_check_va_window_request` (FA 0x6D20), which rejects exactly two ranges plus an overflow case. Measured by calling it directly in the emulator: | request | result | | --- | --- | | **Route C window `0x21500`** | **0 — allowed** | | **Route C window `0x21B78`** | **0 — allowed** | | protected range 1, `0x3700000` | `0xa` rejected | | protected range 1, `0x3780000` | `0xa` rejected | | protected range 2, `0x3900000` | `0xa` rejected | | just below range 1, `0x36FF000` | 0 allowed | | just above range 1, `0x3800000` | 0 allowed | | `addr + size` overflow | `0xa` rejected | The controls matter: the protection is demonstrably real and its boundaries are exactly `[0x3700000, 0x3800000)` and `[0x3900000, 0x3A00000)`, and the overflow guard fires. It simply **does not cover `0x21xxx`**. ## What the window contains At least the bootloader's own boot-stage registers: `bl_set_boot_stage` writes `0x215C0` and `0x2161C` through the same mechanism (recorded in `VULN-LOADIPFW-UNSIGNED-REGWRITE.md`). So the window is PSP-internal state that the bootloader itself uses, sitting outside the VA-window protection. ## Status Upgraded from *unidentified* to **PSP-internal physical space, unprotected by the VA-window access control, containing bootloader boot-stage state**. That is a better answer than the tree has had, and it removes the VCN distraction for good. It does **not** by itself establish impact: what the other registers in `0x21500..0x21B78` do is still unknown, and the "nothing reads them" scan that originally deflated this finding covered only the images we hold. The right next question is narrow and concrete — enumerate which addresses in that 1656-byte window the firmware itself touches, now that we know the window is PSP-internal rather than host-visible. --- # What the firmware actually touches in that window: 3 of 415 dwords With the window identified as PSP-internal physical space, the follow-up is narrow: which of its 415 dwords does firmware we hold reference at all? Scanned sOS and SYS_DRV for 32-bit literals and `MOVW`/`MOVT` immediates landing in `[0x21500, 0x21B78]`: | address | referenced from | what it is | | --- | --- | --- | | `0x215C0` | **`bl_main+0x12` and `+0x1a`** (sOS bootloader) | the boot-stage register | | `0x21B40` | literal at `0xE100AC` in SYS_DRV | Route C handler's own fixup constant | | `0x21B50` | literal at `0xE100A8` in SYS_DRV | Route C handler's own fixup constant | **3 of 415.** And two of the three are the handler's own special cases — `VULN-LOADIPFW-UNSIGNED-REGWRITE.md` already records `0x21B40/44/50/54` as the addresses that "get firmware-chosen values" rather than the host's. So the only address in the window that firmware genuinely *uses* is `0x215C0`, and its user is the **bootloader's `bl_main`**, which runs before SYS_DRV exists. ## A control correction The first version of this scan used `0x2161C` as a positive control, because `VULN-LOADIPFW-UNSIGNED-REGWRITE.md` records `bl_set_boot_stage` writing it. The scan did not find it — and the reason is **not** a broken scan: in *our* build `bl_set_boot_stage` is 28 bytes at FA 0x159E0 and references neither address. That description came from a different firmware version, the same version-mismatch trap that made the v53 map unusable for the TSU subsystem. The working cross-check is `0x21B40`/`0x21B50`: independently documented as the handler's special cases, and found by the scan. ## Impact, now bounded Route C writes up to 64 attacker-chosen 32-bit values into PSP-internal register space that the VA-window access control does not protect. But of the 1656 bytes reachable, firmware we possess references exactly one address meaningfully, and its consumer is the bootloader at boot time — before the code that would be attacked is running. So the original "capability real, impact unestablished" becomes **capability real, impact bounded-low on the evidence available** — with the standing caveat that consumers in hardware, or in code we do not hold, cannot be excluded by a scan over the images we have. That caveat is why this is "bounded-low" and not "none". --- # CORRECTION: "3 of 415" is NOT established — the detector has a demonstrated blind spot Prompted by the question "how did you establish there's only one consumer?". Re-examining the method rather than the result, the answer is: **I did not establish it.** ## What the scan could see Only addresses appearing *whole*: 32-bit literals in constant pools, and `MOVW`/`MOVT` immediate pairs. Over two images (sOS, SYS_DRV). ## What it structurally cannot see Register blocks are normally accessed as **base + immediate offset**. A sequence holding `0x21000` in a register and doing `ldr r0, [r1, #0x500]` never materialises `0x21500` anywhere in the image, so the scan is blind to it — and that is the *expected* access pattern for the very thing this window looks like. Tested for it. Scanning the band `[window_lo - 0x1000, window_hi]` for values usable as a base with a 12-bit offset finds **six candidates**: sOS base 0x021000 (covers the ENTIRE window) at FA 0x168ca SYS_DRV base 0x020d04 at 0xE0EC5C SYS_DRV base 0x020d1c at 0xE104B4, 0xE1657C SYS_DRV base 0x020d5c at 0xE180F8 SYS_DRV base 0x020e30 at 0xE18288 SYS_DRV base 0x020f49 at 0xE01DEC An attempt to resolve the sOS one did not decode as code at the offset the scan assumed, which additionally means **the scan's address model for sOS is itself unverified**. ## Further weaknesses, stated plainly * **The control set was effectively N=1.** Of two positive controls, `0x2161C` failed; the build-mismatch explanation for it is evidence-backed but post-hoc. A detector validated by one surviving control is thin — and this project's own standing lesson is that a scan is worthless until it can find a known positive. * **Coverage was 2 images**, not the boot ROM, earlier bootloader stages, or any TA. ## Status of the impact rating "Firmware references 3 of 415 dwords" should be read as **"3 whole-address references in 2 images, with 6 unresolved indexable bases and an unverified address model"** — not as a census of consumers. The bounded-low rating rested on that count, so it is **downgraded to provisional** until either the six candidates are resolved or the scan is rebuilt to follow base+offset addressing. The capability itself is unaffected; it remains confirmed on hardware. ## Dynamic attempt: the right instrument, and why its first answer is void The static scan's blind spot (base+offset addressing) disappears if the question is asked at run time, so `psp_emu/harness/routec_window_watch.py` traps every read and write in `[0x21500, 0x21B78]` across a full boot, three TA loads and six ring commands. It reports **zero reads and zero writes**, and after fixing two broken controls that result now **stands** (for the paths exercised). The harness carries two mandatory controls, and getting them right took two attempts — both failures worth recording, because they pointed in opposite directions. 1. **Liveness** — the same hook observed 15,438,193 reads in a known-busy range (sOS globals) from 197 distinct PCs. The hook works. 2. **Spanning coverage** — firmware traffic must be seen in the same mapped region both **below and above** the window, which proves the watcher's address-space assumption holds across it. Final result: **20 pages below, 1 above (highest `0x3d000`)**. ### Broken control #1: it retracted a correct result The first version of control 2 injected an `ldr r1,[r0]` with `r0 = 0x21500` and checked the hook fired. Post-boot it did not, and I concluded the MMU had made the watcher blind and declared the zero void. That was wrong. Instrumenting the probe with an unfiltered hook showed **no memory access at all** post-boot, not a translated one — the injected instruction never executed, because once the MMU is configured there is no mapping for the scratch page. The control was measuring code injection, not observability. **A control that fails for a reason unrelated to the claim is worse than no control**: it retracts a correct result and looks rigorous doing it. ### Broken control #2: the hook range again The replacement control looked for traffic above the window and found none — because the hook was registered with `end=0x22000`, so addresses above the window could never be delivered. The same hook-range truncation that had already broken two traces earlier in the session. ### What the corrected run shows With the hook spanning the full region, firmware reads land on 21 pages from `0x0` to `0x3d000`, including above the window — so a read at `0x21500` would have been seen exactly as those are. **It never happens.** This is strictly better evidence than the static scan, and it is immune to the base+offset blind spot, because at run time the address exists whether or not it ever appeared whole in the image. The six unresolved indexable bases are therefore answered on these paths: none of them is used to reach the window. ### Residual limits, unchanged * only **exercised paths** are covered (boot, 3 TA loads, 6 ring commands); * the **boot ROM is not emulated**, and `0x215C0` is a bootloader-era register; * this emulator backs the window with **plain RAM**, so a *hardware* consumer is invisible here by construction — which remains the main reason the rating is not "none".