feat: overhaul userspace heap and virtual memory

This commit is contained in:
2026-08-10 12:25:27 +02:00
parent 4ecec32c5c
commit 9b23d99082
21 changed files with 905 additions and 451 deletions
+20 -18
View File
@@ -9,49 +9,51 @@
.SH DESCRIPTION
The userspace heap provides dynamic memory allocation on top of
the kernel's page-mapping syscall (SYS_ALLOC). Include the
header <montauk/heap.h> to use these functions.
anonymous virtual memory. The Montauk C++ API and libc's
malloc/free API use the same process-wide allocator.
.SS malloc
Allocates 'size' bytes from the free list. Returns a 16-byte
aligned pointer, or nullptr on failure. When the free list is
empty, it requests more pages from the kernel via SYS_ALLOC
(minimum 16 KiB growth, initial seed of 64 KiB).
empty, it reserves more pages from the kernel. Physical pages
are committed as they are first touched.
char* buf = (char*)montauk::malloc(1024);
.SS mfree
Returns the block to the userspace free list. No syscall is
made -- the memory stays mapped and is immediately reusable.
Returns the block to the userspace allocator. Arena blocks are
immediately reusable; large direct mappings are returned to the
kernel, including their virtual address range.
Passing nullptr is a safe no-op.
montauk::mfree(buf);
.SS realloc
Resizes the allocation to 'size' bytes. Allocates a new block,
copies the smaller of old/new sizes, and frees the old block.
Resizes the allocation to 'size' bytes. A block with sufficient
capacity is retained; otherwise a new block is allocated, the
smaller of old/new requested sizes is copied, and the old block
is freed. Integer overflow fails without changing the old block.
If ptr is nullptr, behaves like malloc.
buf = (char*)montauk::realloc(buf, 2048);
.SH IMPLEMENTATION
The allocator uses a linked free-list with first-fit search.
Blocks larger than needed are split. The allocation header is
16 bytes (magic + size). All allocations are 16-byte aligned.
The allocator uses segregated size-class bins and a coalescing
address-ordered overflow list. Headers retain both requested size
and actual block extent. A process-wide lock serializes C and C++
allocation calls. All returned pointers are 16-byte aligned.
The heap grows by requesting pages from the kernel via
SYS_ALLOC. These pages are never returned to the kernel (since
SYS_FREE is currently a no-op), but mfree makes them available
for future malloc calls within the process.
Allocations of 256 KiB or more use direct page mappings so they
can be released promptly. Smaller allocations use growing arenas.
.SH LOW-LEVEL PAGE API
For large allocations or when direct page control is needed:
void* montauk::alloc(uint64_t size); // SYS_ALLOC
void montauk::free(void* ptr); // SYS_FREE (no-op)
void montauk::free(void* ptr); // SYS_FREE
alloc() maps zeroed pages starting at 0x40000000 and growing
upward. Size is rounded up to 4 KiB page boundaries.
alloc() reserves zero-filled, read/write, non-executable pages.
Size is rounded up to 4 KiB. Freed ranges are reusable.
.SH SEE ALSO
syscalls(2), file(2)