IT: What Is Memory-Mapped I/O? How CPUs and Drivers Control Hardware Through Device Registers

Realistic macro photograph of a computer circuit board representing memory-mapped I/O and hardware device registers.

Memory-mapped I/O, usually shortened to MMIO, is a way for a CPU to control hardware devices by giving their registers addresses inside the processor’s memory address space.

The simple version is: software reads or writes a special address, and that access goes to hardware instead of ordinary RAM. A device driver can use those addresses to read device status, configure settings, acknowledge events, start work, or tell a controller where data should go.

Troonics gives a beginner-friendly explanation of memory-mapped I/O, peripheral registers, and how CPUs use ordinary addresses to control hardware.

Start With the Address Space

A CPU works with addresses. Some addresses ultimately refer to normal system memory. With MMIO, other address ranges are reserved for hardware devices and their control registers.

That means an address does not automatically mean “RAM.” The platform’s memory map determines what lives at each physical address range. Depending on the system, a region may point to RAM, firmware, a PCIe device, a graphics frame buffer, a microcontroller peripheral, or another hardware block.

Motherboard and PCIe hardware representing memory-mapped device registers controlled by software.
MMIO gives software an address-based way to control physical devices attached to a motherboard or system bus. Photo via Unsplash.

Device Registers Are Tiny Hardware Control Points

A hardware register is a small storage location inside a device or controller. Different registers may hold configuration bits, command values, error flags, queue pointers, interrupt status, device IDs, or measurements.

When a device is memory-mapped, the driver can access those registers through specific addresses. Reading one address might return a status word. Writing another could enable the device, clear an error, start a transfer, or acknowledge an interrupt.

MMIO Is Not Ordinary RAM

MMIO addresses may look like memory addresses, but the hardware behind them behaves differently from DRAM. Reading a device register can have side effects. Writing a control register can immediately change hardware behavior. Some locations may be read-only, write-only, or meaningful only when accessed at a particular width.

This is why low-level software cannot treat MMIO like an ordinary array in RAM. The operating system, compiler, CPU, and driver must preserve the ordering and access rules expected by the device.

Drivers Map Device Registers Before Using Them

The kernel normally controls which physical device regions a driver is allowed to access. A driver maps the device’s MMIO range into an address it can safely use, then performs reads and writes through operating-system helper functions.

The Linux kernel’s device I/O documentation describes this model directly: drivers commonly map I/O memory with functions such as ioremap() and access registers with helpers such as readl() and writel().

PCIe Devices Commonly Expose MMIO Regions

Modern PCI Express devices commonly expose memory regions that the operating system maps into the system address space. Network adapters, NVMe controllers, GPUs, accelerators, and other expansion hardware can all use MMIO for configuration and control.

PCIe configuration space includes Base Address Registers, or BARs, that describe the address-space resources a device needs. The operating system assigns usable address ranges, then a driver maps the appropriate region before touching the device’s registers.

BAR Does Not Mean the Whole Device Is Stored in RAM

A common beginner mistake is to imagine that mapping a PCIe BAR somehow copies the device into memory. It does not. The address range is a window through which CPU reads and writes reach hardware resources on the device.

For example, a NIC may expose control registers through one MMIO region while packet data is moved separately through DMA. MMIO controls the device; DMA is often used for the bulk data movement.

Embedded System Creations compares memory-mapped I/O with isolated or port-mapped I/O and shows why MMIO uses normal memory-style addressing.

MMIO and DMA Usually Work Together

The previous DMA article makes more sense once MMIO is added. A driver may first write MMIO registers to tell a device where a DMA buffer is located, how large the transfer should be, and which command to execute.

The device then performs the Direct Memory Access operation. When the work completes, it may raise an interrupt. The driver reads MMIO status registers to determine what happened. That gives a simple hardware chain: MMIO setup → DMA transfer → interrupt → MMIO status/acknowledgment.

MMIO Is Common in Embedded Systems Too

On a microcontroller, MMIO is often even more visible. GPIO blocks, UARTs, timers, ADCs, SPI controllers, PWM units, and other peripherals are assigned fixed address ranges. Firmware reads and writes their registers to control physical pins and internal hardware.

BitcoinVersus.Tech’s Microcontroller Architecture lesson covers memory maps, registers, and interrupts in that embedded context, while the Armv8-M architecture explainer shows how this model fits modern embedded processors.

MMIO Is Different From Port-Mapped I/O

Port-mapped I/O, also called isolated I/O, keeps device ports in a separate I/O address space. Classic x86 processors support special instructions such as IN and OUT for that purpose.

MMIO instead places device registers inside the normal memory-address model, so ordinary load/store-style operations can reach them. Modern systems can use both techniques, but MMIO is extremely common across PCIe hardware and embedded architectures.

The stack I built was essentially a Windows kernel driver that bridged IRQs to userspace and allowed you to map PCIe device memory too. With these primitives, I ported the e1000 (Intel Gigabit Ethernet) driver from Raptor, rewriting it in Rust.

— Alex Zenla 🏳️‍⚧️ (@alex.zenla.io) 2024-11-19T12:28:25.033Z

Kernel engineer Alex Zenla described a Windows kernel driver that mapped PCIe device memory into userspace while bridging IRQs, a real-world example of MMIO, device drivers, PCIe, and interrupts meeting in one system.

Memory Ordering Matters

CPUs and compilers are designed to optimize ordinary memory operations aggressively. Device control is different. If the order of two register writes matters to the hardware, software cannot allow them to be freely reordered as though they were ordinary RAM accesses.

Operating systems therefore provide MMIO accessors and memory-barrier rules. Those mechanisms help guarantee that commands, buffer addresses, status reads, and acknowledgments reach hardware in an order that matches the device specification.

Volatile Alone Is Not the Whole Solution

Embedded C examples often use the volatile keyword around hardware registers so the compiler does not optimize away accesses that appear redundant. That is useful, but operating-system drivers need stronger architecture-aware rules than volatile alone.

Linux, Windows, and other operating systems expose dedicated primitives for device I/O because CPU ordering, caching, bus semantics, access width, and architecture differences all matter. Using the platform’s MMIO APIs is safer than inventing raw pointer logic inside a driver.

Caching MMIO Incorrectly Can Break Hardware

Ordinary memory benefits enormously from CPU cache. Device registers usually cannot be treated like normal cacheable RAM, because software may need every read or write to reach the actual hardware.

The operating system therefore assigns appropriate memory attributes when it maps device regions. If a status register were incorrectly served from stale cache, software might never notice that the physical device changed state.

MMIO Connects Directly to System Calls

Normal applications usually do not receive unrestricted MMIO access. Instead, an application makes a system call or uses a software API. The kernel and driver decide what hardware operations are allowed, then the driver performs the MMIO access in privileged context.

That separation protects the machine. If every user-space program could write arbitrary device registers, a bug could disable hardware, corrupt transfers, overwrite protected memory through misconfigured DMA, or crash the entire operating system.

A NIC Gives a Good Full-System Example

Consider a network interface card. The driver can use MMIO registers to configure receive queues, transmit queues, interrupt settings, and device state. DMA moves packet data between the NIC and RAM. Interrupts or polling tell the CPU that packets or completions are ready.

That one example ties together the last several fundamentals: system call → kernel → driver → MMIO registers → DMA → interrupt → driver completion → application. The hardware and software are not separate topics; they form one I/O path.

The Simple Way to Remember MMIO

Memory-mapped I/O makes hardware registers look like addresses in the CPU’s memory space. Reading or writing those special addresses communicates with a device instead of ordinary RAM.

The chain is: driver maps device region → CPU reads/writes MMIO register → device changes state or reports status → DMA and interrupts handle the larger I/O flow. Once that is clear, PCIe BARs, device registers, DMA, interrupts, and low-level drivers become much easier to connect.

Editor’s Note

Featured image: realistic circuit-board photograph via Unsplash, cropped to exactly 1200Ă—630. Body image: separate realistic motherboard/PCIe photograph via Unsplash. The Troonics and Embedded System Creations videos are distinct and directly relevant to MMIO. The Bluesky post is directly relevant to PCIe device-memory mapping and IRQ handling.

Support and donation options are available through BitcoinVersus.Tech.

BitcoinVersus.Tech is not a financial advisor. Content is provided for informational and educational purposes.

One response to “IT: What Is Memory-Mapped I/O? How CPUs and Drivers Control Hardware Through Device Registers”

  1. […] relationship to the previous MMIO article is direct. A driver can write device registers to tell hardware where a descriptor ring […]

    Like

Leave a comment