diff --git a/Include/Library/OcAppleBootPolicyLib.h b/Include/Library/OcAppleBootPolicyLib.h index 78932c77..5d950e69 100755 --- a/Include/Library/OcAppleBootPolicyLib.h +++ b/Include/Library/OcAppleBootPolicyLib.h @@ -47,4 +47,30 @@ OcDescribeBootEntry ( IN OUT CHAR16 **BootPathName OPTIONAL ); +/** + Discovered boot entry. + Note, DevicePath must be freed. +**/ +typedef struct OC_BOOT_ENTRY_ { + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + BOOLEAN PrefersDmgBoot; +} OC_BOOT_ENTRY; + +/** + @param[in] BootPolicy Apple Boot Policy Protocol. + @param[in] Mode Lookup mode. + @param[out] BootEntries List of boot entries (allocated from pool). + @param[out] Count Number of boot entries. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval EFI_ALREADY_STARTED The protocol has already been installed. +**/ +EFI_STATUS +OcScanForBootEntries ( + IN APPLE_BOOT_POLICY_PROTOCOL *BootPolicy, + IN UINT32 Mode, + OUT OC_BOOT_ENTRY **BootEntries, + OUT UINTN *Count + ); + #endif // OC_APPLE_BOOT_POLICY_LIB_H diff --git a/Library/OcAppleBootPolicyLib/OcAppleBootPolicyLib.c b/Library/OcAppleBootPolicyLib/OcAppleBootPolicyLib.c index 28b309d3..066a0a25 100644 --- a/Library/OcAppleBootPolicyLib/OcAppleBootPolicyLib.c +++ b/Library/OcAppleBootPolicyLib/OcAppleBootPolicyLib.c @@ -556,9 +556,10 @@ HasValidGuidStringPrefix ( } for (Index = 0; Index < GuidLength; ++Index) { - if ((Index == 8 || Index == 12 || Index == 16 || Index == 20) - && String[Index] != '-') { - return FALSE; + if (Index == 8 || Index == 13 || Index == 18 || Index == 23) { + if (String[Index] != '-') { + return FALSE; + } } else if (!(String[Index] >= L'0' && String[Index] <= L'9') && !(String[Index] >= L'A' && String[Index] <= L'F') && !(String[Index] >= L'a' && String[Index] <= L'f')) { @@ -1035,12 +1036,12 @@ BootPolicyGetPathNameOnApfsRecovery ( } NewHandle->Close (NewHandle); - (*Root)->Close (*Root); if (!EFI_ERROR (Result)) { break; } + (*Root)->Close (*Root); FreePool (FullPathBuffer); } diff --git a/Library/OcAppleBootPolicyLib/OcAppleBootPolicyLib.inf b/Library/OcAppleBootPolicyLib/OcAppleBootPolicyLib.inf index b1b1506b..d7c37d94 100644 --- a/Library/OcAppleBootPolicyLib/OcAppleBootPolicyLib.inf +++ b/Library/OcAppleBootPolicyLib/OcAppleBootPolicyLib.inf @@ -44,6 +44,7 @@ gAppleApfsVolumeInfoGuid ## SOMETIMES_CONSUMES gAppleBlessedSystemFileInfoGuid ## SOMETIMES_CONSUMES gAppleBlessedSystemFolderInfoGuid ## SOMETIMES_CONSUMES + gAppleBlessedAlternateOsInfoGuid ## SOMETIMES_CONSUMES gEfiFileInfoGuid ## SOMETIMES_CONSUMES [Protocols] diff --git a/Library/OcAppleBootPolicyLib/OcSupportBootPolicy.c b/Library/OcAppleBootPolicyLib/OcSupportBootPolicy.c index 95277ccb..4a73142e 100644 --- a/Library/OcAppleBootPolicyLib/OcSupportBootPolicy.c +++ b/Library/OcAppleBootPolicyLib/OcSupportBootPolicy.c @@ -36,7 +36,8 @@ STATIC CHAR16 * GetAppleDiskLabel ( IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileSystem, - IN CONST CHAR16 *BootDirectoryName + IN CONST CHAR16 *BootDirectoryName, + IN CONST CHAR16 *LabelFilename ) { CHAR16 *DiskLabelPath; @@ -45,14 +46,14 @@ GetAppleDiskLabel ( CHAR16 *UnicodeDiskLabel; UINTN DiskLabelLength; - DiskLabelPathSize = StrSize (BootDirectoryName) + L_STR_SIZE_NT (L".disk_label.contentDetails"); + DiskLabelPathSize = StrSize (BootDirectoryName) + StrLen (LabelFilename); DiskLabelPath = AllocatePool (DiskLabelPathSize); if (DiskLabelPath == NULL) { return NULL; } - UnicodeSPrint (DiskLabelPath, DiskLabelPathSize, L"%s.disk_label.contentDetails", BootDirectoryName); + UnicodeSPrint (DiskLabelPath, DiskLabelPathSize, L"%s%s", BootDirectoryName, LabelFilename); AsciiDiskLabel = (CHAR8 *) ReadFile (FileSystem, DiskLabelPath, &DiskLabelLength); FreePool (DiskLabelPath); @@ -158,6 +159,54 @@ GetAppleRecoveryName ( return UnicodeDiskLabel; } +STATIC +EFI_STATUS +GetAlternateOsBooter ( + IN EFI_HANDLE Device, + OUT EFI_DEVICE_PATH_PROTOCOL **FilePath + ) +{ + EFI_STATUS Status; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileSystem; + EFI_FILE_PROTOCOL *Root; + UINTN FilePathSize; + + Status = gBS->HandleProtocol ( + Device, + &gEfiSimpleFileSystemProtocolGuid, + (VOID **) &FileSystem + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = FileSystem->OpenVolume (FileSystem, &Root); + if (EFI_ERROR (Status)) { + return Status; + } + + *FilePath = (EFI_DEVICE_PATH_PROTOCOL *) GetFileInfo ( + Root, + &gAppleBlessedAlternateOsInfoGuid, + sizeof (EFI_DEVICE_PATH_PROTOCOL), + &FilePathSize + ); + + if (*FilePath != NULL) { + if (!IsDevicePathValid(*FilePath, FilePathSize)) { + FreePool (*FilePath); + *FilePath = NULL; + Status = EFI_NOT_FOUND; + } + } else { + Status = EFI_NOT_FOUND; + } + + Root->Close (Root); + + return Status; +} + EFI_STATUS OcDescribeBootEntry ( IN APPLE_BOOT_POLICY_PROTOCOL *BootPolicy, @@ -198,7 +247,13 @@ OcDescribeBootEntry ( } if (BootEntryName != NULL) { - *BootEntryName = GetAppleDiskLabel (FileSystem, BootDirectoryName); + // + // Try to use APFS-style label or legacy HFS one. + // + *BootEntryName = GetAppleDiskLabel (FileSystem, BootDirectoryName, L".contentDetails"); + if (*BootEntryName == NULL) { + *BootEntryName = GetAppleDiskLabel (FileSystem, BootDirectoryName, L".disk_label.contentDetails"); + } if (*BootEntryName == NULL) { *BootEntryName = GetVolumeLabel (FileSystem); if (*BootEntryName != NULL && !StrCmp (*BootEntryName, L"Recovery HD")) { @@ -223,4 +278,98 @@ OcDescribeBootEntry ( } return EFI_SUCCESS; -} \ No newline at end of file +} + +EFI_STATUS +OcScanForBootEntries ( + IN APPLE_BOOT_POLICY_PROTOCOL *BootPolicy, + IN UINT32 Mode, + OUT OC_BOOT_ENTRY **BootEntries, + OUT UINTN *Count + ) +{ + EFI_STATUS Status; + UINTN NoHandles; + EFI_HANDLE *Handles; + UINTN Index; + OC_BOOT_ENTRY *Entries; + UINTN EntryIndex; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + CHAR16 *RecoveryPath; + VOID *Reserved; + EFI_FILE_PROTOCOL *RecoveryRoot; + EFI_HANDLE RecoveryDeviceHandle; + + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiSimpleFileSystemProtocolGuid, + NULL, + &NoHandles, + &Handles + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + if (NoHandles == 0) { + FreePool (Handles); + return EFI_NOT_FOUND; + } + + Entries = AllocateZeroPool (NoHandles * 2 * sizeof (OC_BOOT_ENTRY)); + if (Entries == NULL) { + FreePool (Handles); + return EFI_OUT_OF_RESOURCES; + } + + EntryIndex = 0; + + for (Index = 0; Index < NoHandles; ++Index) { + Status = BootPolicy->GetBootFileEx ( + Handles[Index], + APPLE_BOOT_POLICY_MODE_1, + &DevicePath + ); + + if (EFI_ERROR (Status)) { + continue; + } + + Entries[EntryIndex].DevicePath = DevicePath; + + ++EntryIndex; + + Status = BootPolicy->GetPathNameOnApfsRecovery ( + DevicePath, + L"", + &RecoveryPath, + &Reserved, + &RecoveryRoot, + &RecoveryDeviceHandle + ); + + if (!EFI_ERROR (Status)) { + DevicePath = FileDevicePath (RecoveryDeviceHandle, RecoveryPath); + FreePool (RecoveryPath); + RecoveryRoot->Close (RecoveryRoot); + } else { + Status = GetAlternateOsBooter (Handles[Index], &DevicePath); + if (EFI_ERROR (Status)) { + continue; + } + } + + Entries[EntryIndex].DevicePath = DevicePath; + Entries[EntryIndex].PrefersDmgBoot = TRUE; + + ++EntryIndex; + } + + FreePool (Handles); + + *BootEntries = Entries; + *Count = EntryIndex; + + return EFI_SUCCESS; +}