vm_control/
lib.rs

1// Copyright 2017 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//! Handles IPC for controlling the main VM process.
6//!
7//! The VM Control IPC protocol is synchronous, meaning that each `VmRequest` sent over a connection
8//! will receive a `VmResponse` for that request next time data is received over that connection.
9//!
10//! The wire message format is a little-endian C-struct of fixed size, along with a file descriptor
11//! if the request type expects one.
12
13pub mod api;
14
15mod any_control_tube;
16pub use any_control_tube::AnyControlTube;
17
18mod device_id;
19pub use device_id::DeviceId;
20pub use device_id::PciId;
21pub use device_id::PlatformDeviceId;
22
23#[cfg(feature = "gdb")]
24pub mod gdb;
25pub mod gpu;
26
27use base::debug;
28#[cfg(any(target_os = "android", target_os = "linux"))]
29use base::linux::MemoryMappingBuilderUnix;
30#[cfg(any(target_os = "android", target_os = "linux"))]
31use base::sys::call_with_extended_max_files;
32#[cfg(any(target_os = "android", target_os = "linux"))]
33use base::MemoryMappingArena;
34#[cfg(windows)]
35use base::MemoryMappingBuilderWindows;
36use hypervisor::BalloonEvent;
37use hypervisor::MemCacheType;
38use hypervisor::MemRegion;
39use snapshot::AnySnapshot;
40
41#[cfg(feature = "balloon")]
42mod balloon_tube;
43pub mod client;
44pub mod sys;
45
46#[cfg(target_arch = "x86_64")]
47use std::arch::x86_64::_rdtsc;
48use std::collections::BTreeMap;
49use std::collections::BTreeSet;
50use std::collections::HashMap;
51use std::convert::TryInto;
52use std::fmt;
53use std::fmt::Display;
54use std::fs::File;
55use std::path::Path;
56use std::path::PathBuf;
57use std::result::Result as StdResult;
58use std::str::FromStr;
59use std::sync::mpsc;
60use std::sync::Arc;
61use std::time::Instant;
62
63use anyhow::bail;
64use anyhow::Context;
65use base::error;
66use base::info;
67use base::warn;
68use base::with_as_descriptor;
69use base::AsRawDescriptor;
70use base::Descriptor;
71use base::Error as SysError;
72use base::Event;
73use base::ExternalMapping;
74#[cfg(feature = "gpu")]
75use base::IntoRawDescriptor;
76use base::MappedRegion;
77use base::MemoryMappingBuilder;
78use base::MmapError;
79use base::Protection;
80use base::Result;
81use base::SafeDescriptor;
82use base::SharedMemory;
83use base::Tube;
84use hypervisor::Datamatch;
85use hypervisor::IoEventAddress;
86use hypervisor::IrqRoute;
87use hypervisor::IrqSource;
88pub use hypervisor::MemSlot;
89use hypervisor::Vm;
90use hypervisor::VmCap;
91use libc::EINVAL;
92use libc::EIO;
93use libc::ENODEV;
94use libc::ENOTSUP;
95use libc::EPERM;
96use libc::ERANGE;
97#[cfg(feature = "registered_events")]
98use protos::registered_events;
99use remain::sorted;
100use resources::Alloc;
101use resources::SystemAllocator;
102#[cfg(feature = "gpu")]
103use rutabaga_gfx::RutabagaDescriptor;
104#[cfg(feature = "gpu")]
105use rutabaga_gfx::RutabagaFromRawDescriptor;
106#[cfg(feature = "gpu")]
107use rutabaga_gfx::RutabagaGralloc;
108#[cfg(feature = "gpu")]
109use rutabaga_gfx::RutabagaMagmaHandle;
110#[cfg(feature = "gpu")]
111use rutabaga_gfx::RutabagaMappedRegion;
112#[cfg(feature = "gpu")]
113use rutabaga_gfx::VulkanInfo;
114use serde::de::Error;
115use serde::Deserialize;
116use serde::Serialize;
117use snapshot::SnapshotReader;
118use snapshot::SnapshotWriter;
119use swap::SwapStatus;
120use sync::Mutex;
121#[cfg(any(target_os = "android", target_os = "linux"))]
122pub use sys::FsMappingRequest;
123#[cfg(windows)]
124pub use sys::InitialAudioSessionState;
125#[cfg(any(target_os = "android", target_os = "linux"))]
126pub use sys::VmMemoryMappingRequest;
127#[cfg(any(target_os = "android", target_os = "linux"))]
128pub use sys::VmMemoryMappingResponse;
129use thiserror::Error;
130pub use vm_control_product::GpuSendToMain;
131pub use vm_control_product::GpuSendToService;
132pub use vm_control_product::ServiceSendToGpu;
133use vm_memory::GuestAddress;
134
135#[cfg(feature = "balloon")]
136pub use crate::balloon_tube::BalloonControlCommand;
137#[cfg(feature = "balloon")]
138pub use crate::balloon_tube::BalloonTube;
139#[cfg(feature = "gdb")]
140pub use crate::gdb::VcpuDebug;
141#[cfg(feature = "gdb")]
142pub use crate::gdb::VcpuDebugStatus;
143#[cfg(feature = "gdb")]
144pub use crate::gdb::VcpuDebugStatusMessage;
145use crate::gpu::GpuControlCommand;
146use crate::gpu::GpuControlResult;
147
148/// Control the state of a particular VM CPU.
149#[derive(Clone, Debug)]
150pub enum VcpuControl {
151    #[cfg(feature = "gdb")]
152    Debug(VcpuDebug),
153    RunState(VmRunMode),
154    MakeRT,
155    // Request the current state of the vCPU. The result is sent back over the included channel.
156    GetStates(mpsc::Sender<VmRunMode>),
157    // Request the vcpu write a snapshot of itself to the writer, then send a `Result` back over
158    // the channel after completion/failure.
159    Snapshot(SnapshotWriter, mpsc::Sender<anyhow::Result<()>>),
160    Restore(VcpuRestoreRequest),
161    #[cfg(any(target_os = "android", target_os = "linux"))]
162    Throttle(u32),
163}
164
165/// Request to restore a Vcpu from a given snapshot, and report the results
166/// back via the provided channel.
167#[derive(Clone, Debug)]
168pub struct VcpuRestoreRequest {
169    pub result_sender: mpsc::Sender<anyhow::Result<()>>,
170    pub snapshot_reader: SnapshotReader,
171    #[cfg(target_arch = "x86_64")]
172    pub host_tsc_reference_moment: u64,
173}
174
175/// Mode of execution for the VM.
176#[derive(Debug, Copy, Clone, Default, PartialEq, Eq)]
177pub enum VmRunMode {
178    /// The default run mode indicating the VCPUs are running.
179    #[default]
180    Running,
181    /// Indicates that the VCPUs are suspending execution until the `Running` mode is set.
182    Suspending,
183    /// Indicates that the VM is exiting all processes.
184    Exiting,
185    /// Indicates that the VM is in a breakpoint waiting for the debugger to do continue.
186    Breakpoint,
187}
188
189impl Display for VmRunMode {
190    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
191        use self::VmRunMode::*;
192
193        match self {
194            Running => write!(f, "running"),
195            Suspending => write!(f, "suspending"),
196            Exiting => write!(f, "exiting"),
197            Breakpoint => write!(f, "breakpoint"),
198        }
199    }
200}
201
202// Trait for devices that get notification on specific PCI PME
203pub trait PmeNotify: Send {
204    fn notify(&mut self, _requester_id: u16) {}
205}
206
207pub trait PmResource {
208    fn pwrbtn_evt(&mut self) {}
209    fn slpbtn_evt(&mut self) {}
210    fn rtc_evt(&mut self, _clear_evt: Event) {}
211    fn gpe_evt(&mut self, _gpe: u32, _clear_evt: Option<Event>) {}
212    fn pme_evt(&mut self, _requester_id: u16) {}
213    fn register_pme_notify_dev(&mut self, _bus: u8, _notify_dev: Arc<Mutex<dyn PmeNotify>>) {}
214}
215
216/// The maximum number of devices that can be listed in one `UsbControlCommand`.
217///
218/// This value was set to be equal to `xhci_regs::MAX_PORTS` for convenience, but it is not
219/// necessary for correctness. Importing that value directly would be overkill because it would
220/// require adding a big dependency for a single const.
221pub const USB_CONTROL_MAX_PORTS: usize = 16;
222
223#[derive(Serialize, Deserialize, Debug)]
224pub enum DiskControlCommand {
225    /// Resize a disk to `new_size` in bytes.
226    Resize { new_size: u64 },
227}
228
229impl Display for DiskControlCommand {
230    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
231        use self::DiskControlCommand::*;
232
233        match self {
234            Resize { new_size } => write!(f, "disk_resize {new_size}"),
235        }
236    }
237}
238
239#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
240pub enum DiskControlResult {
241    Ok,
242    Err(SysError),
243}
244
245#[derive(Serialize, Deserialize, Debug, Clone)]
246pub enum FsAllowlistCommand {
247    AddPaths { paths: Vec<PathBuf> },
248    RemovePaths { paths: Vec<PathBuf> },
249}
250
251#[derive(Serialize, Deserialize, Debug, Clone)]
252pub enum FsAllowlistResponse {
253    Ok,
254    Err(String),
255}
256
257/// Wire protocol request for virtio-snd host audio permission delegation.
258#[repr(u8)]
259#[derive(Copy, Clone, Debug, PartialEq, Eq)]
260pub enum AudioPermissionRequest {
261    /// Audio capture stream starting; request host permission.
262    Check = 1,
263}
264
265impl AudioPermissionRequest {
266    pub const fn to_wire(self) -> u8 {
267        self as u8
268    }
269}
270
271impl TryFrom<u8> for AudioPermissionRequest {
272    type Error = u8;
273
274    fn try_from(val: u8) -> StdResult<Self, Self::Error> {
275        match val {
276            1 => Ok(Self::Check),
277            unknown => Err(unknown),
278        }
279    }
280}
281
282/// Wire protocol response for virtio-snd host audio permission delegation.
283#[repr(u8)]
284#[derive(Copy, Clone, Debug, PartialEq, Eq)]
285pub enum AudioPermissionResponse {
286    /// Permission granted by the user or host policy.
287    Granted = 1,
288    /// Permission denied by the user, host policy, or client disconnect.
289    Denied = 2,
290}
291
292impl AudioPermissionResponse {
293    pub const fn to_wire(self) -> u8 {
294        self as u8
295    }
296}
297
298impl TryFrom<u8> for AudioPermissionResponse {
299    type Error = u8;
300
301    fn try_from(val: u8) -> StdResult<Self, Self::Error> {
302        match val {
303            1 => Ok(Self::Granted),
304            2 => Ok(Self::Denied),
305            unknown => Err(unknown),
306        }
307    }
308}
309
310/// Net control commands for adding and removing tap devices.
311#[cfg(feature = "pci-hotplug")]
312#[derive(Serialize, Deserialize, Debug)]
313pub enum NetControlCommand {
314    AddTap(String),
315    RemoveTap(u8),
316}
317
318#[derive(Serialize, Deserialize, Debug)]
319pub enum UsbControlCommand {
320    AttachDevice {
321        #[serde(with = "with_as_descriptor")]
322        file: File,
323    },
324    AttachSecurityKey {
325        #[serde(with = "with_as_descriptor")]
326        file: File,
327    },
328    DetachDevice {
329        port: u8,
330    },
331    ListDevice {
332        ports: [u8; USB_CONTROL_MAX_PORTS],
333    },
334}
335
336#[derive(Serialize, Deserialize, Copy, Clone, Debug, Default)]
337pub struct UsbControlAttachedDevice {
338    pub port: u8,
339    pub vendor_id: u16,
340    pub product_id: u16,
341}
342
343impl UsbControlAttachedDevice {
344    pub fn valid(self) -> bool {
345        self.port != 0
346    }
347}
348
349#[cfg(feature = "pci-hotplug")]
350#[derive(Serialize, Deserialize, Debug, Clone)]
351#[must_use]
352/// Result for hotplug and removal of PCI device.
353pub enum PciControlResult {
354    AddOk { bus: u8 },
355    ErrString(String),
356    RemoveOk,
357}
358
359#[cfg(feature = "pci-hotplug")]
360impl Display for PciControlResult {
361    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
362        use self::PciControlResult::*;
363
364        match self {
365            AddOk { bus } => write!(f, "add_ok {bus}"),
366            ErrString(e) => write!(f, "error: {e}"),
367            RemoveOk => write!(f, "remove_ok"),
368        }
369    }
370}
371
372#[derive(Serialize, Deserialize, Debug, Clone)]
373pub enum UsbControlResult {
374    Ok { port: u8 },
375    NoAvailablePort,
376    NoSuchDevice,
377    NoSuchPort,
378    FailedToOpenDevice,
379    Devices([UsbControlAttachedDevice; USB_CONTROL_MAX_PORTS]),
380    FailedToInitHostDevice,
381}
382
383impl Display for UsbControlResult {
384    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
385        use self::UsbControlResult::*;
386
387        match self {
388            UsbControlResult::Ok { port } => write!(f, "ok {port}"),
389            NoAvailablePort => write!(f, "no_available_port"),
390            NoSuchDevice => write!(f, "no_such_device"),
391            NoSuchPort => write!(f, "no_such_port"),
392            FailedToOpenDevice => write!(f, "failed_to_open_device"),
393            Devices(devices) => {
394                write!(f, "devices")?;
395                for d in devices.iter().filter(|d| d.valid()) {
396                    write!(f, " {} {:04x} {:04x}", d.port, d.vendor_id, d.product_id)?;
397                }
398                std::result::Result::Ok(())
399            }
400            FailedToInitHostDevice => write!(f, "failed_to_init_host_device"),
401        }
402    }
403}
404
405/// Commands for snapshot feature
406#[derive(Serialize, Deserialize, Debug)]
407pub enum SnapshotCommand {
408    Take {
409        snapshot_path: PathBuf,
410        compress_memory: bool,
411        encrypt: bool,
412    },
413}
414
415/// Commands for actions on devices and the devices control thread.
416#[derive(Serialize, Deserialize, Debug)]
417pub enum DeviceControlCommand {
418    SleepDevices,
419    WakeDevices,
420    SnapshotDevices { snapshot_writer: SnapshotWriter },
421    RestoreDevices { snapshot_reader: SnapshotReader },
422    GetDevicesState,
423    Exit,
424}
425
426/// Commands to control the IRQ handler thread.
427#[derive(Serialize, Deserialize)]
428pub enum IrqHandlerRequest {
429    /// No response is sent for this command.
430    AddIrqControlTubes(Vec<Tube>),
431    /// Refreshes the set of event tokens (Events) from the Irqchip that the IRQ
432    /// handler waits on to forward IRQs to their final destination (e.g. via
433    /// Irqchip::service_irq_event).
434    ///
435    /// If the set of tokens exposed by the Irqchip changes while the VM is
436    /// running (such as for snapshot restore), this command must be sent
437    /// otherwise the VM will not receive IRQs as expected.
438    RefreshIrqEventTokens,
439    WakeAndNotifyIteration,
440    /// No response is sent for this command.
441    Exit,
442}
443
444const EXPECTED_MAX_IRQ_FLUSH_ITERATIONS: usize = 100;
445
446/// Response for [IrqHandlerRequest].
447#[derive(Serialize, Deserialize, Debug)]
448pub enum IrqHandlerResponse {
449    /// Sent when the IRQ event tokens have been refreshed.
450    IrqEventTokenRefreshComplete,
451    /// Specifies the number of tokens serviced in the requested iteration
452    /// (less the token for the `WakeAndNotifyIteration` request).
453    HandlerIterationComplete(usize),
454}
455
456/// Source of a `VmMemoryRequest::RegisterMemory` mapping.
457#[derive(Serialize, Deserialize)]
458pub enum VmMemorySource {
459    /// Register shared memory represented by the given descriptor.
460    /// On Windows, descriptor MUST be a mapping handle.
461    SharedMemory(SharedMemory),
462    /// Register a file mapping from the given descriptor.
463    Descriptor {
464        /// File descriptor to map.
465        descriptor: SafeDescriptor,
466        /// Offset within the file in bytes.
467        offset: u64,
468        /// Size of the mapping in bytes.
469        size: u64,
470    },
471    /// Register memory mapped by Vulkano.
472    Vulkan {
473        descriptor: SafeDescriptor,
474        handle_type: u32,
475        memory_idx: u32,
476        device_uuid: [u8; 16],
477        driver_uuid: [u8; 16],
478        size: u64,
479    },
480    /// Register the current rutabaga external mapping.
481    ExternalMapping { ptr: u64, size: u64 },
482}
483
484// The following are wrappers to avoid base dependencies in the rutabaga crate
485#[cfg(feature = "gpu")]
486fn to_rutabaga_desciptor(s: SafeDescriptor) -> RutabagaDescriptor {
487    // SAFETY:
488    // Safe because we own the SafeDescriptor at this point.
489    unsafe { RutabagaDescriptor::from_raw_descriptor(s.into_raw_descriptor()) }
490}
491
492#[cfg(feature = "gpu")]
493struct RutabagaMemoryRegion {
494    region: Box<dyn RutabagaMappedRegion>,
495}
496
497#[cfg(feature = "gpu")]
498impl RutabagaMemoryRegion {
499    pub fn new(region: Box<dyn RutabagaMappedRegion>) -> RutabagaMemoryRegion {
500        RutabagaMemoryRegion { region }
501    }
502}
503
504#[cfg(feature = "gpu")]
505// SAFETY:
506//
507// Self guarantees `ptr`..`ptr+size` is an mmaped region owned by this object that
508// can't be unmapped during the `MappedRegion`'s lifetime.
509unsafe impl MappedRegion for RutabagaMemoryRegion {
510    fn as_ptr(&self) -> *mut u8 {
511        self.region.as_ptr()
512    }
513
514    fn size(&self) -> usize {
515        self.region.size()
516    }
517}
518
519impl Display for VmMemorySource {
520    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
521        use self::VmMemorySource::*;
522
523        match self {
524            SharedMemory(..) => write!(f, "VmMemorySource::SharedMemory"),
525            Descriptor { .. } => write!(f, "VmMemorySource::Descriptor"),
526            Vulkan { .. } => write!(f, "VmMemorySource::Vulkan"),
527            ExternalMapping { .. } => write!(f, "VmMemorySource::ExternalMapping"),
528        }
529    }
530}
531
532impl VmMemorySource {
533    /// Map the resource and return its mapping and size in bytes.
534    fn map(
535        self,
536        #[cfg(feature = "gpu")] gralloc: &mut RutabagaGralloc,
537        prot: Protection,
538    ) -> anyhow::Result<(Box<dyn MappedRegion>, u64, Option<SafeDescriptor>)> {
539        let (mem_region, size, descriptor) = match self {
540            VmMemorySource::Descriptor {
541                descriptor,
542                offset,
543                size,
544            } => (
545                map_descriptor(&descriptor, offset, size, prot)?,
546                size,
547                Some(descriptor),
548            ),
549
550            VmMemorySource::SharedMemory(shm) => {
551                (map_descriptor(&shm, 0, shm.size(), prot)?, shm.size(), None)
552            }
553            #[cfg(feature = "gpu")]
554            VmMemorySource::Vulkan {
555                descriptor,
556                handle_type,
557                memory_idx,
558                device_uuid,
559                driver_uuid,
560                size,
561            } => {
562                let device_id = rutabaga_gfx::DeviceId {
563                    device_uuid,
564                    driver_uuid,
565                };
566                let mapped_region = gralloc
567                        .import_and_map(
568                            RutabagaMagmaHandle {
569                                os_handle: to_rutabaga_desciptor(descriptor),
570                                handle_type,
571                            },
572                            VulkanInfo {
573                                memory_idx,
574                                device_id,
575                            },
576                            size,
577                        )
578                        .with_context(|| {
579                            format!(
580                                "gralloc failed to import and map, handle type: {handle_type}, memory index {memory_idx}, \
581                                size: {size}"
582                            )
583                        })?;
584                let mapped_region: Box<dyn MappedRegion> =
585                    Box::new(RutabagaMemoryRegion::new(mapped_region));
586                (mapped_region, size, None)
587            }
588            #[cfg(not(feature = "gpu"))]
589            VmMemorySource::Vulkan { .. } => {
590                return Err(anyhow::anyhow!(
591                    "vulkan mapping is not supported without GPU feature"
592                ));
593            }
594            VmMemorySource::ExternalMapping { ptr, size } => {
595                let mapped_region: Box<dyn MappedRegion> = Box::new(ExternalMapping {
596                    ptr,
597                    size: size as usize,
598                });
599                (mapped_region, size, None)
600            }
601        };
602        Ok((mem_region, size, descriptor))
603    }
604}
605
606/// Destination of a `VmMemoryRequest::RegisterMemory` mapping in guest address space.
607#[derive(Serialize, Deserialize)]
608pub enum VmMemoryDestination {
609    /// Map at an offset within an existing PCI BAR allocation.
610    ExistingAllocation { allocation: Alloc, offset: u64 },
611    /// Map at the specified guest physical address.
612    GuestPhysicalAddress(u64),
613}
614
615impl VmMemoryDestination {
616    /// Allocate and return the guest address of a memory mapping destination.
617    pub fn allocate(self, allocator: &mut SystemAllocator, size: u64) -> Result<GuestAddress> {
618        let addr = match self {
619            VmMemoryDestination::ExistingAllocation { allocation, offset } => allocator
620                .mmio_allocator_any()
621                .address_from_pci_offset(allocation, offset, size)
622                .map_err(|_e| SysError::new(EINVAL))?,
623            VmMemoryDestination::GuestPhysicalAddress(gpa) => gpa,
624        };
625        Ok(GuestAddress(addr))
626    }
627}
628
629/// Request to register or unregister an ioevent.
630#[derive(Serialize, Deserialize)]
631pub struct IoEventUpdateRequest {
632    pub event: Event,
633    pub addr: u64,
634    pub datamatch: Datamatch,
635    pub register: bool,
636}
637
638/// Request to mmap a file to a shared memory.
639/// This request is supposed to follow a `VmMemoryRequest::MmapAndRegisterMemory` request that
640/// contains `SharedMemory` that `file` is mmaped to.
641#[cfg(any(target_os = "android", target_os = "linux"))]
642#[derive(Serialize, Deserialize)]
643pub struct VmMemoryFileMapping {
644    #[serde(with = "with_as_descriptor")]
645    pub file: File,
646    pub length: usize,
647    pub mem_offset: usize,
648    pub file_offset: u64,
649}
650
651#[derive(Serialize, Deserialize)]
652pub enum VmMemoryRequest {
653    /// Prepare a shared memory region to make later operations more efficient. This
654    /// may be a no-op depending on underlying platform support.
655    PrepareSharedMemoryRegion { alloc: Alloc, cache: MemCacheType },
656    /// Register a memory to be mapped to the guest.
657    RegisterMemory {
658        /// Source of the memory to register (mapped file descriptor, shared memory region, etc.)
659        source: VmMemorySource,
660        /// Where to map the memory in the guest.
661        dest: VmMemoryDestination,
662        /// Whether to map the memory read only (true) or read-write (false).
663        prot: Protection,
664        /// Cache attribute for guest memory setting
665        cache: MemCacheType,
666    },
667    #[cfg(any(target_os = "android", target_os = "linux"))]
668    /// Call mmap to `shm` and register the memory region as a read-only guest memory.
669    /// This request is followed by an array of `VmMemoryFileMapping` with length
670    /// `num_file_mappings`
671    MmapAndRegisterMemory {
672        /// Source of the memory to register (mapped file descriptor, shared memory region, etc.)
673        shm: SharedMemory,
674        /// Where to map the memory in the guest.
675        dest: VmMemoryDestination,
676        /// Length of the array of `VmMemoryFileMapping` that follows.
677        num_file_mappings: usize,
678    },
679    /// Call hypervisor to free the given memory range.
680    DynamicallyFreeMemoryRanges { ranges: Vec<(GuestAddress, u64)> },
681    /// Call hypervisor to reclaim a priorly freed memory range.
682    DynamicallyReclaimMemoryRanges { ranges: Vec<(GuestAddress, u64)> },
683    /// Balloon allocation/deallocation target reached.
684    BalloonTargetReached { size: u64 },
685    /// Unregister the given memory slot that was previously registered with `RegisterMemory`.
686    UnregisterMemory(VmMemoryRegionId),
687    /// Register an eventfd with raw guest memory address.
688    IoEventRaw(IoEventUpdateRequest),
689}
690
691/// Struct for managing `VmMemoryRequest`s IOMMU related state.
692pub struct VmMemoryRequestIommuClient {
693    tube: Arc<Mutex<Tube>>,
694    registered_memory: BTreeSet<VmMemoryRegionId>,
695}
696
697impl VmMemoryRequestIommuClient {
698    /// Constructs `VmMemoryRequestIommuClient` from a tube for communication with the viommu.
699    pub fn new(tube: Arc<Mutex<Tube>>) -> Self {
700        Self {
701            tube,
702            registered_memory: BTreeSet::new(),
703        }
704    }
705}
706
707enum RegisteredMemory {
708    FixedMapping {
709        slot: MemSlot,
710        offset: usize,
711        size: usize,
712    },
713    DynamicMapping {
714        slot: MemSlot,
715    },
716}
717
718pub struct VmMappedMemoryRegion {
719    guest_address: GuestAddress,
720    slot: MemSlot,
721}
722
723#[derive(Default)]
724pub struct VmMemoryRegionState {
725    mapped_regions: HashMap<Alloc, VmMappedMemoryRegion>,
726    registered_memory: BTreeMap<VmMemoryRegionId, RegisteredMemory>,
727}
728
729fn try_map_to_prepared_region(
730    vm: &dyn Vm,
731    region_state: &mut VmMemoryRegionState,
732    source: &VmMemorySource,
733    dest: &VmMemoryDestination,
734    prot: &Protection,
735) -> Option<VmMemoryResponse> {
736    let VmMemoryDestination::ExistingAllocation {
737        allocation,
738        offset: dest_offset,
739    } = dest
740    else {
741        return None;
742    };
743
744    let VmMappedMemoryRegion {
745        guest_address,
746        slot,
747    } = region_state.mapped_regions.get(allocation)?;
748
749    let (descriptor, file_offset, size) = match source {
750        VmMemorySource::Descriptor {
751            descriptor,
752            offset,
753            size,
754        } => (
755            Descriptor(descriptor.as_raw_descriptor()),
756            *offset,
757            *size as usize,
758        ),
759        VmMemorySource::SharedMemory(shm) => {
760            let size = shm.size() as usize;
761            (Descriptor(shm.as_raw_descriptor()), 0, size)
762        }
763        _ => {
764            let error = anyhow::anyhow!(
765                "source {} is not compatible with fixed mapping into prepared memory region",
766                source
767            );
768            return Some(VmMemoryResponse::Err(error.into()));
769        }
770    };
771    if let Err(err) = vm
772        .add_fd_mapping(
773            *slot,
774            *dest_offset as usize,
775            size,
776            &descriptor,
777            file_offset,
778            *prot,
779        )
780        .context("failed to add fd mapping when trying to map to prepared region")
781    {
782        return Some(VmMemoryResponse::Err(err.into()));
783    }
784
785    let guest_address = GuestAddress(guest_address.0 + dest_offset);
786    let region_id = VmMemoryRegionId(guest_address);
787    region_state.registered_memory.insert(
788        region_id,
789        RegisteredMemory::FixedMapping {
790            slot: *slot,
791            offset: *dest_offset as usize,
792            size,
793        },
794    );
795
796    Some(VmMemoryResponse::RegisterMemory {
797        region_id,
798        slot: *slot,
799    })
800}
801
802impl VmMemoryRequest {
803    /// Executes this request on the given Vm.
804    ///
805    /// # Arguments
806    /// * `vm` - The `Vm` to perform the request on.
807    /// * `allocator` - Used to allocate addresses.
808    ///
809    /// This does not return a result, instead encapsulating the success or failure in a
810    /// `VmMemoryResponse` with the intended purpose of sending the response back over the socket
811    /// that received this `VmMemoryResponse`.
812    pub fn execute(
813        self,
814        #[cfg(any(target_os = "android", target_os = "linux"))] tube: &Tube,
815        vm: &dyn Vm,
816        sys_allocator: &mut SystemAllocator,
817        #[cfg(feature = "gpu")] gralloc: &mut RutabagaGralloc,
818        iommu_client: Option<&mut VmMemoryRequestIommuClient>,
819        region_state: &mut VmMemoryRegionState,
820        remote_peer: bool,
821    ) -> VmMemoryResponse {
822        use self::VmMemoryRequest::*;
823        match self {
824            PrepareSharedMemoryRegion { alloc, cache } => {
825                // Currently the iommu_client is only used by virtio-gpu when used alongside GPU
826                // pci-passthrough.
827                //
828                // TODO(b/323368701): Make compatible with iommu_client by ensuring that
829                // VirtioIOMMUVfioCommand::VfioDmabufMap is submitted for both dynamic mappings and
830                // fixed mappings (i.e. whether or not try_map_to_prepared_region succeeds in
831                // RegisterMemory case below).
832                assert!(iommu_client.is_none());
833
834                if !sys::should_prepare_memory_region() {
835                    return VmMemoryResponse::Ok;
836                }
837
838                match sys::prepare_shared_memory_region(vm, sys_allocator, alloc, cache)
839                    .context("failed to prepare shared memory region")
840                {
841                    Ok(region) => {
842                        region_state.mapped_regions.insert(alloc, region);
843                        VmMemoryResponse::Ok
844                    }
845                    Err(e) => VmMemoryResponse::Err(e.into()),
846                }
847            }
848            RegisterMemory {
849                source,
850                dest,
851                prot,
852                cache,
853            } => {
854                // ExternalMapping contains raw pointers and so should only be allowed for peers
855                // within the main process.
856                if remote_peer && matches!(source, VmMemorySource::ExternalMapping { .. }) {
857                    return VmMemoryResponse::Err(anyhow::Error::new(SysError::new(EPERM)).into());
858                }
859
860                if let Some(resp) =
861                    try_map_to_prepared_region(vm, region_state, &source, &dest, &prot)
862                {
863                    return resp;
864                }
865
866                // Correct on Windows because callers of this IPC guarantee descriptor is a mapping
867                // handle.
868                let (mapped_region, size, descriptor) = match source
869                    .map(
870                        #[cfg(feature = "gpu")]
871                        gralloc,
872                        prot,
873                    )
874                    .context("gralloc mapping")
875                {
876                    Ok((region, size, descriptor)) => (region, size, descriptor),
877                    Err(e) => return VmMemoryResponse::Err(e.into()),
878                };
879
880                let guest_addr = match dest
881                    .allocate(sys_allocator, size)
882                    .context("VM memory destination allocation fails")
883                {
884                    Ok(addr) => addr,
885                    Err(e) => return VmMemoryResponse::Err(e.into()),
886                };
887
888                let slot = match vm
889                    .add_memory_region(
890                        guest_addr,
891                        mapped_region,
892                        prot == Protection::read(),
893                        false,
894                        cache,
895                    )
896                    .context("failed to add memory region when registering memory")
897                {
898                    Ok(slot) => slot,
899                    Err(e) => return VmMemoryResponse::Err(e.into()),
900                };
901
902                let region_id = VmMemoryRegionId(guest_addr);
903                if let (Some(descriptor), Some(iommu_client)) = (descriptor, iommu_client) {
904                    let request =
905                        VirtioIOMMURequest::VfioCommand(VirtioIOMMUVfioCommand::VfioDmabufMap {
906                            region_id,
907                            gpa: guest_addr.0,
908                            size,
909                            dma_buf: descriptor,
910                        });
911
912                    match virtio_iommu_request(&iommu_client.tube.lock(), &request) {
913                        Ok(VirtioIOMMUResponse::VfioResponse(VirtioIOMMUVfioResult::Ok)) => (),
914                        resp => {
915                            let error = anyhow::anyhow!(
916                                "Unexpected virtio-iommu message response when registering memory: \
917                                 {:?}", resp);
918                            if let Err(e) = vm.remove_memory_region(slot) {
919                                // There is nothing we can do here, so we just log a warning
920                                // message.
921                                warn!("failed to remove memory region: {:?}", e);
922                            }
923                            return VmMemoryResponse::Err(error.into());
924                        }
925                    };
926
927                    iommu_client.registered_memory.insert(region_id);
928                }
929
930                region_state
931                    .registered_memory
932                    .insert(region_id, RegisteredMemory::DynamicMapping { slot });
933                VmMemoryResponse::RegisterMemory { region_id, slot }
934            }
935            #[cfg(any(target_os = "android", target_os = "linux"))]
936            MmapAndRegisterMemory {
937                shm,
938                dest,
939                num_file_mappings,
940            } => {
941                // Define a callback to be executed with extended limit of file counts.
942                // It recieves `num_file_mappings` FDs and call `add_fd_mapping` for each.
943                let callback = || {
944                    let mem = match MemoryMappingBuilder::new(shm.size() as usize)
945                        .from_shared_memory(&shm)
946                        .build()
947                        .context("failed to build MemoryMapping from shared memory")
948                    {
949                        Ok(mem) => mem,
950                        Err(e) => return Err(VmMemoryResponse::Err(e.into())),
951                    };
952                    let mut mmap_arena = MemoryMappingArena::from(mem);
953
954                    // If `num_file_mappings` exceeds `SCM_MAX_FD`, `file_mappings` are sent in
955                    // chunks of length `SCM_MAX_FD`.
956                    let mut file_mappings = Vec::with_capacity(num_file_mappings);
957                    let mut read = 0;
958                    while read < num_file_mappings {
959                        let len = std::cmp::min(num_file_mappings - read, base::unix::SCM_MAX_FD);
960                        let mps: Vec<VmMemoryFileMapping> = match tube
961                            .recv_with_max_fds(len)
962                            .with_context(|| format!("get {num_file_mappings} FDs to be mapped"))
963                        {
964                            Ok(m) => m,
965                            Err(e) => return Err(VmMemoryResponse::Err(e.into())),
966                        };
967                        file_mappings.extend(mps.into_iter());
968                        read += len;
969                    }
970
971                    for VmMemoryFileMapping {
972                        mem_offset,
973                        length,
974                        file,
975                        file_offset,
976                    } in file_mappings
977                    {
978                        if let Err(e) = mmap_arena
979                            .add_fd_mapping(
980                                mem_offset,
981                                length,
982                                &file,
983                                file_offset,
984                                Protection::read(),
985                            )
986                            .context(
987                                "failed to add fd mapping when handling mmap and register memory",
988                            )
989                        {
990                            return Err(VmMemoryResponse::Err(e.into()));
991                        }
992                    }
993                    Ok(mmap_arena)
994                };
995                let mmap_arena = match call_with_extended_max_files(callback)
996                    .context("failed to set max count of file descriptors")
997                {
998                    Ok(Ok(m)) => m,
999                    Ok(Err(e)) => {
1000                        return e;
1001                    }
1002                    Err(e) => {
1003                        error!("{e:?}");
1004                        return VmMemoryResponse::Err(e.into());
1005                    }
1006                };
1007
1008                let size = shm.size();
1009                let guest_addr = match dest.allocate(sys_allocator, size).context(
1010                    "VM memory destination allocation fails when handling mmap and register memory",
1011                ) {
1012                    Ok(addr) => addr,
1013                    Err(e) => return VmMemoryResponse::Err(e.into()),
1014                };
1015
1016                let slot = match vm
1017                    .add_memory_region(
1018                        guest_addr,
1019                        Box::new(mmap_arena),
1020                        true,
1021                        false,
1022                        MemCacheType::CacheCoherent,
1023                    )
1024                    .context("failed to add memory region when handling mmap and register memory")
1025                {
1026                    Ok(slot) => slot,
1027                    Err(e) => return VmMemoryResponse::Err(e.into()),
1028                };
1029
1030                let region_id = VmMemoryRegionId(guest_addr);
1031
1032                region_state
1033                    .registered_memory
1034                    .insert(region_id, RegisteredMemory::DynamicMapping { slot });
1035
1036                VmMemoryResponse::RegisterMemory { region_id, slot }
1037            }
1038            UnregisterMemory(id) => match region_state.registered_memory.remove(&id) {
1039                Some(RegisteredMemory::DynamicMapping { slot }) => match vm
1040                    .remove_memory_region(slot)
1041                    .context(
1042                        "failed to remove memory region when unregistering dynamic mapping memory",
1043                    ) {
1044                    Ok(_) => {
1045                        if let Some(iommu_client) = iommu_client {
1046                            if iommu_client.registered_memory.remove(&id) {
1047                                let request = VirtioIOMMURequest::VfioCommand(
1048                                    VirtioIOMMUVfioCommand::VfioDmabufUnmap(id),
1049                                );
1050
1051                                match virtio_iommu_request(&iommu_client.tube.lock(), &request) {
1052                                    Ok(VirtioIOMMUResponse::VfioResponse(
1053                                        VirtioIOMMUVfioResult::Ok,
1054                                    )) => VmMemoryResponse::Ok,
1055                                    resp => {
1056                                        let error = anyhow::anyhow!(
1057                                            "Unexpected virtio-iommu message response when \
1058                                             unregistering memory: {:?}",
1059                                            resp
1060                                        );
1061                                        VmMemoryResponse::Err(error.into())
1062                                    }
1063                                }
1064                            } else {
1065                                VmMemoryResponse::Ok
1066                            }
1067                        } else {
1068                            VmMemoryResponse::Ok
1069                        }
1070                    }
1071                    Err(e) => VmMemoryResponse::Err(e.into()),
1072                },
1073                Some(RegisteredMemory::FixedMapping { slot, offset, size }) => {
1074                    match vm.remove_mapping(slot, offset, size).context(
1075                        "failed to remove memory mapping when unregistering fixed mapping memory",
1076                    ) {
1077                        Ok(()) => VmMemoryResponse::Ok,
1078                        Err(e) => VmMemoryResponse::Err(e.into()),
1079                    }
1080                }
1081                None => {
1082                    let error =
1083                        anyhow::anyhow!("can't find the memory region when unregistering memory");
1084                    VmMemoryResponse::Err(error.into())
1085                }
1086            },
1087            DynamicallyFreeMemoryRanges { ranges } => {
1088                let mut r = VmMemoryResponse::Ok;
1089                for (guest_address, size) in ranges {
1090                    match vm
1091                        .handle_balloon_event(BalloonEvent::Inflate(MemRegion {
1092                            guest_address,
1093                            size,
1094                        }))
1095                        .context(
1096                            "failed to handle the inflate balloon event when freeing memory ranges \
1097                             dynamically",
1098                        ) {
1099                        Ok(_) => {}
1100                        Err(e) => {
1101                            error!("{:?}", e);
1102                            r = VmMemoryResponse::Err(e.into());
1103                            break;
1104                        }
1105                    }
1106                }
1107                r
1108            }
1109            DynamicallyReclaimMemoryRanges { ranges } => {
1110                let mut r = VmMemoryResponse::Ok;
1111                for (guest_address, size) in ranges {
1112                    match vm
1113                        .handle_balloon_event(BalloonEvent::Deflate(MemRegion {
1114                            guest_address,
1115                            size,
1116                        }))
1117                        .context(
1118                            "failed to handle the deflate balloon event when reclaiming memory \
1119                             ranges dynamically",
1120                        ) {
1121                        Ok(_) => {}
1122                        Err(e) => {
1123                            error!("{:?}", e);
1124                            r = VmMemoryResponse::Err(e.into());
1125                            break;
1126                        }
1127                    }
1128                }
1129                r
1130            }
1131            BalloonTargetReached { size } => {
1132                match vm
1133                    .handle_balloon_event(BalloonEvent::BalloonTargetReached(size))
1134                    .context("failed to handle the target reached balloon event")
1135                {
1136                    Ok(_) => VmMemoryResponse::Ok,
1137                    Err(e) => VmMemoryResponse::Err(e.into()),
1138                }
1139            }
1140            IoEventRaw(request) => {
1141                let res = if request.register {
1142                    vm.register_ioevent(
1143                        request.event,
1144                        IoEventAddress::Mmio(request.addr),
1145                        request.datamatch,
1146                    )
1147                    .context("failed to register IO event")
1148                } else {
1149                    vm.unregister_ioevent(
1150                        request.event,
1151                        IoEventAddress::Mmio(request.addr),
1152                        request.datamatch,
1153                    )
1154                    .context("failed to unregister IO event")
1155                };
1156                match res {
1157                    Ok(_) => VmMemoryResponse::Ok,
1158                    Err(e) => VmMemoryResponse::Err(e.into()),
1159                }
1160            }
1161        }
1162    }
1163}
1164
1165#[derive(Serialize, Deserialize, Debug, PartialOrd, PartialEq, Eq, Ord, Clone, Copy)]
1166/// Identifer for registered memory regions. Globally unique.
1167// The current implementation uses guest physical address as the unique identifier.
1168pub struct VmMemoryRegionId(pub GuestAddress);
1169
1170#[derive(Serialize, Deserialize, Debug)]
1171pub enum VmMemoryResponse {
1172    /// The request to register memory into guest address space was successful.
1173    RegisterMemory {
1174        region_id: VmMemoryRegionId,
1175        slot: u32,
1176    },
1177    Ok,
1178    Err(VmMemoryResponseError),
1179}
1180
1181impl<T> From<Result<T>> for VmMemoryResponse {
1182    fn from(r: Result<T>) -> Self {
1183        match r {
1184            Ok(_) => VmMemoryResponse::Ok,
1185            Err(e) => VmMemoryResponse::Err(anyhow::Error::new(e).into()),
1186        }
1187    }
1188}
1189
1190#[derive(Debug, thiserror::Error)]
1191#[error("Vm memory response error: {0}")]
1192pub struct VmMemoryResponseError(#[from] pub anyhow::Error);
1193
1194impl TryFrom<FlatVmMemoryResponseError> for VmMemoryResponseError {
1195    type Error = anyhow::Error;
1196    fn try_from(value: FlatVmMemoryResponseError) -> StdResult<Self, Self::Error> {
1197        let inner = value
1198            .0
1199            .into_iter()
1200            .fold(
1201                None,
1202                |error: Option<anyhow::Error>, current_context| match error {
1203                    Some(error) => Some(error.context(current_context)),
1204                    None => Some(anyhow::Error::msg(current_context)),
1205                },
1206            )
1207            .context("should carry at least one error")?;
1208        Ok(Self(inner))
1209    }
1210}
1211
1212impl Serialize for VmMemoryResponseError {
1213    fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error>
1214    where
1215        S: serde::Serializer,
1216    {
1217        let flat: FlatVmMemoryResponseError = self.into();
1218        flat.serialize(serializer)
1219    }
1220}
1221
1222impl<'de> Deserialize<'de> for VmMemoryResponseError {
1223    fn deserialize<D>(deserializer: D) -> StdResult<Self, D::Error>
1224    where
1225        D: serde::Deserializer<'de>,
1226    {
1227        let flat = FlatVmMemoryResponseError::deserialize(deserializer)?;
1228        flat.try_into()
1229            .map_err(|e: anyhow::Error| D::Error::custom(e.to_string()))
1230    }
1231}
1232
1233#[derive(Debug, Serialize, Deserialize)]
1234struct FlatVmMemoryResponseError(Vec<String>);
1235
1236impl From<&VmMemoryResponseError> for FlatVmMemoryResponseError {
1237    fn from(value: &VmMemoryResponseError) -> Self {
1238        let contexts = value
1239            .0
1240            .chain()
1241            .map(ToString::to_string)
1242            .rev()
1243            .collect::<Vec<_>>();
1244        Self(contexts)
1245    }
1246}
1247
1248#[derive(Serialize, Deserialize, Debug)]
1249pub enum VmIrqRequest {
1250    /// Allocate one gsi, and associate gsi to irqfd with register_irqfd()
1251    AllocateOneMsi {
1252        irqfd: Event,
1253        device_id: DeviceId,
1254        queue_id: usize,
1255        device_name: String,
1256    },
1257    /// Allocate a specific gsi to irqfd with register_irqfd(). This must only
1258    /// be used when it is known that the gsi is free. Only the snapshot
1259    /// subsystem can make this guarantee, and use of this request by any other
1260    /// caller is strongly discouraged.
1261    AllocateOneMsiAtGsi {
1262        irqfd: Event,
1263        gsi: u32,
1264        device_id: DeviceId,
1265        queue_id: usize,
1266        device_name: String,
1267    },
1268    /// Add one msi route entry into the IRQ chip.
1269    AddMsiRoute {
1270        gsi: u32,
1271        msi_address: u64,
1272        msi_data: u32,
1273        #[cfg(target_arch = "aarch64")]
1274        pci_address: resources::PciAddress,
1275    },
1276    // unregister_irqfs() and release gsi
1277    ReleaseOneIrq {
1278        gsi: u32,
1279        irqfd: Event,
1280    },
1281}
1282
1283/// Data to set up an IRQ event or IRQ route on the IRQ chip.
1284/// VmIrqRequest::execute can't take an `IrqChip` argument, because of a dependency cycle between
1285/// devices and vm_control, so it takes a Fn that processes an `IrqSetup`.
1286pub enum IrqSetup<'a> {
1287    Event(u32, &'a Event, DeviceId, usize, String),
1288    Route(IrqRoute),
1289    UnRegister(u32, &'a Event),
1290}
1291
1292impl VmIrqRequest {
1293    /// Executes this request on the given Vm.
1294    ///
1295    /// # Arguments
1296    /// * `set_up_irq` - A function that applies an `IrqSetup` to an IRQ chip.
1297    ///
1298    /// This does not return a result, instead encapsulating the success or failure in a
1299    /// `VmIrqResponse` with the intended purpose of sending the response back over the socket
1300    /// that received this `VmIrqResponse`.
1301    pub fn execute<F>(&self, set_up_irq: F, sys_allocator: &mut SystemAllocator) -> VmIrqResponse
1302    where
1303        F: FnOnce(IrqSetup) -> Result<()>,
1304    {
1305        use self::VmIrqRequest::*;
1306        match *self {
1307            AllocateOneMsi {
1308                ref irqfd,
1309                device_id,
1310                queue_id,
1311                ref device_name,
1312            } => {
1313                if let Some(irq_num) = sys_allocator.allocate_irq() {
1314                    match set_up_irq(IrqSetup::Event(
1315                        irq_num,
1316                        irqfd,
1317                        device_id,
1318                        queue_id,
1319                        device_name.clone(),
1320                    )) {
1321                        Ok(_) => VmIrqResponse::AllocateOneMsi { gsi: irq_num },
1322                        Err(e) => VmIrqResponse::Err(e),
1323                    }
1324                } else {
1325                    VmIrqResponse::Err(SysError::new(EINVAL))
1326                }
1327            }
1328            AllocateOneMsiAtGsi {
1329                ref irqfd,
1330                gsi,
1331                device_id,
1332                queue_id,
1333                ref device_name,
1334            } => {
1335                match set_up_irq(IrqSetup::Event(
1336                    gsi,
1337                    irqfd,
1338                    device_id,
1339                    queue_id,
1340                    device_name.clone(),
1341                )) {
1342                    Ok(_) => VmIrqResponse::Ok,
1343                    Err(e) => VmIrqResponse::Err(e),
1344                }
1345            }
1346            AddMsiRoute {
1347                gsi,
1348                msi_address,
1349                msi_data,
1350                #[cfg(target_arch = "aarch64")]
1351                pci_address,
1352            } => {
1353                let route = IrqRoute {
1354                    gsi,
1355                    source: IrqSource::Msi {
1356                        address: msi_address,
1357                        data: msi_data,
1358                        #[cfg(target_arch = "aarch64")]
1359                        pci_address,
1360                    },
1361                };
1362                match set_up_irq(IrqSetup::Route(route)) {
1363                    Ok(_) => VmIrqResponse::Ok,
1364                    Err(e) => VmIrqResponse::Err(e),
1365                }
1366            }
1367            ReleaseOneIrq { gsi, ref irqfd } => {
1368                let _ = set_up_irq(IrqSetup::UnRegister(gsi, irqfd));
1369                sys_allocator.release_irq(gsi);
1370                VmIrqResponse::Ok
1371            }
1372        }
1373    }
1374}
1375
1376#[derive(Serialize, Deserialize, Debug)]
1377pub enum VmIrqResponse {
1378    AllocateOneMsi { gsi: u32 },
1379    Ok,
1380    Err(SysError),
1381}
1382
1383#[derive(Serialize, Deserialize, Debug, Clone)]
1384pub enum DevicesState {
1385    Sleep,
1386    Wake,
1387}
1388
1389#[derive(Serialize, Deserialize, Debug, Clone)]
1390pub enum BatControlResult {
1391    Ok,
1392    NoBatDevice,
1393    NoSuchHealth,
1394    NoSuchProperty,
1395    NoSuchStatus,
1396    NoSuchBatType,
1397    StringParseIntErr,
1398    StringParseBoolErr,
1399}
1400
1401impl Display for BatControlResult {
1402    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1403        use self::BatControlResult::*;
1404
1405        match self {
1406            Ok => write!(f, "Setting battery property successfully"),
1407            NoBatDevice => write!(f, "No battery device created"),
1408            NoSuchHealth => write!(f, "Invalid Battery health setting. Only support: unknown/good/overheat/dead/overvoltage/unexpectedfailure/cold/watchdogtimerexpire/safetytimerexpire/overcurrent"),
1409            NoSuchProperty => write!(f, "Battery doesn't have such property. Only support: status/health/present/capacity/aconline"),
1410            NoSuchStatus => write!(f, "Invalid Battery status setting. Only support: unknown/charging/discharging/notcharging/full"),
1411            NoSuchBatType => write!(f, "Invalid Battery type setting. Only support: goldfish"),
1412            StringParseIntErr => write!(f, "Battery property target ParseInt error"),
1413            StringParseBoolErr => write!(f, "Battery property target ParseBool error"),
1414        }
1415    }
1416}
1417
1418#[derive(Serialize, Deserialize, Copy, Clone, Debug, Default, PartialEq, Eq)]
1419#[serde(rename_all = "kebab-case")]
1420pub enum BatteryType {
1421    #[default]
1422    Goldfish,
1423}
1424
1425impl FromStr for BatteryType {
1426    type Err = BatControlResult;
1427
1428    fn from_str(s: &str) -> StdResult<Self, Self::Err> {
1429        match s {
1430            "goldfish" => Ok(BatteryType::Goldfish),
1431            _ => Err(BatControlResult::NoSuchBatType),
1432        }
1433    }
1434}
1435
1436#[derive(Serialize, Deserialize, Debug)]
1437pub enum BatProperty {
1438    Status,
1439    Health,
1440    Present,
1441    Capacity,
1442    ACOnline,
1443    SetFakeBatConfig,
1444    CancelFakeBatConfig,
1445}
1446
1447impl FromStr for BatProperty {
1448    type Err = BatControlResult;
1449
1450    fn from_str(s: &str) -> StdResult<Self, Self::Err> {
1451        match s {
1452            "status" => Ok(BatProperty::Status),
1453            "health" => Ok(BatProperty::Health),
1454            "present" => Ok(BatProperty::Present),
1455            "capacity" => Ok(BatProperty::Capacity),
1456            "aconline" => Ok(BatProperty::ACOnline),
1457            "set_fake_bat_config" => Ok(BatProperty::SetFakeBatConfig),
1458            "cancel_fake_bat_config" => Ok(BatProperty::CancelFakeBatConfig),
1459            _ => Err(BatControlResult::NoSuchProperty),
1460        }
1461    }
1462}
1463
1464impl Display for BatProperty {
1465    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1466        match *self {
1467            BatProperty::Status => write!(f, "status"),
1468            BatProperty::Health => write!(f, "health"),
1469            BatProperty::Present => write!(f, "present"),
1470            BatProperty::Capacity => write!(f, "capacity"),
1471            BatProperty::ACOnline => write!(f, "aconline"),
1472            BatProperty::SetFakeBatConfig => write!(f, "set_fake_bat_config"),
1473            BatProperty::CancelFakeBatConfig => write!(f, "cancel_fake_bat_config"),
1474        }
1475    }
1476}
1477
1478#[derive(Serialize, Deserialize, Debug)]
1479pub enum BatStatus {
1480    Unknown,
1481    Charging,
1482    DisCharging,
1483    NotCharging,
1484    Full,
1485}
1486
1487impl BatStatus {
1488    pub fn new(status: String) -> std::result::Result<Self, BatControlResult> {
1489        match status.as_str() {
1490            "unknown" => Ok(BatStatus::Unknown),
1491            "charging" => Ok(BatStatus::Charging),
1492            "discharging" => Ok(BatStatus::DisCharging),
1493            "notcharging" => Ok(BatStatus::NotCharging),
1494            "full" => Ok(BatStatus::Full),
1495            _ => Err(BatControlResult::NoSuchStatus),
1496        }
1497    }
1498}
1499
1500impl FromStr for BatStatus {
1501    type Err = BatControlResult;
1502
1503    fn from_str(s: &str) -> StdResult<Self, Self::Err> {
1504        match s {
1505            "unknown" => Ok(BatStatus::Unknown),
1506            "charging" => Ok(BatStatus::Charging),
1507            "discharging" => Ok(BatStatus::DisCharging),
1508            "notcharging" => Ok(BatStatus::NotCharging),
1509            "full" => Ok(BatStatus::Full),
1510            _ => Err(BatControlResult::NoSuchStatus),
1511        }
1512    }
1513}
1514
1515impl From<BatStatus> for u32 {
1516    fn from(status: BatStatus) -> Self {
1517        status as u32
1518    }
1519}
1520
1521#[derive(Serialize, Deserialize, Debug)]
1522pub enum BatHealth {
1523    Unknown,
1524    Good,
1525    Overheat,
1526    Dead,
1527    OverVoltage,
1528    UnexpectedFailure,
1529    Cold,
1530    WatchdogTimerExpire,
1531    SafetyTimerExpire,
1532    OverCurrent,
1533}
1534
1535impl FromStr for BatHealth {
1536    type Err = BatControlResult;
1537
1538    fn from_str(s: &str) -> StdResult<Self, Self::Err> {
1539        match s {
1540            "unknown" => Ok(BatHealth::Unknown),
1541            "good" => Ok(BatHealth::Good),
1542            "overheat" => Ok(BatHealth::Overheat),
1543            "dead" => Ok(BatHealth::Dead),
1544            "overvoltage" => Ok(BatHealth::OverVoltage),
1545            "unexpectedfailure" => Ok(BatHealth::UnexpectedFailure),
1546            "cold" => Ok(BatHealth::Cold),
1547            "watchdogtimerexpire" => Ok(BatHealth::WatchdogTimerExpire),
1548            "safetytimerexpire" => Ok(BatHealth::SafetyTimerExpire),
1549            "overcurrent" => Ok(BatHealth::OverCurrent),
1550            _ => Err(BatControlResult::NoSuchHealth),
1551        }
1552    }
1553}
1554
1555impl From<BatHealth> for u32 {
1556    fn from(status: BatHealth) -> Self {
1557        status as u32
1558    }
1559}
1560
1561#[derive(Serialize, Deserialize, Debug)]
1562pub enum BatControlCommand {
1563    SetStatus(BatStatus),
1564    SetHealth(BatHealth),
1565    SetPresent(u32),
1566    SetCapacity(u32),
1567    SetACOnline(u32),
1568    SetFakeBatConfig(u32),
1569    CancelFakeConfig,
1570}
1571
1572impl BatControlCommand {
1573    pub fn new(property: String, target: String) -> std::result::Result<Self, BatControlResult> {
1574        let cmd = property.parse::<BatProperty>()?;
1575        match cmd {
1576            BatProperty::Status => Ok(BatControlCommand::SetStatus(target.parse::<BatStatus>()?)),
1577            BatProperty::Health => Ok(BatControlCommand::SetHealth(target.parse::<BatHealth>()?)),
1578            BatProperty::Present => Ok(BatControlCommand::SetPresent(
1579                target
1580                    .parse::<u32>()
1581                    .map_err(|_| BatControlResult::StringParseIntErr)?,
1582            )),
1583            BatProperty::Capacity => Ok(BatControlCommand::SetCapacity(
1584                target
1585                    .parse::<u32>()
1586                    .map_err(|_| BatControlResult::StringParseIntErr)?,
1587            )),
1588            BatProperty::ACOnline => Ok(BatControlCommand::SetACOnline(
1589                target
1590                    .parse::<u32>()
1591                    .map_err(|_| BatControlResult::StringParseIntErr)?,
1592            )),
1593            BatProperty::SetFakeBatConfig => Ok(BatControlCommand::SetFakeBatConfig(
1594                target
1595                    .parse::<u32>()
1596                    .map_err(|_| BatControlResult::StringParseIntErr)?,
1597            )),
1598            BatProperty::CancelFakeBatConfig => Ok(BatControlCommand::CancelFakeConfig),
1599        }
1600    }
1601}
1602
1603/// Used for VM to control battery properties.
1604pub struct BatControl {
1605    pub type_: BatteryType,
1606    pub control_tube: Tube,
1607}
1608
1609/// Used for VM to control for virtio-snd
1610#[derive(Serialize, Deserialize, Debug)]
1611pub enum SndControlCommand {
1612    MuteAll(bool),
1613}
1614
1615// Used to mark hotplug pci device's device type
1616#[derive(Serialize, Deserialize, Debug, Clone)]
1617pub enum HotPlugDeviceType {
1618    UpstreamPort,
1619    DownstreamPort,
1620    EndPoint,
1621}
1622
1623// Used for VM to hotplug pci devices
1624#[derive(Serialize, Deserialize, Debug, Clone)]
1625pub struct HotPlugDeviceInfo {
1626    pub device_type: HotPlugDeviceType,
1627    pub path: PathBuf,
1628    pub hp_interrupt: bool,
1629}
1630
1631/// A request from a device to the main process to perform some operation on the VM.
1632#[derive(Serialize, Deserialize, Debug)]
1633pub enum DeviceControlRequest {
1634    /// Inject a general-purpose event. If `clear_evt` is provided, when the irq associated
1635    /// with the GPE is resampled, it will be re-asserted as long as `clear_evt` is not
1636    /// signaled.
1637    Gpe { gpe: u32, clear_evt: Option<Event> },
1638    /// Inject a PCI PME.
1639    PciPme(u16),
1640    /// Command to add/remove multiple vfio-pci devices.
1641    HotPlugVfioCommand {
1642        device: HotPlugDeviceInfo,
1643        add: bool,
1644    },
1645}
1646
1647/// Response to a `DeviceControlRequest`.
1648#[derive(Serialize, Deserialize, Debug)]
1649#[must_use]
1650pub enum DeviceControlResponse {
1651    Ok,
1652    Err(SysError),
1653}
1654
1655impl Display for DeviceControlResponse {
1656    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1657        match self {
1658            DeviceControlResponse::Ok => write!(f, "ok"),
1659            DeviceControlResponse::Err(e) => write!(f, "error: {e}"),
1660        }
1661    }
1662}
1663
1664impl From<DeviceControlResponse> for VmResponse {
1665    fn from(response: DeviceControlResponse) -> Self {
1666        match response {
1667            DeviceControlResponse::Ok => VmResponse::Ok,
1668            DeviceControlResponse::Err(e) => VmResponse::Err(e),
1669        }
1670    }
1671}
1672
1673impl DeviceControlRequest {
1674    /// Executes this request on the given VM power management resource.
1675    pub fn execute(
1676        &self,
1677        pm: &mut Option<Arc<Mutex<dyn PmResource + Send>>>,
1678    ) -> DeviceControlResponse {
1679        match self {
1680            DeviceControlRequest::Gpe { gpe, clear_evt } => {
1681                if let Some(pm) = pm.as_ref() {
1682                    match clear_evt.as_ref().map(|e| e.try_clone()).transpose() {
1683                        Ok(clear_evt) => {
1684                            pm.lock().gpe_evt(*gpe, clear_evt);
1685                            DeviceControlResponse::Ok
1686                        }
1687                        Err(err) => {
1688                            error!("Error cloning clear_evt: {:?}", err);
1689                            DeviceControlResponse::Err(SysError::new(EIO))
1690                        }
1691                    }
1692                } else {
1693                    error!("{:#?} not supported", *self);
1694                    DeviceControlResponse::Err(SysError::new(ENOTSUP))
1695                }
1696            }
1697            DeviceControlRequest::PciPme(requester_id) => {
1698                if let Some(pm) = pm.as_ref() {
1699                    pm.lock().pme_evt(*requester_id);
1700                    DeviceControlResponse::Ok
1701                } else {
1702                    error!("{:#?} not supported", *self);
1703                    DeviceControlResponse::Err(SysError::new(ENOTSUP))
1704                }
1705            }
1706            DeviceControlRequest::HotPlugVfioCommand { .. } => {
1707                panic!("HotPlugVfioCommand should be handled by the platform run loop");
1708            }
1709        }
1710    }
1711}
1712
1713/// Message for communicating a suspend or resume to the virtio-pvclock device.
1714#[derive(Serialize, Deserialize, Debug, Clone)]
1715pub enum PvClockCommand {
1716    Suspend,
1717    Resume,
1718}
1719
1720/// Message used by virtio-pvclock to communicate command results.
1721#[derive(Serialize, Deserialize, Debug)]
1722pub enum PvClockCommandResponse {
1723    Ok,
1724    Resumed { total_suspended_ticks: u64 },
1725    DeviceInactive,
1726    Err(SysError),
1727}
1728
1729/// Commands for vmm-swap feature
1730#[derive(Serialize, Deserialize, Debug)]
1731pub enum SwapCommand {
1732    Enable,
1733    Trim,
1734    SwapOut,
1735    Disable { slow_file_cleanup: bool },
1736    Status,
1737}
1738
1739///
1740/// A request to the main process to perform some operation on the VM.
1741///
1742/// Unless otherwise noted, each request should expect a `VmResponse::Ok` to be received on success.
1743#[derive(Serialize, Deserialize, Debug)]
1744pub enum VmRequest {
1745    /// Break the VM's run loop and exit.
1746    Exit,
1747    /// Trigger a power button event in the guest.
1748    Powerbtn,
1749    /// Trigger a sleep button event in the guest.
1750    Sleepbtn,
1751    /// Trigger a RTC interrupt in the guest. When the irq associated with the RTC is
1752    /// resampled, it will be re-asserted as long as `clear_evt` is not signaled.
1753    Rtc { clear_evt: Event },
1754    /// Suspend the VM's VCPUs until resume.
1755    SuspendVcpus,
1756    /// Swap the memory content into files on a disk
1757    Swap(SwapCommand),
1758    /// Resume the VM's VCPUs that were previously suspended.
1759    ResumeVcpus,
1760    /// Command to control devices.
1761    DeviceControl(DeviceControlRequest),
1762    /// Make the VM's RT VCPU real-time.
1763    MakeRT,
1764    /// Command for balloon driver.
1765    #[cfg(feature = "balloon")]
1766    BalloonCommand(BalloonControlCommand),
1767    /// Send a command to a disk chosen by `disk_index`.
1768    /// `disk_index` is a 0-based count of `--disk`, `--rwdisk`, and `-r` command-line options.
1769    DiskCommand {
1770        disk_index: usize,
1771        command: DiskControlCommand,
1772    },
1773    /// Command to use controller.
1774    UsbCommand(UsbControlCommand),
1775    /// Command to modify the gpu.
1776    GpuCommand(GpuControlCommand),
1777    /// Command to set battery.
1778    BatCommand(BatteryType, BatControlCommand),
1779    /// Command to control snd devices
1780    #[cfg(feature = "audio")]
1781    SndCommand(SndControlCommand),
1782    /// Command to add/remove network tap device as virtio-pci device
1783    #[cfg(feature = "pci-hotplug")]
1784    HotPlugNetCommand(NetControlCommand),
1785    /// Command to Snapshot devices
1786    Snapshot(SnapshotCommand),
1787    /// Register for event notification
1788    RegisterListener {
1789        socket_addr: String,
1790        event: RegisteredEvent,
1791    },
1792    /// Unregister for notifications for event
1793    UnregisterListener {
1794        socket_addr: String,
1795        event: RegisteredEvent,
1796    },
1797    /// Unregister for all event notification
1798    Unregister { socket_addr: String },
1799    /// Suspend VM VCPUs and Devices until resume.
1800    SuspendVm,
1801    /// Resume VM VCPUs and Devices.
1802    ResumeVm,
1803    /// Returns Vcpus PID/TID
1804    VcpuPidTid,
1805    /// Throttles the requested vCPU for microseconds
1806    Throttle(usize, u32),
1807    /// Returns unique descriptor of this VM.
1808    GetVmDescriptor,
1809    /// Registers memory in guest.
1810    RegisterMemory {
1811        fd: SafeDescriptor,
1812        offset: u64,
1813        range_start: u64,
1814        range_end: u64,
1815        cache_coherent: bool,
1816    },
1817    /// Unregisters memory in guest.
1818    UnregisterMemory { region_id: u64 },
1819}
1820
1821/// NOTE: when making any changes to this enum please also update
1822/// RegisteredEventFfi in crosvm_control/src/lib.rs
1823#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone, Copy)]
1824pub enum RegisteredEvent {
1825    VirtioBalloonWsReport,
1826    VirtioBalloonResize,
1827    VirtioBalloonOOMDeflation,
1828}
1829
1830#[derive(Serialize, Deserialize, Debug)]
1831pub enum RegisteredEventWithData {
1832    VirtioBalloonWsReport {
1833        ws_buckets: Vec<balloon_control::WSBucket>,
1834        balloon_actual: u64,
1835    },
1836    VirtioBalloonResize,
1837    VirtioBalloonOOMDeflation,
1838}
1839
1840impl RegisteredEventWithData {
1841    pub fn into_event(&self) -> RegisteredEvent {
1842        match self {
1843            Self::VirtioBalloonWsReport { .. } => RegisteredEvent::VirtioBalloonWsReport,
1844            Self::VirtioBalloonResize => RegisteredEvent::VirtioBalloonResize,
1845            Self::VirtioBalloonOOMDeflation => RegisteredEvent::VirtioBalloonOOMDeflation,
1846        }
1847    }
1848
1849    #[cfg(feature = "registered_events")]
1850    pub fn into_proto(&self) -> registered_events::RegisteredEvent {
1851        match self {
1852            Self::VirtioBalloonWsReport {
1853                ws_buckets,
1854                balloon_actual,
1855            } => {
1856                let mut report = registered_events::VirtioBalloonWsReport {
1857                    balloon_actual: *balloon_actual,
1858                    ..registered_events::VirtioBalloonWsReport::new()
1859                };
1860                for ws in ws_buckets {
1861                    report.ws_buckets.push(registered_events::VirtioWsBucket {
1862                        age: ws.age,
1863                        file_bytes: ws.bytes[0],
1864                        anon_bytes: ws.bytes[1],
1865                        ..registered_events::VirtioWsBucket::new()
1866                    });
1867                }
1868                let mut event = registered_events::RegisteredEvent::new();
1869                event.set_ws_report(report);
1870                event
1871            }
1872            Self::VirtioBalloonResize => {
1873                let mut event = registered_events::RegisteredEvent::new();
1874                event.set_resize(registered_events::VirtioBalloonResize::new());
1875                event
1876            }
1877            Self::VirtioBalloonOOMDeflation => {
1878                let mut event = registered_events::RegisteredEvent::new();
1879                event.set_oom_deflation(registered_events::VirtioBalloonOOMDeflation::new());
1880                event
1881            }
1882        }
1883    }
1884
1885    pub fn from_ws(ws: &balloon_control::BalloonWS, balloon_actual: u64) -> Self {
1886        RegisteredEventWithData::VirtioBalloonWsReport {
1887            ws_buckets: ws.ws.clone(),
1888            balloon_actual,
1889        }
1890    }
1891}
1892
1893pub fn handle_disk_command(command: &DiskControlCommand, disk_host_tube: &Tube) -> VmResponse {
1894    // Forward the request to the block device process via its control socket.
1895    if let Err(e) = disk_host_tube.send(command) {
1896        error!("disk socket send failed: {}", e);
1897        return VmResponse::Err(SysError::new(EINVAL));
1898    }
1899
1900    // Wait for the disk control command to be processed
1901    match disk_host_tube.recv() {
1902        Ok(DiskControlResult::Ok) => VmResponse::Ok,
1903        Ok(DiskControlResult::Err(e)) => VmResponse::Err(e),
1904        Err(e) => {
1905            error!("disk socket recv failed: {}", e);
1906            VmResponse::Err(SysError::new(EINVAL))
1907        }
1908    }
1909}
1910
1911/// WARNING: descriptor must be a mapping handle on Windows.
1912fn map_descriptor(
1913    descriptor: &dyn AsRawDescriptor,
1914    offset: u64,
1915    size: u64,
1916    prot: Protection,
1917) -> Result<Box<dyn MappedRegion>> {
1918    let size: usize = size.try_into().map_err(|_e| SysError::new(ERANGE))?;
1919    match MemoryMappingBuilder::new(size)
1920        .from_descriptor(descriptor)
1921        .offset(offset)
1922        .protection(prot)
1923        .build()
1924    {
1925        Ok(mmap) => Ok(Box::new(mmap)),
1926        Err(MmapError::SystemCallFailed(e)) => Err(e),
1927        _ => Err(SysError::new(EINVAL)),
1928    }
1929}
1930
1931// Get vCPU state. vCPUs are expected to all hold the same state.
1932// In this function, there may be a time where vCPUs are not holding the same state
1933// as they transition from one state to the other. This is expected, and the final result
1934// should be all vCPUs holding the same state.
1935fn get_vcpu_state(kick_vcpus: impl Fn(VcpuControl), vcpu_num: usize) -> anyhow::Result<VmRunMode> {
1936    let (send_chan, recv_chan) = mpsc::channel();
1937    kick_vcpus(VcpuControl::GetStates(send_chan));
1938    if vcpu_num == 0 {
1939        bail!("vcpu_num is zero");
1940    }
1941    let mut current_mode_vec: Vec<VmRunMode> = Vec::new();
1942    for _ in 0..vcpu_num {
1943        match recv_chan.recv() {
1944            Ok(state) => current_mode_vec.push(state),
1945            Err(e) => {
1946                bail!("Failed to get vCPU state: {}", e);
1947            }
1948        };
1949    }
1950    let first_state = current_mode_vec[0];
1951    if first_state == VmRunMode::Exiting {
1952        panic!("Attempt to snapshot while exiting.");
1953    }
1954    if current_mode_vec.iter().any(|x| *x != first_state) {
1955        // We do not panic here. It could be that vCPUs are transitioning from one mode to another.
1956        bail!("Unknown VM state: vCPUs hold different states.");
1957    }
1958    Ok(first_state)
1959}
1960
1961/// A guard to guarantee that all the vCPUs are suspended during the scope.
1962///
1963/// When this guard is dropped, it rolls back the state of CPUs.
1964pub struct VcpuSuspendGuard<'a> {
1965    saved_run_mode: VmRunMode,
1966    kick_vcpus: &'a dyn Fn(VcpuControl),
1967}
1968
1969impl<'a> VcpuSuspendGuard<'a> {
1970    /// Check the all vCPU state and suspend the vCPUs if they are running.
1971    ///
1972    /// This returns [VcpuSuspendGuard] to rollback the vcpu state.
1973    ///
1974    /// # Arguments
1975    ///
1976    /// * `kick_vcpus` - A funtion to send [VcpuControl] message to all the vCPUs and interrupt
1977    ///   them.
1978    /// * `vcpu_num` - The number of vCPUs.
1979    pub fn new(kick_vcpus: &'a impl Fn(VcpuControl), vcpu_num: usize) -> anyhow::Result<Self> {
1980        // get initial vcpu state
1981        let saved_run_mode = get_vcpu_state(kick_vcpus, vcpu_num)?;
1982        match saved_run_mode {
1983            VmRunMode::Running => {
1984                kick_vcpus(VcpuControl::RunState(VmRunMode::Suspending));
1985                // Blocking call, waiting for response to ensure vCPU state was updated.
1986                // In case of failure, where a vCPU still has the state running, start up vcpus and
1987                // abort operation.
1988                let current_mode = get_vcpu_state(kick_vcpus, vcpu_num)?;
1989                if current_mode != VmRunMode::Suspending {
1990                    kick_vcpus(VcpuControl::RunState(saved_run_mode));
1991                    bail!("vCPUs failed to all suspend. Kicking back all vCPUs to their previous state: {saved_run_mode}");
1992                }
1993            }
1994            VmRunMode::Suspending => {
1995                // do nothing. keep the state suspending.
1996            }
1997            other => {
1998                bail!("vcpus are not in running/suspending state, but {}", other);
1999            }
2000        };
2001        Ok(Self {
2002            saved_run_mode,
2003            kick_vcpus,
2004        })
2005    }
2006}
2007
2008impl Drop for VcpuSuspendGuard<'_> {
2009    fn drop(&mut self) {
2010        if self.saved_run_mode != VmRunMode::Suspending {
2011            (self.kick_vcpus)(VcpuControl::RunState(self.saved_run_mode));
2012        }
2013    }
2014}
2015
2016/// A guard to guarantee that all devices are sleeping during its scope.
2017///
2018/// When this guard is dropped, it wakes the devices.
2019pub struct DeviceSleepGuard<'a> {
2020    device_control_tube: &'a Tube,
2021    devices_state: DevicesState,
2022}
2023
2024impl<'a> DeviceSleepGuard<'a> {
2025    fn new(device_control_tube: &'a Tube) -> anyhow::Result<Self> {
2026        device_control_tube
2027            .send(&DeviceControlCommand::GetDevicesState)
2028            .context("send command to devices control socket")?;
2029        let devices_state = match device_control_tube
2030            .recv()
2031            .context("receive from devices control socket")?
2032        {
2033            VmResponse::DevicesState(state) => state,
2034            resp => bail!("failed to get devices state. Unexpected behavior: {}", resp),
2035        };
2036        if let DevicesState::Wake = devices_state {
2037            device_control_tube
2038                .send(&DeviceControlCommand::SleepDevices)
2039                .context("send command to devices control socket")?;
2040            match device_control_tube
2041                .recv()
2042                .context("receive from devices control socket")?
2043            {
2044                VmResponse::Ok => (),
2045                resp => bail!("device sleep failed: {}", resp),
2046            }
2047        }
2048        Ok(Self {
2049            device_control_tube,
2050            devices_state,
2051        })
2052    }
2053}
2054
2055impl Drop for DeviceSleepGuard<'_> {
2056    fn drop(&mut self) {
2057        if let DevicesState::Wake = self.devices_state {
2058            if let Err(e) = self
2059                .device_control_tube
2060                .send(&DeviceControlCommand::WakeDevices)
2061            {
2062                panic!("failed to request device wake after snapshot: {e}");
2063            }
2064            match self.device_control_tube.recv() {
2065                Ok(VmResponse::Ok) => (),
2066                Ok(resp) => panic!("unexpected response to device wake request: {resp}"),
2067                Err(e) => panic!("failed to get reply for device wake request: {e}"),
2068            }
2069        }
2070    }
2071}
2072
2073impl VmRequest {
2074    /// Executes this request on the given Vm and other mutable state.
2075    ///
2076    /// This does not return a result, instead encapsulating the success or failure in a
2077    /// `VmResponse` with the intended purpose of sending the response back over the  socket that
2078    /// received this `VmRequest`.
2079    ///
2080    /// `suspended_pvclock_state`: If the hypervisor has its own pvclock (not the same as
2081    /// virtio-pvclock) and the VM is suspended (not just the vCPUs, but the full VM), then
2082    /// `suspended_pvclock_state` will be used to store the ClockState saved just after the vCPUs
2083    /// were suspended. It is important that we save the value right after the vCPUs are suspended
2084    /// and restore it right before the vCPUs are resumed (instead of, more naturally, during the
2085    /// snapshot/restore steps) because the pvclock continues to tick even when the vCPUs are
2086    /// suspended.
2087    #[allow(unused_variables)]
2088    pub fn execute(
2089        &self,
2090        vm: &dyn Vm,
2091        disk_host_tubes: &[Tube],
2092        snd_host_tubes: &[Tube],
2093        pm: &mut Option<Arc<Mutex<dyn PmResource + Send>>>,
2094        gpu_control_tube: Option<&Tube>,
2095        usb_control_tube: Option<&Tube>,
2096        bat_control: &mut Option<BatControl>,
2097        kick_vcpus: impl Fn(VcpuControl),
2098        #[cfg(any(target_os = "android", target_os = "linux"))] kick_vcpu: impl Fn(usize, VcpuControl),
2099        force_s2idle: bool,
2100        #[cfg(feature = "swap")] swap_controller: Option<&swap::SwapController>,
2101        device_control_tube: &Tube,
2102        vcpu_size: usize,
2103        irq_handler_control: &Tube,
2104        snapshot_irqchip: impl Fn() -> anyhow::Result<AnySnapshot>,
2105        suspended_pvclock_state: &mut Option<hypervisor::ClockState>,
2106    ) -> VmResponse {
2107        match self {
2108            VmRequest::Exit => {
2109                panic!("VmRequest::Exit should be handled by the platform run loop");
2110            }
2111            VmRequest::Powerbtn => {
2112                if let Some(pm) = pm {
2113                    pm.lock().pwrbtn_evt();
2114                    VmResponse::Ok
2115                } else {
2116                    error!("{:#?} not supported", *self);
2117                    VmResponse::Err(SysError::new(ENOTSUP))
2118                }
2119            }
2120            VmRequest::Sleepbtn => {
2121                if let Some(pm) = pm {
2122                    pm.lock().slpbtn_evt();
2123                    VmResponse::Ok
2124                } else {
2125                    error!("{:#?} not supported", *self);
2126                    VmResponse::Err(SysError::new(ENOTSUP))
2127                }
2128            }
2129            VmRequest::Rtc { clear_evt } => {
2130                if let Some(pm) = pm.as_ref() {
2131                    match clear_evt.try_clone() {
2132                        Ok(clear_evt) => {
2133                            // RTC event will asynchronously trigger wakeup.
2134                            pm.lock().rtc_evt(clear_evt);
2135                            VmResponse::Ok
2136                        }
2137                        Err(err) => {
2138                            error!("Error cloning clear_evt: {:?}", err);
2139                            VmResponse::Err(SysError::new(EIO))
2140                        }
2141                    }
2142                } else {
2143                    error!("{:#?} not supported", *self);
2144                    VmResponse::Err(SysError::new(ENOTSUP))
2145                }
2146            }
2147            VmRequest::SuspendVcpus => {
2148                if !force_s2idle {
2149                    kick_vcpus(VcpuControl::RunState(VmRunMode::Suspending));
2150                    let current_mode = match get_vcpu_state(kick_vcpus, vcpu_size) {
2151                        Ok(state) => state,
2152                        Err(e) => {
2153                            error!("failed to get vcpu state: {e}");
2154                            return VmResponse::Err(SysError::new(EIO));
2155                        }
2156                    };
2157                    if current_mode != VmRunMode::Suspending {
2158                        error!("vCPUs failed to all suspend.");
2159                        return VmResponse::Err(SysError::new(EIO));
2160                    }
2161                }
2162                VmResponse::Ok
2163            }
2164            VmRequest::ResumeVcpus => {
2165                if let Err(e) = device_control_tube.send(&DeviceControlCommand::GetDevicesState) {
2166                    error!("failed to send GetDevicesState: {}", e);
2167                    return VmResponse::Err(SysError::new(EIO));
2168                }
2169                let devices_state = match device_control_tube.recv() {
2170                    Ok(VmResponse::DevicesState(state)) => state,
2171                    Ok(resp) => {
2172                        error!("failed to get devices state. Unexpected behavior: {}", resp);
2173                        return VmResponse::Err(SysError::new(EINVAL));
2174                    }
2175                    Err(e) => {
2176                        error!("failed to get devices state. Unexpected behavior: {}", e);
2177                        return VmResponse::Err(SysError::new(EINVAL));
2178                    }
2179                };
2180                if let DevicesState::Sleep = devices_state {
2181                    error!("Trying to wake Vcpus while Devices are asleep. Did you mean to use `crosvm resume --full`?");
2182                    return VmResponse::Err(SysError::new(EINVAL));
2183                }
2184
2185                if force_s2idle {
2186                    // During resume also emulate powerbtn event which will allow to wakeup fully
2187                    // suspended guest.
2188                    if let Some(pm) = pm {
2189                        pm.lock().pwrbtn_evt();
2190                    } else {
2191                        error!("triggering power btn during resume not supported");
2192                        return VmResponse::Err(SysError::new(ENOTSUP));
2193                    }
2194                }
2195
2196                kick_vcpus(VcpuControl::RunState(VmRunMode::Running));
2197                VmResponse::Ok
2198            }
2199            VmRequest::Swap(SwapCommand::Enable) => {
2200                #[cfg(feature = "swap")]
2201                if let Some(swap_controller) = swap_controller {
2202                    // Suspend all vcpus and devices while vmm-swap is enabling (move the guest
2203                    // memory contents to the staging memory) to guarantee no processes other than
2204                    // the swap monitor process access the guest memory.
2205                    let _vcpu_guard = match VcpuSuspendGuard::new(&kick_vcpus, vcpu_size) {
2206                        Ok(guard) => guard,
2207                        Err(e) => {
2208                            error!("failed to suspend vcpus: {:?}", e);
2209                            return VmResponse::Err(SysError::new(EINVAL));
2210                        }
2211                    };
2212                    // TODO(b/253386409): Use `devices::Suspendable::sleep()` instead of sending
2213                    // `SIGSTOP` signal.
2214                    let _devices_guard = match swap_controller.suspend_devices() {
2215                        Ok(guard) => guard,
2216                        Err(e) => {
2217                            error!("failed to suspend devices: {:?}", e);
2218                            return VmResponse::Err(SysError::new(EINVAL));
2219                        }
2220                    };
2221
2222                    return match swap_controller.enable() {
2223                        Ok(()) => VmResponse::Ok,
2224                        Err(e) => {
2225                            error!("swap enable failed: {}", e);
2226                            VmResponse::Err(SysError::new(EINVAL))
2227                        }
2228                    };
2229                }
2230                VmResponse::Err(SysError::new(ENOTSUP))
2231            }
2232            VmRequest::Swap(SwapCommand::Trim) => {
2233                #[cfg(feature = "swap")]
2234                if let Some(swap_controller) = swap_controller {
2235                    return match swap_controller.trim() {
2236                        Ok(()) => VmResponse::Ok,
2237                        Err(e) => {
2238                            error!("swap trim failed: {}", e);
2239                            VmResponse::Err(SysError::new(EINVAL))
2240                        }
2241                    };
2242                }
2243                VmResponse::Err(SysError::new(ENOTSUP))
2244            }
2245            VmRequest::Swap(SwapCommand::SwapOut) => {
2246                #[cfg(feature = "swap")]
2247                if let Some(swap_controller) = swap_controller {
2248                    return match swap_controller.swap_out() {
2249                        Ok(()) => VmResponse::Ok,
2250                        Err(e) => {
2251                            error!("swap out failed: {}", e);
2252                            VmResponse::Err(SysError::new(EINVAL))
2253                        }
2254                    };
2255                }
2256                VmResponse::Err(SysError::new(ENOTSUP))
2257            }
2258            VmRequest::Swap(SwapCommand::Disable {
2259                #[cfg(feature = "swap")]
2260                slow_file_cleanup,
2261                ..
2262            }) => {
2263                #[cfg(feature = "swap")]
2264                if let Some(swap_controller) = swap_controller {
2265                    return match swap_controller.disable(*slow_file_cleanup) {
2266                        Ok(()) => VmResponse::Ok,
2267                        Err(e) => {
2268                            error!("swap disable failed: {}", e);
2269                            VmResponse::Err(SysError::new(EINVAL))
2270                        }
2271                    };
2272                }
2273                VmResponse::Err(SysError::new(ENOTSUP))
2274            }
2275            VmRequest::Swap(SwapCommand::Status) => {
2276                #[cfg(feature = "swap")]
2277                if let Some(swap_controller) = swap_controller {
2278                    return match swap_controller.status() {
2279                        Ok(status) => VmResponse::SwapStatus(status),
2280                        Err(e) => {
2281                            error!("swap status failed: {}", e);
2282                            VmResponse::Err(SysError::new(EINVAL))
2283                        }
2284                    };
2285                }
2286                VmResponse::Err(SysError::new(ENOTSUP))
2287            }
2288            VmRequest::SuspendVm => {
2289                info!("Starting crosvm suspend");
2290                kick_vcpus(VcpuControl::RunState(VmRunMode::Suspending));
2291                let current_mode = match get_vcpu_state(kick_vcpus, vcpu_size) {
2292                    Ok(state) => state,
2293                    Err(e) => {
2294                        error!("failed to get vcpu state: {e}");
2295                        return VmResponse::Err(SysError::new(EIO));
2296                    }
2297                };
2298                if current_mode != VmRunMode::Suspending {
2299                    error!("vCPUs failed to all suspend.");
2300                    return VmResponse::Err(SysError::new(EIO));
2301                }
2302                // Snapshot the pvclock ASAP after stopping vCPUs.
2303                if vm.check_capability(VmCap::PvClock) {
2304                    if suspended_pvclock_state.is_none() {
2305                        *suspended_pvclock_state = Some(match vm.get_pvclock() {
2306                            Ok(x) => x,
2307                            Err(e) => {
2308                                error!("suspend_pvclock failed: {e:?}");
2309                                return VmResponse::Err(SysError::new(EIO));
2310                            }
2311                        });
2312                    }
2313                }
2314                if let Err(e) = device_control_tube
2315                    .send(&DeviceControlCommand::SleepDevices)
2316                    .context("send command to devices control socket")
2317                {
2318                    error!("{:?}", e);
2319                    return VmResponse::Err(SysError::new(EIO));
2320                };
2321                match device_control_tube
2322                    .recv()
2323                    .context("receive from devices control socket")
2324                {
2325                    Ok(VmResponse::Ok) => {
2326                        info!("Finished crosvm suspend successfully");
2327                        VmResponse::Ok
2328                    }
2329                    Ok(resp) => {
2330                        error!("device sleep failed: {}", resp);
2331                        VmResponse::Err(SysError::new(EIO))
2332                    }
2333                    Err(e) => {
2334                        error!("receive from devices control socket: {:?}", e);
2335                        VmResponse::Err(SysError::new(EIO))
2336                    }
2337                }
2338            }
2339            VmRequest::ResumeVm => {
2340                info!("Starting crosvm resume");
2341                if let Err(e) = device_control_tube
2342                    .send(&DeviceControlCommand::WakeDevices)
2343                    .context("send command to devices control socket")
2344                {
2345                    error!("{:?}", e);
2346                    return VmResponse::Err(SysError::new(EIO));
2347                };
2348                match device_control_tube
2349                    .recv()
2350                    .context("receive from devices control socket")
2351                {
2352                    Ok(VmResponse::Ok) => {
2353                        info!("Finished crosvm resume successfully");
2354                    }
2355                    Ok(resp) => {
2356                        error!("device wake failed: {}", resp);
2357                        return VmResponse::Err(SysError::new(EIO));
2358                    }
2359                    Err(e) => {
2360                        error!("receive from devices control socket: {:?}", e);
2361                        return VmResponse::Err(SysError::new(EIO));
2362                    }
2363                }
2364                // Resume the pvclock as late as possible before starting vCPUs.
2365                if vm.check_capability(VmCap::PvClock) {
2366                    // If None, then we aren't suspended, which is a valid case.
2367                    if let Some(x) = &suspended_pvclock_state.take() {
2368                        if let Err(e) = vm.set_pvclock(x) {
2369                            error!("resume_pvclock failed: {e:?}");
2370                            return VmResponse::Err(SysError::new(EIO));
2371                        }
2372                    }
2373                }
2374                kick_vcpus(VcpuControl::RunState(VmRunMode::Running));
2375                VmResponse::Ok
2376            }
2377            VmRequest::DeviceControl(req) => req.execute(pm).into(),
2378            VmRequest::MakeRT => {
2379                kick_vcpus(VcpuControl::MakeRT);
2380                VmResponse::Ok
2381            }
2382            #[cfg(feature = "balloon")]
2383            VmRequest::BalloonCommand(_) => unreachable!("Should be handled with BalloonTube"),
2384            VmRequest::DiskCommand {
2385                disk_index,
2386                ref command,
2387            } => match &disk_host_tubes.get(*disk_index) {
2388                Some(tube) => handle_disk_command(command, tube),
2389                None => VmResponse::Err(SysError::new(ENODEV)),
2390            },
2391            VmRequest::GpuCommand(ref cmd) => match gpu_control_tube {
2392                Some(gpu_control) => {
2393                    let res = gpu_control.send(cmd);
2394                    if let Err(e) = res {
2395                        error!("fail to send command to gpu control socket: {}", e);
2396                        return VmResponse::Err(SysError::new(EIO));
2397                    }
2398                    match gpu_control.recv() {
2399                        Ok(response) => VmResponse::GpuResponse(response),
2400                        Err(e) => {
2401                            error!("fail to recv command from gpu control socket: {}", e);
2402                            VmResponse::Err(SysError::new(EIO))
2403                        }
2404                    }
2405                }
2406                None => {
2407                    error!("gpu control is not enabled in crosvm");
2408                    VmResponse::Err(SysError::new(EIO))
2409                }
2410            },
2411            VmRequest::UsbCommand(ref cmd) => {
2412                let usb_control_tube = match usb_control_tube {
2413                    Some(t) => t,
2414                    None => {
2415                        error!("attempted to execute USB request without control tube");
2416                        return VmResponse::Err(SysError::new(ENODEV));
2417                    }
2418                };
2419                let res = usb_control_tube.send(cmd);
2420                if let Err(e) = res {
2421                    error!("fail to send command to usb control socket: {}", e);
2422                    return VmResponse::Err(SysError::new(EIO));
2423                }
2424                match usb_control_tube.recv() {
2425                    Ok(response) => VmResponse::UsbResponse(response),
2426                    Err(e) => {
2427                        error!("fail to recv command from usb control socket: {}", e);
2428                        VmResponse::Err(SysError::new(EIO))
2429                    }
2430                }
2431            }
2432            VmRequest::BatCommand(type_, ref cmd) => {
2433                match bat_control {
2434                    Some(battery) => {
2435                        if battery.type_ != *type_ {
2436                            error!("ignored battery command due to battery type: expected {:?}, got {:?}", battery.type_, type_);
2437                            return VmResponse::Err(SysError::new(EINVAL));
2438                        }
2439
2440                        let res = battery.control_tube.send(cmd);
2441                        if let Err(e) = res {
2442                            error!("fail to send command to bat control socket: {}", e);
2443                            return VmResponse::Err(SysError::new(EIO));
2444                        }
2445
2446                        match battery.control_tube.recv() {
2447                            Ok(response) => VmResponse::BatResponse(response),
2448                            Err(e) => {
2449                                error!("fail to recv command from bat control socket: {}", e);
2450                                VmResponse::Err(SysError::new(EIO))
2451                            }
2452                        }
2453                    }
2454                    None => VmResponse::BatResponse(BatControlResult::NoBatDevice),
2455                }
2456            }
2457            #[cfg(feature = "audio")]
2458            VmRequest::SndCommand(ref cmd) => match cmd {
2459                SndControlCommand::MuteAll(muted) => {
2460                    for tube in snd_host_tubes {
2461                        let res = tube.send(&SndControlCommand::MuteAll(*muted));
2462                        if let Err(e) = res {
2463                            error!("fail to send command to snd control socket: {}", e);
2464                            return VmResponse::Err(SysError::new(EIO));
2465                        }
2466
2467                        match tube.recv() {
2468                            Ok(VmResponse::Ok) => {
2469                                debug!("device is successfully muted");
2470                            }
2471                            Ok(resp) => {
2472                                error!("mute failed: {}", resp);
2473                                return VmResponse::ErrString("fail to mute the device".to_owned());
2474                            }
2475                            Err(e) => return VmResponse::Err(SysError::new(EIO)),
2476                        }
2477                    }
2478                    VmResponse::Ok
2479                }
2480            },
2481            #[cfg(feature = "pci-hotplug")]
2482            VmRequest::HotPlugNetCommand(ref _net_cmd) => {
2483                VmResponse::ErrString("hot plug not supported".to_owned())
2484            }
2485            VmRequest::Snapshot(SnapshotCommand::Take {
2486                ref snapshot_path,
2487                compress_memory,
2488                encrypt,
2489            }) => {
2490                info!("Starting crosvm snapshot");
2491                match do_snapshot(
2492                    snapshot_path.to_path_buf(),
2493                    kick_vcpus,
2494                    irq_handler_control,
2495                    device_control_tube,
2496                    vcpu_size,
2497                    snapshot_irqchip,
2498                    *compress_memory,
2499                    *encrypt,
2500                    suspended_pvclock_state,
2501                    vm,
2502                ) {
2503                    Ok(()) => {
2504                        info!("Finished crosvm snapshot successfully");
2505                        VmResponse::Ok
2506                    }
2507                    Err(e) => {
2508                        error!("failed to handle snapshot: {:?}", e);
2509                        VmResponse::Err(SysError::new(EIO))
2510                    }
2511                }
2512            }
2513            VmRequest::RegisterListener {
2514                socket_addr: _,
2515                event: _,
2516            } => VmResponse::Ok,
2517            VmRequest::UnregisterListener {
2518                socket_addr: _,
2519                event: _,
2520            } => VmResponse::Ok,
2521            VmRequest::Unregister { socket_addr: _ } => VmResponse::Ok,
2522            VmRequest::VcpuPidTid => unreachable!(),
2523            VmRequest::Throttle(_, _) => unreachable!(),
2524            VmRequest::GetVmDescriptor => {
2525                let vm_fd = match vm.try_clone_descriptor() {
2526                    Ok(vm_fd) => vm_fd,
2527                    Err(e) => {
2528                        error!("failed to get vm_fd: {:?}", e);
2529                        return VmResponse::Err(e);
2530                    }
2531                };
2532                VmResponse::VmDescriptor {
2533                    hypervisor: vm.hypervisor_kind(),
2534                    vm_fd,
2535                }
2536            }
2537            VmRequest::RegisterMemory { .. } => unreachable!(),
2538            VmRequest::UnregisterMemory { .. } => unreachable!(),
2539        }
2540    }
2541}
2542
2543/// Snapshot the VM to file at `snapshot_path`
2544fn do_snapshot(
2545    snapshot_path: PathBuf,
2546    kick_vcpus: impl Fn(VcpuControl),
2547    irq_handler_control: &Tube,
2548    device_control_tube: &Tube,
2549    vcpu_size: usize,
2550    snapshot_irqchip: impl Fn() -> anyhow::Result<AnySnapshot>,
2551    compress_memory: bool,
2552    encrypt: bool,
2553    suspended_pvclock_state: &mut Option<hypervisor::ClockState>,
2554    vm: &dyn Vm,
2555) -> anyhow::Result<()> {
2556    let snapshot_start = Instant::now();
2557
2558    let _vcpu_guard = VcpuSuspendGuard::new(&kick_vcpus, vcpu_size)?;
2559    let _device_guard = DeviceSleepGuard::new(device_control_tube)?;
2560
2561    // We want to flush all pending IRQs to the interrupt controller. There are two cases:
2562    //
2563    // MSIs: these are directly delivered to the interrupt controller.
2564    // We must verify the handler thread cycles once to deliver these interrupts.
2565    //
2566    // Legacy interrupts: in the case of a split IRQ chip, these interrupts may
2567    // flow through the userspace IOAPIC. If the hypervisor does not support
2568    // irqfds (e.g. WHPX), a single iteration will only flush the IRQ to the
2569    // IOAPIC. The underlying MSI will be asserted at this point, but if the
2570    // IRQ handler doesn't run another iteration, it won't be delivered to the
2571    // interrupt controller. This is why we cycle the handler thread twice (doing so
2572    // ensures we process the underlying MSI).
2573    //
2574    // We can handle both of these cases by iterating until there are no tokens
2575    // serviced on the requested iteration. Note that in the legacy case, this
2576    // ensures at least two iterations.
2577    //
2578    // Note: within crosvm, *all* interrupts are eventually converted into the
2579    // same mechanicism that MSIs use. This is why we say "underlying" MSI for
2580    // a legacy IRQ.
2581    {
2582        let mut flush_attempts = 0;
2583        loop {
2584            irq_handler_control
2585                .send(&IrqHandlerRequest::WakeAndNotifyIteration)
2586                .context("failed to send flush command to IRQ handler thread")?;
2587            let resp = irq_handler_control
2588                .recv()
2589                .context("failed to recv flush response from IRQ handler thread")?;
2590            match resp {
2591                IrqHandlerResponse::HandlerIterationComplete(tokens_serviced) => {
2592                    if tokens_serviced == 0 {
2593                        break;
2594                    }
2595                }
2596                _ => bail!("received unexpected reply from IRQ handler: {:?}", resp),
2597            }
2598            flush_attempts += 1;
2599            if flush_attempts > EXPECTED_MAX_IRQ_FLUSH_ITERATIONS {
2600                warn!(
2601                    "flushing IRQs for snapshot may be stalled after iteration {}, expected <= {}
2602                      iterations",
2603                    flush_attempts, EXPECTED_MAX_IRQ_FLUSH_ITERATIONS
2604                );
2605            }
2606        }
2607        info!("flushed IRQs in {} iterations", flush_attempts);
2608    }
2609    let snapshot_writer = SnapshotWriter::new(snapshot_path, encrypt)?;
2610
2611    // Snapshot hypervisor's paravirtualized clock.
2612    snapshot_writer.write_fragment("pvclock", &AnySnapshot::to_any(suspended_pvclock_state)?)?;
2613
2614    // Snapshot Vcpus
2615    info!("VCPUs snapshotting...");
2616    let (send_chan, recv_chan) = mpsc::channel();
2617    kick_vcpus(VcpuControl::Snapshot(
2618        snapshot_writer.add_namespace("vcpu")?,
2619        send_chan,
2620    ));
2621    // Validate all Vcpus snapshot successfully
2622    for _ in 0..vcpu_size {
2623        recv_chan
2624            .recv()
2625            .context("Failed to recv Vcpu snapshot response")?
2626            .context("Failed to snapshot Vcpu")?;
2627    }
2628    info!("VCPUs snapshotted.");
2629
2630    // Snapshot irqchip
2631    info!("Snapshotting irqchip...");
2632    let irqchip_snap = snapshot_irqchip()?;
2633    snapshot_writer
2634        .write_fragment("irqchip", &irqchip_snap)
2635        .context("Failed to write irqchip state")?;
2636    info!("Snapshotted irqchip.");
2637
2638    // Snapshot memory
2639    {
2640        let mem_snap_start = Instant::now();
2641        // Use 64MB chunks when writing the memory snapshot (if encryption is used).
2642        const MEMORY_SNAP_ENCRYPTED_CHUNK_SIZE_BYTES: usize = 1024 * 1024 * 64;
2643        // SAFETY:
2644        // VM & devices are stopped.
2645        let guest_memory_metadata = unsafe {
2646            vm.get_memory()
2647                .snapshot(
2648                    &mut snapshot_writer.raw_fragment_with_chunk_size(
2649                        "mem",
2650                        MEMORY_SNAP_ENCRYPTED_CHUNK_SIZE_BYTES,
2651                    )?,
2652                    compress_memory,
2653                )
2654                .context("failed to snapshot memory")?
2655        };
2656        snapshot_writer.write_fragment("mem_metadata", &guest_memory_metadata)?;
2657
2658        let mem_snap_duration_ms = mem_snap_start.elapsed().as_millis();
2659        info!(
2660            "snapshot: memory snapshotted {}MB in {}ms",
2661            vm.get_memory().memory_size() / 1024 / 1024,
2662            mem_snap_duration_ms
2663        );
2664        metrics::log_metric_with_details(
2665            metrics::MetricEventType::SnapshotSaveMemoryLatency,
2666            mem_snap_duration_ms as i64,
2667            &metrics_events::RecordDetails {},
2668        );
2669    }
2670    // Snapshot devices
2671    info!("Devices snapshotting...");
2672    device_control_tube
2673        .send(&DeviceControlCommand::SnapshotDevices { snapshot_writer })
2674        .context("send command to devices control socket")?;
2675    let resp: VmResponse = device_control_tube
2676        .recv()
2677        .context("receive from devices control socket")?;
2678    if !matches!(resp, VmResponse::Ok) {
2679        bail!("unexpected SnapshotDevices response: {resp}");
2680    }
2681    info!("Devices snapshotted.");
2682
2683    let snap_duration_ms = snapshot_start.elapsed().as_millis();
2684    info!(
2685        "snapshot: completed snapshot in {}ms; VM mem size: {}MB",
2686        snap_duration_ms,
2687        vm.get_memory().memory_size() / 1024 / 1024,
2688    );
2689    metrics::log_metric_with_details(
2690        metrics::MetricEventType::SnapshotSaveOverallLatency,
2691        snap_duration_ms as i64,
2692        &metrics_events::RecordDetails {},
2693    );
2694    Ok(())
2695}
2696
2697/// Restore the VM to the snapshot at `restore_path`.
2698///
2699/// Same as `VmRequest::execute` with a `VmRequest::Restore`. Exposed as a separate function
2700/// because not all the `VmRequest::execute` arguments are available in the "cold restore" flow.
2701pub fn do_restore(
2702    restore_path: &Path,
2703    kick_vcpus: impl Fn(VcpuControl),
2704    kick_vcpu: impl Fn(VcpuControl, usize),
2705    irq_handler_control: &Tube,
2706    device_control_tube: &Tube,
2707    vcpu_size: usize,
2708    mut restore_irqchip: impl FnMut(AnySnapshot) -> anyhow::Result<()>,
2709    require_encrypted: bool,
2710    suspended_pvclock_state: &mut Option<hypervisor::ClockState>,
2711    vm: &dyn Vm,
2712) -> anyhow::Result<()> {
2713    let restore_start = Instant::now();
2714    let _guard = VcpuSuspendGuard::new(&kick_vcpus, vcpu_size);
2715    let _devices_guard = DeviceSleepGuard::new(device_control_tube)?;
2716
2717    let snapshot_reader = SnapshotReader::new(restore_path, require_encrypted)?;
2718
2719    // Restore hypervisor's paravirtualized clock.
2720    *suspended_pvclock_state = snapshot_reader.read_fragment("pvclock")?;
2721
2722    // Restore IrqChip
2723    let irq_snapshot: AnySnapshot = snapshot_reader.read_fragment("irqchip")?;
2724    restore_irqchip(irq_snapshot)?;
2725
2726    // Restore Vcpu(s)
2727    let vcpu_snapshot_reader = snapshot_reader.namespace("vcpu")?;
2728    let vcpu_snapshot_count = vcpu_snapshot_reader.list_fragments()?.len();
2729    if vcpu_snapshot_count != vcpu_size {
2730        bail!(
2731            "bad cpu count in snapshot: expected={} got={}",
2732            vcpu_size,
2733            vcpu_snapshot_count,
2734        );
2735    }
2736    #[cfg(target_arch = "x86_64")]
2737    let host_tsc_reference_moment = {
2738        // SAFETY: rdtsc takes no arguments.
2739        unsafe { _rdtsc() }
2740    };
2741    let (send_chan, recv_chan) = mpsc::channel();
2742    for vcpu_id in 0..vcpu_size {
2743        kick_vcpu(
2744            VcpuControl::Restore(VcpuRestoreRequest {
2745                result_sender: send_chan.clone(),
2746                snapshot_reader: vcpu_snapshot_reader.clone(),
2747                #[cfg(target_arch = "x86_64")]
2748                host_tsc_reference_moment,
2749            }),
2750            vcpu_id,
2751        );
2752    }
2753    for _ in 0..vcpu_size {
2754        recv_chan
2755            .recv()
2756            .context("Failed to recv restore response")?
2757            .context("Failed to restore vcpu")?;
2758    }
2759
2760    // Restore Memory
2761    {
2762        let mem_restore_start = Instant::now();
2763        let guest_memory_metadata = snapshot_reader.read_fragment("mem_metadata")?;
2764        // SAFETY:
2765        // VM & devices are stopped.
2766        unsafe {
2767            vm.get_memory().restore(
2768                guest_memory_metadata,
2769                &mut snapshot_reader.raw_fragment("mem")?,
2770            )?
2771        };
2772        let mem_restore_duration_ms = mem_restore_start.elapsed().as_millis();
2773        info!(
2774            "snapshot: memory restored {}MB in {}ms",
2775            vm.get_memory().memory_size() / 1024 / 1024,
2776            mem_restore_duration_ms
2777        );
2778        metrics::log_metric_with_details(
2779            metrics::MetricEventType::SnapshotRestoreMemoryLatency,
2780            mem_restore_duration_ms as i64,
2781            &metrics_events::RecordDetails {},
2782        );
2783    }
2784    // Restore devices
2785    device_control_tube
2786        .send(&DeviceControlCommand::RestoreDevices {
2787            snapshot_reader: snapshot_reader.clone(),
2788        })
2789        .context("send restore devices command to devices control socket")?;
2790    let resp: VmResponse = device_control_tube
2791        .recv()
2792        .context("receive from devices control socket")?;
2793    if !matches!(resp, VmResponse::Ok) {
2794        bail!("unexpected RestoreDevices response: {resp}");
2795    }
2796
2797    // refresh the IRQ tokens.
2798    {
2799        irq_handler_control
2800            .send(&IrqHandlerRequest::RefreshIrqEventTokens)
2801            .context("failed to send refresh irq event token command to IRQ handler thread")?;
2802        let resp: IrqHandlerResponse = irq_handler_control
2803            .recv()
2804            .context("failed to recv refresh response from IRQ handler thread")?;
2805        if !matches!(resp, IrqHandlerResponse::IrqEventTokenRefreshComplete) {
2806            bail!(
2807                "received unexpected reply from IRQ handler thread: {:?}",
2808                resp
2809            );
2810        }
2811    }
2812
2813    let restore_duration_ms = restore_start.elapsed().as_millis();
2814    info!(
2815        "snapshot: completed restore in {}ms; mem size: {}",
2816        restore_duration_ms,
2817        vm.get_memory().memory_size(),
2818    );
2819
2820    metrics::log_metric_with_details(
2821        metrics::MetricEventType::SnapshotRestoreOverallLatency,
2822        restore_duration_ms as i64,
2823        &metrics_events::RecordDetails {},
2824    );
2825    Ok(())
2826}
2827
2828pub type HypervisorKind = hypervisor::HypervisorKind;
2829
2830/// Indication of success or failure of a `VmRequest`.
2831///
2832/// Success is usually indicated `VmResponse::Ok` unless there is data associated with the response.
2833#[derive(Serialize, Deserialize, Debug)]
2834#[must_use]
2835pub enum VmResponse {
2836    /// Indicates the request was executed successfully.
2837    Ok,
2838    /// Indicates the request encountered some error during execution.
2839    Err(SysError),
2840    /// Indicates the request encountered some error during execution.
2841    ErrString(String),
2842    /// The memory was registered into guest address space in memory slot number `slot`.
2843    RegisterMemory { slot: u32 },
2844    /// Variant of the register memory but with region_id.
2845    RegisterMemory2 { region_id: u64 },
2846    /// Results of balloon control commands.
2847    #[cfg(feature = "balloon")]
2848    BalloonStats {
2849        stats: balloon_control::BalloonStats,
2850        balloon_actual: u64,
2851    },
2852    /// Results of balloon WS-R command
2853    #[cfg(feature = "balloon")]
2854    BalloonWS {
2855        ws: balloon_control::BalloonWS,
2856        balloon_actual: u64,
2857    },
2858    /// Results of PCI hot plug
2859    #[cfg(feature = "pci-hotplug")]
2860    PciHotPlugResponse { bus: u8 },
2861    /// Results of usb control commands.
2862    UsbResponse(UsbControlResult),
2863    /// Results of gpu control commands.
2864    GpuResponse(GpuControlResult),
2865    /// Results of battery control commands.
2866    BatResponse(BatControlResult),
2867    /// Results of swap status command.
2868    SwapStatus(SwapStatus),
2869    /// Gets the state of Devices (sleep/wake)
2870    DevicesState(DevicesState),
2871    /// Map of the Vcpu PID/TIDs
2872    VcpuPidTidResponse {
2873        pid_tid_map: BTreeMap<usize, (u32, u32)>,
2874    },
2875    VmDescriptor {
2876        hypervisor: HypervisorKind,
2877        vm_fd: SafeDescriptor,
2878    },
2879}
2880
2881impl Display for VmResponse {
2882    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2883        use self::VmResponse::*;
2884
2885        match self {
2886            Ok => write!(f, "ok"),
2887            Err(e) => write!(f, "error: {e}"),
2888            ErrString(e) => write!(f, "error: {e}"),
2889            RegisterMemory { slot } => write!(f, "memory registered in slot {slot}"),
2890            RegisterMemory2 { region_id } => {
2891                write!(f, "memory registered in region id {region_id}")
2892            }
2893            #[cfg(feature = "balloon")]
2894            VmResponse::BalloonStats {
2895                stats,
2896                balloon_actual,
2897            } => {
2898                write!(
2899                    f,
2900                    "stats: {}\nballoon_actual: {}",
2901                    serde_json::to_string_pretty(&stats)
2902                        .unwrap_or_else(|_| "invalid_response".to_string()),
2903                    balloon_actual
2904                )
2905            }
2906            #[cfg(feature = "balloon")]
2907            VmResponse::BalloonWS { ws, balloon_actual } => {
2908                write!(
2909                    f,
2910                    "ws: {}, balloon_actual: {}",
2911                    serde_json::to_string_pretty(&ws)
2912                        .unwrap_or_else(|_| "invalid_response".to_string()),
2913                    balloon_actual,
2914                )
2915            }
2916            UsbResponse(result) => write!(f, "usb control request get result {result:?}"),
2917            #[cfg(feature = "pci-hotplug")]
2918            PciHotPlugResponse { bus } => write!(f, "pci hotplug bus {bus:?}"),
2919            GpuResponse(result) => write!(f, "gpu control request result {result:?}"),
2920            BatResponse(result) => write!(f, "{result}"),
2921            SwapStatus(status) => {
2922                write!(
2923                    f,
2924                    "{}",
2925                    serde_json::to_string(&status)
2926                        .unwrap_or_else(|_| "invalid_response".to_string()),
2927                )
2928            }
2929            DevicesState(status) => write!(f, "devices status: {status:?}"),
2930            VcpuPidTidResponse { pid_tid_map } => write!(f, "vcpu pid tid map: {pid_tid_map:?}"),
2931            VmDescriptor { hypervisor, vm_fd } => {
2932                write!(f, "hypervisor: {hypervisor:?}, vm_fd: {vm_fd:?}")
2933            }
2934        }
2935    }
2936}
2937
2938/// Enum that allows remote control of a wait context (used between the Windows GpuDisplay & the
2939/// GPU worker).
2940#[derive(Serialize, Deserialize)]
2941pub enum ModifyWaitContext {
2942    Add(#[serde(with = "with_as_descriptor")] Descriptor),
2943}
2944
2945#[sorted]
2946#[derive(Error, Debug)]
2947pub enum VirtioIOMMUVfioError {
2948    #[error("socket failed")]
2949    SocketFailed,
2950    #[error("unexpected response: {0}")]
2951    UnexpectedResponse(VirtioIOMMUResponse),
2952    #[error("unknown command: `{0}`")]
2953    UnknownCommand(String),
2954    #[error("{0}")]
2955    VfioControl(VirtioIOMMUVfioResult),
2956}
2957
2958#[derive(Serialize, Deserialize, Debug)]
2959pub enum VirtioIOMMUVfioCommand {
2960    // Add the vfio device attached to virtio-iommu.
2961    VfioDeviceAdd {
2962        endpoint_addr: u32,
2963        wrapper_id: u32,
2964        #[serde(with = "with_as_descriptor")]
2965        container: File,
2966    },
2967    // Delete the vfio device attached to virtio-iommu.
2968    VfioDeviceDel {
2969        endpoint_addr: u32,
2970    },
2971    // Map a dma-buf into vfio iommu table
2972    VfioDmabufMap {
2973        region_id: VmMemoryRegionId,
2974        gpa: u64,
2975        size: u64,
2976        dma_buf: SafeDescriptor,
2977    },
2978    // Unmap a dma-buf from vfio iommu table
2979    VfioDmabufUnmap(VmMemoryRegionId),
2980}
2981
2982#[derive(Serialize, Deserialize, Debug)]
2983pub enum VirtioIOMMUVfioResult {
2984    Ok,
2985    NotInPCIRanges,
2986    NoAvailableContainer,
2987    NoSuchDevice,
2988    NoSuchMappedDmabuf,
2989    InvalidParam,
2990}
2991
2992impl Display for VirtioIOMMUVfioResult {
2993    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2994        use self::VirtioIOMMUVfioResult::*;
2995
2996        match self {
2997            Ok => write!(f, "successfully"),
2998            NotInPCIRanges => write!(f, "not in the pci ranges of virtio-iommu"),
2999            NoAvailableContainer => write!(f, "no available vfio container"),
3000            NoSuchDevice => write!(f, "no such a vfio device"),
3001            NoSuchMappedDmabuf => write!(f, "no such a mapped dmabuf"),
3002            InvalidParam => write!(f, "invalid parameters"),
3003        }
3004    }
3005}
3006
3007/// A request to the virtio-iommu process to perform some operations.
3008///
3009/// Unless otherwise noted, each request should expect a `VirtioIOMMUResponse::Ok` to be received on
3010/// success.
3011#[derive(Serialize, Deserialize, Debug)]
3012pub enum VirtioIOMMURequest {
3013    /// Command for vfio related operations.
3014    VfioCommand(VirtioIOMMUVfioCommand),
3015}
3016
3017/// Indication of success or failure of a `VirtioIOMMURequest`.
3018///
3019/// Success is usually indicated `VirtioIOMMUResponse::Ok` unless there is data associated with the
3020/// response.
3021#[derive(Serialize, Deserialize, Debug)]
3022pub enum VirtioIOMMUResponse {
3023    /// Indicates the request was executed successfully.
3024    Ok,
3025    /// Indicates the request encountered some error during execution.
3026    Err(SysError),
3027    /// Results for Vfio commands.
3028    VfioResponse(VirtioIOMMUVfioResult),
3029}
3030
3031impl Display for VirtioIOMMUResponse {
3032    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3033        use self::VirtioIOMMUResponse::*;
3034        match self {
3035            Ok => write!(f, "ok"),
3036            Err(e) => write!(f, "error: {e}"),
3037            VfioResponse(result) => write!(
3038                f,
3039                "The vfio-related virtio-iommu request got result: {result:?}"
3040            ),
3041        }
3042    }
3043}
3044
3045/// Send VirtioIOMMURequest without waiting for the response
3046pub fn virtio_iommu_request_async(
3047    iommu_control_tube: &Tube,
3048    req: &VirtioIOMMURequest,
3049) -> VirtioIOMMUResponse {
3050    match iommu_control_tube.send(&req) {
3051        Ok(_) => VirtioIOMMUResponse::Ok,
3052        Err(e) => {
3053            error!("virtio-iommu socket send failed: {:?}", e);
3054            VirtioIOMMUResponse::Err(SysError::last())
3055        }
3056    }
3057}
3058
3059pub type VirtioIOMMURequestResult = std::result::Result<VirtioIOMMUResponse, ()>;
3060
3061/// Send VirtioIOMMURequest and wait to get the response
3062pub fn virtio_iommu_request(
3063    iommu_control_tube: &Tube,
3064    req: &VirtioIOMMURequest,
3065) -> VirtioIOMMURequestResult {
3066    let response = match virtio_iommu_request_async(iommu_control_tube, req) {
3067        VirtioIOMMUResponse::Ok => match iommu_control_tube.recv() {
3068            Ok(response) => response,
3069            Err(e) => {
3070                error!("virtio-iommu socket recv failed: {:?}", e);
3071                VirtioIOMMUResponse::Err(SysError::last())
3072            }
3073        },
3074        resp => resp,
3075    };
3076    Ok(response)
3077}
3078
3079#[cfg(test)]
3080mod tests {
3081    use anyhow::anyhow;
3082
3083    use super::*;
3084
3085    #[test]
3086    fn vm_memory_response_error_should_serialize_and_deserialize_correctly() {
3087        let source_error: VmMemoryResponseError = anyhow!("root cause")
3088            .context("context 1")
3089            .context("context 2")
3090            .into();
3091        let serialized_bytes =
3092            serde_json::to_vec(&source_error).expect("should serialize to json successfully");
3093        let target_error = serde_json::from_slice::<VmMemoryResponseError>(&serialized_bytes)
3094            .expect("should deserialize from json successfully");
3095        assert_eq!(source_error.0.to_string(), target_error.0.to_string());
3096        assert_eq!(
3097            source_error
3098                .0
3099                .chain()
3100                .map(ToString::to_string)
3101                .collect::<Vec<_>>(),
3102            target_error
3103                .0
3104                .chain()
3105                .map(ToString::to_string)
3106                .collect::<Vec<_>>()
3107        );
3108    }
3109
3110    #[test]
3111    fn vm_memory_response_error_deserialization_should_handle_malformat_correctly() {
3112        let flat_source = FlatVmMemoryResponseError(vec![]);
3113        let serialized_bytes =
3114            serde_json::to_vec(&flat_source).expect("should serialize to json successfully");
3115        serde_json::from_slice::<VmMemoryResponseError>(&serialized_bytes)
3116            .expect_err("deserialize with 0 error messages should fail");
3117    }
3118
3119    #[test]
3120    fn test_device_control_request_serde() {
3121        let req = DeviceControlRequest::Gpe {
3122            gpe: 5,
3123            clear_evt: None,
3124        };
3125        let bytes = serde_json::to_vec(&req).unwrap();
3126        let deserialized: DeviceControlRequest = serde_json::from_slice(&bytes).unwrap();
3127        match deserialized {
3128            DeviceControlRequest::Gpe { gpe, clear_evt } => {
3129                assert_eq!(gpe, 5);
3130                assert!(clear_evt.is_none());
3131            }
3132            _ => panic!("unexpected request variant"),
3133        }
3134
3135        let resp = DeviceControlResponse::Ok;
3136        let bytes = serde_json::to_vec(&resp).unwrap();
3137        let deserialized: DeviceControlResponse = serde_json::from_slice(&bytes).unwrap();
3138        match deserialized {
3139            DeviceControlResponse::Ok => {}
3140            _ => panic!("unexpected response variant"),
3141        }
3142
3143        let vm_req = VmRequest::DeviceControl(DeviceControlRequest::Gpe {
3144            gpe: 5,
3145            clear_evt: None,
3146        });
3147        let bytes = serde_json::to_vec(&vm_req).unwrap();
3148        let deserialized: VmRequest = serde_json::from_slice(&bytes).unwrap();
3149        match deserialized {
3150            VmRequest::DeviceControl(DeviceControlRequest::Gpe { gpe, clear_evt }) => {
3151                assert_eq!(gpe, 5);
3152                assert!(clear_evt.is_none());
3153            }
3154            _ => panic!("unexpected request variant"),
3155        }
3156        // Ensure that VmRequest cannot be deserialized as DeviceControlRequest directly.
3157        assert!(serde_json::from_slice::<DeviceControlRequest>(&bytes).is_err());
3158    }
3159
3160    #[test]
3161    fn test_audio_permission_wire_protocol() {
3162        // Request wire conversions
3163        assert_eq!(AudioPermissionRequest::Check.to_wire(), 1u8);
3164        assert_eq!(
3165            AudioPermissionRequest::try_from(1u8),
3166            Ok(AudioPermissionRequest::Check)
3167        );
3168        assert_eq!(AudioPermissionRequest::try_from(0u8), Err(0u8));
3169        assert_eq!(AudioPermissionRequest::try_from(255u8), Err(255u8));
3170
3171        // Response wire conversions
3172        assert_eq!(AudioPermissionResponse::Granted.to_wire(), 1u8);
3173        assert_eq!(AudioPermissionResponse::Denied.to_wire(), 2u8);
3174        assert_eq!(
3175            AudioPermissionResponse::try_from(1u8),
3176            Ok(AudioPermissionResponse::Granted)
3177        );
3178        assert_eq!(
3179            AudioPermissionResponse::try_from(2u8),
3180            Ok(AudioPermissionResponse::Denied)
3181        );
3182        assert_eq!(AudioPermissionResponse::try_from(0u8), Err(0u8));
3183        assert_eq!(AudioPermissionResponse::try_from(3u8), Err(3u8));
3184    }
3185}