summaryrefslogtreecommitdiffstats
path: root/tools/guest-diag/wall2/wall2_recscan.py
blob: 7bc4e2c9db44e8677caaf9b408ce64d1eddb1bfe (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
#!/usr/bin/env python3
# wall2_recscan.py - scan the guest RAM for the RM's low-aperture window
# records and their memdesc PAs.
#
# Record layout (verified r685/r686): 0x40-byte stride
#   {u64 tag; u64 VA; u64 SIZE; u64 0; u32 0x7461696c ("tail" as a u32 -
#    on disk the BYTES are "liat"); u32 0}
# The tag is NOT the byte string "tail" - searching for b'tail' finds
# nothing; search for the 4-byte pattern 6c 69 61 74 (struct '<I'
# 0x7461696c) at record+0x20 and decode {tag,VA,SIZE} at -0x20/-0x18/-0x10.
#
# Usage: wall2_recscan.py [VA_prefix_or_full_VA]
# Prints every record and the size-matching memdesc {SIZE,0x03008000,PA}
# found in the same page, and dumps the first words of each memdesc page so
# semaphore windows can be identified by the release payload values.
import struct, sys

RAM = "/dev/shm/vgpu-guest-ram"
TAG = struct.pack("<I", 0x7461696c)

def off2gpa(off):
    return off if off < 0x80000000 else 0x100000000 + (off - 0x80000000)

def gpa2off(pa):
    if pa < 0x80000000:
        return pa
    if pa < 0x180000000:
        return 0x80000000 + (pa - 0x100000000)
    return None

def main():
    want = None
    if len(sys.argv) > 1:
        want = int(sys.argv[1], 0)
    img = open(RAM, "rb", buffering=0)
    img.seek(0, 2); fsz = img.tell()
    recs = []
    pos = 0; CH = 64 << 20
    while pos < fsz:
        img.seek(pos); buf = img.read(min(CH, fsz - pos))
        st = 0
        while True:
            i = buf.find(TAG, st)
            if i < 0:
                break
            st = i + 1
            if i >= 0x20:
                tag, va, sz, z = struct.unpack_from("<QQQQ", buf, i - 0x20)
                if 0x4000000 <= va < 0x100000000 and \
                   0x1000 <= sz <= 0x1000000 and (sz & 0xfff) == 0 and z == 0:
                    if want is None or va == want or (va & ~0xfffff) == (want & ~0xfffff):
                        recs.append((off2gpa(pos + i - 0x20), tag, va, sz))
        pos += CH
    for gpa, tag, va, sz in sorted(recs, key=lambda r: r[2]):
        page = gpa & ~0xfff
        img.seek(gpa2off(page)); d = img.read(0x1000)
        descs = []
        for o in range(0, 0x1000 - 24, 8):
            s2, f2 = struct.unpack_from("<QQ", d, o)
            pa = struct.unpack_from("<Q", d, o + 16)[0]
            if f2 == 0x03008000 and s2 == sz and 0x100000000 <= pa < 0x180000000:
                descs.append(pa)
        print("rec gpa=0x%x tag=0x%x va=0x%x size=0x%x" % (gpa, tag, va, sz))
        for pa in descs:
            img.seek(gpa2off(pa)); pd = img.read(0x20)
            print("    desc pa=0x%x head=%s" % (pa, pd.hex(" ")))
    return 0

if __name__ == "__main__":
    sys.exit(main())