starina_driver_utils

Module mmio

Source
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§

Traits§

  • A trait for defining allowed access types.
  • A trait for endianness conversion.