1use crate::{
9 memory::{
10 self,
11 address_space::{VmaFlags, VmaPageSize, VmaType},
12 phys_to_virt, PhysFrame,
13 },
14 sync::SpinLock,
15};
16use alloc::{sync::Arc, vec::Vec};
17use core::sync::atomic::{AtomicU32, AtomicU64, Ordering};
18
19use super::ops::{AsyncCqe, AsyncSqe, DEFAULT_RING_ENTRIES};
20
21pub struct Ring {
27 pub id: u64,
29 pub owner_pid: u32,
31 pub sq_mapping_cap_id: crate::capability::CapId,
33 pub sq_frame: PhysFrame,
35 pub sq_virt: u64,
37 pub cq_mapping_cap_id: crate::capability::CapId,
39 pub cq_frame: PhysFrame,
41 pub cq_virt: u64,
43 pub entries: u32,
45 pub in_flight: AtomicU32,
47 pub destroyed: AtomicU32,
49 pub cq_lock: SpinLock<()>,
51 pub completion_backlog: SpinLock<Vec<AsyncCqe>>,
53 pub sq_order: u8,
55 pub cq_order: u8,
57 pub wq: crate::sync::WaitQueue,
59}
60
61impl Ring {
62 pub fn create(pid: u32, entries: u32) -> Result<u64, RingError> {
64 if RING_REGISTRY.lock().len() >= MAX_RINGS {
65 return Err(RingError::TooManyRings);
66 }
67
68 let entries = entries.max(2).min(DEFAULT_RING_ENTRIES).next_power_of_two();
69
70 let sq_bytes = RING_META_SIZE + (entries as usize * core::mem::size_of::<AsyncSqe>());
71 let cq_bytes = RING_META_SIZE + (entries as usize * core::mem::size_of::<AsyncCqe>());
72
73 let sq_order = ((sq_bytes + 4095) / 4096)
74 .next_power_of_two()
75 .trailing_zeros() as u8;
76 let cq_order = ((cq_bytes + 4095) / 4096)
77 .next_power_of_two()
78 .trailing_zeros() as u8;
79
80 let sq_frame =
82 crate::sync::with_irqs_disabled(|t| memory::allocate_phys_contiguous(t, sq_order))
83 .map_err(|_| RingError::Alloc)?;
84 let sq_virt = phys_to_virt(sq_frame.start_address.as_u64());
85
86 let cq_frame = match crate::sync::with_irqs_disabled(|t| {
88 memory::allocate_phys_contiguous(t, cq_order)
89 }) {
90 Ok(f) => f,
91 Err(_) => {
92 crate::sync::with_irqs_disabled(|t| {
93 memory::free_phys_contiguous(t, sq_frame, sq_order);
94 });
95 return Err(RingError::Alloc);
96 }
97 };
98 let cq_virt = phys_to_virt(cq_frame.start_address.as_u64());
99
100 unsafe {
102 let sq = sq_virt as *mut RingMeta;
103 (*sq).entries.store(entries, Ordering::Release);
104 (*sq).mask.store(entries - 1, Ordering::Release);
105 (*sq).head.store(0, Ordering::Release);
106 (*sq).tail.store(0, Ordering::Release);
107 (*sq).flags.store(0, Ordering::Release);
108
109 let cq = cq_virt as *mut RingMeta;
110 (*cq).entries.store(entries, Ordering::Release);
111 (*cq).mask.store(entries - 1, Ordering::Release);
112 (*cq).head.store(0, Ordering::Release);
113 (*cq).tail.store(0, Ordering::Release);
114 (*cq).flags.store(0, Ordering::Release);
115 }
116
117 let ring = Arc::new(Ring {
118 id: next_ring_id(),
119 owner_pid: pid,
120 sq_mapping_cap_id: memory::allocate_mapping_cap_id(),
121 sq_frame,
122 sq_virt,
123 cq_mapping_cap_id: memory::allocate_mapping_cap_id(),
124 cq_frame,
125 cq_virt,
126 entries,
127 in_flight: AtomicU32::new(0),
128 destroyed: AtomicU32::new(0),
129 cq_lock: SpinLock::new(()),
130 completion_backlog: SpinLock::new(Vec::with_capacity(16)),
131 sq_order,
132 cq_order,
133 wq: crate::sync::WaitQueue::new(),
134 });
135
136 let id = ring.id;
137 let mut registry = RING_REGISTRY.lock();
138 if registry.len() >= MAX_RINGS {
139 return Err(RingError::TooManyRings);
140 }
141 registry.push(ring);
142 Ok(id)
143 }
144
145 pub fn map_into_process(
147 &self,
148 addr_space: &crate::memory::AddressSpace,
149 ) -> Result<super::syscall::AsyncRingMapping, &'static str> {
150 let sq_page_count = 1usize << self.sq_order;
151 let cq_page_count = 1usize << self.cq_order;
152 let sq_phys_addrs = self.contiguous_phys_addrs(self.sq_frame, sq_page_count);
153 let cq_phys_addrs = self.contiguous_phys_addrs(self.cq_frame, cq_page_count);
154 let sq_mapping_cap_ids = alloc::vec![self.sq_mapping_cap_id; sq_page_count];
155 let cq_mapping_cap_ids = alloc::vec![self.cq_mapping_cap_id; cq_page_count];
156
157 let sq_base = addr_space
158 .find_free_vma_range(
159 crate::syscall::mmap::MMAP_BASE,
160 sq_page_count,
161 VmaPageSize::Small,
162 )
163 .ok_or("async ring: no free range for SQ")?;
164 addr_space.map_shared_frames_with_cap_ids(
165 sq_base,
166 &sq_phys_addrs,
167 Some(&sq_mapping_cap_ids),
168 VmaFlags {
169 readable: true,
170 writable: true,
171 executable: false,
172 user_accessible: true,
173 },
174 VmaType::Anonymous,
175 )?;
176
177 let cq_base = match addr_space.find_free_vma_range(
178 crate::syscall::mmap::MMAP_BASE,
179 cq_page_count,
180 VmaPageSize::Small,
181 ) {
182 Some(base) => base,
183 None => {
184 let _ = addr_space.unmap_region(sq_base, sq_page_count, VmaPageSize::Small);
185 return Err("async ring: no free range for CQ");
186 }
187 };
188
189 if let Err(err) = addr_space.map_shared_frames_with_cap_ids(
190 cq_base,
191 &cq_phys_addrs,
192 Some(&cq_mapping_cap_ids),
193 VmaFlags {
194 readable: true,
195 writable: true,
196 executable: false,
197 user_accessible: true,
198 },
199 VmaType::Anonymous,
200 ) {
201 let _ = addr_space.unmap_region(sq_base, sq_page_count, VmaPageSize::Small);
202 return Err(err);
203 }
204
205 Ok(super::syscall::AsyncRingMapping {
206 sq_base,
207 cq_base,
208 sq_size: (sq_page_count * 4096) as u64,
209 cq_size: (cq_page_count * 4096) as u64,
210 entries: self.entries,
211 })
212 }
213
214 fn contiguous_phys_addrs(&self, frame: PhysFrame, page_count: usize) -> Vec<u64> {
215 let base = frame.start_address.as_u64();
216 (0..page_count)
217 .map(|index| base + (index as u64) * 4096)
218 .collect()
219 }
220
221 #[inline]
223 pub fn sq_tail(&self) -> u32 {
224 self.sq_meta().tail.load(Ordering::Acquire)
225 }
226
227 #[inline]
229 pub fn sq_head(&self) -> u32 {
230 self.sq_meta().head.load(Ordering::Acquire)
231 }
232
233 #[inline]
235 pub fn sq_advance_head(&self, count: u32) {
236 self.sq_meta().head.fetch_add(count, Ordering::Release);
237 }
238
239 #[inline]
241 pub fn cq_advance_tail(&self, count: u32) {
242 self.cq_meta().tail.fetch_add(count, Ordering::Release);
243 }
244
245 #[inline]
247 pub fn cq_head(&self) -> u32 {
248 self.cq_meta().head.load(Ordering::Acquire)
249 }
250
251 #[inline]
253 pub unsafe fn sqe_at(&self, index: u32) -> *const AsyncSqe {
254 let base = (self.sq_virt + RING_META_SIZE as u64) as *const AsyncSqe;
255 base.add(index as usize)
256 }
257
258 #[inline]
260 pub unsafe fn cqe_at(&self, index: u32) -> *mut AsyncCqe {
261 let base = (self.cq_virt + RING_META_SIZE as u64) as *mut AsyncCqe;
262 base.add(index as usize)
263 }
264
265 #[inline]
267 pub fn destroy(&self) {
268 self.destroyed.store(1, Ordering::Release);
269 }
270
271 pub(crate) fn sq_meta(&self) -> &RingMeta {
272 unsafe { &*(self.sq_virt as *const RingMeta) }
273 }
274 pub(crate) fn cq_meta(&self) -> &RingMeta {
275 unsafe { &*(self.cq_virt as *const RingMeta) }
276 }
277}
278
279impl Drop for Ring {
280 fn drop(&mut self) {
281 let _ = memory::revoke_mapping_cap_id(self.sq_mapping_cap_id);
282 let _ = memory::revoke_mapping_cap_id(self.cq_mapping_cap_id);
283 crate::sync::with_irqs_disabled(|t| {
284 memory::free_phys_contiguous(t, self.sq_frame, self.sq_order);
285 memory::free_phys_contiguous(t, self.cq_frame, self.cq_order);
286 });
287 }
288}
289
290#[repr(C)]
297pub(crate) struct RingMeta {
298 pub(crate) head: AtomicU32, pub(crate) tail: AtomicU32, pub(crate) mask: AtomicU32, pub(crate) entries: AtomicU32, pub(crate) flags: AtomicU32, }
304
305const RING_META_SIZE: usize = 64; const MAX_RINGS: usize = 128;
312
313static RING_REGISTRY: SpinLock<Vec<Arc<Ring>>> = SpinLock::new(Vec::new());
314
315static NEXT_RING_ID: AtomicU64 = AtomicU64::new(1);
316
317fn next_ring_id() -> u64 {
318 NEXT_RING_ID.fetch_add(1, Ordering::Relaxed)
319}
320
321pub fn find_ring(id: u64) -> Option<Arc<Ring>> {
323 let guard = RING_REGISTRY.lock();
324 guard.iter().find(|r| r.id == id).cloned()
325}
326
327pub fn destroy_ring(id: u64) -> Result<(), RingError> {
329 let mut guard = RING_REGISTRY.lock();
330 if let Some(pos) = guard.iter().position(|r| r.id == id) {
331 let ring = guard.remove(pos);
332 ring.destroy();
333 ring.wq.wake_all();
334 crate::hardware::storage::ahci::discard_deferred_async_read_completions(id);
335 Ok(())
336 } else {
337 Err(RingError::NotFound)
338 }
339}
340
341#[derive(Debug, Clone, Copy, PartialEq, Eq)]
346pub enum RingError {
347 Alloc,
348 NotFound,
349 TooManyRings,
350}