The Physical Memory Manager (PMM) is one of the most foundational components is OS development. It operates at the lowest level of memory management, dealing directly with phsyical RAM, not abstraction like virtual memory.
Before any advanced features like processes, paging, or heaps can exist, the OS must answer a simple but critical question:
Which parts of RAM are safe to use, and how do we manage them efficiently?
That is exactly what the PMM is responsible for.
What is the Physical Memory Management?
The Physical Memory Manager (PMM) is responsible for:
- Tracking which parts of RAM are free or used
- Allocating and freeing physical memory blocks (frames/pages)
- Providing memory to:
- Kernel
- Virtual Memory Manager (VMM)
- Devices drivers (DMA, buffers, hardware interaction)
Important Note
The PMM does not manage memory byte-by-byte.
Instead, it operates on fixed-size blocks called:
- Frames (physical memory)
- Pages (virtual memory)
Basic Unit:
Physical memory is dividied into fixed-size blocks:
- On x86:
- Page size = 4096 bytes (4 KB)
- Called:
- Frames (physical)
- Pages (virtual)
Example:
If your system has 4 GB RAM.
Then
4GB / 4KB = 1,048,576 framesEach frame represents a single allocatable unit.
Memory Layout at Boot
When the OS boots, RAM is not entirely free.
Some regions are already occupied:
- Kernel code/data
- Bootloader
- BIOS/UEFI structures
- Reserved hardware regions (MMIO, ACPI, etc.)
Example Memory Map (BIOS E820):
From BIOS (e.g., via E820):
0x00000000 - 0x0009FC00 β Usable
0x0009FC00 - 0x000A0000 β Reserved
0x00100000 - 0x7FFFFFFF β UsableKey Responsibility of PMM
The PMM must:
- Parse this memory map
- Identify usable regions
- Avoid reserved areas
- Build an internal structure to manage memory
Memory Map: Bootloader's Role
The OS does not directly discover memory β it relies on the bootloader.
BIOS Memory Detection (E820)
The most reliable method is:
int 0x15, eax = 0xE820This returns a list of memory regions, each with:
- Base address
- Size
- Type
Memory Region Types
| Type | Meaning |
|---|---|
| 1 | Available (usable RAM) |
| 2 | Reserved |
| 3+ | ACPI / firmware / special |
Bootloader Responsibilities
The bootloader:
- Iteratively calls BIOS (
E820) - Builds a memory map
- Stores it in memory
- Passes to kernel:
- Pointer to memory map
- Entry count
- Total memory size
Critical Insight
This becomes the contract between bootloader and kernel.
If this data is wrong β your OS will break.
Why Do We Need a Physical Memory Manager?
When your OS boots, memory is:
- Partially used (kernel, BIOS, bootloader)
- Reserved hardware regions
- Fragmented
- Unstructured
The bootloader gives us a memory map, but that's just information, not a management system.
Without a PMM:
- You might overwrite your kernel
- Allocate the same memory twice
- Corrupt hardware-mapped regions
So, PMM must answer:
- Which pages are free?
- Which pages are reserved?
- How do I allocate contiguous memory?
- How do I avoid overwriting critical regions?
Data Structures for PMM
There are different ways on how to handle a PMM.
This is where design choices matter:
1 Bitmap (Most Common)
Concept:
Each frame is represented by 1 bit:
0: free1: used
This is the simplest approach: one bit per page frame, where 0 = free and 1 = allocated. For a 4GiB machine (1,048,576 pages), this costs just 128 KB of RAM β negligible.
0 β free
1 β used (allocated)Example:
Frame: 0 1 2 3 4 5 6 7
Bitmap: 1 0 0 1 1 0 0 0Memory Cost
For 4 GB RAM:
1,048,576 frames β 1,048,576 bits β 128 KBVery efficient.
Allocations:
Allocation is O(n) in the worst case β you must scan until you find a zero bit.
Freeing is O(1): just clear the bit.
- Scan for first
0 - Mark it
1
Pros:
- Very space efficient, 1 bit per 4 KB
- Simple
- Easy to debug
Cons:
- Slow for large memory (linear scan)
- Hard to find contiguous blocks efficiently
Complexity:
| Operation | Time |
|---|---|
| Allocate | O(n) |
| Free | O(1) |
2 Free List
Maintain a linked list of free frames.
Pos:
- Fast allocation
- Easy to implement
Cons:
- Poor for large contiguous allocation
- Fragmentation issues
3 Buddy Allocator (Advanced)
Splits memory into power-of-2 blocks:
1 page, 2 pages, 4 pages, 8 pages...Pros:
- Efficient merging (coalscing)
- Good for contiguous memory
Cons:
- More complex
- Internal Fragmentation
Core Design: Bitmap-Based PMM
We would use a bitmap-based allocator.
Concept:
Divide memory into fixed-size pages (usually 4 KB):
Physical Memory β [Page0][Page1][Page2]...[PageN]Then track each page with a bit:
Bitmap β 1 0 1 0 0 1 ...
β β β β β β
Used/FreeBitmap tracks:
1: allocated0: free
Memory Representation:
Physical memory is divided into:
Frame 0 β 0x00000000
Frame 1 β 0x00001000
Frame 2 β 0x00002000
...Each frame:
- Size =
PAGE_SIZE(usually 4096 bytes)
Bitmap Structure
A bitmap is stored in memory:
Bit index = Frame numberExample:
| Frame | Bit | Status |
|---|---|---|
| 0 | 1 | Used |
| 1 | 0 | Free |
| 2 | 1 | Used |
Initialization Strategy
The PMM follows a safe-first initialization model:
Step 1: Assume All Memory is Used
The bitmap is initialized to:
111111111111111111...This ensures:
- No accidental use of invalid memory
- No use of unknown memory
Step 2: Free Valid Memory Regions
The kernel iterates over the bootloader-provded memory map:
- For each region of type available (type = 1)
- Corresponding bits are cleared
if (region.type == USABLE)
mark as freeResult:
Used β Reserved regions
Free β Usable RAMStep 3: Reserve Critical Regions
Even if marked βavailableβ, certain regions must remain reserved:
- Kernel image
- Kernel stack
- Memory bitmap itself
- Low memory regions (BIOS / hardware)
- Null page (0x0)
Allocation Model
1 Single Page Allocation
- Scan bitmap
- Find free bit
- Mark as used
- Return physical address
2 Contiguous Allocation
Needed for:
- DMA
- Page tables
- Large buffers
Algorithm:
- Find
Nconsecutive free bits - Mark all as used
Bootloader Input
The OS receives a memory map:
[Base Address | Size | Type]Types:
| Type | Meaning |
|---|---|
| 1 | Usable RAM |
| Others | Reserved |
Key Design Principle
A robust PMM does:
Assume all memory is unsafe -> explicitly mark safe regions as usable.
This avoids accidental corruption of critical memory.
How Memory Looks Physically
Let's take a concrete example.
Assume
- Total RAM = 64 KB
- Page size = 4 KB
64 KB / 4 KB = 16 framesFrame Layout
| Frame | Address |
|---|---|
| 0 | 0x0000 |
| 1 | 0x1000 |
| 2 | 0x2000 |
| ... | ... |
| 15 | 0xF000 |
Bitmap Representation
Since:
1 frame = 1 bit
16 frames = 16 bits = 2 bytesInitial Bitmap (after memset 0xFF)
11111111 11111111Means:
All memory is USED (reserved)
What Happens During Initialization
Step 1: Everything marked USED
memset(MemoryBitmap, 0xFFFFFFFF, MemoryBitmapSize);Bitmap:
11111111 11111111Step 2: BIOS says usable region
Example:
Usable: 0x1000 β 0x9000Frames:
Frame 1 β Frame 8Step 3: MMFreeRegion()
MmMemoryMapUnsetBit(Frame++);Bit-by-bit change
Before:
Frame: 0 1 2 3 4 5 6 7 8 9 ...
Bitmap: 1 1 1 1 1 1 1 1 1 1 ...After freeing 1-8:
Frame: 0 1 2 3 4 5 6 7 8 9 ...
Bitmap: 1 0 0 0 0 0 0 0 0 1 ...Now:
0: free1: reserved
How Bitmap is Stored in Memory
unintptr_t *MemoryBitmap;Assume:
__BITS = 32(32-bit system)
So each entry stores 32 frames.
Example:
MemoryBitmap[0] β frames 0β31
MemoryBitmap[1] β frames 32β63Suppose:
MemoryBitmap[0] = 0b11101111Expanded:
| Bit | Frame | Value |
|---|---|---|
| 0 | Frame 0 | 1 (used) |
| 1 | Frame 1 | 1 |
| 2 | Frame 2 | 1 |
| 3 | Frame 3 | 1 |
| 4 | Frame 4 | 0 (free) |
| 5 | Frame 5 | 1 |
| 6 | Frame 6 | 1 |
| 7 | Frame 7 | 1 |
Leave a comment
Your email address will not be published. Required fields are marked *
