1pub mod async_utils;
8#[cfg(feature = "balloon")]
9mod balloon;
10mod descriptor_chain;
11mod descriptor_utils;
12pub mod device_constants;
13pub mod input;
14mod interrupt;
15mod iommu;
16#[cfg(feature = "pvclock")]
17pub mod pvclock;
18mod queue;
19#[cfg(any(feature = "video-decoder", feature = "video-encoder"))]
20mod video;
21mod virtio_device;
22mod virtio_mmio_device;
23mod virtio_pci_common_config;
24mod virtio_pci_device;
25
26#[cfg(feature = "gpu")]
27pub mod gpu;
28#[cfg(all(unix, feature = "media"))]
29pub mod media;
30pub mod resource_bridge;
31pub mod vhost;
32pub mod vhost_user_backend;
33pub mod vhost_user_frontend;
34
35pub use vmm_vhost::SharedMemoryRegion;
36
37#[cfg(feature = "balloon")]
38pub use self::balloon::Balloon;
39#[cfg(feature = "balloon")]
40pub use self::balloon::BalloonFeatures;
41pub use self::descriptor_chain::DescriptorChain;
42pub use self::descriptor_chain::DescriptorChainIter;
43pub use self::descriptor_utils::create_descriptor_chain;
44pub use self::descriptor_utils::DescriptorType;
45pub use self::descriptor_utils::Reader;
46pub use self::descriptor_utils::Writer;
47#[cfg(feature = "gpu")]
48pub use self::gpu::DisplayBackend;
49#[cfg(feature = "gpu")]
50pub use self::gpu::Gpu;
51#[cfg(feature = "gpu")]
52pub use self::gpu::GpuDisplayMode;
53#[cfg(feature = "gpu")]
54pub use self::gpu::GpuDisplayParameters;
55#[cfg(feature = "gpu")]
56pub use self::gpu::GpuMode;
57#[cfg(feature = "gpu")]
58pub use self::gpu::GpuMouseMode;
59#[cfg(feature = "gpu")]
60pub use self::gpu::GpuParameters;
61#[cfg(feature = "gpu")]
62pub use self::gpu::GpuWsi;
63pub use self::interrupt::Interrupt;
64pub use self::interrupt::InterruptSnapshot;
65pub use self::iommu::ipc_memory_mapper;
66pub use self::iommu::memory_mapper;
67pub use self::iommu::Iommu;
68pub use self::iommu::IommuError;
69pub use self::queue::split_descriptor_chain::Desc;
70pub use self::queue::split_descriptor_chain::SplitDescriptorChain;
71pub use self::queue::PeekedDescriptorChain;
72pub use self::queue::Queue;
73pub use self::queue::QueueConfig;
74pub use self::vhost_user_frontend::VhostUserFrontend;
75#[cfg(any(feature = "video-decoder", feature = "video-encoder"))]
76pub use self::video::VideoDevice;
77pub use self::virtio_device::SharedMemoryMapper;
78pub use self::virtio_device::SharedMemoryPrepareType;
79pub use self::virtio_device::VirtioDevice;
80pub use self::virtio_mmio_device::VirtioMmioDevice;
81pub use self::virtio_pci_device::PciCapabilityType;
82pub use self::virtio_pci_device::VirtioPciCap;
83pub use self::virtio_pci_device::VirtioPciDevice;
84pub use self::virtio_pci_device::VirtioPciShmCap;
85#[cfg(feature = "pvclock")]
86pub use self::DeviceType::Pvclock;
87
88cfg_if::cfg_if! {
89 if #[cfg(any(target_os = "android", target_os = "linux"))] {
90 mod p9;
91 mod pmem;
92
93 #[cfg(feature = "virtio_wl")]
94 pub mod wl;
95 pub mod fs;
96
97 pub use self::iommu::sys::linux::vfio_wrapper;
98 pub use self::p9::P9;
99 pub use self::pmem::Pmem;
100 pub use self::pmem::PmemConfig;
101 pub use self::pmem::MemSlotConfig;
102 #[cfg(feature = "virtio_wl")]
103 pub use self::wl::Wl;
104 } else if #[cfg(windows)] {
105 } else {
106 compile_error!("Unsupported platform");
107 }
108}
109
110use std::cmp;
111use std::convert::TryFrom;
112
113use futures::channel::oneshot;
114use hypervisor::ProtectionType;
115use serde::Deserialize;
116use serde::Serialize;
117use virtio_sys::virtio_config::VIRTIO_F_ACCESS_PLATFORM;
118use virtio_sys::virtio_config::VIRTIO_F_SUSPEND;
119use virtio_sys::virtio_config::VIRTIO_F_VERSION_1;
120use virtio_sys::virtio_ids;
121use virtio_sys::virtio_ring::VIRTIO_RING_F_EVENT_IDX;
122
123const DEVICE_RESET: u32 = 0x0;
124
125const INTERRUPT_STATUS_USED_RING: u32 = 0x1;
126pub const INTERRUPT_STATUS_CONFIG_CHANGED: u32 = 0x2;
127
128const VIRTIO_MSI_NO_VECTOR: u16 = 0xffff;
129
130#[derive(Copy, Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
131#[serde(rename_all = "kebab-case")]
132pub enum DeviceType {
133 Net,
134 Block,
135 Console,
136 Rng,
137 Balloon,
138 Scsi,
139 #[serde(rename = "9p")]
140 P9,
141 Gpu,
142 Input,
143 Vsock,
144 Iommu,
145 Sound,
146 Fs,
147 Pmem,
148 #[serde(rename = "mac80211-hwsim")]
149 Mac80211HwSim,
150 VideoEncoder,
151 VideoDecoder,
152 Scmi,
153 Wl,
154 Tpm,
155 Pvclock,
156 Media,
157 VendorDevice(u32),
158}
159
160impl DeviceType {
161 fn virtio_id(&self) -> u32 {
165 match self {
166 DeviceType::Net => virtio_ids::VIRTIO_ID_NET,
167 DeviceType::Block => virtio_ids::VIRTIO_ID_BLOCK,
168 DeviceType::Console => virtio_ids::VIRTIO_ID_CONSOLE,
169 DeviceType::Rng => virtio_ids::VIRTIO_ID_RNG,
170 DeviceType::Balloon => virtio_ids::VIRTIO_ID_BALLOON,
171 DeviceType::Scsi => virtio_ids::VIRTIO_ID_SCSI,
172 DeviceType::P9 => virtio_ids::VIRTIO_ID_9P,
173 DeviceType::Gpu => virtio_ids::VIRTIO_ID_GPU,
174 DeviceType::Input => virtio_ids::VIRTIO_ID_INPUT,
175 DeviceType::Vsock => virtio_ids::VIRTIO_ID_VSOCK,
176 DeviceType::Iommu => virtio_ids::VIRTIO_ID_IOMMU,
177 DeviceType::Sound => virtio_ids::VIRTIO_ID_SOUND,
178 DeviceType::Fs => virtio_ids::VIRTIO_ID_FS,
179 DeviceType::Pmem => virtio_ids::VIRTIO_ID_PMEM,
180 DeviceType::Mac80211HwSim => virtio_ids::VIRTIO_ID_MAC80211_HWSIM,
181 DeviceType::VideoEncoder => virtio_ids::VIRTIO_ID_VIDEO_ENCODER,
182 DeviceType::VideoDecoder => virtio_ids::VIRTIO_ID_VIDEO_DECODER,
183 DeviceType::Scmi => virtio_ids::VIRTIO_ID_SCMI,
184 DeviceType::Wl => virtio_ids::VIRTIO_ID_WL,
185 DeviceType::Tpm => virtio_ids::VIRTIO_ID_TPM,
186 DeviceType::Pvclock => virtio_ids::VIRTIO_ID_PVCLOCK,
187 DeviceType::Media => virtio_ids::VIRTIO_ID_MEDIA,
188 DeviceType::VendorDevice(id) => *id,
189 }
190 }
191
192 pub fn min_queues(&self) -> usize {
197 match self {
198 DeviceType::Net => 3, DeviceType::Block => 1, DeviceType::Console => 2, DeviceType::Rng => 1, DeviceType::Balloon => 2, DeviceType::Scsi => 3, DeviceType::P9 => 1, DeviceType::Gpu => 2, DeviceType::Input => 2, DeviceType::Vsock => 3, DeviceType::Iommu => 2, DeviceType::Sound => 4, DeviceType::Fs => 2, DeviceType::Pmem => 1, DeviceType::Mac80211HwSim => 2, DeviceType::VideoEncoder => 2, DeviceType::VideoDecoder => 2, DeviceType::Scmi => 2, DeviceType::Wl => 2, DeviceType::Tpm => 1, DeviceType::Pvclock => 1, DeviceType::Media => 2, DeviceType::VendorDevice(_) => unimplemented!("vhost-user frontend is not supported"),
221 }
222 }
223}
224
225impl From<DeviceType> for u32 {
226 fn from(val: DeviceType) -> Self {
227 val.virtio_id()
228 }
229}
230
231impl std::fmt::Display for DeviceType {
233 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
234 match &self {
235 DeviceType::Net => write!(f, "net"),
236 DeviceType::Block => write!(f, "block"),
237 DeviceType::Console => write!(f, "console"),
238 DeviceType::Rng => write!(f, "rng"),
239 DeviceType::Balloon => write!(f, "balloon"),
240 DeviceType::Scsi => write!(f, "scsi"),
241 DeviceType::P9 => write!(f, "9p"),
242 DeviceType::Input => write!(f, "input"),
243 DeviceType::Gpu => write!(f, "gpu"),
244 DeviceType::Vsock => write!(f, "vsock"),
245 DeviceType::Iommu => write!(f, "iommu"),
246 DeviceType::Sound => write!(f, "sound"),
247 DeviceType::Fs => write!(f, "fs"),
248 DeviceType::Pmem => write!(f, "pmem"),
249 DeviceType::Wl => write!(f, "wl"),
250 DeviceType::Tpm => write!(f, "tpm"),
251 DeviceType::Pvclock => write!(f, "pvclock"),
252 DeviceType::VideoDecoder => write!(f, "video-decoder"),
253 DeviceType::VideoEncoder => write!(f, "video-encoder"),
254 DeviceType::Mac80211HwSim => write!(f, "mac80211-hwsim"),
255 DeviceType::Scmi => write!(f, "scmi"),
256 DeviceType::Media => write!(f, "media"),
257 DeviceType::VendorDevice(id) => write!(f, "vendor-device-{}", id),
258 }
259 }
260}
261
262pub fn copy_config(dst: &mut [u8], dst_offset: u64, src: &[u8], src_offset: u64) {
272 if let Ok(dst_offset) = usize::try_from(dst_offset) {
273 if let Ok(src_offset) = usize::try_from(src_offset) {
274 if let Some(dst_slice) = dst.get_mut(dst_offset..) {
275 if let Some(src_slice) = src.get(src_offset..) {
276 let len = cmp::min(dst_slice.len(), src_slice.len());
277 let dst_subslice = &mut dst_slice[0..len];
278 let src_subslice = &src_slice[0..len];
279 dst_subslice.copy_from_slice(src_subslice);
280 }
281 }
282 }
283 }
284}
285
286pub fn base_features(protection_type: ProtectionType) -> u64 {
288 let mut features: u64 =
289 1 << VIRTIO_F_VERSION_1 | 1 << VIRTIO_RING_F_EVENT_IDX | 1 << VIRTIO_F_SUSPEND;
290
291 if protection_type != ProtectionType::Unprotected {
292 features |= 1 << VIRTIO_F_ACCESS_PLATFORM;
293 }
294
295 features
296}
297
298pub enum VirtioDeviceType {
303 Regular,
305 VhostUser,
307}
308
309impl VirtioDeviceType {
310 pub fn seccomp_policy_file(&self, base: &str) -> String {
313 match self {
314 VirtioDeviceType::Regular => format!("{base}_device"),
315 VirtioDeviceType::VhostUser => format!("{base}_device_vhost_user"),
316 }
317 }
318}
319
320pub fn create_stop_oneshot(tx_vec: &mut Vec<oneshot::Sender<()>>) -> oneshot::Receiver<()> {
324 let (stop_tx, stop_rx) = futures::channel::oneshot::channel();
325 tx_vec.push(stop_tx);
326 stop_rx
327}
328
329pub enum StoppedWorker<Q> {
332 WithQueues(Box<Q>),
334
335 AlreadyStopped,
337
338 MissingQueues,
342}