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