1 // Copyright 2017 The Chromium OS Authors. All rights reserved.
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(target_arch = "x86_64", feature = "gdb"))]
14 pub mod gdb;
15
16 pub mod client;
17
18 use std::convert::TryInto;
19 use std::fmt::{self, Display};
20 use std::fs::File;
21 use std::os::raw::c_int;
22 use std::path::PathBuf;
23 use std::result::Result as StdResult;
24 use std::str::FromStr;
25 use std::sync::{mpsc, Arc};
26
27 use std::thread::JoinHandle;
28
29 use remain::sorted;
30 use thiserror::Error;
31
32 use libc::{EINVAL, EIO, ENODEV, ENOTSUP, ERANGE};
33 use serde::{Deserialize, Serialize};
34
35 pub use balloon_control::BalloonStats;
36 use balloon_control::{BalloonTubeCommand, BalloonTubeResult};
37
38 use base::{
39 error, with_as_descriptor, AsRawDescriptor, Error as SysError, Event, ExternalMapping,
40 FromRawDescriptor, IntoRawDescriptor, Killable, MappedRegion, MemoryMappingArena,
41 MemoryMappingBuilder, MemoryMappingBuilderUnix, MmapError, Protection, Result, SafeDescriptor,
42 SharedMemory, Tube, SIGRTMIN,
43 };
44 use hypervisor::{IrqRoute, IrqSource, Vm};
45 use resources::{Alloc, MmioType, SystemAllocator};
46 use rutabaga_gfx::{
47 DrmFormat, ImageAllocationInfo, RutabagaGralloc, RutabagaGrallocFlags, RutabagaHandle,
48 VulkanInfo,
49 };
50 use sync::Mutex;
51 use vm_memory::GuestAddress;
52
53 /// Struct that describes the offset and stride of a plane located in GPU memory.
54 #[derive(Clone, Copy, Debug, PartialEq, Default, Serialize, Deserialize)]
55 pub struct GpuMemoryPlaneDesc {
56 pub stride: u32,
57 pub offset: u32,
58 }
59
60 /// Struct that describes a GPU memory allocation that consists of up to 3 planes.
61 #[derive(Clone, Copy, Debug, Default, Serialize, Deserialize)]
62 pub struct GpuMemoryDesc {
63 pub planes: [GpuMemoryPlaneDesc; 3],
64 }
65
66 #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
67 pub use crate::gdb::*;
68 pub use hypervisor::MemSlot;
69
70 /// Control the state of a particular VM CPU.
71 #[derive(Clone, Debug)]
72 pub enum VcpuControl {
73 #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
74 Debug(VcpuDebug),
75 RunState(VmRunMode),
76 MakeRT,
77 }
78
79 /// Mode of execution for the VM.
80 #[derive(Debug, Clone, PartialEq)]
81 pub enum VmRunMode {
82 /// The default run mode indicating the VCPUs are running.
83 Running,
84 /// Indicates that the VCPUs are suspending execution until the `Running` mode is set.
85 Suspending,
86 /// Indicates that the VM is exiting all processes.
87 Exiting,
88 /// Indicates that the VM is in a breakpoint waiting for the debugger to do continue.
89 Breakpoint,
90 }
91
92 impl Display for VmRunMode {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result93 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
94 use self::VmRunMode::*;
95
96 match self {
97 Running => write!(f, "running"),
98 Suspending => write!(f, "suspending"),
99 Exiting => write!(f, "exiting"),
100 Breakpoint => write!(f, "breakpoint"),
101 }
102 }
103 }
104
105 impl Default for VmRunMode {
default() -> Self106 fn default() -> Self {
107 VmRunMode::Running
108 }
109 }
110
111 // Trait for devices that get notification on specific GPE trigger
112 pub trait GpeNotify: Send {
notify(&mut self)113 fn notify(&mut self) {}
114 }
115
116 pub trait PmResource {
pwrbtn_evt(&mut self)117 fn pwrbtn_evt(&mut self) {}
gpe_evt(&mut self, _gpe: u32)118 fn gpe_evt(&mut self, _gpe: u32) {}
register_gpe_notify_dev(&mut self, _gpe: u32, _notify_dev: Arc<Mutex<dyn GpeNotify>>)119 fn register_gpe_notify_dev(&mut self, _gpe: u32, _notify_dev: Arc<Mutex<dyn GpeNotify>>) {}
120 }
121
122 /// The maximum number of devices that can be listed in one `UsbControlCommand`.
123 ///
124 /// This value was set to be equal to `xhci_regs::MAX_PORTS` for convenience, but it is not
125 /// necessary for correctness. Importing that value directly would be overkill because it would
126 /// require adding a big dependency for a single const.
127 pub const USB_CONTROL_MAX_PORTS: usize = 16;
128
129 // Balloon commands that are sent on the crosvm control socket.
130 #[derive(Serialize, Deserialize, Debug)]
131 pub enum BalloonControlCommand {
132 /// Set the size of the VM's balloon.
133 Adjust {
134 num_bytes: u64,
135 },
136 Stats,
137 }
138
139 // BalloonControlResult holds results for BalloonControlCommand defined above.
140 #[derive(Serialize, Deserialize, Debug)]
141 pub enum BalloonControlResult {
142 Stats {
143 stats: BalloonStats,
144 balloon_actual: u64,
145 },
146 }
147
148 #[derive(Serialize, Deserialize, Debug)]
149 pub enum DiskControlCommand {
150 /// Resize a disk to `new_size` in bytes.
151 Resize { new_size: u64 },
152 }
153
154 impl Display for DiskControlCommand {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result155 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
156 use self::DiskControlCommand::*;
157
158 match self {
159 Resize { new_size } => write!(f, "disk_resize {}", new_size),
160 }
161 }
162 }
163
164 #[derive(Serialize, Deserialize, Debug, Clone)]
165 pub enum DiskControlResult {
166 Ok,
167 Err(SysError),
168 }
169
170 #[derive(Serialize, Deserialize, Debug)]
171 pub enum UsbControlCommand {
172 AttachDevice {
173 bus: u8,
174 addr: u8,
175 vid: u16,
176 pid: u16,
177 #[serde(with = "with_as_descriptor")]
178 file: File,
179 },
180 DetachDevice {
181 port: u8,
182 },
183 ListDevice {
184 ports: [u8; USB_CONTROL_MAX_PORTS],
185 },
186 }
187
188 #[derive(Serialize, Deserialize, Copy, Clone, Debug, Default)]
189 pub struct UsbControlAttachedDevice {
190 pub port: u8,
191 pub vendor_id: u16,
192 pub product_id: u16,
193 }
194
195 impl UsbControlAttachedDevice {
valid(self) -> bool196 pub fn valid(self) -> bool {
197 self.port != 0
198 }
199 }
200
201 #[derive(Serialize, Deserialize, Debug)]
202 pub enum UsbControlResult {
203 Ok { port: u8 },
204 NoAvailablePort,
205 NoSuchDevice,
206 NoSuchPort,
207 FailedToOpenDevice,
208 Devices([UsbControlAttachedDevice; USB_CONTROL_MAX_PORTS]),
209 FailedToInitHostDevice,
210 }
211
212 impl Display for UsbControlResult {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result213 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
214 use self::UsbControlResult::*;
215
216 match self {
217 UsbControlResult::Ok { port } => write!(f, "ok {}", port),
218 NoAvailablePort => write!(f, "no_available_port"),
219 NoSuchDevice => write!(f, "no_such_device"),
220 NoSuchPort => write!(f, "no_such_port"),
221 FailedToOpenDevice => write!(f, "failed_to_open_device"),
222 Devices(devices) => {
223 write!(f, "devices")?;
224 for d in devices.iter().filter(|d| d.valid()) {
225 write!(f, " {} {:04x} {:04x}", d.port, d.vendor_id, d.product_id)?;
226 }
227 std::result::Result::Ok(())
228 }
229 FailedToInitHostDevice => write!(f, "failed_to_init_host_device"),
230 }
231 }
232 }
233
234 /// Source of a `VmMemoryRequest::RegisterMemory` mapping.
235 #[derive(Serialize, Deserialize)]
236 pub enum VmMemorySource {
237 /// Register shared memory represented by the given descriptor.
238 SharedMemory(SharedMemory),
239 /// Register a file mapping from the given descriptor.
240 Descriptor {
241 /// File descriptor to map.
242 descriptor: SafeDescriptor,
243 /// Offset within the file in bytes.
244 offset: u64,
245 /// Size of the mapping in bytes.
246 size: u64,
247 },
248 /// Register memory mapped by Vulkano.
249 Vulkan {
250 descriptor: SafeDescriptor,
251 handle_type: u32,
252 memory_idx: u32,
253 physical_device_idx: u32,
254 size: u64,
255 },
256 /// Register the current rutabaga external mapping.
257 ExternalMapping { size: u64 },
258 }
259
260 impl VmMemorySource {
261 /// Map the resource and return its mapping and size in bytes.
map( self, map_request: Arc<Mutex<Option<ExternalMapping>>>, gralloc: &mut RutabagaGralloc, read_only: bool, ) -> Result<(Box<dyn MappedRegion>, u64)>262 pub fn map(
263 self,
264 map_request: Arc<Mutex<Option<ExternalMapping>>>,
265 gralloc: &mut RutabagaGralloc,
266 read_only: bool,
267 ) -> Result<(Box<dyn MappedRegion>, u64)> {
268 let (mem_region, size) = match self {
269 VmMemorySource::Descriptor {
270 descriptor,
271 offset,
272 size,
273 } => (map_descriptor(&descriptor, offset, size, read_only)?, size),
274 VmMemorySource::SharedMemory(shm) => {
275 (map_descriptor(&shm, 0, shm.size(), read_only)?, shm.size())
276 }
277 VmMemorySource::Vulkan {
278 descriptor,
279 handle_type,
280 memory_idx,
281 physical_device_idx,
282 size,
283 } => {
284 let mapped_region = match gralloc.import_and_map(
285 RutabagaHandle {
286 os_handle: descriptor,
287 handle_type,
288 },
289 VulkanInfo {
290 memory_idx,
291 physical_device_idx,
292 },
293 size,
294 ) {
295 Ok(mapped_region) => mapped_region,
296 Err(e) => {
297 error!("gralloc failed to import and map: {}", e);
298 return Err(SysError::new(EINVAL));
299 }
300 };
301 (mapped_region, size)
302 }
303 VmMemorySource::ExternalMapping { size } => {
304 let mem = map_request
305 .lock()
306 .take()
307 .ok_or_else(|| VmMemoryResponse::Err(SysError::new(EINVAL)))
308 .unwrap();
309 let mapped_region: Box<dyn MappedRegion> = Box::new(mem);
310 (mapped_region, size)
311 }
312 };
313 Ok((mem_region, size))
314 }
315 }
316
317 /// Destination of a `VmMemoryRequest::RegisterMemory` mapping in guest address space.
318 #[derive(Serialize, Deserialize)]
319 pub enum VmMemoryDestination {
320 /// Map at an offset within an existing PCI BAR allocation.
321 ExistingAllocation { allocation: Alloc, offset: u64 },
322 /// Create a new anonymous allocation in MMIO space.
323 NewAllocation,
324 /// Map at the specified guest physical address.
325 GuestPhysicalAddress(u64),
326 }
327
328 impl VmMemoryDestination {
329 /// Allocate and return the guest address of a memory mapping destination.
allocate(self, allocator: &mut SystemAllocator, size: u64) -> Result<GuestAddress>330 pub fn allocate(self, allocator: &mut SystemAllocator, size: u64) -> Result<GuestAddress> {
331 let addr = match self {
332 VmMemoryDestination::ExistingAllocation { allocation, offset } => allocator
333 .mmio_allocator(MmioType::High)
334 .address_from_pci_offset(allocation, offset, size)
335 .map_err(|_e| SysError::new(EINVAL))?,
336 VmMemoryDestination::NewAllocation => {
337 let alloc = allocator.get_anon_alloc();
338 allocator
339 .mmio_allocator(MmioType::High)
340 .allocate(size, alloc, "vmcontrol_register_memory".to_string())
341 .map_err(|_e| SysError::new(EINVAL))?
342 }
343 VmMemoryDestination::GuestPhysicalAddress(gpa) => gpa,
344 };
345 Ok(GuestAddress(addr))
346 }
347 }
348
349 #[derive(Serialize, Deserialize)]
350 pub enum VmMemoryRequest {
351 RegisterMemory {
352 /// Source of the memory to register (mapped file descriptor, shared memory region, etc.)
353 source: VmMemorySource,
354 /// Where to map the memory in the guest.
355 dest: VmMemoryDestination,
356 /// Whether to map the memory read only (true) or read-write (false).
357 read_only: bool,
358 },
359 /// Allocate GPU buffer of a given size/format and register the memory into guest address space.
360 /// The response variant is `VmResponse::AllocateAndRegisterGpuMemory`
361 AllocateAndRegisterGpuMemory {
362 width: u32,
363 height: u32,
364 format: u32,
365 /// Where to map the memory in the guest.
366 dest: VmMemoryDestination,
367 },
368 /// Unregister the given memory slot that was previously registered with `RegisterMemory`.
369 UnregisterMemory(MemSlot),
370 }
371
372 impl VmMemoryRequest {
373 /// Executes this request on the given Vm.
374 ///
375 /// # Arguments
376 /// * `vm` - The `Vm` to perform the request on.
377 /// * `allocator` - Used to allocate addresses.
378 ///
379 /// This does not return a result, instead encapsulating the success or failure in a
380 /// `VmMemoryResponse` with the intended purpose of sending the response back over the socket
381 /// that received this `VmMemoryResponse`.
execute( self, vm: &mut impl Vm, sys_allocator: &mut SystemAllocator, map_request: Arc<Mutex<Option<ExternalMapping>>>, gralloc: &mut RutabagaGralloc, ) -> VmMemoryResponse382 pub fn execute(
383 self,
384 vm: &mut impl Vm,
385 sys_allocator: &mut SystemAllocator,
386 map_request: Arc<Mutex<Option<ExternalMapping>>>,
387 gralloc: &mut RutabagaGralloc,
388 ) -> VmMemoryResponse {
389 use self::VmMemoryRequest::*;
390 match self {
391 RegisterMemory {
392 source,
393 dest,
394 read_only,
395 } => {
396 let (mapped_region, size) = match source.map(map_request, gralloc, read_only) {
397 Ok((region, size)) => (region, size),
398 Err(e) => return VmMemoryResponse::Err(e),
399 };
400
401 let guest_addr = match dest.allocate(sys_allocator, size) {
402 Ok(addr) => addr,
403 Err(e) => return VmMemoryResponse::Err(e),
404 };
405
406 let slot = match vm.add_memory_region(guest_addr, mapped_region, read_only, false) {
407 Ok(slot) => slot,
408 Err(e) => return VmMemoryResponse::Err(e),
409 };
410 let pfn = guest_addr.0 >> 12;
411 VmMemoryResponse::RegisterMemory { pfn, slot }
412 }
413 UnregisterMemory(slot) => match vm.remove_memory_region(slot) {
414 Ok(_) => VmMemoryResponse::Ok,
415 Err(e) => VmMemoryResponse::Err(e),
416 },
417 AllocateAndRegisterGpuMemory {
418 width,
419 height,
420 format,
421 dest,
422 } => {
423 let (mapped_region, size, descriptor, gpu_desc) =
424 match Self::allocate_gpu_memory(gralloc, width, height, format) {
425 Ok(v) => v,
426 Err(e) => return VmMemoryResponse::Err(e),
427 };
428
429 let guest_addr = match dest.allocate(sys_allocator, size) {
430 Ok(addr) => addr,
431 Err(e) => return VmMemoryResponse::Err(e),
432 };
433
434 let slot = match vm.add_memory_region(guest_addr, mapped_region, false, false) {
435 Ok(slot) => slot,
436 Err(e) => return VmMemoryResponse::Err(e),
437 };
438 let pfn = guest_addr.0 >> 12;
439
440 VmMemoryResponse::AllocateAndRegisterGpuMemory {
441 descriptor,
442 pfn,
443 slot,
444 desc: gpu_desc,
445 }
446 }
447 }
448 }
449
allocate_gpu_memory( gralloc: &mut RutabagaGralloc, width: u32, height: u32, format: u32, ) -> Result<(Box<dyn MappedRegion>, u64, SafeDescriptor, GpuMemoryDesc)>450 fn allocate_gpu_memory(
451 gralloc: &mut RutabagaGralloc,
452 width: u32,
453 height: u32,
454 format: u32,
455 ) -> Result<(Box<dyn MappedRegion>, u64, SafeDescriptor, GpuMemoryDesc)> {
456 let img = ImageAllocationInfo {
457 width,
458 height,
459 drm_format: DrmFormat::from(format),
460 // Linear layout is a requirement as virtio wayland guest expects
461 // this for CPU access to the buffer. Scanout and texturing are
462 // optional as the consumer (wayland compositor) is expected to
463 // fall-back to a less efficient meachnisms for presentation if
464 // neccesary. In practice, linear buffers for commonly used formats
465 // will also support scanout and texturing.
466 flags: RutabagaGrallocFlags::empty().use_linear(true),
467 };
468
469 let reqs = match gralloc.get_image_memory_requirements(img) {
470 Ok(reqs) => reqs,
471 Err(e) => {
472 error!("gralloc failed to get image requirements: {}", e);
473 return Err(SysError::new(EINVAL));
474 }
475 };
476
477 let handle = match gralloc.allocate_memory(reqs) {
478 Ok(handle) => handle,
479 Err(e) => {
480 error!("gralloc failed to allocate memory: {}", e);
481 return Err(SysError::new(EINVAL));
482 }
483 };
484
485 let mut desc = GpuMemoryDesc::default();
486 for i in 0..3 {
487 desc.planes[i] = GpuMemoryPlaneDesc {
488 stride: reqs.strides[i],
489 offset: reqs.offsets[i],
490 }
491 }
492
493 // Safe because ownership is transferred to SafeDescriptor via
494 // into_raw_descriptor
495 let descriptor =
496 unsafe { SafeDescriptor::from_raw_descriptor(handle.os_handle.into_raw_descriptor()) };
497
498 let mapped_region = map_descriptor(&descriptor, 0, reqs.size, false)?;
499 Ok((mapped_region, reqs.size, descriptor, desc))
500 }
501 }
502
503 #[derive(Serialize, Deserialize, Debug)]
504 pub enum VmMemoryResponse {
505 /// The request to register memory into guest address space was successfully done at page frame
506 /// number `pfn` and memory slot number `slot`.
507 RegisterMemory {
508 pfn: u64,
509 slot: MemSlot,
510 },
511 /// The request to allocate and register GPU memory into guest address space was successfully
512 /// done at page frame number `pfn` and memory slot number `slot` for buffer with `desc`.
513 AllocateAndRegisterGpuMemory {
514 descriptor: SafeDescriptor,
515 pfn: u64,
516 slot: MemSlot,
517 desc: GpuMemoryDesc,
518 },
519 Ok,
520 Err(SysError),
521 }
522
523 #[derive(Serialize, Deserialize, Debug)]
524 pub enum VmIrqRequest {
525 /// Allocate one gsi, and associate gsi to irqfd with register_irqfd()
526 AllocateOneMsi {
527 irqfd: Event,
528 device_id: u32,
529 queue_id: usize,
530 device_name: String,
531 },
532 /// Add one msi route entry into the IRQ chip.
533 AddMsiRoute {
534 gsi: u32,
535 msi_address: u64,
536 msi_data: u32,
537 },
538 // unregister_irqfs() and release gsi
539 ReleaseOneIrq {
540 gsi: u32,
541 irqfd: Event,
542 },
543 }
544
545 /// Data to set up an IRQ event or IRQ route on the IRQ chip.
546 /// VmIrqRequest::execute can't take an `IrqChip` argument, because of a dependency cycle between
547 /// devices and vm_control, so it takes a Fn that processes an `IrqSetup`.
548 pub enum IrqSetup<'a> {
549 Event(u32, &'a Event, u32, usize, String),
550 Route(IrqRoute),
551 UnRegister(u32, &'a Event),
552 }
553
554 impl VmIrqRequest {
555 /// Executes this request on the given Vm.
556 ///
557 /// # Arguments
558 /// * `set_up_irq` - A function that applies an `IrqSetup` to an IRQ chip.
559 ///
560 /// This does not return a result, instead encapsulating the success or failure in a
561 /// `VmIrqResponse` with the intended purpose of sending the response back over the socket
562 /// that received this `VmIrqResponse`.
execute<F>(&self, set_up_irq: F, sys_allocator: &mut SystemAllocator) -> VmIrqResponse where F: FnOnce(IrqSetup) -> Result<()>,563 pub fn execute<F>(&self, set_up_irq: F, sys_allocator: &mut SystemAllocator) -> VmIrqResponse
564 where
565 F: FnOnce(IrqSetup) -> Result<()>,
566 {
567 use self::VmIrqRequest::*;
568 match *self {
569 AllocateOneMsi {
570 ref irqfd,
571 device_id,
572 queue_id,
573 ref device_name,
574 } => {
575 if let Some(irq_num) = sys_allocator.allocate_irq() {
576 match set_up_irq(IrqSetup::Event(
577 irq_num,
578 irqfd,
579 device_id,
580 queue_id,
581 device_name.clone(),
582 )) {
583 Ok(_) => VmIrqResponse::AllocateOneMsi { gsi: irq_num },
584 Err(e) => VmIrqResponse::Err(e),
585 }
586 } else {
587 VmIrqResponse::Err(SysError::new(EINVAL))
588 }
589 }
590 AddMsiRoute {
591 gsi,
592 msi_address,
593 msi_data,
594 } => {
595 let route = IrqRoute {
596 gsi,
597 source: IrqSource::Msi {
598 address: msi_address,
599 data: msi_data,
600 },
601 };
602 match set_up_irq(IrqSetup::Route(route)) {
603 Ok(_) => VmIrqResponse::Ok,
604 Err(e) => VmIrqResponse::Err(e),
605 }
606 }
607 ReleaseOneIrq { gsi, ref irqfd } => {
608 let _ = set_up_irq(IrqSetup::UnRegister(gsi, irqfd));
609 sys_allocator.release_irq(gsi);
610 VmIrqResponse::Ok
611 }
612 }
613 }
614 }
615
616 #[derive(Serialize, Deserialize, Debug)]
617 pub enum VmIrqResponse {
618 AllocateOneMsi { gsi: u32 },
619 Ok,
620 Err(SysError),
621 }
622
623 #[derive(Serialize, Deserialize, Debug)]
624 pub enum VmMsyncRequest {
625 /// Flush the content of a memory mapping to its backing file.
626 /// `slot` selects the arena (as returned by `Vm::add_mmap_arena`).
627 /// `offset` is the offset of the mapping to sync within the arena.
628 /// `size` is the size of the mapping to sync within the arena.
629 MsyncArena {
630 slot: MemSlot,
631 offset: usize,
632 size: usize,
633 },
634 }
635
636 #[derive(Serialize, Deserialize, Debug)]
637 pub enum VmMsyncResponse {
638 Ok,
639 Err(SysError),
640 }
641
642 impl VmMsyncRequest {
643 /// Executes this request on the given Vm.
644 ///
645 /// # Arguments
646 /// * `vm` - The `Vm` to perform the request on.
647 ///
648 /// This does not return a result, instead encapsulating the success or failure in a
649 /// `VmMsyncResponse` with the intended purpose of sending the response back over the socket
650 /// that received this `VmMsyncResponse`.
execute(&self, vm: &mut impl Vm) -> VmMsyncResponse651 pub fn execute(&self, vm: &mut impl Vm) -> VmMsyncResponse {
652 use self::VmMsyncRequest::*;
653 match *self {
654 MsyncArena { slot, offset, size } => match vm.msync_memory_region(slot, offset, size) {
655 Ok(()) => VmMsyncResponse::Ok,
656 Err(e) => VmMsyncResponse::Err(e),
657 },
658 }
659 }
660 }
661
662 #[derive(Serialize, Deserialize, Debug)]
663 pub enum BatControlResult {
664 Ok,
665 NoBatDevice,
666 NoSuchHealth,
667 NoSuchProperty,
668 NoSuchStatus,
669 NoSuchBatType,
670 StringParseIntErr,
671 }
672
673 impl Display for BatControlResult {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result674 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
675 use self::BatControlResult::*;
676
677 match self {
678 Ok => write!(f, "Setting battery property successfully"),
679 NoBatDevice => write!(f, "No battery device created"),
680 NoSuchHealth => write!(f, "Invalid Battery health setting. Only support: unknown/good/overheat/dead/overvoltage/unexpectedfailure/cold/watchdogtimerexpire/safetytimerexpire/overcurrent"),
681 NoSuchProperty => write!(f, "Battery doesn't have such property. Only support: status/health/present/capacity/aconline"),
682 NoSuchStatus => write!(f, "Invalid Battery status setting. Only support: unknown/charging/discharging/notcharging/full"),
683 NoSuchBatType => write!(f, "Invalid Battery type setting. Only support: goldfish"),
684 StringParseIntErr => write!(f, "Battery property target ParseInt error"),
685 }
686 }
687 }
688
689 #[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq)]
690 pub enum BatteryType {
691 Goldfish,
692 }
693
694 impl Default for BatteryType {
default() -> Self695 fn default() -> Self {
696 BatteryType::Goldfish
697 }
698 }
699
700 impl FromStr for BatteryType {
701 type Err = BatControlResult;
702
from_str(s: &str) -> StdResult<Self, Self::Err>703 fn from_str(s: &str) -> StdResult<Self, Self::Err> {
704 match s {
705 "goldfish" => Ok(BatteryType::Goldfish),
706 _ => Err(BatControlResult::NoSuchBatType),
707 }
708 }
709 }
710
711 #[derive(Serialize, Deserialize, Debug)]
712 pub enum BatProperty {
713 Status,
714 Health,
715 Present,
716 Capacity,
717 ACOnline,
718 }
719
720 impl FromStr for BatProperty {
721 type Err = BatControlResult;
722
from_str(s: &str) -> StdResult<Self, Self::Err>723 fn from_str(s: &str) -> StdResult<Self, Self::Err> {
724 match s {
725 "status" => Ok(BatProperty::Status),
726 "health" => Ok(BatProperty::Health),
727 "present" => Ok(BatProperty::Present),
728 "capacity" => Ok(BatProperty::Capacity),
729 "aconline" => Ok(BatProperty::ACOnline),
730 _ => Err(BatControlResult::NoSuchProperty),
731 }
732 }
733 }
734
735 #[derive(Serialize, Deserialize, Debug)]
736 pub enum BatStatus {
737 Unknown,
738 Charging,
739 DisCharging,
740 NotCharging,
741 Full,
742 }
743
744 impl BatStatus {
new(status: String) -> std::result::Result<Self, BatControlResult>745 pub fn new(status: String) -> std::result::Result<Self, BatControlResult> {
746 match status.as_str() {
747 "unknown" => Ok(BatStatus::Unknown),
748 "charging" => Ok(BatStatus::Charging),
749 "discharging" => Ok(BatStatus::DisCharging),
750 "notcharging" => Ok(BatStatus::NotCharging),
751 "full" => Ok(BatStatus::Full),
752 _ => Err(BatControlResult::NoSuchStatus),
753 }
754 }
755 }
756
757 impl FromStr for BatStatus {
758 type Err = BatControlResult;
759
from_str(s: &str) -> StdResult<Self, Self::Err>760 fn from_str(s: &str) -> StdResult<Self, Self::Err> {
761 match s {
762 "unknown" => Ok(BatStatus::Unknown),
763 "charging" => Ok(BatStatus::Charging),
764 "discharging" => Ok(BatStatus::DisCharging),
765 "notcharging" => Ok(BatStatus::NotCharging),
766 "full" => Ok(BatStatus::Full),
767 _ => Err(BatControlResult::NoSuchStatus),
768 }
769 }
770 }
771
772 impl From<BatStatus> for u32 {
from(status: BatStatus) -> Self773 fn from(status: BatStatus) -> Self {
774 status as u32
775 }
776 }
777
778 #[derive(Serialize, Deserialize, Debug)]
779 pub enum BatHealth {
780 Unknown,
781 Good,
782 Overheat,
783 Dead,
784 OverVoltage,
785 UnexpectedFailure,
786 Cold,
787 WatchdogTimerExpire,
788 SafetyTimerExpire,
789 OverCurrent,
790 }
791
792 impl FromStr for BatHealth {
793 type Err = BatControlResult;
794
from_str(s: &str) -> StdResult<Self, Self::Err>795 fn from_str(s: &str) -> StdResult<Self, Self::Err> {
796 match s {
797 "unknown" => Ok(BatHealth::Unknown),
798 "good" => Ok(BatHealth::Good),
799 "overheat" => Ok(BatHealth::Overheat),
800 "dead" => Ok(BatHealth::Dead),
801 "overvoltage" => Ok(BatHealth::OverVoltage),
802 "unexpectedfailure" => Ok(BatHealth::UnexpectedFailure),
803 "cold" => Ok(BatHealth::Cold),
804 "watchdogtimerexpire" => Ok(BatHealth::WatchdogTimerExpire),
805 "safetytimerexpire" => Ok(BatHealth::SafetyTimerExpire),
806 "overcurrent" => Ok(BatHealth::OverCurrent),
807 _ => Err(BatControlResult::NoSuchHealth),
808 }
809 }
810 }
811
812 impl From<BatHealth> for u32 {
from(status: BatHealth) -> Self813 fn from(status: BatHealth) -> Self {
814 status as u32
815 }
816 }
817
818 #[derive(Serialize, Deserialize, Debug)]
819 pub enum BatControlCommand {
820 SetStatus(BatStatus),
821 SetHealth(BatHealth),
822 SetPresent(u32),
823 SetCapacity(u32),
824 SetACOnline(u32),
825 }
826
827 impl BatControlCommand {
new(property: String, target: String) -> std::result::Result<Self, BatControlResult>828 pub fn new(property: String, target: String) -> std::result::Result<Self, BatControlResult> {
829 let cmd = property.parse::<BatProperty>()?;
830 match cmd {
831 BatProperty::Status => Ok(BatControlCommand::SetStatus(target.parse::<BatStatus>()?)),
832 BatProperty::Health => Ok(BatControlCommand::SetHealth(target.parse::<BatHealth>()?)),
833 BatProperty::Present => Ok(BatControlCommand::SetPresent(
834 target
835 .parse::<u32>()
836 .map_err(|_| BatControlResult::StringParseIntErr)?,
837 )),
838 BatProperty::Capacity => Ok(BatControlCommand::SetCapacity(
839 target
840 .parse::<u32>()
841 .map_err(|_| BatControlResult::StringParseIntErr)?,
842 )),
843 BatProperty::ACOnline => Ok(BatControlCommand::SetACOnline(
844 target
845 .parse::<u32>()
846 .map_err(|_| BatControlResult::StringParseIntErr)?,
847 )),
848 }
849 }
850 }
851
852 /// Used for VM to control battery properties.
853 pub struct BatControl {
854 pub type_: BatteryType,
855 pub control_tube: Tube,
856 }
857
858 #[derive(Serialize, Deserialize, Debug)]
859 pub enum FsMappingRequest {
860 /// Create an anonymous memory mapping that spans the entire region described by `Alloc`.
861 AllocateSharedMemoryRegion(Alloc),
862 /// Create a memory mapping.
863 CreateMemoryMapping {
864 /// The slot for a MemoryMappingArena, previously returned by a response to an
865 /// `AllocateSharedMemoryRegion` request.
866 slot: u32,
867 /// The file descriptor that should be mapped.
868 fd: SafeDescriptor,
869 /// The size of the mapping.
870 size: usize,
871 /// The offset into the file from where the mapping should start.
872 file_offset: u64,
873 /// The memory protection to be used for the mapping. Protections other than readable and
874 /// writable will be silently dropped.
875 prot: u32,
876 /// The offset into the shared memory region where the mapping should be placed.
877 mem_offset: usize,
878 },
879 /// Remove a memory mapping.
880 RemoveMemoryMapping {
881 /// The slot for a MemoryMappingArena.
882 slot: u32,
883 /// The offset into the shared memory region.
884 offset: usize,
885 /// The size of the mapping.
886 size: usize,
887 },
888 }
889
890 impl FsMappingRequest {
execute(&self, vm: &mut dyn Vm, allocator: &mut SystemAllocator) -> VmResponse891 pub fn execute(&self, vm: &mut dyn Vm, allocator: &mut SystemAllocator) -> VmResponse {
892 use self::FsMappingRequest::*;
893 match *self {
894 AllocateSharedMemoryRegion(Alloc::PciBar {
895 bus,
896 dev,
897 func,
898 bar,
899 }) => {
900 match allocator
901 .mmio_allocator(MmioType::High)
902 .get(&Alloc::PciBar {
903 bus,
904 dev,
905 func,
906 bar,
907 }) {
908 Some((addr, length, _)) => {
909 let arena = match MemoryMappingArena::new(*length as usize) {
910 Ok(a) => a,
911 Err(MmapError::SystemCallFailed(e)) => return VmResponse::Err(e),
912 _ => return VmResponse::Err(SysError::new(EINVAL)),
913 };
914
915 match vm.add_memory_region(
916 GuestAddress(*addr),
917 Box::new(arena),
918 false,
919 false,
920 ) {
921 Ok(slot) => VmResponse::RegisterMemory {
922 pfn: addr >> 12,
923 slot,
924 },
925 Err(e) => VmResponse::Err(e),
926 }
927 }
928 None => VmResponse::Err(SysError::new(EINVAL)),
929 }
930 }
931 CreateMemoryMapping {
932 slot,
933 ref fd,
934 size,
935 file_offset,
936 prot,
937 mem_offset,
938 } => {
939 match vm.add_fd_mapping(
940 slot,
941 mem_offset,
942 size,
943 fd,
944 file_offset,
945 Protection::from(prot as c_int & (libc::PROT_READ | libc::PROT_WRITE)),
946 ) {
947 Ok(()) => VmResponse::Ok,
948 Err(e) => VmResponse::Err(e),
949 }
950 }
951 RemoveMemoryMapping { slot, offset, size } => {
952 match vm.remove_mapping(slot, offset, size) {
953 Ok(()) => VmResponse::Ok,
954 Err(e) => VmResponse::Err(e),
955 }
956 }
957 _ => VmResponse::Err(SysError::new(EINVAL)),
958 }
959 }
960 }
961 /// A request to the main process to perform some operation on the VM.
962 ///
963 /// Unless otherwise noted, each request should expect a `VmResponse::Ok` to be received on success.
964 #[derive(Serialize, Deserialize, Debug)]
965 pub enum VmRequest {
966 /// Break the VM's run loop and exit.
967 Exit,
968 /// Trigger a power button event in the guest.
969 Powerbtn,
970 /// Suspend the VM's VCPUs until resume.
971 Suspend,
972 /// Resume the VM's VCPUs that were previously suspended.
973 Resume,
974 /// Inject a general-purpose event.
975 Gpe(u32),
976 /// Make the VM's RT VCPU real-time.
977 MakeRT,
978 /// Command for balloon driver.
979 BalloonCommand(BalloonControlCommand),
980 /// Send a command to a disk chosen by `disk_index`.
981 /// `disk_index` is a 0-based count of `--disk`, `--rwdisk`, and `-r` command-line options.
982 DiskCommand {
983 disk_index: usize,
984 command: DiskControlCommand,
985 },
986 /// Command to use controller.
987 UsbCommand(UsbControlCommand),
988 /// Command to set battery.
989 BatCommand(BatteryType, BatControlCommand),
990 /// Command to add/remove vfio pci device
991 VfioCommand { vfio_path: PathBuf, add: bool },
992 }
993
map_descriptor( descriptor: &dyn AsRawDescriptor, offset: u64, size: u64, read_only: bool, ) -> Result<Box<dyn MappedRegion>>994 fn map_descriptor(
995 descriptor: &dyn AsRawDescriptor,
996 offset: u64,
997 size: u64,
998 read_only: bool,
999 ) -> Result<Box<dyn MappedRegion>> {
1000 let size: usize = size.try_into().map_err(|_e| SysError::new(ERANGE))?;
1001 let prot = if read_only {
1002 Protection::read()
1003 } else {
1004 Protection::read_write()
1005 };
1006 match MemoryMappingBuilder::new(size)
1007 .from_descriptor(descriptor)
1008 .offset(offset)
1009 .protection(prot)
1010 .build()
1011 {
1012 Ok(mmap) => Ok(Box::new(mmap)),
1013 Err(MmapError::SystemCallFailed(e)) => Err(e),
1014 _ => Err(SysError::new(EINVAL)),
1015 }
1016 }
1017
1018 impl VmRequest {
1019 /// Executes this request on the given Vm and other mutable state.
1020 ///
1021 /// This does not return a result, instead encapsulating the success or failure in a
1022 /// `VmResponse` with the intended purpose of sending the response back over the socket that
1023 /// received this `VmRequest`.
execute( &self, run_mode: &mut Option<VmRunMode>, balloon_host_tube: Option<&Tube>, balloon_stats_id: &mut u64, disk_host_tubes: &[Tube], pm: &mut Option<Arc<Mutex<dyn PmResource>>>, usb_control_tube: Option<&Tube>, bat_control: &mut Option<BatControl>, vcpu_handles: &[(JoinHandle<()>, mpsc::Sender<VcpuControl>)], ) -> VmResponse1024 pub fn execute(
1025 &self,
1026 run_mode: &mut Option<VmRunMode>,
1027 balloon_host_tube: Option<&Tube>,
1028 balloon_stats_id: &mut u64,
1029 disk_host_tubes: &[Tube],
1030 pm: &mut Option<Arc<Mutex<dyn PmResource>>>,
1031 usb_control_tube: Option<&Tube>,
1032 bat_control: &mut Option<BatControl>,
1033 vcpu_handles: &[(JoinHandle<()>, mpsc::Sender<VcpuControl>)],
1034 ) -> VmResponse {
1035 match *self {
1036 VmRequest::Exit => {
1037 *run_mode = Some(VmRunMode::Exiting);
1038 VmResponse::Ok
1039 }
1040 VmRequest::Powerbtn => {
1041 if pm.is_some() {
1042 pm.as_ref().unwrap().lock().pwrbtn_evt();
1043 VmResponse::Ok
1044 } else {
1045 error!("{:#?} not supported", *self);
1046 VmResponse::Err(SysError::new(ENOTSUP))
1047 }
1048 }
1049 VmRequest::Suspend => {
1050 *run_mode = Some(VmRunMode::Suspending);
1051 VmResponse::Ok
1052 }
1053 VmRequest::Resume => {
1054 *run_mode = Some(VmRunMode::Running);
1055 VmResponse::Ok
1056 }
1057 VmRequest::Gpe(gpe) => {
1058 if pm.is_some() {
1059 pm.as_ref().unwrap().lock().gpe_evt(gpe);
1060 VmResponse::Ok
1061 } else {
1062 error!("{:#?} not supported", *self);
1063 VmResponse::Err(SysError::new(ENOTSUP))
1064 }
1065 }
1066 VmRequest::MakeRT => {
1067 for (handle, channel) in vcpu_handles {
1068 if let Err(e) = channel.send(VcpuControl::MakeRT) {
1069 error!("failed to send MakeRT: {}", e);
1070 }
1071 let _ = handle.kill(SIGRTMIN() + 0);
1072 }
1073 VmResponse::Ok
1074 }
1075 VmRequest::BalloonCommand(BalloonControlCommand::Adjust { num_bytes }) => {
1076 if let Some(balloon_host_tube) = balloon_host_tube {
1077 match balloon_host_tube.send(&BalloonTubeCommand::Adjust {
1078 num_bytes,
1079 allow_failure: false,
1080 }) {
1081 Ok(_) => VmResponse::Ok,
1082 Err(_) => VmResponse::Err(SysError::last()),
1083 }
1084 } else {
1085 VmResponse::Err(SysError::new(ENOTSUP))
1086 }
1087 }
1088 VmRequest::BalloonCommand(BalloonControlCommand::Stats) => {
1089 if let Some(balloon_host_tube) = balloon_host_tube {
1090 // NB: There are a few reasons stale balloon stats could be left
1091 // in balloon_host_tube:
1092 // - the send succeeds, but the recv fails because the device
1093 // is not ready yet. So when the device is ready, there are
1094 // extra stats requests queued.
1095 // - the send succeed, but the recv times out. When the device
1096 // does return the stats, there will be no consumer.
1097 //
1098 // To guard against this, add an `id` to the stats request. If
1099 // the id returned to us doesn't match, we keep trying to read
1100 // until it does.
1101 *balloon_stats_id = (*balloon_stats_id).wrapping_add(1);
1102 let sent_id = *balloon_stats_id;
1103 match balloon_host_tube.send(&BalloonTubeCommand::Stats { id: sent_id }) {
1104 Ok(_) => {
1105 loop {
1106 match balloon_host_tube.recv() {
1107 Ok(BalloonTubeResult::Stats {
1108 stats,
1109 balloon_actual,
1110 id,
1111 }) => {
1112 if sent_id != id {
1113 // Keep trying to get the fresh stats.
1114 continue;
1115 }
1116 break VmResponse::BalloonStats {
1117 stats,
1118 balloon_actual,
1119 };
1120 }
1121 Err(e) => {
1122 error!("balloon socket recv failed: {}", e);
1123 break VmResponse::Err(SysError::last());
1124 }
1125 Ok(BalloonTubeResult::Adjusted { .. }) => {
1126 unreachable!("unexpected adjusted response")
1127 }
1128 }
1129 }
1130 }
1131 Err(_) => VmResponse::Err(SysError::last()),
1132 }
1133 } else {
1134 VmResponse::Err(SysError::new(ENOTSUP))
1135 }
1136 }
1137 VmRequest::DiskCommand {
1138 disk_index,
1139 ref command,
1140 } => {
1141 // Forward the request to the block device process via its control socket.
1142 if let Some(sock) = disk_host_tubes.get(disk_index) {
1143 if let Err(e) = sock.send(command) {
1144 error!("disk socket send failed: {}", e);
1145 VmResponse::Err(SysError::new(EINVAL))
1146 } else {
1147 match sock.recv() {
1148 Ok(DiskControlResult::Ok) => VmResponse::Ok,
1149 Ok(DiskControlResult::Err(e)) => VmResponse::Err(e),
1150 Err(e) => {
1151 error!("disk socket recv failed: {}", e);
1152 VmResponse::Err(SysError::new(EINVAL))
1153 }
1154 }
1155 }
1156 } else {
1157 VmResponse::Err(SysError::new(ENODEV))
1158 }
1159 }
1160 VmRequest::UsbCommand(ref cmd) => {
1161 let usb_control_tube = match usb_control_tube {
1162 Some(t) => t,
1163 None => {
1164 error!("attempted to execute USB request without control tube");
1165 return VmResponse::Err(SysError::new(ENODEV));
1166 }
1167 };
1168 let res = usb_control_tube.send(cmd);
1169 if let Err(e) = res {
1170 error!("fail to send command to usb control socket: {}", e);
1171 return VmResponse::Err(SysError::new(EIO));
1172 }
1173 match usb_control_tube.recv() {
1174 Ok(response) => VmResponse::UsbResponse(response),
1175 Err(e) => {
1176 error!("fail to recv command from usb control socket: {}", e);
1177 VmResponse::Err(SysError::new(EIO))
1178 }
1179 }
1180 }
1181 VmRequest::BatCommand(type_, ref cmd) => {
1182 match bat_control {
1183 Some(battery) => {
1184 if battery.type_ != type_ {
1185 error!("ignored battery command due to battery type: expected {:?}, got {:?}", battery.type_, type_);
1186 return VmResponse::Err(SysError::new(EINVAL));
1187 }
1188
1189 let res = battery.control_tube.send(cmd);
1190 if let Err(e) = res {
1191 error!("fail to send command to bat control socket: {}", e);
1192 return VmResponse::Err(SysError::new(EIO));
1193 }
1194
1195 match battery.control_tube.recv() {
1196 Ok(response) => VmResponse::BatResponse(response),
1197 Err(e) => {
1198 error!("fail to recv command from bat control socket: {}", e);
1199 VmResponse::Err(SysError::new(EIO))
1200 }
1201 }
1202 }
1203 None => VmResponse::BatResponse(BatControlResult::NoBatDevice),
1204 }
1205 }
1206 VmRequest::VfioCommand {
1207 vfio_path: _,
1208 add: _,
1209 } => VmResponse::Ok,
1210 }
1211 }
1212 }
1213
1214 /// Indication of success or failure of a `VmRequest`.
1215 ///
1216 /// Success is usually indicated `VmResponse::Ok` unless there is data associated with the response.
1217 #[derive(Serialize, Deserialize, Debug)]
1218 pub enum VmResponse {
1219 /// Indicates the request was executed successfully.
1220 Ok,
1221 /// Indicates the request encountered some error during execution.
1222 Err(SysError),
1223 /// The request to register memory into guest address space was successfully done at page frame
1224 /// number `pfn` and memory slot number `slot`.
1225 RegisterMemory { pfn: u64, slot: u32 },
1226 /// The request to allocate and register GPU memory into guest address space was successfully
1227 /// done at page frame number `pfn` and memory slot number `slot` for buffer with `desc`.
1228 AllocateAndRegisterGpuMemory {
1229 descriptor: SafeDescriptor,
1230 pfn: u64,
1231 slot: u32,
1232 desc: GpuMemoryDesc,
1233 },
1234 /// Results of balloon control commands.
1235 BalloonStats {
1236 stats: BalloonStats,
1237 balloon_actual: u64,
1238 },
1239 /// Results of usb control commands.
1240 UsbResponse(UsbControlResult),
1241 /// Results of battery control commands.
1242 BatResponse(BatControlResult),
1243 }
1244
1245 impl Display for VmResponse {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result1246 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1247 use self::VmResponse::*;
1248
1249 match self {
1250 Ok => write!(f, "ok"),
1251 Err(e) => write!(f, "error: {}", e),
1252 RegisterMemory { pfn, slot } => write!(
1253 f,
1254 "memory registered to page frame number {:#x} and memory slot {}",
1255 pfn, slot
1256 ),
1257 AllocateAndRegisterGpuMemory { pfn, slot, .. } => write!(
1258 f,
1259 "gpu memory allocated and registered to page frame number {:#x} and memory slot {}",
1260 pfn, slot
1261 ),
1262 VmResponse::BalloonStats {
1263 stats,
1264 balloon_actual,
1265 } => {
1266 write!(
1267 f,
1268 "stats: {}\nballoon_actual: {}",
1269 serde_json::to_string_pretty(&stats)
1270 .unwrap_or_else(|_| "invalid_response".to_string()),
1271 balloon_actual
1272 )
1273 }
1274 UsbResponse(result) => write!(f, "usb control request get result {:?}", result),
1275 BatResponse(result) => write!(f, "{}", result),
1276 }
1277 }
1278 }
1279
1280 #[sorted]
1281 #[derive(Error, Debug)]
1282 pub enum VirtioIOMMUVfioError {
1283 #[error("socket failed")]
1284 SocketFailed,
1285 #[error("unexpected response: {0}")]
1286 UnexpectedResponse(VirtioIOMMUResponse),
1287 #[error("unknown command: `{0}`")]
1288 UnknownCommand(String),
1289 #[error("{0}")]
1290 VfioControl(VirtioIOMMUVfioResult),
1291 }
1292
1293 #[derive(Serialize, Deserialize, Debug)]
1294 pub enum VirtioIOMMUVfioCommand {
1295 // Add the vfio device attached to virtio-iommu.
1296 VfioDeviceAdd {
1297 endpoint_addr: u32,
1298 #[serde(with = "with_as_descriptor")]
1299 container: File,
1300 },
1301 // Delete the vfio device attached to virtio-iommu.
1302 VfioDeviceDel {
1303 endpoint_addr: u32,
1304 },
1305 }
1306
1307 #[derive(Serialize, Deserialize, Debug)]
1308 pub enum VirtioIOMMUVfioResult {
1309 Ok,
1310 NotInPCIRanges,
1311 NoAvailableContainer,
1312 NoSuchDevice,
1313 }
1314
1315 impl Display for VirtioIOMMUVfioResult {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result1316 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1317 use self::VirtioIOMMUVfioResult::*;
1318
1319 match self {
1320 Ok => write!(f, "successfully"),
1321 NotInPCIRanges => write!(f, "not in the pci ranges of virtio-iommu"),
1322 NoAvailableContainer => write!(f, "no available vfio container"),
1323 NoSuchDevice => write!(f, "no such a vfio device"),
1324 }
1325 }
1326 }
1327
1328 /// A request to the virtio-iommu process to perform some operations.
1329 ///
1330 /// Unless otherwise noted, each request should expect a `VirtioIOMMUResponse::Ok` to be received on
1331 /// success.
1332 #[derive(Serialize, Deserialize, Debug)]
1333 pub enum VirtioIOMMURequest {
1334 /// Command for vfio related operations.
1335 VfioCommand(VirtioIOMMUVfioCommand),
1336 }
1337
1338 /// Indication of success or failure of a `VirtioIOMMURequest`.
1339 ///
1340 /// Success is usually indicated `VirtioIOMMUResponse::Ok` unless there is data associated with the
1341 /// response.
1342 #[derive(Serialize, Deserialize, Debug)]
1343 pub enum VirtioIOMMUResponse {
1344 /// Indicates the request was executed successfully.
1345 Ok,
1346 /// Indicates the request encountered some error during execution.
1347 Err(SysError),
1348 /// Results for Vfio commands.
1349 VfioResponse(VirtioIOMMUVfioResult),
1350 }
1351
1352 impl Display for VirtioIOMMUResponse {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result1353 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1354 use self::VirtioIOMMUResponse::*;
1355 match self {
1356 Ok => write!(f, "ok"),
1357 Err(e) => write!(f, "error: {}", e),
1358 VfioResponse(result) => write!(
1359 f,
1360 "The vfio-related virtio-iommu request got result: {:?}",
1361 result
1362 ),
1363 }
1364 }
1365 }
1366
1367 /// Send VirtioIOMMURequest without waiting for the response
virtio_iommu_request_async( iommu_control_tube: &Tube, req: &VirtioIOMMURequest, ) -> VirtioIOMMUResponse1368 pub fn virtio_iommu_request_async(
1369 iommu_control_tube: &Tube,
1370 req: &VirtioIOMMURequest,
1371 ) -> VirtioIOMMUResponse {
1372 match iommu_control_tube.send(&req) {
1373 Ok(_) => VirtioIOMMUResponse::Ok,
1374 Err(e) => {
1375 error!("virtio-iommu socket send failed: {:?}", e);
1376 VirtioIOMMUResponse::Err(SysError::last())
1377 }
1378 }
1379 }
1380
1381 pub type VirtioIOMMURequestResult = std::result::Result<VirtioIOMMUResponse, ()>;
1382
1383 /// Send VirtioIOMMURequest and wait to get the response
virtio_iommu_request( iommu_control_tube: &Tube, req: &VirtioIOMMURequest, ) -> VirtioIOMMURequestResult1384 pub fn virtio_iommu_request(
1385 iommu_control_tube: &Tube,
1386 req: &VirtioIOMMURequest,
1387 ) -> VirtioIOMMURequestResult {
1388 let response = match virtio_iommu_request_async(iommu_control_tube, req) {
1389 VirtioIOMMUResponse::Ok => match iommu_control_tube.recv() {
1390 Ok(response) => response,
1391 Err(e) => {
1392 error!("virtio-iommu socket recv failed: {:?}", e);
1393 VirtioIOMMUResponse::Err(SysError::last())
1394 }
1395 },
1396 resp => resp,
1397 };
1398 Ok(response)
1399 }
1400