Files
SystemPaw3/paw/stos/mm/vmm.c
T
Chloe M. 7ce1cf27d1 stos: mm: Add locking to VAD lists
Signed-off-by: Chloe M. <chloe@mensia.org>
2026-06-23 22:27:05 +00:00

143 lines
3.1 KiB
C

/*
* Copyright (c) 2026, Chloe M.
* Provided under the BSD-3 clause.
*
* Description: Virtual memory manager
* Author: Chloe M.
*/
#include <mm/vmm.h>
#include <mm/vad.h>
#include <mm/pmm.h>
#include <hal/mmu.h>
#include <hal/page.h>
#include <ex/trace.h>
#include <ke/knot.h>
#include <ke/spinlock.h>
#include <stapi/status.h>
#include <string.h>
#define VALLOC_MAX_PAGES 8192
#define VALLOC_MAX (VALLOC_BASE + (VALLOC_MAX_PAGES * PAGESIZE))
#define PAGES_PER_GRAB 16
#define DTRACE(Fmt, ...) \
TRACE("[ VMM ]: " Fmt, ##__VA_ARGS__)
static MMU_VAS KernelVas;
static MM_VAD_LIST VadList;
static UPTR BumpPtr;
static SPINLOCK VadListLock;
static ST_STATUS
MmGrabPages(VOID)
{
USIZE MaxOff;
UPTR AllocBase;
MMU_VAS Vas;
MM_PFN AllocPfn;
ST_STATUS Status;
MaxOff = PAGES_PER_GRAB * PAGESIZE;
HalMmuReadVas(&Vas);
KeSpinLockAcquire(&VadListLock, true);
for (USIZE Off = 0; Off < MaxOff; Off += PAGESIZE) {
/* Don't blast past the limit */
if ((BumpPtr + Off) >= VALLOC_MAX) {
return STATUS_NO_MEMORY;
}
AllocBase = BumpPtr + Off;
AllocPfn = MmRequestFrame();
if (AllocPfn == 0) {
KeSpinLockRelease(&VadListLock);
return STATUS_NO_MEMORY;
}
Status = HalMmuMapSingle(
&Vas,
AllocBase,
AllocPfn << LOG2_PAGESIZE,
PAGE_READWRITE,
PAGESIZE_4K
);
if (Status != STATUS_SUCCESS) {
KeSpinLockRelease(&VadListLock);
return Status;
}
MmVadListAppend(&VadList, VAD_FROM_VMA(AllocBase));
}
BumpPtr = AllocBase;
KeSpinLockRelease(&VadListLock);
return STATUS_SUCCESS;
}
VOID *
MmAllocPages(USIZE Count)
{
MM_VAD *First, *Vad;
ST_STATUS Status;
if (Count == 0) {
return NULL;
}
First = NULL;
/*
* Request a VAD from the allocation VAD list and pull in
* more pages if we need to.
*
* XXX: We need to consider how we'll deal with fragmentation
* here, once it fills up it may become fragmented.
*/
for (USIZE Iter = 0; Iter < Count; ++Iter) {
Vad = MmVadListPop(&VadList);
if (Vad == NULL) {
Status = MmGrabPages();
if (Status != STATUS_SUCCESS)
return NULL;
Vad = MmVadListPop(&VadList);
}
/* Still no pages? */
if (Vad == NULL) {
return NULL;
}
if (First == NULL) {
First = Vad;
}
}
RtlMemSet(First, 0, sizeof(*First));
return (VOID *)First;
}
VOID
MmInitVmm(VOID)
{
MMU_VAS OldVas;
ST_STATUS Status;
DTRACE("breeding kvas from bootstrap instance...\n");
HalMmuReadVas(&OldVas);
Status = HalMmuForkVas(&OldVas, &KernelVas);
if (Status != STATUS_SUCCESS) {
KeKnot(KNOT_OOM, "could not fork bootstrap vas\n");
}
HalMmuWriteVas(&KernelVas);
DTRACE("ah!~... [ok @ %p]\n", VAS_BASE(&KernelVas));
BumpPtr = VALLOC_BASE;
KeSpinLockInit(&VadListLock, "vmm-vad");
KeSpinLockInit(&VadList.Lock, "vmm-vadlist");
}