diff --git a/reactos/boot/freeldr/freeldr/freeldr_base.rbuild b/reactos/boot/freeldr/freeldr/freeldr_base.rbuild index 42a13495c76..19842ed4ef6 100644 --- a/reactos/boot/freeldr/freeldr/freeldr_base.rbuild +++ b/reactos/boot/freeldr/freeldr/freeldr_base.rbuild @@ -73,6 +73,7 @@ conversion.c peloader.c winldr.c + wlmemory.c wlregistry.c @@ -81,6 +82,7 @@ conversion.c peloader.c winldr.c + wlmemory.c wlregistry.c diff --git a/reactos/boot/freeldr/freeldr/windows/amd64/wlmemory.c b/reactos/boot/freeldr/freeldr/windows/amd64/wlmemory.c index bd111ef09bf..ef6a18dfdfb 100644 --- a/reactos/boot/freeldr/freeldr/windows/amd64/wlmemory.c +++ b/reactos/boot/freeldr/freeldr/windows/amd64/wlmemory.c @@ -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 #include -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() +{ +} + diff --git a/reactos/boot/freeldr/freeldr/windows/i386/wlmemory.c b/reactos/boot/freeldr/freeldr/windows/i386/wlmemory.c index 313413e5451..6eb8b34224f 100644 --- a/reactos/boot/freeldr/freeldr/windows/i386/wlmemory.c +++ b/reactos/boot/freeldr/freeldr/windows/i386/wlmemory.c @@ -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 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= 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"); + } +} + diff --git a/reactos/boot/freeldr/freeldr/windows/wlmemory.c b/reactos/boot/freeldr/freeldr/windows/wlmemory.c new file mode 100644 index 00000000000..2ed849ad545 --- /dev/null +++ b/reactos/boot/freeldr/freeldr/windows/wlmemory.c @@ -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 + +#include +#include + +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 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= 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; +} +