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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
|
# Known-Knowns and Known-Unknowns
> The most important document for planning work. It states, without
> flattery, what we know, what we know we do not know, and what we do not even
> know to ask yet — plus how each gap gets closed.
## 0. How to read this
| Category | Meaning | Our approach |
|---|---|---|
| **Known-knowns** | verified facts, with evidence in this repo | rely on them; keep them tested |
| **Known-unknowns** | gaps we have identified, with a concrete plan to close | schedule them, one by one |
| **Unknown-unknowns** | gaps we cannot yet name | discover them by systematic traversal + invariants + instrumentation |
Anything listed here as a known-unknown has an owner-visible plan; anything
listed as an unknown-unknown has a *method* by which we will discover it.
---
## 1. Known-knowns (verified)
### 1.1 Device and platform
* A stock 570.144 Linux guest driver probes and initializes against our
emulated TU104 device; `nvidia-smi -L` works and CUDA user-space starts
(`cuInit`, `cuDeviceGetCount`, `cuDeviceGet`). Context creation is in
progress: the client reaches `cuCtxCreate` and currently ends in a forced
`rc=999` on a completion wait; the engine inventory is complete (the async
copy engine is included) and the remaining work is in the completion and
work-execution path (see §2.1).
* The same guest **boots unmodified**: no guest code, no guest module
parameters are required for the initialization path.
* The host is unmodified in the standalone configuration (distribution NVIDIA
driver manages the physical GPU); Open-IOV loads as an independent module.
* Multi-VM operation multiplies the same emulated device; each mdev is
independent.
### 1.2 Protocol and firmware
* The GSP boot state machine is emulatable by completing observable stages.
* The message queue transport is understood in detail: element header layout,
page-table translation of non-contiguous queue buffers, sequence matching,
lengths, and quirks (`length` excludes variable payloads).
* The RPC surface used during driver initialization is fully enumerated for
570.144 (§9 of the field guide gives the ID table).
* Firmware images are analyzable: the 570.144 image is decompiled
(~130 functions of interest mapped to C) and its dispatcher/jump tables are
located.
* Version negotiation exists and is honored (the guest tells us its VGX/RPC
version; we answer with a matching profile).
### 1.3 Memory and execution semantics
* GPU VA → guest PA translation is recoverable **without guest cooperation**
by reading the guest's own bookkeeping (VA and CPU-VA pairs recorded in
UVM/RM structures; direct-map relationship for CPU VAs).
* Guest physical memory is readable and writable from the host module through
the hypervisor's DMA interface, from a kernel thread context.
* UVM's pushes are decodable (incrementing-method headers, engine classes,
`SET_SEMAPHORE_A/B/PAYLOAD`, `LAUNCH_DMA`), and completing their semaphore
releases advances UVM through channel manager creation and page-tree
initialization.
* The client's channel memory descriptors carry *physical* addresses we can
trust (instance/userd/ramfc/method buffers).
* The client's page-table contract for server-owned ranges is explicit
(`COPY_SERVER_RESERVED_PDES`) — and its leaf levels are *empty*, i.e. ours to
populate.
### 1.4 Operational
* Module reload, mdev create/destroy, VM start/stop, and guest reboot cycles
are stable when done in the documented order.
* Every layer of the emulation is instrumented and diagnosable from `dmesg`
plus a small set of module parameters.
---
## 2. Known-unknowns (named gaps with plans)
Each entry: **what we do not know**, **why it matters**, **how we will learn
it**, **rough cost**.
### 2.1 Execution forwarding
**Engine topology (solved):** `GPU_GET_ENGINES_V2` now reports the full engine
inventory including the async copy engine, and the copy-engine capabilities
match the physical device (two GRCEs). The earlier zeroed secondary engine
record that made `libcuda` rewrite the channel alloc class and roll back is
gone; context creation now progresses past engine selection and stalls later,
on completion of decoded work (see §1.1).
**Unknown (resolved by decision, not yet implemented):** the correct,
isolated way to run a guest's engine work on the physical GPU. The interface
analysis in
[`../03-architecture/08-physical-gpu-integration.md`](../03-architecture/08-physical-gpu-integration.md)
shows that proxying through the distribution host driver has no callable entry
point from kernel context, so the **chosen mechanism** is for the module to own
the physical GPU and run its real GSP firmware as the resource-manager server
(the module becomes the host-side RM client). The emulation path remains the
control plane.
**Why:** this is *the* blocker for CUDA kernel execution, and later for
graphics.
**Plan:** build the chosen mechanism in stages: device ownership + real GSP
bring-up; host-side RM client for real objects and channels; translation of
guest work and real submission; completion and fault relay. Measure each stage
against a scorecard: correctness, isolation, latency, maintenance cost across
driver versions. Deliverable: a forwarded `vectorAdd` with verified results.
Alternatives (own scheduling without GSP; vendor vGPU or SR-IOV paths) are
analyzed and rejected or deployment-gated in the integration doc.
**Cost:** weeks, not days; the largest single work item in the project.
### 2.2 Server-owned page tables
**Unknown:** the exact division of labour for page tables after
`COPY_SERVER_RESERVED_PDES`: which ranges the client will touch, when it
expects `RELEASE_ENTRIES`/`RESERVE_ENTRIES`, and how invalidations are
communicated.
**Why:** mappings that only we can create must exist for the guest's own
memory to be reachable by engines.
**Plan:** instrument all vaspace controls (add handlers that log their
parameters), then implement `RESERVE_ENTRIES`/`RELEASE_ENTRIES`/mirroring with
a test harness that maps memory and verifies the guest's expectations by
running its own validation paths (UVM page-tree init exercises this).
**Cost:** days to weeks.
**Reachability resolution note (2026-10-02):** the related IOMMU/DMA
reachability question is closed on the reference host. The physical GPU's
IOMMU group is an identity domain (all-RAM identity) and the mediated device
registers as an emulated-IOMMU VFIO device, so its type-1 container holds
guest DMA mappings privately and no kernel `iommu_domain` exists for it:
`iommu_iova_to_phys` cannot translate guest GPAs. Guest RAM is backed by a
shared file instead, and the module translates GPA->HPA through that file's
page cache. A channel page-table line the GMMU has already walked cannot be
updated at runtime (no TLB-invalidate path exists), so channel page-table
slots for the guest window are pre-built before any engine access. Live proof:
the physical copy engine copied 4 KiB from a real guest page into a module
buffer and back, semaphore released, with the guest process observing the
write and the driver-API smoke green (`ALL OK` 64/64). Wrong-page-table writes
remain the top risk; the division-of-labour question above is unchanged.
### 2.3 Fault semantics
**Unknown:** fault buffer formats and replay/cancel semantics as the *guest*
expects them in our virtualized setting (we know the buffer sizes and that
UVM programs them, but not yet the end-to-end contract under forwarding).
**Why:** GPU page faults happen constantly in real CUDA workloads (UVM
oversubscription, migrations); correct handling is required for robustness.
**Plan:** reproduce faults deliberately (map a VA to nothing, touch it from a
forwarded kernel), capture both sides, implement replay; validate with
`uvm_fault`-heavy tests (e.g. oversubscribed memory).
**Cost:** weeks.
### 2.4 Version matrix beyond 570.144
**Unknown:** which parts of the observed protocol drift between driver
families (550/560/570/580 — the families with entries under
`config/versions/`), how much is negotiated, and how much must be
configuration.
**Why:** durability is a core promise; users will run other versions
immediately.
**Plan:** run the same init traces across 2–3 driver families in guests,
diff the message/control inventories, and refactor handlers to be
version-keyed where they differ. Deliverable: a capability matrix and a
documented "add a version" workflow.
**Cost:** days per version, once the workflow exists.
### 2.5 Windows guest specifics
**Unknown:** the WDDM-facing differences (ROM/VBIOS expectations, MSI-X
semantics, power management, display topology) that the Windows driver
requires beyond the Linux path.
**Why:** Windows CUDA/3D users are a first-class audience.
**Plan:** bring up a Windows guest against the same device, capture the driver
logs (Windows ETW + our host traces), and add configuration for discovered
requirements.
**Cost:** weeks.
### 2.6 Non-KVM transports
**Unknown:** what differs for Xen/Argo/OpenXT/Qubes OS Air: IRQ delivery
mechanisms, memory pinning, device-model integration points.
**Why:** the security-focused platforms are a major part of the project's
reason for existing.
**Plan:** abstract the transport boundary (IRQ injection, guest-memory access,
device registration) behind a small interface; implement a Xen backend against
it; test in a Xen guest.
**Cost:** weeks.
### 2.7 aarch64 hosts and Grace/GB10
**Unknown:** host-side differences (page sizes, cache attributes, SMMU
behaviour, power domains) and any firmware/ROM differences in the guest path.
**Why:** Grace-Hopper/Grace-Blackwell/GB10 (DGX Spark, Surface-class laptops)
are explicit targets.
**Plan:** make the emulation architecture-independent by construction
(no x86-specific assumptions in the memory model), then bring up on an
aarch64 host with the same test ladder.
**Cost:** weeks per platform.
### 2.8 Multi-tenant performance policy
**Unknown:** best scheduling policy for sharing one GPU across VM tenants
(time slice, MIG partition, hybrid) and its fairness/isolation properties.
**Why:** multi-tenancy is a core value proposition.
**Plan:** build measurement first (per-tenant attribution), then implement
policy as configuration, then audit isolation.
**Cost:** months (it is a research-y area).
### 2.9 Tooling maturity
**Unknown:** how much of the debug tooling (memory scanners, pokes, push
decoders) can be productized without exposing unsafe interfaces.
**Why:** the tooling is currently how we make progress; it must not become a
security liability.
**Plan:** move tooling behind a debug-only build flag/document its threat
model; keep safe, read-only diagnostics in production builds.
**Cost:** days.
---
## 3. Unknown-unknowns (and how we find them)
Unknown-unknowns are discovered by *systematic traversal* and *invariants*,
not by luck. Our methods:
### 3.1 Traversal by construction
* **Enumerate every interface the guest touches.** For each: prove we answer
it or forward it. Any interface we have not seen is a discovery task, not a
bug.
* **Drive the guest further, always.** Each new guest-side milestone (probe →
nvidia-smi → cuInit → context → allocation → kernel) is a traversal step
that *forces* new interfaces to appear in the trace.
* **Differential testing across versions/hardware.** The same traversal on a
second driver version or GPU surfaces requirements that are invisible on
the first.
### 3.2 Invariants that trip on unknowns
We rely on the guest's own self-checks as an oracle:
* UVM asserts on semaphore jumps, bad page tables, impossible capabilities.
* The RM validates structures and will fault on inconsistencies.
* Kernel drivers log "unexpected" states loudly.
Every guest assert/log is a discovered unknown-unknown if we do not already
have it in this document.
### 3.3 Structural instrumentation
* **Trace-first policy:** no handler is written without logging the request
*and* the reply in a reconstructible form.
* **Reconstruct from dmesg:** the logs must be sufficient to rebuild the
object tree, memory map and push stream offline. This is how protocol drift
is detected early, before it becomes a crash.
### 3.4 Fuzzing and negative tests
* Feed the emulation malformed/partial guest actions (truncated elements,
bad sequence numbers, out-of-range handles) and require graceful
behaviour — this finds assumptions we did not know we had.
* Feed the *guest* plausible-but-wrong device behaviour in a lab profile and
verify the guest recovers (drivers do error recovery we must not break).
### 3.5 Failure archaeology
Every failure leaves artifacts. The discipline is: capture host `dmesg`,
guest `dmesg`, guest PCI config, and the emulation's per-RPC log; then write
the *decision tree* that leads to the failure into the debugging docs. The
tree is the artifact that survives personnel changes.
---
## 4. What we need to know to declare "CUDA works"
To make a defensible statement, we need all of:
1. **Interfaces:** every guest→device message for the CUDA path is either
answered or forwarded, for the supported driver family — and every reply
whose fields the driver consumes is coherent, not just `SUCCESS`-shaped
(the reply-fidelity ladder: status-only → coherent zeroed params → coherent
values for consumed fields → exact values; see
[`../../userspace/cuda/docs/04-virtualization-and-emulation.md` §6](../../userspace/cuda/docs/04-virtualization-and-emulation.md)).
2. **Memory:** every GPU VA used by work is translatable, and every server-owned
page-table range is populated correctly.
3. **Execution:** grid launches and copies run on real hardware with correct
results, repeatedly, with errors surfaced.
4. **Completion:** semaphores, events and faults behave as the guest expects
(values advance correctly, no lost interrupts, no stuck waits).
5. **Version:** at least two driver families pass, with a documented path for
more.
6. **Isolation:** a second tenant cannot observe or influence the first.
7. **Performance:** within an agreed factor of native for the supported cases,
measured with a published methodology.
Until all seven hold, we say "initialization works; execution is in progress",
and we link here. The CUDA-side checklist behind these gates and the current
blocker are in
[`../../userspace/cuda/docs/03-driver-and-gpu-interface.md` §9](../../userspace/cuda/docs/03-driver-and-gpu-interface.md);
start at
[`../../userspace/cuda/READ-ME-FIRST.md`](../../userspace/cuda/READ-ME-FIRST.md).
---
## 5. Practical challenges (summary; details in the challenges doc)
| Challenge | Why it is hard | Mitigation |
|---|---|---|
| Real execution | emulating GR is hopeless; forwarding must be correct and isolated | proxy-first, measure, iterate |
| Page tables both sides | guest's and hardware's expectations must agree | study AMAP/HAL definitions; build a page-table validator |
| Latency | RPC round-trips and push translation add overhead | batch, fast-path pure state in the emulation |
| Version drift | protocol and structures evolve | version-keyed handlers, config-driven profiles |
| Security | forwarding must not weaken isolation | IOMMU-only access, per-tenant contexts, audits |
| Debuggability | most bugs are in the guest's head, not ours | trace-first, reconstruct-from-logs policy |
| Test cost | real GPU time and guest boots are slow | scripted ladders, keep artifacts, parallelize |
|