OcBootManagementLib: Add InstanceIdentifier, and ability to target .contentVisibility to specific instances

This commit is contained in:
Mike Beaton 2023-06-14 22:13:30 +01:00
parent d4bd64ccd7
commit dc182df42c
17 changed files with 214 additions and 23 deletions

View File

@ -3,6 +3,7 @@ OpenCore Changelog
#### v0.9.4
- Fixed kext blocker `Exclude` strategy for prelinked on 32-bit versions of macOS
- Fixed `ForceAquantiaEthernet` quirk on macOS 14 beta 2, thx @Shikumo
- Added `InstanceIdentifier` and option to target `.contentVisibility` to specific instances (thx @dakanji)
#### v0.9.3
- Added `--force-codec` option to AudioDxe, thx @xCuri0

View File

@ -1 +1 @@
0b29a010d2e4411027e326673ef51b53
887b398104bf1d32313b8933cfe455ba

Binary file not shown.

View File

@ -3125,6 +3125,8 @@ installed on the media, while alternate options represent recovery options for t
\end{itemize} \medskip
\end{itemize}
\subsubsection{Boot Algorithm}\label{bootalgorithm}
The algorithm to determine boot options behaves as follows:
\begin{enumerate}
@ -3146,12 +3148,14 @@ The algorithm to determine boot options behaves as follows:
\item For file device paths, check for presence on the file system directly.
% Just kill all \EFI\APPLE\ paths.
\item Exclude entries if there is a \texttt{.contentVisibility} file near the bootloader or
inside the boot directory with \texttt{Disabled} contents (ASCII).
inside the boot directory with \texttt{Disabled} contents (ASCII) (and if the current
\texttt{InstanceIentifier} matches an \texttt{Instance-List} if present, see following).
\item Mark device handle as \textit{used} in the list of partition handles if any.
% Each partition handle will basically have a list of boot option entries for later quick lookup.
\item Register the resulting entries as primary options and determine their types. \\
The option will become auxiliary for some types (e.g. Apple HFS recovery)
or if its \texttt{.contentVisibility} file contains \texttt{Auxiliary}.
or if its \texttt{.contentVisibility} file contains \texttt{Auxiliary} (and if the current
\texttt{InstanceIentifier} matches an \texttt{Instance-List} if present, see following).
\end{itemize}
\item For each partition handle:
\begin{itemize}
@ -3165,14 +3169,32 @@ The algorithm to determine boot options behaves as follows:
\item Lookup alternate entries by ``bless'' recovery option list retrieval and predefined paths.
\item Register the resulting entries as alternate auxiliary options and determine their types if found.
\end{itemize}
\item Custom entries and tools, except such pre-constructed previously, are added as primary options without any checks with respect to \texttt{Auxiliary}.
\item Custom entries and tools, except such pre-constructed previously, are added as primary options
without any checks with respect to \texttt{Auxiliary}.
\item System entries, such as \texttt{Reset NVRAM}, are added as primary auxiliary options.
\end{enumerate}
The \texttt{.contentVisibility} file, when present, may optionally target only specific instances
of OpenCore. Its contents are \texttt{[\{Instance-List\}:](Disabled|Auxiliary)}.
If a colon (\texttt{:}) is present, the preceding \texttt{Instance-List} it is a comma separated
list of \texttt{InstanceIdentifier} values (example: \texttt{OCA,OCB:Disabled}).
When this list is present, the specified visibility is only applied if the
\texttt{InstanceIdentifier} of the current instance of OpenCore is present in the list.
When the list is not present, the specified visibility is applied for all instances of OpenCore.
\emph{Note 1}: For any instance of OpenCore with no \texttt{InstanceIdentifier} value, the specified visibility
from a \texttt{.contentVisibility} file with an \texttt{Instance-List} will never be applied.
\emph{Note 2}: Visibilities with a visibility list will be treated as invalid, and so ignored, in earlier
versions of OpenCore - which may be useful when comparing behaviour of older and newer versions.
\emph{Note 3}: Avoid extraneous spaces in the \texttt{.contentVisibility} file: these will not be treated as
whitespace, but as part of the adjacent token.
The display order of the boot options in the OpenCore picker and the boot process
are determined separately from the scanning algorithm.
The display order as follows:
The display order is as follows:
\begin{itemize}
\tightlist
@ -3391,6 +3413,17 @@ the default boot entry choice will remain changed until the next manual reconfig
To display all entries, the picker menu can be reloaded into ``Extended Mode'' by pressing the
\texttt{Spacebar} key. Hiding auxiliary entries may increase boot performance on multi-disk systems.
\item
\texttt{InstanceIdentifier}\\
\textbf{Type}: \texttt{plist\ string}\\
\textbf{Failsafe}: Empty\\
\textbf{Description}: An optional identifier for the current instance of OpenCore.
This should typically be a short alphanumeric string. The current use of this value is
to optionally target \texttt{.contentVisibility} files to specific instances of OpenCore,
as explained in the \hyperref[bootalgorithm]{Boot Algorithm} section.
\item
\texttt{LauncherOption}\\
\textbf{Type}: \texttt{plist\ string}\\

Binary file not shown.

View File

@ -1,7 +1,7 @@
\documentclass[]{article}
%DIF LATEXDIFF DIFFERENCE FILE
%DIF DEL PreviousConfiguration.tex Tue Jun 13 00:18:48 2023
%DIF ADD ../Configuration.tex Tue Jun 13 00:18:48 2023
%DIF DEL PreviousConfiguration.tex Wed Jun 14 22:10:31 2023
%DIF ADD ../Configuration.tex Fri Jun 23 19:53:46 2023
\usepackage{lmodern}
\usepackage{amssymb,amsmath}
@ -3185,7 +3185,9 @@ installed on the media, while alternate options represent recovery options for t
\end{itemize} \medskip
\end{itemize}
The algorithm to determine boot options behaves as follows:
\DIFaddbegin \subsubsection{\DIFadd{Boot Algorithm}}\label{bootalgorithm}
\DIFaddend The algorithm to determine boot options behaves as follows:
\begin{enumerate}
\tightlist
@ -3206,12 +3208,14 @@ The algorithm to determine boot options behaves as follows:
\item For file device paths, check for presence on the file system directly.
% Just kill all \EFI\APPLE\ paths.
\item Exclude entries if there is a \texttt{.contentVisibility} file near the bootloader or
inside the boot directory with \texttt{Disabled} contents (ASCII).
inside the boot directory with \texttt{Disabled} contents (ASCII) \DIFaddbegin \DIFadd{(and if the current
}\texttt{\DIFadd{InstanceIentifier}} \DIFadd{matches an }\texttt{\DIFadd{Instance-List}} \DIFadd{if present, see following)}\DIFaddend .
\item Mark device handle as \textit{used} in the list of partition handles if any.
% Each partition handle will basically have a list of boot option entries for later quick lookup.
\item Register the resulting entries as primary options and determine their types. \\
The option will become auxiliary for some types (e.g. Apple HFS recovery)
or if its \texttt{.contentVisibility} file contains \texttt{Auxiliary}.
or if its \texttt{.contentVisibility} file contains \texttt{Auxiliary} \DIFaddbegin \DIFadd{(and if the current
}\texttt{\DIFadd{InstanceIentifier}} \DIFadd{matches an }\texttt{\DIFadd{Instance-List}} \DIFadd{if present, see following)}\DIFaddend .
\end{itemize}
\item For each partition handle:
\begin{itemize}
@ -3225,14 +3229,36 @@ The algorithm to determine boot options behaves as follows:
\item Lookup alternate entries by ``bless'' recovery option list retrieval and predefined paths.
\item Register the resulting entries as alternate auxiliary options and determine their types if found.
\end{itemize}
\item Custom entries and tools, except such pre-constructed previously, are added as primary options without any checks with respect to \texttt{Auxiliary}.
\item Custom entries and tools, except such pre-constructed previously, are added as primary options
without any checks with respect to \texttt{Auxiliary}.
\item System entries, such as \texttt{Reset NVRAM}, are added as primary auxiliary options.
\end{enumerate}
The display order of the boot options in the OpenCore picker and the boot process
The \DIFaddbegin \texttt{\DIFadd{.contentVisibility}} \DIFadd{file, when present, may optionally target only specific instances
of OpenCore. Its contents are }\texttt{[\DIFadd{\{Instance-List\}:}]\DIFadd{(Disabled|Auxiliary)}}\DIFadd{.
If a colon (}\texttt{\DIFadd{:}}\DIFadd{) is present, the preceding }\texttt{\DIFadd{Instance-List}} \DIFadd{it is a comma separated
list of }\texttt{\DIFadd{InstanceIdentifier}} \DIFadd{values (example: }\texttt{\DIFadd{OCA,OCB:Disabled}}\DIFadd{).
When this list is present, the specified visibility is only applied if the
}\texttt{\DIFadd{InstanceIdentifier}} \DIFadd{of the current instance of OpenCore is present in the list.
When the list is not present, the specified visibility is applied for all instances of OpenCore.
}
\emph{\DIFadd{Note 1}}\DIFadd{: For any instance of OpenCore with no }\texttt{\DIFadd{InstanceIdentifier}} \DIFadd{value, the specified visibility
from a }\texttt{\DIFadd{.contentVisibility}} \DIFadd{file with an }\texttt{\DIFadd{Instance-List}} \DIFadd{will never be applied.
}
\emph{\DIFadd{Note 2}}\DIFadd{: Visibilities with a visibility list will be treated as invalid, and so ignored, in earlier
versions of OpenCore - which may be useful when comparing behaviour of older and newer versions.
}
\emph{\DIFadd{Note 3}}\DIFadd{: Avoid extraneous spaces in the }\texttt{\DIFadd{.contentVisibility}} \DIFadd{file: these will not be treated as
whitespace, but as part of the adjacent token.
}
\DIFadd{The }\DIFaddend display order of the boot options in the OpenCore picker and the boot process
are determined separately from the scanning algorithm.
The display order as follows:
The display order \DIFaddbegin \DIFadd{is }\DIFaddend as follows:
\begin{itemize}
\tightlist
@ -3449,7 +3475,20 @@ the default boot entry choice will remain changed until the next manual reconfig
\end{itemize}
To display all entries, the picker menu can be reloaded into ``Extended Mode'' by pressing the
\texttt{Spacebar} key. Hiding auxiliary entries may increase boot performance on multi-disk systems.
\texttt{Spacebar} key. Hiding auxiliary entries may increase boot performance on multi-disk systems\DIFaddbegin \DIFadd{.
}
\item
\texttt{\DIFadd{InstanceIdentifier}}\\
\textbf{\DIFadd{Type}}\DIFadd{: }\texttt{\DIFadd{plist\ string}}\\
\textbf{\DIFadd{Failsafe}}\DIFadd{: Empty}\\
\textbf{\DIFadd{Description}}\DIFadd{: An optional identifier for the current instance of OpenCore.
}
\DIFadd{This should typically be a short alphanumeric string. The current use of this value is
to optionally target }\texttt{\DIFadd{.contentVisibility}} \DIFadd{files to specific instances of OpenCore,
as explained in the }\hyperref[bootalgorithm]{Boot Algorithm} \DIFadd{section}\DIFaddend .
\item
\texttt{LauncherOption}\\

Binary file not shown.

View File

@ -1084,6 +1084,8 @@
<false/>
<key>HideAuxiliary</key>
<true/>
<key>InstanceIdentifier</key>
<string></string>
<key>LauncherOption</key>
<string>Disabled</string>
<key>LauncherPath</key>

View File

@ -1084,6 +1084,8 @@
<false/>
<key>HideAuxiliary</key>
<true/>
<key>InstanceIdentifier</key>
<string></string>
<key>LauncherOption</key>
<string>Disabled</string>
<key>LauncherPath</key>

View File

@ -31,6 +31,16 @@
#define OC_TRACE_PARSE_VARS DEBUG_VERBOSE
#endif
/**
Maximum safe instance identifier size.
**/
#define OC_MAX_INSTANCE_IDENTIFIER_SIZE 64
/**
Maximum allowed `.contentVisibility` file size.
**/
#define OC_MAX_CONTENT_VISIBILITY_SIZE 512
/**
Primary picker context.
**/
@ -935,6 +945,10 @@ struct OC_PICKER_CONTEXT_ {
//
CONST CHAR8 *PickerVariant;
//
// Boot loader instance identifier.
//
CONST CHAR8 *InstanceIdentifier;
//
// Enable polling boot arguments.
//
BOOLEAN PollAppleHotKeys;

View File

@ -335,6 +335,7 @@ OC_DECLARE (OC_MISC_BLESS_ARRAY)
#define OC_MISC_BOOT_FIELDS(_, __) \
_(OC_STRING , PickerMode , , OC_STRING_CONSTR ("Builtin", _, __) , OC_DESTR (OC_STRING)) \
_(OC_STRING , HibernateMode , , OC_STRING_CONSTR ("None", _, __) , OC_DESTR (OC_STRING)) \
_(OC_STRING , InstanceIdentifier , , OC_STRING_CONSTR ("", _, __) , OC_DESTR (OC_STRING)) \
_(OC_STRING , LauncherOption , , OC_STRING_CONSTR ("Disabled", _, __), OC_DESTR (OC_STRING) ) \
_(OC_STRING , LauncherPath , , OC_STRING_CONSTR ("Default", _, __) , OC_DESTR (OC_STRING) ) \
_(UINT32 , ConsoleAttributes , , 0 , ()) \

View File

@ -28,7 +28,7 @@
WARNING: This protocol is currently undergoing active design.
**/
#define OC_BOOT_ENTRY_PROTOCOL_REVISION 3
#define OC_BOOT_ENTRY_PROTOCOL_REVISION 4
/**
Forward declaration of OC_BOOT_ENTRY_PROTOCOL structure.

View File

@ -24,7 +24,7 @@
WARNING: This protocol is currently undergoing active design.
**/
#define OC_INTERFACE_REVISION 8
#define OC_INTERFACE_REVISION 9
/**
The GUID of the OC_INTERFACE_PROTOCOL.

View File

@ -200,7 +200,8 @@ STATIC
INTERNAL_ENTRY_VISIBILITY
ReadEntryVisibility (
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
IN BOOLEAN IsFolder
IN BOOLEAN IsFolder,
IN CONST CHAR8 *InstanceIdentifier
)
{
EFI_STATUS Status;
@ -213,6 +214,9 @@ ReadEntryVisibility (
CHAR16 *VisibilityTerminator;
BOOLEAN Result;
CHAR8 *Visibility;
CHAR8 *VisibilityCommand;
CHAR8 *Walker;
UINTN IdentifierLength;
Status = gBS->LocateDevicePath (
&gEfiSimpleFileSystemProtocolGuid,
@ -280,7 +284,7 @@ ReadEntryVisibility (
//
// Note, this guarantees nul-termination.
//
Visibility = OcReadFile (FileSystem, VisibilityPath, NULL, 64);
Visibility = OcReadFile (FileSystem, VisibilityPath, NULL, OC_MAX_CONTENT_VISIBILITY_SIZE);
FreePool (VisibilityPath);
@ -288,17 +292,68 @@ ReadEntryVisibility (
return BootEntryNormal;
}
if (AsciiStrnCmp (Visibility, "Disabled", L_STR_LEN ("Disabled")) == 0) {
//
// Allow for terminating new line, but be strict about it -
// after removing this, things must match exactly.
//
Walker = AsciiStrStr (Visibility, "\r");
if (Walker != NULL) {
*Walker = '\0';
}
Walker = AsciiStrStr (Visibility, "\n");
if (Walker != NULL) {
*Walker = '\0';
}
Walker = AsciiStrStr (Visibility, ":");
if (Walker == NULL) {
VisibilityCommand = Visibility;
} else {
if (*InstanceIdentifier == '\0') {
DEBUG ((DEBUG_INFO, "OCB: No InstanceIdentifier, ignoring qualified visibility\n"));
FreePool (Visibility);
return BootEntryNormal;
}
*Walker++ = '\0';
VisibilityCommand = Walker;
Walker = Visibility;
IdentifierLength = AsciiStrLen (InstanceIdentifier);
Status = EFI_NOT_FOUND;
do {
if ( (AsciiStrnCmp (Walker, InstanceIdentifier, IdentifierLength) == 0)
&& ((Walker[IdentifierLength] == '\0') || (Walker[IdentifierLength] == ',')))
{
Status = EFI_SUCCESS;
break;
}
Walker = AsciiStrStr (Walker, ",");
if (Walker != NULL) {
++Walker;
}
} while (Walker != NULL);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_INFO, "OCB: \"%a\" not present in \"%a\" ignoring visibility\n", InstanceIdentifier, Visibility));
FreePool (Visibility);
return BootEntryNormal;
}
}
if (AsciiStrCmp (VisibilityCommand, "Disabled") == 0) {
FreePool (Visibility);
return BootEntryDisabled;
}
if (AsciiStrnCmp (Visibility, "Auxiliary", L_STR_LEN ("Auxiliary")) == 0) {
if (AsciiStrCmp (VisibilityCommand, "Auxiliary") == 0) {
FreePool (Visibility);
return BootEntryAuxiliary;
}
DEBUG ((DEBUG_INFO, "OCB: Discovered unsupported .contentVisibility\n"));
DEBUG ((DEBUG_INFO, "OCB: Discovered unsupported visibility \"%a\"\n", VisibilityCommand));
FreePool (Visibility);
return BootEntryNormal;
@ -487,7 +542,7 @@ AddBootEntryOnFileSystem (
//
// Skip disabled entries, like OpenCore bootloader.
//
Visibility = ReadEntryVisibility (DevicePath, IsFolder);
Visibility = ReadEntryVisibility (DevicePath, IsFolder, BootContext->PickerContext->InstanceIdentifier);
if (Visibility == BootEntryDisabled) {
DEBUG ((DEBUG_INFO, "OCB: Discarding disabled entry by visibility\n"));
if (IsReallocated) {

View File

@ -410,6 +410,7 @@ OC_SCHEMA
OC_SCHEMA_STRING_IN ("HibernateMode", OC_GLOBAL_CONFIG, Misc.Boot.HibernateMode),
OC_SCHEMA_BOOLEAN_IN ("HibernateSkipsPicker", OC_GLOBAL_CONFIG, Misc.Boot.HibernateSkipsPicker),
OC_SCHEMA_BOOLEAN_IN ("HideAuxiliary", OC_GLOBAL_CONFIG, Misc.Boot.HideAuxiliary),
OC_SCHEMA_STRING_IN ("InstanceIdentifier", OC_GLOBAL_CONFIG, Misc.Boot.InstanceIdentifier),
OC_SCHEMA_STRING_IN ("LauncherOption", OC_GLOBAL_CONFIG, Misc.Boot.LauncherOption),
OC_SCHEMA_STRING_IN ("LauncherPath", OC_GLOBAL_CONFIG, Misc.Boot.LauncherPath),
OC_SCHEMA_INTEGER_IN ("PickerAttributes", OC_GLOBAL_CONFIG, Misc.Boot.PickerAttributes),

View File

@ -790,6 +790,7 @@ OcMiscBoot (
CHAR16 **BlessOverride;
CONST CHAR8 *AsciiPicker;
CONST CHAR8 *AsciiPickerVariant;
CONST CHAR8 *AsciiInstanceIdentifier;
CONST CHAR8 *AsciiDmg;
AsciiPicker = OC_BLOB_GET (&Config->Misc.Boot.PickerMode);
@ -805,7 +806,8 @@ OcMiscBoot (
PickerMode = OcPickerModeBuiltin;
}
AsciiPickerVariant = OC_BLOB_GET (&Config->Misc.Boot.PickerVariant);
AsciiPickerVariant = OC_BLOB_GET (&Config->Misc.Boot.PickerVariant);
AsciiInstanceIdentifier = OC_BLOB_GET (&Config->Misc.Boot.InstanceIdentifier);
AsciiDmg = OC_BLOB_GET (&Config->Misc.Security.DmgLoading);
@ -934,6 +936,7 @@ OcMiscBoot (
Context->ConsoleAttributes = Config->Misc.Boot.ConsoleAttributes;
Context->PickerAttributes = Config->Misc.Boot.PickerAttributes;
Context->PickerVariant = AsciiPickerVariant;
Context->InstanceIdentifier = AsciiInstanceIdentifier;
Context->BlacklistAppleUpdate = Config->Misc.Security.BlacklistAppleUpdate;
if ((Config->Misc.Security.ExposeSensitiveData & OCS_EXPOSE_VERSION_UI) != 0) {

View File

@ -183,6 +183,42 @@ CheckBlessOverride (
return ErrorCount;
}
STATIC
UINT32
ValidateInstanceIdentifier (
IN CONST CHAR8 *InstanceIdentifier
)
{
UINT32 ErrorCount;
CHAR8 InstanceIdentifierCopy[OC_MAX_INSTANCE_IDENTIFIER_SIZE];
UINTN Length;
ErrorCount = 0;
if (AsciiStrSize (InstanceIdentifier) > OC_MAX_INSTANCE_IDENTIFIER_SIZE) {
DEBUG ((DEBUG_WARN, "Misc->Boot->InstanceIdentifier cannot be longer than %d bytes!\n", OC_MAX_INSTANCE_IDENTIFIER_SIZE));
++ErrorCount;
} else {
if (AsciiStrStr (InstanceIdentifier, ",") != NULL) {
DEBUG ((DEBUG_WARN, "Misc->Boot->InstanceIdentifier cannot contain comma (,)!\n"));
++ErrorCount;
}
//
// Illegal chars
//
Length = AsciiStrLen (InstanceIdentifier);
AsciiStrnCpyS (InstanceIdentifierCopy, OC_MAX_INSTANCE_IDENTIFIER_SIZE, InstanceIdentifier, Length);
AsciiFilterString (InstanceIdentifierCopy, TRUE);
if (OcAsciiStrniCmp (InstanceIdentifierCopy, InstanceIdentifier, Length) != 0) {
DEBUG ((DEBUG_WARN, "Misc->Boot->InstanceIdentifier cannot contain CR, LF, TAB or any other non-ASCII characters!\n"));
++ErrorCount;
}
}
return ErrorCount;
}
STATIC
UINT32
CheckMiscBoot (
@ -199,6 +235,7 @@ CheckMiscBoot (
BOOLEAN HasOpenCanopyEfiDriver;
CONST CHAR8 *PickerMode;
CONST CHAR8 *PickerVariant;
CONST CHAR8 *InstanceIdentifier;
UINTN PVSumSize;
UINTN PVPathFixedSize;
BOOLEAN IsPickerAudioAssistEnabled;
@ -258,6 +295,9 @@ CheckMiscBoot (
++ErrorCount;
}
InstanceIdentifier = OC_BLOB_GET (&Config->Misc.Boot.InstanceIdentifier);
ErrorCount += ValidateInstanceIdentifier (InstanceIdentifier);
//
// Check the length of path relative to OC directory.
//