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 cfg_if::cfg_if! {
6 if #[cfg(unix)] {
7 use std::net;
8
9 use base::RawDescriptor;
10 use devices::virtio::vhost::user::device::parse_wayland_sock;
11
12 use super::sys::config::VfioOption;
13 use super::config::SharedDir;
14 } else if #[cfg(windows)] {
15 use crate::crosvm::sys::config::IrqChipKind;
16
17 }
18 }
19
20 use std::collections::BTreeMap;
21 #[cfg(feature = "config-file")]
22 use std::path::Path;
23 use std::path::PathBuf;
24 use std::str::FromStr;
25 use std::sync::atomic::AtomicUsize;
26 use std::sync::atomic::Ordering;
27
28 use arch::CpuSet;
29 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
30 use arch::MsrConfig;
31 use arch::Pstore;
32 use arch::VcpuAffinity;
33 use argh::FromArgs;
34 use base::getpid;
35 use cros_async::ExecutorKind;
36 use devices::virtio::block::block::DiskOption;
37 #[cfg(any(feature = "video-decoder", feature = "video-encoder"))]
38 use devices::virtio::device_constants::video::VideoDeviceConfig;
39 #[cfg(feature = "audio")]
40 use devices::virtio::snd::parameters::Parameters as SndParameters;
41 use devices::virtio::vhost::user::device;
42 use devices::virtio::vsock::VsockConfig;
43 #[cfg(feature = "gpu")]
44 use devices::virtio::GpuDisplayParameters;
45 #[cfg(feature = "gpu")]
46 use devices::virtio::GpuParameters;
47 #[cfg(unix)]
48 use devices::virtio::NetParameters;
49 #[cfg(unix)]
50 use devices::virtio::NetParametersMode;
51 #[cfg(feature = "audio")]
52 use devices::Ac97Parameters;
53 use devices::PflashParameters;
54 use devices::SerialHardware;
55 use devices::SerialParameters;
56 use devices::StubPciParameters;
57 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
58 use hypervisor::CpuHybridType;
59 use hypervisor::ProtectionType;
60 use merge::bool::overwrite_false;
61 use merge::vec::append;
62 use resources::AddressRange;
63 use serde::Deserialize;
64 #[cfg(feature = "gpu")]
65 use serde_keyvalue::FromKeyValues;
66
67 #[cfg(feature = "gpu")]
68 use super::gpu_config::fixup_gpu_display_options;
69 #[cfg(feature = "gpu")]
70 use super::gpu_config::fixup_gpu_options;
71 #[cfg(all(feature = "gpu", feature = "virgl_renderer_next"))]
72 use super::sys::GpuRenderServerParameters;
73 use crate::crosvm::config::from_key_values;
74 #[cfg(feature = "audio")]
75 use crate::crosvm::config::parse_ac97_options;
76 use crate::crosvm::config::parse_bus_id_addr;
77 use crate::crosvm::config::parse_cpu_affinity;
78 use crate::crosvm::config::parse_cpu_capacity;
79 #[cfg(feature = "direct")]
80 use crate::crosvm::config::parse_direct_io_options;
81 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
82 use crate::crosvm::config::parse_memory_region;
83 use crate::crosvm::config::parse_mmio_address_range;
84 #[cfg(feature = "direct")]
85 use crate::crosvm::config::parse_pcie_root_port_params;
86 use crate::crosvm::config::parse_pflash_parameters;
87 #[cfg(feature = "plugin")]
88 use crate::crosvm::config::parse_plugin_mount_option;
89 use crate::crosvm::config::parse_serial_options;
90 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
91 use crate::crosvm::config::parse_userspace_msr_options;
92 use crate::crosvm::config::BatteryConfig;
93 #[cfg(feature = "plugin")]
94 use crate::crosvm::config::BindMount;
95 use crate::crosvm::config::CpuOptions;
96 #[cfg(feature = "direct")]
97 use crate::crosvm::config::DirectIoOption;
98 use crate::crosvm::config::Executable;
99 use crate::crosvm::config::FileBackedMappingParameters;
100 #[cfg(feature = "plugin")]
101 use crate::crosvm::config::GidMap;
102 #[cfg(feature = "direct")]
103 use crate::crosvm::config::HostPcieRootPortParameters;
104 use crate::crosvm::config::HypervisorKind;
105 use crate::crosvm::config::MemOptions;
106 use crate::crosvm::config::TouchDeviceOption;
107 use crate::crosvm::config::VhostUserFsOption;
108 use crate::crosvm::config::VhostUserOption;
109 use crate::crosvm::config::VvuOption;
110
111 #[derive(FromArgs)]
112 /// crosvm
113 pub struct CrosvmCmdlineArgs {
114 #[argh(switch)]
115 /// use extended exit status
116 pub extended_status: bool,
117 #[argh(option, default = r#"String::from("info")"#)]
118 /// specify log level, eg "off", "error", "debug,disk=off", etc
119 pub log_level: String,
120 #[argh(option, arg_name = "TAG")]
121 /// when logging to syslog, use the provided tag
122 pub syslog_tag: Option<String>,
123 #[argh(switch)]
124 /// disable output to syslog
125 pub no_syslog: bool,
126 #[argh(subcommand)]
127 pub command: Command,
128 }
129
130 #[allow(clippy::large_enum_variant)]
131 #[derive(FromArgs)]
132 #[argh(subcommand)]
133 pub enum CrossPlatformCommands {
134 #[cfg(feature = "balloon")]
135 Balloon(BalloonCommand),
136 #[cfg(feature = "balloon")]
137 BalloonStats(BalloonStatsCommand),
138 Battery(BatteryCommand),
139 #[cfg(feature = "composite-disk")]
140 CreateComposite(CreateCompositeCommand),
141 #[cfg(feature = "qcow")]
142 CreateQcow2(CreateQcow2Command),
143 Device(DeviceCommand),
144 Disk(DiskCommand),
145 #[cfg(feature = "gpu")]
146 Gpu(GpuCommand),
147 MakeRT(MakeRTCommand),
148 Resume(ResumeCommand),
149 Run(RunCommand),
150 Stop(StopCommand),
151 Suspend(SuspendCommand),
152 Swap(SwapCommand),
153 Powerbtn(PowerbtnCommand),
154 Sleepbtn(SleepCommand),
155 Gpe(GpeCommand),
156 Usb(UsbCommand),
157 Version(VersionCommand),
158 Vfio(VfioCrosvmCommand),
159 Snapshot(SnapshotCommand),
160 }
161
162 #[allow(clippy::large_enum_variant)]
163 #[derive(argh_helpers::FlattenSubcommand)]
164 pub enum Command {
165 CrossPlatform(CrossPlatformCommands),
166 Sys(super::sys::cmdline::Commands),
167 }
168
169 #[derive(FromArgs)]
170 #[argh(subcommand, name = "balloon")]
171 /// Set balloon size of the crosvm instance to `SIZE` bytes
172 pub struct BalloonCommand {
173 #[argh(positional, arg_name = "SIZE")]
174 /// amount of bytes
175 pub num_bytes: u64,
176 #[argh(positional, arg_name = "VM_SOCKET")]
177 /// VM Socket path
178 pub socket_path: String,
179 }
180
181 #[derive(argh::FromArgs)]
182 #[argh(subcommand, name = "balloon_stats")]
183 /// Prints virtio balloon statistics for a `VM_SOCKET`
184 pub struct BalloonStatsCommand {
185 #[argh(positional, arg_name = "VM_SOCKET")]
186 /// VM Socket path
187 pub socket_path: String,
188 }
189
190 #[derive(FromArgs)]
191 #[argh(subcommand, name = "battery")]
192 /// Modify battery
193 pub struct BatteryCommand {
194 #[argh(positional, arg_name = "BATTERY_TYPE")]
195 /// battery type
196 pub battery_type: String,
197 #[argh(positional)]
198 /// battery property
199 /// status | present | health | capacity | aconline
200 pub property: String,
201 #[argh(positional)]
202 /// battery property target
203 /// STATUS | PRESENT | HEALTH | CAPACITY | ACONLINE
204 pub target: String,
205 #[argh(positional, arg_name = "VM_SOCKET")]
206 /// VM Socket path
207 pub socket_path: String,
208 }
209
210 #[cfg(feature = "composite-disk")]
211 #[derive(FromArgs)]
212 #[argh(subcommand, name = "create_composite")]
213 /// Create a new composite disk image file
214 pub struct CreateCompositeCommand {
215 #[argh(positional, arg_name = "PATH")]
216 /// image path
217 pub path: String,
218 #[argh(positional, arg_name = "LABEL:PARTITION")]
219 /// partitions
220 pub partitions: Vec<String>,
221 }
222
223 #[cfg(feature = "qcow")]
224 #[derive(FromArgs)]
225 #[argh(subcommand, name = "create_qcow2")]
226 /// Create Qcow2 image given path and size
227 pub struct CreateQcow2Command {
228 #[argh(positional, arg_name = "PATH")]
229 /// path to the new qcow2 file to create
230 pub file_path: String,
231 #[argh(positional, arg_name = "SIZE")]
232 /// desired size of the image in bytes; required if not using --backing-file
233 pub size: Option<u64>,
234 #[argh(option)]
235 /// path to backing file; if specified, the image will be the same size as the backing file, and
236 /// SIZE may not be specified
237 pub backing_file: Option<String>,
238 }
239
240 #[derive(FromArgs)]
241 #[argh(subcommand)]
242 pub enum DiskSubcommand {
243 Resize(ResizeDiskSubcommand),
244 }
245
246 #[derive(FromArgs)]
247 /// resize disk
248 #[argh(subcommand, name = "resize")]
249 pub struct ResizeDiskSubcommand {
250 #[argh(positional, arg_name = "DISK_INDEX")]
251 /// disk index
252 pub disk_index: usize,
253 #[argh(positional, arg_name = "NEW_SIZE")]
254 /// new disk size
255 pub disk_size: u64,
256 #[argh(positional, arg_name = "VM_SOCKET")]
257 /// VM Socket path
258 pub socket_path: String,
259 }
260
261 #[derive(FromArgs)]
262 #[argh(subcommand, name = "disk")]
263 /// Manage attached virtual disk devices
264 pub struct DiskCommand {
265 #[argh(subcommand)]
266 pub command: DiskSubcommand,
267 }
268
269 #[derive(FromArgs)]
270 #[argh(subcommand, name = "make_rt")]
271 /// Enables real-time vcpu priority for crosvm instances started with `--delay-rt`
272 pub struct MakeRTCommand {
273 #[argh(positional, arg_name = "VM_SOCKET")]
274 /// VM Socket path
275 pub socket_path: String,
276 }
277
278 #[derive(FromArgs)]
279 #[argh(subcommand, name = "resume")]
280 /// Resumes the crosvm instance
281 pub struct ResumeCommand {
282 #[argh(positional, arg_name = "VM_SOCKET")]
283 /// VM Socket path
284 pub socket_path: String,
285 }
286
287 #[derive(FromArgs)]
288 #[argh(subcommand, name = "stop")]
289 /// Stops crosvm instances via their control sockets
290 pub struct StopCommand {
291 #[argh(positional, arg_name = "VM_SOCKET")]
292 /// VM Socket path
293 pub socket_path: String,
294 }
295
296 #[derive(FromArgs)]
297 #[argh(subcommand, name = "suspend")]
298 /// Suspends the crosvm instance
299 pub struct SuspendCommand {
300 #[argh(positional, arg_name = "VM_SOCKET")]
301 /// VM Socket path
302 pub socket_path: String,
303 }
304
305 #[derive(FromArgs)]
306 #[argh(subcommand, name = "enable")]
307 /// Enable vmm-swap of a VM. The guest memory is moved to staging memory
308 pub struct SwapEnableCommand {
309 #[argh(positional, arg_name = "VM_SOCKET")]
310 /// VM Socket path
311 pub socket_path: String,
312 }
313
314 #[derive(FromArgs)]
315 #[argh(subcommand, name = "trim")]
316 /// Trim pages in the staging memory
317 pub struct SwapTrimCommand {
318 #[argh(positional, arg_name = "VM_SOCKET")]
319 /// VM Socket path
320 pub socket_path: String,
321 }
322
323 #[derive(FromArgs)]
324 #[argh(subcommand, name = "out")]
325 /// Swap out staging memory to swap file
326 pub struct SwapOutCommand {
327 #[argh(positional, arg_name = "VM_SOCKET")]
328 /// VM Socket path
329 pub socket_path: String,
330 }
331
332 #[derive(FromArgs)]
333 #[argh(subcommand, name = "disable")]
334 /// Disable vmm-swap of a VM
335 pub struct SwapDisableCommand {
336 #[argh(positional, arg_name = "VM_SOCKET")]
337 /// VM Socket path
338 pub socket_path: String,
339 }
340
341 #[derive(FromArgs)]
342 #[argh(subcommand, name = "status")]
343 /// Get vmm-swap status of a VM
344 pub struct SwapStatusCommand {
345 #[argh(positional, arg_name = "VM_SOCKET")]
346 /// VM Socket path
347 pub socket_path: String,
348 }
349
350 /// Vmm-swap commands
351 #[derive(FromArgs)]
352 #[argh(subcommand, name = "swap")]
353 pub struct SwapCommand {
354 #[argh(subcommand)]
355 pub nested: SwapSubcommands,
356 }
357
358 #[derive(FromArgs)]
359 #[argh(subcommand)]
360 pub enum SwapSubcommands {
361 Enable(SwapEnableCommand),
362 Trim(SwapTrimCommand),
363 SwapOut(SwapOutCommand),
364 Disable(SwapDisableCommand),
365 Status(SwapStatusCommand),
366 }
367
368 #[derive(FromArgs)]
369 #[argh(subcommand, name = "powerbtn")]
370 /// Triggers a power button event in the crosvm instance
371 pub struct PowerbtnCommand {
372 #[argh(positional, arg_name = "VM_SOCKET")]
373 /// VM Socket path
374 pub socket_path: String,
375 }
376
377 #[derive(FromArgs)]
378 #[argh(subcommand, name = "sleepbtn")]
379 /// Triggers a sleep button event in the crosvm instance
380 pub struct SleepCommand {
381 #[argh(positional, arg_name = "VM_SOCKET")]
382 /// VM Socket path
383 pub socket_path: String,
384 }
385
386 #[derive(FromArgs)]
387 #[argh(subcommand, name = "gpe")]
388 /// Injects a general-purpose event into the crosvm instance
389 pub struct GpeCommand {
390 #[argh(positional)]
391 /// GPE #
392 pub gpe: u32,
393 #[argh(positional, arg_name = "VM_SOCKET")]
394 /// VM Socket path
395 pub socket_path: String,
396 }
397
398 #[derive(FromArgs)]
399 #[argh(subcommand, name = "usb")]
400 /// Manage attached virtual USB devices.
401 pub struct UsbCommand {
402 #[argh(subcommand)]
403 pub command: UsbSubCommand,
404 }
405
406 #[cfg(feature = "gpu")]
407 #[derive(FromArgs)]
408 #[argh(subcommand, name = "gpu")]
409 /// Manage attached virtual GPU device.
410 pub struct GpuCommand {
411 #[argh(subcommand)]
412 pub command: GpuSubCommand,
413 }
414
415 #[derive(FromArgs)]
416 #[argh(subcommand, name = "version")]
417 /// Show package version.
418 pub struct VersionCommand {}
419
420 #[derive(FromArgs)]
421 #[argh(subcommand, name = "add")]
422 /// ADD
423 pub struct VfioAddSubCommand {
424 #[argh(positional)]
425 /// path to host's vfio sysfs
426 pub vfio_path: PathBuf,
427 #[argh(positional, arg_name = "VM_SOCKET")]
428 /// VM Socket path
429 pub socket_path: String,
430 }
431
432 #[derive(FromArgs)]
433 #[argh(subcommand, name = "remove")]
434 /// REMOVE
435 pub struct VfioRemoveSubCommand {
436 #[argh(positional)]
437 /// path to host's vfio sysfs
438 pub vfio_path: PathBuf,
439 #[argh(positional, arg_name = "VM_SOCKET")]
440 /// VM Socket path
441 pub socket_path: String,
442 }
443
444 #[derive(FromArgs)]
445 #[argh(subcommand)]
446 pub enum VfioSubCommand {
447 Add(VfioAddSubCommand),
448 Remove(VfioRemoveSubCommand),
449 }
450
451 #[derive(FromArgs)]
452 #[argh(subcommand, name = "vfio")]
453 /// add/remove host vfio pci device into guest
454 pub struct VfioCrosvmCommand {
455 #[argh(subcommand)]
456 pub command: VfioSubCommand,
457 }
458
459 #[derive(FromArgs)]
460 #[argh(subcommand, name = "device")]
461 /// Start a device process
462 pub struct DeviceCommand {
463 /// configure async executor backend; "uring" or "epoll" on Linux, "handle" on Windows.
464 /// If this option is omitted on Linux, "epoll" is used by default.
465 #[argh(option, arg_name = "EXECUTOR")]
466 pub async_executor: Option<ExecutorKind>,
467
468 #[argh(subcommand)]
469 pub command: DeviceSubcommand,
470 }
471
472 #[derive(FromArgs)]
473 #[argh(subcommand)]
474 /// Cross-platform Devices
475 pub enum CrossPlatformDevicesCommands {
476 Block(device::BlockOptions),
477 #[cfg(feature = "gpu")]
478 Gpu(device::GpuOptions),
479 Net(device::NetOptions),
480 #[cfg(feature = "audio")]
481 Snd(device::SndOptions),
482 }
483
484 #[derive(argh_helpers::FlattenSubcommand)]
485 pub enum DeviceSubcommand {
486 CrossPlatform(CrossPlatformDevicesCommands),
487 Sys(super::sys::cmdline::DeviceSubcommand),
488 }
489
490 #[cfg(feature = "gpu")]
491 #[derive(FromArgs)]
492 #[argh(subcommand)]
493 pub enum GpuSubCommand {
494 AddDisplays(GpuAddDisplaysCommand),
495 ListDisplays(GpuListDisplaysCommand),
496 RemoveDisplays(GpuRemoveDisplaysCommand),
497 }
498
499 #[cfg(feature = "gpu")]
500 #[derive(FromArgs)]
501 /// Attach a new display to the GPU device.
502 #[argh(subcommand, name = "add-displays")]
503 pub struct GpuAddDisplaysCommand {
504 #[argh(option)]
505 /// displays
506 pub gpu_display: Vec<GpuDisplayParameters>,
507
508 #[argh(positional, arg_name = "VM_SOCKET")]
509 /// VM Socket path
510 pub socket_path: String,
511 }
512
513 #[cfg(feature = "gpu")]
514 #[derive(FromArgs)]
515 /// List the displays currently attached to the GPU device.
516 #[argh(subcommand, name = "list-displays")]
517 pub struct GpuListDisplaysCommand {
518 #[argh(positional, arg_name = "VM_SOCKET")]
519 /// VM Socket path
520 pub socket_path: String,
521 }
522
523 #[cfg(feature = "gpu")]
524 #[derive(FromArgs)]
525 /// Detach an existing display from the GPU device.
526 #[argh(subcommand, name = "remove-displays")]
527 pub struct GpuRemoveDisplaysCommand {
528 #[argh(option)]
529 /// display id
530 pub display_id: Vec<u32>,
531 #[argh(positional, arg_name = "VM_SOCKET")]
532 /// VM Socket path
533 pub socket_path: String,
534 }
535
536 #[derive(FromArgs)]
537 #[argh(subcommand)]
538 pub enum UsbSubCommand {
539 Attach(UsbAttachCommand),
540 Detach(UsbDetachCommand),
541 List(UsbListCommand),
542 }
543
544 #[derive(FromArgs)]
545 /// Attach usb device
546 #[argh(subcommand, name = "attach")]
547 pub struct UsbAttachCommand {
548 #[argh(
549 positional,
550 arg_name = "BUS_ID:ADDR:BUS_NUM:DEV_NUM",
551 from_str_fn(parse_bus_id_addr)
552 )]
553 pub addr: (u8, u8, u16, u16),
554 #[argh(positional)]
555 /// usb device path
556 pub dev_path: String,
557 #[argh(positional, arg_name = "VM_SOCKET")]
558 /// VM Socket path
559 pub socket_path: String,
560 }
561
562 #[derive(FromArgs)]
563 /// Detach usb device
564 #[argh(subcommand, name = "detach")]
565 pub struct UsbDetachCommand {
566 #[argh(positional, arg_name = "PORT")]
567 /// usb port
568 pub port: u8,
569 #[argh(positional, arg_name = "VM_SOCKET")]
570 /// VM Socket path
571 pub socket_path: String,
572 }
573
574 #[derive(FromArgs)]
575 /// Detach usb device
576 #[argh(subcommand, name = "list")]
577 pub struct UsbListCommand {
578 #[argh(positional, arg_name = "VM_SOCKET")]
579 /// VM Socket path
580 pub socket_path: String,
581 }
582
583 /// Structure containing the parameters for a single disk as well as a unique counter increasing
584 /// each time a new disk parameter is parsed.
585 ///
586 /// This allows the letters assigned to each disk to reflect the order of their declaration, as
587 /// we have several options for specifying disks (rwroot, root, etc) and order can thus be lost
588 /// when they are aggregated.
589 #[derive(Deserialize, Debug)]
590 #[serde(deny_unknown_fields, from = "DiskOption")]
591 struct DiskOptionWithId {
592 disk_option: DiskOption,
593 index: usize,
594 }
595
596 /// FromStr implementation for argh.
597 impl FromStr for DiskOptionWithId {
598 type Err = String;
599
from_str(s: &str) -> Result<Self, Self::Err>600 fn from_str(s: &str) -> Result<Self, Self::Err> {
601 let disk_option: DiskOption = from_key_values(s)?;
602 Ok(Self::from(disk_option))
603 }
604 }
605
606 /// Assign the next id to `disk_option`.
607 impl From<DiskOption> for DiskOptionWithId {
from(disk_option: DiskOption) -> Self608 fn from(disk_option: DiskOption) -> Self {
609 static DISK_COUNTER: AtomicUsize = AtomicUsize::new(0);
610 Self {
611 disk_option,
612 index: DISK_COUNTER.fetch_add(1, Ordering::Relaxed),
613 }
614 }
615 }
616
617 #[derive(FromArgs)]
618 #[argh(subcommand, name = "snapshot", description = "Snapshot commands")]
619 /// Snapshot commands
620 pub struct SnapshotCommand {
621 #[argh(subcommand)]
622 pub snapshot_command: SnapshotSubCommands,
623 }
624
625 #[derive(FromArgs)]
626 #[argh(subcommand, name = "take")]
627 /// Take a snapshot of the VM
628 pub struct SnapshotTakeCommand {
629 #[argh(positional, arg_name = "snapshot_path")]
630 /// VM Image path
631 pub snapshot_path: PathBuf,
632 #[argh(positional, arg_name = "VM_SOCKET")]
633 /// VM Socket path
634 pub socket_path: String,
635 }
636
637 #[derive(FromArgs)]
638 #[argh(subcommand, name = "restore")]
639 /// Restore VM state from a snapshot created by take
640 pub struct SnapshotRestoreCommand {
641 #[argh(positional)]
642 /// path to snapshot to restore
643 pub snapshot_path: PathBuf,
644 #[argh(positional, arg_name = "VM_SOCKET")]
645 /// VM Socket path
646 pub socket_path: String,
647 }
648
649 #[derive(FromArgs)]
650 #[argh(subcommand)]
651 /// Snapshot commands
652 pub enum SnapshotSubCommands {
653 Take(SnapshotTakeCommand),
654 Restore(SnapshotRestoreCommand),
655 }
656
657 /// Container for GpuParameters that have been fixed after parsing using serde.
658 ///
659 /// This deserializes as a regular `GpuParameters` and applies validation.
660 #[cfg(feature = "gpu")]
661 #[derive(Debug, Deserialize, FromKeyValues)]
662 #[serde(try_from = "GpuParameters")]
663 pub struct FixedGpuParameters(pub GpuParameters);
664
665 #[cfg(feature = "gpu")]
666 impl TryFrom<GpuParameters> for FixedGpuParameters {
667 type Error = String;
668
try_from(gpu_params: GpuParameters) -> Result<Self, Self::Error>669 fn try_from(gpu_params: GpuParameters) -> Result<Self, Self::Error> {
670 fixup_gpu_options(gpu_params)
671 }
672 }
673
674 /// Container for `GpuDisplayParameters` that have been fixed after parsing using serde.
675 ///
676 /// This deserializes as a regular `GpuDisplayParameters` and applies validation.
677 /// TODO(b/260101753): Remove this once the old syntax for specifying DPI is deprecated.
678 #[cfg(feature = "gpu")]
679 #[derive(Debug, Deserialize, FromKeyValues)]
680 #[serde(try_from = "GpuDisplayParameters")]
681 pub struct FixedGpuDisplayParameters(pub GpuDisplayParameters);
682
683 #[cfg(feature = "gpu")]
684 impl TryFrom<GpuDisplayParameters> for FixedGpuDisplayParameters {
685 type Error = String;
686
try_from(gpu_display_params: GpuDisplayParameters) -> Result<Self, Self::Error>687 fn try_from(gpu_display_params: GpuDisplayParameters) -> Result<Self, Self::Error> {
688 fixup_gpu_display_options(gpu_display_params)
689 }
690 }
691
692 /// Deserialize `config_file` into a `RunCommand`.
693 #[cfg(feature = "config-file")]
load_config_file<P: AsRef<Path>>(config_file: P) -> Result<Box<RunCommand>, String>694 fn load_config_file<P: AsRef<Path>>(config_file: P) -> Result<Box<RunCommand>, String> {
695 let config = std::fs::read_to_string(config_file).map_err(|e| e.to_string())?;
696
697 serde_json::from_str(&config)
698 .map_err(|e| e.to_string())
699 .map(Box::new)
700 }
701
702 /// Overwrite an `Option<T>` if the right member is set.
703 ///
704 /// The default merge strategy for `Option<T>` is to merge `right` into `left` iff `left.is_none()`.
705 /// This doesn't play well with our need to overwrite options that have already been set.
706 ///
707 /// `overwrite_option` merges `right` into `left` iff `right.is_some()`, which allows us to override
708 /// previously-set options.
overwrite_option<T>(left: &mut Option<T>, right: Option<T>)709 fn overwrite_option<T>(left: &mut Option<T>, right: Option<T>) {
710 if right.is_some() {
711 *left = right;
712 }
713 }
714
715 #[allow(dead_code)]
overwrite<T>(left: &mut T, right: T)716 fn overwrite<T>(left: &mut T, right: T) {
717 let _ = std::mem::replace(left, right);
718 }
719
bool_default_true() -> bool720 fn bool_default_true() -> bool {
721 true
722 }
723
724 /// Each field of this structure has a dual use:
725 ///
726 /// 1) As a command-line parameter, controlled by the `#[argh]` helper attribute.
727 /// 2) As a configuration file parameter, controlled by the `#[serde]` helper attribute.
728 ///
729 /// For consistency, the names should be the same and use kebab-case for both uses, so please
730 /// refrain from using renaming directives and give the field the desired parameter name (it will
731 /// automatically be converted to kebab-case).
732 ///
733 /// For consistency and convenience, all parameters should be deserializable by `serde_keyvalue`, as
734 /// this will automatically provide the same schema for both the command-line and configuration
735 /// file. This is particularly important for fields that are enums or structs, for which extra
736 /// parameters can be specified. Make sure to annotate your struct/enum with
737 /// `#[serde(deny_unknown_fields, rename_all = "kebab-case")]` so invalid fields are properly
738 /// rejected and all members are converted to kebab-case.
739 ///
740 /// Each member should also have a `#[merge]` helper attribute, which defines the strategy to use
741 /// when merging two configurations into one. This happens when e.g. the user has specified extra
742 /// command-line arguments along with a configuration file. In this case, the `RunCommand` created
743 /// from the command-line arguments will be merged into the `RunCommand` deserialized from the
744 /// configuration file.
745 ///
746 /// The rule of thumb for `#[merge]` attributes is that parameters that can only be specified once
747 /// (typically of `Option` type) should be overridden (`#[merge(strategy = overwrite_option)]`),
748 /// while parameters that can be specified several times (typically of `Vec` type) should be
749 /// appended (`#[merge(strategy = append)]`), but there might also be exceptions.
750 ///
751 /// The doccomment of the member will be displayed as its help message with `--help`.
752 ///
753 /// Note that many parameters are marked with `#[serde(skip)]` and annotated with b/255223604. This
754 /// is because we only want to enable parameters in the config file after they undergo a proper
755 /// review to make sure they won't be obsoleted.
756 #[remain::sorted]
757 #[argh_helpers::pad_description_for_argh]
758 #[derive(FromArgs, Deserialize, merge::Merge)]
759 #[argh(subcommand, name = "run", description = "Start a new crosvm instance")]
760 #[serde(deny_unknown_fields, rename_all = "kebab-case")]
761 pub struct RunCommand {
762 #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), unix))]
763 #[argh(switch)]
764 #[serde(default)]
765 #[merge(strategy = overwrite_false)]
766 /// enable AC adapter device
767 /// It purpose is to emulate ACPI ACPI0003 device, replicate and propagate the
768 /// ac adapter status from the host to the guest.
769 pub ac_adapter: bool,
770
771 #[cfg(feature = "audio")]
772 #[argh(
773 option,
774 from_str_fn(parse_ac97_options),
775 arg_name = "[backend=BACKEND,capture=true,capture_effect=EFFECT,client_type=TYPE,shm-fd=FD,client-fd=FD,server-fd=FD]"
776 )]
777 #[serde(skip)] // TODO(b/255223604)
778 #[merge(strategy = append)]
779 /// comma separated key=value pairs for setting up Ac97 devices.
780 /// Can be given more than once.
781 /// Possible key values:
782 /// backend=(null, cras) - Where to route the audio
783 /// device. If not provided, backend will default to
784 /// null. `null` for /dev/null, cras for CRAS server.
785 /// capture - Enable audio capture
786 /// capture_effects - | separated effects to be enabled for
787 /// recording. The only supported effect value now is
788 /// EchoCancellation or aec.
789 /// client_type - Set specific client type for cras backend.
790 /// socket_type - Set specific socket type for cras backend.
791 pub ac97: Vec<Ac97Parameters>,
792
793 #[argh(option, arg_name = "PATH")]
794 #[serde(skip)] // TODO(b/255223604)
795 #[merge(strategy = append)]
796 /// path to user provided ACPI table
797 pub acpi_table: Vec<PathBuf>,
798
799 #[argh(option)]
800 #[serde(skip)] // TODO(b/255223604)
801 #[merge(strategy = overwrite_option)]
802 /// path to Android fstab
803 pub android_fstab: Option<PathBuf>,
804
805 /// configure async executor backend; "uring" or "epoll" on Linux, "handle" on Windows.
806 /// If this option is omitted on Linux, "epoll" is used by default.
807 #[argh(option, arg_name = "EXECUTOR")]
808 #[serde(skip)] // TODO(b/255223604)
809 pub async_executor: Option<ExecutorKind>,
810
811 #[argh(option, arg_name = "N")]
812 #[serde(skip)] // TODO(b/255223604)
813 #[merge(strategy = overwrite_option)]
814 /// amount to bias balance of memory between host and guest as the balloon inflates, in mib.
815 pub balloon_bias_mib: Option<i64>,
816
817 #[argh(option, arg_name = "PATH")]
818 #[serde(skip)] // TODO(b/255223604)
819 #[merge(strategy = overwrite_option)]
820 /// path for balloon controller socket.
821 pub balloon_control: Option<PathBuf>,
822
823 #[argh(switch)]
824 #[serde(skip)] // TODO(b/255223604)
825 #[merge(strategy = overwrite_false)]
826 /// enable page reporting in balloon.
827 pub balloon_page_reporting: bool,
828
829 #[argh(switch)]
830 #[serde(skip)] // TODO(b/255223604)
831 #[merge(strategy = overwrite_false)]
832 /// enable working set size reporting in balloon.
833 pub balloon_wss_reporting: bool,
834
835 #[argh(option)]
836 /// comma separated key=value pairs for setting up battery
837 /// device
838 /// Possible key values:
839 /// type=goldfish - type of battery emulation, defaults to
840 /// goldfish
841 #[merge(strategy = overwrite_option)]
842 pub battery: Option<BatteryConfig>,
843
844 #[argh(option)]
845 #[serde(skip)] // TODO(b/255223604)
846 #[merge(strategy = overwrite_option)]
847 /// path to BIOS/firmware ROM
848 pub bios: Option<PathBuf>,
849
850 #[argh(option, short = 'b', arg_name = "PATH[,key=value[,key=value[,...]]]")]
851 #[serde(default)]
852 #[merge(strategy = append)]
853 /// parameters for setting up a block device.
854 /// Valid keys:
855 /// path=PATH - Path to the disk image. Can be specified
856 /// without the key as the first argument.
857 /// ro=BOOL - Whether the block should be read-only.
858 /// (default: false)
859 /// root=BOOL - Whether the block device should be mounted
860 /// as the root filesystem. This will add the required
861 /// parameters to the kernel command-line. Can only be
862 /// specified once. (default: false)
863 /// sparse=BOOL - Indicates whether the disk should support
864 /// the discard operation. (default: true)
865 /// block-size=BYTES - Set the reported block size of the
866 /// disk. (default: 512)
867 /// id=STRING - Set the block device identifier to an ASCII
868 /// string, up to 20 characters. (default: no ID)
869 /// direct=BOOL - Use O_DIRECT mode to bypass page cache.
870 /// (default: false)
871 /// async-executor=epoll|uring - set the async executor kind
872 /// to simulate the block device with. This takes
873 /// precedence over the global --async-executor option.
874 /// multiple-workers=BOOL - (Experimental) run multiple
875 /// worker threads in parallel. this option is not
876 /// effective for vhost-user blk device.
877 /// (default: false)
878 block: Vec<DiskOptionWithId>,
879
880 /// ratelimit enforced on detected bus locks in guest.
881 /// The default value of the bus_lock_ratelimit is 0 per second,
882 /// which means no limitation on the guest's bus locks.
883 #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), unix))]
884 #[argh(option)]
885 pub bus_lock_ratelimit: Option<u64>,
886
887 #[cfg(feature = "config-file")]
888 #[argh(option, arg_name = "CONFIG_FILE", from_str_fn(load_config_file))]
889 // TODO(b/218223240) We only allow one configuration file because accurate merging is not
890 // possible on boolean fields. We would need to convert these to `Option<bool>` but
891 // unfortunately argh is currently unable to recognize these as switches.
892 //
893 // For now, we only allow one configuration file to be specified. Since argh's switches can
894 // only be true, and the command-line parameters are merged last, merging using
895 // `merging::overwrite_false` is guaranteed to be accurate since only true values can be
896 // explicitly specified through the command-line.
897 //
898 // Eventually we will want to turn this into a `Vec<Self>` so several configuration files can
899 // be passed, and remove the `#[serde(skip)]` attribute so they can be included from other
900 // configuration files as well.
901 #[serde(skip)]
902 #[merge(skip)]
903 /// path to a JSON configuration file to load.
904 ///
905 /// The options specified in the file can be overridden or augmented by other command-line
906 /// parameters.
907 cfg: Option<Box<Self>>,
908
909 #[argh(option, arg_name = "CID")]
910 #[serde(skip)] // Deprecated - use `vsock` instead.
911 #[merge(strategy = overwrite_option)]
912 /// context ID for virtual sockets.
913 pub cid: Option<u64>,
914
915 #[cfg(unix)]
916 #[argh(
917 option,
918 arg_name = "unpin_policy=POLICY,unpin_interval=NUM,unpin_limit=NUM,unpin_gen_threshold=NUM"
919 )]
920 #[serde(skip)] // TODO(b/255223604)
921 #[merge(strategy = overwrite_option)]
922 /// comma separated key=value pairs for setting up coiommu
923 /// devices.
924 /// Possible key values:
925 /// unpin_policy=lru - LRU unpin policy.
926 /// unpin_interval=NUM - Unpin interval time in seconds.
927 /// unpin_limit=NUM - Unpin limit for each unpin cycle, in
928 /// unit of page count. 0 is invalid.
929 /// unpin_gen_threshold=NUM - Number of unpin intervals a
930 /// pinned page must be busy for to be aged into the
931 /// older which is less frequently checked generation.
932 pub coiommu: Option<devices::CoIommuParameters>,
933
934 #[argh(option, default = "true")]
935 #[merge(strategy = overwrite)]
936 #[serde(default = "bool_default_true")]
937 /// protect VM threads from hyperthreading-based attacks by scheduling them on different cores.
938 /// Enabled by default, and required for per_vm_core_scheduling.
939 pub core_scheduling: bool,
940
941 #[argh(option, arg_name = "CPUSET", from_str_fn(parse_cpu_affinity))]
942 #[serde(skip)] // TODO(b/255223604)
943 #[merge(strategy = overwrite_option)]
944 /// comma-separated list of CPUs or CPU ranges to run VCPUs on (e.g. 0,1-3,5)
945 /// or colon-separated list of assignments of guest to host CPU assignments (e.g. 0=0:1=1:2=2) (default: no mask)
946 pub cpu_affinity: Option<VcpuAffinity>,
947
948 #[argh(
949 option,
950 arg_name = "CPU=CAP[,CPU=CAP[,...]]",
951 from_str_fn(parse_cpu_capacity)
952 )]
953 #[serde(skip)] // TODO(b/255223604)
954 #[merge(strategy = overwrite_option)]
955 /// set the relative capacity of the given CPU (default: no capacity)
956 pub cpu_capacity: Option<BTreeMap<usize, u32>>, // CPU index -> capacity
957
958 #[argh(option, arg_name = "CPUSET")]
959 #[serde(skip)] // Deprecated - use `cpu clusters=[...]` instead.
960 #[merge(strategy = append)]
961 /// group the given CPUs into a cluster (default: no clusters)
962 pub cpu_cluster: Vec<CpuSet>,
963
964 #[argh(option, short = 'c')]
965 #[merge(strategy = overwrite_option)]
966 /// cpu parameters.
967 /// Possible key values:
968 /// num-cores=NUM - number of VCPUs. (default: 1)
969 /// clusters=[[CLUSTER],...] - CPU clusters (default: None)
970 /// Each CLUSTER is a set containing a list of CPUs
971 /// that should belong to the same cluster. Individual
972 /// CPU ids or ranges can be specified, comma-separated.
973 /// Examples:
974 /// clusters=[[0],[1],[2],[3]] - creates 4 clusters, one
975 /// for each specified core.
976 /// clusters=[[0-3]] - creates a cluster for cores 0 to 3
977 /// included.
978 /// clusters=[[0,2],[1,3],[4-7,12]] - creates one cluster
979 /// for cores 0 and 2, another one for cores 1 and 3,
980 /// and one last for cores 4, 5, 6, 7 and 12.
981 /// core-types=[atom=[CPUSET],core=[CPUSET]] - Hybrid core types. (default: None)
982 /// Set the type of virtual hybrid CPUs. Now it supports
983 /// to set intel Atom or intel Core types.
984 /// Examples:
985 /// core-types=[atom=[0,1],core=[2,3]] - set vCPU 0 and
986 /// vCPU 1 as intel Atom type, also set vCPU 2 and vCPU 3
987 /// as intel Core type.
988 pub cpus: Option<CpuOptions>,
989
990 #[cfg(feature = "crash-report")]
991 #[argh(option, arg_name = "\\\\.\\pipe\\PIPE_NAME")]
992 #[serde(skip)] // TODO(b/255223604)
993 #[merge(strategy = overwrite_option)]
994 /// the crash handler ipc pipe name.
995 pub crash_pipe_name: Option<String>,
996
997 #[argh(switch)]
998 #[serde(skip)] // TODO(b/255223604)
999 #[merge(strategy = overwrite_false)]
1000 /// don't set VCPUs real-time until make-rt command is run
1001 pub delay_rt: bool,
1002
1003 #[cfg(feature = "direct")]
1004 #[argh(option, arg_name = "irq")]
1005 #[serde(skip)] // TODO(b/255223604)
1006 #[merge(strategy = overwrite)]
1007 /// enable interrupt passthrough
1008 pub direct_edge_irq: Vec<u32>,
1009
1010 #[cfg(feature = "direct")]
1011 #[argh(option, arg_name = "event=gbllock|powerbtn|sleepbtn|rtc")]
1012 #[serde(skip)] // TODO(b/255223604)
1013 #[merge(strategy = overwrite)]
1014 /// enable ACPI fixed event interrupt and register access passthrough
1015 pub direct_fixed_event: Vec<devices::ACPIPMFixedEvent>,
1016
1017 #[cfg(feature = "direct")]
1018 #[argh(option, arg_name = "gpe")]
1019 #[serde(skip)] // TODO(b/255223604)
1020 #[merge(strategy = overwrite)]
1021 /// enable GPE interrupt and register access passthrough
1022 pub direct_gpe: Vec<u32>,
1023
1024 #[cfg(feature = "direct")]
1025 #[argh(option, arg_name = "irq")]
1026 #[serde(skip)] // TODO(b/255223604)
1027 #[merge(strategy = overwrite)]
1028 /// enable interrupt passthrough
1029 pub direct_level_irq: Vec<u32>,
1030
1031 #[cfg(feature = "direct")]
1032 #[argh(
1033 option,
1034 arg_name = "PATH@RANGE[,RANGE[,...]]",
1035 from_str_fn(parse_direct_io_options)
1036 )]
1037 #[serde(skip)] // TODO(b/255223604)
1038 #[merge(strategy = overwrite_option)]
1039 /// path and ranges for direct memory mapped I/O access. RANGE may be decimal or hex (starting with 0x)
1040 pub direct_mmio: Option<DirectIoOption>,
1041
1042 #[cfg(feature = "direct")]
1043 #[argh(
1044 option,
1045 arg_name = "PATH@RANGE[,RANGE[,...]]",
1046 from_str_fn(parse_direct_io_options)
1047 )]
1048 #[serde(skip)] // TODO(b/255223604)
1049 #[merge(strategy = overwrite_option)]
1050 /// path and ranges for direct port mapped I/O access. RANGE may be decimal or hex (starting with 0x)
1051 pub direct_pmio: Option<DirectIoOption>,
1052
1053 #[argh(switch)]
1054 #[serde(skip)] // TODO(b/255223604)
1055 #[merge(strategy = overwrite_false)]
1056 /// run all devices in one, non-sandboxed process
1057 pub disable_sandbox: bool,
1058
1059 #[argh(switch)]
1060 #[serde(skip)] // TODO(b/255223604)
1061 #[merge(strategy = overwrite_false)]
1062 /// disable INTx in virtio devices
1063 pub disable_virtio_intx: bool,
1064
1065 #[argh(option, short = 'd', arg_name = "PATH[,key=value[,key=value[,...]]]")]
1066 #[serde(skip)] // Deprecated - use `block` instead.
1067 #[merge(strategy = append)]
1068 /// path to a disk image followed by optional comma-separated
1069 /// options.
1070 /// Valid keys:
1071 /// sparse=BOOL - Indicates whether the disk should support
1072 /// the discard operation (default: true)
1073 /// block_size=BYTES - Set the reported block size of the
1074 /// disk (default: 512)
1075 /// id=STRING - Set the block device identifier to an ASCII
1076 /// string, up to 20 characters (default: no ID)
1077 /// o_direct=BOOL - Use O_DIRECT mode to bypass page cache"
1078 disk: Vec<DiskOptionWithId>,
1079
1080 #[argh(switch)]
1081 #[serde(skip)] // TODO(b/255223604)
1082 #[merge(strategy = overwrite_false)]
1083 /// capture keyboard input from the display window
1084 pub display_window_keyboard: bool,
1085
1086 #[argh(switch)]
1087 #[serde(skip)] // TODO(b/255223604)
1088 #[merge(strategy = overwrite_false)]
1089 /// capture keyboard input from the display window
1090 pub display_window_mouse: bool,
1091
1092 #[argh(option, arg_name = "DIR")]
1093 #[serde(skip)] // TODO(b/255223604)
1094 #[merge(strategy = overwrite_option)]
1095 /// directory with smbios_entry_point/DMI files
1096 pub dmi: Option<PathBuf>,
1097
1098 #[argh(option, long = "dump-device-tree-blob", arg_name = "FILE")]
1099 #[serde(skip)] // TODO(b/255223604)
1100 #[merge(strategy = overwrite_option)]
1101 /// dump generated device tree as a DTB file
1102 pub dump_device_tree_blob: Option<PathBuf>,
1103
1104 #[argh(switch)]
1105 #[serde(skip)] // TODO(b/255223604)
1106 #[merge(strategy = overwrite_false)]
1107 /// expose HWP feature to the guest
1108 pub enable_hwp: bool,
1109
1110 #[argh(switch)]
1111 #[serde(skip)] // TODO(b/255223604)
1112 #[merge(strategy = overwrite_false)]
1113 /// expose Power and Perfomance (PnP) data to guest and guest can show these PnP data
1114 pub enable_pnp_data: bool,
1115
1116 #[argh(option, arg_name = "PATH")]
1117 #[serde(skip)] // TODO(b/255223604)
1118 #[merge(strategy = append)]
1119 /// path to an event device node. The device will be grabbed (unusable from the host) and made available to the guest with the same configuration it shows on the host
1120 pub evdev: Vec<PathBuf>,
1121
1122 #[cfg(windows)]
1123 #[argh(switch)]
1124 #[serde(skip)] // TODO(b/255223604)
1125 #[merge(strategy = overwrite_false)]
1126 /// gather and display statistics on Vm Exits and Bus Reads/Writes.
1127 pub exit_stats: bool,
1128
1129 #[argh(
1130 option,
1131 arg_name = "addr=NUM,size=SIZE,path=PATH[,offset=NUM][,rw][,sync]"
1132 )]
1133 #[serde(skip)] // TODO(b/255223604)
1134 #[merge(strategy = append)]
1135 /// map the given file into guest memory at the specified
1136 /// address.
1137 /// Parameters (addr, size, path are required):
1138 /// addr=NUM - guest physical address to map at
1139 /// size=NUM - amount of memory to map
1140 /// path=PATH - path to backing file/device to map
1141 /// offset=NUM - offset in backing file (default 0)
1142 /// rw - make the mapping writable (default readonly)
1143 /// sync - open backing file with O_SYNC
1144 /// align - whether to adjust addr and size to page
1145 /// boundaries implicitly
1146 pub file_backed_mapping: Vec<FileBackedMappingParameters>,
1147
1148 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
1149 #[argh(switch)]
1150 #[serde(skip)] // TODO(b/255223604)
1151 #[merge(strategy = overwrite_false)]
1152 /// force use of a calibrated TSC cpuid leaf (0x15) even if the hypervisor
1153 /// doesn't require one.
1154 pub force_calibrated_tsc_leaf: bool,
1155
1156 #[cfg(feature = "gdb")]
1157 #[argh(option, arg_name = "PORT")]
1158 #[merge(strategy = overwrite_option)]
1159 /// (EXPERIMENTAL) gdb on the given port
1160 pub gdb: Option<u32>,
1161
1162 #[cfg(feature = "gpu")]
1163 #[argh(option)]
1164 // Although `gpu` is a vector, we are currently limited to a single GPU device due to the
1165 // resource bridge and interaction with other video devices. We do use a vector so the GPU
1166 // device can be specified like other device classes in the configuration file, and because we
1167 // hope to lift this limitation eventually.
1168 #[serde(skip)] // TODO(b/255223604)
1169 #[merge(strategy = append)]
1170 /// (EXPERIMENTAL) Comma separated key=value pairs for setting
1171 /// up a virtio-gpu device
1172 /// Possible key values:
1173 /// backend=(2d|virglrenderer|gfxstream) - Which backend to
1174 /// use for virtio-gpu (determining rendering protocol)
1175 /// displays=[[GpuDisplayParameters]] - The list of virtual
1176 /// displays to create. See the possible key values for
1177 /// GpuDisplayParameters in the section below.
1178 /// context-types=LIST - The list of supported context
1179 /// types, separated by ':' (default: no contexts enabled)
1180 /// width=INT - The width of the virtual display connected
1181 /// to the virtio-gpu.
1182 /// Deprecated - use `displays` instead.
1183 /// height=INT - The height of the virtual display
1184 /// connected to the virtio-gpu.
1185 /// Deprecated - use `displays` instead.
1186 /// egl[=true|=false] - If the backend should use a EGL
1187 /// context for rendering.
1188 /// glx[=true|=false] - If the backend should use a GLX
1189 /// context for rendering.
1190 /// surfaceless[=true|=false] - If the backend should use a
1191 /// surfaceless context for rendering.
1192 /// angle[=true|=false] - If the gfxstream backend should
1193 /// use ANGLE (OpenGL on Vulkan) as its native OpenGL
1194 /// driver.
1195 /// vulkan[=true|=false] - If the backend should support
1196 /// vulkan
1197 /// wsi=vk - If the gfxstream backend should use the Vulkan
1198 /// swapchain to draw on a window
1199 /// cache-path=PATH - The path to the virtio-gpu device
1200 /// shader cache.
1201 /// cache-size=SIZE - The maximum size of the shader cache.
1202 /// pci-bar-size=SIZE - The size for the PCI BAR in bytes
1203 /// (default 8gb).
1204 ///
1205 /// Possible key values for GpuDisplayParameters:
1206 /// mode=(borderless_full_screen|windowed[width,height]) -
1207 /// Whether to show the window on the host in full
1208 /// screen or windowed mode. If not specified, windowed
1209 /// mode is used by default. "windowed" can also be
1210 /// specified explicitly to use a window size different
1211 /// from the default one.
1212 /// hidden[=true|=false] - If the display window is
1213 /// initially hidden (default: false).
1214 /// refresh-rate=INT - Force a specific vsync generation
1215 /// rate in hertz on the guest (default: 60)
1216 /// dpi=[INT,INT] - The horizontal and vertical DPI of the
1217 /// display (default: [320,320])
1218 /// horizontal-dpi=INT - The horizontal DPI of the display
1219 /// (default: 320)
1220 /// Deprecated - use `dpi` instead.
1221 /// vertical-dpi=INT - The vertical DPI of the display
1222 /// (default: 320)
1223 /// Deprecated - use `dpi` instead.
1224 pub gpu: Vec<FixedGpuParameters>,
1225
1226 #[cfg(all(unix, feature = "gpu"))]
1227 #[argh(option, arg_name = "PATH")]
1228 #[serde(skip)] // TODO(b/255223604)
1229 #[merge(strategy = overwrite_option)]
1230 /// move all vGPU threads to this Cgroup (default: nothing moves)
1231 pub gpu_cgroup_path: Option<PathBuf>,
1232
1233 #[cfg(feature = "gpu")]
1234 #[argh(option)]
1235 #[serde(skip)] // TODO(b/255223604). Deprecated - use `gpu` instead.
1236 #[merge(strategy = append)]
1237 /// (EXPERIMENTAL) Comma separated key=value pairs for setting
1238 /// up a display on the virtio-gpu device. See comments for `gpu`
1239 /// for possible key values of GpuDisplayParameters.
1240 pub gpu_display: Vec<FixedGpuDisplayParameters>,
1241
1242 #[cfg(all(unix, feature = "gpu", feature = "virgl_renderer_next"))]
1243 #[argh(option)]
1244 #[serde(skip)] // TODO(b/255223604)
1245 #[merge(strategy = overwrite_option)]
1246 /// (EXPERIMENTAL) Comma separated key=value pairs for setting
1247 /// up a render server for the virtio-gpu device
1248 /// Possible key values:
1249 /// path=PATH - The path to the render server executable.
1250 /// cache-path=PATH - The path to the render server shader
1251 /// cache.
1252 /// cache-size=SIZE - The maximum size of the shader cache
1253 /// foz-db-list-path=PATH - The path to GPU foz db list
1254 /// file for dynamically loading RO caches.
1255 pub gpu_render_server: Option<GpuRenderServerParameters>,
1256
1257 #[cfg(all(unix, feature = "gpu"))]
1258 #[argh(option, arg_name = "PATH")]
1259 #[serde(skip)] // TODO(b/255223604)
1260 #[merge(strategy = overwrite_option)]
1261 /// move all vGPU server threads to this Cgroup (default: nothing moves)
1262 pub gpu_server_cgroup_path: Option<PathBuf>,
1263
1264 #[argh(switch)]
1265 #[serde(skip)] // TODO(b/255223604)
1266 #[merge(strategy = overwrite_false)]
1267 /// use mirror cpu topology of Host for Guest VM, also copy some cpu feature to Guest VM
1268 pub host_cpu_topology: bool,
1269
1270 #[cfg(windows)]
1271 #[argh(option, arg_name = "PATH")]
1272 #[serde(skip)] // TODO(b/255223604)
1273 #[merge(strategy = overwrite_option)]
1274 /// string representation of the host guid in registry format, for namespacing vsock connections.
1275 pub host_guid: Option<String>,
1276
1277 #[cfg(unix)]
1278 #[argh(option, arg_name = "IP")]
1279 #[serde(skip)] // Deprecated - use `net` instead.
1280 #[merge(strategy = overwrite_option)]
1281 /// IP address to assign to host tap interface
1282 pub host_ip: Option<net::Ipv4Addr>,
1283
1284 #[argh(switch)]
1285 #[serde(skip)] // TODO(b/255223604)
1286 #[merge(strategy = overwrite_false)]
1287 /// advise the kernel to use Huge Pages for guest memory mappings
1288 pub hugepages: bool,
1289
1290 /// hypervisor backend
1291 #[argh(option)]
1292 #[merge(strategy = overwrite_option)]
1293 pub hypervisor: Option<HypervisorKind>,
1294
1295 #[argh(option, arg_name = "N")]
1296 #[serde(skip)] // TODO(b/255223604)
1297 #[merge(strategy = overwrite_option)]
1298 /// amount of guest memory outside the balloon at boot in MiB. (default: --mem)
1299 pub init_mem: Option<u64>,
1300
1301 #[argh(option, short = 'i', arg_name = "PATH")]
1302 #[merge(strategy = overwrite_option)]
1303 /// initial ramdisk to load
1304 pub initrd: Option<PathBuf>,
1305
1306 #[cfg(windows)]
1307 #[argh(option, arg_name = "kernel|split|userspace")]
1308 #[serde(skip)] // TODO(b/255223604)
1309 #[merge(strategy = overwrite_option)]
1310 /// type of interrupt controller emulation. \"split\" is only available for x86 KVM.
1311 pub irqchip: Option<IrqChipKind>,
1312
1313 #[argh(switch)]
1314 #[serde(skip)] // TODO(b/255223604)
1315 #[merge(strategy = overwrite_false)]
1316 /// allow to enable ITMT scheduling feature in VM. The success of enabling depends on HWP and ACPI CPPC support on hardware
1317 pub itmt: bool,
1318
1319 #[argh(positional, arg_name = "KERNEL")]
1320 #[merge(strategy = overwrite_option)]
1321 /// bzImage of kernel to run
1322 pub kernel: Option<PathBuf>,
1323
1324 #[cfg(windows)]
1325 #[argh(option, arg_name = "PATH")]
1326 #[serde(skip)] // TODO(b/255223604)
1327 #[merge(strategy = overwrite_option)]
1328 /// forward hypervisor kernel driver logs for this VM to a file.
1329 pub kernel_log_file: Option<String>,
1330
1331 #[argh(option, arg_name = "PATH")]
1332 #[serde(skip)] // TODO(b/255223604)
1333 #[merge(strategy = append)]
1334 /// path to a socket from where to read keyboard input events and write status updates to
1335 pub keyboard: Vec<PathBuf>,
1336
1337 #[cfg(unix)]
1338 #[argh(option, arg_name = "PATH")]
1339 #[serde(skip)] // Deprecated - use `hypervisor` instead.
1340 #[merge(strategy = overwrite_option)]
1341 /// path to the KVM device. (default /dev/kvm)
1342 pub kvm_device: Option<PathBuf>,
1343
1344 #[cfg(unix)]
1345 #[argh(switch)]
1346 #[serde(skip)] // TODO(b/255223604)
1347 #[merge(strategy = overwrite_false)]
1348 /// disable host swap on guest VM pages.
1349 pub lock_guest_memory: bool,
1350
1351 #[cfg(windows)]
1352 #[argh(option, arg_name = "PATH")]
1353 #[serde(skip)] // TODO(b/255223604)
1354 #[merge(strategy = overwrite_option)]
1355 /// redirect logs to the supplied log file at PATH rather than stderr. For multi-process mode, use --logs-directory instead
1356 pub log_file: Option<String>,
1357
1358 #[cfg(windows)]
1359 #[argh(option, arg_name = "PATH")]
1360 #[serde(skip)] // TODO(b/255223604)
1361 #[merge(strategy = overwrite_option)]
1362 /// path to the logs directory used for crosvm processes. Logs will be sent to stderr if unset, and stderr/stdout will be uncaptured
1363 pub logs_directory: Option<String>,
1364
1365 #[cfg(unix)]
1366 #[argh(option, arg_name = "MAC", long = "mac")]
1367 #[serde(skip)] // Deprecated - use `net` instead.
1368 #[merge(strategy = overwrite_option)]
1369 /// MAC address for VM
1370 pub mac_address: Option<net_util::MacAddress>,
1371
1372 #[argh(option, short = 'm', arg_name = "N")]
1373 #[merge(strategy = overwrite_option)]
1374 /// memory parameters.
1375 /// Possible key values:
1376 /// size=NUM - amount of guest memory in MiB. (default: 256)
1377 pub mem: Option<MemOptions>,
1378
1379 #[argh(option, from_str_fn(parse_mmio_address_range))]
1380 #[serde(skip)] // TODO(b/255223604)
1381 #[merge(strategy = overwrite_option)]
1382 /// MMIO address ranges
1383 pub mmio_address_range: Option<Vec<AddressRange>>,
1384
1385 #[argh(option, arg_name = "PATH")]
1386 #[serde(skip)] // TODO(b/255223604)
1387 #[merge(strategy = append)]
1388 /// path to a socket from where to read mouse input events and write status updates to
1389 pub mouse: Vec<PathBuf>,
1390
1391 #[cfg(target_arch = "aarch64")]
1392 #[argh(switch)]
1393 #[serde(skip)] // TODO(b/255223604)
1394 #[merge(strategy = overwrite_false)]
1395 /// enable the Memory Tagging Extension in the guest
1396 pub mte: bool,
1397
1398 #[argh(option, arg_name = "PATH:WIDTH:HEIGHT")]
1399 #[serde(skip)] // TODO(b/255223604)
1400 #[merge(strategy = append)]
1401 /// path to a socket from where to read multi touch input events (such as those from a touchscreen) and write status updates to, optionally followed by width and height (defaults to 800x1280)
1402 pub multi_touch: Vec<TouchDeviceOption>,
1403
1404 #[cfg(unix)]
1405 #[argh(
1406 option,
1407 arg_name = "(tap-name=TAP_NAME,mac=MAC_ADDRESS|tap-fd=TAP_FD,mac=MAC_ADDRESS|host-ip=IP,netmask=NETMASK,mac=MAC_ADDRESS),vhost-net=VHOST_NET,vq-pairs=N"
1408 )]
1409 #[serde(default)]
1410 #[merge(strategy = append)]
1411 /// comma separated key=value pairs for setting up a network
1412 /// device.
1413 /// Possible key values:
1414 /// (
1415 /// tap-name=STRING - name of a configured persistent TAP
1416 /// interface to use for networking.
1417 /// mac=STRING - MAC address for VM. [Optional]
1418 /// OR
1419 /// tap-fd=INT - File descriptor for configured tap
1420 /// device.
1421 /// mac=STRING - MAC address for VM. [Optional]
1422 /// OR
1423 /// (
1424 /// host-ip=STRING - IP address to assign to host tap
1425 /// interface.
1426 /// AND
1427 /// netmask=STRING - Netmask for VM subnet.
1428 /// AND
1429 /// mac=STRING - MAC address for VM.
1430 /// )
1431 /// )
1432 /// AND
1433 /// vhost-net=BOOL - whether enable vhost_net or not.
1434 /// Default: false. [Optional]
1435 /// vq-pairs=N - number of rx/tx queue pairs.
1436 /// Default: 1. [Optional]
1437 ///
1438 /// Either one tap_name, one tap_fd or a triplet of host_ip,
1439 /// netmask and mac must be specified.
1440 pub net: Vec<NetParameters>,
1441
1442 #[cfg(unix)]
1443 #[argh(option, arg_name = "N")]
1444 #[serde(skip)] // Deprecated - use `net` instead.
1445 #[merge(strategy = overwrite_option)]
1446 /// virtio net virtual queue pairs. (default: 1)
1447 pub net_vq_pairs: Option<u16>,
1448
1449 #[cfg(unix)]
1450 #[argh(option, arg_name = "NETMASK")]
1451 #[serde(skip)] // Deprecated - use `net` instead.
1452 #[merge(strategy = overwrite_option)]
1453 /// netmask for VM subnet
1454 pub netmask: Option<net::Ipv4Addr>,
1455
1456 #[argh(switch)]
1457 #[serde(skip)] // TODO(b/255223604)
1458 #[merge(strategy = overwrite_false)]
1459 /// don't use virtio-balloon device in the guest
1460 pub no_balloon: bool,
1461
1462 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
1463 #[argh(switch)]
1464 #[serde(skip)] // TODO(b/255223604)
1465 #[merge(strategy = overwrite_false)]
1466 /// don't use legacy KBD devices emulation
1467 pub no_i8042: bool,
1468
1469 #[argh(switch)]
1470 #[serde(skip)] // TODO(b/255223604)
1471 #[merge(strategy = overwrite_false)]
1472 /// don't create RNG device in the guest
1473 pub no_rng: bool,
1474
1475 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
1476 #[argh(switch)]
1477 #[serde(skip)] // TODO(b/255223604)
1478 #[merge(strategy = overwrite_false)]
1479 /// don't use legacy RTC devices emulation
1480 pub no_rtc: bool,
1481
1482 #[argh(switch)]
1483 #[serde(skip)] // TODO(b/255223604)
1484 #[merge(strategy = overwrite_false)]
1485 /// don't use SMT in the guest
1486 pub no_smt: bool,
1487
1488 #[argh(switch)]
1489 #[serde(skip)] // TODO(b/255223604)
1490 #[merge(strategy = overwrite_false)]
1491 /// don't use usb devices in the guest
1492 pub no_usb: bool,
1493
1494 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
1495 #[argh(option, arg_name = "OEM_STRING")]
1496 #[serde(skip)] // TODO(b/255223604)
1497 #[merge(strategy = append)]
1498 /// SMBIOS OEM string values to add to the DMI tables
1499 pub oem_strings: Vec<String>,
1500
1501 #[argh(option, short = 'p', arg_name = "PARAMS")]
1502 #[serde(default)]
1503 #[merge(strategy = append)]
1504 /// extra kernel or plugin command line arguments. Can be given more than once
1505 pub params: Vec<String>,
1506
1507 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
1508 #[argh(option, arg_name = "pci_low_mmio_start")]
1509 #[serde(skip)] // TODO(b/255223604)
1510 #[merge(strategy = overwrite_option)]
1511 /// the pci mmio start address below 4G
1512 pub pci_start: Option<u64>,
1513
1514 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
1515 #[argh(
1516 option,
1517 arg_name = "mmio_base,mmio_length",
1518 from_str_fn(parse_memory_region)
1519 )]
1520 #[serde(skip)] // TODO(b/255223604)
1521 #[merge(strategy = overwrite_option)]
1522 /// region for PCIe Enhanced Configuration Access Mechanism
1523 pub pcie_ecam: Option<AddressRange>,
1524
1525 #[cfg(feature = "direct")]
1526 #[argh(
1527 option,
1528 arg_name = "PATH[,hp_gpe=NUM]",
1529 from_str_fn(parse_pcie_root_port_params)
1530 )]
1531 #[serde(skip)] // TODO(b/255223604)
1532 #[merge(strategy = overwrite)]
1533 /// path to sysfs of host pcie root port and host pcie root port hotplug gpe number
1534 pub pcie_root_port: Vec<HostPcieRootPortParameters>,
1535
1536 #[argh(switch)]
1537 #[serde(skip)] // TODO(b/255223604)
1538 #[merge(strategy = overwrite_false)]
1539 /// enable per-VM core scheduling intead of the default one (per-vCPU core scheduing) by
1540 /// making all vCPU threads share same cookie for core scheduling.
1541 /// This option is no-op on devices that have neither MDS nor L1TF vulnerability
1542 pub per_vm_core_scheduling: bool,
1543
1544 #[argh(
1545 option,
1546 arg_name = "path=PATH,[block_size=SIZE]",
1547 from_str_fn(parse_pflash_parameters)
1548 )]
1549 #[serde(skip)] // TODO(b/255223604)
1550 #[merge(strategy = overwrite_option)]
1551 /// comma-seperated key-value pair for setting up the pflash device, which provides space to store UEFI variables.
1552 /// block_size defaults to 4K.
1553 /// [--pflash <path=PATH,[block_size=SIZE]>]
1554 pub pflash: Option<PflashParameters>,
1555
1556 #[argh(option, arg_name = "PATH")]
1557 #[serde(skip)] // TODO(b/255223604)
1558 #[merge(strategy = overwrite_option)]
1559 /// path to empty directory to use for sandbox pivot root
1560 pub pivot_root: Option<PathBuf>,
1561
1562 #[cfg(feature = "plugin")]
1563 #[argh(option, arg_name = "PATH")]
1564 #[serde(skip)] // TODO(b/255223604)
1565 #[merge(strategy = overwrite_option)]
1566 /// absolute path to plugin process to run under crosvm
1567 pub plugin: Option<PathBuf>,
1568
1569 #[cfg(feature = "plugin")]
1570 #[argh(option, arg_name = "GID:GID:INT")]
1571 #[serde(skip)] // TODO(b/255223604)
1572 #[merge(strategy = append)]
1573 /// supplemental GIDs that should be mapped in plugin jail. Can be given more than once
1574 pub plugin_gid_map: Vec<GidMap>,
1575
1576 #[cfg(feature = "plugin")]
1577 #[argh(option)]
1578 #[serde(skip)] // TODO(b/255223604)
1579 #[merge(strategy = overwrite_option)]
1580 /// path to the file listing supplemental GIDs that should be mapped in plugin jail. Can be given more than once
1581 pub plugin_gid_map_file: Option<PathBuf>,
1582
1583 #[cfg(feature = "plugin")]
1584 #[argh(option, arg_name = "PATH:PATH:BOOL")]
1585 #[serde(skip)] // TODO(b/255223604)
1586 #[merge(strategy = append)]
1587 /// path to be mounted into the plugin's root filesystem. Can be given more than once
1588 pub plugin_mount: Vec<BindMount>,
1589
1590 #[cfg(feature = "plugin")]
1591 #[argh(option, arg_name = "PATH")]
1592 #[serde(skip)] // TODO(b/255223604)
1593 #[merge(strategy = overwrite_option)]
1594 /// path to the file listing paths be mounted into the plugin's root filesystem. Can be given more than once
1595 pub plugin_mount_file: Option<PathBuf>,
1596
1597 #[cfg(feature = "plugin")]
1598 #[argh(option, arg_name = "PATH")]
1599 #[serde(skip)] // TODO(b/255223604)
1600 #[merge(strategy = overwrite_option)]
1601 /// absolute path to a directory that will become root filesystem for the plugin process.
1602 pub plugin_root: Option<PathBuf>,
1603
1604 #[argh(option, arg_name = "PATH")]
1605 #[serde(skip)] // TODO(b/255223604)
1606 #[merge(strategy = append)]
1607 /// path to a disk image
1608 pub pmem_device: Vec<DiskOption>,
1609
1610 #[argh(switch)]
1611 #[serde(skip)] // TODO(b/255223604)
1612 #[merge(strategy = overwrite_false)]
1613 /// grant this Guest VM certain privileges to manage Host resources, such as power management
1614 pub privileged_vm: bool,
1615
1616 #[cfg(feature = "process-invariants")]
1617 #[argh(option, arg_name = "PATH")]
1618 #[serde(skip)] // TODO(b/255223604)
1619 #[merge(strategy = overwrite_option)]
1620 /// shared read-only memory address for a serialized EmulatorProcessInvariants proto
1621 pub process_invariants_handle: Option<u64>,
1622
1623 #[cfg(feature = "process-invariants")]
1624 #[argh(option, arg_name = "PATH")]
1625 #[serde(skip)] // TODO(b/255223604)
1626 #[merge(strategy = overwrite_option)]
1627 /// size of the serialized EmulatorProcessInvariants proto pointed at by process-invariants-handle
1628 pub process_invariants_size: Option<usize>,
1629
1630 #[cfg(windows)]
1631 #[argh(option)]
1632 #[serde(skip)] // TODO(b/255223604)
1633 #[merge(strategy = overwrite_option)]
1634 /// product channel
1635 pub product_channel: Option<String>,
1636
1637 #[cfg(windows)]
1638 #[argh(option)]
1639 #[serde(skip)] // TODO(b/255223604)
1640 #[merge(strategy = overwrite_option)]
1641 /// the product name for file paths.
1642 pub product_name: Option<String>,
1643
1644 #[cfg(windows)]
1645 #[argh(option)]
1646 #[serde(skip)] // TODO(b/255223604)
1647 #[merge(strategy = overwrite_option)]
1648 /// product version
1649 pub product_version: Option<String>,
1650
1651 #[argh(switch)]
1652 #[serde(skip)] // TODO(b/255223604)
1653 #[merge(strategy = overwrite_false)]
1654 /// prevent host access to guest memory
1655 pub protected_vm: bool,
1656
1657 #[argh(option, arg_name = "PATH")]
1658 #[serde(skip)] // TODO(b/255223604)
1659 #[merge(strategy = overwrite_option)]
1660 /// (EXPERIMENTAL/FOR DEBUGGING) Use custom VM firmware to run in protected mode
1661 pub protected_vm_with_firmware: Option<PathBuf>,
1662
1663 #[argh(switch)]
1664 #[serde(skip)] // TODO(b/255223604)
1665 #[merge(strategy = overwrite_false)]
1666 /// (EXPERIMENTAL) prevent host access to guest memory, but don't use protected VM firmware
1667 protected_vm_without_firmware: bool,
1668
1669 #[argh(option, arg_name = "path=PATH,size=SIZE")]
1670 #[serde(skip)] // TODO(b/255223604)
1671 #[merge(strategy = overwrite_option)]
1672 /// path to pstore buffer backend file followed by size
1673 /// [--pstore <path=PATH,size=SIZE>]
1674 pub pstore: Option<Pstore>,
1675
1676 #[cfg(windows)]
1677 #[argh(switch)]
1678 #[serde(skip)] // TODO(b/255223604)
1679 #[merge(strategy = overwrite_false)]
1680 /// enable virtio-pvclock.
1681 pub pvclock: bool,
1682
1683 #[argh(option, long = "restore", arg_name = "PATH")]
1684 #[serde(skip)] // TODO(b/255223604)
1685 #[merge(strategy = overwrite_option)]
1686 /// path of the snapshot that is used to restore the VM on startup.
1687 pub restore: Option<PathBuf>,
1688
1689 #[argh(option, arg_name = "PATH[,key=value[,key=value[,...]]]", short = 'r')]
1690 #[serde(skip)] // Deprecated - use `block` instead.
1691 #[merge(strategy = overwrite_option)]
1692 /// path to a disk image followed by optional comma-separated
1693 /// options.
1694 /// Valid keys:
1695 /// sparse=BOOL - Indicates whether the disk should support
1696 /// the discard operation (default: true)
1697 /// block_size=BYTES - Set the reported block size of the
1698 /// disk (default: 512)
1699 /// id=STRING - Set the block device identifier to an ASCII
1700 /// string, up to 20 characters (default: no ID)
1701 /// o_direct=BOOL - Use O_DIRECT mode to bypass page cache
1702 root: Option<DiskOptionWithId>,
1703
1704 #[argh(option, arg_name = "CPUSET")]
1705 #[serde(skip)] // TODO(b/255223604)
1706 #[merge(strategy = overwrite_option)]
1707 /// comma-separated list of CPUs or CPU ranges to run VCPUs on. (e.g. 0,1-3,5) (default: none)
1708 pub rt_cpus: Option<CpuSet>,
1709
1710 #[argh(option, arg_name = "PATH")]
1711 #[serde(skip)] // TODO(b/255223604)
1712 #[merge(strategy = append)]
1713 /// path to a writable disk image
1714 rw_pmem_device: Vec<DiskOption>,
1715
1716 #[argh(option, arg_name = "PATH[,key=value[,key=value[,...]]]")]
1717 #[serde(skip)] // Deprecated - use `block` instead.
1718 #[merge(strategy = append)]
1719 /// path to a read-write disk image followed by optional
1720 /// comma-separated options.
1721 /// Valid keys:
1722 /// sparse=BOOL - Indicates whether the disk should support
1723 /// the discard operation (default: true)
1724 /// block_size=BYTES - Set the reported block size of the
1725 /// disk (default: 512)
1726 /// id=STRING - Set the block device identifier to an ASCII
1727 /// string, up to 20 characters (default: no ID)
1728 /// o_direct=BOOL - Use O_DIRECT mode to bypass page cache
1729 rwdisk: Vec<DiskOptionWithId>,
1730
1731 #[argh(option, arg_name = "PATH[,key=value[,key=value[,...]]]")]
1732 #[serde(skip)] // Deprecated - use `block` instead.
1733 #[merge(strategy = overwrite_option)]
1734 /// path to a read-write root disk image followed by optional
1735 /// comma-separated options.
1736 /// Valid keys:
1737 /// sparse=BOOL - Indicates whether the disk should support
1738 /// the discard operation (default: true)
1739 /// block_size=BYTES - Set the reported block size of the
1740 /// disk (default: 512)
1741 /// id=STRING - Set the block device identifier to an ASCII
1742 /// string, up to 20 characters (default: no ID)
1743 /// o_direct=BOOL - Use O_DIRECT mode to bypass page cache
1744 rwroot: Option<DiskOptionWithId>,
1745
1746 #[argh(switch)]
1747 #[serde(skip)] // TODO(b/255223604)
1748 #[merge(strategy = overwrite_false)]
1749 /// set Low Power S0 Idle Capable Flag for guest Fixed ACPI
1750 /// Description Table, additionally use enhanced crosvm suspend and resume
1751 /// routines to perform full guest suspension/resumption
1752 pub s2idle: bool,
1753
1754 #[cfg(unix)]
1755 #[argh(switch)]
1756 #[serde(skip)] // TODO(b/255223604)
1757 #[merge(strategy = overwrite_false)]
1758 /// instead of seccomp filter failures being fatal, they will be logged instead
1759 pub seccomp_log_failures: bool,
1760
1761 #[cfg(unix)]
1762 #[argh(option, arg_name = "PATH")]
1763 #[serde(skip)] // TODO(b/255223604)
1764 #[merge(strategy = overwrite_option)]
1765 /// path to seccomp .policy files
1766 pub seccomp_policy_dir: Option<PathBuf>,
1767
1768 #[argh(
1769 option,
1770 arg_name = "type=TYPE,[hardware=HW,num=NUM,path=PATH,input=PATH,console,earlycon,stdin]",
1771 from_str_fn(parse_serial_options)
1772 )]
1773 #[serde(default)]
1774 #[merge(strategy = append)]
1775 /// comma separated key=value pairs for setting up serial
1776 /// devices. Can be given more than once.
1777 /// Possible key values:
1778 /// type=(stdout,syslog,sink,file) - Where to route the
1779 /// serial device
1780 /// hardware=(serial,virtio-console,debugcon) - Which type
1781 /// of serial hardware to emulate. Defaults to 8250 UART
1782 /// (serial).
1783 /// num=(1,2,3,4) - Serial Device Number. If not provided,
1784 /// num will default to 1.
1785 /// debugcon_port=PORT - Port for the debugcon device to
1786 /// listen to. Defaults to 0x402, which is what OVMF
1787 /// expects.
1788 /// path=PATH - The path to the file to write to when
1789 /// type=file
1790 /// input=PATH - The path to the file to read from when not
1791 /// stdin
1792 /// console - Use this serial device as the guest console.
1793 /// Can only be given once. Will default to first
1794 /// serial port if not provided.
1795 /// earlycon - Use this serial device as the early console.
1796 /// Can only be given once.
1797 /// stdin - Direct standard input to this serial device.
1798 /// Can only be given once. Will default to first serial
1799 /// port if not provided.
1800 pub serial: Vec<SerialParameters>,
1801
1802 #[cfg(windows)]
1803 #[argh(option, arg_name = "PIPE_NAME")]
1804 #[serde(skip)] // TODO(b/255223604)
1805 #[merge(strategy = overwrite_option)]
1806 /// the service ipc pipe name. (Prefix \\\\.\\pipe\\ not needed.
1807 pub service_pipe_name: Option<String>,
1808
1809 #[cfg(unix)]
1810 #[argh(
1811 option,
1812 arg_name = "PATH:TAG[:type=TYPE:writeback=BOOL:timeout=SECONDS:uidmap=UIDMAP:gidmap=GIDMAP:cache=CACHE:dax=BOOL,posix_acl=BOOL]"
1813 )]
1814 // TODO(b/218223240) add Deserialize implementation for SharedDir so it can be supported by the
1815 // config file.
1816 #[serde(skip)]
1817 #[merge(strategy = append)]
1818 /// colon-separated options for configuring a directory to be
1819 /// shared with the VM. The first field is the directory to be
1820 /// shared and the second field is the tag that the VM can use
1821 /// to identify the device. The remaining fields are key=value
1822 /// pairs that may appear in any order.
1823 /// Valid keys are:
1824 /// type=(p9, fs) - Indicates whether the directory should
1825 /// be shared via virtio-9p or virtio-fs (default: p9).
1826 /// uidmap=UIDMAP - The uid map to use for the device's
1827 /// jail in the format "inner outer
1828 /// count[,inner outer count]"
1829 /// (default: 0 <current euid> 1).
1830 /// gidmap=GIDMAP - The gid map to use for the device's
1831 /// jail in the format "inner outer
1832 /// count[,inner outer count]"
1833 /// (default: 0 <current egid> 1).
1834 /// cache=(never, auto, always) - Indicates whether the VM
1835 /// can cache the contents of the shared directory
1836 /// (default: auto). When set to "auto" and the type
1837 /// is "fs", the VM will use close-to-open consistency
1838 /// for file contents.
1839 /// timeout=SECONDS - How long the VM should consider file
1840 /// attributes and directory entries to be valid
1841 /// (default: 5). If the VM has exclusive access to the
1842 /// directory, then this should be a large value. If
1843 /// the directory can be modified by other processes,
1844 /// then this should be 0.
1845 /// writeback=BOOL - Enables writeback caching
1846 /// (default: false). This is only safe to do when the
1847 /// VM has exclusive access to the files in a directory.
1848 /// Additionally, the server should have read
1849 /// permission for all files as the VM may issue read
1850 /// requests even for files that are opened write-only.
1851 /// dax=BOOL - Enables DAX support. Enabling DAX can
1852 /// improve performance for frequently accessed files
1853 /// by mapping regions of the file directly into the
1854 /// VM's memory. There is a cost of slightly increased
1855 /// latency the first time the file is accessed. Since
1856 /// the mapping is shared directly from the host kernel's
1857 /// file cache, enabling DAX can improve performance even
1858 /// when the guest cache policy is "Never". The default
1859 /// value for this option is "false".
1860 /// posix_acl=BOOL - Indicates whether the shared directory
1861 /// supports POSIX ACLs. This should only be enabled
1862 /// when the underlying file system supports POSIX ACLs.
1863 /// The default value for this option is "true".
1864 pub shared_dir: Vec<SharedDir>,
1865
1866 #[argh(option, arg_name = "PATH:WIDTH:HEIGHT")]
1867 #[serde(skip)] // TODO(b/255223604)
1868 #[merge(strategy = append)]
1869 /// path to a socket from where to read single touch input events (such as those from a touchscreen) and write status updates to, optionally followed by width and height (defaults to 800x1280)
1870 pub single_touch: Vec<TouchDeviceOption>,
1871
1872 #[cfg(feature = "slirp-ring-capture")]
1873 #[argh(option, arg_name = "PATH")]
1874 #[serde(skip)] // TODO(b/255223604)
1875 #[merge(strategy = overwrite_option)]
1876 /// Redirects slirp network packets to the supplied log file rather than the current directory as `slirp_capture_packets.pcap`
1877 pub slirp_capture_file: Option<String>,
1878
1879 #[argh(option, short = 's', arg_name = "PATH")]
1880 #[merge(strategy = overwrite_option)]
1881 /// path to put the control socket. If PATH is a directory, a name will be generated
1882 pub socket: Option<PathBuf>,
1883
1884 #[cfg(feature = "tpm")]
1885 #[argh(switch)]
1886 #[serde(skip)] // TODO(b/255223604)
1887 #[merge(strategy = overwrite_false)]
1888 /// enable a software emulated trusted platform module device
1889 pub software_tpm: bool,
1890
1891 #[cfg(feature = "audio")]
1892 #[argh(option, arg_name = "PATH")]
1893 #[serde(skip)] // TODO(b/255223604)
1894 #[merge(strategy = overwrite_option)]
1895 /// path to the VioS server socket for setting up virtio-snd devices
1896 pub sound: Option<PathBuf>,
1897
1898 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
1899 #[argh(switch)]
1900 #[serde(skip)] // TODO(b/255223604)
1901 #[merge(strategy = overwrite_false)]
1902 /// (EXPERIMENTAL) enable split-irqchip support
1903 pub split_irqchip: bool,
1904
1905 #[argh(switch)]
1906 #[serde(skip)] // TODO(b/255223604)
1907 #[merge(strategy = overwrite_false)]
1908 /// don't allow guest to use pages from the balloon
1909 pub strict_balloon: bool,
1910
1911 #[argh(
1912 option,
1913 arg_name = "DOMAIN:BUS:DEVICE.FUNCTION[,vendor=NUM][,device=NUM][,class=NUM][,subsystem_vendor=NUM][,subsystem_device=NUM][,revision=NUM]"
1914 )]
1915 #[serde(skip)] // TODO(b/255223604)
1916 #[merge(strategy = append)]
1917 /// comma-separated key=value pairs for setting up a stub PCI
1918 /// device that just enumerates. The first option in the list
1919 /// must specify a PCI address to claim.
1920 /// Optional further parameters
1921 /// vendor=NUM - PCI vendor ID
1922 /// device=NUM - PCI device ID
1923 /// class=NUM - PCI class (including class code, subclass,
1924 /// and programming interface)
1925 /// subsystem_vendor=NUM - PCI subsystem vendor ID
1926 /// subsystem_device=NUM - PCI subsystem device ID
1927 /// revision=NUM - revision
1928 pub stub_pci_device: Vec<StubPciParameters>,
1929
1930 #[argh(option, long = "swap", arg_name = "PATH")]
1931 #[serde(skip)] // TODO(b/255223604)
1932 #[merge(strategy = overwrite_option)]
1933 /// enable vmm-swap via an unnamed temporary file on the filesystem which contains the specified
1934 /// directory.
1935 pub swap_dir: Option<PathBuf>,
1936
1937 #[argh(option, arg_name = "N")]
1938 #[serde(skip)] // TODO(b/255223604)
1939 #[merge(strategy = overwrite_option)]
1940 /// (EXPERIMENTAL) Size of virtio swiotlb buffer in MiB (default: 64 if `--protected-vm` or `--protected-vm-without-firmware` is present)
1941 pub swiotlb: Option<u64>,
1942
1943 #[argh(option, arg_name = "PATH")]
1944 #[serde(skip)] // TODO(b/255223604)
1945 #[merge(strategy = append)]
1946 /// path to a socket from where to read switch input events and write status updates to
1947 pub switches: Vec<PathBuf>,
1948
1949 #[argh(option, arg_name = "TAG")]
1950 #[serde(skip)] // TODO(b/255223604)
1951 #[merge(strategy = overwrite_option)]
1952 /// when logging to syslog, use the provided tag
1953 pub syslog_tag: Option<String>,
1954
1955 #[cfg(unix)]
1956 #[argh(option)]
1957 #[serde(skip)] // Deprecated - use `net` instead.
1958 #[merge(strategy = append)]
1959 /// file descriptor for configured tap device. A different virtual network card will be added each time this argument is given
1960 pub tap_fd: Vec<RawDescriptor>,
1961
1962 #[cfg(unix)]
1963 #[argh(option)]
1964 #[serde(skip)] // Deprecated - use `net` instead.
1965 #[merge(strategy = append)]
1966 /// name of a configured persistent TAP interface to use for networking. A different virtual network card will be added each time this argument is given
1967 pub tap_name: Vec<String>,
1968
1969 #[cfg(target_os = "android")]
1970 #[argh(option, arg_name = "NAME[,...]")]
1971 #[serde(skip)] // TODO(b/255223604)
1972 #[merge(strategy = append)]
1973 /// comma-separated names of the task profiles to apply to all threads in crosvm including the vCPU threads
1974 pub task_profiles: Vec<String>,
1975
1976 #[argh(option, arg_name = "PATH:WIDTH:HEIGHT")]
1977 #[serde(skip)] // TODO(b/255223604)
1978 #[merge(strategy = append)]
1979 /// path to a socket from where to read trackpad input events and write status updates to, optionally followed by screen width and height (defaults to 800x1280)
1980 pub trackpad: Vec<TouchDeviceOption>,
1981
1982 #[cfg(unix)]
1983 #[argh(switch)]
1984 #[serde(skip)] // TODO(b/255223604)
1985 #[merge(strategy = overwrite_false)]
1986 /// set MADV_DONTFORK on guest memory
1987 ///
1988 /// Intended for use in combination with --protected-vm, where the guest memory can be
1989 /// dangerous to access. Some systems, e.g. Android, have tools that fork processes and examine
1990 /// their memory. This flag effectively hides the guest memory from those tools.
1991 ///
1992 /// Not compatible with sandboxing or vvu devices.
1993 pub unmap_guest_memory_on_fork: bool,
1994
1995 // Must be `Some` iff `protection_type == ProtectionType::UnprotectedWithFirmware`.
1996 #[argh(option, arg_name = "PATH")]
1997 #[serde(skip)] // TODO(b/255223604)
1998 #[merge(strategy = overwrite_option)]
1999 /// (EXPERIMENTAL/FOR DEBUGGING) Use VM firmware, but allow host access to guest memory
2000 pub unprotected_vm_with_firmware: Option<PathBuf>,
2001
2002 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
2003 #[argh(
2004 option,
2005 arg_name = "INDEX,type=TYPE,action=ACTION,[from=FROM],[filter=FILTER]",
2006 from_str_fn(parse_userspace_msr_options)
2007 )]
2008 #[serde(skip)] // TODO(b/255223604)
2009 #[merge(strategy = append)]
2010 /// userspace MSR handling. Takes INDEX of the MSR and how they
2011 /// are handled.
2012 /// type=(r|w|rw|wr) - read/write permission control.
2013 /// action=(pass|emu) - if the control of msr is effective
2014 /// on host.
2015 /// from=(cpu0) - source of msr value. if not set, the
2016 /// source is running CPU.
2017 /// filter=(yes|no) - if the msr is filtered in KVM.
2018 pub userspace_msr: Vec<(u32, MsrConfig)>,
2019
2020 #[argh(option, arg_name = "PATH")]
2021 #[serde(skip)] // TODO(b/255223604)
2022 #[merge(strategy = overwrite_option)]
2023 /// move all vCPU threads to this CGroup (default: nothing moves)
2024 pub vcpu_cgroup_path: Option<PathBuf>,
2025
2026 #[cfg(unix)]
2027 #[argh(
2028 option,
2029 arg_name = "PATH[,guest-address=<BUS:DEVICE.FUNCTION>][,iommu=viommu|coiommu|off]"
2030 )]
2031 #[serde(default)]
2032 #[merge(strategy = append)]
2033 /// path to sysfs of VFIO device.
2034 /// guest-address=<BUS:DEVICE.FUNCTION> - PCI address
2035 /// that the device will be assigned in the guest.
2036 /// If not specified, the device will be assigned an
2037 /// address that mirrors its address in the host.
2038 /// Only valid for PCI devices.
2039 /// iommu=viommu|coiommu|off - indicates which type of IOMMU
2040 /// to use for this device.
2041 pub vfio: Vec<VfioOption>,
2042
2043 #[cfg(unix)]
2044 #[argh(switch)]
2045 #[serde(skip)] // TODO(b/255223604)
2046 #[merge(strategy = overwrite_false)]
2047 /// isolate all hotplugged passthrough vfio device behind virtio-iommu
2048 pub vfio_isolate_hotplug: bool,
2049
2050 #[cfg(unix)]
2051 #[argh(option, arg_name = "PATH")]
2052 #[serde(skip)] // Deprecated - use `vfio` instead.
2053 #[merge(strategy = append)]
2054 /// path to sysfs of platform pass through
2055 pub vfio_platform: Vec<VfioOption>,
2056
2057 #[cfg(unix)]
2058 #[argh(switch)]
2059 #[serde(skip)] // Deprecated - use `net` instead.
2060 #[merge(strategy = overwrite_false)]
2061 /// use vhost for networking
2062 pub vhost_net: bool,
2063
2064 #[cfg(unix)]
2065 #[argh(option, arg_name = "PATH")]
2066 #[serde(skip)] // TODO(b/255223604)
2067 #[merge(strategy = overwrite_option)]
2068 /// path to the vhost-net device. (default /dev/vhost-net)
2069 pub vhost_net_device: Option<PathBuf>,
2070
2071 #[argh(option, arg_name = "SOCKET_PATH")]
2072 #[serde(skip)] // TODO(b/255223604)
2073 #[merge(strategy = append)]
2074 /// path to a socket for vhost-user block
2075 pub vhost_user_blk: Vec<VhostUserOption>,
2076
2077 #[argh(option, arg_name = "SOCKET_PATH")]
2078 #[serde(skip)] // TODO(b/255223604)
2079 #[merge(strategy = append)]
2080 /// path to a socket for vhost-user console
2081 pub vhost_user_console: Vec<VhostUserOption>,
2082
2083 #[argh(option, arg_name = "SOCKET_PATH:TAG")]
2084 #[serde(skip)] // TODO(b/255223604)
2085 #[merge(strategy = append)]
2086 /// path to a socket path for vhost-user fs, and tag for the shared dir
2087 pub vhost_user_fs: Vec<VhostUserFsOption>,
2088
2089 #[argh(option, arg_name = "SOCKET_PATH")]
2090 #[serde(skip)] // TODO(b/255223604)
2091 #[merge(strategy = append)]
2092 /// paths to a vhost-user socket for gpu
2093 pub vhost_user_gpu: Vec<VhostUserOption>,
2094
2095 #[argh(option, arg_name = "SOCKET_PATH")]
2096 #[serde(skip)] // TODO(b/255223604)
2097 #[merge(strategy = overwrite_option)]
2098 /// path to a socket for vhost-user mac80211_hwsim
2099 pub vhost_user_mac80211_hwsim: Option<VhostUserOption>,
2100
2101 #[argh(option, arg_name = "SOCKET_PATH")]
2102 #[serde(skip)] // TODO(b/255223604)
2103 #[merge(strategy = append)]
2104 /// path to a socket for vhost-user net
2105 pub vhost_user_net: Vec<VhostUserOption>,
2106
2107 #[argh(option, arg_name = "SOCKET_PATH")]
2108 #[serde(skip)] // TODO(b/255223604)
2109 #[merge(strategy = append)]
2110 /// path to a socket for vhost-user snd
2111 pub vhost_user_snd: Vec<VhostUserOption>,
2112
2113 #[argh(option, arg_name = "SOCKET_PATH")]
2114 #[serde(default)]
2115 #[merge(strategy = append)]
2116 /// path to a socket for vhost-user video decoder
2117 pub vhost_user_video_decoder: Vec<VhostUserOption>,
2118
2119 #[argh(option, arg_name = "SOCKET_PATH")]
2120 #[serde(skip)] // TODO(b/255223604)
2121 #[merge(strategy = append)]
2122 /// path to a socket for vhost-user vsock
2123 pub vhost_user_vsock: Vec<VhostUserOption>,
2124
2125 #[argh(option, arg_name = "SOCKET_PATH")]
2126 #[serde(skip)] // TODO(b/255223604)
2127 #[merge(strategy = overwrite_option)]
2128 /// path to a vhost-user socket for wayland
2129 pub vhost_user_wl: Option<VhostUserOption>,
2130
2131 #[cfg(unix)]
2132 #[argh(option, arg_name = "SOCKET_PATH")]
2133 #[serde(skip)] // Deprecated - use `vsock` instead.
2134 #[merge(strategy = overwrite_option)]
2135 /// path to the vhost-vsock device. (default /dev/vhost-vsock)
2136 pub vhost_vsock_device: Option<PathBuf>,
2137
2138 #[cfg(unix)]
2139 #[argh(option, arg_name = "FD")]
2140 #[serde(skip)] // Deprecated - use `vsock` instead.
2141 #[merge(strategy = overwrite_option)]
2142 /// open FD to the vhost-vsock device, mutually exclusive with vhost-vsock-device
2143 pub vhost_vsock_fd: Option<RawDescriptor>,
2144
2145 #[cfg(feature = "video-decoder")]
2146 #[argh(option, arg_name = "[backend]")]
2147 #[serde(default)]
2148 #[merge(strategy = append)]
2149 /// (EXPERIMENTAL) enable virtio-video decoder device
2150 /// Possible backend values: libvda, ffmpeg, vaapi
2151 pub video_decoder: Vec<VideoDeviceConfig>,
2152
2153 #[cfg(feature = "video-encoder")]
2154 #[argh(option, arg_name = "[backend]")]
2155 #[serde(default)]
2156 #[merge(strategy = append)]
2157 /// (EXPERIMENTAL) enable virtio-video encoder device
2158 /// Possible backend values: libvda
2159 pub video_encoder: Vec<VideoDeviceConfig>,
2160
2161 #[cfg(feature = "audio")]
2162 #[argh(
2163 option,
2164 arg_name = "[capture=true,backend=BACKEND,num_output_devices=1,
2165 num_input_devices=1,num_output_streams=1,num_input_streams=1]"
2166 )]
2167 #[serde(skip)] // TODO(b/255223604)
2168 #[merge(strategy = append)]
2169 /// comma separated key=value pairs for setting up virtio snd
2170 /// devices.
2171 /// Possible key values:
2172 /// capture=(false,true) - Disable/enable audio capture.
2173 /// Default is false.
2174 /// backend=(null,file,[cras]) - Which backend to use for
2175 /// virtio-snd.
2176 /// client_type=(crosvm,arcvm,borealis) - Set specific
2177 /// client type for cras backend. Default is crosvm.
2178 /// socket_type=(legacy,unified) Set specific socket type
2179 /// for cras backend. Default is unified.
2180 /// playback_path=STR - Set directory of output streams
2181 /// for file backend.
2182 /// playback_size=INT - Set size of the output streams
2183 /// from file backend.
2184 /// num_output_devices=INT - Set number of output PCM
2185 /// devices.
2186 /// num_input_devices=INT - Set number of input PCM devices.
2187 /// num_output_streams=INT - Set number of output PCM
2188 /// streams per device.
2189 /// num_input_streams=INT - Set number of input PCM streams
2190 /// per device.
2191 pub virtio_snd: Vec<SndParameters>,
2192
2193 #[argh(option, arg_name = "cid=CID[,device=VHOST_DEVICE]")]
2194 #[serde(default)]
2195 #[merge(strategy = overwrite_option)]
2196 /// add a vsock device. Since a guest can only have one CID,
2197 /// this option can only be specified once.
2198 /// cid=CID - CID to use for the device.
2199 /// device=VHOST_DEVICE - path to the vhost-vsock device to
2200 /// use (Linux only). Defaults to /dev/vhost-vsock.
2201 pub vsock: Option<VsockConfig>,
2202
2203 #[cfg(all(feature = "vtpm", target_arch = "x86_64"))]
2204 #[argh(switch)]
2205 #[serde(skip)] // TODO(b/255223604)
2206 #[merge(strategy = overwrite_false)]
2207 /// enable the virtio-tpm connection to vtpm daemon
2208 pub vtpm_proxy: bool,
2209
2210 #[argh(
2211 option,
2212 arg_name = "SOCKET_PATH[,addr=DOMAIN:BUS:DEVICE.FUNCTION,uuid=UUID]"
2213 )]
2214 #[serde(skip)] // TODO(b/255223604)
2215 #[merge(strategy = append)]
2216 /// socket path for the Virtio Vhost User proxy device.
2217 /// Parameters
2218 /// addr=BUS:DEVICE.FUNCTION - PCI address that the proxy
2219 /// device will be allocated
2220 /// (default: automatically allocated)
2221 /// uuid=UUID - UUID which will be stored in VVU PCI config
2222 /// space that is readable from guest userspace
2223 pub vvu_proxy: Vec<VvuOption>,
2224
2225 #[cfg(unix)]
2226 #[argh(option, arg_name = "PATH[,name=NAME]", from_str_fn(parse_wayland_sock))]
2227 #[serde(skip)] // TODO(b/255223604)
2228 #[merge(strategy = append)]
2229 /// path to the Wayland socket to use. The unnamed one is used for displaying virtual screens. Named ones are only for IPC
2230 pub wayland_sock: Vec<(String, PathBuf)>,
2231
2232 #[cfg(unix)]
2233 #[argh(option, arg_name = "DISPLAY")]
2234 #[serde(skip)] // TODO(b/255223604)
2235 #[merge(strategy = overwrite_option)]
2236 /// X11 display name to use
2237 pub x_display: Option<String>,
2238 }
2239
2240 #[cfg(feature = "config-file")]
2241 impl RunCommand {
2242 /// Merge the content of `self` into `self.cfg` if it exists, and return the merged
2243 /// configuration which `self.cfg` is empty.
squash(mut self) -> Self2244 pub fn squash(mut self) -> Self {
2245 use merge::Merge;
2246
2247 self.cfg
2248 .take()
2249 .map(|b| *b)
2250 .into_iter()
2251 .chain(std::iter::once(self))
2252 .reduce(|mut acc: Self, cfg| {
2253 acc.merge(cfg);
2254 acc
2255 })
2256 .unwrap()
2257 }
2258 }
2259
2260 impl TryFrom<RunCommand> for super::config::Config {
2261 type Error = String;
2262
try_from(cmd: RunCommand) -> Result<Self, Self::Error>2263 fn try_from(cmd: RunCommand) -> Result<Self, Self::Error> {
2264 // Squash the configuration file (if any) and command-line arguments together.
2265 #[cfg(feature = "config-file")]
2266 let cmd = {
2267 if cmd.cfg.is_some() {
2268 log::warn!(
2269 "`--cfg` is still experimental and the configuration file format may change"
2270 );
2271 }
2272 cmd.squash()
2273 };
2274
2275 let mut cfg = Self::default();
2276 // TODO: we need to factor out some(?) of the checks into config::validate_config
2277
2278 // Process arguments
2279 if let Some(p) = cmd.kernel {
2280 cfg.executable_path = Some(Executable::Kernel(p));
2281 }
2282
2283 #[cfg(unix)]
2284 if let Some(p) = cmd.kvm_device {
2285 log::warn!(
2286 "`--kvm-device <PATH>` is deprecated; use `--hypervisor kvm[device=<PATH>]` instead"
2287 );
2288
2289 if cmd.hypervisor.is_some() {
2290 return Err("cannot specify both --hypervisor and --kvm-device".to_string());
2291 }
2292
2293 cfg.hypervisor = Some(crate::crosvm::config::HypervisorKind::Kvm { device: Some(p) });
2294 }
2295
2296 #[cfg(unix)]
2297 if let Some(p) = cmd.vhost_net_device {
2298 if !p.exists() {
2299 return Err(format!("vhost-net-device path {:?} does not exist", p));
2300 }
2301 cfg.vhost_net_device_path = p;
2302 }
2303
2304 cfg.android_fstab = cmd.android_fstab;
2305
2306 cfg.async_executor = cmd.async_executor;
2307
2308 #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), unix))]
2309 if let Some(p) = cmd.bus_lock_ratelimit {
2310 cfg.bus_lock_ratelimit = p;
2311 }
2312
2313 cfg.params.extend(cmd.params);
2314
2315 cfg.core_scheduling = cmd.core_scheduling;
2316 cfg.per_vm_core_scheduling = cmd.per_vm_core_scheduling;
2317
2318 // `--cpu` parameters.
2319 {
2320 let cpus = cmd.cpus.unwrap_or_default();
2321 cfg.vcpu_count = cpus.num_cores;
2322
2323 // Only allow deprecated `--cpu-cluster` option only if `--cpu clusters=[...]` is not
2324 // used.
2325 cfg.cpu_clusters = match (&cpus.clusters.is_empty(), &cmd.cpu_cluster.is_empty()) {
2326 (_, true) => cpus.clusters,
2327 (true, false) => cmd.cpu_cluster,
2328 (false, false) => {
2329 return Err(
2330 "cannot specify both --cpu clusters=[...] and --cpu_cluster".to_string()
2331 )
2332 }
2333 };
2334
2335 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
2336 if let Some(cpu_types) = cpus.core_types {
2337 for cpu in cpu_types.atom {
2338 if cfg
2339 .vcpu_hybrid_type
2340 .insert(cpu, CpuHybridType::Atom)
2341 .is_some()
2342 {
2343 return Err(format!("vCPU index must be unique {}", cpu));
2344 }
2345 }
2346 for cpu in cpu_types.core {
2347 if cfg
2348 .vcpu_hybrid_type
2349 .insert(cpu, CpuHybridType::Core)
2350 .is_some()
2351 {
2352 return Err(format!("vCPU index must be unique {}", cpu));
2353 }
2354 }
2355 }
2356 }
2357
2358 cfg.vcpu_affinity = cmd.cpu_affinity;
2359
2360 if let Some(capacity) = cmd.cpu_capacity {
2361 cfg.cpu_capacity = capacity;
2362 }
2363
2364 cfg.vcpu_cgroup_path = cmd.vcpu_cgroup_path;
2365
2366 cfg.no_smt = cmd.no_smt;
2367
2368 if let Some(rt_cpus) = cmd.rt_cpus {
2369 cfg.rt_cpus = rt_cpus;
2370 }
2371
2372 cfg.delay_rt = cmd.delay_rt;
2373
2374 let mem = cmd.mem.unwrap_or_default();
2375 cfg.memory = mem.size;
2376
2377 #[cfg(target_arch = "aarch64")]
2378 {
2379 if cmd.mte
2380 && !(cmd.pmem_device.is_empty()
2381 && cmd.pstore.is_none()
2382 && cmd.rw_pmem_device.is_empty())
2383 {
2384 return Err(
2385 "--mte cannot be specified together with --pmem-device, --pstore or --rw-pmem-device"
2386 .to_string(),
2387 );
2388 }
2389 cfg.mte = cmd.mte;
2390 cfg.swiotlb = cmd.swiotlb;
2391 }
2392
2393 cfg.hugepages = cmd.hugepages;
2394
2395 // `cfg.hypervisor` may have been set by the deprecated `--kvm-device` option above.
2396 // TODO(b/274817652): remove this workaround when `--kvm-device` is removed.
2397 if cfg.hypervisor.is_none() {
2398 cfg.hypervisor = cmd.hypervisor;
2399 }
2400
2401 #[cfg(unix)]
2402 {
2403 cfg.lock_guest_memory = cmd.lock_guest_memory;
2404 }
2405
2406 #[cfg(feature = "audio")]
2407 {
2408 cfg.ac97_parameters = cmd.ac97;
2409 cfg.sound = cmd.sound;
2410 }
2411 cfg.vhost_user_snd = cmd.vhost_user_snd;
2412
2413 for serial_params in cmd.serial {
2414 super::sys::config::check_serial_params(&serial_params)?;
2415
2416 let num = serial_params.num;
2417 let key = (serial_params.hardware, num);
2418
2419 if cfg.serial_parameters.contains_key(&key) {
2420 return Err(format!(
2421 "serial hardware {} num {}",
2422 serial_params.hardware, num,
2423 ));
2424 }
2425
2426 if serial_params.console {
2427 for params in cfg.serial_parameters.values() {
2428 if params.console {
2429 return Err(format!(
2430 "{} device {} already set as console",
2431 params.hardware, params.num,
2432 ));
2433 }
2434 }
2435 }
2436
2437 if serial_params.earlycon {
2438 // Only SerialHardware::Serial supports earlycon= currently.
2439 match serial_params.hardware {
2440 SerialHardware::Serial => {}
2441 _ => {
2442 return Err(super::config::invalid_value_err(
2443 serial_params.hardware.to_string(),
2444 String::from("earlycon not supported for hardware"),
2445 ));
2446 }
2447 }
2448 for params in cfg.serial_parameters.values() {
2449 if params.earlycon {
2450 return Err(format!(
2451 "{} device {} already set as earlycon",
2452 params.hardware, params.num,
2453 ));
2454 }
2455 }
2456 }
2457
2458 if serial_params.stdin {
2459 if let Some(previous_stdin) = cfg.serial_parameters.values().find(|sp| sp.stdin) {
2460 return Err(format!(
2461 "{} device {} already connected to standard input",
2462 previous_stdin.hardware, previous_stdin.num,
2463 ));
2464 }
2465 }
2466
2467 cfg.serial_parameters.insert(key, serial_params);
2468 }
2469
2470 // Aggregate all the disks with the expected read-only and root values according to the
2471 // option they have been passed with.
2472 let mut disks = cmd
2473 .root
2474 .into_iter()
2475 .map(|mut d| {
2476 d.disk_option.read_only = true;
2477 d.disk_option.root = true;
2478 d
2479 })
2480 .chain(cmd.rwroot.into_iter().map(|mut d| {
2481 d.disk_option.read_only = false;
2482 d.disk_option.root = true;
2483 d
2484 }))
2485 .chain(cmd.disk.into_iter().map(|mut d| {
2486 d.disk_option.read_only = true;
2487 d.disk_option.root = false;
2488 d
2489 }))
2490 .chain(cmd.rwdisk.into_iter().map(|mut d| {
2491 d.disk_option.read_only = false;
2492 d.disk_option.root = false;
2493 d
2494 }))
2495 .chain(cmd.block.into_iter())
2496 .collect::<Vec<_>>();
2497
2498 // Sort all our disks by index.
2499 disks.sort_by_key(|d| d.index);
2500
2501 // Check that we don't have more than one root disk.
2502 if disks.iter().filter(|d| d.disk_option.root).count() > 1 {
2503 return Err("only one root disk can be specified".to_string());
2504 }
2505
2506 // If we have a root disk, add the corresponding command-line parameters.
2507 if let Some(d) = disks.iter().find(|d| d.disk_option.root) {
2508 if d.index >= 26 {
2509 return Err("ran out of letters for to assign to root disk".to_string());
2510 }
2511 cfg.params.push(format!(
2512 "root=/dev/vd{} {}",
2513 char::from(b'a' + d.index as u8),
2514 if d.disk_option.read_only { "ro" } else { "rw" }
2515 ));
2516 }
2517
2518 // Pass the sorted disks to the VM config.
2519 cfg.disks = disks.into_iter().map(|d| d.disk_option).collect();
2520
2521 for (mut pmem, read_only) in cmd
2522 .pmem_device
2523 .into_iter()
2524 .map(|p| (p, true))
2525 .chain(cmd.rw_pmem_device.into_iter().map(|p| (p, false)))
2526 {
2527 pmem.read_only = read_only;
2528 cfg.pmem_devices.push(pmem);
2529 }
2530
2531 #[cfg(windows)]
2532 {
2533 #[cfg(feature = "crash-report")]
2534 {
2535 cfg.crash_pipe_name = cmd.crash_pipe_name;
2536 }
2537 cfg.product_name = cmd.product_name;
2538 cfg.exit_stats = cmd.exit_stats;
2539 cfg.host_guid = cmd.host_guid;
2540 cfg.irq_chip = cmd.irqchip;
2541 cfg.kernel_log_file = cmd.kernel_log_file;
2542 cfg.log_file = cmd.log_file;
2543 cfg.logs_directory = cmd.logs_directory;
2544 #[cfg(feature = "process-invariants")]
2545 {
2546 cfg.process_invariants_data_handle = cmd.process_invariants_handle;
2547
2548 cfg.process_invariants_data_size = cmd.process_invariants_size;
2549 }
2550 cfg.pvclock = cmd.pvclock;
2551 #[cfg(windows)]
2552 {
2553 cfg.service_pipe_name = cmd.service_pipe_name;
2554 }
2555 #[cfg(feature = "slirp-ring-capture")]
2556 {
2557 cfg.slirp_capture_file = cmd.slirp_capture_file;
2558 }
2559 cfg.syslog_tag = cmd.syslog_tag;
2560 cfg.product_channel = cmd.product_channel;
2561 cfg.product_version = cmd.product_version;
2562 }
2563 cfg.pstore = cmd.pstore;
2564
2565 #[cfg(unix)]
2566 for (name, params) in cmd.wayland_sock {
2567 if cfg.wayland_socket_paths.contains_key(&name) {
2568 return Err(format!("wayland socket name already used: '{}'", name));
2569 }
2570 cfg.wayland_socket_paths.insert(name, params);
2571 }
2572
2573 #[cfg(unix)]
2574 {
2575 cfg.x_display = cmd.x_display;
2576 }
2577
2578 cfg.display_window_keyboard = cmd.display_window_keyboard;
2579 cfg.display_window_mouse = cmd.display_window_mouse;
2580
2581 cfg.swap_dir = cmd.swap_dir;
2582 cfg.restore_path = cmd.restore;
2583
2584 if let Some(mut socket_path) = cmd.socket {
2585 if socket_path.is_dir() {
2586 socket_path.push(format!("crosvm-{}.sock", getpid()));
2587 }
2588 cfg.socket_path = Some(socket_path);
2589 }
2590
2591 cfg.balloon_control = cmd.balloon_control;
2592
2593 cfg.vsock = cmd.vsock;
2594
2595 // Legacy vsock options.
2596 if let Some(cid) = cmd.cid {
2597 if cfg.vsock.is_some() {
2598 return Err(
2599 "`cid` and `vsock` cannot be specified together. Use `vsock` only.".to_string(),
2600 );
2601 }
2602
2603 let legacy_vsock_config = VsockConfig::new(
2604 cid,
2605 #[cfg(unix)]
2606 match (cmd.vhost_vsock_device, cmd.vhost_vsock_fd) {
2607 (Some(_), Some(_)) => {
2608 return Err(
2609 "Only one of vhost-vsock-device vhost-vsock-fd has to be specified"
2610 .to_string(),
2611 )
2612 }
2613 (Some(path), None) => Some(path),
2614 (None, Some(fd)) => Some(PathBuf::from(format!("/proc/self/fd/{}", fd))),
2615 (None, None) => None,
2616 },
2617 );
2618
2619 cfg.vsock = Some(legacy_vsock_config);
2620 }
2621
2622 #[cfg(feature = "plugin")]
2623 {
2624 use std::fs::File;
2625 use std::io::BufRead;
2626 use std::io::BufReader;
2627
2628 if let Some(p) = cmd.plugin {
2629 if cfg.executable_path.is_some() {
2630 return Err(format!(
2631 "A VM executable was already specified: {:?}",
2632 cfg.executable_path
2633 ));
2634 }
2635 cfg.executable_path = Some(Executable::Plugin(p));
2636 }
2637 cfg.plugin_root = cmd.plugin_root;
2638 cfg.plugin_mounts = cmd.plugin_mount;
2639
2640 if let Some(path) = cmd.plugin_mount_file {
2641 let file = File::open(path)
2642 .map_err(|_| String::from("unable to open `plugin-mount-file` file"))?;
2643 let reader = BufReader::new(file);
2644 for l in reader.lines() {
2645 let line = l.unwrap();
2646 let trimmed_line = line.split_once('#').map_or(&*line, |x| x.0).trim();
2647 if !trimmed_line.is_empty() {
2648 let mount = parse_plugin_mount_option(trimmed_line)?;
2649 cfg.plugin_mounts.push(mount);
2650 }
2651 }
2652 }
2653
2654 cfg.plugin_gid_maps = cmd.plugin_gid_map;
2655
2656 if let Some(path) = cmd.plugin_gid_map_file {
2657 let file = File::open(path)
2658 .map_err(|_| String::from("unable to open `plugin-gid-map-file` file"))?;
2659 let reader = BufReader::new(file);
2660 for l in reader.lines() {
2661 let line = l.unwrap();
2662 let trimmed_line = line.split_once('#').map_or(&*line, |x| x.0).trim();
2663 if !trimmed_line.is_empty() {
2664 let map = trimmed_line.parse()?;
2665 cfg.plugin_gid_maps.push(map);
2666 }
2667 }
2668 }
2669 }
2670
2671 #[cfg(feature = "tpm")]
2672 {
2673 cfg.software_tpm = cmd.software_tpm;
2674 }
2675
2676 #[cfg(all(feature = "vtpm", target_arch = "x86_64"))]
2677 {
2678 cfg.vtpm_proxy = cmd.vtpm_proxy;
2679 }
2680
2681 cfg.virtio_single_touch = cmd.single_touch;
2682 cfg.virtio_multi_touch = cmd.multi_touch;
2683 cfg.virtio_trackpad = cmd.trackpad;
2684 cfg.virtio_mice = cmd.mouse;
2685 cfg.virtio_keyboard = cmd.keyboard;
2686 cfg.virtio_switches = cmd.switches;
2687 cfg.virtio_input_evdevs = cmd.evdev;
2688
2689 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
2690 {
2691 cfg.split_irqchip = cmd.split_irqchip;
2692 }
2693
2694 cfg.initrd_path = cmd.initrd;
2695
2696 if let Some(p) = cmd.bios {
2697 if cfg.executable_path.is_some() {
2698 return Err(format!(
2699 "A VM executable was already specified: {:?}",
2700 cfg.executable_path
2701 ));
2702 }
2703 cfg.executable_path = Some(Executable::Bios(p));
2704 }
2705 cfg.pflash_parameters = cmd.pflash;
2706
2707 #[cfg(feature = "video-decoder")]
2708 {
2709 cfg.video_dec = cmd.video_decoder;
2710 }
2711 #[cfg(feature = "video-encoder")]
2712 {
2713 cfg.video_enc = cmd.video_encoder;
2714 }
2715
2716 cfg.acpi_tables = cmd.acpi_table;
2717
2718 cfg.usb = !cmd.no_usb;
2719 cfg.rng = !cmd.no_rng;
2720 cfg.balloon = !cmd.no_balloon;
2721 cfg.balloon_page_reporting = cmd.balloon_page_reporting;
2722 cfg.balloon_wss_reporting = cmd.balloon_wss_reporting;
2723 #[cfg(feature = "audio")]
2724 {
2725 cfg.virtio_snds = cmd.virtio_snd;
2726 }
2727
2728 #[cfg(feature = "gpu")]
2729 {
2730 // Due to the resource bridge, we can only create a single GPU device at the moment.
2731 if cmd.gpu.len() > 1 {
2732 return Err("at most one GPU device can currently be created".to_string());
2733 }
2734 cfg.gpu_parameters = cmd.gpu.into_iter().map(|p| p.0).take(1).next();
2735 if !cmd.gpu_display.is_empty() {
2736 cfg.gpu_parameters
2737 .get_or_insert_with(Default::default)
2738 .display_params
2739 .extend(cmd.gpu_display.into_iter().map(|p| p.0));
2740 }
2741
2742 #[cfg(windows)]
2743 if let Some(gpu_parameters) = &cfg.gpu_parameters {
2744 let num_displays = gpu_parameters.display_params.len();
2745 if num_displays > 1 {
2746 return Err(format!(
2747 "Only one display is supported (supplied {})",
2748 num_displays
2749 ));
2750 }
2751 }
2752
2753 #[cfg(unix)]
2754 {
2755 cfg.gpu_cgroup_path = cmd.gpu_cgroup_path;
2756 cfg.gpu_server_cgroup_path = cmd.gpu_server_cgroup_path;
2757 }
2758 }
2759
2760 #[cfg(unix)]
2761 {
2762 cfg.shared_dirs = cmd.shared_dir;
2763
2764 cfg.net = cmd.net;
2765
2766 let vhost_net_msg = match cmd.vhost_net {
2767 true => ",vhost-net=true",
2768 false => "",
2769 };
2770 let vq_pairs_msg = match cmd.net_vq_pairs {
2771 Some(n) => format!(",vq-pairs={}", n),
2772 None => "".to_string(),
2773 };
2774
2775 for tap_name in cmd.tap_name {
2776 log::warn!(
2777 "`--tap-name` is deprecated; please use \
2778 `--net tap-name={tap_name}{vhost_net_msg}{vq_pairs_msg}`"
2779 );
2780 cfg.net.push(NetParameters {
2781 mode: NetParametersMode::TapName {
2782 tap_name,
2783 mac: None,
2784 },
2785 vhost_net: cmd.vhost_net,
2786 vq_pairs: cmd.net_vq_pairs,
2787 });
2788 }
2789
2790 for tap_fd in cmd.tap_fd {
2791 log::warn!(
2792 "`--tap-fd` is deprecated; please use \
2793 `--net tap-fd={tap_fd}{vhost_net_msg}{vq_pairs_msg}`"
2794 );
2795 cfg.net.push(NetParameters {
2796 mode: NetParametersMode::TapFd { tap_fd, mac: None },
2797 vhost_net: cmd.vhost_net,
2798 vq_pairs: cmd.net_vq_pairs,
2799 });
2800 }
2801
2802 if cmd.host_ip.is_some() || cmd.netmask.is_some() || cmd.mac_address.is_some() {
2803 let host_ip = match cmd.host_ip {
2804 Some(host_ip) => host_ip,
2805 None => return Err("`host-ip` missing from network config".to_string()),
2806 };
2807 let netmask = match cmd.netmask {
2808 Some(netmask) => netmask,
2809 None => return Err("`netmask` missing from network config".to_string()),
2810 };
2811 let mac = match cmd.mac_address {
2812 Some(mac) => mac,
2813 None => return Err("`mac` missing from network config".to_string()),
2814 };
2815
2816 if !cmd.vhost_user_net.is_empty() {
2817 return Err(
2818 "vhost-user-net cannot be used with any of --host-ip, --netmask or --mac"
2819 .to_string(),
2820 );
2821 }
2822
2823 log::warn!(
2824 "`--host-ip`, `--netmask`, and `--mac` are deprecated; please use \
2825 `--net host-ip={host_ip},netmask={netmask},mac={mac}{vhost_net_msg}{vq_pairs_msg}`"
2826 );
2827
2828 cfg.net.push(NetParameters {
2829 mode: NetParametersMode::RawConfig {
2830 host_ip,
2831 netmask,
2832 mac,
2833 },
2834 vhost_net: cmd.vhost_net,
2835 vq_pairs: cmd.net_vq_pairs,
2836 });
2837 }
2838
2839 cfg.coiommu_param = cmd.coiommu;
2840
2841 #[cfg(all(feature = "gpu", feature = "virgl_renderer_next"))]
2842 {
2843 cfg.gpu_render_server_parameters = cmd.gpu_render_server;
2844 }
2845
2846 if let Some(d) = cmd.seccomp_policy_dir {
2847 cfg.jail_config
2848 .get_or_insert_with(Default::default)
2849 .seccomp_policy_dir = Some(d);
2850 }
2851
2852 if cmd.seccomp_log_failures {
2853 cfg.jail_config
2854 .get_or_insert_with(Default::default)
2855 .seccomp_log_failures = true;
2856 }
2857
2858 if let Some(p) = cmd.pivot_root {
2859 cfg.jail_config
2860 .get_or_insert_with(Default::default)
2861 .pivot_root = p;
2862 }
2863 }
2864
2865 let protection_flags = [
2866 cmd.protected_vm,
2867 cmd.protected_vm_with_firmware.is_some(),
2868 cmd.protected_vm_without_firmware,
2869 cmd.unprotected_vm_with_firmware.is_some(),
2870 ];
2871
2872 if protection_flags.into_iter().filter(|b| *b).count() > 1 {
2873 return Err("Only one protection mode has to be specified".to_string());
2874 }
2875
2876 cfg.protection_type = if cmd.protected_vm {
2877 ProtectionType::Protected
2878 } else if cmd.protected_vm_without_firmware {
2879 ProtectionType::ProtectedWithoutFirmware
2880 } else if let Some(p) = cmd.protected_vm_with_firmware {
2881 if !p.exists() || !p.is_file() {
2882 return Err(
2883 "protected-vm-with-firmware path should be an existing file".to_string()
2884 );
2885 }
2886 cfg.pvm_fw = Some(p);
2887 ProtectionType::ProtectedWithCustomFirmware
2888 } else if let Some(p) = cmd.unprotected_vm_with_firmware {
2889 if !p.exists() || !p.is_file() {
2890 return Err(
2891 "unprotected-vm-with-firmware path should be an existing file".to_string(),
2892 );
2893 }
2894 cfg.pvm_fw = Some(p);
2895 ProtectionType::UnprotectedWithFirmware
2896 } else {
2897 ProtectionType::Unprotected
2898 };
2899
2900 if !matches!(cfg.protection_type, ProtectionType::Unprotected) {
2901 // USB devices only work for unprotected VMs.
2902 cfg.usb = false;
2903 // Protected VMs can't trust the RNG device, so don't provide it.
2904 cfg.rng = false;
2905 }
2906
2907 cfg.battery_config = cmd.battery;
2908 #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), unix))]
2909 {
2910 cfg.ac_adapter = cmd.ac_adapter;
2911 }
2912
2913 #[cfg(feature = "gdb")]
2914 {
2915 cfg.gdb = cmd.gdb;
2916 }
2917
2918 cfg.host_cpu_topology = cmd.host_cpu_topology;
2919
2920 #[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
2921 {
2922 cfg.enable_hwp = cmd.enable_hwp;
2923 cfg.force_s2idle = cmd.s2idle;
2924 cfg.pcie_ecam = cmd.pcie_ecam;
2925 cfg.pci_low_start = cmd.pci_start;
2926 cfg.no_i8042 = cmd.no_i8042;
2927 cfg.no_rtc = cmd.no_rtc;
2928 cfg.oem_strings = cmd.oem_strings;
2929
2930 if !cfg.oem_strings.is_empty() && cfg.dmi_path.is_some() {
2931 return Err("unable to use oem-strings and dmi-path together".to_string());
2932 }
2933 for (index, msr_config) in cmd.userspace_msr {
2934 if cfg.userspace_msr.insert(index, msr_config).is_some() {
2935 return Err(String::from("msr must be unique"));
2936 }
2937 }
2938 }
2939
2940 // cfg.balloon_bias is in bytes.
2941 if let Some(b) = cmd.balloon_bias_mib {
2942 cfg.balloon_bias = b * 1024 * 1024;
2943 }
2944
2945 cfg.vhost_user_blk = cmd.vhost_user_blk;
2946 cfg.vhost_user_console = cmd.vhost_user_console;
2947 cfg.vhost_user_fs = cmd.vhost_user_fs;
2948 cfg.vhost_user_gpu = cmd.vhost_user_gpu;
2949 cfg.vhost_user_mac80211_hwsim = cmd.vhost_user_mac80211_hwsim;
2950 cfg.vhost_user_net = cmd.vhost_user_net;
2951 cfg.vhost_user_video_dec = cmd.vhost_user_video_decoder;
2952 cfg.vhost_user_vsock = cmd.vhost_user_vsock;
2953 cfg.vhost_user_wl = cmd.vhost_user_wl;
2954
2955 #[cfg(feature = "direct")]
2956 {
2957 cfg.direct_pmio = cmd.direct_pmio;
2958 cfg.direct_mmio = cmd.direct_mmio;
2959 cfg.direct_level_irq = cmd.direct_level_irq;
2960 cfg.direct_edge_irq = cmd.direct_edge_irq;
2961 cfg.direct_gpe = cmd.direct_gpe;
2962 cfg.direct_fixed_evts = cmd.direct_fixed_event;
2963 cfg.pcie_rp = cmd.pcie_root_port;
2964 cfg.mmio_address_ranges = cmd.mmio_address_range.unwrap_or_default();
2965 }
2966
2967 cfg.disable_virtio_intx = cmd.disable_virtio_intx;
2968
2969 cfg.dmi_path = cmd.dmi;
2970
2971 cfg.dump_device_tree_blob = cmd.dump_device_tree_blob;
2972
2973 cfg.itmt = cmd.itmt;
2974
2975 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
2976 if cmd.enable_pnp_data && cmd.force_calibrated_tsc_leaf {
2977 return Err(
2978 "Only one of [enable_pnp_data,force_calibrated_tsc_leaf] can be specified"
2979 .to_string(),
2980 );
2981 }
2982
2983 cfg.enable_pnp_data = cmd.enable_pnp_data;
2984
2985 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
2986 {
2987 cfg.force_calibrated_tsc_leaf = cmd.force_calibrated_tsc_leaf;
2988 }
2989
2990 cfg.privileged_vm = cmd.privileged_vm;
2991
2992 cfg.stub_pci_devices = cmd.stub_pci_device;
2993
2994 cfg.vvu_proxy = cmd.vvu_proxy;
2995
2996 cfg.file_backed_mappings = cmd.file_backed_mapping;
2997
2998 cfg.init_memory = cmd.init_mem;
2999
3000 cfg.strict_balloon = cmd.strict_balloon;
3001
3002 #[cfg(target_os = "android")]
3003 {
3004 cfg.task_profiles = cmd.task_profiles;
3005 }
3006
3007 #[cfg(unix)]
3008 {
3009 if cmd.unmap_guest_memory_on_fork && !cmd.disable_sandbox {
3010 return Err("--unmap-guest-memory-on-fork requires --disable-sandbox".to_string());
3011 }
3012 cfg.unmap_guest_memory_on_fork = cmd.unmap_guest_memory_on_fork;
3013 }
3014
3015 #[cfg(unix)]
3016 {
3017 cfg.vfio.extend(cmd.vfio);
3018 cfg.vfio.extend(cmd.vfio_platform);
3019 cfg.vfio_isolate_hotplug = cmd.vfio_isolate_hotplug;
3020 }
3021
3022 // `--disable-sandbox` has the effect of disabling sandboxing altogether, so make sure
3023 // to handle it after other sandboxing options since they implicitly enable it.
3024 if cmd.disable_sandbox {
3025 cfg.jail_config = None;
3026 }
3027
3028 // Now do validation of constructed config
3029 super::config::validate_config(&mut cfg)?;
3030
3031 Ok(cfg)
3032 }
3033 }
3034