Fix a couple of problems with FreeLDR portability.
[reactos.git] / reactos / boot / freeldr / freeldr / windows / winldr.c
index 2ce1cde..0d04ea6 100644 (file)
-/*\r
- *  FreeLoader\r
- *\r
- *  Copyright (C) 1998-2003  Brian Palmer    <brianp@sginet.com>\r
- *  Copyright (C) 2006       Aleksey Bragin  <aleksey@reactos.org>\r
- *\r
- *  This program is free software; you can redistribute it and/or modify\r
- *  it under the terms of the GNU General Public License as published by\r
- *  the Free Software Foundation; either version 2 of the License, or\r
- *  (at your option) any later version.\r
- *\r
- *  This program is distributed in the hope that it will be useful,\r
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
- *  GNU General Public License for more details.\r
- *\r
- *  You should have received a copy of the GNU General Public License\r
- *  along with this program; if not, write to the Free Software\r
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
- */\r
-\r
-#include <freeldr.h>\r
-\r
-#include <ndk/ldrtypes.h>\r
-#include <debug.h>\r
-\r
-//FIXME: Do a better way to retrieve Arc disk information\r
-extern ULONG reactos_disk_count;\r
-extern ARC_DISK_SIGNATURE reactos_arc_disk_info[];\r
-extern char reactos_arc_strings[32][256];\r
-\r
-BOOLEAN\r
-WinLdrCheckForLoadedDll(IN OUT PLOADER_PARAMETER_BLOCK WinLdrBlock,\r
-                        IN PCH DllName,\r
-                        OUT PLDR_DATA_TABLE_ENTRY *LoadedEntry);\r
-\r
-// debug stuff\r
-VOID DumpMemoryAllocMap(VOID);\r
-VOID WinLdrpDumpMemoryDescriptors(PLOADER_PARAMETER_BLOCK LoaderBlock);\r
-VOID WinLdrpDumpBootDriver(PLOADER_PARAMETER_BLOCK LoaderBlock);\r
-VOID WinLdrpDumpArcDisks(PLOADER_PARAMETER_BLOCK LoaderBlock);\r
-\r
-\r
-// Init "phase 0"\r
-VOID\r
-AllocateAndInitLPB(PLOADER_PARAMETER_BLOCK *OutLoaderBlock)\r
-{\r
-       PLOADER_PARAMETER_BLOCK LoaderBlock;\r
-\r
-       /* Allocate and zero-init the LPB */\r
-       LoaderBlock = MmHeapAlloc(sizeof(LOADER_PARAMETER_BLOCK));\r
-       RtlZeroMemory(LoaderBlock, sizeof(LOADER_PARAMETER_BLOCK));\r
-\r
-       /* Init three critical lists, used right away */\r
-       InitializeListHead(&LoaderBlock->LoadOrderListHead);\r
-       InitializeListHead(&LoaderBlock->MemoryDescriptorListHead);\r
-       InitializeListHead(&LoaderBlock->BootDriverListHead);\r
-\r
-       /* Alloc space for NLS (it will be converted to VA in WinLdrLoadNLS) */\r
-       LoaderBlock->NlsData = MmHeapAlloc(sizeof(NLS_DATA_BLOCK));\r
-       if (LoaderBlock->NlsData == NULL)\r
-       {\r
-               UiMessageBox("Failed to allocate memory for NLS table data!");\r
-               return;\r
-       }\r
-       RtlZeroMemory(LoaderBlock->NlsData, sizeof(NLS_DATA_BLOCK));\r
-\r
-       *OutLoaderBlock = LoaderBlock;\r
-}\r
-\r
-// Init "phase 1"\r
-VOID\r
-WinLdrInitializePhase1(PLOADER_PARAMETER_BLOCK LoaderBlock,\r
-                       PCHAR Options,\r
-                       PCHAR SystemPath,\r
-                       WORD VersionToBoot)\r
-{\r
-       /* Examples of correct options and paths */\r
-       //CHAR  Options[] = "/DEBUGPORT=COM1 /BAUDRATE=115200";\r
-       //CHAR  Options[] = "/NODEBUG";\r
-       //CHAR  SystemRoot[] = "\\WINNT\\";\r
-       //CHAR  ArcBoot[] = "multi(0)disk(0)rdisk(0)partition(1)";\r
-\r
-       CHAR    HalPath[] = "\\";\r
-       CHAR    SystemRoot[256];\r
-       CHAR    ArcBoot[256];\r
-       ULONG i, PathSeparator;\r
-       PLOADER_PARAMETER_EXTENSION Extension;\r
-\r
-       LoaderBlock->u.I386.CommonDataArea = NULL; // Force No ABIOS support\r
-\r
-       /* Construct SystemRoot and ArcBoot from SystemPath */\r
-       PathSeparator = strstr(SystemPath, "\\") - SystemPath;\r
-       strncpy(ArcBoot, SystemPath, PathSeparator);\r
-       ArcBoot[PathSeparator] = 0;\r
-       strcpy(SystemRoot, &SystemPath[PathSeparator]);\r
-       strcat(SystemRoot, "\\");\r
-\r
-       DbgPrint((DPRINT_WINDOWS, "ArcBoot: %s\n", ArcBoot));\r
-       DbgPrint((DPRINT_WINDOWS, "SystemRoot: %s\n", SystemRoot));\r
-       DbgPrint((DPRINT_WINDOWS, "Options: %s\n", Options));\r
-\r
-       /* Fill Arc BootDevice */\r
-       LoaderBlock->ArcBootDeviceName = MmHeapAlloc(strlen(ArcBoot)+1);\r
-       strcpy(LoaderBlock->ArcBootDeviceName, ArcBoot);\r
-       LoaderBlock->ArcBootDeviceName = PaToVa(LoaderBlock->ArcBootDeviceName);\r
-\r
-       /* Fill Arc HalDevice, it matches ArcBoot path */\r
-       LoaderBlock->ArcHalDeviceName = MmHeapAlloc(strlen(ArcBoot)+1);\r
-       strcpy(LoaderBlock->ArcHalDeviceName, ArcBoot);\r
-       LoaderBlock->ArcHalDeviceName = PaToVa(LoaderBlock->ArcHalDeviceName);\r
-\r
-       /* Fill SystemRoot */\r
-       LoaderBlock->NtBootPathName = MmHeapAlloc(strlen(SystemRoot)+1);\r
-       strcpy(LoaderBlock->NtBootPathName, SystemRoot);\r
-       LoaderBlock->NtBootPathName = PaToVa(LoaderBlock->NtBootPathName);\r
-\r
-       /* Fill NtHalPathName */\r
-       LoaderBlock->NtHalPathName = MmHeapAlloc(strlen(HalPath)+1);\r
-       strcpy(LoaderBlock->NtHalPathName, HalPath);\r
-       LoaderBlock->NtHalPathName = PaToVa(LoaderBlock->NtHalPathName);\r
-\r
-       /* Fill load options */\r
-       LoaderBlock->LoadOptions = MmHeapAlloc(strlen(Options)+1);\r
-       strcpy(LoaderBlock->LoadOptions, Options);\r
-       LoaderBlock->LoadOptions = PaToVa(LoaderBlock->LoadOptions);\r
-\r
-       /* Arc devices */\r
-       LoaderBlock->ArcDiskInformation = (PARC_DISK_INFORMATION)MmHeapAlloc(sizeof(ARC_DISK_INFORMATION));\r
-       InitializeListHead(&LoaderBlock->ArcDiskInformation->DiskSignatureListHead);\r
-\r
-       /* Convert ARC disk information from freeldr to a correct format */\r
-       for (i = 0; i < reactos_disk_count; i++)\r
-       {\r
-               PARC_DISK_SIGNATURE ArcDiskInfo;\r
-\r
-               /* Get the ARC structure */\r
-               ArcDiskInfo = (PARC_DISK_SIGNATURE)MmHeapAlloc(sizeof(ARC_DISK_SIGNATURE));\r
-               RtlZeroMemory(ArcDiskInfo, sizeof(ARC_DISK_SIGNATURE));\r
-\r
-               /* Copy the data over */\r
-               ArcDiskInfo->Signature = reactos_arc_disk_info[i].Signature;\r
-               ArcDiskInfo->CheckSum = reactos_arc_disk_info[i].CheckSum;\r
-\r
-               /* Copy the ARC Name */\r
-               ArcDiskInfo->ArcName = (PCHAR)MmHeapAlloc(sizeof(CHAR)*256);\r
-               strcpy(ArcDiskInfo->ArcName, reactos_arc_disk_info[i].ArcName);\r
-               ArcDiskInfo->ArcName = (PCHAR)PaToVa(ArcDiskInfo->ArcName);\r
-\r
-               /* Mark partition table as valid */\r
-               ArcDiskInfo->ValidPartitionTable = TRUE; \r
-\r
-               /* Insert into the list */\r
-               InsertTailList(&LoaderBlock->ArcDiskInformation->DiskSignatureListHead,\r
-                       &ArcDiskInfo->ListEntry);\r
-       }\r
-\r
-       /* Convert all list's to Virtual address */\r
-\r
-       /* Convert the ArcDisks list to virtual address */\r
-       List_PaToVa(&LoaderBlock->ArcDiskInformation->DiskSignatureListHead);\r
-       LoaderBlock->ArcDiskInformation = PaToVa(LoaderBlock->ArcDiskInformation);\r
-\r
-       /* Convert configuration entries to VA */\r
-       ConvertConfigToVA(LoaderBlock->ConfigurationRoot);\r
-       LoaderBlock->ConfigurationRoot = PaToVa(LoaderBlock->ConfigurationRoot);\r
-\r
-       /* Convert all DTE into virtual addresses */\r
-       List_PaToVa(&LoaderBlock->LoadOrderListHead);\r
-\r
-       /* this one will be converted right before switching to\r
-          virtual paging mode */\r
-       //List_PaToVa(&LoaderBlock->MemoryDescriptorListHead);\r
-\r
-       /* Convert list of boot drivers */\r
-       List_PaToVa(&LoaderBlock->BootDriverListHead);\r
-\r
-       /* Initialize Extension now */\r
-       Extension = MmHeapAlloc(sizeof(LOADER_PARAMETER_EXTENSION));\r
-       if (Extension == NULL)\r
-       {\r
-               UiMessageBox("Failed to allocate LPB Extension!");\r
-               return;\r
-       }\r
-       RtlZeroMemory(Extension, sizeof(LOADER_PARAMETER_EXTENSION));\r
-\r
-       /* Save size and version information */\r
-       Extension->Size = sizeof(LOADER_PARAMETER_EXTENSION);\r
-       Extension->MajorVersion = (VersionToBoot & 0xFF00) >> 8;\r
-       Extension->MinorVersion = VersionToBoot & 0xFF;\r
-\r
-\r
-       LoaderBlock->Extension = PaToVa(Extension);\r
-}\r
-\r
-// Last step before going virtual\r
-void WinLdrSetupForNt(PLOADER_PARAMETER_BLOCK LoaderBlock,\r
-                      PVOID *GdtIdt,\r
-                      ULONG *PcrBasePage,\r
-                      ULONG *TssBasePage)\r
-{\r
-       ULONG TssSize;\r
-       ULONG TssPages;\r
-       ULONG_PTR Pcr = 0;\r
-       ULONG_PTR Tss = 0;\r
-       ULONG BlockSize, NumPages;\r
-\r
-       LoaderBlock->u.I386.CommonDataArea = NULL;//CommonDataArea;\r
-       //LoaderBlock->u.I386.MachineType = MachineType; //FIXME: MachineType?\r
-\r
-       /* Allocate 2 pages for PCR */\r
-       Pcr = (ULONG_PTR)MmAllocateMemoryWithType(2 * MM_PAGE_SIZE, LoaderStartupPcrPage);\r
-       *PcrBasePage = Pcr >> MM_PAGE_SHIFT;\r
-\r
-       if (Pcr == 0)\r
-       {\r
-               UiMessageBox("Can't allocate PCR\n");\r
-               return;\r
-       }\r
-\r
-       /* Allocate TSS */\r
-       TssSize = (sizeof(KTSS) + MM_PAGE_SIZE) & ~(MM_PAGE_SIZE - 1);\r
-       TssPages = TssSize / MM_PAGE_SIZE;\r
-\r
-       Tss = (ULONG_PTR)MmAllocateMemoryWithType(TssSize, LoaderMemoryData);\r
-\r
-       *TssBasePage = Tss >> MM_PAGE_SHIFT;\r
-\r
-       /* Allocate space for new GDT + IDT */\r
-       BlockSize = NUM_GDT*sizeof(KGDTENTRY) + NUM_IDT*sizeof(KIDTENTRY);//FIXME: Use GDT/IDT limits here?\r
-       NumPages = (BlockSize + MM_PAGE_SIZE - 1) >> MM_PAGE_SHIFT;\r
-       *GdtIdt = (PKGDTENTRY)MmAllocateMemoryWithType(NumPages * MM_PAGE_SIZE, LoaderMemoryData);\r
-\r
-       if (*GdtIdt == NULL)\r
-       {\r
-               UiMessageBox("Can't allocate pages for GDT+IDT!\n");\r
-               return;\r
-       }\r
-\r
-       /* Zero newly prepared GDT+IDT */\r
-       RtlZeroMemory(*GdtIdt, NumPages << MM_PAGE_SHIFT);\r
-}\r
-\r
-BOOLEAN\r
-WinLdrLoadDeviceDriver(PLOADER_PARAMETER_BLOCK LoaderBlock,\r
-                       LPSTR BootPath,\r
-                       PUNICODE_STRING FilePath,\r
-                       ULONG Flags,\r
-                       PLDR_DATA_TABLE_ENTRY *DriverDTE)\r
-{\r
-       CHAR FullPath[1024];\r
-       CHAR DriverPath[1024];\r
-       CHAR DllName[1024];\r
-       PCHAR DriverNamePos;\r
-       BOOLEAN Status;\r
-       PVOID DriverBase;\r
-\r
-       // Separate the path to file name and directory path\r
-       sprintf(DriverPath, "%wZ", FilePath);\r
-       DriverNamePos = strrchr(DriverPath, '\\');\r
-       if (DriverNamePos != NULL)\r
-       {\r
-               // Copy the name\r
-               strcpy(DllName, DriverNamePos+1);\r
-\r
-               // Cut out the name from the path\r
-               *(DriverNamePos+1) = 0;\r
-       }\r
-\r
-       DbgPrint((DPRINT_WINDOWS, "DriverPath: %s, DllName: %s, LPB %p\n", DriverPath, DllName, LoaderBlock));\r
-\r
-\r
-       // Check if driver is already loaded\r
-       Status = WinLdrCheckForLoadedDll(LoaderBlock, DllName, DriverDTE);\r
-       if (Status)\r
-       {\r
-               // We've got the pointer to its DTE, just return success\r
-               return TRUE;\r
-       }\r
-\r
-       // It's not loaded, we have to load it\r
-       sprintf(FullPath,"%s%wZ", BootPath, FilePath);\r
-       Status = WinLdrLoadImage(FullPath, LoaderBootDriver, &DriverBase);\r
-       if (!Status)\r
-               return FALSE;\r
-\r
-       // Allocate a DTE for it\r
-       Status = WinLdrAllocateDataTableEntry(LoaderBlock, DllName, DllName, DriverBase, DriverDTE);\r
-       if (!Status)\r
-       {\r
-               DbgPrint((DPRINT_WINDOWS, "WinLdrAllocateDataTableEntry() failed\n"));\r
-               return FALSE;\r
-       }\r
-\r
-       // Modify any flags, if needed\r
-       (*DriverDTE)->Flags |= Flags;\r
-\r
-       // Look for any dependencies it may have, and load them too\r
-       sprintf(FullPath,"%s%s", BootPath, DriverPath);\r
-       Status = WinLdrScanImportDescriptorTable(LoaderBlock, FullPath, *DriverDTE);\r
-       if (!Status)\r
-       {\r
-               DbgPrint((DPRINT_WINDOWS, "WinLdrScanImportDescriptorTable() failed for %s\n",\r
-                       FullPath));\r
-               return FALSE;\r
-       }\r
-\r
-       return TRUE;\r
-}\r
-\r
-BOOLEAN\r
-WinLdrLoadBootDrivers(PLOADER_PARAMETER_BLOCK LoaderBlock,\r
-                      LPSTR BootPath)\r
-{\r
-       PLIST_ENTRY NextBd;\r
-       PBOOT_DRIVER_LIST_ENTRY BootDriver;\r
-       BOOLEAN Status;\r
-\r
-       // Walk through the boot drivers list\r
-       NextBd = LoaderBlock->BootDriverListHead.Flink;\r
-\r
-       while (NextBd != &LoaderBlock->BootDriverListHead)\r
-       {\r
-               BootDriver = CONTAINING_RECORD(NextBd, BOOT_DRIVER_LIST_ENTRY, ListEntry);\r
-\r
-               DbgPrint((DPRINT_WINDOWS, "BootDriver %wZ DTE %08X RegPath: %wZ\n", &BootDriver->FilePath,\r
-                       BootDriver->DataTableEntry, &BootDriver->RegistryPath));\r
-\r
-               // Paths are relative (FIXME: Are they always relative?)\r
-\r
-               // Load it\r
-               Status = WinLdrLoadDeviceDriver(LoaderBlock, BootPath, &BootDriver->FilePath,\r
-                       0, &BootDriver->DataTableEntry);\r
-\r
-               // If loading failed - cry loudly\r
-               //FIXME: Maybe remove it from the list and try to continue?\r
-               if (!Status)\r
-               {\r
-                       UiMessageBox("Can't load boot driver!");\r
-                       return FALSE;\r
-               }\r
-\r
-               // Convert the RegistryPath and DTE addresses to VA since we are not going to use it anymore\r
-               BootDriver->RegistryPath.Buffer = PaToVa(BootDriver->RegistryPath.Buffer);\r
-               BootDriver->DataTableEntry = PaToVa(BootDriver->DataTableEntry);\r
-\r
-               NextBd = BootDriver->ListEntry.Flink;\r
-       }\r
-\r
-       return TRUE;\r
-}\r
-\r
-VOID\r
-LoadAndBootWindows(PCSTR OperatingSystemName, WORD OperatingSystemVersion)\r
-{\r
-       CHAR  MsgBuffer[256];\r
-       CHAR  SystemPath[512], SearchPath[512];\r
-       CHAR  FileName[512];\r
-       CHAR  BootPath[512];\r
-       CHAR  BootOptions[256];\r
-       PVOID NtosBase = NULL, HalBase = NULL, KdComBase = NULL;\r
-       BOOLEAN Status;\r
-       ULONG SectionId;\r
-       ULONG BootDevice;\r
-       PLOADER_PARAMETER_BLOCK LoaderBlock, LoaderBlockVA;\r
-       KERNEL_ENTRY_POINT KiSystemStartup;\r
-       PLDR_DATA_TABLE_ENTRY KernelDTE, HalDTE, KdComDTE = NULL;\r
-       // Mm-related things\r
-       PVOID GdtIdt;\r
-       ULONG PcrBasePage=0;\r
-       ULONG TssBasePage=0;\r
-\r
-       //sprintf(MsgBuffer,"Booting Microsoft(R) Windows(R) OS version '%04x' is not implemented yet", OperatingSystemVersion);\r
-       //UiMessageBox(MsgBuffer);\r
-\r
-       // Open the operating system section\r
-       // specified in the .ini file\r
-       if (!IniOpenSection(OperatingSystemName, &SectionId))\r
-       {\r
-               sprintf(MsgBuffer,"Operating System section '%s' not found in freeldr.ini", OperatingSystemName);\r
-               UiMessageBox(MsgBuffer);\r
-               return;\r
-       }\r
-\r
-       UiDrawBackdrop();\r
-       UiDrawStatusText("Detecting Hardware...");\r
-       UiDrawProgressBarCenter(1, 100, "Loading Windows...");\r
-\r
-       /* Make sure the system path is set in the .ini file */\r
-       if (!IniReadSettingByName(SectionId, "SystemPath", SystemPath, sizeof(SystemPath)))\r
-       {\r
-               UiMessageBox("System path not specified for selected operating system.");\r
-               return;\r
-       }\r
-\r
-       /* Read booting options */\r
-       if (!IniReadSettingByName(SectionId, "Options", BootOptions, sizeof(BootOptions)))\r
-       {\r
-               /* Nothing read, make the string empty */\r
-               strcpy(BootOptions, "");\r
-       }\r
-\r
-       /* Normalize system path */\r
-       if (!MachDiskNormalizeSystemPath(SystemPath, sizeof(SystemPath)))\r
-       {\r
-               UiMessageBox("Invalid system path");\r
-               return;\r
-       }\r
-\r
-       /* Let user know we started loading */\r
-       UiDrawStatusText("Loading...");\r
-\r
-       /* Try to open system drive */\r
-       BootDevice = 0xffffffff;\r
-       if (!FsOpenSystemVolume(SystemPath, BootPath, &BootDevice))\r
-       {\r
-               UiMessageBox("Failed to open boot drive.");\r
-               return;\r
-       }\r
-\r
-       /* append a backslash */\r
-       if ((strlen(BootPath)==0) ||\r
-           BootPath[strlen(BootPath)] != '\\')\r
-               strcat(BootPath, "\\");\r
-\r
-       DbgPrint((DPRINT_WINDOWS,"SystemRoot: '%s'\n", BootPath));\r
-\r
-       /* Allocate and minimalistic-initialize LPB */\r
-       AllocateAndInitLPB(&LoaderBlock);\r
-\r
-       /* Detect hardware */\r
-       LoaderBlock->ConfigurationRoot = MachHwDetect();\r
-\r
-       /* Load kernel */\r
-       strcpy(FileName, BootPath);\r
-       strcat(FileName, "SYSTEM32\\NTOSKRNL.EXE");\r
-       Status = WinLdrLoadImage(FileName, LoaderSystemCode, &NtosBase);\r
-       DbgPrint((DPRINT_WINDOWS, "Ntos loaded with status %d at %p\n", Status, NtosBase));\r
-\r
-       /* Load HAL */\r
-       strcpy(FileName, BootPath);\r
-       strcat(FileName, "SYSTEM32\\HAL.DLL");\r
-       Status = WinLdrLoadImage(FileName, LoaderHalCode, &HalBase);\r
-       DbgPrint((DPRINT_WINDOWS, "HAL loaded with status %d at %p\n", Status, HalBase));\r
-\r
-       /* Load kernel-debugger support dll */\r
-       if (OperatingSystemVersion > _WIN32_WINNT_WIN2K)\r
-       {\r
-               strcpy(FileName, BootPath);\r
-               strcat(FileName, "SYSTEM32\\KDCOM.DLL");\r
-               Status = WinLdrLoadImage(FileName, LoaderBootDriver, &KdComBase);\r
-               DbgPrint((DPRINT_WINDOWS, "KdCom loaded with status %d at %p\n", Status, KdComBase));\r
-       }\r
-\r
-       /* Allocate data table entries for above-loaded modules */\r
-       WinLdrAllocateDataTableEntry(LoaderBlock, "ntoskrnl.exe",\r
-               "WINNT\\SYSTEM32\\NTOSKRNL.EXE", NtosBase, &KernelDTE);\r
-       WinLdrAllocateDataTableEntry(LoaderBlock, "hal.dll",\r
-               "WINNT\\SYSTEM32\\HAL.DLL", HalBase, &HalDTE);\r
-       if (OperatingSystemVersion > _WIN32_WINNT_WIN2K)\r
-       {\r
-               WinLdrAllocateDataTableEntry(LoaderBlock, "kdcom.dll",\r
-                       "WINNT\\SYSTEM32\\KDCOM.DLL", KdComBase, &KdComDTE);\r
-       }\r
-\r
-       /* Load all referenced DLLs for kernel, HAL and kdcom.dll */\r
-       strcpy(SearchPath, BootPath);\r
-       strcat(SearchPath, "SYSTEM32\\");\r
-       WinLdrScanImportDescriptorTable(LoaderBlock, SearchPath, KernelDTE);\r
-       WinLdrScanImportDescriptorTable(LoaderBlock, SearchPath, HalDTE);\r
-       if (KdComDTE)\r
-               WinLdrScanImportDescriptorTable(LoaderBlock, SearchPath, KdComDTE);\r
-\r
-       /* Load Hive, and then NLS data, OEM font, and prepare boot drivers list */\r
-       Status = WinLdrLoadAndScanSystemHive(LoaderBlock, BootPath);\r
-       DbgPrint((DPRINT_WINDOWS, "SYSTEM hive loaded and scanned with status %d\n", Status));\r
-\r
-       /* Load boot drivers */\r
-       Status = WinLdrLoadBootDrivers(LoaderBlock, BootPath);\r
-       DbgPrint((DPRINT_WINDOWS, "Boot drivers loaded with status %d\n", Status));\r
-\r
-       /* Initialize Phase 1 - no drivers loading anymore */\r
-       WinLdrInitializePhase1(LoaderBlock, BootOptions, SystemPath, OperatingSystemVersion);\r
-\r
-       /* Alloc PCR, TSS, do magic things with the GDT/IDT */\r
-       WinLdrSetupForNt(LoaderBlock, &GdtIdt, &PcrBasePage, &TssBasePage);\r
-\r
-       /* Save entry-point pointer and Loader block VAs */\r
-       KiSystemStartup = (KERNEL_ENTRY_POINT)KernelDTE->EntryPoint;\r
-       LoaderBlockVA = PaToVa(LoaderBlock);\r
-\r
-       /* "Stop all motors", change videomode */\r
-       DiskStopFloppyMotor();\r
-       if (OperatingSystemVersion < _WIN32_WINNT_WIN2K)\r
-               MachVideoPrepareForReactOS(TRUE);\r
-       else\r
-               MachVideoPrepareForReactOS(FALSE);\r
-\r
-       /* Debugging... */\r
-       //DumpMemoryAllocMap();\r
-\r
-       /* Turn on paging mode of CPU*/\r
-       WinLdrTurnOnPaging(LoaderBlock, PcrBasePage, TssBasePage, GdtIdt);\r
-\r
-       DbgPrint((DPRINT_WINDOWS, "Hello from paged mode, KiSystemStartup %p, LoaderBlockVA %p!\n",\r
-               KiSystemStartup, LoaderBlockVA));\r
-\r
-       WinLdrpDumpMemoryDescriptors(LoaderBlockVA);\r
-       WinLdrpDumpBootDriver(LoaderBlockVA);\r
-       WinLdrpDumpArcDisks(LoaderBlockVA);\r
-\r
-       //FIXME: If I substitute this debugging checkpoint, GCC will "optimize away" the code below\r
-       //while (1) {};\r
-       /*asm(".intel_syntax noprefix\n");\r
-               asm("test1:\n");\r
-               asm("jmp test1\n");\r
-       asm(".att_syntax\n");*/\r
-\r
-       /* Pass control */\r
-       (*KiSystemStartup)(LoaderBlockVA);\r
-\r
-       return;\r
-}\r
-\r
-VOID\r
-WinLdrpDumpMemoryDescriptors(PLOADER_PARAMETER_BLOCK LoaderBlock)\r
-{\r
-       PLIST_ENTRY NextMd;\r
-       PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor;\r
-\r
-       NextMd = LoaderBlock->MemoryDescriptorListHead.Flink;\r
-\r
-       while (NextMd != &LoaderBlock->MemoryDescriptorListHead)\r
-       {\r
-               MemoryDescriptor = CONTAINING_RECORD(NextMd, MEMORY_ALLOCATION_DESCRIPTOR, ListEntry);\r
-\r
-               DbgPrint((DPRINT_WINDOWS, "BP %08X PC %04X MT %d\n", MemoryDescriptor->BasePage,\r
-                       MemoryDescriptor->PageCount, MemoryDescriptor->MemoryType));\r
-\r
-               NextMd = MemoryDescriptor->ListEntry.Flink;\r
-       }\r
-}\r
-\r
-VOID\r
-WinLdrpDumpBootDriver(PLOADER_PARAMETER_BLOCK LoaderBlock)\r
-{\r
-       PLIST_ENTRY NextBd;\r
-       PBOOT_DRIVER_LIST_ENTRY BootDriver;\r
-\r
-       NextBd = LoaderBlock->BootDriverListHead.Flink;\r
-\r
-       while (NextBd != &LoaderBlock->BootDriverListHead)\r
-       {\r
-               BootDriver = CONTAINING_RECORD(NextBd, BOOT_DRIVER_LIST_ENTRY, ListEntry);\r
-\r
-               DbgPrint((DPRINT_WINDOWS, "BootDriver %wZ DTE %08X RegPath: %wZ\n", &BootDriver->FilePath,\r
-                       BootDriver->DataTableEntry, &BootDriver->RegistryPath));\r
-\r
-               NextBd = BootDriver->ListEntry.Flink;\r
-       }\r
-}\r
-\r
-VOID\r
-WinLdrpDumpArcDisks(PLOADER_PARAMETER_BLOCK LoaderBlock)\r
-{\r
-       PLIST_ENTRY NextBd;\r
-       PARC_DISK_SIGNATURE ArcDisk;\r
-\r
-       NextBd = LoaderBlock->ArcDiskInformation->DiskSignatureListHead.Flink;\r
-\r
-       while (NextBd != &LoaderBlock->ArcDiskInformation->DiskSignatureListHead)\r
-       {\r
-               ArcDisk = CONTAINING_RECORD(NextBd, ARC_DISK_SIGNATURE, ListEntry);\r
-\r
-               DbgPrint((DPRINT_WINDOWS, "ArcDisk %s checksum: 0x%X, signature: 0x%X\n",\r
-                       ArcDisk->ArcName, ArcDisk->CheckSum, ArcDisk->Signature));\r
-\r
-               NextBd = ArcDisk->ListEntry.Flink;\r
-       }\r
-}\r
-\r
+/*
+ *  FreeLoader
+ *
+ *  Copyright (C) 1998-2003  Brian Palmer    <brianp@sginet.com>
+ *  Copyright (C) 2006       Aleksey Bragin  <aleksey@reactos.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <freeldr.h>
+
+#include <ndk/ldrtypes.h>
+#include <debug.h>
+
+//FIXME: Do a better way to retrieve Arc disk information
+extern ULONG reactos_disk_count;
+extern ARC_DISK_SIGNATURE reactos_arc_disk_info[];
+extern char reactos_arc_strings[32][256];
+
+extern BOOLEAN UseRealHeap;
+extern ULONG LoaderPagesSpanned;
+
+BOOLEAN
+WinLdrCheckForLoadedDll(IN OUT PLOADER_PARAMETER_BLOCK WinLdrBlock,
+                        IN PCH DllName,
+                        OUT PLDR_DATA_TABLE_ENTRY *LoadedEntry);
+
+// debug stuff
+VOID DumpMemoryAllocMap(VOID);
+VOID WinLdrpDumpMemoryDescriptors(PLOADER_PARAMETER_BLOCK LoaderBlock);
+VOID WinLdrpDumpBootDriver(PLOADER_PARAMETER_BLOCK LoaderBlock);
+VOID WinLdrpDumpArcDisks(PLOADER_PARAMETER_BLOCK LoaderBlock);
+
+
+// Init "phase 0"
+VOID
+AllocateAndInitLPB(PLOADER_PARAMETER_BLOCK *OutLoaderBlock)
+{
+       PLOADER_PARAMETER_BLOCK LoaderBlock;
+
+       /* Allocate and zero-init the LPB */
+       LoaderBlock = MmHeapAlloc(sizeof(LOADER_PARAMETER_BLOCK));
+       RtlZeroMemory(LoaderBlock, sizeof(LOADER_PARAMETER_BLOCK));
+
+       /* Init three critical lists, used right away */
+       InitializeListHead(&LoaderBlock->LoadOrderListHead);
+       InitializeListHead(&LoaderBlock->MemoryDescriptorListHead);
+       InitializeListHead(&LoaderBlock->BootDriverListHead);
+
+       /* Alloc space for NLS (it will be converted to VA in WinLdrLoadNLS) */
+       LoaderBlock->NlsData = MmHeapAlloc(sizeof(NLS_DATA_BLOCK));
+       if (LoaderBlock->NlsData == NULL)
+       {
+               UiMessageBox("Failed to allocate memory for NLS table data!");
+               return;
+       }
+       RtlZeroMemory(LoaderBlock->NlsData, sizeof(NLS_DATA_BLOCK));
+
+       *OutLoaderBlock = LoaderBlock;
+}
+
+// Init "phase 1"
+VOID
+WinLdrInitializePhase1(PLOADER_PARAMETER_BLOCK LoaderBlock,
+                       PCHAR Options,
+                       PCHAR SystemPath,
+                       WORD VersionToBoot)
+{
+       /* Examples of correct options and paths */
+       //CHAR  Options[] = "/DEBUGPORT=COM1 /BAUDRATE=115200";
+       //CHAR  Options[] = "/NODEBUG";
+       //CHAR  SystemRoot[] = "\\WINNT\\";
+       //CHAR  ArcBoot[] = "multi(0)disk(0)rdisk(0)partition(1)";
+
+       CHAR    HalPath[] = "\\";
+       CHAR    SystemRoot[256];
+       CHAR    ArcBoot[256];
+       ULONG i, PathSeparator;
+       PLOADER_PARAMETER_EXTENSION Extension;
+
+       LoaderBlock->u.I386.CommonDataArea = NULL; // Force No ABIOS support
+
+       /* Construct SystemRoot and ArcBoot from SystemPath */
+       PathSeparator = strstr(SystemPath, "\\") - SystemPath;
+       strncpy(ArcBoot, SystemPath, PathSeparator);
+       ArcBoot[PathSeparator] = 0;
+       strcpy(SystemRoot, &SystemPath[PathSeparator]);
+       strcat(SystemRoot, "\\");
+
+       DbgPrint((DPRINT_WINDOWS, "ArcBoot: %s\n", ArcBoot));
+       DbgPrint((DPRINT_WINDOWS, "SystemRoot: %s\n", SystemRoot));
+       DbgPrint((DPRINT_WINDOWS, "Options: %s\n", Options));
+
+       /* Fill Arc BootDevice */
+       LoaderBlock->ArcBootDeviceName = MmHeapAlloc(strlen(ArcBoot)+1);
+       strcpy(LoaderBlock->ArcBootDeviceName, ArcBoot);
+       LoaderBlock->ArcBootDeviceName = PaToVa(LoaderBlock->ArcBootDeviceName);
+
+       /* Fill Arc HalDevice, it matches ArcBoot path */
+       LoaderBlock->ArcHalDeviceName = MmHeapAlloc(strlen(ArcBoot)+1);
+       strcpy(LoaderBlock->ArcHalDeviceName, ArcBoot);
+       LoaderBlock->ArcHalDeviceName = PaToVa(LoaderBlock->ArcHalDeviceName);
+
+       /* Fill SystemRoot */
+       LoaderBlock->NtBootPathName = MmHeapAlloc(strlen(SystemRoot)+1);
+       strcpy(LoaderBlock->NtBootPathName, SystemRoot);
+       LoaderBlock->NtBootPathName = PaToVa(LoaderBlock->NtBootPathName);
+
+       /* Fill NtHalPathName */
+       LoaderBlock->NtHalPathName = MmHeapAlloc(strlen(HalPath)+1);
+       strcpy(LoaderBlock->NtHalPathName, HalPath);
+       LoaderBlock->NtHalPathName = PaToVa(LoaderBlock->NtHalPathName);
+
+       /* Fill load options */
+       LoaderBlock->LoadOptions = MmHeapAlloc(strlen(Options)+1);
+       strcpy(LoaderBlock->LoadOptions, Options);
+       LoaderBlock->LoadOptions = PaToVa(LoaderBlock->LoadOptions);
+
+       /* Arc devices */
+       LoaderBlock->ArcDiskInformation = (PARC_DISK_INFORMATION)MmHeapAlloc(sizeof(ARC_DISK_INFORMATION));
+       InitializeListHead(&LoaderBlock->ArcDiskInformation->DiskSignatureListHead);
+
+       /* Convert ARC disk information from freeldr to a correct format */
+       for (i = 0; i < reactos_disk_count; i++)
+       {
+               PARC_DISK_SIGNATURE ArcDiskInfo;
+
+               /* Get the ARC structure */
+               ArcDiskInfo = (PARC_DISK_SIGNATURE)MmHeapAlloc(sizeof(ARC_DISK_SIGNATURE));
+               RtlZeroMemory(ArcDiskInfo, sizeof(ARC_DISK_SIGNATURE));
+
+               /* Copy the data over */
+               ArcDiskInfo->Signature = reactos_arc_disk_info[i].Signature;
+               ArcDiskInfo->CheckSum = reactos_arc_disk_info[i].CheckSum;
+
+               /* Copy the ARC Name */
+               ArcDiskInfo->ArcName = (PCHAR)MmHeapAlloc(sizeof(CHAR)*256);
+               strcpy(ArcDiskInfo->ArcName, reactos_arc_disk_info[i].ArcName);
+               ArcDiskInfo->ArcName = (PCHAR)PaToVa(ArcDiskInfo->ArcName);
+
+               /* Mark partition table as valid */
+               ArcDiskInfo->ValidPartitionTable = TRUE; 
+
+               /* Insert into the list */
+               InsertTailList(&LoaderBlock->ArcDiskInformation->DiskSignatureListHead,
+                       &ArcDiskInfo->ListEntry);
+       }
+
+       /* Convert all list's to Virtual address */
+
+       /* Convert the ArcDisks list to virtual address */
+       List_PaToVa(&LoaderBlock->ArcDiskInformation->DiskSignatureListHead);
+       LoaderBlock->ArcDiskInformation = PaToVa(LoaderBlock->ArcDiskInformation);
+
+       /* Convert configuration entries to VA */
+       ConvertConfigToVA(LoaderBlock->ConfigurationRoot);
+       LoaderBlock->ConfigurationRoot = PaToVa(LoaderBlock->ConfigurationRoot);
+
+       /* Convert all DTE into virtual addresses */
+       List_PaToVa(&LoaderBlock->LoadOrderListHead);
+
+       /* this one will be converted right before switching to
+          virtual paging mode */
+       //List_PaToVa(&LoaderBlock->MemoryDescriptorListHead);
+
+       /* Convert list of boot drivers */
+       List_PaToVa(&LoaderBlock->BootDriverListHead);
+
+       /* Initialize Extension now */
+       Extension = MmHeapAlloc(sizeof(LOADER_PARAMETER_EXTENSION));
+       if (Extension == NULL)
+       {
+               UiMessageBox("Failed to allocate LPB Extension!");
+               return;
+       }
+       RtlZeroMemory(Extension, sizeof(LOADER_PARAMETER_EXTENSION));
+
+       /* Fill LPB extension */
+       Extension->Size = sizeof(LOADER_PARAMETER_EXTENSION);
+       Extension->MajorVersion = (VersionToBoot & 0xFF00) >> 8;
+       Extension->MinorVersion = VersionToBoot & 0xFF;
+       Extension->Profile.Status = 2;
+
+       LoaderBlock->Extension = PaToVa(Extension);
+}
+
+// Last step before going virtual
+void WinLdrSetupForNt(PLOADER_PARAMETER_BLOCK LoaderBlock,
+                      PVOID *GdtIdt,
+                      ULONG *PcrBasePage,
+                      ULONG *TssBasePage)
+{
+       ULONG TssSize;
+       ULONG TssPages;
+       ULONG_PTR Pcr = 0;
+       ULONG_PTR Tss = 0;
+       ULONG BlockSize, NumPages;
+
+       LoaderBlock->u.I386.CommonDataArea = NULL; //CommonDataArea;
+       LoaderBlock->u.I386.MachineType = 0; // ntldr sets this to 0
+
+       /* Allocate 2 pages for PCR */
+       Pcr = (ULONG_PTR)MmAllocateMemoryWithType(2 * MM_PAGE_SIZE, LoaderStartupPcrPage);
+       *PcrBasePage = Pcr >> MM_PAGE_SHIFT;
+
+       if (Pcr == 0)
+       {
+               UiMessageBox("Can't allocate PCR\n");
+               return;
+       }
+
+       /* Allocate TSS */
+       TssSize = (sizeof(KTSS) + MM_PAGE_SIZE) & ~(MM_PAGE_SIZE - 1);
+       TssPages = TssSize / MM_PAGE_SIZE;
+
+       Tss = (ULONG_PTR)MmAllocateMemoryWithType(TssSize, LoaderMemoryData);
+
+       *TssBasePage = Tss >> MM_PAGE_SHIFT;
+
+       /* Allocate space for new GDT + IDT */
+       BlockSize = NUM_GDT*sizeof(KGDTENTRY) + NUM_IDT*sizeof(KIDTENTRY);//FIXME: Use GDT/IDT limits here?
+       NumPages = (BlockSize + MM_PAGE_SIZE - 1) >> MM_PAGE_SHIFT;
+       *GdtIdt = (PKGDTENTRY)MmAllocateMemoryWithType(NumPages * MM_PAGE_SIZE, LoaderMemoryData);
+
+       if (*GdtIdt == NULL)
+       {
+               UiMessageBox("Can't allocate pages for GDT+IDT!\n");
+               return;
+       }
+
+       /* Zero newly prepared GDT+IDT */
+       RtlZeroMemory(*GdtIdt, NumPages << MM_PAGE_SHIFT);
+}
+
+BOOLEAN
+WinLdrLoadDeviceDriver(PLOADER_PARAMETER_BLOCK LoaderBlock,
+                       LPSTR BootPath,
+                       PUNICODE_STRING FilePath,
+                       ULONG Flags,
+                       PLDR_DATA_TABLE_ENTRY *DriverDTE)
+{
+       CHAR FullPath[1024];
+       CHAR DriverPath[1024];
+       CHAR DllName[1024];
+       PCHAR DriverNamePos;
+       BOOLEAN Status;
+       PVOID DriverBase;
+
+       // Separate the path to file name and directory path
+       sprintf(DriverPath, "%S", FilePath->Buffer);
+       DriverNamePos = strrchr(DriverPath, '\\');
+       if (DriverNamePos != NULL)
+       {
+               // Copy the name
+               strcpy(DllName, DriverNamePos+1);
+
+               // Cut out the name from the path
+               *(DriverNamePos+1) = 0;
+       }
+
+       DbgPrint((DPRINT_WINDOWS, "DriverPath: %s, DllName: %s, LPB %p\n", DriverPath, DllName, LoaderBlock));
+
+
+       // Check if driver is already loaded
+       Status = WinLdrCheckForLoadedDll(LoaderBlock, DllName, DriverDTE);
+       if (Status)
+       {
+               // We've got the pointer to its DTE, just return success
+               return TRUE;
+       }
+
+       // It's not loaded, we have to load it
+       sprintf(FullPath,"%s%S", BootPath, FilePath->Buffer);
+       Status = WinLdrLoadImage(FullPath, LoaderBootDriver, &DriverBase);
+       if (!Status)
+               return FALSE;
+
+       // Allocate a DTE for it
+       Status = WinLdrAllocateDataTableEntry(LoaderBlock, DllName, DllName, DriverBase, DriverDTE);
+       if (!Status)
+       {
+               DbgPrint((DPRINT_WINDOWS, "WinLdrAllocateDataTableEntry() failed\n"));
+               return FALSE;
+       }
+
+       // Modify any flags, if needed
+       (*DriverDTE)->Flags |= Flags;
+
+       // Look for any dependencies it may have, and load them too
+       sprintf(FullPath,"%s%s", BootPath, DriverPath);
+       Status = WinLdrScanImportDescriptorTable(LoaderBlock, FullPath, *DriverDTE);
+       if (!Status)
+       {
+               DbgPrint((DPRINT_WINDOWS, "WinLdrScanImportDescriptorTable() failed for %s\n",
+                       FullPath));
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+BOOLEAN
+WinLdrLoadBootDrivers(PLOADER_PARAMETER_BLOCK LoaderBlock,
+                      LPSTR BootPath)
+{
+       PLIST_ENTRY NextBd;
+       PBOOT_DRIVER_LIST_ENTRY BootDriver;
+       BOOLEAN Status;
+
+       // Walk through the boot drivers list
+       NextBd = LoaderBlock->BootDriverListHead.Flink;
+
+       while (NextBd != &LoaderBlock->BootDriverListHead)
+       {
+               BootDriver = CONTAINING_RECORD(NextBd, BOOT_DRIVER_LIST_ENTRY, ListEntry);
+
+               DbgPrint((DPRINT_WINDOWS, "BootDriver %wZ DTE %08X RegPath: %wZ\n", &BootDriver->FilePath,
+                       BootDriver->DataTableEntry, &BootDriver->RegistryPath));
+
+               // Paths are relative (FIXME: Are they always relative?)
+
+               // Load it
+               Status = WinLdrLoadDeviceDriver(LoaderBlock, BootPath, &BootDriver->FilePath,
+                       0, &BootDriver->DataTableEntry);
+
+               // If loading failed - cry loudly
+               //FIXME: Maybe remove it from the list and try to continue?
+               if (!Status)
+               {
+                       UiMessageBox("Can't load boot driver!");
+                       return FALSE;
+               }
+
+               // Convert the RegistryPath and DTE addresses to VA since we are not going to use it anymore
+               BootDriver->RegistryPath.Buffer = PaToVa(BootDriver->RegistryPath.Buffer);
+               BootDriver->DataTableEntry = PaToVa(BootDriver->DataTableEntry);
+
+               NextBd = BootDriver->ListEntry.Flink;
+       }
+
+       return TRUE;
+}
+
+VOID
+LoadAndBootWindows(PCSTR OperatingSystemName, WORD OperatingSystemVersion)
+{
+       CHAR  MsgBuffer[256];
+       CHAR  SystemPath[512], SearchPath[512];
+       CHAR  FileName[512];
+       CHAR  BootPath[512];
+       CHAR  BootOptions[256];
+       PVOID NtosBase = NULL, HalBase = NULL, KdComBase = NULL;
+       BOOLEAN Status;
+       ULONG SectionId;
+       ULONG BootDevice;
+       PLOADER_PARAMETER_BLOCK LoaderBlock, LoaderBlockVA;
+       KERNEL_ENTRY_POINT KiSystemStartup;
+       PLDR_DATA_TABLE_ENTRY KernelDTE, HalDTE, KdComDTE = NULL;
+       // Mm-related things
+       PVOID GdtIdt;
+       ULONG PcrBasePage=0;
+       ULONG TssBasePage=0;
+
+       //sprintf(MsgBuffer,"Booting Microsoft(R) Windows(R) OS version '%04x' is not implemented yet", OperatingSystemVersion);
+       //UiMessageBox(MsgBuffer);
+
+       // Open the operating system section
+       // specified in the .ini file
+       if (!IniOpenSection(OperatingSystemName, &SectionId))
+       {
+               sprintf(MsgBuffer,"Operating System section '%s' not found in freeldr.ini", OperatingSystemName);
+               UiMessageBox(MsgBuffer);
+               return;
+       }
+
+       UiDrawBackdrop();
+       UiDrawStatusText("Detecting Hardware...");
+       UiDrawProgressBarCenter(1, 100, "Loading Windows...");
+
+       /* Make sure the system path is set in the .ini file */
+       if (!IniReadSettingByName(SectionId, "SystemPath", SystemPath, sizeof(SystemPath)))
+       {
+               UiMessageBox("System path not specified for selected operating system.");
+               return;
+       }
+
+       /* Read booting options */
+       if (!IniReadSettingByName(SectionId, "Options", BootOptions, sizeof(BootOptions)))
+       {
+               /* Nothing read, make the string empty */
+               strcpy(BootOptions, "");
+       }
+
+       /* Normalize system path */
+       if (!MachDiskNormalizeSystemPath(SystemPath, sizeof(SystemPath)))
+       {
+               UiMessageBox("Invalid system path");
+               return;
+       }
+
+       /* Let user know we started loading */
+       UiDrawStatusText("Loading...");
+
+       /* Try to open system drive */
+       BootDevice = 0xffffffff;
+       if (!FsOpenSystemVolume(SystemPath, BootPath, &BootDevice))
+       {
+               UiMessageBox("Failed to open boot drive.");
+               return;
+       }
+
+       /* append a backslash */
+       if ((strlen(BootPath)==0) ||
+           BootPath[strlen(BootPath)] != '\\')
+               strcat(BootPath, "\\");
+
+       DbgPrint((DPRINT_WINDOWS,"SystemRoot: '%s'\n", BootPath));
+
+       /* Allocate and minimalistic-initialize LPB */
+       AllocateAndInitLPB(&LoaderBlock);
+
+       /* Detect hardware */
+       UseRealHeap = TRUE;
+       LoaderBlock->ConfigurationRoot = MachHwDetect();
+
+       /* Load kernel */
+       strcpy(FileName, BootPath);
+       strcat(FileName, "SYSTEM32\\NTOSKRNL.EXE");
+       Status = WinLdrLoadImage(FileName, LoaderSystemCode, &NtosBase);
+       DbgPrint((DPRINT_WINDOWS, "Ntos loaded with status %d at %p\n", Status, NtosBase));
+
+       /* Load HAL */
+       strcpy(FileName, BootPath);
+       strcat(FileName, "SYSTEM32\\HAL.DLL");
+       Status = WinLdrLoadImage(FileName, LoaderHalCode, &HalBase);
+       DbgPrint((DPRINT_WINDOWS, "HAL loaded with status %d at %p\n", Status, HalBase));
+
+       /* Load kernel-debugger support dll */
+       if (OperatingSystemVersion > _WIN32_WINNT_WIN2K)
+       {
+               strcpy(FileName, BootPath);
+               strcat(FileName, "SYSTEM32\\KDCOM.DLL");
+               Status = WinLdrLoadImage(FileName, LoaderBootDriver, &KdComBase);
+               DbgPrint((DPRINT_WINDOWS, "KdCom loaded with status %d at %p\n", Status, KdComBase));
+       }
+
+       /* Allocate data table entries for above-loaded modules */
+       WinLdrAllocateDataTableEntry(LoaderBlock, "ntoskrnl.exe",
+               "WINDOWS\\SYSTEM32\\NTOSKRNL.EXE", NtosBase, &KernelDTE);
+       WinLdrAllocateDataTableEntry(LoaderBlock, "hal.dll",
+               "WINDOWS\\SYSTEM32\\HAL.DLL", HalBase, &HalDTE);
+       if (OperatingSystemVersion > _WIN32_WINNT_WIN2K)
+       {
+               WinLdrAllocateDataTableEntry(LoaderBlock, "kdcom.dll",
+                       "WINDOWS\\SYSTEM32\\KDCOM.DLL", KdComBase, &KdComDTE);
+       }
+
+       /* Load all referenced DLLs for kernel, HAL and kdcom.dll */
+       strcpy(SearchPath, BootPath);
+       strcat(SearchPath, "SYSTEM32\\");
+       WinLdrScanImportDescriptorTable(LoaderBlock, SearchPath, KernelDTE);
+       WinLdrScanImportDescriptorTable(LoaderBlock, SearchPath, HalDTE);
+       if (KdComDTE)
+               WinLdrScanImportDescriptorTable(LoaderBlock, SearchPath, KdComDTE);
+
+       /* Load Hive, and then NLS data, OEM font, and prepare boot drivers list */
+       Status = WinLdrLoadAndScanSystemHive(LoaderBlock, BootPath);
+       DbgPrint((DPRINT_WINDOWS, "SYSTEM hive loaded and scanned with status %d\n", Status));
+
+       /* Load boot drivers */
+       Status = WinLdrLoadBootDrivers(LoaderBlock, BootPath);
+       DbgPrint((DPRINT_WINDOWS, "Boot drivers loaded with status %d\n", Status));
+
+       /* Alloc PCR, TSS, do magic things with the GDT/IDT */
+       WinLdrSetupForNt(LoaderBlock, &GdtIdt, &PcrBasePage, &TssBasePage);
+
+       /* Initialize Phase 1 - no drivers loading anymore */
+       WinLdrInitializePhase1(LoaderBlock, BootOptions, SystemPath, OperatingSystemVersion);
+
+       /* Save entry-point pointer and Loader block VAs */
+       KiSystemStartup = (KERNEL_ENTRY_POINT)KernelDTE->EntryPoint;
+       LoaderBlockVA = PaToVa(LoaderBlock);
+
+       /* "Stop all motors", change videomode */
+       if (OperatingSystemVersion < _WIN32_WINNT_WIN2K)
+               MachPrepareForReactOS(TRUE);
+       else
+               MachPrepareForReactOS(FALSE);
+
+       /* Debugging... */
+       //DumpMemoryAllocMap();
+
+       /* Turn on paging mode of CPU*/
+       WinLdrTurnOnPaging(LoaderBlock, PcrBasePage, TssBasePage, GdtIdt);
+
+       /* Save final value of LoaderPagesSpanned */
+       LoaderBlock->Extension->LoaderPagesSpanned = LoaderPagesSpanned;
+
+       DbgPrint((DPRINT_WINDOWS, "Hello from paged mode, KiSystemStartup %p, LoaderBlockVA %p!\n",
+               KiSystemStartup, LoaderBlockVA));
+
+       WinLdrpDumpMemoryDescriptors(LoaderBlockVA);
+       WinLdrpDumpBootDriver(LoaderBlockVA);
+       WinLdrpDumpArcDisks(LoaderBlockVA);
+
+       //FIXME: If I substitute this debugging checkpoint, GCC will "optimize away" the code below
+       //while (1) {};
+       /*asm(".intel_syntax noprefix\n");
+               asm("test1:\n");
+               asm("jmp test1\n");
+       asm(".att_syntax\n");*/
+
+       /* Pass control */
+       (*KiSystemStartup)(LoaderBlockVA);
+
+       return;
+}
+
+VOID
+WinLdrpDumpMemoryDescriptors(PLOADER_PARAMETER_BLOCK LoaderBlock)
+{
+       PLIST_ENTRY NextMd;
+       PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor;
+
+       NextMd = LoaderBlock->MemoryDescriptorListHead.Flink;
+
+       while (NextMd != &LoaderBlock->MemoryDescriptorListHead)
+       {
+               MemoryDescriptor = CONTAINING_RECORD(NextMd, MEMORY_ALLOCATION_DESCRIPTOR, ListEntry);
+
+               DbgPrint((DPRINT_WINDOWS, "BP %08X PC %04X MT %d\n", MemoryDescriptor->BasePage,
+                       MemoryDescriptor->PageCount, MemoryDescriptor->MemoryType));
+
+               NextMd = MemoryDescriptor->ListEntry.Flink;
+       }
+}
+
+VOID
+WinLdrpDumpBootDriver(PLOADER_PARAMETER_BLOCK LoaderBlock)
+{
+       PLIST_ENTRY NextBd;
+       PBOOT_DRIVER_LIST_ENTRY BootDriver;
+
+       NextBd = LoaderBlock->BootDriverListHead.Flink;
+
+       while (NextBd != &LoaderBlock->BootDriverListHead)
+       {
+               BootDriver = CONTAINING_RECORD(NextBd, BOOT_DRIVER_LIST_ENTRY, ListEntry);
+
+               DbgPrint((DPRINT_WINDOWS, "BootDriver %wZ DTE %08X RegPath: %wZ\n", &BootDriver->FilePath,
+                       BootDriver->DataTableEntry, &BootDriver->RegistryPath));
+
+               NextBd = BootDriver->ListEntry.Flink;
+       }
+}
+
+VOID
+WinLdrpDumpArcDisks(PLOADER_PARAMETER_BLOCK LoaderBlock)
+{
+       PLIST_ENTRY NextBd;
+       PARC_DISK_SIGNATURE ArcDisk;
+
+       NextBd = LoaderBlock->ArcDiskInformation->DiskSignatureListHead.Flink;
+
+       while (NextBd != &LoaderBlock->ArcDiskInformation->DiskSignatureListHead)
+       {
+               ArcDisk = CONTAINING_RECORD(NextBd, ARC_DISK_SIGNATURE, ListEntry);
+
+               DbgPrint((DPRINT_WINDOWS, "ArcDisk %s checksum: 0x%X, signature: 0x%X\n",
+                       ArcDisk->ArcName, ArcDisk->CheckSum, ArcDisk->Signature));
+
+               NextBd = ArcDisk->ListEntry.Flink;
+       }
+}
+
+