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