From 081bb56dd062356df72d93f1d98206c036c4ab17 Mon Sep 17 00:00:00 2001 From: Mykola Grymalyuk <48863253+khronokernel@users.noreply.github.com> Date: Mon, 12 Jul 2021 19:13:30 -0600 Subject: [PATCH] Add backend to support latebloom Kext currently not enabled until ready for mass community usage --- OpenCore-Patcher.command | 26 ++++++++++--------- Resources/Build.py | 5 ++++ Resources/Constants.py | 9 +++++++ Resources/ModelArray.py | 33 +++++++++++++++++++++++- Resources/Utilities.py | 22 ++++++++++++++++ payloads/Config/config.plist | 20 +++++++++++++- payloads/Kexts/Misc/latebloom-v0.17.zip | Bin 0 -> 14385 bytes 7 files changed, 101 insertions(+), 14 deletions(-) create mode 100644 payloads/Kexts/Misc/latebloom-v0.17.zip diff --git a/OpenCore-Patcher.command b/OpenCore-Patcher.command index 6edeb2a7a..f33f35da3 100755 --- a/OpenCore-Patcher.command +++ b/OpenCore-Patcher.command @@ -19,18 +19,6 @@ class OpenCoreLegacyPatcher: self.constants.detected_os = int(platform.uname().release.partition(".")[0]) self.set_defaults(self.computer.real_model, True) - custom_cpu_model_value = Utilities.get_nvram("revcpuname", "4D1FDA02-38C7-4A6A-9CC6-4BCCA8B30102", decode=True) - if custom_cpu_model_value is not None: - # TODO: Fix to not use two separate variables - self.constants.custom_cpu_model = 1 - self.constants.custom_cpu_model_value = custom_cpu_model_value.split("%00")[0] - - if "-v" in (Utilities.get_nvram("boot-args") or ""): - self.constants.verbose_debug = True - - # Check if running in RecoveryOS - self.constants.recovery_status = Utilities.check_recovery() - def set_defaults(self, model, host_is_target): # Defaults self.constants.sip_status = True @@ -72,6 +60,20 @@ class OpenCoreLegacyPatcher: # MacBook8,1 has an odd bug where it cannot install Monterey with Minimal spoofing self.constants.serial_settings == "Moderate" + custom_cpu_model_value = Utilities.get_nvram("revcpuname", "4D1FDA02-38C7-4A6A-9CC6-4BCCA8B30102", decode=True) + if custom_cpu_model_value is not None: + # TODO: Fix to not use two separate variables + self.constants.custom_cpu_model = 1 + self.constants.custom_cpu_model_value = custom_cpu_model_value.split("%00")[0] + + if "-v" in (Utilities.get_nvram("boot-args") or ""): + self.constants.verbose_debug = True + + self.constants.latebloom_delay, self.constants.latebloom_range, self.constants.latebloom_debug = Utilities.latebloom_detection(model) + + # Check if running in RecoveryOS + self.constants.recovery_status = Utilities.check_recovery() + def build_opencore(self): Build.BuildOpenCore(self.constants.custom_model or self.constants.computer.real_model, self.constants).build_opencore() diff --git a/Resources/Build.py b/Resources/Build.py index 0cb695d6b..7c9c3ad2e 100644 --- a/Resources/Build.py +++ b/Resources/Build.py @@ -189,12 +189,17 @@ class BuildOpenCore: # Misc ("FeatureUnlock.kext", self.constants.featureunlock_version, self.constants.featureunlock_path, lambda: self.model in ModelArray.SidecarPatch), ("DebugEnhancer.kext", self.constants.debugenhancer_version, self.constants.debugenhancer_path, lambda: self.constants.kext_debug is True), + #("latebloom.kext", self.constants.latebloom_version, self.constants.latebloom_path, lambda: self.model in ModelArray.PCIRaceCondition), ]: self.enable_kext(name, version, path, check) if self.constants.allow_oc_everywhere is False: self.get_item_by_kv(self.config["Kernel"]["Patch"], "Identifier", "com.apple.driver.AppleSMC")["Enabled"] = True + if self.get_kext_by_bundle_path("latebloom.kext")["Enabled"] is True: + print(f"Setting latebloom delay of {self.constants.latebloom_delay}, range {self.constants.latebloom_range}, debug {self.constants.latebloom_debug}") + self.config["NVRAM"]["Add"]["7C436110-AB2A-4BBB-A880-FE41995C9F82"]["boot-args"] += f" latebloom={self.constants.latebloom_delay}, lb_range={self.constants.latebloom_range}, lb_debug={self.constants.latebloom_debug}" + if not self.constants.custom_model and (self.constants.allow_oc_everywhere is True or self.model in ModelArray.MacPro71): # Use Innie's same logic: # https://github.com/cdf/Innie/blob/v1.3.0/Innie/Innie.cpp#L90-L97 diff --git a/Resources/Constants.py b/Resources/Constants.py index 67576e55b..a87d0f730 100644 --- a/Resources/Constants.py +++ b/Resources/Constants.py @@ -42,6 +42,7 @@ class Constants: self.debugenhancer_version = "1.0.3" self.innie_version = "1.3.0" self.fw_kext = "1.0.0" + self.latebloom_version = "0.17" self.disk = "" self.patch_disk = "" self.patcher_support_pkg_version = "0.0.13" # PatcherSupportPkg @@ -90,6 +91,10 @@ class Constants: self.enable_wake_on_wlan = False self.allow_ivy_igpu = False self.moj_cat_accel = False + self.latebloom_status = False + self.latebloom_delay = 0 + self.latebloom_range = 0 + self.latebloom_debug = 0 # OS Versions self.tiger = 8 @@ -284,6 +289,10 @@ class Constants: @property def innie_path(self): return self.payload_kexts_path / Path(f"Misc/Innie-v{self.innie_version}.zip") + + @property + def latebloom_path(self): + return self.payload_kexts_path / Path(f"Misc/latebloom-v{self.latebloom_version}.zip") @property def plist_folder_path(self): diff --git a/Resources/ModelArray.py b/Resources/ModelArray.py index b8f3b68f5..6009b509e 100644 --- a/Resources/ModelArray.py +++ b/Resources/ModelArray.py @@ -994,4 +994,35 @@ NoFireWireSupport = [ "MacBookAir3,2", ] -RecoveryIgnore = ["Update", "VM", "Recovery", "Preboot"] +PCIRaceCondition = [ + "MacBook4,1", + "MacBook5,1", + "MacBook5,2", + "MacBook6,1", + "MacBook7,1", + "MacBookAir2,1", + "MacBookAir3,1", + "MacBookAir3,2", + "MacBookPro4,1", + "MacBookPro5,1", + "MacBookPro5,2", + "MacBookPro5,3", + "MacBookPro5,4", + "MacBookPro5,5", + "MacBookPro6,1", + "MacBookPro6,2", + "MacBookPro7,1", + "Macmini3,1", + "Macmini4,1", + "Macmini5,1", + "Macmini5,2", + "Macmini5,3", + "iMac7,1", + "iMac8,1", + "iMac9,1", + "iMac10,1", + "iMac11,1", + "iMac11,2", + "iMac11,3", + "Dortania1,1", +] \ No newline at end of file diff --git a/Resources/Utilities.py b/Resources/Utilities.py index 3fa454cff..24ca2b3a2 100644 --- a/Resources/Utilities.py +++ b/Resources/Utilities.py @@ -7,6 +7,7 @@ import os import plistlib import subprocess from pathlib import Path +import re import requests @@ -49,6 +50,27 @@ def get_disk_path(): return root_mount_path +def latebloom_detection(model): + if model in ["MacPro4,1", "MacPro5,1", "iMac7,1", "iMac8,1"]: + # These machines are more likely to experience boot hangs, increase delays to accomodate + lb_delay = "250" + else: + lb_delay = "100" + lb_range = "1" + lb_debug = "0" + if get_nvram("boot-args", decode=False): + if "latebloom=" in get_nvram("boot-args", decode=False): + lb_delay = re.search(r"(?:[, ])latebloom=(\d+)", get_nvram("boot-args", decode=False)) + lb_delay = lb_delay[1] + if "lb_range=" in get_nvram("boot-args", decode=False): + lb_range = re.search(r"(?:[, ])lb_range=(\d+)", get_nvram("boot-args", decode=False)) + lb_range = lb_range[1] + if "lb_debug=" in get_nvram("boot-args", decode=False): + lb_debug = re.search(r"(?:[, ])lb_debug=(\d+)", get_nvram("boot-args", decode=False)) + lb_debug = lb_debug[1] + return int(lb_range), int(lb_range), int(lb_debug) + + def csr_decode(csr_active_config, os_sip): if csr_active_config is None: csr_active_config = b"\x00\x00\x00\x00" diff --git a/payloads/Config/config.plist b/payloads/Config/config.plist index dda43d9c7..de93fff23 100644 --- a/payloads/Config/config.plist +++ b/payloads/Config/config.plist @@ -940,7 +940,7 @@ BundlePath DebugEnhancer.kext Comment - + Enhance DEBUG output in system logs Enabled ExecutablePath @@ -952,6 +952,24 @@ PlistPath Contents/Info.plist + + Arch + x86_64 + BundlePath + latebloom.kext + Comment + Work-around PCI race condition + Enabled + + ExecutablePath + Contents/MacOS/latebloom + MaxKernel + + MinKernel + 20.4.0 + PlistPath + Contents/Info.plist + Block diff --git a/payloads/Kexts/Misc/latebloom-v0.17.zip b/payloads/Kexts/Misc/latebloom-v0.17.zip new file mode 100644 index 0000000000000000000000000000000000000000..62f88be2f18dc1102e75c12de589627680e908d9 GIT binary patch literal 14385 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