diff options
Diffstat (limited to 'tools/guest-diag')
| -rw-r--r-- | tools/guest-diag/semfix_watch.py | 70 |
1 files changed, 40 insertions, 30 deletions
diff --git a/tools/guest-diag/semfix_watch.py b/tools/guest-diag/semfix_watch.py index 8fd534d..c0ce072 100644 --- a/tools/guest-diag/semfix_watch.py +++ b/tools/guest-diag/semfix_watch.py @@ -197,16 +197,22 @@ def resolve_pushbuffer(q, sem): def pin_pushbuffer(q, gpu_vas, cpu, gpa): + """Pin the whole pushbuffer with *per-page* translations (the layout is + not linear across the allocation: page 32 jumped on a real client).""" pinned = 0 for gv in gpu_vas: + miss = 0 for i in range(PUSHBUF_MAX_PAGES): - if i in (0, 1, 2, 3, 8, 32, 128, 512): - g = q.gva2gpa(cpu + i * 0x1000) - if g != gpa - i * 0x1000: - print("semfix: pushbuf va=0x%x: page %d not linear (gpa=%s), stop at %d" - % (gv, i, hex(g) if g else None, pinned), flush=True) + g = q.gva2gpa(cpu + i * 0x1000) + if not g: + miss += 1 + if miss >= 32: + print("semfix: pushbuf va=0x%x: 32 unmapped pages at %d, stop (%d pinned)" + % (gv, i, pinned), flush=True) return pinned - if not pin(gv + i * 0x1000, gpa - i * 0x1000): + continue + miss = 0 + if not pin(gv + i * 0x1000, g): print("semfix: pushbuf va=0x%x: pin failed at page %d" % (gv, i), flush=True) return pinned pinned += 1 @@ -220,22 +226,28 @@ def main(): q = Qmp(QMP_SOCK) seen = set() seen_pb = set() - pb_done = False + pinned_ranges = set() + + def pin_range_once(gpu_vas, cpu, gpa): + key = tuple(gpu_vas), cpu + if key in pinned_ranges: + return + pinned_ranges.add(key) + pin_pushbuffer(q, gpu_vas, cpu, gpa) + print("semfix: watching (interval %.1fs)" % interval, flush=True) while True: sems, pbs = guest_trace() - if not pb_done: - for pb in pbs - seen_pb: - seen_pb.add(pb) - try: - gpu_vas, cpu, gpa = resolve_pb_ptr(q, pb) - except Exception as e: - print("semfix: pb=0x%x resolve failed: %s" % (pb, e), flush=True) - continue - if gpu_vas: - pin_pushbuffer(q, gpu_vas, cpu, gpa) - pb_done = True - break + for pb in pbs - seen_pb: + seen_pb.add(pb) + try: + gpu_vas, cpu, gpa = resolve_pb_ptr(q, pb) + except Exception as e: + print("semfix: pb=0x%x resolve failed: %s" % (pb, e), flush=True) + continue + if gpu_vas: + pin_range_once(gpu_vas, cpu, gpa) + else: print("semfix: pb=0x%x no pushbuffer rm_mem (retry)" % pb, flush=True) for sem in sems - seen: try: @@ -251,17 +263,15 @@ def main(): ok = pin(gv, gpa) print("semfix: sem=0x%x va=0x%x -> gpa=0x%x pin=%s" % (sem, gv, gpa, "ok" if ok else "FAILED"), flush=True) - if not pb_done: - try: - gpu_vas, cpu, gpa = resolve_pushbuffer(q, sem) - except Exception as e: - print("semfix: pushbuf resolve failed: %s" % e, flush=True) - gpu_vas = [] - if gpu_vas: - pin_pushbuffer(q, gpu_vas, cpu, gpa) - pb_done = True - else: - print("semfix: pushbuf not found near sem=0x%x (retry)" % sem, flush=True) + try: + gpu_vas, cpu, gpa = resolve_pushbuffer(q, sem) + except Exception as e: + print("semfix: pushbuf resolve failed: %s" % e, flush=True) + gpu_vas = [] + if gpu_vas: + pin_range_once(gpu_vas, cpu, gpa) + else: + print("semfix: pushbuf not found near sem=0x%x (retry)" % sem, flush=True) time.sleep(interval) |
