1#![allow(unused_imports)]
6#![allow(static_mut_refs)]
7#![allow(clippy::wrong_self_convention)]
8use crate::systypes::shm::ShmInfo;
9use crate::systypes::{ExchangeHeader, Status};
10use core::mem;
11use core::ptr::*;
12
13const EXCHANGE_AREA_LEN: usize = 128; #[unsafe(link_section = ".svcexchange")]
18static mut EXCHANGE_AREA: [u8; EXCHANGE_AREA_LEN] = [0u8; EXCHANGE_AREA_LEN];
19
20pub trait SentryExchangeable {
35 fn to_kernel(&self) -> Result<Status, Status>;
37
38 fn from_kernel(&mut self) -> Result<Status, Status>;
40}
41
42impl SentryExchangeable for crate::systypes::shm::ShmInfo {
52 #[allow(static_mut_refs)]
53 fn from_kernel(&mut self) -> Result<Status, Status> {
54 unsafe {
55 core::ptr::copy_nonoverlapping(
56 EXCHANGE_AREA.as_ptr(),
57 addr_of_mut!(*self) as *mut u8,
58 core::mem::size_of::<ShmInfo>().min(EXCHANGE_AREA_LEN),
59 );
60 }
61 Ok(Status::Ok)
62 }
63
64 #[cfg(test)]
65 #[allow(static_mut_refs)]
66 fn to_kernel(&self) -> Result<Status, Status> {
67 unsafe {
68 core::ptr::copy_nonoverlapping(
69 addr_of!(*self) as *const u8,
70 EXCHANGE_AREA.as_mut_ptr(),
71 core::mem::size_of::<ShmInfo>().min(EXCHANGE_AREA_LEN),
72 );
73 }
74 Ok(Status::Ok)
75 }
76
77 #[cfg(not(test))]
78 #[allow(static_mut_refs)]
79 fn to_kernel(&self) -> Result<Status, Status> {
80 Err(Status::Invalid)
81 }
82}
83
84impl SentryExchangeable for crate::systypes::dma::GpdmaStreamConfig {
94 #[allow(static_mut_refs)]
95 fn from_kernel(&mut self) -> Result<Status, Status> {
96 unsafe {
97 core::ptr::copy_nonoverlapping(
98 EXCHANGE_AREA.as_ptr(),
99 addr_of_mut!(*self) as *mut u8,
100 core::mem::size_of::<crate::systypes::dma::GpdmaStreamConfig>()
101 .min(EXCHANGE_AREA_LEN),
102 );
103 }
104 Ok(Status::Ok)
105 }
106
107 #[cfg(test)]
108 #[allow(static_mut_refs)]
109 fn to_kernel(&self) -> Result<Status, Status> {
110 unsafe {
111 core::ptr::copy_nonoverlapping(
112 addr_of!(*self) as *const u8,
113 EXCHANGE_AREA.as_mut_ptr(),
114 core::mem::size_of::<crate::systypes::dma::GpdmaStreamConfig>()
115 .min(EXCHANGE_AREA_LEN),
116 );
117 }
118 Ok(Status::Ok)
119 }
120
121 #[cfg(not(test))]
122 #[allow(static_mut_refs)]
123 fn to_kernel(&self) -> Result<Status, Status> {
124 Err(Status::Invalid)
125 }
126}
127
128macro_rules! impl_exchangeable {
131 ($($t:ty),*) => {
132 $(
133 impl SentryExchangeable for $t {
134 fn from_kernel(&mut self) -> Result<Status, Status> {
135 let (_, aligned, _) = unsafe { EXCHANGE_AREA.align_to_mut::<$t>() };
136 let slot = aligned.first_mut().ok_or(Status::Invalid)?;
137 *self = *slot;
138 Ok(Status::Ok)
139 }
140
141 #[cfg(test)]
142 fn to_kernel(&self) -> Result<Status, Status> {
143 let (_, aligned, _) = unsafe { EXCHANGE_AREA.align_to_mut::<$t>() };
144 let slot = aligned.first_mut().ok_or(Status::Invalid)?;
145 *slot = *self;
146 Ok(Status::Ok)
147 }
148
149 #[cfg(not(test))]
150 fn to_kernel(&self) -> Result<Status, Status> {
151 Err(Status::Invalid)
152 }
153 }
154 )*
155 };
156}
157
158impl_exchangeable!(u8, u16, u32, u64, usize);
159
160impl ExchangeHeader {
162 unsafe fn from_addr() -> Option<&'static Self> {
165 let (_, aligned, _) = unsafe { EXCHANGE_AREA.align_to::<Self>() };
166 aligned.first()
167 }
168
169 #[cfg(test)]
170 unsafe fn from_addr_mut(self) -> &'static mut Self {
171 let (_, aligned, _) = unsafe { EXCHANGE_AREA.align_to_mut::<Self>() };
172 aligned
174 .first_mut()
175 .expect("Exchange area too small or misaligned")
176 }
177
178 pub unsafe fn from_exchange(self) -> Option<&'static Self> {
187 unsafe { Self::from_addr() }
188 }
189
190 #[cfg(test)]
191 pub unsafe fn from_exchange_mut(self) -> &'static mut Self {
192 unsafe { self.from_addr_mut() }
193 }
194}
195
196impl SentryExchangeable for crate::systypes::Event<'_> {
239 #[allow(static_mut_refs)]
240 fn from_kernel(&mut self) -> Result<Status, Status> {
241 use core::ptr;
242
243 unsafe {
244 let header = ptr::read_unaligned(EXCHANGE_AREA.as_ptr() as *const ExchangeHeader);
248 self.header = header;
249 }
250
251 if !self.header.is_valid() {
252 return Err(Status::Invalid);
253 }
254
255 let header_len = core::mem::size_of::<ExchangeHeader>();
256 if header_len + usize::from(self.header.length) > EXCHANGE_AREA_LEN {
257 return Err(Status::Invalid);
258 }
259
260 unsafe {
261 let data_ptr = EXCHANGE_AREA.as_ptr().add(header_len);
262 let data_slice = core::slice::from_raw_parts(data_ptr, self.header.length.into());
263 if data_slice.len() > self.data.len() {
264 return Err(Status::Invalid);
265 }
266 for (dst, src) in self.data.iter_mut().zip(data_slice.iter()) {
267 *dst = *src;
268 }
269 }
270
271 Ok(Status::Ok)
272 }
273
274 #[cfg(not(test))]
280 fn to_kernel(&self) -> Result<Status, Status> {
281 use crate::systypes::EventType;
282
283 if self.header.event == EventType::Ipc.into() {
284 self.data.to_kernel()
285 } else {
286 Err(Status::Invalid)
287 }
288 }
289
290 #[cfg(test)]
291 #[allow(static_mut_refs)]
292 fn to_kernel(&self) -> Result<Status, Status> {
293 use core::ptr;
294
295 if usize::from(self.header.length) > self.data.len() {
296 return Err(Status::Invalid);
297 }
298
299 unsafe {
300 ptr::write_unaligned(
302 EXCHANGE_AREA.as_mut_ptr() as *mut ExchangeHeader,
303 self.header,
304 );
305
306 let header_len = core::mem::size_of::<ExchangeHeader>();
308 let data_addr = EXCHANGE_AREA.as_mut_ptr().add(header_len);
309 let dst_slice = core::slice::from_raw_parts_mut(data_addr, self.header.length.into());
310 dst_slice.copy_from_slice(&self.data[..self.header.length.into()]);
311 }
312
313 Ok(Status::Ok)
314 }
315}
316
317impl SentryExchangeable for &mut [u8] {
318 #[allow(static_mut_refs)]
319 fn from_kernel(&mut self) -> Result<Status, Status> {
320 unsafe {
321 core::ptr::copy_nonoverlapping(
322 EXCHANGE_AREA.as_ptr(),
323 self.as_mut_ptr(),
324 self.len().min(EXCHANGE_AREA_LEN),
325 );
326 }
327 Ok(Status::Ok)
328 }
329
330 #[allow(static_mut_refs)]
331 fn to_kernel(&self) -> Result<Status, Status> {
332 unsafe {
333 core::ptr::copy_nonoverlapping(
334 self.as_ptr(),
335 EXCHANGE_AREA.as_mut_ptr(),
336 self.len().min(EXCHANGE_AREA_LEN),
337 );
338 }
339 Ok(Status::Ok)
340 }
341}
342
343impl SentryExchangeable for &[u8] {
344 #[allow(static_mut_refs)]
345 fn from_kernel(&mut self) -> Result<Status, Status> {
346 Err(Status::Invalid)
347 }
348
349 #[allow(static_mut_refs)]
350 fn to_kernel(&self) -> Result<Status, Status> {
351 unsafe {
352 core::ptr::copy_nonoverlapping(
353 self.as_ptr(),
354 EXCHANGE_AREA.as_mut_ptr(),
355 self.len().min(EXCHANGE_AREA_LEN),
356 );
357 }
358 Ok(Status::Ok)
359 }
360}
361
362pub const fn length() -> usize {
363 EXCHANGE_AREA_LEN
364}
365
366pub fn copy_to_kernel<T>(from: &T) -> Result<Status, Status>
381where
382 T: SentryExchangeable + ?Sized,
383{
384 from.to_kernel()
385}
386
387pub fn copy_from_kernel<T>(to: &mut T) -> Result<Status, Status>
388where
389 T: SentryExchangeable + ?Sized,
390{
391 to.from_kernel()
392}
393
394#[cfg(test)]
395mod tests {
396 #[allow(dead_code)]
397 #[repr(align(8))]
398 pub struct ExchangeAligned(pub [u8; 128]);
399 #[unsafe(no_mangle)]
400 pub static mut EXCHANGE_AREA_TEST: ExchangeAligned = ExchangeAligned([0u8; 128]);
401
402 use crate::systypes::{EventType, ShmHandle};
403
404 use super::*;
405
406 #[test]
407 fn back_to_back_shminfo() {
408 let src = ShmInfo {
409 handle: 2,
410 label: 42,
411 base: 0x123456,
412 len: 64,
413 perms: 0x1,
414 };
415 let mut dst = ShmInfo {
416 handle: 0,
417 label: 0,
418 base: 0,
419 len: 0,
420 perms: 0,
421 };
422 let _ = src.to_kernel();
423 let _ = dst.from_kernel();
424 assert_eq!(src, dst);
425 }
426
427 #[test]
428 fn back_to_back_shmhandle() {
429 let src: ShmHandle = 33;
430 let mut dst: ShmHandle = 0;
431 let res1 = src.to_kernel();
433 let res2 = dst.from_kernel();
434 assert_eq!(res1, Ok(Status::Ok));
435 assert_eq!(res2, Ok(Status::Ok));
436 assert_eq!(src, dst);
437 }
438
439 #[test]
440 fn back_to_back_event() {
441 let src = crate::systypes::Event {
442 header: ExchangeHeader {
443 peer: 0x42,
444 event: EventType::Irq.into(),
445 length: 12,
446 magic: 0x4242,
447 },
448 data: &mut [0x42; 12],
449 };
450 let mut dst = crate::systypes::Event {
451 header: ExchangeHeader {
452 peer: 0,
453 event: EventType::None.into(),
454 length: 0,
455 magic: 0,
456 },
457 data: &mut [0; 12],
458 };
459
460 assert_eq!(src.to_kernel(), Ok(Status::Ok));
461 assert_eq!(dst.from_kernel(), Ok(Status::Ok));
462 assert_eq!(src.header, dst.header);
463 assert_eq!(
464 src.data[..src.header.length.into()],
465 dst.data[..src.header.length.into()]
466 );
467 let mut shorter_dst = crate::systypes::Event {
468 header: ExchangeHeader {
469 peer: 0,
470 event: EventType::None.into(),
471 length: 0,
472 magic: 0,
473 },
474 data: &mut [0; 8],
475 };
476 assert_eq!(shorter_dst.from_kernel(), Err(Status::Invalid));
478 }
479
480 #[test]
481 fn back_to_back_c_string() {
482 let src: &[u8] = &[42, 1, 3, 5, 12];
483 let mut dst: &mut [u8] = &mut [0, 0, 0, 0, 0];
484 assert_eq!(src.to_kernel(), Ok(Status::Ok));
485 assert_eq!(dst.from_kernel(), Ok(Status::Ok));
486 assert_eq!(src, dst);
487 }
488
489 #[test]
490 fn back_to_back_u8() {
491 let src: u8 = 42;
492 let mut dst = 0;
493 assert_eq!(src.to_kernel(), Ok(Status::Ok));
494 assert_eq!(dst.from_kernel(), Ok(Status::Ok));
495 assert_eq!(src, dst);
496 }
497
498 #[test]
499 fn back_to_back_u16() {
500 let src: u16 = 42;
501 let mut dst = 0;
502 assert_eq!(src.to_kernel(), Ok(Status::Ok));
503 assert_eq!(dst.from_kernel(), Ok(Status::Ok));
504 assert_eq!(src, dst);
505 }
506
507 #[test]
508 fn back_to_back_u32() {
509 let src: u32 = 42;
510 let mut dst = 0;
511 assert_eq!(src.to_kernel(), Ok(Status::Ok));
512 assert_eq!(dst.from_kernel(), Ok(Status::Ok));
513 assert_eq!(src, dst);
514 }
515
516 #[test]
517 fn back_to_back_u64() {
518 let src: u64 = 42;
519 let mut dst = 0;
520 assert_eq!(src.to_kernel(), Ok(Status::Ok));
521 assert_eq!(dst.from_kernel(), Ok(Status::Ok));
522 assert_eq!(src, dst);
523 }
524}