xref: /cloud-hypervisor/vm-virtio/src/lib.rs (revision b440cb7d2330770cd415b63544a371d4caa2db3a)
1 // Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 //
3 // Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
4 // Use of this source code is governed by a BSD-style license that can be
5 // found in the LICENSE-BSD-3-Clause file.
6 //
7 // Copyright © 2019 Intel Corporation
8 //
9 // SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
10 
11 //! Implements virtio queues
12 
13 use std::fmt::{self, Debug};
14 use std::sync::Arc;
15 use virtio_queue::Queue;
16 use vm_memory::{bitmap::AtomicBitmap, GuestAddress, GuestMemoryAtomic};
17 
18 type GuestMemoryMmap = vm_memory::GuestMemoryMmap<AtomicBitmap>;
19 
20 pub mod queue;
21 pub use queue::*;
22 
23 pub const VIRTIO_MSI_NO_VECTOR: u16 = 0xffff;
24 
25 // Types taken from linux/virtio_ids.h
26 #[derive(Copy, Clone, Debug)]
27 #[allow(dead_code)]
28 #[allow(non_camel_case_types)]
29 #[repr(C)]
30 pub enum VirtioDeviceType {
31     Net = 1,
32     Block = 2,
33     Console = 3,
34     Rng = 4,
35     Balloon = 5,
36     Fs9P = 9,
37     Gpu = 16,
38     Input = 18,
39     Vsock = 19,
40     Iommu = 23,
41     Mem = 24,
42     Fs = 26,
43     Pmem = 27,
44     Watchdog = 35, // Temporary until official number allocated
45     Unknown = 0xFF,
46 }
47 
48 impl From<u32> for VirtioDeviceType {
49     fn from(t: u32) -> Self {
50         match t {
51             1 => VirtioDeviceType::Net,
52             2 => VirtioDeviceType::Block,
53             3 => VirtioDeviceType::Console,
54             4 => VirtioDeviceType::Rng,
55             5 => VirtioDeviceType::Balloon,
56             9 => VirtioDeviceType::Fs9P,
57             16 => VirtioDeviceType::Gpu,
58             18 => VirtioDeviceType::Input,
59             19 => VirtioDeviceType::Vsock,
60             23 => VirtioDeviceType::Iommu,
61             24 => VirtioDeviceType::Mem,
62             26 => VirtioDeviceType::Fs,
63             27 => VirtioDeviceType::Pmem,
64             35 => VirtioDeviceType::Watchdog,
65             _ => VirtioDeviceType::Unknown,
66         }
67     }
68 }
69 
70 // In order to use the `{}` marker, the trait `fmt::Display` must be implemented
71 // manually for the type VirtioDeviceType.
72 impl fmt::Display for VirtioDeviceType {
73     // This trait requires `fmt` with this exact signature.
74     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
75         let output = match *self {
76             VirtioDeviceType::Net => "net",
77             VirtioDeviceType::Block => "block",
78             VirtioDeviceType::Console => "console",
79             VirtioDeviceType::Rng => "rng",
80             VirtioDeviceType::Balloon => "balloon",
81             VirtioDeviceType::Gpu => "gpu",
82             VirtioDeviceType::Fs9P => "9p",
83             VirtioDeviceType::Input => "input",
84             VirtioDeviceType::Vsock => "vsock",
85             VirtioDeviceType::Iommu => "iommu",
86             VirtioDeviceType::Mem => "mem",
87             VirtioDeviceType::Fs => "fs",
88             VirtioDeviceType::Pmem => "pmem",
89             VirtioDeviceType::Watchdog => "watchdog",
90             VirtioDeviceType::Unknown => "UNKNOWN",
91         };
92         write!(f, "{}", output)
93     }
94 }
95 
96 /// Trait for devices with access to data in memory being limited and/or
97 /// translated.
98 pub trait AccessPlatform: Send + Sync + Debug {
99     /// Provide a way to translate GVA address ranges into GPAs.
100     fn translate_gva(&self, base: u64, size: u64) -> std::result::Result<u64, std::io::Error>;
101     /// Provide a way to translate GPA address ranges into GVAs.
102     fn translate_gpa(&self, base: u64, size: u64) -> std::result::Result<u64, std::io::Error>;
103 }
104 
105 pub trait Translatable {
106     fn translate_gva(&self, access_platform: Option<&Arc<dyn AccessPlatform>>, len: usize) -> Self;
107     fn translate_gpa(&self, access_platform: Option<&Arc<dyn AccessPlatform>>, len: usize) -> Self;
108 }
109 
110 impl Translatable for GuestAddress {
111     fn translate_gva(&self, access_platform: Option<&Arc<dyn AccessPlatform>>, len: usize) -> Self {
112         if let Some(access_platform) = access_platform {
113             GuestAddress(access_platform.translate_gva(self.0, len as u64).unwrap())
114         } else {
115             *self
116         }
117     }
118     fn translate_gpa(&self, access_platform: Option<&Arc<dyn AccessPlatform>>, len: usize) -> Self {
119         if let Some(access_platform) = access_platform {
120             GuestAddress(access_platform.translate_gpa(self.0, len as u64).unwrap())
121         } else {
122             *self
123         }
124     }
125 }
126 
127 /// Helper for cloning a Queue since QueueState doesn't derive Clone
128 pub fn clone_queue(
129     queue: &Queue<GuestMemoryAtomic<GuestMemoryMmap>>,
130 ) -> Queue<GuestMemoryAtomic<GuestMemoryMmap>> {
131     Queue::<GuestMemoryAtomic<GuestMemoryMmap>, virtio_queue::QueueState> {
132         mem: queue.mem.clone(),
133         state: virtio_queue::QueueState {
134             max_size: queue.state.max_size,
135             next_avail: queue.state.next_avail,
136             next_used: queue.state.next_used,
137             event_idx_enabled: queue.state.event_idx_enabled,
138             num_added: queue.state.num_added,
139             size: queue.state.size,
140             ready: queue.state.ready,
141             desc_table: queue.state.desc_table,
142             avail_ring: queue.state.avail_ring,
143             used_ring: queue.state.used_ring,
144         },
145     }
146 }
147