patches and low-level development discussion
 help / color / mirror / code / Atom feed
From: colbyt <colby@colbyt.com>
To: devel@spectrum-os.org
Cc: colbyt <colby@colbyt.com>
Subject: [PATCH 6/8] pkgs/cloud-hypervisor: update GPU patchset to v52
Date: Fri, 26 Jun 2026 11:55:06 -0700	[thread overview]
Message-ID: <20260626185509.3715326-7-colby@colbyt.com> (raw)
In-Reply-To: <20260626185509.3715326-1-colby@colbyt.com>

Update Spectrum's patched Cloud Hypervisor package to 52.0 and rebase
the local virtio-gpu/vhost-user GPU support onto that release.

Cloud Hypervisor 52.0 uses vhost 0.16.0 and vhost-user-backend 0.22.0,
so update the paired rust-vmm/vhost checkout as well.

Keep the local GPU support on top of that checkout, including the crosvm
SHMEM_MAP protocol-bit spelling needed by the crosvm GPU backend
packaged in the current nixpkgs pin.

The GPU frontend now uses the shared-memory region advertised by the
backend instead of assuming region 0, matching crosvm's host-visible
region ID.

The cargo vendor derivation vendors dependencies after applying the local
Cloud Hypervisor and vhost patches, so the patched vhost checkout is
included in the fixed-output dependency tree.

Signed-off-by: colbyt <colby@colbyt.com>
---
 .../0001-build-use-local-vhost.patch          |  38 +-
 ...0002-virtio-devices-add-a-GPU-device.patch | 684 ++++++++----------
 pkgs/cloud-hypervisor/default.nix             |  77 +-
 ...ost_user-add-crosvm-shmem-map-compat.patch |  79 ++
 4 files changed, 482 insertions(+), 396 deletions(-)
 create mode 100644 pkgs/cloud-hypervisor/vhost/0003-vhost_user-add-crosvm-shmem-map-compat.patch

diff --git a/pkgs/cloud-hypervisor/0001-build-use-local-vhost.patch b/pkgs/cloud-hypervisor/0001-build-use-local-vhost.patch
index 3e00250..8f18b94 100644
--- a/pkgs/cloud-hypervisor/0001-build-use-local-vhost.patch
+++ b/pkgs/cloud-hypervisor/0001-build-use-local-vhost.patch
@@ -1,55 +1,55 @@
 From fca364182f5c4e595384297316e9c74069ca5169 Mon Sep 17 00:00:00 2001
 From: Alyssa Ross <alyssa.ross@unikie.com>
 Date: Wed, 28 Sep 2022 12:18:19 +0000
-Subject: [PATCH 1/2] build: use local vhost
+Subject: [PATCH] build: use local vhost
 SPDX-FileCopyrightText: 2022 Unikie
 SPDX-FileCopyrightText: 2023 Alyssa Ross <hi@alyssa.is>
 SPDX-License-Identifier: Apache-2.0 AND LicenseRef-BSD-3-Clause-Google
 
 Signed-off-by: Alyssa Ross <alyssa.ross@unikie.com>
 Signed-off-by: Alyssa Ross <hi@alyssa.is>
+Signed-off-by: colbyt <colby@colbyt.com>
 ---
  Cargo.lock | 4 ----
  Cargo.toml | 4 ++--
  2 files changed, 2 insertions(+), 6 deletions(-)
 
 diff --git a/Cargo.lock b/Cargo.lock
-index 62bbf709f..39df61015 100644
+index d0a21c5..e7af1c2 100644
 --- a/Cargo.lock
 +++ b/Cargo.lock
-@@ -2304,8 +2304,6 @@ dependencies = [
+@@ -2408,8 +2408,6 @@ dependencies = [
  [[package]]
  name = "vhost"
- version = "0.14.0"
+ version = "0.16.0"
 -source = "registry+https://github.com/rust-lang/crates.io-index"
--checksum = "2a4dcad85a129d97d5d4b2f3c47a4affdeedd76bdcd02094bcb5d9b76cac2d05"
+-checksum = "ee90657203a8644e9a0860a0db6a7887d8ef0c7bc09fc22dfa4ae75df65bac86"
  dependencies = [
-  "bitflags 2.10.0",
+  "bitflags 2.11.1",
   "libc",
-@@ -2317,8 +2315,6 @@ dependencies = [
+@@ -2421,8 +2419,6 @@ dependencies = [
  [[package]]
  name = "vhost-user-backend"
- version = "0.20.0"
+ version = "0.22.0"
 -source = "registry+https://github.com/rust-lang/crates.io-index"
--checksum = "e183205a9ba7cb9c47fcb0fc0a07fc295a110efbb11ab78ad0d793b0a38a7bde"
+-checksum = "d5925983d8fb537752ad3e26604c0a17abfa5de77cb6773a096c8a959c9eca0f"
  dependencies = [
   "libc",
   "log",
 diff --git a/Cargo.toml b/Cargo.toml
-index b738dde5b..1118f1eb1 100644
+index 3ef574c..197f8fd 100644
 --- a/Cargo.toml
 +++ b/Cargo.toml
-@@ -55,8 +55,8 @@ seccompiler = "0.5.0"
- vfio-bindings = { version = "0.6.0", default-features = false }
- vfio-ioctls = { version = "0.5.1", default-features = false }
- vfio_user = { version = "0.1.1", default-features = false }
--vhost = { version = "0.14.0", default-features = false }
--vhost-user-backend = { version = "0.20.0", default-features = false }
+@@ -63,8 +63,8 @@ seccompiler = "0.5.0"
+ vfio-bindings = { version = "0.6.2", default-features = false }
+ vfio-ioctls = { version = "0.6.0", default-features = false }
+ vfio_user = { version = "0.1.3", default-features = false }
+-vhost = { version = "0.16.0", default-features = false }
+-vhost-user-backend = { version = "0.22.0", default-features = false }
 +vhost = { path = "../vhost/vhost" }
 +vhost-user-backend = { path = "../vhost/vhost-user-backend" }
  virtio-bindings = "0.2.6"
- virtio-queue = "0.16.0"
+ virtio-queue = "0.17.0"
  vm-fdt = "0.3.0"
 -- 
-2.53.0
-
+2.54.0
diff --git a/pkgs/cloud-hypervisor/0002-virtio-devices-add-a-GPU-device.patch b/pkgs/cloud-hypervisor/0002-virtio-devices-add-a-GPU-device.patch
index d53755b..b5cd93b 100644
--- a/pkgs/cloud-hypervisor/0002-virtio-devices-add-a-GPU-device.patch
+++ b/pkgs/cloud-hypervisor/0002-virtio-devices-add-a-GPU-device.patch
@@ -1,7 +1,7 @@
 From e4f29830f953c826c0fca137ef87ab3b67ac74ae Mon Sep 17 00:00:00 2001
 From: Alyssa Ross <alyssa.ross@unikie.com>
 Date: Wed, 7 Sep 2022 14:16:29 +0000
-Subject: [PATCH 2/2] virtio-devices: add a GPU device
+Subject: [PATCH] virtio-devices: add a GPU device
 SPDX-FileCopyrightText: The Cloud Hypervisor Authors
 SPDX-FileCopyrightText: 2017-2018 The Chromium OS Authors. All rights reserved.
 SPDX-FileCopyrightText: 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
@@ -26,65 +26,64 @@ Adding a GPU device from the command line looks like this:
 Signed-off-by: Alyssa Ross <alyssa.ross@unikie.com>
 Co-authored-by: Alyssa Ross <hi@alyssa.is>
 Signed-off-by: Alyssa Ross <hi@alyssa.is>
+Signed-off-by: colbyt <colby@colbyt.com>
 ---
- cloud-hypervisor/src/bin/ch-remote.rs         |  46 +-
- cloud-hypervisor/src/main.rs                  |  12 +-
+ cloud-hypervisor/src/bin/ch-remote.rs         |  44 +-
+ cloud-hypervisor/src/main.rs                  |   9 +-
  virtio-devices/src/device.rs                  |   4 +-
- virtio-devices/src/lib.rs                     |   4 +-
- virtio-devices/src/seccomp_filters.rs         |  16 +
+ virtio-devices/src/lib.rs                     |   6 +-
+ virtio-devices/src/seccomp_filters.rs         |  14 +
  virtio-devices/src/transport/pci_device.rs    |   4 +-
- virtio-devices/src/vhost_user/gpu.rs          | 411 ++++++++++++++++++
- virtio-devices/src/vhost_user/mod.rs          |   6 +
- .../src/vhost_user/vu_common_ctrl.rs          |   9 +-
+ virtio-devices/src/vhost_user/gpu.rs          | 421 ++++++++++++++++++
+ virtio-devices/src/vhost_user/mod.rs          |   8 +
+ .../src/vhost_user/vu_common_ctrl.rs          |   8 +-
  vmm/src/api/dbus/mod.rs                       |   7 +-
- vmm/src/api/http/http_endpoint.rs             |   9 +-
- vmm/src/api/http/mod.rs                       |  12 +-
- vmm/src/api/mod.rs                            |  47 +-
- vmm/src/api/openapi/cloud-hypervisor.yaml     |  39 ++
- vmm/src/config.rs                             | 109 +++++
- vmm/src/device_manager.rs                     | 144 +++++-
- vmm/src/lib.rs                                |  79 +++-
- vmm/src/vm.rs                                 |  28 +-
- vmm/src/vm_config.rs                          |  10 +
- 19 files changed, 967 insertions(+), 29 deletions(-)
- create mode 100644 virtio-devices/src/vhost_user/gpu.rs
+ vmm/src/api/http/http_endpoint.rs             |   3 +-
+ vmm/src/api/http/mod.rs                       |   6 +-
+ vmm/src/api/mod.rs                            |  45 +-
+ vmm/src/api/openapi/cloud-hypervisor.yaml     |  42 ++
+ vmm/src/config.rs                             |  72 +++
+ vmm/src/device_manager.rs                     | 147 +++++-
+ vmm/src/lib.rs                                |  77 +++-
+ vmm/src/vm.rs                                 |  26 +-
+ vmm/src/vm_config.rs                          |   8 +
+ 19 files changed, 933 insertions(+), 18 deletions(-)
+create mode 100644 virtio-devices/src/vhost_user/gpu.rs
 
 REUSE-IgnoreStart
 
 diff --git a/cloud-hypervisor/src/bin/ch-remote.rs b/cloud-hypervisor/src/bin/ch-remote.rs
-index fd48ffab1..680a2b62f 100644
+index 236e743..75845ed 100644
 --- a/cloud-hypervisor/src/bin/ch-remote.rs
 +++ b/cloud-hypervisor/src/bin/ch-remote.rs
-@@ -22,8 +22,8 @@ use option_parser::{ByteSized, ByteSizedParseError};
+@@ -24,7 +24,7 @@ use option_parser::{ByteSized, ByteSizedParseError};
  use thiserror::Error;
  use vmm::config::RestoreConfig;
  use vmm::vm_config::{
--    DeviceConfig, DiskConfig, FsConfig, NetConfig, PmemConfig, UserDeviceConfig, VdpaConfig,
--    VsockConfig,
-+    DeviceConfig, DiskConfig, FsConfig, GpuConfig, NetConfig, PmemConfig, UserDeviceConfig,
-+    VdpaConfig, VsockConfig,
+-    DeviceConfig, DiskConfig, FsConfig, GenericVhostUserConfig, NetConfig, PmemConfig,
++    DeviceConfig, DiskConfig, FsConfig, GenericVhostUserConfig, GpuConfig, NetConfig, PmemConfig,
+     UserDeviceConfig, VdpaConfig, VsockConfig,
  };
  #[cfg(feature = "dbus_api")]
- use zbus::{proxy, zvariant::Optional};
-@@ -49,6 +49,8 @@ enum Error {
-     AddDiskConfig(#[source] vmm::config::Error),
-     #[error("Error parsing filesystem syntax")]
+@@ -53,6 +53,8 @@ enum Error {
      AddFsConfig(#[source] vmm::config::Error),
+     #[error("Error parsing generic vhost-user syntax")]
+     AddGenericVhostUserConfig(#[source] vmm::config::Error),
 +    #[error("Error parsing GPU syntax: {0}")]
 +    AddGpuConfig(#[source] vmm::config::Error),
      #[error("Error parsing persistent memory syntax")]
      AddPmemConfig(#[source] vmm::config::Error),
      #[error("Error parsing network syntax")]
-@@ -83,6 +85,7 @@ trait DBusApi1 {
-     fn vm_add_device(&self, device_config: &str) -> zbus::Result<Optional<String>>;
-     fn vm_add_disk(&self, disk_config: &str) -> zbus::Result<Optional<String>>;
-     fn vm_add_fs(&self, fs_config: &str) -> zbus::Result<Optional<String>>;
+@@ -93,6 +95,7 @@ trait DBusApi1 {
+         &self,
+         generic_vhost_user_config: &str,
+     ) -> zbus::Result<Optional<String>>;
 +    fn vm_add_gpu(&self, gpu_config: &str) -> zbus::Result<Optional<String>>;
      fn vm_add_net(&self, net_config: &str) -> zbus::Result<Optional<String>>;
      fn vm_add_pmem(&self, pmem_config: &str) -> zbus::Result<Optional<String>>;
      fn vm_add_user_device(&self, vm_add_user_device: &str) -> zbus::Result<Optional<String>>;
-@@ -155,6 +158,10 @@ impl<'a> DBusApi1ProxyBlocking<'a> {
-         self.print_response(self.vm_add_fs(fs_config))
+@@ -169,6 +172,10 @@ impl<'a> DBusApi1ProxyBlocking<'a> {
+         self.print_response(self.vm_add_generic_vhost_user(generic_vhost_user_config))
      }
  
 +    fn api_vm_add_gpu(&self, gpu_config: &str) -> ApiResult {
@@ -94,9 +93,9 @@ index fd48ffab1..680a2b62f 100644
      fn api_vm_add_net(&self, net_config: &str) -> ApiResult {
          self.print_response(self.vm_add_net(net_config))
      }
-@@ -398,6 +405,17 @@ fn rest_api_do_command(matches: &ArgMatches, socket: &mut UnixStream) -> ApiResu
-             simple_api_command(socket, "PUT", "add-fs", Some(&fs_config))
-                 .map_err(Error::HttpApiClient)
+@@ -428,6 +435,17 @@ fn rest_api_do_command(matches: &ArgMatches, socket: &mut UnixStream) -> ApiResu
+             )
+             .map_err(Error::HttpApiClient)
          }
 +        Some("add-gpu") => {
 +            let gpu_config = add_gpu_config(
@@ -112,9 +111,9 @@ index fd48ffab1..680a2b62f 100644
          Some("add-pmem") => {
              let pmem_config = add_pmem_config(
                  matches
-@@ -620,6 +638,16 @@ fn dbus_api_do_command(matches: &ArgMatches, proxy: &DBusApi1ProxyBlocking<'_>)
+@@ -656,6 +674,16 @@ fn dbus_api_do_command(matches: &ArgMatches, proxy: &DBusApi1ProxyBlocking<'_>)
              )?;
-             proxy.api_vm_add_fs(&fs_config)
+             proxy.api_vm_add_generic_vhost_user(&generic_vhost_user_config)
          }
 +        Some("add-gpu") => {
 +            let gpu_config = add_gpu_config(
@@ -129,8 +128,8 @@ index fd48ffab1..680a2b62f 100644
          Some("add-pmem") => {
              let pmem_config = add_pmem_config(
                  matches
-@@ -835,6 +863,13 @@ fn add_fs_config(config: &str) -> Result<String, Error> {
-     Ok(fs_config)
+@@ -875,6 +903,13 @@ fn add_generic_vhost_user_config(config: &str) -> Result<String, Error> {
+     Ok(generic_vhost_user_config)
  }
  
 +fn add_gpu_config(config: &str) -> Result<String, Error> {
@@ -143,12 +142,12 @@ index fd48ffab1..680a2b62f 100644
  fn add_pmem_config(config: &str) -> Result<String, Error> {
      let pmem_config = PmemConfig::parse(config).map_err(Error::AddPmemConfig)?;
      let pmem_config = serde_json::to_string(&pmem_config).unwrap();
-@@ -981,6 +1016,13 @@ fn get_cli_commands_sorted() -> Box<[Command]> {
+@@ -1026,6 +1061,13 @@ fn get_cli_commands_sorted() -> Box<[Command]> {
                      .index(1)
-                     .help(vmm::vm_config::FsConfig::SYNTAX),
+                     .help(vmm::vm_config::GenericVhostUserConfig::SYNTAX),
              ),
 +        Command::new("add-gpu")
-+            .about("Add virtio-gpu backed gpu device")
++            .about("Add virtio-gpu backed GPU device")
 +            .arg(
 +                Arg::new("gpu_config")
 +                    .index(1)
@@ -158,44 +157,41 @@ index fd48ffab1..680a2b62f 100644
              .about("Add network device")
              .arg(Arg::new("net_config").index(1).help(NetConfig::SYNTAX)),
 diff --git a/cloud-hypervisor/src/main.rs b/cloud-hypervisor/src/main.rs
-index d08293b6e..cde764e8a 100644
+index 5de2e4c..2f5afce 100644
 --- a/cloud-hypervisor/src/main.rs
 +++ b/cloud-hypervisor/src/main.rs
-@@ -32,9 +32,9 @@ use vmm::vm_config::FwCfgConfig;
- #[cfg(feature = "ivshmem")]
+@@ -33,7 +33,7 @@ use vmm::vm_config::FwCfgConfig;
  use vmm::vm_config::IvshmemConfig;
  use vmm::vm_config::{
--    BalloonConfig, DeviceConfig, DiskConfig, FsConfig, LandlockConfig, NetConfig, NumaConfig,
--    PciSegmentConfig, PmemConfig, RateLimiterGroupConfig, TpmConfig, UserDeviceConfig, VdpaConfig,
--    VmConfig, VsockConfig,
-+    BalloonConfig, DeviceConfig, DiskConfig, FsConfig, GpuConfig, LandlockConfig, NetConfig,
-+    NumaConfig, PciSegmentConfig, PmemConfig, RateLimiterGroupConfig, TpmConfig, UserDeviceConfig,
-+    VdpaConfig, VmConfig, VsockConfig,
+     BalloonConfig, ConsoleConfig, DeviceConfig, DiskConfig, FsConfig, GenericVhostUserConfig,
+-    LandlockConfig, NetConfig, NumaConfig, PciSegmentConfig, PlatformConfig, PmemConfig,
++    GpuConfig, LandlockConfig, NetConfig, NumaConfig, PciSegmentConfig, PlatformConfig, PmemConfig,
+     RateLimiterGroupConfig, RngConfig, SerialConfig, TpmConfig, UserDeviceConfig, VdpaConfig,
+     VmConfig, VsockConfig,
  };
- use vmm_sys_util::eventfd::EventFd;
- use vmm_sys_util::signal::block_signal;
-@@ -280,6 +280,11 @@ fn get_cli_options_sorted(
-             .help("GDB socket (UNIX domain socket): path=</path/to/a/file>")
-             .num_args(1)
-             .group("vmm-config"),
+@@ -252,6 +252,12 @@ fn get_cli_options_sorted(
+             .num_args(1..)
+             .action(ArgAction::Append)
+             .group("vm-config"),
 +        Arg::new("gpu")
 +            .long("gpu")
 +            .help(GpuConfig::SYNTAX)
 +            .num_args(1..)
++            .action(ArgAction::Append)
 +            .group("vm-config"),
          #[cfg(feature = "igvm")]
          Arg::new("igvm")
              .long("igvm")
-@@ -998,6 +1003,7 @@ mod unit_tests {
-             },
+@@ -1011,6 +1017,7 @@ mod unit_tests {
              balloon: None,
              fs: None,
+             generic_vhost_user: None,
 +            gpu: None,
              pmem: None,
-             serial: ConsoleConfig {
-                 file: None,
+             serial: SerialConfig {
+                 common: CommonConsoleConfig {
 diff --git a/virtio-devices/src/device.rs b/virtio-devices/src/device.rs
-index f0ed28f51..892bf08ee 100644
+index 4c61ba3..8b44101 100644
 --- a/virtio-devices/src/device.rs
 +++ b/virtio-devices/src/device.rs
 @@ -6,7 +6,7 @@
@@ -206,8 +202,8 @@ index f0ed28f51..892bf08ee 100644
 +use std::collections::{BTreeMap, HashMap};
  use std::io::Write;
  use std::num::Wrapping;
- use std::sync::atomic::{AtomicBool, Ordering};
-@@ -50,7 +50,7 @@ pub struct VirtioSharedMemoryList {
+ use std::sync::atomic::{AtomicBool, AtomicU8, Ordering};
+@@ -58,7 +58,7 @@ pub struct VirtioSharedMemoryList {
      pub mem_slot: u32,
      pub addr: GuestAddress,
      pub mapping: Arc<MmapRegion>,
@@ -215,31 +211,33 @@ index f0ed28f51..892bf08ee 100644
 +    pub region_list: BTreeMap<u8, VirtioSharedMemory>,
  }
  
- /// Trait for virtio devices to be driven by a virtio transport.
+ pub struct ActivationContext {
 diff --git a/virtio-devices/src/lib.rs b/virtio-devices/src/lib.rs
-index da4f1c91b..4298e23ae 100644
+index 6ac3977..5f8aa61 100644
 --- a/virtio-devices/src/lib.rs
 +++ b/virtio-devices/src/lib.rs
-@@ -43,7 +43,7 @@ pub use self::block::{Block, BlockState};
+@@ -44,7 +44,7 @@ pub use self::block::{Block, BlockState};
  pub use self::console::{Console, ConsoleResizer, Endpoint};
  pub use self::device::{
-     DmaRemapping, VirtioCommon, VirtioDevice, VirtioInterrupt, VirtioInterruptType,
--    VirtioSharedMemoryList,
-+    VirtioSharedMemory, VirtioSharedMemoryList,
+     ActivationContext, DmaRemapping, VirtioCommon, VirtioDevice, VirtioInterrupt,
+-    VirtioInterruptType, VirtioSharedMemoryList,
++    VirtioInterruptType, VirtioSharedMemory, VirtioSharedMemoryList,
  };
  pub use self::epoll_helper::{
      EPOLL_HELPER_EVENT_LAST, EpollHelper, EpollHelperError, EpollHelperHandler,
-@@ -91,6 +91,8 @@ pub enum ActivateError {
+@@ -114,7 +114,9 @@ pub enum ActivateError {
+     VhostUserFsSetup(#[source] vhost_user::Error),
      #[error("Failed to setup vhost-user daemon")]
      VhostUserSetup(#[source] vhost_user::Error),
-     #[error("Failed to create seccomp filter")]
+-    #[error("Failed to create seccomp filter")]
++    #[error("Failed to setup vhost-user-gpu daemon")]
 +    VhostUserGpuSetup(#[source] vhost_user::Error),
 +    #[error("Failed to create seccomp filter: {0}")]
      CreateSeccompFilter(#[source] seccompiler::Error),
      #[error("Failed to create rate limiter")]
      CreateRateLimiter(#[source] std::io::Error),
 diff --git a/virtio-devices/src/seccomp_filters.rs b/virtio-devices/src/seccomp_filters.rs
-index 07601b68a..68910c756 100644
+index 73c347e..5531747 100644
 --- a/virtio-devices/src/seccomp_filters.rs
 +++ b/virtio-devices/src/seccomp_filters.rs
 @@ -24,6 +24,7 @@ pub enum Thread {
@@ -247,10 +245,10 @@ index 07601b68a..68910c756 100644
      VirtioVhostBlock,
      VirtioVhostFs,
 +    VirtioVhostGpu,
+     VirtioGenericVhostUser,
      VirtioVhostNet,
      VirtioVhostNetCtl,
-     VirtioVsock,
-@@ -192,6 +193,20 @@ fn virtio_vhost_fs_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
+@@ -219,6 +220,18 @@ fn virtio_generic_vhost_user_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
      ]
  }
  
@@ -261,8 +259,6 @@ index 07601b68a..68910c756 100644
 +        (libc::SYS_getcwd, vec![]),
 +        (libc::SYS_nanosleep, vec![]),
 +        (libc::SYS_recvmsg, vec![]),
-+        (libc::SYS_recvmsg, vec![]),
-+        (libc::SYS_sendmsg, vec![]),
 +        (libc::SYS_sendmsg, vec![]),
 +        (libc::SYS_socket, vec![]),
 +    ]
@@ -271,19 +267,19 @@ index 07601b68a..68910c756 100644
  fn virtio_vhost_net_ctl_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
      vec![]
  }
-@@ -271,6 +286,7 @@ fn get_seccomp_rules(thread_type: Thread) -> Vec<(i64, Vec<SeccompRule>)> {
+@@ -299,6 +312,7 @@ fn get_seccomp_rules(thread_type: Thread) -> Vec<(i64, Vec<SeccompRule>)> {
          Thread::VirtioRng => virtio_rng_thread_rules(),
          Thread::VirtioVhostBlock => virtio_vhost_block_thread_rules(),
          Thread::VirtioVhostFs => virtio_vhost_fs_thread_rules(),
 +        Thread::VirtioVhostGpu => virtio_vhost_gpu_thread_rules(),
+         Thread::VirtioGenericVhostUser => virtio_generic_vhost_user_thread_rules(),
          Thread::VirtioVhostNet => virtio_vhost_net_thread_rules(),
          Thread::VirtioVhostNetCtl => virtio_vhost_net_ctl_thread_rules(),
-         Thread::VirtioVsock => virtio_vsock_thread_rules(),
 diff --git a/virtio-devices/src/transport/pci_device.rs b/virtio-devices/src/transport/pci_device.rs
-index 408611e29..08ba91908 100644
+index ac37c58..5b33239 100644
 --- a/virtio-devices/src/transport/pci_device.rs
 +++ b/virtio-devices/src/transport/pci_device.rs
-@@ -1036,11 +1036,11 @@ impl PciDevice for VirtioPciDevice {
+@@ -1092,11 +1092,11 @@ impl PciDevice for VirtioPciDevice {
                      PciDeviceError::IoRegistrationFailed(shm_list.addr.raw_value(), e)
                  })?;
  
@@ -299,10 +295,10 @@ index 408611e29..08ba91908 100644
                      );
 diff --git a/virtio-devices/src/vhost_user/gpu.rs b/virtio-devices/src/vhost_user/gpu.rs
 new file mode 100644
-index 000000000..7eec07ba6
+index 0000000..f04c74a
 --- /dev/null
 +++ b/virtio-devices/src/vhost_user/gpu.rs
-@@ -0,0 +1,411 @@
+@@ -0,0 +1,423 @@
 +// Copyright 2019 Intel Corporation. All Rights Reserved.
 +// Copyright 2022 Unikie
 +// Copyright 2023 Alyssa Ross <hi@alyssa.is>
@@ -317,8 +313,8 @@ index 000000000..7eec07ba6
 +use log::error;
 +use seccompiler::SeccompAction;
 +use vhost::vhost_user::message::{
-+    VhostSharedMemoryRegion, VhostUserConfigFlags, VhostUserProtocolFeatures, VhostUserShmemMapMsg,
-+    VhostUserShmemUnmapMsg, VhostUserVirtioFeatures,
++    VhostUserConfigFlags, VhostUserMMap, VhostUserMMapFlags, VhostUserProtocolFeatures,
++    VhostUserShMemConfig, VhostUserVirtioFeatures,
 +};
 +use vhost::vhost_user::{
 +    FrontendReqHandler, HandlerResult, VhostUserFrontend, VhostUserFrontendReqHandler,
@@ -327,7 +323,6 @@ index 000000000..7eec07ba6
 +    VIRTIO_GPU_F_CONTEXT_INIT, VIRTIO_GPU_F_RESOURCE_BLOB, VIRTIO_GPU_F_RESOURCE_UUID,
 +    VIRTIO_GPU_F_VIRGL,
 +};
-+use virtio_queue::Queue;
 +use vm_device::UserspaceMapping;
 +use vm_memory::volatile_memory::PtrGuardMut;
 +use vm_memory::{GuestMemoryAtomic, VolatileMemory};
@@ -341,8 +336,8 @@ index 000000000..7eec07ba6
 +use crate::vhost_user::VhostUserCommon;
 +use crate::{
 +    ActivateError, ActivateResult, GuestMemoryMmap, GuestRegionMmap, MmapRegion,
-+    VIRTIO_F_IOMMU_PLATFORM, VIRTIO_F_VERSION_1, VirtioCommon, VirtioDevice, VirtioDeviceType,
-+    VirtioInterrupt, VirtioSharedMemoryList,
++    VIRTIO_F_ACCESS_PLATFORM, VIRTIO_F_VERSION_1, VirtioCommon, VirtioDevice, VirtioDeviceType,
++    VirtioSharedMemoryList,
 +};
 +
 +const QUEUE_SIZES: &[u16] = &[256, 16];
@@ -369,8 +364,16 @@ index 000000000..7eec07ba6
 +}
 +
 +impl VhostUserFrontendReqHandler for BackendReqHandler {
-+    fn shmem_map(&self, req: &VhostUserShmemMapMsg, fd: &dyn AsRawFd) -> HandlerResult<u64> {
++    fn shmem_map(&self, req: &VhostUserMMap, fd: &dyn AsRawFd) -> HandlerResult<u64> {
 +        let target = self.ptr_guard_mut(req.shm_offset, req.len)?;
++        let flags = VhostUserMMapFlags::from_bits(req.flags)
++            .ok_or_else(|| io::Error::from_raw_os_error(libc::EINVAL))?;
++        let prot = libc::PROT_READ
++            | if flags.contains(VhostUserMMapFlags::WRITABLE) {
++                libc::PROT_WRITE
++            } else {
++                0
++            };
 +
 +        // SAFETY: we've checked we're only giving addr and length
 +        // within the region, and are passing MAP_FIXED to ensure they
@@ -379,9 +382,9 @@ index 000000000..7eec07ba6
 +            libc::mmap(
 +                target.as_ptr().cast(),
 +                target.len(),
-+                req.flags.bits() as i32,
++                prot,
 +                // https://bugzilla.kernel.org/show_bug.cgi?id=217238
-+                if req.flags.bits() as i32 & libc::PROT_WRITE != 0 {
++                if flags.contains(VhostUserMMapFlags::WRITABLE) {
 +                    libc::MAP_SHARED
 +                } else {
 +                    libc::MAP_PRIVATE
@@ -398,7 +401,7 @@ index 000000000..7eec07ba6
 +        Ok(0)
 +    }
 +
-+    fn shmem_unmap(&self, req: &VhostUserShmemUnmapMsg) -> HandlerResult<u64> {
++    fn shmem_unmap(&self, req: &VhostUserMMap) -> HandlerResult<u64> {
 +        let target = self.ptr_guard_mut(req.shm_offset, req.len)?;
 +
 +        // SAFETY: we've checked we're only giving addr and length
@@ -445,9 +448,10 @@ index 000000000..7eec07ba6
 +        seccomp_action: SeccompAction,
 +        exit_evt: EventFd,
 +        iommu: bool,
-+    ) -> Result<(Gpu, VhostSharedMemoryRegion)> {
++    ) -> Result<(Gpu, VhostUserShMemConfig)> {
 +        // Connect to the vhost-user socket.
-+        let mut vu = VhostUserHandle::connect_vhost_user(false, path, NUM_QUEUES as u64, false)?;
++        let mut vu =
++            VhostUserHandle::connect_vhost_user(false, path, NUM_QUEUES as u64, false, None)?;
 +
 +        let avail_features = 1 << VIRTIO_F_VERSION_1
 +            | 1 << VIRTIO_GPU_F_VIRGL
@@ -458,19 +462,23 @@ index 000000000..7eec07ba6
 +
 +        let avail_protocol_features = VhostUserProtocolFeatures::CONFIG
 +            | VhostUserProtocolFeatures::BACKEND_REQ
-+            | VhostUserProtocolFeatures::SHARED_MEMORY_REGIONS;
++            | VhostUserProtocolFeatures::SHMEM_MAP;
 +
 +        let (acked_features, acked_protocol_features) =
 +            vu.negotiate_features_vhost_user(avail_features, avail_protocol_features)?;
 +
-+        let shm_regions = vu.get_shared_memory_regions()?;
-+        if shm_regions.len() != 1 {
++        let shm_config = vu.get_shmem_config()?;
++        let shmem_regions_count = shm_config
++            .memory_sizes
++            .iter()
++            .filter(|&&len| len != 0)
++            .count();
++        if shm_config.nregions != 1 || shmem_regions_count != 1 {
 +            return Err(Error::VhostUserUnexpectedSharedMemoryRegionsCount(
 +                1,
-+                shm_regions.len(),
++                shmem_regions_count,
 +            ));
 +        }
-+        let shm_region = shm_regions[0];
 +
 +        Ok((
 +            Gpu {
@@ -506,7 +514,7 @@ index 000000000..7eec07ba6
 +                exit_evt,
 +                iommu,
 +            },
-+            shm_region,
++            shm_config,
 +        ))
 +    }
 +
@@ -536,7 +544,7 @@ index 000000000..7eec07ba6
 +    fn features(&self) -> u64 {
 +        let mut features = self.common.avail_features;
 +        if self.iommu {
-+            features |= 1u64 << VIRTIO_F_IOMMU_PLATFORM;
++            features |= 1u64 << VIRTIO_F_ACCESS_PLATFORM;
 +        }
 +        features
 +    }
@@ -564,12 +572,13 @@ index 000000000..7eec07ba6
 +        }
 +    }
 +
-+    fn activate(
-+        &mut self,
-+        mem: GuestMemoryAtomic<GuestMemoryMmap>,
-+        interrupt_cb: Arc<dyn VirtioInterrupt>,
-+        queues: Vec<(usize, Queue, EventFd)>,
-+    ) -> ActivateResult {
++    fn activate(&mut self, context: crate::device::ActivationContext) -> ActivateResult {
++        let crate::device::ActivationContext {
++            mem,
++            interrupt_cb,
++            queues,
++            device_status,
++        } = context;
 +        self.common.activate(&queues, interrupt_cb.clone())?;
 +        self.guest_memory = Some(mem.clone());
 +
@@ -607,7 +616,7 @@ index 000000000..7eec07ba6
 +        let mut handler = self.vu_common.activate(
 +            mem,
 +            &queues,
-+            interrupt_cb,
++            interrupt_cb.clone(),
 +            self.common.acked_features,
 +            backend_req_handler,
 +            kill_evt,
@@ -624,6 +633,8 @@ index 000000000..7eec07ba6
 +            Thread::VirtioVhostGpu,
 +            &mut epoll_threads,
 +            &self.exit_evt,
++            device_status.clone(),
++            interrupt_cb.clone(),
 +            move || handler.run(&paused, paused_sync.as_ref().unwrap()),
 +        )?;
 +        self.epoll_thread = Some(epoll_threads.remove(0));
@@ -632,17 +643,17 @@ index 000000000..7eec07ba6
 +        Ok(())
 +    }
 +
-+    fn reset(&mut self) -> Option<Arc<dyn VirtioInterrupt>> {
++    fn reset(&mut self) {
 +        // We first must resume the virtio thread if it was paused.
 +        if self.common.pause_evt.take().is_some() {
-+            self.common.resume().ok()?;
++            self.common.resume().ok();
 +        }
 +
 +        if let Some(vu) = &self.vu_common.vu
 +            && let Err(e) = vu.lock().unwrap().reset_vhost_user()
 +        {
 +            error!("Failed to reset vhost-user daemon: {e:?}");
-+            return None;
++            return;
 +        }
 +
 +        if let Some(kill_evt) = self.common.kill_evt.take() {
@@ -651,9 +662,6 @@ index 000000000..7eec07ba6
 +        }
 +
 +        event!("virtio-device", "reset", "id", &self.id);
-+
-+        // Return the interrupt
-+        Some(self.common.interrupt_cb.take().unwrap())
 +    }
 +
 +    fn shutdown(&mut self) {
@@ -715,24 +723,25 @@ index 000000000..7eec07ba6
 +    }
 +}
 diff --git a/virtio-devices/src/vhost_user/mod.rs b/virtio-devices/src/vhost_user/mod.rs
-index 05233a0be..f2e83ff84 100644
+index babc823..76146b3 100644
 --- a/virtio-devices/src/vhost_user/mod.rs
 +++ b/virtio-devices/src/vhost_user/mod.rs
-@@ -33,11 +33,13 @@ use crate::{
- 
+@@ -37,12 +37,14 @@ use crate::{
  pub mod blk;
  pub mod fs;
+ pub mod generic_vhost_user;
 +pub mod gpu;
  pub mod net;
  pub mod vu_common_ctrl;
  
  pub use self::blk::Blk;
  pub use self::fs::*;
+ pub use self::generic_vhost_user::GenericVhostUser;
 +pub use self::gpu::*;
  pub use self::net::Net;
  pub use self::vu_common_ctrl::VhostUserConfig;
  
-@@ -75,6 +77,8 @@ pub enum Error {
+@@ -82,6 +84,8 @@ pub enum Error {
      VhostUserGetQueueMaxNum(#[source] VhostError),
      #[error("Get protocol features failed")]
      VhostUserGetProtocolFeatures(#[source] VhostError),
@@ -741,36 +750,37 @@ index 05233a0be..f2e83ff84 100644
      #[error("Get vring base failed")]
      VhostUserGetVringBase(#[source] VhostError),
      #[error("Vhost-user Backend not support vhost-user protocol")]
-@@ -123,6 +127,8 @@ pub enum Error {
+@@ -130,6 +134,10 @@ pub enum Error {
      VhostUserSetInflight(#[source] VhostError),
      #[error("Failed setting the log base")]
      VhostUserSetLogBase(#[source] VhostError),
 +    #[error("Expected {0} shared memory regions; got {1}")]
 +    VhostUserUnexpectedSharedMemoryRegionsCount(usize, usize),
++    #[error("Invalid shared memory region")]
++    VhostUserInvalidSharedMemoryRegion,
      #[error("Invalid used address")]
      UsedAddress,
      #[error("Invalid features provided from vhost-user backend")]
 diff --git a/virtio-devices/src/vhost_user/vu_common_ctrl.rs b/virtio-devices/src/vhost_user/vu_common_ctrl.rs
-index 264635149..220b49112 100644
+index 23a37c3..8c668a3 100644
 --- a/virtio-devices/src/vhost_user/vu_common_ctrl.rs
 +++ b/virtio-devices/src/vhost_user/vu_common_ctrl.rs
-@@ -13,7 +13,8 @@ use std::time::{Duration, Instant};
- use log::{error, info};
- use vhost::vhost_kern::vhost_binding::{VHOST_F_LOG_ALL, VHOST_VRING_F_LOG};
+@@ -14,7 +14,7 @@ use log::{error, info};
+ use vhost::vhost_kern::vhost_binding::VHOST_VRING_F_LOG;
  use vhost::vhost_user::message::{
--    VhostUserHeaderFlag, VhostUserInflight, VhostUserProtocolFeatures, VhostUserVirtioFeatures,
-+    VhostSharedMemoryRegion, VhostUserHeaderFlag, VhostUserInflight, VhostUserProtocolFeatures,
-+    VhostUserVirtioFeatures,
+     VhostTransferStateDirection, VhostTransferStatePhase, VhostUserHeaderFlag, VhostUserInflight,
+-    VhostUserProtocolFeatures, VhostUserVirtioFeatures,
++    VhostUserProtocolFeatures, VhostUserShMemConfig, VhostUserVirtioFeatures,
  };
  use vhost::vhost_user::{
      Frontend, FrontendReqHandler, VhostUserFrontend, VhostUserFrontendReqHandler,
-@@ -107,6 +108,12 @@ impl VhostUserHandle {
+@@ -114,6 +114,12 @@ impl VhostUserHandle {
              .map_err(Error::VhostUserAddMemReg)
      }
  
-+    pub fn get_shared_memory_regions(&self) -> Result<Vec<VhostSharedMemoryRegion>> {
++    pub fn get_shmem_config(&mut self) -> Result<VhostUserShMemConfig> {
 +        self.vu
-+            .get_shared_memory_regions()
++            .get_shmem_config()
 +            .map_err(Error::VhostUserGetSharedMemoryRegions)
 +    }
 +
@@ -778,20 +788,20 @@ index 264635149..220b49112 100644
          &mut self,
          avail_features: u64,
 diff --git a/vmm/src/api/dbus/mod.rs b/vmm/src/api/dbus/mod.rs
-index 6f75fb5cd..78275925d 100644
+index ae39feb..aa579e9 100644
 --- a/vmm/src/api/dbus/mod.rs
 +++ b/vmm/src/api/dbus/mod.rs
 @@ -22,7 +22,7 @@ use super::{ApiAction, ApiRequest};
  #[cfg(all(target_arch = "x86_64", feature = "guest_debug"))]
  use crate::api::VmCoredump;
  use crate::api::{
--    AddDisk, Body, VmAddDevice, VmAddFs, VmAddNet, VmAddPmem, VmAddUserDevice, VmAddVdpa,
-+    AddDisk, Body, VmAddDevice, VmAddFs, VmAddGpu, VmAddNet, VmAddPmem, VmAddUserDevice, VmAddVdpa,
-     VmAddVsock, VmBoot, VmCounters, VmCreate, VmDelete, VmInfo, VmPause, VmPowerButton, VmReboot,
-     VmReceiveMigration, VmRemoveDevice, VmResize, VmResizeZone, VmRestore, VmResume,
-     VmSendMigration, VmShutdown, VmSnapshot, VmmPing, VmmShutdown,
-@@ -144,6 +144,11 @@ impl DBusApi {
-         self.vm_action(&VmAddFs, fs_config).await
+-    AddDisk, Body, VmAddDevice, VmAddFs, VmAddGenericVhostUser, VmAddNet, VmAddPmem,
++    AddDisk, Body, VmAddDevice, VmAddFs, VmAddGenericVhostUser, VmAddGpu, VmAddNet, VmAddPmem,
+     VmAddUserDevice, VmAddVdpa, VmAddVsock, VmBoot, VmCounters, VmCreate, VmDelete, VmInfo,
+     VmPause, VmPowerButton, VmReboot, VmReceiveMigration, VmRemoveDevice, VmResize, VmResizeZone,
+     VmRestore, VmResume, VmSendMigration, VmShutdown, VmSnapshot, VmmPing, VmmShutdown,
+@@ -154,6 +154,11 @@ impl DBusApi {
+             .await
      }
  
 +    async fn vm_add_gpu(&self, gpu_config: String) -> Result<Optional<String>> {
@@ -803,54 +813,42 @@ index 6f75fb5cd..78275925d 100644
          let mut net_config: NetConfig = serde_json::from_str(&net_config).map_err(api_error)?;
          if net_config.fds.is_some() {
 diff --git a/vmm/src/api/http/http_endpoint.rs b/vmm/src/api/http/http_endpoint.rs
-index e463a2081..0936eff22 100644
+index 92b53ac..0e67daf 100644
 --- a/vmm/src/api/http/http_endpoint.rs
 +++ b/vmm/src/api/http/http_endpoint.rs
-@@ -45,10 +45,10 @@ use crate::api::VmCoredump;
+@@ -45,7 +45,7 @@ use crate::api::VmCoredump;
  use crate::api::http::http_endpoint::fds_helper::{attach_fds_to_cfg, attach_fds_to_cfgs};
  use crate::api::http::{EndpointHandler, HttpError, error_response};
  use crate::api::{
--    AddDisk, ApiAction, ApiError, ApiRequest, NetConfig, VmAddDevice, VmAddFs, VmAddNet, VmAddPmem,
--    VmAddUserDevice, VmAddVdpa, VmAddVsock, VmBoot, VmConfig, VmCounters, VmDelete, VmNmi, VmPause,
--    VmPowerButton, VmReboot, VmReceiveMigration, VmRemoveDevice, VmResize, VmResizeDisk,
--    VmResizeZone, VmRestore, VmResume, VmSendMigration, VmShutdown, VmSnapshot,
-+    AddDisk, ApiAction, ApiError, ApiRequest, NetConfig, VmAddDevice, VmAddFs, VmAddGpu, VmAddNet,
-+    VmAddPmem, VmAddUserDevice, VmAddVdpa, VmAddVsock, VmBoot, VmConfig, VmCounters, VmDelete,
-+    VmNmi, VmPause, VmPowerButton, VmReboot, VmReceiveMigration, VmRemoveDevice, VmResize,
-+    VmResizeDisk, VmResizeZone, VmRestore, VmResume, VmSendMigration, VmShutdown, VmSnapshot,
- };
- use crate::config::RestoreConfig;
- use crate::cpu::Error as CpuError;
-@@ -419,6 +419,7 @@ vm_action_put_handler!(VmNmi);
- vm_action_put_handler_body!(VmAddDevice);
+-    AddDisk, ApiAction, ApiError, ApiRequest, NetConfig, VmAddDevice, VmAddFs,
++    AddDisk, ApiAction, ApiError, ApiRequest, NetConfig, VmAddDevice, VmAddFs, VmAddGpu,
+     VmAddGenericVhostUser, VmAddNet, VmAddPmem, VmAddUserDevice, VmAddVdpa, VmAddVsock, VmBoot,
+     VmConfig, VmCounters, VmDelete, VmNmi, VmPause, VmPowerButton, VmReboot, VmReceiveMigration,
+     VmRemoveDevice, VmResize, VmResizeDisk, VmResizeZone, VmRestore, VmResume, VmSendMigration,
+@@ -421,6 +421,7 @@ vm_action_put_handler_body!(VmAddDevice);
  vm_action_put_handler_body!(AddDisk);
  vm_action_put_handler_body!(VmAddFs);
+ vm_action_put_handler_body!(VmAddGenericVhostUser);
 +vm_action_put_handler_body!(VmAddGpu);
  vm_action_put_handler_body!(VmAddPmem);
  vm_action_put_handler_body!(VmAddVdpa);
  vm_action_put_handler_body!(VmAddVsock);
 diff --git a/vmm/src/api/http/mod.rs b/vmm/src/api/http/mod.rs
-index 2aa52e8e3..7eccb57d1 100644
+index f7cea4f..bd71ce9 100644
 --- a/vmm/src/api/http/mod.rs
 +++ b/vmm/src/api/http/mod.rs
-@@ -28,10 +28,10 @@ use self::http_endpoint::{VmActionHandler, VmCreate, VmInfo, VmmPing, VmmShutdow
+@@ -28,7 +28,7 @@ use self::http_endpoint::{VmActionHandler, VmCreate, VmInfo, VmmPing, VmmShutdow
  #[cfg(all(target_arch = "x86_64", feature = "guest_debug"))]
  use crate::api::VmCoredump;
  use crate::api::{
--    AddDisk, ApiError, ApiRequest, VmAddDevice, VmAddFs, VmAddNet, VmAddPmem, VmAddUserDevice,
--    VmAddVdpa, VmAddVsock, VmBoot, VmCounters, VmDelete, VmNmi, VmPause, VmPowerButton, VmReboot,
--    VmReceiveMigration, VmRemoveDevice, VmResize, VmResizeDisk, VmResizeZone, VmRestore, VmResume,
--    VmSendMigration, VmShutdown, VmSnapshot,
-+    AddDisk, ApiError, ApiRequest, VmAddDevice, VmAddFs, VmAddGpu, VmAddNet, VmAddPmem,
-+    VmAddUserDevice, VmAddVdpa, VmAddVsock, VmBoot, VmCounters, VmDelete, VmNmi, VmPause,
-+    VmPowerButton, VmReboot, VmReceiveMigration, VmRemoveDevice, VmResize, VmResizeDisk,
-+    VmResizeZone, VmRestore, VmResume, VmSendMigration, VmShutdown, VmSnapshot,
- };
- use crate::landlock::Landlock;
- use crate::seccomp_filters::{Thread, get_seccomp_filter};
-@@ -196,6 +196,10 @@ pub static HTTP_ROUTES: LazyLock<HttpRoutes> = LazyLock::new(|| {
-         endpoint!("/vm.add-fs"),
-         Box::new(VmActionHandler::new(&VmAddFs)),
+-    AddDisk, ApiError, ApiRequest, VmAddDevice, VmAddFs, VmAddGenericVhostUser, VmAddNet,
++    AddDisk, ApiError, ApiRequest, VmAddDevice, VmAddFs, VmAddGenericVhostUser, VmAddGpu, VmAddNet,
+     VmAddPmem, VmAddUserDevice, VmAddVdpa, VmAddVsock, VmBoot, VmCounters, VmDelete, VmNmi,
+     VmPause, VmPowerButton, VmReboot, VmReceiveMigration, VmRemoveDevice, VmResize, VmResizeDisk,
+     VmResizeZone, VmRestore, VmResume, VmSendMigration, VmShutdown, VmSnapshot,
+@@ -202,6 +202,10 @@ pub static HTTP_ROUTES: LazyLock<HttpRoutes> = LazyLock::new(|| {
+         endpoint!("/vm.add-generic-vhost-user"),
+         Box::new(VmActionHandler::new(&VmAddGenericVhostUser)),
      );
 +    r.routes.insert(
 +        endpoint!("/vm.add-gpu"),
@@ -860,41 +858,39 @@ index 2aa52e8e3..7eccb57d1 100644
          endpoint!("/vm.add-net"),
          Box::new(VmActionHandler::new(&VmAddNet)),
 diff --git a/vmm/src/api/mod.rs b/vmm/src/api/mod.rs
-index 12ca6b987..aaafe3843 100644
+index e4ee723..8f8052e 100644
 --- a/vmm/src/api/mod.rs
 +++ b/vmm/src/api/mod.rs
-@@ -51,8 +51,8 @@ use crate::config::RestoreConfig;
- use crate::device_tree::DeviceTree;
+@@ -56,7 +56,7 @@ use crate::device_tree::DeviceTree;
+ use crate::migration_transport::MAX_MIGRATION_CONNECTIONS;
  use crate::vm::{Error as VmError, VmState};
  use crate::vm_config::{
--    DeviceConfig, DiskConfig, FsConfig, NetConfig, PmemConfig, UserDeviceConfig, VdpaConfig,
--    VmConfig, VsockConfig,
-+    DeviceConfig, DiskConfig, FsConfig, GpuConfig, NetConfig, PmemConfig, UserDeviceConfig,
-+    VdpaConfig, VmConfig, VsockConfig,
+-    DeviceConfig, DiskConfig, FsConfig, GenericVhostUserConfig, NetConfig, PmemConfig,
++    DeviceConfig, DiskConfig, FsConfig, GenericVhostUserConfig, GpuConfig, NetConfig, PmemConfig,
+     UserDeviceConfig, VdpaConfig, VmConfig, VsockConfig,
  };
  
- /// API errors are sent back from the VMM API server through the ApiResponse.
-@@ -170,6 +170,10 @@ pub enum ApiError {
-     #[error("The fs could not be added to the VM")]
-     VmAddFs(#[source] VmError),
+@@ -179,6 +179,10 @@ pub enum ApiError {
+     #[error("The generic vhost-user device could not be added to the VM")]
+     VmAddGenericVhostUser(#[source] VmError),
  
-+    /// The gpu could not be added to the VM.
-+    #[error("The GPU could not be added to the VM: {0}")]
++    /// The gpu device could not be added to the VM.
++    #[error("The gpu device could not be added to the VM")]
 +    VmAddGpu(#[source] VmError),
 +
      /// The pmem device could not be added to the VM.
      #[error("The pmem device could not be added to the VM")]
      VmAddPmem(#[source] VmError),
-@@ -340,6 +344,8 @@ pub trait RequestHandler {
- 
-     fn vm_add_fs(&mut self, fs_cfg: FsConfig) -> Result<Option<Vec<u8>>, VmError>;
+@@ -561,6 +565,8 @@ pub trait RequestHandler {
+         fs_cfg: GenericVhostUserConfig,
+     ) -> Result<Option<Vec<u8>>, VmError>;
  
 +    fn vm_add_gpu(&mut self, gpu_cfg: GpuConfig) -> Result<Option<Vec<u8>>, VmError>;
 +
      fn vm_add_pmem(&mut self, pmem_cfg: PmemConfig) -> Result<Option<Vec<u8>>, VmError>;
  
      fn vm_add_net(&mut self, net_cfg: NetConfig) -> Result<Option<Vec<u8>>, VmError>;
-@@ -539,6 +545,43 @@ impl ApiAction for VmAddFs {
+@@ -797,6 +803,43 @@ impl ApiAction for VmAddGenericVhostUser {
      }
  }
  
@@ -939,10 +935,10 @@ index 12ca6b987..aaafe3843 100644
  
  impl ApiAction for VmAddPmem {
 diff --git a/vmm/src/api/openapi/cloud-hypervisor.yaml b/vmm/src/api/openapi/cloud-hypervisor.yaml
-index 1fa3d9b51..cc290e27f 100644
+index e8b72f7..5c01292 100644
 --- a/vmm/src/api/openapi/cloud-hypervisor.yaml
 +++ b/vmm/src/api/openapi/cloud-hypervisor.yaml
-@@ -277,6 +277,28 @@ paths:
+@@ -299,6 +299,28 @@ paths:
          500:
            description: The new device could not be added to the VM instance.
  
@@ -971,7 +967,7 @@ index 1fa3d9b51..cc290e27f 100644
    /vm.add-pmem:
      put:
        summary: Add a new pmem device to the VM
-@@ -603,6 +625,10 @@ components:
+@@ -629,6 +651,10 @@ components:
            type: array
            items:
              $ref: "#/components/schemas/FsConfig"
@@ -979,12 +975,12 @@ index 1fa3d9b51..cc290e27f 100644
 +          type: array
 +          items:
 +            $ref: "#/components/schemas/GpuConfig"
-         pmem:
+         generic-vhost-user:
            type: array
            items:
-@@ -1044,6 +1070,19 @@ components:
-         id:
-           type: string
+@@ -1154,6 +1180,22 @@ components:
+         virtio_id:
+           type: uint32
  
 +    GpuConfig:
 +      required:
@@ -993,50 +989,46 @@ index 1fa3d9b51..cc290e27f 100644
 +      properties:
 +        socket:
 +          type: string
++        id:
++          type: string
 +        pci_segment:
 +          type: integer
 +          format: int16
-+        id:
-+          type: string
++        pci_device_id:
++          type: integer
++          format: uint8
 +
      PmemConfig:
        required:
          - file
 diff --git a/vmm/src/config.rs b/vmm/src/config.rs
-index 78d6f9f1e..e1a54b0fa 100644
+index 00bf251..906410b 100644
 --- a/vmm/src/config.rs
 +++ b/vmm/src/config.rs
-@@ -45,6 +45,9 @@ pub enum Error {
-     /// Filesystem socket is missing
-     #[error("Error parsing --fs: socket missing")]
-     ParseFsSockMissing,
-+    /// GPU socket is missing
-+    #[error("Error parsing --gpu: socket missing")]
-+    ParseGpuSockMissing,
-     /// Missing persistent memory file parameter.
-     #[error("Error parsing --pmem: file missing")]
-     ParsePmemFileMissing,
-@@ -90,6 +93,9 @@ pub enum Error {
+@@ -122,6 +122,12 @@ pub enum Error {
      /// Error parsing filesystem parameters
      #[error("Error parsing --fs")]
      ParseFileSystem(#[source] OptionParserError),
 +    /// Error parsing GPU parameters
 +    #[error("Error parsing --gpu")]
 +    ParseGpu(#[source] OptionParserError),
++    /// GPU socket is missing
++    #[error("Error parsing --gpu: socket missing")]
++    ParseGpuSockMissing,
      /// Error parsing persistent memory parameters
      #[error("Error parsing --pmem")]
      ParsePersistentMemory(#[source] OptionParserError),
-@@ -390,6 +396,7 @@ pub struct VmParams<'a> {
-     pub rng: &'a str,
+@@ -460,6 +466,7 @@ pub struct VmParams<'a> {
      pub balloon: Option<&'a str>,
      pub fs: Option<Vec<&'a str>>,
+     pub generic_vhost_user: Option<Vec<&'a str>>,
 +    pub gpu: Option<Vec<&'a str>>,
      pub pmem: Option<Vec<&'a str>>,
      pub serial: &'a str,
      pub console: &'a str,
-@@ -451,6 +458,9 @@ impl<'a> VmParams<'a> {
-         let fs: Option<Vec<&str>> = args
-             .get_many::<String>("fs")
+@@ -524,6 +531,9 @@ impl<'a> VmParams<'a> {
+         let generic_vhost_user: Option<Vec<&str>> = args
+             .get_many::<String>("generic-vhost-user")
              .map(|x| x.map(|y| y as &str).collect());
 +        let gpu: Option<Vec<&str>> = args
 +            .get_many::<String>("gpu")
@@ -1044,65 +1036,45 @@ index 78d6f9f1e..e1a54b0fa 100644
          let pmem: Option<Vec<&str>> = args
              .get_many::<String>("pmem")
              .map(|x| x.map(|y| y as &str).collect());
-@@ -505,6 +515,7 @@ impl<'a> VmParams<'a> {
-             rng,
+@@ -579,6 +589,7 @@ impl<'a> VmParams<'a> {
              balloon,
              fs,
+             generic_vhost_user,
 +            gpu,
              pmem,
              serial,
              console,
-@@ -1766,6 +1777,49 @@ impl FwCfgItem {
+@@ -2100,6 +2111,29 @@ impl FwCfgItem {
      }
  }
  
 +impl GpuConfig {
 +    pub const SYNTAX: &'static str = "virtio-gpu parameters \
-+    \"socket=<socket_path>,id=<device_id>,pci_segment=<segment_id>\"";
++    \"socket=<socket_path>,id=<device_id>,pci_segment=<segment_id>,pci_device_id=<pci_slot>\"";
 +
 +    pub fn parse(gpu: &str) -> Result<Self> {
 +        let mut parser = OptionParser::new();
-+        parser.add("socket").add("id").add("pci_segment");
++        parser.add("socket").add_all(PciDeviceCommonConfig::OPTIONS);
 +        parser.parse(gpu).map_err(Error::ParseGpu)?;
 +
++        let pci_common = PciDeviceCommonConfig::parse(gpu)?;
 +        let socket = PathBuf::from(parser.get("socket").ok_or(Error::ParseGpuSockMissing)?);
-+        let id = parser.get("id");
-+
-+        let pci_segment = parser
-+            .convert("pci_segment")
-+            .map_err(Error::ParseGpu)?
-+            .unwrap_or_default();
 +
-+        Ok(GpuConfig {
-+            socket,
-+            id,
-+            pci_segment,
-+        })
++        Ok(GpuConfig { pci_common, socket })
 +    }
 +
 +    pub fn validate(&self, vm_config: &VmConfig) -> ValidationResult<()> {
-+        if let Some(platform_config) = vm_config.platform.as_ref() {
-+            if self.pci_segment >= platform_config.num_pci_segments {
-+                return Err(ValidationError::InvalidPciSegment(self.pci_segment));
-+            }
-+
-+            if let Some(iommu_segments) = platform_config.iommu_segments.as_ref()
-+                && iommu_segments.contains(&self.pci_segment)
-+            {
-+                return Err(ValidationError::IommuNotSupportedOnSegment(
-+                    self.pci_segment,
-+                ));
-+            }
++        if self.pci_common.iommu {
++            return Err(ValidationError::IommuUnsupported);
 +        }
-+
-+        Ok(())
++        self.pci_common.validate(vm_config)
 +    }
 +}
 +
  impl PmemConfig {
      pub const SYNTAX: &'static str = "Persistent memory parameters \
      \"file=<backing_file_path>,size=<persistent_memory_size>,iommu=on|off,\
-@@ -2624,6 +2678,17 @@ impl VmConfig {
+@@ -3041,6 +3075,17 @@ impl VmConfig {
              }
          }
  
@@ -1113,15 +1085,15 @@ index 78d6f9f1e..e1a54b0fa 100644
 +            for gpu in gpus {
 +                gpu.validate(self)?;
 +
-+                Self::validate_identifier(&mut id_list, &gpu.id)?;
++                Self::validate_identifier(&mut id_list, &gpu.pci_common.id)?;
 +            }
 +        }
 +
          if let Some(pmems) = &self.pmem {
              for pmem in pmems {
                  pmem.validate(self)?;
-@@ -2876,6 +2941,15 @@ impl VmConfig {
-             fs = Some(fs_config_list);
+@@ -3318,6 +3363,15 @@ impl VmConfig {
+             generic_vhost_user = Some(generic_vhost_user_config_list);
          }
  
 +        let mut gpu: Option<Vec<GpuConfig>> = None;
@@ -1136,77 +1108,53 @@ index 78d6f9f1e..e1a54b0fa 100644
          let mut pmem: Option<Vec<PmemConfig>> = None;
          if let Some(pmem_list) = &vm_params.pmem {
              let mut pmem_config_list = Vec::new();
-@@ -3012,6 +3086,7 @@ impl VmConfig {
-             rng,
+@@ -3455,6 +3509,7 @@ impl VmConfig {
              balloon,
+             generic_vhost_user,
              fs,
 +            gpu,
              pmem,
              serial,
              console,
-@@ -3073,6 +3148,13 @@ impl VmConfig {
-             removed |= fs.len() != len;
+@@ -3524,6 +3579,13 @@ impl VmConfig {
+             removed |= generic_vhost_user.len() != len;
          }
  
 +        // Remove if gpu device
 +        if let Some(gpu) = self.gpu.as_mut() {
 +            let len = gpu.len();
-+            gpu.retain(|dev| dev.id.as_ref().map(|id| id.as_ref()) != Some(id));
++            gpu.retain(|dev| dev.pci_common.id.as_ref().map(|id| id.as_ref()) != Some(id));
 +            removed |= gpu.len() != len;
 +        }
 +
          // Remove if net device
          if let Some(net) = self.net.as_mut() {
              let len = net.len();
-@@ -3145,6 +3227,7 @@ impl Clone for VmConfig {
-             #[cfg(feature = "pvmemcontrol")]
+@@ -3597,6 +3659,7 @@ impl Clone for VmConfig {
              pvmemcontrol: self.pvmemcontrol.clone(),
              fs: self.fs.clone(),
+             generic_vhost_user: self.generic_vhost_user.clone(),
 +            gpu: self.gpu.clone(),
              pmem: self.pmem.clone(),
              serial: self.serial.clone(),
              console: self.console.clone(),
-@@ -3665,6 +3748,23 @@ mod unit_tests {
-         Ok(())
-     }
- 
-+    fn gpu_fixture() -> GpuConfig {
-+        GpuConfig {
-+            socket: PathBuf::from("/tmp/sock"),
-+            id: None,
-+            pci_segment: 0,
-+        }
-+    }
-+
-+    #[test]
-+    fn test_parse_gpu() -> Result<()> {
-+        // "socket" must be supplied
-+        assert!(GpuConfig::parse("").is_err());
-+        assert_eq!(GpuConfig::parse("socket=/tmp/sock")?, gpu_fixture());
-+
-+        Ok(())
-+    }
-+
-     fn pmem_fixture() -> PmemConfig {
-         PmemConfig {
-             file: PathBuf::from("/tmp/pmem"),
-@@ -3936,6 +4036,7 @@ mod unit_tests {
-             rng: RngConfig::default(),
+@@ -4811,6 +4874,7 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}"
+             generic_vhost_user: None,
              balloon: None,
              fs: None,
 +            gpu: None,
              pmem: None,
-             serial: default_serial(),
-             console: default_console(),
-@@ -4138,6 +4239,7 @@ mod unit_tests {
-             },
+             serial: SerialConfig::default(),
+             console: ConsoleConfig::default(),
+@@ -5045,6 +5109,7 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}"
              balloon: None,
              fs: None,
+             generic_vhost_user: None,
 +            gpu: None,
              pmem: None,
-             serial: ConsoleConfig {
-                 file: None,
-@@ -4334,6 +4436,13 @@ mod unit_tests {
+             serial: SerialConfig {
+                 common: CommonConsoleConfig {
+@@ -5354,6 +5419,13 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}"
              Err(ValidationError::VhostUserRequiresSharedMemory)
          );
  
@@ -1221,7 +1169,7 @@ index 78d6f9f1e..e1a54b0fa 100644
          still_valid_config.memory.shared = true;
          still_valid_config.validate().unwrap();
 diff --git a/vmm/src/device_manager.rs b/vmm/src/device_manager.rs
-index 6d465047b..7eb1358e1 100644
+index e6902a4..4329af3 100644
 --- a/vmm/src/device_manager.rs
 +++ b/vmm/src/device_manager.rs
 @@ -12,6 +12,7 @@
@@ -1232,40 +1180,41 @@ index 6d465047b..7eb1358e1 100644
  use std::num::Wrapping;
  use std::os::unix::fs::OpenOptionsExt;
  use std::os::unix::io::{AsRawFd, FromRawFd};
-@@ -91,7 +92,7 @@ use virtio_devices::transport::{VirtioPciDevice, VirtioPciDeviceActivator, Virti
+@@ -89,7 +90,7 @@ use virtio_devices::transport::{VirtioPciDevice, VirtioPciDeviceActivator, Virti
  use virtio_devices::vhost_user::VhostUserConfig;
  use virtio_devices::{
      AccessPlatformMapping, ActivateError, Block, Endpoint, IommuMapping, VdpaDmaMapping,
 -    VirtioMemMappingSource,
 +    VirtioMemMappingSource, VirtioSharedMemory, VirtioSharedMemoryList,
  };
- use vm_allocator::{AddressAllocator, SystemAllocator};
+ use vm_allocator::{AddressAllocator, InterruptAllocError, SystemAllocator};
  use vm_device::dma_mapping::ExternalDmaMapping;
-@@ -124,8 +125,8 @@ use crate::serial_manager::{Error as SerialManagerError, SerialManager};
+@@ -122,8 +123,9 @@ use crate::serial_manager::{Error as SerialManagerError, SerialManager};
  use crate::vm_config::IvshmemConfig;
  use crate::vm_config::{
      ConsoleOutputMode, DEFAULT_IOMMU_ADDRESS_WIDTH_BITS, DEFAULT_PCI_SEGMENT_APERTURE_WEIGHT,
--    DeviceConfig, DiskConfig, FsConfig, NetConfig, PmemConfig, UserDeviceConfig, VdpaConfig,
--    VhostMode, VmConfig, VsockConfig,
-+    DeviceConfig, DiskConfig, FsConfig, GpuConfig, NetConfig, PmemConfig, UserDeviceConfig,
-+    VdpaConfig, VhostMode, VmConfig, VsockConfig,
+-    DeviceConfig, DiskConfig, FsConfig, GenericVhostUserConfig, NetConfig, PciDeviceCommonConfig,
+-    PmemConfig, UserDeviceConfig, VdpaConfig, VhostMode, VmConfig, VsockConfig,
++    DeviceConfig, DiskConfig, FsConfig, GenericVhostUserConfig, GpuConfig, NetConfig,
++    PciDeviceCommonConfig, PmemConfig, UserDeviceConfig, VdpaConfig, VhostMode, VmConfig,
++    VsockConfig,
  };
  use crate::{DEVICE_MANAGER_SNAPSHOT_ID, GuestRegionMmap, PciDeviceInfo, device_node};
  
-@@ -154,6 +155,7 @@ const IVSHMEM_DEVICE_NAME: &str = "__ivshmem";
- // identifiers if the user doesn't give one
- const DISK_DEVICE_NAME_PREFIX: &str = "_disk";
+@@ -154,6 +156,7 @@ const DISK_DEVICE_NAME_PREFIX: &str = "_disk";
  const FS_DEVICE_NAME_PREFIX: &str = "_fs";
-+const GPU_DEVICE_NAME_PREFIX: &str = "_gpu";
  const NET_DEVICE_NAME_PREFIX: &str = "_net";
+ const GENERIC_VHOST_USER_DEVICE_NAME_PREFIX: &str = "_generic_vhost_user";
++const GPU_DEVICE_NAME_PREFIX: &str = "_gpu";
  const PMEM_DEVICE_NAME_PREFIX: &str = "_pmem";
  const VDPA_DEVICE_NAME_PREFIX: &str = "_vdpa";
-@@ -198,10 +200,18 @@ pub enum DeviceManagerError {
+ const VSOCK_DEVICE_NAME_PREFIX: &str = "_vsock";
+@@ -201,10 +204,18 @@ pub enum DeviceManagerError {
      #[error("Cannot create virtio-fs device")]
      CreateVirtioFs(#[source] virtio_devices::vhost_user::Error),
  
 +    /// Cannot create virtio-gpu device
-+    #[error("Cannot create virtio-gpu device: {0}")]
++    #[error("Cannot create virtio-gpu device")]
 +    CreateVirtioGpu(#[source] virtio_devices::vhost_user::Error),
 +
      /// Virtio-fs device was created without a socket.
@@ -1276,10 +1225,10 @@ index 6d465047b..7eb1358e1 100644
 +    #[error("Virtio-gpu device was created without a socket")]
 +    NoVirtioGpuSock,
 +
-     /// Cannot create vhost-user-blk device
-     #[error("Cannot create vhost-user-blk device")]
-     CreateVhostUserBlk(#[source] virtio_devices::vhost_user::Error),
-@@ -319,6 +329,10 @@ pub enum DeviceManagerError {
+     /// Generic vhost-user device was created without a socket.
+     #[error("Generic vhost-user device was created without a socket")]
+     NoGenericVhostUserSock,
+@@ -318,6 +329,10 @@ pub enum DeviceManagerError {
      #[error("Cannot find a memory range for virtio-fs")]
      FsRangeAllocation,
  
@@ -1290,7 +1239,7 @@ index 6d465047b..7eb1358e1 100644
      /// Error creating serial output file
      #[error("Error creating serial output file")]
      SerialOutputFileOpen(#[source] io::Error),
-@@ -2537,6 +2551,9 @@ impl DeviceManager {
+@@ -2630,6 +2645,9 @@ impl DeviceManager {
          // Add virtio-fs if required
          self.make_virtio_fs_devices()?;
  
@@ -1300,7 +1249,7 @@ index 6d465047b..7eb1358e1 100644
          // Add virtio-pmem if required
          self.make_virtio_pmem_devices()?;
  
-@@ -3117,6 +3134,119 @@ impl DeviceManager {
+@@ -3234,6 +3252,129 @@ impl DeviceManager {
          Ok(())
      }
  
@@ -1308,12 +1257,13 @@ index 6d465047b..7eb1358e1 100644
 +        &mut self,
 +        gpu_cfg: &mut GpuConfig,
 +    ) -> DeviceManagerResult<MetaVirtioDevice> {
-+        let id = if let Some(id) = &gpu_cfg.id {
-+            id.clone()
-+        } else {
-+            let id = self.next_device_name(GPU_DEVICE_NAME_PREFIX)?;
-+            gpu_cfg.id = Some(id.clone());
-+            id
++        let id = match gpu_cfg.pci_common.id.as_ref() {
++            Some(id) => id.clone(),
++            None => gpu_cfg
++                .pci_common
++                .id
++                .insert(self.next_device_name(GPU_DEVICE_NAME_PREFIX)?)
++                .clone(),
 +        };
 +
 +        info!("Creating virtio-gpu device: {gpu_cfg:?}");
@@ -1321,35 +1271,46 @@ index 6d465047b..7eb1358e1 100644
 +        let mut node = device_node!(id);
 +
 +        if let Some(gpu_socket) = gpu_cfg.socket.to_str() {
-+            let (mut virtio_gpu_device, region) = virtio_devices::vhost_user::Gpu::new(
++            let (mut virtio_gpu_device, shmem_config) = virtio_devices::vhost_user::Gpu::new(
 +                id.clone(),
 +                gpu_socket,
 +                self.seccomp_action.clone(),
 +                self.exit_evt
 +                    .try_clone()
 +                    .map_err(DeviceManagerError::EventFd)?,
-+                self.force_iommu,
++                self.force_access_platform | gpu_cfg.pci_common.iommu,
 +            )
 +            .map_err(DeviceManagerError::CreateVirtioGpu)?;
 +
++            let (shm_id, shm_len) = shmem_config
++                .memory_sizes
++                .iter()
++                .copied()
++                .enumerate()
++                .find(|(_, len)| *len != 0)
++                .ok_or(DeviceManagerError::CreateVirtioGpu(
++                    virtio_devices::vhost_user::Error::VhostUserInvalidSharedMemoryRegion,
++                ))?;
++            let shm_id = shm_id as u8;
++
 +            // In crosvm, the 8 GiB bar is 8 GiB-aligned.
-+            let cache_base = self.pci_segments[gpu_cfg.pci_segment as usize]
++            let cache_base = self.pci_segments[gpu_cfg.pci_common.pci_segment as usize]
 +                .mem64_allocator
 +                .lock()
 +                .unwrap()
-+                .allocate(None, region.length as GuestUsize, Some(region.length))
++                .allocate(None, shm_len as GuestUsize, Some(shm_len))
 +                .ok_or(DeviceManagerError::GpuRangeAllocation)?
 +                .raw_value();
 +
 +            // Update the node with correct resource information.
 +            node.resources.push(Resource::MmioAddressRange {
 +                base: cache_base,
-+                size: region.length,
++                size: shm_len,
 +            });
 +
 +            let mmap_region = MmapRegion::build(
 +                None,
-+                region.length as usize,
++                shm_len as usize,
 +                libc::PROT_NONE,
 +                libc::MAP_ANONYMOUS | libc::MAP_PRIVATE,
 +            )
@@ -1374,10 +1335,10 @@ index 6d465047b..7eb1358e1 100644
 +            };
 +
 +            let region_list = once((
-+                region.id,
++                shm_id,
 +                VirtioSharedMemory {
 +                    offset: 0,
-+                    len: region.length,
++                    len: shm_len,
 +                },
 +            ))
 +            .collect();
@@ -1394,9 +1355,7 @@ index 6d465047b..7eb1358e1 100644
 +            Ok(MetaVirtioDevice {
 +                virtio_device: Arc::new(Mutex::new(virtio_gpu_device))
 +                    as Arc<Mutex<dyn virtio_devices::VirtioDevice>>,
-+                iommu: false,
-+                id,
-+                pci_segment: gpu_cfg.pci_segment,
++                pci_common: gpu_cfg.pci_common.clone(),
 +                dma_handler: None,
 +            })
 +        } else {
@@ -1420,7 +1379,7 @@ index 6d465047b..7eb1358e1 100644
      fn make_virtio_pmem_device(
          &mut self,
          pmem_cfg: &mut PmemConfig,
-@@ -4541,6 +4671,7 @@ impl DeviceManager {
+@@ -4765,6 +4898,7 @@ impl DeviceManager {
                  VirtioDeviceType::Block
                  | VirtioDeviceType::Pmem
                  | VirtioDeviceType::Fs
@@ -1428,36 +1387,34 @@ index 6d465047b..7eb1358e1 100644
                  | VirtioDeviceType::Vsock => {}
                  _ => return Err(DeviceManagerError::RemovalNotAllowed(device_type)),
              }
-@@ -4827,6 +4958,13 @@ impl DeviceManager {
+@@ -5086,6 +5220,13 @@ impl DeviceManager {
          self.hotplug_virtio_pci_device(device)
      }
  
 +    pub fn add_gpu(&mut self, gpu_cfg: &mut GpuConfig) -> DeviceManagerResult<PciDeviceInfo> {
-+        self.validate_identifier(&gpu_cfg.id)?;
++        self.validate_identifier(&gpu_cfg.pci_common.id)?;
 +
 +        let device = self.make_virtio_gpu_device(gpu_cfg)?;
 +        self.hotplug_virtio_pci_device(device)
 +    }
 +
      pub fn add_pmem(&mut self, pmem_cfg: &mut PmemConfig) -> DeviceManagerResult<PciDeviceInfo> {
-         self.validate_identifier(&pmem_cfg.id)?;
+         self.validate_identifier(&pmem_cfg.pci_common.id)?;
  
 diff --git a/vmm/src/lib.rs b/vmm/src/lib.rs
-index 6917e005e..5a3db353a 100644
+index 6c9d476..d0e1c33 100644
 --- a/vmm/src/lib.rs
 +++ b/vmm/src/lib.rs
-@@ -59,8 +59,8 @@ use crate::migration::{recv_vm_config, recv_vm_state};
+@@ -65,7 +65,7 @@ use crate::migration_transport::{
  use crate::seccomp_filters::{Thread, get_seccomp_filter};
  use crate::vm::{Error as VmError, Vm, VmState};
  use crate::vm_config::{
--    DeviceConfig, DiskConfig, FsConfig, NetConfig, PmemConfig, UserDeviceConfig, VdpaConfig,
--    VmConfig, VsockConfig,
-+    DeviceConfig, DiskConfig, FsConfig, GpuConfig, NetConfig, PmemConfig, UserDeviceConfig,
-+    VdpaConfig, VmConfig, VsockConfig,
+-    DeviceConfig, DiskConfig, FsConfig, GenericVhostUserConfig, NetConfig, PmemConfig,
++    DeviceConfig, DiskConfig, FsConfig, GenericVhostUserConfig, GpuConfig, NetConfig, PmemConfig,
+     UserDeviceConfig, VdpaConfig, VmConfig, VsockConfig,
  };
  
- mod acpi;
-@@ -2120,6 +2120,31 @@ impl RequestHandler for Vmm {
+@@ -2365,6 +2365,31 @@ impl RequestHandler for Vmm {
          }
      }
  
@@ -1489,15 +1446,15 @@ index 6917e005e..5a3db353a 100644
      fn vm_add_pmem(&mut self, pmem_cfg: PmemConfig) -> result::Result<Option<Vec<u8>>, VmError> {
          self.vm_config.as_ref().ok_or(VmError::VmNotCreated)?;
  
-@@ -2438,6 +2463,7 @@ mod unit_tests {
-             },
+@@ -2722,6 +2747,7 @@ mod unit_tests {
              balloon: None,
              fs: None,
+             generic_vhost_user: None,
 +            gpu: None,
              pmem: None,
-             serial: ConsoleConfig {
-                 file: None,
-@@ -2674,6 +2700,55 @@ mod unit_tests {
+             serial: SerialConfig {
+                 common: CommonConsoleConfig {
+@@ -3014,6 +3040,55 @@ mod unit_tests {
          );
      }
  
@@ -1554,21 +1511,19 @@ index 6917e005e..5a3db353a 100644
      fn test_vmm_vm_cold_add_pmem() {
          let mut vmm = create_dummy_vmm();
 diff --git a/vmm/src/vm.rs b/vmm/src/vm.rs
-index 536481885..d2e5de0fe 100644
+index 1c3baf8..ae5a2e8 100644
 --- a/vmm/src/vm.rs
 +++ b/vmm/src/vm.rs
-@@ -100,8 +100,8 @@ use crate::migration::{SNAPSHOT_CONFIG_FILE, SNAPSHOT_STATE_FILE, url_to_path};
+@@ -115,7 +115,7 @@ use crate::sev::MeasuredBootInfo;
  #[cfg(feature = "fw_cfg")]
  use crate::vm_config::FwCfgConfig;
  use crate::vm_config::{
--    DeviceConfig, DiskConfig, FsConfig, HotplugMethod, NetConfig, NumaConfig, PayloadConfig,
--    PmemConfig, UserDeviceConfig, VdpaConfig, VmConfig, VsockConfig,
-+    DeviceConfig, DiskConfig, FsConfig, GpuConfig, HotplugMethod, NetConfig, NumaConfig,
-+    PayloadConfig, PmemConfig, UserDeviceConfig, VdpaConfig, VmConfig, VsockConfig,
+-    DeviceConfig, DiskConfig, FsConfig, GenericVhostUserConfig, HotplugMethod, NetConfig,
++    DeviceConfig, DiskConfig, FsConfig, GenericVhostUserConfig, GpuConfig, HotplugMethod, NetConfig,
+     NumaConfig, PayloadConfig, PmemConfig, UserDeviceConfig, VdpaConfig, VmConfig, VsockConfig,
  };
  use crate::{
-     CPU_MANAGER_SNAPSHOT_ID, DEVICE_MANAGER_SNAPSHOT_ID, GuestMemoryMmap,
-@@ -1869,6 +1869,30 @@ impl Vm {
+@@ -2348,6 +2348,30 @@ impl Vm {
          Ok(pci_device_info)
      }
  
@@ -1600,33 +1555,30 @@ index 536481885..d2e5de0fe 100644
          let pci_device_info = self
              .device_manager
 diff --git a/vmm/src/vm_config.rs b/vmm/src/vm_config.rs
-index 9c28e536d..f21974ac2 100644
+index 6fefc8f..3834d1e 100644
 --- a/vmm/src/vm_config.rs
 +++ b/vmm/src/vm_config.rs
-@@ -461,6 +461,15 @@ impl ApplyLandlock for FsConfig {
-     }
+@@ -485,6 +485,13 @@ pub struct FsConfig {
+     pub queue_size: u16,
  }
  
 +#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
 +pub struct GpuConfig {
++    #[serde(flatten)]
++    pub pci_common: PciDeviceCommonConfig,
 +    pub socket: PathBuf,
-+    #[serde(default)]
-+    pub id: Option<String>,
-+    #[serde(default)]
-+    pub pci_segment: u16,
 +}
 +
- #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
- pub struct PmemConfig {
-     pub file: PathBuf,
-@@ -913,6 +922,7 @@ pub struct VmConfig {
-     pub rng: RngConfig,
+ pub fn default_fsconfig_num_queues() -> usize {
+     1
+ }
+@@ -1028,6 +1035,7 @@ pub struct VmConfig {
      pub balloon: Option<BalloonConfig>,
+     pub generic_vhost_user: Option<Vec<GenericVhostUserConfig>>,
      pub fs: Option<Vec<FsConfig>>,
 +    pub gpu: Option<Vec<GpuConfig>>,
      pub pmem: Option<Vec<PmemConfig>>,
-     #[serde(default = "default_serial")]
-     pub serial: ConsoleConfig,
+     #[serde(default)]
+     pub serial: SerialConfig,
 -- 
-2.53.0
-
+2.54.0
diff --git a/pkgs/cloud-hypervisor/default.nix b/pkgs/cloud-hypervisor/default.nix
index ee5a7ea..f43b080 100644
--- a/pkgs/cloud-hypervisor/default.nix
+++ b/pkgs/cloud-hypervisor/default.nix
@@ -5,21 +5,77 @@
 import ../../lib/overlay-package.nix [ "cloud-hypervisor" ] ({ final, super }:
 
 super.cloud-hypervisor.overrideAttrs (oldAttrs: rec {
-  cargoDeps = final.rustPlatform.fetchCargoVendor {
-    inherit patches;
-    inherit (oldAttrs) src;
-    hash = "sha256-wGtsyKDg1z1QK9mJ1Q43NSjoPbm3m81p++DoD8ipIUI=";
+  version = "52.0";
+
+  src = final.fetchFromGitHub {
+    owner = "cloud-hypervisor";
+    repo = "cloud-hypervisor";
+    rev = "v${version}";
+    hash = "sha256-OGyvmedSaWPsyH6mdHhgXN7MvTnK1HzdfTKUhJRlq8I=";
+  };
+
+  cargoDeps = final.stdenvNoCC.mkDerivation {
+    name = "cloud-hypervisor-${version}-vendor";
+    inherit src patches vhost vhostPatches;
+
+    nativeBuildInputs = [
+      final.cacert
+      final.cargo
+      final.git
+    ];
+
+    outputHashMode = "recursive";
+    outputHashAlgo = "sha256";
+    outputHash = "sha256-DD0Mobe/mnsGb7xHKUFfdk/5VXvp8mZbfuRymtNvZLg=";
+    dontFixup = true;
+
+    postUnpack = ''
+      unpackFile $vhost
+      chmod -R +w vhost
+    '';
+
+    postPatch = ''
+      pushd ../vhost
+      for patch in $vhostPatches; do
+          echo applying patch $patch
+          patch -p1 < $patch
+      done
+      popd
+    '';
+
+    buildPhase = ''
+      runHook preBuild
+
+      export CARGO_HOME=$TMPDIR/cargo-home
+      mkdir -p .cargo
+      cargo vendor vendor > .cargo/config.toml
+      substituteInPlace .cargo/config.toml \
+        --replace-fail 'directory = "vendor"' 'directory = "@vendor@/vendor"'
+
+      runHook postBuild
+    '';
+
+    installPhase = ''
+      runHook preInstall
+
+      mkdir -p $out
+      cp Cargo.lock $out/Cargo.lock
+      cp -R vendor $out/vendor
+      cp -R .cargo $out/.cargo
+
+      runHook postInstall
+    '';
   };
 
   vhost = final.fetchFromGitHub {
     name = "vhost";
     owner = "rust-vmm";
     repo = "vhost";
-    rev = "vhost-user-backend-v0.20.0";
-    hash = "sha256-KK1+mwYQr7YkyGT9+51v7TJael9D0lle2JXfRoTqYq8=";
+    rev = "vhost-user-backend-v0.22.0";
+    hash = "sha256-UzzwLi4O6rWuIJuGU0C0+tzJ7NZrgRamt/iYereRHZU=";
   };
 
-  patches = oldAttrs.patches or [] ++ [
+  patches = (oldAttrs.patches or []) ++ [
     ./0001-build-use-local-vhost.patch
     ./0002-virtio-devices-add-a-GPU-device.patch
   ];
@@ -27,16 +83,15 @@ super.cloud-hypervisor.overrideAttrs (oldAttrs: rec {
   vhostPatches = [
     vhost/0001-vhost_user-add-get_size-to-MsgHeader.patch
     vhost/0002-vhost-fix-receiving-reply-payloads.patch
-    vhost/0003-vhost_user-add-shared-memory-region-support.patch
-    vhost/0004-vhost_user-add-protocol-flag-for-shmem.patch
+    vhost/0003-vhost_user-add-crosvm-shmem-map-compat.patch
   ];
 
-  postUnpack = oldAttrs.postUnpack or "" + ''
+  postUnpack = (oldAttrs.postUnpack or "") + ''
     unpackFile $vhost
     chmod -R +w vhost
   '';
 
-  postPatch = oldAttrs.postPatch or "" + ''
+  postPatch = (oldAttrs.postPatch or "") + ''
     pushd ../vhost
     for patch in $vhostPatches; do
         echo applying patch $patch
diff --git a/pkgs/cloud-hypervisor/vhost/0003-vhost_user-add-crosvm-shmem-map-compat.patch b/pkgs/cloud-hypervisor/vhost/0003-vhost_user-add-crosvm-shmem-map-compat.patch
new file mode 100644
index 0000000..2a846bf
--- /dev/null
+++ b/pkgs/cloud-hypervisor/vhost/0003-vhost_user-add-crosvm-shmem-map-compat.patch
@@ -0,0 +1,79 @@
+From 4f0849043c9ef8d683f257f34e590a6842d7355c Mon Sep 17 00:00:00 2001
+From: Colby Townsend <colby@colbyt.com>
+Date: Fri, 26 Jun 2026 04:01:00 -0700
+Subject: [PATCH] vhost_user: add crosvm SHMEM_MAP compatibility
+SPDX-License-Identifier: Apache-2.0
+
+crosvm's vhost-user GPU backend advertises the shared-memory mapping
+protocol bit as SHMEM_MAP at 0x0010_0000.  rust-vmm/vhost 0.16 uses
+SHMEM at 0x0020_0000 for the same GET_SHMEM_CONFIG and SHMEM_MAP/
+SHMEM_UNMAP flow.
+
+Accept either bit when checking local state, and expose the crosvm bit
+name so frontends can negotiate with crosvm without sending an
+unsupported protocol feature.
+
+Signed-off-by: Colby Townsend <colby@colbyt.com>
+---
+ vhost-user-backend/src/handler.rs           | 4 +++-
+ vhost/src/vhost_user/backend_req_handler.rs | 4 +++-
+ vhost/src/vhost_user/frontend.rs            | 4 +++-
+ vhost/src/vhost_user/message.rs             | 2 ++
+ 4 files changed, 11 insertions(+), 3 deletions(-)
+
+diff --git a/vhost-user-backend/src/handler.rs b/vhost-user-backend/src/handler.rs
+index ea1fd6942..465dc2757 100644
+--- a/vhost-user-backend/src/handler.rs
++++ b/vhost-user-backend/src/handler.rs
+@@ -571,7 +571,9 @@ where
+         if self.acked_protocol_features & VhostUserProtocolFeatures::SHARED_OBJECT.bits() != 0 {
+             backend.set_shared_object_flag(true);
+         }
+-        if self.acked_protocol_features & VhostUserProtocolFeatures::SHMEM.bits() != 0 {
++        let shmem_features = VhostUserProtocolFeatures::SHMEM
++            | VhostUserProtocolFeatures::SHMEM_MAP;
++        if self.acked_protocol_features & shmem_features.bits() != 0 {
+             backend.set_shmem_flag(true);
+         }
+         self.backend.set_backend_req_fd(backend);
+diff --git a/vhost/src/vhost_user/backend_req_handler.rs b/vhost/src/vhost_user/backend_req_handler.rs
+index d74b04558..fbe750c15 100644
+--- a/vhost/src/vhost_user/backend_req_handler.rs
++++ b/vhost/src/vhost_user/backend_req_handler.rs
+@@ -686,7 +686,9 @@ impl<S: VhostUserBackendReqHandler> BackendReqHandler<S> {
+                 self.send_reply_message(&hdr, &msg)?;
+             }
+             Ok(FrontendReq::GET_SHMEM_CONFIG) => {
+-                self.check_proto_feature(VhostUserProtocolFeatures::SHMEM)?;
++                self.check_proto_feature(
++                    VhostUserProtocolFeatures::SHMEM | VhostUserProtocolFeatures::SHMEM_MAP,
++                )?;
+                 let msg = self.backend.get_shmem_config()?;
+                 self.send_reply_message(&hdr, &msg)?;
+             }
+diff --git a/vhost/src/vhost_user/frontend.rs b/vhost/src/vhost_user/frontend.rs
+index 195a6af1e..037f1b7f3 100644
+--- a/vhost/src/vhost_user/frontend.rs
++++ b/vhost/src/vhost_user/frontend.rs
+@@ -590,3 +590,5 @@ impl VhostUserFrontend for Frontend {
+         let mut node = self.node();
+-        node.check_proto_feature(VhostUserProtocolFeatures::SHMEM)?;
++        node.check_proto_feature(
++            VhostUserProtocolFeatures::SHMEM | VhostUserProtocolFeatures::SHMEM_MAP,
++        )?;
+ 
+diff --git a/vhost/src/vhost_user/message.rs b/vhost/src/vhost_user/message.rs
+index 5826d19a6..006f2e0fe 100644
+--- a/vhost/src/vhost_user/message.rs
++++ b/vhost/src/vhost_user/message.rs
+@@ -441,6 +441,8 @@ bitflags! {
+         const DEVICE_STATE = 0x0008_0000;
+         /// Support suspend in-flight I/O requests and record them
+         const GET_VRING_BASE_INFLIGHT = 0x0010_0000;
++        /// crosvm name for the shared-memory mapping protocol bit.
++        const SHMEM_MAP = 0x0010_0000;
+         /// Allow the backend to request file descriptors be mapped into virtio shared memory
+         /// regions.
+         const SHMEM = 0x0020_0000;
+--
+2.50.0
-- 
2.54.0


  parent reply	other threads:[~2026-06-26 18:55 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-26 18:55 [PATCH 0/8] refresh nixpkgs for Linux 7.1 colbyt
2026-06-26 18:55 ` [PATCH 1/8] pkgs: fix aarch64-musl builds with current nixpkgs colbyt
2026-07-02 12:18   ` Alyssa Ross
2026-06-26 18:55 ` [PATCH 2/8] lib: update nixpkgs colbyt
2026-06-26 18:55 ` [PATCH 3/8] pkgs/skaware: vendor backported patches colbyt
2026-07-02 11:53   ` Alyssa Ross
2026-06-26 18:55 ` [PATCH 4/8] pkgs/gtk3: skip integrated Wayland backport colbyt
2026-07-02 12:19   ` Alyssa Ross
2026-06-26 18:55 ` [PATCH 5/8] pkgs/skaware: skip integrated backports colbyt
2026-06-26 18:55 ` colbyt [this message]
2026-06-26 18:55 ` [PATCH 7/8] pkgs/libfyaml: fix pkg-config libs colbyt
2026-06-26 18:55 ` [PATCH 8/8] vm-lib: allow app VMs to name closure roots colbyt
2026-07-02 13:38   ` Alyssa Ross
2026-07-02 23:40     ` colby
2026-07-03 14:02       ` Alyssa Ross
2026-06-26 18:55 ` [PATCH optional] linux: use 6.18 for generic images colbyt
2026-07-02 13:42   ` Alyssa Ross
2026-07-02 23:20     ` colby
2026-07-02 12:03 ` [PATCH 0/8] refresh nixpkgs for Linux 7.1 Alyssa Ross

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260626185509.3715326-7-colby@colbyt.com \
    --to=colby@colbyt.com \
    --cc=devel@spectrum-os.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://spectrum-os.org/git/crosvm
	https://spectrum-os.org/git/doc
	https://spectrum-os.org/git/mktuntap
	https://spectrum-os.org/git/nixpkgs
	https://spectrum-os.org/git/spectrum
	https://spectrum-os.org/git/ucspi-vsock
	https://spectrum-os.org/git/www

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).