• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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