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