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