Files
2026-06-22 06:50:36 +00:00

231 lines
4.7 KiB
C

/*
* Copyright (c) 2026, Chloe M.
* Provided under the BSD-3 clause.
*
* Description: Physical memory management
* Author: Chloe M.
*/
#include <ex/trace.h>
#include <ke/bpal.h>
#include <mm/pmm.h>
#include <mm/vmm.h>
#include <hal/page.h>
#include <units.h>
#include <stdef.h>
#include <string.h>
#define LOAD_DELAY 128
#define DTRACE(Fmt, ...) \
TRACE("[ PMM ]: " Fmt, ##__VA_ARGS__)
/* Use to convert type constants to strings */
#define MEM_TYPE(TYPE) \
((TYPE) < NELEM(TypeTab)) \
? TypeTab[(TYPE)] \
: "invalid"
/*
* Physical frame descriptor
*
* @Next: Next PFD in list
* @Prev: Previous PFD in list
*/
typedef struct _MM_PFD {
struct _MM_PFD *Next;
struct _MM_PFD *Prev;
} MM_PFD;
/*
* Page frame descriptor list
*
* @First: First entry in list
* @Last: Last entry in list
*/
typedef struct {
MM_PFD *First;
MM_PFD *Last;
} MM_PFD_LIST;
/*
* Memory type constant to human readable
* string table.
*/
static const char *TypeTab[] = {
[MEMORY_USABLE] = "usable",
[MEMORY_RESERVED] = "reserved",
[MEMORY_ACPI_RECLAIM] = "acpi reclaimable",
[MEMORY_ACPI_NVS] = "acpi nvs",
[MEMORY_BAD] = "bad*",
[MEMORY_BOOTLOADER] = "bootloader",
[MEMORY_KERNEL] = "stoskrnl.sys",
[MEMORY_FRAMEBUFFER] = "framebuffer",
[MEMORY_ACPI_TABLES] = "acpi tables"
};
/* Globals */
static USIZE UsableMemory = 0;
static MM_PFD_LIST PfdList;
/*
* Append a page frame descriptor to a page frame descriptor list
*
* @List: PFD list to append to
* @Pfd: PFD to append
*/
static VOID
MmPfdAppend(MM_PFD_LIST *List, MM_PFD *Pfd)
{
MM_PFD *Last;
if (List == NULL || Pfd == NULL) {
return;
}
if (List->Last == NULL || List->First == NULL) {
List->Last = Pfd;
List->First = Pfd;
} else {
Last = List->Last;
Pfd->Prev = Last;
Last->Next = Pfd;
List->Last = Pfd;
}
}
/*
* Pop a page frame descriptor from a page frame descriptor list
*
* @List: Page frame descriptor list to pop from
*
* Returns NULL if there are no entries left
*/
static MM_PFD *
MmPfdPop(MM_PFD_LIST *List)
{
MM_PFD *Last, *Prev;
if (List == NULL) {
return NULL;
}
Last = List->Last;
if (Last == NULL) {
return NULL;
}
/* Unlink from the list */
Prev = Last->Prev;
List->Last = List->Last->Prev;
Prev->Next = NULL;
List->Last = Prev;
return Last;
}
/*
* Print the units of a size in a pretty format
*
* @Length: Number of bytes
* @Title: Title of units
*/
static inline VOID
MmPrintUnits(USIZE Length, const CHAR *Title)
{
if (Title == NULL) {
return;
}
if (Length >= UNIT_GIB) {
DTRACE("%d gib %s\n", Length / UNIT_GIB, Title);
} else if (Length >= UNIT_MIB) {
DTRACE("%d mib %s\n", Length / UNIT_MIB, Title);
} else {
DTRACE("%010d b %s\n", Length, Title);
}
}
/*
* Display a loading status
*/
static VOID
MmLoadUpdate(VOID)
{
const UCHAR LoadMax = 3;
static UCHAR LoadIdx = 0;
static CHAR LoadProg[3] = {'/', '-', '\\'};
TRACE("\x1b[?25l%c \b\b", LoadProg[LoadIdx++]);
LoadIdx %= LoadMax;
}
MM_PFN
MmRequestFrame(VOID)
{
MM_PFD *Pfd;
UPTR Pma;
Pfd = MmPfdPop(&PfdList);
if (Pfd == NULL) {
return 0;
}
RtlMemSet(Pfd, 0, PAGESIZE);
Pma = VMA_TO_PMA(Pfd);
return Pma >> LOG2_PAGESIZE;
}
static VOID
MmProbeMemory(VOID)
{
BPAL_HANDLE BpalHandle;
MEMMAP_ENTRY Entry;
UPTR EntryEnd;
VOID *Vma, *Base;
USIZE Idx, Offset;
USIZE EntryCount = 0;
ST_STATUS Status;
KeBpalGetHandle(&BpalHandle);
for (Idx = 0;; ++Idx) {
Status = BpalHandle.MemEntryIdx(Idx, &Entry);
if (Status != STATUS_SUCCESS) {
break;
}
EntryEnd = Entry.Base + Entry.Length;
DTRACE("[%p - %p) ~ %s\n", Entry.Base, EntryEnd, MEM_TYPE(Entry.Type));
/* Only usable entries from this point on */
if (Entry.Type != MEMORY_USABLE) {
continue;
}
Base = PMA_TO_VMA(Entry.Base);
for (Offset = 0; Offset < Entry.Length; Offset += PAGESIZE) {
Vma = PTR_OFFSET(Base, Offset);
MmPfdAppend(&PfdList, Vma);
EntryCount++;
/* Display a little loader as this takes awhile */
if ((EntryCount & (LOAD_DELAY - 1)) == 0) {
MmLoadUpdate();
}
}
UsableMemory += Entry.Length;
}
TRACE("\b\x1b[?25h");
DTRACE("%d entries populated\n", EntryCount);
MmPrintUnits(UsableMemory, "avl");
}
VOID
MmInitPmm(VOID)
{
DTRACE("sniffing out installed ram...\n");
MmProbeMemory();
}