Day 96 - MMIO Access APIs¶
Today's Goal¶
After implementing ioremap() and iounmap(), today's goal is to understand how Linux kernel drivers access memory-mapped I/O (MMIO) registers.
Unlike normal memory access, device registers must be accessed through dedicated MMIO APIs such as readb(), readw(), readl(), writeb(), writew(), and writel(). These APIs provide a consistent interface for reading and writing device registers while preserving the semantics required by different CPU architectures.
To understand their behavior, I extended the MMIO simulator from Day95 and implemented Linux-style MMIO access APIs.
What I Learned¶
- The purpose of
readb(),readw(),readl(),writeb(),writew(), andwritel() - The difference between normal memory access and MMIO access
- Why Linux drivers use dedicated MMIO APIs instead of directly dereferencing pointers
- How Little Endian affects register layout in memory
- Accessing registers using base address plus register offsets
- Validating MMIO mapping boundaries before each access
- Managing multiple independent MMIO mappings simultaneously
Implementation¶
Implemented a Linux-style MMIO access layer.
utils/memory/io/
├── io_mapping.c
├── io_mapping.h
├── ioremap.c
├── ioremap.h
├── mmio_access.c
└── mmio_access.h
Responsibilities:
io_mapping- Maintain MMIO mapping information
- Translate virtual addresses into backing memory
-
Validate mapping boundaries
-
ioremap - Create virtual mappings
-
Remove mappings
-
mmio_access readb()readw()readl()writeb()writew()writel()
The simulator assumes a Little Endian architecture, matching Raspberry Pi, ARM64, and x86 systems.
Labs Completed¶
Lab 1 — 8-bit MMIO Access¶
Implemented and verified:
writeb()readb()
Lab 2 — 16-bit MMIO Access¶
Implemented and verified:
writew()readw()
Lab 3 — 32-bit MMIO Access¶
Implemented and verified:
writel()readl()
Lab 4 — Little Endian Memory Layout¶
Verified the byte layout of a 32-bit register.
This demonstrates how a 32-bit register value is stored in Little Endian systems.
Lab 5 — Register Layout with Offsets¶
Implemented Linux-style register access using register offsets.
Verified that each register can be accessed independently.
Lab 6 — Boundary Validation¶
Validated that every MMIO access remains inside the mapped region.
Verified:
- last valid 32-bit access succeeds
- out-of-range access is rejected
- no partial write occurs
Lab 7 — Multiple MMIO Mappings¶
Created two independent MMIO mappings.
Verified:
- different physical addresses map to different virtual addresses
- each mapping owns independent backing memory
- accesses to one mapping do not affect the other
Summary¶
Today I completed a Linux-style MMIO access layer on top of the ioremap() simulator.
The implementation now supports:
- Linux MMIO access APIs
- 8-bit, 16-bit, and 32-bit register access
- Little Endian register layout
- Register offset access
- Boundary validation
- Multiple independent MMIO mappings
With Day95 and Day96 completed, the simulator now models the complete MMIO workflow used by Linux drivers:
Physical Address
│
▼
ioremap()
│
▼
Virtual MMIO Address
│
▼
readb()/readw()/readl()
writeb()/writew()/writel()
This mirrors the programming model used by real Linux platform drivers when accessing hardware registers.