summaryrefslogtreecommitdiffstats
path: root/tools/guest-diag/wall2
diff options
context:
space:
mode:
Diffstat (limited to 'tools/guest-diag/wall2')
-rw-r--r--tools/guest-diag/wall2/README-session77.md26
-rw-r--r--tools/guest-diag/wall2/wall2_recscan.py70
2 files changed, 96 insertions, 0 deletions
diff --git a/tools/guest-diag/wall2/README-session77.md b/tools/guest-diag/wall2/README-session77.md
index 5d3c70b..2eac8f4 100644
--- a/tools/guest-diag/wall2/README-session77.md
+++ b/tools/guest-diag/wall2/README-session77.md
@@ -128,3 +128,29 @@
NvOgl wait spins. Find their PAs (client mapping pages / RM
VA-tracker / live poll-watch), inject, and the pending releases
should apply.
+
+## ADDENDUM (r686, session 80) — ALL low-aperture window records found (the "liat" tag fix); the semaphore windows identified and their releases applying
+
+* **The record scan fix**: the RM window record is 0x40 bytes
+ {u64 tag; u64 VA; u64 SIZE; u64 0; u32 0x7461696c; u32 0}. The tag is
+ stored as the u32 0x7461696c - on disk the BYTES are "liat", NOT
+ "tail" (the hex display `7461696c` reads as "tail" only as a number).
+ Searching for b'tail' finds nothing; `wall2_recscan.py` searches for
+ the byte pattern 6c 69 61 74 and decodes {tag,VA,SIZE} at
+ -0x20/-0x18/-0x10. It found **all 75 records** in one pass.
+* **The GR init semaphore windows** (r686):
+ `va=0x4b17000 size=0x2000 -> pa=0x12a76f000` (verified by content:
+ +0xbb0=3, +0xe30=1 - exactly the rel=0x4b17bb0 pay=3 /
+ rel=0x4b17e30 pay=1 payloads) and
+ `va=0x4b19000 size=0x1000 -> pa=0x122f9b000` (after injection the
+ release applied there: +0xb10 became 2). Injections:
+ `echo 0x4b17000,0x12a76f000,0x2000,1 > sema_map_add` and
+ `echo 0x4b19000,0x122f9b000,0x1000,1 > sema_map_add`.
+* **State after the injections**: the low-VA releases decode
+ (`have_rel=1`) and apply to the semaphore pages; `pending` hovers at
+ ~418 (the client re-kicks continuously); the NvOgl wait still spins
+ (the A8 loop compares per-entry counter tables r14+0x5e8 vs the
+ wanted set - the completion is not just the semaphore value). Next:
+ the A8 counter tables' source (what fills r14+0x5e8 / the "wanted"
+ table - likely the GR channel's own progress counters) or the GR
+ forward/ucode execution (`forwarded=0 gr_nocap=7` still).
diff --git a/tools/guest-diag/wall2/wall2_recscan.py b/tools/guest-diag/wall2/wall2_recscan.py
new file mode 100644
index 0000000..7bc4e2c
--- /dev/null
+++ b/tools/guest-diag/wall2/wall2_recscan.py
@@ -0,0 +1,70 @@
+#!/usr/bin/env python3
+# wall2_recscan.py - scan the guest RAM for the RM's low-aperture window
+# records and their memdesc PAs.
+#
+# Record layout (verified r685/r686): 0x40-byte stride
+# {u64 tag; u64 VA; u64 SIZE; u64 0; u32 0x7461696c ("tail" as a u32 -
+# on disk the BYTES are "liat"); u32 0}
+# The tag is NOT the byte string "tail" - searching for b'tail' finds
+# nothing; search for the 4-byte pattern 6c 69 61 74 (struct '<I'
+# 0x7461696c) at record+0x20 and decode {tag,VA,SIZE} at -0x20/-0x18/-0x10.
+#
+# Usage: wall2_recscan.py [VA_prefix_or_full_VA]
+# Prints every record and the size-matching memdesc {SIZE,0x03008000,PA}
+# found in the same page, and dumps the first words of each memdesc page so
+# semaphore windows can be identified by the release payload values.
+import struct, sys
+
+RAM = "/dev/shm/vgpu-guest-ram"
+TAG = struct.pack("<I", 0x7461696c)
+
+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 main():
+ want = None
+ if len(sys.argv) > 1:
+ want = int(sys.argv[1], 0)
+ img = open(RAM, "rb", buffering=0)
+ img.seek(0, 2); fsz = img.tell()
+ recs = []
+ pos = 0; CH = 64 << 20
+ while pos < fsz:
+ img.seek(pos); buf = img.read(min(CH, fsz - pos))
+ st = 0
+ while True:
+ i = buf.find(TAG, st)
+ if i < 0:
+ break
+ st = i + 1
+ if i >= 0x20:
+ tag, va, sz, z = struct.unpack_from("<QQQQ", buf, i - 0x20)
+ if 0x4000000 <= va < 0x100000000 and \
+ 0x1000 <= sz <= 0x1000000 and (sz & 0xfff) == 0 and z == 0:
+ if want is None or va == want or (va & ~0xfffff) == (want & ~0xfffff):
+ recs.append((off2gpa(pos + i - 0x20), tag, va, sz))
+ pos += CH
+ for gpa, tag, va, sz in sorted(recs, key=lambda r: r[2]):
+ page = gpa & ~0xfff
+ img.seek(gpa2off(page)); d = img.read(0x1000)
+ descs = []
+ for o in range(0, 0x1000 - 24, 8):
+ s2, f2 = struct.unpack_from("<QQ", d, o)
+ pa = struct.unpack_from("<Q", d, o + 16)[0]
+ if f2 == 0x03008000 and s2 == sz and 0x100000000 <= pa < 0x180000000:
+ descs.append(pa)
+ print("rec gpa=0x%x tag=0x%x va=0x%x size=0x%x" % (gpa, tag, va, sz))
+ for pa in descs:
+ img.seek(gpa2off(pa)); pd = img.read(0x20)
+ print(" desc pa=0x%x head=%s" % (pa, pd.hex(" ")))
+ return 0
+
+if __name__ == "__main__":
+ sys.exit(main())