https://git.reactos.org/?p=reactos.git;a=commitdiff;h=4792c007aafa9739c76ff…
commit 4792c007aafa9739c76fff31cb3c19ffdc7a456d
Author: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
AuthorDate: Tue Nov 3 01:42:09 2020 +0100
Commit: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
CommitDate: Wed Nov 4 19:59:28 2020 +0100
[FREELDR] Add the possibility to change the boot load options from TXTSETUP.SIF
at runtime from the boot selection menu or from FREELDR.INI.
CORE-17350, CORE-9023
For a proper override of the options by new user options, specify the
/SIFOPTIONSOVERRIDE switch in addition. Otherwise, user options are
merged with those retrieved from TXTSETUP.SIF, with priority given to
the former ones.
- Update the documentation for the 'ReactOSSetup' OS type in the
FREELDR.INI file template.
- Use a different prompt in the custom boot options editor for the
'ReactOSSetup' OS type, with adequate explanation.
- Get rid of the ReactOS-specific TXTSETUP.SIF 'DbgOsLoadOptions' value,
and use instead the Windows-compatible 'SetupDebugOptions' value that
is added to the other load options when debugging is to be enabled.
---
boot/bootdata/txtsetup.sif | 6 +-
boot/freeldr/FREELDR.INI | 24 +-
boot/freeldr/freeldr/custom.c | 9 +-
boot/freeldr/freeldr/ntldr/ntldropts.c | 80 ++++++
boot/freeldr/freeldr/ntldr/ntldropts.h | 7 +
boot/freeldr/freeldr/ntldr/setupldr.c | 429 ++++++++++++++++++++++++++++++---
6 files changed, 511 insertions(+), 44 deletions(-)
diff --git a/boot/bootdata/txtsetup.sif b/boot/bootdata/txtsetup.sif
index 2b7b04002e2..2ddb0512ed3 100644
--- a/boot/bootdata/txtsetup.sif
+++ b/boot/bootdata/txtsetup.sif
@@ -212,10 +212,10 @@ Cabinet=reactos.cab
[SetupData]
DefaultPath = \ReactOS
+SetupDebugOptions = "/DEBUG /KDSERIAL /DEBUGPORT=COM1 /FIRSTCHANCE"
+;SetupDebugOptions = "/DEBUG /SOS /DEBUGPORT=SCREEN"
+;SetupDebugOptions = "/DEBUG /DEBUGPORT=BOCHS"
OsLoadOptions = "/NOGUIBOOT /NODEBUG"
-DbgOsLoadOptions = "/NOGUIBOOT /KDSERIAL /DEBUGPORT=COM1 /FIRSTCHANCE"
-;DbgOsLoadOptions = "/SOS /DEBUGPORT=SCREEN"
-;DbgOsLoadOptions = "/NOGUIBOOT /DEBUGPORT=BOCHS"
[NLS]
AnsiCodepage = c_1252.nls
diff --git a/boot/freeldr/FREELDR.INI b/boot/freeldr/FREELDR.INI
index 0bd420d06dc..48561fc4475 100644
--- a/boot/freeldr/FREELDR.INI
+++ b/boot/freeldr/FREELDR.INI
@@ -115,14 +115,14 @@
; will only be used to set the boot partition.
; Initrd - specifies the optional init ramdisk file name to be used.
; The same remarks about the path as for "Kernel" remain valid.
-; CommandLine - specifies the command line options for the kernel.
+; CommandLine - specifies the boot load options for the kernel.
; ["Windows(NT40|2003)" OSType] Section Commands:
;
; SystemPath - specifies the system root path (must be a valid ARC path):
; multi(0)disk(0)rdisk(0)partition(1)\reactos
; multi(0)disk(0)fdisk(0)
-; Options - specifies the command line options for the kernel being booted.
+; Options - specifies the boot load options for the kernel.
; Kernel - specifies the kernel file name (default: ntoskrnl.exe)
; Hal - specifies the HAL file name (default: hal.dll)
;
@@ -133,8 +133,24 @@
; ["ReactOSSetup" OSType] Section Commands:
;
-; No options defined for the moment. This OS type is used to tell FreeLdr
-; to start the SETUP portion of NT / ReactOS.
+; This OS type is used to start the SETUP portion of NT / ReactOS.
+;
+; SystemPath - specifies the system root path (must be a valid ARC path):
+; multi(0)disk(0)rdisk(0)partition(1)\reactos
+; multi(0)disk(0)fdisk(0)
+; Options - specifies extra boot load options for the kernel and the
+; setup environment (see REMARK 2 below).
+;
+; REMARK: Contrary to the "Windows" type, this OS type does not support separate
+; "Kernel" and "Hal" values. Instead, these values must be specified using the
+; NT-compatible "/HAL=filename" and "/KERNEL=filename" option switches.
+;
+; REMARK 2: The SETUP portion retrieves the default boot load options from the
+; TXTSETUP.SIF file present in the installation source (section "[SetupData]",
+; values "OsLoadOptions" and "SetupDebugOptions"). Thus, any options specified
+; using the "Options" value will supplement those already obtained from the
+; TXTSETUP.SIF file, unless the "/SIFOPTIONSOVERRIDE" option switch is specified,
+; in which case the "Options" value overrides those from TXTSETUP.SIF.
[FREELOADER]
diff --git a/boot/freeldr/freeldr/custom.c b/boot/freeldr/freeldr/custom.c
index 7cfd38c8d40..2422107d58e 100644
--- a/boot/freeldr/freeldr/custom.c
+++ b/boot/freeldr/freeldr/custom.c
@@ -36,7 +36,8 @@ const CHAR BootDrivePrompt[] = "Enter the boot drive.\n\nExamples:\nfd0 - first
const CHAR BootPartitionPrompt[] = "Enter the boot partition.\n\nEnter 0 for the active (bootable) partition.";
const CHAR ARCPathPrompt[] = "Enter the boot ARC path.\n\nExamples:\nmulti(0)disk(0)rdisk(0)partition(1)\nmulti(0)disk(0)fdisk(0)";
const CHAR ReactOSSystemPathPrompt[] = "Enter the path to your ReactOS system directory.\n\nExamples:\n\\REACTOS\n\\ROS";
-const CHAR ReactOSOptionsPrompt[] = "Enter the options you want passed to the kernel.\n\nExamples:\n/DEBUG /DEBUGPORT=COM1 /BAUDRATE=115200\n/FASTDETECT /SOS /NOGUIBOOT\n/BASEVIDEO /MAXMEM=64\n/KERNEL=NTKRNLMP.EXE /HAL=HALMPS.DLL";
+const CHAR ReactOSOptionsPrompt[] = "Enter the load options you want passed to the kernel.\n\nExamples:\n/DEBUG /DEBUGPORT=COM1 /BAUDRATE=115200\n/FASTDETECT /SOS /NOGUIBOOT\n/BASEVIDEO /MAXMEM=64\n/KERNEL=NTKRNLMP.EXE /HAL=HALMPS.DLL";
+const CHAR ReactOSSetupOptionsPrompt[] = "Enter additional load options you want passed to the ReactOS Setup.\nThese options will supplement those obtained from the TXTSETUP.SIF\nfile, unless you also specify the /SIFOPTIONSOVERRIDE option switch.\n\nExample:\n/NOGUIBOOT /DEBUG /DEBUGPORT=COM1 /BAUDRATE=115200";
const CHAR CustomBootPrompt[] = "Press ENTER to boot your custom boot setup.";
/* FUNCTIONS ******************************************************************/
@@ -659,7 +660,7 @@ EditCustomBootReactOS(
return;
}
- if (!UiEditBox(ReactOSOptionsPrompt, ReactOSOptions, sizeof(ReactOSOptions)))
+ if (!UiEditBox(IsSetup ? ReactOSSetupOptionsPrompt : ReactOSOptionsPrompt, ReactOSOptions, sizeof(ReactOSOptions)))
return;
/* Modify the settings values and return if we were in edit mode */
@@ -686,7 +687,9 @@ EditCustomBootReactOS(
return;
/* Construct the ReactOS ARC system path */
- ConstructArcPath(ReactOSARCPath, ReactOSSystemPath, DriveMapGetBiosDriveNumber(BootDriveString), atoi(BootPartitionString));
+ ConstructArcPath(ReactOSARCPath, ReactOSSystemPath,
+ DriveMapGetBiosDriveNumber(BootDriveString),
+ atoi(BootPartitionString));
/* Add the system path */
if (!IniAddSettingValueToSection(SectionId, "SystemPath", ReactOSARCPath))
diff --git a/boot/freeldr/freeldr/ntldr/ntldropts.c b/boot/freeldr/freeldr/ntldr/ntldropts.c
index 2173924e224..ee3eb344cde 100644
--- a/boot/freeldr/freeldr/ntldr/ntldropts.c
+++ b/boot/freeldr/freeldr/ntldr/ntldropts.c
@@ -131,3 +131,83 @@ NtLdrGetOption(
{
return NtLdrGetOptionEx(Options, OptionName, NULL);
}
+
+/*
+ * Appends or prepends new options to the ones originally contained
+ * in the buffer pointed by LoadOptions, of maximum size BufferSize.
+ */
+VOID
+NtLdrAddOptions(
+ IN OUT PSTR LoadOptions,
+ IN ULONG BufferSize,
+ IN BOOLEAN Append,
+ IN PCSTR NewOptions OPTIONAL)
+{
+ ULONG OptionsLength;
+ ULONG NewOptsLength;
+ BOOLEAN AddSeparator;
+
+ if (!LoadOptions || (BufferSize == 0))
+ return;
+ // ASSERT(strlen(LoadOptions) + 1 <= BufferSize);
+
+ if (!NewOptions || !*NewOptions)
+ return;
+
+ if (Append)
+ {
+ OptionsLength = (ULONG)strlen(LoadOptions);
+ OptionsLength = min(OptionsLength, BufferSize-1);
+
+ /* Add a whitespace separator if needed */
+ if (OptionsLength != 0 &&
+ (LoadOptions[OptionsLength-1] != ' ') &&
+ (LoadOptions[OptionsLength-1] != '\t') &&
+ (*NewOptions != '\0') &&
+ (*NewOptions != ' ') &&
+ (*NewOptions != '\t'))
+ {
+ RtlStringCbCatA(LoadOptions, BufferSize * sizeof(CHAR), " ");
+ }
+
+ /* Append the options */
+ RtlStringCbCatA(LoadOptions, BufferSize * sizeof(CHAR), NewOptions);
+ }
+ else
+ {
+ NewOptsLength = (ULONG)strlen(NewOptions);
+ NewOptsLength = min(NewOptsLength, BufferSize-1);
+
+ /* Add a whitespace separator if needed */
+ AddSeparator = FALSE;
+ if (NewOptsLength != 0 &&
+ (NewOptions[NewOptsLength-1] != ' ') &&
+ (NewOptions[NewOptsLength-1] != '\t') &&
+ (*LoadOptions != '\0') &&
+ (*LoadOptions != ' ') &&
+ (*LoadOptions != '\t'))
+ {
+ AddSeparator = TRUE;
+ ++NewOptsLength;
+ }
+
+ /*
+ * Move the original load options forward (possibly truncating them
+ * at the end if the buffer is not large enough) to make place for
+ * the options to prepend.
+ */
+ OptionsLength = (ULONG)strlen(LoadOptions) + 1;
+ OptionsLength = min(OptionsLength, BufferSize - NewOptsLength);
+ RtlMoveMemory(LoadOptions + NewOptsLength,
+ LoadOptions,
+ OptionsLength * sizeof(CHAR));
+ /* NULL-terminate */
+ (LoadOptions + NewOptsLength)[OptionsLength-1] = '\0';
+
+ /* Restore the new options length back to its original value */
+ if (AddSeparator) --NewOptsLength;
+ /* Prepend the options and add the whitespace separator if needed */
+ strncpy(LoadOptions, NewOptions, NewOptsLength);
+ if (AddSeparator) LoadOptions[NewOptsLength] = ' ';
+ }
+}
diff --git a/boot/freeldr/freeldr/ntldr/ntldropts.h b/boot/freeldr/freeldr/ntldr/ntldropts.h
index aab539ce92d..9b92eac8e74 100644
--- a/boot/freeldr/freeldr/ntldr/ntldropts.h
+++ b/boot/freeldr/freeldr/ntldr/ntldropts.h
@@ -29,3 +29,10 @@ PCSTR
NtLdrGetOption(
IN PCSTR Options,
IN PCSTR OptionName);
+
+VOID
+NtLdrAddOptions(
+ IN OUT PSTR LoadOptions,
+ IN ULONG BufferSize,
+ IN BOOLEAN Append,
+ IN PCSTR NewOptions OPTIONAL);
diff --git a/boot/freeldr/freeldr/ntldr/setupldr.c b/boot/freeldr/freeldr/ntldr/setupldr.c
index 548e4b7c21b..e80d15e03a6 100644
--- a/boot/freeldr/freeldr/ntldr/setupldr.c
+++ b/boot/freeldr/freeldr/ntldr/setupldr.c
@@ -15,8 +15,6 @@
#include <debug.h>
DBG_DEFAULT_CHANNEL(WINDOWS);
-#define TAG_BOOT_OPTIONS 'pOtB'
-
// TODO: Move to .h
VOID
AllocateAndInitLPB(
@@ -175,6 +173,264 @@ SetupLdrScanBootDrivers(PLIST_ENTRY BootDriverListHead, HINF InfHandle, PCSTR Se
/* 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,
@@ -196,9 +452,8 @@ LoadReactOSSetup(
PSETUP_LOADER_BLOCK SetupBlock;
CHAR BootPath[MAX_PATH];
CHAR FilePath[MAX_PATH];
- CHAR BootOptions2[256];
- PSTR BootOptions;
- PCSTR LoadOptions;
+ CHAR UserBootOptions[256];
+ PCSTR BootOptions;
static PCSTR SourcePaths[] =
{
@@ -287,20 +542,22 @@ LoadReactOSSetup(
TRACE("BootPath: '%s'\n", BootPath);
- /* Retrieve the boot options */
- *BootOptions2 = ANSI_NULL;
- ArgValue = GetArgumentValue(Argc, Argv, "Options");
- if (ArgValue && *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(BootOptions2, "RDPATH=", &FileNameLength);
+ FileName = (PSTR)NtLdrGetOptionEx(BootOptions, "RDPATH=", &FileNameLength);
if (FileName && (FileNameLength > 7))
{
/* Load the RAM disk */
- Status = RamDiskInitialize(FALSE, BootOptions2, SystemPartition);
+ Status = RamDiskInitialize(FALSE, BootOptions, SystemPartition);
if (Status != ESUCCESS)
{
FileName += 7; FileNameLength -= 7;
@@ -335,34 +592,138 @@ LoadReactOSSetup(
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;
- }
+ // UseLocalSif = NtLdrGetOption(BootOptions, "USELOCALSIF");
- if (!InfGetDataField(&InfContext, 1, &LoadOptions))
+ if (NtLdrGetOption(BootOptions, "SIFOPTIONSOVERRIDE"))
{
- ERR("Failed to get load options\n");
- return EINVAL;
- }
+ PCSTR OptionsToRemove[2] = {"SIFOPTIONSOVERRIDE", NULL};
-#if DBG
- /* Get debug load options and use them */
- if (InfFindFirstLine(InfHandle, "SetupData", "DbgOsLoadOptions", &InfContext))
- {
- PCSTR DbgLoadOptions;
+ /* Do not use any load options from TXTSETUP.SIF, but
+ * use instead those passed from the command line. */
+ RtlStringCbCopyA(UserBootOptions, sizeof(UserBootOptions), BootOptions);
- if (InfGetDataField(&InfContext, 1, &DbgLoadOptions))
- LoadOptions = DbgLoadOptions;
+ /* Remove the private switch from the options */
+ NtLdrUpdateLoadOptions(UserBootOptions,
+ sizeof(UserBootOptions),
+ FALSE,
+ NULL,
+ OptionsToRemove);
+
+ BootOptions = UserBootOptions;
}
+ else // if (!*BootOptions || NtLdrGetOption(BootOptions, "SIFOPTIONSADD"))
+ {
+ 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
+
+ /* Initialize the load options with those from TXTSETUP.SIF */
+ *UserBootOptions = ANSI_NULL;
+ if (LoadOptions && *LoadOptions)
+ RtlStringCbCopyA(UserBootOptions, sizeof(UserBootOptions), LoadOptions);
- /* Copy LoadOptions (original string will be freed) */
- BootOptions = FrLdrTempAlloc(strlen(LoadOptions) + 1, TAG_BOOT_OPTIONS);
- ASSERT(BootOptions);
- strcpy(BootOptions, LoadOptions);
+ /* Merge the debug load options if any */
+ if (DbgLoadOptions)
+ {
+ 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;
+ }
TRACE("BootOptions: '%s'\n", BootOptions);