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