diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-09-23 12:26:03 -0400 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-09-23 12:26:03 -0400 |
| commit | 71c1a2147681127209453a811b918d66d8eebbad (patch) | |
| tree | 14dfebfbabd347aed9161d9e9cf0115d8725c2c2 /kernel/main.c | |
| parent | 692c095ae48f2829613873e60e4dbbf14b36323d (diff) | |
| download | open-iov-71c1a2147681127209453a811b918d66d8eebbad.tar.gz open-iov-71c1a2147681127209453a811b918d66d8eebbad.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.c | 50 |
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++; |
