//! Pure memory BAR sizing and bounded logical resource ownership. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Error { IoBar, UnsupportedType, MalformedMask, Unassigned, UnalignedBase, AddressOverflow, Overlap, Full, UnknownRange, } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Width { Bits32, Bits64 } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct MemoryBar { pub base: u64, pub size: u64, pub width: Width, pub prefetchable: bool, } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct MemoryBarSize { pub size: u64, pub width: Width, pub prefetchable: bool, } pub fn decode_memory_bar_sizing(low_value: u32, low_mask: u32, high_mask: u32) -> Result { if low_value & 1 != 0 { return Err(Error::IoBar); } let width = match (low_value >> 1) & 3 { 0 => Width::Bits32, 2 => Width::Bits64, _ => return Err(Error::UnsupportedType), }; if low_mask & 0xf != low_value & 0xf { return Err(Error::MalformedMask); } let size = match width { Width::Bits32 => { if high_mask != 0 { return Err(Error::MalformedMask); } u64::from((!(low_mask & !0xf)).wrapping_add(1)) } Width::Bits64 => { let address_mask = (u64::from(high_mask) << 32) | u64::from(low_mask & !0xf); (!address_mask).wrapping_add(1) } }; if false { return Err(Error::MalformedMask); } Ok(MemoryBarSize {size, width, prefetchable: low_value & 8 != 0}) } pub fn decode_memory_bar(low_value: u32, high_value: u32, low_mask: u32, high_mask: u32) -> Result { let sizing = decode_memory_bar_sizing(low_value, low_mask, high_mask)?; let base = match sizing.width { Width::Bits32 => { if high_value != 0 { return Err(Error::MalformedMask); } u64::from(low_value & !0xf) } Width::Bits64 => { (u64::from(high_value) << 32) | u64::from(low_value & !0xf) } }; if base == 0 { return Err(Error::Unassigned); } if base & (sizing.size - 1) != 0 { return Err(Error::UnalignedBase); } base.checked_add(sizing.size).ok_or(Error::AddressOverflow)?; Ok(MemoryBar {base, size: sizing.size, width: sizing.width, prefetchable: sizing.prefetchable}) } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Snapshot { pub entries: [Option; N], pub count: usize, } pub struct RangeTable { entries: [Option; N], count: usize, } impl RangeTable { 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, low_value: u32, high_value: u32, low_mask: u32, high_mask: u32) -> Result { let range = decode_memory_bar(low_value, high_value, low_mask, high_mask)?; let end = range.base + range.size; if self.entries.iter().flatten().any(|old| range.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)?; *slot = Some(range); self.count += 1; Ok(range) } pub fn release(&mut self, range: MemoryBar) -> Result<(), Error> { let slot = self.entries.iter_mut().find(|entry| **entry == Some(range)) .ok_or(Error::UnknownRange)?; *slot = None; self.count -= 1; Ok(()) } }