Compare commits
184 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8eebf7e1e1 | ||
|
|
85cf440996 | ||
|
|
db2768a2bf | ||
|
|
48c74a1d75 | ||
|
|
73aa594ab6 | ||
|
|
42478c726b | ||
|
|
00ea5a7843 | ||
|
|
7f0a96126b | ||
|
|
c6f6fe4b43 | ||
|
|
c3dcb35b33 | ||
|
|
eefe49b837 | ||
|
|
bf3f4481dc | ||
|
|
ce6f65de1f | ||
|
|
045cc3726e | ||
|
|
60d392f969 | ||
|
|
e992fbdd14 | ||
|
|
3d40c94787 | ||
|
|
9794cc5fb1 | ||
|
|
8ae451f37f | ||
|
|
3c309d71b9 | ||
|
|
dbdddd063f | ||
|
|
0e1421f7fc | ||
|
|
3a3bba4c65 | ||
|
|
1f000d893f | ||
|
|
87469b71d0 | ||
|
|
8d838a3148 | ||
|
|
c1f5be775d | ||
|
|
7539d175b5 | ||
|
|
5a1fa12e5b | ||
|
|
6aed21aae2 | ||
|
|
c0ae23367e | ||
|
|
4bbfe465fa | ||
|
|
2fb243cc00 | ||
|
|
b74001a6e5 | ||
|
|
4e4157c125 | ||
|
|
9ef569e949 | ||
|
|
4b7c399ce6 | ||
|
|
fcf24cef88 | ||
|
|
1d37c5a4ee | ||
|
|
27d95a9aae | ||
|
|
8cae25b95a | ||
|
|
fb0ea6bb08 | ||
|
|
303a908248 | ||
|
|
3585053633 | ||
|
|
a329e80082 | ||
|
|
8332b714b5 | ||
|
|
4add945fa0 | ||
|
|
807d394bdb | ||
|
|
0ba78bae68 | ||
|
|
d73b3dcc69 | ||
|
|
d9e91bd17e | ||
|
|
8a9db4c2a5 | ||
|
|
fccde7214b | ||
|
|
24cc303530 | ||
|
|
2753f88bfa | ||
|
|
4056224476 | ||
|
|
5b55d17e42 | ||
|
|
669cc0ac5f | ||
|
|
9a3181d465 | ||
|
|
728fef9256 | ||
|
|
b06feb9dbe | ||
|
|
bd51332a17 | ||
|
|
a6503bcd97 | ||
|
|
f931c3b6c2 | ||
|
|
c8aa13664d | ||
|
|
f32a813a0c | ||
|
|
2696879109 | ||
|
|
df28ea288a | ||
|
|
fc5b250d41 | ||
|
|
b349459da6 | ||
|
|
132f12c885 | ||
|
|
bbdfb8158f | ||
|
|
be7493f74a | ||
|
|
fbe216164a | ||
|
|
1cbee930cb | ||
|
|
f77a45a587 | ||
|
|
ef32e07ac6 | ||
|
|
e4f1f6b288 | ||
|
|
ba0a6a59e5 | ||
|
|
1ff1934595 | ||
|
|
61eb938350 | ||
|
|
5a57ee1cc9 | ||
|
|
258b0309ab | ||
|
|
53dd5d3477 | ||
|
|
c4cda81df6 | ||
|
|
35b365c8ca | ||
|
|
1653fec580 | ||
|
|
d1e721d8d7 | ||
|
|
e453bd1b51 | ||
|
|
1a576c72a2 | ||
|
|
9a55317f86 | ||
|
|
23d7f9f07c | ||
|
|
8c99335b83 | ||
|
|
5fd7ad0b4b | ||
|
|
b065da6dbf | ||
|
|
90092a296d | ||
|
|
57356bcceb | ||
|
|
d726851d9c | ||
|
|
cdd81c5466 | ||
|
|
7897cd14b6 | ||
|
|
628fe4f8fc | ||
|
|
260fcf4c93 | ||
|
|
a074baa2e9 | ||
|
|
e81c138d2e | ||
|
|
aa4fd137d1 | ||
|
|
960090fd80 | ||
|
|
8203cbc756 | ||
|
|
fb88795923 | ||
|
|
7e6da1d056 | ||
|
|
a7837f1ae8 | ||
|
|
4544c99fde | ||
|
|
1f2409043d | ||
|
|
580fb83b4d | ||
|
|
de3875279a | ||
|
|
cdfefe1612 | ||
|
|
6f7f309a4d | ||
|
|
86a7e306f6 | ||
|
|
8d88fbbfa4 | ||
|
|
414d114b85 | ||
|
|
0749d14e1c | ||
|
|
ae423888d7 | ||
|
|
4583a743be | ||
|
|
537853418d | ||
|
|
6603df4cce | ||
|
|
21e144ee5f | ||
|
|
4f44737f12 | ||
|
|
50e7f1d3ad | ||
|
|
18157fe5aa | ||
|
|
3b551d565a | ||
|
|
b7c4ea2b89 | ||
|
|
66f0009c65 | ||
|
|
49da508bde | ||
|
|
76516394fd | ||
|
|
f46f4cf857 | ||
|
|
4f104de405 | ||
|
|
4f2f9a8763 | ||
|
|
ceeef7c1a5 | ||
|
|
9cadfec802 | ||
|
|
dbae3383d0 | ||
|
|
99daa4c2b1 | ||
|
|
18ec8ca665 | ||
|
|
5f675ab9de | ||
|
|
ed002ce988 | ||
|
|
9f24c8738a | ||
|
|
5551780fcb | ||
|
|
820481a288 | ||
|
|
a32e148ec0 | ||
|
|
e7c9f4e90c | ||
|
|
692c0de9f2 | ||
|
|
dbae4db28c | ||
|
|
ded1e8c2c7 | ||
|
|
0f83e77f1a | ||
|
|
1fc1595ffb | ||
|
|
1c147819f7 | ||
|
|
4aaf658c8f | ||
|
|
2fb193692b | ||
|
|
7f6a2e393c | ||
|
|
0a48986ddb | ||
|
|
edd9814f12 | ||
|
|
f32f94e588 | ||
|
|
5fb4bbf7f4 | ||
|
|
7d8d9324e0 | ||
|
|
f717bdceae | ||
|
|
d015f8d1e4 | ||
|
|
462d6f633a | ||
|
|
b2c01da5b2 | ||
|
|
fc650bfd97 | ||
|
|
ffeec342a9 | ||
|
|
ea12d44d68 | ||
|
|
09c3b8e3da | ||
|
|
697dbec6a1 | ||
|
|
991c059f30 | ||
|
|
40484a42dd | ||
|
|
832232dd37 | ||
|
|
f9ecafb661 | ||
|
|
42c6d6b042 | ||
|
|
1d9fbec9ef | ||
|
|
9a2fca8d18 | ||
|
|
475b9e793f | ||
|
|
73ce7e5bda | ||
|
|
3bffad8001 | ||
|
|
aa40e9328a | ||
|
|
ec103c1d2e | ||
|
|
dd88879dc0 |
56
CHANGELOG.md
@@ -1,5 +1,61 @@
|
||||
# OpenCore Legacy Patcher changelog
|
||||
|
||||
## 2.0.0
|
||||
- Set `AssociatedBundleIdentifiers` property in launch services as an array
|
||||
- Move to auto-generated pre/postinstall scripts for PKGs
|
||||
- Streamlines PKG creation process, ensuring Install and AutoPKG scripts are always in sync
|
||||
- Add support for `gktool` in PKG postinstall scripts
|
||||
- Removes Gatekeeper "verifying" prompt on first launch after PKG installation
|
||||
- Note `gktool` is only available on macOS Sonoma and newer
|
||||
- Resolve unpatching crash edge case when host doesn't require patches.
|
||||
- Implement new Software Update Catalog Parser for macOS Installers
|
||||
- Implement new Copy on Write detection mechanism for all file copying operations
|
||||
- Implemented using `getattrlist` and `VOL_CAP_INT_CLONE` flag
|
||||
- Helps improve performance on APFS volumes
|
||||
- Increase model range for S1X/S3X patching to include Haswell Macs and `MacPro6,1`
|
||||
- Helps avoid an issue where older machines with newer, unsupported SSDs would fail to boot
|
||||
- Only affects building EFI from another machine
|
||||
- Resolve AMD Navi MXM GPU detection for modded iMac9,x-12,x
|
||||
- Thanks @Ausdauersportler for the patch!
|
||||
- Implement early macOS Sequoia support:
|
||||
- Supporting Macs with Metal and non-Metal-based graphics:
|
||||
- MacBook5,x - 10,1
|
||||
- MacBookAir2,x - 7,x
|
||||
- MacBookPro4,1 - 14,x
|
||||
- Macmini3,1 - 7,1
|
||||
- iMac7,1 - 18,x
|
||||
- MacPro3,1 - 6,1
|
||||
- MacPro3,1 can only boot with 4 cores max currently
|
||||
- 8 cores can be re-enabled for older OSes in the GUI:
|
||||
- Settings -> Build -> MacPro3,1/Xserve2,1 Workaround
|
||||
- Xserve2,1 - 3,1
|
||||
- Xserve2,1 can only boot with 4 cores max currently
|
||||
- 8 cores can be re-enabled for older OSes in the GUI:
|
||||
- Settings -> Build -> MacPro3,1/Xserve2,1 Workaround
|
||||
- Excludes the newly dropped MacBookAir8,x series.
|
||||
- No estimate can be given when support will be added.
|
||||
- For non-Metal graphics, Photos app will be broken.
|
||||
- No estimate can be given when support will be added.
|
||||
- Implement new MetallibSupportPkg system to support macOS Sequoia on Metal 3802-based GPUs.
|
||||
- See repository for more details: [MetallibSupportPkg](https://github.com/dortania/MetallibSupportPkg).
|
||||
- Implement new Patchset Detection architecture.
|
||||
- Implement new kernel cache building architecture.
|
||||
- Resolve "Label" error in com.dortania.opencore-legacy-patcher.os-caching.plist.
|
||||
- Add macOS Sequoia icons to boot picker and GUI.
|
||||
- Resolve Memoji crashes on 3802 GPUs.
|
||||
- Resolve Photos Memories tab crash on Intel Ivy Bridge/Haswell iGPUs.
|
||||
- Increment Binaries:
|
||||
- PatcherSupportPkg 1.8.0 - release
|
||||
- OpenCorePkg 1.0.1 - release
|
||||
- Lilu 1.6.8 - release
|
||||
- WhateverGreen 1.6.7 - release
|
||||
- RestrictEvents 1.1.4 - release
|
||||
- FeatureUnlock 1.1.6 - release
|
||||
- DebugEnhancer 1.0.9 - release
|
||||
- CPUFriend 1.2.8 - release
|
||||
- AutoPkgInstaller 1.0.4 - release
|
||||
- CryptexFixup 1.0.3 - release
|
||||
|
||||
## 1.5.0
|
||||
- Restructure project directories
|
||||
- Python:
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
Copyright (c) 2020-2024, Dhinak G
|
||||
Copyright (c) 2020-2024, Mykola Grymalyuk
|
||||
Copyright (c) 2020-2024 Dhinak G, Mykola Grymalyuk, and individual contributors.
|
||||
|
||||
All rights reserved.
|
||||
|
||||
|
||||
@@ -100,7 +100,16 @@ To run the project from source, see here: [Build and run from source](./SOURCE.m
|
||||
* Pre-Ivy Bridge Aquantia Ethernet Patch
|
||||
* Non-Metal Photo Booth Patch for Monterey+
|
||||
* GUI and Backend Development
|
||||
* Updater UI
|
||||
* macOS Downloader UI
|
||||
* Downloader UI
|
||||
* USB Top Case probing
|
||||
* Developer root patching
|
||||
* Vaulting implementation
|
||||
* macOS 15 3802 Helios Research
|
||||
* UEFI bootx64.efi research
|
||||
* universal2 build research
|
||||
* Various documentation contributions
|
||||
* Amazing users who've graciously donate hardware:
|
||||
* [JohnD](https://forums.macrumors.com/members/johnd.53633/) - 2013 Mac Pro
|
||||
* [SpiGAndromeda](https://github.com/SpiGAndromeda) - AMD Vega 64
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
#!/bin/zsh --no-rcs
|
||||
# ------------------------------------------------------
|
||||
# AutoPkg Assets Postinstall Script
|
||||
# ------------------------------------------------------
|
||||
# Create alias for app, start patching and reboot.
|
||||
# ------------------------------------------------------
|
||||
|
||||
# MARK: PackageKit Parameters
|
||||
# ---------------------------
|
||||
|
||||
pathToScript=$0 # ex. /tmp/PKInstallSandbox.*/Scripts/*/preinstall
|
||||
pathToPackage=$1 # ex. ~/Downloads/Installer.pkg
|
||||
pathToTargetLocation=$2 # ex. '/', '/Applications', etc (depends on pkgbuild's '--install-location' argument)
|
||||
pathToTargetVolume=$3 # ex. '/', '/Volumes/MyVolume', etc
|
||||
pathToStartupDisk=$4 # ex. '/'
|
||||
|
||||
|
||||
# MARK: Variables
|
||||
# ---------------------------
|
||||
|
||||
helperPath="Library/PrivilegedHelperTools/com.dortania.opencore-legacy-patcher.privileged-helper"
|
||||
mainAppPath="Library/Application Support/Dortania/OpenCore-Patcher.app"
|
||||
shimAppPath="Applications/OpenCore-Patcher.app"
|
||||
executablePath="$mainAppPath/Contents/MacOS/OpenCore-Patcher"
|
||||
|
||||
|
||||
# MARK: Functions
|
||||
# ---------------------------
|
||||
|
||||
function _setSUIDBit() {
|
||||
local binaryPath=$1
|
||||
|
||||
echo "Setting SUID bit on: $binaryPath"
|
||||
|
||||
# Check if path is a directory
|
||||
if [[ -d $binaryPath ]]; then
|
||||
/bin/chmod -R +s $binaryPath
|
||||
else
|
||||
/bin/chmod +s $binaryPath
|
||||
fi
|
||||
}
|
||||
|
||||
function _createAlias() {
|
||||
local mainPath=$1
|
||||
local aliasPath=$2
|
||||
|
||||
# Check if alias path exists
|
||||
if [[ -e $aliasPath ]]; then
|
||||
# Check if alias path is a symbolic link
|
||||
if [[ -L $aliasPath ]]; then
|
||||
echo "Removing old symbolic link: $aliasPath"
|
||||
/bin/rm -f $aliasPath
|
||||
else
|
||||
echo "Removing old file: $aliasPath"
|
||||
/bin/rm -rf $aliasPath
|
||||
fi
|
||||
fi
|
||||
|
||||
# Create symbolic link
|
||||
echo "Creating symbolic link: $aliasPath"
|
||||
/bin/ln -s $mainPath $aliasPath
|
||||
}
|
||||
|
||||
function _startPatching() {
|
||||
local executable=$1
|
||||
local logPath=$(_logFile)
|
||||
|
||||
# Start patching
|
||||
"$executable" "--patch_sys_vol" &> $logPath
|
||||
}
|
||||
|
||||
function _logFile() {
|
||||
echo "/Users/Shared/.OCLP-AutoPatcher-Log-$(/bin/date +"%Y_%m_%d_%I_%M_%p").txt"
|
||||
}
|
||||
|
||||
function _fixSettingsFilePermission() {
|
||||
local settingsPath="$pathToTargetVolume/Users/Shared/.com.dortania.opencore-legacy-patcher.plist"
|
||||
|
||||
if [[ -e $settingsPath ]]; then
|
||||
echo "Fixing settings file permissions: $settingsPath"
|
||||
/bin/chmod 666 $settingsPath
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
function _reboot() {
|
||||
/sbin/reboot
|
||||
}
|
||||
|
||||
function _main() {
|
||||
_setSUIDBit "$pathToTargetVolume/$helperPath"
|
||||
_createAlias "$pathToTargetVolume/$mainAppPath" "$pathToTargetVolume/$shimAppPath"
|
||||
_startPatching "$pathToTargetVolume/$executablePath"
|
||||
_fixSettingsFilePermission
|
||||
_reboot
|
||||
}
|
||||
|
||||
|
||||
# MARK: Main
|
||||
# ---------------------------
|
||||
|
||||
echo "Starting postinstall script..."
|
||||
_main
|
||||
@@ -1,80 +0,0 @@
|
||||
#!/bin/zsh --no-rcs
|
||||
# ------------------------------------------------------
|
||||
# AutoPkg Assets Preinstall Script
|
||||
# ------------------------------------------------------
|
||||
# Remove old files, and prepare directories.
|
||||
# ------------------------------------------------------
|
||||
|
||||
|
||||
# MARK: PackageKit Parameters
|
||||
# ---------------------------
|
||||
|
||||
pathToScript=$0 # ex. /tmp/PKInstallSandbox.*/Scripts/*/preinstall
|
||||
pathToPackage=$1 # ex. ~/Downloads/Installer.pkg
|
||||
pathToTargetLocation=$2 # ex. '/', '/Applications', etc (depends on pkgbuild's '--install-location' argument)
|
||||
pathToTargetVolume=$3 # ex. '/', '/Volumes/MyVolume', etc
|
||||
pathToStartupDisk=$4 # ex. '/'
|
||||
|
||||
|
||||
# MARK: Variables
|
||||
# ---------------------------
|
||||
|
||||
filesToRemove=(
|
||||
"Applications/OpenCore-Patcher.app"
|
||||
"Library/Application Support/Dortania/Update.plist"
|
||||
"Library/Application Support/Dortania/OpenCore-Patcher.app"
|
||||
"Library/LaunchAgents/com.dortania.opencore-legacy-patcher.auto-patch.plist"
|
||||
"Library/PrivilegedHelperTools/com.dortania.opencore-legacy-patcher.privileged-helper"
|
||||
)
|
||||
|
||||
|
||||
# MARK: Functions
|
||||
# ---------------------------
|
||||
|
||||
function _removeFile() {
|
||||
local file=$1
|
||||
|
||||
if [[ ! -e $file ]]; then
|
||||
# Check if file is a symbolic link
|
||||
if [[ -L $file ]]; then
|
||||
echo "Removing symbolic link: $file"
|
||||
/bin/rm -f $file
|
||||
fi
|
||||
return
|
||||
fi
|
||||
|
||||
echo "Removing file: $file"
|
||||
|
||||
# Check if file is a directory
|
||||
if [[ -d $file ]]; then
|
||||
/bin/rm -rf $file
|
||||
else
|
||||
/bin/rm -f $file
|
||||
fi
|
||||
}
|
||||
|
||||
function _createParentDirectory() {
|
||||
local file=$1
|
||||
|
||||
local parentDirectory="$(/usr/bin/dirname $file)"
|
||||
|
||||
# Check if parent directory exists
|
||||
if [[ ! -d $parentDirectory ]]; then
|
||||
echo "Creating parent directory: $parentDirectory"
|
||||
/bin/mkdir -p $parentDirectory
|
||||
fi
|
||||
}
|
||||
|
||||
function _main() {
|
||||
for file in $filesToRemove; do
|
||||
_removeFile $pathToTargetVolume/$file
|
||||
_createParentDirectory $pathToTargetVolume/$file
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
# MARK: Main
|
||||
# ---------------------------
|
||||
|
||||
echo "Starting preinstall script..."
|
||||
_main
|
||||
@@ -5,7 +5,7 @@ import subprocess
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from opencore_legacy_patcher import constants
|
||||
from opencore_legacy_patcher.volume import generate_copy_arguments
|
||||
from opencore_legacy_patcher.support import subprocess_wrapper
|
||||
|
||||
|
||||
@@ -158,7 +158,7 @@ class GenerateApplication:
|
||||
print("Embedding resources")
|
||||
for file in Path("payloads/Icon/AppIcons").glob("*.icns"):
|
||||
subprocess_wrapper.run_and_verify(
|
||||
["/bin/cp", str(file), self._application_output / "Contents" / "Resources/"],
|
||||
generate_copy_arguments(str(file), self._application_output / "Contents" / "Resources/"),
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE
|
||||
)
|
||||
|
||||
|
||||
@@ -78,6 +78,7 @@ class GenerateDiskImages:
|
||||
'-format', 'UDZO', '-ov',
|
||||
'-volname', 'OpenCore Patcher Resources (Base)',
|
||||
'-fs', 'HFS+',
|
||||
'-layout', 'NONE',
|
||||
'-srcfolder', './payloads',
|
||||
'-passphrase', 'password', '-encryption'
|
||||
], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
|
||||
@@ -2,9 +2,13 @@
|
||||
package.py: Generate packages (Installer, Uninstaller, AutoPkg-Assets)
|
||||
"""
|
||||
|
||||
import tempfile
|
||||
import macos_pkg_builder
|
||||
|
||||
from opencore_legacy_patcher import constants
|
||||
|
||||
from .package_scripts import GenerateScripts
|
||||
|
||||
|
||||
class GeneratePackage:
|
||||
"""
|
||||
@@ -63,48 +67,82 @@ class GeneratePackage:
|
||||
return _welcome
|
||||
|
||||
|
||||
def _generate_autopkg_welcome(self) -> str:
|
||||
"""
|
||||
Generate Welcome message for AutoPkg-Assets PKG
|
||||
"""
|
||||
_welcome = ""
|
||||
|
||||
_welcome += "# DO NOT RUN AUTOPKG-ASSETS MANUALLY!\n\n"
|
||||
_welcome += "## THIS CAN BREAK YOUR SYSTEM'S INSTALL!\n\n"
|
||||
_welcome += "This package should only ever be invoked by the Patcher itself, never downloaded or run by the user. Download the OpenCore-Patcher.pkg on the Github Repository.\n\n"
|
||||
_welcome += f"[OpenCore Legacy Patcher GitHub Release]({constants.Constants().repo_link})"
|
||||
|
||||
return _welcome
|
||||
|
||||
|
||||
def generate(self) -> None:
|
||||
"""
|
||||
Generate OpenCore-Patcher.pkg
|
||||
"""
|
||||
print("Generating OpenCore-Patcher-Uninstaller.pkg")
|
||||
_tmp_uninstall = tempfile.NamedTemporaryFile(delete=False)
|
||||
with open(_tmp_uninstall.name, "w") as f:
|
||||
f.write(GenerateScripts().uninstall())
|
||||
|
||||
assert macos_pkg_builder.Packages(
|
||||
pkg_output="./dist/OpenCore-Patcher-Uninstaller.pkg",
|
||||
pkg_bundle_id="com.dortania.opencore-legacy-patcher-uninstaller",
|
||||
pkg_version=constants.Constants().patcher_version,
|
||||
pkg_background="./ci_tooling/installation_pkg/PkgBackgroundUninstaller.png",
|
||||
pkg_preinstall_script="./ci_tooling/installation_pkg/uninstall.sh",
|
||||
pkg_background="./ci_tooling/pkg_assets/PkgBackground-Uninstaller.png",
|
||||
pkg_preinstall_script=_tmp_uninstall.name,
|
||||
pkg_as_distribution=True,
|
||||
pkg_title="OpenCore Legacy Patcher Uninstaller",
|
||||
pkg_welcome=self._generate_uninstaller_welcome(),
|
||||
).build() is True
|
||||
|
||||
print("Generating OpenCore-Patcher.pkg")
|
||||
|
||||
_tmp_pkg_preinstall = tempfile.NamedTemporaryFile(delete=False)
|
||||
_tmp_pkg_postinstall = tempfile.NamedTemporaryFile(delete=False)
|
||||
with open(_tmp_pkg_preinstall.name, "w") as f:
|
||||
f.write(GenerateScripts().preinstall_pkg())
|
||||
with open(_tmp_pkg_postinstall.name, "w") as f:
|
||||
f.write(GenerateScripts().postinstall_pkg())
|
||||
|
||||
assert macos_pkg_builder.Packages(
|
||||
pkg_output="./dist/OpenCore-Patcher.pkg",
|
||||
pkg_bundle_id="com.dortania.opencore-legacy-patcher",
|
||||
pkg_version=constants.Constants().patcher_version,
|
||||
pkg_allow_relocation=False,
|
||||
pkg_as_distribution=True,
|
||||
pkg_background="./ci_tooling/installation_pkg/PkgBackground.png",
|
||||
pkg_preinstall_script="./ci_tooling/installation_pkg/preinstall.sh",
|
||||
pkg_postinstall_script="./ci_tooling/installation_pkg/postinstall.sh",
|
||||
pkg_background="./ci_tooling/pkg_assets/PkgBackground-Installer.png",
|
||||
pkg_preinstall_script=_tmp_pkg_preinstall.name,
|
||||
pkg_postinstall_script=_tmp_pkg_postinstall.name,
|
||||
pkg_file_structure=self._files,
|
||||
pkg_title="OpenCore Legacy Patcher",
|
||||
pkg_welcome=self._generate_installer_welcome(),
|
||||
).build() is True
|
||||
|
||||
print("Generating AutoPkg-Assets.pkg")
|
||||
|
||||
_tmp_auto_pkg_preinstall = tempfile.NamedTemporaryFile(delete=False)
|
||||
_tmp_auto_pkg_postinstall = tempfile.NamedTemporaryFile(delete=False)
|
||||
with open(_tmp_auto_pkg_preinstall.name, "w") as f:
|
||||
f.write(GenerateScripts().preinstall_autopkg())
|
||||
with open(_tmp_auto_pkg_postinstall.name, "w") as f:
|
||||
f.write(GenerateScripts().postinstall_autopkg())
|
||||
|
||||
assert macos_pkg_builder.Packages(
|
||||
pkg_output="./dist/AutoPkg-Assets.pkg",
|
||||
pkg_bundle_id="com.dortania.pkg.AutoPkg-Assets",
|
||||
pkg_version=constants.Constants().patcher_version,
|
||||
pkg_allow_relocation=False,
|
||||
pkg_as_distribution=True,
|
||||
pkg_background="./ci_tooling/autopkg/PkgBackground.png",
|
||||
pkg_preinstall_script="./ci_tooling/autopkg/preinstall.sh",
|
||||
pkg_postinstall_script="./ci_tooling/autopkg/postinstall.sh",
|
||||
pkg_background="./ci_tooling/pkg_assets/PkgBackground-AutoPkg.png",
|
||||
pkg_preinstall_script=_tmp_auto_pkg_preinstall.name,
|
||||
pkg_postinstall_script=_tmp_auto_pkg_postinstall.name,
|
||||
pkg_file_structure=self._autopkg_files,
|
||||
pkg_title="AutoPkg Assets",
|
||||
pkg_welcome="# DO NOT RUN AUTOPKG-ASSETS MANUALLY!\n\n## THIS CAN BREAK YOUR SYSTEM'S INSTALL!\n\nThis package should only ever be invoked by the Patcher itself, never downloaded or run by the user. Download the OpenCore-Patcher.pkg on the Github Repository.\n\n[OpenCore Legacy Patcher GitHub Release](https://github.com/dortania/OpenCore-Legacy-Patcher/releases/)",
|
||||
pkg_welcome=self._generate_autopkg_welcome(),
|
||||
).build() is True
|
||||
|
||||
556
ci_tooling/build_modules/package_scripts.py
Normal file
@@ -0,0 +1,556 @@
|
||||
"""
|
||||
package_scripts.py: Generate pre/postinstall scripts for PKG and AutoPkg
|
||||
"""
|
||||
|
||||
|
||||
class ZSHFunctions:
|
||||
|
||||
def __init__(self) -> None:
|
||||
pass
|
||||
|
||||
|
||||
def generate_standard_pkg_parameters(self) -> str:
|
||||
"""
|
||||
ZSH variables for standard PackageKit parameters
|
||||
"""
|
||||
|
||||
_script = ""
|
||||
|
||||
_script += "# MARK: PackageKit Parameters\n"
|
||||
_script += "# " + "-" * 27 + "\n\n"
|
||||
|
||||
_script += "pathToScript=$0 # ex. /tmp/PKInstallSandbox.*/Scripts/*/preinstall\n"
|
||||
_script += "pathToPackage=$1 # ex. ~/Downloads/Installer.pkg\n"
|
||||
_script += "pathToTargetLocation=$2 # ex. '/', '/Applications', etc (depends on pkgbuild's '--install-location' argument)\n"
|
||||
_script += "pathToTargetVolume=$3 # ex. '/', '/Volumes/MyVolume', etc\n"
|
||||
_script += "pathToStartupDisk=$4 # ex. '/'\n"
|
||||
|
||||
return _script
|
||||
|
||||
|
||||
def generate_script_remove_file(self) -> str:
|
||||
"""
|
||||
ZSH function to remove files
|
||||
"""
|
||||
|
||||
_script = ""
|
||||
|
||||
_script += "function _removeFile() {\n"
|
||||
_script += " local file=$1\n\n"
|
||||
|
||||
_script += " if [[ ! -e $file ]]; then\n"
|
||||
_script += " # Check if file is a symbolic link\n"
|
||||
_script += " if [[ -L $file ]]; then\n"
|
||||
_script += " echo \"Removing symbolic link: $file\"\n"
|
||||
_script += " /bin/rm -f $file\n"
|
||||
_script += " fi\n"
|
||||
_script += " return\n"
|
||||
_script += " fi\n\n"
|
||||
|
||||
_script += " echo \"Removing file: $file\"\n\n"
|
||||
|
||||
_script += " # Check if file is a directory\n"
|
||||
_script += " if [[ -d $file ]]; then\n"
|
||||
_script += " /bin/rm -rf $file\n"
|
||||
_script += " else\n"
|
||||
_script += " /bin/rm -f $file\n"
|
||||
_script += " fi\n"
|
||||
_script += "}\n"
|
||||
|
||||
return _script
|
||||
|
||||
|
||||
def generate_script_create_parent_directory(self) -> str:
|
||||
"""
|
||||
ZSH function to create parent directory
|
||||
"""
|
||||
|
||||
_script = ""
|
||||
|
||||
_script += "function _createParentDirectory() {\n"
|
||||
_script += " local file=$1\n\n"
|
||||
|
||||
_script += " local parentDirectory=\"$(/usr/bin/dirname $file)\"\n\n"
|
||||
|
||||
_script += " # Check if parent directory exists\n"
|
||||
_script += " if [[ ! -d $parentDirectory ]]; then\n"
|
||||
_script += " echo \"Creating parent directory: $parentDirectory\"\n"
|
||||
_script += " /bin/mkdir -p $parentDirectory\n"
|
||||
_script += " fi\n"
|
||||
_script += "}\n"
|
||||
|
||||
return _script
|
||||
|
||||
|
||||
def generate_set_suid_bit(self) -> str:
|
||||
"""
|
||||
ZSH function to set SUID bit
|
||||
"""
|
||||
|
||||
_script = ""
|
||||
|
||||
_script += "function _setSUIDBit() {\n"
|
||||
_script += " local binaryPath=$1\n\n"
|
||||
|
||||
_script += " echo \"Setting SUID bit on: $binaryPath\"\n\n"
|
||||
|
||||
_script += " # Check if path is a directory\n"
|
||||
_script += " if [[ -d $binaryPath ]]; then\n"
|
||||
_script += " /bin/chmod -R +s $binaryPath\n"
|
||||
_script += " else\n"
|
||||
_script += " /bin/chmod +s $binaryPath\n"
|
||||
_script += " fi\n"
|
||||
_script += "}\n"
|
||||
|
||||
return _script
|
||||
|
||||
|
||||
def generate_create_alias(self) -> str:
|
||||
"""
|
||||
ZSH function to create alias
|
||||
"""
|
||||
|
||||
_script = ""
|
||||
|
||||
_script += "function _createAlias() {\n"
|
||||
_script += " local mainPath=$1\n"
|
||||
_script += " local aliasPath=$2\n\n"
|
||||
|
||||
_script += " # Check if alias path exists\n"
|
||||
_script += " if [[ -e $aliasPath ]]; then\n"
|
||||
_script += " # Check if alias path is a symbolic link\n"
|
||||
_script += " if [[ -L $aliasPath ]]; then\n"
|
||||
_script += " echo \"Removing old symbolic link: $aliasPath\"\n"
|
||||
_script += " /bin/rm -f $aliasPath\n"
|
||||
_script += " else\n"
|
||||
_script += " echo \"Removing old file: $aliasPath\"\n"
|
||||
_script += " /bin/rm -rf $aliasPath\n"
|
||||
_script += " fi\n"
|
||||
_script += " fi\n\n"
|
||||
|
||||
_script += " # Create symbolic link\n"
|
||||
_script += " echo \"Creating symbolic link: $aliasPath\"\n"
|
||||
_script += " /bin/ln -s $mainPath $aliasPath\n"
|
||||
_script += "}\n"
|
||||
|
||||
return _script
|
||||
|
||||
|
||||
def generate_start_patching(self) -> str:
|
||||
"""
|
||||
ZSH function to start patching
|
||||
"""
|
||||
|
||||
_script = ""
|
||||
|
||||
_script += "function _startPatching() {\n"
|
||||
_script += " local executable=$1\n"
|
||||
_script += " local logPath=$(_logFile)\n\n"
|
||||
|
||||
_script += " # Start patching\n"
|
||||
_script += " \"$executable\" \"--patch_sys_vol\" &> $logPath\n"
|
||||
_script += "}\n"
|
||||
|
||||
return _script
|
||||
|
||||
|
||||
def generate_log_file(self) -> str:
|
||||
"""
|
||||
ZSH function to generate log file
|
||||
"""
|
||||
|
||||
_script = ""
|
||||
|
||||
_script += "function _logFile() {\n"
|
||||
_script += " echo \"/Users/Shared/.OCLP-AutoPatcher-Log-$(/bin/date +\"%Y_%m_%d_%I_%M_%p\").txt\"\n"
|
||||
_script += "}\n"
|
||||
|
||||
return _script
|
||||
|
||||
|
||||
def generate_fix_settings_file_permission(self) -> str:
|
||||
"""
|
||||
ZSH function to fix settings file permission
|
||||
"""
|
||||
|
||||
_script = ""
|
||||
|
||||
_script += "function _fixSettingsFilePermission() {\n"
|
||||
_script += " local settingsPath=\"$pathToTargetVolume/Users/Shared/.com.dortania.opencore-legacy-patcher.plist\"\n\n"
|
||||
|
||||
_script += " if [[ -e $settingsPath ]]; then\n"
|
||||
_script += " echo \"Fixing settings file permissions: $settingsPath\"\n"
|
||||
_script += " /bin/chmod 666 $settingsPath\n"
|
||||
_script += " fi\n"
|
||||
|
||||
_script += "}\n"
|
||||
|
||||
return _script
|
||||
|
||||
|
||||
def generate_reboot(self) -> str:
|
||||
"""
|
||||
ZSH function to reboot
|
||||
"""
|
||||
|
||||
_script = ""
|
||||
|
||||
_script += "function _reboot() {\n"
|
||||
_script += " /sbin/reboot\n"
|
||||
_script += "}\n"
|
||||
|
||||
return _script
|
||||
|
||||
|
||||
def generate_prewarm_gatekeeper(self) -> str:
|
||||
"""
|
||||
ZSH function to prewarm Gatekeeper
|
||||
"""
|
||||
|
||||
_script = ""
|
||||
|
||||
_script += "function _prewarmGatekeeper() {\n"
|
||||
_script += " local appPath=$1\n\n"
|
||||
|
||||
_script += " # Check if /usr/bin/gktool exists\n"
|
||||
_script += " if [[ ! -e /usr/bin/gktool ]]; then\n"
|
||||
_script += " echo \"Host doesn't support Gatekeeper prewarming, skipping...\"\n"
|
||||
_script += " return\n"
|
||||
_script += " fi\n\n"
|
||||
|
||||
_script += " echo \"Prewarming Gatekeeper for application: $appPath\"\n"
|
||||
_script += " /usr/bin/gktool scan $appPath\n"
|
||||
_script += "}\n"
|
||||
|
||||
return _script
|
||||
|
||||
|
||||
def generate_clean_launch_service(self) -> str:
|
||||
"""
|
||||
ZSH function to clean Launch Service
|
||||
"""
|
||||
|
||||
_script = ""
|
||||
|
||||
_script += "function _cleanLaunchService() {\n"
|
||||
_script += " local domain=\"com.dortania.opencore-legacy-patcher\"\n\n"
|
||||
|
||||
_script += " # Iterate over launch agents and daemons\n"
|
||||
_script += " for launchServiceVariant in \"$pathToTargetVolume/Library/LaunchAgents\" \"$pathToTargetVolume/Library/LaunchDaemons\"; do\n"
|
||||
_script += " # Check if directory exists\n"
|
||||
_script += " if [[ ! -d $launchServiceVariant ]]; then\n"
|
||||
_script += " continue\n"
|
||||
_script += " fi\n\n"
|
||||
|
||||
_script += " # Iterate over launch service files\n"
|
||||
_script += " for launchServiceFile in $(/bin/ls -1 $launchServiceVariant | /usr/bin/grep $domain); do\n"
|
||||
_script += " local launchServicePath=\"$launchServiceVariant/$launchServiceFile\"\n\n"
|
||||
|
||||
_script += " # Remove launch service file\n"
|
||||
_script += " _removeFile $launchServicePath\n"
|
||||
_script += " done\n"
|
||||
_script += " done\n"
|
||||
_script += "}\n"
|
||||
|
||||
return _script
|
||||
|
||||
|
||||
def generate_preinstall_main(self) -> str:
|
||||
"""
|
||||
ZSH function for preinstall's main
|
||||
"""
|
||||
|
||||
_script = ""
|
||||
|
||||
_script += "function _main() {\n"
|
||||
_script += " for file in $filesToRemove; do\n"
|
||||
_script += " _removeFile $pathToTargetVolume/$file\n"
|
||||
_script += " _createParentDirectory $pathToTargetVolume/$file\n"
|
||||
_script += " done\n"
|
||||
_script += "}\n"
|
||||
|
||||
return _script
|
||||
|
||||
|
||||
def generate_postinstall_main(self, is_autopkg: bool = False) -> str:
|
||||
"""
|
||||
ZSH function for postinstall's main
|
||||
"""
|
||||
|
||||
_script = ""
|
||||
|
||||
_script += "function _main() {\n"
|
||||
_script += " _setSUIDBit \"$pathToTargetVolume/$helperPath\"\n"
|
||||
_script += " _createAlias \"$pathToTargetVolume/$mainAppPath\" \"$pathToTargetVolume/$shimAppPath\"\n"
|
||||
_script += " _prewarmGatekeeper \"$pathToTargetVolume/$mainAppPath\"\n"
|
||||
if is_autopkg:
|
||||
_script += " _startPatching \"$pathToTargetVolume/$executablePath\"\n"
|
||||
_script += " _fixSettingsFilePermission\n"
|
||||
_script += " _reboot\n"
|
||||
_script += "}\n"
|
||||
|
||||
return _script
|
||||
|
||||
|
||||
def generate_uninstall_main(self) -> str:
|
||||
"""
|
||||
ZSH function for uninstall's main
|
||||
"""
|
||||
|
||||
_script = ""
|
||||
|
||||
_script += "function _main() {\n"
|
||||
_script += " _cleanLaunchService\n"
|
||||
_script += " for file in $filesToRemove; do\n"
|
||||
_script += " _removeFile $pathToTargetVolume/$file\n"
|
||||
_script += " done\n"
|
||||
_script += "}\n"
|
||||
|
||||
return _script
|
||||
|
||||
|
||||
class GenerateScripts:
|
||||
|
||||
def __init__(self):
|
||||
self.zsh_functions = ZSHFunctions()
|
||||
|
||||
self.files = [
|
||||
"Applications/OpenCore-Patcher.app",
|
||||
"Library/Application Support/Dortania/Update.plist",
|
||||
"Library/Application Support/Dortania/OpenCore-Patcher.app",
|
||||
"Library/PrivilegedHelperTools/com.dortania.opencore-legacy-patcher.privileged-helper"
|
||||
]
|
||||
|
||||
self.additional_auto_pkg_files = [
|
||||
"Library/LaunchAgents/com.dortania.opencore-legacy-patcher.auto-patch.plist"
|
||||
]
|
||||
|
||||
|
||||
def __generate_shebang(self) -> str:
|
||||
"""
|
||||
Standard shebang for ZSH
|
||||
"""
|
||||
return "#!/bin/zsh --no-rcs\n"
|
||||
|
||||
|
||||
def _generate_header_bar(self) -> str:
|
||||
"""
|
||||
# ------------------------------------------------------
|
||||
"""
|
||||
return "# " + "-" * 54 + "\n"
|
||||
|
||||
|
||||
def _generate_label_bar(self) -> str:
|
||||
"""
|
||||
# ------------------------------
|
||||
"""
|
||||
return "# " + "-" * 27 + "\n"
|
||||
|
||||
|
||||
def _generate_preinstall_script(self, is_autopkg: bool = False) -> str:
|
||||
"""
|
||||
Generate preinstall script for PKG
|
||||
"""
|
||||
|
||||
_script = ""
|
||||
|
||||
_script += self.__generate_shebang()
|
||||
|
||||
_script += self._generate_header_bar()
|
||||
_script += f"# {'AutoPkg Assets' if is_autopkg else 'OpenCore Legacy Patcher'} Preinstall Script\n"
|
||||
_script += self._generate_header_bar()
|
||||
_script += "# Remove old files, and prepare directories.\n"
|
||||
_script += self._generate_header_bar()
|
||||
_script += "\n\n"
|
||||
|
||||
_script += self.zsh_functions.generate_standard_pkg_parameters()
|
||||
_script += "\n\n"
|
||||
|
||||
_script += "# MARK: Variables\n"
|
||||
_script += self._generate_label_bar()
|
||||
_script += "\n"
|
||||
|
||||
_files = self.files
|
||||
if is_autopkg:
|
||||
_files += self.additional_auto_pkg_files
|
||||
|
||||
_script += f"filesToRemove=(\n"
|
||||
for _file in _files:
|
||||
_script += f" \"{_file}\"\n"
|
||||
|
||||
_script += ")\n"
|
||||
|
||||
_script += "\n\n"
|
||||
|
||||
_script += "# MARK: Functions\n"
|
||||
_script += self._generate_label_bar()
|
||||
_script += "\n"
|
||||
|
||||
_script += self.zsh_functions.generate_script_remove_file()
|
||||
_script += "\n"
|
||||
_script += self.zsh_functions.generate_script_create_parent_directory()
|
||||
_script += "\n"
|
||||
_script += self.zsh_functions.generate_preinstall_main()
|
||||
_script += "\n\n"
|
||||
|
||||
_script += "# MARK: Main\n"
|
||||
_script += self._generate_label_bar()
|
||||
_script += "\n"
|
||||
|
||||
_script += "echo \"Starting preinstall script...\"\n"
|
||||
_script += "_main\n"
|
||||
|
||||
return _script
|
||||
|
||||
|
||||
def _generate_postinstall_script(self, is_autopkg: bool = False) -> str:
|
||||
"""
|
||||
"""
|
||||
|
||||
_script = ""
|
||||
|
||||
_script += self.__generate_shebang()
|
||||
|
||||
_script += self._generate_header_bar()
|
||||
_script += f"# {'AutoPkg Assets' if is_autopkg else 'OpenCore Legacy Patcher'} Post Install Script\n"
|
||||
_script += self._generate_header_bar()
|
||||
if is_autopkg:
|
||||
_script += "# Set UID, create alias, start patching, and reboot.\n"
|
||||
else:
|
||||
_script += "# Set SUID bit on helper tool, and create app alias.\n"
|
||||
_script += self._generate_header_bar()
|
||||
_script += "\n\n"
|
||||
|
||||
_script += self.zsh_functions.generate_standard_pkg_parameters()
|
||||
_script += "\n\n"
|
||||
|
||||
_script += "# MARK: Variables\n"
|
||||
_script += self._generate_label_bar()
|
||||
_script += "\n"
|
||||
|
||||
_script += "helperPath=\"Library/PrivilegedHelperTools/com.dortania.opencore-legacy-patcher.privileged-helper\"\n"
|
||||
_script += "mainAppPath=\"Library/Application Support/Dortania/OpenCore-Patcher.app\"\n"
|
||||
_script += "shimAppPath=\"Applications/OpenCore-Patcher.app\"\n"
|
||||
if is_autopkg:
|
||||
_script += "executablePath=\"$mainAppPath/Contents/MacOS/OpenCore-Patcher\"\n"
|
||||
|
||||
_script += "\n\n"
|
||||
|
||||
_script += "# MARK: Functions\n"
|
||||
_script += self._generate_label_bar()
|
||||
_script += "\n"
|
||||
|
||||
_script += self.zsh_functions.generate_set_suid_bit()
|
||||
_script += "\n"
|
||||
_script += self.zsh_functions.generate_create_alias()
|
||||
_script += "\n"
|
||||
_script += self.zsh_functions.generate_prewarm_gatekeeper()
|
||||
_script += "\n"
|
||||
if is_autopkg:
|
||||
_script += self.zsh_functions.generate_start_patching()
|
||||
_script += "\n"
|
||||
_script += self.zsh_functions.generate_log_file()
|
||||
_script += "\n"
|
||||
_script += self.zsh_functions.generate_fix_settings_file_permission()
|
||||
_script += "\n"
|
||||
_script += self.zsh_functions.generate_reboot()
|
||||
_script += "\n"
|
||||
|
||||
_script += self.zsh_functions.generate_postinstall_main(is_autopkg)
|
||||
_script += "\n\n"
|
||||
|
||||
_script += "# MARK: Main\n"
|
||||
_script += self._generate_label_bar()
|
||||
_script += "\n"
|
||||
|
||||
_script += "echo \"Starting postinstall script...\"\n"
|
||||
_script += "_main\n"
|
||||
|
||||
return _script
|
||||
|
||||
|
||||
def _generate_uninstall_script(self) -> str:
|
||||
"""
|
||||
"""
|
||||
_script = ""
|
||||
|
||||
_script += self.__generate_shebang()
|
||||
|
||||
_script += self._generate_header_bar()
|
||||
_script += f"# OpenCore Legacy Patcher Uninstall Script\n"
|
||||
_script += self._generate_header_bar()
|
||||
_script += "# Remove OpenCore Legacy Patcher files and directories.\n"
|
||||
_script += self._generate_header_bar()
|
||||
_script += "\n\n"
|
||||
|
||||
_script += self.zsh_functions.generate_standard_pkg_parameters()
|
||||
_script += "\n\n"
|
||||
|
||||
_script += "# MARK: Variables\n"
|
||||
_script += self._generate_label_bar()
|
||||
_script += "\n"
|
||||
|
||||
_files = self.files
|
||||
|
||||
_script += "filesToRemove=(\n"
|
||||
for _file in _files:
|
||||
_script += f" \"{_file}\"\n"
|
||||
|
||||
_script += ")\n"
|
||||
|
||||
_script += "\n\n"
|
||||
|
||||
_script += "# MARK: Functions\n"
|
||||
_script += self._generate_label_bar()
|
||||
_script += "\n"
|
||||
|
||||
_script += self.zsh_functions.generate_script_remove_file()
|
||||
_script += "\n"
|
||||
_script += self.zsh_functions.generate_clean_launch_service()
|
||||
_script += "\n"
|
||||
_script += self.zsh_functions.generate_uninstall_main()
|
||||
_script += "\n\n"
|
||||
|
||||
_script += "# MARK: Main\n"
|
||||
_script += self._generate_label_bar()
|
||||
_script += "\n"
|
||||
|
||||
_script += "echo \"Starting uninstall script...\"\n"
|
||||
_script += "_main\n"
|
||||
|
||||
return _script
|
||||
|
||||
|
||||
def preinstall_pkg(self) -> str:
|
||||
"""
|
||||
Generate preinstall script for PKG
|
||||
"""
|
||||
return self._generate_preinstall_script()
|
||||
|
||||
|
||||
def preinstall_autopkg(self) -> str:
|
||||
"""
|
||||
Generate preinstall script for AutoPkg
|
||||
"""
|
||||
return self._generate_preinstall_script(is_autopkg=True)
|
||||
|
||||
|
||||
def postinstall_pkg(self) -> str:
|
||||
"""
|
||||
Generate postinstall script for PKG
|
||||
"""
|
||||
return self._generate_postinstall_script()
|
||||
|
||||
|
||||
def postinstall_autopkg(self) -> str:
|
||||
"""
|
||||
Generate postinstall script for AutoPkg
|
||||
"""
|
||||
return self._generate_postinstall_script(is_autopkg=True)
|
||||
|
||||
|
||||
def uninstall(self) -> str:
|
||||
"""
|
||||
Generate uninstall script
|
||||
"""
|
||||
return self._generate_uninstall_script()
|
||||
@@ -4,6 +4,7 @@ shim.py: Generate Update Shim
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from opencore_legacy_patcher.volume import generate_copy_arguments
|
||||
from opencore_legacy_patcher.support import subprocess_wrapper
|
||||
|
||||
|
||||
@@ -25,9 +26,9 @@ class GenerateShim:
|
||||
if Path(self._shim_pkg).exists():
|
||||
Path(self._shim_pkg).unlink()
|
||||
|
||||
subprocess_wrapper.run_and_verify(["/bin/cp", "-R", self._build_pkg, self._shim_pkg])
|
||||
subprocess_wrapper.run_and_verify(generate_copy_arguments(self._build_pkg, self._shim_pkg))
|
||||
|
||||
if Path(self._output_shim).exists():
|
||||
Path(self._output_shim).unlink()
|
||||
|
||||
subprocess_wrapper.run_and_verify(["/bin/cp", "-R", self._shim_path, self._output_shim])
|
||||
subprocess_wrapper.run_and_verify(generate_copy_arguments(self._shim_path, self._output_shim))
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
#!/bin/zsh --no-rcs
|
||||
# ------------------------------------------------------
|
||||
# OpenCore Legacy Patcher PKG Post Install Script
|
||||
# ------------------------------------------------------
|
||||
# Set SUID bit on helper tool, and create app alias.
|
||||
# ------------------------------------------------------
|
||||
|
||||
|
||||
# MARK: PackageKit Parameters
|
||||
# ---------------------------
|
||||
|
||||
pathToScript=$0 # ex. /tmp/PKInstallSandbox.*/Scripts/*/preinstall
|
||||
pathToPackage=$1 # ex. ~/Downloads/Installer.pkg
|
||||
pathToTargetLocation=$2 # ex. '/', '/Applications', etc (depends on pkgbuild's '--install-location' argument)
|
||||
pathToTargetVolume=$3 # ex. '/', '/Volumes/MyVolume', etc
|
||||
pathToStartupDisk=$4 # ex. '/'
|
||||
|
||||
|
||||
# MARK: Variables
|
||||
# ---------------------------
|
||||
|
||||
helperPath="Library/PrivilegedHelperTools/com.dortania.opencore-legacy-patcher.privileged-helper"
|
||||
mainAppPath="Library/Application Support/Dortania/OpenCore-Patcher.app"
|
||||
shimAppPath="Applications/OpenCore-Patcher.app"
|
||||
|
||||
|
||||
# MARK: Functions
|
||||
# ---------------------------
|
||||
|
||||
function _setSUIDBit() {
|
||||
local binaryPath=$1
|
||||
|
||||
echo "Setting SUID bit on: $binaryPath"
|
||||
|
||||
# Check if path is a directory
|
||||
if [[ -d $binaryPath ]]; then
|
||||
/bin/chmod -R +s $binaryPath
|
||||
else
|
||||
/bin/chmod +s $binaryPath
|
||||
fi
|
||||
}
|
||||
|
||||
function _createAlias() {
|
||||
local mainPath=$1
|
||||
local aliasPath=$2
|
||||
|
||||
# Check if alias path exists
|
||||
if [[ -e $aliasPath ]]; then
|
||||
# Check if alias path is a symbolic link
|
||||
if [[ -L $aliasPath ]]; then
|
||||
echo "Removing old symbolic link: $aliasPath"
|
||||
/bin/rm -f $aliasPath
|
||||
else
|
||||
echo "Removing old file: $aliasPath"
|
||||
/bin/rm -rf $aliasPath
|
||||
fi
|
||||
fi
|
||||
|
||||
# Create symbolic link
|
||||
echo "Creating symbolic link: $aliasPath"
|
||||
/bin/ln -s $mainPath $aliasPath
|
||||
}
|
||||
|
||||
function _main() {
|
||||
_setSUIDBit "$pathToTargetVolume/$helperPath"
|
||||
_createAlias "$pathToTargetVolume/$mainAppPath" "$pathToTargetVolume/$shimAppPath"
|
||||
}
|
||||
|
||||
|
||||
# MARK: Main
|
||||
# ---------------------------
|
||||
|
||||
echo "Starting postinstall script..."
|
||||
_main
|
||||
@@ -1,79 +0,0 @@
|
||||
#!/bin/zsh --no-rcs
|
||||
# ------------------------------------------------------
|
||||
# OpenCore Legacy Patcher PKG Preinstall Script
|
||||
# ------------------------------------------------------
|
||||
# Remove old files, and prepare directories.
|
||||
# ------------------------------------------------------
|
||||
|
||||
|
||||
# MARK: PackageKit Parameters
|
||||
# ---------------------------
|
||||
|
||||
pathToScript=$0 # ex. /tmp/PKInstallSandbox.*/Scripts/*/preinstall
|
||||
pathToPackage=$1 # ex. ~/Downloads/Installer.pkg
|
||||
pathToTargetLocation=$2 # ex. '/', '/Applications', etc (depends on pkgbuild's '--install-location' argument)
|
||||
pathToTargetVolume=$3 # ex. '/', '/Volumes/MyVolume', etc
|
||||
pathToStartupDisk=$4 # ex. '/'
|
||||
|
||||
|
||||
# MARK: Variables
|
||||
# ---------------------------
|
||||
|
||||
filesToRemove=(
|
||||
"Applications/OpenCore-Patcher.app"
|
||||
"Library/Application Support/Dortania/Update.plist"
|
||||
"Library/Application Support/Dortania/OpenCore-Patcher.app"
|
||||
"Library/PrivilegedHelperTools/com.dortania.opencore-legacy-patcher.privileged-helper"
|
||||
)
|
||||
|
||||
|
||||
# MARK: Functions
|
||||
# ---------------------------
|
||||
|
||||
function _removeFile() {
|
||||
local file=$1
|
||||
|
||||
if [[ ! -e $file ]]; then
|
||||
# Check if file is a symbolic link
|
||||
if [[ -L $file ]]; then
|
||||
echo "Removing symbolic link: $file"
|
||||
/bin/rm -f $file
|
||||
fi
|
||||
return
|
||||
fi
|
||||
|
||||
echo "Removing file: $file"
|
||||
|
||||
# Check if file is a directory
|
||||
if [[ -d $file ]]; then
|
||||
/bin/rm -rf $file
|
||||
else
|
||||
/bin/rm -f $file
|
||||
fi
|
||||
}
|
||||
|
||||
function _createParentDirectory() {
|
||||
local file=$1
|
||||
|
||||
local parentDirectory="$(/usr/bin/dirname $file)"
|
||||
|
||||
# Check if parent directory exists
|
||||
if [[ ! -d $parentDirectory ]]; then
|
||||
echo "Creating parent directory: $parentDirectory"
|
||||
/bin/mkdir -p $parentDirectory
|
||||
fi
|
||||
}
|
||||
|
||||
function _main() {
|
||||
for file in $filesToRemove; do
|
||||
_removeFile $pathToTargetVolume/$file
|
||||
_createParentDirectory $pathToTargetVolume/$file
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
# MARK: Main
|
||||
# ---------------------------
|
||||
|
||||
echo "Starting preinstall script..."
|
||||
_main
|
||||
@@ -1,85 +0,0 @@
|
||||
#!/bin/zsh --no-rcs
|
||||
# ------------------------------------------------------
|
||||
# OpenCore Legacy Patcher PKG Uninstall Script
|
||||
# ------------------------------------------------------
|
||||
|
||||
|
||||
# MARK: PackageKit Parameters
|
||||
# ---------------------------
|
||||
|
||||
pathToScript=$0 # ex. /tmp/PKInstallSandbox.*/Scripts/*/preinstall
|
||||
pathToPackage=$1 # ex. ~/Downloads/Installer.pkg
|
||||
pathToTargetLocation=$2 # ex. '/', '/Applications', etc (depends on pkgbuild's '--install-location' argument)
|
||||
pathToTargetVolume=$3 # ex. '/', '/Volumes/MyVolume', etc
|
||||
pathToStartupDisk=$4 # ex. '/'
|
||||
|
||||
|
||||
# MARK: Variables
|
||||
# ---------------------------
|
||||
|
||||
filesToRemove=(
|
||||
"Applications/OpenCore-Patcher.app"
|
||||
"Library/Application Support/Dortania/Update.plist"
|
||||
"Library/Application Support/Dortania/OpenCore-Patcher.app"
|
||||
"Library/PrivilegedHelperTools/com.dortania.opencore-legacy-patcher.privileged-helper"
|
||||
)
|
||||
|
||||
|
||||
# MARK: Functions
|
||||
# ---------------------------
|
||||
|
||||
function _removeFile() {
|
||||
local file=$1
|
||||
|
||||
if [[ ! -e $file ]]; then
|
||||
# Check if file is a symbolic link
|
||||
if [[ -L $file ]]; then
|
||||
echo "Removing symbolic link: $file"
|
||||
/bin/rm -f $file
|
||||
fi
|
||||
return
|
||||
fi
|
||||
|
||||
echo "Removing file: $file"
|
||||
|
||||
# Check if file is a directory
|
||||
if [[ -d $file ]]; then
|
||||
/bin/rm -rf $file
|
||||
else
|
||||
/bin/rm -f $file
|
||||
fi
|
||||
}
|
||||
|
||||
function _cleanLaunchService() {
|
||||
local domain="com.dortania.opencore-legacy-patcher"
|
||||
|
||||
# Iterate over launch agents and daemons
|
||||
for launchServiceVariant in "$pathToTargetVolume/Library/LaunchAgents" "$pathToTargetVolume/Library/LaunchDaemons"; do
|
||||
# Check if directory exists
|
||||
if [[ ! -d $launchServiceVariant ]]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Iterate over launch service files
|
||||
for launchServiceFile in $(/bin/ls -1 $launchServiceVariant | /usr/bin/grep $domain); do
|
||||
local launchServicePath="$launchServiceVariant/$launchServiceFile"
|
||||
|
||||
# Remove launch service file
|
||||
_removeFile $launchServicePath
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
function _main() {
|
||||
_cleanLaunchService
|
||||
for file in $filesToRemove; do
|
||||
_removeFile "$pathToTargetVolume/$file"
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
# MARK: Main
|
||||
# ---------------------------
|
||||
|
||||
echo "Starting uninstall script..."
|
||||
_main
|
||||
@@ -42,7 +42,8 @@ class InstallerBackup:
|
||||
os_data.os_data.big_sur,
|
||||
os_data.os_data.monterey,
|
||||
os_data.os_data.ventura,
|
||||
os_data.os_data.sonoma
|
||||
os_data.os_data.sonoma,
|
||||
os_data.os_data.sequoia,
|
||||
],
|
||||
first_run: bool = False
|
||||
) -> None:
|
||||
@@ -57,6 +58,7 @@ class InstallerBackup:
|
||||
os_data.os_data.monterey: Path(self._directory, "12 Monterey"),
|
||||
os_data.os_data.ventura: Path(self._directory, "13 Ventura"),
|
||||
os_data.os_data.sonoma: Path(self._directory, "14 Sonoma"),
|
||||
os_data.os_data.sequoia: Path(self._directory, "15 Sequoia"),
|
||||
}
|
||||
|
||||
for os_version in self._supported_oses:
|
||||
|
||||
|
Before Width: | Height: | Size: 156 KiB After Width: | Height: | Size: 156 KiB |
|
Before Width: | Height: | Size: 320 KiB After Width: | Height: | Size: 320 KiB |
|
Before Width: | Height: | Size: 160 KiB After Width: | Height: | Size: 160 KiB |
@@ -131,6 +131,7 @@ module.exports = {
|
||||
'ICNS',
|
||||
'WINDOWS',
|
||||
'UNIVERSALCONTROL',
|
||||
'PROCESS',
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,9 +1,25 @@
|
||||
# Supported Models
|
||||
|
||||
### Application requirements
|
||||
The patcher application requires **OS X Yosemite 10.10** or later to run.
|
||||
* **OS X El Capitan 10.11** or later is required to make installers for macOS Ventura and later.
|
||||
|
||||
The patcher is designed to target **macOS Big Sur 11.x to macOS Sonoma 14.x**.
|
||||
* Other versions may work, albeit in a broken state. No support is provided for any version outside of the above.
|
||||
|
||||
-------
|
||||
|
||||
Any Intel-based Mac listed below can install and make use of OpenCore Legacy Patcher. To check your hardware model, open System Information and look for the `Model Identifier` key.
|
||||
* This applies even if Apple supports the model natively.
|
||||
* OpenCore Legacy Patcher does not support PowerPC- or Apple Silicon-based Macs.
|
||||
* If your model is not listed below, it is not supported by this patcher.
|
||||
|
||||
::: warning Note
|
||||
It is **extremely recommended** to update your Mac to its latest native version before using OpenCore Legacy Patcher, to ensure you're on the highest firmware.
|
||||
:::
|
||||
|
||||
|
||||
|
||||
The below tables can be used to reference issues with a particular model, and see which OS would work best on your machine.
|
||||
* [MacBook](#macbook)
|
||||
* [MacBook Air](#macbook-air)
|
||||
@@ -13,14 +29,6 @@ The below tables can be used to reference issues with a particular model, and se
|
||||
* [Mac Pro](#mac-pro)
|
||||
* [Xserve](#xserve)
|
||||
|
||||
::: details OpenCore Patcher application
|
||||
The patcher application requires **OS X Yosemite 10.10** or later to run.
|
||||
* **OS X El Capitan 10.11** or later is required to make installers for macOS Ventura and later.
|
||||
|
||||
The patcher is designed to target **macOS Big Sur 11.x to macOS Sonoma 14.x**.
|
||||
* Other versions may work, albeit in a broken state. No support is provided for any version outside of the above.
|
||||
:::
|
||||
|
||||
|
||||
### MacBook
|
||||
|
||||
@@ -50,8 +58,8 @@ The patcher is designed to target **macOS Big Sur 11.x to macOS Sonoma 14.x**.
|
||||
| MacBook Air (11-inch, Early 2015) | `MacBookAir7,1` | ^^ |
|
||||
| MacBook Air (13-inch, Early 2015)<br>MacBook Air (13-inch, 2017) | `MacBookAir7,2` | ^^ |
|
||||
| MacBook Air (Retina, 13-inch, 2018) | `MacBookAir8,1` | - Supported by Apple |
|
||||
| MacBook Air (Retina, 13-inch, 2019) | `MacBookAir9,1` | ^^ |
|
||||
| MacBook Air (Retina, 13-inch, 2020) | `MacBookAir10,1` | ^^ |
|
||||
| MacBook Air (Retina, 13-inch, 2019) | `MacBookAir8,2` | ^^ |
|
||||
| MacBook Air (Retina, 13-inch, 2020) | `MacBookAir9,1` | ^^ |
|
||||
|
||||
### MacBook Pro
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
* [Booting without USB drive](#booting-without-usb-drive)
|
||||
* [Booting seamlessly without Boot Picker](#booting-seamlessly-without-boot-picker)
|
||||
* [SIP settings](#sip-settings)
|
||||
* [Applying Post Install Volume Patches](#applying-post-install-volume-patches)
|
||||
|
||||
## Booting without USB drive
|
||||
@@ -24,23 +25,40 @@ To do this, run the OpenCore Patcher and head to Patcher Settings, then uncheck
|
||||
|
||||
Once you've toggled it off, build your OpenCore EFI once again and install to your desired drive. Now to show the OpenCore selector, you can simply hold down the "ESC" key while clicking on EFI boot, and then you can release the "ESC" key when you see the cursor arrow at the top left.
|
||||
|
||||
## Enabling SIP
|
||||
## SIP settings
|
||||
|
||||
For many users, SIP will be lowered by default on build. For Intel HD 4000 users, you may have noticed that SIP is partially disabled. This is to ensure full compatibility with macOS Monterey and allow seamless booting between it and older OSes. However for users who do not plan to boot Monterey, you can re-enable under Patcher Settings.
|
||||
SIP, or System Integrity Protection, needs to be lowered on systems where root patching is required to patch data on disk. This will vary between OS versions and the model in question. OCLP by default will determine the proper SIP options for the OS version and Mac model, in most cases the user has no need to touch these settings. However, this part explains how the SIP settings work in OCLP, where lowered SIP is needed and where full SIP could be enabled.
|
||||
|
||||
Note: Machines running macOS Ventura or systems with non-Metal GPUs cannot enable SIP outright, due to having a patched root volume. Enabling it will brick the installation.
|
||||
:::warning
|
||||
|
||||
Going forward with 0.6.6, SIP settings can be accessed from the Security tab shown in the images.
|
||||
If you're unsure whether you should change the SIP settings, leave them as-is. Systems where you have already ran the Post Install Root Patching cannot enable SIP without potentially breaking the current install.
|
||||
|
||||
:::
|
||||
|
||||
SIP settings can be accessed from the Security tab shown in the images. To change SIP settings, make the changes here, return in main menu and rebuild OpenCore using the first option.
|
||||
|
||||
| SIP Enabled | SIP Lowered (Root Patching) | SIP Disabled |
|
||||
| :--- | :--- | :--- |
|
||||
|  |  |  |
|
||||
|
||||
:::warning
|
||||
|
||||
If you're unsure whether you should enable SIP, leave it as-is. Systems where you have already ran the Post Install Root Patching cannot enable SIP without potentially breaking the current install.
|
||||
In the cases where SIP can be enabled, manually enabling it is needed. Easiest way to check whether you can fully enable SIP is the "Post Install Root Patch" section, if that section tells your system doesn't need patches (or you don't install the patches e.g. in case you don't need WiFi on a Mac Pro with upgraded GPU running Monterey) then it is safe to assume full SIP can be enabled.
|
||||
|
||||
:::
|
||||
**Ventura and newer**
|
||||
|
||||
All unsupported systems require lowered SIP.
|
||||
|
||||
**Monterey**
|
||||
|
||||
Majority of unsupported systems from 2013 onward can enable full SIP.
|
||||
Pre-2012 systems, also known as "non-Metal" (includes Mac Pros without upgraded GPU), as well as NVIDIA Kepler and Intel HD 4000 GPUs require lowered SIP.
|
||||
|
||||
Some systems such as Mac Pros also require root patching for stock WiFi cards but if you do not need WiFi or you plan to upgrade the card, there is no need for root patching and as such SIP can be fully enabled.
|
||||
|
||||
**Big Sur**
|
||||
|
||||
All Metal capable systems from 2012 onward (incl. NVIDIA Kepler and Intel HD 4000) as well as Mac Pros with upgraded GPU can run with full SIP enabled.
|
||||
Non-Metal systems still require lowered SIP.
|
||||
|
||||
## Applying Post Install Volume Patches
|
||||
|
||||
|
||||
19
docs/PROCESS.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Background process
|
||||
|
||||
OpenCore Legacy Patcher utilizes a background process to:
|
||||
- Check for mismatched configurations and warn the user (e.g. installed MacBookPro11,1 config on MacBookPro11,5)
|
||||
- Monitor the status of installed Root Patches and OpenCore
|
||||
- Ask you to install Root Patches in case they aren't detected (typically after an update)
|
||||
- Check whether OpenCore is being booted from USB drive or internal drive
|
||||
- Ask you to install OpenCore on the internal disk in case booted from USB
|
||||
- React to upcoming updates requiring a new KDK to be downloaded, starting KDK download automatically
|
||||
|
||||
It is recommended to keep the background process enabled for smoothest functionality. e.g. to try and avoid failed patching when new KDK is not found.
|
||||
|
||||
If you decide to disable the background process, the KDK installation for each update has to be done manually. OCLP is also unable to detect Root Patches on boot, meaning manually opening the app and root patching is required.
|
||||
|
||||
::: warning Note:
|
||||
|
||||
In some cases macOS may report background process being added by "Mykola Grymalyuk", this happens due to a macOS bug where sometimes the developer name who sent the app for notarization is shown instead of the application name.
|
||||
Dortania cannot do anything about this.
|
||||
:::
|
||||
@@ -1,206 +1,264 @@
|
||||
# Troubleshooting
|
||||
|
||||
Here are some common errors that users may experience while using this patcher:
|
||||
|
||||
* [OpenCore Legacy Patcher not launching](#opencore-legacy-patcher-not-launching)
|
||||
* [Stuck on `This version of Mac OS X is not supported on this platform` or (🚫) Prohibited Symbol](#stuck-on-this-version-of-mac-os-x-is-not-supported-on-this-platform-or-(🚫)-prohibited-symbol)
|
||||
* [Cannot boot macOS without the USB](#cannot-boot-macos-without-the-usb)
|
||||
* [Infinite Recovery OS Booting](#infinite-recovery-os-reboot)
|
||||
* [Stuck on boot after root patching](#stuck-on-boot-after-root-patching)
|
||||
* [Reboot when entering Hibernation (`Sleep Wake Failure`)](#reboot-when-entering-hibernation-sleep-wake-failure)
|
||||
* [How to Boot Recovery through OpenCore Legacy Patcher](#how-to-boot-recovery-through-opencore-legacy-patcher)
|
||||
* [Stuck on "Your Mac needs a firmware update"](#stuck-on-your-mac-needs-a-firmware-update)
|
||||
* [No Brightness Control](#no-brightness-control)
|
||||
* [Cannot connect Wi-Fi on Monterey with legacy cards](#cannot-connect-Wi-Fi-on-Monterey-with-legacy-cards)
|
||||
* [No Graphics Acceleration](#no-graphics-acceleration)
|
||||
* [Black Screen on MacBookPro11,3 in macOS Monterey](#black-screen-on-macbookpro113-in-macos-monterey)
|
||||
* [No DisplayPort Output on Mac Pros with NVIDIA Kepler](#no-displayport-output-on-mac-pros-with-NVIDIA-kepler)
|
||||
* [Volume Hash Mismatch Error in macOS Monterey](#volume-hash-mismatch-error-in-macos-monterey)
|
||||
* [Cannot Disable SIP in recoveryOS](#cannot-disable-sip-in-recoveryos)
|
||||
* [Stuck on "Less than a minute remaining..."](#stuck-on-less-than-a-minute-remaining)
|
||||
* [No acceleration after a Metal GPU swap on Mac Pro](#no-acceleration-after-a-metal-gpu-swap-on-mac-pro)
|
||||
* [Keyboard, Mouse and Trackpad not working in installer or after update](#keyboard-mouse-and-trackpad-not-working-in-installer-or-after-update)
|
||||
|
||||
|
||||
## OpenCore Legacy Patcher not launching
|
||||
|
||||
If the application won't launch (e.g. icon will bounce in the Dock), try launching OCLP via Terminal by typing the following command, make sure you've moved the app to `/Applications` before this.
|
||||
|
||||
```sh
|
||||
/Applications/OpenCore-Patcher.app/Contents/MacOS/OpenCore-Patcher
|
||||
```
|
||||
|
||||
## Stuck on `This version of Mac OS X is not supported on this platform` or (🚫) Prohibited Symbol
|
||||
|
||||
This means macOS has detected an SMBIOS it does not support. To resolve this, ensure you're booting OpenCore **before** the macOS installer in the boot picker. Reminder that the option will be called `EFI Boot`.
|
||||
|
||||
Once you've booted OpenCore at least once, your hardware should now auto-boot it until either an NVRAM reset occurs, or you remove the drive with OpenCore installed.
|
||||
|
||||
However, if the 🚫 Symbol only appears after the boot process has already started (the bootscreen appears/verbose boot starts), it could mean that your USB drive has failed to pass macOS' integrity checks. To resolve this, create a new installer using a different USB drive (preferably of a different model.)
|
||||
|
||||
## Cannot boot macOS without the USB
|
||||
|
||||
By default, the OpenCore Patcher won't install OpenCore onto the internal drive itself during installs.
|
||||
|
||||
After installing macOS, OpenCore Legacy Patcher should automatically prompt you to install OpenCore onto the internal drive. However, if it doesn't show the prompt, you'll need to either [manually transfer](https://dortania.github.io/OpenCore-Post-Install/universal/oc2hdd.html) OpenCore to the internal drive's EFI or Build and Install again and select your internal drive.
|
||||
|
||||
Reminder that once this is done, you'll need to select OpenCore in the boot picker again for your hardware to remember this entry and auto boot from then on.
|
||||
|
||||
## Infinite Recovery OS Booting
|
||||
|
||||
With OpenCore Legacy Patcher, we rely on Apple Secure Boot to ensure OS updates work correctly and reliably with Big Sur. However this installs NVRAM variables that will confuse your Mac if not running with OpenCore. To resolve this, simply uninstall OpenCore and [reset NVRAM](https://support.apple.com/en-mide/HT201255).
|
||||
|
||||
* Note: Machines with modified root volumes will also result in an infinite recovery loop until integrity is restored.
|
||||
|
||||
## Stuck on boot after root patching
|
||||
|
||||
Boot into recovery by pressing space when your disk is selected on the OCLP bootpicker (if you have it hidden, hold ESC while starting up)
|
||||
|
||||
* **Note:** If your disk name is something else than "Macintosh HD", make sure to change the path accordingly. You can figure out your disk name by typing `ls /Volumes`.
|
||||
|
||||
Go into terminal and first mount the disk by typing
|
||||
```sh
|
||||
mount -uw "/Volumes/Macintosh HD"
|
||||
```
|
||||
Then revert the snapshot
|
||||
```sh
|
||||
bless --mount "/Volumes/Macintosh HD" --bootefi --last-sealed-snapshot
|
||||
```
|
||||
Now we're going to clean the /Library/Extensions folder from offending kexts while keeping needed ones.
|
||||
|
||||
Run the following and **make sure to type it carefully**
|
||||
|
||||
::: warning
|
||||
If you have **FileVault 2 enabled**, you will need to mount the Data volume first. This can be done in Disk Utility by locating your macOS volume name, selecting its Data volume, and selecting the Mount option in the toolbar.
|
||||
:::
|
||||
|
||||
```sh
|
||||
cd "/Volumes/Macintosh HD - Data/Library/Extensions" && ls | grep -v "HighPoint*\|SoftRAID*" | xargs rm -rf
|
||||
```
|
||||
|
||||
Then restart and now your system should be restored to the unpatched snapshot and should be able to boot again.
|
||||
|
||||
|
||||
|
||||
## Reboot when entering Hibernation (`Sleep Wake Failure`)
|
||||
|
||||
[Known issue on some models](https://github.com/dortania/Opencore-Legacy-Patcher/issues/72), a temporary fix is to disable Hibernation by executing the following command in the terminal:
|
||||
|
||||
```
|
||||
sudo pmset -a hibernatemode 0
|
||||
```
|
||||
|
||||
## How to Boot Recovery through OpenCore Legacy Patcher
|
||||
|
||||
By default, the patcher will try to hide extra boot options such as recovery from the user. To make them appear, simply press the `Spacebar` key while inside OpenCore's Picker to list all boot options.
|
||||
|
||||
## Stuck on "Your Mac needs a firmware update"
|
||||
|
||||
Full error: "Your Mac needs a firmware update in order to install to this Volume. Please select a Mac OS Extended (Journaled) volume instead."
|
||||
|
||||
This error occurs when macOS determines that the current firmware does not have full APFS support. To resolve this, when installing OpenCore, head to "Patcher Settings" and enable "Moderate SMBIOS Patching" or higher. This will ensure that the firmware reported will show support for full APFS capabilities.
|
||||
|
||||
## No Brightness Control
|
||||
|
||||
With OCLP v0.0.22, we've added support for brightness control on many models. However, some users may have noticed that their brightness keys do not work.
|
||||
|
||||
As a work-around, we recommend users try out the below app:
|
||||
|
||||
* [Brightness Slider](https://actproductions.net/free-apps/brightness-slider/)
|
||||
|
||||
## Cannot connect Wi-Fi on Monterey with legacy cards
|
||||
|
||||
With OCLP v0.2.5, we've added support for legacy Wi-Fi on Monterey. However, some users may have noticed that they can't connect to wireless networks.
|
||||
|
||||
To work-around this, we recommend that users manually connect using the "Other" option in the Wi-Fi menu bar or manually adding the network in the "Network" preference pane.
|
||||
|
||||
## No Graphics Acceleration
|
||||
|
||||
In macOS, GPU drivers are often dropped from the OS with each major release of it. With macOS Big Sur, currently, all non-Metal GPUs require additional patches to gain acceleration. In addition, macOS Monterey removed Graphics Drivers for both Intel Ivy Bridge and NVIDIA Kepler graphics processors.
|
||||
|
||||
If you're using OCLP v0.4.4, you should have been prompted to install Root Volume patches after the first boot from installation of macOS. If you need to do this manually, you can do so within the patcher app. Once rebooted, acceleration will be re-enabled as well as brightness control for laptops.
|
||||
|
||||
## Black Screen on MacBookPro11,3 in macOS Monterey
|
||||
|
||||
Due to Apple dropping NVIDIA Kepler support in macOS Monterey, [MacBookPro11,3's GMUX has difficulties switching back to the iGPU to display macOS correctly.](https://github.com/dortania/OpenCore-Legacy-Patcher/issues/522) To work-around this issue, boot the MacBookPro11,3 in Safe Mode and once macOS is installed, run OCLP's Post Install Root Patches to enable GPU Acceleration for the NVIDIA dGPU.
|
||||
|
||||
* Safe Mode can be started by holding `Shift` + `Enter` when selecting macOS Monterey in OCLP's Boot Menu.
|
||||
|
||||
## No DisplayPort Output on Mac Pros with NVIDIA Kepler
|
||||
|
||||
If you're having trouble with DisplayPort output on Mac Pros, try enabling Minimal Spoofing in Settings -> SMBIOS Settings and rebuild/install OpenCore. This will trick macOS drivers into thinking you have a newer MacPro7,1 and resolve the issue.
|
||||
|
||||

|
||||
|
||||
## Volume Hash Mismatch Error in macOS Monterey
|
||||
|
||||
A semi-common popup some users face is the "Volume Hash Mismatch" error:
|
||||
|
||||
<p align="center">
|
||||
<img src="./images/Hash-Mismatch.png">
|
||||
</p>
|
||||
|
||||
What this error signifies is that the OS detects that the boot volume's hash does not match what the OS is expecting, this error is generally cosmetic and can be ignored. However if your system starts to crash spontaneously shortly after, you'll want to reinstall macOS fresh without importing any data at first.
|
||||
|
||||
* Note that this bug affects native Macs as well and is not due to issues with unsupported Macs: [OSX Daily: “Volume Hash Mismatch” Error in MacOS Monterey](https://osxdaily.com/2021/11/10/volume-hash-mismatch-error-in-macos-monterey/)
|
||||
|
||||
Additionally, it can help to disable FeatureUnlock in Settings -> Misc Settings as this tool can be strenuous on systems with weaker memory stability.
|
||||
|
||||
## Cannot Disable SIP in recoveryOS
|
||||
|
||||
With OCLP, the patcher will always overwrite the current SIP value on boot to ensure that users don't brick an installation after an NVRAM reset. However, for users wanting to disable SIP entirely, this can be done easily.
|
||||
|
||||
Head into the GUI, go to Patcher Settings, and toggle the bits you need disabled from SIP:
|
||||
|
||||
| SIP Enabled | SIP Lowered (Root Patching) | SIP Disabled |
|
||||
| :--- | :--- | :--- |
|
||||
|  |  |  |
|
||||
|
||||
## Intermediate issues with USB 1.1 and Bluetooth on MacPro3,1 - MacPro5,1
|
||||
|
||||
For those experiencing issues with USB 1.1 devices (such as mice, keyboards and bluetooth chipsets), macOS Big Sur and newer have weakened OS-side reliability for the UHCI controller in older Mac Pros.
|
||||
|
||||
* UHCI is a USB 1.1 controller that is hooked together with the USB 2.0 ports in your system. Whenever a USB 1.1 device is detected, the UHCI controller is given ownership of the device at a hardware/firmware level.
|
||||
* EHCI is the USB 2.0 controller in older Mac Pros
|
||||
|
||||
Because of this, we recommend placing a USB 2.0/3.0 hub between your devices and the port on the Mac Pro. UHCI and EHCI cannot both be used at once, so using a USB hub will always force the EHCI controller on.
|
||||
|
||||
* Alternatively, you can try cold-starting the hardware and see if macOS recognizes the UHCI controller properly.
|
||||
|
||||
## Stuck on "Less than a minute remaining..."
|
||||
|
||||
A common area for systems to get "stuck", namely for units that are missing the `AES` CPU instruction/older mobile hardware. During this stage, a lot of heavy cryptography is performed, which can make systems appear to be stuck. In reality they are working quite hard to finish up the installation.
|
||||
|
||||
Because this step can take a few hours or more depending on drive speeds, be patient at this stage and do not manually power off or reboot your machine as this will break the installation and require you to reinstall. If you think your system has stalled, press the Caps Lock key. If the light turns on, your system is busy and not actually frozen.
|
||||
|
||||
## No acceleration after a Metal GPU swap on Mac Pro
|
||||
|
||||
If you finished installing Monterey with the original card installed (to see bootpicker for example) and swapped your GPU to a Metal supported one, you may notice that you're missing acceleration. To fix this, open OCLP and revert root patches to get your Metal-supported GPU work again.
|
||||
|
||||
Alternatively, you can remove "AutoPkg-Assets.pkg" from /Library/Packages on the USB drive before proceeding with the installation. To see the folder, enable hidden files with `Command` + `Shift` + `.`
|
||||
|
||||
The reason for this is that the autopatcher will assume that you will be using the original graphics card and therefore does non-metal patching, which includes removing some drivers for other cards. This causes Metal cards to not accelerate after swapping.
|
||||
|
||||
## Keyboard, Mouse and Trackpad not working in installer or after update
|
||||
|
||||
For Macs using legacy USB 1.1 controllers, OpenCore Legacy Patcher can only restore support once it has performed root volume patches. Thus to install macOS, you need to hook up a USB hub between your Mac and Keyboard/Mouse.
|
||||
|
||||
* For MacBook users, you'll need to find an external keyboard/mouse in addition to the USB hub
|
||||
|
||||
More information can be found here:
|
||||
|
||||
* [Legacy UHCI/OHCI support in Ventura #1021](https://github.com/dortania/OpenCore-Legacy-Patcher/issues/1021)
|
||||
|
||||
Applicable models include:
|
||||
|
||||
| Family | Year | Model | Notes |
|
||||
| :---------- | :--------------------| :---------------------------- | :----------------------------------------------- |
|
||||
| MacBook | Mid 2010 and older | MacBook5,1 - MacBook7,1 | |
|
||||
| MacBook Air | Late 2010 and older | MacBookAir2,1 - MacBookAir3,x | |
|
||||
| MacBook Pro | Mid 2010 and older | MacBookPro4,1 - MacBookPro7,x | Excludes Mid 2010 15" and 17" (MacBookPro6,x) |
|
||||
| iMac | Late 2009 and older | iMac7,1 - iMac10,x | Excludes Core i5/7 27" late 2009 iMac (iMac11,1) |
|
||||
| Mac mini | Mid 2011 and older | Macmini3,1 - Macmini5,x | |
|
||||
| Mac Pro | Mid 2010 and older | MacPro3,1 - MacPro5,1 | |
|
||||
|
||||
|
||||

|
||||
# Troubleshooting
|
||||
|
||||
Here are some common errors that users may experience while using this patcher:
|
||||
|
||||
* [OpenCore Legacy Patcher not launching](#opencore-legacy-patcher-not-launching)
|
||||
* ["You don't have permission to save..." error when creating USB installer](#you-don-t-have-permission-to-save-error-when-creating-usb-installer)
|
||||
* [Stuck on `This version of Mac OS X is not supported on this platform` or (🚫) Prohibited Symbol](#stuck-on-this-version-of-mac-os-x-is-not-supported-on-this-platform-or-🚫-prohibited-symbol)
|
||||
* [Cannot boot macOS without the USB](#cannot-boot-macos-without-the-usb)
|
||||
* [Infinite Recovery OS Booting](#infinite-recovery-os-reboot)
|
||||
* [Stuck on boot after root patching](#stuck-on-boot-after-root-patching)
|
||||
* ["Unable to resolve dependencies, error code 71" when root patching](#unable-to-resolve-dependencies-error-code-71-when-root-patching)
|
||||
* [Reboot when entering Hibernation (`Sleep Wake Failure`)](#reboot-when-entering-hibernation-sleep-wake-failure)
|
||||
* [How to Boot Recovery through OpenCore Legacy Patcher](#how-to-boot-recovery-through-opencore-legacy-patcher)
|
||||
* [Stuck on "Your Mac needs a firmware update"](#stuck-on-your-mac-needs-a-firmware-update)
|
||||
* [No Brightness Control](#no-brightness-control)
|
||||
* [Cannot connect Wi-Fi on Monterey with legacy cards](#cannot-connect-Wi-Fi-on-Monterey-with-legacy-cards)
|
||||
* [No Graphics Acceleration](#no-graphics-acceleration)
|
||||
* [Black Screen on MacBookPro11,3 in macOS Monterey](#black-screen-on-macbookpro113-in-macos-monterey)
|
||||
* [No DisplayPort Output on Mac Pros with NVIDIA Kepler](#no-displayport-output-on-mac-pros-with-NVIDIA-kepler)
|
||||
* [Volume Hash Mismatch Error in macOS Monterey](#volume-hash-mismatch-error-in-macos-monterey)
|
||||
* [Cannot Disable SIP in recoveryOS](#cannot-disable-sip-in-recoveryos)
|
||||
* [Stuck on "Less than a minute remaining..."](#stuck-on-less-than-a-minute-remaining)
|
||||
* [No acceleration after a Metal GPU swap on Mac Pro](#no-acceleration-after-a-metal-gpu-swap-on-mac-pro)
|
||||
* [Keyboard, Mouse and Trackpad not working in installer or after update](#keyboard-mouse-and-trackpad-not-working-in-installer-or-after-update)
|
||||
|
||||
|
||||
## OpenCore Legacy Patcher not launching
|
||||
|
||||
If the application won't launch (e.g. icon will bounce in the Dock), try launching OCLP via Terminal by typing the following command, make sure you've moved the app to `/Applications` before this.
|
||||
|
||||
```sh
|
||||
/Applications/OpenCore-Patcher.app/Contents/MacOS/OpenCore-Patcher
|
||||
```
|
||||
|
||||
## "You don't have permission to save..." error when creating USB installer
|
||||
|
||||
In some cases, a following error saying "The bless of the installer disk failed" stating the reason as "You don't have permission to save..." may appear.
|
||||
|
||||
|
||||
<div align="center">
|
||||
<img src="./images/Error-No-Permission-To-Save.png" alt="NoPermissionToSave" width="400" />
|
||||
</div>
|
||||
|
||||
|
||||
To resolve this, you may try adding Full Disk Access permission for OpenCore Legacy Patcher. To add it, first go to the settings
|
||||
|
||||
* Ventura and Sonoma: Go to System Settings -> Privacy and Security -> Full Disk Access
|
||||
|
||||
* Big Sur and Monterey: Go to System Preferences -> Security and Privacy -> Full Disk Access
|
||||
|
||||
Enable OpenCore-Patcher in the list. If not found on the list, press the + sign to add a new entity and find OpenCore Legacy Patcher from Applications.
|
||||
|
||||
Restart OpenCore Legacy Patcher and try creating your USB drive again.
|
||||
|
||||
Optional: After you've created your USB drive, you can remove OpenCore Legacy Patcher from Full Disk Access again.
|
||||
|
||||
|
||||
## Stuck on `This version of Mac OS X is not supported on this platform` or (🚫) Prohibited Symbol
|
||||
|
||||
This means macOS has detected an SMBIOS it does not support. To resolve this, ensure you're booting OpenCore **before** the macOS installer in the boot picker. Reminder that the option will be called `EFI Boot`.
|
||||
|
||||
Once you've booted OpenCore at least once, your hardware should now auto-boot it until either an NVRAM reset occurs, or you remove the drive with OpenCore installed.
|
||||
|
||||
However, if the 🚫 Symbol only appears after the boot process has already started (the bootscreen appears/verbose boot starts), it could mean that your USB drive has failed to pass macOS' integrity checks. To resolve this, create a new installer using a different USB drive (preferably of a different model.)
|
||||
|
||||
## Cannot boot macOS without the USB
|
||||
|
||||
By default, the OpenCore Patcher won't install OpenCore onto the internal drive itself during installs.
|
||||
|
||||
After installing macOS, OpenCore Legacy Patcher should automatically prompt you to install OpenCore onto the internal drive. However, if it doesn't show the prompt, you'll need to either [manually transfer](https://dortania.github.io/OpenCore-Post-Install/universal/oc2hdd.html) OpenCore to the internal drive's EFI or Build and Install again and select your internal drive.
|
||||
|
||||
Reminder that once this is done, you'll need to select OpenCore in the boot picker again for your hardware to remember this entry and auto boot from then on.
|
||||
|
||||
## Infinite Recovery OS Booting
|
||||
|
||||
With OpenCore Legacy Patcher, we rely on Apple Secure Boot to ensure OS updates work correctly and reliably with Big Sur. However this installs NVRAM variables that will confuse your Mac if not running with OpenCore. To resolve this, simply uninstall OpenCore and [reset NVRAM](https://support.apple.com/en-mide/HT201255).
|
||||
|
||||
* Note: Machines with modified root volumes will also result in an infinite recovery loop until integrity is restored.
|
||||
|
||||
## Stuck on boot after root patching
|
||||
|
||||
Boot into recovery by pressing space when your disk is selected on the OCLP bootpicker (if you have it hidden, hold ESC while starting up)
|
||||
|
||||
* **Note:** If your disk name is something else than "Macintosh HD", make sure to change the path accordingly. You can figure out your disk name by typing `ls /Volumes`.
|
||||
|
||||
Go into terminal and first mount the disk by typing
|
||||
```sh
|
||||
mount -uw "/Volumes/Macintosh HD"
|
||||
```
|
||||
Then revert the snapshot
|
||||
```sh
|
||||
bless --mount "/Volumes/Macintosh HD" --bootefi --last-sealed-snapshot
|
||||
```
|
||||
Now we're going to clean the /Library/Extensions folder from offending kexts while keeping needed ones.
|
||||
|
||||
Run the following and **make sure to type it carefully**
|
||||
|
||||
::: warning
|
||||
If you have **FileVault 2 enabled**, you will need to mount the Data volume first. This can be done in Disk Utility by locating your macOS volume name, selecting its Data volume, and selecting the Mount option in the toolbar.
|
||||
:::
|
||||
|
||||
```sh
|
||||
cd "/Volumes/Macintosh HD - Data/Library/Extensions" && ls | grep -v "HighPoint*\|SoftRAID*" | xargs rm -rf
|
||||
```
|
||||
|
||||
Then restart and now your system should be restored to the unpatched snapshot and should be able to boot again.
|
||||
|
||||
## "Unable to resolve dependencies, error code 71" when root patching
|
||||
|
||||
If you're getting this error, it typically means you have some offending kernel extensions, to fix this you will have to clear them.
|
||||
|
||||
Semi-automated way:
|
||||
|
||||
1. Open Terminal
|
||||
2. Type `sudo zsh`
|
||||
3. Type `cd "/Volumes/Macintosh HD/Library/Extensions" && ls | grep -v "HighPoint*\|SoftRAID*" | xargs rm -rf`
|
||||
* Make sure to rename "Macintosh HD" to what your drive name is
|
||||
4. Run OCLP root patcher again
|
||||
|
||||
Manual way:
|
||||
|
||||
1. Navigate to /Library/Extensions
|
||||
2. Delete everything **except** HighPointIOP.kext, HighPointRR.kext and SoftRAID.kext
|
||||
3. Run OCLP root patcher again
|
||||
|
||||
If there is no success, navigate to "/Library/Developer/KDKs" and delete everything.
|
||||
|
||||
If still no success, type `sudo bless --mount "/Volumes/Macintosh HD/" --bootefi --last-sealed-snapshot`
|
||||
* Make sure again to rename "Macintosh HD" to what your drive name is
|
||||
|
||||
Run OCLP root patcher again.
|
||||
|
||||
## Reboot when entering Hibernation (`Sleep Wake Failure`)
|
||||
|
||||
[Known issue on some models](https://github.com/dortania/Opencore-Legacy-Patcher/issues/72), a temporary fix is to disable Hibernation by executing the following command in the terminal:
|
||||
|
||||
```
|
||||
sudo pmset -a hibernatemode 0
|
||||
```
|
||||
|
||||
## How to Boot Recovery through OpenCore Legacy Patcher
|
||||
|
||||
By default, the patcher will try to hide extra boot options such as recovery from the user. To make them appear, simply press the `Spacebar` key while inside OpenCore's Picker to list all boot options.
|
||||
|
||||
## Stuck on "Your Mac needs a firmware update"
|
||||
|
||||
Full error: "Your Mac needs a firmware update in order to install to this Volume. Please select a Mac OS Extended (Journaled) volume instead."
|
||||
|
||||
This error occurs when macOS determines that the current firmware does not have full APFS support. To resolve this, when installing OpenCore, head to "Patcher Settings" and enable "Moderate SMBIOS Patching" or higher. This will ensure that the firmware reported will show support for full APFS capabilities.
|
||||
|
||||
## No Brightness Control
|
||||
|
||||
With OCLP v0.0.22, we've added support for brightness control on many models. However, some users may have noticed that their brightness keys do not work.
|
||||
|
||||
As a work-around, we recommend users try out the below app:
|
||||
|
||||
* [Brightness Slider](https://actproductions.net/free-apps/brightness-slider/)
|
||||
|
||||
## Cannot connect Wi-Fi on Monterey with legacy cards
|
||||
|
||||
With OCLP v0.2.5, we've added support for legacy Wi-Fi on Monterey. However, some users may have noticed that they can't connect to wireless networks.
|
||||
|
||||
To work-around this, we recommend that users manually connect using the "Other" option in the Wi-Fi menu bar or manually adding the network in the "Network" preference pane.
|
||||
|
||||
## No Graphics Acceleration
|
||||
|
||||
In macOS, GPU drivers are often dropped from the OS with each major release of it. With macOS Big Sur, currently, all non-Metal GPUs require additional patches to gain acceleration. In addition, macOS Monterey removed Graphics Drivers for both Intel Ivy Bridge and NVIDIA Kepler graphics processors.
|
||||
|
||||
If you're using OCLP v0.4.4, you should have been prompted to install Root Volume patches after the first boot from installation of macOS. If you need to do this manually, you can do so within the patcher app. Once rebooted, acceleration will be re-enabled as well as brightness control for laptops.
|
||||
|
||||
## Black Screen on MacBookPro11,3 in macOS Monterey
|
||||
|
||||
Due to Apple dropping NVIDIA Kepler support in macOS Monterey, [MacBookPro11,3's GMUX has difficulties switching back to the iGPU to display macOS correctly.](https://github.com/dortania/OpenCore-Legacy-Patcher/issues/522) To work-around this issue, boot the MacBookPro11,3 in Safe Mode and once macOS is installed, run OCLP's Post Install Root Patches to enable GPU Acceleration for the NVIDIA dGPU.
|
||||
|
||||
* Safe Mode can be started by holding `Shift` + `Enter` when selecting macOS Monterey in OCLP's Boot Menu.
|
||||
|
||||
## No DisplayPort Output on Mac Pros with NVIDIA Kepler
|
||||
|
||||
If you're having trouble with DisplayPort output on Mac Pros, try enabling Minimal Spoofing in Settings -> SMBIOS Settings and rebuild/install OpenCore. This will trick macOS drivers into thinking you have a newer MacPro7,1 and resolve the issue.
|
||||
|
||||

|
||||
|
||||
## Volume Hash Mismatch Error in macOS Monterey
|
||||
|
||||
A semi-common popup some users face is the "Volume Hash Mismatch" error:
|
||||
|
||||
<p align="center">
|
||||
<img src="./images/Hash-Mismatch.png">
|
||||
</p>
|
||||
|
||||
What this error signifies is that the OS detects that the boot volume's hash does not match what the OS is expecting, this error is generally cosmetic and can be ignored. However if your system starts to crash spontaneously shortly after, you'll want to reinstall macOS fresh without importing any data at first.
|
||||
|
||||
* Note that this bug affects native Macs as well and is not due to issues with unsupported Macs: [OSX Daily: “Volume Hash Mismatch” Error in MacOS Monterey](https://osxdaily.com/2021/11/10/volume-hash-mismatch-error-in-macos-monterey/)
|
||||
|
||||
Additionally, it can help to disable FeatureUnlock in Settings -> Misc Settings as this tool can be strenuous on systems with weaker memory stability.
|
||||
|
||||
## Cannot Disable SIP in recoveryOS
|
||||
|
||||
With OCLP, the patcher will always overwrite the current SIP value on boot to ensure that users don't brick an installation after an NVRAM reset. However, for users wanting to disable SIP entirely, this can be done easily.
|
||||
|
||||
Head into the GUI, go to Patcher Settings, and toggle the bits you need disabled from SIP:
|
||||
|
||||
| SIP Enabled | SIP Lowered (Root Patching) | SIP Disabled |
|
||||
| :--- | :--- | :--- |
|
||||
|  |  |  |
|
||||
|
||||
## Intermediate issues with USB 1.1 and Bluetooth on MacPro3,1 - MacPro5,1
|
||||
|
||||
For those experiencing issues with USB 1.1 devices (such as mice, keyboards and bluetooth chipsets), macOS Big Sur and newer have weakened OS-side reliability for the UHCI controller in older Mac Pros.
|
||||
|
||||
* UHCI is a USB 1.1 controller that is hooked together with the USB 2.0 ports in your system. Whenever a USB 1.1 device is detected, the UHCI controller is given ownership of the device at a hardware/firmware level.
|
||||
* EHCI is the USB 2.0 controller in older Mac Pros
|
||||
|
||||
Because of this, we recommend placing a USB 2.0/3.0 hub between your devices and the port on the Mac Pro. UHCI and EHCI cannot both be used at once, so using a USB hub will always force the EHCI controller on.
|
||||
|
||||
* Alternatively, you can try cold-starting the hardware and see if macOS recognizes the UHCI controller properly.
|
||||
|
||||
## Stuck on "Less than a minute remaining..."
|
||||
|
||||
A common area for systems to get "stuck", namely for units that are missing the `AES` CPU instruction/older mobile hardware. During this stage, a lot of heavy cryptography is performed, which can make systems appear to be stuck. In reality they are working quite hard to finish up the installation.
|
||||
|
||||
Because this step can take a few hours or more depending on drive speeds, be patient at this stage and do not manually power off or reboot your machine as this will break the installation and require you to reinstall. If you think your system has stalled, press the Caps Lock key. If the light turns on, your system is busy and not actually frozen.
|
||||
|
||||
## No acceleration after a Metal GPU swap on Mac Pro
|
||||
|
||||
If you finished installing Monterey with the original card installed (to see bootpicker for example) and swapped your GPU to a Metal supported one, you may notice that you're missing acceleration. To fix this, open OCLP and revert root patches to get your Metal-supported GPU work again.
|
||||
|
||||
Alternatively, you can remove "AutoPkg-Assets.pkg" from /Library/Packages on the USB drive before proceeding with the installation. To see the folder, enable hidden files with `Command` + `Shift` + `.`
|
||||
|
||||
The reason for this is that the autopatcher will assume that you will be using the original graphics card and therefore does non-metal patching, which includes removing some drivers for other cards. This causes Metal cards to not accelerate after swapping.
|
||||
|
||||
## Keyboard, Mouse and Trackpad not working in installer or after update
|
||||
|
||||
For Macs using legacy USB 1.1 controllers, OpenCore Legacy Patcher can only restore support once it has performed root volume patches. Thus to install macOS, you need to hook up a USB hub between your Mac and Keyboard/Mouse.
|
||||
|
||||
::: warning Note
|
||||
|
||||
In macOS Sonoma, this seems to have been further weakened and some hubs may not be functional.
|
||||
|
||||
Alternative way is making sure to enable "Remote Login" in General -> Sharing before updating, which will enable SSH. That means you can take control using Terminal in another system by typing `ssh username@lan-ip-address` and your password. After that run Post Install Volume Patching by typing `/Applications/OpenCore-Patcher.app/Contents/MacOS/OpenCore-Patcher --patch-sys-vol` and finally `sudo reboot`.
|
||||
|
||||
:::
|
||||
|
||||
|
||||
|
||||
* For MacBook users, you'll need to find an external keyboard/mouse in addition to the USB hub
|
||||
|
||||
More information can be found here:
|
||||
|
||||
* [Legacy UHCI/OHCI support in Ventura #1021](https://github.com/dortania/OpenCore-Legacy-Patcher/issues/1021)
|
||||
|
||||
Applicable models include:
|
||||
|
||||
| Family | Year | Model | Notes |
|
||||
| :---------- | :--------------------| :---------------------------- | :----------------------------------------------- |
|
||||
| MacBook | Mid 2010 and older | MacBook5,1 - MacBook7,1 | |
|
||||
| MacBook Air | Late 2010 and older | MacBookAir2,1 - MacBookAir3,x | |
|
||||
| MacBook Pro | Mid 2010 and older | MacBookPro4,1 - MacBookPro7,x | Excludes Mid 2010 15" and 17" (MacBookPro6,x) |
|
||||
| iMac | Late 2009 and older | iMac7,1 - iMac10,x | Excludes Core i5/7 27" late 2009 iMac (iMac11,1) |
|
||||
| Mac mini | Mid 2011 and older | Macmini3,1 - Macmini5,x | |
|
||||
| Mac Pro | Mid 2010 and older | MacPro3,1 - MacPro5,1 | |
|
||||
|
||||
|
||||

|
||||
|
||||
BIN
docs/images/Error-No-Permission-To-Save.png
Normal file
|
After Width: | Height: | Size: 267 KiB |
@@ -13,8 +13,8 @@ from .detections import device_probe
|
||||
class Constants:
|
||||
def __init__(self) -> None:
|
||||
# Patcher Versioning
|
||||
self.patcher_version: str = "1.5.0" # OpenCore-Legacy-Patcher
|
||||
self.patcher_support_pkg_version: str = "1.4.9" # PatcherSupportPkg
|
||||
self.patcher_version: str = "2.0.0" # OpenCore-Legacy-Patcher
|
||||
self.patcher_support_pkg_version: str = "1.8.0" # PatcherSupportPkg
|
||||
self.copyright_date: str = "Copyright © 2020-2024 Dortania"
|
||||
self.patcher_name: str = "OpenCore Legacy Patcher"
|
||||
|
||||
@@ -28,25 +28,25 @@ class Constants:
|
||||
|
||||
# OpenCore Versioning
|
||||
# https://github.com/acidanthera/OpenCorePkg
|
||||
self.opencore_version: str = "1.0.0"
|
||||
self.opencore_version: str = "1.0.1"
|
||||
|
||||
# Kext Versioning
|
||||
## Acidanthera
|
||||
## https://github.com/acidanthera
|
||||
self.lilu_version: str = "1.6.7" # Lilu
|
||||
self.whatevergreen_version: str = "1.6.6" # WhateverGreen
|
||||
self.whatevergreen_navi_version: str = "1.6.6-Navi" # WhateverGreen (Navi Patch)
|
||||
self.lilu_version: str = "1.6.8" # Lilu
|
||||
self.whatevergreen_version: str = "1.6.7" # WhateverGreen
|
||||
self.whatevergreen_navi_version: str = "1.6.7-Navi" # WhateverGreen (Navi Patch)
|
||||
self.airportbcrmfixup_version: str = "2.1.8" # AirPortBrcmFixup
|
||||
self.nvmefix_version: str = "1.1.1" # NVMeFix
|
||||
self.applealc_version: str = "1.6.3" # AppleALC
|
||||
self.restrictevents_version: str = "1.1.3" # RestrictEvents
|
||||
self.featureunlock_version: str = "1.1.5" # FeatureUnlock
|
||||
self.debugenhancer_version: str = "1.0.8" # DebugEnhancer
|
||||
self.cpufriend_version: str = "1.2.7" # CPUFriend
|
||||
self.restrictevents_version: str = "1.1.4" # RestrictEvents
|
||||
self.featureunlock_version: str = "1.1.6" # FeatureUnlock
|
||||
self.debugenhancer_version: str = "1.0.9" # DebugEnhancer
|
||||
self.cpufriend_version: str = "1.2.8" # CPUFriend
|
||||
self.bluetool_version: str = "2.6.8" # BlueToolFixup (BrcmPatchRAM)
|
||||
self.cslvfixup_version: str = "2.6.1" # CSLVFixup
|
||||
self.autopkg_version: str = "1.0.3" # AutoPkgInstaller
|
||||
self.cryptexfixup_version: str = "1.0.2" # CryptexFixup
|
||||
self.autopkg_version: str = "1.0.4" # AutoPkgInstaller
|
||||
self.cryptexfixup_version: str = "1.0.3" # CryptexFixup
|
||||
|
||||
## Apple
|
||||
## https://www.apple.com
|
||||
@@ -61,6 +61,7 @@ class Constants:
|
||||
self.apfs_zlib_v2_version: str = "12.6" # NoAVXFSCompressionTypeZlib (patched with AVXpel)
|
||||
self.multitouch_version: str = "1.0.0" # AppleUSBMultitouch
|
||||
self.topcase_version: str = "1.0.0" # AppleUSBTopCase
|
||||
self.topcase_inj_version: str = "1.0.0" # AppleTopCaseInjector
|
||||
self.intel_82574l_version: str = "1.0.0" # Intel82574L
|
||||
self.intel_8254x_version: str = "1.0.0" # AppleIntel8254XEthernet
|
||||
self.apple_usb_11_injector: str = "1.0.0" # AppleUSBUHCI/OHCI
|
||||
@@ -73,6 +74,7 @@ class Constants:
|
||||
self.t1_corecrypto_version: str = "1.0.1" # corecrypto (13.6 - T1 support)
|
||||
self.apple_spi_version: str = "1.0.0" # AppleHSSPISupport (14.4 Beta 1)
|
||||
self.apple_spi_hid_version: str = "1.0.0" # AppleHSSPIHIDDriver (14.4 Beta 1)
|
||||
self.kernel_relay_version: str = "1.0.0" # KernelRelayHost (15.0 Beta 3)
|
||||
|
||||
## Apple - Dortania Modified
|
||||
self.bcm570_version: str = "1.0.2" # CatalinaBCM5701Ethernet
|
||||
@@ -80,7 +82,7 @@ class Constants:
|
||||
self.corecaptureelcap_version: str = "1.0.2" # corecaptureElCap
|
||||
self.io80211elcap_version: str = "2.0.1" # IO80211ElCap
|
||||
self.io80211legacy_version: str = "1.0.0" # IO80211FamilyLegacy (Ventura)
|
||||
self.ioskywalk_version: str = "1.1.0" # IOSkywalkFamily (Ventura)
|
||||
self.ioskywalk_version: str = "1.2.0" # IOSkywalkFamily (Ventura)
|
||||
self.bigsursdxc_version: str = "1.0.0" # BigSurSDXC
|
||||
self.monterey_ahci_version: str = "1.0.0" # CatalinaAHCI
|
||||
|
||||
@@ -96,8 +98,8 @@ class Constants:
|
||||
self.btspoof_version: str = "1.0.0" # Bluetooth-Spoof
|
||||
self.aspp_override_version: str = "1.0.1" # ACPI_SMC_PlatformPlugin Override
|
||||
self.ecm_override_version: str = "1.0.0" # AppleUSBECM Override
|
||||
self.rsrhelper_version: str = "1.0.0" # RSRHelper
|
||||
self.amfipass_version: str = "1.4.0" # AMFIPass
|
||||
self.rsrhelper_version: str = "1.0.2" # RSRHelper
|
||||
self.amfipass_version: str = "1.4.1" # AMFIPass
|
||||
self.amfipass_compatibility_version: str = "1.2.1" # Minimum AMFIPass version required
|
||||
|
||||
## Syncretic
|
||||
@@ -177,7 +179,7 @@ class Constants:
|
||||
## SMBIOS Settings
|
||||
self.serial_settings: str = "None" # Set SMBIOS level used
|
||||
self.override_smbios: str = "Default" # Set SMBIOS model used
|
||||
self.allow_native_spoofs: bool = False # Allow native models to recieve spoofs
|
||||
self.allow_native_spoofs: bool = False # Allow native models to receive spoofs
|
||||
|
||||
### Serial Number Overrides
|
||||
self.custom_serial_number: str = "" # Set SMBIOS serial number
|
||||
@@ -232,6 +234,7 @@ class Constants:
|
||||
self.disable_connectdrivers: bool = False # Disable ConnectDrivers (hibernation)
|
||||
self.set_vmm_cpuid: bool = False # Set VMM bit inside CPUID
|
||||
self.disable_mediaanalysisd: bool = False # Set mediaanalysisd to spawn
|
||||
self.force_quad_thread: bool = False # Force quad thread mode (cpus=4)
|
||||
self.set_alc_usage: bool = True # Set AppleALC usage
|
||||
self.allow_3rd_party_drives: bool = True # Allow ThridPartyDrives quirk
|
||||
self.allow_nvme_fixing: bool = True # Allow NVMe Kernel Space Patches
|
||||
@@ -244,6 +247,7 @@ class Constants:
|
||||
os_data.os_data.monterey,
|
||||
os_data.os_data.ventura,
|
||||
os_data.os_data.sonoma,
|
||||
os_data.os_data.sequoia,
|
||||
]
|
||||
|
||||
@property
|
||||
@@ -450,6 +454,10 @@ class Constants:
|
||||
def top_case_path(self):
|
||||
return self.payload_kexts_path / Path(f"Misc/AppleUSBTopCase-v{self.topcase_version}.zip")
|
||||
|
||||
@property
|
||||
def top_case_inj_path(self):
|
||||
return self.payload_kexts_path / Path(f"Misc/AppleTopCaseInjector-v{self.topcase_inj_version}.zip")
|
||||
|
||||
@property
|
||||
def t1_key_store_path(self):
|
||||
return self.payload_kexts_path / Path(f"Misc/AppleKeyStore-v{self.t1_key_store_version}.zip")
|
||||
@@ -474,6 +482,10 @@ class Constants:
|
||||
def apple_spi_hid_path(self):
|
||||
return self.payload_kexts_path / Path(f"Misc/AppleHSSPIHIDDriver-v{self.apple_spi_hid_version}.zip")
|
||||
|
||||
@property
|
||||
def kernel_relay_path(self):
|
||||
return self.payload_kexts_path / Path(f"Misc/KernelRelayHost-v{self.kernel_relay_version}.zip")
|
||||
|
||||
@property
|
||||
def mousse_path(self):
|
||||
return self.payload_kexts_path / Path(f"SSE/AAAMouSSE-v{self.mousse_version}.zip")
|
||||
@@ -777,6 +789,10 @@ class Constants:
|
||||
def icon_path_macos_sonoma(self):
|
||||
return self.icns_resource_path / Path("Sonoma.icns")
|
||||
|
||||
@property
|
||||
def icon_path_macos_sequoia(self):
|
||||
return self.icns_resource_path / Path("Sequoia.icns")
|
||||
|
||||
@property
|
||||
def gui_path(self):
|
||||
return self.payload_path / Path("Icon/Resources.zip")
|
||||
@@ -798,6 +814,10 @@ class Constants:
|
||||
def kdk_download_path(self):
|
||||
return self.payload_path / Path("KDK.dmg")
|
||||
|
||||
@property
|
||||
def metallib_download_path(self):
|
||||
return self.payload_path / Path("MetallibSupportPkg.pkg")
|
||||
|
||||
@property
|
||||
def icons_path(self):
|
||||
return [
|
||||
@@ -805,7 +825,8 @@ class Constants:
|
||||
str(self.icon_path_macos_big_sur),
|
||||
str(self.icon_path_macos_monterey),
|
||||
str(self.icon_path_macos_ventura),
|
||||
str(self.icon_path_macos_sonoma)
|
||||
str(self.icon_path_macos_sonoma),
|
||||
str(self.icon_path_macos_sequoia),
|
||||
]
|
||||
|
||||
sbm_values = [
|
||||
|
||||
@@ -24,6 +24,8 @@ SupportedSMBIOS = [
|
||||
"MacBookAir6,2",
|
||||
"MacBookAir7,1",
|
||||
"MacBookAir7,2",
|
||||
# "MacBookAir8,1",
|
||||
# "MacBookAir8,2",
|
||||
# MacBook Pro
|
||||
"MacBookPro4,1",
|
||||
"MacBookPro5,1",
|
||||
|
||||
@@ -29,6 +29,7 @@ class os_data(enum.IntEnum):
|
||||
monterey = 21
|
||||
ventura = 22
|
||||
sonoma = 23
|
||||
sequoia = 24
|
||||
max_os = 99
|
||||
|
||||
|
||||
|
||||
@@ -507,7 +507,7 @@ smbios_dictionary = {
|
||||
"FirmwareFeatures": "0x8FD8FF42E",
|
||||
"SecureBootModel": "j140k",
|
||||
"CPU Generation": cpu_data.CPUGen.coffee_lake.value,
|
||||
"Max OS Supported": os_data.os_data.max_os,
|
||||
"Max OS Supported": os_data.os_data.sonoma,
|
||||
"Wireless Model": device_probe.Broadcom.Chipsets.AppleBCMWLANBusInterfacePCIe,
|
||||
"Bluetooth Model": bluetooth_data.bluetooth_data.UART,
|
||||
"Screen Size": 13,
|
||||
@@ -524,7 +524,7 @@ smbios_dictionary = {
|
||||
"FirmwareFeatures": "0x8FD8FF42E",
|
||||
"SecureBootModel": "j140k", # TODO: Verify
|
||||
"CPU Generation": cpu_data.CPUGen.coffee_lake.value,
|
||||
"Max OS Supported": os_data.os_data.max_os,
|
||||
"Max OS Supported": os_data.os_data.sonoma,
|
||||
"Wireless Model": device_probe.Broadcom.Chipsets.AppleBCMWLANBusInterfacePCIe,
|
||||
"Bluetooth Model": bluetooth_data.bluetooth_data.UART,
|
||||
"Screen Size": 13,
|
||||
@@ -543,7 +543,7 @@ smbios_dictionary = {
|
||||
"FirmwareFeatures": "0x8FD8FF42E",
|
||||
"SecureBootModel": "x589amlu",
|
||||
"CPU Generation": cpu_data.CPUGen.coffee_lake.value,
|
||||
"Max OS Supported": os_data.os_data.max_os,
|
||||
"Max OS Supported": os_data.os_data.sonoma,
|
||||
"Wireless Model": device_probe.Broadcom.Chipsets.AppleBCMWLANBusInterfacePCIe,
|
||||
"Bluetooth Model": bluetooth_data.bluetooth_data.UART,
|
||||
"Screen Size": 13,
|
||||
@@ -561,7 +561,7 @@ smbios_dictionary = {
|
||||
"FirmwareFeatures": "0x8FD8FF42E",
|
||||
"SecureBootModel": "j140a",
|
||||
"CPU Generation": cpu_data.CPUGen.coffee_lake.value,
|
||||
"Max OS Supported": os_data.os_data.max_os,
|
||||
"Max OS Supported": os_data.os_data.sonoma,
|
||||
"Wireless Model": device_probe.Broadcom.Chipsets.AppleBCMWLANBusInterfacePCIe,
|
||||
"Bluetooth Model": bluetooth_data.bluetooth_data.UART,
|
||||
"Screen Size": 13,
|
||||
|
||||
@@ -67,6 +67,9 @@ class BuildOpenCore:
|
||||
support.BuildSupport(self.model, self.constants, self.config).enable_kext("Lilu.kext", self.constants.lilu_version, self.constants.lilu_path)
|
||||
self.config["Kernel"]["Quirks"]["DisableLinkeditJettison"] = True
|
||||
|
||||
# macOS Sequoia support for Lilu plugins
|
||||
self.config["NVRAM"]["Add"]["7C436110-AB2A-4BBB-A880-FE41995C9F82"]["boot-args"] += " -lilubetaall"
|
||||
|
||||
# Call support functions
|
||||
for function in [
|
||||
firmware.BuildFirmware,
|
||||
|
||||
@@ -199,6 +199,12 @@ class BuildFirmware:
|
||||
logging.info("- Adding IOHIDFamily patch")
|
||||
support.BuildSupport(self.model, self.constants, self.config).get_item_by_kv(self.config["Kernel"]["Patch"], "Identifier", "com.apple.iokit.IOHIDFamily")["Enabled"] = True
|
||||
|
||||
# MacPro3,1/Xserve2,1 cannot boot with more than 4 threads in Sequoia
|
||||
# Note cpus=4 only overrides if more than 4 threads are present. So same on dual-core units
|
||||
if self.constants.force_quad_thread is True:
|
||||
logging.info("- Adding CPU Thread Limit Patch")
|
||||
self.config["NVRAM"]["Add"]["7C436110-AB2A-4BBB-A880-FE41995C9F82"]["boot-args"] += " cpus=4"
|
||||
|
||||
|
||||
def _firmware_driver_handling(self) -> None:
|
||||
"""
|
||||
|
||||
@@ -142,11 +142,15 @@ class BuildGraphicsAudio:
|
||||
iMac MXM dGPU Backlight DevicePath Detection
|
||||
"""
|
||||
|
||||
if not self.constants.custom_model and self.computer.dgpu and self.computer.dgpu.pci_path:
|
||||
if not self.constants.custom_model:
|
||||
for i, device in enumerate(self.computer.gpus):
|
||||
logging.info(f"- Found dGPU ({i + 1}): {utilities.friendly_hex(device.vendor_id)}:{utilities.friendly_hex(device.device_id)}")
|
||||
self.config["#Revision"][f"Hardware-iMac-dGPU-{i + 1}"] = f"{utilities.friendly_hex(device.vendor_id)}:{utilities.friendly_hex(device.device_id)}"
|
||||
|
||||
# Work-around for AMD Navi MXM cards with PCIe bridge
|
||||
if not self.computer.dgpu:
|
||||
self.computer.dgpu=self.computer.gpus[i]
|
||||
|
||||
if device.pci_path != self.computer.dgpu.pci_path:
|
||||
logging.info("- device path and GFX0 Device path are different")
|
||||
self.gfx0_path = device.pci_path
|
||||
@@ -350,7 +354,8 @@ class BuildGraphicsAudio:
|
||||
|
||||
# Due to regression in AppleALC 1.6.4+, temporarily use 1.6.3 and set override
|
||||
if support.BuildSupport(self.model, self.constants, self.config).get_kext_by_bundle_path("AppleALC.kext")["Enabled"] is True:
|
||||
self.config["NVRAM"]["Add"]["7C436110-AB2A-4BBB-A880-FE41995C9F82"]["boot-args"] += " -lilubetaall"
|
||||
if "-lilubetaall" not in self.config["NVRAM"]["Add"]["7C436110-AB2A-4BBB-A880-FE41995C9F82"]["boot-args"]:
|
||||
self.config["NVRAM"]["Add"]["7C436110-AB2A-4BBB-A880-FE41995C9F82"]["boot-args"] += " -lilubetaall"
|
||||
|
||||
|
||||
def _firmware_handling(self) -> None:
|
||||
|
||||
@@ -18,7 +18,8 @@ from ..detections import device_probe
|
||||
from ..datasets import (
|
||||
model_array,
|
||||
smbios_data,
|
||||
cpu_data
|
||||
cpu_data,
|
||||
os_data
|
||||
)
|
||||
|
||||
|
||||
@@ -64,6 +65,12 @@ xw
|
||||
if self.constants.fu_status is False:
|
||||
return
|
||||
|
||||
if not self.model in smbios_data.smbios_dictionary:
|
||||
return
|
||||
|
||||
if smbios_data.smbios_dictionary[self.model]["Max OS Supported"] >= os_data.os_data.sonoma:
|
||||
return
|
||||
|
||||
support.BuildSupport(self.model, self.constants, self.config).enable_kext("FeatureUnlock.kext", self.constants.featureunlock_version, self.constants.featureunlock_path)
|
||||
if self.constants.fu_arguments is not None:
|
||||
logging.info(f"- Adding additional FeatureUnlock args: {self.constants.fu_arguments}")
|
||||
@@ -199,6 +206,7 @@ xw
|
||||
logging.info("- Enabling SPI-based top case support")
|
||||
support.BuildSupport(self.model, self.constants, self.config).enable_kext("AppleHSSPISupport.kext", self.constants.apple_spi_version, self.constants.apple_spi_path)
|
||||
support.BuildSupport(self.model, self.constants, self.config).enable_kext("AppleHSSPIHIDDriver.kext", self.constants.apple_spi_hid_version, self.constants.apple_spi_hid_path)
|
||||
support.BuildSupport(self.model, self.constants, self.config).enable_kext("AppleTopCaseInjector.kext", self.constants.topcase_inj_version, self.constants.top_case_inj_path)
|
||||
|
||||
|
||||
#On-device probing
|
||||
@@ -298,7 +306,7 @@ xw
|
||||
# And MacPro4,1, MacPro5,1 and Xserve3,1 are the only post-Penryn Macs that lack an internal USB hub
|
||||
# - Ref: https://techcommunity.microsoft.com/t5/microsoft-usb-blog/reasons-to-avoid-companion-controllers/ba-p/270710
|
||||
#
|
||||
# To be paired for sys_patch_dict.py's 'Legacy USB 1.1' patchset
|
||||
# To be paired for usb11.py's 'Legacy USB 1.1' patchset
|
||||
#
|
||||
# Note: With macOS 14.1, injection of these kexts causes a panic.
|
||||
# To avoid this, a MaxKernel is configured with XNU 23.0.0 (macOS 14.0).
|
||||
@@ -380,4 +388,5 @@ xw
|
||||
support.BuildSupport(self.model, self.constants, self.config).enable_kext("corecrypto_T1.kext", self.constants.t1_corecrypto_version, self.constants.t1_corecrypto_path)
|
||||
support.BuildSupport(self.model, self.constants, self.config).enable_kext("AppleSSE.kext", self.constants.t1_sse_version, self.constants.t1_sse_path)
|
||||
support.BuildSupport(self.model, self.constants, self.config).enable_kext("AppleKeyStore.kext", self.constants.t1_key_store_version, self.constants.t1_key_store_path)
|
||||
support.BuildSupport(self.model, self.constants, self.config).enable_kext("AppleCredentialManager.kext", self.constants.t1_credential_version, self.constants.t1_credential_path)
|
||||
support.BuildSupport(self.model, self.constants, self.config).enable_kext("AppleCredentialManager.kext", self.constants.t1_credential_version, self.constants.t1_credential_path)
|
||||
support.BuildSupport(self.model, self.constants, self.config).enable_kext("KernelRelayHost.kext", self.constants.kernel_relay_version, self.constants.kernel_relay_path)
|
||||
@@ -10,7 +10,8 @@ from ...detections import device_probe
|
||||
|
||||
from ...datasets import (
|
||||
smbios_data,
|
||||
cpu_data
|
||||
cpu_data,
|
||||
os_data
|
||||
)
|
||||
|
||||
|
||||
@@ -55,6 +56,11 @@ class BuildWiredNetworking:
|
||||
# the kernel driver to prevent a kernel panic
|
||||
# - DriverKit: com.apple.DriverKit.AppleUserECM.dext
|
||||
# - Kext: AppleUSBECM.kext
|
||||
if not self.model in smbios_data.smbios_dictionary:
|
||||
return
|
||||
if smbios_data.smbios_dictionary[self.model]["Max OS Supported"] >= os_data.os_data.sonoma:
|
||||
return
|
||||
|
||||
support.BuildSupport(self.model, self.constants, self.config).enable_kext("ECM-Override.kext", self.constants.ecm_override_version, self.constants.ecm_override_path)
|
||||
|
||||
|
||||
@@ -66,6 +72,8 @@ class BuildWiredNetworking:
|
||||
# See ECM logic for why it's always enabled
|
||||
if not self.model in smbios_data.smbios_dictionary:
|
||||
return
|
||||
if smbios_data.smbios_dictionary[self.model]["Max OS Supported"] >= os_data.os_data.sonoma:
|
||||
return
|
||||
support.BuildSupport(self.model, self.constants, self.config).enable_kext("CatalinaIntelI210Ethernet.kext", self.constants.i210_version, self.constants.i210_path)
|
||||
# Ivy Bridge and newer natively support DriverKit, so set MinKernel to 23.0.0
|
||||
if smbios_data.smbios_dictionary[self.model]["CPU Generation"] >= cpu_data.CPUGen.ivy_bridge.value:
|
||||
|
||||
@@ -12,6 +12,11 @@ from .. import constants
|
||||
from ..support import utilities
|
||||
from ..detections import device_probe
|
||||
|
||||
from ..datasets import (
|
||||
smbios_data,
|
||||
os_data
|
||||
)
|
||||
|
||||
|
||||
class BuildSecurity:
|
||||
"""
|
||||
@@ -83,5 +88,6 @@ class BuildSecurity:
|
||||
logging.info("- Disabling SecureBootModel")
|
||||
self.config["Misc"]["Security"]["SecureBootModel"] = "Disabled"
|
||||
|
||||
logging.info("- Enabling AMFIPass")
|
||||
support.BuildSupport(self.model, self.constants, self.config).enable_kext("AMFIPass.kext", self.constants.amfipass_version, self.constants.amfipass_path)
|
||||
if smbios_data.smbios_dictionary[self.model]["Max OS Supported"] < os_data.os_data.sonoma:
|
||||
logging.info("- Enabling AMFIPass")
|
||||
support.BuildSupport(self.model, self.constants, self.config).enable_kext("AMFIPass.kext", self.constants.amfipass_version, self.constants.amfipass_path)
|
||||
|
||||
@@ -150,9 +150,10 @@ class BuildStorage:
|
||||
|
||||
# Restore S1X/S3X NVMe support removed in 14.0 Beta 2
|
||||
# Apple's usage of the S1X and S3X is quite sporadic and inconsistent, so we'll try a catch all for units with NVMe drives
|
||||
# Additionally expanded to cover all Mac models with the 12+16 pin SSD layout, for older machines with newer drives
|
||||
if self.constants.custom_model and self.model in smbios_data.smbios_dictionary:
|
||||
if "CPU Generation" in smbios_data.smbios_dictionary[self.model]:
|
||||
if cpu_data.CPUGen.broadwell <= smbios_data.smbios_dictionary[self.model]["CPU Generation"] <= cpu_data.CPUGen.kaby_lake:
|
||||
if (cpu_data.CPUGen.haswell <= smbios_data.smbios_dictionary[self.model]["CPU Generation"] <= cpu_data.CPUGen.kaby_lake) or self.model in [ "MacPro6,1" ]:
|
||||
support.BuildSupport(self.model, self.constants, self.config).enable_kext("IOS3XeFamily.kext", self.constants.s3x_nvme_version, self.constants.s3x_nvme_path)
|
||||
|
||||
# Apple RAID Card check
|
||||
@@ -193,4 +194,4 @@ class BuildStorage:
|
||||
|
||||
if self.constants.apfs_trim_timeout is False:
|
||||
logging.info(f"- Disabling APFS TRIM timeout")
|
||||
self.config["Kernel"]["Quirks"]["SetApfsTrimTimeout"] = 0
|
||||
self.config["Kernel"]["Quirks"]["SetApfsTrimTimeout"] = 0
|
||||
|
||||
111
opencore_legacy_patcher/sucatalog/__init__.py
Normal file
@@ -0,0 +1,111 @@
|
||||
"""
|
||||
sucatalog: Python module for querying Apple's Software Update Catalog, supporting Tiger through Sequoia.
|
||||
|
||||
-------------------
|
||||
|
||||
## Usage
|
||||
|
||||
### Get Software Update Catalog URL
|
||||
|
||||
```python
|
||||
>>> import sucatalog
|
||||
|
||||
>>> # Defaults to PublicRelease seed
|
||||
>>> url = sucatalog.CatalogURL().url
|
||||
"https://swscan.apple.com/.../index-15-14-13-12-10.16-10.15-10.14-10.13-10.12-10.11-10.10-10.9-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog"
|
||||
|
||||
>>> url = sucatalog.CatalogURL(seed=sucatalog.SeedType.DeveloperSeed).url
|
||||
"https://swscan.apple.com/.../index-15seed-15-14-13-12-10.16-10.15-10.14-10.13-10.12-10.11-10.10-10.9-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog"
|
||||
|
||||
>>> url = sucatalog.CatalogURL(version=sucatalog.CatalogVersion.HIGH_SIERRA).url
|
||||
"https://swscan.apple.com/.../index-10.13-10.12-10.11-10.10-10.9-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog"
|
||||
```
|
||||
|
||||
|
||||
### Parse Software Update Catalog - InstallAssistants only
|
||||
|
||||
>>> import sucatalog
|
||||
|
||||
>>> # Pass contents of URL (as dictionary)
|
||||
>>> catalog = plistlib.loads(requests.get(url).content)
|
||||
|
||||
>>> products = sucatalog.CatalogProducts(catalog).products
|
||||
[
|
||||
{
|
||||
'Build': '22G720',
|
||||
'Catalog': <SeedType.PublicRelease: ''>,
|
||||
'InstallAssistant': {
|
||||
'IntegrityDataSize': 42008,
|
||||
'IntegrityDataURL': 'https://swcdn.apple.com/.../InstallAssistant.pkg.integrityDataV1',
|
||||
'Size': 12210304673,
|
||||
'URL': 'https://swcdn.apple.com/.../InstallAssistant.pkg'
|
||||
},
|
||||
'PostDate': datetime.datetime(2024, 5, 20, 17, 18, 21),
|
||||
'ProductID': '052-96247',
|
||||
'Title': 'macOS Ventura',
|
||||
'Version': '13.6.7'
|
||||
}
|
||||
]
|
||||
|
||||
### Parse Software Update Catalog - All products
|
||||
|
||||
By default, `CatalogProducts` will only return InstallAssistants. To get all products, set `install_assistants_only=False`.
|
||||
|
||||
>>> import sucatalog
|
||||
|
||||
>>> # Pass contents of URL (as dictionary)
|
||||
>>> products = sucatalog.CatalogProducts(catalog, install_assistants_only=False).products
|
||||
[
|
||||
{
|
||||
'Build': None,
|
||||
'Catalog': None,
|
||||
'Packages': [
|
||||
{
|
||||
'MetadataURL': 'https://swdist.apple.com/.../iLifeSlideshow_v2.pkm',
|
||||
'Size': 116656956,
|
||||
'URL': 'http://swcdn.apple.com/.../iLifeSlideshow_v2.pkg'
|
||||
},
|
||||
{
|
||||
'MetadataURL': 'https://swdist.apple.com/.../iPhoto9.2.3ContentUpdate.pkm',
|
||||
'Size': 59623907,
|
||||
'URL': 'http://swcdn.apple.com/.../iPhoto9.2.3ContentUpdate.pkg'
|
||||
},
|
||||
{
|
||||
'MetadataURL': 'https://swdist.apple.com/.../iPhoto9.2.3Update.pkm',
|
||||
'Size': 197263405,
|
||||
'URL': 'http://swcdn.apple.com/.../iPhoto9.2.3Update.pkg'
|
||||
}
|
||||
],
|
||||
'PostDate': datetime.datetime(2019, 10, 23, 0, 2, 42),
|
||||
'ProductID': '041-85230',
|
||||
'Title': 'iPhoto Update',
|
||||
'Version': '9.2.3'
|
||||
},
|
||||
{
|
||||
'Build': None,
|
||||
'Catalog': None,
|
||||
'Packages': [
|
||||
{
|
||||
'Digest': '9aba109078feec7ea841529e955440b63d7755a0',
|
||||
'MetadataURL': 'https://swdist.apple.com/.../iPhoto9.4.3Update.pkm',
|
||||
'Size': 555246460,
|
||||
'URL': 'http://swcdn.apple.com/.../iPhoto9.4.3Update.pkg'
|
||||
},
|
||||
{
|
||||
'Digest': '0bb013221ca2df5e178d950cb229f41b8e680d00',
|
||||
'MetadataURL': 'https://swdist.apple.com/.../iPhoto9.4.3ContentUpdate.pkm',
|
||||
'Size': 213073666,
|
||||
'URL': 'http://swcdn.apple.com/.../iPhoto9.4.3ContentUpdate.pkg'
|
||||
}
|
||||
],
|
||||
'PostDate': datetime.datetime(2019, 10, 13, 3, 23, 14),
|
||||
'ProductID': '041-88859',
|
||||
'Title': 'iPhoto Update',
|
||||
'Version': '9.4.3'
|
||||
}
|
||||
]
|
||||
"""
|
||||
|
||||
from .url import CatalogURL
|
||||
from .constants import CatalogVersion, SeedType
|
||||
from .products import CatalogProducts
|
||||
57
opencore_legacy_patcher/sucatalog/constants.py
Normal file
@@ -0,0 +1,57 @@
|
||||
"""
|
||||
constants.py: Enumerations for sucatalog-py
|
||||
"""
|
||||
|
||||
from enum import StrEnum
|
||||
|
||||
|
||||
class SeedType(StrEnum):
|
||||
"""
|
||||
Enum for catalog types
|
||||
|
||||
Variants:
|
||||
DeveloperSeed: Developer Beta (Part of the Apple Developer Program)
|
||||
PublicSeed: Public Beta
|
||||
CustomerSeed: AppleSeed Program (Generally mirrors DeveloperSeed)
|
||||
PublicRelease: Public Release
|
||||
"""
|
||||
DeveloperSeed: str = "seed"
|
||||
PublicSeed: str = "beta"
|
||||
CustomerSeed: str = "customerseed"
|
||||
PublicRelease: str = ""
|
||||
|
||||
|
||||
class CatalogVersion(StrEnum):
|
||||
"""
|
||||
Enum for macOS versions
|
||||
|
||||
Used for generating sucatalog URLs
|
||||
"""
|
||||
SEQUOIA: str = "15"
|
||||
SONOMA: str = "14"
|
||||
VENTURA: str = "13"
|
||||
MONTEREY: str = "12"
|
||||
BIG_SUR: str = "11"
|
||||
BIG_SUR_LEGACY: str = "10.16"
|
||||
CATALINA: str = "10.15"
|
||||
MOJAVE: str = "10.14"
|
||||
HIGH_SIERRA: str = "10.13"
|
||||
SIERRA: str = "10.12"
|
||||
EL_CAPITAN: str = "10.11"
|
||||
YOSEMITE: str = "10.10"
|
||||
MAVERICKS: str = "10.9"
|
||||
MOUNTAIN_LION: str = "mountainlion"
|
||||
LION: str = "lion"
|
||||
SNOW_LEOPARD: str = "snowleopard"
|
||||
LEOPARD: str = "leopard"
|
||||
TIGER: str = ""
|
||||
|
||||
|
||||
class CatalogExtension(StrEnum):
|
||||
"""
|
||||
Enum for catalog extensions
|
||||
|
||||
Used for generating sucatalog URLs
|
||||
"""
|
||||
PLIST: str = ".sucatalog"
|
||||
GZIP: str = ".sucatalog.gz"
|
||||
407
opencore_legacy_patcher/sucatalog/products.py
Normal file
@@ -0,0 +1,407 @@
|
||||
"""
|
||||
products.py: Parse products from Software Update Catalog
|
||||
"""
|
||||
|
||||
import re
|
||||
import plistlib
|
||||
|
||||
import packaging.version
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
from pathlib import Path
|
||||
from functools import cached_property
|
||||
|
||||
from .url import CatalogURL
|
||||
from .constants import CatalogVersion, SeedType
|
||||
|
||||
from ..support import network_handler
|
||||
|
||||
|
||||
class CatalogProducts:
|
||||
"""
|
||||
Args:
|
||||
catalog (dict): Software Update Catalog (contents of CatalogURL's URL)
|
||||
install_assistants_only (bool): Only list InstallAssistant products
|
||||
only_vmm_install_assistants (bool): Only list VMM-x86_64-compatible InstallAssistant products
|
||||
max_install_assistant_version (CatalogVersion): Maximum InstallAssistant version to list
|
||||
"""
|
||||
def __init__(self,
|
||||
catalog: dict,
|
||||
install_assistants_only: bool = True,
|
||||
only_vmm_install_assistants: bool = True,
|
||||
max_install_assistant_version: CatalogVersion = CatalogVersion.SEQUOIA
|
||||
) -> None:
|
||||
self.catalog: dict = catalog
|
||||
self.ia_only: bool = install_assistants_only
|
||||
self.vmm_only: bool = only_vmm_install_assistants
|
||||
self.max_ia_version: packaging = packaging.version.parse(f"{max_install_assistant_version.value}.99.99")
|
||||
self.max_ia_catalog: CatalogVersion = max_install_assistant_version
|
||||
|
||||
|
||||
def _legacy_parse_info_plist(self, data: dict) -> dict:
|
||||
"""
|
||||
Legacy version of parsing for installer details through Info.plist
|
||||
"""
|
||||
|
||||
if "MobileAssetProperties" not in data:
|
||||
return {}
|
||||
if "SupportedDeviceModels" not in data["MobileAssetProperties"]:
|
||||
return {}
|
||||
if "OSVersion" not in data["MobileAssetProperties"]:
|
||||
return {}
|
||||
if "Build" not in data["MobileAssetProperties"]:
|
||||
return {}
|
||||
|
||||
# Ensure Apple Silicon specific Installers are not listed
|
||||
if "VMM-x86_64" not in data["MobileAssetProperties"]["SupportedDeviceModels"]:
|
||||
if self.vmm_only:
|
||||
return {}
|
||||
|
||||
version = data["MobileAssetProperties"]["OSVersion"]
|
||||
build = data["MobileAssetProperties"]["Build"]
|
||||
|
||||
catalog = ""
|
||||
try:
|
||||
catalog = data["MobileAssetProperties"]["BridgeVersionInfo"]["CatalogURL"]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
if any([version, build]) is None:
|
||||
return {}
|
||||
|
||||
return {
|
||||
"Version": version,
|
||||
"Build": build,
|
||||
"Catalog": CatalogURL().catalog_url_to_seed(catalog),
|
||||
}
|
||||
|
||||
|
||||
def _parse_mobile_asset_plist(self, data: dict) -> dict:
|
||||
"""
|
||||
Parses the MobileAsset plist for installer details
|
||||
|
||||
With macOS Sequoia, the Info.plist is no longer present in the InstallAssistant's assets
|
||||
"""
|
||||
|
||||
for entry in data["Assets"]:
|
||||
if "SupportedDeviceModels" not in entry:
|
||||
continue
|
||||
if "OSVersion" not in entry:
|
||||
continue
|
||||
if "Build" not in entry:
|
||||
continue
|
||||
if "VMM-x86_64" not in entry["SupportedDeviceModels"]:
|
||||
if self.vmm_only:
|
||||
continue
|
||||
|
||||
build = entry["Build"]
|
||||
version = entry["OSVersion"]
|
||||
|
||||
catalog_url = ""
|
||||
try:
|
||||
catalog_url = entry["BridgeVersionInfo"]["CatalogURL"]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
return {
|
||||
"Version": version,
|
||||
"Build": build,
|
||||
"Catalog": CatalogURL().catalog_url_to_seed(catalog_url),
|
||||
}
|
||||
|
||||
return {}
|
||||
|
||||
|
||||
def _parse_english_distributions(self, data: bytes) -> dict:
|
||||
"""
|
||||
Resolve Title, Build and Version from the English distribution file
|
||||
"""
|
||||
try:
|
||||
plist_contents = plistlib.loads(data)
|
||||
except plistlib.InvalidFileException:
|
||||
plist_contents = None
|
||||
|
||||
try:
|
||||
xml_contents = ET.fromstring(data)
|
||||
except ET.ParseError:
|
||||
xml_contents = None
|
||||
|
||||
_product_map = {
|
||||
"Title": None,
|
||||
"Build": None,
|
||||
"Version": None,
|
||||
}
|
||||
|
||||
if plist_contents:
|
||||
if "macOSProductBuildVersion" in plist_contents:
|
||||
_product_map["Build"] = plist_contents["macOSProductBuildVersion"]
|
||||
if "macOSProductVersion" in plist_contents:
|
||||
_product_map["Version"] = plist_contents["macOSProductVersion"]
|
||||
if "BUILD" in plist_contents:
|
||||
_product_map["Build"] = plist_contents["BUILD"]
|
||||
if "VERSION" in plist_contents:
|
||||
_product_map["Version"] = plist_contents["VERSION"]
|
||||
|
||||
if xml_contents:
|
||||
# Fetch item title
|
||||
item_title = xml_contents.find(".//title").text
|
||||
if item_title in ["SU_TITLE", "MANUAL_TITLE", "MAN_TITLE"]:
|
||||
# regex search the contents for the title
|
||||
title_search = re.search(r'"SU_TITLE"\s*=\s*"(.*)";', data.decode("utf-8"))
|
||||
if title_search:
|
||||
item_title = title_search.group(1)
|
||||
|
||||
_product_map["Title"] = item_title
|
||||
|
||||
return _product_map
|
||||
|
||||
|
||||
def _build_installer_name(self, version: str, catalog: SeedType) -> str:
|
||||
"""
|
||||
Builds the installer name based on the version and catalog
|
||||
"""
|
||||
try:
|
||||
marketing_name = CatalogVersion(version.split(".")[0]).name
|
||||
except ValueError:
|
||||
marketing_name = "Unknown"
|
||||
|
||||
# Replace _ with space
|
||||
marketing_name = marketing_name.replace("_", " ")
|
||||
|
||||
# Convert to upper for each word
|
||||
marketing_name = "macOS " + " ".join([word.capitalize() for word in marketing_name.split()])
|
||||
|
||||
# Append Beta if needed
|
||||
if catalog in [SeedType.DeveloperSeed, SeedType.PublicSeed, SeedType.CustomerSeed]:
|
||||
marketing_name += " Beta"
|
||||
|
||||
return marketing_name
|
||||
|
||||
|
||||
def _list_latest_installers_only(self, products: list) -> list:
|
||||
"""
|
||||
List only the latest installers per macOS version
|
||||
|
||||
macOS versions capped at n-3 (n being the latest macOS version)
|
||||
"""
|
||||
|
||||
supported_versions = []
|
||||
|
||||
# Build list of supported versions (n to n-3, where n is the latest macOS version set)
|
||||
did_find_latest = False
|
||||
for version in CatalogVersion:
|
||||
if did_find_latest is False:
|
||||
if version != self.max_ia_catalog:
|
||||
continue
|
||||
did_find_latest = True
|
||||
|
||||
supported_versions.append(version)
|
||||
|
||||
if len(supported_versions) == 4:
|
||||
break
|
||||
|
||||
# Invert the list
|
||||
supported_versions = supported_versions[::-1]
|
||||
|
||||
# Create duplicate product list
|
||||
products_copy = products.copy()
|
||||
|
||||
# Remove all but the newest version
|
||||
for version in supported_versions:
|
||||
_newest_version = packaging.version.parse("0.0.0")
|
||||
|
||||
# First, determine largest version
|
||||
for installer in products:
|
||||
if installer["Version"] is None:
|
||||
continue
|
||||
if not installer["Version"].startswith(version.value):
|
||||
continue
|
||||
if installer["Catalog"] in [SeedType.CustomerSeed, SeedType.DeveloperSeed, SeedType.PublicSeed]:
|
||||
continue
|
||||
try:
|
||||
if packaging.version.parse(installer["Version"]) > _newest_version:
|
||||
_newest_version = packaging.version.parse(installer["Version"])
|
||||
except packaging.version.InvalidVersion:
|
||||
pass
|
||||
|
||||
# Next, remove all installers that are not the newest version
|
||||
for installer in products:
|
||||
if installer["Version"] is None:
|
||||
continue
|
||||
if not installer["Version"].startswith(version.value):
|
||||
continue
|
||||
try:
|
||||
if packaging.version.parse(installer["Version"]) < _newest_version:
|
||||
if installer in products_copy:
|
||||
products_copy.pop(products_copy.index(installer))
|
||||
except packaging.version.InvalidVersion:
|
||||
pass
|
||||
|
||||
# Remove beta versions if a public release is available
|
||||
if _newest_version != packaging.version.parse("0.0.0"):
|
||||
if installer["Catalog"] in [SeedType.CustomerSeed, SeedType.DeveloperSeed, SeedType.PublicSeed]:
|
||||
if installer in products_copy:
|
||||
products_copy.pop(products_copy.index(installer))
|
||||
|
||||
|
||||
# Remove EOL versions (older than n-3)
|
||||
for installer in products:
|
||||
if installer["Version"].split(".")[0] < supported_versions[-4].value:
|
||||
if installer in products_copy:
|
||||
products_copy.pop(products_copy.index(installer))
|
||||
|
||||
return products_copy
|
||||
|
||||
|
||||
@cached_property
|
||||
def products(self) -> None:
|
||||
"""
|
||||
Returns a list of products from the sucatalog
|
||||
"""
|
||||
|
||||
catalog = self.catalog
|
||||
|
||||
_products = []
|
||||
|
||||
for product in catalog["Products"]:
|
||||
|
||||
# InstallAssistants.pkgs (macOS Installers) will have the following keys:
|
||||
if self.ia_only:
|
||||
if "ExtendedMetaInfo" not in catalog["Products"][product]:
|
||||
continue
|
||||
if "InstallAssistantPackageIdentifiers" not in catalog["Products"][product]["ExtendedMetaInfo"]:
|
||||
continue
|
||||
if "SharedSupport" not in catalog["Products"][product]["ExtendedMetaInfo"]["InstallAssistantPackageIdentifiers"]:
|
||||
continue
|
||||
|
||||
_product_map = {
|
||||
"ProductID": product,
|
||||
"PostDate": catalog["Products"][product]["PostDate"],
|
||||
"Title": None,
|
||||
"Build": None,
|
||||
"Version": None,
|
||||
"Catalog": None,
|
||||
|
||||
# Optional keys if not InstallAssistant only:
|
||||
# "Packages": None,
|
||||
|
||||
# Optional keys if InstallAssistant found:
|
||||
# "InstallAssistant": {
|
||||
# "URL": None,
|
||||
# "Size": None,
|
||||
# "XNUMajor": None,
|
||||
# "IntegrityDataURL": None,
|
||||
# "IntegrityDataSize": None
|
||||
# },
|
||||
}
|
||||
|
||||
# InstallAssistant logic
|
||||
if "Packages" in catalog["Products"][product]:
|
||||
# Add packages to product map if not InstallAssistant only
|
||||
if self.ia_only is False:
|
||||
_product_map["Packages"] = catalog["Products"][product]["Packages"]
|
||||
for package in catalog["Products"][product]["Packages"]:
|
||||
if "URL" in package:
|
||||
if Path(package["URL"]).name == "InstallAssistant.pkg":
|
||||
_product_map["InstallAssistant"] = {
|
||||
"URL": package["URL"],
|
||||
"Size": package["Size"],
|
||||
"IntegrityDataURL": package["IntegrityDataURL"],
|
||||
"IntegrityDataSize": package["IntegrityDataSize"]
|
||||
}
|
||||
|
||||
if Path(package["URL"]).name not in ["Info.plist", "com_apple_MobileAsset_MacSoftwareUpdate.plist"]:
|
||||
continue
|
||||
|
||||
net_obj = network_handler.NetworkUtilities().get(package["URL"])
|
||||
if net_obj is None:
|
||||
continue
|
||||
|
||||
contents = net_obj.content
|
||||
try:
|
||||
plist_contents = plistlib.loads(contents)
|
||||
except plistlib.InvalidFileException:
|
||||
continue
|
||||
|
||||
if plist_contents:
|
||||
if Path(package["URL"]).name == "Info.plist":
|
||||
_product_map.update(self._legacy_parse_info_plist(plist_contents))
|
||||
else:
|
||||
_product_map.update(self._parse_mobile_asset_plist(plist_contents))
|
||||
|
||||
if _product_map["Version"] is not None:
|
||||
_product_map["Title"] = self._build_installer_name(_product_map["Version"], _product_map["Catalog"])
|
||||
|
||||
# Fall back to English distribution if no version is found
|
||||
if _product_map["Version"] is None:
|
||||
url = None
|
||||
if "Distributions" in catalog["Products"][product]:
|
||||
if "English" in catalog["Products"][product]["Distributions"]:
|
||||
url = catalog["Products"][product]["Distributions"]["English"]
|
||||
elif "en" in catalog["Products"][product]["Distributions"]:
|
||||
url = catalog["Products"][product]["Distributions"]["en"]
|
||||
|
||||
if url is None:
|
||||
continue
|
||||
|
||||
net_obj = network_handler.NetworkUtilities().get(url)
|
||||
if net_obj is None:
|
||||
continue
|
||||
|
||||
contents = net_obj.content
|
||||
|
||||
_product_map.update(self._parse_english_distributions(contents))
|
||||
|
||||
if _product_map["Version"] is None:
|
||||
if "ServerMetadataURL" in catalog["Products"][product]:
|
||||
server_metadata_url = catalog["Products"][product]["ServerMetadataURL"]
|
||||
|
||||
net_obj = network_handler.NetworkUtilities().get(server_metadata_url)
|
||||
if net_obj is None:
|
||||
continue
|
||||
|
||||
server_metadata_contents = net_obj.content
|
||||
|
||||
try:
|
||||
server_metadata_plist = plistlib.loads(server_metadata_contents)
|
||||
except plistlib.InvalidFileException:
|
||||
pass
|
||||
|
||||
if "CFBundleShortVersionString" in server_metadata_plist:
|
||||
_product_map["Version"] = server_metadata_plist["CFBundleShortVersionString"]
|
||||
|
||||
|
||||
if _product_map["Version"] is not None:
|
||||
# Check if version is newer than the max version
|
||||
if self.ia_only:
|
||||
try:
|
||||
if packaging.version.parse(_product_map["Version"]) > self.max_ia_version:
|
||||
continue
|
||||
except packaging.version.InvalidVersion:
|
||||
pass
|
||||
|
||||
if _product_map["Build"] is not None:
|
||||
if "InstallAssistant" in _product_map:
|
||||
try:
|
||||
# Grab first 2 characters of build
|
||||
_product_map["InstallAssistant"]["XNUMajor"] = int(_product_map["Build"][:2])
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
# If version is still None, set to 0.0.0
|
||||
if _product_map["Version"] is None:
|
||||
_product_map["Version"] = "0.0.0"
|
||||
|
||||
_products.append(_product_map)
|
||||
|
||||
_products = sorted(_products, key=lambda x: x["Version"])
|
||||
|
||||
return _products
|
||||
|
||||
|
||||
@cached_property
|
||||
def latest_products(self) -> list:
|
||||
"""
|
||||
Returns a list of the latest products from the sucatalog
|
||||
"""
|
||||
return self._list_latest_installers_only(self.products)
|
||||
175
opencore_legacy_patcher/sucatalog/url.py
Normal file
@@ -0,0 +1,175 @@
|
||||
"""
|
||||
url.py: Generate URL for Software Update Catalog
|
||||
|
||||
Usage:
|
||||
>>> import sucatalog
|
||||
>>> catalog_url = sucatalog.CatalogURL().url
|
||||
https://swscan.apple.com/content/catalogs/others/index-15seed-15-14-13-12-10.16-10.15-10.14-10.13-10.12-10.11-10.10-10.9-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog
|
||||
"""
|
||||
|
||||
import logging
|
||||
import plistlib
|
||||
|
||||
from .constants import (
|
||||
SeedType,
|
||||
CatalogVersion,
|
||||
CatalogExtension
|
||||
)
|
||||
|
||||
from ..support import network_handler
|
||||
|
||||
|
||||
class CatalogURL:
|
||||
"""
|
||||
Provides URL generation for Software Update Catalog
|
||||
|
||||
Args:
|
||||
version (CatalogVersion): Version of macOS
|
||||
seed (SeedType): Seed type
|
||||
extension (CatalogExtension): Extension for the catalog URL
|
||||
"""
|
||||
def __init__(self,
|
||||
version: CatalogVersion = CatalogVersion.SEQUOIA,
|
||||
seed: SeedType = SeedType.PublicRelease,
|
||||
extension: CatalogExtension = CatalogExtension.PLIST
|
||||
) -> None:
|
||||
self.version = version
|
||||
self.seed = seed
|
||||
self.extension = extension
|
||||
|
||||
self.seed = self._fix_seed_type()
|
||||
self.version = self._fix_version()
|
||||
|
||||
|
||||
def _fix_seed_type(self) -> SeedType:
|
||||
"""
|
||||
Fixes seed type for URL generation
|
||||
"""
|
||||
# Pre-Mountain Lion lacked seed types
|
||||
if self.version in [CatalogVersion.LION, CatalogVersion.SNOW_LEOPARD, CatalogVersion.LEOPARD, CatalogVersion.TIGER]:
|
||||
if self.seed != SeedType.PublicRelease:
|
||||
logging.warning(f"{self.seed.name} not supported for {self.version.name}, defaulting to PublicRelease")
|
||||
return SeedType.PublicRelease
|
||||
|
||||
# Pre-Yosemite lacked PublicSeed/CustomerSeed, thus override to DeveloperSeed
|
||||
if self.version in [CatalogVersion.MAVERICKS, CatalogVersion.MOUNTAIN_LION]:
|
||||
if self.seed in [SeedType.PublicSeed, SeedType.CustomerSeed]:
|
||||
logging.warning(f"{self.seed.name} not supported for {self.version.name}, defaulting to DeveloperSeed")
|
||||
return SeedType.DeveloperSeed
|
||||
|
||||
return self.seed
|
||||
|
||||
|
||||
def _fix_version(self) -> CatalogVersion:
|
||||
"""
|
||||
Fixes version for URL generation
|
||||
"""
|
||||
if self.version == CatalogVersion.BIG_SUR:
|
||||
return CatalogVersion.BIG_SUR_LEGACY
|
||||
|
||||
return self.version
|
||||
|
||||
|
||||
def _fetch_versions_for_url(self) -> list:
|
||||
"""
|
||||
Fetches versions for URL generation
|
||||
"""
|
||||
versions: list = []
|
||||
|
||||
_did_hit_variant: bool = False
|
||||
for variant in CatalogVersion:
|
||||
|
||||
# Avoid appending versions newer than the current version
|
||||
if variant == self.version:
|
||||
_did_hit_variant = True
|
||||
if _did_hit_variant is False:
|
||||
continue
|
||||
|
||||
# Skip invalid version
|
||||
if variant in [CatalogVersion.BIG_SUR, CatalogVersion.TIGER]:
|
||||
continue
|
||||
|
||||
versions.append(variant.value)
|
||||
|
||||
if self.version == CatalogVersion.SNOW_LEOPARD:
|
||||
# Reverse list pre-Lion (ie. just Snow Leopard, since Lion is a list of one)
|
||||
versions = versions[::-1]
|
||||
|
||||
return versions
|
||||
|
||||
|
||||
def _construct_catalog_url(self) -> str:
|
||||
"""
|
||||
Constructs the catalog URL based on the seed type
|
||||
"""
|
||||
|
||||
url: str = "https://swscan.apple.com/content/catalogs"
|
||||
|
||||
if self.version == CatalogVersion.TIGER:
|
||||
url += "/index"
|
||||
else:
|
||||
url += "/others/index"
|
||||
|
||||
if self.seed in [SeedType.DeveloperSeed, SeedType.PublicSeed, SeedType.CustomerSeed]:
|
||||
url += f"-{self.version.value}"
|
||||
if self.version == CatalogVersion.MAVERICKS and self.seed == SeedType.CustomerSeed:
|
||||
# Apple previously used 'publicseed' for CustomerSeed in Mavericks
|
||||
url += "publicseed"
|
||||
else:
|
||||
url += f"{self.seed.value}"
|
||||
|
||||
# 10.10 and older don't append versions for CustomerSeed
|
||||
if self.seed == SeedType.CustomerSeed and self.version in [
|
||||
CatalogVersion.YOSEMITE,
|
||||
CatalogVersion.MAVERICKS,
|
||||
CatalogVersion.MOUNTAIN_LION,
|
||||
CatalogVersion.LION,
|
||||
CatalogVersion.SNOW_LEOPARD,
|
||||
CatalogVersion.LEOPARD
|
||||
]:
|
||||
pass
|
||||
else:
|
||||
for version in self._fetch_versions_for_url():
|
||||
url += f"-{version}"
|
||||
|
||||
if self.version != CatalogVersion.TIGER:
|
||||
url += ".merged-1"
|
||||
url += self.extension.value
|
||||
|
||||
return url
|
||||
|
||||
|
||||
def catalog_url_to_seed(self, catalog_url: str) -> SeedType:
|
||||
"""
|
||||
Converts the Catalog URL to a SeedType
|
||||
"""
|
||||
if "beta" in catalog_url:
|
||||
return SeedType.PublicSeed
|
||||
elif "customerseed" in catalog_url:
|
||||
return SeedType.CustomerSeed
|
||||
elif "seed" in catalog_url:
|
||||
return SeedType.DeveloperSeed
|
||||
return SeedType.PublicRelease
|
||||
|
||||
|
||||
@property
|
||||
def url(self) -> str:
|
||||
"""
|
||||
Generate URL for Software Update Catalog
|
||||
|
||||
Returns:
|
||||
str: URL for Software Update Catalog
|
||||
"""
|
||||
return self._construct_catalog_url()
|
||||
|
||||
|
||||
@property
|
||||
def url_contents(self) -> dict:
|
||||
"""
|
||||
Return URL contents
|
||||
"""
|
||||
try:
|
||||
return plistlib.loads(network_handler.NetworkUtilities().get(self.url).content)
|
||||
except Exception as e:
|
||||
logging.error(f"Failed to fetch URL contents: {e}")
|
||||
return None
|
||||
@@ -17,15 +17,14 @@ from .. import constants
|
||||
|
||||
from ..wx_gui import gui_entry
|
||||
from ..efi_builder import build
|
||||
from ..sys_patch import sys_patch
|
||||
from ..sys_patch.auto_patcher import StartAutomaticPatching
|
||||
|
||||
from ..datasets import (
|
||||
model_array,
|
||||
os_data
|
||||
)
|
||||
from ..sys_patch import (
|
||||
sys_patch,
|
||||
sys_patch_auto
|
||||
)
|
||||
|
||||
from . import (
|
||||
utilities,
|
||||
defaults,
|
||||
@@ -118,7 +117,7 @@ class arguments:
|
||||
"""
|
||||
|
||||
logging.info("Set Auto patching")
|
||||
sys_patch_auto.AutomaticSysPatch(self.constants).start_auto_patch()
|
||||
StartAutomaticPatching(self.constants).start_auto_patch()
|
||||
|
||||
|
||||
def _prepare_for_update_handler(self) -> None:
|
||||
|
||||
@@ -1,292 +0,0 @@
|
||||
#################################################################################
|
||||
# Copyright (C) 2009-2011 Vladimir "Farcaller" Pouzanov <farcaller@gmail.com> #
|
||||
# #
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy #
|
||||
# of this software and associated documentation files (the "Software"), to deal #
|
||||
# in the Software without restriction, including without limitation the rights #
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell #
|
||||
# copies of the Software, and to permit persons to whom the Software is #
|
||||
# furnished to do so, subject to the following conditions: #
|
||||
# #
|
||||
# The above copyright notice and this permission notice shall be included in #
|
||||
# all copies or substantial portions of the Software. #
|
||||
# #
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR #
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, #
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE #
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER #
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, #
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN #
|
||||
# THE SOFTWARE. #
|
||||
#################################################################################
|
||||
|
||||
import struct
|
||||
import codecs
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
class BPListWriter(object):
|
||||
def __init__(self, objects):
|
||||
self.bplist = ""
|
||||
self.objects = objects
|
||||
|
||||
def binary(self):
|
||||
'''binary -> string
|
||||
|
||||
Generates bplist
|
||||
'''
|
||||
self.data = 'bplist00'
|
||||
|
||||
# TODO: flatten objects and count max length size
|
||||
|
||||
# TODO: write objects and save offsets
|
||||
|
||||
# TODO: write offsets
|
||||
|
||||
# TODO: write metadata
|
||||
|
||||
return self.data
|
||||
|
||||
def write(self, filename):
|
||||
'''
|
||||
|
||||
Writes bplist to file
|
||||
'''
|
||||
if self.bplist != "":
|
||||
pass
|
||||
# TODO: save self.bplist to file
|
||||
else:
|
||||
raise Exception('BPlist not yet generated')
|
||||
|
||||
class BPListReader(object):
|
||||
def __init__(self, s):
|
||||
self.data = s
|
||||
self.objects = []
|
||||
self.resolved = {}
|
||||
|
||||
def __unpackIntStruct(self, sz, s):
|
||||
'''__unpackIntStruct(size, string) -> int
|
||||
|
||||
Unpacks the integer of given size (1, 2 or 4 bytes) from string
|
||||
'''
|
||||
if sz == 1:
|
||||
ot = '!B'
|
||||
elif sz == 2:
|
||||
ot = '!H'
|
||||
elif sz == 4:
|
||||
ot = '!I'
|
||||
elif sz == 8:
|
||||
ot = '!Q'
|
||||
else:
|
||||
raise Exception('int unpack size '+str(sz)+' unsupported')
|
||||
return struct.unpack(ot, s)[0]
|
||||
|
||||
def __unpackInt(self, offset):
|
||||
'''__unpackInt(offset) -> int
|
||||
|
||||
Unpacks int field from plist at given offset
|
||||
'''
|
||||
return self.__unpackIntMeta(offset)[1]
|
||||
|
||||
def __unpackIntMeta(self, offset):
|
||||
'''__unpackIntMeta(offset) -> (size, int)
|
||||
|
||||
Unpacks int field from plist at given offset and returns its size and value
|
||||
'''
|
||||
obj_header = self.data[offset]
|
||||
obj_type, obj_info = (obj_header & 0xF0), (obj_header & 0x0F)
|
||||
int_sz = 2**obj_info
|
||||
return int_sz, self.__unpackIntStruct(int_sz, self.data[offset+1:offset+1+int_sz])
|
||||
|
||||
def __resolveIntSize(self, obj_info, offset):
|
||||
'''__resolveIntSize(obj_info, offset) -> (count, offset)
|
||||
|
||||
Calculates count of objref* array entries and returns count and offset to first element
|
||||
'''
|
||||
if obj_info == 0x0F:
|
||||
ofs, obj_count = self.__unpackIntMeta(offset+1)
|
||||
objref = offset+2+ofs
|
||||
else:
|
||||
obj_count = obj_info
|
||||
objref = offset+1
|
||||
return obj_count, objref
|
||||
|
||||
def __unpackFloatStruct(self, sz, s):
|
||||
'''__unpackFloatStruct(size, string) -> float
|
||||
|
||||
Unpacks the float of given size (4 or 8 bytes) from string
|
||||
'''
|
||||
if sz == 4:
|
||||
ot = '!f'
|
||||
elif sz == 8:
|
||||
ot = '!d'
|
||||
else:
|
||||
raise Exception('float unpack size '+str(sz)+' unsupported')
|
||||
return struct.unpack(ot, s)[0]
|
||||
|
||||
def __unpackFloat(self, offset):
|
||||
'''__unpackFloat(offset) -> float
|
||||
|
||||
Unpacks float field from plist at given offset
|
||||
'''
|
||||
obj_header = self.data[offset]
|
||||
obj_type, obj_info = (obj_header & 0xF0), (obj_header & 0x0F)
|
||||
int_sz = 2**obj_info
|
||||
return int_sz, self.__unpackFloatStruct(int_sz, self.data[offset+1:offset+1+int_sz])
|
||||
|
||||
def __unpackDate(self, offset):
|
||||
td = int(struct.unpack(">d", self.data[offset+1:offset+9])[0])
|
||||
return datetime(year=2001,month=1,day=1) + timedelta(seconds=td)
|
||||
|
||||
def __unpackItem(self, offset):
|
||||
'''__unpackItem(offset)
|
||||
|
||||
Unpacks and returns an item from plist
|
||||
'''
|
||||
obj_header = self.data[offset]
|
||||
obj_type, obj_info = (obj_header & 0xF0), (obj_header & 0x0F)
|
||||
if obj_type == 0x00:
|
||||
if obj_info == 0x00: # null 0000 0000
|
||||
return None
|
||||
elif obj_info == 0x08: # bool 0000 1000 // false
|
||||
return False
|
||||
elif obj_info == 0x09: # bool 0000 1001 // true
|
||||
return True
|
||||
elif obj_info == 0x0F: # fill 0000 1111 // fill byte
|
||||
raise Exception("0x0F Not Implemented") # this is really pad byte, FIXME
|
||||
else:
|
||||
raise Exception('unpack item type '+str(obj_header)+' at '+str(offset)+ 'failed')
|
||||
elif obj_type == 0x10: # int 0001 nnnn ... // # of bytes is 2^nnnn, big-endian bytes
|
||||
return self.__unpackInt(offset)
|
||||
elif obj_type == 0x20: # real 0010 nnnn ... // # of bytes is 2^nnnn, big-endian bytes
|
||||
return self.__unpackFloat(offset)
|
||||
elif obj_type == 0x30: # date 0011 0011 ... // 8 byte float follows, big-endian bytes
|
||||
return self.__unpackDate(offset)
|
||||
elif obj_type == 0x40: # data 0100 nnnn [int] ... // nnnn is number of bytes unless 1111 then int count follows, followed by bytes
|
||||
obj_count, objref = self.__resolveIntSize(obj_info, offset)
|
||||
return self.data[objref:objref+obj_count] # XXX: we return data as str
|
||||
elif obj_type == 0x50: # string 0101 nnnn [int] ... // ASCII string, nnnn is # of chars, else 1111 then int count, then bytes
|
||||
obj_count, objref = self.__resolveIntSize(obj_info, offset)
|
||||
return self.data[objref:objref+obj_count]
|
||||
elif obj_type == 0x60: # string 0110 nnnn [int] ... // Unicode string, nnnn is # of chars, else 1111 then int count, then big-endian 2-byte uint16_t
|
||||
obj_count, objref = self.__resolveIntSize(obj_info, offset)
|
||||
return self.data[objref:objref+obj_count*2].decode('utf-16be')
|
||||
elif obj_type == 0x80: # uid 1000 nnnn ... // nnnn+1 is # of bytes
|
||||
# FIXME: Accept as a string for now
|
||||
obj_count, objref = self.__resolveIntSize(obj_info, offset)
|
||||
return self.data[objref:objref+obj_count]
|
||||
elif obj_type == 0xA0: # array 1010 nnnn [int] objref* // nnnn is count, unless '1111', then int count follows
|
||||
obj_count, objref = self.__resolveIntSize(obj_info, offset)
|
||||
arr = []
|
||||
for i in range(obj_count):
|
||||
arr.append(self.__unpackIntStruct(self.object_ref_size, self.data[objref+i*self.object_ref_size:objref+i*self.object_ref_size+self.object_ref_size]))
|
||||
return arr
|
||||
elif obj_type == 0xC0: # set 1100 nnnn [int] objref* // nnnn is count, unless '1111', then int count follows
|
||||
# XXX: not serializable via apple implementation
|
||||
raise Exception("0xC0 Not Implemented") # FIXME: implement
|
||||
elif obj_type == 0xD0: # dict 1101 nnnn [int] keyref* objref* // nnnn is count, unless '1111', then int count follows
|
||||
obj_count, objref = self.__resolveIntSize(obj_info, offset)
|
||||
keys = []
|
||||
for i in range(obj_count):
|
||||
keys.append(self.__unpackIntStruct(self.object_ref_size, self.data[objref+i*self.object_ref_size:objref+i*self.object_ref_size+self.object_ref_size]))
|
||||
values = []
|
||||
objref += obj_count*self.object_ref_size
|
||||
for i in range(obj_count):
|
||||
values.append(self.__unpackIntStruct(self.object_ref_size, self.data[objref+i*self.object_ref_size:objref+i*self.object_ref_size+self.object_ref_size]))
|
||||
dic = {}
|
||||
for i in range(obj_count):
|
||||
dic[keys[i]] = values[i]
|
||||
return dic
|
||||
else:
|
||||
raise Exception('don\'t know how to unpack obj type '+hex(obj_type)+' at '+str(offset))
|
||||
|
||||
def __resolveObject(self, idx):
|
||||
try:
|
||||
return self.resolved[idx]
|
||||
except KeyError:
|
||||
obj = self.objects[idx]
|
||||
if type(obj) == list:
|
||||
newArr = []
|
||||
for i in obj:
|
||||
newArr.append(self.__resolveObject(i))
|
||||
self.resolved[idx] = newArr
|
||||
return newArr
|
||||
if type(obj) == dict:
|
||||
newDic = {}
|
||||
for k,v in obj.items():
|
||||
key_resolved = self.__resolveObject(k)
|
||||
if isinstance(key_resolved, str):
|
||||
rk = key_resolved
|
||||
else:
|
||||
rk = codecs.decode(key_resolved, "utf-8")
|
||||
rv = self.__resolveObject(v)
|
||||
newDic[rk] = rv
|
||||
self.resolved[idx] = newDic
|
||||
return newDic
|
||||
else:
|
||||
self.resolved[idx] = obj
|
||||
return obj
|
||||
|
||||
def parse(self):
|
||||
# read header
|
||||
if self.data[:8] != b'bplist00':
|
||||
raise Exception('Bad magic')
|
||||
|
||||
# read trailer
|
||||
self.offset_size, self.object_ref_size, self.number_of_objects, self.top_object, self.table_offset = struct.unpack('!6xBB4xI4xI4xI', self.data[-32:])
|
||||
#print "** plist offset_size:",self.offset_size,"objref_size:",self.object_ref_size,"num_objs:",self.number_of_objects,"top:",self.top_object,"table_ofs:",self.table_offset
|
||||
|
||||
# read offset table
|
||||
self.offset_table = self.data[self.table_offset:-32]
|
||||
self.offsets = []
|
||||
ot = self.offset_table
|
||||
for i in range(self.number_of_objects):
|
||||
offset_entry = ot[:self.offset_size]
|
||||
ot = ot[self.offset_size:]
|
||||
self.offsets.append(self.__unpackIntStruct(self.offset_size, offset_entry))
|
||||
#print "** plist offsets:",self.offsets
|
||||
|
||||
# read object table
|
||||
self.objects = []
|
||||
k = 0
|
||||
for i in self.offsets:
|
||||
obj = self.__unpackItem(i)
|
||||
#print "** plist unpacked",k,type(obj),obj,"at",i
|
||||
k += 1
|
||||
self.objects.append(obj)
|
||||
|
||||
# rebuild object tree
|
||||
#for i in range(len(self.objects)):
|
||||
# self.__resolveObject(i)
|
||||
|
||||
# return root object
|
||||
return self.__resolveObject(self.top_object)
|
||||
|
||||
@classmethod
|
||||
def plistWithString(cls, s):
|
||||
parser = cls(s)
|
||||
return parser.parse()
|
||||
|
||||
# helpers for testing
|
||||
def plist(obj):
|
||||
from Foundation import NSPropertyListSerialization, NSPropertyListBinaryFormat_v1_0
|
||||
b = NSPropertyListSerialization.dataWithPropertyList_format_options_error_(obj, NSPropertyListBinaryFormat_v1_0, 0, None)
|
||||
return str(b.bytes())
|
||||
|
||||
def unplist(s):
|
||||
from Foundation import NSData, NSPropertyListSerialization
|
||||
d = NSData.dataWithBytes_length_(s, len(s))
|
||||
return NSPropertyListSerialization.propertyListWithData_options_format_error_(d, 0, None, None)
|
||||
|
||||
if __name__ == "__main__":
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
file_path = sys.argv[1]
|
||||
|
||||
with open(file_path, "rb") as fp:
|
||||
data = fp.read()
|
||||
|
||||
out = BPListReader(data).parse()
|
||||
|
||||
with open(file_path + ".json", "w") as fp:
|
||||
json.dump(out, indent=4)
|
||||
@@ -71,6 +71,11 @@ class GenerateDefaults:
|
||||
global_settings.GlobalEnviromentSettings().write_property("MacBookPro_TeraScale_2_Accel", False)
|
||||
self.constants.allow_ts2_accel = False
|
||||
|
||||
if self.model in ["MacPro3,1", "Xserve2,1"]:
|
||||
self.constants.force_quad_thread = True
|
||||
else:
|
||||
self.constants.force_quad_thread = False
|
||||
|
||||
if self.model in smbios_data.smbios_dictionary:
|
||||
if smbios_data.smbios_dictionary[self.model]["CPU Generation"] >= cpu_data.CPUGen.skylake.value:
|
||||
# On 2016-2017 MacBook Pros, 15" devices used a stock Samsung SSD with IONVMeController
|
||||
@@ -115,7 +120,6 @@ class GenerateDefaults:
|
||||
# As we don't spoof on native models, we can safely ignore this
|
||||
spoof_model = self.model
|
||||
|
||||
|
||||
if spoof_model in smbios_data.smbios_dictionary:
|
||||
if smbios_data.smbios_dictionary[spoof_model]["SecureBootModel"] is not None:
|
||||
if self.constants.sip_status is False:
|
||||
@@ -198,7 +202,6 @@ class GenerateDefaults:
|
||||
device_probe.Broadcom.Chipsets.AirportBrcmNIC,
|
||||
]
|
||||
):
|
||||
print("Modern WiFi")
|
||||
is_modern_wifi = True
|
||||
|
||||
if is_legacy_wifi is False and is_modern_wifi is False:
|
||||
@@ -206,10 +209,13 @@ class GenerateDefaults:
|
||||
|
||||
# 12.0: Legacy Wireless chipsets require root patching
|
||||
# 14.0: Modern Wireless chipsets require root patching
|
||||
self.constants.sip_status = False
|
||||
self.constants.secure_status = False
|
||||
self.constants.disable_cs_lv = True
|
||||
self.constants.disable_amfi = True
|
||||
if self.model in smbios_data.smbios_dictionary:
|
||||
if smbios_data.smbios_dictionary[self.model]["Max OS Supported"] < os_data.os_data.sonoma:
|
||||
self.constants.sip_status = True
|
||||
self.constants.sip_status = False
|
||||
self.constants.secure_status = False
|
||||
self.constants.disable_cs_lv = True
|
||||
self.constants.disable_amfi = True
|
||||
|
||||
if is_legacy_wifi is True:
|
||||
# 13.0: Enabling AirPlay to Mac patches breaks Control Center on legacy chipsets
|
||||
|
||||
@@ -7,12 +7,9 @@ This is to ensure compatibility when running without a user
|
||||
ie. during automated patching
|
||||
"""
|
||||
|
||||
import os
|
||||
import logging
|
||||
import plistlib
|
||||
|
||||
from . import subprocess_wrapper
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ install.py: Installation of OpenCore files to ESP
|
||||
import logging
|
||||
import plistlib
|
||||
import subprocess
|
||||
import applescript
|
||||
import re
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
@@ -13,8 +13,6 @@ from . import utilities, subprocess_wrapper
|
||||
|
||||
from .. import constants
|
||||
|
||||
from ..datasets import os_data
|
||||
|
||||
|
||||
class tui_disk_installation:
|
||||
def __init__(self, versions):
|
||||
@@ -30,9 +28,15 @@ class tui_disk_installation:
|
||||
# Sierra and older
|
||||
disks = plistlib.loads(subprocess.run(["/usr/sbin/diskutil", "list", "-plist"], stdout=subprocess.PIPE).stdout.decode().strip().encode())
|
||||
for disk in disks["AllDisksAndPartitions"]:
|
||||
disk_info = plistlib.loads(subprocess.run(["/usr/sbin/diskutil", "info", "-plist", disk["DeviceIdentifier"]], stdout=subprocess.PIPE).stdout.decode().strip().encode())
|
||||
try:
|
||||
all_disks[disk["DeviceIdentifier"]] = {"identifier": disk_info["DeviceNode"], "name": disk_info["MediaName"], "size": disk_info["TotalSize"], "partitions": {}}
|
||||
disk_info = plistlib.loads(subprocess.run(["/usr/sbin/diskutil", "info", "-plist", disk["DeviceIdentifier"]], stdout=subprocess.PIPE).stdout.decode().strip().encode())
|
||||
except:
|
||||
# Chinesium USB can have garbage data in MediaName
|
||||
diskutil_output = subprocess.run(["/usr/sbin/diskutil", "info", "-plist", disk["DeviceIdentifier"]], stdout=subprocess.PIPE).stdout.decode().strip()
|
||||
ungarbafied_output = re.sub(r'(<key>MediaName</key>\s*<string>).*?(</string>)', r'\1\2', diskutil_output).encode()
|
||||
disk_info = plistlib.loads(ungarbafied_output)
|
||||
try:
|
||||
all_disks[disk["DeviceIdentifier"]] = {"identifier": disk_info["DeviceNode"], "name": disk_info.get("MediaName", "Disk"), "size": disk_info["TotalSize"], "partitions": {}}
|
||||
for partition in disk["Partitions"]:
|
||||
partition_info = plistlib.loads(subprocess.run(["/usr/sbin/diskutil", "info", "-plist", partition["DeviceIdentifier"]], stdout=subprocess.PIPE).stdout.decode().strip().encode())
|
||||
all_disks[disk["DeviceIdentifier"]]["partitions"][partition["DeviceIdentifier"]] = {
|
||||
@@ -101,7 +105,7 @@ class tui_disk_installation:
|
||||
partition_info = plistlib.loads(subprocess.run(["/usr/sbin/diskutil", "info", "-plist", full_disk_identifier], stdout=subprocess.PIPE).stdout.decode().strip().encode())
|
||||
parent_disk = partition_info["ParentWholeDisk"]
|
||||
drive_host_info = plistlib.loads(subprocess.run(["/usr/sbin/diskutil", "info", "-plist", parent_disk], stdout=subprocess.PIPE).stdout.decode().strip().encode())
|
||||
sd_type = drive_host_info["MediaName"]
|
||||
sd_type = drive_host_info.get("MediaName", "Disk")
|
||||
try:
|
||||
ssd_type = drive_host_info["SolidState"]
|
||||
except KeyError:
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
kdk_handler.py: Module for parsing and determining best Kernel Debug Kit for host OS
|
||||
"""
|
||||
|
||||
import os
|
||||
import logging
|
||||
import plistlib
|
||||
import requests
|
||||
@@ -16,6 +15,7 @@ from pathlib import Path
|
||||
from .. import constants
|
||||
|
||||
from ..datasets import os_data
|
||||
from ..volume import generate_copy_arguments
|
||||
|
||||
from . import (
|
||||
network_handler,
|
||||
@@ -668,7 +668,7 @@ class KernelDebugKitUtilities:
|
||||
logging.info("Backup already exists, skipping")
|
||||
return
|
||||
|
||||
result = subprocess_wrapper.run_as_root(["/bin/cp", "-R", kdk_path, kdk_dst_path], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
result = subprocess_wrapper.run_as_root(generate_copy_arguments(kdk_path, kdk_dst_path), stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
if result.returncode != 0:
|
||||
logging.info("Failed to create KDK backup:")
|
||||
subprocess_wrapper.log(result)
|
||||
@@ -18,8 +18,7 @@ from .. import constants
|
||||
|
||||
from . import (
|
||||
analytics_handler,
|
||||
global_settings,
|
||||
subprocess_wrapper
|
||||
global_settings
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -1,47 +1,29 @@
|
||||
"""
|
||||
macos_installer_handler.py: Handler for macOS installers, both local and remote
|
||||
macos_installer_handler.py: Handler for local macOS installers
|
||||
"""
|
||||
|
||||
import enum
|
||||
import logging
|
||||
import plistlib
|
||||
import tempfile
|
||||
import subprocess
|
||||
import applescript
|
||||
import re
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from ..datasets import os_data
|
||||
|
||||
from . import (
|
||||
network_handler,
|
||||
utilities,
|
||||
subprocess_wrapper
|
||||
)
|
||||
|
||||
from ..volume import (
|
||||
can_copy_on_write,
|
||||
generate_copy_arguments
|
||||
)
|
||||
|
||||
|
||||
APPLICATION_SEARCH_PATH: str = "/Applications"
|
||||
SFR_SOFTWARE_UPDATE_PATH: str = "SFR/com_apple_MobileAsset_SFRSoftwareUpdate/com_apple_MobileAsset_SFRSoftwareUpdate.xml"
|
||||
CATALOG_URL_BASE: str = "https://swscan.apple.com/content/catalogs/others/index"
|
||||
CATALOG_URL_EXTENSION: str = ".merged-1.sucatalog"
|
||||
CATALOG_URL_VARIANTS: list = [
|
||||
"15",
|
||||
"14",
|
||||
"13",
|
||||
"12",
|
||||
"10.16",
|
||||
"10.15",
|
||||
"10.14",
|
||||
"10.13",
|
||||
"10.12",
|
||||
"10.11",
|
||||
"10.10",
|
||||
"10.9",
|
||||
"mountainlion",
|
||||
"lion",
|
||||
"snowleopard",
|
||||
"leopard",
|
||||
]
|
||||
|
||||
tmp_dir = tempfile.TemporaryDirectory()
|
||||
|
||||
@@ -113,13 +95,9 @@ class InstallerCreation():
|
||||
for file in Path(ia_tmp).glob("*"):
|
||||
subprocess.run(["/bin/rm", "-rf", str(file)])
|
||||
|
||||
# Copy installer to tmp (use CoW to avoid extra disk writes)
|
||||
args = ["/bin/cp", "-cR", installer_path, ia_tmp]
|
||||
if utilities.check_filesystem_type() != "apfs":
|
||||
# HFS+ disks do not support CoW
|
||||
args[1] = "-R"
|
||||
|
||||
# Ensure we have enough space for the duplication
|
||||
# Copy installer to tmp
|
||||
if can_copy_on_write(installer_path, ia_tmp) is False:
|
||||
# Ensure we have enough space for the duplication when CoW is not supported
|
||||
space_available = utilities.get_free_space()
|
||||
space_needed = Path(ia_tmp).stat().st_size
|
||||
if space_available < space_needed:
|
||||
@@ -127,7 +105,7 @@ class InstallerCreation():
|
||||
logging.info(f"{utilities.human_fmt(space_available)} available, {utilities.human_fmt(space_needed)} required")
|
||||
return False
|
||||
|
||||
subprocess.run(args)
|
||||
subprocess.run(generate_copy_arguments(installer_path, ia_tmp))
|
||||
|
||||
# Adjust installer_path to point to the copied installer
|
||||
installer_path = Path(ia_tmp) / Path(Path(installer_path).name)
|
||||
@@ -193,9 +171,15 @@ fi
|
||||
disks = plistlib.loads(subprocess.run(["/usr/sbin/diskutil", "list", "-plist"], stdout=subprocess.PIPE).stdout.decode().strip().encode())
|
||||
|
||||
for disk in disks["AllDisksAndPartitions"]:
|
||||
disk_info = plistlib.loads(subprocess.run(["/usr/sbin/diskutil", "info", "-plist", disk["DeviceIdentifier"]], stdout=subprocess.PIPE).stdout.decode().strip().encode())
|
||||
try:
|
||||
all_disks[disk["DeviceIdentifier"]] = {"identifier": disk_info["DeviceNode"], "name": disk_info["MediaName"], "size": disk_info["TotalSize"], "removable": disk_info["Internal"], "partitions": {}}
|
||||
disk_info = plistlib.loads(subprocess.run(["/usr/sbin/diskutil", "info", "-plist", disk["DeviceIdentifier"]], stdout=subprocess.PIPE).stdout.decode().strip().encode())
|
||||
except:
|
||||
# Chinesium USB can have garbage data in MediaName
|
||||
diskutil_output = subprocess.run(["/usr/sbin/diskutil", "info", "-plist", disk["DeviceIdentifier"]], stdout=subprocess.PIPE).stdout.decode().strip()
|
||||
ungarbafied_output = re.sub(r'(<key>MediaName</key>\s*<string>).*?(</string>)', r'\1\2', diskutil_output).encode()
|
||||
disk_info = plistlib.loads(ungarbafied_output)
|
||||
try:
|
||||
all_disks[disk["DeviceIdentifier"]] = {"identifier": disk_info["DeviceNode"], "name": disk_info.get("MediaName", "Disk"), "size": disk_info["TotalSize"], "removable": disk_info["Internal"], "partitions": {}}
|
||||
except KeyError:
|
||||
# Avoid crashing with CDs installed
|
||||
continue
|
||||
@@ -221,288 +205,6 @@ fi
|
||||
return list_disks
|
||||
|
||||
|
||||
class SeedType(enum.IntEnum):
|
||||
"""
|
||||
Enum for catalog types
|
||||
|
||||
Variants:
|
||||
DeveloperSeed: Developer Beta (Part of the Apple Developer Program)
|
||||
PublicSeed: Public Beta
|
||||
CustomerSeed: AppleSeed Program (Generally mirrors DeveloperSeed)
|
||||
PublicRelease: Public Release
|
||||
"""
|
||||
DeveloperSeed: int = 0
|
||||
PublicSeed: int = 1
|
||||
CustomerSeed: int = 2
|
||||
PublicRelease: int = 3
|
||||
|
||||
|
||||
class RemoteInstallerCatalog:
|
||||
"""
|
||||
Parses Apple's Software Update catalog and finds all macOS installers.
|
||||
"""
|
||||
|
||||
def __init__(self, seed_override: SeedType = SeedType.PublicRelease, os_override: int = os_data.os_data.sonoma) -> None:
|
||||
|
||||
self.catalog_url: str = self._construct_catalog_url(seed_override, os_override)
|
||||
|
||||
self.available_apps: dict = self._parse_catalog()
|
||||
self.available_apps_latest: dict = self._list_newest_installers_only()
|
||||
|
||||
|
||||
def _construct_catalog_url(self, seed_type: SeedType, os_kernel: int) -> str:
|
||||
"""
|
||||
Constructs the catalog URL based on the seed type
|
||||
|
||||
Parameters:
|
||||
seed_type (SeedType): The seed type to use
|
||||
|
||||
Returns:
|
||||
str: The catalog URL
|
||||
"""
|
||||
|
||||
url: str = CATALOG_URL_BASE
|
||||
|
||||
os_version: str = os_data.os_conversion.kernel_to_os(os_kernel)
|
||||
os_version = "10.16" if os_version == "11" else os_version
|
||||
if os_version not in CATALOG_URL_VARIANTS:
|
||||
logging.error(f"OS version {os_version} is not supported, defaulting to latest")
|
||||
os_version = CATALOG_URL_VARIANTS[0]
|
||||
|
||||
url += f"-{os_version}"
|
||||
if seed_type == SeedType.DeveloperSeed:
|
||||
url += f"seed"
|
||||
elif seed_type == SeedType.PublicSeed:
|
||||
url += f"beta"
|
||||
elif seed_type == SeedType.CustomerSeed:
|
||||
url += f"customerseed"
|
||||
|
||||
did_find_variant: bool = False
|
||||
for variant in CATALOG_URL_VARIANTS:
|
||||
if variant in url:
|
||||
did_find_variant = True
|
||||
if did_find_variant:
|
||||
url += f"-{variant}"
|
||||
|
||||
url += f"{CATALOG_URL_EXTENSION}"
|
||||
|
||||
return url
|
||||
|
||||
|
||||
def _fetch_catalog(self) -> dict:
|
||||
"""
|
||||
Fetches the catalog from Apple's servers
|
||||
|
||||
Returns:
|
||||
dict: The catalog as a dictionary
|
||||
"""
|
||||
|
||||
catalog: dict = {}
|
||||
|
||||
if network_handler.NetworkUtilities(self.catalog_url).verify_network_connection() is False:
|
||||
return catalog
|
||||
|
||||
try:
|
||||
catalog = plistlib.loads(network_handler.NetworkUtilities().get(self.catalog_url).content)
|
||||
except plistlib.InvalidFileException:
|
||||
return {}
|
||||
|
||||
return catalog
|
||||
|
||||
def _parse_catalog(self) -> dict:
|
||||
"""
|
||||
Parses the catalog and returns a dictionary of available installers
|
||||
|
||||
Returns:
|
||||
dict: Dictionary of available installers
|
||||
"""
|
||||
available_apps: dict = {}
|
||||
|
||||
catalog: dict = self._fetch_catalog()
|
||||
if not catalog:
|
||||
return available_apps
|
||||
|
||||
if "Products" not in catalog:
|
||||
return available_apps
|
||||
|
||||
for product in catalog["Products"]:
|
||||
if "ExtendedMetaInfo" not in catalog["Products"][product]:
|
||||
continue
|
||||
if "Packages" not in catalog["Products"][product]:
|
||||
continue
|
||||
if "InstallAssistantPackageIdentifiers" not in catalog["Products"][product]["ExtendedMetaInfo"]:
|
||||
continue
|
||||
if "SharedSupport" not in catalog["Products"][product]["ExtendedMetaInfo"]["InstallAssistantPackageIdentifiers"]:
|
||||
continue
|
||||
if "BuildManifest" not in catalog["Products"][product]["ExtendedMetaInfo"]["InstallAssistantPackageIdentifiers"]:
|
||||
continue
|
||||
|
||||
for bm_package in catalog["Products"][product]["Packages"]:
|
||||
if "Info.plist" not in bm_package["URL"]:
|
||||
continue
|
||||
if "InstallInfo.plist" in bm_package["URL"]:
|
||||
continue
|
||||
|
||||
try:
|
||||
build_plist = plistlib.loads(network_handler.NetworkUtilities().get(bm_package["URL"]).content)
|
||||
except plistlib.InvalidFileException:
|
||||
continue
|
||||
|
||||
if "MobileAssetProperties" not in build_plist:
|
||||
continue
|
||||
if "SupportedDeviceModels" not in build_plist["MobileAssetProperties"]:
|
||||
continue
|
||||
if "OSVersion" not in build_plist["MobileAssetProperties"]:
|
||||
continue
|
||||
if "Build" not in build_plist["MobileAssetProperties"]:
|
||||
continue
|
||||
|
||||
# Ensure Apple Silicon specific Installers are not listed
|
||||
if "VMM-x86_64" not in build_plist["MobileAssetProperties"]["SupportedDeviceModels"]:
|
||||
continue
|
||||
|
||||
version = build_plist["MobileAssetProperties"]["OSVersion"]
|
||||
build = build_plist["MobileAssetProperties"]["Build"]
|
||||
|
||||
try:
|
||||
catalog_url = build_plist["MobileAssetProperties"]["BridgeVersionInfo"]["CatalogURL"]
|
||||
if "beta" in catalog_url:
|
||||
catalog_url = "PublicSeed"
|
||||
elif "customerseed" in catalog_url:
|
||||
catalog_url = "CustomerSeed"
|
||||
elif "seed" in catalog_url:
|
||||
catalog_url = "DeveloperSeed"
|
||||
else:
|
||||
catalog_url = "Public"
|
||||
except KeyError:
|
||||
# Assume Public if no catalog URL is found
|
||||
catalog_url = "Public"
|
||||
|
||||
download_link = None
|
||||
integrity = None
|
||||
size = None
|
||||
date = catalog["Products"][product]["PostDate"]
|
||||
|
||||
for ia_package in catalog["Products"][product]["Packages"]:
|
||||
if "InstallAssistant.pkg" not in ia_package["URL"]:
|
||||
continue
|
||||
if "URL" not in ia_package:
|
||||
continue
|
||||
if "IntegrityDataURL" not in ia_package:
|
||||
continue
|
||||
|
||||
download_link = ia_package["URL"]
|
||||
integrity = ia_package["IntegrityDataURL"]
|
||||
size = ia_package["Size"] if ia_package["Size"] else 0
|
||||
|
||||
|
||||
if any([version, build, download_link, size, integrity]) is None:
|
||||
continue
|
||||
|
||||
available_apps.update({
|
||||
product: {
|
||||
"Version": version,
|
||||
"Build": build,
|
||||
"Link": download_link,
|
||||
"Size": size,
|
||||
"integrity": integrity,
|
||||
"Source": "Apple Inc.",
|
||||
"Variant": catalog_url,
|
||||
"OS": os_data.os_conversion.os_to_kernel(version),
|
||||
"Models": build_plist["MobileAssetProperties"]["SupportedDeviceModels"],
|
||||
"Date": date
|
||||
}
|
||||
})
|
||||
|
||||
available_apps = {k: v for k, v in sorted(available_apps.items(), key=lambda x: x[1]['Version'])}
|
||||
|
||||
return available_apps
|
||||
|
||||
|
||||
def _list_newest_installers_only(self) -> dict:
|
||||
"""
|
||||
Returns a dictionary of the newest macOS installers only.
|
||||
Primarily used to avoid overwhelming the user with a list of
|
||||
installers that are not the newest version.
|
||||
|
||||
Returns:
|
||||
dict: A dictionary of the newest macOS installers only.
|
||||
"""
|
||||
|
||||
if self.available_apps is None:
|
||||
return {}
|
||||
|
||||
newest_apps: dict = self.available_apps.copy()
|
||||
supported_versions = ["10.13", "10.14", "10.15", "11", "12", "13", "14"]
|
||||
|
||||
for version in supported_versions:
|
||||
remote_version_minor = 0
|
||||
remote_version_security = 0
|
||||
os_builds = []
|
||||
|
||||
# First determine the largest version
|
||||
for ia in newest_apps:
|
||||
if newest_apps[ia]["Version"].startswith(version):
|
||||
if newest_apps[ia]["Variant"] not in ["CustomerSeed", "DeveloperSeed", "PublicSeed"]:
|
||||
remote_version = newest_apps[ia]["Version"].split(".")
|
||||
if remote_version[0] == "10":
|
||||
remote_version.pop(0)
|
||||
remote_version.pop(0)
|
||||
else:
|
||||
remote_version.pop(0)
|
||||
if int(remote_version[0]) > remote_version_minor:
|
||||
remote_version_minor = int(remote_version[0])
|
||||
remote_version_security = 0 # Reset as new minor version found
|
||||
if len(remote_version) > 1:
|
||||
if int(remote_version[1]) > remote_version_security:
|
||||
remote_version_security = int(remote_version[1])
|
||||
|
||||
# Now remove all versions that are not the largest
|
||||
for ia in list(newest_apps):
|
||||
# Don't use Beta builds to determine latest version
|
||||
if newest_apps[ia]["Variant"] in ["CustomerSeed", "DeveloperSeed", "PublicSeed"]:
|
||||
continue
|
||||
|
||||
if newest_apps[ia]["Version"].startswith(version):
|
||||
remote_version = newest_apps[ia]["Version"].split(".")
|
||||
if remote_version[0] == "10":
|
||||
remote_version.pop(0)
|
||||
remote_version.pop(0)
|
||||
else:
|
||||
remote_version.pop(0)
|
||||
if int(remote_version[0]) < remote_version_minor:
|
||||
newest_apps.pop(ia)
|
||||
continue
|
||||
if int(remote_version[0]) == remote_version_minor:
|
||||
if len(remote_version) > 1:
|
||||
if int(remote_version[1]) < remote_version_security:
|
||||
newest_apps.pop(ia)
|
||||
continue
|
||||
else:
|
||||
if remote_version_security > 0:
|
||||
newest_apps.pop(ia)
|
||||
continue
|
||||
|
||||
# Remove duplicate builds
|
||||
# ex. macOS 12.5.1 has 2 builds in the Software Update Catalog
|
||||
# ref: https://twitter.com/classicii_mrmac/status/1560357471654379522
|
||||
if newest_apps[ia]["Build"] in os_builds:
|
||||
newest_apps.pop(ia)
|
||||
continue
|
||||
|
||||
os_builds.append(newest_apps[ia]["Build"])
|
||||
|
||||
# Remove Betas if there's a non-beta version available
|
||||
for ia in list(newest_apps):
|
||||
if newest_apps[ia]["Variant"] in ["CustomerSeed", "DeveloperSeed", "PublicSeed"]:
|
||||
for ia2 in newest_apps:
|
||||
if newest_apps[ia2]["Version"].split(".")[0] == newest_apps[ia]["Version"].split(".")[0] and newest_apps[ia2]["Variant"] not in ["CustomerSeed", "DeveloperSeed", "PublicSeed"]:
|
||||
newest_apps.pop(ia)
|
||||
break
|
||||
|
||||
return newest_apps
|
||||
|
||||
|
||||
class LocalInstallerCatalog:
|
||||
"""
|
||||
Finds all macOS installers on the local machine.
|
||||
@@ -641,9 +343,15 @@ class LocalInstallerCatalog:
|
||||
if output.returncode != 0:
|
||||
return (detected_build, detected_os)
|
||||
|
||||
ss_info = Path(SFR_SOFTWARE_UPDATE_PATH)
|
||||
|
||||
if Path(tmpdir / ss_info).exists():
|
||||
ss_info_files = [
|
||||
Path("SFR/com_apple_MobileAsset_SFRSoftwareUpdate/com_apple_MobileAsset_SFRSoftwareUpdate.xml"),
|
||||
Path("com_apple_MobileAsset_MacSoftwareUpdate/com_apple_MobileAsset_MacSoftwareUpdate.xml")
|
||||
]
|
||||
|
||||
for ss_info in ss_info_files:
|
||||
if not Path(tmpdir / ss_info).exists():
|
||||
continue
|
||||
plist = plistlib.load((tmpdir / ss_info).open("rb"))
|
||||
if "Assets" in plist:
|
||||
if "Build" in plist["Assets"][0]:
|
||||
|
||||
274
opencore_legacy_patcher/support/metallib_handler.py
Normal file
@@ -0,0 +1,274 @@
|
||||
"""
|
||||
metallib_handler.py: Library for handling Metal libraries
|
||||
"""
|
||||
|
||||
import logging
|
||||
import requests
|
||||
import subprocess
|
||||
import packaging.version
|
||||
|
||||
from typing import cast
|
||||
from pathlib import Path
|
||||
|
||||
from . import network_handler, subprocess_wrapper
|
||||
from .. import constants
|
||||
|
||||
from ..datasets import os_data
|
||||
|
||||
|
||||
METALLIB_INSTALL_PATH: str = "/Library/Application Support/Dortania/MetallibSupportPkg"
|
||||
METALLIB_API_LINK: str = "https://dortania.github.io/MetallibSupportPkg/manifest.json"
|
||||
|
||||
METALLIB_ASSET_LIST: list = None
|
||||
|
||||
|
||||
class MetalLibraryObject:
|
||||
|
||||
def __init__(self, global_constants: constants.Constants,
|
||||
host_build: str, host_version: str,
|
||||
ignore_installed: bool = False, passive: bool = False
|
||||
) -> None:
|
||||
|
||||
self.constants: constants.Constants = global_constants
|
||||
|
||||
self.host_build: str = host_build # ex. 20A5384c
|
||||
self.host_version: str = host_version # ex. 11.0.1
|
||||
|
||||
self.passive: bool = passive # Don't perform actions requiring elevated privileges
|
||||
|
||||
self.ignore_installed: bool = ignore_installed # If True, will ignore any installed MetallibSupportPkg PKGs and download the latest
|
||||
self.metallib_already_installed: bool = False
|
||||
|
||||
self.metallib_installed_path: str = ""
|
||||
|
||||
self.metallib_url: str = ""
|
||||
self.metallib_url_build: str = ""
|
||||
self.metallib_url_version: str = ""
|
||||
|
||||
self.metallib_url_is_exactly_match: bool = False
|
||||
|
||||
self.metallib_closest_match_url: str = ""
|
||||
self.metallib_closest_match_url_build: str = ""
|
||||
self.metallib_closest_match_url_version: str = ""
|
||||
|
||||
self.success: bool = False
|
||||
|
||||
self.error_msg: str = ""
|
||||
|
||||
self._get_latest_metallib()
|
||||
|
||||
|
||||
def _get_remote_metallibs(self) -> dict:
|
||||
"""
|
||||
Get the MetallibSupportPkg list from the API
|
||||
"""
|
||||
|
||||
global METALLIB_ASSET_LIST
|
||||
|
||||
logging.info("Pulling metallib list from MetallibSupportPkg API")
|
||||
if METALLIB_ASSET_LIST:
|
||||
return METALLIB_ASSET_LIST
|
||||
|
||||
try:
|
||||
results = network_handler.NetworkUtilities().get(
|
||||
METALLIB_API_LINK,
|
||||
headers={
|
||||
"User-Agent": f"OCLP/{self.constants.patcher_version}"
|
||||
},
|
||||
timeout=5
|
||||
)
|
||||
except (requests.exceptions.Timeout, requests.exceptions.TooManyRedirects, requests.exceptions.ConnectionError):
|
||||
logging.info("Could not contact MetallibSupportPkg API")
|
||||
return None
|
||||
|
||||
if results.status_code != 200:
|
||||
logging.info("Could not fetch Metallib list")
|
||||
return None
|
||||
|
||||
METALLIB_ASSET_LIST = results.json()
|
||||
|
||||
return METALLIB_ASSET_LIST
|
||||
|
||||
|
||||
def _get_latest_metallib(self) -> None:
|
||||
"""
|
||||
Get the latest MetallibSupportPkg PKG
|
||||
"""
|
||||
|
||||
parsed_version = cast(packaging.version.Version, packaging.version.parse(self.host_version))
|
||||
|
||||
if os_data.os_conversion.os_to_kernel(str(parsed_version.major)) < os_data.os_data.sequoia:
|
||||
self.error_msg = "MetallibSupportPkg is not required for macOS Sonoma or older"
|
||||
logging.warning(f"{self.error_msg}")
|
||||
return
|
||||
|
||||
self.metallib_installed_path = self._local_metallib_installed()
|
||||
if self.metallib_installed_path:
|
||||
logging.info(f"metallib already installed ({Path(self.metallib_installed_path).name}), skipping")
|
||||
self.metallib_already_installed = True
|
||||
self.success = True
|
||||
return
|
||||
|
||||
remote_metallib_version = self._get_remote_metallibs()
|
||||
|
||||
if remote_metallib_version is None:
|
||||
logging.warning("Failed to fetch metallib list, falling back to local metallib matching")
|
||||
|
||||
# First check if a metallib matching the current macOS version is installed
|
||||
# ex. 13.0.1 vs 13.0
|
||||
loose_version = f"{parsed_version.major}.{parsed_version.minor}"
|
||||
logging.info(f"Checking for metallibs loosely matching {loose_version}")
|
||||
self.metallib_installed_path = self._local_metallib_installed(match=loose_version, check_version=True)
|
||||
if self.metallib_installed_path:
|
||||
logging.info(f"Found matching metallib: {Path(self.metallib_installed_path).name}")
|
||||
self.metallib_already_installed = True
|
||||
self.success = True
|
||||
return
|
||||
|
||||
older_version = f"{parsed_version.major}.{parsed_version.minor - 1 if parsed_version.minor > 0 else 0}"
|
||||
logging.info(f"Checking for metallibs matching {older_version}")
|
||||
self.metallib_installed_path = self._local_metallib_installed(match=older_version, check_version=True)
|
||||
if self.metallib_installed_path:
|
||||
logging.info(f"Found matching metallib: {Path(self.metallib_installed_path).name}")
|
||||
self.metallib_already_installed = True
|
||||
self.success = True
|
||||
return
|
||||
|
||||
logging.warning(f"Couldn't find metallib matching {self.host_version} or {older_version}, please install one manually")
|
||||
|
||||
self.error_msg = f"Could not contact MetallibSupportPkg API, and no metallib matching {self.host_version} ({self.host_build}) or {older_version} was installed.\nPlease ensure you have a network connection or manually install a metallib."
|
||||
|
||||
return
|
||||
|
||||
|
||||
# First check exact match
|
||||
for metallib in remote_metallib_version:
|
||||
if (metallib["build"] != self.host_build):
|
||||
continue
|
||||
self.metallib_url = metallib["url"]
|
||||
self.metallib_url_build = metallib["build"]
|
||||
self.metallib_url_version = metallib["version"]
|
||||
self.metallib_url_is_exactly_match = True
|
||||
break
|
||||
|
||||
# If no exact match, check for closest match
|
||||
if self.metallib_url == "":
|
||||
for metallib in remote_metallib_version:
|
||||
metallib_version = cast(packaging.version.Version, packaging.version.parse(metallib["version"]))
|
||||
if metallib_version > parsed_version:
|
||||
continue
|
||||
if metallib_version.major != parsed_version.major:
|
||||
continue
|
||||
if metallib_version.minor not in range(parsed_version.minor - 1, parsed_version.minor + 1):
|
||||
continue
|
||||
|
||||
# The metallib list is already sorted by version then date, so the first match is the closest
|
||||
self.metallib_closest_match_url = metallib["url"]
|
||||
self.metallib_closest_match_url_build = metallib["build"]
|
||||
self.metallib_closest_match_url_version = metallib["version"]
|
||||
self.metallib_url_is_exactly_match = False
|
||||
break
|
||||
|
||||
if self.metallib_url == "":
|
||||
if self.metallib_closest_match_url == "":
|
||||
logging.warning(f"No metallibs found for {self.host_build} ({self.host_version})")
|
||||
self.error_msg = f"No metallibs found for {self.host_build} ({self.host_version})"
|
||||
return
|
||||
logging.info(f"No direct match found for {self.host_build}, falling back to closest match")
|
||||
logging.info(f"Closest Match: {self.metallib_closest_match_url_build} ({self.metallib_closest_match_url_version})")
|
||||
|
||||
self.metallib_url = self.metallib_closest_match_url
|
||||
self.metallib_url_build = self.metallib_closest_match_url_build
|
||||
self.metallib_url_version = self.metallib_closest_match_url_version
|
||||
else:
|
||||
logging.info(f"Direct match found for {self.host_build} ({self.host_version})")
|
||||
|
||||
|
||||
# Check if this metallib is already installed
|
||||
self.metallib_installed_path = self._local_metallib_installed(match=self.metallib_url_build)
|
||||
if self.metallib_installed_path:
|
||||
logging.info(f"metallib already installed ({Path(self.metallib_installed_path).name}), skipping")
|
||||
self.metallib_already_installed = True
|
||||
self.success = True
|
||||
return
|
||||
|
||||
logging.info("Following metallib is recommended:")
|
||||
logging.info(f"- metallib Build: {self.metallib_url_build}")
|
||||
logging.info(f"- metallib Version: {self.metallib_url_version}")
|
||||
logging.info(f"- metallib URL: {self.metallib_url}")
|
||||
|
||||
self.success = True
|
||||
|
||||
|
||||
def _local_metallib_installed(self, match: str = None, check_version: bool = False) -> str:
|
||||
"""
|
||||
Check if a metallib is already installed
|
||||
"""
|
||||
|
||||
if self.ignore_installed:
|
||||
return None
|
||||
|
||||
if not Path(METALLIB_INSTALL_PATH).exists():
|
||||
return None
|
||||
|
||||
for metallib_folder in Path(METALLIB_INSTALL_PATH).iterdir():
|
||||
if not metallib_folder.is_dir():
|
||||
continue
|
||||
if check_version:
|
||||
if match not in metallib_folder.name:
|
||||
continue
|
||||
else:
|
||||
if not metallib_folder.name.endswith(f"-{match}"):
|
||||
continue
|
||||
|
||||
return metallib_folder
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def retrieve_download(self, override_path: str = "") -> network_handler.DownloadObject:
|
||||
"""
|
||||
Retrieve MetallibSupportPkg PKG download object
|
||||
"""
|
||||
|
||||
self.success = False
|
||||
self.error_msg = ""
|
||||
|
||||
if self.metallib_already_installed:
|
||||
logging.info("No download required, metallib already installed")
|
||||
self.success = True
|
||||
return None
|
||||
|
||||
if self.metallib_url == "":
|
||||
self.error_msg = "Could not retrieve metallib catalog, no metallib to download"
|
||||
logging.error(self.error_msg)
|
||||
return None
|
||||
|
||||
logging.info(f"Returning DownloadObject for metallib: {Path(self.metallib_url).name}")
|
||||
self.success = True
|
||||
|
||||
metallib_download_path = self.constants.metallib_download_path if override_path == "" else Path(override_path)
|
||||
return network_handler.DownloadObject(self.metallib_url, metallib_download_path)
|
||||
|
||||
|
||||
def install_metallib(self, metallib: str = None) -> None:
|
||||
"""
|
||||
Install MetallibSupportPkg PKG
|
||||
"""
|
||||
|
||||
if not self.success:
|
||||
logging.error("Cannot install metallib, no metallib was successfully retrieved")
|
||||
return False
|
||||
|
||||
if self.metallib_already_installed:
|
||||
logging.info("No installation required, metallib already installed")
|
||||
return True
|
||||
|
||||
result = subprocess_wrapper.run_as_root([
|
||||
"/usr/sbin/installer", "-pkg", metallib if metallib else self.constants.metallib_download_path, "-target", "/"
|
||||
], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
if result.returncode != 0:
|
||||
subprocess_wrapper.log(result)
|
||||
return False
|
||||
|
||||
return True
|
||||
@@ -3,7 +3,6 @@ subprocess_wrapper.py: Wrapper for subprocess module to better handle errors and
|
||||
Additionally handles our Privileged Helper Tool
|
||||
"""
|
||||
|
||||
import os
|
||||
import enum
|
||||
import logging
|
||||
import subprocess
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
validation.py: Validation class for the patcher
|
||||
"""
|
||||
|
||||
import atexit
|
||||
import logging
|
||||
import subprocess
|
||||
|
||||
@@ -18,9 +19,13 @@ from ..support import subprocess_wrapper
|
||||
from ..datasets import (
|
||||
example_data,
|
||||
model_array,
|
||||
sys_patch_dict,
|
||||
os_data
|
||||
)
|
||||
from ..sys_patch.patchsets import (
|
||||
HardwarePatchsetDetection,
|
||||
PatchType,
|
||||
DynamicPatchset
|
||||
)
|
||||
|
||||
|
||||
class PatcherValidation:
|
||||
@@ -119,48 +124,55 @@ class PatcherValidation:
|
||||
minor_kernel (int): Minor kernel version
|
||||
"""
|
||||
|
||||
patchset = sys_patch_dict.SystemPatchDictionary(major_kernel, minor_kernel, self.constants.legacy_accel_support, self.constants.detected_os_version).patchset_dict
|
||||
host_os_float = float(f"{major_kernel}.{minor_kernel}")
|
||||
patch_type_merge_exempt = ["MechanismPlugins"]
|
||||
patch_type_overwrite_exempt = []
|
||||
|
||||
for patch_subject in patchset:
|
||||
for patch_core in patchset[patch_subject]:
|
||||
patch_os_min_float = float(f'{patchset[patch_subject][patch_core]["OS Support"]["Minimum OS Support"]["OS Major"]}.{patchset[patch_subject][patch_core]["OS Support"]["Minimum OS Support"]["OS Minor"]}')
|
||||
patch_os_max_float = float(f'{patchset[patch_subject][patch_core]["OS Support"]["Maximum OS Support"]["OS Major"]}.{patchset[patch_subject][patch_core]["OS Support"]["Maximum OS Support"]["OS Minor"]}')
|
||||
if (host_os_float < patch_os_min_float or host_os_float > patch_os_max_float):
|
||||
continue
|
||||
for install_type in ["Install", "Install Non-Root"]:
|
||||
if install_type in patchset[patch_subject][patch_core]:
|
||||
for install_directory in patchset[patch_subject][patch_core][install_type]:
|
||||
for install_file in patchset[patch_subject][patch_core][install_type][install_directory]:
|
||||
source_file = str(self.constants.payload_local_binaries_root_path) + "/" + patchset[patch_subject][patch_core][install_type][install_directory][install_file] + install_directory + "/" + install_file
|
||||
if not Path(source_file).exists():
|
||||
logging.info(f"File not found: {source_file}")
|
||||
raise Exception(f"Failed to find {source_file}")
|
||||
if self.verify_unused_files is True:
|
||||
patchset = HardwarePatchsetDetection(self.constants, xnu_major=major_kernel, xnu_minor=minor_kernel, validation=True).patches
|
||||
|
||||
for patch_core in patchset:
|
||||
# Check if any unknown PathType is present
|
||||
for install_type in patchset[patch_core]:
|
||||
if install_type not in PatchType:
|
||||
raise Exception(f"Unknown PatchType: {install_type}")
|
||||
|
||||
for install_type in [PatchType.OVERWRITE_SYSTEM_VOLUME, PatchType.OVERWRITE_DATA_VOLUME, PatchType.MERGE_SYSTEM_VOLUME, PatchType.MERGE_DATA_VOLUME]:
|
||||
if install_type in patchset[patch_core]:
|
||||
for install_directory in patchset[patch_core][install_type]:
|
||||
for install_file in patchset[patch_core][install_type][install_directory]:
|
||||
try:
|
||||
if patchset[patch_core][install_type][install_directory][install_file] in DynamicPatchset:
|
||||
continue
|
||||
except TypeError:
|
||||
pass
|
||||
|
||||
# Technically there is nothing wrong with using a .framework with OVERWRITE, but it's a good indicator of a mistake
|
||||
if install_type in [PatchType.OVERWRITE_SYSTEM_VOLUME, PatchType.OVERWRITE_DATA_VOLUME]:
|
||||
if install_file.endswith(".framework") and install_file not in patch_type_overwrite_exempt:
|
||||
raise Exception(f"{install_file} used with {install_type}, are you certain this is correct?")
|
||||
elif install_type in [PatchType.MERGE_SYSTEM_VOLUME, PatchType.MERGE_DATA_VOLUME]:
|
||||
if not install_file.endswith(".framework") and install_file not in patch_type_merge_exempt:
|
||||
raise Exception(f"{install_file} used with {install_type}, are you certain this is correct?")
|
||||
|
||||
source_file = str(self.constants.payload_local_binaries_root_path) + "/" + patchset[patch_core][install_type][install_directory][install_file] + install_directory + "/" + install_file
|
||||
if not Path(source_file).exists():
|
||||
logging.info(f"File not found: {source_file}")
|
||||
raise Exception(f"Failed to find {source_file}")
|
||||
if self.verify_unused_files is True:
|
||||
if source_file not in self.active_patchset_files:
|
||||
self.active_patchset_files.append(source_file)
|
||||
|
||||
logging.info(f"Validating against Darwin {major_kernel}.{minor_kernel}")
|
||||
if not sys_patch_helpers.SysPatchHelpers(self.constants).generate_patchset_plist(patchset, f"OpenCore-Legacy-Patcher-{major_kernel}.{minor_kernel}.plist", None):
|
||||
if not sys_patch_helpers.SysPatchHelpers(self.constants).generate_patchset_plist(patchset, f"OpenCore-Legacy-Patcher-{major_kernel}.{minor_kernel}.plist", None, None):
|
||||
raise Exception("Failed to generate patchset plist")
|
||||
|
||||
# Remove the plist file after validation
|
||||
Path(self.constants.payload_path / f"OpenCore-Legacy-Patcher-{major_kernel}.{minor_kernel}.plist").unlink()
|
||||
|
||||
|
||||
def _validate_sys_patch(self) -> None:
|
||||
def _unmount_dmg(self) -> None:
|
||||
"""
|
||||
Validates sys_patch modules
|
||||
Unmounts the Universal-Binaries.dmg
|
||||
"""
|
||||
|
||||
if not Path(self.constants.payload_local_binaries_root_path_dmg).exists():
|
||||
dl_obj = network_handler.DownloadObject(f"https://github.com/dortania/PatcherSupportPkg/releases/download/{self.constants.patcher_support_pkg_version}/Universal-Binaries.dmg", self.constants.payload_local_binaries_root_path_dmg)
|
||||
dl_obj.download(spawn_thread=False)
|
||||
if dl_obj.download_complete is False:
|
||||
logging.info("Failed to download Universal-Binaries.dmg")
|
||||
raise Exception("Failed to download Universal-Binaries.dmg")
|
||||
|
||||
logging.info("Validating Root Patch File integrity")
|
||||
|
||||
if Path(self.constants.payload_path / Path("Universal-Binaries_overlay")).exists():
|
||||
subprocess.run(
|
||||
[
|
||||
@@ -183,6 +195,23 @@ class PatcherValidation:
|
||||
|
||||
raise Exception("Failed to unmount Universal-Binaries.dmg")
|
||||
|
||||
|
||||
def _validate_sys_patch(self) -> None:
|
||||
"""
|
||||
Validates sys_patch modules
|
||||
"""
|
||||
|
||||
if not Path(self.constants.payload_local_binaries_root_path_dmg).exists():
|
||||
dl_obj = network_handler.DownloadObject(f"https://github.com/dortania/PatcherSupportPkg/releases/download/{self.constants.patcher_support_pkg_version}/Universal-Binaries.dmg", self.constants.payload_local_binaries_root_path_dmg)
|
||||
dl_obj.download(spawn_thread=False)
|
||||
if dl_obj.download_complete is False:
|
||||
logging.info("Failed to download Universal-Binaries.dmg")
|
||||
raise Exception("Failed to download Universal-Binaries.dmg")
|
||||
|
||||
logging.info("Validating Root Patch File integrity")
|
||||
|
||||
self._unmount_dmg()
|
||||
|
||||
output = subprocess.run(
|
||||
[
|
||||
"/usr/bin/hdiutil", "attach", "-noverify", f"{self.constants.payload_local_binaries_root_path_dmg}",
|
||||
@@ -202,8 +231,9 @@ class PatcherValidation:
|
||||
|
||||
logging.info("Mounted Universal-Binaries.dmg")
|
||||
|
||||
atexit.register(self._unmount_dmg)
|
||||
|
||||
for supported_os in [os_data.os_data.big_sur, os_data.os_data.monterey, os_data.os_data.ventura, os_data.os_data.sonoma]:
|
||||
for supported_os in [os_data.os_data.big_sur, os_data.os_data.monterey, os_data.os_data.ventura, os_data.os_data.sonoma, os_data.os_data.sequoia]:
|
||||
for i in range(0, 10):
|
||||
self._validate_root_patch_files(supported_os, i)
|
||||
|
||||
|
||||
17
opencore_legacy_patcher/sys_patch/auto_patcher/__init__.py
Normal file
@@ -0,0 +1,17 @@
|
||||
"""
|
||||
auto_patcher: Automatic system volume patching after updates, etc.
|
||||
|
||||
Usage:
|
||||
|
||||
>>> # Installing launch services
|
||||
>>> from auto_patcher import InstallAutomaticPatchingServices
|
||||
>>> InstallAutomaticPatchingServices(self.constants).install_auto_patcher_launch_agent()
|
||||
|
||||
|
||||
>>> # When patching the system volume (ex. launch service)
|
||||
>>> from auto_patcher import StartAutomaticPatching
|
||||
>>> StartAutomaticPatching(self.constants).start_auto_patch()
|
||||
"""
|
||||
|
||||
from .install import InstallAutomaticPatchingServices
|
||||
from .start import StartAutomaticPatching
|
||||
120
opencore_legacy_patcher/sys_patch/auto_patcher/install.py
Normal file
@@ -0,0 +1,120 @@
|
||||
"""
|
||||
install.py: Install the auto patcher launch services
|
||||
"""
|
||||
|
||||
import hashlib
|
||||
import logging
|
||||
import plistlib
|
||||
import subprocess
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from ... import constants
|
||||
|
||||
from ...volume import generate_copy_arguments
|
||||
|
||||
from ...support import (
|
||||
utilities,
|
||||
subprocess_wrapper
|
||||
)
|
||||
|
||||
|
||||
class InstallAutomaticPatchingServices:
|
||||
"""
|
||||
Install the auto patcher launch services
|
||||
"""
|
||||
|
||||
def __init__(self, global_constants: constants.Constants):
|
||||
self.constants: constants.Constants = global_constants
|
||||
|
||||
|
||||
def install_auto_patcher_launch_agent(self, kdk_caching_needed: bool = False):
|
||||
"""
|
||||
Install patcher launch services
|
||||
|
||||
See start_auto_patch() comments for more info
|
||||
"""
|
||||
|
||||
if self.constants.launcher_script is not None:
|
||||
logging.info("- Skipping Auto Patcher Launch Agent, not supported when running from source")
|
||||
return
|
||||
|
||||
services = {
|
||||
self.constants.auto_patch_launch_agent_path: "/Library/LaunchAgents/com.dortania.opencore-legacy-patcher.auto-patch.plist",
|
||||
self.constants.update_launch_daemon_path: "/Library/LaunchDaemons/com.dortania.opencore-legacy-patcher.macos-update.plist",
|
||||
**({ self.constants.rsr_monitor_launch_daemon_path: "/Library/LaunchDaemons/com.dortania.opencore-legacy-patcher.rsr-monitor.plist" } if self._create_rsr_monitor_daemon() else {}),
|
||||
**({ self.constants.kdk_launch_daemon_path: "/Library/LaunchDaemons/com.dortania.opencore-legacy-patcher.os-caching.plist" } if kdk_caching_needed is True else {} ),
|
||||
}
|
||||
|
||||
for service in services:
|
||||
name = Path(service).name
|
||||
logging.info(f"- Installing {name}")
|
||||
if Path(services[service]).exists():
|
||||
if hashlib.sha256(open(service, "rb").read()).hexdigest() == hashlib.sha256(open(services[service], "rb").read()).hexdigest():
|
||||
logging.info(f" - {name} checksums match, skipping")
|
||||
continue
|
||||
logging.info(f" - Existing service found, removing")
|
||||
subprocess_wrapper.run_as_root_and_verify(["/bin/rm", services[service]], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
# Create parent directories
|
||||
if not Path(services[service]).parent.exists():
|
||||
logging.info(f" - Creating {Path(services[service]).parent} directory")
|
||||
subprocess_wrapper.run_as_root_and_verify(["/bin/mkdir", "-p", Path(services[service]).parent], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
subprocess_wrapper.run_as_root_and_verify(generate_copy_arguments(service, services[service]), stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
|
||||
# Set the permissions on the service
|
||||
subprocess_wrapper.run_as_root_and_verify(["/bin/chmod", "644", services[service]], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
subprocess_wrapper.run_as_root_and_verify(["/usr/sbin/chown", "root:wheel", services[service]], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
|
||||
|
||||
def _create_rsr_monitor_daemon(self) -> bool:
|
||||
# Get kext list in /Library/Extensions that have the 'GPUCompanionBundles' property
|
||||
# This is used to determine if we need to run the RSRMonitor
|
||||
logging.info("- Checking if RSRMonitor is needed")
|
||||
|
||||
cryptex_path = f"/System/Volumes/Preboot/{utilities.get_preboot_uuid()}/cryptex1/current/OS.dmg"
|
||||
if not Path(cryptex_path).exists():
|
||||
logging.info("- No OS.dmg, skipping RSRMonitor")
|
||||
return False
|
||||
|
||||
kexts = []
|
||||
for kext in Path("/Library/Extensions").glob("*.kext"):
|
||||
try:
|
||||
if not Path(f"{kext}/Contents/Info.plist").exists():
|
||||
continue
|
||||
except Exception as e:
|
||||
logging.info(f" - Failed to check if {kext.name} is a directory: {e}")
|
||||
continue
|
||||
try:
|
||||
kext_plist = plistlib.load(open(f"{kext}/Contents/Info.plist", "rb"))
|
||||
except Exception as e:
|
||||
logging.info(f" - Failed to load plist for {kext.name}: {e}")
|
||||
continue
|
||||
if "GPUCompanionBundles" not in kext_plist:
|
||||
continue
|
||||
logging.info(f" - Found kext with GPUCompanionBundles: {kext.name}")
|
||||
kexts.append(kext.name)
|
||||
|
||||
# If we have no kexts, we don't need to run the RSRMonitor
|
||||
if not kexts:
|
||||
logging.info("- No kexts found with GPUCompanionBundles, skipping RSRMonitor")
|
||||
return False
|
||||
|
||||
# Load the RSRMonitor plist
|
||||
rsr_monitor_plist = plistlib.load(open(self.constants.rsr_monitor_launch_daemon_path, "rb"))
|
||||
|
||||
arguments = ["/bin/rm", "-Rfv"]
|
||||
arguments += [f"/Library/Extensions/{kext}" for kext in kexts]
|
||||
|
||||
# Add the arguments to the RSRMonitor plist
|
||||
rsr_monitor_plist["ProgramArguments"] = arguments
|
||||
|
||||
# Next add monitoring for '/System/Volumes/Preboot/{UUID}/cryptex1/OS.dmg'
|
||||
logging.info(f" - Adding monitor: {cryptex_path}")
|
||||
rsr_monitor_plist["WatchPaths"] = [
|
||||
cryptex_path,
|
||||
]
|
||||
|
||||
# Write the RSRMonitor plist
|
||||
plistlib.dump(rsr_monitor_plist, Path(self.constants.rsr_monitor_launch_daemon_path).open("wb"))
|
||||
|
||||
return True
|
||||
@@ -1,11 +1,10 @@
|
||||
"""
|
||||
sys_patch_auto.py: Library of functions for launch services, including automatic patching
|
||||
start.py: Start automatic patching of host
|
||||
"""
|
||||
|
||||
import wx
|
||||
import wx.html2
|
||||
|
||||
import hashlib
|
||||
import logging
|
||||
import plistlib
|
||||
import requests
|
||||
@@ -13,30 +12,30 @@ import markdown2
|
||||
import subprocess
|
||||
import webbrowser
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from . import sys_patch_detect
|
||||
from ... import constants
|
||||
|
||||
from .. import constants
|
||||
from ...datasets import css_data
|
||||
|
||||
from ..datasets import css_data
|
||||
|
||||
from ..wx_gui import (
|
||||
from ...wx_gui import (
|
||||
gui_entry,
|
||||
gui_support
|
||||
)
|
||||
from ..support import (
|
||||
from ...support import (
|
||||
utilities,
|
||||
updates,
|
||||
global_settings,
|
||||
network_handler,
|
||||
subprocess_wrapper
|
||||
)
|
||||
from ..patchsets import (
|
||||
HardwarePatchsetDetection,
|
||||
HardwarePatchsetValidation
|
||||
)
|
||||
|
||||
|
||||
class AutomaticSysPatch:
|
||||
class StartAutomaticPatching:
|
||||
"""
|
||||
Library of functions for launch agent, including automatic patching
|
||||
Start automatic patching of host
|
||||
"""
|
||||
|
||||
def __init__(self, global_constants: constants.Constants):
|
||||
@@ -146,12 +145,12 @@ Please check the Github page for more information about this release."""
|
||||
|
||||
if utilities.check_seal() is True:
|
||||
logging.info("- Detected Snapshot seal intact, detecting patches")
|
||||
patches = sys_patch_detect.DetectRootPatch(self.constants.computer.real_model, self.constants).detect_patch_set()
|
||||
patches = HardwarePatchsetDetection(self.constants).device_properties
|
||||
if not any(not patch.startswith("Settings") and not patch.startswith("Validation") and patches[patch] is True for patch in patches):
|
||||
patches = []
|
||||
patches = {}
|
||||
if patches:
|
||||
logging.info("- Detected applicable patches, determining whether possible to patch")
|
||||
if patches["Validation: Patching Possible"] is False:
|
||||
if patches[HardwarePatchsetValidation.PATCHING_NOT_POSSIBLE] is True:
|
||||
logging.info("- Cannot run patching")
|
||||
return
|
||||
|
||||
@@ -190,10 +189,12 @@ Please check the Github page for more information about this release."""
|
||||
if self._determine_if_versions_match():
|
||||
self._determine_if_boot_matches()
|
||||
|
||||
|
||||
def _onWebviewNav(self, event):
|
||||
url = event.GetURL()
|
||||
webbrowser.open(url)
|
||||
|
||||
|
||||
def _determine_if_versions_match(self):
|
||||
"""
|
||||
Determine if the booted version of OCLP matches the installed version
|
||||
@@ -316,92 +317,4 @@ Please check the Github page for more information about this release."""
|
||||
gui_entry.EntryPoint(self.constants).start(entry=gui_entry.SupportedEntryPoints.BUILD_OC)
|
||||
|
||||
except KeyError:
|
||||
logging.info("- Unable to determine if boot disk is removable, skipping prompt")
|
||||
|
||||
|
||||
def install_auto_patcher_launch_agent(self, kdk_caching_needed: bool = False):
|
||||
"""
|
||||
Install patcher launch services
|
||||
|
||||
See start_auto_patch() comments for more info
|
||||
"""
|
||||
|
||||
if self.constants.launcher_script is not None:
|
||||
logging.info("- Skipping Auto Patcher Launch Agent, not supported when running from source")
|
||||
return
|
||||
|
||||
services = {
|
||||
self.constants.auto_patch_launch_agent_path: "/Library/LaunchAgents/com.dortania.opencore-legacy-patcher.auto-patch.plist",
|
||||
self.constants.update_launch_daemon_path: "/Library/LaunchDaemons/com.dortania.opencore-legacy-patcher.macos-update.plist",
|
||||
**({ self.constants.rsr_monitor_launch_daemon_path: "/Library/LaunchDaemons/com.dortania.opencore-legacy-patcher.rsr-monitor.plist" } if self._create_rsr_monitor_daemon() else {}),
|
||||
**({ self.constants.kdk_launch_daemon_path: "/Library/LaunchDaemons/com.dortania.opencore-legacy-patcher.os-caching.plist" } if kdk_caching_needed is True else {} ),
|
||||
}
|
||||
|
||||
for service in services:
|
||||
name = Path(service).name
|
||||
logging.info(f"- Installing {name}")
|
||||
if Path(services[service]).exists():
|
||||
if hashlib.sha256(open(service, "rb").read()).hexdigest() == hashlib.sha256(open(services[service], "rb").read()).hexdigest():
|
||||
logging.info(f" - {name} checksums match, skipping")
|
||||
continue
|
||||
logging.info(f" - Existing service found, removing")
|
||||
subprocess_wrapper.run_as_root_and_verify(["/bin/rm", services[service]], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
# Create parent directories
|
||||
if not Path(services[service]).parent.exists():
|
||||
logging.info(f" - Creating {Path(services[service]).parent} directory")
|
||||
subprocess_wrapper.run_as_root_and_verify(["/bin/mkdir", "-p", Path(services[service]).parent], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
subprocess_wrapper.run_as_root_and_verify(["/bin/cp", service, services[service]], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
|
||||
# Set the permissions on the service
|
||||
subprocess_wrapper.run_as_root_and_verify(["/bin/chmod", "644", services[service]], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
subprocess_wrapper.run_as_root_and_verify(["/usr/sbin/chown", "root:wheel", services[service]], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
|
||||
|
||||
def _create_rsr_monitor_daemon(self) -> bool:
|
||||
# Get kext list in /Library/Extensions that have the 'GPUCompanionBundles' property
|
||||
# This is used to determine if we need to run the RSRMonitor
|
||||
logging.info("- Checking if RSRMonitor is needed")
|
||||
|
||||
cryptex_path = f"/System/Volumes/Preboot/{utilities.get_preboot_uuid()}/cryptex1/current/OS.dmg"
|
||||
if not Path(cryptex_path).exists():
|
||||
logging.info("- No OS.dmg, skipping RSRMonitor")
|
||||
return False
|
||||
|
||||
kexts = []
|
||||
for kext in Path("/Library/Extensions").glob("*.kext"):
|
||||
if not Path(f"{kext}/Contents/Info.plist").exists():
|
||||
continue
|
||||
try:
|
||||
kext_plist = plistlib.load(open(f"{kext}/Contents/Info.plist", "rb"))
|
||||
except Exception as e:
|
||||
logging.info(f" - Failed to load plist for {kext.name}: {e}")
|
||||
continue
|
||||
if "GPUCompanionBundles" not in kext_plist:
|
||||
continue
|
||||
logging.info(f" - Found kext with GPUCompanionBundles: {kext.name}")
|
||||
kexts.append(kext.name)
|
||||
|
||||
# If we have no kexts, we don't need to run the RSRMonitor
|
||||
if not kexts:
|
||||
logging.info("- No kexts found with GPUCompanionBundles, skipping RSRMonitor")
|
||||
return False
|
||||
|
||||
# Load the RSRMonitor plist
|
||||
rsr_monitor_plist = plistlib.load(open(self.constants.rsr_monitor_launch_daemon_path, "rb"))
|
||||
|
||||
arguments = ["/bin/rm", "-Rfv"]
|
||||
arguments += [f"/Library/Extensions/{kext}" for kext in kexts]
|
||||
|
||||
# Add the arguments to the RSRMonitor plist
|
||||
rsr_monitor_plist["ProgramArguments"] = arguments
|
||||
|
||||
# Next add monitoring for '/System/Volumes/Preboot/{UUID}/cryptex1/OS.dmg'
|
||||
logging.info(f" - Adding monitor: {cryptex_path}")
|
||||
rsr_monitor_plist["WatchPaths"] = [
|
||||
cryptex_path,
|
||||
]
|
||||
|
||||
# Write the RSRMonitor plist
|
||||
plistlib.dump(rsr_monitor_plist, Path(self.constants.rsr_monitor_launch_daemon_path).open("wb"))
|
||||
|
||||
return True
|
||||
logging.info("- Unable to determine if boot disk is removable, skipping prompt")
|
||||
11
opencore_legacy_patcher/sys_patch/kernelcache/__init__.py
Normal file
@@ -0,0 +1,11 @@
|
||||
"""
|
||||
kernelcache: Library for rebuilding macOS kernelcache files.
|
||||
|
||||
Usage:
|
||||
|
||||
>>> from kernelcache import RebuildKernelCache
|
||||
>>> RebuildKernelCache(os_version, mount_location, auxiliary_cache, auxiliary_cache_only).rebuild()
|
||||
"""
|
||||
|
||||
from .rebuild import RebuildKernelCache
|
||||
from .kernel_collection.support import KernelCacheSupport
|
||||
@@ -0,0 +1,8 @@
|
||||
"""
|
||||
cache.py: Base class for kernel cache management
|
||||
"""
|
||||
|
||||
class BaseKernelCache:
|
||||
|
||||
def rebuild(self) -> None:
|
||||
raise NotImplementedError("To be implemented in subclass")
|
||||
@@ -0,0 +1,72 @@
|
||||
"""
|
||||
auxiliary.py: Auxiliary Kernel Collection management
|
||||
"""
|
||||
|
||||
import logging
|
||||
import subprocess
|
||||
|
||||
from ..base.cache import BaseKernelCache
|
||||
from ....support import subprocess_wrapper
|
||||
|
||||
|
||||
class AuxiliaryKernelCollection(BaseKernelCache):
|
||||
|
||||
def __init__(self, mount_location: str) -> None:
|
||||
self.mount_location = mount_location
|
||||
|
||||
|
||||
def _kmutil_arguments(self) -> list[str]:
|
||||
args = ["/usr/bin/kmutil", "create", "--allow-missing-kdk"]
|
||||
|
||||
args.append("--new")
|
||||
args.append("aux")
|
||||
|
||||
args.append("--boot-path")
|
||||
args.append(f"{self.mount_location}/System/Library/KernelCollections/BootKernelExtensions.kc")
|
||||
|
||||
args.append("--system-path")
|
||||
args.append(f"{self.mount_location}/System/Library/KernelCollections/SystemKernelExtensions.kc")
|
||||
|
||||
return args
|
||||
|
||||
|
||||
def _force_auxiliary_usage(self) -> bool:
|
||||
"""
|
||||
Force the auxiliary kernel collection to be used.
|
||||
|
||||
This is required as Apple doesn't offer a public way
|
||||
to rebuild the auxiliary kernel collection. Instead deleting
|
||||
necessary files and directories will force the newly built
|
||||
collection to be used.
|
||||
"""
|
||||
|
||||
print("- Forcing Auxiliary Kernel Collection usage")
|
||||
result = subprocess_wrapper.run_as_root(["/usr/bin/killall", "syspolicyd", "kernelmanagerd"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
if result.returncode != 0:
|
||||
logging.info("- Unable to kill syspolicyd and kernelmanagerd")
|
||||
subprocess_wrapper.log(result)
|
||||
return False
|
||||
|
||||
for file in ["KextPolicy", "KextPolicy-shm", "KextPolicy-wal"]:
|
||||
result = subprocess_wrapper.run_as_root(["/bin/rm", f"/private/var/db/SystemPolicyConfiguration/{file}"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
if result.returncode != 0:
|
||||
logging.info(f"- Unable to remove {file}")
|
||||
subprocess_wrapper.log(result)
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def rebuild(self) -> None:
|
||||
logging.info("- Building new Auxiliary Kernel Collection")
|
||||
result = subprocess_wrapper.run_as_root(self._kmutil_arguments(), stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
if result.returncode != 0:
|
||||
logging.info("- Unable to build Auxiliary Kernel Collection")
|
||||
subprocess_wrapper.log(result)
|
||||
return False
|
||||
|
||||
if self._force_auxiliary_usage() is False:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
"""
|
||||
boot_system.py: Boot and System Kernel Collection management
|
||||
"""
|
||||
|
||||
import logging
|
||||
import subprocess
|
||||
|
||||
from ..base.cache import BaseKernelCache
|
||||
from ....support import subprocess_wrapper
|
||||
from ....datasets import os_data
|
||||
|
||||
|
||||
class BootSystemKernelCollections(BaseKernelCache):
|
||||
|
||||
def __init__(self, mount_location: str, detected_os: int, auxiliary_kc: bool) -> None:
|
||||
self.mount_location = mount_location
|
||||
self.detected_os = detected_os
|
||||
self.auxiliary_kc = auxiliary_kc
|
||||
|
||||
|
||||
def _kmutil_arguments(self) -> list[str]:
|
||||
"""
|
||||
Generate kmutil arguments for creating or updating
|
||||
the boot, system and auxiliary kernel collections
|
||||
"""
|
||||
|
||||
args = ["/usr/bin/kmutil"]
|
||||
|
||||
if self.detected_os >= os_data.os_data.ventura:
|
||||
args.append("create")
|
||||
args.append("--allow-missing-kdk")
|
||||
else:
|
||||
args.append("install")
|
||||
|
||||
args.append("--volume-root")
|
||||
args.append(self.mount_location)
|
||||
|
||||
args.append("--update-all")
|
||||
|
||||
args.append("--variant-suffix")
|
||||
args.append("release")
|
||||
|
||||
if self.auxiliary_kc is True:
|
||||
# Following arguments are supposed to skip kext consent
|
||||
# prompts when creating auxiliary KCs with SIP disabled
|
||||
args.append("--no-authentication")
|
||||
args.append("--no-authorization")
|
||||
|
||||
return args
|
||||
|
||||
|
||||
def rebuild(self) -> bool:
|
||||
logging.info(f"- Rebuilding {'Boot and System' if self.auxiliary_kc is False else 'Boot, System and Auxiliary'} Kernel Collections")
|
||||
if self.auxiliary_kc is True:
|
||||
logging.info(" (You will get a prompt by System Preferences, ignore for now)")
|
||||
|
||||
result = subprocess_wrapper.run_as_root(self._kmutil_arguments(), stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
if result.returncode != 0:
|
||||
subprocess_wrapper.log(result)
|
||||
return False
|
||||
|
||||
return True
|
||||
@@ -0,0 +1,165 @@
|
||||
"""
|
||||
support.py: Kernel Cache support functions
|
||||
"""
|
||||
|
||||
import logging
|
||||
import plistlib
|
||||
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
|
||||
from ...patchsets import PatchType
|
||||
|
||||
from ....datasets import os_data
|
||||
from ....support import subprocess_wrapper
|
||||
|
||||
|
||||
class KernelCacheSupport:
|
||||
|
||||
def __init__(self, mount_location_data: str, detected_os: int, skip_root_kmutil_requirement: bool) -> None:
|
||||
self.mount_location_data = mount_location_data
|
||||
self.detected_os = detected_os
|
||||
self.skip_root_kmutil_requirement = skip_root_kmutil_requirement
|
||||
|
||||
|
||||
def check_kexts_needs_authentication(self, kext_name: str) -> bool:
|
||||
"""
|
||||
Verify whether the user needs to authenticate in System Preferences
|
||||
Sets 'needs_to_open_preferences' to True if the kext is not in the AuxKC
|
||||
|
||||
Logic:
|
||||
Under 'private/var/db/KernelManagement/AuxKC/CurrentAuxKC/com.apple.kcgen.instructions.plist'
|
||||
["kextsToBuild"][i]:
|
||||
["bundlePathMainOS"] = /Library/Extensions/Test.kext
|
||||
["cdHash"] = Bundle's CDHash (random on ad-hoc signed, static on dev signed)
|
||||
["teamID"] = Team ID (blank on ad-hoc signed)
|
||||
To grab the CDHash of a kext, run 'codesign -dvvv <kext_path>'
|
||||
"""
|
||||
if not kext_name.endswith(".kext"):
|
||||
return False
|
||||
|
||||
try:
|
||||
aux_cache_path = Path(self.mount_location_data) / Path("/private/var/db/KernelExtensionManagement/AuxKC/CurrentAuxKC/com.apple.kcgen.instructions.plist")
|
||||
if aux_cache_path.exists():
|
||||
aux_cache_data = plistlib.load((aux_cache_path).open("rb"))
|
||||
for kext in aux_cache_data["kextsToBuild"]:
|
||||
if "bundlePathMainOS" in aux_cache_data["kextsToBuild"][kext]:
|
||||
if aux_cache_data["kextsToBuild"][kext]["bundlePathMainOS"] == f"/Library/Extensions/{kext_name}":
|
||||
return False
|
||||
except PermissionError:
|
||||
pass
|
||||
|
||||
logging.info(f" - {kext_name} requires authentication in System Preferences")
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def add_auxkc_support(self, install_file: str, source_folder_path: str, install_patch_directory: str, destination_folder_path: str) -> str:
|
||||
"""
|
||||
Patch provided Kext to support Auxiliary Kernel Collection
|
||||
|
||||
Logic:
|
||||
In macOS Ventura, KDKs are required to build new Boot and System KCs
|
||||
However for some patch sets, we're able to use the Auxiliary KCs with '/Library/Extensions'
|
||||
|
||||
kernelmanagerd determines which kext is installed by their 'OSBundleRequired' entry
|
||||
If a kext is labeled as 'OSBundleRequired: Root' or 'OSBundleRequired: Safe Boot',
|
||||
kernelmanagerd will require the kext to be installed in the Boot/SysKC
|
||||
|
||||
Additionally, kexts starting with 'com.apple.' are not natively allowed to be installed
|
||||
in the AuxKC. So we need to explicitly set our 'OSBundleRequired' to 'Auxiliary'
|
||||
|
||||
Parameters:
|
||||
install_file (str): Kext file name
|
||||
source_folder_path (str): Source folder path
|
||||
install_patch_directory (str): Patch directory
|
||||
destination_folder_path (str): Destination folder path
|
||||
|
||||
Returns:
|
||||
str: Updated destination folder path
|
||||
"""
|
||||
|
||||
if self.skip_root_kmutil_requirement is False:
|
||||
return destination_folder_path
|
||||
if not install_file.endswith(".kext"):
|
||||
return destination_folder_path
|
||||
if install_patch_directory != "/System/Library/Extensions":
|
||||
return destination_folder_path
|
||||
if self.detected_os < os_data.os_data.ventura:
|
||||
return destination_folder_path
|
||||
|
||||
updated_install_location = str(self.mount_location_data) + "/Library/Extensions"
|
||||
|
||||
logging.info(f" - Adding AuxKC support to {install_file}")
|
||||
plist_path = Path(Path(source_folder_path) / Path(install_file) / Path("Contents/Info.plist"))
|
||||
plist_data = plistlib.load((plist_path).open("rb"))
|
||||
|
||||
# Check if we need to update the 'OSBundleRequired' entry
|
||||
if not plist_data["CFBundleIdentifier"].startswith("com.apple."):
|
||||
return updated_install_location
|
||||
if "OSBundleRequired" in plist_data:
|
||||
if plist_data["OSBundleRequired"] == "Auxiliary":
|
||||
return updated_install_location
|
||||
|
||||
plist_data["OSBundleRequired"] = "Auxiliary"
|
||||
plistlib.dump(plist_data, plist_path.open("wb"))
|
||||
|
||||
return updated_install_location
|
||||
|
||||
|
||||
def clean_auxiliary_kc(self) -> None:
|
||||
"""
|
||||
Clean the Auxiliary Kernel Collection
|
||||
|
||||
Logic:
|
||||
When reverting root volume patches, the AuxKC will still retain the UUID
|
||||
it was built against. Thus when Boot/SysKC are reverted, Aux will break
|
||||
To resolve this, delete all installed kexts in /L*/E* and rebuild the AuxKC
|
||||
We can verify our binaries based off the OpenCore-Legacy-Patcher.plist file
|
||||
"""
|
||||
|
||||
if self.detected_os < os_data.os_data.big_sur:
|
||||
return
|
||||
|
||||
logging.info("- Cleaning Auxiliary Kernel Collection")
|
||||
oclp_path = "/System/Library/CoreServices/OpenCore-Legacy-Patcher.plist"
|
||||
if Path(oclp_path).exists():
|
||||
oclp_plist_data = plistlib.load(Path(oclp_path).open("rb"))
|
||||
for key in oclp_plist_data:
|
||||
if isinstance(oclp_plist_data[key], (bool, int)):
|
||||
continue
|
||||
for install_type in [PatchType.OVERWRITE_SYSTEM_VOLUME, PatchType.OVERWRITE_DATA_VOLUME, PatchType.MERGE_SYSTEM_VOLUME, PatchType.MERGE_DATA_VOLUME]:
|
||||
if install_type not in oclp_plist_data[key]:
|
||||
continue
|
||||
for location in oclp_plist_data[key][install_type]:
|
||||
if not location.endswith("Extensions"):
|
||||
continue
|
||||
for file in oclp_plist_data[key][install_type][location]:
|
||||
if not file.endswith(".kext"):
|
||||
continue
|
||||
if not Path(f"/Library/Extensions/{file}").exists():
|
||||
continue
|
||||
logging.info(f" - Removing {file}")
|
||||
subprocess_wrapper.run_as_root(["/bin/rm", "-Rf", f"/Library/Extensions/{file}"])
|
||||
|
||||
# Handle situations where users migrated from older OSes with a lot of garbage in /L*/E*
|
||||
# ex. Nvidia Web Drivers, NetUSB, dosdude1's patches, etc.
|
||||
# Move if file's age is older than October 2021 (year before Ventura)
|
||||
if self.detected_os < os_data.os_data.ventura:
|
||||
return
|
||||
|
||||
relocation_path = "/Library/Relocated Extensions"
|
||||
if not Path(relocation_path).exists():
|
||||
subprocess_wrapper.run_as_root(["/bin/mkdir", relocation_path])
|
||||
|
||||
for file in Path("/Library/Extensions").glob("*.kext"):
|
||||
try:
|
||||
if datetime.fromtimestamp(file.stat().st_mtime) < datetime(2021, 10, 1):
|
||||
logging.info(f" - Relocating {file.name} kext to {relocation_path}")
|
||||
if Path(relocation_path) / Path(file.name).exists():
|
||||
subprocess_wrapper.run_as_root(["/bin/rm", "-Rf", relocation_path / Path(file.name)])
|
||||
subprocess_wrapper.run_as_root(["/bin/mv", file, relocation_path])
|
||||
except:
|
||||
# Some users have the most cursed /L*/E* folders
|
||||
# ex. Symlinks pointing to symlinks pointing to dead files
|
||||
pass
|
||||
32
opencore_legacy_patcher/sys_patch/kernelcache/mkext/mkext.py
Normal file
@@ -0,0 +1,32 @@
|
||||
"""
|
||||
mkext.py: MKext cache management
|
||||
"""
|
||||
|
||||
import logging
|
||||
import subprocess
|
||||
|
||||
from ..base.cache import BaseKernelCache
|
||||
|
||||
from ....support import subprocess_wrapper
|
||||
|
||||
|
||||
class MKext(BaseKernelCache):
|
||||
|
||||
def __init__(self, mount_location: str) -> None:
|
||||
self.mount_location = mount_location
|
||||
|
||||
|
||||
def _mkext_arguments(self) -> list[str]:
|
||||
args = ["/usr/bin/touch", f"{self.mount_location}/System/Library/Extensions"]
|
||||
return args
|
||||
|
||||
|
||||
def rebuild(self) -> None:
|
||||
logging.info("- Rebuilding MKext cache")
|
||||
result = subprocess_wrapper.run_as_root(self._mkext_arguments(), stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
|
||||
if result.returncode != 0:
|
||||
subprocess_wrapper.log(result)
|
||||
return False
|
||||
|
||||
return True
|
||||
@@ -0,0 +1,48 @@
|
||||
"""
|
||||
prelinked.py: Prelinked Kernel cache management
|
||||
"""
|
||||
|
||||
import logging
|
||||
import subprocess
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from ..base.cache import BaseKernelCache
|
||||
from ....support import subprocess_wrapper
|
||||
|
||||
|
||||
class PrelinkedKernel(BaseKernelCache):
|
||||
|
||||
def __init__(self, mount_location: str) -> None:
|
||||
self.mount_location = mount_location
|
||||
|
||||
|
||||
def _kextcache_arguments(self) -> list[str]:
|
||||
args = ["/usr/sbin/kextcache", "-invalidate", f"{self.mount_location}/"]
|
||||
return args
|
||||
|
||||
def _update_preboot_kernel_cache(self) -> bool:
|
||||
"""
|
||||
Ensure Preboot volume's kernel cache is updated
|
||||
"""
|
||||
if not Path("/usr/sbin/kcditto").exists():
|
||||
return
|
||||
|
||||
logging.info("- Syncing Kernel Cache to Preboot")
|
||||
subprocess_wrapper.run_as_root_and_verify(["/usr/sbin/kcditto"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
|
||||
|
||||
def rebuild(self) -> None:
|
||||
logging.info("- Rebuilding Prelinked Kernel")
|
||||
result = subprocess_wrapper.run_as_root(self._kextcache_arguments(), stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
|
||||
# kextcache notes:
|
||||
# - kextcache always returns 0, even if it fails
|
||||
# - Check the output for 'KernelCache ID' to see if the cache was successfully rebuilt
|
||||
if "KernelCache ID" not in result.stdout.decode():
|
||||
subprocess_wrapper.log(result)
|
||||
return False
|
||||
|
||||
self._update_preboot_kernel_cache()
|
||||
|
||||
return True
|
||||
51
opencore_legacy_patcher/sys_patch/kernelcache/rebuild.py
Normal file
@@ -0,0 +1,51 @@
|
||||
"""
|
||||
rebuild.py: Manage kernel cache rebuilding regardless of macOS version
|
||||
"""
|
||||
|
||||
from .base.cache import BaseKernelCache
|
||||
from ...datasets import os_data
|
||||
|
||||
|
||||
class RebuildKernelCache:
|
||||
"""
|
||||
RebuildKernelCache: Rebuild the kernel cache
|
||||
|
||||
Parameters:
|
||||
- os_version: macOS version
|
||||
- mount_location: Path to the mounted volume
|
||||
- auxiliary_cache: Whether to create auxiliary kernel cache (Big Sur and later)
|
||||
- auxiliary_cache_only: Whether to only create auxiliary kernel cache (Ventura and later)
|
||||
"""
|
||||
def __init__(self, os_version: os_data.os_data, mount_location: str, auxiliary_cache: bool, auxiliary_cache_only: bool) -> None:
|
||||
self.os_version = os_version
|
||||
self.mount_location = mount_location
|
||||
self.auxiliary_cache = auxiliary_cache
|
||||
self.auxiliary_cache_only = auxiliary_cache_only
|
||||
|
||||
|
||||
def _rebuild_method(self) -> BaseKernelCache:
|
||||
"""
|
||||
Determine the correct method to rebuild the kernel cache
|
||||
"""
|
||||
if self.os_version >= os_data.os_data.big_sur:
|
||||
if self.os_version >= os_data.os_data.ventura:
|
||||
if self.auxiliary_cache_only:
|
||||
from .kernel_collection.auxiliary import AuxiliaryKernelCollection
|
||||
return AuxiliaryKernelCollection(self.mount_location)
|
||||
|
||||
from .kernel_collection.boot_system import BootSystemKernelCollections
|
||||
return BootSystemKernelCollections(self.mount_location, self.os_version, self.auxiliary_cache)
|
||||
|
||||
if os_data.os_data.catalina >= self.os_version >= os_data.os_data.lion:
|
||||
from .prelinked.prelinked import PrelinkedKernel
|
||||
return PrelinkedKernel(self.mount_location)
|
||||
|
||||
from .mkext.mkext import MKext
|
||||
return MKext(self.mount_location)
|
||||
|
||||
|
||||
def rebuild(self) -> bool:
|
||||
"""
|
||||
Rebuild the kernel cache
|
||||
"""
|
||||
return self._rebuild_method().rebuild()
|
||||
16
opencore_legacy_patcher/sys_patch/mount/__init__.py
Normal file
@@ -0,0 +1,16 @@
|
||||
"""
|
||||
mount: Library for mounting and unmounting the root volume and interacting with APFS snapshots.
|
||||
|
||||
Usage:
|
||||
|
||||
>>> from mount import RootVolumeMount
|
||||
>>> RootVolumeMount(xnu_major).mount()
|
||||
'/System/Volumes/Update/mnt1'
|
||||
>>> RootVolumeMount(xnu_major).unmount()
|
||||
|
||||
>>> RootVolumeMount(xnu_major).create_snapshot()
|
||||
>>> RootVolumeMount(xnu_major).revert_snapshot()
|
||||
"""
|
||||
|
||||
from .mount import RootVolumeMount
|
||||
from .snapshot import APFSSnapshot
|
||||
@@ -1,62 +1,28 @@
|
||||
"""
|
||||
sys_patch_mount.py: Handling macOS root volume mounting and unmounting,
|
||||
as well as APFS snapshots for Big Sur and newer
|
||||
mount.py: Handling macOS root volume mounting and unmounting
|
||||
"""
|
||||
|
||||
import logging
|
||||
import plistlib
|
||||
import platform
|
||||
import subprocess
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from ..datasets import os_data
|
||||
from ..support import subprocess_wrapper
|
||||
from .snapshot import APFSSnapshot
|
||||
|
||||
from ...datasets import os_data
|
||||
from ...support import subprocess_wrapper
|
||||
|
||||
|
||||
class SysPatchMount:
|
||||
class RootVolumeMount:
|
||||
|
||||
def __init__(self, xnu_major: int, rosetta_status: bool) -> None:
|
||||
def __init__(self, xnu_major: int) -> None:
|
||||
self.xnu_major = xnu_major
|
||||
self.rosetta_status = rosetta_status
|
||||
self.root_volume_identifier = self._fetch_root_volume_identifier()
|
||||
|
||||
self.mount_path = None
|
||||
|
||||
|
||||
def mount(self) -> str:
|
||||
"""
|
||||
Mount the root volume.
|
||||
|
||||
Returns the path to the root volume.
|
||||
|
||||
If none, failed to mount.
|
||||
"""
|
||||
result = self._mount_root_volume()
|
||||
if result is None:
|
||||
logging.error("Failed to mount root volume")
|
||||
return None
|
||||
if not Path(result).exists():
|
||||
logging.error(f"Attempted to mount root volume, but failed: {result}")
|
||||
return None
|
||||
|
||||
self.mount_path = result
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def unmount(self, ignore_errors: bool = True) -> bool:
|
||||
"""
|
||||
Unmount the root volume.
|
||||
|
||||
Returns True if successful, False otherwise.
|
||||
|
||||
Note for Big Sur and newer, a snapshot is created before unmounting.
|
||||
And that unmounting is not critical to the process.
|
||||
"""
|
||||
return self._unmount_root_volume(ignore_errors=ignore_errors)
|
||||
|
||||
|
||||
def _fetch_root_volume_identifier(self) -> str:
|
||||
"""
|
||||
Resolve path to disk identifier
|
||||
@@ -136,43 +102,48 @@ class SysPatchMount:
|
||||
return True
|
||||
|
||||
|
||||
def mount(self) -> str:
|
||||
"""
|
||||
Mount the root volume.
|
||||
|
||||
Returns the path to the root volume.
|
||||
|
||||
If none, failed to mount.
|
||||
"""
|
||||
result = self._mount_root_volume()
|
||||
if result is None:
|
||||
logging.error("Failed to mount root volume")
|
||||
return None
|
||||
if not Path(result).exists():
|
||||
logging.error(f"Attempted to mount root volume, but failed: {result}")
|
||||
return None
|
||||
|
||||
self.mount_path = result
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def unmount(self, ignore_errors: bool = True) -> bool:
|
||||
"""
|
||||
Unmount the root volume.
|
||||
|
||||
Returns True if successful, False otherwise.
|
||||
|
||||
Note for Big Sur and newer, a snapshot is created before unmounting.
|
||||
And that unmounting is not critical to the process.
|
||||
"""
|
||||
return self._unmount_root_volume(ignore_errors=ignore_errors)
|
||||
|
||||
|
||||
def create_snapshot(self) -> bool:
|
||||
"""
|
||||
Create APFS snapshot of the root volume.
|
||||
"""
|
||||
if self.xnu_major < os_data.os_data.big_sur.value:
|
||||
return True
|
||||
|
||||
args = ["/usr/sbin/bless"]
|
||||
if platform.machine() == "arm64" or self.rosetta_status is True:
|
||||
args += ["--mount", self.mount_path, "--create-snapshot"]
|
||||
else:
|
||||
args += ["--folder", f"{self.mount_path}/System/Library/CoreServices", "--bootefi", "--create-snapshot"]
|
||||
|
||||
|
||||
result = subprocess_wrapper.run_as_root(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
if result.returncode != 0:
|
||||
logging.error("Failed to create APFS snapshot")
|
||||
subprocess_wrapper.log(result)
|
||||
if "Can't use last-sealed-snapshot or create-snapshot on non system volume" in result.stdout.decode():
|
||||
logging.info("- This is an APFS bug with Monterey and newer! Perform a clean installation to ensure your APFS volume is built correctly")
|
||||
|
||||
return False
|
||||
|
||||
return True
|
||||
return APFSSnapshot(self.xnu_major, self.mount_path).create_snapshot()
|
||||
|
||||
|
||||
def revert_snapshot(self) -> bool:
|
||||
"""
|
||||
Revert APFS snapshot of the root volume.
|
||||
"""
|
||||
if self.xnu_major < os_data.os_data.big_sur.value:
|
||||
return True
|
||||
|
||||
result = subprocess_wrapper.run_as_root(["/usr/sbin/bless", "--mount", self.mount_path, "--bootefi", "--last-sealed-snapshot"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
if result.returncode != 0:
|
||||
logging.error("Failed to revert APFS snapshot")
|
||||
subprocess_wrapper.log(result)
|
||||
return False
|
||||
|
||||
return True
|
||||
return APFSSnapshot(self.xnu_major, self.mount_path).revert_snapshot()
|
||||
69
opencore_legacy_patcher/sys_patch/mount/snapshot.py
Normal file
@@ -0,0 +1,69 @@
|
||||
"""
|
||||
snapshot.py: Handling APFS snapshots
|
||||
"""
|
||||
|
||||
import logging
|
||||
import platform
|
||||
import subprocess
|
||||
|
||||
from ...datasets import os_data
|
||||
from ...support import subprocess_wrapper
|
||||
|
||||
|
||||
class APFSSnapshot:
|
||||
|
||||
def __init__(self, xnu_major: int, mount_path: str):
|
||||
self.xnu_major = xnu_major
|
||||
self.mount_path = mount_path
|
||||
|
||||
|
||||
def _rosetta_status(self) -> bool:
|
||||
"""
|
||||
Check if currently running inside of Rosetta
|
||||
"""
|
||||
result = subprocess_wrapper.run(["/usr/sbin/sysctl", "-n", "sysctl.proc_translated"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
if result.returncode != 0:
|
||||
return False
|
||||
|
||||
return True if result.stdout.decode().strip() == "1" else False
|
||||
|
||||
|
||||
def create_snapshot(self) -> bool:
|
||||
"""
|
||||
Create APFS snapshot of the root volume.
|
||||
"""
|
||||
if self.xnu_major < os_data.os_data.big_sur.value:
|
||||
return True
|
||||
|
||||
args = ["/usr/sbin/bless"]
|
||||
if platform.machine() == "arm64" or self._rosetta_status() is True:
|
||||
args += ["--mount", self.mount_path, "--create-snapshot"]
|
||||
else:
|
||||
args += ["--folder", f"{self.mount_path}/System/Library/CoreServices", "--bootefi", "--create-snapshot"]
|
||||
|
||||
result = subprocess_wrapper.run_as_root(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
if result.returncode != 0:
|
||||
logging.error("Failed to create APFS snapshot")
|
||||
subprocess_wrapper.log(result)
|
||||
if "Can't use last-sealed-snapshot or create-snapshot on non system volume" in result.stdout.decode():
|
||||
logging.info("- This is an APFS bug with Monterey and newer! Perform a clean installation to ensure your APFS volume is built correctly")
|
||||
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def revert_snapshot(self) -> bool:
|
||||
"""
|
||||
Revert APFS snapshot of the root volume.
|
||||
"""
|
||||
if self.xnu_major < os_data.os_data.big_sur.value:
|
||||
return True
|
||||
|
||||
result = subprocess_wrapper.run_as_root(["/usr/sbin/bless", "--mount", self.mount_path, "--bootefi", "--last-sealed-snapshot"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
if result.returncode != 0:
|
||||
logging.error("Failed to revert APFS snapshot")
|
||||
subprocess_wrapper.log(result)
|
||||
return False
|
||||
|
||||
return True
|
||||
6
opencore_legacy_patcher/sys_patch/patchsets/__init__.py
Normal file
@@ -0,0 +1,6 @@
|
||||
"""
|
||||
patchsets module
|
||||
"""
|
||||
|
||||
from .base import PatchType, DynamicPatchset
|
||||
from .detect import HardwarePatchsetDetection, HardwarePatchsetSettings, HardwarePatchsetValidation
|
||||
35
opencore_legacy_patcher/sys_patch/patchsets/base.py
Normal file
@@ -0,0 +1,35 @@
|
||||
"""
|
||||
base.py: Base class for all patch sets
|
||||
"""
|
||||
|
||||
from enum import StrEnum
|
||||
|
||||
|
||||
class PatchType(StrEnum):
|
||||
"""
|
||||
Type of patch
|
||||
"""
|
||||
OVERWRITE_SYSTEM_VOLUME = "Overwrite System Volume"
|
||||
OVERWRITE_DATA_VOLUME = "Overwrite Data Volume"
|
||||
MERGE_SYSTEM_VOLUME = "Merge System Volume"
|
||||
MERGE_DATA_VOLUME = "Merge Data Volume"
|
||||
REMOVE_SYSTEM_VOLUME = "Remove System Volume"
|
||||
REMOVE_DATA_VOLUME = "Remove Data Volume"
|
||||
EXECUTE = "Execute"
|
||||
|
||||
|
||||
class DynamicPatchset(StrEnum):
|
||||
MetallibSupportPkg = "MetallibSupportPkg"
|
||||
|
||||
|
||||
class BasePatchset:
|
||||
|
||||
def __init__(self) -> None:
|
||||
# XNU Kernel versions
|
||||
self.macOS_12_0_B7: float = 21.1
|
||||
self.macOS_12_4: float = 21.5
|
||||
self.macOS_12_5: float = 21.6
|
||||
self.macOS_13_3: float = 22.4
|
||||
self.macOS_14_1: float = 23.1
|
||||
self.macOS_14_2: float = 23.2
|
||||
self.macOS_14_4: float = 23.4
|
||||
549
opencore_legacy_patcher/sys_patch/patchsets/detect.py
Normal file
@@ -0,0 +1,549 @@
|
||||
"""
|
||||
detect.py: Detects patches for a given system
|
||||
"""
|
||||
|
||||
import logging
|
||||
import plistlib
|
||||
import subprocess
|
||||
import py_sip_xnu
|
||||
import packaging.version
|
||||
|
||||
from enum import StrEnum
|
||||
from pathlib import Path
|
||||
from functools import cache
|
||||
|
||||
from .hardware.base import BaseHardware, HardwareVariantGraphicsSubclass
|
||||
|
||||
from .hardware.graphics import (
|
||||
intel_iron_lake,
|
||||
intel_sandy_bridge,
|
||||
intel_ivy_bridge,
|
||||
intel_haswell,
|
||||
intel_broadwell,
|
||||
intel_skylake,
|
||||
|
||||
nvidia_tesla,
|
||||
nvidia_kepler,
|
||||
nvidia_webdriver,
|
||||
|
||||
amd_terascale_1,
|
||||
amd_terascale_2,
|
||||
amd_legacy_gcn,
|
||||
amd_polaris,
|
||||
amd_vega,
|
||||
)
|
||||
from .hardware.networking import (
|
||||
legacy_wireless,
|
||||
modern_wireless,
|
||||
)
|
||||
from .hardware.misc import (
|
||||
display_backlight,
|
||||
gmux,
|
||||
keyboard_backlight,
|
||||
legacy_audio,
|
||||
pcie_webcam,
|
||||
t1_security,
|
||||
usb11,
|
||||
)
|
||||
|
||||
from ... import constants
|
||||
|
||||
from ...datasets import sip_data
|
||||
from ...datasets.os_data import os_data
|
||||
from ...support import (
|
||||
network_handler,
|
||||
utilities,
|
||||
kdk_handler,
|
||||
metallib_handler
|
||||
)
|
||||
from ...detections import (
|
||||
amfi_detect,
|
||||
device_probe
|
||||
)
|
||||
|
||||
|
||||
class HardwarePatchsetSettings(StrEnum):
|
||||
"""
|
||||
Enum for patch settings
|
||||
"""
|
||||
KERNEL_DEBUG_KIT_REQUIRED = "Settings: Kernel Debug Kit required"
|
||||
KERNEL_DEBUG_KIT_MISSING = "Settings: Kernel Debug Kit missing"
|
||||
METALLIB_SUPPORT_PKG_REQUIRED = "Settings: MetallibSupportPkg.pkg required"
|
||||
METALLIB_SUPPORT_PKG_MISSING = "Settings: MetallibSupportPkg.pkg missing"
|
||||
|
||||
|
||||
class HardwarePatchsetValidation(StrEnum):
|
||||
"""
|
||||
Enum for validation settings
|
||||
"""
|
||||
UNSUPPORTED_HOST_OS = "Validation: Unsupported Host OS"
|
||||
MISSING_NETWORK_CONNECTION = "Validation: Missing Network Connection"
|
||||
FILEVAULT_ENABLED = "Validation: FileVault is enabled"
|
||||
SIP_ENABLED = "Validation: System Integrity Protection is enabled"
|
||||
SECURE_BOOT_MODEL_ENABLED = "Validation: SecureBootModel is enabled"
|
||||
AMFI_ENABLED = "Validation: AMFI is enabled"
|
||||
WHATEVERGREEN_MISSING = "Validation: WhateverGreen.kext missing"
|
||||
FORCE_OPENGL_MISSING = "Validation: Force OpenGL property missing"
|
||||
FORCE_COMPAT_MISSING = "Validation: Force compat property missing"
|
||||
NVDA_DRV_MISSING = "Validation: nvda_drv(_vrl) variable missing"
|
||||
PATCHING_NOT_POSSIBLE = "Validation: Patching not possible"
|
||||
UNPATCHING_NOT_POSSIBLE = "Validation: Unpatching not possible"
|
||||
|
||||
|
||||
class HardwarePatchsetDetection:
|
||||
|
||||
def __init__(self, constants: constants.Constants,
|
||||
xnu_major: int = None, xnu_minor: int = None,
|
||||
os_build: str = None, os_version: str = None,
|
||||
validation: bool = False # Whether to run validation checks
|
||||
) -> None:
|
||||
self._constants = constants
|
||||
|
||||
self._xnu_major = xnu_major or self._constants.detected_os
|
||||
self._xnu_minor = xnu_minor or self._constants.detected_os_minor
|
||||
self._os_build = os_build or self._constants.detected_os_build
|
||||
self._os_version = os_version or self._constants.detected_os_version
|
||||
self._validation = validation
|
||||
|
||||
self._hardware_variants = [
|
||||
intel_iron_lake.IntelIronLake,
|
||||
intel_sandy_bridge.IntelSandyBridge,
|
||||
intel_ivy_bridge.IntelIvyBridge,
|
||||
intel_haswell.IntelHaswell,
|
||||
intel_broadwell.IntelBroadwell,
|
||||
intel_skylake.IntelSkylake,
|
||||
|
||||
nvidia_tesla.NvidiaTesla,
|
||||
nvidia_kepler.NvidiaKepler,
|
||||
nvidia_webdriver.NvidiaWebDriver,
|
||||
|
||||
amd_terascale_1.AMDTeraScale1,
|
||||
amd_terascale_2.AMDTeraScale2,
|
||||
amd_legacy_gcn.AMDLegacyGCN,
|
||||
amd_polaris.AMDPolaris,
|
||||
amd_vega.AMDVega,
|
||||
|
||||
legacy_wireless.LegacyWireless,
|
||||
modern_wireless.ModernWireless,
|
||||
|
||||
display_backlight.DisplayBacklight,
|
||||
gmux.GraphicsMultiplexer,
|
||||
keyboard_backlight.KeyboardBacklight,
|
||||
legacy_audio.LegacyAudio,
|
||||
pcie_webcam.PCIeFaceTimeCamera,
|
||||
t1_security.T1SecurityChip,
|
||||
usb11.USB11Controller,
|
||||
]
|
||||
|
||||
self.device_properties = None
|
||||
self.patches = None
|
||||
|
||||
self.can_patch = False
|
||||
self.can_unpatch = False
|
||||
|
||||
self._detect()
|
||||
|
||||
|
||||
def _validation_check_unsupported_host_os(self) -> bool:
|
||||
"""
|
||||
Determine if host OS is unsupported
|
||||
"""
|
||||
_min_os = os_data.big_sur.value
|
||||
_max_os = os_data.sequoia.value
|
||||
if self._dortania_internal_check() is True:
|
||||
return False
|
||||
if self._xnu_major < _min_os or self._xnu_major > _max_os:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
@cache
|
||||
def _validation_check_missing_network_connection(self) -> bool:
|
||||
"""
|
||||
Determine if network connection is present
|
||||
"""
|
||||
return network_handler.NetworkUtilities().verify_network_connection() is False
|
||||
|
||||
|
||||
@cache
|
||||
def _validation_check_filevault_is_enabled(self) -> bool:
|
||||
"""
|
||||
Determine if FileVault is enabled
|
||||
"""
|
||||
# macOS 11.0 introduced a FileVault check for root patching
|
||||
if self._xnu_major < os_data.big_sur.value:
|
||||
return False
|
||||
|
||||
# OpenCore Legacy Patcher exposes whether it patched APFS.kext to allow for FileVault
|
||||
nvram = utilities.get_nvram("OCLP-Settings", "4D1FDA02-38C7-4A6A-9CC6-4BCCA8B30102", decode=True)
|
||||
if nvram:
|
||||
if "-allow_fv" in nvram:
|
||||
return False
|
||||
|
||||
return "FileVault is Off" not in subprocess.run(["/usr/bin/fdesetup", "status"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT).stdout.decode()
|
||||
|
||||
|
||||
def _validation_check_system_integrity_protection_enabled(self, configs: list[str]) -> bool:
|
||||
"""
|
||||
Determine if System Integrity Protection is enabled
|
||||
"""
|
||||
return utilities.csr_decode(configs)
|
||||
|
||||
|
||||
def _validation_check_secure_boot_model_enabled(self) -> bool:
|
||||
"""
|
||||
Determine if SecureBootModel is enabled
|
||||
"""
|
||||
return utilities.check_secure_boot_level()
|
||||
|
||||
|
||||
def _validation_check_amfi_enabled(self, level: amfi_detect.AmfiConfigDetectLevel) -> bool:
|
||||
"""
|
||||
Determine if AMFI is enabled
|
||||
"""
|
||||
return not amfi_detect.AmfiConfigurationDetection().check_config(self._override_amfi_level(level))
|
||||
|
||||
|
||||
def _validation_check_whatevergreen_missing(self) -> bool:
|
||||
"""
|
||||
Determine if WhateverGreen.kext is missing
|
||||
"""
|
||||
return utilities.check_kext_loaded("as.vit9696.WhateverGreen") is False
|
||||
|
||||
|
||||
@cache
|
||||
def _validation_check_force_opengl_missing(self) -> bool:
|
||||
"""
|
||||
Determine if Force OpenGL property is missing
|
||||
"""
|
||||
nv_on = utilities.get_nvram("boot-args", decode=True)
|
||||
if nv_on:
|
||||
if "ngfxgl=" in nv_on:
|
||||
return True
|
||||
for gpu in self._constants.computer.gpus:
|
||||
if isinstance(gpu, device_probe.NVIDIA):
|
||||
if gpu.disable_metal is True:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _validation_check_force_compat_missing(self) -> bool:
|
||||
"""
|
||||
Determine if Force compat property is missing
|
||||
"""
|
||||
nv_on = utilities.get_nvram("boot-args", decode=True)
|
||||
if nv_on:
|
||||
if "ngfxcompat=" in nv_on:
|
||||
return True
|
||||
for gpu in self._constants.computer.gpus:
|
||||
if isinstance(gpu, device_probe.NVIDIA):
|
||||
if gpu.force_compatible is True:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _validation_check_nvda_drv_missing(self) -> bool:
|
||||
"""
|
||||
Determine if nvda_drv(_vrl) variable is missing
|
||||
"""
|
||||
nv_on = utilities.get_nvram("boot-args", decode=True)
|
||||
if nv_on:
|
||||
if "nvda_drv_vrl=" in nv_on:
|
||||
return True
|
||||
nv_on = utilities.get_nvram("nvda_drv")
|
||||
if nv_on:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
@cache
|
||||
def _override_amfi_level(self, level: amfi_detect.AmfiConfigDetectLevel) -> amfi_detect.AmfiConfigDetectLevel:
|
||||
"""
|
||||
Override level required based on whether AMFIPass is loaded
|
||||
"""
|
||||
amfipass_version = utilities.check_kext_loaded("com.dhinakg.AMFIPass")
|
||||
if amfipass_version:
|
||||
if packaging.version.parse(amfipass_version) >= packaging.version.parse(self._constants.amfipass_compatibility_version):
|
||||
# If AMFIPass is loaded, our binaries will work
|
||||
return amfi_detect.AmfiConfigDetectLevel.NO_CHECK
|
||||
return level
|
||||
|
||||
|
||||
def _dortania_internal_check(self) -> None:
|
||||
"""
|
||||
Determine whether to unlock Dortania Developer mode
|
||||
"""
|
||||
return Path("~/.dortania_developer").expanduser().exists()
|
||||
|
||||
|
||||
def _already_has_networking_patches(self) -> bool:
|
||||
"""
|
||||
Check if network patches are already applied
|
||||
"""
|
||||
oclp_patch_path = "/System/Library/CoreServices/OpenCore-Legacy-Patcher.plist"
|
||||
if not Path(oclp_patch_path).exists():
|
||||
return False
|
||||
try:
|
||||
oclp_plist = plistlib.load(open(oclp_patch_path, "rb"))
|
||||
except Exception as e:
|
||||
return False
|
||||
if "Legacy Wireless" in oclp_plist or "Modern Wireless" in oclp_plist:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _is_cached_kernel_debug_kit_present(self) -> bool:
|
||||
"""
|
||||
Check if Kernel Debug Kit is present
|
||||
"""
|
||||
return kdk_handler.KernelDebugKitObject(self._constants, self._os_build, self._os_version, passive=True).kdk_already_installed
|
||||
|
||||
|
||||
def _is_cached_metallib_support_pkg_present(self) -> bool:
|
||||
"""
|
||||
Check if MetallibSupportPkg is present
|
||||
"""
|
||||
return metallib_handler.MetalLibraryObject(self._constants, self._os_build, self._os_version).metallib_already_installed
|
||||
|
||||
|
||||
def _can_patch(self, requirements: dict, ignore_keys: list[str] = []) -> bool:
|
||||
"""
|
||||
Check if patching is possible
|
||||
"""
|
||||
for key, value in requirements.items():
|
||||
if key in ignore_keys:
|
||||
continue
|
||||
if not key.startswith("Validation:"):
|
||||
continue
|
||||
if value is True:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def _convert_required_sip_config_to_int(self, configs: list[str]) -> int:
|
||||
"""
|
||||
Convert required SIP configurations to integer
|
||||
"""
|
||||
value = 0
|
||||
for config in configs:
|
||||
if config in sip_data.system_integrity_protection.csr_values_extended:
|
||||
value += sip_data.system_integrity_protection.csr_values_extended[config]["value"]
|
||||
|
||||
return value
|
||||
|
||||
|
||||
def _strip_incompatible_hardware(self, present_hardware: list[BaseHardware]) -> list[BaseHardware]:
|
||||
"""
|
||||
Strip out incompatible hardware. Priority is given to Metal GPUs (specifically 31001 when applicable)
|
||||
|
||||
Notes:
|
||||
- Non-Metal GPUs are stripped out if any Metal GPUs are present
|
||||
- Metal 3802 GPUs are stripped out if Metal 31001 GPUs are present on macOS Sequoia or newer
|
||||
- Exception is made for "Graphics: AMD Legacy GCN" on Sequoia or newer
|
||||
- Special handling is done in amd_legacy_gcn.py
|
||||
"""
|
||||
non_metal_gpu_present = False
|
||||
metal_gpu_present = False
|
||||
metal_3802_gpu_present = False
|
||||
metal_31001_gpu_present = False
|
||||
metal_31001_name = None
|
||||
|
||||
for hardware in present_hardware:
|
||||
hardware: BaseHardware
|
||||
sub_variant = hardware.hardware_variant_graphics_subclass()
|
||||
if sub_variant == HardwareVariantGraphicsSubclass.METAL_31001_GRAPHICS:
|
||||
metal_31001_gpu_present = True
|
||||
metal_31001_name = hardware.name()
|
||||
elif sub_variant == HardwareVariantGraphicsSubclass.METAL_3802_GRAPHICS:
|
||||
metal_3802_gpu_present = True
|
||||
elif sub_variant == HardwareVariantGraphicsSubclass.NON_METAL_GRAPHICS:
|
||||
non_metal_gpu_present = True
|
||||
|
||||
metal_gpu_present = metal_31001_gpu_present or metal_3802_gpu_present
|
||||
|
||||
if metal_gpu_present and non_metal_gpu_present:
|
||||
logging.error("Cannot mix Metal and Non-Metal GPUs")
|
||||
logging.error("Stripping out Non-Metal GPUs")
|
||||
for hardware in list(present_hardware):
|
||||
if hardware.hardware_variant_graphics_subclass() == HardwareVariantGraphicsSubclass.NON_METAL_GRAPHICS:
|
||||
print(f" Stripping out {hardware.name()}")
|
||||
present_hardware.remove(hardware)
|
||||
|
||||
if metal_3802_gpu_present and metal_31001_gpu_present and self._xnu_major >= os_data.sequoia.value:
|
||||
if metal_31001_name != "Graphics: AMD Legacy GCN":
|
||||
logging.error("Cannot mix Metal 3802 and Metal 31001 GPUs on macOS Sequoia or newer")
|
||||
logging.error("Stripping out Metal 3802 GPUs")
|
||||
for hardware in list(present_hardware):
|
||||
if hardware.hardware_variant_graphics_subclass() == HardwareVariantGraphicsSubclass.METAL_3802_GRAPHICS:
|
||||
logging.error(f" Stripping out {hardware.name()}")
|
||||
present_hardware.remove(hardware)
|
||||
|
||||
return present_hardware
|
||||
|
||||
|
||||
def _handle_missing_network_connection(self, requirements: dict, device_properties: dict) -> tuple[dict, dict]:
|
||||
"""
|
||||
Sync network connection requirements
|
||||
"""
|
||||
if self._can_patch(requirements, ignore_keys=[HardwarePatchsetValidation.MISSING_NETWORK_CONNECTION]) is False:
|
||||
return requirements, device_properties
|
||||
logging.info("Network connection missing, checking whether network patches are applicable")
|
||||
if self._already_has_networking_patches() is True:
|
||||
logging.info("Network patches are already applied, requiring network connection")
|
||||
return requirements, device_properties
|
||||
|
||||
if not any([key.startswith("Networking:") for key in device_properties.keys()]):
|
||||
logging.info("Network patches are not applicable, requiring network connection")
|
||||
return requirements, device_properties
|
||||
|
||||
logging.info("Network patches are applicable, removing other patches")
|
||||
for key in list(device_properties.keys()):
|
||||
if key.startswith("Networking:"):
|
||||
continue
|
||||
device_properties.pop(key, None)
|
||||
|
||||
requirements[HardwarePatchsetValidation.MISSING_NETWORK_CONNECTION] = False
|
||||
requirements[HardwarePatchsetSettings.KERNEL_DEBUG_KIT_REQUIRED] = False
|
||||
requirements[HardwarePatchsetSettings.KERNEL_DEBUG_KIT_MISSING] = False
|
||||
requirements[HardwarePatchsetSettings.METALLIB_SUPPORT_PKG_REQUIRED] = False
|
||||
requirements[HardwarePatchsetSettings.METALLIB_SUPPORT_PKG_MISSING] = False
|
||||
|
||||
return requirements, device_properties
|
||||
|
||||
|
||||
def _handle_sip_breakdown(self, requirements: dict, required_sip_configs: list[str]) -> dict:
|
||||
"""
|
||||
Handle SIP breakdown
|
||||
"""
|
||||
current_sip_status = hex(py_sip_xnu.SipXnu().get_sip_status().value)
|
||||
expected_sip_status = hex(self._convert_required_sip_config_to_int(required_sip_configs))
|
||||
sip_string = f"Validation: Booted SIP: {current_sip_status} vs expected: {expected_sip_status}"
|
||||
index = list(requirements.keys()).index(HardwarePatchsetValidation.SIP_ENABLED)
|
||||
return dict(list(requirements.items())[:index+1] + [(sip_string, True)] + list(requirements.items())[index+1:])
|
||||
|
||||
|
||||
def _detect(self) -> None:
|
||||
"""
|
||||
Detect patches for a given system
|
||||
"""
|
||||
present_hardware = []
|
||||
device_properties = {}
|
||||
patches = {}
|
||||
|
||||
requires_metallib_support_pkg = False
|
||||
missing_metallib_support_pkg = False
|
||||
requires_kernel_debug_kit = False
|
||||
missing_kernel_debug_kit = False
|
||||
requires_network_connection = False
|
||||
has_nvidia_web_drivers = False
|
||||
highest_amfi_level = amfi_detect.AmfiConfigDetectLevel.NO_CHECK
|
||||
required_sip_configs = []
|
||||
|
||||
# First pass to find all present hardware
|
||||
for hardware in self._hardware_variants:
|
||||
item: BaseHardware = hardware(
|
||||
xnu_major = self._xnu_major,
|
||||
xnu_minor = self._xnu_minor,
|
||||
os_build = self._os_build,
|
||||
global_constants = self._constants
|
||||
)
|
||||
# During validation, don't skip missing items
|
||||
# This is to ensure we can validate all files
|
||||
if self._validation is False:
|
||||
if item.present() is False: # Skip if not present
|
||||
continue
|
||||
if item.native_os() is True: # Skip if native OS
|
||||
continue
|
||||
present_hardware.append(item)
|
||||
|
||||
if self._validation is False:
|
||||
present_hardware = self._strip_incompatible_hardware(present_hardware)
|
||||
|
||||
# Second pass to determine requirements
|
||||
for item in present_hardware:
|
||||
item: BaseHardware
|
||||
device_properties[item.name()] = True
|
||||
|
||||
if item.name() == "Graphics: Nvidia Web Drivers":
|
||||
has_nvidia_web_drivers = True
|
||||
|
||||
for config in item.required_system_integrity_protection_configurations():
|
||||
if config not in required_sip_configs:
|
||||
required_sip_configs.append(config)
|
||||
|
||||
if item.requires_metallib_support_pkg() is True:
|
||||
requires_metallib_support_pkg = True
|
||||
if item.requires_kernel_debug_kit() is True:
|
||||
requires_kernel_debug_kit = True
|
||||
if item.required_amfi_level() > highest_amfi_level:
|
||||
highest_amfi_level = item.required_amfi_level()
|
||||
|
||||
if self._validation is False:
|
||||
if requires_metallib_support_pkg is True:
|
||||
missing_metallib_support_pkg = not self._is_cached_metallib_support_pkg_present()
|
||||
if requires_kernel_debug_kit is True:
|
||||
missing_kernel_debug_kit = not self._is_cached_kernel_debug_kit_present()
|
||||
|
||||
requires_network_connection = missing_metallib_support_pkg or missing_kernel_debug_kit
|
||||
|
||||
requirements = {
|
||||
HardwarePatchsetSettings.KERNEL_DEBUG_KIT_REQUIRED: requires_kernel_debug_kit,
|
||||
HardwarePatchsetSettings.KERNEL_DEBUG_KIT_MISSING: missing_kernel_debug_kit,
|
||||
HardwarePatchsetSettings.METALLIB_SUPPORT_PKG_REQUIRED: requires_metallib_support_pkg,
|
||||
HardwarePatchsetSettings.METALLIB_SUPPORT_PKG_MISSING: missing_metallib_support_pkg,
|
||||
|
||||
HardwarePatchsetValidation.UNSUPPORTED_HOST_OS: self._validation_check_unsupported_host_os(),
|
||||
HardwarePatchsetValidation.MISSING_NETWORK_CONNECTION: self._validation_check_missing_network_connection() if requires_network_connection else False,
|
||||
HardwarePatchsetValidation.FILEVAULT_ENABLED: self._validation_check_filevault_is_enabled(),
|
||||
HardwarePatchsetValidation.SIP_ENABLED: self._validation_check_system_integrity_protection_enabled(required_sip_configs),
|
||||
HardwarePatchsetValidation.SECURE_BOOT_MODEL_ENABLED: self._validation_check_secure_boot_model_enabled(),
|
||||
HardwarePatchsetValidation.AMFI_ENABLED: self._validation_check_amfi_enabled(highest_amfi_level),
|
||||
HardwarePatchsetValidation.WHATEVERGREEN_MISSING: self._validation_check_whatevergreen_missing() if has_nvidia_web_drivers is True else False,
|
||||
HardwarePatchsetValidation.FORCE_OPENGL_MISSING: self._validation_check_force_opengl_missing() if has_nvidia_web_drivers is True else False,
|
||||
HardwarePatchsetValidation.FORCE_COMPAT_MISSING: self._validation_check_force_compat_missing() if has_nvidia_web_drivers is True else False,
|
||||
HardwarePatchsetValidation.NVDA_DRV_MISSING: self._validation_check_nvda_drv_missing() if has_nvidia_web_drivers is True else False,
|
||||
}
|
||||
|
||||
_cant_patch = False
|
||||
_cant_unpatch = requirements[HardwarePatchsetValidation.SIP_ENABLED]
|
||||
|
||||
if self._validation is False:
|
||||
if requirements[HardwarePatchsetValidation.SIP_ENABLED] is True:
|
||||
requirements = self._handle_sip_breakdown(requirements, required_sip_configs)
|
||||
if requirements[HardwarePatchsetValidation.MISSING_NETWORK_CONNECTION] is True:
|
||||
requirements, device_properties = self._handle_missing_network_connection(requirements, device_properties)
|
||||
|
||||
# Third pass to sync stripped hardware (ie. '_handle_missing_network_connection()')
|
||||
for item in present_hardware:
|
||||
item: BaseHardware
|
||||
if item.name() not in device_properties:
|
||||
continue
|
||||
patches.update(item.patches())
|
||||
|
||||
_cant_patch = not self._can_patch(requirements)
|
||||
|
||||
requirements[HardwarePatchsetValidation.PATCHING_NOT_POSSIBLE] = _cant_patch
|
||||
requirements[HardwarePatchsetValidation.UNPATCHING_NOT_POSSIBLE] = _cant_unpatch
|
||||
|
||||
self.can_patch = not _cant_patch
|
||||
self.can_unpatch = not _cant_unpatch
|
||||
|
||||
device_properties.update(requirements)
|
||||
|
||||
self.device_properties = device_properties
|
||||
self.patches = patches
|
||||
|
||||
|
||||
def detailed_errors(self) -> None:
|
||||
"""
|
||||
Print out detailed errors
|
||||
"""
|
||||
logging.error("- Breakdown:")
|
||||
for key, value in self.device_properties.items():
|
||||
if not key.startswith("Validation:"):
|
||||
continue
|
||||
if key in [HardwarePatchsetValidation.PATCHING_NOT_POSSIBLE, HardwarePatchsetValidation.UNPATCHING_NOT_POSSIBLE]:
|
||||
continue
|
||||
if value is False:
|
||||
continue
|
||||
logging.error(f" - {key.replace('Validation: ', '')}")
|
||||
176
opencore_legacy_patcher/sys_patch/patchsets/hardware/base.py
Normal file
@@ -0,0 +1,176 @@
|
||||
"""
|
||||
base.py: Base class for hardware patch set detection
|
||||
"""
|
||||
|
||||
from enum import StrEnum
|
||||
from pathlib import Path
|
||||
|
||||
from ..base import BasePatchset
|
||||
|
||||
from ....constants import Constants
|
||||
|
||||
from ....datasets.os_data import os_data
|
||||
from ....datasets.sip_data import system_integrity_protection
|
||||
from ....detections.amfi_detect import AmfiConfigDetectLevel
|
||||
from ....detections import device_probe
|
||||
|
||||
|
||||
class HardwareVariant(StrEnum):
|
||||
"""
|
||||
Hardware variant for patch set
|
||||
"""
|
||||
GRAPHICS: str = "Graphics"
|
||||
NETWORKING: str = "Networking"
|
||||
AUDIO: str = "Audio"
|
||||
MISCELLANEOUS: str = "Miscellaneous"
|
||||
|
||||
|
||||
class HardwareVariantGraphicsSubclass(StrEnum):
|
||||
"""
|
||||
Graphics hardware variant subclass
|
||||
"""
|
||||
NON_METAL_GRAPHICS: str = "Non-Metal Graphics"
|
||||
METAL_3802_GRAPHICS: str = "Metal 3802 Graphics"
|
||||
METAL_31001_GRAPHICS: str = "Metal 31001 Graphics"
|
||||
HEADLESS_GRAPHICS: str = "Headless Graphics"
|
||||
NOT_APPLICABLE: str = "N/A"
|
||||
|
||||
|
||||
class BaseHardware(BasePatchset):
|
||||
|
||||
def __init__(self, xnu_major, xnu_minor, os_build, global_constants: Constants) -> None:
|
||||
super().__init__()
|
||||
self._xnu_major = xnu_major
|
||||
self._xnu_minor = xnu_minor
|
||||
self._os_build = os_build
|
||||
self._constants = global_constants
|
||||
self._computer = global_constants.computer
|
||||
|
||||
self._xnu_float = float(f"{self._xnu_major}.{self._xnu_minor}")
|
||||
|
||||
|
||||
def name(self) -> str:
|
||||
"""
|
||||
Name of the patch set
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def present(self) -> bool:
|
||||
"""
|
||||
Whether the hardware is present in the system
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def native_os(self) -> bool:
|
||||
"""
|
||||
Is on native OS
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def hardware_variant(self) -> HardwareVariant:
|
||||
"""
|
||||
What hardware variant is this patch set for
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def hardware_variant_graphics_subclass(self) -> HardwareVariantGraphicsSubclass:
|
||||
"""
|
||||
What subclass of graphics
|
||||
"""
|
||||
return HardwareVariantGraphicsSubclass.NOT_APPLICABLE
|
||||
|
||||
|
||||
def required_amfi_level(self) -> AmfiConfigDetectLevel:
|
||||
"""
|
||||
What level of AMFI configuration is required for this patch set
|
||||
Currently defaulted to AMFI needing to be disabled
|
||||
"""
|
||||
return AmfiConfigDetectLevel.ALLOW_ALL
|
||||
|
||||
|
||||
def requires_primary_kernel_cache(self) -> bool:
|
||||
"""
|
||||
Whether patch set requires access to the primary kernel cache
|
||||
ex. Boot/System Kernel Collection on Big Sur and newer
|
||||
"""
|
||||
return False
|
||||
|
||||
|
||||
def requires_kernel_debug_kit(self) -> bool:
|
||||
"""
|
||||
Whether patch set requires access to the Kernel Debug Kit
|
||||
"""
|
||||
return False
|
||||
|
||||
|
||||
def requires_metallib_support_pkg(self) -> bool:
|
||||
"""
|
||||
Whether patch set requires access to the MetallibSupportPkg PKG
|
||||
"""
|
||||
return False
|
||||
|
||||
|
||||
def required_system_integrity_protection_configurations(self) -> list[str]:
|
||||
"""
|
||||
List of required SIP configurations for the patch set
|
||||
"""
|
||||
if self._xnu_major >= os_data.ventura.value:
|
||||
return system_integrity_protection.root_patch_sip_ventura
|
||||
if self._xnu_major >= os_data.big_sur.value:
|
||||
return system_integrity_protection.root_patch_sip_big_sur
|
||||
return system_integrity_protection.root_patch_sip_mojave
|
||||
|
||||
|
||||
def patches(self) -> dict:
|
||||
"""
|
||||
Dictionary of patches
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def _is_gpu_architecture_present(self, gpu_architectures: list[device_probe.GPU]) -> bool:
|
||||
"""
|
||||
Check if a GPU architecture is present
|
||||
"""
|
||||
for gpu in self._computer.gpus:
|
||||
if not gpu.class_code:
|
||||
continue
|
||||
if not gpu.arch:
|
||||
continue
|
||||
if gpu.class_code == 0xFFFFFFFF:
|
||||
continue
|
||||
|
||||
if gpu.arch in gpu_architectures:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def _resolve_monterey_framebuffers(self) -> str:
|
||||
"""
|
||||
Resolve patchset directory for framebuffers last supported in Monterey:
|
||||
- AppleIntelBDWGraphics.kext
|
||||
- AppleIntelBDWGraphicsFramebuffer.kext
|
||||
- AppleIntelFramebufferAzul.kext
|
||||
- AppleIntelHD5000Graphics.kext
|
||||
- AppleIntelSKLGraphics.kext
|
||||
- AppleIntelSKLGraphicsFramebuffer.kext
|
||||
- AMDRadeonX4000.kext
|
||||
- AMDRadeonX5000.kext
|
||||
"""
|
||||
if self._xnu_major < os_data.sonoma.value:
|
||||
return "12.5"
|
||||
if self._xnu_float < self.macOS_14_4:
|
||||
return "12.5-23"
|
||||
return "12.5-23.4"
|
||||
|
||||
|
||||
def _dortania_internal_check(self) -> None:
|
||||
"""
|
||||
Determine whether to unlock Dortania Developer mode
|
||||
"""
|
||||
return Path("~/.dortania_developer").expanduser().exists()
|
||||
@@ -0,0 +1,135 @@
|
||||
"""
|
||||
amd_legacy_gcn.py: AMD Legacy GCN detection
|
||||
"""
|
||||
|
||||
from ..base import BaseHardware, HardwareVariant, HardwareVariantGraphicsSubclass
|
||||
|
||||
from ...base import PatchType
|
||||
|
||||
from ...shared_patches.monterey_gva import MontereyGVA
|
||||
from ...shared_patches.monterey_opencl import MontereyOpenCL
|
||||
from ...shared_patches.amd_opencl import AMDOpenCL
|
||||
|
||||
from .....constants import Constants
|
||||
from .....detections import device_probe
|
||||
|
||||
from .....datasets.os_data import os_data
|
||||
|
||||
|
||||
class AMDLegacyGCN(BaseHardware):
|
||||
|
||||
def __init__(self, xnu_major, xnu_minor, os_build, global_constants: Constants) -> None:
|
||||
super().__init__(xnu_major, xnu_minor, os_build, global_constants)
|
||||
|
||||
|
||||
def name(self) -> str:
|
||||
"""
|
||||
Display name for end users
|
||||
"""
|
||||
return f"{self.hardware_variant()}: AMD Legacy GCN"
|
||||
|
||||
|
||||
def present(self) -> bool:
|
||||
"""
|
||||
Targeting AMD Legacy GCN GPUs
|
||||
"""
|
||||
return self._is_gpu_architecture_present(
|
||||
gpu_architectures=[
|
||||
device_probe.AMD.Archs.Legacy_GCN_7000,
|
||||
device_probe.AMD.Archs.Legacy_GCN_8000,
|
||||
device_probe.AMD.Archs.Legacy_GCN_9000
|
||||
]
|
||||
) and self._computer.rosetta_active is False # Rosetta 2 mimics an AMD R9 270X
|
||||
|
||||
|
||||
def native_os(self) -> bool:
|
||||
"""
|
||||
Dropped support with macOS 13, Ventura
|
||||
"""
|
||||
return self._xnu_major < os_data.ventura.value
|
||||
|
||||
|
||||
def hardware_variant(self) -> HardwareVariant:
|
||||
"""
|
||||
Type of hardware variant
|
||||
"""
|
||||
return HardwareVariant.GRAPHICS
|
||||
|
||||
|
||||
def hardware_variant_graphics_subclass(self) -> HardwareVariantGraphicsSubclass:
|
||||
"""
|
||||
Type of hardware variant subclass
|
||||
"""
|
||||
return HardwareVariantGraphicsSubclass.METAL_31001_GRAPHICS
|
||||
|
||||
|
||||
def requires_kernel_debug_kit(self) -> bool:
|
||||
"""
|
||||
Apple no longer provides standalone kexts in the base OS
|
||||
"""
|
||||
return self._xnu_major >= os_data.ventura.value
|
||||
|
||||
|
||||
def _model_specific_patches(self) -> dict:
|
||||
"""
|
||||
Model specific patches
|
||||
"""
|
||||
# If 3802 GPU present, use stock Monterey bronze bundle even on Sequoia
|
||||
bronze_bundle_source = "12.5"
|
||||
if self._is_gpu_architecture_present(
|
||||
[
|
||||
device_probe.Intel.Archs.Ivy_Bridge,
|
||||
device_probe.Intel.Archs.Haswell,
|
||||
device_probe.NVIDIA.Archs.Kepler,
|
||||
]
|
||||
) is False:
|
||||
if self._xnu_major >= os_data.sequoia:
|
||||
bronze_bundle_source = "12.5-24"
|
||||
|
||||
return {
|
||||
"AMD Legacy GCN": {
|
||||
PatchType.OVERWRITE_SYSTEM_VOLUME: {
|
||||
"/System/Library/Extensions": {
|
||||
"AMD7000Controller.kext": "12.5",
|
||||
"AMD8000Controller.kext": "12.5",
|
||||
"AMD9000Controller.kext": "12.5",
|
||||
"AMD9500Controller.kext": "12.5",
|
||||
"AMD10000Controller.kext": "12.5",
|
||||
"AMDRadeonX4000.kext": self._resolve_monterey_framebuffers(),
|
||||
"AMDRadeonX4000HWServices.kext": "12.5",
|
||||
"AMDFramebuffer.kext": "12.5" if self._xnu_float < self.macOS_13_3 else "12.5-GCN",
|
||||
"AMDSupport.kext": "12.5",
|
||||
|
||||
"AMDRadeonVADriver.bundle": "12.5",
|
||||
"AMDRadeonVADriver2.bundle": "12.5",
|
||||
"AMDRadeonX4000GLDriver.bundle": "12.5",
|
||||
"AMDMTLBronzeDriver.bundle": bronze_bundle_source,
|
||||
"AMDShared.bundle": "12.5",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def patches(self) -> dict:
|
||||
"""
|
||||
Patches for AMD Legacy GCN GPUs
|
||||
"""
|
||||
if self.native_os() is True:
|
||||
return {}
|
||||
|
||||
_base = {}
|
||||
|
||||
if self._is_gpu_architecture_present(gpu_architectures=[device_probe.Intel.Archs.Skylake]) is False:
|
||||
# Monterey GVA is not required for Intel Skylake iGPUs
|
||||
_base.update({
|
||||
**MontereyGVA(self._xnu_major, self._xnu_minor, self._constants.detected_os_version).patches(),
|
||||
})
|
||||
|
||||
_base.update({
|
||||
**MontereyOpenCL(self._xnu_major, self._xnu_minor, self._constants.detected_os_version).patches(),
|
||||
**AMDOpenCL(self._xnu_major, self._xnu_minor, self._constants.detected_os_version).patches(),
|
||||
**self._model_specific_patches(),
|
||||
})
|
||||
|
||||
return _base
|
||||
@@ -0,0 +1,146 @@
|
||||
"""
|
||||
amd_polaris.py: AMD Polaris detection
|
||||
"""
|
||||
|
||||
from .amd_legacy_gcn import AMDLegacyGCN
|
||||
|
||||
from ..base import BaseHardware, HardwareVariant, HardwareVariantGraphicsSubclass
|
||||
|
||||
from ...base import PatchType
|
||||
|
||||
from ...shared_patches.monterey_gva import MontereyGVA
|
||||
from ...shared_patches.monterey_opencl import MontereyOpenCL
|
||||
from ...shared_patches.amd_opencl import AMDOpenCL
|
||||
|
||||
from .....constants import Constants
|
||||
from .....detections import device_probe
|
||||
|
||||
from .....datasets.os_data import os_data
|
||||
|
||||
|
||||
class AMDPolaris(BaseHardware):
|
||||
|
||||
def __init__(self, xnu_major, xnu_minor, os_build, global_constants: Constants) -> None:
|
||||
super().__init__(xnu_major, xnu_minor, os_build, global_constants)
|
||||
|
||||
|
||||
def name(self) -> str:
|
||||
"""
|
||||
Display name for end users
|
||||
"""
|
||||
return f"{self.hardware_variant()}: AMD Polaris"
|
||||
|
||||
|
||||
def present(self) -> bool:
|
||||
"""
|
||||
Targeting AMD Polaris GPUs with CPUs lacking AVX2.0 or missing Framebuffer patches (ie. MacBookPro13,3 and MacBookPro14,3)
|
||||
"""
|
||||
return self._is_gpu_architecture_present(
|
||||
gpu_architectures=[
|
||||
device_probe.AMD.Archs.Polaris
|
||||
]
|
||||
) and ("AVX2" not in self._computer.cpu.leafs or self._computer.real_model in ["MacBookPro13,3", "MacBookPro14,3"])
|
||||
|
||||
|
||||
def native_os(self) -> bool:
|
||||
"""
|
||||
Dropped support with macOS 13, Ventura
|
||||
"""
|
||||
return self._xnu_major < os_data.ventura.value
|
||||
|
||||
|
||||
def hardware_variant(self) -> HardwareVariant:
|
||||
"""
|
||||
Type of hardware variant
|
||||
"""
|
||||
return HardwareVariant.GRAPHICS
|
||||
|
||||
|
||||
def hardware_variant_graphics_subclass(self) -> HardwareVariantGraphicsSubclass:
|
||||
"""
|
||||
Type of hardware variant subclass
|
||||
"""
|
||||
return HardwareVariantGraphicsSubclass.METAL_31001_GRAPHICS
|
||||
|
||||
|
||||
def requires_kernel_debug_kit(self) -> bool:
|
||||
"""
|
||||
Apple no longer provides standalone kexts in the base OS
|
||||
"""
|
||||
return self._xnu_major >= os_data.ventura.value
|
||||
|
||||
|
||||
def _model_specific_patches(self) -> dict:
|
||||
"""
|
||||
Model specific patches
|
||||
"""
|
||||
|
||||
# For MacBookPro13,3 missing framebuffers (ex. 'ATY,Berbice')
|
||||
if self._computer.real_model in ["MacBookPro13,3"]:
|
||||
# Since dropped at the same time, we can use the same patches
|
||||
return AMDLegacyGCN(self._xnu_major, self._xnu_minor, self._os_build, self._constants)._model_specific_patches()
|
||||
|
||||
# For MacBookPro14,3 (and other AMD dGPUs that no longer function in Sonoma)
|
||||
# iMac18,2/3 still function with the generic framebuffer, however if issues arise
|
||||
# we'll downgrade them as well.
|
||||
if self._computer.real_model in ["MacBookPro14,3"]:
|
||||
if self._xnu_major < os_data.sonoma.value:
|
||||
return {}
|
||||
return {
|
||||
"AMD Polaris": {
|
||||
PatchType.OVERWRITE_SYSTEM_VOLUME: {
|
||||
"/System/Library/Extensions": {
|
||||
"AMD9500Controller.kext": "13.5.2",
|
||||
"AMD10000Controller.kext": "13.5.2",
|
||||
"AMDFramebuffer.kext": "13.5.2",
|
||||
"AMDSupport.kext": "13.5.2",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
# Assuming non-AVX2.0 CPUs
|
||||
# Note missing framebuffers are not restored (ex. 'ATY,Berbice')
|
||||
return {
|
||||
"AMD Polaris": {
|
||||
PatchType.OVERWRITE_SYSTEM_VOLUME: {
|
||||
"/System/Library/Extensions": {
|
||||
"AMDRadeonX4000.kext": self._resolve_monterey_framebuffers(),
|
||||
"AMDRadeonX4000HWServices.kext": "12.5",
|
||||
"AMDRadeonVADriver2.bundle": "12.5",
|
||||
"AMDRadeonX4000GLDriver.bundle": "12.5",
|
||||
"AMDMTLBronzeDriver.bundle": "12.5" if self._xnu_major < os_data.sequoia else "12.5-24",
|
||||
"AMDShared.bundle": "12.5",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def patches(self) -> dict:
|
||||
"""
|
||||
Patches for AMD Polaris GPUs
|
||||
"""
|
||||
if self.native_os() is True:
|
||||
return {}
|
||||
|
||||
# Minimal amount of patches required for 2017 Polaris
|
||||
if self._computer.real_model in ["MacBookPro14,3"]:
|
||||
return self._model_specific_patches()
|
||||
|
||||
_base = {
|
||||
**MontereyOpenCL(self._xnu_major, self._xnu_minor, self._constants.detected_os_version).patches(),
|
||||
**self._model_specific_patches(),
|
||||
}
|
||||
if "AVX2" not in self._computer.cpu.leafs:
|
||||
_base.update({
|
||||
**AMDOpenCL(self._xnu_major, self._xnu_minor, self._constants.detected_os_version).patches(),
|
||||
})
|
||||
|
||||
if self._is_gpu_architecture_present(gpu_architectures=[device_probe.Intel.Archs.Skylake]) is False:
|
||||
# Monterey GVA is not required for Intel Skylake iGPUs
|
||||
_base.update({
|
||||
**MontereyGVA(self._xnu_major, self._xnu_minor, self._constants.detected_os_version).patches(),
|
||||
})
|
||||
|
||||
return _base
|
||||
@@ -0,0 +1,112 @@
|
||||
"""
|
||||
amd_terascale_1.py: AMD TeraScale 1 detection
|
||||
"""
|
||||
|
||||
from ..base import BaseHardware, HardwareVariant, HardwareVariantGraphicsSubclass
|
||||
|
||||
from ...base import PatchType
|
||||
|
||||
from ...shared_patches.non_metal import NonMetal
|
||||
from ...shared_patches.monterey_webkit import MontereyWebKit
|
||||
from ...shared_patches.amd_terascale import AMDTeraScale
|
||||
|
||||
from .....constants import Constants
|
||||
from .....detections import device_probe
|
||||
|
||||
from .....datasets.os_data import os_data
|
||||
|
||||
|
||||
class AMDTeraScale1(BaseHardware):
|
||||
|
||||
def __init__(self, xnu_major, xnu_minor, os_build, global_constants: Constants) -> None:
|
||||
super().__init__(xnu_major, xnu_minor, os_build, global_constants)
|
||||
|
||||
|
||||
def name(self) -> str:
|
||||
"""
|
||||
Display name for end users
|
||||
"""
|
||||
return f"{self.hardware_variant()}: AMD TeraScale 1"
|
||||
|
||||
|
||||
def present(self) -> bool:
|
||||
"""
|
||||
Targeting AMD TeraScale GPUs
|
||||
"""
|
||||
return self._is_gpu_architecture_present(
|
||||
gpu_architectures=[
|
||||
device_probe.AMD.Archs.TeraScale_1
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def native_os(self) -> bool:
|
||||
"""
|
||||
Dropped support with macOS 10.14, Mojave
|
||||
"""
|
||||
return self._xnu_major < os_data.mojave.value
|
||||
|
||||
|
||||
def hardware_variant(self) -> HardwareVariant:
|
||||
"""
|
||||
Type of hardware variant
|
||||
"""
|
||||
return HardwareVariant.GRAPHICS
|
||||
|
||||
|
||||
def hardware_variant_graphics_subclass(self) -> HardwareVariantGraphicsSubclass:
|
||||
"""
|
||||
Type of hardware variant subclass
|
||||
"""
|
||||
return HardwareVariantGraphicsSubclass.NON_METAL_GRAPHICS
|
||||
|
||||
|
||||
def requires_kernel_debug_kit(self) -> bool:
|
||||
"""
|
||||
Apple no longer provides standalone kexts in the base OS
|
||||
"""
|
||||
return self._xnu_major >= os_data.ventura.value
|
||||
|
||||
|
||||
def _model_specific_patches(self) -> dict:
|
||||
"""
|
||||
Model specific patches
|
||||
"""
|
||||
return {
|
||||
"AMD TeraScale 1": {
|
||||
PatchType.OVERWRITE_SYSTEM_VOLUME: {
|
||||
"/System/Library/Extensions": {
|
||||
"AMD2400Controller.kext": "10.13.6",
|
||||
"AMD2600Controller.kext": "10.13.6",
|
||||
"AMD3800Controller.kext": "10.13.6",
|
||||
"AMD4600Controller.kext": "10.13.6",
|
||||
"AMD4800Controller.kext": "10.13.6",
|
||||
"ATIRadeonX2000.kext": "10.13.6" if self._xnu_major < os_data.ventura else "10.13.6 TS1",
|
||||
"ATIRadeonX2000GA.plugin": "10.13.6",
|
||||
"ATIRadeonX2000GLDriver.bundle": "10.13.6",
|
||||
"ATIRadeonX2000VADriver.bundle": "10.13.6",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def patches(self) -> dict:
|
||||
"""
|
||||
Patches for AMD TeraScale 1 GPUs
|
||||
"""
|
||||
if self.native_os() is True:
|
||||
return {}
|
||||
|
||||
if self._xnu_major not in self._constants.legacy_accel_support and self._dortania_internal_check() is False:
|
||||
return {
|
||||
**AMDTeraScale(self._xnu_major, self._xnu_minor, self._os_build).patches(),
|
||||
**self._model_specific_patches()
|
||||
}
|
||||
|
||||
return {
|
||||
**NonMetal(self._xnu_major, self._xnu_minor, self._os_build).patches(),
|
||||
**MontereyWebKit(self._xnu_major, self._xnu_minor, self._os_build).patches(),
|
||||
**AMDTeraScale(self._xnu_major, self._xnu_minor, self._os_build).patches(),
|
||||
**self._model_specific_patches(),
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
"""
|
||||
amd_terascale_2.py: AMD TeraScale 2 detection
|
||||
"""
|
||||
|
||||
from ..base import BaseHardware, HardwareVariant, HardwareVariantGraphicsSubclass
|
||||
|
||||
from ...base import PatchType
|
||||
|
||||
from ...shared_patches.non_metal import NonMetal
|
||||
from ...shared_patches.non_metal_ioaccel import NonMetalIOAccelerator
|
||||
from ...shared_patches.monterey_webkit import MontereyWebKit
|
||||
from ...shared_patches.amd_terascale import AMDTeraScale
|
||||
|
||||
from .....constants import Constants
|
||||
from .....detections import device_probe
|
||||
|
||||
from .....datasets.os_data import os_data
|
||||
|
||||
|
||||
class AMDTeraScale2(BaseHardware):
|
||||
|
||||
def __init__(self, xnu_major, xnu_minor, os_build, global_constants: Constants) -> None:
|
||||
super().__init__(xnu_major, xnu_minor, os_build, global_constants)
|
||||
|
||||
|
||||
def name(self) -> str:
|
||||
"""
|
||||
Display name for end users
|
||||
"""
|
||||
return f"{self.hardware_variant()}: AMD TeraScale 2"
|
||||
|
||||
|
||||
def present(self) -> bool:
|
||||
"""
|
||||
Targeting AMD TeraScale GPUs
|
||||
"""
|
||||
return self._is_gpu_architecture_present(
|
||||
gpu_architectures=[
|
||||
device_probe.AMD.Archs.TeraScale_2
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def native_os(self) -> bool:
|
||||
"""
|
||||
Dropped support with macOS 10.14, Mojave
|
||||
"""
|
||||
return self._xnu_major < os_data.mojave.value
|
||||
|
||||
|
||||
def hardware_variant(self) -> HardwareVariant:
|
||||
"""
|
||||
Type of hardware variant
|
||||
"""
|
||||
return HardwareVariant.GRAPHICS
|
||||
|
||||
|
||||
def hardware_variant_graphics_subclass(self) -> HardwareVariantGraphicsSubclass:
|
||||
"""
|
||||
Type of hardware variant subclass
|
||||
"""
|
||||
return HardwareVariantGraphicsSubclass.NON_METAL_GRAPHICS
|
||||
|
||||
|
||||
def requires_kernel_debug_kit(self) -> bool:
|
||||
"""
|
||||
Apple no longer provides standalone kexts in the base OS
|
||||
"""
|
||||
return self._xnu_major >= os_data.ventura.value
|
||||
|
||||
|
||||
def _model_specific_patches(self) -> dict:
|
||||
"""
|
||||
Model specific patches
|
||||
"""
|
||||
_base = {
|
||||
"AMD TeraScale 2": {
|
||||
PatchType.OVERWRITE_SYSTEM_VOLUME: {
|
||||
"/System/Library/Extensions": {
|
||||
"AMD5000Controller.kext": "10.13.6",
|
||||
"AMD6000Controller.kext": "10.13.6",
|
||||
"AMDRadeonVADriver.bundle": "10.13.6",
|
||||
"AMDRadeonVADriver2.bundle": "10.13.6",
|
||||
"AMDRadeonX3000.kext": "10.13.6",
|
||||
"AMDRadeonX3000GLDriver.bundle": "10.13.6",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
# TeraScale 2 MacBooks with faulty GPUs are highly prone to crashing with AMDRadeonX3000 attached
|
||||
if self._constants.allow_ts2_accel is False and self._constants.host_is_hackintosh is False:
|
||||
_base["AMD TeraScale 2"][PatchType.OVERWRITE_SYSTEM_VOLUME]["/System/Library/Extensions"].pop("AMDRadeonX3000.kext")
|
||||
|
||||
return _base
|
||||
|
||||
|
||||
def patches(self) -> dict:
|
||||
"""
|
||||
Patches for AMD TeraScale 2 GPUs
|
||||
"""
|
||||
if self.native_os() is True:
|
||||
return {}
|
||||
|
||||
if self._xnu_major not in self._constants.legacy_accel_support and self._dortania_internal_check() is False:
|
||||
return {
|
||||
**AMDTeraScale(self._xnu_major, self._xnu_minor, self._os_build).patches(),
|
||||
**self._model_specific_patches()
|
||||
}
|
||||
|
||||
return {
|
||||
**NonMetal(self._xnu_major, self._xnu_minor, self._os_build).patches(),
|
||||
**NonMetalIOAccelerator(self._xnu_major, self._xnu_minor, self._os_build).patches(),
|
||||
**MontereyWebKit(self._xnu_major, self._xnu_minor, self._os_build).patches(),
|
||||
**AMDTeraScale(self._xnu_major, self._xnu_minor, self._os_build).patches(),
|
||||
**self._model_specific_patches(),
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
"""
|
||||
amd_vega.py: AMD Vega detection
|
||||
"""
|
||||
|
||||
from ..base import BaseHardware, HardwareVariant, HardwareVariantGraphicsSubclass
|
||||
|
||||
from ...base import PatchType
|
||||
|
||||
from ...shared_patches.monterey_gva import MontereyGVA
|
||||
from ...shared_patches.monterey_opencl import MontereyOpenCL
|
||||
from ...shared_patches.amd_opencl import AMDOpenCL
|
||||
|
||||
from .....constants import Constants
|
||||
from .....detections import device_probe
|
||||
|
||||
from .....datasets.os_data import os_data
|
||||
|
||||
|
||||
class AMDVega(BaseHardware):
|
||||
|
||||
def __init__(self, xnu_major, xnu_minor, os_build, global_constants: Constants) -> None:
|
||||
super().__init__(xnu_major, xnu_minor, os_build, global_constants)
|
||||
|
||||
|
||||
def name(self) -> str:
|
||||
"""
|
||||
Display name for end users
|
||||
"""
|
||||
return f"{self.hardware_variant()}: AMD Vega"
|
||||
|
||||
|
||||
def present(self) -> bool:
|
||||
"""
|
||||
Targeting AMD Vega GPUs with CPUs lacking AVX2.0
|
||||
"""
|
||||
return self._is_gpu_architecture_present(
|
||||
gpu_architectures=[
|
||||
device_probe.AMD.Archs.Vega
|
||||
]
|
||||
) and "AVX2" not in self._computer.cpu.leafs
|
||||
|
||||
|
||||
def native_os(self) -> bool:
|
||||
"""
|
||||
Dropped support with macOS 13, Ventura
|
||||
"""
|
||||
return self._xnu_major < os_data.ventura.value
|
||||
|
||||
|
||||
def hardware_variant(self) -> HardwareVariant:
|
||||
"""
|
||||
Type of hardware variant
|
||||
"""
|
||||
return HardwareVariant.GRAPHICS
|
||||
|
||||
|
||||
def hardware_variant_graphics_subclass(self) -> HardwareVariantGraphicsSubclass:
|
||||
"""
|
||||
Type of hardware variant subclass
|
||||
"""
|
||||
return HardwareVariantGraphicsSubclass.METAL_31001_GRAPHICS
|
||||
|
||||
|
||||
def requires_kernel_debug_kit(self) -> bool:
|
||||
"""
|
||||
Apple no longer provides standalone kexts in the base OS
|
||||
"""
|
||||
return self._xnu_major >= os_data.ventura.value
|
||||
|
||||
|
||||
def _model_specific_patches(self) -> dict:
|
||||
"""
|
||||
Model specific patches
|
||||
"""
|
||||
return {
|
||||
"AMD Vega": {
|
||||
PatchType.OVERWRITE_SYSTEM_VOLUME: {
|
||||
"/System/Library/Extensions": {
|
||||
"AMDRadeonX5000.kext": self._resolve_monterey_framebuffers(),
|
||||
|
||||
"AMDRadeonVADriver2.bundle": "12.5",
|
||||
"AMDRadeonX5000GLDriver.bundle": "12.5",
|
||||
"AMDRadeonX5000MTLDriver.bundle": "12.5" if self._xnu_major < os_data.sequoia else "12.5-24",
|
||||
"AMDRadeonX5000Shared.bundle": "12.5",
|
||||
|
||||
"AMDShared.bundle": "12.5",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def _model_specific_patches_extended(self) -> dict:
|
||||
"""
|
||||
Support mixed legacy and modern AMD GPUs
|
||||
Specifically systems using AMD GCN 1-3 and Vega (ex. MacPro6,1 with eGPU)
|
||||
Assume 'AMD Legacy GCN' patchset is installed alongside this
|
||||
"""
|
||||
if self._is_gpu_architecture_present([
|
||||
device_probe.AMD.Archs.Legacy_GCN_7000,
|
||||
device_probe.AMD.Archs.Legacy_GCN_8000,
|
||||
device_probe.AMD.Archs.Legacy_GCN_9000
|
||||
]) is False:
|
||||
return {}
|
||||
|
||||
return {
|
||||
"AMD Vega Extended": {
|
||||
PatchType.OVERWRITE_SYSTEM_VOLUME: {
|
||||
"/System/Library/Extensions": {
|
||||
"AMDRadeonX5000HWServices.kext": "12.5",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def patches(self) -> dict:
|
||||
"""
|
||||
Patches for AMD Vega GPUs
|
||||
"""
|
||||
if self.native_os() is True:
|
||||
return {}
|
||||
|
||||
return {
|
||||
**MontereyGVA(self._xnu_major, self._xnu_minor, self._constants.detected_os_version).patches(),
|
||||
**MontereyOpenCL(self._xnu_major, self._xnu_minor, self._constants.detected_os_version).patches(),
|
||||
**AMDOpenCL(self._xnu_major, self._xnu_minor, self._constants.detected_os_version).patches(),
|
||||
**self._model_specific_patches(),
|
||||
**self._model_specific_patches_extended(),
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
"""
|
||||
intel_broadwell.py: Intel Broadwell detection
|
||||
"""
|
||||
|
||||
from ..base import BaseHardware, HardwareVariant, HardwareVariantGraphicsSubclass
|
||||
|
||||
from ...base import PatchType
|
||||
|
||||
from ...shared_patches.monterey_gva import MontereyGVA
|
||||
from ...shared_patches.monterey_opencl import MontereyOpenCL
|
||||
|
||||
from .....constants import Constants
|
||||
from .....detections import device_probe
|
||||
|
||||
from .....datasets.os_data import os_data
|
||||
|
||||
|
||||
class IntelBroadwell(BaseHardware):
|
||||
|
||||
def __init__(self, xnu_major, xnu_minor, os_build, global_constants: Constants) -> None:
|
||||
super().__init__(xnu_major, xnu_minor, os_build, global_constants)
|
||||
|
||||
|
||||
def name(self) -> str:
|
||||
"""
|
||||
Display name for end users
|
||||
"""
|
||||
return f"{self.hardware_variant()}: Intel Broadwell"
|
||||
|
||||
|
||||
def present(self) -> bool:
|
||||
"""
|
||||
Targeting Intel Broadwell GPUs
|
||||
"""
|
||||
return self._is_gpu_architecture_present(
|
||||
gpu_architectures=[
|
||||
device_probe.Intel.Archs.Broadwell
|
||||
]
|
||||
)
|
||||
|
||||
def hardware_variant(self) -> HardwareVariant:
|
||||
"""
|
||||
Type of hardware variant
|
||||
"""
|
||||
return HardwareVariant.GRAPHICS
|
||||
|
||||
|
||||
def hardware_variant_graphics_subclass(self) -> HardwareVariantGraphicsSubclass:
|
||||
"""
|
||||
Type of hardware variant subclass
|
||||
"""
|
||||
return HardwareVariantGraphicsSubclass.METAL_31001_GRAPHICS
|
||||
|
||||
|
||||
def native_os(self) -> bool:
|
||||
"""
|
||||
Dropped support with macOS 13, Ventura
|
||||
"""
|
||||
return self._xnu_major < os_data.ventura.value
|
||||
|
||||
|
||||
def _model_specific_patches(self) -> dict:
|
||||
"""
|
||||
Model specific patches
|
||||
"""
|
||||
return {
|
||||
"Intel Broadwell": {
|
||||
PatchType.OVERWRITE_SYSTEM_VOLUME: {
|
||||
"/System/Library/Extensions": {
|
||||
"AppleIntelBDWGraphics.kext": self._resolve_monterey_framebuffers(),
|
||||
"AppleIntelBDWGraphicsFramebuffer.kext": self._resolve_monterey_framebuffers(),
|
||||
"AppleIntelBDWGraphicsGLDriver.bundle": "12.5",
|
||||
"AppleIntelBDWGraphicsMTLDriver.bundle": "12.5-22" if self._xnu_major < os_data.sequoia else "12.5-24",
|
||||
"AppleIntelBDWGraphicsVADriver.bundle": "12.5",
|
||||
"AppleIntelBDWGraphicsVAME.bundle": "12.5",
|
||||
"AppleIntelGraphicsShared.bundle": "12.5",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def patches(self) -> dict:
|
||||
"""
|
||||
Patches for Intel Broadwell iGPUs
|
||||
"""
|
||||
if self.native_os() is True:
|
||||
return {}
|
||||
|
||||
return {
|
||||
**MontereyGVA(self._xnu_major, self._xnu_minor, self._constants.detected_os_version).patches(),
|
||||
**MontereyOpenCL(self._xnu_major, self._xnu_minor, self._constants.detected_os_version).patches(),
|
||||
**self._model_specific_patches(),
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
"""
|
||||
intel_haswell.py: Intel Haswell detection
|
||||
"""
|
||||
|
||||
from ..base import BaseHardware, HardwareVariant, HardwareVariantGraphicsSubclass
|
||||
|
||||
from ...base import PatchType
|
||||
|
||||
from ...shared_patches.metal_3802 import LegacyMetal3802
|
||||
from ...shared_patches.monterey_gva import MontereyGVA
|
||||
from ...shared_patches.monterey_opencl import MontereyOpenCL
|
||||
|
||||
from .....constants import Constants
|
||||
from .....detections import device_probe
|
||||
|
||||
from .....datasets.os_data import os_data
|
||||
|
||||
|
||||
class IntelHaswell(BaseHardware):
|
||||
|
||||
def __init__(self, xnu_major, xnu_minor, os_build, global_constants: Constants) -> None:
|
||||
super().__init__(xnu_major, xnu_minor, os_build, global_constants)
|
||||
|
||||
|
||||
def name(self) -> str:
|
||||
"""
|
||||
Display name for end users
|
||||
"""
|
||||
return f"{self.hardware_variant()}: Intel Haswell"
|
||||
|
||||
|
||||
def present(self) -> bool:
|
||||
"""
|
||||
Targeting Intel Haswell GPUs
|
||||
"""
|
||||
return self._is_gpu_architecture_present(
|
||||
gpu_architectures=[
|
||||
device_probe.Intel.Archs.Haswell
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def native_os(self) -> bool:
|
||||
"""
|
||||
Dropped support with macOS 13, Ventura
|
||||
"""
|
||||
return self._xnu_major < os_data.ventura.value
|
||||
|
||||
|
||||
def hardware_variant(self) -> HardwareVariant:
|
||||
"""
|
||||
Type of hardware variant
|
||||
"""
|
||||
return HardwareVariant.GRAPHICS
|
||||
|
||||
|
||||
def hardware_variant_graphics_subclass(self) -> HardwareVariantGraphicsSubclass:
|
||||
"""
|
||||
Type of hardware variant subclass
|
||||
"""
|
||||
return HardwareVariantGraphicsSubclass.METAL_3802_GRAPHICS
|
||||
|
||||
|
||||
def requires_metallib_support_pkg(self) -> bool:
|
||||
"""
|
||||
New compiler format introduced in macOS 15, Sequoia
|
||||
"""
|
||||
return self._xnu_major >= os_data.sequoia.value
|
||||
|
||||
|
||||
def _model_specific_patches(self) -> dict:
|
||||
"""
|
||||
Model specific patches
|
||||
"""
|
||||
return {
|
||||
"Intel Haswell": {
|
||||
PatchType.OVERWRITE_SYSTEM_VOLUME: {
|
||||
"/System/Library/Extensions": {
|
||||
"AppleIntelFramebufferAzul.kext": self._resolve_monterey_framebuffers(),
|
||||
"AppleIntelHD5000Graphics.kext": self._resolve_monterey_framebuffers(),
|
||||
"AppleIntelHD5000GraphicsGLDriver.bundle": "12.5",
|
||||
"AppleIntelHD5000GraphicsMTLDriver.bundle": "12.5",
|
||||
"AppleIntelHD5000GraphicsVADriver.bundle": "12.5",
|
||||
"AppleIntelHSWVA.bundle": "12.5",
|
||||
"AppleIntelGraphicsShared.bundle": "12.5",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def _framebuffer_only_patches(self) -> dict:
|
||||
"""
|
||||
Framebuffer only patches
|
||||
"""
|
||||
return {
|
||||
"Intel Haswell": {
|
||||
PatchType.OVERWRITE_SYSTEM_VOLUME: {
|
||||
"/System/Library/Extensions": {
|
||||
"AppleIntelFramebufferAzul.kext": self._resolve_monterey_framebuffers(),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def patches(self) -> dict:
|
||||
"""
|
||||
Patches for Intel Haswell iGPUs
|
||||
"""
|
||||
if self.native_os() is True:
|
||||
return {}
|
||||
|
||||
return {
|
||||
**LegacyMetal3802(self._xnu_major, self._xnu_minor, self._constants.detected_os_version).patches(),
|
||||
**MontereyGVA(self._xnu_major, self._xnu_minor, self._constants.detected_os_version).patches(),
|
||||
**MontereyOpenCL(self._xnu_major, self._xnu_minor, self._constants.detected_os_version).patches(),
|
||||
**self._model_specific_patches(),
|
||||
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
"""
|
||||
intel_iron_lake.py: Intel Iron Lake detection
|
||||
"""
|
||||
|
||||
from ..base import BaseHardware, HardwareVariant, HardwareVariantGraphicsSubclass
|
||||
|
||||
from ...base import PatchType
|
||||
|
||||
from ...shared_patches.non_metal import NonMetal
|
||||
from ...shared_patches.monterey_webkit import MontereyWebKit
|
||||
|
||||
from .....constants import Constants
|
||||
from .....detections import device_probe
|
||||
|
||||
from .....datasets.os_data import os_data
|
||||
|
||||
|
||||
class IntelIronLake(BaseHardware):
|
||||
|
||||
def __init__(self, xnu_major, xnu_minor, os_build, global_constants: Constants) -> None:
|
||||
super().__init__(xnu_major, xnu_minor, os_build, global_constants)
|
||||
|
||||
|
||||
def name(self) -> str:
|
||||
"""
|
||||
Display name for end users
|
||||
"""
|
||||
return f"{self.hardware_variant()}: Intel Iron Lake"
|
||||
|
||||
|
||||
def present(self) -> bool:
|
||||
"""
|
||||
Targeting Intel Iron Lake GPUs
|
||||
"""
|
||||
return self._is_gpu_architecture_present(
|
||||
gpu_architectures=[
|
||||
device_probe.Intel.Archs.Iron_Lake
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def native_os(self) -> bool:
|
||||
"""
|
||||
Dropped support with macOS 10.14, Mojave
|
||||
"""
|
||||
return self._xnu_major < os_data.mojave.value
|
||||
|
||||
|
||||
def hardware_variant(self) -> HardwareVariant:
|
||||
"""
|
||||
Type of hardware variant
|
||||
"""
|
||||
return HardwareVariant.GRAPHICS
|
||||
|
||||
|
||||
def hardware_variant_graphics_subclass(self) -> HardwareVariantGraphicsSubclass:
|
||||
"""
|
||||
Type of hardware variant subclass
|
||||
"""
|
||||
return HardwareVariantGraphicsSubclass.NON_METAL_GRAPHICS
|
||||
|
||||
|
||||
def requires_kernel_debug_kit(self) -> bool:
|
||||
"""
|
||||
Apple no longer provides standalone kexts in the base OS
|
||||
"""
|
||||
return self._xnu_major >= os_data.ventura.value
|
||||
|
||||
|
||||
def _model_specific_patches(self) -> dict:
|
||||
"""
|
||||
Model specific patches
|
||||
"""
|
||||
return {
|
||||
"Intel Iron Lake": {
|
||||
PatchType.OVERWRITE_SYSTEM_VOLUME: {
|
||||
"/System/Library/Extensions": {
|
||||
"AppleIntelHDGraphics.kext": "10.13.6",
|
||||
"AppleIntelHDGraphicsFB.kext": "10.13.6",
|
||||
"AppleIntelHDGraphicsGA.plugin": "10.13.6",
|
||||
"AppleIntelHDGraphicsGLDriver.bundle": "10.13.6",
|
||||
"AppleIntelHDGraphicsVADriver.bundle": "10.13.6",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def patches(self) -> dict:
|
||||
"""
|
||||
Patches for Intel Iron Lake iGPUs
|
||||
"""
|
||||
if self.native_os() is True:
|
||||
return {}
|
||||
|
||||
if self._xnu_major not in self._constants.legacy_accel_support and self._dortania_internal_check() is False:
|
||||
return {**self._model_specific_patches()}
|
||||
|
||||
return {
|
||||
**NonMetal(self._xnu_major, self._xnu_minor, self._os_build).patches(),
|
||||
**MontereyWebKit(self._xnu_major, self._xnu_minor, self._os_build).patches(),
|
||||
**self._model_specific_patches(),
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
"""
|
||||
intel_ivy_bridge.py: Intel Ivy Bridge detection
|
||||
"""
|
||||
|
||||
from ..base import BaseHardware, HardwareVariant, HardwareVariantGraphicsSubclass
|
||||
|
||||
from ...base import PatchType
|
||||
|
||||
from ...shared_patches.metal_3802 import LegacyMetal3802
|
||||
from ...shared_patches.big_sur_gva import BigSurGVA
|
||||
from ...shared_patches.monterey_opencl import MontereyOpenCL
|
||||
from ...shared_patches.big_sur_opencl import BigSurOpenCL
|
||||
from ...shared_patches.monterey_webkit import MontereyWebKit
|
||||
|
||||
from .....constants import Constants
|
||||
from .....detections import device_probe
|
||||
|
||||
from .....datasets.os_data import os_data
|
||||
|
||||
|
||||
class IntelIvyBridge(BaseHardware):
|
||||
|
||||
def __init__(self, xnu_major, xnu_minor, os_build, global_constants: Constants) -> None:
|
||||
super().__init__(xnu_major, xnu_minor, os_build, global_constants)
|
||||
|
||||
|
||||
def name(self) -> str:
|
||||
"""
|
||||
Display name for end users
|
||||
"""
|
||||
return f"{self.hardware_variant()}: Intel Ivy Bridge"
|
||||
|
||||
|
||||
def present(self) -> bool:
|
||||
"""
|
||||
Targeting Intel Ivy Bridge GPUs
|
||||
"""
|
||||
return self._is_gpu_architecture_present(
|
||||
gpu_architectures=[
|
||||
device_probe.Intel.Archs.Ivy_Bridge
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def native_os(self) -> bool:
|
||||
"""
|
||||
Dropped support with macOS 12, Monterey
|
||||
"""
|
||||
return self._xnu_major < os_data.monterey.value
|
||||
|
||||
|
||||
def hardware_variant(self) -> HardwareVariant:
|
||||
"""
|
||||
Type of hardware variant
|
||||
"""
|
||||
return HardwareVariant.GRAPHICS
|
||||
|
||||
|
||||
def hardware_variant_graphics_subclass(self) -> HardwareVariantGraphicsSubclass:
|
||||
"""
|
||||
Type of hardware variant subclass
|
||||
"""
|
||||
return HardwareVariantGraphicsSubclass.METAL_3802_GRAPHICS
|
||||
|
||||
|
||||
def requires_metallib_support_pkg(self) -> bool:
|
||||
"""
|
||||
New compiler format introduced in macOS 15, Sequoia
|
||||
"""
|
||||
return self._xnu_major >= os_data.sequoia.value
|
||||
|
||||
|
||||
def _resolve_ivy_bridge_framebuffers(self) -> str:
|
||||
"""
|
||||
Resolve patchset directory for Ivy Bridge framebuffers:
|
||||
- AppleIntelFramebufferCapri.kext
|
||||
- AppleIntelHD4000Graphics.kext
|
||||
"""
|
||||
if self._xnu_major < os_data.sonoma:
|
||||
return "11.7.10"
|
||||
if self._xnu_float < self.macOS_14_4:
|
||||
return "11.7.10-23"
|
||||
return "11.7.10-23.4"
|
||||
|
||||
|
||||
def _model_specific_patches(self) -> dict:
|
||||
"""
|
||||
Model specific patches
|
||||
"""
|
||||
return {
|
||||
"Intel Ivy Bridge": {
|
||||
PatchType.OVERWRITE_SYSTEM_VOLUME: {
|
||||
"/System/Library/Extensions": {
|
||||
"AppleIntelHD4000GraphicsGLDriver.bundle": "11.7.10",
|
||||
"AppleIntelHD4000GraphicsMTLDriver.bundle": "11.7.10" if self._xnu_major < os_data.ventura else "11.7.10-22",
|
||||
"AppleIntelHD4000GraphicsVADriver.bundle": "11.7.10",
|
||||
"AppleIntelFramebufferCapri.kext": self._resolve_ivy_bridge_framebuffers(),
|
||||
"AppleIntelHD4000Graphics.kext": self._resolve_ivy_bridge_framebuffers(),
|
||||
"AppleIntelIVBVA.bundle": "11.7.10",
|
||||
"AppleIntelGraphicsShared.bundle": "11.7.10", # libIGIL-Metal.dylib pulled from 11.0 Beta 6
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def patches(self) -> dict:
|
||||
"""
|
||||
Patches for Intel Ivy Bridge iGPUs
|
||||
"""
|
||||
if self.native_os() is True:
|
||||
return {}
|
||||
|
||||
return {
|
||||
**LegacyMetal3802(self._xnu_major, self._xnu_minor, self._constants.detected_os_version).patches(),
|
||||
**BigSurGVA(self._xnu_major, self._xnu_minor, self._constants.detected_os_version).patches(),
|
||||
**MontereyOpenCL(self._xnu_major, self._xnu_minor, self._constants.detected_os_version).patches(),
|
||||
**BigSurOpenCL(self._xnu_major, self._xnu_minor, self._constants.detected_os_version).patches(),
|
||||
**MontereyWebKit(self._xnu_major, self._xnu_minor, self._os_build).patches(),
|
||||
**self._model_specific_patches(),
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
"""
|
||||
intel_sandy_bridge.py: Intel Sandy Bridge detection
|
||||
"""
|
||||
|
||||
from ..base import BaseHardware, HardwareVariant, HardwareVariantGraphicsSubclass
|
||||
|
||||
from ...base import PatchType
|
||||
|
||||
from ...shared_patches.non_metal import NonMetal
|
||||
from ...shared_patches.monterey_webkit import MontereyWebKit
|
||||
from ...shared_patches.high_sierra_gva import HighSierraGVA
|
||||
|
||||
from .....constants import Constants
|
||||
from .....detections import device_probe
|
||||
|
||||
from .....datasets.os_data import os_data
|
||||
|
||||
|
||||
class IntelSandyBridge(BaseHardware):
|
||||
|
||||
def __init__(self, xnu_major, xnu_minor, os_build, global_constants: Constants) -> None:
|
||||
super().__init__(xnu_major, xnu_minor, os_build, global_constants)
|
||||
|
||||
|
||||
def name(self) -> str:
|
||||
"""
|
||||
Display name for end users
|
||||
"""
|
||||
return f"{self.hardware_variant()}: Intel Sandy Bridge"
|
||||
|
||||
|
||||
def present(self) -> bool:
|
||||
"""
|
||||
Targeting Intel Sandy Bridge GPUs
|
||||
"""
|
||||
return self._is_gpu_architecture_present(
|
||||
gpu_architectures=[
|
||||
device_probe.Intel.Archs.Sandy_Bridge
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def native_os(self) -> bool:
|
||||
"""
|
||||
Dropped support with macOS 10.14, Mojave
|
||||
"""
|
||||
return self._xnu_major < os_data.mojave.value
|
||||
|
||||
|
||||
def hardware_variant(self) -> HardwareVariant:
|
||||
"""
|
||||
Type of hardware variant
|
||||
"""
|
||||
return HardwareVariant.GRAPHICS
|
||||
|
||||
|
||||
def hardware_variant_graphics_subclass(self) -> HardwareVariantGraphicsSubclass:
|
||||
"""
|
||||
Type of hardware variant subclass
|
||||
"""
|
||||
return HardwareVariantGraphicsSubclass.NON_METAL_GRAPHICS
|
||||
|
||||
|
||||
def requires_kernel_debug_kit(self) -> bool:
|
||||
"""
|
||||
Requires replacing a number of kexts in the BootKC
|
||||
"""
|
||||
if self._xnu_major >= os_data.ventura.value:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _model_specific_patches(self) -> dict:
|
||||
"""
|
||||
Model specific patches
|
||||
"""
|
||||
return {
|
||||
"Intel Sandy Bridge": {
|
||||
PatchType.OVERWRITE_SYSTEM_VOLUME: {
|
||||
"/System/Library/Extensions": {
|
||||
"AppleIntelHD3000Graphics.kext": "10.13.6",
|
||||
"AppleIntelHD3000GraphicsGA.plugin": "10.13.6",
|
||||
"AppleIntelHD3000GraphicsGLDriver.bundle": "10.13.6",
|
||||
"AppleIntelHD3000GraphicsVADriver.bundle": "10.13.6",
|
||||
"AppleIntelSNBGraphicsFB.kext": "10.13.6",
|
||||
"AppleIntelSNBVA.bundle": "10.13.6",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def patches(self) -> dict:
|
||||
"""
|
||||
Patches for Intel Sandy Bridge GPUs
|
||||
"""
|
||||
if self.native_os() is True:
|
||||
return {}
|
||||
|
||||
if self._xnu_major not in self._constants.legacy_accel_support and self._dortania_internal_check() is False:
|
||||
return {**self._model_specific_patches()}
|
||||
|
||||
return {
|
||||
**NonMetal(self._xnu_major, self._xnu_minor, self._os_build).patches(),
|
||||
**HighSierraGVA(self._xnu_major, self._xnu_minor, self._os_build).patches(),
|
||||
**MontereyWebKit(self._xnu_major, self._xnu_minor, self._os_build).patches(),
|
||||
**self._model_specific_patches(),
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
"""
|
||||
intel_skylake.py: Intel Skylake detection
|
||||
"""
|
||||
|
||||
from ..base import BaseHardware, HardwareVariant, HardwareVariantGraphicsSubclass
|
||||
|
||||
from ...base import PatchType
|
||||
|
||||
from ...shared_patches.monterey_opencl import MontereyOpenCL
|
||||
|
||||
from .....constants import Constants
|
||||
from .....detections import device_probe
|
||||
|
||||
from .....datasets.os_data import os_data
|
||||
|
||||
|
||||
class IntelSkylake(BaseHardware):
|
||||
|
||||
def __init__(self, xnu_major, xnu_minor, os_build, global_constants: Constants) -> None:
|
||||
super().__init__(xnu_major, xnu_minor, os_build, global_constants)
|
||||
|
||||
|
||||
def name(self) -> str:
|
||||
"""
|
||||
Display name for end users
|
||||
"""
|
||||
return f"{self.hardware_variant()}: Intel Skylake"
|
||||
|
||||
|
||||
def present(self) -> bool:
|
||||
"""
|
||||
Targeting Intel Skylake GPUs
|
||||
"""
|
||||
return self._is_gpu_architecture_present(
|
||||
gpu_architectures=[
|
||||
device_probe.Intel.Archs.Skylake
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def native_os(self) -> bool:
|
||||
"""
|
||||
Dropped support with macOS 13, Ventura
|
||||
"""
|
||||
return self._xnu_major < os_data.ventura.value
|
||||
|
||||
|
||||
def hardware_variant(self) -> HardwareVariant:
|
||||
"""
|
||||
Type of hardware variant
|
||||
"""
|
||||
return HardwareVariant.GRAPHICS
|
||||
|
||||
|
||||
def hardware_variant_graphics_subclass(self) -> HardwareVariantGraphicsSubclass:
|
||||
"""
|
||||
Type of hardware variant subclass
|
||||
"""
|
||||
return HardwareVariantGraphicsSubclass.METAL_31001_GRAPHICS
|
||||
|
||||
|
||||
def _model_specific_patches(self) -> dict:
|
||||
"""
|
||||
Model specific patches
|
||||
"""
|
||||
return {
|
||||
"Intel Skylake": {
|
||||
PatchType.OVERWRITE_SYSTEM_VOLUME: {
|
||||
"/System/Library/Extensions": {
|
||||
"AppleIntelSKLGraphics.kext": self._resolve_monterey_framebuffers(),
|
||||
"AppleIntelSKLGraphicsFramebuffer.kext": self._resolve_monterey_framebuffers(),
|
||||
"AppleIntelSKLGraphicsGLDriver.bundle": "12.5",
|
||||
"AppleIntelSKLGraphicsMTLDriver.bundle": "12.5" if self._xnu_major < os_data.sequoia else "12.5-24",
|
||||
"AppleIntelSKLGraphicsVADriver.bundle": "12.5",
|
||||
"AppleIntelSKLGraphicsVAME.bundle": "12.5",
|
||||
"AppleIntelGraphicsShared.bundle": "12.5",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def patches(self) -> dict:
|
||||
"""
|
||||
Patches for Intel Skylake iGPUs
|
||||
"""
|
||||
if self.native_os() is True:
|
||||
return {}
|
||||
|
||||
return {
|
||||
**MontereyOpenCL(self._xnu_major, self._xnu_minor, self._constants.detected_os_version).patches(),
|
||||
**self._model_specific_patches(),
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
"""
|
||||
nvidia_kepler.py: Nvidia Kepler detection
|
||||
"""
|
||||
|
||||
from ..base import BaseHardware, HardwareVariant, HardwareVariantGraphicsSubclass
|
||||
|
||||
from ...base import PatchType
|
||||
|
||||
from ...shared_patches.metal_3802 import LegacyMetal3802
|
||||
from ...shared_patches.monterey_opencl import MontereyOpenCL
|
||||
from ...shared_patches.big_sur_opencl import BigSurOpenCL
|
||||
from ...shared_patches.monterey_webkit import MontereyWebKit
|
||||
|
||||
from .....constants import Constants
|
||||
from .....detections import device_probe
|
||||
|
||||
from .....datasets.os_data import os_data
|
||||
|
||||
|
||||
class NvidiaKepler(BaseHardware):
|
||||
|
||||
def __init__(self, xnu_major, xnu_minor, os_build, global_constants: Constants) -> None:
|
||||
super().__init__(xnu_major, xnu_minor, os_build, global_constants)
|
||||
|
||||
|
||||
def name(self) -> str:
|
||||
"""
|
||||
Display name for end users
|
||||
"""
|
||||
return f"{self.hardware_variant()}: Nvidia Kepler"
|
||||
|
||||
|
||||
def present(self) -> bool:
|
||||
"""
|
||||
Targeting Nvidia Kepler GPUs
|
||||
"""
|
||||
return self._is_gpu_architecture_present(
|
||||
gpu_architectures=[
|
||||
device_probe.NVIDIA.Archs.Kepler
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def native_os(self) -> bool:
|
||||
"""
|
||||
Dropped support with macOS 12.0 Beta 7, Monterey
|
||||
"""
|
||||
if self._xnu_major < os_data.monterey:
|
||||
return True
|
||||
|
||||
if self._xnu_major == os_data.monterey:
|
||||
if self._xnu_minor > 0:
|
||||
return True
|
||||
if self._os_build != "21A5522h": # 12.0 Beta 7
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def hardware_variant(self) -> HardwareVariant:
|
||||
"""
|
||||
Type of hardware variant
|
||||
"""
|
||||
return HardwareVariant.GRAPHICS
|
||||
|
||||
|
||||
def hardware_variant_graphics_subclass(self) -> HardwareVariantGraphicsSubclass:
|
||||
"""
|
||||
Type of hardware variant subclass
|
||||
"""
|
||||
return HardwareVariantGraphicsSubclass.METAL_3802_GRAPHICS
|
||||
|
||||
|
||||
def requires_metallib_support_pkg(self) -> bool:
|
||||
"""
|
||||
New compiler format introduced in macOS 15, Sequoia
|
||||
"""
|
||||
return self._xnu_major >= os_data.sequoia.value
|
||||
|
||||
|
||||
def _resolve_kepler_geforce_framebuffers(self) -> str:
|
||||
"""
|
||||
Resolve patchset directory for GeForce.kext
|
||||
"""
|
||||
if self._xnu_major < os_data.sonoma:
|
||||
return "12.0 Beta 6"
|
||||
if self._xnu_float < self.macOS_14_4:
|
||||
return "12.0 Beta 6-23"
|
||||
return "12.0 Beta 6-23.4"
|
||||
|
||||
|
||||
def _model_specific_patches(self) -> dict:
|
||||
"""
|
||||
Model specific patches
|
||||
"""
|
||||
return {
|
||||
"Nvidia Kepler": {
|
||||
PatchType.OVERWRITE_SYSTEM_VOLUME: {
|
||||
"/System/Library/Extensions": {
|
||||
"GeForce.kext": self._resolve_kepler_geforce_framebuffers(),
|
||||
"NVDAGF100Hal.kext": "12.0 Beta 6",
|
||||
"NVDAGK100Hal.kext": "12.0 Beta 6",
|
||||
"NVDAResman.kext": "12.0 Beta 6",
|
||||
"NVDAStartup.kext": "12.0 Beta 6",
|
||||
"GeForceAIRPlugin.bundle": "11.0 Beta 3",
|
||||
"GeForceGLDriver.bundle": "11.0 Beta 3",
|
||||
"GeForceMTLDriver.bundle": "11.0 Beta 3" if self._xnu_major <= os_data.monterey else f"11.0 Beta 3-22",
|
||||
"GeForceVADriver.bundle": "12.0 Beta 6",
|
||||
},
|
||||
},
|
||||
PatchType.MERGE_SYSTEM_VOLUME: {
|
||||
"/System/Library/Frameworks": {
|
||||
# XNU 21.6 (macOS 12.5)
|
||||
**({ "Metal.framework": "12.5 Beta 2"} if (self._xnu_float >= self.macOS_12_5 and self._xnu_major < os_data.ventura) else {}),
|
||||
},
|
||||
"/System/Library/PrivateFrameworks": {
|
||||
"GPUCompiler.framework": "11.6",
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def patches(self) -> dict:
|
||||
"""
|
||||
Patches for Nvidia Kepler GPUs
|
||||
"""
|
||||
if self.native_os() is True:
|
||||
return {}
|
||||
|
||||
return {
|
||||
**LegacyMetal3802(self._xnu_major, self._xnu_minor, self._constants.detected_os_version).patches(),
|
||||
**MontereyOpenCL(self._xnu_major, self._xnu_minor, self._constants.detected_os_version).patches(),
|
||||
**BigSurOpenCL(self._xnu_major, self._xnu_minor, self._constants.detected_os_version).patches(),
|
||||
**MontereyWebKit(self._xnu_major, self._xnu_minor, self._os_build).patches(),
|
||||
**self._model_specific_patches(),
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
"""
|
||||
nvidia_tesla.py: Nvidia Tesla detection
|
||||
"""
|
||||
|
||||
from ..base import BaseHardware, HardwareVariant, HardwareVariantGraphicsSubclass
|
||||
|
||||
from ...base import PatchType
|
||||
|
||||
from ...shared_patches.non_metal import NonMetal
|
||||
from ...shared_patches.monterey_webkit import MontereyWebKit
|
||||
|
||||
from .....constants import Constants
|
||||
from .....detections import device_probe
|
||||
|
||||
from .....datasets.os_data import os_data
|
||||
|
||||
|
||||
class NvidiaTesla(BaseHardware):
|
||||
|
||||
def __init__(self, xnu_major, xnu_minor, os_build, global_constants: Constants) -> None:
|
||||
super().__init__(xnu_major, xnu_minor, os_build, global_constants)
|
||||
|
||||
|
||||
def name(self) -> str:
|
||||
"""
|
||||
Display name for end users
|
||||
"""
|
||||
return f"{self.hardware_variant()}: Nvidia Tesla"
|
||||
|
||||
|
||||
def present(self) -> bool:
|
||||
"""
|
||||
Targeting Nvidia Tesla GPUs
|
||||
"""
|
||||
return self._is_gpu_architecture_present(
|
||||
gpu_architectures=[
|
||||
device_probe.NVIDIA.Archs.Tesla
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def native_os(self) -> bool:
|
||||
"""
|
||||
Dropped support with macOS 10.14, Mojave
|
||||
"""
|
||||
return self._xnu_major < os_data.ventura.value
|
||||
|
||||
|
||||
def hardware_variant(self) -> HardwareVariant:
|
||||
"""
|
||||
Type of hardware variant
|
||||
"""
|
||||
return HardwareVariant.GRAPHICS
|
||||
|
||||
|
||||
def hardware_variant_graphics_subclass(self) -> HardwareVariantGraphicsSubclass:
|
||||
"""
|
||||
Type of hardware variant subclass
|
||||
"""
|
||||
return HardwareVariantGraphicsSubclass.NON_METAL_GRAPHICS
|
||||
|
||||
|
||||
def requires_kernel_debug_kit(self) -> bool:
|
||||
"""
|
||||
Apple no longer provides standalone kexts in the base OS
|
||||
"""
|
||||
return self._xnu_major >= os_data.ventura.value
|
||||
|
||||
|
||||
def _model_specific_patches(self) -> dict:
|
||||
"""
|
||||
Model specific patches
|
||||
"""
|
||||
return {
|
||||
"Nvidia Tesla": {
|
||||
PatchType.OVERWRITE_SYSTEM_VOLUME: {
|
||||
"/System/Library/Extensions": {
|
||||
"GeForceGA.bundle": "10.13.6",
|
||||
"GeForceTesla.kext": "10.13.6",
|
||||
"GeForceTeslaGLDriver.bundle": "10.13.6",
|
||||
"GeForceTeslaVADriver.bundle": "10.13.6",
|
||||
"NVDANV50HalTesla.kext": "10.13.6",
|
||||
"NVDAResmanTesla.kext": "10.13.6",
|
||||
# Apple dropped NVDAStartup in 12.0 Beta 7 (XNU 21.1)
|
||||
**({ "NVDAStartup.kext": "12.0 Beta 6" } if self._xnu_float >= self.macOS_12_0_B7 else {})
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def patches(self) -> dict:
|
||||
"""
|
||||
Patches for Nvidia Tesla GPUs
|
||||
"""
|
||||
if self.native_os() is True:
|
||||
return {}
|
||||
|
||||
if self._xnu_major not in self._constants.legacy_accel_support and self._dortania_internal_check() is False:
|
||||
return {**self._model_specific_patches()}
|
||||
|
||||
return {
|
||||
**NonMetal(self._xnu_major, self._xnu_minor, self._os_build).patches(),
|
||||
**MontereyWebKit(self._xnu_major, self._xnu_minor, self._os_build).patches(),
|
||||
**self._model_specific_patches(),
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
"""
|
||||
nvidia_webdriver.py: Nvidia Web Driver detection
|
||||
"""
|
||||
|
||||
from ..base import BaseHardware, HardwareVariant, HardwareVariantGraphicsSubclass
|
||||
|
||||
from ...base import PatchType
|
||||
|
||||
from ...shared_patches.non_metal import NonMetal
|
||||
from ...shared_patches.monterey_webkit import MontereyWebKit
|
||||
from ...shared_patches.non_metal_ioaccel import NonMetalIOAccelerator
|
||||
from ...shared_patches.non_metal_coredisplay import NonMetalCoreDisplay
|
||||
from ...shared_patches.non_metal_enforcement import NonMetalEnforcement
|
||||
|
||||
from .....constants import Constants
|
||||
from .....detections import device_probe
|
||||
|
||||
from .....datasets.os_data import os_data
|
||||
from .....datasets.sip_data import system_integrity_protection
|
||||
|
||||
|
||||
class NvidiaWebDriver(BaseHardware):
|
||||
|
||||
def __init__(self, xnu_major, xnu_minor, os_build, global_constants: Constants) -> None:
|
||||
super().__init__(xnu_major, xnu_minor, os_build, global_constants)
|
||||
|
||||
|
||||
def name(self) -> str:
|
||||
"""
|
||||
Display name for end users
|
||||
"""
|
||||
return f"{self.hardware_variant()}: Nvidia Web Drivers"
|
||||
|
||||
|
||||
def present(self) -> bool:
|
||||
"""
|
||||
Targeting Nvidia Fermi, Maxwell, Pascal GPUs
|
||||
"""
|
||||
return self._is_gpu_architecture_present(
|
||||
gpu_architectures=[
|
||||
device_probe.NVIDIA.Archs.Fermi,
|
||||
device_probe.NVIDIA.Archs.Maxwell,
|
||||
device_probe.NVIDIA.Archs.Pascal,
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def native_os(self) -> bool:
|
||||
"""
|
||||
Dropped support with macOS 10.14, Mojave
|
||||
"""
|
||||
return self._xnu_major < os_data.mojave.value
|
||||
|
||||
|
||||
def hardware_variant(self) -> HardwareVariant:
|
||||
"""
|
||||
Type of hardware variant
|
||||
"""
|
||||
return HardwareVariant.GRAPHICS
|
||||
|
||||
|
||||
def hardware_variant_graphics_subclass(self) -> HardwareVariantGraphicsSubclass:
|
||||
"""
|
||||
Type of hardware variant subclass
|
||||
"""
|
||||
return HardwareVariantGraphicsSubclass.NON_METAL_GRAPHICS
|
||||
|
||||
|
||||
def requires_kernel_debug_kit(self) -> bool:
|
||||
"""
|
||||
Apple no longer provides standalone kexts in the base OS
|
||||
"""
|
||||
return self._xnu_major >= os_data.ventura.value
|
||||
|
||||
|
||||
def required_system_integrity_protection_configurations(self) -> list[str]:
|
||||
"""
|
||||
List of required SIP configurations for the patch set
|
||||
"""
|
||||
return system_integrity_protection.root_patch_sip_big_sur_3rd_part_kexts
|
||||
|
||||
|
||||
def _model_specific_patches(self) -> dict:
|
||||
"""
|
||||
Model specific patches
|
||||
"""
|
||||
return {
|
||||
"Nvidia Web Drivers": {
|
||||
PatchType.OVERWRITE_SYSTEM_VOLUME: {
|
||||
"/System/Library/Extensions": {
|
||||
"GeForceAIRPluginWeb.bundle": "WebDriver-387.10.10.10.40.140",
|
||||
"GeForceGLDriverWeb.bundle": "WebDriver-387.10.10.10.40.140",
|
||||
"GeForceMTLDriverWeb.bundle": "WebDriver-387.10.10.10.40.140",
|
||||
"GeForceVADriverWeb.bundle": "WebDriver-387.10.10.10.40.140",
|
||||
|
||||
# Tesla-only files
|
||||
"GeForceTeslaGAWeb.bundle": "WebDriver-387.10.10.10.40.140",
|
||||
"GeForceTeslaGLDriverWeb.bundle": "WebDriver-387.10.10.10.40.140",
|
||||
"GeForceTeslaVADriverWeb.bundle": "WebDriver-387.10.10.10.40.140",
|
||||
},
|
||||
},
|
||||
PatchType.OVERWRITE_DATA_VOLUME: {
|
||||
"/Library/Extensions": {
|
||||
"GeForceWeb.kext": "WebDriver-387.10.10.10.40.140",
|
||||
"NVDAGF100HalWeb.kext": "WebDriver-387.10.10.10.40.140",
|
||||
"NVDAGK100HalWeb.kext": "WebDriver-387.10.10.10.40.140",
|
||||
"NVDAGM100HalWeb.kext": "WebDriver-387.10.10.10.40.140",
|
||||
"NVDAGP100HalWeb.kext": "WebDriver-387.10.10.10.40.140",
|
||||
"NVDAResmanWeb.kext": "WebDriver-387.10.10.10.40.140",
|
||||
"NVDAStartupWeb.kext": "WebDriver-387.10.10.10.40.140",
|
||||
|
||||
# Tesla-only files
|
||||
"GeForceTeslaWeb.kext": "WebDriver-387.10.10.10.40.140",
|
||||
"NVDANV50HalTeslaWeb.kext": "WebDriver-387.10.10.10.40.140",
|
||||
"NVDAResmanTeslaWeb.kext": "WebDriver-387.10.10.10.40.140",
|
||||
},
|
||||
|
||||
# Disabled due to issues with Pref pane stripping 'nvda_drv' NVRAM
|
||||
# variables
|
||||
# "/Library/PreferencePanes": {
|
||||
# "NVIDIA Driver Manager.prefPane": "WebDriver-387.10.10.10.40.140",
|
||||
# },
|
||||
# "/Library/LaunchAgents": {
|
||||
# "com.nvidia.nvagent.plist": "WebDriver-387.10.10.10.40.140",
|
||||
# },
|
||||
# "/Library/LaunchDaemons": {
|
||||
# "com.nvidia.nvroothelper.plist": "WebDriver-387.10.10.10.40.140",
|
||||
# },
|
||||
},
|
||||
PatchType.MERGE_SYSTEM_VOLUME: {
|
||||
"/System/Library/PrivateFrameworks": {
|
||||
# Restore OpenCL by adding missing compiler files
|
||||
**({ "GPUCompiler.framework": "11.6"} if self._xnu_major >= os_data.monterey else {}),
|
||||
},
|
||||
},
|
||||
PatchType.REMOVE_SYSTEM_VOLUME: {
|
||||
"/System/Library/Extensions": [
|
||||
# Due to how late the Auxiliary cache loads, NVDAStartup will match first and then the Web Driver kexts.
|
||||
# This has no effect for Maxwell and Pascal, however for development purposes, Tesla and Kepler are partially supported.
|
||||
"NVDAStartup.kext",
|
||||
],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def patches(self) -> dict:
|
||||
"""
|
||||
Patches for Nvidia Web Drivers
|
||||
"""
|
||||
if self.native_os() is True:
|
||||
return {}
|
||||
|
||||
if self._xnu_major not in self._constants.legacy_accel_support and self._dortania_internal_check() is False:
|
||||
return {**self._model_specific_patches()}
|
||||
|
||||
return {
|
||||
**NonMetal(self._xnu_major, self._xnu_minor, self._os_build).patches(),
|
||||
**NonMetalIOAccelerator(self._xnu_major, self._xnu_minor, self._os_build).patches(),
|
||||
**NonMetalCoreDisplay(self._xnu_major, self._xnu_minor, self._os_build).patches(),
|
||||
**MontereyWebKit(self._xnu_major, self._xnu_minor, self._os_build).patches(),
|
||||
**self._model_specific_patches(),
|
||||
**NonMetalEnforcement(self._xnu_major, self._xnu_minor, self._os_build).patches(),
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
"""
|
||||
display_backlight.py: Legacy Backlight Control detection
|
||||
"""
|
||||
|
||||
from ..base import BaseHardware, HardwareVariant
|
||||
|
||||
from ...base import PatchType
|
||||
|
||||
from .....constants import Constants
|
||||
|
||||
from .....datasets.os_data import os_data
|
||||
|
||||
|
||||
class DisplayBacklight(BaseHardware):
|
||||
|
||||
def __init__(self, xnu_major, xnu_minor, os_build, global_constants: Constants) -> None:
|
||||
super().__init__(xnu_major, xnu_minor, os_build, global_constants)
|
||||
|
||||
|
||||
def name(self) -> str:
|
||||
"""
|
||||
Display name for end users
|
||||
"""
|
||||
return f"{self.hardware_variant()}: Legacy Backlight Control"
|
||||
|
||||
|
||||
def present(self) -> bool:
|
||||
"""
|
||||
Targeting Legacy Backlight Controllers
|
||||
"""
|
||||
return self._computer.real_model in [
|
||||
"MacBook5,2",
|
||||
"iMac7,1",
|
||||
"iMac8,1",
|
||||
"iMac9,1",
|
||||
]
|
||||
|
||||
|
||||
def native_os(self) -> bool:
|
||||
"""
|
||||
Dropped support with macOS 10.13, High Sierra
|
||||
"""
|
||||
return self._xnu_major < os_data.high_sierra.value
|
||||
|
||||
|
||||
def hardware_variant(self) -> HardwareVariant:
|
||||
"""
|
||||
Type of hardware variant
|
||||
"""
|
||||
return HardwareVariant.MISCELLANEOUS
|
||||
|
||||
|
||||
def requires_kernel_debug_kit(self) -> bool:
|
||||
"""
|
||||
Apple no longer provides standalone kexts in the base OS
|
||||
"""
|
||||
return self._xnu_major >= os_data.ventura.value
|
||||
|
||||
|
||||
def patches(self) -> dict:
|
||||
"""
|
||||
Patches for Legacy Backlight Control
|
||||
"""
|
||||
if self.native_os() is True:
|
||||
return {}
|
||||
|
||||
return {
|
||||
"Legacy Backlight Control": {
|
||||
PatchType.OVERWRITE_SYSTEM_VOLUME: {
|
||||
"/System/Library/Extensions": {
|
||||
"AppleBacklight.kext": "10.12.6",
|
||||
"AppleBacklightExpert.kext": "10.12.6",
|
||||
},
|
||||
},
|
||||
PatchType.MERGE_SYSTEM_VOLUME: {
|
||||
"/System/Library/PrivateFrameworks": {
|
||||
"DisplayServices.framework": "10.12.6",
|
||||
},
|
||||
},
|
||||
PatchType.REMOVE_SYSTEM_VOLUME: {
|
||||
"/System/Library/Extensions/AppleGraphicsControl.kext/Contents/PlugIns": [
|
||||
"AGDCBacklightControl.kext",
|
||||
],
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
"""
|
||||
gmux.py: Legacy GMUX detection
|
||||
"""
|
||||
|
||||
from ..base import BaseHardware, HardwareVariant
|
||||
|
||||
from ...base import PatchType
|
||||
|
||||
from .....constants import Constants
|
||||
from .....support import utilities
|
||||
|
||||
from .....datasets.os_data import os_data
|
||||
|
||||
|
||||
class GraphicsMultiplexer(BaseHardware):
|
||||
|
||||
def __init__(self, xnu_major, xnu_minor, os_build, global_constants: Constants) -> None:
|
||||
super().__init__(xnu_major, xnu_minor, os_build, global_constants)
|
||||
|
||||
|
||||
def name(self) -> str:
|
||||
"""
|
||||
Display name for end users
|
||||
"""
|
||||
return f"{self.hardware_variant()}: Legacy GMUX"
|
||||
|
||||
|
||||
def _check_dgpu_status(self) -> bool:
|
||||
"""
|
||||
Query whether system has an active dGPU
|
||||
"""
|
||||
dgpu = self._computer.dgpu
|
||||
if dgpu:
|
||||
if dgpu.class_code and dgpu.class_code == 0xFFFFFFFF:
|
||||
# If dGPU is disabled via class-codes, assume demuxed
|
||||
return False
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _detect_demux(self) -> bool:
|
||||
"""
|
||||
Query whether system has been demuxed (ex. MacBookPro8,2, disabled dGPU)
|
||||
"""
|
||||
# If GFX0 is missing, assume machine was demuxed
|
||||
# -wegnoegpu would also trigger this, so ensure arg is not present
|
||||
if not "-wegnoegpu" in (utilities.get_nvram("boot-args", decode=True) or ""):
|
||||
igpu = self._constants.computer.igpu
|
||||
dgpu = self._check_dgpu_status()
|
||||
if igpu and not dgpu:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def present(self) -> bool:
|
||||
"""
|
||||
Targeting Legacy GMUX Controllers
|
||||
Ref: https://doslabelectronics.com/Demux.html
|
||||
|
||||
Sierra uses a legacy GMUX control method needed for dGPU switching on MacBookPro5,x
|
||||
Same method is also used for demuxed machines
|
||||
Note that MacBookPro5,x machines are extremely unstable with this patch set, so disabled until investigated further
|
||||
Ref: https://github.com/dortania/OpenCore-Legacy-Patcher/files/7360909/KP-b10-030.txt
|
||||
"""
|
||||
return self._computer.real_model in ["MacBookPro8,2", "MacBookPro8,3"] and self._detect_demux()
|
||||
|
||||
|
||||
def native_os(self) -> bool:
|
||||
"""
|
||||
Dropped support with macOS 10.13, High Sierra
|
||||
"""
|
||||
return self._xnu_major < os_data.sierra.value
|
||||
|
||||
|
||||
def hardware_variant(self) -> HardwareVariant:
|
||||
"""
|
||||
Type of hardware variant
|
||||
"""
|
||||
return HardwareVariant.MISCELLANEOUS
|
||||
|
||||
|
||||
def requires_kernel_debug_kit(self) -> bool:
|
||||
"""
|
||||
Apple no longer provides standalone kexts in the base OS
|
||||
"""
|
||||
return self._xnu_major >= os_data.ventura.value
|
||||
|
||||
|
||||
def patches(self) -> dict:
|
||||
"""
|
||||
Patches for Legacy GMUX Controllers
|
||||
"""
|
||||
if self.native_os() is True:
|
||||
return {}
|
||||
|
||||
if self._xnu_major not in self._constants.legacy_accel_support:
|
||||
return {}
|
||||
|
||||
return {
|
||||
"Legacy GMUX": {
|
||||
PatchType.OVERWRITE_SYSTEM_VOLUME: {
|
||||
"/System/Library/Extensions/AppleGraphicsControl.kext/Contents/PlugIns": {
|
||||
"AppleMuxControl.kext": "10.12.6",
|
||||
},
|
||||
},
|
||||
PatchType.REMOVE_SYSTEM_VOLUME: {
|
||||
"/System/Library/Extensions": [
|
||||
"AppleBacklight.kext",
|
||||
],
|
||||
"/System/Library/Extensions/AppleGraphicsControl.kext/Contents/PlugIns": [
|
||||
"AGDCBacklightControl.kext",
|
||||
"AppleMuxControl.kext",
|
||||
],
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
"""
|
||||
keyboard_backlight.py: Legacy Keyboard Backlight detection
|
||||
"""
|
||||
|
||||
from ..base import BaseHardware, HardwareVariant
|
||||
|
||||
from ...base import PatchType
|
||||
|
||||
from .....constants import Constants
|
||||
from .....detections import device_probe
|
||||
|
||||
from .....datasets.os_data import os_data
|
||||
|
||||
|
||||
class KeyboardBacklight(BaseHardware):
|
||||
|
||||
def __init__(self, xnu_major, xnu_minor, os_build, global_constants: Constants) -> None:
|
||||
super().__init__(xnu_major, xnu_minor, os_build, global_constants)
|
||||
|
||||
|
||||
def name(self) -> str:
|
||||
"""
|
||||
Display name for end users
|
||||
"""
|
||||
return f"{self.hardware_variant()}: Legacy Keyboard Backlight"
|
||||
|
||||
|
||||
def present(self) -> bool:
|
||||
"""
|
||||
Targeting Legacy Keyboard Backlight (ie. non-Metal Macs)
|
||||
"""
|
||||
return self._computer.real_model.startswith("MacBook") and self._is_gpu_architecture_present(
|
||||
gpu_architectures=[
|
||||
device_probe.Intel.Archs.Iron_Lake,
|
||||
device_probe.Intel.Archs.Sandy_Bridge,
|
||||
device_probe.AMD.Archs.TeraScale_1,
|
||||
device_probe.AMD.Archs.TeraScale_2,
|
||||
device_probe.NVIDIA.Archs.Tesla,
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def native_os(self) -> bool:
|
||||
"""
|
||||
Dropped support with macOS 11, Big Sur
|
||||
"""
|
||||
return self._xnu_major < os_data.big_sur.value
|
||||
|
||||
|
||||
def hardware_variant(self) -> HardwareVariant:
|
||||
"""
|
||||
Type of hardware variant
|
||||
"""
|
||||
return HardwareVariant.MISCELLANEOUS
|
||||
|
||||
|
||||
def requires_kernel_debug_kit(self) -> bool:
|
||||
"""
|
||||
Apple no longer provides standalone kexts in the base OS
|
||||
"""
|
||||
return self._xnu_major >= os_data.ventura.value
|
||||
|
||||
|
||||
def patches(self) -> dict:
|
||||
"""
|
||||
Patches for Legacy Keyboard Backlight
|
||||
"""
|
||||
if self.native_os() is True:
|
||||
return {}
|
||||
|
||||
if self._xnu_major not in self._constants.legacy_accel_support:
|
||||
return {}
|
||||
|
||||
return {
|
||||
"Legacy Keyboard Backlight": {
|
||||
PatchType.EXECUTE: {
|
||||
"/usr/bin/defaults write /Library/Preferences/.GlobalPreferences.plist Moraea_BacklightHack -bool true": True,
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
"""
|
||||
legacy_audio.py: Legacy Audio detection
|
||||
"""
|
||||
|
||||
from ..base import BaseHardware, HardwareVariant
|
||||
|
||||
from ...base import PatchType
|
||||
|
||||
from .....constants import Constants
|
||||
from .....support import utilities
|
||||
|
||||
from .....datasets.os_data import os_data
|
||||
|
||||
|
||||
class LegacyAudio(BaseHardware):
|
||||
|
||||
def __init__(self, xnu_major, xnu_minor, os_build, global_constants: Constants) -> None:
|
||||
super().__init__(xnu_major, xnu_minor, os_build, global_constants)
|
||||
|
||||
|
||||
def name(self) -> str:
|
||||
"""
|
||||
Display name for end users
|
||||
"""
|
||||
return f"{self.hardware_variant()}: Legacy Audio"
|
||||
|
||||
|
||||
def present(self) -> bool:
|
||||
"""
|
||||
Targeting Realtek Audio and machines without AppleALC
|
||||
"""
|
||||
return self._computer.real_model in ["iMac7,1", "iMac8,1"] or (
|
||||
self._computer.real_model in ["MacBook5,1",
|
||||
"MacBook5,2",
|
||||
"MacBook6,1",
|
||||
"MacBook7,1",
|
||||
"MacBookAir2,1",
|
||||
"MacBookAir3,1",
|
||||
"MacBookAir3,2",
|
||||
"MacBookAir4,1",
|
||||
"MacBookAir4,2",
|
||||
"MacBookPro4,1",
|
||||
"MacBookPro5,1",
|
||||
"MacBookPro5,2",
|
||||
"MacBookPro5,3",
|
||||
"MacBookPro5,4",
|
||||
"MacBookPro5,5",
|
||||
"MacBookPro6,1",
|
||||
"MacBookPro6,2",
|
||||
"MacBookPro7,1",
|
||||
"MacBookPro8,1",
|
||||
"MacBookPro8,2",
|
||||
"MacBookPro8,3",
|
||||
"Macmini3,1",
|
||||
"Macmini4,1",
|
||||
"Macmini5,1",
|
||||
"Macmini5,2",
|
||||
"Macmini5,3",
|
||||
"iMac9,1",
|
||||
"iMac10,1",
|
||||
"iMac11,1",
|
||||
"iMac11,2",
|
||||
"iMac11,3",
|
||||
"iMac12,1",
|
||||
"iMac12,2",
|
||||
"MacPro3,1"
|
||||
] and utilities.check_kext_loaded("as.vit9696.AppleALC") is False)
|
||||
|
||||
|
||||
def native_os(self) -> bool:
|
||||
"""
|
||||
- iMac7,1 and iMac8,1 last supported in macOS 10.11, El Capitan
|
||||
- All other models pre-2012 models last supported in macOS 10.13, High Sierra
|
||||
"""
|
||||
if self._computer.real_model in ["iMac7,1", "iMac8,1"]:
|
||||
return self._xnu_major < os_data.sierra.value
|
||||
return self._xnu_major < os_data.mojave.value
|
||||
|
||||
|
||||
def hardware_variant(self) -> HardwareVariant:
|
||||
"""
|
||||
Type of hardware variant
|
||||
"""
|
||||
return HardwareVariant.MISCELLANEOUS
|
||||
|
||||
|
||||
def _missing_gop_patches(self) -> dict:
|
||||
"""
|
||||
Patches for graphics cards with missing GOP (ie. breaking AppleALC functionality)
|
||||
"""
|
||||
return {
|
||||
"Legacy Non-GOP": {
|
||||
PatchType.OVERWRITE_SYSTEM_VOLUME: {
|
||||
"/System/Library/Extensions": {
|
||||
"AppleHDA.kext": "10.13.6",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def _realtek_audio_patches(self) -> dict:
|
||||
"""
|
||||
Patches for Realtek Audio
|
||||
"""
|
||||
return {
|
||||
"Legacy Realtek": {
|
||||
PatchType.OVERWRITE_SYSTEM_VOLUME: {
|
||||
"/System/Library/Extensions": {
|
||||
"AppleHDA.kext": "10.11.6",
|
||||
"IOAudioFamily.kext": "10.11.6",
|
||||
},
|
||||
},
|
||||
PatchType.REMOVE_SYSTEM_VOLUME: {
|
||||
"/System/Library/Extensions": [
|
||||
"AppleVirtIO.kext",
|
||||
"AppleVirtualGraphics.kext",
|
||||
"AppleVirtualPlatform.kext",
|
||||
"ApplePVPanic.kext",
|
||||
"AppleVirtIOStorage.kext",
|
||||
],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def patches(self) -> dict:
|
||||
"""
|
||||
Patches for legacy audio
|
||||
"""
|
||||
if self.native_os() is True:
|
||||
return {}
|
||||
|
||||
if self._computer.real_model in ["iMac7,1", "iMac8,1"]:
|
||||
return self._realtek_audio_patches()
|
||||
return self._missing_gop_patches()
|
||||
@@ -0,0 +1,66 @@
|
||||
"""
|
||||
pci_webcam.py: PCIe FaceTime Camera detection
|
||||
"""
|
||||
|
||||
from ..base import BaseHardware, HardwareVariant
|
||||
|
||||
from ...base import PatchType
|
||||
|
||||
from .....constants import Constants
|
||||
|
||||
from .....datasets.os_data import os_data
|
||||
|
||||
|
||||
class PCIeFaceTimeCamera(BaseHardware):
|
||||
|
||||
def __init__(self, xnu_major, xnu_minor, os_build, global_constants: Constants) -> None:
|
||||
super().__init__(xnu_major, xnu_minor, os_build, global_constants)
|
||||
|
||||
|
||||
def name(self) -> str:
|
||||
"""
|
||||
Display name for end users
|
||||
"""
|
||||
return f"{self.hardware_variant()}: PCIe FaceTime Camera"
|
||||
|
||||
|
||||
def present(self) -> bool:
|
||||
"""
|
||||
Targeting PCIe FaceTime Cameras
|
||||
"""
|
||||
return self._computer.pcie_webcam
|
||||
|
||||
|
||||
def native_os(self) -> bool:
|
||||
"""
|
||||
Dropped support with macOS 14 Developer Beta 1 (23A5257q)
|
||||
"""
|
||||
return self._xnu_major < os_data.sonoma.value or self._os_build == "23A5257q"
|
||||
|
||||
|
||||
def hardware_variant(self) -> HardwareVariant:
|
||||
"""
|
||||
Type of hardware variant
|
||||
"""
|
||||
return HardwareVariant.MISCELLANEOUS
|
||||
|
||||
|
||||
def patches(self) -> dict:
|
||||
"""
|
||||
Patches for PCIe FaceTime Camera
|
||||
"""
|
||||
if self.native_os() is True:
|
||||
return {}
|
||||
|
||||
return {
|
||||
"PCIe FaceTime Camera": {
|
||||
PatchType.OVERWRITE_SYSTEM_VOLUME: {
|
||||
"/System/Library/Frameworks/CoreMediaIO.framework/Versions/A/Resources": {
|
||||
"AppleCamera.plugin": "14.0 Beta 1"
|
||||
},
|
||||
"/System/Library/LaunchDaemons": {
|
||||
"com.apple.cmio.AppleCameraAssistant.plist": "14.0 Beta 1"
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
"""
|
||||
t1_security.py: T1 Security Chip detection
|
||||
"""
|
||||
|
||||
from ..base import BaseHardware, HardwareVariant
|
||||
|
||||
from ...base import PatchType
|
||||
|
||||
from .....constants import Constants
|
||||
|
||||
from .....datasets.os_data import os_data
|
||||
|
||||
|
||||
class T1SecurityChip(BaseHardware):
|
||||
|
||||
def __init__(self, xnu_major, xnu_minor, os_build, global_constants: Constants) -> None:
|
||||
super().__init__(xnu_major, xnu_minor, os_build, global_constants)
|
||||
|
||||
|
||||
def name(self) -> str:
|
||||
"""
|
||||
Display name for end users
|
||||
"""
|
||||
return f"{self.hardware_variant()}: T1 Security Chip"
|
||||
|
||||
|
||||
def present(self) -> bool:
|
||||
"""
|
||||
Targeting T1 Security Chip
|
||||
"""
|
||||
return self._computer.t1_chip
|
||||
|
||||
|
||||
def native_os(self) -> bool:
|
||||
"""
|
||||
Dropped support with macOS 14, Sonoma
|
||||
"""
|
||||
return self._xnu_major < os_data.sonoma.value
|
||||
|
||||
|
||||
def hardware_variant(self) -> HardwareVariant:
|
||||
"""
|
||||
Type of hardware variant
|
||||
"""
|
||||
return HardwareVariant.MISCELLANEOUS
|
||||
|
||||
|
||||
def patches(self) -> dict:
|
||||
"""
|
||||
Patches for T1 Security Chip
|
||||
"""
|
||||
if self.native_os() is True:
|
||||
return {}
|
||||
|
||||
return {
|
||||
"T1 Security Chip": {
|
||||
PatchType.OVERWRITE_SYSTEM_VOLUME: {
|
||||
# Required for Apple Pay
|
||||
"/usr/lib": {
|
||||
"libNFC_Comet.dylib": "13.6",
|
||||
"libNFC_HAL.dylib": "13.6",
|
||||
|
||||
"libnfshared.dylib": "13.6",
|
||||
"libnfshared.dylibOld.dylib": "13.6",
|
||||
"libnfstorage.dylib": "13.6",
|
||||
"libnfrestore.dylib": "13.6",
|
||||
|
||||
"libPN548_API.dylib": "13.6"
|
||||
},
|
||||
"/usr/libexec": {
|
||||
"biometrickitd": "13.6", # Required for Touch ID
|
||||
"nfcd": "13.6", # Required for Apple Pay
|
||||
"nfrestore_service": "13.6", # Required for Apple Pay
|
||||
},
|
||||
"/usr/standalone/firmware/nfrestore/firmware/fw": {
|
||||
"PN549_FW_02_01_5A_rev88207.bin": "13.6",
|
||||
"SN100V_FW_A3_01_01_81_rev127208.bin": "13.6",
|
||||
"SN200V_FW_B1_02_01_86_rev127266.bin": "13.6",
|
||||
"SN300V_FW_B0_02_01_22_rev129172.bin": "13.6",
|
||||
}
|
||||
},
|
||||
PatchType.MERGE_SYSTEM_VOLUME: {
|
||||
"/System/Library/Frameworks/LocalAuthentication.framework/Support": {
|
||||
"SharedUtils.framework": f"13.6-{self._xnu_major}", # Required for Password Authentication (SharedUtils.framework)
|
||||
**({ "MechanismPlugins": "15.0 Beta 4" } if self._xnu_major >= os_data.sequoia else {}), # Required to add a TouchID fingerprint
|
||||
},
|
||||
"/System/Library/PrivateFrameworks": {
|
||||
"EmbeddedOSInstall.framework": "13.6", # Required for biometrickitd
|
||||
**({ "NearField.framework": "14.5" } if self._xnu_major >= os_data.sequoia else {}),
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
|
||||
|
||||
"""
|
||||
usb11.py: Legacy USB 1.1 Controller detection
|
||||
"""
|
||||
|
||||
from ..base import BaseHardware, HardwareVariant
|
||||
|
||||
from ...base import PatchType
|
||||
|
||||
from .....constants import Constants
|
||||
from .....detections import device_probe
|
||||
|
||||
from .....datasets.os_data import os_data
|
||||
from .....datasets import smbios_data, cpu_data
|
||||
|
||||
|
||||
class USB11Controller(BaseHardware):
|
||||
|
||||
def __init__(self, xnu_major, xnu_minor, os_build, global_constants: Constants) -> None:
|
||||
super().__init__(xnu_major, xnu_minor, os_build, global_constants)
|
||||
|
||||
|
||||
def name(self) -> str:
|
||||
"""
|
||||
Display name for end users
|
||||
"""
|
||||
return f"{self.hardware_variant()}: Legacy USB 1.1"
|
||||
|
||||
|
||||
def present(self) -> bool:
|
||||
"""
|
||||
Targeting UHCI/OHCI controllers
|
||||
"""
|
||||
# If we're on a hackintosh, check for UHCI/OHCI controllers
|
||||
if self._constants.host_is_hackintosh is True:
|
||||
for controller in self._computer.usb_controllers:
|
||||
if (
|
||||
isinstance(controller, device_probe.UHCIController) or
|
||||
isinstance(controller, device_probe.OHCIController)
|
||||
):
|
||||
return True
|
||||
return False
|
||||
|
||||
if self._computer.real_model not in smbios_data.smbios_dictionary:
|
||||
return False
|
||||
|
||||
# If we're on a Mac, check for Penryn or older
|
||||
# This is due to Apple implementing an internal USB hub on post-Penryn (excluding MacPro4,1, MacPro5,1 and Xserve3,1)
|
||||
# Ref: https://techcommunity.microsoft.com/t5/microsoft-usb-blog/reasons-to-avoid-companion-controllers/ba-p/270710
|
||||
if (
|
||||
smbios_data.smbios_dictionary[self._computer.real_model]["CPU Generation"] <= cpu_data.CPUGen.penryn.value or \
|
||||
self._computer.real_model in ["MacPro4,1", "MacPro5,1", "Xserve3,1"]
|
||||
):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def native_os(self) -> bool:
|
||||
"""
|
||||
Dropped support with macOS 13, Ventura
|
||||
"""
|
||||
return self._xnu_major < os_data.ventura.value
|
||||
|
||||
|
||||
def hardware_variant(self) -> HardwareVariant:
|
||||
"""
|
||||
Type of hardware variant
|
||||
"""
|
||||
return HardwareVariant.MISCELLANEOUS
|
||||
|
||||
|
||||
def _base_patches(self) -> dict:
|
||||
"""
|
||||
Base patches for USB 1.1 Controller
|
||||
"""
|
||||
return {
|
||||
"Legacy USB 1.1": {
|
||||
PatchType.OVERWRITE_SYSTEM_VOLUME: {
|
||||
"/System/Library/Extensions": {
|
||||
"IOUSBHostFamily.kext": "12.6.2" if self._xnu_float < self.macOS_14_4 else "12.6.2-23.4",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def _extended_patches(self) -> dict:
|
||||
"""
|
||||
Extended patches for USB 1.1 Controller
|
||||
"""
|
||||
if self._xnu_float < self.macOS_14_1:
|
||||
return {}
|
||||
|
||||
return {
|
||||
# Injection of UHCI/OHCI causes a panic on 14.1+
|
||||
"Legacy USB 1.1 Extended": {
|
||||
PatchType.OVERWRITE_SYSTEM_VOLUME: {
|
||||
"/System/Library/Extensions/IOUSBHostFamily.kext/Contents/PlugIns": {
|
||||
"AppleUSBOHCI.kext": "12.6.2-USB",
|
||||
"AppleUSBOHCIPCI.kext": "12.6.2-USB",
|
||||
"AppleUSBUHCI.kext": "12.6.2-USB",
|
||||
"AppleUSBUHCIPCI.kext": "12.6.2-USB",
|
||||
},
|
||||
"/System/Library/Extensions": {
|
||||
**({ "AppleUSBAudio.kext": "14.5" } if self._xnu_major >= os_data.sequoia else {}),
|
||||
**({ "AppleUSBCDC.kext": "14.5" } if self._xnu_major >= os_data.sequoia else {}),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def patches(self) -> dict:
|
||||
"""
|
||||
Patches for USB 1.1 Controller
|
||||
"""
|
||||
if self.native_os() is True:
|
||||
return {}
|
||||
|
||||
return {
|
||||
**self._base_patches(),
|
||||
**self._extended_patches(),
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
"""
|
||||
legacy_wireless.py: Legacy Wireless detection
|
||||
"""
|
||||
|
||||
import packaging.version
|
||||
|
||||
from ..base import BaseHardware, HardwareVariant
|
||||
|
||||
from ...base import PatchType
|
||||
|
||||
from .....constants import Constants
|
||||
from .....detections import device_probe
|
||||
|
||||
from .....datasets.os_data import os_data
|
||||
|
||||
|
||||
class LegacyWireless(BaseHardware):
|
||||
|
||||
def __init__(self, xnu_major, xnu_minor, os_build, global_constants: Constants) -> None:
|
||||
super().__init__(xnu_major, xnu_minor, os_build, global_constants)
|
||||
|
||||
|
||||
def name(self) -> str:
|
||||
"""
|
||||
Display name for end users
|
||||
"""
|
||||
return f"{self.hardware_variant()}: Legacy Wireless"
|
||||
|
||||
|
||||
def present(self) -> bool:
|
||||
"""
|
||||
Targeting Legacy Wireless
|
||||
"""
|
||||
if (
|
||||
isinstance(self._computer.wifi, device_probe.Broadcom)
|
||||
and self._computer.wifi.chipset in [device_probe.Broadcom.Chipsets.AirPortBrcm4331, device_probe.Broadcom.Chipsets.AirPortBrcm43224]
|
||||
):
|
||||
return True
|
||||
|
||||
if (
|
||||
isinstance(self._computer.wifi, device_probe.Atheros)
|
||||
and self._computer.wifi.chipset == device_probe.Atheros.Chipsets.AirPortAtheros40
|
||||
):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def native_os(self) -> bool:
|
||||
"""
|
||||
Dropped support with macOS 12, Monterey
|
||||
"""
|
||||
return self._xnu_major < os_data.monterey.value
|
||||
|
||||
|
||||
def hardware_variant(self) -> HardwareVariant:
|
||||
"""
|
||||
Type of hardware variant
|
||||
"""
|
||||
return HardwareVariant.NETWORKING
|
||||
|
||||
|
||||
def _affected_by_cve_2024_23227(self) -> bool:
|
||||
"""
|
||||
CVE-2024-23227 broke our airportd patches for 12.7.4, 13.6.5 and 14.4
|
||||
|
||||
Note that since the XNU version's security patch level is not increment
|
||||
"""
|
||||
|
||||
if self._xnu_major > os_data.sonoma:
|
||||
return True
|
||||
|
||||
marketing_version = self._constants.detected_os_version
|
||||
parsed_version = packaging.version.parse(marketing_version)
|
||||
|
||||
if marketing_version.startswith("12"):
|
||||
return parsed_version >= packaging.version.parse("12.7.4")
|
||||
if marketing_version.startswith("13"):
|
||||
return parsed_version >= packaging.version.parse("13.6.5")
|
||||
if marketing_version.startswith("14"):
|
||||
return parsed_version >= packaging.version.parse("14.4")
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def _base_patch(self) -> dict:
|
||||
"""
|
||||
Base patches for Legacy Wireless
|
||||
"""
|
||||
return {
|
||||
"Legacy Wireless": {
|
||||
PatchType.OVERWRITE_SYSTEM_VOLUME: {
|
||||
"/usr/libexec": {
|
||||
"airportd": "11.7.10" if self._affected_by_cve_2024_23227 is False else "11.7.10-Sandbox",
|
||||
},
|
||||
"/System/Library/CoreServices": {
|
||||
"WiFiAgent.app": "11.7.10",
|
||||
},
|
||||
},
|
||||
PatchType.OVERWRITE_DATA_VOLUME: {
|
||||
"/Library/Application Support/SkyLightPlugins": {
|
||||
**({ "CoreWLAN.dylib": "SkyLightPlugins" } if self._xnu_major == os_data.monterey else {}),
|
||||
**({ "CoreWLAN.txt": "SkyLightPlugins" } if self._xnu_major == os_data.monterey else {}),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def _extended_patch(self) -> dict:
|
||||
"""
|
||||
Extended patches for Legacy Wireless
|
||||
"""
|
||||
if self._xnu_major < os_data.ventura:
|
||||
return {}
|
||||
|
||||
return {
|
||||
"Legacy Wireless Extended": {
|
||||
PatchType.OVERWRITE_SYSTEM_VOLUME: {
|
||||
"/usr/libexec": {
|
||||
"wps": "12.7.2",
|
||||
"wifip2pd": "12.7.2",
|
||||
},
|
||||
},
|
||||
PatchType.MERGE_SYSTEM_VOLUME: {
|
||||
"/System/Library/Frameworks": {
|
||||
"CoreWLAN.framework": "12.7.2",
|
||||
},
|
||||
"/System/Library/PrivateFrameworks": {
|
||||
"CoreWiFi.framework": "12.7.2",
|
||||
"IO80211.framework": "12.7.2",
|
||||
"WiFiPeerToPeer.framework": "12.7.2",
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def patches(self) -> dict:
|
||||
"""
|
||||
Patches for Legacy Wireless
|
||||
"""
|
||||
if self.native_os() is True:
|
||||
return {}
|
||||
|
||||
return {
|
||||
**self._base_patch(),
|
||||
**self._extended_patch(),
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
"""
|
||||
modern_wireless.py: Modern Wireless detection
|
||||
"""
|
||||
|
||||
from ..base import BaseHardware, HardwareVariant
|
||||
|
||||
from ...base import PatchType
|
||||
|
||||
from .....constants import Constants
|
||||
from .....detections import device_probe
|
||||
|
||||
from .....datasets.os_data import os_data
|
||||
|
||||
|
||||
class ModernWireless(BaseHardware):
|
||||
|
||||
def __init__(self, xnu_major, xnu_minor, os_build, global_constants: Constants) -> None:
|
||||
super().__init__(xnu_major, xnu_minor, os_build, global_constants)
|
||||
|
||||
|
||||
def name(self) -> str:
|
||||
"""
|
||||
Display name for end users
|
||||
"""
|
||||
return f"{self.hardware_variant()}: Modern Wireless"
|
||||
|
||||
|
||||
def present(self) -> bool:
|
||||
"""
|
||||
Targeting Modern Wireless
|
||||
"""
|
||||
return isinstance(self._computer.wifi, device_probe.Broadcom) and (
|
||||
self._computer.wifi.chipset in [
|
||||
device_probe.Broadcom.Chipsets.AirPortBrcm4360,
|
||||
device_probe.Broadcom.Chipsets.AirportBrcmNIC,
|
||||
# We don't officially support this chipset, however we'll throw a bone to hackintosh users
|
||||
device_probe.Broadcom.Chipsets.AirPortBrcmNICThirdParty,
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def native_os(self) -> bool:
|
||||
"""
|
||||
Dropped support with macOS 14, Sonoma
|
||||
"""
|
||||
return self._xnu_major < os_data.sonoma.value
|
||||
|
||||
|
||||
def hardware_variant(self) -> HardwareVariant:
|
||||
"""
|
||||
Type of hardware variant
|
||||
"""
|
||||
return HardwareVariant.NETWORKING
|
||||
|
||||
|
||||
def patches(self) -> dict:
|
||||
"""
|
||||
Patches for Modern Wireless
|
||||
"""
|
||||
if self.native_os() is True:
|
||||
return {}
|
||||
|
||||
return {
|
||||
"Modern Wireless": {
|
||||
PatchType.OVERWRITE_SYSTEM_VOLUME: {
|
||||
"/usr/libexec": {
|
||||
"airportd": "13.6.5",
|
||||
"wifip2pd": "13.6.5",
|
||||
},
|
||||
"/System/Library/CoreServices": {
|
||||
**({ "WiFiAgent.app": "14.5" } if self._xnu_major >= os_data.sequoia else {}),
|
||||
},
|
||||
},
|
||||
PatchType.MERGE_SYSTEM_VOLUME: {
|
||||
"/System/Library/Frameworks": {
|
||||
"CoreWLAN.framework": f"13.6.5-{self._xnu_major}",
|
||||
},
|
||||
"/System/Library/PrivateFrameworks": {
|
||||
"CoreWiFi.framework": f"13.6.5-{self._xnu_major}",
|
||||
"IO80211.framework": f"13.6.5-{self._xnu_major}",
|
||||
"WiFiPeerToPeer.framework": f"13.6.5-{self._xnu_major}",
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
"""
|
||||
amd_opencl.py: AMD OpenCL patches
|
||||
"""
|
||||
|
||||
from .base import BaseSharedPatchSet
|
||||
|
||||
from ..base import PatchType
|
||||
|
||||
from ....datasets.os_data import os_data
|
||||
|
||||
|
||||
class AMDOpenCL(BaseSharedPatchSet):
|
||||
|
||||
def __init__(self, xnu_major: int, xnu_minor: int, marketing_version: str) -> None:
|
||||
super().__init__(xnu_major, xnu_minor, marketing_version)
|
||||
|
||||
|
||||
def _os_requires_patches(self) -> bool:
|
||||
"""
|
||||
Check if the current OS requires
|
||||
"""
|
||||
return self._xnu_major >= os_data.ventura.value
|
||||
|
||||
|
||||
def patches(self) -> dict:
|
||||
"""
|
||||
In Ventura, Apple added AVX2.0 code to AMD's OpenCL/GL compilers
|
||||
"""
|
||||
if self._os_requires_patches() is False:
|
||||
return {}
|
||||
|
||||
return {
|
||||
"AMD OpenCL": {
|
||||
PatchType.MERGE_SYSTEM_VOLUME: {
|
||||
"/System/Library/Frameworks": {
|
||||
"OpenCL.framework": "12.5 non-AVX2.0",
|
||||
"OpenGL.framework": "12.5 non-AVX2.0",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
"""
|
||||
amd_terascale.py: AMD TeraScale patches
|
||||
"""
|
||||
|
||||
from .base import BaseSharedPatchSet
|
||||
|
||||
from ..base import PatchType
|
||||
|
||||
from ....datasets.os_data import os_data
|
||||
|
||||
|
||||
class AMDTeraScale(BaseSharedPatchSet):
|
||||
|
||||
def __init__(self, xnu_major: int, xnu_minor: int, marketing_version: str) -> None:
|
||||
super().__init__(xnu_major, xnu_minor, marketing_version)
|
||||
|
||||
|
||||
def _os_requires_patches(self) -> bool:
|
||||
"""
|
||||
Dropped support with macOS 10.14, Mojave
|
||||
"""
|
||||
return self._xnu_major >= os_data.mojave.value
|
||||
|
||||
|
||||
def patches(self) -> dict:
|
||||
"""
|
||||
Shared patches between TeraScale 1 and 2
|
||||
"""
|
||||
if self._os_requires_patches() is False:
|
||||
return {}
|
||||
|
||||
return {
|
||||
"AMD TeraScale Common": {
|
||||
PatchType.OVERWRITE_SYSTEM_VOLUME: {
|
||||
"/System/Library/Extensions": {
|
||||
"AMDFramebuffer.kext": "10.13.6",
|
||||
"AMDLegacyFramebuffer.kext": "10.13.6",
|
||||
"AMDLegacySupport.kext": "10.13.6",
|
||||
"AMDShared.bundle": "10.13.6",
|
||||
"AMDSupport.kext": "10.13.6",
|
||||
},
|
||||
},
|
||||
PatchType.REMOVE_SYSTEM_VOLUME: {
|
||||
"/System/Library/Extensions": [
|
||||
"AMD7000Controller.kext",
|
||||
"AMD8000Controller.kext",
|
||||
"AMD9000Controller.kext",
|
||||
"AMD9500Controller.kext",
|
||||
"AMD10000Controller.kext",
|
||||
],
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
"""
|
||||
base.py: Base class for shared patch sets
|
||||
"""
|
||||
|
||||
from ..base import BasePatchset
|
||||
|
||||
|
||||
class BaseSharedPatchSet(BasePatchset):
|
||||
|
||||
def __init__(self, xnu_major: int, xnu_minor: int, marketing_version: str) -> None:
|
||||
super().__init__()
|
||||
self._xnu_major = xnu_major
|
||||
self._xnu_minor = xnu_minor
|
||||
self._marketing_version = marketing_version
|
||||
|
||||
self._xnu_float = float(f"{self._xnu_major}.{self._xnu_minor}")
|
||||
|
||||
|
||||
def _os_requires_patches(self) -> bool:
|
||||
"""
|
||||
Check if the current OS requires patches
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def patches(self) -> dict:
|
||||
"""
|
||||
Dictionary of patches
|
||||
"""
|
||||
raise NotImplementedError
|
||||
@@ -0,0 +1,42 @@
|
||||
"""
|
||||
big_sur_gva.py: Big Sur GVA patches
|
||||
"""
|
||||
|
||||
from .base import BaseSharedPatchSet
|
||||
|
||||
from ..base import PatchType
|
||||
|
||||
from ....datasets.os_data import os_data
|
||||
|
||||
|
||||
class BigSurGVA(BaseSharedPatchSet):
|
||||
|
||||
def __init__(self, xnu_major: int, xnu_minor: int, marketing_version: str) -> None:
|
||||
super().__init__(xnu_major, xnu_minor, marketing_version)
|
||||
|
||||
|
||||
def _os_requires_patches(self) -> bool:
|
||||
"""
|
||||
Check if the current OS requires
|
||||
"""
|
||||
return self._xnu_major >= os_data.monterey.value
|
||||
|
||||
|
||||
def patches(self) -> dict:
|
||||
"""
|
||||
For GPUs last natively supported in Catalina/Big Sur
|
||||
Restores DRM support for these GPUs
|
||||
"""
|
||||
if self._os_requires_patches() is False:
|
||||
return {}
|
||||
|
||||
return {
|
||||
"Big Sur GVA": {
|
||||
PatchType.MERGE_SYSTEM_VOLUME: {
|
||||
"/System/Library/PrivateFrameworks": {
|
||||
"AppleGVA.framework": "11.7.10",
|
||||
"AppleGVACore.framework": "11.7.10",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
"""
|
||||
big_sur_opencl.py: Big Sur OpenCL patches
|
||||
"""
|
||||
|
||||
from .base import BaseSharedPatchSet
|
||||
|
||||
from ..base import PatchType
|
||||
|
||||
from ....datasets.os_data import os_data
|
||||
|
||||
|
||||
class BigSurOpenCL(BaseSharedPatchSet):
|
||||
|
||||
def __init__(self, xnu_major: int, xnu_minor: int, marketing_version: str) -> None:
|
||||
super().__init__(xnu_major, xnu_minor, marketing_version)
|
||||
|
||||
|
||||
def _os_requires_patches(self) -> bool:
|
||||
"""
|
||||
Check if the current OS requires
|
||||
"""
|
||||
return self._xnu_major >= os_data.monterey.value
|
||||
|
||||
|
||||
def patches(self) -> dict:
|
||||
"""
|
||||
For graphics cards dropped in Monterey
|
||||
"""
|
||||
if self._os_requires_patches() is False:
|
||||
return {}
|
||||
|
||||
return {
|
||||
"Big Sur OpenCL": {
|
||||
PatchType.MERGE_SYSTEM_VOLUME: {
|
||||
"/System/Library/Frameworks": {
|
||||
"OpenCL.framework": "11.6",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
"""
|
||||
high_sierra_gva.py: High Sierra GVA patches
|
||||
"""
|
||||
|
||||
from .base import BaseSharedPatchSet
|
||||
|
||||
from ..base import PatchType
|
||||
|
||||
from ....datasets.os_data import os_data
|
||||
|
||||
|
||||
class HighSierraGVA(BaseSharedPatchSet):
|
||||
|
||||
def __init__(self, xnu_major: int, xnu_minor: int, marketing_version: str) -> None:
|
||||
super().__init__(xnu_major, xnu_minor, marketing_version)
|
||||
|
||||
|
||||
def _os_requires_patches(self) -> bool:
|
||||
"""
|
||||
Dropped support with macOS 11.0, Big Sur
|
||||
"""
|
||||
return self._xnu_major >= os_data.big_sur.value
|
||||
|
||||
|
||||
def patches(self) -> dict:
|
||||
"""
|
||||
For GPUs last natively supported in High Sierra/Catalina
|
||||
"""
|
||||
if self._os_requires_patches() is False:
|
||||
return {}
|
||||
|
||||
return {
|
||||
# For GPUs last natively supported in High Sierra/Catalina
|
||||
# Restores DRM support
|
||||
"High Sierra GVA": {
|
||||
PatchType.MERGE_SYSTEM_VOLUME: {
|
||||
"/System/Library/PrivateFrameworks": {
|
||||
"AppleGVA.framework": "10.13.6",
|
||||
"AppleGVACore.framework": "10.15.7",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,485 @@
|
||||
"""
|
||||
metal_3802.py: Metal 3802 patches
|
||||
"""
|
||||
|
||||
from .base import BaseSharedPatchSet
|
||||
|
||||
from ..base import PatchType, DynamicPatchset
|
||||
|
||||
from ....datasets.os_data import os_data
|
||||
|
||||
|
||||
class LegacyMetal3802(BaseSharedPatchSet):
|
||||
|
||||
def __init__(self, xnu_major: int, xnu_minor: int, marketing_version: str) -> None:
|
||||
super().__init__(xnu_major, xnu_minor, marketing_version)
|
||||
|
||||
|
||||
def _os_requires_patches(self) -> bool:
|
||||
"""
|
||||
Check if the current OS requires
|
||||
"""
|
||||
return self._xnu_major >= os_data.ventura.value
|
||||
|
||||
|
||||
def _patches_metal_3802_common(self) -> dict:
|
||||
"""
|
||||
Intel Ivy Bridge, Haswell and Nvidia Kepler are Metal 3802-based GPUs
|
||||
Due to this, we need to re-add 3802 compiler support to the Metal stack
|
||||
"""
|
||||
if self._os_requires_patches() is False:
|
||||
return {}
|
||||
|
||||
return {
|
||||
"Metal 3802 Common": {
|
||||
PatchType.OVERWRITE_SYSTEM_VOLUME: {
|
||||
"/System/Library/Sandbox/Profiles": {
|
||||
"com.apple.mtlcompilerservice.sb": "12.5-3802",
|
||||
}
|
||||
},
|
||||
PatchType.MERGE_SYSTEM_VOLUME: {
|
||||
"/System/Library/Frameworks": {
|
||||
"Metal.framework": "12.5-3802-22" if self._xnu_major < os_data.sonoma else "12.5-3802-23",
|
||||
},
|
||||
"/System/Library/PrivateFrameworks": {
|
||||
"MTLCompiler.framework": "12.7.6-3802",
|
||||
"GPUCompiler.framework": "12.7.6-3802",
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def _patches_metal_3802_common_extended(self) -> dict:
|
||||
"""
|
||||
Support for 3802 GPUs were broken with 13.3+
|
||||
Downgrades 31001 stack to 13.2.1, however nukes AMFI support
|
||||
"""
|
||||
if self._xnu_float < self.macOS_13_3:
|
||||
return {}
|
||||
|
||||
return {
|
||||
"Metal 3802 Common Extended": {
|
||||
PatchType.MERGE_SYSTEM_VOLUME: {
|
||||
"/System/Library/Frameworks": {
|
||||
"Metal.framework": f"13.2.1-{self._xnu_major}",
|
||||
**({ "CoreImage.framework": "14.0 Beta 3" if self._xnu_major < os_data.sequoia.value else "14.0 Beta 3-24"} if self._xnu_major >= os_data.sonoma.value else {}),
|
||||
},
|
||||
"/System/Library/PrivateFrameworks": {
|
||||
**({ "MTLCompiler.framework": "13.2.1" } if self._xnu_major == os_data.ventura.value else {}),
|
||||
**({ "GPUCompiler.framework": "13.2.1" } if self._xnu_major == os_data.ventura.value else {}),
|
||||
"RenderBox.framework": "13.2.1-3802" if self._xnu_major == os_data.ventura.value else "14.0-3802",
|
||||
|
||||
# More issues for 3802, now with 14.2 Beta 2+...
|
||||
# If there is a god, they clearly despise us and legacy Macs.
|
||||
**({ "MTLCompiler.framework": "14.2 Beta 1" } if self._xnu_float >= self.macOS_14_2 else {}),
|
||||
**({ "GPUCompiler.framework": "14.2 Beta 1" } if self._xnu_float >= self.macOS_14_2 else {}),
|
||||
},
|
||||
|
||||
},
|
||||
PatchType.OVERWRITE_SYSTEM_VOLUME: {
|
||||
"/System/Library/PrivateFrameworks/PhotosUICore.framework/Versions/A/Resources": {
|
||||
**({ "default.metallib": "14.6.1" } if self._xnu_major == os_data.sonoma.value else {}),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def _patches_metal_3802_metallibs(self) -> dict:
|
||||
"""
|
||||
With macOS Sequoia, a new .metallib compiler format was introduced (V27)
|
||||
Thus we need to patch all .metallib files to support 3802 GPUs using MetallibSupportPkg
|
||||
|
||||
Reference:
|
||||
https://github.com/dortania/MetallibSupportPkg
|
||||
"""
|
||||
if self._xnu_major < os_data.sequoia.value:
|
||||
return {}
|
||||
|
||||
return {
|
||||
"Metal 3802 .metallibs": {
|
||||
PatchType.OVERWRITE_SYSTEM_VOLUME: {
|
||||
"/System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/Frameworks/MPSCore.framework/Versions/A/Resources": {
|
||||
"default.metallib": "14.6.1",
|
||||
},
|
||||
"/System/Library/Frameworks/MLCompute.framework/Versions/A/Resources": {
|
||||
"default.metallib": "14.6.1"
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/CoreUI.framework/Versions/A/Resources": {
|
||||
"default.metallib": "14.6.1",
|
||||
},
|
||||
"/System/Library/Frameworks/CoreImage.framework/Versions/A": {
|
||||
"CoreImage.metallib": "14.6.1",
|
||||
},
|
||||
"/System/Library/Frameworks/CoreImage.framework/Versions/A/Resources": {
|
||||
"default.metallib": "14.6.1",
|
||||
"ci_filters.metallib": "14.6.1",
|
||||
"ci_stdlib_stitchable_h.metallib": "14.6.1",
|
||||
"ci_stdlib_stitchable.metallib": "14.6.1",
|
||||
"CIPortraitBlurStitchableV3.metallib": "14.6.1",
|
||||
"CIPortraitBlurStitchableV2.metallib": "14.6.1",
|
||||
"ci_stdlib_h.metallib": "14.6.1",
|
||||
"ci_filters_stitchable.metallib": "14.6.1",
|
||||
"CIPortraitBlurV2.metallib": "14.6.1",
|
||||
"CIPortraitBlurV3.metallib": "14.6.1",
|
||||
"ci_stdlib.metallib": "14.6.1",
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/Tungsten.framework/Versions/A/Resources": {
|
||||
"default.metallib": "15.0 Beta 7",
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/RenderBox.framework/Versions/A/Resources": {
|
||||
"default.metallib": "15.0 Beta 8",
|
||||
},
|
||||
"/System/iOSSupport/System/Library/PrivateFrameworks/VFX.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/iOSSupport/System/Library/PrivateFrameworks/VisionKitInternal.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/iOSSupport/System/Library/PrivateFrameworks/TSReading.framework/Versions/A/Resources": {
|
||||
"TSDDefaultMetalLibrary.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
"KeynoteMetalLibrary.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/iOSSupport/System/Library/PrivateFrameworks/WeatherUI.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
"ForegroundEffectShaders.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/iOSSupport/System/Library/PrivateFrameworks/AvatarKit.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/iOSSupport/System/Library/PrivateFrameworks/Tungsten.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/iOSSupport/System/Library/PrivateFrameworks/TextInputUI.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/iOSSupport/System/Library/PrivateFrameworks/ActivityRingsUI.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/iOSSupport/System/Library/PrivateFrameworks/ChatKit.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/iOSSupport/System/Library/PrivateFrameworks/WeatherMaps.framework/Versions/A/Resources": {
|
||||
"WeatherMapsMetalLib.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/iOSSupport/System/Library/PrivateFrameworks/HomeAccessoryControlUI.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/iOSSupport/System/Library/PrivateFrameworks/PassKitUIFoundation.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/iOSSupport/System/Library/PrivateFrameworks/MediaCoreUI.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/iOSSupport/System/Library/Frameworks/ARKit.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/iOSSupport/System/Library/Frameworks/SpriteKit.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/iOSSupport/System/Library/Frameworks/PencilKit.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/iOSSupport/System/Library/Frameworks/SwiftUI.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/iOSSupport/System/Library/Frameworks/SceneKit.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/Video/Plug-Ins/AppleGVAHEVCEncoder.bundle/Contents/Resources": {
|
||||
"AppleGVAHEVCFrameStatistics.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/Video/Plug-Ins/AV1DecoderSW.bundle/Contents/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/Video/Plug-Ins/AppleAVEEncoder.bundle/Contents/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/CoreServices/MTLReplayer.app/Contents/Frameworks/MTLReplayController.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/CoreImage/CIPassThrough.cifilter/Contents/Resources": {
|
||||
"CIPassThrough.ci.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/CoreImage/PortraitFilters.cifilter/Contents/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
"portrait_filters.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/ScreenCaptureKitMetal/ScreenCaptureKitMetal.bundle/Contents/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/ExtensionKit/Extensions/Monterey.appex/Contents/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/ExtensionKit/Extensions/Drift.appex/Contents/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/ExtensionKit/Extensions/WallpaperMacintoshExtension.appex/Contents/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/ExtensionKit/Extensions/WallpaperSequoiaExtension.appex/Contents/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/SetupAssistantSupportUI.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/GESS.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/VFX.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/VisionCore.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/CMImaging.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/CoreRE.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/HDRProcessing.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/AvatarKit.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/SkyLight.framework/Versions/A/Resources": {
|
||||
"SkyLightShaders.air64.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/AppleISPEmulator.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/NeutrinoCore.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/ImageHarmonizationKit.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/VideoProcessing.framework/Versions/A/PlugIns/Codecs/VCPRealtimeEncoder.bundle/Contents/Resources": {
|
||||
"ProcessAccelerate.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/VideoProcessing.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
"ProcessAccelerate.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/Portrait.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/VisualGeneration.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
"NonMaxLineSuppress.ci.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/AccelerateGPU.framework": {
|
||||
"GPUBLAS.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/AccelerateGPU.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/ShaderGraph.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/Hydra.framework/Plugins/HydraQLThumbnailExtension.appex/Contents/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/Hydra.framework/Plugins/HydraQLPreviewExtension.appex/Contents/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/Hydra.framework/Versions/C/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/SiriUI.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/TextRecognition.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/Leonardo.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/VectorKit.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/VectorKit.framework/Versions/A/Resources/metal_libraries": {
|
||||
"AlloyCommonLibrary.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/GPUToolsCapture.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/PhotoImaging.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/PhotosUICore.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/MetalTools.framework/Versions/A/Resources": {
|
||||
"MTLLegacySVICBSupport.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
"MTLGPUDebugICBSupport.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
"MTLGPUDebugAccelerationStructureSupport.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
"MTLDebugShaders.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
"MTLLegacySVAccelerationStructureSupport.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/AppleDepth.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/Human.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/CorePhotogrammetry.framework/Versions/A/Resources": {
|
||||
"ComputerVision_Tess_Kernels.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
"Photogrammetry_Matching_Kernels.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
"Photogrammetry_Texturing_Kernels.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
"Photogrammetry_MVS_Kernels.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
"Photogrammetry_Meshing_Kernels.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/HumanUI.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/Quagga.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/Espresso.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/CMPhoto.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/MediaAnalysis.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/AltruisticBodyPoseKit.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/MusicUI.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/FRC.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/H13ISPServices.framework/Versions/A/Resources": {
|
||||
"CalibrateRgbIr.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/SiriUICore.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/PassKitUIFoundation.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/H16ISPServices.framework/Versions/A/Resources": {
|
||||
"CalibrateRgbIr.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/CoreOCModules.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/PhotosensitivityProcessing.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/PrivateFrameworks/MediaCoreUI.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/Frameworks/Metal.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
"MTLMeshShaderEmulator.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
"MTLBVHBuilder.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
"MTLECBE.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/Frameworks/QuartzCore.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/Frameworks/CoreMediaIO.framework/Versions/A/Resources/ACD.plugin/Contents/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/Frameworks/MPSFunctions.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/Frameworks/MPSRayIntersector.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/Frameworks/MPSNeuralNetwork.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/Frameworks/MPSNDArray.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/Frameworks/MPSImage.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/Frameworks/MPSMatrix.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/Frameworks/MetalFX.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/Frameworks/ParavirtualizedGraphics.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/Frameworks/ImageIO.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/Frameworks/SpriteKit.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/Frameworks/PencilKit.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/Frameworks/CoreDisplay.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/Frameworks/SwiftUICore.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/Frameworks/SwiftUI.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/Frameworks/Vision.framework/Versions/A/Resources": {
|
||||
"ImageFilters.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/Frameworks/StickerKit.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/Frameworks/VideoToolbox.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/Frameworks/SceneKit.framework/Versions/A/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Library/VideoProcessors/CCPortrait.bundle/Contents/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
"CoreImageKernels_only.ci.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
"CoreImageKernels.ci.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Applications/Music.app/Contents/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Applications/Chess.app/Contents/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Applications/Freeform.app/Contents/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
"coreimage.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
"/System/Applications/Freeform.app/Contents/Extensions/USDRendererExtension.appex/Contents/Resources": {
|
||||
"default.metallib": DynamicPatchset.MetallibSupportPkg,
|
||||
},
|
||||
},
|
||||
PatchType.REMOVE_SYSTEM_VOLUME: {
|
||||
"/System/Library/PrivateFrameworks/RenderBox.framework/Versions/A/Resources": [
|
||||
# For some reason Ivy Bridge can't tell the metallib lacks AIR64 support, and errors out
|
||||
"archive.metallib",
|
||||
],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def patches(self) -> dict:
|
||||
"""
|
||||
Dictionary of patches
|
||||
"""
|
||||
return {
|
||||
**self._patches_metal_3802_common(),
|
||||
**self._patches_metal_3802_common_extended(),
|
||||
**self._patches_metal_3802_metallibs(),
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
"""
|
||||
monterey_gva.py: Monterey GVA patches
|
||||
"""
|
||||
|
||||
from .base import BaseSharedPatchSet
|
||||
|
||||
from ..base import PatchType
|
||||
|
||||
from ....datasets.os_data import os_data
|
||||
|
||||
|
||||
class MontereyGVA(BaseSharedPatchSet):
|
||||
|
||||
def __init__(self, xnu_major: int, xnu_minor: int, marketing_version: str) -> None:
|
||||
super().__init__(xnu_major, xnu_minor, marketing_version)
|
||||
|
||||
|
||||
def _os_requires_patches(self) -> bool:
|
||||
"""
|
||||
Check if the current OS requires
|
||||
"""
|
||||
return self._xnu_major >= os_data.ventura.value
|
||||
|
||||
|
||||
def patches(self) -> dict:
|
||||
"""
|
||||
For GPUs last natively supported in Monterey
|
||||
Restores DRM support
|
||||
"""
|
||||
if self._os_requires_patches() is False:
|
||||
return {}
|
||||
|
||||
return {
|
||||
"Monterey GVA": {
|
||||
PatchType.MERGE_SYSTEM_VOLUME: {
|
||||
"/System/Library/PrivateFrameworks": {
|
||||
"AppleGVA.framework": "12.5",
|
||||
"AppleGVACore.framework": "12.5",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||