Course contentsShow
← Rust
Lesson 1658 of 1,91014. System Integration and EcosystemFree lesson

Direct Memory Mapping

You will map hardware memory addresses into your address space for high-speed device access.

In this lesson, you will learn how to bypass standard I/O abstractions to manipulate hardware registers directly by mapping physical memory addresses into your process's virtual address space.

The Concept of Memory-Mapped I/O (MMIO)

In high-performance systems, hardware devices—like network cards or GPUs—are often controlled by reading from or writing to specific memory addresses. When the CPU performs a store operation to these addresses, the bus logic routes the signal to the device's registers rather than to RAM. In Rust, we perform this "Direct Memory Mapping" to achieve zero-copy communication and ultra-low latency.

Since user-space processes cannot arbitrarily access physical memory, we rely on the OS to map these addresses for us. On Unix-like systems, this is typically done by opening /dev/mem (if permissions allow) or using mmap.

Implementing the Mapping

To interact with these addresses safely, we must treat the mapped region as volatile memory. This prevents the compiler from optimizing away reads or writes that it deems "redundant" but which are actually critical for hardware signaling.

use std::ptr::{read_volatile, write_volatile};

/// Represents a simple hardware register at a known physical address
pub struct DeviceRegister {
    ptr: *mut u32,
}

impl DeviceRegister {
    pub fn write(&self, value: u32) {
        // We use volatile operations because the hardware may change
        // the state behind the CPU's back.
        unsafe { write_volatile(self.ptr, value) };
    }

    pub fn read(&self) -> u32 {
        unsafe { read_volatile(self.ptr) }
    }
}

Safety and Requirements

Because hardware is inherently "unsafe" from the compiler’s perspective, wrapping these mappings in a safe abstraction is mandatory. You must ensure the mapping is page-aligned (usually 4KiB) and handle the lifetime of the pointer carefully. If you attempt to access memory outside the allocated range, the OS will send a SIGSEGV (segmentation fault) to your process.

When integrating this into a larger system, treat these pointers as *mut T and strictly use volatile intrinsics to ensure the generated machine code maintains the precise sequence of operations required by the hardware spec.

Key Takeaway: Direct Memory Mapping allows you to interact with hardware at the speed of the bus by treating physical registers as volatile memory, provided you manually manage safety and respect memory alignment constraints.