1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
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;
}
|