Expand description
Type-safe MMIO register access.
MMIO (Memory-Mapped I/O) is a mechanism to access hardware devices using memory read and write operations. Unlike normal memory accesses, in MMIO, you need to carefully handle endianness and unexpected compiler/CPU optimizations. This module will help you.
§Why is &mut MappedFolio
required in read
methods?
This is to ensure that the caller has exclusive access to the MMIO region. This is important because reads from MMIO may have side effects (e.g. clearing an interrupt) and concurrent access to the same MMIO region might lead to unexpected behavior.
§Example (Goldfish RTC driver)
In this example, two MMIO registers are defined: TIME_LOW_REG
and
TIME_HIGH_REG
and prints the current time read from the Goldfish RTC
device.
To access the MMIO registers, you need to acquire and map the MMIO region
using MappedFolio::create_pinned
. Then, pass the mutable reference of
the MappedFolio
to the read
method of the MMIO register:
use starina_api::folio::MappedFolio;
use starina_driver_utils::mmio::{LittleEndian, MmioReg, ReadOnly};
const MMIO_BASE: PAddr =PAddr::new(0x101000);
const MMIO_SIZE: usize = 4096;
static TIME_LOW_REG: MmioReg<LittleEndian, ReadOnly, u32> = MmioReg::new(0x00);
static TIME_HIGH_REG: MmioReg<LittleEndian, ReadOnly, u32> = MmioReg::new(0x04);
let mut folio = MappedFolio::create_pinned(MMIO_BASE, MMIO_SIZE).unwrap();
let low: u32 = TIME_LOW_REG.read(&mut folio);
let high: u32 = TIME_HIGH_REG.read(&mut folio);
let now: u64 = (high as u64) << 32 | (low as u64);
let now_i64: i64 = now.try_into().unwrap();
let datetime = chrono::DateTime::from_timestamp_nanos(now_i64);
info!("now: {datetime}");
Structs§
- Big-endian endianness.
- Little-endian endianness.
- A memory-mapped I/O register.
- Read-only MMIO register.
- Read-write MMIO register.
- Write-only MMIO register.
Traits§
- A trait for defining allowed access types.
- A trait for endianness conversion.