ptos: pm: Add frame allocation and reclamation
Signed-off-by: Chloe M <chloe@yiffware.org>
This commit is contained in:
@@ -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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user