islet_rmm/mm/page_table/
entry.rs1use 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], ADDR_BLK_L2[47 - 21], ADDR_TBL_OR_PAGE[47 - 12], AF[10 - 10], SH[9 - 8], AP[7 - 6], NS[5 - 5], INDX[4 - 2], 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}