memory savings
This commit is contained in:
1 parent
ddb074f0e0
commit
def649b995
7 files changed
+2049
-1883
No files matched your search
+175
-177
@@ -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;
|
||||
}
|
||||
Reference in new issue
Block a user