Skip to content

hal::dma

DMA reachability — the one fact a driver needs before pointing an engine at a buffer.

A DMA engine reaches only certain address ranges: on the ESP32 that is internal DRAM (0x3FFAE000..0x40000000), on a Cortex-M it is a different SRAM window, and external PSRAM or flash-mapped memory is off-limits to both. A driver that starts a transfer into an unreachable buffer gets silence or garbage, not a fault — so the check has to happen first.

[DmaReach] is that check, behind a trait so the rule lives with the SoC and a portable driver does not hard-code one chip’s memory map. It is the first of the hal seams the second-architecture plan calls for (doc/plan-arm32.md, Phase 1.1).

struct DmaHandle { /* private fields */ }

A handle to a DMA-safe buffer the broker handed out.

Lives here, not in the kernel, so a driver and api can name it without naming the kernel; the kernel’s broker builds it with [DmaHandle::new] and re-exports the type from dma_broker.

It carries the buffer’s already-resolved address rather than an offset: the pool base is a linker symbol only the kernel can see, so the kernel does the arithmetic once, at allocation, and every reader here just reads the answer.

Implements: Clone, Copy, Debug

struct DmaTransferId(/* private */);

Identifies one transfer, from the broker’s begin to its await_transfer.

Lives here rather than in the kernel so a driver — and api — can name it without naming the kernel; the kernel re-exports it from dma_broker.

Implements: Clone, Copy, Debug, Eq, PartialEq, StructuralPartialEq

enum DmaError {
PoolExhausted,
NotOwner,
Timeout,
}

Why the kernel’s DMA broker refused or lost a transfer.

Defined here rather than in the kernel so a driver can name it without naming the kernel; the kernel re-exports it from dma_broker.

Implements: Clone, Copy, Debug, Display, Eq, From, PartialEq, StructuralPartialEq

trait DmaReach: Send + Sync {
fn reachable(&self, addr: u32, len: u32) -> bool
}

Whether a byte range is reachable by this SoC’s DMA engines.

const fn range_within(addr: u32, len: u32, low: u32, high: u32) -> bool

Whether every byte of [addr, addr + len) lies within [low, high).

The shared building block for [DmaReach::reachable] impls whose reachable memory is a single contiguous window: only low/high differ per chip. len == 0 is vacuously within; a range whose last byte would overflow u32 is rejected rather than wrapped.