- Add most needed memory-manipulating functions. Some places are really crappy (like...
authorAleksey Bragin <aleksey@reactos.org>
Wed, 4 Oct 2006 21:58:36 +0000 (21:58 +0000)
committerAleksey Bragin <aleksey@reactos.org>
Wed, 4 Oct 2006 21:58:36 +0000 (21:58 +0000)
- FIXME: Since FreeLdr doesn't really keep track of which memory is of which type, this code has a massive hack for guessing the memory type, which is incorrect for future usage

svn path=/trunk/; revision=24405

reactos/boot/freeldr/freeldr/windows/wlmemory.c

index a9393a6..1a81473 100644 (file)
 #undef KIP0PCRADDRESS\r
 #define KIP0PCRADDRESS                      0xffdff000\r
 \r
+//\r
+// This is the zone which is used by the OS loader\r
+//\r
+#define LOADER_HIGH_ZONE ((16*1024*1024) >> MM_PAGE_SHIFT) //16Mb page\r
+\r
 #define HYPER_SPACE_ENTRY       0x300\r
 \r
+//TODO: Check if this is correct\r
+PCHAR  MemTypeDesc[]  = {\r
+    "ExceptionBlock    ",\r
+    "SystemBlock       ",\r
+    "Free              ",\r
+    "Bad               ",\r
+    "LoadedProgram     ",\r
+    "FirmwareTemporary ",\r
+    "FirmwarePermanent ",\r
+    "OsloaderHeap      ",\r
+    "OsloaderStack     ",\r
+    "SystemCode        ",\r
+    "HalCode           ",\r
+    "BootDriver        ",\r
+    "ConsoleInDriver   ",\r
+    "ConsoleOutDriver  ",\r
+    "StartupDpcStack   ",\r
+    "StartupKernelStack",\r
+    "StartupPanicStack ",\r
+    "StartupPcrPage    ",\r
+    "StartupPdrPage    ",\r
+    "RegistryData      ",\r
+    "MemoryData        ",\r
+    "NlsData           ",\r
+    "SpecialMemory     ",\r
+    "BBTMemory         ",\r
+    "Maximum           "\r
+    };\r
+\r
+VOID\r
+WinLdrpDumpMemoryDescriptors(PLOADER_PARAMETER_BLOCK LoaderBlock);\r
+\r
+\r
+VOID\r
+MempAddMemoryBlock(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,\r
+                   UINT64 BasePage,\r
+                   UINT64 PageCount,\r
+                   ULONG Type);\r
+VOID\r
+WinLdrInsertDescriptor(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,\r
+                       IN PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor);\r
+\r
+VOID\r
+WinLdrRemoveDescriptor(IN PMEMORY_ALLOCATION_DESCRIPTOR Descriptor);\r
+\r
+VOID\r
+WinLdrSetProcessorContext(PVOID GdtIdt, IN ULONG Pcr, IN ULONG Tss);\r
+\r
+// This is needed only for SetProcessorContext routine\r
+#pragma pack(2)\r
+       typedef struct\r
+       {\r
+               USHORT Limit;\r
+               ULONG Base;\r
+       } GDTIDT;\r
+#pragma pack(4)\r
+\r
+// this is needed for new IDT filling\r
+#if 0\r
+extern ULONG_PTR i386DivideByZero;\r
+extern ULONG_PTR i386DebugException;\r
+extern ULONG_PTR i386NMIException;\r
+extern ULONG_PTR i386Breakpoint;\r
+extern ULONG_PTR i386Overflow;\r
+extern ULONG_PTR i386BoundException;\r
+extern ULONG_PTR i386InvalidOpcode;\r
+extern ULONG_PTR i386FPUNotAvailable;\r
+extern ULONG_PTR i386DoubleFault;\r
+extern ULONG_PTR i386CoprocessorSegment;\r
+extern ULONG_PTR i386InvalidTSS;\r
+extern ULONG_PTR i386SegmentNotPresent;\r
+extern ULONG_PTR i386StackException;\r
+extern ULONG_PTR i386GeneralProtectionFault;\r
+extern ULONG_PTR i386PageFault; // exc 14\r
+extern ULONG_PTR i386CoprocessorError; // exc 16\r
+extern ULONG_PTR i386AlignmentCheck; // exc 17\r
+#endif\r
+\r
 /* GLOBALS ***************************************************************/\r
 \r
+PHARDWARE_PTE PDE;\r
+PHARDWARE_PTE HalPT;\r
+\r
+PUCHAR PhysicalPageTablesBuffer;\r
+PUCHAR KernelPageTablesBuffer;\r
+ULONG PhysicalPageTables;\r
+ULONG KernelPageTables;\r
+\r
+MEMORY_ALLOCATION_DESCRIPTOR Mad[1024];\r
+ULONG MadCount = 0;\r
+\r
+\r
 /* FUNCTIONS **************************************************************/\r
 \r
+BOOLEAN\r
+MempAllocatePageTables()\r
+{\r
+       ULONG NumPageTables, TotalSize;\r
+       PUCHAR Buffer;\r
+       // It's better to allocate PDE + PTEs contigiuos\r
+\r
+       // Max number of entries = MaxPageNum >> 10\r
+       // FIXME: This is a number to describe ALL physical memory\r
+       // and windows doesn't expect ALL memory mapped...\r
+       NumPageTables = (GetSystemMemorySize() >> MM_PAGE_SHIFT) >> 10;\r
+\r
+       DbgPrint((DPRINT_WINDOWS, "NumPageTables = %d\n", NumPageTables));\r
+\r
+       // Allocate memory block for all these things:\r
+       // PDE, HAL mapping page table, physical mapping, kernel mapping\r
+       TotalSize = (1+1+NumPageTables*2)*MM_PAGE_SIZE;\r
+       Buffer = MmAllocateMemory(TotalSize);\r
+\r
+       if (Buffer == NULL)\r
+       {\r
+               UiMessageBox("Impossible to allocate memory block for page tables!");\r
+               return FALSE;\r
+       }\r
+\r
+       // Zero all this memory block\r
+       RtlZeroMemory(Buffer, TotalSize);\r
+\r
+       // Set up pointers correctly now\r
+       PDE = (PHARDWARE_PTE)Buffer;\r
+\r
+       // Map the page directory at 0xC0000000 (maps itself)\r
+       PDE[HYPER_SPACE_ENTRY].PageFrameNumber = (ULONG)PDE >> MM_PAGE_SHIFT;\r
+       PDE[HYPER_SPACE_ENTRY].Valid = 1;\r
+       PDE[HYPER_SPACE_ENTRY].Write = 1;\r
+\r
+       // The last PDE slot is allocated for HAL's memory mapping (Virtual Addresses 0xFFC00000 - 0xFFFFFFFF)\r
+       HalPT = (PHARDWARE_PTE)&Buffer[MM_PAGE_SIZE*1];\r
+\r
+       // Map it\r
+       PDE[1023].PageFrameNumber = (ULONG)HalPT >> MM_PAGE_SHIFT;\r
+       PDE[1023].Valid = 1;\r
+       PDE[1023].Write = 1;\r
+\r
+       // Store pointers to the tables for easier access\r
+       PhysicalPageTablesBuffer = &Buffer[MM_PAGE_SIZE*2];\r
+       KernelPageTablesBuffer = PhysicalPageTablesBuffer + NumPageTables*MM_PAGE_SIZE;\r
+\r
+       // Zero counters of page tables used\r
+       PhysicalPageTables = 0;\r
+       KernelPageTables = 0;\r
+\r
+       return TRUE;\r
+}\r
+\r
+VOID\r
+MempAllocatePTE(ULONG Entry, PHARDWARE_PTE *PhysicalPT, PHARDWARE_PTE *KernelPT)\r
+{\r
+       //Print(L"Creating PDE Entry %X\n", Entry);\r
+\r
+       // Identity mapping\r
+       *PhysicalPT = (PHARDWARE_PTE)&PhysicalPageTablesBuffer[PhysicalPageTables*MM_PAGE_SIZE];\r
+       PhysicalPageTables++;\r
+\r
+       PDE[Entry].PageFrameNumber = (ULONG)*PhysicalPT >> MM_PAGE_SHIFT;\r
+       PDE[Entry].Valid = 1;\r
+       PDE[Entry].Write = 1;\r
+\r
+       if (Entry+(KSEG0_BASE >> 22) > 1023)\r
+       {\r
+               DbgPrint((DPRINT_WINDOWS, "WARNING! Entry: %X > 1023\n", Entry+(KSEG0_BASE >> 22)));\r
+       }\r
+\r
+       // Kernel-mode mapping\r
+       *KernelPT = (PHARDWARE_PTE)&KernelPageTablesBuffer[KernelPageTables*MM_PAGE_SIZE];\r
+       KernelPageTables++;\r
+\r
+       PDE[Entry+(KSEG0_BASE >> 22)].PageFrameNumber = ((ULONG)*KernelPT >> MM_PAGE_SHIFT);\r
+       PDE[Entry+(KSEG0_BASE >> 22)].Valid = 1;\r
+       PDE[Entry+(KSEG0_BASE >> 22)].Write = 1;\r
+}\r
+\r
+BOOLEAN\r
+MempSetupPaging(IN ULONG StartPage,\r
+                               IN ULONG NumberOfPages)\r
+{\r
+       PHARDWARE_PTE PhysicalPT;\r
+       PHARDWARE_PTE KernelPT;\r
+       ULONG Entry, Page;\r
+\r
+       //Print(L"MempSetupPaging: SP 0x%X, Number: 0x%X\n", StartPage, NumberOfPages);\r
+       \r
+       // HACK\r
+       if (StartPage+NumberOfPages >= 0x80000)\r
+       {\r
+               //\r
+               // We can't map this as it requires more than 1 PDE\r
+               // and in fact it's not possible at all ;)\r
+               //\r
+               //Print(L"skipping...\n");\r
+               return TRUE;\r
+       }\r
+\r
+       //\r
+       // Now actually set up the page tables for identity mapping\r
+       //\r
+       for (Page=StartPage; Page < StartPage+NumberOfPages; Page++)\r
+       {\r
+               Entry = Page >> 10;\r
+\r
+               if (((PULONG)PDE)[Entry] == 0)\r
+               {\r
+                       MempAllocatePTE(Entry, &PhysicalPT, &KernelPT);\r
+               }\r
+               else\r
+               {\r
+                       PhysicalPT = (PHARDWARE_PTE)(PDE[Entry].PageFrameNumber << MM_PAGE_SHIFT);\r
+                       KernelPT = (PHARDWARE_PTE)(PDE[Entry+(KSEG0_BASE >> 22)].PageFrameNumber << MM_PAGE_SHIFT);\r
+               }\r
+\r
+               if (Page == 0)\r
+               {\r
+                       PhysicalPT[Page & 0x3ff].PageFrameNumber = Page;\r
+                       PhysicalPT[Page & 0x3ff].Valid = 0;\r
+                       PhysicalPT[Page & 0x3ff].Write = 0;\r
+\r
+                       KernelPT[Page & 0x3ff].PageFrameNumber = Page;\r
+                       KernelPT[Page & 0x3ff].Valid = 0;\r
+                       KernelPT[Page & 0x3ff].Write = 0;\r
+               }\r
+               else\r
+               {\r
+                       PhysicalPT[Page & 0x3ff].PageFrameNumber = Page;\r
+                       PhysicalPT[Page & 0x3ff].Valid = 1;\r
+                       PhysicalPT[Page & 0x3ff].Write = 1;\r
+\r
+                       KernelPT[Page & 0x3ff].PageFrameNumber = Page;\r
+                       KernelPT[Page & 0x3ff].Valid = 1;\r
+                       KernelPT[Page & 0x3ff].Write = 1;\r
+               }\r
+       }\r
+\r
+       return TRUE;\r
+}\r
+\r
+VOID\r
+MempAddMemoryBlock(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,\r
+                   UINT64 BasePage,\r
+                   UINT64 PageCount,\r
+                   ULONG Type)\r
+{\r
+       BOOLEAN Status;\r
+\r
+       //\r
+       // Check for some weird stuff at the top\r
+       //\r
+       if (BasePage + PageCount > 0xF0000)\r
+       {\r
+               //\r
+               // Just skip this, without even adding to MAD list\r
+               //\r
+               return;\r
+       }\r
+\r
+       //\r
+       // Base page and page count are always set\r
+       //\r
+       Mad[MadCount].BasePage = BasePage;\r
+       Mad[MadCount].PageCount = PageCount;\r
+\r
+       //\r
+       // Check if it's more than the allowed for OS loader\r
+       // if yes - don't map the pages, just add as FirmwareTemporary\r
+       //\r
+       if (BasePage + PageCount > LOADER_HIGH_ZONE)\r
+       {\r
+               Mad[MadCount].MemoryType = LoaderFirmwareTemporary;\r
+\r
+               WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]);\r
+               MadCount++;\r
+\r
+               Status = MempSetupPaging(BasePage, PageCount);\r
+               if (!Status)\r
+               {\r
+                       DbgPrint((DPRINT_WINDOWS, "Error during WinLdrpSetupPaging\n"));\r
+                       return;\r
+               }\r
+               return;\r
+       }\r
+       \r
+       if (BasePage == 0xFFF && PageCount == 1)\r
+       {\r
+               Mad[MadCount].MemoryType = LoaderSpecialMemory;\r
+\r
+               WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]);\r
+               MadCount++;\r
+\r
+               //\r
+               // Map it\r
+               //\r
+               Status = MempSetupPaging(BasePage, PageCount);\r
+               if (!Status)\r
+               {\r
+                       DbgPrint((DPRINT_WINDOWS, "Error during MempSetupPaging\n"));\r
+                       return;\r
+               }\r
+       }\r
+       else if (BasePage == 0 && PageCount == 1)\r
+       {\r
+               Mad[MadCount].MemoryType = LoaderFirmwarePermanent;\r
+\r
+               WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]);\r
+               MadCount++;\r
+\r
+               //\r
+               // Map it\r
+               //\r
+               Status = MempSetupPaging(BasePage, PageCount);\r
+               if (!Status)\r
+               {\r
+                       DbgPrint((DPRINT_WINDOWS, "Error during MempSetupPaging\n"));\r
+                       return;\r
+               }\r
+       }\r
+       else\r
+       {\r
+               //\r
+               // Now choose memory type as usual. FIXME!!!\r
+               //\r
+               if (Type == 0)\r
+               {\r
+                       Mad[MadCount].MemoryType = LoaderFree;\r
+               }\r
+               else if (Type != 0 && Type != 1)\r
+               {\r
+                       Mad[MadCount].MemoryType = LoaderFirmwarePermanent;\r
+               }\r
+               else if (Type == 1)\r
+               {\r
+                       Mad[MadCount].MemoryType = LoaderSystemCode;\r
+               }\r
+               else\r
+               {\r
+                       Mad[MadCount].MemoryType = LoaderFirmwarePermanent;\r
+               }\r
+\r
+               //\r
+               // Add descriptor\r
+               //\r
+               WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]);\r
+               MadCount++;\r
+\r
+               //\r
+               // Map it\r
+               //\r
+               Status = MempSetupPaging(BasePage, PageCount);\r
+               if (!Status)\r
+               {\r
+                       DbgPrint((DPRINT_WINDOWS, "Error during MempSetupPaging\n"));\r
+                       return;\r
+               }\r
+       }\r
+}\r
+\r
 BOOLEAN\r
 WinLdrTurnOnPaging(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,\r
                    ULONG PcrBasePage,\r
                    ULONG TssBasePage,\r
                    PVOID GdtIdt)\r
 {\r
-       return FALSE;\r
+       ULONG i, PagesCount;\r
+       ULONG LastPageIndex, LastPageType;\r
+       PPAGE_LOOKUP_TABLE_ITEM MemoryMap;\r
+       ULONG NoEntries;\r
+       PKTSS Tss;\r
+\r
+       //\r
+       // Creating a suitable memory map for the Windows can be tricky, so let's\r
+       // give a few advices:\r
+       // 1) One must not map the whole available memory pages to PDE!\r
+       //    Map only what's needed - 16Mb, 24Mb, 32Mb max I think,\r
+       //    thus occupying 4, 6 or 8 PDE entries for identical mapping,\r
+       //    the same quantity for KSEG0_BASE mapping, one more entry for\r
+       //    hyperspace and one more entry for HAL physical pages mapping.\r
+       // 2) Memory descriptors must map *the whole* physical memory\r
+       //    showing any memory above 16/24/32 as FirmwareTemporary\r
+       //\r
+       // 3) Overall memory blocks count must not exceed 30\r
+       //\r
+\r
+       //\r
+       // During MmInitMachineDependent, the kernel zeroes PDE at the following address\r
+       // 0xC0300000 - 0xC03007FC\r
+       //\r
+       // Then it finds the best place for non-paged pool:\r
+       // StartPde C0300F70, EndPde C0300FF8, NumberOfPages C13, NextPhysPage 3AD\r
+       //\r
+\r
+       // Before we start mapping pages, create a block of memory, which will contain\r
+       // PDE and PTEs\r
+       if (MempAllocatePageTables() == FALSE)\r
+               return FALSE;\r
+\r
+       // Setup an entry for each descriptor\r
+       MemoryMap = MmGetMemoryMap(&NoEntries);\r
+       if (MemoryMap == NULL)\r
+       {\r
+               UiMessageBox("Can not retrieve the current memory map");\r
+               return FALSE;\r
+       }\r
+\r
+       DbgPrint((DPRINT_WINDOWS, "Got memory map with %d entries\n"));\r
+\r
+       // Construct a good memory map from what we've got\r
+       PagesCount = 1;\r
+       LastPageIndex = 0;\r
+       LastPageType = MemoryMap[0].PageAllocated;\r
+       for(i=1;i<NoEntries;i++)\r
+       {\r
+               if (MemoryMap[i].PageAllocated == LastPageType)\r
+               {\r
+                       PagesCount++;\r
+               }\r
+               else\r
+               {\r
+                       // Add the region\r
+                       MempAddMemoryBlock(LoaderBlock, LastPageIndex, PagesCount, LastPageType);\r
+\r
+                       // Reset our counter vars\r
+                       LastPageIndex = i;\r
+                       LastPageType = MemoryMap[i].PageAllocated;\r
+                       PagesCount = 1;\r
+               }\r
+       }\r
+\r
+       DbgPrint((DPRINT_WINDOWS, "MadCount: %d\n", MadCount));\r
+\r
+       WinLdrpDumpMemoryDescriptors(LoaderBlock); //FIXME: Delete!\r
+\r
+       // Map our loader image, so we can continue running\r
+       /*Status = MempSetupPaging(OsLoaderBase >> MM_PAGE_SHIFT, OsLoaderSize >> MM_PAGE_SHIFT);\r
+       if (!Status)\r
+       {\r
+               UiMessageBox("Error during MempSetupPaging");\r
+               return;\r
+       }*/\r
+\r
+       //VideoDisplayString(L"Hello from VGA, going into the kernel\n");\r
+       DbgPrint((DPRINT_WINDOWS, "HalPT: 0x%X\n", HalPT));\r
+\r
+       // Page Tables have been setup, make special handling for PCR and TSS\r
+       // (which is done in BlSetupFotNt in usual ntldr)\r
+       HalPT[(KI_USER_SHARED_DATA - 0xFFC00000) >> MM_PAGE_SHIFT].PageFrameNumber = PcrBasePage+1;\r
+       HalPT[(KI_USER_SHARED_DATA - 0xFFC00000) >> MM_PAGE_SHIFT].Valid = 1;\r
+       HalPT[(KI_USER_SHARED_DATA - 0xFFC00000) >> MM_PAGE_SHIFT].Write = 1;\r
+\r
+       HalPT[(KIP0PCRADDRESS - 0xFFC00000) >> MM_PAGE_SHIFT].PageFrameNumber = PcrBasePage;\r
+       HalPT[(KIP0PCRADDRESS - 0xFFC00000) >> MM_PAGE_SHIFT].Valid = 1;\r
+       HalPT[(KIP0PCRADDRESS - 0xFFC00000) >> MM_PAGE_SHIFT].Write = 1;\r
+\r
+       // Map VGA memory\r
+       //VideoMemoryBase = MmMapIoSpace(0xb8000, 4000, MmNonCached);\r
+       //DbgPrint((DPRINT_WINDOWS, "VideoMemoryBase: 0x%X\n", VideoMemoryBase));\r
+\r
+       Tss = (PKTSS)(KSEG0_BASE | (TssBasePage << MM_PAGE_SHIFT));\r
+\r
+       // Fill the memory descriptor list and \r
+       //PrepareMemoryDescriptorList();\r
+       DbgPrint((DPRINT_WINDOWS, "Memory Descriptor List prepared, printing PDE\n"));\r
+       List_PaToVa(&LoaderBlock->MemoryDescriptorListHead);\r
+\r
+       {\r
+               ULONG *PDE_Addr=(ULONG *)PDE;//0xC0300000;\r
+               int j;\r
+\r
+               DbgPrint((DPRINT_WINDOWS, "\nPDE\n"));\r
+\r
+               for (i=0; i<128; i++)\r
+               {\r
+                       DbgPrint((DPRINT_WINDOWS, "0x%04X | ", i*8));\r
+\r
+                       for (j=0; j<8; j++)\r
+                       {\r
+                               DbgPrint((DPRINT_WINDOWS, "0x%08X ", PDE_Addr[i*8+j]));\r
+                       }\r
+\r
+                       DbgPrint((DPRINT_WINDOWS, "\n"));\r
+               }\r
+       }\r
+\r
+\r
+       // Enable paging\r
+       //BS->ExitBootServices(ImageHandle,MapKey);\r
+\r
+       // Disable Interrupts\r
+       Ke386DisableInterrupts();\r
+\r
+       // Re-initalize EFLAGS\r
+       Ke386EraseFlags();\r
+\r
+       // Set the PDBR\r
+       Ke386SetPageTableDirectory((ULONG_PTR)PDE);\r
+\r
+       // Enable paging by modifying CR0\r
+       Ke386SetCr0(Ke386GetCr0() | CR0_PG);\r
+\r
+       // Set processor context\r
+       WinLdrSetProcessorContext(GdtIdt, KIP0PCRADDRESS, KSEG0_BASE | (TssBasePage << MM_PAGE_SHIFT));\r
+\r
+       // Zero KI_USER_SHARED_DATA page\r
+       memset((PVOID)KI_USER_SHARED_DATA, 0, MM_PAGE_SIZE);\r
+\r
+       return TRUE;\r
+}\r
+\r
+// Two special things this func does: it sorts descriptors,\r
+// and it merges free ones\r
+VOID\r
+WinLdrInsertDescriptor(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,\r
+                       IN PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor)\r
+{\r
+       PLIST_ENTRY ListHead = &LoaderBlock->MemoryDescriptorListHead;\r
+       PLIST_ENTRY PreviousEntry, NextEntry;\r
+       PMEMORY_ALLOCATION_DESCRIPTOR PreviousDescriptor = NULL, NextDescriptor = NULL;\r
+\r
+       DbgPrint((DPRINT_WINDOWS, "BP=0x%X PC=0x%X %s\n", NewDescriptor->BasePage,\r
+               NewDescriptor->PageCount, MemTypeDesc[NewDescriptor->MemoryType]));\r
+\r
+       /* Find a place where to insert the new descriptor to */\r
+       PreviousEntry = ListHead;\r
+       NextEntry = ListHead->Flink;\r
+       while (NextEntry != ListHead)\r
+       {\r
+               NextDescriptor = CONTAINING_RECORD(NextEntry,\r
+                       MEMORY_ALLOCATION_DESCRIPTOR,\r
+                       ListEntry);\r
+               if (NewDescriptor->BasePage < NextDescriptor->BasePage)\r
+                       break;\r
+\r
+               PreviousEntry = NextEntry;\r
+               PreviousDescriptor = NextDescriptor;\r
+               NextEntry = NextEntry->Flink;\r
+       }\r
+\r
+       /* Don't forget about merging free areas */\r
+       if (NewDescriptor->MemoryType != LoaderFree)\r
+       {\r
+               /* Just insert, nothing to merge */\r
+               InsertHeadList(PreviousEntry, &NewDescriptor->ListEntry);\r
+       }\r
+       else\r
+       {\r
+               /* Previous block also free? */\r
+               if ((PreviousEntry != ListHead) && (PreviousDescriptor->MemoryType == LoaderFree) &&\r
+                       ((PreviousDescriptor->BasePage + PreviousDescriptor->PageCount) ==\r
+                       NewDescriptor->BasePage))\r
+               {\r
+                       /* Just enlarge previous descriptor's PageCount */\r
+                       PreviousDescriptor->PageCount += NewDescriptor->PageCount;\r
+                       NewDescriptor = PreviousDescriptor;\r
+               }\r
+               else\r
+               {\r
+                       /* Nope, just insert */\r
+                       InsertHeadList(PreviousEntry, &NewDescriptor->ListEntry);\r
+               }\r
+\r
+               /* Next block is free ?*/\r
+               if ((NextEntry != ListHead) &&\r
+                       (NextDescriptor->MemoryType == LoaderFree) &&\r
+                       ((NewDescriptor->BasePage + NewDescriptor->PageCount) == NextDescriptor->BasePage))\r
+               {\r
+                       /* Enlarge next descriptor's PageCount */\r
+                       NewDescriptor->PageCount += NextDescriptor->PageCount;\r
+                       RemoveEntryList(&NextDescriptor->ListEntry);\r
+               }\r
+       }\r
+\r
+       return;\r
+}\r
+\r
+VOID\r
+WinLdrSetProcessorContext(PVOID GdtIdt, IN ULONG Pcr, IN ULONG Tss)\r
+{\r
+       GDTIDT GdtDesc, IdtDesc, OldIdt;\r
+       PKGDTENTRY      pGdt;\r
+       PKIDTENTRY      pIdt;\r
+       ULONG Ldt = 0;\r
+       //ULONG i;\r
+\r
+       DbgPrint((DPRINT_WINDOWS, "GDtIdt %p, Pcr %p, Tss 0x%08X\n",\r
+               GdtIdt, Pcr, Tss));\r
+\r
+       // Kernel expects the PCR to be zero-filled on startup\r
+       // FIXME: Why zero it here when we can zero it right after allocation?\r
+       RtlZeroMemory((PVOID)Pcr, MM_PAGE_SIZE); //FIXME: Why zero only 1 page when we allocate 2?\r
+\r
+       // Get old values of GDT and IDT\r
+       Ke386GetGlobalDescriptorTable(GdtDesc);\r
+       Ke386GetInterruptDescriptorTable(IdtDesc);\r
+\r
+       // Save old IDT\r
+       OldIdt.Base = IdtDesc.Base;\r
+       OldIdt.Limit = IdtDesc.Limit;\r
+\r
+       // Prepare new IDT+GDT\r
+       GdtDesc.Base  = KSEG0_BASE | (ULONG_PTR)GdtIdt;\r
+       GdtDesc.Limit = NUM_GDT * sizeof(KGDTENTRY) - 1;\r
+       IdtDesc.Base  = (ULONG)((PUCHAR)GdtDesc.Base + GdtDesc.Limit + 1);\r
+       IdtDesc.Limit = NUM_IDT * sizeof(KIDTENTRY) - 1;\r
+\r
+       // ========================\r
+       // Fill all descriptors now\r
+       // ========================\r
+\r
+       pGdt = (PKGDTENTRY)GdtDesc.Base;\r
+       pIdt = (PKIDTENTRY)IdtDesc.Base;\r
+\r
+       //\r
+       // Code selector (0x8)\r
+       // Flat 4Gb\r
+       //\r
+       pGdt[1].LimitLow                                = 0xFFFF;\r
+       pGdt[1].BaseLow                                 = 0;\r
+       pGdt[1].HighWord.Bytes.BaseMid  = 0;\r
+       pGdt[1].HighWord.Bytes.Flags1   = 0x9A;\r
+       pGdt[1].HighWord.Bytes.Flags2   = 0xCF;\r
+       pGdt[1].HighWord.Bytes.BaseHi   = 0;\r
+\r
+       //\r
+       // Data selector (0x10)\r
+       // Flat 4Gb\r
+       //\r
+       pGdt[2].LimitLow                                = 0xFFFF;\r
+       pGdt[2].BaseLow                                 = 0;\r
+       pGdt[2].HighWord.Bytes.BaseMid  = 0;\r
+       pGdt[2].HighWord.Bytes.Flags1   = 0x92;\r
+       pGdt[2].HighWord.Bytes.Flags2   = 0xCF;\r
+       pGdt[2].HighWord.Bytes.BaseHi   = 0;\r
+\r
+       //\r
+       // Selector (0x18)\r
+       // Flat 2Gb\r
+       //\r
+       pGdt[3].LimitLow                                = 0xFFFF;\r
+       pGdt[3].BaseLow                                 = 0;\r
+       pGdt[3].HighWord.Bytes.BaseMid  = 0;\r
+       pGdt[3].HighWord.Bytes.Flags1   = 0xFA;\r
+       pGdt[3].HighWord.Bytes.Flags2   = 0xCF;\r
+       pGdt[3].HighWord.Bytes.BaseHi   = 0;\r
+\r
+       //\r
+       // Selector (0x20)\r
+       // Flat 2Gb\r
+       //\r
+       pGdt[4].LimitLow                                = 0xFFFF;\r
+       pGdt[4].BaseLow                                 = 0;\r
+       pGdt[4].HighWord.Bytes.BaseMid  = 0;\r
+       pGdt[4].HighWord.Bytes.Flags1   = 0xF2;\r
+       pGdt[4].HighWord.Bytes.Flags2   = 0xCF;\r
+       pGdt[4].HighWord.Bytes.BaseHi   = 0;\r
+\r
+       //\r
+       // TSS Selector (0x28)\r
+       //\r
+       pGdt[5].LimitLow                                = 0x78-1; // 60 dwords\r
+       pGdt[5].BaseLow = (USHORT)(Tss & 0xffff);\r
+       pGdt[5].HighWord.Bytes.BaseMid = (UCHAR)((Tss >> 16) & 0xff);\r
+       pGdt[5].HighWord.Bytes.Flags1   = 0x89;\r
+       pGdt[5].HighWord.Bytes.Flags2   = 0x00;\r
+       pGdt[5].HighWord.Bytes.BaseHi  = (UCHAR)((Tss >> 24) & 0xff);\r
+\r
+       //\r
+       // PCR Selector (0x30)\r
+       //\r
+       pGdt[6].LimitLow                                = 0x01;\r
+       pGdt[6].BaseLow  = (USHORT)(Pcr & 0xffff);\r
+       pGdt[6].HighWord.Bytes.BaseMid = (UCHAR)((Pcr >> 16) & 0xff);\r
+       pGdt[6].HighWord.Bytes.Flags1   = 0x92;\r
+       pGdt[6].HighWord.Bytes.Flags2   = 0xC0;\r
+       pGdt[6].HighWord.Bytes.BaseHi  = (UCHAR)((Pcr >> 24) & 0xff);\r
+\r
+       //\r
+       // Selector (0x38)\r
+       //\r
+       pGdt[7].LimitLow                                = 0xFFFF;\r
+       pGdt[7].BaseLow                                 = 0;\r
+       pGdt[7].HighWord.Bytes.BaseMid  = 0;\r
+       pGdt[7].HighWord.Bytes.Flags1   = 0xF3;\r
+       pGdt[7].HighWord.Bytes.Flags2   = 0x40;\r
+       pGdt[7].HighWord.Bytes.BaseHi   = 0;\r
+\r
+       //\r
+       // Some BIOS fuck (0x40)\r
+       //\r
+       pGdt[8].LimitLow                                = 0xFFFF;\r
+       pGdt[8].BaseLow                                 = 0x400;\r
+       pGdt[8].HighWord.Bytes.BaseMid  = 0;\r
+       pGdt[8].HighWord.Bytes.Flags1   = 0xF2;\r
+       pGdt[8].HighWord.Bytes.Flags2   = 0x0;\r
+       pGdt[8].HighWord.Bytes.BaseHi   = 0;\r
+\r
+       //\r
+       // Selector (0x48)\r
+       //\r
+       pGdt[9].LimitLow                                = 0;\r
+       pGdt[9].BaseLow                                 = 0;\r
+       pGdt[9].HighWord.Bytes.BaseMid  = 0;\r
+       pGdt[9].HighWord.Bytes.Flags1   = 0;\r
+       pGdt[9].HighWord.Bytes.Flags2   = 0;\r
+       pGdt[9].HighWord.Bytes.BaseHi   = 0;\r
+\r
+       //\r
+       // Selector (0x50)\r
+       //\r
+       pGdt[10].LimitLow                               = 0xFFFF; //FIXME: Not correct!\r
+       pGdt[10].BaseLow                                = 0;\r
+       pGdt[10].HighWord.Bytes.BaseMid = 0x2;\r
+       pGdt[10].HighWord.Bytes.Flags1  = 0x89;\r
+       pGdt[10].HighWord.Bytes.Flags2  = 0;\r
+       pGdt[10].HighWord.Bytes.BaseHi  = 0;\r
+\r
+       //\r
+       // Selector (0x58)\r
+       //\r
+       pGdt[11].LimitLow                               = 0xFFFF;\r
+       pGdt[11].BaseLow                                = 0;\r
+       pGdt[11].HighWord.Bytes.BaseMid = 0x2;\r
+       pGdt[11].HighWord.Bytes.Flags1  = 0x9A;\r
+       pGdt[11].HighWord.Bytes.Flags2  = 0;\r
+       pGdt[11].HighWord.Bytes.BaseHi  = 0;\r
+\r
+       //\r
+       // Selector (0x60)\r
+       //\r
+       pGdt[12].LimitLow                               = 0xFFFF;\r
+       pGdt[12].BaseLow                                = 0; //FIXME: Maybe not correct, but noone cares\r
+       pGdt[12].HighWord.Bytes.BaseMid = 0x2;\r
+       pGdt[12].HighWord.Bytes.Flags1  = 0x92;\r
+       pGdt[12].HighWord.Bytes.Flags2  = 0;\r
+       pGdt[12].HighWord.Bytes.BaseHi  = 0;\r
+\r
+       //\r
+       // Video buffer Selector (0x68)\r
+       //\r
+       pGdt[13].LimitLow                               = 0x3FFF;\r
+       pGdt[13].BaseLow                                = 0x8000; //FIXME: I guess not correct for UGA\r
+       pGdt[13].HighWord.Bytes.BaseMid = 0x0B;\r
+       pGdt[13].HighWord.Bytes.Flags1  = 0x92;\r
+       pGdt[13].HighWord.Bytes.Flags2  = 0;\r
+       pGdt[13].HighWord.Bytes.BaseHi  = 0;\r
+\r
+       //\r
+       // Points to GDT (0x70)\r
+       //\r
+       pGdt[14].LimitLow                               = NUM_GDT*sizeof(KGDTENTRY) - 1;\r
+       pGdt[14].BaseLow                                = 0x7000;\r
+       pGdt[14].HighWord.Bytes.BaseMid = 0xFF;\r
+       pGdt[14].HighWord.Bytes.Flags1  = 0x92;\r
+       pGdt[14].HighWord.Bytes.Flags2  = 0;\r
+       pGdt[14].HighWord.Bytes.BaseHi  = 0xFF;\r
+\r
+       //\r
+       // Some unused descriptors should go here\r
+       // ...\r
+\r
+       //\r
+       // Fill IDT with Traps\r
+       //\r
+#if 0\r
+       pIdt[0].Offset = (i386DivideByZero | KSEG0_BASE) & 0xFFFF;\r
+       pIdt[0].ExtendedOffset = 0x8; // Selector\r
+       pIdt[0].Access = 0x8F00;\r
+       pIdt[0].Selector = (i386DivideByZero | KSEG0_BASE) >> 16; // Extended Offset\r
+\r
+       pIdt[1].Offset = (i386DebugException | KSEG0_BASE) & 0xFFFF;\r
+       pIdt[1].ExtendedOffset = 0x8; // Selector\r
+       pIdt[1].Access = 0x8F00;\r
+       pIdt[1].Selector = (i386DebugException | KSEG0_BASE) >> 16; // Extended Offset\r
+\r
+       pIdt[2].Offset = (i386NMIException | KSEG0_BASE) & 0xFFFF;\r
+       pIdt[2].ExtendedOffset = 0x8; // Selector\r
+       pIdt[2].Access = 0x8F00;\r
+       pIdt[2].Selector = (i386NMIException | KSEG0_BASE) >> 16; // Extended Offset\r
+\r
+       pIdt[3].Offset = (i386Breakpoint | KSEG0_BASE) & 0xFFFF;\r
+       pIdt[3].ExtendedOffset = 0x8; // Selector\r
+       pIdt[3].Access = 0x8F00;\r
+       pIdt[3].Selector = (i386Breakpoint | KSEG0_BASE) >> 16; // Extended Offset\r
+\r
+       pIdt[4].Offset = (i386Overflow | KSEG0_BASE) & 0xFFFF;\r
+       pIdt[4].ExtendedOffset = 0x8; // Selector\r
+       pIdt[4].Access = 0x8F00;\r
+       pIdt[4].Selector = (i386Overflow | KSEG0_BASE) >> 16; // Extended Offset\r
+\r
+       pIdt[5].Selector = (i386BoundException | KSEG0_BASE) >> 16; // Extended Offset\r
+       pIdt[5].Offset = (i386BoundException | KSEG0_BASE) & 0xFFFF;\r
+       pIdt[5].ExtendedOffset = 0x8; // Selector\r
+       pIdt[5].Access = 0x8F00;\r
+\r
+       pIdt[6].Selector = (i386InvalidOpcode | KSEG0_BASE) >> 16; // Extended Offset\r
+       pIdt[6].Offset = (i386InvalidOpcode | KSEG0_BASE) & 0xFFFF;\r
+       pIdt[6].ExtendedOffset = 0x8; // Selector\r
+       pIdt[6].Access = 0x8F00;\r
+\r
+       pIdt[7].Selector = (i386FPUNotAvailable | KSEG0_BASE) >> 16; // Extended Offset\r
+       pIdt[7].Offset = (i386FPUNotAvailable | KSEG0_BASE) & 0xFFFF;\r
+       pIdt[7].ExtendedOffset = 0x8; // Selector\r
+       pIdt[7].Access = 0x8F00;\r
+\r
+       pIdt[8].Selector = (i386DoubleFault | KSEG0_BASE) >> 16; // Extended Offset\r
+       pIdt[8].Offset = (i386DoubleFault | KSEG0_BASE) & 0xFFFF;\r
+       pIdt[8].ExtendedOffset = 0x8; // Selector\r
+       pIdt[8].Access = 0x8F00;\r
+\r
+       pIdt[9].Selector = (i386CoprocessorSegment | KSEG0_BASE) >> 16; // Extended Offset\r
+       pIdt[9].Offset = (i386CoprocessorSegment | KSEG0_BASE) & 0xFFFF;\r
+       pIdt[9].ExtendedOffset = 0x8; // Selector\r
+       pIdt[9].Access = 0x8F00;\r
+\r
+       pIdt[10].Selector = (i386InvalidTSS | KSEG0_BASE) >> 16; // Extended Offset\r
+       pIdt[10].Offset = (i386InvalidTSS | KSEG0_BASE) & 0xFFFF;\r
+       pIdt[10].ExtendedOffset = 0x8; // Selector\r
+       pIdt[10].Access = 0x8F00;\r
+\r
+       pIdt[11].Selector = (i386SegmentNotPresent | KSEG0_BASE) >> 16; // Extended Offset\r
+       pIdt[11].Offset = (i386SegmentNotPresent | KSEG0_BASE) & 0xFFFF;\r
+       pIdt[11].ExtendedOffset = 0x8; // Selector\r
+       pIdt[11].Access = 0x8F00;\r
+\r
+       pIdt[12].Selector = (i386StackException | KSEG0_BASE) >> 16; // Extended Offset\r
+       pIdt[12].Offset = (i386StackException | KSEG0_BASE) & 0xFFFF;\r
+       pIdt[12].ExtendedOffset = 0x8; // Selector\r
+       pIdt[12].Access = 0x8F00;\r
+\r
+       pIdt[13].Selector = (i386GeneralProtectionFault | KSEG0_BASE) >> 16; // Extended Offset\r
+       pIdt[13].Offset = (i386GeneralProtectionFault | KSEG0_BASE) & 0xFFFF;\r
+       pIdt[13].ExtendedOffset = 0x8; // Selector\r
+       pIdt[13].Access = 0x8F00;\r
+\r
+       pIdt[14].Selector = (i386PageFault | KSEG0_BASE) >> 16; // Extended Offset\r
+       pIdt[14].Offset = (i386PageFault | KSEG0_BASE) & 0xFFFF;\r
+       pIdt[14].ExtendedOffset = 0x8; // Selector\r
+       pIdt[14].Access = 0x8F00;\r
+\r
+       pIdt[15].Selector = 0; // Extended Offset\r
+       pIdt[15].Offset = 0;\r
+       pIdt[15].ExtendedOffset = 0; // Selector\r
+       pIdt[15].Access = 0;\r
+\r
+       pIdt[16].Selector = (i386CoprocessorError | KSEG0_BASE) >> 16; // Extended Offset\r
+       pIdt[16].Offset = (i386CoprocessorError | KSEG0_BASE) & 0xFFFF;\r
+       pIdt[16].ExtendedOffset = 0x8; // Selector\r
+       pIdt[16].Access = 0x8F00;\r
+\r
+       pIdt[17].Selector = (i386AlignmentCheck | KSEG0_BASE) >> 16; // Extended Offset\r
+       pIdt[17].Offset = (i386AlignmentCheck | KSEG0_BASE) & 0xFFFF;\r
+       pIdt[17].ExtendedOffset = 0x8; // Selector\r
+       pIdt[17].Access = 0x8F00;\r
+#endif\r
+\r
+       /*for (i=0; i<16; i++)\r
+       {\r
+               //pIdt[i].Offset = ((ULONG_PTR)i386GeneralProtectionFault | KSEG0_BASE) & 0xFFFF;\r
+               //pIdt[i].ExtendedOffset = 0x8; // Selector\r
+               //pIdt[i].Access = 0x8F00;\r
+               //pIdt[i].Selector = ((ULONG_PTR)i386GeneralProtectionFault | KSEG0_BASE) >> 16; // Extended Offset\r
+\r
+               pIdt[i].Offset = ((ULONG_PTR)i386GeneralProtectionFault | KSEG0_BASE) & 0xFFFF;\r
+               pIdt[i].ExtendedOffset = ((ULONG_PTR)i386GeneralProtectionFault | KSEG0_BASE) >> 16; // Extended Offset\r
+               pIdt[i].Access = 0x8F00;\r
+               pIdt[i].Selector = 0x8;\r
+       }*/\r
+\r
+       // Copy the old IDT\r
+       RtlCopyMemory(pIdt, (PVOID)OldIdt.Base, OldIdt.Limit);\r
+\r
+\r
+       // Mask interrupts\r
+       //asm("cli\n"); // they are already masked before enabling paged mode\r
+\r
+       // Load GDT+IDT\r
+       Ke386SetGlobalDescriptorTable(GdtDesc);\r
+       Ke386SetInterruptDescriptorTable(IdtDesc);\r
+\r
+       // Jump to proper CS and clear prefetch queue\r
+       asm("ljmp       $0x08, $mb1\n"\r
+               "mb1:\n");\r
+\r
+       // Set SS selector\r
+       asm(".intel_syntax noprefix\n");\r
+               asm("mov ax, 0x10\n"); // DataSelector=0x10\r
+               asm("mov ss, ax\n");\r
+       asm(".att_syntax\n");\r
+\r
+       // Set DS and ES selectors\r
+       Ke386SetDs(0x10);\r
+       Ke386SetEs(0x10); // this is vital for rep stosd\r
+\r
+       // LDT = not used ever, thus set to 0\r
+       Ke386SetLocalDescriptorTable(Ldt);\r
+\r
+       // Load TSR\r
+       Ke386SetTr(0x28);\r
+\r
+       // Clear GS\r
+       asm(".intel_syntax noprefix\n");\r
+               asm("push 0\n");\r
+               asm("pop gs\n");\r
+       asm(".att_syntax\n");\r
+\r
+       // Set FS to PCR\r
+       Ke386SetFs(0x30);\r
+\r
+               // Real end of the function, just for information\r
+               /* do not uncomment!\r
+               pop edi;\r
+               pop esi;\r
+               pop ebx;\r
+               mov esp, ebp;\r
+               pop ebp;\r
+               ret\r
+               */\r
 }\r