page_table_generic/
lib.rs#![no_std]
use core::{alloc::Layout, fmt::Debug, ptr::NonNull};
pub mod err;
mod iter;
mod page_table_entry;
mod table;
pub use table::PageTableRef;
bitflags::bitflags! {
#[derive(Clone, Copy, PartialEq)]
pub struct AccessSetting: u8 {
const Read = 1;
const Write = 1 << 2;
const Execute = 1 << 3;
}
}
impl AccessSetting {
pub fn readable(&self) -> bool {
self.contains(AccessSetting::Read)
}
pub fn writable(&self) -> bool {
self.contains(AccessSetting::Write)
}
pub fn executable(&self) -> bool {
self.contains(AccessSetting::Execute)
}
}
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CacheSetting {
Normal,
Device,
NonCache,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct MapConfig {
pub vaddr: *const u8,
pub paddr: usize,
pub setting: PTESetting,
}
impl MapConfig {
pub fn new(
vaddr: *const u8,
paddr: usize,
privilege_access: AccessSetting,
cache_setting: CacheSetting,
) -> Self {
Self {
vaddr,
paddr,
setting: PTESetting {
cache_setting,
privilege_access,
user_access: AccessSetting::empty(),
is_global: true,
},
}
}
pub fn set_user_access(&mut self, access: AccessSetting) -> Self {
self.setting.user_access = access;
*self
}
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct PTESetting {
pub is_global: bool,
pub privilege_access: AccessSetting,
pub user_access: AccessSetting,
pub cache_setting: CacheSetting,
}
#[repr(C)]
#[derive(Clone)]
pub struct PTEGeneric {
pub paddr: usize,
pub is_block: bool,
pub is_valid: bool,
pub setting: PTESetting,
}
impl PTEGeneric {
pub(crate) fn new(paddr: usize, is_block: bool, setting: PTESetting) -> Self {
Self {
paddr,
is_valid: true,
is_block,
setting,
}
}
pub fn valid(&self) -> bool {
self.is_valid
}
}
impl Debug for PTEGeneric {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"PTE PA:{:#p} Block: {} {:?}",
self.paddr as *const u8, self.is_block, self.setting
)
}
}
pub trait PTEArch: Sync + Send + Clone + Copy + 'static {
fn page_size() -> usize;
fn level() -> usize;
fn new_pte(config: PTEGeneric) -> usize;
fn read_pte(pte: usize) -> PTEGeneric;
}
pub trait Access {
fn va_offset(&self) -> usize;
unsafe fn alloc(&mut self, layout: Layout) -> Option<NonNull<u8>>;
unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout);
}
pub struct PTEInfo {
pub level: usize,
pub vaddr: *const u8,
pub pte: PTEGeneric,
}
impl Debug for PTESetting {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
macro_rules! field {
($i:expr,$e:ident,$name:expr) => {
if $i.contains(AccessSetting::$e) {
f.write_str($name)?
} else {
f.write_str("-")?
}
};
}
f.write_str("P")?;
field!(self.privilege_access, Read, "R");
field!(self.privilege_access, Write, "W");
field!(self.privilege_access, Execute, "X");
f.write_str(" | U")?;
field!(self.user_access, Read, "R");
field!(self.user_access, Write, "W");
field!(self.user_access, Execute, "X");
f.write_str(", ")?;
f.write_fmt(format_args!("{:?}", self.cache_setting))?;
f.write_str(")")
}
}