diff --git a/Docs/Configuration.tex b/Docs/Configuration.tex index 6618f72a..2d911612 100755 --- a/Docs/Configuration.tex +++ b/Docs/Configuration.tex @@ -2296,24 +2296,43 @@ blocking. \textbf{Type}: \texttt{plist\ string}\\ \textbf{Failsafe}: \texttt{Auto}\\ \textbf{Description}: Prefer specified kernel architecture (\texttt{Auto}, \texttt{i386}, - \texttt{x86\_64}) when available. + \texttt{i386-user32}, \texttt{x86\_64}) when available. On macOS 10.7 and earlier XNU kernel may not boot with the usual \texttt{x86\_64} architecture, and the exact choice depends on many factors including boot arguments, SMBIOS, and operating system type. This setting will use the specified architecture to boot macOS when it is supported - by the macOS and the configuration. Below is the algorithm determining the kernel architecture. + by the macOS and the configuration: + + \begin{itemize} + \tightlist + \item \texttt{Auto} --- Choose the preferred architecture automatically. + \item \texttt{i386} --- Use \texttt{i386} (32-bit) kernel when available. + \item \texttt{i386-user32} --- Use \texttt{i386} (32-bit) kernel when available + and force the use of 32-bit userspace even on 64-bit capable processors + (similar to \texttt{-legacy} boot argument). This mode is relevant for older Pentium + processors with \texttt{x86\_64} support but without \texttt{SSSE3}, which + on macOS 10.6 will result in some applications crashing. + \item \texttt{x86\_64} --- Use \texttt{x86\_64} (64-bit) kernel when available. + \end{itemize} + + Below is the algorithm determining the kernel architecture. \begin{enumerate} \tightlist \item \texttt{arch} argument in image arguments (e.g. when launched - via UEFI Shell) or in \texttt{boot-args} variable override any compatibility - checks and force the specified architecture. + via UEFI Shell) or in \texttt{boot-args} variable overrides any compatibility + checks and forces the specified architecture, ending this algorithm. + \item OpenCore build architecture restricts capabilities to \texttt{i386} + and \texttt{i386-user32} mode in 32-bit firmware variant. \item Determined EfiBoot version restricts architecture choice: \begin{itemize} - \item 10.4-10.5 --- \texttt{i386} - \item 10.6-10.7 --- \texttt{i386} or \texttt{x86\_64} + \item 10.4-10.5 --- \texttt{i386} or \texttt{i386-user32} + \item 10.6-10.7 --- \texttt{i386}, \texttt{i386-user32}, or \texttt{x86\_64} \item 10.8 or newer --- \texttt{x86\_64} \end{itemize} + \item \texttt{CPUID} capabilities restrict capabilities to + \texttt{i386-user32} if \texttt{SSSE3} is not available + and \texttt{KernelArch} is set to \texttt{Auto}. \item SMBIOS model information and EfiBoot version restrict architecture choice and define architecture preference for client and server operating systems according to the table below. diff --git a/Include/Acidanthera/Library/OcAfterBootCompatLib.h b/Include/Acidanthera/Library/OcAfterBootCompatLib.h index 223f290e..3b1482df 100644 --- a/Include/Acidanthera/Library/OcAfterBootCompatLib.h +++ b/Include/Acidanthera/Library/OcAfterBootCompatLib.h @@ -141,16 +141,4 @@ OcAbcInitialize ( IN OC_ABC_SETTINGS *Settings ); -/** - Determine if 32-bit kernel boot mode is preferred. - - @param[out] Prefer32Bit TRUE if 32-bit is preferred. - - @retval EFI_SUCCESS on success. -**/ -EFI_STATUS -OcAbcIs32BitPreferred ( - OUT BOOLEAN *Prefer32Bit - ); - #endif // OC_AFTER_BOOT_COMPAT_LIB_H diff --git a/Include/Acidanthera/Library/OcAppleKernelLib.h b/Include/Acidanthera/Library/OcAppleKernelLib.h index 3b7c80d3..564bbb43 100644 --- a/Include/Acidanthera/Library/OcAppleKernelLib.h +++ b/Include/Acidanthera/Library/OcAppleKernelLib.h @@ -70,6 +70,23 @@ #define KC_LINKEDIT_SEGMENT "__LINKEDIT" #define KC_MOSCOW_SEGMENT "__MOSCOW101" +// +// Kernel cache types. +// +typedef enum KERNEL_CACHE_TYPE_ { + CacheTypeCacheless, + CacheTypeMkext, + CacheTypePrelinked +} KERNEL_CACHE_TYPE; + +// +// Macro to print kernel cache type. +// +#define PRINT_KERNEL_CACHE_TYPE(a) ( \ + (a) == CacheTypeCacheless ? "Cacheless" : \ + ((a) == CacheTypeMkext ? "Mkext" : \ + (((a) == CacheTypePrelinked ? "Prelinked" : "Unknown")))) + // // As PageCount is UINT16, we can only index 2^16 * 4096 Bytes with one chain. // diff --git a/Include/Acidanthera/Library/OcBootManagementLib.h b/Include/Acidanthera/Library/OcBootManagementLib.h index f9c199f5..e9bfa55a 100755 --- a/Include/Acidanthera/Library/OcBootManagementLib.h +++ b/Include/Acidanthera/Library/OcBootManagementLib.h @@ -117,10 +117,21 @@ typedef enum OC_PICKER_MODE_ { /** macOS Kernel capabilities. + Written in pairs of kernel and user capabilities. + + On IA32 firmware: + 10.4-10.5 - K32_U32 | K32_U64. + 10.6 - K32_U32 | K32_U64. + 10.7+ - K32_U64. + + On X64 firmware: + 10.4-10.5 - K32_U32 | K32_U64. + 10.6 - K32_U32 | K32_U64 | K64_U64. + 10.7+ - K32_U64 | K64_U64. **/ -#define OC_KERN_CAPABILITY_K32_32 BIT0 ///< Supports K32 with i386 requirement (10.4~10.6) -#define OC_KERN_CAPABILITY_K32_64 BIT1 ///< Supports K32 with x86_64 requirement (10.7) -#define OC_KERN_CAPABILITY_K64 BIT2 ///< Supports K64 (10.6+) +#define OC_KERN_CAPABILITY_K32_U32 BIT0 ///< Supports K32 and U32 (10.4~10.6) +#define OC_KERN_CAPABILITY_K32_U64 BIT1 ///< Supports K32 and U64 (10.4~10.7) +#define OC_KERN_CAPABILITY_K64_U64 BIT2 ///< Supports K64 and U64 (10.6+) /** Action to perform as part of executing a system boot entry. @@ -1262,13 +1273,45 @@ OcImageLoaderActivate ( ); /** - Get Apple kernel capabilities for the currently loaded image. - - @returns OC_KERN_CAPABILITY bitmask. + Image loader callback triggered before LoadImage. **/ -UINT32 -OcImageLoaderGetKernCaps ( - VOID +typedef +VOID +(*OC_IMAGE_LOADER_PATCH) ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL, + IN VOID *SourceBuffer, + IN UINTN SourceSize + ); + +/** + Image loader callback triggered before StartImage. +**/ +typedef +VOID +(*OC_IMAGE_LOADER_CONFIGURE) ( + IN OUT EFI_LOADED_IMAGE_PROTOCOL *LoadedImage, + IN UINT32 Capabilities + ); + + +/** + Register image loading callback. + + @param[in] Patch Callback function to call on image load. +**/ +VOID +OcImageLoaderRegisterPatch ( + IN OC_IMAGE_LOADER_PATCH Patch OPTIONAL + ); + +/** + Register image start callback. + + @param[in] Configure Callback function to call on image start. +**/ +VOID +OcImageLoaderRegisterConfigure ( + IN OC_IMAGE_LOADER_CONFIGURE Configure OPTIONAL ); /** diff --git a/Include/Acidanthera/OpenCore.h b/Include/Acidanthera/OpenCore.h index 3c81f405..5b7046e4 100644 --- a/Include/Acidanthera/OpenCore.h +++ b/Include/Acidanthera/OpenCore.h @@ -15,6 +15,7 @@ #ifndef OPEN_CORE_H #define OPEN_CORE_H +#include #include #include #include @@ -119,6 +120,42 @@ OcLoadKernelSupport ( IN OC_CPU_INFO *CpuInfo ); +/** + Apply kernel quirk. +**/ +EFI_STATUS +OcKernelApplyQuirk ( + IN KERNEL_QUIRK_NAME Quirk, + IN KERNEL_CACHE_TYPE CacheType, + IN UINT32 DarwinVersion, + IN OUT VOID *Context, + IN OUT PATCHER_CONTEXT *KernelPatcher + ); + +/** + Apply kernel patch. +**/ +VOID +OcKernelApplyPatches ( + IN OC_GLOBAL_CONFIG *Config, + IN OC_CPU_INFO *CpuInfo, + IN UINT32 DarwinVersion, + IN KERNEL_CACHE_TYPE CacheType, + IN VOID *Context, + IN OUT UINT8 *Kernel, + IN UINT32 Size + ); + +/** + Apply kernel block patch. +**/ +VOID +OcKernelBlockKexts ( + IN OC_GLOBAL_CONFIG *Config, + IN UINT32 DarwinVersion, + IN PRELINKED_CONTEXT *Context + ); + /** Cleanup Kernel compatibility support on failure. **/ diff --git a/Library/OcAfterBootCompatLib/BootCompatInternal.h b/Library/OcAfterBootCompatLib/BootCompatInternal.h index ff7595d9..a87e209d 100644 --- a/Library/OcAfterBootCompatLib/BootCompatInternal.h +++ b/Library/OcAfterBootCompatLib/BootCompatInternal.h @@ -229,14 +229,6 @@ typedef struct SERVICES_OVERRIDE_STATE_ { /// TRUE if we are waiting for performance memory allocation. /// BOOLEAN AwaitingPerfAlloc; - /// - /// TRUE if arch= argument is present in boot args. - /// - BOOLEAN AppleArch; - /// - /// TRUE if we should boot in 32-bit kernel mode. - /// - BOOLEAN AppleArchPrefer32Bit; } SERVICES_OVERRIDE_STATE; /** diff --git a/Library/OcAfterBootCompatLib/OcAfterBootCompatLib.c b/Library/OcAfterBootCompatLib/OcAfterBootCompatLib.c index 702ea385..f74792a9 100644 --- a/Library/OcAfterBootCompatLib/OcAfterBootCompatLib.c +++ b/Library/OcAfterBootCompatLib/OcAfterBootCompatLib.c @@ -158,20 +158,3 @@ OcAbcInitialize ( return EFI_SUCCESS; } - -EFI_STATUS -OcAbcIs32BitPreferred ( - OUT BOOLEAN *Prefer32Bit - ) -{ - BOOT_COMPAT_CONTEXT *BootCompat; - - BootCompat = GetBootCompatContext (); - - if (BootCompat->ServiceState.AppleArch) { - *Prefer32Bit = BootCompat->ServiceState.AppleArchPrefer32Bit; - return EFI_SUCCESS; - } - - return EFI_NOT_FOUND; -} diff --git a/Library/OcAfterBootCompatLib/ServiceOverrides.c b/Library/OcAfterBootCompatLib/ServiceOverrides.c index c6778238..a4fc1f4a 100644 --- a/Library/OcAfterBootCompatLib/ServiceOverrides.c +++ b/Library/OcAfterBootCompatLib/ServiceOverrides.c @@ -611,8 +611,6 @@ OcStartImage ( OC_FWRT_CONFIG Config; UINTN DataSize; - CHAR8 *AppleArchValue; - BootCompat = GetBootCompatContext (); AppleLoadedImage = OcGetAppleBootLoadedImage (ImageHandle); @@ -647,17 +645,6 @@ OcStartImage ( L_STR_LEN ("slide="), NULL ); - BootCompat->ServiceState.AppleArch = OcCheckArgumentFromEnv ( - AppleLoadedImage, - BootCompat->ServicePtrs.GetVariable, - "arch=", - L_STR_LEN ("arch="), - &AppleArchValue - ); - if (BootCompat->ServiceState.AppleArch) { - BootCompat->ServiceState.AppleArchPrefer32Bit = AsciiStrCmp (AppleArchValue, "i386") == 0; - FreePool (AppleArchValue); - } if (BootCompat->Settings.EnableSafeModeSlide) { ASSERT (AppleLoadedImage->ImageSize <= MAX_UINTN); diff --git a/Library/OcBootManagementLib/ImageLoader.c b/Library/OcBootManagementLib/ImageLoader.c index 30a014bf..8d47f65c 100644 --- a/Library/OcBootManagementLib/ImageLoader.c +++ b/Library/OcBootManagementLib/ImageLoader.c @@ -74,8 +74,11 @@ STATIC EFI_IMAGE_START mOriginalEfiStartImage; STATIC EFI_IMAGE_UNLOAD mOriginalEfiUnloadImage; STATIC EFI_EXIT mOriginalEfiExit; STATIC EFI_HANDLE mCurrentImageHandle; -STATIC UINT32 mImageLoaderCaps; -STATIC BOOLEAN mImageLoaderEnabled; + +STATIC OC_IMAGE_LOADER_PATCH mImageLoaderPatch; +STATIC OC_IMAGE_LOADER_CONFIGURE mImageLoaderConfigure; +STATIC UINT32 mImageLoaderCaps; +STATIC BOOLEAN mImageLoaderEnabled; STATIC EFI_STATUS @@ -198,12 +201,12 @@ OcImageLoaderLoad ( { EFI_STATUS Status; IMAGE_STATUS ImageStatus; - PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; EFI_PHYSICAL_ADDRESS DestinationArea; VOID *DestinationBuffer; OC_LOADED_IMAGE_PROTOCOL *OcLoadedImage; EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; - + ASSERT (SourceBuffer != NULL); // @@ -628,9 +631,9 @@ DetectCapabilities ( // version pattern presence. // if (Result >= 0) { - return OC_KERN_CAPABILITY_K32_64; + return OC_KERN_CAPABILITY_K32_U64; } - return OC_KERN_CAPABILITY_K32_32; + return OC_KERN_CAPABILITY_K32_U32 | OC_KERN_CAPABILITY_K32_U64; #else // // For X64 mode, when the pattern is found, this can be 10.7 or 10.8+. @@ -638,9 +641,9 @@ DetectCapabilities ( // if (Result >= 0) { if (((UINT8 *)SourceBuffer)[Result + L_STR_LEN ("Mac OS X 10.")] == '7') { - return OC_KERN_CAPABILITY_K32_64 | OC_KERN_CAPABILITY_K64; + return OC_KERN_CAPABILITY_K32_U64 | OC_KERN_CAPABILITY_K64_U64; } - return OC_KERN_CAPABILITY_K64; + return OC_KERN_CAPABILITY_K64_U64; } // @@ -657,9 +660,9 @@ DetectCapabilities ( (INT32) (SourceSize / 2) ); if (Result >= 0) { - return OC_KERN_CAPABILITY_K32_32 | OC_KERN_CAPABILITY_K64; + return OC_KERN_CAPABILITY_K32_U32 | OC_KERN_CAPABILITY_K32_U64 | OC_KERN_CAPABILITY_K64_U64; } - return OC_KERN_CAPABILITY_K32_32; + return OC_KERN_CAPABILITY_K32_U32 | OC_KERN_CAPABILITY_K32_U64; #endif } @@ -738,9 +741,9 @@ InternalEfiLoadImage ( // By default assume target default. // #ifdef MDE_CPU_IA32 - mImageLoaderCaps = OC_KERN_CAPABILITY_K32_32; + mImageLoaderCaps = OC_KERN_CAPABILITY_K32_U32 | OC_KERN_CAPABILITY_K32_U64; #else - mImageLoaderCaps = OC_KERN_CAPABILITY_K64; + mImageLoaderCaps = OC_KERN_CAPABILITY_K64_U64; #endif if (SourceBuffer != NULL) { @@ -778,6 +781,14 @@ InternalEfiLoadImage ( } } + if (SourceBuffer != NULL && mImageLoaderPatch != NULL) { + mImageLoaderPatch ( + DevicePath, + SourceBuffer, + SourceSize + ); + } + // // Load the image ourselves in secure boot mode. // @@ -833,8 +844,9 @@ InternalEfiStartImage ( OUT CHAR16 **ExitData OPTIONAL ) { - EFI_STATUS Status; - OC_LOADED_IMAGE_PROTOCOL *OcLoadedImage; + EFI_STATUS Status; + OC_LOADED_IMAGE_PROTOCOL *OcLoadedImage; + EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; // // If we loaded the image, invoke the entry point manually. @@ -845,6 +857,16 @@ InternalEfiStartImage ( (VOID **) &OcLoadedImage ); if (!EFI_ERROR (Status)) { + // + // Call configure update for our images. + // + if (mImageLoaderConfigure != NULL) { + mImageLoaderConfigure ( + &OcLoadedImage->LoadedImage, + mImageLoaderCaps + ); + } + return InternalDirectStartImage ( OcLoadedImage, ImageHandle, @@ -853,6 +875,23 @@ InternalEfiStartImage ( ); } + // + // Call configure update for generic images too. + // + if (mImageLoaderConfigure != NULL) { + Status = gBS->HandleProtocol ( + ImageHandle, + &gEfiLoadedImageProtocolGuid, + (VOID **) &LoadedImage + ); + if (!EFI_ERROR (Status)) { + mImageLoaderConfigure ( + LoadedImage, + mImageLoaderCaps + ); + } + } + return mOriginalEfiStartImage (ImageHandle, ExitDataSize, ExitData); } @@ -948,10 +987,18 @@ OcImageLoaderActivate ( mImageLoaderEnabled = TRUE; } -UINT32 -OcImageLoaderGetKernCaps ( - VOID +VOID +OcImageLoaderRegisterPatch ( + IN OC_IMAGE_LOADER_PATCH Patch OPTIONAL ) { - return mImageLoaderCaps; + mImageLoaderPatch = Patch; +} + +VOID +OcImageLoaderRegisterConfigure ( + IN OC_IMAGE_LOADER_CONFIGURE Configure OPTIONAL + ) +{ + mImageLoaderConfigure = Configure; } diff --git a/Platform/OpenCore/OpenCore.inf b/Platform/OpenCore/OpenCore.inf index 25093c45..5b59d354 100644 --- a/Platform/OpenCore/OpenCore.inf +++ b/Platform/OpenCore/OpenCore.inf @@ -39,6 +39,7 @@ OpenCoreAcpi.c OpenCoreDevProps.c OpenCoreKernel.c + OpenCoreKernelPatch.c OpenCoreMisc.c OpenCoreNvram.c OpenCorePlatform.c diff --git a/Platform/OpenCore/OpenCoreKernel.c b/Platform/OpenCore/OpenCoreKernel.c index 15a6bcd4..35c11701 100644 --- a/Platform/OpenCore/OpenCoreKernel.c +++ b/Platform/OpenCore/OpenCoreKernel.c @@ -26,6 +26,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include #include +#include STATIC OC_STORAGE_CONTEXT *mOcStorage; STATIC OC_GLOBAL_CONFIG *mOcConfiguration; @@ -38,72 +39,73 @@ STATIC BOOLEAN mUse32BitKernel; STATIC CACHELESS_CONTEXT mOcCachelessContext; STATIC BOOLEAN mOcCachelessInProgress; -// -// Kernel cache types. -// -typedef enum KERNEL_CACHE_TYPE_ { - CacheTypeCacheless, - CacheTypeMkext, - CacheTypePrelinked -} KERNEL_CACHE_TYPE; - -#define PRINT_KERNEL_CACHE_TYPE(a) ( \ - (a) == CacheTypeCacheless ? L"Cacheless" : \ - ((a) == CacheTypeMkext ? L"Mkext" : \ - (((a) == CacheTypePrelinked ? L"Prelinked" : L"Unknown")))) - STATIC -VOID * -OcKernelReadSystemKextFile ( - IN EFI_FILE_PROTOCOL *RootFile, - IN CONST CHAR16 *FilePath, - OUT UINT32 *FileSize OPTIONAL +VOID +OcKernelConfigureCapabilities ( + IN OUT EFI_LOADED_IMAGE_PROTOCOL *LoadedImage, + IN UINT32 Capabilities ) { - EFI_STATUS Status; - EFI_FILE_PROTOCOL *File; - UINT32 Size; - UINT8 *FileBuffer; + CONST CHAR8 *KernelArch; + CHAR8 *AppleArchValue; + BOOLEAN HasAppleArch; + BOOLEAN Automatic; - Status = SafeFileOpen ( - RootFile, - &File, - (CHAR16 *) FilePath, - EFI_FILE_MODE_READ, - 0 + // + // Reset to the default value. + // Capabilities will always have K64 stripped when compiled for IA32. + // + mUse32BitKernel = (Capabilities & OC_KERN_CAPABILITY_K64_U64) == 0; + + // + // Skip if not Apple image. + // + if (LoadedImage->FilePath == NULL + || (OcGetBootDevicePathType (LoadedImage->FilePath, NULL, NULL) & OC_BOOT_APPLE_ANY) == 0) { + return; + } + + // + // arch boot argument overrides any compatibility checks. + // + HasAppleArch = OcCheckArgumentFromEnv ( + LoadedImage, + gRT->GetVariable, + "arch=", + L_STR_LEN ("arch="), + &AppleArchValue ); - if (EFI_ERROR (Status)) { - return NULL; + if (AppleArchValue) { + mUse32BitKernel = AsciiStrCmp (AppleArchValue, "i386") == 0; + DEBUG ((DEBUG_INFO, "OC: Arch %a overrides capabilities %u\n", AppleArchValue, Capabilities)); + FreePool (AppleArchValue); + return; } - Status = GetFileSize (File, &Size); - if (EFI_ERROR (Status) || Size >= MAX_UINT32 - 1) { - File->Close (File); - return NULL; + // + // FIXME: The rest is not complete. + // + + KernelArch = OC_BLOB_GET (&mOcConfiguration->Kernel.Scheme.KernelArch); + Automatic = KernelArch[0] == '\0' || AsciiStrCmp (KernelArch, "Auto") == 0; + + // + // In automatic mode, if we do not support SSSE3 and can downgrade to U32, do it. + // + if (Automatic && (Capabilities & OC_KERN_CAPABILITY_K32_U32) != 0 + && (Capabilities & (OC_KERN_CAPABILITY_K32_U64 | OC_KERN_CAPABILITY_K64_U64)) != 0 + && (mOcCpuInfo->Features & CPUID_FEATURE_SSSE3) == 0) { + DEBUG ((DEBUG_INFO, "OC: Missing SSSE3 disables U64 capabilities %u\n", Capabilities)); + Capabilities &= ~(OC_KERN_CAPABILITY_K32_U64 | OC_KERN_CAPABILITY_K64_U64); } - FileBuffer = AllocatePool (Size + 2); - if (FileBuffer == NULL) { - File->Close (File); - return NULL; + // + // If we do not support K64 for this target, force 32. + // + if ((Capabilities & OC_KERN_CAPABILITY_K64_U64) == 0) { + mUse32BitKernel = TRUE; } - - Status = GetFileData (File, 0, Size, FileBuffer); - File->Close (File); - if (EFI_ERROR (Status)) { - FreePool (FileBuffer); - return NULL; - } - - FileBuffer[Size] = 0; - FileBuffer[Size + 1] = 0; - - if (FileSize != NULL) { - *FileSize = Size; - } - - return FileBuffer; } STATIC @@ -191,10 +193,11 @@ OcKernelLoadKextsAndReserve ( UnicodeUefiSlashes (FullPath); - Kext->PlistData = OcKernelReadSystemKextFile ( + Kext->PlistData = ReadFileFromFile ( RootFile, FullPath, - &Kext->PlistDataSize + &Kext->PlistDataSize, + 0 ); if (Kext->PlistData == NULL) { @@ -231,10 +234,11 @@ OcKernelLoadKextsAndReserve ( UnicodeUefiSlashes (FullPath); - Kext->ImageData = OcKernelReadSystemKextFile ( + Kext->ImageData = ReadFileFromFile ( RootFile, FullPath, - &Kext->ImageDataSize + &Kext->ImageDataSize, + 0 ); if (Kext->ImageData == NULL) { @@ -439,314 +443,6 @@ OcKernelLoadKextsAndReserve ( return EFI_SUCCESS; } -STATIC -EFI_STATUS -OcKernelApplyQuirk ( - IN KERNEL_QUIRK_NAME Quirk, - IN KERNEL_CACHE_TYPE CacheType, - IN UINT32 DarwinVersion, - IN OUT VOID *Context, - IN OUT PATCHER_CONTEXT *KernelPatcher - ) -{ - // - // Apply kernel quirks to kernel, kext patches to context. - // - if (Context == NULL) { - ASSERT (KernelPatcher != NULL); - return KernelApplyQuirk (Quirk, KernelPatcher, DarwinVersion); - } - - if (CacheType == CacheTypeCacheless) { - return CachelessContextAddQuirk (Context, Quirk); - } - - if (CacheType == CacheTypeMkext) { - return MkextContextApplyQuirk (Context, Quirk, DarwinVersion); - } - - if (CacheType == CacheTypePrelinked) { - return PrelinkedContextApplyQuirk (Context, Quirk, DarwinVersion); - } - - return EFI_UNSUPPORTED; -} - -STATIC -VOID -OcKernelApplyPatches ( - IN OC_GLOBAL_CONFIG *Config, - IN UINT32 DarwinVersion, - IN KERNEL_CACHE_TYPE CacheType, - IN VOID *Context, - IN OUT UINT8 *Kernel, - IN UINT32 Size - ) -{ - EFI_STATUS Status; - PATCHER_CONTEXT KernelPatcher; - UINT32 Index; - PATCHER_GENERIC_PATCH Patch; - OC_KERNEL_PATCH_ENTRY *UserPatch; - CONST CHAR8 *Target; - CONST CHAR8 *Comment; - UINT32 MaxKernel; - UINT32 MinKernel; - BOOLEAN IsKernelPatch; - - IsKernelPatch = Context == NULL; - - if (IsKernelPatch) { - ASSERT (Kernel != NULL); - - Status = PatcherInitContextFromBuffer ( - &KernelPatcher, - Kernel, - Size - ); - - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_ERROR, "OC: Kernel patcher kernel init failure - %r\n", Status)); - return; - } - } - - for (Index = 0; Index < Config->Kernel.Patch.Count; ++Index) { - UserPatch = Config->Kernel.Patch.Values[Index]; - Target = OC_BLOB_GET (&UserPatch->Identifier); - Comment = OC_BLOB_GET (&UserPatch->Comment); - - if (!UserPatch->Enabled || (AsciiStrCmp (Target, "kernel") == 0) != IsKernelPatch) { - continue; - } - - MaxKernel = OcParseDarwinVersion (OC_BLOB_GET (&UserPatch->MaxKernel)); - MinKernel = OcParseDarwinVersion (OC_BLOB_GET (&UserPatch->MinKernel)); - - if (!OcMatchDarwinVersion (DarwinVersion, MinKernel, MaxKernel)) { - DEBUG (( - DEBUG_INFO, - "OC: Kernel patcher skips %a (%a) patch at %u due to version %u <= %u <= %u\n", - Target, - Comment, - Index, - MinKernel, - DarwinVersion, - MaxKernel - )); - continue; - } - - // - // Ignore patch if: - // - There is nothing to replace. - // - We have neither symbolic base, nor find data. - // - Find and replace mismatch in size. - // - Mask and ReplaceMask mismatch in size when are available. - // - if (UserPatch->Replace.Size == 0 - || (OC_BLOB_GET (&UserPatch->Base)[0] == '\0' && UserPatch->Find.Size != UserPatch->Replace.Size) - || (UserPatch->Mask.Size > 0 && UserPatch->Find.Size != UserPatch->Mask.Size) - || (UserPatch->ReplaceMask.Size > 0 && UserPatch->Find.Size != UserPatch->ReplaceMask.Size)) { - DEBUG ((DEBUG_ERROR, "OC: Kernel patch %u for %a (%a) is borked\n", Index, Target, Comment)); - continue; - } - - ZeroMem (&Patch, sizeof (Patch)); - - if (OC_BLOB_GET (&UserPatch->Comment)[0] != '\0') { - Patch.Comment = OC_BLOB_GET (&UserPatch->Comment); - } - - if (OC_BLOB_GET (&UserPatch->Base)[0] != '\0') { - Patch.Base = OC_BLOB_GET (&UserPatch->Base); - } - - if (UserPatch->Find.Size > 0) { - Patch.Find = OC_BLOB_GET (&UserPatch->Find); - } - - Patch.Replace = OC_BLOB_GET (&UserPatch->Replace); - - if (UserPatch->Mask.Size > 0) { - Patch.Mask = OC_BLOB_GET (&UserPatch->Mask); - } - - if (UserPatch->ReplaceMask.Size > 0) { - Patch.ReplaceMask = OC_BLOB_GET (&UserPatch->ReplaceMask); - } - - Patch.Size = UserPatch->Replace.Size; - Patch.Count = UserPatch->Count; - Patch.Skip = UserPatch->Skip; - Patch.Limit = UserPatch->Limit; - - if (IsKernelPatch) { - Status = PatcherApplyGenericPatch (&KernelPatcher, &Patch); - } else { - if (CacheType == CacheTypeCacheless) { - Status = CachelessContextAddPatch (Context, Target, &Patch); - } else if (CacheType == CacheTypeMkext) { - Status = MkextContextApplyPatch (Context, Target, &Patch); - } else if (CacheType == CacheTypePrelinked) { - Status = PrelinkedContextApplyPatch (Context, Target, &Patch); - } - } - - DEBUG (( - EFI_ERROR (Status) ? DEBUG_WARN : DEBUG_INFO, - "OC: Kernel patcher result %u for %a (%a) - %r\n", - Index, - Target, - Comment, - Status - )); - } - - if (!IsKernelPatch) { - if (Config->Kernel.Quirks.AppleCpuPmCfgLock) { - OcKernelApplyQuirk (KernelQuirkAppleCpuPmCfgLock, CacheType, DarwinVersion, Context, NULL); - } - - if (Config->Kernel.Quirks.ExternalDiskIcons) { - OcKernelApplyQuirk (KernelQuirkExternalDiskIcons, CacheType, DarwinVersion, Context, NULL); - } - - if (Config->Kernel.Quirks.ThirdPartyDrives) { - OcKernelApplyQuirk (KernelQuirkThirdPartyDrives, CacheType, DarwinVersion, Context, NULL); - } - - if (Config->Kernel.Quirks.XhciPortLimit) { - OcKernelApplyQuirk (KernelQuirkXhciPortLimit1, CacheType, DarwinVersion, Context, NULL); - OcKernelApplyQuirk (KernelQuirkXhciPortLimit2, CacheType, DarwinVersion, Context, NULL); - OcKernelApplyQuirk (KernelQuirkXhciPortLimit3, CacheType, DarwinVersion, Context, NULL); - } - - if (Config->Kernel.Quirks.DisableIoMapper) { - OcKernelApplyQuirk (KernelQuirkDisableIoMapper, CacheType, DarwinVersion, Context, NULL); - } - - if (Config->Kernel.Quirks.DisableRtcChecksum) { - OcKernelApplyQuirk (KernelQuirkDisableRtcChecksum, CacheType, DarwinVersion, Context, NULL); - } - - if (Config->Kernel.Quirks.IncreasePciBarSize) { - OcKernelApplyQuirk (KernelQuirkIncreasePciBarSize, CacheType, DarwinVersion, Context, NULL); - } - - if (Config->Kernel.Quirks.CustomSmbiosGuid) { - OcKernelApplyQuirk (KernelQuirkCustomSmbiosGuid1, CacheType, DarwinVersion, Context, NULL); - OcKernelApplyQuirk (KernelQuirkCustomSmbiosGuid2, CacheType, DarwinVersion, Context, NULL); - } - - if (Config->Kernel.Quirks.DummyPowerManagement) { - OcKernelApplyQuirk (KernelQuirkDummyPowerManagement, CacheType, DarwinVersion, Context, NULL); - } - } else { - if (Config->Kernel.Quirks.AppleXcpmCfgLock) { - OcKernelApplyQuirk (KernelQuirkAppleXcpmCfgLock, CacheType, DarwinVersion, NULL, &KernelPatcher); - } - - if (Config->Kernel.Quirks.AppleXcpmExtraMsrs) { - OcKernelApplyQuirk (KernelQuirkAppleXcpmExtraMsrs, CacheType, DarwinVersion, NULL, &KernelPatcher); - } - - if (Config->Kernel.Quirks.AppleXcpmForceBoost) { - OcKernelApplyQuirk (KernelQuirkAppleXcpmForceBoost, CacheType, DarwinVersion, NULL, &KernelPatcher); - } - - if (Config->Kernel.Quirks.PanicNoKextDump) { - OcKernelApplyQuirk (KernelQuirkPanicNoKextDump, CacheType, DarwinVersion, NULL, &KernelPatcher); - } - - if (Config->Kernel.Emulate.Cpuid1Data[0] != 0 - || Config->Kernel.Emulate.Cpuid1Data[1] != 0 - || Config->Kernel.Emulate.Cpuid1Data[2] != 0 - || Config->Kernel.Emulate.Cpuid1Data[3] != 0) { - PatchKernelCpuId ( - &KernelPatcher, - mOcCpuInfo, - Config->Kernel.Emulate.Cpuid1Data, - Config->Kernel.Emulate.Cpuid1Mask - ); - } - - if (Config->Kernel.Quirks.LapicKernelPanic) { - OcKernelApplyQuirk (KernelQuirkLapicKernelPanic, CacheType, DarwinVersion, NULL, &KernelPatcher); - } - - if (Config->Kernel.Quirks.PowerTimeoutKernelPanic) { - OcKernelApplyQuirk (KernelQuirkPowerTimeoutKernelPanic, CacheType, DarwinVersion, NULL, &KernelPatcher); - } - } -} - -STATIC -VOID -OcKernelBlockKexts ( - IN OC_GLOBAL_CONFIG *Config, - IN UINT32 DarwinVersion, - IN PRELINKED_CONTEXT *Context - ) -{ - EFI_STATUS Status; - PATCHER_CONTEXT Patcher; - UINT32 Index; - OC_KERNEL_BLOCK_ENTRY *Kext; - CONST CHAR8 *Target; - CONST CHAR8 *Comment; - UINT32 MaxKernel; - UINT32 MinKernel; - - for (Index = 0; Index < Config->Kernel.Block.Count; ++Index) { - Kext = Config->Kernel.Block.Values[Index]; - Target = OC_BLOB_GET (&Kext->Identifier); - Comment = OC_BLOB_GET (&Kext->Comment); - - if (!Kext->Enabled) { - continue; - } - - MaxKernel = OcParseDarwinVersion (OC_BLOB_GET (&Kext->MaxKernel)); - MinKernel = OcParseDarwinVersion (OC_BLOB_GET (&Kext->MinKernel)); - - if (!OcMatchDarwinVersion (DarwinVersion, MinKernel, MaxKernel)) { - DEBUG (( - DEBUG_INFO, - "OC: Prelink blocker skips %a (%a) block at %u due to version %u <= %u <= %u\n", - Target, - Comment, - Index, - MinKernel, - DarwinVersion, - MaxKernel - )); - continue; - } - - Status = PatcherInitContextFromPrelinked ( - &Patcher, - Context, - Target - ); - - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_WARN, "OC: Prelink blocker %a (%a) init failure - %r\n", Target, Comment, Status)); - continue; - } - - Status = PatcherBlockKext (&Patcher); - - DEBUG (( - EFI_ERROR (Status) ? DEBUG_WARN : DEBUG_INFO, - "OC: Prelink blocker %a (%a) - %r\n", - Target, - Comment, - Status - )); - } -} - STATIC VOID OcKernelInjectKext ( @@ -780,9 +476,9 @@ OcKernelInjectKext ( if (!OcMatchDarwinVersion (DarwinVersion, MinKernel, MaxKernel)) { DEBUG (( DEBUG_INFO, - "OC: %s%s injection skips %a (%a) kext at %u due to version %u <= %u <= %u\n", + "OC: %a%a injection skips %a (%a) kext at %u due to version %u <= %u <= %u\n", PRINT_KERNEL_CACHE_TYPE (CacheType), - IsForced ? L" force" : L"", + IsForced ? " force" : "", BundlePath, Comment, Index, @@ -845,9 +541,9 @@ OcKernelInjectKext ( DEBUG (( EFI_ERROR (Status) ? DEBUG_WARN : DEBUG_INFO, - "OC: %s%s injection %a (%a) - %r\n", + "OC: %a%a injection %a (%a) - %r\n", PRINT_KERNEL_CACHE_TYPE (CacheType), - IsForced ? L" force" : L"", + IsForced ? " force" : "", BundlePath, Comment, Status @@ -928,7 +624,7 @@ OcKernelInjectKexts ( } if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_WARN, "OC: %s insertion error - %r\n", PRINT_KERNEL_CACHE_TYPE (CacheType), Status)); + DEBUG ((DEBUG_WARN, "OC: %a insertion error - %r\n", PRINT_KERNEL_CACHE_TYPE (CacheType), Status)); } } @@ -952,7 +648,7 @@ OcKernelProcessPrelinked ( if (!EFI_ERROR (Status)) { OcKernelInjectKexts (Config, CacheTypePrelinked, &Context, DarwinVersion, LinkedExpansion, ReservedExeSize); - OcKernelApplyPatches (Config, DarwinVersion, CacheTypePrelinked, &Context, NULL, 0); + OcKernelApplyPatches (Config, mOcCpuInfo, DarwinVersion, CacheTypePrelinked, &Context, NULL, 0); OcKernelBlockKexts (Config, DarwinVersion, &Context); @@ -984,7 +680,7 @@ OcKernelProcessMkext ( OcKernelInjectKexts (Config, CacheTypeMkext, &Context, DarwinVersion, 0, 0); - OcKernelApplyPatches (Config, DarwinVersion, CacheTypeMkext, &Context, NULL, 0); + OcKernelApplyPatches (Config, mOcCpuInfo, DarwinVersion, CacheTypeMkext, &Context, NULL, 0); MkextInjectPatchComplete (&Context); @@ -1019,7 +715,7 @@ OcKernelInitCacheless ( OcKernelInjectKexts (Config, CacheTypeCacheless, Context, DarwinVersion, 0, 0); - OcKernelApplyPatches (Config, DarwinVersion, CacheTypeCacheless, Context, NULL, 0); + OcKernelApplyPatches (Config, mOcCpuInfo, DarwinVersion, CacheTypeCacheless, Context, NULL, 0); return CachelessContextOverlayExtensionsDir (Context, File); } @@ -1040,11 +736,9 @@ OcKernelReadAppleKernel ( ) { EFI_STATUS Status; - EFI_STATUS Status2; BOOLEAN Result; UINT32 DarwinVersionNew; BOOLEAN IsKernel32Bit; - BOOLEAN Use32BitKernel; UINT32 ReservedInfoSize; UINT32 NumReservedKexts; @@ -1094,10 +788,10 @@ OcKernelReadAppleKernel ( "OC: Result of %a XNU hook on %s (%02X%02X%02X%02X) is %r\n", IsKernel32Bit ? "32-bit" : "64-bit", FileName, - Digest ? Digest[0] : 0, - Digest ? Digest[1] : 0, - Digest ? Digest[2] : 0, - Digest ? Digest[3] : 0, + Digest != NULL ? Digest[0] : 0, + Digest != NULL ? Digest[1] : 0, + Digest != NULL ? Digest[2] : 0, + Digest != NULL ? Digest[3] : 0, Status )); @@ -1114,89 +808,16 @@ OcKernelReadAppleKernel ( } // - // Recheck kernel version and expected vs actual bitness returned. If either of those differ, - // re-evaluate whether we can run 64-bit kernels on this platform. + // If we failed to obtain the requested bitness for the platform, abort. // - if (DarwinVersionNew != *DarwinVersion || mUse32BitKernel != IsKernel32Bit) { - // - // Query command line arch= argument and fallback to SMBIOS checking. - // Arch argument will force the desired arch. - // - Status2 = OcAbcIs32BitPreferred (&Use32BitKernel); - if (EFI_ERROR (Status2)) { - Use32BitKernel = !OcPlatformIs64BitSupported (DarwinVersionNew); - } - - // - // If we did not change our desired arch, but the original kernel - // was wrong, just abort right away as the desired arch does not exist. - // - if (mUse32BitKernel == Use32BitKernel && mUse32BitKernel != IsKernel32Bit) { - DEBUG ((DEBUG_WARN, "OC: %a kernel architecture is not available, aborting.\n", mUse32BitKernel ? "32-bit" : "64-bit")); - FreePool (*Kernel); - *Kernel = NULL; - - return EFI_NOT_FOUND; - } - - // - // If a different kernel arch is required, but we did not originally read it, - // we'll need to try to get the kernel again. - // - if (mUse32BitKernel != Use32BitKernel) { - FreePool (*Kernel); - mUse32BitKernel = Use32BitKernel; - - DEBUG ((DEBUG_INFO, "OC: Wrong arch read, retrying %a XNU hook on %s\n", mUse32BitKernel ? "32-bit" : "64-bit", FileName)); - Status = ReadAppleKernel ( - KernelFile, - mUse32BitKernel, - &IsKernel32Bit, - Kernel, - KernelSize, - AllocatedSize, - ReservedFullSize, - Digest - ); - DEBUG (( - DEBUG_INFO, - "OC: Result of %a XNU hook on %s (%02X%02X%02X%02X) is %r\n", - IsKernel32Bit ? "32-bit" : "64-bit", - FileName, - Digest != NULL ? Digest[0] : 0, - Digest != NULL ? Digest[1] : 0, - Digest != NULL ? Digest[2] : 0, - Digest != NULL ? Digest[3] : 0, - Status - )); - - if (!EFI_ERROR (Status)) { - // - // 10.6 and below may keep older prelinkedkernels around, do not load those. - // - DarwinVersionNew = OcKernelReadDarwinVersion (*Kernel, *KernelSize); - if (DarwinVersionNew < *DarwinVersion) { - FreePool (*Kernel); - *Kernel = NULL; - - return EFI_INVALID_PARAMETER; - } - - // - // We should be matching the required arch if we get here, but check just in case. - // - if (mUse32BitKernel != IsKernel32Bit) { - DEBUG ((DEBUG_WARN, "OC: %a kernel architecture is not available, aborting.\n", mUse32BitKernel ? "32-bit" : "64-bit")); - FreePool (*Kernel); - *Kernel = NULL; - - return EFI_NOT_FOUND; - } - } - } - - *DarwinVersion = DarwinVersionNew; + if (mUse32BitKernel != IsKernel32Bit) { + DEBUG ((DEBUG_WARN, "OC: %a kernel architecture is not available, aborting.\n", mUse32BitKernel ? "32-bit" : "64-bit")); + FreePool (*Kernel); + *Kernel = NULL; + return EFI_NOT_FOUND; } + + *DarwinVersion = DarwinVersionNew; } return Status; @@ -1479,7 +1100,7 @@ OcKernelFileOpen ( return EFI_NOT_FOUND; } - OcKernelApplyPatches (mOcConfiguration, mOcDarwinVersion, 0, NULL, Kernel, KernelSize); + OcKernelApplyPatches (mOcConfiguration, mOcCpuInfo, mOcDarwinVersion, 0, NULL, Kernel, KernelSize); PrelinkedStatus = OcKernelProcessPrelinked ( mOcConfiguration, mOcDarwinVersion, @@ -1687,14 +1308,7 @@ OcLoadKernelSupport ( mOcCpuInfo = CpuInfo; mOcDarwinVersion = 0; mOcCachelessInProgress = FALSE; - -#if defined(MDE_CPU_IA32) - mUse32BitKernel = TRUE; -#elif defined(MDE_CPU_X64) - mUse32BitKernel = FALSE; -#else -#error "Unsupported architecture" -#endif + OcImageLoaderRegisterConfigure (OcKernelConfigureCapabilities); } else { DEBUG ((DEBUG_ERROR, "OC: Failed to enable vfs - %r\n", Status)); } @@ -1708,6 +1322,7 @@ OcUnloadKernelSupport ( EFI_STATUS Status; if (mOcStorage != NULL) { + OcImageLoaderRegisterConfigure (NULL); Status = DisableVirtualFs (gBS); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "OC: Failed to disable vfs - %r\n", Status)); diff --git a/Platform/OpenCore/OpenCoreKernelPatch.c b/Platform/OpenCore/OpenCoreKernelPatch.c new file mode 100644 index 00000000..a5ce460e --- /dev/null +++ b/Platform/OpenCore/OpenCoreKernelPatch.c @@ -0,0 +1,334 @@ +/** @file + OpenCore driver. + +Copyright (c) 2019, 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 "ProcessorBind.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +EFI_STATUS +OcKernelApplyQuirk ( + IN KERNEL_QUIRK_NAME Quirk, + IN KERNEL_CACHE_TYPE CacheType, + IN UINT32 DarwinVersion, + IN OUT VOID *Context, + IN OUT PATCHER_CONTEXT *KernelPatcher + ) +{ + // + // Apply kernel quirks to kernel, kext patches to context. + // + if (Context == NULL) { + ASSERT (KernelPatcher != NULL); + return KernelApplyQuirk (Quirk, KernelPatcher, DarwinVersion); + } + + if (CacheType == CacheTypeCacheless) { + return CachelessContextAddQuirk (Context, Quirk); + } + + if (CacheType == CacheTypeMkext) { + return MkextContextApplyQuirk (Context, Quirk, DarwinVersion); + } + + if (CacheType == CacheTypePrelinked) { + return PrelinkedContextApplyQuirk (Context, Quirk, DarwinVersion); + } + + return EFI_UNSUPPORTED; +} + +VOID +OcKernelApplyPatches ( + IN OC_GLOBAL_CONFIG *Config, + IN OC_CPU_INFO *CpuInfo, + IN UINT32 DarwinVersion, + IN KERNEL_CACHE_TYPE CacheType, + IN VOID *Context, + IN OUT UINT8 *Kernel, + IN UINT32 Size + ) +{ + EFI_STATUS Status; + PATCHER_CONTEXT KernelPatcher; + UINT32 Index; + PATCHER_GENERIC_PATCH Patch; + OC_KERNEL_PATCH_ENTRY *UserPatch; + CONST CHAR8 *Target; + CONST CHAR8 *Comment; + UINT32 MaxKernel; + UINT32 MinKernel; + BOOLEAN IsKernelPatch; + + IsKernelPatch = Context == NULL; + + if (IsKernelPatch) { + ASSERT (Kernel != NULL); + + Status = PatcherInitContextFromBuffer ( + &KernelPatcher, + Kernel, + Size + ); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "OC: Kernel patcher kernel init failure - %r\n", Status)); + return; + } + } + + for (Index = 0; Index < Config->Kernel.Patch.Count; ++Index) { + UserPatch = Config->Kernel.Patch.Values[Index]; + Target = OC_BLOB_GET (&UserPatch->Identifier); + Comment = OC_BLOB_GET (&UserPatch->Comment); + + if (!UserPatch->Enabled || (AsciiStrCmp (Target, "kernel") == 0) != IsKernelPatch) { + continue; + } + + MaxKernel = OcParseDarwinVersion (OC_BLOB_GET (&UserPatch->MaxKernel)); + MinKernel = OcParseDarwinVersion (OC_BLOB_GET (&UserPatch->MinKernel)); + + if (!OcMatchDarwinVersion (DarwinVersion, MinKernel, MaxKernel)) { + DEBUG (( + DEBUG_INFO, + "OC: Kernel patcher skips %a (%a) patch at %u due to version %u <= %u <= %u\n", + Target, + Comment, + Index, + MinKernel, + DarwinVersion, + MaxKernel + )); + continue; + } + + // + // Ignore patch if: + // - There is nothing to replace. + // - We have neither symbolic base, nor find data. + // - Find and replace mismatch in size. + // - Mask and ReplaceMask mismatch in size when are available. + // + if (UserPatch->Replace.Size == 0 + || (OC_BLOB_GET (&UserPatch->Base)[0] == '\0' && UserPatch->Find.Size != UserPatch->Replace.Size) + || (UserPatch->Mask.Size > 0 && UserPatch->Find.Size != UserPatch->Mask.Size) + || (UserPatch->ReplaceMask.Size > 0 && UserPatch->Find.Size != UserPatch->ReplaceMask.Size)) { + DEBUG ((DEBUG_ERROR, "OC: Kernel patch %u for %a (%a) is borked\n", Index, Target, Comment)); + continue; + } + + ZeroMem (&Patch, sizeof (Patch)); + + if (OC_BLOB_GET (&UserPatch->Comment)[0] != '\0') { + Patch.Comment = OC_BLOB_GET (&UserPatch->Comment); + } + + if (OC_BLOB_GET (&UserPatch->Base)[0] != '\0') { + Patch.Base = OC_BLOB_GET (&UserPatch->Base); + } + + if (UserPatch->Find.Size > 0) { + Patch.Find = OC_BLOB_GET (&UserPatch->Find); + } + + Patch.Replace = OC_BLOB_GET (&UserPatch->Replace); + + if (UserPatch->Mask.Size > 0) { + Patch.Mask = OC_BLOB_GET (&UserPatch->Mask); + } + + if (UserPatch->ReplaceMask.Size > 0) { + Patch.ReplaceMask = OC_BLOB_GET (&UserPatch->ReplaceMask); + } + + Patch.Size = UserPatch->Replace.Size; + Patch.Count = UserPatch->Count; + Patch.Skip = UserPatch->Skip; + Patch.Limit = UserPatch->Limit; + + if (IsKernelPatch) { + Status = PatcherApplyGenericPatch (&KernelPatcher, &Patch); + } else { + if (CacheType == CacheTypeCacheless) { + Status = CachelessContextAddPatch (Context, Target, &Patch); + } else if (CacheType == CacheTypeMkext) { + Status = MkextContextApplyPatch (Context, Target, &Patch); + } else if (CacheType == CacheTypePrelinked) { + Status = PrelinkedContextApplyPatch (Context, Target, &Patch); + } + } + + DEBUG (( + EFI_ERROR (Status) ? DEBUG_WARN : DEBUG_INFO, + "OC: Kernel patcher result %u for %a (%a) - %r\n", + Index, + Target, + Comment, + Status + )); + } + + if (!IsKernelPatch) { + if (Config->Kernel.Quirks.AppleCpuPmCfgLock) { + OcKernelApplyQuirk (KernelQuirkAppleCpuPmCfgLock, CacheType, DarwinVersion, Context, NULL); + } + + if (Config->Kernel.Quirks.ExternalDiskIcons) { + OcKernelApplyQuirk (KernelQuirkExternalDiskIcons, CacheType, DarwinVersion, Context, NULL); + } + + if (Config->Kernel.Quirks.ThirdPartyDrives) { + OcKernelApplyQuirk (KernelQuirkThirdPartyDrives, CacheType, DarwinVersion, Context, NULL); + } + + if (Config->Kernel.Quirks.XhciPortLimit) { + OcKernelApplyQuirk (KernelQuirkXhciPortLimit1, CacheType, DarwinVersion, Context, NULL); + OcKernelApplyQuirk (KernelQuirkXhciPortLimit2, CacheType, DarwinVersion, Context, NULL); + OcKernelApplyQuirk (KernelQuirkXhciPortLimit3, CacheType, DarwinVersion, Context, NULL); + } + + if (Config->Kernel.Quirks.DisableIoMapper) { + OcKernelApplyQuirk (KernelQuirkDisableIoMapper, CacheType, DarwinVersion, Context, NULL); + } + + if (Config->Kernel.Quirks.DisableRtcChecksum) { + OcKernelApplyQuirk (KernelQuirkDisableRtcChecksum, CacheType, DarwinVersion, Context, NULL); + } + + if (Config->Kernel.Quirks.IncreasePciBarSize) { + OcKernelApplyQuirk (KernelQuirkIncreasePciBarSize, CacheType, DarwinVersion, Context, NULL); + } + + if (Config->Kernel.Quirks.CustomSmbiosGuid) { + OcKernelApplyQuirk (KernelQuirkCustomSmbiosGuid1, CacheType, DarwinVersion, Context, NULL); + OcKernelApplyQuirk (KernelQuirkCustomSmbiosGuid2, CacheType, DarwinVersion, Context, NULL); + } + + if (Config->Kernel.Quirks.DummyPowerManagement) { + OcKernelApplyQuirk (KernelQuirkDummyPowerManagement, CacheType, DarwinVersion, Context, NULL); + } + } else { + if (Config->Kernel.Quirks.AppleXcpmCfgLock) { + OcKernelApplyQuirk (KernelQuirkAppleXcpmCfgLock, CacheType, DarwinVersion, NULL, &KernelPatcher); + } + + if (Config->Kernel.Quirks.AppleXcpmExtraMsrs) { + OcKernelApplyQuirk (KernelQuirkAppleXcpmExtraMsrs, CacheType, DarwinVersion, NULL, &KernelPatcher); + } + + if (Config->Kernel.Quirks.AppleXcpmForceBoost) { + OcKernelApplyQuirk (KernelQuirkAppleXcpmForceBoost, CacheType, DarwinVersion, NULL, &KernelPatcher); + } + + if (Config->Kernel.Quirks.PanicNoKextDump) { + OcKernelApplyQuirk (KernelQuirkPanicNoKextDump, CacheType, DarwinVersion, NULL, &KernelPatcher); + } + + if (Config->Kernel.Emulate.Cpuid1Data[0] != 0 + || Config->Kernel.Emulate.Cpuid1Data[1] != 0 + || Config->Kernel.Emulate.Cpuid1Data[2] != 0 + || Config->Kernel.Emulate.Cpuid1Data[3] != 0) { + PatchKernelCpuId ( + &KernelPatcher, + CpuInfo, + Config->Kernel.Emulate.Cpuid1Data, + Config->Kernel.Emulate.Cpuid1Mask + ); + } + + if (Config->Kernel.Quirks.LapicKernelPanic) { + OcKernelApplyQuirk (KernelQuirkLapicKernelPanic, CacheType, DarwinVersion, NULL, &KernelPatcher); + } + + if (Config->Kernel.Quirks.PowerTimeoutKernelPanic) { + OcKernelApplyQuirk (KernelQuirkPowerTimeoutKernelPanic, CacheType, DarwinVersion, NULL, &KernelPatcher); + } + } +} + +VOID +OcKernelBlockKexts ( + IN OC_GLOBAL_CONFIG *Config, + IN UINT32 DarwinVersion, + IN PRELINKED_CONTEXT *Context + ) +{ + EFI_STATUS Status; + PATCHER_CONTEXT Patcher; + UINT32 Index; + OC_KERNEL_BLOCK_ENTRY *Kext; + CONST CHAR8 *Target; + CONST CHAR8 *Comment; + UINT32 MaxKernel; + UINT32 MinKernel; + + for (Index = 0; Index < Config->Kernel.Block.Count; ++Index) { + Kext = Config->Kernel.Block.Values[Index]; + Target = OC_BLOB_GET (&Kext->Identifier); + Comment = OC_BLOB_GET (&Kext->Comment); + + if (!Kext->Enabled) { + continue; + } + + MaxKernel = OcParseDarwinVersion (OC_BLOB_GET (&Kext->MaxKernel)); + MinKernel = OcParseDarwinVersion (OC_BLOB_GET (&Kext->MinKernel)); + + if (!OcMatchDarwinVersion (DarwinVersion, MinKernel, MaxKernel)) { + DEBUG (( + DEBUG_INFO, + "OC: Prelink blocker skips %a (%a) block at %u due to version %u <= %u <= %u\n", + Target, + Comment, + Index, + MinKernel, + DarwinVersion, + MaxKernel + )); + continue; + } + + Status = PatcherInitContextFromPrelinked ( + &Patcher, + Context, + Target + ); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_WARN, "OC: Prelink blocker %a (%a) init failure - %r\n", Target, Comment, Status)); + continue; + } + + Status = PatcherBlockKext (&Patcher); + + DEBUG (( + EFI_ERROR (Status) ? DEBUG_WARN : DEBUG_INFO, + "OC: Prelink blocker %a (%a) - %r\n", + Target, + Comment, + Status + )); + } +}