diff --git a/Changelog.md b/Changelog.md
index 33ffd690b25..741ab07d2a1 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -5,6 +5,7 @@ OpenCore Changelog
- Fixed EHCI handoff logic in OpenDuet, causing older machines to hang at start
- Added Arrow Lake CPU detection
- Fixed Raptor Lake CPU detection
+- Supported booting with TuneD in Fedora 41 in OpenLinuxBoot
#### v1.0.2
- Fixed error in macrecovery when running headless, thx @mkorje
diff --git a/Docs/Configuration.md5 b/Docs/Configuration.md5
index 7ca274f8883..b89bfacc187 100644
--- a/Docs/Configuration.md5
+++ b/Docs/Configuration.md5
@@ -1 +1 @@
-29ba6cfd103b4a2b7c4e935fcf700cd3
+c025c15e04dc77d69d19ce3e12047a79
diff --git a/Docs/Configuration.pdf b/Docs/Configuration.pdf
index 73dacf28f33..06b1bfcda14 100644
Binary files a/Docs/Configuration.pdf and b/Docs/Configuration.pdf differ
diff --git a/Docs/Configuration.tex b/Docs/Configuration.tex
index 63738e0c97b..63ecd3c373b 100755
--- a/Docs/Configuration.tex
+++ b/Docs/Configuration.tex
@@ -6920,7 +6920,8 @@ \subsubsection{Configuration}
\begin{itemize}
\tightlist
\item \texttt{LINUX\_BOOT\_ADD\_RW},
- \item \texttt{LINUX\_BOOT\_LOG\_VERBOSE} and
+ \item \texttt{LINUX\_BOOT\_LOG\_VERBOSE},
+ \item \texttt{LINUX\_BOOT\_LOG\_GRUB\_VARS} and
\item \texttt{LINUX\_BOOT\_ADD\_DEBUG\_INFO}.
\end{itemize}
\medskip
@@ -7001,6 +7002,17 @@ \subsubsection{Configuration}
partition's unique partition uuid, to each generated entry name. Can help with debugging
the origin of entries generated by the driver when there are multiple Linux installs on
one system.
+ \item \texttt{0x00010000} (bit \texttt{16}) --- \texttt{LINUX\_BOOT\_LOG\_GRUB\_VARS},
+ When a \texttt{BootLoaderSpecByDefault} setup is detected, log available GRUB variables
+ found in \texttt{grub2/grubenv} and \texttt{grub2/grub.cfg}.
+ \item \texttt{0x00020000} (bit \texttt{17}) --- \texttt{LINUX\_BOOT\_FIX\_TUNED},
+ In some circumstances, such as after upgrades which add TuneD to existing systems, the TuneD
+ system tuning plugin may add its GRUB variables to \texttt{loader/entries/*.conf} files but not
+ initialise them in \texttt{grub2/grub.cfg}. In order to avoid incorrect boots, OpenLinuxBoot
+ treats used, non-initialised GRUB variables as an error. When this flag is set, empty values
+ are added for the TuneD variables \texttt{tuned\_params} and \texttt{tuned\_initrd} if they
+ are not present. This is required for OpenLinuxBoot on TuneD systems with this problem, and
+ harmless otherwise.
\end{itemize} \medskip
Flag values can be specified in hexadecimal beginning with \texttt{0x} or in decimal,
@@ -7048,7 +7060,7 @@ \subsubsection{Additional information}
OpenLinuxBoot can detect the \texttt{loader/entries/*.conf} files created according to the
\href{https://systemd.io/BOOT_LOADER_SPECIFICATION/}{Boot Loader Specification} or the closely related
-\href{https://fedoraproject.org/wiki/Changes/BootLoaderSpecByDefault}{systemd BootLoaderSpecByDefault}. The
+\href{https://fedoraproject.org/wiki/Changes/BootLoaderSpecByDefault}{Fedora BootLoaderSpecByDefault}. The
former is specific to systemd-boot and is used by Arch Linux, the latter applies to most Fedora-related distros
including Fedora itself, RHEL and variants.
@@ -7064,13 +7076,13 @@ \subsubsection{Additional information}
\texttt{autoopts:\{partuuid\}=...} (\texttt{+=} variants of these options will not work, as these only add additional
arguments).
-BootLoaderSpecByDefault (but not pure Boot Loader Specification) can expand GRUB variables
+Fedora \texttt{BootLoaderSpecByDefault} (but not pure Boot Loader Specification) can expand GRUB variables
in the \texttt{*.conf} files -- and this is used in practice in certain distros such as CentOS.
In order to handle this correctly, when this situation is detected OpenLinuxBoot extracts all variables from
\texttt{\{boot\}/grub2/grubenv} and also any unconditionally set variables from
\texttt{\{boot\}/grub2/grub.cfg}, and then expands these where required in \texttt{*.conf} file entries.
-The only currently supported method of starting Linux kernels relies on their being compiled with EFISTUB.
+The only currently supported method of starting Linux kernels from OpenLinuxBoot relies on their being compiled with EFISTUB.
This applies to almost all modern distros, particularly those which use systemd. Note that most modern
distros use systemd as their system manager, even though most do not use systemd-boot as
their bootloader.
diff --git a/Docs/Differences/Differences.pdf b/Docs/Differences/Differences.pdf
index 5bb9dd913b2..606f3afb676 100644
Binary files a/Docs/Differences/Differences.pdf and b/Docs/Differences/Differences.pdf differ
diff --git a/Docs/Differences/Differences.tex b/Docs/Differences/Differences.tex
index 622105cadd4..acba9b75d32 100644
--- a/Docs/Differences/Differences.tex
+++ b/Docs/Differences/Differences.tex
@@ -1,7 +1,7 @@
\documentclass[]{article}
%DIF LATEXDIFF DIFFERENCE FILE
-%DIF DEL PreviousConfiguration.tex Thu Oct 10 12:37:13 2024
-%DIF ADD ../Configuration.tex Thu Oct 10 12:37:13 2024
+%DIF DEL PreviousConfiguration.tex Sat Nov 9 05:47:31 2024
+%DIF ADD ../Configuration.tex Mon Nov 18 22:46:55 2024
\usepackage{lmodern}
\usepackage{amssymb,amsmath}
@@ -118,7 +118,7 @@
%DIF HYPERREF PREAMBLE %DIF PREAMBLE
\providecommand{\DIFadd}[1]{\texorpdfstring{\DIFaddtex{#1}}{#1}} %DIF PREAMBLE
\providecommand{\DIFdel}[1]{\texorpdfstring{\DIFdeltex{#1}}{}} %DIF PREAMBLE
-%DIF LISTINGS PREAMBLE %DIF PREAMBLE
+%DIF COLORLISTINGS PREAMBLE %DIF PREAMBLE
\RequirePackage{listings} %DIF PREAMBLE
\RequirePackage{color} %DIF PREAMBLE
\lstdefinelanguage{DIFcode}{ %DIF PREAMBLE
@@ -6980,7 +6980,8 @@ \subsubsection{Configuration}
\begin{itemize}
\tightlist
\item \texttt{LINUX\_BOOT\_ADD\_RW},
- \item \texttt{LINUX\_BOOT\_LOG\_VERBOSE} and
+ \item \texttt{LINUX\_BOOT\_LOG\_VERBOSE}\DIFaddbegin \DIFadd{,
+ }\item \texttt{\DIFadd{LINUX\_BOOT\_LOG\_GRUB\_VARS}} \DIFaddend and
\item \texttt{LINUX\_BOOT\_ADD\_DEBUG\_INFO}.
\end{itemize}
\medskip
@@ -7061,7 +7062,18 @@ \subsubsection{Configuration}
partition's unique partition uuid, to each generated entry name. Can help with debugging
the origin of entries generated by the driver when there are multiple Linux installs on
one system.
- \end{itemize} \medskip
+ \DIFaddbegin \item \texttt{\DIFadd{0x00010000}} \DIFadd{(bit }\texttt{\DIFadd{16}}\DIFadd{) --- }\texttt{\DIFadd{LINUX\_BOOT\_LOG\_GRUB\_VARS}}\DIFadd{,
+ When a }\texttt{\DIFadd{BootLoaderSpecByDefault}} \DIFadd{setup is detected, log available GRUB variables
+ found in }\texttt{\DIFadd{grub2/grubenv}} \DIFadd{and }\texttt{\DIFadd{grub2/grub.cfg}}\DIFadd{.
+ }\item \texttt{\DIFadd{0x00020000}} \DIFadd{(bit }\texttt{\DIFadd{17}}\DIFadd{) --- }\texttt{\DIFadd{LINUX\_BOOT\_FIX\_TUNED}}\DIFadd{,
+ In some circumstances, such as after upgrades which add TuneD to existing systems, the TuneD
+ system tuning plugin may add its GRUB variables to }\texttt{\DIFadd{loader/entries/*.conf}} \DIFadd{files but not
+ initialise them in }\texttt{\DIFadd{grub2/grub.cfg}}\DIFadd{. In order to avoid incorrect boots, OpenLinuxBoot
+ treats used, non-initialised GRUB variables as an error. When this flag is set, empty values
+ are added for the TuneD variables }\texttt{\DIFadd{tuned\_params}} \DIFadd{and }\texttt{\DIFadd{tuned\_initrd}} \DIFadd{if they
+ are not present. This is required for OpenLinuxBoot on TuneD systems with this problem, and
+ harmless otherwise.
+ }\DIFaddend \end{itemize} \medskip
Flag values can be specified in hexadecimal beginning with \texttt{0x} or in decimal,
e.g. \texttt{flags=0x80} or \texttt{flags=128}. It is also possible to specify flags to
@@ -7108,7 +7120,7 @@ \subsubsection{Additional information}
OpenLinuxBoot can detect the \texttt{loader/entries/*.conf} files created according to the
\href{https://systemd.io/BOOT_LOADER_SPECIFICATION/}{Boot Loader Specification} or the closely related
-\href{https://fedoraproject.org/wiki/Changes/BootLoaderSpecByDefault}{systemd BootLoaderSpecByDefault}. The
+\href{https://fedoraproject.org/wiki/Changes/BootLoaderSpecByDefault}{\DIFdelbegin \DIFdel{systemd }\DIFdelend \DIFaddbegin \DIFadd{Fedora }\DIFaddend BootLoaderSpecByDefault}. The
former is specific to systemd-boot and is used by Arch Linux, the latter applies to most Fedora-related distros
including Fedora itself, RHEL and variants.
@@ -7124,13 +7136,13 @@ \subsubsection{Additional information}
\texttt{autoopts:\{partuuid\}=...} (\texttt{+=} variants of these options will not work, as these only add additional
arguments).
-BootLoaderSpecByDefault (but not pure Boot Loader Specification) can expand GRUB variables
+\DIFdelbegin \DIFdel{BootLoaderSpecByDefault }\DIFdelend \DIFaddbegin \DIFadd{Fedora }\texttt{\DIFadd{BootLoaderSpecByDefault}} \DIFaddend (but not pure Boot Loader Specification) can expand GRUB variables
in the \texttt{*.conf} files -- and this is used in practice in certain distros such as CentOS.
In order to handle this correctly, when this situation is detected OpenLinuxBoot extracts all variables from
\texttt{\{boot\}/grub2/grubenv} and also any unconditionally set variables from
\texttt{\{boot\}/grub2/grub.cfg}, and then expands these where required in \texttt{*.conf} file entries.
-The only currently supported method of starting Linux kernels relies on their being compiled with EFISTUB.
+The only currently supported method of starting Linux kernels \DIFaddbegin \DIFadd{from OpenLinuxBoot }\DIFaddend relies on their being compiled with EFISTUB.
This applies to almost all modern distros, particularly those which use systemd. Note that most modern
distros use systemd as their system manager, even though most do not use systemd-boot as
their bootloader.
diff --git a/Docs/Errata/Errata.pdf b/Docs/Errata/Errata.pdf
index bd025070416..9ab315cbf0a 100644
Binary files a/Docs/Errata/Errata.pdf and b/Docs/Errata/Errata.pdf differ
diff --git a/Include/Acidanthera/Library/OcBootManagementLib.h b/Include/Acidanthera/Library/OcBootManagementLib.h
index 9c49cec5129..e1f717d7654 100644
--- a/Include/Acidanthera/Library/OcBootManagementLib.h
+++ b/Include/Acidanthera/Library/OcBootManagementLib.h
@@ -1926,7 +1926,7 @@ OcParseLoadOptions (
/**
Parse Unix-style var file or string. Parses a couple of useful ASCII
- GRUB config files (multi-line, name=var, with optinal comments) and
+ GRUB config files (multi-line, name=var, with optional comments) and
defines a standard format for Unicode UEFI LoadOptions.
Assumes CHAR_NULL terminated Unicode string of space separated options,
@@ -1940,9 +1940,10 @@ OcParseLoadOptions (
@param[in] StrVars Raw var string.
@param[out] ParsedVars Parsed variables if successful, NULL otherwise.
- Caller may free after use with OcFlexArrayFree
- if required.
+ Caller may free after use with OcFlexArrayFree.
@param[in] StringFormat Are option names and values Unicode or ASCII?
+ @param[in] TokensOnly If TRUE parse as a sequence of token values only,
+ rather than as a sequence of name[=[value]] pairs.
@retval EFI_SUCCESS Success.
@retval EFI_NOT_FOUND Missing or empty load options.
@@ -1953,7 +1954,8 @@ EFI_STATUS
OcParseVars (
IN VOID *StrVars,
OUT OC_FLEX_ARRAY **ParsedVars,
- IN CONST OC_STRING_FORMAT StringFormat
+ IN CONST OC_STRING_FORMAT StringFormat,
+ IN CONST BOOLEAN TokensOnly
);
/**
diff --git a/Include/Acidanthera/Library/OcStringLib.h b/Include/Acidanthera/Library/OcStringLib.h
index 45e22d41d3c..caf25e7efb1 100644
--- a/Include/Acidanthera/Library/OcStringLib.h
+++ b/Include/Acidanthera/Library/OcStringLib.h
@@ -742,4 +742,16 @@ OcIsSpace (
CHAR16 Ch
);
+/**
+ Determine if a particular character is whitespace or CHAR_NULL.
+
+ @param[in] Ch The character to check.
+
+ @return Returns TRUE if Ch is a whitespace character or CHAR_NULL.
+**/
+BOOLEAN
+OcIsSpaceOrNull (
+ CHAR16 Ch
+ );
+
#endif // OC_STRING_LIB_H
diff --git a/Library/OcBootManagementLib/BootArguments.c b/Library/OcBootManagementLib/BootArguments.c
index 9b6e02f7786..eeed86ea3cf 100644
--- a/Library/OcBootManagementLib/BootArguments.c
+++ b/Library/OcBootManagementLib/BootArguments.c
@@ -1,5 +1,5 @@
/** @file
- Copyright (C) 2019-2021, vit9696, mikebeaton. All rights reserved.
+ Copyright (C) 2019-2024, vit9696, mikebeaton. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause
**/
@@ -24,19 +24,19 @@ typedef enum PARSE_VARS_STATE_ {
PARSE_VARS_WHITE_SPACE,
PARSE_VARS_COMMENT,
PARSE_VARS_NAME,
- PARSE_VARS_VALUE_FIRST,
PARSE_VARS_VALUE,
PARSE_VARS_QUOTED_VALUE,
PARSE_VARS_SHELL_EXPANSION
} PARSE_VARS_STATE;
//
-// Shift from token start to current position forwards by offset characters.
+// Shift memory from token start to current position forwards by offset bytes
+// and update token to point to shifted start (thereby discarding offset bytes
+// from the token ending at current position).
//
#define SHIFT_TOKEN(pos, token, offset) do {\
CopyMem ((UINT8 *)(token) + (offset), (token), (UINT8 *)(pos) - (UINT8 *)(token)); \
(token) = (UINT8 *)(token) + (offset); \
- (pos) = (UINT8 *)(pos) + (offset); \
} while (0)
VOID
@@ -434,7 +434,7 @@ OcParseLoadOptions (
return EFI_NOT_FOUND;
}
- Status = OcParseVars (LoadedImage->LoadOptions, ParsedVars, OcStringFormatUnicode);
+ Status = OcParseVars (LoadedImage->LoadOptions, ParsedVars, OcStringFormatUnicode, FALSE);
if (Status == EFI_INVALID_PARAMETER) {
DEBUG ((DEBUG_ERROR, "OCB: Failed to parse LoadOptions (%p:%u)\n", LoadedImage->LoadOptions, LoadedImage->LoadOptionsSize));
@@ -449,16 +449,21 @@ EFI_STATUS
OcParseVars (
IN VOID *StrVars,
OUT OC_FLEX_ARRAY **ParsedVars,
- IN CONST OC_STRING_FORMAT StringFormat
+ IN CONST OC_STRING_FORMAT StringFormat,
+ IN CONST BOOLEAN TokensOnly
)
{
VOID *Pos;
+ VOID *NewPos;
PARSE_VARS_STATE State;
PARSE_VARS_STATE PushState;
BOOLEAN Retake;
CHAR16 Ch;
+ CHAR16 NewCh;
+ CHAR16 QuoteChar;
VOID *Name;
VOID *Value;
+ VOID *OriginalValue;
OC_PARSED_VAR *Option;
if ((StrVars == NULL) || ((StringFormat == OcStringFormatUnicode) ? (((CHAR16 *)StrVars)[0] == CHAR_NULL) : (((CHAR8 *)StrVars)[0] == '\0'))) {
@@ -475,6 +480,7 @@ OcParseVars (
State = PARSE_VARS_WHITE_SPACE;
PushState = PARSE_VARS_WHITE_SPACE;
Retake = FALSE;
+ QuoteChar = CHAR_NULL;
do {
Ch = (StringFormat == OcStringFormatUnicode) ? *((CHAR16 *)Pos) : *((CHAR8 *)Pos);
@@ -482,9 +488,24 @@ OcParseVars (
case PARSE_VARS_WHITE_SPACE:
if (Ch == '#') {
State = PARSE_VARS_COMMENT;
- } else if (!(OcIsSpace (Ch) || (Ch == CHAR_NULL))) {
- Name = Pos;
- State = PARSE_VARS_NAME;
+ } else if (!OcIsSpaceOrNull (Ch)) {
+ if (TokensOnly) {
+ Option = OcFlexArrayAddItem (*ParsedVars);
+ if (Option == NULL) {
+ OcFlexArrayFree (ParsedVars);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ DEBUG ((OC_TRACE_PARSE_VARS, "OCB: Value-only token\n"));
+
+ State = PARSE_VARS_VALUE;
+ Value = Pos;
+ OriginalValue = Value;
+ Retake = TRUE;
+ } else {
+ State = PARSE_VARS_NAME;
+ Name = Pos;
+ }
}
break;
@@ -497,7 +518,7 @@ OcParseVars (
break;
case PARSE_VARS_NAME:
- if ((Ch == L'=') || OcIsSpace (Ch) || (Ch == CHAR_NULL)) {
+ if ((Ch == L'=') || OcIsSpaceOrNull (Ch)) {
if (StringFormat == OcStringFormatUnicode) {
*((CHAR16 *)Pos) = CHAR_NULL;
} else {
@@ -505,7 +526,9 @@ OcParseVars (
}
if (Ch == L'=') {
- State = PARSE_VARS_VALUE_FIRST;
+ State = PARSE_VARS_VALUE;
+ Value = (UINT8 *)Pos + ((StringFormat == OcStringFormatUnicode) ? sizeof (CHAR16) : sizeof (CHAR8));
+ OriginalValue = Value;
} else {
State = PARSE_VARS_WHITE_SPACE;
}
@@ -533,18 +556,6 @@ OcParseVars (
break;
- case PARSE_VARS_VALUE_FIRST:
- if (Ch == L'"') {
- State = PARSE_VARS_QUOTED_VALUE;
- Value = (UINT8 *)Pos + ((StringFormat == OcStringFormatUnicode) ? sizeof (CHAR16) : sizeof (CHAR8));
- } else {
- State = PARSE_VARS_VALUE;
- Value = Pos;
- Retake = TRUE;
- }
-
- break;
-
case PARSE_VARS_SHELL_EXPANSION:
if (Ch == '`') {
ASSERT (PushState != PARSE_VARS_WHITE_SPACE);
@@ -553,23 +564,39 @@ OcParseVars (
break;
+ //
+ // In token value (but not name) we handle sh and grub quoting and string concatenation, e.g. 'abc\'"'\""def becomes abc\'"def.
+ //
case PARSE_VARS_VALUE:
case PARSE_VARS_QUOTED_VALUE:
- if (Ch == L'`') {
+ if ((State != PARSE_VARS_QUOTED_VALUE) && ((Ch == L'\'') || (Ch == L'"'))) {
+ QuoteChar = Ch;
+ SHIFT_TOKEN (Pos, Value, (StringFormat == OcStringFormatUnicode) ? sizeof (CHAR16) : sizeof (CHAR8));
+ State = PARSE_VARS_QUOTED_VALUE;
+ } else if ((State == PARSE_VARS_QUOTED_VALUE) && (Ch == QuoteChar)) {
+ SHIFT_TOKEN (Pos, Value, (StringFormat == OcStringFormatUnicode) ? sizeof (CHAR16) : sizeof (CHAR8));
+ QuoteChar = CHAR_NULL;
+ State = PARSE_VARS_VALUE;
+ } else if (((State != PARSE_VARS_QUOTED_VALUE) || (QuoteChar == L'"')) && (Ch == L'\\')) {
+ NewPos = (UINT8 *)Pos + ((StringFormat == OcStringFormatUnicode) ? sizeof (CHAR16) : sizeof (CHAR8));
+ NewCh = (StringFormat == OcStringFormatUnicode) ? *((CHAR16 *)Pos) : *((CHAR8 *)Pos);
+ //
+ // https://www.gnu.org/software/bash/manual/html_node/Double-Quotes.html
+ //
+ if ((State != PARSE_VARS_QUOTED_VALUE) || (NewCh == '"') || (NewCh == '\\') || (NewCh == '$') || (NewCh == '`')) {
+ SHIFT_TOKEN (Pos, Value, (StringFormat == OcStringFormatUnicode) ? sizeof (CHAR16) : sizeof (CHAR8));
+ Pos = NewPos;
+ Ch = NewCh;
+ }
+ } else if (Ch == L'`') {
PushState = State;
State = PARSE_VARS_SHELL_EXPANSION;
- } else if (Ch == L'\\') {
- SHIFT_TOKEN (Pos, Value, (StringFormat == OcStringFormatUnicode) ? sizeof (CHAR16) : sizeof (CHAR8));
- Ch = (StringFormat == OcStringFormatUnicode) ? *((CHAR16 *)Pos) : *((CHAR8 *)Pos);
- } else if (
- ((State == PARSE_VARS_VALUE) && (OcIsSpace (Ch) || (Ch == CHAR_NULL))) ||
- ((State == PARSE_VARS_QUOTED_VALUE) && (Ch == '"')))
- {
+ } else if ((State == PARSE_VARS_VALUE) && OcIsSpaceOrNull (Ch)) {
//
- // Explicitly quoted empty string needs to be stored detectably
- // differently from missing value.
+ // Explicitly quoted empty string (e.g. `var=""`) is stored detectably differently from missing value (i.e. `var=`, or just `var`).
//
- if ((State != PARSE_VARS_QUOTED_VALUE) && (Pos == Value)) {
+ if (Pos == OriginalValue) {
+ ASSERT (!TokensOnly);
DEBUG ((OC_TRACE_PARSE_VARS, "OCB: No value %u\n", 2));
} else {
if (PushState != PARSE_VARS_WHITE_SPACE) {
@@ -588,9 +615,10 @@ OcParseVars (
}
}
- Value = NULL;
- Option = NULL;
- State = PARSE_VARS_WHITE_SPACE;
+ Value = NULL;
+ OriginalValue = NULL;
+ Option = NULL;
+ State = PARSE_VARS_WHITE_SPACE;
}
break;
diff --git a/Library/OcStringLib/OcUnicodeLib.c b/Library/OcStringLib/OcUnicodeLib.c
index f123991c278..c2a6de18754 100644
--- a/Library/OcStringLib/OcUnicodeLib.c
+++ b/Library/OcStringLib/OcUnicodeLib.c
@@ -530,3 +530,11 @@ OcIsSpace (
{
return (Ch == L' ') || (Ch == L'\t') || (Ch == L'\r') || (Ch == L'\n') || (Ch == L'\v') || (Ch == L'\f');
}
+
+BOOLEAN
+OcIsSpaceOrNull (
+ CHAR16 Ch
+ )
+{
+ return (Ch == CHAR_NULL) || OcIsSpace (Ch);
+}
diff --git a/Platform/OpenLinuxBoot/Autodetect.c b/Platform/OpenLinuxBoot/Autodetect.c
index 0dd76330c81..b4db7d43d3f 100644
--- a/Platform/OpenLinuxBoot/Autodetect.c
+++ b/Platform/OpenLinuxBoot/Autodetect.c
@@ -269,7 +269,7 @@ LoadOsRelease (
"LNX: Reading %s\n",
OS_RELEASE_FILE
));
- Status = OcParseVars (mEtcOsReleaseFileContents, &mEtcOsReleaseOptions, OcStringFormatAscii);
+ Status = OcParseVars (mEtcOsReleaseFileContents, &mEtcOsReleaseOptions, OcStringFormatAscii, FALSE);
if (EFI_ERROR (Status)) {
FreePool (mEtcOsReleaseFileContents);
mEtcOsReleaseFileContents = NULL;
@@ -320,7 +320,7 @@ LoadDefaultGrub (
"LNX: Reading %s\n",
GRUB_DEFAULT_FILE
));
- Status = OcParseVars (mEtcDefaultGrubFileContents, &mEtcDefaultGrubOptions, OcStringFormatAscii);
+ Status = OcParseVars (mEtcDefaultGrubFileContents, &mEtcDefaultGrubOptions, OcStringFormatAscii, FALSE);
if (EFI_ERROR (Status)) {
FreePool (mEtcDefaultGrubFileContents);
mEtcDefaultGrubFileContents = NULL;
diff --git a/Platform/OpenLinuxBoot/GrubVars.c b/Platform/OpenLinuxBoot/GrubVars.c
index 0da488996df..c65fe6ac0c3 100644
--- a/Platform/OpenLinuxBoot/GrubVars.c
+++ b/Platform/OpenLinuxBoot/GrubVars.c
@@ -82,7 +82,7 @@ InternalSetGrubVar (
Var->Errors |= Errors;
DEBUG ((
- OC_TRACE_GRUB_VARS,
+ (gLinuxBootFlags & LINUX_BOOT_LOG_GRUB_VARS) == 0 ? DEBUG_VERBOSE : DEBUG_INFO,
"LNX: Repeated %a=%a (0x%x->0x%x)\n",
Key,
Value,
@@ -100,7 +100,7 @@ InternalSetGrubVar (
Var->Errors = Errors;
DEBUG ((
- OC_TRACE_GRUB_VARS,
+ (gLinuxBootFlags & LINUX_BOOT_LOG_GRUB_VARS) == 0 ? DEBUG_VERBOSE : DEBUG_INFO,
"LNX: Added %a=%a (0x%x)\n",
Key,
Value,
@@ -273,7 +273,13 @@ InternalExpandGrubVars (
}
}
- DEBUG ((OC_TRACE_GRUB_VARS, "LNX: Expanding '%a' => '%a' - %r\n", Value, *Result, Status));
+ DEBUG ((
+ (gLinuxBootFlags & LINUX_BOOT_LOG_GRUB_VARS) == 0 ? DEBUG_VERBOSE : DEBUG_INFO,
+ "LNX: Expanding '%a' => '%a' - %r\n",
+ Value,
+ *Result,
+ Status
+ ));
return Status;
}
diff --git a/Platform/OpenLinuxBoot/LinuxBootInternal.h b/Platform/OpenLinuxBoot/LinuxBootInternal.h
index ae52d165db0..8401e73d875 100644
--- a/Platform/OpenLinuxBoot/LinuxBootInternal.h
+++ b/Platform/OpenLinuxBoot/LinuxBootInternal.h
@@ -6,10 +6,6 @@
#ifndef LINUX_BOOT_INTERNAL_H
#define LINUX_BOOT_INTERNAL_H
-#if !defined (OC_TRACE_GRUB_VARS)
-#define OC_TRACE_GRUB_VARS DEBUG_VERBOSE
-#endif
-
/*
Standard attached drives on OVMF appear as MBR, so it can be convenient when
debugging to allow entries with incorrect (i.e. specifies no/every drive)
@@ -80,7 +76,8 @@
#define LINUX_BOOT_ADD_RW BIT11
/*
- TODO: Both blspec-style and autodetect can make use of grub.cfg info if this flag is set.
+ TODO: (?) Both blspec-style and autodetect can make use of grub.cfg info if this flag is set.
+ These are currently parsed when needed for GRUB2+blscfg, i.e. if we find /loader/entries and /grub2/grub.cfg.
*/
// #define LINUX_BOOT_ALLOW_PARSE_GRUB BIT12
@@ -100,6 +97,16 @@
*/
#define LINUX_BOOT_ADD_DEBUG_INFO BIT15
+/*
+ Trace grub var processing.
+*/
+#define LINUX_BOOT_LOG_GRUB_VARS BIT16
+
+/*
+ Fix TuneD processing by initialising its grub variables if they are not present.
+*/
+#define LINUX_BOOT_FIX_TUNED BIT17
+
#define LINUX_BOOT_ALL ( \
LINUX_BOOT_SCAN_ESP | \
LINUX_BOOT_SCAN_XBOOTLDR | \
@@ -112,7 +119,9 @@
LINUX_BOOT_ADD_RW | \
LINUX_BOOT_ALLOW_CONF_AUTO_ROOT | \
LINUX_BOOT_LOG_VERBOSE | \
- LINUX_BOOT_ADD_DEBUG_INFO \
+ LINUX_BOOT_ADD_DEBUG_INFO | \
+ LINUX_BOOT_LOG_GRUB_VARS | \
+ LINUX_BOOT_FIX_TUNED \
)
/*
diff --git a/Platform/OpenLinuxBoot/LoaderEntry.c b/Platform/OpenLinuxBoot/LoaderEntry.c
index 34930cd4056..3cf88a2e636 100644
--- a/Platform/OpenLinuxBoot/LoaderEntry.c
+++ b/Platform/OpenLinuxBoot/LoaderEntry.c
@@ -22,6 +22,15 @@
#include
+//
+// Vars which require blank values if not present after GRUB2+blscfg var parsing, in order
+// to fix up the fact that TuneD does not always initialise them.
+//
+STATIC CHAR8 *mTuneDVars[] = {
+ "tuned_params",
+ "tuned_initrd"
+};
+
//
// Root.
//
@@ -68,6 +77,10 @@
//
#define MAX_LOADER_ENTRY_FILE_SIZE SIZE_4KB
+//
+// grub2/grub.cfg was found, we treat this as enough to show that /loader/entries
+// we have found are a GRUB2+blscfg setup.
+//
STATIC
BOOLEAN
mIsGrub2;
@@ -435,10 +448,6 @@ ExpandReplaceOptions (
GRUB_VAR *DefaultOptionsVar;
if (Entry->Options->Count > 0) {
- //
- // Grub2 blscfg takes the first only.
- //
- ASSERT (Entry->Options->Count == 1);
Status = InternalExpandGrubVarsForArray (Entry->Options);
if (EFI_ERROR (Status)) {
return Status;
@@ -478,6 +487,68 @@ ExpandReplaceOptions (
return EFI_SUCCESS;
}
+//
+// Expand grub vars, and expand multiple initrds per line to multiple initrd lines.
+// Do this before checking for files, etc.
+//
+STATIC
+EFI_STATUS
+ExpandInitrds (
+ IN OUT LOADER_ENTRY *Entry
+ )
+{
+ EFI_STATUS Status;
+ UINTN OptionsIndex;
+ CHAR8 **Options;
+ OC_FLEX_ARRAY *ExpandedInitrds;
+ OC_FLEX_ARRAY *SplitInitrds;
+ UINTN SplitInitrdsIndex;
+
+ if (Entry->Initrds->Count == 0) {
+ return EFI_SUCCESS;
+ }
+
+ Status = InternalExpandGrubVarsForArray (Entry->Initrds);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ExpandedInitrds = OcFlexArrayInit (sizeof (CHAR8 *), OcFlexArrayFreePointerItem);
+
+ for (OptionsIndex = 0; OptionsIndex < Entry->Initrds->Count; OptionsIndex++) {
+ Options = OcFlexArrayItemAt (Entry->Initrds, OptionsIndex);
+
+ Status = OcParseVars (*Options, &SplitInitrds, OcStringFormatAscii, TRUE);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ for (SplitInitrdsIndex = 0; SplitInitrdsIndex < SplitInitrds->Count; SplitInitrdsIndex++) {
+ Status = EntryCopyMultipleValue (FALSE, ExpandedInitrds, OcParsedVarsItemAt (SplitInitrds, SplitInitrdsIndex)->Ascii.Value);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ }
+
+ OcFlexArrayFree (&SplitInitrds);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ OcFlexArrayFree (&ExpandedInitrds);
+ return Status;
+ }
+
+ ASSERT (ExpandedInitrds->Count >= Entry->Initrds->Count);
+
+ OcFlexArrayFree (&Entry->Initrds);
+ Entry->Initrds = ExpandedInitrds;
+
+ return EFI_SUCCESS;
+}
+
STATIC
EFI_STATUS
DoFilterLoaderEntry (
@@ -696,7 +767,7 @@ HasRootOption (
return TRUE;
}
- Status = OcParseVars (OptionCopy, &ParsedVars, OcStringFormatAscii);
+ Status = OcParseVars (OptionCopy, &ParsedVars, OcStringFormatAscii, FALSE);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_WARN, "LNX: Error parsing Options[%u]=<%a> - %r\n", Index, *Option, Status));
FreePool (OptionCopy);
@@ -804,6 +875,21 @@ DoProcessLoaderEntry (
return EFI_NOT_FOUND;
}
+ if (mIsGrub2) {
+ Status = ExpandReplaceOptions (Entry);
+ if (!EFI_ERROR (Status)) {
+ Status = ExpandInitrds (Entry);
+ }
+
+ if (EFI_ERROR (Status)) {
+ OcFlexArrayDiscardItem (gLoaderEntries, TRUE);
+ return Status;
+ }
+ }
+
+ //
+ // Check all files exist, see comment on FindLoaderFile.
+ //
Status = FindLoaderFile (Directory, DirName, &Entry->Linux);
if (!EFI_ERROR (Status)) {
for (Index = 0; Index < Entry->Initrds->Count; Index++) {
@@ -820,14 +906,6 @@ DoProcessLoaderEntry (
return Status;
}
- if (mIsGrub2) {
- Status = ExpandReplaceOptions (Entry);
- if (EFI_ERROR (Status)) {
- OcFlexArrayDiscardItem (gLoaderEntries, TRUE);
- return Status;
- }
- }
-
//
// Need to understand other reasons to apply this fix (if any),
// so not automatically applying unless we recognise the layout.
@@ -889,6 +967,30 @@ ProcessLoaderEntry (
return EFI_SUCCESS;
}
+STATIC
+EFI_STATUS
+FixTuneDVars (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+
+ STATIC_ASSERT (ARRAY_SIZE (mTuneDVars) > 0, "No TuneD vars to set");
+
+ Status = EFI_SUCCESS;
+ for (Index = 0; Index < ARRAY_SIZE (mTuneDVars); Index++) {
+ if (InternalGetGrubVar (mTuneDVars[Index]) == NULL) {
+ Status = InternalSetGrubVar (mTuneDVars[Index], "", VAR_ERR_NONE);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ }
+ }
+
+ return Status;
+}
+
STATIC
EFI_STATUS
ScanLoaderEntriesAtDirectory (
@@ -915,7 +1017,7 @@ ScanLoaderEntriesAtDirectory (
gLoaderEntries = NULL;
//
- // Only treat as GRUB2 if grub2/grub.cfg exists.
+ // Treat /loader/entries as being GRUB2+blscfg style if /grub2/grub.cfg exists.
//
GrubCfg = OcReadFileFromDirectory (RootDirectory, GRUB2_GRUB_CFG, NULL, 0);
if (GrubCfg == NULL) {
@@ -947,15 +1049,23 @@ ScanLoaderEntriesAtDirectory (
));
Status = InternalProcessGrubCfg (GrubCfg);
}
+
+ if ( !EFI_ERROR (Status)
+ && ((gLinuxBootFlags & LINUX_BOOT_FIX_TUNED) != 0))
+ {
+ DEBUG ((
+ (gLinuxBootFlags & LINUX_BOOT_LOG_VERBOSE) == 0 ? DEBUG_VERBOSE : DEBUG_INFO,
+ "LNX: Fix TuneD vars\n"
+ ));
+ Status = FixTuneDVars ();
+ }
}
}
//
// If we are grub2 and $early_initrd exists, then warn and halt (blscfg logic is to use it).
- // Would not be hard to implement if required. This is a space separated list of filenames
- // to use first as initrds.
- // Note: they are filenames only, so (following how blscfg module does it) we need to prepend
- // the path of either another (the first) initrd or the (first) vmlinuz.
+ // Would not be hard to implement in ExpandInitrds if required. This is a space separated list
+ // of filenames to use first as initrds.
//
if (!EFI_ERROR (Status)) {
if (mIsGrub2) {
diff --git a/Platform/OpenLinuxBoot/OpenLinuxBoot.c b/Platform/OpenLinuxBoot/OpenLinuxBoot.c
index 23cef3de56d..4dec7143b49 100644
--- a/Platform/OpenLinuxBoot/OpenLinuxBoot.c
+++ b/Platform/OpenLinuxBoot/OpenLinuxBoot.c
@@ -21,7 +21,7 @@
#include
-UINTN gLinuxBootFlags = LINUX_BOOT_ALL & ~(LINUX_BOOT_ADD_DEBUG_INFO | LINUX_BOOT_LOG_VERBOSE | LINUX_BOOT_ADD_RW);
+UINTN gLinuxBootFlags = LINUX_BOOT_ALL & ~(LINUX_BOOT_ADD_DEBUG_INFO | LINUX_BOOT_LOG_VERBOSE | LINUX_BOOT_LOG_GRUB_VARS | LINUX_BOOT_ADD_RW);
STATIC OC_FLEX_ARRAY *mParsedLoadOptions;