Nothing to see here, move along
at main 163 lines 4.0 kB view raw
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);