vm_device/
lib.rs

1// Copyright © 2019 Intel Corporation. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
3
4#![deny(missing_docs)]
5
6//! This crate provides:
7//! * device traits defining read and write operations on specialized buses
8//! * device manager (bus-specific traits and a concrete implementation) for
9//! operating devices and dispatching I/O
10//! * abstractions for defining resources and their constraints (e.g. a specific bus
11//! address range, IRQ number, etc)
12//!
13//! [`MutDevicePio`] and [`MutDeviceMmio`] traits help with composite inner mutability
14//! (i.e. if we have a `Mutex` that holds a `T` which implements [`MutDevicePio`],
15//! then the `Mutex` can implement [`DevicePio`] based on its inner
16//! mutability properties).
17//!
18//! # Example
19//!
20//! Implement a simple log PIO device, register it with
21//! [`IoManager`](device_manager/struct.IoManager.html)
22//! and dispatch a write operation to the device.
23//!```
24//! use std::sync::{Arc, Mutex};
25//! use vm_device::bus::{PioAddress, PioAddressOffset, PioRange};
26//! use vm_device::device_manager::{IoManager, PioManager};
27//! use vm_device::MutDevicePio;
28//!
29//! struct LogDevice {}
30//!
31//! impl MutDevicePio for LogDevice {
32//!     fn pio_read(&mut self, base: PioAddress, offset: PioAddressOffset, _data: &mut [u8]) {
33//!         println!("mut pio_read: base {:?}, offset {}", base, offset);
34//!     }
35//!     fn pio_write(&mut self, base: PioAddress, offset: PioAddressOffset, data: &[u8]) {
36//!         println!(
37//!             "mut pio_write: base {:?}, offset {}, data {:?}",
38//!             base, offset, data
39//!         );
40//!     }
41//! }
42//!
43//! // IoManager implements PioManager trait.
44//! let mut manager = IoManager::new();
45//! let device = LogDevice {};
46//! let bus_range = PioRange::new(PioAddress(0), 10).unwrap();
47//! manager
48//!     .register_pio(bus_range, Arc::new(Mutex::new(device)))
49//!     .unwrap();
50//! manager.pio_write(PioAddress(0), &vec![b'o', b'k']).unwrap();
51//! ```
52
53pub mod bus;
54pub mod device_manager;
55pub mod resources;
56
57use std::ops::Deref;
58use std::sync::{Arc, Mutex};
59
60use bus::{MmioAddress, MmioAddressOffset, PioAddress, PioAddressOffset};
61
62/// Allows a device to be attached to a
63/// [PIO](https://en.wikipedia.org/wiki/Programmed_input%E2%80%93output) bus.
64///
65/// # Example
66/// ```
67/// # use std::sync::Mutex;
68/// # use vm_device::{DevicePio, bus::{PioAddress, PioAddressOffset}};
69/// struct DummyDevice {
70///     config: Mutex<u32>,
71/// }
72///
73/// impl DevicePio for DummyDevice {
74///     fn pio_read(&self, _base: PioAddress, _offset: PioAddressOffset, data: &mut [u8]) {
75///         if data.len() > 4 {
76///             return;
77///         }
78///         for (idx, iter) in data.iter_mut().enumerate() {
79///             let config = self.config.lock().expect("failed to acquire lock");
80///             *iter = (*config >> (idx * 8) & 0xff) as u8;
81///         }
82///     }
83///
84///     fn pio_write(&self, _base: PioAddress, _offset: PioAddressOffset, data: &[u8]) {
85///         let mut config = self.config.lock().expect("failed to acquire lock");
86///         *config = u32::from(data[0]) & 0xff;
87///     }
88/// }
89/// ```
90pub trait DevicePio {
91    /// Handle a read operation on the device.
92    ///
93    /// # Arguments
94    ///
95    /// * `base`:   base address on a PIO bus
96    /// * `offset`: base address' offset
97    /// * `data`:   a buffer provided by the caller to store the read data
98    fn pio_read(&self, base: PioAddress, offset: PioAddressOffset, data: &mut [u8]);
99
100    /// Handle a write operation to the device.
101    ///
102    /// # Arguments
103    ///
104    /// * `base`:   base address on a PIO bus
105    /// * `offset`: base address' offset
106    /// * `data`:   a buffer provided by the caller holding the data to write
107    fn pio_write(&self, base: PioAddress, offset: PioAddressOffset, data: &[u8]);
108}
109
110/// Allows a device to be attached to a
111/// [MMIO](https://en.wikipedia.org/wiki/Memory-mapped_I/O) bus.
112///
113/// # Example
114/// ```
115/// # use std::sync::Mutex;
116/// # use vm_device::{DeviceMmio, bus::{MmioAddress, MmioAddressOffset}};
117/// struct DummyDevice {
118///     config: Mutex<u32>,
119/// }
120///
121/// impl DeviceMmio for DummyDevice {
122///     fn mmio_read(&self, _base: MmioAddress, _offset: MmioAddressOffset, data: &mut [u8]) {
123///         if data.len() > 4 {
124///             return;
125///         }
126///         for (idx, iter) in data.iter_mut().enumerate() {
127///             let config = self.config.lock().expect("failed to acquire lock");
128///             *iter = (*config >> (idx * 8) & 0xff) as u8;
129///         }
130///     }
131///
132///     fn mmio_write(&self, _base: MmioAddress, _offset: MmioAddressOffset, data: &[u8]) {
133///         let mut config = self.config.lock().expect("failed to acquire lock");
134///         *config = u32::from(data[0]) & 0xff;
135///     }
136/// }
137/// ```
138pub trait DeviceMmio {
139    /// Handle a read operation on the device.
140    ///
141    /// # Arguments
142    ///
143    /// * `base`:   base address on a MMIO bus
144    /// * `offset`: base address' offset
145    /// * `data`:   a buffer provided by the caller to store the read data
146    fn mmio_read(&self, base: MmioAddress, offset: MmioAddressOffset, data: &mut [u8]);
147
148    /// Handle a write operation to the device.
149    ///
150    /// # Arguments
151    ///
152    /// * `base`:   base address on a MMIO bus
153    /// * `offset`: base address' offset
154    /// * `data`:   a buffer provided by the caller holding the data to write
155    fn mmio_write(&self, base: MmioAddress, offset: MmioAddressOffset, data: &[u8]);
156}
157
158/// Same as [DevicePio] but the methods are invoked with a mutable self borrow.
159///
160/// # Example
161/// ```
162/// # use vm_device::{MutDevicePio, bus::{PioAddress, PioAddressOffset}};
163/// struct DummyDevice {
164///     config: u32,
165/// }
166///
167/// impl MutDevicePio for DummyDevice {
168///     fn pio_read(&mut self, _base: PioAddress, _offset: PioAddressOffset, data: &mut [u8]) {
169///         if data.len() > 4 {
170///             return;
171///         }
172///         for (idx, iter) in data.iter_mut().enumerate() {
173///             *iter = (self.config >> (idx * 8) & 0xff) as u8;
174///         }
175///     }
176///
177///     fn pio_write(&mut self, _base: PioAddress, _offset: PioAddressOffset, data: &[u8]) {
178///         self.config = u32::from(data[0]) & 0xff;
179///     }
180/// }
181/// ```
182pub trait MutDevicePio {
183    /// Handle a read operation on the device.
184    ///
185    /// # Arguments
186    ///
187    /// * `base`:   base address on a PIO bus
188    /// * `offset`: base address' offset
189    /// * `data`:   a buffer provided by the caller to store the read data
190    fn pio_read(&mut self, base: PioAddress, offset: PioAddressOffset, data: &mut [u8]);
191
192    /// Handle a write operation to the device.
193    ///
194    /// # Arguments
195    ///
196    /// * `base`:   base address on a PIO bus
197    /// * `offset`: base address' offset
198    /// * `data`:   a buffer provided by the caller holding the data to write
199    fn pio_write(&mut self, base: PioAddress, offset: PioAddressOffset, data: &[u8]);
200}
201
202/// Same as [DeviceMmio] but the methods are invoked with a mutable self borrow.
203/// # Example
204/// ```
205/// # use vm_device::{MutDeviceMmio, bus::{MmioAddress, MmioAddressOffset}};
206/// struct DummyDevice {
207///     config: u32,
208/// }
209///
210/// impl MutDeviceMmio for DummyDevice {
211///     fn mmio_read(&mut self, _base: MmioAddress, _offset: MmioAddressOffset, data: &mut [u8]) {
212///         if data.len() > 4 {
213///             return;
214///         }
215///         for (idx, iter) in data.iter_mut().enumerate() {
216///             *iter = (self.config >> (idx * 8) & 0xff) as u8;
217///         }
218///     }
219///
220///     fn mmio_write(&mut self, _base: MmioAddress, _offset: MmioAddressOffset, data: &[u8]) {
221///         self.config = u32::from(data[0]) & 0xff;
222///     }
223/// }
224/// ```
225pub trait MutDeviceMmio {
226    /// Handle a read operation on the device.
227    ///
228    /// # Arguments
229    ///
230    /// * `base`:   base address on a MMIO bus
231    /// * `offset`: base address' offset
232    /// * `data`:   a buffer provided by the caller to store the read data
233    fn mmio_read(&mut self, base: MmioAddress, offset: MmioAddressOffset, data: &mut [u8]);
234
235    /// Handle a write operation to the device.
236    ///
237    /// # Arguments
238    ///
239    /// * `base`:   base address on a MMIO bus
240    /// * `offset`: base address' offset
241    /// * `data`:   a buffer provided by the caller holding the data to write
242    fn mmio_write(&mut self, base: MmioAddress, offset: MmioAddressOffset, data: &[u8]);
243}
244
245// Blanket implementations for Arc<T>.
246
247impl<T: DeviceMmio + ?Sized> DeviceMmio for Arc<T> {
248    fn mmio_read(&self, base: MmioAddress, offset: MmioAddressOffset, data: &mut [u8]) {
249        self.deref().mmio_read(base, offset, data);
250    }
251
252    fn mmio_write(&self, base: MmioAddress, offset: MmioAddressOffset, data: &[u8]) {
253        self.deref().mmio_write(base, offset, data);
254    }
255}
256
257impl<T: DevicePio + ?Sized> DevicePio for Arc<T> {
258    fn pio_read(&self, base: PioAddress, offset: PioAddressOffset, data: &mut [u8]) {
259        self.deref().pio_read(base, offset, data);
260    }
261
262    fn pio_write(&self, base: PioAddress, offset: PioAddressOffset, data: &[u8]) {
263        self.deref().pio_write(base, offset, data);
264    }
265}
266
267// Blanket implementations for Mutex<T>.
268
269impl<T: MutDeviceMmio + ?Sized> DeviceMmio for Mutex<T> {
270    fn mmio_read(&self, base: MmioAddress, offset: MmioAddressOffset, data: &mut [u8]) {
271        self.lock().unwrap().mmio_read(base, offset, data)
272    }
273
274    fn mmio_write(&self, base: MmioAddress, offset: MmioAddressOffset, data: &[u8]) {
275        self.lock().unwrap().mmio_write(base, offset, data)
276    }
277}
278
279impl<T: MutDevicePio + ?Sized> DevicePio for Mutex<T> {
280    fn pio_read(&self, base: PioAddress, offset: PioAddressOffset, data: &mut [u8]) {
281        self.lock().unwrap().pio_read(base, offset, data)
282    }
283
284    fn pio_write(&self, base: PioAddress, offset: PioAddressOffset, data: &[u8]) {
285        self.lock().unwrap().pio_write(base, offset, data)
286    }
287}