Paravirtual NVIDIA GPU for KVM guests — run unmodified CUDA, PyTorch and Vulkan inside a VM at host parity, on a GPU the host keeps using. No passthrough, no vGPU licence. Experimental.
70
stars
952
commits
C
primary language
Sep 8, 2026
updated
Run CUDA, PyTorch, Vulkan or a graphical display inside a KVM guest, on the same GPU your host is still using.

Real recording on an RTX 3050 Laptop GPU: cold boot to nvidia-smi inside
the guest, with the host still holding the card. Idle time is fast-forwarded;
nothing printed was cut. (asciinema cast ·
how it was made)
nvkvm gives a virtual machine real, driver-level access to an NVIDIA GPU
without handing the card over to it. It feels like a CUDA container upgraded with actual VM support.
/dev/nvidia0 and friends, backed by a small kernel module that forwards the
NVIDIA driver's own API interface over virtio to the host driver. Unmodified
NVIDIA userspace runs inside the guest — not a CUDA shim, not an API remoting
layer, not a shared kernel container.
This project fixes the limitations of the alternatives:
It provides you
vfio-pci rebindThis project is both intended for compute workload VMs (e.g deep learning) and for graphics VMs (e.g gaming)
| Host | Linux with working KVM (confirm virtualiziation technology is enabled in BIOS), an NVIDIA GPU, and the NVIDIA driver - either module flavour, proprietary or open (which) |
| Guest | Linux, kernel 5.15 – 7.0 (guest kernels) |
| GPU | Turing or newer - Volta/Pascal/Maxwell support is in the making |
| Size | Recommended 16 GB RAM and 4 vCPUs for the guest and 40 GB disk |
Check you can open /dev/kvm before anything else - not CPU flags, which a
container inherits from its host:
exec 3<>/dev/kvm && echo "KVM usable" && exec 3>&-
Without /dev/kvm, QEMU silently falls back to software emulation: it appears
to work and is unusably slow.
Permissions, containers and nested virt can be found here: install guide.
docker run --rm -it --device /dev/kvm --gpus all \
-e NVIDIA_DRIVER_CAPABILITIES=compute,utility,graphics,display,video \
-p 127.0.0.1:2222:2222 -v nvkvm-guest:/opt/nvkvm-guest \
ghcr.io/reindertpelsma/nvkvm-pv:v0.2.5
ssh -p 2222 ubuntu@127.0.0.1 # password: ubuntu -- nvidia-smi already works
Keep the 127.0.0.1: in the -p flag. The guest is ubuntu:ubuntu with
NOPASSWD:ALL; published as a bare -p 2222:2222 it is a root shell with your
GPU attached, offered to your whole network.
NVIDIA_DRIVER_CAPABILITIES is not optional decoration: --gpus all alone
gives the container compute,utility, and the guest then gets a compute-only
driver with no GL or Vulkan — which does not fail, it silently falls back to
llvmpipe.
A prebuilt tarball runs
on a bare host, and bash scripts/build_qemu.sh --install-deps builds from
source. Both, plus the container knobs and the attestation check:
install guide.
Inside the guest:
nvidia-smi # a guest enumerating a GPU the host has not given up
bash /mnt/nvkvm/tests/validate.sh
TOTAL 37 PASS 37 FAIL 0 SKIP 0
VERDICT: PASS (all 37 checks passed)
Exits 0 on a full pass, 1 on failure, 2 if anything was skipped. Every result below is this command on that hardware — the check count has grown over time, so older rows record a smaller total than a run today prints.
It is fast because the guest is not in a hot path. Control calls are forwarded; the work itself is not - launching a kernel is a write to memory the guest already has mapped, and nvkvm is not in that path at all.
Geekbench 7 GPU (OpenCL) runs at 98.0–99.9% of host, on four machines, published to Geekbench's own servers · RTX 4070 99.6% · RTX 3050 Laptop 99.9% · H100 PCIe 98.8% · A100 80GB 98.0%. The RTX rows are bare metal on both sides; the datacenter rentals' "host" is itself a VM, so those two measure nvkvm nested a level deeper — why that's still meaningful.
A 32B model through vLLM runs at 0.99–1.00x of host and produces token-identical output at temperature 0; fifteen other workloads land at 1.00x. Three shapes cost more, all measured: single-stream greedy decode without CUDA graphs (0.73–0.82x), tensor-parallel serving (0.89–1.06x, one configuration at 0.52x), and NVENC encode. All the numbers.
SECURITY.md
before deciding where to run this. The code is intended to become secure against multi tenant use in the future so everything is written defensive,
but some issues are still open (to be fixed) and a project with a single author cannot be claimed to be battle tested without external review.
Do not put untrusted tenants behind it. GUEST HOST
────────────────────────────── ──────────────────────────────
CUDA / PyTorch / Vulkan / OpenGL
│ ioctl(/dev/nvidia*)
▼
nvkvm-guest.ko ─── virtio ────► QEMU: virtio-nvgpu device
│
▼
one sandboxed process per guest
process ──► NVIDIA driver ──► GPU
The guest never gets the device — something PCIe passthrough cannot offer, since a passed-through GPU keeps DMA access to host RAM. The work itself is never forwarded: setting a job up crosses the boundary, running it does not. And the VMM does not have to hold your display — a separate display broker owns the window, so QEMU needs no GL and no X11 or Wayland socket at all.
The request path end to end, and what the boundary does with a guest pointer:
ARCHITECTURE.md.
| GPU | architecture | host drivers | validate.sh |
|---|---|---|---|
| GTX 1660 SUPER / Ti, RTX 2080 Ti | Turing | 535, 575 | 28/28 |
| RTX 3060 → 3090, 3050 Laptop | Ampere GA10x | 545 → 610 | 28/28 |
| RTX 4060 → 4090, RTX 4000 Ada | Ada AD10x | 575 → 595 | 28/28 |
| RTX 5070, RTX 5090 | Blackwell | 580 | 28/28 |
| A100 80GB, H100 PCIe | GA100 / Hopper | 550 → 580 | 28/28 |
Six architectures; multiple GPUs in one guest work, up to six concurrent isolates each driving their own card. Full matrix, every box and footnote. Coverage is a function of what someone happened to rent, so it is uneven by construction — reports from hardware not listed are wanted, and a failure is worth more than a success.
37/37 is not proof your workload is correct. A real correctness bug has
passed it before — check against a host run
(what that bug was).| ARCHITECTURE.md | the request path and the five hard problems |
| SECURITY.md | the trust model, and what is not yet a boundary |
| Install | container, tarball, source; /dev/kvm; attestation |
| Parity | every measurement behind the numbers above |
| Tested platforms | the full hardware matrix |
| FAQ | including why not VFIO, vGPU or virtio-gpu |
Everything else: docs/README.md.
Experimental — a research artifact, not a supported product. It runs real workloads at host parity on six GPU architectures, including multiple GPUs in one guest. The largest open item is NVIDIA's X driver; everything else is in known limitations. Issues and measurements from hardware this repository has not exercised are welcome — see contributing.
If it did not build or boot for you, that is worth reporting even when it
looks like your own setup. Run scripts/nvkvm-report.sh on the host (and in
the guest if it gets that far) and paste the output into an issue — it reads
only and collects exactly what is needed. "It worked" is worth sending too: a
successful install leaves no trace anywhere visible from here.
nvkvm derives substantially from gVisor's nvproxy (Apache-2.0) for the
ioctl allowlist model, object tracking and frontend handling, and from
NVIDIA's open-gpu-kernel-modules for ABI struct definitions. Per-file
attribution is in CREDITS.
Two other public non-vendor efforts at driver-level NVIDIA GPU virtualization
are worth reading: nestrilabs/virtio-nvgpu
and straylight-software/isospin-microvm.
Apache-2.0, except the guest kernel module (src/guest/), which is GPL-2.0 as
required for kernel symbol access, and the QEMU shipped in release tarballs,
which is GPL-2.0 and rebuildable from the pinned upstream commit plus
patches/. See LICENSE and NOTICE — the
latter also carries the trademark and independence statement.
811 commits
141 commits
C
70.8%
Shell
16.8%
Python
9.8%
Go
1.1%
Paravirtual NVIDIA GPU for KVM guests — run unmodified CUDA, PyTorch and Vulkan inside a VM at host parity, on a GPU the host keeps using. No passthrough, no vGPU licence. Experimental.
70
stars
952
commits
C
primary language
Sep 8, 2026
updated
Run CUDA, PyTorch, Vulkan or a graphical display inside a KVM guest, on the same GPU your host is still using.

Real recording on an RTX 3050 Laptop GPU: cold boot to nvidia-smi inside
the guest, with the host still holding the card. Idle time is fast-forwarded;
nothing printed was cut. (asciinema cast ·
how it was made)
nvkvm gives a virtual machine real, driver-level access to an NVIDIA GPU
without handing the card over to it. It feels like a CUDA container upgraded with actual VM support.
/dev/nvidia0 and friends, backed by a small kernel module that forwards the
NVIDIA driver's own API interface over virtio to the host driver. Unmodified
NVIDIA userspace runs inside the guest — not a CUDA shim, not an API remoting
layer, not a shared kernel container.
This project fixes the limitations of the alternatives:
It provides you
vfio-pci rebindThis project is both intended for compute workload VMs (e.g deep learning) and for graphics VMs (e.g gaming)
| Host | Linux with working KVM (confirm virtualiziation technology is enabled in BIOS), an NVIDIA GPU, and the NVIDIA driver - either module flavour, proprietary or open (which) |
| Guest | Linux, kernel 5.15 – 7.0 (guest kernels) |
| GPU | Turing or newer - Volta/Pascal/Maxwell support is in the making |
| Size | Recommended 16 GB RAM and 4 vCPUs for the guest and 40 GB disk |
Check you can open /dev/kvm before anything else - not CPU flags, which a
container inherits from its host:
exec 3<>/dev/kvm && echo "KVM usable" && exec 3>&-
Without /dev/kvm, QEMU silently falls back to software emulation: it appears
to work and is unusably slow.
Permissions, containers and nested virt can be found here: install guide.
docker run --rm -it --device /dev/kvm --gpus all \
-e NVIDIA_DRIVER_CAPABILITIES=compute,utility,graphics,display,video \
-p 127.0.0.1:2222:2222 -v nvkvm-guest:/opt/nvkvm-guest \
ghcr.io/reindertpelsma/nvkvm-pv:v0.2.5
ssh -p 2222 ubuntu@127.0.0.1 # password: ubuntu -- nvidia-smi already works
Keep the 127.0.0.1: in the -p flag. The guest is ubuntu:ubuntu with
NOPASSWD:ALL; published as a bare -p 2222:2222 it is a root shell with your
GPU attached, offered to your whole network.
NVIDIA_DRIVER_CAPABILITIES is not optional decoration: --gpus all alone
gives the container compute,utility, and the guest then gets a compute-only
driver with no GL or Vulkan — which does not fail, it silently falls back to
llvmpipe.
A prebuilt tarball runs
on a bare host, and bash scripts/build_qemu.sh --install-deps builds from
source. Both, plus the container knobs and the attestation check:
install guide.
Inside the guest:
nvidia-smi # a guest enumerating a GPU the host has not given up
bash /mnt/nvkvm/tests/validate.sh
TOTAL 37 PASS 37 FAIL 0 SKIP 0
VERDICT: PASS (all 37 checks passed)
Exits 0 on a full pass, 1 on failure, 2 if anything was skipped. Every result below is this command on that hardware — the check count has grown over time, so older rows record a smaller total than a run today prints.
It is fast because the guest is not in a hot path. Control calls are forwarded; the work itself is not - launching a kernel is a write to memory the guest already has mapped, and nvkvm is not in that path at all.
Geekbench 7 GPU (OpenCL) runs at 98.0–99.9% of host, on four machines, published to Geekbench's own servers · RTX 4070 99.6% · RTX 3050 Laptop 99.9% · H100 PCIe 98.8% · A100 80GB 98.0%. The RTX rows are bare metal on both sides; the datacenter rentals' "host" is itself a VM, so those two measure nvkvm nested a level deeper — why that's still meaningful.
A 32B model through vLLM runs at 0.99–1.00x of host and produces token-identical output at temperature 0; fifteen other workloads land at 1.00x. Three shapes cost more, all measured: single-stream greedy decode without CUDA graphs (0.73–0.82x), tensor-parallel serving (0.89–1.06x, one configuration at 0.52x), and NVENC encode. All the numbers.
SECURITY.md
before deciding where to run this. The code is intended to become secure against multi tenant use in the future so everything is written defensive,
but some issues are still open (to be fixed) and a project with a single author cannot be claimed to be battle tested without external review.
Do not put untrusted tenants behind it. GUEST HOST
────────────────────────────── ──────────────────────────────
CUDA / PyTorch / Vulkan / OpenGL
│ ioctl(/dev/nvidia*)
▼
nvkvm-guest.ko ─── virtio ────► QEMU: virtio-nvgpu device
│
▼
one sandboxed process per guest
process ──► NVIDIA driver ──► GPU
The guest never gets the device — something PCIe passthrough cannot offer, since a passed-through GPU keeps DMA access to host RAM. The work itself is never forwarded: setting a job up crosses the boundary, running it does not. And the VMM does not have to hold your display — a separate display broker owns the window, so QEMU needs no GL and no X11 or Wayland socket at all.
The request path end to end, and what the boundary does with a guest pointer:
ARCHITECTURE.md.
| GPU | architecture | host drivers | validate.sh |
|---|---|---|---|
| GTX 1660 SUPER / Ti, RTX 2080 Ti | Turing | 535, 575 | 28/28 |
| RTX 3060 → 3090, 3050 Laptop | Ampere GA10x | 545 → 610 | 28/28 |
| RTX 4060 → 4090, RTX 4000 Ada | Ada AD10x | 575 → 595 | 28/28 |
| RTX 5070, RTX 5090 | Blackwell | 580 | 28/28 |
| A100 80GB, H100 PCIe | GA100 / Hopper | 550 → 580 | 28/28 |
Six architectures; multiple GPUs in one guest work, up to six concurrent isolates each driving their own card. Full matrix, every box and footnote. Coverage is a function of what someone happened to rent, so it is uneven by construction — reports from hardware not listed are wanted, and a failure is worth more than a success.
37/37 is not proof your workload is correct. A real correctness bug has
passed it before — check against a host run
(what that bug was).| ARCHITECTURE.md | the request path and the five hard problems |
| SECURITY.md | the trust model, and what is not yet a boundary |
| Install | container, tarball, source; /dev/kvm; attestation |
| Parity | every measurement behind the numbers above |
| Tested platforms | the full hardware matrix |
| FAQ | including why not VFIO, vGPU or virtio-gpu |
Everything else: docs/README.md.
Experimental — a research artifact, not a supported product. It runs real workloads at host parity on six GPU architectures, including multiple GPUs in one guest. The largest open item is NVIDIA's X driver; everything else is in known limitations. Issues and measurements from hardware this repository has not exercised are welcome — see contributing.
If it did not build or boot for you, that is worth reporting even when it
looks like your own setup. Run scripts/nvkvm-report.sh on the host (and in
the guest if it gets that far) and paste the output into an issue — it reads
only and collects exactly what is needed. "It worked" is worth sending too: a
successful install leaves no trace anywhere visible from here.
nvkvm derives substantially from gVisor's nvproxy (Apache-2.0) for the
ioctl allowlist model, object tracking and frontend handling, and from
NVIDIA's open-gpu-kernel-modules for ABI struct definitions. Per-file
attribution is in CREDITS.
Two other public non-vendor efforts at driver-level NVIDIA GPU virtualization
are worth reading: nestrilabs/virtio-nvgpu
and straylight-software/isospin-microvm.
Apache-2.0, except the guest kernel module (src/guest/), which is GPL-2.0 as
required for kernel symbol access, and the QEMU shipped in release tarballs,
which is GPL-2.0 and rebuildable from the pinned upstream commit plus
patches/. See LICENSE and NOTICE — the
latter also carries the trademark and independence statement.
811 commits
141 commits
C
70.8%
Shell
16.8%
Python
9.8%
Go
1.1%