1 // Copyright 2017 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 //! Handles IPC for controlling the main VM process.
6 //!
7 //! The VM Control IPC protocol is synchronous, meaning that each `VmRequest` sent over a connection
8 //! will receive a `VmResponse` for that request next time data is received over that connection.
9 //!
10 //! The wire message format is a little-endian C-struct of fixed size, along with a file descriptor
11 //! if the request type expects one.
12
13 #[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), feature = "gdb"))]
14 pub mod gdb;
15 #[cfg(feature = "gpu")]
16 pub mod gpu;
17
18 #[cfg(unix)]
19 use base::MemoryMappingBuilderUnix;
20 #[cfg(windows)]
21 use base::MemoryMappingBuilderWindows;
22
23 pub mod client;
24 pub mod display;
25 pub mod sys;
26
27 use std::collections::BTreeSet;
28 use std::convert::TryInto;
29 use std::fmt;
30 use std::fmt::Display;
31 use std::fs::File;
32 use std::path::PathBuf;
33 use std::result::Result as StdResult;
34 use std::str::FromStr;
35 use std::sync::mpsc;
36 use std::sync::Arc;
37
38 use anyhow::bail;
39 use anyhow::Context;
40 pub use balloon_control::BalloonStats;
41 #[cfg(feature = "balloon")]
42 use balloon_control::BalloonTubeCommand;
43 #[cfg(feature = "balloon")]
44 use balloon_control::BalloonTubeResult;
45 pub use balloon_control::BalloonWSS;
46 pub use balloon_control::WSSBucket;
47 use base::error;
48 use base::info;
49 use base::warn;
50 use base::with_as_descriptor;
51 use base::AsRawDescriptor;
52 use base::Error as SysError;
53 use base::Event;
54 use base::ExternalMapping;
55 use base::IntoRawDescriptor;
56 use base::MappedRegion;
57 use base::MemoryMappingBuilder;
58 use base::MmapError;
59 use base::Protection;
60 use base::Result;
61 use base::SafeDescriptor;
62 use base::SharedMemory;
63 use base::Tube;
64 use hypervisor::Datamatch;
65 use hypervisor::IoEventAddress;
66 use hypervisor::IrqRoute;
67 use hypervisor::IrqSource;
68 pub use hypervisor::MemSlot;
69 use hypervisor::VcpuSnapshot;
70 use hypervisor::Vm;
71 use libc::EINVAL;
72 use libc::EIO;
73 use libc::ENODEV;
74 use libc::ENOTSUP;
75 use libc::ERANGE;
76 use remain::sorted;
77 use resources::Alloc;
78 use resources::SystemAllocator;
79 use rutabaga_gfx::DeviceId;
80 use rutabaga_gfx::RutabagaDescriptor;
81 use rutabaga_gfx::RutabagaFromRawDescriptor;
82 use rutabaga_gfx::RutabagaGralloc;
83 use rutabaga_gfx::RutabagaHandle;
84 use rutabaga_gfx::RutabagaMappedRegion;
85 use rutabaga_gfx::VulkanInfo;
86 use serde::Deserialize;
87 use serde::Serialize;
88 use sync::Mutex;
89 #[cfg(unix)]
90 pub use sys::FsMappingRequest;
91 #[cfg(unix)]
92 pub use sys::VmMsyncRequest;
93 #[cfg(unix)]
94 pub use sys::VmMsyncResponse;
95 use thiserror::Error;
96 use vm_memory::GuestAddress;
97
98 use crate::display::AspectRatio;
99 use crate::display::DisplaySize;
100 use crate::display::GuestDisplayDensity;
101 use crate::display::MouseMode;
102 use crate::display::WindowEvent;
103 use crate::display::WindowMode;
104 use crate::display::WindowVisibility;
105 #[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), feature = "gdb"))]
106 pub use crate::gdb::VcpuDebug;
107 #[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), feature = "gdb"))]
108 pub use crate::gdb::VcpuDebugStatus;
109 #[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), feature = "gdb"))]
110 pub use crate::gdb::VcpuDebugStatusMessage;
111 #[cfg(feature = "gpu")]
112 use crate::gpu::GpuControlCommand;
113 #[cfg(feature = "gpu")]
114 use crate::gpu::GpuControlResult;
115
116 /// Control the state of a particular VM CPU.
117 #[derive(Clone, Debug)]
118 pub enum VcpuControl {
119 #[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), feature = "gdb"))]
120 Debug(VcpuDebug),
121 RunState(VmRunMode),
122 MakeRT,
123 // Request the current state of the vCPU. The result is sent back over the included channel.
124 GetStates(mpsc::Sender<VmRunMode>),
125 Snapshot(mpsc::Sender<anyhow::Result<VcpuSnapshot>>),
126 Restore(mpsc::Sender<anyhow::Result<()>>, Box<VcpuSnapshot>),
127 }
128
129 /// Mode of execution for the VM.
130 #[derive(Debug, Copy, Clone, Default, PartialEq, Eq)]
131 pub enum VmRunMode {
132 /// The default run mode indicating the VCPUs are running.
133 #[default]
134 Running,
135 /// Indicates that the VCPUs are suspending execution until the `Running` mode is set.
136 Suspending,
137 /// Indicates that the VM is exiting all processes.
138 Exiting,
139 /// Indicates that the VM is in a breakpoint waiting for the debugger to do continue.
140 Breakpoint,
141 }
142
143 impl Display for VmRunMode {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result144 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
145 use self::VmRunMode::*;
146
147 match self {
148 Running => write!(f, "running"),
149 Suspending => write!(f, "suspending"),
150 Exiting => write!(f, "exiting"),
151 Breakpoint => write!(f, "breakpoint"),
152 }
153 }
154 }
155
156 // Trait for devices that get notification on specific GPE trigger
157 pub trait GpeNotify: Send {
notify(&mut self)158 fn notify(&mut self) {}
159 }
160
161 // Trait for devices that get notification on specific PCI PME
162 pub trait PmeNotify: Send {
notify(&mut self, _requester_id: u16)163 fn notify(&mut self, _requester_id: u16) {}
164 }
165
166 pub trait PmResource {
pwrbtn_evt(&mut self)167 fn pwrbtn_evt(&mut self) {}
slpbtn_evt(&mut self)168 fn slpbtn_evt(&mut self) {}
rtc_evt(&mut self)169 fn rtc_evt(&mut self) {}
gpe_evt(&mut self, _gpe: u32)170 fn gpe_evt(&mut self, _gpe: u32) {}
pme_evt(&mut self, _requester_id: u16)171 fn pme_evt(&mut self, _requester_id: u16) {}
register_gpe_notify_dev(&mut self, _gpe: u32, _notify_dev: Arc<Mutex<dyn GpeNotify>>)172 fn register_gpe_notify_dev(&mut self, _gpe: u32, _notify_dev: Arc<Mutex<dyn GpeNotify>>) {}
register_pme_notify_dev(&mut self, _bus: u8, _notify_dev: Arc<Mutex<dyn PmeNotify>>)173 fn register_pme_notify_dev(&mut self, _bus: u8, _notify_dev: Arc<Mutex<dyn PmeNotify>>) {}
174 }
175
176 /// The maximum number of devices that can be listed in one `UsbControlCommand`.
177 ///
178 /// This value was set to be equal to `xhci_regs::MAX_PORTS` for convenience, but it is not
179 /// necessary for correctness. Importing that value directly would be overkill because it would
180 /// require adding a big dependency for a single const.
181 pub const USB_CONTROL_MAX_PORTS: usize = 16;
182
183 // Balloon commands that are sent on the crosvm control socket.
184 #[derive(Serialize, Deserialize, Debug)]
185 pub enum BalloonControlCommand {
186 /// Set the size of the VM's balloon.
187 Adjust {
188 num_bytes: u64,
189 },
190 Stats,
191 WorkingSetSize,
192 }
193
194 // BalloonControlResult holds results for BalloonControlCommand defined above.
195 #[derive(Serialize, Deserialize, Debug)]
196 pub enum BalloonControlResult {
197 Stats {
198 stats: BalloonStats,
199 balloon_actual: u64,
200 },
201 WorkingSetSize {
202 wss: BalloonWSS,
203 },
204 }
205
206 #[derive(Serialize, Deserialize, Debug)]
207 pub enum DiskControlCommand {
208 /// Resize a disk to `new_size` in bytes.
209 Resize { new_size: u64 },
210 }
211
212 impl Display for DiskControlCommand {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result213 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
214 use self::DiskControlCommand::*;
215
216 match self {
217 Resize { new_size } => write!(f, "disk_resize {}", new_size),
218 }
219 }
220 }
221
222 #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
223 pub enum DiskControlResult {
224 Ok,
225 Err(SysError),
226 }
227
228 #[derive(Serialize, Deserialize, Debug)]
229 pub enum UsbControlCommand {
230 AttachDevice {
231 #[serde(with = "with_as_descriptor")]
232 file: File,
233 },
234 DetachDevice {
235 port: u8,
236 },
237 ListDevice {
238 ports: [u8; USB_CONTROL_MAX_PORTS],
239 },
240 }
241
242 #[derive(Serialize, Deserialize, Copy, Clone, Debug, Default)]
243 pub struct UsbControlAttachedDevice {
244 pub port: u8,
245 pub vendor_id: u16,
246 pub product_id: u16,
247 }
248
249 impl UsbControlAttachedDevice {
valid(self) -> bool250 pub fn valid(self) -> bool {
251 self.port != 0
252 }
253 }
254
255 #[derive(Serialize, Deserialize, Debug, Clone)]
256 pub enum UsbControlResult {
257 Ok { port: u8 },
258 NoAvailablePort,
259 NoSuchDevice,
260 NoSuchPort,
261 FailedToOpenDevice,
262 Devices([UsbControlAttachedDevice; USB_CONTROL_MAX_PORTS]),
263 FailedToInitHostDevice,
264 }
265
266 impl Display for UsbControlResult {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result267 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
268 use self::UsbControlResult::*;
269
270 match self {
271 UsbControlResult::Ok { port } => write!(f, "ok {}", port),
272 NoAvailablePort => write!(f, "no_available_port"),
273 NoSuchDevice => write!(f, "no_such_device"),
274 NoSuchPort => write!(f, "no_such_port"),
275 FailedToOpenDevice => write!(f, "failed_to_open_device"),
276 Devices(devices) => {
277 write!(f, "devices")?;
278 for d in devices.iter().filter(|d| d.valid()) {
279 write!(f, " {} {:04x} {:04x}", d.port, d.vendor_id, d.product_id)?;
280 }
281 std::result::Result::Ok(())
282 }
283 FailedToInitHostDevice => write!(f, "failed_to_init_host_device"),
284 }
285 }
286 }
287
288 /// Commands for snapshot feature
289 #[derive(Serialize, Deserialize, Debug)]
290 pub enum SnapshotCommand {
291 Take { snapshot_path: PathBuf },
292 }
293
294 /// Commands for restore feature
295 #[derive(Serialize, Deserialize, Debug)]
296 pub enum RestoreCommand {
297 Apply { restore_path: PathBuf },
298 }
299
300 /// Commands for actions on devices and the devices control thread.
301 #[derive(Serialize, Deserialize, Debug)]
302 pub enum DeviceControlCommand {
303 SleepDevices,
304 WakeDevices,
305 SnapshotDevices { snapshot_path: PathBuf },
306 RestoreDevices { restore_path: PathBuf },
307 Exit,
308 }
309
310 /// Commands to control the IRQ handler thread.
311 #[derive(Serialize, Deserialize)]
312 pub enum IrqHandlerRequest {
313 /// No response is sent for this command.
314 AddIrqControlTubes(Vec<Tube>),
315 WakeAndNotifyIteration,
316 /// No response is sent for this command.
317 Exit,
318 }
319
320 const EXPECTED_MAX_IRQ_FLUSH_ITERATIONS: usize = 100;
321
322 /// Response for [IrqHandlerRequest].
323 #[derive(Serialize, Deserialize, Debug)]
324 pub enum IrqHandlerResponse {
325 /// Specifies the number of tokens serviced in the requested iteration
326 /// (less the token for the `WakeAndNotifyIteration` request).
327 HandlerIterationComplete(usize),
328 }
329
330 /// Source of a `VmMemoryRequest::RegisterMemory` mapping.
331 #[derive(Serialize, Deserialize)]
332 pub enum VmMemorySource {
333 /// Register shared memory represented by the given descriptor.
334 /// On Windows, descriptor MUST be a mapping handle.
335 SharedMemory(SharedMemory),
336 /// Register a file mapping from the given descriptor.
337 Descriptor {
338 /// File descriptor to map.
339 descriptor: SafeDescriptor,
340 /// Offset within the file in bytes.
341 offset: u64,
342 /// Size of the mapping in bytes.
343 size: u64,
344 },
345 /// Register memory mapped by Vulkano.
346 Vulkan {
347 descriptor: SafeDescriptor,
348 handle_type: u32,
349 memory_idx: u32,
350 device_id: DeviceId,
351 size: u64,
352 },
353 /// Register the current rutabaga external mapping.
354 ExternalMapping { ptr: u64, size: u64 },
355 }
356
357 // The following are wrappers to avoid base dependencies in the rutabaga crate
to_rutabaga_desciptor(s: SafeDescriptor) -> RutabagaDescriptor358 fn to_rutabaga_desciptor(s: SafeDescriptor) -> RutabagaDescriptor {
359 // Safe because we own the SafeDescriptor at this point.
360 unsafe { RutabagaDescriptor::from_raw_descriptor(s.into_raw_descriptor()) }
361 }
362
363 struct RutabagaMemoryRegion {
364 region: Box<dyn RutabagaMappedRegion>,
365 }
366
367 impl RutabagaMemoryRegion {
new(region: Box<dyn RutabagaMappedRegion>) -> RutabagaMemoryRegion368 pub fn new(region: Box<dyn RutabagaMappedRegion>) -> RutabagaMemoryRegion {
369 RutabagaMemoryRegion { region }
370 }
371 }
372
373 unsafe impl MappedRegion for RutabagaMemoryRegion {
as_ptr(&self) -> *mut u8374 fn as_ptr(&self) -> *mut u8 {
375 self.region.as_ptr()
376 }
377
size(&self) -> usize378 fn size(&self) -> usize {
379 self.region.size()
380 }
381 }
382
383 impl VmMemorySource {
384 /// Map the resource and return its mapping and size in bytes.
map( self, gralloc: &mut RutabagaGralloc, prot: Protection, ) -> Result<(Box<dyn MappedRegion>, u64, Option<SafeDescriptor>)>385 pub fn map(
386 self,
387 gralloc: &mut RutabagaGralloc,
388 prot: Protection,
389 ) -> Result<(Box<dyn MappedRegion>, u64, Option<SafeDescriptor>)> {
390 let (mem_region, size, descriptor) = match self {
391 VmMemorySource::Descriptor {
392 descriptor,
393 offset,
394 size,
395 } => (
396 map_descriptor(&descriptor, offset, size, prot)?,
397 size,
398 Some(descriptor),
399 ),
400
401 VmMemorySource::SharedMemory(shm) => {
402 (map_descriptor(&shm, 0, shm.size(), prot)?, shm.size(), None)
403 }
404 VmMemorySource::Vulkan {
405 descriptor,
406 handle_type,
407 memory_idx,
408 device_id,
409 size,
410 } => {
411 let mapped_region = match gralloc.import_and_map(
412 RutabagaHandle {
413 os_handle: to_rutabaga_desciptor(descriptor),
414 handle_type,
415 },
416 VulkanInfo {
417 memory_idx,
418 device_id,
419 },
420 size,
421 ) {
422 Ok(mapped_region) => {
423 let mapped_region: Box<dyn MappedRegion> =
424 Box::new(RutabagaMemoryRegion::new(mapped_region));
425 mapped_region
426 }
427 Err(e) => {
428 error!("gralloc failed to import and map: {}", e);
429 return Err(SysError::new(EINVAL));
430 }
431 };
432 (mapped_region, size, None)
433 }
434 VmMemorySource::ExternalMapping { ptr, size } => {
435 let mapped_region: Box<dyn MappedRegion> = Box::new(ExternalMapping {
436 ptr,
437 size: size as usize,
438 });
439 (mapped_region, size, None)
440 }
441 };
442 Ok((mem_region, size, descriptor))
443 }
444 }
445
446 /// Destination of a `VmMemoryRequest::RegisterMemory` mapping in guest address space.
447 #[derive(Serialize, Deserialize)]
448 pub enum VmMemoryDestination {
449 /// Map at an offset within an existing PCI BAR allocation.
450 ExistingAllocation { allocation: Alloc, offset: u64 },
451 /// Map at the specified guest physical address.
452 GuestPhysicalAddress(u64),
453 }
454
455 impl VmMemoryDestination {
456 /// Allocate and return the guest address of a memory mapping destination.
allocate(self, allocator: &mut SystemAllocator, size: u64) -> Result<GuestAddress>457 pub fn allocate(self, allocator: &mut SystemAllocator, size: u64) -> Result<GuestAddress> {
458 let addr = match self {
459 VmMemoryDestination::ExistingAllocation { allocation, offset } => allocator
460 .mmio_allocator_any()
461 .address_from_pci_offset(allocation, offset, size)
462 .map_err(|_e| SysError::new(EINVAL))?,
463 VmMemoryDestination::GuestPhysicalAddress(gpa) => gpa,
464 };
465 Ok(GuestAddress(addr))
466 }
467 }
468
469 /// Request to register or unregister an ioevent.
470 #[derive(Serialize, Deserialize)]
471 pub struct IoEventUpdateRequest {
472 pub event: Event,
473 pub addr: u64,
474 pub datamatch: Datamatch,
475 pub register: bool,
476 }
477
478 #[derive(Serialize, Deserialize)]
479 pub enum VmMemoryRequest {
480 RegisterMemory {
481 /// Source of the memory to register (mapped file descriptor, shared memory region, etc.)
482 source: VmMemorySource,
483 /// Where to map the memory in the guest.
484 dest: VmMemoryDestination,
485 /// Whether to map the memory read only (true) or read-write (false).
486 prot: Protection,
487 },
488 /// Call hypervisor to free the given memory range.
489 DynamicallyFreeMemoryRange {
490 guest_address: GuestAddress,
491 size: u64,
492 },
493 /// Call hypervisor to reclaim a priorly freed memory range.
494 DynamicallyReclaimMemoryRange {
495 guest_address: GuestAddress,
496 size: u64,
497 },
498 /// Unregister the given memory slot that was previously registered with `RegisterMemory`.
499 UnregisterMemory(MemSlot),
500 /// Register an ioeventfd by looking up using Alloc info.
501 IoEventWithAlloc {
502 evt: Event,
503 allocation: Alloc,
504 offset: u64,
505 datamatch: Datamatch,
506 register: bool,
507 },
508 /// Register an eventfd with raw guest memory address.
509 IoEventRaw(IoEventUpdateRequest),
510 }
511
512 /// Struct for managing `VmMemoryRequest`s IOMMU related state.
513 pub struct VmMemoryRequestIommuClient<'a> {
514 tube: &'a Tube,
515 gpu_memory: BTreeSet<MemSlot>,
516 }
517
518 impl<'a> VmMemoryRequestIommuClient<'a> {
519 /// Constructs `VmMemoryRequestIommuClient` from a tube for communication with the viommu.
new(tube: &'a Tube) -> Self520 pub fn new(tube: &'a Tube) -> Self {
521 Self {
522 tube,
523 gpu_memory: BTreeSet::new(),
524 }
525 }
526 }
527
528 impl VmMemoryRequest {
529 /// Executes this request on the given Vm.
530 ///
531 /// # Arguments
532 /// * `vm` - The `Vm` to perform the request on.
533 /// * `allocator` - Used to allocate addresses.
534 ///
535 /// This does not return a result, instead encapsulating the success or failure in a
536 /// `VmMemoryResponse` with the intended purpose of sending the response back over the socket
537 /// that received this `VmMemoryResponse`.
execute( self, vm: &mut impl Vm, sys_allocator: &mut SystemAllocator, gralloc: &mut RutabagaGralloc, iommu_client: Option<&mut VmMemoryRequestIommuClient>, ) -> VmMemoryResponse538 pub fn execute(
539 self,
540 vm: &mut impl Vm,
541 sys_allocator: &mut SystemAllocator,
542 gralloc: &mut RutabagaGralloc,
543 iommu_client: Option<&mut VmMemoryRequestIommuClient>,
544 ) -> VmMemoryResponse {
545 use self::VmMemoryRequest::*;
546 match self {
547 RegisterMemory { source, dest, prot } => {
548 // Correct on Windows because callers of this IPC guarantee descriptor is a mapping
549 // handle.
550 let (mapped_region, size, descriptor) = match source.map(gralloc, prot) {
551 Ok((region, size, descriptor)) => (region, size, descriptor),
552 Err(e) => return VmMemoryResponse::Err(e),
553 };
554
555 let guest_addr = match dest.allocate(sys_allocator, size) {
556 Ok(addr) => addr,
557 Err(e) => return VmMemoryResponse::Err(e),
558 };
559
560 let slot = match vm.add_memory_region(
561 guest_addr,
562 mapped_region,
563 prot == Protection::read(),
564 false,
565 ) {
566 Ok(slot) => slot,
567 Err(e) => return VmMemoryResponse::Err(e),
568 };
569
570 if let (Some(descriptor), Some(iommu_client)) = (descriptor, iommu_client) {
571 let request =
572 VirtioIOMMURequest::VfioCommand(VirtioIOMMUVfioCommand::VfioDmabufMap {
573 mem_slot: slot,
574 gfn: guest_addr.0 >> 12,
575 size,
576 dma_buf: descriptor,
577 });
578
579 match virtio_iommu_request(iommu_client.tube, &request) {
580 Ok(VirtioIOMMUResponse::VfioResponse(VirtioIOMMUVfioResult::Ok)) => (),
581 resp => {
582 error!("Unexpected message response: {:?}", resp);
583 // Ignore the result because there is nothing we can do with a failure.
584 let _ = vm.remove_memory_region(slot);
585 return VmMemoryResponse::Err(SysError::new(EINVAL));
586 }
587 };
588
589 iommu_client.gpu_memory.insert(slot);
590 }
591
592 let pfn = guest_addr.0 >> 12;
593 VmMemoryResponse::RegisterMemory { pfn, slot }
594 }
595 UnregisterMemory(slot) => match vm.remove_memory_region(slot) {
596 Ok(_) => {
597 if let Some(iommu_client) = iommu_client {
598 if iommu_client.gpu_memory.remove(&slot) {
599 let request = VirtioIOMMURequest::VfioCommand(
600 VirtioIOMMUVfioCommand::VfioDmabufUnmap(slot),
601 );
602
603 match virtio_iommu_request(iommu_client.tube, &request) {
604 Ok(VirtioIOMMUResponse::VfioResponse(
605 VirtioIOMMUVfioResult::Ok,
606 )) => VmMemoryResponse::Ok,
607 resp => {
608 error!("Unexpected message response: {:?}", resp);
609 VmMemoryResponse::Err(SysError::new(EINVAL))
610 }
611 }
612 } else {
613 VmMemoryResponse::Ok
614 }
615 } else {
616 VmMemoryResponse::Ok
617 }
618 }
619 Err(e) => VmMemoryResponse::Err(e),
620 },
621 DynamicallyFreeMemoryRange {
622 guest_address,
623 size,
624 } => match vm.handle_inflate(guest_address, size) {
625 Ok(_) => VmMemoryResponse::Ok,
626 Err(e) => VmMemoryResponse::Err(e),
627 },
628 DynamicallyReclaimMemoryRange {
629 guest_address,
630 size,
631 } => match vm.handle_deflate(guest_address, size) {
632 Ok(_) => VmMemoryResponse::Ok,
633 Err(e) => VmMemoryResponse::Err(e),
634 },
635 IoEventWithAlloc {
636 evt,
637 allocation,
638 offset,
639 datamatch,
640 register,
641 } => {
642 let len = match datamatch {
643 Datamatch::AnyLength => 1,
644 Datamatch::U8(_) => 1,
645 Datamatch::U16(_) => 2,
646 Datamatch::U32(_) => 4,
647 Datamatch::U64(_) => 8,
648 };
649 let addr = match sys_allocator
650 .mmio_allocator_any()
651 .address_from_pci_offset(allocation, offset, len)
652 {
653 Ok(addr) => addr,
654 Err(e) => {
655 error!("error getting target address: {:#}", e);
656 return VmMemoryResponse::Err(SysError::new(EINVAL));
657 }
658 };
659 let res = if register {
660 vm.register_ioevent(&evt, IoEventAddress::Mmio(addr), datamatch)
661 } else {
662 vm.unregister_ioevent(&evt, IoEventAddress::Mmio(addr), datamatch)
663 };
664 match res {
665 Ok(_) => VmMemoryResponse::Ok,
666 Err(e) => VmMemoryResponse::Err(e),
667 }
668 }
669 IoEventRaw(request) => {
670 let res = if request.register {
671 vm.register_ioevent(
672 &request.event,
673 IoEventAddress::Mmio(request.addr),
674 request.datamatch,
675 )
676 } else {
677 vm.unregister_ioevent(
678 &request.event,
679 IoEventAddress::Mmio(request.addr),
680 request.datamatch,
681 )
682 };
683 match res {
684 Ok(_) => VmMemoryResponse::Ok,
685 Err(e) => VmMemoryResponse::Err(e),
686 }
687 }
688 }
689 }
690 }
691
692 #[derive(Serialize, Deserialize, Debug)]
693 pub enum VmMemoryResponse {
694 /// The request to register memory into guest address space was successfully done at page frame
695 /// number `pfn` and memory slot number `slot`.
696 RegisterMemory {
697 pfn: u64,
698 slot: MemSlot,
699 },
700 Ok,
701 Err(SysError),
702 }
703
704 #[derive(Serialize, Deserialize, Debug)]
705 pub enum VmIrqRequest {
706 /// Allocate one gsi, and associate gsi to irqfd with register_irqfd()
707 AllocateOneMsi {
708 irqfd: Event,
709 device_id: u32,
710 queue_id: usize,
711 device_name: String,
712 },
713 /// Allocate a specific gsi to irqfd with register_irqfd(). This must only
714 /// be used when it is known that the gsi is free. Only the snapshot
715 /// subsystem can make this guarantee, and use of this request by any other
716 /// caller is strongly discouraged.
717 AllocateOneMsiAtGsi {
718 irqfd: Event,
719 gsi: u32,
720 device_id: u32,
721 queue_id: usize,
722 device_name: String,
723 },
724 /// Add one msi route entry into the IRQ chip.
725 AddMsiRoute {
726 gsi: u32,
727 msi_address: u64,
728 msi_data: u32,
729 },
730 // unregister_irqfs() and release gsi
731 ReleaseOneIrq {
732 gsi: u32,
733 irqfd: Event,
734 },
735 }
736
737 /// Data to set up an IRQ event or IRQ route on the IRQ chip.
738 /// VmIrqRequest::execute can't take an `IrqChip` argument, because of a dependency cycle between
739 /// devices and vm_control, so it takes a Fn that processes an `IrqSetup`.
740 pub enum IrqSetup<'a> {
741 Event(u32, &'a Event, u32, usize, String),
742 Route(IrqRoute),
743 UnRegister(u32, &'a Event),
744 }
745
746 impl VmIrqRequest {
747 /// Executes this request on the given Vm.
748 ///
749 /// # Arguments
750 /// * `set_up_irq` - A function that applies an `IrqSetup` to an IRQ chip.
751 ///
752 /// This does not return a result, instead encapsulating the success or failure in a
753 /// `VmIrqResponse` with the intended purpose of sending the response back over the socket
754 /// that received this `VmIrqResponse`.
execute<F>(&self, set_up_irq: F, sys_allocator: &mut SystemAllocator) -> VmIrqResponse where F: FnOnce(IrqSetup) -> Result<()>,755 pub fn execute<F>(&self, set_up_irq: F, sys_allocator: &mut SystemAllocator) -> VmIrqResponse
756 where
757 F: FnOnce(IrqSetup) -> Result<()>,
758 {
759 use self::VmIrqRequest::*;
760 match *self {
761 AllocateOneMsi {
762 ref irqfd,
763 device_id,
764 queue_id,
765 ref device_name,
766 } => {
767 if let Some(irq_num) = sys_allocator.allocate_irq() {
768 match set_up_irq(IrqSetup::Event(
769 irq_num,
770 irqfd,
771 device_id,
772 queue_id,
773 device_name.clone(),
774 )) {
775 Ok(_) => VmIrqResponse::AllocateOneMsi { gsi: irq_num },
776 Err(e) => VmIrqResponse::Err(e),
777 }
778 } else {
779 VmIrqResponse::Err(SysError::new(EINVAL))
780 }
781 }
782 AllocateOneMsiAtGsi {
783 ref irqfd,
784 gsi,
785 device_id,
786 queue_id,
787 ref device_name,
788 } => {
789 match set_up_irq(IrqSetup::Event(
790 gsi,
791 irqfd,
792 device_id,
793 queue_id,
794 device_name.clone(),
795 )) {
796 Ok(_) => VmIrqResponse::Ok,
797 Err(e) => VmIrqResponse::Err(e),
798 }
799 }
800 AddMsiRoute {
801 gsi,
802 msi_address,
803 msi_data,
804 } => {
805 let route = IrqRoute {
806 gsi,
807 source: IrqSource::Msi {
808 address: msi_address,
809 data: msi_data,
810 },
811 };
812 match set_up_irq(IrqSetup::Route(route)) {
813 Ok(_) => VmIrqResponse::Ok,
814 Err(e) => VmIrqResponse::Err(e),
815 }
816 }
817 ReleaseOneIrq { gsi, ref irqfd } => {
818 let _ = set_up_irq(IrqSetup::UnRegister(gsi, irqfd));
819 sys_allocator.release_irq(gsi);
820 VmIrqResponse::Ok
821 }
822 }
823 }
824 }
825
826 #[derive(Serialize, Deserialize, Debug)]
827 pub enum VmIrqResponse {
828 AllocateOneMsi { gsi: u32 },
829 Ok,
830 Err(SysError),
831 }
832
833 #[derive(Serialize, Deserialize, Debug, Clone)]
834 pub enum BatControlResult {
835 Ok,
836 NoBatDevice,
837 NoSuchHealth,
838 NoSuchProperty,
839 NoSuchStatus,
840 NoSuchBatType,
841 StringParseIntErr,
842 }
843
844 impl Display for BatControlResult {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result845 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
846 use self::BatControlResult::*;
847
848 match self {
849 Ok => write!(f, "Setting battery property successfully"),
850 NoBatDevice => write!(f, "No battery device created"),
851 NoSuchHealth => write!(f, "Invalid Battery health setting. Only support: unknown/good/overheat/dead/overvoltage/unexpectedfailure/cold/watchdogtimerexpire/safetytimerexpire/overcurrent"),
852 NoSuchProperty => write!(f, "Battery doesn't have such property. Only support: status/health/present/capacity/aconline"),
853 NoSuchStatus => write!(f, "Invalid Battery status setting. Only support: unknown/charging/discharging/notcharging/full"),
854 NoSuchBatType => write!(f, "Invalid Battery type setting. Only support: goldfish"),
855 StringParseIntErr => write!(f, "Battery property target ParseInt error"),
856 }
857 }
858 }
859
860 #[derive(Serialize, Deserialize, Copy, Clone, Debug, Default, PartialEq, Eq)]
861 #[serde(rename_all = "kebab-case")]
862 pub enum BatteryType {
863 #[default]
864 Goldfish,
865 }
866
867 impl FromStr for BatteryType {
868 type Err = BatControlResult;
869
from_str(s: &str) -> StdResult<Self, Self::Err>870 fn from_str(s: &str) -> StdResult<Self, Self::Err> {
871 match s {
872 "goldfish" => Ok(BatteryType::Goldfish),
873 _ => Err(BatControlResult::NoSuchBatType),
874 }
875 }
876 }
877
878 #[derive(Serialize, Deserialize, Debug)]
879 pub enum BatProperty {
880 Status,
881 Health,
882 Present,
883 Capacity,
884 ACOnline,
885 }
886
887 impl FromStr for BatProperty {
888 type Err = BatControlResult;
889
from_str(s: &str) -> StdResult<Self, Self::Err>890 fn from_str(s: &str) -> StdResult<Self, Self::Err> {
891 match s {
892 "status" => Ok(BatProperty::Status),
893 "health" => Ok(BatProperty::Health),
894 "present" => Ok(BatProperty::Present),
895 "capacity" => Ok(BatProperty::Capacity),
896 "aconline" => Ok(BatProperty::ACOnline),
897 _ => Err(BatControlResult::NoSuchProperty),
898 }
899 }
900 }
901
902 #[derive(Serialize, Deserialize, Debug)]
903 pub enum BatStatus {
904 Unknown,
905 Charging,
906 DisCharging,
907 NotCharging,
908 Full,
909 }
910
911 impl BatStatus {
new(status: String) -> std::result::Result<Self, BatControlResult>912 pub fn new(status: String) -> std::result::Result<Self, BatControlResult> {
913 match status.as_str() {
914 "unknown" => Ok(BatStatus::Unknown),
915 "charging" => Ok(BatStatus::Charging),
916 "discharging" => Ok(BatStatus::DisCharging),
917 "notcharging" => Ok(BatStatus::NotCharging),
918 "full" => Ok(BatStatus::Full),
919 _ => Err(BatControlResult::NoSuchStatus),
920 }
921 }
922 }
923
924 impl FromStr for BatStatus {
925 type Err = BatControlResult;
926
from_str(s: &str) -> StdResult<Self, Self::Err>927 fn from_str(s: &str) -> StdResult<Self, Self::Err> {
928 match s {
929 "unknown" => Ok(BatStatus::Unknown),
930 "charging" => Ok(BatStatus::Charging),
931 "discharging" => Ok(BatStatus::DisCharging),
932 "notcharging" => Ok(BatStatus::NotCharging),
933 "full" => Ok(BatStatus::Full),
934 _ => Err(BatControlResult::NoSuchStatus),
935 }
936 }
937 }
938
939 impl From<BatStatus> for u32 {
from(status: BatStatus) -> Self940 fn from(status: BatStatus) -> Self {
941 status as u32
942 }
943 }
944
945 #[derive(Serialize, Deserialize, Debug)]
946 pub enum BatHealth {
947 Unknown,
948 Good,
949 Overheat,
950 Dead,
951 OverVoltage,
952 UnexpectedFailure,
953 Cold,
954 WatchdogTimerExpire,
955 SafetyTimerExpire,
956 OverCurrent,
957 }
958
959 impl FromStr for BatHealth {
960 type Err = BatControlResult;
961
from_str(s: &str) -> StdResult<Self, Self::Err>962 fn from_str(s: &str) -> StdResult<Self, Self::Err> {
963 match s {
964 "unknown" => Ok(BatHealth::Unknown),
965 "good" => Ok(BatHealth::Good),
966 "overheat" => Ok(BatHealth::Overheat),
967 "dead" => Ok(BatHealth::Dead),
968 "overvoltage" => Ok(BatHealth::OverVoltage),
969 "unexpectedfailure" => Ok(BatHealth::UnexpectedFailure),
970 "cold" => Ok(BatHealth::Cold),
971 "watchdogtimerexpire" => Ok(BatHealth::WatchdogTimerExpire),
972 "safetytimerexpire" => Ok(BatHealth::SafetyTimerExpire),
973 "overcurrent" => Ok(BatHealth::OverCurrent),
974 _ => Err(BatControlResult::NoSuchHealth),
975 }
976 }
977 }
978
979 impl From<BatHealth> for u32 {
from(status: BatHealth) -> Self980 fn from(status: BatHealth) -> Self {
981 status as u32
982 }
983 }
984
985 #[derive(Serialize, Deserialize, Debug)]
986 pub enum BatControlCommand {
987 SetStatus(BatStatus),
988 SetHealth(BatHealth),
989 SetPresent(u32),
990 SetCapacity(u32),
991 SetACOnline(u32),
992 }
993
994 impl BatControlCommand {
new(property: String, target: String) -> std::result::Result<Self, BatControlResult>995 pub fn new(property: String, target: String) -> std::result::Result<Self, BatControlResult> {
996 let cmd = property.parse::<BatProperty>()?;
997 match cmd {
998 BatProperty::Status => Ok(BatControlCommand::SetStatus(target.parse::<BatStatus>()?)),
999 BatProperty::Health => Ok(BatControlCommand::SetHealth(target.parse::<BatHealth>()?)),
1000 BatProperty::Present => Ok(BatControlCommand::SetPresent(
1001 target
1002 .parse::<u32>()
1003 .map_err(|_| BatControlResult::StringParseIntErr)?,
1004 )),
1005 BatProperty::Capacity => Ok(BatControlCommand::SetCapacity(
1006 target
1007 .parse::<u32>()
1008 .map_err(|_| BatControlResult::StringParseIntErr)?,
1009 )),
1010 BatProperty::ACOnline => Ok(BatControlCommand::SetACOnline(
1011 target
1012 .parse::<u32>()
1013 .map_err(|_| BatControlResult::StringParseIntErr)?,
1014 )),
1015 }
1016 }
1017 }
1018
1019 /// Used for VM to control battery properties.
1020 pub struct BatControl {
1021 pub type_: BatteryType,
1022 pub control_tube: Tube,
1023 }
1024
1025 // Used to mark hotplug pci device's device type
1026 #[derive(Serialize, Deserialize, Debug, Clone)]
1027 pub enum HotPlugDeviceType {
1028 UpstreamPort,
1029 DownstreamPort,
1030 EndPoint,
1031 }
1032
1033 // Used for VM to hotplug pci devices
1034 #[derive(Serialize, Deserialize, Debug, Clone)]
1035 pub struct HotPlugDeviceInfo {
1036 pub device_type: HotPlugDeviceType,
1037 pub path: PathBuf,
1038 pub hp_interrupt: bool,
1039 }
1040
1041 /// Message for communicating a suspend or resume to the virtio-pvclock device.
1042 #[derive(Serialize, Deserialize, Debug)]
1043 pub enum PvClockCommand {
1044 Suspend,
1045 Resume,
1046 }
1047
1048 /// Message used by virtio-pvclock to communicate command results.
1049 #[derive(Serialize, Deserialize, Debug)]
1050 pub enum PvClockCommandResponse {
1051 Ok,
1052 Err(SysError),
1053 }
1054
1055 /// Commands for vmm-swap feature
1056 #[derive(Serialize, Deserialize, Debug)]
1057 pub enum SwapCommand {
1058 Enable,
1059 Trim,
1060 SwapOut,
1061 Disable,
1062 Status,
1063 }
1064
1065 cfg_if::cfg_if! {
1066 if #[cfg(feature = "swap")] {
1067 use swap::Status as SwapStatus;
1068 } else {
1069 #[derive(Serialize, Deserialize, Debug, Clone)]
1070 pub enum SwapStatus {}
1071 }
1072 }
1073
1074 ///
1075 /// A request to the main process to perform some operation on the VM.
1076 ///
1077 /// Unless otherwise noted, each request should expect a `VmResponse::Ok` to be received on success.
1078 #[derive(Serialize, Deserialize, Debug)]
1079 pub enum VmRequest {
1080 /// Break the VM's run loop and exit.
1081 Exit,
1082 /// Trigger a power button event in the guest.
1083 Powerbtn,
1084 /// Trigger a sleep button event in the guest.
1085 Sleepbtn,
1086 /// Trigger a RTC interrupt in the guest.
1087 Rtc,
1088 /// Suspend the VM's VCPUs until resume.
1089 Suspend,
1090 /// Swap the memory content into files on a disk
1091 Swap(SwapCommand),
1092 /// Resume the VM's VCPUs that were previously suspended.
1093 Resume,
1094 /// Inject a general-purpose event.
1095 Gpe(u32),
1096 /// Inject a PCI PME
1097 PciPme(u16),
1098 /// Make the VM's RT VCPU real-time.
1099 MakeRT,
1100 /// Command for balloon driver.
1101 BalloonCommand(BalloonControlCommand),
1102 /// Send a command to a disk chosen by `disk_index`.
1103 /// `disk_index` is a 0-based count of `--disk`, `--rwdisk`, and `-r` command-line options.
1104 DiskCommand {
1105 disk_index: usize,
1106 command: DiskControlCommand,
1107 },
1108 /// Command to use controller.
1109 UsbCommand(UsbControlCommand),
1110 #[cfg(feature = "gpu")]
1111 /// Command to modify the gpu.
1112 GpuCommand(GpuControlCommand),
1113 /// Command to set battery.
1114 BatCommand(BatteryType, BatControlCommand),
1115 /// Command to add/remove multiple pci devices
1116 HotPlugCommand {
1117 device: HotPlugDeviceInfo,
1118 add: bool,
1119 },
1120 /// Command to Snapshot devices
1121 Snapshot(SnapshotCommand),
1122 /// Command to Restore devices
1123 Restore(RestoreCommand),
1124 /// Register for event notification
1125 RegisterListener {
1126 socket_addr: String,
1127 event: RegisteredEvent,
1128 },
1129 /// Unregister for notifications for event
1130 UnregisterListener {
1131 socket_addr: String,
1132 event: RegisteredEvent,
1133 },
1134 /// Unregister for all event notification
1135 Unregister { socket_addr: String },
1136 }
1137
1138 /// NOTE: when making any changes to this enum please also update
1139 /// RegisteredEventFfi in crosvm_control/src/lib.rs
1140 #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone, Copy)]
1141 pub enum RegisteredEvent {
1142 VirtioBalloonWssReport,
1143 VirtioBalloonResize,
1144 VirtioBalloonOOMDeflation,
1145 }
1146
handle_disk_command(command: &DiskControlCommand, disk_host_tube: &Tube) -> VmResponse1147 pub fn handle_disk_command(command: &DiskControlCommand, disk_host_tube: &Tube) -> VmResponse {
1148 // Forward the request to the block device process via its control socket.
1149 if let Err(e) = disk_host_tube.send(command) {
1150 error!("disk socket send failed: {}", e);
1151 return VmResponse::Err(SysError::new(EINVAL));
1152 }
1153
1154 // Wait for the disk control command to be processed
1155 match disk_host_tube.recv() {
1156 Ok(DiskControlResult::Ok) => VmResponse::Ok,
1157 Ok(DiskControlResult::Err(e)) => VmResponse::Err(e),
1158 Err(e) => {
1159 error!("disk socket recv failed: {}", e);
1160 VmResponse::Err(SysError::new(EINVAL))
1161 }
1162 }
1163 }
1164
1165 /// WARNING: descriptor must be a mapping handle on Windows.
map_descriptor( descriptor: &dyn AsRawDescriptor, offset: u64, size: u64, prot: Protection, ) -> Result<Box<dyn MappedRegion>>1166 fn map_descriptor(
1167 descriptor: &dyn AsRawDescriptor,
1168 offset: u64,
1169 size: u64,
1170 prot: Protection,
1171 ) -> Result<Box<dyn MappedRegion>> {
1172 let size: usize = size.try_into().map_err(|_e| SysError::new(ERANGE))?;
1173 match MemoryMappingBuilder::new(size)
1174 .from_descriptor(descriptor)
1175 .offset(offset)
1176 .protection(prot)
1177 .build()
1178 {
1179 Ok(mmap) => Ok(Box::new(mmap)),
1180 Err(MmapError::SystemCallFailed(e)) => Err(e),
1181 _ => Err(SysError::new(EINVAL)),
1182 }
1183 }
1184
1185 // Get vCPU state. vCPUs are expected to all hold the same state.
1186 // In this function, there may be a time where vCPUs are not
get_vcpu_state(kick_vcpus: impl Fn(VcpuControl), vcpu_num: usize) -> anyhow::Result<VmRunMode>1187 fn get_vcpu_state(kick_vcpus: impl Fn(VcpuControl), vcpu_num: usize) -> anyhow::Result<VmRunMode> {
1188 let (send_chan, recv_chan) = mpsc::channel();
1189 kick_vcpus(VcpuControl::GetStates(send_chan));
1190 if vcpu_num == 0 {
1191 bail!("vcpu_num is zero");
1192 }
1193 let mut current_mode_vec: Vec<VmRunMode> = Vec::new();
1194 for _ in 0..vcpu_num {
1195 match recv_chan.recv() {
1196 Ok(state) => current_mode_vec.push(state),
1197 Err(e) => {
1198 bail!("Failed to get vCPU state: {}", e);
1199 }
1200 };
1201 }
1202 let first_state = current_mode_vec[0];
1203 if first_state == VmRunMode::Exiting {
1204 panic!("Attempt to snapshot while exiting.");
1205 }
1206 if current_mode_vec.iter().any(|x| *x != first_state) {
1207 // We do not panic here. It could be that vCPUs are transitioning from one mode to another.
1208 bail!("Unknown VM state: vCPUs hold different states.");
1209 }
1210 Ok(first_state)
1211 }
1212
1213 /// A guard to guarantee that all the vCPUs are suspended during the scope.
1214 ///
1215 /// When this guard is dropped, it rolls back the state of CPUs.
1216 pub struct VcpuSuspendGuard<'a> {
1217 saved_run_mode: VmRunMode,
1218 kick_vcpus: &'a dyn Fn(VcpuControl),
1219 }
1220
1221 impl<'a> VcpuSuspendGuard<'a> {
1222 /// Check the all vCPU state and suspend the vCPUs if they are running.
1223 ///
1224 /// This returns [VcpuSuspendGuard] to rollback the vcpu state.
1225 ///
1226 /// # Arguments
1227 ///
1228 /// * `kick_vcpus` - A funtion to send [VcpuControl] message to all the vCPUs and interrupt
1229 /// them.
1230 /// * `vcpu_num` - The number of vCPUs.
new(kick_vcpus: &'a impl Fn(VcpuControl), vcpu_num: usize) -> anyhow::Result<Self>1231 pub fn new(kick_vcpus: &'a impl Fn(VcpuControl), vcpu_num: usize) -> anyhow::Result<Self> {
1232 // get initial vcpu state
1233 let saved_run_mode = get_vcpu_state(kick_vcpus, vcpu_num)?;
1234 match saved_run_mode {
1235 VmRunMode::Running => {
1236 kick_vcpus(VcpuControl::RunState(VmRunMode::Suspending));
1237 // Blocking call, waiting for response to ensure vCPU state was updated.
1238 // In case of failure, where a vCPU still has the state running, start up vcpus and
1239 // abort operation.
1240 let current_mode = get_vcpu_state(kick_vcpus, vcpu_num)?;
1241 if current_mode != VmRunMode::Suspending {
1242 kick_vcpus(VcpuControl::RunState(saved_run_mode));
1243 bail!("vCPUs failed to all suspend. Kicking back all vCPUs to their previous state: {saved_run_mode}");
1244 }
1245 }
1246 VmRunMode::Suspending => {
1247 // do nothing. keep the state suspending.
1248 }
1249 other => {
1250 bail!("vcpus are not in running/suspending state, but {}", other);
1251 }
1252 };
1253 Ok(Self {
1254 saved_run_mode,
1255 kick_vcpus,
1256 })
1257 }
1258 }
1259
1260 impl Drop for VcpuSuspendGuard<'_> {
drop(&mut self)1261 fn drop(&mut self) {
1262 if self.saved_run_mode != VmRunMode::Suspending {
1263 (self.kick_vcpus)(VcpuControl::RunState(self.saved_run_mode));
1264 }
1265 }
1266 }
1267
1268 /// A guard to guarantee that all devices are sleeping during its scope.
1269 ///
1270 /// When this guard is dropped, it wakes the devices.
1271 pub struct DeviceSleepGuard<'a> {
1272 device_control_tube: &'a Tube,
1273 }
1274
1275 impl<'a> DeviceSleepGuard<'a> {
new(device_control_tube: &'a Tube) -> anyhow::Result<Self>1276 fn new(device_control_tube: &'a Tube) -> anyhow::Result<Self> {
1277 device_control_tube
1278 .send(&DeviceControlCommand::SleepDevices)
1279 .context("send command to devices control socket")?;
1280 match device_control_tube
1281 .recv()
1282 .context("receive from devices control socket")?
1283 {
1284 VmResponse::Ok => (),
1285 resp => bail!("device sleep failed: {}", resp),
1286 }
1287 Ok(Self {
1288 device_control_tube,
1289 })
1290 }
1291 }
1292
1293 impl Drop for DeviceSleepGuard<'_> {
drop(&mut self)1294 fn drop(&mut self) {
1295 if let Err(e) = self
1296 .device_control_tube
1297 .send(&DeviceControlCommand::WakeDevices)
1298 {
1299 panic!("failed to request device wake after snapshot: {}", e);
1300 }
1301 match self.device_control_tube.recv() {
1302 Ok(VmResponse::Ok) => (),
1303 Ok(resp) => panic!("unexpected response to device wake request: {}", resp),
1304 Err(e) => panic!("failed to get reply for device wake request: {}", e),
1305 }
1306 }
1307 }
1308
1309 impl VmRequest {
1310 /// Executes this request on the given Vm and other mutable state.
1311 ///
1312 /// This does not return a result, instead encapsulating the success or failure in a
1313 /// `VmResponse` with the intended purpose of sending the response back over the socket that
1314 /// received this `VmRequest`.
execute( &self, run_mode: &mut Option<VmRunMode>, #[cfg(feature = "balloon")] balloon_host_tube: Option<&Tube>, #[cfg(feature = "balloon")] balloon_wss_host_tube: Option<&Tube>, #[cfg(feature = "balloon")] balloon_stats_id: &mut u64, #[cfg(feature = "balloon")] balloon_wss_id: &mut u64, disk_host_tubes: &[Tube], pm: &mut Option<Arc<Mutex<dyn PmResource + Send>>>, #[cfg(feature = "gpu")] gpu_control_tube: &Tube, usb_control_tube: Option<&Tube>, bat_control: &mut Option<BatControl>, kick_vcpus: impl Fn(VcpuControl), kick_vcpu: impl Fn(VcpuControl, usize), force_s2idle: bool, #[cfg(feature = "swap")] swap_controller: Option<&swap::SwapController>, device_control_tube: &Tube, vcpu_size: usize, irq_handler_control: &Tube, ) -> VmResponse1315 pub fn execute(
1316 &self,
1317 run_mode: &mut Option<VmRunMode>,
1318 #[cfg(feature = "balloon")] balloon_host_tube: Option<&Tube>,
1319 #[cfg(feature = "balloon")] balloon_wss_host_tube: Option<&Tube>,
1320 #[cfg(feature = "balloon")] balloon_stats_id: &mut u64,
1321 #[cfg(feature = "balloon")] balloon_wss_id: &mut u64,
1322 disk_host_tubes: &[Tube],
1323 pm: &mut Option<Arc<Mutex<dyn PmResource + Send>>>,
1324 #[cfg(feature = "gpu")] gpu_control_tube: &Tube,
1325 usb_control_tube: Option<&Tube>,
1326 bat_control: &mut Option<BatControl>,
1327 kick_vcpus: impl Fn(VcpuControl),
1328 kick_vcpu: impl Fn(VcpuControl, usize),
1329 force_s2idle: bool,
1330 #[cfg(feature = "swap")] swap_controller: Option<&swap::SwapController>,
1331 device_control_tube: &Tube,
1332 vcpu_size: usize,
1333 irq_handler_control: &Tube,
1334 ) -> VmResponse {
1335 match *self {
1336 VmRequest::Exit => {
1337 *run_mode = Some(VmRunMode::Exiting);
1338 VmResponse::Ok
1339 }
1340 VmRequest::Powerbtn => {
1341 if let Some(pm) = pm {
1342 pm.lock().pwrbtn_evt();
1343 VmResponse::Ok
1344 } else {
1345 error!("{:#?} not supported", *self);
1346 VmResponse::Err(SysError::new(ENOTSUP))
1347 }
1348 }
1349 VmRequest::Sleepbtn => {
1350 if let Some(pm) = pm {
1351 pm.lock().slpbtn_evt();
1352 VmResponse::Ok
1353 } else {
1354 error!("{:#?} not supported", *self);
1355 VmResponse::Err(SysError::new(ENOTSUP))
1356 }
1357 }
1358 VmRequest::Rtc => {
1359 if let Some(pm) = pm {
1360 pm.lock().rtc_evt();
1361 VmResponse::Ok
1362 } else {
1363 error!("{:#?} not supported", *self);
1364 VmResponse::Err(SysError::new(ENOTSUP))
1365 }
1366 }
1367 VmRequest::Suspend => {
1368 *run_mode = Some(VmRunMode::Suspending);
1369 VmResponse::Ok
1370 }
1371 VmRequest::Swap(SwapCommand::Enable) => {
1372 #[cfg(feature = "swap")]
1373 if let Some(swap_controller) = swap_controller {
1374 // Suspend all vcpus and devices while vmm-swap is enabling (move the guest
1375 // memory contents to the staging memory) to guarantee no processes other than
1376 // the swap monitor process access the guest memory.
1377 let _vcpu_guard = match VcpuSuspendGuard::new(&kick_vcpus, vcpu_size) {
1378 Ok(guard) => guard,
1379 Err(e) => {
1380 error!("failed to suspend vcpus: {:?}", e);
1381 return VmResponse::Err(SysError::new(EINVAL));
1382 }
1383 };
1384 // TODO(b/253386409): Use `devices::Suspendable::sleep()` instead of sending
1385 // `SIGSTOP` signal.
1386 let _devices_guard = match swap_controller.suspend_devices() {
1387 Ok(guard) => guard,
1388 Err(e) => {
1389 error!("failed to suspend devices: {:?}", e);
1390 return VmResponse::Err(SysError::new(EINVAL));
1391 }
1392 };
1393
1394 return match swap_controller.enable() {
1395 Ok(()) => VmResponse::Ok,
1396 Err(e) => {
1397 error!("swap enable failed: {}", e);
1398 VmResponse::Err(SysError::new(EINVAL))
1399 }
1400 };
1401 }
1402 VmResponse::Err(SysError::new(ENOTSUP))
1403 }
1404 VmRequest::Swap(SwapCommand::Trim) => {
1405 #[cfg(feature = "swap")]
1406 if let Some(swap_controller) = swap_controller {
1407 return match swap_controller.trim() {
1408 Ok(()) => VmResponse::Ok,
1409 Err(e) => {
1410 error!("swap trim failed: {}", e);
1411 VmResponse::Err(SysError::new(EINVAL))
1412 }
1413 };
1414 }
1415 VmResponse::Err(SysError::new(ENOTSUP))
1416 }
1417 VmRequest::Swap(SwapCommand::SwapOut) => {
1418 #[cfg(feature = "swap")]
1419 if let Some(swap_controller) = swap_controller {
1420 return match swap_controller.swap_out() {
1421 Ok(()) => VmResponse::Ok,
1422 Err(e) => {
1423 error!("swap out failed: {}", e);
1424 VmResponse::Err(SysError::new(EINVAL))
1425 }
1426 };
1427 }
1428 VmResponse::Err(SysError::new(ENOTSUP))
1429 }
1430 VmRequest::Swap(SwapCommand::Disable) => {
1431 #[cfg(feature = "swap")]
1432 if let Some(swap_controller) = swap_controller {
1433 return match swap_controller.disable() {
1434 Ok(()) => VmResponse::Ok,
1435 Err(e) => {
1436 error!("swap disable failed: {}", e);
1437 VmResponse::Err(SysError::new(EINVAL))
1438 }
1439 };
1440 }
1441 VmResponse::Err(SysError::new(ENOTSUP))
1442 }
1443 VmRequest::Swap(SwapCommand::Status) => {
1444 #[cfg(feature = "swap")]
1445 if let Some(swap_controller) = swap_controller {
1446 return match swap_controller.status() {
1447 Ok(status) => VmResponse::SwapStatus(status),
1448 Err(e) => {
1449 error!("swap status failed: {}", e);
1450 VmResponse::Err(SysError::new(EINVAL))
1451 }
1452 };
1453 }
1454 VmResponse::Err(SysError::new(ENOTSUP))
1455 }
1456 VmRequest::Resume => {
1457 *run_mode = Some(VmRunMode::Running);
1458
1459 if force_s2idle {
1460 // During resume also emulate powerbtn event which will allow to wakeup fully
1461 // suspended guest.
1462 if let Some(pm) = pm {
1463 pm.lock().pwrbtn_evt();
1464 } else {
1465 error!("triggering power btn during resume not supported");
1466 return VmResponse::Err(SysError::new(ENOTSUP));
1467 }
1468 }
1469
1470 VmResponse::Ok
1471 }
1472 VmRequest::Gpe(gpe) => {
1473 if let Some(pm) = pm.as_ref() {
1474 pm.lock().gpe_evt(gpe);
1475 VmResponse::Ok
1476 } else {
1477 error!("{:#?} not supported", *self);
1478 VmResponse::Err(SysError::new(ENOTSUP))
1479 }
1480 }
1481 VmRequest::PciPme(requester_id) => {
1482 if let Some(pm) = pm.as_ref() {
1483 pm.lock().pme_evt(requester_id);
1484 VmResponse::Ok
1485 } else {
1486 error!("{:#?} not supported", *self);
1487 VmResponse::Err(SysError::new(ENOTSUP))
1488 }
1489 }
1490 VmRequest::MakeRT => {
1491 kick_vcpus(VcpuControl::MakeRT);
1492 VmResponse::Ok
1493 }
1494 #[cfg(feature = "balloon")]
1495 VmRequest::BalloonCommand(BalloonControlCommand::Adjust { num_bytes }) => {
1496 if let Some(balloon_host_tube) = balloon_host_tube {
1497 match balloon_host_tube.send(&BalloonTubeCommand::Adjust {
1498 num_bytes,
1499 allow_failure: false,
1500 }) {
1501 Ok(_) => VmResponse::Ok,
1502 Err(_) => VmResponse::Err(SysError::last()),
1503 }
1504 } else {
1505 VmResponse::Err(SysError::new(ENOTSUP))
1506 }
1507 }
1508 #[cfg(feature = "balloon")]
1509 VmRequest::BalloonCommand(BalloonControlCommand::Stats) => {
1510 if let Some(balloon_host_tube) = balloon_host_tube {
1511 // NB: There are a few reasons stale balloon stats could be left
1512 // in balloon_host_tube:
1513 // - the send succeeds, but the recv fails because the device
1514 // is not ready yet. So when the device is ready, there are
1515 // extra stats requests queued.
1516 // - the send succeed, but the recv times out. When the device
1517 // does return the stats, there will be no consumer.
1518 //
1519 // To guard against this, add an `id` to the stats request. If
1520 // the id returned to us doesn't match, we keep trying to read
1521 // until it does.
1522 *balloon_stats_id = (*balloon_stats_id).wrapping_add(1);
1523 let sent_id = *balloon_stats_id;
1524 match balloon_host_tube.send(&BalloonTubeCommand::Stats { id: sent_id }) {
1525 Ok(_) => {
1526 loop {
1527 match balloon_host_tube.recv() {
1528 Ok(BalloonTubeResult::Stats {
1529 stats,
1530 balloon_actual,
1531 id,
1532 }) => {
1533 if sent_id != id {
1534 // Keep trying to get the fresh stats.
1535 continue;
1536 }
1537 break VmResponse::BalloonStats {
1538 stats,
1539 balloon_actual,
1540 };
1541 }
1542 Err(e) => {
1543 error!("balloon socket recv for stats failed: {}", e);
1544 break VmResponse::Err(SysError::last());
1545 }
1546 Ok(BalloonTubeResult::Adjusted { .. }) => {
1547 unreachable!("unexpected adjusted response")
1548 }
1549 Ok(BalloonTubeResult::WorkingSetSize { .. }) => {
1550 unreachable!("unexpected wss response")
1551 }
1552 }
1553 }
1554 }
1555 Err(_) => VmResponse::Err(SysError::last()),
1556 }
1557 } else {
1558 VmResponse::Err(SysError::new(ENOTSUP))
1559 }
1560 }
1561 #[cfg(feature = "balloon")]
1562 VmRequest::BalloonCommand(BalloonControlCommand::WorkingSetSize) => {
1563 if let Some(balloon_wss_host_tube) = balloon_wss_host_tube {
1564 // NB: There are a few reasons stale balloon wss could be left
1565 // in balloon_wss_host_tube:
1566 // - the send succeeds, but the recv fails because the device
1567 // is not ready yet. So when the device is ready, there are
1568 // extra ess requests queued.
1569 // - the send succeed, but the recv times out. When the device
1570 // does return the stats, there will be no consumer.
1571 //
1572 // To guard against this, add an `id` to the wss request. If
1573 // the id returned to us doesn't match, we keep trying to read
1574 // until it does.
1575 *balloon_wss_id = (*balloon_wss_id).wrapping_add(1);
1576 let sent_id = *balloon_wss_id;
1577 match balloon_wss_host_tube
1578 .send(&BalloonTubeCommand::WorkingSetSize { id: sent_id })
1579 {
1580 Ok(_) => {
1581 loop {
1582 match balloon_wss_host_tube.recv() {
1583 Ok(BalloonTubeResult::WorkingSetSize { wss, id }) => {
1584 if sent_id != id {
1585 // Keep trying to get fresh stats.
1586 continue;
1587 }
1588 break VmResponse::BalloonWSS { wss };
1589 }
1590 Err(e) => {
1591 error!("balloon socket recv for wss failed: {}", e);
1592 break VmResponse::Err(SysError::last());
1593 }
1594 Ok(BalloonTubeResult::Adjusted { .. }) => {
1595 unreachable!("unexpected adjusted response")
1596 }
1597 Ok(BalloonTubeResult::Stats { .. }) => {
1598 unreachable!("unexpected stats response")
1599 }
1600 }
1601 }
1602 }
1603 Err(_) => VmResponse::Err(SysError::last()),
1604 }
1605 } else {
1606 VmResponse::Err(SysError::new(ENOTSUP))
1607 }
1608 }
1609 #[cfg(not(feature = "balloon"))]
1610 VmRequest::BalloonCommand(_) => VmResponse::Err(SysError::new(ENOTSUP)),
1611 VmRequest::DiskCommand {
1612 disk_index,
1613 ref command,
1614 } => match &disk_host_tubes.get(disk_index) {
1615 Some(tube) => handle_disk_command(command, tube),
1616 None => VmResponse::Err(SysError::new(ENODEV)),
1617 },
1618 #[cfg(feature = "gpu")]
1619 VmRequest::GpuCommand(ref cmd) => {
1620 let res = gpu_control_tube.send(cmd);
1621 if let Err(e) = res {
1622 error!("fail to send command to gpu control socket: {}", e);
1623 return VmResponse::Err(SysError::new(EIO));
1624 }
1625 match gpu_control_tube.recv() {
1626 Ok(response) => VmResponse::GpuResponse(response),
1627 Err(e) => {
1628 error!("fail to recv command from gpu control socket: {}", e);
1629 VmResponse::Err(SysError::new(EIO))
1630 }
1631 }
1632 }
1633 VmRequest::UsbCommand(ref cmd) => {
1634 let usb_control_tube = match usb_control_tube {
1635 Some(t) => t,
1636 None => {
1637 error!("attempted to execute USB request without control tube");
1638 return VmResponse::Err(SysError::new(ENODEV));
1639 }
1640 };
1641 let res = usb_control_tube.send(cmd);
1642 if let Err(e) = res {
1643 error!("fail to send command to usb control socket: {}", e);
1644 return VmResponse::Err(SysError::new(EIO));
1645 }
1646 match usb_control_tube.recv() {
1647 Ok(response) => VmResponse::UsbResponse(response),
1648 Err(e) => {
1649 error!("fail to recv command from usb control socket: {}", e);
1650 VmResponse::Err(SysError::new(EIO))
1651 }
1652 }
1653 }
1654 VmRequest::BatCommand(type_, ref cmd) => {
1655 match bat_control {
1656 Some(battery) => {
1657 if battery.type_ != type_ {
1658 error!("ignored battery command due to battery type: expected {:?}, got {:?}", battery.type_, type_);
1659 return VmResponse::Err(SysError::new(EINVAL));
1660 }
1661
1662 let res = battery.control_tube.send(cmd);
1663 if let Err(e) = res {
1664 error!("fail to send command to bat control socket: {}", e);
1665 return VmResponse::Err(SysError::new(EIO));
1666 }
1667
1668 match battery.control_tube.recv() {
1669 Ok(response) => VmResponse::BatResponse(response),
1670 Err(e) => {
1671 error!("fail to recv command from bat control socket: {}", e);
1672 VmResponse::Err(SysError::new(EIO))
1673 }
1674 }
1675 }
1676 None => VmResponse::BatResponse(BatControlResult::NoBatDevice),
1677 }
1678 }
1679 VmRequest::HotPlugCommand { device: _, add: _ } => VmResponse::Ok,
1680 VmRequest::Snapshot(SnapshotCommand::Take { ref snapshot_path }) => {
1681 let f = || -> anyhow::Result<VmResponse> {
1682 let _vcpu_guard = VcpuSuspendGuard::new(&kick_vcpus, vcpu_size)?;
1683 let _device_guard = DeviceSleepGuard::new(device_control_tube)?;
1684
1685 // We want to flush all pending IRQs to the LAPICs. There are two cases:
1686 //
1687 // MSIs: these are directly delivered to the LAPIC. We must verify the handler
1688 // thread cycles once to deliver these interrupts.
1689 //
1690 // Legacy interrupts: in the case of a split IRQ chip, these interrupts may
1691 // flow through the userspace IOAPIC. If the hypervisor does not support
1692 // irqfds (e.g. WHPX), a single iteration will only flush the IRQ to the
1693 // IOAPIC. The underlying MSI will be asserted at this point, but if the
1694 // IRQ handler doesn't run another iteration, it won't be delivered to the
1695 // LAPIC. This is why we cycle the handler thread twice (doing so ensures we
1696 // process the underlying MSI).
1697 //
1698 // We can handle both of these cases by iterating until there are no tokens
1699 // serviced on the requested iteration. Note that in the legacy case, this
1700 // ensures at least two iterations.
1701 //
1702 // Note: within CrosVM, *all* interrupts are eventually converted into the
1703 // same mechanicism that MSIs use. This is why we say "underlying" MSI for
1704 // a legacy IRQ.
1705 let mut flush_attempts = 0;
1706 loop {
1707 irq_handler_control
1708 .send(&IrqHandlerRequest::WakeAndNotifyIteration)
1709 .context("failed to send flush command to IRQ handler thread")?;
1710 let resp = irq_handler_control
1711 .recv()
1712 .context("failed to recv flush response from IRQ handler thread")?;
1713 match resp {
1714 IrqHandlerResponse::HandlerIterationComplete(tokens_serviced) => {
1715 if tokens_serviced == 0 {
1716 break;
1717 }
1718 }
1719 }
1720 flush_attempts += 1;
1721 if flush_attempts > EXPECTED_MAX_IRQ_FLUSH_ITERATIONS {
1722 warn!("flushing IRQs for snapshot may be stalled after iteration {}, expected <= {} iterations", flush_attempts, EXPECTED_MAX_IRQ_FLUSH_ITERATIONS);
1723 }
1724 }
1725 info!("flushed IRQs in {} iterations", flush_attempts);
1726 let vcpu_path = snapshot_path.with_extension("vcpu");
1727 let cpu_file = File::create(&vcpu_path)
1728 .with_context(|| format!("failed to open path {}", vcpu_path.display()))?;
1729 let (send_chan, recv_chan) = mpsc::channel();
1730 kick_vcpus(VcpuControl::Snapshot(send_chan));
1731 // Validate all Vcpus snapshot successfully
1732 let mut cpu_vec = Vec::with_capacity(vcpu_size);
1733 for _ in 0..vcpu_size {
1734 match recv_chan
1735 .recv()
1736 .context("Failed to snapshot Vcpu, aborting snapshot")?
1737 {
1738 Ok(snap) => {
1739 cpu_vec.push(snap);
1740 }
1741 Err(e) => bail!("Failed to snapshot Vcpu, aborting snapshot: {}", e),
1742 }
1743 }
1744 serde_json::to_writer(cpu_file, &cpu_vec).expect("Failed to write Vcpu state");
1745 device_control_tube
1746 .send(&DeviceControlCommand::SnapshotDevices {
1747 snapshot_path: snapshot_path.clone(),
1748 })
1749 .context("send command to devices control socket")?;
1750 device_control_tube
1751 .recv()
1752 .context("receive from devices control socket")
1753 };
1754 match f() {
1755 Ok(r) => r,
1756 Err(e) => {
1757 error!("failed to handle snapshot: {:?}", e);
1758 VmResponse::Err(SysError::new(EIO))
1759 }
1760 }
1761 }
1762 VmRequest::Restore(RestoreCommand::Apply { ref restore_path }) => {
1763 match do_restore(
1764 restore_path.clone(),
1765 kick_vcpus,
1766 kick_vcpu,
1767 device_control_tube,
1768 vcpu_size,
1769 ) {
1770 Ok(()) => VmResponse::Ok,
1771 Err(e) => {
1772 error!("failed to handle restore: {:?}", e);
1773 VmResponse::Err(SysError::new(EIO))
1774 }
1775 }
1776 }
1777 VmRequest::RegisterListener {
1778 socket_addr: _,
1779 event: _,
1780 } => VmResponse::Ok,
1781 VmRequest::UnregisterListener {
1782 socket_addr: _,
1783 event: _,
1784 } => VmResponse::Ok,
1785 VmRequest::Unregister { socket_addr: _ } => VmResponse::Ok,
1786 }
1787 }
1788 }
1789
1790 /// Restore the VM to the snapshot at `restore_path`.
1791 ///
1792 /// Same as `VmRequest::execute` with a `VmRequest::Restore`. Exposed as a separate function
1793 /// because not all the `VmRequest::execute` arguments are available in the "cold restore" flow.
do_restore( restore_path: PathBuf, kick_vcpus: impl Fn(VcpuControl), kick_vcpu: impl Fn(VcpuControl, usize), device_control_tube: &Tube, vcpu_size: usize, ) -> anyhow::Result<()>1794 pub fn do_restore(
1795 restore_path: PathBuf,
1796 kick_vcpus: impl Fn(VcpuControl),
1797 kick_vcpu: impl Fn(VcpuControl, usize),
1798 device_control_tube: &Tube,
1799 vcpu_size: usize,
1800 ) -> anyhow::Result<()> {
1801 let _guard = VcpuSuspendGuard::new(&kick_vcpus, vcpu_size)?;
1802 let _device_guard = DeviceSleepGuard::new(device_control_tube)?;
1803 let vcpu_path = restore_path.with_extension("vcpu");
1804 let cpu_file = File::open(&vcpu_path)
1805 .with_context(|| format!("failed to open path {}", vcpu_path.display()))?;
1806 let vcpu_snapshots: Vec<VcpuSnapshot> = serde_json::from_reader(cpu_file)?;
1807 if vcpu_snapshots.len() != vcpu_size {
1808 bail!(
1809 "bad cpu count in snapshot: expected={} got={}",
1810 vcpu_size,
1811 vcpu_snapshots.len()
1812 );
1813 }
1814 let (send_chan, recv_chan) = mpsc::channel();
1815 for vcpu_snap in vcpu_snapshots {
1816 let vcpu_id = vcpu_snap.vcpu_id;
1817 kick_vcpu(
1818 VcpuControl::Restore(send_chan.clone(), Box::new(vcpu_snap)),
1819 vcpu_id,
1820 );
1821 }
1822 for _ in 0..vcpu_size {
1823 if let Err(e) = recv_chan.recv() {
1824 bail!("Failed to restore vcpu: {}", e);
1825 }
1826 }
1827 device_control_tube
1828 .send(&DeviceControlCommand::RestoreDevices { restore_path })
1829 .context("send command to devices control socket")?;
1830 let resp = device_control_tube
1831 .recv()
1832 .context("receive from devices control socket")?;
1833 match resp {
1834 VmResponse::Ok => Ok(()),
1835 _ => bail!("unexpected RestoreDevices response: {resp}"),
1836 }
1837 }
1838
1839 /// Indication of success or failure of a `VmRequest`.
1840 ///
1841 /// Success is usually indicated `VmResponse::Ok` unless there is data associated with the response.
1842 #[derive(Serialize, Deserialize, Debug, Clone)]
1843 #[must_use]
1844 pub enum VmResponse {
1845 /// Indicates the request was executed successfully.
1846 Ok,
1847 /// Indicates the request encountered some error during execution.
1848 Err(SysError),
1849 /// Indicates the request encountered some error during execution.
1850 ErrString(String),
1851 /// The request to register memory into guest address space was successfully done at page frame
1852 /// number `pfn` and memory slot number `slot`.
1853 RegisterMemory { pfn: u64, slot: u32 },
1854 /// Results of balloon control commands.
1855 BalloonStats {
1856 stats: BalloonStats,
1857 balloon_actual: u64,
1858 },
1859 /// Results of balloon WSS-R command
1860 BalloonWSS { wss: BalloonWSS },
1861 /// Results of usb control commands.
1862 UsbResponse(UsbControlResult),
1863 #[cfg(feature = "gpu")]
1864 /// Results of gpu control commands.
1865 GpuResponse(GpuControlResult),
1866 /// Results of battery control commands.
1867 BatResponse(BatControlResult),
1868 /// Results of swap status command.
1869 SwapStatus(SwapStatus),
1870 }
1871
1872 impl Display for VmResponse {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result1873 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1874 use self::VmResponse::*;
1875
1876 match self {
1877 Ok => write!(f, "ok"),
1878 Err(e) => write!(f, "error: {}", e),
1879 ErrString(e) => write!(f, "error: {}", e),
1880 RegisterMemory { pfn, slot } => write!(
1881 f,
1882 "memory registered to page frame number {:#x} and memory slot {}",
1883 pfn, slot
1884 ),
1885 VmResponse::BalloonStats {
1886 stats,
1887 balloon_actual,
1888 } => {
1889 write!(
1890 f,
1891 "stats: {}\nballoon_actual: {}",
1892 serde_json::to_string_pretty(&stats)
1893 .unwrap_or_else(|_| "invalid_response".to_string()),
1894 balloon_actual
1895 )
1896 }
1897 VmResponse::BalloonWSS { wss } => {
1898 write!(
1899 f,
1900 "wss: {}",
1901 serde_json::to_string_pretty(&wss)
1902 .unwrap_or_else(|_| "invalid_response".to_string())
1903 )
1904 }
1905 UsbResponse(result) => write!(f, "usb control request get result {:?}", result),
1906 #[cfg(feature = "gpu")]
1907 GpuResponse(result) => write!(f, "gpu control request result {:?}", result),
1908 BatResponse(result) => write!(f, "{}", result),
1909 SwapStatus(status) => {
1910 write!(
1911 f,
1912 "{}",
1913 serde_json::to_string(&status)
1914 .unwrap_or_else(|_| "invalid_response".to_string()),
1915 )
1916 }
1917 }
1918 }
1919 }
1920
1921 /// Enum that comes from the Gpu device that will be received by the main event loop.
1922 #[derive(Serialize, Deserialize, Debug)]
1923 pub enum GpuSendToService {
1924 SendWindowState {
1925 window_event: Option<WindowEvent>,
1926 hwnd: usize,
1927 visibility: WindowVisibility,
1928 mode: WindowMode,
1929 aspect_ratio: AspectRatio,
1930 // TODO(b/203662783): Once we make the controller decide the initial size, this can be removed.
1931 initial_guest_display_size: DisplaySize,
1932 recommended_guest_display_density: GuestDisplayDensity,
1933 },
1934 SendExitWindowRequest,
1935 SendMouseModeState {
1936 mouse_mode: MouseMode,
1937 },
1938 SendGpuDevice {
1939 description: String,
1940 },
1941 }
1942
1943 /// Enum that serves as a general purose Gpu device message that is sent to the main loop.
1944 #[derive(Serialize, Deserialize, Debug)]
1945 pub enum GpuSendToMain {
1946 // Send these messages to the controller.
1947 SendToService(GpuSendToService),
1948 // Send to Ac97 device to set mute state.
1949 MuteAc97(bool),
1950 }
1951
1952 /// Enum to send control requests to all Ac97 audio devices.
1953 #[derive(Serialize, Deserialize, Debug)]
1954 pub enum Ac97Control {
1955 Mute(bool),
1956 }
1957
1958 /// Enum that send controller Ipc requests from the main event loop to the GPU device.
1959 #[derive(Serialize, Deserialize, Debug)]
1960 pub enum ServiceSendToGpu {
1961 ShowWindow {
1962 mode: WindowMode,
1963 aspect_ratio: AspectRatio,
1964 guest_display_size: DisplaySize,
1965 },
1966 HideWindow,
1967 Shutdown,
1968 MouseInputMode {
1969 mouse_mode: MouseMode,
1970 },
1971 }
1972
1973 #[cfg(test)]
1974 mod tests {
1975 use base::Event;
1976
1977 use super::*;
1978
1979 #[test]
sock_send_recv_event()1980 fn sock_send_recv_event() {
1981 let (req, res) = Tube::pair().unwrap();
1982 let e1 = Event::new().unwrap();
1983 res.send(&e1).unwrap();
1984
1985 let recv_event: Event = req.recv().unwrap();
1986 recv_event.signal().unwrap();
1987 e1.wait().unwrap();
1988 }
1989 }
1990
1991 #[sorted]
1992 #[derive(Error, Debug)]
1993 pub enum VirtioIOMMUVfioError {
1994 #[error("socket failed")]
1995 SocketFailed,
1996 #[error("unexpected response: {0}")]
1997 UnexpectedResponse(VirtioIOMMUResponse),
1998 #[error("unknown command: `{0}`")]
1999 UnknownCommand(String),
2000 #[error("{0}")]
2001 VfioControl(VirtioIOMMUVfioResult),
2002 }
2003
2004 #[derive(Serialize, Deserialize, Debug)]
2005 pub enum VirtioIOMMUVfioCommand {
2006 // Add the vfio device attached to virtio-iommu.
2007 VfioDeviceAdd {
2008 endpoint_addr: u32,
2009 wrapper_id: u32,
2010 #[serde(with = "with_as_descriptor")]
2011 container: File,
2012 },
2013 // Delete the vfio device attached to virtio-iommu.
2014 VfioDeviceDel {
2015 endpoint_addr: u32,
2016 },
2017 // Map a dma-buf into vfio iommu table
2018 VfioDmabufMap {
2019 mem_slot: MemSlot,
2020 gfn: u64,
2021 size: u64,
2022 dma_buf: SafeDescriptor,
2023 },
2024 // Unmap a dma-buf from vfio iommu table
2025 VfioDmabufUnmap(MemSlot),
2026 }
2027
2028 #[derive(Serialize, Deserialize, Debug)]
2029 pub enum VirtioIOMMUVfioResult {
2030 Ok,
2031 NotInPCIRanges,
2032 NoAvailableContainer,
2033 NoSuchDevice,
2034 NoSuchMappedDmabuf,
2035 InvalidParam,
2036 }
2037
2038 impl Display for VirtioIOMMUVfioResult {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result2039 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2040 use self::VirtioIOMMUVfioResult::*;
2041
2042 match self {
2043 Ok => write!(f, "successfully"),
2044 NotInPCIRanges => write!(f, "not in the pci ranges of virtio-iommu"),
2045 NoAvailableContainer => write!(f, "no available vfio container"),
2046 NoSuchDevice => write!(f, "no such a vfio device"),
2047 NoSuchMappedDmabuf => write!(f, "no such a mapped dmabuf"),
2048 InvalidParam => write!(f, "invalid parameters"),
2049 }
2050 }
2051 }
2052
2053 /// A request to the virtio-iommu process to perform some operations.
2054 ///
2055 /// Unless otherwise noted, each request should expect a `VirtioIOMMUResponse::Ok` to be received on
2056 /// success.
2057 #[derive(Serialize, Deserialize, Debug)]
2058 pub enum VirtioIOMMURequest {
2059 /// Command for vfio related operations.
2060 VfioCommand(VirtioIOMMUVfioCommand),
2061 }
2062
2063 /// Indication of success or failure of a `VirtioIOMMURequest`.
2064 ///
2065 /// Success is usually indicated `VirtioIOMMUResponse::Ok` unless there is data associated with the
2066 /// response.
2067 #[derive(Serialize, Deserialize, Debug)]
2068 pub enum VirtioIOMMUResponse {
2069 /// Indicates the request was executed successfully.
2070 Ok,
2071 /// Indicates the request encountered some error during execution.
2072 Err(SysError),
2073 /// Results for Vfio commands.
2074 VfioResponse(VirtioIOMMUVfioResult),
2075 }
2076
2077 impl Display for VirtioIOMMUResponse {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result2078 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2079 use self::VirtioIOMMUResponse::*;
2080 match self {
2081 Ok => write!(f, "ok"),
2082 Err(e) => write!(f, "error: {}", e),
2083 VfioResponse(result) => write!(
2084 f,
2085 "The vfio-related virtio-iommu request got result: {:?}",
2086 result
2087 ),
2088 }
2089 }
2090 }
2091
2092 /// Send VirtioIOMMURequest without waiting for the response
virtio_iommu_request_async( iommu_control_tube: &Tube, req: &VirtioIOMMURequest, ) -> VirtioIOMMUResponse2093 pub fn virtio_iommu_request_async(
2094 iommu_control_tube: &Tube,
2095 req: &VirtioIOMMURequest,
2096 ) -> VirtioIOMMUResponse {
2097 match iommu_control_tube.send(&req) {
2098 Ok(_) => VirtioIOMMUResponse::Ok,
2099 Err(e) => {
2100 error!("virtio-iommu socket send failed: {:?}", e);
2101 VirtioIOMMUResponse::Err(SysError::last())
2102 }
2103 }
2104 }
2105
2106 pub type VirtioIOMMURequestResult = std::result::Result<VirtioIOMMUResponse, ()>;
2107
2108 /// Send VirtioIOMMURequest and wait to get the response
virtio_iommu_request( iommu_control_tube: &Tube, req: &VirtioIOMMURequest, ) -> VirtioIOMMURequestResult2109 pub fn virtio_iommu_request(
2110 iommu_control_tube: &Tube,
2111 req: &VirtioIOMMURequest,
2112 ) -> VirtioIOMMURequestResult {
2113 let response = match virtio_iommu_request_async(iommu_control_tube, req) {
2114 VirtioIOMMUResponse::Ok => match iommu_control_tube.recv() {
2115 Ok(response) => response,
2116 Err(e) => {
2117 error!("virtio-iommu socket recv failed: {:?}", e);
2118 VirtioIOMMUResponse::Err(SysError::last())
2119 }
2120 },
2121 resp => resp,
2122 };
2123 Ok(response)
2124 }
2125