2023-06-24 17:18:31 -05:00
|
|
|
//! Page table and associated structures implementation
|
|
|
|
|
2023-07-11 03:33:25 -05:00
|
|
|
use {
|
|
|
|
core::{
|
|
|
|
fmt::Debug,
|
|
|
|
mem::MaybeUninit,
|
|
|
|
ops::{Index, IndexMut},
|
|
|
|
slice::SliceIndex,
|
|
|
|
},
|
|
|
|
delegate::delegate,
|
2023-06-20 19:07:48 -05:00
|
|
|
};
|
|
|
|
|
2023-06-24 17:16:14 -05:00
|
|
|
/// Page entry permission
|
2023-06-20 19:07:48 -05:00
|
|
|
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
|
|
|
#[repr(u8)]
|
|
|
|
pub enum Permission {
|
2023-06-24 17:16:14 -05:00
|
|
|
/// No page present
|
2023-06-20 19:07:48 -05:00
|
|
|
#[default]
|
|
|
|
Empty,
|
2023-06-24 17:16:14 -05:00
|
|
|
/// Points to another pagetable
|
2023-06-20 19:07:48 -05:00
|
|
|
Node,
|
2023-06-24 17:16:14 -05:00
|
|
|
/// Page is read only
|
2023-06-20 19:07:48 -05:00
|
|
|
Readonly,
|
2023-06-24 17:16:14 -05:00
|
|
|
/// Page is readable and writable
|
2023-06-20 19:07:48 -05:00
|
|
|
Write,
|
2023-06-24 17:16:14 -05:00
|
|
|
/// Page is readable and executable
|
2023-06-20 19:07:48 -05:00
|
|
|
Exec,
|
|
|
|
}
|
|
|
|
|
2023-06-24 17:16:14 -05:00
|
|
|
/// Page table entry
|
2023-06-20 19:07:48 -05:00
|
|
|
#[derive(Clone, Copy, Default, PartialEq, Eq)]
|
|
|
|
pub struct PtEntry(u64);
|
|
|
|
impl PtEntry {
|
2023-06-24 17:16:14 -05:00
|
|
|
/// Create new
|
2023-07-11 03:33:25 -05:00
|
|
|
///
|
2023-06-24 17:21:40 -05:00
|
|
|
/// # Safety
|
|
|
|
/// - `ptr` has to point to valid data and shall not be deallocated
|
|
|
|
/// troughout the entry lifetime
|
2023-06-20 19:07:48 -05:00
|
|
|
#[inline]
|
|
|
|
pub unsafe fn new(ptr: *mut PtPointedData, permission: Permission) -> Self {
|
|
|
|
Self(ptr as u64 | permission as u64)
|
|
|
|
}
|
|
|
|
|
2023-06-24 17:16:14 -05:00
|
|
|
/// Get permission
|
2023-06-20 19:07:48 -05:00
|
|
|
#[inline]
|
|
|
|
pub fn permission(&self) -> Permission {
|
|
|
|
unsafe { core::mem::transmute(self.0 as u8 & 0b111) }
|
|
|
|
}
|
|
|
|
|
2023-06-24 17:16:14 -05:00
|
|
|
/// Get pointer to the data (leaf) or next page table (node)
|
2023-06-20 19:07:48 -05:00
|
|
|
#[inline]
|
|
|
|
pub fn ptr(&self) -> *mut PtPointedData {
|
|
|
|
(self.0 & !((1 << 12) - 1)) as _
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Debug for PtEntry {
|
|
|
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
|
|
|
f.debug_struct("PtEntry")
|
|
|
|
.field("ptr", &self.ptr())
|
|
|
|
.field("permission", &self.permission())
|
|
|
|
.finish()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-24 17:16:14 -05:00
|
|
|
/// Page table
|
2023-06-20 19:07:48 -05:00
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
|
|
#[repr(align(4096))]
|
|
|
|
pub struct PageTable([PtEntry; 512]);
|
|
|
|
|
|
|
|
impl PageTable {
|
|
|
|
delegate!(to self.0 {
|
2023-06-24 17:21:40 -05:00
|
|
|
/// Returns a reference to an element or subslice depending on the type of
|
|
|
|
/// index.
|
|
|
|
///
|
|
|
|
/// - If given a position, returns a reference to the element at that
|
|
|
|
/// position or `None` if out of bounds.
|
|
|
|
/// - If given a range, returns the subslice corresponding to that range,
|
|
|
|
/// or `None` if out of bounds.
|
|
|
|
///
|
|
|
|
pub fn get<I>(&self, ix: I) -> Option<&I::Output>
|
2023-06-20 19:07:48 -05:00
|
|
|
where I: SliceIndex<[PtEntry]>;
|
|
|
|
|
2023-06-24 17:21:40 -05:00
|
|
|
/// Returns a mutable reference to an element or subslice depending on the
|
|
|
|
/// type of index (see [`get`]) or `None` if the index is out of bounds.
|
|
|
|
pub fn get_mut<I>(&mut self, ix: I) -> Option<&mut I::Output>
|
2023-06-20 19:07:48 -05:00
|
|
|
where I: SliceIndex<[PtEntry]>;
|
|
|
|
|
2023-06-24 17:21:40 -05:00
|
|
|
/// Returns a reference to an element or subslice, without doing bounds
|
|
|
|
/// checking.
|
|
|
|
///
|
|
|
|
/// For a safe alternative see [`get`].
|
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
///
|
|
|
|
/// Calling this method with an out-of-bounds index is *[undefined behavior]*
|
|
|
|
/// even if the resulting reference is not used.
|
2023-06-20 19:07:48 -05:00
|
|
|
pub unsafe fn get_unchecked<I>(&self, index: I) -> &I::Output
|
|
|
|
where I: SliceIndex<[PtEntry]>;
|
|
|
|
|
2023-06-24 17:21:40 -05:00
|
|
|
/// Returns a mutable reference to an element or subslice, without doing
|
|
|
|
/// bounds checking.
|
|
|
|
///
|
|
|
|
/// For a safe alternative see [`get_mut`].
|
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
///
|
|
|
|
/// Calling this method with an out-of-bounds index is *[undefined behavior]*
|
|
|
|
/// even if the resulting reference is not used.
|
2023-06-20 19:07:48 -05:00
|
|
|
pub unsafe fn get_unchecked_mut<I>(&mut self, index: I) -> &mut I::Output
|
|
|
|
where I: SliceIndex<[PtEntry]>;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<Idx> Index<Idx> for PageTable
|
|
|
|
where
|
|
|
|
Idx: SliceIndex<[PtEntry]>,
|
|
|
|
{
|
|
|
|
type Output = Idx::Output;
|
|
|
|
|
|
|
|
#[inline(always)]
|
|
|
|
fn index(&self, index: Idx) -> &Self::Output {
|
|
|
|
&self.0[index]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<Idx> IndexMut<Idx> for PageTable
|
|
|
|
where
|
|
|
|
Idx: SliceIndex<[PtEntry]>,
|
|
|
|
{
|
|
|
|
#[inline(always)]
|
|
|
|
fn index_mut(&mut self, index: Idx) -> &mut Self::Output {
|
|
|
|
&mut self.0[index]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for PageTable {
|
|
|
|
fn default() -> Self {
|
2023-06-24 17:16:14 -05:00
|
|
|
// SAFETY: It's fine, zeroed page table entry is valid (= empty)
|
2023-06-20 19:07:48 -05:00
|
|
|
Self(unsafe { MaybeUninit::zeroed().assume_init() })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-24 17:16:14 -05:00
|
|
|
/// Data page table entry can possibly point to
|
2023-06-20 19:07:48 -05:00
|
|
|
#[derive(Clone, Copy)]
|
|
|
|
#[repr(C, align(4096))]
|
|
|
|
pub union PtPointedData {
|
2023-06-24 17:16:14 -05:00
|
|
|
/// Node - next page table
|
2023-07-11 03:33:25 -05:00
|
|
|
pub pt: PageTable,
|
2023-06-24 17:16:14 -05:00
|
|
|
/// Leaf
|
2023-06-20 19:07:48 -05:00
|
|
|
pub page: u8,
|
|
|
|
}
|