summaryrefslogtreecommitdiffstats
path: root/tools/guest-diag/wall2/pdbtick.py
blob: d65b79db7dec77109516bbdcf49e79e00f2babb3 (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
#!/usr/bin/env python3
# pdbtick.py - content-locate the GR0 ring page (deterministic first three
# GPFIFO entries) in the guest RAM file, then hand the verified
# {ring VA -> ring PA} pair to the service (sema_pdb_discover), which
# verifies the parked COPY_SERVER_PDES candidates and falls back to the
# vidmem walk-root sweep. Runs while the client is alive.
import mmap, struct, subprocess, sys, threading, time

F = "/dev/shm/vgpu-guest-ram"
PARAM = "/sys/module/vgsp/parameters/sema_pdb_discover"
PAT = struct.pack("<QQQ", 0x0005980004ca0000, 0x8000040004ca0598,
                  0x0003d00004ca059c)
RING_VA = 0x4cc0000

def gpa_of(x):
    return x if x < 0x80000000 else x - 0x80000000 + 0x100000000

def main():
    fobj = open(F, "rb")
    mm = mmap.mmap(fobj.fileno(), 0, access=mmap.ACCESS_READ)
    size = len(mm)
    nthr = 8
    step = size // nthr
    res = []
    lock = threading.Lock()
    def worker(a, b):
        CH = 8 << 20
        off = a
        while off < b:
            d = mm[off:off + CH]
            i = d.find(PAT)
            while i >= 0:
                with lock:
                    res.append(off + i)
                i = d.find(PAT, i + 1)
            off += CH - 64
    ts = []
    for k in range(nthr):
        a = k * step
        b = (k + 1) * step if k < nthr - 1 else size
        t = threading.Thread(target=worker, args=(a, b)); t.start(); ts.append(t)
    for t in ts: t.join()
    if not res:
        print("RING NOT FOUND")
        return None
    hits = [gpa_of(x) for x in res]
    print("ring candidates:", [hex(h) for h in hits], flush=True)
    for gpa in hits:
        cmd = "echo 0x%x,0x%x > %s" % (RING_VA, gpa, PARAM)
        r = subprocess.run(["sudo", "sh", "-c", cmd], capture_output=True)
        print("sema_pdb_discover 0x%x,0x%x rc=%d" % (RING_VA, gpa, r.returncode), flush=True)
    return hits


def loop():
    import time as _t
    dur = float(sys.argv[1]) if len(sys.argv) > 1 else 120
    end = _t.time() + dur
    fired = set()
    while _t.time() < end:
        hits = main()
        if hits:
            new = [h for h in hits if h not in fired]
            if new:
                fired.update(new)
        _t.sleep(1.0)
    print("# pdbtick end", flush=True)

loop()