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)]
1580pub enum DeviceControlRequest {
1581 Gpe { gpe: u32, clear_evt: Option<Event> },
1585 PciPme(u16),
1587 HotPlugVfioCommand {
1589 device: HotPlugDeviceInfo,
1590 add: bool,
1591 },
1592}
1593
1594#[derive(Serialize, Deserialize, Debug)]
1596#[must_use]
1597pub enum DeviceControlResponse {
1598 Ok,
1599 Err(SysError),
1600}
1601
1602impl Display for DeviceControlResponse {
1603 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1604 match self {
1605 DeviceControlResponse::Ok => write!(f, "ok"),
1606 DeviceControlResponse::Err(e) => write!(f, "error: {e}"),
1607 }
1608 }
1609}
1610
1611impl From<DeviceControlResponse> for VmResponse {
1612 fn from(response: DeviceControlResponse) -> Self {
1613 match response {
1614 DeviceControlResponse::Ok => VmResponse::Ok,
1615 DeviceControlResponse::Err(e) => VmResponse::Err(e),
1616 }
1617 }
1618}
1619
1620impl DeviceControlRequest {
1621 pub fn execute(
1623 &self,
1624 pm: &mut Option<Arc<Mutex<dyn PmResource + Send>>>,
1625 ) -> DeviceControlResponse {
1626 match self {
1627 DeviceControlRequest::Gpe { gpe, clear_evt } => {
1628 if let Some(pm) = pm.as_ref() {
1629 match clear_evt.as_ref().map(|e| e.try_clone()).transpose() {
1630 Ok(clear_evt) => {
1631 pm.lock().gpe_evt(*gpe, clear_evt);
1632 DeviceControlResponse::Ok
1633 }
1634 Err(err) => {
1635 error!("Error cloning clear_evt: {:?}", err);
1636 DeviceControlResponse::Err(SysError::new(EIO))
1637 }
1638 }
1639 } else {
1640 error!("{:#?} not supported", *self);
1641 DeviceControlResponse::Err(SysError::new(ENOTSUP))
1642 }
1643 }
1644 DeviceControlRequest::PciPme(requester_id) => {
1645 if let Some(pm) = pm.as_ref() {
1646 pm.lock().pme_evt(*requester_id);
1647 DeviceControlResponse::Ok
1648 } else {
1649 error!("{:#?} not supported", *self);
1650 DeviceControlResponse::Err(SysError::new(ENOTSUP))
1651 }
1652 }
1653 DeviceControlRequest::HotPlugVfioCommand { .. } => {
1654 panic!("HotPlugVfioCommand should be handled by the platform run loop");
1655 }
1656 }
1657 }
1658}
1659
1660#[derive(Serialize, Deserialize, Debug, Clone)]
1662pub enum PvClockCommand {
1663 Suspend,
1664 Resume,
1665}
1666
1667#[derive(Serialize, Deserialize, Debug)]
1669pub enum PvClockCommandResponse {
1670 Ok,
1671 Resumed { total_suspended_ticks: u64 },
1672 DeviceInactive,
1673 Err(SysError),
1674}
1675
1676#[derive(Serialize, Deserialize, Debug)]
1678pub enum SwapCommand {
1679 Enable,
1680 Trim,
1681 SwapOut,
1682 Disable { slow_file_cleanup: bool },
1683 Status,
1684}
1685
1686#[derive(Serialize, Deserialize, Debug)]
1691pub enum VmRequest {
1692 Exit,
1694 Powerbtn,
1696 Sleepbtn,
1698 Rtc { clear_evt: Event },
1701 SuspendVcpus,
1703 Swap(SwapCommand),
1705 ResumeVcpus,
1707 DeviceControl(DeviceControlRequest),
1709 MakeRT,
1711 #[cfg(feature = "balloon")]
1713 BalloonCommand(BalloonControlCommand),
1714 DiskCommand {
1717 disk_index: usize,
1718 command: DiskControlCommand,
1719 },
1720 UsbCommand(UsbControlCommand),
1722 GpuCommand(GpuControlCommand),
1724 BatCommand(BatteryType, BatControlCommand),
1726 #[cfg(feature = "audio")]
1728 SndCommand(SndControlCommand),
1729 #[cfg(feature = "pci-hotplug")]
1731 HotPlugNetCommand(NetControlCommand),
1732 Snapshot(SnapshotCommand),
1734 RegisterListener {
1736 socket_addr: String,
1737 event: RegisteredEvent,
1738 },
1739 UnregisterListener {
1741 socket_addr: String,
1742 event: RegisteredEvent,
1743 },
1744 Unregister { socket_addr: String },
1746 SuspendVm,
1748 ResumeVm,
1750 VcpuPidTid,
1752 Throttle(usize, u32),
1754 GetVmDescriptor,
1756 RegisterMemory {
1758 fd: SafeDescriptor,
1759 offset: u64,
1760 range_start: u64,
1761 range_end: u64,
1762 cache_coherent: bool,
1763 },
1764 UnregisterMemory { region_id: u64 },
1766}
1767
1768#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone, Copy)]
1771pub enum RegisteredEvent {
1772 VirtioBalloonWsReport,
1773 VirtioBalloonResize,
1774 VirtioBalloonOOMDeflation,
1775}
1776
1777#[derive(Serialize, Deserialize, Debug)]
1778pub enum RegisteredEventWithData {
1779 VirtioBalloonWsReport {
1780 ws_buckets: Vec<balloon_control::WSBucket>,
1781 balloon_actual: u64,
1782 },
1783 VirtioBalloonResize,
1784 VirtioBalloonOOMDeflation,
1785}
1786
1787impl RegisteredEventWithData {
1788 pub fn into_event(&self) -> RegisteredEvent {
1789 match self {
1790 Self::VirtioBalloonWsReport { .. } => RegisteredEvent::VirtioBalloonWsReport,
1791 Self::VirtioBalloonResize => RegisteredEvent::VirtioBalloonResize,
1792 Self::VirtioBalloonOOMDeflation => RegisteredEvent::VirtioBalloonOOMDeflation,
1793 }
1794 }
1795
1796 #[cfg(feature = "registered_events")]
1797 pub fn into_proto(&self) -> registered_events::RegisteredEvent {
1798 match self {
1799 Self::VirtioBalloonWsReport {
1800 ws_buckets,
1801 balloon_actual,
1802 } => {
1803 let mut report = registered_events::VirtioBalloonWsReport {
1804 balloon_actual: *balloon_actual,
1805 ..registered_events::VirtioBalloonWsReport::new()
1806 };
1807 for ws in ws_buckets {
1808 report.ws_buckets.push(registered_events::VirtioWsBucket {
1809 age: ws.age,
1810 file_bytes: ws.bytes[0],
1811 anon_bytes: ws.bytes[1],
1812 ..registered_events::VirtioWsBucket::new()
1813 });
1814 }
1815 let mut event = registered_events::RegisteredEvent::new();
1816 event.set_ws_report(report);
1817 event
1818 }
1819 Self::VirtioBalloonResize => {
1820 let mut event = registered_events::RegisteredEvent::new();
1821 event.set_resize(registered_events::VirtioBalloonResize::new());
1822 event
1823 }
1824 Self::VirtioBalloonOOMDeflation => {
1825 let mut event = registered_events::RegisteredEvent::new();
1826 event.set_oom_deflation(registered_events::VirtioBalloonOOMDeflation::new());
1827 event
1828 }
1829 }
1830 }
1831
1832 pub fn from_ws(ws: &balloon_control::BalloonWS, balloon_actual: u64) -> Self {
1833 RegisteredEventWithData::VirtioBalloonWsReport {
1834 ws_buckets: ws.ws.clone(),
1835 balloon_actual,
1836 }
1837 }
1838}
1839
1840pub fn handle_disk_command(command: &DiskControlCommand, disk_host_tube: &Tube) -> VmResponse {
1841 if let Err(e) = disk_host_tube.send(command) {
1843 error!("disk socket send failed: {}", e);
1844 return VmResponse::Err(SysError::new(EINVAL));
1845 }
1846
1847 match disk_host_tube.recv() {
1849 Ok(DiskControlResult::Ok) => VmResponse::Ok,
1850 Ok(DiskControlResult::Err(e)) => VmResponse::Err(e),
1851 Err(e) => {
1852 error!("disk socket recv failed: {}", e);
1853 VmResponse::Err(SysError::new(EINVAL))
1854 }
1855 }
1856}
1857
1858fn map_descriptor(
1860 descriptor: &dyn AsRawDescriptor,
1861 offset: u64,
1862 size: u64,
1863 prot: Protection,
1864) -> Result<Box<dyn MappedRegion>> {
1865 let size: usize = size.try_into().map_err(|_e| SysError::new(ERANGE))?;
1866 match MemoryMappingBuilder::new(size)
1867 .from_descriptor(descriptor)
1868 .offset(offset)
1869 .protection(prot)
1870 .build()
1871 {
1872 Ok(mmap) => Ok(Box::new(mmap)),
1873 Err(MmapError::SystemCallFailed(e)) => Err(e),
1874 _ => Err(SysError::new(EINVAL)),
1875 }
1876}
1877
1878fn get_vcpu_state(kick_vcpus: impl Fn(VcpuControl), vcpu_num: usize) -> anyhow::Result<VmRunMode> {
1883 let (send_chan, recv_chan) = mpsc::channel();
1884 kick_vcpus(VcpuControl::GetStates(send_chan));
1885 if vcpu_num == 0 {
1886 bail!("vcpu_num is zero");
1887 }
1888 let mut current_mode_vec: Vec<VmRunMode> = Vec::new();
1889 for _ in 0..vcpu_num {
1890 match recv_chan.recv() {
1891 Ok(state) => current_mode_vec.push(state),
1892 Err(e) => {
1893 bail!("Failed to get vCPU state: {}", e);
1894 }
1895 };
1896 }
1897 let first_state = current_mode_vec[0];
1898 if first_state == VmRunMode::Exiting {
1899 panic!("Attempt to snapshot while exiting.");
1900 }
1901 if current_mode_vec.iter().any(|x| *x != first_state) {
1902 bail!("Unknown VM state: vCPUs hold different states.");
1904 }
1905 Ok(first_state)
1906}
1907
1908pub struct VcpuSuspendGuard<'a> {
1912 saved_run_mode: VmRunMode,
1913 kick_vcpus: &'a dyn Fn(VcpuControl),
1914}
1915
1916impl<'a> VcpuSuspendGuard<'a> {
1917 pub fn new(kick_vcpus: &'a impl Fn(VcpuControl), vcpu_num: usize) -> anyhow::Result<Self> {
1927 let saved_run_mode = get_vcpu_state(kick_vcpus, vcpu_num)?;
1929 match saved_run_mode {
1930 VmRunMode::Running => {
1931 kick_vcpus(VcpuControl::RunState(VmRunMode::Suspending));
1932 let current_mode = get_vcpu_state(kick_vcpus, vcpu_num)?;
1936 if current_mode != VmRunMode::Suspending {
1937 kick_vcpus(VcpuControl::RunState(saved_run_mode));
1938 bail!("vCPUs failed to all suspend. Kicking back all vCPUs to their previous state: {saved_run_mode}");
1939 }
1940 }
1941 VmRunMode::Suspending => {
1942 }
1944 other => {
1945 bail!("vcpus are not in running/suspending state, but {}", other);
1946 }
1947 };
1948 Ok(Self {
1949 saved_run_mode,
1950 kick_vcpus,
1951 })
1952 }
1953}
1954
1955impl Drop for VcpuSuspendGuard<'_> {
1956 fn drop(&mut self) {
1957 if self.saved_run_mode != VmRunMode::Suspending {
1958 (self.kick_vcpus)(VcpuControl::RunState(self.saved_run_mode));
1959 }
1960 }
1961}
1962
1963pub struct DeviceSleepGuard<'a> {
1967 device_control_tube: &'a Tube,
1968 devices_state: DevicesState,
1969}
1970
1971impl<'a> DeviceSleepGuard<'a> {
1972 fn new(device_control_tube: &'a Tube) -> anyhow::Result<Self> {
1973 device_control_tube
1974 .send(&DeviceControlCommand::GetDevicesState)
1975 .context("send command to devices control socket")?;
1976 let devices_state = match device_control_tube
1977 .recv()
1978 .context("receive from devices control socket")?
1979 {
1980 VmResponse::DevicesState(state) => state,
1981 resp => bail!("failed to get devices state. Unexpected behavior: {}", resp),
1982 };
1983 if let DevicesState::Wake = devices_state {
1984 device_control_tube
1985 .send(&DeviceControlCommand::SleepDevices)
1986 .context("send command to devices control socket")?;
1987 match device_control_tube
1988 .recv()
1989 .context("receive from devices control socket")?
1990 {
1991 VmResponse::Ok => (),
1992 resp => bail!("device sleep failed: {}", resp),
1993 }
1994 }
1995 Ok(Self {
1996 device_control_tube,
1997 devices_state,
1998 })
1999 }
2000}
2001
2002impl Drop for DeviceSleepGuard<'_> {
2003 fn drop(&mut self) {
2004 if let DevicesState::Wake = self.devices_state {
2005 if let Err(e) = self
2006 .device_control_tube
2007 .send(&DeviceControlCommand::WakeDevices)
2008 {
2009 panic!("failed to request device wake after snapshot: {e}");
2010 }
2011 match self.device_control_tube.recv() {
2012 Ok(VmResponse::Ok) => (),
2013 Ok(resp) => panic!("unexpected response to device wake request: {resp}"),
2014 Err(e) => panic!("failed to get reply for device wake request: {e}"),
2015 }
2016 }
2017 }
2018}
2019
2020impl VmRequest {
2021 #[allow(unused_variables)]
2035 pub fn execute(
2036 &self,
2037 vm: &dyn Vm,
2038 disk_host_tubes: &[Tube],
2039 snd_host_tubes: &[Tube],
2040 pm: &mut Option<Arc<Mutex<dyn PmResource + Send>>>,
2041 gpu_control_tube: Option<&Tube>,
2042 usb_control_tube: Option<&Tube>,
2043 bat_control: &mut Option<BatControl>,
2044 kick_vcpus: impl Fn(VcpuControl),
2045 #[cfg(any(target_os = "android", target_os = "linux"))] kick_vcpu: impl Fn(usize, VcpuControl),
2046 force_s2idle: bool,
2047 #[cfg(feature = "swap")] swap_controller: Option<&swap::SwapController>,
2048 device_control_tube: &Tube,
2049 vcpu_size: usize,
2050 irq_handler_control: &Tube,
2051 snapshot_irqchip: impl Fn() -> anyhow::Result<AnySnapshot>,
2052 suspended_pvclock_state: &mut Option<hypervisor::ClockState>,
2053 ) -> VmResponse {
2054 match self {
2055 VmRequest::Exit => {
2056 panic!("VmRequest::Exit should be handled by the platform run loop");
2057 }
2058 VmRequest::Powerbtn => {
2059 if let Some(pm) = pm {
2060 pm.lock().pwrbtn_evt();
2061 VmResponse::Ok
2062 } else {
2063 error!("{:#?} not supported", *self);
2064 VmResponse::Err(SysError::new(ENOTSUP))
2065 }
2066 }
2067 VmRequest::Sleepbtn => {
2068 if let Some(pm) = pm {
2069 pm.lock().slpbtn_evt();
2070 VmResponse::Ok
2071 } else {
2072 error!("{:#?} not supported", *self);
2073 VmResponse::Err(SysError::new(ENOTSUP))
2074 }
2075 }
2076 VmRequest::Rtc { clear_evt } => {
2077 if let Some(pm) = pm.as_ref() {
2078 match clear_evt.try_clone() {
2079 Ok(clear_evt) => {
2080 pm.lock().rtc_evt(clear_evt);
2082 VmResponse::Ok
2083 }
2084 Err(err) => {
2085 error!("Error cloning clear_evt: {:?}", err);
2086 VmResponse::Err(SysError::new(EIO))
2087 }
2088 }
2089 } else {
2090 error!("{:#?} not supported", *self);
2091 VmResponse::Err(SysError::new(ENOTSUP))
2092 }
2093 }
2094 VmRequest::SuspendVcpus => {
2095 if !force_s2idle {
2096 kick_vcpus(VcpuControl::RunState(VmRunMode::Suspending));
2097 let current_mode = match get_vcpu_state(kick_vcpus, vcpu_size) {
2098 Ok(state) => state,
2099 Err(e) => {
2100 error!("failed to get vcpu state: {e}");
2101 return VmResponse::Err(SysError::new(EIO));
2102 }
2103 };
2104 if current_mode != VmRunMode::Suspending {
2105 error!("vCPUs failed to all suspend.");
2106 return VmResponse::Err(SysError::new(EIO));
2107 }
2108 }
2109 VmResponse::Ok
2110 }
2111 VmRequest::ResumeVcpus => {
2112 if let Err(e) = device_control_tube.send(&DeviceControlCommand::GetDevicesState) {
2113 error!("failed to send GetDevicesState: {}", e);
2114 return VmResponse::Err(SysError::new(EIO));
2115 }
2116 let devices_state = match device_control_tube.recv() {
2117 Ok(VmResponse::DevicesState(state)) => state,
2118 Ok(resp) => {
2119 error!("failed to get devices state. Unexpected behavior: {}", resp);
2120 return VmResponse::Err(SysError::new(EINVAL));
2121 }
2122 Err(e) => {
2123 error!("failed to get devices state. Unexpected behavior: {}", e);
2124 return VmResponse::Err(SysError::new(EINVAL));
2125 }
2126 };
2127 if let DevicesState::Sleep = devices_state {
2128 error!("Trying to wake Vcpus while Devices are asleep. Did you mean to use `crosvm resume --full`?");
2129 return VmResponse::Err(SysError::new(EINVAL));
2130 }
2131
2132 if force_s2idle {
2133 if let Some(pm) = pm {
2136 pm.lock().pwrbtn_evt();
2137 } else {
2138 error!("triggering power btn during resume not supported");
2139 return VmResponse::Err(SysError::new(ENOTSUP));
2140 }
2141 }
2142
2143 kick_vcpus(VcpuControl::RunState(VmRunMode::Running));
2144 VmResponse::Ok
2145 }
2146 VmRequest::Swap(SwapCommand::Enable) => {
2147 #[cfg(feature = "swap")]
2148 if let Some(swap_controller) = swap_controller {
2149 let _vcpu_guard = match VcpuSuspendGuard::new(&kick_vcpus, vcpu_size) {
2153 Ok(guard) => guard,
2154 Err(e) => {
2155 error!("failed to suspend vcpus: {:?}", e);
2156 return VmResponse::Err(SysError::new(EINVAL));
2157 }
2158 };
2159 let _devices_guard = match swap_controller.suspend_devices() {
2162 Ok(guard) => guard,
2163 Err(e) => {
2164 error!("failed to suspend devices: {:?}", e);
2165 return VmResponse::Err(SysError::new(EINVAL));
2166 }
2167 };
2168
2169 return match swap_controller.enable() {
2170 Ok(()) => VmResponse::Ok,
2171 Err(e) => {
2172 error!("swap enable failed: {}", e);
2173 VmResponse::Err(SysError::new(EINVAL))
2174 }
2175 };
2176 }
2177 VmResponse::Err(SysError::new(ENOTSUP))
2178 }
2179 VmRequest::Swap(SwapCommand::Trim) => {
2180 #[cfg(feature = "swap")]
2181 if let Some(swap_controller) = swap_controller {
2182 return match swap_controller.trim() {
2183 Ok(()) => VmResponse::Ok,
2184 Err(e) => {
2185 error!("swap trim failed: {}", e);
2186 VmResponse::Err(SysError::new(EINVAL))
2187 }
2188 };
2189 }
2190 VmResponse::Err(SysError::new(ENOTSUP))
2191 }
2192 VmRequest::Swap(SwapCommand::SwapOut) => {
2193 #[cfg(feature = "swap")]
2194 if let Some(swap_controller) = swap_controller {
2195 return match swap_controller.swap_out() {
2196 Ok(()) => VmResponse::Ok,
2197 Err(e) => {
2198 error!("swap out failed: {}", e);
2199 VmResponse::Err(SysError::new(EINVAL))
2200 }
2201 };
2202 }
2203 VmResponse::Err(SysError::new(ENOTSUP))
2204 }
2205 VmRequest::Swap(SwapCommand::Disable {
2206 #[cfg(feature = "swap")]
2207 slow_file_cleanup,
2208 ..
2209 }) => {
2210 #[cfg(feature = "swap")]
2211 if let Some(swap_controller) = swap_controller {
2212 return match swap_controller.disable(*slow_file_cleanup) {
2213 Ok(()) => VmResponse::Ok,
2214 Err(e) => {
2215 error!("swap disable failed: {}", e);
2216 VmResponse::Err(SysError::new(EINVAL))
2217 }
2218 };
2219 }
2220 VmResponse::Err(SysError::new(ENOTSUP))
2221 }
2222 VmRequest::Swap(SwapCommand::Status) => {
2223 #[cfg(feature = "swap")]
2224 if let Some(swap_controller) = swap_controller {
2225 return match swap_controller.status() {
2226 Ok(status) => VmResponse::SwapStatus(status),
2227 Err(e) => {
2228 error!("swap status failed: {}", e);
2229 VmResponse::Err(SysError::new(EINVAL))
2230 }
2231 };
2232 }
2233 VmResponse::Err(SysError::new(ENOTSUP))
2234 }
2235 VmRequest::SuspendVm => {
2236 info!("Starting crosvm suspend");
2237 kick_vcpus(VcpuControl::RunState(VmRunMode::Suspending));
2238 let current_mode = match get_vcpu_state(kick_vcpus, vcpu_size) {
2239 Ok(state) => state,
2240 Err(e) => {
2241 error!("failed to get vcpu state: {e}");
2242 return VmResponse::Err(SysError::new(EIO));
2243 }
2244 };
2245 if current_mode != VmRunMode::Suspending {
2246 error!("vCPUs failed to all suspend.");
2247 return VmResponse::Err(SysError::new(EIO));
2248 }
2249 if vm.check_capability(VmCap::PvClock) {
2251 if suspended_pvclock_state.is_none() {
2252 *suspended_pvclock_state = Some(match vm.get_pvclock() {
2253 Ok(x) => x,
2254 Err(e) => {
2255 error!("suspend_pvclock failed: {e:?}");
2256 return VmResponse::Err(SysError::new(EIO));
2257 }
2258 });
2259 }
2260 }
2261 if let Err(e) = device_control_tube
2262 .send(&DeviceControlCommand::SleepDevices)
2263 .context("send command to devices control socket")
2264 {
2265 error!("{:?}", e);
2266 return VmResponse::Err(SysError::new(EIO));
2267 };
2268 match device_control_tube
2269 .recv()
2270 .context("receive from devices control socket")
2271 {
2272 Ok(VmResponse::Ok) => {
2273 info!("Finished crosvm suspend successfully");
2274 VmResponse::Ok
2275 }
2276 Ok(resp) => {
2277 error!("device sleep failed: {}", resp);
2278 VmResponse::Err(SysError::new(EIO))
2279 }
2280 Err(e) => {
2281 error!("receive from devices control socket: {:?}", e);
2282 VmResponse::Err(SysError::new(EIO))
2283 }
2284 }
2285 }
2286 VmRequest::ResumeVm => {
2287 info!("Starting crosvm resume");
2288 if let Err(e) = device_control_tube
2289 .send(&DeviceControlCommand::WakeDevices)
2290 .context("send command to devices control socket")
2291 {
2292 error!("{:?}", e);
2293 return VmResponse::Err(SysError::new(EIO));
2294 };
2295 match device_control_tube
2296 .recv()
2297 .context("receive from devices control socket")
2298 {
2299 Ok(VmResponse::Ok) => {
2300 info!("Finished crosvm resume successfully");
2301 }
2302 Ok(resp) => {
2303 error!("device wake failed: {}", resp);
2304 return VmResponse::Err(SysError::new(EIO));
2305 }
2306 Err(e) => {
2307 error!("receive from devices control socket: {:?}", e);
2308 return VmResponse::Err(SysError::new(EIO));
2309 }
2310 }
2311 if vm.check_capability(VmCap::PvClock) {
2313 if let Some(x) = &suspended_pvclock_state.take() {
2315 if let Err(e) = vm.set_pvclock(x) {
2316 error!("resume_pvclock failed: {e:?}");
2317 return VmResponse::Err(SysError::new(EIO));
2318 }
2319 }
2320 }
2321 kick_vcpus(VcpuControl::RunState(VmRunMode::Running));
2322 VmResponse::Ok
2323 }
2324 VmRequest::DeviceControl(req) => req.execute(pm).into(),
2325 VmRequest::MakeRT => {
2326 kick_vcpus(VcpuControl::MakeRT);
2327 VmResponse::Ok
2328 }
2329 #[cfg(feature = "balloon")]
2330 VmRequest::BalloonCommand(_) => unreachable!("Should be handled with BalloonTube"),
2331 VmRequest::DiskCommand {
2332 disk_index,
2333 ref command,
2334 } => match &disk_host_tubes.get(*disk_index) {
2335 Some(tube) => handle_disk_command(command, tube),
2336 None => VmResponse::Err(SysError::new(ENODEV)),
2337 },
2338 VmRequest::GpuCommand(ref cmd) => match gpu_control_tube {
2339 Some(gpu_control) => {
2340 let res = gpu_control.send(cmd);
2341 if let Err(e) = res {
2342 error!("fail to send command to gpu control socket: {}", e);
2343 return VmResponse::Err(SysError::new(EIO));
2344 }
2345 match gpu_control.recv() {
2346 Ok(response) => VmResponse::GpuResponse(response),
2347 Err(e) => {
2348 error!("fail to recv command from gpu control socket: {}", e);
2349 VmResponse::Err(SysError::new(EIO))
2350 }
2351 }
2352 }
2353 None => {
2354 error!("gpu control is not enabled in crosvm");
2355 VmResponse::Err(SysError::new(EIO))
2356 }
2357 },
2358 VmRequest::UsbCommand(ref cmd) => {
2359 let usb_control_tube = match usb_control_tube {
2360 Some(t) => t,
2361 None => {
2362 error!("attempted to execute USB request without control tube");
2363 return VmResponse::Err(SysError::new(ENODEV));
2364 }
2365 };
2366 let res = usb_control_tube.send(cmd);
2367 if let Err(e) = res {
2368 error!("fail to send command to usb control socket: {}", e);
2369 return VmResponse::Err(SysError::new(EIO));
2370 }
2371 match usb_control_tube.recv() {
2372 Ok(response) => VmResponse::UsbResponse(response),
2373 Err(e) => {
2374 error!("fail to recv command from usb control socket: {}", e);
2375 VmResponse::Err(SysError::new(EIO))
2376 }
2377 }
2378 }
2379 VmRequest::BatCommand(type_, ref cmd) => {
2380 match bat_control {
2381 Some(battery) => {
2382 if battery.type_ != *type_ {
2383 error!("ignored battery command due to battery type: expected {:?}, got {:?}", battery.type_, type_);
2384 return VmResponse::Err(SysError::new(EINVAL));
2385 }
2386
2387 let res = battery.control_tube.send(cmd);
2388 if let Err(e) = res {
2389 error!("fail to send command to bat control socket: {}", e);
2390 return VmResponse::Err(SysError::new(EIO));
2391 }
2392
2393 match battery.control_tube.recv() {
2394 Ok(response) => VmResponse::BatResponse(response),
2395 Err(e) => {
2396 error!("fail to recv command from bat control socket: {}", e);
2397 VmResponse::Err(SysError::new(EIO))
2398 }
2399 }
2400 }
2401 None => VmResponse::BatResponse(BatControlResult::NoBatDevice),
2402 }
2403 }
2404 #[cfg(feature = "audio")]
2405 VmRequest::SndCommand(ref cmd) => match cmd {
2406 SndControlCommand::MuteAll(muted) => {
2407 for tube in snd_host_tubes {
2408 let res = tube.send(&SndControlCommand::MuteAll(*muted));
2409 if let Err(e) = res {
2410 error!("fail to send command to snd control socket: {}", e);
2411 return VmResponse::Err(SysError::new(EIO));
2412 }
2413
2414 match tube.recv() {
2415 Ok(VmResponse::Ok) => {
2416 debug!("device is successfully muted");
2417 }
2418 Ok(resp) => {
2419 error!("mute failed: {}", resp);
2420 return VmResponse::ErrString("fail to mute the device".to_owned());
2421 }
2422 Err(e) => return VmResponse::Err(SysError::new(EIO)),
2423 }
2424 }
2425 VmResponse::Ok
2426 }
2427 },
2428 #[cfg(feature = "pci-hotplug")]
2429 VmRequest::HotPlugNetCommand(ref _net_cmd) => {
2430 VmResponse::ErrString("hot plug not supported".to_owned())
2431 }
2432 VmRequest::Snapshot(SnapshotCommand::Take {
2433 ref snapshot_path,
2434 compress_memory,
2435 encrypt,
2436 }) => {
2437 info!("Starting crosvm snapshot");
2438 match do_snapshot(
2439 snapshot_path.to_path_buf(),
2440 kick_vcpus,
2441 irq_handler_control,
2442 device_control_tube,
2443 vcpu_size,
2444 snapshot_irqchip,
2445 *compress_memory,
2446 *encrypt,
2447 suspended_pvclock_state,
2448 vm,
2449 ) {
2450 Ok(()) => {
2451 info!("Finished crosvm snapshot successfully");
2452 VmResponse::Ok
2453 }
2454 Err(e) => {
2455 error!("failed to handle snapshot: {:?}", e);
2456 VmResponse::Err(SysError::new(EIO))
2457 }
2458 }
2459 }
2460 VmRequest::RegisterListener {
2461 socket_addr: _,
2462 event: _,
2463 } => VmResponse::Ok,
2464 VmRequest::UnregisterListener {
2465 socket_addr: _,
2466 event: _,
2467 } => VmResponse::Ok,
2468 VmRequest::Unregister { socket_addr: _ } => VmResponse::Ok,
2469 VmRequest::VcpuPidTid => unreachable!(),
2470 VmRequest::Throttle(_, _) => unreachable!(),
2471 VmRequest::GetVmDescriptor => {
2472 let vm_fd = match vm.try_clone_descriptor() {
2473 Ok(vm_fd) => vm_fd,
2474 Err(e) => {
2475 error!("failed to get vm_fd: {:?}", e);
2476 return VmResponse::Err(e);
2477 }
2478 };
2479 VmResponse::VmDescriptor {
2480 hypervisor: vm.hypervisor_kind(),
2481 vm_fd,
2482 }
2483 }
2484 VmRequest::RegisterMemory { .. } => unreachable!(),
2485 VmRequest::UnregisterMemory { .. } => unreachable!(),
2486 }
2487 }
2488}
2489
2490fn do_snapshot(
2492 snapshot_path: PathBuf,
2493 kick_vcpus: impl Fn(VcpuControl),
2494 irq_handler_control: &Tube,
2495 device_control_tube: &Tube,
2496 vcpu_size: usize,
2497 snapshot_irqchip: impl Fn() -> anyhow::Result<AnySnapshot>,
2498 compress_memory: bool,
2499 encrypt: bool,
2500 suspended_pvclock_state: &mut Option<hypervisor::ClockState>,
2501 vm: &dyn Vm,
2502) -> anyhow::Result<()> {
2503 let snapshot_start = Instant::now();
2504
2505 let _vcpu_guard = VcpuSuspendGuard::new(&kick_vcpus, vcpu_size)?;
2506 let _device_guard = DeviceSleepGuard::new(device_control_tube)?;
2507
2508 {
2529 let mut flush_attempts = 0;
2530 loop {
2531 irq_handler_control
2532 .send(&IrqHandlerRequest::WakeAndNotifyIteration)
2533 .context("failed to send flush command to IRQ handler thread")?;
2534 let resp = irq_handler_control
2535 .recv()
2536 .context("failed to recv flush response from IRQ handler thread")?;
2537 match resp {
2538 IrqHandlerResponse::HandlerIterationComplete(tokens_serviced) => {
2539 if tokens_serviced == 0 {
2540 break;
2541 }
2542 }
2543 _ => bail!("received unexpected reply from IRQ handler: {:?}", resp),
2544 }
2545 flush_attempts += 1;
2546 if flush_attempts > EXPECTED_MAX_IRQ_FLUSH_ITERATIONS {
2547 warn!(
2548 "flushing IRQs for snapshot may be stalled after iteration {}, expected <= {}
2549 iterations",
2550 flush_attempts, EXPECTED_MAX_IRQ_FLUSH_ITERATIONS
2551 );
2552 }
2553 }
2554 info!("flushed IRQs in {} iterations", flush_attempts);
2555 }
2556 let snapshot_writer = SnapshotWriter::new(snapshot_path, encrypt)?;
2557
2558 snapshot_writer.write_fragment("pvclock", &AnySnapshot::to_any(suspended_pvclock_state)?)?;
2560
2561 info!("VCPUs snapshotting...");
2563 let (send_chan, recv_chan) = mpsc::channel();
2564 kick_vcpus(VcpuControl::Snapshot(
2565 snapshot_writer.add_namespace("vcpu")?,
2566 send_chan,
2567 ));
2568 for _ in 0..vcpu_size {
2570 recv_chan
2571 .recv()
2572 .context("Failed to recv Vcpu snapshot response")?
2573 .context("Failed to snapshot Vcpu")?;
2574 }
2575 info!("VCPUs snapshotted.");
2576
2577 info!("Snapshotting irqchip...");
2579 let irqchip_snap = snapshot_irqchip()?;
2580 snapshot_writer
2581 .write_fragment("irqchip", &irqchip_snap)
2582 .context("Failed to write irqchip state")?;
2583 info!("Snapshotted irqchip.");
2584
2585 {
2587 let mem_snap_start = Instant::now();
2588 const MEMORY_SNAP_ENCRYPTED_CHUNK_SIZE_BYTES: usize = 1024 * 1024 * 64;
2590 let guest_memory_metadata = unsafe {
2593 vm.get_memory()
2594 .snapshot(
2595 &mut snapshot_writer.raw_fragment_with_chunk_size(
2596 "mem",
2597 MEMORY_SNAP_ENCRYPTED_CHUNK_SIZE_BYTES,
2598 )?,
2599 compress_memory,
2600 )
2601 .context("failed to snapshot memory")?
2602 };
2603 snapshot_writer.write_fragment("mem_metadata", &guest_memory_metadata)?;
2604
2605 let mem_snap_duration_ms = mem_snap_start.elapsed().as_millis();
2606 info!(
2607 "snapshot: memory snapshotted {}MB in {}ms",
2608 vm.get_memory().memory_size() / 1024 / 1024,
2609 mem_snap_duration_ms
2610 );
2611 metrics::log_metric_with_details(
2612 metrics::MetricEventType::SnapshotSaveMemoryLatency,
2613 mem_snap_duration_ms as i64,
2614 &metrics_events::RecordDetails {},
2615 );
2616 }
2617 info!("Devices snapshotting...");
2619 device_control_tube
2620 .send(&DeviceControlCommand::SnapshotDevices { snapshot_writer })
2621 .context("send command to devices control socket")?;
2622 let resp: VmResponse = device_control_tube
2623 .recv()
2624 .context("receive from devices control socket")?;
2625 if !matches!(resp, VmResponse::Ok) {
2626 bail!("unexpected SnapshotDevices response: {resp}");
2627 }
2628 info!("Devices snapshotted.");
2629
2630 let snap_duration_ms = snapshot_start.elapsed().as_millis();
2631 info!(
2632 "snapshot: completed snapshot in {}ms; VM mem size: {}MB",
2633 snap_duration_ms,
2634 vm.get_memory().memory_size() / 1024 / 1024,
2635 );
2636 metrics::log_metric_with_details(
2637 metrics::MetricEventType::SnapshotSaveOverallLatency,
2638 snap_duration_ms as i64,
2639 &metrics_events::RecordDetails {},
2640 );
2641 Ok(())
2642}
2643
2644pub fn do_restore(
2649 restore_path: &Path,
2650 kick_vcpus: impl Fn(VcpuControl),
2651 kick_vcpu: impl Fn(VcpuControl, usize),
2652 irq_handler_control: &Tube,
2653 device_control_tube: &Tube,
2654 vcpu_size: usize,
2655 mut restore_irqchip: impl FnMut(AnySnapshot) -> anyhow::Result<()>,
2656 require_encrypted: bool,
2657 suspended_pvclock_state: &mut Option<hypervisor::ClockState>,
2658 vm: &dyn Vm,
2659) -> anyhow::Result<()> {
2660 let restore_start = Instant::now();
2661 let _guard = VcpuSuspendGuard::new(&kick_vcpus, vcpu_size);
2662 let _devices_guard = DeviceSleepGuard::new(device_control_tube)?;
2663
2664 let snapshot_reader = SnapshotReader::new(restore_path, require_encrypted)?;
2665
2666 *suspended_pvclock_state = snapshot_reader.read_fragment("pvclock")?;
2668
2669 let irq_snapshot: AnySnapshot = snapshot_reader.read_fragment("irqchip")?;
2671 restore_irqchip(irq_snapshot)?;
2672
2673 let vcpu_snapshot_reader = snapshot_reader.namespace("vcpu")?;
2675 let vcpu_snapshot_count = vcpu_snapshot_reader.list_fragments()?.len();
2676 if vcpu_snapshot_count != vcpu_size {
2677 bail!(
2678 "bad cpu count in snapshot: expected={} got={}",
2679 vcpu_size,
2680 vcpu_snapshot_count,
2681 );
2682 }
2683 #[cfg(target_arch = "x86_64")]
2684 let host_tsc_reference_moment = {
2685 unsafe { _rdtsc() }
2687 };
2688 let (send_chan, recv_chan) = mpsc::channel();
2689 for vcpu_id in 0..vcpu_size {
2690 kick_vcpu(
2691 VcpuControl::Restore(VcpuRestoreRequest {
2692 result_sender: send_chan.clone(),
2693 snapshot_reader: vcpu_snapshot_reader.clone(),
2694 #[cfg(target_arch = "x86_64")]
2695 host_tsc_reference_moment,
2696 }),
2697 vcpu_id,
2698 );
2699 }
2700 for _ in 0..vcpu_size {
2701 recv_chan
2702 .recv()
2703 .context("Failed to recv restore response")?
2704 .context("Failed to restore vcpu")?;
2705 }
2706
2707 {
2709 let mem_restore_start = Instant::now();
2710 let guest_memory_metadata = snapshot_reader.read_fragment("mem_metadata")?;
2711 unsafe {
2714 vm.get_memory().restore(
2715 guest_memory_metadata,
2716 &mut snapshot_reader.raw_fragment("mem")?,
2717 )?
2718 };
2719 let mem_restore_duration_ms = mem_restore_start.elapsed().as_millis();
2720 info!(
2721 "snapshot: memory restored {}MB in {}ms",
2722 vm.get_memory().memory_size() / 1024 / 1024,
2723 mem_restore_duration_ms
2724 );
2725 metrics::log_metric_with_details(
2726 metrics::MetricEventType::SnapshotRestoreMemoryLatency,
2727 mem_restore_duration_ms as i64,
2728 &metrics_events::RecordDetails {},
2729 );
2730 }
2731 device_control_tube
2733 .send(&DeviceControlCommand::RestoreDevices {
2734 snapshot_reader: snapshot_reader.clone(),
2735 })
2736 .context("send restore devices command to devices control socket")?;
2737 let resp: VmResponse = device_control_tube
2738 .recv()
2739 .context("receive from devices control socket")?;
2740 if !matches!(resp, VmResponse::Ok) {
2741 bail!("unexpected RestoreDevices response: {resp}");
2742 }
2743
2744 {
2746 irq_handler_control
2747 .send(&IrqHandlerRequest::RefreshIrqEventTokens)
2748 .context("failed to send refresh irq event token command to IRQ handler thread")?;
2749 let resp: IrqHandlerResponse = irq_handler_control
2750 .recv()
2751 .context("failed to recv refresh response from IRQ handler thread")?;
2752 if !matches!(resp, IrqHandlerResponse::IrqEventTokenRefreshComplete) {
2753 bail!(
2754 "received unexpected reply from IRQ handler thread: {:?}",
2755 resp
2756 );
2757 }
2758 }
2759
2760 let restore_duration_ms = restore_start.elapsed().as_millis();
2761 info!(
2762 "snapshot: completed restore in {}ms; mem size: {}",
2763 restore_duration_ms,
2764 vm.get_memory().memory_size(),
2765 );
2766
2767 metrics::log_metric_with_details(
2768 metrics::MetricEventType::SnapshotRestoreOverallLatency,
2769 restore_duration_ms as i64,
2770 &metrics_events::RecordDetails {},
2771 );
2772 Ok(())
2773}
2774
2775pub type HypervisorKind = hypervisor::HypervisorKind;
2776
2777#[derive(Serialize, Deserialize, Debug)]
2781#[must_use]
2782pub enum VmResponse {
2783 Ok,
2785 Err(SysError),
2787 ErrString(String),
2789 RegisterMemory { slot: u32 },
2791 RegisterMemory2 { region_id: u64 },
2793 #[cfg(feature = "balloon")]
2795 BalloonStats {
2796 stats: balloon_control::BalloonStats,
2797 balloon_actual: u64,
2798 },
2799 #[cfg(feature = "balloon")]
2801 BalloonWS {
2802 ws: balloon_control::BalloonWS,
2803 balloon_actual: u64,
2804 },
2805 #[cfg(feature = "pci-hotplug")]
2807 PciHotPlugResponse { bus: u8 },
2808 UsbResponse(UsbControlResult),
2810 GpuResponse(GpuControlResult),
2812 BatResponse(BatControlResult),
2814 SwapStatus(SwapStatus),
2816 DevicesState(DevicesState),
2818 VcpuPidTidResponse {
2820 pid_tid_map: BTreeMap<usize, (u32, u32)>,
2821 },
2822 VmDescriptor {
2823 hypervisor: HypervisorKind,
2824 vm_fd: SafeDescriptor,
2825 },
2826}
2827
2828impl Display for VmResponse {
2829 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2830 use self::VmResponse::*;
2831
2832 match self {
2833 Ok => write!(f, "ok"),
2834 Err(e) => write!(f, "error: {e}"),
2835 ErrString(e) => write!(f, "error: {e}"),
2836 RegisterMemory { slot } => write!(f, "memory registered in slot {slot}"),
2837 RegisterMemory2 { region_id } => {
2838 write!(f, "memory registered in region id {region_id}")
2839 }
2840 #[cfg(feature = "balloon")]
2841 VmResponse::BalloonStats {
2842 stats,
2843 balloon_actual,
2844 } => {
2845 write!(
2846 f,
2847 "stats: {}\nballoon_actual: {}",
2848 serde_json::to_string_pretty(&stats)
2849 .unwrap_or_else(|_| "invalid_response".to_string()),
2850 balloon_actual
2851 )
2852 }
2853 #[cfg(feature = "balloon")]
2854 VmResponse::BalloonWS { ws, balloon_actual } => {
2855 write!(
2856 f,
2857 "ws: {}, balloon_actual: {}",
2858 serde_json::to_string_pretty(&ws)
2859 .unwrap_or_else(|_| "invalid_response".to_string()),
2860 balloon_actual,
2861 )
2862 }
2863 UsbResponse(result) => write!(f, "usb control request get result {result:?}"),
2864 #[cfg(feature = "pci-hotplug")]
2865 PciHotPlugResponse { bus } => write!(f, "pci hotplug bus {bus:?}"),
2866 GpuResponse(result) => write!(f, "gpu control request result {result:?}"),
2867 BatResponse(result) => write!(f, "{result}"),
2868 SwapStatus(status) => {
2869 write!(
2870 f,
2871 "{}",
2872 serde_json::to_string(&status)
2873 .unwrap_or_else(|_| "invalid_response".to_string()),
2874 )
2875 }
2876 DevicesState(status) => write!(f, "devices status: {status:?}"),
2877 VcpuPidTidResponse { pid_tid_map } => write!(f, "vcpu pid tid map: {pid_tid_map:?}"),
2878 VmDescriptor { hypervisor, vm_fd } => {
2879 write!(f, "hypervisor: {hypervisor:?}, vm_fd: {vm_fd:?}")
2880 }
2881 }
2882 }
2883}
2884
2885#[derive(Serialize, Deserialize)]
2888pub enum ModifyWaitContext {
2889 Add(#[serde(with = "with_as_descriptor")] Descriptor),
2890}
2891
2892#[sorted]
2893#[derive(Error, Debug)]
2894pub enum VirtioIOMMUVfioError {
2895 #[error("socket failed")]
2896 SocketFailed,
2897 #[error("unexpected response: {0}")]
2898 UnexpectedResponse(VirtioIOMMUResponse),
2899 #[error("unknown command: `{0}`")]
2900 UnknownCommand(String),
2901 #[error("{0}")]
2902 VfioControl(VirtioIOMMUVfioResult),
2903}
2904
2905#[derive(Serialize, Deserialize, Debug)]
2906pub enum VirtioIOMMUVfioCommand {
2907 VfioDeviceAdd {
2909 endpoint_addr: u32,
2910 wrapper_id: u32,
2911 #[serde(with = "with_as_descriptor")]
2912 container: File,
2913 },
2914 VfioDeviceDel {
2916 endpoint_addr: u32,
2917 },
2918 VfioDmabufMap {
2920 region_id: VmMemoryRegionId,
2921 gpa: u64,
2922 size: u64,
2923 dma_buf: SafeDescriptor,
2924 },
2925 VfioDmabufUnmap(VmMemoryRegionId),
2927}
2928
2929#[derive(Serialize, Deserialize, Debug)]
2930pub enum VirtioIOMMUVfioResult {
2931 Ok,
2932 NotInPCIRanges,
2933 NoAvailableContainer,
2934 NoSuchDevice,
2935 NoSuchMappedDmabuf,
2936 InvalidParam,
2937}
2938
2939impl Display for VirtioIOMMUVfioResult {
2940 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2941 use self::VirtioIOMMUVfioResult::*;
2942
2943 match self {
2944 Ok => write!(f, "successfully"),
2945 NotInPCIRanges => write!(f, "not in the pci ranges of virtio-iommu"),
2946 NoAvailableContainer => write!(f, "no available vfio container"),
2947 NoSuchDevice => write!(f, "no such a vfio device"),
2948 NoSuchMappedDmabuf => write!(f, "no such a mapped dmabuf"),
2949 InvalidParam => write!(f, "invalid parameters"),
2950 }
2951 }
2952}
2953
2954#[derive(Serialize, Deserialize, Debug)]
2959pub enum VirtioIOMMURequest {
2960 VfioCommand(VirtioIOMMUVfioCommand),
2962}
2963
2964#[derive(Serialize, Deserialize, Debug)]
2969pub enum VirtioIOMMUResponse {
2970 Ok,
2972 Err(SysError),
2974 VfioResponse(VirtioIOMMUVfioResult),
2976}
2977
2978impl Display for VirtioIOMMUResponse {
2979 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2980 use self::VirtioIOMMUResponse::*;
2981 match self {
2982 Ok => write!(f, "ok"),
2983 Err(e) => write!(f, "error: {e}"),
2984 VfioResponse(result) => write!(
2985 f,
2986 "The vfio-related virtio-iommu request got result: {result:?}"
2987 ),
2988 }
2989 }
2990}
2991
2992pub fn virtio_iommu_request_async(
2994 iommu_control_tube: &Tube,
2995 req: &VirtioIOMMURequest,
2996) -> VirtioIOMMUResponse {
2997 match iommu_control_tube.send(&req) {
2998 Ok(_) => VirtioIOMMUResponse::Ok,
2999 Err(e) => {
3000 error!("virtio-iommu socket send failed: {:?}", e);
3001 VirtioIOMMUResponse::Err(SysError::last())
3002 }
3003 }
3004}
3005
3006pub type VirtioIOMMURequestResult = std::result::Result<VirtioIOMMUResponse, ()>;
3007
3008pub fn virtio_iommu_request(
3010 iommu_control_tube: &Tube,
3011 req: &VirtioIOMMURequest,
3012) -> VirtioIOMMURequestResult {
3013 let response = match virtio_iommu_request_async(iommu_control_tube, req) {
3014 VirtioIOMMUResponse::Ok => match iommu_control_tube.recv() {
3015 Ok(response) => response,
3016 Err(e) => {
3017 error!("virtio-iommu socket recv failed: {:?}", e);
3018 VirtioIOMMUResponse::Err(SysError::last())
3019 }
3020 },
3021 resp => resp,
3022 };
3023 Ok(response)
3024}
3025
3026#[cfg(test)]
3027mod tests {
3028 use anyhow::anyhow;
3029
3030 use super::*;
3031
3032 #[test]
3033 fn vm_memory_response_error_should_serialize_and_deserialize_correctly() {
3034 let source_error: VmMemoryResponseError = anyhow!("root cause")
3035 .context("context 1")
3036 .context("context 2")
3037 .into();
3038 let serialized_bytes =
3039 serde_json::to_vec(&source_error).expect("should serialize to json successfully");
3040 let target_error = serde_json::from_slice::<VmMemoryResponseError>(&serialized_bytes)
3041 .expect("should deserialize from json successfully");
3042 assert_eq!(source_error.0.to_string(), target_error.0.to_string());
3043 assert_eq!(
3044 source_error
3045 .0
3046 .chain()
3047 .map(ToString::to_string)
3048 .collect::<Vec<_>>(),
3049 target_error
3050 .0
3051 .chain()
3052 .map(ToString::to_string)
3053 .collect::<Vec<_>>()
3054 );
3055 }
3056
3057 #[test]
3058 fn vm_memory_response_error_deserialization_should_handle_malformat_correctly() {
3059 let flat_source = FlatVmMemoryResponseError(vec![]);
3060 let serialized_bytes =
3061 serde_json::to_vec(&flat_source).expect("should serialize to json successfully");
3062 serde_json::from_slice::<VmMemoryResponseError>(&serialized_bytes)
3063 .expect_err("deserialize with 0 error messages should fail");
3064 }
3065
3066 #[test]
3067 fn test_device_control_request_serde() {
3068 let req = DeviceControlRequest::Gpe {
3069 gpe: 5,
3070 clear_evt: None,
3071 };
3072 let bytes = serde_json::to_vec(&req).unwrap();
3073 let deserialized: DeviceControlRequest = serde_json::from_slice(&bytes).unwrap();
3074 match deserialized {
3075 DeviceControlRequest::Gpe { gpe, clear_evt } => {
3076 assert_eq!(gpe, 5);
3077 assert!(clear_evt.is_none());
3078 }
3079 _ => panic!("unexpected request variant"),
3080 }
3081
3082 let resp = DeviceControlResponse::Ok;
3083 let bytes = serde_json::to_vec(&resp).unwrap();
3084 let deserialized: DeviceControlResponse = serde_json::from_slice(&bytes).unwrap();
3085 match deserialized {
3086 DeviceControlResponse::Ok => {}
3087 _ => panic!("unexpected response variant"),
3088 }
3089
3090 let vm_req = VmRequest::DeviceControl(DeviceControlRequest::Gpe {
3091 gpe: 5,
3092 clear_evt: None,
3093 });
3094 let bytes = serde_json::to_vec(&vm_req).unwrap();
3095 let deserialized: VmRequest = serde_json::from_slice(&bytes).unwrap();
3096 match deserialized {
3097 VmRequest::DeviceControl(DeviceControlRequest::Gpe { gpe, clear_evt }) => {
3098 assert_eq!(gpe, 5);
3099 assert!(clear_evt.is_none());
3100 }
3101 _ => panic!("unexpected request variant"),
3102 }
3103 assert!(serde_json::from_slice::<DeviceControlRequest>(&bytes).is_err());
3105 }
3106}