ptos: pm: Add frame allocation and reclamation

Signed-off-by: Chloe M <chloe@yiffware.org>
This commit is contained in:
2026-07-10 19:07:11 -04:00
parent 92f4720898
commit 79bbbc074b
2 changed files with 159 additions and 3 deletions
+17
View File
@@ -12,6 +12,9 @@
#include <ptdef.h>
#include <hal/page.h>
/* 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_ */
+142 -3
View File
@@ -7,8 +7,10 @@
*/
#include <mm/pm.h>
#include <mm/vm.h>
#include <ke/bpal.h>
#include <ex/trace.h>
#include <string.h>
#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