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