diff --git a/Changelog.md b/Changelog.md index 1051edc0..6f8e308b 100644 --- a/Changelog.md +++ b/Changelog.md @@ -14,6 +14,9 @@ OpenCore Changelog - Reduced OpenCanopy size by restricting boot management access - Added `BuiltinText` variant for `TextRenderer` for older laptops - Fixed `SyncRuntimePermissions` creating invalid MAT table +- Added EFI FAT image loading support (macOS 10.8 and earlier) +- Added cacheless kext injection support (macOS 10.9 and earlier) +- Added mkext kext injection support (macOS 10.6 and earlier) #### v0.6.0 - Fixed sound corruption with AudioDxe diff --git a/Library/OcBootManagementLib/BootManagementInternal.h b/Library/OcBootManagementLib/BootManagementInternal.h index 0811f1cf..1a8164d5 100644 --- a/Library/OcBootManagementLib/BootManagementInternal.h +++ b/Library/OcBootManagementLib/BootManagementInternal.h @@ -176,4 +176,14 @@ InternalSystemActionResetNvram ( VOID ); +/** + Initialises custom gBS->LoadImage override. + + @retval EFI_SUCCESS on success. +**/ +EFI_STATUS +InternalInitImageLoader ( + VOID + ); + #endif // BOOT_MANAGEMENET_INTERNAL_H diff --git a/Library/OcBootManagementLib/ImageLoader.c b/Library/OcBootManagementLib/ImageLoader.c new file mode 100644 index 00000000..a1cc0589 --- /dev/null +++ b/Library/OcBootManagementLib/ImageLoader.c @@ -0,0 +1,249 @@ +/** @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 "BootManagementInternal.h" + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +STATIC EFI_IMAGE_LOAD mOriginalEfiLoadImage; + +STATIC +EFI_STATUS +InternalEfiLoadImageFile ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + OUT UINTN *FileSize, + OUT VOID **FileBuffer + ) +{ + EFI_STATUS Status; + EFI_FILE_PROTOCOL *File; + VOID *Buffer; + UINT32 Size; + + Status = OcOpenFileByDevicePath ( + &DevicePath, + &File, + EFI_FILE_MODE_READ, + 0 + ); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + + Status = GetFileSize ( + File, + &Size + ); + if (EFI_ERROR (Status) || Size == 0) { + File->Close (File); + return EFI_UNSUPPORTED; + } + + Buffer = AllocatePool (Size); + if (Buffer == NULL) { + File->Close (File); + return EFI_OUT_OF_RESOURCES; + } + + Status = GetFileData ( + File, + 0, + Size, + Buffer + ); + if (EFI_ERROR (Status)) { + FreePool (Buffer); + File->Close (File); + return EFI_DEVICE_ERROR; + } + + *FileBuffer = Buffer; + *FileSize = Size; + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +InternalEfiLoadImageProtocol ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN BOOLEAN UseLoadImage2, + OUT UINTN *FileSize, + OUT VOID **FileBuffer + ) +{ + // + // TODO: Implement image load protocol if necessary. + // + return EFI_UNSUPPORTED; +} + +STATIC +EFI_STATUS +InternalUpdateLoadedImage ( + IN EFI_HANDLE ImageHandle, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + EFI_STATUS Status; + EFI_HANDLE DeviceHandle; + EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; + EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath; + + Status = gBS->HandleProtocol ( + ImageHandle, + &gEfiLoadedImageProtocolGuid, + (VOID **) &LoadedImage + ); + if (EFI_ERROR (Status)) { + return Status; + } + + RemainingDevicePath = DevicePath; + Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &RemainingDevicePath, &DeviceHandle); + if (EFI_ERROR (Status)) { + // + // TODO: Handle load protocol if necessary. + // + return Status; + } + + if (LoadedImage->DeviceHandle != DeviceHandle) { + LoadedImage->DeviceHandle = DeviceHandle; + LoadedImage->FilePath = DuplicateDevicePath (RemainingDevicePath); + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +InternalEfiLoadImage ( + IN BOOLEAN BootPolicy, + IN EFI_HANDLE ParentImageHandle, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN VOID *SourceBuffer OPTIONAL, + IN UINTN SourceSize, + OUT EFI_HANDLE *ImageHandle + ) +{ + EFI_STATUS Status; + VOID *AllocatedBuffer; + UINT32 RealSize; + + if (ParentImageHandle == NULL || ImageHandle == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (SourceBuffer == NULL && DevicePath == NULL) { + return EFI_NOT_FOUND; + } + + if (SourceBuffer != NULL && SourceSize == 0) { + return EFI_UNSUPPORTED; + } + + AllocatedBuffer = NULL; + if (SourceBuffer == NULL) { + Status = InternalEfiLoadImageFile ( + DevicePath, + &SourceSize, + &SourceBuffer + ); + if (EFI_ERROR (Status)) { + Status = InternalEfiLoadImageProtocol ( + DevicePath, + BootPolicy == FALSE, + &SourceSize, + &SourceBuffer + ); + } + + if (!EFI_ERROR (Status)) { + AllocatedBuffer = SourceBuffer; + } + } + + if (SourceBuffer != NULL) { + RealSize = (UINT32) SourceSize; +#ifdef MDE_CPU_IA32 + Status = FatFilterArchitecture32 ((UINT8 **) &SourceBuffer, &RealSize); +#else + Status = FatFilterArchitecture64 ((UINT8 **) &SourceBuffer, &RealSize); +#endif + if (!EFI_ERROR (Status)) { + SourceSize = RealSize; + } else if (AllocatedBuffer != NULL) { + SourceBuffer = NULL; + SourceSize = 0; + } + } + + Status = mOriginalEfiLoadImage ( + BootPolicy, + ParentImageHandle, + DevicePath, + SourceBuffer, + SourceSize, + ImageHandle + ); + + if (AllocatedBuffer != NULL) { + FreePool (AllocatedBuffer); + } + + // + // Some firmwares may not update loaded image protocol fields correctly + // when loading via source buffer. Do it here. + // + if (!EFI_ERROR (Status) && SourceBuffer != NULL && DevicePath != NULL) { + InternalUpdateLoadedImage (*ImageHandle, DevicePath); + } + + return Status; +} + +EFI_STATUS +InternalInitImageLoader ( + VOID + ) +{ + mOriginalEfiLoadImage = gBS->LoadImage; + gBS->LoadImage = InternalEfiLoadImage; + + gBS->Hdr.CRC32 = 0; + gBS->CalculateCrc32 (gBS, gBS->Hdr.HeaderSize, &gBS->Hdr.CRC32); + return EFI_SUCCESS; +} diff --git a/Library/OcBootManagementLib/OcBootManagementLib.c b/Library/OcBootManagementLib/OcBootManagementLib.c index b9c9180b..bef5cd50 100644 --- a/Library/OcBootManagementLib/OcBootManagementLib.c +++ b/Library/OcBootManagementLib/OcBootManagementLib.c @@ -508,6 +508,11 @@ OcRunBootPicker ( SaidWelcome = FALSE; + Status = InternalInitImageLoader (); + if (EFI_ERROR (Status)) { + return Status; + } + // // Reset NVRAM right away if requested by a key combination. // This function should not return under normal conditions. diff --git a/Library/OcBootManagementLib/OcBootManagementLib.inf b/Library/OcBootManagementLib/OcBootManagementLib.inf index f2ae65d6..11bfb7bf 100644 --- a/Library/OcBootManagementLib/OcBootManagementLib.inf +++ b/Library/OcBootManagementLib/OcBootManagementLib.inf @@ -41,6 +41,7 @@ DefaultEntryChoice.c DmgBootSupport.c HotKeySupport.c + ImageLoader.c PolicyManagement.c OcBootManagementLib.c VariableManagement.c diff --git a/Library/OcMachoLib/Fat.c b/Library/OcMachoLib/Fat.c index a38aba5b..06a4c086 100644 --- a/Library/OcMachoLib/Fat.c +++ b/Library/OcMachoLib/Fat.c @@ -55,7 +55,8 @@ FatGetArchitectureOffset ( FatHeader = (MACH_FAT_HEADER*) Buffer; if (FatHeader->Signature != MACH_FAT_BINARY_INVERT_SIGNATURE - && FatHeader->Signature != MACH_FAT_BINARY_SIGNATURE) { + && FatHeader->Signature != MACH_FAT_BINARY_SIGNATURE + && FatHeader->Signature != EFI_FAT_BINARY_SIGNATURE) { // // Non-fat binary. // diff --git a/Utilities/TestKextInject/KextInject.c b/Utilities/TestKextInject/KextInject.c index 3e1ec749..acece09f 100644 --- a/Utilities/TestKextInject/KextInject.c +++ b/Utilities/TestKextInject/KextInject.c @@ -12,8 +12,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ -#include - +#include #include #include #include