• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 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 use std::path::PathBuf;
6 
7 use devices::IommuDevType;
8 use devices::PciAddress;
9 use devices::SerialParameters;
10 use serde::Deserialize;
11 use serde::Serialize;
12 use serde_keyvalue::FromKeyValues;
13 
14 use crate::crosvm::config::Config;
15 
16 #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, FromKeyValues)]
17 #[serde(deny_unknown_fields, rename_all = "kebab-case")]
18 pub enum HypervisorKind {
19     Kvm {
20         device: Option<PathBuf>,
21     },
22     #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
23     #[cfg(feature = "geniezone")]
24     Geniezone {
25         device: Option<PathBuf>,
26     },
27     #[cfg(all(any(target_arch = "arm", target_arch = "aarch64"), feature = "gunyah"))]
28     Gunyah {
29         device: Option<PathBuf>,
30     },
31 }
32 
33 #[cfg(feature = "audio")]
parse_ac97_options( #[allow(unused_variables)] ac97_params: &mut devices::Ac97Parameters, key: &str, #[allow(unused_variables)] value: &str, ) -> Result<(), String>34 pub fn parse_ac97_options(
35     #[allow(unused_variables)] ac97_params: &mut devices::Ac97Parameters,
36     key: &str,
37     #[allow(unused_variables)] value: &str,
38 ) -> Result<(), String> {
39     match key {
40         #[cfg(feature = "audio_cras")]
41         "client_type" => ac97_params
42             .set_client_type(value)
43             .map_err(|e| crate::crosvm::config::invalid_value_err(value, e)),
44         #[cfg(feature = "audio_cras")]
45         "socket_type" => ac97_params
46             .set_socket_type(value)
47             .map_err(|e| crate::crosvm::config::invalid_value_err(value, e)),
48         _ => Err(format!("unknown ac97 parameter {}", key)),
49     }
50 }
51 
52 // Doesn't do anything on unix.
check_serial_params(_serial_params: &SerialParameters) -> Result<(), String>53 pub fn check_serial_params(_serial_params: &SerialParameters) -> Result<(), String> {
54     Ok(())
55 }
56 
validate_config(_cfg: &mut Config) -> std::result::Result<(), String>57 pub fn validate_config(_cfg: &mut Config) -> std::result::Result<(), String> {
58     Ok(())
59 }
60 
61 /// VFIO device structure for creating a new instance based on command line options.
62 #[derive(Serialize, Deserialize, FromKeyValues)]
63 #[serde(deny_unknown_fields, rename_all = "kebab-case")]
64 pub struct VfioOption {
65     /// Path to the VFIO device.
66     pub path: PathBuf,
67 
68     /// IOMMU type to use for this VFIO device.
69     #[serde(default)]
70     pub iommu: IommuDevType,
71 
72     /// PCI address to use for the VFIO device in the guest.
73     /// If not specified, defaults to mirroring the host PCI address.
74     pub guest_address: Option<PciAddress>,
75 
76     /// Apply special handling for Intel LPSS devices.
77     #[cfg(feature = "direct")]
78     #[serde(default)]
79     pub intel_lpss: bool,
80 }
81 
82 #[cfg(test)]
83 mod tests {
84     use std::path::PathBuf;
85 
86     use argh::FromArgs;
87 
88     use super::*;
89     use crate::crosvm::config::from_key_values;
90     #[cfg(feature = "audio_cras")]
91     use crate::crosvm::config::parse_ac97_options;
92     use crate::crosvm::config::BindMount;
93     use crate::crosvm::config::DEFAULT_TOUCH_DEVICE_HEIGHT;
94     use crate::crosvm::config::DEFAULT_TOUCH_DEVICE_WIDTH;
95 
96     #[cfg(feature = "audio_cras")]
97     #[test]
parse_ac97_socket_type()98     fn parse_ac97_socket_type() {
99         parse_ac97_options("socket_type=unified").expect("parse should have succeded");
100         parse_ac97_options("socket_type=legacy").expect("parse should have succeded");
101     }
102 
103     #[test]
parse_coiommu_options()104     fn parse_coiommu_options() {
105         use std::time::Duration;
106 
107         use devices::CoIommuParameters;
108         use devices::CoIommuUnpinPolicy;
109 
110         // unpin_policy
111         let coiommu_params = from_key_values::<CoIommuParameters>("unpin_policy=off").unwrap();
112         assert_eq!(
113             coiommu_params,
114             CoIommuParameters {
115                 unpin_policy: CoIommuUnpinPolicy::Off,
116                 ..Default::default()
117             }
118         );
119         let coiommu_params = from_key_values::<CoIommuParameters>("unpin_policy=lru").unwrap();
120         assert_eq!(
121             coiommu_params,
122             CoIommuParameters {
123                 unpin_policy: CoIommuUnpinPolicy::Lru,
124                 ..Default::default()
125             }
126         );
127         let coiommu_params = from_key_values::<CoIommuParameters>("unpin_policy=foo");
128         assert!(coiommu_params.is_err());
129 
130         // unpin_interval
131         let coiommu_params = from_key_values::<CoIommuParameters>("unpin_interval=42").unwrap();
132         assert_eq!(
133             coiommu_params,
134             CoIommuParameters {
135                 unpin_interval: Duration::from_secs(42),
136                 ..Default::default()
137             }
138         );
139         let coiommu_params = from_key_values::<CoIommuParameters>("unpin_interval=foo");
140         assert!(coiommu_params.is_err());
141 
142         // unpin_limit
143         let coiommu_params = from_key_values::<CoIommuParameters>("unpin_limit=256").unwrap();
144         assert_eq!(
145             coiommu_params,
146             CoIommuParameters {
147                 unpin_limit: Some(256),
148                 ..Default::default()
149             }
150         );
151         let coiommu_params = from_key_values::<CoIommuParameters>("unpin_limit=0");
152         assert!(coiommu_params.is_err());
153         let coiommu_params = from_key_values::<CoIommuParameters>("unpin_limit=foo");
154         assert!(coiommu_params.is_err());
155 
156         // unpin_gen_threshold
157         let coiommu_params =
158             from_key_values::<CoIommuParameters>("unpin_gen_threshold=32").unwrap();
159         assert_eq!(
160             coiommu_params,
161             CoIommuParameters {
162                 unpin_gen_threshold: 32,
163                 ..Default::default()
164             }
165         );
166         let coiommu_params = from_key_values::<CoIommuParameters>("unpin_gen_threshold=foo");
167         assert!(coiommu_params.is_err());
168 
169         // All together
170         let coiommu_params = from_key_values::<CoIommuParameters>(
171             "unpin_policy=lru,unpin_interval=90,unpin_limit=8,unpin_gen_threshold=64",
172         )
173         .unwrap();
174         assert_eq!(
175             coiommu_params,
176             CoIommuParameters {
177                 unpin_policy: CoIommuUnpinPolicy::Lru,
178                 unpin_interval: Duration::from_secs(90),
179                 unpin_limit: Some(8),
180                 unpin_gen_threshold: 64,
181             }
182         );
183 
184         // invalid parameter
185         let coiommu_params = from_key_values::<CoIommuParameters>("unpin_invalid_param=0");
186         assert!(coiommu_params.is_err());
187     }
188 
189     #[test]
parse_plugin_mount_valid()190     fn parse_plugin_mount_valid() {
191         let opt: BindMount = "/dev/null:/dev/zero:true".parse().unwrap();
192 
193         assert_eq!(opt.src, PathBuf::from("/dev/null"));
194         assert_eq!(opt.dst, PathBuf::from("/dev/zero"));
195         assert!(opt.writable);
196     }
197 
198     #[test]
parse_plugin_mount_valid_shorthand()199     fn parse_plugin_mount_valid_shorthand() {
200         let opt: BindMount = "/dev/null".parse().unwrap();
201         assert_eq!(opt.dst, PathBuf::from("/dev/null"));
202         assert!(!opt.writable);
203 
204         let opt: BindMount = "/dev/null:/dev/zero".parse().unwrap();
205         assert_eq!(opt.dst, PathBuf::from("/dev/zero"));
206         assert!(!opt.writable);
207 
208         let opt: BindMount = "/dev/null::true".parse().unwrap();
209         assert_eq!(opt.dst, PathBuf::from("/dev/null"));
210         assert!(opt.writable);
211     }
212 
213     #[test]
single_touch_spec_and_track_pad_spec_default_size()214     fn single_touch_spec_and_track_pad_spec_default_size() {
215         let config: Config = crate::crosvm::cmdline::RunCommand::from_args(
216             &[],
217             &[
218                 "--single-touch",
219                 "/dev/single-touch-test",
220                 "--trackpad",
221                 "/dev/single-touch-test",
222                 "/dev/null",
223             ],
224         )
225         .unwrap()
226         .try_into()
227         .unwrap();
228 
229         assert_eq!(
230             config.virtio_single_touch.first().unwrap().get_size(),
231             (DEFAULT_TOUCH_DEVICE_WIDTH, DEFAULT_TOUCH_DEVICE_HEIGHT)
232         );
233         assert_eq!(
234             config.virtio_trackpad.first().unwrap().get_size(),
235             (DEFAULT_TOUCH_DEVICE_WIDTH, DEFAULT_TOUCH_DEVICE_HEIGHT)
236         );
237     }
238 
239     #[cfg(feature = "gpu")]
240     #[test]
single_touch_spec_default_size_from_gpu()241     fn single_touch_spec_default_size_from_gpu() {
242         let width = 12345u32;
243         let height = 54321u32;
244 
245         let config: Config = crate::crosvm::cmdline::RunCommand::from_args(
246             &[],
247             &[
248                 "--single-touch",
249                 "/dev/single-touch-test",
250                 "--gpu",
251                 &format!("width={},height={}", width, height),
252                 "/dev/null",
253             ],
254         )
255         .unwrap()
256         .try_into()
257         .unwrap();
258 
259         assert_eq!(
260             config.virtio_single_touch.first().unwrap().get_size(),
261             (width, height)
262         );
263     }
264 
265     #[test]
single_touch_spec_and_track_pad_spec_with_size()266     fn single_touch_spec_and_track_pad_spec_with_size() {
267         let width = 12345u32;
268         let height = 54321u32;
269         let config: Config = crate::crosvm::cmdline::RunCommand::from_args(
270             &[],
271             &[
272                 "--single-touch",
273                 &format!("/dev/single-touch-test:{}:{}", width, height),
274                 "--trackpad",
275                 &format!("/dev/single-touch-test:{}:{}", width, height),
276                 "/dev/null",
277             ],
278         )
279         .unwrap()
280         .try_into()
281         .unwrap();
282 
283         assert_eq!(
284             config.virtio_single_touch.first().unwrap().get_size(),
285             (width, height)
286         );
287         assert_eq!(
288             config.virtio_trackpad.first().unwrap().get_size(),
289             (width, height)
290         );
291     }
292 
293     #[cfg(feature = "gpu")]
294     #[test]
single_touch_spec_with_size_independent_from_gpu()295     fn single_touch_spec_with_size_independent_from_gpu() {
296         let touch_width = 12345u32;
297         let touch_height = 54321u32;
298         let display_width = 1234u32;
299         let display_height = 5432u32;
300         let config: Config = crate::crosvm::cmdline::RunCommand::from_args(
301             &[],
302             &[
303                 "--single-touch",
304                 &format!("/dev/single-touch-test:{}:{}", touch_width, touch_height),
305                 "--gpu",
306                 &format!("width={},height={}", display_width, display_height),
307                 "/dev/null",
308             ],
309         )
310         .unwrap()
311         .try_into()
312         .unwrap();
313 
314         assert_eq!(
315             config.virtio_single_touch.first().unwrap().get_size(),
316             (touch_width, touch_height)
317         );
318     }
319 
320     #[test]
virtio_switches()321     fn virtio_switches() {
322         let mut config: Config = crate::crosvm::cmdline::RunCommand::from_args(
323             &[],
324             &["--switches", "/dev/switches-test", "/dev/null"],
325         )
326         .unwrap()
327         .try_into()
328         .unwrap();
329 
330         assert_eq!(
331             config.virtio_switches.pop().unwrap(),
332             PathBuf::from("/dev/switches-test")
333         );
334     }
335 
336     #[test]
vfio_pci_path()337     fn vfio_pci_path() {
338         let config: Config = crate::crosvm::cmdline::RunCommand::from_args(
339             &[],
340             &["--vfio", "/path/to/dev", "/dev/null"],
341         )
342         .unwrap()
343         .try_into()
344         .unwrap();
345 
346         let vfio = config.vfio.first().unwrap();
347 
348         assert_eq!(vfio.path, PathBuf::from("/path/to/dev"));
349         assert_eq!(vfio.iommu, IommuDevType::NoIommu);
350         assert_eq!(vfio.guest_address, None);
351     }
352 
353     #[test]
vfio_pci_path_coiommu()354     fn vfio_pci_path_coiommu() {
355         let config: Config = crate::crosvm::cmdline::RunCommand::from_args(
356             &[],
357             &["--vfio", "/path/to/dev,iommu=coiommu", "/dev/null"],
358         )
359         .unwrap()
360         .try_into()
361         .unwrap();
362 
363         let vfio = config.vfio.first().unwrap();
364 
365         assert_eq!(vfio.path, PathBuf::from("/path/to/dev"));
366         assert_eq!(vfio.iommu, IommuDevType::CoIommu);
367         assert_eq!(vfio.guest_address, None);
368     }
369 
370     #[test]
vfio_pci_path_viommu_guest_address()371     fn vfio_pci_path_viommu_guest_address() {
372         let config: Config = crate::crosvm::cmdline::RunCommand::from_args(
373             &[],
374             &[
375                 "--vfio",
376                 "/path/to/dev,iommu=viommu,guest-address=42:15.4",
377                 "/dev/null",
378             ],
379         )
380         .unwrap()
381         .try_into()
382         .unwrap();
383 
384         let vfio = config.vfio.first().unwrap();
385 
386         assert_eq!(vfio.path, PathBuf::from("/path/to/dev"));
387         assert_eq!(vfio.iommu, IommuDevType::VirtioIommu);
388         assert_eq!(
389             vfio.guest_address,
390             Some(PciAddress::new(0, 0x42, 0x15, 4).unwrap())
391         );
392     }
393 
394     #[test]
395     #[cfg(feature = "direct")]
vfio_pci_intel_lpss()396     fn vfio_pci_intel_lpss() {
397         let config: Config = crate::crosvm::cmdline::RunCommand::from_args(
398             &[],
399             &["--vfio", "/path/to/dev,intel-lpss=true", "/dev/null"],
400         )
401         .unwrap()
402         .try_into()
403         .unwrap();
404 
405         let vfio = config.vfio.first().unwrap();
406 
407         assert_eq!(vfio.intel_lpss, true);
408     }
409 
410     #[test]
vfio_platform()411     fn vfio_platform() {
412         let config: Config = crate::crosvm::cmdline::RunCommand::from_args(
413             &[],
414             &["--vfio-platform", "/path/to/dev", "/dev/null"],
415         )
416         .unwrap()
417         .try_into()
418         .unwrap();
419 
420         let vfio = config.vfio.first().unwrap();
421 
422         assert_eq!(vfio.path, PathBuf::from("/path/to/dev"));
423     }
424 }
425