diff --git a/Application/BootKicker/BootKicker.c b/Application/BootKicker/BootKicker.c
new file mode 100644
index 00000000..1a685845
--- /dev/null
+++ b/Application/BootKicker/BootKicker.c
@@ -0,0 +1,99 @@
+/** @file
+ Run Apple boot picker.
+
+Copyright (c) 2020, vit9696. 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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+EFI_STATUS
+EFIAPI
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Pixel;
+
+ Status = gBS->HandleProtocol (
+ gST->ConsoleOutHandle,
+ &gEfiGraphicsOutputProtocolGuid,
+ (VOID **) &Gop
+ );
+
+ gBS->SetWatchdogTimer (0, 0, 0, NULL);
+ OcProvideConsoleGop ();
+
+ if (EFI_ERROR (Status)) {
+ gBS->Stall (SECONDS_TO_MICROSECONDS (10));
+ return Status;
+ }
+
+ Status = OcRunAppleBootPicker ();
+
+ Pixel.Raw = 0x0;
+ if (Status == EFI_NOT_FOUND) {
+ //
+ // Red. No BootPicker in firmware or we cannot get it.
+ //
+ Pixel.Pixel.Red = 0xFF;
+ } else if (Status == EFI_UNSUPPORTED) {
+ //
+ // Yellow. BootPicker does not start.
+ //
+ Pixel.Pixel.Red = 0xFF;
+ Pixel.Pixel.Green = 0xFF;
+ } else if (EFI_ERROR (Status) /* Status == EFI_INVALID_PARAMETER */) {
+ //
+ // Fuchsia. BootPicker does not load.
+ //
+ Pixel.Pixel.Blue = 0xFF;
+ Pixel.Pixel.Red = 0xFF;
+ } else {
+ //
+ // Green. BootPicker started but returned.
+ //
+ Pixel.Pixel.Green = 0xFF;
+ }
+
+ Gop->Blt (
+ Gop,
+ &Pixel.Pixel,
+ EfiBltVideoFill,
+ 0,
+ 0,
+ 0,
+ 0,
+ Gop->Mode->Info->HorizontalResolution,
+ Gop->Mode->Info->VerticalResolution,
+ 0
+ );
+
+ gBS->Stall (SECONDS_TO_MICROSECONDS (10));
+
+ return EFI_SUCCESS;
+}
diff --git a/Application/BootKicker/BootKicker.inf b/Application/BootKicker/BootKicker.inf
new file mode 100644
index 00000000..3f1c3d80
--- /dev/null
+++ b/Application/BootKicker/BootKicker.inf
@@ -0,0 +1,55 @@
+## @file
+# Clean several important nvram variables to recover from issues.
+#
+# Copyright (c) 2018, vit9696. 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.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BootKicker
+ FILE_GUID = 3099A880-582F-44BA-8DA3-F4A875F3E34D
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = UefiMain
+
+#
+# This flag specifies whether HII resource section is generated into PE image.
+#
+ UEFI_HII_RESOURCE_SECTION = TRUE
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ BootKicker.c
+
+[Guids]
+ gAppleBootPickerFileGuid
+
+[Protocols]
+ gEfiDevicePathProtocolGuid
+ gEfiFirmwareVolumeProtocolGuid
+
+[Packages]
+ EfiPkg/EfiPkg.dec
+ MdePkg/MdePkg.dec
+ OcSupportPkg/OcSupportPkg.dec
+
+[LibraryClasses]
+ OcBootManagementLib
+ OcConsoleLib
+ OcFileLib
+ UefiApplicationEntryPoint
+ UefiBootServicesTableLib
+ UefiLib
diff --git a/Include/Library/OcBootManagementLib.h b/Include/Library/OcBootManagementLib.h
index da1924c0..a9760719 100755
--- a/Include/Library/OcBootManagementLib.h
+++ b/Include/Library/OcBootManagementLib.h
@@ -36,6 +36,15 @@ typedef enum OC_BOOT_ENTRY_TYPE_ {
OcBootSystem
} OC_BOOT_ENTRY_TYPE;
+/**
+ Picker mode.
+**/
+typedef enum OC_PICKER_MODE_ {
+ OcPickerModeBuiltin,
+ OcPickerModeExternal,
+ OcPickerModeApple,
+} OC_PICKER_MODE;
+
/**
Action to perform as part of executing a system boot entry.
**/
@@ -399,6 +408,10 @@ typedef struct {
//
CONST CHAR8 *TitleSuffix;
//
+ // Used picker mode.
+ //
+ OC_PICKER_MODE PickerMode;
+ //
// Console attributes. 0 is reserved as disabled.
//
UINT32 ConsoleAttributes;
@@ -830,4 +843,15 @@ OcDeleteVariables (
VOID
);
+
+/**
+ Launch Apple BootPicker.
+
+ @retval error code, should not return.
+**/
+EFI_STATUS
+OcRunAppleBootPicker (
+ VOID
+ );
+
#endif // OC_BOOT_MANAGEMENT_LIB_H
diff --git a/Include/Library/OcConfigurationLib.h b/Include/Library/OcConfigurationLib.h
index fdf9b8fd..349407f6 100644
--- a/Include/Library/OcConfigurationLib.h
+++ b/Include/Library/OcConfigurationLib.h
@@ -268,14 +268,14 @@
OC_DECLARE (OC_MISC_BLESS_ARRAY)
#define OC_MISC_BOOT_FIELDS(_, __) \
- _(BOOLEAN , HideSelf , , FALSE , ()) \
- _(BOOLEAN , PollAppleHotKeys , , FALSE , ()) \
- _(BOOLEAN , ShowPicker , , FALSE , ()) \
- _(BOOLEAN , UsePicker , , FALSE , ()) \
- _(UINT32 , PickerAttributes , , 0 , ()) \
- _(UINT32 , TakeoffDelay , , 0 , ()) \
- _(UINT32 , Timeout , , 0 , ()) \
- _(OC_STRING , HibernateMode , , OC_STRING_CONSTR ("None", _, __), OC_DESTR (OC_STRING))
+ _(OC_STRING , PickerMode , , OC_STRING_CONSTR ("Builtin", _, __) , OC_DESTR (OC_STRING)) \
+ _(OC_STRING , HibernateMode , , OC_STRING_CONSTR ("None", _, __) , OC_DESTR (OC_STRING)) \
+ _(UINT32 , PickerAttributes , , 0 , ()) \
+ _(UINT32 , TakeoffDelay , , 0 , ()) \
+ _(UINT32 , Timeout , , 0 , ()) \
+ _(BOOLEAN , HideSelf , , FALSE , ()) \
+ _(BOOLEAN , PollAppleHotKeys , , FALSE , ()) \
+ _(BOOLEAN , ShowPicker , , FALSE , ())
OC_DECLARE (OC_MISC_BOOT)
#define OC_MISC_DEBUG_FIELDS(_, __) \
diff --git a/Include/Library/OcFileLib.h b/Include/Library/OcFileLib.h
index 204ff9b7..068bb821 100755
--- a/Include/Library/OcFileLib.h
+++ b/Include/Library/OcFileLib.h
@@ -307,11 +307,24 @@ OcGetGptPartitionEntry (
/**
Unblocks all partition handles without a File System protocol attached from
driver connection, if applicable.
-
**/
VOID
OcUnblockUnmountedPartitions (
VOID
);
+
+/**
+ Creates a device path for a firmware file.
+
+ @param[in] FileGuid Firmware file GUID.
+
+ @retval device path allocated from pool on success.
+ @retval NULL on failure (e.g. when a file is not present).
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+CreateFvFileDevicePath (
+ IN EFI_GUID *FileGuid
+ );
+
#endif // OC_FILE_LIB_H
diff --git a/Library/OcBootManagementLib/OcBootManagementLib.c b/Library/OcBootManagementLib/OcBootManagementLib.c
index dccf480d..8f3cca19 100644
--- a/Library/OcBootManagementLib/OcBootManagementLib.c
+++ b/Library/OcBootManagementLib/OcBootManagementLib.c
@@ -14,6 +14,7 @@
#include "BootManagementInternal.h"
+#include
#include
#include
@@ -347,6 +348,7 @@ OcRunSimpleBootPicker (
OC_BOOT_ENTRY *Entries;
UINTN EntryCount;
INTN DefaultEntry;
+ BOOLEAN ForbidApple;
AppleBootPolicy = OcAppleBootPolicyInstallProtocol (FALSE);
if (AppleBootPolicy == NULL) {
@@ -360,6 +362,9 @@ OcRunSimpleBootPicker (
return EFI_NOT_FOUND;
}
+ //
+ // This one is handled as is for Apple BootPicker for now.
+ //
if (Context->PickerCommand != OcPickerDefault) {
Status = Context->RequestPrivilege (
Context->PrivilegeContext,
@@ -375,6 +380,14 @@ OcRunSimpleBootPicker (
}
}
+ if (Context->PickerCommand == OcPickerShowPicker && Context->PickerMode == OcPickerModeApple) {
+ Status = OcRunAppleBootPicker ();
+ DEBUG ((DEBUG_INFO, "OCB: Apple BootPicker failed - %r, fallback to builtin\n", Status));
+ ForbidApple = TRUE;
+ } else {
+ ForbidApple = FALSE;
+ }
+
while (TRUE) {
DEBUG ((DEBUG_INFO, "OCB: Performing OcScanForBootEntries...\n"));
@@ -406,6 +419,12 @@ OcRunSimpleBootPicker (
DefaultEntry = OcGetDefaultBootEntry (Context, Entries, EntryCount);
if (Context->PickerCommand == OcPickerShowPicker) {
+ if (!ForbidApple && Context->PickerMode == OcPickerModeApple) {
+ Status = OcRunAppleBootPicker ();
+ DEBUG ((DEBUG_INFO, "OCB: Apple BootPicker failed on error - %r, fallback to builtin\n", Status));
+ ForbidApple = TRUE;
+ }
+
Status = OcShowSimpleBootMenu (
Context,
Entries,
@@ -478,3 +497,45 @@ OcRunSimpleBootPicker (
OcFreeBootEntries (Entries, EntryCount);
}
}
+
+EFI_STATUS
+OcRunAppleBootPicker (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE NewHandle;
+ EFI_DEVICE_PATH_PROTOCOL *Dp;
+
+ Dp = CreateFvFileDevicePath (&gAppleBootPickerFileGuid);
+ if (Dp != NULL) {
+ NewHandle = NULL;
+ Status = gBS->LoadImage (
+ FALSE,
+ gImageHandle,
+ Dp,
+ NULL,
+ 0,
+ &NewHandle
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_INVALID_PARAMETER;
+ }
+ } else {
+ Status = EFI_NOT_FOUND;
+ }
+
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->StartImage (
+ NewHandle,
+ NULL,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_UNSUPPORTED;
+ }
+ }
+
+ return Status;
+}
diff --git a/Library/OcBootManagementLib/OcBootManagementLib.inf b/Library/OcBootManagementLib/OcBootManagementLib.inf
index dc898f28..a4743eb7 100644
--- a/Library/OcBootManagementLib/OcBootManagementLib.inf
+++ b/Library/OcBootManagementLib/OcBootManagementLib.inf
@@ -74,6 +74,7 @@
gOcVendorVariableGuid ## SOMETIMES_CONSUMES
gOcReadOnlyVariableGuid ## SOMETIMES_CONSUMES
gOcWriteOnlyVariableGuid ## SOMETIMES_CONSUMES
+ gAppleBootPickerFileGuid ## SOMETIMES_CONSUMES
[Protocols]
gAppleBootPolicyProtocolGuid ## PRODUCES
diff --git a/Library/OcConfigurationLib/OcConfigurationLib.c b/Library/OcConfigurationLib/OcConfigurationLib.c
index ed5e862e..352a163f 100644
--- a/Library/OcConfigurationLib/OcConfigurationLib.c
+++ b/Library/OcConfigurationLib/OcConfigurationLib.c
@@ -321,11 +321,11 @@ mMiscConfigurationBootSchema[] = {
OC_SCHEMA_STRING_IN ("HibernateMode", OC_GLOBAL_CONFIG, Misc.Boot.HibernateMode),
OC_SCHEMA_BOOLEAN_IN ("HideSelf", OC_GLOBAL_CONFIG, Misc.Boot.HideSelf),
OC_SCHEMA_INTEGER_IN ("PickerAttributes", OC_GLOBAL_CONFIG, Misc.Boot.PickerAttributes),
+ OC_SCHEMA_STRING_IN ("PickerMode", OC_GLOBAL_CONFIG, Misc.Boot.PickerMode),
OC_SCHEMA_BOOLEAN_IN ("PollAppleHotKeys", OC_GLOBAL_CONFIG, Misc.Boot.PollAppleHotKeys),
OC_SCHEMA_BOOLEAN_IN ("ShowPicker", OC_GLOBAL_CONFIG, Misc.Boot.ShowPicker),
OC_SCHEMA_INTEGER_IN ("TakeoffDelay", OC_GLOBAL_CONFIG, Misc.Boot.TakeoffDelay),
OC_SCHEMA_INTEGER_IN ("Timeout", OC_GLOBAL_CONFIG, Misc.Boot.Timeout),
- OC_SCHEMA_BOOLEAN_IN ("UsePicker", OC_GLOBAL_CONFIG, Misc.Boot.UsePicker),
};
STATIC
diff --git a/Library/OcFileLib/FirmwareFile.c b/Library/OcFileLib/FirmwareFile.c
new file mode 100644
index 00000000..83bae1ae
--- /dev/null
+++ b/Library/OcFileLib/FirmwareFile.c
@@ -0,0 +1,113 @@
+/** @file
+ Copyright (C) 2020, 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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+STATIC
+EFI_HANDLE
+GetFvFileVolume (
+ IN EFI_GUID *FvNameGuid
+ )
+{
+ UINTN Index;
+ EFI_STATUS Status;
+ UINT32 AuthenticationStatus;
+ EFI_FIRMWARE_VOLUME_PROTOCOL *FirmwareVolumeInterface;
+ UINTN NumOfHandles;
+ EFI_HANDLE *HandleBuffer;
+ EFI_FV_FILETYPE Type;
+ UINTN Size;
+ EFI_FV_FILE_ATTRIBUTES Attributes;
+ EFI_HANDLE CurrentVolume;
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiFirmwareVolumeProtocolGuid,
+ NULL,
+ &NumOfHandles,
+ &HandleBuffer
+ );
+
+ //
+ // TODO: Support FirmwareVolume2?
+ //
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ for (Index = 0; Index < NumOfHandles; ++Index) {
+ CurrentVolume = HandleBuffer[Index];
+
+ Status = gBS->HandleProtocol (
+ CurrentVolume,
+ &gEfiFirmwareVolumeProtocolGuid,
+ (VOID **) &FirmwareVolumeInterface
+ );
+
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ Status = FirmwareVolumeInterface->ReadFile (
+ FirmwareVolumeInterface,
+ FvNameGuid,
+ NULL,
+ &Size,
+ &Type,
+ &Attributes,
+ &AuthenticationStatus
+ );
+
+ if (!EFI_ERROR (Status)) {
+ gBS->FreePool (HandleBuffer);
+ return CurrentVolume;
+ }
+ }
+
+ gBS->FreePool (HandleBuffer);
+ return NULL;
+}
+
+EFI_DEVICE_PATH_PROTOCOL *
+CreateFvFileDevicePath (
+ IN EFI_GUID *FileGuid
+ )
+{
+ EFI_HANDLE VolumeHandle;
+ EFI_DEVICE_PATH_PROTOCOL *VolumeDevicePath;
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FvFileNode;
+
+ VolumeHandle = GetFvFileVolume (FileGuid);
+ if (VolumeHandle == NULL) {
+ return NULL;
+ }
+
+ VolumeDevicePath = DevicePathFromHandle (VolumeHandle);
+ if (VolumeDevicePath == NULL) {
+ return NULL;
+ }
+
+ EfiInitializeFwVolDevicepathNode (&FvFileNode, FileGuid);
+ return AppendDevicePathNode (VolumeDevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &FvFileNode);
+}
diff --git a/Library/OcFileLib/OcFileLib.inf b/Library/OcFileLib/OcFileLib.inf
index 589f36ca..d124e6d1 100755
--- a/Library/OcFileLib/OcFileLib.inf
+++ b/Library/OcFileLib/OcFileLib.inf
@@ -34,9 +34,11 @@
OpenFile.c
ReadFile.c
GptPartitionEntry.c
+ FirmwareFile.c
FsConnectQuirk.c
[Packages]
+ EfiPkg/EfiPkg.dec
OcSupportPkg/OcSupportPkg.dec
MdePkg/MdePkg.dec
@@ -54,7 +56,9 @@
gEfiPartTypeSystemPartGuid ## CONSUMES
[Protocols]
+ gEfiFirmwareVolumeProtocolGuid
gEfiFirmwareVolume2ProtocolGuid
+ gEfiDevicePathProtocolGuid
gEfiBlockIo2ProtocolGuid
gEfiBlockIoProtocolGuid
gEfiDiskIo2ProtocolGuid
diff --git a/Library/OcInputLib/Keycode/AIK.c b/Library/OcInputLib/Keycode/AIK.c
index d4158866..a71f2dda 100644
--- a/Library/OcInputLib/Keycode/AIK.c
+++ b/Library/OcInputLib/Keycode/AIK.c
@@ -130,9 +130,14 @@ AIKPollKeyboardHandler (
&KeyData
);
if (!EFI_ERROR (Status)) {
- (VOID) Counter;
- DEBUG ((DEBUG_VERBOSE, "Read key with scan 0x%X and unicode 0x%X at %Lu\n",
- KeyData.Key.ScanCode, KeyData.Key.UnicodeChar, Counter
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "AIK: Key scan 0x%X uni 0x%X Shift 0x%X toggle 0x%X at %Lu\n",
+ KeyData.Key.ScanCode,
+ KeyData.Key.UnicodeChar,
+ KeyData.KeyState.KeyShiftState,
+ KeyData.KeyState.KeyToggleState,
+ Counter
));
AIKDataWriteEntry (&Keycode->Data, &KeyData);
AIKTargetWriteEntry (&Keycode->Target, &KeyData);
diff --git a/OcSupportPkg.dsc b/OcSupportPkg.dsc
index 5df6459d..0bd87563 100644
--- a/OcSupportPkg.dsc
+++ b/OcSupportPkg.dsc
@@ -102,6 +102,7 @@
UefiUsbLib|MdePkg/Library/UefiUsbLib/UefiUsbLib.inf
[Components]
+ OcSupportPkg/Application/BootKicker/BootKicker.inf
OcSupportPkg/Application/CleanNvram/CleanNvram.inf
OcSupportPkg/Application/PavpProvision/PavpProvision.inf
OcSupportPkg/Application/VerifyMsrE2/VerifyMsrE2.inf