use core::ops::{Deref, DerefMut};
use core::{fmt, ops::Range};
pub use memory_addr::{PAGE_SIZE_4K, PhysAddr, VirtAddr, pa, va};
bitflags::bitflags! {
#[derive(Clone, Copy)]
pub struct MemRegionFlags: usize {
const READ = 1 << 0;
const WRITE = 1 << 1;
const EXECUTE = 1 << 2;
const DEVICE = 1 << 4;
const UNCACHED = 1 << 5;
const RESERVED = 1 << 6;
const FREE = 1 << 7;
}
}
impl fmt::Debug for MemRegionFlags {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&self.0, f)
}
}
pub const DEFAULT_RAM_FLAGS: MemRegionFlags = MemRegionFlags::READ
.union(MemRegionFlags::WRITE)
.union(MemRegionFlags::FREE);
pub const DEFAULT_RESERVED_FLAGS: MemRegionFlags = MemRegionFlags::READ
.union(MemRegionFlags::WRITE)
.union(MemRegionFlags::RESERVED);
pub const DEFAULT_MMIO_FLAGS: MemRegionFlags = MemRegionFlags::READ
.union(MemRegionFlags::WRITE)
.union(MemRegionFlags::DEVICE)
.union(MemRegionFlags::RESERVED);
pub type RawRange = (usize, usize);
#[repr(align(4096))]
pub struct Aligned4K<T: Sized>(T);
impl<T: Sized> Aligned4K<T> {
pub const fn new(value: T) -> Self {
Self(value)
}
}
impl<T> Deref for Aligned4K<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T> DerefMut for Aligned4K<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
#[derive(Debug, Clone, Copy)]
pub struct PhysMemRegion {
pub paddr: PhysAddr,
pub size: usize,
pub flags: MemRegionFlags,
pub name: &'static str,
}
impl PhysMemRegion {
pub const fn new_ram(start: usize, size: usize, name: &'static str) -> Self {
Self {
paddr: PhysAddr::from_usize(start),
size,
flags: DEFAULT_RAM_FLAGS,
name,
}
}
pub const fn new_mmio(start: usize, size: usize, name: &'static str) -> Self {
Self {
paddr: PhysAddr::from_usize(start),
size,
flags: DEFAULT_MMIO_FLAGS,
name,
}
}
pub const fn new_reserved(start: usize, size: usize, name: &'static str) -> Self {
Self {
paddr: PhysAddr::from_usize(start),
size,
flags: DEFAULT_RESERVED_FLAGS,
name,
}
}
}
#[def_plat_interface]
pub trait MemIf {
fn phys_ram_ranges() -> &'static [RawRange];
fn reserved_phys_ram_ranges() -> &'static [RawRange];
fn mmio_ranges() -> &'static [RawRange];
fn phys_to_virt(paddr: PhysAddr) -> VirtAddr;
fn virt_to_phys(vaddr: VirtAddr) -> PhysAddr;
fn kernel_aspace() -> (VirtAddr, usize);
}
pub fn total_ram_size() -> usize {
phys_ram_ranges().iter().map(|range| range.1).sum()
}
pub type OverlapErr = (Range<usize>, Range<usize>);
pub fn check_sorted_ranges_overlap(
ranges: impl Iterator<Item = RawRange>,
) -> Result<(), OverlapErr> {
let mut prev = Range::default();
for (start, size) in ranges {
if prev.end > start {
return Err((prev, start..start + size));
}
prev = start..start + size;
}
Ok(())
}
pub fn ranges_difference<F>(
from: &[RawRange],
exclude: &[RawRange],
mut result_op: F,
) -> Result<(), OverlapErr>
where
F: FnMut(RawRange),
{
check_sorted_ranges_overlap(exclude.iter().cloned())?;
for &(start, size) in from {
let mut start = start;
let end = start + size;
for &(exclude_start, exclude_size) in exclude {
let exclude_end = exclude_start + exclude_size;
if exclude_end <= start {
continue;
} else if exclude_start >= end {
break;
} else if exclude_start > start {
result_op((start, exclude_start - start));
}
start = exclude_end;
}
if start < end {
result_op((start, end - start));
}
}
Ok(())
}
#[cfg(test)]
mod tests {
#[test]
fn check_sorted_ranges_overlap() {
use super::check_sorted_ranges_overlap as f;
assert!(f([(0, 10), (10, 10), (20, 10)].into_iter()).is_ok());
assert!(f([(0, 10), (20, 10), (40, 10)].into_iter()).is_ok());
assert_eq!(f([(0, 1), (0, 2)].into_iter()), Err((0..1, 0..2)));
assert_eq!(
f([(0, 11), (10, 10), (20, 10)].into_iter()),
Err((0..11, 10..20)),
);
assert_eq!(
f([(0, 10), (20, 10), (10, 10)].into_iter()),
Err((20..30, 10..20)), );
}
#[test]
fn ranges_difference() {
let f = |from, exclude| {
let mut res = Vec::new();
super::ranges_difference(from, exclude, |r| res.push(r)).unwrap();
res
};
assert_eq!(
f(&[(0, 10), (20, 10)], &[(5, 5), (25, 5)]), &[(0, 5), (20, 5)] );
assert_eq!(
f(&[(0, 10), (20, 10)], &[(5, 10), (15, 5)]), &[(0, 5), (20, 10)] );
assert_eq!(
f(&[(0, 10), (20, 10)], &[(5, 1), (25, 1), (30, 1)]), &[(0, 5), (6, 4), (20, 5), (26, 4)] );
assert_eq!(f(&[(0, 10), (20, 10)], &[(5, 20)]), &[(0, 5), (25, 5)]); assert_eq!(f(&[(0, 10), (20, 10)], &[(0, 30)]), &[]);
assert_eq!(
f(&[(0, 30)], &[(0, 5), (10, 5), (20, 5)]), &[(5, 5), (15, 5), (25, 5)] );
assert_eq!(
f(
&[(0, 30)],
&[(0, 5), (5, 5), (10, 5), (15, 5), (20, 5), (25, 5)] ),
&[] );
assert_eq!(f(&[(10, 10)], &[(0, 30)]), &[]); }
}