1use crate::config;
2use crate::granule::array::GRANULE_STATUS_TABLE;
3use crate::rmi::error::Error;
4
5use super::{GranuleState, GRANULE_SIZE};
6use core::sync::atomic::{AtomicU8, Ordering};
7use safe_abstraction::raw_ptr;
8use spinning_top::{Spinlock, SpinlockGuard};
9use vmsa::guard::Content;
10
11#[cfg(not(any(kani, miri, test, fuzzing)))]
16#[derive(Debug)]
17pub struct Granule {
18 state: u8,
20 ref_count: AtomicU8,
22}
23#[cfg(any(kani, miri, test, fuzzing))]
24pub struct Granule {
26 state: u8,
28 ref_count: AtomicU8,
30 pub gpt: GranuleGpt,
32}
33
34#[cfg(kani)]
35#[derive(Copy, Clone, PartialEq, kani::Arbitrary)]
36pub enum GranuleGpt {
37 GPT_NS,
38 GPT_OTHER,
39 GPT_REALM,
40}
41
42#[cfg(any(miri, test, fuzzing))]
43#[derive(Copy, Clone, PartialEq)]
44pub enum GranuleGpt {
45 GPT_NS,
46 GPT_OTHER,
47 GPT_REALM,
48}
49
50impl Granule {
51 #[cfg(not(any(kani, miri, test, fuzzing)))]
52 fn new() -> Self {
53 let state = GranuleState::Undelegated;
54 let ref_count = AtomicU8::new(0);
55 Granule { state, ref_count }
56 }
57 #[cfg(any(kani, miri, test, fuzzing))]
58 fn new() -> Self {
60 #[cfg(kani)]
61 {
62 let state = kani::any();
63 let ref_count = AtomicU8::new(kani::any());
64 kani::assume(state >= GranuleState::Undelegated && state <= GranuleState::RTT);
65 let gpt = {
66 if state != GranuleState::Undelegated {
67 GranuleGpt::GPT_REALM
68 } else {
69 let gpt = kani::any();
70 kani::assume(gpt != GranuleGpt::GPT_REALM);
71 gpt
72 }
73 };
74 Granule {
75 state,
76 ref_count,
77 gpt,
78 }
79 }
80
81 #[cfg(any(miri, test, fuzzing))]
82 {
83 Self {
84 state: GranuleState::Undelegated,
85 ref_count: AtomicU8::new(0),
86 gpt: GranuleGpt::GPT_NS,
87 }
88 }
89 }
90
91 pub fn inc_count(&mut self) {
92 let _ = self.ref_count.fetch_add(1, Ordering::SeqCst);
93 }
94
95 pub fn dec_count(&mut self) {
96 let _ = self.ref_count.fetch_sub(1, Ordering::SeqCst);
97 }
98
99 pub fn load_count(&self) -> u8 {
100 self.ref_count.load(Ordering::SeqCst)
101 }
102
103 pub fn num_children(&self) -> usize {
104 self.ref_count.load(Ordering::SeqCst) as usize
105 }
106
107 #[cfg(any(kani, miri, test, fuzzing))]
108 pub fn set_gpt(&mut self, gpt: GranuleGpt) {
109 self.gpt = gpt;
110 }
111
112 #[cfg(any(kani, miri, test, fuzzing))]
113 pub fn is_valid(&self) -> bool {
114 self.state >= GranuleState::Undelegated &&
115 self.state <= GranuleState::RTT &&
116 if self.state != GranuleState::Undelegated {
118 self.gpt == GranuleGpt::GPT_REALM
119 } else {
120 self.gpt != GranuleGpt::GPT_REALM
121 }
122 }
123
124 pub fn state(&self) -> u8 {
125 self.state
126 }
127
128 pub fn set_state(&mut self, state: u8) -> Result<(), Error> {
129 let prev = self.state;
130 if (prev == GranuleState::Delegated && state == GranuleState::Undelegated)
131 || (state == GranuleState::Delegated)
132 {
133 self.zeroize();
134 }
135 self.state = state;
136 Ok(())
137 }
138
139 pub fn content_mut<T>(&mut self) -> Result<raw_ptr::SafetyAssumed<T>, Error>
140 where
141 T: Content + raw_ptr::SafetyChecked + raw_ptr::SafetyAssured,
142 {
143 let addr = self.index_to_addr();
144 Ok(raw_ptr::assume_safe::<T>(addr)?)
145 }
146
147 pub fn new_uninit_with<T>(&mut self, value: T) -> Result<raw_ptr::SafetyAssumed<T>, Error>
148 where
149 T: Content + raw_ptr::SafetyChecked + raw_ptr::SafetyAssured,
150 {
151 let addr = self.index_to_addr();
152 Ok(raw_ptr::assume_safe_uninit_with::<T>(addr, value)?)
153 }
154
155 pub fn content<T>(&self) -> Result<raw_ptr::SafetyAssumed<T>, Error>
156 where
157 T: Content + raw_ptr::SafetyChecked + raw_ptr::SafetyAssured,
158 {
159 let addr = self.index_to_addr();
160 Ok(raw_ptr::assume_safe::<T>(addr)?)
161 }
162
163 fn index(&self) -> usize {
164 let entry_size = core::mem::size_of::<Entry>();
165 let granule_size = core::mem::size_of::<Granule>();
166 let granule_offset = entry_size - granule_size;
170 let granule_addr = self as *const Granule as usize;
171 let entry_addr = granule_addr - granule_offset;
172 let gst = &GRANULE_STATUS_TABLE;
173 let table_base = gst.entries.as_ptr() as usize;
174 (entry_addr - table_base) / core::mem::size_of::<Entry>()
175 }
176
177 #[cfg(not(any(kani, miri, test, fuzzing)))]
178 fn index_to_addr(&self) -> usize {
179 let mut idx = self.index();
180 let regions = config::NS_DRAM_REGIONS.lock();
181
182 for range in regions.iter() {
183 let region_max = (range.end - range.start) / GRANULE_SIZE;
184 if idx < region_max {
185 return range.start + (idx * GRANULE_SIZE);
186 }
187 idx -= region_max;
188 }
189 0
190 }
191 #[cfg(any(kani, miri, test, fuzzing))]
192 pub fn index_to_addr(&self) -> usize {
194 use crate::granule::{GRANULE_REGION, GRANULE_STATUS_TABLE_SIZE};
195 let idx = self.index();
196 assert!(idx < GRANULE_STATUS_TABLE_SIZE);
197
198 #[cfg(any(miri, test, fuzzing))]
199 return crate::test_utils::align_up(unsafe {
200 GRANULE_REGION.as_ptr() as usize + (idx * GRANULE_SIZE)
201 });
202
203 #[cfg(kani)]
204 return unsafe { GRANULE_REGION.as_ptr() as usize + (idx * GRANULE_SIZE) };
205 }
206
207 #[cfg(not(any(kani, miri, test, fuzzing)))]
208 fn zeroize(&mut self) {
209 let addr = self.index_to_addr();
210
211 unsafe {
215 core::ptr::write_bytes(addr as *mut u8, 0x0, GRANULE_SIZE);
216 }
217 }
218 #[cfg(any(kani, miri, test, fuzzing))]
219 fn zeroize(&mut self) {
222 let addr = self.index_to_addr();
223 let g_start = unsafe { crate::granule::array::GRANULE_REGION.as_ptr() as usize };
224 let g_end = g_start + crate::granule::array::GRANULE_MEM_SIZE;
225 assert!(addr >= g_start && addr < g_end);
226
227 unsafe {
228 core::ptr::write_bytes(addr as *mut u8, 0x0, 8);
229 assert!(*(addr as *const u8) == 0);
230 }
231 }
232}
233
234pub struct Entry(Spinlock<Granule>);
235impl Entry {
236 #[cfg(not(any(kani, miri, test, fuzzing)))]
237 pub fn new() -> Self {
238 Self(Spinlock::new(Granule::new()))
239 }
240 #[cfg(any(kani, miri, test, fuzzing))]
241 pub fn new() -> Self {
243 let granule = Granule::new();
244 assert!(granule.is_valid());
245 Self(Spinlock::new(granule))
246 }
247
248 pub fn lock(&self) -> Result<SpinlockGuard<'_, Granule>, Error> {
249 let granule = self.0.lock();
250 Ok(granule)
251 }
252}