memory savings

This commit is contained in:
maksw committed 2026-05-14 14:57:00 +02:00
1 parent ddb074f0e0
commit def649b995
7 files changed
+2049 -1883

No files matched your search

+175 -177
View File
@@ -1,177 +1,175 @@
// mm_phys.c - physical memory manager
//
// The free-frame stack is a flat array of PHYSICAL_ADDRESS values carved out of
// the first suitable usable region before any allocation is served. All access
// to physical memory goes through the direct physical window established by the
// bootloader at PhysicalWindowBase (always 0xFFFF880000000000).
//
// Lock: a single spinlock guards Push/Pop. O(1) for both operations.
#include <mm_phys.h>
#include <ke_spinlock.h>
// ---------------------------------------------------------------------------
// Physical-to-virtual translation via the direct map window.
// ---------------------------------------------------------------------------
static uint64_t gPhysBase = 0; // set by MmInitializePhysical
static inline void* PhysToVirt(PHYSICAL_ADDRESS phys) {
return (void *)(phys + gPhysBase);
}
// ---------------------------------------------------------------------------
// Frame stack
// ---------------------------------------------------------------------------
typedef struct {
PHYSICAL_ADDRESS* Stack; // pointer into physical window
size_t Top; // index of next free slot (stack grows up)
size_t Capacity;
size_t Total; // total frames ever pushed
SPINLOCK Lock;
} FRAME_STACK;
static FRAME_STACK gFrameStack;
// Push a physical frame address onto the stack.
static void PushFrame(PHYSICAL_ADDRESS frame) {
uintptr_t flags = KeAcquireSpinlock(&gFrameStack.Lock);
if (gFrameStack.Top < gFrameStack.Capacity) {
gFrameStack.Stack[gFrameStack.Top++] = frame;
}
KeReleaseSpinlock(&gFrameStack.Lock, flags);
}
// ---------------------------------------------------------------------------
// Initialisation
// ---------------------------------------------------------------------------
bool MmInitializePhysical(const MEMORY_MAP* map, uint64_t physicalWindowBase) {
gPhysBase = physicalWindowBase;
// --- Phase 0: Count total usable frames so we can size the stack
// dynamically instead of capping at a hardcoded 1 GB. ---
uint64_t totalUsableBytes = 0;
for (uint32_t i = 0; i < map->RegionCount; i++) {
if (map->Regions[i].Type == MemoryUsable)
totalUsableBytes += map->Regions[i].Length;
}
const size_t maxFrames = (size_t)(totalUsableBytes / PAGE_SIZE);
const size_t stackBytes = maxFrames * sizeof(PHYSICAL_ADDRESS);
// --- Phase 1: Find a usable region large enough to hold the stack. ---
PHYSICAL_ADDRESS stackPhys = 0;
for (uint32_t i = 0; i < map->RegionCount; i++) {
const MEMORY_REGION* r = &map->Regions[i];
if (r->Type == MemoryUsable && r->Length >= stackBytes + PAGE_SIZE) {
stackPhys = r->Base;
break;
}
}
if (!stackPhys) {
return false;
}
gFrameStack.Stack = (PHYSICAL_ADDRESS *)PhysToVirt(stackPhys);
gFrameStack.Top = 0;
gFrameStack.Capacity = maxFrames;
gFrameStack.Total = 0;
gFrameStack.Lock = (SPINLOCK)SPINLOCK_INIT;
// --- Phase 2: Push all free 4 KB frames, skipping the stack pages. ---
const PHYSICAL_ADDRESS stackEnd =
stackPhys + ((stackBytes + PAGE_SIZE - 1) & PAGE_MASK);
for (uint32_t i = 0; i < map->RegionCount; i++) {
const MEMORY_REGION* r = &map->Regions[i];
if (r->Type != MemoryUsable) continue;
PHYSICAL_ADDRESS base = r->Base;
PHYSICAL_ADDRESS end = r->Base + r->Length;
for (PHYSICAL_ADDRESS frame = base; frame < end; frame += PAGE_SIZE) {
if (frame >= stackPhys && frame < stackEnd) continue;
if (gFrameStack.Top < gFrameStack.Capacity) {
gFrameStack.Stack[gFrameStack.Top++] = frame;
gFrameStack.Total++;
}
}
}
return true;
}
// ---------------------------------------------------------------------------
// Public API
// ---------------------------------------------------------------------------
PHYSICAL_ADDRESS MmAllocateFrame(void) {
uintptr_t flags = KeAcquireSpinlock(&gFrameStack.Lock);
if (gFrameStack.Top == 0) {
KeReleaseSpinlock(&gFrameStack.Lock, flags);
return (PHYSICAL_ADDRESS)0;
}
PHYSICAL_ADDRESS frame = gFrameStack.Stack[--gFrameStack.Top];
KeReleaseSpinlock(&gFrameStack.Lock, flags);
return frame;
}
void MmFreeFrame(PHYSICAL_ADDRESS frame) {
if (!frame || (frame & (PAGE_SIZE - 1))) return;
uintptr_t flags = KeAcquireSpinlock(&gFrameStack.Lock);
if (gFrameStack.Top < gFrameStack.Capacity)
gFrameStack.Stack[gFrameStack.Top++] = frame;
// else: stack full - leak rather than corrupt
KeReleaseSpinlock(&gFrameStack.Lock, flags);
}
__declspec(dllexport) PHYSICAL_ADDRESS MmAllocateContiguous(size_t count) {
if (!count) return (PHYSICAL_ADDRESS)0;
uintptr_t flags = KeAcquireSpinlock(&gFrameStack.Lock);
if (gFrameStack.Top < count) {
KeReleaseSpinlock(&gFrameStack.Lock, flags);
return (PHYSICAL_ADDRESS)0;
}
// Frames are pushed in ascending address order by MmInitializePhysical,
// so physically consecutive pages sit at consecutive stack indices.
// Scan from bottom upward for a run of 'count' adjacent frames.
size_t run = (size_t)-1;
for (size_t i = 0; i + count <= gFrameStack.Top; i++) {
int ok = 1;
for (size_t j = 1; j < count; j++) {
if (gFrameStack.Stack[i + j] != gFrameStack.Stack[i] + j * PAGE_SIZE) {
ok = 0;
// Skip past this broken run; the next candidate can't start
// before the frame that broke the sequence.
i += j - 1; // outer loop adds 1 more
break;
}
}
if (ok) { run = i; break; }
}
if (run == (size_t)-1) {
KeReleaseSpinlock(&gFrameStack.Lock, flags);
return (PHYSICAL_ADDRESS)0;
}
PHYSICAL_ADDRESS base = gFrameStack.Stack[run];
// Splice out the 'count' entries by sliding the tail down.
size_t tail = gFrameStack.Top - run - count;
for (size_t i = 0; i < tail; i++)
gFrameStack.Stack[run + i] = gFrameStack.Stack[run + count + i];
gFrameStack.Top -= count;
KeReleaseSpinlock(&gFrameStack.Lock, flags);
return base;
}
size_t MmFreeFrameCount(void) {
return gFrameStack.Top;
}
size_t MmTotalFrameCount(void) {
return gFrameStack.Total;
}
// mm_phys.c - physical memory manager
//
// The free-frame stack is a flat array of PHYSICAL_ADDRESS values carved out of
// the first suitable usable region before any allocation is served. All access
// to physical memory goes through the direct physical window established by the
// bootloader at PhysicalWindowBase (always 0xFFFF880000000000).
//
// Lock: a single spinlock guards Push/Pop. O(1) for both operations.
#include <mm_phys.h>
#include <ke_spinlock.h>
// ---------------------------------------------------------------------------
// Physical-to-virtual translation via the direct map window.
// ---------------------------------------------------------------------------
static uint64_t gPhysBase = 0; // set by MmInitializePhysical
static inline void* PhysToVirt(PHYSICAL_ADDRESS phys) {
return (void *)(phys + gPhysBase);
}
// ---------------------------------------------------------------------------
// Frame stack
// ---------------------------------------------------------------------------
typedef struct {
PHYSICAL_ADDRESS* Stack; // pointer into physical window
size_t Top; // index of next free slot (stack grows up)
size_t Capacity;
size_t Total; // total frames ever pushed
SPINLOCK Lock;
} FRAME_STACK;
static FRAME_STACK gFrameStack;
// Push a physical frame address onto the stack.
static void PushFrame(PHYSICAL_ADDRESS frame) {
uintptr_t flags = KeAcquireSpinlock(&gFrameStack.Lock);
if (gFrameStack.Top < gFrameStack.Capacity) {
gFrameStack.Stack[gFrameStack.Top++] = frame;
gFrameStack.Total++;
}
KeReleaseSpinlock(&gFrameStack.Lock, flags);
}
// ---------------------------------------------------------------------------
// Initialisation
// ---------------------------------------------------------------------------
bool MmInitializePhysical(const MEMORY_MAP* map, uint64_t physicalWindowBase) {
gPhysBase = physicalWindowBase;
// --- Phase 0: Count total usable frames so we can size the stack
// dynamically instead of capping at a hardcoded 1 GB. ---
uint64_t totalUsableBytes = 0;
for (uint32_t i = 0; i < map->RegionCount; i++) {
if (map->Regions[i].Type == MemoryUsable)
totalUsableBytes += map->Regions[i].Length;
}
const size_t maxFrames = (size_t)(totalUsableBytes / PAGE_SIZE);
const size_t stackBytes = maxFrames * sizeof(PHYSICAL_ADDRESS);
// --- Phase 1: Find a usable region large enough to hold the stack. ---
PHYSICAL_ADDRESS stackPhys = 0;
for (uint32_t i = 0; i < map->RegionCount; i++) {
const MEMORY_REGION* r = &map->Regions[i];
if (r->Type == MemoryUsable && r->Length >= stackBytes + PAGE_SIZE) {
stackPhys = r->Base;
break;
}
}
if (!stackPhys) {
return false;
}
gFrameStack.Stack = (PHYSICAL_ADDRESS *)PhysToVirt(stackPhys);
gFrameStack.Top = 0;
gFrameStack.Capacity = maxFrames;
gFrameStack.Total = 0;
gFrameStack.Lock = (SPINLOCK)SPINLOCK_INIT;
// --- Phase 2: Push all free 4 KB frames, skipping the stack pages. ---
const PHYSICAL_ADDRESS stackEnd =
stackPhys + ((stackBytes + PAGE_SIZE - 1) & PAGE_MASK);
for (uint32_t i = 0; i < map->RegionCount; i++) {
const MEMORY_REGION* r = &map->Regions[i];
if (r->Type != MemoryUsable) continue;
PHYSICAL_ADDRESS base = r->Base;
PHYSICAL_ADDRESS end = r->Base + r->Length;
for (PHYSICAL_ADDRESS frame = base; frame < end; frame += PAGE_SIZE) {
if (frame >= stackPhys && frame < stackEnd) continue;
PushFrame(frame);
}
}
return true;
}
// ---------------------------------------------------------------------------
// Public API
// ---------------------------------------------------------------------------
PHYSICAL_ADDRESS MmAllocateFrame(void) {
uintptr_t flags = KeAcquireSpinlock(&gFrameStack.Lock);
if (gFrameStack.Top == 0) {
KeReleaseSpinlock(&gFrameStack.Lock, flags);
return (PHYSICAL_ADDRESS)0;
}
PHYSICAL_ADDRESS frame = gFrameStack.Stack[--gFrameStack.Top];
KeReleaseSpinlock(&gFrameStack.Lock, flags);
return frame;
}
void MmFreeFrame(PHYSICAL_ADDRESS frame) {
if (!frame || (frame & (PAGE_SIZE - 1))) return;
uintptr_t flags = KeAcquireSpinlock(&gFrameStack.Lock);
if (gFrameStack.Top < gFrameStack.Capacity)
gFrameStack.Stack[gFrameStack.Top++] = frame;
// else: stack full - leak rather than corrupt
KeReleaseSpinlock(&gFrameStack.Lock, flags);
}
__declspec(dllexport) PHYSICAL_ADDRESS MmAllocateContiguous(size_t count) {
if (!count) return (PHYSICAL_ADDRESS)0;
uintptr_t flags = KeAcquireSpinlock(&gFrameStack.Lock);
if (gFrameStack.Top < count) {
KeReleaseSpinlock(&gFrameStack.Lock, flags);
return (PHYSICAL_ADDRESS)0;
}
// Frames are pushed in ascending address order by MmInitializePhysical,
// so physically consecutive pages sit at consecutive stack indices.
// Scan from bottom upward for a run of 'count' adjacent frames.
size_t run = (size_t)-1;
for (size_t i = 0; i + count <= gFrameStack.Top; i++) {
int ok = 1;
for (size_t j = 1; j < count; j++) {
if (gFrameStack.Stack[i + j] != gFrameStack.Stack[i] + j * PAGE_SIZE) {
ok = 0;
// Skip past this broken run; the next candidate can't start
// before the frame that broke the sequence.
i += j - 1; // outer loop adds 1 more
break;
}
}
if (ok) { run = i; break; }
}
if (run == (size_t)-1) {
KeReleaseSpinlock(&gFrameStack.Lock, flags);
return (PHYSICAL_ADDRESS)0;
}
PHYSICAL_ADDRESS base = gFrameStack.Stack[run];
// Splice out the 'count' entries by sliding the tail down.
size_t tail = gFrameStack.Top - run - count;
for (size_t i = 0; i < tail; i++)
gFrameStack.Stack[run + i] = gFrameStack.Stack[run + count + i];
gFrameStack.Top -= count;
KeReleaseSpinlock(&gFrameStack.Lock, flags);
return base;
}
size_t MmFreeFrameCount(void) {
return gFrameStack.Top;
}
size_t MmTotalFrameCount(void) {
return gFrameStack.Total;
}