summaryrefslogtreecommitdiffstats
path: root/tools/guest-diag/tick_gen.py
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-11-12 20:01:04 -0500
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-11-12 20:01:04 -0500
commit725898e44666b4def396f7f3c5e50712fd37aa33 (patch)
tree261bba910db49036624cc2cf89baac6554a6f58d /tools/guest-diag/tick_gen.py
parent800c108f9d2463066a221a0e4ff56867304551a6 (diff)
downloadopen-iov-725898e44666b4def396f7f3c5e50712fd37aa33.tar.gz
open-iov-725898e44666b4def396f7f3c5e50712fd37aa33.zip
vgsp: stop fabricating 0xFFFF into the nvPush error notifier; add r1780 GL ops tooling
The uncommitted keep-alive change wrote 0xFFFF into slot 0's status field (u16 at notifier+0x0e) on the X DDX / GLX kick-idle channel families. Ground truth (570.144 reference sources + stock nvidia_drv.so disassembly): slot 0 of an nvPush notifier block is the ERROR notifier; nvPushCheckChannelError reads that status and 0xFFFF aborts every nvPushWaitForNotifier/idle wait as a channel error. There is no pb_kickIfIdle in 570.144 - the DDX DMA-idle test reads the progress-tracker semaphore word, not this slot. Leave slot 0 untouched; keep the 0x8000->0 completion ack for the remaining slots and the r864 0xFFFF/0x8000 completion on the RC-watchdog/beef families. Correct the CONT.408/409 comments accordingly. New host/guest tooling: gpa.py (QMP gva2gpa), tick_gen.py (guest-RM timer BO tick), guest_mode.sh (shared nvClip modeNum reader), gl_verify.sh (X/GLX bring-up with ScreenInit-lottery retries), push_gl_tools.sh, the gzdoom_pbuf_run.sh guest recipe and the test_tri SDL2 harness validation program; ignore tools/guest-diag/build/.
Diffstat (limited to 'tools/guest-diag/tick_gen.py')
-rwxr-xr-xtools/guest-diag/tick_gen.py97
1 files changed, 97 insertions, 0 deletions
diff --git a/tools/guest-diag/tick_gen.py b/tools/guest-diag/tick_gen.py
new file mode 100755
index 0000000..d2c176b
--- /dev/null
+++ b/tools/guest-diag/tick_gen.py
@@ -0,0 +1,97 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright (c) 2026 Open-IOV contributors
+# tick_gen.py - keep the guest-RM timer tick page live in the host-side
+# /dev/shm/vgpu-guest-ram image. The guest's timer vmap page is read as a
+# u32 millisecond counter; writing a strictly increasing u32 there at 1 ms
+# (or --ms) keeps the guest RM's timer path moving.
+#
+# Usage: sudo python3 tools/guest-diag/tick_gen.py <gpa_hex> [--ms 1] [--file PATH]
+# <gpa_hex> guest physical address of the timer tick u32 (the guest's
+# timer vmap base + 0x6c004)
+# --ms N write interval in milliseconds (default 1)
+# --file P guest RAM file (default /dev/shm/vgpu-guest-ram)
+#
+# The file offset is gpa - 0x80000000. The mapping is created once; the loop
+# only writes the u32. SIGINT stops cleanly.
+import argparse
+import mmap
+import os
+import signal
+import struct
+import sys
+import time
+
+RAM_BASE = 0x80000000
+DEFAULT_FILE = "/dev/shm/vgpu-guest-ram"
+stop = False
+
+
+def on_sigint(signum, frame):
+ global stop
+ stop = True
+
+
+def main():
+ ap = argparse.ArgumentParser(add_help=True)
+ ap.add_argument("gpa", help="guest physical address (hex, 0x prefix optional)")
+ ap.add_argument("--ms", type=float, default=1.0,
+ help="write interval in milliseconds (default 1)")
+ ap.add_argument("--file", default=DEFAULT_FILE, help="guest RAM file")
+ args = ap.parse_args()
+
+ try:
+ gpa = int(args.gpa, 0)
+ except ValueError:
+ gpa = int(args.gpa, 16)
+ if gpa < RAM_BASE:
+ print("tick_gen: gpa 0x%x is below 0x%x" % (gpa, RAM_BASE),
+ file=sys.stderr)
+ return 2
+ off = gpa - RAM_BASE
+
+ fd = os.open(args.file, os.O_RDWR)
+ try:
+ size = os.fstat(fd).st_size
+ if off + 4 > size:
+ print("tick_gen: offset 0x%x beyond %s (0x%x bytes)"
+ % (off, args.file, size), file=sys.stderr)
+ return 2
+ mm = mmap.mmap(fd, size, access=mmap.ACCESS_WRITE)
+ try:
+ signal.signal(signal.SIGINT, on_sigint)
+ interval = max(0.0, args.ms / 1000.0)
+ counter = time.monotonic_ns() // 1_000_000
+ iterations = 0
+ last_print = time.monotonic()
+ print("tick_gen: file=%s gpa=0x%x off=0x%x interval=%.3fms"
+ % (args.file, gpa, off, args.ms), flush=True)
+ while not stop:
+ now_ms = time.monotonic_ns() // 1_000_000
+ if now_ms <= counter:
+ now_ms = counter + 1
+ counter = now_ms
+ val = counter & 0xFFFFFFFF
+ struct.pack_into("<I", mm, off, val)
+ iterations += 1
+ t = time.monotonic()
+ if t - last_print >= 2.0:
+ print("tick_gen: iterations=%d value=%d (0x%08x)"
+ % (iterations, val, val), flush=True)
+ last_print = t
+ if interval:
+ time.sleep(interval)
+ print("tick_gen: stopped iterations=%d value=0x%08x"
+ % (iterations, counter & 0xFFFFFFFF), flush=True)
+ finally:
+ mm.close()
+ finally:
+ os.close(fd)
+ return 0
+
+
+if __name__ == "__main__":
+ try:
+ sys.exit(main())
+ except KeyboardInterrupt:
+ sys.exit(0)