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