vm_control/
lib.rs

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