[freeldr] Never suppose that buffer in UNICODE_STRING is null terminated. Fixes some...
[reactos.git] / reactos / boot / freeldr / freeldr / windows / winldr.c
index ad2b9ce..f3f7cd1 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
-extern BOOLEAN UseRealHeap;\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
-       Extension->LoaderPagesSpanned = LOADER_HIGH_ZONE;\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
-       UseRealHeap = TRUE;\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
-               "WINDOWS\\SYSTEM32\\NTOSKRNL.EXE", NtosBase, &KernelDTE);\r
-       WinLdrAllocateDataTableEntry(LoaderBlock, "hal.dll",\r
-               "WINDOWS\\SYSTEM32\\HAL.DLL", HalBase, &HalDTE);\r
-       if (OperatingSystemVersion > _WIN32_WINNT_WIN2K)\r
-       {\r
-               WinLdrAllocateDataTableEntry(LoaderBlock, "kdcom.dll",\r
-                       "WINDOWS\\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.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <freeldr.h>
+
+#include <ndk/ldrtypes.h>
+#include <debug.h>
+
+// TODO: Move to .h
+void WinLdrSetupForNt(PLOADER_PARAMETER_BLOCK LoaderBlock,
+                      PVOID *GdtIdt,
+                      ULONG *PcrBasePage,
+                      ULONG *TssBasePage);
+
+//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;
+extern BOOLEAN AcpiPresent;
+
+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 SystemRoot,
+                       PCHAR BootPath,
+                       USHORT 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    ArcBoot[256];
+       CHAR    MiscFiles[256];
+       ULONG i, PathSeparator;
+       PLOADER_PARAMETER_EXTENSION Extension;
+
+       /* Construct SystemRoot and ArcBoot from SystemPath */
+       PathSeparator = strstr(BootPath, "\\") - BootPath;
+       strncpy(ArcBoot, BootPath, PathSeparator);
+       ArcBoot[PathSeparator] = 0;
+
+       DPRINTM(DPRINT_WINDOWS, "ArcBoot: %s\n", ArcBoot);
+       DPRINTM(DPRINT_WINDOWS, "SystemRoot: %s\n", SystemRoot);
+       DPRINTM(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;
+
+       /* Check if ACPI is present */
+       if (AcpiPresent)
+       {
+               /* See KiRosFrldrLpbToNtLpb for details */
+               Extension->AcpiTable = (PVOID)1;
+       }
+
+       /* Load drivers database */
+       strcpy(MiscFiles, BootPath);
+       strcat(MiscFiles, "AppPatch\\drvmain.sdb");
+       Extension->DrvDBImage = PaToVa(WinLdrLoadModule(MiscFiles,
+               &Extension->DrvDBSize, LoaderRegistryData));
+
+       /* Convert extension and setup block pointers */
+       LoaderBlock->Extension = PaToVa(Extension);
+
+       if (LoaderBlock->SetupLdrBlock)
+               LoaderBlock->SetupLdrBlock = PaToVa(LoaderBlock->SetupLdrBlock);
+}
+
+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
+       snprintf(DriverPath, sizeof(DriverPath), "%wZ", FilePath);
+       DriverNamePos = strrchr(DriverPath, '\\');
+       if (DriverNamePos != NULL)
+       {
+               // Copy the name
+               strcpy(DllName, DriverNamePos+1);
+
+               // Cut out the name from the path
+               *(DriverNamePos+1) = 0;
+       }
+       else
+       {
+               // There is no directory in the path
+               strcpy(DllName, DriverPath);
+               DriverPath[0] = 0;
+       }
+
+       DPRINTM(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
+       snprintf(FullPath, sizeof(FullPath), "%s%wZ", BootPath, FilePath);
+       Status = WinLdrLoadImage(FullPath, LoaderBootDriver, &DriverBase);
+       if (!Status)
+               return FALSE;
+
+       // Allocate a DTE for it
+       Status = WinLdrAllocateDataTableEntry(LoaderBlock, DllName, DllName, DriverBase, DriverDTE);
+       if (!Status)
+       {
+               DPRINTM(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)
+       {
+               DPRINTM(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, Link);
+
+               DPRINTM(DPRINT_WINDOWS, "BootDriver %wZ DTE %08X RegPath: %wZ\n", &BootDriver->FilePath,
+                       BootDriver->LdrEntry, &BootDriver->RegistryPath);
+
+               // Paths are relative (FIXME: Are they always relative?)
+
+               // Load it
+               Status = WinLdrLoadDeviceDriver(LoaderBlock, BootPath, &BootDriver->FilePath,
+                       0, &BootDriver->LdrEntry);
+
+               // 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->FilePath.Buffer = PaToVa(BootDriver->FilePath.Buffer);
+               BootDriver->LdrEntry = PaToVa(BootDriver->LdrEntry);
+
+               NextBd = BootDriver->Link.Flink;
+       }
+
+       return TRUE;
+}
+
+PVOID WinLdrLoadModule(PCSTR ModuleName, ULONG *Size,
+                                          TYPE_OF_MEMORY MemoryType)
+{
+       ULONG FileId;
+       PVOID PhysicalBase;
+       FILEINFORMATION FileInfo;
+       ULONG FileSize;
+       ULONG Status;
+       ULONG BytesRead;
+
+       //CHAR ProgressString[256];
+
+       /* Inform user we are loading files */
+       //sprintf(ProgressString, "Loading %s...", FileName);
+       //UiDrawProgressBarCenter(1, 100, ProgressString);
+
+       DPRINTM(DPRINT_WINDOWS, "Loading module %s\n", ModuleName);
+       *Size = 0;
+
+       /* Open the image file */
+       Status = ArcOpen((PCHAR)ModuleName, OpenReadOnly, &FileId);
+       if (Status != ESUCCESS)
+       {
+               /* In case of errors, we just return, without complaining to the user */
+               return NULL;
+       }
+
+       /* Get this file's size */
+       Status = ArcGetFileInformation(FileId, &FileInfo);
+       if (Status != ESUCCESS)
+       {
+               ArcClose(FileId);
+               return NULL;
+       }
+       FileSize = FileInfo.EndingAddress.LowPart;
+       *Size = FileSize;
+
+       /* Allocate memory */
+       PhysicalBase = MmAllocateMemoryWithType(FileSize, MemoryType);
+       if (PhysicalBase == NULL)
+       {
+               ArcClose(FileId);
+               return NULL;
+       }
+
+       /* Load whole file */
+       Status = ArcRead(FileId, PhysicalBase, FileSize, &BytesRead);
+       ArcClose(FileId);
+       if (Status != ESUCCESS)
+       {
+               return NULL;
+       }
+
+       DPRINTM(DPRINT_WINDOWS, "Loaded %s at 0x%x with size 0x%x\n", ModuleName, PhysicalBase, FileSize);
+
+       return PhysicalBase;
+}
+
+
+USHORT
+WinLdrDetectVersion()
+{
+       LONG rc;
+       FRLDRHKEY hKey;
+
+       rc = RegOpenKey(
+               NULL,
+               L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Terminal Server",
+               &hKey);
+       if (rc != ERROR_SUCCESS)
+       {
+               // Key doesn't exist; assume NT 4.0
+               return _WIN32_WINNT_NT4;
+       }
+
+       // We may here want to read the value of ProductVersion
+       return _WIN32_WINNT_WS03;
+}
+
+
+VOID
+LoadAndBootWindows(PCSTR OperatingSystemName,
+                   PSTR SettingsValue,
+                   USHORT OperatingSystemVersion)
+{
+       BOOLEAN HasSection;
+       char  FullPath[MAX_PATH], SystemRoot[MAX_PATH], BootPath[MAX_PATH];
+       CHAR  FileName[MAX_PATH];
+       CHAR  BootOptions[256];
+       PCHAR File;
+       PCHAR PathSeparator;
+       PVOID NtosBase = NULL, HalBase = NULL, KdComBase = NULL;
+       BOOLEAN Status;
+       ULONG_PTR SectionId;
+       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;
+
+       // Open the operating system section
+       // specified in the .ini file
+       HasSection = IniOpenSection(OperatingSystemName, &SectionId);
+
+       UiDrawBackdrop();
+       UiDrawStatusText("Detecting Hardware...");
+       UiDrawProgressBarCenter(1, 100, "Loading NT...");
+
+       /* Read the system path is set in the .ini file */
+       if (!HasSection || !IniReadSettingByName(SectionId, "SystemPath", FullPath, sizeof(FullPath)))
+       {
+               strcpy(FullPath, OperatingSystemName);
+       }
+
+       /* Special case for LiveCD */
+       if (!_strnicmp(FullPath, "LiveCD", strlen("LiveCD")))
+       {
+               strcpy(BootPath, FullPath + strlen("LiveCD"));
+               MachDiskGetBootPath(FullPath, sizeof(FullPath));
+               strcat(FullPath, BootPath);
+       }
+
+       /* Convert FullPath to SystemRoot */
+       PathSeparator = strstr(FullPath, "\\");
+       strcpy(SystemRoot, PathSeparator);
+       strcat(SystemRoot, "\\");
+
+       /* Read booting options */
+       if (!HasSection || !IniReadSettingByName(SectionId, "Options", BootOptions, sizeof(BootOptions)))
+       {
+               /* Get options after the title */
+               const CHAR*p = SettingsValue;
+               while (*p == ' ' || *p == '"')
+                       p++;
+               while (*p != '\0' && *p != '"')
+                       p++;
+               strcpy(BootOptions, p);
+               DPRINTM(DPRINT_WINDOWS,"BootOptions: '%s'\n", BootOptions);
+       }
+
+       //
+       // Check if a ramdisk file was given
+       //
+       File = strstr(BootOptions, "/RDPATH=");
+       if (File)
+       {
+               //
+               // Copy the file name and everything else after it
+               //
+               strcpy(FileName, File + 8);
+
+               //
+               // Null-terminate
+               //
+               *strstr(FileName, " ") = ANSI_NULL;
+
+               //
+               // Load the ramdisk
+               //
+               RamDiskLoadVirtualFile(FileName);
+       }
+
+       /* Let user know we started loading */
+       UiDrawStatusText("Loading...");
+
+       /* append a backslash */
+       strcpy(BootPath, FullPath);
+       if ((strlen(BootPath)==0) ||
+           BootPath[strlen(BootPath)] != '\\')
+               strcat(BootPath, "\\");
+
+       DPRINTM(DPRINT_WINDOWS,"BootPath: '%s'\n", BootPath);
+
+       /* Allocate and minimalistic-initialize LPB */
+       AllocateAndInitLPB(&LoaderBlock);
+
+       /* Detect hardware */
+       UseRealHeap = TRUE;
+       LoaderBlock->ConfigurationRoot = MachHwDetect();
+
+       /* Load Hive */
+       Status = WinLdrInitSystemHive(LoaderBlock, BootPath);
+       DPRINTM(DPRINT_WINDOWS, "SYSTEM hive loaded with status %d\n", Status);
+
+       if (OperatingSystemVersion == 0)
+               OperatingSystemVersion = WinLdrDetectVersion();
+
+       /* Load kernel */
+       strcpy(FileName, BootPath);
+       strcat(FileName, "SYSTEM32\\NTOSKRNL.EXE");
+       Status = WinLdrLoadImage(FileName, LoaderSystemCode, &NtosBase);
+       DPRINTM(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);
+       DPRINTM(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);
+               DPRINTM(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(FileName, BootPath);
+       strcat(FileName, "SYSTEM32\\");
+       WinLdrScanImportDescriptorTable(LoaderBlock, FileName, KernelDTE);
+       WinLdrScanImportDescriptorTable(LoaderBlock, FileName, HalDTE);
+       if (KdComDTE)
+               WinLdrScanImportDescriptorTable(LoaderBlock, FileName, KdComDTE);
+
+       /* Load NLS data, OEM font, and prepare boot drivers list */
+       Status = WinLdrScanSystemHive(LoaderBlock, BootPath);
+       DPRINTM(DPRINT_WINDOWS, "SYSTEM hive scanned with status %d\n", Status);
+
+       /* Load boot drivers */
+       Status = WinLdrLoadBootDrivers(LoaderBlock, BootPath);
+       DPRINTM(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, SystemRoot, BootPath, 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 */
+       LoaderBlockVA->Extension->LoaderPagesSpanned = LoaderPagesSpanned;
+
+       DPRINTM(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);
+
+               DPRINTM(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, Link);
+
+               DPRINTM(DPRINT_WINDOWS, "BootDriver %wZ DTE %08X RegPath: %wZ\n", &BootDriver->FilePath,
+                       BootDriver->LdrEntry, &BootDriver->RegistryPath);
+
+               NextBd = BootDriver->Link.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);
+
+               DPRINTM(DPRINT_WINDOWS, "ArcDisk %s checksum: 0x%X, signature: 0x%X\n",
+                       ArcDisk->ArcName, ArcDisk->CheckSum, ArcDisk->Signature);
+
+               NextBd = ArcDisk->ListEntry.Flink;
+       }
+}
+
+