/*
- * FreeLoader
- *
- * Copyright (C) 2009 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 Setup Loader.
+ * COPYRIGHT: Copyright 2009-2019 Aleksey Bragin <aleksey@reactos.org>
*/
#include <freeldr.h>
-#include "winldr.h"
-
#include <ndk/ldrtypes.h>
#include <arc/setupblk.h>
+#include "winldr.h"
+#include "inffile.h"
+#include "ntldropts.h"
#include <debug.h>
-
DBG_DEFAULT_CHANNEL(WINDOWS);
-#define TAG_BOOT_OPTIONS 'pOtB'
// TODO: Move to .h
-VOID AllocateAndInitLPB(PLOADER_PARAMETER_BLOCK *OutLoaderBlock);
+VOID
+AllocateAndInitLPB(
+ IN USHORT VersionToBoot,
+ OUT PLOADER_PARAMETER_BLOCK* OutLoaderBlock);
static VOID
-SetupLdrLoadNlsData(PLOADER_PARAMETER_BLOCK LoaderBlock, HINF InfHandle, LPCSTR SearchPath)
+SetupLdrLoadNlsData(
+ _Inout_ PLOADER_PARAMETER_BLOCK LoaderBlock,
+ _In_ HINF InfHandle,
+ _In_ PCSTR SearchPath)
{
+ BOOLEAN Success;
INFCONTEXT InfContext;
- LPCSTR AnsiName, OemName, LangName;
+ PCSTR AnsiData;
+ UNICODE_STRING AnsiFileName = {0};
+ UNICODE_STRING OemFileName = {0};
+ UNICODE_STRING LangFileName = {0}; // CaseTable
+ UNICODE_STRING OemHalFileName = {0};
/* Get ANSI codepage file */
- if (!InfFindFirstLine(InfHandle, "NLS", "AnsiCodepage", &InfContext))
+ if (!InfFindFirstLine(InfHandle, "NLS", "AnsiCodepage", &InfContext) ||
+ !InfGetDataField(&InfContext, 1, &AnsiData) ||
+ !RtlCreateUnicodeStringFromAsciiz(&AnsiFileName, AnsiData))
{
- ERR("Failed to find 'NLS/AnsiCodepage'\n");
+ ERR("Failed to find or get 'NLS/AnsiCodepage'\n");
return;
}
- if (!InfGetDataField(&InfContext, 1, &AnsiName))
+
+ /* Get OEM codepage file */
+ if (!InfFindFirstLine(InfHandle, "NLS", "OemCodepage", &InfContext) ||
+ !InfGetDataField(&InfContext, 1, &AnsiData) ||
+ !RtlCreateUnicodeStringFromAsciiz(&OemFileName, AnsiData))
{
- ERR("Failed to get load options\n");
- return;
+ ERR("Failed to find or get 'NLS/OemCodepage'\n");
+ goto Quit;
}
- /* Get OEM codepage file */
- if (!InfFindFirstLine(InfHandle, "NLS", "OemCodepage", &InfContext))
+ /* Get the Unicode case table file */
+ if (!InfFindFirstLine(InfHandle, "NLS", "UnicodeCasetable", &InfContext) ||
+ !InfGetDataField(&InfContext, 1, &AnsiData) ||
+ !RtlCreateUnicodeStringFromAsciiz(&LangFileName, AnsiData))
{
- ERR("Failed to find 'NLS/AnsiCodepage'\n");
- return;
+ ERR("Failed to find or get 'NLS/UnicodeCasetable'\n");
+ goto Quit;
}
- if (!InfGetDataField(&InfContext, 1, &OemName))
+
+ /* Get OEM HAL font file */
+ if (!InfFindFirstLine(InfHandle, "NLS", "OemHalFont", &InfContext) ||
+ !InfGetData(&InfContext, NULL, &AnsiData) ||
+ !RtlCreateUnicodeStringFromAsciiz(&OemHalFileName, AnsiData))
{
- ERR("Failed to get load options\n");
- return;
+ WARN("Failed to find or get 'NLS/OemHalFont'\n");
+ /* Ignore, this is an optional file */
+ RtlInitEmptyUnicodeString(&OemHalFileName, NULL, 0);
}
- if (!InfFindFirstLine(InfHandle, "NLS", "UnicodeCasetable", &InfContext))
+ TRACE("NLS data: '%wZ' '%wZ' '%wZ' '%wZ'\n",
+ &AnsiFileName, &OemFileName, &LangFileName, &OemHalFileName);
+
+ /* Load NLS data */
+ Success = WinLdrLoadNLSData(LoaderBlock,
+ SearchPath,
+ &AnsiFileName,
+ &OemFileName,
+ &LangFileName,
+ &OemHalFileName);
+ TRACE("NLS data loading %s\n", Success ? "successful" : "failed");
+ (VOID)Success;
+
+Quit:
+ RtlFreeUnicodeString(&OemHalFileName);
+ RtlFreeUnicodeString(&LangFileName);
+ RtlFreeUnicodeString(&OemFileName);
+ RtlFreeUnicodeString(&AnsiFileName);
+}
+
+static
+BOOLEAN
+SetupLdrInitErrataInf(
+ IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
+ IN HINF InfHandle,
+ IN PCSTR SystemRoot)
+{
+ INFCONTEXT InfContext;
+ PCSTR FileName;
+ ULONG FileSize;
+ PVOID PhysicalBase;
+ CHAR ErrataFilePath[MAX_PATH];
+
+ /* Retrieve the INF file name value */
+ if (!InfFindFirstLine(InfHandle, "BiosInfo", "InfName", &InfContext))
{
- ERR("Failed to find 'NLS/AnsiCodepage'\n");
- return;
+ WARN("Failed to find 'BiosInfo/InfName'\n");
+ return FALSE;
}
- if (!InfGetDataField(&InfContext, 1, &LangName))
+ if (!InfGetDataField(&InfContext, 1, &FileName))
{
- ERR("Failed to get load options\n");
- return;
+ WARN("Failed to read 'InfName' value\n");
+ return FALSE;
}
- TRACE("NLS data '%s' '%s' '%s'\n", AnsiName, OemName, LangName);
+ RtlStringCbCopyA(ErrataFilePath, sizeof(ErrataFilePath), SystemRoot);
+ RtlStringCbCatA(ErrataFilePath, sizeof(ErrataFilePath), FileName);
-#if DBG
+ /* Load the INF file */
+ PhysicalBase = WinLdrLoadModule(ErrataFilePath, &FileSize, LoaderRegistryData);
+ if (!PhysicalBase)
{
- BOOLEAN Success = WinLdrLoadNLSData(LoaderBlock, SearchPath, AnsiName, OemName, LangName);
- TRACE("NLS data loading %s\n", Success ? "successful" : "failed");
- }
-#else
- WinLdrLoadNLSData(LoaderBlock, SearchPath, AnsiName, OemName, LangName);
-#endif
+ WARN("Could not load '%s'\n", ErrataFilePath);
+ return FALSE;
+ }
- /* TODO: Load OEM HAL font */
- // Value "OemHalFont"
+ LoaderBlock->Extension->EmInfFileImage = PaToVa(PhysicalBase);
+ LoaderBlock->Extension->EmInfFileSize = FileSize;
+
+ return TRUE;
}
static VOID
-SetupLdrScanBootDrivers(PLIST_ENTRY BootDriverListHead, HINF InfHandle, LPCSTR SearchPath)
+SetupLdrScanBootDrivers(
+ _Inout_ PLIST_ENTRY BootDriverListHead,
+ _In_ HINF InfHandle,
+ _In_ PCSTR SearchPath)
{
INFCONTEXT InfContext, dirContext;
+ PCSTR Media, DriverName, dirIndex, ImagePath;
BOOLEAN Success;
- LPCSTR Media, DriverName, dirIndex, ImagePath;
- WCHAR ServiceName[256];
- WCHAR ImagePathW[256];
+ WCHAR ImagePathW[MAX_PATH];
+ WCHAR DriverNameW[256];
+
+ UNREFERENCED_PARAMETER(SearchPath);
- /* Open inf section */
+ /* Open INF section */
if (!InfFindFirstLine(InfHandle, "SourceDisksFiles", NULL, &InfContext))
- return;
+ goto Quit;
/* Load all listed boot drivers */
do
InfFindFirstLine(InfHandle, "Directories", dirIndex, &dirContext) &&
InfGetDataField(&dirContext, 1, &ImagePath))
{
- /* Convert name to widechar */
- swprintf(ServiceName, L"%S", DriverName);
-
/* Prepare image path */
- swprintf(ImagePathW, L"%S", ImagePath);
- wcscat(ImagePathW, L"\\");
- wcscat(ImagePathW, ServiceName);
+ RtlStringCbPrintfW(ImagePathW, sizeof(ImagePathW),
+ L"%S\\%S", ImagePath, DriverName);
- /* Remove .sys extension */
- ServiceName[wcslen(ServiceName) - 4] = 0;
+ /* Convert name to unicode and remove .sys extension */
+ RtlStringCbPrintfW(DriverNameW, sizeof(DriverNameW),
+ L"%S", DriverName);
+ DriverNameW[wcslen(DriverNameW) - 4] = UNICODE_NULL;
/* Add it to the list */
Success = WinLdrAddDriverToList(BootDriverListHead,
- L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\",
+ FALSE,
+ DriverNameW,
ImagePathW,
- ServiceName);
+ NULL,
+ SERVICE_ERROR_NORMAL,
+ -1);
if (!Success)
{
- ERR("Could not add boot driver '%s', '%s'\n", SearchPath, DriverName);
- return;
+ ERR("Could not add boot driver '%s'\n", DriverName);
+ /* Ignore and continue adding other drivers */
}
}
}
} while (InfFindNextLine(&InfContext, &InfContext));
+
+Quit:
+ /* Finally, add the boot filesystem driver to the list */
+ if (BootFileSystem)
+ {
+ TRACE("Adding filesystem driver %S\n", BootFileSystem);
+ Success = WinLdrAddDriverToList(BootDriverListHead,
+ FALSE,
+ BootFileSystem,
+ NULL,
+ L"Boot File System",
+ SERVICE_ERROR_CRITICAL,
+ -1);
+ if (!Success)
+ ERR("Failed to add filesystem driver %S\n", BootFileSystem);
+ }
+ else
+ {
+ TRACE("No required filesystem driver\n");
+ }
}
/* SETUP STARTER **************************************************************/
+/*
+ * Update the options in the buffer pointed by LoadOptions, of maximum size
+ * BufferSize, by first removing any specified options, and then adding any
+ * other ones.
+ *
+ * OptionsToAdd is a NULL-terminated array of string buffer pointers that
+ * specify the options to be added into LoadOptions. Whether they are
+ * prepended or appended to LoadOptions is controlled via the Append
+ * parameter. The options are added in the order specified by the array.
+ *
+ * OptionsToRemove is a NULL-terminated array of string buffer pointers that
+ * specify the options to remove from LoadOptions. Specifying also there
+ * any options to add, has the effect of removing from LoadOptions any
+ * duplicates of the options to be added, before adding them later into
+ * LoadOptions. The options are removed in the order specified by the array.
+ *
+ * The options string buffers in the OptionsToRemove array have the format:
+ * "/option1 /option2[=] ..."
+ *
+ * An option in the OptionsToRemove list with a trailing '=' or ':' designates
+ * an option in LoadOptions with user-specific data appended after the sign.
+ * When such an option is being removed from LoadOptions, all the appended
+ * data is also removed until the next option.
+ */
+VOID
+NtLdrUpdateLoadOptions(
+ IN OUT PSTR LoadOptions,
+ IN ULONG BufferSize,
+ IN BOOLEAN Append,
+ IN PCSTR OptionsToAdd[] OPTIONAL,
+ IN PCSTR OptionsToRemove[] OPTIONAL)
+{
+ PCSTR NextOptions, NextOpt;
+ PSTR Options, Option;
+ ULONG NextOptLength;
+ ULONG OptionLength;
+
+ if (!LoadOptions || (BufferSize == 0))
+ return;
+ // ASSERT(strlen(LoadOptions) + 1 <= BufferSize);
+
+ /* Loop over the options to remove */
+ for (; OptionsToRemove && *OptionsToRemove; ++OptionsToRemove)
+ {
+ NextOptions = *OptionsToRemove;
+ while ((NextOpt = NtLdrGetNextOption(&NextOptions, &NextOptLength)))
+ {
+ /* Scan the load options */
+ Options = LoadOptions;
+ while ((Option = (PSTR)NtLdrGetNextOption((PCSTR*)&Options, &OptionLength)))
+ {
+ /*
+ * Check whether the option to find exactly matches the current
+ * load option, or is a prefix thereof if this is an option with
+ * appended data.
+ */
+ if ((OptionLength >= NextOptLength) &&
+ (_strnicmp(Option, NextOpt, NextOptLength) == 0))
+ {
+ if ((OptionLength == NextOptLength) ||
+ (NextOpt[NextOptLength-1] == '=') ||
+ (NextOpt[NextOptLength-1] == ':'))
+ {
+ /* Eat any skipped option or whitespace separators */
+ while ((Option > LoadOptions) &&
+ (Option[-1] == '/' ||
+ Option[-1] == ' ' ||
+ Option[-1] == '\t'))
+ {
+ --Option;
+ }
+
+ /* If the option was not preceded by a whitespace
+ * separator, insert one and advance the pointer. */
+ if ((Option > LoadOptions) &&
+ (Option[-1] != ' ') &&
+ (Option[-1] != '\t') &&
+ (*Options != '\0') /* &&
+ ** Not necessary since NtLdrGetNextOption() **
+ ** stripped any leading separators. **
+ (*Options != ' ') &&
+ (*Options != '\t') */)
+ {
+ *Option++ = ' ';
+ }
+
+ /* Move the remaining options back, erasing the current one */
+ ASSERT(Option <= Options);
+ RtlMoveMemory(Option,
+ Options,
+ (strlen(Options) + 1) * sizeof(CHAR));
+
+ /* Reset the iterator */
+ Options = Option;
+ }
+ }
+ }
+ }
+ }
+
+ /* Now loop over the options to add */
+ for (; OptionsToAdd && *OptionsToAdd; ++OptionsToAdd)
+ {
+ NtLdrAddOptions(LoadOptions,
+ BufferSize,
+ Append,
+ *OptionsToAdd);
+ }
+}
+
+
+/*
+ * List of options and their corresponding higher priority ones,
+ * that are either checked before any other ones, or whose name
+ * includes another option name as a subset (e.g. NODEBUG vs. DEBUG).
+ * See also https://geoffchappell.com/notes/windows/boot/editoptions.htm
+ */
+static const struct
+{
+ PCSTR Options;
+ PCSTR ExtraOptions;
+ PCSTR HigherPriorOptions;
+} HighPriorOptionsMap[] =
+{
+ /* NODEBUG has a higher precedence than DEBUG */
+ {"/DEBUG/DEBUG=", NULL, "/NODEBUG"},
+
+ /* When using SCREEN debug port, we need boot video */
+ {"/DEBUGPORT=SCREEN", NULL, "/NOGUIBOOT"},
+
+ /* DETECTHAL has a higher precedence than HAL= or KERNEL= */
+ {"/HAL=/KERNEL=", NULL, "/DETECTHAL"},
+
+ /* NOPAE has a higher precedence than PAE */
+ {"/PAE", NULL, "/NOPAE"},
+
+ /* NOEXECUTE(=) has a higher precedence than EXECUTE */
+ {"/EXECUTE", "/NOEXECUTE=ALWAYSOFF", "/NOEXECUTE/NOEXECUTE="},
+ /* NOEXECUTE(=) options are self-excluding and
+ * some have higher precedence than others. */
+ {"/NOEXECUTE/NOEXECUTE=", NULL, "/NOEXECUTE/NOEXECUTE="},
+
+ /* SAFEBOOT(:) options are self-excluding */
+ {"/SAFEBOOT/SAFEBOOT:", NULL, "/SAFEBOOT/SAFEBOOT:"},
+};
+
+#define TAG_BOOT_OPTIONS 'pOtB'
+
+VOID
+NtLdrGetHigherPriorityOptions(
+ IN PCSTR BootOptions,
+ OUT PSTR* ExtraOptions,
+ OUT PSTR* HigherPriorityOptions)
+{
+ ULONG i;
+ PCSTR NextOptions, NextOpt;
+ ULONG NextOptLength;
+ SIZE_T ExtraOptsSize = 0;
+ SIZE_T HighPriorOptsSize = 0;
+
+ /* Masks specifying the presence (TRUE) or absence (FALSE) of the options */
+ BOOLEAN Masks[RTL_NUMBER_OF(HighPriorOptionsMap)];
+
+ /* Just return if we cannot return anything */
+ if (!ExtraOptions && !HigherPriorityOptions)
+ return;
+
+ if (ExtraOptions)
+ *ExtraOptions = NULL;
+ if (HigherPriorityOptions)
+ *HigherPriorityOptions = NULL;
+
+ /* Just return if no initial options were given */
+ if (!BootOptions || !*BootOptions)
+ return;
+
+ /* Determine the presence of the colliding options, and the
+ * maximum necessary sizes for the pointers to be allocated. */
+ RtlZeroMemory(Masks, sizeof(Masks));
+ for (i = 0; i < RTL_NUMBER_OF(HighPriorOptionsMap); ++i)
+ {
+ /* Loop over the given options to search for */
+ NextOptions = HighPriorOptionsMap[i].Options;
+ while ((NextOpt = NtLdrGetNextOption(&NextOptions, &NextOptLength)))
+ {
+ /* If any of these options are present... */
+ if (NtLdrGetOptionExN(BootOptions, NextOpt, NextOptLength, NULL))
+ {
+ /* ... set the mask, retrieve the sizes and stop looking for these options */
+ Masks[i] = TRUE;
+ if (ExtraOptions && HighPriorOptionsMap[i].ExtraOptions)
+ {
+ ExtraOptsSize += strlen(HighPriorOptionsMap[i].ExtraOptions) * sizeof(CHAR);
+ }
+ if (HigherPriorityOptions && HighPriorOptionsMap[i].HigherPriorOptions)
+ {
+ HighPriorOptsSize += strlen(HighPriorOptionsMap[i].HigherPriorOptions) * sizeof(CHAR);
+ }
+ break;
+ }
+ }
+ }
+ /* Count the NULL-terminator */
+ if (ExtraOptions)
+ ExtraOptsSize += sizeof(ANSI_NULL);
+ if (HigherPriorityOptions)
+ HighPriorOptsSize += sizeof(ANSI_NULL);
+
+ /* Allocate the string pointers */
+ if (ExtraOptions)
+ {
+ *ExtraOptions = FrLdrHeapAlloc(ExtraOptsSize, TAG_BOOT_OPTIONS);
+ if (!*ExtraOptions)
+ return;
+ }
+ if (HigherPriorityOptions)
+ {
+ *HigherPriorityOptions = FrLdrHeapAlloc(HighPriorOptsSize, TAG_BOOT_OPTIONS);
+ if (!*HigherPriorityOptions)
+ {
+ if (ExtraOptions)
+ {
+ FrLdrHeapFree(*ExtraOptions, TAG_BOOT_OPTIONS);
+ *ExtraOptions = NULL;
+ }
+ return;
+ }
+ }
+
+ /* Initialize the strings */
+ if (ExtraOptions)
+ *(*ExtraOptions) = '\0';
+ if (HigherPriorityOptions)
+ *(*HigherPriorityOptions) = '\0';
+
+ /* Go through the masks that determine the options to check */
+ for (i = 0; i < RTL_NUMBER_OF(HighPriorOptionsMap); ++i)
+ {
+ if (Masks[i])
+ {
+ /* Retrieve the strings */
+ if (ExtraOptions && HighPriorOptionsMap[i].ExtraOptions)
+ {
+ RtlStringCbCatA(*ExtraOptions,
+ ExtraOptsSize,
+ HighPriorOptionsMap[i].ExtraOptions);
+ }
+ if (HigherPriorityOptions && HighPriorOptionsMap[i].HigherPriorOptions)
+ {
+ RtlStringCbCatA(*HigherPriorityOptions,
+ HighPriorOptsSize,
+ HighPriorOptionsMap[i].HigherPriorOptions);
+ }
+ }
+ }
+}
+
+
ARC_STATUS
LoadReactOSSetup(
IN ULONG Argc,
IN PCHAR Argv[],
IN PCHAR Envp[])
{
+ ARC_STATUS Status;
PCSTR ArgValue;
- PCHAR File;
- CHAR FileName[512];
- CHAR BootPath[512];
- CHAR BootOptions2[256];
- LPCSTR LoadOptions;
- LPSTR BootOptions;
+ PCSTR SystemPartition;
+ PCSTR SystemPath;
+ PSTR FileName;
+ ULONG FileNameLength;
BOOLEAN BootFromFloppy;
BOOLEAN Success;
- ULONG i, ErrorLine;
HINF InfHandle;
INFCONTEXT InfContext;
+ ULONG i, ErrorLine;
PLOADER_PARAMETER_BLOCK LoaderBlock;
PSETUP_LOADER_BLOCK SetupBlock;
- LPCSTR SystemPath;
+ CHAR BootPath[MAX_PATH];
+ CHAR FilePath[MAX_PATH];
+ CHAR UserBootOptions[256];
+ PCSTR BootOptions;
- static LPCSTR SourcePaths[] =
+ static PCSTR SourcePaths[] =
{
"", /* Only for floppy boot */
#if defined(_M_IX86)
NULL
};
- UiDrawStatusText("Setup is loading...");
+ /* Retrieve the (mandatory) boot type */
+ ArgValue = GetArgumentValue(Argc, Argv, "BootType");
+ if (!ArgValue || !*ArgValue)
+ {
+ ERR("No 'BootType' value, aborting!\n");
+ return EINVAL;
+ }
+ if (_stricmp(ArgValue, "ReactOSSetup") != 0)
+ {
+ ERR("Unknown 'BootType' value '%s', aborting!\n", ArgValue);
+ return EINVAL;
+ }
+ /* Retrieve the (mandatory) system partition */
+ SystemPartition = GetArgumentValue(Argc, Argv, "SystemPartition");
+ if (!SystemPartition || !*SystemPartition)
+ {
+ ERR("No 'SystemPartition' specified, aborting!\n");
+ return EINVAL;
+ }
+
+ /* Let the user know we started loading */
UiDrawBackdrop();
- UiDrawProgressBarCenter(1, 100, "Loading ReactOS Setup...");
+ UiDrawStatusText("Setup is loading...");
+ UiDrawProgressBarCenter("Loading ReactOS Setup...");
/* Retrieve the system path */
*BootPath = ANSI_NULL;
else
{
/*
- * IMPROVE: I don't want to call MachDiskGetBootPath here as a
- * default choice because I can call it after (see few lines below).
+ * IMPROVE: I don't want to use the SystemPartition here as a
+ * default choice because I can do it after (see few lines below).
* Instead I reset BootPath here so that we can build the full path
* using the general code from below.
*/
- // MachDiskGetBootPath(BootPath, sizeof(BootPath));
- // RtlStringCbCopyA(BootPath, sizeof(BootPath), ArgValue);
+ // RtlStringCbCopyA(BootPath, sizeof(BootPath), SystemPartition);
*BootPath = ANSI_NULL;
}
if (strrchr(BootPath, ')') == NULL)
{
/* Temporarily save the boot path */
- RtlStringCbCopyA(FileName, sizeof(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 != '\\' && *FileName != '/')
+ if (*FilePath != '\\' && *FilePath != '/')
RtlStringCbCatA(BootPath, sizeof(BootPath), "\\");
/* Append the remaining path */
- RtlStringCbCatA(BootPath, sizeof(BootPath), FileName);
+ RtlStringCbCatA(BootPath, sizeof(BootPath), FilePath);
}
- /* Append a backslash if needed */
+ /* Append a path separator if needed */
if (!*BootPath || BootPath[strlen(BootPath) - 1] != '\\')
RtlStringCbCatA(BootPath, sizeof(BootPath), "\\");
TRACE("BootPath: '%s'\n", BootPath);
- /* Retrieve the boot options */
- *BootOptions2 = ANSI_NULL;
- ArgValue = GetArgumentValue(Argc, Argv, "Options");
- if (ArgValue)
- RtlStringCbCopyA(BootOptions2, sizeof(BootOptions2), ArgValue);
+ /*
+ * Retrieve the boot options. Any options present here will supplement or
+ * override those that will be specified in TXTSETUP.SIF's OsLoadOptions.
+ */
+ BootOptions = GetArgumentValue(Argc, Argv, "Options");
+ if (!BootOptions)
+ BootOptions = "";
- TRACE("BootOptions: '%s'\n", BootOptions2);
+ TRACE("BootOptions: '%s'\n", BootOptions);
+
+ /* Check if a RAM disk file was given */
+ FileName = (PSTR)NtLdrGetOptionEx(BootOptions, "RDPATH=", &FileNameLength);
+ if (FileName && (FileNameLength > 7))
+ {
+ /* Load the RAM disk */
+ Status = RamDiskInitialize(FALSE, BootOptions, SystemPartition);
+ if (Status != ESUCCESS)
+ {
+ FileName += 7; FileNameLength -= 7;
+ UiMessageBox("Failed to load RAM disk file '%.*s'",
+ FileNameLength, FileName);
+ return Status;
+ }
+ }
/* Check if we booted from floppy */
BootFromFloppy = strstr(BootPath, "fdisk") != NULL;
- /* Open 'txtsetup.sif' from any of source paths */
- File = BootPath + strlen(BootPath);
+ /* Open 'txtsetup.sif' from any of the source paths */
+ FileName = BootPath + strlen(BootPath);
for (i = BootFromFloppy ? 0 : 1; ; i++)
{
SystemPath = SourcePaths[i];
UiMessageBox("Failed to open txtsetup.sif");
return ENOENT;
}
- RtlStringCbCopyA(File, sizeof(BootPath) - (File - BootPath)*sizeof(CHAR), SystemPath);
- RtlStringCbCopyA(FileName, sizeof(FileName), BootPath);
- RtlStringCbCatA(FileName, sizeof(FileName), "txtsetup.sif");
- if (InfOpenFile(&InfHandle, FileName, &ErrorLine))
+ FileNameLength = (ULONG)(sizeof(BootPath) - (FileName - BootPath)*sizeof(CHAR));
+ RtlStringCbCopyA(FileName, FileNameLength, SystemPath);
+ RtlStringCbCopyA(FilePath, sizeof(FilePath), BootPath);
+ RtlStringCbCatA(FilePath, sizeof(FilePath), "txtsetup.sif");
+ if (InfOpenFile(&InfHandle, FilePath, &ErrorLine))
{
break;
}
TRACE("BootPath: '%s', SystemPath: '%s'\n", BootPath, SystemPath);
- /* Get Load options - debug and non-debug */
- if (!InfFindFirstLine(InfHandle, "SetupData", "OsLoadOptions", &InfContext))
- {
- ERR("Failed to find 'SetupData/OsLoadOptions'\n");
- return EINVAL;
- }
-
- if (!InfGetDataField(&InfContext, 1, &LoadOptions))
- {
- ERR("Failed to get load options\n");
- return EINVAL;
- }
+ // UseLocalSif = NtLdrGetOption(BootOptions, "USELOCALSIF");
-#if DBG
- /* Get debug load options and use them */
- if (InfFindFirstLine(InfHandle, "SetupData", "DbgOsLoadOptions", &InfContext))
+ if (NtLdrGetOption(BootOptions, "SIFOPTIONSOVERRIDE"))
{
- LPCSTR DbgLoadOptions;
+ PCSTR OptionsToRemove[2] = {"SIFOPTIONSOVERRIDE", NULL};
- if (InfGetDataField(&InfContext, 1, &DbgLoadOptions))
- LoadOptions = DbgLoadOptions;
- }
-#endif
+ /* Do not use any load options from TXTSETUP.SIF, but
+ * use instead those passed from the command line. */
+ RtlStringCbCopyA(UserBootOptions, sizeof(UserBootOptions), BootOptions);
- /* Copy loadoptions (original string will be freed) */
- BootOptions = FrLdrTempAlloc(strlen(LoadOptions) + 1, TAG_BOOT_OPTIONS);
- ASSERT(BootOptions);
- strcpy(BootOptions, LoadOptions);
+ /* Remove the private switch from the options */
+ NtLdrUpdateLoadOptions(UserBootOptions,
+ sizeof(UserBootOptions),
+ FALSE,
+ NULL,
+ OptionsToRemove);
- TRACE("BootOptions: '%s'\n", BootOptions);
-
- /* Check if a ramdisk file was given */
- File = strstr(BootOptions2, "/RDPATH=");
- if (File)
+ BootOptions = UserBootOptions;
+ }
+ else // if (!*BootOptions || NtLdrGetOption(BootOptions, "SIFOPTIONSADD"))
{
- /* Copy the file name and everything else after it */
- RtlStringCbCopyA(FileName, sizeof(FileName), File + 8);
+ PCSTR LoadOptions = NULL;
+ PCSTR DbgLoadOptions = NULL;
+ PSTR ExtraOptions, HigherPriorityOptions;
+ PSTR OptionsToAdd[3];
+ PSTR OptionsToRemove[4];
+
+ /* Load the options from TXTSETUP.SIF */
+ if (InfFindFirstLine(InfHandle, "SetupData", "OsLoadOptions", &InfContext))
+ {
+ if (!InfGetDataField(&InfContext, 1, &LoadOptions))
+ WARN("Failed to get load options\n");
+ }
+
+#if !DBG
+ /* Non-debug mode: get the debug load options only if /DEBUG was specified
+ * in the Argv command-line options (was e.g. added to the options when
+ * the user selected "Debugging Mode" in the advanced boot menu). */
+ if (NtLdrGetOption(BootOptions, "DEBUG") ||
+ NtLdrGetOption(BootOptions, "DEBUG="))
+ {
+#else
+ /* Debug mode: always get the debug load options */
+#endif
+ if (InfFindFirstLine(InfHandle, "SetupData", "SetupDebugOptions", &InfContext))
+ {
+ if (!InfGetDataField(&InfContext, 1, &DbgLoadOptions))
+ WARN("Failed to get debug load options\n");
+ }
+ /* If none was found, default to enabling debugging */
+ if (!DbgLoadOptions)
+ DbgLoadOptions = "/DEBUG";
+#if !DBG
+ }
+#endif
- /* Null-terminate */
- *strstr(FileName, " ") = ANSI_NULL;
+ /* Initialize the load options with those from TXTSETUP.SIF */
+ *UserBootOptions = ANSI_NULL;
+ if (LoadOptions && *LoadOptions)
+ RtlStringCbCopyA(UserBootOptions, sizeof(UserBootOptions), LoadOptions);
- /* Load the ramdisk */
- if (!RamDiskLoadVirtualFile(FileName))
+ /* Merge the debug load options if any */
+ if (DbgLoadOptions)
{
- UiMessageBox("Failed to load RAM disk file %s", FileName);
- return ENOENT;
+ RtlZeroMemory(OptionsToAdd, sizeof(OptionsToAdd));
+ RtlZeroMemory(OptionsToRemove, sizeof(OptionsToRemove));
+
+ /*
+ * Retrieve any option patterns that we should remove from the
+ * SIF load options because they are of higher precedence than
+ * those specified in the debug load options to be added.
+ * Also always remove NODEBUG (even if the debug load options
+ * do not contain explicitly the DEBUG option), since we want
+ * to have debugging enabled if possible.
+ */
+ OptionsToRemove[0] = "/NODEBUG";
+ NtLdrGetHigherPriorityOptions(DbgLoadOptions,
+ &ExtraOptions,
+ &HigherPriorityOptions);
+ OptionsToAdd[1] = (ExtraOptions ? ExtraOptions : "");
+ OptionsToRemove[1] = (HigherPriorityOptions ? HigherPriorityOptions : "");
+
+ /*
+ * Prepend the debug load options, so that in case it contains
+ * redundant options with respect to the SIF load options, the
+ * former can take precedence over the latter.
+ */
+ OptionsToAdd[0] = (PSTR)DbgLoadOptions;
+ OptionsToRemove[2] = (PSTR)DbgLoadOptions;
+ NtLdrUpdateLoadOptions(UserBootOptions,
+ sizeof(UserBootOptions),
+ FALSE,
+ (PCSTR*)OptionsToAdd,
+ (PCSTR*)OptionsToRemove);
+
+ if (ExtraOptions)
+ FrLdrHeapFree(ExtraOptions, TAG_BOOT_OPTIONS);
+ if (HigherPriorityOptions)
+ FrLdrHeapFree(HigherPriorityOptions, TAG_BOOT_OPTIONS);
}
+
+ RtlZeroMemory(OptionsToAdd, sizeof(OptionsToAdd));
+ RtlZeroMemory(OptionsToRemove, sizeof(OptionsToRemove));
+
+ /*
+ * Retrieve any option patterns that we should remove from the
+ * SIF load options because they are of higher precedence than
+ * those specified in the options to be added.
+ */
+ NtLdrGetHigherPriorityOptions(BootOptions,
+ &ExtraOptions,
+ &HigherPriorityOptions);
+ OptionsToAdd[1] = (ExtraOptions ? ExtraOptions : "");
+ OptionsToRemove[0] = (HigherPriorityOptions ? HigherPriorityOptions : "");
+
+ /* Finally, prepend the user-specified options that
+ * take precedence over those from TXTSETUP.SIF. */
+ OptionsToAdd[0] = (PSTR)BootOptions;
+ OptionsToRemove[1] = (PSTR)BootOptions;
+ NtLdrUpdateLoadOptions(UserBootOptions,
+ sizeof(UserBootOptions),
+ FALSE,
+ (PCSTR*)OptionsToAdd,
+ (PCSTR*)OptionsToRemove);
+
+ if (ExtraOptions)
+ FrLdrHeapFree(ExtraOptions, TAG_BOOT_OPTIONS);
+ if (HigherPriorityOptions)
+ FrLdrHeapFree(HigherPriorityOptions, TAG_BOOT_OPTIONS);
+
+ BootOptions = UserBootOptions;
}
- /* Allocate and minimalist-initialize LPB */
- AllocateAndInitLPB(&LoaderBlock);
+ 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);
- /* Allocate and initialize setup loader block */
+ /* Allocate and initialize the setup loader block */
SetupBlock = &WinLdrSystemBlock->SetupBlock;
LoaderBlock->SetupLdrBlock = SetupBlock;
/* Set textmode setup flag */
SetupBlock->Flags = SETUPLDR_TEXT_MODE;
- /* Load the system hive "setupreg.hiv" for setup */
- UiDrawBackdrop();
- UiDrawProgressBarCenter(15, 100, "Loading setup system hive...");
+ /* Load the "setupreg.hiv" setup system hive */
+ UiUpdateProgressBar(15, "Loading setup system hive...");
Success = WinLdrInitSystemHive(LoaderBlock, BootPath, TRUE);
TRACE("Setup SYSTEM hive %s\n", (Success ? "loaded" : "not loaded"));
/* Bail out if failure */
return ENOEXEC;
/* Load NLS data, they are in the System32 directory of the installation medium */
- RtlStringCbCopyA(FileName, sizeof(FileName), BootPath);
- RtlStringCbCatA(FileName, sizeof(FileName), "system32\\");
- SetupLdrLoadNlsData(LoaderBlock, InfHandle, FileName);
+ RtlStringCbCopyA(FilePath, sizeof(FilePath), BootPath);
+ RtlStringCbCatA(FilePath, sizeof(FilePath), "system32\\");
+ SetupLdrLoadNlsData(LoaderBlock, InfHandle, FilePath);
+
+ /* Load the Firmware Errata file from the installation medium */
+ Success = SetupLdrInitErrataInf(LoaderBlock, InfHandle, BootPath);
+ TRACE("Firmware Errata file %s\n", (Success ? "loaded" : "not loaded"));
+ /* Not necessarily fatal if not found - carry on going */
// UiDrawStatusText("Press F6 if you need to install a 3rd-party SCSI or RAID driver...");
UiDrawStatusText("The Setup program is starting...");
- /* Load ReactOS Setup */
+ /* Finish loading */
return LoadAndBootWindowsCommon(_WIN32_WINNT_WS03,
LoaderBlock,
BootOptions,
- BootPath,
- TRUE);
+ BootPath);
}