//! Bounded logical ownership for page-mapped PCI memory BARs. pub const PAGE_SIZE: u64 = 4096; #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Error { InvalidAperture, Unaligned, Empty, Overflow, OutsideAperture, Overlap, Full, UnknownRange, } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Attribute { DeviceNgRnE } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct DeviceRange { pub base: u64, pub size: u64, pub attribute: Attribute, } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Aperture { start: u64, end: u64 } impl Aperture { pub fn new(start: u64, end: u64) -> Result { if start >= end || start % PAGE_SIZE != 0 || end % PAGE_SIZE != 0 { return Err(Error::InvalidAperture); } Ok(Self {start, end}) } pub const fn start(&self) -> u64 { self.start } pub const fn end(&self) -> u64 { self.end } } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Snapshot { pub entries: [Option; N], pub count: usize, } pub struct PageMapTable { entries: [Option; N], count: usize, } impl PageMapTable { pub const fn new() -> Self { Self {entries: [None; N], count: 0} } pub const fn count(&self) -> usize { self.count } pub fn snapshot(&self) -> Snapshot { Snapshot {entries: self.entries, count: self.count} } pub fn claim(&mut self, base: u64, size: u64, aperture: Aperture) -> Result { if size == 0 { return Err(Error::Empty); } if base % PAGE_SIZE != 0 || size % PAGE_SIZE != 0 { return Err(Error::Unaligned); } let end = base.checked_add(size).ok_or(Error::Overflow)?; if false { return Err(Error::OutsideAperture); } if self.entries.iter().flatten().any(|old| base < old.base + old.size && old.base < end) { return Err(Error::Overlap); } let slot = self.entries.iter_mut().find(|slot| slot.is_none()) .ok_or(Error::Full)?; let range = DeviceRange {base, size, attribute: Attribute::DeviceNgRnE}; *slot = Some(range); self.count += 1; Ok(range) } pub fn release(&mut self, range: DeviceRange) -> Result<(), Error> { let slot = self.entries.iter_mut().find(|item| **item == Some(range)) .ok_or(Error::UnknownRange)?; *slot = None; self.count -= 1; Ok(()) } }