diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-11-12 20:01:04 -0500 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-11-12 20:01:04 -0500 |
| commit | 725898e44666b4def396f7f3c5e50712fd37aa33 (patch) | |
| tree | 261bba910db49036624cc2cf89baac6554a6f58d /tools/guest-diag/tick_gen.py | |
| parent | 800c108f9d2463066a221a0e4ff56867304551a6 (diff) | |
| download | open-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-x | tools/guest-diag/tick_gen.py | 97 |
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) |
