From 79bbbc074bd1d96bb56256bc0e4c6603a93673af Mon Sep 17 00:00:00 2001 From: Chloe M Date: Fri, 10 Jul 2026 19:07:11 -0400 Subject: [PATCH] ptos: pm: Add frame allocation and reclamation Signed-off-by: Chloe M --- service/ptos/head/mm/pm.h | 17 +++++ service/ptos/mm/pm.c | 145 +++++++++++++++++++++++++++++++++++++- 2 files changed, 159 insertions(+), 3 deletions(-) diff --git a/service/ptos/head/mm/pm.h b/service/ptos/head/mm/pm.h index 0b56361..74899d9 100644 --- a/service/ptos/head/mm/pm.h +++ b/service/ptos/head/mm/pm.h @@ -12,6 +12,9 @@ #include #include +/* Used when out of memory */ +#define PFN_ERROR 0 + /* Page frame number type */ typedef USIZE MM_PFN; @@ -29,4 +32,18 @@ typedef USIZE MM_PFN; */ VOID MmPmInit(VOID); +/* + * Request a single frame of memory + * + * Returns PFN_ERROR on failure + */ +MM_PFN MmRequestFrame(VOID); + +/* + * Reclaim a single frame of memory + * + * @Pfn: Page frame number to reclaim + */ +VOID MmReclaimFrame(MM_PFN Pfn); + #endif /* !_MM_PM_H_ */ diff --git a/service/ptos/mm/pm.c b/service/ptos/mm/pm.c index ca537cf..0712f74 100644 --- a/service/ptos/mm/pm.c +++ b/service/ptos/mm/pm.c @@ -7,8 +7,10 @@ */ #include +#include #include #include +#include #define DTRACE(Fmt, ...) \ TRACE("[ PM ]: " Fmt, ##__VA_ARGS__) @@ -34,6 +36,88 @@ static const CHAR *PmRegionTable[] = { [MEMORY_ACPI_TABLES] = "acpi tables" }; +/* + * A page frame descriptor is an entry within the physical memory + * freelist. + * + * @Next: Next PFD in freelist + * @Prev: Previous PFD in freelist + */ +typedef struct _MM_PFD { + struct _MM_PFD *Next; + struct _MM_PFD *Prev; +} MM_PFD; + +/* + * A page frame descriptor list holds many page frame + * descriptors and marks the start and end of a physical + * memory freelist. + * + * @First: First entry in freelist + * @Last: Last entry in freelist + * + * TODO: Add a lock to this structure + */ +typedef struct { + MM_PFD *First; + MM_PFD *Last; +} MM_PFD_LIST; + +/* Standard usable memory list */ +static MM_PFD_LIST AvlList; + +/* + * Appends a page frame descriptor to a page frame descriptor + * list. + * + * @List: Page frame descriptor list to append to + * @Pfd: Page frame descriptor to append + */ +static VOID +PmPfdListAppend(MM_PFD_LIST *List, MM_PFD *Pfd) +{ + MM_PFD *LastPfd; + + if (List == NULL || Pfd == NULL) { + return; + } + + Pfd->Next = NULL; + Pfd->Prev = NULL; + + if (List->First == NULL || List->Last == NULL) { + List->First = Pfd; + List->Last = Pfd; + } else { + LastPfd = List->Last; + LastPfd->Next = Pfd; + Pfd->Prev = LastPfd; + List->Last = Pfd; + } +} + +/* + * Pop a page frame descriptor from the beginning of a page + * frame descriptor list. + * + * @List: Page frame descriptor list to pop from + * + * Returns NULL on failure + */ +static MM_PFD * +PmPfdListPop(MM_PFD_LIST *List) +{ + MM_PFD *FirstPfd; + + if (List == NULL) { + return NULL; + } + + FirstPfd = List->First; + List->First = FirstPfd->Next; + return FirstPfd; +} + /* * Probe physical memory for usable regions and list * installed memory. @@ -44,8 +128,10 @@ PmProbe(VOID) PT_STATUS Status; BPAL_HANDLE BpalHandle; MEMMAP_ENTRY Entry; - UPTR Start, End; - USIZE Index; + UPTR Start, End, Off; + MM_PFD *PfdBase, *PfdCurrent; + USIZE Index, PfdCount = 0; + USIZE ZoneCount = 0; /* * We obtain memory map entries from the BPAL layer as it is provided @@ -53,7 +139,15 @@ PmProbe(VOID) */ KeBpalGetHandle(&BpalHandle); - /* Iterate each memory entry */ + /* + * Iterate each memory entry, we use two terms here: + * + * Zones: A zone is a contigious region of frames and consists + * of many page frame descriptors. + * + * PFDs: A page frame descriptor represents a single frame within + * a zone. + */ for (Index = 0;; ++Index) { Status = BpalHandle.MemEntryIdx(Index, &Entry); @@ -70,7 +164,52 @@ PmProbe(VOID) End, PM_REGION(Entry.Type) ); + + /* Usable entries from this point only */ + if (Entry.Type != MEMORY_USABLE) { + continue; + } + + /* Append this zone */ + PfdBase = (MM_PFD *)PMA_TO_VMA(Entry.Base); + for (Off = 0; Off < Entry.Length; Off += PAGESIZE) { + PfdCurrent = PTR_OFFSET(PfdBase, Off); + PmPfdListAppend(&AvlList, PfdCurrent); + ++PfdCount; + } + + ++ZoneCount; } + + DTRACE("%d pfds, %d zones\n", PfdCount, ZoneCount); +} + +MM_PFN +MmRequestFrame(VOID) +{ + MM_PFD *Pfd; + UPTR PhysicalBase; + + Pfd = PmPfdListPop(&AvlList); + RtlMemSet(Pfd, 0, PAGESIZE); + + PhysicalBase = (UPTR)Pfd; + return ADDRESS_TO_PFN(PhysicalBase); +} + +VOID +MmReclaimFrame(MM_PFN Pfn) +{ + MM_PFD *Pfd; + UPTR PhysicalBase; + + if (Pfn == PFN_ERROR) { + return; + } + + PhysicalBase = PFN_TO_ADDRESS(Pfn); + Pfd = (VOID *)PMA_TO_VMA(PhysicalBase); + PmPfdListAppend(&AvlList, Pfd); } VOID