memory savings
This commit is contained in:
1 parent
ddb074f0e0
commit
def649b995
7 files changed
+193
-27
No files matched your search
Binary file not shown.
+125
-21
@@ -109,21 +109,91 @@ static UINT64* AllocPage(EFI_PHYSICAL_ADDRESS* physOut) {
|
||||
#define PDT_IDX(va) (((va) >> 21) & 0x1FF)
|
||||
#define PT_IDX(va) (((va) >> 12) & 0x1FF)
|
||||
|
||||
#define PAGE_2M (2ULL * 1024ULL * 1024ULL)
|
||||
#define PAGE_1G (1024ULL * 1024ULL * 1024ULL)
|
||||
|
||||
static UINT64* gPml4;
|
||||
|
||||
static void MapPage(UINT64 virt, UINT64 phys, UINT64 flags) {
|
||||
UINT64* pml4e = &gPml4[PML4_IDX(virt)];
|
||||
if (!(*pml4e & 1)) { EFI_PHYSICAL_ADDRESS p; AllocPage(&p); *pml4e = p | 3; }
|
||||
UINT64* pdpt = (UINT64 *)(*pml4e & ~0xFFFULL);
|
||||
UINT64* pdpte = &pdpt[PDPT_IDX(virt)];
|
||||
if (!(*pdpte & 1)) { EFI_PHYSICAL_ADDRESS p; AllocPage(&p); *pdpte = p | 3; }
|
||||
UINT64* pdt = (UINT64 *)(*pdpte & ~0xFFFULL);
|
||||
UINT64* pdte = &pdt[PDT_IDX(virt)];
|
||||
if (!(*pdte & 1)) { EFI_PHYSICAL_ADDRESS p; AllocPage(&p); *pdte = p | 3; }
|
||||
UINT64* pt = (UINT64 *)(*pdte & ~0xFFFULL);
|
||||
static UINT64* EnsureTable(UINT64* parent, UINTN index) {
|
||||
UINT64* entry = &parent[index];
|
||||
if (!(*entry & 1)) {
|
||||
EFI_PHYSICAL_ADDRESS p;
|
||||
UINT64* child = AllocPage(&p);
|
||||
*entry = p | 3;
|
||||
return child;
|
||||
}
|
||||
return (UINT64 *)(*entry & ~0xFFFULL);
|
||||
}
|
||||
|
||||
static void Map4K(UINT64 virt, UINT64 phys, UINT64 flags) {
|
||||
UINT64* pdpt = EnsureTable(gPml4, PML4_IDX(virt));
|
||||
UINT64* pdt = EnsureTable(pdpt, PDPT_IDX(virt));
|
||||
UINT64* pt = EnsureTable(pdt, PDT_IDX(virt));
|
||||
pt[PT_IDX(virt)] = phys | flags;
|
||||
}
|
||||
|
||||
static void Map2M(UINT64 virt, UINT64 phys, UINT64 flags) {
|
||||
UINT64* pdpt = EnsureTable(gPml4, PML4_IDX(virt));
|
||||
UINT64* pdt = EnsureTable(pdpt, PDPT_IDX(virt));
|
||||
pdt[PDT_IDX(virt)] = phys | flags | 0x80ULL; // PS bit
|
||||
}
|
||||
|
||||
static void Map1G(UINT64 virt, UINT64 phys, UINT64 flags) {
|
||||
UINT64* pdpt = EnsureTable(gPml4, PML4_IDX(virt));
|
||||
pdpt[PDPT_IDX(virt)] = phys | flags | 0x80ULL; // PS bit
|
||||
}
|
||||
|
||||
static void MapRangeSmart(UINT64 virt, UINT64 phys, UINT64 size, UINT64 flags) {
|
||||
while (size) {
|
||||
if ((virt & (PAGE_1G - 1)) == 0 && (phys & (PAGE_1G - 1)) == 0 && size >= PAGE_1G) {
|
||||
Map1G(virt, phys, flags);
|
||||
virt += PAGE_1G;
|
||||
phys += PAGE_1G;
|
||||
size -= PAGE_1G;
|
||||
} else if ((virt & (PAGE_2M - 1)) == 0 && (phys & (PAGE_2M - 1)) == 0 && size >= PAGE_2M) {
|
||||
Map2M(virt, phys, flags);
|
||||
virt += PAGE_2M;
|
||||
phys += PAGE_2M;
|
||||
size -= PAGE_2M;
|
||||
} else {
|
||||
Map4K(virt, phys, flags);
|
||||
virt += PAGE_SIZE;
|
||||
phys += PAGE_SIZE;
|
||||
size -= PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void MapRangeSkipping(UINT64 virt, UINT64 phys, UINT64 size, UINT64 flags,
|
||||
const UINT64* holes, UINTN holeCount) {
|
||||
UINT64 curVirt = virt;
|
||||
UINT64 curPhys = phys;
|
||||
UINT64 end = virt + size;
|
||||
|
||||
for (UINTN i = 0; i < holeCount; i++) {
|
||||
UINT64 hStart = holes[i * 2 + 0];
|
||||
UINT64 hEnd = holes[i * 2 + 1];
|
||||
if (hEnd <= curVirt || hStart >= end) continue;
|
||||
|
||||
if (curVirt < hStart) {
|
||||
UINT64 prefixSize = hStart - curVirt;
|
||||
MapRangeSmart(curVirt, curPhys, prefixSize, flags);
|
||||
curPhys += prefixSize;
|
||||
curVirt += prefixSize;
|
||||
}
|
||||
|
||||
if (curVirt < hEnd) {
|
||||
UINT64 skip = hEnd - curVirt;
|
||||
curVirt += skip;
|
||||
curPhys += skip;
|
||||
}
|
||||
}
|
||||
|
||||
if (curVirt < end) {
|
||||
MapRangeSmart(curVirt, curPhys, end - curVirt, flags);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// File loading
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -592,7 +662,7 @@ EFI_STATUS EFIAPI UefiMain(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable
|
||||
imgLen = (imgLen + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
|
||||
|
||||
for (UINT64 off = 0; off < imgLen; off += PAGE_SIZE) {
|
||||
MapPage(virtCursor + off, physBase + off, 0x03 /* P|W */);
|
||||
Map4K(virtCursor + off, physBase + off, 0x03 /* P|W */);
|
||||
}
|
||||
|
||||
// Fill BOOT_INFO
|
||||
@@ -642,6 +712,8 @@ EFI_STATUS EFIAPI UefiMain(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable
|
||||
|
||||
// Query GOP FIRST, before the GetMemoryMap loop
|
||||
EFI_GRAPHICS_OUTPUT_PROTOCOL* gop;
|
||||
UINT64 fbBase = 0;
|
||||
UINT64 fbBytes = 0;
|
||||
if (!EFI_ERROR(gBS->LocateProtocol(&gEfiGraphicsOutputProtocolGuid, NULL, (VOID **)&gop))) {
|
||||
bi->FramebufferBase = gop->Mode->FrameBufferBase;
|
||||
bi->FramebufferWidth = gop->Mode->Info->HorizontalResolution;
|
||||
@@ -651,15 +723,16 @@ EFI_STATUS EFIAPI UefiMain(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable
|
||||
// FrameBufferSize is a lie - EFI reports it as Width*Height*4.
|
||||
// The ACTUAL consumed bytes are Stride*Height*4.
|
||||
// Add one extra page as a safety margin.
|
||||
UINT64 fbBytes = (UINT64)gop->Mode->Info->PixelsPerScanLine
|
||||
fbBase = gop->Mode->FrameBufferBase;
|
||||
fbBytes = (UINT64)gop->Mode->Info->PixelsPerScanLine
|
||||
* (UINT64)gop->Mode->Info->VerticalResolution
|
||||
* 4 + PAGE_SIZE;
|
||||
fbBytes = (fbBytes + PAGE_SIZE - 1) & ~(UINT64)(PAGE_SIZE - 1);
|
||||
|
||||
for (UINT64 i = 0; i < fbBytes; i += PAGE_SIZE) {
|
||||
UINT64 phys = gop->Mode->FrameBufferBase + i;
|
||||
MapPage(PHYS_MAP_BASE + phys, phys, 0x13); // P|W|PCD (write-combined MMIO)
|
||||
MapPage(phys, phys, 0x13);
|
||||
Map4K(PHYS_MAP_BASE + phys, phys, 0x13); // P|W|PCD (write-combined MMIO)
|
||||
Map4K(phys, phys, 0x13);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -672,10 +745,43 @@ EFI_STATUS EFIAPI UefiMain(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable
|
||||
EFI_MEMORY_DESCRIPTOR* efiMap = AllocatePool(mapSize);
|
||||
gBS->GetMemoryMap(&mapSize, efiMap, &mapKey, &descSz, &descVer);
|
||||
{
|
||||
UINT64 idHoles[4];
|
||||
UINT64 winHoles[4];
|
||||
UINTN holeCount = 0;
|
||||
if (fbBytes) {
|
||||
idHoles[holeCount * 2 + 0] = fbBase;
|
||||
idHoles[holeCount * 2 + 1] = fbBase + fbBytes;
|
||||
winHoles[holeCount * 2 + 0] = PHYS_MAP_BASE + fbBase;
|
||||
winHoles[holeCount * 2 + 1] = PHYS_MAP_BASE + fbBase + fbBytes;
|
||||
holeCount++;
|
||||
}
|
||||
idHoles[holeCount * 2 + 0] = 0xFEC00000ULL;
|
||||
idHoles[holeCount * 2 + 1] = 0xFEE01000ULL;
|
||||
winHoles[holeCount * 2 + 0] = PHYS_MAP_BASE + 0xFEC00000ULL;
|
||||
winHoles[holeCount * 2 + 1] = PHYS_MAP_BASE + 0xFEE01000ULL;
|
||||
holeCount++;
|
||||
|
||||
if (holeCount == 2) {
|
||||
if (idHoles[2] < idHoles[0]) {
|
||||
UINT64 t0 = idHoles[0], t1 = idHoles[1];
|
||||
idHoles[0] = idHoles[2];
|
||||
idHoles[1] = idHoles[3];
|
||||
idHoles[2] = t0;
|
||||
idHoles[3] = t1;
|
||||
}
|
||||
if (winHoles[2] < winHoles[0]) {
|
||||
UINT64 t0 = winHoles[0], t1 = winHoles[1];
|
||||
winHoles[0] = winHoles[2];
|
||||
winHoles[1] = winHoles[3];
|
||||
winHoles[2] = t0;
|
||||
winHoles[3] = t1;
|
||||
}
|
||||
}
|
||||
|
||||
for (UINTN i = 0; i < mapSize / descSz; i++) {
|
||||
EFI_MEMORY_DESCRIPTOR* desc = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)efiMap + i * descSz);
|
||||
|
||||
// Map everything except unusable memory to the Physical Window
|
||||
// Map everything except unusable memory to the Physical Window.
|
||||
if (desc->Type != EfiUnusableMemory && desc->Type != EfiMemoryMappedIOPortSpace) {
|
||||
UINT64 start = desc->PhysicalStart;
|
||||
UINT64 end = start + (desc->NumberOfPages * PAGE_SIZE);
|
||||
@@ -685,10 +791,8 @@ EFI_STATUS EFIAPI UefiMain(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable
|
||||
// memory because of buggy UEFI size reporting.
|
||||
end += 2 * PAGE_SIZE;
|
||||
|
||||
for (UINT64 phys = start; phys < end; phys += PAGE_SIZE) {
|
||||
MapPage(phys, phys, 0x03); // Identity
|
||||
MapPage(PHYS_MAP_BASE + phys, phys, 0x03); // High-half
|
||||
}
|
||||
MapRangeSkipping(start, start, end - start, 0x03, idHoles, holeCount);
|
||||
MapRangeSkipping(PHYS_MAP_BASE + start, start, end - start, 0x03, winHoles, holeCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -703,8 +807,8 @@ EFI_STATUS EFIAPI UefiMain(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable
|
||||
for (UINT64 phys = 0xFEC00000; phys < 0xFEE01000; phys += PAGE_SIZE) {
|
||||
// In a production OS you'd use Cache-Disable flags (0x13 or 0x1B),
|
||||
// but 0x03 is fine for hobby OS initialization before PAT is set up.
|
||||
MapPage(phys, phys, 0x03); // Identity Map
|
||||
MapPage(PHYS_MAP_BASE + phys, phys, 0x03); // Physical Window Map
|
||||
Map4K(phys, phys, 0x03); // Identity Map
|
||||
Map4K(PHYS_MAP_BASE + phys, phys, 0x03); // Physical Window Map
|
||||
}
|
||||
|
||||
Print(L"8\n");
|
||||
|
||||
@@ -30,6 +30,37 @@ typedef KSTATUS (*DRIVER_ENTRY_FN)(const HAL_API *);
|
||||
// threading a parameter through every call chain.
|
||||
static const HAL_API* gKmainHal;
|
||||
|
||||
static int PageInBootloaderRegion(const BOOT_INFO* bootInfo, PHYSICAL_ADDRESS page) {
|
||||
for (uint32_t i = 0; i < bootInfo->MemoryMap.RegionCount; i++) {
|
||||
const MEMORY_REGION* r = &bootInfo->MemoryMap.Regions[i];
|
||||
if (r->Type != MemoryBootloader) continue;
|
||||
|
||||
uintptr_t start = r->Base & PAGE_MASK;
|
||||
uintptr_t end = (r->Base + r->Length + PAGE_SIZE - 1) & PAGE_MASK;
|
||||
if ((uintptr_t)page >= start && (uintptr_t)page < end) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ReclaimBootloaderMemory(const BOOT_INFO* bootInfo) {
|
||||
// Reclaim only the raw buffers backing boot-loaded .sys modules.
|
||||
// The kernel/HAL images, page tables, and bootloader code remain live.
|
||||
for (uint32_t i = 2; i < bootInfo->ModuleCount; i++) {
|
||||
const BOOT_MODULE* mod = &bootInfo->Modules[i];
|
||||
if (!mod->PhysBase || !mod->ImageSize) continue;
|
||||
|
||||
uintptr_t base = (uintptr_t)(mod->PhysBase & PAGE_MASK);
|
||||
uintptr_t end = (uintptr_t)((mod->PhysBase + mod->ImageSize + PAGE_SIZE - 1) & PAGE_MASK);
|
||||
|
||||
for (uintptr_t page = base; page < end; page += PAGE_SIZE) {
|
||||
if (!PageInBootloaderRegion(bootInfo, (PHYSICAL_ADDRESS)page)) continue;
|
||||
MmFreeFrame((PHYSICAL_ADDRESS)page);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Phase Helper: Resolve Imports for core modules
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -330,6 +361,7 @@ void SystemInitThread(void* arg) {
|
||||
InitializeDrivers(args->bootInfo, args->hal);
|
||||
|
||||
ResolveSystemImports(args->bootInfo);
|
||||
ReclaimBootloaderMemory(args->bootInfo);
|
||||
|
||||
args->hal->Screen.Clear(0x000000);
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ 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);
|
||||
}
|
||||
@@ -90,10 +91,7 @@ bool MmInitializePhysical(const MEMORY_MAP* map, uint64_t physicalWindowBase) {
|
||||
|
||||
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++;
|
||||
}
|
||||
PushFrame(frame);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -239,6 +239,37 @@ static void FreeListRemove(HEAP* h, BLOCK_HDR* blk) {
|
||||
blk->PrevFree = blk->NextFree = (BLOCK_HDR *)0;
|
||||
}
|
||||
|
||||
static void HeapTryDecommitTail(HEAP* h, BLOCK_HDR* blk) {
|
||||
if (!blk || blk->Free == 0) return;
|
||||
|
||||
while (h->Brk > h->Start) {
|
||||
uintptr_t blockEnd = (uintptr_t)blk + HDR_SIZE + blk->Size + FTR_SIZE;
|
||||
if (blockEnd != h->Brk) break;
|
||||
|
||||
// Keep at least one page for the block header/footer and a small payload.
|
||||
if (blk->Size < PAGE_SIZE + sizeof(void*)) break;
|
||||
|
||||
uintptr_t pageStart = h->Brk - PAGE_SIZE;
|
||||
if (pageStart <= (uintptr_t)blk) break; // would unmap the page containing the header
|
||||
|
||||
PHYSICAL_ADDRESS phys = MmGetPhysicalAddress(pageStart);
|
||||
if (!phys) break;
|
||||
if (!KSUCCESS(MmUnmapPage(pageStart))) {
|
||||
break;
|
||||
}
|
||||
MmFreeFrame(phys);
|
||||
|
||||
h->Brk -= PAGE_SIZE;
|
||||
blk->Size -= PAGE_SIZE;
|
||||
}
|
||||
|
||||
if (blk->Free) {
|
||||
HdrToFtr(blk)->Size = blk->Size;
|
||||
HdrToFtr(blk)->Magic = BLOCK_MAGIC;
|
||||
HdrToFtr(blk)->Free = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void* HeapAlloc(HEAP* h, size_t size) {
|
||||
if (!size) return (void *)0;
|
||||
size = (size + 7) & ~7ULL; // 8-byte align
|
||||
@@ -338,6 +369,8 @@ static void HeapFree(HEAP* h, void* ptr) {
|
||||
HdrToFtr(blk)->Free = 1;
|
||||
HdrToFtr(blk)->Magic = BLOCK_MAGIC;
|
||||
|
||||
HeapTryDecommitTail(h, blk);
|
||||
|
||||
KeReleaseSpinlock(&h->Lock, flags);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -106,7 +106,7 @@ int main(const char* cmdline) {
|
||||
BinkNextFrame(b);
|
||||
}
|
||||
|
||||
WriteConsoleA(h, "shell: goodbye\n", 15, 0, 0);
|
||||
WriteConsoleA(h, "video: goodbye\n", 15, 0, 0);
|
||||
|
||||
ExitProcess(0);
|
||||
}
|
||||
@@ -78,7 +78,6 @@ The Win32 personality supports programs that expect drive letters, familiar proc
|
||||
|
||||
- open the VS x64 build tools as administrator
|
||||
- change into this directory
|
||||
- run `mkimage.bat`
|
||||
- run `build.bat`
|
||||
- use one of `run.bat` (IDE), `rund.bat` (IDE, debug), `runa.bat` (AHCI), or `runad.bat` (AHCI, debug)
|
||||
|
||||
|
||||
Reference in new issue
Block a user