mirror of
https://github.com/dortania/OpenCore-Legacy-Patcher.git
synced 2026-04-14 04:38:20 +10:00
270 lines
10 KiB
Python
270 lines
10 KiB
Python
# Additional support functions for sys_patch.py
|
|
# Copyright (C) 2020-2023, Dhinak G, Mykola Grymalyuk
|
|
|
|
import plistlib
|
|
import os
|
|
import logging
|
|
import subprocess
|
|
|
|
from typing import Union
|
|
from pathlib import Path
|
|
from datetime import datetime
|
|
|
|
from data import os_data
|
|
from resources import bplist, constants, generate_smbios, utilities
|
|
|
|
|
|
class SysPatchHelpers:
|
|
"""
|
|
Library of helper functions for sys_patch.py and related libraries
|
|
"""
|
|
|
|
def __init__(self, global_constants: constants.Constants):
|
|
self.constants: constants.Constants = global_constants
|
|
|
|
|
|
def snb_board_id_patch(self, source_files_path: str):
|
|
"""
|
|
Patch AppleIntelSNBGraphicsFB.kext to support unsupported Board IDs
|
|
|
|
AppleIntelSNBGraphicsFB hard codes the supported Board IDs for Sandy Bridge iGPUs
|
|
Because of this, the kext errors out on unsupported systems
|
|
This function simply patches in a supported Board ID, using 'determine_best_board_id_for_sandy()'
|
|
to supplement the ideal Board ID
|
|
|
|
Parameters:
|
|
source_files_path (str): Path to the source files
|
|
|
|
"""
|
|
|
|
source_files_path = str(source_files_path)
|
|
|
|
if self.constants.computer.reported_board_id in self.constants.sandy_board_id_stock:
|
|
return
|
|
|
|
logging.info(f"- Found unsupported Board ID {self.constants.computer.reported_board_id}, performing AppleIntelSNBGraphicsFB bin patching")
|
|
|
|
board_to_patch = generate_smbios.determine_best_board_id_for_sandy(self.constants.computer.reported_board_id, self.constants.computer.gpus)
|
|
logging.info(f"- Replacing {board_to_patch} with {self.constants.computer.reported_board_id}")
|
|
|
|
board_to_patch_hex = bytes.fromhex(board_to_patch.encode('utf-8').hex())
|
|
reported_board_hex = bytes.fromhex(self.constants.computer.reported_board_id.encode('utf-8').hex())
|
|
|
|
if len(board_to_patch_hex) > len(reported_board_hex):
|
|
# Pad the reported Board ID with zeros to match the length of the board to patch
|
|
reported_board_hex = reported_board_hex + bytes(len(board_to_patch_hex) - len(reported_board_hex))
|
|
elif len(board_to_patch_hex) < len(reported_board_hex):
|
|
logging.info(f"- Error: Board ID {self.constants.computer.reported_board_id} is longer than {board_to_patch}")
|
|
raise Exception("Host's Board ID is longer than the kext's Board ID, cannot patch!!!")
|
|
|
|
path = source_files_path + "/10.13.6/System/Library/Extensions/AppleIntelSNBGraphicsFB.kext/Contents/MacOS/AppleIntelSNBGraphicsFB"
|
|
if not Path(path).exists():
|
|
logging.info(f"- Error: Could not find {path}")
|
|
raise Exception("Failed to find AppleIntelSNBGraphicsFB.kext, cannot patch!!!")
|
|
|
|
with open(path, 'rb') as f:
|
|
data = f.read()
|
|
data = data.replace(board_to_patch_hex, reported_board_hex)
|
|
with open(path, 'wb') as f:
|
|
f.write(data)
|
|
|
|
|
|
def generate_patchset_plist(self, patchset: dict, file_name: str, kdk_used: Path):
|
|
"""
|
|
Generate patchset file for user reference
|
|
|
|
Parameters:
|
|
patchset (dict): Dictionary of patchset, see sys_patch_detect.py and sys_patch_dict.py
|
|
file_name (str): Name of the file to write to
|
|
kdk_used (Path): Path to the KDK used, if any
|
|
|
|
Returns:
|
|
bool: True if successful, False if not
|
|
|
|
"""
|
|
|
|
source_path = f"{self.constants.payload_path}"
|
|
source_path_file = f"{source_path}/{file_name}"
|
|
|
|
kdk_string = "Not applicable"
|
|
if kdk_used:
|
|
kdk_string = kdk_used
|
|
|
|
data = {
|
|
"OpenCore Legacy Patcher": f"v{self.constants.patcher_version}",
|
|
"PatcherSupportPkg": f"v{self.constants.patcher_support_pkg_version}",
|
|
"Time Patched": f"{datetime.now().strftime('%B %d, %Y @ %H:%M:%S')}",
|
|
"Commit URL": f"{self.constants.commit_info[2]}",
|
|
"Kernel Debug Kit Used": f"{kdk_string}",
|
|
"OS Version": f"{self.constants.detected_os}.{self.constants.detected_os_minor} ({self.constants.detected_os_build})",
|
|
}
|
|
|
|
data.update(patchset)
|
|
|
|
if Path(source_path_file).exists():
|
|
os.remove(source_path_file)
|
|
|
|
# Need to write to a safe location
|
|
plistlib.dump(data, Path(source_path_file).open("wb"), sort_keys=False)
|
|
|
|
if Path(source_path_file).exists():
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
def disable_window_server_caching(self):
|
|
"""
|
|
Disable WindowServer's asset caching
|
|
|
|
On legacy GCN GPUs, the WindowServer cache generated creates
|
|
corrupted Opaque shaders.
|
|
|
|
To work-around this, we disable WindowServer caching
|
|
And force macOS into properly generating the Opaque shaders
|
|
"""
|
|
|
|
if self.constants.detected_os < os_data.os_data.ventura:
|
|
return
|
|
|
|
logging.info("- Disabling WindowServer Caching")
|
|
# Invoke via 'bash -c' to resolve pathing
|
|
utilities.elevated(["bash", "-c", "rm -rf /private/var/folders/*/*/*/WindowServer/com.apple.WindowServer"])
|
|
# Disable writing to WindowServer folder
|
|
utilities.elevated(["bash", "-c", "chflags uchg /private/var/folders/*/*/*/WindowServer"])
|
|
# Reference:
|
|
# To reverse write lock:
|
|
# 'chflags nouchg /private/var/folders/*/*/*/WindowServer'
|
|
|
|
|
|
def remove_news_widgets(self):
|
|
"""
|
|
Remove News Widgets from Notification Centre
|
|
|
|
On Ivy Bridge and Haswell iGPUs, RenderBox will crash the News Widgets in
|
|
Notification Centre. To ensure users can access Notifications normally,
|
|
we manually remove all News Widgets
|
|
"""
|
|
|
|
if self.constants.detected_os < os_data.os_data.ventura:
|
|
return
|
|
|
|
logging.info("- Parsing Notification Centre Widgets")
|
|
file_path = "~/Library/Containers/com.apple.notificationcenterui/Data/Library/Preferences/com.apple.notificationcenterui.plist"
|
|
file_path = Path(file_path).expanduser()
|
|
|
|
if not file_path.exists():
|
|
logging.info(" - Defaults file not found, skipping")
|
|
return
|
|
|
|
did_find = False
|
|
with open(file_path, "rb") as f:
|
|
data = plistlib.load(f)
|
|
if "widgets" not in data:
|
|
return
|
|
|
|
if "instances" not in data["widgets"]:
|
|
return
|
|
|
|
for widget in list(data["widgets"]["instances"]):
|
|
widget_data = bplist.BPListReader(widget).parse()
|
|
for entry in widget_data:
|
|
if 'widget' not in entry:
|
|
continue
|
|
sub_data = bplist.BPListReader(widget_data[entry]).parse()
|
|
for sub_entry in sub_data:
|
|
if not '$object' in sub_entry:
|
|
continue
|
|
if not b'com.apple.news' in sub_data[sub_entry][2]:
|
|
continue
|
|
logging.info(f" - Found News Widget to remove: {sub_data[sub_entry][2].decode('ascii')}")
|
|
data["widgets"]["instances"].remove(widget)
|
|
did_find = True
|
|
|
|
if did_find:
|
|
with open(file_path, "wb") as f:
|
|
plistlib.dump(data, f, sort_keys=False)
|
|
subprocess.run(["killall", "NotificationCenter"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
|
|
|
|
|
def install_rsr_repair_binary(self):
|
|
"""
|
|
Installs RSRRepair
|
|
|
|
RSRRepair is a utility that will sync the SysKC and BootKC in the event of a panic
|
|
|
|
With macOS 13.2, Apple implemented the Rapid Security Response System
|
|
However Apple added a half baked snapshot reversion system if seal was broken,
|
|
which forgets to handle Preboot BootKC syncing.
|
|
|
|
Thus this application will try to re-sync the BootKC with SysKC in the event of a panic
|
|
Reference: https://github.com/dortania/OpenCore-Legacy-Patcher/issues/1019
|
|
|
|
This is a (hopefully) temporary work-around, however likely to stay.
|
|
RSRRepair has the added bonus of fixing desynced KCs from 'bless', so useful in Big Sur+
|
|
Source: https://github.com/flagersgit/RSRRepair
|
|
|
|
"""
|
|
|
|
if self.constants.detected_os < os_data.os_data.big_sur:
|
|
return
|
|
|
|
logging.info("- Installing Kernel Collection syncing utility")
|
|
result = utilities.elevated([self.constants.rsrrepair_userspace_path, "--install"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
|
if result.returncode != 0:
|
|
logging.info(f" - Failed to install RSRRepair: {result.stdout.decode()}")
|
|
|
|
|
|
def patch_gpu_compiler_libraries(self, mount_point: Union[str, Path]):
|
|
"""
|
|
Fix GPUCompiler.framework's libraries to resolve linking issues
|
|
|
|
On 13.3 with 3802 GPUs, OCLP will downgrade GPUCompiler to resolve
|
|
graphics support. However the binary hardcodes the library names,
|
|
and thus we need to adjust the libraries to match (31001.669)
|
|
|
|
Important portions of the library will be downgraded to 31001.669,
|
|
and the remaining bins will be copied over (via CoW to reduce waste)
|
|
|
|
Primary folders to merge:
|
|
- 31001.XXX: (current OS version)
|
|
- include:
|
|
- module.modulemap
|
|
- opencl-c.h
|
|
- lib (entire directory)
|
|
|
|
Parameters:
|
|
mount_point: The mount point of the target volume
|
|
"""
|
|
|
|
if self.constants.detected_os < os_data.os_data.ventura:
|
|
return
|
|
if self.constants.detected_os == os_data.os_data.ventura:
|
|
if self.constants.detected_os_minor < 4:
|
|
return
|
|
|
|
LIBRARY_DIR = f"{mount_point}/System/Library/PrivateFrameworks/GPUCompiler.framework/Versions/31001/Libraries/lib/clang"
|
|
GPU_VERSION = "31001.669"
|
|
|
|
DEST_DIR = f"{LIBRARY_DIR}/{GPU_VERSION}"
|
|
|
|
if not Path(DEST_DIR).exists():
|
|
return
|
|
|
|
for file in Path(LIBRARY_DIR).iterdir():
|
|
if file.is_file():
|
|
continue
|
|
if file.name == GPU_VERSION:
|
|
continue
|
|
|
|
# Partial match as each OS can increment the version
|
|
if not file.name.startswith("31001."):
|
|
continue
|
|
|
|
logging.info(f"- Merging GPUCompiler.framework libraries to match binary")
|
|
|
|
src_dir = f"{LIBRARY_DIR}/{file.name}"
|
|
if not Path(f"{DEST_DIR}/lib").exists():
|
|
utilities.process_status(utilities.elevated(["cp", "-cR", f"{src_dir}/lib", f"{DEST_DIR}/"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
|
|
|
|
break |