From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from atuin.qyliss.net (localhost [IPv6:::1]) by atuin.qyliss.net (Postfix) with ESMTP id CB487AF70; Fri, 26 Jun 2026 18:55:38 +0000 (UTC) Received: by atuin.qyliss.net (Postfix, from userid 993) id 9FFB0AF44; Fri, 26 Jun 2026 18:55:36 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-26) on atuin.qyliss.net X-Spam-Level: X-Spam-Status: No, score=-0.1 required=3.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,DMARC_PASS,SPF_HELO_PASS,T_FILL_THIS_FORM_SHORT autolearn=unavailable autolearn_force=no version=4.0.1 Received: from mail-244106.protonmail.ch (mail-244106.protonmail.ch [109.224.244.106]) by atuin.qyliss.net (Postfix) with ESMTPS id 02670AF1F for ; Fri, 26 Jun 2026 18:55:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=colbyt.com; s=protonmail; t=1782500131; x=1782759331; bh=CM9i87n1RPg8PuZSJy2DViLs4UMMeGS+8vQpGOCsFCA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References:From:To: Cc:Date:Subject:Reply-To:Feedback-ID:Message-ID:BIMI-Selector; b=t8+HaQeRcT9LhbXWZTGWDV/s8Cavx3QdHWhZdpyt9mb9iTKEHpJnMxBSHCQBXGc9G MtNzbDtXfgn9Zzdt5LD1a8Gti4UdGMPeG2pwezROm/LcT7P3SytE8X9FpJqdeclxZY fZV5lqh6vwiCSnokXYNmVc6c2fnIIiHGNiFR38CgP3a0OXmk2JMb9C0UhCli9W2J56 yxRuOzdgTQyB3B6rIZr0uSoWSJqvyWSZMyThbFMrfCBmOTtJDhOzvjFfNSHiVxD376 Kl3YUxhwDH/+fb+QL3ax6FkaGjQ7Jlm1rPBwdfrngJcpTh3/9PzMkvYCXEYJwOqzwz sgLOQw3gQfT7A== X-Pm-Submission-Id: 4gn4cb1s8Rz2Sd39 From: colbyt To: devel@spectrum-os.org Subject: [PATCH 6/8] pkgs/cloud-hypervisor: update GPU patchset to v52 Date: Fri, 26 Jun 2026 11:55:06 -0700 Message-ID: <20260626185509.3715326-7-colby@colbyt.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260626185509.3715326-1-colby@colbyt.com> References: <20260626185509.3715326-1-colby@colbyt.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Message-ID-Hash: L5BRSFVA2RPNGXUFAKF6NVRSKN5GXVVY X-Message-ID-Hash: L5BRSFVA2RPNGXUFAKF6NVRSKN5GXVVY X-MailFrom: colby@colbyt.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; header-match-devel.spectrum-os.org-0; header-match-devel.spectrum-os.org-1; header-match-devel.spectrum-os.org-2; header-match-devel.spectrum-os.org-3; header-match-devel.spectrum-os.org-4; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: colbyt X-Mailman-Version: 3.3.10 Precedence: list List-Id: Patches and low-level development discussion Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Update Spectrum's patched Cloud Hypervisor package to 52.0 and rebase the local virtio-gpu/vhost-user GPU support onto that release. Cloud Hypervisor 52.0 uses vhost 0.16.0 and vhost-user-backend 0.22.0, so update the paired rust-vmm/vhost checkout as well. Keep the local GPU support on top of that checkout, including the crosvm SHMEM_MAP protocol-bit spelling needed by the crosvm GPU backend packaged in the current nixpkgs pin. The GPU frontend now uses the shared-memory region advertised by the backend instead of assuming region 0, matching crosvm's host-visible region ID. The cargo vendor derivation vendors dependencies after applying the local Cloud Hypervisor and vhost patches, so the patched vhost checkout is included in the fixed-output dependency tree. Signed-off-by: colbyt --- .../0001-build-use-local-vhost.patch | 38 +- ...0002-virtio-devices-add-a-GPU-device.patch | 684 ++++++++---------- pkgs/cloud-hypervisor/default.nix | 77 +- ...ost_user-add-crosvm-shmem-map-compat.patch | 79 ++ 4 files changed, 482 insertions(+), 396 deletions(-) create mode 100644 pkgs/cloud-hypervisor/vhost/0003-vhost_user-add-crosvm-shmem-map-compat.patch diff --git a/pkgs/cloud-hypervisor/0001-build-use-local-vhost.patch b/pkgs/cloud-hypervisor/0001-build-use-local-vhost.patch index 3e00250..8f18b94 100644 --- a/pkgs/cloud-hypervisor/0001-build-use-local-vhost.patch +++ b/pkgs/cloud-hypervisor/0001-build-use-local-vhost.patch @@ -1,55 +1,55 @@ From fca364182f5c4e595384297316e9c74069ca5169 Mon Sep 17 00:00:00 2001 From: Alyssa Ross 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 SPDX-License-Identifier: Apache-2.0 AND LicenseRef-BSD-3-Clause-Google Signed-off-by: Alyssa Ross Signed-off-by: Alyssa Ross +Signed-off-by: colbyt --- Cargo.lock | 4 ---- Cargo.toml | 4 ++-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock -index 62bbf709f..39df61015 100644 +index d0a21c5..e7af1c2 100644 --- a/Cargo.lock +++ b/Cargo.lock -@@ -2304,8 +2304,6 @@ dependencies = [ +@@ -2408,8 +2408,6 @@ dependencies = [ [[package]] name = "vhost" - version = "0.14.0" + version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "2a4dcad85a129d97d5d4b2f3c47a4affdeedd76bdcd02094bcb5d9b76cac2d05" +-checksum = "ee90657203a8644e9a0860a0db6a7887d8ef0c7bc09fc22dfa4ae75df65bac86" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.1", "libc", -@@ -2317,8 +2315,6 @@ dependencies = [ +@@ -2421,8 +2419,6 @@ dependencies = [ [[package]] name = "vhost-user-backend" - version = "0.20.0" + version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "e183205a9ba7cb9c47fcb0fc0a07fc295a110efbb11ab78ad0d793b0a38a7bde" +-checksum = "d5925983d8fb537752ad3e26604c0a17abfa5de77cb6773a096c8a959c9eca0f" dependencies = [ "libc", "log", diff --git a/Cargo.toml b/Cargo.toml -index b738dde5b..1118f1eb1 100644 +index 3ef574c..197f8fd 100644 --- a/Cargo.toml +++ b/Cargo.toml -@@ -55,8 +55,8 @@ seccompiler = "0.5.0" - vfio-bindings = { version = "0.6.0", default-features = false } - vfio-ioctls = { version = "0.5.1", default-features = false } - vfio_user = { version = "0.1.1", default-features = false } --vhost = { version = "0.14.0", default-features = false } --vhost-user-backend = { version = "0.20.0", default-features = false } +@@ -63,8 +63,8 @@ seccompiler = "0.5.0" + vfio-bindings = { version = "0.6.2", default-features = false } + vfio-ioctls = { version = "0.6.0", default-features = false } + vfio_user = { version = "0.1.3", default-features = false } +-vhost = { version = "0.16.0", default-features = false } +-vhost-user-backend = { version = "0.22.0", default-features = false } +vhost = { path = "../vhost/vhost" } +vhost-user-backend = { path = "../vhost/vhost-user-backend" } virtio-bindings = "0.2.6" - virtio-queue = "0.16.0" + virtio-queue = "0.17.0" vm-fdt = "0.3.0" -- -2.53.0 - +2.54.0 diff --git a/pkgs/cloud-hypervisor/0002-virtio-devices-add-a-GPU-device.patch b/pkgs/cloud-hypervisor/0002-virtio-devices-add-a-GPU-device.patch index d53755b..b5cd93b 100644 --- a/pkgs/cloud-hypervisor/0002-virtio-devices-add-a-GPU-device.patch +++ b/pkgs/cloud-hypervisor/0002-virtio-devices-add-a-GPU-device.patch @@ -1,7 +1,7 @@ From e4f29830f953c826c0fca137ef87ab3b67ac74ae Mon Sep 17 00:00:00 2001 From: Alyssa Ross 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 Co-authored-by: Alyssa Ross Signed-off-by: Alyssa Ross +Signed-off-by: colbyt --- - 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>; - fn vm_add_disk(&self, disk_config: &str) -> zbus::Result>; - fn vm_add_fs(&self, fs_config: &str) -> zbus::Result>; +@@ -93,6 +95,7 @@ trait DBusApi1 { + &self, + generic_vhost_user_config: &str, + ) -> zbus::Result>; + fn vm_add_gpu(&self, gpu_config: &str) -> zbus::Result>; fn vm_add_net(&self, net_config: &str) -> zbus::Result>; fn vm_add_pmem(&self, pmem_config: &str) -> zbus::Result>; fn vm_add_user_device(&self, vm_add_user_device: &str) -> zbus::Result>; -@@ -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 { - Ok(fs_config) +@@ -875,6 +903,13 @@ fn add_generic_vhost_user_config(config: &str) -> Result { + Ok(generic_vhost_user_config) } +fn add_gpu_config(config: &str) -> Result { @@ -143,12 +142,12 @@ index fd48ffab1..680a2b62f 100644 fn add_pmem_config(config: &str) -> Result { 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=") - .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, @@ -215,31 +211,33 @@ index f0ed28f51..892bf08ee 100644 + pub region_list: BTreeMap, } - /// 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)> { +@@ -219,6 +220,18 @@ fn virtio_generic_vhost_user_thread_rules() -> Vec<(i64, Vec)> { ] } @@ -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)> { vec![] } -@@ -271,6 +286,7 @@ fn get_seccomp_rules(thread_type: Thread) -> Vec<(i64, Vec)> { +@@ -299,6 +312,7 @@ fn get_seccomp_rules(thread_type: Thread) -> Vec<(i64, Vec)> { Thread::VirtioRng => virtio_rng_thread_rules(), Thread::VirtioVhostBlock => virtio_vhost_block_thread_rules(), Thread::VirtioVhostFs => virtio_vhost_fs_thread_rules(), + Thread::VirtioVhostGpu => virtio_vhost_gpu_thread_rules(), + Thread::VirtioGenericVhostUser => virtio_generic_vhost_user_thread_rules(), Thread::VirtioVhostNet => virtio_vhost_net_thread_rules(), Thread::VirtioVhostNetCtl => virtio_vhost_net_ctl_thread_rules(), - Thread::VirtioVsock => virtio_vsock_thread_rules(), diff --git a/virtio-devices/src/transport/pci_device.rs b/virtio-devices/src/transport/pci_device.rs -index 408611e29..08ba91908 100644 +index ac37c58..5b33239 100644 --- a/virtio-devices/src/transport/pci_device.rs +++ b/virtio-devices/src/transport/pci_device.rs -@@ -1036,11 +1036,11 @@ impl PciDevice for VirtioPciDevice { +@@ -1092,11 +1092,11 @@ impl PciDevice for VirtioPciDevice { PciDeviceError::IoRegistrationFailed(shm_list.addr.raw_value(), e) })?; @@ -299,10 +295,10 @@ index 408611e29..08ba91908 100644 ); diff --git a/virtio-devices/src/vhost_user/gpu.rs b/virtio-devices/src/vhost_user/gpu.rs new file mode 100644 -index 000000000..7eec07ba6 +index 0000000..f04c74a --- /dev/null +++ b/virtio-devices/src/vhost_user/gpu.rs -@@ -0,0 +1,411 @@ +@@ -0,0 +1,423 @@ +// Copyright 2019 Intel Corporation. All Rights Reserved. +// Copyright 2022 Unikie +// Copyright 2023 Alyssa Ross @@ -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 { ++ fn shmem_map(&self, req: &VhostUserMMap, fd: &dyn AsRawFd) -> HandlerResult { + 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 { ++ fn shmem_unmap(&self, req: &VhostUserMMap) -> HandlerResult { + let target = self.ptr_guard_mut(req.shm_offset, req.len)?; + + // SAFETY: we've checked we're only giving addr and length @@ -445,9 +448,10 @@ index 000000000..7eec07ba6 + seccomp_action: SeccompAction, + exit_evt: EventFd, + iommu: bool, -+ ) -> Result<(Gpu, VhostSharedMemoryRegion)> { ++ ) -> Result<(Gpu, VhostUserShMemConfig)> { + // Connect to the vhost-user socket. -+ let mut vu = VhostUserHandle::connect_vhost_user(false, path, NUM_QUEUES as u64, false)?; ++ let mut vu = ++ VhostUserHandle::connect_vhost_user(false, path, NUM_QUEUES as u64, false, None)?; + + let avail_features = 1 << VIRTIO_F_VERSION_1 + | 1 << VIRTIO_GPU_F_VIRGL @@ -458,19 +462,23 @@ index 000000000..7eec07ba6 + + let avail_protocol_features = VhostUserProtocolFeatures::CONFIG + | VhostUserProtocolFeatures::BACKEND_REQ -+ | VhostUserProtocolFeatures::SHARED_MEMORY_REGIONS; ++ | VhostUserProtocolFeatures::SHMEM_MAP; + + let (acked_features, acked_protocol_features) = + vu.negotiate_features_vhost_user(avail_features, avail_protocol_features)?; + -+ let shm_regions = vu.get_shared_memory_regions()?; -+ if shm_regions.len() != 1 { ++ let shm_config = vu.get_shmem_config()?; ++ let shmem_regions_count = shm_config ++ .memory_sizes ++ .iter() ++ .filter(|&&len| len != 0) ++ .count(); ++ if shm_config.nregions != 1 || shmem_regions_count != 1 { + return Err(Error::VhostUserUnexpectedSharedMemoryRegionsCount( + 1, -+ shm_regions.len(), ++ shmem_regions_count, + )); + } -+ let shm_region = shm_regions[0]; + + Ok(( + Gpu { @@ -506,7 +514,7 @@ index 000000000..7eec07ba6 + exit_evt, + iommu, + }, -+ shm_region, ++ shm_config, + )) + } + @@ -536,7 +544,7 @@ index 000000000..7eec07ba6 + fn features(&self) -> u64 { + let mut features = self.common.avail_features; + if self.iommu { -+ features |= 1u64 << VIRTIO_F_IOMMU_PLATFORM; ++ features |= 1u64 << VIRTIO_F_ACCESS_PLATFORM; + } + features + } @@ -564,12 +572,13 @@ index 000000000..7eec07ba6 + } + } + -+ fn activate( -+ &mut self, -+ mem: GuestMemoryAtomic, -+ interrupt_cb: Arc, -+ queues: Vec<(usize, Queue, EventFd)>, -+ ) -> ActivateResult { ++ fn activate(&mut self, context: crate::device::ActivationContext) -> ActivateResult { ++ let crate::device::ActivationContext { ++ mem, ++ interrupt_cb, ++ queues, ++ device_status, ++ } = context; + self.common.activate(&queues, interrupt_cb.clone())?; + self.guest_memory = Some(mem.clone()); + @@ -607,7 +616,7 @@ index 000000000..7eec07ba6 + let mut handler = self.vu_common.activate( + mem, + &queues, -+ interrupt_cb, ++ interrupt_cb.clone(), + self.common.acked_features, + backend_req_handler, + kill_evt, @@ -624,6 +633,8 @@ index 000000000..7eec07ba6 + Thread::VirtioVhostGpu, + &mut epoll_threads, + &self.exit_evt, ++ device_status.clone(), ++ interrupt_cb.clone(), + move || handler.run(&paused, paused_sync.as_ref().unwrap()), + )?; + self.epoll_thread = Some(epoll_threads.remove(0)); @@ -632,17 +643,17 @@ index 000000000..7eec07ba6 + Ok(()) + } + -+ fn reset(&mut self) -> Option> { ++ fn reset(&mut self) { + // We first must resume the virtio thread if it was paused. + if self.common.pause_evt.take().is_some() { -+ self.common.resume().ok()?; ++ self.common.resume().ok(); + } + + if let Some(vu) = &self.vu_common.vu + && let Err(e) = vu.lock().unwrap().reset_vhost_user() + { + error!("Failed to reset vhost-user daemon: {e:?}"); -+ return None; ++ return; + } + + if let Some(kill_evt) = self.common.kill_evt.take() { @@ -651,9 +662,6 @@ index 000000000..7eec07ba6 + } + + event!("virtio-device", "reset", "id", &self.id); -+ -+ // Return the interrupt -+ Some(self.common.interrupt_cb.take().unwrap()) + } + + fn shutdown(&mut self) { @@ -715,24 +723,25 @@ index 000000000..7eec07ba6 + } +} diff --git a/virtio-devices/src/vhost_user/mod.rs b/virtio-devices/src/vhost_user/mod.rs -index 05233a0be..f2e83ff84 100644 +index babc823..76146b3 100644 --- a/virtio-devices/src/vhost_user/mod.rs +++ b/virtio-devices/src/vhost_user/mod.rs -@@ -33,11 +33,13 @@ use crate::{ - +@@ -37,12 +37,14 @@ use crate::{ pub mod blk; pub mod fs; + pub mod generic_vhost_user; +pub mod gpu; pub mod net; pub mod vu_common_ctrl; pub use self::blk::Blk; pub use self::fs::*; + pub use self::generic_vhost_user::GenericVhostUser; +pub use self::gpu::*; pub use self::net::Net; pub use self::vu_common_ctrl::VhostUserConfig; -@@ -75,6 +77,8 @@ pub enum Error { +@@ -82,6 +84,8 @@ pub enum Error { VhostUserGetQueueMaxNum(#[source] VhostError), #[error("Get protocol features failed")] VhostUserGetProtocolFeatures(#[source] VhostError), @@ -741,36 +750,37 @@ index 05233a0be..f2e83ff84 100644 #[error("Get vring base failed")] VhostUserGetVringBase(#[source] VhostError), #[error("Vhost-user Backend not support vhost-user protocol")] -@@ -123,6 +127,8 @@ pub enum Error { +@@ -130,6 +134,10 @@ pub enum Error { VhostUserSetInflight(#[source] VhostError), #[error("Failed setting the log base")] VhostUserSetLogBase(#[source] VhostError), + #[error("Expected {0} shared memory regions; got {1}")] + VhostUserUnexpectedSharedMemoryRegionsCount(usize, usize), ++ #[error("Invalid shared memory region")] ++ VhostUserInvalidSharedMemoryRegion, #[error("Invalid used address")] UsedAddress, #[error("Invalid features provided from vhost-user backend")] diff --git a/virtio-devices/src/vhost_user/vu_common_ctrl.rs b/virtio-devices/src/vhost_user/vu_common_ctrl.rs -index 264635149..220b49112 100644 +index 23a37c3..8c668a3 100644 --- a/virtio-devices/src/vhost_user/vu_common_ctrl.rs +++ b/virtio-devices/src/vhost_user/vu_common_ctrl.rs -@@ -13,7 +13,8 @@ use std::time::{Duration, Instant}; - use log::{error, info}; - use vhost::vhost_kern::vhost_binding::{VHOST_F_LOG_ALL, VHOST_VRING_F_LOG}; +@@ -14,7 +14,7 @@ use log::{error, info}; + use vhost::vhost_kern::vhost_binding::VHOST_VRING_F_LOG; use vhost::vhost_user::message::{ -- VhostUserHeaderFlag, VhostUserInflight, VhostUserProtocolFeatures, VhostUserVirtioFeatures, -+ VhostSharedMemoryRegion, VhostUserHeaderFlag, VhostUserInflight, VhostUserProtocolFeatures, -+ VhostUserVirtioFeatures, + VhostTransferStateDirection, VhostTransferStatePhase, VhostUserHeaderFlag, VhostUserInflight, +- VhostUserProtocolFeatures, VhostUserVirtioFeatures, ++ VhostUserProtocolFeatures, VhostUserShMemConfig, VhostUserVirtioFeatures, }; use vhost::vhost_user::{ Frontend, FrontendReqHandler, VhostUserFrontend, VhostUserFrontendReqHandler, -@@ -107,6 +108,12 @@ impl VhostUserHandle { +@@ -114,6 +114,12 @@ impl VhostUserHandle { .map_err(Error::VhostUserAddMemReg) } -+ pub fn get_shared_memory_regions(&self) -> Result> { ++ pub fn get_shmem_config(&mut self) -> Result { + self.vu -+ .get_shared_memory_regions() ++ .get_shmem_config() + .map_err(Error::VhostUserGetSharedMemoryRegions) + } + @@ -778,20 +788,20 @@ index 264635149..220b49112 100644 &mut self, avail_features: u64, diff --git a/vmm/src/api/dbus/mod.rs b/vmm/src/api/dbus/mod.rs -index 6f75fb5cd..78275925d 100644 +index ae39feb..aa579e9 100644 --- a/vmm/src/api/dbus/mod.rs +++ b/vmm/src/api/dbus/mod.rs @@ -22,7 +22,7 @@ use super::{ApiAction, ApiRequest}; #[cfg(all(target_arch = "x86_64", feature = "guest_debug"))] use crate::api::VmCoredump; use crate::api::{ -- AddDisk, Body, VmAddDevice, VmAddFs, VmAddNet, VmAddPmem, VmAddUserDevice, VmAddVdpa, -+ AddDisk, Body, VmAddDevice, VmAddFs, VmAddGpu, VmAddNet, VmAddPmem, VmAddUserDevice, VmAddVdpa, - VmAddVsock, VmBoot, VmCounters, VmCreate, VmDelete, VmInfo, VmPause, VmPowerButton, VmReboot, - VmReceiveMigration, VmRemoveDevice, VmResize, VmResizeZone, VmRestore, VmResume, - VmSendMigration, VmShutdown, VmSnapshot, VmmPing, VmmShutdown, -@@ -144,6 +144,11 @@ impl DBusApi { - self.vm_action(&VmAddFs, fs_config).await +- AddDisk, Body, VmAddDevice, VmAddFs, VmAddGenericVhostUser, VmAddNet, VmAddPmem, ++ AddDisk, Body, VmAddDevice, VmAddFs, VmAddGenericVhostUser, VmAddGpu, VmAddNet, VmAddPmem, + VmAddUserDevice, VmAddVdpa, VmAddVsock, VmBoot, VmCounters, VmCreate, VmDelete, VmInfo, + VmPause, VmPowerButton, VmReboot, VmReceiveMigration, VmRemoveDevice, VmResize, VmResizeZone, + VmRestore, VmResume, VmSendMigration, VmShutdown, VmSnapshot, VmmPing, VmmShutdown, +@@ -154,6 +154,11 @@ impl DBusApi { + .await } + async fn vm_add_gpu(&self, gpu_config: String) -> Result> { @@ -803,54 +813,42 @@ index 6f75fb5cd..78275925d 100644 let mut net_config: NetConfig = serde_json::from_str(&net_config).map_err(api_error)?; if net_config.fds.is_some() { diff --git a/vmm/src/api/http/http_endpoint.rs b/vmm/src/api/http/http_endpoint.rs -index e463a2081..0936eff22 100644 +index 92b53ac..0e67daf 100644 --- a/vmm/src/api/http/http_endpoint.rs +++ b/vmm/src/api/http/http_endpoint.rs -@@ -45,10 +45,10 @@ use crate::api::VmCoredump; +@@ -45,7 +45,7 @@ use crate::api::VmCoredump; use crate::api::http::http_endpoint::fds_helper::{attach_fds_to_cfg, attach_fds_to_cfgs}; use crate::api::http::{EndpointHandler, HttpError, error_response}; use crate::api::{ -- AddDisk, ApiAction, ApiError, ApiRequest, NetConfig, VmAddDevice, VmAddFs, VmAddNet, VmAddPmem, -- VmAddUserDevice, VmAddVdpa, VmAddVsock, VmBoot, VmConfig, VmCounters, VmDelete, VmNmi, VmPause, -- VmPowerButton, VmReboot, VmReceiveMigration, VmRemoveDevice, VmResize, VmResizeDisk, -- VmResizeZone, VmRestore, VmResume, VmSendMigration, VmShutdown, VmSnapshot, -+ AddDisk, ApiAction, ApiError, ApiRequest, NetConfig, VmAddDevice, VmAddFs, VmAddGpu, VmAddNet, -+ VmAddPmem, VmAddUserDevice, VmAddVdpa, VmAddVsock, VmBoot, VmConfig, VmCounters, VmDelete, -+ VmNmi, VmPause, VmPowerButton, VmReboot, VmReceiveMigration, VmRemoveDevice, VmResize, -+ VmResizeDisk, VmResizeZone, VmRestore, VmResume, VmSendMigration, VmShutdown, VmSnapshot, - }; - use crate::config::RestoreConfig; - use crate::cpu::Error as CpuError; -@@ -419,6 +419,7 @@ vm_action_put_handler!(VmNmi); - vm_action_put_handler_body!(VmAddDevice); +- AddDisk, ApiAction, ApiError, ApiRequest, NetConfig, VmAddDevice, VmAddFs, ++ AddDisk, ApiAction, ApiError, ApiRequest, NetConfig, VmAddDevice, VmAddFs, VmAddGpu, + VmAddGenericVhostUser, VmAddNet, VmAddPmem, VmAddUserDevice, VmAddVdpa, VmAddVsock, VmBoot, + VmConfig, VmCounters, VmDelete, VmNmi, VmPause, VmPowerButton, VmReboot, VmReceiveMigration, + VmRemoveDevice, VmResize, VmResizeDisk, VmResizeZone, VmRestore, VmResume, VmSendMigration, +@@ -421,6 +421,7 @@ vm_action_put_handler_body!(VmAddDevice); vm_action_put_handler_body!(AddDisk); vm_action_put_handler_body!(VmAddFs); + vm_action_put_handler_body!(VmAddGenericVhostUser); +vm_action_put_handler_body!(VmAddGpu); vm_action_put_handler_body!(VmAddPmem); vm_action_put_handler_body!(VmAddVdpa); vm_action_put_handler_body!(VmAddVsock); diff --git a/vmm/src/api/http/mod.rs b/vmm/src/api/http/mod.rs -index 2aa52e8e3..7eccb57d1 100644 +index f7cea4f..bd71ce9 100644 --- a/vmm/src/api/http/mod.rs +++ b/vmm/src/api/http/mod.rs -@@ -28,10 +28,10 @@ use self::http_endpoint::{VmActionHandler, VmCreate, VmInfo, VmmPing, VmmShutdow +@@ -28,7 +28,7 @@ use self::http_endpoint::{VmActionHandler, VmCreate, VmInfo, VmmPing, VmmShutdow #[cfg(all(target_arch = "x86_64", feature = "guest_debug"))] use crate::api::VmCoredump; use crate::api::{ -- AddDisk, ApiError, ApiRequest, VmAddDevice, VmAddFs, VmAddNet, VmAddPmem, VmAddUserDevice, -- VmAddVdpa, VmAddVsock, VmBoot, VmCounters, VmDelete, VmNmi, VmPause, VmPowerButton, VmReboot, -- VmReceiveMigration, VmRemoveDevice, VmResize, VmResizeDisk, VmResizeZone, VmRestore, VmResume, -- VmSendMigration, VmShutdown, VmSnapshot, -+ AddDisk, ApiError, ApiRequest, VmAddDevice, VmAddFs, VmAddGpu, VmAddNet, VmAddPmem, -+ VmAddUserDevice, VmAddVdpa, VmAddVsock, VmBoot, VmCounters, VmDelete, VmNmi, VmPause, -+ VmPowerButton, VmReboot, VmReceiveMigration, VmRemoveDevice, VmResize, VmResizeDisk, -+ VmResizeZone, VmRestore, VmResume, VmSendMigration, VmShutdown, VmSnapshot, - }; - use crate::landlock::Landlock; - use crate::seccomp_filters::{Thread, get_seccomp_filter}; -@@ -196,6 +196,10 @@ pub static HTTP_ROUTES: LazyLock = 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 = LazyLock::new(|| { + endpoint!("/vm.add-generic-vhost-user"), + Box::new(VmActionHandler::new(&VmAddGenericVhostUser)), ); + r.routes.insert( + endpoint!("/vm.add-gpu"), @@ -860,41 +858,39 @@ index 2aa52e8e3..7eccb57d1 100644 endpoint!("/vm.add-net"), Box::new(VmActionHandler::new(&VmAddNet)), diff --git a/vmm/src/api/mod.rs b/vmm/src/api/mod.rs -index 12ca6b987..aaafe3843 100644 +index e4ee723..8f8052e 100644 --- a/vmm/src/api/mod.rs +++ b/vmm/src/api/mod.rs -@@ -51,8 +51,8 @@ use crate::config::RestoreConfig; - use crate::device_tree::DeviceTree; +@@ -56,7 +56,7 @@ use crate::device_tree::DeviceTree; + use crate::migration_transport::MAX_MIGRATION_CONNECTIONS; use crate::vm::{Error as VmError, VmState}; use crate::vm_config::{ -- DeviceConfig, DiskConfig, FsConfig, NetConfig, PmemConfig, UserDeviceConfig, VdpaConfig, -- VmConfig, VsockConfig, -+ DeviceConfig, DiskConfig, FsConfig, GpuConfig, NetConfig, PmemConfig, UserDeviceConfig, -+ VdpaConfig, VmConfig, VsockConfig, +- DeviceConfig, DiskConfig, FsConfig, GenericVhostUserConfig, NetConfig, PmemConfig, ++ DeviceConfig, DiskConfig, FsConfig, GenericVhostUserConfig, GpuConfig, NetConfig, PmemConfig, + UserDeviceConfig, VdpaConfig, VmConfig, VsockConfig, }; - /// API errors are sent back from the VMM API server through the ApiResponse. -@@ -170,6 +170,10 @@ pub enum ApiError { - #[error("The fs could not be added to the VM")] - VmAddFs(#[source] VmError), +@@ -179,6 +179,10 @@ pub enum ApiError { + #[error("The generic vhost-user device could not be added to the VM")] + VmAddGenericVhostUser(#[source] VmError), -+ /// The gpu could not be added to the VM. -+ #[error("The GPU could not be added to the VM: {0}")] ++ /// The gpu device could not be added to the VM. ++ #[error("The gpu device could not be added to the VM")] + VmAddGpu(#[source] VmError), + /// The pmem device could not be added to the VM. #[error("The pmem device could not be added to the VM")] VmAddPmem(#[source] VmError), -@@ -340,6 +344,8 @@ pub trait RequestHandler { - - fn vm_add_fs(&mut self, fs_cfg: FsConfig) -> Result>, VmError>; +@@ -561,6 +565,8 @@ pub trait RequestHandler { + fs_cfg: GenericVhostUserConfig, + ) -> Result>, VmError>; + fn vm_add_gpu(&mut self, gpu_cfg: GpuConfig) -> Result>, VmError>; + fn vm_add_pmem(&mut self, pmem_cfg: PmemConfig) -> Result>, VmError>; fn vm_add_net(&mut self, net_cfg: NetConfig) -> Result>, VmError>; -@@ -539,6 +545,43 @@ impl ApiAction for VmAddFs { +@@ -797,6 +803,43 @@ impl ApiAction for VmAddGenericVhostUser { } } @@ -939,10 +935,10 @@ index 12ca6b987..aaafe3843 100644 impl ApiAction for VmAddPmem { diff --git a/vmm/src/api/openapi/cloud-hypervisor.yaml b/vmm/src/api/openapi/cloud-hypervisor.yaml -index 1fa3d9b51..cc290e27f 100644 +index e8b72f7..5c01292 100644 --- a/vmm/src/api/openapi/cloud-hypervisor.yaml +++ b/vmm/src/api/openapi/cloud-hypervisor.yaml -@@ -277,6 +277,28 @@ paths: +@@ -299,6 +299,28 @@ paths: 500: description: The new device could not be added to the VM instance. @@ -971,7 +967,7 @@ index 1fa3d9b51..cc290e27f 100644 /vm.add-pmem: put: summary: Add a new pmem device to the VM -@@ -603,6 +625,10 @@ components: +@@ -629,6 +651,10 @@ components: type: array items: $ref: "#/components/schemas/FsConfig" @@ -979,12 +975,12 @@ index 1fa3d9b51..cc290e27f 100644 + type: array + items: + $ref: "#/components/schemas/GpuConfig" - pmem: + generic-vhost-user: type: array items: -@@ -1044,6 +1070,19 @@ components: - id: - type: string +@@ -1154,6 +1180,22 @@ components: + virtio_id: + type: uint32 + GpuConfig: + required: @@ -993,50 +989,46 @@ index 1fa3d9b51..cc290e27f 100644 + properties: + socket: + type: string ++ id: ++ type: string + pci_segment: + type: integer + format: int16 -+ id: -+ type: string ++ pci_device_id: ++ type: integer ++ format: uint8 + PmemConfig: required: - file diff --git a/vmm/src/config.rs b/vmm/src/config.rs -index 78d6f9f1e..e1a54b0fa 100644 +index 00bf251..906410b 100644 --- a/vmm/src/config.rs +++ b/vmm/src/config.rs -@@ -45,6 +45,9 @@ pub enum Error { - /// Filesystem socket is missing - #[error("Error parsing --fs: socket missing")] - ParseFsSockMissing, -+ /// GPU socket is missing -+ #[error("Error parsing --gpu: socket missing")] -+ ParseGpuSockMissing, - /// Missing persistent memory file parameter. - #[error("Error parsing --pmem: file missing")] - ParsePmemFileMissing, -@@ -90,6 +93,9 @@ pub enum Error { +@@ -122,6 +122,12 @@ pub enum Error { /// Error parsing filesystem parameters #[error("Error parsing --fs")] ParseFileSystem(#[source] OptionParserError), + /// Error parsing GPU parameters + #[error("Error parsing --gpu")] + ParseGpu(#[source] OptionParserError), ++ /// GPU socket is missing ++ #[error("Error parsing --gpu: socket missing")] ++ ParseGpuSockMissing, /// Error parsing persistent memory parameters #[error("Error parsing --pmem")] ParsePersistentMemory(#[source] OptionParserError), -@@ -390,6 +396,7 @@ pub struct VmParams<'a> { - pub rng: &'a str, +@@ -460,6 +466,7 @@ pub struct VmParams<'a> { pub balloon: Option<&'a str>, pub fs: Option>, + pub generic_vhost_user: Option>, + pub gpu: Option>, pub pmem: Option>, pub serial: &'a str, pub console: &'a str, -@@ -451,6 +458,9 @@ impl<'a> VmParams<'a> { - let fs: Option> = args - .get_many::("fs") +@@ -524,6 +531,9 @@ impl<'a> VmParams<'a> { + let generic_vhost_user: Option> = args + .get_many::("generic-vhost-user") .map(|x| x.map(|y| y as &str).collect()); + let gpu: Option> = args + .get_many::("gpu") @@ -1044,65 +1036,45 @@ index 78d6f9f1e..e1a54b0fa 100644 let pmem: Option> = args .get_many::("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=,id=,pci_segment=\""; ++ \"socket=,id=,pci_segment=,pci_device_id=\""; + + pub fn parse(gpu: &str) -> Result { + 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=,size=,iommu=on|off,\ -@@ -2624,6 +2678,17 @@ impl VmConfig { +@@ -3041,6 +3075,17 @@ impl VmConfig { } } @@ -1113,15 +1085,15 @@ index 78d6f9f1e..e1a54b0fa 100644 + for gpu in gpus { + gpu.validate(self)?; + -+ Self::validate_identifier(&mut id_list, &gpu.id)?; ++ Self::validate_identifier(&mut id_list, &gpu.pci_common.id)?; + } + } + if let Some(pmems) = &self.pmem { for pmem in pmems { pmem.validate(self)?; -@@ -2876,6 +2941,15 @@ impl VmConfig { - fs = Some(fs_config_list); +@@ -3318,6 +3363,15 @@ impl VmConfig { + generic_vhost_user = Some(generic_vhost_user_config_list); } + let mut gpu: Option> = None; @@ -1136,77 +1108,53 @@ index 78d6f9f1e..e1a54b0fa 100644 let mut pmem: Option> = None; if let Some(pmem_list) = &vm_params.pmem { let mut pmem_config_list = Vec::new(); -@@ -3012,6 +3086,7 @@ impl VmConfig { - rng, +@@ -3455,6 +3509,7 @@ impl VmConfig { balloon, + generic_vhost_user, fs, + gpu, pmem, serial, console, -@@ -3073,6 +3148,13 @@ impl VmConfig { - removed |= fs.len() != len; +@@ -3524,6 +3579,13 @@ impl VmConfig { + removed |= generic_vhost_user.len() != len; } + // Remove if gpu device + if let Some(gpu) = self.gpu.as_mut() { + let len = gpu.len(); -+ gpu.retain(|dev| dev.id.as_ref().map(|id| id.as_ref()) != Some(id)); ++ gpu.retain(|dev| dev.pci_common.id.as_ref().map(|id| id.as_ref()) != Some(id)); + removed |= gpu.len() != len; + } + // Remove if net device if let Some(net) = self.net.as_mut() { let len = net.len(); -@@ -3145,6 +3227,7 @@ impl Clone for VmConfig { - #[cfg(feature = "pvmemcontrol")] +@@ -3597,6 +3659,7 @@ impl Clone for VmConfig { pvmemcontrol: self.pvmemcontrol.clone(), fs: self.fs.clone(), + generic_vhost_user: self.generic_vhost_user.clone(), + gpu: self.gpu.clone(), pmem: self.pmem.clone(), serial: self.serial.clone(), console: self.console.clone(), -@@ -3665,6 +3748,23 @@ mod unit_tests { - Ok(()) - } - -+ fn gpu_fixture() -> GpuConfig { -+ GpuConfig { -+ socket: PathBuf::from("/tmp/sock"), -+ id: None, -+ pci_segment: 0, -+ } -+ } -+ -+ #[test] -+ fn test_parse_gpu() -> Result<()> { -+ // "socket" must be supplied -+ assert!(GpuConfig::parse("").is_err()); -+ assert_eq!(GpuConfig::parse("socket=/tmp/sock")?, gpu_fixture()); -+ -+ Ok(()) -+ } -+ - fn pmem_fixture() -> PmemConfig { - PmemConfig { - file: PathBuf::from("/tmp/pmem"), -@@ -3936,6 +4036,7 @@ mod unit_tests { - rng: RngConfig::default(), +@@ -4811,6 +4874,7 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}" + generic_vhost_user: None, balloon: None, fs: None, + gpu: None, pmem: None, - serial: default_serial(), - console: default_console(), -@@ -4138,6 +4239,7 @@ mod unit_tests { - }, + serial: SerialConfig::default(), + console: ConsoleConfig::default(), +@@ -5045,6 +5109,7 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}" balloon: None, fs: None, + generic_vhost_user: None, + gpu: None, pmem: None, - serial: ConsoleConfig { - file: None, -@@ -4334,6 +4436,13 @@ mod unit_tests { + serial: SerialConfig { + common: CommonConsoleConfig { +@@ -5354,6 +5419,13 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}" Err(ValidationError::VhostUserRequiresSharedMemory) ); @@ -1221,7 +1169,7 @@ index 78d6f9f1e..e1a54b0fa 100644 still_valid_config.memory.shared = true; still_valid_config.validate().unwrap(); diff --git a/vmm/src/device_manager.rs b/vmm/src/device_manager.rs -index 6d465047b..7eb1358e1 100644 +index e6902a4..4329af3 100644 --- a/vmm/src/device_manager.rs +++ b/vmm/src/device_manager.rs @@ -12,6 +12,7 @@ @@ -1232,40 +1180,41 @@ index 6d465047b..7eb1358e1 100644 use std::num::Wrapping; use std::os::unix::fs::OpenOptionsExt; use std::os::unix::io::{AsRawFd, FromRawFd}; -@@ -91,7 +92,7 @@ use virtio_devices::transport::{VirtioPciDevice, VirtioPciDeviceActivator, Virti +@@ -89,7 +90,7 @@ use virtio_devices::transport::{VirtioPciDevice, VirtioPciDeviceActivator, Virti use virtio_devices::vhost_user::VhostUserConfig; use virtio_devices::{ AccessPlatformMapping, ActivateError, Block, Endpoint, IommuMapping, VdpaDmaMapping, - VirtioMemMappingSource, + VirtioMemMappingSource, VirtioSharedMemory, VirtioSharedMemoryList, }; - use vm_allocator::{AddressAllocator, SystemAllocator}; + use vm_allocator::{AddressAllocator, InterruptAllocError, SystemAllocator}; use vm_device::dma_mapping::ExternalDmaMapping; -@@ -124,8 +125,8 @@ use crate::serial_manager::{Error as SerialManagerError, SerialManager}; +@@ -122,8 +123,9 @@ use crate::serial_manager::{Error as SerialManagerError, SerialManager}; use crate::vm_config::IvshmemConfig; use crate::vm_config::{ ConsoleOutputMode, DEFAULT_IOMMU_ADDRESS_WIDTH_BITS, DEFAULT_PCI_SEGMENT_APERTURE_WEIGHT, -- DeviceConfig, DiskConfig, FsConfig, NetConfig, PmemConfig, UserDeviceConfig, VdpaConfig, -- VhostMode, VmConfig, VsockConfig, -+ DeviceConfig, DiskConfig, FsConfig, GpuConfig, NetConfig, PmemConfig, UserDeviceConfig, -+ VdpaConfig, VhostMode, VmConfig, VsockConfig, +- DeviceConfig, DiskConfig, FsConfig, GenericVhostUserConfig, NetConfig, PciDeviceCommonConfig, +- PmemConfig, UserDeviceConfig, VdpaConfig, VhostMode, VmConfig, VsockConfig, ++ DeviceConfig, DiskConfig, FsConfig, GenericVhostUserConfig, GpuConfig, NetConfig, ++ PciDeviceCommonConfig, PmemConfig, UserDeviceConfig, VdpaConfig, VhostMode, VmConfig, ++ VsockConfig, }; use crate::{DEVICE_MANAGER_SNAPSHOT_ID, GuestRegionMmap, PciDeviceInfo, device_node}; -@@ -154,6 +155,7 @@ const IVSHMEM_DEVICE_NAME: &str = "__ivshmem"; - // identifiers if the user doesn't give one - const DISK_DEVICE_NAME_PREFIX: &str = "_disk"; +@@ -154,6 +156,7 @@ const DISK_DEVICE_NAME_PREFIX: &str = "_disk"; const FS_DEVICE_NAME_PREFIX: &str = "_fs"; -+const GPU_DEVICE_NAME_PREFIX: &str = "_gpu"; const NET_DEVICE_NAME_PREFIX: &str = "_net"; + const GENERIC_VHOST_USER_DEVICE_NAME_PREFIX: &str = "_generic_vhost_user"; ++const GPU_DEVICE_NAME_PREFIX: &str = "_gpu"; const PMEM_DEVICE_NAME_PREFIX: &str = "_pmem"; const VDPA_DEVICE_NAME_PREFIX: &str = "_vdpa"; -@@ -198,10 +200,18 @@ pub enum DeviceManagerError { + const VSOCK_DEVICE_NAME_PREFIX: &str = "_vsock"; +@@ -201,10 +204,18 @@ pub enum DeviceManagerError { #[error("Cannot create virtio-fs device")] CreateVirtioFs(#[source] virtio_devices::vhost_user::Error), + /// Cannot create virtio-gpu device -+ #[error("Cannot create virtio-gpu device: {0}")] ++ #[error("Cannot create virtio-gpu device")] + CreateVirtioGpu(#[source] virtio_devices::vhost_user::Error), + /// Virtio-fs device was created without a socket. @@ -1276,10 +1225,10 @@ index 6d465047b..7eb1358e1 100644 + #[error("Virtio-gpu device was created without a socket")] + NoVirtioGpuSock, + - /// Cannot create vhost-user-blk device - #[error("Cannot create vhost-user-blk device")] - CreateVhostUserBlk(#[source] virtio_devices::vhost_user::Error), -@@ -319,6 +329,10 @@ pub enum DeviceManagerError { + /// Generic vhost-user device was created without a socket. + #[error("Generic vhost-user device was created without a socket")] + NoGenericVhostUserSock, +@@ -318,6 +329,10 @@ pub enum DeviceManagerError { #[error("Cannot find a memory range for virtio-fs")] FsRangeAllocation, @@ -1290,7 +1239,7 @@ index 6d465047b..7eb1358e1 100644 /// Error creating serial output file #[error("Error creating serial output file")] SerialOutputFileOpen(#[source] io::Error), -@@ -2537,6 +2551,9 @@ impl DeviceManager { +@@ -2630,6 +2645,9 @@ impl DeviceManager { // Add virtio-fs if required self.make_virtio_fs_devices()?; @@ -1300,7 +1249,7 @@ index 6d465047b..7eb1358e1 100644 // Add virtio-pmem if required self.make_virtio_pmem_devices()?; -@@ -3117,6 +3134,119 @@ impl DeviceManager { +@@ -3234,6 +3252,129 @@ impl DeviceManager { Ok(()) } @@ -1308,12 +1257,13 @@ index 6d465047b..7eb1358e1 100644 + &mut self, + gpu_cfg: &mut GpuConfig, + ) -> DeviceManagerResult { -+ let id = if let Some(id) = &gpu_cfg.id { -+ id.clone() -+ } else { -+ let id = self.next_device_name(GPU_DEVICE_NAME_PREFIX)?; -+ gpu_cfg.id = Some(id.clone()); -+ id ++ let id = match gpu_cfg.pci_common.id.as_ref() { ++ Some(id) => id.clone(), ++ None => gpu_cfg ++ .pci_common ++ .id ++ .insert(self.next_device_name(GPU_DEVICE_NAME_PREFIX)?) ++ .clone(), + }; + + info!("Creating virtio-gpu device: {gpu_cfg:?}"); @@ -1321,35 +1271,46 @@ index 6d465047b..7eb1358e1 100644 + let mut node = device_node!(id); + + if let Some(gpu_socket) = gpu_cfg.socket.to_str() { -+ let (mut virtio_gpu_device, region) = virtio_devices::vhost_user::Gpu::new( ++ let (mut virtio_gpu_device, shmem_config) = virtio_devices::vhost_user::Gpu::new( + id.clone(), + gpu_socket, + self.seccomp_action.clone(), + self.exit_evt + .try_clone() + .map_err(DeviceManagerError::EventFd)?, -+ self.force_iommu, ++ self.force_access_platform | gpu_cfg.pci_common.iommu, + ) + .map_err(DeviceManagerError::CreateVirtioGpu)?; + ++ let (shm_id, shm_len) = shmem_config ++ .memory_sizes ++ .iter() ++ .copied() ++ .enumerate() ++ .find(|(_, len)| *len != 0) ++ .ok_or(DeviceManagerError::CreateVirtioGpu( ++ virtio_devices::vhost_user::Error::VhostUserInvalidSharedMemoryRegion, ++ ))?; ++ let shm_id = shm_id as u8; ++ + // In crosvm, the 8 GiB bar is 8 GiB-aligned. -+ let cache_base = self.pci_segments[gpu_cfg.pci_segment as usize] ++ let cache_base = self.pci_segments[gpu_cfg.pci_common.pci_segment as usize] + .mem64_allocator + .lock() + .unwrap() -+ .allocate(None, region.length as GuestUsize, Some(region.length)) ++ .allocate(None, shm_len as GuestUsize, Some(shm_len)) + .ok_or(DeviceManagerError::GpuRangeAllocation)? + .raw_value(); + + // Update the node with correct resource information. + node.resources.push(Resource::MmioAddressRange { + base: cache_base, -+ size: region.length, ++ size: shm_len, + }); + + let mmap_region = MmapRegion::build( + None, -+ region.length as usize, ++ shm_len as usize, + libc::PROT_NONE, + libc::MAP_ANONYMOUS | libc::MAP_PRIVATE, + ) @@ -1374,10 +1335,10 @@ index 6d465047b..7eb1358e1 100644 + }; + + let region_list = once(( -+ region.id, ++ shm_id, + VirtioSharedMemory { + offset: 0, -+ len: region.length, ++ len: shm_len, + }, + )) + .collect(); @@ -1394,9 +1355,7 @@ index 6d465047b..7eb1358e1 100644 + Ok(MetaVirtioDevice { + virtio_device: Arc::new(Mutex::new(virtio_gpu_device)) + as Arc>, -+ iommu: false, -+ id, -+ pci_segment: gpu_cfg.pci_segment, ++ pci_common: gpu_cfg.pci_common.clone(), + dma_handler: None, + }) + } else { @@ -1420,7 +1379,7 @@ index 6d465047b..7eb1358e1 100644 fn make_virtio_pmem_device( &mut self, pmem_cfg: &mut PmemConfig, -@@ -4541,6 +4671,7 @@ impl DeviceManager { +@@ -4765,6 +4898,7 @@ impl DeviceManager { VirtioDeviceType::Block | VirtioDeviceType::Pmem | VirtioDeviceType::Fs @@ -1428,36 +1387,34 @@ index 6d465047b..7eb1358e1 100644 | VirtioDeviceType::Vsock => {} _ => return Err(DeviceManagerError::RemovalNotAllowed(device_type)), } -@@ -4827,6 +4958,13 @@ impl DeviceManager { +@@ -5086,6 +5220,13 @@ impl DeviceManager { self.hotplug_virtio_pci_device(device) } + pub fn add_gpu(&mut self, gpu_cfg: &mut GpuConfig) -> DeviceManagerResult { -+ 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 { - self.validate_identifier(&pmem_cfg.id)?; + self.validate_identifier(&pmem_cfg.pci_common.id)?; diff --git a/vmm/src/lib.rs b/vmm/src/lib.rs -index 6917e005e..5a3db353a 100644 +index 6c9d476..d0e1c33 100644 --- a/vmm/src/lib.rs +++ b/vmm/src/lib.rs -@@ -59,8 +59,8 @@ use crate::migration::{recv_vm_config, recv_vm_state}; +@@ -65,7 +65,7 @@ use crate::migration_transport::{ use crate::seccomp_filters::{Thread, get_seccomp_filter}; use crate::vm::{Error as VmError, Vm, VmState}; use crate::vm_config::{ -- DeviceConfig, DiskConfig, FsConfig, NetConfig, PmemConfig, UserDeviceConfig, VdpaConfig, -- VmConfig, VsockConfig, -+ DeviceConfig, DiskConfig, FsConfig, GpuConfig, NetConfig, PmemConfig, UserDeviceConfig, -+ VdpaConfig, VmConfig, VsockConfig, +- DeviceConfig, DiskConfig, FsConfig, GenericVhostUserConfig, NetConfig, PmemConfig, ++ DeviceConfig, DiskConfig, FsConfig, GenericVhostUserConfig, GpuConfig, NetConfig, PmemConfig, + UserDeviceConfig, VdpaConfig, VmConfig, VsockConfig, }; - mod acpi; -@@ -2120,6 +2120,31 @@ impl RequestHandler for Vmm { +@@ -2365,6 +2365,31 @@ impl RequestHandler for Vmm { } } @@ -1489,15 +1446,15 @@ index 6917e005e..5a3db353a 100644 fn vm_add_pmem(&mut self, pmem_cfg: PmemConfig) -> result::Result>, VmError> { self.vm_config.as_ref().ok_or(VmError::VmNotCreated)?; -@@ -2438,6 +2463,7 @@ mod unit_tests { - }, +@@ -2722,6 +2747,7 @@ mod unit_tests { balloon: None, fs: None, + generic_vhost_user: None, + gpu: None, pmem: None, - serial: ConsoleConfig { - file: None, -@@ -2674,6 +2700,55 @@ mod unit_tests { + serial: SerialConfig { + common: CommonConsoleConfig { +@@ -3014,6 +3040,55 @@ mod unit_tests { ); } @@ -1554,21 +1511,19 @@ index 6917e005e..5a3db353a 100644 fn test_vmm_vm_cold_add_pmem() { let mut vmm = create_dummy_vmm(); diff --git a/vmm/src/vm.rs b/vmm/src/vm.rs -index 536481885..d2e5de0fe 100644 +index 1c3baf8..ae5a2e8 100644 --- a/vmm/src/vm.rs +++ b/vmm/src/vm.rs -@@ -100,8 +100,8 @@ use crate::migration::{SNAPSHOT_CONFIG_FILE, SNAPSHOT_STATE_FILE, url_to_path}; +@@ -115,7 +115,7 @@ use crate::sev::MeasuredBootInfo; #[cfg(feature = "fw_cfg")] use crate::vm_config::FwCfgConfig; use crate::vm_config::{ -- DeviceConfig, DiskConfig, FsConfig, HotplugMethod, NetConfig, NumaConfig, PayloadConfig, -- PmemConfig, UserDeviceConfig, VdpaConfig, VmConfig, VsockConfig, -+ DeviceConfig, DiskConfig, FsConfig, GpuConfig, HotplugMethod, NetConfig, NumaConfig, -+ PayloadConfig, PmemConfig, UserDeviceConfig, VdpaConfig, VmConfig, VsockConfig, +- DeviceConfig, DiskConfig, FsConfig, GenericVhostUserConfig, HotplugMethod, NetConfig, ++ DeviceConfig, DiskConfig, FsConfig, GenericVhostUserConfig, GpuConfig, HotplugMethod, NetConfig, + NumaConfig, PayloadConfig, PmemConfig, UserDeviceConfig, VdpaConfig, VmConfig, VsockConfig, }; use crate::{ - CPU_MANAGER_SNAPSHOT_ID, DEVICE_MANAGER_SNAPSHOT_ID, GuestMemoryMmap, -@@ -1869,6 +1869,30 @@ impl Vm { +@@ -2348,6 +2348,30 @@ impl Vm { Ok(pci_device_info) } @@ -1600,33 +1555,30 @@ index 536481885..d2e5de0fe 100644 let pci_device_info = self .device_manager diff --git a/vmm/src/vm_config.rs b/vmm/src/vm_config.rs -index 9c28e536d..f21974ac2 100644 +index 6fefc8f..3834d1e 100644 --- a/vmm/src/vm_config.rs +++ b/vmm/src/vm_config.rs -@@ -461,6 +461,15 @@ impl ApplyLandlock for FsConfig { - } +@@ -485,6 +485,13 @@ pub struct FsConfig { + pub queue_size: u16, } +#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] +pub struct GpuConfig { ++ #[serde(flatten)] ++ pub pci_common: PciDeviceCommonConfig, + pub socket: PathBuf, -+ #[serde(default)] -+ pub id: Option, -+ #[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, + pub generic_vhost_user: Option>, pub fs: Option>, + pub gpu: Option>, pub pmem: Option>, - #[serde(default = "default_serial")] - pub serial: ConsoleConfig, + #[serde(default)] + pub serial: SerialConfig, -- -2.53.0 - +2.54.0 diff --git a/pkgs/cloud-hypervisor/default.nix b/pkgs/cloud-hypervisor/default.nix index ee5a7ea..f43b080 100644 --- a/pkgs/cloud-hypervisor/default.nix +++ b/pkgs/cloud-hypervisor/default.nix @@ -5,21 +5,77 @@ import ../../lib/overlay-package.nix [ "cloud-hypervisor" ] ({ final, super }: super.cloud-hypervisor.overrideAttrs (oldAttrs: rec { - cargoDeps = final.rustPlatform.fetchCargoVendor { - inherit patches; - inherit (oldAttrs) src; - hash = "sha256-wGtsyKDg1z1QK9mJ1Q43NSjoPbm3m81p++DoD8ipIUI="; + version = "52.0"; + + src = final.fetchFromGitHub { + owner = "cloud-hypervisor"; + repo = "cloud-hypervisor"; + rev = "v${version}"; + hash = "sha256-OGyvmedSaWPsyH6mdHhgXN7MvTnK1HzdfTKUhJRlq8I="; + }; + + cargoDeps = final.stdenvNoCC.mkDerivation { + name = "cloud-hypervisor-${version}-vendor"; + inherit src patches vhost vhostPatches; + + nativeBuildInputs = [ + final.cacert + final.cargo + final.git + ]; + + outputHashMode = "recursive"; + outputHashAlgo = "sha256"; + outputHash = "sha256-DD0Mobe/mnsGb7xHKUFfdk/5VXvp8mZbfuRymtNvZLg="; + dontFixup = true; + + postUnpack = '' + unpackFile $vhost + chmod -R +w vhost + ''; + + postPatch = '' + pushd ../vhost + for patch in $vhostPatches; do + echo applying patch $patch + patch -p1 < $patch + done + popd + ''; + + buildPhase = '' + runHook preBuild + + export CARGO_HOME=$TMPDIR/cargo-home + mkdir -p .cargo + cargo vendor vendor > .cargo/config.toml + substituteInPlace .cargo/config.toml \ + --replace-fail 'directory = "vendor"' 'directory = "@vendor@/vendor"' + + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + + mkdir -p $out + cp Cargo.lock $out/Cargo.lock + cp -R vendor $out/vendor + cp -R .cargo $out/.cargo + + runHook postInstall + ''; }; vhost = final.fetchFromGitHub { name = "vhost"; owner = "rust-vmm"; repo = "vhost"; - rev = "vhost-user-backend-v0.20.0"; - hash = "sha256-KK1+mwYQr7YkyGT9+51v7TJael9D0lle2JXfRoTqYq8="; + rev = "vhost-user-backend-v0.22.0"; + hash = "sha256-UzzwLi4O6rWuIJuGU0C0+tzJ7NZrgRamt/iYereRHZU="; }; - patches = oldAttrs.patches or [] ++ [ + patches = (oldAttrs.patches or []) ++ [ ./0001-build-use-local-vhost.patch ./0002-virtio-devices-add-a-GPU-device.patch ]; @@ -27,16 +83,15 @@ super.cloud-hypervisor.overrideAttrs (oldAttrs: rec { vhostPatches = [ vhost/0001-vhost_user-add-get_size-to-MsgHeader.patch vhost/0002-vhost-fix-receiving-reply-payloads.patch - vhost/0003-vhost_user-add-shared-memory-region-support.patch - vhost/0004-vhost_user-add-protocol-flag-for-shmem.patch + vhost/0003-vhost_user-add-crosvm-shmem-map-compat.patch ]; - postUnpack = oldAttrs.postUnpack or "" + '' + postUnpack = (oldAttrs.postUnpack or "") + '' unpackFile $vhost chmod -R +w vhost ''; - postPatch = oldAttrs.postPatch or "" + '' + postPatch = (oldAttrs.postPatch or "") + '' pushd ../vhost for patch in $vhostPatches; do echo applying patch $patch diff --git a/pkgs/cloud-hypervisor/vhost/0003-vhost_user-add-crosvm-shmem-map-compat.patch b/pkgs/cloud-hypervisor/vhost/0003-vhost_user-add-crosvm-shmem-map-compat.patch new file mode 100644 index 0000000..2a846bf --- /dev/null +++ b/pkgs/cloud-hypervisor/vhost/0003-vhost_user-add-crosvm-shmem-map-compat.patch @@ -0,0 +1,79 @@ +From 4f0849043c9ef8d683f257f34e590a6842d7355c Mon Sep 17 00:00:00 2001 +From: Colby Townsend +Date: Fri, 26 Jun 2026 04:01:00 -0700 +Subject: [PATCH] vhost_user: add crosvm SHMEM_MAP compatibility +SPDX-License-Identifier: Apache-2.0 + +crosvm's vhost-user GPU backend advertises the shared-memory mapping +protocol bit as SHMEM_MAP at 0x0010_0000. rust-vmm/vhost 0.16 uses +SHMEM at 0x0020_0000 for the same GET_SHMEM_CONFIG and SHMEM_MAP/ +SHMEM_UNMAP flow. + +Accept either bit when checking local state, and expose the crosvm bit +name so frontends can negotiate with crosvm without sending an +unsupported protocol feature. + +Signed-off-by: Colby Townsend +--- + vhost-user-backend/src/handler.rs | 4 +++- + vhost/src/vhost_user/backend_req_handler.rs | 4 +++- + vhost/src/vhost_user/frontend.rs | 4 +++- + vhost/src/vhost_user/message.rs | 2 ++ + 4 files changed, 11 insertions(+), 3 deletions(-) + +diff --git a/vhost-user-backend/src/handler.rs b/vhost-user-backend/src/handler.rs +index ea1fd6942..465dc2757 100644 +--- a/vhost-user-backend/src/handler.rs ++++ b/vhost-user-backend/src/handler.rs +@@ -571,7 +571,9 @@ where + if self.acked_protocol_features & VhostUserProtocolFeatures::SHARED_OBJECT.bits() != 0 { + backend.set_shared_object_flag(true); + } +- if self.acked_protocol_features & VhostUserProtocolFeatures::SHMEM.bits() != 0 { ++ let shmem_features = VhostUserProtocolFeatures::SHMEM ++ | VhostUserProtocolFeatures::SHMEM_MAP; ++ if self.acked_protocol_features & shmem_features.bits() != 0 { + backend.set_shmem_flag(true); + } + self.backend.set_backend_req_fd(backend); +diff --git a/vhost/src/vhost_user/backend_req_handler.rs b/vhost/src/vhost_user/backend_req_handler.rs +index d74b04558..fbe750c15 100644 +--- a/vhost/src/vhost_user/backend_req_handler.rs ++++ b/vhost/src/vhost_user/backend_req_handler.rs +@@ -686,7 +686,9 @@ impl BackendReqHandler { + self.send_reply_message(&hdr, &msg)?; + } + Ok(FrontendReq::GET_SHMEM_CONFIG) => { +- self.check_proto_feature(VhostUserProtocolFeatures::SHMEM)?; ++ self.check_proto_feature( ++ VhostUserProtocolFeatures::SHMEM | VhostUserProtocolFeatures::SHMEM_MAP, ++ )?; + let msg = self.backend.get_shmem_config()?; + self.send_reply_message(&hdr, &msg)?; + } +diff --git a/vhost/src/vhost_user/frontend.rs b/vhost/src/vhost_user/frontend.rs +index 195a6af1e..037f1b7f3 100644 +--- a/vhost/src/vhost_user/frontend.rs ++++ b/vhost/src/vhost_user/frontend.rs +@@ -590,3 +590,5 @@ impl VhostUserFrontend for Frontend { + let mut node = self.node(); +- node.check_proto_feature(VhostUserProtocolFeatures::SHMEM)?; ++ node.check_proto_feature( ++ VhostUserProtocolFeatures::SHMEM | VhostUserProtocolFeatures::SHMEM_MAP, ++ )?; + +diff --git a/vhost/src/vhost_user/message.rs b/vhost/src/vhost_user/message.rs +index 5826d19a6..006f2e0fe 100644 +--- a/vhost/src/vhost_user/message.rs ++++ b/vhost/src/vhost_user/message.rs +@@ -441,6 +441,8 @@ bitflags! { + const DEVICE_STATE = 0x0008_0000; + /// Support suspend in-flight I/O requests and record them + const GET_VRING_BASE_INFLIGHT = 0x0010_0000; ++ /// crosvm name for the shared-memory mapping protocol bit. ++ const SHMEM_MAP = 0x0010_0000; + /// Allow the backend to request file descriptors be mapped into virtio shared memory + /// regions. + const SHMEM = 0x0020_0000; +-- +2.50.0 -- 2.54.0