pub use self::mapped_page_table::MappedPageTable;
#[cfg(target_arch = "x86_64")]
pub use self::recursive_page_table::RecursivePageTable;
use crate::structures::paging::{
frame_alloc::FrameAllocator, page_table::PageTableFlags, Page, PageSize, PhysFrame, Size1GiB,
Size2MiB, Size4KiB,
};
use crate::{PhysAddr, VirtAddr};
mod mapped_page_table;
mod recursive_page_table;
pub trait MapperAllSizes: Mapper<Size4KiB> + Mapper<Size2MiB> + Mapper<Size1GiB> {
fn translate(&self, addr: VirtAddr) -> TranslateResult;
fn translate_addr(&self, addr: VirtAddr) -> Option<PhysAddr> {
match self.translate(addr) {
TranslateResult::PageNotMapped | TranslateResult::InvalidFrameAddress(_) => None,
TranslateResult::Frame4KiB { frame, offset } => Some(frame.start_address() + offset),
TranslateResult::Frame2MiB { frame, offset } => Some(frame.start_address() + offset),
TranslateResult::Frame1GiB { frame, offset } => Some(frame.start_address() + offset),
}
}
}
#[derive(Debug)]
pub enum TranslateResult {
Frame4KiB {
frame: PhysFrame<Size4KiB>,
offset: u64,
},
Frame2MiB {
frame: PhysFrame<Size2MiB>,
offset: u64,
},
Frame1GiB {
frame: PhysFrame<Size1GiB>,
offset: u64,
},
PageNotMapped,
InvalidFrameAddress(PhysAddr),
}
pub trait Mapper<S: PageSize> {
unsafe fn map_to<A>(
&mut self,
page: Page<S>,
frame: PhysFrame<S>,
flags: PageTableFlags,
frame_allocator: &mut A,
) -> Result<MapperFlush<S>, MapToError>
where
A: FrameAllocator<Size4KiB>;
fn unmap(&mut self, page: Page<S>) -> Result<(PhysFrame<S>, MapperFlush<S>), UnmapError>;
fn update_flags(
&mut self,
page: Page<S>,
flags: PageTableFlags,
) -> Result<MapperFlush<S>, FlagUpdateError>;
fn translate_page(&self, page: Page<S>) -> Result<PhysFrame<S>, TranslateError>;
unsafe fn identity_map<A>(
&mut self,
frame: PhysFrame<S>,
flags: PageTableFlags,
frame_allocator: &mut A,
) -> Result<MapperFlush<S>, MapToError>
where
A: FrameAllocator<Size4KiB>,
S: PageSize,
Self: Mapper<S>,
{
let page = Page::containing_address(VirtAddr::new(frame.start_address().as_u64()));
self.map_to(page, frame, flags, frame_allocator)
}
}
#[derive(Debug)]
#[must_use = "Page Table changes must be flushed or ignored."]
pub struct MapperFlush<S: PageSize>(Page<S>);
impl<S: PageSize> MapperFlush<S> {
fn new(page: Page<S>) -> Self {
MapperFlush(page)
}
#[cfg(target_arch = "x86_64")]
pub fn flush(self) {
crate::instructions::tlb::flush(self.0.start_address());
}
pub fn ignore(self) {}
}
#[derive(Debug)]
pub enum MapToError {
FrameAllocationFailed,
ParentEntryHugePage,
PageAlreadyMapped,
}
#[derive(Debug)]
pub enum UnmapError {
ParentEntryHugePage,
PageNotMapped,
InvalidFrameAddress(PhysAddr),
}
#[derive(Debug)]
pub enum FlagUpdateError {
PageNotMapped,
ParentEntryHugePage,
}
#[derive(Debug)]
pub enum TranslateError {
PageNotMapped,
ParentEntryHugePage,
InvalidFrameAddress(PhysAddr),
}