summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/guest-diag/guest_pin_stream.py100
1 files changed, 99 insertions, 1 deletions
diff --git a/tools/guest-diag/guest_pin_stream.py b/tools/guest-diag/guest_pin_stream.py
index ddc7098..a645a86 100644
--- a/tools/guest-diag/guest_pin_stream.py
+++ b/tools/guest-diag/guest_pin_stream.py
@@ -789,6 +789,87 @@ def resolve_va_client_mem(pid, ent_va, off, ln, out):
os.close(mfd)
+def _strict_kvm_sweep(kc, ent_va, off, ln, out):
+ """Kernel-vmap sweep for an anchor with no known-family page index.
+
+ SESSION 153-CONTINUED-74: mirrors the k == 0 known-family path (the
+ resolver that found the r1126 0x3200000 macro window) but works for ANY
+ anchor outside PB_GL_FAMILIES. Every candidate window passes the host's
+ own full parse (`_window_accept`) before a single pin is emitted, so a
+ false positive is impossible by construction; the cheap per-page prefix
+ walk rejects arbitrary data after a few words. Bounded: at most
+ 8192 candidate windows and at most 64 pages of a window (the same caps
+ as resolve_va_client_mem).
+
+ Areas swept: the nv_vm_map_pages vmap set (the historical resolver) plus
+ the nvidia os_alloc_mem vmalloc areas (`vpages`), which the r1156 probe
+ showed can be large (571 pages in one area) and are completely outside
+ _nv_vmap_areas' filter. A window is only emitted for an area whose pages
+ are all present in the CPU alias.
+ """
+ import re as _re
+
+ page = ent_va & ~0xFFF
+ need = (off + ln + 0xFFF) // 0x1000
+ if ln <= 0 or ln > 0x40000 or need > 64:
+ return False
+ areas = list(_nv_vmap_areas(kc))
+ try:
+ for line in open("/proc/vmallocinfo"):
+ if "[nvidia]" not in line or "vmalloc" not in line:
+ continue
+ if "nv_vm_map_pages" in line or "phys=" in line:
+ continue
+ if "os_map_kernel_space" in line or "ioremap" in line:
+ continue
+ m = _re.match(r'0x([0-9a-f]+)-0x([0-9a-f]+)\s+(\d+)', line)
+ if not m:
+ continue
+ lo = int(m.group(1), 16)
+ hi = int(m.group(2), 16)
+ pages = (hi - lo) >> 12
+ if pages >= need and lo < hi:
+ areas.append((lo, hi, pages))
+ except OSError:
+ pass
+ tried = 0
+ for (lo, _hi, pages) in areas:
+ for adj in range(0, max(1, pages - need + 1)):
+ tried += 1
+ if tried > 8192:
+ return False
+ cpu = lo + adj * 0x1000
+ first = kc.read(cpu, 0x1000)
+ if not first:
+ continue
+ if any(first) and not _prefix_walk_ok(first, off):
+ continue
+ buf = _read_window(kc, cpu, off, ln)
+ if buf is None:
+ continue
+ acc, mode = _window_accept(buf, ln)
+ if not acc:
+ continue
+ pas = []
+ for j in range(need):
+ vpa = kc.va_to_pa(cpu + j * 0x1000)
+ if vpa is None:
+ pas = None
+ break
+ pas.append(vpa)
+ if not pas:
+ continue
+ for j, vpa in enumerate(pas):
+ out.append("0x%x,0x%x,1\n" % (page + j * 0x1000, vpa))
+ dbg("demand-va: 0x%x -> pa=0x%x (%s vmap parse %u B ok"
+ " pages=%u area=0x%x adj=%+d)"
+ % (page, pas[0], mode, ln, need, lo, adj))
+ return True
+ dbg("demand-va: 0x%x strict vmap sweep failed (%u B, %u windows)"
+ % (page, ln, tried))
+ return False
+
+
def resolve_va_strict(kc, ent_va, off, ln, out, pid=None):
"""Demand pin validated by the host's exact full-parse of [ent_va, +ln).
@@ -811,12 +892,29 @@ def resolve_va_strict(kc, ent_va, off, ln, out, pid=None):
# SESSION 153-CONTINUED-64e: an anchor outside the known families
# (r1124: the hold moved to a 153600-byte push at 0x3200000) has no
# identity page index; only the client-mapping sweep can resolve it.
+ #
+ # SESSION 153-CONTINUED-74: the unknown-family branch skipped the
+ # kernel-vmap sweep entirely - the known-family path has always tried
+ # it, and it is the resolver that found the r1126 0x3200000 macro
+ # window (a KERNEL-mapped allocation no process pagemap covers). The
+ # r1156 held push (va=0x3e4ccccc, 123916 B) failed here after only
+ # the client-mem attempt ("strict unknown-family client-mem failed"),
+ # so a kernel-resident window could never be found for any anchor
+ # outside PB_GL_FAMILIES. Try the vmap sweep first (same full-parse
+ # gate; strictly additive - a failed sweep costs the bounded reads
+ # and falls through to the client-mem path unchanged).
+ try:
+ if _strict_kvm_sweep(kc, ent_va, off, ln, out):
+ return True
+ except Exception:
+ pass
try:
if resolve_va_client_mem(pid, ent_va, off, ln, out):
return True
except Exception:
pass
- dbg("demand-va: 0x%x strict unknown-family client-mem failed" % page)
+ dbg("demand-va: 0x%x strict unknown-family (vmap+client-mem) failed"
+ % page)
return False
gl_hi = next(hi for lo, hi in PB_GL_FAMILIES if lo <= page < hi)
k = (page - gl_base) >> 12