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