From cc6c198a234cf3a42ae565328fe83d490faf1f02 Mon Sep 17 00:00:00 2001 From: Arthur Hanson Rasmusson Date: Sat, 31 Oct 2026 10:50:08 -0400 Subject: vgsp: replay/block capacity 1024->2048 words (r1126 drop was arithmetic: window 390+prelude 901+sa 47 > 1024), two-page module pushbuffer (VA_PB2 0x102000 small-PT 0x102, CE SRC->0x109000, warm-sem probe page 0x10a000), gsp_phys_gr_pb_copy page-wise, static_asserts - planted verified (r1127 pb page2+probe planted before first fetch); >4KB path never exercised (5 boots beef never forwarded; walk PA 0x23921d000=8.89GB outside 8GB image); guest setup push NOT in guest RAM (ram_content_pin accepted 0/74); next: drop+re-walk src=4 all-zero reads, reject PA>guest-RAM top - SESSION 153 r1127 --- tools/guest-diag/ram_content_pin.py | 160 ++++++++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100755 tools/guest-diag/ram_content_pin.py (limited to 'tools/guest-diag') diff --git a/tools/guest-diag/ram_content_pin.py b/tools/guest-diag/ram_content_pin.py new file mode 100755 index 0000000..d521d91 --- /dev/null +++ b/tools/guest-diag/ram_content_pin.py @@ -0,0 +1,160 @@ +#!/usr/bin/env python3 +"""Host-side CONTENT-based resolver for demanded GR setup-push windows. + +SESSION 153-CONTINUED-66. The client's GL setup pushes (and its 0x3200000 / +0x6f00000 macro-upload windows) live in allocations that have NO kernel vmap +and NO client CPU mapping on the failing boots: the guest scanner's area+idx +identity sweep and its client-mem sweep both fail (`strict unknown-family +client-mem failed`, `strict parse failed (N B, M windows tried)`), so the +armed GR setup hold never lands its pin and the MME prelude stays 0. + +The bytes ARE in guest RAM - a RAM-wide pattern scan finds the MME/SA +prelude runs (`0xa0100045` = INC 0x114 x16 args, `0x20020047` = INC 0x11c x2 +args). This tool therefore resolves a demanded window from CONTENT instead of +identity: + + 1. read the demand set the service publishes (debugfs sema_setup_demand: + "0xVA 0xOFF LEN" per line); + 2. locate every physical page in the guest RAM image that carries an + MME/SA prelude run signature; + 3. for each candidate physical page P and each window page index j, read + the EXACT window bytes the host would read - [P - j*0x1000 + OFF, +LEN) + - straight out of the RAM image and run the host's own method-stream + acceptance on them; + 4. inject the validated page run into the service through the + sema_map_add module parameter (0xVA,0xPA,LEN,1), so the host read + resolves the demanded window from real content. + +Nothing is injected unless the host's parser accepts the exact bytes, so a +wrong candidate cannot mis-resolve a demand VA (the r1120 lesson). + +Usage: ram_content_pin.py [ram-image] [seconds] +""" +import importlib.util +import mmap +import os +import re +import subprocess +import sys +import time + +import numpy as np + +RAM = sys.argv[1] if len(sys.argv) > 1 else '/dev/shm/vgpu-guest-ram' +SECS = float(sys.argv[2]) if len(sys.argv) > 2 else 120.0 +DEMAND = '/sys/kernel/debug/vgsp/sema_setup_demand' +MAPADD = '/sys/module/vgsp/parameters/sema_map_add' +GPS = ('/home/rmcore/Git/integdev_gpu_drv/open-iov/tools/guest-diag/' + 'guest_pin_stream.py') +SIGS = (0xa0100045, 0x20020047) # INC 0x114 x16, INC 0x11c x2 +PAGE = 0x1000 +MAXHITS = 4096 + + +def log(msg): + print('[%s] %s' % (time.strftime('%H:%M:%S'), msg), flush=True) + + +def load_accept(): + spec = importlib.util.spec_from_file_location('gps', GPS) + mod = importlib.util.module_from_spec(spec) + spec.loader.exec_module(mod) + return mod._window_accept + + +def read_demand(): + out = [] + try: + with open(DEMAND) as f: + for ln in f: + m = re.match(r'0x([0-9a-fA-F]+)\s+0x([0-9a-fA-F]+)\s+(\d+)', + ln.strip()) + if not m: + continue + out.append((int(m.group(1), 16), int(m.group(2), 16), + int(m.group(3)))) + except OSError: + pass + return out + + +def inject(va_page, pa_page, ln): + cmd = "printf '0x%x,0x%x,0x%x,1' > %s" % (va_page, pa_page, ln, MAPADD) + try: + r = subprocess.run(['sudo', '-n', 'sh', '-c', cmd], + capture_output=True, text=True, timeout=10) + except subprocess.TimeoutExpired: + return False + return r.returncode == 0 + + +def main(): + accept = load_accept() + f = open(RAM, 'rb') + mm = mmap.mmap(f.fileno(), 0, prot=mmap.PROT_READ) + size = len(mm) + a32 = np.frombuffer(mm, dtype=np.uint32) + hits = [] + for sig in SIGS: + idx = np.flatnonzero(a32 == sig) + log('sig 0x%08x: %d hit(s)' % (sig, idx.size)) + for i in idx[:MAXHITS]: + hits.append(int(i) * 4) + del a32 + hits = sorted(set(h >> 12 for h in hits)) + log('candidate physical pages: %d (ram image %d MB)' + % (len(hits), size >> 20)) + if not hits: + return 1 + seen = set() + t0 = time.time() + while time.time() - t0 < SECS: + dem = read_demand() + for (va, off, ln) in dem: + key = (va & ~(PAGE - 1), ln) + if key in seen: + continue + if ln <= 0 or ln > 0x40000: + continue + need = (off + ln + PAGE - 1) // PAGE + if need > 64: + continue + va_page = va & ~(PAGE - 1) + found = None + for P in hits: + for j in range(need): + P0 = P - j * PAGE + if P0 < 0 or P0 + off + ln > size: + continue + buf = mm[P0 + off:P0 + off + ln] + try: + ok, mode = accept(buf, ln) + except Exception: + ok = False + if ok: + found = (P0, mode) + break + if found: + break + if not found: + log('demand va=0x%x off=0x%x len=%d: no content candidate' + % (va, off, ln)) + seen.add(key) + continue + P0, mode = found + if inject(va_page, P0, need * PAGE): + log('demand va=0x%x off=0x%x len=%d -> pa=0x%x (%s parse, ' + 'pages=%d) INJECTED' + % (va, off, ln, P0, mode, need)) + seen.add(key) + else: + log('demand va=0x%x: injection refused by the module param' + % va) + seen.add(key) + time.sleep(1.0) + log('done') + return 0 + + +if __name__ == '__main__': + sys.exit(main()) -- cgit v1.2.3