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#[repr(u8)]
259#[derive(Copy, Clone, Debug, PartialEq, Eq)]
260pub enum AudioPermissionRequest {
261 Check = 1,
263}
264
265impl AudioPermissionRequest {
266 pub const fn to_wire(self) -> u8 {
267 self as u8
268 }
269}
270
271impl TryFrom<u8> for AudioPermissionRequest {
272 type Error = u8;
273
274 fn try_from(val: u8) -> StdResult<Self, Self::Error> {
275 match val {
276 1 => Ok(Self::Check),
277 unknown => Err(unknown),
278 }
279 }
280}
281
282#[repr(u8)]
284#[derive(Copy, Clone, Debug, PartialEq, Eq)]
285pub enum AudioPermissionResponse {
286 Granted = 1,
288 Denied = 2,
290}
291
292impl AudioPermissionResponse {
293 pub const fn to_wire(self) -> u8 {
294 self as u8
295 }
296}
297
298impl TryFrom<u8> for AudioPermissionResponse {
299 type Error = u8;
300
301 fn try_from(val: u8) -> StdResult<Self, Self::Error> {
302 match val {
303 1 => Ok(Self::Granted),
304 2 => Ok(Self::Denied),
305 unknown => Err(unknown),
306 }
307 }
308}
309
310#[cfg(feature = "pci-hotplug")]
312#[derive(Serialize, Deserialize, Debug)]
313pub enum NetControlCommand {
314 AddTap(String),
315 RemoveTap(u8),
316}
317
318#[derive(Serialize, Deserialize, Debug)]
319pub enum UsbControlCommand {
320 AttachDevice {
321 #[serde(with = "with_as_descriptor")]
322 file: File,
323 },
324 AttachSecurityKey {
325 #[serde(with = "with_as_descriptor")]
326 file: File,
327 },
328 DetachDevice {
329 port: u8,
330 },
331 ListDevice {
332 ports: [u8; USB_CONTROL_MAX_PORTS],
333 },
334}
335
336#[derive(Serialize, Deserialize, Copy, Clone, Debug, Default)]
337pub struct UsbControlAttachedDevice {
338 pub port: u8,
339 pub vendor_id: u16,
340 pub product_id: u16,
341}
342
343impl UsbControlAttachedDevice {
344 pub fn valid(self) -> bool {
345 self.port != 0
346 }
347}
348
349#[cfg(feature = "pci-hotplug")]
350#[derive(Serialize, Deserialize, Debug, Clone)]
351#[must_use]
352pub enum PciControlResult {
354 AddOk { bus: u8 },
355 ErrString(String),
356 RemoveOk,
357}
358
359#[cfg(feature = "pci-hotplug")]
360impl Display for PciControlResult {
361 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
362 use self::PciControlResult::*;
363
364 match self {
365 AddOk { bus } => write!(f, "add_ok {bus}"),
366 ErrString(e) => write!(f, "error: {e}"),
367 RemoveOk => write!(f, "remove_ok"),
368 }
369 }
370}
371
372#[derive(Serialize, Deserialize, Debug, Clone)]
373pub enum UsbControlResult {
374 Ok { port: u8 },
375 NoAvailablePort,
376 NoSuchDevice,
377 NoSuchPort,
378 FailedToOpenDevice,
379 Devices([UsbControlAttachedDevice; USB_CONTROL_MAX_PORTS]),
380 FailedToInitHostDevice,
381}
382
383impl Display for UsbControlResult {
384 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
385 use self::UsbControlResult::*;
386
387 match self {
388 UsbControlResult::Ok { port } => write!(f, "ok {port}"),
389 NoAvailablePort => write!(f, "no_available_port"),
390 NoSuchDevice => write!(f, "no_such_device"),
391 NoSuchPort => write!(f, "no_such_port"),
392 FailedToOpenDevice => write!(f, "failed_to_open_device"),
393 Devices(devices) => {
394 write!(f, "devices")?;
395 for d in devices.iter().filter(|d| d.valid()) {
396 write!(f, " {} {:04x} {:04x}", d.port, d.vendor_id, d.product_id)?;
397 }
398 std::result::Result::Ok(())
399 }
400 FailedToInitHostDevice => write!(f, "failed_to_init_host_device"),
401 }
402 }
403}
404
405#[derive(Serialize, Deserialize, Debug)]
407pub enum SnapshotCommand {
408 Take {
409 snapshot_path: PathBuf,
410 compress_memory: bool,
411 encrypt: bool,
412 },
413}
414
415#[derive(Serialize, Deserialize, Debug)]
417pub enum DeviceControlCommand {
418 SleepDevices,
419 WakeDevices,
420 SnapshotDevices { snapshot_writer: SnapshotWriter },
421 RestoreDevices { snapshot_reader: SnapshotReader },
422 GetDevicesState,
423 Exit,
424}
425
426#[derive(Serialize, Deserialize)]
428pub enum IrqHandlerRequest {
429 AddIrqControlTubes(Vec<Tube>),
431 RefreshIrqEventTokens,
439 WakeAndNotifyIteration,
440 Exit,
442}
443
444const EXPECTED_MAX_IRQ_FLUSH_ITERATIONS: usize = 100;
445
446#[derive(Serialize, Deserialize, Debug)]
448pub enum IrqHandlerResponse {
449 IrqEventTokenRefreshComplete,
451 HandlerIterationComplete(usize),
454}
455
456#[derive(Serialize, Deserialize)]
458pub enum VmMemorySource {
459 SharedMemory(SharedMemory),
462 Descriptor {
464 descriptor: SafeDescriptor,
466 offset: u64,
468 size: u64,
470 },
471 Vulkan {
473 descriptor: SafeDescriptor,
474 handle_type: u32,
475 memory_idx: u32,
476 device_uuid: [u8; 16],
477 driver_uuid: [u8; 16],
478 size: u64,
479 },
480 ExternalMapping { ptr: u64, size: u64 },
482}
483
484#[cfg(feature = "gpu")]
486fn to_rutabaga_desciptor(s: SafeDescriptor) -> RutabagaDescriptor {
487 unsafe { RutabagaDescriptor::from_raw_descriptor(s.into_raw_descriptor()) }
490}
491
492#[cfg(feature = "gpu")]
493struct RutabagaMemoryRegion {
494 region: Box<dyn RutabagaMappedRegion>,
495}
496
497#[cfg(feature = "gpu")]
498impl RutabagaMemoryRegion {
499 pub fn new(region: Box<dyn RutabagaMappedRegion>) -> RutabagaMemoryRegion {
500 RutabagaMemoryRegion { region }
501 }
502}
503
504#[cfg(feature = "gpu")]
505unsafe impl MappedRegion for RutabagaMemoryRegion {
510 fn as_ptr(&self) -> *mut u8 {
511 self.region.as_ptr()
512 }
513
514 fn size(&self) -> usize {
515 self.region.size()
516 }
517}
518
519impl Display for VmMemorySource {
520 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
521 use self::VmMemorySource::*;
522
523 match self {
524 SharedMemory(..) => write!(f, "VmMemorySource::SharedMemory"),
525 Descriptor { .. } => write!(f, "VmMemorySource::Descriptor"),
526 Vulkan { .. } => write!(f, "VmMemorySource::Vulkan"),
527 ExternalMapping { .. } => write!(f, "VmMemorySource::ExternalMapping"),
528 }
529 }
530}
531
532impl VmMemorySource {
533 fn map(
535 self,
536 #[cfg(feature = "gpu")] gralloc: &mut RutabagaGralloc,
537 prot: Protection,
538 ) -> anyhow::Result<(Box<dyn MappedRegion>, u64, Option<SafeDescriptor>)> {
539 let (mem_region, size, descriptor) = match self {
540 VmMemorySource::Descriptor {
541 descriptor,
542 offset,
543 size,
544 } => (
545 map_descriptor(&descriptor, offset, size, prot)?,
546 size,
547 Some(descriptor),
548 ),
549
550 VmMemorySource::SharedMemory(shm) => {
551 (map_descriptor(&shm, 0, shm.size(), prot)?, shm.size(), None)
552 }
553 #[cfg(feature = "gpu")]
554 VmMemorySource::Vulkan {
555 descriptor,
556 handle_type,
557 memory_idx,
558 device_uuid,
559 driver_uuid,
560 size,
561 } => {
562 let device_id = rutabaga_gfx::DeviceId {
563 device_uuid,
564 driver_uuid,
565 };
566 let mapped_region = gralloc
567 .import_and_map(
568 RutabagaMagmaHandle {
569 os_handle: to_rutabaga_desciptor(descriptor),
570 handle_type,
571 },
572 VulkanInfo {
573 memory_idx,
574 device_id,
575 },
576 size,
577 )
578 .with_context(|| {
579 format!(
580 "gralloc failed to import and map, handle type: {handle_type}, memory index {memory_idx}, \
581 size: {size}"
582 )
583 })?;
584 let mapped_region: Box<dyn MappedRegion> =
585 Box::new(RutabagaMemoryRegion::new(mapped_region));
586 (mapped_region, size, None)
587 }
588 #[cfg(not(feature = "gpu"))]
589 VmMemorySource::Vulkan { .. } => {
590 return Err(anyhow::anyhow!(
591 "vulkan mapping is not supported without GPU feature"
592 ));
593 }
594 VmMemorySource::ExternalMapping { ptr, size } => {
595 let mapped_region: Box<dyn MappedRegion> = Box::new(ExternalMapping {
596 ptr,
597 size: size as usize,
598 });
599 (mapped_region, size, None)
600 }
601 };
602 Ok((mem_region, size, descriptor))
603 }
604}
605
606#[derive(Serialize, Deserialize)]
608pub enum VmMemoryDestination {
609 ExistingAllocation { allocation: Alloc, offset: u64 },
611 GuestPhysicalAddress(u64),
613}
614
615impl VmMemoryDestination {
616 pub fn allocate(self, allocator: &mut SystemAllocator, size: u64) -> Result<GuestAddress> {
618 let addr = match self {
619 VmMemoryDestination::ExistingAllocation { allocation, offset } => allocator
620 .mmio_allocator_any()
621 .address_from_pci_offset(allocation, offset, size)
622 .map_err(|_e| SysError::new(EINVAL))?,
623 VmMemoryDestination::GuestPhysicalAddress(gpa) => gpa,
624 };
625 Ok(GuestAddress(addr))
626 }
627}
628
629#[derive(Serialize, Deserialize)]
631pub struct IoEventUpdateRequest {
632 pub event: Event,
633 pub addr: u64,
634 pub datamatch: Datamatch,
635 pub register: bool,
636}
637
638#[cfg(any(target_os = "android", target_os = "linux"))]
642#[derive(Serialize, Deserialize)]
643pub struct VmMemoryFileMapping {
644 #[serde(with = "with_as_descriptor")]
645 pub file: File,
646 pub length: usize,
647 pub mem_offset: usize,
648 pub file_offset: u64,
649}
650
651#[derive(Serialize, Deserialize)]
652pub enum VmMemoryRequest {
653 PrepareSharedMemoryRegion { alloc: Alloc, cache: MemCacheType },
656 RegisterMemory {
658 source: VmMemorySource,
660 dest: VmMemoryDestination,
662 prot: Protection,
664 cache: MemCacheType,
666 },
667 #[cfg(any(target_os = "android", target_os = "linux"))]
668 MmapAndRegisterMemory {
672 shm: SharedMemory,
674 dest: VmMemoryDestination,
676 num_file_mappings: usize,
678 },
679 DynamicallyFreeMemoryRanges { ranges: Vec<(GuestAddress, u64)> },
681 DynamicallyReclaimMemoryRanges { ranges: Vec<(GuestAddress, u64)> },
683 BalloonTargetReached { size: u64 },
685 UnregisterMemory(VmMemoryRegionId),
687 IoEventRaw(IoEventUpdateRequest),
689}
690
691pub struct VmMemoryRequestIommuClient {
693 tube: Arc<Mutex<Tube>>,
694 registered_memory: BTreeSet<VmMemoryRegionId>,
695}
696
697impl VmMemoryRequestIommuClient {
698 pub fn new(tube: Arc<Mutex<Tube>>) -> Self {
700 Self {
701 tube,
702 registered_memory: BTreeSet::new(),
703 }
704 }
705}
706
707enum RegisteredMemory {
708 FixedMapping {
709 slot: MemSlot,
710 offset: usize,
711 size: usize,
712 },
713 DynamicMapping {
714 slot: MemSlot,
715 },
716}
717
718pub struct VmMappedMemoryRegion {
719 guest_address: GuestAddress,
720 slot: MemSlot,
721}
722
723#[derive(Default)]
724pub struct VmMemoryRegionState {
725 mapped_regions: HashMap<Alloc, VmMappedMemoryRegion>,
726 registered_memory: BTreeMap<VmMemoryRegionId, RegisteredMemory>,
727}
728
729fn try_map_to_prepared_region(
730 vm: &dyn Vm,
731 region_state: &mut VmMemoryRegionState,
732 source: &VmMemorySource,
733 dest: &VmMemoryDestination,
734 prot: &Protection,
735) -> Option<VmMemoryResponse> {
736 let VmMemoryDestination::ExistingAllocation {
737 allocation,
738 offset: dest_offset,
739 } = dest
740 else {
741 return None;
742 };
743
744 let VmMappedMemoryRegion {
745 guest_address,
746 slot,
747 } = region_state.mapped_regions.get(allocation)?;
748
749 let (descriptor, file_offset, size) = match source {
750 VmMemorySource::Descriptor {
751 descriptor,
752 offset,
753 size,
754 } => (
755 Descriptor(descriptor.as_raw_descriptor()),
756 *offset,
757 *size as usize,
758 ),
759 VmMemorySource::SharedMemory(shm) => {
760 let size = shm.size() as usize;
761 (Descriptor(shm.as_raw_descriptor()), 0, size)
762 }
763 _ => {
764 let error = anyhow::anyhow!(
765 "source {} is not compatible with fixed mapping into prepared memory region",
766 source
767 );
768 return Some(VmMemoryResponse::Err(error.into()));
769 }
770 };
771 if let Err(err) = vm
772 .add_fd_mapping(
773 *slot,
774 *dest_offset as usize,
775 size,
776 &descriptor,
777 file_offset,
778 *prot,
779 )
780 .context("failed to add fd mapping when trying to map to prepared region")
781 {
782 return Some(VmMemoryResponse::Err(err.into()));
783 }
784
785 let guest_address = GuestAddress(guest_address.0 + dest_offset);
786 let region_id = VmMemoryRegionId(guest_address);
787 region_state.registered_memory.insert(
788 region_id,
789 RegisteredMemory::FixedMapping {
790 slot: *slot,
791 offset: *dest_offset as usize,
792 size,
793 },
794 );
795
796 Some(VmMemoryResponse::RegisterMemory {
797 region_id,
798 slot: *slot,
799 })
800}
801
802impl VmMemoryRequest {
803 pub fn execute(
813 self,
814 #[cfg(any(target_os = "android", target_os = "linux"))] tube: &Tube,
815 vm: &dyn Vm,
816 sys_allocator: &mut SystemAllocator,
817 #[cfg(feature = "gpu")] gralloc: &mut RutabagaGralloc,
818 iommu_client: Option<&mut VmMemoryRequestIommuClient>,
819 region_state: &mut VmMemoryRegionState,
820 remote_peer: bool,
821 ) -> VmMemoryResponse {
822 use self::VmMemoryRequest::*;
823 match self {
824 PrepareSharedMemoryRegion { alloc, cache } => {
825 assert!(iommu_client.is_none());
833
834 if !sys::should_prepare_memory_region() {
835 return VmMemoryResponse::Ok;
836 }
837
838 match sys::prepare_shared_memory_region(vm, sys_allocator, alloc, cache)
839 .context("failed to prepare shared memory region")
840 {
841 Ok(region) => {
842 region_state.mapped_regions.insert(alloc, region);
843 VmMemoryResponse::Ok
844 }
845 Err(e) => VmMemoryResponse::Err(e.into()),
846 }
847 }
848 RegisterMemory {
849 source,
850 dest,
851 prot,
852 cache,
853 } => {
854 if remote_peer && matches!(source, VmMemorySource::ExternalMapping { .. }) {
857 return VmMemoryResponse::Err(anyhow::Error::new(SysError::new(EPERM)).into());
858 }
859
860 if let Some(resp) =
861 try_map_to_prepared_region(vm, region_state, &source, &dest, &prot)
862 {
863 return resp;
864 }
865
866 let (mapped_region, size, descriptor) = match source
869 .map(
870 #[cfg(feature = "gpu")]
871 gralloc,
872 prot,
873 )
874 .context("gralloc mapping")
875 {
876 Ok((region, size, descriptor)) => (region, size, descriptor),
877 Err(e) => return VmMemoryResponse::Err(e.into()),
878 };
879
880 let guest_addr = match dest
881 .allocate(sys_allocator, size)
882 .context("VM memory destination allocation fails")
883 {
884 Ok(addr) => addr,
885 Err(e) => return VmMemoryResponse::Err(e.into()),
886 };
887
888 let slot = match vm
889 .add_memory_region(
890 guest_addr,
891 mapped_region,
892 prot == Protection::read(),
893 false,
894 cache,
895 )
896 .context("failed to add memory region when registering memory")
897 {
898 Ok(slot) => slot,
899 Err(e) => return VmMemoryResponse::Err(e.into()),
900 };
901
902 let region_id = VmMemoryRegionId(guest_addr);
903 if let (Some(descriptor), Some(iommu_client)) = (descriptor, iommu_client) {
904 let request =
905 VirtioIOMMURequest::VfioCommand(VirtioIOMMUVfioCommand::VfioDmabufMap {
906 region_id,
907 gpa: guest_addr.0,
908 size,
909 dma_buf: descriptor,
910 });
911
912 match virtio_iommu_request(&iommu_client.tube.lock(), &request) {
913 Ok(VirtioIOMMUResponse::VfioResponse(VirtioIOMMUVfioResult::Ok)) => (),
914 resp => {
915 let error = anyhow::anyhow!(
916 "Unexpected virtio-iommu message response when registering memory: \
917 {:?}", resp);
918 if let Err(e) = vm.remove_memory_region(slot) {
919 warn!("failed to remove memory region: {:?}", e);
922 }
923 return VmMemoryResponse::Err(error.into());
924 }
925 };
926
927 iommu_client.registered_memory.insert(region_id);
928 }
929
930 region_state
931 .registered_memory
932 .insert(region_id, RegisteredMemory::DynamicMapping { slot });
933 VmMemoryResponse::RegisterMemory { region_id, slot }
934 }
935 #[cfg(any(target_os = "android", target_os = "linux"))]
936 MmapAndRegisterMemory {
937 shm,
938 dest,
939 num_file_mappings,
940 } => {
941 let callback = || {
944 let mem = match MemoryMappingBuilder::new(shm.size() as usize)
945 .from_shared_memory(&shm)
946 .build()
947 .context("failed to build MemoryMapping from shared memory")
948 {
949 Ok(mem) => mem,
950 Err(e) => return Err(VmMemoryResponse::Err(e.into())),
951 };
952 let mut mmap_arena = MemoryMappingArena::from(mem);
953
954 let mut file_mappings = Vec::with_capacity(num_file_mappings);
957 let mut read = 0;
958 while read < num_file_mappings {
959 let len = std::cmp::min(num_file_mappings - read, base::unix::SCM_MAX_FD);
960 let mps: Vec<VmMemoryFileMapping> = match tube
961 .recv_with_max_fds(len)
962 .with_context(|| format!("get {num_file_mappings} FDs to be mapped"))
963 {
964 Ok(m) => m,
965 Err(e) => return Err(VmMemoryResponse::Err(e.into())),
966 };
967 file_mappings.extend(mps.into_iter());
968 read += len;
969 }
970
971 for VmMemoryFileMapping {
972 mem_offset,
973 length,
974 file,
975 file_offset,
976 } in file_mappings
977 {
978 if let Err(e) = mmap_arena
979 .add_fd_mapping(
980 mem_offset,
981 length,
982 &file,
983 file_offset,
984 Protection::read(),
985 )
986 .context(
987 "failed to add fd mapping when handling mmap and register memory",
988 )
989 {
990 return Err(VmMemoryResponse::Err(e.into()));
991 }
992 }
993 Ok(mmap_arena)
994 };
995 let mmap_arena = match call_with_extended_max_files(callback)
996 .context("failed to set max count of file descriptors")
997 {
998 Ok(Ok(m)) => m,
999 Ok(Err(e)) => {
1000 return e;
1001 }
1002 Err(e) => {
1003 error!("{e:?}");
1004 return VmMemoryResponse::Err(e.into());
1005 }
1006 };
1007
1008 let size = shm.size();
1009 let guest_addr = match dest.allocate(sys_allocator, size).context(
1010 "VM memory destination allocation fails when handling mmap and register memory",
1011 ) {
1012 Ok(addr) => addr,
1013 Err(e) => return VmMemoryResponse::Err(e.into()),
1014 };
1015
1016 let slot = match vm
1017 .add_memory_region(
1018 guest_addr,
1019 Box::new(mmap_arena),
1020 true,
1021 false,
1022 MemCacheType::CacheCoherent,
1023 )
1024 .context("failed to add memory region when handling mmap and register memory")
1025 {
1026 Ok(slot) => slot,
1027 Err(e) => return VmMemoryResponse::Err(e.into()),
1028 };
1029
1030 let region_id = VmMemoryRegionId(guest_addr);
1031
1032 region_state
1033 .registered_memory
1034 .insert(region_id, RegisteredMemory::DynamicMapping { slot });
1035
1036 VmMemoryResponse::RegisterMemory { region_id, slot }
1037 }
1038 UnregisterMemory(id) => match region_state.registered_memory.remove(&id) {
1039 Some(RegisteredMemory::DynamicMapping { slot }) => match vm
1040 .remove_memory_region(slot)
1041 .context(
1042 "failed to remove memory region when unregistering dynamic mapping memory",
1043 ) {
1044 Ok(_) => {
1045 if let Some(iommu_client) = iommu_client {
1046 if iommu_client.registered_memory.remove(&id) {
1047 let request = VirtioIOMMURequest::VfioCommand(
1048 VirtioIOMMUVfioCommand::VfioDmabufUnmap(id),
1049 );
1050
1051 match virtio_iommu_request(&iommu_client.tube.lock(), &request) {
1052 Ok(VirtioIOMMUResponse::VfioResponse(
1053 VirtioIOMMUVfioResult::Ok,
1054 )) => VmMemoryResponse::Ok,
1055 resp => {
1056 let error = anyhow::anyhow!(
1057 "Unexpected virtio-iommu message response when \
1058 unregistering memory: {:?}",
1059 resp
1060 );
1061 VmMemoryResponse::Err(error.into())
1062 }
1063 }
1064 } else {
1065 VmMemoryResponse::Ok
1066 }
1067 } else {
1068 VmMemoryResponse::Ok
1069 }
1070 }
1071 Err(e) => VmMemoryResponse::Err(e.into()),
1072 },
1073 Some(RegisteredMemory::FixedMapping { slot, offset, size }) => {
1074 match vm.remove_mapping(slot, offset, size).context(
1075 "failed to remove memory mapping when unregistering fixed mapping memory",
1076 ) {
1077 Ok(()) => VmMemoryResponse::Ok,
1078 Err(e) => VmMemoryResponse::Err(e.into()),
1079 }
1080 }
1081 None => {
1082 let error =
1083 anyhow::anyhow!("can't find the memory region when unregistering memory");
1084 VmMemoryResponse::Err(error.into())
1085 }
1086 },
1087 DynamicallyFreeMemoryRanges { ranges } => {
1088 let mut r = VmMemoryResponse::Ok;
1089 for (guest_address, size) in ranges {
1090 match vm
1091 .handle_balloon_event(BalloonEvent::Inflate(MemRegion {
1092 guest_address,
1093 size,
1094 }))
1095 .context(
1096 "failed to handle the inflate balloon event when freeing memory ranges \
1097 dynamically",
1098 ) {
1099 Ok(_) => {}
1100 Err(e) => {
1101 error!("{:?}", e);
1102 r = VmMemoryResponse::Err(e.into());
1103 break;
1104 }
1105 }
1106 }
1107 r
1108 }
1109 DynamicallyReclaimMemoryRanges { ranges } => {
1110 let mut r = VmMemoryResponse::Ok;
1111 for (guest_address, size) in ranges {
1112 match vm
1113 .handle_balloon_event(BalloonEvent::Deflate(MemRegion {
1114 guest_address,
1115 size,
1116 }))
1117 .context(
1118 "failed to handle the deflate balloon event when reclaiming memory \
1119 ranges dynamically",
1120 ) {
1121 Ok(_) => {}
1122 Err(e) => {
1123 error!("{:?}", e);
1124 r = VmMemoryResponse::Err(e.into());
1125 break;
1126 }
1127 }
1128 }
1129 r
1130 }
1131 BalloonTargetReached { size } => {
1132 match vm
1133 .handle_balloon_event(BalloonEvent::BalloonTargetReached(size))
1134 .context("failed to handle the target reached balloon event")
1135 {
1136 Ok(_) => VmMemoryResponse::Ok,
1137 Err(e) => VmMemoryResponse::Err(e.into()),
1138 }
1139 }
1140 IoEventRaw(request) => {
1141 let res = if request.register {
1142 vm.register_ioevent(
1143 request.event,
1144 IoEventAddress::Mmio(request.addr),
1145 request.datamatch,
1146 )
1147 .context("failed to register IO event")
1148 } else {
1149 vm.unregister_ioevent(
1150 request.event,
1151 IoEventAddress::Mmio(request.addr),
1152 request.datamatch,
1153 )
1154 .context("failed to unregister IO event")
1155 };
1156 match res {
1157 Ok(_) => VmMemoryResponse::Ok,
1158 Err(e) => VmMemoryResponse::Err(e.into()),
1159 }
1160 }
1161 }
1162 }
1163}
1164
1165#[derive(Serialize, Deserialize, Debug, PartialOrd, PartialEq, Eq, Ord, Clone, Copy)]
1166pub struct VmMemoryRegionId(pub GuestAddress);
1169
1170#[derive(Serialize, Deserialize, Debug)]
1171pub enum VmMemoryResponse {
1172 RegisterMemory {
1174 region_id: VmMemoryRegionId,
1175 slot: u32,
1176 },
1177 Ok,
1178 Err(VmMemoryResponseError),
1179}
1180
1181impl<T> From<Result<T>> for VmMemoryResponse {
1182 fn from(r: Result<T>) -> Self {
1183 match r {
1184 Ok(_) => VmMemoryResponse::Ok,
1185 Err(e) => VmMemoryResponse::Err(anyhow::Error::new(e).into()),
1186 }
1187 }
1188}
1189
1190#[derive(Debug, thiserror::Error)]
1191#[error("Vm memory response error: {0}")]
1192pub struct VmMemoryResponseError(#[from] pub anyhow::Error);
1193
1194impl TryFrom<FlatVmMemoryResponseError> for VmMemoryResponseError {
1195 type Error = anyhow::Error;
1196 fn try_from(value: FlatVmMemoryResponseError) -> StdResult<Self, Self::Error> {
1197 let inner = value
1198 .0
1199 .into_iter()
1200 .fold(
1201 None,
1202 |error: Option<anyhow::Error>, current_context| match error {
1203 Some(error) => Some(error.context(current_context)),
1204 None => Some(anyhow::Error::msg(current_context)),
1205 },
1206 )
1207 .context("should carry at least one error")?;
1208 Ok(Self(inner))
1209 }
1210}
1211
1212impl Serialize for VmMemoryResponseError {
1213 fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error>
1214 where
1215 S: serde::Serializer,
1216 {
1217 let flat: FlatVmMemoryResponseError = self.into();
1218 flat.serialize(serializer)
1219 }
1220}
1221
1222impl<'de> Deserialize<'de> for VmMemoryResponseError {
1223 fn deserialize<D>(deserializer: D) -> StdResult<Self, D::Error>
1224 where
1225 D: serde::Deserializer<'de>,
1226 {
1227 let flat = FlatVmMemoryResponseError::deserialize(deserializer)?;
1228 flat.try_into()
1229 .map_err(|e: anyhow::Error| D::Error::custom(e.to_string()))
1230 }
1231}
1232
1233#[derive(Debug, Serialize, Deserialize)]
1234struct FlatVmMemoryResponseError(Vec<String>);
1235
1236impl From<&VmMemoryResponseError> for FlatVmMemoryResponseError {
1237 fn from(value: &VmMemoryResponseError) -> Self {
1238 let contexts = value
1239 .0
1240 .chain()
1241 .map(ToString::to_string)
1242 .rev()
1243 .collect::<Vec<_>>();
1244 Self(contexts)
1245 }
1246}
1247
1248#[derive(Serialize, Deserialize, Debug)]
1249pub enum VmIrqRequest {
1250 AllocateOneMsi {
1252 irqfd: Event,
1253 device_id: DeviceId,
1254 queue_id: usize,
1255 device_name: String,
1256 },
1257 AllocateOneMsiAtGsi {
1262 irqfd: Event,
1263 gsi: u32,
1264 device_id: DeviceId,
1265 queue_id: usize,
1266 device_name: String,
1267 },
1268 AddMsiRoute {
1270 gsi: u32,
1271 msi_address: u64,
1272 msi_data: u32,
1273 #[cfg(target_arch = "aarch64")]
1274 pci_address: resources::PciAddress,
1275 },
1276 ReleaseOneIrq {
1278 gsi: u32,
1279 irqfd: Event,
1280 },
1281}
1282
1283pub enum IrqSetup<'a> {
1287 Event(u32, &'a Event, DeviceId, usize, String),
1288 Route(IrqRoute),
1289 UnRegister(u32, &'a Event),
1290}
1291
1292impl VmIrqRequest {
1293 pub fn execute<F>(&self, set_up_irq: F, sys_allocator: &mut SystemAllocator) -> VmIrqResponse
1302 where
1303 F: FnOnce(IrqSetup) -> Result<()>,
1304 {
1305 use self::VmIrqRequest::*;
1306 match *self {
1307 AllocateOneMsi {
1308 ref irqfd,
1309 device_id,
1310 queue_id,
1311 ref device_name,
1312 } => {
1313 if let Some(irq_num) = sys_allocator.allocate_irq() {
1314 match set_up_irq(IrqSetup::Event(
1315 irq_num,
1316 irqfd,
1317 device_id,
1318 queue_id,
1319 device_name.clone(),
1320 )) {
1321 Ok(_) => VmIrqResponse::AllocateOneMsi { gsi: irq_num },
1322 Err(e) => VmIrqResponse::Err(e),
1323 }
1324 } else {
1325 VmIrqResponse::Err(SysError::new(EINVAL))
1326 }
1327 }
1328 AllocateOneMsiAtGsi {
1329 ref irqfd,
1330 gsi,
1331 device_id,
1332 queue_id,
1333 ref device_name,
1334 } => {
1335 match set_up_irq(IrqSetup::Event(
1336 gsi,
1337 irqfd,
1338 device_id,
1339 queue_id,
1340 device_name.clone(),
1341 )) {
1342 Ok(_) => VmIrqResponse::Ok,
1343 Err(e) => VmIrqResponse::Err(e),
1344 }
1345 }
1346 AddMsiRoute {
1347 gsi,
1348 msi_address,
1349 msi_data,
1350 #[cfg(target_arch = "aarch64")]
1351 pci_address,
1352 } => {
1353 let route = IrqRoute {
1354 gsi,
1355 source: IrqSource::Msi {
1356 address: msi_address,
1357 data: msi_data,
1358 #[cfg(target_arch = "aarch64")]
1359 pci_address,
1360 },
1361 };
1362 match set_up_irq(IrqSetup::Route(route)) {
1363 Ok(_) => VmIrqResponse::Ok,
1364 Err(e) => VmIrqResponse::Err(e),
1365 }
1366 }
1367 ReleaseOneIrq { gsi, ref irqfd } => {
1368 let _ = set_up_irq(IrqSetup::UnRegister(gsi, irqfd));
1369 sys_allocator.release_irq(gsi);
1370 VmIrqResponse::Ok
1371 }
1372 }
1373 }
1374}
1375
1376#[derive(Serialize, Deserialize, Debug)]
1377pub enum VmIrqResponse {
1378 AllocateOneMsi { gsi: u32 },
1379 Ok,
1380 Err(SysError),
1381}
1382
1383#[derive(Serialize, Deserialize, Debug, Clone)]
1384pub enum DevicesState {
1385 Sleep,
1386 Wake,
1387}
1388
1389#[derive(Serialize, Deserialize, Debug, Clone)]
1390pub enum BatControlResult {
1391 Ok,
1392 NoBatDevice,
1393 NoSuchHealth,
1394 NoSuchProperty,
1395 NoSuchStatus,
1396 NoSuchBatType,
1397 StringParseIntErr,
1398 StringParseBoolErr,
1399}
1400
1401impl Display for BatControlResult {
1402 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1403 use self::BatControlResult::*;
1404
1405 match self {
1406 Ok => write!(f, "Setting battery property successfully"),
1407 NoBatDevice => write!(f, "No battery device created"),
1408 NoSuchHealth => write!(f, "Invalid Battery health setting. Only support: unknown/good/overheat/dead/overvoltage/unexpectedfailure/cold/watchdogtimerexpire/safetytimerexpire/overcurrent"),
1409 NoSuchProperty => write!(f, "Battery doesn't have such property. Only support: status/health/present/capacity/aconline"),
1410 NoSuchStatus => write!(f, "Invalid Battery status setting. Only support: unknown/charging/discharging/notcharging/full"),
1411 NoSuchBatType => write!(f, "Invalid Battery type setting. Only support: goldfish"),
1412 StringParseIntErr => write!(f, "Battery property target ParseInt error"),
1413 StringParseBoolErr => write!(f, "Battery property target ParseBool error"),
1414 }
1415 }
1416}
1417
1418#[derive(Serialize, Deserialize, Copy, Clone, Debug, Default, PartialEq, Eq)]
1419#[serde(rename_all = "kebab-case")]
1420pub enum BatteryType {
1421 #[default]
1422 Goldfish,
1423}
1424
1425impl FromStr for BatteryType {
1426 type Err = BatControlResult;
1427
1428 fn from_str(s: &str) -> StdResult<Self, Self::Err> {
1429 match s {
1430 "goldfish" => Ok(BatteryType::Goldfish),
1431 _ => Err(BatControlResult::NoSuchBatType),
1432 }
1433 }
1434}
1435
1436#[derive(Serialize, Deserialize, Debug)]
1437pub enum BatProperty {
1438 Status,
1439 Health,
1440 Present,
1441 Capacity,
1442 ACOnline,
1443 SetFakeBatConfig,
1444 CancelFakeBatConfig,
1445}
1446
1447impl FromStr for BatProperty {
1448 type Err = BatControlResult;
1449
1450 fn from_str(s: &str) -> StdResult<Self, Self::Err> {
1451 match s {
1452 "status" => Ok(BatProperty::Status),
1453 "health" => Ok(BatProperty::Health),
1454 "present" => Ok(BatProperty::Present),
1455 "capacity" => Ok(BatProperty::Capacity),
1456 "aconline" => Ok(BatProperty::ACOnline),
1457 "set_fake_bat_config" => Ok(BatProperty::SetFakeBatConfig),
1458 "cancel_fake_bat_config" => Ok(BatProperty::CancelFakeBatConfig),
1459 _ => Err(BatControlResult::NoSuchProperty),
1460 }
1461 }
1462}
1463
1464impl Display for BatProperty {
1465 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1466 match *self {
1467 BatProperty::Status => write!(f, "status"),
1468 BatProperty::Health => write!(f, "health"),
1469 BatProperty::Present => write!(f, "present"),
1470 BatProperty::Capacity => write!(f, "capacity"),
1471 BatProperty::ACOnline => write!(f, "aconline"),
1472 BatProperty::SetFakeBatConfig => write!(f, "set_fake_bat_config"),
1473 BatProperty::CancelFakeBatConfig => write!(f, "cancel_fake_bat_config"),
1474 }
1475 }
1476}
1477
1478#[derive(Serialize, Deserialize, Debug)]
1479pub enum BatStatus {
1480 Unknown,
1481 Charging,
1482 DisCharging,
1483 NotCharging,
1484 Full,
1485}
1486
1487impl BatStatus {
1488 pub fn new(status: String) -> std::result::Result<Self, BatControlResult> {
1489 match status.as_str() {
1490 "unknown" => Ok(BatStatus::Unknown),
1491 "charging" => Ok(BatStatus::Charging),
1492 "discharging" => Ok(BatStatus::DisCharging),
1493 "notcharging" => Ok(BatStatus::NotCharging),
1494 "full" => Ok(BatStatus::Full),
1495 _ => Err(BatControlResult::NoSuchStatus),
1496 }
1497 }
1498}
1499
1500impl FromStr for BatStatus {
1501 type Err = BatControlResult;
1502
1503 fn from_str(s: &str) -> StdResult<Self, Self::Err> {
1504 match s {
1505 "unknown" => Ok(BatStatus::Unknown),
1506 "charging" => Ok(BatStatus::Charging),
1507 "discharging" => Ok(BatStatus::DisCharging),
1508 "notcharging" => Ok(BatStatus::NotCharging),
1509 "full" => Ok(BatStatus::Full),
1510 _ => Err(BatControlResult::NoSuchStatus),
1511 }
1512 }
1513}
1514
1515impl From<BatStatus> for u32 {
1516 fn from(status: BatStatus) -> Self {
1517 status as u32
1518 }
1519}
1520
1521#[derive(Serialize, Deserialize, Debug)]
1522pub enum BatHealth {
1523 Unknown,
1524 Good,
1525 Overheat,
1526 Dead,
1527 OverVoltage,
1528 UnexpectedFailure,
1529 Cold,
1530 WatchdogTimerExpire,
1531 SafetyTimerExpire,
1532 OverCurrent,
1533}
1534
1535impl FromStr for BatHealth {
1536 type Err = BatControlResult;
1537
1538 fn from_str(s: &str) -> StdResult<Self, Self::Err> {
1539 match s {
1540 "unknown" => Ok(BatHealth::Unknown),
1541 "good" => Ok(BatHealth::Good),
1542 "overheat" => Ok(BatHealth::Overheat),
1543 "dead" => Ok(BatHealth::Dead),
1544 "overvoltage" => Ok(BatHealth::OverVoltage),
1545 "unexpectedfailure" => Ok(BatHealth::UnexpectedFailure),
1546 "cold" => Ok(BatHealth::Cold),
1547 "watchdogtimerexpire" => Ok(BatHealth::WatchdogTimerExpire),
1548 "safetytimerexpire" => Ok(BatHealth::SafetyTimerExpire),
1549 "overcurrent" => Ok(BatHealth::OverCurrent),
1550 _ => Err(BatControlResult::NoSuchHealth),
1551 }
1552 }
1553}
1554
1555impl From<BatHealth> for u32 {
1556 fn from(status: BatHealth) -> Self {
1557 status as u32
1558 }
1559}
1560
1561#[derive(Serialize, Deserialize, Debug)]
1562pub enum BatControlCommand {
1563 SetStatus(BatStatus),
1564 SetHealth(BatHealth),
1565 SetPresent(u32),
1566 SetCapacity(u32),
1567 SetACOnline(u32),
1568 SetFakeBatConfig(u32),
1569 CancelFakeConfig,
1570}
1571
1572impl BatControlCommand {
1573 pub fn new(property: String, target: String) -> std::result::Result<Self, BatControlResult> {
1574 let cmd = property.parse::<BatProperty>()?;
1575 match cmd {
1576 BatProperty::Status => Ok(BatControlCommand::SetStatus(target.parse::<BatStatus>()?)),
1577 BatProperty::Health => Ok(BatControlCommand::SetHealth(target.parse::<BatHealth>()?)),
1578 BatProperty::Present => Ok(BatControlCommand::SetPresent(
1579 target
1580 .parse::<u32>()
1581 .map_err(|_| BatControlResult::StringParseIntErr)?,
1582 )),
1583 BatProperty::Capacity => Ok(BatControlCommand::SetCapacity(
1584 target
1585 .parse::<u32>()
1586 .map_err(|_| BatControlResult::StringParseIntErr)?,
1587 )),
1588 BatProperty::ACOnline => Ok(BatControlCommand::SetACOnline(
1589 target
1590 .parse::<u32>()
1591 .map_err(|_| BatControlResult::StringParseIntErr)?,
1592 )),
1593 BatProperty::SetFakeBatConfig => Ok(BatControlCommand::SetFakeBatConfig(
1594 target
1595 .parse::<u32>()
1596 .map_err(|_| BatControlResult::StringParseIntErr)?,
1597 )),
1598 BatProperty::CancelFakeBatConfig => Ok(BatControlCommand::CancelFakeConfig),
1599 }
1600 }
1601}
1602
1603pub struct BatControl {
1605 pub type_: BatteryType,
1606 pub control_tube: Tube,
1607}
1608
1609#[derive(Serialize, Deserialize, Debug)]
1611pub enum SndControlCommand {
1612 MuteAll(bool),
1613}
1614
1615#[derive(Serialize, Deserialize, Debug, Clone)]
1617pub enum HotPlugDeviceType {
1618 UpstreamPort,
1619 DownstreamPort,
1620 EndPoint,
1621}
1622
1623#[derive(Serialize, Deserialize, Debug, Clone)]
1625pub struct HotPlugDeviceInfo {
1626 pub device_type: HotPlugDeviceType,
1627 pub path: PathBuf,
1628 pub hp_interrupt: bool,
1629}
1630
1631#[derive(Serialize, Deserialize, Debug)]
1633pub enum DeviceControlRequest {
1634 Gpe { gpe: u32, clear_evt: Option<Event> },
1638 PciPme(u16),
1640 HotPlugVfioCommand {
1642 device: HotPlugDeviceInfo,
1643 add: bool,
1644 },
1645}
1646
1647#[derive(Serialize, Deserialize, Debug)]
1649#[must_use]
1650pub enum DeviceControlResponse {
1651 Ok,
1652 Err(SysError),
1653}
1654
1655impl Display for DeviceControlResponse {
1656 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1657 match self {
1658 DeviceControlResponse::Ok => write!(f, "ok"),
1659 DeviceControlResponse::Err(e) => write!(f, "error: {e}"),
1660 }
1661 }
1662}
1663
1664impl From<DeviceControlResponse> for VmResponse {
1665 fn from(response: DeviceControlResponse) -> Self {
1666 match response {
1667 DeviceControlResponse::Ok => VmResponse::Ok,
1668 DeviceControlResponse::Err(e) => VmResponse::Err(e),
1669 }
1670 }
1671}
1672
1673impl DeviceControlRequest {
1674 pub fn execute(
1676 &self,
1677 pm: &mut Option<Arc<Mutex<dyn PmResource + Send>>>,
1678 ) -> DeviceControlResponse {
1679 match self {
1680 DeviceControlRequest::Gpe { gpe, clear_evt } => {
1681 if let Some(pm) = pm.as_ref() {
1682 match clear_evt.as_ref().map(|e| e.try_clone()).transpose() {
1683 Ok(clear_evt) => {
1684 pm.lock().gpe_evt(*gpe, clear_evt);
1685 DeviceControlResponse::Ok
1686 }
1687 Err(err) => {
1688 error!("Error cloning clear_evt: {:?}", err);
1689 DeviceControlResponse::Err(SysError::new(EIO))
1690 }
1691 }
1692 } else {
1693 error!("{:#?} not supported", *self);
1694 DeviceControlResponse::Err(SysError::new(ENOTSUP))
1695 }
1696 }
1697 DeviceControlRequest::PciPme(requester_id) => {
1698 if let Some(pm) = pm.as_ref() {
1699 pm.lock().pme_evt(*requester_id);
1700 DeviceControlResponse::Ok
1701 } else {
1702 error!("{:#?} not supported", *self);
1703 DeviceControlResponse::Err(SysError::new(ENOTSUP))
1704 }
1705 }
1706 DeviceControlRequest::HotPlugVfioCommand { .. } => {
1707 panic!("HotPlugVfioCommand should be handled by the platform run loop");
1708 }
1709 }
1710 }
1711}
1712
1713#[derive(Serialize, Deserialize, Debug, Clone)]
1715pub enum PvClockCommand {
1716 Suspend,
1717 Resume,
1718}
1719
1720#[derive(Serialize, Deserialize, Debug)]
1722pub enum PvClockCommandResponse {
1723 Ok,
1724 Resumed { total_suspended_ticks: u64 },
1725 DeviceInactive,
1726 Err(SysError),
1727}
1728
1729#[derive(Serialize, Deserialize, Debug)]
1731pub enum SwapCommand {
1732 Enable,
1733 Trim,
1734 SwapOut,
1735 Disable { slow_file_cleanup: bool },
1736 Status,
1737}
1738
1739#[derive(Serialize, Deserialize, Debug)]
1744pub enum VmRequest {
1745 Exit,
1747 Powerbtn,
1749 Sleepbtn,
1751 Rtc { clear_evt: Event },
1754 SuspendVcpus,
1756 Swap(SwapCommand),
1758 ResumeVcpus,
1760 DeviceControl(DeviceControlRequest),
1762 MakeRT,
1764 #[cfg(feature = "balloon")]
1766 BalloonCommand(BalloonControlCommand),
1767 DiskCommand {
1770 disk_index: usize,
1771 command: DiskControlCommand,
1772 },
1773 UsbCommand(UsbControlCommand),
1775 GpuCommand(GpuControlCommand),
1777 BatCommand(BatteryType, BatControlCommand),
1779 #[cfg(feature = "audio")]
1781 SndCommand(SndControlCommand),
1782 #[cfg(feature = "pci-hotplug")]
1784 HotPlugNetCommand(NetControlCommand),
1785 Snapshot(SnapshotCommand),
1787 RegisterListener {
1789 socket_addr: String,
1790 event: RegisteredEvent,
1791 },
1792 UnregisterListener {
1794 socket_addr: String,
1795 event: RegisteredEvent,
1796 },
1797 Unregister { socket_addr: String },
1799 SuspendVm,
1801 ResumeVm,
1803 VcpuPidTid,
1805 Throttle(usize, u32),
1807 GetVmDescriptor,
1809 RegisterMemory {
1811 fd: SafeDescriptor,
1812 offset: u64,
1813 range_start: u64,
1814 range_end: u64,
1815 cache_coherent: bool,
1816 },
1817 UnregisterMemory { region_id: u64 },
1819}
1820
1821#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone, Copy)]
1824pub enum RegisteredEvent {
1825 VirtioBalloonWsReport,
1826 VirtioBalloonResize,
1827 VirtioBalloonOOMDeflation,
1828}
1829
1830#[derive(Serialize, Deserialize, Debug)]
1831pub enum RegisteredEventWithData {
1832 VirtioBalloonWsReport {
1833 ws_buckets: Vec<balloon_control::WSBucket>,
1834 balloon_actual: u64,
1835 },
1836 VirtioBalloonResize,
1837 VirtioBalloonOOMDeflation,
1838}
1839
1840impl RegisteredEventWithData {
1841 pub fn into_event(&self) -> RegisteredEvent {
1842 match self {
1843 Self::VirtioBalloonWsReport { .. } => RegisteredEvent::VirtioBalloonWsReport,
1844 Self::VirtioBalloonResize => RegisteredEvent::VirtioBalloonResize,
1845 Self::VirtioBalloonOOMDeflation => RegisteredEvent::VirtioBalloonOOMDeflation,
1846 }
1847 }
1848
1849 #[cfg(feature = "registered_events")]
1850 pub fn into_proto(&self) -> registered_events::RegisteredEvent {
1851 match self {
1852 Self::VirtioBalloonWsReport {
1853 ws_buckets,
1854 balloon_actual,
1855 } => {
1856 let mut report = registered_events::VirtioBalloonWsReport {
1857 balloon_actual: *balloon_actual,
1858 ..registered_events::VirtioBalloonWsReport::new()
1859 };
1860 for ws in ws_buckets {
1861 report.ws_buckets.push(registered_events::VirtioWsBucket {
1862 age: ws.age,
1863 file_bytes: ws.bytes[0],
1864 anon_bytes: ws.bytes[1],
1865 ..registered_events::VirtioWsBucket::new()
1866 });
1867 }
1868 let mut event = registered_events::RegisteredEvent::new();
1869 event.set_ws_report(report);
1870 event
1871 }
1872 Self::VirtioBalloonResize => {
1873 let mut event = registered_events::RegisteredEvent::new();
1874 event.set_resize(registered_events::VirtioBalloonResize::new());
1875 event
1876 }
1877 Self::VirtioBalloonOOMDeflation => {
1878 let mut event = registered_events::RegisteredEvent::new();
1879 event.set_oom_deflation(registered_events::VirtioBalloonOOMDeflation::new());
1880 event
1881 }
1882 }
1883 }
1884
1885 pub fn from_ws(ws: &balloon_control::BalloonWS, balloon_actual: u64) -> Self {
1886 RegisteredEventWithData::VirtioBalloonWsReport {
1887 ws_buckets: ws.ws.clone(),
1888 balloon_actual,
1889 }
1890 }
1891}
1892
1893pub fn handle_disk_command(command: &DiskControlCommand, disk_host_tube: &Tube) -> VmResponse {
1894 if let Err(e) = disk_host_tube.send(command) {
1896 error!("disk socket send failed: {}", e);
1897 return VmResponse::Err(SysError::new(EINVAL));
1898 }
1899
1900 match disk_host_tube.recv() {
1902 Ok(DiskControlResult::Ok) => VmResponse::Ok,
1903 Ok(DiskControlResult::Err(e)) => VmResponse::Err(e),
1904 Err(e) => {
1905 error!("disk socket recv failed: {}", e);
1906 VmResponse::Err(SysError::new(EINVAL))
1907 }
1908 }
1909}
1910
1911fn map_descriptor(
1913 descriptor: &dyn AsRawDescriptor,
1914 offset: u64,
1915 size: u64,
1916 prot: Protection,
1917) -> Result<Box<dyn MappedRegion>> {
1918 let size: usize = size.try_into().map_err(|_e| SysError::new(ERANGE))?;
1919 match MemoryMappingBuilder::new(size)
1920 .from_descriptor(descriptor)
1921 .offset(offset)
1922 .protection(prot)
1923 .build()
1924 {
1925 Ok(mmap) => Ok(Box::new(mmap)),
1926 Err(MmapError::SystemCallFailed(e)) => Err(e),
1927 _ => Err(SysError::new(EINVAL)),
1928 }
1929}
1930
1931fn get_vcpu_state(kick_vcpus: impl Fn(VcpuControl), vcpu_num: usize) -> anyhow::Result<VmRunMode> {
1936 let (send_chan, recv_chan) = mpsc::channel();
1937 kick_vcpus(VcpuControl::GetStates(send_chan));
1938 if vcpu_num == 0 {
1939 bail!("vcpu_num is zero");
1940 }
1941 let mut current_mode_vec: Vec<VmRunMode> = Vec::new();
1942 for _ in 0..vcpu_num {
1943 match recv_chan.recv() {
1944 Ok(state) => current_mode_vec.push(state),
1945 Err(e) => {
1946 bail!("Failed to get vCPU state: {}", e);
1947 }
1948 };
1949 }
1950 let first_state = current_mode_vec[0];
1951 if first_state == VmRunMode::Exiting {
1952 panic!("Attempt to snapshot while exiting.");
1953 }
1954 if current_mode_vec.iter().any(|x| *x != first_state) {
1955 bail!("Unknown VM state: vCPUs hold different states.");
1957 }
1958 Ok(first_state)
1959}
1960
1961pub struct VcpuSuspendGuard<'a> {
1965 saved_run_mode: VmRunMode,
1966 kick_vcpus: &'a dyn Fn(VcpuControl),
1967}
1968
1969impl<'a> VcpuSuspendGuard<'a> {
1970 pub fn new(kick_vcpus: &'a impl Fn(VcpuControl), vcpu_num: usize) -> anyhow::Result<Self> {
1980 let saved_run_mode = get_vcpu_state(kick_vcpus, vcpu_num)?;
1982 match saved_run_mode {
1983 VmRunMode::Running => {
1984 kick_vcpus(VcpuControl::RunState(VmRunMode::Suspending));
1985 let current_mode = get_vcpu_state(kick_vcpus, vcpu_num)?;
1989 if current_mode != VmRunMode::Suspending {
1990 kick_vcpus(VcpuControl::RunState(saved_run_mode));
1991 bail!("vCPUs failed to all suspend. Kicking back all vCPUs to their previous state: {saved_run_mode}");
1992 }
1993 }
1994 VmRunMode::Suspending => {
1995 }
1997 other => {
1998 bail!("vcpus are not in running/suspending state, but {}", other);
1999 }
2000 };
2001 Ok(Self {
2002 saved_run_mode,
2003 kick_vcpus,
2004 })
2005 }
2006}
2007
2008impl Drop for VcpuSuspendGuard<'_> {
2009 fn drop(&mut self) {
2010 if self.saved_run_mode != VmRunMode::Suspending {
2011 (self.kick_vcpus)(VcpuControl::RunState(self.saved_run_mode));
2012 }
2013 }
2014}
2015
2016pub struct DeviceSleepGuard<'a> {
2020 device_control_tube: &'a Tube,
2021 devices_state: DevicesState,
2022}
2023
2024impl<'a> DeviceSleepGuard<'a> {
2025 fn new(device_control_tube: &'a Tube) -> anyhow::Result<Self> {
2026 device_control_tube
2027 .send(&DeviceControlCommand::GetDevicesState)
2028 .context("send command to devices control socket")?;
2029 let devices_state = match device_control_tube
2030 .recv()
2031 .context("receive from devices control socket")?
2032 {
2033 VmResponse::DevicesState(state) => state,
2034 resp => bail!("failed to get devices state. Unexpected behavior: {}", resp),
2035 };
2036 if let DevicesState::Wake = devices_state {
2037 device_control_tube
2038 .send(&DeviceControlCommand::SleepDevices)
2039 .context("send command to devices control socket")?;
2040 match device_control_tube
2041 .recv()
2042 .context("receive from devices control socket")?
2043 {
2044 VmResponse::Ok => (),
2045 resp => bail!("device sleep failed: {}", resp),
2046 }
2047 }
2048 Ok(Self {
2049 device_control_tube,
2050 devices_state,
2051 })
2052 }
2053}
2054
2055impl Drop for DeviceSleepGuard<'_> {
2056 fn drop(&mut self) {
2057 if let DevicesState::Wake = self.devices_state {
2058 if let Err(e) = self
2059 .device_control_tube
2060 .send(&DeviceControlCommand::WakeDevices)
2061 {
2062 panic!("failed to request device wake after snapshot: {e}");
2063 }
2064 match self.device_control_tube.recv() {
2065 Ok(VmResponse::Ok) => (),
2066 Ok(resp) => panic!("unexpected response to device wake request: {resp}"),
2067 Err(e) => panic!("failed to get reply for device wake request: {e}"),
2068 }
2069 }
2070 }
2071}
2072
2073impl VmRequest {
2074 #[allow(unused_variables)]
2088 pub fn execute(
2089 &self,
2090 vm: &dyn Vm,
2091 disk_host_tubes: &[Tube],
2092 snd_host_tubes: &[Tube],
2093 pm: &mut Option<Arc<Mutex<dyn PmResource + Send>>>,
2094 gpu_control_tube: Option<&Tube>,
2095 usb_control_tube: Option<&Tube>,
2096 bat_control: &mut Option<BatControl>,
2097 kick_vcpus: impl Fn(VcpuControl),
2098 #[cfg(any(target_os = "android", target_os = "linux"))] kick_vcpu: impl Fn(usize, VcpuControl),
2099 force_s2idle: bool,
2100 #[cfg(feature = "swap")] swap_controller: Option<&swap::SwapController>,
2101 device_control_tube: &Tube,
2102 vcpu_size: usize,
2103 irq_handler_control: &Tube,
2104 snapshot_irqchip: impl Fn() -> anyhow::Result<AnySnapshot>,
2105 suspended_pvclock_state: &mut Option<hypervisor::ClockState>,
2106 ) -> VmResponse {
2107 match self {
2108 VmRequest::Exit => {
2109 panic!("VmRequest::Exit should be handled by the platform run loop");
2110 }
2111 VmRequest::Powerbtn => {
2112 if let Some(pm) = pm {
2113 pm.lock().pwrbtn_evt();
2114 VmResponse::Ok
2115 } else {
2116 error!("{:#?} not supported", *self);
2117 VmResponse::Err(SysError::new(ENOTSUP))
2118 }
2119 }
2120 VmRequest::Sleepbtn => {
2121 if let Some(pm) = pm {
2122 pm.lock().slpbtn_evt();
2123 VmResponse::Ok
2124 } else {
2125 error!("{:#?} not supported", *self);
2126 VmResponse::Err(SysError::new(ENOTSUP))
2127 }
2128 }
2129 VmRequest::Rtc { clear_evt } => {
2130 if let Some(pm) = pm.as_ref() {
2131 match clear_evt.try_clone() {
2132 Ok(clear_evt) => {
2133 pm.lock().rtc_evt(clear_evt);
2135 VmResponse::Ok
2136 }
2137 Err(err) => {
2138 error!("Error cloning clear_evt: {:?}", err);
2139 VmResponse::Err(SysError::new(EIO))
2140 }
2141 }
2142 } else {
2143 error!("{:#?} not supported", *self);
2144 VmResponse::Err(SysError::new(ENOTSUP))
2145 }
2146 }
2147 VmRequest::SuspendVcpus => {
2148 if !force_s2idle {
2149 kick_vcpus(VcpuControl::RunState(VmRunMode::Suspending));
2150 let current_mode = match get_vcpu_state(kick_vcpus, vcpu_size) {
2151 Ok(state) => state,
2152 Err(e) => {
2153 error!("failed to get vcpu state: {e}");
2154 return VmResponse::Err(SysError::new(EIO));
2155 }
2156 };
2157 if current_mode != VmRunMode::Suspending {
2158 error!("vCPUs failed to all suspend.");
2159 return VmResponse::Err(SysError::new(EIO));
2160 }
2161 }
2162 VmResponse::Ok
2163 }
2164 VmRequest::ResumeVcpus => {
2165 if let Err(e) = device_control_tube.send(&DeviceControlCommand::GetDevicesState) {
2166 error!("failed to send GetDevicesState: {}", e);
2167 return VmResponse::Err(SysError::new(EIO));
2168 }
2169 let devices_state = match device_control_tube.recv() {
2170 Ok(VmResponse::DevicesState(state)) => state,
2171 Ok(resp) => {
2172 error!("failed to get devices state. Unexpected behavior: {}", resp);
2173 return VmResponse::Err(SysError::new(EINVAL));
2174 }
2175 Err(e) => {
2176 error!("failed to get devices state. Unexpected behavior: {}", e);
2177 return VmResponse::Err(SysError::new(EINVAL));
2178 }
2179 };
2180 if let DevicesState::Sleep = devices_state {
2181 error!("Trying to wake Vcpus while Devices are asleep. Did you mean to use `crosvm resume --full`?");
2182 return VmResponse::Err(SysError::new(EINVAL));
2183 }
2184
2185 if force_s2idle {
2186 if let Some(pm) = pm {
2189 pm.lock().pwrbtn_evt();
2190 } else {
2191 error!("triggering power btn during resume not supported");
2192 return VmResponse::Err(SysError::new(ENOTSUP));
2193 }
2194 }
2195
2196 kick_vcpus(VcpuControl::RunState(VmRunMode::Running));
2197 VmResponse::Ok
2198 }
2199 VmRequest::Swap(SwapCommand::Enable) => {
2200 #[cfg(feature = "swap")]
2201 if let Some(swap_controller) = swap_controller {
2202 let _vcpu_guard = match VcpuSuspendGuard::new(&kick_vcpus, vcpu_size) {
2206 Ok(guard) => guard,
2207 Err(e) => {
2208 error!("failed to suspend vcpus: {:?}", e);
2209 return VmResponse::Err(SysError::new(EINVAL));
2210 }
2211 };
2212 let _devices_guard = match swap_controller.suspend_devices() {
2215 Ok(guard) => guard,
2216 Err(e) => {
2217 error!("failed to suspend devices: {:?}", e);
2218 return VmResponse::Err(SysError::new(EINVAL));
2219 }
2220 };
2221
2222 return match swap_controller.enable() {
2223 Ok(()) => VmResponse::Ok,
2224 Err(e) => {
2225 error!("swap enable failed: {}", e);
2226 VmResponse::Err(SysError::new(EINVAL))
2227 }
2228 };
2229 }
2230 VmResponse::Err(SysError::new(ENOTSUP))
2231 }
2232 VmRequest::Swap(SwapCommand::Trim) => {
2233 #[cfg(feature = "swap")]
2234 if let Some(swap_controller) = swap_controller {
2235 return match swap_controller.trim() {
2236 Ok(()) => VmResponse::Ok,
2237 Err(e) => {
2238 error!("swap trim failed: {}", e);
2239 VmResponse::Err(SysError::new(EINVAL))
2240 }
2241 };
2242 }
2243 VmResponse::Err(SysError::new(ENOTSUP))
2244 }
2245 VmRequest::Swap(SwapCommand::SwapOut) => {
2246 #[cfg(feature = "swap")]
2247 if let Some(swap_controller) = swap_controller {
2248 return match swap_controller.swap_out() {
2249 Ok(()) => VmResponse::Ok,
2250 Err(e) => {
2251 error!("swap out failed: {}", e);
2252 VmResponse::Err(SysError::new(EINVAL))
2253 }
2254 };
2255 }
2256 VmResponse::Err(SysError::new(ENOTSUP))
2257 }
2258 VmRequest::Swap(SwapCommand::Disable {
2259 #[cfg(feature = "swap")]
2260 slow_file_cleanup,
2261 ..
2262 }) => {
2263 #[cfg(feature = "swap")]
2264 if let Some(swap_controller) = swap_controller {
2265 return match swap_controller.disable(*slow_file_cleanup) {
2266 Ok(()) => VmResponse::Ok,
2267 Err(e) => {
2268 error!("swap disable failed: {}", e);
2269 VmResponse::Err(SysError::new(EINVAL))
2270 }
2271 };
2272 }
2273 VmResponse::Err(SysError::new(ENOTSUP))
2274 }
2275 VmRequest::Swap(SwapCommand::Status) => {
2276 #[cfg(feature = "swap")]
2277 if let Some(swap_controller) = swap_controller {
2278 return match swap_controller.status() {
2279 Ok(status) => VmResponse::SwapStatus(status),
2280 Err(e) => {
2281 error!("swap status failed: {}", e);
2282 VmResponse::Err(SysError::new(EINVAL))
2283 }
2284 };
2285 }
2286 VmResponse::Err(SysError::new(ENOTSUP))
2287 }
2288 VmRequest::SuspendVm => {
2289 info!("Starting crosvm suspend");
2290 kick_vcpus(VcpuControl::RunState(VmRunMode::Suspending));
2291 let current_mode = match get_vcpu_state(kick_vcpus, vcpu_size) {
2292 Ok(state) => state,
2293 Err(e) => {
2294 error!("failed to get vcpu state: {e}");
2295 return VmResponse::Err(SysError::new(EIO));
2296 }
2297 };
2298 if current_mode != VmRunMode::Suspending {
2299 error!("vCPUs failed to all suspend.");
2300 return VmResponse::Err(SysError::new(EIO));
2301 }
2302 if vm.check_capability(VmCap::PvClock) {
2304 if suspended_pvclock_state.is_none() {
2305 *suspended_pvclock_state = Some(match vm.get_pvclock() {
2306 Ok(x) => x,
2307 Err(e) => {
2308 error!("suspend_pvclock failed: {e:?}");
2309 return VmResponse::Err(SysError::new(EIO));
2310 }
2311 });
2312 }
2313 }
2314 if let Err(e) = device_control_tube
2315 .send(&DeviceControlCommand::SleepDevices)
2316 .context("send command to devices control socket")
2317 {
2318 error!("{:?}", e);
2319 return VmResponse::Err(SysError::new(EIO));
2320 };
2321 match device_control_tube
2322 .recv()
2323 .context("receive from devices control socket")
2324 {
2325 Ok(VmResponse::Ok) => {
2326 info!("Finished crosvm suspend successfully");
2327 VmResponse::Ok
2328 }
2329 Ok(resp) => {
2330 error!("device sleep failed: {}", resp);
2331 VmResponse::Err(SysError::new(EIO))
2332 }
2333 Err(e) => {
2334 error!("receive from devices control socket: {:?}", e);
2335 VmResponse::Err(SysError::new(EIO))
2336 }
2337 }
2338 }
2339 VmRequest::ResumeVm => {
2340 info!("Starting crosvm resume");
2341 if let Err(e) = device_control_tube
2342 .send(&DeviceControlCommand::WakeDevices)
2343 .context("send command to devices control socket")
2344 {
2345 error!("{:?}", e);
2346 return VmResponse::Err(SysError::new(EIO));
2347 };
2348 match device_control_tube
2349 .recv()
2350 .context("receive from devices control socket")
2351 {
2352 Ok(VmResponse::Ok) => {
2353 info!("Finished crosvm resume successfully");
2354 }
2355 Ok(resp) => {
2356 error!("device wake failed: {}", resp);
2357 return VmResponse::Err(SysError::new(EIO));
2358 }
2359 Err(e) => {
2360 error!("receive from devices control socket: {:?}", e);
2361 return VmResponse::Err(SysError::new(EIO));
2362 }
2363 }
2364 if vm.check_capability(VmCap::PvClock) {
2366 if let Some(x) = &suspended_pvclock_state.take() {
2368 if let Err(e) = vm.set_pvclock(x) {
2369 error!("resume_pvclock failed: {e:?}");
2370 return VmResponse::Err(SysError::new(EIO));
2371 }
2372 }
2373 }
2374 kick_vcpus(VcpuControl::RunState(VmRunMode::Running));
2375 VmResponse::Ok
2376 }
2377 VmRequest::DeviceControl(req) => req.execute(pm).into(),
2378 VmRequest::MakeRT => {
2379 kick_vcpus(VcpuControl::MakeRT);
2380 VmResponse::Ok
2381 }
2382 #[cfg(feature = "balloon")]
2383 VmRequest::BalloonCommand(_) => unreachable!("Should be handled with BalloonTube"),
2384 VmRequest::DiskCommand {
2385 disk_index,
2386 ref command,
2387 } => match &disk_host_tubes.get(*disk_index) {
2388 Some(tube) => handle_disk_command(command, tube),
2389 None => VmResponse::Err(SysError::new(ENODEV)),
2390 },
2391 VmRequest::GpuCommand(ref cmd) => match gpu_control_tube {
2392 Some(gpu_control) => {
2393 let res = gpu_control.send(cmd);
2394 if let Err(e) = res {
2395 error!("fail to send command to gpu control socket: {}", e);
2396 return VmResponse::Err(SysError::new(EIO));
2397 }
2398 match gpu_control.recv() {
2399 Ok(response) => VmResponse::GpuResponse(response),
2400 Err(e) => {
2401 error!("fail to recv command from gpu control socket: {}", e);
2402 VmResponse::Err(SysError::new(EIO))
2403 }
2404 }
2405 }
2406 None => {
2407 error!("gpu control is not enabled in crosvm");
2408 VmResponse::Err(SysError::new(EIO))
2409 }
2410 },
2411 VmRequest::UsbCommand(ref cmd) => {
2412 let usb_control_tube = match usb_control_tube {
2413 Some(t) => t,
2414 None => {
2415 error!("attempted to execute USB request without control tube");
2416 return VmResponse::Err(SysError::new(ENODEV));
2417 }
2418 };
2419 let res = usb_control_tube.send(cmd);
2420 if let Err(e) = res {
2421 error!("fail to send command to usb control socket: {}", e);
2422 return VmResponse::Err(SysError::new(EIO));
2423 }
2424 match usb_control_tube.recv() {
2425 Ok(response) => VmResponse::UsbResponse(response),
2426 Err(e) => {
2427 error!("fail to recv command from usb control socket: {}", e);
2428 VmResponse::Err(SysError::new(EIO))
2429 }
2430 }
2431 }
2432 VmRequest::BatCommand(type_, ref cmd) => {
2433 match bat_control {
2434 Some(battery) => {
2435 if battery.type_ != *type_ {
2436 error!("ignored battery command due to battery type: expected {:?}, got {:?}", battery.type_, type_);
2437 return VmResponse::Err(SysError::new(EINVAL));
2438 }
2439
2440 let res = battery.control_tube.send(cmd);
2441 if let Err(e) = res {
2442 error!("fail to send command to bat control socket: {}", e);
2443 return VmResponse::Err(SysError::new(EIO));
2444 }
2445
2446 match battery.control_tube.recv() {
2447 Ok(response) => VmResponse::BatResponse(response),
2448 Err(e) => {
2449 error!("fail to recv command from bat control socket: {}", e);
2450 VmResponse::Err(SysError::new(EIO))
2451 }
2452 }
2453 }
2454 None => VmResponse::BatResponse(BatControlResult::NoBatDevice),
2455 }
2456 }
2457 #[cfg(feature = "audio")]
2458 VmRequest::SndCommand(ref cmd) => match cmd {
2459 SndControlCommand::MuteAll(muted) => {
2460 for tube in snd_host_tubes {
2461 let res = tube.send(&SndControlCommand::MuteAll(*muted));
2462 if let Err(e) = res {
2463 error!("fail to send command to snd control socket: {}", e);
2464 return VmResponse::Err(SysError::new(EIO));
2465 }
2466
2467 match tube.recv() {
2468 Ok(VmResponse::Ok) => {
2469 debug!("device is successfully muted");
2470 }
2471 Ok(resp) => {
2472 error!("mute failed: {}", resp);
2473 return VmResponse::ErrString("fail to mute the device".to_owned());
2474 }
2475 Err(e) => return VmResponse::Err(SysError::new(EIO)),
2476 }
2477 }
2478 VmResponse::Ok
2479 }
2480 },
2481 #[cfg(feature = "pci-hotplug")]
2482 VmRequest::HotPlugNetCommand(ref _net_cmd) => {
2483 VmResponse::ErrString("hot plug not supported".to_owned())
2484 }
2485 VmRequest::Snapshot(SnapshotCommand::Take {
2486 ref snapshot_path,
2487 compress_memory,
2488 encrypt,
2489 }) => {
2490 info!("Starting crosvm snapshot");
2491 match do_snapshot(
2492 snapshot_path.to_path_buf(),
2493 kick_vcpus,
2494 irq_handler_control,
2495 device_control_tube,
2496 vcpu_size,
2497 snapshot_irqchip,
2498 *compress_memory,
2499 *encrypt,
2500 suspended_pvclock_state,
2501 vm,
2502 ) {
2503 Ok(()) => {
2504 info!("Finished crosvm snapshot successfully");
2505 VmResponse::Ok
2506 }
2507 Err(e) => {
2508 error!("failed to handle snapshot: {:?}", e);
2509 VmResponse::Err(SysError::new(EIO))
2510 }
2511 }
2512 }
2513 VmRequest::RegisterListener {
2514 socket_addr: _,
2515 event: _,
2516 } => VmResponse::Ok,
2517 VmRequest::UnregisterListener {
2518 socket_addr: _,
2519 event: _,
2520 } => VmResponse::Ok,
2521 VmRequest::Unregister { socket_addr: _ } => VmResponse::Ok,
2522 VmRequest::VcpuPidTid => unreachable!(),
2523 VmRequest::Throttle(_, _) => unreachable!(),
2524 VmRequest::GetVmDescriptor => {
2525 let vm_fd = match vm.try_clone_descriptor() {
2526 Ok(vm_fd) => vm_fd,
2527 Err(e) => {
2528 error!("failed to get vm_fd: {:?}", e);
2529 return VmResponse::Err(e);
2530 }
2531 };
2532 VmResponse::VmDescriptor {
2533 hypervisor: vm.hypervisor_kind(),
2534 vm_fd,
2535 }
2536 }
2537 VmRequest::RegisterMemory { .. } => unreachable!(),
2538 VmRequest::UnregisterMemory { .. } => unreachable!(),
2539 }
2540 }
2541}
2542
2543fn do_snapshot(
2545 snapshot_path: PathBuf,
2546 kick_vcpus: impl Fn(VcpuControl),
2547 irq_handler_control: &Tube,
2548 device_control_tube: &Tube,
2549 vcpu_size: usize,
2550 snapshot_irqchip: impl Fn() -> anyhow::Result<AnySnapshot>,
2551 compress_memory: bool,
2552 encrypt: bool,
2553 suspended_pvclock_state: &mut Option<hypervisor::ClockState>,
2554 vm: &dyn Vm,
2555) -> anyhow::Result<()> {
2556 let snapshot_start = Instant::now();
2557
2558 let _vcpu_guard = VcpuSuspendGuard::new(&kick_vcpus, vcpu_size)?;
2559 let _device_guard = DeviceSleepGuard::new(device_control_tube)?;
2560
2561 {
2582 let mut flush_attempts = 0;
2583 loop {
2584 irq_handler_control
2585 .send(&IrqHandlerRequest::WakeAndNotifyIteration)
2586 .context("failed to send flush command to IRQ handler thread")?;
2587 let resp = irq_handler_control
2588 .recv()
2589 .context("failed to recv flush response from IRQ handler thread")?;
2590 match resp {
2591 IrqHandlerResponse::HandlerIterationComplete(tokens_serviced) => {
2592 if tokens_serviced == 0 {
2593 break;
2594 }
2595 }
2596 _ => bail!("received unexpected reply from IRQ handler: {:?}", resp),
2597 }
2598 flush_attempts += 1;
2599 if flush_attempts > EXPECTED_MAX_IRQ_FLUSH_ITERATIONS {
2600 warn!(
2601 "flushing IRQs for snapshot may be stalled after iteration {}, expected <= {}
2602 iterations",
2603 flush_attempts, EXPECTED_MAX_IRQ_FLUSH_ITERATIONS
2604 );
2605 }
2606 }
2607 info!("flushed IRQs in {} iterations", flush_attempts);
2608 }
2609 let snapshot_writer = SnapshotWriter::new(snapshot_path, encrypt)?;
2610
2611 snapshot_writer.write_fragment("pvclock", &AnySnapshot::to_any(suspended_pvclock_state)?)?;
2613
2614 info!("VCPUs snapshotting...");
2616 let (send_chan, recv_chan) = mpsc::channel();
2617 kick_vcpus(VcpuControl::Snapshot(
2618 snapshot_writer.add_namespace("vcpu")?,
2619 send_chan,
2620 ));
2621 for _ in 0..vcpu_size {
2623 recv_chan
2624 .recv()
2625 .context("Failed to recv Vcpu snapshot response")?
2626 .context("Failed to snapshot Vcpu")?;
2627 }
2628 info!("VCPUs snapshotted.");
2629
2630 info!("Snapshotting irqchip...");
2632 let irqchip_snap = snapshot_irqchip()?;
2633 snapshot_writer
2634 .write_fragment("irqchip", &irqchip_snap)
2635 .context("Failed to write irqchip state")?;
2636 info!("Snapshotted irqchip.");
2637
2638 {
2640 let mem_snap_start = Instant::now();
2641 const MEMORY_SNAP_ENCRYPTED_CHUNK_SIZE_BYTES: usize = 1024 * 1024 * 64;
2643 let guest_memory_metadata = unsafe {
2646 vm.get_memory()
2647 .snapshot(
2648 &mut snapshot_writer.raw_fragment_with_chunk_size(
2649 "mem",
2650 MEMORY_SNAP_ENCRYPTED_CHUNK_SIZE_BYTES,
2651 )?,
2652 compress_memory,
2653 )
2654 .context("failed to snapshot memory")?
2655 };
2656 snapshot_writer.write_fragment("mem_metadata", &guest_memory_metadata)?;
2657
2658 let mem_snap_duration_ms = mem_snap_start.elapsed().as_millis();
2659 info!(
2660 "snapshot: memory snapshotted {}MB in {}ms",
2661 vm.get_memory().memory_size() / 1024 / 1024,
2662 mem_snap_duration_ms
2663 );
2664 metrics::log_metric_with_details(
2665 metrics::MetricEventType::SnapshotSaveMemoryLatency,
2666 mem_snap_duration_ms as i64,
2667 &metrics_events::RecordDetails {},
2668 );
2669 }
2670 info!("Devices snapshotting...");
2672 device_control_tube
2673 .send(&DeviceControlCommand::SnapshotDevices { snapshot_writer })
2674 .context("send command to devices control socket")?;
2675 let resp: VmResponse = device_control_tube
2676 .recv()
2677 .context("receive from devices control socket")?;
2678 if !matches!(resp, VmResponse::Ok) {
2679 bail!("unexpected SnapshotDevices response: {resp}");
2680 }
2681 info!("Devices snapshotted.");
2682
2683 let snap_duration_ms = snapshot_start.elapsed().as_millis();
2684 info!(
2685 "snapshot: completed snapshot in {}ms; VM mem size: {}MB",
2686 snap_duration_ms,
2687 vm.get_memory().memory_size() / 1024 / 1024,
2688 );
2689 metrics::log_metric_with_details(
2690 metrics::MetricEventType::SnapshotSaveOverallLatency,
2691 snap_duration_ms as i64,
2692 &metrics_events::RecordDetails {},
2693 );
2694 Ok(())
2695}
2696
2697pub fn do_restore(
2702 restore_path: &Path,
2703 kick_vcpus: impl Fn(VcpuControl),
2704 kick_vcpu: impl Fn(VcpuControl, usize),
2705 irq_handler_control: &Tube,
2706 device_control_tube: &Tube,
2707 vcpu_size: usize,
2708 mut restore_irqchip: impl FnMut(AnySnapshot) -> anyhow::Result<()>,
2709 require_encrypted: bool,
2710 suspended_pvclock_state: &mut Option<hypervisor::ClockState>,
2711 vm: &dyn Vm,
2712) -> anyhow::Result<()> {
2713 let restore_start = Instant::now();
2714 let _guard = VcpuSuspendGuard::new(&kick_vcpus, vcpu_size);
2715 let _devices_guard = DeviceSleepGuard::new(device_control_tube)?;
2716
2717 let snapshot_reader = SnapshotReader::new(restore_path, require_encrypted)?;
2718
2719 *suspended_pvclock_state = snapshot_reader.read_fragment("pvclock")?;
2721
2722 let irq_snapshot: AnySnapshot = snapshot_reader.read_fragment("irqchip")?;
2724 restore_irqchip(irq_snapshot)?;
2725
2726 let vcpu_snapshot_reader = snapshot_reader.namespace("vcpu")?;
2728 let vcpu_snapshot_count = vcpu_snapshot_reader.list_fragments()?.len();
2729 if vcpu_snapshot_count != vcpu_size {
2730 bail!(
2731 "bad cpu count in snapshot: expected={} got={}",
2732 vcpu_size,
2733 vcpu_snapshot_count,
2734 );
2735 }
2736 #[cfg(target_arch = "x86_64")]
2737 let host_tsc_reference_moment = {
2738 unsafe { _rdtsc() }
2740 };
2741 let (send_chan, recv_chan) = mpsc::channel();
2742 for vcpu_id in 0..vcpu_size {
2743 kick_vcpu(
2744 VcpuControl::Restore(VcpuRestoreRequest {
2745 result_sender: send_chan.clone(),
2746 snapshot_reader: vcpu_snapshot_reader.clone(),
2747 #[cfg(target_arch = "x86_64")]
2748 host_tsc_reference_moment,
2749 }),
2750 vcpu_id,
2751 );
2752 }
2753 for _ in 0..vcpu_size {
2754 recv_chan
2755 .recv()
2756 .context("Failed to recv restore response")?
2757 .context("Failed to restore vcpu")?;
2758 }
2759
2760 {
2762 let mem_restore_start = Instant::now();
2763 let guest_memory_metadata = snapshot_reader.read_fragment("mem_metadata")?;
2764 unsafe {
2767 vm.get_memory().restore(
2768 guest_memory_metadata,
2769 &mut snapshot_reader.raw_fragment("mem")?,
2770 )?
2771 };
2772 let mem_restore_duration_ms = mem_restore_start.elapsed().as_millis();
2773 info!(
2774 "snapshot: memory restored {}MB in {}ms",
2775 vm.get_memory().memory_size() / 1024 / 1024,
2776 mem_restore_duration_ms
2777 );
2778 metrics::log_metric_with_details(
2779 metrics::MetricEventType::SnapshotRestoreMemoryLatency,
2780 mem_restore_duration_ms as i64,
2781 &metrics_events::RecordDetails {},
2782 );
2783 }
2784 device_control_tube
2786 .send(&DeviceControlCommand::RestoreDevices {
2787 snapshot_reader: snapshot_reader.clone(),
2788 })
2789 .context("send restore devices command to devices control socket")?;
2790 let resp: VmResponse = device_control_tube
2791 .recv()
2792 .context("receive from devices control socket")?;
2793 if !matches!(resp, VmResponse::Ok) {
2794 bail!("unexpected RestoreDevices response: {resp}");
2795 }
2796
2797 {
2799 irq_handler_control
2800 .send(&IrqHandlerRequest::RefreshIrqEventTokens)
2801 .context("failed to send refresh irq event token command to IRQ handler thread")?;
2802 let resp: IrqHandlerResponse = irq_handler_control
2803 .recv()
2804 .context("failed to recv refresh response from IRQ handler thread")?;
2805 if !matches!(resp, IrqHandlerResponse::IrqEventTokenRefreshComplete) {
2806 bail!(
2807 "received unexpected reply from IRQ handler thread: {:?}",
2808 resp
2809 );
2810 }
2811 }
2812
2813 let restore_duration_ms = restore_start.elapsed().as_millis();
2814 info!(
2815 "snapshot: completed restore in {}ms; mem size: {}",
2816 restore_duration_ms,
2817 vm.get_memory().memory_size(),
2818 );
2819
2820 metrics::log_metric_with_details(
2821 metrics::MetricEventType::SnapshotRestoreOverallLatency,
2822 restore_duration_ms as i64,
2823 &metrics_events::RecordDetails {},
2824 );
2825 Ok(())
2826}
2827
2828pub type HypervisorKind = hypervisor::HypervisorKind;
2829
2830#[derive(Serialize, Deserialize, Debug)]
2834#[must_use]
2835pub enum VmResponse {
2836 Ok,
2838 Err(SysError),
2840 ErrString(String),
2842 RegisterMemory { slot: u32 },
2844 RegisterMemory2 { region_id: u64 },
2846 #[cfg(feature = "balloon")]
2848 BalloonStats {
2849 stats: balloon_control::BalloonStats,
2850 balloon_actual: u64,
2851 },
2852 #[cfg(feature = "balloon")]
2854 BalloonWS {
2855 ws: balloon_control::BalloonWS,
2856 balloon_actual: u64,
2857 },
2858 #[cfg(feature = "pci-hotplug")]
2860 PciHotPlugResponse { bus: u8 },
2861 UsbResponse(UsbControlResult),
2863 GpuResponse(GpuControlResult),
2865 BatResponse(BatControlResult),
2867 SwapStatus(SwapStatus),
2869 DevicesState(DevicesState),
2871 VcpuPidTidResponse {
2873 pid_tid_map: BTreeMap<usize, (u32, u32)>,
2874 },
2875 VmDescriptor {
2876 hypervisor: HypervisorKind,
2877 vm_fd: SafeDescriptor,
2878 },
2879}
2880
2881impl Display for VmResponse {
2882 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2883 use self::VmResponse::*;
2884
2885 match self {
2886 Ok => write!(f, "ok"),
2887 Err(e) => write!(f, "error: {e}"),
2888 ErrString(e) => write!(f, "error: {e}"),
2889 RegisterMemory { slot } => write!(f, "memory registered in slot {slot}"),
2890 RegisterMemory2 { region_id } => {
2891 write!(f, "memory registered in region id {region_id}")
2892 }
2893 #[cfg(feature = "balloon")]
2894 VmResponse::BalloonStats {
2895 stats,
2896 balloon_actual,
2897 } => {
2898 write!(
2899 f,
2900 "stats: {}\nballoon_actual: {}",
2901 serde_json::to_string_pretty(&stats)
2902 .unwrap_or_else(|_| "invalid_response".to_string()),
2903 balloon_actual
2904 )
2905 }
2906 #[cfg(feature = "balloon")]
2907 VmResponse::BalloonWS { ws, balloon_actual } => {
2908 write!(
2909 f,
2910 "ws: {}, balloon_actual: {}",
2911 serde_json::to_string_pretty(&ws)
2912 .unwrap_or_else(|_| "invalid_response".to_string()),
2913 balloon_actual,
2914 )
2915 }
2916 UsbResponse(result) => write!(f, "usb control request get result {result:?}"),
2917 #[cfg(feature = "pci-hotplug")]
2918 PciHotPlugResponse { bus } => write!(f, "pci hotplug bus {bus:?}"),
2919 GpuResponse(result) => write!(f, "gpu control request result {result:?}"),
2920 BatResponse(result) => write!(f, "{result}"),
2921 SwapStatus(status) => {
2922 write!(
2923 f,
2924 "{}",
2925 serde_json::to_string(&status)
2926 .unwrap_or_else(|_| "invalid_response".to_string()),
2927 )
2928 }
2929 DevicesState(status) => write!(f, "devices status: {status:?}"),
2930 VcpuPidTidResponse { pid_tid_map } => write!(f, "vcpu pid tid map: {pid_tid_map:?}"),
2931 VmDescriptor { hypervisor, vm_fd } => {
2932 write!(f, "hypervisor: {hypervisor:?}, vm_fd: {vm_fd:?}")
2933 }
2934 }
2935 }
2936}
2937
2938#[derive(Serialize, Deserialize)]
2941pub enum ModifyWaitContext {
2942 Add(#[serde(with = "with_as_descriptor")] Descriptor),
2943}
2944
2945#[sorted]
2946#[derive(Error, Debug)]
2947pub enum VirtioIOMMUVfioError {
2948 #[error("socket failed")]
2949 SocketFailed,
2950 #[error("unexpected response: {0}")]
2951 UnexpectedResponse(VirtioIOMMUResponse),
2952 #[error("unknown command: `{0}`")]
2953 UnknownCommand(String),
2954 #[error("{0}")]
2955 VfioControl(VirtioIOMMUVfioResult),
2956}
2957
2958#[derive(Serialize, Deserialize, Debug)]
2959pub enum VirtioIOMMUVfioCommand {
2960 VfioDeviceAdd {
2962 endpoint_addr: u32,
2963 wrapper_id: u32,
2964 #[serde(with = "with_as_descriptor")]
2965 container: File,
2966 },
2967 VfioDeviceDel {
2969 endpoint_addr: u32,
2970 },
2971 VfioDmabufMap {
2973 region_id: VmMemoryRegionId,
2974 gpa: u64,
2975 size: u64,
2976 dma_buf: SafeDescriptor,
2977 },
2978 VfioDmabufUnmap(VmMemoryRegionId),
2980}
2981
2982#[derive(Serialize, Deserialize, Debug)]
2983pub enum VirtioIOMMUVfioResult {
2984 Ok,
2985 NotInPCIRanges,
2986 NoAvailableContainer,
2987 NoSuchDevice,
2988 NoSuchMappedDmabuf,
2989 InvalidParam,
2990}
2991
2992impl Display for VirtioIOMMUVfioResult {
2993 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2994 use self::VirtioIOMMUVfioResult::*;
2995
2996 match self {
2997 Ok => write!(f, "successfully"),
2998 NotInPCIRanges => write!(f, "not in the pci ranges of virtio-iommu"),
2999 NoAvailableContainer => write!(f, "no available vfio container"),
3000 NoSuchDevice => write!(f, "no such a vfio device"),
3001 NoSuchMappedDmabuf => write!(f, "no such a mapped dmabuf"),
3002 InvalidParam => write!(f, "invalid parameters"),
3003 }
3004 }
3005}
3006
3007#[derive(Serialize, Deserialize, Debug)]
3012pub enum VirtioIOMMURequest {
3013 VfioCommand(VirtioIOMMUVfioCommand),
3015}
3016
3017#[derive(Serialize, Deserialize, Debug)]
3022pub enum VirtioIOMMUResponse {
3023 Ok,
3025 Err(SysError),
3027 VfioResponse(VirtioIOMMUVfioResult),
3029}
3030
3031impl Display for VirtioIOMMUResponse {
3032 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3033 use self::VirtioIOMMUResponse::*;
3034 match self {
3035 Ok => write!(f, "ok"),
3036 Err(e) => write!(f, "error: {e}"),
3037 VfioResponse(result) => write!(
3038 f,
3039 "The vfio-related virtio-iommu request got result: {result:?}"
3040 ),
3041 }
3042 }
3043}
3044
3045pub fn virtio_iommu_request_async(
3047 iommu_control_tube: &Tube,
3048 req: &VirtioIOMMURequest,
3049) -> VirtioIOMMUResponse {
3050 match iommu_control_tube.send(&req) {
3051 Ok(_) => VirtioIOMMUResponse::Ok,
3052 Err(e) => {
3053 error!("virtio-iommu socket send failed: {:?}", e);
3054 VirtioIOMMUResponse::Err(SysError::last())
3055 }
3056 }
3057}
3058
3059pub type VirtioIOMMURequestResult = std::result::Result<VirtioIOMMUResponse, ()>;
3060
3061pub fn virtio_iommu_request(
3063 iommu_control_tube: &Tube,
3064 req: &VirtioIOMMURequest,
3065) -> VirtioIOMMURequestResult {
3066 let response = match virtio_iommu_request_async(iommu_control_tube, req) {
3067 VirtioIOMMUResponse::Ok => match iommu_control_tube.recv() {
3068 Ok(response) => response,
3069 Err(e) => {
3070 error!("virtio-iommu socket recv failed: {:?}", e);
3071 VirtioIOMMUResponse::Err(SysError::last())
3072 }
3073 },
3074 resp => resp,
3075 };
3076 Ok(response)
3077}
3078
3079#[cfg(test)]
3080mod tests {
3081 use anyhow::anyhow;
3082
3083 use super::*;
3084
3085 #[test]
3086 fn vm_memory_response_error_should_serialize_and_deserialize_correctly() {
3087 let source_error: VmMemoryResponseError = anyhow!("root cause")
3088 .context("context 1")
3089 .context("context 2")
3090 .into();
3091 let serialized_bytes =
3092 serde_json::to_vec(&source_error).expect("should serialize to json successfully");
3093 let target_error = serde_json::from_slice::<VmMemoryResponseError>(&serialized_bytes)
3094 .expect("should deserialize from json successfully");
3095 assert_eq!(source_error.0.to_string(), target_error.0.to_string());
3096 assert_eq!(
3097 source_error
3098 .0
3099 .chain()
3100 .map(ToString::to_string)
3101 .collect::<Vec<_>>(),
3102 target_error
3103 .0
3104 .chain()
3105 .map(ToString::to_string)
3106 .collect::<Vec<_>>()
3107 );
3108 }
3109
3110 #[test]
3111 fn vm_memory_response_error_deserialization_should_handle_malformat_correctly() {
3112 let flat_source = FlatVmMemoryResponseError(vec![]);
3113 let serialized_bytes =
3114 serde_json::to_vec(&flat_source).expect("should serialize to json successfully");
3115 serde_json::from_slice::<VmMemoryResponseError>(&serialized_bytes)
3116 .expect_err("deserialize with 0 error messages should fail");
3117 }
3118
3119 #[test]
3120 fn test_device_control_request_serde() {
3121 let req = DeviceControlRequest::Gpe {
3122 gpe: 5,
3123 clear_evt: None,
3124 };
3125 let bytes = serde_json::to_vec(&req).unwrap();
3126 let deserialized: DeviceControlRequest = serde_json::from_slice(&bytes).unwrap();
3127 match deserialized {
3128 DeviceControlRequest::Gpe { gpe, clear_evt } => {
3129 assert_eq!(gpe, 5);
3130 assert!(clear_evt.is_none());
3131 }
3132 _ => panic!("unexpected request variant"),
3133 }
3134
3135 let resp = DeviceControlResponse::Ok;
3136 let bytes = serde_json::to_vec(&resp).unwrap();
3137 let deserialized: DeviceControlResponse = serde_json::from_slice(&bytes).unwrap();
3138 match deserialized {
3139 DeviceControlResponse::Ok => {}
3140 _ => panic!("unexpected response variant"),
3141 }
3142
3143 let vm_req = VmRequest::DeviceControl(DeviceControlRequest::Gpe {
3144 gpe: 5,
3145 clear_evt: None,
3146 });
3147 let bytes = serde_json::to_vec(&vm_req).unwrap();
3148 let deserialized: VmRequest = serde_json::from_slice(&bytes).unwrap();
3149 match deserialized {
3150 VmRequest::DeviceControl(DeviceControlRequest::Gpe { gpe, clear_evt }) => {
3151 assert_eq!(gpe, 5);
3152 assert!(clear_evt.is_none());
3153 }
3154 _ => panic!("unexpected request variant"),
3155 }
3156 assert!(serde_json::from_slice::<DeviceControlRequest>(&bytes).is_err());
3158 }
3159
3160 #[test]
3161 fn test_audio_permission_wire_protocol() {
3162 assert_eq!(AudioPermissionRequest::Check.to_wire(), 1u8);
3164 assert_eq!(
3165 AudioPermissionRequest::try_from(1u8),
3166 Ok(AudioPermissionRequest::Check)
3167 );
3168 assert_eq!(AudioPermissionRequest::try_from(0u8), Err(0u8));
3169 assert_eq!(AudioPermissionRequest::try_from(255u8), Err(255u8));
3170
3171 assert_eq!(AudioPermissionResponse::Granted.to_wire(), 1u8);
3173 assert_eq!(AudioPermissionResponse::Denied.to_wire(), 2u8);
3174 assert_eq!(
3175 AudioPermissionResponse::try_from(1u8),
3176 Ok(AudioPermissionResponse::Granted)
3177 );
3178 assert_eq!(
3179 AudioPermissionResponse::try_from(2u8),
3180 Ok(AudioPermissionResponse::Denied)
3181 );
3182 assert_eq!(AudioPermissionResponse::try_from(0u8), Err(0u8));
3183 assert_eq!(AudioPermissionResponse::try_from(3u8), Err(3u8));
3184 }
3185}