1use crate::error::{CapError, CapResult};
8use crate::DEFAULT_CAP_TABLE_CAPACITY;
9use rvm_types::{CapRights, CapToken, CapType, PartitionId};
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub struct CapSlot {
17 pub token: CapToken,
19 pub generation: u32,
34 pub owner: PartitionId,
36 pub depth: u8,
38 pub parent_index: u32,
40 pub badge: u64,
42}
43
44impl CapSlot {
45 #[inline]
49 #[must_use]
50 const fn empty() -> Self {
51 Self {
52 token: CapToken::new(0, CapType::Region, CapRights::empty(), 0),
53 generation: 0,
54 owner: PartitionId::new(0),
55 depth: 0,
56 parent_index: u32::MAX,
57 badge: 0,
58 }
59 }
60
61 #[inline]
63 #[must_use]
64 pub const fn is_valid(&self) -> bool {
65 self.generation != 0
66 }
67
68 #[inline]
70 #[must_use]
71 pub const fn matches(&self, generation: u32) -> bool {
72 self.is_valid() && self.generation == generation
73 }
74
75 #[inline]
86 pub fn invalidate(&mut self) {
87 let next_gen = self.generation.wrapping_add(1);
88 let safe_gen = if next_gen == 0 { 1 } else { next_gen };
90 self.parent_index = safe_gen;
92 self.generation = 0;
94 }
95
96 #[inline]
102 #[must_use]
103 const fn next_generation(&self) -> u32 {
104 if self.generation != 0 {
107 self.generation
109 } else if self.parent_index == u32::MAX {
110 1
112 } else {
113 self.parent_index
115 }
116 }
117}
118
119pub struct CapabilityTable<const N: usize = DEFAULT_CAP_TABLE_CAPACITY> {
124 slots: [CapSlot; N],
126 count: usize,
128 free_hint: usize,
130}
131
132impl<const N: usize> core::fmt::Debug for CapabilityTable<N> {
133 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
134 f.debug_struct("CapabilityTable")
135 .field("count", &self.count)
136 .field("capacity", &N)
137 .finish_non_exhaustive()
138 }
139}
140
141impl<const N: usize> CapabilityTable<N> {
142 #[inline]
144 #[must_use]
145 pub const fn new() -> Self {
146 Self {
147 slots: [CapSlot::empty(); N],
148 count: 0,
149 free_hint: 0,
150 }
151 }
152
153 #[inline]
155 #[must_use]
156 pub const fn capacity(&self) -> usize {
157 N
158 }
159
160 #[inline]
162 #[must_use]
163 pub const fn len(&self) -> usize {
164 self.count
165 }
166
167 #[inline]
169 #[must_use]
170 pub const fn is_empty(&self) -> bool {
171 self.count == 0
172 }
173
174 #[inline]
176 #[must_use]
177 pub const fn is_full(&self) -> bool {
178 self.count >= N
179 }
180
181 #[allow(clippy::cast_possible_truncation)]
187 pub fn insert_root(
188 &mut self,
189 token: CapToken,
190 owner: PartitionId,
191 badge: u64,
192 ) -> CapResult<(u32, u32)> {
193 let index = self.find_free_slot()?;
194 let generation = self.slots[index].next_generation();
195
196 self.slots[index] = CapSlot {
197 token,
198 generation,
199 owner,
200 depth: 0,
201 parent_index: u32::MAX,
202 badge,
203 };
204 self.count += 1;
205
206 Ok((index as u32, generation))
207 }
208
209 #[allow(clippy::cast_possible_truncation)]
215 pub fn insert_derived(
216 &mut self,
217 token: CapToken,
218 owner: PartitionId,
219 depth: u8,
220 parent_index: u32,
221 badge: u64,
222 ) -> CapResult<(u32, u32)> {
223 let index = self.find_free_slot()?;
224 let generation = self.slots[index].next_generation();
225
226 self.slots[index] = CapSlot {
227 token,
228 generation,
229 owner,
230 depth,
231 parent_index,
232 badge,
233 };
234 self.count += 1;
235
236 Ok((index as u32, generation))
237 }
238
239 #[inline]
246 pub fn lookup(&self, index: u32, generation: u32) -> CapResult<&CapSlot> {
247 let idx = index as usize;
248 if idx >= N {
249 return Err(CapError::InvalidHandle);
250 }
251 let slot = &self.slots[idx];
252 if !slot.is_valid() {
253 return Err(CapError::InvalidHandle);
254 }
255 if slot.generation != generation {
256 return Err(CapError::StaleHandle);
257 }
258 Ok(slot)
259 }
260
261 pub fn lookup_mut(&mut self, index: u32, generation: u32) -> CapResult<&mut CapSlot> {
268 let idx = index as usize;
269 if idx >= N {
270 return Err(CapError::InvalidHandle);
271 }
272 let slot = &mut self.slots[idx];
273 if !slot.is_valid() {
274 return Err(CapError::InvalidHandle);
275 }
276 if slot.generation != generation {
277 return Err(CapError::StaleHandle);
278 }
279 Ok(slot)
280 }
281
282 pub fn remove(&mut self, index: u32, generation: u32) -> CapResult<()> {
289 let idx = index as usize;
290 if idx >= N {
291 return Err(CapError::InvalidHandle);
292 }
293 let slot = &mut self.slots[idx];
294 if !slot.is_valid() {
295 return Err(CapError::InvalidHandle);
296 }
297 if slot.generation != generation {
298 return Err(CapError::StaleHandle);
299 }
300 slot.invalidate();
301 self.count -= 1;
302 if idx < self.free_hint {
303 self.free_hint = idx;
304 }
305 Ok(())
306 }
307
308 pub(crate) fn force_invalidate(&mut self, index: u32) {
310 let idx = index as usize;
311 if idx < N && self.slots[idx].is_valid() {
312 self.slots[idx].invalidate();
313 self.count -= 1;
314 if idx < self.free_hint {
315 self.free_hint = idx;
316 }
317 }
318 }
319
320 #[allow(clippy::cast_possible_truncation)]
322 pub fn iter(&self) -> impl Iterator<Item = (u32, &CapSlot)> {
323 self.slots
324 .iter()
325 .enumerate()
326 .filter(|(_, s)| s.is_valid())
327 .map(|(i, s)| (i as u32, s))
329 }
330
331 fn find_free_slot(&mut self) -> CapResult<usize> {
333 for i in self.free_hint..N {
334 if !self.slots[i].is_valid() {
335 self.free_hint = i + 1;
336 return Ok(i);
337 }
338 }
339 for i in 0..self.free_hint {
340 if !self.slots[i].is_valid() {
341 self.free_hint = i + 1;
342 return Ok(i);
343 }
344 }
345 Err(CapError::TableFull)
346 }
347}
348
349impl<const N: usize> Default for CapabilityTable<N> {
350 fn default() -> Self {
351 Self::new()
352 }
353}
354
355#[cfg(test)]
356mod tests {
357 use super::*;
358
359 fn test_token(id: u64) -> CapToken {
360 CapToken::new(
361 id,
362 CapType::Region,
363 CapRights::READ.union(CapRights::WRITE),
364 0,
365 )
366 }
367
368 #[test]
369 fn test_insert_and_lookup() {
370 let mut table = CapabilityTable::<16>::new();
371 let owner = PartitionId::new(1);
372 let token = test_token(100);
373
374 let (idx, gen) = table.insert_root(token, owner, 0).unwrap();
375 assert_eq!(table.len(), 1);
376
377 let slot = table.lookup(idx, gen).unwrap();
378 assert_eq!(slot.token.id(), 100);
379 assert_eq!(slot.depth, 0);
380 assert_eq!(slot.parent_index, u32::MAX);
381 }
382
383 #[test]
384 fn test_remove_and_stale() {
385 let mut table = CapabilityTable::<16>::new();
386 let owner = PartitionId::new(1);
387 let token = test_token(200);
388
389 let (idx, gen) = table.insert_root(token, owner, 0).unwrap();
390 table.remove(idx, gen).unwrap();
391 assert_eq!(table.len(), 0);
392 assert!(table.lookup(idx, gen).is_err());
393 }
394
395 #[test]
396 fn test_generation_counter() {
397 let mut table = CapabilityTable::<16>::new();
398 let owner = PartitionId::new(1);
399 let token = test_token(300);
400
401 let (idx, gen1) = table.insert_root(token, owner, 0).unwrap();
402 table.remove(idx, gen1).unwrap();
403
404 let (idx2, gen2) = table.insert_root(token, owner, 0).unwrap();
405 assert_eq!(idx, idx2);
406 assert_ne!(gen1, gen2);
407
408 assert!(table.lookup(idx, gen1).is_err());
409 assert!(table.lookup(idx2, gen2).is_ok());
410 }
411
412 #[test]
413 fn test_table_full() {
414 let mut table = CapabilityTable::<2>::new();
415 let owner = PartitionId::new(1);
416 let token = test_token(400);
417
418 table.insert_root(token, owner, 0).unwrap();
419 table.insert_root(token, owner, 0).unwrap();
420 assert!(table.is_full());
421 assert_eq!(table.insert_root(token, owner, 0), Err(CapError::TableFull));
422 }
423
424 #[test]
425 fn test_insert_derived() {
426 let mut table = CapabilityTable::<16>::new();
427 let owner = PartitionId::new(1);
428 let token = test_token(500);
429
430 let (parent_idx, _) = table.insert_root(token, owner, 0).unwrap();
431 let derived = CapToken::new(501, CapType::Region, CapRights::READ, 0);
432 let (child_idx, child_gen) = table
433 .insert_derived(derived, owner, 1, parent_idx, 42)
434 .unwrap();
435
436 let slot = table.lookup(child_idx, child_gen).unwrap();
437 assert_eq!(slot.depth, 1);
438 assert_eq!(slot.parent_index, parent_idx);
439 assert_eq!(slot.badge, 42);
440 }
441
442 #[test]
443 fn test_iter_valid_entries() {
444 let mut table = CapabilityTable::<16>::new();
445 let owner = PartitionId::new(1);
446
447 table.insert_root(test_token(1), owner, 0).unwrap();
448 table.insert_root(test_token(2), owner, 0).unwrap();
449 table.insert_root(test_token(3), owner, 0).unwrap();
450
451 let count = table.iter().count();
452 assert_eq!(count, 3);
453 }
454}