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
|
# session 76 notes (r680) — the 0x2080a097 engine-monitor re-examined
## What the firmware says (ground truth for the a097 family)
The shipped GSP-RM 570.144 image embeds the host-side control
descriptor table (file offset 0x41df8..0x42450, entry = 0x20 bytes
{u32 cmd, u32 params_size, u32 0x4049580, u32 0, u32 handler_ptr,
u32 0, u32 out_size, u32 0}). Entries seen:
0x2080a07f size 0x408 handler vaddr 0x551b2c0
0x2080a079 size 0x14804
0x2080a097 size 0x490 handler vaddr 0x55166f4
0x2080a0d1 size 0x7e8
...
The real 0x2080a097 handler (0x55166f4) writes up to FOUR {u32,u32}
mode pairs into params+4..+0x23 (params[0] low byte = the request's
count flag): for i=1..4 it calls an engine-status helper
(0x5516334 / 0x55d7f04 / 0x55d7c1c / 0x55d7d60) with mode=i and emits
{pair} = {engine value, 1000 * u16(engine+0x1bc0)}; the loop stops at
the first helper error. So the real reply overwrites the client's
request record {1,0,0,0}.
## What the client does with the reply
libnvidia-eglcore's local handler (file offset 0xecd2e0, the userspace
implementation of the internal cmd 0x2080a040) copies back:
result+0 = reply+0 (count)
result+0x10 = reply+0x204 (flag)
result+0x20 = reply+0x488
result+0x24 = reply+0x48c
count*16 bytes from reply+4 -> *(result+8)
For the engine tick (file offset 0xd5e3e0, called from the wait loop
0xd6ef40 per iteration) the result struct IS the caller's request at
rsp+0x10, and *(result+8) points at a 16-byte "inner" buffer
(rsp+0). The tick then reads inner+4 and stores it to session+0xe104
(the per-engine "progress" cache; poll interval ~1.25 s from the same
function). A second consumer of the tick's return value compares it
against per-boot config at lib+0x2019320:
0xfc8 = 1000, 0xffc = 95 (progress threshold),
0xfec = 10, 0xfed = 20 (bit-history cutoffs),
0x1000 = 500
and ORs the comparison bit into a round-robin bitfield (+0xb4) of the
state machine object.
## Live evidence on r680 (fresh boot, full-param recipe)
* The 0x2080a097 polls (NVOS54 0x2a, 1.25 s cadence) come from a
WORKER thread (gdb bt: start_thread -> eglcore a11b2a -> wait loop
0xd6ef40 -> tick 0xd5e3e0). The engine object E (0x604101365e90)
sits at E+0x150 = 0x00200000 (bit 21 only), E+0x1b038 = 1,
E+0x1b039 = 1, *(E+0x1b030)+8 != 0 — all static for 5+ minutes.
* MAIN thread (vkCreateDevice) is in a poll(fd=/dev/nvidia0, events
POLLIN|POLLPRI, timeout=10s) loop inside eglcore (bt: poll <-
eglcore+0xa12de4 <- 0xd69159 <- 0xd6a02b <- 0xdcebc6 <- ... <-
libvulkan vkCreateDevice). No -4 is ever printed in this state: the
client waits indefinitely (killed by its own timeout in runs).
* GR channel kicks continue concurrently (sema-entry lines for
h=0xbeec0100 va=0x4ca0000 len=1432 etc.) and end as
"skipping stale entry ... after N failed rescues" (gr_wedge>0).
* Reply sweep on r680 (module params) — flag=0/2/1/1..0xffffffff,
v488, v48c AND the new record matrix count/rec0..rec7 =
0/{1,0,0,0}/100/1000/100000/1000000/0xdeadbeef — produced ZERO
observable change: same a097 cadence, no writers to
E+0x150/E+0x1b038/E+0x1b039 ever caught, no client progress. The
hw watchpoints on those words fired zero times over ~5 min.
## Tools
* t75g.py — in-guest gdb python: dispatcher-type log, a097 issuer
dump, tick (d5e449) state + cfg dump, E/S capture, hw watchpoints on
E+0x150 / E+0x1b038 / E+0x1b039 / S+0x120, POST a040 consumption
dump.
* diag76.py — in-guest gdb python: thread-apply bt + map-relative
address resolution (used to find the main-thread poll wait).
* slots_probe.sh — read the u16 completion-slot words of every small
/dev/nvidiactl rw-s mapping (SESSION 74's slotfill ABI).
* run75g.sh — trace + record-word sweep driver.
## Verdict
The a097 monitor is a background worker, not an obviously blocking
gate: every knob the client reads from it can be varied with no
observable state change, while the main thread blocks elsewhere
(/dev/nvidia0 poll loop) and the GR channel-init pushes still cannot
be read by the sema service. Next lever is the main thread's wait
(what would make the /dev/nvidia0 poll return readable) or the GR
channel-init completion — not the a097 reply words.
|