• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! VirtIO transports.
2 
3 #[cfg(test)]
4 pub mod fake;
5 pub mod mmio;
6 pub mod pci;
7 
8 use crate::{PhysAddr, Result, PAGE_SIZE};
9 use bitflags::bitflags;
10 use core::ptr::NonNull;
11 
12 /// A VirtIO transport layer.
13 pub trait Transport {
14     /// Gets the device type.
device_type(&self) -> DeviceType15     fn device_type(&self) -> DeviceType;
16 
17     /// Reads device features.
read_device_features(&mut self) -> u6418     fn read_device_features(&mut self) -> u64;
19 
20     /// Writes device features.
write_driver_features(&mut self, driver_features: u64)21     fn write_driver_features(&mut self, driver_features: u64);
22 
23     /// Gets the max size of queue.
max_queue_size(&self) -> u3224     fn max_queue_size(&self) -> u32;
25 
26     /// Notifies the given queue on the device.
notify(&mut self, queue: u16)27     fn notify(&mut self, queue: u16);
28 
29     /// Gets the device status.
get_status(&self) -> DeviceStatus30     fn get_status(&self) -> DeviceStatus;
31 
32     /// Sets the device status.
set_status(&mut self, status: DeviceStatus)33     fn set_status(&mut self, status: DeviceStatus);
34 
35     /// Sets the guest page size.
set_guest_page_size(&mut self, guest_page_size: u32)36     fn set_guest_page_size(&mut self, guest_page_size: u32);
37 
38     /// Returns whether the transport requires queues to use the legacy layout.
39     ///
40     /// Ref: 2.6.2 Legacy Interfaces: A Note on Virtqueue Layout
requires_legacy_layout(&self) -> bool41     fn requires_legacy_layout(&self) -> bool;
42 
43     /// Sets up the given queue.
queue_set( &mut self, queue: u16, size: u32, descriptors: PhysAddr, driver_area: PhysAddr, device_area: PhysAddr, )44     fn queue_set(
45         &mut self,
46         queue: u16,
47         size: u32,
48         descriptors: PhysAddr,
49         driver_area: PhysAddr,
50         device_area: PhysAddr,
51     );
52 
53     /// Disables and resets the given queue.
queue_unset(&mut self, queue: u16)54     fn queue_unset(&mut self, queue: u16);
55 
56     /// Returns whether the queue is in use, i.e. has a nonzero PFN or is marked as ready.
queue_used(&mut self, queue: u16) -> bool57     fn queue_used(&mut self, queue: u16) -> bool;
58 
59     /// Acknowledges an interrupt.
60     ///
61     /// Returns true on success.
ack_interrupt(&mut self) -> bool62     fn ack_interrupt(&mut self) -> bool;
63 
64     /// Begins initializing the device.
65     ///
66     /// Ref: virtio 3.1.1 Device Initialization
begin_init(&mut self, negotiate_features: impl FnOnce(u64) -> u64)67     fn begin_init(&mut self, negotiate_features: impl FnOnce(u64) -> u64) {
68         self.set_status(DeviceStatus::ACKNOWLEDGE | DeviceStatus::DRIVER);
69 
70         let features = self.read_device_features();
71         self.write_driver_features(negotiate_features(features));
72         self.set_status(
73             DeviceStatus::ACKNOWLEDGE | DeviceStatus::DRIVER | DeviceStatus::FEATURES_OK,
74         );
75 
76         self.set_guest_page_size(PAGE_SIZE as u32);
77     }
78 
79     /// Finishes initializing the device.
finish_init(&mut self)80     fn finish_init(&mut self) {
81         self.set_status(
82             DeviceStatus::ACKNOWLEDGE
83                 | DeviceStatus::DRIVER
84                 | DeviceStatus::FEATURES_OK
85                 | DeviceStatus::DRIVER_OK,
86         );
87     }
88 
89     /// Gets the pointer to the config space.
config_space<T: 'static>(&self) -> Result<NonNull<T>>90     fn config_space<T: 'static>(&self) -> Result<NonNull<T>>;
91 }
92 
93 bitflags! {
94     /// The device status field.
95     #[derive(Default)]
96     pub struct DeviceStatus: u32 {
97         /// Indicates that the guest OS has found the device and recognized it
98         /// as a valid virtio device.
99         const ACKNOWLEDGE = 1;
100 
101         /// Indicates that the guest OS knows how to drive the device.
102         const DRIVER = 2;
103 
104         /// Indicates that something went wrong in the guest, and it has given
105         /// up on the device. This could be an internal error, or the driver
106         /// didn’t like the device for some reason, or even a fatal error
107         /// during device operation.
108         const FAILED = 128;
109 
110         /// Indicates that the driver has acknowledged all the features it
111         /// understands, and feature negotiation is complete.
112         const FEATURES_OK = 8;
113 
114         /// Indicates that the driver is set up and ready to drive the device.
115         const DRIVER_OK = 4;
116 
117         /// Indicates that the device has experienced an error from which it
118         /// can’t recover.
119         const DEVICE_NEEDS_RESET = 64;
120     }
121 }
122 
123 /// Types of virtio devices.
124 #[repr(u8)]
125 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
126 #[allow(missing_docs)]
127 pub enum DeviceType {
128     Invalid = 0,
129     Network = 1,
130     Block = 2,
131     Console = 3,
132     EntropySource = 4,
133     MemoryBallooning = 5,
134     IoMemory = 6,
135     Rpmsg = 7,
136     ScsiHost = 8,
137     _9P = 9,
138     Mac80211 = 10,
139     RprocSerial = 11,
140     VirtioCAIF = 12,
141     MemoryBalloon = 13,
142     GPU = 16,
143     Timer = 17,
144     Input = 18,
145     Socket = 19,
146     Crypto = 20,
147     SignalDistributionModule = 21,
148     Pstore = 22,
149     IOMMU = 23,
150     Memory = 24,
151 }
152 
153 impl From<u32> for DeviceType {
from(virtio_device_id: u32) -> Self154     fn from(virtio_device_id: u32) -> Self {
155         match virtio_device_id {
156             1 => DeviceType::Network,
157             2 => DeviceType::Block,
158             3 => DeviceType::Console,
159             4 => DeviceType::EntropySource,
160             5 => DeviceType::MemoryBalloon,
161             6 => DeviceType::IoMemory,
162             7 => DeviceType::Rpmsg,
163             8 => DeviceType::ScsiHost,
164             9 => DeviceType::_9P,
165             10 => DeviceType::Mac80211,
166             11 => DeviceType::RprocSerial,
167             12 => DeviceType::VirtioCAIF,
168             13 => DeviceType::MemoryBalloon,
169             16 => DeviceType::GPU,
170             17 => DeviceType::Timer,
171             18 => DeviceType::Input,
172             19 => DeviceType::Socket,
173             20 => DeviceType::Crypto,
174             21 => DeviceType::SignalDistributionModule,
175             22 => DeviceType::Pstore,
176             23 => DeviceType::IOMMU,
177             24 => DeviceType::Memory,
178             _ => DeviceType::Invalid,
179         }
180     }
181 }
182 
183 impl From<u16> for DeviceType {
from(virtio_device_id: u16) -> Self184     fn from(virtio_device_id: u16) -> Self {
185         u32::from(virtio_device_id).into()
186     }
187 }
188 
189 impl From<u8> for DeviceType {
from(virtio_device_id: u8) -> Self190     fn from(virtio_device_id: u8) -> Self {
191         u32::from(virtio_device_id).into()
192     }
193 }
194