[FREELDR]
[reactos.git] / boot / freeldr / freeldr / windows / winldr.c
index 3da7eb0..f800af2 100644 (file)
@@ -30,7 +30,6 @@ DBG_DEFAULT_CHANNEL(WINDOWS);
 extern ULONG reactos_disk_count;
 extern ARC_DISK_SIGNATURE reactos_arc_disk_info[];
 
-extern BOOLEAN UseRealHeap;
 extern ULONG LoaderPagesSpanned;
 extern BOOLEAN AcpiPresent;
 
@@ -228,7 +227,7 @@ WinLdrInitializePhase1(PLOADER_PARAMETER_BLOCK LoaderBlock,
 
 static BOOLEAN
 WinLdrLoadDeviceDriver(PLIST_ENTRY LoadOrderListHead,
-                       LPSTR BootPath,
+                       LPCSTR BootPath,
                        PUNICODE_STRING FilePath,
                        ULONG Flags,
                        PLDR_DATA_TABLE_ENTRY *DriverDTE)
@@ -300,7 +299,7 @@ WinLdrLoadDeviceDriver(PLIST_ENTRY LoadOrderListHead,
 
 BOOLEAN
 WinLdrLoadBootDrivers(PLOADER_PARAMETER_BLOCK LoaderBlock,
-                      LPSTR BootPath)
+                      LPCSTR BootPath)
 {
        PLIST_ENTRY NextBd;
        PBOOT_DRIVER_LIST_ENTRY BootDriver;
@@ -319,8 +318,11 @@ WinLdrLoadBootDrivers(PLOADER_PARAMETER_BLOCK LoaderBlock,
                // Paths are relative (FIXME: Are they always relative?)
 
                // Load it
-               Status = WinLdrLoadDeviceDriver(&LoaderBlock->LoadOrderListHead, 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?
@@ -341,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;
@@ -399,7 +403,6 @@ PVOID WinLdrLoadModule(PCSTR ModuleName, ULONG *Size,
        return PhysicalBase;
 }
 
-
 USHORT
 WinLdrDetectVersion()
 {
@@ -428,6 +431,7 @@ LoadModule(
     PCCH File,
     TYPE_OF_MEMORY MemoryType,
     PLDR_DATA_TABLE_ENTRY *Dte,
+    BOOLEAN IsKdTransportDll,
     ULONG Percentage)
 {
        CHAR FullFileName[MAX_PATH];
@@ -449,12 +453,139 @@ LoadModule(
 
        strcpy(FullFileName, "WINDOWS\\SYSTEM32\\");
        strcat(FullFileName, File);
-       WinLdrAllocateDataTableEntry(&LoaderBlock->LoadOrderListHead, File,
-               FullFileName, BaseAdress, Dte);
+       /*
+        * 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(IN OperatingSystemItem* OperatingSystem,
                    IN USHORT OperatingSystemVersion)
@@ -497,7 +628,7 @@ LoadAndBootWindows(IN OperatingSystemItem* OperatingSystem,
                strcat(BootPath, FileName);
        }
 
-       /* append a backslash */
+       /* Append a backslash */
        if ((strlen(BootPath)==0) || BootPath[strlen(BootPath)] != '\\')
                strcat(BootPath, "\\");
 
@@ -554,7 +685,7 @@ LoadAndBootWindows(IN OperatingSystemItem* OperatingSystem,
        Status = WinLdrScanSystemHive(LoaderBlock, BootPath);
        TRACE("SYSTEM hive scanned with status %d\n", Status);
 
-
+       /* Finish loading */
        LoadAndBootWindowsCommon(OperatingSystemVersion,
                                 LoaderBlock,
                                 BootOptions,
@@ -572,8 +703,7 @@ LoadAndBootWindowsCommon(
 {
        PLOADER_PARAMETER_BLOCK LoaderBlockVA;
        BOOLEAN Status;
-       CHAR FileName[MAX_PATH];
-       PLDR_DATA_TABLE_ENTRY KernelDTE, HalDTE, KdComDTE = NULL;
+       PLDR_DATA_TABLE_ENTRY KernelDTE;
        KERNEL_ENTRY_POINT KiSystemStartup;
        LPCSTR SystemRoot;
        TRACE("LoadAndBootWindowsCommon()\n");
@@ -582,46 +712,35 @@ LoadAndBootWindowsCommon(
        SystemRoot = strstr(BootPath, "\\");
 
        /* Detect hardware */
-       UseRealHeap = TRUE;
        LoaderBlock->ConfigurationRoot = MachHwDetect();
 
        if (OperatingSystemVersion == 0)
                OperatingSystemVersion = WinLdrDetectVersion();
 
-       /* Load kernel */
-       LoadModule(LoaderBlock, BootPath, "NTOSKRNL.EXE", LoaderSystemCode, &KernelDTE, 30);
-
-       /* Load HAL */
-       LoadModule(LoaderBlock, BootPath, "HAL.DLL", LoaderHalCode, &HalDTE, 45);
-
-       /* Load kernel-debugger support dll */
-       if (OperatingSystemVersion > _WIN32_WINNT_WIN2K)
-       {
-               LoadModule(LoaderBlock, BootPath, "KDCOM.DLL", LoaderSystemCode, &KdComDTE, 60);
-       }
-
-       /* Load all referenced DLLs for kernel, HAL and kdcom.dll */
-       strcpy(FileName, BootPath);
-       strcat(FileName, "system32\\");
-       Status = WinLdrScanImportDescriptorTable(&LoaderBlock->LoadOrderListHead, FileName, KernelDTE);
-       Status &= WinLdrScanImportDescriptorTable(&LoaderBlock->LoadOrderListHead, FileName, HalDTE);
-       if (KdComDTE)
-               Status &= WinLdrScanImportDescriptorTable(&LoaderBlock->LoadOrderListHead, FileName, KdComDTE);
-
+       /* Load the operating system core: the Kernel, the HAL and the Kernel Debugger Transport DLL */
+       Status = LoadWindowsCore(OperatingSystemVersion,
+                                LoaderBlock,
+                                BootOptions,
+                                BootPath,
+                                &KernelDTE);
        if (!Status)
        {
-               UiMessageBox("Error loading imported dll.");
+               UiMessageBox("Error loading NTOS core.");
                return;
        }
 
        /* Load boot drivers */
        UiDrawBackdrop();
        UiDrawProgressBarCenter(100, 100, "Loading boot drivers...");
-       Status = WinLdrLoadBootDrivers(LoaderBlock, (PCHAR)BootPath);
+       Status = WinLdrLoadBootDrivers(LoaderBlock, BootPath);
        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;
@@ -646,7 +765,7 @@ LoadAndBootWindowsCommon(
        LoaderBlock->Extension->LoaderPagesSpanned = LoaderPagesSpanned;
 
        TRACE("Hello from paged mode, KiSystemStartup %p, LoaderBlockVA %p!\n",
-               KiSystemStartup, LoaderBlockVA);
+             KiSystemStartup, LoaderBlockVA);
 
        // Zero KI_USER_SHARED_DATA page
        memset((PVOID)KI_USER_SHARED_DATA, 0, MM_PAGE_SIZE);
@@ -724,5 +843,3 @@ WinLdrpDumpArcDisks(PLOADER_PARAMETER_BLOCK LoaderBlock)
                NextBd = ArcDisk->ListEntry.Flink;
        }
 }
-
-