summaryrefslogtreecommitdiffstats
path: root/kernel/main.c
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-09-23 06:31:44 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-09-23 06:31:44 -0400
commit893318f45eff1a2b5f4d554297d08a9e987c2a52 (patch)
tree9c232d4b1a30ec8af64b369fa36c72e2f4548b88 /kernel/main.c
parent36af41ae7460eac87b6a929a3b9af3a130507a26 (diff)
downloadopen-iov-893318f45eff1a2b5f4d554297d08a9e987c2a52.tar.gz
open-iov-893318f45eff1a2b5f4d554297d08a9e987c2a52.zip
kernel: execute pushed CE work (PTE memsets, copies) and track semaphores
The progress service now decodes push buffers as method streams and performs the work the driver pushes, not just the tracking semaphore: - C5B5 method decoder: SET_REMAP_CONST_A/B + COMPONENTS + OFFSET_OUT + LINE_LENGTH_IN + LAUNCH_DMA = memset (into vidmem or guest RAM); OFFSET_IN + OFFSET_OUT + LAUNCH_DMA = copy; SET_SEMAPHORE_A/B/PAYLOAD + LAUNCH_DMA = release. Contiguous method runs (count 2/4) are applied in full - OFFSET_IN/OUT arrive as one run. - Pushes span page boundaries, so pages are decoded as method streams without a start marker. Collected operations execute only when the push's release is reached and still pending (payload ahead of the semaphore), so recycled buffers replaying old pushes are skipped and their stale memsets cannot overwrite newer state. - VA->PA map is first-wins: stale copies of freed allocations and unrelated adjacent u64 pairs produced bogus entries that hijacked a good mapping and sent semaphore writes to the wrong page. - dump_guest module parameter (hex dump of guest PA, kthread via completion; kthread_stop before the thread runs loses the work). With this the guest no longer stalls in uvm_tracker_wait and no longer oopses in the UVM path; the failure moved to a userspace segfault inside libcuda (NULL-0x38) after the driver's page allocations. Also add tools/cuda-ab: run one deterministic CUDA workload on the host (bare metal oracle) and in the guest, then compare the stable result lines. The binary links the CUDA runtime statically so the guest only needs the driver's libcuda.so.
Diffstat (limited to 'kernel/main.c')
-rw-r--r--kernel/main.c89
1 files changed, 89 insertions, 0 deletions
diff --git a/kernel/main.c b/kernel/main.c
index 637c79b..0a1ebc2 100644
--- a/kernel/main.c
+++ b/kernel/main.c
@@ -2560,5 +2560,94 @@ static const struct kernel_param_ops nv_vgpu_dump_vidmem_ops = {
module_param_cb(dump_vidmem, &nv_vgpu_dump_vidmem_ops, NULL, 0200);
MODULE_PARM_DESC(dump_vidmem, "Dump emulated vidmem range (hex offset,hex len)");
+/*
+ * Debug: hex-dump a guest physical range (kthread: guest-DMA needs it):
+ * echo 0x<gpa>,0x<len> > .../parameters/dump_guest
+ */
+struct nv_vgpu_dump_guest_req {
+ u64 gpa;
+ unsigned long len;
+ struct completion done;
+};
+
+static int nv_vgpu_dump_guest_thread(void *arg)
+{
+ struct nv_vgpu_dump_guest_req *req = arg;
+ struct nv_vgpu_device *vgpu;
+ u32 *buf;
+ unsigned long i;
+
+ buf = kmalloc(256, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ mutex_lock(&nv_vgpu_driver.lock);
+ list_for_each_entry(vgpu, &nv_vgpu_driver.devices, list) {
+ u64 o;
+
+ if (atomic_read(&vgpu->vfio_dev_open_count) <= 0)
+ continue;
+ pr_info("gsp-resman-vfio: guest dump 0x%llx..0x%llx\n",
+ req->gpa, req->gpa + req->len);
+ for (o = 0; o < req->len; o += 256) {
+ unsigned long chunk = min_t(unsigned long, 256,
+ req->len - o);
+
+ if (vfio_dma_rw(&vgpu->vfio_dev, req->gpa + o, buf,
+ chunk, false)) {
+ pr_info("gsp-resman-vfio: guest dump read failed at 0x%llx\n",
+ req->gpa + o);
+ break;
+ }
+ for (i = 0; i < chunk / 4; i += 4)
+ pr_info("gsp-resman-vfio: 0x%llx: %08x %08x %08x %08x\n",
+ req->gpa + o + i * 4, buf[i], buf[i + 1],
+ buf[i + 2], buf[i + 3]);
+ }
+ }
+ mutex_unlock(&nv_vgpu_driver.lock);
+
+ kfree(buf);
+ complete(&req->done);
+ return 0;
+}
+
+static int nv_vgpu_dump_guest_set(const char *val, const struct kernel_param *kp)
+{
+ static struct nv_vgpu_dump_guest_req req;
+ struct task_struct *task;
+ char buf[64];
+ char *comma;
+
+ memset(&req, 0, sizeof(req));
+ strscpy(buf, val, sizeof(buf));
+ comma = strchr(buf, ',');
+ if (comma)
+ *comma = '\0';
+ if (kstrtoull(buf, 0, &req.gpa))
+ return -EINVAL;
+ req.len = 0x100;
+ if (comma && kstrtoul(comma + 1, 0, &req.len))
+ return -EINVAL;
+ if (!req.len)
+ req.len = 0x100;
+ if (req.len > 0x4000)
+ req.len = 0x4000;
+
+ init_completion(&req.done);
+ task = kthread_run(nv_vgpu_dump_guest_thread, &req, "vgpu-dump");
+ if (IS_ERR(task))
+ return PTR_ERR(task);
+ wait_for_completion(&req.done);
+ return 0;
+}
+
+static const struct kernel_param_ops nv_vgpu_dump_guest_ops = {
+ .set = nv_vgpu_dump_guest_set,
+};
+
+module_param_cb(dump_guest, &nv_vgpu_dump_guest_ops, NULL, 0200);
+MODULE_PARM_DESC(dump_guest, "Hex-dump a guest physical range (hex gpa,hex len)");
+
module_init(nv_vgpu_init);
module_exit(nv_vgpu_exit);