diff options
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/guest-diag/guest_pin_stream.py | 40 |
1 files changed, 33 insertions, 7 deletions
diff --git a/tools/guest-diag/guest_pin_stream.py b/tools/guest-diag/guest_pin_stream.py index 35cbfb9..2c1a1a3 100644 --- a/tools/guest-diag/guest_pin_stream.py +++ b/tools/guest-diag/guest_pin_stream.py @@ -266,11 +266,17 @@ def _vmalloc_pages_for(kc, va): return 0 -def resolve_mem_pins(kc, mem, out, default_pages=16, va_lo=0, va_hi=0): +def resolve_mem_pins(kc, mem, out, default_pages=16, va_lo=0, va_hi=0, + page_off=0): """uvm_rm_mem kptr -> GPU-VA/GPA runs (direct map or page-table walk). va_lo/va_hi optionally restrict the emitted GPU VA range; the kcore - chain resolver targets the CE push-buffer window only. + chain resolver targets the CE push-buffer window only. page_off shifts + the vmap page paired with GPU data page k (the CE push-buffer vmap is + a 4097-page area = 1 header page + 4096 data pages, so data page k + lives at vmap page k+1; pairing k with k pinned the previous page and + every entry read returned the adjacent push - the second-session + content-rescue crawl). """ if not is_kern_ptr(mem): return 0 @@ -297,7 +303,7 @@ def resolve_mem_pins(kc, mem, out, default_pages=16, va_lo=0, va_hi=0): runs = [] cur = None for k in range(npages): - pa = kc.va_to_pa(cpu + k * 0x1000) + pa = kc.va_to_pa(cpu + (k + page_off) * 0x1000) if pa is None: if cur: runs.append(cur) @@ -318,6 +324,23 @@ def resolve_mem_pins(kc, mem, out, default_pages=16, va_lo=0, va_hi=0): return emitted +def mem_page_off(kc, mem): + """vmap-page offset for a uvm_rm_mem's GPU data pages. + + The CE push-buffer allocation's vmap is one page longer than its GPU + data window (16 MB of data + one leading page), so GPU data page k is + vmap page k+1. Content-validated against the host's rescue anchors + (five independent (va,pa) pairs, k=20..28, all delta +1). + """ + vas = [kc.read64(mem + 0x10 + i * 8) for i in range(16)] + cpu = next((v for v in vas if is_kern_ptr(v)), None) + if not cpu: + return 0 + if _direct_map_pa(kc, cpu) is not None: + return 0 + return 1 if _vmalloc_pages_for(kc, cpu) == 4097 else 0 + + def _emit_ring_pins(kc, gpu_va, entries_cpu, entries, out): """Pin the GPFIFO ring pages (and the pages after it, where the GPPUT buffer usually sits) from the ring's CPU mapping.""" @@ -444,7 +467,8 @@ def resolve_pb_pins(kc, pb, out): mem = kc.read64(pb + 8) if not mem: return 0 - return resolve_mem_pins(kc, mem, out, default_pages=64) + return resolve_mem_pins(kc, mem, out, default_pages=64, + page_off=mem_page_off(kc, mem)) # The CE push-buffer window is the one UVM region the client never maps into @@ -510,12 +534,14 @@ def resolve_pb_chain(kc, sem, out): continue RESOLVED_KC_PB.add(mem) n = resolve_mem_pins(kc, mem, out, default_pages=64, - va_lo=PB_CE_LO, va_hi=PB_CE_HI) + va_lo=PB_CE_LO, va_hi=PB_CE_HI, + page_off=mem_page_off(kc, mem)) try: with open('/tmp/guest_pin_stream.log', 'a') as f: f.write('%s kc-chain CE push-buffer mem=0x%x sem=0x%x ' - 'pin-runs=%d\n' - % (time.strftime('%T'), mem, sem, n)) + 'pin-runs=%d off=%d\n' + % (time.strftime('%T'), mem, sem, n, + mem_page_off(kc, mem))) except OSError: pass return found |
