[FREELDR:NTLDR] Implement support for the SOS option.
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Fri, 7 Jan 2022 14:39:25 +0000 (15:39 +0100)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sun, 6 Feb 2022 22:53:41 +0000 (23:53 +0100)
CORE-9023, CORE-18033

- Reset the UI to a minimal one in SOS mode.

- In SOS mode, a trace of loaded files is displayed on the screen,
  instead of the usual progress bar.

- Add a callback to the PE loader to notify when imported DLLs are
  loaded for a main image. This allows getting an accurate SOS trace.

boot/freeldr/freeldr/include/peloader.h
boot/freeldr/freeldr/lib/peloader.c
boot/freeldr/freeldr/ntldr/arch/i386/winldr.c
boot/freeldr/freeldr/ntldr/setupldr.c
boot/freeldr/freeldr/ntldr/winldr.c
boot/freeldr/freeldr/ntldr/winldr.h
boot/freeldr/freeldr/ntldr/wlregistry.c

index a582f76..63ffa80 100644 (file)
 
 #pragma once
 
+/* Optional user-provided callback used by the PE loader
+ * when it loads DLLs imported by a main image. */
+typedef VOID
+(NTAPI *PELDR_IMPORTDLL_LOAD_CALLBACK)(
+    _In_ PCSTR FileName);
+
+extern PELDR_IMPORTDLL_LOAD_CALLBACK PeLdrImportDllLoadCallback;
+
 BOOLEAN
 PeLdrLoadImage(
     IN PCHAR FileName,
index 935c0ee..b768aa9 100644 (file)
 #include <debug.h>
 DBG_DEFAULT_CHANNEL(PELOADER);
 
+/* GLOBALS *******************************************************************/
+
+PELDR_IMPORTDLL_LOAD_CALLBACK PeLdrImportDllLoadCallback = NULL;
+
+
 /* PRIVATE FUNCTIONS *********************************************************/
 
 /* DllName - physical, UnicodeString->Buffer - virtual */
@@ -356,6 +361,9 @@ PeLdrpLoadAndScanReferencedDll(
 
     TRACE("Loading referenced DLL: %s\n", FullDllName);
 
+    if (PeLdrImportDllLoadCallback)
+        PeLdrImportDllLoadCallback(FullDllName);
+
     /* Load the image */
     Success = PeLdrLoadImage(FullDllName, LoaderBootDriver, &BasePA);
     if (!Success)
@@ -722,7 +730,7 @@ PeLdrLoadImage(
     LARGE_INTEGER Position;
     ULONG i, BytesRead;
 
-    TRACE("PeLdrLoadImage(%s, %ld, *)\n", FileName, MemoryType);
+    TRACE("PeLdrLoadImage(%s, %ld)\n", FileName, MemoryType);
 
     /* Open the image file */
     Status = ArcOpen((PSTR)FileName, OpenReadOnly, &FileId);
index 759a72f..e28778b 100644 (file)
@@ -254,7 +254,7 @@ static
 VOID
 MempAllocatePTE(ULONG Entry, PHARDWARE_PTE *PhysicalPT, PHARDWARE_PTE *KernelPT)
 {
-    //Print(L"Creating PDE Entry %X\n", Entry);
+    //TRACE("Creating PDE Entry %X\n", Entry);
 
     // Identity mapping
     *PhysicalPT = (PHARDWARE_PTE)&PhysicalPageTablesBuffer[PhysicalPageTables*MM_PAGE_SIZE];
@@ -297,7 +297,7 @@ MempSetupPaging(IN PFN_NUMBER StartPage,
         // We cannot map this as it requires more than 1 PDE
         // and in fact it's not possible at all ;)
         //
-        //Print(L"skipping...\n");
+        //TRACE("skipping...\n");
         return TRUE;
     }
 
index 89fde95..2deaf6c 100644 (file)
@@ -490,6 +490,7 @@ LoadReactOSSetup(
         return EINVAL;
     }
 
+    /* Let the user know we started loading */
     UiDrawBackdrop();
     UiDrawStatusText("Setup is loading...");
     UiDrawProgressBarCenter(1, 100, "Loading ReactOS Setup...");
@@ -726,6 +727,11 @@ LoadReactOSSetup(
 
     TRACE("BootOptions: '%s'\n", BootOptions);
 
+    /* Handle the SOS option */
+    SosEnabled = !!NtLdrGetOption(BootOptions, "SOS");
+    if (SosEnabled)
+        UiResetForSOS();
+
     /* Allocate and minimally-initialize the Loader Parameter Block */
     AllocateAndInitLPB(_WIN32_WINNT_WS03, &LoaderBlock);
 
@@ -737,7 +743,7 @@ LoadReactOSSetup(
     SetupBlock->Flags = SETUPLDR_TEXT_MODE;
 
     /* Load the "setupreg.hiv" setup system hive */
-    UiDrawProgressBarCenter(15, 100, "Loading setup system hive...");
+    if (!SosEnabled) UiDrawProgressBarCenter(15, 100, "Loading setup system hive...");
     Success = WinLdrInitSystemHive(LoaderBlock, BootPath, TRUE);
     TRACE("Setup SYSTEM hive %s\n", (Success ? "loaded" : "not loaded"));
     /* Bail out if failure */
index b485835..3a21d2f 100644 (file)
@@ -39,6 +39,38 @@ BOOLEAN NoexecuteEnabled = FALSE;
 // debug stuff
 VOID DumpMemoryAllocMap(VOID);
 
+/* PE loader import-DLL loading callback */
+static VOID
+NTAPI
+NtLdrImportDllLoadCallback(
+    _In_ PCSTR FileName)
+{
+    NtLdrOutputLoadMsg(FileName, NULL);
+}
+
+VOID
+NtLdrOutputLoadMsg(
+    _In_ PCSTR FileName,
+    _In_opt_ PCSTR Description)
+{
+    if (SosEnabled)
+    {
+        printf("  %s\n", FileName);
+        TRACE("Loading: %s\n", FileName);
+    }
+    else
+    {
+        /* Inform the user we load a file */
+        CHAR ProgressString[256];
+
+        RtlStringCbPrintfA(ProgressString, sizeof(ProgressString),
+                           "Loading %s...",
+                           (Description ? Description : FileName));
+        // UiDrawProgressBarCenter(1, 100, ProgressString);
+        UiDrawStatusText(ProgressString);
+    }
+}
+
 // Init "phase 0"
 VOID
 AllocateAndInitLPB(
@@ -288,6 +320,8 @@ WinLdrLoadDeviceDriver(PLIST_ENTRY LoadOrderListHead,
 
     // It's not loaded, we have to load it
     RtlStringCbPrintfA(FullPath, sizeof(FullPath), "%s%wZ", BootPath, FilePath);
+
+    NtLdrOutputLoadMsg(FullPath, NULL);
     Success = PeLdrLoadImage(FullPath, LoaderBootDriver, &DriverBase);
     if (!Success)
         return FALSE;
@@ -379,16 +413,10 @@ WinLdrLoadModule(PCSTR ModuleName,
     ARC_STATUS Status;
     ULONG BytesRead;
 
-    //CHAR ProgressString[256];
-
-    /* Inform user we are loading files */
-    //RtlStringCbPrintfA(ProgressString, sizeof(ProgressString), "Loading %s...", FileName);
-    //UiDrawProgressBarCenter(1, 100, ProgressString);
-
-    TRACE("Loading module %s\n", ModuleName);
     *Size = 0;
 
     /* Open the image file */
+    NtLdrOutputLoadMsg(ModuleName, NULL);
     Status = ArcOpen((PSTR)ModuleName, OpenReadOnly, &FileId);
     if (Status != ESUCCESS)
     {
@@ -467,11 +495,12 @@ LoadModule(
     PVOID BaseAddress = NULL;
 
     RtlStringCbPrintfA(ProgressString, sizeof(ProgressString), "Loading %s...", File);
-    UiDrawProgressBarCenter(Percentage, 100, ProgressString);
+    if (!SosEnabled) UiDrawProgressBarCenter(Percentage, 100, ProgressString);
 
     RtlStringCbCopyA(FullFileName, sizeof(FullFileName), Path);
     RtlStringCbCatA(FullFileName, sizeof(FullFileName), File);
 
+    NtLdrOutputLoadMsg(FullFileName, NULL);
     Success = PeLdrLoadImage(FullFileName, MemoryType, &BaseAddress);
     if (!Success)
     {
@@ -620,12 +649,6 @@ LoadWindowsCore(IN USHORT OperatingSystemVersion,
         FIXME("LoadWindowsCore: 3GB - TRUE (not implemented)\n");
         VirtualBias = TRUE;
     }
-    if (NtLdrGetOption(BootOptions, "SOS"))
-    {
-        /* We found the SOS option. */
-        FIXME("LoadWindowsCore: SOS - TRUE (not implemented)\n");
-        SosEnabled = TRUE;
-    }
 
     if (OperatingSystemVersion > _WIN32_WINNT_NT4)
     {
@@ -813,7 +836,9 @@ LoadAndBootWindows(
         return EINVAL;
     }
 
+    /* Let the user know we started loading */
     UiDrawBackdrop();
+    UiDrawStatusText("Loading...");
     UiDrawProgressBarCenter(1, 100, "Loading NT...");
 
     /* Retrieve the system path */
@@ -909,14 +934,16 @@ LoadAndBootWindows(
         }
     }
 
-    /* Let user know we started loading */
-    //UiDrawStatusText("Loading...");
+    /* Handle the SOS option */
+    SosEnabled = !!NtLdrGetOption(BootOptions, "SOS");
+    if (SosEnabled)
+        UiResetForSOS();
 
     /* Allocate and minimally-initialize the Loader Parameter Block */
     AllocateAndInitLPB(OperatingSystemVersion, &LoaderBlock);
 
     /* Load the system hive */
-    UiDrawProgressBarCenter(15, 100, "Loading system hive...");
+    if (!SosEnabled) UiDrawProgressBarCenter(15, 100, "Loading system hive...");
     Success = WinLdrInitSystemHive(LoaderBlock, BootPath, FALSE);
     TRACE("SYSTEM hive %s\n", (Success ? "loaded" : "not loaded"));
     /* Bail out if failure */
@@ -974,9 +1001,13 @@ LoadAndBootWindowsCommon(
     SystemRoot = strstr(BootPath, "\\");
 
     /* Detect hardware */
-    UiDrawProgressBarCenter(20, 100, "Detecting hardware...");
+    if (!SosEnabled) UiDrawProgressBarCenter(20, 100, "Detecting hardware...");
     LoaderBlock->ConfigurationRoot = MachHwDetect();
 
+    /* Initialize the PE loader import-DLL callback, so that we can obtain
+     * feedback (for example during SOS) on the PE images that get loaded. */
+    PeLdrImportDllLoadCallback = NtLdrImportDllLoadCallback;
+
     /* Load the operating system core: the Kernel, the HAL and the Kernel Debugger Transport DLL */
     Success = LoadWindowsCore(OperatingSystemVersion,
                               LoaderBlock,
@@ -985,17 +1016,27 @@ LoadAndBootWindowsCommon(
                               &KernelDTE);
     if (!Success)
     {
+        /* Reset the PE loader import-DLL callback */
+        PeLdrImportDllLoadCallback = NULL;
+
         UiMessageBox("Error loading NTOS core.");
         return ENOEXEC;
     }
 
+    /* Cleanup INI file */
+    IniCleanup();
+
+/****
+ **** WE HAVE NOW REACHED THE POINT OF NO RETURN !!
+ ****/
+
     /* Load boot drivers */
-    UiDrawProgressBarCenter(100, 100, "Loading boot drivers...");
+    if (!SosEnabled) UiDrawProgressBarCenter(100, 100, "Loading boot drivers...");
     Success = WinLdrLoadBootDrivers(LoaderBlock, BootPath);
     TRACE("Boot drivers loading %s\n", Success ? "successful" : "failed");
 
-    /* Cleanup ini file */
-    IniCleanup();
+    /* Reset the PE loader import-DLL callback */
+    PeLdrImportDllLoadCallback = NULL;
 
     /* Initialize Phase 1 - no drivers loading anymore */
     WinLdrInitializePhase1(LoaderBlock,
index c89010e..03cc68f 100644 (file)
@@ -73,6 +73,28 @@ VOID ConvertConfigToVA(PCONFIGURATION_COMPONENT_DATA Start);
 
 
 // winldr.c
+extern BOOLEAN SosEnabled;
+
+FORCEINLINE
+VOID
+UiResetForSOS(VOID)
+{
+#ifdef _M_ARM
+    /* Re-initialize the UI */
+    UiInitialize(TRUE);
+#else
+    /* Reset the UI and switch to MiniTui */
+    UiVtbl.UnInitialize();
+    UiVtbl = MiniTuiVtbl;
+    UiVtbl.Initialize();
+#endif
+}
+
+VOID
+NtLdrOutputLoadMsg(
+    _In_ PCSTR FileName,
+    _In_opt_ PCSTR Description);
+
 PVOID WinLdrLoadModule(PCSTR ModuleName, PULONG Size,
                        TYPE_OF_MEMORY MemoryType);
 
index 83bbda9..4f82fb8 100644 (file)
@@ -50,6 +50,7 @@ WinLdrLoadSystemHive(
     RtlStringCbCopyA(FullHiveName, sizeof(FullHiveName), DirectoryPath);
     RtlStringCbCatA(FullHiveName, sizeof(FullHiveName), HiveName);
 
+    NtLdrOutputLoadMsg(FullHiveName, NULL);
     Status = ArcOpen(FullHiveName, OpenReadOnly, &FileId);
     if (Status != ESUCCESS)
     {
@@ -330,6 +331,8 @@ WinLdrLoadNLSData(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
     /* Open file with ANSI and store its size */
     RtlStringCbCopyA(FileName, sizeof(FileName), DirectoryPath);
     RtlStringCbCatA(FileName, sizeof(FileName), AnsiFileName);
+
+    NtLdrOutputLoadMsg(FileName, NULL);
     Status = ArcOpen(FileName, OpenReadOnly, &FileId);
     if (Status != ESUCCESS)
     {
@@ -351,9 +354,10 @@ WinLdrLoadNLSData(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
     }
     else
     {
-        //Print(L"Loading %s...\n", Filename);
         RtlStringCbCopyA(FileName, sizeof(FileName), DirectoryPath);
         RtlStringCbCatA(FileName, sizeof(FileName), OemFileName);
+
+        NtLdrOutputLoadMsg(FileName, NULL);
         Status = ArcOpen(FileName, OpenReadOnly, &FileId);
         if (Status != ESUCCESS)
         {
@@ -370,9 +374,10 @@ WinLdrLoadNLSData(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
     TRACE("OemFileSize: %d\n", OemFileSize);
 
     /* And finally open the language codepage file and store its length */
-    //Print(L"Loading %s...\n", Filename);
     RtlStringCbCopyA(FileName, sizeof(FileName), DirectoryPath);
     RtlStringCbCatA(FileName, sizeof(FileName), LanguageFileName);
+
+    NtLdrOutputLoadMsg(FileName, NULL);
     Status = ArcOpen(FileName, OpenReadOnly, &FileId);
     if (Status != ESUCCESS)
     {
@@ -415,6 +420,8 @@ WinLdrLoadNLSData(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
     /* Now actually read the data into memory, starting with Ansi file */
     RtlStringCbCopyA(FileName, sizeof(FileName), DirectoryPath);
     RtlStringCbCatA(FileName, sizeof(FileName), AnsiFileName);
+
+    NtLdrOutputLoadMsg(FileName, NULL);
     Status = ArcOpen(FileName, OpenReadOnly, &FileId);
     if (Status != ESUCCESS)
     {
@@ -435,6 +442,8 @@ WinLdrLoadNLSData(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
     {
         RtlStringCbCopyA(FileName, sizeof(FileName), DirectoryPath);
         RtlStringCbCatA(FileName, sizeof(FileName), OemFileName);
+
+        NtLdrOutputLoadMsg(FileName, NULL);
         Status = ArcOpen(FileName, OpenReadOnly, &FileId);
         if (Status != ESUCCESS)
         {
@@ -454,6 +463,8 @@ WinLdrLoadNLSData(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
     /* Finally the language file */
     RtlStringCbCopyA(FileName, sizeof(FileName), DirectoryPath);
     RtlStringCbCatA(FileName, sizeof(FileName), LanguageFileName);
+
+    NtLdrOutputLoadMsg(FileName, NULL);
     Status = ArcOpen(FileName, OpenReadOnly, &FileId);
     if (Status != ESUCCESS)
     {