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