1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
# Fuse / debug-unlock reachability, round 1: method established, result under-powered
Following `LEAD-SYSDRV-FUSE-DEBUG-DMA-SURFACE.md`, which found
`fuse_program_bits`, `debug_unlock_apply` and friends in our own symbol map with
**no mention anywhere in the project**. The question is how they are dispatched
and whether anything host- or TA-reachable gets to them.
## Static pointer-table scan — useless, and its control said so
Scanned the SYS_DRV image for each target address as a 32-bit word (with and
without the Thumb bit), expecting dispatch tables.
**Method control: 0 of 40 randomly sampled known functions appear as a 32-bit
word anywhere in the image.** So SYS_DRV does not hold absolute pointer tables in
the static image — dispatch is via `tbb`/`tbh` switch tables, the same shape
already documented for HDCP. The scan could not have found anything, and the
control is what established that rather than the empty result.
## Dynamic sweep — controls good, coverage bad
Swept 4352 opcodes (0x0000-0x00FF and 0x1000-0x1FFF) through the real entry
`sub_E087E4` in `sysdrv_env`, with execution hooks on 19 fuse/debug/flash
functions.
Controls all fire, so the path and the hooks work:
| control | hits |
| --- | --- |
| entry `sub_E087E4` | 4352 |
| high dispatcher `sub_E105A8` | 4096 |
| allowlist `sub_E0AB44` | 4443 |
| crypto dispatcher `sub_E1DC30` | 256 |
Targets: **none of the 19 reached.**
## Why that negative does not mean "unreachable"
Two of the 19 are `spirom_write_checked` and `rom_parse_directory` — known,
real SYS_DRV functionality that this project has studied in depth. They were not
reached either. Total coverage was **666 SYS_DRV blocks**, and it stopped growing
after the first ~2000 opcodes.
So the sweep dispatches every opcode but the handlers bail early — almost
certainly on argument validation or uninitialised state, exactly the class of
gap that blocked RAS at `0xE575B8`. The experiment cannot distinguish "not
reachable" from "my requests are too poorly formed to get past the front door",
and the flash controls prove it is the latter.
**This result bounds nothing about the fuse/debug surface.** It establishes the
method and shows the current request construction is too weak.
## What round 2 needs
Per-opcode valid arguments, not one generic request. The tree already knows how
to do this for a few opcodes (`sysdrv_bridge.py` drives 0x0001/0x0002/0x000d/
0x1077 with RAS-supplied arguments and gets three to succeed). The useful
target is coverage: drive handlers deep enough that `spirom_write_checked`
becomes reachable, and only then is a negative on `fuse_program_bits`
meaningful.
An alternative that avoids the argument problem entirely: run the sweep inside
`full_system.py`, where SYS_DRV has real state and real callers, and hook the
targets there over a long boot. That measures what actually executes rather
than what a synthetic request can reach.
## Artifacts
`psp_out/fuse_reach.py`.
---
# Round 2: measure what actually executes in a real boot
Hooking the targets inside `full_system.py`, where SYS_DRV has real state and
real callers, instead of trying to synthesise valid requests.
## First reading was wrong
The entry-point hook reported `fuse_program_bits` executing once, which looked
like a headline result. It is not. The call context showed `LR = 0xE0BE7D` —
pointing *into the function itself*, not at a caller — and **zero blocks
executed inside its 464-byte body**, with the next block being `0x8`, an
exception vector. An entry address being touched is not the function running.
Re-measured at **body level**: count blocks executed *within* each function's
range across a whole boot, with two known functions as controls.
| function | hits | distinct blocks | |
| --- | --- | --- | --- |
| `heap2_zero_block` | 156 | 4 | **CONTROL — measurement works** |
| `bn_from_bytes_be` | 0 | 0 | control, crypto-only path |
| **`dma_transfer`** | **17** | **16** | **genuinely executes** |
| `fuse_program_bits` | 2 | 1 | one block only — prologue/guard, not its logic |
| `spirom_read_checked` | 1 | 1 | one block only |
| `fuse_write_field` | 0 | 0 | |
| `debug_unlock_apply` | 0 | 0 | |
| `secure_boot_state` | 0 | 0 | |
| `fuse_read_flag` / `fuse_read_config` / `fuse_read_pair` | 0 | 0 | |
| `rom_parse_directory` / `spirom_read_header` | 0 | 0 | |
## What this establishes
* **`dma_transfer` is live.** 16 distinct blocks across a normal boot — a PSP
DMA engine that actually runs and that the emulator does not model. That is
the most substantive item here and it was not previously known to execute.
* **The fuse-write and debug-unlock paths do not execute during a normal boot.**
`fuse_program_bits` reaching exactly one block twice is a guard or prologue
returning immediately, not its logic; `fuse_write_field`, `debug_unlock_apply`
and `secure_boot_state` are never entered at all.
## What it does not establish
Not executing during boot says nothing about whether they can be *driven* by a
host or TA request. Round 1 showed the synthetic-request sweep is too weak to
test that, and round 2 measures a different thing: normal-path execution. The
reachability question stays open.
The honest summary of both rounds: the dispatch mechanism is `tbb`/`tbh` switch
tables (no pointer tables to scan), these functions are not on the boot path
except `dma_transfer`, and testing request-driven reachability still needs
per-opcode valid arguments with `spirom_write_checked` as the coverage gate.
|