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 crate::{ 8 bindings, 9 prelude::*, // 10 }; 11 12 pub mod mem; 13 pub mod poll; 14 pub mod resource; 15 16 pub use resource::Resource; 17 18 /// Physical address type. 19 /// 20 /// This is a type alias to either `u32` or `u64` depending on the config option 21 /// `CONFIG_PHYS_ADDR_T_64BIT`, and it can be a u64 even on 32-bit architectures. 22 pub type PhysAddr = bindings::phys_addr_t; 23 24 /// Resource Size type. 25 /// 26 /// This is a type alias to either `u32` or `u64` depending on the config option 27 /// `CONFIG_PHYS_ADDR_T_64BIT`, and it can be a u64 even on 32-bit architectures. 28 pub type ResourceSize = bindings::resource_size_t; 29 30 /// Raw representation of an MMIO region. 31 /// 32 /// By itself, the existence of an instance of this structure does not provide any guarantees that 33 /// the represented MMIO region does exist or is properly mapped. 34 /// 35 /// Instead, the bus specific MMIO implementation must convert this raw representation into an 36 /// `Mmio` instance providing the actual memory accessors. Only by the conversion into an `Mmio` 37 /// structure any guarantees are given. 38 pub struct MmioRaw<const SIZE: usize = 0> { 39 addr: usize, 40 maxsize: usize, 41 } 42 43 impl<const SIZE: usize> MmioRaw<SIZE> { 44 /// Returns a new `MmioRaw` instance on success, an error otherwise. 45 pub fn new(addr: usize, maxsize: usize) -> Result<Self> { 46 if maxsize < SIZE { 47 return Err(EINVAL); 48 } 49 50 Ok(Self { addr, maxsize }) 51 } 52 53 /// Returns the base address of the MMIO region. 54 #[inline] 55 pub fn addr(&self) -> usize { 56 self.addr 57 } 58 59 /// Returns the maximum size of the MMIO region. 60 #[inline] 61 pub fn maxsize(&self) -> usize { 62 self.maxsize 63 } 64 } 65 66 /// IO-mapped memory region. 67 /// 68 /// The creator (usually a subsystem / bus such as PCI) is responsible for creating the 69 /// mapping, performing an additional region request etc. 70 /// 71 /// # Invariant 72 /// 73 /// `addr` is the start and `maxsize` the length of valid I/O mapped memory region of size 74 /// `maxsize`. 75 /// 76 /// # Examples 77 /// 78 /// ```no_run 79 /// use kernel::{ 80 /// bindings, 81 /// ffi::c_void, 82 /// io::{ 83 /// Io, 84 /// IoKnownSize, 85 /// Mmio, 86 /// MmioRaw, 87 /// PhysAddr, 88 /// }, 89 /// }; 90 /// use core::ops::Deref; 91 /// 92 /// // See also `pci::Bar` for a real example. 93 /// struct IoMem<const SIZE: usize>(MmioRaw<SIZE>); 94 /// 95 /// impl<const SIZE: usize> IoMem<SIZE> { 96 /// /// # Safety 97 /// /// 98 /// /// [`paddr`, `paddr` + `SIZE`) must be a valid MMIO region that is mappable into the CPUs 99 /// /// virtual address space. 100 /// unsafe fn new(paddr: usize) -> Result<Self>{ 101 /// // SAFETY: By the safety requirements of this function [`paddr`, `paddr` + `SIZE`) is 102 /// // valid for `ioremap`. 103 /// let addr = unsafe { bindings::ioremap(paddr as PhysAddr, SIZE) }; 104 /// if addr.is_null() { 105 /// return Err(ENOMEM); 106 /// } 107 /// 108 /// Ok(IoMem(MmioRaw::new(addr as usize, SIZE)?)) 109 /// } 110 /// } 111 /// 112 /// impl<const SIZE: usize> Drop for IoMem<SIZE> { 113 /// fn drop(&mut self) { 114 /// // SAFETY: `self.0.addr()` is guaranteed to be properly mapped by `Self::new`. 115 /// unsafe { bindings::iounmap(self.0.addr() as *mut c_void); }; 116 /// } 117 /// } 118 /// 119 /// impl<const SIZE: usize> Deref for IoMem<SIZE> { 120 /// type Target = Mmio<SIZE>; 121 /// 122 /// fn deref(&self) -> &Self::Target { 123 /// // SAFETY: The memory range stored in `self` has been properly mapped in `Self::new`. 124 /// unsafe { Mmio::from_raw(&self.0) } 125 /// } 126 /// } 127 /// 128 ///# fn no_run() -> Result<(), Error> { 129 /// // SAFETY: Invalid usage for example purposes. 130 /// let iomem = unsafe { IoMem::<{ core::mem::size_of::<u32>() }>::new(0xBAAAAAAD)? }; 131 /// iomem.write32(0x42, 0x0); 132 /// assert!(iomem.try_write32(0x42, 0x0).is_ok()); 133 /// assert!(iomem.try_write32(0x42, 0x4).is_err()); 134 /// # Ok(()) 135 /// # } 136 /// ``` 137 #[repr(transparent)] 138 pub struct Mmio<const SIZE: usize = 0>(MmioRaw<SIZE>); 139 140 /// Internal helper macros used to invoke C MMIO read functions. 141 /// 142 /// This macro is intended to be used by higher-level MMIO access macros (io_define_read) and 143 /// provides a unified expansion for infallible vs. fallible read semantics. It emits a direct call 144 /// into the corresponding C helper and performs the required cast to the Rust return type. 145 /// 146 /// # Parameters 147 /// 148 /// * `$c_fn` – The C function performing the MMIO read. 149 /// * `$self` – The I/O backend object. 150 /// * `$ty` – The type of the value to be read. 151 /// * `$addr` – The MMIO address to read. 152 /// 153 /// This macro does not perform any validation; all invariants must be upheld by the higher-level 154 /// abstraction invoking it. 155 macro_rules! call_mmio_read { 156 (infallible, $c_fn:ident, $self:ident, $type:ty, $addr:expr) => { 157 // SAFETY: By the type invariant `addr` is a valid address for MMIO operations. 158 unsafe { bindings::$c_fn($addr as *const c_void) as $type } 159 }; 160 161 (fallible, $c_fn:ident, $self:ident, $type:ty, $addr:expr) => {{ 162 // SAFETY: By the type invariant `addr` is a valid address for MMIO operations. 163 Ok(unsafe { bindings::$c_fn($addr as *const c_void) as $type }) 164 }}; 165 } 166 167 /// Internal helper macros used to invoke C MMIO write functions. 168 /// 169 /// This macro is intended to be used by higher-level MMIO access macros (io_define_write) and 170 /// provides a unified expansion for infallible vs. fallible write semantics. It emits a direct call 171 /// into the corresponding C helper and performs the required cast to the Rust return type. 172 /// 173 /// # Parameters 174 /// 175 /// * `$c_fn` – The C function performing the MMIO write. 176 /// * `$self` – The I/O backend object. 177 /// * `$ty` – The type of the written value. 178 /// * `$addr` – The MMIO address to write. 179 /// * `$value` – The value to write. 180 /// 181 /// This macro does not perform any validation; all invariants must be upheld by the higher-level 182 /// abstraction invoking it. 183 macro_rules! call_mmio_write { 184 (infallible, $c_fn:ident, $self:ident, $ty:ty, $addr:expr, $value:expr) => { 185 // SAFETY: By the type invariant `addr` is a valid address for MMIO operations. 186 unsafe { bindings::$c_fn($value, $addr as *mut c_void) } 187 }; 188 189 (fallible, $c_fn:ident, $self:ident, $ty:ty, $addr:expr, $value:expr) => {{ 190 // SAFETY: By the type invariant `addr` is a valid address for MMIO operations. 191 unsafe { bindings::$c_fn($value, $addr as *mut c_void) }; 192 Ok(()) 193 }}; 194 } 195 196 /// Generates an accessor method for reading from an I/O backend. 197 /// 198 /// This macro reduces boilerplate by automatically generating either compile-time bounds-checked 199 /// (infallible) or runtime bounds-checked (fallible) read methods. It abstracts the address 200 /// calculation and bounds checking, and delegates the actual I/O read operation to a specified 201 /// helper macro, making it generic over different I/O backends. 202 /// 203 /// # Parameters 204 /// 205 /// * `infallible` / `fallible` - Determines the bounds-checking strategy. `infallible` relies on 206 /// `IoKnownSize` for compile-time checks and returns the value directly. `fallible` performs 207 /// runtime checks against `maxsize()` and returns a `Result<T>`. 208 /// * `$(#[$attr:meta])*` - Optional attributes to apply to the generated method (e.g., 209 /// `#[cfg(CONFIG_64BIT)]` or inline directives). 210 /// * `$vis:vis` - The visibility of the generated method (e.g., `pub`). 211 /// * `$name:ident` / `$try_name:ident` - The name of the generated method (e.g., `read32`, 212 /// `try_read8`). 213 /// * `$call_macro:ident` - The backend-specific helper macro used to emit the actual I/O call 214 /// (e.g., `call_mmio_read`). 215 /// * `$c_fn:ident` - The backend-specific C function or identifier to be passed into the 216 /// `$call_macro`. 217 /// * `$type_name:ty` - The Rust type of the value being read (e.g., `u8`, `u32`). 218 #[macro_export] 219 macro_rules! io_define_read { 220 (infallible, $(#[$attr:meta])* $vis:vis $name:ident, $call_macro:ident($c_fn:ident) -> 221 $type_name:ty) => { 222 /// Read IO data from a given offset known at compile time. 223 /// 224 /// Bound checks are performed on compile time, hence if the offset is not known at compile 225 /// time, the build will fail. 226 $(#[$attr])* 227 // Always inline to optimize out error path of `io_addr_assert`. 228 #[inline(always)] 229 $vis fn $name(&self, offset: usize) -> $type_name { 230 let addr = self.io_addr_assert::<$type_name>(offset); 231 232 // SAFETY: By the type invariant `addr` is a valid address for IO operations. 233 $call_macro!(infallible, $c_fn, self, $type_name, addr) 234 } 235 }; 236 237 (fallible, $(#[$attr:meta])* $vis:vis $try_name:ident, $call_macro:ident($c_fn:ident) -> 238 $type_name:ty) => { 239 /// Read IO data from a given offset. 240 /// 241 /// Bound checks are performed on runtime, it fails if the offset (plus the type size) is 242 /// out of bounds. 243 $(#[$attr])* 244 $vis fn $try_name(&self, offset: usize) -> Result<$type_name> { 245 let addr = self.io_addr::<$type_name>(offset)?; 246 247 // SAFETY: By the type invariant `addr` is a valid address for IO operations. 248 $call_macro!(fallible, $c_fn, self, $type_name, addr) 249 } 250 }; 251 } 252 pub use io_define_read; 253 254 /// Generates an accessor method for writing to an I/O backend. 255 /// 256 /// This macro reduces boilerplate by automatically generating either compile-time bounds-checked 257 /// (infallible) or runtime bounds-checked (fallible) write methods. It abstracts the address 258 /// calculation and bounds checking, and delegates the actual I/O write operation to a specified 259 /// helper macro, making it generic over different I/O backends. 260 /// 261 /// # Parameters 262 /// 263 /// * `infallible` / `fallible` - Determines the bounds-checking strategy. `infallible` relies on 264 /// `IoKnownSize` for compile-time checks and returns `()`. `fallible` performs runtime checks 265 /// against `maxsize()` and returns a `Result`. 266 /// * `$(#[$attr:meta])*` - Optional attributes to apply to the generated method (e.g., 267 /// `#[cfg(CONFIG_64BIT)]` or inline directives). 268 /// * `$vis:vis` - The visibility of the generated method (e.g., `pub`). 269 /// * `$name:ident` / `$try_name:ident` - The name of the generated method (e.g., `write32`, 270 /// `try_write8`). 271 /// * `$call_macro:ident` - The backend-specific helper macro used to emit the actual I/O call 272 /// (e.g., `call_mmio_write`). 273 /// * `$c_fn:ident` - The backend-specific C function or identifier to be passed into the 274 /// `$call_macro`. 275 /// * `$type_name:ty` - The Rust type of the value being written (e.g., `u8`, `u32`). Note the use 276 /// of `<-` before the type to denote a write operation. 277 #[macro_export] 278 macro_rules! io_define_write { 279 (infallible, $(#[$attr:meta])* $vis:vis $name:ident, $call_macro:ident($c_fn:ident) <- 280 $type_name:ty) => { 281 /// Write IO data from a given offset known at compile time. 282 /// 283 /// Bound checks are performed on compile time, hence if the offset is not known at compile 284 /// time, the build will fail. 285 $(#[$attr])* 286 // Always inline to optimize out error path of `io_addr_assert`. 287 #[inline(always)] 288 $vis fn $name(&self, value: $type_name, offset: usize) { 289 let addr = self.io_addr_assert::<$type_name>(offset); 290 291 $call_macro!(infallible, $c_fn, self, $type_name, addr, value); 292 } 293 }; 294 295 (fallible, $(#[$attr:meta])* $vis:vis $try_name:ident, $call_macro:ident($c_fn:ident) <- 296 $type_name:ty) => { 297 /// Write IO data from a given offset. 298 /// 299 /// Bound checks are performed on runtime, it fails if the offset (plus the type size) is 300 /// out of bounds. 301 $(#[$attr])* 302 $vis fn $try_name(&self, value: $type_name, offset: usize) -> Result { 303 let addr = self.io_addr::<$type_name>(offset)?; 304 305 $call_macro!(fallible, $c_fn, self, $type_name, addr, value) 306 } 307 }; 308 } 309 pub use io_define_write; 310 311 /// Checks whether an access of type `U` at the given `offset` 312 /// is valid within this region. 313 #[inline] 314 const fn offset_valid<U>(offset: usize, size: usize) -> bool { 315 let type_size = core::mem::size_of::<U>(); 316 if let Some(end) = offset.checked_add(type_size) { 317 end <= size && offset % type_size == 0 318 } else { 319 false 320 } 321 } 322 323 /// Trait indicating that an I/O backend supports operations of a certain type and providing an 324 /// implementation for these operations. 325 /// 326 /// Different I/O backends can implement this trait to expose only the operations they support. 327 /// 328 /// For example, a PCI configuration space may implement `IoCapable<u8>`, `IoCapable<u16>`, 329 /// and `IoCapable<u32>`, but not `IoCapable<u64>`, while an MMIO region on a 64-bit 330 /// system might implement all four. 331 pub trait IoCapable<T> { 332 /// Performs an I/O read of type `T` at `address` and returns the result. 333 /// 334 /// # Safety 335 /// 336 /// The range `[address..address + size_of::<T>()]` must be within the bounds of `Self`. 337 unsafe fn io_read(&self, address: usize) -> T; 338 339 /// Performs an I/O write of `value` at `address`. 340 /// 341 /// # Safety 342 /// 343 /// The range `[address..address + size_of::<T>()]` must be within the bounds of `Self`. 344 unsafe fn io_write(&self, value: T, address: usize); 345 } 346 347 /// Types implementing this trait (e.g. MMIO BARs or PCI config regions) 348 /// can perform I/O operations on regions of memory. 349 /// 350 /// This is an abstract representation to be implemented by arbitrary I/O 351 /// backends (e.g. MMIO, PCI config space, etc.). 352 /// 353 /// The [`Io`] trait provides: 354 /// - Base address and size information 355 /// - Helper methods for offset validation and address calculation 356 /// - Fallible (runtime checked) accessors for different data widths 357 /// 358 /// Which I/O methods are available depends on which [`IoCapable<T>`] traits 359 /// are implemented for the type. 360 /// 361 /// # Examples 362 /// 363 /// For MMIO regions, all widths (u8, u16, u32, and u64 on 64-bit systems) are typically 364 /// supported. For PCI configuration space, u8, u16, and u32 are supported but u64 is not. 365 pub trait Io { 366 /// Returns the base address of this mapping. 367 fn addr(&self) -> usize; 368 369 /// Returns the maximum size of this mapping. 370 fn maxsize(&self) -> usize; 371 372 /// Returns the absolute I/O address for a given `offset`, 373 /// performing runtime bound checks. 374 #[inline] 375 fn io_addr<U>(&self, offset: usize) -> Result<usize> { 376 if !offset_valid::<U>(offset, self.maxsize()) { 377 return Err(EINVAL); 378 } 379 380 // Probably no need to check, since the safety requirements of `Self::new` guarantee that 381 // this can't overflow. 382 self.addr().checked_add(offset).ok_or(EINVAL) 383 } 384 385 /// Fallible 8-bit read with runtime bounds check. 386 #[inline(always)] 387 fn try_read8(&self, offset: usize) -> Result<u8> 388 where 389 Self: IoCapable<u8>, 390 { 391 let address = self.io_addr::<u8>(offset)?; 392 393 // SAFETY: `address` has been validated by `io_addr`. 394 Ok(unsafe { self.io_read(address) }) 395 } 396 397 /// Fallible 16-bit read with runtime bounds check. 398 #[inline(always)] 399 fn try_read16(&self, offset: usize) -> Result<u16> 400 where 401 Self: IoCapable<u16>, 402 { 403 let address = self.io_addr::<u16>(offset)?; 404 405 // SAFETY: `address` has been validated by `io_addr`. 406 Ok(unsafe { self.io_read(address) }) 407 } 408 409 /// Fallible 32-bit read with runtime bounds check. 410 #[inline(always)] 411 fn try_read32(&self, offset: usize) -> Result<u32> 412 where 413 Self: IoCapable<u32>, 414 { 415 let address = self.io_addr::<u32>(offset)?; 416 417 // SAFETY: `address` has been validated by `io_addr`. 418 Ok(unsafe { self.io_read(address) }) 419 } 420 421 /// Fallible 64-bit read with runtime bounds check. 422 #[inline(always)] 423 fn try_read64(&self, offset: usize) -> Result<u64> 424 where 425 Self: IoCapable<u64>, 426 { 427 let address = self.io_addr::<u64>(offset)?; 428 429 // SAFETY: `address` has been validated by `io_addr`. 430 Ok(unsafe { self.io_read(address) }) 431 } 432 433 /// Fallible 8-bit write with runtime bounds check. 434 #[inline(always)] 435 fn try_write8(&self, value: u8, offset: usize) -> Result 436 where 437 Self: IoCapable<u8>, 438 { 439 let address = self.io_addr::<u8>(offset)?; 440 441 // SAFETY: `address` has been validated by `io_addr`. 442 unsafe { self.io_write(value, address) }; 443 Ok(()) 444 } 445 446 /// Fallible 16-bit write with runtime bounds check. 447 #[inline(always)] 448 fn try_write16(&self, value: u16, offset: usize) -> Result 449 where 450 Self: IoCapable<u16>, 451 { 452 let address = self.io_addr::<u16>(offset)?; 453 454 // SAFETY: `address` has been validated by `io_addr`. 455 unsafe { self.io_write(value, address) }; 456 Ok(()) 457 } 458 459 /// Fallible 32-bit write with runtime bounds check. 460 #[inline(always)] 461 fn try_write32(&self, value: u32, offset: usize) -> Result 462 where 463 Self: IoCapable<u32>, 464 { 465 let address = self.io_addr::<u32>(offset)?; 466 467 // SAFETY: `address` has been validated by `io_addr`. 468 unsafe { self.io_write(value, address) }; 469 Ok(()) 470 } 471 472 /// Fallible 64-bit write with runtime bounds check. 473 #[inline(always)] 474 fn try_write64(&self, value: u64, offset: usize) -> Result 475 where 476 Self: IoCapable<u64>, 477 { 478 let address = self.io_addr::<u64>(offset)?; 479 480 // SAFETY: `address` has been validated by `io_addr`. 481 unsafe { self.io_write(value, address) }; 482 Ok(()) 483 } 484 485 /// Infallible 8-bit read with compile-time bounds check. 486 #[inline(always)] 487 fn read8(&self, offset: usize) -> u8 488 where 489 Self: IoKnownSize + IoCapable<u8>, 490 { 491 let address = self.io_addr_assert::<u8>(offset); 492 493 // SAFETY: `address` has been validated by `io_addr_assert`. 494 unsafe { self.io_read(address) } 495 } 496 497 /// Infallible 16-bit read with compile-time bounds check. 498 #[inline(always)] 499 fn read16(&self, offset: usize) -> u16 500 where 501 Self: IoKnownSize + IoCapable<u16>, 502 { 503 let address = self.io_addr_assert::<u16>(offset); 504 505 // SAFETY: `address` has been validated by `io_addr_assert`. 506 unsafe { self.io_read(address) } 507 } 508 509 /// Infallible 32-bit read with compile-time bounds check. 510 #[inline(always)] 511 fn read32(&self, offset: usize) -> u32 512 where 513 Self: IoKnownSize + IoCapable<u32>, 514 { 515 let address = self.io_addr_assert::<u32>(offset); 516 517 // SAFETY: `address` has been validated by `io_addr_assert`. 518 unsafe { self.io_read(address) } 519 } 520 521 /// Infallible 64-bit read with compile-time bounds check. 522 #[inline(always)] 523 fn read64(&self, offset: usize) -> u64 524 where 525 Self: IoKnownSize + IoCapable<u64>, 526 { 527 let address = self.io_addr_assert::<u64>(offset); 528 529 // SAFETY: `address` has been validated by `io_addr_assert`. 530 unsafe { self.io_read(address) } 531 } 532 533 /// Infallible 8-bit write with compile-time bounds check. 534 #[inline(always)] 535 fn write8(&self, value: u8, offset: usize) 536 where 537 Self: IoKnownSize + IoCapable<u8>, 538 { 539 let address = self.io_addr_assert::<u8>(offset); 540 541 // SAFETY: `address` has been validated by `io_addr_assert`. 542 unsafe { self.io_write(value, address) } 543 } 544 545 /// Infallible 16-bit write with compile-time bounds check. 546 #[inline(always)] 547 fn write16(&self, value: u16, offset: usize) 548 where 549 Self: IoKnownSize + IoCapable<u16>, 550 { 551 let address = self.io_addr_assert::<u16>(offset); 552 553 // SAFETY: `address` has been validated by `io_addr_assert`. 554 unsafe { self.io_write(value, address) } 555 } 556 557 /// Infallible 32-bit write with compile-time bounds check. 558 #[inline(always)] 559 fn write32(&self, value: u32, offset: usize) 560 where 561 Self: IoKnownSize + IoCapable<u32>, 562 { 563 let address = self.io_addr_assert::<u32>(offset); 564 565 // SAFETY: `address` has been validated by `io_addr_assert`. 566 unsafe { self.io_write(value, address) } 567 } 568 569 /// Infallible 64-bit write with compile-time bounds check. 570 #[inline(always)] 571 fn write64(&self, value: u64, offset: usize) 572 where 573 Self: IoKnownSize + IoCapable<u64>, 574 { 575 let address = self.io_addr_assert::<u64>(offset); 576 577 // SAFETY: `address` has been validated by `io_addr_assert`. 578 unsafe { self.io_write(value, address) } 579 } 580 } 581 582 /// Trait for types with a known size at compile time. 583 /// 584 /// This trait is implemented by I/O backends that have a compile-time known size, 585 /// enabling the use of infallible I/O accessors with compile-time bounds checking. 586 /// 587 /// Types implementing this trait can use the infallible methods in [`Io`] trait 588 /// (e.g., `read8`, `write32`), which require `Self: IoKnownSize` bound. 589 pub trait IoKnownSize: Io { 590 /// Minimum usable size of this region. 591 const MIN_SIZE: usize; 592 593 /// Returns the absolute I/O address for a given `offset`, 594 /// performing compile-time bound checks. 595 // Always inline to optimize out error path of `build_assert`. 596 #[inline(always)] 597 fn io_addr_assert<U>(&self, offset: usize) -> usize { 598 build_assert!(offset_valid::<U>(offset, Self::MIN_SIZE)); 599 600 self.addr() + offset 601 } 602 } 603 604 /// Implements [`IoCapable`] on `$mmio` for `$ty` using `$read_fn` and `$write_fn`. 605 macro_rules! impl_mmio_io_capable { 606 ($mmio:ident, $(#[$attr:meta])* $ty:ty, $read_fn:ident, $write_fn:ident) => { 607 $(#[$attr])* 608 impl<const SIZE: usize> IoCapable<$ty> for $mmio<SIZE> { 609 unsafe fn io_read(&self, address: usize) -> $ty { 610 // SAFETY: By the trait invariant `address` is a valid address for MMIO operations. 611 unsafe { bindings::$read_fn(address as *const c_void) } 612 } 613 614 unsafe fn io_write(&self, value: $ty, address: usize) { 615 // SAFETY: By the trait invariant `address` is a valid address for MMIO operations. 616 unsafe { bindings::$write_fn(value, address as *mut c_void) } 617 } 618 } 619 }; 620 } 621 622 // MMIO regions support 8, 16, and 32-bit accesses. 623 impl_mmio_io_capable!(Mmio, u8, readb, writeb); 624 impl_mmio_io_capable!(Mmio, u16, readw, writew); 625 impl_mmio_io_capable!(Mmio, u32, readl, writel); 626 // MMIO regions on 64-bit systems also support 64-bit accesses. 627 impl_mmio_io_capable!( 628 Mmio, 629 #[cfg(CONFIG_64BIT)] 630 u64, 631 readq, 632 writeq 633 ); 634 635 impl<const SIZE: usize> Io for Mmio<SIZE> { 636 /// Returns the base address of this mapping. 637 #[inline] 638 fn addr(&self) -> usize { 639 self.0.addr() 640 } 641 642 /// Returns the maximum size of this mapping. 643 #[inline] 644 fn maxsize(&self) -> usize { 645 self.0.maxsize() 646 } 647 648 io_define_read!(fallible, try_read8, call_mmio_read(readb) -> u8); 649 io_define_read!(fallible, try_read16, call_mmio_read(readw) -> u16); 650 io_define_read!(fallible, try_read32, call_mmio_read(readl) -> u32); 651 io_define_read!( 652 fallible, 653 #[cfg(CONFIG_64BIT)] 654 try_read64, 655 call_mmio_read(readq) -> u64 656 ); 657 658 io_define_write!(fallible, try_write8, call_mmio_write(writeb) <- u8); 659 io_define_write!(fallible, try_write16, call_mmio_write(writew) <- u16); 660 io_define_write!(fallible, try_write32, call_mmio_write(writel) <- u32); 661 io_define_write!( 662 fallible, 663 #[cfg(CONFIG_64BIT)] 664 try_write64, 665 call_mmio_write(writeq) <- u64 666 ); 667 668 io_define_read!(infallible, read8, call_mmio_read(readb) -> u8); 669 io_define_read!(infallible, read16, call_mmio_read(readw) -> u16); 670 io_define_read!(infallible, read32, call_mmio_read(readl) -> u32); 671 io_define_read!( 672 infallible, 673 #[cfg(CONFIG_64BIT)] 674 read64, 675 call_mmio_read(readq) -> u64 676 ); 677 678 io_define_write!(infallible, write8, call_mmio_write(writeb) <- u8); 679 io_define_write!(infallible, write16, call_mmio_write(writew) <- u16); 680 io_define_write!(infallible, write32, call_mmio_write(writel) <- u32); 681 io_define_write!( 682 infallible, 683 #[cfg(CONFIG_64BIT)] 684 write64, 685 call_mmio_write(writeq) <- u64 686 ); 687 } 688 689 impl<const SIZE: usize> IoKnownSize for Mmio<SIZE> { 690 const MIN_SIZE: usize = SIZE; 691 } 692 693 impl<const SIZE: usize> Mmio<SIZE> { 694 /// Converts an `MmioRaw` into an `Mmio` instance, providing the accessors to the MMIO mapping. 695 /// 696 /// # Safety 697 /// 698 /// Callers must ensure that `addr` is the start of a valid I/O mapped memory region of size 699 /// `maxsize`. 700 pub unsafe fn from_raw(raw: &MmioRaw<SIZE>) -> &Self { 701 // SAFETY: `Mmio` is a transparent wrapper around `MmioRaw`. 702 unsafe { &*core::ptr::from_ref(raw).cast() } 703 } 704 705 io_define_read!(infallible, pub read8_relaxed, call_mmio_read(readb_relaxed) -> u8); 706 io_define_read!(infallible, pub read16_relaxed, call_mmio_read(readw_relaxed) -> u16); 707 io_define_read!(infallible, pub read32_relaxed, call_mmio_read(readl_relaxed) -> u32); 708 io_define_read!( 709 infallible, 710 #[cfg(CONFIG_64BIT)] 711 pub read64_relaxed, 712 call_mmio_read(readq_relaxed) -> u64 713 ); 714 715 io_define_read!(fallible, pub try_read8_relaxed, call_mmio_read(readb_relaxed) -> u8); 716 io_define_read!(fallible, pub try_read16_relaxed, call_mmio_read(readw_relaxed) -> u16); 717 io_define_read!(fallible, pub try_read32_relaxed, call_mmio_read(readl_relaxed) -> u32); 718 io_define_read!( 719 fallible, 720 #[cfg(CONFIG_64BIT)] 721 pub try_read64_relaxed, 722 call_mmio_read(readq_relaxed) -> u64 723 ); 724 725 io_define_write!(infallible, pub write8_relaxed, call_mmio_write(writeb_relaxed) <- u8); 726 io_define_write!(infallible, pub write16_relaxed, call_mmio_write(writew_relaxed) <- u16); 727 io_define_write!(infallible, pub write32_relaxed, call_mmio_write(writel_relaxed) <- u32); 728 io_define_write!( 729 infallible, 730 #[cfg(CONFIG_64BIT)] 731 pub write64_relaxed, 732 call_mmio_write(writeq_relaxed) <- u64 733 ); 734 735 io_define_write!(fallible, pub try_write8_relaxed, call_mmio_write(writeb_relaxed) <- u8); 736 io_define_write!(fallible, pub try_write16_relaxed, call_mmio_write(writew_relaxed) <- u16); 737 io_define_write!(fallible, pub try_write32_relaxed, call_mmio_write(writel_relaxed) <- u32); 738 io_define_write!( 739 fallible, 740 #[cfg(CONFIG_64BIT)] 741 pub try_write64_relaxed, 742 call_mmio_write(writeq_relaxed) <- u64 743 ); 744 } 745