diff options
| -rw-r--r-- | kernel/gsp_sema_service.c | 11 | ||||
| -rwxr-xr-x | tools/guest-diag/push_guest_tools.sh | 1 | ||||
| -rw-r--r-- | tools/guest-diag/trkinfo.py | 105 |
3 files changed, 116 insertions, 1 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c index a67107b..34b9ffd 100644 --- a/kernel/gsp_sema_service.c +++ b/kernel/gsp_sema_service.c @@ -1068,7 +1068,16 @@ static int svc_resolve_va(struct nv_vgpu_device *vgpu, u64 va, u64 *addr, { int ap = SVC_APERTURE_SYS; - if (svc_lookup(vgpu, va, addr, &ap)) + /* + * Semaphore I/O must never go through the vidmem window convention. + * The convention turns any VA above the window base into a vidmem + * offset, and the client's GPU semaphores are sysmem objects mapped + * into its address space at those same VAs: the write would land in + * the vidmem shadow instead of the page the client polls, silently + * losing the release. Trusted translations only; an unresolved + * semaphore is counted as a miss so the gap stays visible. + */ + if (svc_lookup_trusted(vgpu, va, addr, &ap)) return -ENOENT; *aperture = (ap == SVC_APERTURE_FB) ? 1 : 0; return 0; diff --git a/tools/guest-diag/push_guest_tools.sh b/tools/guest-diag/push_guest_tools.sh index 665011e..516c64a 100755 --- a/tools/guest-diag/push_guest_tools.sh +++ b/tools/guest-diag/push_guest_tools.sh @@ -25,6 +25,7 @@ push_b64 "$HERE/rmq_probe.c" /tmp/rmqp.c push_b64 "$HERE/ioctl_trace.c" /tmp/iot.c push_b64 "$REPO/tools/test/cuda_drv_test.c" /tmp/cdt.c push_b64 "$HERE/dumpctx.py" /tmp/dumpctx.py +push_b64 "$HERE/trkinfo.py" /tmp/trkinfo.py echo "[*] compiling in guest..." "$VMEXEC" exec "gcc -O1 -w -o /tmp/ptio /tmp/ptio.c && \ diff --git a/tools/guest-diag/trkinfo.py b/tools/guest-diag/trkinfo.py new file mode 100644 index 0000000..46b6a69 --- /dev/null +++ b/tools/guest-diag/trkinfo.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python3 +# gdb script (run with: sudo gdb -p <pid> -batch -x /tmp/trkinfo.py) +# Drills into the libcuda tracker the client spins on (the wait loop around +# libcuda+0x23f700): dumps the tracker object at p+0x9410, the semaphore +# object it references at +0x20, and the u32 semaphore memory that object +# points at (+0x10), plus the VMA that memory lives in. +import gdb + +def r32(a): + return int.from_bytes(gdb.selected_inferior().read_memory(a, 4).tobytes(), "little") +def r64(a): + return int.from_bytes(gdb.selected_inferior().read_memory(a, 8).tobytes(), "little") +def rmem(a, n): + return gdb.selected_inferior().read_memory(a, n).tobytes() + +out = gdb.execute("info proc mappings", to_string=True) +base = None +maps = [] +for line in out.splitlines(): + f = line.split() + if len(f) >= 5: + try: + lo = int(f[0], 16); hi = int(f[1], 16) + maps.append((lo, hi, line.strip())) + except Exception: + pass + if "libcuda" in line and "r-xp" in line and base is None: + base = int(f[0], 16) - int(f[3], 16) + +def vma_of(addr): + for lo, hi, line in maps: + if lo <= addr < hi: + return line + return "(none)" + +if base is None: + print("NO_LIBCUDA_BASE") + raise SystemExit +LO = base + 0x23f700 +HI = base + 0x23fd10 + +found = None +for t in gdb.selected_inferior().threads(): + t.switch() + f = gdb.newest_frame() + for i in range(14): + if f is None: + break + try: + pc = int(f.pc()) + except Exception: + pc = 0 + if LO <= pc < HI: + try: + ctx = int(f.read_register("rbx")) & 0xffffffffffffffff + except Exception: + ctx = None + found = (t.num, pc, ctx) + break + f = f.older() + if found: + break + +if not found: + print("NO_SPIN_FRAME") + raise SystemExit + +tid, pc, ctx = found +print("SPINNER tid=%s pc=0x%x ctx=0x%x" % (tid, pc, ctx)) +count = r32(ctx + 0x10) +ent = r64(ctx + 0x18) +print("count=%d entries=0x%x" % (count, ent)) +n = min(count, 32) +for i in range(n): + e = ent + i * 0x28 + typ = r32(e) + p = r64(e + 8) + v = r32(e + 0x10) + if typ != 1: + print("e%d type=%d p=0x%x v=0x%x (skip)" % (i, typ, p, v)) + continue + t = p + 0x9410 + try: + trk = rmem(t, 0x40) + except Exception as ex: + print("e%d tracker unreadable: %s" % (i, ex)) + continue + last = int.from_bytes(trk[0x10:0x18], "little") + cur = int.from_bytes(trk[0x18:0x20], "little") + sem = int.from_bytes(trk[0x20:0x28], "little") + print("e%d p=0x%x v=0x%x TRK=0x%x last=0x%x cur=0x%x sem_obj=0x%x" + % (i, p, v, t, last, cur, sem)) + try: + so = rmem(sem, 0x40) + print(" sem_obj[0:0x40]=%s" % so.hex()) + mem = int.from_bytes(so[0x10:0x18], "little") + print(" sem_mem=0x%x vma=%s" % (mem, vma_of(mem))) + try: + mv = rmem(mem & ~0xfff, 0x40) + print(" sem_page[0:0x40]=%s val@+0x%x=0x%x" % (mv.hex(), mem & 0xfff, r32(mem))) + except Exception as ex: + print(" sem_page unreadable: %s" % ex) + except Exception as ex: + print(" sem_obj unreadable: %s" % ex) +print("DONE_TRK")
\ No newline at end of file |
