summaryrefslogtreecommitdiffstats
path: root/kernel/main.c
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-09-23 12:26:03 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-09-23 12:26:03 -0400
commitf7980444a921a0b5027e05a74f7535138e816a3d (patch)
tree1c2f59c3fb9e8422c90f0f699d12e0330f17c5fb /kernel/main.c
parent13f46e60760cc0855484cc69de913ea34f55c24f (diff)
downloadopen-iov-f7980444a921a0b5027e05a74f7535138e816a3d.tar.gz
open-iov-f7980444a921a0b5027e05a74f7535138e816a3d.zip
kernel: service BAR0/BAR1 region reads and extended config-space writes
Two more retry loops surfaced once the guest driver got past the CE binding: - BAR0 region reads returned -EINVAL ("would be handled by mmap"), so a QEMU-trapped read of BAR0+0x88084 failed and the driver polled it forever. Serve reads from the BAR0 shadow/trap handler (and mirror BAR1 reads from the emulated vidmem backing). - Config-space writes above offset 0xFF were refused with -EINVAL, so the driver's write to extended config 0x704 (PCIe device control area) never took effect and it retried. Accept and store extended-space writes; keep the legacy identity registers fixed.
Diffstat (limited to 'kernel/main.c')
-rw-r--r--kernel/main.c50
1 files changed, 42 insertions, 8 deletions
diff --git a/kernel/main.c b/kernel/main.c
index 45c34ab..2ec7ab9 100644
--- a/kernel/main.c
+++ b/kernel/main.c
@@ -725,10 +725,38 @@ static ssize_t nv_vgpu_vfio_dev_read(struct vfio_device *vdev, char __user *buf,
return to_read;
}
- /* BAR0 region: VFIO_PCI_INDEX_TO_OFFSET(VFIO_PCI_BAR0_REGION_INDEX) = 0x0 */
- if (pos >= 0x0 && pos < 0x0 + (256 * 1024 * 1024)) {
- /* This would be handled by mmap, not read */
- return -EINVAL;
+ /* BAR0 region (register space). Most guest accesses hit the mmap'd shadow
+ * directly, but region reads also arrive here. They must be served from
+ * the shadow (and the trap table) - refusing them makes the guest driver
+ * poll a register forever. */
+ if (pos >= 0 && (u64)pos < vgpu->bars[0].size && count <= 8) {
+ u8 tmp[8];
+ int ret;
+
+ if (!vgpu->bar_emul_ctx)
+ return -ENODEV;
+ if (count > sizeof(tmp))
+ return -EINVAL;
+
+ ret = nv_vgpu_bar_emul_read(vgpu, 0, (u64)pos, tmp, count);
+ if (ret)
+ return ret;
+ if (copy_to_user(buf, tmp, count))
+ return -EFAULT;
+ *ppos += count;
+ return count;
+ }
+
+ /* BAR1 region (VRAM): read from the emulated vidmem backing. */
+ if (pos >= (1ULL << 40) &&
+ (u64)pos < (1ULL << 40) + vgpu->bars[1].size &&
+ vgpu->bars[1].vaddr && count <= 8) {
+ u64 bar1_off = (u64)pos - (1ULL << 40);
+
+ if (copy_to_user(buf, vgpu->bars[1].vaddr + bar1_off, count))
+ return -EFAULT;
+ *ppos += count;
+ return count;
}
return 0;
@@ -1855,11 +1883,11 @@ static ssize_t nv_vgpu_config_write(struct nv_vgpu_device *vgpu, const char __us
size_t written = 0;
u8 val;
- if (pos >= 256)
+ if (pos >= 4096)
return -EINVAL;
- if (pos + count > 256)
- count = 256 - pos;
+ if (pos + count > 4096)
+ count = 4096 - pos;
/* Handle specific writable registers */
while (count--) {
@@ -1902,8 +1930,14 @@ static ssize_t nv_vgpu_config_write(struct nv_vgpu_device *vgpu, const char __us
case 0xa4: case 0xa5: /* Link Control 2 */
vgpu->pci_config[pos] = val;
break;
+ case 0x100 ... 0xfff:
+ /* Extended capability space: accept and store. The guest
+ * driver programs registers here (e.g. 0x704) and retries
+ * forever if the write is refused. */
+ vgpu->pci_config[pos] = val;
+ break;
default:
- /* Most config space is read-only for guest */
+ /* Legacy identity/read-only registers stay fixed */
break;
}
pos++;