Merge freeldr from amd64 branch:
[reactos.git] / reactos / boot / freeldr / freeldr / windows / wlmemory.c
index 6ae0d1d..78e9589 100644 (file)
-/*\r
- * PROJECT:         EFI Windows Loader\r
- * LICENSE:         GPL - See COPYING in the top level directory\r
- * FILE:            freeldr/winldr/wlmemory.c\r
- * PURPOSE:         Memory related routines\r
- * PROGRAMMERS:     Aleksey Bragin (aleksey@reactos.org)\r
- */\r
-\r
-/* INCLUDES ***************************************************************/\r
-\r
-#include <freeldr.h>\r
-\r
-#include <ndk/asm.h>\r
-#include <debug.h>\r
-\r
-extern ULONG TotalNLSSize;\r
-extern ULONG LoaderPagesSpanned;\r
-\r
-// This is needed because headers define wrong one for ReactOS\r
-#undef KIP0PCRADDRESS\r
-#define KIP0PCRADDRESS                      0xffdff000\r
-\r
-#define HYPER_SPACE_ENTRY       0x300\r
-\r
-PCHAR  MemTypeDesc[]  = {\r
-    "ExceptionBlock    ", // ?\r
-    "SystemBlock       ", // ?\r
-    "Free              ",\r
-    "Bad               ", // used\r
-    "LoadedProgram     ", // == Free\r
-    "FirmwareTemporary ", // == Free\r
-    "FirmwarePermanent ", // == Bad\r
-    "OsloaderHeap      ", // used\r
-    "OsloaderStack     ", // == Free\r
-    "SystemCode        ",\r
-    "HalCode           ",\r
-    "BootDriver        ", // not used\r
-    "ConsoleInDriver   ", // ?\r
-    "ConsoleOutDriver  ", // ?\r
-    "StartupDpcStack   ", // ?\r
-    "StartupKernelStack", // ?\r
-    "StartupPanicStack ", // ?\r
-    "StartupPcrPage    ", // ?\r
-    "StartupPdrPage    ", // ?\r
-    "RegistryData      ", // used\r
-    "MemoryData        ", // not used\r
-    "NlsData           ", // used\r
-    "SpecialMemory     ", // == Bad\r
-    "BBTMemory         " // == Bad\r
-    };\r
-\r
-VOID\r
-WinLdrpDumpMemoryDescriptors(PLOADER_PARAMETER_BLOCK LoaderBlock);\r
-\r
-\r
-VOID\r
-MempAddMemoryBlock(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,\r
-                   ULONG BasePage,\r
-                   ULONG 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 HalPageTable;\r
-\r
-PUCHAR PhysicalPageTablesBuffer;\r
-PUCHAR KernelPageTablesBuffer;\r
-ULONG PhysicalPageTables;\r
-ULONG KernelPageTables;\r
-\r
-MEMORY_ALLOCATION_DESCRIPTOR *Mad;\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
-\r
-       // PDE+HAL+KernelPTEs == MemoryData\r
-       Buffer = MmAllocateMemoryWithType(\r
-               TotalSize - NumPageTables*MM_PAGE_SIZE, LoaderMemoryData);\r
-\r
-       // Physical PTEs = FirmwareTemporary\r
-       PhysicalPageTablesBuffer = MmAllocateMemoryWithType(\r
-               NumPageTables*MM_PAGE_SIZE, LoaderFirmwareTemporary);\r
-\r
-       if (Buffer + (TotalSize - NumPageTables*MM_PAGE_SIZE) !=\r
-               PhysicalPageTablesBuffer)\r
-       {\r
-               DbgPrint((DPRINT_WINDOWS, "There was a problem allocating two adjacent blocks of memory!"));\r
-       }\r
-\r
-       if (Buffer == NULL || PhysicalPageTablesBuffer == 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
-       HalPageTable = (PHARDWARE_PTE)&Buffer[MM_PAGE_SIZE*1];\r
-\r
-       // Map it\r
-       PDE[1023].PageFrameNumber = (ULONG)HalPageTable >> MM_PAGE_SHIFT;\r
-       PDE[1023].Valid = 1;\r
-       PDE[1023].Write = 1;\r
-\r
-       // Store pointer to the table for easier access\r
-       KernelPageTablesBuffer = &Buffer[MM_PAGE_SIZE*2];\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
-MempDisablePages()\r
-{\r
-       int i;\r
-\r
-       //\r
-       // We need to delete kernel mapping from memory areas which are\r
-       // marked as Special or Permanent memory (thus non-accessible)\r
-       //\r
-\r
-       for (i=0; i<MadCount; i++)\r
-       {\r
-               ULONG StartPage, EndPage, Page;\r
-\r
-               StartPage = Mad[i].BasePage;\r
-               EndPage = Mad[i].BasePage + Mad[i].PageCount;\r
-\r
-               if (Mad[i].MemoryType == LoaderFirmwarePermanent ||\r
-                       Mad[i].MemoryType == LoaderSpecialMemory ||\r
-                       Mad[i].MemoryType == LoaderFree ||\r
-                       (Mad[i].MemoryType == LoaderFirmwareTemporary && EndPage <= LoaderPagesSpanned) ||\r
-                       Mad[i].MemoryType == LoaderOsloaderStack ||\r
-                       Mad[i].MemoryType == LoaderLoadedProgram)\r
-               {\r
-                       //\r
-                       // But, the first megabyte of memory always stays!\r
-                       // And, to tell the truth, we don't care about what's higher\r
-                       // than LoaderPagesSpanned\r
-                       if (Mad[i].MemoryType == LoaderFirmwarePermanent ||\r
-                               Mad[i].MemoryType == LoaderSpecialMemory)\r
-                       {\r
-                               if (StartPage < 0x100)\r
-                                       StartPage = 0x100;\r
-\r
-                               if (EndPage > LoaderPagesSpanned)\r
-                                       EndPage = LoaderPagesSpanned;\r
-                       }\r
-\r
-                       for (Page = StartPage; Page < EndPage; Page++)\r
-                       {\r
-                               PHARDWARE_PTE KernelPT;\r
-                               ULONG Entry = (Page >> 10) + (KSEG0_BASE >> 22);\r
-\r
-                               if (PDE[Entry].Valid)\r
-                               {\r
-                                       KernelPT = (PHARDWARE_PTE)(PDE[Entry].PageFrameNumber << MM_PAGE_SHIFT);\r
-\r
-                                       if (KernelPT)\r
-                                       {\r
-                                               KernelPT[Page & 0x3ff].PageFrameNumber = 0;\r
-                                               KernelPT[Page & 0x3ff].Valid = 0;\r
-                                               KernelPT[Page & 0x3ff].Write = 0;\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-}\r
-\r
-VOID\r
-MempAddMemoryBlock(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,\r
-                   ULONG BasePage,\r
-                   ULONG 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
-       // Set Base page, page count and type\r
-       //\r
-       Mad[MadCount].BasePage = BasePage;\r
-       Mad[MadCount].PageCount = PageCount;\r
-       Mad[MadCount].MemoryType = Type;\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 > LoaderPagesSpanned)\r
-       {\r
-               if (Mad[MadCount].MemoryType != LoaderSpecialMemory &&\r
-                       Mad[MadCount].MemoryType != LoaderFirmwarePermanent &&\r
-                       Mad[MadCount].MemoryType != LoaderFree)\r
-               {\r
-                       DbgPrint((DPRINT_WINDOWS, "Setting page %x %x to Temporary from %d\n",\r
-                               BasePage, PageCount, Mad[MadCount].MemoryType));\r
-                       Mad[MadCount].MemoryType = LoaderFirmwareTemporary;\r
-               }\r
-\r
-               WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]);\r
-               MadCount++;\r
-\r
-               return;\r
-       }\r
-       \r
-       //\r
-       // Add descriptor\r
-       //\r
-       WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]);\r
-       MadCount++;\r
-\r
-       //\r
-       // Map it (don't map low 1Mb because it was already contigiously\r
-       // mapped in WinLdrTurnOnPaging)\r
-       //\r
-       if (BasePage >= 0x100)\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
-#ifdef _M_IX86\r
-\r
-BOOLEAN LocalAPIC = FALSE;\r
-ULONG_PTR APICAddress = 0;\r
-\r
-VOID\r
-WinLdrpMapApic()\r
-{\r
-       /* Check if we have a local APIC */\r
-       asm(".intel_syntax noprefix\n");\r
-               asm("mov eax, 1\n");\r
-               asm("cpuid\n");\r
-               asm("shr edx, 9\n");\r
-               asm("and edx, 0x1\n");\r
-               asm("mov _LocalAPIC, edx\n");\r
-       asm(".att_syntax\n");\r
-\r
-       /* If there is no APIC, just return */\r
-       if (!LocalAPIC)\r
-               return;\r
-\r
-       asm(".intel_syntax noprefix\n");\r
-               asm("mov ecx, 0x1B\n");\r
-               asm("rdmsr\n");\r
-               asm("mov edx, eax\n");\r
-               asm("and edx, 0xFFFFF000\n");\r
-               asm("mov _APICAddress, edx");\r
-       asm(".att_syntax\n");\r
-\r
-       DbgPrint((DPRINT_WINDOWS, "Local APIC detected at address 0x%x\n",\r
-               APICAddress));\r
-\r
-       /* Map it */\r
-       HalPageTable[(APIC_BASE - 0xFFC00000) >> MM_PAGE_SHIFT].PageFrameNumber\r
-               = APICAddress >> MM_PAGE_SHIFT;\r
-       HalPageTable[(APIC_BASE - 0xFFC00000) >> MM_PAGE_SHIFT].Valid = 1;\r
-       HalPageTable[(APIC_BASE - 0xFFC00000) >> MM_PAGE_SHIFT].Write = 1;\r
-       HalPageTable[(APIC_BASE - 0xFFC00000) >> MM_PAGE_SHIFT].WriteThrough = 1;\r
-       HalPageTable[(APIC_BASE - 0xFFC00000) >> MM_PAGE_SHIFT].CacheDisable = 1;\r
-}\r
-#else\r
-VOID\r
-WinLdrpMapApic()\r
-{\r
-       /* Implement it for another arch */\r
-}\r
-#endif\r
-\r
-BOOLEAN\r
-WinLdrTurnOnPaging(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,\r
-                   ULONG PcrBasePage,\r
-                   ULONG TssBasePage,\r
-                   PVOID GdtIdt)\r
-{\r
-       ULONG i, PagesCount, MemoryMapSizeInPages;\r
-       ULONG LastPageIndex, LastPageType, MemoryMapStartPage;\r
-       PPAGE_LOOKUP_TABLE_ITEM MemoryMap;\r
-       ULONG NoEntries;\r
-       PKTSS Tss;\r
-       BOOLEAN Status;\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 (?? why?)\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
-       // Allocate memory for memory allocation descriptors\r
-       Mad = MmHeapAlloc(sizeof(MEMORY_ALLOCATION_DESCRIPTOR) * 1024);\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
-       // Calculate parameters of the memory map\r
-       MemoryMapStartPage = (ULONG_PTR)MemoryMap >> MM_PAGE_SHIFT;\r
-       MemoryMapSizeInPages = NoEntries * sizeof(PAGE_LOOKUP_TABLE_ITEM);\r
-\r
-       DbgPrint((DPRINT_WINDOWS, "Got memory map with %d entries\n", NoEntries));\r
-\r
-       // Always contigiously map low 1Mb of memory\r
-       Status = MempSetupPaging(0, 0x100);\r
-       if (!Status)\r
-       {\r
-               DbgPrint((DPRINT_WINDOWS, "Error during MempSetupPaging of low 1Mb\n"));\r
-               return FALSE;\r
-       }\r
-\r
-       // Construct a good memory map from what we've got,\r
-       // but mark entries which the memory allocation bitmap takes\r
-       // as free entries (this is done in order to have the ability\r
-       // to place mem alloc bitmap outside lower 16Mb zone)\r
-       PagesCount = 1;\r
-       LastPageIndex = 0;\r
-       LastPageType = MemoryMap[0].PageAllocated;\r
-       for(i=1;i<NoEntries;i++)\r
-       {\r
-               // Check if its memory map itself\r
-               if (i >= MemoryMapStartPage &&\r
-                       i < (MemoryMapStartPage+MemoryMapSizeInPages))\r
-               {\r
-                       // Exclude it if current page belongs to the memory map\r
-                       MemoryMap[i].PageAllocated = LoaderFree;\r
-               }\r
-\r
-               // Process entry\r
-               if (MemoryMap[i].PageAllocated == LastPageType &&\r
-                       (i != NoEntries-1) )\r
-               {\r
-                       PagesCount++;\r
-               }\r
-               else\r
-               {\r
-                       // Add the resulting 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
-       // TEMP, DEBUG!\r
-       // adding special reserved memory zones for vmware workstation\r
-#if 0\r
-       {\r
-               Mad[MadCount].BasePage = 0xfec00;\r
-               Mad[MadCount].PageCount = 0x10;\r
-               Mad[MadCount].MemoryType = LoaderSpecialMemory;\r
-               WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]);\r
-               MadCount++;\r
-\r
-               Mad[MadCount].BasePage = 0xfee00;\r
-               Mad[MadCount].PageCount = 0x1;\r
-               Mad[MadCount].MemoryType = LoaderSpecialMemory;\r
-               WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]);\r
-               MadCount++;\r
-\r
-               Mad[MadCount].BasePage = 0xfffe0;\r
-               Mad[MadCount].PageCount = 0x20;\r
-               Mad[MadCount].MemoryType = LoaderSpecialMemory;\r
-               WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]);\r
-               MadCount++;\r
-       }\r
-#endif\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, "HalPageTable: 0x%X\n", HalPageTable));\r
-\r
-       // Page Tables have been setup, make special handling for PCR and TSS\r
-       // (which is done in BlSetupFotNt in usual ntldr)\r
-       HalPageTable[(KI_USER_SHARED_DATA - 0xFFC00000) >> MM_PAGE_SHIFT].PageFrameNumber = PcrBasePage+1;\r
-       HalPageTable[(KI_USER_SHARED_DATA - 0xFFC00000) >> MM_PAGE_SHIFT].Valid = 1;\r
-       HalPageTable[(KI_USER_SHARED_DATA - 0xFFC00000) >> MM_PAGE_SHIFT].Write = 1;\r
-\r
-       HalPageTable[(KIP0PCRADDRESS - 0xFFC00000) >> MM_PAGE_SHIFT].PageFrameNumber = PcrBasePage;\r
-       HalPageTable[(KIP0PCRADDRESS - 0xFFC00000) >> MM_PAGE_SHIFT].Valid = 1;\r
-       HalPageTable[(KIP0PCRADDRESS - 0xFFC00000) >> MM_PAGE_SHIFT].Write = 1;\r
-\r
-       // Map APIC\r
-       WinLdrpMapApic();\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
-       // Unmap what is not needed from kernel page table\r
-       MempDisablePages();\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
-#ifdef DBG\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
-#endif\r
-\r
-\r
-       // Enable paging\r
-       //BS->ExitBootServices(ImageHandle,MapKey);\r
-\r
-       // Disable Interrupts\r
-       _disable();\r
-\r
-       // Re-initalize EFLAGS\r
-       Ke386EraseFlags();\r
-\r
-       // Set the PDBR\r
-       __writecr3((ULONG_PTR)PDE);\r
-\r
-       // Enable paging by modifying CR0\r
-       __writecr0(__readcr0() | 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; //FIXME: Check this\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 stuff (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;\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
-       // Copy the old IDT\r
-       RtlCopyMemory(pIdt, (PVOID)OldIdt.Base, OldIdt.Limit);\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
+/*
+ * 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 TotalNLSSize;
+extern ULONG LoaderPagesSpanned;
+
+// This is needed because headers define wrong one for ReactOS
+#undef KIP0PCRADDRESS
+#define KIP0PCRADDRESS                      0xffdff000
+
+#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
+       {
+               USHORT Limit;
+               ULONG Base;
+       } GDTIDT;
+#pragma pack(4)
+
+// this is needed for new IDT filling
+#if 0
+extern ULONG_PTR i386DivideByZero;
+extern ULONG_PTR i386DebugException;
+extern ULONG_PTR i386NMIException;
+extern ULONG_PTR i386Breakpoint;
+extern ULONG_PTR i386Overflow;
+extern ULONG_PTR i386BoundException;
+extern ULONG_PTR i386InvalidOpcode;
+extern ULONG_PTR i386FPUNotAvailable;
+extern ULONG_PTR i386DoubleFault;
+extern ULONG_PTR i386CoprocessorSegment;
+extern ULONG_PTR i386InvalidTSS;
+extern ULONG_PTR i386SegmentNotPresent;
+extern ULONG_PTR i386StackException;
+extern ULONG_PTR i386GeneralProtectionFault;
+extern ULONG_PTR i386PageFault; // exc 14
+extern ULONG_PTR i386CoprocessorError; // exc 16
+extern ULONG_PTR i386AlignmentCheck; // exc 17
+#endif
+
+/* GLOBALS ***************************************************************/
+
+PHARDWARE_PTE PDE;
+PHARDWARE_PTE HalPageTable;
+
+PUCHAR PhysicalPageTablesBuffer;
+PUCHAR KernelPageTablesBuffer;
+ULONG PhysicalPageTables;
+ULONG KernelPageTables;
+
+MEMORY_ALLOCATION_DESCRIPTOR *Mad;
+ULONG MadCount = 0;
+
+
+/* FUNCTIONS **************************************************************/
+
+BOOLEAN
+MempAllocatePageTables()
+{
+       ULONG NumPageTables, TotalSize;
+       PUCHAR Buffer;
+       // It's better to allocate PDE + PTEs contigiuos
+
+       // Max number of entries = MaxPageNum >> 10
+       // FIXME: This is a number to describe ALL physical memory
+       // and windows doesn't expect ALL memory mapped...
+       NumPageTables = (GetSystemMemorySize() >> MM_PAGE_SHIFT) >> 10;
+
+       DPRINTM(DPRINT_WINDOWS, "NumPageTables = %d\n", NumPageTables);
+
+       // Allocate memory block for all these things:
+       // PDE, HAL mapping page table, physical mapping, kernel mapping
+       TotalSize = (1+1+NumPageTables*2)*MM_PAGE_SIZE;
+
+       // PDE+HAL+KernelPTEs == MemoryData
+       Buffer = MmAllocateMemoryWithType(TotalSize, LoaderMemoryData);
+
+       // Physical PTEs = FirmwareTemporary
+       PhysicalPageTablesBuffer = (PUCHAR)Buffer + TotalSize - NumPageTables*MM_PAGE_SIZE;
+       MmSetMemoryType(PhysicalPageTablesBuffer,
+                       NumPageTables*MM_PAGE_SIZE,
+                       LoaderFirmwareTemporary);
+
+       // This check is now redundant
+       if (Buffer + (TotalSize - NumPageTables*MM_PAGE_SIZE) !=
+               PhysicalPageTablesBuffer)
+       {
+               DPRINTM(DPRINT_WINDOWS, "There was a problem allocating two adjacent blocks of memory!");
+       }
+
+       if (Buffer == NULL || PhysicalPageTablesBuffer == NULL)
+       {
+               UiMessageBox("Impossible to allocate memory block for page tables!");
+               return FALSE;
+       }
+
+       // Zero all this memory block
+       RtlZeroMemory(Buffer, TotalSize);
+
+       // Set up pointers correctly now
+       PDE = (PHARDWARE_PTE)Buffer;
+
+       // Map the page directory at 0xC0000000 (maps itself)
+       PDE[HYPER_SPACE_ENTRY].PageFrameNumber = (ULONG)PDE >> MM_PAGE_SHIFT;
+       PDE[HYPER_SPACE_ENTRY].Valid = 1;
+       PDE[HYPER_SPACE_ENTRY].Write = 1;
+
+       // The last PDE slot is allocated for HAL's memory mapping (Virtual Addresses 0xFFC00000 - 0xFFFFFFFF)
+       HalPageTable = (PHARDWARE_PTE)&Buffer[MM_PAGE_SIZE*1];
+
+       // Map it
+       PDE[1023].PageFrameNumber = (ULONG)HalPageTable >> MM_PAGE_SHIFT;
+       PDE[1023].Valid = 1;
+       PDE[1023].Write = 1;
+
+       // Store pointer to the table for easier access
+       KernelPageTablesBuffer = &Buffer[MM_PAGE_SIZE*2];
+
+       // Zero counters of page tables used
+       PhysicalPageTables = 0;
+       KernelPageTables = 0;
+
+       return TRUE;
+}
+
+VOID
+MempAllocatePTE(ULONG Entry, PHARDWARE_PTE *PhysicalPT, PHARDWARE_PTE *KernelPT)
+{
+       //Print(L"Creating PDE Entry %X\n", Entry);
+
+       // Identity mapping
+       *PhysicalPT = (PHARDWARE_PTE)&PhysicalPageTablesBuffer[PhysicalPageTables*MM_PAGE_SIZE];
+       PhysicalPageTables++;
+
+       PDE[Entry].PageFrameNumber = (ULONG)*PhysicalPT >> MM_PAGE_SHIFT;
+       PDE[Entry].Valid = 1;
+       PDE[Entry].Write = 1;
+
+       if (Entry+(KSEG0_BASE >> 22) > 1023)
+       {
+               DPRINTM(DPRINT_WINDOWS, "WARNING! Entry: %X > 1023\n", Entry+(KSEG0_BASE >> 22));
+       }
+
+       // Kernel-mode mapping
+       *KernelPT = (PHARDWARE_PTE)&KernelPageTablesBuffer[KernelPageTables*MM_PAGE_SIZE];
+       KernelPageTables++;
+
+       PDE[Entry+(KSEG0_BASE >> 22)].PageFrameNumber = ((ULONG)*KernelPT >> MM_PAGE_SHIFT);
+       PDE[Entry+(KSEG0_BASE >> 22)].Valid = 1;
+       PDE[Entry+(KSEG0_BASE >> 22)].Write = 1;
+}
+
+BOOLEAN
+MempSetupPaging(IN ULONG StartPage,
+                               IN ULONG NumberOfPages)
+{
+       PHARDWARE_PTE PhysicalPT;
+       PHARDWARE_PTE KernelPT;
+       ULONG Entry, Page;
+
+       //Print(L"MempSetupPaging: SP 0x%X, Number: 0x%X\n", StartPage, NumberOfPages);
+       
+       // HACK
+       if (StartPage+NumberOfPages >= 0x80000)
+       {
+               //
+               // We can't map this as it requires more than 1 PDE
+               // and in fact it's not possible at all ;)
+               //
+               //Print(L"skipping...\n");
+               return TRUE;
+       }
+
+       //
+       // Now actually set up the page tables for identity mapping
+       //
+       for (Page=StartPage; Page < StartPage+NumberOfPages; Page++)
+       {
+               Entry = Page >> 10;
+
+               if (((PULONG)PDE)[Entry] == 0)
+               {
+                       MempAllocatePTE(Entry, &PhysicalPT, &KernelPT);
+               }
+               else
+               {
+                       PhysicalPT = (PHARDWARE_PTE)(PDE[Entry].PageFrameNumber << MM_PAGE_SHIFT);
+                       KernelPT = (PHARDWARE_PTE)(PDE[Entry+(KSEG0_BASE >> 22)].PageFrameNumber << MM_PAGE_SHIFT);
+               }
+
+               if (Page == 0)
+               {
+                       PhysicalPT[Page & 0x3ff].PageFrameNumber = Page;
+                       PhysicalPT[Page & 0x3ff].Valid = 0;
+                       PhysicalPT[Page & 0x3ff].Write = 0;
+
+                       KernelPT[Page & 0x3ff].PageFrameNumber = Page;
+                       KernelPT[Page & 0x3ff].Valid = 0;
+                       KernelPT[Page & 0x3ff].Write = 0;
+               }
+               else
+               {
+                       PhysicalPT[Page & 0x3ff].PageFrameNumber = Page;
+                       PhysicalPT[Page & 0x3ff].Valid = 1;
+                       PhysicalPT[Page & 0x3ff].Write = 1;
+
+                       KernelPT[Page & 0x3ff].PageFrameNumber = Page;
+                       KernelPT[Page & 0x3ff].Valid = 1;
+                       KernelPT[Page & 0x3ff].Write = 1;
+               }
+       }
+
+       return TRUE;
+}
+
+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++)
+                       {
+                               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;
+                                       }
+                               }
+                       }
+               }
+       }
+}
+
+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
+
+BOOLEAN LocalAPIC = FALSE;
+ULONG_PTR APICAddress = 0;
+
+VOID
+WinLdrpMapApic()
+{
+       /* Check if we have a local APIC */
+       asm(".intel_syntax noprefix\n");
+               asm("mov eax, 1\n");
+               asm("cpuid\n");
+               asm("shr edx, 9\n");
+               asm("and edx, 0x1\n");
+               asm("mov _LocalAPIC, edx\n");
+       asm(".att_syntax\n");
+
+       /* If there is no APIC, just return */
+       if (!LocalAPIC)
+               return;
+
+       asm(".intel_syntax noprefix\n");
+               asm("mov ecx, 0x1B\n");
+               asm("rdmsr\n");
+               asm("mov edx, eax\n");
+               asm("and edx, 0xFFFFF000\n");
+               asm("mov _APICAddress, edx");
+       asm(".att_syntax\n");
+
+       DPRINTM(DPRINT_WINDOWS, "Local APIC detected at address 0x%x\n",
+               APICAddress);
+
+       /* Map it */
+       HalPageTable[(APIC_BASE - 0xFFC00000) >> MM_PAGE_SHIFT].PageFrameNumber
+               = APICAddress >> MM_PAGE_SHIFT;
+       HalPageTable[(APIC_BASE - 0xFFC00000) >> MM_PAGE_SHIFT].Valid = 1;
+       HalPageTable[(APIC_BASE - 0xFFC00000) >> MM_PAGE_SHIFT].Write = 1;
+       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)
+{
+       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);
+
+       // Page Tables have been setup, make special handling for PCR and TSS
+       // (which is done in BlSetupFotNt in usual ntldr)
+       HalPageTable[(KI_USER_SHARED_DATA - 0xFFC00000) >> MM_PAGE_SHIFT].PageFrameNumber = PcrBasePage+1;
+       HalPageTable[(KI_USER_SHARED_DATA - 0xFFC00000) >> MM_PAGE_SHIFT].Valid = 1;
+       HalPageTable[(KI_USER_SHARED_DATA - 0xFFC00000) >> MM_PAGE_SHIFT].Write = 1;
+
+       HalPageTable[(KIP0PCRADDRESS - 0xFFC00000) >> MM_PAGE_SHIFT].PageFrameNumber = PcrBasePage;
+       HalPageTable[(KIP0PCRADDRESS - 0xFFC00000) >> MM_PAGE_SHIFT].Valid = 1;
+       HalPageTable[(KIP0PCRADDRESS - 0xFFC00000) >> MM_PAGE_SHIFT].Write = 1;
+
+       // Map APIC
+       WinLdrpMapApic();
+
+       // Map VGA memory
+       //VideoMemoryBase = MmMapIoSpace(0xb8000, 4000, MmNonCached);
+       //DPRINTM(DPRINT_WINDOWS, "VideoMemoryBase: 0x%X\n", VideoMemoryBase);
+
+       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);
+
+#ifdef 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
+
+
+       // Enable paging
+       //BS->ExitBootServices(ImageHandle,MapKey);
+
+       // Disable Interrupts
+       _disable();
+
+       // Re-initalize EFLAGS
+       Ke386EraseFlags();
+
+       // Set the PDBR
+       __writecr3((ULONG_PTR)PDE);
+
+       // 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?
+
+       // Get old values of GDT and IDT
+       Ke386GetGlobalDescriptorTable(GdtDesc);
+       Ke386GetInterruptDescriptorTable(IdtDesc);
+
+       // Save old IDT
+       OldIdt.Base = IdtDesc.Base;
+       OldIdt.Limit = IdtDesc.Limit;
+
+       // Prepare new IDT+GDT
+       GdtDesc.Base  = KSEG0_BASE | (ULONG_PTR)GdtIdt;
+       GdtDesc.Limit = NUM_GDT * sizeof(KGDTENTRY) - 1;
+       IdtDesc.Base  = (ULONG)((PUCHAR)GdtDesc.Base + GdtDesc.Limit + 1);
+       IdtDesc.Limit = NUM_IDT * sizeof(KIDTENTRY) - 1;
+
+       // ========================
+       // Fill all descriptors now
+       // ========================
+
+       pGdt = (PKGDTENTRY)GdtDesc.Base;
+       pIdt = (PKIDTENTRY)IdtDesc.Base;
+
+       //
+       // Code selector (0x8)
+       // Flat 4Gb
+       //
+       pGdt[1].LimitLow                                = 0xFFFF;
+       pGdt[1].BaseLow                                 = 0;
+       pGdt[1].HighWord.Bytes.BaseMid  = 0;
+       pGdt[1].HighWord.Bytes.Flags1   = 0x9A;
+       pGdt[1].HighWord.Bytes.Flags2   = 0xCF;
+       pGdt[1].HighWord.Bytes.BaseHi   = 0;
+
+       //
+       // Data selector (0x10)
+       // Flat 4Gb
+       //
+       pGdt[2].LimitLow                                = 0xFFFF;
+       pGdt[2].BaseLow                                 = 0;
+       pGdt[2].HighWord.Bytes.BaseMid  = 0;
+       pGdt[2].HighWord.Bytes.Flags1   = 0x92;
+       pGdt[2].HighWord.Bytes.Flags2   = 0xCF;
+       pGdt[2].HighWord.Bytes.BaseHi   = 0;
+
+       //
+       // Selector (0x18)
+       // Flat 2Gb
+       //
+       pGdt[3].LimitLow                                = 0xFFFF;
+       pGdt[3].BaseLow                                 = 0;
+       pGdt[3].HighWord.Bytes.BaseMid  = 0;
+       pGdt[3].HighWord.Bytes.Flags1   = 0xFA;
+       pGdt[3].HighWord.Bytes.Flags2   = 0xCF;
+       pGdt[3].HighWord.Bytes.BaseHi   = 0;
+
+       //
+       // Selector (0x20)
+       // Flat 2Gb
+       //
+       pGdt[4].LimitLow                                = 0xFFFF;
+       pGdt[4].BaseLow                                 = 0;
+       pGdt[4].HighWord.Bytes.BaseMid  = 0;
+       pGdt[4].HighWord.Bytes.Flags1   = 0xF2;
+       pGdt[4].HighWord.Bytes.Flags2   = 0xCF;
+       pGdt[4].HighWord.Bytes.BaseHi   = 0;
+
+       //
+       // TSS Selector (0x28)
+       //
+       pGdt[5].LimitLow                                = 0x78-1; //FIXME: Check this
+       pGdt[5].BaseLow = (USHORT)(Tss & 0xffff);
+       pGdt[5].HighWord.Bytes.BaseMid = (UCHAR)((Tss >> 16) & 0xff);
+       pGdt[5].HighWord.Bytes.Flags1   = 0x89;
+       pGdt[5].HighWord.Bytes.Flags2   = 0x00;
+       pGdt[5].HighWord.Bytes.BaseHi  = (UCHAR)((Tss >> 24) & 0xff);
+
+       //
+       // PCR Selector (0x30)
+       //
+       pGdt[6].LimitLow                                = 0x01;
+       pGdt[6].BaseLow  = (USHORT)(Pcr & 0xffff);
+       pGdt[6].HighWord.Bytes.BaseMid = (UCHAR)((Pcr >> 16) & 0xff);
+       pGdt[6].HighWord.Bytes.Flags1   = 0x92;
+       pGdt[6].HighWord.Bytes.Flags2   = 0xC0;
+       pGdt[6].HighWord.Bytes.BaseHi  = (UCHAR)((Pcr >> 24) & 0xff);
+
+       //
+       // Selector (0x38)
+       //
+       pGdt[7].LimitLow                                = 0xFFFF;
+       pGdt[7].BaseLow                                 = 0;
+       pGdt[7].HighWord.Bytes.BaseMid  = 0;
+       pGdt[7].HighWord.Bytes.Flags1   = 0xF3;
+       pGdt[7].HighWord.Bytes.Flags2   = 0x40;
+       pGdt[7].HighWord.Bytes.BaseHi   = 0;
+
+       //
+       // Some BIOS stuff (0x40)
+       //
+       pGdt[8].LimitLow                                = 0xFFFF;
+       pGdt[8].BaseLow                                 = 0x400;
+       pGdt[8].HighWord.Bytes.BaseMid  = 0;
+       pGdt[8].HighWord.Bytes.Flags1   = 0xF2;
+       pGdt[8].HighWord.Bytes.Flags2   = 0x0;
+       pGdt[8].HighWord.Bytes.BaseHi   = 0;
+
+       //
+       // Selector (0x48)
+       //
+       pGdt[9].LimitLow                                = 0;
+       pGdt[9].BaseLow                                 = 0;
+       pGdt[9].HighWord.Bytes.BaseMid  = 0;
+       pGdt[9].HighWord.Bytes.Flags1   = 0;
+       pGdt[9].HighWord.Bytes.Flags2   = 0;
+       pGdt[9].HighWord.Bytes.BaseHi   = 0;
+
+       //
+       // Selector (0x50)
+       //
+       pGdt[10].LimitLow                               = 0xFFFF; //FIXME: Not correct!
+       pGdt[10].BaseLow                                = 0;
+       pGdt[10].HighWord.Bytes.BaseMid = 0x2;
+       pGdt[10].HighWord.Bytes.Flags1  = 0x89;
+       pGdt[10].HighWord.Bytes.Flags2  = 0;
+       pGdt[10].HighWord.Bytes.BaseHi  = 0;
+
+       //
+       // Selector (0x58)
+       //
+       pGdt[11].LimitLow                               = 0xFFFF;
+       pGdt[11].BaseLow                                = 0;
+       pGdt[11].HighWord.Bytes.BaseMid = 0x2;
+       pGdt[11].HighWord.Bytes.Flags1  = 0x9A;
+       pGdt[11].HighWord.Bytes.Flags2  = 0;
+       pGdt[11].HighWord.Bytes.BaseHi  = 0;
+
+       //
+       // Selector (0x60)
+       //
+       pGdt[12].LimitLow                               = 0xFFFF;
+       pGdt[12].BaseLow                                = 0; //FIXME: Maybe not correct, but noone cares
+       pGdt[12].HighWord.Bytes.BaseMid = 0x2;
+       pGdt[12].HighWord.Bytes.Flags1  = 0x92;
+       pGdt[12].HighWord.Bytes.Flags2  = 0;
+       pGdt[12].HighWord.Bytes.BaseHi  = 0;
+
+       //
+       // Video buffer Selector (0x68)
+       //
+       pGdt[13].LimitLow                               = 0x3FFF;
+       pGdt[13].BaseLow                                = 0x8000;
+       pGdt[13].HighWord.Bytes.BaseMid = 0x0B;
+       pGdt[13].HighWord.Bytes.Flags1  = 0x92;
+       pGdt[13].HighWord.Bytes.Flags2  = 0;
+       pGdt[13].HighWord.Bytes.BaseHi  = 0;
+
+       //
+       // Points to GDT (0x70)
+       //
+       pGdt[14].LimitLow                               = NUM_GDT*sizeof(KGDTENTRY) - 1;
+       pGdt[14].BaseLow                                = 0x7000;
+       pGdt[14].HighWord.Bytes.BaseMid = 0xFF;
+       pGdt[14].HighWord.Bytes.Flags1  = 0x92;
+       pGdt[14].HighWord.Bytes.Flags2  = 0;
+       pGdt[14].HighWord.Bytes.BaseHi  = 0xFF;
+
+       //
+       // Some unused descriptors should go here
+       //
+
+       // Copy the old IDT
+       RtlCopyMemory(pIdt, (PVOID)OldIdt.Base, OldIdt.Limit);
+
+       // Mask interrupts
+       //asm("cli\n"); // they are already masked before enabling paged mode
+
+       // Load GDT+IDT
+       Ke386SetGlobalDescriptorTable(GdtDesc);
+       Ke386SetInterruptDescriptorTable(IdtDesc);
+
+       // Jump to proper CS and clear prefetch queue
+       asm("ljmp       $0x08, $mb1\n"
+               "mb1:\n");
+
+       // Set SS selector
+       asm(".intel_syntax noprefix\n");
+               asm("mov ax, 0x10\n"); // DataSelector=0x10
+               asm("mov ss, ax\n");
+       asm(".att_syntax\n");
+
+       // Set DS and ES selectors
+       Ke386SetDs(0x10);
+       Ke386SetEs(0x10); // this is vital for rep stosd
+
+       // LDT = not used ever, thus set to 0
+       Ke386SetLocalDescriptorTable(Ldt);
+
+       // Load TSR
+       Ke386SetTr(0x28);
+
+       // Clear GS
+       asm(".intel_syntax noprefix\n");
+               asm("push 0\n");
+               asm("pop gs\n");
+       asm(".att_syntax\n");
+
+       // Set FS to PCR
+       Ke386SetFs(0x30);
+
+               // Real end of the function, just for information
+               /* do not uncomment!
+               pop edi;
+               pop esi;
+               pop ebx;
+               mov esp, ebp;
+               pop ebp;
+               ret
+               */
+}