diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-09-13 18:36:21 -0400 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-09-13 18:36:21 -0400 |
| commit | 00e54c13c7c9030c4d5f7151467f2d85a3730e29 (patch) | |
| tree | 17a45239df8d2e4912ff3697ed06e85a10b969de /driver/bar | |
| download | open-iov-00e54c13c7c9030c4d5f7151467f2d85a3730e29.tar.gz open-iov-00e54c13c7c9030c4d5f7151467f2d85a3730e29.zip | |
Initial commit: Open-IOV vGPU-IO complete stack
- Firmware decompilation: GSP 570.144W (28.5MB ELF, RV64IMAC), 132 decompiled C files
- Kernel modules: nvidia.ko (34MB, OpenRM), open-iov-vfio.ko (2.8MB, VFIO mdev), gsp-vgpu.ko (1.8MB, guest driver)
- Userspace: libiov.so/libvgpu.so (76KB), example_vgpu (28KB), rpc_emulator.c
- PCI config space emulation (256B with PM, MSI, MSI-X, PCIe caps)
- 12 RPC types fully mapped from firmware decompilation
- BAR trap, WPR, scheduling, notification, migration emulation
- Helper scripts: load_vgpu_stack, create_mdev, launch_qemu_vgpu, test_vgpu_stack, setup_guest_driver, unload_vgpu_stack
- Architecture documentation
- Wiki: 10 technical documents
- Git LFS for large binaries (.ko, .bin, .iso, .img, .o, ghidra repos)
- nvidia-open-gpu-kernel-modules as submodule
Diffstat (limited to 'driver/bar')
| -rw-r--r-- | driver/bar/gsp_bar.c | 242 |
1 files changed, 242 insertions, 0 deletions
diff --git a/driver/bar/gsp_bar.c b/driver/bar/gsp_bar.c new file mode 100644 index 0000000..aa3ed62 --- /dev/null +++ b/driver/bar/gsp_bar.c @@ -0,0 +1,242 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * GSP vGPU-IO Driver - BAR Emulation + */ + +#include "gsp_core.h" +#include <linux/slab.h> +#include <linux/vmalloc.h> + +/* BAR Emulation Ops */ +static int gsp_bar_trap_handler(struct gsp_vf *vf, struct gsp_bar_trap_payload *trap) +{ + struct gsp_bar_state *bar = &vf->bar_state; + struct gsp_bar_trap_response resp = {0}; + size_t resp_size = sizeof(resp); + int ret; + + /* Validate BAR index (we only support BAR1) */ + if (trap->bar_index != 1) + return -EINVAL; + + /* Validate offset */ + if (trap->offset >= bar->aperture_size) + return -ERANGE; + + /* Check ForceBarAccess */ + if (bar->force_access && vf->id != bar->force_vf) + return -EPERM; + + /* In emulation mode, handle locally */ + if (emulation_mode) { + /* Simulate BAR trap handling */ + if (trap->trap_type == GSP_BAR_WRITE) { + /* Config write - update aperture */ + bar->aperture_offset = trap->offset; + bar->aperture_size = trap->value; + } else if (trap->trap_type == GSP_BAR_ATOMIC) { + /* Force access control */ + bar->force_access = trap->offset ? true : false; + bar->force_vf = trap->offset ? vf->id : 0; + } + resp.value = 0; + return 0; + } + + /* Forward to GSP BAR trap handler (0x04CB8188) */ + ret = gsp_rpc_send_sync(vf->gsp->rpc, GSP_RPC_BAR_TRAP, + trap, sizeof(*trap), &resp, &resp_size); + + return ret; +} + +/* Aperture Configuration */ +static int gsp_bar_config_aperture(struct gsp_vf *vf, uint64_t offset, uint64_t size) +{ + struct gsp_bar_state *bar = &vf->bar_state; + struct gsp_bar_trap_payload payload = {0}; + struct gsp_bar_trap_response resp = {0}; + size_t resp_size = sizeof(resp); + int ret; + + /* Validate alignment (4KB) */ + if (offset & 0xFFF || size & 0xFFF) + return -EINVAL; + + /* Validate max size (256KB per firmware) */ + if (size > 0x40000) + return -EINVAL; + + /* In emulation mode, handle locally */ + if (emulation_mode) { + bar->aperture_offset = offset; + bar->aperture_size = size; + return 0; + } + + payload.bar_index = 1; + payload.trap_type = GSP_BAR_WRITE; /* Config write */ + payload.offset = offset; + payload.value = size; + payload.size = 8; + payload.vf_id = vf->id; + + ret = gsp_rpc_send_sync(vf->gsp->rpc, GSP_RPC_BAR_TRAP, + &payload, sizeof(payload), &resp, &resp_size); + if (!ret) { + bar->aperture_offset = offset; + bar->aperture_size = size; + } + + return ret; +} + +/* ForceBarAccess Control */ +int gsp_bar_force_access(struct gsp_vf *vf, bool enable) +{ + struct gsp_bar_state *bar = &vf->bar_state; + struct gsp_bar_trap_payload payload = {0}; + struct gsp_bar_trap_response resp = {0}; + size_t resp_size = sizeof(resp); + int ret; + + /* In emulation mode, handle locally */ + if (emulation_mode) { + bar->force_access = enable; + bar->force_vf = enable ? vf->id : 0; + return 0; + } + + payload.bar_index = 1; + payload.trap_type = GSP_BAR_ATOMIC; /* Force access control */ + payload.offset = enable ? 1 : 0; + payload.value = enable ? vf->id : 0; + payload.size = 8; + payload.vf_id = vf->id; + + ret = gsp_rpc_send_sync(vf->gsp->rpc, GSP_RPC_BAR_TRAP, + &payload, sizeof(payload), &resp, &resp_size); + if (!ret) { + bar->force_access = enable; + bar->force_vf = enable ? vf->id : 0; + } + + return ret; +} + +/* State Save for Migration */ +static int gsp_bar_save_state(struct gsp_vf *vf, void *buf, size_t *size) +{ + struct gsp_bar_state *bar = &vf->bar_state; + size_t needed = sizeof(*bar) + bar->backing_size; + + if (!buf || *size < needed) + return -ENOSPC; + + memcpy(buf, bar, sizeof(*bar)); + if (bar->backing_store && bar->backing_size > 0) + memcpy(buf + sizeof(*bar), bar->backing_store, bar->backing_size); + + *size = needed; + return 0; +} + +/* State Restore for Migration */ +static int gsp_bar_restore_state(struct gsp_vf *vf, void *buf, size_t size) +{ + struct gsp_bar_state *bar = &vf->bar_state; + size_t min_size = sizeof(*bar); + + if (!buf || size < min_size) + return -EINVAL; + + memcpy(bar, buf, sizeof(*bar)); + + if (size > min_size && bar->backing_size > 0) { + if (!bar->backing_store) { + bar->backing_store = vzalloc(bar->backing_size); + if (!bar->backing_store) + return -ENOMEM; + } + memcpy(bar->backing_store, buf + min_size, + min(size - min_size, bar->backing_size)); + } + + /* Reconfigure BAR in GSP */ + return gsp_bar_config_aperture(vf, bar->aperture_offset, bar->aperture_size); +} + +/* VF BAR Initialization */ +int gsp_vf_bar_init(struct gsp_vf *vf) +{ + struct gsp_bar_state *bar = &vf->bar_state; + int ret; + + /* Initialize with config values */ + bar->aperture_offset = vf->bar1_offset; + bar->aperture_size = vf->bar1_size; + bar->force_access = false; + bar->force_vf = 0; + bar->backing_store = NULL; + bar->backing_size = 0; + + /* Allocate backing store (max 256KB) */ + if (bar->aperture_size > 0) { + bar->backing_size = min(bar->aperture_size, (uint64_t)0x40000); + bar->backing_store = vzalloc(bar->backing_size); + if (!bar->backing_store) + return -ENOMEM; + } + + /* Configure aperture in GSP (skip in emulation mode) */ + if (!emulation_mode) { + ret = gsp_bar_config_aperture(vf, bar->aperture_offset, bar->aperture_size); + if (ret) { + dev_err(vf->gsp->dev, "VF %u: BAR aperture config failed: %d\n", vf->id, ret); + goto err_backing; + } + } else { + dev_info(vf->gsp->dev, "VF %u: BAR1 initialized in emulation mode [0x%llx, 0x%llx)\n", + vf->id, bar->aperture_offset, bar->aperture_offset + bar->aperture_size); + } + + dev_info(vf->gsp->dev, "VF %u: BAR1 initialized [0x%llx, 0x%llx)\n", + vf->id, bar->aperture_offset, bar->aperture_offset + bar->aperture_size); + + return 0; + +err_backing: + vfree(bar->backing_store); + bar->backing_store = NULL; + bar->backing_size = 0; + return ret; +} + +/* VF BAR Cleanup */ +void gsp_vf_bar_fini(struct gsp_vf *vf) +{ + struct gsp_bar_state *bar = &vf->bar_state; + + vfree(bar->backing_store); + bar->backing_store = NULL; + bar->backing_size = 0; + + dev_info(vf->gsp->dev, "VF %u: BAR1 cleaned up\n", vf->id); +} + +/* BAR Trap Entry Point (called from ISR/notification) */ +int gsp_vf_bar_trap(struct gsp_vf *vf, struct gsp_bar_trap_payload *trap) +{ + return gsp_bar_trap_handler(vf, trap); +} + +/* Migration Interface */ +int gsp_migration_bar_save(struct gsp_vf *vf, void *buf, size_t *size) +{ + return gsp_bar_save_state(vf, buf, size); +} + +int gsp_migration_bar_restore(struct gsp_vf *vf, void *buf, size_t size) +{ + return gsp_bar_restore_state(vf, buf, size); +}
\ No newline at end of file |
