summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/guest-diag/wall2/README-session77.md25
-rw-r--r--tools/guest-diag/wall2/wall2_resolver7.py125
2 files changed, 150 insertions, 0 deletions
diff --git a/tools/guest-diag/wall2/README-session77.md b/tools/guest-diag/wall2/README-session77.md
index 282b3a0..5d3c70b 100644
--- a/tools/guest-diag/wall2/README-session77.md
+++ b/tools/guest-diag/wall2/README-session77.md
@@ -103,3 +103,28 @@
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.
+
+## ADDENDUM (r686, session 79) — the low-VA release fix and the corrected injection recipe
+
+* The GR/GL init releases decode only with the low-aperture acceptance
+ (`SEMA_VA_LO` bound relaxed to >= 0x4000000 in both release forms,
+ commit cb8b75c5): live `rel=0x4b19b10 pay=1` (REPORT_SEM group
+ `200426c0 00000000 04b19b10 00000001 10000000`), `rel=0x4b17bb0
+ pay=3` and `rel=0x4b17e30 pay=1` (0x5c-form `2005c017 04923060 ...
+ 02000001`); `have_rel=1`, `applied` rising, un-translated releases
+ queue in svc_pending (417 observed).
+* Corrected pair-specific push injections for r686:
+ `0x4480000 -> 0x125692000` (record page 0x1163c9000, live desc),
+ `0x4ca0000 -> 0x131649000` (page 0x122f20000), plus
+ `0x4b16000 -> 0x12a76a000` (the {0x4b16000,0x1000} window).
+ CAUTION: resolver7 injects each page's descs for BOTH pairs (union
+ loop) - fix it to keep per-pair pages or inject manually from the
+ per-pair scan. The window-record layout is {tag, VA, SIZE, 0,
+ "tail", ...} stride 0x40 (search the VA u64 with size at +8 and
+ "tail" at +0x10).
+* Remaining: the semaphore VAs (0x4b17bb0/0x4b17e30/0x4b19b10) have no
+ window records in the known record pages; the service cannot resolve
+ them (targeted rm_mem miss) so the releases stay pending and the
+ NvOgl wait spins. Find their PAs (client mapping pages / RM
+ VA-tracker / live poll-watch), inject, and the pending releases
+ should apply.
diff --git a/tools/guest-diag/wall2/wall2_resolver7.py b/tools/guest-diag/wall2/wall2_resolver7.py
new file mode 100644
index 0000000..5d9e58e
--- /dev/null
+++ b/tools/guest-diag/wall2/wall2_resolver7.py
@@ -0,0 +1,125 @@
+#!/usr/bin/env python3
+# wall2_resolver7.py - resolver6 + release-window injection + live-first ordering.
+# Fixes the resolver6 zero-page overwrite: candidates are injected good-first
+# (live_nz>0) and zero pages last, so the readable mapping wins by order if the
+# service keeps the newest write.
+# New: the GR init release windows (0x4b16000 size 0x1000 from the record page,
+# and any {VA,0x1000} record alongside) are injected from the size-0x1000
+# memdescs of the same page.
+import subprocess, struct, time, sys, os
+
+RAM = "/dev/shm/vgpu-guest-ram"
+PARAM = "/sys/module/vgsp/parameters/sema_map_add"
+LOG = "/tmp/opencode/wall2_resolver7.log"
+WATCH_S = int(os.environ.get("W2_WATCH", "420"))
+PAIRS = [(0x4480000, 0x44a0000), (0x4ca0000, 0x4cc0000)]
+REL_WINS = [0x4b16000]
+
+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 collect(page):
+ d = rd(page, 0x1000)
+ if not d: return None
+ descs = []
+ wins = []
+ for o in range(0, 0x1000 - 24, 8):
+ sz, fl = struct.unpack_from("<QQ", d, o)
+ pa = struct.unpack_from("<Q", d, o + 16)[0]
+ if fl == 0x03008000 and 0x1000 <= sz <= 0x400000 and \
+ 0x100000000 <= pa < 0x180000000:
+ descs.append((o, sz, pa))
+ va2 = sz
+ if 0x4000000 <= va2 < 0x100000000 and (va2 & 0xfff) == 0:
+ sz2 = fl
+ if 0x1000 <= sz2 <= 0x1000000 and (sz2 & 0xfff) == 0:
+ wins.append((va2, sz2))
+ return descs, wins
+
+def main():
+ log("=== resolver7 start (watch=%ds) ===" % WATCH_S)
+ injected = set()
+ deadline = time.time() + WATCH_S
+ while time.time() < deadline:
+ pages = set()
+ 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)
+ for page in sorted(pages):
+ got = collect(page)
+ if not got: continue
+ descs, wins = got
+ # push windows: inject live-first (nz>0 first, zeros last)
+ for (pva, _rva) in PAIRS:
+ cands = [(o, sz, pa) for (o, sz, pa) in descs if sz == 0x20000]
+ order = []
+ for (o, sz, pa) in cands:
+ 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" % (pva, page, o, pa, nz))
+ order.append((nz, o, pa))
+ order.sort(key=lambda t: t[0]) # zeros first, live last
+ for (nz, o, pa) in order:
+ key = (pva, page, o)
+ if key in injected: continue
+ if inject(pva, pa):
+ injected.add(key)
+ # release windows: any {VA, 0x1000} record on the page -> size-0x1000 descs
+ for (va, sz) in wins:
+ if va not in REL_WINS and not (0x4b00000 <= va <= 0x4b20000):
+ continue
+ for (o, dsz, pa) in descs:
+ if dsz != sz:
+ continue
+ key = (va, page, o)
+ if key in injected: continue
+ if inject(va, pa):
+ injected.add(key)
+ time.sleep(1)
+ log("=== resolver7 done: %d injection(s) ===" % len(injected))
+ return 0
+
+if __name__ == "__main__":
+ sys.exit(main())