summaryrefslogtreecommitdiffstats
path: root/tools/guest-diag/wall2/host_resolve.py
blob: 258d994d50c9d1e9bc6a53eb550c4143fef7c40f (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
#!/usr/bin/env python3
# host_resolve.py - host-side push resolver: read the service's sema-pushall
# lines (pa=0x0, non-zero first8), find the content page in
# /dev/shm/vgpu-guest-ram by the push's first8 bytes, and inject the page
# mapping via sema_map_add. Replaces the guest-side kcore walker: the
# service already tells us push VA + content prefix, the host RAM file has
# the bytes.
import mmap, os, re, subprocess, sys, time

RAM = "/dev/shm/vgpu-guest-ram"
PARAM = "/sys/module/vgsp/parameters/sema_map_add"
BASE = 0x80000000  # file offset = pa - BASE

def inject(va_page, pa):
    cmd = "echo 0x%x,0x%x,0x1000,1 > %s" % (va_page, pa, PARAM)
    r = subprocess.run(["sudo", "sh", "-c", cmd], capture_output=True)
    ok = r.returncode == 0
    print("inject 0x%x -> 0x%x : %s" % (va_page, pa, "ok" if ok else r.stderr.decode().strip()))
    return ok

def main():
    seen = set()
    f = open(RAM, "rb")
    mm = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
    injected = 0
    deadline = time.time() + (float(sys.argv[1]) if len(sys.argv) > 1 else 600)
    while time.time() < deadline and injected < 40:
        out = subprocess.run(["sudo", "dmesg"], capture_output=True).stdout.decode(errors="ignore")
        lines = [l for l in out.splitlines() if "sema-pushall" in l]
        for l in lines[-800:]:
            m = re.search(r"va=(0x[0-9a-f]+) pa=0x0 len=\d+ allow=\d trusted=\d first8=([0-9a-f]{8}) ([0-9a-f]{8})", l)
            if not m:
                continue
            va = int(m.group(1), 16)
            w0, w1 = int(m.group(2), 16), int(m.group(3), 16)
            if (w0, w1) == (0, 0) and (w0 == 0 or w1 == 0):
                pass
            if w0 == 0 and w1 == 0:
                continue
            key = (va & ~0xFFF, w0, w1)
            if key in seen:
                continue
            pat = w0.to_bytes(4, "little") + w1.to_bytes(4, "little")
            inpage = va & 0xFFF
            # search with the in-page offset constraint
            start = 0
            hit = None
            while True:
                i = mm.find(pat, start)
                if i < 0:
                    break
                if (i & 0xFFF) == inpage:
                    hit = i
                    break
                start = i + 1
            if hit is None:
                # fallback: any hit within the same page offset modulo
                start = 0
                while True:
                    i = mm.find(pat, start)
                    if i < 0:
                        break
                    hit = i
                    break
                # proceed only if the constraint is loose? no - skip
                hit = None
            if hit is None:
                seen.add(key)
                print("no match for va=0x%x first8=%08x %08x" % (va, w0, w1))
                continue
            pa = (hit & ~0xFFF) + BASE
            seen.add(key)
            if inject(va & ~0xFFF, pa):
                injected += 1
        time.sleep(0.5)
    mm.close()
    f.close()
    print("done: injected=%d" % injected)

if __name__ == "__main__":
    main()