[FREELDR]
[reactos.git] / boot / freeldr / freeldr / windows / winldr.c
index 25eaa15..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;
 
@@ -85,9 +84,10 @@ 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];
+       LPSTR LoadOptions, NewLoadOptions;
+       CHAR  HalPath[] = "\\";
+       CHAR  ArcBoot[256];
+       CHAR  MiscFiles[256];
        ULONG i;
        ULONG_PTR PathSeparator;
        PLOADER_PARAMETER_EXTENSION Extension;
@@ -120,9 +120,18 @@ WinLdrInitializePhase1(PLOADER_PARAMETER_BLOCK LoaderBlock,
        strncpy(LoaderBlock->NtHalPathName, HalPath, MAX_PATH);
        LoaderBlock->NtHalPathName = PaToVa(LoaderBlock->NtHalPathName);
 
-       /* Fill load options */
-       LoaderBlock->LoadOptions = WinLdrSystemBlock->LoadOptions;
+       /* 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 */
@@ -136,8 +145,8 @@ WinLdrInitializePhase1(PLOADER_PARAMETER_BLOCK LoaderBlock,
 
                /* Allocate the ARC structure */
                ArcDiskSig = HeapAllocate(FrLdrDefaultHeap,
-                                  sizeof(ARC_DISK_SIGNATURE_EX),
-                                 'giSD');
+                                         sizeof(ARC_DISK_SIGNATURE_EX),
+                                         'giSD');
 
                /* Copy the data over */
                ArcDiskSig->DiskSignature.Signature = reactos_arc_disk_info[i].Signature;
@@ -218,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)
@@ -290,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;
@@ -309,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?
@@ -331,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;
@@ -389,7 +403,6 @@ PVOID WinLdrLoadModule(PCSTR ModuleName, ULONG *Size,
        return PhysicalBase;
 }
 
-
 USHORT
 WinLdrDetectVersion()
 {
@@ -418,6 +431,7 @@ LoadModule(
     PCCH File,
     TYPE_OF_MEMORY MemoryType,
     PLDR_DATA_TABLE_ENTRY *Dte,
+    BOOLEAN IsKdTransportDll,
     ULONG Percentage)
 {
        CHAR FullFileName[MAX_PATH];
@@ -439,29 +453,162 @@ 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(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  BootPath[MAX_PATH];
+       CHAR  BootPath[MAX_PATH];
        CHAR  FileName[MAX_PATH];
        CHAR  BootOptions[256];
        PCHAR File;
        BOOLEAN Status;
-       ULONG_PTR SectionId;
        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();
        UiDrawProgressBarCenter(1, 100, "Loading NT...");
@@ -470,7 +617,7 @@ LoadAndBootWindows(PCSTR OperatingSystemName,
        if (!HasSection ||
            !IniReadSettingByName(SectionId, "SystemPath", BootPath, sizeof(BootPath)))
        {
-               strcpy(BootPath, OperatingSystemName);
+               strcpy(BootPath, SectionName);
        }
 
        /* Special case for LiveCD */
@@ -481,7 +628,7 @@ LoadAndBootWindows(PCSTR OperatingSystemName,
                strcat(BootPath, FileName);
        }
 
-       /* append a backslash */
+       /* Append a backslash */
        if ((strlen(BootPath)==0) || BootPath[strlen(BootPath)] != '\\')
                strcat(BootPath, "\\");
 
@@ -489,7 +636,7 @@ LoadAndBootWindows(PCSTR OperatingSystemName,
        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 != '"')
@@ -524,7 +671,7 @@ LoadAndBootWindows(PCSTR OperatingSystemName,
        AllocateAndInitLPB(&LoaderBlock);
 
 #ifdef _M_IX86
-       /* Setup redirection support */
+       /* Setup redirection support */
        WinLdrSetupEms(BootOptions);
 #endif
 
@@ -538,7 +685,7 @@ LoadAndBootWindows(PCSTR OperatingSystemName,
        Status = WinLdrScanSystemHive(LoaderBlock, BootPath);
        TRACE("SYSTEM hive scanned with status %d\n", Status);
 
-
+       /* Finish loading */
        LoadAndBootWindowsCommon(OperatingSystemVersion,
                                 LoaderBlock,
                                 BootOptions,
@@ -556,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");
@@ -566,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;
@@ -630,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);
@@ -708,5 +843,3 @@ WinLdrpDumpArcDisks(PLOADER_PARAMETER_BLOCK LoaderBlock)
                NextBd = ArcDisk->ListEntry.Flink;
        }
 }
-
-