[FREELDR]
[reactos.git] / boot / freeldr / freeldr / windows / winldr.c
index c068517..f800af2 100644 (file)
 #include <ndk/ldrtypes.h>
 #include <debug.h>
 
-// TODO: Move to .h
-void WinLdrSetupForNt(PLOADER_PARAMETER_BLOCK LoaderBlock,
-                      PVOID *GdtIdt,
-                      ULONG *PcrBasePage,
-                      ULONG *TssBasePage);
+DBG_DEFAULT_CHANNEL(WINDOWS);
 
 //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);
+extern HEADLESS_LOADER_BLOCK LoaderRedirectionInformation;
+extern BOOLEAN WinLdrTerminalConnected;
+extern void WinLdrSetupEms(IN PCHAR BootOptions);
+
+PLOADER_SYSTEM_BLOCK WinLdrSystemBlock;
 
 // 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
@@ -58,32 +49,33 @@ 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));
+       WinLdrSystemBlock = MmAllocateMemoryWithType(sizeof(LOADER_SYSTEM_BLOCK),
+                                                 LoaderSystemBlock);
+       if (WinLdrSystemBlock == NULL)
+       {
+               UiMessageBox("Failed to allocate memory for system block!");
+               return;
+       }
+
+       RtlZeroMemory(WinLdrSystemBlock, sizeof(LOADER_SYSTEM_BLOCK));
+
+    LoaderBlock = &WinLdrSystemBlock->LoaderBlock;
+       LoaderBlock->NlsData = &WinLdrSystemBlock->NlsDataBlock;
 
        /* 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,
+                       LPCSTR Options,
+                       LPCSTR SystemRoot,
+                       LPCSTR BootPath,
                        USHORT VersionToBoot)
 {
        /* Examples of correct options and paths */
@@ -92,10 +84,12 @@ WinLdrInitializePhase1(PLOADER_PARAMETER_BLOCK LoaderBlock,
        //CHAR  SystemRoot[] = "\\WINNT\\";
        //CHAR  ArcBoot[] = "multi(0)disk(0)rdisk(0)partition(1)";
 
-       CHAR    HalPath[] = "\\";
-       CHAR    ArcBoot[256];
-       CHAR    MiscFiles[256];
-       ULONG i, PathSeparator;
+       LPSTR LoadOptions, NewLoadOptions;
+       CHAR  HalPath[] = "\\";
+       CHAR  ArcBoot[256];
+       CHAR  MiscFiles[256];
+       ULONG i;
+       ULONG_PTR PathSeparator;
        PLOADER_PARAMETER_EXTENSION Extension;
 
        /* Construct SystemRoot and ArcBoot from SystemPath */
@@ -103,63 +97,71 @@ WinLdrInitializePhase1(PLOADER_PARAMETER_BLOCK LoaderBlock,
        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);
+       TRACE("ArcBoot: %s\n", ArcBoot);
+       TRACE("SystemRoot: %s\n", SystemRoot);
+       TRACE("Options: %s\n", Options);
 
        /* Fill Arc BootDevice */
-       LoaderBlock->ArcBootDeviceName = MmHeapAlloc(strlen(ArcBoot)+1);
-       strcpy(LoaderBlock->ArcBootDeviceName, ArcBoot);
+       LoaderBlock->ArcBootDeviceName = WinLdrSystemBlock->ArcBootDeviceName;
+       strncpy(LoaderBlock->ArcBootDeviceName, ArcBoot, MAX_PATH);
        LoaderBlock->ArcBootDeviceName = PaToVa(LoaderBlock->ArcBootDeviceName);
 
        /* Fill Arc HalDevice, it matches ArcBoot path */
-       LoaderBlock->ArcHalDeviceName = MmHeapAlloc(strlen(ArcBoot)+1);
-       strcpy(LoaderBlock->ArcHalDeviceName, ArcBoot);
+       LoaderBlock->ArcHalDeviceName = WinLdrSystemBlock->ArcBootDeviceName;
        LoaderBlock->ArcHalDeviceName = PaToVa(LoaderBlock->ArcHalDeviceName);
 
        /* Fill SystemRoot */
-       LoaderBlock->NtBootPathName = MmHeapAlloc(strlen(SystemRoot)+1);
-       strcpy(LoaderBlock->NtBootPathName, SystemRoot);
+       LoaderBlock->NtBootPathName = WinLdrSystemBlock->NtBootPathName;
+       strncpy(LoaderBlock->NtBootPathName, SystemRoot, MAX_PATH);
        LoaderBlock->NtBootPathName = PaToVa(LoaderBlock->NtBootPathName);
 
        /* Fill NtHalPathName */
-       LoaderBlock->NtHalPathName = MmHeapAlloc(strlen(HalPath)+1);
-       strcpy(LoaderBlock->NtHalPathName, HalPath);
+       LoaderBlock->NtHalPathName = WinLdrSystemBlock->NtHalPathName;
+       strncpy(LoaderBlock->NtHalPathName, HalPath, MAX_PATH);
        LoaderBlock->NtHalPathName = PaToVa(LoaderBlock->NtHalPathName);
 
-       /* Fill load options */
-       LoaderBlock->LoadOptions = MmHeapAlloc(strlen(Options)+1);
-       strcpy(LoaderBlock->LoadOptions, Options);
+       /* Fill LoadOptions and strip the '/' commutator symbol in front of each option */
+       NewLoadOptions = LoadOptions = LoaderBlock->LoadOptions = WinLdrSystemBlock->LoadOptions;
+       strncpy(LoaderBlock->LoadOptions, Options, MAX_OPTIONS_LENGTH);
+
+       do
+       {
+               while (*LoadOptions == '/')
+                       ++LoadOptions;
+
+               *NewLoadOptions++ = *LoadOptions;
+       } while (*LoadOptions++);
+
        LoaderBlock->LoadOptions = PaToVa(LoaderBlock->LoadOptions);
 
        /* Arc devices */
-       LoaderBlock->ArcDiskInformation = (PARC_DISK_INFORMATION)MmHeapAlloc(sizeof(ARC_DISK_INFORMATION));
+       LoaderBlock->ArcDiskInformation = &WinLdrSystemBlock->ArcDiskInformation;
        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;
+               PARC_DISK_SIGNATURE_EX ArcDiskSig;
 
-               /* Get the ARC structure */
-               ArcDiskInfo = (PARC_DISK_SIGNATURE)MmHeapAlloc(sizeof(ARC_DISK_SIGNATURE));
-               RtlZeroMemory(ArcDiskInfo, sizeof(ARC_DISK_SIGNATURE));
+               /* Allocate the ARC structure */
+               ArcDiskSig = HeapAllocate(FrLdrDefaultHeap,
+                                         sizeof(ARC_DISK_SIGNATURE_EX),
+                                         'giSD');
 
                /* Copy the data over */
-               ArcDiskInfo->Signature = reactos_arc_disk_info[i].Signature;
-               ArcDiskInfo->CheckSum = reactos_arc_disk_info[i].CheckSum;
+               ArcDiskSig->DiskSignature.Signature = reactos_arc_disk_info[i].Signature;
+               ArcDiskSig->DiskSignature.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);
+               strncpy(ArcDiskSig->ArcName, reactos_arc_disk_info[i].ArcName, MAX_PATH);
+               ArcDiskSig->DiskSignature.ArcName = PaToVa(ArcDiskSig->ArcName);
 
                /* Mark partition table as valid */
-               ArcDiskInfo->ValidPartitionTable = TRUE; 
+               ArcDiskSig->DiskSignature.ValidPartitionTable = TRUE;
 
                /* Insert into the list */
                InsertTailList(&LoaderBlock->ArcDiskInformation->DiskSignatureListHead,
-                       &ArcDiskInfo->ListEntry);
+                              &ArcDiskSig->DiskSignature.ListEntry);
        }
 
        /* Convert all list's to Virtual address */
@@ -183,15 +185,7 @@ WinLdrInitializePhase1(PLOADER_PARAMETER_BLOCK LoaderBlock,
        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 = &WinLdrSystemBlock->Extension;
        Extension->Size = sizeof(LOADER_PARAMETER_EXTENSION);
        Extension->MajorVersion = (VersionToBoot & 0xFF00) >> 8;
        Extension->MinorVersion = VersionToBoot & 0xFF;
@@ -204,22 +198,36 @@ WinLdrInitializePhase1(PLOADER_PARAMETER_BLOCK LoaderBlock,
                Extension->AcpiTable = (PVOID)1;
        }
 
+#ifdef _M_IX86
+    /* Set headless block pointer */
+    if (WinLdrTerminalConnected)
+    {
+        Extension->HeadlessLoaderBlock = &WinLdrSystemBlock->HeadlessLoaderBlock;
+        RtlCopyMemory(Extension->HeadlessLoaderBlock,
+                      &LoaderRedirectionInformation,
+                      sizeof(HEADLESS_LOADER_BLOCK));
+        Extension->HeadlessLoaderBlock = PaToVa(Extension->HeadlessLoaderBlock);
+    }
+#endif
        /* Load drivers database */
        strcpy(MiscFiles, BootPath);
        strcat(MiscFiles, "AppPatch\\drvmain.sdb");
        Extension->DrvDBImage = PaToVa(WinLdrLoadModule(MiscFiles,
-               &Extension->DrvDBSize, LoaderRegistryData));
+                                                           &Extension->DrvDBSize,
+                                                           LoaderRegistryData));
 
        /* Convert extension and setup block pointers */
        LoaderBlock->Extension = PaToVa(Extension);
 
        if (LoaderBlock->SetupLdrBlock)
                LoaderBlock->SetupLdrBlock = PaToVa(LoaderBlock->SetupLdrBlock);
+
+    TRACE("WinLdrInitializePhase1() completed\n");
 }
 
-BOOLEAN
-WinLdrLoadDeviceDriver(PLOADER_PARAMETER_BLOCK LoaderBlock,
-                       LPSTR BootPath,
+static BOOLEAN
+WinLdrLoadDeviceDriver(PLIST_ENTRY LoadOrderListHead,
+                       LPCSTR BootPath,
                        PUNICODE_STRING FilePath,
                        ULONG Flags,
                        PLDR_DATA_TABLE_ENTRY *DriverDTE)
@@ -249,11 +257,11 @@ WinLdrLoadDeviceDriver(PLOADER_PARAMETER_BLOCK LoaderBlock,
                DriverPath[0] = 0;
        }
 
-       DPRINTM(DPRINT_WINDOWS, "DriverPath: %s, DllName: %s, LPB %p\n", DriverPath, DllName, LoaderBlock);
+       TRACE("DriverPath: %s, DllName: %s, LPB\n", DriverPath, DllName);
 
 
        // Check if driver is already loaded
-       Status = WinLdrCheckForLoadedDll(LoaderBlock, DllName, DriverDTE);
+       Status = WinLdrCheckForLoadedDll(LoadOrderListHead, DllName, DriverDTE);
        if (Status)
        {
                // We've got the pointer to its DTE, just return success
@@ -267,10 +275,10 @@ WinLdrLoadDeviceDriver(PLOADER_PARAMETER_BLOCK LoaderBlock,
                return FALSE;
 
        // Allocate a DTE for it
-       Status = WinLdrAllocateDataTableEntry(LoaderBlock, DllName, DllName, DriverBase, DriverDTE);
+       Status = WinLdrAllocateDataTableEntry(LoadOrderListHead, DllName, DllName, DriverBase, DriverDTE);
        if (!Status)
        {
-               DPRINTM(DPRINT_WINDOWS, "WinLdrAllocateDataTableEntry() failed\n");
+               ERR("WinLdrAllocateDataTableEntry() failed\n");
                return FALSE;
        }
 
@@ -279,11 +287,10 @@ WinLdrLoadDeviceDriver(PLOADER_PARAMETER_BLOCK LoaderBlock,
 
        // Look for any dependencies it may have, and load them too
        sprintf(FullPath,"%s%s", BootPath, DriverPath);
-       Status = WinLdrScanImportDescriptorTable(LoaderBlock, FullPath, *DriverDTE);
+       Status = WinLdrScanImportDescriptorTable(LoadOrderListHead, FullPath, *DriverDTE);
        if (!Status)
        {
-               DPRINTM(DPRINT_WINDOWS, "WinLdrScanImportDescriptorTable() failed for %s\n",
-                       FullPath);
+               ERR("WinLdrScanImportDescriptorTable() failed for %s\n", FullPath);
                return FALSE;
        }
 
@@ -292,7 +299,7 @@ WinLdrLoadDeviceDriver(PLOADER_PARAMETER_BLOCK LoaderBlock,
 
 BOOLEAN
 WinLdrLoadBootDrivers(PLOADER_PARAMETER_BLOCK LoaderBlock,
-                      LPSTR BootPath)
+                      LPCSTR BootPath)
 {
        PLIST_ENTRY NextBd;
        PBOOT_DRIVER_LIST_ENTRY BootDriver;
@@ -305,14 +312,17 @@ WinLdrLoadBootDrivers(PLOADER_PARAMETER_BLOCK LoaderBlock,
        {
                BootDriver = CONTAINING_RECORD(NextBd, BOOT_DRIVER_LIST_ENTRY, Link);
 
-               DPRINTM(DPRINT_WINDOWS, "BootDriver %wZ DTE %08X RegPath: %wZ\n", &BootDriver->FilePath,
+               TRACE("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);
+               Status = WinLdrLoadDeviceDriver(&LoaderBlock->LoadOrderListHead,
+                                               BootPath,
+                                               &BootDriver->FilePath,
+                                               0,
+                                               &BootDriver->LdrEntry);
 
                // If loading failed - cry loudly
                //FIXME: Maybe remove it from the list and try to continue?
@@ -333,8 +343,10 @@ WinLdrLoadBootDrivers(PLOADER_PARAMETER_BLOCK LoaderBlock,
        return TRUE;
 }
 
-PVOID WinLdrLoadModule(PCSTR ModuleName, ULONG *Size,
-                                          TYPE_OF_MEMORY MemoryType)
+PVOID
+WinLdrLoadModule(PCSTR ModuleName,
+                 ULONG *Size,
+                 TYPE_OF_MEMORY MemoryType)
 {
        ULONG FileId;
        PVOID PhysicalBase;
@@ -349,7 +361,7 @@ PVOID WinLdrLoadModule(PCSTR ModuleName, ULONG *Size,
        //sprintf(ProgressString, "Loading %s...", FileName);
        //UiDrawProgressBarCenter(1, 100, ProgressString);
 
-       DPRINTM(DPRINT_WINDOWS, "Loading module %s\n", ModuleName);
+       TRACE("Loading module %s\n", ModuleName);
        *Size = 0;
 
        /* Open the image file */
@@ -386,12 +398,11 @@ PVOID WinLdrLoadModule(PCSTR ModuleName, ULONG *Size,
                return NULL;
        }
 
-       DPRINTM(DPRINT_WINDOWS, "Loaded %s at 0x%x with size 0x%x\n", ModuleName, PhysicalBase, FileSize);
+       TRACE("Loaded %s at 0x%x with size 0x%x\n", ModuleName, PhysicalBase, FileSize);
 
        return PhysicalBase;
 }
 
-
 USHORT
 WinLdrDetectVersion()
 {
@@ -412,198 +423,358 @@ WinLdrDetectVersion()
        return _WIN32_WINNT_WS03;
 }
 
+static
+PVOID
+LoadModule(
+    PLOADER_PARAMETER_BLOCK LoaderBlock,
+    PCCH Path,
+    PCCH File,
+    TYPE_OF_MEMORY MemoryType,
+    PLDR_DATA_TABLE_ENTRY *Dte,
+    BOOLEAN IsKdTransportDll,
+    ULONG Percentage)
+{
+       CHAR FullFileName[MAX_PATH];
+       CHAR ProgressString[256];
+       NTSTATUS Status;
+       PVOID BaseAdress;
+
+       UiDrawBackdrop();
+       sprintf(ProgressString, "Loading %s...", File);
+       UiDrawProgressBarCenter(Percentage, 100, ProgressString);
+
+       strcpy(FullFileName, Path);
+       strcat(FullFileName, "SYSTEM32\\");
+       strcat(FullFileName, File);
+
+       Status = WinLdrLoadImage(FullFileName, MemoryType, &BaseAdress);
+       TRACE("%s loaded with status %d at %p\n",
+               File, Status, BaseAdress);
+
+       strcpy(FullFileName, "WINDOWS\\SYSTEM32\\");
+       strcat(FullFileName, File);
+       /*
+        * Cheat about the base DLL name if we are loading
+        * the Kernel Debugger Transport DLL, to make the
+        * PE loader happy.
+        */
+       WinLdrAllocateDataTableEntry(&LoaderBlock->LoadOrderListHead,
+                                    (IsKdTransportDll ? "KDCOM.DLL" : File),
+                                    FullFileName,
+                                    BaseAdress,
+                                    Dte);
+
+       return BaseAdress;
+}
+
+static
+BOOLEAN
+LoadWindowsCore(IN USHORT OperatingSystemVersion,
+                IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
+                IN LPCSTR BootOptions,
+                IN LPCSTR BootPath,
+                IN OUT PLDR_DATA_TABLE_ENTRY* KernelDTE)
+{
+       BOOLEAN Status;
+       CHAR DirPath[MAX_PATH];
+       CHAR KdTransportDllName[MAX_PATH];
+       PLDR_DATA_TABLE_ENTRY HalDTE, KdComDTE = NULL;
+
+       if (!KernelDTE) return FALSE;
+
+       /* Load the Kernel */
+       LoadModule(LoaderBlock, BootPath, "NTOSKRNL.EXE", LoaderSystemCode, KernelDTE, FALSE, 30);
+
+       /* Load the HAL */
+       LoadModule(LoaderBlock, BootPath, "HAL.DLL", LoaderHalCode, &HalDTE, FALSE, 45);
+
+       /* Load the Kernel Debugger Transport DLL */
+       if (OperatingSystemVersion > _WIN32_WINNT_WIN2K)
+       {
+               /*
+                * According to http://www.nynaeve.net/?p=173 :
+                * "[...] Another enhancement that could be done Microsoft-side would be
+                * a better interface for replacing KD transport modules. Right now, due
+                * to the fact that ntoskrnl is static linked to KDCOM.DLL, the OS loader
+                * has a hardcoded hack that interprets the KD type in the OS loader options,
+                * loads one of the (hardcoded filenames) "kdcom.dll", "kd1394.dll", or
+                * "kdusb2.dll" modules, and inserts them into the loaded module list under
+                * the name "kdcom.dll". [...]"
+                */
+
+               /*
+                * This loop replaces a dumb call to strstr(..., "DEBUGPORT=").
+                * Indeed I want it to be case-insensitive to allow "debugport="
+                * or "DeBuGpOrT=" or... , and I don't want it to match malformed
+                * command-line options, such as:
+                *
+                * "...foo DEBUGPORT=xxx bar..."
+                * "...foo/DEBUGPORT=xxx bar..."
+                * "...foo/DEBUGPORT=bar..."
+                *
+                * i.e. the "DEBUGPORT=" switch must start with a slash and be separated
+                * from the rest by whitespace, unless it begins the command-line, e.g.:
+                *
+                * "/DEBUGPORT=COM1 foo...bar..."
+                * "...foo /DEBUGPORT=USB bar..."
+                * or:
+                * "...foo /DEBUGPORT= bar..."
+                * (in that case, we default the port to COM).
+                */
+               while (BootOptions)
+               {
+                       /* Skip possible initial whitespace */
+                       BootOptions += strspn(BootOptions, " \t");
+
+                       /* Check whether a new commutator starts and it is the DEBUGPORT one */
+                       if (*BootOptions != '/' || _strnicmp(++BootOptions, "DEBUGPORT=", 10) != 0)
+                       {
+                               /* Search for another whitespace */
+                               BootOptions = strpbrk(BootOptions, " \t");
+                               continue;
+                       }
+                       else
+                       {
+                               /* We found the DEBUGPORT commutator. Move to the port name. */
+                               BootOptions += 10;
+                               break;
+                       }
+               }
+
+               if (BootOptions)
+               {
+                       /*
+                        * We have found the DEBUGPORT commutator. Parse the port name.
+                        * Format: /DEBUGPORT=COM1 or /DEBUGPORT=FILE:\Device\HarddiskX\PartitionY\debug.log or /DEBUGPORT=FOO
+                        * If we only have /DEBUGPORT= (i.e. without any port name), defaults it to "COM".
+                        */
+                       strcpy(KdTransportDllName, "KD");
+                       if (_strnicmp(BootOptions, "COM", 3) == 0 && '0' <= BootOptions[3] && BootOptions[3] <= '9')
+                       {
+                               strncat(KdTransportDllName, BootOptions, 3);
+                       }
+                       else
+                       {
+                               size_t i = strcspn(BootOptions, " \t:"); /* Skip valid separators: whitespace or colon */
+                               if (i == 0)
+                                       strcat(KdTransportDllName, "COM");
+                               else
+                                       strncat(KdTransportDllName, BootOptions, i);
+                       }
+                       strcat(KdTransportDllName, ".DLL");
+                       _strupr(KdTransportDllName);
+
+                       /*
+                        * Load the transport DLL. Specify it to LoadModule so that it can
+                        * change the base DLL name of the loaded transport DLL to the default
+                        * "KDCOM.DLL" name, to make the PE loader happy.
+                        */
+                       LoadModule(LoaderBlock, BootPath, KdTransportDllName, LoaderSystemCode, &KdComDTE, TRUE, 60);
+               }
+       }
+
+       /* Load all referenced DLLs for Kernel, HAL and Kernel Debugger Transport DLL */
+       strcpy(DirPath, BootPath);
+       strcat(DirPath, "system32\\");
+       Status  = WinLdrScanImportDescriptorTable(&LoaderBlock->LoadOrderListHead, DirPath, *KernelDTE);
+       Status &= WinLdrScanImportDescriptorTable(&LoaderBlock->LoadOrderListHead, DirPath, HalDTE);
+       if (KdComDTE)
+       {
+               Status &= WinLdrScanImportDescriptorTable(&LoaderBlock->LoadOrderListHead, DirPath, KdComDTE);
+       }
+
+       return Status;
+}
 
 VOID
-LoadAndBootWindows(PCSTR OperatingSystemName,
-                   PSTR SettingsValue,
-                   USHORT OperatingSystemVersion)
+LoadAndBootWindows(IN OperatingSystemItem* OperatingSystem,
+                   IN USHORT OperatingSystemVersion)
 {
+       ULONG_PTR SectionId;
+       PCSTR SectionName = OperatingSystem->SystemPartition;
+       CHAR  SettingsValue[80];
        BOOLEAN HasSection;
-       char  FullPath[MAX_PATH], SystemRoot[MAX_PATH], BootPath[MAX_PATH];
+       CHAR  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;
+       PLOADER_PARAMETER_BLOCK LoaderBlock;
+
+       // Get OS setting value
+       SettingsValue[0] = ANSI_NULL;
+       IniOpenSection("Operating Systems", &SectionId);
+       IniReadSettingByName(SectionId, SectionName, SettingsValue, sizeof(SettingsValue));
 
        // Open the operating system section
        // specified in the .ini file
-       HasSection = IniOpenSection(OperatingSystemName, &SectionId);
+       HasSection = IniOpenSection(SectionName, &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)))
+       if (!HasSection ||
+           !IniReadSettingByName(SectionId, "SystemPath", BootPath, sizeof(BootPath)))
        {
-               strcpy(FullPath, OperatingSystemName);
+               strcpy(BootPath, SectionName);
        }
 
        /* Special case for LiveCD */
-       if (!_strnicmp(FullPath, "LiveCD", strlen("LiveCD")))
+       if (!_strnicmp(BootPath, "LiveCD", strlen("LiveCD")))
        {
-               strcpy(BootPath, FullPath + strlen("LiveCD"));
-               MachDiskGetBootPath(FullPath, sizeof(FullPath));
-               strcat(FullPath, BootPath);
+               strcpy(FileName, BootPath + strlen("LiveCD"));
+               MachDiskGetBootPath(BootPath, sizeof(BootPath));
+               strcat(BootPath, FileName);
        }
 
-       /* Convert FullPath to SystemRoot */
-       PathSeparator = strstr(FullPath, "\\");
-       strcpy(SystemRoot, PathSeparator);
-       strcat(SystemRoot, "\\");
+       /* Append a backslash */
+       if ((strlen(BootPath)==0) || BootPath[strlen(BootPath)] != '\\')
+               strcat(BootPath, "\\");
 
        /* Read booting options */
        if (!HasSection || !IniReadSettingByName(SectionId, "Options", BootOptions, sizeof(BootOptions)))
        {
                /* Get options after the title */
-               const CHAR*p = SettingsValue;
+               PCSTR p = SettingsValue;
                while (*p == ' ' || *p == '"')
                        p++;
                while (*p != '\0' && *p != '"')
                        p++;
                strcpy(BootOptions, p);
-               DPRINTM(DPRINT_WINDOWS,"BootOptions: '%s'\n", BootOptions);
+               TRACE("BootOptions: '%s'\n", BootOptions);
        }
 
        /* Append boot-time options */
        AppendBootTimeOptions(BootOptions);
 
-       //
-       // Check if a ramdisk file was given
-       //
+       /* Check if a ramdisk file was given */
        File = strstr(BootOptions, "/RDPATH=");
        if (File)
        {
-               //
-               // Copy the file name and everything else after it
-               //
+               /* Copy the file name and everything else after it */
                strcpy(FileName, File + 8);
 
-               //
-               // Null-terminate
-               //
+               /* Null-terminate */
                *strstr(FileName, " ") = ANSI_NULL;
 
-               //
-               // Load the ramdisk
-               //
+               /* 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, "\\");
+       //UiDrawStatusText("Loading...");
 
-       DPRINTM(DPRINT_WINDOWS,"BootPath: '%s'\n", BootPath);
+       TRACE("BootPath: '%s'\n", BootPath);
 
        /* Allocate and minimalistic-initialize LPB */
        AllocateAndInitLPB(&LoaderBlock);
 
-       /* Detect hardware */
-       UseRealHeap = TRUE;
-       LoaderBlock->ConfigurationRoot = MachHwDetect();
+#ifdef _M_IX86
+       /* Setup redirection support */
+       WinLdrSetupEms(BootOptions);
+#endif
 
        /* Load Hive */
+       UiDrawBackdrop();
+       UiDrawProgressBarCenter(15, 100, "Loading system hive...");
        Status = WinLdrInitSystemHive(LoaderBlock, BootPath);
-       DPRINTM(DPRINT_WINDOWS, "SYSTEM hive loaded with status %d\n", Status);
+       TRACE("SYSTEM hive loaded with status %d\n", Status);
 
-       if (OperatingSystemVersion == 0)
-               OperatingSystemVersion = WinLdrDetectVersion();
+       /* Load NLS data, OEM font, and prepare boot drivers list */
+       Status = WinLdrScanSystemHive(LoaderBlock, BootPath);
+       TRACE("SYSTEM hive scanned with status %d\n", Status);
+
+       /* Finish loading */
+       LoadAndBootWindowsCommon(OperatingSystemVersion,
+                                LoaderBlock,
+                                BootOptions,
+                                BootPath,
+                                0);
+}
 
-       /* 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);
+VOID
+LoadAndBootWindowsCommon(
+       USHORT OperatingSystemVersion,
+       PLOADER_PARAMETER_BLOCK LoaderBlock,
+       LPCSTR BootOptions,
+       LPCSTR BootPath,
+       BOOLEAN Setup)
+{
+       PLOADER_PARAMETER_BLOCK LoaderBlockVA;
+       BOOLEAN Status;
+       PLDR_DATA_TABLE_ENTRY KernelDTE;
+       KERNEL_ENTRY_POINT KiSystemStartup;
+       LPCSTR SystemRoot;
+       TRACE("LoadAndBootWindowsCommon()\n");
 
-       /* 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);
+       /* Convert BootPath to SystemRoot */
+       SystemRoot = strstr(BootPath, "\\");
 
-       /* 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);
-       }
+       /* Detect hardware */
+       LoaderBlock->ConfigurationRoot = MachHwDetect();
 
-       /* 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)
+       if (OperatingSystemVersion == 0)
+               OperatingSystemVersion = WinLdrDetectVersion();
+
+       /* Load the operating system core: the Kernel, the HAL and the Kernel Debugger Transport DLL */
+       Status = LoadWindowsCore(OperatingSystemVersion,
+                                LoaderBlock,
+                                BootOptions,
+                                BootPath,
+                                &KernelDTE);
+       if (!Status)
        {
-               WinLdrAllocateDataTableEntry(LoaderBlock, "kdcom.dll",
-                       "WINDOWS\\SYSTEM32\\KDCOM.DLL", KdComBase, &KdComDTE);
+               UiMessageBox("Error loading NTOS core.");
+               return;
        }
 
-       /* 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 */
+       UiDrawBackdrop();
+       UiDrawProgressBarCenter(100, 100, "Loading 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);
+       TRACE("Boot drivers loaded with status %d\n", Status);
 
        /* Initialize Phase 1 - no drivers loading anymore */
-       WinLdrInitializePhase1(LoaderBlock, BootOptions, SystemRoot, BootPath, OperatingSystemVersion);
+       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);
+       MachPrepareForReactOS(Setup);
 
        /* Debugging... */
        //DumpMemoryAllocMap();
 
-       /* Turn on paging mode of CPU*/
-       WinLdrTurnOnPaging(LoaderBlock, PcrBasePage, TssBasePage, GdtIdt);
+       /* Do the machine specific initialization */
+       WinLdrSetupMachineDependent(LoaderBlock);
+
+       /* Map pages and create memory descriptors */
+       WinLdrSetupMemoryLayout(LoaderBlock);
+
+       /* Set processor context */
+       WinLdrSetProcessorContext();
 
        /* Save final value of LoaderPagesSpanned */
-       LoaderBlockVA->Extension->LoaderPagesSpanned = LoaderPagesSpanned;
+       LoaderBlock->Extension->LoaderPagesSpanned = LoaderPagesSpanned;
+
+       TRACE("Hello from paged mode, KiSystemStartup %p, LoaderBlockVA %p!\n",
+             KiSystemStartup, LoaderBlockVA);
 
-       DPRINTM(DPRINT_WINDOWS, "Hello from paged mode, KiSystemStartup %p, LoaderBlockVA %p!\n",
-               KiSystemStartup, LoaderBlockVA);
+       // Zero KI_USER_SHARED_DATA page
+       memset((PVOID)KI_USER_SHARED_DATA, 0, MM_PAGE_SIZE);
 
        WinLdrpDumpMemoryDescriptors(LoaderBlockVA);
        WinLdrpDumpBootDriver(LoaderBlockVA);
+#ifndef _M_AMD64
        WinLdrpDumpArcDisks(LoaderBlockVA);
+#endif
 
        //FIXME: If I substitute this debugging checkpoint, GCC will "optimize away" the code below
        //while (1) {};
@@ -614,8 +785,6 @@ LoadAndBootWindows(PCSTR OperatingSystemName,
 
        /* Pass control */
        (*KiSystemStartup)(LoaderBlockVA);
-
-       return;
 }
 
 VOID
@@ -630,7 +799,7 @@ WinLdrpDumpMemoryDescriptors(PLOADER_PARAMETER_BLOCK LoaderBlock)
        {
                MemoryDescriptor = CONTAINING_RECORD(NextMd, MEMORY_ALLOCATION_DESCRIPTOR, ListEntry);
 
-               DPRINTM(DPRINT_WINDOWS, "BP %08X PC %04X MT %d\n", MemoryDescriptor->BasePage,
+               TRACE("BP %08X PC %04X MT %d\n", MemoryDescriptor->BasePage,
                        MemoryDescriptor->PageCount, MemoryDescriptor->MemoryType);
 
                NextMd = MemoryDescriptor->ListEntry.Flink;
@@ -649,7 +818,7 @@ WinLdrpDumpBootDriver(PLOADER_PARAMETER_BLOCK LoaderBlock)
        {
                BootDriver = CONTAINING_RECORD(NextBd, BOOT_DRIVER_LIST_ENTRY, Link);
 
-               DPRINTM(DPRINT_WINDOWS, "BootDriver %wZ DTE %08X RegPath: %wZ\n", &BootDriver->FilePath,
+               TRACE("BootDriver %wZ DTE %08X RegPath: %wZ\n", &BootDriver->FilePath,
                        BootDriver->LdrEntry, &BootDriver->RegistryPath);
 
                NextBd = BootDriver->Link.Flink;
@@ -668,11 +837,9 @@ WinLdrpDumpArcDisks(PLOADER_PARAMETER_BLOCK LoaderBlock)
        {
                ArcDisk = CONTAINING_RECORD(NextBd, ARC_DISK_SIGNATURE, ListEntry);
 
-               DPRINTM(DPRINT_WINDOWS, "ArcDisk %s checksum: 0x%X, signature: 0x%X\n",
+               TRACE("ArcDisk %s checksum: 0x%X, signature: 0x%X\n",
                        ArcDisk->ArcName, ArcDisk->CheckSum, ArcDisk->Signature);
 
                NextBd = ArcDisk->ListEntry.Flink;
        }
 }
-
-