Skip to main content

safe_mmio/
lib.rs

1// Copyright 2025 The safe-mmio Authors.
2// This project is dual-licensed under Apache 2.0 and MIT terms.
3// See LICENSE-APACHE and LICENSE-MIT for details.
4
5//! Types for safe MMIO device access, especially in systems with an MMU.
6
7#![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
29/// A unique owned pointer to the registers of some MMIO device.
30///
31/// It is guaranteed to be valid and unique; no other access to the MMIO space of the device may
32/// happen for the lifetime `'a`.
33///
34/// A `UniqueMmioPointer` may be created from a mutable reference, but this should only be used for
35/// testing purposes, as references should never be constructed for real MMIO address space.
36pub struct UniqueMmioPointer<'a, T: ?Sized>(SharedMmioPointer<'a, T>);
37
38// Implement Debug, Eq and PartialEq manually rather than deriving to avoid an unneccessary bound on
39// T.
40
41impl<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    /// Creates a new `UniqueMmioPointer` from a non-null raw pointer.
59    ///
60    /// # Safety
61    ///
62    /// `regs` must be a properly aligned and valid pointer to some MMIO address space of type T,
63    /// which is mapped as device memory and valid to read and write from any thread with volatile
64    /// operations. There must not be any other aliases which are used to access the same MMIO
65    /// region while this `UniqueMmioPointer` exists.
66    ///
67    /// If `T` contains any fields wrapped in [`ReadOnly`], [`WriteOnly`] or [`ReadWrite`] then they
68    /// must indeed be safe to perform MMIO reads or writes on.
69    pub const unsafe fn new(regs: NonNull<T>) -> Self {
70        Self(SharedMmioPointer {
71            regs,
72            phantom: PhantomData,
73        })
74    }
75
76    /// Creates a new `UniqueMmioPointer` with the same lifetime as this one.
77    ///
78    /// This is used internally by the [`field!`] macro and shouldn't be called directly.
79    ///
80    /// # Safety
81    ///
82    /// `regs` must be a properly aligned and valid pointer to some MMIO address space of type T,
83    /// within the allocation that `self` points to.
84    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    /// Returns a raw mut pointer to the MMIO registers.
92    pub const fn ptr_mut(&mut self) -> *mut T {
93        self.0.regs.as_ptr()
94    }
95
96    /// Returns a `NonNull<T>` pointer to the MMIO registers.
97    pub const fn ptr_nonnull(&mut self) -> NonNull<T> {
98        self.0.regs
99    }
100
101    /// Returns a new `UniqueMmioPointer` with a lifetime no greater than this one.
102    pub const fn reborrow(&mut self) -> UniqueMmioPointer<'_, T> {
103        let ptr = self.ptr_nonnull();
104        // SAFETY: `ptr` must be properly aligned and valid and within our allocation because it is
105        // exactly our allocation.
106        unsafe { self.child(ptr) }
107    }
108}
109
110impl<'a, T: ?Sized> UniqueMmioPointer<'a, T> {
111    /// Creates a new `UniqueMmioPointer` with the same lifetime as this one, but not tied to the
112    /// lifetime this one is borrowed for.
113    ///
114    /// This is used internally by the [`split_fields!`] macro and shouldn't be called directly.
115    ///
116    /// # Safety
117    ///
118    /// `regs` must be a properly aligned and valid pointer to some MMIO address space of type T,
119    /// within the allocation that `self` points to. `split_child` must not be called for the same
120    /// child field more than once, and the original `UniqueMmioPointer` must not be used after
121    /// `split_child` has been called for one or more of its fields.
122    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    /// Performs an MMIO read of the entire `T`.
135    pub fn read(&mut self) -> T {
136        // SAFETY: self.regs is always a valid and unique pointer to MMIO address space, and `T`
137        // being wrapped in `ReadWrite` implies that it is safe to read.
138        unsafe { self.read_unsafe().0 }
139    }
140}
141
142impl<T: Immutable + IntoBytes> UniqueMmioPointer<'_, ReadWrite<T>> {
143    /// Performs an MMIO write of the entire `T`.
144    pub fn write(&mut self, value: T) {
145        // SAFETY: self.regs is always a valid and unique pointer to MMIO address space, and `T`
146        // being wrapped in `ReadWrite` implies that it is safe to write.
147        unsafe {
148            self.write_unsafe(ReadWrite(value));
149        }
150    }
151}
152
153impl<T: FromBytes + Immutable + IntoBytes> UniqueMmioPointer<'_, ReadWrite<T>> {
154    /// Performs an MMIO read of the entire `T`, applies the given function to it, and then performs
155    /// an MMIO write of the resulting value.
156    ///
157    /// This is equivalent to calling [`read`](Self::read) then [`write`](Self::write).
158    pub fn modify(&mut self, f: impl FnOnce(T) -> T) {
159        let value = self.read();
160        self.write(f(value));
161    }
162
163    /// Performs an MMIO read of the entire `T`, calls the given function to modify it, and then
164    /// performs an MMIO write of the resulting value.
165    ///
166    /// This is equivalent to calling [`read`](Self::read) then [`write`](Self::write).
167    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    /// Performs an MMIO write of the entire `T`.
176    pub fn write(&mut self, value: T) {
177        // SAFETY: self.regs is always a valid and unique pointer to MMIO address space, and `T`
178        // being wrapped in `ReadPureWrite` implies that it is safe to write.
179        unsafe {
180            self.write_unsafe(ReadPureWrite(value));
181        }
182    }
183}
184
185impl<T: FromBytes + Immutable + IntoBytes> UniqueMmioPointer<'_, ReadPureWrite<T>> {
186    /// Performs an MMIO read of the entire `T`, applies the given function to it, and then performs
187    /// an MMIO write of the resulting value.
188    ///
189    /// This is equivalent to calling [`read`](Self::read) then [`write`](Self::write).
190    pub fn modify(&mut self, f: impl FnOnce(T) -> T) {
191        let value = self.read();
192        self.write(f(value));
193    }
194
195    /// Performs an MMIO read of the entire `T`, calls the given function to modify it, and then
196    /// performs an MMIO write of the resulting value.
197    ///
198    /// This is equivalent to calling [`read`](Self::read) then [`write`](Self::write).
199    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    /// Performs an MMIO read of the entire `T`.
208    pub fn read(&mut self) -> T {
209        // SAFETY: self.regs is always a valid and unique pointer to MMIO address space, and `T`
210        // being wrapped in `ReadOnly` implies that it is safe to read.
211        unsafe { self.read_unsafe().0 }
212    }
213}
214
215impl<T: Immutable + IntoBytes> UniqueMmioPointer<'_, WriteOnly<T>> {
216    /// Performs an MMIO write of the entire `T`.
217    pub fn write(&mut self, value: T) {
218        // SAFETY: self.regs is always a valid and unique pointer to MMIO address space, and `T`
219        // being wrapped in `WriteOnly` implies that it is safe to write.
220        unsafe {
221            self.write_unsafe(WriteOnly(value));
222        }
223    }
224}
225
226impl<'a, T> UniqueMmioPointer<'a, [T]> {
227    /// Returns a `UniqueMmioPointer` to an element of this slice, or `None` if the index is out of
228    /// bounds.
229    ///
230    /// # Example
231    ///
232    /// ```
233    /// use safe_mmio::{UniqueMmioPointer, fields::ReadWrite};
234    ///
235    /// let mut slice: UniqueMmioPointer<[ReadWrite<u32>]>;
236    /// # let mut fake = [ReadWrite(1), ReadWrite(2), ReadWrite(3)];
237    /// # slice = UniqueMmioPointer::from(fake.as_mut_slice());
238    /// let mut element = slice.get(1).unwrap();
239    /// element.write(42);
240    /// ```
241    pub const fn get(&mut self, index: usize) -> Option<UniqueMmioPointer<'_, T>> {
242        if index >= self.0.len() {
243            return None;
244        }
245        // SAFETY: self.ptr_mut() is guaranteed to return a pointer that is valid for MMIO and
246        // unique, as promised by the caller of `UniqueMmioPointer::new`.
247        let regs = NonNull::new(unsafe { &raw mut (*self.ptr_mut())[index] }).unwrap();
248        // SAFETY: We created regs from the raw slice in self.regs, so it must also be valid, unique
249        // and within the allocation of self.regs.
250        Some(unsafe { self.child(regs) })
251    }
252
253    /// Returns a `UniqueMmioPointer` to a range of elements of this slice, or `None` if the range
254    /// is out of bounds.
255    ///
256    /// # Example
257    ///
258    /// ```
259    /// use safe_mmio::{UniqueMmioPointer, fields::ReadWrite};
260    ///
261    /// let mut slice: UniqueMmioPointer<[ReadWrite<u32>]>;
262    /// # let mut fake = [ReadWrite(1), ReadWrite(2), ReadWrite(3)];
263    /// # slice = UniqueMmioPointer::from(fake.as_mut_slice());
264    /// let mut range = slice.get_range(1..3).unwrap();
265    /// range.get(0).unwrap().write(100);
266    /// range.get(1).unwrap().write(200);
267    /// assert_eq!(None, range.get(2));
268    /// assert_eq!(100, slice.get(1).unwrap().read());
269    /// assert_eq!(200, slice.get(2).unwrap().read());
270    /// ```
271    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            // SAFETY: self.ptr_mut() is guaranteed to return a pointer that is valid for MMIO and
278            // unique, as promised by the caller of `UniqueMmioPointer::new`. range.start is within the
279            // boundaries of the slice.
280            unsafe { &raw mut (*self.ptr_mut())[range.start] }
281        } else {
282            // Based on the documentation of core::slice::from_raw_parts_mut, NonNull::dangling()
283            // should be used for creating zero-length slices.
284            NonNull::dangling().as_ptr()
285        };
286
287        let regs = NonNull::new(slice_from_raw_parts_mut(regs_start, range.len())).unwrap();
288
289        // SAFETY: We created regs from the valid start address of regs_start and `range` is within
290        // the boundaries of self.regs, so it must also be valid, unique and within the allocation
291        // of self.regs.
292        Some(unsafe { self.child(regs) })
293    }
294
295    /// Returns a new iterator of the items of the slice.
296    pub fn iter(&mut self) -> UniqueMmioPointerIterator<'_, T> {
297        UniqueMmioPointerIterator {
298            tail: self.reborrow(),
299        }
300    }
301
302    /// Returns a `UniqueMmioPointer` to an element of this slice, or `None` if the index is out of
303    /// bounds.
304    ///
305    /// Unlike [`UniqueMmioPointer::get`] this takes ownership of the original pointer. This is
306    /// useful when you want to store the resulting pointer without keeping the original pointer
307    /// around.
308    ///
309    /// # Example
310    ///
311    /// ```
312    /// use safe_mmio::{UniqueMmioPointer, fields::ReadWrite};
313    ///
314    /// let mut slice: UniqueMmioPointer<[ReadWrite<u32>]>;
315    /// # let mut fake = [ReadWrite(1), ReadWrite(2), ReadWrite(3)];
316    /// # slice = UniqueMmioPointer::from(fake.as_mut_slice());
317    /// let mut element = slice.take(1).unwrap();
318    /// element.write(42);
319    /// // `slice` can no longer be used at this point.
320    /// ```
321    pub const fn take(mut self, index: usize) -> Option<UniqueMmioPointer<'a, T>> {
322        if index >= self.0.len() {
323            return None;
324        }
325        // SAFETY: self.ptr_mut() is guaranteed to return a pointer that is valid for MMIO and
326        // unique, as promised by the caller of `UniqueMmioPointer::new`.
327        let regs = NonNull::new(unsafe { &raw mut (*self.ptr_mut())[index] }).unwrap();
328        // SAFETY: We created regs from the raw slice in self.regs, so it must also be valid, unique
329        // and within the allocation of self.regs. `self` is dropped immediately after this and we
330        // don't split out any other children.
331        Some(unsafe { self.split_child(regs) })
332    }
333}
334
335impl<'a, T, const LEN: usize> UniqueMmioPointer<'a, [T; LEN]> {
336    /// Splits a `UniqueMmioPointer` to an array into an array of `UniqueMmioPointer`s.
337    pub fn split(mut self) -> [UniqueMmioPointer<'a, T>; LEN] {
338        array::from_fn(|i| {
339            UniqueMmioPointer(SharedMmioPointer {
340                // SAFETY: self.regs is always unique and valid for MMIO access. We make sure the
341                // pointers we split it into don't overlap, so the same applies to each of them.
342                regs: NonNull::new(unsafe { &raw mut (*self.ptr_mut())[i] }).unwrap(),
343                phantom: PhantomData,
344            })
345        })
346    }
347
348    /// Splits a `UniqueMmioPointer` to an array into an array of `UniqueMmioPointer`s, taking only
349    /// the `chosen` indices.
350    ///
351    /// Panics if `chosen` contains the same index more than once, or any index out of bounds.
352    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                // SAFETY: self.regs is always unique and valid for MMIO access. We checked that
364                // `chosen` doesn't contain duplicates so the pointers we split it into don't
365                // overlap, so the same applies to each of them.
366                regs: NonNull::new(unsafe { &raw mut (*self.ptr_mut())[chosen_index] }).unwrap(),
367                phantom: PhantomData,
368            })
369        })
370    }
371
372    /// Converts this array pointer to an equivalent slice pointer.
373    pub const fn as_mut_slice(&mut self) -> UniqueMmioPointer<'_, [T]> {
374        let regs = NonNull::new(self.ptr_mut()).unwrap();
375        // SAFETY: We created regs from the raw array in self.regs, so it must also be valid, unique
376        // and within the allocation of self.regs.
377        unsafe { self.child(regs) }
378    }
379
380    /// Returns a `UniqueMmioPointer` to an element of this array, or `None` if the index is out of
381    /// bounds.
382    ///
383    /// # Example
384    ///
385    /// ```
386    /// use safe_mmio::{UniqueMmioPointer, fields::ReadWrite};
387    ///
388    /// let mut slice: UniqueMmioPointer<[ReadWrite<u32>; 3]>;
389    /// # let mut fake = [ReadWrite(1), ReadWrite(2), ReadWrite(3)];
390    /// # slice = UniqueMmioPointer::from(&mut fake);
391    /// let mut element = slice.get(1).unwrap();
392    /// element.write(42);
393    /// slice.get(2).unwrap().write(100);
394    /// ```
395    pub const fn get(&mut self, index: usize) -> Option<UniqueMmioPointer<'_, T>> {
396        if index >= LEN {
397            return None;
398        }
399        // SAFETY: self.ptr_mut() is guaranteed to return a pointer that is valid for MMIO and
400        // unique, as promised by the caller of `UniqueMmioPointer::new`.
401        let regs = NonNull::new(unsafe { &raw mut (*self.ptr_mut())[index] }).unwrap();
402        // SAFETY: We created regs from the raw array in self.regs, so it must also be valid, unique
403        // and within the allocation of self.regs.
404        Some(unsafe { self.child(regs) })
405    }
406
407    /// Returns a `UniqueMmioPointer` to a range of elements of this array, or `None` if the range
408    /// is out of bounds.
409    ///
410    /// # Example
411    ///
412    /// ```
413    /// use safe_mmio::{UniqueMmioPointer, fields::ReadWrite};
414    ///
415    /// let mut slice: UniqueMmioPointer<[ReadWrite<u32>; 3]>;
416    /// # let mut fake = [ReadWrite(1), ReadWrite(2), ReadWrite(3)];
417    /// # slice = UniqueMmioPointer::from(&mut fake);
418    /// let mut range = slice.get_range(1..3).unwrap();
419    /// range.get(0).unwrap().write(100);
420    /// range.get(1).unwrap().write(200);
421    /// assert_eq!(None, range.get(2));
422    /// assert_eq!(100, slice.get(1).unwrap().read());
423    /// assert_eq!(200, slice.get(2).unwrap().read());
424    /// ```
425    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            // SAFETY: self.ptr_mut() is guaranteed to return a pointer that is valid for MMIO and
432            // unique, as promised by the caller of `UniqueMmioPointer::new`. range.start is within the
433            // boundaries of the array.
434            unsafe { &raw mut (*self.ptr_mut())[range.start] }
435        } else {
436            // Based on the documentation of core::slice::from_raw_parts_mut, NonNull::dangling()
437            // should be used for creating zero-length slices.
438            NonNull::dangling().as_ptr()
439        };
440
441        let regs = NonNull::new(slice_from_raw_parts_mut(regs_start, range.len())).unwrap();
442
443        // SAFETY: We created regs from the valid start address of regs_start and `range` is within
444        // the boundaries of self.regs, so it must also be valid, unique and within the allocation
445        // of self.regs.
446        Some(unsafe { self.child(regs) })
447    }
448
449    /// Returns a new iterator to the items of the array.
450    pub fn iter(&mut self) -> UniqueMmioPointerIterator<'_, T> {
451        UniqueMmioPointerIterator {
452            tail: self.as_mut_slice(),
453        }
454    }
455
456    /// Returns a `UniqueMmioPointer` to an element of this array, or `None` if the index is out of
457    /// bounds.
458    ///
459    /// Unlike [`UniqueMmioPointer::get`] this takes ownership of the original pointer. This is
460    /// useful when you want to store the resulting pointer without keeping the original pointer
461    /// around.
462    ///
463    /// # Example
464    ///
465    /// ```
466    /// use safe_mmio::{UniqueMmioPointer, fields::ReadWrite};
467    ///
468    /// let mut array: UniqueMmioPointer<[ReadWrite<u32>; 3]>;
469    /// # let mut fake = [ReadWrite(1), ReadWrite(2), ReadWrite(3)];
470    /// # array = UniqueMmioPointer::from(&mut fake);
471    /// let mut element = array.take(1).unwrap();
472    /// element.write(42);
473    /// // `array` can no longer be used at this point.
474    /// ```
475    pub const fn take(mut self, index: usize) -> Option<UniqueMmioPointer<'a, T>> {
476        if index >= LEN {
477            return None;
478        }
479        // SAFETY: self.ptr_mut() is guaranteed to return a pointer that is valid for MMIO and
480        // unique, as promised by the caller of `UniqueMmioPointer::new`.
481        let regs = NonNull::new(unsafe { &raw mut (*self.ptr_mut())[index] }).unwrap();
482        // SAFETY: We created regs from the raw array in self.regs, so it must also be valid, unique
483        // and within the allocation of self.regs. `self` is dropped immediately after this and we
484        // don't split out any other children.
485        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        // SAFETY: regs comes from a UniqueMmioPointer so already satisfies all the safety
493        // requirements.
494        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        // SAFETY: regs comes from a UniqueMmioPointer so already satisfies all the safety
502        // requirements.
503        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        // SAFETY: regs comes from a UniqueMmioPointer so already satisfies all the safety
512        // requirements.
513        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            // SAFETY: `split_child` is called only once on each item and the original
524            // `UniqueMmioPointer` is consumed by this function.
525            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/// Iterator over a `UniqueMmioPointer` slice, yielding pointers to items.
568///
569/// This iterator advances by splitting off the head element and shortening the
570/// remaining tail.
571#[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            // SAFETY: self.ptr_mut() is guaranteed to return a pointer that is valid for MMIO and
582            // unique, as promised by the caller of `UniqueMmioPointer::new` and the slice is
583            // not empty.
584            let regs_head = NonNull::new(unsafe { &raw mut (*self.tail.ptr_mut())[0] }).unwrap();
585
586            // SAFETY: regs_head is created from self.tail so it is valid and within the range of
587            // the original pointer. There no other further split_child calls to the same child and
588            // self.tail is moved by one in the following lines.
589            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            // SAFETY: regs is created from self.tail so it is valid and within the range of the
598            // original pointer. The new pointer overwrites the original so it cannot be used
599            // afterwards, and there are no further calls to split_child().
600            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
613/// A shared pointer to the registers of some MMIO device.
614///
615/// It is guaranteed to be valid but unlike [`UniqueMmioPointer`] may not be unique.
616pub struct SharedMmioPointer<'a, T: ?Sized> {
617    regs: NonNull<T>,
618    phantom: PhantomData<&'a T>,
619}
620
621// Implement Debug, Eq and PartialEq manually rather than deriving to avoid an unneccessary bound on
622// T.
623
624impl<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    /// Creates a new `SharedMmioPointer` with the same lifetime as this one.
650    ///
651    /// This is used internally by the [`field_shared!`] macro and shouldn't be called directly.
652    ///
653    /// # Safety
654    ///
655    /// `regs` must be a properly aligned and valid pointer to some MMIO address space of type T,
656    /// within the allocation that `self` points to.
657    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    /// Returns a raw const pointer to the MMIO registers.
665    pub const fn ptr(&self) -> *const T {
666        self.regs.as_ptr()
667    }
668}
669
670// SAFETY: A `SharedMmioPointer` always originates either from a reference or from a
671// `UniqueMmioPointer`. The caller of `UniqueMmioPointer::new` promises that the MMIO registers can
672// be accessed from any thread.
673unsafe 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    /// Performs an MMIO read of the entire `T`.
692    pub fn read(&self) -> T {
693        // SAFETY: self.regs is always a valid and unique pointer to MMIO address space, and `T`
694        // being wrapped in `ReadPure` implies that it is safe to read from a shared reference
695        // because doing so has no side-effects.
696        unsafe { self.read_unsafe().0 }
697    }
698}
699
700impl<T: FromBytes + IntoBytes> SharedMmioPointer<'_, ReadPureWrite<T>> {
701    /// Performs an MMIO read of the entire `T`.
702    pub fn read(&self) -> T {
703        // SAFETY: self.regs is always a valid pointer to MMIO address space, and `T`
704        // being wrapped in `ReadPureWrite` implies that it is safe to read from a shared reference
705        // because doing so has no side-effects.
706        unsafe { self.read_unsafe().0 }
707    }
708}
709
710impl<'a, T> SharedMmioPointer<'a, [T]> {
711    /// Splits a `UniqueMmioPointer` to a slice into an array of `UniqueMmioPointer`s, taking only
712    /// the `chosen` indices.
713    ///
714    /// Panics if `chosen` contains the same index more than once, or any index out of bounds.
715    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                // SAFETY: self.regs is always unique and valid for MMIO access. We checked that
724                // `chosen` doesn't contain duplicates so the pointers we split it into don't
725                // overlap, so the same applies to each of them.
726                regs: NonNull::new(unsafe { &raw mut (*self.regs.as_ptr())[chosen_index] })
727                    .unwrap(),
728                phantom: PhantomData,
729            })
730        })
731    }
732
733    /// Returns a `SharedMmioPointer` to an element of this slice, or `None` if the index is out of
734    /// bounds.
735    pub const fn get(&self, index: usize) -> Option<SharedMmioPointer<'a, T>> {
736        if index >= self.len() {
737            return None;
738        }
739        // SAFETY: self.regs is always unique and valid for MMIO access.
740        let regs = NonNull::new(unsafe { &raw mut (*self.regs.as_ptr())[index] }).unwrap();
741        // SAFETY: We created regs from the raw slice in self.regs, so it must also be valid, unique
742        // and within the allocation of self.regs.
743        Some(unsafe { self.child(regs) })
744    }
745
746    /// Returns a `SharedMmioPointer` to a range of elements of this slice, or `None` if the range
747    /// is out of bounds.
748    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            // SAFETY: self.ptr_mut() is guaranteed to return a pointer that is valid for MMIO and
755            // unique, as promised by the caller of `UniqueMmioPointer::new`. range.start is within the
756            // boundaries of the slice.
757            unsafe { &raw mut (*self.regs.as_ptr())[range.start] }
758        } else {
759            // Based on the documentation of core::slice::from_raw_parts_mut, NonNull::dangling()
760            // should be used for creating zero-length slices.
761            NonNull::dangling().as_ptr()
762        };
763
764        let regs = NonNull::new(slice_from_raw_parts_mut(regs_start, range.len())).unwrap();
765
766        // SAFETY: We created regs from the valid start address of regs_start and `range` is within
767        // the boundaries of self.regs, so it must also be valid, unique and within the allocation
768        // of self.regs.
769        Some(unsafe { self.child(regs) })
770    }
771
772    /// Returns a new iterator of the items of the slice.
773    pub fn iter(&self) -> SharedMmioPointerIterator<'_, T> {
774        SharedMmioPointerIterator { tail: *self }
775    }
776
777    /// Returns the length of the slice.
778    pub const fn len(&self) -> usize {
779        self.regs.len()
780    }
781
782    /// Returns whether the slice is empty.
783    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    /// Splits a `SharedMmioPointer` to an array into an array of `SharedMmioPointer`s.
790    pub fn split(self) -> [SharedMmioPointer<'a, T>; LEN] {
791        array::from_fn(|i| SharedMmioPointer {
792            // SAFETY: self.regs is always unique and valid for MMIO access. We make sure the
793            // pointers we split it into don't overlap, so the same applies to each of them.
794            regs: NonNull::new(unsafe { &raw mut (*self.regs.as_ptr())[i] }).unwrap(),
795            phantom: PhantomData,
796        })
797    }
798
799    /// Converts this array pointer to an equivalent slice pointer.
800    pub const fn as_slice(&self) -> SharedMmioPointer<'a, [T]> {
801        let regs = NonNull::new(self.regs.as_ptr()).unwrap();
802        // SAFETY: We created regs from the raw array in self.regs, so it must also be valid, unique
803        // and within the allocation of self.regs.
804        unsafe { self.child(regs) }
805    }
806
807    /// Returns a `SharedMmioPointer` to an element of this array, or `None` if the index is out of
808    /// bounds.
809    pub const fn get(&self, index: usize) -> Option<SharedMmioPointer<'a, T>> {
810        if index >= LEN {
811            return None;
812        }
813        // SAFETY: self.regs is always unique and valid for MMIO access.
814        let regs = NonNull::new(unsafe { &raw mut (*self.regs.as_ptr())[index] }).unwrap();
815        // SAFETY: We created regs from the raw array in self.regs, so it must also be valid, unique
816        // and within the allocation of self.regs.
817        Some(unsafe { self.child(regs) })
818    }
819
820    /// Returns a `SharedMmioPointer` to a range of elements of this array, or `None` if the range
821    /// is out of bounds.
822    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            // SAFETY: self.regs is always unique and valid for MMIO access. range.start is within the
829            // boundaries of the slice.
830            unsafe { &raw mut (*self.regs.as_ptr())[range.start] }
831        } else {
832            // Based on the documentation of core::slice::from_raw_parts_mut, NonNull::dangling()
833            // should be used for creating zero-length slices.
834            NonNull::dangling().as_ptr()
835        };
836
837        let regs = NonNull::new(slice_from_raw_parts_mut(regs_start, range.len())).unwrap();
838
839        // SAFETY: We created regs from the valid start address of regs_start and `range` is within
840        // the boundaries of self.regs, so it must also be valid, unique and within the allocation
841        // of self.regs.
842        Some(unsafe { self.child(regs) })
843    }
844
845    /// Returns a new iterator of the items of the array.
846    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/// Iterator over a `SharedMmioPointer` slice, yielding pointers to items.
905///
906/// This iterator advances by creating a head pointer and shortening the
907/// remaining tail.
908#[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            // SAFETY: self.ptr_mut() is guaranteed to return a pointer that is valid for MMIO and
919            // unique, as promised by the caller of `UniqueMmioPointer::new` and the slice is
920            // not empty.
921            let regs_head =
922                NonNull::new(unsafe { &raw mut (*self.tail.regs.as_ptr())[0] }).unwrap();
923
924            // SAFETY: regs_head is created from self.tail so it is valid and within the range of
925            // the original pointer.
926            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            // SAFETY: We created regs from the raw array in self.regs, so it must also be valid,
935            // unique and within the allocation of self.regs.
936            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    /// Performs an MMIO read and returns the value.
951    ///
952    /// If `T` is exactly 1, 2, 4 or 8 bytes long and naturally aligned then this will be a single
953    /// operation. Otherwise it will be split into several, reading chunks as large as possible.
954    ///
955    /// Note that this takes `&mut self` rather than `&self` because an MMIO read may cause
956    /// side-effects that change the state of the device.
957    ///
958    /// # Safety
959    ///
960    /// This field must be safe to perform an MMIO read from.
961    pub unsafe fn read_unsafe(&mut self) -> T {
962        // SAFETY: self.regs is always a valid and unique pointer to MMIO address space.
963        unsafe { Ops::read(self.regs) }
964    }
965}
966
967impl<T: Immutable + IntoBytes> UniqueMmioPointer<'_, T> {
968    /// Performs an MMIO write of the given value.
969    ///
970    /// If `T` is exactly 1, 2, 4 or 8 bytes long and naturally aligned then this will be a single
971    /// operation. Otherwise it will be split into several, reading chunks as large as possible.
972    ///
973    /// # Safety
974    ///
975    /// This field must be safe to perform an MMIO write to.
976    pub unsafe fn write_unsafe(&mut self, value: T) {
977        // SAFETY: self.regs is always a valid and unique pointer to MMIO address space.
978        unsafe {
979            Ops::write(self.regs, value);
980        }
981    }
982}
983
984impl<T: FromBytes + IntoBytes> SharedMmioPointer<'_, T> {
985    /// Performs an MMIO read and returns the value.
986    ///
987    /// If `T` is exactly 1, 2, 4 or 8 bytes long and naturally aligned then this will be a single
988    /// operation. Otherwise it will be split into several, reading chunks as large as possible.
989    ///
990    /// # Safety
991    ///
992    /// This field must be safe to perform an MMIO read from, and doing so must not cause any
993    /// side-effects.
994    pub unsafe fn read_unsafe(&self) -> T {
995        // SAFETY: self.regs is always a valid and unique pointer to MMIO address space.
996        unsafe { Ops::read(self.regs) }
997    }
998}
999
1000/// Gets a `UniqueMmioPointer` to a field of a type wrapped in a `UniqueMmioPointer`.
1001#[macro_export]
1002macro_rules! field {
1003    ($mmio_pointer:expr, $field:ident) => {{
1004        _ = &mut $mmio_pointer;
1005
1006        // SAFETY: ptr_mut is guaranteed to return a valid pointer for MMIO, so the pointer to the
1007        // field must also be valid. UniqueMmioPointer::child gives it the same lifetime as the
1008        // original pointer.
1009        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/// Gets `UniqueMmioPointer`s to several fields of a type wrapped in a `UniqueMmioPointer`.
1020///
1021/// # Safety
1022///
1023/// The same field name must not be passed more than once.
1024#[macro_export]
1025macro_rules! split_fields {
1026    ($mmio_pointer:expr, $( $field:ident ),+) => {{
1027        // Make sure $mmio_pointer is the right type, and take ownership of it.
1028        let mut mmio_pointer: $crate::UniqueMmioPointer<_> = $mmio_pointer;
1029        let pointer = mmio_pointer.ptr_mut();
1030        let ret = (
1031            $(
1032                // SAFETY: ptr_mut is guaranteed to return a valid pointer for MMIO, so the pointer
1033                // to the field must also be valid. MmioPointer::child gives it the same lifetime as
1034                // the original pointer, and the caller of `split_fields!` promised not to pass the
1035                // same field more than once.
1036                {
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/// Gets a `SharedMmioPointer` to a field of a type wrapped in a `SharedMmioPointer`.
1047#[macro_export]
1048macro_rules! field_shared {
1049    ($mmio_pointer:expr, $field:ident) => {{
1050        _ = &$mmio_pointer;
1051
1052        // SAFETY: ptr_mut is guaranteed to return a valid pointer for MMIO, so the pointer to the
1053        // field must also be valid. MmioPointer::child gives it the same lifetime as the original
1054        // pointer.
1055        #[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        // SAFETY: 'u' is safe to read or write because it's just a fake.
1168        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        // Test that lifetime of pointer returned from `get` isn't tied to the lifetime of the slice
1236        // pointer.
1237        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                // SAFETY: `Regs` is repr(transparent) so a reference to its field has the same
1271                // metadata as a reference to `Regs``.
1272                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        // SAFETY: We don't pass the same field name more than once.
1301        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(&regs);
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(&regs);
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(&regs);
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(&regs);
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    /// 15 bytes = 8 + 4 + 2 + 1, exercises all chunk-size paths in read_slice/write_slice.
1578    #[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    /// 8-aligned buffer large enough to place an `A` (15 bytes) at any byte offset 0..8.
1585    #[repr(C, align(8))]
1586    struct AlignedBuf([u8; 32]);
1587
1588    /// Write `A_VAL` to offset `offset` within an 8-aligned buffer, read it back, and verify.
1589    /// Different offsets exercise different ramp-up/ramp-down patterns in write_slice/read_slice.
1590    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        // SAFETY: offset + 15 <= 32 (asserted above), and base is valid for 32 bytes.
1596        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        // SAFETY: ptr points into our local buffer, which is valid and unique.
1601        let mut mmio = unsafe { UniqueMmioPointer::new(ptr) };
1602
1603        // SAFETY: writing to and reading from our buffer is safe.
1604        unsafe { mmio.write_unsafe(A_VAL) };
1605        // SAFETY: writing to and reading from our buffer is safe.
1606        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        // 8-aligned: chunks 8 + 4 + 2 + 1
1613        round_trip_at_offset(0);
1614    }
1615
1616    #[test]
1617    fn unique_read_write_aligned_1() {
1618        // offset 1: ramp-up 1 byte, then 8 + 4 + 2
1619        round_trip_at_offset(1);
1620    }
1621
1622    #[test]
1623    fn unique_read_write_aligned_2() {
1624        // offset 2: ramp-up 2 bytes, then 8 + 4 + 1
1625        round_trip_at_offset(2);
1626    }
1627
1628    #[test]
1629    fn unique_read_write_aligned_3() {
1630        // offset 3: ramp-up 1 + 2 + 4 bytes, then 8
1631        round_trip_at_offset(3);
1632    }
1633
1634    #[test]
1635    fn unique_read_write_aligned_4() {
1636        // offset 4: ramp-up 4 bytes, then 8 + 2 + 1
1637        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}