use core::fmt;
use memory_addr::{AddrRange, MemoryAddr};
use crate::{MappingBackend, MappingError, MappingResult};
pub struct MemoryArea<B: MappingBackend> {
va_range: AddrRange<B::Addr>,
flags: B::Flags,
backend: B,
}
impl<B: MappingBackend> MemoryArea<B> {
pub fn new(start: B::Addr, size: usize, flags: B::Flags, backend: B) -> Self {
Self {
va_range: AddrRange::from_start_size(start, size),
flags,
backend,
}
}
pub const fn va_range(&self) -> AddrRange<B::Addr> {
self.va_range
}
pub const fn flags(&self) -> B::Flags {
self.flags
}
pub const fn start(&self) -> B::Addr {
self.va_range.start
}
pub const fn end(&self) -> B::Addr {
self.va_range.end
}
pub fn size(&self) -> usize {
self.va_range.size()
}
pub const fn backend(&self) -> &B {
&self.backend
}
}
impl<B: MappingBackend> MemoryArea<B> {
pub(crate) fn set_flags(&mut self, new_flags: B::Flags) {
self.flags = new_flags;
}
pub(crate) fn set_end(&mut self, new_end: B::Addr) {
self.va_range.end = new_end;
}
pub(crate) fn map_area(&self, page_table: &mut B::PageTable) -> MappingResult {
self.backend
.map(self.start(), self.size(), self.flags, page_table)
.then_some(())
.ok_or(MappingError::BadState)
}
pub(crate) fn unmap_area(&self, page_table: &mut B::PageTable) -> MappingResult {
self.backend
.unmap(self.start(), self.size(), page_table)
.then_some(())
.ok_or(MappingError::BadState)
}
pub(crate) fn protect_area(
&mut self,
new_flags: B::Flags,
page_table: &mut B::PageTable,
) -> MappingResult {
self.backend
.protect(self.start(), self.size(), new_flags, page_table);
Ok(())
}
pub(crate) fn shrink_left(
&mut self,
new_size: usize,
page_table: &mut B::PageTable,
) -> MappingResult {
assert!(new_size > 0 && new_size < self.size());
let old_size = self.size();
let unmap_size = old_size - new_size;
if !self.backend.unmap(self.start(), unmap_size, page_table) {
return Err(MappingError::BadState);
}
self.va_range.start = self.va_range.start.wrapping_add(unmap_size);
Ok(())
}
pub(crate) fn shrink_right(
&mut self,
new_size: usize,
page_table: &mut B::PageTable,
) -> MappingResult {
assert!(new_size > 0 && new_size < self.size());
let old_size = self.size();
let unmap_size = old_size - new_size;
let unmap_start = self.start().wrapping_add(new_size);
if !self.backend.unmap(unmap_start, unmap_size, page_table) {
return Err(MappingError::BadState);
}
self.va_range.end = self.va_range.end.wrapping_sub(unmap_size);
Ok(())
}
pub(crate) fn split(&mut self, pos: B::Addr) -> Option<Self> {
if self.start() < pos && pos < self.end() {
let new_area = Self::new(
pos,
self.end().wrapping_sub_addr(pos),
self.flags,
self.backend.clone(),
);
self.va_range.end = pos;
Some(new_area)
} else {
None
}
}
}
impl<B: MappingBackend> fmt::Debug for MemoryArea<B>
where
B::Addr: fmt::Debug,
B::Flags: fmt::Debug + Copy,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("MemoryArea")
.field("va_range", &self.va_range)
.field("flags", &self.flags)
.finish()
}
}