reactos/boot/freeldr/freeldr/ntldr/wlmemory.c
2019-01-06 18:42:01 +01:00

419 lines
13 KiB
C

/*
* PROJECT: EFI Windows Loader
* LICENSE: GPL - See COPYING in the top level directory
* FILE: boot/freeldr/freeldr/windows/wlmemory.c
* PURPOSE: Memory related routines
* PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org)
*/
/* INCLUDES ***************************************************************/
#include <freeldr.h>
#include "winldr.h"
#include <debug.h>
DBG_DEFAULT_CHANNEL(WINDOWS);
extern ULONG LoaderPagesSpanned;
static const PCSTR MemTypeDesc[] = {
"ExceptionBlock ", // ?
"SystemBlock ", // ?
"Free ",
"Bad ", // used
"LoadedProgram ", // == Free
"FirmwareTemporary ", // == Free
"FirmwarePermanent ", // == Bad
"OsloaderHeap ", // used
"OsloaderStack ", // == Free
"SystemCode ",
"HalCode ",
"BootDriver ", // not used
"ConsoleInDriver ", // ?
"ConsoleOutDriver ", // ?
"StartupDpcStack ", // ?
"StartupKernelStack", // ?
"StartupPanicStack ", // ?
"StartupPcrPage ", // ?
"StartupPdrPage ", // ?
"RegistryData ", // used
"MemoryData ", // not used
"NlsData ", // used
"SpecialMemory ", // == Bad
"BBTMemory " // == Bad
};
static VOID
WinLdrInsertDescriptor(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
IN PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor);
extern PFREELDR_MEMORY_DESCRIPTOR BiosMemoryMap;
extern ULONG BiosMemoryMapEntryCount;
extern PFN_NUMBER MmLowestPhysicalPage;
extern PFN_NUMBER MmHighestPhysicalPage;
/* GLOBALS ***************************************************************/
MEMORY_ALLOCATION_DESCRIPTOR *Mad;
ULONG MadCount = 0;
/* 200 MADs fit into 1 page, that should really be enough! */
#define MAX_MAD_COUNT 200
/* FUNCTIONS **************************************************************/
VOID
MempAddMemoryBlock(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
PFN_NUMBER BasePage,
PFN_NUMBER PageCount,
ULONG Type)
{
TRACE("MempAddMemoryBlock(BasePage=0x%lx, PageCount=0x%lx, Type=%ld)\n",
BasePage, PageCount, Type);
/* Check for memory block after 4GB - we don't support it yet
Note: Even last page before 4GB limit is not supported */
if (BasePage >= MM_MAX_PAGE)
{
/* Just skip this, without even adding to MAD list */
return;
}
/* Check if last page is after 4GB limit and shorten this block if needed */
if (BasePage + PageCount > MM_MAX_PAGE)
{
/* Shorten this block */
PageCount = MM_MAX_PAGE - BasePage;
}
/* Check if we have slots left */
if (MadCount >= MAX_MAD_COUNT)
{
ERR("Error: no MAD slots left!\n");
return;
}
/* Set Base page, page count and type */
Mad[MadCount].BasePage = BasePage;
Mad[MadCount].PageCount = PageCount;
Mad[MadCount].MemoryType = Type;
/* Add descriptor */
WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]);
MadCount++;
}
VOID
MempSetupPagingForRegion(
PFN_NUMBER BasePage,
PFN_NUMBER PageCount,
ULONG Type)
{
BOOLEAN Status = TRUE;
TRACE("MempSetupPagingForRegion(BasePage=0x%lx, PageCount=0x%lx, Type=%ld)\n",
BasePage, PageCount, Type);
/* Make sure we don't map too high */
if (BasePage + PageCount > LoaderPagesSpanned) return;
switch (Type)
{
/* Pages used by the loader */
case LoaderLoadedProgram:
case LoaderOsloaderStack:
case LoaderFirmwareTemporary:
/* Map these pages into user mode */
Status = MempSetupPaging(BasePage, PageCount, FALSE);
break;
/* Pages used by the kernel */
case LoaderExceptionBlock:
case LoaderSystemBlock:
case LoaderFirmwarePermanent:
case LoaderSystemCode:
case LoaderHalCode:
case LoaderBootDriver:
case LoaderConsoleInDriver:
case LoaderConsoleOutDriver:
case LoaderStartupDpcStack:
case LoaderStartupKernelStack:
case LoaderStartupPanicStack:
case LoaderStartupPcrPage:
case LoaderStartupPdrPage:
case LoaderRegistryData:
case LoaderMemoryData:
case LoaderNlsData:
case LoaderXIPRom:
case LoaderOsloaderHeap: // FIXME
/* Map these pages into kernel mode */
Status = MempSetupPaging(BasePage, PageCount, TRUE);
break;
/* Pages not in use */
case LoaderFree:
case LoaderBad:
break;
/* Invisible to kernel */
case LoaderSpecialMemory:
case LoaderHALCachedMemory:
case LoaderBBTMemory:
break;
// FIXME: not known (not used anyway)
case LoaderReserve:
case LoaderLargePageFiller:
case LoaderErrorLogMemory:
break;
}
if (!Status)
{
ERR("Error during MempSetupPaging\n");
}
}
#ifdef _M_ARM
#define PKTSS PVOID
#endif
BOOLEAN
WinLdrSetupMemoryLayout(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock)
{
PFN_NUMBER i, PagesCount, MemoryMapSizeInPages, NoEntries;
PFN_NUMBER LastPageIndex, MemoryMapStartPage;
PPAGE_LOOKUP_TABLE_ITEM MemoryMap;
ULONG LastPageType;
//PKTSS Tss;
//BOOLEAN Status;
/* Cleanup heap */
FrLdrHeapCleanupAll();
//
// Creating a suitable memory map for Windows can be tricky, so let's
// give a few advices:
// 1) One must not map the whole available memory pages to PDE!
// Map only what's needed - 16Mb, 24Mb, 32Mb max I think,
// thus occupying 4, 6 or 8 PDE entries for identical mapping,
// the same quantity for KSEG0_BASE mapping, one more entry for
// hyperspace and one more entry for HAL physical pages mapping.
// 2) Memory descriptors must map *the whole* physical memory
// showing any memory above 16/24/32 as FirmwareTemporary
//
// 3) Overall memory blocks count must not exceed 30 (?? why?)
//
//
// During MmInitMachineDependent, the kernel zeroes PDE at the following address
// 0xC0300000 - 0xC03007FC
//
// Then it finds the best place for non-paged pool:
// StartPde C0300F70, EndPde C0300FF8, NumberOfPages C13, NextPhysPage 3AD
//
// Allocate memory for memory allocation descriptors
Mad = MmAllocateMemoryWithType(sizeof(MEMORY_ALLOCATION_DESCRIPTOR) * MAX_MAD_COUNT,
LoaderMemoryData);
// Setup an entry for each descriptor
MemoryMap = MmGetMemoryMap(&NoEntries);
if (MemoryMap == NULL)
{
UiMessageBox("Can not retrieve the current memory map.");
return FALSE;
}
// Calculate parameters of the memory map
MemoryMapStartPage = (ULONG_PTR)MemoryMap >> MM_PAGE_SHIFT;
MemoryMapSizeInPages = (NoEntries * sizeof(PAGE_LOOKUP_TABLE_ITEM) + MM_PAGE_SIZE - 1) / MM_PAGE_SIZE;
TRACE("Got memory map with %d entries\n", NoEntries);
#if 0
// Always contiguously map low 1Mb of memory
Status = MempSetupPaging(0, 0x100, FALSE);
if (!Status)
{
ERR("Error during MempSetupPaging of low 1Mb\n");
return FALSE;
}
#endif
/* Before creating the map, we need to map pages to kernel mode */
LastPageIndex = 1;
LastPageType = MemoryMap[1].PageAllocated;
for (i = 2; i < NoEntries; i++)
{
if ((MemoryMap[i].PageAllocated != LastPageType) ||
(i == NoEntries - 1))
{
MempSetupPagingForRegion(LastPageIndex, i - LastPageIndex, LastPageType);
LastPageIndex = i;
LastPageType = MemoryMap[i].PageAllocated;
}
}
// Construct a good memory map from what we've got,
// but mark entries which the memory allocation bitmap takes
// as free entries (this is done in order to have the ability
// to place mem alloc bitmap outside lower 16Mb zone)
PagesCount = 1;
LastPageIndex = 0;
LastPageType = MemoryMap[0].PageAllocated;
for (i = 1; i < NoEntries; i++)
{
// Check if its memory map itself
if (i >= MemoryMapStartPage &&
i < (MemoryMapStartPage+MemoryMapSizeInPages))
{
// Exclude it if current page belongs to the memory map
MemoryMap[i].PageAllocated = LoaderFree;
}
// Process entry
if (MemoryMap[i].PageAllocated == LastPageType &&
(i != NoEntries-1) )
{
PagesCount++;
}
else
{
// Add the resulting region
MempAddMemoryBlock(LoaderBlock, LastPageIndex, PagesCount, LastPageType);
// Reset our counter vars
LastPageIndex = i;
LastPageType = MemoryMap[i].PageAllocated;
PagesCount = 1;
}
}
// TEMP, DEBUG!
// adding special reserved memory zones for vmware workstation
#if 0
{
Mad[MadCount].BasePage = 0xfec00;
Mad[MadCount].PageCount = 0x10;
Mad[MadCount].MemoryType = LoaderSpecialMemory;
WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]);
MadCount++;
Mad[MadCount].BasePage = 0xfee00;
Mad[MadCount].PageCount = 0x1;
Mad[MadCount].MemoryType = LoaderSpecialMemory;
WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]);
MadCount++;
Mad[MadCount].BasePage = 0xfffe0;
Mad[MadCount].PageCount = 0x20;
Mad[MadCount].MemoryType = LoaderSpecialMemory;
WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]);
MadCount++;
}
#endif
/* Now we need to add high descriptors from the bios memory map */
for (i = 0; i < BiosMemoryMapEntryCount; i++)
{
/* Check if its higher than the lookup table */
if (BiosMemoryMap->BasePage > MmHighestPhysicalPage)
{
/* Copy this descriptor */
MempAddMemoryBlock(LoaderBlock,
BiosMemoryMap->BasePage,
BiosMemoryMap->PageCount,
BiosMemoryMap->MemoryType);
}
}
TRACE("MadCount: %d\n", MadCount);
WinLdrpDumpMemoryDescriptors(LoaderBlock); //FIXME: Delete!
// Map our loader image, so we can continue running
/*Status = MempSetupPaging(OsLoaderBase >> MM_PAGE_SHIFT, OsLoaderSize >> MM_PAGE_SHIFT);
if (!Status)
{
UiMessageBox("Error during MempSetupPaging.");
return;
}*/
// Fill the memory descriptor list and
//PrepareMemoryDescriptorList();
TRACE("Memory Descriptor List prepared, printing PDE\n");
List_PaToVa(&LoaderBlock->MemoryDescriptorListHead);
#if DBG
MempDump();
#endif
return TRUE;
}
// Two special things this func does: it sorts descriptors,
// and it merges free ones
static VOID
WinLdrInsertDescriptor(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
IN PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor)
{
PLIST_ENTRY ListHead = &LoaderBlock->MemoryDescriptorListHead;
PLIST_ENTRY PreviousEntry, NextEntry;
PMEMORY_ALLOCATION_DESCRIPTOR PreviousDescriptor = NULL, NextDescriptor = NULL;
TRACE("BP=0x%X PC=0x%X %s\n", NewDescriptor->BasePage,
NewDescriptor->PageCount, MemTypeDesc[NewDescriptor->MemoryType]);
/* Find a place where to insert the new descriptor to */
PreviousEntry = ListHead;
NextEntry = ListHead->Flink;
while (NextEntry != ListHead)
{
NextDescriptor = CONTAINING_RECORD(NextEntry,
MEMORY_ALLOCATION_DESCRIPTOR,
ListEntry);
if (NewDescriptor->BasePage < NextDescriptor->BasePage)
break;
PreviousEntry = NextEntry;
PreviousDescriptor = NextDescriptor;
NextEntry = NextEntry->Flink;
}
/* Don't forget about merging free areas */
if (NewDescriptor->MemoryType != LoaderFree)
{
/* Just insert, nothing to merge */
InsertHeadList(PreviousEntry, &NewDescriptor->ListEntry);
}
else
{
/* Previous block also free? */
if ((PreviousEntry != ListHead) && (PreviousDescriptor->MemoryType == LoaderFree) &&
((PreviousDescriptor->BasePage + PreviousDescriptor->PageCount) ==
NewDescriptor->BasePage))
{
/* Just enlarge previous descriptor's PageCount */
PreviousDescriptor->PageCount += NewDescriptor->PageCount;
NewDescriptor = PreviousDescriptor;
}
else
{
/* Nope, just insert */
InsertHeadList(PreviousEntry, &NewDescriptor->ListEntry);
}
/* Next block is free ?*/
if ((NextEntry != ListHead) &&
(NextDescriptor->MemoryType == LoaderFree) &&
((NewDescriptor->BasePage + NewDescriptor->PageCount) == NextDescriptor->BasePage))
{
/* Enlarge next descriptor's PageCount */
NewDescriptor->PageCount += NextDescriptor->PageCount;
RemoveEntryList(&NextDescriptor->ListEntry);
}
}
return;
}