summaryrefslogtreecommitdiffstats
path: root/tools/guest-diag/wall2/README-session77.md
diff options
context:
space:
mode:
Diffstat (limited to 'tools/guest-diag/wall2/README-session77.md')
-rw-r--r--tools/guest-diag/wall2/README-session77.md132
1 files changed, 132 insertions, 0 deletions
diff --git a/tools/guest-diag/wall2/README-session77.md b/tools/guest-diag/wall2/README-session77.md
index 1ae9a62..d830bef 100644
--- a/tools/guest-diag/wall2/README-session77.md
+++ b/tools/guest-diag/wall2/README-session77.md
@@ -1061,3 +1061,135 @@ service-side durable route: have the SERVICE write the marker into the
channel-buffer page once it can resolve it (the memdesc VA = the CE
channel's buffer; the service's channel registration fields + the PT walk
give the page candidates).
+
+**39. Sessions 112b-114: THE SCRUB GATE FELL, THE COMPR WALL WAS DECODED AND FLIPPED, AND THE FIRST VULKAN SUBMISSION LANDED (VKFENCES IS THE NEW WALL).**
+Context first (sessions 112b/112c, commits `97489187`/`cb7d8ce7`/`752e2b30`/
+`d6ccdaf3`/`8700f65a`): the CeUtils scrubber's finish payload is authored
+in-service (bound to the EXACT 4096-entry channel), the client then leaves
+`scrubCheckAndWaitForSize` permanently and runs
+vkCreateImage -> vkGetImageMemoryRequirements -> vkAllocateMemory; the
+remaining `-2` was decomposed to the guest-internal VidHeap `#149`-shape
+call (attr COMPR_ANY + 2MB page + owner 0x474C0000) returning 0x51
+NV_ERR_NO_MEMORY; session 113 read that as a 64KB comptag/CBM alloc. This
+session REFINED it: the COMPR+2MB class is not always 64KB - the r705
+runs show the *image data* alloc itself (size 0x140000 = 1.25 MB for
+640x480x4 + pad, attr 0x1002000, flags 0xc10d) in exactly the same shape.
+The "separate 64KB CBM" reading was too narrow; every alloc of the class
+{attr&0xF000 == 0x2000, 2MB page, owner 0x474C0000} fails 0x51.
+
+**A. THE ZERO-TOUCH CREATE RECIPE (NEW, SCRIPTED).** Two live assists are
+required per client, both proven again this session: (1) the
+instance-phase marker clears at eglcore+0xB33D30 (t106/t99 `BC`, 5
+clears); (2) THE DEVICE-PHASE WAIT-WORD CHASER at eglcore+0xDCEBD9
+(t99 `BW`: word = *(holder+0x58)+*(u32)(obj2+0x60) with
+obj2 = *(*(rbx+0x70)+0x58); write 1 when 0). Without (2) the client
+reaches `VKDEVICE`'s poll(`/dev/nvidia0`, 10 ms) retry loop and sits
+there INDEFINITELY (session-76 state; the a097 engine-monitor worker
+keeps polling 0x2080a097 every 1.25 s regardless - its reply words are
+still a red herring for the main-thread gate). With (1)+(2) the run is
+`VKINSTANCE ok / VKDEVS 2 / VKDEVICE ok family=0` then straight to the
+image path. `t99.py`-style attach works too: attaching `BW` to an
+already-stuck client writes the word and the client immediately
+proceeds (proven on a stuck pid 15797: WORDWROTE x2 -> VKDEVICE ok ->
+VKFAIL -2 at the alloc).
+NEW TOOLS: `t120.py` (BC+BW+single-shot COMPR->non-COMPR flip),
+`t121.py` (BC+BW+full VidHeap trace from #120), `t122.py` (BC+BW+flip
+for ANY COMPR+2MB internal alloc, size >= 0x10000), `a8clear.py` (the
+no-ptrace count-gate clearer for base+0x2070b7c, reconstructed).
+
+**B. THE FLIP (THE DECISIVE EXPERIMENT).** With `t122.py`: at the
+vidheap ioctl whose params match (attr&0xF000)==0x2000, owner
+0x474C0000, size>=0x10000, the script clears attr bits 13:12
+(COMPR_ANY -> NONE) in the client's own params before the kernel sees
+them. Result (r705c, reproducible twice on the same boot):
+`HIT149 size=0x140000 attr=0x1002000 -> 0x1000000` (image data alloc
+SUCCEEDS), a second `HIT149 size=0x140000 attr=0x1022004 -> 0x1020004`
+(buffer-class COMPR alloc) also succeeds, and the client runs the WHOLE
+pipeline for the first time in project history:
+vkCreateImageView -> buffer -> shader module -> descriptor set
+layout/pool -> pipeline layout -> compute pipeline -> command pool ->
+command buffer -> fence -> vkResetFences -> **vkQueueSubmit OK** ->
+`VKFAIL vkWaitForFences(dev, 1, &fence, VK_TRUE, 30000000000ull) -> 2
+(line 459)` - THE FIRST VULKAN SUBMISSION, then the FIRST FENCE TIMEOUT
+(30 s, the client's own bound; the run exits rc=1 cleanly).
+
+**C. THE NEW WALL = THE FIRST FENCE RELEASE.** Host-side evidence in the
+submit window: the client's GR channel registers
+(`sema-chan: h=0xbeec0100 eng=0 gpfifo=0x4cc0000 ent=32768
+userd=0xfee00 put=11 get=2 ring rc=0 pa=0x1217e3000 ap=1`) - the guest
+driver published 11 GPFIFO entries, the emulation's reader consumed 2;
+the service still reports the channel-init pushes unread
+(`sema-entry: unread h=0xbeec0100 idx=2 va=0x4ca059c len=976 want=0
+exp=0 unread=1`) and `gr_wedge` grew 3 -> 9 over the runs. So the fence's
+release is never authored after the submit - this is the session-76/93
+"wall #2" class (push-page readability/completion), now the ONLY gate
+between the flipped client and the first `VKFRAME seq/DONE` + PPM.
+
+**D. DURABLE-FIX LEADS (for the COMPR class, no guest patching).**
+(1) memmgrAllocHal_GM107 (570.144) downgrades COMPR_ANY -> NONE when
+`pMemorySystemConfig->bDisableCompbitBacking` is set - the guest's
+MEMORY_SYSTEM_STATIC_CONFIG comes from the GSP (the MEMSYS_GET_STATIC_
+CONFIG control 0x20800a1c / the GSP static info path); answering it (or
+the same knob wherever the guest's config actually comes from) is the
+host-side durable equivalent of the flip. 0x20800a1c was NEVER observed
+in the RM_CONTROL log, so first find where the guest's config is fed
+(control cache? GSP init args?) before coding the handler.
+(2) Alternatively locate glcore's COMPR decision (attr construction at
+eglcore+0x2c83fb/0x2c8465 and +0x50e038/0x50e894/0x50e8bd per session
+113) and answer the capability that drives it. (3) The session-85
+device-local -2 story (2g mdev type) remains a prerequisite context.
+
+NEXT (ranked): (1) author the fence release for the first submit (the
+push-page-5 content-match / pinning machinery; or have the service
+complete the fence when it consumes the submit's GPFIFO entries); (2)
+then the first VKFRAME seq/DONE + PPM; (3) fold the COMPR flip into a
+host-side answer (see D); (4) the mission series (Xorg/GZDOOM, KVMFR,
+CUDA 15/15 + soak, test series, video, Windows).
+
+**40. Session 115: THE FENCE WALL DECOMPOSED - THE CLIENT VAS PAGE DIRECTORY IS UNDISCOVERABLE AND THE PUSHES ARE NONCONTIGUOUS; RING PAGES ARE CONTENT-LOCATABLE AND INJECTABLE, BUT THE RING PAIR ALONE DOES NOT UNLOCK THE PUSH DECODE.**
+(1) The fence timeout is upstream of everything else: the sema service cannot
+decode the submit's GR pushes (`sema-entry: unread ... va=0x4ca0000
+len=1432` -> `skipping stale entry ... after 185-194 failed rescues`;
+`work_gr submitted=0` - no GR forward ever starts). (2) The pump's push
+reads resolve ONLY through the client VAS page directory (or pins). The
+service has NO pdb for this client: `walk_probe` of the ring and push VAs
+prints `discovered pdb=0x0 found=0` and no registered VASes; the r496f
+vidmem pdb discovery never ran (it is only called from the RAM ring-scan
+latch), and the r496j COPY_SERVER_PDES candidate (0x109b9c000) is garbage
+(its content is not a page table). (3) THE RAM RING SCAN MISSES BY
+CONSTRUCTION for this client: it sweeps [0, 6 GB) in 12 slices and gives
+up (`found no candidate in 12 slice(s)`), but the sweep runs BEFORE the
+client's pushes exist and never re-runs - while the ring page content is
+provably in RAM (content-located below). (4) CONTENT LOCATION WORKS: the
+GR ring page (ring VA 0x4cc0000, first entries {va=0x4ca0000 len=1432,
+va=0x4ca0598 len=4}) was found in the guest RAM file by its first two GPFIFO
+entries (at GPA 0x12C600000 then 0x12898c000 on later runs - per-run
+allocations), and `sema_map_add` injection of the TRUE ring pair is
+accepted (`INJECT va=0x4d20000 pa=0x13619d000 : ok`). BUT the pushes do not
+become readable from the ring pair alone: the pushbuffer is NONCONTIGUOUS
+(the window guess `ring_pa - 0x20000` reads zeros for both the GR and the
+CE channels), the pushes are not CPU-mapped in the client process (the
+ring GPA is absent from /proc/PID/pagemap of every rw-s nvidia mapping),
+and a bottom-up search for the level-3 table (a 4 KB page whose index-2
+big/small entry maps into the ring's 2 MB window) found ZERO candidates in
+RAM - the page tables are almost certainly in VIDMEM (r496f's note) or use
+a shape the walker does not model. (5) The service's OWN successful read of
+one CE init push (`sema-push: h=0xbeec0104 va=0x4d00000 ... rel=0x4b19b10
+pay=1 have_rel=1`, `ops_runs=0`) did NOT apply its release either -
+whatever resolved that one read is not reproducible for the GR pushes.
+NEW TOOLS: `fence_assist.py` (host: watches a `dmesg -w` capture for the
+pump's entry decodes, content-locates the ring pages by their first two
+entries in the RAM file, injects the pairs via sema_map_add - proven to
+find and inject, but the ring pair alone is insufficient) and
+`find_push.py` (guest: tests whether the client CPU-maps the ring GPA).
+NEXT (ranked, concrete): (1) find the client VAS page directory: extract the
+pdb from the GUEST kernel's RM objects (kcore walk of the VAS/GPU object
+for this channel - the GPFIFO ring page content anchors the search), then
+register it via the service's VAS table (a new sysfs/debugfs entry point
+or the existing candidate path) - this is the "PDB injection" the mission
+names; (2) or scan VIDMEM for the pdb with the ring pair as the verifier
+(extend `svc_xvas_pdb_discover`'s trigger: call it from the ring-injection
+path, not only from the RAM scan latch); (3) make the RAM ring scan re-arm
+per channel with the pushes present (its 12-slice give-up is the reason
+the auto-discovery never latches on this client); (4) then the submit
+decodes, the release lands and `vkWaitForFences` returns -> VKFRAME.