pub use self::mapped_page_table::{MappedPageTable, PageTableFrameMapping};
#[cfg(target_pointer_width = "64")]
pub use self::offset_page_table::OffsetPageTable;
#[cfg(target_pointer_width = "64")]
pub use self::offset_page_table::OffsetPageTable5;
#[cfg(all(feature = "instructions", target_arch = "x86_64"))]
pub use self::recursive_page_table::{InvalidPageTable, RecursivePageTable};
use crate::structures::paging::{
frame_alloc::{FrameAllocator, FrameDeallocator},
page::PageRangeInclusive,
page_table::PageTableFlags,
Page, PageSize, PhysFrame, Size1GiB, Size2MiB, Size4KiB,
};
use crate::{PhysAddr, VirtAddr};
mod mapped_page_table;
mod offset_page_table;
#[cfg(all(feature = "instructions", target_arch = "x86_64"))]
mod recursive_page_table;
pub trait MapperAllSizes: Mapper<Size4KiB> + Mapper<Size2MiB> + Mapper<Size1GiB> {}
impl<T> MapperAllSizes for T where T: Mapper<Size4KiB> + Mapper<Size2MiB> + Mapper<Size1GiB> {}
pub trait Translate {
fn translate(&self, addr: VirtAddr) -> TranslateResult;
#[inline]
fn translate_addr(&self, addr: VirtAddr) -> Option<PhysAddr> {
match self.translate(addr) {
TranslateResult::NotMapped | TranslateResult::InvalidFrameAddress(_) => None,
TranslateResult::Mapped { frame, offset, .. } => Some(frame.start_address() + offset),
}
}
}
#[derive(Debug)]
pub enum TranslateResult {
Mapped {
frame: MappedFrame,
offset: u64,
flags: PageTableFlags,
},
NotMapped,
InvalidFrameAddress(PhysAddr),
}
#[derive(Debug)]
pub enum MappedFrame {
Size4KiB(PhysFrame<Size4KiB>),
Size2MiB(PhysFrame<Size2MiB>),
Size1GiB(PhysFrame<Size1GiB>),
}
impl MappedFrame {
pub const fn start_address(&self) -> PhysAddr {
match self {
MappedFrame::Size4KiB(frame) => frame.start_address,
MappedFrame::Size2MiB(frame) => frame.start_address,
MappedFrame::Size1GiB(frame) => frame.start_address,
}
}
pub const fn size(&self) -> u64 {
match self {
MappedFrame::Size4KiB(_) => Size4KiB::SIZE,
MappedFrame::Size2MiB(_) => Size2MiB::SIZE,
MappedFrame::Size1GiB(_) => Size1GiB::SIZE,
}
}
}
pub trait Mapper<S: PageSize> {
#[inline]
unsafe fn map_to<A>(
&mut self,
page: Page<S>,
frame: PhysFrame<S>,
flags: PageTableFlags,
frame_allocator: &mut A,
) -> Result<MapperFlush<S>, MapToError<S>>
where
Self: Sized,
A: FrameAllocator<Size4KiB> + ?Sized,
{
let parent_table_flags = flags
& (PageTableFlags::PRESENT
| PageTableFlags::WRITABLE
| PageTableFlags::USER_ACCESSIBLE);
unsafe {
self.map_to_with_table_flags(page, frame, flags, parent_table_flags, frame_allocator)
}
}
unsafe fn map_to_with_table_flags<A>(
&mut self,
page: Page<S>,
frame: PhysFrame<S>,
flags: PageTableFlags,
parent_table_flags: PageTableFlags,
frame_allocator: &mut A,
) -> Result<MapperFlush<S>, MapToError<S>>
where
Self: Sized,
A: FrameAllocator<Size4KiB> + ?Sized;
fn unmap(&mut self, page: Page<S>) -> Result<(PhysFrame<S>, MapperFlush<S>), UnmapError>;
unsafe fn update_flags(
&mut self,
page: Page<S>,
flags: PageTableFlags,
) -> Result<MapperFlush<S>, FlagUpdateError>;
unsafe fn set_flags_p4_entry(
&mut self,
page: Page<S>,
flags: PageTableFlags,
) -> Result<MapperFlushAll, FlagUpdateError>;
unsafe fn set_flags_p3_entry(
&mut self,
page: Page<S>,
flags: PageTableFlags,
) -> Result<MapperFlushAll, FlagUpdateError>;
unsafe fn set_flags_p2_entry(
&mut self,
page: Page<S>,
flags: PageTableFlags,
) -> Result<MapperFlushAll, FlagUpdateError>;
fn translate_page(&self, page: Page<S>) -> Result<PhysFrame<S>, TranslateError>;
#[inline]
unsafe fn identity_map<A>(
&mut self,
frame: PhysFrame<S>,
flags: PageTableFlags,
frame_allocator: &mut A,
) -> Result<MapperFlush<S>, MapToError<S>>
where
Self: Sized,
A: FrameAllocator<Size4KiB> + ?Sized,
S: PageSize,
Self: Mapper<S>,
{
let page = Page::containing_address(VirtAddr::new(frame.start_address().as_u64()));
unsafe { self.map_to(page, frame, flags, frame_allocator) }
}
}
#[derive(Debug)]
#[must_use = "Page Table changes must be flushed or ignored."]
#[cfg_attr(
not(all(feature = "instructions", target_arch = "x86_64")),
allow(dead_code)
)] pub struct MapperFlush<S: PageSize>(Page<S>);
impl<S: PageSize> MapperFlush<S> {
#[inline]
pub fn new(page: Page<S>) -> Self {
MapperFlush(page)
}
#[cfg(all(feature = "instructions", target_arch = "x86_64"))]
#[inline]
pub fn flush(self) {
crate::instructions::tlb::flush(self.0.start_address());
}
#[inline]
pub fn ignore(self) {}
#[inline]
pub fn page(&self) -> Page<S> {
self.0
}
}
#[derive(Debug, Default)]
#[must_use = "Page Table changes must be flushed or ignored."]
pub struct MapperFlushAll(());
impl MapperFlushAll {
#[inline]
pub fn new() -> Self {
MapperFlushAll(())
}
#[cfg(all(feature = "instructions", target_arch = "x86_64"))]
#[inline]
pub fn flush_all(self) {
crate::instructions::tlb::flush_all()
}
#[inline]
pub fn ignore(self) {}
}
#[derive(Debug)]
pub enum MapToError<S: PageSize> {
FrameAllocationFailed,
ParentEntryHugePage,
PageAlreadyMapped(PhysFrame<S>),
}
#[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),
}
static _ASSERT_OBJECT_SAFE: Option<&(dyn Translate + Sync)> = None;
pub trait CleanUp {
unsafe fn clean_up<D>(&mut self, frame_deallocator: &mut D)
where
D: FrameDeallocator<Size4KiB>;
unsafe fn clean_up_addr_range<D>(
&mut self,
range: PageRangeInclusive,
frame_deallocator: &mut D,
) where
D: FrameDeallocator<Size4KiB>;
}