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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
|
#!/usr/bin/env python3
# fence_assist.py - content-locate the client's ring pages in guest RAM from the
# service's own GPFIFO entry decodes (dmesg) and inject the TRUE VA->PA pairs
# via sema_map_add, so the pump's push reads (and its pushbuffer pairing) have
# a correct anchor.
import mmap, re, struct, subprocess, sys, threading, time
F = "/dev/shm/vgpu-guest-ram"
PARAM = "/sys/module/vgsp/parameters/sema_map_add"
def gpa_of(fo):
return fo if fo < 0x80000000 else fo - 0x80000000 + 0x100000000
def inject(va, pa, ln=0x1000, flag=1):
cmd = "echo 0x%x,0x%x,0x%x,%d > %s" % (va & ~0xfff, pa & ~0xfff, ln, flag, PARAM)
r = subprocess.run(["sudo", "sh", "-c", cmd], capture_output=True)
print("INJECT va=0x%x pa=0x%x : %s" % (va & ~0xfff, pa & ~0xfff,
"ok" if r.returncode == 0 else "FAIL"), flush=True)
def search(mm, pats, results):
CH = 8 << 20
size = len(mm)
off = 0
while off < size:
d = mm[off:off+CH]
for (name, pat) in pats.items():
if name in results:
continue
i = d.find(pat)
if i >= 0:
results[name] = gpa_of(off + i)
off += CH - 32
def main():
dur = float(sys.argv[1]) if len(sys.argv) > 1 else 120
f = open(F, "rb")
mm = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
end = time.time() + dur
pats = {} # name -> pattern bytes
ring_va = {} # name -> ring VA
seen = set() # raw entry lines processed
done = set() # injected names
print("# fence_assist start (%.0fs)" % dur, flush=True)
while time.time() < end:
try:
with open("/tmp/opencode/dmsg_w.txt", "r", errors="ignore") as df:
tail = df.read().splitlines()[-6000:]
out = "\n".join(tail)
except OSError:
out = ""
tail = []
tail = [ln for ln in tail if "sema-chan:" in ln or "sema-push" in ln]
cur = {}
for ln in tail:
m = re.search(r"sema-chan: entry\[(\d+)\] h=0x([0-9a-f]+) eng=\d+ raw=([0-9a-f]+) va=0x([0-9a-f]+)", ln)
if m:
idx, h, raw, va = int(m.group(1)), m.group(2), int(m.group(3), 16), int(m.group(4), 16)
cur.setdefault(h, {})[idx] = raw
if idx == 0:
ring_va[h] = va # entry[0] va is the push VA (ring_va - 0x20000)
for h, ents in cur.items():
key = (h, tuple(sorted(ents.items())))
if key in seen or len(ents) < 2:
continue
seen.add(key)
name = h
pat = b"".join(struct.pack("<Q", ents[i]) for i in sorted(ents)[:2])
pats[name] = pat
print("# channel h=0x%s entries=%s pattern ready" % (h, sorted(ents)), flush=True)
if pats:
results = {}
threads = []
# split the map among 4 threads
LO = 0x100000000; HI = 0x180000000
size = len(mm)
step = size // 4
class Sl(shim := object):
def __init__(self, a, b):
self.a, self.b = a, b
def worker(a, b):
CH = 8 << 20
off = a
while off < b:
if off < 0x80000000 and b <= 0x80000000: pass
d = mm[off:off+CH]
for (nm, p) in list(pats.items()):
if nm in results: continue
i = d.find(p)
if i >= 0:
results[nm] = gpa_of(off + i)
off += CH - 32
for k in range(4):
a = 0x80000000 + k * (0x80000000 // 4)
b = 0x80000000 + (k + 1) * (0x80000000 // 4)
t = threading.Thread(target=worker, args=(a, b))
t.start(); threads.append(t)
for t in threads: t.join()
for nm, gpa in results.items():
if nm in done: continue
done.add(nm)
# ring page content starts with entry[0]; the ring VA is the
# channel's gpfifo VA = we reconstruct: entry0 va is the push,
# ring = first "gpfifo=0x..." dmesg line for this h
m = re.search(r"sema-chan: h=0x%s eng=\d+ cid=\d+ gpfifo=0x([0-9a-f]+)" % nm, out)
rva = int(m.group(1), 16) if m else None
if rva:
print("RING FOUND h=0x%s gpfifo_va=0x%x -> gpa=0x%x" % (nm, rva, gpa), flush=True)
inject(rva, gpa, 0x1000)
time.sleep(0.6)
print("# fence_assist done, injected %d" % len(done), flush=True)
main()
|