Files
OpenCore-Legacy-Patcher/OpenCore-Patcher.command
Mykola Grymalyuk b2fcb77c24 Fix more typos
2021-04-25 00:37:17 -06:00

210 lines
12 KiB
Bash
Executable File

#!/usr/bin/env python3
# Copyright (C) 2020-2021, Dhinak G, Mykola Grymalyuk
from __future__ import print_function
import binascii
import plistlib
import subprocess
import sys
import time
import platform
from Resources import Build, ModelArray, Constants, SysPatch, Utilities, CliMenu
class OpenCoreLegacyPatcher():
def __init__(self):
self.constants = Constants.Constants()
self.current_model: str = None
opencore_model: str = subprocess.run("nvram 4D1FDA02-38C7-4A6A-9CC6-4BCCA8B30102:oem-product".split(), stdout=subprocess.PIPE, stderr=subprocess.STDOUT).stdout.decode()
if not opencore_model.startswith("nvram: Error getting variable"):
opencore_model = [line.strip().split(":oem-product ", 1)[1] for line in opencore_model.split("\n") if line.strip().startswith("4D1FDA02-38C7-4A6A-9CC6-4BCCA8B30102:")][0]
self.current_model = opencore_model
else:
self.current_model = subprocess.run("system_profiler SPHardwareDataType".split(), stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
self.current_model = [line.strip().split(": ", 1)[1] for line in self.current_model.stdout.decode().split("\n") if line.strip().startswith("Model Identifier")][0]
self.constants.detected_os = int(platform.uname().release.partition(".")[0])
if self.current_model in ModelArray.NoAPFSsupport:
self.constants.serial_settings = "Moderate"
if self.current_model in ModelArray.LegacyGPU:
try:
dgpu_devices = plistlib.loads(subprocess.run("ioreg -r -n GFX0 -a".split(), stdout=subprocess.PIPE).stdout.decode().strip().encode())
dgpu_vendor = self.hexswap(binascii.hexlify(dgpu_devices[0]["vendor-id"]).decode()[:4])
dgpu_device = self.hexswap(binascii.hexlify(dgpu_devices[0]["device-id"]).decode()[:4])
except ValueError:
dgpu_vendor = ""
dgpu_device = ""
if (dgpu_vendor == self.constants.pci_amd_ati and dgpu_device in ModelArray.AMDMXMGPUs) or (dgpu_vendor == self.constants.pci_nvidia and dgpu_device in ModelArray.NVIDIAMXMGPUs):
self.constants.sip_status = True
self.constants.secure_status = True
else:
self.constants.sip_status = False
self.constants.secure_status = False
# Logic for when user runs custom OpenCore build and do not expose it
# Note: This logic currently only applies for iMacPro1,1 users, see below threads on the culprits:
# - https://forums.macrumors.com/threads/2011-imac-graphics-card-upgrade.1596614/post-17425857
# - https://forums.macrumors.com/threads/opencore-on-the-mac-pro.2207814/
# PLEASE FOR THE LOVE OF GOD JUST SET ExposeSensitiveData CORRECTLY!!!
if self.current_model == "iMacPro1,1":
serial: str = subprocess.run("system_profiler SPHardwareDataType | grep Serial".split(), stdout=subprocess.PIPE, stderr=subprocess.STDOUT).stdout.decode()
serial = [line.strip().split("Number (system): ", 1)[1] for line in serial.split("\n") if line.strip().startswith("Serial")][0]
true_model = subprocess.run([str(self.constants.macserial_path), "--info", str(serial)], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
true_model = [i.partition(" - ")[2] for i in true_model.stdout.decode().split("\n") if "Model: " in i][0]
print(f"True Model: {true_model}")
if not true_model.startswith("Unknown"):
self.current_model = true_model
def hexswap(self, input_hex: str):
hex_pairs = [input_hex[i:i + 2] for i in range(0, len(input_hex), 2)]
hex_rev = hex_pairs[::-1]
hex_str = "".join(["".join(x) for x in hex_rev])
return hex_str.upper()
def build_opencore(self):
Build.BuildOpenCore(self.constants.custom_model or self.current_model, self.constants).build_opencore()
def install_opencore(self):
Build.BuildOpenCore(self.constants.custom_model or self.current_model, self.constants).copy_efi()
def change_model(self):
Utilities.cls()
Utilities.header(["Select Different Model"])
print("""
Tip: Run the following command on the target machine to find the model identifier:
system_profiler SPHardwareDataType | grep 'Model Identifier'
""")
self.constants.custom_model = input("Please enter the model identifier of the target machine: ").strip()
if self.constants.custom_model not in ModelArray.SupportedSMBIOS:
print(f"""
{self.constants.custom_model} is not a valid SMBIOS Identifier for macOS {self.constants.os_support}!
""")
print_models = input(f"Print list of valid options for macOS {self.constants.os_support}? (y/n)")
if print_models in {"y", "Y", "yes", "Yes"}:
print("\n".join(ModelArray.SupportedSMBIOS))
input("Press any key to continue...")
if self.constants.custom_model in ModelArray.NoAPFSsupport:
self.constants.serial_settings = "Moderate"
def patcher_settings(self):
response = None
while not (response and response == -1):
title = [
"Adjust Patcher Settings"
]
menu = Utilities.TUIMenu(title, "Please select an option: ", auto_number=True, top_level=True)
options = [
# TODO: Enable setting OS target when more OSes become supported by the patcher
#[f"Change OS version:\t\t\tCurrently macOS {self.constants.os_support}", self.change_os],
[f"Enable Verbose Mode:\t\tCurrently {self.constants.verbose_debug}", CliMenu.MenuOptions(self.constants.custom_model or self.current_model, self.constants).change_verbose],
[f"Enable OpenCore DEBUG:\t\tCurrently {self.constants.opencore_debug}", CliMenu.MenuOptions(self.constants.custom_model or self.current_model, self.constants).change_oc],
[f"Enable Kext DEBUG:\t\t\tCurrently {self.constants.kext_debug}", CliMenu.MenuOptions(self.constants.custom_model or self.current_model, self.constants).change_kext],
[f"Force iMac Metal Patch:\t\tCurrently {self.constants.imac_vendor}", CliMenu.MenuOptions(self.constants.custom_model or self.current_model, self.constants).change_metal],
[f"Assume Upgraded Wifi Always:\tCurrently {self.constants.wifi_build}", CliMenu.MenuOptions(self.constants.custom_model or self.current_model, self.constants).change_wifi],
[f"Set ShowPicker Mode:\t\tCurrently {self.constants.showpicker}", CliMenu.MenuOptions(self.constants.custom_model or self.current_model, self.constants).change_showpicker],
[f"Set Vault Mode:\t\t\tCurrently {self.constants.vault}", CliMenu.MenuOptions(self.constants.custom_model or self.current_model, self.constants).change_vault],
[f"Set SIP and SecureBootModel:\tSIP: {self.constants.sip_status} SBM: {self.constants.secure_status}", CliMenu.MenuOptions(self.constants.custom_model or self.current_model, self.constants).change_sip],
[f"Set SMBIOS Mode:\t\t\tCurrently {self.constants.serial_settings}", CliMenu.MenuOptions(self.constants.custom_model or self.current_model, self.constants).change_serial],
[f"DRM Preferences:\t\t\tCurrently {self.constants.drm_support}", CliMenu.MenuOptions(self.constants.custom_model or self.current_model, self.constants).drm_setting],
[f"Set Generic Bootstrap:\t\t{self.constants.boot_efi}", CliMenu.MenuOptions(self.constants.custom_model or self.current_model, self.constants).bootstrap_setting],
[f"Set Acceleration Patches:\t\t{self.constants.legacy_acceleration_patch}", CliMenu.MenuOptions(self.constants.custom_model or self.current_model, self.constants).accel_setting],
[f"Assume Legacy GPU:\t\t\t{self.constants.assume_legacy}", CliMenu.MenuOptions(self.constants.custom_model or self.current_model, self.constants).force_accel_setting],
]
for option in options:
menu.add_menu_option(option[0], function=option[1])
response = menu.start()
def credits(self):
Utilities.TUIOnlyPrint(["Credits"], "Press [Enter] to go back.\n",
["""Many thanks to the following:
- Acidanthera:\tOpenCore, kexts and other tools
- Khronokernel:\tWriting and maintaining this patcher
- DhinakG:\t\tWriting and maintaining this patcher
- ASentientBot:\tLegacy Acceleration Patches
- Ausdauersportler:\tLinking fixes for SNBGraphicsFB and AMDX3000
- Syncretic:\t\tAAAMouSSE and telemetrap
- cdf:\t\tNightShiftEnabler"""]).start()
def PatchVolume(self):
Utilities.cls()
Utilities.header(["Patching System Volume"])
print("""Patches Root volume to fix misc issues such as:
- Brightness control for non-Metal GPUs
WARNING: Root Volume Patching is still in active development, please
have all important user data backed up. Note when the system volume
is patched, you can no longer have Delta updates or have FileVault
enabled.
Supported Options:
1. Patch System Volume
2. Unpatch System Volume (Experimental)
B. Exit
""")
change_menu = input("Patch System Volume?: ")
if change_menu == "1":
SysPatch.PatchSysVolume(self.constants.custom_model or self.current_model, self.constants).start_patch()
elif change_menu == "2":
SysPatch.PatchSysVolume(self.constants.custom_model or self.current_model, self.constants).start_unpatch()
else:
print("Returning to main menu")
def main_menu(self):
response = None
ModelArray.SupportedSMBIOS = ModelArray.SupportedSMBIOS11
while not (response and response == -1):
title = [
f"OpenCore Legacy Patcher v{self.constants.patcher_version}",
f"Selected Model: {self.constants.custom_model or self.current_model}",
f"Target OS: macOS {self.constants.os_support}",
]
if (self.constants.custom_model or self.current_model) not in ModelArray.SupportedSMBIOS:
in_between = [
'Your model is not supported by this patcher!',
'',
'If you plan to create the USB for another machine, please select the "Change Model" option in the menu.'
]
elif not self.constants.custom_model and self.current_model == "iMac7,1" and \
"SSE4.1" not in subprocess.run("sysctl machdep.cpu.features".split(), stdout=subprocess.PIPE, stderr=subprocess.STDOUT).stdout.decode():
in_between = [
'Your model requires a CPU upgrade to a CPU supporting SSE4.1+ to be supported by this patcher!',
'',
f'If you plan to create the USB for another {self.current_model} with SSE4.1+, please select the "Change Model" option in the menu.'
]
elif self.constants.custom_model == "iMac7,1":
in_between = ["This model is supported",
"However please ensure the CPU has been upgraded to support SSE4.1+"
]
else:
in_between = ["This model is supported"]
menu = Utilities.TUIMenu(title, "Please select an option: ", in_between=in_between, auto_number=True, top_level=True)
options = (
[["Build OpenCore", self.build_opencore]] if ((self.constants.custom_model or self.current_model) in ModelArray.SupportedSMBIOS) else []) + [
["Install OpenCore to USB/internal drive", self.install_opencore],
["Post-Install Volume Patch", self.PatchVolume],
["Change Model", self.change_model],
["Patcher Settings", self.patcher_settings],
["Credits", self.credits]
]
for option in options:
menu.add_menu_option(option[0], function=option[1])
response = menu.start()
if getattr(sys, "frozen", False):
subprocess.run("""osascript -e 'tell application "Terminal" to close first window' & exit""", shell=True)
OpenCoreLegacyPatcher().main_menu()