/*
- * 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 "registry.h"
-#include <ndk/ldrtypes.h>
-
#include <debug.h>
DBG_DEFAULT_CHANNEL(WINDOWS);
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)";
+ */
PSTR LoadOptions, NewLoadOptions;
CHAR HalPath[] = "\\";
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
RtlStringCbPrintfA(FullPath, sizeof(FullPath), "%s%wZ", BootPath, FilePath);
- Success = WinLdrLoadImage(FullPath, LoaderBootDriver, &DriverBase);
+ Success = PeLdrLoadImage(FullPath, LoaderBootDriver, &DriverBase);
if (!Success)
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");
+ ERR("PeLdrAllocateDataTableEntry() failed\n");
return FALSE;
}
// Look for any dependencies it may have, and load them too
RtlStringCbPrintfA(FullPath, sizeof(FullPath), "%s%s", BootPath, DriverPath);
- Success = WinLdrScanImportDescriptorTable(LoadOrderListHead, FullPath, *DriverDTE);
+ Success = PeLdrScanImportDescriptorTable(LoadOrderListHead, FullPath, *DriverDTE);
if (!Success)
{
- ERR("WinLdrScanImportDescriptorTable() failed for %s\n", FullPath);
+ ERR("PeLdrScanImportDescriptorTable() failed for %s\n", FullPath);
return FALSE;
}
*Size = 0;
/* Open the image file */
- Status = ArcOpen((PCHAR)ModuleName, OpenReadOnly, &FileId);
+ Status = ArcOpen((PSTR)ModuleName, OpenReadOnly, &FileId);
if (Status != ESUCCESS)
{
/* In case of errors, we just return, without complaining to the user */
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)
LONG rc;
HKEY hKey;
- rc = RegOpenKey(
- NULL,
- L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Terminal Server",
- &hKey);
+ rc = RegOpenKey(NULL,
+ L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\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;
}
- // We may here want to read the value of ProductVersion
+ /* We may here want to read the value of ProductVersion */
return _WIN32_WINNT_WS03;
}
RtlStringCbCopyA(FullFileName, sizeof(FullFileName), Path);
RtlStringCbCatA(FullFileName, sizeof(FullFileName), File);
- Success = WinLdrLoadImage(FullFileName, MemoryType, &BaseAddress);
+ Success = PeLdrLoadImage(FullFileName, MemoryType, &BaseAddress);
if (!Success)
{
TRACE("Loading %s failed\n", File);
* 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);
return Success;
}
BOOLEAN Success;
PCSTR Options;
CHAR DirPath[MAX_PATH];
- CHAR KernelFileName[MAX_PATH];
CHAR HalFileName[MAX_PATH];
+ CHAR KernelFileName[MAX_PATH];
CHAR KdTransportDllName[MAX_PATH];
PLDR_DATA_TABLE_ENTRY HalDTE, KdComDTE = NULL;
RtlStringCbCopyA(DirPath, sizeof(DirPath), BootPath);
RtlStringCbCatA(DirPath, sizeof(DirPath), "system32\\");
- //
- // TODO: Parse also the separate INI values "Kernel=" and "Hal="
- //
-
- /* Default KERNEL and HAL file names */
- RtlStringCbCopyA(KernelFileName, sizeof(KernelFileName), "ntoskrnl.exe");
+ /*
+ * Default HAL and KERNEL file names.
+ * 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
+ */
RtlStringCbCopyA(HalFileName , sizeof(HalFileName) , "hal.dll");
+ RtlStringCbCopyA(KernelFileName, sizeof(KernelFileName), "ntoskrnl.exe");
- /* Find any /KERNEL= or /HAL= switch in the boot options */
+ /* Find any "/HAL=" or "/KERNEL=" switch in the boot options */
Options = BootOptions;
while (Options)
{
/* Skip possible initial whitespace */
Options += strspn(Options, " \t");
- /* Check whether a new option starts and it is either KERNEL or HAL */
+ /* Check whether a new option starts and it is either HAL or KERNEL */
if (*Options != '/' || (++Options,
- !(_strnicmp(Options, "KERNEL=", 7) == 0 ||
- _strnicmp(Options, "HAL=", 4) == 0)) )
+ !(_strnicmp(Options, "HAL=", 4) == 0 ||
+ _strnicmp(Options, "KERNEL=", 7) == 0)) )
{
/* Search for another whitespace */
Options = strpbrk(Options, " \t");
break;
}
- /* We have found either KERNEL or HAL options */
- if (_strnicmp(Options, "KERNEL=", 7) == 0)
- {
- Options += 7; i -= 7;
- RtlStringCbCopyNA(KernelFileName, sizeof(KernelFileName), Options, i);
- _strupr(KernelFileName);
- }
- else if (_strnicmp(Options, "HAL=", 4) == 0)
+ /* We have found either HAL or KERNEL options */
+ if (_strnicmp(Options, "HAL=", 4) == 0)
{
Options += 4; i -= 4;
RtlStringCbCopyNA(HalFileName, sizeof(HalFileName), Options, i);
_strupr(HalFileName);
}
+ else if (_strnicmp(Options, "KERNEL=", 7) == 0)
+ {
+ Options += 7; i -= 7;
+ RtlStringCbCopyNA(KernelFileName, sizeof(KernelFileName), Options, i);
+ _strupr(KernelFileName);
+ }
}
}
- TRACE("Kernel file = '%s' ; HAL file = '%s'\n", KernelFileName, HalFileName);
+ TRACE("HAL file = '%s' ; Kernel file = '%s'\n", HalFileName, KernelFileName);
/* Load the Kernel */
LoadModule(LoaderBlock, DirPath, KernelFileName, "ntoskrnl.exe", LoaderSystemCode, KernelDTE, 30);
}
/* Load all referenced DLLs for Kernel, HAL and Kernel Debugger Transport DLL */
- Success = WinLdrScanImportDescriptorTable(&LoaderBlock->LoadOrderListHead, DirPath, *KernelDTE);
- Success &= WinLdrScanImportDescriptorTable(&LoaderBlock->LoadOrderListHead, DirPath, HalDTE);
+ Success = PeLdrScanImportDescriptorTable(&LoaderBlock->LoadOrderListHead, DirPath, *KernelDTE);
+ Success &= PeLdrScanImportDescriptorTable(&LoaderBlock->LoadOrderListHead, DirPath, HalDTE);
if (KdComDTE)
{
- Success &= WinLdrScanImportDescriptorTable(&LoaderBlock->LoadOrderListHead, DirPath, KdComDTE);
+ Success &= PeLdrScanImportDescriptorTable(&LoaderBlock->LoadOrderListHead, DirPath, KdComDTE);
}
return Success;
}
+static
+BOOLEAN
+WinLdrInitErrataInf(
+ 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(NULL,
+ L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Errata",
+ &hKey);
+ }
+ else // (OperatingSystemVersion <= _WIN32_WINNT_WS03)
+ {
+ rc = RegOpenKey(NULL,
+ L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\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);
+ return FALSE;
+ }
+
+ // TODO: "SystemBiosDate"
+
+ 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;
+ }
+
+ WinLdrSystemBlock->Extension.EmInfFileImage = PaToVa(PhysicalBase);
+ WinLdrSystemBlock->Extension.EmInfFileSize = FileSize;
+
+ return TRUE;
+}
+
ARC_STATUS
LoadAndBootWindows(
IN ULONG Argc,
IN PCHAR Argv[],
IN PCHAR Envp[])
{
+ ARC_STATUS Status;
PCSTR ArgValue;
+ PCSTR SystemPartition;
PCHAR File;
BOOLEAN Success;
USHORT OperatingSystemVersion;
CHAR FileName[MAX_PATH];
CHAR BootOptions[256];
+ /* Retrieve the (mandatory) boot type */
ArgValue = GetArgumentValue(Argc, Argv, "BootType");
- if (!ArgValue)
+ if (!ArgValue || !*ArgValue)
{
ERR("No 'BootType' value, aborting!\n");
return EINVAL;
}
+ /* Convert it to an OS version */
if (_stricmp(ArgValue, "Windows") == 0 ||
_stricmp(ArgValue, "Windows2003") == 0)
{
return EINVAL;
}
+ /* Retrieve the (mandatory) system partition */
+ SystemPartition = GetArgumentValue(Argc, Argv, "SystemPartition");
+ if (!SystemPartition || !*SystemPartition)
+ {
+ ERR("No 'SystemPartition' specified, aborting!\n");
+ return EINVAL;
+ }
+
UiDrawBackdrop();
UiDrawProgressBarCenter(1, 100, "Loading NT...");
/* Temporarily save the boot path */
RtlStringCbCopyA(FileName, sizeof(FileName), 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 != '\\' && *FileName != '/')
RtlStringCbCatA(BootPath, sizeof(BootPath), FileName);
}
- /* Append a backslash if needed */
+ /* Append a path separator if needed */
if (!*BootPath || BootPath[strlen(BootPath) - 1] != '\\')
RtlStringCbCatA(BootPath, sizeof(BootPath), "\\");
/* Retrieve the boot options */
*BootOptions = ANSI_NULL;
ArgValue = GetArgumentValue(Argc, Argv, "Options");
- if (ArgValue)
+ if (ArgValue && *ArgValue)
RtlStringCbCopyA(BootOptions, sizeof(BootOptions), ArgValue);
/* Append boot-time options */
AppendBootTimeOptions(BootOptions);
+ /*
+ * Set "/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 (strstr(BootOptions, "/HAL=") != 0)
+ {
+ /*
+ * 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 (strstr(BootOptions, "/KERNEL=") != 0)
+ {
+ /*
+ * 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);
+ }
+ }
+
TRACE("BootOptions: '%s'\n", BootOptions);
/* Check if a ramdisk file was given */
*strstr(FileName, " ") = ANSI_NULL;
/* Load the ramdisk */
- if (!RamDiskLoadVirtualFile(FileName))
+ Status = RamDiskLoadVirtualFile(FileName, SystemPartition);
+ if (Status != ESUCCESS)
{
UiMessageBox("Failed to load RAM disk file %s", FileName);
- return ENOENT;
+ return Status;
}
}
if (!Success)
return ENOEXEC;
+ /* Load the Firmware Errata file */
+ Success = WinLdrInitErrataInf(OperatingSystemVersion, BootPath);
+ TRACE("Firmware Errata file %s\n", (Success ? "loaded" : "not loaded"));
+ /* Not necessarily fatal if not found - carry on going */
+
/* Finish loading */
return LoadAndBootWindowsCommon(OperatingSystemVersion,
LoaderBlock,
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);