diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-09-30 09:32:48 -0400 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-09-30 09:32:48 -0400 |
| commit | 2ae04a244ee80f4c3bc8a9e15d2271e7fee554de (patch) | |
| tree | 7ab5ad42f19499a03cb72d2b2fb670ddc630190f /tools/guest-diag/semfix_watch.py | |
| parent | cbc4f39f447cd5f7508ce1f4066cb25c373e627d (diff) | |
| download | open-iov-2ae04a244ee80f4c3bc8a9e15d2271e7fee554de.tar.gz open-iov-2ae04a244ee80f4c3bc8a9e15d2271e7fee554de.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/semfix_watch.py')
| -rw-r--r-- | tools/guest-diag/semfix_watch.py | 43 |
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): |
