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