summaryrefslogtreecommitdiffstats
path: root/tools/guest-diag
diff options
context:
space:
mode:
Diffstat (limited to 'tools/guest-diag')
-rw-r--r--tools/guest-diag/wall2/README-session77.md30
-rw-r--r--tools/guest-diag/wall2/wall2_resolver6.py93
2 files changed, 123 insertions, 0 deletions
diff --git a/tools/guest-diag/wall2/README-session77.md b/tools/guest-diag/wall2/README-session77.md
index cf2450e..282b3a0 100644
--- a/tools/guest-diag/wall2/README-session77.md
+++ b/tools/guest-diag/wall2/README-session77.md
@@ -73,3 +73,33 @@
nvidiactl mapping (pagemap; run in the guest as root).
* `nudge.sh` — host-side loop: poll guest_words.sh and write 1 to any
zero word (multi-page variant; prefer the single-word recipe).
+
+## ADDENDUM (r685, session 78) — POST-DEVICE WAIT IDENTIFIED: the NvOgl (GL ucode) engine init; push windows now READABLE (resolver6)
+
+* The post-device spin is the **GL module bring-up**: the main thread's
+ A8-layer retry loop (eglcore 0xa85d24) works on a work item whose
+ embedded name is ASCII **"NvOgl_m0"** (+0xf04: "NvOgl_m40"); the D6
+ submit layer (0xd624e0) ORs **0x200000** into its pending word (the
+ same engine-pending bit SESSION 75/76 watched on E+0x150), then the
+ A8 loop yields via the B284B0 spin helper (sched_yield) waiting for
+ the GL ucode init to complete on the GR engine.
+* **The push windows ARE now readable** (first time): the resolver6
+ recipe (window-record pair {push_va,0x20000}+{ring_va,0x40000} ->
+ same-page 0x20000 memdesc PA -> `sema_map_add`) injected
+ `0x4480000 -> 0x120cfb000` (content `2001c00d 70000000 2001c00d
+ 68000000` = the 2-method semaphore-like push) and `0x4ca0000 ->
+ 0x12e51e000` (the 1432-byte GR init stream: SET_OBJECT 0xc5c0/0xc5b5,
+ `0x200121ed`, `0x200120a9`, bulk methods, tail `2001c00d
+ 70/68`). The service now decodes the streams (`sema-push ... tail=0dc0
+ 012000000070...`) where SESSION 73-74 saw "unread".
+ CAUTION: the resolver injects every candidate; a zero-page candidate
+ injected last replaces the good mapping for that VA (re-inject the
+ good page after the scan).
+* **Remaining gate**: the service still reports `have_rel=0` for every
+ GR push (the CE-shaped release matcher) and — decisively — the
+ GR-forward machinery is NOT engaging: `drain held=4 starved=149
+ forwarded=0 ... gr_nocap=4`. The GL ucode init work is never
+ forwarded/executed, so the completion (and the 0x200000 bit clear)
+ never arrives. Next: the GR forward/capture path for these channels
+ (operand capture + release decode for the GR shape), then the client
+ proceeds to VKFRAME.
diff --git a/tools/guest-diag/wall2/wall2_resolver6.py b/tools/guest-diag/wall2/wall2_resolver6.py
new file mode 100644
index 0000000..4653efa
--- /dev/null
+++ b/tools/guest-diag/wall2/wall2_resolver6.py
@@ -0,0 +1,93 @@
+#!/usr/bin/env python3
+# wall2_resolver6.py - resolver5 logic for BOTH current push windows:
+# pair A: push 0x4480000 (0x20000) + ring 0x44a0000 (0x40000)
+# pair B: push 0x4ca0000 (0x20000) + ring 0x4cc0000 (0x40000)
+# Scans guest RAM continuously; injects PUSH_VA -> every 0x20000 memdesc PA
+# found in a page holding both window records.
+import subprocess, struct, time, sys, os
+
+RAM = "/dev/shm/vgpu-guest-ram"
+PARAM = "/sys/module/vgsp/parameters/sema_map_add"
+LOG = "/tmp/opencode/wall2_resolver6.log"
+WATCH_S = int(os.environ.get("W2_WATCH", "420"))
+PAIRS = [(0x4480000, 0x44a0000), (0x4ca0000, 0x4cc0000)]
+
+logf = open(LOG, "a", buffering=1)
+def log(*a):
+ s = " ".join(str(x) for x in a)
+ print(s, flush=True)
+ logf.write("[%s] %s\n" % (time.strftime("%H:%M:%S"), s))
+
+img = open(RAM, "rb", buffering=0)
+def off2gpa(off):
+ return off if off < 0x80000000 else 0x100000000 + (off - 0x80000000)
+def gpa2off(pa):
+ if pa < 0x80000000: return pa
+ if pa < 0x180000000: return 0x80000000 + (pa - 0x100000000)
+ return None
+def rd(pa, n):
+ off = gpa2off(pa)
+ if off is None: return None
+ img.seek(off); return img.read(n)
+
+def inject(va, pa, ln=0x1000, ap=1):
+ cmd = "echo 0x%x,0x%x,0x%x,%d > %s" % (va, pa, ln, ap, PARAM)
+ r = subprocess.run(["sudo", "sh", "-c", cmd], capture_output=True, text=True)
+ if r.returncode == 0:
+ log("INJECT va=0x%x -> pa=0x%x" % (va, pa))
+ return True
+ log("inject FAIL rc=%d %s" % (r.returncode, r.stderr.strip()))
+ return False
+
+def find_qpair(a, b):
+ img.seek(0, 2); fsz = img.tell()
+ pat = struct.pack("<QQ", a, b)
+ out = []
+ CH = 64 << 20
+ pos = 0
+ while pos < fsz:
+ img.seek(pos); d = img.read(min(CH, fsz - pos))
+ st = 0
+ while True:
+ i = d.find(pat, st)
+ if i < 0: break
+ st = i + 1
+ out.append(off2gpa(pos + i) & ~0xfff)
+ pos += CH
+ return out
+
+def main():
+ log("=== resolver6 start (watch=%ds) ===" % WATCH_S)
+ injected = set()
+ deadline = time.time() + WATCH_S
+ while time.time() < deadline:
+ for (pva, rva) in PAIRS:
+ try:
+ pages = set(find_qpair(pva, 0x20000)) & set(find_qpair(rva, 0x40000))
+ except Exception as e:
+ log("scan error:", e); continue
+ for page in sorted(pages):
+ d = rd(page, 0x1000)
+ if not d: continue
+ cands = []
+ for o in range(0, 0x1000 - 24, 8):
+ sz, fl = struct.unpack_from("<QQ", d, o)
+ if sz == 0x20000 and fl == 0x03008000:
+ pa = struct.unpack_from("<Q", d, o + 16)[0]
+ if 0x100000000 <= pa < 0x180000000:
+ cands.append((o, pa))
+ for (o, pa) in cands:
+ key = (pva, page, o)
+ if key in injected: continue
+ pd = rd(pa, 0x40)
+ nz = sum(1 for b in pd if b) if pd else -1
+ log("pair=0x%x page=0x%x desc@0x%x pa=0x%x live_nz=%d head=%s"
+ % (pva, page, o, pa, nz, pd.hex()[:64] if pd else "?"))
+ if inject(pva, pa):
+ injected.add(key)
+ time.sleep(1)
+ log("=== resolver6 done: %d injection(s) ===" % len(injected))
+ return 0
+
+if __name__ == "__main__":
+ sys.exit(main())