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 const unsafe fn new(regs: NonNull<T>) -> Self {
64 Self(SharedMmioPointer {
65 regs,
66 phantom: PhantomData,
67 })
68 }
69
70 pub const unsafe fn child<U: ?Sized>(&mut self, regs: NonNull<U>) -> UniqueMmioPointer<U> {
79 UniqueMmioPointer(SharedMmioPointer {
80 regs,
81 phantom: PhantomData,
82 })
83 }
84
85 pub const fn ptr_mut(&mut self) -> *mut T {
87 self.0.regs.as_ptr()
88 }
89
90 pub const fn ptr_nonnull(&mut self) -> NonNull<T> {
92 self.0.regs
93 }
94
95 pub const fn reborrow(&mut self) -> UniqueMmioPointer<T> {
97 let ptr = self.ptr_nonnull();
98 unsafe { self.child(ptr) }
101 }
102}
103
104impl<'a, T: ?Sized> UniqueMmioPointer<'a, T> {
105 pub const unsafe fn split_child<U: ?Sized>(
117 &mut self,
118 regs: NonNull<U>,
119 ) -> UniqueMmioPointer<'a, U> {
120 UniqueMmioPointer(SharedMmioPointer {
121 regs,
122 phantom: PhantomData,
123 })
124 }
125}
126
127impl<T: FromBytes + IntoBytes> UniqueMmioPointer<'_, ReadWrite<T>> {
128 pub fn read(&mut self) -> T {
130 unsafe { self.read_unsafe().0 }
133 }
134}
135
136impl<T: Immutable + IntoBytes> UniqueMmioPointer<'_, ReadWrite<T>> {
137 pub fn write(&mut self, value: T) {
139 unsafe {
142 self.write_unsafe(ReadWrite(value));
143 }
144 }
145}
146
147impl<T: Immutable + IntoBytes> UniqueMmioPointer<'_, ReadPureWrite<T>> {
148 pub fn write(&mut self, value: T) {
150 unsafe {
153 self.write_unsafe(ReadPureWrite(value));
154 }
155 }
156}
157
158impl<T: FromBytes + IntoBytes> UniqueMmioPointer<'_, ReadOnly<T>> {
159 pub fn read(&mut self) -> T {
161 unsafe { self.read_unsafe().0 }
164 }
165}
166
167impl<T: Immutable + IntoBytes> UniqueMmioPointer<'_, WriteOnly<T>> {
168 pub fn write(&mut self, value: T) {
170 unsafe {
173 self.write_unsafe(WriteOnly(value));
174 }
175 }
176}
177
178impl<'a, T> UniqueMmioPointer<'a, [T]> {
179 pub const fn get(&mut self, index: usize) -> Option<UniqueMmioPointer<T>> {
194 if index >= self.0.len() {
195 return None;
196 }
197 let regs = NonNull::new(unsafe { &raw mut (*self.ptr_mut())[index] }).unwrap();
200 Some(unsafe { self.child(regs) })
203 }
204
205 pub const fn take(mut self, index: usize) -> Option<UniqueMmioPointer<'a, T>> {
225 if index >= self.0.len() {
226 return None;
227 }
228 let regs = NonNull::new(unsafe { &raw mut (*self.ptr_mut())[index] }).unwrap();
231 Some(unsafe { self.split_child(regs) })
235 }
236}
237
238impl<'a, T, const LEN: usize> UniqueMmioPointer<'a, [T; LEN]> {
239 pub fn split(&mut self) -> [UniqueMmioPointer<T>; LEN] {
241 array::from_fn(|i| {
242 UniqueMmioPointer(SharedMmioPointer {
243 regs: NonNull::new(unsafe { &raw mut (*self.ptr_mut())[i] }).unwrap(),
246 phantom: PhantomData,
247 })
248 })
249 }
250
251 pub const fn as_mut_slice(&mut self) -> UniqueMmioPointer<[T]> {
253 let regs = NonNull::new(self.ptr_mut()).unwrap();
254 unsafe { self.child(regs) }
257 }
258
259 pub const fn get(&mut self, index: usize) -> Option<UniqueMmioPointer<T>> {
275 if index >= LEN {
276 return None;
277 }
278 let regs = NonNull::new(unsafe { &raw mut (*self.ptr_mut())[index] }).unwrap();
281 Some(unsafe { self.child(regs) })
284 }
285
286 pub const fn take(mut self, index: usize) -> Option<UniqueMmioPointer<'a, T>> {
306 if index >= LEN {
307 return None;
308 }
309 let regs = NonNull::new(unsafe { &raw mut (*self.ptr_mut())[index] }).unwrap();
312 Some(unsafe { self.split_child(regs) })
316 }
317}
318
319impl<'a, T, const LEN: usize> From<UniqueMmioPointer<'a, [T; LEN]>> for UniqueMmioPointer<'a, [T]> {
320 fn from(mut value: UniqueMmioPointer<'a, [T; LEN]>) -> Self {
321 let regs = NonNull::new(value.ptr_mut()).unwrap();
322 unsafe { UniqueMmioPointer::new(regs) }
325 }
326}
327
328impl<'a, T> From<UniqueMmioPointer<'a, T>> for UniqueMmioPointer<'a, [T; 1]> {
329 fn from(mut value: UniqueMmioPointer<'a, T>) -> Self {
330 let regs = NonNull::new(value.ptr_mut()).unwrap().cast();
331 unsafe { UniqueMmioPointer::new(regs) }
334 }
335}
336
337impl<'a, T> From<UniqueMmioPointer<'a, T>> for UniqueMmioPointer<'a, [T]> {
338 fn from(mut value: UniqueMmioPointer<'a, T>) -> Self {
339 let array: *mut [T; 1] = value.ptr_mut().cast();
340 let regs = NonNull::new(array).unwrap();
341 unsafe { UniqueMmioPointer::new(regs) }
344 }
345}
346
347impl<'a, T, const LEN: usize> From<UniqueMmioPointer<'a, [T; LEN]>>
348 for [UniqueMmioPointer<'a, T>; LEN]
349{
350 fn from(mut value: UniqueMmioPointer<'a, [T; LEN]>) -> Self {
351 array::from_fn(|i| {
352 let item_pointer = value.split()[i].ptr_mut();
353 unsafe { value.split_child(core::ptr::NonNull::new(item_pointer).unwrap()) }
356 })
357 }
358}
359
360impl<'a, T: ?Sized> From<&'a mut T> for UniqueMmioPointer<'a, T> {
361 fn from(r: &'a mut T) -> Self {
362 Self(SharedMmioPointer {
363 regs: r.into(),
364 phantom: PhantomData,
365 })
366 }
367}
368
369impl<'a, T: ?Sized> Deref for UniqueMmioPointer<'a, T> {
370 type Target = SharedMmioPointer<'a, T>;
371
372 fn deref(&self) -> &Self::Target {
373 &self.0
374 }
375}
376
377pub struct SharedMmioPointer<'a, T: ?Sized> {
381 regs: NonNull<T>,
382 phantom: PhantomData<&'a T>,
383}
384
385impl<T: ?Sized> Debug for SharedMmioPointer<'_, T> {
389 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
390 f.debug_tuple("SharedMmioPointer")
391 .field(&self.regs)
392 .finish()
393 }
394}
395
396impl<T: ?Sized> PartialEq for SharedMmioPointer<'_, T> {
397 fn eq(&self, other: &Self) -> bool {
398 ptr::eq(self.regs.as_ptr(), other.regs.as_ptr())
399 }
400}
401
402impl<T: ?Sized> Eq for SharedMmioPointer<'_, T> {}
403
404impl<T: ?Sized> Clone for SharedMmioPointer<'_, T> {
405 fn clone(&self) -> Self {
406 *self
407 }
408}
409
410impl<T: ?Sized> Copy for SharedMmioPointer<'_, T> {}
411
412impl<'a, T: ?Sized> SharedMmioPointer<'a, T> {
413 pub const unsafe fn child<U: ?Sized>(&self, regs: NonNull<U>) -> SharedMmioPointer<'a, U> {
422 SharedMmioPointer {
423 regs,
424 phantom: PhantomData,
425 }
426 }
427
428 pub const fn ptr(&self) -> *const T {
430 self.regs.as_ptr()
431 }
432}
433
434unsafe impl<T: ?Sized + Send + Sync> Send for SharedMmioPointer<'_, T> {}
438
439impl<'a, T: ?Sized> From<&'a T> for SharedMmioPointer<'a, T> {
440 fn from(r: &'a T) -> Self {
441 Self {
442 regs: r.into(),
443 phantom: PhantomData,
444 }
445 }
446}
447
448impl<'a, T: ?Sized> From<UniqueMmioPointer<'a, T>> for SharedMmioPointer<'a, T> {
449 fn from(unique: UniqueMmioPointer<'a, T>) -> Self {
450 unique.0
451 }
452}
453
454impl<T: FromBytes + IntoBytes> SharedMmioPointer<'_, ReadPure<T>> {
455 pub fn read(&self) -> T {
457 unsafe { self.read_unsafe().0 }
461 }
462}
463
464impl<T: FromBytes + IntoBytes> SharedMmioPointer<'_, ReadPureWrite<T>> {
465 pub fn read(&self) -> T {
467 unsafe { self.read_unsafe().0 }
471 }
472}
473
474impl<'a, T> SharedMmioPointer<'a, [T]> {
475 pub const fn get(&self, index: usize) -> Option<SharedMmioPointer<'a, T>> {
478 if index >= self.len() {
479 return None;
480 }
481 let regs = NonNull::new(unsafe { &raw mut (*self.regs.as_ptr())[index] }).unwrap();
483 Some(unsafe { self.child(regs) })
486 }
487
488 pub const fn len(&self) -> usize {
490 self.regs.len()
491 }
492
493 pub const fn is_empty(&self) -> bool {
495 self.regs.is_empty()
496 }
497}
498
499impl<'a, T, const LEN: usize> SharedMmioPointer<'a, [T; LEN]> {
500 pub fn split(&self) -> [SharedMmioPointer<'a, T>; LEN] {
502 array::from_fn(|i| SharedMmioPointer {
503 regs: NonNull::new(unsafe { &raw mut (*self.regs.as_ptr())[i] }).unwrap(),
506 phantom: PhantomData,
507 })
508 }
509
510 pub const fn as_slice(&self) -> SharedMmioPointer<'a, [T]> {
512 let regs = NonNull::new(self.regs.as_ptr()).unwrap();
513 unsafe { self.child(regs) }
516 }
517
518 pub const fn get(&self, index: usize) -> Option<SharedMmioPointer<'a, T>> {
521 if index >= LEN {
522 return None;
523 }
524 let regs = NonNull::new(unsafe { &raw mut (*self.regs.as_ptr())[index] }).unwrap();
526 Some(unsafe { self.child(regs) })
529 }
530}
531
532impl<'a, T, const LEN: usize> From<SharedMmioPointer<'a, [T; LEN]>> for SharedMmioPointer<'a, [T]> {
533 fn from(value: SharedMmioPointer<'a, [T; LEN]>) -> Self {
534 let regs = NonNull::new(value.regs.as_ptr()).unwrap();
535 SharedMmioPointer {
536 regs,
537 phantom: PhantomData,
538 }
539 }
540}
541
542impl<'a, T> From<SharedMmioPointer<'a, T>> for SharedMmioPointer<'a, [T; 1]> {
543 fn from(value: SharedMmioPointer<'a, T>) -> Self {
544 let regs = NonNull::new(value.regs.as_ptr()).unwrap().cast();
545 SharedMmioPointer {
546 regs,
547 phantom: PhantomData,
548 }
549 }
550}
551
552impl<'a, T> From<SharedMmioPointer<'a, T>> for SharedMmioPointer<'a, [T]> {
553 fn from(value: SharedMmioPointer<'a, T>) -> Self {
554 let array: *mut [T; 1] = value.regs.as_ptr().cast();
555 let regs = NonNull::new(array).unwrap();
556 SharedMmioPointer {
557 regs,
558 phantom: PhantomData,
559 }
560 }
561}
562
563#[macro_export]
565macro_rules! field {
566 ($mmio_pointer:expr, $field:ident) => {{
567 let mmio_pointer: &mut $crate::UniqueMmioPointer<_> = &mut $mmio_pointer;
569 unsafe {
573 let child_pointer =
574 core::ptr::NonNull::new(&raw mut (*mmio_pointer.ptr_mut()).$field).unwrap();
575 mmio_pointer.child(child_pointer)
576 }
577 }};
578}
579
580#[macro_export]
586macro_rules! split_fields {
587 ($mmio_pointer:expr, $( $field:ident ),+) => {{
588 let mut mmio_pointer: $crate::UniqueMmioPointer<_> = $mmio_pointer;
590 let pointer = mmio_pointer.ptr_mut();
591 let ret = (
592 $(
593 {
598 let child_pointer = core::ptr::NonNull::new(&raw mut (*pointer).$field).unwrap();
599 mmio_pointer.split_child(child_pointer)
600 }
601 ),+
602 );
603 ret
604 }};
605}
606
607#[macro_export]
609macro_rules! field_shared {
610 ($mmio_pointer:expr, $field:ident) => {{
611 let mmio_pointer: &$crate::SharedMmioPointer<_> = &$mmio_pointer;
613 unsafe {
617 let child_pointer =
618 core::ptr::NonNull::new((&raw const (*mmio_pointer.ptr()).$field).cast_mut())
619 .unwrap();
620 mmio_pointer.child(child_pointer)
621 }
622 }};
623}
624
625#[cfg(test)]
626mod tests {
627 use super::*;
628
629 #[test]
630 fn fields() {
631 #[repr(C)]
632 struct Foo {
633 a: ReadWrite<u32>,
634 b: ReadOnly<u32>,
635 c: ReadPure<u32>,
636 }
637
638 let mut foo = Foo {
639 a: ReadWrite(1),
640 b: ReadOnly(2),
641 c: ReadPure(3),
642 };
643 let mut owned: UniqueMmioPointer<Foo> = UniqueMmioPointer::from(&mut foo);
644
645 let mut owned_a: UniqueMmioPointer<ReadWrite<u32>> = field!(owned, a);
646 assert_eq!(owned_a.read(), 1);
647 owned_a.write(42);
648 assert_eq!(owned_a.read(), 42);
649 field!(owned, a).write(44);
650 assert_eq!(field!(owned, a).read(), 44);
651
652 let mut owned_b: UniqueMmioPointer<ReadOnly<u32>> = field!(owned, b);
653 assert_eq!(owned_b.read(), 2);
654
655 let owned_c: UniqueMmioPointer<ReadPure<u32>> = field!(owned, c);
656 assert_eq!(owned_c.read(), 3);
657 assert_eq!(field!(owned, c).read(), 3);
658 }
659
660 #[test]
661 fn shared_fields() {
662 #[repr(C)]
663 struct Foo {
664 a: ReadPureWrite<u32>,
665 b: ReadPure<u32>,
666 }
667
668 let foo = Foo {
669 a: ReadPureWrite(1),
670 b: ReadPure(2),
671 };
672 let shared: SharedMmioPointer<Foo> = SharedMmioPointer::from(&foo);
673
674 let shared_a: SharedMmioPointer<ReadPureWrite<u32>> = field_shared!(shared, a);
675 assert_eq!(shared_a.read(), 1);
676 assert_eq!(field_shared!(shared, a).read(), 1);
677
678 let shared_b: SharedMmioPointer<ReadPure<u32>> = field_shared!(shared, b);
679 assert_eq!(shared_b.read(), 2);
680 }
681
682 #[test]
683 fn shared_from_unique() {
684 #[repr(C)]
685 struct Foo {
686 a: ReadPureWrite<u32>,
687 b: ReadPure<u32>,
688 }
689
690 let mut foo = Foo {
691 a: ReadPureWrite(1),
692 b: ReadPure(2),
693 };
694 let unique: UniqueMmioPointer<Foo> = UniqueMmioPointer::from(&mut foo);
695
696 let shared_a: SharedMmioPointer<ReadPureWrite<u32>> = field_shared!(unique, a);
697 assert_eq!(shared_a.read(), 1);
698
699 let shared_b: SharedMmioPointer<ReadPure<u32>> = field_shared!(unique, b);
700 assert_eq!(shared_b.read(), 2);
701 }
702
703 #[test]
704 fn restricted_fields() {
705 #[repr(C)]
706 struct Foo {
707 r: ReadOnly<u32>,
708 w: WriteOnly<u32>,
709 u: u32,
710 }
711
712 let mut foo = Foo {
713 r: ReadOnly(1),
714 w: WriteOnly(2),
715 u: 3,
716 };
717 let mut owned: UniqueMmioPointer<Foo> = UniqueMmioPointer::from(&mut foo);
718
719 let mut owned_r: UniqueMmioPointer<ReadOnly<u32>> = field!(owned, r);
720 assert_eq!(owned_r.read(), 1);
721
722 let mut owned_w: UniqueMmioPointer<WriteOnly<u32>> = field!(owned, w);
723 owned_w.write(42);
724
725 let mut owned_u: UniqueMmioPointer<u32> = field!(owned, u);
726 unsafe {
728 assert_eq!(owned_u.read_unsafe(), 3);
729 owned_u.write_unsafe(42);
730 assert_eq!(owned_u.read_unsafe(), 42);
731 }
732 }
733
734 #[test]
735 fn array() {
736 let mut foo = [ReadWrite(1), ReadWrite(2), ReadWrite(3)];
737 let mut owned = UniqueMmioPointer::from(&mut foo);
738
739 let mut parts = owned.split();
740 assert_eq!(parts[0].read(), 1);
741 assert_eq!(parts[1].read(), 2);
742 assert_eq!(owned.split()[2].read(), 3);
743 }
744
745 #[test]
746 fn array_shared() {
747 let foo = [ReadPure(1), ReadPure(2), ReadPure(3)];
748 let shared = SharedMmioPointer::from(&foo);
749
750 let parts = shared.split();
751 assert_eq!(parts[0].read(), 1);
752 assert_eq!(parts[1].read(), 2);
753 assert_eq!(shared.split()[2].read(), 3);
754 }
755
756 #[test]
757 fn slice() {
758 let mut foo = [ReadWrite(1), ReadWrite(2), ReadWrite(3)];
759 let mut owned = UniqueMmioPointer::from(foo.as_mut_slice());
760
761 assert!(!owned.ptr().is_null());
762 assert!(!owned.ptr_mut().is_null());
763
764 assert!(!owned.is_empty());
765 assert_eq!(owned.len(), 3);
766
767 let mut first: UniqueMmioPointer<ReadWrite<i32>> = owned.get(0).unwrap();
768 assert_eq!(first.read(), 1);
769
770 let mut second: UniqueMmioPointer<ReadWrite<i32>> = owned.get(1).unwrap();
771 assert_eq!(second.read(), 2);
772
773 assert!(owned.get(3).is_none());
774 }
775
776 #[test]
777 fn slice_shared() {
778 let foo = [ReadPure(1), ReadPure(2), ReadPure(3)];
779 let shared = SharedMmioPointer::from(foo.as_slice());
780
781 assert!(!shared.ptr().is_null());
782
783 assert!(!shared.is_empty());
784 assert_eq!(shared.len(), 3);
785
786 let first: SharedMmioPointer<ReadPure<i32>> = shared.get(0).unwrap();
787 assert_eq!(first.read(), 1);
788
789 let second: SharedMmioPointer<ReadPure<i32>> = shared.get(1).unwrap();
790 assert_eq!(second.read(), 2);
791
792 assert!(shared.get(3).is_none());
793
794 let second = {
797 let shared_copy = shared;
798 shared_copy.get(1).unwrap()
799 };
800 assert_eq!(second.read(), 2);
801 }
802
803 #[test]
804 fn array_field() {
805 #[repr(C)]
806 struct Regs {
807 a: [ReadPureWrite<u32>; 4],
808 }
809
810 let mut foo = Regs {
811 a: [const { ReadPureWrite(0) }; 4],
812 };
813 let mut owned: UniqueMmioPointer<Regs> = UniqueMmioPointer::from(&mut foo);
814
815 field!(owned, a).get(0).unwrap().write(42);
816 assert_eq!(field_shared!(owned, a).get(0).unwrap().read(), 42);
817 }
818
819 #[test]
820 fn slice_field() {
821 #[repr(transparent)]
822 struct Regs {
823 s: [ReadPureWrite<u32>],
824 }
825
826 impl Regs {
827 fn from_slice<'a>(slice: &'a mut [ReadPureWrite<u32>]) -> &'a mut Self {
828 let regs_ptr: *mut Self = slice as *mut [ReadPureWrite<u32>] as *mut Self;
829 unsafe { &mut *regs_ptr }
832 }
833 }
834
835 let mut foo: [ReadPureWrite<u32>; 1] = [ReadPureWrite(0)];
836 let regs_mut = Regs::from_slice(foo.as_mut_slice());
837 let mut owned: UniqueMmioPointer<Regs> = UniqueMmioPointer::from(regs_mut);
838
839 field!(owned, s).get(0).unwrap().write(42);
840 assert_eq!(field_shared!(owned, s).get(0).unwrap().read(), 42);
841 }
842
843 #[test]
844 fn multiple_fields() {
845 #[repr(C)]
846 struct Regs {
847 first: ReadPureWrite<u32>,
848 second: ReadPureWrite<u32>,
849 third: ReadPureWrite<u32>,
850 }
851
852 let mut foo = Regs {
853 first: ReadPureWrite(1),
854 second: ReadPureWrite(2),
855 third: ReadPureWrite(3),
856 };
857 let mut owned: UniqueMmioPointer<Regs> = UniqueMmioPointer::from(&mut foo);
858
859 let (first, second) = unsafe { split_fields!(owned.reborrow(), first, second) };
861
862 assert_eq!(first.read(), 1);
863 assert_eq!(second.read(), 2);
864
865 drop(first);
866 drop(second);
867
868 assert_eq!(field!(owned, first).read(), 1);
869 }
870
871 #[test]
872 fn split_array() {
873 let mut foo = [ReadWrite(1), ReadWrite(2), ReadWrite(3)];
874
875 let mut parts: [UniqueMmioPointer<ReadWrite<i32>>; 3] = {
876 let owned = UniqueMmioPointer::from(&mut foo);
877
878 owned.into()
879 };
880
881 assert_eq!(parts[0].read(), 1);
882 assert_eq!(parts[1].read(), 2);
883 }
884}