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