mirror of
https://github.com/acidanthera/OpenCorePkg.git
synced 2025-12-08 19:25:01 +00:00
664 lines
17 KiB
C
664 lines
17 KiB
C
/** @file
|
|
Copyright (C) 2019, vit9696. All rights reserved.
|
|
|
|
All rights reserved.
|
|
|
|
This program and the accompanying materials
|
|
are licensed and made available under the terms and conditions of the BSD License
|
|
which accompanies this distribution. The full text of the license may be found at
|
|
http://opensource.org/licenses/bsd-license.php
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
**/
|
|
|
|
#include <AppleMacEfi.h>
|
|
#include <Uefi.h>
|
|
|
|
#include <Guid/AppleApfsInfo.h>
|
|
#include <Guid/AppleBless.h>
|
|
#include <Guid/FileInfo.h>
|
|
|
|
#include <Protocol/AppleBootPolicy.h>
|
|
#include <Protocol/SimpleFileSystem.h>
|
|
#include <Protocol/SimpleTextOut.h>
|
|
|
|
#include <Library/OcBootManagementLib.h>
|
|
#include <Library/OcFileLib.h>
|
|
#include <Library/OcMiscLib.h>
|
|
#include <Library/OcStringLib.h>
|
|
#include <Library/OcXmlLib.h>
|
|
#include <Library/BaseLib.h>
|
|
#include <Library/BaseMemoryLib.h>
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/DevicePathLib.h>
|
|
#include <Library/MemoryAllocationLib.h>
|
|
#include <Library/PrintLib.h>
|
|
#include <Library/UefiBootServicesTableLib.h>
|
|
#include <Library/UefiLib.h>
|
|
|
|
STATIC
|
|
CHAR16 *
|
|
GetAppleDiskLabel (
|
|
IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileSystem,
|
|
IN CONST CHAR16 *BootDirectoryName,
|
|
IN CONST CHAR16 *LabelFilename
|
|
)
|
|
{
|
|
CHAR16 *DiskLabelPath;
|
|
UINTN DiskLabelPathSize;
|
|
CHAR8 *AsciiDiskLabel;
|
|
CHAR16 *UnicodeDiskLabel;
|
|
UINT32 DiskLabelLength;
|
|
|
|
DiskLabelPathSize = StrSize (BootDirectoryName) + StrLen (LabelFilename) * sizeof (CHAR16);
|
|
DiskLabelPath = AllocatePool (DiskLabelPathSize);
|
|
|
|
if (DiskLabelPath == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
UnicodeSPrint (DiskLabelPath, DiskLabelPathSize, L"%s%s", BootDirectoryName, LabelFilename);
|
|
AsciiDiskLabel = (CHAR8 *) ReadFile (FileSystem, DiskLabelPath, &DiskLabelLength);
|
|
FreePool (DiskLabelPath);
|
|
|
|
if (AsciiDiskLabel != NULL) {
|
|
UnicodeDiskLabel = AsciiStrCopyToUnicode (AsciiDiskLabel, DiskLabelLength);
|
|
FreePool (AsciiDiskLabel);
|
|
} else {
|
|
UnicodeDiskLabel = NULL;
|
|
}
|
|
|
|
return UnicodeDiskLabel;
|
|
}
|
|
|
|
STATIC
|
|
CHAR16 *
|
|
GetAppleRecoveryNameFromPlist (
|
|
IN CHAR8 *SystemVersionData,
|
|
IN UINT32 SystemVersionDataSize
|
|
)
|
|
{
|
|
XML_DOCUMENT *Document;
|
|
XML_NODE *RootDict;
|
|
UINT32 DictSize;
|
|
UINT32 Index;
|
|
CONST CHAR8 *CurrentKey;
|
|
XML_NODE *CurrentValue;
|
|
CONST CHAR8 *Version;
|
|
CHAR16 *RecoveryName;
|
|
UINTN RecoveryNameSize;
|
|
|
|
Document = XmlDocumentParse (SystemVersionData, SystemVersionDataSize, FALSE);
|
|
|
|
if (Document == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
RootDict = PlistNodeCast (PlistDocumentRoot (Document), PLIST_NODE_TYPE_DICT);
|
|
|
|
if (RootDict == NULL) {
|
|
XmlDocumentFree (Document);
|
|
return NULL;
|
|
}
|
|
|
|
RecoveryName = NULL;
|
|
|
|
DictSize = PlistDictChildren (RootDict);
|
|
for (Index = 0; Index < DictSize; Index++) {
|
|
CurrentKey = PlistKeyValue (PlistDictChild (RootDict, Index, &CurrentValue));
|
|
|
|
if (CurrentKey == NULL || AsciiStrCmp (CurrentKey, "ProductUserVisibleVersion") != 0) {
|
|
continue;
|
|
}
|
|
|
|
if (PlistNodeCast (CurrentValue, PLIST_NODE_TYPE_STRING) != NULL) {
|
|
Version = XmlNodeContent (CurrentValue);
|
|
if (Version != NULL) {
|
|
RecoveryNameSize = L_STR_SIZE(L"Recovery ") + AsciiStrLen (Version) * sizeof (CHAR16);
|
|
RecoveryName = AllocatePool (RecoveryNameSize);
|
|
if (RecoveryName != NULL) {
|
|
UnicodeSPrint(RecoveryName, RecoveryNameSize, L"Recovery %a", Version);
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
XmlDocumentFree (Document);
|
|
return RecoveryName;
|
|
}
|
|
|
|
STATIC
|
|
CHAR16 *
|
|
GetAppleRecoveryName (
|
|
IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileSystem,
|
|
IN CONST CHAR16 *BootDirectoryName
|
|
)
|
|
{
|
|
CHAR16 *SystemVersionPath;
|
|
UINTN SystemVersionPathSize;
|
|
CHAR8 *SystemVersionData;
|
|
CHAR16 *UnicodeDiskLabel;
|
|
UINT32 SystemVersionDataSize;
|
|
|
|
SystemVersionPathSize = StrSize (BootDirectoryName) + L_STR_SIZE_NT (L"SystemVersion.plist");
|
|
SystemVersionPath = AllocatePool (SystemVersionPathSize);
|
|
|
|
if (SystemVersionPath == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
UnicodeSPrint (SystemVersionPath, SystemVersionPathSize, L"%sSystemVersion.plist", BootDirectoryName);
|
|
SystemVersionData = (CHAR8 *) ReadFile (FileSystem, SystemVersionPath, &SystemVersionDataSize);
|
|
FreePool (SystemVersionPath);
|
|
|
|
if (SystemVersionData != NULL) {
|
|
UnicodeDiskLabel = GetAppleRecoveryNameFromPlist (SystemVersionData, SystemVersionDataSize);
|
|
FreePool (SystemVersionData);
|
|
} else {
|
|
UnicodeDiskLabel = NULL;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
//
|
|
// TODO: This should be less hardcoded.
|
|
//
|
|
STATIC
|
|
VOID
|
|
SetBootEntryFlags (
|
|
IN OUT OC_BOOT_ENTRY *BootEntry
|
|
)
|
|
{
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePathWalker;
|
|
FILEPATH_DEVICE_PATH *FolderDevicePath;
|
|
|
|
BootEntry->IsRecovery = FALSE;
|
|
BootEntry->IsFolder = FALSE;
|
|
|
|
DevicePathWalker = BootEntry->DevicePath;
|
|
while (!IsDevicePathEnd (DevicePathWalker)) {
|
|
if ((DevicePathType (DevicePathWalker) == MEDIA_DEVICE_PATH)
|
|
&& (DevicePathSubType (DevicePathWalker) == MEDIA_FILEPATH_DP)) {
|
|
FolderDevicePath = (FILEPATH_DEVICE_PATH *) DevicePathWalker;
|
|
if (FolderDevicePath->PathName[StrLen (FolderDevicePath->PathName) - 1] == L'\\') {
|
|
BootEntry->IsFolder = TRUE;
|
|
}
|
|
if (StrStr (FolderDevicePath->PathName, L"com.apple.recovery.boot") != NULL) {
|
|
BootEntry->IsRecovery = TRUE;
|
|
}
|
|
} else {
|
|
BootEntry->IsFolder = FALSE;
|
|
}
|
|
|
|
DevicePathWalker = NextDevicePathNode (DevicePathWalker);
|
|
}
|
|
}
|
|
|
|
EFI_STATUS
|
|
OcDescribeBootEntry (
|
|
IN APPLE_BOOT_POLICY_PROTOCOL *BootPolicy,
|
|
IN OUT OC_BOOT_ENTRY *BootEntry
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
CHAR16 *BootDirectoryName;
|
|
CHAR16 *RecoveryBootName;
|
|
EFI_HANDLE Device;
|
|
EFI_HANDLE ApfsVolumeHandle;
|
|
UINT32 BcdSize;
|
|
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileSystem;
|
|
|
|
Status = BootPolicy->GetBootInfo (
|
|
BootEntry->DevicePath,
|
|
&BootDirectoryName,
|
|
&Device,
|
|
&ApfsVolumeHandle
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = gBS->HandleProtocol (
|
|
Device,
|
|
&gEfiSimpleFileSystemProtocolGuid,
|
|
(VOID **) &FileSystem
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
FreePool (BootDirectoryName);
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Try to use APFS-style label or legacy HFS one.
|
|
//
|
|
BootEntry->Name = GetAppleDiskLabel (FileSystem, BootDirectoryName, L".contentDetails");
|
|
if (BootEntry->Name == NULL) {
|
|
BootEntry->Name = GetAppleDiskLabel (FileSystem, BootDirectoryName, L".disk_label.contentDetails");
|
|
}
|
|
Status = ReadFileSize (FileSystem, L"\\EFI\\Microsoft\\Boot\\BCD", &BcdSize);
|
|
if (!EFI_ERROR (Status)) {
|
|
BootEntry->Name = AllocateCopyPool(sizeof (L"BOOTCAMP Windows"), L"BOOTCAMP Windows");
|
|
}
|
|
if (BootEntry->Name == NULL) {
|
|
BootEntry->Name = GetVolumeLabel (FileSystem);
|
|
if (BootEntry->Name != NULL
|
|
&& (!StrCmp (BootEntry->Name, L"Recovery HD")
|
|
|| !StrCmp (BootEntry->Name, L"Recovery"))) {
|
|
BootEntry->IsRecovery = TRUE;
|
|
RecoveryBootName = GetAppleRecoveryName (FileSystem, BootDirectoryName);
|
|
if (RecoveryBootName != NULL) {
|
|
FreePool (BootEntry->Name);
|
|
BootEntry->Name = RecoveryBootName;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (BootEntry->Name == NULL) {
|
|
FreePool (BootDirectoryName);
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
BootEntry->PathName = BootDirectoryName;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
OcResetBootEntry (
|
|
IN OUT OC_BOOT_ENTRY *BootEntry
|
|
)
|
|
{
|
|
if (BootEntry->DevicePath != NULL) {
|
|
FreePool (BootEntry->DevicePath);
|
|
BootEntry->DevicePath = NULL;
|
|
}
|
|
|
|
if (BootEntry->Name != NULL) {
|
|
FreePool (BootEntry->Name);
|
|
BootEntry->Name = NULL;
|
|
}
|
|
|
|
if (BootEntry->PathName != NULL) {
|
|
FreePool (BootEntry->PathName);
|
|
BootEntry->PathName = NULL;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
OcFreeBootEntries (
|
|
IN OUT OC_BOOT_ENTRY *BootEntries,
|
|
IN UINTN Count
|
|
)
|
|
{
|
|
UINTN Index;
|
|
|
|
for (Index = 0; Index < Count; ++Index) {
|
|
OcResetBootEntry (&BootEntries[Index]);
|
|
}
|
|
|
|
FreePool (BootEntries);
|
|
}
|
|
|
|
UINTN
|
|
OcFillBootEntry (
|
|
IN APPLE_BOOT_POLICY_PROTOCOL *BootPolicy,
|
|
IN UINT32 Policy,
|
|
IN EFI_HANDLE Handle,
|
|
OUT OC_BOOT_ENTRY *BootEntry,
|
|
OUT OC_BOOT_ENTRY *AlternateBootEntry OPTIONAL
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
|
CHAR16 *RecoveryPath;
|
|
VOID *Reserved;
|
|
EFI_FILE_PROTOCOL *RecoveryRoot;
|
|
EFI_HANDLE RecoveryDeviceHandle;
|
|
|
|
Status = BootPolicy->GetBootFileEx (
|
|
Handle,
|
|
APPLE_BOOT_POLICY_MODE_1,
|
|
&DevicePath
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
return 0;
|
|
}
|
|
|
|
BootEntry->DevicePath = DevicePath;
|
|
SetBootEntryFlags (BootEntry);
|
|
|
|
//
|
|
// We skip alternate entry when current one is actually a recovery.
|
|
// This is to prevent recovery duplicates on HFS+ systems.
|
|
//
|
|
if (AlternateBootEntry != NULL && !BootEntry->IsRecovery) {
|
|
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 (Handle, &DevicePath);
|
|
if (EFI_ERROR (Status)) {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
AlternateBootEntry->DevicePath = DevicePath;
|
|
SetBootEntryFlags (AlternateBootEntry);
|
|
return 2;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
EFI_STATUS
|
|
OcScanForBootEntries (
|
|
IN APPLE_BOOT_POLICY_PROTOCOL *BootPolicy,
|
|
IN UINT32 Policy,
|
|
OUT OC_BOOT_ENTRY **BootEntries,
|
|
OUT UINTN *Count,
|
|
OUT UINTN *AllocCount OPTIONAL,
|
|
IN BOOLEAN Describe
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN NoHandles;
|
|
EFI_HANDLE *Handles;
|
|
UINTN Index;
|
|
OC_BOOT_ENTRY *Entries;
|
|
UINTN EntryIndex;
|
|
|
|
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) {
|
|
EntryIndex += OcFillBootEntry (
|
|
BootPolicy,
|
|
Policy,
|
|
Handles[Index],
|
|
&Entries[EntryIndex],
|
|
&Entries[EntryIndex+1]
|
|
);
|
|
}
|
|
|
|
FreePool (Handles);
|
|
|
|
if (Describe) {
|
|
for (Index = 0; Index < EntryIndex; ++Index) {
|
|
Status = OcDescribeBootEntry (BootPolicy, &Entries[Index]);
|
|
if (EFI_ERROR (Status)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
OcFreeBootEntries (Entries, EntryIndex);
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
*BootEntries = Entries;
|
|
*Count = EntryIndex;
|
|
|
|
if (AllocCount != NULL) {
|
|
*AllocCount = NoHandles * 2;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
OcShowSimpleBootMenu (
|
|
IN OC_BOOT_ENTRY *BootEntries,
|
|
IN UINTN Count,
|
|
IN UINTN DefaultEntry,
|
|
IN UINTN TimeOutSeconds,
|
|
OUT OC_BOOT_ENTRY **ChosenBootEntry
|
|
)
|
|
{
|
|
UINTN Index;
|
|
INTN KeyIndex;
|
|
CHAR16 Code[2];
|
|
|
|
Code[1] = '\0';
|
|
|
|
while (TRUE) {
|
|
gST->ConOut->ClearScreen (gST->ConOut);
|
|
gST->ConOut->OutputString (gST->ConOut, L"OpenCore Boot Menu\r\n\r\n");
|
|
|
|
for (Index = 0; Index < MIN (Count, OC_INPUT_MAX); ++Index) {
|
|
Code[0] = OC_INPUT_STR[Index];
|
|
gST->ConOut->OutputString (gST->ConOut, DefaultEntry == Index && TimeOutSeconds > 0 ? L"* " : L" ");
|
|
gST->ConOut->OutputString (gST->ConOut, Code);
|
|
gST->ConOut->OutputString (gST->ConOut, L". ");
|
|
gST->ConOut->OutputString (gST->ConOut, BootEntries[Index].Name);
|
|
if (BootEntries[Index].IsFolder) {
|
|
gST->ConOut->OutputString (gST->ConOut, L" (dmg)");
|
|
}
|
|
if (BootEntries[Index].IsRecovery) {
|
|
gST->ConOut->OutputString (gST->ConOut, L" (recovery)");
|
|
}
|
|
gST->ConOut->OutputString (gST->ConOut, L"\r\n");
|
|
}
|
|
|
|
if (Index < Count) {
|
|
gST->ConOut->OutputString (gST->ConOut, L"WARN: Some entries were skipped!\r\n");
|
|
}
|
|
|
|
gST->ConOut->OutputString (gST->ConOut, L"\r\nChoose boot entry: ");
|
|
|
|
while (TRUE) {
|
|
KeyIndex = WaitForKeyIndex (TimeOutSeconds);
|
|
if (KeyIndex == OC_INPUT_TIMEOUT) {
|
|
*ChosenBootEntry = &BootEntries[DefaultEntry];
|
|
gST->ConOut->OutputString (gST->ConOut, L"Timeout\r\n");
|
|
return EFI_SUCCESS;
|
|
} else if (KeyIndex == OC_INPUT_ABORTED) {
|
|
gST->ConOut->OutputString (gST->ConOut, L"Aborted\r\n");
|
|
return EFI_ABORTED;
|
|
} else if (KeyIndex != OC_INPUT_INVALID && (UINTN)KeyIndex < Count) {
|
|
ASSERT (KeyIndex >= 0);
|
|
*ChosenBootEntry = &BootEntries[KeyIndex];
|
|
Code[0] = OC_INPUT_STR[KeyIndex];
|
|
gST->ConOut->OutputString (gST->ConOut, Code);
|
|
gST->ConOut->OutputString (gST->ConOut, L"\r\n");
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
if (TimeOutSeconds > 0) {
|
|
TimeOutSeconds = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
ASSERT (FALSE);
|
|
}
|
|
|
|
EFI_STATUS
|
|
OcLoadBootEntry (
|
|
IN OC_BOOT_ENTRY *BootEntry,
|
|
IN UINT32 Policy,
|
|
IN EFI_HANDLE ParentHandle,
|
|
OUT EFI_HANDLE *EntryHandle
|
|
)
|
|
{
|
|
//
|
|
// TODO: support Apple loaded image, policy, and dmg boot.
|
|
//
|
|
return gBS->LoadImage (FALSE, ParentHandle, BootEntry->DevicePath, NULL, 0, EntryHandle);
|
|
}
|
|
|
|
EFI_STATUS
|
|
OcRunSimpleBootMenu (
|
|
IN UINT32 LookupPolicy,
|
|
IN UINT32 BootPolicy,
|
|
IN UINT32 TimeoutSeconds,
|
|
IN EFI_IMAGE_START StartImage
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
APPLE_BOOT_POLICY_PROTOCOL *AppleBootPolicy;
|
|
OC_BOOT_ENTRY *Chosen;
|
|
OC_BOOT_ENTRY *Entries;
|
|
UINTN EntryCount;
|
|
EFI_HANDLE BooterHandle;
|
|
|
|
Status = OcAppleBootPolicyInstallProtocol (gImageHandle, gST);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_INFO, "AppleBootPolicy install failure - %r\n", Status));
|
|
}
|
|
|
|
Status = gBS->LocateProtocol (
|
|
&gAppleBootPolicyProtocolGuid,
|
|
NULL,
|
|
(VOID **) &AppleBootPolicy
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "AppleBootPolicy locate failure - %r\n", Status));
|
|
return Status;
|
|
}
|
|
|
|
while (TRUE) {
|
|
Status = OcScanForBootEntries (
|
|
AppleBootPolicy,
|
|
LookupPolicy,
|
|
&Entries,
|
|
&EntryCount,
|
|
NULL,
|
|
TRUE
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "OcScanForBootEntries failure - %r\n", Status));
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// TODO: obtain default entry!
|
|
//
|
|
Status = OcShowSimpleBootMenu (
|
|
Entries,
|
|
EntryCount,
|
|
0,
|
|
TimeoutSeconds,
|
|
&Chosen
|
|
);
|
|
|
|
if (EFI_ERROR (Status) && Status != EFI_ABORTED) {
|
|
DEBUG ((DEBUG_ERROR, "OcShowSimpleBootMenu failed - %r\n", Status));
|
|
OcFreeBootEntries (Entries, EntryCount);
|
|
return Status;
|
|
}
|
|
|
|
TimeoutSeconds = 0;
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_INFO, "Should boot from %s\n", Chosen->Name));
|
|
}
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
Status = OcLoadBootEntry (Chosen, BootPolicy, gImageHandle, &BooterHandle);
|
|
if (!EFI_ERROR (Status)) {
|
|
Status = StartImage (BooterHandle, NULL, NULL);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "StartImage failed - %r\n", Status));
|
|
}
|
|
} else {
|
|
DEBUG ((DEBUG_ERROR, "LoadImage failed - %r\n", Status));
|
|
}
|
|
|
|
gBS->Stall (5000000);
|
|
}
|
|
|
|
OcFreeBootEntries (Entries, EntryCount);
|
|
}
|
|
}
|