[FREELDR]

- Split wlmemory into portable and arch specific code
- Partly implement amd64 version, doesn't work correctly yet

svn path=/branches/ros-amd64-bringup/; revision=43598
This commit is contained in:
Timo Kreuzer 2009-10-19 11:29:10 +00:00
parent 9e1db2627d
commit 2a3e82aae5
4 changed files with 720 additions and 519 deletions

View file

@ -73,6 +73,7 @@
<file>conversion.c</file>
<file>peloader.c</file>
<file>winldr.c</file>
<file>wlmemory.c</file>
<file>wlregistry.c</file>
</directory>
</if>
@ -81,6 +82,7 @@
<file>conversion.c</file>
<file>peloader.c</file>
<file>winldr.c</file>
<file>wlmemory.c</file>
<file>wlregistry.c</file>
</directory>
</if>

View file

@ -1,9 +1,9 @@
/*
* PROJECT: EFI Windows Loader
* LICENSE: GPL - See COPYING in the top level directory
* FILE: freeldr/winldr/wlmemory.c
* FILE: freeldr/amd64/wlmemory.c
* PURPOSE: Memory related routines
* PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org)
* PROGRAMMERS: Timo Kreuzer (timo.kreuzer@reactos.org)
*/
/* INCLUDES ***************************************************************/
@ -13,8 +13,7 @@
#include <ndk/asm.h>
#include <debug.h>
extern ULONG TotalNLSSize;
extern ULONG LoaderPagesSpanned;
//extern ULONG LoaderPagesSpanned;
// This is needed because headers define wrong one for ReactOS
#undef KIP0PCRADDRESS
@ -22,52 +21,6 @@ extern ULONG LoaderPagesSpanned;
#define HYPER_SPACE_ENTRY 0x300
PCHAR 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
};
VOID
WinLdrpDumpMemoryDescriptors(PLOADER_PARAMETER_BLOCK LoaderBlock);
VOID
MempAddMemoryBlock(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
ULONG BasePage,
ULONG PageCount,
ULONG Type);
VOID
WinLdrInsertDescriptor(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
IN PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor);
VOID
WinLdrRemoveDescriptor(IN PMEMORY_ALLOCATION_DESCRIPTOR Descriptor);
VOID
WinLdrSetProcessorContext(PVOID GdtIdt, IN ULONG Pcr, IN ULONG Tss);
// This is needed only for SetProcessorContext routine
#pragma pack(2)
typedef struct
@ -79,91 +32,284 @@ WinLdrSetProcessorContext(PVOID GdtIdt, IN ULONG Pcr, IN ULONG Tss);
/* GLOBALS ***************************************************************/
PHARDWARE_PTE PDE;
PHARDWARE_PTE HalPageTable;
PUCHAR PhysicalPageTablesBuffer;
PUCHAR KernelPageTablesBuffer;
ULONG PhysicalPageTables;
ULONG KernelPageTables;
MEMORY_ALLOCATION_DESCRIPTOR *Mad;
ULONG MadCount = 0;
//PHARDWARE_PTE PDE;
//PHARDWARE_PTE HalPageTable;
PPAGE_DIRECTORY_AMD64 pPML4;
/* FUNCTIONS **************************************************************/
BOOLEAN
MempAllocatePageTables()
{
ULONG KernelPages;
PVOID UserSharedData;
DPRINTM(DPRINT_WINDOWS,">>> MempAllocatePageTables\n");
/* Allocate a page for the PML4 */
pPML4 = MmAllocateMemoryWithType(PAGE_SIZE, LoaderMemoryData);
if (!pPML4)
{
DPRINTM(DPRINT_WINDOWS,"failed to allocate PML4\n");
return FALSE;
}
// FIXME: Physical PTEs = FirmwareTemporary ?
/* Zero the PML4 */
RtlZeroMemory(pPML4, PAGE_SIZE);
/* The page tables are located at 0xfffff68000000000
* We create a recursive self mapping through all 4 levels at
* virtual address 0xfffff6fb7dbedf68 */
pPML4->Pde[VAtoPXI(PXE_BASE)].Valid = 1;
pPML4->Pde[VAtoPXI(PXE_BASE)].Write = 1;
pPML4->Pde[VAtoPXI(PXE_BASE)].PageFrameNumber = PtrToPfn(pPML4);
// FIXME: map PDE's for hals memory mapping
DPRINTM(DPRINT_WINDOWS,">>> leave MempAllocatePageTables\n");
return TRUE;
}
VOID
MempAllocatePTE(ULONG Entry, PHARDWARE_PTE *PhysicalPT, PHARDWARE_PTE *KernelPT)
PPAGE_DIRECTORY_AMD64
MempGetOrCreatePageDir(PPAGE_DIRECTORY_AMD64 pDir, ULONG Index)
{
PPAGE_DIRECTORY_AMD64 pSubDir;
if (!pDir)
return NULL;
if (!pDir->Pde[Index].Valid)
{
pSubDir = MmAllocateMemoryWithType(PAGE_SIZE, LoaderSpecialMemory);
if (!pSubDir)
return NULL;
RtlZeroMemory(pSubDir, PAGE_SIZE);
pDir->Pde[Index].PageFrameNumber = PtrToPfn(pSubDir);
pDir->Pde[Index].Valid = 1;
pDir->Pde[Index].Write = 1;
}
else
{
pSubDir = (PPAGE_DIRECTORY_AMD64)((ULONGLONG)(pDir->Pde[Index].PageFrameNumber) * PAGE_SIZE);
}
return pSubDir;
}
BOOLEAN
MempMapSinglePage(ULONGLONG VirtualAddress, ULONGLONG PhysicalAddress)
{
PPAGE_DIRECTORY_AMD64 pDir3, pDir2, pDir1;
ULONG Index;
pDir3 = MempGetOrCreatePageDir(pPML4, VAtoPXI(VirtualAddress));
pDir2 = MempGetOrCreatePageDir(pDir3, VAtoPPI(VirtualAddress));
pDir1 = MempGetOrCreatePageDir(pDir2, VAtoPDI(VirtualAddress));
if (!pDir1)
return FALSE;
Index = VAtoPTI(VirtualAddress);
if (pDir1->Pde[Index].Valid)
{
return FALSE;
}
pDir1->Pde[Index].Valid = 1;
pDir1->Pde[Index].Write = 1;
pDir1->Pde[Index].PageFrameNumber = PhysicalAddress / PAGE_SIZE;
return TRUE;
}
ULONG
MempMapRangeOfPages(ULONGLONG VirtualAddress, ULONGLONG PhysicalAddress, ULONG cPages)
{
ULONG i;
for (i = 0; i < cPages; i++)
{
if (!FrLdrMapSinglePage(VirtualAddress, PhysicalAddress))
{
return i;
}
VirtualAddress += PAGE_SIZE;
PhysicalAddress += PAGE_SIZE;
}
return i;
}
BOOLEAN
MempSetupPaging(IN ULONG StartPage,
IN ULONG NumberOfPages)
{
DPRINTM(DPRINT_WINDOWS,">>> MempSetupPaging(0x%lx, %ld)\n", StartPage, NumberOfPages);
if (MempMapRangeOfPages(StartPage * PAGE_SIZE,
StartPage * PAGE_SIZE,
NumberOfPages) != NumberOfPages)
{
DPRINTM(DPRINT_WINDOWS,"Failed to map pages\n");
return FALSE;
}
return TRUE;
}
VOID
MempDisablePages()
MempUnmapPage(ULONG Page)
{
// DPRINTM(DPRINT_WINDOWS,">>> MempUnmapPage\n");
}
VOID
MempAddMemoryBlock(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
ULONG BasePage,
ULONG PageCount,
ULONG Type)
{
}
#ifdef _M_IX86
VOID
WinLdrpMapApic()
{
BOOLEAN LocalAPIC;
LARGE_INTEGER MsrValue;
ULONG CpuInfo[4];
ULONG64 APICAddress;
DPRINTM(DPRINT_WINDOWS,">>> WinLdrpMapApic\n");
/* Check if we have a local APIC */
__cpuid((int*)CpuInfo, 1);
LocalAPIC = (((CpuInfo[3] >> 9) & 1) != 0);
/* If there is no APIC, just return */
if (!LocalAPIC)
{
DPRINTM(DPRINT_WINDOWS,"No APIC found.\n");
return;
}
/* Read the APIC Address */
MsrValue.QuadPart = __readmsr(0x1B);
APICAddress = (MsrValue.LowPart & 0xFFFFF000);
DPRINTM(DPRINT_WINDOWS, "Local APIC detected at address 0x%x\n",
APICAddress);
/* Map it */
MempMapSinglePage(APIC_BASE, APICAddress);
}
#else
VOID
WinLdrpMapApic()
{
/* Implement it for another arch */
}
#endif
BOOLEAN
WinLdrTurnOnPaging(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
ULONG PcrBasePage,
ULONG TssBasePage,
PVOID GdtIdt)
WinLdrMapSpecialPages(ULONG PcrBasePage)
{
return 1;
/* Map the PCR page */
if (!MempMapSinglePage(PcrBasePage * PAGE_SIZE, KIP0PCRADDRESS))
{
DPRINTM(DPRINT_WINDOWS, "Could not map PCR @ %lx\n", PcrBasePage);
return FALSE;
}
/* Map KI_USER_SHARED_DATA */
if (!MempMapSinglePage((PcrBasePage+1) * PAGE_SIZE, KI_USER_SHARED_DATA))
{
DPRINTM(DPRINT_WINDOWS, "Could not map KI_USER_SHARED_DATA\n");
return FALSE;
}
/* Map the APIC page */
WinLdrpMapApic();
return TRUE;
}
// Two special things this func does: it sorts descriptors,
// and it merges free ones
VOID
WinLdrInsertDescriptor(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
IN PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor)
WinLdrSetupGdt(PVOID GdtBase, ULONG64 TssBase)
{
PKGDTENTRY64 Entry;
KDESCRIPTOR GdtDesc;
/* Setup KGDT_64_R0_CODE */
Entry = KiGetGdtEntry(GdtBase, KGDT_64_R0_CODE);
*(PULONG64)Entry = 0x00209b0000000000ULL;
/* Setup KGDT_64_R0_SS */
Entry = KiGetGdtEntry(GdtBase, KGDT_64_R0_SS);
*(PULONG64)Entry = 0x00cf93000000ffffULL;
/* Setup KGDT_64_DATA */
Entry = KiGetGdtEntry(GdtBase, KGDT_64_DATA);
*(PULONG64)Entry = 0x00cff3000000ffffULL;
/* Setup KGDT_64_R3_CODE */
Entry = KiGetGdtEntry(GdtBase, KGDT_64_R3_CODE);
*(PULONG64)Entry = 0x0020fb0000000000ULL;
/* Setup KGDT_32_R3_TEB */
Entry = KiGetGdtEntry(GdtBase, KGDT_32_R3_TEB);
*(PULONG64)Entry = 0xff40f3fd50003c00ULL;
/* Setup TSS entry */
Entry = KiGetGdtEntry(GdtBase, KGDT_TSS);
KiInitGdtEntry(Entry, TssBase, sizeof(KTSS), I386_TSS, 0);
/* Setup GDT descriptor */
GdtDesc.Base = GdtBase;
GdtDesc.Limit = NUM_GDT * sizeof(KGDTENTRY) - 1;
/* Set the new Gdt */
__lgdt(&GdtDesc.Limit);
DbgPrint("Gdtr.Base = %p, num = %ld\n", GdtDesc.Base, NUM_GDT);
}
VOID
WinLdrSetProcessorContext(PVOID GdtIdt, IN ULONG Pcr, IN ULONG Tss)
WinLdrSetupIdt(PVOID IdtBase)
{
KDESCRIPTOR IdtDesc, OldIdt;
/* Get old IDT */
__sidt(&OldIdt);
/* Copy the old IDT */
RtlCopyMemory(IdtBase, (PVOID)OldIdt.Base, OldIdt.Limit + 1);
/* Setup the new IDT descriptor */
IdtDesc.Base = IdtBase;
IdtDesc.Limit = NUM_IDT * sizeof(KIDTENTRY) - 1;
/* Set the new IDT */
__lidt(&IdtDesc.Limit);
DbgPrint("Idtr.Base = %p\n", IdtDesc.Base);
}
VOID
WinLdrSetProcessorContext(PVOID GdtIdt, IN ULONG64 Pcr, IN ULONG64 Tss)
{
/* Disable Interrupts */
_disable();
/* Re-initalize EFLAGS */
__writeeflags(0);
/* Set the new PML4 */
__writecr3((ULONGLONG)pPML4);
// Enable paging by modifying CR0
__writecr0(__readcr0() | CR0_PG);
// Kernel expects the PCR to be zero-filled on startup
// FIXME: Why zero it here when we can zero it right after allocation?
RtlZeroMemory((PVOID)Pcr, MM_PAGE_SIZE); //FIXME: Why zero only 1 page when we allocate 2?
RtlZeroMemory(GdtIdt, PAGE_SIZE);
WinLdrSetupGdt(GdtIdt, Tss);
WinLdrSetupIdt(GdtIdt);
}
VOID
MempDump()
{
}

View file

@ -1,7 +1,7 @@
/*
* PROJECT: EFI Windows Loader
* LICENSE: GPL - See COPYING in the top level directory
* FILE: freeldr/winldr/wlmemory.c
* FILE: freeldr/winldr/i386/wlmemory.c
* PURPOSE: Memory related routines
* PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org)
*/
@ -22,52 +22,6 @@ extern ULONG LoaderPagesSpanned;
#define HYPER_SPACE_ENTRY 0x300
PCHAR 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
};
VOID
WinLdrpDumpMemoryDescriptors(PLOADER_PARAMETER_BLOCK LoaderBlock);
VOID
MempAddMemoryBlock(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
ULONG BasePage,
ULONG PageCount,
ULONG Type);
VOID
WinLdrInsertDescriptor(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
IN PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor);
VOID
WinLdrRemoveDescriptor(IN PMEMORY_ALLOCATION_DESCRIPTOR Descriptor);
VOID
WinLdrSetProcessorContext(PVOID GdtIdt, IN ULONG Pcr, IN ULONG Tss);
// This is needed only for SetProcessorContext routine
#pragma pack(2)
typedef struct
@ -87,10 +41,6 @@ PUCHAR KernelPageTablesBuffer;
ULONG PhysicalPageTables;
ULONG KernelPageTables;
MEMORY_ALLOCATION_DESCRIPTOR *Mad;
ULONG MadCount = 0;
/* FUNCTIONS **************************************************************/
BOOLEAN
@ -253,133 +203,24 @@ MempSetupPaging(IN ULONG StartPage,
}
VOID
MempDisablePages()
MempUnmapPage(ULONG Page)
{
ULONG i;
PHARDWARE_PTE KernelPT;
ULONG Entry = (Page >> 10) + (KSEG0_BASE >> 22);
//
// We need to delete kernel mapping from memory areas which are
// marked as Special or Permanent memory (thus non-accessible)
//
if (PDE[Entry].Valid)
{
KernelPT = (PHARDWARE_PTE)(PDE[Entry].PageFrameNumber << MM_PAGE_SHIFT);
for (i=0; i<MadCount; i++)
{
ULONG StartPage, EndPage, Page;
StartPage = Mad[i].BasePage;
EndPage = Mad[i].BasePage + Mad[i].PageCount;
if (Mad[i].MemoryType == LoaderFirmwarePermanent ||
Mad[i].MemoryType == LoaderSpecialMemory ||
Mad[i].MemoryType == LoaderFree ||
(Mad[i].MemoryType == LoaderFirmwareTemporary && EndPage <= LoaderPagesSpanned) ||
Mad[i].MemoryType == LoaderOsloaderStack ||
Mad[i].MemoryType == LoaderLoadedProgram)
{
//
// But, the first megabyte of memory always stays!
// And, to tell the truth, we don't care about what's higher
// than LoaderPagesSpanned
if (Mad[i].MemoryType == LoaderFirmwarePermanent ||
Mad[i].MemoryType == LoaderSpecialMemory)
{
if (StartPage < 0x100)
StartPage = 0x100;
if (EndPage > LoaderPagesSpanned)
EndPage = LoaderPagesSpanned;
}
for (Page = StartPage; Page < EndPage; Page++)
{
PHARDWARE_PTE KernelPT;
ULONG Entry = (Page >> 10) + (KSEG0_BASE >> 22);
if (PDE[Entry].Valid)
{
KernelPT = (PHARDWARE_PTE)(PDE[Entry].PageFrameNumber << MM_PAGE_SHIFT);
if (KernelPT)
{
KernelPT[Page & 0x3ff].PageFrameNumber = 0;
KernelPT[Page & 0x3ff].Valid = 0;
KernelPT[Page & 0x3ff].Write = 0;
}
}
}
}
}
if (KernelPT)
{
KernelPT[Page & 0x3ff].PageFrameNumber = 0;
KernelPT[Page & 0x3ff].Valid = 0;
KernelPT[Page & 0x3ff].Write = 0;
}
}
}
VOID
MempAddMemoryBlock(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
ULONG BasePage,
ULONG PageCount,
ULONG Type)
{
BOOLEAN Status;
//
// Check for some weird stuff at the top
//
if (BasePage + PageCount > 0xF0000)
{
//
// Just skip this, without even adding to MAD list
//
return;
}
//
// Set Base page, page count and type
//
Mad[MadCount].BasePage = BasePage;
Mad[MadCount].PageCount = PageCount;
Mad[MadCount].MemoryType = Type;
//
// Check if it's more than the allowed for OS loader
// if yes - don't map the pages, just add as FirmwareTemporary
//
if (BasePage + PageCount > LoaderPagesSpanned)
{
if (Mad[MadCount].MemoryType != LoaderSpecialMemory &&
Mad[MadCount].MemoryType != LoaderFirmwarePermanent &&
Mad[MadCount].MemoryType != LoaderFree)
{
DPRINTM(DPRINT_WINDOWS, "Setting page %x %x to Temporary from %d\n",
BasePage, PageCount, Mad[MadCount].MemoryType);
Mad[MadCount].MemoryType = LoaderFirmwareTemporary;
}
WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]);
MadCount++;
return;
}
//
// Add descriptor
//
WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]);
MadCount++;
//
// Map it (don't map low 1Mb because it was already contigiously
// mapped in WinLdrTurnOnPaging)
//
if (BasePage >= 0x100)
{
Status = MempSetupPaging(BasePage, PageCount);
if (!Status)
{
DPRINTM(DPRINT_WINDOWS, "Error during MempSetupPaging\n");
return;
}
}
}
#ifdef _M_IX86
VOID
WinLdrpMapApic()
{
@ -410,149 +251,10 @@ WinLdrpMapApic()
HalPageTable[(APIC_BASE - 0xFFC00000) >> MM_PAGE_SHIFT].WriteThrough = 1;
HalPageTable[(APIC_BASE - 0xFFC00000) >> MM_PAGE_SHIFT].CacheDisable = 1;
}
#else
VOID
WinLdrpMapApic()
{
/* Implement it for another arch */
}
#endif
BOOLEAN
WinLdrTurnOnPaging(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
ULONG PcrBasePage,
ULONG TssBasePage,
PVOID GdtIdt)
WinLdrMapSpecialPages(ULONG PcrBasePage)
{
ULONG i, PagesCount, MemoryMapSizeInPages;
ULONG LastPageIndex, LastPageType, MemoryMapStartPage;
PPAGE_LOOKUP_TABLE_ITEM MemoryMap;
ULONG NoEntries;
PKTSS Tss;
BOOLEAN Status;
//
// Creating a suitable memory map for the 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
//
// Before we start mapping pages, create a block of memory, which will contain
// PDE and PTEs
if (MempAllocatePageTables() == FALSE)
return FALSE;
// Allocate memory for memory allocation descriptors
Mad = MmHeapAlloc(sizeof(MEMORY_ALLOCATION_DESCRIPTOR) * 1024);
// 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);
DPRINTM(DPRINT_WINDOWS, "Got memory map with %d entries\n", NoEntries);
// Always contigiously map low 1Mb of memory
Status = MempSetupPaging(0, 0x100);
if (!Status)
{
DPRINTM(DPRINT_WINDOWS, "Error during MempSetupPaging of low 1Mb\n");
return FALSE;
}
// 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
DPRINTM(DPRINT_WINDOWS, "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;
}*/
//VideoDisplayString(L"Hello from VGA, going into the kernel\n");
DPRINTM(DPRINT_WINDOWS, "HalPageTable: 0x%X\n", HalPageTable);
@ -574,37 +276,21 @@ WinLdrTurnOnPaging(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
//VideoMemoryBase = MmMapIoSpace(0xb8000, 4000, MmNonCached);
//DPRINTM(DPRINT_WINDOWS, "VideoMemoryBase: 0x%X\n", VideoMemoryBase);
Tss = (PKTSS)(KSEG0_BASE | (TssBasePage << MM_PAGE_SHIFT));
return TRUE;
}
// Unmap what is not needed from kernel page table
MempDisablePages();
// Fill the memory descriptor list and
//PrepareMemoryDescriptorList();
DPRINTM(DPRINT_WINDOWS, "Memory Descriptor List prepared, printing PDE\n");
List_PaToVa(&LoaderBlock->MemoryDescriptorListHead);
#if DBG
{
ULONG *PDE_Addr=(ULONG *)PDE;//0xC0300000;
int j;
DPRINTM(DPRINT_WINDOWS, "\nPDE\n");
for (i=0; i<128; i++)
{
DPRINTM(DPRINT_WINDOWS, "0x%04X | ", i*8);
for (j=0; j<8; j++)
{
DPRINTM(DPRINT_WINDOWS, "0x%08X ", PDE_Addr[i*8+j]);
}
DPRINTM(DPRINT_WINDOWS, "\n");
}
}
#endif
VOID
WinLdrSetProcessorContext(PVOID GdtIdt, IN ULONG Pcr, IN ULONG Tss)
{
GDTIDT GdtDesc, IdtDesc, OldIdt;
PKGDTENTRY pGdt;
PKIDTENTRY pIdt;
ULONG Ldt = 0;
//ULONG i;
DPRINTM(DPRINT_WINDOWS, "GDtIdt %p, Pcr %p, Tss 0x%08X\n",
GdtIdt, Pcr, Tss);
// Enable paging
//BS->ExitBootServices(ImageHandle,MapKey);
@ -621,93 +307,6 @@ WinLdrTurnOnPaging(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
// Enable paging by modifying CR0
__writecr0(__readcr0() | CR0_PG);
// Set processor context
WinLdrSetProcessorContext(GdtIdt, KIP0PCRADDRESS, KSEG0_BASE | (TssBasePage << MM_PAGE_SHIFT));
// Zero KI_USER_SHARED_DATA page
memset((PVOID)KI_USER_SHARED_DATA, 0, MM_PAGE_SIZE);
return TRUE;
}
// Two special things this func does: it sorts descriptors,
// and it merges free ones
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;
DPRINTM(DPRINT_WINDOWS, "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;
}
VOID
WinLdrSetProcessorContext(PVOID GdtIdt, IN ULONG Pcr, IN ULONG Tss)
{
GDTIDT GdtDesc, IdtDesc, OldIdt;
PKGDTENTRY pGdt;
PKIDTENTRY pIdt;
ULONG Ldt = 0;
//ULONG i;
DPRINTM(DPRINT_WINDOWS, "GDtIdt %p, Pcr %p, Tss 0x%08X\n",
GdtIdt, Pcr, Tss);
// Kernel expects the PCR to be zero-filled on startup
// FIXME: Why zero it here when we can zero it right after allocation?
RtlZeroMemory((PVOID)Pcr, MM_PAGE_SIZE); //FIXME: Why zero only 1 page when we allocate 2?
@ -937,3 +536,25 @@ WinLdrSetProcessorContext(PVOID GdtIdt, IN ULONG Pcr, IN ULONG Tss)
ret
*/
}
VOID
MempDump()
{
ULONG *PDE_Addr=(ULONG *)PDE;//0xC0300000;
int j;
DPRINTM(DPRINT_WINDOWS, "\nPDE\n");
for (i=0; i<128; i++)
{
DPRINTM(DPRINT_WINDOWS, "0x%04X | ", i*8);
for (j=0; j<8; j++)
{
DPRINTM(DPRINT_WINDOWS, "0x%08X ", PDE_Addr[i*8+j]);
}
DPRINTM(DPRINT_WINDOWS, "\n");
}
}

View file

@ -0,0 +1,432 @@
/*
* PROJECT: EFI Windows Loader
* LICENSE: GPL - See COPYING in the top level directory
* FILE: freeldr/winldr/wlmemory.c
* PURPOSE: Memory related routines
* PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org)
*/
/* INCLUDES ***************************************************************/
#include <freeldr.h>
#include <ndk/asm.h>
#include <debug.h>
extern ULONG LoaderPagesSpanned;
// This is needed because headers define wrong one for ReactOS
#undef KIP0PCRADDRESS
#define KIP0PCRADDRESS 0xffdff000
PCHAR 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
};
VOID
WinLdrpDumpMemoryDescriptors(PLOADER_PARAMETER_BLOCK LoaderBlock);
VOID
MempAddMemoryBlock(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
ULONG BasePage,
ULONG PageCount,
ULONG Type);
VOID
WinLdrInsertDescriptor(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
IN PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor);
VOID
WinLdrRemoveDescriptor(IN PMEMORY_ALLOCATION_DESCRIPTOR Descriptor);
VOID
WinLdrSetProcessorContext(PVOID GdtIdt, IN ULONG Pcr, IN ULONG Tss);
BOOLEAN
MempAllocatePageTables();
BOOLEAN
MempSetupPaging(IN ULONG StartPage,
IN ULONG NumberOfPages);
BOOLEAN
WinLdrMapSpecialPages(ULONG PcrBasePage);
VOID
MempUnmapPage(ULONG Page);
VOID
MempDump();
/* GLOBALS ***************************************************************/
MEMORY_ALLOCATION_DESCRIPTOR *Mad;
ULONG MadCount = 0;
/* FUNCTIONS **************************************************************/
VOID
MempDisablePages()
{
ULONG i;
//
// We need to delete kernel mapping from memory areas which are
// marked as Special or Permanent memory (thus non-accessible)
//
for (i=0; i<MadCount; i++)
{
ULONG StartPage, EndPage, Page;
StartPage = Mad[i].BasePage;
EndPage = Mad[i].BasePage + Mad[i].PageCount;
if (Mad[i].MemoryType == LoaderFirmwarePermanent ||
Mad[i].MemoryType == LoaderSpecialMemory ||
Mad[i].MemoryType == LoaderFree ||
(Mad[i].MemoryType == LoaderFirmwareTemporary && EndPage <= LoaderPagesSpanned) ||
Mad[i].MemoryType == LoaderOsloaderStack ||
Mad[i].MemoryType == LoaderLoadedProgram)
{
//
// But, the first megabyte of memory always stays!
// And, to tell the truth, we don't care about what's higher
// than LoaderPagesSpanned
if (Mad[i].MemoryType == LoaderFirmwarePermanent ||
Mad[i].MemoryType == LoaderSpecialMemory)
{
if (StartPage < 0x100)
StartPage = 0x100;
if (EndPage > LoaderPagesSpanned)
EndPage = LoaderPagesSpanned;
}
for (Page = StartPage; Page < EndPage; Page++)
{
MempUnmapPage(Page);
}
}
}
}
VOID
MempAddMemoryBlock(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
ULONG BasePage,
ULONG PageCount,
ULONG Type)
{
BOOLEAN Status;
//
// Check for some weird stuff at the top
//
if (BasePage + PageCount > 0xF0000)
{
//
// Just skip this, without even adding to MAD list
//
return;
}
//
// Set Base page, page count and type
//
Mad[MadCount].BasePage = BasePage;
Mad[MadCount].PageCount = PageCount;
Mad[MadCount].MemoryType = Type;
//
// Check if it's more than the allowed for OS loader
// if yes - don't map the pages, just add as FirmwareTemporary
//
if (BasePage + PageCount > LoaderPagesSpanned)
{
if (Mad[MadCount].MemoryType != LoaderSpecialMemory &&
Mad[MadCount].MemoryType != LoaderFirmwarePermanent &&
Mad[MadCount].MemoryType != LoaderFree)
{
DPRINTM(DPRINT_WINDOWS, "Setting page %x %x to Temporary from %d\n",
BasePage, PageCount, Mad[MadCount].MemoryType);
Mad[MadCount].MemoryType = LoaderFirmwareTemporary;
}
WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]);
MadCount++;
return;
}
//
// Add descriptor
//
WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]);
MadCount++;
//
// Map it (don't map low 1Mb because it was already contigiously
// mapped in WinLdrTurnOnPaging)
//
if (BasePage >= 0x100)
{
Status = MempSetupPaging(BasePage, PageCount);
if (!Status)
{
DPRINTM(DPRINT_WINDOWS, "Error during MempSetupPaging\n");
return;
}
}
}
BOOLEAN
WinLdrTurnOnPaging(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
ULONG PcrBasePage,
ULONG TssBasePage,
PVOID GdtIdt)
{
ULONG i, PagesCount, MemoryMapSizeInPages;
ULONG LastPageIndex, LastPageType, MemoryMapStartPage;
PPAGE_LOOKUP_TABLE_ITEM MemoryMap;
ULONG NoEntries;
PKTSS Tss;
BOOLEAN Status;
//
// Creating a suitable memory map for the 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
//
// Before we start mapping pages, create a block of memory, which will contain
// PDE and PTEs
if (MempAllocatePageTables() == FALSE)
return FALSE;
// Allocate memory for memory allocation descriptors
Mad = MmHeapAlloc(sizeof(MEMORY_ALLOCATION_DESCRIPTOR) * 1024);
// 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);
DPRINTM(DPRINT_WINDOWS, "Got memory map with %d entries\n", NoEntries);
// Always contigiously map low 1Mb of memory
Status = MempSetupPaging(0, 0x100);
if (!Status)
{
DPRINTM(DPRINT_WINDOWS, "Error during MempSetupPaging of low 1Mb\n");
return FALSE;
}
// 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
DPRINTM(DPRINT_WINDOWS, "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;
}*/
/* Map stuff like PCR, KI_USER_SHARED_DATA and Apic */
WinLdrMapSpecialPages(PcrBasePage);
Tss = (PKTSS)(KSEG0_BASE | (TssBasePage << MM_PAGE_SHIFT));
// Unmap what is not needed from kernel page table
MempDisablePages();
// Fill the memory descriptor list and
//PrepareMemoryDescriptorList();
DPRINTM(DPRINT_WINDOWS, "Memory Descriptor List prepared, printing PDE\n");
List_PaToVa(&LoaderBlock->MemoryDescriptorListHead);
#if DBG
MempDump();
#endif
// Set processor context
WinLdrSetProcessorContext(GdtIdt, KIP0PCRADDRESS, KSEG0_BASE | (TssBasePage << MM_PAGE_SHIFT));
// Zero KI_USER_SHARED_DATA page
memset((PVOID)KI_USER_SHARED_DATA, 0, MM_PAGE_SIZE);
return TRUE;
}
// Two special things this func does: it sorts descriptors,
// and it merges free ones
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;
DPRINTM(DPRINT_WINDOWS, "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;
}