/* 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 #include #include #include 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; }