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