|
|
@@ -0,0 +1,203 @@
|
|
|
+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<PTE64>, 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<PageBlock>) -> 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;
|