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