mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2025-02-22 11:22:26 +00:00
devices: bus: Sync with crosvm code
Partial sync as we're not going to use the the full_addr boolean. This is based on crosvm commit 44863792. Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
This commit is contained in:
parent
4a15316101
commit
33796c4b0b
@ -34,26 +34,40 @@ pub enum Error {
|
|||||||
|
|
||||||
pub type Result<T> = result::Result<T, Error>;
|
pub type Result<T> = result::Result<T, Error>;
|
||||||
|
|
||||||
|
/// Holds a base and length representing the address space occupied by a `BusDevice`.
|
||||||
|
///
|
||||||
|
/// * base - The address at which the range start.
|
||||||
|
/// * len - The length of the range in bytes.
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
struct BusRange(u64, u64);
|
pub struct BusRange {
|
||||||
|
pub base: u64,
|
||||||
|
pub len: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BusRange {
|
||||||
|
/// Returns true if there is overlap with the given range.
|
||||||
|
pub fn overlaps(&self, base: u64, len: u64) -> bool {
|
||||||
|
self.base < (base + len) && base < self.base + self.len
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Eq for BusRange {}
|
impl Eq for BusRange {}
|
||||||
|
|
||||||
impl PartialEq for BusRange {
|
impl PartialEq for BusRange {
|
||||||
fn eq(&self, other: &BusRange) -> bool {
|
fn eq(&self, other: &BusRange) -> bool {
|
||||||
self.0 == other.0
|
self.base == other.base
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ord for BusRange {
|
impl Ord for BusRange {
|
||||||
fn cmp(&self, other: &BusRange) -> Ordering {
|
fn cmp(&self, other: &BusRange) -> Ordering {
|
||||||
self.0.cmp(&other.0)
|
self.base.cmp(&other.base)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialOrd for BusRange {
|
impl PartialOrd for BusRange {
|
||||||
fn partial_cmp(&self, other: &BusRange) -> Option<Ordering> {
|
fn partial_cmp(&self, other: &BusRange) -> Option<Ordering> {
|
||||||
self.0.partial_cmp(&other.0)
|
self.base.partial_cmp(&other.base)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,19 +89,18 @@ impl Bus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn first_before(&self, addr: u64) -> Option<(BusRange, &Mutex<BusDevice>)> {
|
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()
|
let (range, dev) = self
|
||||||
for (range, dev) in self.devices.iter().rev() {
|
.devices
|
||||||
if range.0 <= addr {
|
.range(..=BusRange { base: addr, len: 1 })
|
||||||
return Some((*range, dev));
|
.rev()
|
||||||
}
|
.next()?;
|
||||||
}
|
Some((*range, dev))
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_device(&self, addr: u64) -> Option<(u64, &Mutex<BusDevice>)> {
|
pub fn get_device(&self, addr: u64) -> Option<(u64, &Mutex<BusDevice>)> {
|
||||||
if let Some((BusRange(start, len), dev)) = self.first_before(addr) {
|
if let Some((range, dev)) = self.first_before(addr) {
|
||||||
let offset = addr - start;
|
let offset = addr - range.base;
|
||||||
if offset < len {
|
if offset < range.len {
|
||||||
return Some((offset, dev));
|
return Some((offset, dev));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -100,24 +113,20 @@ impl Bus {
|
|||||||
return Err(Error::Overlap);
|
return Err(Error::Overlap);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reject all cases where the new device's base is within an old device's range.
|
// Reject all cases where the new device's range overlaps with an existing device.
|
||||||
if self.get_device(base).is_some() {
|
if self
|
||||||
|
.devices
|
||||||
|
.iter()
|
||||||
|
.any(|(range, _dev)| range.overlaps(base, len))
|
||||||
|
{
|
||||||
return Err(Error::Overlap);
|
return Err(Error::Overlap);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The above check will miss an overlap in which the new device's base address is before the
|
if self
|
||||||
// range of another device. To catch that case, we search for a device with a range before
|
.devices
|
||||||
// the new device's range's end. If there is no existing device in that range that starts
|
.insert(BusRange { base, len }, device)
|
||||||
// after the new device, then there will be no overlap.
|
.is_some()
|
||||||
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);
|
return Err(Error::Overlap);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -232,14 +241,14 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn busrange_cmp_and_clone() {
|
fn busrange_cmp_and_clone() {
|
||||||
assert_eq!(BusRange(0x10, 2), BusRange(0x10, 3));
|
let range = BusRange { base: 0x10, len: 2 };
|
||||||
assert_eq!(BusRange(0x10, 2), BusRange(0x10, 2));
|
assert_eq!(range, BusRange { base: 0x10, len: 3 });
|
||||||
|
assert_eq!(range, BusRange { base: 0x10, len: 2 });
|
||||||
|
|
||||||
assert!(BusRange(0x10, 2) < BusRange(0x12, 1));
|
assert!(range < BusRange { base: 0x12, len: 1 });
|
||||||
assert!(BusRange(0x10, 2) < BusRange(0x12, 3));
|
assert!(range < BusRange { base: 0x12, len: 3 });
|
||||||
|
|
||||||
let bus_range = BusRange(0x10, 2);
|
assert_eq!(range, range.clone());
|
||||||
assert_eq!(bus_range, bus_range.clone());
|
|
||||||
|
|
||||||
let mut bus = Bus::new();
|
let mut bus = Bus::new();
|
||||||
let mut data = [1, 2, 3, 4];
|
let mut data = [1, 2, 3, 4];
|
||||||
@ -253,4 +262,20 @@ mod tests {
|
|||||||
assert!(bus_clone.read(0x10, &mut data));
|
assert!(bus_clone.read(0x10, &mut data));
|
||||||
assert_eq!(data, [1, 2, 3, 4]);
|
assert_eq!(data, [1, 2, 3, 4]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn bus_range_overlap() {
|
||||||
|
let a = BusRange {
|
||||||
|
base: 0x1000,
|
||||||
|
len: 0x400,
|
||||||
|
};
|
||||||
|
assert!(a.overlaps(0x1000, 0x400));
|
||||||
|
assert!(a.overlaps(0xf00, 0x400));
|
||||||
|
assert!(a.overlaps(0x1000, 0x01));
|
||||||
|
assert!(a.overlaps(0xfff, 0x02));
|
||||||
|
assert!(a.overlaps(0x1100, 0x100));
|
||||||
|
assert!(a.overlaps(0x13ff, 0x100));
|
||||||
|
assert!(!a.overlaps(0x1400, 0x100));
|
||||||
|
assert!(!a.overlaps(0xf00, 0x100));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user