#!/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())