diff options
| author | Open-IOV <dev@open-iov.org> | 2026-09-23 05:44:08 -0400 |
|---|---|---|
| committer | Open-IOV <dev@open-iov.org> | 2026-09-23 05:46:43 -0400 |
| commit | 2302fc09080bad51c73f293294e19fd4db464eb0 (patch) | |
| tree | c722d186347fdef5a34131e9e143b1549b1daf8e /legacy-driver-guest/bar | |
| download | open-iov-2302fc09080bad51c73f293294e19fd4db464eb0.tar.gz open-iov-2302fc09080bad51c73f293294e19fd4db464eb0.zip | |
Open-IOV: initial public release
Open-IOV virtualizes NVIDIA GPUs so that unmodified guest drivers run with
real GPU functionality - CUDA first, 3D and video to follow - on unmodified
hosts, without a proprietary vGPU license and without patching any driver,
firmware or hypervisor.
Core principle: emulate the interface, pass through the work.
kernel/ open-iov-vfio.ko - host VFIO mdev driver: virtual GPU device
(PCI config space, BAR shadows, MSI-X), GSP boot emulation,
GSP-RM message-queue/RPC emulation, memory model (GPU-VA to
guest-PA discovery) and the semaphore-completion service that
advances guest UVM progress.
userspace/ libiov.so management API and examples.
tools/ guest diagnostics, firmware analysis wrappers, RM probes.
scripts/ stack manager, VM harness, build/load/test automation.
config/ hardware/version profiles (the portability surface).
docs/ documentation tree - start at docs/README.md.
wiki/ long-form firmware and protocol deep dives.
Status: initialization works end to end for a stock 570.144 Linux guest on
Turing (TU104): driver probe, nvidia-smi, the full GSP-RM control battery,
object creation and the early CUDA/UVM start-up path. GPU work forwarding -
the step that makes CUDA kernels execute on real hardware - is the active
work item; see docs/04-implementation/01-known-knowns-and-unknowns.md.
License: BSD-3-Clause for the project; GPL-2.0 for kernel modules that link
GPL-only kernel interfaces. See LICENSE and docs/09-reference/legal-and-licensing.md.
Diffstat (limited to 'legacy-driver-guest/bar')
| -rw-r--r-- | legacy-driver-guest/bar/gsp_bar.c | 242 |
1 files changed, 242 insertions, 0 deletions
diff --git a/legacy-driver-guest/bar/gsp_bar.c b/legacy-driver-guest/bar/gsp_bar.c new file mode 100644 index 0000000..aa3ed62 --- /dev/null +++ b/legacy-driver-guest/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 |
