diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-09-30 06:13:26 -0400 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-09-30 06:13:26 -0400 |
| commit | 330e63e05106740749c3ca4d8c94a94352d6cc4c (patch) | |
| tree | cf88c45603ddb3ee60c7fe5ebdcbdaff2a2c685b /tools | |
| parent | a9916e3ad37eb03ebe0d764729e4c9c51fda3fcc (diff) | |
| download | open-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-x | tools/guest-diag/push_guest_tools.sh | 4 | ||||
| -rw-r--r-- | tools/test/cuda_drv_test2.c | 144 |
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; +} |
