Skip to main content

islet_rmm/realm/mm/
entry.rs

1use crate::config::PAGE_SIZE;
2use crate::realm::mm::attribute::{desc_type, memattr, page_type, shareable};
3use crate::realm::mm::stage2_tte::S2TTE;
4use crate::realm::mm::table_level::L3Table;
5use vmsa::address::PhysAddr;
6use vmsa::error::Error;
7use vmsa::page_table::{self, Level};
8use vmsa::RawGPA;
9
10#[derive(Clone, Copy)]
11pub struct Entry(S2TTE);
12
13impl From<usize> for S2TTE {
14    fn from(val: usize) -> Self {
15        Self(val as u64)
16    }
17}
18
19impl page_table::Entry for Entry {
20    type Inner = S2TTE;
21
22    fn new() -> Self {
23        Self(S2TTE::new(0))
24    }
25
26    fn is_valid(&self) -> bool {
27        self.0.get_masked_value(S2TTE::VALID) != 0
28    }
29
30    fn clear(&mut self) {
31        self.0 = S2TTE::new(0);
32    }
33
34    fn pte(&self) -> u64 {
35        self.0.get()
36    }
37
38    fn mut_pte(&mut self) -> &mut Self::Inner {
39        self.0.get_mut()
40    }
41
42    fn address(&self, level: usize) -> Option<PhysAddr> {
43        match self.is_valid() {
44            true => match self.0.get_masked_value(S2TTE::TYPE) {
45                page_type::TABLE_OR_PAGE => {
46                    Some(PhysAddr::from(self.0.get_masked(S2TTE::ADDR_TBL_OR_PAGE)))
47                }
48                page_type::BLOCK => match level {
49                    1 => Some(PhysAddr::from(self.0.get_masked(S2TTE::ADDR_BLK_L1))),
50                    2 => Some(PhysAddr::from(self.0.get_masked(S2TTE::ADDR_BLK_L2))),
51                    _ => None,
52                },
53                _ => None,
54            },
55            false => None,
56        }
57    }
58
59    fn set(&mut self, addr: PhysAddr, flags: u64) -> Result<(), Error> {
60        self.0.set(addr.as_u64() | flags);
61
62        #[cfg(not(any(miri, test, fuzzing)))]
63        unsafe {
64            core::arch::asm!(
65                "dsb ishst",
66                "dc civac, {}",
67                "dsb ish",
68                "isb",
69                in(reg) &self.0 as *const _ as usize,
70            );
71        }
72        Ok(())
73    }
74
75    fn point_to_subtable(&mut self, _index: usize, addr: PhysAddr) -> Result<(), Error> {
76        let mut flags = S2TTE::new(0);
77        flags
78            .set_masked_value(S2TTE::DESC_TYPE, desc_type::L012_TABLE)
79            .set_masked_value(S2TTE::MEMATTR, memattr::NORMAL_FWB)
80            .set_masked_value(S2TTE::SH, shareable::INNER);
81        self.set(addr, flags.get())
82    }
83
84    fn index<L: Level>(addr: usize) -> usize {
85        match L::THIS_LEVEL {
86            0 => RawGPA::from(addr).get_masked_value(RawGPA::L0Index) as usize,
87            1 => {
88                if L::TABLE_SIZE > PAGE_SIZE {
89                    // We know that refering one direct parent table is enough
90                    // because concatenation of the initial lookup table is upto 16.
91                    let l0 = RawGPA::from(addr).get_masked_value(RawGPA::L0Index) as usize;
92                    let l1 = RawGPA::from(addr).get_masked_value(RawGPA::L1Index) as usize;
93                    // assuming L3Table is a single page-sized
94                    l0 * L3Table::NUM_ENTRIES + l1
95                } else {
96                    RawGPA::from(addr).get_masked_value(RawGPA::L1Index) as usize
97                }
98            }
99            2 => {
100                if L::TABLE_SIZE > PAGE_SIZE {
101                    let l1 = RawGPA::from(addr).get_masked_value(RawGPA::L1Index) as usize;
102                    let l2 = RawGPA::from(addr).get_masked_value(RawGPA::L2Index) as usize;
103                    l1 * L3Table::NUM_ENTRIES + l2
104                } else {
105                    RawGPA::from(addr).get_masked_value(RawGPA::L2Index) as usize
106                }
107            }
108            3 => RawGPA::from(addr).get_masked_value(RawGPA::L3Index) as usize,
109            _ => panic!(),
110        }
111    }
112
113    fn points_to_table_or_page(&self) -> bool {
114        match self.is_valid() {
115            true => match self.0.get_masked_value(S2TTE::TYPE) {
116                page_type::TABLE_OR_PAGE => true,
117                page_type::BLOCK => false,
118                _ => false,
119            },
120            false => false,
121        }
122    }
123}