diff --git a/boot/freeldr/freeldr/CMakeLists.txt b/boot/freeldr/freeldr/CMakeLists.txt index eab985b94e5..9bc6cd499fa 100644 --- a/boot/freeldr/freeldr/CMakeLists.txt +++ b/boot/freeldr/freeldr/CMakeLists.txt @@ -94,7 +94,7 @@ endif() list(APPEND FREELDR_BASE_SOURCE freeldr.c - ntldr/ntldropts.c # Should be in rosload, but is currently needed by machpc.c, etc. + ntldr/ntldropts.c # Is in rosload, but is currently needed by machpc.c and ramdisk.c lib/rtl/libsupp.c) if(ARCH STREQUAL "i386" OR ARCH STREQUAL "amd64") diff --git a/boot/freeldr/freeldr/freeldr.spec b/boot/freeldr/freeldr/freeldr.spec index da0842a4927..97933f34efe 100644 --- a/boot/freeldr/freeldr/freeldr.spec +++ b/boot/freeldr/freeldr/freeldr.spec @@ -54,13 +54,6 @@ @ cdecl MmGetSystemMemoryMapTypeString() @ cdecl MmGetTotalPagesInLookupTable() -# NtLdr options -@ cdecl NtLdrGetNextOption() -@ cdecl NtLdrGetOption() -@ cdecl NtLdrGetOptionEx() -@ cdecl NtLdrGetOptionExN() -@ cdecl NtLdrAddOptions() - # PeLdr @ cdecl PeLdrAllocateDataTableEntry() @ cdecl PeLdrCheckForLoadedDll() diff --git a/boot/freeldr/freeldr/ntldr/ntldropts.c b/boot/freeldr/freeldr/ntldr/ntldropts.c index ee3eb344cde..9a286b59df5 100644 --- a/boot/freeldr/freeldr/ntldr/ntldropts.c +++ b/boot/freeldr/freeldr/ntldr/ntldropts.c @@ -1,8 +1,10 @@ /* * PROJECT: FreeLoader - * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) + * LICENSE: Dual-licensed: + * GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * MIT (https://spdx.org/licenses/MIT) * PURPOSE: NT Kernel Load Options Support Functions - * COPYRIGHT: Copyright 2020 Hermes Belusca-Maito + * COPYRIGHT: Copyright 2020-2026 Hermès Bélusca-Maïto */ /* INCLUDES ******************************************************************/ @@ -14,8 +16,8 @@ PCSTR NtLdrGetNextOption( - IN OUT PCSTR* Options, - OUT PULONG OptionLength OPTIONAL) + _Inout_ PCSTR* Options, + _Out_opt_ PULONG OptionLength) { PCSTR NextOption; PCSTR Option = NULL; @@ -39,10 +41,8 @@ NtLdrGetNextOption( if (Option) break; - /* - * Check whether a new option starts. Options are delimited - * with an option separator '/' or with whitespace. - */ + /* Check whether a new option starts. Options are delimited + * with an option separator '/' or with whitespace. */ if (*NextOption == '/') ++NextOption; @@ -71,10 +71,10 @@ NtLdrGetNextOption( */ PCSTR NtLdrGetOptionExN( - IN PCSTR Options, - IN PCCH OptionName, - IN ULONG OptNameLength, - OUT PULONG OptionLength OPTIONAL) + _In_ PCSTR Options, + _In_reads_(OptNameLength) PCCH OptionName, + _In_ ULONG OptNameLength, + _Out_opt_ PULONG OptionLength) { PCSTR NextOptions; PCSTR Option = NULL; @@ -115,9 +115,9 @@ NtLdrGetOptionExN( PCSTR NtLdrGetOptionEx( - IN PCSTR Options, - IN PCSTR OptionName, - OUT PULONG OptionLength OPTIONAL) + _In_ PCSTR Options, + _In_ PCSTR OptionName, + _Out_opt_ PULONG OptionLength) { return NtLdrGetOptionExN(Options, OptionName, (ULONG)strlen(OptionName), @@ -126,52 +126,53 @@ NtLdrGetOptionEx( PCSTR NtLdrGetOption( - IN PCSTR Options, - IN PCSTR OptionName) + _In_ PCSTR Options, + _In_ PCSTR OptionName) { return NtLdrGetOptionEx(Options, OptionName, NULL); } -/* +/** + * @brief * Appends or prepends new options to the ones originally contained - * in the buffer pointed by LoadOptions, of maximum size BufferSize. - */ + * in the buffer pointed by Options, of maximum size BufferSize. + **/ VOID NtLdrAddOptions( - IN OUT PSTR LoadOptions, - IN ULONG BufferSize, - IN BOOLEAN Append, - IN PCSTR NewOptions OPTIONAL) + _Inout_updates_z_(BufferSize) PSTR Options, + _In_ ULONG BufferSize, + _In_ BOOLEAN Append, + _In_opt_ PCSTR NewOptions) { ULONG OptionsLength; ULONG NewOptsLength; BOOLEAN AddSeparator; - if (!LoadOptions || (BufferSize == 0)) + if (!Options || (BufferSize == 0)) return; - // ASSERT(strlen(LoadOptions) + 1 <= BufferSize); + // ASSERT(strlen(Options) + 1 <= BufferSize); if (!NewOptions || !*NewOptions) return; if (Append) { - OptionsLength = (ULONG)strlen(LoadOptions); + OptionsLength = (ULONG)strlen(Options); OptionsLength = min(OptionsLength, BufferSize-1); /* Add a whitespace separator if needed */ if (OptionsLength != 0 && - (LoadOptions[OptionsLength-1] != ' ') && - (LoadOptions[OptionsLength-1] != '\t') && + (Options[OptionsLength-1] != ' ') && + (Options[OptionsLength-1] != '\t') && (*NewOptions != '\0') && (*NewOptions != ' ') && (*NewOptions != '\t')) { - RtlStringCbCatA(LoadOptions, BufferSize * sizeof(CHAR), " "); + RtlStringCbCatA(Options, BufferSize * sizeof(CHAR), " "); } /* Append the options */ - RtlStringCbCatA(LoadOptions, BufferSize * sizeof(CHAR), NewOptions); + RtlStringCbCatA(Options, BufferSize * sizeof(CHAR), NewOptions); } else { @@ -183,9 +184,9 @@ NtLdrAddOptions( if (NewOptsLength != 0 && (NewOptions[NewOptsLength-1] != ' ') && (NewOptions[NewOptsLength-1] != '\t') && - (*LoadOptions != '\0') && - (*LoadOptions != ' ') && - (*LoadOptions != '\t')) + (*Options != '\0') && + (*Options != ' ') && + (*Options != '\t')) { AddSeparator = TRUE; ++NewOptsLength; @@ -196,18 +197,131 @@ NtLdrAddOptions( * at the end if the buffer is not large enough) to make place for * the options to prepend. */ - OptionsLength = (ULONG)strlen(LoadOptions) + 1; + OptionsLength = (ULONG)strlen(Options) + 1; OptionsLength = min(OptionsLength, BufferSize - NewOptsLength); - RtlMoveMemory(LoadOptions + NewOptsLength, - LoadOptions, + RtlMoveMemory(Options + NewOptsLength, + Options, OptionsLength * sizeof(CHAR)); /* NULL-terminate */ - (LoadOptions + NewOptsLength)[OptionsLength-1] = '\0'; + (Options + NewOptsLength)[OptionsLength-1] = '\0'; /* Restore the new options length back to its original value */ - if (AddSeparator) --NewOptsLength; + if (AddSeparator) + --NewOptsLength; /* Prepend the options and add the whitespace separator if needed */ - strncpy(LoadOptions, NewOptions, NewOptsLength); - if (AddSeparator) LoadOptions[NewOptsLength] = ' '; + strncpy(Options, NewOptions, NewOptsLength); + if (AddSeparator) + Options[NewOptsLength] = ' '; + } +} + +/** + * @brief + * Updates 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 +NtLdrUpdateOptions( + _Inout_updates_z_(BufferSize) PSTR LoadOptions, + _In_ ULONG BufferSize, + _In_ BOOLEAN Append, + _In_opt_ PCSTR OptionsToAdd[], + _In_opt_ PCSTR OptionsToRemove[]) +{ + 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); } } diff --git a/boot/freeldr/freeldr/ntldr/ntldropts.h b/boot/freeldr/freeldr/ntldr/ntldropts.h index 9b92eac8e74..253bc612567 100644 --- a/boot/freeldr/freeldr/ntldr/ntldropts.h +++ b/boot/freeldr/freeldr/ntldr/ntldropts.h @@ -1,38 +1,48 @@ /* * PROJECT: FreeLoader - * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) + * LICENSE: Dual-licensed: + * GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * MIT (https://spdx.org/licenses/MIT) * PURPOSE: NT Kernel Load Options Support Functions - * COPYRIGHT: Copyright 2020 Hermes Belusca-Maito + * COPYRIGHT: Copyright 2020-2026 Hermès Bélusca-Maïto */ #pragma once PCSTR NtLdrGetNextOption( - IN OUT PCSTR* Options, - OUT PULONG OptionLength OPTIONAL); + _Inout_ PCSTR* Options, + _Out_opt_ PULONG OptionLength); PCSTR NtLdrGetOptionExN( - IN PCSTR Options, - IN PCCH OptionName, - IN ULONG OptNameLength, - OUT PULONG OptionLength OPTIONAL); + _In_ PCSTR Options, + _In_reads_(OptNameLength) PCCH OptionName, + _In_ ULONG OptNameLength, + _Out_opt_ PULONG OptionLength); PCSTR NtLdrGetOptionEx( - IN PCSTR Options, - IN PCSTR OptionName, - OUT PULONG OptionLength OPTIONAL); + _In_ PCSTR Options, + _In_ PCSTR OptionName, + _Out_opt_ PULONG OptionLength); PCSTR NtLdrGetOption( - IN PCSTR Options, - IN PCSTR OptionName); + _In_ PCSTR Options, + _In_ PCSTR OptionName); VOID NtLdrAddOptions( - IN OUT PSTR LoadOptions, - IN ULONG BufferSize, - IN BOOLEAN Append, - IN PCSTR NewOptions OPTIONAL); + _Inout_updates_z_(BufferSize) PSTR Options, + _In_ ULONG BufferSize, + _In_ BOOLEAN Append, + _In_opt_ PCSTR NewOptions); + +VOID +NtLdrUpdateOptions( + _Inout_updates_z_(BufferSize) PSTR LoadOptions, + _In_ ULONG BufferSize, + _In_ BOOLEAN Append, + _In_opt_ PCSTR OptionsToAdd[], + _In_opt_ PCSTR OptionsToRemove[]); diff --git a/boot/freeldr/freeldr/ntldr/setupldr.c b/boot/freeldr/freeldr/ntldr/setupldr.c index 1f7f2cd0b54..cb9512f5c87 100644 --- a/boot/freeldr/freeldr/ntldr/setupldr.c +++ b/boot/freeldr/freeldr/ntldr/setupldr.c @@ -230,117 +230,6 @@ SetupLdrScanBootDrivers( /* 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 @@ -675,11 +564,11 @@ LoadReactOSSetup( RtlStringCbCopyA(UserBootOptions, sizeof(UserBootOptions), BootOptions); /* Remove the private switch from the options */ - NtLdrUpdateLoadOptions(UserBootOptions, - sizeof(UserBootOptions), - FALSE, - NULL, - OptionsToRemove); + NtLdrUpdateOptions(UserBootOptions, + sizeof(UserBootOptions), + FALSE, + NULL, + OptionsToRemove); } else // if (!*BootOptions || NtLdrGetOption(BootOptions, "SIFOPTIONSADD")) { @@ -751,11 +640,11 @@ LoadReactOSSetup( */ OptionsToAdd[0] = (PSTR)DbgLoadOptions; OptionsToRemove[2] = (PSTR)DbgLoadOptions; - NtLdrUpdateLoadOptions(UserBootOptions, - sizeof(UserBootOptions), - FALSE, - (PCSTR*)OptionsToAdd, - (PCSTR*)OptionsToRemove); + NtLdrUpdateOptions(UserBootOptions, + sizeof(UserBootOptions), + FALSE, + (PCSTR*)OptionsToAdd, + (PCSTR*)OptionsToRemove); if (ExtraOptions) FrLdrHeapFree(ExtraOptions, TAG_BOOT_OPTIONS); @@ -781,11 +670,11 @@ LoadReactOSSetup( * take precedence over those from TXTSETUP.SIF. */ OptionsToAdd[0] = (PSTR)BootOptions; OptionsToRemove[1] = (PSTR)BootOptions; - NtLdrUpdateLoadOptions(UserBootOptions, - sizeof(UserBootOptions), - FALSE, - (PCSTR*)OptionsToAdd, - (PCSTR*)OptionsToRemove); + NtLdrUpdateOptions(UserBootOptions, + sizeof(UserBootOptions), + FALSE, + (PCSTR*)OptionsToAdd, + (PCSTR*)OptionsToRemove); if (ExtraOptions) FrLdrHeapFree(ExtraOptions, TAG_BOOT_OPTIONS); diff --git a/boot/freeldr/freeldr/rosload.cmake b/boot/freeldr/freeldr/rosload.cmake index c0bc5b1adb2..240b27002a9 100644 --- a/boot/freeldr/freeldr/rosload.cmake +++ b/boot/freeldr/freeldr/rosload.cmake @@ -22,12 +22,12 @@ list(APPEND ROSLOAD_SOURCE ntldr/conversion.c ntldr/headless.c ntldr/inffile.c + ntldr/ntldropts.c ntldr/registry.c ntldr/setupldr.c ntldr/winldr.c ntldr/wlmemory.c - ntldr/wlregistry.c -) + ntldr/wlregistry.c) if(ARCH STREQUAL "i386") diff --git a/boot/freeldr/freeldr/uefi.cmake b/boot/freeldr/freeldr/uefi.cmake index b1766a672ef..2880919d92f 100644 --- a/boot/freeldr/freeldr/uefi.cmake +++ b/boot/freeldr/freeldr/uefi.cmake @@ -60,6 +60,7 @@ list(APPEND FREELDR_NTLDR_SOURCE ntldr/conversion.c ntldr/headless.c ntldr/inffile.c + ntldr/ntldropts.c ntldr/registry.c ntldr/setupldr.c ntldr/winldr.c