Nothing to see here, move along
1use core::sync::atomic::AtomicU32;
2
3pub const MAX_SQ_ENTRIES: u32 = 64;
4pub const MAX_CQ_ENTRIES: u32 = 64;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub struct RingIndex(u32);
8
9impl RingIndex {
10 pub const fn new(val: u32) -> Self {
11 Self(val)
12 }
13
14 #[inline]
15 pub const fn raw(self) -> u32 {
16 self.0
17 }
18
19 #[inline]
20 pub const fn advance(self, n: u32) -> Self {
21 Self(self.0.wrapping_add(n))
22 }
23
24 #[inline]
25 pub const fn distance(self, older: Self) -> u32 {
26 self.0.wrapping_sub(older.0)
27 }
28
29 #[inline]
30 pub const fn slot(self, capacity: u32) -> u32 {
31 self.0 % capacity
32 }
33}
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq)]
36#[repr(u8)]
37pub enum RingOpcode {
38 Nop = 0,
39 CapCreate = 1,
40 CapDerive = 2,
41 IpcSend = 10,
42 IpcRecv = 11,
43 NotifySignal = 20,
44 NotifyPoll = 21,
45}
46
47impl RingOpcode {
48 pub const fn from_u8(val: u8) -> Option<Self> {
49 match val {
50 0 => Some(Self::Nop),
51 1 => Some(Self::CapCreate),
52 2 => Some(Self::CapDerive),
53 10 => Some(Self::IpcSend),
54 11 => Some(Self::IpcRecv),
55 20 => Some(Self::NotifySignal),
56 21 => Some(Self::NotifyPoll),
57 _ => None,
58 }
59 }
60}
61
62pub const RING_OP_NOP: u8 = RingOpcode::Nop as u8;
63pub const RING_OP_CAP_CREATE: u8 = RingOpcode::CapCreate as u8;
64pub const RING_OP_CAP_DERIVE: u8 = RingOpcode::CapDerive as u8;
65pub const RING_OP_IPC_SEND: u8 = RingOpcode::IpcSend as u8;
66pub const RING_OP_IPC_RECV: u8 = RingOpcode::IpcRecv as u8;
67pub const RING_OP_NOTIFY_SIGNAL: u8 = RingOpcode::NotifySignal as u8;
68pub const RING_OP_NOTIFY_POLL: u8 = RingOpcode::NotifyPoll as u8;
69
70#[repr(C)]
71pub struct RingHeader {
72 pub sq_head: AtomicU32,
73 pub sq_tail: AtomicU32,
74 pub cq_head: AtomicU32,
75 pub cq_tail: AtomicU32,
76 pub sq_len: u32,
77 pub cq_len: u32,
78}
79
80#[derive(Debug, Clone, Copy)]
81#[repr(C)]
82#[derive(zerocopy::FromBytes, zerocopy::IntoBytes, zerocopy::KnownLayout, zerocopy::Immutable)]
83pub struct SubmissionEntry {
84 pub arg0: u64,
85 pub arg1: u64,
86 pub arg2: u64,
87 pub user_data: u32,
88 pub cap_slot: u8,
89 pub opcode: u8,
90 pub flags: u8,
91 pub _pad: u8,
92}
93
94#[derive(Debug, Clone, Copy)]
95#[repr(C)]
96#[derive(zerocopy::FromBytes, zerocopy::IntoBytes, zerocopy::KnownLayout, zerocopy::Immutable)]
97pub struct CompletionEntry {
98 pub result: i64,
99 pub user_data: u64,
100 pub extra: u64,
101}
102
103#[allow(dead_code)]
104impl SubmissionEntry {
105 pub const fn zeroed() -> Self {
106 Self {
107 arg0: 0,
108 arg1: 0,
109 arg2: 0,
110 user_data: 0,
111 cap_slot: 0,
112 opcode: 0,
113 flags: 0,
114 _pad: 0,
115 }
116 }
117}
118
119#[allow(dead_code)]
120impl CompletionEntry {
121 pub const fn zeroed() -> Self {
122 Self {
123 result: 0,
124 user_data: 0,
125 extra: 0,
126 }
127 }
128}
129
130pub fn ring_sq_offset() -> usize {
131 core::mem::size_of::<RingHeader>()
132}
133
134pub fn ring_cq_offset() -> usize {
135 ring_sq_offset() + (MAX_SQ_ENTRIES as usize) * core::mem::size_of::<SubmissionEntry>()
136}
137
138pub fn ring_total_size() -> usize {
139 ring_cq_offset() + (MAX_CQ_ENTRIES as usize) * core::mem::size_of::<CompletionEntry>()
140}
141
142const _: () = assert!(
143 core::mem::align_of::<RingHeader>() <= 4096,
144 "RingHeader alignment must not exceed page size (ring buffer is page-aligned)"
145);
146
147const _: () = assert!(
148 core::mem::size_of::<SubmissionEntry>() == 32,
149 "SubmissionEntry must be exactly 32 bytes"
150);
151
152const _: () = assert!(
153 core::mem::size_of::<CompletionEntry>() == 24,
154 "CompletionEntry must be exactly 24 bytes"
155);
156
157const _: () = assert!(
158 core::mem::size_of::<RingHeader>()
159 + MAX_SQ_ENTRIES as usize * core::mem::size_of::<SubmissionEntry>()
160 + MAX_CQ_ENTRIES as usize * core::mem::size_of::<CompletionEntry>()
161 <= 4096,
162 "ring layout must fit in a single 4KiB page"
163);