1#![no_std]
8#![deny(clippy::undocumented_unsafe_blocks)]
9#![deny(unsafe_op_in_unsafe_fn)]
10#![cfg_attr(docsrs, feature(doc_cfg))]
11
12mod backend;
13pub mod fields;
14mod physical;
15
16use crate::backend::Ops;
17pub use crate::backend::mmio_ops::MmioOps;
18use crate::fields::{ReadOnly, ReadPure, ReadPureWrite, ReadWrite, WriteOnly};
19use core::{
20 array,
21 fmt::Debug,
22 marker::PhantomData,
23 ops::{Deref, Range},
24 ptr::{self, NonNull, slice_from_raw_parts_mut},
25};
26pub use physical::PhysicalInstance;
27use zerocopy::{FromBytes, Immutable, IntoBytes};
28
29pub struct UniqueMmioPointer<'a, T: ?Sized>(SharedMmioPointer<'a, T>);
37
38impl<T: ?Sized> Debug for UniqueMmioPointer<'_, T> {
42 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
43 f.debug_tuple("UniqueMmioPointer")
44 .field(&self.0.regs)
45 .finish()
46 }
47}
48
49impl<T: ?Sized> PartialEq for UniqueMmioPointer<'_, T> {
50 fn eq(&self, other: &Self) -> bool {
51 self.0 == other.0
52 }
53}
54
55impl<T: ?Sized> Eq for UniqueMmioPointer<'_, T> {}
56
57impl<T: ?Sized> UniqueMmioPointer<'_, T> {
58 pub const unsafe fn new(regs: NonNull<T>) -> Self {
70 Self(SharedMmioPointer {
71 regs,
72 phantom: PhantomData,
73 })
74 }
75
76 pub const unsafe fn child<U: ?Sized>(&mut self, regs: NonNull<U>) -> UniqueMmioPointer<'_, U> {
85 UniqueMmioPointer(SharedMmioPointer {
86 regs,
87 phantom: PhantomData,
88 })
89 }
90
91 pub const fn ptr_mut(&mut self) -> *mut T {
93 self.0.regs.as_ptr()
94 }
95
96 pub const fn ptr_nonnull(&mut self) -> NonNull<T> {
98 self.0.regs
99 }
100
101 pub const fn reborrow(&mut self) -> UniqueMmioPointer<'_, T> {
103 let ptr = self.ptr_nonnull();
104 unsafe { self.child(ptr) }
107 }
108}
109
110impl<'a, T: ?Sized> UniqueMmioPointer<'a, T> {
111 pub const unsafe fn split_child<U: ?Sized>(
123 &mut self,
124 regs: NonNull<U>,
125 ) -> UniqueMmioPointer<'a, U> {
126 UniqueMmioPointer(SharedMmioPointer {
127 regs,
128 phantom: PhantomData,
129 })
130 }
131}
132
133impl<T: FromBytes + IntoBytes> UniqueMmioPointer<'_, ReadWrite<T>> {
134 pub fn read(&mut self) -> T {
136 unsafe { self.read_unsafe().0 }
139 }
140}
141
142impl<T: Immutable + IntoBytes> UniqueMmioPointer<'_, ReadWrite<T>> {
143 pub fn write(&mut self, value: T) {
145 unsafe {
148 self.write_unsafe(ReadWrite(value));
149 }
150 }
151}
152
153impl<T: FromBytes + Immutable + IntoBytes> UniqueMmioPointer<'_, ReadWrite<T>> {
154 pub fn modify(&mut self, f: impl FnOnce(T) -> T) {
159 let value = self.read();
160 self.write(f(value));
161 }
162
163 pub fn modify_mut(&mut self, f: impl FnOnce(&mut T)) {
168 let mut value = self.read();
169 f(&mut value);
170 self.write(value);
171 }
172}
173
174impl<T: Immutable + IntoBytes> UniqueMmioPointer<'_, ReadPureWrite<T>> {
175 pub fn write(&mut self, value: T) {
177 unsafe {
180 self.write_unsafe(ReadPureWrite(value));
181 }
182 }
183}
184
185impl<T: FromBytes + Immutable + IntoBytes> UniqueMmioPointer<'_, ReadPureWrite<T>> {
186 pub fn modify(&mut self, f: impl FnOnce(T) -> T) {
191 let value = self.read();
192 self.write(f(value));
193 }
194
195 pub fn modify_mut(&mut self, f: impl FnOnce(&mut T)) {
200 let mut value = self.read();
201 f(&mut value);
202 self.write(value);
203 }
204}
205
206impl<T: FromBytes + IntoBytes> UniqueMmioPointer<'_, ReadOnly<T>> {
207 pub fn read(&mut self) -> T {
209 unsafe { self.read_unsafe().0 }
212 }
213}
214
215impl<T: Immutable + IntoBytes> UniqueMmioPointer<'_, WriteOnly<T>> {
216 pub fn write(&mut self, value: T) {
218 unsafe {
221 self.write_unsafe(WriteOnly(value));
222 }
223 }
224}
225
226impl<'a, T> UniqueMmioPointer<'a, [T]> {
227 pub const fn get(&mut self, index: usize) -> Option<UniqueMmioPointer<'_, T>> {
242 if index >= self.0.len() {
243 return None;
244 }
245 let regs = NonNull::new(unsafe { &raw mut (*self.ptr_mut())[index] }).unwrap();
248 Some(unsafe { self.child(regs) })
251 }
252
253 pub fn get_range(&mut self, range: Range<usize>) -> Option<UniqueMmioPointer<'_, [T]>> {
272 if range.start > range.end || range.end > self.0.len() {
273 return None;
274 }
275
276 let regs_start = if !range.is_empty() {
277 unsafe { &raw mut (*self.ptr_mut())[range.start] }
281 } else {
282 NonNull::dangling().as_ptr()
285 };
286
287 let regs = NonNull::new(slice_from_raw_parts_mut(regs_start, range.len())).unwrap();
288
289 Some(unsafe { self.child(regs) })
293 }
294
295 pub fn iter(&mut self) -> UniqueMmioPointerIterator<'_, T> {
297 UniqueMmioPointerIterator {
298 tail: self.reborrow(),
299 }
300 }
301
302 pub const fn take(mut self, index: usize) -> Option<UniqueMmioPointer<'a, T>> {
322 if index >= self.0.len() {
323 return None;
324 }
325 let regs = NonNull::new(unsafe { &raw mut (*self.ptr_mut())[index] }).unwrap();
328 Some(unsafe { self.split_child(regs) })
332 }
333}
334
335impl<'a, T, const LEN: usize> UniqueMmioPointer<'a, [T; LEN]> {
336 pub fn split(mut self) -> [UniqueMmioPointer<'a, T>; LEN] {
338 array::from_fn(|i| {
339 UniqueMmioPointer(SharedMmioPointer {
340 regs: NonNull::new(unsafe { &raw mut (*self.ptr_mut())[i] }).unwrap(),
343 phantom: PhantomData,
344 })
345 })
346 }
347
348 pub fn split_some<const N: usize>(
353 mut self,
354 chosen: [usize; N],
355 ) -> [UniqueMmioPointer<'a, T>; N] {
356 for (i, a) in chosen.iter().enumerate() {
357 for (j, b) in chosen.iter().enumerate() {
358 assert!(i == j || a != b, "chosen array must not contain duplicates");
359 }
360 }
361 chosen.map(|chosen_index| {
362 UniqueMmioPointer(SharedMmioPointer {
363 regs: NonNull::new(unsafe { &raw mut (*self.ptr_mut())[chosen_index] }).unwrap(),
367 phantom: PhantomData,
368 })
369 })
370 }
371
372 pub const fn as_mut_slice(&mut self) -> UniqueMmioPointer<'_, [T]> {
374 let regs = NonNull::new(self.ptr_mut()).unwrap();
375 unsafe { self.child(regs) }
378 }
379
380 pub const fn get(&mut self, index: usize) -> Option<UniqueMmioPointer<'_, T>> {
396 if index >= LEN {
397 return None;
398 }
399 let regs = NonNull::new(unsafe { &raw mut (*self.ptr_mut())[index] }).unwrap();
402 Some(unsafe { self.child(regs) })
405 }
406
407 pub fn get_range(&mut self, range: Range<usize>) -> Option<UniqueMmioPointer<'_, [T]>> {
426 if range.start > range.end || range.end > LEN {
427 return None;
428 }
429
430 let regs_start = if !range.is_empty() {
431 unsafe { &raw mut (*self.ptr_mut())[range.start] }
435 } else {
436 NonNull::dangling().as_ptr()
439 };
440
441 let regs = NonNull::new(slice_from_raw_parts_mut(regs_start, range.len())).unwrap();
442
443 Some(unsafe { self.child(regs) })
447 }
448
449 pub fn iter(&mut self) -> UniqueMmioPointerIterator<'_, T> {
451 UniqueMmioPointerIterator {
452 tail: self.as_mut_slice(),
453 }
454 }
455
456 pub const fn take(mut self, index: usize) -> Option<UniqueMmioPointer<'a, T>> {
476 if index >= LEN {
477 return None;
478 }
479 let regs = NonNull::new(unsafe { &raw mut (*self.ptr_mut())[index] }).unwrap();
482 Some(unsafe { self.split_child(regs) })
486 }
487}
488
489impl<'a, T, const LEN: usize> From<UniqueMmioPointer<'a, [T; LEN]>> for UniqueMmioPointer<'a, [T]> {
490 fn from(mut value: UniqueMmioPointer<'a, [T; LEN]>) -> Self {
491 let regs = NonNull::new(value.ptr_mut()).unwrap();
492 unsafe { UniqueMmioPointer::new(regs) }
495 }
496}
497
498impl<'a, T> From<UniqueMmioPointer<'a, T>> for UniqueMmioPointer<'a, [T; 1]> {
499 fn from(mut value: UniqueMmioPointer<'a, T>) -> Self {
500 let regs = NonNull::new(value.ptr_mut()).unwrap().cast();
501 unsafe { UniqueMmioPointer::new(regs) }
504 }
505}
506
507impl<'a, T> From<UniqueMmioPointer<'a, T>> for UniqueMmioPointer<'a, [T]> {
508 fn from(mut value: UniqueMmioPointer<'a, T>) -> Self {
509 let array: *mut [T; 1] = value.ptr_mut().cast();
510 let regs = NonNull::new(array).unwrap();
511 unsafe { UniqueMmioPointer::new(regs) }
514 }
515}
516
517impl<'a, T, const LEN: usize> From<UniqueMmioPointer<'a, [T; LEN]>>
518 for [UniqueMmioPointer<'a, T>; LEN]
519{
520 fn from(mut value: UniqueMmioPointer<'a, [T; LEN]>) -> Self {
521 array::from_fn(|i| {
522 let item_pointer = value.get(i).unwrap().ptr_mut();
523 unsafe { value.split_child(core::ptr::NonNull::new(item_pointer).unwrap()) }
526 })
527 }
528}
529
530impl<'a, T: ?Sized> From<&'a mut T> for UniqueMmioPointer<'a, T> {
531 fn from(r: &'a mut T) -> Self {
532 Self(SharedMmioPointer {
533 regs: r.into(),
534 phantom: PhantomData,
535 })
536 }
537}
538
539impl<'a, T: ?Sized> Deref for UniqueMmioPointer<'a, T> {
540 type Target = SharedMmioPointer<'a, T>;
541
542 fn deref(&self) -> &Self::Target {
543 &self.0
544 }
545}
546
547impl<'a, T> IntoIterator for UniqueMmioPointer<'a, [T]> {
548 type Item = UniqueMmioPointer<'a, T>;
549
550 type IntoIter = UniqueMmioPointerIterator<'a, T>;
551
552 fn into_iter(self) -> Self::IntoIter {
553 UniqueMmioPointerIterator { tail: self }
554 }
555}
556
557impl<'a, T, const LEN: usize> IntoIterator for UniqueMmioPointer<'a, [T; LEN]> {
558 type Item = UniqueMmioPointer<'a, T>;
559
560 type IntoIter = UniqueMmioPointerIterator<'a, T>;
561
562 fn into_iter(self) -> Self::IntoIter {
563 UniqueMmioPointerIterator { tail: self.into() }
564 }
565}
566
567#[derive(Debug)]
572pub struct UniqueMmioPointerIterator<'a, T> {
573 tail: UniqueMmioPointer<'a, [T]>,
574}
575
576impl<'a, T> Iterator for UniqueMmioPointerIterator<'a, T> {
577 type Item = UniqueMmioPointer<'a, T>;
578
579 fn next(&mut self) -> Option<Self::Item> {
580 if !self.tail.is_empty() {
581 let regs_head = NonNull::new(unsafe { &raw mut (*self.tail.ptr_mut())[0] }).unwrap();
585
586 let head = unsafe { self.tail.split_child(regs_head) };
590
591 let regs_tail = NonNull::new(slice_from_raw_parts_mut(
592 regs_head.as_ptr().wrapping_add(1),
593 self.tail.len() - 1,
594 ))
595 .unwrap();
596
597 self.tail = unsafe { self.tail.split_child(regs_tail) };
601
602 Some(head)
603 } else {
604 None
605 }
606 }
607
608 fn size_hint(&self) -> (usize, Option<usize>) {
609 (self.tail.len(), Some(self.tail.len()))
610 }
611}
612
613pub struct SharedMmioPointer<'a, T: ?Sized> {
617 regs: NonNull<T>,
618 phantom: PhantomData<&'a T>,
619}
620
621impl<T: ?Sized> Debug for SharedMmioPointer<'_, T> {
625 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
626 f.debug_tuple("SharedMmioPointer")
627 .field(&self.regs)
628 .finish()
629 }
630}
631
632impl<T: ?Sized> PartialEq for SharedMmioPointer<'_, T> {
633 fn eq(&self, other: &Self) -> bool {
634 ptr::eq(self.regs.as_ptr(), other.regs.as_ptr())
635 }
636}
637
638impl<T: ?Sized> Eq for SharedMmioPointer<'_, T> {}
639
640impl<T: ?Sized> Clone for SharedMmioPointer<'_, T> {
641 fn clone(&self) -> Self {
642 *self
643 }
644}
645
646impl<T: ?Sized> Copy for SharedMmioPointer<'_, T> {}
647
648impl<'a, T: ?Sized> SharedMmioPointer<'a, T> {
649 pub const unsafe fn child<U: ?Sized>(&self, regs: NonNull<U>) -> SharedMmioPointer<'a, U> {
658 SharedMmioPointer {
659 regs,
660 phantom: PhantomData,
661 }
662 }
663
664 pub const fn ptr(&self) -> *const T {
666 self.regs.as_ptr()
667 }
668}
669
670unsafe impl<T: ?Sized + Send + Sync> Send for SharedMmioPointer<'_, T> {}
674
675impl<'a, T: ?Sized> From<&'a T> for SharedMmioPointer<'a, T> {
676 fn from(r: &'a T) -> Self {
677 Self {
678 regs: r.into(),
679 phantom: PhantomData,
680 }
681 }
682}
683
684impl<'a, T: ?Sized> From<UniqueMmioPointer<'a, T>> for SharedMmioPointer<'a, T> {
685 fn from(unique: UniqueMmioPointer<'a, T>) -> Self {
686 unique.0
687 }
688}
689
690impl<T: FromBytes + IntoBytes> SharedMmioPointer<'_, ReadPure<T>> {
691 pub fn read(&self) -> T {
693 unsafe { self.read_unsafe().0 }
697 }
698}
699
700impl<T: FromBytes + IntoBytes> SharedMmioPointer<'_, ReadPureWrite<T>> {
701 pub fn read(&self) -> T {
703 unsafe { self.read_unsafe().0 }
707 }
708}
709
710impl<'a, T> SharedMmioPointer<'a, [T]> {
711 pub fn split_some<const N: usize>(self, chosen: [usize; N]) -> [UniqueMmioPointer<'a, T>; N] {
716 for (i, a) in chosen.iter().enumerate() {
717 for (j, b) in chosen.iter().enumerate() {
718 assert!(i == j || a != b, "chosen array must not contain duplicates");
719 }
720 }
721 chosen.map(|chosen_index| {
722 UniqueMmioPointer(SharedMmioPointer {
723 regs: NonNull::new(unsafe { &raw mut (*self.regs.as_ptr())[chosen_index] })
727 .unwrap(),
728 phantom: PhantomData,
729 })
730 })
731 }
732
733 pub const fn get(&self, index: usize) -> Option<SharedMmioPointer<'a, T>> {
736 if index >= self.len() {
737 return None;
738 }
739 let regs = NonNull::new(unsafe { &raw mut (*self.regs.as_ptr())[index] }).unwrap();
741 Some(unsafe { self.child(regs) })
744 }
745
746 pub fn get_range(&self, range: Range<usize>) -> Option<SharedMmioPointer<'_, [T]>> {
749 if range.start > range.end || range.end > self.len() {
750 return None;
751 }
752
753 let regs_start = if !range.is_empty() {
754 unsafe { &raw mut (*self.regs.as_ptr())[range.start] }
758 } else {
759 NonNull::dangling().as_ptr()
762 };
763
764 let regs = NonNull::new(slice_from_raw_parts_mut(regs_start, range.len())).unwrap();
765
766 Some(unsafe { self.child(regs) })
770 }
771
772 pub fn iter(&self) -> SharedMmioPointerIterator<'_, T> {
774 SharedMmioPointerIterator { tail: *self }
775 }
776
777 pub const fn len(&self) -> usize {
779 self.regs.len()
780 }
781
782 pub const fn is_empty(&self) -> bool {
784 self.regs.is_empty()
785 }
786}
787
788impl<'a, T, const LEN: usize> SharedMmioPointer<'a, [T; LEN]> {
789 pub fn split(self) -> [SharedMmioPointer<'a, T>; LEN] {
791 array::from_fn(|i| SharedMmioPointer {
792 regs: NonNull::new(unsafe { &raw mut (*self.regs.as_ptr())[i] }).unwrap(),
795 phantom: PhantomData,
796 })
797 }
798
799 pub const fn as_slice(&self) -> SharedMmioPointer<'a, [T]> {
801 let regs = NonNull::new(self.regs.as_ptr()).unwrap();
802 unsafe { self.child(regs) }
805 }
806
807 pub const fn get(&self, index: usize) -> Option<SharedMmioPointer<'a, T>> {
810 if index >= LEN {
811 return None;
812 }
813 let regs = NonNull::new(unsafe { &raw mut (*self.regs.as_ptr())[index] }).unwrap();
815 Some(unsafe { self.child(regs) })
818 }
819
820 pub fn get_range(&self, range: Range<usize>) -> Option<SharedMmioPointer<'_, [T]>> {
823 if range.start > range.end || range.end > LEN {
824 return None;
825 }
826
827 let regs_start = if !range.is_empty() {
828 unsafe { &raw mut (*self.regs.as_ptr())[range.start] }
831 } else {
832 NonNull::dangling().as_ptr()
835 };
836
837 let regs = NonNull::new(slice_from_raw_parts_mut(regs_start, range.len())).unwrap();
838
839 Some(unsafe { self.child(regs) })
843 }
844
845 pub fn iter(&self) -> SharedMmioPointerIterator<'_, T> {
847 SharedMmioPointerIterator {
848 tail: self.as_slice(),
849 }
850 }
851}
852
853impl<'a, T, const LEN: usize> From<SharedMmioPointer<'a, [T; LEN]>> for SharedMmioPointer<'a, [T]> {
854 fn from(value: SharedMmioPointer<'a, [T; LEN]>) -> Self {
855 let regs = NonNull::new(value.regs.as_ptr()).unwrap();
856 SharedMmioPointer {
857 regs,
858 phantom: PhantomData,
859 }
860 }
861}
862
863impl<'a, T> From<SharedMmioPointer<'a, T>> for SharedMmioPointer<'a, [T; 1]> {
864 fn from(value: SharedMmioPointer<'a, T>) -> Self {
865 let regs = NonNull::new(value.regs.as_ptr()).unwrap().cast();
866 SharedMmioPointer {
867 regs,
868 phantom: PhantomData,
869 }
870 }
871}
872
873impl<'a, T> From<SharedMmioPointer<'a, T>> for SharedMmioPointer<'a, [T]> {
874 fn from(value: SharedMmioPointer<'a, T>) -> Self {
875 let array: *mut [T; 1] = value.regs.as_ptr().cast();
876 let regs = NonNull::new(array).unwrap();
877 SharedMmioPointer {
878 regs,
879 phantom: PhantomData,
880 }
881 }
882}
883
884impl<'a, T> IntoIterator for SharedMmioPointer<'a, [T]> {
885 type Item = SharedMmioPointer<'a, T>;
886
887 type IntoIter = SharedMmioPointerIterator<'a, T>;
888
889 fn into_iter(self) -> Self::IntoIter {
890 SharedMmioPointerIterator { tail: self }
891 }
892}
893
894impl<'a, T, const LEN: usize> IntoIterator for SharedMmioPointer<'a, [T; LEN]> {
895 type Item = SharedMmioPointer<'a, T>;
896
897 type IntoIter = SharedMmioPointerIterator<'a, T>;
898
899 fn into_iter(self) -> Self::IntoIter {
900 SharedMmioPointerIterator { tail: self.into() }
901 }
902}
903
904#[derive(Clone, Copy, Debug)]
909pub struct SharedMmioPointerIterator<'a, T> {
910 tail: SharedMmioPointer<'a, [T]>,
911}
912
913impl<'a, T> Iterator for SharedMmioPointerIterator<'a, T> {
914 type Item = SharedMmioPointer<'a, T>;
915
916 fn next(&mut self) -> Option<Self::Item> {
917 if !self.tail.is_empty() {
918 let regs_head =
922 NonNull::new(unsafe { &raw mut (*self.tail.regs.as_ptr())[0] }).unwrap();
923
924 let head = unsafe { self.tail.child(regs_head) };
927
928 let regs_tail = NonNull::new(slice_from_raw_parts_mut(
929 regs_head.as_ptr().wrapping_add(1),
930 self.tail.len() - 1,
931 ))
932 .unwrap();
933
934 self.tail = unsafe { self.tail.child(regs_tail) };
937
938 Some(head)
939 } else {
940 None
941 }
942 }
943
944 fn size_hint(&self) -> (usize, Option<usize>) {
945 (self.tail.len(), Some(self.tail.len()))
946 }
947}
948
949impl<T: FromBytes + IntoBytes> UniqueMmioPointer<'_, T> {
950 pub unsafe fn read_unsafe(&mut self) -> T {
962 unsafe { Ops::read(self.regs) }
964 }
965}
966
967impl<T: Immutable + IntoBytes> UniqueMmioPointer<'_, T> {
968 pub unsafe fn write_unsafe(&mut self, value: T) {
977 unsafe {
979 Ops::write(self.regs, value);
980 }
981 }
982}
983
984impl<T: FromBytes + IntoBytes> SharedMmioPointer<'_, T> {
985 pub unsafe fn read_unsafe(&self) -> T {
995 unsafe { Ops::read(self.regs) }
997 }
998}
999
1000#[macro_export]
1002macro_rules! field {
1003 ($mmio_pointer:expr, $field:ident) => {{
1004 _ = &mut $mmio_pointer;
1005
1006 unsafe {
1010 let child_pointer = core::ptr::NonNull::new(
1011 &raw mut (*$crate::UniqueMmioPointer::ptr_mut(&mut $mmio_pointer)).$field,
1012 )
1013 .unwrap();
1014 $crate::UniqueMmioPointer::child(&mut $mmio_pointer, child_pointer)
1015 }
1016 }};
1017}
1018
1019#[macro_export]
1025macro_rules! split_fields {
1026 ($mmio_pointer:expr, $( $field:ident ),+) => {{
1027 let mut mmio_pointer: $crate::UniqueMmioPointer<_> = $mmio_pointer;
1029 let pointer = mmio_pointer.ptr_mut();
1030 let ret = (
1031 $(
1032 {
1037 let child_pointer = core::ptr::NonNull::new(&raw mut (*pointer).$field).unwrap();
1038 mmio_pointer.split_child(child_pointer)
1039 }
1040 ),+
1041 );
1042 ret
1043 }};
1044}
1045
1046#[macro_export]
1048macro_rules! field_shared {
1049 ($mmio_pointer:expr, $field:ident) => {{
1050 _ = &$mmio_pointer;
1051
1052 #[allow(unused_unsafe, reason = "May be nested")]
1056 unsafe {
1057 let child_pointer = core::ptr::NonNull::new(
1058 (&raw const (*$crate::SharedMmioPointer::ptr(&$mmio_pointer)).$field).cast_mut(),
1059 )
1060 .unwrap();
1061 $crate::SharedMmioPointer::child(&$mmio_pointer, child_pointer)
1062 }
1063 }};
1064}
1065
1066#[cfg(test)]
1067mod tests {
1068 use super::*;
1069
1070 #[test]
1071 fn fields() {
1072 #[repr(C)]
1073 struct Foo {
1074 a: ReadWrite<u32>,
1075 b: ReadOnly<u32>,
1076 c: ReadPure<u32>,
1077 }
1078
1079 let mut foo = Foo {
1080 a: ReadWrite(1),
1081 b: ReadOnly(2),
1082 c: ReadPure(3),
1083 };
1084 let mut owned: UniqueMmioPointer<Foo> = UniqueMmioPointer::from(&mut foo);
1085
1086 let mut owned_a: UniqueMmioPointer<ReadWrite<u32>> = field!(owned, a);
1087 assert_eq!(owned_a.read(), 1);
1088 owned_a.write(42);
1089 assert_eq!(owned_a.read(), 42);
1090 field!(owned, a).write(44);
1091 assert_eq!(field!(owned, a).read(), 44);
1092
1093 let mut owned_b: UniqueMmioPointer<ReadOnly<u32>> = field!(owned, b);
1094 assert_eq!(owned_b.read(), 2);
1095
1096 let owned_c: UniqueMmioPointer<ReadPure<u32>> = field!(owned, c);
1097 assert_eq!(owned_c.read(), 3);
1098 assert_eq!(field!(owned, c).read(), 3);
1099 }
1100
1101 #[test]
1102 fn shared_fields() {
1103 #[repr(C)]
1104 struct Foo {
1105 a: ReadPureWrite<u32>,
1106 b: ReadPure<u32>,
1107 }
1108
1109 let foo = Foo {
1110 a: ReadPureWrite(1),
1111 b: ReadPure(2),
1112 };
1113 let shared: SharedMmioPointer<Foo> = SharedMmioPointer::from(&foo);
1114
1115 let shared_a: SharedMmioPointer<ReadPureWrite<u32>> = field_shared!(shared, a);
1116 assert_eq!(shared_a.read(), 1);
1117 assert_eq!(field_shared!(shared, a).read(), 1);
1118
1119 let shared_b: SharedMmioPointer<ReadPure<u32>> = field_shared!(shared, b);
1120 assert_eq!(shared_b.read(), 2);
1121 }
1122
1123 #[test]
1124 fn shared_from_unique() {
1125 #[repr(C)]
1126 struct Foo {
1127 a: ReadPureWrite<u32>,
1128 b: ReadPure<u32>,
1129 }
1130
1131 let mut foo = Foo {
1132 a: ReadPureWrite(1),
1133 b: ReadPure(2),
1134 };
1135 let unique: UniqueMmioPointer<Foo> = UniqueMmioPointer::from(&mut foo);
1136
1137 let shared_a: SharedMmioPointer<ReadPureWrite<u32>> = field_shared!(unique, a);
1138 assert_eq!(shared_a.read(), 1);
1139
1140 let shared_b: SharedMmioPointer<ReadPure<u32>> = field_shared!(unique, b);
1141 assert_eq!(shared_b.read(), 2);
1142 }
1143
1144 #[test]
1145 fn restricted_fields() {
1146 #[repr(C)]
1147 struct Foo {
1148 r: ReadOnly<u32>,
1149 w: WriteOnly<u32>,
1150 u: u32,
1151 }
1152
1153 let mut foo = Foo {
1154 r: ReadOnly(1),
1155 w: WriteOnly(2),
1156 u: 3,
1157 };
1158 let mut owned: UniqueMmioPointer<Foo> = UniqueMmioPointer::from(&mut foo);
1159
1160 let mut owned_r: UniqueMmioPointer<ReadOnly<u32>> = field!(owned, r);
1161 assert_eq!(owned_r.read(), 1);
1162
1163 let mut owned_w: UniqueMmioPointer<WriteOnly<u32>> = field!(owned, w);
1164 owned_w.write(42);
1165
1166 let mut owned_u: UniqueMmioPointer<u32> = field!(owned, u);
1167 unsafe {
1169 assert_eq!(owned_u.read_unsafe(), 3);
1170 owned_u.write_unsafe(42);
1171 assert_eq!(owned_u.read_unsafe(), 42);
1172 }
1173 }
1174
1175 #[test]
1176 fn array() {
1177 let mut foo = [ReadWrite(1), ReadWrite(2), ReadWrite(3)];
1178 let mut owned = UniqueMmioPointer::from(&mut foo);
1179
1180 let mut parts = owned.reborrow().split();
1181 assert_eq!(parts[0].read(), 1);
1182 assert_eq!(parts[1].read(), 2);
1183 assert_eq!(owned.split()[2].read(), 3);
1184 }
1185
1186 #[test]
1187 fn array_shared() {
1188 let foo = [ReadPure(1), ReadPure(2), ReadPure(3)];
1189 let shared = SharedMmioPointer::from(&foo);
1190
1191 let parts = shared.split();
1192 assert_eq!(parts[0].read(), 1);
1193 assert_eq!(parts[1].read(), 2);
1194 assert_eq!(shared.split()[2].read(), 3);
1195 }
1196
1197 #[test]
1198 fn slice() {
1199 let mut foo = [ReadWrite(1), ReadWrite(2), ReadWrite(3)];
1200 let mut owned = UniqueMmioPointer::from(foo.as_mut_slice());
1201
1202 assert!(!owned.ptr().is_null());
1203 assert!(!owned.ptr_mut().is_null());
1204
1205 assert!(!owned.is_empty());
1206 assert_eq!(owned.len(), 3);
1207
1208 let mut first: UniqueMmioPointer<ReadWrite<i32>> = owned.get(0).unwrap();
1209 assert_eq!(first.read(), 1);
1210
1211 let mut second: UniqueMmioPointer<ReadWrite<i32>> = owned.get(1).unwrap();
1212 assert_eq!(second.read(), 2);
1213
1214 assert!(owned.get(3).is_none());
1215 }
1216
1217 #[test]
1218 fn slice_shared() {
1219 let foo = [ReadPure(1), ReadPure(2), ReadPure(3)];
1220 let shared = SharedMmioPointer::from(foo.as_slice());
1221
1222 assert!(!shared.ptr().is_null());
1223
1224 assert!(!shared.is_empty());
1225 assert_eq!(shared.len(), 3);
1226
1227 let first: SharedMmioPointer<ReadPure<i32>> = shared.get(0).unwrap();
1228 assert_eq!(first.read(), 1);
1229
1230 let second: SharedMmioPointer<ReadPure<i32>> = shared.get(1).unwrap();
1231 assert_eq!(second.read(), 2);
1232
1233 assert!(shared.get(3).is_none());
1234
1235 let second = {
1238 let shared_copy = shared;
1239 shared_copy.get(1).unwrap()
1240 };
1241 assert_eq!(second.read(), 2);
1242 }
1243
1244 #[test]
1245 fn array_field() {
1246 #[repr(C)]
1247 struct Regs {
1248 a: [ReadPureWrite<u32>; 4],
1249 }
1250
1251 let mut foo = Regs {
1252 a: [const { ReadPureWrite(0) }; 4],
1253 };
1254 let mut owned: UniqueMmioPointer<Regs> = UniqueMmioPointer::from(&mut foo);
1255
1256 field!(owned, a).get(0).unwrap().write(42);
1257 assert_eq!(field_shared!(owned, a).get(0).unwrap().read(), 42);
1258 }
1259
1260 #[test]
1261 fn slice_field() {
1262 #[repr(transparent)]
1263 struct Regs {
1264 s: [ReadPureWrite<u32>],
1265 }
1266
1267 impl Regs {
1268 fn from_slice(slice: &mut [ReadPureWrite<u32>]) -> &mut Self {
1269 let regs_ptr: *mut Self = slice as *mut [ReadPureWrite<u32>] as *mut Self;
1270 unsafe { &mut *regs_ptr }
1273 }
1274 }
1275
1276 let mut foo: [ReadPureWrite<u32>; 1] = [ReadPureWrite(0)];
1277 let regs_mut = Regs::from_slice(foo.as_mut_slice());
1278 let mut owned: UniqueMmioPointer<Regs> = UniqueMmioPointer::from(regs_mut);
1279
1280 field!(owned, s).get(0).unwrap().write(42);
1281 assert_eq!(field_shared!(owned, s).get(0).unwrap().read(), 42);
1282 }
1283
1284 #[test]
1285 fn multiple_fields() {
1286 #[repr(C)]
1287 struct Regs {
1288 first: ReadPureWrite<u32>,
1289 second: ReadPureWrite<u32>,
1290 third: ReadPureWrite<u32>,
1291 }
1292
1293 let mut foo = Regs {
1294 first: ReadPureWrite(1),
1295 second: ReadPureWrite(2),
1296 third: ReadPureWrite(3),
1297 };
1298 let mut owned: UniqueMmioPointer<Regs> = UniqueMmioPointer::from(&mut foo);
1299
1300 let (first, second) = unsafe { split_fields!(owned.reborrow(), first, second) };
1302
1303 assert_eq!(first.read(), 1);
1304 assert_eq!(second.read(), 2);
1305
1306 assert_eq!(first.read(), 1);
1307 assert_eq!(second.read(), 2);
1308
1309 assert_eq!(field!(owned, first).read(), 1);
1310 }
1311
1312 #[test]
1313 fn split_array() {
1314 let mut foo = [ReadWrite(1), ReadWrite(2), ReadWrite(3)];
1315
1316 let mut parts: [UniqueMmioPointer<ReadWrite<i32>>; 3] = {
1317 let owned = UniqueMmioPointer::from(&mut foo);
1318
1319 owned.into()
1320 };
1321
1322 assert_eq!(parts[0].read(), 1);
1323 assert_eq!(parts[1].read(), 2);
1324 }
1325
1326 #[test]
1327 fn subfield() {
1328 #[repr(C)]
1329 struct Regs {
1330 subregs: Subregs,
1331 }
1332
1333 #[repr(C)]
1334 struct Subregs {
1335 field: ReadPureWrite<u32>,
1336 }
1337
1338 let mut foo = Regs {
1339 subregs: Subregs {
1340 field: ReadPureWrite(0),
1341 },
1342 };
1343 let mut owned: UniqueMmioPointer<Regs> = UniqueMmioPointer::from(&mut foo);
1344
1345 assert_eq!(
1346 field_shared!(field_shared!(owned, subregs), field).read(),
1347 0
1348 );
1349
1350 let mut sub = field!(owned, subregs);
1351 let mut field = field!(sub, field);
1352 field.write(42);
1353
1354 assert_eq!(foo.subregs.field.0, 42);
1355 }
1356
1357 #[test]
1358 fn get_range_slice() {
1359 let mut regs = [ReadWrite(1), ReadWrite(2), ReadWrite(3)];
1360
1361 {
1362 let mut ptr = UniqueMmioPointer::from(&mut regs);
1363 let mut slice = ptr.as_mut_slice();
1364
1365 let range = slice.get_range(100..200);
1366 assert!(range.is_none());
1367
1368 let range = slice.get_range(0..3).unwrap();
1369 assert_eq!(range.len(), 3);
1370
1371 let range = slice.get_range(1..3).unwrap();
1372 assert_eq!(range.len(), 2);
1373
1374 let range = slice.get_range(0..0).unwrap();
1375 assert_eq!(range.len(), 0);
1376
1377 let range = slice.get_range(2..2).unwrap();
1378 assert_eq!(range.len(), 0);
1379
1380 let range = slice.get_range(3..3).unwrap();
1381 assert_eq!(range.len(), 0);
1382
1383 let range = slice.get_range(4..4);
1384 assert!(range.is_none());
1385
1386 let mut range = slice.get_range(3..3).unwrap();
1387 let nested_range = range.get_range(0..0).unwrap();
1388 assert_eq!(nested_range.len(), 0);
1389
1390 let nested_range = range.get_range(1..1);
1391 assert!(nested_range.is_none());
1392 }
1393 }
1394
1395 #[test]
1396 fn get_range_array() {
1397 let mut regs = [ReadWrite(1), ReadWrite(2), ReadWrite(3)];
1398
1399 {
1400 let mut ptr = UniqueMmioPointer::from(&mut regs);
1401
1402 let range = ptr.get_range(100..200);
1403 assert!(range.is_none());
1404
1405 let range = ptr.get_range(0..3).unwrap();
1406 assert_eq!(range.len(), 3);
1407
1408 let range = ptr.get_range(1..3).unwrap();
1409 assert_eq!(range.len(), 2);
1410
1411 let range = ptr.get_range(0..0).unwrap();
1412 assert_eq!(range.len(), 0);
1413
1414 let range = ptr.get_range(2..2).unwrap();
1415 assert_eq!(range.len(), 0);
1416
1417 let range = ptr.get_range(3..3).unwrap();
1418 assert_eq!(range.len(), 0);
1419
1420 let range = ptr.get_range(4..4);
1421 assert!(range.is_none());
1422
1423 let mut range = ptr.get_range(3..3).unwrap();
1424 let nested_range = range.get_range(0..0).unwrap();
1425 assert_eq!(nested_range.len(), 0);
1426
1427 let nested_range = range.get_range(1..1);
1428 assert!(nested_range.is_none());
1429 }
1430 }
1431
1432 #[test]
1433 fn shared_get_range_slice() {
1434 let regs = [ReadWrite(1), ReadWrite(2), ReadWrite(3)];
1435
1436 {
1437 let ptr = SharedMmioPointer::from(®s);
1438 let slice = ptr.as_slice();
1439
1440 let range = slice.get_range(100..200);
1441 assert!(range.is_none());
1442
1443 let range = slice.get_range(0..3).unwrap();
1444 assert_eq!(range.len(), 3);
1445
1446 let range = slice.get_range(1..3).unwrap();
1447 assert_eq!(range.len(), 2);
1448
1449 let range = slice.get_range(0..0).unwrap();
1450 assert_eq!(range.len(), 0);
1451
1452 let range = slice.get_range(2..2).unwrap();
1453 assert_eq!(range.len(), 0);
1454
1455 let range = slice.get_range(3..3).unwrap();
1456 assert_eq!(range.len(), 0);
1457
1458 let range = slice.get_range(4..4);
1459 assert!(range.is_none());
1460
1461 let range = slice.get_range(3..3).unwrap();
1462 let nested_range = range.get_range(0..0).unwrap();
1463 assert_eq!(nested_range.len(), 0);
1464
1465 let nested_range = range.get_range(1..1);
1466 assert!(nested_range.is_none());
1467 }
1468 }
1469
1470 #[test]
1471 fn shared_get_range_array() {
1472 let regs = [ReadWrite(1), ReadWrite(2), ReadWrite(3)];
1473
1474 {
1475 let ptr = SharedMmioPointer::from(®s);
1476
1477 let range = ptr.get_range(100..200);
1478 assert!(range.is_none());
1479
1480 let range = ptr.get_range(0..3).unwrap();
1481 assert_eq!(range.len(), 3);
1482
1483 let range = ptr.get_range(1..3).unwrap();
1484 assert_eq!(range.len(), 2);
1485
1486 let range = ptr.get_range(0..0).unwrap();
1487 assert_eq!(range.len(), 0);
1488
1489 let range = ptr.get_range(2..2).unwrap();
1490 assert_eq!(range.len(), 0);
1491
1492 let range = ptr.get_range(3..3).unwrap();
1493 assert_eq!(range.len(), 0);
1494
1495 let range = ptr.get_range(4..4);
1496 assert!(range.is_none());
1497
1498 let range = ptr.get_range(3..3).unwrap();
1499 let nested_range = range.get_range(0..0).unwrap();
1500 assert_eq!(nested_range.len(), 0);
1501
1502 let nested_range = range.get_range(1..1);
1503 assert!(nested_range.is_none());
1504 }
1505 }
1506
1507 #[test]
1508 fn iterator_slice() {
1509 let mut regs = [ReadWrite(1), ReadWrite(2), ReadWrite(3)];
1510
1511 {
1512 let mut ptr = UniqueMmioPointer::from(&mut regs);
1513 let mut slice = ptr.as_mut_slice();
1514
1515 let mut iter = slice.iter();
1516
1517 iter.next().unwrap().write(4);
1518 iter.next().unwrap().write(5);
1519 iter.next().unwrap().write(6);
1520 assert_eq!(iter.next(), None);
1521 }
1522
1523 assert_eq!(regs[0].0, 4);
1524 assert_eq!(regs[1].0, 5);
1525 assert_eq!(regs[2].0, 6);
1526 }
1527
1528 #[test]
1529 fn iterator_array() {
1530 let mut regs = [ReadWrite(1), ReadWrite(2), ReadWrite(3)];
1531
1532 {
1533 let mut ptr = UniqueMmioPointer::from(&mut regs);
1534
1535 let mut iter = ptr.iter();
1536
1537 iter.next().unwrap().write(4);
1538 iter.next().unwrap().write(5);
1539 iter.next().unwrap().write(6);
1540 assert_eq!(iter.next(), None);
1541 }
1542
1543 assert_eq!(regs[0].0, 4);
1544 assert_eq!(regs[1].0, 5);
1545 assert_eq!(regs[2].0, 6);
1546 }
1547
1548 #[test]
1549 fn shared_iterator_slice() {
1550 let regs = [ReadPureWrite(1), ReadPureWrite(2), ReadPureWrite(3)];
1551
1552 let ptr = SharedMmioPointer::from(®s);
1553 let slice = ptr.as_slice();
1554
1555 let mut iter = slice.iter();
1556
1557 assert_eq!(iter.next().unwrap().read(), 1);
1558 assert_eq!(iter.next().unwrap().read(), 2);
1559 assert_eq!(iter.next().unwrap().read(), 3);
1560 assert_eq!(iter.next(), None);
1561 }
1562
1563 #[test]
1564 fn shared_iterator_array() {
1565 let regs = [ReadPureWrite(1), ReadPureWrite(2), ReadPureWrite(3)];
1566
1567 let ptr = SharedMmioPointer::from(®s);
1568
1569 let mut iter = ptr.iter();
1570
1571 assert_eq!(iter.next().unwrap().read(), 1);
1572 assert_eq!(iter.next().unwrap().read(), 2);
1573 assert_eq!(iter.next().unwrap().read(), 3);
1574 assert_eq!(iter.next(), None);
1575 }
1576
1577 #[repr(C)]
1579 #[derive(Debug, PartialEq, Eq, Clone, Copy, FromBytes, IntoBytes, Immutable)]
1580 struct A([u8; 15]);
1581
1582 const A_VAL: A = A([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]);
1583
1584 #[repr(C, align(8))]
1586 struct AlignedBuf([u8; 32]);
1587
1588 fn round_trip_at_offset(offset: usize) {
1591 assert!(offset + size_of::<A>() <= 32);
1592 let mut buf = AlignedBuf([0u8; 32]);
1593
1594 let base = buf.0.as_mut_ptr();
1595 let ptr = unsafe { NonNull::new_unchecked(base.add(offset).cast::<A>()) };
1597 let actual_align = ptr.as_ptr() as usize % 8;
1598 assert_eq!(actual_align, offset % 8);
1599
1600 let mut mmio = unsafe { UniqueMmioPointer::new(ptr) };
1602
1603 unsafe { mmio.write_unsafe(A_VAL) };
1605 let readback = unsafe { mmio.read_unsafe() };
1607 assert_eq!(readback, A_VAL, "round-trip failed at offset {offset}");
1608 }
1609
1610 #[test]
1611 fn unique_read_write_aligned_0() {
1612 round_trip_at_offset(0);
1614 }
1615
1616 #[test]
1617 fn unique_read_write_aligned_1() {
1618 round_trip_at_offset(1);
1620 }
1621
1622 #[test]
1623 fn unique_read_write_aligned_2() {
1624 round_trip_at_offset(2);
1626 }
1627
1628 #[test]
1629 fn unique_read_write_aligned_3() {
1630 round_trip_at_offset(3);
1632 }
1633
1634 #[test]
1635 fn unique_read_write_aligned_4() {
1636 round_trip_at_offset(4);
1638 }
1639
1640 #[test]
1641 fn unique_read_write_aligned_5() {
1642 round_trip_at_offset(5);
1643 }
1644
1645 #[test]
1646 fn unique_read_write_aligned_6() {
1647 round_trip_at_offset(6);
1648 }
1649
1650 #[test]
1651 fn unique_read_write_aligned_7() {
1652 round_trip_at_offset(7);
1653 }
1654}