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