strat9_kernel/ipc/
shared_ring.rs1use crate::{memory::PhysFrame, sync::SpinLock};
2use alloc::{collections::BTreeMap, sync::Arc, vec::Vec};
3use core::sync::atomic::{AtomicU64, Ordering};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
6pub struct RingId(pub u64);
7
8impl RingId {
9 pub fn as_u64(self) -> u64 {
11 self.0
12 }
13 pub fn from_u64(raw: u64) -> Self {
15 Self(raw)
16 }
17}
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
20pub enum RingError {
21 #[error("invalid size")]
22 InvalidSize,
23 #[error("allocation failed")]
24 Alloc,
25 #[error("ring not found")]
26 NotFound,
27}
28
29pub struct SharedRing {
30 size: usize,
31 frames: Vec<PhysFrame>,
32}
33
34impl SharedRing {
35 pub fn size(&self) -> usize {
37 self.size
38 }
39
40 pub fn page_count(&self) -> usize {
42 self.frames.len()
43 }
44
45 pub fn frame_phys_addrs(&self) -> Vec<u64> {
47 self.frames
48 .iter()
49 .map(|f| f.start_address.as_u64())
50 .collect()
51 }
52}
53
54impl Drop for SharedRing {
55 fn drop(&mut self) {
57 for frame in self.frames.drain(..) {
58 crate::memory::cow::frame_dec_ref(frame);
59 }
60 }
61}
62
63static NEXT_RING_ID: AtomicU64 = AtomicU64::new(1);
64static RINGS: SpinLock<Option<BTreeMap<RingId, Arc<SharedRing>>>> = SpinLock::new(None);
65
66fn ensure_registry(guard: &mut Option<BTreeMap<RingId, Arc<SharedRing>>>) {
68 if guard.is_none() {
69 *guard = Some(BTreeMap::new());
70 }
71}
72
73pub fn create_ring(size: usize) -> Result<RingId, RingError> {
75 if size == 0 {
76 return Err(RingError::InvalidSize);
77 }
78 let page_count = (size.saturating_add(4095)) / 4096;
79 if page_count == 0 {
80 return Err(RingError::InvalidSize);
81 }
82
83 let mut frames = Vec::with_capacity(page_count);
84 let mut alloc_failed = false;
85 for _ in 0..page_count {
86 let frame = match crate::sync::with_irqs_disabled(|token| {
87 crate::memory::allocate_frame(token)
88 }) {
89 Ok(f) => f,
90 Err(_) => {
91 alloc_failed = true;
92 break;
93 }
94 };
95 let v = crate::memory::phys_to_virt(frame.start_address.as_u64());
96 unsafe { core::ptr::write_bytes(v as *mut u8, 0, 4096) };
97 crate::memory::cow::frame_inc_ref(frame);
98 frames.push(frame);
99 }
100 if alloc_failed {
101 for rollback in frames.drain(..) {
102 crate::memory::cow::frame_dec_ref(rollback);
103 }
104 return Err(RingError::Alloc);
105 }
106
107 let id = RingId(NEXT_RING_ID.fetch_add(1, Ordering::Relaxed));
108 let ring = Arc::new(SharedRing { size, frames });
109
110 let mut reg = RINGS.lock();
111 ensure_registry(&mut *reg);
112 reg.as_mut().unwrap().insert(id, ring);
113 Ok(id)
114}
115
116pub fn get_ring(id: RingId) -> Option<Arc<SharedRing>> {
118 let reg = RINGS.lock();
119 reg.as_ref().and_then(|map| map.get(&id).cloned())
120}
121
122pub fn destroy_ring(id: RingId) -> Result<(), RingError> {
124 let mut reg = RINGS.lock();
125 let map = reg.as_mut().ok_or(RingError::NotFound)?;
126
127 let len = map.len();
141 if len > 10_000 {
142 crate::serial_println!(
143 "\x1b[1;31m[ipc] RINGS BTreeMap corrupted: len={} for id={} \u{2014} aborting remove\x1b[0m",
144 len, id.as_u64()
145 );
146 return Err(RingError::NotFound);
147 }
148 crate::serial_println!("[ipc] destroy_ring(id={}) map.len={}", id.as_u64(), len);
149
150 map.remove(&id).ok_or(RingError::NotFound)?;
151 Ok(())
152}