summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-09-30 06:13:26 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-09-30 06:13:26 -0400
commit330e63e05106740749c3ca4d8c94a94352d6cc4c (patch)
treecf88c45603ddb3ee60c7fe5ebdcbdaff2a2c685b /tools
parenta9916e3ad37eb03ebe0d764729e4c9c51fda3fcc (diff)
downloadopen-iov-330e63e05106740749c3ca4d8c94a94352d6cc4c.tar.gz
open-iov-330e63e05106740749c3ca4d8c94a94352d6cc4c.zip
sema-svc: decode GRCE inline-data DMA (small HtoD path)
The 256-byte cuMemcpyHtoD payload never appears in any CE push: CUDA submits it on the compute channel as a compute-class DMA whose source is the push's own inline data (LINE_LENGTH_IN=256, OFFSET_OUT=<device VA>, LAUNCH_DMA=0x41, LOAD_INLINE_DATA 64 dwords, then the channel's SET_REPORT_SEMAPHORE release). The CE-shaped decoder skipped the data run (opcode 3) and no GR work ran at all. - Decode NVC5C0 GRCE methods on subchannel 1 (LINE_LENGTH_IN, LINE_COUNT, OFFSET_OUT/UPPER, LAUNCH_DMA) and the opcode-3 LOAD_INLINE_DATA run. - svc_grce_inline_write resolves the destination VA through trusted sources (pins, map, published page directories, targeted rm_mem resolve), pins the page and writes into vidmem or guest RAM; budgeted sema-grce logs name the target or report UNRESOLVED. - cdt2 test binary gains CDT_CP_PAUSE / CDT_HP_PAUSE for live inspection of the copy path; pushed by push_guest_tools.sh.
Diffstat (limited to 'tools')
-rwxr-xr-xtools/guest-diag/push_guest_tools.sh4
-rw-r--r--tools/test/cuda_drv_test2.c144
2 files changed, 147 insertions, 1 deletions
diff --git a/tools/guest-diag/push_guest_tools.sh b/tools/guest-diag/push_guest_tools.sh
index 18db05c..9a45fd3 100755
--- a/tools/guest-diag/push_guest_tools.sh
+++ b/tools/guest-diag/push_guest_tools.sh
@@ -24,6 +24,7 @@ push_b64 "$HERE/guest_engines.c" /tmp/ge.c
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 "$REPO/tools/test/cuda_drv_test2.c" /tmp/cdt2.c
push_b64 "$HERE/dumpctx.py" /tmp/dumpctx.py
push_b64 "$HERE/trkinfo.py" /tmp/trkinfo.py
push_b64 "$HERE/bp999.py" /tmp/bp999.py
@@ -66,4 +67,5 @@ echo "[*] compiling in guest..."
gcc -O1 -w -o /tmp/ge /tmp/ge.c && \
gcc -O1 -w -o /tmp/rmqp /tmp/rmqp.c && \
gcc -O1 -w -o /tmp/iot /tmp/iot.c && \
-gcc -O1 -o /tmp/cdt /tmp/cdt.c -ldl && echo BUILD_OK"
+gcc -O1 -o /tmp/cdt /tmp/cdt.c -ldl && \
+gcc -O1 -o /tmp/cdt2 /tmp/cdt2.c -ldl && echo BUILD_OK"
diff --git a/tools/test/cuda_drv_test2.c b/tools/test/cuda_drv_test2.c
new file mode 100644
index 0000000..a146bc2
--- /dev/null
+++ b/tools/test/cuda_drv_test2.c
@@ -0,0 +1,144 @@
+/* cuda_drv_test2.c - minimal CUDA driver-API smoke test (dlopen, no toolkit)
+ * with copy-path pause points for live inspection.
+ *
+ * Same sequence as cuda_drv_test.c, plus:
+ * CDT_CP_PAUSE=<s> sleep before cuMemcpyHtoD (after cuMemAlloc): the
+ * context is live, the device pointer is known - probe
+ * the GPU VA translation while parked.
+ * CDT_HP_PAUSE=<s> sleep after cuMemcpyHtoD (before DtoH): inspect what
+ * the HtoD left behind.
+ * CDT_WAIT=<s> park after the test (existing behaviour).
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <dlfcn.h>
+#include <stdint.h>
+
+typedef int CUresult;
+typedef int CUdevice;
+typedef void *CUcontext;
+typedef uint64_t CUdeviceptr;
+
+static void fail_info(CUresult r)
+{
+ const char *(*errname)(CUresult, const char **) = dlsym(RTLD_DEFAULT, "cuGetErrorName");
+ const char *(*errstr)(CUresult, const char **) = dlsym(RTLD_DEFAULT, "cuGetErrorString");
+ const char *s = NULL;
+ const char *hold = getenv("CDT_HOLD");
+
+ if (errname && errname(r, &s) == 0 && s)
+ printf("cuGetErrorName: %s\n", s);
+ if (errstr && errstr(r, &s) == 0 && s)
+ printf("cuGetErrorString: %s\n", s);
+ if (hold && atoi(hold) > 0) {
+ printf("CDT_HOLD: sleeping %d s for inspection\n", atoi(hold));
+ fflush(stdout);
+ sleep((unsigned)atoi(hold));
+ }
+}
+
+#define CHECK(expr) do { \
+ CUresult r = (expr); \
+ if (r) { printf("%-24s FAILED rc=%d\n", #expr, r); fail_info(r); return 1; } \
+ printf("%-24s OK\n", #expr); \
+} while (0)
+
+#define MARK(name) do { printf("-> %s\n", name); } while (0)
+
+static void pause_env(const char *name)
+{
+ const char *v = getenv(name);
+
+ if (v && atoi(v) > 0) {
+ printf("%s: parked %d s\n", name, atoi(v));
+ fflush(stdout);
+ sleep((unsigned)atoi(v));
+ }
+}
+
+int main(void)
+{
+ setvbuf(stdout, NULL, _IONBF, 0);
+
+ void *h = dlopen("libcuda.so.1", RTLD_NOW);
+ if (!h) { printf("dlopen libcuda.so.1 failed: %s\n", dlerror()); return 1; }
+
+ CUresult (*cuInit)(unsigned int) = dlsym(h, "cuInit");
+ CUresult (*cuDeviceGetCount)(int *) = dlsym(h, "cuDeviceGetCount");
+ CUresult (*cuDeviceGet)(CUdevice *, int) = dlsym(h, "cuDeviceGet");
+ CUresult (*cuCtxCreate)(CUcontext *, unsigned int, CUdevice) = dlsym(h, "cuCtxCreate_v2");
+ CUresult (*cuMemAlloc)(CUdeviceptr *, size_t) = dlsym(h, "cuMemAlloc_v2");
+ CUresult (*cuMemcpyHtoD)(CUdeviceptr, const void *, size_t) = dlsym(h, "cuMemcpyHtoD_v2");
+ CUresult (*cuMemcpyDtoH)(void *, CUdeviceptr, size_t) = dlsym(h, "cuMemcpyDtoH_v2");
+ CUresult (*cuMemFree)(CUdeviceptr) = dlsym(h, "cuMemFree_v2");
+ CUresult (*cuCtxDestroy)(CUcontext) = dlsym(h, "cuCtxDestroy_v2");
+
+ if (!cuInit || !cuDeviceGetCount || !cuDeviceGet || !cuCtxCreate ||
+ !cuMemAlloc || !cuMemcpyHtoD || !cuMemcpyDtoH || !cuMemFree || !cuCtxDestroy) {
+ printf("dlsym failed\n");
+ return 1;
+ }
+
+ int count = 0;
+ CUdevice dev;
+ CUcontext ctx = NULL;
+ CUdeviceptr dptr = 0;
+ unsigned int buf[64];
+ unsigned int back[64];
+ size_t i;
+
+ MARK("cuInit");
+ CHECK(cuInit(0));
+ MARK("cuDeviceGetCount");
+ CHECK(cuDeviceGetCount(&count));
+ printf("device count = %d\n", count);
+ if (count < 1) return 1;
+
+ MARK("cuDeviceGet");
+ CHECK(cuDeviceGet(&dev, 0));
+ printf("device 0 = %d\n", dev);
+
+ MARK("cuCtxCreate");
+ {
+ const char *pause = getenv("CDT_PAUSE");
+ if (pause && atoi(pause) > 0) {
+ printf("CDT_PAUSE: sleeping %d s before cuCtxCreate\n", atoi(pause));
+ fflush(stdout);
+ sleep((unsigned)atoi(pause));
+ }
+ }
+ CHECK(cuCtxCreate(&ctx, 0, dev));
+ printf("context = %p\n", ctx);
+
+ MARK("cuMemAlloc");
+ CHECK(cuMemAlloc(&dptr, sizeof(buf)));
+ printf("device ptr = 0x%llx (%zu bytes)\n", (unsigned long long)dptr, sizeof(buf));
+
+ for (i = 0; i < 64; i++) buf[i] = (unsigned int)(i * 3 + 1);
+ pause_env("CDT_CP_PAUSE");
+ MARK("cuMemcpyHtoD");
+ CHECK(cuMemcpyHtoD(dptr, buf, sizeof(buf)));
+ pause_env("CDT_HP_PAUSE");
+ memset(back, 0, sizeof(back));
+ MARK("cuMemcpyDtoH");
+ CHECK(cuMemcpyDtoH(back, dptr, sizeof(buf)));
+ {
+ size_t matched = 0;
+ for (i = 0; i < 64; i++)
+ if (buf[i] == back[i]) matched++;
+ printf("roundtrip %s matched=%zu/64 back[0..7]=%u,%u,%u,%u,%u,%u,%u,%u expected 1,4,7,10,13,16,19,22\n",
+ matched == 64 ? "match" : "MISMATCH", matched,
+ back[0], back[1], back[2], back[3],
+ back[4], back[5], back[6], back[7]);
+ }
+
+ MARK("cuMemFree");
+ CHECK(cuMemFree(dptr));
+ MARK("cuCtxDestroy");
+ CHECK(cuCtxDestroy(ctx));
+ printf("ALL OK\n");
+ pause_env("CDT_WAIT");
+ return 0;
+}