Skip to content

Commit

Permalink
OcBootManagementLib: Add InstanceIdentifier, and ability to target .c…
Browse files Browse the repository at this point in the history
…ontentVisibility to specific instances
  • Loading branch information
mikebeaton committed Jun 23, 2023
1 parent d4bd64c commit a4da464
Show file tree
Hide file tree
Showing 12 changed files with 165 additions and 13 deletions.
1 change: 1 addition & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
41 changes: 37 additions & 4 deletions Docs/Configuration.tex
Original file line number Diff line number Diff line change
Expand Up @@ -3125,6 +3125,8 @@ \subsection{Introduction}\label{miscintro}
\end{itemize} \medskip
\end{itemize}

\subsubsection{Boot Algorithm}\label{bootalgorithm}

The algorithm to determine boot options behaves as follows:

\begin{enumerate}
Expand All @@ -3146,12 +3148,14 @@ \subsection{Introduction}\label{miscintro}
\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}
Expand All @@ -3165,14 +3169,32 @@ \subsection{Introduction}\label{miscintro}
\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
Expand Down Expand Up @@ -3391,6 +3413,17 @@ \subsection{Boot Properties}\label{miscbootprops}
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}\\
Expand Down
2 changes: 2 additions & 0 deletions Docs/Sample.plist
Original file line number Diff line number Diff line change
Expand Up @@ -1084,6 +1084,8 @@
<false/>
<key>HideAuxiliary</key>
<true/>
<key>InstanceIdentifier</key>
<string></string>
<key>LauncherOption</key>
<string>Disabled</string>
<key>LauncherPath</key>
Expand Down
2 changes: 2 additions & 0 deletions Docs/SampleCustom.plist
Original file line number Diff line number Diff line change
Expand Up @@ -1084,6 +1084,8 @@
<false/>
<key>HideAuxiliary</key>
<true/>
<key>InstanceIdentifier</key>
<string></string>
<key>LauncherOption</key>
<string>Disabled</string>
<key>LauncherPath</key>
Expand Down
14 changes: 14 additions & 0 deletions Include/Acidanthera/Library/OcBootManagementLib.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
**/
Expand Down Expand Up @@ -935,6 +945,10 @@ struct OC_PICKER_CONTEXT_ {
//
CONST CHAR8 *PickerVariant;
//
// Boot loader instance identifier.
//
CONST CHAR8 *InstanceIdentifier;
//
// Enable polling boot arguments.
//
BOOLEAN PollAppleHotKeys;
Expand Down
1 change: 1 addition & 0 deletions Include/Acidanthera/Library/OcConfigurationLib.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 , ()) \
Expand Down
2 changes: 1 addition & 1 deletion Include/Acidanthera/Protocol/OcBootEntry.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion Include/Acidanthera/Protocol/OcInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
67 changes: 61 additions & 6 deletions Library/OcBootManagementLib/BootEntryManagement.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -213,6 +214,9 @@ ReadEntryVisibility (
CHAR16 *VisibilityTerminator;
BOOLEAN Result;
CHAR8 *Visibility;
CHAR8 *VisibilityCommand;
CHAR8 *Walker;
UINTN IdentifierLength;

Status = gBS->LocateDevicePath (
&gEfiSimpleFileSystemProtocolGuid,
Expand Down Expand Up @@ -280,25 +284,76 @@ ReadEntryVisibility (
//
// Note, this guarantees nul-termination.
//
Visibility = OcReadFile (FileSystem, VisibilityPath, NULL, 64);
Visibility = OcReadFile (FileSystem, VisibilityPath, NULL, OC_MAX_CONTENT_VISIBILITY_SIZE);

FreePool (VisibilityPath);

if (Visibility == NULL) {
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;
Expand Down Expand Up @@ -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) {
Expand Down
1 change: 1 addition & 0 deletions Library/OcConfigurationLib/OcConfigurationLib.c
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
5 changes: 4 additions & 1 deletion Library/OcMainLib/OpenCoreMisc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);

Expand Down Expand Up @@ -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) {
Expand Down
40 changes: 40 additions & 0 deletions Utilities/ocvalidate/ValidateMisc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand All @@ -199,6 +235,7 @@ CheckMiscBoot (
BOOLEAN HasOpenCanopyEfiDriver;
CONST CHAR8 *PickerMode;
CONST CHAR8 *PickerVariant;
CONST CHAR8 *InstanceIdentifier;
UINTN PVSumSize;
UINTN PVPathFixedSize;
BOOLEAN IsPickerAudioAssistEnabled;
Expand Down Expand Up @@ -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.
//
Expand Down

0 comments on commit a4da464

Please sign in to comment.