page_table_generic/
lib.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#![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! {
    /// Generic page table entry flags that indicate the corresponding mapped
    /// memory region permissions and attributes.
    #[derive(Clone, Copy, PartialEq)]
    pub struct PageAttribute: u32 {
        const Read = 1;
        const Write = 1 << 2;
        const PrivilegeExecute = 1 << 3;
        const UserExcute = 1 << 4;
        const UserAccess = 1 << 5;
        const Device = 1 << 6;
        const NonCache = 1 << 7;
    }
}

#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct MapConfig {
    pub vaddr: *const u8,
    pub paddr: usize,
    pub attrs: PageAttribute,
}

#[repr(C)]
#[derive(Clone)]
pub struct PTEConfig {
    pub paddr: usize,
    pub is_block: bool,
    pub attributes: PageAttribute,
}

impl PTEConfig {
    pub(crate) fn new(paddr: usize, is_block: bool, attrs: PageAttribute) -> Self {
        Self {
            paddr,
            is_block,
            attributes: attrs,
        }
    }

    pub fn valid(&self) -> bool {
        self.attributes.contains(PageAttribute::Read)
    }
}

impl Debug for PTEConfig {
    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.attributes
        )
    }
}

pub trait PTEArch: Sync + Send + Clone + Copy + 'static {
    fn page_size() -> usize;
    fn level() -> usize;
    fn new_pte(config: PTEConfig) -> usize;
    fn read_pte(pte: usize) -> PTEConfig;
}

pub trait Access {
    fn va_offset(&self) -> usize;
    /// Alloc memory for a page table entry.
    ///
    /// # Safety
    ///
    /// should be deallocated by [`dealloc`].
    unsafe fn alloc(&mut self, layout: Layout) -> Option<NonNull<u8>>;
    /// dealloc memory for a page table entry.
    ///
    /// # Safety
    ///
    /// ptr must be allocated by [`alloc`].
    unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout);
}

pub struct PTEInfo {
    pub level: usize,
    pub vaddr: *const u8,
    pub pte: PTEConfig,
}

impl Debug for PageAttribute {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        macro_rules! field {
            ($e:ident,$name:expr) => {
                if self.contains(PageAttribute::$e) {
                    f.write_str($name)?
                } else {
                    f.write_str("-")?
                }
            };
        }

        f.write_str("P-")?;
        field!(Read, "R");
        field!(Write, "W");
        field!(PrivilegeExecute, "X");
        f.write_str(", U-")?;
        if self.contains(PageAttribute::UserAccess) {
            field!(Read, "R");
            field!(Write, "W");
        } else {
            f.write_str("--")?;
        }
        field!(UserExcute, "X");
        f.write_str(", ")?;
        f.write_str(if self.contains(PageAttribute::NonCache) {
            "NonCache"
        } else if self.contains(PageAttribute::Device) {
            "Device"
        } else {
            "Cache"
        })?;
        f.write_str(")")
    }
}