crosvm/crosvm/
cmdline.rs

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