1#![no_std]
8#![deny(clippy::undocumented_unsafe_blocks)]
9#![deny(unsafe_op_in_unsafe_fn)]
10
11#[cfg(target_arch = "aarch64")]
12mod aarch64_mmio;
13pub mod fields;
14mod physical;
15#[cfg(not(target_arch = "aarch64"))]
16mod volatile_mmio;
17
18use crate::fields::{ReadOnly, ReadPure, ReadPureWrite, ReadWrite, WriteOnly};
19use core::{array, fmt::Debug, marker::PhantomData, ops::Deref, ptr, ptr::NonNull};
20pub use physical::PhysicalInstance;
21use zerocopy::{FromBytes, Immutable, IntoBytes};
22
23pub struct UniqueMmioPointer<'a, T: ?Sized>(SharedMmioPointer<'a, T>);
31
32impl<T: ?Sized> Debug for UniqueMmioPointer<'_, T> {
36 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
37 f.debug_tuple("UniqueMmioPointer")
38 .field(&self.0.regs)
39 .finish()
40 }
41}
42
43impl<T: ?Sized> PartialEq for UniqueMmioPointer<'_, T> {
44 fn eq(&self, other: &Self) -> bool {
45 self.0 == other.0
46 }
47}
48
49impl<T: ?Sized> Eq for UniqueMmioPointer<'_, T> {}
50
51impl<T: ?Sized> UniqueMmioPointer<'_, T> {
52 pub unsafe fn new(regs: NonNull<T>) -> Self {
64 Self(SharedMmioPointer {
65 regs,
66 phantom: PhantomData,
67 })
68 }
69
70 pub unsafe fn child<U>(&mut self, regs: NonNull<U>) -> UniqueMmioPointer<U> {
79 UniqueMmioPointer(SharedMmioPointer {
80 regs,
81 phantom: PhantomData,
82 })
83 }
84
85 pub fn ptr_mut(&mut self) -> *mut T {
87 self.0.regs.as_ptr()
88 }
89
90 pub fn ptr_nonnull(&mut self) -> NonNull<T> {
92 self.0.regs
93 }
94}
95
96impl<T: FromBytes + IntoBytes> UniqueMmioPointer<'_, ReadWrite<T>> {
97 pub fn read(&mut self) -> T {
99 unsafe { self.read_unsafe().0 }
102 }
103}
104
105impl<T: Immutable + IntoBytes> UniqueMmioPointer<'_, ReadWrite<T>> {
106 pub fn write(&mut self, value: T) {
108 unsafe {
111 self.write_unsafe(ReadWrite(value));
112 }
113 }
114}
115
116impl<T: Immutable + IntoBytes> UniqueMmioPointer<'_, ReadPureWrite<T>> {
117 pub fn write(&mut self, value: T) {
119 unsafe {
122 self.write_unsafe(ReadPureWrite(value));
123 }
124 }
125}
126
127impl<T: FromBytes + IntoBytes> UniqueMmioPointer<'_, ReadOnly<T>> {
128 pub fn read(&mut self) -> T {
130 unsafe { self.read_unsafe().0 }
133 }
134}
135
136impl<T: Immutable + IntoBytes> UniqueMmioPointer<'_, WriteOnly<T>> {
137 pub fn write(&mut self, value: T) {
139 unsafe {
142 self.write_unsafe(WriteOnly(value));
143 }
144 }
145}
146
147impl<T> UniqueMmioPointer<'_, [T]> {
148 pub fn get(&mut self, index: usize) -> Option<UniqueMmioPointer<T>> {
163 if index >= self.len() {
164 return None;
165 }
166 let regs = NonNull::new(unsafe { &raw mut (*self.ptr_mut())[index] }).unwrap();
169 Some(unsafe { self.child(regs) })
172 }
173}
174
175impl<T, const LEN: usize> UniqueMmioPointer<'_, [T; LEN]> {
176 pub fn split(&mut self) -> [UniqueMmioPointer<T>; LEN] {
178 array::from_fn(|i| {
179 UniqueMmioPointer(SharedMmioPointer {
180 regs: NonNull::new(unsafe { &raw mut (*self.ptr_mut())[i] }).unwrap(),
183 phantom: PhantomData,
184 })
185 })
186 }
187
188 pub fn get(&mut self, index: usize) -> Option<UniqueMmioPointer<T>> {
203 if index >= LEN {
204 return None;
205 }
206 let regs = NonNull::new(unsafe { &raw mut (*self.ptr_mut())[index] }).unwrap();
209 Some(unsafe { self.child(regs) })
212 }
213}
214
215impl<'a, T: ?Sized> From<&'a mut T> for UniqueMmioPointer<'a, T> {
216 fn from(r: &'a mut T) -> Self {
217 Self(SharedMmioPointer {
218 regs: r.into(),
219 phantom: PhantomData,
220 })
221 }
222}
223
224impl<'a, T: ?Sized> Deref for UniqueMmioPointer<'a, T> {
225 type Target = SharedMmioPointer<'a, T>;
226
227 fn deref(&self) -> &Self::Target {
228 &self.0
229 }
230}
231
232pub struct SharedMmioPointer<'a, T: ?Sized> {
236 regs: NonNull<T>,
237 phantom: PhantomData<&'a T>,
238}
239
240impl<T: ?Sized> Debug for SharedMmioPointer<'_, T> {
244 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
245 f.debug_tuple("SharedMmioPointer")
246 .field(&self.regs)
247 .finish()
248 }
249}
250
251impl<T: ?Sized> PartialEq for SharedMmioPointer<'_, T> {
252 fn eq(&self, other: &Self) -> bool {
253 ptr::eq(self.regs.as_ptr(), other.regs.as_ptr())
254 }
255}
256
257impl<T: ?Sized> Eq for SharedMmioPointer<'_, T> {}
258
259impl<T: ?Sized> Clone for SharedMmioPointer<'_, T> {
260 fn clone(&self) -> Self {
261 Self {
262 regs: self.regs.clone(),
263 phantom: self.phantom.clone(),
264 }
265 }
266}
267
268impl<T: ?Sized> SharedMmioPointer<'_, T> {
269 pub unsafe fn child<U>(&self, regs: NonNull<U>) -> SharedMmioPointer<U> {
278 SharedMmioPointer {
279 regs,
280 phantom: PhantomData,
281 }
282 }
283
284 pub fn ptr(&self) -> *const T {
286 self.regs.as_ptr()
287 }
288}
289
290unsafe impl<T: ?Sized + Send + Sync> Send for SharedMmioPointer<'_, T> {}
294
295impl<'a, T: ?Sized> From<&'a T> for SharedMmioPointer<'a, T> {
296 fn from(r: &'a T) -> Self {
297 Self {
298 regs: r.into(),
299 phantom: PhantomData,
300 }
301 }
302}
303
304impl<'a, T: ?Sized> From<UniqueMmioPointer<'a, T>> for SharedMmioPointer<'a, T> {
305 fn from(unique: UniqueMmioPointer<'a, T>) -> Self {
306 unique.0
307 }
308}
309
310impl<T: FromBytes + IntoBytes> SharedMmioPointer<'_, ReadPure<T>> {
311 pub fn read(&self) -> T {
313 unsafe { self.read_unsafe().0 }
317 }
318}
319
320impl<T: FromBytes + IntoBytes> SharedMmioPointer<'_, ReadPureWrite<T>> {
321 pub fn read(&self) -> T {
323 unsafe { self.read_unsafe().0 }
327 }
328}
329
330impl<T> SharedMmioPointer<'_, [T]> {
331 pub fn get(&self, index: usize) -> Option<SharedMmioPointer<T>> {
334 if index >= self.len() {
335 return None;
336 }
337 let regs = NonNull::new(unsafe { &raw mut (*self.regs.as_ptr())[index] }).unwrap();
339 Some(unsafe { self.child(regs) })
342 }
343
344 pub const fn len(&self) -> usize {
346 self.regs.len()
347 }
348
349 pub const fn is_empty(&self) -> bool {
351 self.regs.is_empty()
352 }
353}
354
355impl<T, const LEN: usize> SharedMmioPointer<'_, [T; LEN]> {
356 pub fn split(&self) -> [SharedMmioPointer<T>; LEN] {
358 array::from_fn(|i| SharedMmioPointer {
359 regs: NonNull::new(unsafe { &raw mut (*self.regs.as_ptr())[i] }).unwrap(),
362 phantom: PhantomData,
363 })
364 }
365
366 pub fn get(&self, index: usize) -> Option<SharedMmioPointer<T>> {
369 if index >= LEN {
370 return None;
371 }
372 let regs = NonNull::new(unsafe { &raw mut (*self.regs.as_ptr())[index] }).unwrap();
374 Some(unsafe { self.child(regs) })
377 }
378}
379
380#[macro_export]
382macro_rules! field {
383 ($mmio_pointer:expr, $field:ident) => {{
384 let mmio_pointer: &mut $crate::UniqueMmioPointer<_> = &mut $mmio_pointer;
386 unsafe {
390 let child_pointer =
391 core::ptr::NonNull::new(&raw mut (*mmio_pointer.ptr_mut()).$field).unwrap();
392 mmio_pointer.child(child_pointer)
393 }
394 }};
395}
396
397#[macro_export]
399macro_rules! field_shared {
400 ($mmio_pointer:expr, $field:ident) => {{
401 let mmio_pointer: &$crate::SharedMmioPointer<_> = &$mmio_pointer;
403 unsafe {
407 let child_pointer =
408 core::ptr::NonNull::new((&raw const (*mmio_pointer.ptr()).$field).cast_mut())
409 .unwrap();
410 mmio_pointer.child(child_pointer)
411 }
412 }};
413}
414
415#[cfg(test)]
416mod tests {
417 use super::*;
418
419 #[test]
420 fn fields() {
421 #[repr(C)]
422 struct Foo {
423 a: ReadWrite<u32>,
424 b: ReadOnly<u32>,
425 c: ReadPure<u32>,
426 }
427
428 let mut foo = Foo {
429 a: ReadWrite(1),
430 b: ReadOnly(2),
431 c: ReadPure(3),
432 };
433 let mut owned: UniqueMmioPointer<Foo> = UniqueMmioPointer::from(&mut foo);
434
435 let mut owned_a: UniqueMmioPointer<ReadWrite<u32>> = field!(owned, a);
436 assert_eq!(owned_a.read(), 1);
437 owned_a.write(42);
438 assert_eq!(owned_a.read(), 42);
439 field!(owned, a).write(44);
440 assert_eq!(field!(owned, a).read(), 44);
441
442 let mut owned_b: UniqueMmioPointer<ReadOnly<u32>> = field!(owned, b);
443 assert_eq!(owned_b.read(), 2);
444
445 let owned_c: UniqueMmioPointer<ReadPure<u32>> = field!(owned, c);
446 assert_eq!(owned_c.read(), 3);
447 assert_eq!(field!(owned, c).read(), 3);
448 }
449
450 #[test]
451 fn shared_fields() {
452 #[repr(C)]
453 struct Foo {
454 a: ReadPureWrite<u32>,
455 b: ReadPure<u32>,
456 }
457
458 let foo = Foo {
459 a: ReadPureWrite(1),
460 b: ReadPure(2),
461 };
462 let shared: SharedMmioPointer<Foo> = SharedMmioPointer::from(&foo);
463
464 let shared_a: SharedMmioPointer<ReadPureWrite<u32>> = field_shared!(shared, a);
465 assert_eq!(shared_a.read(), 1);
466 assert_eq!(field_shared!(shared, a).read(), 1);
467
468 let shared_b: SharedMmioPointer<ReadPure<u32>> = field_shared!(shared, b);
469 assert_eq!(shared_b.read(), 2);
470 }
471
472 #[test]
473 fn shared_from_unique() {
474 #[repr(C)]
475 struct Foo {
476 a: ReadPureWrite<u32>,
477 b: ReadPure<u32>,
478 }
479
480 let mut foo = Foo {
481 a: ReadPureWrite(1),
482 b: ReadPure(2),
483 };
484 let unique: UniqueMmioPointer<Foo> = UniqueMmioPointer::from(&mut foo);
485
486 let shared_a: SharedMmioPointer<ReadPureWrite<u32>> = field_shared!(unique, a);
487 assert_eq!(shared_a.read(), 1);
488
489 let shared_b: SharedMmioPointer<ReadPure<u32>> = field_shared!(unique, b);
490 assert_eq!(shared_b.read(), 2);
491 }
492
493 #[test]
494 fn restricted_fields() {
495 #[repr(C)]
496 struct Foo {
497 r: ReadOnly<u32>,
498 w: WriteOnly<u32>,
499 u: u32,
500 }
501
502 let mut foo = Foo {
503 r: ReadOnly(1),
504 w: WriteOnly(2),
505 u: 3,
506 };
507 let mut owned: UniqueMmioPointer<Foo> = UniqueMmioPointer::from(&mut foo);
508
509 let mut owned_r: UniqueMmioPointer<ReadOnly<u32>> = field!(owned, r);
510 assert_eq!(owned_r.read(), 1);
511
512 let mut owned_w: UniqueMmioPointer<WriteOnly<u32>> = field!(owned, w);
513 owned_w.write(42);
514
515 let mut owned_u: UniqueMmioPointer<u32> = field!(owned, u);
516 unsafe {
518 assert_eq!(owned_u.read_unsafe(), 3);
519 owned_u.write_unsafe(42);
520 assert_eq!(owned_u.read_unsafe(), 42);
521 }
522 }
523
524 #[test]
525 fn array() {
526 let mut foo = [ReadWrite(1), ReadWrite(2), ReadWrite(3)];
527 let mut owned = UniqueMmioPointer::from(&mut foo);
528
529 let mut parts = owned.split();
530 assert_eq!(parts[0].read(), 1);
531 assert_eq!(parts[1].read(), 2);
532 assert_eq!(owned.split()[2].read(), 3);
533 }
534
535 #[test]
536 fn array_shared() {
537 let foo = [ReadPure(1), ReadPure(2), ReadPure(3)];
538 let shared = SharedMmioPointer::from(&foo);
539
540 let parts = shared.split();
541 assert_eq!(parts[0].read(), 1);
542 assert_eq!(parts[1].read(), 2);
543 assert_eq!(shared.split()[2].read(), 3);
544 }
545
546 #[test]
547 fn slice() {
548 let mut foo = [ReadWrite(1), ReadWrite(2), ReadWrite(3)];
549 let mut owned = UniqueMmioPointer::from(foo.as_mut_slice());
550
551 assert!(!owned.ptr().is_null());
552 assert!(!owned.ptr_mut().is_null());
553
554 assert!(!owned.is_empty());
555 assert_eq!(owned.len(), 3);
556
557 let mut first: UniqueMmioPointer<ReadWrite<i32>> = owned.get(0).unwrap();
558 assert_eq!(first.read(), 1);
559
560 let mut second: UniqueMmioPointer<ReadWrite<i32>> = owned.get(1).unwrap();
561 assert_eq!(second.read(), 2);
562
563 assert!(owned.get(3).is_none());
564 }
565
566 #[test]
567 fn slice_shared() {
568 let foo = [ReadPure(1), ReadPure(2), ReadPure(3)];
569 let shared = SharedMmioPointer::from(foo.as_slice());
570
571 assert!(!shared.ptr().is_null());
572
573 assert!(!shared.is_empty());
574 assert_eq!(shared.len(), 3);
575
576 let first: SharedMmioPointer<ReadPure<i32>> = shared.get(0).unwrap();
577 assert_eq!(first.read(), 1);
578
579 let second: SharedMmioPointer<ReadPure<i32>> = shared.get(1).unwrap();
580 assert_eq!(second.read(), 2);
581
582 assert!(shared.get(3).is_none());
583 }
584}