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
|
# Driving the RAS TA on real silicon, and what it settles
The emulator cannot open RAS's init gate: SYS_DRV RPC opcode 0x000d fails a
capacity check because the context at 0xE575B8 is zero (see
`harness/sysdrv_bridge.py`). A bounded search found nothing that populates it --
not init, not any of RAS's RPCs, no low opcode, none of 36 sampled high opcodes,
and not a full `full_system.py` boot. The open question was whether that is a
**missing-state gap in our emulation** or something the firmware genuinely never
does.
That question is not answerable inside the emulator. It is answerable on a card.
## Tooling: a LOAD_TA path that did not exist
tinygrad has no TA loading support, so `psp_out/load_ta.py` builds one on top of
`AM_PSP._ring_submit`: allocate VRAM for the signed TA container and a shared
command buffer, fill `cmd_load_ta` with MC addresses, submit `GFX_CMD_ID_LOAD_TA`
to get a session id, then `GFX_CMD_ID_INVOKE_CMD` per command, and
`GFX_CMD_ID_UNLOAD_TA` at the end. PSP heartbeat is checked before and after
every submit.
The TA driven is the card's own signed RAS 27.0.2.5 container, taken from
`psp_13_0_0_ta.bin` -- the same TA whose body is byte-identical to our
`ras2.elf`, so this is the exact code the emulator runs.
## The control that saved the result
The first run reported `status=0` for commands 1, 2, 3 and 4 and looked like a
clean sweep of successes. It was not. `resp.status` is **ring delivery only**:
feeding it `0xdead` and `0x7fff` also returned `status=0` with byte-identical
output. Reporting that would have been a fabricated "all RAS commands succeed on
hardware".
The TA's own verdict lives in the shared buffer, `struct ta_ras_shared_memory`:
+0x00 cmd_id +0x04 resp_id +0x08 ras_status +0x0c if_version
and the command id goes **in the buffer**, not only in the ring command -- the
same shape as the HDCP invoke ABI decoded earlier in this tree. With that fixed,
valid and invalid commands separate cleanly.
## The RAS command surface on this card
| command | ring status | ras_status |
| --- | --- | --- |
| 1 | 0x0 | **0x0 -- success** |
| 2 | 0x0 | 0xa002 |
| 3 | 0x0 | 0xa010 |
| 4 | 0x0 | 0xa010 |
| 5 .. 0x10 | **0xFFFF000A (rejected at the ring)** | -- |
So RAS exposes exactly four commands, 1 through 4; everything above is refused
before reaching the TA. Command 1 completes successfully, 2 and 3/4 return
TA-level errors in RAS's `0xa0XX` family. (3 and 4 returning "not available" on a
consumer card with no ECC memory is unsurprising, but that reading is an
interpretation, not something measured here.)
## What this settles
**RAS initialises on real hardware.** Command 1 returns `ras_status = 0`, which
means the TA processed it rather than short-circuiting on its init gate. RAS
gates every command on the byte at 0x4060E0, written only inside
`TA_OpenSessionEntryPoint` on a path that bottoms out in the SYS_DRV RPC chain
including opcode 0x000d. For command 1 to succeed, that chain must have
succeeded, so **the SYS_DRV context at 0xE575B8 is populated on a real boot.**
The emulator blocker is therefore a **missing-state gap in our emulation, not a
firmware defect** -- which was always the suspicion, and is now evidence. The
harness note was already careful to say "uninitialised SYS_DRV state, NOT a
defect"; that call is now confirmed from outside the emulator.
## What this does NOT settle
It does not reveal **what** populates 0xE575B8. That is PSP-internal state on a
path the host cannot observe -- the host speaks GFX ring commands, and the
capacity is set somewhere inside SYS_DRV. Hardware confirms the destination;
finding the writer remains an emulator-side problem.
It also does not make RAS command coverage reportable in the emulator. What it
does provide is an **oracle**: once the gate opens, the emulator must reproduce
1 -> 0x0, 2 -> 0xa002, 3/4 -> 0xa010, and reject 5+ at the ring. Any emulated
RAS result that disagrees with that table is wrong.
## Housekeeping
`LOAD_TA` allocates a fresh session id on every call (observed climbing 0, 1, 2,
... across runs), so sessions are a finite resource that leaks if not released.
`load_ta.py` now issues `UNLOAD_TA` before exiting. The card was verified healthy
after every run: heartbeat advancing, LTSSM 0x78 (L0, link up). No ATX cycle was
needed at any point.
|