1use core::mem::size_of;
10
11pub const SMALL_MESSAGE_MAX_SIZE: usize = 64;
13
14pub const DATA_REGISTERS: usize = 4;
16
17#[repr(C)]
22#[derive(Debug, Clone, Copy, PartialEq, Eq)]
23pub struct SmallMessage {
24 pub capability: u64,
26 pub opcode: u32,
28 pub flags: u32,
30 pub data: [u64; DATA_REGISTERS],
32}
33
34impl SmallMessage {
35 pub const fn new(capability: u64, opcode: u32) -> Self {
37 Self {
38 capability,
39 opcode,
40 flags: 0,
41 data: [0; DATA_REGISTERS],
42 }
43 }
44
45 pub fn with_flags(mut self, flags: u32) -> Self {
47 self.flags = flags;
48 self
49 }
50
51 pub fn with_data(mut self, index: usize, value: u64) -> Self {
53 if index < DATA_REGISTERS {
54 self.data[index] = value;
55 }
56 self
57 }
58
59 pub const fn size() -> usize {
61 size_of::<Self>()
62 }
63}
64
65#[repr(C)]
67#[derive(Debug, Clone, Copy, PartialEq, Eq)]
68pub struct MessageHeader {
69 pub capability: u64,
71 pub opcode: u32,
73 pub flags: u32,
75 pub total_size: u64,
77 pub checksum: u32,
79 _reserved: u32,
81}
82
83impl MessageHeader {
84 pub const fn new(capability: u64, opcode: u32, total_size: u64) -> Self {
86 Self {
87 capability,
88 opcode,
89 flags: 0,
90 total_size,
91 checksum: 0,
92 _reserved: 0,
93 }
94 }
95}
96
97#[repr(C)]
99#[derive(Debug, Clone, Copy, PartialEq, Eq)]
100pub struct MemoryRegion {
101 pub base_addr: u64,
103 pub size: u64,
105 pub permissions: u32,
107 pub cache_policy: u32,
109}
110
111impl MemoryRegion {
112 pub const fn new(base_addr: u64, size: u64) -> Self {
114 Self {
115 base_addr,
116 size,
117 permissions: 0,
118 cache_policy: 0,
119 }
120 }
121
122 pub fn with_permissions(mut self, permissions: u32) -> Self {
124 self.permissions = permissions;
125 self
126 }
127
128 pub fn with_cache_policy(mut self, policy: u32) -> Self {
130 self.cache_policy = policy;
131 self
132 }
133}
134
135#[repr(C)]
140#[derive(Debug, Clone, Copy)]
141pub struct LargeMessage {
142 pub header: MessageHeader,
144 pub memory_region: MemoryRegion,
146 pub inline_data: [u8; SMALL_MESSAGE_MAX_SIZE],
148}
149
150impl LargeMessage {
151 pub fn new(capability: u64, opcode: u32, region: MemoryRegion) -> Self {
153 let total_size = region.size + size_of::<Self>() as u64;
154 Self {
155 header: MessageHeader::new(capability, opcode, total_size),
156 memory_region: region,
157 inline_data: [0; SMALL_MESSAGE_MAX_SIZE],
158 }
159 }
160
161 pub fn with_inline_data(mut self, data: &[u8]) -> Self {
163 let len = data.len().min(SMALL_MESSAGE_MAX_SIZE);
164 self.inline_data[..len].copy_from_slice(&data[..len]);
165 self
166 }
167}
168
169#[derive(Debug, Clone, Copy)]
171pub enum Message {
172 Small(SmallMessage),
174 Large(LargeMessage),
176}
177
178impl Message {
179 pub const fn small(capability: u64, opcode: u32) -> Self {
181 Message::Small(SmallMessage::new(capability, opcode))
182 }
183
184 pub fn large(capability: u64, opcode: u32, region: MemoryRegion) -> Self {
186 Message::Large(LargeMessage::new(capability, opcode, region))
187 }
188
189 pub fn capability(&self) -> u64 {
191 match self {
192 Message::Small(msg) => msg.capability,
193 Message::Large(msg) => msg.header.capability,
194 }
195 }
196
197 pub fn opcode(&self) -> u32 {
199 match self {
200 Message::Small(msg) => msg.opcode,
201 Message::Large(msg) => msg.header.opcode,
202 }
203 }
204
205 pub fn flags(&self) -> u32 {
207 match self {
208 Message::Small(msg) => msg.flags,
209 Message::Large(msg) => msg.header.flags,
210 }
211 }
212
213 pub fn set_flags(&mut self, flags: u32) {
215 match self {
216 Message::Small(msg) => msg.flags = flags,
217 Message::Large(msg) => msg.header.flags = flags,
218 }
219 }
220}
221
222pub mod flags {
224 pub const URGENT: u32 = 1 << 0;
226 pub const UNORDERED: u32 = 1 << 1;
228 pub const NEEDS_ACK: u32 = 1 << 2;
230 pub const IS_REPLY: u32 = 1 << 3;
232 pub const HAS_CAPABILITY: u32 = 1 << 4;
234}
235
236pub mod permissions {
238 pub const READ: u32 = 1 << 0;
240 pub const WRITE: u32 = 1 << 1;
242 pub const EXECUTE: u32 = 1 << 2;
244 pub const SHARED: u32 = 1 << 3;
246}
247
248pub mod cache_policy {
250 pub const WRITE_BACK: u32 = 0;
252 pub const WRITE_THROUGH: u32 = 1;
254 pub const UNCACHED: u32 = 2;
256 pub const WRITE_COMBINING: u32 = 3;
258}
259
260#[cfg(all(test, not(target_os = "none")))]
261mod tests {
262 use super::*;
263
264 #[test]
265 fn test_small_message_size() {
266 assert_eq!(SmallMessage::size(), 48); }
268
269 #[test]
270 fn test_message_creation() {
271 let small = Message::small(0x1234, 42);
272 assert_eq!(small.capability(), 0x1234);
273 assert_eq!(small.opcode(), 42);
274
275 let region = MemoryRegion::new(0x1000, 4096);
276 let large = Message::large(0x5678, 84, region);
277 assert_eq!(large.capability(), 0x5678);
278 assert_eq!(large.opcode(), 84);
279 }
280}