From 8fe7bef8257d790355e27059f0f2feeab798e191 Mon Sep 17 00:00:00 2001 From: vit9696 Date: Sun, 1 Sep 2019 22:33:14 +0300 Subject: [PATCH] OcBootManagement: Support OPT and CMD+R with picker --- Include/Library/OcBootManagementLib.h | 82 ++++++--- Library/OcBootManagementLib/BootEntryInfo.c | 18 +- .../OcBootManagementLib/DefaultEntryChoice.c | 76 +++++++- .../OcBootManagementLib/OcBootManagementLib.c | 171 +++++++++++++++--- .../OcBootManagementLib.inf | 1 + .../OcBootManagementLib/PolicyManagement.c | 72 +++++--- 6 files changed, 334 insertions(+), 86 deletions(-) diff --git a/Include/Library/OcBootManagementLib.h b/Include/Library/OcBootManagementLib.h index 011ca543..f2c94b8f 100755 --- a/Include/Library/OcBootManagementLib.h +++ b/Include/Library/OcBootManagementLib.h @@ -20,6 +20,18 @@ #include #include +/** + Operating system boot type. + WARNING: This is only for debug purposes. +**/ +typedef enum OC_BOOT_ENTRY_TYPE_ { + OcBootUnknown, + OcBootApple, + OcBootAppleRecovery, + OcBootWindows, + OcBootCustom +} OC_BOOT_ENTRY_TYPE; + /** Discovered boot entry. Note, inner resources must be freed with OcResetBootEntry. @@ -40,9 +52,10 @@ typedef struct OC_BOOT_ENTRY_ { // CHAR16 *PathName; // - // Set when this entry is a custom externally loadable tool entry. + // Heuristical value signalising about booted os. + // WARNING: This is only for debug purposes. // - BOOLEAN IsCustom; + OC_BOOT_ENTRY_TYPE Type; // // Set when this entry is an externally available entry (e.g. USB). // @@ -52,15 +65,6 @@ typedef struct OC_BOOT_ENTRY_ { // BOOLEAN IsFolder; // - // Heuristical value signalising about recovery os. - // - BOOLEAN IsRecovery; - // - // Heuristical value signalising about Windows os (otherwise macOS). - // WARNING: This is only for debug purposes. - // - BOOLEAN IsWindows; - // // Load option data (usually "boot args") size. // UINT32 LoadOptionsSize; @@ -270,7 +274,7 @@ EFI_STATUS ); /** - Custom picker entry + Custom picker entry. **/ typedef struct { // @@ -283,6 +287,17 @@ typedef struct { CONST CHAR8 *Path; } OC_PICKER_ENTRY; +/** + Picker behaviour action. +**/ +typedef enum { + OcPickerDefault = 0, + OcPickerShowPicker = 1, + OcPickerResetNvram = 2, + OcPickerBootApple = 3, + OcPickerBootAppleRecovery = 4, +} OC_PICKER_CMD; + /** Boot picker context describing picker behaviour. **/ @@ -300,9 +315,10 @@ typedef struct { // UINT32 TimeoutSeconds; // - // Show boot menu or just boot the default option. + // Define picker behaviour. + // For example, show boot menu or just boot the default option. // - BOOLEAN ShowPicker; + OC_PICKER_CMD PickerCommand; // // Use custom (gOcVendorVariableGuid) for Boot#### variables. // @@ -412,21 +428,19 @@ OcScanForBootEntries ( ); /** - Obtain default entry from the list. + Obtain default entry from picker context. + @param[in] Context Picker context. @param[in,out] BootEntries Described list of entries, may get updated. @param[in] NumBootEntries Positive number of boot entries. - @param[in] CustomBootGuid Use custom GUID for Boot#### lookup. - @param[in] LoadHandle Handle to skip (potential OpenCore handle). - @retval boot entry or NULL. + @retval boot entry or 0. **/ -OC_BOOT_ENTRY * +UINT32 OcGetDefaultBootEntry ( - IN OUT OC_BOOT_ENTRY *BootEntries, - IN UINTN NumBootEntries, - IN BOOLEAN CustomBootGuid, - IN EFI_HANDLE LoadHandle OPTIONAL + IN OC_PICKER_CONTEXT *Context, + IN OUT OC_BOOT_ENTRY *BootEntries, + IN UINTN NumBootEntries ); /** @@ -490,6 +504,16 @@ OcIsAppleHibernateWake ( VOID ); +/** + Check pressed hotkeys and update booter context based on this. + + @param[in,out] Context Picker context. +**/ +VOID +OcLoadPickerHotkeys ( + IN OUT OC_PICKER_CONTEXT *Context + ); + /** Install missing boot policy, scan, and show simple boot menu. @@ -528,6 +552,18 @@ OcGetFileSystemPolicyType ( IN EFI_HANDLE Handle ); +/** + Check if supplied device path contains Apple bootloader. + + @param[in] DevicePath Device path. + + @retval TRUE for potentially Apple images. +**/ +BOOLEAN +OcIsAppleBootDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ); + /** Get loaded image protocol for Apple bootloader. diff --git a/Library/OcBootManagementLib/BootEntryInfo.c b/Library/OcBootManagementLib/BootEntryInfo.c index c09ca7a5..be6fc3e3 100644 --- a/Library/OcBootManagementLib/BootEntryInfo.c +++ b/Library/OcBootManagementLib/BootEntryInfo.c @@ -297,9 +297,8 @@ InternalSetBootEntryFlags ( BOOLEAN Result; INTN CmpResult; + BootEntry->Type = OcBootUnknown; BootEntry->IsFolder = FALSE; - BootEntry->IsRecovery = FALSE; - BootEntry->IsWindows = FALSE; DevicePathWalker = BootEntry->DevicePath; @@ -307,6 +306,9 @@ InternalSetBootEntryFlags ( return; } + // + // TODO: Move this to a new OcIsAppleRecoveryBootDevicePath function. + // while (!IsDevicePathEnd (DevicePathWalker)) { if ((DevicePathType (DevicePathWalker) == MEDIA_DEVICE_PATH) && (DevicePathSubType (DevicePathWalker) == MEDIA_FILEPATH_DP)) { @@ -318,7 +320,7 @@ InternalSetBootEntryFlags ( // BootEntry->IsFolder = (FilePath->PathName[Len - 1] == L'\\'); - if (!BootEntry->IsRecovery) { + if (BootEntry->Type == OcBootUnknown) { Result = OcOverflowSubUN ( Len, L_STR_LEN (L"com.apple.recovery.boot"), @@ -332,7 +334,7 @@ InternalSetBootEntryFlags ( L_STR_SIZE_NT (L"com.apple.recovery.boot") ); if (CmpResult == 0) { - BootEntry->IsRecovery = TRUE; + BootEntry->Type = OcBootAppleRecovery; break; } } @@ -345,6 +347,10 @@ InternalSetBootEntryFlags ( DevicePathWalker = NextDevicePathNode (DevicePathWalker); } + + if (BootEntry->Type == OcBootUnknown && OcIsAppleBootDevicePath (BootEntry->DevicePath)) { + BootEntry->Type = OcBootApple; + } } EFI_STATUS @@ -544,7 +550,7 @@ InternalFillValidBootEntries ( DEBUG_BULK_INFO, "OCB: Adding entry %u, external - %d, skip recovery - %d\n", (UINT32) EntryIndex, - Entries[EntryIndex].IsExternal, + DevPathScanInfo->IsExternal, DevPathScanInfo->SkipRecovery )); DebugPrintDevicePath (DEBUG_BULK_INFO, "DevicePath", DevicePath); @@ -571,7 +577,7 @@ InternalFillValidBootEntries ( DEBUG (( DEBUG_BULK_INFO, "OCB: Adding entry %u recovery (%s) - %r\n", - Entries[EntryIndex].IsExternal, + DevPathScanInfo->IsExternal, RecoveryPath != NULL ? RecoveryPath : L"", Status )); diff --git a/Library/OcBootManagementLib/DefaultEntryChoice.c b/Library/OcBootManagementLib/DefaultEntryChoice.c index 294f67df..653c3991 100644 --- a/Library/OcBootManagementLib/DefaultEntryChoice.c +++ b/Library/OcBootManagementLib/DefaultEntryChoice.c @@ -272,7 +272,7 @@ InternalGetBootEntryByDevicePath ( for (Index = 0; Index < NumBootEntries; ++Index) { BootEntry = &BootEntries[Index]; - if (BootEntry->IsCustom) { + if (BootEntry->Type == OcBootCustom) { continue; } @@ -352,8 +352,19 @@ InternalIsAppleLegacyLoadApp ( return FALSE; } +/** + Obtain default entry from the list. + + @param[in,out] BootEntries Described list of entries, may get updated. + @param[in] NumBootEntries Positive number of boot entries. + @param[in] CustomBootGuid Use custom GUID for Boot#### lookup. + @param[in] LoadHandle Handle to skip (potential OpenCore handle). + + @retval boot entry or NULL. +**/ +STATIC OC_BOOT_ENTRY * -OcGetDefaultBootEntry ( +InternalGetDefaultBootEntry ( IN OUT OC_BOOT_ENTRY *BootEntries, IN UINTN NumBootEntries, IN BOOLEAN CustomBootGuid, @@ -695,6 +706,63 @@ OcGetDefaultBootEntry ( return NULL; } +UINT32 +OcGetDefaultBootEntry ( + IN OC_PICKER_CONTEXT *Context, + IN OUT OC_BOOT_ENTRY *BootEntries, + IN UINTN NumBootEntries + ) +{ + UINT32 BootEntryIndex; + OC_BOOT_ENTRY *BootEntry; + UINTN Index; + + BootEntry = InternalGetDefaultBootEntry ( + BootEntries, + NumBootEntries, + Context->CustomBootGuid, + Context->ExcludeHandle + ); + + if (BootEntry != NULL) { + BootEntryIndex = (UINT32) (BootEntry - BootEntries); + DEBUG ((DEBUG_INFO, "OCB: Initial default is %u\n", BootEntryIndex)); + } else { + BootEntryIndex = 0; + DEBUG ((DEBUG_INFO, "OCB: Initial default is 0, fallback\n")); + } + + if (Context->PickerCommand == OcPickerBootApple) { + if (BootEntries[BootEntryIndex].Type != OcBootApple) { + for (Index = 0; Index < NumBootEntries; ++Index) { + if (BootEntries[Index].Type == OcBootApple) { + BootEntryIndex = (UINT32) Index; + DEBUG ((DEBUG_INFO, "OCB: Override default to Apple %u\n", BootEntryIndex)); + break; + } + } + } + } else if (Context->PickerCommand == OcPickerBootAppleRecovery) { + if (BootEntries[BootEntryIndex].Type != OcBootAppleRecovery) { + if (BootEntryIndex + 1 < NumBootEntries + && BootEntries[BootEntryIndex + 1].Type == OcBootAppleRecovery) { + BootEntryIndex = BootEntryIndex + 1; + DEBUG ((DEBUG_INFO, "OCB: Override default to Apple Recovery %u, next\n", BootEntryIndex)); + } else { + for (Index = 0; Index < NumBootEntries; ++Index) { + if (BootEntries[Index].Type == OcBootAppleRecovery) { + BootEntryIndex = (UINT32) Index; + DEBUG ((DEBUG_INFO, "OCB: Override default option to Apple Recovery %u\n", BootEntryIndex)); + break; + } + } + } + } + } + + return BootEntryIndex; +} + #if 0 STATIC VOID @@ -830,7 +898,7 @@ InternalLoadBootEntry ( if (DevicePath == NULL) { return EFI_UNSUPPORTED; } - } else if (BootEntry->IsCustom && BootEntry->DevicePath == NULL) { + } else if (BootEntry->Type == OcBootCustom && BootEntry->DevicePath == NULL) { ASSERT (Context->CustomRead != NULL); Status = Context->CustomRead ( @@ -894,7 +962,7 @@ InternalLoadBootEntry ( LoadedImage->LoadOptionsSize = BootEntry->LoadOptionsSize; LoadedImage->LoadOptions = BootEntry->LoadOptions; - if (BootEntry->IsCustom) { + if (BootEntry->Type == OcBootCustom) { DEBUG (( DEBUG_INFO, "OCB: Custom DeviceHandle %p FilePath %p\n", diff --git a/Library/OcBootManagementLib/OcBootManagementLib.c b/Library/OcBootManagementLib/OcBootManagementLib.c index fbca1b64..1a652951 100644 --- a/Library/OcBootManagementLib/OcBootManagementLib.c +++ b/Library/OcBootManagementLib/OcBootManagementLib.c @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -56,7 +57,7 @@ OcDescribeBootEntry ( // // Custom entries need no special description. // - if (BootEntry->IsCustom) { + if (BootEntry->Type == OcBootCustom) { return EFI_SUCCESS; } @@ -106,14 +107,16 @@ OcDescribeBootEntry ( // // - // Windows boot entry may have a custom name, so ensure IsWindows is set correctly. + // Windows boot entry may have a custom name, so ensure OcBootWindows is set correctly. // - DEBUG ((DEBUG_INFO, "Trying to detect Microsoft BCD\n")); - Status = ReadFileSize (FileSystem, L"\\EFI\\Microsoft\\Boot\\BCD", &BcdSize); - if (!EFI_ERROR (Status)) { - BootEntry->IsWindows = TRUE; - if (BootEntry->Name == NULL) { - BootEntry->Name = AllocateCopyPool (sizeof (L"BOOTCAMP Windows"), L"BOOTCAMP Windows"); + if (BootEntry->Type == OcBootUnknown) { + DEBUG ((DEBUG_INFO, "Trying to detect Microsoft BCD\n")); + Status = ReadFileSize (FileSystem, L"\\EFI\\Microsoft\\Boot\\BCD", &BcdSize); + if (!EFI_ERROR (Status)) { + BootEntry->Type = OcBootWindows; + if (BootEntry->Name == NULL) { + BootEntry->Name = AllocateCopyPool (sizeof (L"BOOTCAMP Windows"), L"BOOTCAMP Windows"); + } } } @@ -122,7 +125,9 @@ OcDescribeBootEntry ( if (BootEntry->Name != NULL && (!StrCmp (BootEntry->Name, L"Recovery HD") || !StrCmp (BootEntry->Name, L"Recovery"))) { - BootEntry->IsRecovery = TRUE; + if (BootEntry->Type == OcBootUnknown || BootEntry->Type == OcBootApple) { + BootEntry->Type = OcBootAppleRecovery; + } RecoveryBootName = InternalGetAppleRecoveryName (FileSystem, BootDirectoryName); if (RecoveryBootName != NULL) { FreePool (BootEntry->Name); @@ -323,12 +328,11 @@ OcScanForBootEntries ( DEBUG_CODE_BEGIN (); DEBUG (( DEBUG_INFO, - "Entry %u is %s at %s (W:%d|R:%d|F:%d)\n", + "Entry %u is %s at %s (T:%d|F:%d)\n", (UINT32) Index, Entries[Index].Name, Entries[Index].PathName, - Entries[Index].IsWindows, - Entries[Index].IsRecovery, + Entries[Index].Type, Entries[Index].IsFolder )); @@ -360,7 +364,7 @@ OcScanForBootEntries ( return EFI_OUT_OF_RESOURCES; } - Entries[EntryIndex].IsCustom = TRUE; + Entries[EntryIndex].Type = OcBootCustom; if (Index < Context->AbsoluteEntryCount) { Entries[EntryIndex].DevicePath = ConvertTextToDevicePath (PathName); @@ -758,6 +762,131 @@ OcLoadBootEntry ( return Status; } +STATIC +BOOLEAN +OcKeyMapHasModifier ( + IN APPLE_KEY_MAP_AGGREGATOR_PROTOCOL *KeyMapAggregator, + IN APPLE_MODIFIER_MAP ModifierLeft, + IN APPLE_MODIFIER_MAP ModifierRight OPTIONAL + ) +{ + EFI_STATUS Status; + + Status = KeyMapAggregator->ContainsKeyStrokes ( + KeyMapAggregator, + ModifierLeft, + 0, + NULL, + FALSE + ); + + if (EFI_ERROR (Status) && ModifierRight != 0) { + Status = KeyMapAggregator->ContainsKeyStrokes ( + KeyMapAggregator, + ModifierRight, + 0, + NULL, + FALSE + ); + } + + return !EFI_ERROR (Status); +} + +STATIC +BOOLEAN +OcKeyMapHasKey ( + IN APPLE_KEY_MAP_AGGREGATOR_PROTOCOL *KeyMapAggregator, + IN APPLE_KEY_CODE KeyCode + ) +{ + EFI_STATUS Status; + + Status = KeyMapAggregator->ContainsKeyStrokes ( + KeyMapAggregator, + 0, + 1, + &KeyCode, + FALSE + ); + + return !EFI_ERROR (Status); +} + +VOID +OcLoadPickerHotkeys ( + IN OUT OC_PICKER_CONTEXT *Context + ) +{ + EFI_STATUS Status; + APPLE_KEY_MAP_AGGREGATOR_PROTOCOL *KeyMap; + BOOLEAN HasCommand; + BOOLEAN HasOption; + BOOLEAN HasShift; + BOOLEAN HasKeyP; + BOOLEAN HasKeyR; + BOOLEAN HasKeyX; + + Status = gBS->LocateProtocol ( + &gAppleKeyMapAggregatorProtocolGuid, + NULL, + (VOID **) &KeyMap + ); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "OCB: Missing AppleKeyMapAggregator - %r\n", Status)); + return; + } + + // + // I do not like this code a little, as it is prone to race conditions during key presses. + // For the good false positives are not too critical here, and in reality users are not that fast. + // + // Reference key list: + // https://support.apple.com/HT201255 + // https://support.apple.com/HT204904 + // + // We are slightly more permissive than AppleBds, as we permit combining keys. + // + + HasCommand = OcKeyMapHasModifier (KeyMap, APPLE_MODIFIER_LEFT_COMMAND, APPLE_MODIFIER_RIGHT_COMMAND); + HasOption = OcKeyMapHasModifier (KeyMap, APPLE_MODIFIER_LEFT_OPTION, APPLE_MODIFIER_RIGHT_OPTION); + HasShift = OcKeyMapHasModifier (KeyMap, APPLE_MODIFIER_LEFT_SHIFT, APPLE_MODIFIER_RIGHT_SHIFT); + HasKeyP = OcKeyMapHasKey (KeyMap, AppleHidUsbKbUsageKeyP); + HasKeyR = OcKeyMapHasKey (KeyMap, AppleHidUsbKbUsageKeyP); + HasKeyX = OcKeyMapHasKey (KeyMap, AppleHidUsbKbUsageKeyX); + + if (HasOption && HasCommand && HasKeyP && HasKeyR) { + // + // TODO: Protect this with some policy? + // + DEBUG ((DEBUG_INFO, "OCB: CMD+OPT+P+R causes NVRAM reset\n")); + Context->PickerCommand = OcPickerResetNvram; + } else if (HasCommand && HasKeyR) { + DEBUG ((DEBUG_INFO, "OCB: CMD+R causes recovery to boot\n")); + Context->PickerCommand = OcPickerBootAppleRecovery; + } else if (HasKeyX) { + DEBUG ((DEBUG_INFO, "OCB: X causes macOS to boot\n")); + Context->PickerCommand = OcPickerBootApple; + } else if (HasOption) { + DEBUG ((DEBUG_INFO, "OCB: OPT causes picker to show\n")); + Context->PickerCommand = OcPickerShowPicker; + } else { + // + // In addition to these overrides we always have ShowPicker = YES in config. + // The following keys are not implemented: + // C - CD/DVD boot, legacy that is gone now. + // D - Diagnostics, could implement dumping stuff here in some future, + // but we will need to store the data before handling the key. + // Should also be DEBUG only for security reasons. + // N - Network boot, simply not supported (and bad for security). + // T - Target disk mode, simply not supported (and bad for security). + // + } + + +} + EFI_STATUS OcRunSimpleBootPicker ( IN OC_PICKER_CONTEXT *Context @@ -767,9 +896,8 @@ OcRunSimpleBootPicker ( APPLE_BOOT_POLICY_PROTOCOL *AppleBootPolicy; OC_BOOT_ENTRY *Chosen; OC_BOOT_ENTRY *Entries; - OC_BOOT_ENTRY *Entry; UINTN EntryCount; - UINT32 DefaultEntry; + INTN DefaultEntry; AppleBootPolicy = OcAppleBootPolicyInstallProtocol (FALSE); if (AppleBootPolicy == NULL) { @@ -801,13 +929,9 @@ OcRunSimpleBootPicker ( DEBUG ((DEBUG_INFO, "Performing OcShowSimpleBootMenu...\n")); - DefaultEntry = 0; - Entry = OcGetDefaultBootEntry (Entries, EntryCount, Context->CustomBootGuid, Context->ExcludeHandle); - if (Entry != NULL) { - DefaultEntry = (UINT32)(Entry - Entries); - } + DefaultEntry = OcGetDefaultBootEntry (Context, Entries, EntryCount); - if (Context->ShowPicker) { + if (Context->PickerCommand == OcPickerShowPicker) { Status = OcShowSimpleBootMenu ( Entries, EntryCount, @@ -831,10 +955,9 @@ OcRunSimpleBootPicker ( if (!EFI_ERROR (Status)) { DEBUG (( DEBUG_INFO, - "Should boot from %s (W:%d|R:%d|F:%d)\n", + "Should boot from %s (T:%d|F:%d)\n", Chosen->Name, - Chosen->IsWindows, - Chosen->IsRecovery, + Chosen->Type, Chosen->IsFolder )); } diff --git a/Library/OcBootManagementLib/OcBootManagementLib.inf b/Library/OcBootManagementLib/OcBootManagementLib.inf index de58697a..4a42b208 100644 --- a/Library/OcBootManagementLib/OcBootManagementLib.inf +++ b/Library/OcBootManagementLib/OcBootManagementLib.inf @@ -61,6 +61,7 @@ [Protocols] gAppleBootPolicyProtocolGuid ## PRODUCES + gAppleKeyMapAggregatorProtocolGuid ## SOMETIMES_CONSUMES gEfiSimpleFileSystemProtocolGuid ## SOMETIMES_CONSUMES gEfiLoadedImageProtocolGuid ## SOMETIMES_CONSUMES gEfiUsbIoProtocolGuid ## SOMETIMES_CONSUMES diff --git a/Library/OcBootManagementLib/PolicyManagement.c b/Library/OcBootManagementLib/PolicyManagement.c index 7852e428..b6edacde 100644 --- a/Library/OcBootManagementLib/PolicyManagement.c +++ b/Library/OcBootManagementLib/PolicyManagement.c @@ -220,6 +220,39 @@ InternalCheckScanPolicy ( return RETURN_SUCCESS; } +BOOLEAN +OcIsAppleBootDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + EFI_DEVICE_PATH_PROTOCOL *CurrNode; + FILEPATH_DEVICE_PATH *LastNode; + UINTN PathLen; + UINTN Index; + + LastNode = NULL; + + for (CurrNode = DevicePath; !IsDevicePathEnd (CurrNode); CurrNode = NextDevicePathNode (CurrNode)) { + if (DevicePathType (CurrNode) == MEDIA_DEVICE_PATH && DevicePathSubType (CurrNode) == MEDIA_FILEPATH_DP) { + LastNode = (FILEPATH_DEVICE_PATH *) CurrNode; + } + } + + if (LastNode != NULL) { + // + // Detect macOS by boot.efi in the bootloader name. + // + PathLen = OcFileDevicePathNameLen (LastNode); + if (PathLen >= L_STR_LEN ("boot.efi")) { + Index = PathLen - L_STR_LEN ("boot.efi"); + return (Index == 0 || LastNode->PathName[Index - 1] == L'\\') + && CompareMem (&LastNode->PathName[Index], L"boot.efi", L_STR_SIZE (L"boot.efi")) == 0; + } + } + + return FALSE; +} + EFI_LOADED_IMAGE_PROTOCOL * OcGetAppleBootLoadedImage ( IN EFI_HANDLE ImageHandle @@ -227,37 +260,18 @@ OcGetAppleBootLoadedImage ( { EFI_STATUS Status; EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; - EFI_DEVICE_PATH_PROTOCOL *CurrNode; - FILEPATH_DEVICE_PATH *LastNode; - BOOLEAN IsMacOS; - UINTN PathLen; - UINTN Index; - IsMacOS = FALSE; + Status = gBS->HandleProtocol ( + ImageHandle, + &gEfiLoadedImageProtocolGuid, + (VOID **)&LoadedImage + ); - Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **)&LoadedImage); - - if (!EFI_ERROR (Status) && LoadedImage->FilePath) { - LastNode = NULL; - - for (CurrNode = LoadedImage->FilePath; !IsDevicePathEnd (CurrNode); CurrNode = NextDevicePathNode (CurrNode)) { - if (DevicePathType (CurrNode) == MEDIA_DEVICE_PATH && DevicePathSubType (CurrNode) == MEDIA_FILEPATH_DP) { - LastNode = (FILEPATH_DEVICE_PATH *) CurrNode; - } - } - - if (LastNode != NULL) { - // - // Detect macOS by boot.efi in the bootloader name. - // - PathLen = OcFileDevicePathNameLen (LastNode); - if (PathLen >= L_STR_LEN ("boot.efi")) { - Index = PathLen - L_STR_LEN ("boot.efi"); - IsMacOS = (Index == 0 || LastNode->PathName[Index - 1] == L'\\') - && CompareMem (&LastNode->PathName[Index], L"boot.efi", L_STR_SIZE (L"boot.efi")) == 0; - } - } + if (!EFI_ERROR (Status) + && LoadedImage->FilePath != NULL + && OcIsAppleBootDevicePath (LoadedImage->FilePath)) { + return LoadedImage; } - return IsMacOS ? LoadedImage : NULL; + return NULL; }