Skip to main content

kernel/
io.rs

1// SPDX-License-Identifier: GPL-2.0
2
3//! Memory-mapped IO.
4//!
5//! C header: [`include/asm-generic/io.h`](srctree/include/asm-generic/io.h)
6
7use core::{
8    marker::PhantomData,
9    mem::MaybeUninit, //
10};
11
12use crate::{
13    bindings,
14    mem::{
15        AsRepr,
16        AsReprMut, //
17    },
18    prelude::*,
19    ptr::{
20        Alignment,
21        KnownSize, //
22    }, //
23};
24
25#[cfg(CONFIG_HAS_IOMEM)]
26pub mod mem;
27pub mod poll;
28pub mod register;
29pub mod resource;
30
31pub use crate::register;
32pub use resource::Resource;
33
34use register::LocatedRegister;
35
36/// Physical address type.
37///
38/// This is a type alias to either `u32` or `u64` depending on the config option
39/// `CONFIG_PHYS_ADDR_T_64BIT`, and it can be a u64 even on 32-bit architectures.
40pub type PhysAddr = bindings::phys_addr_t;
41
42/// Resource Size type.
43///
44/// This is a type alias to either `u32` or `u64` depending on the config option
45/// `CONFIG_PHYS_ADDR_T_64BIT`, and it can be a u64 even on 32-bit architectures.
46pub type ResourceSize = bindings::resource_size_t;
47
48/// Untyped I/O region.
49///
50/// This type can be used when an I/O region without known type information has a compile-time known
51/// minimum size (and a runtime known actual size).
52///
53/// # Invariants
54///
55/// - Size of the region is at least as large as the `SIZE` generic parameter.
56/// - Size of the region is multiple of 4.
57#[repr(C, align(4))]
58#[derive(FromBytes)]
59pub struct Region<const SIZE: usize = 0> {
60    inner: [u8],
61}
62
63impl<const SIZE: usize> Region<SIZE> {
64    /// Create a raw mutable pointer from given base address and size.
65    ///
66    /// `size` should be at least as large as the minimum size `SIZE`, and `base` and `size` should
67    /// be 4-byte aligned to uphold the type invariant.
68    ///
69    /// Just like other methods on raw pointers, it is not unsafe to create a raw pointer
70    /// that does not uphold the type invariants. However such pointers are not valid.
71    #[inline]
72    pub fn ptr_from_raw_parts_mut(base: *mut u8, size: usize) -> *mut Self {
73        core::ptr::slice_from_raw_parts_mut(base, size) as *mut Region<SIZE>
74    }
75
76    /// Create a raw mutable pointer from given base address and size.
77    ///
78    /// The alignment of `base` is checked, and `size` is checked against the minimum size specified
79    /// via const generics.
80    #[inline]
81    pub fn ptr_try_from_raw_parts_mut(base: *mut u8, size: usize) -> Result<*mut Self> {
82        if size < SIZE || base.align_offset(4) != 0 || !size.is_multiple_of(4) {
83            return Err(EINVAL);
84        }
85
86        Ok(Self::ptr_from_raw_parts_mut(base, size))
87    }
88}
89
90impl<const SIZE: usize> KnownSize for Region<SIZE> {
91    const MIN_SIZE: usize = SIZE;
92    // Alignment of 4 is the most common; different base types can be added once required.
93    const MIN_ALIGN: Alignment = Alignment::new::<4>();
94
95    #[inline(always)]
96    fn size(p: *const Self) -> usize {
97        (p as *const [u8]).len()
98    }
99}
100
101// SAFETY:
102// - Values read from I/O are always treated as initialized.
103// - Per type invariant the size is multiple of 4 and the type is 4-byte aligned, so it is padding
104//   free.
105//
106// This cannot be derived as `derive(IntoBytes)` as the padding free property comes from type
107// invariant which the macro does not know.
108unsafe impl<const SIZE: usize> IntoBytes for Region<SIZE> {
109    #[inline]
110    #[allow(unused)] // Rust 1.87+ stops requiring this and will emit unused warnings.
111    fn only_derive_is_allowed_to_implement_this_trait() {}
112}
113
114/// Raw representation of an MMIO region.
115///
116/// `MmioRaw<T>` is equivalent to `T __iomem *` in C.
117///
118/// By itself, the existence of an instance of this structure does not provide any guarantees that
119/// the represented MMIO region does exist or is properly mapped.
120///
121/// Instead, the bus specific MMIO implementation must convert this raw representation into an
122/// `Mmio` instance providing the actual memory accessors. Only by the conversion into an `Mmio`
123/// structure any guarantees are given.
124pub struct MmioRaw<T: ?Sized> {
125    /// Pointer is in I/O address space.
126    ///
127    /// The provenance does not matter, only the address and metadata do.
128    ptr: *mut T,
129}
130
131impl<T: ?Sized> Copy for MmioRaw<T> {}
132impl<T: ?Sized> Clone for MmioRaw<T> {
133    #[inline]
134    fn clone(&self) -> Self {
135        *self
136    }
137}
138
139// SAFETY: `MmioRaw` is just an address, so is thread-safe.
140unsafe impl<T: ?Sized> Send for MmioRaw<T> {}
141// SAFETY: `MmioRaw` is just an address, so is thread-safe.
142unsafe impl<T: ?Sized> Sync for MmioRaw<T> {}
143
144impl<T> MmioRaw<T> {
145    /// Create a `MmioRaw` from address.
146    #[inline]
147    pub fn new(addr: usize) -> Self {
148        Self {
149            ptr: core::ptr::without_provenance_mut(addr),
150        }
151    }
152}
153
154impl<const SIZE: usize> MmioRaw<Region<SIZE>> {
155    /// Create a `MmioRaw` representing a I/O region with given size.
156    ///
157    /// The size is checked against the minimum size specified via const generics.
158    #[inline]
159    pub fn new_region(addr: usize, size: usize) -> Result<Self> {
160        Ok(Self {
161            ptr: Region::ptr_try_from_raw_parts_mut(core::ptr::without_provenance_mut(addr), size)?,
162        })
163    }
164}
165
166impl<T: ?Sized + KnownSize> MmioRaw<T> {
167    /// Returns the base address of the MMIO region.
168    #[inline]
169    pub fn addr(&self) -> usize {
170        self.ptr.addr()
171    }
172
173    /// Returns the size of the MMIO region.
174    #[inline]
175    pub fn size(&self) -> usize {
176        KnownSize::size(self.ptr)
177    }
178}
179
180/// Checks whether an access of type `U` at the given `base` and the given `offset`
181/// is valid within this region.
182///
183/// The `base` is used for alignment checking only. This can be set to 0 to skip the check.
184#[inline]
185const fn offset_valid<U>(base: usize, offset: usize, size: usize) -> bool {
186    if let Some(end) = offset.checked_add(size_of::<U>()) {
187        end <= size && (base.wrapping_add(offset) % align_of::<U>() == 0)
188    } else {
189        false
190    }
191}
192
193/// Returns a view for a given `offset`, performing compile-time bound checks.
194// Always inline to optimize out error path of `build_assert`.
195#[inline(always)]
196fn io_view_assert<'a, IO: Io<'a>, U>(
197    this: IO,
198    offset: usize,
199) -> <IO::Backend as IoBackend>::View<'a, U> {
200    // We cannot check alignment with `offset_valid` using `ptr.addr()`. So set 0 for it and
201    // ensure alignment by checking that the alignment of `U` is smaller or equal to the
202    // alignment of `IO::Target`.
203    const_assert!(Alignment::of::<U>().as_usize() <= IO::Target::MIN_ALIGN.as_usize());
204    build_assert!(offset_valid::<U>(0, offset, IO::Target::MIN_SIZE));
205
206    let view = this.as_view();
207    let ptr = IO::Backend::as_ptr(view);
208    let projected_ptr = ptr.cast::<U>().wrapping_byte_add(offset);
209    // SAFETY: `offset_valid` checks for size and alignment and therefore `projected_ptr` is a
210    // valid projection.
211    unsafe { IO::Backend::project_view(view, projected_ptr) }
212}
213
214/// Returns a view for a given `offset`, performing runtime bound checks.
215#[inline]
216fn io_view<'a, IO: Io<'a>, U>(
217    this: IO,
218    offset: usize,
219) -> Result<<IO::Backend as IoBackend>::View<'a, U>> {
220    let view = this.as_view();
221    let ptr = IO::Backend::as_ptr(view);
222
223    if !offset_valid::<U>(ptr.addr(), offset, KnownSize::size(ptr)) {
224        return Err(EINVAL);
225    }
226
227    let projected_ptr = ptr.cast::<U>().wrapping_byte_add(offset);
228    // SAFETY: `offset_valid` checks for size and alignment and therefore `projected_ptr` is a
229    // valid projection.
230    Ok(unsafe { IO::Backend::project_view(view, projected_ptr) })
231}
232
233/// Returns the primitive view of a I/O view.
234#[inline]
235fn io_view_as_repr<'a, IO: Io<'a, Target = T>, T: AsRepr>(
236    this: IO,
237) -> <IO::Backend as IoBackend>::View<'a, T::Repr> {
238    let view = this.as_view();
239
240    // SAFETY: `AsRepr` guarantees layout compatibility.
241    unsafe { IO::Backend::project_view(view, IO::Backend::as_ptr(view).cast::<T::Repr>()) }
242}
243
244/// I/O backends.
245///
246/// This is an abstract representation to be implemented by arbitrary I/O
247/// backends (e.g. MMIO, PCI config space, etc.).
248///
249/// The base trait only defines the projection operations; which I/O methods are available depends
250/// on which [`IoCapable<T>`] traits are implemented for the type. For example, for MMIO regions,
251/// all widths (u8, u16, u32, and u64 on 64-bit systems) are typically supported. For PCI
252/// configuration space, u8, u16, and u32 are supported but u64 is not.
253///
254/// This trait is separate from the `Io` trait as multiple different I/O types may share the same
255/// operation.
256pub trait IoBackend {
257    /// View type for this I/O backend.
258    type View<'a, T: ?Sized + KnownSize>: IoBase<'a, Backend = Self, Target = T>;
259
260    /// Convert a `view` to a raw pointer for projection.
261    ///
262    /// The returned pointer is private implementation detail of the backend; it is likely not
263    /// valid. It should not be dereferenced.
264    fn as_ptr<'a, T: ?Sized + KnownSize>(view: Self::View<'a, T>) -> *mut T;
265
266    /// Project `view` to its subregion indicated by `ptr`.
267    ///
268    /// If input `view` is valid, returned view must also be valid.
269    ///
270    /// # Safety
271    ///
272    /// `ptr` must be a projection of `Self::as_ptr(view)`.
273    unsafe fn project_view<'a, T: ?Sized + KnownSize, U: ?Sized + KnownSize>(
274        view: Self::View<'a, T>,
275        ptr: *mut U,
276    ) -> Self::View<'a, U>;
277}
278
279/// Trait indicating that an I/O backend supports operations of a certain type and providing an
280/// implementation for these operations.
281///
282/// Different I/O backends can implement this trait to expose only the operations they support.
283///
284/// For example, a PCI configuration space may implement `IoCapable<u8>`, `IoCapable<u16>`,
285/// and `IoCapable<u32>`, but not `IoCapable<u64>`, while an MMIO region on a 64-bit
286/// system might implement all four.
287pub trait IoCapable<T>: IoBackend {
288    /// Performs an I/O read of type `T` at `view` and returns the result.
289    fn io_read<'a>(view: Self::View<'a, T>) -> T;
290
291    /// Performs an I/O write of `value` at `view`.
292    fn io_write<'a>(view: Self::View<'a, T>, value: T);
293}
294
295/// Trait indicating that an I/O backend supports memory copy operations.
296pub trait IoCopyable: IoBackend {
297    /// Copy contents of `view` to `buffer`.
298    ///
299    /// # Safety
300    ///
301    /// - `buffer` is valid for volatile write for `view.size()` bytes.
302    /// - `buffer` should not overlap with `view`.
303    unsafe fn copy_from_io(view: Self::View<'_, [u8]>, buffer: *mut u8);
304
305    /// Copy contents from `buffer` to `view`.
306    ///
307    /// # Safety
308    ///
309    /// - `buffer` is valid for volatile read for `view.size()` bytes.
310    /// - `buffer` should not overlap with `view`.
311    unsafe fn copy_to_io(view: Self::View<'_, [u8]>, buffer: *const u8);
312
313    /// Copy from `view` and return the value.
314    #[inline]
315    fn copy_read<T: FromBytes>(view: Self::View<'_, T>) -> T {
316        // Project `self` to `[u8]`.
317        let ptr = Self::as_ptr(view);
318        // SAFETY: This is a identity projection.
319        let slice_view = unsafe {
320            Self::project_view(
321                view,
322                core::ptr::slice_from_raw_parts_mut::<u8>(ptr.cast(), size_of::<T>()),
323            )
324        };
325
326        let mut buf = MaybeUninit::<T>::uninit();
327        // SAFETY:
328        // - `buf.as_mut_ptr()` is valid for write for `size_of::<T>()` bytes.
329        // - `buf` is local so `buf.as_mut_ptr()` cannot overlap with `slice_view`.
330        unsafe { Self::copy_from_io(slice_view, buf.as_mut_ptr().cast()) };
331        // SAFETY: `T: FromBytes` guarantee that all bit patterns are valid.
332        unsafe { buf.assume_init() }
333    }
334
335    /// Copy `value` to `view`.
336    ///
337    /// Destructor of `value` will not be executed, consistent with [`zerocopy::transmute`].
338    #[inline]
339    fn copy_write<T: IntoBytes>(view: Self::View<'_, T>, value: T) {
340        // Project `self` to `[u8]`.
341        let ptr = Self::as_ptr(view);
342        // SAFETY: This is a identity projection.
343        let slice_view = unsafe {
344            Self::project_view(
345                view,
346                core::ptr::slice_from_raw_parts_mut::<u8>(ptr.cast(), size_of::<T>()),
347            )
348        };
349
350        // SAFETY:
351        // - `&raw const value` is valid for read for `size_of::<T>()` bytes.
352        // - `value` is local so `&raw const value` cannot overlap with `slice_view`.
353        unsafe { Self::copy_to_io(slice_view, (&raw const value).cast()) };
354        core::mem::forget(value);
355    }
356}
357
358/// Describes a given I/O location: its offset, width, and type to convert the raw value from and
359/// into.
360///
361/// This trait is the key abstraction allowing [`Io::read`], [`Io::write`], and [`Io::update`] (and
362/// their fallible [`try_read`](Io::try_read), [`try_write`](Io::try_write) and
363/// [`try_update`](Io::try_update) counterparts) to work uniformly with both raw [`usize`] offsets
364/// (for primitive types like [`u32`]) and typed ones (like those generated by the [`register!`]
365/// macro).
366///
367/// An `IoLoc<Base, T>` carries the following pieces of information:
368///
369/// - The valid `Base` to operate on. For most registers, this should be [`Region`].
370/// - The offset to access (returned by [`IoLoc::offset`]),
371/// - The type `T` in which the data is returned or provided.
372///
373/// `T` is not necessarily the type for underlying I/O operation. Methods that take `IoLoc` have `T:
374/// AsRepr` bound and the `<T as AsRepr>::Repr` type would be used to perform I/O and converted to
375/// `T` instead.
376pub trait IoLoc<Base: ?Sized, T> {
377    /// Consumes `self` and returns the offset of this location.
378    fn offset(self) -> usize;
379}
380
381/// Implements [`IoLoc<Region<SIZE>, $ty>`] for [`usize`], allowing [`usize`] to be used as a
382/// parameter of [`Io::read`] and [`Io::write`].
383macro_rules! impl_usize_ioloc {
384    ($($ty:ty),*) => {
385        $(
386            impl<const SIZE: usize> IoLoc<Region<SIZE>, $ty> for usize {
387                #[inline(always)]
388                fn offset(self) -> usize {
389                    self
390                }
391            }
392        )*
393    }
394}
395
396// Provide the ability to read any primitive type from a [`usize`].
397impl_usize_ioloc!(u8, u16, u32, u64);
398
399/// Types implementing this trait (e.g. MMIO BARs or PCI config regions)
400/// can perform I/O operations on regions of memory.
401///
402/// This trait defines which backend shall be used for I/O operations and provides a method to
403/// convert into [`IoBackend::View`]. Users should use the [`Io`] trait which provides the actual
404/// methods to perform I/O operations.
405///
406/// This should be implemented on cheaply copyable handles, such as references or view types.
407pub trait IoBase<'a>: Copy {
408    /// Type that defines all I/O operations.
409    type Backend: IoBackend;
410
411    /// Type of this I/O region. For untyped regions, [`Region`] can be used.
412    type Target: ?Sized + KnownSize;
413
414    /// Return a view that covers the full region.
415    fn as_view(self) -> <Self::Backend as IoBackend>::View<'a, Self::Target>;
416}
417
418/// Extension trait to provide I/O operation methods to types that implement [`IoBase`].
419///
420/// This trait provides:
421/// - Helper methods for offset validation and address calculation
422/// - Fallible (runtime checked) accessors for different data widths
423///
424/// Which I/O methods are available depends on the associated [`IoBackend`] implementation.
425pub trait Io<'a>: IoBase<'a> {
426    /// Returns the size of this I/O region.
427    #[inline]
428    fn size(self) -> usize {
429        KnownSize::size(Self::Backend::as_ptr(self.as_view()))
430    }
431
432    /// Returns the length of the slice in number of elements.
433    #[inline]
434    fn len<T>(self) -> usize
435    where
436        Self: Io<'a, Target = [T]>,
437    {
438        Self::Backend::as_ptr(self.as_view()).len()
439    }
440
441    /// Returns `true` if the slice has a length of 0.
442    #[inline]
443    fn is_empty<T>(self) -> bool
444    where
445        Self: Io<'a, Target = [T]>,
446    {
447        self.len() == 0
448    }
449
450    /// Convert into a different typed I/O view.
451    ///
452    /// The target type must be known (statically) to be of the same or smaller size to current
453    /// type, and the current view must be properly aligned for the target type.
454    ///
455    /// # Examples
456    ///
457    /// ```no_run
458    /// use kernel::io::{
459    ///     io_project,
460    ///     Mmio,
461    ///     Io,
462    ///     Region,
463    /// };
464    /// #[derive(FromBytes, IntoBytes)]
465    /// #[repr(C)]
466    /// struct MyStruct { field: u32, }
467    ///
468    /// # fn test(mmio: &Mmio<'_, Region<0x1000>>) {
469    /// // let mmio: Mmio<'_, Region<0x1000>>;
470    /// let whole: Mmio<'_, MyStruct> = mmio.cast();
471    /// # }
472    /// ```
473    #[inline]
474    fn cast<U>(self) -> <Self::Backend as IoBackend>::View<'a, U>
475    where
476        Self::Target: FromBytes + IntoBytes,
477        U: FromBytes + IntoBytes,
478    {
479        let view = self.as_view();
480        let ptr = Self::Backend::as_ptr(view);
481
482        const_assert!(size_of::<U>() <= Self::Target::MIN_SIZE);
483        const_assert!(align_of::<U>() <= Self::Target::MIN_ALIGN.as_usize());
484
485        // SAFETY: We have checked bounds and alignment, so this is a valid projection.
486        unsafe { Self::Backend::project_view(view, ptr.cast()) }
487    }
488
489    /// Try to convert into a different typed I/O view.
490    ///
491    /// A runtime check is performed to ensure that the target type is of same or smaller size to
492    /// current type, and the current view is properly aligned for the target type. Returns
493    /// `Err(EINVAL)` if the runtime check fails.
494    ///
495    /// # Examples
496    ///
497    /// ```no_run
498    /// use kernel::io::{
499    ///     io_project,
500    ///     Mmio,
501    ///     Io,
502    ///     Region,
503    /// };
504    /// #[derive(FromBytes, IntoBytes)]
505    /// #[repr(C)]
506    /// struct MyStruct { field: u32, }
507    ///
508    /// # fn test(mmio: &Mmio<'_, Region>) -> Result {
509    /// // let mmio: Mmio<'_, Region>;
510    /// let whole: Mmio<'_, MyStruct> = mmio.try_cast()?;
511    /// # Ok::<(), Error>(()) }
512    /// ```
513    #[inline]
514    fn try_cast<U>(self) -> Result<<Self::Backend as IoBackend>::View<'a, U>>
515    where
516        Self::Target: FromBytes + IntoBytes,
517        U: FromBytes + IntoBytes,
518    {
519        let view = self.as_view();
520        let ptr = Self::Backend::as_ptr(view);
521
522        if size_of::<U>() > KnownSize::size(ptr) {
523            return Err(EINVAL);
524        }
525
526        if ptr.addr() % align_of::<U>() != 0 {
527            return Err(EINVAL);
528        }
529
530        // SAFETY: We have checked bounds and alignment, so this is a valid projection.
531        Ok(unsafe { Self::Backend::project_view(view, ptr.cast()) })
532    }
533
534    /// Read a value from I/O.
535    ///
536    /// This only works for primitives supported by the I/O backend.
537    ///
538    /// # Examples
539    ///
540    /// ```no_run
541    /// # use kernel::io::*;
542    /// # fn test_read_val(mmio: Mmio<'_, u32>) {
543    /// // let mmio: Mmio<'_, u32>;
544    /// let val: u32 = mmio.read_val();
545    /// # }
546    /// ```
547    #[inline]
548    fn read_val(self) -> Self::Target
549    where
550        Self::Target: AsReprMut,
551        Self::Backend: IoCapable<<Self::Target as AsRepr>::Repr>,
552    {
553        Self::Target::from_repr(Self::Backend::io_read(io_view_as_repr(self)))
554    }
555
556    /// Write a value to I/O.
557    ///
558    /// This only works for primitives supported by the I/O backend.
559    ///
560    /// # Examples
561    ///
562    /// ```no_run
563    /// # use kernel::io::*;
564    /// # fn test_write_val(mmio: Mmio<'_, u32>) {
565    /// // let mmio: Mmio<'_, u32>;
566    /// mmio.write_val(1u32);
567    /// # }
568    /// ```
569    #[inline]
570    fn write_val(self, value: Self::Target)
571    where
572        Self::Target: AsRepr,
573        Self::Backend: IoCapable<<Self::Target as AsRepr>::Repr>,
574    {
575        Self::Backend::io_write(io_view_as_repr(self), Self::Target::into_repr(value))
576    }
577
578    /// Copy-read from I/O memory.
579    ///
580    /// This is equivalent to reading from the I/O memory with byte-wise copy, although the actual
581    /// implementation might be more efficient. There is no atomicity guarantee. Note that for some
582    /// backends (e.g. `Mmio`), this can read different value compared to [`read_val`] as
583    /// byte-swapping is not performed.
584    ///
585    /// [`read_val`]: Io::read_val
586    ///
587    /// # Examples
588    ///
589    /// ```no_run
590    /// # use kernel::io::*;
591    /// # fn test_copy_read(mmio: Mmio<'_, [u8; 6]>) {
592    /// // let mmio: Mmio<'_, [u8; 6]>;
593    /// let val: [u8; 6] = mmio.copy_read();
594    /// # }
595    /// ```
596    #[inline]
597    fn copy_read(self) -> Self::Target
598    where
599        Self::Backend: IoCopyable,
600        Self::Target: Sized + FromBytes,
601    {
602        Self::Backend::copy_read(self.as_view())
603    }
604
605    /// Copy-write to I/O memory.
606    ///
607    /// This is equivalent to writing to the I/O memory with byte-wise copy, although the actual
608    /// implementation might be more efficient. There is no atomicity guarantee. Note that for some
609    /// backends (e.g. `Mmio`), this can write different value compared to [`write_val`] as
610    /// byte-swapping is not performed.
611    ///
612    /// [`write_val`]: Io::write_val
613    ///
614    /// # Examples
615    ///
616    /// ```no_run
617    /// # use kernel::io::*;
618    /// # fn test_copy_write(mmio: Mmio<'_, [u8; 6]>) {
619    /// // let mmio: Mmio<'_, [u8; 6]>;
620    /// mmio.copy_write([0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF]);
621    /// # }
622    /// ```
623    #[inline]
624    fn copy_write(self, value: Self::Target)
625    where
626        Self::Backend: IoCopyable,
627        Self::Target: Sized + IntoBytes,
628    {
629        Self::Backend::copy_write(self.as_view(), value);
630    }
631
632    /// Copy bytes from `data` to I/O memory.
633    ///
634    /// # Panics
635    ///
636    /// This function will panic if the length of `self` differs from the length of `data`, similar
637    /// to [`[u8]::copy_from_slice`].
638    ///
639    /// # Examples
640    ///
641    /// ```no_run
642    /// # use kernel::io::*;
643    /// # fn test_copy_write(mmio: Mmio<'_, [u8]>) {
644    /// // let mmio: Mmio<'_, [u8]>;
645    /// mmio.copy_from_slice(&[0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF]);
646    /// # }
647    /// ```
648    #[inline]
649    fn copy_from_slice(self, data: &[u8])
650    where
651        Self::Backend: IoCopyable,
652        Self: Io<'a, Target = [u8]>,
653    {
654        assert_eq!(self.len(), data.len());
655
656        // SAFETY: `data.as_ptr()` is valid for read for `self.size()` bytes.
657        unsafe {
658            Self::Backend::copy_to_io(self.as_view(), data.as_ptr());
659        }
660    }
661
662    /// Copy bytes from I/O memory to `data`.
663    ///
664    /// # Panics
665    ///
666    /// This function will panic if the length of `self` differs from the length of `data`, similar
667    /// to [`[u8]::copy_from_slice`].
668    ///
669    /// # Examples
670    ///
671    /// ```no_run
672    /// # use kernel::io::*;
673    /// # fn test_copy_write(mmio: Mmio<'_, [u8]>) {
674    /// // let mmio: Mmio<'_, [u8]>;
675    /// let mut buf = [0; 6];
676    /// mmio.copy_to_slice(&mut buf);
677    /// # }
678    /// ```
679    #[inline]
680    fn copy_to_slice(self, data: &mut [u8])
681    where
682        Self::Backend: IoCopyable,
683        Self: Io<'a, Target = [u8]>,
684    {
685        assert_eq!(self.len(), data.len());
686
687        // SAFETY: `data.as_mut_ptr()` is valid for write for `self.size()` bytes.
688        unsafe {
689            Self::Backend::copy_from_io(self.as_view(), data.as_mut_ptr());
690        }
691    }
692
693    /// Fallible 8-bit read with runtime bounds check.
694    #[inline(always)]
695    fn try_read8(self, offset: usize) -> Result<u8>
696    where
697        usize: IoLoc<Self::Target, u8>,
698        Self::Backend: IoCapable<u8>,
699    {
700        self.try_read(offset)
701    }
702
703    /// Fallible 16-bit read with runtime bounds check.
704    #[inline(always)]
705    fn try_read16(self, offset: usize) -> Result<u16>
706    where
707        usize: IoLoc<Self::Target, u16>,
708        Self::Backend: IoCapable<u16>,
709    {
710        self.try_read(offset)
711    }
712
713    /// Fallible 32-bit read with runtime bounds check.
714    #[inline(always)]
715    fn try_read32(self, offset: usize) -> Result<u32>
716    where
717        usize: IoLoc<Self::Target, u32>,
718        Self::Backend: IoCapable<u32>,
719    {
720        self.try_read(offset)
721    }
722
723    /// Fallible 64-bit read with runtime bounds check.
724    #[inline(always)]
725    fn try_read64(self, offset: usize) -> Result<u64>
726    where
727        usize: IoLoc<Self::Target, u64>,
728        Self::Backend: IoCapable<u64>,
729    {
730        self.try_read(offset)
731    }
732
733    /// Fallible 8-bit write with runtime bounds check.
734    #[inline(always)]
735    fn try_write8(self, value: u8, offset: usize) -> Result
736    where
737        usize: IoLoc<Self::Target, u8>,
738        Self::Backend: IoCapable<u8>,
739    {
740        self.try_write(offset, value)
741    }
742
743    /// Fallible 16-bit write with runtime bounds check.
744    #[inline(always)]
745    fn try_write16(self, value: u16, offset: usize) -> Result
746    where
747        usize: IoLoc<Self::Target, u16>,
748        Self::Backend: IoCapable<u16>,
749    {
750        self.try_write(offset, value)
751    }
752
753    /// Fallible 32-bit write with runtime bounds check.
754    #[inline(always)]
755    fn try_write32(self, value: u32, offset: usize) -> Result
756    where
757        usize: IoLoc<Self::Target, u32>,
758        Self::Backend: IoCapable<u32>,
759    {
760        self.try_write(offset, value)
761    }
762
763    /// Fallible 64-bit write with runtime bounds check.
764    #[inline(always)]
765    fn try_write64(self, value: u64, offset: usize) -> Result
766    where
767        usize: IoLoc<Self::Target, u64>,
768        Self::Backend: IoCapable<u64>,
769    {
770        self.try_write(offset, value)
771    }
772
773    /// Infallible 8-bit read with compile-time bounds check.
774    ///
775    /// `offset` should be constant.
776    #[inline(always)]
777    fn read8(self, offset: usize) -> u8
778    where
779        usize: IoLoc<Self::Target, u8>,
780        Self::Backend: IoCapable<u8>,
781    {
782        self.read(offset)
783    }
784
785    /// Infallible 16-bit read with compile-time bounds check.
786    ///
787    /// `offset` should be constant.
788    #[inline(always)]
789    fn read16(self, offset: usize) -> u16
790    where
791        usize: IoLoc<Self::Target, u16>,
792        Self::Backend: IoCapable<u16>,
793    {
794        self.read(offset)
795    }
796
797    /// Infallible 32-bit read with compile-time bounds check.
798    ///
799    /// `offset` should be constant.
800    #[inline(always)]
801    fn read32(self, offset: usize) -> u32
802    where
803        usize: IoLoc<Self::Target, u32>,
804        Self::Backend: IoCapable<u32>,
805    {
806        self.read(offset)
807    }
808
809    /// Infallible 64-bit read with compile-time bounds check.
810    ///
811    /// `offset` should be constant.
812    #[inline(always)]
813    fn read64(self, offset: usize) -> u64
814    where
815        usize: IoLoc<Self::Target, u64>,
816        Self::Backend: IoCapable<u64>,
817    {
818        self.read(offset)
819    }
820
821    /// Infallible 8-bit write with compile-time bounds check.
822    ///
823    /// `offset` should be constant.
824    #[inline(always)]
825    fn write8(self, value: u8, offset: usize)
826    where
827        usize: IoLoc<Self::Target, u8>,
828        Self::Backend: IoCapable<u8>,
829    {
830        self.write(offset, value)
831    }
832
833    /// Infallible 16-bit write with compile-time bounds check.
834    ///
835    /// `offset` should be constant.
836    #[inline(always)]
837    fn write16(self, value: u16, offset: usize)
838    where
839        usize: IoLoc<Self::Target, u16>,
840        Self::Backend: IoCapable<u16>,
841    {
842        self.write(offset, value)
843    }
844
845    /// Infallible 32-bit write with compile-time bounds check.
846    ///
847    /// `offset` should be constant.
848    #[inline(always)]
849    fn write32(self, value: u32, offset: usize)
850    where
851        usize: IoLoc<Self::Target, u32>,
852        Self::Backend: IoCapable<u32>,
853    {
854        self.write(offset, value)
855    }
856
857    /// Infallible 64-bit write with compile-time bounds check.
858    ///
859    /// `offset` should be constant.
860    #[inline(always)]
861    fn write64(self, value: u64, offset: usize)
862    where
863        usize: IoLoc<Self::Target, u64>,
864        Self::Backend: IoCapable<u64>,
865    {
866        self.write(offset, value)
867    }
868
869    /// Generic fallible read with runtime bounds check.
870    ///
871    /// # Examples
872    ///
873    /// Read a primitive type from an I/O address:
874    ///
875    /// ```no_run
876    /// use kernel::io::{
877    ///     Io,
878    ///     Mmio,
879    ///     Region,
880    /// };
881    ///
882    /// fn do_reads(io: Mmio<'_, Region>) -> Result {
883    ///     // 32-bit read from address `0x10`.
884    ///     let v: u32 = io.try_read(0x10)?;
885    ///
886    ///     // 8-bit read from address `0xfff`.
887    ///     let v: u8 = io.try_read(0xfff)?;
888    ///
889    ///     Ok(())
890    /// }
891    /// ```
892    #[inline(always)]
893    fn try_read<T, L>(self, location: L) -> Result<T>
894    where
895        T: AsReprMut,
896        L: IoLoc<Self::Target, T>,
897        Self::Backend: IoCapable<<T as AsRepr>::Repr>,
898    {
899        Ok(io_read!(self, try: location))
900    }
901
902    /// Generic fallible write with runtime bounds check.
903    ///
904    /// # Examples
905    ///
906    /// Write a primitive type to an I/O address:
907    ///
908    /// ```no_run
909    /// use kernel::io::{
910    ///     Io,
911    ///     Mmio,
912    ///     Region,
913    /// };
914    ///
915    /// fn do_writes(io: Mmio<'_, Region>) -> Result {
916    ///     // 32-bit write of value `1` at address `0x10`.
917    ///     io.try_write(0x10, 1u32)?;
918    ///
919    ///     // 8-bit write of value `0xff` at address `0xfff`.
920    ///     io.try_write(0xfff, 0xffu8)?;
921    ///
922    ///     Ok(())
923    /// }
924    /// ```
925    #[inline(always)]
926    fn try_write<T, L>(self, location: L, value: T) -> Result
927    where
928        T: AsRepr,
929        L: IoLoc<Self::Target, T>,
930        Self::Backend: IoCapable<<T as AsRepr>::Repr>,
931    {
932        io_write!(self, try: location, value);
933        Ok(())
934    }
935
936    /// Generic fallible write of a fully-located register value.
937    ///
938    /// # Examples
939    ///
940    /// Tuples carrying a location and a value can be used with this method:
941    ///
942    /// ```no_run
943    /// use kernel::io::{
944    ///     register,
945    ///     Io,
946    ///     Mmio,
947    ///     Region,
948    /// };
949    ///
950    /// register! {
951    ///     base: Region;
952    ///
953    ///     VERSION(u32) @ 0x100 {
954    ///         15:8 major;
955    ///         7:0  minor;
956    ///     }
957    /// }
958    ///
959    /// impl VERSION {
960    ///     fn new(major: u8, minor: u8) -> Self {
961    ///         VERSION::zeroed().with_major(major).with_minor(minor)
962    ///     }
963    /// }
964    ///
965    /// fn do_write_reg(io: Mmio<'_, Region>) -> Result {
966    ///
967    ///     io.try_write_reg(VERSION::new(1, 0))
968    /// }
969    /// ```
970    #[inline(always)]
971    fn try_write_reg<T, L, V>(self, value: V) -> Result
972    where
973        T: AsRepr,
974        L: IoLoc<Self::Target, T>,
975        V: LocatedRegister<Self::Target, Location = L, Value = T>,
976        Self::Backend: IoCapable<<T as AsRepr>::Repr>,
977    {
978        let (location, value) = value.into_io_op();
979
980        self.try_write(location, value)
981    }
982
983    /// Generic fallible update with runtime bounds check.
984    ///
985    /// Note: this does not perform any synchronization. The caller is responsible for ensuring
986    /// exclusive access if required.
987    ///
988    /// # Examples
989    ///
990    /// Read the u32 value at address `0x10`, increment it, and store the updated value back:
991    ///
992    /// ```no_run
993    /// use kernel::io::{
994    ///     Io,
995    ///     Mmio,
996    ///     Region,
997    /// };
998    ///
999    /// fn do_update(io: Mmio<'_, Region<0x1000>>) -> Result {
1000    ///     io.try_update(0x10, |v: u32| {
1001    ///         v + 1
1002    ///     })
1003    /// }
1004    /// ```
1005    #[inline(always)]
1006    fn try_update<T, L, F>(self, location: L, f: F) -> Result
1007    where
1008        T: AsReprMut,
1009        L: IoLoc<Self::Target, T>,
1010        Self::Backend: IoCapable<<T as AsRepr>::Repr>,
1011        F: FnOnce(T) -> T,
1012    {
1013        let view = io_project!(self, try: location);
1014        view.write_val(f(view.read_val()));
1015        Ok(())
1016    }
1017
1018    /// Generic infallible read with compile-time bounds check.
1019    ///
1020    /// # Examples
1021    ///
1022    /// Read a primitive type from an I/O address:
1023    ///
1024    /// ```no_run
1025    /// use kernel::io::{
1026    ///     Io,
1027    ///     Mmio,
1028    ///     Region,
1029    /// };
1030    ///
1031    /// fn do_reads(io: Mmio<'_, Region<0x1000>>) {
1032    ///     // 32-bit read from address `0x10`.
1033    ///     let v: u32 = io.read(0x10);
1034    ///
1035    ///     // 8-bit read from the top of the I/O space.
1036    ///     let v: u8 = io.read(0xfff);
1037    /// }
1038    /// ```
1039    #[inline(always)]
1040    fn read<T, L>(self, location: L) -> T
1041    where
1042        T: AsReprMut,
1043        L: IoLoc<Self::Target, T>,
1044        Self::Backend: IoCapable<<T as AsRepr>::Repr>,
1045    {
1046        io_read!(self, build: location)
1047    }
1048
1049    /// Generic infallible write with compile-time bounds check.
1050    ///
1051    /// # Examples
1052    ///
1053    /// Write a primitive type to an I/O address:
1054    ///
1055    /// ```no_run
1056    /// use kernel::io::{
1057    ///     Io,
1058    ///     Mmio,
1059    ///     Region,
1060    /// };
1061    ///
1062    /// fn do_writes(io: Mmio<'_, Region<0x1000>>) {
1063    ///     // 32-bit write of value `1` at address `0x10`.
1064    ///     io.write(0x10, 1u32);
1065    ///
1066    ///     // 8-bit write of value `0xff` at the top of the I/O space.
1067    ///     io.write(0xfff, 0xffu8);
1068    /// }
1069    /// ```
1070    #[inline(always)]
1071    fn write<T, L>(self, location: L, value: T)
1072    where
1073        T: AsRepr,
1074        L: IoLoc<Self::Target, T>,
1075        Self::Backend: IoCapable<<T as AsRepr>::Repr>,
1076    {
1077        io_write!(self, build: location, value);
1078    }
1079
1080    /// Generic infallible write of a fully-located register value.
1081    ///
1082    /// # Examples
1083    ///
1084    /// Tuples carrying a location and a value can be used with this method:
1085    ///
1086    /// ```no_run
1087    /// use kernel::io::{
1088    ///     register,
1089    ///     Io,
1090    ///     Mmio,
1091    ///     Region,
1092    /// };
1093    ///
1094    /// register! {
1095    ///     base: Region<0x1000>;
1096    ///
1097    ///     VERSION(u32) @ 0x100 {
1098    ///         15:8 major;
1099    ///         7:0  minor;
1100    ///     }
1101    /// }
1102    ///
1103    /// impl VERSION {
1104    ///     fn new(major: u8, minor: u8) -> Self {
1105    ///         VERSION::zeroed().with_major(major).with_minor(minor)
1106    ///     }
1107    /// }
1108    ///
1109    /// fn do_write_reg(io: Mmio<'_, Region<0x1000>>) {
1110    ///     io.write_reg(VERSION::new(1, 0));
1111    /// }
1112    /// ```
1113    #[inline(always)]
1114    fn write_reg<T, L, V>(self, value: V)
1115    where
1116        T: AsRepr,
1117        L: IoLoc<Self::Target, T>,
1118        V: LocatedRegister<Self::Target, Location = L, Value = T>,
1119        Self::Backend: IoCapable<<T as AsRepr>::Repr>,
1120    {
1121        let (location, value) = value.into_io_op();
1122
1123        self.write(location, value)
1124    }
1125
1126    /// Generic infallible update with compile-time bounds check.
1127    ///
1128    /// Note: this does not perform any synchronization. The caller is responsible for ensuring
1129    /// exclusive access if required.
1130    ///
1131    /// # Examples
1132    ///
1133    /// Read the u32 value at address `0x10`, increment it, and store the updated value back:
1134    ///
1135    /// ```no_run
1136    /// use kernel::io::{
1137    ///     Io,
1138    ///     Mmio,
1139    ///     Region,
1140    /// };
1141    ///
1142    /// fn do_update(io: Mmio<'_, Region<0x1000>>) {
1143    ///     io.update(0x10, |v: u32| {
1144    ///         v + 1
1145    ///     })
1146    /// }
1147    /// ```
1148    #[inline(always)]
1149    fn update<T, L, F>(self, location: L, f: F)
1150    where
1151        T: AsReprMut,
1152        L: IoLoc<Self::Target, T>,
1153        Self::Backend: IoCapable<<T as AsRepr>::Repr>,
1154        F: FnOnce(T) -> T,
1155    {
1156        let view = io_project!(self, build: location);
1157        view.write_val(f(view.read_val()));
1158    }
1159}
1160
1161// Blanket implementation ensures that provided methods cannot be arbitrarily overridden by
1162// implementers, which is relied upon for correctness and soundness.
1163impl<'a, T: IoBase<'a>> Io<'a> for T {}
1164
1165/// A view of memory-mapped I/O region.
1166///
1167/// # Invariant
1168///
1169/// `ptr` points to a valid and aligned memory-mapped I/O region for the duration lifetime `'a`.
1170pub struct Mmio<'a, T: ?Sized> {
1171    ptr: *mut T,
1172    phantom: PhantomData<&'a ()>,
1173}
1174
1175impl<T: ?Sized> Copy for Mmio<'_, T> {}
1176impl<T: ?Sized> Clone for Mmio<'_, T> {
1177    #[inline]
1178    fn clone(&self) -> Self {
1179        *self
1180    }
1181}
1182
1183impl<'a, T: ?Sized> Mmio<'a, T> {
1184    /// Create a `Mmio`, providing the accessors to the MMIO mapping.
1185    ///
1186    /// # Safety
1187    ///
1188    /// `raw` represents a valid and aligned memory-mapped I/O region while `'a` is alive.
1189    #[inline]
1190    pub unsafe fn from_raw(raw: MmioRaw<T>) -> Self {
1191        // INVARIANT: Per safety requirement.
1192        Self {
1193            ptr: raw.ptr,
1194            phantom: PhantomData,
1195        }
1196    }
1197}
1198
1199// SAFETY: `Mmio<'_, T>` is conceptually `&T` but in I/O memory.
1200unsafe impl<T: ?Sized + Sync> Send for Mmio<'_, T> {}
1201
1202// SAFETY: `Mmio<'_, T>` is conceptually `&T` but in I/O memory.
1203unsafe impl<T: ?Sized + Sync> Sync for Mmio<'_, T> {}
1204
1205impl<'a, T: ?Sized + KnownSize> IoBase<'a> for Mmio<'a, T> {
1206    type Backend = MmioBackend;
1207    type Target = T;
1208
1209    #[inline]
1210    fn as_view(self) -> Mmio<'a, T> {
1211        self
1212    }
1213}
1214
1215/// I/O Backend for memory-mapped I/O.
1216pub struct MmioBackend;
1217
1218impl IoBackend for MmioBackend {
1219    type View<'a, T: ?Sized + KnownSize> = Mmio<'a, T>;
1220
1221    #[inline]
1222    fn as_ptr<'a, T: ?Sized + KnownSize>(view: Self::View<'a, T>) -> *mut T {
1223        view.ptr
1224    }
1225
1226    #[inline]
1227    unsafe fn project_view<'a, T: ?Sized + KnownSize, U: ?Sized + KnownSize>(
1228        _view: Self::View<'a, T>,
1229        ptr: *mut U,
1230    ) -> Self::View<'a, U> {
1231        // INVARIANT: Per safety requirement, `ptr` is projection from `view`, so it is also a valid
1232        // memory-mapped I/O region.
1233        Mmio {
1234            ptr,
1235            phantom: PhantomData,
1236        }
1237    }
1238}
1239
1240/// Implements [`IoCapable`] on `$backend` for `$ty` using `$read_fn` and `$write_fn`.
1241macro_rules! impl_mmio_io_capable {
1242    ($backend: ident, $ty:ty, $read_fn:ident, $write_fn:ident) => {
1243        impl IoCapable<$ty> for $backend {
1244            #[inline]
1245            fn io_read(view: <$backend as IoBackend>::View<'_, $ty>) -> $ty {
1246                // SAFETY: `$backend::as_ptr(view)` is a valid pointer for MMIO operations for both
1247                // `MmioBackend` and `RelaxedMmioBackend`.
1248                unsafe { bindings::$read_fn($backend::as_ptr(view).cast_const().cast()) }
1249            }
1250
1251            #[inline]
1252            fn io_write(view: <$backend as IoBackend>::View<'_, $ty>, value: $ty) {
1253                // SAFETY: `$backend::as_ptr(view)` is a valid pointer for MMIO operations for both
1254                // `MmioBackend` and `RelaxedMmioBackend`.
1255                unsafe { bindings::$write_fn(value, $backend::as_ptr(view).cast()) }
1256            }
1257        }
1258    };
1259}
1260
1261// MMIO regions support 8, 16, and 32-bit accesses.
1262impl_mmio_io_capable!(MmioBackend, u8, readb, writeb);
1263impl_mmio_io_capable!(MmioBackend, u16, readw, writew);
1264impl_mmio_io_capable!(MmioBackend, u32, readl, writel);
1265// MMIO regions on 64-bit systems also support 64-bit accesses.
1266#[cfg(CONFIG_64BIT)]
1267impl_mmio_io_capable!(MmioBackend, u64, readq, writeq);
1268
1269impl IoCopyable for MmioBackend {
1270    #[inline]
1271    unsafe fn copy_from_io(view: Self::View<'_, [u8]>, buffer: *mut u8) {
1272        // SAFETY:
1273        // - `view.ptr` is valid MMIO memory for `view.size()` bytes.
1274        // - `buffer` is valid for write for `view.size()` bytes.
1275        unsafe {
1276            bindings::memcpy_fromio(buffer.cast(), view.ptr.cast(), view.size());
1277        }
1278    }
1279
1280    #[inline]
1281    unsafe fn copy_to_io(view: Self::View<'_, [u8]>, buffer: *const u8) {
1282        // SAFETY:
1283        // - `view.ptr` is valid MMIO memory for `view.size()` bytes.
1284        // - `buffer` is valid for read for `view.size()` bytes.
1285        unsafe {
1286            bindings::memcpy_toio(view.ptr.cast(), buffer.cast(), view.size());
1287        }
1288    }
1289}
1290
1291/// [`Mmio`] but using relaxed accessors.
1292///
1293/// This type provides an implementation of [`Io`] that uses relaxed I/O MMIO operands instead of
1294/// the regular ones.
1295///
1296/// See [`Mmio::relaxed`] for a usage example.
1297pub struct RelaxedMmio<'a, T: ?Sized>(Mmio<'a, T>);
1298
1299impl<T: ?Sized> Copy for RelaxedMmio<'_, T> {}
1300impl<T: ?Sized> Clone for RelaxedMmio<'_, T> {
1301    #[inline]
1302    fn clone(&self) -> Self {
1303        *self
1304    }
1305}
1306
1307/// I/O Backend for memory-mapped I/O, with relaxed access semantics.
1308pub struct RelaxedMmioBackend;
1309
1310impl IoBackend for RelaxedMmioBackend {
1311    type View<'a, T: ?Sized + KnownSize> = RelaxedMmio<'a, T>;
1312
1313    #[inline]
1314    fn as_ptr<'a, T: ?Sized + KnownSize>(view: Self::View<'a, T>) -> *mut T {
1315        MmioBackend::as_ptr(view.0)
1316    }
1317
1318    #[inline]
1319    unsafe fn project_view<'a, T: ?Sized + KnownSize, U: ?Sized + KnownSize>(
1320        view: Self::View<'a, T>,
1321        ptr: *mut U,
1322    ) -> Self::View<'a, U> {
1323        // SAFETY: Per safety requirement.
1324        RelaxedMmio(unsafe { MmioBackend::project_view(view.0, ptr) })
1325    }
1326}
1327
1328impl<'a, T: ?Sized + KnownSize> IoBase<'a> for RelaxedMmio<'a, T> {
1329    type Backend = RelaxedMmioBackend;
1330    type Target = T;
1331
1332    #[inline]
1333    fn as_view(self) -> RelaxedMmio<'a, T> {
1334        self
1335    }
1336}
1337
1338impl<'a, T: ?Sized> Mmio<'a, T> {
1339    /// Returns a [`RelaxedMmio`] that performs relaxed I/O operations.
1340    ///
1341    /// Relaxed accessors do not provide ordering guarantees with respect to DMA or memory accesses
1342    /// and can be used when such ordering is not required.
1343    ///
1344    /// # Examples
1345    ///
1346    /// ```no_run
1347    /// use kernel::io::{
1348    ///     Io,
1349    ///     Mmio,
1350    ///     Region,
1351    ///     RelaxedMmio,
1352    /// };
1353    ///
1354    /// fn do_io(io: Mmio<'_, Region<0x100>>) {
1355    ///     // The access is performed using `readl_relaxed` instead of `readl`.
1356    ///     let v = io.relaxed().read32(0x10);
1357    /// }
1358    ///
1359    /// ```
1360    #[inline]
1361    pub fn relaxed(self) -> RelaxedMmio<'a, T> {
1362        RelaxedMmio(self)
1363    }
1364}
1365
1366// MMIO regions support 8, 16, and 32-bit accesses.
1367impl_mmio_io_capable!(RelaxedMmioBackend, u8, readb_relaxed, writeb_relaxed);
1368impl_mmio_io_capable!(RelaxedMmioBackend, u16, readw_relaxed, writew_relaxed);
1369impl_mmio_io_capable!(RelaxedMmioBackend, u32, readl_relaxed, writel_relaxed);
1370// MMIO regions on 64-bit systems also support 64-bit accesses.
1371#[cfg(CONFIG_64BIT)]
1372impl_mmio_io_capable!(RelaxedMmioBackend, u64, readq_relaxed, writeq_relaxed);
1373
1374/// I/O Backend for system memory.
1375pub struct SysMemBackend;
1376
1377impl IoBackend for SysMemBackend {
1378    type View<'a, T: ?Sized + KnownSize> = SysMem<'a, T>;
1379
1380    #[inline]
1381    fn as_ptr<'a, T: ?Sized + KnownSize>(view: Self::View<'a, T>) -> *mut T {
1382        view.ptr
1383    }
1384
1385    #[inline]
1386    unsafe fn project_view<'a, T: ?Sized + KnownSize, U: ?Sized + KnownSize>(
1387        _view: Self::View<'a, T>,
1388        ptr: *mut U,
1389    ) -> Self::View<'a, U> {
1390        // INVARIANT: Per safety requirement, `ptr` is projection from `view`, so it is also a valid
1391        // kernel accessible memory region.
1392        SysMem {
1393            ptr,
1394            phantom: PhantomData,
1395        }
1396    }
1397}
1398
1399/// Implements [`IoCapable`] on `SysMemBackend` for `$ty` using `read_volatile` and
1400/// `write_volatile`.
1401macro_rules! impl_sysmem_io_capable {
1402    ($ty:ty) => {
1403        impl IoCapable<$ty> for SysMemBackend {
1404            #[inline]
1405            fn io_read(view: SysMem<'_, $ty>) -> $ty {
1406                // SAFETY:
1407                // - Per type invariant, `ptr` is valid and aligned.
1408                // - Using read_volatile() here so that race with hardware is well-defined.
1409                // - Using read_volatile() here is not sound if it races with other CPU per Rust
1410                //   rules, but this is allowed per LKMM.
1411                // - The macro is only used on primitives so all bit patterns are valid.
1412                unsafe { view.ptr.read_volatile() }
1413            }
1414
1415            #[inline]
1416            fn io_write(view: SysMem<'_, $ty>, value: $ty) {
1417                // SAFETY:
1418                // - Per type invariant, `ptr` is valid and aligned.
1419                // - Using write_volatile() here so that race with hardware is well-defined.
1420                // - Using write_volatile() here is not sound if it races with other CPU per Rust
1421                //   rules, but this is allowed per LKMM.
1422                unsafe { view.ptr.write_volatile(value) }
1423            }
1424        }
1425    };
1426}
1427
1428impl_sysmem_io_capable!(u8);
1429impl_sysmem_io_capable!(u16);
1430impl_sysmem_io_capable!(u32);
1431#[cfg(CONFIG_64BIT)]
1432impl_sysmem_io_capable!(u64);
1433
1434impl IoCopyable for SysMemBackend {
1435    #[inline]
1436    unsafe fn copy_from_io(view: Self::View<'_, [u8]>, buffer: *mut u8) {
1437        // Use `bindings::memcpy` instead of `copy_nonoverlapping` for volatile.
1438        // SAFETY:
1439        // - `view.ptr` is in CPU address space and valid for read.
1440        // - `buffer` is valid for write for `view.size()` bytes which is equal to `view.ptr.len()`.
1441        unsafe { bindings::memcpy(buffer.cast(), view.ptr.cast(), view.ptr.len()) };
1442    }
1443
1444    #[inline]
1445    unsafe fn copy_to_io(view: Self::View<'_, [u8]>, buffer: *const u8) {
1446        // Use `bindings::memcpy` instead of `copy_nonoverlapping` for volatile.
1447        // SAFETY:
1448        // - `view.ptr` is in CPU address space and valid for write.
1449        // - `buffer` is valid for read for `view.size()` bytes which is equal to `view.ptr.len()`.
1450        unsafe { bindings::memcpy(view.ptr.cast(), buffer.cast(), view.ptr.len()) };
1451    }
1452
1453    #[inline]
1454    fn copy_read<T: FromBytes>(view: Self::View<'_, T>) -> T {
1455        // SAFETY:
1456        // - Per type invariant, `ptr` is valid and aligned.
1457        // - Using read_volatile() here so that race with hardware is well-defined.
1458        // - Using read_volatile() here is not sound if it races with other CPU per Rust
1459        //   rules, but this is allowed per LKMM.
1460        // - `T: FromBytes` so all bit patterns are valid.
1461        unsafe { view.ptr.read_volatile() }
1462    }
1463
1464    #[inline]
1465    fn copy_write<T: IntoBytes>(view: Self::View<'_, T>, value: T) {
1466        // SAFETY:
1467        // - Per type invariant, `ptr` is valid and aligned.
1468        // - Using write_volatile() here so that race with hardware is well-defined.
1469        // - Using write_volatile() here is not sound if it races with other CPU per Rust
1470        //   rules, but this is allowed per LKMM.
1471        unsafe { view.ptr.write_volatile(value) }
1472    }
1473}
1474
1475/// A view of a system memory region.
1476///
1477/// Provides `Io` trait implementation for kernel virtual address ranges,
1478/// using volatile read/write to safely access shared memory that may be
1479/// concurrently accessed by external hardware.
1480///
1481/// # Invariants
1482///
1483/// `self.ptr.addr() .. self.ptr.addr() + KnownSize::size(self.ptr)` is valid and aligned kernel
1484/// accessible memory region for the lifetime `'a`.
1485pub struct SysMem<'a, T: ?Sized> {
1486    ptr: *mut T,
1487    phantom: PhantomData<&'a ()>,
1488}
1489
1490impl<T: ?Sized> Copy for SysMem<'_, T> {}
1491impl<T: ?Sized> Clone for SysMem<'_, T> {
1492    #[inline]
1493    fn clone(&self) -> Self {
1494        *self
1495    }
1496}
1497
1498// SAFETY: `SysMem<'_, T>` is conceptually `&T`.
1499unsafe impl<T: ?Sized + Sync> Send for SysMem<'_, T> {}
1500
1501// SAFETY: `SysMem<'_, T>` is conceptually `&T`.
1502unsafe impl<T: ?Sized + Sync> Sync for SysMem<'_, T> {}
1503
1504impl<'a, T: ?Sized> SysMem<'a, T> {
1505    /// Create a `SysMem` from a raw pointer.
1506    ///
1507    /// # Safety
1508    ///
1509    /// `ptr.addr() .. ptr.addr() + KnownSize::size(ptr)` must be valid and aligned kernel
1510    /// accessible memory region for the lifetime `'a`.
1511    #[inline]
1512    pub unsafe fn new(ptr: *mut T) -> Self {
1513        // INVARIANT: Per safety requirement.
1514        Self {
1515            ptr,
1516            phantom: PhantomData,
1517        }
1518    }
1519
1520    /// Obtain the raw pointer to the memory.
1521    #[inline]
1522    pub fn as_ptr(self) -> *mut T {
1523        self.ptr
1524    }
1525}
1526
1527impl<'a, T: ?Sized + KnownSize> IoBase<'a> for SysMem<'a, T> {
1528    type Backend = SysMemBackend;
1529    type Target = T;
1530
1531    #[inline]
1532    fn as_view(self) -> <Self::Backend as IoBackend>::View<'a, Self::Target> {
1533        self
1534    }
1535}
1536
1537/// I/O Backend for [`IoSysMap`].
1538pub struct IoSysMapBackend;
1539
1540/// Either [`Mmio`] or [`SysMem`].
1541///
1542/// This can be used when a piece of logic may wish to handle both MMIO or system memory but does
1543/// not want or cannot be generic over I/O backends. This serves a similar purpose to
1544/// [`include/linux/iosys-map.h`] in C.
1545///
1546/// This type can be used like any other types that implements [`Io`]; this also include
1547/// [`io_project!`], [`io_read!`], [`io_write!`].
1548///
1549/// [`include/linux/iosys-map.h`]: srctree/include/linux/iosys-map.h
1550pub enum IoSysMap<'a, T: ?Sized> {
1551    /// The view is I/O memory.
1552    Io(Mmio<'a, T>),
1553    /// The view is system memory.
1554    Sys(SysMem<'a, T>),
1555}
1556
1557impl<T: ?Sized> Copy for IoSysMap<'_, T> {}
1558impl<T: ?Sized> Clone for IoSysMap<'_, T> {
1559    #[inline]
1560    fn clone(&self) -> Self {
1561        *self
1562    }
1563}
1564
1565impl<'a, T: ?Sized> From<Mmio<'a, T>> for IoSysMap<'a, T> {
1566    #[inline]
1567    fn from(value: Mmio<'a, T>) -> Self {
1568        IoSysMap::Io(value)
1569    }
1570}
1571
1572impl<'a, T: ?Sized> From<SysMem<'a, T>> for IoSysMap<'a, T> {
1573    #[inline]
1574    fn from(value: SysMem<'a, T>) -> Self {
1575        IoSysMap::Sys(value)
1576    }
1577}
1578
1579impl IoBackend for IoSysMapBackend {
1580    type View<'a, T: ?Sized + KnownSize> = IoSysMap<'a, T>;
1581
1582    #[inline]
1583    fn as_ptr<'a, T: ?Sized + KnownSize>(view: Self::View<'a, T>) -> *mut T {
1584        match view {
1585            IoSysMap::Io(l) => MmioBackend::as_ptr(l),
1586            IoSysMap::Sys(r) => SysMemBackend::as_ptr(r),
1587        }
1588    }
1589
1590    #[inline]
1591    unsafe fn project_view<'a, T: ?Sized + KnownSize, U: ?Sized + KnownSize>(
1592        view: Self::View<'a, T>,
1593        ptr: *mut U,
1594    ) -> Self::View<'a, U> {
1595        match view {
1596            // SAFETY: Per safety requirement.
1597            IoSysMap::Io(l) => IoSysMap::Io(unsafe { MmioBackend::project_view(l, ptr) }),
1598            // SAFETY: Per safety requirement.
1599            IoSysMap::Sys(r) => IoSysMap::Sys(unsafe { SysMemBackend::project_view(r, ptr) }),
1600        }
1601    }
1602}
1603
1604impl<T> IoCapable<T> for IoSysMapBackend
1605where
1606    MmioBackend: IoCapable<T>,
1607    SysMemBackend: IoCapable<T>,
1608{
1609    #[inline]
1610    fn io_read(view: Self::View<'_, T>) -> T {
1611        match view {
1612            IoSysMap::Io(l) => MmioBackend::io_read(l),
1613            IoSysMap::Sys(r) => SysMemBackend::io_read(r),
1614        }
1615    }
1616
1617    #[inline]
1618    fn io_write<'a>(view: Self::View<'a, T>, value: T) {
1619        match view {
1620            IoSysMap::Io(l) => MmioBackend::io_write(l, value),
1621            IoSysMap::Sys(r) => SysMemBackend::io_write(r, value),
1622        }
1623    }
1624}
1625
1626impl IoCopyable for IoSysMapBackend {
1627    #[inline]
1628    unsafe fn copy_from_io(view: Self::View<'_, [u8]>, buffer: *mut u8) {
1629        match view {
1630            // SAFETY: Per safety requirement.
1631            IoSysMap::Io(l) => unsafe { MmioBackend::copy_from_io(l, buffer) },
1632            // SAFETY: Per safety requirement.
1633            IoSysMap::Sys(r) => unsafe { SysMemBackend::copy_from_io(r, buffer) },
1634        }
1635    }
1636
1637    #[inline]
1638    unsafe fn copy_to_io(view: Self::View<'_, [u8]>, buffer: *const u8) {
1639        match view {
1640            // SAFETY: Per safety requirement.
1641            IoSysMap::Io(l) => unsafe { MmioBackend::copy_to_io(l, buffer) },
1642            // SAFETY: Per safety requirement.
1643            IoSysMap::Sys(r) => unsafe { SysMemBackend::copy_to_io(r, buffer) },
1644        }
1645    }
1646
1647    #[inline]
1648    fn copy_read<T: FromBytes>(view: Self::View<'_, T>) -> T {
1649        match view {
1650            IoSysMap::Io(l) => MmioBackend::copy_read(l),
1651            IoSysMap::Sys(r) => SysMemBackend::copy_read(r),
1652        }
1653    }
1654
1655    #[inline]
1656    fn copy_write<T: IntoBytes>(view: Self::View<'_, T>, value: T) {
1657        match view {
1658            IoSysMap::Io(l) => MmioBackend::copy_write(l, value),
1659            IoSysMap::Sys(r) => SysMemBackend::copy_write(r, value),
1660        }
1661    }
1662}
1663
1664impl<'a, T: ?Sized + KnownSize> IoBase<'a> for IoSysMap<'a, T> {
1665    type Backend = IoSysMapBackend;
1666    type Target = T;
1667
1668    #[inline]
1669    fn as_view(self) -> IoSysMap<'a, T> {
1670        self
1671    }
1672}
1673
1674// This helper turns associated functions to methods so it can be invoked in macro.
1675// Used by `io_project!()` only.
1676#[doc(hidden)]
1677#[derive(Clone, Copy)]
1678pub struct ProjectHelper<T>(pub T);
1679
1680impl<'a, T> ProjectHelper<T>
1681where
1682    T: Io<'a, Backend: IoBackend<View<'a, T::Target> = T>>,
1683{
1684    // These helper methods must not have symbols present in the binary to avoid confusion.
1685    #[inline(always)]
1686    pub fn as_ptr(self) -> *mut T::Target {
1687        T::Backend::as_ptr(self.0)
1688    }
1689
1690    /// # Safety
1691    ///
1692    /// Same as `IoBackend::project_view`
1693    #[inline(always)]
1694    pub unsafe fn project_view<U: ?Sized + KnownSize>(
1695        self,
1696        ptr: *mut U,
1697    ) -> <T::Backend as IoBackend>::View<'a, U> {
1698        // SAFETY: Per safety requirement.
1699        unsafe { T::Backend::project_view::<T::Target, _>(self.0, ptr) }
1700    }
1701
1702    #[inline(always)]
1703    pub fn try_project_loc<U, L>(
1704        self,
1705        location: L,
1706    ) -> Result<<T::Backend as IoBackend>::View<'a, U>>
1707    where
1708        L: IoLoc<T::Target, U>,
1709    {
1710        io_view::<_, U>(self.0, location.offset())
1711    }
1712
1713    #[inline(always)]
1714    pub fn project_loc<U, L>(self, location: L) -> <T::Backend as IoBackend>::View<'a, U>
1715    where
1716        L: IoLoc<T::Target, U>,
1717    {
1718        io_view_assert::<_, U>(self.0, location.offset())
1719    }
1720}
1721
1722/// Project an I/O type to a subview of it.
1723///
1724/// The syntax is of form `io_project!(io, proj)` where `io` is an expression to a type that
1725/// implements [`Io`] and `proj` is a [projection specification](kernel::ptr::project!).
1726///
1727/// `io_project!` can also project to a subview of registers defined with [`register!`] macro.
1728/// Register projection has syntax `io_project!(io, try: REGISTER)` for fallible projection and
1729/// `io_project!(io, build: REGISTER)` for infallible projection.
1730///
1731/// # Examples
1732///
1733/// ```
1734/// use kernel::io::{
1735///     io_project,
1736///     register,
1737///     Mmio,
1738/// };
1739/// #[repr(C)]
1740/// struct MyStruct { field: u32, }
1741///
1742/// register! {
1743///     base: MyStruct;
1744///     FIELD(u32) @ 0 {
1745///         31:0 val;
1746///     }
1747/// }
1748///
1749/// # fn test(mmio: Mmio<'_, [MyStruct]>) -> Result {
1750/// // let mmio: Mmio<[MyStruct]>;
1751/// let field: Mmio<'_, u32> = io_project!(mmio, [try: 1].field);
1752/// let whole: Mmio<'_, MyStruct> = io_project!(mmio, [try: 2]);
1753/// let nested: Mmio<'_, u32> = io_project!(whole, .field);
1754/// let reg: Mmio<'_, FIELD> = io_project!(whole, build: FIELD);
1755/// # Ok::<(), Error>(()) }
1756/// ```
1757#[macro_export]
1758#[doc(hidden)]
1759macro_rules! io_project {
1760    // Register projection
1761    ($io:expr, try: $ioloc:expr) => {{
1762        #[allow(unused)]
1763        use $crate::io::IoBase as _;
1764        let view = $crate::io::ProjectHelper($io.as_view());
1765        view.try_project_loc($ioloc)?
1766    }};
1767    ($io:expr, build: $ioloc:expr) => {{
1768        #[allow(unused)]
1769        use $crate::io::IoBase as _;
1770        let view = $crate::io::ProjectHelper($io.as_view());
1771        view.project_loc($ioloc)
1772    }};
1773
1774    // Field or index projection
1775    ($io:expr, $($proj:tt)*) => {{
1776        #[allow(unused)]
1777        use $crate::io::IoBase as _;
1778        let view = $crate::io::ProjectHelper($io.as_view());
1779        let ptr = $crate::ptr::project!(
1780            mut view.as_ptr(), $($proj)*
1781        );
1782        #[allow(unused_unsafe)]
1783        // SAFETY: `ptr` is a projection.
1784        unsafe { view.project_view(ptr) }
1785    }};
1786}
1787#[doc(inline)]
1788pub use crate::io_project;
1789
1790/// Read from I/O memory.
1791///
1792/// The syntax is of form `io_read!(io, proj)` where `io` is an expression to a type that
1793/// implements [`Io`] and `proj` is a [projection specification](kernel::ptr::project!).
1794///
1795/// # Examples
1796///
1797/// ```
1798/// #[repr(C)]
1799/// struct MyStruct { field: u32, }
1800///
1801/// # fn test(mmio: kernel::io::Mmio<'_, [MyStruct]>) -> Result {
1802/// // let mmio: Mmio<'_, [MyStruct]>;
1803/// let field: u32 = kernel::io::io_read!(mmio, [try: 2].field);
1804/// # Ok::<(), Error>(()) }
1805/// ```
1806#[macro_export]
1807#[doc(hidden)]
1808macro_rules! io_read {
1809    ($io:expr, $($proj:tt)*) => {
1810        $crate::io::Io::read_val($crate::io_project!($io, $($proj)*))
1811    };
1812}
1813#[doc(inline)]
1814pub use crate::io_read;
1815
1816/// Writes to I/O memory.
1817///
1818/// The syntax is of form `io_write!(io, proj, val)` where `io` is an expression to a type that
1819/// implements [`Io`] and `proj` is a [projection specification](kernel::ptr::project!),
1820/// and `val` is the value to be written to the projected location.
1821///
1822/// # Examples
1823///
1824/// ```
1825/// #[repr(C)]
1826/// struct MyStruct { field: u32, }
1827///
1828/// # fn test(mmio: kernel::io::Mmio<'_, [MyStruct]>) -> Result {
1829/// // let mmio: Mmio<'_, [MyStruct]>;
1830/// kernel::io::io_write!(mmio, [try: 2].field, 10);
1831/// # Ok::<(), Error>(()) }
1832/// ```
1833#[macro_export]
1834#[doc(hidden)]
1835macro_rules! io_write {
1836    (@parse [$io:expr] [$($proj:tt)*] [, $val:expr]) => {
1837        $crate::io::Io::write_val($crate::io_project!($io, $($proj)*), $val)
1838    };
1839    (@parse [$io:expr] [$($proj:tt)*] [.$field:tt $($rest:tt)*]) => {
1840        $crate::io_write!(@parse [$io] [$($proj)* .$field] [$($rest)*])
1841    };
1842    (@parse [$io:expr] [$($proj:tt)*] [[$flavor:ident: $index:expr] $($rest:tt)*]) => {
1843        $crate::io_write!(@parse [$io] [$($proj)* [$flavor: $index]] [$($rest)*])
1844    };
1845    (@parse [$io:expr] [] [try: $ioloc:expr, $($rest:tt)*]) => {
1846        $crate::io_write!(@parse [$io] [try: $ioloc] [, $($rest)*])
1847    };
1848    (@parse [$io:expr] [] [build: $ioloc:expr, $($rest:tt)*]) => {
1849        $crate::io_write!(@parse [$io] [build: $ioloc] [, $($rest)*])
1850    };
1851    ($io:expr, $($rest:tt)*) => {
1852        $crate::io_write!(@parse [$io] [] [$($rest)*])
1853    };
1854}
1855#[doc(inline)]
1856pub use crate::io_write;