/*
- * 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.
+ * PROJECT: FreeLoader
+ * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
+ * PURPOSE: Windows-compatible NT OS Loader.
+ * COPYRIGHT: Copyright 2006-2019 Aleksey Bragin <aleksey@reactos.org>
*/
#include <freeldr.h>
+#include <ndk/ldrtypes.h>
#include "winldr.h"
+#include "ntldropts.h"
#include "registry.h"
-
-#include <ndk/ldrtypes.h>
+#include <internal/cmboot.h>
#include <debug.h>
DBG_DEFAULT_CHANNEL(WINDOWS);
extern HEADLESS_LOADER_BLOCK LoaderRedirectionInformation;
extern BOOLEAN WinLdrTerminalConnected;
-extern void WinLdrSetupEms(IN PCHAR BootOptions);
+extern VOID WinLdrSetupEms(IN PCSTR BootOptions);
PLOADER_SYSTEM_BLOCK WinLdrSystemBlock;
+/**/PCWSTR BootFileSystem = NULL;/**/
+
+BOOLEAN VirtualBias = FALSE;
+BOOLEAN SosEnabled = FALSE;
+BOOLEAN SafeBoot = FALSE;
+BOOLEAN BootLogo = FALSE;
+#ifdef _M_IX86
+BOOLEAN PaeModeOn = FALSE;
+#endif
+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));
+ // UiSetProgressBarText(ProgressString);
+ // UiIndicateProgress();
+ UiDrawStatusText(ProgressString);
+ }
+}
+
// Init "phase 0"
VOID
-AllocateAndInitLPB(PLOADER_PARAMETER_BLOCK *OutLoaderBlock)
+AllocateAndInitLPB(
+ IN USHORT VersionToBoot,
+ OUT PLOADER_PARAMETER_BLOCK* OutLoaderBlock)
{
PLOADER_PARAMETER_BLOCK LoaderBlock;
+ PLOADER_PARAMETER_EXTENSION Extension;
- /* Allocate and zero-init the LPB */
+ /* Allocate and zero-init the Loader Parameter Block */
WinLdrSystemBlock = MmAllocateMemoryWithType(sizeof(LOADER_SYSTEM_BLOCK),
LoaderSystemBlock);
if (WinLdrSystemBlock == NULL)
LoaderBlock = &WinLdrSystemBlock->LoaderBlock;
LoaderBlock->NlsData = &WinLdrSystemBlock->NlsDataBlock;
+ /* Initialize the Loader Block Extension */
+ Extension = &WinLdrSystemBlock->Extension;
+ LoaderBlock->Extension = Extension;
+ Extension->Size = sizeof(LOADER_PARAMETER_EXTENSION);
+ Extension->MajorVersion = (VersionToBoot & 0xFF00) >> 8;
+ Extension->MinorVersion = (VersionToBoot & 0xFF);
+
/* Init three critical lists, used right away */
InitializeListHead(&LoaderBlock->LoadOrderListHead);
InitializeListHead(&LoaderBlock->MemoryDescriptorListHead);
// Init "phase 1"
VOID
WinLdrInitializePhase1(PLOADER_PARAMETER_BLOCK LoaderBlock,
- LPCSTR Options,
- LPCSTR SystemRoot,
- LPCSTR BootPath,
+ PCSTR Options,
+ PCSTR SystemRoot,
+ PCSTR 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)";
+ /*
+ * 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)";
+ */
- LPSTR LoadOptions, NewLoadOptions;
+ PSTR LoadOptions, NewLoadOptions;
CHAR HalPath[] = "\\";
- CHAR ArcBoot[256];
- CHAR MiscFiles[256];
+ CHAR ArcBoot[MAX_PATH+1];
+ CHAR MiscFiles[MAX_PATH+1];
ULONG i;
ULONG_PTR PathSeparator;
PLOADER_PARAMETER_EXTENSION Extension;
/* Construct SystemRoot and ArcBoot from SystemPath */
PathSeparator = strstr(BootPath, "\\") - BootPath;
- strncpy(ArcBoot, BootPath, PathSeparator);
- ArcBoot[PathSeparator] = ANSI_NULL;
+ RtlStringCbCopyNA(ArcBoot, sizeof(ArcBoot), BootPath, PathSeparator);
- TRACE("ArcBoot: %s\n", ArcBoot);
- TRACE("SystemRoot: %s\n", SystemRoot);
- TRACE("Options: %s\n", Options);
+ TRACE("ArcBoot: '%s'\n", ArcBoot);
+ TRACE("SystemRoot: '%s'\n", SystemRoot);
+ TRACE("Options: '%s'\n", Options);
- /* Fill Arc BootDevice */
+ /* Fill ARC BootDevice */
LoaderBlock->ArcBootDeviceName = WinLdrSystemBlock->ArcBootDeviceName;
- strncpy(LoaderBlock->ArcBootDeviceName, ArcBoot, MAX_PATH);
+ RtlStringCbCopyA(LoaderBlock->ArcBootDeviceName, sizeof(WinLdrSystemBlock->ArcBootDeviceName), ArcBoot);
LoaderBlock->ArcBootDeviceName = PaToVa(LoaderBlock->ArcBootDeviceName);
- /* Fill Arc HalDevice, it matches ArcBoot path */
+//
+// IMPROVE!!
+// SetupBlock->ArcSetupDeviceName must be the path to the setup **SOURCE**,
+// and not the setup boot path. Indeed they may differ!!
+//
+ if (LoaderBlock->SetupLdrBlock)
+ {
+ PSETUP_LOADER_BLOCK SetupBlock = LoaderBlock->SetupLdrBlock;
+
+ /* Adjust the ARC path in the setup block - Matches ArcBoot path */
+ SetupBlock->ArcSetupDeviceName = WinLdrSystemBlock->ArcBootDeviceName;
+ SetupBlock->ArcSetupDeviceName = PaToVa(SetupBlock->ArcSetupDeviceName);
+
+ /* Convert the setup block pointer */
+ LoaderBlock->SetupLdrBlock = PaToVa(LoaderBlock->SetupLdrBlock);
+ }
+
+ /* Fill ARC HalDevice, it matches ArcBoot path */
LoaderBlock->ArcHalDeviceName = WinLdrSystemBlock->ArcBootDeviceName;
LoaderBlock->ArcHalDeviceName = PaToVa(LoaderBlock->ArcHalDeviceName);
/* Fill SystemRoot */
LoaderBlock->NtBootPathName = WinLdrSystemBlock->NtBootPathName;
- strncpy(LoaderBlock->NtBootPathName, SystemRoot, MAX_PATH);
+ RtlStringCbCopyA(LoaderBlock->NtBootPathName, sizeof(WinLdrSystemBlock->NtBootPathName), SystemRoot);
LoaderBlock->NtBootPathName = PaToVa(LoaderBlock->NtBootPathName);
/* Fill NtHalPathName */
LoaderBlock->NtHalPathName = WinLdrSystemBlock->NtHalPathName;
- strncpy(LoaderBlock->NtHalPathName, HalPath, MAX_PATH);
+ RtlStringCbCopyA(LoaderBlock->NtHalPathName, sizeof(WinLdrSystemBlock->NtHalPathName), HalPath);
LoaderBlock->NtHalPathName = PaToVa(LoaderBlock->NtHalPathName);
- /* Fill LoadOptions and strip the '/' commutator symbol in front of each option */
+ /* Fill LoadOptions and strip the '/' switch symbol in front of each option */
NewLoadOptions = LoadOptions = LoaderBlock->LoadOptions = WinLdrSystemBlock->LoadOptions;
- strncpy(LoaderBlock->LoadOptions, Options, MAX_OPTIONS_LENGTH);
+ RtlStringCbCopyA(LoaderBlock->LoadOptions, sizeof(WinLdrSystemBlock->LoadOptions), Options);
do
{
LoaderBlock->LoadOptions = PaToVa(LoaderBlock->LoadOptions);
- /* Arc devices */
+ /* ARC devices */
LoaderBlock->ArcDiskInformation = &WinLdrSystemBlock->ArcDiskInformation;
InitializeListHead(&LoaderBlock->ArcDiskInformation->DiskSignatureListHead);
/* Allocate the ARC structure */
ArcDiskSig = FrLdrHeapAlloc(sizeof(ARC_DISK_SIGNATURE_EX), 'giSD');
+ if (!ArcDiskSig)
+ {
+ ERR("Failed to allocate ARC structure! Ignoring remaining ARC disks. (i = %lu, DiskCount = %lu)\n",
+ i, reactos_disk_count);
+ break;
+ }
/* Copy the data over */
RtlCopyMemory(ArcDiskSig, &reactos_arc_disk_info[i], sizeof(ARC_DISK_SIGNATURE_EX));
- /* Set the ARC Name pointer and mark the partition table as valid */
+ /* Set the ARC Name pointer */
ArcDiskSig->DiskSignature.ArcName = PaToVa(ArcDiskSig->ArcName);
- ArcDiskSig->DiskSignature.ValidPartitionTable = TRUE;
/* Insert into the list */
InsertTailList(&LoaderBlock->ArcDiskInformation->DiskSignatureListHead,
&ArcDiskSig->DiskSignature.ListEntry);
}
- /* Convert all list's to Virtual address */
+ /* Convert all lists to Virtual address */
/* Convert the ArcDisks list to virtual address */
List_PaToVa(&LoaderBlock->ArcDiskInformation->DiskSignatureListHead);
/* Convert list of boot drivers */
List_PaToVa(&LoaderBlock->BootDriverListHead);
- /* Initialize Extension now */
- Extension = &WinLdrSystemBlock->Extension;
- Extension->Size = sizeof(LOADER_PARAMETER_EXTENSION);
- Extension->MajorVersion = (VersionToBoot & 0xFF00) >> 8;
- Extension->MinorVersion = VersionToBoot & 0xFF;
+ Extension = LoaderBlock->Extension;
+
+ /* FIXME! HACK value for docking profile */
Extension->Profile.Status = 2;
/* Check if FreeLdr detected a ACPI table */
}
#endif
/* Load drivers database */
- strcpy(MiscFiles, BootPath);
- strcat(MiscFiles, "AppPatch\\drvmain.sdb");
+ RtlStringCbCopyA(MiscFiles, sizeof(MiscFiles), BootPath);
+ RtlStringCbCatA(MiscFiles, sizeof(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);
+ /* Convert the extension block pointer */
+ LoaderBlock->Extension = PaToVa(LoaderBlock->Extension);
TRACE("WinLdrInitializePhase1() completed\n");
}
static BOOLEAN
WinLdrLoadDeviceDriver(PLIST_ENTRY LoadOrderListHead,
- LPCSTR BootPath,
+ PCSTR BootPath,
PUNICODE_STRING FilePath,
ULONG Flags,
PLDR_DATA_TABLE_ENTRY *DriverDTE)
PVOID DriverBase = NULL;
// Separate the path to file name and directory path
- _snprintf(DriverPath, sizeof(DriverPath), "%wZ", FilePath);
+ RtlStringCbPrintfA(DriverPath, sizeof(DriverPath), "%wZ", FilePath);
DriverNamePos = strrchr(DriverPath, '\\');
if (DriverNamePos != NULL)
{
// Copy the name
- strcpy(DllName, DriverNamePos+1);
+ RtlStringCbCopyA(DllName, sizeof(DllName), DriverNamePos+1);
// Cut out the name from the path
- *(DriverNamePos+1) = 0;
+ *(DriverNamePos+1) = ANSI_NULL;
}
else
{
// There is no directory in the path
- strcpy(DllName, DriverPath);
- DriverPath[0] = ANSI_NULL;
+ RtlStringCbCopyA(DllName, sizeof(DllName), DriverPath);
+ *DriverPath = ANSI_NULL;
}
- TRACE("DriverPath: %s, DllName: %s, LPB\n", DriverPath, DllName);
+ TRACE("DriverPath: '%s', DllName: '%s', LPB\n", DriverPath, DllName);
// Check if driver is already loaded
- Success = WinLdrCheckForLoadedDll(LoadOrderListHead, DllName, DriverDTE);
+ Success = PeLdrCheckForLoadedDll(LoadOrderListHead, DllName, DriverDTE);
if (Success)
{
// We've got the pointer to its DTE, just return success
}
// It's not loaded, we have to load it
- _snprintf(FullPath, sizeof(FullPath), "%s%wZ", BootPath, FilePath);
- Success = WinLdrLoadImage(FullPath, LoaderBootDriver, &DriverBase);
+ RtlStringCbPrintfA(FullPath, sizeof(FullPath), "%s%wZ", BootPath, FilePath);
+
+ NtLdrOutputLoadMsg(FullPath, NULL);
+ Success = PeLdrLoadImage(FullPath, LoaderBootDriver, &DriverBase);
if (!Success)
+ {
+ ERR("PeLdrLoadImage('%s') failed\n", DllName);
return FALSE;
+ }
// Allocate a DTE for it
- Success = WinLdrAllocateDataTableEntry(LoadOrderListHead, DllName, DllName, DriverBase, DriverDTE);
+ Success = PeLdrAllocateDataTableEntry(LoadOrderListHead, DllName, DllName, DriverBase, DriverDTE);
if (!Success)
{
- ERR("WinLdrAllocateDataTableEntry() failed\n");
+ /* Cleanup and bail out */
+ ERR("PeLdrAllocateDataTableEntry('%s') failed\n", DllName);
+ MmFreeMemory(DriverBase);
return FALSE;
}
+ /* Init security cookie */
+ PeLdrInitSecurityCookie(*DriverDTE);
+
// 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);
- Success = WinLdrScanImportDescriptorTable(LoadOrderListHead, FullPath, *DriverDTE);
+ RtlStringCbPrintfA(FullPath, sizeof(FullPath), "%s%s", BootPath, DriverPath);
+ Success = PeLdrScanImportDescriptorTable(LoadOrderListHead, FullPath, *DriverDTE);
if (!Success)
{
- ERR("WinLdrScanImportDescriptorTable() failed for %s\n", FullPath);
+ /* Cleanup and bail out */
+ ERR("PeLdrScanImportDescriptorTable('%s') failed\n", FullPath);
+ PeLdrFreeDataTableEntry(*DriverDTE);
+ MmFreeMemory(DriverBase);
return FALSE;
}
BOOLEAN
WinLdrLoadBootDrivers(PLOADER_PARAMETER_BLOCK LoaderBlock,
- LPCSTR BootPath)
+ PCSTR BootPath)
{
PLIST_ENTRY NextBd;
+ PBOOT_DRIVER_NODE DriverNode;
PBOOT_DRIVER_LIST_ENTRY BootDriver;
BOOLEAN Success;
BOOLEAN ret = TRUE;
- // Walk through the boot drivers list
+ /* Walk through the boot drivers list */
NextBd = LoaderBlock->BootDriverListHead.Flink;
-
while (NextBd != &LoaderBlock->BootDriverListHead)
{
- BootDriver = CONTAINING_RECORD(NextBd, BOOT_DRIVER_LIST_ENTRY, Link);
+ DriverNode = CONTAINING_RECORD(NextBd,
+ BOOT_DRIVER_NODE,
+ ListEntry.Link);
+ BootDriver = &DriverNode->ListEntry;
- TRACE("BootDriver %wZ DTE %08X RegPath: %wZ\n", &BootDriver->FilePath,
- BootDriver->LdrEntry, &BootDriver->RegistryPath);
+ /* Get the next list entry as we may remove the current one on failure */
+ NextBd = BootDriver->Link.Flink;
+
+ TRACE("BootDriver %wZ DTE %08X RegPath: %wZ\n",
+ &BootDriver->FilePath, BootDriver->LdrEntry,
+ &BootDriver->RegistryPath);
// Paths are relative (FIXME: Are they always relative?)
- // Load it
+ /* Load it */
+ UiIndicateProgress();
Success = WinLdrLoadDeviceDriver(&LoaderBlock->LoadOrderListHead,
BootPath,
&BootDriver->FilePath,
0,
&BootDriver->LdrEntry);
-
if (Success)
{
- // Convert the RegistryPath and DTE addresses to VA since we are not going to use it anymore
+ /* Convert the addresses to VA since we are not going to use them anymore */
BootDriver->RegistryPath.Buffer = PaToVa(BootDriver->RegistryPath.Buffer);
BootDriver->FilePath.Buffer = PaToVa(BootDriver->FilePath.Buffer);
BootDriver->LdrEntry = PaToVa(BootDriver->LdrEntry);
+
+ if (DriverNode->Group.Buffer)
+ DriverNode->Group.Buffer = PaToVa(DriverNode->Group.Buffer);
+ DriverNode->Name.Buffer = PaToVa(DriverNode->Name.Buffer);
}
else
{
- // Loading failed - cry loudly
- ERR("Can't load boot driver '%wZ'!\n", &BootDriver->FilePath);
- UiMessageBox("Can't load boot driver '%wZ'!", &BootDriver->FilePath);
+ /* Loading failed: cry loudly */
+ ERR("Cannot load boot driver '%wZ'!\n", &BootDriver->FilePath);
+ UiMessageBox("Cannot load boot driver '%wZ'!", &BootDriver->FilePath);
ret = FALSE;
- // Remove it from the list and try to continue
- RemoveEntryList(NextBd);
+ /* Remove it from the list and try to continue */
+ RemoveEntryList(&BootDriver->Link);
}
-
- NextBd = BootDriver->Link.Flink;
}
return ret;
PVOID
WinLdrLoadModule(PCSTR ModuleName,
- ULONG *Size,
+ PULONG Size,
TYPE_OF_MEMORY MemoryType)
{
ULONG FileId;
ARC_STATUS Status;
ULONG BytesRead;
- //CHAR ProgressString[256];
-
- /* Inform user we are loading files */
- //sprintf(ProgressString, "Loading %s...", FileName);
- //UiDrawProgressBarCenter(1, 100, ProgressString);
-
- TRACE("Loading module %s\n", ModuleName);
*Size = 0;
/* Open the image file */
- Status = ArcOpen((PCHAR)ModuleName, OpenReadOnly, &FileId);
+ NtLdrOutputLoadMsg(ModuleName, NULL);
+ Status = ArcOpen((PSTR)ModuleName, OpenReadOnly, &FileId);
if (Status != ESUCCESS)
{
/* In case of errors, we just return, without complaining to the user */
+ WARN("Error while opening '%s', Status: %u\n", ModuleName, Status);
return NULL;
}
- /* Get this file's size */
+ /* Retrieve its size */
Status = ArcGetFileInformation(FileId, &FileInfo);
if (Status != ESUCCESS)
{
PhysicalBase = MmAllocateMemoryWithType(FileSize, MemoryType);
if (PhysicalBase == NULL)
{
+ ERR("Could not allocate memory for '%s'\n", ModuleName);
ArcClose(FileId);
return NULL;
}
- /* Load whole file */
+ /* Load the whole file */
Status = ArcRead(FileId, PhysicalBase, FileSize, &BytesRead);
ArcClose(FileId);
if (Status != ESUCCESS)
{
+ WARN("Error while reading '%s', Status: %u\n", ModuleName, Status);
return NULL;
}
LONG rc;
HKEY hKey;
- rc = RegOpenKey(
- NULL,
- L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Terminal Server",
- &hKey);
+ rc = RegOpenKey(CurrentControlSetKey, L"Control\\Terminal Server", &hKey);
if (rc != ERROR_SUCCESS)
{
- // Key doesn't exist; assume NT 4.0
+ /* Key doesn't exist; assume NT 4.0 */
return _WIN32_WINNT_NT4;
}
+ RegCloseKey(hKey);
- // We may here want to read the value of ProductVersion
+ /* We may here want to read the value of ProductVersion */
return _WIN32_WINNT_WS03;
}
static
-BOOLEAN
+PVOID
LoadModule(
IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
IN PCCH Path,
BOOLEAN Success;
CHAR FullFileName[MAX_PATH];
CHAR ProgressString[256];
- PVOID BaseAddress = NULL;
+ PVOID BaseAddress;
- UiDrawBackdrop();
- sprintf(ProgressString, "Loading %s...", File);
- UiDrawProgressBarCenter(Percentage, 100, ProgressString);
+ RtlStringCbPrintfA(ProgressString, sizeof(ProgressString), "Loading %s...", File);
+ UiUpdateProgressBar(Percentage, ProgressString);
- strcpy(FullFileName, Path);
- strcat(FullFileName, File);
+ RtlStringCbCopyA(FullFileName, sizeof(FullFileName), Path);
+ RtlStringCbCatA(FullFileName, sizeof(FullFileName), File);
- Success = WinLdrLoadImage(FullFileName, MemoryType, &BaseAddress);
+ NtLdrOutputLoadMsg(FullFileName, NULL);
+ Success = PeLdrLoadImage(FullFileName, MemoryType, &BaseAddress);
if (!Success)
{
- TRACE("Loading %s failed\n", File);
- return FALSE;
+ ERR("PeLdrLoadImage('%s') failed\n", File);
+ return NULL;
}
TRACE("%s loaded successfully at %p\n", File, BaseAddress);
- /*
- * Cheat about the base DLL name if we are loading
- * the Kernel Debugger Transport DLL, to make the
- * PE loader happy.
- */
- Success = WinLdrAllocateDataTableEntry(&LoaderBlock->LoadOrderListHead,
- ImportName,
- FullFileName,
- BaseAddress,
- Dte);
+ Success = PeLdrAllocateDataTableEntry(&LoaderBlock->LoadOrderListHead,
+ ImportName,
+ FullFileName,
+ BaseAddress,
+ Dte);
+ if (!Success)
+ {
+ /* Cleanup and bail out */
+ ERR("PeLdrAllocateDataTableEntry('%s') failed\n", FullFileName);
+ MmFreeMemory(BaseAddress);
+ return NULL;
+ }
- return Success;
+ /* Init security cookie */
+ PeLdrInitSecurityCookie(*Dte);
+
+ return BaseAddress;
}
+#ifdef _M_IX86
+static
+BOOLEAN
+WinLdrIsPaeSupported(
+ _In_ USHORT OperatingSystemVersion,
+ _In_ PLOADER_PARAMETER_BLOCK LoaderBlock,
+ _In_ PCSTR BootOptions,
+ _In_ PCSTR HalFileName,
+ _Inout_updates_bytes_(KernelFileNameSize) _Always_(_Post_z_)
+ PSTR KernelFileName,
+ _In_ SIZE_T KernelFileNameSize)
+{
+ BOOLEAN PaeEnabled = FALSE;
+ BOOLEAN PaeDisabled = FALSE;
+ BOOLEAN Result;
+
+ if ((OperatingSystemVersion > _WIN32_WINNT_NT4) &&
+ NtLdrGetOption(BootOptions, "PAE"))
+ {
+ /* We found the PAE option */
+ PaeEnabled = TRUE;
+ }
+
+ Result = PaeEnabled;
+
+ if ((OperatingSystemVersion > _WIN32_WINNT_WIN2K) &&
+ NtLdrGetOption(BootOptions, "NOPAE"))
+ {
+ PaeDisabled = TRUE;
+ }
+
+ if (SafeBoot)
+ PaeDisabled = TRUE;
+
+ TRACE("PaeEnabled %X, PaeDisabled %X\n", PaeEnabled, PaeDisabled);
+
+ if (PaeDisabled)
+ Result = FALSE;
+
+ /* Enable PAE if DEP is enabled */
+ if (NoExecuteEnabled)
+ Result = TRUE;
+
+ // TODO: checks for CPU support, hotplug memory support ... other tests
+ // TODO: select kernel name ("ntkrnlpa.exe" or "ntoskrnl.exe"), or,
+ // if KernelFileName is a user-specified kernel file, check whether it
+ // has, if PAE needs to be enabled, the IMAGE_FILE_LARGE_ADDRESS_AWARE
+ // Characteristics bit set, and that the HAL image has a similar support.
+
+ if (Result) UNIMPLEMENTED;
+
+ return Result;
+}
+#endif /* _M_IX86 */
+
static
BOOLEAN
LoadWindowsCore(IN USHORT OperatingSystemVersion,
IN OUT PLDR_DATA_TABLE_ENTRY* KernelDTE)
{
BOOLEAN Success;
- PCSTR Options;
+ PCSTR Option;
+ ULONG OptionLength;
+ PVOID KernelBase, HalBase, KdDllBase = NULL;
+ PLDR_DATA_TABLE_ENTRY HalDTE, KdDllDTE = NULL;
CHAR DirPath[MAX_PATH];
- CHAR KernelFileName[MAX_PATH];
CHAR HalFileName[MAX_PATH];
- CHAR KdTransportDllName[MAX_PATH];
- PLDR_DATA_TABLE_ENTRY HalDTE, KdComDTE = NULL;
+ CHAR KernelFileName[MAX_PATH];
+ CHAR KdDllName[MAX_PATH];
if (!KernelDTE) return FALSE;
/* Initialize SystemRoot\System32 path */
- strcpy(DirPath, BootPath);
- strcat(DirPath, "system32\\");
+ RtlStringCbCopyA(DirPath, sizeof(DirPath), BootPath);
+ RtlStringCbCatA(DirPath, sizeof(DirPath), "system32\\");
- //
- // TODO: Parse also the separate INI values "Kernel=" and "Hal="
- //
+ /* Parse the boot options */
+ TRACE("LoadWindowsCore: BootOptions '%s'\n", BootOptions);
+
+#ifdef _M_IX86
+ if (NtLdrGetOption(BootOptions, "3GB"))
+ {
+ /* We found the 3GB option. */
+ FIXME("LoadWindowsCore: 3GB - TRUE (not implemented)\n");
+ VirtualBias = TRUE;
+ }
+ // TODO: "USERVA=" for XP/2k3
+#endif
+
+ if ((OperatingSystemVersion > _WIN32_WINNT_NT4) &&
+ (NtLdrGetOption(BootOptions, "SAFEBOOT") ||
+ NtLdrGetOption(BootOptions, "SAFEBOOT:")))
+ {
+ /* We found the SAFEBOOT option. */
+ FIXME("LoadWindowsCore: SAFEBOOT - TRUE (not implemented)\n");
+ SafeBoot = TRUE;
+ }
- /* Default KERNEL and HAL file names */
- strcpy(KernelFileName, "ntoskrnl.exe");
- strcpy(HalFileName , "hal.dll");
+ if ((OperatingSystemVersion > _WIN32_WINNT_WIN2K) &&
+ NtLdrGetOption(BootOptions, "BOOTLOGO"))
+ {
+ /* We found the BOOTLOGO option. */
+ FIXME("LoadWindowsCore: BOOTLOGO - TRUE (not implemented)\n");
+ BootLogo = TRUE;
+ }
- /* Find any /KERNEL= or /HAL= switch in the boot options */
- Options = BootOptions;
- while (Options)
+ /* Check the (NO)EXECUTE options */
+ if ((OperatingSystemVersion > _WIN32_WINNT_WIN2K) &&
+ !LoaderBlock->SetupLdrBlock)
{
- /* Skip possible initial whitespace */
- Options += strspn(Options, " \t");
+ /* Disable NX by default on x86, otherwise enable it */
+#ifdef _M_IX86
+ NoExecuteEnabled = FALSE;
+#else
+ NoExecuteEnabled = TRUE;
+#endif
- /* Check whether a new commutator starts and it is either KERNEL or HAL */
- if (*Options != '/' || (++Options,
- !(_strnicmp(Options, "KERNEL=", 7) == 0 ||
- _strnicmp(Options, "HAL=", 4) == 0)) )
+#ifdef _M_IX86
+ /* Check the options in decreasing order of precedence */
+ if (NtLdrGetOption(BootOptions, "NOEXECUTE=OPTIN") ||
+ NtLdrGetOption(BootOptions, "NOEXECUTE=OPTOUT") ||
+ NtLdrGetOption(BootOptions, "NOEXECUTE=ALWAYSON"))
{
- /* Search for another whitespace */
- Options = strpbrk(Options, " \t");
- continue;
+ NoExecuteEnabled = TRUE;
}
+ else if (NtLdrGetOption(BootOptions, "NOEXECUTE=ALWAYSOFF"))
+ NoExecuteEnabled = FALSE;
else
- {
- size_t i = strcspn(Options, " \t"); /* Skip whitespace */
- if (i == 0)
- {
- /* Use the default values */
- break;
- }
+#else
+ /* Only the following two options really apply for x64 and other platforms */
+#endif
+ if (NtLdrGetOption(BootOptions, "NOEXECUTE"))
+ NoExecuteEnabled = TRUE;
+ else if (NtLdrGetOption(BootOptions, "EXECUTE"))
+ NoExecuteEnabled = FALSE;
- /* We have found either KERNEL or HAL commutator */
- if (_strnicmp(Options, "KERNEL=", 7) == 0)
- {
- Options += 7; i -= 7;
- strncpy(KernelFileName, Options, i);
- KernelFileName[i] = ANSI_NULL;
- _strupr(KernelFileName);
- }
- else if (_strnicmp(Options, "HAL=", 4) == 0)
- {
- Options += 4; i -= 4;
- strncpy(HalFileName, Options, i);
- HalFileName[i] = ANSI_NULL;
- _strupr(HalFileName);
- }
- }
+#ifdef _M_IX86
+ /* Disable DEP in SafeBoot mode for x86 only */
+ if (SafeBoot)
+ NoExecuteEnabled = FALSE;
+#endif
}
+ TRACE("NoExecuteEnabled %X\n", NoExecuteEnabled);
- TRACE("Kernel file = '%s' ; HAL file = '%s'\n", KernelFileName, HalFileName);
+ /*
+ * Select the HAL and KERNEL file names.
+ * Check for any "/HAL=" or "/KERNEL=" override option.
+ *
+ * See the following links to know how the file names are actually chosen:
+ * https://www.geoffchappell.com/notes/windows/boot/bcd/osloader/detecthal.htm
+ * https://www.geoffchappell.com/notes/windows/boot/bcd/osloader/hal.htm
+ * https://www.geoffchappell.com/notes/windows/boot/bcd/osloader/kernel.htm
+ */
+ /* Default HAL and KERNEL file names */
+ RtlStringCbCopyA(HalFileName , sizeof(HalFileName) , "hal.dll");
+ RtlStringCbCopyA(KernelFileName, sizeof(KernelFileName), "ntoskrnl.exe");
+
+ Option = NtLdrGetOptionEx(BootOptions, "HAL=", &OptionLength);
+ if (Option && (OptionLength > 4))
+ {
+ /* Retrieve the HAL file name */
+ Option += 4; OptionLength -= 4;
+ RtlStringCbCopyNA(HalFileName, sizeof(HalFileName), Option, OptionLength);
+ _strlwr(HalFileName);
+ }
+
+ Option = NtLdrGetOptionEx(BootOptions, "KERNEL=", &OptionLength);
+ if (Option && (OptionLength > 7))
+ {
+ /* Retrieve the KERNEL file name */
+ Option += 7; OptionLength -= 7;
+ RtlStringCbCopyNA(KernelFileName, sizeof(KernelFileName), Option, OptionLength);
+ _strlwr(KernelFileName);
+ }
+
+#ifdef _M_IX86
+ /* Check for PAE support and select the adequate kernel image */
+ PaeModeOn = WinLdrIsPaeSupported(OperatingSystemVersion,
+ LoaderBlock,
+ BootOptions,
+ HalFileName,
+ KernelFileName,
+ sizeof(KernelFileName));
+ if (PaeModeOn) FIXME("WinLdrIsPaeSupported: PaeModeOn\n");
+#endif
+
+ TRACE("HAL file = '%s' ; Kernel file = '%s'\n", HalFileName, KernelFileName);
+
+ /*
+ * Load the core NT files: Kernel, HAL and KD transport DLL.
+ * Cheat about their base DLL name so as to satisfy the imports/exports,
+ * even if the corresponding underlying files do not have the same names
+ * -- this happens e.g. with UP vs. MP kernel, standard vs. ACPI hal, or
+ * different KD transport DLLs.
+ */
/* Load the Kernel */
- LoadModule(LoaderBlock, DirPath, KernelFileName, "ntoskrnl.exe", LoaderSystemCode, KernelDTE, 30);
+ KernelBase = LoadModule(LoaderBlock, DirPath, KernelFileName,
+ "ntoskrnl.exe", LoaderSystemCode, KernelDTE, 30);
+ if (!KernelBase)
+ {
+ ERR("LoadModule('%s') failed\n", KernelFileName);
+ UiMessageBox("Could not load %s", KernelFileName);
+ return FALSE;
+ }
/* Load the HAL */
- LoadModule(LoaderBlock, DirPath, HalFileName, "hal.dll", LoaderHalCode, &HalDTE, 45);
+ HalBase = LoadModule(LoaderBlock, DirPath, HalFileName,
+ "hal.dll", LoaderHalCode, &HalDTE, 35);
+ if (!HalBase)
+ {
+ ERR("LoadModule('%s') failed\n", HalFileName);
+ UiMessageBox("Could not load %s", HalFileName);
+ PeLdrFreeDataTableEntry(*KernelDTE);
+ MmFreeMemory(KernelBase);
+ return FALSE;
+ }
/* Load the Kernel Debugger Transport DLL */
if (OperatingSystemVersion > _WIN32_WINNT_WIN2K)
*/
/*
- * 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).
+ * A Kernel Debugger Transport DLL is always loaded for Windows XP+ :
+ * either the standard KDCOM.DLL (by default): IsCustomKdDll == FALSE
+ * or an alternative user-provided one via the /DEBUGPORT= option:
+ * IsCustomKdDll == TRUE if it does not specify the default KDCOM.
*/
- Options = BootOptions;
- while (Options)
+ BOOLEAN IsCustomKdDll = FALSE;
+
+ /* Check whether there is a DEBUGPORT option */
+ Option = NtLdrGetOptionEx(BootOptions, "DEBUGPORT=", &OptionLength);
+ if (Option && (OptionLength > 10))
{
- /* Skip possible initial whitespace */
- Options += strspn(Options, " \t");
+ /* Move to the debug port name */
+ Option += 10; OptionLength -= 10;
+
+ /*
+ * Parse the port name.
+ * Format: /DEBUGPORT=COM[0-9]
+ * or: /DEBUGPORT=FILE:\Device\HarddiskX\PartitionY\debug.log
+ * or: /DEBUGPORT=FOO
+ * If we only have /DEBUGPORT= (i.e. without any port name),
+ * default to "COM".
+ */
- /* Check whether a new commutator starts and it is the DEBUGPORT one */
- if (*Options != '/' || _strnicmp(++Options, "DEBUGPORT=", 10) != 0)
+ /* Get the actual length of the debug port
+ * until the next whitespace or colon. */
+ OptionLength = (ULONG)strcspn(Option, " \t:");
+
+ if ((OptionLength == 0) ||
+ ( (OptionLength >= 3) && (_strnicmp(Option, "COM", 3) == 0) &&
+ ((OptionLength == 3) || ('0' <= Option[3] && Option[3] <= '9')) ))
{
- /* Search for another whitespace */
- Options = strpbrk(Options, " \t");
- continue;
+ /* The standard KDCOM.DLL is used */
}
else
{
- /* We found the DEBUGPORT commutator. Move to the port name. */
- Options += 10;
- break;
+ /* A custom KD DLL is used */
+ IsCustomKdDll = TRUE;
}
}
+ if (!IsCustomKdDll)
+ {
+ Option = "COM"; OptionLength = 3;
+ }
+
+ RtlStringCbPrintfA(KdDllName, sizeof(KdDllName), "kd%.*s.dll",
+ OptionLength, Option);
+ _strlwr(KdDllName);
- if (Options)
+ /* Load the KD DLL. Override its base DLL name to the default "KDCOM.DLL". */
+ KdDllBase = LoadModule(LoaderBlock, DirPath, KdDllName,
+ "kdcom.dll", LoaderSystemCode, &KdDllDTE, 40);
+ if (!KdDllBase)
{
- /*
- * 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(Options, "COM", 3) == 0 && '0' <= Options[3] && Options[3] <= '9')
+ /* If we failed to load a custom KD DLL, fall back to the standard one */
+ if (IsCustomKdDll)
{
- strncat(KdTransportDllName, Options, 3);
+ /* The custom KD DLL being optional, just ignore the failure */
+ WARN("LoadModule('%s') failed\n", KdDllName);
+
+ IsCustomKdDll = FALSE;
+ RtlStringCbCopyA(KdDllName, sizeof(KdDllName), "kdcom.dll");
+
+ KdDllBase = LoadModule(LoaderBlock, DirPath, KdDllName,
+ "kdcom.dll", LoaderSystemCode, &KdDllDTE, 40);
}
- else
+
+ if (!KdDllBase)
{
- size_t i = strcspn(Options, " \t:"); /* Skip valid separators: whitespace or colon */
- if (i == 0)
- strcat(KdTransportDllName, "COM");
- else
- strncat(KdTransportDllName, Options, i);
+ /* Ignore the failure; we will fail later when scanning the
+ * kernel import tables, if it really needs the KD DLL. */
+ ERR("LoadModule('%s') failed\n", KdDllName);
}
- strcat(KdTransportDllName, ".DLL");
- _strupr(KdTransportDllName);
-
- /*
- * Load the transport DLL. Override the base DLL name of the
- * loaded transport DLL to the default "KDCOM.DLL" name.
- */
- LoadModule(LoaderBlock, DirPath, KdTransportDllName, "kdcom.dll", LoaderSystemCode, &KdComDTE, 60);
}
}
/* Load all referenced DLLs for Kernel, HAL and Kernel Debugger Transport DLL */
- Success = WinLdrScanImportDescriptorTable(&LoaderBlock->LoadOrderListHead, DirPath, *KernelDTE);
- Success &= WinLdrScanImportDescriptorTable(&LoaderBlock->LoadOrderListHead, DirPath, HalDTE);
- if (KdComDTE)
+ Success = PeLdrScanImportDescriptorTable(&LoaderBlock->LoadOrderListHead, DirPath, *KernelDTE);
+ if (!Success)
+ {
+ UiMessageBox("Could not load %s", KernelFileName);
+ goto Quit;
+ }
+ Success = PeLdrScanImportDescriptorTable(&LoaderBlock->LoadOrderListHead, DirPath, HalDTE);
+ if (!Success)
+ {
+ UiMessageBox("Could not load %s", HalFileName);
+ goto Quit;
+ }
+ if (KdDllDTE)
+ {
+ Success = PeLdrScanImportDescriptorTable(&LoaderBlock->LoadOrderListHead, DirPath, KdDllDTE);
+ if (!Success)
+ {
+ UiMessageBox("Could not load %s", KdDllName);
+ goto Quit;
+ }
+ }
+
+Quit:
+ if (!Success)
{
- Success &= WinLdrScanImportDescriptorTable(&LoaderBlock->LoadOrderListHead, DirPath, KdComDTE);
+ /* Cleanup and bail out */
+ if (KdDllDTE)
+ PeLdrFreeDataTableEntry(KdDllDTE);
+ if (KdDllBase) // Optional
+ MmFreeMemory(KdDllBase);
+
+ PeLdrFreeDataTableEntry(HalDTE);
+ MmFreeMemory(HalBase);
+
+ PeLdrFreeDataTableEntry(*KernelDTE);
+ MmFreeMemory(KernelBase);
}
return Success;
}
-VOID
-LoadAndBootWindows(IN OperatingSystemItem* OperatingSystem,
- IN USHORT OperatingSystemVersion)
+static
+BOOLEAN
+WinLdrInitErrataInf(
+ IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
+ IN USHORT OperatingSystemVersion,
+ IN PCSTR SystemRoot)
+{
+ LONG rc;
+ HKEY hKey;
+ ULONG BufferSize;
+ ULONG FileSize;
+ PVOID PhysicalBase;
+ WCHAR szFileName[80];
+ CHAR ErrataFilePath[MAX_PATH];
+
+ /* Open either the 'BiosInfo' (Windows <= 2003) or the 'Errata' (Vista+) key */
+ if (OperatingSystemVersion >= _WIN32_WINNT_VISTA)
+ {
+ rc = RegOpenKey(CurrentControlSetKey, L"Control\\Errata", &hKey);
+ }
+ else // (OperatingSystemVersion <= _WIN32_WINNT_WS03)
+ {
+ rc = RegOpenKey(CurrentControlSetKey, L"Control\\BiosInfo", &hKey);
+ }
+ if (rc != ERROR_SUCCESS)
+ {
+ WARN("Could not open the BiosInfo/Errata registry key (Error %u)\n", (int)rc);
+ return FALSE;
+ }
+
+ /* Retrieve the INF file name value */
+ BufferSize = sizeof(szFileName);
+ rc = RegQueryValue(hKey, L"InfName", NULL, (PUCHAR)szFileName, &BufferSize);
+ if (rc != ERROR_SUCCESS)
+ {
+ WARN("Could not retrieve the InfName value (Error %u)\n", (int)rc);
+ RegCloseKey(hKey);
+ return FALSE;
+ }
+
+ // TODO: "SystemBiosDate"
+
+ RegCloseKey(hKey);
+
+ RtlStringCbPrintfA(ErrataFilePath, sizeof(ErrataFilePath), "%s%s%S",
+ SystemRoot, "inf\\", szFileName);
+
+ /* Load the INF file */
+ PhysicalBase = WinLdrLoadModule(ErrataFilePath, &FileSize, LoaderRegistryData);
+ if (!PhysicalBase)
+ {
+ WARN("Could not load '%s'\n", ErrataFilePath);
+ return FALSE;
+ }
+
+ LoaderBlock->Extension->EmInfFileImage = PaToVa(PhysicalBase);
+ LoaderBlock->Extension->EmInfFileSize = FileSize;
+
+ return TRUE;
+}
+
+ARC_STATUS
+LoadAndBootWindows(
+ IN ULONG Argc,
+ IN PCHAR Argv[],
+ IN PCHAR Envp[])
{
- ULONG_PTR SectionId;
- PCSTR SectionName = OperatingSystem->SystemPartition;
- CHAR SettingsValue[80];
- BOOLEAN HasSection;
- CHAR BootPath[MAX_PATH];
- CHAR FileName[MAX_PATH];
- CHAR BootOptions[256];
- PCHAR File;
+ ARC_STATUS Status;
+ PCSTR ArgValue;
+ PCSTR SystemPartition;
+ PCSTR FileName;
+ ULONG FileNameLength;
BOOLEAN Success;
+ USHORT OperatingSystemVersion;
PLOADER_PARAMETER_BLOCK LoaderBlock;
+ CHAR BootPath[MAX_PATH];
+ CHAR FilePath[MAX_PATH];
+ CHAR BootOptions[256];
- /* 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(SectionName, &SectionId);
+ /* Retrieve the (mandatory) boot type */
+ ArgValue = GetArgumentValue(Argc, Argv, "BootType");
+ if (!ArgValue || !*ArgValue)
+ {
+ ERR("No 'BootType' value, aborting!\n");
+ return EINVAL;
+ }
- UiDrawBackdrop();
- UiDrawProgressBarCenter(1, 100, "Loading NT...");
+ /* Convert it to an OS version */
+ if (_stricmp(ArgValue, "Windows") == 0 ||
+ _stricmp(ArgValue, "Windows2003") == 0)
+ {
+ OperatingSystemVersion = _WIN32_WINNT_WS03;
+ }
+ else if (_stricmp(ArgValue, "WindowsNT40") == 0)
+ {
+ OperatingSystemVersion = _WIN32_WINNT_NT4;
+ }
+ else
+ {
+ ERR("Unknown 'BootType' value '%s', aborting!\n", ArgValue);
+ return EINVAL;
+ }
- /* Read the system path is set in the .ini file */
- if (!HasSection ||
- !IniReadSettingByName(SectionId, "SystemPath", BootPath, sizeof(BootPath)))
+ /* Retrieve the (mandatory) system partition */
+ SystemPartition = GetArgumentValue(Argc, Argv, "SystemPartition");
+ if (!SystemPartition || !*SystemPartition)
{
- strcpy(BootPath, SectionName);
+ ERR("No 'SystemPartition' specified, aborting!\n");
+ return EINVAL;
}
+ /* Let the user know we started loading */
+ UiDrawBackdrop();
+ UiDrawStatusText("Loading...");
+ UiDrawProgressBarCenter("Loading NT...");
+
+ /* Retrieve the system path */
+ *BootPath = ANSI_NULL;
+ ArgValue = GetArgumentValue(Argc, Argv, "SystemPath");
+ if (ArgValue)
+ RtlStringCbCopyA(BootPath, sizeof(BootPath), ArgValue);
+
/*
* Check whether BootPath is a full path
* and if not, create a full boot path.
if (strrchr(BootPath, ')') == NULL)
{
/* Temporarily save the boot path */
- strcpy(FileName, BootPath);
+ RtlStringCbCopyA(FilePath, sizeof(FilePath), BootPath);
- /* This is not a full path. Use the current (i.e. boot) device. */
- MachDiskGetBootPath(BootPath, sizeof(BootPath));
+ /* This is not a full path: prepend the SystemPartition */
+ RtlStringCbCopyA(BootPath, sizeof(BootPath), SystemPartition);
/* Append a path separator if needed */
- if (FileName[0] != '\\' && FileName[0] != '/')
- strcat(BootPath, "\\");
+ if (*FilePath != '\\' && *FilePath != '/')
+ RtlStringCbCatA(BootPath, sizeof(BootPath), "\\");
/* Append the remaining path */
- strcat(BootPath, FileName);
+ RtlStringCbCatA(BootPath, sizeof(BootPath), FilePath);
}
- /* Append a backslash if needed */
- if ((BootPath[0] == 0) || BootPath[strlen(BootPath) - 1] != '\\')
- strcat(BootPath, "\\");
+ /* Append a path separator if needed */
+ if (!*BootPath || BootPath[strlen(BootPath) - 1] != '\\')
+ RtlStringCbCatA(BootPath, sizeof(BootPath), "\\");
- /* Read booting options */
- if (!HasSection || !IniReadSettingByName(SectionId, "Options", BootOptions, sizeof(BootOptions)))
- {
- /* Get options after the title */
- PCSTR p = SettingsValue;
- while (*p == ' ' || *p == '"')
- p++;
- while (*p != '\0' && *p != '"')
- p++;
- strcpy(BootOptions, p);
- TRACE("BootOptions: '%s'\n", BootOptions);
- }
+ TRACE("BootPath: '%s'\n", BootPath);
+
+ /* Retrieve the boot options */
+ *BootOptions = ANSI_NULL;
+ ArgValue = GetArgumentValue(Argc, Argv, "Options");
+ if (ArgValue && *ArgValue)
+ RtlStringCbCopyA(BootOptions, sizeof(BootOptions), ArgValue);
/* Append boot-time options */
AppendBootTimeOptions(BootOptions);
- /* Check if a ramdisk file was given */
- File = strstr(BootOptions, "/RDPATH=");
- if (File)
+ /*
+ * Set the "/HAL=" and "/KERNEL=" options if needed.
+ * If already present on the standard "Options=" option line, they take
+ * precedence over those passed via the separate "Hal=" and "Kernel="
+ * options.
+ */
+ if (!NtLdrGetOption(BootOptions, "HAL="))
+ {
+ /*
+ * Not found in the options, try to retrieve the
+ * separate value and append it to the options.
+ */
+ ArgValue = GetArgumentValue(Argc, Argv, "Hal");
+ if (ArgValue && *ArgValue)
+ {
+ RtlStringCbCatA(BootOptions, sizeof(BootOptions), " /HAL=");
+ RtlStringCbCatA(BootOptions, sizeof(BootOptions), ArgValue);
+ }
+ }
+ if (!NtLdrGetOption(BootOptions, "KERNEL="))
{
- /* Copy the file name and everything else after it */
- strcpy(FileName, File + 8);
+ /*
+ * Not found in the options, try to retrieve the
+ * separate value and append it to the options.
+ */
+ ArgValue = GetArgumentValue(Argc, Argv, "Kernel");
+ if (ArgValue && *ArgValue)
+ {
+ RtlStringCbCatA(BootOptions, sizeof(BootOptions), " /KERNEL=");
+ RtlStringCbCatA(BootOptions, sizeof(BootOptions), ArgValue);
+ }
+ }
- /* Null-terminate */
- *strstr(FileName, " ") = ANSI_NULL;
+ TRACE("BootOptions: '%s'\n", BootOptions);
- /* Load the ramdisk */
- if (!RamDiskLoadVirtualFile(FileName))
+ /* Check if a RAM disk file was given */
+ FileName = NtLdrGetOptionEx(BootOptions, "RDPATH=", &FileNameLength);
+ if (FileName && (FileNameLength > 7))
+ {
+ /* Load the RAM disk */
+ Status = RamDiskInitialize(FALSE, BootOptions, SystemPartition);
+ if (Status != ESUCCESS)
{
- UiMessageBox("Failed to load RAM disk file %s", FileName);
- return;
+ FileName += 7; FileNameLength -= 7;
+ UiMessageBox("Failed to load RAM disk file '%.*s'",
+ FileNameLength, FileName);
+ return Status;
}
}
- /* Let user know we started loading */
- //UiDrawStatusText("Loading...");
+ /* Handle the SOS option */
+ SosEnabled = !!NtLdrGetOption(BootOptions, "SOS");
+ if (SosEnabled)
+ UiResetForSOS();
- TRACE("BootPath: '%s'\n", BootPath);
-
- /* Allocate and minimalist-initialize LPB */
- AllocateAndInitLPB(&LoaderBlock);
+ /* Allocate and minimally-initialize the Loader Parameter Block */
+ AllocateAndInitLPB(OperatingSystemVersion, &LoaderBlock);
/* Load the system hive */
- UiDrawBackdrop();
- UiDrawProgressBarCenter(15, 100, "Loading system hive...");
- Success = WinLdrInitSystemHive(LoaderBlock, BootPath);
+ UiUpdateProgressBar(15, "Loading system hive...");
+ Success = WinLdrInitSystemHive(LoaderBlock, BootPath, FALSE);
TRACE("SYSTEM hive %s\n", (Success ? "loaded" : "not loaded"));
/* Bail out if failure */
if (!Success)
- return;
+ return ENOEXEC;
+
+ /* Fixup the version number using data from the registry */
+ if (OperatingSystemVersion == 0)
+ OperatingSystemVersion = WinLdrDetectVersion();
+ LoaderBlock->Extension->MajorVersion = (OperatingSystemVersion & 0xFF00) >> 8;
+ LoaderBlock->Extension->MinorVersion = (OperatingSystemVersion & 0xFF);
/* Load NLS data, OEM font, and prepare boot drivers list */
Success = WinLdrScanSystemHive(LoaderBlock, BootPath);
TRACE("SYSTEM hive %s\n", (Success ? "scanned" : "not scanned"));
/* Bail out if failure */
if (!Success)
- return;
+ return ENOEXEC;
+
+ /* Load the Firmware Errata file */
+ Success = WinLdrInitErrataInf(LoaderBlock, OperatingSystemVersion, BootPath);
+ TRACE("Firmware Errata file %s\n", (Success ? "loaded" : "not loaded"));
+ /* Not necessarily fatal if not found - carry on going */
/* Finish loading */
- LoadAndBootWindowsCommon(OperatingSystemVersion,
- LoaderBlock,
- BootOptions,
- BootPath,
- FALSE);
+ return LoadAndBootWindowsCommon(OperatingSystemVersion,
+ LoaderBlock,
+ BootOptions,
+ BootPath);
}
-VOID
+ARC_STATUS
LoadAndBootWindowsCommon(
- USHORT OperatingSystemVersion,
- PLOADER_PARAMETER_BLOCK LoaderBlock,
- LPCSTR BootOptions,
- LPCSTR BootPath,
- BOOLEAN Setup)
+ IN USHORT OperatingSystemVersion,
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock,
+ IN PCSTR BootOptions,
+ IN PCSTR BootPath)
{
PLOADER_PARAMETER_BLOCK LoaderBlockVA;
BOOLEAN Success;
PLDR_DATA_TABLE_ENTRY KernelDTE;
KERNEL_ENTRY_POINT KiSystemStartup;
- LPCSTR SystemRoot;
+ PCSTR SystemRoot;
+
TRACE("LoadAndBootWindowsCommon()\n");
+ ASSERT(OperatingSystemVersion != 0);
+
#ifdef _M_IX86
/* Setup redirection support */
- WinLdrSetupEms((PCHAR)BootOptions);
+ WinLdrSetupEms(BootOptions);
#endif
/* Convert BootPath to SystemRoot */
SystemRoot = strstr(BootPath, "\\");
/* Detect hardware */
- UiDrawBackdrop();
- UiDrawProgressBarCenter(20, 100, "Detecting hardware...");
- LoaderBlock->ConfigurationRoot = MachHwDetect();
+ UiUpdateProgressBar(20, "Detecting hardware...");
+ LoaderBlock->ConfigurationRoot = MachHwDetect(BootOptions);
- if (OperatingSystemVersion == 0)
- OperatingSystemVersion = WinLdrDetectVersion();
+ /* 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,
&KernelDTE);
if (!Success)
{
+ /* Reset the PE loader import-DLL callback */
+ PeLdrImportDllLoadCallback = NULL;
+
UiMessageBox("Error loading NTOS core.");
- return;
+ return ENOEXEC;
}
+ /* Cleanup INI file */
+ IniCleanup();
+
+/****
+ **** WE HAVE NOW REACHED THE POINT OF NO RETURN !!
+ ****/
+
+ UiSetProgressBarSubset(40, 90); // NTOS goes from 25 to 75%
+
/* Load boot drivers */
- UiDrawBackdrop();
- UiDrawProgressBarCenter(100, 100, "Loading boot drivers...");
+ UiSetProgressBarText("Loading boot drivers...");
Success = WinLdrLoadBootDrivers(LoaderBlock, BootPath);
TRACE("Boot drivers loading %s\n", Success ? "successful" : "failed");
+ UiSetProgressBarSubset(0, 100);
+
+ /* Reset the PE loader import-DLL callback */
+ PeLdrImportDllLoadCallback = NULL;
+
/* Initialize Phase 1 - no drivers loading anymore */
WinLdrInitializePhase1(LoaderBlock,
BootOptions,
BootPath,
OperatingSystemVersion);
+ UiUpdateProgressBar(100, NULL);
+
/* Save entry-point pointer and Loader block VAs */
KiSystemStartup = (KERNEL_ENTRY_POINT)KernelDTE->EntryPoint;
LoaderBlockVA = PaToVa(LoaderBlock);
/* "Stop all motors", change videomode */
- MachPrepareForReactOS(Setup);
-
- /* Cleanup ini file */
- IniCleanup();
+ MachPrepareForReactOS();
/* Debugging... */
//DumpMemoryAllocMap();
TRACE("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);
+ /* Zero KI_USER_SHARED_DATA page */
+ RtlZeroMemory((PVOID)KI_USER_SHARED_DATA, MM_PAGE_SIZE);
WinLdrpDumpMemoryDescriptors(LoaderBlockVA);
WinLdrpDumpBootDriver(LoaderBlockVA);
/* Pass control */
(*KiSystemStartup)(LoaderBlockVA);
+
+ UNREACHABLE; // return ESUCCESS;
}
VOID