提交 8a514aa7 编写于 作者: M Marvin Häuser 提交者: Vitaly Cheptsov

OcBootManagementLib: Support default custom entries

上级 557b3f18
......@@ -194,6 +194,10 @@ typedef struct OC_BOOT_ENTRY_ {
//
BOOLEAN IsGeneric;
//
// Set when this entry refers to a custom boot entry.
//
BOOLEAN IsCustom;
//
// Should make this option default boot option.
//
BOOLEAN SetDefault;
......
......@@ -613,6 +613,8 @@ AddBootEntryFromCustomEntry (
}
}
BootEntry->IsCustom = TRUE;
RegisterBootOption (
BootContext,
FileSystem,
......@@ -996,7 +998,9 @@ EFI_STATUS
AddBootEntryFromBootOption (
IN OUT OC_BOOT_CONTEXT *BootContext,
IN UINT16 BootOption,
IN BOOLEAN LazyScan
IN BOOLEAN LazyScan,
IN OUT OC_BOOT_FILESYSTEM *CustomFileSystem,
IN OUT UINT32 *CustomIndex
)
{
EFI_STATUS Status;
......@@ -1012,6 +1016,10 @@ AddBootEntryFromBootOption (
EFI_LOAD_OPTION *LoadOption;
UINTN LoadOptionSize;
CONST OC_CUSTOM_BOOT_DEVICE_PATH *CustomDevPath;
UINT32 Index;
INTN CmpResult;
DEBUG ((DEBUG_INFO, "OCB: Building entry from Boot%04x\n", BootOption));
//
......@@ -1179,6 +1187,31 @@ AddBootEntryFromBootOption (
NULL
);
} while (NumPatchedNodes > 0);
//
// If requested, pre-construct a custom entry found in BOOT#### so it can be
// set as default.
//
if (ExpandedDevicePath == NULL && CustomFileSystem != NULL) {
ASSERT (CustomIndex != NULL);
CustomDevPath = InternetGetOcCustomDevPath (DevicePath);
for (Index = 0; Index < BootContext->PickerContext->AllCustomEntryCount; ++Index) {
CmpResult = MixedStrCmp (
CustomDevPath->EntryName.PathName,
BootContext->PickerContext->CustomEntries[Index].Name
);
if (CmpResult == 0) {
*CustomIndex = Index;
AddBootEntryFromCustomEntry (
BootContext,
CustomFileSystem,
&BootContext->PickerContext->CustomEntries[Index]
);
break;
}
}
}
FreePool (DevicePath);
DevicePath = ExpandedDevicePath;
......@@ -1397,25 +1430,21 @@ AddFileSystemEntry (
}
STATIC
EFI_STATUS
AddFileSystemEntryForCustom (
IN OUT OC_BOOT_CONTEXT *BootContext
OC_BOOT_FILESYSTEM *
CreateFileSystemForCustom (
IN OUT CONST OC_BOOT_CONTEXT *BootContext
)
{
EFI_STATUS Status;
OC_BOOT_FILESYSTEM *FileSystem;
UINTN Index;
//
// When there are no custom entries and NVRAM reset is hidden
// we have no work to do.
//
if (BootContext->PickerContext->AllCustomEntryCount == 0
&& (!BootContext->PickerContext->ShowNvramReset
|| BootContext->PickerContext->HideAuxiliary)) {
return EFI_NOT_FOUND;
FileSystem = AllocateZeroPool (sizeof (*FileSystem));
if (FileSystem == NULL) {
return NULL;
}
FileSystem->Handle = OC_CUSTOM_FS_HANDLE;
InitializeListHead (&FileSystem->BootEntries);
DEBUG ((
DEBUG_INFO,
"OCB: Adding fs %p for %u custom entries%a%a\n",
......@@ -1425,19 +1454,40 @@ AddFileSystemEntryForCustom (
BootContext->PickerContext->HideAuxiliary ? " (aux hidden)" : " (aux shown)"
));
FileSystem = AllocateZeroPool (sizeof (*FileSystem));
if (FileSystem == NULL) {
return EFI_OUT_OF_RESOURCES;
}
return FileSystem;
}
FileSystem->Handle = OC_CUSTOM_FS_HANDLE;
InitializeListHead (&FileSystem->BootEntries);
InsertTailList (&BootContext->FileSystems, &FileSystem->Link);
++BootContext->FileSystemCount;
STATIC
EFI_STATUS
AddFileSystemEntryForCustom (
IN OUT OC_BOOT_CONTEXT *BootContext,
IN OUT OC_BOOT_FILESYSTEM *FileSystem,
IN UINT32 PrecreatedCustomIndex
)
{
EFI_STATUS Status;
UINTN Index;
//
// When there are no custom entries and NVRAM reset is hidden
// we have no work to do.
//
if (BootContext->PickerContext->AllCustomEntryCount == 0
&& (!BootContext->PickerContext->ShowNvramReset
|| BootContext->PickerContext->HideAuxiliary)) {
return EFI_NOT_FOUND;
}
Status = EFI_NOT_FOUND;
for (Index = 0; Index < BootContext->PickerContext->AllCustomEntryCount; ++Index) {
Status = AddBootEntryFromCustomEntry (
//
// Skip the custom boot entry that has already been created.
//
if (Index == PrecreatedCustomIndex) {
continue;
}
AddBootEntryFromCustomEntry (
BootContext,
FileSystem,
&BootContext->PickerContext->CustomEntries[Index]
......@@ -1681,6 +1731,9 @@ OcScanForBootEntries (
UINTN Index;
LIST_ENTRY *Link;
OC_BOOT_FILESYSTEM *FileSystem;
OC_BOOT_FILESYSTEM *CustomFileSystem;
OC_BOOT_FILESYSTEM *CustomFileSystemDefault;
UINT32 DefaultCustomIndex;
//
// Obtain the list of filesystems filtered by scan policy.
......@@ -1706,9 +1759,33 @@ OcScanForBootEntries (
);
}
CustomFileSystem = CreateFileSystemForCustom (BootContext);
//
// Delay CustomFileSystem insertion to have custom entries and the end.
//
DefaultCustomIndex = MAX_UINT32;
if (Context->BootOrder != NULL) {
CustomFileSystemDefault = CustomFileSystem;
for (Index = 0; Index < Context->BootOrderCount; ++Index) {
AddBootEntryFromBootOption (BootContext, Context->BootOrder[Index], FALSE);
AddBootEntryFromBootOption (
BootContext,
Context->BootOrder[Index],
FALSE,
CustomFileSystemDefault,
&DefaultCustomIndex
);
//
// Pre-create at most one custom entry. Under normal circumstances, no
// more than one entry should exist anyway.
//
if (DefaultCustomIndex != MAX_UINT32) {
CustomFileSystemDefault = NULL;
}
}
}
......@@ -1744,10 +1821,18 @@ OcScanForBootEntries (
AddBootEntryFromSelfRecovery (BootContext, FileSystem);
}
//
// Build custom and system options.
//
AddFileSystemEntryForCustom (BootContext);
if (CustomFileSystem != NULL) {
//
// Insert the custom file system last for entry order.
//
InsertTailList (&BootContext->FileSystems, &CustomFileSystem->Link);
++BootContext->FileSystemCount;
//
// Build custom and system options.
//
AddFileSystemEntryForCustom (BootContext, CustomFileSystem, DefaultCustomIndex);
}
if (BootContext->BootEntryCount == 0) {
OcFreeBootContext (BootContext);
......@@ -1775,6 +1860,8 @@ OcScanForDefaultBootEntry (
EFI_STATUS Status;
UINTN NoHandles;
EFI_HANDLE *Handles;
UINT32 DefaultCustomIndex;
OC_BOOT_FILESYSTEM *CustomFileSystem;
//
// Obtain empty list of filesystems.
......@@ -1797,9 +1884,27 @@ OcScanForDefaultBootEntry (
);
}
CustomFileSystem = CreateFileSystemForCustom (BootContext);
if (CustomFileSystem != NULL) {
//
// The entry order does not matter, UI will not be shown.
//
InsertTailList (&BootContext->FileSystems, &CustomFileSystem->Link);
++BootContext->FileSystemCount;
}
if (Context->BootOrder != NULL) {
for (Index = 0; Index < Context->BootOrderCount; ++Index) {
AddBootEntryFromBootOption (BootContext, Context->BootOrder[Index], TRUE);
//
// DefaultCustomIndex is not used as the entry list will never be shown.
//
AddBootEntryFromBootOption (
BootContext,
Context->BootOrder[Index],
TRUE,
CustomFileSystem,
&DefaultCustomIndex
);
//
// Return as long as we are good.
......@@ -1865,10 +1970,13 @@ OcScanForDefaultBootEntry (
FreePool (Handles);
}
//
// Build custom and system options.
//
AddFileSystemEntryForCustom (BootContext);
if (CustomFileSystem != NULL) {
//
// Build custom and system options. Do not try to deduplicate custom options
// as the list is never shown.
//
AddFileSystemEntryForCustom (BootContext, CustomFileSystem, MAX_UINT32);
}
if (BootContext->DefaultEntry == NULL) {
OcFreeBootContext (BootContext);
......
......@@ -26,6 +26,41 @@
#define OC_CUSTOM_FS_HANDLE ((EFI_HANDLE)(UINTN) 0x2007C5F5U)
///
/// Identifies the DevicePath structure for OpenCore custom entries.
///
#define OC_CUSTOM_BOOT_DEVICE_PATH_GUID \
{ 0xd6f263f9, 0x0b19, 0x4670, \
{ 0xb0, 0xa4, 0x9d, 0x95, 0x9f, 0x58, 0xdf, 0x65 } }
#pragma pack(1)
///
/// DevicePath to describe OpenCore custom entries.
///
typedef PACKED struct {
VENDOR_DEVICE_PATH Hdr;
FILEPATH_DEVICE_PATH EntryName;
} OC_CUSTOM_BOOT_DEVICE_PATH;
//
// Ideally, a variant of FILEPATH_DEVICE_PATH will be used with PathName as a
// flexible array. Such cannot be used for declarations, so provide an
// alternative.
//
typedef PACKED struct {
VENDOR_DEVICE_PATH Header;
EFI_DEVICE_PATH_PROTOCOL EntryName;
} OC_CUSTOM_BOOT_DEVICE_PATH_DECL;
#pragma pack()
///
/// The size of a OC_CUSTOM_BOOT_DEVICE_PATH structure excluding the name.
///
#define SIZE_OF_OC_CUSTOM_BOOT_DEVICE_PATH \
(sizeof (VENDOR_DEVICE_PATH) + SIZE_OF_FILEPATH_DEVICE_PATH)
typedef struct {
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
OC_APPLE_DISK_IMAGE_CONTEXT *DmgContext;
......@@ -169,4 +204,14 @@ InternalSystemActionResetNvram (
VOID
);
/**
Determines whether DevicePath is an OpenCore custom boot entry.
@returns The OpenCore custom boot entry, or NULL.
**/
CONST OC_CUSTOM_BOOT_DEVICE_PATH *
InternetGetOcCustomDevPath (
IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath
);
#endif // BOOT_MANAGEMENET_INTERNAL_H
......@@ -39,6 +39,57 @@
#include <Library/UefiLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
///
/// Template for an OpenCore custom boot entry DevicePath node.
///
STATIC CONST OC_CUSTOM_BOOT_DEVICE_PATH_DECL mOcCustomBootDevPathTemplate = {
{
{
HARDWARE_DEVICE_PATH,
HW_VENDOR_DP,
{ sizeof (VENDOR_DEVICE_PATH), 0 }
},
OC_CUSTOM_BOOT_DEVICE_PATH_GUID
},
{
MEDIA_DEVICE_PATH,
MEDIA_FILEPATH_DP,
{ SIZE_OF_FILEPATH_DEVICE_PATH, 0 }
}
};
CONST OC_CUSTOM_BOOT_DEVICE_PATH *
InternetGetOcCustomDevPath (
IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath
)
{
UINTN DevicePathSize;
INTN CmpResult;
CONST OC_CUSTOM_BOOT_DEVICE_PATH *CustomDevPath;
DevicePathSize = GetDevicePathSize (DevicePath);
if (DevicePathSize < SIZE_OF_OC_CUSTOM_BOOT_DEVICE_PATH) {
return NULL;
}
CmpResult = CompareMem (
DevicePath,
&mOcCustomBootDevPathTemplate.Header,
sizeof (mOcCustomBootDevPathTemplate.Header)
);
if (CmpResult != 0) {
return NULL;
}
CustomDevPath = (CONST OC_CUSTOM_BOOT_DEVICE_PATH *) DevicePath;
if (CustomDevPath->EntryName.Header.Type != MEDIA_DEVICE_PATH
|| CustomDevPath->EntryName.Header.SubType != MEDIA_FILEPATH_DP) {
return NULL;
}
return CustomDevPath;
}
EFI_LOAD_OPTION *
InternalGetBootOptionData (
OUT UINTN *OptionSize,
......@@ -226,10 +277,9 @@ InternalDebugBootEnvironment (
}
STATIC
OC_BOOT_ENTRY *
InternalGetBootEntryByDevicePath (
IN OUT OC_BOOT_ENTRY *BootEntries,
IN UINTN NumBootEntries,
BOOLEAN
InternalMatchBootEntryByDevicePath (
IN OUT OC_BOOT_ENTRY *BootEntry,
IN EFI_DEVICE_PATH_PROTOCOL *UefiDevicePath,
IN EFI_DEVICE_PATH_PROTOCOL *UefiRemainingDevicePath,
IN UINTN UefiDevicePathSize,
......@@ -243,68 +293,81 @@ InternalGetBootEntryByDevicePath (
EFI_DEVICE_PATH_PROTOCOL *OcDevicePath;
EFI_DEVICE_PATH_PROTOCOL *OcRemainingDevicePath;
OC_BOOT_ENTRY *BootEntry;
UINTN Index;
RootDevicePathSize = ((UINT8 *)UefiRemainingDevicePath - (UINT8 *)UefiDevicePath);
for (Index = 0; Index < NumBootEntries; ++Index) {
BootEntry = &BootEntries[Index];
if (BootEntry->DevicePath == NULL || BootEntry->Type == OC_BOOT_SYSTEM) {
continue;
}
if (BootEntry->DevicePath == NULL || BootEntry->Type == OC_BOOT_SYSTEM) {
return FALSE;
}
OcDevicePath = BootEntry->DevicePath;
OcDevicePath = BootEntry->DevicePath;
if ((GetDevicePathSize (OcDevicePath) - END_DEVICE_PATH_LENGTH) < RootDevicePathSize) {
continue;
}
if ((GetDevicePathSize (OcDevicePath) - END_DEVICE_PATH_LENGTH) < RootDevicePathSize) {
return FALSE;
}
CmpResult = CompareMem (OcDevicePath, UefiDevicePath, RootDevicePathSize);
if (CmpResult != 0) {
continue;
CmpResult = CompareMem (OcDevicePath, UefiDevicePath, RootDevicePathSize);
if (CmpResult != 0) {
return FALSE;
}
//
// FIXME: Ensure that all the entries get properly filtered against any
// malicious sources. The drive itself should already be safe, but it is
// unclear whether a potentially safe device path can be transformed into
// an unsafe one.
//
OcRemainingDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)(
(UINT8 *)OcDevicePath + RootDevicePathSize
);
if (!IsBootNext) {
//
// For non-BootNext boot, the File Paths must match for the entries to be
// matched. Startup Disk however only stores the drive's Device Path
// excluding the booter path, which we treat as a match as well.
//
if (!IsDevicePathEnd (UefiRemainingDevicePath)
&& !IsDevicePathEqual (UefiRemainingDevicePath, OcRemainingDevicePath)
) {
return FALSE;
}
} else {
//
// FIXME: Ensure that all the entries get properly filtered against any
// malicious sources. The drive itself should already be safe, but it is
// unclear whether a potentially safe device path can be transformed into
// an unsafe one.
// Only use the BootNext path when it has a file path.
//
OcRemainingDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)(
(UINT8 *)OcDevicePath + RootDevicePathSize
);
if (!IsBootNext) {
if (!IsDevicePathEnd (UefiRemainingDevicePath)) {
//
// For non-BootNext boot, the File Paths must match for the entries to be
// matched. Startup Disk however only stores the drive's Device Path
// excluding the booter path, which we treat as a match as well.
// TODO: Investigate whether macOS adds BootNext entries that are not
// possibly located by bless.
//
if (!IsDevicePathEnd (UefiRemainingDevicePath)
&& !IsDevicePathEqual (UefiRemainingDevicePath, OcRemainingDevicePath)
) {
continue;
}
} else {
//
// Only use the BootNext path when it has a file path.
//
if (!IsDevicePathEnd (UefiRemainingDevicePath)) {
//
// TODO: Investigate whether macOS adds BootNext entries that are not
// possibly located by bless.
//
FreePool (BootEntry->DevicePath);
BootEntry->DevicePath = AllocateCopyPool (
UefiDevicePathSize,
UefiDevicePath
);
}
FreePool (BootEntry->DevicePath);
BootEntry->DevicePath = AllocateCopyPool (
UefiDevicePathSize,
UefiDevicePath
);
}
}
return TRUE;
}
STATIC
BOOLEAN
InternalMatchCustomBootEntryByDevicePath (
IN OUT OC_BOOT_ENTRY *BootEntry,
IN CONST OC_CUSTOM_BOOT_DEVICE_PATH *DevicePath
)
{
INTN CmpResult;
if (!BootEntry->IsCustom) {
return FALSE;
}
return BootEntry;
CmpResult = StrCmp (BootEntry->Name, DevicePath->EntryName.PathName);
if (CmpResult != 0) {
return FALSE;
}
return NULL;
return TRUE;
}
STATIC
......@@ -671,7 +734,7 @@ OcSetDefaultBootEntry (
EFI_DEVICE_PATH *BootOptionDevicePath;
EFI_DEVICE_PATH *BootOptionRemainingDevicePath;
EFI_HANDLE DeviceHandle;
OC_BOOT_ENTRY *MatchedEntry;
BOOLEAN MatchedEntry;
EFI_GUID *BootVariableGuid;
CHAR16 *BootOrderName;
CHAR16 *BootVariableName;
......@@ -686,6 +749,10 @@ OcSetDefaultBootEntry (
UINTN LoadOptionNameSize;
EFI_LOAD_OPTION *LoadOption;
CONST OC_CUSTOM_BOOT_DEVICE_PATH *CustomDevPath;
OC_CUSTOM_BOOT_DEVICE_PATH *DestCustomDevPath;
EFI_DEVICE_PATH_PROTOCOL *DestCustomEndNode;
//
// Do not allow when prohibited.
//
......@@ -718,14 +785,14 @@ OcSetDefaultBootEntry (
NULL
);
MatchedEntry = NULL;
MatchedEntry = FALSE;
BootChosenIndex = BootOrderCount;
for (Index = 0; Index < BootOrderCount; ++Index) {
if (BootOrder[Index] == 0x80) {
BootChosenIndex = Index;
}
if (MatchedEntry != NULL) {
if (MatchedEntry) {
if (BootChosenIndex != BootOrderCount) {
break;
}
......@@ -758,25 +825,38 @@ OcSetDefaultBootEntry (
);
if (!EFI_ERROR (Status)) {
MatchedEntry = InternalGetBootEntryByDevicePath (
MatchedEntry = InternalMatchBootEntryByDevicePath (
Entry,
1,
BootOptionDevicePath,
BootOptionRemainingDevicePath,
LoadOption->FilePathListLength,
FALSE
);
} else {
CustomDevPath = InternetGetOcCustomDevPath (BootOptionDevicePath);
if (CustomDevPath != NULL) {
MatchedEntry = InternalMatchCustomBootEntryByDevicePath (
Entry,
CustomDevPath
);
}
}
FreePool (LoadOption);
}
if (MatchedEntry == NULL) {
if (!MatchedEntry) {
//
// Write to Boot0080
//
LoadOptionNameSize = StrSize (Entry->Name);
DevicePathSize = GetDevicePathSize (Entry->DevicePath);
if (!Entry->IsCustom) {
DevicePathSize = GetDevicePathSize (Entry->DevicePath);
} else {
DevicePathSize = SIZE_OF_OC_CUSTOM_BOOT_DEVICE_PATH + LoadOptionNameSize + sizeof (EFI_DEVICE_PATH_PROTOCOL);
}
LoadOptionSize = sizeof (EFI_LOAD_OPTION) + LoadOptionNameSize + DevicePathSize;
LoadOption = AllocatePool (LoadOptionSize);
......@@ -791,7 +871,35 @@ OcSetDefaultBootEntry (
LoadOption->Attributes = LOAD_OPTION_ACTIVE | LOAD_OPTION_CATEGORY_BOOT;
LoadOption->FilePathListLength = (UINT16) DevicePathSize;
CopyMem (LoadOption + 1, Entry->Name, LoadOptionNameSize);
CopyMem ((UINT8 *) (LoadOption + 1) + LoadOptionNameSize, Entry->DevicePath, DevicePathSize);
if (!Entry->IsCustom) {
CopyMem ((UINT8 *) (LoadOption + 1) + LoadOptionNameSize, Entry->DevicePath, DevicePathSize);
} else {
DestCustomDevPath = (OC_CUSTOM_BOOT_DEVICE_PATH *) (
(UINT8 *) (LoadOption + 1) + LoadOptionNameSize
);
CopyMem (
DestCustomDevPath,
&mOcCustomBootDevPathTemplate,
sizeof (mOcCustomBootDevPathTemplate)
);
CopyMem (
DestCustomDevPath->EntryName.PathName,
Entry->Name,
LoadOptionNameSize
);
//
// FIXME: This may theoretically overflow.
//
DestCustomDevPath->EntryName.Header.Length[0] += (UINT8) LoadOptionNameSize;
DestCustomEndNode = (EFI_DEVICE_PATH_PROTOCOL *) (
(UINT8 *) DestCustomDevPath + SIZE_OF_OC_CUSTOM_BOOT_DEVICE_PATH + LoadOptionNameSize
);
SetDevicePathEndNode (DestCustomEndNode);
ASSERT (GetDevicePathSize (&DestCustomDevPath->Hdr.Header) == DevicePathSize);
}
Status = gRT->SetVariable (
BootVariableName,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册