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