1 // Copyright 2017 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 //! Implements virtio devices, queues, and transport mechanisms.
6
7 mod async_device;
8 mod async_utils;
9 #[cfg(feature = "balloon")]
10 mod balloon;
11 mod descriptor_utils;
12 pub mod device_constants;
13 mod input;
14 mod interrupt;
15 mod iommu;
16 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
17 pub mod pvclock;
18 mod queue;
19 mod rng;
20 mod sys;
21 #[cfg(any(feature = "tpm", feature = "vtpm"))]
22 mod tpm;
23 #[cfg(any(feature = "video-decoder", feature = "video-encoder"))]
24 mod video;
25 mod virtio_device;
26 mod virtio_mmio_device;
27 mod virtio_pci_common_config;
28 mod virtio_pci_device;
29
30 pub mod block;
31 pub mod console;
32 #[cfg(feature = "gpu")]
33 pub mod gpu;
34 pub mod resource_bridge;
35 #[cfg(feature = "audio")]
36 pub mod snd;
37 pub mod vhost;
38 pub mod vsock;
39
40 #[cfg(feature = "balloon")]
41 pub use self::balloon::*;
42 pub use self::block::*;
43 pub use self::console::*;
44 pub use self::descriptor_utils::Error as DescriptorError;
45 pub use self::descriptor_utils::*;
46 #[cfg(feature = "gpu")]
47 pub use self::gpu::*;
48 pub use self::input::*;
49 pub use self::interrupt::*;
50 pub use self::iommu::*;
51 pub use self::queue::*;
52 pub use self::rng::*;
53 #[cfg(any(feature = "tpm", feature = "vtpm"))]
54 pub use self::tpm::*;
55 #[cfg(any(feature = "video-decoder", feature = "video-encoder"))]
56 pub use self::video::*;
57 pub use self::virtio_device::*;
58 pub use self::virtio_mmio_device::*;
59 pub use self::virtio_pci_device::*;
60 cfg_if::cfg_if! {
61 if #[cfg(unix)] {
62 mod p9;
63 mod pmem;
64
65 pub mod wl;
66 pub mod fs;
67 pub mod net;
68
69 pub use self::iommu::sys::unix::vfio_wrapper;
70 pub use self::net::*;
71 pub use self::p9::*;
72 pub use self::pmem::*;
73 #[cfg(feature = "audio")]
74 pub use self::snd::*;
75 pub use self::wl::*;
76
77 } else if #[cfg(windows)] {
78 #[cfg(feature = "slirp")]
79 pub mod net;
80
81 #[cfg(feature = "slirp")]
82 pub use self::net::*;
83 #[cfg(feature = "slirp")]
84 pub use self::sys::windows::NetExt;
85 pub use self::vsock::*;
86 } else {
87 compile_error!("Unsupported platform");
88 }
89 }
90 use std::cmp;
91 use std::convert::TryFrom;
92
93 use hypervisor::ProtectionType;
94 use virtio_sys::virtio_config::VIRTIO_F_ACCESS_PLATFORM;
95 use virtio_sys::virtio_config::VIRTIO_F_VERSION_1;
96 use virtio_sys::virtio_ids;
97 use virtio_sys::virtio_ring::VIRTIO_RING_F_EVENT_IDX;
98
99 const DEVICE_RESET: u32 = 0x0;
100
101 const INTERRUPT_STATUS_USED_RING: u32 = 0x1;
102 const INTERRUPT_STATUS_CONFIG_CHANGED: u32 = 0x2;
103
104 const VIRTIO_MSI_NO_VECTOR: u16 = 0xffff;
105
106 #[derive(Copy, Clone, Eq, PartialEq)]
107 #[repr(u32)]
108 pub enum DeviceType {
109 Net = virtio_ids::VIRTIO_ID_NET,
110 Block = virtio_ids::VIRTIO_ID_BLOCK,
111 Console = virtio_ids::VIRTIO_ID_CONSOLE,
112 Rng = virtio_ids::VIRTIO_ID_RNG,
113 Balloon = virtio_ids::VIRTIO_ID_BALLOON,
114 Rpmsg = virtio_ids::VIRTIO_ID_RPMSG,
115 Scsi = virtio_ids::VIRTIO_ID_SCSI,
116 P9 = virtio_ids::VIRTIO_ID_9P,
117 RprocSerial = virtio_ids::VIRTIO_ID_RPROC_SERIAL,
118 Caif = virtio_ids::VIRTIO_ID_CAIF,
119 Gpu = virtio_ids::VIRTIO_ID_GPU,
120 Input = virtio_ids::VIRTIO_ID_INPUT,
121 Vsock = virtio_ids::VIRTIO_ID_VSOCK,
122 Crypto = virtio_ids::VIRTIO_ID_CRYPTO,
123 Iommu = virtio_ids::VIRTIO_ID_IOMMU,
124 Sound = virtio_ids::VIRTIO_ID_SOUND,
125 Fs = virtio_ids::VIRTIO_ID_FS,
126 Pmem = virtio_ids::VIRTIO_ID_PMEM,
127 Mac80211HwSim = virtio_ids::VIRTIO_ID_MAC80211_HWSIM,
128 VideoEnc = virtio_ids::VIRTIO_ID_VIDEO_ENCODER,
129 VideoDec = virtio_ids::VIRTIO_ID_VIDEO_DECODER,
130 Wl = virtio_ids::VIRTIO_ID_WL,
131 Tpm = virtio_ids::VIRTIO_ID_TPM,
132 Pvclock = virtio_ids::VIRTIO_ID_PVCLOCK,
133 VhostUser = virtio_ids::VIRTIO_ID_VHOST_USER,
134 }
135
136 /// Prints a string representation of the given virtio device type.
137 impl std::fmt::Display for DeviceType {
fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result138 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
139 match &self {
140 DeviceType::Net => write!(f, "net"),
141 DeviceType::Block => write!(f, "block"),
142 DeviceType::Console => write!(f, "console"),
143 DeviceType::Rng => write!(f, "rng"),
144 DeviceType::Balloon => write!(f, "balloon"),
145 DeviceType::Rpmsg => write!(f, "rpmsg"),
146 DeviceType::Scsi => write!(f, "scsi"),
147 DeviceType::P9 => write!(f, "9p"),
148 DeviceType::RprocSerial => write!(f, "rproc-serial"),
149 DeviceType::Caif => write!(f, "caif"),
150 DeviceType::Input => write!(f, "input"),
151 DeviceType::Gpu => write!(f, "gpu"),
152 DeviceType::Vsock => write!(f, "vsock"),
153 DeviceType::Crypto => write!(f, "crypto"),
154 DeviceType::Iommu => write!(f, "iommu"),
155 DeviceType::VhostUser => write!(f, "vhost-user"),
156 DeviceType::Sound => write!(f, "snd"),
157 DeviceType::Fs => write!(f, "fs"),
158 DeviceType::Pmem => write!(f, "pmem"),
159 DeviceType::Wl => write!(f, "wl"),
160 DeviceType::Tpm => write!(f, "tpm"),
161 DeviceType::Pvclock => write!(f, "pvclock"),
162 DeviceType::VideoDec => write!(f, "video-decoder"),
163 DeviceType::VideoEnc => write!(f, "video-encoder"),
164 DeviceType::Mac80211HwSim => write!(f, "mac-80211-hw-sim"),
165 }
166 }
167 }
168
169 /// Copy virtio device configuration data from a subslice of `src` to a subslice of `dst`.
170 /// Unlike std::slice::copy_from_slice(), this function copies as much as possible within
171 /// the common subset of the two slices, truncating the requested range instead of
172 /// panicking if the slices do not match in size.
173 ///
174 /// `dst_offset` and `src_offset` specify the starting indexes of the `dst` and `src`
175 /// slices, respectively; if either index is out of bounds, this function is a no-op
176 /// rather than panicking. This makes it safe to call with arbitrary user-controlled
177 /// inputs.
copy_config(dst: &mut [u8], dst_offset: u64, src: &[u8], src_offset: u64)178 pub fn copy_config(dst: &mut [u8], dst_offset: u64, src: &[u8], src_offset: u64) {
179 if let Ok(dst_offset) = usize::try_from(dst_offset) {
180 if let Ok(src_offset) = usize::try_from(src_offset) {
181 if let Some(dst_slice) = dst.get_mut(dst_offset..) {
182 if let Some(src_slice) = src.get(src_offset..) {
183 let len = cmp::min(dst_slice.len(), src_slice.len());
184 let dst_subslice = &mut dst_slice[0..len];
185 let src_subslice = &src_slice[0..len];
186 dst_subslice.copy_from_slice(src_subslice);
187 }
188 }
189 }
190 }
191 }
192
193 /// Returns the set of reserved base features common to all virtio devices.
base_features(protection_type: ProtectionType) -> u64194 pub fn base_features(protection_type: ProtectionType) -> u64 {
195 let mut features: u64 = 1 << VIRTIO_F_VERSION_1 | 1 << VIRTIO_RING_F_EVENT_IDX;
196
197 if protection_type != ProtectionType::Unprotected {
198 features |= 1 << VIRTIO_F_ACCESS_PLATFORM;
199 }
200
201 features
202 }
203
204 /// Type of virtio transport.
205 ///
206 /// The virtio protocol can be transported by several means, which affects a few things for device
207 /// creation - for instance, the seccomp policy we need to use when jailing the device.
208 pub enum VirtioDeviceType {
209 /// A regular (in-VMM) virtio device.
210 Regular,
211 /// Socket-backed vhost-user device.
212 VhostUser,
213 /// Virtio-backed vhost-user device, aka virtio-vhost-user.
214 Vvu,
215 }
216
217 impl VirtioDeviceType {
218 /// Returns the seccomp policy file that we will want to load for device `base`, depending on
219 /// the virtio transport type.
seccomp_policy_file(&self, base: &str) -> String220 pub fn seccomp_policy_file(&self, base: &str) -> String {
221 match self {
222 VirtioDeviceType::Regular => format!("{base}_device"),
223 VirtioDeviceType::VhostUser => format!("{base}_device_vhost_user"),
224 VirtioDeviceType::Vvu => format!("{base}_device_vvu"),
225 }
226 }
227 }
228