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::fmt::{self, Display};
19 use std::fs::File;
20 use std::os::raw::c_int;
21 use std::result::Result as StdResult;
22 use std::str::FromStr;
23 use std::sync::Arc;
24
25 use libc::{EINVAL, EIO, ENODEV};
26 use serde::{Deserialize, Serialize};
27
28 use base::{
29 error, with_as_descriptor, AsRawDescriptor, Error as SysError, Event, ExternalMapping, Fd,
30 FromRawDescriptor, IntoRawDescriptor, MappedRegion, MemoryMappingArena, MemoryMappingBuilder,
31 MemoryMappingBuilderUnix, MmapError, Protection, Result, SafeDescriptor, SharedMemory, Tube,
32 };
33 use hypervisor::{IrqRoute, IrqSource, Vm};
34 use resources::{Alloc, MmioType, SystemAllocator};
35 use rutabaga_gfx::{
36 DrmFormat, ImageAllocationInfo, RutabagaGralloc, RutabagaGrallocFlags, RutabagaHandle,
37 VulkanInfo,
38 };
39 use sync::Mutex;
40 use vm_memory::GuestAddress;
41
42 /// Struct that describes the offset and stride of a plane located in GPU memory.
43 #[derive(Clone, Copy, Debug, PartialEq, Default, Serialize, Deserialize)]
44 pub struct GpuMemoryPlaneDesc {
45 pub stride: u32,
46 pub offset: u32,
47 }
48
49 /// Struct that describes a GPU memory allocation that consists of up to 3 planes.
50 #[derive(Clone, Copy, Debug, Default, Serialize, Deserialize)]
51 pub struct GpuMemoryDesc {
52 pub planes: [GpuMemoryPlaneDesc; 3],
53 }
54
55 #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
56 pub use crate::gdb::*;
57 pub use hypervisor::MemSlot;
58
59 /// Control the state of a particular VM CPU.
60 #[derive(Debug)]
61 pub enum VcpuControl {
62 #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
63 Debug(VcpuDebug),
64 RunState(VmRunMode),
65 }
66
67 /// Mode of execution for the VM.
68 #[derive(Debug, Clone, PartialEq)]
69 pub enum VmRunMode {
70 /// The default run mode indicating the VCPUs are running.
71 Running,
72 /// Indicates that the VCPUs are suspending execution until the `Running` mode is set.
73 Suspending,
74 /// Indicates that the VM is exiting all processes.
75 Exiting,
76 /// Indicates that the VM is in a breakpoint waiting for the debugger to do continue.
77 Breakpoint,
78 }
79
80 impl Display for VmRunMode {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result81 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
82 use self::VmRunMode::*;
83
84 match self {
85 Running => write!(f, "running"),
86 Suspending => write!(f, "suspending"),
87 Exiting => write!(f, "exiting"),
88 Breakpoint => write!(f, "breakpoint"),
89 }
90 }
91 }
92
93 impl Default for VmRunMode {
default() -> Self94 fn default() -> Self {
95 VmRunMode::Running
96 }
97 }
98
99 /// The maximum number of devices that can be listed in one `UsbControlCommand`.
100 ///
101 /// This value was set to be equal to `xhci_regs::MAX_PORTS` for convenience, but it is not
102 /// necessary for correctness. Importing that value directly would be overkill because it would
103 /// require adding a big dependency for a single const.
104 pub const USB_CONTROL_MAX_PORTS: usize = 16;
105
106 #[derive(Serialize, Deserialize, Debug)]
107 pub enum BalloonControlCommand {
108 /// Set the size of the VM's balloon.
109 Adjust {
110 num_bytes: u64,
111 },
112 Stats,
113 }
114
115 // BalloonStats holds stats returned from the stats_queue.
116 #[derive(Default, Serialize, Deserialize, Debug)]
117 pub struct BalloonStats {
118 pub swap_in: Option<u64>,
119 pub swap_out: Option<u64>,
120 pub major_faults: Option<u64>,
121 pub minor_faults: Option<u64>,
122 pub free_memory: Option<u64>,
123 pub total_memory: Option<u64>,
124 pub available_memory: Option<u64>,
125 pub disk_caches: Option<u64>,
126 pub hugetlb_allocations: Option<u64>,
127 pub hugetlb_failures: Option<u64>,
128 }
129
130 impl Display for BalloonStats {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result131 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
132 write!(f, "{{")?;
133 if let Some(swap_in) = self.swap_in {
134 write!(f, "\n swap_in: {}", swap_in)?;
135 }
136 if let Some(swap_out) = self.swap_out {
137 write!(f, "\n swap_out: {}", swap_out)?;
138 }
139 if let Some(major_faults) = self.major_faults {
140 write!(f, "\n major_faults: {}", major_faults)?;
141 }
142 if let Some(minor_faults) = self.minor_faults {
143 write!(f, "\n minor_faults: {}", minor_faults)?;
144 }
145 if let Some(free_memory) = self.free_memory {
146 write!(f, "\n free_memory: {}", free_memory)?;
147 }
148 if let Some(total_memory) = self.total_memory {
149 write!(f, "\n total_memory: {}", total_memory)?;
150 }
151 if let Some(available_memory) = self.available_memory {
152 write!(f, "\n available_memory: {}", available_memory)?;
153 }
154 if let Some(disk_caches) = self.disk_caches {
155 write!(f, "\n disk_caches: {}", disk_caches)?;
156 }
157 if let Some(hugetlb_allocations) = self.hugetlb_allocations {
158 write!(f, "\n hugetlb_allocations: {}", hugetlb_allocations)?;
159 }
160 if let Some(hugetlb_failures) = self.hugetlb_failures {
161 write!(f, "\n hugetlb_failures: {}", hugetlb_failures)?;
162 }
163 write!(f, "\n}}")
164 }
165 }
166
167 #[derive(Serialize, Deserialize, Debug)]
168 pub enum BalloonControlResult {
169 Stats {
170 stats: BalloonStats,
171 balloon_actual: u64,
172 },
173 }
174
175 #[derive(Serialize, Deserialize, Debug)]
176 pub enum DiskControlCommand {
177 /// Resize a disk to `new_size` in bytes.
178 Resize { new_size: u64 },
179 }
180
181 impl Display for DiskControlCommand {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result182 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
183 use self::DiskControlCommand::*;
184
185 match self {
186 Resize { new_size } => write!(f, "disk_resize {}", new_size),
187 }
188 }
189 }
190
191 #[derive(Serialize, Deserialize, Debug)]
192 pub enum DiskControlResult {
193 Ok,
194 Err(SysError),
195 }
196
197 #[derive(Serialize, Deserialize, Debug)]
198 pub enum UsbControlCommand {
199 AttachDevice {
200 bus: u8,
201 addr: u8,
202 vid: u16,
203 pid: u16,
204 #[serde(with = "with_as_descriptor")]
205 file: File,
206 },
207 DetachDevice {
208 port: u8,
209 },
210 ListDevice {
211 ports: [u8; USB_CONTROL_MAX_PORTS],
212 },
213 }
214
215 #[derive(Serialize, Deserialize, Copy, Clone, Debug, Default)]
216 pub struct UsbControlAttachedDevice {
217 pub port: u8,
218 pub vendor_id: u16,
219 pub product_id: u16,
220 }
221
222 impl UsbControlAttachedDevice {
valid(self) -> bool223 pub fn valid(self) -> bool {
224 self.port != 0
225 }
226 }
227
228 #[derive(Serialize, Deserialize, Debug)]
229 pub enum UsbControlResult {
230 Ok { port: u8 },
231 NoAvailablePort,
232 NoSuchDevice,
233 NoSuchPort,
234 FailedToOpenDevice,
235 Devices([UsbControlAttachedDevice; USB_CONTROL_MAX_PORTS]),
236 }
237
238 impl Display for UsbControlResult {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result239 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
240 use self::UsbControlResult::*;
241
242 match self {
243 UsbControlResult::Ok { port } => write!(f, "ok {}", port),
244 NoAvailablePort => write!(f, "no_available_port"),
245 NoSuchDevice => write!(f, "no_such_device"),
246 NoSuchPort => write!(f, "no_such_port"),
247 FailedToOpenDevice => write!(f, "failed_to_open_device"),
248 Devices(devices) => {
249 write!(f, "devices")?;
250 for d in devices.iter().filter(|d| d.valid()) {
251 write!(f, " {} {:04x} {:04x}", d.port, d.vendor_id, d.product_id)?;
252 }
253 std::result::Result::Ok(())
254 }
255 }
256 }
257 }
258
259 #[derive(Serialize, Deserialize)]
260 pub enum VmMemoryRequest {
261 /// Register shared memory represented by the given descriptor into guest address space.
262 /// The response variant is `VmResponse::RegisterMemory`.
263 RegisterMemory(SharedMemory),
264 /// Similiar to `VmMemoryRequest::RegisterMemory`, but doesn't allocate new address space.
265 /// Useful for cases where the address space is already allocated (PCI regions).
266 RegisterFdAtPciBarOffset(Alloc, SafeDescriptor, usize, u64),
267 /// Similar to RegisterFdAtPciBarOffset, but is for buffers in the current address space.
268 RegisterHostPointerAtPciBarOffset(Alloc, u64),
269 /// Similiar to `RegisterFdAtPciBarOffset`, but uses Vulkano to map the resource instead of
270 /// the mmap system call.
271 RegisterVulkanMemoryAtPciBarOffset {
272 alloc: Alloc,
273 descriptor: SafeDescriptor,
274 handle_type: u32,
275 memory_idx: u32,
276 physical_device_idx: u32,
277 offset: u64,
278 size: u64,
279 },
280 /// Unregister the given memory slot that was previously registered with `RegisterMemory*`.
281 UnregisterMemory(MemSlot),
282 /// Allocate GPU buffer of a given size/format and register the memory into guest address space.
283 /// The response variant is `VmResponse::AllocateAndRegisterGpuMemory`
284 AllocateAndRegisterGpuMemory {
285 width: u32,
286 height: u32,
287 format: u32,
288 },
289 /// Register mmaped memory into the hypervisor's EPT.
290 RegisterMmapMemory {
291 descriptor: SafeDescriptor,
292 size: usize,
293 offset: u64,
294 gpa: u64,
295 },
296 }
297
298 impl VmMemoryRequest {
299 /// Executes this request on the given Vm.
300 ///
301 /// # Arguments
302 /// * `vm` - The `Vm` to perform the request on.
303 /// * `allocator` - Used to allocate addresses.
304 ///
305 /// This does not return a result, instead encapsulating the success or failure in a
306 /// `VmMemoryResponse` with the intended purpose of sending the response back over the socket
307 /// that received this `VmMemoryResponse`.
execute( self, vm: &mut impl Vm, sys_allocator: &mut SystemAllocator, map_request: Arc<Mutex<Option<ExternalMapping>>>, gralloc: &mut RutabagaGralloc, ) -> VmMemoryResponse308 pub fn execute(
309 self,
310 vm: &mut impl Vm,
311 sys_allocator: &mut SystemAllocator,
312 map_request: Arc<Mutex<Option<ExternalMapping>>>,
313 gralloc: &mut RutabagaGralloc,
314 ) -> VmMemoryResponse {
315 use self::VmMemoryRequest::*;
316 match self {
317 RegisterMemory(ref shm) => {
318 match register_memory(vm, sys_allocator, shm, shm.size() as usize, None) {
319 Ok((pfn, slot)) => VmMemoryResponse::RegisterMemory { pfn, slot },
320 Err(e) => VmMemoryResponse::Err(e),
321 }
322 }
323 RegisterFdAtPciBarOffset(alloc, ref descriptor, size, offset) => {
324 match register_memory(vm, sys_allocator, descriptor, size, Some((alloc, offset))) {
325 Ok((pfn, slot)) => VmMemoryResponse::RegisterMemory { pfn, slot },
326 Err(e) => VmMemoryResponse::Err(e),
327 }
328 }
329 UnregisterMemory(slot) => match vm.remove_memory_region(slot) {
330 Ok(_) => VmMemoryResponse::Ok,
331 Err(e) => VmMemoryResponse::Err(e),
332 },
333 RegisterHostPointerAtPciBarOffset(alloc, offset) => {
334 let mem = map_request
335 .lock()
336 .take()
337 .ok_or_else(|| VmMemoryResponse::Err(SysError::new(EINVAL)))
338 .unwrap();
339
340 match register_host_pointer(vm, sys_allocator, Box::new(mem), (alloc, offset)) {
341 Ok((pfn, slot)) => VmMemoryResponse::RegisterMemory { pfn, slot },
342 Err(e) => VmMemoryResponse::Err(e),
343 }
344 }
345 RegisterVulkanMemoryAtPciBarOffset {
346 alloc,
347 descriptor,
348 handle_type,
349 memory_idx,
350 physical_device_idx,
351 offset,
352 size,
353 } => {
354 let mapped_region = match gralloc.import_and_map(
355 RutabagaHandle {
356 os_handle: descriptor,
357 handle_type,
358 },
359 VulkanInfo {
360 memory_idx,
361 physical_device_idx,
362 },
363 size,
364 ) {
365 Ok(mapped_region) => mapped_region,
366 Err(e) => {
367 error!("gralloc failed to import and map: {}", e);
368 return VmMemoryResponse::Err(SysError::new(EINVAL));
369 }
370 };
371
372 match register_host_pointer(vm, sys_allocator, mapped_region, (alloc, offset)) {
373 Ok((pfn, slot)) => VmMemoryResponse::RegisterMemory { pfn, slot },
374 Err(e) => VmMemoryResponse::Err(e),
375 }
376 }
377 AllocateAndRegisterGpuMemory {
378 width,
379 height,
380 format,
381 } => {
382 let img = ImageAllocationInfo {
383 width,
384 height,
385 drm_format: DrmFormat::from(format),
386 // Linear layout is a requirement as virtio wayland guest expects
387 // this for CPU access to the buffer. Scanout and texturing are
388 // optional as the consumer (wayland compositor) is expected to
389 // fall-back to a less efficient meachnisms for presentation if
390 // neccesary. In practice, linear buffers for commonly used formats
391 // will also support scanout and texturing.
392 flags: RutabagaGrallocFlags::empty().use_linear(true),
393 };
394
395 let reqs = match gralloc.get_image_memory_requirements(img) {
396 Ok(reqs) => reqs,
397 Err(e) => {
398 error!("gralloc failed to get image requirements: {}", e);
399 return VmMemoryResponse::Err(SysError::new(EINVAL));
400 }
401 };
402
403 let handle = match gralloc.allocate_memory(reqs) {
404 Ok(handle) => handle,
405 Err(e) => {
406 error!("gralloc failed to allocate memory: {}", e);
407 return VmMemoryResponse::Err(SysError::new(EINVAL));
408 }
409 };
410
411 let mut desc = GpuMemoryDesc::default();
412 for i in 0..3 {
413 desc.planes[i] = GpuMemoryPlaneDesc {
414 stride: reqs.strides[i],
415 offset: reqs.offsets[i],
416 }
417 }
418
419 match register_memory(
420 vm,
421 sys_allocator,
422 &handle.os_handle,
423 reqs.size as usize,
424 None,
425 ) {
426 Ok((pfn, slot)) => VmMemoryResponse::AllocateAndRegisterGpuMemory {
427 // Safe because ownership is transferred to SafeDescriptor via
428 // into_raw_descriptor
429 descriptor: unsafe {
430 SafeDescriptor::from_raw_descriptor(
431 handle.os_handle.into_raw_descriptor(),
432 )
433 },
434 pfn,
435 slot,
436 desc,
437 },
438 Err(e) => VmMemoryResponse::Err(e),
439 }
440 }
441 RegisterMmapMemory {
442 ref descriptor,
443 size,
444 offset,
445 gpa,
446 } => {
447 let mmap = match MemoryMappingBuilder::new(size)
448 .from_descriptor(descriptor)
449 .offset(offset as u64)
450 .build()
451 {
452 Ok(v) => v,
453 Err(_e) => return VmMemoryResponse::Err(SysError::new(EINVAL)),
454 };
455 match vm.add_memory_region(GuestAddress(gpa), Box::new(mmap), false, false) {
456 Ok(_) => VmMemoryResponse::Ok,
457 Err(e) => VmMemoryResponse::Err(e),
458 }
459 }
460 }
461 }
462 }
463
464 #[derive(Serialize, Deserialize, Debug)]
465 pub enum VmMemoryResponse {
466 /// The request to register memory into guest address space was successfully done at page frame
467 /// number `pfn` and memory slot number `slot`.
468 RegisterMemory {
469 pfn: u64,
470 slot: MemSlot,
471 },
472 /// The request to allocate and register GPU memory into guest address space was successfully
473 /// done at page frame number `pfn` and memory slot number `slot` for buffer with `desc`.
474 AllocateAndRegisterGpuMemory {
475 descriptor: SafeDescriptor,
476 pfn: u64,
477 slot: MemSlot,
478 desc: GpuMemoryDesc,
479 },
480 Ok,
481 Err(SysError),
482 }
483
484 #[derive(Serialize, Deserialize, Debug)]
485 pub enum VmIrqRequest {
486 /// Allocate one gsi, and associate gsi to irqfd with register_irqfd()
487 AllocateOneMsi { irqfd: Event },
488 /// Add one msi route entry into the IRQ chip.
489 AddMsiRoute {
490 gsi: u32,
491 msi_address: u64,
492 msi_data: u32,
493 },
494 }
495
496 /// Data to set up an IRQ event or IRQ route on the IRQ chip.
497 /// VmIrqRequest::execute can't take an `IrqChip` argument, because of a dependency cycle between
498 /// devices and vm_control, so it takes a Fn that processes an `IrqSetup`.
499 pub enum IrqSetup<'a> {
500 Event(u32, &'a Event),
501 Route(IrqRoute),
502 }
503
504 impl VmIrqRequest {
505 /// Executes this request on the given Vm.
506 ///
507 /// # Arguments
508 /// * `set_up_irq` - A function that applies an `IrqSetup` to an IRQ chip.
509 ///
510 /// This does not return a result, instead encapsulating the success or failure in a
511 /// `VmIrqResponse` with the intended purpose of sending the response back over the socket
512 /// that received this `VmIrqResponse`.
execute<F>(&self, set_up_irq: F, sys_allocator: &mut SystemAllocator) -> VmIrqResponse where F: FnOnce(IrqSetup) -> Result<()>,513 pub fn execute<F>(&self, set_up_irq: F, sys_allocator: &mut SystemAllocator) -> VmIrqResponse
514 where
515 F: FnOnce(IrqSetup) -> Result<()>,
516 {
517 use self::VmIrqRequest::*;
518 match *self {
519 AllocateOneMsi { ref irqfd } => {
520 if let Some(irq_num) = sys_allocator.allocate_irq() {
521 match set_up_irq(IrqSetup::Event(irq_num, &irqfd)) {
522 Ok(_) => VmIrqResponse::AllocateOneMsi { gsi: irq_num },
523 Err(e) => VmIrqResponse::Err(e),
524 }
525 } else {
526 VmIrqResponse::Err(SysError::new(EINVAL))
527 }
528 }
529 AddMsiRoute {
530 gsi,
531 msi_address,
532 msi_data,
533 } => {
534 let route = IrqRoute {
535 gsi,
536 source: IrqSource::Msi {
537 address: msi_address,
538 data: msi_data,
539 },
540 };
541 match set_up_irq(IrqSetup::Route(route)) {
542 Ok(_) => VmIrqResponse::Ok,
543 Err(e) => VmIrqResponse::Err(e),
544 }
545 }
546 }
547 }
548 }
549
550 #[derive(Serialize, Deserialize, Debug)]
551 pub enum VmIrqResponse {
552 AllocateOneMsi { gsi: u32 },
553 Ok,
554 Err(SysError),
555 }
556
557 #[derive(Serialize, Deserialize, Debug)]
558 pub enum VmMsyncRequest {
559 /// Flush the content of a memory mapping to its backing file.
560 /// `slot` selects the arena (as returned by `Vm::add_mmap_arena`).
561 /// `offset` is the offset of the mapping to sync within the arena.
562 /// `size` is the size of the mapping to sync within the arena.
563 MsyncArena {
564 slot: MemSlot,
565 offset: usize,
566 size: usize,
567 },
568 }
569
570 #[derive(Serialize, Deserialize, Debug)]
571 pub enum VmMsyncResponse {
572 Ok,
573 Err(SysError),
574 }
575
576 impl VmMsyncRequest {
577 /// Executes this request on the given Vm.
578 ///
579 /// # Arguments
580 /// * `vm` - The `Vm` to perform the request on.
581 ///
582 /// This does not return a result, instead encapsulating the success or failure in a
583 /// `VmMsyncResponse` with the intended purpose of sending the response back over the socket
584 /// that received this `VmMsyncResponse`.
execute(&self, vm: &mut impl Vm) -> VmMsyncResponse585 pub fn execute(&self, vm: &mut impl Vm) -> VmMsyncResponse {
586 use self::VmMsyncRequest::*;
587 match *self {
588 MsyncArena { slot, offset, size } => match vm.msync_memory_region(slot, offset, size) {
589 Ok(()) => VmMsyncResponse::Ok,
590 Err(e) => VmMsyncResponse::Err(e),
591 },
592 }
593 }
594 }
595
596 #[derive(Serialize, Deserialize, Debug)]
597 pub enum BatControlResult {
598 Ok,
599 NoBatDevice,
600 NoSuchHealth,
601 NoSuchProperty,
602 NoSuchStatus,
603 NoSuchBatType,
604 StringParseIntErr,
605 }
606
607 impl Display for BatControlResult {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result608 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
609 use self::BatControlResult::*;
610
611 match self {
612 Ok => write!(f, "Setting battery property successfully"),
613 NoBatDevice => write!(f, "No battery device created"),
614 NoSuchHealth => write!(f, "Invalid Battery health setting. Only support: unknown/good/overheat/dead/overvoltage/unexpectedfailure/cold/watchdogtimerexpire/safetytimerexpire/overcurrent"),
615 NoSuchProperty => write!(f, "Battery doesn't have such property. Only support: status/health/present/capacity/aconline"),
616 NoSuchStatus => write!(f, "Invalid Battery status setting. Only support: unknown/charging/discharging/notcharging/full"),
617 NoSuchBatType => write!(f, "Invalid Battery type setting. Only support: goldfish"),
618 StringParseIntErr => write!(f, "Battery property target ParseInt error"),
619 }
620 }
621 }
622
623 #[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq)]
624 pub enum BatteryType {
625 Goldfish,
626 }
627
628 impl Default for BatteryType {
default() -> Self629 fn default() -> Self {
630 BatteryType::Goldfish
631 }
632 }
633
634 impl FromStr for BatteryType {
635 type Err = BatControlResult;
636
from_str(s: &str) -> StdResult<Self, Self::Err>637 fn from_str(s: &str) -> StdResult<Self, Self::Err> {
638 match s {
639 "goldfish" => Ok(BatteryType::Goldfish),
640 _ => Err(BatControlResult::NoSuchBatType),
641 }
642 }
643 }
644
645 #[derive(Serialize, Deserialize, Debug)]
646 pub enum BatProperty {
647 Status,
648 Health,
649 Present,
650 Capacity,
651 ACOnline,
652 }
653
654 impl FromStr for BatProperty {
655 type Err = BatControlResult;
656
from_str(s: &str) -> StdResult<Self, Self::Err>657 fn from_str(s: &str) -> StdResult<Self, Self::Err> {
658 match s {
659 "status" => Ok(BatProperty::Status),
660 "health" => Ok(BatProperty::Health),
661 "present" => Ok(BatProperty::Present),
662 "capacity" => Ok(BatProperty::Capacity),
663 "aconline" => Ok(BatProperty::ACOnline),
664 _ => Err(BatControlResult::NoSuchProperty),
665 }
666 }
667 }
668
669 #[derive(Serialize, Deserialize, Debug)]
670 pub enum BatStatus {
671 Unknown,
672 Charging,
673 DisCharging,
674 NotCharging,
675 Full,
676 }
677
678 impl BatStatus {
new(status: String) -> std::result::Result<Self, BatControlResult>679 pub fn new(status: String) -> std::result::Result<Self, BatControlResult> {
680 match status.as_str() {
681 "unknown" => Ok(BatStatus::Unknown),
682 "charging" => Ok(BatStatus::Charging),
683 "discharging" => Ok(BatStatus::DisCharging),
684 "notcharging" => Ok(BatStatus::NotCharging),
685 "full" => Ok(BatStatus::Full),
686 _ => Err(BatControlResult::NoSuchStatus),
687 }
688 }
689 }
690
691 impl FromStr for BatStatus {
692 type Err = BatControlResult;
693
from_str(s: &str) -> StdResult<Self, Self::Err>694 fn from_str(s: &str) -> StdResult<Self, Self::Err> {
695 match s {
696 "unknown" => Ok(BatStatus::Unknown),
697 "charging" => Ok(BatStatus::Charging),
698 "discharging" => Ok(BatStatus::DisCharging),
699 "notcharging" => Ok(BatStatus::NotCharging),
700 "full" => Ok(BatStatus::Full),
701 _ => Err(BatControlResult::NoSuchStatus),
702 }
703 }
704 }
705
706 impl From<BatStatus> for u32 {
from(status: BatStatus) -> Self707 fn from(status: BatStatus) -> Self {
708 status as u32
709 }
710 }
711
712 #[derive(Serialize, Deserialize, Debug)]
713 pub enum BatHealth {
714 Unknown,
715 Good,
716 Overheat,
717 Dead,
718 OverVoltage,
719 UnexpectedFailure,
720 Cold,
721 WatchdogTimerExpire,
722 SafetyTimerExpire,
723 OverCurrent,
724 }
725
726 impl FromStr for BatHealth {
727 type Err = BatControlResult;
728
from_str(s: &str) -> StdResult<Self, Self::Err>729 fn from_str(s: &str) -> StdResult<Self, Self::Err> {
730 match s {
731 "unknown" => Ok(BatHealth::Unknown),
732 "good" => Ok(BatHealth::Good),
733 "overheat" => Ok(BatHealth::Overheat),
734 "dead" => Ok(BatHealth::Dead),
735 "overvoltage" => Ok(BatHealth::OverVoltage),
736 "unexpectedfailure" => Ok(BatHealth::UnexpectedFailure),
737 "cold" => Ok(BatHealth::Cold),
738 "watchdogtimerexpire" => Ok(BatHealth::WatchdogTimerExpire),
739 "safetytimerexpire" => Ok(BatHealth::SafetyTimerExpire),
740 "overcurrent" => Ok(BatHealth::OverCurrent),
741 _ => Err(BatControlResult::NoSuchHealth),
742 }
743 }
744 }
745
746 impl From<BatHealth> for u32 {
from(status: BatHealth) -> Self747 fn from(status: BatHealth) -> Self {
748 status as u32
749 }
750 }
751
752 #[derive(Serialize, Deserialize, Debug)]
753 pub enum BatControlCommand {
754 SetStatus(BatStatus),
755 SetHealth(BatHealth),
756 SetPresent(u32),
757 SetCapacity(u32),
758 SetACOnline(u32),
759 }
760
761 impl BatControlCommand {
new(property: String, target: String) -> std::result::Result<Self, BatControlResult>762 pub fn new(property: String, target: String) -> std::result::Result<Self, BatControlResult> {
763 let cmd = property.parse::<BatProperty>()?;
764 match cmd {
765 BatProperty::Status => Ok(BatControlCommand::SetStatus(target.parse::<BatStatus>()?)),
766 BatProperty::Health => Ok(BatControlCommand::SetHealth(target.parse::<BatHealth>()?)),
767 BatProperty::Present => Ok(BatControlCommand::SetPresent(
768 target
769 .parse::<u32>()
770 .map_err(|_| BatControlResult::StringParseIntErr)?,
771 )),
772 BatProperty::Capacity => Ok(BatControlCommand::SetCapacity(
773 target
774 .parse::<u32>()
775 .map_err(|_| BatControlResult::StringParseIntErr)?,
776 )),
777 BatProperty::ACOnline => Ok(BatControlCommand::SetACOnline(
778 target
779 .parse::<u32>()
780 .map_err(|_| BatControlResult::StringParseIntErr)?,
781 )),
782 }
783 }
784 }
785
786 /// Used for VM to control battery properties.
787 pub struct BatControl {
788 pub type_: BatteryType,
789 pub control_tube: Tube,
790 }
791
792 #[derive(Serialize, Deserialize, Debug)]
793 pub enum FsMappingRequest {
794 /// Create an anonymous memory mapping that spans the entire region described by `Alloc`.
795 AllocateSharedMemoryRegion(Alloc),
796 /// Create a memory mapping.
797 CreateMemoryMapping {
798 /// The slot for a MemoryMappingArena, previously returned by a response to an
799 /// `AllocateSharedMemoryRegion` request.
800 slot: u32,
801 /// The file descriptor that should be mapped.
802 fd: SafeDescriptor,
803 /// The size of the mapping.
804 size: usize,
805 /// The offset into the file from where the mapping should start.
806 file_offset: u64,
807 /// The memory protection to be used for the mapping. Protections other than readable and
808 /// writable will be silently dropped.
809 prot: u32,
810 /// The offset into the shared memory region where the mapping should be placed.
811 mem_offset: usize,
812 },
813 /// Remove a memory mapping.
814 RemoveMemoryMapping {
815 /// The slot for a MemoryMappingArena.
816 slot: u32,
817 /// The offset into the shared memory region.
818 offset: usize,
819 /// The size of the mapping.
820 size: usize,
821 },
822 }
823
824 impl FsMappingRequest {
execute(&self, vm: &mut dyn Vm, allocator: &mut SystemAllocator) -> VmResponse825 pub fn execute(&self, vm: &mut dyn Vm, allocator: &mut SystemAllocator) -> VmResponse {
826 use self::FsMappingRequest::*;
827 match *self {
828 AllocateSharedMemoryRegion(Alloc::PciBar {
829 bus,
830 dev,
831 func,
832 bar,
833 }) => {
834 match allocator
835 .mmio_allocator(MmioType::High)
836 .get(&Alloc::PciBar {
837 bus,
838 dev,
839 func,
840 bar,
841 }) {
842 Some((addr, length, _)) => {
843 let arena = match MemoryMappingArena::new(*length as usize) {
844 Ok(a) => a,
845 Err(MmapError::SystemCallFailed(e)) => return VmResponse::Err(e),
846 _ => return VmResponse::Err(SysError::new(EINVAL)),
847 };
848
849 match vm.add_memory_region(
850 GuestAddress(*addr),
851 Box::new(arena),
852 false,
853 false,
854 ) {
855 Ok(slot) => VmResponse::RegisterMemory {
856 pfn: addr >> 12,
857 slot,
858 },
859 Err(e) => VmResponse::Err(e),
860 }
861 }
862 None => VmResponse::Err(SysError::new(EINVAL)),
863 }
864 }
865 CreateMemoryMapping {
866 slot,
867 ref fd,
868 size,
869 file_offset,
870 prot,
871 mem_offset,
872 } => {
873 let raw_fd: Fd = Fd(fd.as_raw_descriptor());
874
875 match vm.add_fd_mapping(
876 slot,
877 mem_offset,
878 size,
879 &raw_fd,
880 file_offset,
881 Protection::from(prot as c_int & (libc::PROT_READ | libc::PROT_WRITE)),
882 ) {
883 Ok(()) => VmResponse::Ok,
884 Err(e) => VmResponse::Err(e),
885 }
886 }
887 RemoveMemoryMapping { slot, offset, size } => {
888 match vm.remove_mapping(slot, offset, size) {
889 Ok(()) => VmResponse::Ok,
890 Err(e) => VmResponse::Err(e),
891 }
892 }
893 _ => VmResponse::Err(SysError::new(EINVAL)),
894 }
895 }
896 }
897 /// A request to the main process to perform some operation on the VM.
898 ///
899 /// Unless otherwise noted, each request should expect a `VmResponse::Ok` to be received on success.
900 #[derive(Serialize, Deserialize, Debug)]
901 pub enum VmRequest {
902 /// Break the VM's run loop and exit.
903 Exit,
904 /// Suspend the VM's VCPUs until resume.
905 Suspend,
906 /// Resume the VM's VCPUs that were previously suspended.
907 Resume,
908 /// Command for balloon driver.
909 BalloonCommand(BalloonControlCommand),
910 /// Send a command to a disk chosen by `disk_index`.
911 /// `disk_index` is a 0-based count of `--disk`, `--rwdisk`, and `-r` command-line options.
912 DiskCommand {
913 disk_index: usize,
914 command: DiskControlCommand,
915 },
916 /// Command to use controller.
917 UsbCommand(UsbControlCommand),
918 /// Command to set battery.
919 BatCommand(BatteryType, BatControlCommand),
920 }
921
register_memory( vm: &mut impl Vm, allocator: &mut SystemAllocator, descriptor: &dyn AsRawDescriptor, size: usize, pci_allocation: Option<(Alloc, u64)>, ) -> Result<(u64, MemSlot)>922 fn register_memory(
923 vm: &mut impl Vm,
924 allocator: &mut SystemAllocator,
925 descriptor: &dyn AsRawDescriptor,
926 size: usize,
927 pci_allocation: Option<(Alloc, u64)>,
928 ) -> Result<(u64, MemSlot)> {
929 let mmap = match MemoryMappingBuilder::new(size)
930 .from_descriptor(descriptor)
931 .build()
932 {
933 Ok(v) => v,
934 Err(MmapError::SystemCallFailed(e)) => return Err(e),
935 _ => return Err(SysError::new(EINVAL)),
936 };
937
938 let addr = match pci_allocation {
939 Some(pci_allocation) => allocator
940 .mmio_allocator_any()
941 .address_from_pci_offset(pci_allocation.0, pci_allocation.1, size as u64)
942 .map_err(|_e| SysError::new(EINVAL))?,
943 None => {
944 let alloc = allocator.get_anon_alloc();
945 allocator
946 .mmio_allocator_any()
947 .allocate(size as u64, alloc, "vmcontrol_register_memory".to_string())
948 .map_err(|_e| SysError::new(EINVAL))?
949 }
950 };
951
952 let slot = vm.add_memory_region(GuestAddress(addr), Box::new(mmap), false, false)?;
953
954 Ok((addr >> 12, slot))
955 }
956
register_host_pointer( vm: &mut impl Vm, allocator: &mut SystemAllocator, mem: Box<dyn MappedRegion>, pci_allocation: (Alloc, u64), ) -> Result<(u64, MemSlot)>957 fn register_host_pointer(
958 vm: &mut impl Vm,
959 allocator: &mut SystemAllocator,
960 mem: Box<dyn MappedRegion>,
961 pci_allocation: (Alloc, u64),
962 ) -> Result<(u64, MemSlot)> {
963 let addr = allocator
964 .mmio_allocator_any()
965 .address_from_pci_offset(pci_allocation.0, pci_allocation.1, mem.size() as u64)
966 .map_err(|_e| SysError::new(EINVAL))?;
967
968 let slot = vm.add_memory_region(GuestAddress(addr), mem, false, false)?;
969 Ok((addr >> 12, slot))
970 }
971
972 impl VmRequest {
973 /// Executes this request on the given Vm and other mutable state.
974 ///
975 /// This does not return a result, instead encapsulating the success or failure in a
976 /// `VmResponse` with the intended purpose of sending the response back over the socket that
977 /// received this `VmRequest`.
execute( &self, run_mode: &mut Option<VmRunMode>, balloon_host_tube: &Tube, disk_host_tubes: &[Tube], usb_control_tube: &Tube, bat_control: &mut Option<BatControl>, ) -> VmResponse978 pub fn execute(
979 &self,
980 run_mode: &mut Option<VmRunMode>,
981 balloon_host_tube: &Tube,
982 disk_host_tubes: &[Tube],
983 usb_control_tube: &Tube,
984 bat_control: &mut Option<BatControl>,
985 ) -> VmResponse {
986 match *self {
987 VmRequest::Exit => {
988 *run_mode = Some(VmRunMode::Exiting);
989 VmResponse::Ok
990 }
991 VmRequest::Suspend => {
992 *run_mode = Some(VmRunMode::Suspending);
993 VmResponse::Ok
994 }
995 VmRequest::Resume => {
996 *run_mode = Some(VmRunMode::Running);
997 VmResponse::Ok
998 }
999 VmRequest::BalloonCommand(BalloonControlCommand::Adjust { num_bytes }) => {
1000 match balloon_host_tube.send(&BalloonControlCommand::Adjust { num_bytes }) {
1001 Ok(_) => VmResponse::Ok,
1002 Err(_) => VmResponse::Err(SysError::last()),
1003 }
1004 }
1005 VmRequest::BalloonCommand(BalloonControlCommand::Stats) => {
1006 match balloon_host_tube.send(&BalloonControlCommand::Stats {}) {
1007 Ok(_) => match balloon_host_tube.recv() {
1008 Ok(BalloonControlResult::Stats {
1009 stats,
1010 balloon_actual,
1011 }) => VmResponse::BalloonStats {
1012 stats,
1013 balloon_actual,
1014 },
1015 Err(e) => {
1016 error!("balloon socket recv failed: {}", e);
1017 VmResponse::Err(SysError::last())
1018 }
1019 },
1020 Err(_) => VmResponse::Err(SysError::last()),
1021 }
1022 }
1023 VmRequest::DiskCommand {
1024 disk_index,
1025 ref command,
1026 } => {
1027 // Forward the request to the block device process via its control socket.
1028 if let Some(sock) = disk_host_tubes.get(disk_index) {
1029 if let Err(e) = sock.send(command) {
1030 error!("disk socket send failed: {}", e);
1031 VmResponse::Err(SysError::new(EINVAL))
1032 } else {
1033 match sock.recv() {
1034 Ok(DiskControlResult::Ok) => VmResponse::Ok,
1035 Ok(DiskControlResult::Err(e)) => VmResponse::Err(e),
1036 Err(e) => {
1037 error!("disk socket recv failed: {}", e);
1038 VmResponse::Err(SysError::new(EINVAL))
1039 }
1040 }
1041 }
1042 } else {
1043 VmResponse::Err(SysError::new(ENODEV))
1044 }
1045 }
1046 VmRequest::UsbCommand(ref cmd) => {
1047 let res = usb_control_tube.send(cmd);
1048 if let Err(e) = res {
1049 error!("fail to send command to usb control socket: {}", e);
1050 return VmResponse::Err(SysError::new(EIO));
1051 }
1052 match usb_control_tube.recv() {
1053 Ok(response) => VmResponse::UsbResponse(response),
1054 Err(e) => {
1055 error!("fail to recv command from usb control socket: {}", e);
1056 VmResponse::Err(SysError::new(EIO))
1057 }
1058 }
1059 }
1060 VmRequest::BatCommand(type_, ref cmd) => {
1061 match bat_control {
1062 Some(battery) => {
1063 if battery.type_ != type_ {
1064 error!("ignored battery command due to battery type: expected {:?}, got {:?}", battery.type_, type_);
1065 return VmResponse::Err(SysError::new(EINVAL));
1066 }
1067
1068 let res = battery.control_tube.send(cmd);
1069 if let Err(e) = res {
1070 error!("fail to send command to bat control socket: {}", e);
1071 return VmResponse::Err(SysError::new(EIO));
1072 }
1073
1074 match battery.control_tube.recv() {
1075 Ok(response) => VmResponse::BatResponse(response),
1076 Err(e) => {
1077 error!("fail to recv command from bat control socket: {}", e);
1078 VmResponse::Err(SysError::new(EIO))
1079 }
1080 }
1081 }
1082 None => VmResponse::BatResponse(BatControlResult::NoBatDevice),
1083 }
1084 }
1085 }
1086 }
1087 }
1088
1089 /// Indication of success or failure of a `VmRequest`.
1090 ///
1091 /// Success is usually indicated `VmResponse::Ok` unless there is data associated with the response.
1092 #[derive(Serialize, Deserialize, Debug)]
1093 pub enum VmResponse {
1094 /// Indicates the request was executed successfully.
1095 Ok,
1096 /// Indicates the request encountered some error during execution.
1097 Err(SysError),
1098 /// The request to register memory into guest address space was successfully done at page frame
1099 /// number `pfn` and memory slot number `slot`.
1100 RegisterMemory { pfn: u64, slot: u32 },
1101 /// The request to allocate and register GPU memory into guest address space was successfully
1102 /// done at page frame number `pfn` and memory slot number `slot` for buffer with `desc`.
1103 AllocateAndRegisterGpuMemory {
1104 descriptor: SafeDescriptor,
1105 pfn: u64,
1106 slot: u32,
1107 desc: GpuMemoryDesc,
1108 },
1109 /// Results of balloon control commands.
1110 BalloonStats {
1111 stats: BalloonStats,
1112 balloon_actual: u64,
1113 },
1114 /// Results of usb control commands.
1115 UsbResponse(UsbControlResult),
1116 /// Results of battery control commands.
1117 BatResponse(BatControlResult),
1118 }
1119
1120 impl Display for VmResponse {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result1121 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1122 use self::VmResponse::*;
1123
1124 match self {
1125 Ok => write!(f, "ok"),
1126 Err(e) => write!(f, "error: {}", e),
1127 RegisterMemory { pfn, slot } => write!(
1128 f,
1129 "memory registered to page frame number {:#x} and memory slot {}",
1130 pfn, slot
1131 ),
1132 AllocateAndRegisterGpuMemory { pfn, slot, .. } => write!(
1133 f,
1134 "gpu memory allocated and registered to page frame number {:#x} and memory slot {}",
1135 pfn, slot
1136 ),
1137 VmResponse::BalloonStats {
1138 stats,
1139 balloon_actual,
1140 } => write!(
1141 f,
1142 "balloon size: {}\nballoon stats: {}",
1143 balloon_actual, stats
1144 ),
1145 UsbResponse(result) => write!(f, "usb control request get result {:?}", result),
1146 BatResponse(result) => write!(f, "{}", result),
1147 }
1148 }
1149 }
1150