summaryrefslogtreecommitdiffstats
path: root/kernel/bar_init.c
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-04 16:19:31 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-04 16:19:31 -0400
commit31594b263cc4fbe30ebbe412a4a788f726f03a02 (patch)
treed8a66620be59cf8fa6e174ccfb823e28a1c436ac /kernel/bar_init.c
parent4c220de4bee80aa4b5f367e79845d5f77163c361 (diff)
downloadopen-iov-31594b263cc4fbe30ebbe412a4a788f726f03a02.tar.gz
open-iov-31594b263cc4fbe30ebbe412a4a788f726f03a02.zip
vgsp: end-to-end CUDA acceptance in the guest
The no-claim emulation path now runs a stock CUDA program end to end: device properties, cudaMalloc, a GPU-authored string kernel read back byte-for-byte, two 4 MB host-to-device copies, a 1 M-element vectorAdd executed on the physical GPU through the host bridge, and the device-to-host copy-back verified element by element. Three consecutive supervised cycles report MAIL + VADD bad=0 checksum=392344090.500000 + STATUS OK with identical input/output hashes. Two data-path correctness fixes make the transfers sound: - Once-only op execution per GPFIFO entry. The pump replays recently consumed ring entries when translation batches are injected so missed releases can land; re-executing a CE copy is not idempotent because its source is a client staging buffer that may have been refilled. Slots now record their raw entry words and a replayed entry matching that identity suppresses operations while still processing releases. - Per-page translation of virtual operands. svc_copy resolved only the first page of a VA range and walked the PA linearly; client staging ranges are frequently split (observed 195 + 61 pages), so the tail of alternating chunks was read from unrelated memory. Multi-page copies now re-resolve each 4 KB page through the trusted resolver. Also carries the earlier uncommitted emulation fixes that got the client to the launch (QMD address-window gate, counter registration persistence, 512 MiB emulated FB, bridge slot hygiene) and bounded diagnostics (sema-bigop, sema-bigcopy, bridge-in/out hashes, daemon INCHECK/OUTCHECK/dumps).
Diffstat (limited to 'kernel/bar_init.c')
-rw-r--r--kernel/bar_init.c41
1 files changed, 36 insertions, 5 deletions
diff --git a/kernel/bar_init.c b/kernel/bar_init.c
index 9926e2b..5e4b0a0 100644
--- a/kernel/bar_init.c
+++ b/kernel/bar_init.c
@@ -5,6 +5,7 @@
#include "nvidia-vgpu-vfio.h"
#include "bar_emulation.h"
+#include "gsp_phys_gpu.h"
#include "irq.h"
int nv_vgpu_bar_init(struct nv_vgpu_device *vgpu)
@@ -75,12 +76,34 @@ int nv_vgpu_bar_init(struct nv_vgpu_device *vgpu)
if (bar_addr && bar_size) {
vgpu->bars[2].gpa = bar_addr;
vgpu->bars[2].size = bar_size;
- vgpu->bars[2].vaddr = ioremap_wc(bar_addr, bar_size);
- if (!vgpu->bars[2].vaddr) {
- nv_vgpu_err(vgpu, "Failed to map BAR2");
- return -ENOMEM;
+ /*
+ * Emulation-only mode (gsp_phys_gpu=0): the host nvidia driver
+ * owns the physical GPU. Never ioremap the real BAR2 nor expose
+ * its PFNs to the guest - guest BAR2 MMIO against a device the
+ * distribution driver owns is the suspected trigger of the Xid
+ * 140 uncorrectable-ECC incident (2026-10-03). Back the region
+ * with a private host-RAM shadow instead, exactly like BAR1/BAR3.
+ * Claim/backend mode keeps the real mapping.
+ */
+ if (gsp_phys_gpu_enabled()) {
+ vgpu->bars[2].vaddr = ioremap_wc(bar_addr, bar_size);
+ if (!vgpu->bars[2].vaddr) {
+ nv_vgpu_err(vgpu, "Failed to map BAR2");
+ return -ENOMEM;
+ }
+ nv_vgpu_info(vgpu, "BAR2: gpa=0x%llx, size=0x%llx, vaddr=%p (real, claim mode)",
+ bar_addr, bar_size, vgpu->bars[2].vaddr);
+ } else {
+ vgpu->bars[2].vaddr = vzalloc(bar_size);
+ vgpu->bars[2].emulated = true;
+ if (!vgpu->bars[2].vaddr) {
+ nv_vgpu_err(vgpu, "Failed to allocate emulated BAR2 (%llu bytes)",
+ (unsigned long long)bar_size);
+ return -ENOMEM;
+ }
+ nv_vgpu_info(vgpu, "BAR2: gpa=0x%llx, size=0x%llx, emulated shadow=%p",
+ bar_addr, bar_size, vgpu->bars[2].vaddr);
}
- nv_vgpu_info(vgpu, "BAR2: gpa=0x%llx, size=0x%llx, vaddr=%p", bar_addr, bar_size, vgpu->bars[2].vaddr);
}
bar_addr = pci_resource_start(pdev, 3);
@@ -142,9 +165,17 @@ void nv_vgpu_bar_cleanup(struct nv_vgpu_device *vgpu)
vgpu->bars[3].vaddr = NULL;
}
+ /* Free the emulated BAR2 shadow (emulation-only mode) */
+ if (vgpu->bars[2].emulated && vgpu->bars[2].vaddr) {
+ vfree(vgpu->bars[2].vaddr);
+ vgpu->bars[2].vaddr = NULL;
+ }
+
for (i = 0; i < NV_VGPU_MAX_REGIONS; i++) {
if (i == 1 || i == 3)
continue; /* shadow buffers already freed above */
+ if (i == 2 && vgpu->bars[2].emulated)
+ continue; /* shadow buffer already freed above */
if (vgpu->bars[i].vaddr) {
iounmap(vgpu->bars[i].vaddr);
vgpu->bars[i].vaddr = NULL;