summaryrefslogtreecommitdiffstats
path: root/tools/guest-diag/wall2/find_push.py
blob: 4bf8ccc066d9df6d8320a7771ae849090407fd6c (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
#!/usr/bin/env python3
# find_push.py - locate the client's CPU mapping that owns the GR ring page
# (GPA 0x12C600000 as content-located on the host) and print the CPU VA<->
# GPU VA correspondence for the low GPU VAs (0x4ca0000 etc).
import os, struct, sys, subprocess, mmap, time

RING_GPA = 0x12C600000
PUSH_GVA = 0x4ca0000
RING_GVA = 0x4cc0000

def pids():
    out = subprocess.run(["pgrep", "-x", "vk_frame"], capture_output=True).stdout
    return [int(x) for x in out.split()]

def read_pagemap(pid, va):
    try:
        with open("/proc/%d/pagemap" % pid, "rb") as f:
            f.seek((va // 4096) * 8)
            d = f.read(8)
        if len(d) < 8:
            return None
        e = int.from_bytes(d, "little")
        if not (e >> 63) & 1:
            return None
        return (e & ((1 << 55) - 1)) << 12
    except OSError:
        return None

def main():
    for pid in pids():
        print("pid=%d" % pid)
        try:
            maps = open("/proc/%d/maps" % pid).read().splitlines()
        except OSError:
            continue
        for line in maps:
            p = line.split()
            if len(p) < 6 or "nvidia" not in p[-1]:
                continue
            lo, hi = [int(x, 16) for x in p[0].split("-")]
            if hi - lo > 0x1000000:
                continue
            # scan pages; look for RING_GPA
            for va in range(lo, hi, 0x10000):
                for off in range(0, 0x10000, 0x1000):
                    pa = read_pagemap(pid, va + off)
                    if pa == RING_GPA:
                        print("FOUND ring page: cpu_va=0x%x (map 0x%x-0x%x %s)" % (va+off, lo, hi, p[-1]))
                        delta_cpu = (va + off) - RING_GVA
                        push_cpu = PUSH_GVA + delta_cpu
                        print("  delta_cpu = 0x%x" % delta_cpu)
                        for gva in (PUSH_GVA, PUSH_GVA+0x1000, 0x4ca059c, 0x4ca0980, 0x4ca5870, 0x4903000):
                            cva = gva + delta_cpu
                            pa2 = read_pagemap(pid, cva & ~0xfff)
                            print("  gva=0x%x -> cpu=0x%x -> pa=%s" % (gva, cva, hex(pa2) if pa2 else None))
                        return
        print("  ring GPA 0x%x not found in this pid's mappings" % RING_GPA)

main()