cloud-hypervisor/devices/src/bus.rs
Samuel Ortiz 040ea5432d cloud-hypervisor: Add proper licensing
Add the BSD and Apache license.
Make all crosvm references point to the BSD license.
Add the right copyrights and identifier to our VMM code.
Add Intel copyright to the vm-virtio and pci crates.

Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
2019-05-09 15:44:17 +02:00

267 lines
9.1 KiB
Rust

// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
//
// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE-BSD-3-Clause file.
//! Handles routing to devices in an address space.
use std::cmp::{Ord, Ordering, PartialEq, PartialOrd};
use std::collections::btree_map::BTreeMap;
use std::result;
use std::sync::{Arc, Mutex};
/// Trait for devices that respond to reads or writes in an arbitrary address space.
///
/// The device does not care where it exists in address space as each method is only given an offset
/// into its allocated portion of address space.
#[allow(unused_variables)]
pub trait BusDevice: Send {
/// Reads at `offset` from this device
fn read(&mut self, offset: u64, data: &mut [u8]) {}
/// Writes at `offset` into this device
fn write(&mut self, offset: u64, data: &[u8]) {}
/// Triggers the `irq_mask` interrupt on this device
fn interrupt(&self, irq_mask: u32) {}
/// Sets a register in the configuration space. Only used by PCI.
/// * `reg_idx` - The index of the config register to modify.
/// * `offset` - Offset in to the register.
fn write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8]) {}
/// Gets a register from the configuration space. Only used by PCI.
/// * `reg_idx` - The index of the config register to read.
fn read_config_register(&self, reg_idx: usize) -> u32 {
0
}
}
#[derive(Debug)]
pub enum Error {
/// The insertion failed because the new device overlapped with an old device.
Overlap,
}
pub type Result<T> = result::Result<T, Error>;
#[derive(Debug, Copy, Clone)]
struct BusRange(u64, u64);
impl Eq for BusRange {}
impl PartialEq for BusRange {
fn eq(&self, other: &BusRange) -> bool {
self.0 == other.0
}
}
impl Ord for BusRange {
fn cmp(&self, other: &BusRange) -> Ordering {
self.0.cmp(&other.0)
}
}
impl PartialOrd for BusRange {
fn partial_cmp(&self, other: &BusRange) -> Option<Ordering> {
self.0.partial_cmp(&other.0)
}
}
/// A device container for routing reads and writes over some address space.
///
/// This doesn't have any restrictions on what kind of device or address space this applies to. The
/// only restriction is that no two devices can overlap in this address space.
#[derive(Clone, Default)]
pub struct Bus {
devices: BTreeMap<BusRange, Arc<Mutex<BusDevice>>>,
}
impl Bus {
/// Constructs an a bus with an empty address space.
pub fn new() -> Bus {
Bus {
devices: BTreeMap::new(),
}
}
fn first_before(&self, addr: u64) -> Option<(BusRange, &Mutex<BusDevice>)> {
// for when we switch to rustc 1.17: self.devices.range(..addr).iter().rev().next()
for (range, dev) in self.devices.iter().rev() {
if range.0 <= addr {
return Some((*range, dev));
}
}
None
}
pub fn get_device(&self, addr: u64) -> Option<(u64, &Mutex<BusDevice>)> {
if let Some((BusRange(start, len), dev)) = self.first_before(addr) {
let offset = addr - start;
if offset < len {
return Some((offset, dev));
}
}
None
}
/// Puts the given device at the given address space.
pub fn insert(&mut self, device: Arc<Mutex<BusDevice>>, base: u64, len: u64) -> Result<()> {
if len == 0 {
return Err(Error::Overlap);
}
// Reject all cases where the new device's base is within an old device's range.
if self.get_device(base).is_some() {
return Err(Error::Overlap);
}
// The above check will miss an overlap in which the new device's base address is before the
// range of another device. To catch that case, we search for a device with a range before
// the new device's range's end. If there is no existing device in that range that starts
// after the new device, then there will be no overlap.
if let Some((BusRange(start, _), _)) = self.first_before(base + len - 1) {
// Such a device only conflicts with the new device if it also starts after the new
// device because of our initial `get_device` check above.
if start >= base {
return Err(Error::Overlap);
}
}
if self.devices.insert(BusRange(base, len), device).is_some() {
return Err(Error::Overlap);
}
Ok(())
}
/// Reads data from the device that owns the range containing `addr` and puts it into `data`.
///
/// Returns true on success, otherwise `data` is untouched.
pub fn read(&self, addr: u64, data: &mut [u8]) -> bool {
if let Some((offset, dev)) = self.get_device(addr) {
// OK to unwrap as lock() failing is a serious error condition and should panic.
dev.lock()
.expect("Failed to acquire device lock")
.read(offset, data);
true
} else {
false
}
}
/// Writes `data` to the device that owns the range containing `addr`.
///
/// Returns true on success, otherwise `data` is untouched.
pub fn write(&self, addr: u64, data: &[u8]) -> bool {
if let Some((offset, dev)) = self.get_device(addr) {
// OK to unwrap as lock() failing is a serious error condition and should panic.
dev.lock()
.expect("Failed to acquire device lock")
.write(offset, data);
true
} else {
false
}
}
}
#[cfg(test)]
mod tests {
use super::*;
struct DummyDevice;
impl BusDevice for DummyDevice {}
struct ConstantDevice;
impl BusDevice for ConstantDevice {
fn read(&mut self, offset: u64, data: &mut [u8]) {
for (i, v) in data.iter_mut().enumerate() {
*v = (offset as u8) + (i as u8);
}
}
fn write(&mut self, offset: u64, data: &[u8]) {
for (i, v) in data.iter().enumerate() {
assert_eq!(*v, (offset as u8) + (i as u8))
}
}
}
#[test]
fn bus_insert() {
let mut bus = Bus::new();
let dummy = Arc::new(Mutex::new(DummyDevice));
assert!(bus.insert(dummy.clone(), 0x10, 0).is_err());
assert!(bus.insert(dummy.clone(), 0x10, 0x10).is_ok());
let result = bus.insert(dummy.clone(), 0x0f, 0x10);
assert!(result.is_err());
assert_eq!(format!("{:?}", result), "Err(Overlap)");
assert!(bus.insert(dummy.clone(), 0x10, 0x10).is_err());
assert!(bus.insert(dummy.clone(), 0x10, 0x15).is_err());
assert!(bus.insert(dummy.clone(), 0x12, 0x15).is_err());
assert!(bus.insert(dummy.clone(), 0x12, 0x01).is_err());
assert!(bus.insert(dummy.clone(), 0x0, 0x20).is_err());
assert!(bus.insert(dummy.clone(), 0x20, 0x05).is_ok());
assert!(bus.insert(dummy.clone(), 0x25, 0x05).is_ok());
assert!(bus.insert(dummy.clone(), 0x0, 0x10).is_ok());
}
#[test]
fn bus_read_write() {
let mut bus = Bus::new();
let dummy = Arc::new(Mutex::new(DummyDevice));
assert!(bus.insert(dummy.clone(), 0x10, 0x10).is_ok());
assert!(bus.read(0x10, &mut [0, 0, 0, 0]));
assert!(bus.write(0x10, &[0, 0, 0, 0]));
assert!(bus.read(0x11, &mut [0, 0, 0, 0]));
assert!(bus.write(0x11, &[0, 0, 0, 0]));
assert!(bus.read(0x16, &mut [0, 0, 0, 0]));
assert!(bus.write(0x16, &[0, 0, 0, 0]));
assert!(!bus.read(0x20, &mut [0, 0, 0, 0]));
assert!(!bus.write(0x20, &mut [0, 0, 0, 0]));
assert!(!bus.read(0x06, &mut [0, 0, 0, 0]));
assert!(!bus.write(0x06, &mut [0, 0, 0, 0]));
}
#[test]
fn bus_read_write_values() {
let mut bus = Bus::new();
let dummy = Arc::new(Mutex::new(ConstantDevice));
assert!(bus.insert(dummy.clone(), 0x10, 0x10).is_ok());
let mut values = [0, 1, 2, 3];
assert!(bus.read(0x10, &mut values));
assert_eq!(values, [0, 1, 2, 3]);
assert!(bus.write(0x10, &values));
assert!(bus.read(0x15, &mut values));
assert_eq!(values, [5, 6, 7, 8]);
assert!(bus.write(0x15, &values));
}
#[test]
fn busrange_cmp_and_clone() {
assert_eq!(BusRange(0x10, 2), BusRange(0x10, 3));
assert_eq!(BusRange(0x10, 2), BusRange(0x10, 2));
assert!(BusRange(0x10, 2) < BusRange(0x12, 1));
assert!(BusRange(0x10, 2) < BusRange(0x12, 3));
let bus_range = BusRange(0x10, 2);
assert_eq!(bus_range, bus_range.clone());
let mut bus = Bus::new();
let mut data = [1, 2, 3, 4];
assert!(bus
.insert(Arc::new(Mutex::new(DummyDevice)), 0x10, 0x10)
.is_ok());
assert!(bus.write(0x10, &mut data));
let bus_clone = bus.clone();
assert!(bus.read(0x10, &mut data));
assert_eq!(data, [1, 2, 3, 4]);
assert!(bus_clone.read(0x10, &mut data));
assert_eq!(data, [1, 2, 3, 4]);
}
}