SilverOS manages physical memory through two cooperating subsystems: a bitmap physical memory manager (PMM) that tracks 4 KB pages, and a linked-list heap allocator that carves a fixed 4 MB region into variable-size kernel allocations. There is no virtual memory paging beyond the identity-mapped page tables set up in the assembly entry stub — every address the kernel uses is a direct physical address. This page documents the memory map, both allocators’ internals, and their public APIs.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/pastaboy12345/SilverOS/llms.txt
Use this file to discover all available pages before exploring further.
SilverOS does not use demand paging or virtual address translation beyond the identity map established at boot. All physical addresses are directly accessible in the kernel’s flat 64-bit address space. PMM and heap addresses are identical to physical machine addresses.
Physical memory map
The regions below describe how physical memory is divided at runtime. Sizes are approximate;_kernel_end is determined by the linker and varies with the build.
| Region | Address range | Description |
|---|---|---|
| IVT / BIOS data | 0x00000000 – 0x000FFFFF | First 1 MB — real-mode interrupt vector table, BIOS data area, option ROMs. Never touched by the kernel after boot. |
| Kernel image | 0x00100000 (1 MB) – _kernel_end | ELF sections loaded by GRUB2: .multiboot, .text, .rodata, .data, .bss. Range recorded by linker symbols _kernel_start / _kernel_end. |
| First 2 MB guard | 0x00000000 – 0x001FFFFF | The PMM unconditionally marks every page below 0x200000 as reserved, regardless of the Multiboot2 memory map, to prevent accidental allocation of BIOS or boot structures. |
| Kernel heap | 0x01000000 (16 MB) – 0x013FFFFF | 4 MB fixed-size heap managed by kmalloc / kfree. Defined by HEAP_START = 0x1000000 and HEAP_SIZE = 4 * 1024 * 1024 in kernel.c. |
| Free pages | Above _kernel_end and above 0x200000 | All pages in MULTIBOOT2_MEMORY_AVAILABLE regions that pass the reservation checks are tracked by the PMM bitmap and available for pmm_alloc_page(). |
| Upper memory | Up to ~4 GB | The PMM bitmap supports up to MAX_PAGES = 1 048 576 pages (4 GB). Pages beyond the installed RAM are never freed and remain marked as used in the bitmap. |
Physical Memory Manager (PMM)
The PMM inkernel/pmm.c uses a flat bitmap: one bit per 4 KB page, stored in a static uint8_t page_bitmap[MAX_PAGES / 8] array. A set bit (1) means the page is in use or reserved; a clear bit (0) means the page is free.
Design constants
MAX_PAGES / 8 = 131 072 bytes (128 KB) in the .bss section — a fixed, compile-time cost regardless of installed RAM.
Initialisation
pmm_init is called from kernel_main after the Multiboot2 info has been parsed:
- Mark everything as used —
memset(page_bitmap, 0xFF, sizeof(page_bitmap))sets every bit, making the entire address space appear reserved. - Walk the Multiboot2 memory map — for each entry with
type == MULTIBOOT2_MEMORY_AVAILABLE, iterate through its pages and callbitmap_clear(page)to mark them free. - Apply hard reservations — any page whose physical address is below
kernel_endor below0x200000is skipped and stays marked used, regardless of what the memory map says. - Fallback without a memory map — if GRUB2 provided no
MMAPtag, the PMM falls back to freeing pages starting just abovemax(kernel_end, 512 pages), up tomem_size / PAGE_SIZE.
pmm_init returns, pmm_get_free_pages() reports the available page count, and the kernel prints something like:
Public API
pmm_alloc_page()
Scans the bitmap from page index 0 upward for the first clear bit. When found:
- Sets the bit (
bitmap_set(i)) to mark the page in use. - Decrements
free_pages. - Zeroes the page with
memset(addr, 0, PAGE_SIZE)— every allocated page is clean. - Returns the physical address
(void *)(i * PAGE_SIZE).
NULL and logs an error if no free pages remain.
pmm_free_page(addr)
Converts addr to a page index (addr / PAGE_SIZE), validates it is within total_pages and currently marked used, then calls bitmap_clear(page) and increments free_pages.
Bitmap helpers
The three inline helpers used throughoutpmm.c:
Kernel Heap Allocator
The heap allocator inkernel/heap.c manages a single contiguous region using an intrusive singly-linked list of block headers. It is initialised once and used for all dynamic kernel allocations via kmalloc / kfree.
Heap region
Block header layout
Every allocation (free or in-use) is prefixed by aheap_block header:
heap_init time the entire heap is a single free block:
kmalloc(size)
- Alignment —
sizeis rounded up to the nearest 16-byte boundary usingALIGN_UP(size, 16). - First-fit search — the free list is walked from
heap_start; the first block withfree == trueandblock->size >= sizeis selected. - Block splitting — if the chosen block is large enough to hold the requested allocation plus a new header plus at least 64 bytes of usable space (
block->size >= size + sizeof(heap_block) + 64), the tail is split off as a new free block. This prevents wasting large free blocks on small allocations. - Mark in use —
block->free = false. - Return — a pointer to the byte immediately after the header:
(void *)((uint8_t *)block + sizeof(heap_block)).
NULL and logs an error if no suitable block exists.
kfree(ptr)
- Recovers the block header:
block = (heap_block *)((uint8_t *)ptr - sizeof(heap_block)). - Sets
block->free = true. - Forward coalesce — if
block->nextis also free, merges it intoblockby absorbing its size and header, and skipping its pointer. - Backward coalesce — walks from
heap_startto find the block whosenextpoints toblock. If that predecessor is free, the predecessor absorbsblock.
kcalloc and krealloc
kcalloc— callskmalloc(count * size)and zeroes the result withmemset.krealloc— if the existing block is already large enough, returnsptrunchanged. Otherwisekmallocs a new region,memcpys the old content (up toblock->sizebytes),kfrees the original, and returns the new pointer.
Public API
Address space overview
SilverOS runs entirely in ring 0 with a single flat 64-bit address space. The page tables built inboot.asm identity-map the first 4 GB using 2 MB huge pages, so virtual address N equals physical address N for all addresses in that range. There is no user-space ring-3 separation, no ASLR, and no demand paging in the current version.
Because all addresses are identity-mapped physical addresses, both
pmm_alloc_page() and kmalloc() return pointers that are directly dereferenceable in C — no mmap or virtual-address translation step is required.