1 // Copyright 2019 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 //! The root level module that includes the config and aggregate of the submodules for running said
6 //! configs.
7 
8 pub mod argument;
9 #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
10 pub mod gdb;
11 #[path = "linux.rs"]
12 pub mod platform;
13 #[cfg(feature = "plugin")]
14 pub mod plugin;
15 
16 use std::collections::BTreeMap;
17 use std::net;
18 use std::os::unix::io::RawFd;
19 use std::path::{Path, PathBuf};
20 use std::str::FromStr;
21 
22 use arch::{Pstore, SerialHardware, SerialParameters, VcpuAffinity};
23 use devices::virtio::fs::passthrough;
24 #[cfg(feature = "gpu")]
25 use devices::virtio::gpu::GpuParameters;
26 #[cfg(feature = "audio")]
27 use devices::Ac97Parameters;
28 use devices::ProtectionType;
29 use libc::{getegid, geteuid};
30 use vm_control::BatteryType;
31 
32 static KVM_PATH: &str = "/dev/kvm";
33 static VHOST_VSOCK_PATH: &str = "/dev/vhost-vsock";
34 static VHOST_NET_PATH: &str = "/dev/vhost-net";
35 static SECCOMP_POLICY_DIR: &str = "/usr/share/policy/crosvm";
36 
37 /// Indicates the location and kind of executable kernel for a VM.
38 #[derive(Debug)]
39 pub enum Executable {
40     /// An executable intended to be run as a BIOS directly.
41     Bios(PathBuf),
42     /// A elf linux kernel, loaded and executed by crosvm.
43     Kernel(PathBuf),
44     /// Path to a plugin executable that is forked by crosvm.
45     Plugin(PathBuf),
46 }
47 
48 /// Maximum length of a `DiskOption` identifier.
49 ///
50 /// This is based on the virtio-block ID length limit.
51 pub const DISK_ID_LEN: usize = 20;
52 
53 pub struct DiskOption {
54     pub path: PathBuf,
55     pub read_only: bool,
56     pub sparse: bool,
57     pub block_size: u32,
58     pub id: Option<[u8; DISK_ID_LEN]>,
59 }
60 
61 pub struct VhostUserOption {
62     pub socket: PathBuf,
63 }
64 
65 pub struct VhostUserFsOption {
66     pub socket: PathBuf,
67     pub tag: String,
68 }
69 
70 /// A bind mount for directories in the plugin process.
71 pub struct BindMount {
72     pub src: PathBuf,
73     pub dst: PathBuf,
74     pub writable: bool,
75 }
76 
77 /// A mapping of linux group IDs for the plugin process.
78 pub struct GidMap {
79     pub inner: libc::gid_t,
80     pub outer: libc::gid_t,
81     pub count: u32,
82 }
83 
84 /// Direct IO forwarding options
85 #[cfg(feature = "direct")]
86 pub struct DirectIoOption {
87     pub path: PathBuf,
88     pub ranges: Vec<(u64, u64)>,
89 }
90 
91 pub const DEFAULT_TOUCH_DEVICE_HEIGHT: u32 = 1024;
92 pub const DEFAULT_TOUCH_DEVICE_WIDTH: u32 = 1280;
93 
94 pub struct TouchDeviceOption {
95     path: PathBuf,
96     width: Option<u32>,
97     height: Option<u32>,
98     default_width: u32,
99     default_height: u32,
100 }
101 
102 impl TouchDeviceOption {
new(path: PathBuf) -> TouchDeviceOption103     pub fn new(path: PathBuf) -> TouchDeviceOption {
104         TouchDeviceOption {
105             path,
106             width: None,
107             height: None,
108             default_width: DEFAULT_TOUCH_DEVICE_WIDTH,
109             default_height: DEFAULT_TOUCH_DEVICE_HEIGHT,
110         }
111     }
112 
113     /// Getter for the path to the input event streams.
get_path(&self) -> &Path114     pub fn get_path(&self) -> &Path {
115         self.path.as_path()
116     }
117 
118     /// When a user specifies the parameters for a touch device, width and height are optional.
119     /// If the width and height are missing, default values are used. Default values can be set
120     /// dynamically, for example from the display sizes specified by the gpu argument.
set_default_size(&mut self, width: u32, height: u32)121     pub fn set_default_size(&mut self, width: u32, height: u32) {
122         self.default_width = width;
123         self.default_height = height;
124     }
125 
126     /// Setter for the width specified by the user.
set_width(&mut self, width: u32)127     pub fn set_width(&mut self, width: u32) {
128         self.width.replace(width);
129     }
130 
131     /// Setter for the height specified by the user.
set_height(&mut self, height: u32)132     pub fn set_height(&mut self, height: u32) {
133         self.height.replace(height);
134     }
135 
136     /// If the user specifies the size, use it. Otherwise, use the default values.
get_size(&self) -> (u32, u32)137     pub fn get_size(&self) -> (u32, u32) {
138         (
139             self.width.unwrap_or(self.default_width),
140             self.height.unwrap_or(self.default_height),
141         )
142     }
143 }
144 
145 #[derive(Eq, PartialEq)]
146 pub enum SharedDirKind {
147     FS,
148     P9,
149 }
150 
151 impl FromStr for SharedDirKind {
152     type Err = &'static str;
153 
from_str(s: &str) -> Result<Self, Self::Err>154     fn from_str(s: &str) -> Result<Self, Self::Err> {
155         use SharedDirKind::*;
156         match s {
157             "fs" | "FS" => Ok(FS),
158             "9p" | "9P" | "p9" | "P9" => Ok(P9),
159             _ => Err("invalid file system type"),
160         }
161     }
162 }
163 
164 impl Default for SharedDirKind {
default() -> SharedDirKind165     fn default() -> SharedDirKind {
166         SharedDirKind::P9
167     }
168 }
169 
170 pub struct SharedDir {
171     pub src: PathBuf,
172     pub tag: String,
173     pub kind: SharedDirKind,
174     pub uid_map: String,
175     pub gid_map: String,
176     pub fs_cfg: passthrough::Config,
177     pub p9_cfg: p9::Config,
178 }
179 
180 impl Default for SharedDir {
default() -> SharedDir181     fn default() -> SharedDir {
182         SharedDir {
183             src: Default::default(),
184             tag: Default::default(),
185             kind: Default::default(),
186             uid_map: format!("0 {} 1", unsafe { geteuid() }),
187             gid_map: format!("0 {} 1", unsafe { getegid() }),
188             fs_cfg: Default::default(),
189             p9_cfg: Default::default(),
190         }
191     }
192 }
193 
194 /// Aggregate of all configurable options for a running VM.
195 pub struct Config {
196     pub kvm_device_path: PathBuf,
197     pub vhost_vsock_device_path: PathBuf,
198     pub vhost_net_device_path: PathBuf,
199     pub vcpu_count: Option<usize>,
200     pub rt_cpus: Vec<usize>,
201     pub vcpu_affinity: Option<VcpuAffinity>,
202     pub no_smt: bool,
203     pub memory: Option<u64>,
204     pub hugepages: bool,
205     pub memory_file: Option<PathBuf>,
206     pub executable_path: Option<Executable>,
207     pub android_fstab: Option<PathBuf>,
208     pub initrd_path: Option<PathBuf>,
209     pub params: Vec<String>,
210     pub socket_path: Option<PathBuf>,
211     pub plugin_root: Option<PathBuf>,
212     pub plugin_mounts: Vec<BindMount>,
213     pub plugin_gid_maps: Vec<GidMap>,
214     pub disks: Vec<DiskOption>,
215     pub pmem_devices: Vec<DiskOption>,
216     pub pstore: Option<Pstore>,
217     pub host_ip: Option<net::Ipv4Addr>,
218     pub netmask: Option<net::Ipv4Addr>,
219     pub mac_address: Option<net_util::MacAddress>,
220     pub net_vq_pairs: Option<u16>,
221     pub vhost_net: bool,
222     pub tap_fd: Vec<RawFd>,
223     pub cid: Option<u64>,
224     pub wayland_socket_paths: BTreeMap<String, PathBuf>,
225     pub wayland_dmabuf: bool,
226     pub x_display: Option<String>,
227     pub shared_dirs: Vec<SharedDir>,
228     pub sandbox: bool,
229     pub seccomp_policy_dir: PathBuf,
230     pub seccomp_log_failures: bool,
231     #[cfg(feature = "gpu")]
232     pub gpu_parameters: Option<GpuParameters>,
233     pub software_tpm: bool,
234     pub display_window_keyboard: bool,
235     pub display_window_mouse: bool,
236     #[cfg(feature = "audio")]
237     pub ac97_parameters: Vec<Ac97Parameters>,
238     pub serial_parameters: BTreeMap<(SerialHardware, u8), SerialParameters>,
239     pub syslog_tag: Option<String>,
240     pub virtio_single_touch: Option<TouchDeviceOption>,
241     pub virtio_multi_touch: Option<TouchDeviceOption>,
242     pub virtio_trackpad: Option<TouchDeviceOption>,
243     pub virtio_mouse: Option<PathBuf>,
244     pub virtio_keyboard: Option<PathBuf>,
245     pub virtio_switches: Option<PathBuf>,
246     pub virtio_input_evdevs: Vec<PathBuf>,
247     pub split_irqchip: bool,
248     pub vfio: Vec<PathBuf>,
249     pub video_dec: bool,
250     pub video_enc: bool,
251     pub acpi_tables: Vec<PathBuf>,
252     pub protected_vm: ProtectionType,
253     pub battery_type: Option<BatteryType>,
254     #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
255     pub gdb: Option<u32>,
256     pub balloon_bias: i64,
257     pub vhost_user_blk: Vec<VhostUserOption>,
258     pub vhost_user_fs: Vec<VhostUserFsOption>,
259     pub vhost_user_net: Vec<VhostUserOption>,
260     #[cfg(feature = "direct")]
261     pub direct_pmio: Option<DirectIoOption>,
262     #[cfg(feature = "direct")]
263     pub direct_level_irq: Vec<u32>,
264     #[cfg(feature = "direct")]
265     pub direct_edge_irq: Vec<u32>,
266     pub dmi_path: Option<PathBuf>,
267 }
268 
269 impl Default for Config {
default() -> Config270     fn default() -> Config {
271         Config {
272             kvm_device_path: PathBuf::from(KVM_PATH),
273             vhost_vsock_device_path: PathBuf::from(VHOST_VSOCK_PATH),
274             vhost_net_device_path: PathBuf::from(VHOST_NET_PATH),
275             vcpu_count: None,
276             rt_cpus: Vec::new(),
277             vcpu_affinity: None,
278             no_smt: false,
279             memory: None,
280             hugepages: false,
281             memory_file: None,
282             executable_path: None,
283             android_fstab: None,
284             initrd_path: None,
285             params: Vec::new(),
286             socket_path: None,
287             plugin_root: None,
288             plugin_mounts: Vec::new(),
289             plugin_gid_maps: Vec::new(),
290             disks: Vec::new(),
291             pmem_devices: Vec::new(),
292             pstore: None,
293             host_ip: None,
294             netmask: None,
295             mac_address: None,
296             net_vq_pairs: None,
297             vhost_net: false,
298             tap_fd: Vec::new(),
299             cid: None,
300             #[cfg(feature = "gpu")]
301             gpu_parameters: None,
302             software_tpm: false,
303             wayland_socket_paths: BTreeMap::new(),
304             wayland_dmabuf: false,
305             x_display: None,
306             display_window_keyboard: false,
307             display_window_mouse: false,
308             shared_dirs: Vec::new(),
309             sandbox: !cfg!(feature = "default-no-sandbox"),
310             seccomp_policy_dir: PathBuf::from(SECCOMP_POLICY_DIR),
311             seccomp_log_failures: false,
312             #[cfg(feature = "audio")]
313             ac97_parameters: Vec::new(),
314             serial_parameters: BTreeMap::new(),
315             syslog_tag: None,
316             virtio_single_touch: None,
317             virtio_multi_touch: None,
318             virtio_trackpad: None,
319             virtio_mouse: None,
320             virtio_keyboard: None,
321             virtio_switches: None,
322             virtio_input_evdevs: Vec::new(),
323             split_irqchip: false,
324             vfio: Vec::new(),
325             video_dec: false,
326             video_enc: false,
327             acpi_tables: Vec::new(),
328             protected_vm: ProtectionType::Unprotected,
329             battery_type: None,
330             #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
331             gdb: None,
332             balloon_bias: 0,
333             vhost_user_blk: Vec::new(),
334             vhost_user_fs: Vec::new(),
335             vhost_user_net: Vec::new(),
336             #[cfg(feature = "direct")]
337             direct_pmio: None,
338             #[cfg(feature = "direct")]
339             direct_level_irq: Vec::new(),
340             #[cfg(feature = "direct")]
341             direct_edge_irq: Vec::new(),
342             dmi_path: None,
343         }
344     }
345 }
346