use consortium_cfg_common::config::MemoryRegion;
use crate::components::uio::{ToUio, UioBacking, UioDevice};
use crate::error::CfgError;
const UIO_MAX_MMAPS: usize = 5;
impl ToUio for [MemoryRegion] {
fn to_uio(&self) -> Result<Option<UioDevice>, CfgError> {
if self.is_empty() {
return Ok(None);
}
if self.len() > UIO_MAX_MMAPS {
return Err(CfgError::UioMmapLimit {
device: "shared-memory".to_string(),
found: self.len(),
max: UIO_MAX_MMAPS,
});
}
let mmap = self
.iter()
.map(|region| (region.base, region.length))
.collect();
Ok(Some(UioDevice {
mmap,
irq: None,
backing: UioBacking::ReservedMemory,
interrupt_parent: None,
clock: None,
}))
}
}
#[cfg(test)]
mod tests {
use super::*;
fn region(base: u32, length: u32) -> MemoryRegion {
MemoryRegion { base, length }
}
#[test]
fn maps_regions_in_slice_order() {
let memory = [region(0x0040_0000, 0x8000), region(0x0040_8000, 0x2000)];
let uio = memory.as_slice().to_uio().unwrap().unwrap();
assert_eq!(uio.mmap, vec![(0x0040_0000, 0x8000), (0x0040_8000, 0x2000)]);
assert!(uio.irq.is_none());
}
#[test]
fn maps_single_region() {
let memory = [region(0x0040_0000, 0x8000)];
let uio = memory.as_slice().to_uio().unwrap().unwrap();
assert_eq!(uio.mmap, vec![(0x0040_0000, 0x8000)]);
}
#[test]
fn none_when_no_regions() {
let memory: [MemoryRegion; 0] = [];
assert!(memory.as_slice().to_uio().unwrap().is_none());
}
#[test]
fn errors_when_more_than_five_regions() {
let memory = [
region(0x0040_0000, 0x1000),
region(0x0040_1000, 0x1000),
region(0x0040_2000, 0x1000),
region(0x0040_3000, 0x1000),
region(0x0040_4000, 0x1000),
region(0x0040_5000, 0x1000),
];
assert_eq!(
memory.as_slice().to_uio().err(),
Some(CfgError::UioMmapLimit {
device: "shared-memory".to_string(),
found: 6,
max: 5,
})
);
}
}