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    /// Converts this array pointer to an equivalent slice pointer.
252    pub const fn as_mut_slice(&mut self) -> UniqueMmioPointer<[T]> {
253        let regs = NonNull::new(self.ptr_mut()).unwrap();
254        // SAFETY: We created regs from the raw array in self.regs, so it must also be valid, unique
255        // and within the allocation of self.regs.
256        unsafe { self.child(regs) }
257    }
258
259    /// Returns a `UniqueMmioPointer` to an element of this array, or `None` if the index is out of
260    /// bounds.
261    ///
262    /// # Example
263    ///
264    /// ```
265    /// use safe_mmio::{UniqueMmioPointer, fields::ReadWrite};
266    ///
267    /// let mut slice: UniqueMmioPointer<[ReadWrite<u32>; 3]>;
268    /// # let mut fake = [ReadWrite(1), ReadWrite(2), ReadWrite(3)];
269    /// # slice = UniqueMmioPointer::from(&mut fake);
270    /// let mut element = slice.get(1).unwrap();
271    /// element.write(42);
272    /// slice.get(2).unwrap().write(100);
273    /// ```
274    pub const fn get(&mut self, index: usize) -> Option<UniqueMmioPointer<T>> {
275        if index >= LEN {
276            return None;
277        }
278        // SAFETY: self.ptr_mut() is guaranteed to return a pointer that is valid for MMIO and
279        // unique, as promised by the caller of `UniqueMmioPointer::new`.
280        let regs = NonNull::new(unsafe { &raw mut (*self.ptr_mut())[index] }).unwrap();
281        // SAFETY: We created regs from the raw array in self.regs, so it must also be valid, unique
282        // and within the allocation of self.regs.
283        Some(unsafe { self.child(regs) })
284    }
285
286    /// Returns a `UniqueMmioPointer` to an element of this array, or `None` if the index is out of
287    /// bounds.
288    ///
289    /// Unlike [`UniqueMmioPointer::get`] this takes ownership of the original pointer. This is
290    /// useful when you want to store the resulting pointer without keeping the original pointer
291    /// around.
292    ///
293    /// # Example
294    ///
295    /// ```
296    /// use safe_mmio::{UniqueMmioPointer, fields::ReadWrite};
297    ///
298    /// let mut array: UniqueMmioPointer<[ReadWrite<u32>; 3]>;
299    /// # let mut fake = [ReadWrite(1), ReadWrite(2), ReadWrite(3)];
300    /// # array = UniqueMmioPointer::from(&mut fake);
301    /// let mut element = array.take(1).unwrap();
302    /// element.write(42);
303    /// // `array` can no longer be used at this point.
304    /// ```
305    pub const fn take(mut self, index: usize) -> Option<UniqueMmioPointer<'a, T>> {
306        if index >= LEN {
307            return None;
308        }
309        // SAFETY: self.ptr_mut() is guaranteed to return a pointer that is valid for MMIO and
310        // unique, as promised by the caller of `UniqueMmioPointer::new`.
311        let regs = NonNull::new(unsafe { &raw mut (*self.ptr_mut())[index] }).unwrap();
312        // SAFETY: We created regs from the raw array in self.regs, so it must also be valid, unique
313        // and within the allocation of self.regs. `self` is dropped immediately after this and we
314        // don't split out any other children.
315        Some(unsafe { self.split_child(regs) })
316    }
317}
318
319impl<'a, T, const LEN: usize> From<UniqueMmioPointer<'a, [T; LEN]>> for UniqueMmioPointer<'a, [T]> {
320    fn from(mut value: UniqueMmioPointer<'a, [T; LEN]>) -> Self {
321        let regs = NonNull::new(value.ptr_mut()).unwrap();
322        // SAFETY: regs comes from a UniqueMmioPointer so already satisfies all the safety
323        // requirements.
324        unsafe { UniqueMmioPointer::new(regs) }
325    }
326}
327
328impl<'a, T> From<UniqueMmioPointer<'a, T>> for UniqueMmioPointer<'a, [T; 1]> {
329    fn from(mut value: UniqueMmioPointer<'a, T>) -> Self {
330        let regs = NonNull::new(value.ptr_mut()).unwrap().cast();
331        // SAFETY: regs comes from a UniqueMmioPointer so already satisfies all the safety
332        // requirements.
333        unsafe { UniqueMmioPointer::new(regs) }
334    }
335}
336
337impl<'a, T> From<UniqueMmioPointer<'a, T>> for UniqueMmioPointer<'a, [T]> {
338    fn from(mut value: UniqueMmioPointer<'a, T>) -> Self {
339        let array: *mut [T; 1] = value.ptr_mut().cast();
340        let regs = NonNull::new(array).unwrap();
341        // SAFETY: regs comes from a UniqueMmioPointer so already satisfies all the safety
342        // requirements.
343        unsafe { UniqueMmioPointer::new(regs) }
344    }
345}
346
347impl<'a, T, const LEN: usize> From<UniqueMmioPointer<'a, [T; LEN]>>
348    for [UniqueMmioPointer<'a, T>; LEN]
349{
350    fn from(mut value: UniqueMmioPointer<'a, [T; LEN]>) -> Self {
351        array::from_fn(|i| {
352            let item_pointer = value.split()[i].ptr_mut();
353            // SAFETY: `split_child` is called only once on each item and the original
354            // `UniqueMmioPointer` is consumed by this function.
355            unsafe { value.split_child(core::ptr::NonNull::new(item_pointer).unwrap()) }
356        })
357    }
358}
359
360impl<'a, T: ?Sized> From<&'a mut T> for UniqueMmioPointer<'a, T> {
361    fn from(r: &'a mut T) -> Self {
362        Self(SharedMmioPointer {
363            regs: r.into(),
364            phantom: PhantomData,
365        })
366    }
367}
368
369impl<'a, T: ?Sized> Deref for UniqueMmioPointer<'a, T> {
370    type Target = SharedMmioPointer<'a, T>;
371
372    fn deref(&self) -> &Self::Target {
373        &self.0
374    }
375}
376
377/// A shared pointer to the registers of some MMIO device.
378///
379/// It is guaranteed to be valid but unlike [`UniqueMmioPointer`] may not be unique.
380pub struct SharedMmioPointer<'a, T: ?Sized> {
381    regs: NonNull<T>,
382    phantom: PhantomData<&'a T>,
383}
384
385// Implement Debug, Eq and PartialEq manually rather than deriving to avoid an unneccessary bound on
386// T.
387
388impl<T: ?Sized> Debug for SharedMmioPointer<'_, T> {
389    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
390        f.debug_tuple("SharedMmioPointer")
391            .field(&self.regs)
392            .finish()
393    }
394}
395
396impl<T: ?Sized> PartialEq for SharedMmioPointer<'_, T> {
397    fn eq(&self, other: &Self) -> bool {
398        ptr::eq(self.regs.as_ptr(), other.regs.as_ptr())
399    }
400}
401
402impl<T: ?Sized> Eq for SharedMmioPointer<'_, T> {}
403
404impl<T: ?Sized> Clone for SharedMmioPointer<'_, T> {
405    fn clone(&self) -> Self {
406        *self
407    }
408}
409
410impl<T: ?Sized> Copy for SharedMmioPointer<'_, T> {}
411
412impl<'a, T: ?Sized> SharedMmioPointer<'a, T> {
413    /// Creates a new `SharedMmioPointer` with the same lifetime as this one.
414    ///
415    /// This is used internally by the [`field_shared!`] macro and shouldn't be called directly.
416    ///
417    /// # Safety
418    ///
419    /// `regs` must be a properly aligned and valid pointer to some MMIO address space of type T,
420    /// within the allocation that `self` points to.
421    pub const unsafe fn child<U: ?Sized>(&self, regs: NonNull<U>) -> SharedMmioPointer<'a, U> {
422        SharedMmioPointer {
423            regs,
424            phantom: PhantomData,
425        }
426    }
427
428    /// Returns a raw const pointer to the MMIO registers.
429    pub const fn ptr(&self) -> *const T {
430        self.regs.as_ptr()
431    }
432}
433
434// SAFETY: A `SharedMmioPointer` always originates either from a reference or from a
435// `UniqueMmioPointer`. The caller of `UniqueMmioPointer::new` promises that the MMIO registers can
436// be accessed from any thread.
437unsafe impl<T: ?Sized + Send + Sync> Send for SharedMmioPointer<'_, T> {}
438
439impl<'a, T: ?Sized> From<&'a T> for SharedMmioPointer<'a, T> {
440    fn from(r: &'a T) -> Self {
441        Self {
442            regs: r.into(),
443            phantom: PhantomData,
444        }
445    }
446}
447
448impl<'a, T: ?Sized> From<UniqueMmioPointer<'a, T>> for SharedMmioPointer<'a, T> {
449    fn from(unique: UniqueMmioPointer<'a, T>) -> Self {
450        unique.0
451    }
452}
453
454impl<T: FromBytes + IntoBytes> SharedMmioPointer<'_, ReadPure<T>> {
455    /// Performs an MMIO read of the entire `T`.
456    pub fn read(&self) -> T {
457        // SAFETY: self.regs is always a valid and unique pointer to MMIO address space, and `T`
458        // being wrapped in `ReadPure` implies that it is safe to read from a shared reference
459        // because doing so has no side-effects.
460        unsafe { self.read_unsafe().0 }
461    }
462}
463
464impl<T: FromBytes + IntoBytes> SharedMmioPointer<'_, ReadPureWrite<T>> {
465    /// Performs an MMIO read of the entire `T`.
466    pub fn read(&self) -> T {
467        // SAFETY: self.regs is always a valid pointer to MMIO address space, and `T`
468        // being wrapped in `ReadPureWrite` implies that it is safe to read from a shared reference
469        // because doing so has no side-effects.
470        unsafe { self.read_unsafe().0 }
471    }
472}
473
474impl<'a, T> SharedMmioPointer<'a, [T]> {
475    /// Returns a `SharedMmioPointer` to an element of this slice, or `None` if the index is out of
476    /// bounds.
477    pub const fn get(&self, index: usize) -> Option<SharedMmioPointer<'a, T>> {
478        if index >= self.len() {
479            return None;
480        }
481        // SAFETY: self.regs is always unique and valid for MMIO access.
482        let regs = NonNull::new(unsafe { &raw mut (*self.regs.as_ptr())[index] }).unwrap();
483        // SAFETY: We created regs from the raw slice in self.regs, so it must also be valid, unique
484        // and within the allocation of self.regs.
485        Some(unsafe { self.child(regs) })
486    }
487
488    /// Returns the length of the slice.
489    pub const fn len(&self) -> usize {
490        self.regs.len()
491    }
492
493    /// Returns whether the slice is empty.
494    pub const fn is_empty(&self) -> bool {
495        self.regs.is_empty()
496    }
497}
498
499impl<'a, T, const LEN: usize> SharedMmioPointer<'a, [T; LEN]> {
500    /// Splits a `SharedMmioPointer` to an array into an array of `SharedMmioPointer`s.
501    pub fn split(&self) -> [SharedMmioPointer<'a, T>; LEN] {
502        array::from_fn(|i| SharedMmioPointer {
503            // SAFETY: self.regs is always unique and valid for MMIO access. We make sure the
504            // pointers we split it into don't overlap, so the same applies to each of them.
505            regs: NonNull::new(unsafe { &raw mut (*self.regs.as_ptr())[i] }).unwrap(),
506            phantom: PhantomData,
507        })
508    }
509
510    /// Converts this array pointer to an equivalent slice pointer.
511    pub const fn as_slice(&self) -> SharedMmioPointer<'a, [T]> {
512        let regs = NonNull::new(self.regs.as_ptr()).unwrap();
513        // SAFETY: We created regs from the raw array in self.regs, so it must also be valid, unique
514        // and within the allocation of self.regs.
515        unsafe { self.child(regs) }
516    }
517
518    /// Returns a `SharedMmioPointer` to an element of this array, or `None` if the index is out of
519    /// bounds.
520    pub const fn get(&self, index: usize) -> Option<SharedMmioPointer<'a, T>> {
521        if index >= LEN {
522            return None;
523        }
524        // SAFETY: self.regs is always unique and valid for MMIO access.
525        let regs = NonNull::new(unsafe { &raw mut (*self.regs.as_ptr())[index] }).unwrap();
526        // SAFETY: We created regs from the raw array in self.regs, so it must also be valid, unique
527        // and within the allocation of self.regs.
528        Some(unsafe { self.child(regs) })
529    }
530}
531
532impl<'a, T, const LEN: usize> From<SharedMmioPointer<'a, [T; LEN]>> for SharedMmioPointer<'a, [T]> {
533    fn from(value: SharedMmioPointer<'a, [T; LEN]>) -> Self {
534        let regs = NonNull::new(value.regs.as_ptr()).unwrap();
535        SharedMmioPointer {
536            regs,
537            phantom: PhantomData,
538        }
539    }
540}
541
542impl<'a, T> From<SharedMmioPointer<'a, T>> for SharedMmioPointer<'a, [T; 1]> {
543    fn from(value: SharedMmioPointer<'a, T>) -> Self {
544        let regs = NonNull::new(value.regs.as_ptr()).unwrap().cast();
545        SharedMmioPointer {
546            regs,
547            phantom: PhantomData,
548        }
549    }
550}
551
552impl<'a, T> From<SharedMmioPointer<'a, T>> for SharedMmioPointer<'a, [T]> {
553    fn from(value: SharedMmioPointer<'a, T>) -> Self {
554        let array: *mut [T; 1] = value.regs.as_ptr().cast();
555        let regs = NonNull::new(array).unwrap();
556        SharedMmioPointer {
557            regs,
558            phantom: PhantomData,
559        }
560    }
561}
562
563/// Gets a `UniqueMmioPointer` to a field of a type wrapped in a `UniqueMmioPointer`.
564#[macro_export]
565macro_rules! field {
566    ($mmio_pointer:expr, $field:ident) => {{
567        // Make sure $mmio_pointer is the right type.
568        let mmio_pointer: &mut $crate::UniqueMmioPointer<_> = &mut $mmio_pointer;
569        // SAFETY: ptr_mut is guaranteed to return a valid pointer for MMIO, so the pointer to the
570        // field must also be valid. MmioPointer::child gives it the same lifetime as the original
571        // pointer.
572        unsafe {
573            let child_pointer =
574                core::ptr::NonNull::new(&raw mut (*mmio_pointer.ptr_mut()).$field).unwrap();
575            mmio_pointer.child(child_pointer)
576        }
577    }};
578}
579
580/// Gets `UniqueMmioPointer`s to several fields of a type wrapped in a `UniqueMmioPointer`.
581///
582/// # Safety
583///
584/// The same field name must not be passed more than once.
585#[macro_export]
586macro_rules! split_fields {
587    ($mmio_pointer:expr, $( $field:ident ),+) => {{
588        // Make sure $mmio_pointer is the right type, and take ownership of it.
589        let mut mmio_pointer: $crate::UniqueMmioPointer<_> = $mmio_pointer;
590        let pointer = mmio_pointer.ptr_mut();
591        let ret = (
592            $(
593                // SAFETY: ptr_mut is guaranteed to return a valid pointer for MMIO, so the pointer
594                // to the field must also be valid. MmioPointer::child gives it the same lifetime as
595                // the original pointer, and the caller of `split_fields!` promised not to pass the
596                // same field more than once.
597                {
598                    let child_pointer = core::ptr::NonNull::new(&raw mut (*pointer).$field).unwrap();
599                    mmio_pointer.split_child(child_pointer)
600                }
601            ),+
602        );
603        ret
604    }};
605}
606
607/// Gets a `SharedMmioPointer` to a field of a type wrapped in a `SharedMmioPointer`.
608#[macro_export]
609macro_rules! field_shared {
610    ($mmio_pointer:expr, $field:ident) => {{
611        // Make sure $mmio_pointer is the right type.
612        let mmio_pointer: &$crate::SharedMmioPointer<_> = &$mmio_pointer;
613        // SAFETY: ptr_mut is guaranteed to return a valid pointer for MMIO, so the pointer to the
614        // field must also be valid. MmioPointer::child gives it the same lifetime as the original
615        // pointer.
616        unsafe {
617            let child_pointer =
618                core::ptr::NonNull::new((&raw const (*mmio_pointer.ptr()).$field).cast_mut())
619                    .unwrap();
620            mmio_pointer.child(child_pointer)
621        }
622    }};
623}
624
625#[cfg(test)]
626mod tests {
627    use super::*;
628
629    #[test]
630    fn fields() {
631        #[repr(C)]
632        struct Foo {
633            a: ReadWrite<u32>,
634            b: ReadOnly<u32>,
635            c: ReadPure<u32>,
636        }
637
638        let mut foo = Foo {
639            a: ReadWrite(1),
640            b: ReadOnly(2),
641            c: ReadPure(3),
642        };
643        let mut owned: UniqueMmioPointer<Foo> = UniqueMmioPointer::from(&mut foo);
644
645        let mut owned_a: UniqueMmioPointer<ReadWrite<u32>> = field!(owned, a);
646        assert_eq!(owned_a.read(), 1);
647        owned_a.write(42);
648        assert_eq!(owned_a.read(), 42);
649        field!(owned, a).write(44);
650        assert_eq!(field!(owned, a).read(), 44);
651
652        let mut owned_b: UniqueMmioPointer<ReadOnly<u32>> = field!(owned, b);
653        assert_eq!(owned_b.read(), 2);
654
655        let owned_c: UniqueMmioPointer<ReadPure<u32>> = field!(owned, c);
656        assert_eq!(owned_c.read(), 3);
657        assert_eq!(field!(owned, c).read(), 3);
658    }
659
660    #[test]
661    fn shared_fields() {
662        #[repr(C)]
663        struct Foo {
664            a: ReadPureWrite<u32>,
665            b: ReadPure<u32>,
666        }
667
668        let foo = Foo {
669            a: ReadPureWrite(1),
670            b: ReadPure(2),
671        };
672        let shared: SharedMmioPointer<Foo> = SharedMmioPointer::from(&foo);
673
674        let shared_a: SharedMmioPointer<ReadPureWrite<u32>> = field_shared!(shared, a);
675        assert_eq!(shared_a.read(), 1);
676        assert_eq!(field_shared!(shared, a).read(), 1);
677
678        let shared_b: SharedMmioPointer<ReadPure<u32>> = field_shared!(shared, b);
679        assert_eq!(shared_b.read(), 2);
680    }
681
682    #[test]
683    fn shared_from_unique() {
684        #[repr(C)]
685        struct Foo {
686            a: ReadPureWrite<u32>,
687            b: ReadPure<u32>,
688        }
689
690        let mut foo = Foo {
691            a: ReadPureWrite(1),
692            b: ReadPure(2),
693        };
694        let unique: UniqueMmioPointer<Foo> = UniqueMmioPointer::from(&mut foo);
695
696        let shared_a: SharedMmioPointer<ReadPureWrite<u32>> = field_shared!(unique, a);
697        assert_eq!(shared_a.read(), 1);
698
699        let shared_b: SharedMmioPointer<ReadPure<u32>> = field_shared!(unique, b);
700        assert_eq!(shared_b.read(), 2);
701    }
702
703    #[test]
704    fn restricted_fields() {
705        #[repr(C)]
706        struct Foo {
707            r: ReadOnly<u32>,
708            w: WriteOnly<u32>,
709            u: u32,
710        }
711
712        let mut foo = Foo {
713            r: ReadOnly(1),
714            w: WriteOnly(2),
715            u: 3,
716        };
717        let mut owned: UniqueMmioPointer<Foo> = UniqueMmioPointer::from(&mut foo);
718
719        let mut owned_r: UniqueMmioPointer<ReadOnly<u32>> = field!(owned, r);
720        assert_eq!(owned_r.read(), 1);
721
722        let mut owned_w: UniqueMmioPointer<WriteOnly<u32>> = field!(owned, w);
723        owned_w.write(42);
724
725        let mut owned_u: UniqueMmioPointer<u32> = field!(owned, u);
726        // SAFETY: 'u' is safe to read or write because it's just a fake.
727        unsafe {
728            assert_eq!(owned_u.read_unsafe(), 3);
729            owned_u.write_unsafe(42);
730            assert_eq!(owned_u.read_unsafe(), 42);
731        }
732    }
733
734    #[test]
735    fn array() {
736        let mut foo = [ReadWrite(1), ReadWrite(2), ReadWrite(3)];
737        let mut owned = UniqueMmioPointer::from(&mut foo);
738
739        let mut parts = owned.split();
740        assert_eq!(parts[0].read(), 1);
741        assert_eq!(parts[1].read(), 2);
742        assert_eq!(owned.split()[2].read(), 3);
743    }
744
745    #[test]
746    fn array_shared() {
747        let foo = [ReadPure(1), ReadPure(2), ReadPure(3)];
748        let shared = SharedMmioPointer::from(&foo);
749
750        let parts = shared.split();
751        assert_eq!(parts[0].read(), 1);
752        assert_eq!(parts[1].read(), 2);
753        assert_eq!(shared.split()[2].read(), 3);
754    }
755
756    #[test]
757    fn slice() {
758        let mut foo = [ReadWrite(1), ReadWrite(2), ReadWrite(3)];
759        let mut owned = UniqueMmioPointer::from(foo.as_mut_slice());
760
761        assert!(!owned.ptr().is_null());
762        assert!(!owned.ptr_mut().is_null());
763
764        assert!(!owned.is_empty());
765        assert_eq!(owned.len(), 3);
766
767        let mut first: UniqueMmioPointer<ReadWrite<i32>> = owned.get(0).unwrap();
768        assert_eq!(first.read(), 1);
769
770        let mut second: UniqueMmioPointer<ReadWrite<i32>> = owned.get(1).unwrap();
771        assert_eq!(second.read(), 2);
772
773        assert!(owned.get(3).is_none());
774    }
775
776    #[test]
777    fn slice_shared() {
778        let foo = [ReadPure(1), ReadPure(2), ReadPure(3)];
779        let shared = SharedMmioPointer::from(foo.as_slice());
780
781        assert!(!shared.ptr().is_null());
782
783        assert!(!shared.is_empty());
784        assert_eq!(shared.len(), 3);
785
786        let first: SharedMmioPointer<ReadPure<i32>> = shared.get(0).unwrap();
787        assert_eq!(first.read(), 1);
788
789        let second: SharedMmioPointer<ReadPure<i32>> = shared.get(1).unwrap();
790        assert_eq!(second.read(), 2);
791
792        assert!(shared.get(3).is_none());
793
794        // Test that lifetime of pointer returned from `get` isn't tied to the lifetime of the slice
795        // pointer.
796        let second = {
797            let shared_copy = shared;
798            shared_copy.get(1).unwrap()
799        };
800        assert_eq!(second.read(), 2);
801    }
802
803    #[test]
804    fn array_field() {
805        #[repr(C)]
806        struct Regs {
807            a: [ReadPureWrite<u32>; 4],
808        }
809
810        let mut foo = Regs {
811            a: [const { ReadPureWrite(0) }; 4],
812        };
813        let mut owned: UniqueMmioPointer<Regs> = UniqueMmioPointer::from(&mut foo);
814
815        field!(owned, a).get(0).unwrap().write(42);
816        assert_eq!(field_shared!(owned, a).get(0).unwrap().read(), 42);
817    }
818
819    #[test]
820    fn slice_field() {
821        #[repr(transparent)]
822        struct Regs {
823            s: [ReadPureWrite<u32>],
824        }
825
826        impl Regs {
827            fn from_slice<'a>(slice: &'a mut [ReadPureWrite<u32>]) -> &'a mut Self {
828                let regs_ptr: *mut Self = slice as *mut [ReadPureWrite<u32>] as *mut Self;
829                // SAFETY: `Regs` is repr(transparent) so a reference to its field has the same
830                // metadata as a reference to `Regs``.
831                unsafe { &mut *regs_ptr }
832            }
833        }
834
835        let mut foo: [ReadPureWrite<u32>; 1] = [ReadPureWrite(0)];
836        let regs_mut = Regs::from_slice(foo.as_mut_slice());
837        let mut owned: UniqueMmioPointer<Regs> = UniqueMmioPointer::from(regs_mut);
838
839        field!(owned, s).get(0).unwrap().write(42);
840        assert_eq!(field_shared!(owned, s).get(0).unwrap().read(), 42);
841    }
842
843    #[test]
844    fn multiple_fields() {
845        #[repr(C)]
846        struct Regs {
847            first: ReadPureWrite<u32>,
848            second: ReadPureWrite<u32>,
849            third: ReadPureWrite<u32>,
850        }
851
852        let mut foo = Regs {
853            first: ReadPureWrite(1),
854            second: ReadPureWrite(2),
855            third: ReadPureWrite(3),
856        };
857        let mut owned: UniqueMmioPointer<Regs> = UniqueMmioPointer::from(&mut foo);
858
859        // SAFETY: We don't pass the same field name more than once.
860        let (first, second) = unsafe { split_fields!(owned.reborrow(), first, second) };
861
862        assert_eq!(first.read(), 1);
863        assert_eq!(second.read(), 2);
864
865        drop(first);
866        drop(second);
867
868        assert_eq!(field!(owned, first).read(), 1);
869    }
870
871    #[test]
872    fn split_array() {
873        let mut foo = [ReadWrite(1), ReadWrite(2), ReadWrite(3)];
874
875        let mut parts: [UniqueMmioPointer<ReadWrite<i32>>; 3] = {
876            let owned = UniqueMmioPointer::from(&mut foo);
877
878            owned.into()
879        };
880
881        assert_eq!(parts[0].read(), 1);
882        assert_eq!(parts[1].read(), 2);
883    }
884}