Day 95 - ioremap() Internals¶
Today's Goal¶
Today's objective is to understand how Linux maps MMIO (Memory-Mapped I/O) physical addresses into the kernel virtual address space.
Unlike normal RAM allocation, hardware registers already exist at fixed physical addresses. Drivers cannot safely access these physical addresses directly, so they must first create a kernel virtual mapping using ioremap().
In this lab, we implement a simplified MMIO mapping manager to simulate the behavior of Linux ioremap() and understand the relationship between physical addresses, virtual addresses, and hardware registers.
Why ioremap()?¶
Modern operating systems use virtual memory.
Kernel drivers generally operate on virtual addresses, while hardware peripherals expose physical addresses.
For example, a GPIO controller may reside at:
A driver cannot simply dereference this physical address.
Instead, Linux creates a kernel virtual mapping:
After mapping, the driver accesses the device through the returned virtual address using APIs such as readl() and writel().
Linux Architecture¶
In Linux, ioremap() creates a page-table mapping.
The CPU MMU automatically translates virtual addresses into physical addresses whenever the driver accesses an MMIO register.
The driver never performs this translation itself.
Simulator Architecture¶
Since a userspace program cannot create kernel page-table mappings, this lab implements a simplified MMIO mapping simulator.
Instead of modifying page tables, the simulator maintains its own mapping table and backing storage.
+----------------------+
| io_region |
|----------------------|
Physical Address | 0x10000000 |
Size | 0x1000 |
Storage | malloc() buffer |
+----------+-----------+
|
|
+----------v-----------+
| io_mapping |
|----------------------|
Virtual Address | 0x20000000 |
Physical Address | 0x10000000 |
Size | 0x100 |
+----------+-----------+
|
|
io_mapping_translate()
|
▼
Backing Storage Pointer
The simulator therefore separates:
- Physical MMIO regions
- Virtual mappings
- Address translation
This closely resembles the responsibilities of the Linux MMU while remaining entirely in userspace.
MMIO Region Management¶
The simulator first registers available MMIO regions.
Each region represents a simulated hardware device.
Internally, every region owns a block of backing storage allocated from heap memory.
Unlike Linux, this storage does not exist in real hardware. It only simulates hardware registers for userspace testing.
Virtual Mapping¶
Drivers create virtual mappings through ioremap().
Instead of returning a heap pointer, the simulator allocates a simulated kernel virtual address.
For example:
Virtual addresses are allocated in page-sized increments to resemble Linux kernel mappings.
Address Translation¶
The simulated virtual address cannot be dereferenced directly.
Instead, every MMIO access is translated into the corresponding backing storage address.
This translation performs the role that the MMU would normally provide inside the Linux kernel.
Mapping Lifecycle¶
The simulator enforces the same ownership rules as Linux.
A region cannot be removed while active mappings still exist.
Lab Summary¶
Lab 1 — Region Registration¶
Validated:
- Region registration
- Overlap detection
- Adjacent regions
- Zero-sized regions
- Address overflow
Lab 2 — ioremap()¶
Validated:
- Virtual address allocation
- Page alignment
- Partial mappings
- Multiple mappings
- Mapping boundary checking
Lab 3 — Address Translation¶
Validated:
- Virtual-to-storage translation
- Mapping offsets
- Physical region offsets
- Shared backing storage
- Translation boundary checking
Lab 4 — Mapping Lifecycle¶
Validated:
- Region busy protection
- Multiple active mappings
- Double
iounmap() - Invalid
iounmap() - Manager cleanup
- Reinitialization
Key Takeaways¶
- Hardware peripherals are accessed through MMIO rather than normal RAM allocation.
ioremap()maps MMIO physical addresses into the kernel virtual address space.- Linux relies on the MMU to translate virtual addresses into physical addresses.
- The simulator replaces MMU translation with
io_mapping_translate(). - Backing storage is only used by the simulator to emulate hardware registers in userspace.
- Separating region management, virtual mappings, and address translation closely mirrors the Linux MMIO architecture.
Related APIs¶
ioremap()iounmap()readb()readw()readl()writeb()writew()writel()