summaryrefslogtreecommitdiffstats
path: root/tools/guest-diag
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-09-30 09:32:48 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-09-30 09:32:48 -0400
commit7f58bcaaad6a4b3cd89a3d3290adb58211219687 (patch)
treefc1dd1b7cfbc4d3e0c64ab45fcc216a81ed4b2ca /tools/guest-diag
parent0ca74e1719a88ea429999fdbdccbfe25564ad95d (diff)
downloadopen-iov-7f58bcaaad6a4b3cd89a3d3290adb58211219687.tar.gz
open-iov-7f58bcaaad6a4b3cd89a3d3290adb58211219687.zip
guest-diag: cycle monitor CPUs on kernel-VA translation failure
HMP x/gva2gpa translate with the selected vCPU's CR3; while that CPU runs user code under PTI the kernel half is hidden, so kernel-VA reads (the tracking-sem chain and the CE pushbuffer CPU alias) fail and the pin pass aborts. Try the other vCPUs before giving up: during an active CUDA client at least one CPU is in kernel mode, so the chain/pin work no longer require the client to be parked in sleep().
Diffstat (limited to 'tools/guest-diag')
-rw-r--r--tools/guest-diag/semfix_watch.py43
1 files changed, 39 insertions, 4 deletions
diff --git a/tools/guest-diag/semfix_watch.py b/tools/guest-diag/semfix_watch.py
index fa435ea..1bb4b39 100644
--- a/tools/guest-diag/semfix_watch.py
+++ b/tools/guest-diag/semfix_watch.py
@@ -96,11 +96,42 @@ class Qmp:
def hmp(self, line):
return self.cmd("human-monitor-command", **{"command-line": line}).get("return", "")
+ def ncpu(self):
+ if getattr(self, "_ncpu", 0):
+ return self._ncpu
+ n = 0
+ for line in self.hmp("info cpus").splitlines():
+ if line.strip().startswith("CPU #") or line.strip().startswith("* CPU #"):
+ n += 1
+ self._ncpu = n or 4
+ return self._ncpu
+
+ def _set_cpu(self, n):
+ """Select the monitor's current CPU. HMP `x`/`gva2gpa` translate with
+ the selected CPU's CR3: while that CPU runs user code under PTI the
+ kernel half is hidden, so a translation of a kernel VA fails. Cycling
+ CPUs until one is in kernel mode makes the reads work during active
+ clients (the client spins/sleeps in kernel code on at least one CPU)."""
+ if getattr(self, "_cpu", 0) == n:
+ return
+ self.hmp("cpu %d" % n)
+ self._cpu = n
+
+ def _cpu_order(self):
+ cur = getattr(self, "_cpu", 0)
+ return [cur] + [c for c in range(self.ncpu()) if c != cur]
+
def read64(self, addr, n=1, cache=True):
key = (addr, n)
if cache and key in self._cache:
return self._cache[key]
- out = self.hmp("x/%dgx 0x%x" % (n, addr))
+ out = ""
+ for c in self._cpu_order():
+ self._set_cpu(c)
+ out = self.hmp("x/%dgx 0x%x" % (n, addr))
+ m = re.search(r":(.*)$", out, re.S)
+ if m and re.findall(r"0x([0-9a-fA-F]+)", m.group(1))[:n]:
+ break
m = re.search(r":(.*)$", out, re.S)
if not m:
return []
@@ -110,9 +141,13 @@ class Qmp:
return vals
def gva2gpa(self, va):
- out = self.hmp("gva2gpa 0x%x" % va)
- m = re.search(r"gpa: 0x([0-9a-fA-F]+)", out)
- return int(m.group(1), 16) if m else None
+ for c in self._cpu_order():
+ self._set_cpu(c)
+ out = self.hmp("gva2gpa 0x%x" % va)
+ m = re.search(r"gpa: 0x([0-9a-fA-F]+)", out)
+ if m:
+ return int(m.group(1), 16)
+ return None
def is_kern(v):