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