#![cfg_attr(not(test), no_std)]
#![cfg_attr(doc, feature(doc_cfg))]
#![doc = include_str!("../README.md")]
#[macro_use]
extern crate log;
mod arch;
#[cfg(any(target_pointer_width = "32", doc, docsrs))]
mod bits32;
#[cfg(any(target_pointer_width = "64", doc, docsrs))]
mod bits64;
use core::fmt::Debug;
use arrayvec::ArrayVec;
use memory_addr::{MemoryAddr, PAGE_SIZE_4K, PhysAddr, VirtAddr};
#[doc(no_inline)]
pub use page_table_entry::{GenericPTE, MappingFlags};
#[cfg(any(target_pointer_width = "32", doc, docsrs))]
pub use self::{
arch::*,
bits32::{PageTable32, PageTable32Cursor},
};
#[cfg(any(target_pointer_width = "64", doc, docsrs))]
pub use self::{
arch::*,
bits64::{PageTable64, PageTable64Cursor},
};
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum PagingError {
NoMemory,
NotAligned,
NotMapped,
AlreadyMapped,
MappedToHugePage,
}
#[cfg(feature = "axerrno")]
impl From<PagingError> for axerrno::AxError {
fn from(value: PagingError) -> Self {
match value {
PagingError::NoMemory => axerrno::AxError::NoMemory,
_ => axerrno::AxError::InvalidInput,
}
}
}
pub type PagingResult<T = ()> = Result<T, PagingError>;
pub trait PagingMetaData: Sync + Send {
const LEVELS: usize;
const PA_MAX_BITS: usize;
const VA_MAX_BITS: usize;
const PA_MAX_ADDR: usize = (1 << Self::PA_MAX_BITS) - 1;
type VirtAddr: MemoryAddr;
#[inline]
fn paddr_is_valid(paddr: usize) -> bool {
paddr <= Self::PA_MAX_ADDR }
#[inline]
fn vaddr_is_valid(vaddr: usize) -> bool {
let top_mask = usize::MAX << (Self::VA_MAX_BITS - 1);
(vaddr & top_mask) == 0 || (vaddr & top_mask) == top_mask
}
fn flush_tlb(vaddr: Option<Self::VirtAddr>);
}
pub trait PagingHandler: Sized {
fn alloc_frame() -> Option<PhysAddr> {
Self::alloc_frames(1, PAGE_SIZE_4K)
}
fn alloc_frames(num: usize, align: usize) -> Option<PhysAddr>;
fn dealloc_frame(paddr: PhysAddr) {
Self::dealloc_frames(paddr, 1)
}
fn dealloc_frames(paddr: PhysAddr, num: usize);
fn phys_to_virt(paddr: PhysAddr) -> VirtAddr;
}
#[repr(usize)]
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum PageSize {
Size4K = 0x1000,
Size1M = 0x10_0000,
Size2M = 0x20_0000,
Size1G = 0x4000_0000,
}
impl PageSize {
pub const fn is_huge(self) -> bool {
matches!(self, Self::Size1G | Self::Size2M | Self::Size1M)
}
pub const fn is_aligned(self, addr_or_size: usize) -> bool {
memory_addr::is_aligned(addr_or_size, self as usize)
}
pub const fn align_offset(self, addr: usize) -> usize {
memory_addr::align_offset(addr, self as usize)
}
}
impl From<PageSize> for usize {
#[inline]
fn from(size: PageSize) -> usize {
size as usize
}
}
const SMALL_FLUSH_THRESHOLD: usize = 32;
enum TlbFlusher<M: PagingMetaData> {
None,
Array(ArrayVec<M::VirtAddr, SMALL_FLUSH_THRESHOLD>),
Full,
}