Skip to main content

islet_rmm/mm/page_table/
entry.rs

1use super::attr;
2
3use attr::mair_idx;
4use vmsa::address::PhysAddr;
5use vmsa::error::Error;
6use vmsa::page_table::{self, Level};
7use vmsa::RawGPA;
8
9use armv9a::{define_bitfield, define_bits, define_mask};
10
11define_bits!(
12    PTDesc,
13    Reserved[58 - 55],
14    UXN[54 - 54],
15    PXN[53 - 53],
16    ADDR_BLK_L1[47 - 30],      // block descriptor; level 1
17    ADDR_BLK_L2[47 - 21],      // block descriptor; level 2
18    ADDR_TBL_OR_PAGE[47 - 12], // table descriptor(level 0-2) || page descriptor(level3)
19    AF[10 - 10],               // access flag
20    SH[9 - 8],                 // pte_shareable
21    AP[7 - 6],                 // pte_access_perm
22    NS[5 - 5],                 // security bit
23    INDX[4 - 2],               // the index into the Memory Attribute Indirection Register MAIR_ELn
24    TYPE[1 - 1],
25    VALID[0 - 0]
26);
27
28#[derive(Clone, Copy)]
29pub struct Entry(PTDesc);
30impl page_table::Entry for Entry {
31    type Inner = PTDesc;
32
33    fn new() -> Self {
34        Self(PTDesc::new(0))
35    }
36
37    fn is_valid(&self) -> bool {
38        self.0.get_masked_value(PTDesc::VALID) != 0
39    }
40
41    fn clear(&mut self) {
42        self.0 = PTDesc::new(0);
43    }
44
45    fn pte(&self) -> u64 {
46        self.0.get()
47    }
48
49    fn mut_pte(&mut self) -> &mut Self::Inner {
50        self.0.get_mut()
51    }
52
53    fn address(&self, level: usize) -> Option<PhysAddr> {
54        match self.is_valid() {
55            true => match self.0.get_masked_value(PTDesc::TYPE) {
56                attr::page_type::TABLE_OR_PAGE => {
57                    Some(PhysAddr::from(self.0.get_masked(PTDesc::ADDR_TBL_OR_PAGE)))
58                }
59                attr::page_type::BLOCK => match level {
60                    1 => Some(PhysAddr::from(self.0.get_masked(PTDesc::ADDR_BLK_L1))),
61                    2 => Some(PhysAddr::from(self.0.get_masked(PTDesc::ADDR_BLK_L2))),
62                    _ => None,
63                },
64                _ => None,
65            },
66            false => None,
67        }
68    }
69
70    fn set(&mut self, addr: PhysAddr, flags: u64) -> Result<(), Error> {
71        self.0.set(addr.as_u64() | flags);
72
73        #[cfg(not(any(miri, test, fuzzing)))]
74        unsafe {
75            core::arch::asm!(
76                "dsb ishst",
77                "dc civac, {}",
78                "dsb ish",
79                "isb",
80                in(reg) &self.0 as *const _ as usize,
81            );
82        }
83        Ok(())
84    }
85
86    fn point_to_subtable(&mut self, _index: usize, addr: PhysAddr) -> Result<(), Error> {
87        let mut flags = PTDesc::new(0);
88        flags
89            .set_masked_value(PTDesc::INDX, mair_idx::RMM_MEM)
90            .set_masked_value(PTDesc::TYPE, attr::page_type::TABLE_OR_PAGE)
91            .set_masked_value(PTDesc::SH, attr::shareable::INNER)
92            .set_bits(PTDesc::AF | PTDesc::VALID);
93        self.set(addr, flags.get())
94    }
95
96    fn index<L: Level>(addr: usize) -> usize {
97        match L::THIS_LEVEL {
98            0 => RawGPA::from(addr).get_masked_value(RawGPA::L0Index) as usize,
99            1 => RawGPA::from(addr).get_masked_value(RawGPA::L1Index) as usize,
100            2 => RawGPA::from(addr).get_masked_value(RawGPA::L2Index) as usize,
101            3 => RawGPA::from(addr).get_masked_value(RawGPA::L3Index) as usize,
102            _ => panic!(),
103        }
104    }
105
106    fn points_to_table_or_page(&self) -> bool {
107        match self.is_valid() {
108            true => match self.0.get_masked_value(PTDesc::TYPE) {
109                attr::page_type::TABLE_OR_PAGE => true,
110                _ => false,
111            },
112            false => false,
113        }
114    }
115}