use core::{marker::PhantomData, ptr::NonNull}; use eonix_mm::{ address::{Addr as _, PAddr}, page_table::{PageAttribute, PageTableLevel, PagingMode, RawPageTable, PTE}, paging::{PageBlock, PFN}, }; pub const PAGE_SIZE: usize = 0x1000; const PAGE_TABLE_BASE: PFN = PFN::from_val(0x8030_0000 >> 12); const PA_V: u64 = 0b1 << 0; const PA_R: u64 = 0b1 << 1; const PA_W: u64 = 0b1 << 2; const PA_X: u64 = 0b1 << 3; const PA_U: u64 = 0b1 << 4; const PA_G: u64 = 0b1 << 5; const PA_A: u64 = 0b1 << 6; const PA_D: u64 = 0b1 << 7; // in RSW const PA_COW: u64 = 0b1 << 8; const PA_MMAP: u64 = 0b1 << 9; const PA_SHIFT: u64 = 10; const PA_MASK: u64 = 0xFFC0_0000_0000_03FF; // 44 bit PPN, from 10 to 53 // Bit 0-9 (V, R, W, X, U, G, A, D, RSW) const PA_FLAGS_MASK: u64 = 0x3FF; // 0b11_1111_1111 #[repr(transparent)] pub struct PTE64(u64); #[derive(Clone, Copy)] pub struct PageAttribute64(u64); pub struct RawPageTableSv39<'a>(NonNull, PhantomData<&'a ()>); pub struct PagingModeSv39; impl PTE for PTE64 { type Attr = PageAttribute64; fn set(&mut self, pfn: PFN, attr: Self::Attr) { self.0 = (PAddr::from(pfn).addr() as u64 & !PA_MASK) | (attr.0 & PA_MASK); } fn get(&self) -> (PFN, Self::Attr) { ( PFN::from(PAddr::from((self.0 & !PA_MASK) as usize)), PageAttribute64(self.0 & PA_MASK), ) } fn take(&mut self) -> (PFN, Self::Attr) { let pfn_attr = self.get(); self.0 = 0; pfn_attr } } impl PagingMode for PagingModeSv39 { type Entry = PTE64; type RawTable<'a> = RawPageTableSv39<'a>; const LEVELS: &'static [PageTableLevel] = &[ PageTableLevel::new(30, 9), PageTableLevel::new(21, 9), PageTableLevel::new(12, 9), ]; const KERNEL_ROOT_TABLE_PFN: PFN = PAGE_TABLE_BASE; } impl<'a> RawPageTable<'a> for RawPageTableSv39<'a> { type Entry = PTE64; fn index(&self, index: u16) -> &'a Self::Entry { unsafe { &self.0.cast::<[PTE64; 512]>().as_ref()[index as usize] } } fn index_mut(&mut self, index: u16) -> &'a mut Self::Entry { unsafe { &mut self.0.cast::<[PTE64; 512]>().as_mut()[index as usize] } } unsafe fn from_ptr(ptr: NonNull) -> Self { Self(ptr.cast(), PhantomData) } } impl PageAttribute for PageAttribute64 { fn new() -> Self { Self(PA_R) } fn present(self, present: bool) -> Self { if present { Self(self.0 | PA_V) } else { Self(self.0 & !PA_V) } } fn write(self, write: bool) -> Self { if write { Self(self.0 | PA_W) } else { Self(self.0 & !PA_W) } } fn execute(self, execute: bool) -> Self { if execute { Self(self.0 | PA_X) } else { Self(self.0 & !PA_X) } } fn user(self, user: bool) -> Self { if user { Self(self.0 | PA_U) } else { Self(self.0 & !PA_U) } } fn accessed(self, accessed: bool) -> Self { if accessed { Self(self.0 | PA_A) } else { Self(self.0 & !PA_A) } } fn dirty(self, dirty: bool) -> Self { if dirty { Self(self.0 | PA_D) } else { Self(self.0 & !PA_D) } } fn global(self, global: bool) -> Self { if global { Self(self.0 | PA_G) } else { Self(self.0 & !PA_G) } } fn copy_on_write(self, cow: bool) -> Self { if cow { Self(self.0 | PA_COW) } else { Self(self.0 & !PA_COW) } } fn mapped(self, mmap: bool) -> Self { if mmap { Self(self.0 | PA_MMAP) } else { Self(self.0 & !PA_MMAP) } } fn is_present(&self) -> bool { self.0 & PA_V != 0 } fn is_write(&self) -> bool { self.0 & PA_W != 0 } fn is_execute(&self) -> bool { self.0 & PA_X != 0 } fn is_user(&self) -> bool { self.0 & PA_U != 0 } fn is_accessed(&self) -> bool { self.0 & PA_A != 0 } fn is_dirty(&self) -> bool { self.0 & PA_D != 0 } fn is_global(&self) -> bool { self.0 & PA_G != 0 } fn is_copy_on_write(&self) -> bool { self.0 & PA_COW != 0 } fn is_mapped(&self) -> bool { self.0 & PA_MMAP != 0 } } pub type DefaultPagingMode = PagingModeSv39;