patches and low-level development discussion
 help / color / mirror / code / Atom feed
* [PATCH 0/6] cloud-hypervisor v52 and VM runtime fixes
@ 2026-06-25 17:48 colbyt
  2026-06-25 17:48 ` [PATCH 1/6] pkgs/skaware: vendor backported patches colbyt
                   ` (5 more replies)
  0 siblings, 6 replies; 16+ messages in thread
From: colbyt @ 2026-06-25 17:48 UTC (permalink / raw)
  To: devel; +Cc: colbyt

This series fixes the VM runtime issues from the bug list and updates
Spectrum's patched Cloud Hypervisor package to 52.0.

The first patch vendors two skaware backports that were already being
applied.  The old cgit patch URLs can return the wrong patch, so keeping
the small diffs in-tree makes those builds reproducible again.

The Cloud Hypervisor patch rebases Spectrum's vhost-user GPU support
onto 52.0 and updates the paired rust-vmm/vhost checkout to
vhost-user-backend-v0.22.0.  The old local vhost shared-memory patches
are dropped because v0.22.0 already has the support needed by the GPU
frontend.

The rest of the series fixes the crosvm and installer issues: crosvm
test VMs use the existing passt-backed vhost-user-net path, the GPU
documentation uses crosvm's current --socket-path option, the installer
stops forwarding boot status noise to the console during graphical
startup, and start-vmm gains a regression test for the generated GPU
socket wiring.

colbyt (6):
  pkgs/skaware: vendor backported patches
  pkgs/cloud-hypervisor: update GPU patchset to v52
  vm: use vhost-user networking for crosvm
  Documentation: use crosvm GPU socket-path option
  installer: suppress boot console status noise
  start-vmm: test GPU socket configuration

 .../software/cloud-hypervisor/index.html      |   2 +-
 img/app/Makefile                              |   7 +-
 .../0001-build-use-local-vhost.patch          |  38 +-
 ...0002-virtio-devices-add-a-GPU-device.patch | 674 ++++++++----------
 pkgs/cloud-hypervisor/default.nix             |  76 +-
 ...d-don-t-chmod-device-nodes-for-lines.patch |  10 +
 ...limit-add-p-option-for-rlimit-rtprio.patch |  25 +
 pkgs/skaware-packages/default.nix             |  12 +-
 release/installer/configuration.nix           |   9 +-
 release/installer/run-vm.nix                  |   5 +-
 tools/start-vmm/tests/vm_command-basic.rs     |   5 +
 vm/sys/net/Makefile                           |   5 +-
 12 files changed, 453 insertions(+), 415 deletions(-)
 create mode 100644 pkgs/skaware-packages/0001-mdevd-don-t-chmod-device-nodes-for-lines.patch
 create mode 100644 pkgs/skaware-packages/0001-s6-softlimit-add-p-option-for-rlimit-rtprio.patch

-- 
2.54.0

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH 1/6] pkgs/skaware: vendor backported patches
  2026-06-25 17:48 [PATCH 0/6] cloud-hypervisor v52 and VM runtime fixes colbyt
@ 2026-06-25 17:48 ` colbyt
  2026-06-26 13:39   ` Alyssa Ross
  2026-06-25 17:48 ` [PATCH 2/6] pkgs/cloud-hypervisor: update GPU patchset to v52 colbyt
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 16+ messages in thread
From: colbyt @ 2026-06-25 17:48 UTC (permalink / raw)
  To: devel; +Cc: colbyt

Two skaware backports were fetched from cgit patch endpoints.  Those
endpoints are not stable enough for package inputs: the same URL can
return an unrelated patch, breaking the build before the VM can start.

Keep the small upstream diffs in-tree instead.  The package still
applies the same s6 and mdevd fixes, and the comments next to each patch
record the upstream commit IDs.

Signed-off-by: colbyt <colby@colbyt.com>
---
 ...d-don-t-chmod-device-nodes-for-lines.patch | 10 ++++++++
 ...limit-add-p-option-for-rlimit-rtprio.patch | 25 +++++++++++++++++++
 pkgs/skaware-packages/default.nix             | 12 +++------
 3 files changed, 39 insertions(+), 8 deletions(-)
 create mode 100644 pkgs/skaware-packages/0001-mdevd-don-t-chmod-device-nodes-for-lines.patch
 create mode 100644 pkgs/skaware-packages/0001-s6-softlimit-add-p-option-for-rlimit-rtprio.patch

diff --git a/pkgs/skaware-packages/0001-mdevd-don-t-chmod-device-nodes-for-lines.patch b/pkgs/skaware-packages/0001-mdevd-don-t-chmod-device-nodes-for-lines.patch
new file mode 100644
index 0000000..919f412
--- /dev/null
+++ b/pkgs/skaware-packages/0001-mdevd-don-t-chmod-device-nodes-for-lines.patch
@@ -0,0 +1,10 @@
+SPDX-FileCopyrightText: 2025 Alyssa Ross <hi@alyssa.is>
+SPDX-License-Identifier: ISC
+
+diff --git a/src/mdevd/mdevd.c b/src/mdevd/mdevd.c
+index 3040ba6..aecd5a7 100644
+--- a/src/mdevd/mdevd.c
++++ b/src/mdevd/mdevd.c
+@@ -643 +643 @@ static inline int run_scriptelem (struct uevent_s const *event, scriptelem const
+-  if (nodelen && ud->action == ACTION_ADD && ud->mmaj >= 0)
++  if (elem->movetype != MOVEINFO_NOCREATE && nodelen && ud->action == ACTION_ADD && ud->mmaj >= 0)
diff --git a/pkgs/skaware-packages/0001-s6-softlimit-add-p-option-for-rlimit-rtprio.patch b/pkgs/skaware-packages/0001-s6-softlimit-add-p-option-for-rlimit-rtprio.patch
new file mode 100644
index 0000000..b1aa586
--- /dev/null
+++ b/pkgs/skaware-packages/0001-s6-softlimit-add-p-option-for-rlimit-rtprio.patch
@@ -0,0 +1,25 @@
+SPDX-FileCopyrightText: 2025 Alyssa Ross <hi@alyssa.is>
+SPDX-License-Identifier: ISC
+
+diff --git a/doc/s6-softlimit.html b/doc/s6-softlimit.html
+index 05701ce..49a5b40 100644
+--- a/doc/s6-softlimit.html
++++ b/doc/s6-softlimit.html
+@@ -28 +28 @@ s6-softlimit changes its process limits, then executes into another program.
+-     s6-softlimit [ -H | -h ] [ -a <em>allmem</em> ] [ -c <em>core</em> ] [ -d <em>data</em> ] [ -f <em>fsize</em> ] [ -l <em>lock</em> ] [ -m <em>mem</em> ] [ -o <em>ofiles</em> ] [ -p <em>proc</em> ] [ -r <em>res</em> ] [ -s <em>stack</em> ] [ -t <em>cpusecs</em> ] <em>prog...</em>
++     s6-softlimit [ -H | -h ] [ -a <em>allmem</em> ] [ -c <em>core</em> ] [ -d <em>data</em> ] [ -f <em>fsize</em> ] [ -l <em>lock</em> ] [ -m <em>mem</em> ] [ -o <em>ofiles</em> ] [ -P <em>prio</em> ] [ -p <em>proc</em> ] [ -r <em>res</em> ] [ -s <em>stack</em> ] [ -t <em>cpusecs</em> ] <em>prog...</em>
+@@ -60,0 +61 @@ and s6-softlimit will die. There is virtually no reason to ever use this. </li>
++ <li> <tt>-P&nbsp;<em>prio</em></tt>&nbsp;: limit the real-time priority to <em>prio</em>. </li>
+diff --git a/src/daemontools-extras/s6-softlimit.c b/src/daemontools-extras/s6-softlimit.c
+index d6112b2..beb7325 100644
+--- a/src/daemontools-extras/s6-softlimit.c
++++ b/src/daemontools-extras/s6-softlimit.c
+@@ -44 +44 @@ int main (int argc, char const *const *argv)
+-    int opt = subgetopt_r(argc, argv, "hHa:c:d:f:l:m:o:p:r:s:t:", &l) ;
++    int opt = subgetopt_r(argc, argv, "hHa:c:d:f:l:m:o:P:p:r:s:t:", &l) ;
+@@ -105,0 +106,5 @@ int main (int argc, char const *const *argv)
++#endif
++        break ;
++      case 'P' :
++#ifdef RLIMIT_RTPRIO
++        doit(RLIMIT_RTPRIO, l.arg) ;
diff --git a/pkgs/skaware-packages/default.nix b/pkgs/skaware-packages/default.nix
index e248201..1489317 100644
--- a/pkgs/skaware-packages/default.nix
+++ b/pkgs/skaware-packages/default.nix
@@ -6,19 +6,15 @@ import ../../lib/overlay-package.nix [ "skawarePackages" ] ({ final, super }:
 super.skawarePackages.overrideScope (_: prev: {
   s6 = prev.s6.overrideAttrs ({ patches ? [], ... }: {
     patches = patches ++ [
-      (final.fetchpatch {
-        url = "https://git.skarnet.org/cgi-bin/cgit.cgi/s6/patch/?id=c3a8ef7034fb2bc02f35381a8970ac026822a810";
-        hash = "sha256-lgCoPbEYru6/a2bpVpLsZ2Rq2OHhNVs0lDgFO/df1Aw=";
-      })
+      # Upstream c3a8ef70; vendored because cgit patch URLs are unstable.
+      ./0001-s6-softlimit-add-p-option-for-rlimit-rtprio.patch
     ];
   });
 
   mdevd = prev.mdevd.overrideAttrs ({ patches ? [], ... }: {
     patches = patches ++ [
-      (final.fetchpatch {
-        url = "https://git.skarnet.org/cgi-bin/cgit.cgi/mdevd/patch/?id=252f241e425bf09ddfb4a824e40403f40da0da1e";
-        hash = "sha256-0tEC+yJGyPapsxBqzBXPztF3bl7OwjVAGjhNXtwZQ0g=";
-      })
+      # Upstream 252f241e; vendored because cgit patch URLs are unstable.
+      ./0001-mdevd-don-t-chmod-device-nodes-for-lines.patch
     ];
   });
 }))
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 2/6] pkgs/cloud-hypervisor: update GPU patchset to v52
  2026-06-25 17:48 [PATCH 0/6] cloud-hypervisor v52 and VM runtime fixes colbyt
  2026-06-25 17:48 ` [PATCH 1/6] pkgs/skaware: vendor backported patches colbyt
@ 2026-06-25 17:48 ` colbyt
  2026-06-26 14:06   ` Alyssa Ross
  2026-06-25 17:48 ` [PATCH 3/6] vm: use vhost-user networking for crosvm colbyt
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 16+ messages in thread
From: colbyt @ 2026-06-25 17:48 UTC (permalink / raw)
  To: devel; +Cc: colbyt

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.  The local vhost
shared-memory patches are no longer applied because vhost-user-backend
0.22.0 already has the protocol support used by the GPU frontend.

The cargo vendor derivation now 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 | 674 ++++++++----------
 pkgs/cloud-hypervisor/default.nix             |  76 +-
 3 files changed, 392 insertions(+), 396 deletions(-)

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..3c6ec13 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,421 @@
 +// 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,21 @@ index 000000000..7eec07ba6
 +
 +        let avail_protocol_features = VhostUserProtocolFeatures::CONFIG
 +            | VhostUserProtocolFeatures::BACKEND_REQ
-+            | VhostUserProtocolFeatures::SHARED_MEMORY_REGIONS;
++            | VhostUserProtocolFeatures::SHMEM;
 +
 +        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()?;
++        if shm_config.nregions != 1 {
 +            return Err(Error::VhostUserUnexpectedSharedMemoryRegionsCount(
 +                1,
-+                shm_regions.len(),
++                shm_config.nregions as usize,
 +            ));
 +        }
-+        let shm_region = shm_regions[0];
++        if shm_config.memory_sizes[0] == 0 {
++            return Err(Error::VhostUserInvalidSharedMemoryRegion);
++        }
 +
 +        Ok((
 +            Gpu {
@@ -506,7 +512,7 @@ index 000000000..7eec07ba6
 +                exit_evt,
 +                iommu,
 +            },
-+            shm_region,
++            shm_config,
 +        ))
 +    }
 +
@@ -536,7 +542,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 +570,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 +614,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 +631,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 +641,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 +660,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 +721,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 +748,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 +786,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 +811,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 +856,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 +933,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 +965,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 +973,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 +987,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 +1034,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 +1083,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 +1106,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 +1167,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 +1178,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 +1223,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 +1237,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 +1247,7 @@ index 6d465047b..7eb1358e1 100644
          // Add virtio-pmem if required
          self.make_virtio_pmem_devices()?;
  
-@@ -3117,6 +3134,119 @@ impl DeviceManager {
+@@ -3234,6 +3252,121 @@ impl DeviceManager {
          Ok(())
      }
  
@@ -1308,12 +1255,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 +1269,38 @@ 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 = 0;
++            let shm_len = shmem_config.memory_sizes[shm_id as usize];
++
 +            // 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 +1325,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 +1345,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 +1369,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 +1377,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 +1436,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 +1501,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 +1545,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..e4ddb89 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,14 @@ 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
   ];
 
-  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
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 3/6] vm: use vhost-user networking for crosvm
  2026-06-25 17:48 [PATCH 0/6] cloud-hypervisor v52 and VM runtime fixes colbyt
  2026-06-25 17:48 ` [PATCH 1/6] pkgs/skaware: vendor backported patches colbyt
  2026-06-25 17:48 ` [PATCH 2/6] pkgs/cloud-hypervisor: update GPU patchset to v52 colbyt
@ 2026-06-25 17:48 ` colbyt
  2026-06-26 14:45   ` Alyssa Ross
  2026-07-02  9:07   ` Alyssa Ross
  2026-06-25 17:48 ` [PATCH 4/6] Documentation: use crosvm GPU socket-path option colbyt
                   ` (2 subsequent siblings)
  5 siblings, 2 replies; 16+ messages in thread
From: colbyt @ 2026-06-25 17:48 UTC (permalink / raw)
  To: devel; +Cc: colbyt

The crosvm VM test paths used raw tap networking for their primary
network device, while the Cloud Hypervisor paths already used Spectrum's
passt-backed vhost-user-net helper.

Start the existing helper for crosvm and pass it to crosvm with
--vhost-user net,socket=build/vhost-user-net.sock.  The net VM still
keeps tap1 for its downstream interface, and the start-vhost-user-net
targets are marked phony like the other service-start targets.

Signed-off-by: colbyt <colby@colbyt.com>
---
 img/app/Makefile    | 7 ++++---
 vm/sys/net/Makefile | 5 +++--
 2 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/img/app/Makefile b/img/app/Makefile
index fd75e6e..915db3d 100644
--- a/img/app/Makefile
+++ b/img/app/Makefile
@@ -84,6 +84,7 @@ start-vhost-user-gpu:
 start-vhost-user-net:
 	mkdir -p build
 	../../scripts/start-passt.elb
+.PHONY: start-vhost-user-net
 
 start-virtiofsd: scripts/start-virtiofsd.elb
 	mkdir -p build
@@ -127,11 +128,11 @@ run-cloud-hypervisor: $(imgdir)/appvm/blk/root.img start-vhost-user-gpu start-vh
 	    --serial file=build/serial.log
 .PHONY: run-cloud-hypervisor
 
-run-crosvm: $(imgdir)/appvm/blk/root.img start-vhost-user-gpu start-virtiofsd
-	../../scripts/with-taps.elb $(CROSVM_RUN) \
+run-crosvm: $(imgdir)/appvm/blk/root.img start-vhost-user-gpu start-vhost-user-net start-virtiofsd
+	$(CROSVM_RUN) \
 	    -b path=$(imgdir)/appvm/blk/root.img,ro=true \
 	    -p "console=ttyS0 root=PARTLABEL=root" \
-	    --net tap-name=tap0,mac=02:00:00:00:00:01 \
+	    --vhost-user net,socket=build/vhost-user-net.sock \
 	    --vhost-user fs,socket=build/virtiofsd.sock \
 	    --vhost-user gpu,socket=build/vhost-user-gpu.sock \
 	    --vsock cid=3 \
diff --git a/vm/sys/net/Makefile b/vm/sys/net/Makefile
index 653ef13..e37fe8c 100644
--- a/vm/sys/net/Makefile
+++ b/vm/sys/net/Makefile
@@ -63,6 +63,7 @@ debug:
 start-vhost-user-net:
 	mkdir -p build
 	../../../scripts/start-passt.elb
+.PHONY: start-vhost-user-net
 
 run-qemu: $(vmdir)/netvm/blk/root.img
 	@../../../scripts/run-qemu.sh -m 256 -cpu max -kernel $(KERNEL) -vga none \
@@ -93,11 +94,11 @@ run-cloud-hypervisor: $(vmdir)/netvm/blk/root.img start-vhost-user-net
 	    --serial file=build/serial.log
 .PHONY: run-cloud-hypervisor
 
-run-crosvm: $(vmdir)/netvm/blk/root.img
+run-crosvm: $(vmdir)/netvm/blk/root.img start-vhost-user-net
 	../../../scripts/with-taps.elb $(CROSVM_RUN) \
 	    -b path=$(vmdir)/netvm/blk/root.img,ro=true \
 	    -p "console=ttyS0 root=PARTLABEL=root" \
-	    --net tap-name=tap0 \
+	    --vhost-user net,socket=build/vhost-user-net.sock \
 	    --net tap-name=tap1,mac=02:01:00:00:00:01 \
 	    --serial type=file,hardware=serial,path=build/serial.log \
 	    --serial type=stdout,hardware=virtio-console,stdin=true \
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 4/6] Documentation: use crosvm GPU socket-path option
  2026-06-25 17:48 [PATCH 0/6] cloud-hypervisor v52 and VM runtime fixes colbyt
                   ` (2 preceding siblings ...)
  2026-06-25 17:48 ` [PATCH 3/6] vm: use vhost-user networking for crosvm colbyt
@ 2026-06-25 17:48 ` colbyt
  2026-06-26 14:18   ` Alyssa Ross
  2026-06-25 17:48 ` [PATCH 5/6] installer: suppress boot console status noise colbyt
  2026-06-25 17:48 ` [PATCH 6/6] start-vmm: test GPU socket configuration colbyt
  5 siblings, 1 reply; 16+ messages in thread
From: colbyt @ 2026-06-25 17:48 UTC (permalink / raw)
  To: devel; +Cc: colbyt

Current crosvm exposes the GPU device socket option as --socket-path.
The old --socket spelling is deprecated, so update the Cloud Hypervisor
GPU usage example to match the supported command line.

Signed-off-by: colbyt <colby@colbyt.com>
---
 Documentation/software/cloud-hypervisor/index.html | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Documentation/software/cloud-hypervisor/index.html b/Documentation/software/cloud-hypervisor/index.html
index 9b4315c..399b5e5 100644
--- a/Documentation/software/cloud-hypervisor/index.html
+++ b/Documentation/software/cloud-hypervisor/index.html
@@ -53,7 +53,7 @@ source tree under the same parent directory as Cloud Hypervisor’s.
 
 Start the crosvm GPU device:
 
-<pre><code>crosvm device gpu --socket gpu.sock</code></pre>
+<pre><code>crosvm device gpu --socket-path gpu.sock</code></pre>
 
 Connect to the GPU device with cloud-hypervisor:
 
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 5/6] installer: suppress boot console status noise
  2026-06-25 17:48 [PATCH 0/6] cloud-hypervisor v52 and VM runtime fixes colbyt
                   ` (3 preceding siblings ...)
  2026-06-25 17:48 ` [PATCH 4/6] Documentation: use crosvm GPU socket-path option colbyt
@ 2026-06-25 17:48 ` colbyt
  2026-06-26 14:46   ` Alyssa Ross
  2026-06-25 17:48 ` [PATCH 6/6] start-vmm: test GPU socket configuration colbyt
  5 siblings, 1 reply; 16+ messages in thread
From: colbyt @ 2026-06-25 17:48 UTC (permalink / raw)
  To: devel; +Cc: colbyt

The installer can show systemd or udev messages between Plymouth exiting
and cage starting, which breaks the intended flicker-free graphical
handoff.

Add quiet/systemd/udev kernel parameters to suppress status output and
stop forcing systemd.journald.forward_to_console in the QEMU runner.
This keeps the installer VM aligned with the quiet graphical boot path.

Signed-off-by: colbyt <colby@colbyt.com>
---
 release/installer/configuration.nix | 9 ++++++++-
 release/installer/run-vm.nix        | 5 +----
 2 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/release/installer/configuration.nix b/release/installer/configuration.nix
index 3f9ef24..daaf5b7 100644
--- a/release/installer/configuration.nix
+++ b/release/installer/configuration.nix
@@ -11,7 +11,14 @@ in
   imports = [ (modulesPath + "/profiles/all-hardware.nix") ];
 
   boot.consoleLogLevel = lib.mkDefault 2;
-  boot.kernelParams = [ "udev.log_priority=5" ];
+  boot.kernelParams = [
+    "quiet"
+    "loglevel=3"
+    "systemd.show_status=false"
+    "rd.systemd.show_status=false"
+    "udev.log_level=3"
+    "rd.udev.log_level=3"
+  ];
   boot.initrd.verbose = false;
 
   boot.kernelPackages = pkgs.linuxPackages_latest;
diff --git a/release/installer/run-vm.nix b/release/installer/run-vm.nix
index b9907f7..6639c8b 100644
--- a/release/installer/run-vm.nix
+++ b/release/installer/run-vm.nix
@@ -40,8 +40,5 @@ writeShellScript "run-spectrum-installer-vm.sh" ''
     -drive file=/proc/self/fd/3,format=raw,if=virtio \
     -kernel ${installer.kernel} \
     -initrd ${installer.initramfs} \
-    -append ${escapeShellArg (toString [
-      installer.kernelParams
-      "systemd.journald.forward_to_console"
-    ])}
+    -append ${escapeShellArg installer.kernelParams}
 '') (_: {})
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 6/6] start-vmm: test GPU socket configuration
  2026-06-25 17:48 [PATCH 0/6] cloud-hypervisor v52 and VM runtime fixes colbyt
                   ` (4 preceding siblings ...)
  2026-06-25 17:48 ` [PATCH 5/6] installer: suppress boot console status noise colbyt
@ 2026-06-25 17:48 ` colbyt
  2026-06-26 14:18   ` Alyssa Ross
  5 siblings, 1 reply; 16+ messages in thread
From: colbyt @ 2026-06-25 17:48 UTC (permalink / raw)
  To: devel; +Cc: colbyt

Extend the basic VM command test to assert that GPU configuration
includes the expected crosvm vhost-user GPU socket path.

This adds coverage for the generated GPU service wiring without
requiring a full VM boot.

Signed-off-by: colbyt <colby@colbyt.com>
---
 tools/start-vmm/tests/vm_command-basic.rs | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/tools/start-vmm/tests/vm_command-basic.rs b/tools/start-vmm/tests/vm_command-basic.rs
index 2e9ad0c..80937ef 100644
--- a/tools/start-vmm/tests/vm_command-basic.rs
+++ b/tools/start-vmm/tests/vm_command-basic.rs
@@ -32,6 +32,11 @@ fn main() -> std::io::Result<()> {
     let expected =
         "/run/service/vm-services/instance/testvm/data/service/vhost-user-fs/env/virtiofsd.sock";
     assert_eq!(fs1.socket, expected);
+    assert_eq!(config.gpu.len(), 1);
+    let gpu1 = &config.gpu[0];
+    let expected =
+        "/run/service/vm-services/instance/testvm/data/service/vhost-user-gpu/env/crosvm.sock";
+    assert_eq!(gpu1.socket, expected);
     assert_eq!(PathBuf::from(config.payload.kernel), kernel_path);
     #[cfg(target_arch = "x86_64")]
     assert_eq!(config.payload.cmdline, "console=ttyS0 root=PARTLABEL=root");
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [PATCH 1/6] pkgs/skaware: vendor backported patches
  2026-06-25 17:48 ` [PATCH 1/6] pkgs/skaware: vendor backported patches colbyt
@ 2026-06-26 13:39   ` Alyssa Ross
  0 siblings, 0 replies; 16+ messages in thread
From: Alyssa Ross @ 2026-06-26 13:39 UTC (permalink / raw)
  To: colbyt; +Cc: devel

[-- Attachment #1: Type: text/plain, Size: 1026 bytes --]

colbyt <colby@colbyt.com> writes:

> Two skaware backports were fetched from cgit patch endpoints.  Those
> endpoints are not stable enough for package inputs: the same URL can
> return an unrelated patch, breaking the build before the VM can start.
>
> Keep the small upstream diffs in-tree instead.  The package still
> applies the same s6 and mdevd fixes, and the comments next to each patch
> record the upstream commit IDs.
>
> Signed-off-by: colbyt <colby@colbyt.com>

Yes, it has been unreliable… I looked into it before and it seemed like
it was some sort of overzealous anti-scraper mitigation.  I reported it
but it doesn't seem to have been improved, so something should be done
here.  I prefer not vendoring patches unless absolutely necessary
because experience from Homebrew and Nixpkgs shows they can end up
permanently accumulating quite an impact on repo size over time, but
these repos have an official GitHub mirror, so I'll change to fetching
the patches from there instead.  Thanks!

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 227 bytes --]

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/6] pkgs/cloud-hypervisor: update GPU patchset to v52
  2026-06-25 17:48 ` [PATCH 2/6] pkgs/cloud-hypervisor: update GPU patchset to v52 colbyt
@ 2026-06-26 14:06   ` Alyssa Ross
  0 siblings, 0 replies; 16+ messages in thread
From: Alyssa Ross @ 2026-06-26 14:06 UTC (permalink / raw)
  To: colbyt; +Cc: devel

[-- Attachment #1: Type: text/plain, Size: 1901 bytes --]

colbyt <colby@colbyt.com> writes:

> 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.  The local vhost
> shared-memory patches are no longer applied because vhost-user-backend
> 0.22.0 already has the protocol support used by the GPU frontend.
>
> The cargo vendor derivation now 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>
> ---

For Cloud Hypervisor 52.0, my plan had been to drop the custom GPU
device, and just extend the new generic vhost-user device Demi
upstreamed to support SHMEM, reducing the divergence with upstream and
easing the path towards upstreaming the rest.  I have this version of
the patch locally, but had been waiting for the Nixpkgs update that will
bring in the new Cloud Hypervisor.  I expect that Nixpkgs update will
come in the next week or two, after the next Nixpkgs staging cycle
(which will bring some package fixes we need).  Keeping Nixpkgs up to date got
away from me this year so far, because I was focused on some big
organizational/long-term things for the first few months (that I hope
will visibly bear fruit shortly…), but I've been back on it in the last
few weeks getting Nixpkgs back into shape, so it should be back to
regular updates shortly.

If you'd like though, we could decouple our Cloud Hypervisor version
from Nixpkgs' like you've done here, and I could update Cloud Hypervisor
to 52.0 with my patch to extend the generic vhost-user device, rather
than waiting another week or two for the Nixpkgs update.  What do you
think?

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 227 bytes --]

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 4/6] Documentation: use crosvm GPU socket-path option
  2026-06-25 17:48 ` [PATCH 4/6] Documentation: use crosvm GPU socket-path option colbyt
@ 2026-06-26 14:18   ` Alyssa Ross
  0 siblings, 0 replies; 16+ messages in thread
From: Alyssa Ross @ 2026-06-26 14:18 UTC (permalink / raw)
  To: colbyt, devel; +Cc: colbyt

This patch has been committed as af2828d2bd647a6cc3d1065e284db3d753fdaf93,
which can be viewed online at
https://spectrum-os.org/git/spectrum/commit/?id=af2828d2bd647a6cc3d1065e284db3d753fdaf93.

This is an automated message.  Send comments/questions/requests to:
Alyssa Ross <hi@alyssa.is>

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 6/6] start-vmm: test GPU socket configuration
  2026-06-25 17:48 ` [PATCH 6/6] start-vmm: test GPU socket configuration colbyt
@ 2026-06-26 14:18   ` Alyssa Ross
  0 siblings, 0 replies; 16+ messages in thread
From: Alyssa Ross @ 2026-06-26 14:18 UTC (permalink / raw)
  To: colbyt, devel; +Cc: colbyt

This patch has been committed as 50542452384fc18a6e1728ba84de95aae3375248,
which can be viewed online at
https://spectrum-os.org/git/spectrum/commit/?id=50542452384fc18a6e1728ba84de95aae3375248.

This is an automated message.  Send comments/questions/requests to:
Alyssa Ross <hi@alyssa.is>

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 3/6] vm: use vhost-user networking for crosvm
  2026-06-25 17:48 ` [PATCH 3/6] vm: use vhost-user networking for crosvm colbyt
@ 2026-06-26 14:45   ` Alyssa Ross
  2026-07-02  9:07   ` Alyssa Ross
  1 sibling, 0 replies; 16+ messages in thread
From: Alyssa Ross @ 2026-06-26 14:45 UTC (permalink / raw)
  To: colbyt; +Cc: devel

[-- Attachment #1: Type: text/plain, Size: 3698 bytes --]

colbyt <colby@colbyt.com> writes:

> The crosvm VM test paths used raw tap networking for their primary
> network device, while the Cloud Hypervisor paths already used Spectrum's
> passt-backed vhost-user-net helper.
>
> Start the existing helper for crosvm and pass it to crosvm with
> --vhost-user net,socket=build/vhost-user-net.sock.  The net VM still
> keeps tap1 for its downstream interface, and the start-vhost-user-net
> targets are marked phony like the other service-start targets.
>
> Signed-off-by: colbyt <colby@colbyt.com>
> ---
>  img/app/Makefile    | 7 ++++---
>  vm/sys/net/Makefile | 5 +++--
>  2 files changed, 7 insertions(+), 5 deletions(-)
>
> diff --git a/img/app/Makefile b/img/app/Makefile
> index fd75e6e..915db3d 100644
> --- a/img/app/Makefile
> +++ b/img/app/Makefile
> @@ -84,6 +84,7 @@ start-vhost-user-gpu:
>  start-vhost-user-net:
>  	mkdir -p build
>  	../../scripts/start-passt.elb
> +.PHONY: start-vhost-user-net
>  
>  start-virtiofsd: scripts/start-virtiofsd.elb
>  	mkdir -p build
> @@ -127,11 +128,11 @@ run-cloud-hypervisor: $(imgdir)/appvm/blk/root.img start-vhost-user-gpu start-vh
>  	    --serial file=build/serial.log
>  .PHONY: run-cloud-hypervisor
>  
> -run-crosvm: $(imgdir)/appvm/blk/root.img start-vhost-user-gpu start-virtiofsd
> -	../../scripts/with-taps.elb $(CROSVM_RUN) \
> +run-crosvm: $(imgdir)/appvm/blk/root.img start-vhost-user-gpu start-vhost-user-net start-virtiofsd
> +	$(CROSVM_RUN) \
>  	    -b path=$(imgdir)/appvm/blk/root.img,ro=true \
>  	    -p "console=ttyS0 root=PARTLABEL=root" \
> -	    --net tap-name=tap0,mac=02:00:00:00:00:01 \
> +	    --vhost-user net,socket=build/vhost-user-net.sock \
>  	    --vhost-user fs,socket=build/virtiofsd.sock \
>  	    --vhost-user gpu,socket=build/vhost-user-gpu.sock \
>  	    --vsock cid=3 \

I'm not sure about this.  If we lose the ability to set the MAC, the VM
can't recognize this as a Spectrum internal interface, and configure it
appropriately.  At present the only configuration involved is setting
the interface up, but I'm not sure it's so useful to test with an
interface that to the VM looks like a passed through physical interface,
which would be an unusual (but not impossible) thing for an app VM to
have.

> diff --git a/vm/sys/net/Makefile b/vm/sys/net/Makefile
> index 653ef13..e37fe8c 100644
> --- a/vm/sys/net/Makefile
> +++ b/vm/sys/net/Makefile
> @@ -63,6 +63,7 @@ debug:
>  start-vhost-user-net:
>  	mkdir -p build
>  	../../../scripts/start-passt.elb
> +.PHONY: start-vhost-user-net
>  
>  run-qemu: $(vmdir)/netvm/blk/root.img
>  	@../../../scripts/run-qemu.sh -m 256 -cpu max -kernel $(KERNEL) -vga none \
> @@ -93,11 +94,11 @@ run-cloud-hypervisor: $(vmdir)/netvm/blk/root.img start-vhost-user-net
>  	    --serial file=build/serial.log
>  .PHONY: run-cloud-hypervisor
>  
> -run-crosvm: $(vmdir)/netvm/blk/root.img
> +run-crosvm: $(vmdir)/netvm/blk/root.img start-vhost-user-net
>  	../../../scripts/with-taps.elb $(CROSVM_RUN) \
>  	    -b path=$(vmdir)/netvm/blk/root.img,ro=true \
>  	    -p "console=ttyS0 root=PARTLABEL=root" \
> -	    --net tap-name=tap0 \
> +	    --vhost-user net,socket=build/vhost-user-net.sock \
>  	    --net tap-name=tap1,mac=02:01:00:00:00:01 \
>  	    --serial type=file,hardware=serial,path=build/serial.log \
>  	    --serial type=stdout,hardware=virtio-console,stdin=true \

This is fine though, since here we're using passt to simulate a physical
device that wouldn't have a special MAC.

The .PHONY additions are of course also correct, so I propose applying
this patch minus the change to run-crosvm in img/app.  What do you think?

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 227 bytes --]

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 5/6] installer: suppress boot console status noise
  2026-06-25 17:48 ` [PATCH 5/6] installer: suppress boot console status noise colbyt
@ 2026-06-26 14:46   ` Alyssa Ross
  2026-06-26 19:09     ` colby
  0 siblings, 1 reply; 16+ messages in thread
From: Alyssa Ross @ 2026-06-26 14:46 UTC (permalink / raw)
  To: colbyt; +Cc: devel

[-- Attachment #1: Type: text/plain, Size: 2290 bytes --]

colbyt <colby@colbyt.com> writes:

> The installer can show systemd or udev messages between Plymouth exiting
> and cage starting, which breaks the intended flicker-free graphical
> handoff.
>
> Add quiet/systemd/udev kernel parameters to suppress status output and
> stop forcing systemd.journald.forward_to_console in the QEMU runner.
> This keeps the installer VM aligned with the quiet graphical boot path.
>
> Signed-off-by: colbyt <colby@colbyt.com>
> ---
>  release/installer/configuration.nix | 9 ++++++++-
>  release/installer/run-vm.nix        | 5 +----
>  2 files changed, 9 insertions(+), 5 deletions(-)
>
> diff --git a/release/installer/configuration.nix b/release/installer/configuration.nix
> index 3f9ef24..daaf5b7 100644
> --- a/release/installer/configuration.nix
> +++ b/release/installer/configuration.nix
> @@ -11,7 +11,14 @@ in
>    imports = [ (modulesPath + "/profiles/all-hardware.nix") ];
>  
>    boot.consoleLogLevel = lib.mkDefault 2;
> -  boot.kernelParams = [ "udev.log_priority=5" ];
> +  boot.kernelParams = [
> +    "quiet"
> +    "loglevel=3"
> +    "systemd.show_status=false"
> +    "rd.systemd.show_status=false"
> +    "udev.log_level=3"
> +    "rd.udev.log_level=3"
> +  ];

Why 3 in particular?  Experimentation?  Inspiration from some other
distribution?

>    boot.initrd.verbose = false;
>  
>    boot.kernelPackages = pkgs.linuxPackages_latest;
> diff --git a/release/installer/run-vm.nix b/release/installer/run-vm.nix
> index b9907f7..6639c8b 100644
> --- a/release/installer/run-vm.nix
> +++ b/release/installer/run-vm.nix
> @@ -40,8 +40,5 @@ writeShellScript "run-spectrum-installer-vm.sh" ''
>      -drive file=/proc/self/fd/3,format=raw,if=virtio \
>      -kernel ${installer.kernel} \
>      -initrd ${installer.initramfs} \
> -    -append ${escapeShellArg (toString [
> -      installer.kernelParams
> -      "systemd.journald.forward_to_console"
> -    ])}
> +    -append ${escapeShellArg installer.kernelParams}
>  '') (_: {})

The divergence here was intentional, since in development it's very
useful to be able to see logs on the serial console, and it should have
a minimal impact on anything else.  Did you see this causing problems
with flicker-free boot or something?

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 227 bytes --]

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 5/6] installer: suppress boot console status noise
  2026-06-26 14:46   ` Alyssa Ross
@ 2026-06-26 19:09     ` colby
  2026-07-02 11:44       ` Alyssa Ross
  0 siblings, 1 reply; 16+ messages in thread
From: colby @ 2026-06-26 19:09 UTC (permalink / raw)
  To: Alyssa Ross; +Cc: devel

That was just me reading the bugs page and taking a crack at https://pad.lassul.us/s/mDfFPvHjA

"Make flicker-free boot work more reliably in the installer
systemd messages are sometimes displayed in the installer in between Plymouth exiting and cage starting. Reproduce some of these messages, and figure out what we need to set to disable them."

It seemed to me that was your answer!  But I could be wrong, I'm very new here.


On Friday, June 26th, 2026 at 7:46 AM, Alyssa Ross <hi@alyssa.is> wrote:

> colbyt <colby@colbyt.com> writes:
> 
> > The installer can show systemd or udev messages between Plymouth exiting
> > and cage starting, which breaks the intended flicker-free graphical
> > handoff.
> >
> > Add quiet/systemd/udev kernel parameters to suppress status output and
> > stop forcing systemd.journald.forward_to_console in the QEMU runner.
> > This keeps the installer VM aligned with the quiet graphical boot path.
> >
> > Signed-off-by: colbyt <colby@colbyt.com>
> > ---
> >  release/installer/configuration.nix | 9 ++++++++-
> >  release/installer/run-vm.nix        | 5 +----
> >  2 files changed, 9 insertions(+), 5 deletions(-)
> >
> > diff --git a/release/installer/configuration.nix b/release/installer/configuration.nix
> > index 3f9ef24..daaf5b7 100644
> > --- a/release/installer/configuration.nix
> > +++ b/release/installer/configuration.nix
> > @@ -11,7 +11,14 @@ in
> >    imports = [ (modulesPath + "/profiles/all-hardware.nix") ];
> >  
> >    boot.consoleLogLevel = lib.mkDefault 2;
> > -  boot.kernelParams = [ "udev.log_priority=5" ];
> > +  boot.kernelParams = [
> > +    "quiet"
> > +    "loglevel=3"
> > +    "systemd.show_status=false"
> > +    "rd.systemd.show_status=false"
> > +    "udev.log_level=3"
> > +    "rd.udev.log_level=3"
> > +  ];
> 
> Why 3 in particular?  Experimentation?  Inspiration from some other
> distribution?
> 
> >    boot.initrd.verbose = false;
> >  
> >    boot.kernelPackages = pkgs.linuxPackages_latest;
> > diff --git a/release/installer/run-vm.nix b/release/installer/run-vm.nix
> > index b9907f7..6639c8b 100644
> > --- a/release/installer/run-vm.nix
> > +++ b/release/installer/run-vm.nix
> > @@ -40,8 +40,5 @@ writeShellScript "run-spectrum-installer-vm.sh" ''
> >      -drive file=/proc/self/fd/3,format=raw,if=virtio \
> >      -kernel ${installer.kernel} \
> >      -initrd ${installer.initramfs} \
> > -    -append ${escapeShellArg (toString [
> > -      installer.kernelParams
> > -      "systemd.journald.forward_to_console"
> > -    ])}
> > +    -append ${escapeShellArg installer.kernelParams}
> >  '') (_: {})
> 
> The divergence here was intentional, since in development it's very
> useful to be able to see logs on the serial console, and it should have
> a minimal impact on anything else.  Did you see this causing problems
> with flicker-free boot or something?
>

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 3/6] vm: use vhost-user networking for crosvm
  2026-06-25 17:48 ` [PATCH 3/6] vm: use vhost-user networking for crosvm colbyt
  2026-06-26 14:45   ` Alyssa Ross
@ 2026-07-02  9:07   ` Alyssa Ross
  1 sibling, 0 replies; 16+ messages in thread
From: Alyssa Ross @ 2026-07-02  9:07 UTC (permalink / raw)
  To: colbyt, devel; +Cc: colbyt

This patch has been committed as ae0c83afbd65c6e535753b4dd806d12ce1f61e34,
which can be viewed online at
https://spectrum-os.org/git/spectrum/commit/?id=ae0c83afbd65c6e535753b4dd806d12ce1f61e34.

This is an automated message.  Send comments/questions/requests to:
Alyssa Ross <hi@alyssa.is>

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 5/6] installer: suppress boot console status noise
  2026-06-26 19:09     ` colby
@ 2026-07-02 11:44       ` Alyssa Ross
  0 siblings, 0 replies; 16+ messages in thread
From: Alyssa Ross @ 2026-07-02 11:44 UTC (permalink / raw)
  To: colby; +Cc: devel

[-- Attachment #1: Type: text/plain, Size: 3323 bytes --]

colby@colbyt.com writes:

> That was just me reading the bugs page and taking a crack at https://pad.lassul.us/s/mDfFPvHjA
>
> "Make flicker-free boot work more reliably in the installer
> systemd messages are sometimes displayed in the installer in between Plymouth exiting and cage starting. Reproduce some of these messages, and figure out what we need to set to disable them."
>
> It seemed to me that was your answer!  But I could be wrong, I'm very new here.

No, that's exactly the right thing to have done!  I was just wondering
about the detail — did you try larger log levels and find them
insufficient?  Did you have to use all of these at once to achieve
flicker free boot?  I just want to make sure we understand why we're
adding each line!

> On Friday, June 26th, 2026 at 7:46 AM, Alyssa Ross <hi@alyssa.is> wrote:
>
>> colbyt <colby@colbyt.com> writes:
>> 
>> > The installer can show systemd or udev messages between Plymouth exiting
>> > and cage starting, which breaks the intended flicker-free graphical
>> > handoff.
>> >
>> > Add quiet/systemd/udev kernel parameters to suppress status output and
>> > stop forcing systemd.journald.forward_to_console in the QEMU runner.
>> > This keeps the installer VM aligned with the quiet graphical boot path.
>> >
>> > Signed-off-by: colbyt <colby@colbyt.com>
>> > ---
>> >  release/installer/configuration.nix | 9 ++++++++-
>> >  release/installer/run-vm.nix        | 5 +----
>> >  2 files changed, 9 insertions(+), 5 deletions(-)
>> >
>> > diff --git a/release/installer/configuration.nix b/release/installer/configuration.nix
>> > index 3f9ef24..daaf5b7 100644
>> > --- a/release/installer/configuration.nix
>> > +++ b/release/installer/configuration.nix
>> > @@ -11,7 +11,14 @@ in
>> >    imports = [ (modulesPath + "/profiles/all-hardware.nix") ];
>> >  
>> >    boot.consoleLogLevel = lib.mkDefault 2;
>> > -  boot.kernelParams = [ "udev.log_priority=5" ];
>> > +  boot.kernelParams = [
>> > +    "quiet"
>> > +    "loglevel=3"
>> > +    "systemd.show_status=false"
>> > +    "rd.systemd.show_status=false"
>> > +    "udev.log_level=3"
>> > +    "rd.udev.log_level=3"
>> > +  ];
>> 
>> Why 3 in particular?  Experimentation?  Inspiration from some other
>> distribution?
>> 
>> >    boot.initrd.verbose = false;
>> >  
>> >    boot.kernelPackages = pkgs.linuxPackages_latest;
>> > diff --git a/release/installer/run-vm.nix b/release/installer/run-vm.nix
>> > index b9907f7..6639c8b 100644
>> > --- a/release/installer/run-vm.nix
>> > +++ b/release/installer/run-vm.nix
>> > @@ -40,8 +40,5 @@ writeShellScript "run-spectrum-installer-vm.sh" ''
>> >      -drive file=/proc/self/fd/3,format=raw,if=virtio \
>> >      -kernel ${installer.kernel} \
>> >      -initrd ${installer.initramfs} \
>> > -    -append ${escapeShellArg (toString [
>> > -      installer.kernelParams
>> > -      "systemd.journald.forward_to_console"
>> > -    ])}
>> > +    -append ${escapeShellArg installer.kernelParams}
>> >  '') (_: {})
>> 
>> The divergence here was intentional, since in development it's very
>> useful to be able to see logs on the serial console, and it should have
>> a minimal impact on anything else.  Did you see this causing problems
>> with flicker-free boot or something?
>> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 227 bytes --]

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2026-07-02 11:45 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-25 17:48 [PATCH 0/6] cloud-hypervisor v52 and VM runtime fixes colbyt
2026-06-25 17:48 ` [PATCH 1/6] pkgs/skaware: vendor backported patches colbyt
2026-06-26 13:39   ` Alyssa Ross
2026-06-25 17:48 ` [PATCH 2/6] pkgs/cloud-hypervisor: update GPU patchset to v52 colbyt
2026-06-26 14:06   ` Alyssa Ross
2026-06-25 17:48 ` [PATCH 3/6] vm: use vhost-user networking for crosvm colbyt
2026-06-26 14:45   ` Alyssa Ross
2026-07-02  9:07   ` Alyssa Ross
2026-06-25 17:48 ` [PATCH 4/6] Documentation: use crosvm GPU socket-path option colbyt
2026-06-26 14:18   ` Alyssa Ross
2026-06-25 17:48 ` [PATCH 5/6] installer: suppress boot console status noise colbyt
2026-06-26 14:46   ` Alyssa Ross
2026-06-26 19:09     ` colby
2026-07-02 11:44       ` Alyssa Ross
2026-06-25 17:48 ` [PATCH 6/6] start-vmm: test GPU socket configuration colbyt
2026-06-26 14:18   ` Alyssa Ross

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).