summaryrefslogtreecommitdiffstats
path: root/tools/test/cuda_drv_test.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/test/cuda_drv_test.c')
-rw-r--r--tools/test/cuda_drv_test.c87
1 files changed, 87 insertions, 0 deletions
diff --git a/tools/test/cuda_drv_test.c b/tools/test/cuda_drv_test.c
new file mode 100644
index 0000000..6868a2e
--- /dev/null
+++ b/tools/test/cuda_drv_test.c
@@ -0,0 +1,87 @@
+/* cuda_drv_test.c - minimal CUDA driver-API smoke test (dlopen, no toolkit).
+ *
+ * Run inside the guest. Exercises the paths CUDA needs beyond NVML:
+ * cuInit -> cuDeviceGetCount/Get -> cuCtxCreate -> cuMemAlloc ->
+ * cuMemcpyHtoD/DtoH -> cuMemFree -> cuCtxDestroy
+ *
+ * Expected output on success: "ALL OK".
+ *
+ * Status (2026-09-23): cuInit returns 3 (CUDA_ERROR_NOT_INITIALIZED) on the
+ * emulated GPU. strace shows every nvidia.ko ioctl succeeding (RM status 0),
+ * the driver completing RmInitAdapter and then closing the device, and
+ * libcuda opening /dev/nvidia-uvm before /dev/nvidia0 - i.e. the next blocker
+ * is the UVM driver (nvidia-uvm.ko), which needs the GPU MMU/VAS model that
+ * the GSP-RM emulation does not provide yet. Build in the guest with:
+ * gcc -O1 -o /tmp/cdt cuda_drv_test.c -ldl
+ */
+#include <stdio.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <stdint.h>
+
+typedef int CUresult;
+typedef int CUdevice;
+typedef void *CUcontext;
+typedef uint64_t CUdeviceptr;
+
+#define CHECK(expr) do { \
+ CUresult r = (expr); \
+ if (r) { printf("%-24s FAILED rc=%d\n", #expr, r); return 1; } \
+ printf("%-24s OK\n", #expr); \
+} while (0)
+
+int main(void)
+{
+ 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;
+
+ CHECK(cuInit(0));
+ CHECK(cuDeviceGetCount(&count));
+ printf("device count = %d\n", count);
+ if (count < 1) return 1;
+
+ CHECK(cuDeviceGet(&dev, 0));
+ printf("device 0 = %d\n", dev);
+
+ CHECK(cuCtxCreate(&ctx, 0, dev));
+ printf("context = %p\n", ctx);
+
+ 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);
+ CHECK(cuMemcpyHtoD(dptr, buf, sizeof(buf)));
+ memset(back, 0, sizeof(back));
+ CHECK(cuMemcpyDtoH(back, dptr, sizeof(buf)));
+ printf("roundtrip %s (back[7]=%u expected 22)\n",
+ memcmp(buf, back, sizeof(buf)) ? "MISMATCH" : "match", back[7]);
+
+ CHECK(cuMemFree(dptr));
+ CHECK(cuCtxDestroy(ctx));
+ printf("ALL OK\n");
+ return 0;
+}