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
11#[cfg(target_arch = "aarch64")]
12mod aarch64_mmio;
13pub mod fields;
14mod physical;
15#[cfg(not(target_arch = "aarch64"))]
16mod volatile_mmio;
17
18use crate::fields::{ReadOnly, ReadPure, ReadPureWrite, ReadWrite, WriteOnly};
19use core::{array, fmt::Debug, marker::PhantomData, ops::Deref, ptr, ptr::NonNull};
20pub use physical::PhysicalInstance;
21use zerocopy::{FromBytes, Immutable, IntoBytes};
22
23/// A unique owned pointer to the registers of some MMIO device.
24///
25/// It is guaranteed to be valid and unique; no other access to the MMIO space of the device may
26/// happen for the lifetime `'a`.
27///
28/// A `UniqueMmioPointer` may be created from a mutable reference, but this should only be used for
29/// testing purposes, as references should never be constructed for real MMIO address space.
30pub struct UniqueMmioPointer<'a, T: ?Sized>(SharedMmioPointer<'a, T>);
31
32// Implement Debug, Eq and PartialEq manually rather than deriving to avoid an unneccessary bound on
33// T.
34
35impl<T: ?Sized> Debug for UniqueMmioPointer<'_, T> {
36    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
37        f.debug_tuple("UniqueMmioPointer")
38            .field(&self.0.regs)
39            .finish()
40    }
41}
42
43impl<T: ?Sized> PartialEq for UniqueMmioPointer<'_, T> {
44    fn eq(&self, other: &Self) -> bool {
45        self.0 == other.0
46    }
47}
48
49impl<T: ?Sized> Eq for UniqueMmioPointer<'_, T> {}
50
51impl<T: ?Sized> UniqueMmioPointer<'_, T> {
52    /// Creates a new `UniqueMmioPointer` from a non-null raw pointer.
53    ///
54    /// # Safety
55    ///
56    /// `regs` must be a properly aligned and valid pointer to some MMIO address space of type T,
57    /// which is mapped as device memory and valid to read and write from any thread with volatile
58    /// operations. There must not be any other aliases which are used to access the same MMIO
59    /// region while this `UniqueMmioPointer` exists.
60    ///
61    /// If `T` contains any fields wrapped in [`ReadOnly`], [`WriteOnly`] or [`ReadWrite`] then they
62    /// must indeed be safe to perform MMIO reads or writes on.
63    pub const unsafe fn new(regs: NonNull<T>) -> Self {
64        Self(SharedMmioPointer {
65            regs,
66            phantom: PhantomData,
67        })
68    }
69
70    /// Creates a new `UniqueMmioPointer` with the same lifetime as this one.
71    ///
72    /// This is used internally by the [`field!`] macro and shouldn't be called directly.
73    ///
74    /// # Safety
75    ///
76    /// `regs` must be a properly aligned and valid pointer to some MMIO address space of type T,
77    /// within the allocation that `self` points to.
78    pub const unsafe fn child<U: ?Sized>(&mut self, regs: NonNull<U>) -> UniqueMmioPointer<'_, U> {
79        UniqueMmioPointer(SharedMmioPointer {
80            regs,
81            phantom: PhantomData,
82        })
83    }
84
85    /// Returns a raw mut pointer to the MMIO registers.
86    pub const fn ptr_mut(&mut self) -> *mut T {
87        self.0.regs.as_ptr()
88    }
89
90    /// Returns a `NonNull<T>` pointer to the MMIO registers.
91    pub const fn ptr_nonnull(&mut self) -> NonNull<T> {
92        self.0.regs
93    }
94
95    /// Returns a new `UniqueMmioPointer` with a lifetime no greater than this one.
96    pub const fn reborrow(&mut self) -> UniqueMmioPointer<'_, T> {
97        let ptr = self.ptr_nonnull();
98        // SAFETY: `ptr` must be properly aligned and valid and within our allocation because it is
99        // exactly our allocation.
100        unsafe { self.child(ptr) }
101    }
102}
103
104impl<'a, T: ?Sized> UniqueMmioPointer<'a, T> {
105    /// Creates a new `UniqueMmioPointer` with the same lifetime as this one, but not tied to the
106    /// lifetime this one is borrowed for.
107    ///
108    /// This is used internally by the [`split_fields!`] macro and shouldn't be called directly.
109    ///
110    /// # Safety
111    ///
112    /// `regs` must be a properly aligned and valid pointer to some MMIO address space of type T,
113    /// within the allocation that `self` points to. `split_child` must not be called for the same
114    /// child field more than once, and the original `UniqueMmioPointer` must not be used after
115    /// `split_child` has been called for one or more of its fields.
116    pub const unsafe fn split_child<U: ?Sized>(
117        &mut self,
118        regs: NonNull<U>,
119    ) -> UniqueMmioPointer<'a, U> {
120        UniqueMmioPointer(SharedMmioPointer {
121            regs,
122            phantom: PhantomData,
123        })
124    }
125}
126
127impl<T: FromBytes + IntoBytes> UniqueMmioPointer<'_, ReadWrite<T>> {
128    /// Performs an MMIO read of the entire `T`.
129    pub fn read(&mut self) -> T {
130        // SAFETY: self.regs is always a valid and unique pointer to MMIO address space, and `T`
131        // being wrapped in `ReadWrite` implies that it is safe to read.
132        unsafe { self.read_unsafe().0 }
133    }
134}
135
136impl<T: Immutable + IntoBytes> UniqueMmioPointer<'_, ReadWrite<T>> {
137    /// Performs an MMIO write of the entire `T`.
138    pub fn write(&mut self, value: T) {
139        // SAFETY: self.regs is always a valid and unique pointer to MMIO address space, and `T`
140        // being wrapped in `ReadWrite` implies that it is safe to write.
141        unsafe {
142            self.write_unsafe(ReadWrite(value));
143        }
144    }
145}
146
147impl<T: Immutable + IntoBytes> UniqueMmioPointer<'_, ReadPureWrite<T>> {
148    /// Performs an MMIO write of the entire `T`.
149    pub fn write(&mut self, value: T) {
150        // SAFETY: self.regs is always a valid and unique pointer to MMIO address space, and `T`
151        // being wrapped in `ReadPureWrite` implies that it is safe to write.
152        unsafe {
153            self.write_unsafe(ReadPureWrite(value));
154        }
155    }
156}
157
158impl<T: FromBytes + IntoBytes> UniqueMmioPointer<'_, ReadOnly<T>> {
159    /// Performs an MMIO read of the entire `T`.
160    pub fn read(&mut self) -> T {
161        // SAFETY: self.regs is always a valid and unique pointer to MMIO address space, and `T`
162        // being wrapped in `ReadOnly` implies that it is safe to read.
163        unsafe { self.read_unsafe().0 }
164    }
165}
166
167impl<T: Immutable + IntoBytes> UniqueMmioPointer<'_, WriteOnly<T>> {
168    /// Performs an MMIO write of the entire `T`.
169    pub fn write(&mut self, value: T) {
170        // SAFETY: self.regs is always a valid and unique pointer to MMIO address space, and `T`
171        // being wrapped in `WriteOnly` implies that it is safe to write.
172        unsafe {
173            self.write_unsafe(WriteOnly(value));
174        }
175    }
176}
177
178impl<'a, T> UniqueMmioPointer<'a, [T]> {
179    /// Returns a `UniqueMmioPointer` to an element of this slice, or `None` if the index is out of
180    /// bounds.
181    ///
182    /// # Example
183    ///
184    /// ```
185    /// use safe_mmio::{UniqueMmioPointer, fields::ReadWrite};
186    ///
187    /// let mut slice: UniqueMmioPointer<[ReadWrite<u32>]>;
188    /// # let mut fake = [ReadWrite(1), ReadWrite(2), ReadWrite(3)];
189    /// # slice = UniqueMmioPointer::from(fake.as_mut_slice());
190    /// let mut element = slice.get(1).unwrap();
191    /// element.write(42);
192    /// ```
193    pub const fn get(&mut self, index: usize) -> Option<UniqueMmioPointer<'_, T>> {
194        if index >= self.0.len() {
195            return None;
196        }
197        // SAFETY: self.ptr_mut() is guaranteed to return a pointer that is valid for MMIO and
198        // unique, as promised by the caller of `UniqueMmioPointer::new`.
199        let regs = NonNull::new(unsafe { &raw mut (*self.ptr_mut())[index] }).unwrap();
200        // SAFETY: We created regs from the raw slice in self.regs, so it must also be valid, unique
201        // and within the allocation of self.regs.
202        Some(unsafe { self.child(regs) })
203    }
204
205    /// Returns a `UniqueMmioPointer` to an element of this slice, or `None` if the index is out of
206    /// bounds.
207    ///
208    /// Unlike [`UniqueMmioPointer::get`] this takes ownership of the original pointer. This is
209    /// useful when you want to store the resulting pointer without keeping the original pointer
210    /// around.
211    ///
212    /// # Example
213    ///
214    /// ```
215    /// use safe_mmio::{UniqueMmioPointer, fields::ReadWrite};
216    ///
217    /// let mut slice: UniqueMmioPointer<[ReadWrite<u32>]>;
218    /// # let mut fake = [ReadWrite(1), ReadWrite(2), ReadWrite(3)];
219    /// # slice = UniqueMmioPointer::from(fake.as_mut_slice());
220    /// let mut element = slice.take(1).unwrap();
221    /// element.write(42);
222    /// // `slice` can no longer be used at this point.
223    /// ```
224    pub const fn take(mut self, index: usize) -> Option<UniqueMmioPointer<'a, T>> {
225        if index >= self.0.len() {
226            return None;
227        }
228        // SAFETY: self.ptr_mut() is guaranteed to return a pointer that is valid for MMIO and
229        // unique, as promised by the caller of `UniqueMmioPointer::new`.
230        let regs = NonNull::new(unsafe { &raw mut (*self.ptr_mut())[index] }).unwrap();
231        // SAFETY: We created regs from the raw slice in self.regs, so it must also be valid, unique
232        // and within the allocation of self.regs. `self` is dropped immediately after this and we
233        // don't split out any other children.
234        Some(unsafe { self.split_child(regs) })
235    }
236}
237
238impl<'a, T, const LEN: usize> UniqueMmioPointer<'a, [T; LEN]> {
239    /// Splits a `UniqueMmioPointer` to an array into an array of `UniqueMmioPointer`s.
240    pub fn split(&mut self) -> [UniqueMmioPointer<'_, T>; LEN] {
241        array::from_fn(|i| {
242            UniqueMmioPointer(SharedMmioPointer {
243                // SAFETY: self.regs is always unique and valid for MMIO access. We make sure the
244                // pointers we split it into don't overlap, so the same applies to each of them.
245                regs: NonNull::new(unsafe { &raw mut (*self.ptr_mut())[i] }).unwrap(),
246                phantom: PhantomData,
247            })
248        })
249    }
250
251    /// Splits a `UniqueMmioPointer` to an array into an array of `UniqueMmioPointer`s, taking only
252    /// the `chosen` indices.
253    ///
254    /// Panics if `chosen` contains the same index more than once, or any index out of bounds.
255    pub fn split_some<const N: usize>(
256        mut self,
257        chosen: [usize; N],
258    ) -> [UniqueMmioPointer<'a, T>; N] {
259        for (i, a) in chosen.iter().enumerate() {
260            for (j, b) in chosen.iter().enumerate() {
261                assert!(i == j || a != b, "chosen array must not contain duplicates");
262            }
263        }
264        chosen.map(|chosen_index| {
265            UniqueMmioPointer(SharedMmioPointer {
266                // SAFETY: self.regs is always unique and valid for MMIO access. We checked that
267                // `chosen` doesn't contain duplicates so the pointers we split it into don't
268                // overlap, so the same applies to each of them.
269                regs: NonNull::new(unsafe { &raw mut (*self.ptr_mut())[chosen_index] }).unwrap(),
270                phantom: PhantomData,
271            })
272        })
273    }
274
275    /// Converts this array pointer to an equivalent slice pointer.
276    pub const fn as_mut_slice(&mut self) -> UniqueMmioPointer<'_, [T]> {
277        let regs = NonNull::new(self.ptr_mut()).unwrap();
278        // SAFETY: We created regs from the raw array in self.regs, so it must also be valid, unique
279        // and within the allocation of self.regs.
280        unsafe { self.child(regs) }
281    }
282
283    /// Returns a `UniqueMmioPointer` to an element of this array, or `None` if the index is out of
284    /// bounds.
285    ///
286    /// # Example
287    ///
288    /// ```
289    /// use safe_mmio::{UniqueMmioPointer, fields::ReadWrite};
290    ///
291    /// let mut slice: UniqueMmioPointer<[ReadWrite<u32>; 3]>;
292    /// # let mut fake = [ReadWrite(1), ReadWrite(2), ReadWrite(3)];
293    /// # slice = UniqueMmioPointer::from(&mut fake);
294    /// let mut element = slice.get(1).unwrap();
295    /// element.write(42);
296    /// slice.get(2).unwrap().write(100);
297    /// ```
298    pub const fn get(&mut self, index: usize) -> Option<UniqueMmioPointer<'_, T>> {
299        if index >= LEN {
300            return None;
301        }
302        // SAFETY: self.ptr_mut() is guaranteed to return a pointer that is valid for MMIO and
303        // unique, as promised by the caller of `UniqueMmioPointer::new`.
304        let regs = NonNull::new(unsafe { &raw mut (*self.ptr_mut())[index] }).unwrap();
305        // SAFETY: We created regs from the raw array in self.regs, so it must also be valid, unique
306        // and within the allocation of self.regs.
307        Some(unsafe { self.child(regs) })
308    }
309
310    /// Returns a `UniqueMmioPointer` to an element of this array, or `None` if the index is out of
311    /// bounds.
312    ///
313    /// Unlike [`UniqueMmioPointer::get`] this takes ownership of the original pointer. This is
314    /// useful when you want to store the resulting pointer without keeping the original pointer
315    /// around.
316    ///
317    /// # Example
318    ///
319    /// ```
320    /// use safe_mmio::{UniqueMmioPointer, fields::ReadWrite};
321    ///
322    /// let mut array: UniqueMmioPointer<[ReadWrite<u32>; 3]>;
323    /// # let mut fake = [ReadWrite(1), ReadWrite(2), ReadWrite(3)];
324    /// # array = UniqueMmioPointer::from(&mut fake);
325    /// let mut element = array.take(1).unwrap();
326    /// element.write(42);
327    /// // `array` can no longer be used at this point.
328    /// ```
329    pub const fn take(mut self, index: usize) -> Option<UniqueMmioPointer<'a, T>> {
330        if index >= LEN {
331            return None;
332        }
333        // SAFETY: self.ptr_mut() is guaranteed to return a pointer that is valid for MMIO and
334        // unique, as promised by the caller of `UniqueMmioPointer::new`.
335        let regs = NonNull::new(unsafe { &raw mut (*self.ptr_mut())[index] }).unwrap();
336        // SAFETY: We created regs from the raw array in self.regs, so it must also be valid, unique
337        // and within the allocation of self.regs. `self` is dropped immediately after this and we
338        // don't split out any other children.
339        Some(unsafe { self.split_child(regs) })
340    }
341}
342
343impl<'a, T, const LEN: usize> From<UniqueMmioPointer<'a, [T; LEN]>> for UniqueMmioPointer<'a, [T]> {
344    fn from(mut value: UniqueMmioPointer<'a, [T; LEN]>) -> Self {
345        let regs = NonNull::new(value.ptr_mut()).unwrap();
346        // SAFETY: regs comes from a UniqueMmioPointer so already satisfies all the safety
347        // requirements.
348        unsafe { UniqueMmioPointer::new(regs) }
349    }
350}
351
352impl<'a, T> From<UniqueMmioPointer<'a, T>> for UniqueMmioPointer<'a, [T; 1]> {
353    fn from(mut value: UniqueMmioPointer<'a, T>) -> Self {
354        let regs = NonNull::new(value.ptr_mut()).unwrap().cast();
355        // SAFETY: regs comes from a UniqueMmioPointer so already satisfies all the safety
356        // requirements.
357        unsafe { UniqueMmioPointer::new(regs) }
358    }
359}
360
361impl<'a, T> From<UniqueMmioPointer<'a, T>> for UniqueMmioPointer<'a, [T]> {
362    fn from(mut value: UniqueMmioPointer<'a, T>) -> Self {
363        let array: *mut [T; 1] = value.ptr_mut().cast();
364        let regs = NonNull::new(array).unwrap();
365        // SAFETY: regs comes from a UniqueMmioPointer so already satisfies all the safety
366        // requirements.
367        unsafe { UniqueMmioPointer::new(regs) }
368    }
369}
370
371impl<'a, T, const LEN: usize> From<UniqueMmioPointer<'a, [T; LEN]>>
372    for [UniqueMmioPointer<'a, T>; LEN]
373{
374    fn from(mut value: UniqueMmioPointer<'a, [T; LEN]>) -> Self {
375        array::from_fn(|i| {
376            let item_pointer = value.get(i).unwrap().ptr_mut();
377            // SAFETY: `split_child` is called only once on each item and the original
378            // `UniqueMmioPointer` is consumed by this function.
379            unsafe { value.split_child(core::ptr::NonNull::new(item_pointer).unwrap()) }
380        })
381    }
382}
383
384impl<'a, T: ?Sized> From<&'a mut T> for UniqueMmioPointer<'a, T> {
385    fn from(r: &'a mut T) -> Self {
386        Self(SharedMmioPointer {
387            regs: r.into(),
388            phantom: PhantomData,
389        })
390    }
391}
392
393impl<'a, T: ?Sized> Deref for UniqueMmioPointer<'a, T> {
394    type Target = SharedMmioPointer<'a, T>;
395
396    fn deref(&self) -> &Self::Target {
397        &self.0
398    }
399}
400
401/// A shared pointer to the registers of some MMIO device.
402///
403/// It is guaranteed to be valid but unlike [`UniqueMmioPointer`] may not be unique.
404pub struct SharedMmioPointer<'a, T: ?Sized> {
405    regs: NonNull<T>,
406    phantom: PhantomData<&'a T>,
407}
408
409// Implement Debug, Eq and PartialEq manually rather than deriving to avoid an unneccessary bound on
410// T.
411
412impl<T: ?Sized> Debug for SharedMmioPointer<'_, T> {
413    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
414        f.debug_tuple("SharedMmioPointer")
415            .field(&self.regs)
416            .finish()
417    }
418}
419
420impl<T: ?Sized> PartialEq for SharedMmioPointer<'_, T> {
421    fn eq(&self, other: &Self) -> bool {
422        ptr::eq(self.regs.as_ptr(), other.regs.as_ptr())
423    }
424}
425
426impl<T: ?Sized> Eq for SharedMmioPointer<'_, T> {}
427
428impl<T: ?Sized> Clone for SharedMmioPointer<'_, T> {
429    fn clone(&self) -> Self {
430        *self
431    }
432}
433
434impl<T: ?Sized> Copy for SharedMmioPointer<'_, T> {}
435
436impl<'a, T: ?Sized> SharedMmioPointer<'a, T> {
437    /// Creates a new `SharedMmioPointer` with the same lifetime as this one.
438    ///
439    /// This is used internally by the [`field_shared!`] macro and shouldn't be called directly.
440    ///
441    /// # Safety
442    ///
443    /// `regs` must be a properly aligned and valid pointer to some MMIO address space of type T,
444    /// within the allocation that `self` points to.
445    pub const unsafe fn child<U: ?Sized>(&self, regs: NonNull<U>) -> SharedMmioPointer<'a, U> {
446        SharedMmioPointer {
447            regs,
448            phantom: PhantomData,
449        }
450    }
451
452    /// Returns a raw const pointer to the MMIO registers.
453    pub const fn ptr(&self) -> *const T {
454        self.regs.as_ptr()
455    }
456}
457
458// SAFETY: A `SharedMmioPointer` always originates either from a reference or from a
459// `UniqueMmioPointer`. The caller of `UniqueMmioPointer::new` promises that the MMIO registers can
460// be accessed from any thread.
461unsafe impl<T: ?Sized + Send + Sync> Send for SharedMmioPointer<'_, T> {}
462
463impl<'a, T: ?Sized> From<&'a T> for SharedMmioPointer<'a, T> {
464    fn from(r: &'a T) -> Self {
465        Self {
466            regs: r.into(),
467            phantom: PhantomData,
468        }
469    }
470}
471
472impl<'a, T: ?Sized> From<UniqueMmioPointer<'a, T>> for SharedMmioPointer<'a, T> {
473    fn from(unique: UniqueMmioPointer<'a, T>) -> Self {
474        unique.0
475    }
476}
477
478impl<T: FromBytes + IntoBytes> SharedMmioPointer<'_, ReadPure<T>> {
479    /// Performs an MMIO read of the entire `T`.
480    pub fn read(&self) -> T {
481        // SAFETY: self.regs is always a valid and unique pointer to MMIO address space, and `T`
482        // being wrapped in `ReadPure` implies that it is safe to read from a shared reference
483        // because doing so has no side-effects.
484        unsafe { self.read_unsafe().0 }
485    }
486}
487
488impl<T: FromBytes + IntoBytes> SharedMmioPointer<'_, ReadPureWrite<T>> {
489    /// Performs an MMIO read of the entire `T`.
490    pub fn read(&self) -> T {
491        // SAFETY: self.regs is always a valid pointer to MMIO address space, and `T`
492        // being wrapped in `ReadPureWrite` implies that it is safe to read from a shared reference
493        // because doing so has no side-effects.
494        unsafe { self.read_unsafe().0 }
495    }
496}
497
498impl<'a, T> SharedMmioPointer<'a, [T]> {
499    /// Splits a `UniqueMmioPointer` to a slice into an array of `UniqueMmioPointer`s, taking only
500    /// the `chosen` indices.
501    ///
502    /// Panics if `chosen` contains the same index more than once, or any index out of bounds.
503    pub fn split_some<const N: usize>(self, chosen: [usize; N]) -> [UniqueMmioPointer<'a, T>; N] {
504        for (i, a) in chosen.iter().enumerate() {
505            for (j, b) in chosen.iter().enumerate() {
506                assert!(i == j || a != b, "chosen array must not contain duplicates");
507            }
508        }
509        chosen.map(|chosen_index| {
510            UniqueMmioPointer(SharedMmioPointer {
511                // SAFETY: self.regs is always unique and valid for MMIO access. We checked that
512                // `chosen` doesn't contain duplicates so the pointers we split it into don't
513                // overlap, so the same applies to each of them.
514                regs: NonNull::new(unsafe { &raw mut (*self.regs.as_ptr())[chosen_index] })
515                    .unwrap(),
516                phantom: PhantomData,
517            })
518        })
519    }
520
521    /// Returns a `SharedMmioPointer` to an element of this slice, or `None` if the index is out of
522    /// bounds.
523    pub const fn get(&self, index: usize) -> Option<SharedMmioPointer<'a, T>> {
524        if index >= self.len() {
525            return None;
526        }
527        // SAFETY: self.regs is always unique and valid for MMIO access.
528        let regs = NonNull::new(unsafe { &raw mut (*self.regs.as_ptr())[index] }).unwrap();
529        // SAFETY: We created regs from the raw slice in self.regs, so it must also be valid, unique
530        // and within the allocation of self.regs.
531        Some(unsafe { self.child(regs) })
532    }
533
534    /// Returns the length of the slice.
535    pub const fn len(&self) -> usize {
536        self.regs.len()
537    }
538
539    /// Returns whether the slice is empty.
540    pub const fn is_empty(&self) -> bool {
541        self.regs.is_empty()
542    }
543}
544
545impl<'a, T, const LEN: usize> SharedMmioPointer<'a, [T; LEN]> {
546    /// Splits a `SharedMmioPointer` to an array into an array of `SharedMmioPointer`s.
547    pub fn split(&self) -> [SharedMmioPointer<'a, T>; LEN] {
548        array::from_fn(|i| SharedMmioPointer {
549            // SAFETY: self.regs is always unique and valid for MMIO access. We make sure the
550            // pointers we split it into don't overlap, so the same applies to each of them.
551            regs: NonNull::new(unsafe { &raw mut (*self.regs.as_ptr())[i] }).unwrap(),
552            phantom: PhantomData,
553        })
554    }
555
556    /// Converts this array pointer to an equivalent slice pointer.
557    pub const fn as_slice(&self) -> SharedMmioPointer<'a, [T]> {
558        let regs = NonNull::new(self.regs.as_ptr()).unwrap();
559        // SAFETY: We created regs from the raw array in self.regs, so it must also be valid, unique
560        // and within the allocation of self.regs.
561        unsafe { self.child(regs) }
562    }
563
564    /// Returns a `SharedMmioPointer` to an element of this array, or `None` if the index is out of
565    /// bounds.
566    pub const fn get(&self, index: usize) -> Option<SharedMmioPointer<'a, T>> {
567        if index >= LEN {
568            return None;
569        }
570        // SAFETY: self.regs is always unique and valid for MMIO access.
571        let regs = NonNull::new(unsafe { &raw mut (*self.regs.as_ptr())[index] }).unwrap();
572        // SAFETY: We created regs from the raw array in self.regs, so it must also be valid, unique
573        // and within the allocation of self.regs.
574        Some(unsafe { self.child(regs) })
575    }
576}
577
578impl<'a, T, const LEN: usize> From<SharedMmioPointer<'a, [T; LEN]>> for SharedMmioPointer<'a, [T]> {
579    fn from(value: SharedMmioPointer<'a, [T; LEN]>) -> Self {
580        let regs = NonNull::new(value.regs.as_ptr()).unwrap();
581        SharedMmioPointer {
582            regs,
583            phantom: PhantomData,
584        }
585    }
586}
587
588impl<'a, T> From<SharedMmioPointer<'a, T>> for SharedMmioPointer<'a, [T; 1]> {
589    fn from(value: SharedMmioPointer<'a, T>) -> Self {
590        let regs = NonNull::new(value.regs.as_ptr()).unwrap().cast();
591        SharedMmioPointer {
592            regs,
593            phantom: PhantomData,
594        }
595    }
596}
597
598impl<'a, T> From<SharedMmioPointer<'a, T>> for SharedMmioPointer<'a, [T]> {
599    fn from(value: SharedMmioPointer<'a, T>) -> Self {
600        let array: *mut [T; 1] = value.regs.as_ptr().cast();
601        let regs = NonNull::new(array).unwrap();
602        SharedMmioPointer {
603            regs,
604            phantom: PhantomData,
605        }
606    }
607}
608
609/// Gets a `UniqueMmioPointer` to a field of a type wrapped in a `UniqueMmioPointer`.
610#[macro_export]
611macro_rules! field {
612    ($mmio_pointer:expr, $field:ident) => {{
613        // Make sure $mmio_pointer is the right type.
614        let mmio_pointer: &mut $crate::UniqueMmioPointer<_> = &mut $mmio_pointer;
615        // SAFETY: ptr_mut is guaranteed to return a valid pointer for MMIO, so the pointer to the
616        // field must also be valid. MmioPointer::child gives it the same lifetime as the original
617        // pointer.
618        unsafe {
619            let child_pointer =
620                core::ptr::NonNull::new(&raw mut (*mmio_pointer.ptr_mut()).$field).unwrap();
621            mmio_pointer.child(child_pointer)
622        }
623    }};
624}
625
626/// Gets `UniqueMmioPointer`s to several fields of a type wrapped in a `UniqueMmioPointer`.
627///
628/// # Safety
629///
630/// The same field name must not be passed more than once.
631#[macro_export]
632macro_rules! split_fields {
633    ($mmio_pointer:expr, $( $field:ident ),+) => {{
634        // Make sure $mmio_pointer is the right type, and take ownership of it.
635        let mut mmio_pointer: $crate::UniqueMmioPointer<_> = $mmio_pointer;
636        let pointer = mmio_pointer.ptr_mut();
637        let ret = (
638            $(
639                // SAFETY: ptr_mut is guaranteed to return a valid pointer for MMIO, so the pointer
640                // to the field must also be valid. MmioPointer::child gives it the same lifetime as
641                // the original pointer, and the caller of `split_fields!` promised not to pass the
642                // same field more than once.
643                {
644                    let child_pointer = core::ptr::NonNull::new(&raw mut (*pointer).$field).unwrap();
645                    mmio_pointer.split_child(child_pointer)
646                }
647            ),+
648        );
649        ret
650    }};
651}
652
653/// Gets a `SharedMmioPointer` to a field of a type wrapped in a `SharedMmioPointer`.
654#[macro_export]
655macro_rules! field_shared {
656    ($mmio_pointer:expr, $field:ident) => {{
657        // Make sure $mmio_pointer is the right type.
658        let mmio_pointer: &$crate::SharedMmioPointer<_> = &$mmio_pointer;
659        // SAFETY: ptr_mut is guaranteed to return a valid pointer for MMIO, so the pointer to the
660        // field must also be valid. MmioPointer::child gives it the same lifetime as the original
661        // pointer.
662        unsafe {
663            let child_pointer =
664                core::ptr::NonNull::new((&raw const (*mmio_pointer.ptr()).$field).cast_mut())
665                    .unwrap();
666            mmio_pointer.child(child_pointer)
667        }
668    }};
669}
670
671#[cfg(test)]
672mod tests {
673    use super::*;
674
675    #[test]
676    fn fields() {
677        #[repr(C)]
678        struct Foo {
679            a: ReadWrite<u32>,
680            b: ReadOnly<u32>,
681            c: ReadPure<u32>,
682        }
683
684        let mut foo = Foo {
685            a: ReadWrite(1),
686            b: ReadOnly(2),
687            c: ReadPure(3),
688        };
689        let mut owned: UniqueMmioPointer<Foo> = UniqueMmioPointer::from(&mut foo);
690
691        let mut owned_a: UniqueMmioPointer<ReadWrite<u32>> = field!(owned, a);
692        assert_eq!(owned_a.read(), 1);
693        owned_a.write(42);
694        assert_eq!(owned_a.read(), 42);
695        field!(owned, a).write(44);
696        assert_eq!(field!(owned, a).read(), 44);
697
698        let mut owned_b: UniqueMmioPointer<ReadOnly<u32>> = field!(owned, b);
699        assert_eq!(owned_b.read(), 2);
700
701        let owned_c: UniqueMmioPointer<ReadPure<u32>> = field!(owned, c);
702        assert_eq!(owned_c.read(), 3);
703        assert_eq!(field!(owned, c).read(), 3);
704    }
705
706    #[test]
707    fn shared_fields() {
708        #[repr(C)]
709        struct Foo {
710            a: ReadPureWrite<u32>,
711            b: ReadPure<u32>,
712        }
713
714        let foo = Foo {
715            a: ReadPureWrite(1),
716            b: ReadPure(2),
717        };
718        let shared: SharedMmioPointer<Foo> = SharedMmioPointer::from(&foo);
719
720        let shared_a: SharedMmioPointer<ReadPureWrite<u32>> = field_shared!(shared, a);
721        assert_eq!(shared_a.read(), 1);
722        assert_eq!(field_shared!(shared, a).read(), 1);
723
724        let shared_b: SharedMmioPointer<ReadPure<u32>> = field_shared!(shared, b);
725        assert_eq!(shared_b.read(), 2);
726    }
727
728    #[test]
729    fn shared_from_unique() {
730        #[repr(C)]
731        struct Foo {
732            a: ReadPureWrite<u32>,
733            b: ReadPure<u32>,
734        }
735
736        let mut foo = Foo {
737            a: ReadPureWrite(1),
738            b: ReadPure(2),
739        };
740        let unique: UniqueMmioPointer<Foo> = UniqueMmioPointer::from(&mut foo);
741
742        let shared_a: SharedMmioPointer<ReadPureWrite<u32>> = field_shared!(unique, a);
743        assert_eq!(shared_a.read(), 1);
744
745        let shared_b: SharedMmioPointer<ReadPure<u32>> = field_shared!(unique, b);
746        assert_eq!(shared_b.read(), 2);
747    }
748
749    #[test]
750    fn restricted_fields() {
751        #[repr(C)]
752        struct Foo {
753            r: ReadOnly<u32>,
754            w: WriteOnly<u32>,
755            u: u32,
756        }
757
758        let mut foo = Foo {
759            r: ReadOnly(1),
760            w: WriteOnly(2),
761            u: 3,
762        };
763        let mut owned: UniqueMmioPointer<Foo> = UniqueMmioPointer::from(&mut foo);
764
765        let mut owned_r: UniqueMmioPointer<ReadOnly<u32>> = field!(owned, r);
766        assert_eq!(owned_r.read(), 1);
767
768        let mut owned_w: UniqueMmioPointer<WriteOnly<u32>> = field!(owned, w);
769        owned_w.write(42);
770
771        let mut owned_u: UniqueMmioPointer<u32> = field!(owned, u);
772        // SAFETY: 'u' is safe to read or write because it's just a fake.
773        unsafe {
774            assert_eq!(owned_u.read_unsafe(), 3);
775            owned_u.write_unsafe(42);
776            assert_eq!(owned_u.read_unsafe(), 42);
777        }
778    }
779
780    #[test]
781    fn array() {
782        let mut foo = [ReadWrite(1), ReadWrite(2), ReadWrite(3)];
783        let mut owned = UniqueMmioPointer::from(&mut foo);
784
785        let mut parts = owned.split();
786        assert_eq!(parts[0].read(), 1);
787        assert_eq!(parts[1].read(), 2);
788        assert_eq!(owned.split()[2].read(), 3);
789    }
790
791    #[test]
792    fn array_shared() {
793        let foo = [ReadPure(1), ReadPure(2), ReadPure(3)];
794        let shared = SharedMmioPointer::from(&foo);
795
796        let parts = shared.split();
797        assert_eq!(parts[0].read(), 1);
798        assert_eq!(parts[1].read(), 2);
799        assert_eq!(shared.split()[2].read(), 3);
800    }
801
802    #[test]
803    fn slice() {
804        let mut foo = [ReadWrite(1), ReadWrite(2), ReadWrite(3)];
805        let mut owned = UniqueMmioPointer::from(foo.as_mut_slice());
806
807        assert!(!owned.ptr().is_null());
808        assert!(!owned.ptr_mut().is_null());
809
810        assert!(!owned.is_empty());
811        assert_eq!(owned.len(), 3);
812
813        let mut first: UniqueMmioPointer<ReadWrite<i32>> = owned.get(0).unwrap();
814        assert_eq!(first.read(), 1);
815
816        let mut second: UniqueMmioPointer<ReadWrite<i32>> = owned.get(1).unwrap();
817        assert_eq!(second.read(), 2);
818
819        assert!(owned.get(3).is_none());
820    }
821
822    #[test]
823    fn slice_shared() {
824        let foo = [ReadPure(1), ReadPure(2), ReadPure(3)];
825        let shared = SharedMmioPointer::from(foo.as_slice());
826
827        assert!(!shared.ptr().is_null());
828
829        assert!(!shared.is_empty());
830        assert_eq!(shared.len(), 3);
831
832        let first: SharedMmioPointer<ReadPure<i32>> = shared.get(0).unwrap();
833        assert_eq!(first.read(), 1);
834
835        let second: SharedMmioPointer<ReadPure<i32>> = shared.get(1).unwrap();
836        assert_eq!(second.read(), 2);
837
838        assert!(shared.get(3).is_none());
839
840        // Test that lifetime of pointer returned from `get` isn't tied to the lifetime of the slice
841        // pointer.
842        let second = {
843            let shared_copy = shared;
844            shared_copy.get(1).unwrap()
845        };
846        assert_eq!(second.read(), 2);
847    }
848
849    #[test]
850    fn array_field() {
851        #[repr(C)]
852        struct Regs {
853            a: [ReadPureWrite<u32>; 4],
854        }
855
856        let mut foo = Regs {
857            a: [const { ReadPureWrite(0) }; 4],
858        };
859        let mut owned: UniqueMmioPointer<Regs> = UniqueMmioPointer::from(&mut foo);
860
861        field!(owned, a).get(0).unwrap().write(42);
862        assert_eq!(field_shared!(owned, a).get(0).unwrap().read(), 42);
863    }
864
865    #[test]
866    fn slice_field() {
867        #[repr(transparent)]
868        struct Regs {
869            s: [ReadPureWrite<u32>],
870        }
871
872        impl Regs {
873            fn from_slice<'a>(slice: &'a mut [ReadPureWrite<u32>]) -> &'a mut Self {
874                let regs_ptr: *mut Self = slice as *mut [ReadPureWrite<u32>] as *mut Self;
875                // SAFETY: `Regs` is repr(transparent) so a reference to its field has the same
876                // metadata as a reference to `Regs``.
877                unsafe { &mut *regs_ptr }
878            }
879        }
880
881        let mut foo: [ReadPureWrite<u32>; 1] = [ReadPureWrite(0)];
882        let regs_mut = Regs::from_slice(foo.as_mut_slice());
883        let mut owned: UniqueMmioPointer<Regs> = UniqueMmioPointer::from(regs_mut);
884
885        field!(owned, s).get(0).unwrap().write(42);
886        assert_eq!(field_shared!(owned, s).get(0).unwrap().read(), 42);
887    }
888
889    #[test]
890    fn multiple_fields() {
891        #[repr(C)]
892        struct Regs {
893            first: ReadPureWrite<u32>,
894            second: ReadPureWrite<u32>,
895            third: ReadPureWrite<u32>,
896        }
897
898        let mut foo = Regs {
899            first: ReadPureWrite(1),
900            second: ReadPureWrite(2),
901            third: ReadPureWrite(3),
902        };
903        let mut owned: UniqueMmioPointer<Regs> = UniqueMmioPointer::from(&mut foo);
904
905        // SAFETY: We don't pass the same field name more than once.
906        let (first, second) = unsafe { split_fields!(owned.reborrow(), first, second) };
907
908        assert_eq!(first.read(), 1);
909        assert_eq!(second.read(), 2);
910
911        drop(first);
912        drop(second);
913
914        assert_eq!(field!(owned, first).read(), 1);
915    }
916
917    #[test]
918    fn split_array() {
919        let mut foo = [ReadWrite(1), ReadWrite(2), ReadWrite(3)];
920
921        let mut parts: [UniqueMmioPointer<ReadWrite<i32>>; 3] = {
922            let owned = UniqueMmioPointer::from(&mut foo);
923
924            owned.into()
925        };
926
927        assert_eq!(parts[0].read(), 1);
928        assert_eq!(parts[1].read(), 2);
929    }
930}