summaryrefslogtreecommitdiffstats
path: root/tools/guest-diag/wall2/unwait2.py
blob: cd4169bad326cddbf997d9ab9e48ac242c5fb3d0 (plain)
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
#!/usr/bin/env python3
# unwait2.py - no-ptrace guest-side harness:
#  (a) writes 1 to any zero u32 at +0x80 of every 0x4000-byte rw-s nvidia
#      mapping of EVERY live vk_frame;
#  (b) scans each live vk_frame's anonymous/heap rw-p mappings (16-byte
#      aligned) for marker slots {u32@0==0, u16@+0xe==0xffff} and clears
#      u16@+0xe to 0 (the instance-phase pending markers the t105 gdb used
#      to clear). No ptrace anywhere.
import os, subprocess, sys, time
DUR = float(sys.argv[1]) if len(sys.argv) > 1 else 600
def pids():
    try:
        out = subprocess.run(["pgrep", "-x", "vk_frame"], capture_output=True).stdout
        return [int(x) for x in out.split()]
    except Exception:
        return []
def rd(fd, off, n):
    try:
        os.lseek(fd, off, 0)
        return os.read(fd, n)
    except Exception:
        return b""
def wr(fd, off, data):
    try:
        os.lseek(fd, off, 0)
        os.write(fd, data)
        return True
    except Exception:
        return False
wlog = set(); mlog = set()
end = time.time() + DUR
last_scan = 0.0
while time.time() < end:
    for pid in pids():
        try:
            fd = os.open("/proc/%d/mem" % pid, os.O_RDWR)
        except Exception:
            continue
        try:
            for line in open("/proc/%d/maps" % pid):
                p = line.split()
                if len(p) < 6 or "nvidia" not in p[-1] or "rw-s" not in p[1]:
                    continue
                lo, hi = [int(x, 16) for x in p[0].split("-")]
                if hi - lo != 0x4000:
                    continue
                wa = lo + 0x80
                v = rd(fd, wa, 4)
                if len(v) == 4 and v == b"\x00\x00\x00\x00":
                    if wr(fd, wa, b"\x01\x00\x00\x00"):
                        k = (pid, wa)
                        if k not in wlog:
                            wlog.add(k)
                            print("WORDWROTE pid=%d va=0x%x" % (pid, wa), flush=True)
        except Exception:
            pass
        if time.time() - last_scan > 1.5:
            budget = 64
            try:
                for line in open("/proc/%d/maps" % pid):
                    p = line.split()
                    if len(p) < 6 or p[1] != "rw-p":
                        continue
                    path = p[-1]
                    if path.startswith("/") and "nvidia" not in path and path != "[heap]":
                        continue
                    lo, hi = [int(x, 16) for x in p[0].split("-")]
                    if hi - lo > 0x10000000:
                        hi = lo + 0x10000000
                    off = lo
                    while off < hi:
                        chunk = rd(fd, off, 0x100000)
                        if len(chunk) < 32:
                            break
                        j = 0
                        while j + 16 <= len(chunk):
                            if chunk[j:j+4] == b"\x00\x00\x00\x00" and chunk[j+0xe:j+0x10] == b"\xff\xff":
                                wa = off + j + 0xe
                                if (pid, wa) not in mlog:
                                    if wr(fd, wa, b"\x00\x00"):
                                        mlog.add((pid, wa))
                                        print("MARKCLR pid=%d va=0x%x" % (pid, wa), flush=True)
                            j += 16
                        off += 0x100000
                        budget -= 1
                        if budget <= 0:
                            break
                    if budget <= 0:
                        break
            except Exception:
                pass
            last_scan = time.time()
        os.close(fd)
    time.sleep(0.4)
print("UNWAIT2-DONE", flush=True)