use core::arch::asm;
use core::mem::{align_of, size_of};
use core::{fmt, mem};
use super::regs;
pub fn enable() {
super::regs::Cr0::update(|v| v.with_paging(true).with_write_protect(true));
}
pub fn invalidate_tlb(page: Virtual) {
unsafe { asm!("invlpg [{}]", in(reg) page.ptr()) };
}
#[derive(Clone)]
#[repr(align(0x1000))]
pub struct Page {
pub data: [u8; Page::SIZE],
}
const _: () = assert!(size_of::<Page>() == Page::SIZE);
const _: () = assert!(align_of::<Page>() == Page::SIZE);
impl Page {
pub const BITS: usize = 12; pub const SIZE: usize = 1 << Page::BITS;
pub const fn new() -> Self {
Self {
data: [0; Page::SIZE],
}
}
}
pub const ENTRIES: usize = Page::SIZE / size_of::<usize>();
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Virtual(pub usize);
impl Virtual {
pub fn new<T>(ptr: *mut T) -> Self {
Self(ptr as usize / Page::SIZE)
}
pub fn idx(dir: usize, table: usize) -> Self {
Self(dir * ENTRIES + table)
}
pub const fn ptr(self) -> *mut Page {
(self.0 * Page::SIZE) as _
}
pub fn dir_idx(self) -> usize {
self.0 / ENTRIES
}
pub fn table_idx(self) -> usize {
self.0 % ENTRIES
}
}
impl fmt::Debug for Virtual {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "V{:x}", self.0)
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Physical(pub usize);
impl Physical {
pub fn new<T>(ptr: *mut T) -> Self {
Self(ptr as usize / Page::SIZE)
}
pub const fn ptr(self) -> *mut Page {
(self.0 * Page::SIZE) as _
}
pub const fn from_bits(v: u32) -> Self {
Self(v as _)
}
pub const fn into_bits(self) -> u32 {
self.0 as _
}
}
impl fmt::Debug for Physical {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "P{:x}", self.0)
}
}