commit 72a124244b62fc30cdec2aae520f69048aa5bdc8 Author: Hoang Hong Quan Date: Fri Jul 26 18:09:54 2024 +0700 Initial commit diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..dfe0770 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..337c691 --- /dev/null +++ b/.gitignore @@ -0,0 +1,163 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +*.DS_Store +OCK_Files \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100755 index 0000000..10a7ee2 --- /dev/null +++ b/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2024, lzhoang2601 +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/OcBinaryData/Resources/Font/Font_1x.bin b/OcBinaryData/Resources/Font/Font_1x.bin new file mode 100755 index 0000000..a4ef287 Binary files /dev/null and b/OcBinaryData/Resources/Font/Font_1x.bin differ diff --git a/OcBinaryData/Resources/Font/Font_1x.png b/OcBinaryData/Resources/Font/Font_1x.png new file mode 100755 index 0000000..3b5f3ef Binary files /dev/null and b/OcBinaryData/Resources/Font/Font_1x.png differ diff --git a/OcBinaryData/Resources/Font/Font_2x.bin b/OcBinaryData/Resources/Font/Font_2x.bin new file mode 100755 index 0000000..714ace8 Binary files /dev/null and b/OcBinaryData/Resources/Font/Font_2x.bin differ diff --git a/OcBinaryData/Resources/Font/Font_2x.png b/OcBinaryData/Resources/Font/Font_2x.png new file mode 100755 index 0000000..a06e748 Binary files /dev/null and b/OcBinaryData/Resources/Font/Font_2x.png differ diff --git a/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/AppleRecv.icns b/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/AppleRecv.icns new file mode 100755 index 0000000..54b49c9 Binary files /dev/null and b/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/AppleRecv.icns differ diff --git a/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/AppleTM.icns b/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/AppleTM.icns new file mode 100755 index 0000000..7acb4f3 Binary files /dev/null and b/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/AppleTM.icns differ diff --git a/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/Background.icns b/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/Background.icns new file mode 100755 index 0000000..d79cbe8 Binary files /dev/null and b/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/Background.icns differ diff --git a/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/BtnFocus.icns b/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/BtnFocus.icns new file mode 100755 index 0000000..1627a67 Binary files /dev/null and b/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/BtnFocus.icns differ diff --git a/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/Cursor.icns b/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/Cursor.icns new file mode 100755 index 0000000..e84f198 Binary files /dev/null and b/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/Cursor.icns differ diff --git a/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/Dot.icns b/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/Dot.icns new file mode 100755 index 0000000..60a4c41 Binary files /dev/null and b/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/Dot.icns differ diff --git a/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/Enter.icns b/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/Enter.icns new file mode 100755 index 0000000..087d050 Binary files /dev/null and b/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/Enter.icns differ diff --git a/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/ExtAppleRecv.icns b/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/ExtAppleRecv.icns new file mode 100755 index 0000000..2ec68de Binary files /dev/null and b/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/ExtAppleRecv.icns differ diff --git a/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/ExtAppleTM.icns b/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/ExtAppleTM.icns new file mode 100755 index 0000000..ec13a62 Binary files /dev/null and b/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/ExtAppleTM.icns differ diff --git a/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/ExtHardDrive.icns b/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/ExtHardDrive.icns new file mode 100755 index 0000000..890d769 Binary files /dev/null and b/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/ExtHardDrive.icns differ diff --git a/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/HardDrive.icns b/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/HardDrive.icns new file mode 100755 index 0000000..ec8343f Binary files /dev/null and b/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/HardDrive.icns differ diff --git a/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/Left.icns b/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/Left.icns new file mode 100755 index 0000000..e3a2313 Binary files /dev/null and b/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/Left.icns differ diff --git a/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/Lock.icns b/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/Lock.icns new file mode 100755 index 0000000..499b103 Binary files /dev/null and b/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/Lock.icns differ diff --git a/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/Password.icns b/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/Password.icns new file mode 100755 index 0000000..7a5c2c8 Binary files /dev/null and b/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/Password.icns differ diff --git a/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/Restart.icns b/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/Restart.icns new file mode 100755 index 0000000..6bc45b2 Binary files /dev/null and b/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/Restart.icns differ diff --git a/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/Right.icns b/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/Right.icns new file mode 100755 index 0000000..537a1e2 Binary files /dev/null and b/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/Right.icns differ diff --git a/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/Selected.icns b/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/Selected.icns new file mode 100755 index 0000000..8f59155 Binary files /dev/null and b/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/Selected.icns differ diff --git a/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/Selector.icns b/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/Selector.icns new file mode 100755 index 0000000..44c81a5 Binary files /dev/null and b/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/Selector.icns differ diff --git a/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/SetDefault.icns b/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/SetDefault.icns new file mode 100755 index 0000000..faa5807 Binary files /dev/null and b/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/SetDefault.icns differ diff --git a/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/Shell.icns b/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/Shell.icns new file mode 100755 index 0000000..2e453d6 Binary files /dev/null and b/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/Shell.icns differ diff --git a/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/ShutDown.icns b/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/ShutDown.icns new file mode 100755 index 0000000..ee11240 Binary files /dev/null and b/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/ShutDown.icns differ diff --git a/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/Tool.icns b/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/Tool.icns new file mode 100755 index 0000000..d8e13fd Binary files /dev/null and b/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/Tool.icns differ diff --git a/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/Windows.icns b/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/Windows.icns new file mode 100755 index 0000000..cc9e1ad Binary files /dev/null and b/OcBinaryData/Resources/Image/Acidanthera/GoldenGate/Windows.icns differ diff --git a/OcBinaryData/Resources/Label/Apple.l2x b/OcBinaryData/Resources/Label/Apple.l2x new file mode 100755 index 0000000..d347265 Binary files /dev/null and b/OcBinaryData/Resources/Label/Apple.l2x differ diff --git a/OcBinaryData/Resources/Label/Apple.lbl b/OcBinaryData/Resources/Label/Apple.lbl new file mode 100755 index 0000000..5303b1c Binary files /dev/null and b/OcBinaryData/Resources/Label/Apple.lbl differ diff --git a/OcBinaryData/Resources/Label/AppleRecv.l2x b/OcBinaryData/Resources/Label/AppleRecv.l2x new file mode 100755 index 0000000..9708b38 Binary files /dev/null and b/OcBinaryData/Resources/Label/AppleRecv.l2x differ diff --git a/OcBinaryData/Resources/Label/AppleRecv.lbl b/OcBinaryData/Resources/Label/AppleRecv.lbl new file mode 100755 index 0000000..d11eee3 Binary files /dev/null and b/OcBinaryData/Resources/Label/AppleRecv.lbl differ diff --git a/OcBinaryData/Resources/Label/AppleTM.l2x b/OcBinaryData/Resources/Label/AppleTM.l2x new file mode 100755 index 0000000..cf3cdd3 Binary files /dev/null and b/OcBinaryData/Resources/Label/AppleTM.l2x differ diff --git a/OcBinaryData/Resources/Label/AppleTM.lbl b/OcBinaryData/Resources/Label/AppleTM.lbl new file mode 100755 index 0000000..887aa26 Binary files /dev/null and b/OcBinaryData/Resources/Label/AppleTM.lbl differ diff --git a/OcBinaryData/Resources/Label/EFIBoot.l2x b/OcBinaryData/Resources/Label/EFIBoot.l2x new file mode 100755 index 0000000..6fe1655 Binary files /dev/null and b/OcBinaryData/Resources/Label/EFIBoot.l2x differ diff --git a/OcBinaryData/Resources/Label/EFIBoot.lbl b/OcBinaryData/Resources/Label/EFIBoot.lbl new file mode 100755 index 0000000..28f1a31 Binary files /dev/null and b/OcBinaryData/Resources/Label/EFIBoot.lbl differ diff --git a/OcBinaryData/Resources/Label/Other.l2x b/OcBinaryData/Resources/Label/Other.l2x new file mode 100755 index 0000000..ee05430 Binary files /dev/null and b/OcBinaryData/Resources/Label/Other.l2x differ diff --git a/OcBinaryData/Resources/Label/Other.lbl b/OcBinaryData/Resources/Label/Other.lbl new file mode 100755 index 0000000..be76830 Binary files /dev/null and b/OcBinaryData/Resources/Label/Other.lbl differ diff --git a/OcBinaryData/Resources/Label/ResetNVRAM.l2x b/OcBinaryData/Resources/Label/ResetNVRAM.l2x new file mode 100755 index 0000000..37c9425 Binary files /dev/null and b/OcBinaryData/Resources/Label/ResetNVRAM.l2x differ diff --git a/OcBinaryData/Resources/Label/ResetNVRAM.lbl b/OcBinaryData/Resources/Label/ResetNVRAM.lbl new file mode 100755 index 0000000..d64bd59 Binary files /dev/null and b/OcBinaryData/Resources/Label/ResetNVRAM.lbl differ diff --git a/OcBinaryData/Resources/Label/SIPDisabled.l2x b/OcBinaryData/Resources/Label/SIPDisabled.l2x new file mode 100755 index 0000000..73293ba Binary files /dev/null and b/OcBinaryData/Resources/Label/SIPDisabled.l2x differ diff --git a/OcBinaryData/Resources/Label/SIPDisabled.lbl b/OcBinaryData/Resources/Label/SIPDisabled.lbl new file mode 100755 index 0000000..6a16cf9 Binary files /dev/null and b/OcBinaryData/Resources/Label/SIPDisabled.lbl differ diff --git a/OcBinaryData/Resources/Label/SIPEnabled.l2x b/OcBinaryData/Resources/Label/SIPEnabled.l2x new file mode 100755 index 0000000..41faffa Binary files /dev/null and b/OcBinaryData/Resources/Label/SIPEnabled.l2x differ diff --git a/OcBinaryData/Resources/Label/SIPEnabled.lbl b/OcBinaryData/Resources/Label/SIPEnabled.lbl new file mode 100755 index 0000000..c943e6a Binary files /dev/null and b/OcBinaryData/Resources/Label/SIPEnabled.lbl differ diff --git a/OcBinaryData/Resources/Label/Shell.l2x b/OcBinaryData/Resources/Label/Shell.l2x new file mode 100755 index 0000000..4193b25 Binary files /dev/null and b/OcBinaryData/Resources/Label/Shell.l2x differ diff --git a/OcBinaryData/Resources/Label/Shell.lbl b/OcBinaryData/Resources/Label/Shell.lbl new file mode 100755 index 0000000..06dc4ac Binary files /dev/null and b/OcBinaryData/Resources/Label/Shell.lbl differ diff --git a/OcBinaryData/Resources/Label/Tool.l2x b/OcBinaryData/Resources/Label/Tool.l2x new file mode 100755 index 0000000..9eb557a Binary files /dev/null and b/OcBinaryData/Resources/Label/Tool.l2x differ diff --git a/OcBinaryData/Resources/Label/Tool.lbl b/OcBinaryData/Resources/Label/Tool.lbl new file mode 100755 index 0000000..4ca11ce Binary files /dev/null and b/OcBinaryData/Resources/Label/Tool.lbl differ diff --git a/OcBinaryData/Resources/Label/Windows.l2x b/OcBinaryData/Resources/Label/Windows.l2x new file mode 100755 index 0000000..87b014e Binary files /dev/null and b/OcBinaryData/Resources/Label/Windows.l2x differ diff --git a/OcBinaryData/Resources/Label/Windows.lbl b/OcBinaryData/Resources/Label/Windows.lbl new file mode 100755 index 0000000..be97d86 Binary files /dev/null and b/OcBinaryData/Resources/Label/Windows.lbl differ diff --git a/OpCore-Simplify.bat b/OpCore-Simplify.bat new file mode 100755 index 0000000..457c6b5 --- /dev/null +++ b/OpCore-Simplify.bat @@ -0,0 +1,397 @@ +@echo off +REM Get our local path before delayed expansion - allows ! in path +set "thisDir=%~dp0" + +setlocal enableDelayedExpansion +REM Setup initial vars +set "script_name=" +set /a tried=0 +set "toask=yes" +set "pause_on_error=yes" +set "py2v=" +set "py2path=" +set "py3v=" +set "py3path=" +set "pypath=" +set "targetpy=3" + +REM use_py3: +REM TRUE = Use if found, use py2 otherwise +REM FALSE = Use py2 +REM FORCE = Use py3 +set "use_py3=TRUE" + +REM We'll parse if the first argument passed is +REM --install-python and if so, we'll just install +set "just_installing=FALSE" + +REM Get the system32 (or equivalent) path +call :getsyspath "syspath" + +REM Make sure the syspath exists +if "!syspath!" == "" ( + if exist "%SYSTEMROOT%\system32\cmd.exe" ( + if exist "%SYSTEMROOT%\system32\reg.exe" ( + if exist "%SYSTEMROOT%\system32\where.exe" ( + REM Fall back on the default path if it exists + set "ComSpec=%SYSTEMROOT%\system32\cmd.exe" + set "syspath=%SYSTEMROOT%\system32\" + ) + ) + ) + if "!syspath!" == "" ( + cls + echo ### ### + echo # Warning # + echo ### ### + echo. + echo Could not locate cmd.exe, reg.exe, or where.exe + echo. + echo Please ensure your ComSpec environment variable is properly configured and + echo points directly to cmd.exe, then try again. + echo. + echo Current CompSpec Value: "%ComSpec%" + echo. + echo Press [enter] to quit. + pause > nul + exit /b 1 + ) +) + +if "%~1" == "--install-python" ( + set "just_installing=TRUE" + goto installpy +) + +goto checkscript + +:checkscript +REM Check for our script first +set "looking_for=!script_name!" +if "!script_name!" == "" ( + set "looking_for=%~n0.py or %~n0.command" + set "script_name=%~n0.py" + if not exist "!thisDir!\!script_name!" ( + set "script_name=%~n0.command" + ) +) +if not exist "!thisDir!\!script_name!" ( + echo Could not find !looking_for!. + echo Please make sure to run this script from the same directory + echo as !looking_for!. + echo. + echo Press [enter] to quit. + pause > nul + exit /b 1 +) +goto checkpy + +:checkpy +call :updatepath +for /f "USEBACKQ tokens=*" %%x in (`!syspath!where.exe python 2^> nul`) do ( call :checkpyversion "%%x" "py2v" "py2path" "py3v" "py3path" ) +for /f "USEBACKQ tokens=*" %%x in (`!syspath!where.exe python3 2^> nul`) do ( call :checkpyversion "%%x" "py2v" "py2path" "py3v" "py3path" ) +for /f "USEBACKQ tokens=*" %%x in (`!syspath!where.exe py 2^> nul`) do ( call :checkpylauncher "%%x" "py2v" "py2path" "py3v" "py3path" ) +REM Walk our returns to see if we need to install +if /i "!use_py3!" == "FALSE" ( + set "targetpy=2" + set "pypath=!py2path!" +) else if /i "!use_py3!" == "FORCE" ( + set "pypath=!py3path!" +) else if /i "!use_py3!" == "TRUE" ( + set "pypath=!py3path!" + if "!pypath!" == "" set "pypath=!py2path!" +) +if not "!pypath!" == "" ( + goto runscript +) +if !tried! lss 1 ( + if /i "!toask!"=="yes" ( + REM Better ask permission first + goto askinstall + ) else ( + goto installpy + ) +) else ( + cls + echo ### ### + echo # Warning # + echo ### ### + echo. + REM Couldn't install for whatever reason - give the error message + echo Python is not installed or not found in your PATH var. + echo Please install it from https://www.python.org/downloads/windows/ + echo. + echo Make sure you check the box labeled: + echo. + echo "Add Python X.X to PATH" + echo. + echo Where X.X is the py version you're installing. + echo. + echo Press [enter] to quit. + pause > nul + exit /b 1 +) +goto runscript + +:checkpylauncher +REM Attempt to check the latest python 2 and 3 versions via the py launcher +for /f "USEBACKQ tokens=*" %%x in (`%~1 -2 -c "import sys; print(sys.executable)" 2^> nul`) do ( call :checkpyversion "%%x" "%~2" "%~3" "%~4" "%~5" ) +for /f "USEBACKQ tokens=*" %%x in (`%~1 -3 -c "import sys; print(sys.executable)" 2^> nul`) do ( call :checkpyversion "%%x" "%~2" "%~3" "%~4" "%~5" ) +goto :EOF + +:checkpyversion +set "version="&for /f "tokens=2* USEBACKQ delims= " %%a in (`"%~1" -V 2^>^&1`) do ( + REM Ensure we have a version number + call :isnumber "%%a" + if not "!errorlevel!" == "0" goto :EOF + set "version=%%a" +) +if not defined version goto :EOF +if "!version:~0,1!" == "2" ( + REM Python 2 + call :comparepyversion "!version!" "!%~2!" + if "!errorlevel!" == "1" ( + set "%~2=!version!" + set "%~3=%~1" + ) +) else ( + REM Python 3 + call :comparepyversion "!version!" "!%~4!" + if "!errorlevel!" == "1" ( + set "%~4=!version!" + set "%~5=%~1" + ) +) +goto :EOF + +:isnumber +set "var="&for /f "delims=0123456789." %%i in ("%~1") do set var=%%i +if defined var (exit /b 1) +exit /b 0 + +:comparepyversion +REM Exits with status 0 if equal, 1 if v1 gtr v2, 2 if v1 lss v2 +for /f "tokens=1,2,3 delims=." %%a in ("%~1") do ( + set a1=%%a + set a2=%%b + set a3=%%c +) +for /f "tokens=1,2,3 delims=." %%a in ("%~2") do ( + set b1=%%a + set b2=%%b + set b3=%%c +) +if not defined a1 set a1=0 +if not defined a2 set a2=0 +if not defined a3 set a3=0 +if not defined b1 set b1=0 +if not defined b2 set b2=0 +if not defined b3 set b3=0 +if %a1% gtr %b1% exit /b 1 +if %a1% lss %b1% exit /b 2 +if %a2% gtr %b2% exit /b 1 +if %a2% lss %b2% exit /b 2 +if %a3% gtr %b3% exit /b 1 +if %a3% lss %b3% exit /b 2 +exit /b 0 + +:askinstall +cls +echo ### ### +echo # Python Not Found # +echo ### ### +echo. +echo Python !targetpy! was not found on the system or in the PATH var. +echo. +set /p "menu=Would you like to install it now? [y/n]: " +if /i "!menu!"=="y" ( + REM We got the OK - install it + goto installpy +) else if "!menu!"=="n" ( + REM No OK here... + set /a tried=!tried!+1 + goto checkpy +) +REM Incorrect answer - go back +goto askinstall + +:installpy +REM This will attempt to download and install python +REM First we get the html for the python downloads page for Windows +set /a tried=!tried!+1 +cls +echo ### ### +echo # Installing Python # +echo ### ### +echo. +echo Gathering info from https://www.python.org/downloads/windows/... +powershell -command "[Net.ServicePointManager]::SecurityProtocol=[Net.SecurityProtocolType]::Tls12;(new-object System.Net.WebClient).DownloadFile('https://www.python.org/downloads/windows/','%TEMP%\pyurl.txt')" +REM Extract it if it's gzip compressed +powershell -command "$infile='%TEMP%\pyurl.txt';$outfile='%TEMP%\pyurl.temp';try{$input=New-Object System.IO.FileStream $infile,([IO.FileMode]::Open),([IO.FileAccess]::Read),([IO.FileShare]::Read);$output=New-Object System.IO.FileStream $outfile,([IO.FileMode]::Create),([IO.FileAccess]::Write),([IO.FileShare]::None);$gzipStream=New-Object System.IO.Compression.GzipStream $input,([IO.Compression.CompressionMode]::Decompress);$buffer=New-Object byte[](1024);while($true){$read=$gzipstream.Read($buffer,0,1024);if($read -le 0){break};$output.Write($buffer,0,$read)};$gzipStream.Close();$output.Close();$input.Close();Move-Item -Path $outfile -Destination $infile -Force}catch{}" +if not exist "%TEMP%\pyurl.txt" ( + if /i "!just_installing!" == "TRUE" ( + echo Failed to get info + exit /b 1 + ) else ( + goto checkpy + ) +) +echo Parsing for latest... +pushd "%TEMP%" +:: Version detection code slimmed by LussacZheng (https://github.com/corpnewt/gibMacOS/issues/20) +for /f "tokens=9 delims=< " %%x in ('findstr /i /c:"Latest Python !targetpy! Release" pyurl.txt') do ( set "release=%%x" ) +popd +if "!release!" == "" ( + if /i "!just_installing!" == "TRUE" ( + echo Failed to get python version + exit /b 1 + ) else ( + goto checkpy + ) +) +echo Found Python !release! - Downloading... +REM Let's delete our txt file now - we no longer need it +del "%TEMP%\pyurl.txt" +REM At this point - we should have the version number. +REM We can build the url like so: "https://www.python.org/ftp/python/[version]/python-[version]-amd64.exe" +set "url=https://www.python.org/ftp/python/!release!/python-!release!-amd64.exe" +set "pytype=exe" +if "!targetpy!" == "2" ( + set "url=https://www.python.org/ftp/python/!release!/python-!release!.amd64.msi" + set "pytype=msi" +) +REM Now we download it with our slick powershell command +powershell -command "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; (new-object System.Net.WebClient).DownloadFile('!url!','%TEMP%\pyinstall.!pytype!')" +REM If it doesn't exist - we bail +if not exist "%TEMP%\pyinstall.!pytype!" ( + if /i "!just_installing!" == "TRUE" ( + echo Failed to download installer + exit /b 1 + ) else ( + goto checkpy + ) +) +REM It should exist at this point - let's run it to install silently +echo Installing... +pushd "%TEMP%" +if /i "!pytype!" == "exe" ( + echo pyinstall.exe /quiet PrependPath=1 Include_test=0 Shortcuts=0 Include_launcher=0 + pyinstall.exe /quiet PrependPath=1 Include_test=0 Shortcuts=0 Include_launcher=0 +) else ( + set "foldername=!release:.=!" + echo msiexec /i pyinstall.msi /qb ADDLOCAL=ALL TARGETDIR="%LocalAppData%\Programs\Python\Python!foldername:~0,2!" + msiexec /i pyinstall.msi /qb ADDLOCAL=ALL TARGETDIR="%LocalAppData%\Programs\Python\Python!foldername:~0,2!" +) +popd +echo Installer finished with %ERRORLEVEL% status. +REM Now we should be able to delete the installer and check for py again +del "%TEMP%\pyinstall.!pytype!" +REM If it worked, then we should have python in our PATH +REM this does not get updated right away though - let's try +REM manually updating the local PATH var +call :updatepath +if /i "!just_installing!" == "TRUE" ( + echo. + echo Done. +) else ( + goto checkpy +) +exit /b + +:runscript +REM Python found +cls +set "args=%*" +set "args=!args:"=!" +"!pypath!" -m pip install -r "!thisDir!\requirements.txt" +if "!args!"=="" ( + "!pypath!" "!thisDir!!script_name!" +) else ( + "!pypath!" "!thisDir!!script_name!" %* +) +if /i "!pause_on_error!" == "yes" ( + if not "%ERRORLEVEL%" == "0" ( + echo Script exited with error code: %ERRORLEVEL% + echo. + ) + echo Press Enter to exit... + pause > nul +) +goto :EOF + +:undouble +REM Helper function to strip doubles of a single character out of a string recursively +set "string_value=%~2" +:undouble_continue +set "check=!string_value:%~3%~3=%~3!" +if not "!check!" == "!string_value!" ( + set "string_value=!check!" + goto :undouble_continue +) +set "%~1=!check!" +goto :EOF + +:updatepath +set "spath=" +set "upath=" +for /f "USEBACKQ tokens=2* delims= " %%i in (`!syspath!reg.exe query "HKCU\Environment" /v "Path" 2^> nul`) do ( if not "%%j" == "" set "upath=%%j" ) +for /f "USEBACKQ tokens=2* delims= " %%i in (`!syspath!reg.exe query "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /v "Path" 2^> nul`) do ( if not "%%j" == "" set "spath=%%j" ) +if not "%spath%" == "" ( + REM We got something in the system path + set "PATH=%spath%" + if not "%upath%" == "" ( + REM We also have something in the user path + set "PATH=%PATH%;%upath%" + ) +) else if not "%upath%" == "" ( + set "PATH=%upath%" +) +REM Remove double semicolons from the adjusted PATH +call :undouble "PATH" "%PATH%" ";" +goto :EOF + +:getsyspath +REM Helper method to return a valid path to cmd.exe, reg.exe, and where.exe by +REM walking the ComSpec var - will also repair it in memory if need be +REM Strip double semi-colons +call :undouble "temppath" "%ComSpec%" ";" + +REM Dirty hack to leverage the "line feed" approach - there are some odd side +REM effects with this. Do not use this variable name in comments near this +REM line - as it seems to behave erradically. +(set LF=^ +%=this line is empty=% +) +REM Replace instances of semi-colons with a line feed and wrap +REM in parenthesis to work around some strange batch behavior +set "testpath=%temppath:;=!LF!%" + +REM Let's walk each path and test if cmd.exe, reg.exe, and where.exe exist there +set /a found=0 +for /f "tokens=* delims=" %%i in ("!testpath!") do ( + REM Only continue if we haven't found it yet + if not "%%i" == "" ( + if !found! lss 1 ( + set "checkpath=%%i" + REM Remove "cmd.exe" from the end if it exists + if /i "!checkpath:~-7!" == "cmd.exe" ( + set "checkpath=!checkpath:~0,-7!" + ) + REM Pad the end with a backslash if needed + if not "!checkpath:~-1!" == "\" ( + set "checkpath=!checkpath!\" + ) + REM Let's see if cmd, reg, and where exist there - and set it if so + if EXIST "!checkpath!cmd.exe" ( + if EXIST "!checkpath!reg.exe" ( + if EXIST "!checkpath!where.exe" ( + set /a found=1 + set "ComSpec=!checkpath!cmd.exe" + set "%~1=!checkpath!" + ) + ) + ) + ) + ) +) +goto :EOF \ No newline at end of file diff --git a/OpCore-Simplify.command b/OpCore-Simplify.command new file mode 100755 index 0000000..7c2c9f5 --- /dev/null +++ b/OpCore-Simplify.command @@ -0,0 +1,302 @@ +#!/usr/bin/env bash + +# Get the curent directory, the script name +# and the script name with "py" substituted for the extension. +args=( "$@" ) +dir="${0%/*}" +script="${0##*/}" +target="${script%.*}.py" + +# use_py3: +# TRUE = Use if found, use py2 otherwise +# FALSE = Use py2 +# FORCE = Use py3 +use_py3="TRUE" + +tempdir="" + +compare_to_version () { + # Compares our OS version to the passed OS version, and + # return a 1 if we match the passed compare type, or a 0 if we don't. + # $1 = 0 (equal), 1 (greater), 2 (less), 3 (gequal), 4 (lequal) + # $2 = OS version to compare ours to + if [ -z "$1" ] || [ -z "$2" ]; then + # Missing info - bail. + return + fi + local current_os= comp= + current_os="$(sw_vers -productVersion)" + comp="$(vercomp "$current_os" "$2")" + # Check gequal and lequal first + if [[ "$1" == "3" && ("$comp" == "1" || "$comp" == "0") ]] || [[ "$1" == "4" && ("$comp" == "2" || "$comp" == "0") ]] || [[ "$comp" == "$1" ]]; then + # Matched + echo "1" + else + # No match + echo "0" + fi +} + +set_use_py3_if () { + # Auto sets the "use_py3" variable based on + # conditions passed + # $1 = 0 (equal), 1 (greater), 2 (less), 3 (gequal), 4 (lequal) + # $2 = OS version to compare + # $3 = TRUE/FALSE/FORCE in case of match + if [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ]; then + # Missing vars - bail with no changes. + return + fi + if [ "$(compare_to_version "$1" "$2")" == "1" ]; then + use_py3="$3" + fi +} + +get_remote_py_version () { + local pyurl= py_html= py_vers= py_num="3" + pyurl="https://www.python.org/downloads/macos/" + py_html="$(curl -L $pyurl 2>&1)" + if [ -z "$use_py3" ]; then + use_py3="TRUE" + fi + if [ "$use_py3" == "FALSE" ]; then + py_num="2" + fi + py_vers="$(echo "$py_html" | grep -i "Latest Python $py_num Release" | awk '{print $8}' | cut -d'<' -f1)" + echo "$py_vers" +} + +download_py () { + local vers="$1" url= + clear + echo " ### ###" + echo " # Downloading Python #" + echo "### ###" + echo + if [ -z "$vers" ]; then + echo "Gathering latest version..." + vers="$(get_remote_py_version)" + fi + if [ -z "$vers" ]; then + # Didn't get it still - bail + print_error + fi + echo "Located Version: $vers" + echo + echo "Building download url..." + url="$(curl -L https://www.python.org/downloads/release/python-${vers//./}/ 2>&1 | grep -iE "python-$vers-macos.*.pkg\"" | awk -F'"' '{ print $2 }')" + if [ -z "$url" ]; then + # Couldn't get the URL - bail + print_error + fi + echo " - $url" + echo + echo "Downloading..." + echo + # Create a temp dir and download to it + tempdir="$(mktemp -d 2>/dev/null || mktemp -d -t 'tempdir')" + curl "$url" -o "$tempdir/python.pkg" + if [ "$?" != "0" ]; then + echo + echo " - Failed to download python installer!" + echo + exit $? + fi + echo + echo "Running python install package..." + sudo installer -pkg "$tempdir/python.pkg" -target / + if [ "$?" != "0" ]; then + echo + echo " - Failed to install python!" + echo + exit $? + fi + echo + vers_folder="Python $(echo "$vers" | cut -d'.' -f1 -f2)" + if [ -f "/Applications/$vers_folder/Install Certificates.command" ]; then + # Certs script exists - let's execute that to make sure our certificates are updated + echo "Updating Certificates..." + echo + "/Applications/$vers_folder/Install Certificates.command" + echo + fi + echo "Cleaning up..." + cleanup + echo + # Now we check for py again + echo "Rechecking py..." + downloaded="TRUE" + clear + main +} + +cleanup () { + if [ -d "$tempdir" ]; then + rm -Rf "$tempdir" + fi +} + +print_error() { + clear + cleanup + echo " ### ###" + echo " # Python Not Found #" + echo "### ###" + echo + echo "Python is not installed or not found in your PATH var." + echo + echo "Please go to https://www.python.org/downloads/macos/" + echo "to download and install the latest version." + echo + exit 1 +} + +print_target_missing() { + clear + cleanup + echo " ### ###" + echo " # Target Not Found #" + echo "### ###" + echo + echo "Could not locate $target!" + echo + exit 1 +} + +format_version () { + local vers="$1" + echo "$(echo "$1" | awk -F. '{ printf("%d%03d%03d%03d\n", $1,$2,$3,$4); }')" +} + +vercomp () { + # Modified from: https://apple.stackexchange.com/a/123408/11374 + local ver1="$(format_version "$1")" ver2="$(format_version "$2")" + if [ $ver1 -gt $ver2 ]; then + echo "1" + elif [ $ver1 -lt $ver2 ]; then + echo "2" + else + echo "0" + fi +} + +get_local_python_version() { + # $1 = Python bin name (defaults to python3) + # Echoes the path to the highest version of the passed python bin if any + local py_name="$1" max_version= python= python_version= python_path= + if [ -z "$py_name" ]; then + py_name="python3" + fi + py_list="$(which -a "$py_name" 2>/dev/null)" + # Walk that newline separated list + while read python; do + if [ -z "$python" ]; then + # Got a blank line - skip + continue + fi + if [ "$check_py3_stub" == "1" ] && [ "$python" == "/usr/bin/python3" ]; then + # See if we have a valid developer path + xcode-select -p > /dev/null 2>&1 + if [ "$?" != "0" ]; then + # /usr/bin/python3 path - but no valid developer dir + continue + fi + fi + python_version="$(get_python_version $python)" + if [ -z "$python_version" ]; then + # Didn't find a py version - skip + continue + fi + # Got the py version - compare to our max + if [ -z "$max_version" ] || [ "$(vercomp "$python_version" "$max_version")" == "1" ]; then + # Max not set, or less than the current - update it + max_version="$python_version" + python_path="$python" + fi + done <<< "$py_list" + echo "$python_path" +} + +get_python_version() { + local py_path="$1" py_version= + # Get the python version by piping stderr into stdout (for py2), then grepping the output for + # the word "python", getting the second element, and grepping for an alphanumeric version number + py_version="$($py_path -V 2>&1 | grep -i python | cut -d' ' -f2 | grep -E "[A-Za-z\d\.]+")" + if [ ! -z "$py_version" ]; then + echo "$py_version" + fi +} + +prompt_and_download() { + if [ "$downloaded" != "FALSE" ]; then + # We already tried to download - just bail + print_error + fi + clear + echo " ### ###" + echo " # Python Not Found #" + echo "### ###" + echo + target_py="Python 3" + printed_py="Python 2 or 3" + if [ "$use_py3" == "FORCE" ]; then + printed_py="Python 3" + elif [ "$use_py3" == "FALSE" ]; then + target_py="Python 2" + printed_py="Python 2" + fi + echo "Could not locate $printed_py!" + echo + echo "This script requires $printed_py to run." + echo + while true; do + read -p "Would you like to install the latest $target_py now? (y/n): " yn + case $yn in + [Yy]* ) download_py;break;; + [Nn]* ) print_error;; + esac + done +} + +main() { + local python= version= + # Verify our target exists + if [ ! -f "$dir/$target" ]; then + # Doesn't exist + print_target_missing + fi + if [ -z "$use_py3" ]; then + use_py3="TRUE" + fi + if [ "$use_py3" != "FALSE" ]; then + # Check for py3 first + python="$(get_local_python_version python3)" + fi + if [ "$use_py3" != "FORCE" ] && [ -z "$python" ]; then + # We aren't using py3 explicitly, and we don't already have a path + python="$(get_local_python_version python2)" + if [ -z "$python" ]; then + # Try just looking for "python" + python="$(get_local_python_version python)" + fi + fi + if [ -z "$python" ]; then + # Didn't ever find it - prompt + prompt_and_download + return 1 + fi + # Found it - start our script and pass all args + "$python" -m pip install -r "$dir/requirements.txt" + "$python" "$dir/$target" "${args[@]}" +} + +# Check to see if we need to force based on +# macOS version. 10.15 has a dummy python3 version +# that can trip up some py3 detection in other scripts. +# set_use_py3_if "3" "10.15" "FORCE" +downloaded="FALSE" +# Check for the aforementioned /usr/bin/python3 stub if +# our OS version is 10.15 or greater. +check_py3_stub="$(compare_to_version "3" "10.15")" +trap cleanup EXIT +main diff --git a/OpCore-Simplify.py b/OpCore-Simplify.py new file mode 100755 index 0000000..18c9828 --- /dev/null +++ b/OpCore-Simplify.py @@ -0,0 +1,232 @@ +from Scripts import aida64 +from Scripts import compatibility_checker +from Scripts import efi_builder +from Scripts import gathering_files +from Scripts import utils +import os + +class OCPE: + def __init__(self): + self.u = utils.Utils("OpCore Simplify") + self.o = gathering_files.gatheringFiles() + self.a = aida64.AIDA64() + self.c = compatibility_checker.CompatibilityChecker() + self.b = efi_builder.builder() + self.u = utils.Utils() + self.current_version = "0.0.1" + self.hardware = None + self.compatibility = None + self.macos_version = None + self.macos_version_data = { + "24": "macOS Sequoia 15 (Beta)", + "23": "macOS Sonoma 14 (14.4+)", + "22": "macOS Ventura 13", + "21": "macOS Monterey 12", + "20": "macOS Big Sur 11", + "19": "macOS Catalina 10.15", + "18": "macOS Mojave 10.14", + "17": "macOS High Sierra 10.13" + } + self.result_dir = os.path.join(os.getcwd(), "Results") + + def check_for_update(self): + self.u.head("Check for update") + print("") + print(f"Current script version: {self.current_version}") + latest_version = self.u.check_latest_version() + print(f"Latest script version: {latest_version}") + print("") + if latest_version and latest_version > self.current_version: + print(self.u.message("An update is available at \"https://github.com/lzhoang2801/OpCore-Simplify\"", "reminder")) + print(self.u.message("Please download the latest version to ensure the best experience.", "reminder")) + print("") + self.u.request_input() + else: + return + self.u.exit_program() + + def gathering_files(self): + self.u.head("Gathering Files") + print("") + print("Please wait for download OpenCore NO ACPI, kexts and macserial...") + print("") + + try: + self.o.gathering_bootloader_kexts() + except Exception as e: + print("") + print(self.u.message(e, "warning")) + print("") + self.u.request_input() + if len(os.listdir(self.o.ock_files_dir)) < 54: + os.remove(self.o.download_history_file) + raise Exception("The download process was not completed. Please try again once the REST API request quota is reset in about an hour") + return + + def select_aida64_report(self): + while True: + self.u.head("Select your AIDA64 report") + print("") + print("To ensure the best results, please follow these instructions before generating the AIDA64 report:") + print("") + print(" 1. Install all available drivers if possible (skip this step when using Windows PE)") + print(" 2. Use the latest version of AIDA64 Extreme, available at \"https://aida64.com/downloads\"") + print(" 3. In the Report Wizard, ensure \"Hardware-related pages\" is selected on the Report Profiles\n and choose the \"HTML\" format") + print("") + print("Q. Quit") + print("") + user_input = self.u.request_input("Please drag and drop your AIDA64 report here: (*HTML/.htm) ") + if user_input.lower() == "q": + self.u.exit_program() + path = self.u.normalize_path(user_input) + if not path: + continue + self.hardware = self.a.dump(path) + return + + def hardware_report(self): + if not self.hardware: + self.select_aida64_report() + + self.u.head("Review the hardware information") + contents = ["\n"] + for index, device_type in enumerate(self.hardware, start=1): + contents.append("{}. {}{}".format(index, device_type, "" if device_type == "Intel MEI" else ":")) + + if device_type == "SD Controller": + contents.append("{}* {}".format(" "*4, self.hardware.get(device_type).get("Device Description"))) + elif device_type == "Intel MEI": + pass + else: + for device_name, device_props in self.hardware.get(device_type).items(): + if "Controllers" in device_name or "Devices" in device_name or "Drives" in device_name: + contents.append("{}* {}:".format(" "*4, device_name)) + for device_name_child, device_props_child in device_props.items(): + contents.append("{}- {}".format(" "*8, device_name_child)) + else: + contents.append("{}* {}{}".format(" "*4, device_name, f": {device_props}" if isinstance(device_props, str) else "")) + content = "\n".join(contents) + "\n" + print(content, end="") + self.u.adjust_window_size(content) + self.u.request_input() + return + + def compatibility_check(self): + if not self.hardware: + self.select_aida64_report() + + self.hardware = self.c.check_compatibility(self.hardware) + self.compatibility = self.hardware.get("Compatibility") + supported_macOS_version = self.compatibility.get("macOS Version") + min_verion = supported_macOS_version.get("Min Version") + max_verion = supported_macOS_version.get("Max Version") + + self.u.head("Compatibility Checker") + print("") + if max_verion == -1: + self.u.request_input("Your hardware is not compatible with macOS!") + self.u.exit_program() + print("* Supported macOS Version:") + print("{}Max Version: {}".format(" "*4, self.macos_version_data[str(max_verion)])) + print("{}Min Version: {}".format(" "*4, self.macos_version_data[str(min_verion)])) + if self.compatibility.get("Unsupported Devices"): + print("* Unsupported devices:") + for index, device in enumerate(self.compatibility.get("Unsupported Devices"), start=1): + print("{}{}. {}".format(" "*4, index, device)) + print("") + self.u.request_input() + return + + def select_macos_version(self): + if not self.compatibility: + self.compatibility_check() + + supported_macOS_version = self.compatibility.get("macOS Version") + min_verion = supported_macOS_version.get("Min Version") + max_verion = supported_macOS_version.get("Max Version") + + while True: + self.u.head("Select macOS Version") + print("") + for index, macos_version in enumerate(range(max_verion, min_verion - 1, -1), start=1): + print("{}. {}".format(index, self.macos_version_data[str(macos_version)])) + print("") + print("Q. Quit") + print("") + option = self.u.request_input("Please select the macOS version you wish to install: ") + if option.lower() == "q": + self.u.exit_program() + if "1" <= option <= str(max_verion - min_verion + 1): + self.macos_version = max_verion - int(option) + 1 + return + else: + continue + + def show_result(self): + def generate_tree_content(dir_path, prefix=''): + contents = sorted(os.listdir(dir_path)) + pointers = ['├── '] * (len(contents) - 1) + ['└── '] + content = "" + + if not contents: + content += prefix + '└── (empty)\n' + elif ".kext" in ", ".join(contents): + pointers = pointers[:-1] + ['├── '] + ['└── '] + contents.append("USBMap.kext ({})".format(self.u.message("use USBToolBox with the 'Use Native Class' option enabled to create this kext", "reminder"))) + + for pointer, path in zip(pointers, contents): + if path.startswith("."): + continue + + if path.endswith(".dsl"): + path += " ({})".format(self.u.message("adjust the ACPI path accordingly before compiling and using it", "reminder")) + elif path.startswith("itlwm"): + path += " ({})".format(self.u.message("use the HeliPort app to connect to WiFi", "reminder")) + full_path = os.path.join(dir_path, path) + content += f"{prefix + pointer + path}\n" + if os.path.isdir(full_path) and not ".kext" in os.path.splitext(path)[1]: + extension = '│ ' if pointer == '├── ' else ' ' + if "Resources" in path: + content += prefix + extension + '└── ...hidden\n' + else: + content += generate_tree_content(full_path, prefix + extension) + + return content + + efi_dir = os.path.join(self.result_dir, "EFI") + content = "\nYour OpenCore EFI for {} has been built at:".format(self.hardware.get("Motherboard").get("Motherboard Name")) + content += f"\n\t{self.result_dir}\n" + content += "\nEFI\n{}\n".format(generate_tree_content(efi_dir)) + self.u.adjust_window_size(content) + + while True: + self.u.head("Results", resize=False) + print(content) + option = self.u.request_input("Do you want to open the OpenCore EFI folder? (yes/no): ") + if option.lower() == "yes": + self.u.open_folder(self.result_dir) + break + elif option.lower() == "no": + break + return + + def main(self): + self.check_for_update() + self.gathering_files() + self.select_aida64_report() + self.hardware_report() + self.compatibility_check() + self.select_macos_version() + self.b.build_efi(self.hardware, self.macos_version) + self.show_result() + reminder_message = "\n\nIMPORTANT REMINDER: Please make sure you add the USBMap.kext to /EFI/OC/Kext before using this\nOpenCore EFI.\n\n" + self.u.exit_program(o.u.message(reminder_message, "reminder")) + +if __name__ == '__main__': + o = OCPE() + try: + o.main() + except SystemExit: + raise + except BaseException as e: + o.u.exit_program(o.u.message("\nAn error occurred: {}\n".format(e))) diff --git a/README.md b/README.md new file mode 100644 index 0000000..98d6dd7 --- /dev/null +++ b/README.md @@ -0,0 +1,79 @@ +
+
+

OpCore Simplify

+ +

+ A tool designed to simplify the creation of OpenCore EFI. It includes features such as auto-patching DSDT, adding suitable kexts, and customizing the config.plist to make Hackintosh installation easy for beginners. +
+
+ Report Bug + · + Request Feature +

+
+ +
+ Table of Contents +
    +
  1. Features
  2. +
  3. Usage Guide
  4. +
  5. Contributing
  6. +
  7. License
  8. +
  9. Contact
  10. +
+
+ +## Features + +1. **Automatic Updates**: Check and update AMD Vanilla Patches, OpenCore NO ACPI, and kexts automatically. +2. **Hardware Information Gathering**: Use AIDA64 reports to collect detailed hardware information, utilizing USB ID and PCI ID for the most precise compatibility checks. +3. **Comprehensive Hardware Support**: Fully supports all available hardware (excluding legacy hardware). Try and view results on the Compatibility Checker screen. +4. **Enhanced ACPI Patching**: Add various ACPI patches with support from the [SSDTTime](https://github.com/corpnewt/SSDTTime). +5. **Device-Specific Kexts**: Identify and add the correct kexts for devices such as WiFi, ethernet, sound codec, bluetooth, keyboard, mouse, touchpad, USB controller, and SATA controller based on their IDs. +6. **Custom Tweaks**: Apply additional customizations based on a variety of sources and personal experience. + +## Usage Guide + +Follow the steps, customize as needed, and enjoy your optimized system! + +1. Run `OpCore-Simplify.bat` on Windows or `OpCore-Simplify.command` on macOS. + +2. **AIDA64 Report**: Enter the path or drag and drop your AIDA64 report. + - Ensure you follow any instructions on this screen. + +3. **Review Hardware Information**: Verify the detected hardware information and receive compatibility results. + +4. **Select macOS Version**: Choose the compatible macOS version you wish to install. + +5. **Enter ACPI Tables Folder Path**: + - Select `P` to dump ACPI tables from the current machine if it is the same machine used for the AIDA64 report. + +6. **Preview OpenCore EFI Results**: + - Review the generated OpenCore EFI for your hardware. + - Make sure to read any green-highlighted lines (in parentheses). + +7. **USB Mapping**: Use USBToolBox with the 'Use Native Class' option enabled to map USBs and add the resulting kext to `OC/Kexts`. + +8. **Create USB and Install macOS**: Follow the guide at [OpenCore Install Guide](https://dortania.github.io/OpenCore-Install-Guide/installer-guide/) and use the generated OpenCore EFI. + - For troubleshooting issues booting macOS, please refer to the [OpenCore Troubleshooting Guide](https://dortania.github.io/OpenCore-Install-Guide/troubleshooting/troubleshooting.html) or contact me for assistance. + +#### Reference Resources + +- [OpenCore Install Guide](https://dortania.github.io/OpenCore-Install-Guide) (some parts may be outdated) +- [ChefKissNext](https://chefkissnext.netlify.app/guides/hackintosh/) (dedicated to AMD CPU systems) + +## Contributing + +Any contributions you make are **greatly appreciated**. + +If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement". + +**Don't forget to give the project a star! Thanks again!** + +## License + +Distributed under the BSD 3-Clause License. See `LICENSE` for more information. + +## Contact + +Hoang Hong Quan - [@facebook](https://facebook.com/macforce2601) - [@telegram](https://t.me/lzhoang2601) - lzhoang2601@gmail.com \ No newline at end of file diff --git a/Scripts/acpi_guru.py b/Scripts/acpi_guru.py new file mode 100755 index 0000000..8eda0a1 --- /dev/null +++ b/Scripts/acpi_guru.py @@ -0,0 +1,2842 @@ +# Original source: +# https://github.com/corpnewt/SSDTTime/blob/7b3fb78112bf320a1bc6a7e50dddb2b375cb70b0/SSDTTime.py + +from Scripts.datasets import chipset_data +from Scripts.datasets import cpu_data +from Scripts import smbios +from Scripts import dsdt +from Scripts import utils +import os +import binascii +import re +import tempfile +import shutil +import sys +import subprocess + +class ACPIGuru: + def __init__(self): + self.acpi = dsdt.DSDT() + self.smbios = smbios.SMBIOS() + self.utils = utils.Utils() + self.dsdt = None + self.lpc_bus_device = None + self.osi_strings = { + "Windows 2000": "Windows 2000", + "Windows XP": "Windows 2001", + "Windows XP SP1": "Windows 2001 SP1", + "Windows Server 2003": "Windows 2001.1", + "Windows XP SP2": "Windows 2001 SP2", + "Windows Server 2003 SP1": "Windows 2001.1 SP1", + "Windows Vista": "Windows 2006", + "Windows Vista SP1": "Windows 2006 SP1", + "Windows Server 2008": "Windows 2006.1", + "Windows 7, Win Server 2008 R2": "Windows 2009", + "Windows 8, Win Server 2012": "Windows 2012", + "Windows 8.1": "Windows 2013", + "Windows 10": "Windows 2015", + "Windows 10, version 1607": "Windows 2016", + "Windows 10, version 1703": "Windows 2017", + "Windows 10, version 1709": "Windows 2017.2", + "Windows 10, version 1803": "Windows 2018", + "Windows 10, version 1809": "Windows 2018.2", + "Windows 10, version 1903": "Windows 2019", + "Windows 10, version 2004": "Windows 2020", + "Windows 11": "Windows 2021", + "Windows 11, version 22H2": "Windows 2022" + } + self.pre_patches = ( + { + "PrePatch":"GPP7 duplicate _PRW methods", + "Comment" :"GPP7._PRW to XPRW to fix Gigabyte's Mistake", + "Find" :"3708584847500A021406535245470214065350525701085F505257", + "Replace" :"3708584847500A0214065352454702140653505257010858505257" + }, + { + "PrePatch":"GPP7 duplicate UP00 devices", + "Comment" :"GPP7.UP00 to UPXX to fix Gigabyte's Mistake", + "Find" :"1047052F035F53425F50434930475050375B82450455503030", + "Replace" :"1047052F035F53425F50434930475050375B82450455505858" + }, + { + "PrePatch":"GPP6 duplicate _PRW methods", + "Comment" :"GPP6._PRW to XPRW to fix ASRock's Mistake", + "Find" :"47505036085F4144520C04000200140F5F505257", + "Replace" :"47505036085F4144520C04000200140F58505257" + }, + { + "PrePatch":"GPP1 duplicate PTXH devices", + "Comment" :"GPP1.PTXH to XTXH to fix MSI's Mistake", + "Find" :"50545848085F41445200140F", + "Replace" :"58545848085F41445200140F" + } + ) + self.target_irqs = [0, 2, 8, 11] + self.illegal_names = ("XHC1", "EHC1", "EHC2", "PXSX") + self.result = { + "Add": [], + "Patch": [] + } + + def get_unique_name(self,name,target_folder,name_append="-Patched"): + # Get a new file name in the Results folder so we don't override the original + name = os.path.basename(name) + ext = "" if not "." in name else name.split(".")[-1] + if ext: name = name[:-len(ext)-1] + if name_append: name = name+str(name_append) + check_name = ".".join((name,ext)) if ext else name + if not os.path.exists(os.path.join(target_folder,check_name)): + return check_name + # We need a unique name + num = 1 + while True: + check_name = "{}-{}".format(name,num) + if ext: check_name += "."+ext + if not os.path.exists(os.path.join(target_folder,check_name)): + return check_name + num += 1 # Increment our counter + + def get_unique_device(self, path, base_name, starting_number=0, used_names = []): + # Appends a hex number until a unique device is found + while True: + hex_num = hex(starting_number).replace("0x","").upper() + name = base_name[:-1*len(hex_num)]+hex_num + if not len(self.acpi.get_device_paths("."+name)) and not name in used_names: + return (name,starting_number) + starting_number += 1 + + def sorted_nicely(self, l): + convert = lambda text: int(text) if text.isdigit() else text + alphanum_key = lambda key: [ convert(c) for c in re.split('([0-9]+)', key.lower()) ] + return sorted(l, key = alphanum_key) + + def read_dsdt(self, path): + if not path: + return + tables = [] + trouble_dsdt = None + fixed = False + temp = None + prior_tables = self.acpi.acpi_tables # Retain in case of failure + # Clear any existing tables so we load anew + self.acpi.acpi_tables = {} + if os.path.isdir(path): + print("Gathering valid tables from {}...\n".format(os.path.basename(path))) + for t in self.sorted_nicely(os.listdir(path)): + if self.acpi.table_is_valid(path,t): + print(" - {}".format(t)) + tables.append(t) + if not tables: + # Check if there's an ACPI directory within the passed + # directory - this may indicate SysReport was dropped + if os.path.isdir(os.path.join(path,"ACPI")): + # Rerun this function with that updated path + return self.read_dsdt(os.path.join(path,"ACPI")) + print(" - No valid .aml files were found!") + print("") + self.utils.request_input() + # Restore any prior tables + self.acpi.acpi_tables = prior_tables + return + print("") + # We got at least one file - let's look for the DSDT specifically + # and try to load that as-is. If it doesn't load, we'll have to + # manage everything with temp folders + dsdt_list = [x for x in tables if self.acpi._table_signature(path,x) == "DSDT"] + if len(dsdt_list) > 1: + print("Multiple files with DSDT signature passed:") + for d in self.sorted_nicely(dsdt_list): + print(" - {}".format(d)) + print("\nOnly one is allowed at a time. Please remove one of the above and try again.") + print("") + self.utils.request_input() + # Restore any prior tables + self.acpi.acpi_tables = prior_tables + return + # Get the DSDT, if any + dsdt = dsdt_list[0] if len(dsdt_list) else None + if dsdt: # Try to load it and see if it causes problems + print("Disassembling {} to verify if pre-patches are needed...".format(dsdt)) + if not self.acpi.load(os.path.join(path,dsdt))[0]: + trouble_dsdt = dsdt + else: + print("\nDisassembled successfully!\n") + elif os.path.isfile(path): + #print("Loading {}...".format(os.path.basename(path))) + if self.acpi.load(path)[0]: + #print("\nDone.") + # If it loads fine - just return the path + # to the parent directory + return os.path.dirname(path) + if not self.acpi._table_signature(path) == "DSDT": + # Not a DSDT, we aren't applying pre-patches + print("\n{} could not be disassembled!".format(os.path.basename(path))) + print("") + self.utils.request_input() + # Restore any prior tables + self.acpi.acpi_tables = prior_tables + return + # It didn't load - set it as the trouble file + trouble_dsdt = os.path.basename(path) + # Put the table in the tables list, and adjust + # the path to represent the parent dir + tables.append(os.path.basename(path)) + path = os.path.dirname(path) + else: + print("Passed file/folder does not exist!") + print("") + self.utils.request_input() + # Restore any prior tables + self.acpi.acpi_tables = prior_tables + return + # If we got here - check if we have a trouble_dsdt. + if trouble_dsdt: + # We need to move our ACPI files to a temp folder + # then try patching the DSDT there + temp = tempfile.mkdtemp() + for table in tables: + shutil.copy( + os.path.join(path,table), + temp + ) + # Get a reference to the new trouble file + trouble_path = os.path.join(temp,trouble_dsdt) + # Now we try patching it + print("Checking available pre-patches...") + print("Loading {} into memory...".format(trouble_dsdt)) + with open(trouble_path,"rb") as f: + d = f.read() + res = self.acpi.check_output(self.output) + target_name = self.get_unique_name(trouble_dsdt,res,name_append="-Patched") + patches = [] + print("Iterating patches...\n") + for p in self.pre_patches: + if not all(x in p for x in ("PrePatch","Comment","Find","Replace")): continue + print(" - {}".format(p["PrePatch"])) + find = binascii.unhexlify(p["Find"]) + if d.count(find) == 1: + self.result.get("Patch").append(p) # Retain the patch + repl = binascii.unhexlify(p["Replace"]) + print(" --> Located - applying...") + d = d.replace(find,repl) # Replace it in memory + with open(trouble_path,"wb") as f: + f.write(d) # Write the updated file + # Attempt to load again + if self.acpi.load(trouble_path)[0]: + fixed = True + # We got it to load - let's write the patches + print("\nDisassembled successfully!\n") + #self.make_plist(None, None, patches) + # Save to the local file + with open(os.path.join(res,target_name),"wb") as f: + f.write(d) + #print("\n!! Patches applied to modified file in Results folder:\n {}".format(target_name)) + #self.patch_warn() + break + if not fixed: + print("\n{} could not be disassembled!".format(trouble_dsdt)) + print("") + self.utils.request_input() + if temp: + shutil.rmtree(temp,ignore_errors=True) + # Restore any prior tables + self.acpi.acpi_tables = prior_tables + return + # Let's load the rest of the tables + if len(tables) > 1: + print("Loading valid tables in {}...".format(path)) + loaded_tables,failed = self.acpi.load(temp or path) + if not loaded_tables or failed: + print("\nFailed to load tables in {}{}\n".format( + os.path.dirname(path) if os.path.isfile(path) else path, + ":" if failed else "" + )) + for t in self.sorted_nicely(failed): + print(" - {}".format(t)) + # Restore any prior tables + if not loaded_tables: + self.acpi.acpi_tables = prior_tables + else: + if len(tables) > 1: + print("") # Newline for readability + print("Done.") + # If we had to patch the DSDT, or if not all tables loaded, + # make sure we get interaction from the user to continue + if trouble_dsdt or not loaded_tables or failed: + print("") + self.utils.request_input() + if temp: + shutil.rmtree(temp,ignore_errors=True) + return path + + def get_sta_var(self,var="STAS",device=None,dev_hid="ACPI000E",dev_name="AWAC",log_locate=True,table=None): + # Helper to check for a device, check for (and qualify) an _STA method, + # and look for a specific variable in the _STA scope + # + # Returns a dict with device info - only "valid" parameter is + # guaranteed. + has_var = False + patches = [] + root = None + if device: + dev_list = self.acpi.get_device_paths(device,table=table) + if not len(dev_list): + #if log_locate: print(" - Could not locate {}".format(device)) + return {"value":False} + else: + #if log_locate: print("Locating {} ({}) devices...".format(dev_hid,dev_name)) + dev_list = self.acpi.get_device_paths_with_hid(dev_hid,table=table) + if not len(dev_list): + #if log_locate: print(" - Could not locate any {} devices".format(dev_hid)) + return {"valid":False} + dev = dev_list[0] + #if log_locate: print(" - Found {}".format(dev[0])) + root = dev[0].split(".")[0] + #print(" --> Verifying _STA...") + # Check Method first - then Name + sta_type = "MethodObj" + sta = self.acpi.get_method_paths(dev[0]+"._STA",table=table) + xsta = self.acpi.get_method_paths(dev[0]+".XSTA",table=table) + if not sta and not xsta: + # Check for names + sta_type = "IntObj" + sta = self.acpi.get_name_paths(dev[0]+"._STA",table=table) + xsta = self.acpi.get_name_paths(dev[0]+".XSTA",table=table) + if xsta and not sta: + #print(" --> _STA already renamed to XSTA! Skipping other checks...") + #print(" Please disable _STA to XSTA renames for this device, reboot, and try again.") + #print("") + return {"valid":False,"break":True,"device":dev,"dev_name":dev_name,"dev_hid":dev_hid,"sta_type":sta_type} + if sta: + if var: + scope = "\n".join(self.acpi.get_scope(sta[0][1],strip_comments=True,table=table)) + has_var = var in scope + #print(" --> {} {} variable".format("Has" if has_var else "Does NOT have",var)) + else: + pass + #print(" --> No _STA method/name found") + # Let's find out of we need a unique patch for _STA -> XSTA + if sta and not has_var: + #print(" --> Generating _STA to XSTA rename") + sta_index = self.acpi.find_next_hex(sta[0][1],table=table)[1] + #print(" ----> Found at index {}".format(sta_index)) + sta_hex = "5F535441" # _STA + xsta_hex = "58535441" # XSTA + padl,padr = self.acpi.get_shortest_unique_pad(sta_hex,sta_index,table=table) + patches.append({"Comment":"{} _STA to XSTA Rename".format(dev_name),"Find":padl+sta_hex+padr,"Replace":padl+xsta_hex+padr}) + return {"valid":True,"has_var":has_var,"sta":sta,"patches":patches,"device":dev,"dev_name":dev_name,"dev_hid":dev_hid,"root":root,"sta_type":sta_type} + + def get_address_from_line(self, line, split_by="_ADR, ", table=None): + if table is None: + table = self.acpi.get_dsdt_or_only() + try: + return int(table["lines"][line].split(split_by)[1].split(")")[0].replace("Zero","0x0").replace("One","0x1"),16) + except: + return None + + def check_acpi_directory(self, acpi_directory): + if acpi_directory: + if not os.path.isdir(acpi_directory): + self.utils.mkdirs(acpi_directory) + return acpi_directory + else: + return acpi_directory + return None + + def write_ssdt(self, ssdt_name, ssdt_content, compile=True): + dsl_path = os.path.join(self.acpi_directory, f"{ssdt_name}.dsl") + aml_path = os.path.join(self.acpi_directory, f"{ssdt_name}.aml") + + with open(dsl_path,"w") as f: + f.write(ssdt_content) + + if not compile: + return False + + compile = subprocess.run( + [self.acpi.iasl, dsl_path], + capture_output=True, + check=True, # Raises CalledProcessError for non-zero return code + ) + if "Compilation successful" not in compile.stdout.decode().strip(): + return False + else: + os.remove(dsl_path) + + return os.path.exists(aml_path) + + def apply_acpi_patches(self): + for acpi_patch in self.result.get("Patch"): + acpi_patch["Base"] = acpi_patch.get("Base", "") + acpi_patch["BaseSkip"] = acpi_patch.get("BaseSkip", 0) + acpi_patch["Count"] = acpi_patch.get("Count", 0) + acpi_patch["Enabled"] = True + acpi_patch["Find"] = self.utils.hex_to_bytes(acpi_patch["Find"]) + acpi_patch["Limit"] = acpi_patch.get("Limit", 0) + acpi_patch["Mask"] = self.utils.hex_to_bytes(acpi_patch.get("Mask", "")) + acpi_patch["OemTableId"] = self.utils.hex_to_bytes(acpi_patch.get("OemTableId", "")) + acpi_patch["Replace"] = self.utils.hex_to_bytes(acpi_patch["Replace"]) + acpi_patch["ReplaceMask"] = self.utils.hex_to_bytes(acpi_patch.get("ReplaceMask", "")) + acpi_patch["Skip"] = acpi_patch.get("Skip", 0) + acpi_patch["TableLength"] = acpi_patch.get("TableLength", 0) + acpi_patch["TableSignature"] = self.utils.hex_to_bytes(acpi_patch.get("TableSignature", "")) + + self.result["Patch"] = sorted(self.result["Patch"], key=lambda x: x["Comment"]) + + def get_low_pin_count_bus_device(self): + for lpc_bus_name in ("LPCB", "LPC0", "LPC", "SBRG", "PX40"): + try: + self.lpc_bus_device = self.acpi.get_device_paths(lpc_bus_name)[0][0] + break + except: + pass + + def add_intel_management_engine(self, cpu_codename, intel_mei): + comment = "Creates a fake IMEI device to ensure Intel iGPUs acceleration functions properly" + ssdt_name = "SSDT-IMEI" + ssdt_content = """ +DefinitionBlock ("", "SSDT", 2, "ZPSS", "IMEI", 0x00000000) +{ + External (_SB_.PCI0, DeviceObj) + + Scope (_SB.PCI0) + { + Device (IMEI) + { + Name (_ADR, 0x00160000) // _ADR: Address + Method (_STA, 0, NotSerialized) // _STA: Status + { + If (_OSI ("Darwin")) + { + Return (0x0F) + } + Else + { + Return (Zero) + } + } + } + } +}""" + + if intel_mei: + if "Sandy Bridge" in cpu_codename and intel_mei.get("Device ID") in "8086-1E3A" or "Ivy Bridge" in cpu_codename and intel_mei.get("Device ID") in "8086-1C3A": + imei_device = self.acpi.get_device_paths_with_hid("0x00160000", self.dsdt) + + if not imei_device: + if self.write_ssdt(ssdt_name, ssdt_content): + self.result["Add"].append({ + "Comment": comment, + "Enabled": True, + "Path": f"{ssdt_name}.aml" + }) + + def add_memory_controller_device(self, cpu_manufacturer, cpu_codename, smbios): + if "Intel" not in cpu_manufacturer or "MacPro" in smbios and self.is_intel_hedt_cpu(cpu_codename): + return + + comment = "Add a Memory Controller Hub Controller device to fix AppleSMBus" + ssdt_name = "SSDT-MCHC" + ssdt_content = """ +DefinitionBlock ("", "SSDT", 2, "ZPSS", "MCHC", 0) +{ + External ([[PCIName]], DeviceObj) + + Scope ([[PCIName]]) + { + Device (MCHC) + { + Name (_ADR, Zero) + Method (_STA, 0, NotSerialized) + { + If (_OSI ("Darwin")) + { + Return (0x0F) + } + Else + { + Return (Zero) + } + } + } + } +}""" + + mchc_device = self.acpi.get_device_paths("MCHC", self.dsdt) + + if mchc_device: + return + + pci_bus_device = ".".join(self.lpc_bus_device.split(".")[:2]) + ssdt_content = ssdt_content.replace("[[PCIName]]", pci_bus_device) + + if self.write_ssdt(ssdt_name, ssdt_content): + self.result["Add"].append({ + "Comment": comment, + "Enabled": True, + "Path": f"{ssdt_name}.aml" + }) + + def add_system_management_bus_device(self, cpu_manufacturer, cpu_codename): + if "Intel" not in cpu_manufacturer: + return + + try: + smbus_device_name = self.acpi.get_device_paths_with_hid("0x001F0003" if self.utils.contains_any(cpu_data.IntelCPUGenerations, cpu_codename, end=4) else "0x001F0004", self.dsdt)[0][0].split(".")[-1] + except: + smbus_device_name = "SBUS" + + pci_bus_device = ".".join(self.lpc_bus_device.split(".")[:2]) + smbus_device_path = f"{pci_bus_device}.{smbus_device_name}" + + comment = "Add a System Management Bus device to fix AppleSMBus issues" + ssdt_name = f"SSDT-{smbus_device_name}" + ssdt_content = """ +DefinitionBlock ("", "SSDT", 2, "ZPSS", "[[SMBUSName]]", 0) +{ + External ([[SMBUSDevice]], DeviceObj) + + Scope ([[SMBUSDevice]]) + { + Device (BUS0) + { + Name (_CID, "smbus") + Name (_ADR, Zero) + Method (_STA, 0, NotSerialized) + { + If (_OSI ("Darwin")) + { + Return (0x0F) + } + Else + { + Return (Zero) + } + } + } + } +}""".replace("[[SMBUSName]]", smbus_device_name).replace("[[SMBUSDevice]]", smbus_device_path) + + if self.write_ssdt(ssdt_name, ssdt_content): + self.result["Add"].append({ + "Comment": comment, + "Enabled": True, + "Path": f"{ssdt_name}.aml" + }) + + def add_usb_power_properties(self, smbios): + comment = "Creates an USBX device to inject USB power properties" + ssdt_name = "SSDT-USBX" + ssdt_content = """ +DefinitionBlock ("", "SSDT", 2, "ZPSS", "USBX", 0x00001000) +{ + Scope (\\_SB) + { + Device (USBX) + { + Name (_ADR, Zero) // _ADR: Address + Method (_DSM, 4, NotSerialized) // _DSM: Device-Specific Method + { + If (LNot (Arg2)) + { + Return (Buffer () + { + 0x03 + }) + } + Return (Package () + {[[USBX_PROPS]] + }) + } + Method (_STA, 0, NotSerialized) // _STA: Status + { + If (_OSI ("Darwin")) + { + Return (0x0F) + } + Else + { + Return (Zero) + } + } + } + } +}""" + + usb_power_properties = None + if self.utils.contains_any(["MacPro7,1", "iMacPro1,1", "iMac20,", "iMac19,", "iMac18,", "iMac17,", "iMac16,"], smbios): + usb_power_properties = { + "kUSBSleepPowerSupply":"0x13EC", + "kUSBSleepPortCurrentLimit":"0x0834", + "kUSBWakePowerSupply":"0x13EC", + "kUSBWakePortCurrentLimit":"0x0834" + } + elif "MacMini8,1" in smbios: + usb_power_properties = { + "kUSBSleepPowerSupply":"0x0C80", + "kUSBSleepPortCurrentLimit":"0x0834", + "kUSBWakePowerSupply":"0x0C80", + "kUSBWakePortCurrentLimit":"0x0834" + } + elif self.utils.contains_any(["MacBookPro16,", "MacBookPro15,", "MacBookPro14,", "MacBookPro13,", "MacBookAir9,1"], smbios): + usb_power_properties = { + "kUSBSleepPortCurrentLimit":"0x0BB8", + "kUSBWakePortCurrentLimit":"0x0BB8" + } + elif "MacBook9,1" in smbios: + usb_power_properties = { + "kUSBSleepPowerSupply":"0x05DC", + "kUSBSleepPortCurrentLimit":"0x05DC", + "kUSBWakePowerSupply":"0x05DC", + "kUSBWakePortCurrentLimit":"0x05DC" + } + + if usb_power_properties: + ssdt_content = ssdt_content.replace("[[USBX_PROPS]]", + "".join("\n \"{}\",\n {}{}".format(key, usb_power_properties[key], "," if index < len(usb_power_properties) else "") + for index, key in enumerate(usb_power_properties, start=1)) + ) + if self.write_ssdt(ssdt_name, ssdt_content): + self.result["Add"].append({ + "Comment": comment, + "Enabled": True, + "Path": f"{ssdt_name}.aml" + }) + + def ambient_light_sensor(self, motherboard_name, platform, integrated_gpu): + if "Laptop" not in platform or not integrated_gpu or "SURFACE" in motherboard_name: + return + + ssdt_name = "SSDT-ALS0" + ssdt_content = """ +// Resource: https://github.com/acidanthera/OpenCorePkg/blob/master/Docs/AcpiSamples/Source/SSDT-ALS0.dsl + +/* + * Starting with macOS 10.15 Ambient Light Sensor presence is required for backlight functioning. + * Here we create an Ambient Light Sensor ACPI Device, which can be used by SMCLightSensor kext + * to report either dummy (when no device is present) or valid values through SMC interface. + */ +DefinitionBlock ("", "SSDT", 2, "ZPSS", "ALS0", 0x00000000) +{ + Scope (_SB) + { + Device (ALS0) + { + Name (_HID, "ACPI0008" /* Ambient Light Sensor Device */) // _HID: Hardware ID + Name (_CID, "smc-als") // _CID: Compatible ID + Name (_ALI, 0x012C) // _ALI: Ambient Light Illuminance + Name (_ALR, Package (0x01) // _ALR: Ambient Light Response + { + Package (0x02) + { + 0x64, + 0x012C + } + }) + Method (_STA, 0, NotSerialized) // _STA: Status + { + If (_OSI ("Darwin")) + { + Return (0x0F) + } + Else + { + Return (Zero) + } + } + } + } +}""" + try: + als_device = self.acpi.get_device_paths_with_hid("ACPI0008", self.dsdt)[0][0] + except: + als_device = None + + if als_device: + als_device_name = als_device.split(".")[-1] + if "." not in als_device: + als_device_name = als_device_name[1:] + + sta = self.get_sta_var(var=None, device=None, dev_hid="ACPI0008", dev_name=als_device_name, table=self.dsdt) + + if sta.get("patches"): + self.result["Patch"].extend(sta.get("patches", [])) + + ssdt_name = f"SSDT-{als_device_name}" + ssdt_content = """ +DefinitionBlock ("", "SSDT", 2, "ZPSS", "[[ALSName]]", 0x00000000) +{ + External ([[ALSDevice]], DeviceObj) + External ([[ALSDevice]].XSTA, [[STAType]]) + + Scope ([[ALSDevice]]) + { + Method (_STA, 0, NotSerialized) // _STA: Status + { + If (_OSI ("Darwin")) + { + Return (0) + } + Else + { + Return ([[XSTA]]) + } + } + } +}""".replace("[[ALSName]]", als_device_name) \ + .replace("[[ALSDevice]]", als_device) \ + .replace("[[STAType]]", sta.get("sta_type","MethodObj")) \ + .replace("[[XSTA]]", "{}.XSTA{}".format(als_device," ()" if sta.get("sta_type","MethodObj") == "MethodObj" else "") if sta else "0x0F") + + comment = "{} Ambient Light Sensor device for storing the current brightness/auto-brightness level".format("Fake" if not als_device else "Enable") + if self.write_ssdt(ssdt_name, ssdt_content): + self.result["Add"].append({ + "Comment": comment, + "Enabled": True, + "Path": f"{ssdt_name}.aml" + }) + + def disable_rhub_devices(self): + comment = "Disable RHUB/HUBN/URTH devices and rename PXSX, XHC1, EHC1, and EHC2 devices" + ssdt_name = "SSDT-USB-Reset" + ssdt_content = """ +DefinitionBlock ("", "SSDT", 2, "ZPSS", "UsbReset", 0x00001000) +{ +""" + rhub_devices = self.acpi.get_device_paths("RHUB", self.dsdt) + rhub_devices.extend(self.acpi.get_device_paths("HUBN", self.dsdt)) + rhub_devices.extend(self.acpi.get_device_paths("URTH", self.dsdt)) + if not len(rhub_devices): + return + + tasks = [] + used_names = [] + xhc_num = 2 + ehc_num = 1 + for rhub_device in rhub_devices: + task = { + "device": rhub_device[0] + } + name = rhub_device[0].split(".")[-2] + + if name in self.illegal_names or name in used_names: + task["device"] = ".".join(task["device"].split(".")[:-1]) + task["parent"] = ".".join(task["device"].split(".")[:-1]) + + if name.startswith("EHC"): + task["rename"],ehc_num = self.get_unique_device(task["parent"],"EH01",ehc_num,used_names) + ehc_num += 1 # Increment the name number + else: + task["rename"],xhc_num = self.get_unique_device(task["parent"],"XHCI",xhc_num,used_names) + xhc_num += 1 # Increment the name number + used_names.append(task["rename"]) + else: + used_names.append(name) + sta_method = self.acpi.get_method_paths(task["device"]+"._STA", self.dsdt) + if len(sta_method): + sta_index = self.acpi.find_next_hex(sta_method[0][1], self.dsdt)[1] + sta_hex = "5F535441" + xsta_hex = "58535441" + padl,padr = self.acpi.get_shortest_unique_pad(sta_hex, sta_index, self.dsdt) + self.result.get("Patch").append({ + "Comment": "{} _STA to XSTA Rename".format(task["device"].split(".")[-1]), + "Find": padl+sta_hex+padr, + "Replace": padl+xsta_hex+padr + }) + scope_adr = self.acpi.get_name_paths(task["device"]+"._ADR", self.dsdt) + task["address"] = self.dsdt.get("lines")[scope_adr[0][1]].strip() if len(scope_adr) else "Name (_ADR, Zero) // _ADR: Address" + tasks.append(task) + + parents = sorted(list(set([task["parent"] for task in tasks if task.get("parent", None)]))) + for parent in parents: + ssdt_content += " External ({}, DeviceObj)\n".format(parent) + for task in tasks: + ssdt_content += " External ({}, DeviceObj)\n".format(task["device"]) + for task in tasks: + if task.get("rename", None): + ssdt_content += """ + Scope ([[device]]) + { + Method (_STA, 0, NotSerialized) // _STA: Status + { + If (_OSI ("Darwin")) + { + Return (Zero) + } + Else + { + Return (0x0F) + } + } + } + + Scope ([[parent]]) + { + Device ([[new_device]]) + { + [[address]] + Method (_STA, 0, NotSerialized) // _STA: Status + { + If (_OSI ("Darwin")) + { + Return (0x0F) + } + Else + { + Return (Zero) + } + } + } + } +""".replace("[[device]]", task["device"]) \ + .replace("[[parent]]", task["parent"]) \ + .replace("[[address]]", task.get("address", "Name (_ADR, Zero) // _ADR: Address")) \ + .replace("[[new_device]]", task["rename"]) + else: + ssdt_content += """ + Scope ([[device]]) + { + Method (_STA, 0, NotSerialized) // _STA: Status + { + If (_OSI ("Darwin")) + { + Return (Zero) + } + Else + { + Return (0x0F) + } + } + } + """.replace("[[device]]", task["device"]) + ssdt_content += "\n}" + + if self.write_ssdt(ssdt_name, ssdt_content): + self.result["Add"].append({ + "Comment": comment, + "Enabled": True, + "Path": f"{ssdt_name}.aml" + }) + + def disable_unsupported_device(self, unsupported_devices): + for device in unsupported_devices: + comment = "Disable {}".format(device.split(": ")[-1]) + ssdt_name = None + if "Storage" in device: + ssdt_name = "SSDT-Disable_NVMe" + ssdt_content = """ +// Replace all "_SB.PCI0.RP09.PXSX" with the ACPI path of your SSD NVMe + +DefinitionBlock ("", "SSDT", 2, "ZPSS", "DNVMe", 0x00000000) +{ + External (_SB.PCI0.RP09.PXSX, DeviceObj) + + Method (_SB.PCI0.RP09.PXSX._DSM, 4, NotSerialized) // _DSM: Device-Specific Method + { + If (_OSI ("Darwin")) + { + If (!Arg2) + { + Return (Buffer (One) + { + 0x03 // . + }) + } + + Return (Package (0x02) + { + "class-code", + Buffer (0x04) + { + 0xFF, 0x08, 0x01, 0x00 // .... + } + }) + } + } +} +""" + elif "WiFi" in device or "SD Controller" in device: + if "USB" in device: + continue + + ssdt_name = "SSDT-Disable_{}".format("WiFi" if "WiFi" in device else "SD_Card_Reader") + ssdt_content = """ +// Replace all "_SB.PCI0.RP01" with the ACPI path of your [[DeviceType]] + +DefinitionBlock ("", "SSDT", 2, "ZPSS", "[[DeviceType]]", 0) +{ + External (_SB.PCI0.RP01, DeviceObj) + + Scope (_SB.PCI0.RP01) + { + OperationRegion (DE01, PCI_Config, 0x50, 1) + Field (DE01, AnyAcc, NoLock, Preserve) + { + , 4, + DDDD, 1 + } + Method (_STA, 0, Serialized) + { + If (_OSI ("Darwin")) + { + Return (0) + } + Else + { + Return (0x0F) + } + } + } + + Scope (\\) + { + If (_OSI ("Darwin")) + { + \\_SB.PCI0.RP01.DDDD = One + } + } +}""".replace("[[DeviceType]]", "DWiFi" if "WiFi" in device else "DSDC") + + if ssdt_name: + if self.write_ssdt(ssdt_name, ssdt_content, compile="Discrete GPU" in device): + self.result["Add"].append({ + "Comment": comment, + "Enabled": True, + "Path": f"{ssdt_name}.aml" + }) + + def enable_backlight_controls(self, platform, cpu_codename, integrated_gpu): + if "Laptop" not in platform or not integrated_gpu: + return + + uid_value = 19 + if self.utils.contains_any(cpu_data.IntelCPUGenerations, cpu_codename, end=2): + uid_value = 14 + elif self.utils.contains_any(cpu_data.IntelCPUGenerations, cpu_codename, start=2, end=4): + uid_value = 15 + elif self.utils.contains_any(cpu_data.IntelCPUGenerations, cpu_codename, start=4, end=7): + uid_value = 16 + + igpu = "" + if uid_value == 14: + # Try to gather our iGPU device + paths = self.acpi.get_path_of_type(obj_type="Name", obj="_ADR", table=self.dsdt) + for path in paths: + adr = self.get_address_from_line(path[1], self.dsdt) + if adr == 0x00020000: + igpu = path[0][:-5] + break + if not igpu: # Try matching by name + pci_roots = self.acpi.get_device_paths_with_hid("PNP0A08", self.dsdt) + pci_roots += self.acpi.get_device_paths_with_hid("PNP0A03", self.dsdt) + pci_roots += self.acpi.get_device_paths_with_hid("ACPI0016", self.dsdt) + external = [] + for line in self.dsdt.get("lines"): + if not line.strip().startswith("External ("): continue # We don't need it + try: + path = line.split("(")[1].split(", ")[0] + # Prepend the backslash and ensure trailing underscores are stripped. + path = "\\"+".".join([x.rstrip("_").replace("\\","") for x in path.split(".")]) + external.append(path) + except: pass + for root in pci_roots: + for name in ("IGPU","_VID","VID0","VID1","GFX0","VGA","_VGA"): + test_path = "{}.{}".format(root[0],name) + device = self.acpi.get_device_paths(test_path, self.dsdt) + if device: device = device[0][0] # Unpack to the path + else: + # Walk the external paths and see if it's declared elsewhere? + # We're not patching anything directly - just getting a pathing + # reference, so it's fine to not have the surrounding code. + device = next((x for x in external if test_path == x),None) + if not device: continue # Not found :( + # Got a device - see if it has an _ADR, and skip if so - as it was wrong in the prior loop + if self.acpi.get_path_of_type(obj_type="Name",obj=device+"._ADR", table=self.dsdt): continue + # At this point - we got a hit + igpu = device + + if "PNLF" in self.dsdt.get("table"): + self.result.get("Patch").append({ + "Comment": "PNLF to XNLF Rename", + "Find": "504E4C46", + "Replace": "584E4C46" + }) + + nbcf = binascii.unhexlify("084E42434600") + if nbcf in self.dsdt.get("raw"): + self.result.get("Patch").append({ + "Comment": "NBCF Zero to One for BrightnessKeys.kext", + "Find": "084E42434600", + "Replace": "084E42434601" + }) + + comment = "Defines a PNLF device to enable backlight controls on laptops" + ssdt_name = "SSDT-PNLF" + ssdt_content = """ +DefinitionBlock ("", "SSDT", 2, "ZPSS", "PNLF", 0x00000000) +{""" + if igpu: + ssdt_content += """\n External ([[igpu_path]], DeviceObj)\n""" + ssdt_content += """ + Device (PNLF) + { + Name (_HID, EisaId ("APP0002")) // _HID: Hardware ID + Name (_CID, "backlight") // _CID: Compatible ID + Name (_UID, [[uid_value]]) // _UID: Unique ID + + Method (_STA, 0, NotSerialized) // _STA: Status + { + If (_OSI ("Darwin")) + { + Return (0x0B) + } + Else + { + Return (Zero) + } + }""" + if igpu: + ssdt_content += """ + Method (_INI, 0, Serialized) + { + If (LAnd (_OSI ("Darwin"), CondRefOf ([[igpu_path]]))) + { + OperationRegion ([[igpu_path]].RMP3, PCI_Config, Zero, 0x14) + Field ([[igpu_path]].RMP3, AnyAcc, NoLock, Preserve) + { + Offset (0x02), GDID,16, + Offset (0x10), BAR1,32, + } + // IGPU PWM backlight register descriptions: + // LEV2 not currently used + // LEVL level of backlight in Sandy/Ivy + // P0BL counter, when zero is vertical blank + // GRAN see description below in INI1 method + // LEVW should be initialized to 0xC0000000 + // LEVX PWMMax except FBTYPE_HSWPLUS combo of max/level (Sandy/Ivy stored in MSW) + // LEVD level of backlight for Coffeelake + // PCHL not currently used + OperationRegion (RMB1, SystemMemory, BAR1 & ~0xF, 0xe1184) + Field(RMB1, AnyAcc, Lock, Preserve) + { + Offset (0x48250), + LEV2, 32, + LEVL, 32, + Offset (0x70040), + P0BL, 32, + Offset (0xc2000), + GRAN, 32, + Offset (0xc8250), + LEVW, 32, + LEVX, 32, + LEVD, 32, + Offset (0xe1180), + PCHL, 32, + } + // Now fixup the backlight PWM depending on the framebuffer type + // At this point: + // Local4 is RMCF.BLKT value (unused here), if specified (default is 1) + // Local0 is device-id for IGPU + // Local2 is LMAX, if specified (Ones means based on device-id) + // Local3 is framebuffer type + + // Adjustment required when using WhateverGreen.kext + Local0 = GDID + Local2 = Ones + Local3 = 0 + + // check Sandy/Ivy + // #define FBTYPE_SANDYIVY 1 + If (LOr (LEqual (1, Local3), LNotEqual (Match (Package() + { + // Sandy HD3000 + 0x010b, 0x0102, + 0x0106, 0x1106, 0x1601, 0x0116, 0x0126, + 0x0112, 0x0122, + // Ivy + 0x0152, 0x0156, 0x0162, 0x0166, + 0x016a, + // Arrandale + 0x0046, 0x0042, + }, MEQ, Local0, MTR, 0, 0), Ones))) + { + if (LEqual (Local2, Ones)) + { + // #define SANDYIVY_PWMMAX 0x710 + Store (0x710, Local2) + } + // change/scale only if different than current... + Store (LEVX >> 16, Local1) + If (LNot (Local1)) + { + Store (Local2, Local1) + } + If (LNotEqual (Local2, Local1)) + { + // set new backlight PWMMax but retain current backlight level by scaling + Store ((LEVL * Local2) / Local1, Local0) + Store (Local2 << 16, Local3) + If (LGreater (Local2, Local1)) + { + // PWMMax is getting larger... store new PWMMax first + Store (Local3, LEVX) + Store (Local0, LEVL) + } + Else + { + // otherwise, store new brightness level, followed by new PWMMax + Store (Local0, LEVL) + Store (Local3, LEVX) + } + } + } + } + }""" + ssdt_content += """ + } +}""" + # Perform the replacements + ssdt_content = ssdt_content.replace("[[uid_value]]", str(uid_value)).replace("[[igpu_path]]",igpu) + + if self.write_ssdt(ssdt_name, ssdt_content): + self.result["Add"].append({ + "Comment": comment, + "Enabled": True, + "Path": f"{ssdt_name}.aml" + }) + + def enable_cpu_power_management(self, cpu_codename): + if self.utils.contains_any(cpu_data.IntelCPUGenerations, cpu_codename, end=2): + return + + comment = "Sets plugin-type to 1 on the first Processor object to enable CPU power management" + ssdt_name = "SSDT-PLUG" + + try: + cpu_name = self.acpi.get_processor_paths()[0][0] + except: + cpu_name = None + + if cpu_name: + ssdt = """ +// Resource: https://github.com/acidanthera/OpenCorePkg/blob/master/Docs/AcpiSamples/SSDT-PLUG.dsl + +DefinitionBlock ("", "SSDT", 2, "ZPSS", "CpuPlug", 0x00003000) +{ + External ([[CPUName]], ProcessorObj) + Scope ([[CPUName]]) + { + If (_OSI ("Darwin")) { + Method (_DSM, 4, NotSerialized) // _DSM: Device-Specific Method + { + If (LNot (Arg2)) + { + Return (Buffer (One) + { + 0x03 + }) + } + Return (Package (0x02) + { + "plugin-type", + One + }) + } + } + } +}""".replace("[[CPUName]]", cpu_name) + else: + comment = "Redefines modern CPU Devices as legacy Processor objects and sets plugin-type to 1 on the first to enable CPU power management" + ssdt_name += "-ALT" + procs = self.acpi.get_device_paths_with_hid("ACPI0007", self.dsdt) + if not procs: + return + parent = procs[0][0].split(".")[0] + proc_list = [] + for proc in procs: + uid = self.acpi.get_path_of_type(obj_type="Name", obj=proc[0]+"._UID", table=self.dsdt) + if not uid: + continue + # Let's get the actual _UID value + try: + _uid = self.dsdt.get("lines")[uid[0][1]].split("_UID, ")[1].split(")")[0] + proc_list.append((proc[0],_uid)) + except: + pass + if not proc_list: + return + ssdt = """ +// Resource: https://github.com/acidanthera/OpenCorePkg/blob/master/Docs/AcpiSamples/Source/SSDT-PLUG-ALT.dsl + +DefinitionBlock ("", "SSDT", 2, "ZPSS", "CpuPlugA", 0x00003000) +{ + External ([[parent]], DeviceObj) + + Scope ([[parent]]) + {""".replace("[[parent]]",parent) + # Walk the processor objects, and add them to the SSDT + for i,proc_uid in enumerate(proc_list): + proc,uid = proc_uid + adr = hex(i)[2:].upper() + name = "CP00"[:-len(adr)]+adr + ssdt += """ + Processor ([[name]], [[uid]], 0x00000510, 0x06) + { + // [[proc]] + Name (_HID, "ACPI0007" /* Processor Device */) // _HID: Hardware ID + Name (_UID, [[uid]]) + Method (_STA, 0, NotSerialized) // _STA: Status + { + If (_OSI ("Darwin")) + { + Return (0x0F) + } + Else + { + Return (Zero) + } + }""".replace("[[name]]",name).replace("[[uid]]",uid).replace("[[proc]]",proc) + if i == 0: # Got the first, add plugin-type as well + ssdt += """ + Method (_DSM, 4, NotSerialized) + { + If (LNot (Arg2)) { + Return (Buffer (One) { 0x03 }) + } + + Return (Package (0x02) + { + "plugin-type", + One + }) + }""" + # Close up the SSDT + ssdt += """ + }""" + ssdt += """ + } +}""" + + if self.write_ssdt(ssdt_name, ssdt): + self.result["Add"].append({ + "Comment": comment, + "Enabled": True, + "Path": f"{ssdt_name}.aml" + }) + + def enable_gpio_device(self, platform, cpu_manufacturer, touchpad_communication): + if "Laptop" not in platform or "Intel" not in cpu_manufacturer or not "I2C" in touchpad_communication: + return + + try: + gpio_device = self.acpi.get_device_paths("GPI0", self.dsdt)[0][0] or self.acpi.get_device_paths("GPIO", self.dsdt)[0][0] + except: + gpio_device = None + + if not gpio_device: + return + + sta = self.get_sta_var(var=None, device=gpio_device, dev_hid=None, dev_name=gpio_device.split(".")[-1], table=self.dsdt) + + if sta.get("patches"): + self.result["Patch"].extend(sta.get("patches", [])) + + comment = "Enable GPIO device for a I2C TouchPads to function properly" + ssdt_name = "SSDT-GPI0" + ssdt_content = """ +DefinitionBlock ("", "SSDT", 2, "ZPSS", "GPI0", 0x00000000) +{ + External ([[GPI0Path]], DeviceObj) + External ([[GPI0Path]].XSTA, [[STAType]]) + + Scope ([[GPI0Path]]) + { + Method (_STA, 0, NotSerialized) // _STA: Status + { + If (_OSI ("Darwin")) + { + Return (0x0F) + } + Else + { + Return ([[XSTA]]) + } + } + } +}""".replace("[[GPI0Path]]", gpio_device) \ + .replace("[[STAType]]", sta.get("sta_type","MethodObj")) \ + .replace("[[XSTA]]", "{}.XSTA{}".format(gpio_device," ()" if sta.get("sta_type","MethodObj") == "MethodObj" else "") if sta else "0x0F") + + if self.write_ssdt(ssdt_name, ssdt_content): + self.result["Add"].append({ + "Comment": comment, + "Enabled": True, + "Path": f"{ssdt_name}.aml" + }) + + def enable_nvram_support(self, motherboard_chipset): + if not self.utils.contains_any(["H310", "H370", "B360", "B365", "Z390"], motherboard_chipset) or not self.lpc_bus_device: + return + + comment = "Add a PMCR device to enable NVRAM support for 300-series mainboards" + ssdt_name = "SSDT-PMC" + ssdt_content = """ +// Resource: https://github.com/acidanthera/OpenCorePkg/blob/master/Docs/AcpiSamples/Source/SSDT-PMC.dsl + +/* + * Intel 300-series PMC support for macOS + * + * Starting from Z390 chipsets PMC (D31:F2) is only available through MMIO. + * Since there is no standard device for PMC in ACPI, Apple introduced its + * own naming "APP9876" to access this device from AppleIntelPCHPMC driver. + * To avoid confusion we disable this device for all other operating systems, + * as they normally use another non-standard device with "PNP0C02" HID and + * "PCHRESV" UID. + * + * On certain implementations, including APTIO V, PMC initialisation is + * required for NVRAM access. Otherwise it will freeze in SMM mode. + * The reason for this is rather unclear. Note, that PMC and SPI are + * located in separate memory regions and PCHRESV maps both, yet only + * PMC region is used by AppleIntelPCHPMC: + * 0xFE000000~0xFE00FFFF - PMC MBAR + * 0xFE010000~0xFE010FFF - SPI BAR0 + * 0xFE020000~0xFE035FFF - SerialIo BAR in ACPI mode + * + * PMC device has nothing to do to LPC bus, but is added to its scope for + * faster initialisation. If we add it to PCI0, where it normally exists, + * it will start in the end of PCI configuration, which is too late for + * NVRAM support. + */ +DefinitionBlock ("", "SSDT", 2, "ACDT", "PMCR", 0x00001000) +{ + External ([[LPCPath]], DeviceObj) + + Scope ([[LPCPath]]) + { + Device (PMCR) + { + Name (_HID, EisaId ("APP9876")) // _HID: Hardware ID + Method (_STA, 0, NotSerialized) // _STA: Status + { + If (_OSI ("Darwin")) + { + Return (0x0B) + } + Else + { + Return (Zero) + } + } + Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings + { + Memory32Fixed (ReadWrite, + 0xFE000000, // Address Base + 0x00010000, // Address Length + ) + }) + } + } +}""".replace("[[LPCPath]]", self.lpc_bus_device) + + if self.write_ssdt(ssdt_name, ssdt_content): + self.result["Add"].append({ + "Comment": comment, + "Enabled": True, + "Path": f"{ssdt_name}.aml" + }) + + def fake_embedded_controller(self, platform): + comment = "Add a fake EC to ensure macOS compatibility" + ssdt_name = "SSDT-EC" + + laptop = "Laptop" in platform + + def sta_needs_patching(sta): + if not isinstance(sta,dict) or not sta.get("sta"): + return False + # Check if we have an IntObj or MethodObj + # _STA, and scrape for values if possible. + if sta.get("sta_type") == "IntObj": + # We got an int - see if it's force-enabled + try: + sta_scope = self.dsdt.get("lines")[sta["sta"][0][1]] + if not "Name (_STA, 0x0F)" in sta_scope: + return True + except Exception as e: + print(e) + return True + elif sta.get("sta_type") == "MethodObj": + # We got a method - if we have more than one + # "Return (", or not a single "Return (0x0F)", + # then we need to patch this out and replace + try: + sta_scope = "\n".join(self.acpi.get_scope(sta["sta"][0][1],strip_comments=True,table=self.dsdt)) + if sta_scope.count("Return (") > 1 or not "Return (0x0F)" in sta_scope: + # More than one return, or our return isn't force-enabled + return True + except Exception as e: + return True + # If we got here - it's not a recognized type, or + # it was fullly qualified and doesn't need patching + return False + rename = False + named_ec = False + ec_to_patch = [] + ec_to_enable = [] + ec_sta = {} + ec_enable_sta = {} + patches = [] + ec_located = False + + ec_list = self.acpi.get_device_paths_with_hid("PNP0C09",table=self.dsdt) + if len(ec_list): + self.lpc_bus_device = ".".join(ec_list[0][0].split(".")[:-1]) + for x in ec_list: + device = orig_device = x[0] + #print(" --> {}".format(device)) + if device.split(".")[-1] == "EC": + named_ec = True + if not laptop: + # Only rename if we're trying to replace it + #print(" ----> PNP0C09 (EC) called EC. Renaming") + device = ".".join(device.split(".")[:-1]+["EC0"]) + rename = True + scope = "\n".join(self.acpi.get_scope(x[1],strip_comments=True,table=self.dsdt)) + # We need to check for _HID, _CRS, and _GPE + if all(y in scope for y in ["_HID","_CRS","_GPE"]): + #print(" ----> Valid PNP0C09 (EC) Device") + ec_located = True + sta = self.get_sta_var( + var=None, + device=orig_device, + dev_hid="PNP0C09", + dev_name=orig_device.split(".")[-1], + log_locate=False, + table=self.dsdt + ) + if not laptop: + ec_to_patch.append(device) + # Only unconditionally override _STA methods + # if not building for a laptop + if sta.get("patches"): + patches.extend(sta.get("patches",[])) + ec_sta[device] = sta + elif sta.get("patches"): + if sta_needs_patching(sta): + # Retain the info as we need to override it + ec_to_enable.append(device) + ec_enable_sta[device] = sta + # Disable the patches by default and add to the list + for patch in sta.get("patches",[]): + patch["Enabled"] = False + patch["Disabled"] = True + patches.append(patch) + if not ec_located: + pass + #print(" - No valid PNP0C09 (EC) devices found - only needs a Fake EC device") + if laptop and named_ec and not patches: + #print(" ----> Named EC device located - no fake needed.") + #print("") + #self.utils.request_input("Press [enter] to return to main menu...") + return + if not self.lpc_bus_device: + #self.utils.request_input("Press [enter] to return to main menu...") + return + if rename == True: + patches.insert(0,{ + "Comment":"EC to EC0{}".format("" if not ec_sta else " - must come before any EC _STA to XSTA renames!"), + "Find":"45435f5f", + "Replace":"4543305f" + }) + comment += " - Needs EC to EC0 {}".format( + "and EC _STA to XSTA renames" if ec_sta else "rename" + ) + elif ec_sta: + comment += " - Needs EC _STA to XSTA renames" + #oc = {"Comment":comment,"Enabled":True,"Path":"SSDT-EC.aml"} + #self.make_plist(oc, "SSDT-EC.aml", patches, replace=True) + #print("Creating SSDT-EC...") + ssdt = """ +DefinitionBlock ("", "SSDT", 2, "CORP ", "SsdtEC", 0x00001000) +{ + External ([[LPCName]], DeviceObj) +""".replace("[[LPCName]]",self.lpc_bus_device) + for x in ec_to_patch: + ssdt += " External ({}, DeviceObj)\n".format(x) + if x in ec_sta: + ssdt += " External ({}.XSTA, {})\n".format(x,ec_sta[x].get("sta_type","MethodObj")) + # Walk the ECs to enable + for x in ec_to_enable: + ssdt += " External ({}, DeviceObj)\n".format(x) + if x in ec_enable_sta: + # Add the _STA and XSTA refs as the patch may not be enabled + ssdt += " External ({0}._STA, {1})\n External ({0}.XSTA, {1})\n".format(x,ec_enable_sta[x].get("sta_type","MethodObj")) + # Walk them again and add the _STAs + for x in ec_to_patch: + ssdt += """ + Scope ([[ECName]]) + { + Method (_STA, 0, NotSerialized) // _STA: Status + { + If (_OSI ("Darwin")) + { + Return (0) + } + Else + { + Return ([[XSTA]]) + } + } + } +""".replace("[[LPCName]]",self.lpc_bus_device).replace("[[ECName]]",x) \ + .replace("[[XSTA]]","{}.XSTA{}".format(x," ()" if ec_sta[x].get("sta_type","MethodObj")=="MethodObj" else "") if x in ec_sta else "0x0F") + # Walk them yet again - and force enable as needed + for x in ec_to_enable: + ssdt += """ + If (LAnd (CondRefOf ([[ECName]].XSTA), LNot (CondRefOf ([[ECName]]._STA)))) + { + Scope ([[ECName]]) + { + Method (_STA, 0, NotSerialized) // _STA: Status + { + If (_OSI ("Darwin")) + { + Return (0x0F) + } + Else + { + Return ([[XSTA]]) + } + } + } + } +""".replace("[[LPCName]]", self.lpc_bus_device).replace("[[ECName]]",x) \ + .replace("[[XSTA]]","{}.XSTA{}".format(x," ()" if ec_enable_sta[x].get("sta_type","MethodObj")=="MethodObj" else "") if x in ec_enable_sta else "Zero") + # Create the faked EC + if not laptop or not named_ec: + ssdt += """ + Scope ([[LPCName]]) + { + Device (EC) + { + Name (_HID, "ACID0001") // _HID: Hardware ID + Method (_STA, 0, NotSerialized) // _STA: Status + { + If (_OSI ("Darwin")) + { + Return (0x0F) + } + Else + { + Return (Zero) + } + } + } + }""".replace("[[LPCName]]", self.lpc_bus_device) + # Close the SSDT scope + ssdt += """ +}""" + + if self.write_ssdt(ssdt_name, ssdt): + self.result.get("Patch").extend(patches) + self.result["Add"].append({ + "Comment": comment, + "Enabled": True, + "Path": f"{ssdt_name}.aml" + }) + + def fix_hp_005_post_error(self, motherboard_name): + if "HP" not in motherboard_name: + return + + if binascii.unhexlify("4701700070000108") in self.dsdt.get("raw"): + self.result.get("Patch").append({ + "Comment": "Fix HP Real-Time Clock Power Loss (005) Post Error", + "Find": "4701700070000108", + "Replace": "4701700070000102" + }) + + def add_null_ethernet_device(self, ethernet_pci): + if ethernet_pci: + return + + random_mac_address = self.smbios.generate_random_mac() + mac_address_byte = ", ".join([f'0x{random_mac_address[i:i+2]}' for i in range(0, len(random_mac_address), 2)]) + + comment = "Creates a Null Ethernet to allow macOS system access to iServices" + ssdt_name = "SSDT-RMNE" + ssdt_content = """ +// Resource: https://github.com/RehabMan/OS-X-Null-Ethernet/blob/master/SSDT-RMNE.dsl + +/* ssdt.dsl -- SSDT injector for NullEthernet + * + * Copyright (c) 2014 RehabMan + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +// Use this SSDT as an alternative to patching your DSDT... + +DefinitionBlock("", "SSDT", 2, "ZPSS", "RMNE", 0x00001000) +{ + Device (RMNE) + { + Name (_ADR, Zero) + // The NullEthernet kext matches on this HID + Name (_HID, "NULE0000") + // This is the MAC address returned by the kext. Modify if necessary. + Name (MAC, Buffer() { [[MACAddress]] }) + Method (_DSM, 4, NotSerialized) + { + If (LEqual (Arg2, Zero)) { Return (Buffer() { 0x03 } ) } + Return (Package() + { + "built-in", Buffer() { 0x00 }, + "IOName", "ethernet", + "name", Buffer() { "ethernet" }, + "model", Buffer() { "RM-NullEthernet-1001" }, + "device_type", Buffer() { "ethernet" }, + }) + } + + Method (_STA, 0, NotSerialized) // _STA: Status + { + If (_OSI ("Darwin")) + { + Return (0x0F) + } + Else + { + Return (Zero) + } + } + } +}""".replace("[[MACAddress]]", mac_address_byte) + + if self.write_ssdt(ssdt_name, ssdt_content): + self.result["Add"].append({ + "Comment": comment, + "Enabled": True, + "Path": f"{ssdt_name}.aml" + }) + + def is_intel_hedt_cpu(self, cpu_codename): + return "-E" in cpu_codename and not self.utils.contains_any(cpu_data.IntelCPUGenerations, cpu_codename, end=4) is None or \ + ("-X" in cpu_codename or "-W" in cpu_codename) and not self.utils.contains_any(cpu_data.IntelCPUGenerations, cpu_codename, start=4, end=6) is None + + def list_irqs(self): + # Walks the DSDT keeping track of the current device and + # saving the IRQNoFlags if found + devices = {} + current_device = None + current_hid = None + irq = False + last_irq = False + irq_index = 0 + for index,line in enumerate(self.acpi.get_dsdt_or_only()["lines"]): + if self.acpi.is_hex(line): + # Skip all hex lines + continue + if irq: + # Get the values + num = line.split("{")[1].split("}")[0].replace(" ","") + num = "#" if not len(num) else num + if current_device in devices: + if last_irq: # In a row + devices[current_device]["irq"] += ":"+num + else: # Skipped at least one line + irq_index = self.acpi.find_next_hex(index)[1] + devices[current_device]["irq"] += "-"+str(irq_index)+"|"+num + else: + irq_index = self.acpi.find_next_hex(index)[1] + devices[current_device] = {"irq":str(irq_index)+"|"+num} + irq = False + last_irq = True + elif "Device (" in line: + # Check if we retain the _HID here + if current_device and current_device in devices and current_hid: + # Save it + devices[current_device]["hid"] = current_hid + last_irq = False + current_hid = None + try: current_device = line.split("(")[1].split(")")[0] + except: + current_device = None + continue + elif "_HID, " in line and current_device: + try: current_hid = line.split('"')[1] + except: pass + elif "IRQNoFlags" in line and current_device: + # Next line has our interrupts + irq = True + # Check if just a filler line + elif len(line.replace("{","").replace("}","").replace("(","").replace(")","").replace(" ","").split("//")[0]): + # Reset last IRQ as it's not in a row + last_irq = False + # Retain the final _HID if needed + if current_device and current_device in devices and current_hid: + devices[current_device]["hid"] = current_hid + return devices + + def get_irq_choice(self, irqs): + names_and_hids = [ + "PIC", + "IPIC", + "TMR", + "TIMR", + "RTC", + "RTC0", + "RTC1", + "PNPC0000", + "PNP0100", + "PNP0B00" + ] + defaults = [x for x in irqs if x.upper() in names_and_hids or irqs[x].get("hid","").upper() in names_and_hids] + d = {} + + for x in defaults: + d[x] = self.target_irqs + return d + + def get_hex_from_irqs(self, irq, rem_irq = None): + # We need to search for a few different types: + # + # 22 XX XX 22 XX XX 22 XX XX (multiples on different lines) + # 22 XX XX (summed multiples in the same bracket - {0,8,11}) + # 22 XX XX (single IRQNoFlags entry) + # + # Can end with 79 [00] (end of method), 86 09 (middle of method) or 47 01 (unknown) + lines = [] + remd = [] + for a in irq.split("-"): + index,i = a.split("|") # Get the index + index = int(index) + find = self.get_int_for_line(i) + repl = [0]*len(find) + # Now we need to verify if we're patching *all* IRQs, or just some specifics + if rem_irq: + repl = [x for x in find] + matched = [] + for x in rem_irq: + # Get the int + rem = self.convert_irq_to_int(x) + repl1 = [y&(rem^0xFFFF) if y >= rem else y for y in repl] + if repl1 != repl: + # Changes were made + remd.append(x) + repl = [y for y in repl1] + # Get the hex + d = { + "irq":i, + "find": "".join(["22"+self.acpi.get_hex_from_int(x) for x in find]), + "repl": "".join(["22"+self.acpi.get_hex_from_int(x) for x in repl]), + "remd": remd, + "index": index + } + d["changed"] = not (d["find"]==d["repl"]) + lines.append(d) + return lines + + def get_int_for_line(self, irq): + irq_list = [] + for i in irq.split(":"): + irq_list.append(self.same_line_irq(i)) + return irq_list + + def convert_irq_to_int(self, irq): + b = "0"*(16-irq)+"1"+"0"*(irq) + return int(b,2) + + def same_line_irq(self, irq): + # We sum the IRQ values and return the int + total = 0 + for i in irq.split(","): + if i == "#": + continue # Null value + try: i=int(i) + except: continue # Not an int + if i > 15 or i < 0: + continue # Out of range + total = total | self.convert_irq_to_int(i) + return total + + def fix_irq_conflicts(self, platform, cpu_codename): + if "Laptop" not in platform or self.utils.contains_any(cpu_data.IntelCPUGenerations, cpu_codename, end=4) is None: + return + + hpets = self.acpi.get_device_paths_with_hid("PNP0103") + hpet_fake = not hpets + hpet_sta = False + sta = None + if hpets: + name = hpets[0][0] + + sta = self.get_sta_var(var=None,dev_hid="PNP0103",dev_name="HPET",log_locate=False) + if sta.get("patches"): + hpet_sta = True + self.result.get("Patch").extend(sta.get("patches",[])) + + hpet = self.acpi.get_method_paths(name+"._CRS") or self.acpi.get_name_paths(name+"._CRS") + if not hpet: + return + + crs_index = self.acpi.find_next_hex(hpet[0][1])[1] + + mem_base = mem_length = primed = None + for line in self.acpi.get_scope(hpets[0][1],strip_comments=True): + if "Memory32Fixed (" in line: + primed = True + continue + if not primed: + continue + elif ")" in line: # Reached the end of the scope + break + # We're primed, and not at the end - let's try to get the base and length + try: + val = line.strip().split(",")[0].replace("Zero","0x0").replace("One","0x1") + check = int(val,16) + except: + break + # Set them in order + if mem_base is None: + mem_base = val + else: + mem_length = val + break # Leave after we get both values + # Check if we found the values + got_mem = mem_base and mem_length + if not got_mem: + mem_base = "0xFED00000" + mem_length = "0x00000400" + crs = "5F435253" + xcrs = "58435253" + padl,padr = self.acpi.get_shortest_unique_pad(crs, crs_index) + self.result.get("Patch").append({"Comment":"{} _CRS to XCRS Rename".format(name.split(".")[-1].lstrip("\\")),"Find":padl+crs+padr,"Replace":padl+xcrs+padr}) + else: + ec_list = self.acpi.get_device_paths_with_hid("PNP0C09") + name = None + if len(ec_list): + name = ".".join(ec_list[0][0].split(".")[:-1]) + if name == None: + for x in ("LPCB", "LPC0", "LPC", "SBRG", "PX40"): + try: + name = self.acpi.get_device_paths(x)[0][0] + break + except: pass + if not name: + return + + devs = self.list_irqs() + target_irqs = self.get_irq_choice(devs) + if target_irqs is None: return # Bailed, going to the main menu + # Let's apply patches as we go + saved_dsdt = self.dsdt.get("raw") + unique_patches = {} + generic_patches = [] + for dev in devs: + if not dev in target_irqs: + continue + irq_patches = self.get_hex_from_irqs(devs[dev]["irq"],target_irqs[dev]) + i = [x for x in irq_patches if x["changed"]] + for a,t in enumerate(i): + if not t["changed"]: + # Nothing patched - skip + continue + # Try our endings here - 7900, 8609, and 4701 - also allow for up to 8 chars of pad (thanks MSI) + matches = re.findall("("+t["find"]+"(.{0,8})(7900|4701|8609))",self.acpi.get_hex_starting_at(t["index"])[0]) + if not len(matches): + continue + if len(matches) > 1: + # Found too many matches! + # Add them all as find/replace entries + for x in matches: + generic_patches.append({ + "remd":",".join([str(y) for y in set(t["remd"])]), + "orig":t["find"], + "find":t["find"]+"".join(x[1:]), + "repl":t["repl"]+"".join(x[1:]) + }) + continue + ending = "".join(matches[0][1:]) + padl,padr = self.acpi.get_shortest_unique_pad(t["find"]+ending, t["index"]) + t_patch = padl+t["find"]+ending+padr + r_patch = padl+t["repl"]+ending+padr + if not dev in unique_patches: + unique_patches[dev] = [] + unique_patches[dev].append({ + "dev":dev, + "remd":",".join([str(y) for y in set(t["remd"])]), + "orig":t["find"], + "find":t_patch, + "repl":r_patch + }) + # Walk the unique patches if any + if len(unique_patches): + for x in unique_patches: + for i,p in enumerate(unique_patches[x]): + patch_name = "{} IRQ {} Patch".format(x, p["remd"]) + if len(unique_patches[x]) > 1: + patch_name += " - {} of {}".format(i+1, len(unique_patches[x])) + self.result.get("Patch").append({ + "Comment": patch_name, + "Find": p["find"], + "Replace": p["repl"] + }) + # Walk the generic patches if any + if len(generic_patches): + generic_set = [] # Make sure we don't repeat find values + for x in generic_patches: + if x in generic_set: + continue + generic_set.append(x) + + for i,x in enumerate(generic_set): + patch_name = "Generic IRQ Patch {} of {} - {} - {}".format(i+1,len(generic_set),x["remd"],x["orig"]) + self.result.get("Patch").append({ + "Comment": patch_name, + "Find": x["find"], + "Replace": x["repl"], + "Enabled": False + }) + # Restore the original DSDT in memory + self.dsdt["raw"] = saved_dsdt + + comment = "HPET Device Fake" if hpet_fake else "{} _CRS (Needs _CRS to XCRS Rename)".format(name.split(".")[-1].lstrip("\\")) + ssdt_name = "SSDT-HPET" + + if hpet_fake: + ssdt_content = """// Fake HPET device +// +DefinitionBlock ("", "SSDT", 2, "CORP", "HPET", 0x00000000) +{ + External ([[name]], DeviceObj) + + Scope ([[name]]) + { + Device (HPET) + { + Name (_HID, EisaId ("PNP0103") /* HPET System Timer */) // _HID: Hardware ID + Name (_CID, EisaId ("PNP0C01") /* System Board */) // _CID: Compatible ID + Method (_STA, 0, NotSerialized) // _STA: Status + { + If (_OSI ("Darwin")) + { + Return (0x0F) + } + Else + { + Return (Zero) + } + } + Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings + { + IRQNoFlags () + {0,8,11} + Memory32Fixed (ReadWrite, + 0xFED00000, // Address Base + 0x00000400, // Address Length + ) + }) + } + } +}""".replace("[[name]]",name) + else: + ssdt_content = """// +// Supplementary HPET _CRS from Goldfish64 +// Requires the HPET's _CRS to XCRS rename +// +DefinitionBlock ("", "SSDT", 2, "CORP", "HPET", 0x00000000) +{ + External ([[name]], DeviceObj) + External ([[name]].XCRS, [[type]]) + + Scope ([[name]]) + { + Name (BUFX, ResourceTemplate () + { + IRQNoFlags () + {0,8,11} + Memory32Fixed (ReadWrite, + // [[mem]] + [[mem_base]], // Address Base + [[mem_length]], // Address Length + ) + }) + Method (_CRS, 0, Serialized) // _CRS: Current Resource Settings + { + // Return our buffer if booting macOS or the XCRS method + // no longer exists for some reason + If (LOr (_OSI ("Darwin"), LNot(CondRefOf ([[name]].XCRS)))) + { + Return (BUFX) + } + // Not macOS and XCRS exists - return its result + Return ([[name]].XCRS[[method]]) + }""" \ + .replace("[[name]]",name) \ + .replace("[[type]]","MethodObj" if hpet[0][-1] == "Method" else "BuffObj") \ + .replace("[[mem]]","Base/Length pulled from DSDT" if got_mem else "Default Base/Length - verify with your DSDT!") \ + .replace("[[mem_base]]",mem_base) \ + .replace("[[mem_length]]",mem_length) \ + .replace("[[method]]"," ()" if hpet[0][-1]=="Method" else "") + if hpet_sta: + # Inject our external reference to the renamed XSTA method + ssdt_parts = [] + external = False + for line in ssdt_content.split("\n"): + if "External (" in line: external = True + elif external: + ssdt_parts.append(" External ({}.XSTA, {})".format(name,sta["sta_type"])) + external = False + ssdt_parts.append(line) + ssdt_content = "\n".join(ssdt_parts) + # Add our method + ssdt_content += """ + Method (_STA, 0, NotSerialized) // _STA: Status + { + // Return 0x0F if booting macOS or the XSTA method + // no longer exists for some reason + If (LOr (_OSI ("Darwin"), LNot (CondRefOf ([[name]].XSTA)))) + { + Return (0x0F) + } + // Not macOS and XSTA exists - return its result + Return ([[name]].XSTA[[called]]) + }""".replace("[[name]]",name).replace("[[called]]"," ()" if sta["sta_type"]=="MethodObj" else "") + ssdt_content += """ + } +}""" + + if self.write_ssdt(ssdt_name, ssdt_content): + self.result["Add"].append({ + "Comment": comment, + "Enabled": True, + "Path": f"{ssdt_name}.aml" + }) + + def fix_system_clock_awac(self, motherboard_chipset): + if not self.utils.contains_any(chipset_data.IntelChipsets, motherboard_chipset, start=85): + return + + rtc_range_needed = False + rtc_crs_type = None + crs_lines = [] + lpc_name = None + awac_dict = self.get_sta_var(var="STAS",dev_hid="ACPI000E",dev_name="AWAC") + rtc_dict = self.get_sta_var(var="STAS",dev_hid="PNP0B00",dev_name="RTC") + # At this point - we should have any info about our AWAC and RTC devices + # we need. Let's see if we need an RTC fake - then build the SSDT. + if not rtc_dict.get("valid"): + #print(" - Fake needed!") + lpc_name = self.get_lpc_name() + if lpc_name is None: + self.utils.request_input("Press [enter] to return to main menu...") + return + else: + # Let's check if our RTC device has a _CRS variable - and if so, let's look for any skipped ranges + #print(" --> Checking for _CRS...") + rtc_crs = self.acpi.get_method_paths(rtc_dict["device"][0]+"._CRS") or self.acpi.get_name_paths(rtc_dict["device"][0]+"._CRS") + if rtc_crs: + #print(" ----> {}".format(rtc_crs[0][0])) + rtc_crs_type = "MethodObj" if rtc_crs[0][-1] == "Method" else "BuffObj" + # Only check for the range if it's a buffobj + if rtc_crs_type.lower() == "buffobj": + last_adr = last_len = last_ind = None + crs_scope = self.acpi.get_scope(rtc_crs[0][1]) + # Let's try and clean up the scope - it's often a jumbled mess + pad_len = len(crs_scope[0])-len(crs_scope[0].lstrip()) + pad = crs_scope[0][:pad_len] + fixed_scope = [] + for line in crs_scope: + if line.startswith(pad): # Got a full line - strip the pad, and save it + fixed_scope.append(line[pad_len:]) + else: # Likely a part of the prior line + fixed_scope[-1] = fixed_scope[-1]+line + for i,line in enumerate(fixed_scope): + if "Name (_CRS, " in line: + # Rename _CRS to BUFX for later - and strip any comments to avoid confusion + line = line.replace("Name (_CRS, ","Name (BUFX, ").split(" //")[0] + if "IO (Decode16," in line: + # We have our start - get the the next line, and 4th line + try: + curr_adr = int(fixed_scope[i+1].strip().split(",")[0],16) + curr_len = int(fixed_scope[i+4].strip().split(",")[0],16) + curr_ind = i+4 # Save the value we may pad + except: # Bad values? Bail... + #print(" ----> Failed to gather values - could not verify RTC range.") + rtc_range_needed = False + break + if last_adr is not None: # Compare our range values + adjust = curr_adr - (last_adr + last_len) + if adjust: # We need to increment the previous length by our adjust value + rtc_range_needed = True + #print(" ----> Adjusting IO range {} length to {}".format(self.hexy(last_adr,pad_to=4),self.hexy(last_len+adjust,pad_to=2))) + try: + hex_find,hex_repl = self.hexy(last_len,pad_to=2),self.hexy(last_len+adjust,pad_to=2) + crs_lines[last_ind] = crs_lines[last_ind].replace(hex_find,hex_repl) + except: + #print(" ----> Failed to adjust values - could not verify RTC range.") + rtc_range_needed = False + break + # Save our last values + last_adr,last_len,last_ind = curr_adr,curr_len,curr_ind + crs_lines.append(line) + if rtc_range_needed: # We need to generate a rename for _CRS -> XCRS + # print(" --> Generating _CRS to XCRS rename...") + crs_index = self.acpi.find_next_hex(rtc_crs[0][1])[1] + #print(" ----> Found at index {}".format(crs_index)) + crs_hex = "5F435253" # _CRS + xcrs_hex = "58435253" # XCRS + padl,padr = self.acpi.get_shortest_unique_pad(crs_hex, crs_index) + patches = rtc_dict.get("patches",[]) + patches.append({"Comment":"{} _CRS to XCRS Rename".format(rtc_dict["dev_name"]),"Find":padl+crs_hex+padr,"Replace":padl+xcrs_hex+padr}) + rtc_dict["patches"] = patches + rtc_dict["crs"] = True + else: + pass + #print(" ----> Not found") + # Let's see if we even need an SSDT + # Not required if AWAC is not present; RTC is present, doesn't have an STAS var, and doesn't have an _STA method, and no range fixes are needed + if not awac_dict.get("valid") and rtc_dict.get("valid") and not rtc_dict.get("has_var") and not rtc_dict.get("sta") and not rtc_range_needed: + #print("") + #print("Valid PNP0B00 (RTC) device located and qualified, and no ACPI000E (AWAC) devices found.") + #print("No patching or SSDT needed.") + #print("") + #self.utils.request_input("Press [enter] to return to main menu...") + return + comment = "Incompatible AWAC Fix" if awac_dict.get("valid") else "RTC Fake" if not rtc_dict.get("valid") else "RTC Range Fix" if rtc_range_needed else "RTC Enable Fix" + suffix = [] + for x in (awac_dict,rtc_dict): + if not x.get("valid"): continue + val = "" + if x.get("sta") and not x.get("has_var"): + val = "{} _STA to XSTA".format(x["dev_name"]) + if x.get("crs"): + val += "{} _CRS to XCRS".format(" and " if val else x["dev_name"]) + if val: suffix.append(val) + if suffix: + comment += " - Requires {} Rename".format(", ".join(suffix)) + # At this point - we need to do the following: + # 1. Change STAS if needed + # 2. Setup _STA with _OSI and call XSTA if needed + # 3. Fake RTC if needed + + ssdt_name = "SSDT-RTCAWAC" + ssdt = """// +// Original sources from Acidanthera: +// - https://github.com/acidanthera/OpenCorePkg/blob/master/Docs/AcpiSamples/SSDT-AWAC.dsl +// - https://github.com/acidanthera/OpenCorePkg/blob/master/Docs/AcpiSamples/SSDT-RTC0.dsl +// +// +DefinitionBlock ("", "SSDT", 2, "ZPSS", "RTCAWAC", 0x00000000) +{ +""" + if any(x.get("has_var") for x in (awac_dict,rtc_dict)): + ssdt += """ External (STAS, IntObj) + Scope (\\) + { + Method (_INI, 0, NotSerialized) // _INI: Initialize + { + If (_OSI ("Darwin")) + { + Store (One, STAS) + } + } + } +""" + for x in (awac_dict,rtc_dict): + if not x.get("valid") or x.get("has_var") or not x.get("device"): continue + # Device was found, and it doesn't have the STAS var - check if we + # have an _STA (which would be renamed) + macos,original = ("Zero","0x0F") if x.get("dev_hid") == "ACPI000E" else ("0x0F","Zero") + if x.get("sta"): + ssdt += """ External ([[DevPath]], DeviceObj) + External ([[DevPath]].XSTA, [[sta_type]]) + Scope ([[DevPath]]) + { + Name (ZSTA, [[Original]]) + Method (_STA, 0, NotSerialized) // _STA: Status + { + If (_OSI ("Darwin")) + { + Return ([[macOS]]) + } + // Default to [[Original]] - but return the result of the renamed XSTA if possible + If (CondRefOf ([[DevPath]].XSTA)) + { + Store ([[DevPath]].XSTA[[called]], ZSTA) + } + Return (ZSTA) + } + } +""".replace("[[DevPath]]",x["device"][0]).replace("[[Original]]",original).replace("[[macOS]]",macos).replace("[[sta_type]]",x["sta_type"]).replace("[[called]]"," ()" if x["sta_type"]=="MethodObj" else "") + elif x.get("dev_hid") == "ACPI000E": + # AWAC device with no STAS, and no _STA - let's just add one + ssdt += """ External ([[DevPath]], DeviceObj) + Scope ([[DevPath]]) + { + Method (_STA, 0, NotSerialized) // _STA: Status + { + If (_OSI ("Darwin")) + { + Return (Zero) + } + Else + { + Return (0x0F) + } + } + } +""".replace("[[DevPath]]",x["device"][0]) + # Check if we need to setup an RTC range correction + if rtc_range_needed and rtc_crs_type.lower() == "buffobj" and crs_lines and rtc_dict.get("valid"): + ssdt += """ External ([[DevPath]], DeviceObj) + External ([[DevPath]].XCRS, [[type]]) + Scope ([[DevPath]]) + { + // Adjusted and renamed _CRS buffer ripped from DSDT with corrected range +[[NewCRS]] + // End of adjusted _CRS and renamed buffer + + // Create a new _CRS method that returns the result of the renamed XCRS + Method (_CRS, 0, Serialized) // _CRS: Current Resource Settings + { + If (LOr (_OSI ("Darwin"), LNot (CondRefOf ([[DevPath]].XCRS)))) + { + // Return our buffer if booting macOS or the XCRS method + // no longer exists for some reason + Return (BUFX) + } + // Not macOS and XCRS exists - return its result + Return ([[DevPath]].XCRS[[method]]) + } + } +""".replace("[[DevPath]]",rtc_dict["device"][0]) \ + .replace("[[type]]",rtc_crs_type) \ + .replace("[[method]]"," ()" if rtc_crs_type == "Method" else "") \ + .replace("[[NewCRS]]","\n".join([(" "*8)+x for x in crs_lines])) + # Check if we do not have an RTC device at all + if not rtc_dict.get("valid") and lpc_name: + ssdt += """ External ([[LPCName]], DeviceObj) // (from opcode) + Scope ([[LPCName]]) + { + Device (RTC0) + { + Name (_HID, EisaId ("PNP0B00")) // _HID: Hardware ID + Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings + { + IO (Decode16, + 0x0070, // Range Minimum + 0x0070, // Range Maximum + 0x01, // Alignment + 0x08, // Length + ) + IRQNoFlags () + {8} + }) + Method (_STA, 0, NotSerialized) // _STA: Status + { + If (_OSI ("Darwin")) + { + Return (0x0F) + } + Else + { + Return (0) + } + } + } + } +""".replace("[[LPCName]]",lpc_name) + ssdt += "}" + + if self.write_ssdt(ssdt_name, ssdt): + self.result.get("Patch").extend(rtc_dict["patches"]) + self.result["Add"].append({ + "Comment": comment, + "Enabled": True, + "Path": f"{ssdt_name}.aml" + }) + + def fix_system_clock_hedt(self, motherboard_chipset, macos_version): + if macos_version < 20 or not self.utils.contains_any(["X99", "X299"], motherboard_chipset): + return + + if not self.lpc_bus_device: + return + + awac_device = self.acpi.get_device_paths_with_hid("ACPI000E") + rtc_device_name = self.acpi.get_device_paths_with_hid("PNP0B00")[0][0].split(".")[-1] + + comment = "Creates a new RTC device to resolve PCI Configuration issues in macOS Big Sur 11+" + ssdt_name = "SSDT-RTC0-RANGE" + ssdt_content = """ +// Resource: https://github.com/acidanthera/OpenCorePkg/blob/master/Docs/AcpiSamples/Source/SSDT-RTC0-RANGE.dsl + +/* + * On certain motherboards(mainly Asus X299 boards), not all ports are + * mapped in the RTC device. For the majority of the time, users will not notice + * this issue though in extreme circumstances macOS may halt in early booting. + * Most prominently seen around the PCI Configuration stage with macOS 11 Big Sur. + * + * To resolve this, we'll want to create a new RTC device(PNP0B00) with the correct + * range. + * + * Note that due to AWAC systems having an _STA method already defined, attempting + * to set another _STA method in your RTC device will conflict. To resolve this, + * SSDT-AWAC should be removed and instead opt for this SSDT instead. + */ +DefinitionBlock ("", "SSDT", 2, "ZPSS", "RtcRange", 0x00000000) +{ + External ([[LPCPath]], DeviceObj)""" + if not awac_device: + ssdt_content += """ + External ([[LPCPath]].[[RTCName]], DeviceObj)""" + ssdt_content += """ + Scope ([[LPCPath]]) + {""" + if not awac_device: + ssdt_content += """ + Scope ([[RTCName]]) + { + Method (_STA, 0, NotSerialized) // _STA: Status + { + If (_OSI ("Darwin")) + { + Return (Zero) + } + Else + { + Return (0x0F) + } + } + }""".replace("[[RTCName]]", rtc_device_name) + + ssdt_content += """ + Device (RTC0) + { + /* + * Change the below _CSR range to match your hardware. + * + * For this example, we'll use the Asus Strix X299-E Gaming's ACPI, and show how to correct it. + * Within the original RTC device, we see that sections 0x70 through 0x77 are mapped: + * + * Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings + * { + * IO (Decode16, + * 0x0070, // Range Minimum 1 + * 0x0070, // Range Maximum 1 + * 0x01, // Alignment 1 + * 0x02, // Length 1 + * ) + * IO (Decode16, + * 0x0074, // Range Minimum 2 + * 0x0074, // Range Maximum 2 + * 0x01, // Alignment 2 + * 0x04, // Length 2 + * ) + * IRQNoFlags () + * {8} + * }) + * + * Though Asus seems to have forgotten to map sections 0x72 and 0x73 in the first bank, so + * we'll want to expand the range to include them under Length 1. + * Note that not all boards will be the same, verify with your ACPI tables for both the range and + * missing regions. + */ + + Name (_HID, EisaId ("PNP0B00")) // _HID: Hardware ID + Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings + { + IO (Decode16, + 0x0070, // Range Minimum 1 + 0x0070, // Range Maximum 1 + 0x01, // Alignment 1 + 0x04, // Length 1 (Expanded to include 0x72 and 0x73) + ) + IO (Decode16, + 0x0074, // Range Minimum 2 + 0x0074, // Range Maximum 2 + 0x01, // Alignment 2 + 0x04, // Length 2 + ) + IRQNoFlags () + {8} + }) + Method (_STA, 0, NotSerialized) // _STA: Status + { + If (_OSI ("Darwin")) + { + Return (0x0F) + } + Else + { + Return (Zero) + } + } + } + } +}""" + + ssdt_content = ssdt_content.replace("[[LPCPath]]", self.lpc_bus_device).replace("[[RTCName]]", rtc_device_name) + if self.write_ssdt(ssdt_name, ssdt_content): + self.result["Add"].append({ + "Comment": comment, + "Enabled": True, + "Path": f"{ssdt_name}.aml" + }) + + def instant_wake_fix(self): + comment = "Fix sleep state values in _PRW methods to prevent immediate wake in macOS" + ssdt_name = "SSDT-PRW" + + uswe_object = "9355535745" + wole_object = "93574F4C45" + gprw_method = "4750525702" + uprw_method = "5550525702" + xprw_method = "5850525702" + + if binascii.unhexlify(gprw_method) in self.dsdt.get("raw"): + self.result.get("Patch").append({ + "Comment": "GPRW to XPRW Rename", + "Find": gprw_method, + "Replace": xprw_method + }) + if binascii.unhexlify(uprw_method) in self.dsdt.get("raw"): + self.result.get("Patch").append({ + "Comment": "UPRW to XPRW Rename", + "Find": uprw_method, + "Replace": xprw_method + }) + if not binascii.unhexlify(uswe_object) in self.dsdt.get("raw"): + uswe_object = None + if not binascii.unhexlify(wole_object) in self.dsdt.get("raw"): + wole_object = None + + ssdt_content = """ +// Resource: https://github.com/5T33Z0/OC-Little-Translated/blob/main/04_Fixing_Sleep_and_Wake_Issues/060D_Instant_Wake_Fix/README.md + +DefinitionBlock ("", "SSDT", 2, "ZPSS", "_PRW", 0x00000000) +{""" + if binascii.unhexlify(gprw_method[2:]) in self.dsdt.get("raw"): + ssdt_content += """\n External(XPRW, MethodObj)""" + if uswe_object: + ssdt_content += f"\n External (USWE, FieldUnitObj)" + if wole_object: + ssdt_content += f"\n External (WOLE, FieldUnitObj)" + if uswe_object or wole_object: + ssdt_content += """\n + Scope (\\) + { + If (_OSI ("Darwin")) + {""" + if uswe_object: + ssdt_content += f"\n USWE = Zero" + if wole_object: + ssdt_content += f"\n WOLE = Zero" + ssdt_content += """ } + }""" + if binascii.unhexlify(gprw_method) in self.dsdt.get("raw"): + ssdt_content += """ + Method (GPRW, 2, NotSerialized) + { + If (_OSI ("Darwin")) + { + If ((0x6D == Arg0)) + { + Return (Package () + { + 0x6D, + Zero + }) + } + + If ((0x0D == Arg0)) + { + Return (Package () + { + 0x0D, + Zero + }) + } + } + Return (XPRW (Arg0, Arg1)) + }""" + if binascii.unhexlify(uprw_method) in self.dsdt.get("raw"): + ssdt_content += """ + Method (UPRW, 2, NotSerialized) + { + If (_OSI ("Darwin")) + { + If ((0x6D == Arg0)) + { + Return (Package () + { + 0x6D, + Zero + }) + } + + If ((0x0D == Arg0)) + { + Return (Package () + { + 0x0D, + Zero + }) + } + } + Return (XPRW (Arg0, Arg1)) + }""" + ssdt_content += "\n}" + if self.write_ssdt(ssdt_name, ssdt_content): + self.result["Add"].append({ + "Comment": comment, + "Enabled": True, + "Path": f"{ssdt_name}.aml" + }) + + def fix_uncore_bridge(self, motherboard_chipset, macos_version): + if macos_version < 20 or not self.utils.contains_any(["X79", "C602", "Patsburg", "C612", "X99", "Wellsburg"], motherboard_chipset): + return + + unc0_device = self.acpi.get_device_paths("UNC0") + + if not unc0_device: + return + + comment = "Disables unused uncore bridges to prevent kenel panic in macOS Big Sur 11+" + ssdt_name = "SSDT-UNC" + ssdt_content = """ +// Resource: https://github.com/acidanthera/OpenCorePkg/blob/master/Docs/AcpiSamples/Source/SSDT-UNC.dsl + +/* + * Discovered on X99-series. + * These platforms have uncore PCI bridges for 4 CPU sockets + * present in ACPI despite having none physically. + * + * Under normal conditions these are disabled depending on + * CPU presence in the socket via Processor Bit Mask (PRBM), + * but on X99 this code is unused or broken as such bridges + * simply do not exist. We fix that by writing 0 to PRBM. + * + * Doing so is important as starting with macOS 11 IOPCIFamily + * will crash as soon as it sees non-existent PCI bridges. + */ + +DefinitionBlock ("", "SSDT", 2, "ZPSS", "UNC", 0x00000000) +{ + External (_SB.UNC0, DeviceObj) + External (PRBM, IntObj) + + Scope (_SB.UNC0) + { + Method (_INI, 0, NotSerialized) + { + // In most cases this patch does benefit all operating systems, + // yet on select pre-Windows 10 it may cause issues. + // Remove If (_OSI ("Darwin")) in case you have none. + If (_OSI ("Darwin")) { + PRBM = 0 + } + } + } +}""" + + if self.write_ssdt(ssdt_name, ssdt_content): + self.result["Add"].append({ + "Comment": comment, + "Enabled": True, + "Path": f"{ssdt_name}.aml" + }) + + def operating_system_patch(self, platform): + if not "Laptop" in platform: + return + + comment = "Spoofs the operating system to Windows, enabling devices locked behind non-Windows systems on macOS" + ssdt_name = "SSDT-XOSI" + ssdt_content = """ +// Resource: https://github.com/dortania/Getting-Started-With-ACPI/blob/master/extra-files/decompiled/SSDT-XOSI.dsl + +DefinitionBlock ("", "SSDT", 2, "ZPSS", "XOSI", 0x00001000) +{ + Method (XOSI, 1, NotSerialized) + { + // Based off of: + // https://docs.microsoft.com/en-us/windows-hardware/drivers/acpi/winacpi-osi#_osi-strings-for-windows-operating-systems + // Add OSes from the below list as needed, most only check up to Windows 2015 + // but check what your DSDT looks for + Store (Package () + { +[[OSIStrings]] + }, Local0) + If (_OSI ("Darwin")) + { + Return (LNotEqual (Match (Local0, MEQ, Arg0, MTR, Zero, Zero), Ones)) + } + Else + { + Return (_OSI (Arg0)) + } + } +}""".replace("[[OSIStrings]]", "\n,".join([f" \"{osi_string}\"" for target_os, osi_string in self.osi_strings.items() if osi_string in self.dsdt.get("table")])) + + osid = self.acpi.get_method_paths("OSID") + if osid: + self.result.get("Patch").append({ + "Comment": "OSID to XSID rename - must come before _OSI to XOSI rename!", + "Find": "4F534944", + "Replace": "58534944" + }) + + osif = self.acpi.get_method_paths("OSIF") + if osif: + self.result.get("Patch").append({ + "Comment": "OSIF to XSIF rename - must come before _OSI to XOSI rename!", + "Find": "4F534946", + "Replace": "58534946" + }) + + self.result.get("Patch").append({ + "Comment": "_OSI to XOSI rename - requires SSDT-XOSI.aml", + "Find": "5F4F5349", + "Replace": "584F5349" + }) + + if self.write_ssdt(ssdt_name, ssdt_content): + self.result["Add"].append({ + "Comment": comment, + "Enabled": True, + "Path": f"{ssdt_name}.aml" + }) + + def surface_laptop_special_patch(self, motherboard_name, platform): + if "Surface".upper() not in motherboard_name or "Laptop" not in platform: + return + + comment = "Special Patch for all Surface Pro / Book / Laptop hardwares" + ssdt_name = "SSDT-SURFACE" + ssdt_content = """ +DefinitionBlock ("", "SSDT", 2, "ZPSS", "Surface", 0x00001000) +{ + External (_SB_.PCI0, DeviceObj) + External (GPRW, MethodObj) // 2 Arguments + + If (_OSI ("Darwin")) + { + Scope (_SB) + { + Device (ALS0) + { + Name (_HID, "ACPI0008" /* Ambient Light Sensor Device */) // _HID: Hardware ID + Name (_CID, "smc-als") // _CID: Compatible ID + Name (_ALI, 0x012C) // _ALI: Ambient Light Illuminance + Name (_ALR, Package (0x05) // _ALR: Ambient Light Response + { + Package (0x02) + { + 0x46, + Zero + }, + + Package (0x02) + { + 0x49, + 0x0A + }, + + Package (0x02) + { + 0x55, + 0x50 + }, + + Package (0x02) + { + 0x64, + 0x012C + }, + + Package (0x02) + { + 0x96, + 0x03E8 + } + }) + Method (XALI, 1, Serialized) + { + _ALI = Arg0 + } + } + + Device (ADP0) + { + Name (_HID, "ACPI0003" /* Power Source Device */) // _HID: Hardware ID + Name (SPSR, Zero) + Method (_PRW, 0, NotSerialized) // _PRW: Power Resources for Wake + { + Return (GPRW (0x6D, 0x04)) + } + + Method (_STA, 0, NotSerialized) // _STA: Status + { + Return (0x0F) + } + + Method (XPSR, 1, Serialized) + { + If ((Arg0 == Zero)) + { + SPSR = Zero + } + ElseIf ((Arg0 == One)) + { + SPSR = One + } + + Notify (ADP0, 0x80) // Status Change + } + + Method (_PSR, 0, Serialized) // _PSR: Power Source + { + Return (SPSR) /* \\_SB_.ADP0.SPSR */ + } + + Method (_PCL, 0, NotSerialized) // _PCL: Power Consumer List + { + Return (\\_SB) + } + } + + Device (BAT0) + { + Name (_HID, EisaId ("PNP0C0A") /* Control Method Battery */) // _HID: Hardware ID + Name (_UID, Zero) // _UID: Unique ID + Name (_PCL, Package (0x01) // _PCL: Power Consumer List + { + _SB + }) + Method (_STA, 0, NotSerialized) // _STA: Status + { + Return (0x1F) + } + } + } + + Scope (_SB.PCI0) + { + Device (IPTS) + { + Name (_ADR, 0x00160004) // _ADR: Address + } + } + } +}""" + + if self.write_ssdt(ssdt_name, ssdt_content): + self.result["Add"].append({ + "Comment": comment, + "Enabled": True, + "Path": f"{ssdt_name}.aml" + }) + + def battery_status_check(self, platform): + if "Laptop" not in platform: + return + + if not self.dsdt: + self.result["Battery Status Patch Needed"] = True + return + + search_start_idx = 0 + + while "EmbeddedControl" in self.dsdt.get("table")[search_start_idx:]: + emb_ctrl_start_idx = self.dsdt.get("table").index("EmbeddedControl", search_start_idx) + emb_ctrl_end_idx = emb_ctrl_start_idx + self.dsdt.get("table")[emb_ctrl_start_idx:].index("}") + emb_ctrl_block = self.dsdt.get("table")[emb_ctrl_start_idx:emb_ctrl_end_idx] + + for line in emb_ctrl_block.splitlines(): + if ", " in line and ", 8" not in line: + self.result["Battery Status Patch Needed"] = True + return + + search_start_idx = emb_ctrl_end_idx + + return + + def select_dsdt(self): + results_path = os.path.join(os.getcwd(), "Results") + apcidump_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "acpidump.exe") + while True: + self.utils.head("Select ACPI Tables") + print("") + if sys.platform == "win32": + print("To manually dump ACPI tables, open Command Prompt and enter the following\ncommands in sequence:") + print("") + print(" cd \"{}\"".format(results_path.replace("/", "\\"))) + print(" mkdir \"ACPI Table\"") + print(" cd \"ACPI Table\"") + print(" \"{}\" -b".format(apcidump_path.replace("/", "\\"))) + print(" rename *.dat *.aml") + print("") + print("The ACPI tables will now be available in\n \"{}\\ACPI Tables\"".format(results_path.replace("/", "\\"))) + print("") + if sys.platform.startswith("linux") or sys.platform == "win32": + print("P. Dump ACPI Tables") + print("Q. Quit") + print(" ") + menu = self.utils.request_input("Please drag and drop ACPI Tables folder here: ") + if menu.lower() == "p" and (sys.platform.startswith("linux") or sys.platform == "win32"): + return self.read_dsdt( + self.acpi.dump_tables(os.path.join(results_path, "ACPI Tables")) + ) + elif menu.lower() == "q": + self.utils.exit_program() + path = self.utils.normalize_path(menu) + if not path: + continue + return self.read_dsdt(path) + + def initialize_patches(self, motherboard_name, motherboard_chipset, platform, cpu_manufacturer, cpu_codename, integrated_gpu, ethernet_pci, touchpad_communication, smbios, intel_mei, unsupported_devices, macos_version, acpi_directory): + self.acpi_directory = self.check_acpi_directory(acpi_directory) + + if self.select_dsdt(): + self.dsdt = self.acpi.get_dsdt_or_only() + self.get_low_pin_count_bus_device() + self.add_intel_management_engine(cpu_codename, intel_mei) + self.add_memory_controller_device(cpu_manufacturer, cpu_codename, smbios) + self.add_null_ethernet_device(ethernet_pci) + self.add_system_management_bus_device(cpu_manufacturer, cpu_codename) + self.add_usb_power_properties(smbios) + self.ambient_light_sensor(motherboard_name, platform, integrated_gpu) + self.battery_status_check(platform) + self.disable_rhub_devices() + self.disable_unsupported_device(unsupported_devices) + self.enable_backlight_controls(platform, cpu_codename, integrated_gpu) + self.enable_cpu_power_management(cpu_codename) + self.enable_gpio_device(platform, cpu_manufacturer, touchpad_communication) + self.enable_nvram_support(motherboard_chipset) + self.fake_embedded_controller(platform) + self.fix_hp_005_post_error(motherboard_name) + self.fix_irq_conflicts(platform, cpu_codename) + self.fix_system_clock_awac(motherboard_chipset) + self.fix_system_clock_hedt(motherboard_chipset, macos_version) + self.fix_uncore_bridge(motherboard_chipset, macos_version) + self.instant_wake_fix() + self.operating_system_patch(platform) + self.surface_laptop_special_patch(motherboard_name, platform) + + self.result["Add"] = sorted(self.result["Add"], key=lambda x: x["Path"]) + self.apply_acpi_patches() + return self.result diff --git a/Scripts/aida64.py b/Scripts/aida64.py new file mode 100755 index 0000000..69fc2ee --- /dev/null +++ b/Scripts/aida64.py @@ -0,0 +1,606 @@ +from Scripts.datasets import pci_data +from Scripts import utils +from bs4 import BeautifulSoup + +class AIDA64: + def __init__(self): + self.aida64_download_url = "https://www.aida64.com/downloads" + self.headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"} + self.encodings = ['utf-8', 'latin-1', 'ISO-8859-1'] + self.utils = utils.Utils() + + def try_open(self, file_path): + for encoding in self.encodings: + try: + with open(file_path, 'r', encoding=encoding) as file: + return file.read() + except UnicodeDecodeError: + continue + raise UnicodeDecodeError(f"Unable to decode file {file_path} with given encodings") + + def hardware_id(self, hardware_id): + if "VEN" in hardware_id: + return { + "Bus Type": hardware_id.split("\\")[0], + "Device ID": "{}-{}".format(hardware_id.split("VEN_")[-1].split("&")[0], hardware_id.split("DEV_")[-1].split("&")[0]) + } + + if "VID" in hardware_id: + return { + "Bus Type": hardware_id.split("\\")[0], + "Device ID": "{}-{}".format(hardware_id.split("VID_")[-1].split("&")[0], hardware_id.split("PID_")[-1].split("&")[0]), + "Revision": hardware_id.split("REV_")[-1].split("&")[0] + } + + return { + "Bus Type": hardware_id.split("\\")[0], + "Device": hardware_id.split("\\")[-1] + } + + def motherboard(self, motherboard_props, dmi): + motherboard_info = {} + + # Extract motherboard name and chipset from provided properties + motherboard_info["Motherboard Name"] = motherboard_props.get("Motherboard Name", "Unknown").split("(")[0].strip() + motherboard_info["Motherboard Chipset"] = motherboard_props.get("Motherboard Chipset", "Unknown").split(", ")[0] + + # If motherboard name is still unknown, attempt to derive it from DMI information + if "Unknown" in motherboard_info.get("Motherboard Name"): + motherboard_info["Motherboard Name"] = "Unknown" + merged_report = dmi.get("System", {}).copy() + merged_report.update(dmi.get("Motherboard", {})) + for device_key, device_value in merged_report.items(): + motherboard_name = "{} {}".format(device_value.get("Manufacturer", "O.E.M."), device_value.get("Product", "O.E.M.")) + if "O.E.M." not in motherboard_name and "System Product Name" not in motherboard_name and len(motherboard_name) > len(motherboard_info.get("Motherboard Name")): + motherboard_info["Motherboard Name"] = motherboard_name + + # Extract platform type from chassis information + motherboard_info["Platform"] = dmi.get("Chassis", {}).get("Chassis Properties", {}).get("Chassis Type", "Unknown") + if any(word in motherboard_info["Platform"].lower() for word in ["convertible", "notebook", "laptop", "docking station"]): + motherboard_info["Platform"] = "Laptop" + elif any(word in motherboard_info["Platform"].lower() for word in ["desktop", "mini pc"]): + motherboard_info["Platform"] = "Desktop" + elif "NUC" in motherboard_info["Motherboard Name"]: + motherboard_info["Platform"] = "NUC" + + # Count and format CPU configuration + motherboard_info["CPU Configuration"] = str(len(dmi.get("Processors", {}))).zfill(2) + + return motherboard_info + + def cpu(self, cpu_table): + cpu_info = {} + + # Extract CPU Manufacturer + cpu_info["CPU Manufacturer"] = cpu_table.get("CPU Manufacturer", {}).get("Company Name", "Unknown") + + # Extract Processor Name + cpu_props = cpu_table.get("CPU Properties", {}) + cpu_info["Processor Name"] = cpu_props.get("CPU Type", "Unknown").split(",")[0] + + # Determine CPU Manufacturer if still unknown + if "Intel" in cpu_info["CPU Manufacturer"]: + cpu_info["CPU Manufacturer"] = "Intel" + elif "Advanced Micro Devices" in cpu_info["CPU Manufacturer"]: + cpu_info["CPU Manufacturer"] = "AMD" + elif cpu_info["CPU Manufacturer"] == "Unknown": + processor_name = cpu_table.get("Multi CPU", {}).get("CPU #1", "Unknown").split("with")[0].split(",")[0] + if "Intel" in processor_name: + cpu_info["CPU Manufacturer"] = "Intel" + elif "AMD" in processor_name: + cpu_info["CPU Manufacturer"] = "AMD" + cpu_info["Processor Name"] += cpu_info["CPU Manufacturer"] + processor_name.split(cpu_info["CPU Manufacturer"])[-1] + + # Extract CPU Codename + cpu_info["CPU Codename"] = cpu_props.get("CPU Alias", "Unknown") + + # Extract CPU Cores count + core_indices = [] + for key in list(cpu_table.get("CPU Utilization", {}).keys()): + core_index = key.split("#")[2].split(" ")[0] + if "CPU #1" in key and core_index not in core_indices: + core_indices.append(core_index) + cpu_info["CPU Cores"] = str(len(core_indices)).zfill(2) + + # Extract Instruction Set + cpu_info["Instruction Set"] = cpu_props.get("Instruction Set", "Unknown") + + return cpu_info + + def memory(self, memory_arrays, memory_devices): + return { + "Memory Arrays": [ + memory_array.get("Memory Array Properties", {}) + for function, memory_array in memory_arrays.items() + ], + "Memory Devices": [ + memory_device.get("Memory Device Properties", {}) + for device_locator, memory_device in memory_devices.items() + ] + } + + def storage(self, ata_controllers, storage_controllers, ata_devices): + storage_info = { + "Storage Controllers": {}, + "Disk Drives": {} + } + + storage_controllers.update(ata_controllers) + for controller_name, controller_props in storage_controllers.items(): + bus_type = controller_props.get("Bus Type", "Unknown") + if "PCI" in bus_type or "VID" in bus_type: + pci_device = controller_props.get("PCI Device") + if " SD " in pci_device or "MMC" in pci_device: + continue + + storage_info["Storage Controllers"][controller_name] = { + "Bus Type": controller_props.get("Bus Type", "Unknown"), + "Device ID": controller_props.get("Device ID", "Unknown"), + "Device Description": controller_props.get("PCI Device", "Unknown") + } + + device_categories = ["NVMe Device Properties", "SSD Physical Info", "ATA Device Properties", "Disk Device Physical Info", "Device Properties"] + + for device_name, device_props in ata_devices.items(): + disk_props = {} + relevant_categories = [key for key in list(device_props.keys()) if key in device_categories] + for category in relevant_categories: + category_props = device_props[category] + + disk_props["Controller"] = category_props.get("Controller Type", "Unknown") + disk_props["Interface"] = category_props.get("Interface", "Unknown") + if category_props.get("Device Type", None): + disk_props["Interface"] = category_props.get("Device Type") + + storage_info["Disk Drives"][device_name] = disk_props + + return storage_info + + def monitor(self, monitor): + return { + monitor_data["Monitor Properties"].get("Monitor Name", monitor_name): { + "Monitor Type": monitor_data["Monitor Properties"].get("Monitor Type", "Unknown"), + "Maximum Resolution": monitor_data["Monitor Properties"].get("Maximum Resolution", list(monitor_data.get("Supported Video Modes", {}).keys())[-1].split("_")[0] if "Supported Video Modes" in monitor_data else "Unknown") + } + for monitor_name, monitor_data in monitor.items() + if "Monitor Properties" in monitor_data + } + + def acpi(self, acpi_tables): + return [ + { + "ACPI Signature": acpi_table["ACPI Table Properties"].get("ACPI Signature", "Unknown"), + "Table Description": acpi_table["ACPI Table Properties"].get("Table Description", "Unknown"), + "Table Length": acpi_table["ACPI Table Properties"].get("Table Length", "Unknown"), + "OEM Table ID": acpi_table["ACPI Table Properties"].get("OEM Table ID", "Unknown") + } + for table_key, acpi_table in acpi_tables.items() + if "ACPI Table Properties" in acpi_table + ] + + def audio(self, windows_devices): + audio_devices_info = {} + audio_device_ids = [] + + for device_name, device_props in windows_devices.get("Audio inputs and outputs", {}).items(): + driver_description = device_props.get("Driver Description", "Unknown") + + if " (" not in driver_description: + continue + + audio_endpoint = driver_description.split(" (")[0] + audio_controller_name = driver_description.split(" (")[-1].strip(" )").split("- ")[-1] + + audio_controller_props = self.utils.search_dict_iter(windows_devices, audio_controller_name) + bus_type = audio_controller_props.get("Bus Type", "") + + if audio_controller_name not in audio_devices_info and (bus_type.endswith("AUDIO") or bus_type.endswith("USB") or bus_type.endswith("ACP")): + audio_devices_info[audio_controller_name] = { + "Bus Type": bus_type, + "{} ID".format("USB" if bus_type.endswith("USB") else "Codec"): audio_controller_props.get("Device ID", "Unknown"), + "Audio Endpoints": [audio_endpoint] + } + audio_device_ids.append(audio_controller_props.get("Device ID", "Unknown")) + elif audio_controller_name in audio_devices_info: + audio_devices_info[audio_controller_name]["Audio Endpoints"].append(audio_endpoint) + + detected_audio_devices = self.utils.search_dict_iter(windows_devices, "AUDIO", equal=False) + windows_audio_devices = self.utils.search_dict_iter(windows_devices, detected_audio_devices) + + for device_name, device_props in windows_audio_devices.items(): + bus_type = device_props.get("Bus Type", "") + if bus_type.endswith("AUDIO") or bus_type.endswith("USB"): + if device_props.get("Device ID", "Unknown") not in audio_device_ids: + occurrences = self.count_keys(audio_devices_info, device_name) + unique_device_name = f"{device_name}_#{occurrences}" if occurrences > 0 else device_name + audio_devices_info[unique_device_name] = { + "Bus Type": bus_type, + "{} ID".format("USB" if bus_type.endswith("USB") else "Codec"): device_props.get("Device ID", "Unknown") + } + + return audio_devices_info + + def gpu(self, gpu_data, vulkan_data, windows_devices): + gpu_info_dict = {} + + for adapter_name, adapter_props in windows_devices.get("Display adapters", windows_devices.get("Display adaptors", {})).items(): + device_id = adapter_props.get("Device ID") + if not device_id: + continue + manufacturer = "Intel" if device_id.startswith("8086") else "AMD" if device_id.startswith("1002") else "NVIDIA" if device_id.startswith("10DE") else "Unknown" + props_in_vulkan = self.utils.search_dict_iter(vulkan_data, device_id, equal=False) + gpu_props = self.utils.search_dict_iter(gpu_data, device_id, equal=False) + bus_type = gpu_props.get("Bus Type", "Unknown") + device_type = props_in_vulkan.get("Device Type", "Discrete GPU" if "PCI Express" in bus_type else "Integrated GPU" if "Integrated" in bus_type else "Unknown") + gpu_codename = gpu_props.get("GPU Code Name", props_in_vulkan.get("Device Code Name", "Unknown")) + + gpu_info_dict[gpu_props.get("Video Adapter", adapter_name)] = { + "Manufacturer": manufacturer, + "GPU Codename": gpu_codename, + "Device ID": device_id, + "Device Type": device_type, + "Memory Size": gpu_props.get("Memory Size", "Unknown") + } + + if not gpu_info_dict: + if gpu_data: + for gpu_name, gpu_props in gpu_data.items(): + gpu_props = gpu_props.get("Graphics Processor Properties", {}) + device_id = gpu_props.get("PCI Device", "Unknown").split(" / ")[0] + manufacturer = "Intel" if device_id.startswith("8086") else "AMD" if device_id.startswith("1002") else "NVIDIA" if device_id.startswith("10DE") else "Unknown" + bus_type = gpu_props.get("Bus Type", "Unknown") + device_type = "Discrete GPU" if "PCI Express" in bus_type else "Integrated GPU" if "Integrated" in bus_type else "Unknown" + gpu_codename = gpu_props.get("GPU Code Name", "Unknown") + + gpu_info_dict[gpu_props.get("Video Adapter", gpu_name.split(": ")[-1])] = { + "Manufacturer": manufacturer, + "GPU Codename": gpu_codename, + "Device ID": device_id, + "Device Type": device_type, + "Memory Size": gpu_props.get("Memory Size", "Unknown") + } + + return self.utils.sort_dict_by_key(gpu_info_dict, "Device Type") + + def input(self, human_interface_devices, keyboards, pointing_devices, usb_devices): + input_devices_info = {} + + combined_devices = human_interface_devices.copy() + combined_devices.update(keyboards) + combined_devices.update(pointing_devices) + + for device_name, device_props in combined_devices.items(): + bus_type = device_props.get("Bus Type", "Unknown") + device_id = device_props.get("Device ID", "Unknown") + + if "ACPI" in bus_type or "ROOT" in bus_type or "USB" in bus_type: + if "USB" in bus_type: + device_name = self.utils.search_dict_iter(usb_devices, device_props["Device ID"]).get("Device Description", device_name) + + input_devices_info[device_name] = { + "Bus Type": bus_type, + "Device ID": device_id + } + + return input_devices_info + + def usb(self, usb_controllers, usb_devices, windows_devices): + usb_info = { + "USB Controllers": { + controller_name: { + "Bus Type": controller_props.get("Bus Type", "Unknown"), + "Device ID": controller_props.get("Device ID", "Unknown") + } + for controller_name, controller_props in usb_controllers.items() + if controller_props.get("Bus Type", "Unknown").startswith("PCI") + }, + "USB Devices": {} + } + + for device_name, device_data in usb_devices.items(): + device_props = device_data.get("Device Properties", {}) + manufacturer = device_props.get("Manufacturer", None) + product = device_props.get("Product", None) + device_description = f"{manufacturer} {product}" if manufacturer and product else product if product else None + + if not device_description: + device_id = device_props.get("Device ID", None) + revision = device_props.get("Revision", None)[:-1] if device_props.get("Revision") else None + hardware_id = f'USB\\VID_{device_id[:4]}&PID_{device_id[5:]}&REV_{revision}' if device_id and revision else None + + if hardware_id: + device_description = self.utils.search_dict_iter(windows_devices, hardware_id + "&MI_00").get("Driver Description", None) + if not device_description: + device_description = self.utils.search_dict_iter(windows_devices, hardware_id).get("Driver Description", device_name) + + occurrences = self.count_keys(usb_info["USB Devices"], device_description) + device_description = f"{device_description}_#{occurrences}" if occurrences > 0 else device_description + + if "Hub" not in device_description and "Billboard" not in device_description and not "0000-0000" in device_props.get("Device ID"): + usb_info["USB Devices"][device_description] = { + "Device Description": device_description.split("_#")[0], + "Device Class": device_props.get("Device Class"), + "Device ID": device_props.get("Device ID"), + "Revision": device_props.get("Revision") + } + + return usb_info + + def network(self, windows_devices, pci_devices): + network_info = {} + + for device_name, device_props in pci_devices.items(): + device_class = device_props.get("Device Properties", {}).get("Device Class", "Unknown")[6:-1] + + if self.utils.contains_any(["Network", "Ethernet", "WiFi", "Wi-Fi", "Wireless"], device_class + device_name): + device_id = device_props.get("Device Properties").get("Device ID") + + network_adapter = self.utils.search_dict_iter(windows_devices, device_id) + network_adapters = self.utils.search_dict_iter(windows_devices, network_adapter) + + for adapter_name, adapter_props in network_adapters.items(): + device_description = adapter_name + adapter_props.get("PCI Device", "Unknown") + connection_name = "WiFi" if "WiFi" in device_description or "Wi-Fi" in device_description or "Wireless" in device_description else \ + "Ethernet" if "Network" in device_description or "Ethernet" in device_description else None + bus_type = adapter_props.get("Bus Type", "Unknown") + if (bus_type.startswith("PCI") or bus_type.startswith("USB")) and connection_name: + device_key = adapter_props.get("PCI Device") if not " - " in adapter_props.get("PCI Device", " - ") else adapter_name + network_info[device_key.split(" [")[0]] = { + "Connection Name": connection_name, + "Bus Type": bus_type, + "Device ID": adapter_props.get("Device ID", "Unknown") + } + + return self.utils.sort_dict_by_key(network_info, "Connection Name") + + def sd_controller(self, pci_devices, usb_devices, hardware): + combined_devices = pci_devices.copy() + combined_devices.update(usb_devices) + + for device_name, device_data in combined_devices.items(): + device_props = device_data.get("Device Properties", device_data) + device_class = device_props.get("Device Class", "Unknown") + + if self.utils.contains_any(["SD Host Controller", "Card Reader", "SDHC", "SDXC", "SDUC", " SD ", "MMC"], f"{device_name} {device_class}"): + hardware["SD Controller"] = { + "Device Description": device_name, + "Bus Type": "PCI" if device_props.get("Bus Type", "Unknown").startswith("PCI") else "USB", + "Device ID": device_props.get("Device ID", "Unknown") + } + + return hardware + + def intel_mei(self, cpu_codename, pci_devices, hardware): + if "Sandy Bridge" in cpu_codename or "Ivy Bridge" in cpu_codename: + intel_mei_data = self.utils.search_dict_iter(pci_devices, "HECI", equal=False) + + if not intel_mei_data: + intel_mei_data = self.utils.search_dict_iter(pci_devices, "Management Engine Interface", equal=False) + + if intel_mei_data: + intel_mei_props = intel_mei_data.get("Device Properties", {}) + hardware["Intel MEI"] = { + "Bus Type": intel_mei_props.get("Bus Type", "Unknown"), + "Device ID": intel_mei_props.get("Device ID", "Unknown") + } + + return hardware + + def bluetooth(self, bluetooth, usb_devices, hardware): + bluetooth_info = {} + + for device_name, device_props in bluetooth.items(): + bus_type = device_props.get("Bus Type", "Unknown") + + if bus_type.startswith("USB"): + bluetooth_info[device_name] = { + "Device ID": device_props.get("Device ID"), + "Revision": device_props.get("Revision") + } + + if not bluetooth_info: + for usb_device_name, usb_device_props in usb_devices.items(): + device_class = usb_device_props.get("Device Class", {}) + device_id = usb_device_props.get("Device ID", {}) + + if "bluetooth" in (usb_device_name + device_class).lower() or device_id in pci_data.BluetoothIDs: + bluetooth_info[usb_device_name] = usb_device_props + + if bluetooth_info: + hardware["Bluetooth"] = bluetooth_info + + return hardware + + def biometric(self, biometric_devices, usb_devices, hardware): + biometric_info = { + device_name: { + "Bus Type": device_props.get("Bus Type", "Unknown"), + "Device ID": device_props.get("Device ID", "Unknown") + } + for device_name, device_props in biometric_devices.items() + } + + if not biometric_info: + for device_name, device_data in usb_devices.items(): + if "fingerprint" in device_name.lower(): + device_props = device_data.get("Device Properties", {}) + + biometric_info[device_name] = { + "Bus Type": device_props.get("Bus Type", "Unknown"), + "Device ID": device_props.get("Device ID", "Unknown") + } + + if biometric_info: + hardware["Biometric"] = biometric_info + + return hardware + + def parse_dmi(self, dmi_data): + parsed_dmi = {} + + for full_key, item_value in dmi_data.items(): + occurrence_suffix = '' + category_name = None + + if '_#' in full_key: + suffix_idx = full_key.index('_#') + occurrence_suffix = full_key[suffix_idx:] + full_key = full_key[:suffix_idx] + + if ' / ' in full_key: + category_idx = full_key.index(' / ') + category_name = full_key[:category_idx] + device_name = full_key[category_idx + 3:] + + if not category_name: + parsed_dmi[f"{full_key}{occurrence_suffix}"] = item_value + else: + if category_name not in parsed_dmi: + parsed_dmi[category_name] = {} + parsed_dmi[category_name][f"{device_name}{occurrence_suffix}"] = item_value + + return parsed_dmi + + def parse_windows_devices(self, windows_devices): + parsed_windows_devices = {} + + for full_key, item_value in windows_devices.items(): + device_props = item_value.get("Device Properties", {}) + + # Update device properties with hardware ID if available + if "Hardware ID" in device_props: + device_props.update(self.hardware_id(device_props.get("Hardware ID"))) + + # Extract category name from the full key + category_name = full_key.split(" / ")[0] + + # Initialize category dictionary if not already present + if category_name not in parsed_windows_devices: + parsed_windows_devices[category_name] = {} + + # Extract device name from device properties + device_name = device_props.get("Driver Description") + + # Count occurrences of device name within category + occurrences = self.count_keys(parsed_windows_devices[category_name], device_name) + device_name = f"{device_name}_#{occurrences}" if occurrences > 0 else device_name + + # Add device to category dictionary + parsed_windows_devices[category_name][device_name] = device_props + + return parsed_windows_devices + + def count_keys(self, dictionary, target_key): + return sum(1 for key in dictionary if target_key in key) + + def html_to_dict(self, html_content): + soup = BeautifulSoup(html_content, "html.parser") + tables = soup.find_all('table') + + if not tables: + return {} + + root = {} + table_names = [ + "Summary", + "DMI", + "CPU", + "GPU", + "Vulkan", + "ATA", + "Windows Devices", + "PCI Devices", + "USB Devices" + ] + table = None + + for table_content in tables: + # Find the table header to identify the table + pt_element = table_content.find("td", class_="pt") + if pt_element: + table = pt_element.text.strip() + elif table in table_names: + root[table] = {} + stack = [(root[table], -1)] # Stack holds (current_dict, current_level) + + lines = str(table_content).strip().splitlines() + + for line in lines: + if line.startswith(''): + # Remove tag + line = line.replace('', '') + + # Calculate the current level based on the number of tags + level = (len(line) - len(line.lstrip(''))) // 3 - 1 + if level < 1: + continue + + # Remove all tags from the left + while line.startswith(""): + line = line[line.find(">") + 1:] + + if not line.startswith('', line[:idx], '', line[idx:]) + else: + continue + + soup_line = BeautifulSoup(line, "html.parser") + td_elements = soup_line.find_all('td') + key = td_elements[0].text.strip() + value = None if len(td_elements) < 2 else td_elements[-1].text.strip() + + # Clean the key + key = key.rstrip(":").strip("[]").strip() + + # Pop from stack to find the correct parent dictionary + while stack and stack[-1][1] >= level: + stack.pop() + + # Add the new key-value pair + current_dict = stack[-1][0] + occurrences = self.count_keys(current_dict, key) + key = f"{key}_#{occurrences}" if occurrences > 0 else key + + if value is None: + new_dict = {} + current_dict[key] = new_dict + stack.append((new_dict, level)) + else: + if '' not in line: + current_dict[key] = value + else: + if not current_dict.items(): + current_dict[key] = [] + current_dict[value] = [] + else: + current_dict[list(current_dict.keys())[0]].append(key) + current_dict[list(current_dict.keys())[1]].append(value) + + if len(table_names) - len(root) > 1: + raise Exception("Your AIDA64 report is missing some information. Please revise it according to the provided guidelines") + return root + + def dump(self, report_path): + html_content = self.try_open(report_path) + report_dict = self.html_to_dict(html_content) + + dmi = self.parse_dmi(report_dict.get("DMI", {})) + windows_devices = self.parse_windows_devices(report_dict.get("Windows Devices", {})) + + hardware = {} + hardware["Motherboard"] = self.motherboard(report_dict.get("Summary", {}).get("Motherboard", {}), dmi) + hardware["CPU"] = self.cpu(report_dict.get("CPU", {})) + hardware["GPU"] = self.gpu(report_dict.get("GPU", {}), report_dict.get("Vulkan", {}), windows_devices) + hardware["Network"] = self.network(windows_devices, report_dict.get("PCI Devices", {})) + hardware["Storage"] = self.storage(windows_devices.get("IDE ATA/ATAPI controllers", {}), windows_devices.get("Storage controllers", {}), report_dict.get("ATA", {})) + hardware["Audio"] = self.audio(windows_devices) + hardware["USB"] = self.usb(windows_devices.get("Universal Serial Bus controllers", {}), report_dict.get("USB Devices", {}), windows_devices) + hardware["Input"] = self.input(windows_devices.get("Human Interface Devices", {}), windows_devices.get("Keyboards", {}), windows_devices.get("Mice and other pointing devices", {}), hardware["USB"].get("USB Devices", {})) + + hardware = self.biometric(windows_devices.get("Biometric devices", {}), hardware["USB"].get("USB Devices", {}), hardware) + hardware = self.bluetooth(windows_devices.get("Bluetooth", {}), hardware["USB"].get("USB Devices", {}), hardware) + hardware = self.sd_controller(report_dict.get("PCI Devices", {}), hardware["USB"].get("USB Devices", {}), hardware) + hardware = self.intel_mei(hardware["CPU"].get("CPU Codename"), report_dict.get("PCI Devices", {}), hardware) + + return hardware diff --git a/Scripts/codec_layouts.py b/Scripts/codec_layouts.py new file mode 100755 index 0000000..024f1c9 --- /dev/null +++ b/Scripts/codec_layouts.py @@ -0,0 +1,951 @@ +from Scripts import github +from Scripts import resource_fetcher +from Scripts import utils +import os + +class CodecLayouts: + def __init__(self): + self.github = github.Github() + self.fetcher = resource_fetcher.ResourceFetcher(self.github.headers) + self.utils = utils.Utils() + self.vendors = { + "11D4": ["AD", "AnalogDevices"], + "10EC": ["ALC", "Realtek"], + "1102": ["CA", "Creative"], + "1013": ["CS", "CirrusLogic"], + "14F1": ["CX", "Conexant"], + "111D": ["IDT"], + "8384": ["STAC", "SigmaTel"], + "1106": ["VT", "VIA"] + } + + def get_layout_ids_from_applealc_repo(self): + # Define the GitHub API URL for the AppleALC repository contents + url = "https://api.github.com/repos/acidanthera/AppleALC/contents/Resources" + + self.github.check_ratelimit() + + # Dictionary to store sound codec information + sound_codec_info = {} + + # Retrieve content information from the GitHub repository + content = self.fetcher.fetch_and_parse_content(url, "json") + + # Iterate through folders in the content + for folder in content: + codec_folder_name = folder["name"] + + if "." in codec_folder_name: + continue + + # Identify vendor based on the vendor information + vendor_id = next((id for id, vendor in self.vendors.items() if vendor[0] in codec_folder_name), None) + + if not vendor_id: + # Skip if vendor ID is not found + print(f"Unknown vendor for codec: {codec_folder_name}") + continue + + # Extract vendor name from vendor information + vendor_name = self.vendors[vendor_id][-1] + + # Build the raw URL for the Info.plist file + raw_url = f"https://raw.githubusercontent.com/acidanthera/AppleALC/master/Resources/{codec_folder_name}/Info.plist" + + # Retrieve content from the Info.plist file and parse as plist + info = self.fetcher.fetch_and_parse_content(raw_url, "json") + + # Extract relevant information from the Info.plist + codec_id_hex = self.utils.int_to_hex(info["CodecID"]).zfill(4) + formatted_codec_name = "{} {}".format(vendor_name, info["CodecName"]) + layout_ids = sorted([int(layouts["Id"]) for layouts in info["Files"]["Layouts"]]) + pci_id = f"{vendor_id}-{codec_id_hex}".upper() + + sound_codec_info[pci_id] = layout_ids + + # Sort sound codec information by name + sorted_sound_codec_info = dict(sorted(sound_codec_info.items(), key=lambda item: item[1]["Name"])) + + return sorted_sound_codec_info + + def get_layout_ids_from_applealc_kext(self, applealc_path): + if not os.path.exists(applealc_path): + return {} + + plist_path = os.path.join(applealc_path, "Contents", "Info.plist") + plist_data = self.utils.read_file(plist_path) + + if not plist_data: + return {} + + codec_layouts = {} + + hda_config_defaults = plist_data.get("IOKitPersonalities", {}).get("as.vit9696.AppleALC", {}).get("HDAConfigDefault", []) + for layout in hda_config_defaults: + codec_id_hex = self.utils.int_to_hex(layout.get("CodecID", 0)).zfill(8) + formatted_codec_id = f"{codec_id_hex[:4]}-{codec_id_hex[-4:]}" + layout_id = layout.get("LayoutID") + if layout_id is not None: + if formatted_codec_id not in codec_layouts: + codec_layouts[formatted_codec_id] = [] + codec_layouts[formatted_codec_id].append(layout_id) + + # Sort the layout IDs for each codec + for codec_id in codec_layouts: + codec_layouts[codec_id] = sorted(codec_layouts[codec_id]) + + return codec_layouts + +data = { + "10EC-0295": [ + 1, + 3, + 11, + 13, + 14, + 15, + 21, + 22, + 23, + 24, + 28, + 33, + 69, + 75, + 77 + ], + "10EC-0298": [ + 3, + 11, + 13, + 15, + 16, + 21, + 22, + 25, + 28, + 29, + 30, + 32, + 33, + 47, + 66, + 72, + 94, + 99 + ], + "10EC-1168": [ + 1, + 2, + 3, + 5, + 7, + 8, + 11, + 13, + 15, + 20, + 21, + 99 + ], + "10EC-0256": [ + 5, + 11, + 12, + 13, + 14, + 16, + 17, + 19, + 20, + 21, + 22, + 23, + 24, + 28, + 33, + 38, + 56, + 57, + 66, + 67, + 68, + 69, + 70, + 76, + 77, + 88, + 95, + 97, + 99 + ], + "10EC-0282": [ + 3, + 4, + 13, + 21, + 22, + 27, + 28, + 29, + 30, + 41, + 43, + 51, + 69, + 76, + 86, + 127 + ], + "10EC-0269": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 44, + 45, + 47, + 55, + 58, + 66, + 69, + 76, + 77, + 88, + 91, + 93, + 99, + 100, + 111, + 127, + 128, + 138, + 188 + ], + "111D-7695": [ + 11, + 12, + 14 + ], + "14F1-5098": [ + 20, + 21, + 23, + 28 + ], + "1102-0011": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 9, + 10, + 11, + 12, + 99 + ], + "1013-4210": [ + 13 + ], + "1013-4213": [ + 28 + ], + "11D4-1884": [ + 11 + ], + "11D4-1984": [ + 11 + ], + "11D4-194A": [ + 11, + 13, + 44 + ], + "11D4-1988": [ + 12 + ], + "11D4-198B": [ + 5, + 7, + 12 + ], + "11D4-989B": [ + 5, + 7 + ], + "10EC-0215": [ + 18 + ], + "10EC-0221": [ + 11, + 15, + 88 + ], + "10EC-0222": [ + 11, + 12 + ], + "10EC-0225": [ + 28, + 30, + 33, + 90 + ], + "10EC-0230": [ + 13, + 20 + ], + "10EC-0233": [ + 3, + 4, + 5, + 11, + 13, + 21, + 27, + 28, + 29, + 32, + 33 + ], + "10EC-0236": [ + 3, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 23, + 36, + 54, + 55, + 68, + 69, + 99 + ], + "10EC-0235": [ + 3, + 8, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 21, + 22, + 24, + 28, + 29, + 33, + 35, + 36, + 37, + 72, + 88, + 99 + ], + "10EC-0245": [ + 11, + 12, + 13 + ], + "10EC-0255": [ + 3, + 11, + 12, + 13, + 15, + 17, + 18, + 20, + 21, + 22, + 23, + 27, + 28, + 29, + 30, + 31, + 37, + 66, + 69, + 71, + 80, + 82, + 86, + 96, + 99, + 100, + 255 + ], + "10EC-0257": [ + 11, + 18, + 86, + 96, + 97, + 99, + 100, + 101 + ], + "10EC-0260": [ + 11, + 12 + ], + "10EC-0262": [ + 7, + 11, + 12, + 13, + 14, + 28, + 66 + ], + "10EC-0268": [ + 3, + 11 + ], + "10EC-0270": [ + 3, + 4, + 21, + 27, + 28 + ], + "10EC-0272": [ + 3, + 11, + 12, + 18, + 21 + ], + "10EC-0274": [ + 21, + 28, + 35, + 39 + ], + "10EC-0275": [ + 3, + 13, + 15, + 28 + ], + "10EC-0280": [ + 3, + 4, + 11, + 13, + 15, + 16, + 17, + 18, + 21 + ], + "10EC-0283": [ + 1, + 3, + 11, + 12, + 13, + 15, + 44, + 45, + 66, + 73, + 88 + ], + "10EC-0284": [ + 3 + ], + "10EC-0285": [ + 11, + 21, + 31, + 52, + 61, + 66, + 71, + 88 + ], + "10EC-0286": [ + 3, + 11, + 69 + ], + "10EC-0287": [ + 11, + 13, + 21 + ], + "10EC-0288": [ + 3, + 13, + 23 + ], + "10EC-0289": [ + 11, + 12, + 13, + 15, + 23, + 33, + 68, + 69, + 87, + 93, + 99 + ], + "10EC-0290": [ + 3, + 4, + 10, + 15, + 28 + ], + "10EC-0292": [ + 12, + 15, + 18, + 28, + 32, + 55, + 59 + ], + "10EC-0293": [ + 11, + 28, + 29, + 30, + 31 + ], + "10EC-0294": [ + 11, + 12, + 13, + 15, + 21, + 22, + 28, + 44, + 66, + 99 + ], + "10EC-0299": [ + 21, + 22 + ], + "10EC-0623": [ + 13, + 21 + ], + "10EC-0662": [ + 5, + 7, + 11, + 12, + 13, + 15, + 16, + 17, + 18, + 19, + 66 + ], + "10EC-0663": [ + 3, + 4, + 15, + 28, + 99 + ], + "10EC-0665": [ + 12, + 13 + ], + "10EC-0668": [ + 3, + 20, + 27, + 28, + 29 + ], + "10EC-0670": [ + 12 + ], + "10EC-0671": [ + 12, + 15, + 16, + 88 + ], + "10EC-0700": [ + 11, + 22 + ], + "10EC-0882": [ + 5, + 7 + ], + "10EC-0883": [ + 7, + 20 + ], + "10EC-0885": [ + 1, + 12, + 15 + ], + "10EC-0887": [ + 1, + 2, + 3, + 5, + 7, + 11, + 12, + 13, + 17, + 18, + 20, + 33, + 40, + 50, + 52, + 53, + 87, + 99 + ], + "10EC-0888": [ + 1, + 2, + 3, + 4, + 5, + 7, + 11, + 27, + 28, + 29 + ], + "10EC-0889": [ + 1, + 2, + 3, + 11, + 12 + ], + "10EC-0867": [ + 11, + 13 + ], + "10EC-0892": [ + 1, + 2, + 3, + 4, + 5, + 7, + 11, + 12, + 15, + 16, + 17, + 18, + 20, + 21, + 22, + 23, + 28, + 31, + 32, + 90, + 92, + 97, + 98, + 99, + 100 + ], + "10EC-0897": [ + 11, + 12, + 13, + 21, + 22, + 23, + 66, + 69, + 77, + 98, + 99 + ], + "10EC-0899": [ + 1, + 2, + 3, + 5, + 7, + 11, + 13, + 28, + 65, + 66, + 98, + 99, + 101 + ], + "10EC-0900": [ + 1, + 2, + 3, + 5, + 7, + 11, + 99 + ], + "10EC-1220": [ + 1, + 2, + 3, + 5, + 7, + 11, + 13, + 15, + 16, + 17, + 18, + 20, + 21, + 25, + 27, + 28, + 29, + 30, + 34, + 35, + 69, + 98, + 99, + 100 + ], + "10EC-0B00": [ + 1, + 2, + 3, + 7, + 11, + 49, + 50, + 51, + 52, + 69 + ], + "14F1-1F72": [ + 3, + 13 + ], + "14F1-1F86": [ + 15, + 21 + ], + "14F1-1FD6": [ + 21, + 22 + ], + "14F1-2008": [ + 3, + 15, + 21, + 23, + 80 + ], + "14F1-20D0": [ + 12, + 13 + ], + "14F1-5051": [ + 11 + ], + "14F1-5067": [ + 3 + ], + "14F1-5069": [ + 3, + 13 + ], + "14F1-506C": [ + 3 + ], + "14F1-506E": [ + 3, + 12, + 13, + 14, + 28 + ], + "14F1-50A1": [ + 11, + 13 + ], + "14F1-50A2": [ + 11, + 13 + ], + "14F1-50F2": [ + 3 + ], + "14F1-50F4": [ + 3, + 13 + ], + "14F1-510F": [ + 3, + 21, + 28 + ], + "14F1-5111": [ + 3, + 14, + 15, + 21 + ], + "14F1-5113": [ + 3 + ], + "14F1-5114": [ + 3, + 13 + ], + "14F1-5115": [ + 3, + 28 + ], + "111D-76D1": [ + 12, + 13 + ], + "111D-76D9": [ + 13 + ], + "111D-76F3": [ + 3 + ], + "111D-76B2": [ + 3 + ], + "111D-7675": [ + 19, + 21 + ], + "111D-7676": [ + 15 + ], + "111D-76D5": [ + 3, + 11 + ], + "111D-7605": [ + 3, + 3, + 12, + 20, + 21, + 28, + 76 + ], + "111D-7608": [ + 3 + ], + "111D-7603": [ + 3, + 11 + ], + "111D-76E7": [ + 3, + 12 + ], + "111D-76E0": [ + 3, + 12, + 13, + 33, + 84 + ], + "111D-76DF": [ + 12 + ], + "111D-76E5": [ + 3 + ], + "8384-7690": [ + 11 + ], + "8384-76A0": [ + 11 + ], + "8384-7662": [ + 12 + ], + "1106-4760": [ + 21 + ], + "1106-8446": [ + 3, + 33, + 65 + ], + "1106-0441": [ + 5, + 7, + 9, + 13 + ] +} \ No newline at end of file diff --git a/Scripts/compatibility_checker.py b/Scripts/compatibility_checker.py new file mode 100755 index 0000000..a607c62 --- /dev/null +++ b/Scripts/compatibility_checker.py @@ -0,0 +1,212 @@ +from Scripts.datasets import chipset_data +from Scripts.datasets import cpu_data +from Scripts.datasets import pci_data +from Scripts import utils + +class CompatibilityChecker: + def __init__(self): + self.utils = utils.Utils() + self.latest_macos_version = 24 + + def is_low_end_intel_cpu(self, processor_name): + return any(brand in processor_name for brand in ["Celeron", "Pentium"]) + + def check_cpu_compatibility(self, processor_name, instruction_set): + if "x86-64" not in instruction_set or "SSE4" not in instruction_set: + self.max_supported_macos_version = self.min_supported_macos_version = -1 + self.unsupported_devices.append(f"CPU: {processor_name}") + return + + if "SSE4.2" not in instruction_set: + self.min_supported_macos_version = 18 + if "SSE4.1" in instruction_set: + self.max_supported_macos_version = 21 + + def check_gpu_compatibility(self, motherboard_chipset, processor_name, instruction_set, gpu_info): + supported_gpus = {} + is_supported_discrete_gpu = False + + for gpu_name, gpu_props in gpu_info.items(): + gpu_manufacturer = gpu_props.get("Manufacturer") + gpu_codename = gpu_props.get("GPU Codename") + device_type = gpu_props.get("Device Type") + is_supported_gpu = True + + if "Integrated GPU" in device_type: + if "Intel" in gpu_manufacturer: + if self.utils.contains_any(cpu_data.IntelCPUGenerations, gpu_codename, end=12) and \ + not self.is_low_end_intel_cpu(processor_name) and \ + not "2000" in gpu_name and not "2500" in gpu_name: + self.min_supported_macos_version = max(17, self.min_supported_macos_version) + if "Sandy Bridge" in gpu_codename: + self.max_supported_macos_version = max(17, self.max_supported_macos_version if is_supported_discrete_gpu else -1) + elif "Ivy Bridge" in gpu_codename: + self.max_supported_macos_version = max(20, self.max_supported_macos_version if is_supported_discrete_gpu else -1) + elif "Haswell" in gpu_codename or "Broadwell" in gpu_codename: + self.max_supported_macos_version = max(21, self.max_supported_macos_version if is_supported_discrete_gpu else -1) + elif "Skylake" in gpu_codename or "Kaby Lake" in gpu_codename and not "-r" in gpu_codename.lower(): + self.max_supported_macos_version = max(22, self.max_supported_macos_version if is_supported_discrete_gpu else -1) + elif "Amber Lake" in gpu_codename or "Whiskey Lake" in gpu_codename: + self.min_supported_macos_version = max(17, self.min_supported_macos_version if is_supported_discrete_gpu else -1) + self.max_supported_macos_version = self.latest_macos_version + elif not is_supported_discrete_gpu and "Comet Lake" in gpu_codename and self.utils.contains_any(chipset_data.IntelChipsets, motherboard_chipset, start=110, end=122): + self.max_supported_macos_version = self.min_supported_macos_version = -1 + elif "Ice Lake" in gpu_codename: + self.min_supported_macos_version = max(19, self.min_supported_macos_version) + self.max_supported_macos_version = self.latest_macos_version + else: + self.max_supported_macos_version = self.latest_macos_version + else: + is_supported_gpu = False + if not is_supported_discrete_gpu: + self.max_supported_macos_version = self.min_supported_macos_version = -1 + elif "AMD" in gpu_manufacturer: + is_supported_gpu = gpu_props.get("Device ID") in pci_data.AMDGPUIDs + if is_supported_gpu: + self.max_supported_macos_version = self.latest_macos_version + self.min_supported_macos_version = max(19, self.min_supported_macos_version) + elif "Discrete GPU" in device_type: + if "AMD" in gpu_manufacturer: + is_supported_discrete_gpu = True + + if "Navi 2" in gpu_codename: + if not "AVX2" in instruction_set: + self.max_supported_macos_version = min(21, self.max_supported_macos_version) + else: + if "Navi 23" in gpu_codename or "Navi 22" in gpu_codename: + self.min_supported_macos_version = max(21, self.min_supported_macos_version) + elif "Navi 21" in gpu_codename: + self.min_supported_macos_version = max(20, self.min_supported_macos_version) + else: + self.max_supported_macos_version = self.min_supported_macos_version = -1 + is_supported_discrete_gpu = is_supported_gpu = False + elif "Navi 10" in gpu_codename: + self.min_supported_macos_version = max(19, self.min_supported_macos_version) + elif "Vega 20" in gpu_codename: + self.min_supported_macos_version = max(17, self.min_supported_macos_version) + elif "Vega 10" in gpu_codename or "Polaris" in gpu_codename or "550" in gpu_name: + self.min_supported_macos_version = max(17, self.min_supported_macos_version) + else: + self.max_supported_macos_version = self.min_supported_macos_version = -1 + is_supported_discrete_gpu = is_supported_gpu = False + elif "NVIDIA" in gpu_manufacturer: + is_supported_discrete_gpu = True + + if "GK" in gpu_codename: + self.max_supported_macos_version = 20 + elif "GP" in gpu_codename or "GM" in gpu_codename or "GF" in gpu_codename or "GT" in gpu_codename or gpu_codename.startswith("C"): + self.max_supported_macos_version = self.min_supported_macos_version = 17 + else: + self.max_supported_macos_version = self.min_supported_macos_version = -1 + is_supported_discrete_gpu = is_supported_gpu = False + + if not is_supported_gpu: + self.unsupported_devices.append(f"{device_type}: {gpu_name}") + else: + supported_gpus[gpu_name] = gpu_props + + return supported_gpus + + def check_audio_compatibility(self, audio_info): + supported_audio = {} + audio_endpoint = None + + for audio_device, audio_props in audio_info.items(): + codec_id = audio_props.get("Codec ID") + if "USB" in audio_props.get("Bus Type") or \ + codec_id.startswith("8086") or \ + codec_id.startswith("1002") or \ + codec_id in pci_data.CodecIDs: + if codec_id in pci_data.CodecIDs: + supported_audio = {**{audio_device: audio_props}, **supported_audio} + else: + supported_audio[audio_device] = audio_props + else: + if "Audio Endpoints" in audio_props: + audio_endpoint = ",".join(audio_props.get("Audio Endpoints")) + self.unsupported_devices.append("Audio: {}{}".format(audio_device, "" if not audio_endpoint else f" ({audio_endpoint})")) + + return supported_audio + + def check_biometric_compatibility(self, hardware): + biometric = hardware.get("Biometric", {}) + if biometric: + for biometric_device, biometric_props in biometric.items(): + self.unsupported_devices.append(f"Biometric: {biometric_device}") + + del hardware["Biometric"] + + def check_network_compatibility(self, network_info): + supported_network = {} + + for device_name, device_props in network_info.items(): + connection_name = device_props.get("Connection Name") + bus_type = device_props.get("Bus Type") + device_id = device_props.get("Device ID") + is_device_supported = device_id in pci_data.NetworkIDs + + if bus_type.startswith("PCI"): + if device_id in ["8086-125B", "8086-125C", "8086-125D", "8086-3102"]: + self.min_supported_macos_version = 19 + + if not is_device_supported: + self.unsupported_devices.append(f"{connection_name}: {device_name}") + else: + supported_network[device_name] = device_props + + return supported_network + + def check_storage_compatibility(self, storage_controller_info): + supported_storage = {} + + for controller_name, controller_props in storage_controller_info.items(): + if "PCI" in controller_props.get("Bus Type"): + device_id = controller_props.get("Device ID") + if device_id in pci_data.IntelVMDIDs or device_id in pci_data.UnsupportedNVMeSSDIDs: + self.unsupported_devices.append("Storage: {}".format(pci_data.UnsupportedNVMeSSDIDs[device_id])) + else: + supported_storage[controller_name] = controller_props + + return supported_storage + + def check_sd_controller_compatibility(self, hardware): + sd_controller_props = hardware.get("SD Controller", {}) + + if sd_controller_props: + if sd_controller_props.get("Device ID") not in pci_data.RealtekCardReaderIDs: + self.unsupported_devices.append("SD Controller: {}".format(sd_controller_props.get("Device Description"))) + hardware["SD Controller"] = {} + + def check_compatibility(self, hardware): + self.max_supported_macos_version = self.latest_macos_version + self.min_supported_macos_version = 17 + self.unsupported_devices = [] + + self.check_cpu_compatibility( + hardware.get("CPU").get("Processor Name"), + hardware.get("CPU").get("Instruction Set") + ) + + if self.max_supported_macos_version != -1: + hardware["GPU"] = self.check_gpu_compatibility( + hardware.get("Motherboard").get("Motherboard Chipset"), + hardware.get("CPU").get("Processor Name"), + hardware.get("CPU").get("Instruction Set"), + hardware.get("GPU") + ) + if hardware.get("GPU"): + hardware["Audio"] = self.check_audio_compatibility(hardware.get("Audio")) + self.check_biometric_compatibility(hardware) + hardware["Network"] = self.check_network_compatibility(hardware.get("Network")) + hardware["Storage"]["Storage Controllers"] = self.check_storage_compatibility(hardware.get("Storage").get("Storage Controllers")) + self.check_sd_controller_compatibility(hardware) + + hardware["Compatibility"] = { + "macOS Version": { + "Max Version": self.max_supported_macos_version, + "Min Version": self.min_supported_macos_version + }, + "Unsupported Devices": self.unsupported_devices + } + + return hardware diff --git a/Scripts/config_prodigy.py b/Scripts/config_prodigy.py new file mode 100755 index 0000000..798eac7 --- /dev/null +++ b/Scripts/config_prodigy.py @@ -0,0 +1,364 @@ +from Scripts.datasets import chipset_data +from Scripts.datasets import cpu_data +from Scripts import codec_layouts +from Scripts import gathering_files +from Scripts import smbios +from Scripts import utils +import random + +class ConfigProdigy: + def __init__(self): + self.g = gathering_files.gatheringFiles() + self.smbios = smbios.SMBIOS() + self.utils = utils.Utils() + self.latest_macos_version = "24.99.99" + self.kernel_patches = { + "Force enable Hyper Threading": [ + { + "Arch": "Any", + "Base": "_cpu_thread_alloc", + "Comment": "Force enable Hyper Threading for macOS Mojave or later", + "Count": 1, + "Enabled": True, + "Find": self.utils.hex_to_bytes("8B8894010000"), + "Identifier": "kernel", + "Limit": 0, + "Mask": self.utils.hex_to_bytes(""), + "MaxKernel": "", + "MinKernel": "18.0.0", + "Replace": self.utils.hex_to_bytes("B9FF00000090"), + "ReplaceMask": self.utils.hex_to_bytes(""), + "Skip": 0 + } + ], + "AMD Vanilla Patches": self.g.get_amd_kernel_patches() + } + self.cpuids = { + "Ivy Bridge": "A9060300", + "Haswell": "C3060300", + "Broadwell": "D4060300", + "Coffee Lake": "EB060800", + "Comet Lake": "55060A00" + } + + def mmio_whitelist(self, cpu_codename): + booter_mmiowhitelist = [] + + if "Ice Lake" in cpu_codename: + booter_mmiowhitelist.append({ + "Address": 4284481536, + "Comment": "MMIO 0xFF600000 Ice Lake", + "Enable": True + }) + + return booter_mmiowhitelist + + def check_mats_support(self, cpu_manufacturer, motherboard_chipset, cpu_codename): + return "AMD" in cpu_manufacturer or \ + (self.utils.contains_any(cpu_data.IntelCPUGenerations, cpu_codename, start=7, end=9) is None and not self.utils.contains_any(chipset_data.IntelChipsets, motherboard_chipset, start=85) is None) or \ + not self.utils.contains_any(chipset_data.IntelChipsets, motherboard_chipset, start=49, end=60) is None + + def check_resizable_bar_support(self, motherboard_chipset, platform, cpu_codename, discrete_gpu): + return "Desktop" in platform and discrete_gpu and not (self.utils.contains_any(chipset_data.AMDChipsets, motherboard_chipset) is None or \ + self.utils.contains_any(cpu_data.IntelCPUGenerations, cpu_codename, start=10) is None) + + def is_low_end_intel_cpu(self, processor_name): + return any(brand in processor_name for brand in ["Celeron", "Pentium"]) + + def deviceproperties(self, cpu_codename, intel_mei, igpu_properties): + deviceproperties_add = {} + + if igpu_properties: + deviceproperties_add["PciRoot(0x0)/Pci(0x2,0x0)"] = igpu_properties + if intel_mei: + if "Sandy Bridge" in cpu_codename and intel_mei.get("Device ID") in "8086-1E3A": + deviceproperties_add["PciRoot(0x0)/Pci(0x16,0x0)"] = { + "device-id": "3A1C0000" + } + elif "Ivy Bridge" in cpu_codename and intel_mei.get("Device ID") in "8086-1C3A": + deviceproperties_add["PciRoot(0x0)/Pci(0x16,0x0)"] = { + "device-id": "3A1E0000" + } + + for key, value in deviceproperties_add.items(): + for key_child, value_child in value.items(): + if isinstance(value_child, str): + deviceproperties_add[key][key_child] = self.utils.hex_to_bytes(deviceproperties_add[key][key_child]) + + return deviceproperties_add + + def block_kext_bundle(self, wifi_pci, macos_version): + kernel_block = [] + + if wifi_pci and macos_version > 22 and wifi_pci in ["14E4-43A0", "14E4-43A3", "14E4-43BA"]: + kernel_block.append({ + "Arch": "x86_64", + "Comment": "Allow IOSkywalk Downgrade", + "Enable": True, + "Identifier": "com.apple.iokit.IOSkywalkFamily", + "MaxKernel": "", + "MinKernel": "", + "Strategy": "Exclude" + }) + + return kernel_block + + def is_low_end_haswell_plus(self, processor_name, cpu_codename): + return self.is_low_end_intel_cpu(processor_name) and not self.utils.contains_any(cpu_data.IntelCPUGenerations, cpu_codename, start=2) is None + + def is_intel_hedt_cpu(self, cpu_codename): + return "-E" in cpu_codename and not self.utils.contains_any(cpu_data.IntelCPUGenerations, cpu_codename, end=4) is None or \ + ("-X" in cpu_codename or "-W" in cpu_codename) and not self.utils.contains_any(cpu_data.IntelCPUGenerations, cpu_codename, start=4, end=6) is None + + def spoof_cpuid(self, processor_name, cpu_codename, macos_version): + if self.is_low_end_haswell_plus(processor_name, cpu_codename): + return self.cpuids.get("Ivy Bridge") + elif "Haswell" in cpu_codename and self.is_intel_hedt_cpu(cpu_codename): + return self.cpuids.get("Haswell") + elif "Broadwell" in cpu_codename and self.is_intel_hedt_cpu(cpu_codename): + return self.cpuids.get("Broadwell") + elif "Ice Lake" not in cpu_codename and not self.utils.contains_any(cpu_data.IntelCPUGenerations, cpu_codename, start=10) is None: + if not "Comet Lake" in cpu_codename: + return self.cpuids.get("Comet Lake") + if macos_version < 19: + return self.cpuids.get("Coffee Lake") + + return None + + def load_kernel_patch(self, motherboard_chipset, cpu_manufacturer, cpu_codename, cpu_cores, gpu_manufacturer, tsc_sync, macos_version): + kernel_patch = [] + patches_to_remove = [] + + if "AMD" in cpu_manufacturer: + kernel_patch.extend(self.kernel_patches["AMD Vanilla Patches"]) + elif tsc_sync: + kernel_patch.extend(self.kernel_patches["AMD Vanilla Patches"][-6:-4]) + + if not self.utils.contains_any(cpu_data.IntelCPUGenerations, cpu_codename, start=13) is None: + kernel_patch.extend(self.kernel_patches["Force enable Hyper Threading"]) + + for index, patch in enumerate(kernel_patch): + max_supported_macos_version = patch.get("MaxKernel") or self.latest_macos_version + min_supported_macos_version = patch.get("MinKernel") or "17.0.0" + + if "cpuid_cores_per_package" in patch["Comment"]: + patch["Replace"] = patch["Replace"].hex() + patch["Replace"] = self.utils.hex_to_bytes(patch["Replace"][:2] + self.utils.int_to_hex(int(cpu_cores)) + patch["Replace"][4:]) + elif "IOPCIIsHotplugPort" in patch["Comment"]: + if not self.utils.contains_any(chipset_data.AMDChipsets, motherboard_chipset, start=6) is None: + patch["Enabled"] = True + if "_mtrr_update_action" in patch["Comment"]: + if chipset_data.AMDChipsets[0].lower() in motherboard_chipset: + patch["Enabled"] = False + elif "AMD" in gpu_manufacturer: + if "Algrey" in patch["Comment"]: + patch["Enabled"] = False + elif "Shaneee" in patch["Comment"]: + patch["Enabled"] = True + + if not min_supported_macos_version[:2] <= str(macos_version) <= max_supported_macos_version[:2] or not patch["Enabled"]: + patches_to_remove.append(index) + + for index in patches_to_remove[::-1]: + kernel_patch.pop(index) + + return kernel_patch + + def boot_args(self, motherboard_name, platform, cpu_manufacturer, cpu_codename, discrete_gpu_codename, integrated_gpu_name, ethernet_pci, codec_id, touchpad_communication, unsupported_devices, custom_cpu_name, macos_version): + boot_args = [ + "-v", + "debug=0x100", + "keepsyms=1" + ] + + if codec_id in codec_layouts.data: + boot_args.append("alcid={}".format(random.choice(codec_layouts.data.get(codec_id)))) + + if "AMD" in cpu_manufacturer or self.is_intel_hedt_cpu(cpu_codename): + boot_args.append("npci=0x2000") + + if macos_version > 22: + boot_args.append("revpatch=sbvmm{}".format(",cpuname" if custom_cpu_name else "")) + else: + boot_args.append("revpatch=cpuname") + + if not self.utils.contains_any(cpu_data.IntelCPUGenerations, cpu_codename, start=13) is None: + boot_args.append("-ctrsmt") + + if ethernet_pci in ["8086-15F2", "8086-15F3", "8086-15F8"]: + if macos_version == 20: + boot_args.append("dk.e1000=0") + if macos_version == 21: + boot_args.append("e1000=0") + + if "Intel" in cpu_manufacturer: + if "Laptop" in platform: + if not self.utils.contains_any(cpu_data.IntelCPUGenerations, cpu_codename, start=6) is None: + boot_args.append("-igfxbl{}".format("t" if macos_version > 22 else "r")) + + if "UHD" in integrated_gpu_name and macos_version > 18: + boot_args.append("igfxonln=1") + + if "Ice Lake" in cpu_codename: + boot_args += ["-noDC9", "-igfxcdc", "-igfxdvmt", "-igfxdbeo"] + else: + if "Navi" in discrete_gpu_codename and not "Navi 2" in discrete_gpu_codename: + boot_args.append("agdpmod=pikera") + elif "UHD" in integrated_gpu_name and macos_version > 18: + boot_args.append("igfxonln=1") + + if "Laptop" in platform and not "SURFACE" in motherboard_name and "I2C" in touchpad_communication: + boot_args.append("-vi2c-force-polling") + + if macos_version > 23: + boot_args.append("-lilubetaall") + + if self.utils.contains_any(unsupported_devices, "Discrete GPU"): + boot_args.append("-wegnoegpu") + + return " ".join(boot_args) + + def csr_active_config(self, macos_version): + if macos_version > 19: + return "03080000" + elif macos_version > 17: + return "FF070000" + else: + return "FF030000" + + def load_drivers(self): + uefi_drivers = [] + + for driver_path in ["OpenCanopy.efi", "OpenHfsPlus.efi", "OpenRuntime.efi", "ResetNvramEntry.efi"]: + uefi_drivers.append({ + "Arguments": "", + "Comment": "", + "Enabled": True, + "LoadEarly": False, + "Path": driver_path + }) + + return uefi_drivers + + def genarate(self, hardware, efi_option, config): + del config["#WARNING - 1"] + del config["#WARNING - 2"] + del config["#WARNING - 3"] + del config["#WARNING - 4"] + config["ACPI"]["Add"] = efi_option.get("ACPI").get("Add") + if not self.is_intel_hedt_cpu(hardware.get("CPU Codename")) and not self.utils.contains_any(cpu_data.IntelCPUGenerations, hardware.get("CPU Codename"), end=2) is None: + for item in config["ACPI"]["Delete"]: + item.update({ + "All": True, + "Enabled": True + }) + else: + config["ACPI"]["Delete"] = [] + config["ACPI"]["Patch"] = efi_option.get("ACPI").get("Patch") + + config["Booter"]["MmioWhitelist"] = self.mmio_whitelist(hardware.get("CPU Codename")) + config["Booter"]["Patch"] = [] + config["Booter"]["Quirks"]["DevirtualiseMmio"] = self.check_mats_support(hardware.get("CPU Manufacturer"), hardware.get("Motherboard Chipset"), hardware.get("CPU Codename")) + if "AMD" in hardware.get("CPU Manufacturer") and not "TRX40" in hardware.get("Motherboard Chipset") or \ + not "Desktop" in hardware.get("Platform") and "Coffee Lake" in hardware.get("CPU Codename"): + config["Booter"]["Quirks"]["DevirtualiseMmio"] = False + config["Booter"]["Quirks"]["EnableWriteUnprotector"] = False if "Coffee Lake" in hardware.get("CPU Codename") else False if "AMD" in hardware.get("CPU Manufacturer") else not config["Booter"]["Quirks"]["DevirtualiseMmio"] + config["Booter"]["Quirks"]["ProtectUefiServices"] = "Z390" in hardware.get("Motherboard Chipset") or \ + not self.utils.contains_any(cpu_data.IntelCPUGenerations, hardware.get("CPU Codename"), start=10) is None + config["Booter"]["Quirks"]["RebuildAppleMemoryMap"] = not config["Booter"]["Quirks"]["EnableWriteUnprotector"] + config["Booter"]["Quirks"]["ResizeAppleGpuBars"] = 0 if self.check_resizable_bar_support( + hardware.get("Motherboard Chipset"), + hardware.get("Platform"), + hardware.get("CPU Codename"), + hardware.get("Discrete GPU") + ) else -1 + config["Booter"]["Quirks"]["SetupVirtualMap"] = not (not self.utils.contains_any(chipset_data.AMDChipsets, hardware.get("Motherboard Chipset"), end=5) is None or \ + "ASUS" in hardware.get("Motherboard Name") and self.is_intel_hedt_cpu(hardware.get("CPU Codename")) and config["Booter"]["Quirks"]["DevirtualiseMmio"]) + config["Booter"]["Quirks"]["SyncRuntimePermissions"] = config["Booter"]["Quirks"]["RebuildAppleMemoryMap"] + + config["DeviceProperties"]["Add"] = self.deviceproperties(hardware.get("CPU Codename"), hardware.get("Intel MEI"), efi_option.get("iGPU Properties")) + + config["Kernel"]["Add"] = efi_option.get("Kernel_Add") + config["Kernel"]["Block"] = self.block_kext_bundle(hardware.get("Wi-Fi (PCI)"), efi_option.get("macOS Version")) + spoof_cpuid = self.spoof_cpuid( + hardware.get("Processor Name"), + hardware.get("CPU Codename"), + efi_option.get("macOS Version") + ) + if spoof_cpuid: + config["Kernel"]["Emulate"]["Cpuid1Data"] = self.utils.hex_to_bytes("{}{}".format(spoof_cpuid, "0"*8*3)) + config["Kernel"]["Emulate"]["Cpuid1Mask"] = self.utils.hex_to_bytes("FFFFFFFF{}".format("0"*8*3)) + config["Kernel"]["Emulate"]["DummyPowerManagement"] = "AMD" in hardware.get("CPU Manufacturer") or \ + self.is_low_end_intel_cpu(hardware.get("Processor Name")) + config["Kernel"]["Force"] = [] + config["Kernel"]["Patch"] = self.load_kernel_patch( + hardware.get("Motherboard Chipset"), + hardware.get("CPU Manufacturer"), + hardware.get("CPU Codename"), + hardware["CPU Cores"], + hardware["Discrete GPU Manufacturer"] or hardware["Integrated GPU Manufacturer"], + efi_option.get("Synchronize the TSC"), + efi_option.get("macOS Version"), + ) + config["Kernel"]["Quirks"]["AppleCpuPmCfgLock"] = not self.utils.contains_any(cpu_data.IntelCPUGenerations, hardware.get("CPU Codename"), end=2) is None + config["Kernel"]["Quirks"]["AppleXcpmCfgLock"] = False if "AMD" in hardware.get("CPU Manufacturer") else not config["Kernel"]["Quirks"]["AppleCpuPmCfgLock"] + config["Kernel"]["Quirks"]["AppleXcpmExtraMsrs"] = self.is_intel_hedt_cpu(hardware.get("CPU Codename")) and not self.utils.contains_any(cpu_data.IntelCPUGenerations, hardware.get("CPU Codename"), end=4) is None + config["Kernel"]["Quirks"]["CustomSMBIOSGuid"] = True + config["Kernel"]["Quirks"]["DisableIoMapper"] = not "AMD" in hardware.get("CPU Manufacturer") + config["Kernel"]["Quirks"]["DisableRtcChecksum"] = "ASUS" in hardware.get("Motherboard Name") or "HP" in hardware.get("Motherboard Name") + config["Kernel"]["Quirks"]["LapicKernelPanic"] = "HP" in hardware.get("Motherboard Name") + config["Kernel"]["Quirks"]["PanicNoKextDump"] = config["Kernel"]["Quirks"]["PowerTimeoutKernelPanic"] = True + config["Kernel"]["Quirks"]["ProvideCurrentCpuInfo"] = "AMD" in hardware.get("CPU Manufacturer") or \ + not self.utils.contains_any(cpu_data.IntelCPUGenerations, hardware.get("CPU Codename"), start=13) is None + config["Kernel"]["Quirks"]["SetApfsTrimTimeout"] = 0 if any(controller_props.get("Device ID").startswith("144D") for controller_name, controller_props in hardware.get("Storage Controllers").items()) else -1 + + config["Misc"]["BlessOverride"] = [] + config["Misc"]["Boot"]["LauncherOption"] = "Full" + config["Misc"]["Boot"]["PickerMode"] = "External" + config["Misc"]["Boot"]["Timeout"] = 10 + config["Misc"]["Debug"]["AppleDebug"] = config["Misc"]["Debug"]["ApplePanic"] = False + config["Misc"]["Debug"]["DisableWatchDog"] = True + config["Misc"]["Debug"]["Target"] = 0 + config["Misc"]["Entries"] = [] + config["Misc"]["Security"]["AllowSetDefault"] = True + config["Misc"]["Security"]["ScanPolicy"] = 0 + config["Misc"]["Security"]["SecureBootModel"] = "Default" if 19 < efi_option.get("macOS Version") < 23 else "Disabled" + config["Misc"]["Security"]["Vault"] = "Optional" + config["Misc"]["Tools"] = [] + + if efi_option.get("Custom CPU Name"): + config["NVRAM"]["Add"]["4D1FDA02-38C7-4A6A-9CC6-4BCCA8B30102"]["revcpu"] = 1 + config["NVRAM"]["Add"]["4D1FDA02-38C7-4A6A-9CC6-4BCCA8B30102"]["revcpuname"] = hardware.get("Processor Name") + del config["NVRAM"]["Add"]["7C436110-AB2A-4BBB-A880-FE41995C9F82"]["#INFO (prev-lang:kbd)"] + config["NVRAM"]["Add"]["7C436110-AB2A-4BBB-A880-FE41995C9F82"]["boot-args"] = self.boot_args( + hardware.get("Motherboard Name"), + hardware.get("Platform"), + hardware.get("CPU Manufacturer"), + hardware.get("CPU Codename"), + hardware.get("Discrete GPU Codename"), + hardware.get("Integrated GPU Name"), + hardware.get("Ethernet (PCI)"), + hardware.get("Codec ID"), + hardware.get("Touchpad Communication"), + hardware.get("Unsupported Devices"), + efi_option.get("Custom CPU Name"), + efi_option.get("macOS Version") + ) + config["NVRAM"]["Add"]["7C436110-AB2A-4BBB-A880-FE41995C9F82"]["csr-active-config"] = self.utils.hex_to_bytes(self.csr_active_config(efi_option.get("macOS Version"))) + config["NVRAM"]["Add"]["7C436110-AB2A-4BBB-A880-FE41995C9F82"]["prev-lang:kbd"] = "en:252" + if efi_option.get("Custom CPU Name"): + config["NVRAM"]["Delete"]["4D1FDA02-38C7-4A6A-9CC6-4BCCA8B30102"].extend(["revcpu", "revcpuname"]) + + config["PlatformInfo"]["Generic"].update(self.smbios.generate(efi_option.get("SMBIOS"))) + if efi_option.get("Custom CPU Name"): + config["PlatformInfo"]["Generic"]["ProcessorType"] = 1537 if int(hardware["CPU Cores"]) < 8 else 3841 + config["PlatformInfo"]["Generic"]["ROM"] = self.utils.hex_to_bytes(config["PlatformInfo"]["Generic"]["ROM"]) + + config["UEFI"]["APFS"]["MinDate"] = config["UEFI"]["APFS"]["MinVersion"] = -1 + config["UEFI"]["Drivers"] = self.load_drivers() + config["UEFI"]["Quirks"]["IgnoreInvalidFlexRatio"] = not self.utils.contains_any(cpu_data.IntelCPUGenerations, hardware.get("CPU Codename"), end=4) is None + config["UEFI"]["Quirks"]["ReleaseUsbOwnership"] = True + config["UEFI"]["Quirks"]["UnblockFsConnect"] = "HP" in hardware.get("Motherboard Name") + config["UEFI"]["ReservedMemory"] = [] + + return config \ No newline at end of file diff --git a/Scripts/datasets/chipset_data.py b/Scripts/datasets/chipset_data.py new file mode 100755 index 0000000..7765c6f --- /dev/null +++ b/Scripts/datasets/chipset_data.py @@ -0,0 +1,161 @@ +# Resource: https://en.wikipedia.org/wiki/List_of_Intel_chipsets +IntelChipsets = [ + "H61", + "B65", + "Q65", + "P67", + "H67", + "Q67", + "Z68", + "HM65", + "HM67", + "UM67", + "QM67", + "QS67", + "Cougar Point", + "B75", + "Q75", + "Z75", + "H77", + "Q77", + "Z77", + "C216", + "NM70", + "HM70", + "HM75", + "HM76", + "UM77", + "HM77", + "QM77", + "QS77", + "X79", + "C602", + "Panther Point", + "Patsburg", + "H81", + "B85", + "Q85", + "Q87", + "H87", + "Z87", + "HM86", + "QM87", + "HM87", + "Lynx Point", + "H97", + "Z97", + "HM97", + "C612", + "X99", + "Wildcat Point", + "Wellsburg", + "X299", + "C422", + "C621", + "C622", + "C624", + "C625", + "C626", + "C627", + "C628", + "Basin Falls", + "Lewisburg", + "H110", + "B150", + "Q150", + "H170", + "Q170", + "Z170", + "HM170", + "QM170", + "QMS180", + "QMU185", + "HM175", + "QM175", + "B250", + "Q250", + "H270", + "Q270", + "Z270", + "C232", + "C236", + "CM236", + "CM238", + "B365", + "Sunrise Point", + "Kaby Point", + "Union Point", + "Z370", + "H310", + "B360", + "H370", + "Q370", + "Z390", + "C242", + "C246", + "HM370", + "QM370", + "CM246", + "Cannon Point", + "H410", + "B460", + "H470", + "Q470", + "Z490", + "W480", + "H420E", + "Q470E", + "W480E", + "HM470", + "QM480", + "WM490", + "Comet Point", + "H510", + "B560", + "H570", + "Z590", + "W580", + "HM570E", + "QM580E", + "RM590E", + "HM570", + "QM580", + "WM590", + "Tiger Point", + "495", + "Ice Point", + "Ice Lake", + "Z690", + "W680", + "Q670", + "H670", + "B660", + "H610", + "R680E", + "Q670E", + "H610E", + "HM670", + "WM690", + "Alder Point", + "Z790", + "H770", + "B760", + "HM770", + "WM790", + "Raptor Point", +] + +# Resource: https://en.wikipedia.org/wiki/List_of_AMD_chipsets +AMDChipsets = [ + "TRX40", + "B450", + "X470", + "A520", + "B550", + "X570", + "A620", + "B650", + "X670", + "X870" +] + diff --git a/Scripts/datasets/cpu_data.py b/Scripts/datasets/cpu_data.py new file mode 100755 index 0000000..7d32054 --- /dev/null +++ b/Scripts/datasets/cpu_data.py @@ -0,0 +1,43 @@ +AMDCPUGenerations = [ + "Summit Ridge", + "Raven Ridge", + "Pinnacle Ridge", + "Dalí", + "Picasso", + "Matisse", + "Renoir", + "Lucienne", + "Vermeer", + "Cezanne", + "Barcelo", + "Rembrandt", + "Raphael", + "Mendocino", + "Phoenix", + "Dragon Range", + "Hawk Point", + "Granite Ridge", + "Whitehaven", + "Colfax", + "Castle Peak", + "Chagall", + "Storm Peak" +] + +IntelCPUGenerations = [ + "Sandy Bridge", + "Ivy Bridge", + "Haswell", + "Broadwell", + "Skylake", + "Cascade Lake", + "Kaby Lake", + "Amber Lake", + "Whiskey Lake", + "Coffee Lake", + "Comet Lake", + "Ice Lake", + "Rocket Lake", + "Alder Lake", + "Raptor Lake" +] \ No newline at end of file diff --git a/Scripts/datasets/pci_data.py b/Scripts/datasets/pci_data.py new file mode 100755 index 0000000..45e460b --- /dev/null +++ b/Scripts/datasets/pci_data.py @@ -0,0 +1,1157 @@ +AMDGPUIDs = [ + # NootedRed and NootRX + "1002-15D8", + "1002-15D8", + "1002-15DD", + "1002-15DD", + "1002-15E7", + "1002-15E7", + "1002-1636", + "1002-1636", + "1002-1638", + "1002-1638", + "1002-164C", + "1002-164C", + "1002-73A2", + "1002-73A2", + "1002-73A3", + "1002-73A3", + "1002-73A5", + "1002-73A5", + "1002-73AB", + "1002-73AB", + "1002-73AF", + "1002-73AF", + "1002-73BF", + "1002-73BF", + "1002-73DF", + "1002-73DF", + "1002-73E0", + "1002-73E0", + "1002-73E1", + "1002-73E1", + "1002-73E3", + "1002-73E3", + "1002-73EF", + "1002-73EF", + "1002-73FF", + "1002-73FF" +] + +BluetoothIDs = [ + # BrcmPatchRAM Plugins + "0489-E032", + "0489-E042", + "0489-E046", + "0489-E047", + "0489-E04F", + "0489-E052", + "0489-E055", + "0489-E059", + "0489-E062", + "0489-E079", + "0489-E07A", + "0489-E087", + "0489-E096", + "0489-E0A1", + "04CA-2003", + "04CA-2004", + "04CA-2005", + "04CA-2006", + "04CA-2007", + "04CA-2009", + "04CA-200A", + "04CA-200B", + "04CA-200C", + "04CA-200E", + "04CA-200F", + "04CA-2012", + "04CA-2016", + "04F2-B49D", + "04F2-B4A1", + "050D-065A", + "0930-021E", + "0930-021F", + "0930-0221", + "0930-0223", + "0930-0225", + "0930-0226", + "0930-0229", + "0A5C-2167", + "0A5C-2168", + "0A5C-2169", + "0A5C-216A", + "0A5C-216B", + "0A5C-216C", + "0A5C-216D", + "0A5C-216E", + "0A5C-216F", + "0A5C-21D3", + "0A5C-21D6", + "0A5C-21D7", + "0A5C-21D8", + "0A5C-21DC", + "0A5C-21DE", + "0A5C-21E1", + "0A5C-21E3", + "0A5C-21E6", + "0A5C-21E8", + "0A5C-21EC", + "0A5C-21F1", + "0A5C-21F3", + "0A5C-21F4", + "0A5C-21FB", + "0A5C-21FD", + "0A5C-21FE", + "0A5C-640B", + "0A5C-6410", + "0A5C-6412", + "0A5C-6413", + "0A5C-6414", + "0A5C-6417", + "0A5C-6418", + "0A5C-7460", + "0B05-17B5", + "0B05-17CB", + "0B05-17CF", + "0B05-180A", + "0BB4-0306", + "105B-E065", + "105B-E066", + "13D3-3384", + "13D3-3388", + "13D3-3389", + "13D3-3392", + "13D3-3404", + "13D3-3411", + "13D3-3413", + "13D3-3418", + "13D3-3427", + "13D3-3435", + "13D3-3456", + "13D3-3482", + "13D3-3484", + "13D3-3504", + "13D3-3508", + "13D3-3517", + "145F-01A3", + "185F-2167", + "19FF-0239", + "413C-8143", + "413C-8197", + # IntelBluetoothFirmware.kext + "8087-0025", + "8087-0026", + "8087-0029", + "8087-0032", + "8087-0033", + "8087-0035", + "8087-0036", + "8087-0038", + "8087-07DA", + "8087-07DC", + "8087-0A2A", + "8087-0A2B", + "8087-0AA7", + "8087-0AAA", + "0A12-0001" +] + +CodecIDs = [ + # AppleALC.kext + "1013-4210", + "1013-4213", + "10EC-0215", + "10EC-0221", + "10EC-0222", + "10EC-0225", + "10EC-0230", + "10EC-0233", + "10EC-0235", + "10EC-0236", + "10EC-0245", + "10EC-0255", + "10EC-0256", + "10EC-0257", + "10EC-0260", + "10EC-0262", + "10EC-0268", + "10EC-0269", + "10EC-0270", + "10EC-0272", + "10EC-0274", + "10EC-0275", + "10EC-0280", + "10EC-0282", + "10EC-0283", + "10EC-0284", + "10EC-0285", + "10EC-0286", + "10EC-0287", + "10EC-0288", + "10EC-0289", + "10EC-0290", + "10EC-0292", + "10EC-0293", + "10EC-0294", + "10EC-0295", + "10EC-0298", + "10EC-0299", + "10EC-0623", + "10EC-0662", + "10EC-0663", + "10EC-0665", + "10EC-0668", + "10EC-0670", + "10EC-0671", + "10EC-0700", + "10EC-0867", + "10EC-0882", + "10EC-0883", + "10EC-0885", + "10EC-0887", + "10EC-0888", + "10EC-0889", + "10EC-0892", + "10EC-0897", + "10EC-0899", + "10EC-0900", + "10EC-0B00", + "10EC-1168", + "10EC-1220", + "1102-0011", + "1106-0441", + "1106-4760", + "1106-8446", + "111D-7603", + "111D-7605", + "111D-7608", + "111D-7675", + "111D-7676", + "111D-7695", + "111D-76B2", + "111D-76D1", + "111D-76D5", + "111D-76D9", + "111D-76DF", + "111D-76E0", + "111D-76E5", + "111D-76E7", + "111D-76F3", + "11D4-1884", + "11D4-194A", + "11D4-1984", + "11D4-1988", + "11D4-198B", + "11D4-989B", + "14F1-1F72", + "14F1-1F86", + "14F1-1FD6", + "14F1-2008", + "14F1-20D0", + "14F1-5051", + "14F1-5067", + "14F1-5069", + "14F1-506C", + "14F1-506E", + "14F1-5098", + "14F1-50A1", + "14F1-50A2", + "14F1-50F2", + "14F1-50F4", + "14F1-510F", + "14F1-5111", + "14F1-5113", + "14F1-5114", + "14F1-5115", + "8384-7662", + "8384-7690", + "8384-76A0" +] + +InputIDs = [ + # AlpsHID.kext + # http://linux-hardware.org/ + "044E-1207", + "044E-120A", + "044E-120B", + "044E-120C", + "044E-120D", + "044E-1215", + "044E-1216", + "044E-1217", + "044E-121E", + "044E-121F", + "ALP-0001", + "ALP-000D", + "ALP-000E", + "ALP-000F", + "ALP-0011", + "ALP-0012", + "ALP-0013", + "ALP-0015", + "ALP-0016", + "ALP-001C", + "ALPS-07AP", + "ALPS-121E", + "AUI-1657", + "AUI-165C", + "AUI-1661", + "AUI-1664", + "AUI-1665", + "AUI-1666", + "AUI-1667", + "AUI-1669", + "DELL-07B7", + "DELL-07B8", + "DELL-080E", + "DELL-080F", + "DELL-0810", + "DELL-0811", + "DELL-0812", + "DELL-0814", + "DELL-0815", + "DELL-0816", + "DELL-0817", + "DELL-0818", + "DELL-0819", + "DELL-081A", + "DELL-081B", + "DELL-081C", + "DELL-0820", + "DELL-0823", + "DELL-0831", + "DELL-0832", + "DELL-0839", + "DELL-083A", + "DELL-0848", + "DELL-0849", + "DELL-0879", + "DELL-087A", + "DELL-08B6", + "DELL-08B7", + "DELL-0926", + "DELL-0927", + "DELL-099E", + "DELL-099F", + "DLL-079F", + "DLL-07A0", + "DLL-07A6", + "DLL-07A7", + "DLL-07A8", + "DLL-07A9", + "DLL-07AA", + "DLL-07AB", + "DLL-07B0", + "DLL-07B1", + "DLL-07D0", + "DLL-07D1", + "DLL-07F3", + "MSFT-0001", + "O44E-1220", + # VoodooSMBus.kext + "ELAN-001D", + "ELAN-0028", + "ELAN-0200", + # VoodooRMI.kext + "SYN-1B7F", + "SYN-3054", + "SYNA-0000", + "SYNA-1202", + "SYNA-2393", + "SYNA-2B2C", + "SYNA-2B31", + "SYNA-2B33", + "SYNA-2B34", + "SYNA-2B5A", + "SYNA-2B61", + "SYNA-3083", + "SYNA-3105", + "SYNA-328B", + "SYNA-328E", + "SYNA-3602", + "SYNA-7500", + "SYNA-7501", + "SYNA-7DAB", + "SYNA-7DB5" +] + +NetworkIDs = [ + # AirportBrcmFixup.kext + "14E4-4311", + "14E4-4312", + "14E4-4313", + "14E4-4318", + "14E4-4319", + "14E4-431A", + "14E4-4320", + "14E4-4324", + "14E4-4325", + "14E4-4328", + "14E4-432B", + "14E4-432C", + "14E4-432D", + "14E4-4331", + "14E4-4353", + "14E4-4357", + "14E4-43A0", + "14E4-43A3", + "14E4-43B1", + "14E4-43B2", + "14E4-43BA", + # itlwm.kext + "8086-0060", + "8086-0064", + "8086-0082", + "8086-0083", + "8086-0084", + "8086-0085", + "8086-0087", + "8086-0089", + "8086-008A", + "8086-008B", + "8086-0090", + "8086-0091", + "8086-00A0", + "8086-00A4", + "8086-0260", + "8086-0264", + "8086-02A0", + "8086-02F0", + "8086-06F0", + "8086-0887", + "8086-0888", + "8086-088E", + "8086-088F", + "8086-0890", + "8086-0891", + "8086-0892", + "8086-0893", + "8086-0894", + "8086-0895", + "8086-0896", + "8086-0897", + "8086-08AE", + "8086-08AF", + "8086-08B1", + "8086-08B2", + "8086-08B3", + "8086-08B4", + "8086-095A", + "8086-095B", + "8086-24F3", + "8086-24F4", + "8086-24F5", + "8086-24F6", + "8086-24FB", + "8086-24FD", + "8086-2526", + "8086-271B", + "8086-271C", + "8086-2720", + "8086-2723", + "8086-2725", + "8086-2726", + "8086-2729", + "8086-30DC", + "8086-3165", + "8086-3166", + "8086-31DC", + "8086-34F0", + "8086-3DF0", + "8086-40A4", + "8086-4229", + "8086-422B", + "8086-422C", + "8086-4230", + "8086-4232", + "8086-4235", + "8086-4236", + "8086-4237", + "8086-4238", + "8086-4239", + "8086-423A", + "8086-423B", + "8086-423C", + "8086-423D", + "8086-42A4", + "8086-43F0", + "8086-4DF0", + "8086-51F0", + "8086-51F1", + "8086-54F0", + "8086-7A70", + "8086-7AF0", + "8086-7E40", + "8086-7F70", + "8086-9DF0", + "8086-A0F0", + "8086-A370", + # AppleIGC.kext + "8086-125B", + "8086-125C", + "8086-125D", + "8086-15F2", + "8086-15F3", + "8086-15F8", + "8086-3102", + # AtherosE2200Ethernet.kext + "1969-1090", + "1969-1091", + "1969-10A0", + "1969-10A1", + "1969-E091", + "1969-E0A1", + "1969-E0B1", + # IntelMausi.kext + "8086-0D4C", + "8086-0D4D", + "8086-0D4E", + "8086-0D4F", + "8086-0D53", + "8086-0D55", + "8086-10EA", + "8086-10EB", + "8086-10EF", + "8086-10F0", + "8086-1502", + "8086-1503", + "8086-153A", + "8086-153B", + "8086-1559", + "8086-155A", + "8086-156F", + "8086-1570", + "8086-15A0", + "8086-15A1", + "8086-15A2", + "8086-15A3", + "8086-15B7", + "8086-15B8", + "8086-15B9", + "8086-15BB", + "8086-15BC", + "8086-15BD", + "8086-15BE", + "8086-15D6", + "8086-15D7", + "8086-15D8", + "8086-15DF", + "8086-15E0", + "8086-15E1", + "8086-15E2", + "8086-15E3", + "8086-15F4", + "8086-15F5", + "8086-15F9", + "8086-15FA", + "8086-15FB", + "8086-15FC", + "8086-1A1C", + "8086-1A1D", + "8086-1A1E", + "8086-1A1F", + "8086-550A", + "8086-550B", + "8086-550C", + "8086-550D", + # LucyRTL8125Ethernet.kext + "10EC-3000", + "10EC-8125", + "1186-8125", + # RealtekRTL8100.kext + "10EC-8136", + # RealtekRTL8111.kext + "10EC-8168", + "1186-8168", + "10EC-2502", + "10EC-2600", + # RtWlanU.kext, RtWlanU1827.kext and RT2870USBWirelessDriver.kext + "0409-0408", + "0411-0242", + "0411-025D", + "0411-029B", + "0411-029D", + "04BB-0952", + "04BB-0953", + "04BB-0959", + "04BB-095A", + "04CA-8602", + "050D-1106", + "050D-1109", + "056E-4007", + "056E-4008", + "056E-400B", + "056E-400D", + "056E-400E", + "056E-400F", + "056E-4010", + "056E-4011", + "0586-3426", + "058C-FF20", + "0789-016E", + "07B8-0811", + "07B8-8179", + "07B8-818B", + "07B8-8812", + "0846-9051", + "0846-9052", + "0846-9054", + "0846-9055", + "08C4-0115", + "0B05-17D2", + "0B05-1817", + "0B05-1841", + "0B05-184C", + "0B05-1852", + "0B05-1853", + "0B05-1870", + "0B05-1874", + "0B05-18E9", + "0B05-18F0", + "0B05-18F1", + "0BDA-0170", + "0BDA-0179", + "0BDA-0811", + "0BDA-0823", + "0BDA-2003", + "0BDA-2005", + "0BDA-2006", + "0BDA-2102", + "0BDA-318B", + "0BDA-8179", + "0BDA-818B", + "0BDA-818C", + "0BDA-8812", + "0BDA-8813", + "0BDA-881A", + "0BDA-881B", + "0BDA-881C", + "0BDA-A179", + "0BDA-A811", + "0BDA-A812", + "0BDA-B711", + "0BDA-B720", + "0BDA-B812", + "0BDA-B814", + "0BDA-B81A", + "0BDA-B82C", + "0BDA-C811", + "0BDA-C812", + "0BDA-C820", + "0BDA-C82B", + "0BDA-C82C", + "0BDA-F192", + "0DF6-0074", + "0DF6-0076", + "0DF6-007A", + "0DF6-007B", + "0E66-0022", + "0E66-0023", + "0E66-0024", + "0E66-0025", + "0E66-0026", + "1058-0632", + "13B1-003F", + "13B1-0043", + "13B1-0045", + "148F-9097", + "1668-8105", + "1668-8108", + "1740-0100", + "1EDA-2520", + "1EDA-2525", + "2001-330E", + "2001-330F", + "2001-3310", + "2001-3311", + "2001-3312", + "2001-3313", + "2001-3314", + "2001-3315", + "2001-3316", + "2001-3318", + "2001-3319", + "2001-331A", + "2001-331B", + "2001-331C", + "2001-331D", + "2001-331E", + "2001-331F", + "2001-3320", + "2001-3322", + "2019-AB30", + "2019-AB32", + "2019-AB33", + "20F4-108A", + "20F4-804B", + "20F4-805A", + "20F4-805B", + "20F4-808A", + "20F4-809A", + "2357-0101", + "2357-0103", + "2357-0106", + "2357-0107", + "2357-0108", + "2357-0109", + "2357-010C", + "2357-010D", + "2357-010E", + "2357-010F", + "2357-0111", + "2357-0112", + "2357-0113", + "2357-0114", + "2357-0115", + "2357-0116", + "2357-0117", + "2357-011E", + "2357-011F", + "2357-0120", + "2357-0121", + "2357-0122", + "2357-0126", + "2357-0127", + "2357-0128", + "2357-0129", + "2357-012A", + "2357-012C", + "2357-012D", + "2357-012E", + "2357-012F", + "2357-0132", + "2357-0138", + "2604-0012", + "2C2B-0002", + "7392-A611", + "7392-A811", + "7392-A812", + "7392-A813", + "7392-A822", + "7392-A833", + "7392-A834", + "7392-B611", + "7392-B722", + "7392-B811", + "7392-B822", + "7392-C822", + "7392-D822", + "7392-E822", + "7392-F822", + "038B-0100", + "04BB-094C", + "04F2-AFF7", + "04F2-AFF8", + "04F2-AFF9", + "04F2-AFFA", + "04F2-AFFB", + "04F2-AFFC", + "050D-1004", + "050D-1102", + "050D-1105", + "050D-110A", + "050D-120A", + "050D-2102", + "050D-2103", + "056E-4009", + "0586-341F", + "06F8-E033", + "06F8-E035", + "0789-016D", + "07AA-0056", + "07B8-8178", + "07B8-8189", + "0846-9021", + "0846-9041", + "0846-F001", + "0B05-17AB", + "0B05-17BA", + "0B05-17C0", + "0BDA-018A", + "0BDA-0A8A", + "0BDA-1E1E", + "0BDA-2E2E", + "0BDA-317F", + "0BDA-5088", + "0BDA-8011", + "0BDA-8176", + "0BDA-8177", + "0BDA-8178", + "0BDA-817A", + "0BDA-817B", + "0BDA-817F", + "0BDA-818A", + "0BDA-8192", + "0BDA-8194", + "0DF6-0052", + "0DF6-005C", + "0DF6-0061", + "0DF6-0070", + "0DF6-0077", + "0E0B-9071", + "0E66-0019", + "0E66-0020", + "103C-1629", + "13D3-3357", + "2001-3307", + "2001-3308", + "2001-3309", + "2001-330A", + "2001-330B", + "2001-330D", + "2019-1201", + "2019-4902", + "2019-AB2A", + "2019-AB2B", + "2019-AB2E", + "2019-ED17", + "20F4-624D", + "20F4-648B", + "20F4-648C", + "20F4-664B", + "4855-0090", + "4855-0091", + "4856-0091", + "7392-7811", + "7392-7822", + "CDAB-8010", + "CDAB-8011", + "0411-00E8", + "0411-0148", + "0411-0150", + "0411-015D", + "0471-200F", + "04BB-0944", + "04BB-0945", + "050D-8053", + "050D-815C", + "056E-400A", + "0586-3416", + "0586-3418", + "0586-341A", + "0586-341E", + "0586-3425", + "0789-0164", + "0789-0166", + "0789-0168", + "0789-0169", + "07AA-002F", + "07AA-003C", + "07AA-003F", + "07AA-0041", + "07AA-0042", + "07B8-2770", + "07B8-2870", + "07B8-3070", + "07B8-3071", + "07B8-3072", + "07B8-7610", + "07D1-3317", + "07D1-3C08", + "07D1-3C09", + "07D1-3C0A", + "07D1-3C0B", + "07D1-3C0D", + "07D1-3C0E", + "07D1-3C0F", + "07D1-3C11", + "07D1-3C13", + "07D1-3C13", + "07D1-3C15", + "07D1-3C16", + "07D1-3C17", + "07D1-3C1B", + "07D1-3D02", + "083A-6618", + "083A-7511", + "083A-7512", + "083A-7522", + "083A-8522", + "083A-A512", + "083A-A618", + "083A-A618", + "083A-A701", + "083A-A702", + "083A-A703", + "083A-B522", + "083A-D522", + "083A-F511", + "0846-9012", + "0846-9053", + "0B05-1731", + "0B05-1732", + "0B05-1742", + "0B05-1760", + "0B05-1761", + "0B05-1784", + "0B05-179D", + "0B05-17A7", + "0B05-17AD", + "0B05-17BC", + "0B05-17D1", + "0B05-17DB", + "0B05-17EB", + "0B05-180B", + "0B05-1833", + "0CDE-0022", + "0DB0-3870", + "0DB0-6899", + "0DB0-870A", + "0DB0-899A", + "0DF6-0017", + "0DF6-002B", + "0DF6-002C", + "0DF6-002D", + "0DF6-0039", + "0DF6-003B", + "0DF6-003C", + "0DF6-003E", + "0DF6-0040", + "0DF6-0041", + "0DF6-0042", + "0DF6-0047", + "0DF6-0048", + "0DF6-004A", + "0DF6-004D", + "0DF6-0050", + "0DF6-0051", + "0DF6-0062", + "0DF6-0067", + "0DF6-0068", + "0DF6-0069", + "0DF6-006A", + "0DF6-006E", + "0DF6-006F", + "0E66-0001", + "0E66-0002", + "0E66-0003", + "0E66-0004", + "0E66-0009", + "0E66-000A", + "0E66-000B", + "0E66-000C", + "0E66-0013", + "0E66-0017", + "0E66-0018", + "0E66-0020", + "0E66-0021", + "0E8D-7610", + "0E8D-7612", + "0E8D-761A", + "0E8D-761B", + "0E8D-7652", + "0E8D-7662", + "100D-9031", + "100D-9032", + "1044-800B", + "1044-800C", + "1044-800D", + "13B1-003B", + "13B1-003E", + "13D3-3247", + "13D3-3262", + "13D3-3305", + "148F-2070", + "148F-2770", + "148F-2870", + "148F-3070", + "148F-3070", + "148F-3071", + "148F-3072", + "148F-3370", + "148F-3572", + "148F-3573", + "148F-5370", + "148F-5372", + "148F-5572", + "148F-7601", + "148F-760B", + "148F-7610", + "148F-761A", + "148F-8070", + "14B2-3C06", + "14B2-3C07", + "14B2-3C08", + "14B2-3C08", + "14B2-3C11", + "14B2-3C12", + "14B2-3C23", + "14B2-3C25", + "14B2-3C25", + "14B2-3C27", + "157E-300E", + "157E-300E", + "15A9-0006", + "15A9-0006", + "15A9-0010", + "1690-0740", + "1690-0744", + "1737-0070", + "1737-0071", + "1737-0078", + "1740-0600", + "1740-0602", + "1740-0605", + "1740-0615", + "1740-9701", + "1740-9702", + "1740-9703", + "1740-9705", + "1740-9706", + "1740-9707", + "1740-9708", + "1740-9709", + "1740-9801", + "1761-0B05", + "177F-0302", + "18C5-0008", + "18C5-0011", + "18C5-0012", + "18E8-6259", + "1B75-2770", + "1B75-2870", + "1B75-3072", + "1D4D-0001", + "1D4D-0002", + "1D4D-000C", + "1D4D-000E", + "2001-3C15", + "2001-3C19", + "2001-3C1A", + "2001-3C1B", + "2001-3C1C", + "2001-3C1D", + "2001-3C1F", + "2001-3C20", + "2001-3C21", + "2001-3C22", + "2001-3C24", + "2019-AB24", + "2019-AB24", + "2019-AB25", + "2019-AB29", + "2019-AB31", + "2019-AB31", + "2019-ED06", + "2019-ED06", + "2019-ED10", + "2019-ED14", + "2019-ED15", + "203D-1480", + "203D-149A", + "203D-14A1", + "203D-14A9", + "20B8-8888", + "20F4-806B", + "2357-0105", + "2357-010B", + "2357-0123", + "5702-293C", + "5A57-0283", + "5A57-0284", + "5A57-5257", + "7392-7710", + "7392-7711", + "7392-7717", + "7392-7718", + "7392-7722", + "7392-7733", + "7392-A711", + "7392-A722", + "7392-B711", + "7392-B720", + "7392-C711", + "F201-5370" +] + +RealtekCardReaderIDs = [ + # RealtekCardReader.kext + "0BDA-0129", + "0BDA-0139", + "0BDA-0140", + "10EC-5209", + "10EC-5227", + "10EC-5229", + "10EC-522A", + "10EC-5249", + "10EC-524A", + "10EC-525A", + "10EC-5260", + "10EC-5286", + "10EC-5287", + "10EC-5289" +] + +UnsupportedUSBControllerIDs = [ + "1022-1639", + # XHCI-unsupported.kext + "8086-02ED", + "8086-06ED", + "8086-34ED", + "8086-43ED", + "8086-51ED", + "8086-7A60", + "8086-7AE0", + "8086-8CB1", + "8086-8D31", + "8086-9DED", + "8086-A0ED", + "8086-A2AF", + "8086-A36D", + "8086-A3AF" +] + +UnsupportedSATAControllerIDs = [ + # CtlnaAHCIPort.kext + "1022-7901", + "8086-06D6", + "8086-1C02", + "8086-1C03", + "8086-1E02", + "8086-1E03", + "8086-2822", + "8086-282A", + "8086-3B22", + "8086-3B29", + "8086-3B2F", + "8086-43D2", + "8086-7AE2", + "8086-8C02", + "8086-8C03", + "8086-8C83", + "8086-9C03", + "8086-9C83", + "8086-9D03", + "8086-9DD3", + "8086-A102", + "8086-A103", + "8086-A182", + "8086-A282", + "8086-A352", + "8086-A353" +] + +# Resource: https://github.com/torvalds/linux/blob/master/drivers/pci/controller/vmd.c +IntelVMDIDs = [ + "8086-201D", + "8086-28C0", + "8086-467F", + "8086-4C3D", + "8086-7D0B", + "8086-9A0B", + "8086-A77F", + "8086-AD0B" +] + +# Resource: https://pci-ids.ucw.cz/ +UnsupportedNVMeSSDIDs = { + "1344-5410": "Micron 2200S", + "144D-A808": "Samsung SM981/PM981/PM983", + "2646-2263": "Kingston A2000 NVMe SSD SM2263EN", + "1C5C-174A": "SK hynix BC711/PC711", + "1C5C-1639": "SK hynix PC611", + "1C5C-1627": "SK hynix PC601", + "1C5C-1327": "SK hynix BC501", + "8086-390B": "Intel 760p", +} \ No newline at end of file diff --git a/Scripts/dsdt.py b/Scripts/dsdt.py new file mode 100755 index 0000000..7973e03 --- /dev/null +++ b/Scripts/dsdt.py @@ -0,0 +1,728 @@ +# Original source: +# https://github.com/corpnewt/SSDTTime/blob/7b3fb78112bf320a1bc6a7e50dddb2b375cb70b0/Scripts/dsdt.py + +import os, errno, tempfile, shutil, plistlib, sys, binascii, zipfile, getpass, re +from Scripts import resource_fetcher +from Scripts import run +from Scripts import utils + +class DSDT: + def __init__(self, **kwargs): + #self.dl = downloader.Downloader() + self.fetcher = resource_fetcher.ResourceFetcher() + self.r = run.Run() + #self.u = utils.Utils("SSDT Time") + self.u = utils.Utils() + self.iasl_url_macOS = "https://raw.githubusercontent.com/acidanthera/MaciASL/master/Dist/iasl-stable" + self.iasl_url_macOS_legacy = "https://raw.githubusercontent.com/acidanthera/MaciASL/master/Dist/iasl-legacy" + self.iasl_url_linux = "https://raw.githubusercontent.com/corpnewt/linux_iasl/main/iasl.zip" + self.iasl_url_linux_legacy = "https://raw.githubusercontent.com/corpnewt/iasl-legacy/main/iasl-legacy-linux.zip" + self.acpi_binary_tools = "https://www.intel.com/content/www/us/en/developer/topic-technology/open/acpica/download.html" + self.iasl_url_windows_legacy = "https://raw.githubusercontent.com/corpnewt/iasl-legacy/main/iasl-legacy-windows.zip" + self.h = {} # {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"} + self.iasl = self.check_iasl() + #self.iasl_legacy = self.check_iasl(legacy=True) + if not self.iasl: + url = self.acpi_binary_tools if os.name=="nt" else \ + self.iasl_url_macOS if sys.platform=="darwin" else \ + self.iasl_url_linux if sys.platform.startswith("linux") else None + exception = "Could not locate or download iasl!" + if url: + exception += "\n\nPlease manually download {} from:\n - {}\n\nAnd place in:\n - {}\n".format( + "and extract iasl.exe and acpidump.exe" if os.name=="nt" else "iasl", + url, + os.path.dirname(os.path.realpath(__file__)) + ) + raise Exception(exception) + self.allowed_signatures = ("APIC","DMAR","DSDT","SSDT") + self.mixed_listing = ("DSDT","SSDT") + self.acpi_tables = {} + # Setup regex matches + self.hex_match = re.compile(r"^\s*[0-9A-F]{4,}:(\s[0-9A-F]{2})+(\s+\/\/.*)?$") + self.type_match = re.compile(r".*(?PProcessor|Scope|Device|Method|Name) \((?P[^,\)]+).*") + + def _table_name_is_valid(self, table_name): + if table_name.startswith(".") or not table_name.lower().endswith(self.table_suffixes): + return False + if not table_name.lower().startswith(self.table_prefixes): + return False + return True + + def _table_signature(self, table_path, table_name = None): + path = os.path.join(table_path,table_name) if table_name else table_path + if not os.path.isfile(path): + return None + # Try to load it and read the first 4 bytes to verify the + # signature + with open(path,"rb") as f: + try: + sig = f.read(4) + if 2/3!=0: sig = sig.decode() + return sig + except: + pass + return None + + def table_is_valid(self, table_path, table_name = None): + return self._table_signature(table_path,table_name=table_name) in self.allowed_signatures + + def load(self, table_path): + # Attempt to load the passed file - or if a directory + # was passed, load all .aml and .dat files within + cwd = os.getcwd() + temp = None + target_files = {} + failed = [] + try: + if os.path.isdir(table_path): + # Got a directory - gather all files + # Gather valid files in the directory + valid_files = [x for x in os.listdir(table_path) if self.table_is_valid(table_path,x)] + elif os.path.isfile(table_path): + # Just loading the one table + valid_files = [table_path] + else: + # Not a valid path + raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), table_path) + if not valid_files: + # No valid files were found + raise FileNotFoundError( + errno.ENOENT, + os.strerror(errno.ENOENT), + "No valid .aml/.dat files found at {}".format(table_path) + ) + # Create a temp dir and copy all files there + temp = tempfile.mkdtemp() + for file in valid_files: + shutil.copy( + os.path.join(table_path,file), + temp + ) + # Build a list of all target files in the temp folder - and save + # the disassembled_name for each to verify after + list_dir = os.listdir(temp) + for x in list_dir: + if len(list_dir) > 1 and not self.table_is_valid(temp,x): + continue # Skip invalid files when multiple are passed + name_ext = [y for y in os.path.basename(x).split(".") if y] + if name_ext and name_ext[-1].lower() in ("asl","dsl"): + continue # Skip any already disassembled files + target_files[x] = { + "assembled_name": os.path.basename(x), + "disassembled_name": ".".join(x.split(".")[:-1]) + ".dsl", + } + if not target_files: + # Somehow we ended up with none? + raise FileNotFoundError( + errno.ENOENT, + os.strerror(errno.ENOENT), + "No valid .aml/.dat files found at {}".format(table_path) + ) + os.chdir(temp) + # Generate and run a command + dsdt_or_ssdt = [x for x in list(target_files) if self._table_signature(temp,x) in self.mixed_listing] + other_tables = [x for x in list(target_files) if not x in dsdt_or_ssdt] + out_d = ("","",0) + out_t = ("","",0) + + def exists(folder_path,file_name): + # Helper to make sure the file exists and has a non-Zero size + check_path = os.path.join(folder_path,file_name) + if os.path.isfile(check_path) and os.stat(check_path).st_size > 0: + return True + return False + + # Check our DSDT and SSDTs first + if dsdt_or_ssdt: + args = [self.iasl,"-da","-dl","-l"]+list(dsdt_or_ssdt) + out_d = self.r.run({"args":args}) + if out_d[2] != 0: + # Attempt to run without `-da` if the above failed + args = [self.iasl,"-dl","-l"]+list(dsdt_or_ssdt) + out_d = self.r.run({"args":args}) + # Get a list of disassembled names that failed + fail_temp = [] + for x in dsdt_or_ssdt: + if not exists(temp,target_files[x]["disassembled_name"]): + fail_temp.append(x) + # Let's try to disassemble any that failed individually + for x in fail_temp: + args = [self.iasl,"-dl","-l",x] + self.r.run({"args":args}) + if not exists(temp,target_files[x]["disassembled_name"]): + failed.append(x) + # Check for other tables (DMAR, APIC, etc) + if other_tables: + args = [self.iasl]+list(other_tables) + out_t = self.r.run({"args":args}) + # Get a list of disassembled names that failed + for x in other_tables: + if not exists(temp,target_files[x]["disassembled_name"]): + failed.append(x) + if len(failed) == len(target_files): + raise Exception("Failed to disassemble - {}".format(", ".join(failed))) + # Actually process the tables now + to_remove = [] + for file in target_files: + # We need to load the .aml and .dsl into memory + # and get the paths and scopes + if not exists(temp,target_files[file]["disassembled_name"]): + to_remove.append(file) + continue + with open(os.path.join(temp,target_files[file]["disassembled_name"]),"r") as f: + target_files[file]["table"] = f.read() + # Remove the compiler info at the start + if target_files[file]["table"].startswith("/*"): + target_files[file]["table"] = "*/".join(target_files[file]["table"].split("*/")[1:]).strip() + # Check for "Table Header:" or "Raw Table Data: Length" and strip everything + # after the last occurrence + for h in ("\nTable Header:","\nRaw Table Data: Length"): + if h in target_files[file]["table"]: + target_files[file]["table"] = h.join(target_files[file]["table"].split(h)[:-1]).rstrip() + break # Bail on the first match + target_files[file]["lines"] = target_files[file]["table"].split("\n") + target_files[file]["scopes"] = self.get_scopes(table=target_files[file]) + target_files[file]["paths"] = self.get_paths(table=target_files[file]) + with open(os.path.join(temp,file),"rb") as f: + table_bytes = f.read() + target_files[file]["raw"] = table_bytes + # Let's read the table header and get the info we need + # + # [0:4] = Table Signature + # [4:8] = Length (little endian) + # [8] = Compliance Revision + # [9] = Checksum + # [10:16] = OEM ID (6 chars, padded to the right with \x00) + # [16:24] = Table ID (8 chars, padded to the right with \x00) + # [24:28] = OEM Revision (little endian) + # + target_files[file]["signature"] = table_bytes[0:4] + target_files[file]["revision"] = table_bytes[8] + target_files[file]["oem"] = table_bytes[10:16].rstrip(b"\x00") + target_files[file]["id"] = table_bytes[16:24].rstrip(b"\x00") + target_files[file]["oem_revision"] = int(binascii.hexlify(table_bytes[24:28][::-1]),16) + # Cast as int on py2, and decode bytes to strings on py3 + if 2/3==0: + target_files[file]["revision"] = int(binascii.hexlify(target_files[file]["revision"]),16) + else: + for key in ("signature","oem","id"): + target_files[file][key] = target_files[file][key].decode() + # The disassembler omits the last line of hex data in a mixed listing + # file... convenient. However - we should be able to reconstruct this + # manually. + last_hex = next((l for l in target_files[file]["lines"][::-1] if self.is_hex(l)),None) + if last_hex: + # Get the address left of the colon + addr = int(last_hex.split(":")[0].strip(),16) + # Get the hex bytes right of the colon + hexs = last_hex.split(":")[1].split("//")[0].strip() + # Increment the address by the number of hex bytes + next_addr = addr+len(hexs.split()) + # Now we need to get the bytes at the end + hexb = self.get_hex_bytes(hexs.replace(" ","")) + # Get the last occurrence after the split + remaining = target_files[file]["raw"].split(hexb)[-1] + # Iterate in chunks of 16 + for chunk in [remaining[i:i+16] for i in range(0,len(remaining),16)]: + # Build a new byte string + hex_string = binascii.hexlify(chunk) + # Decode the bytes if we're on python 3 + if 2/3!=0: hex_string = hex_string.decode() + # Ensure the bytes are all upper case + hex_string = hex_string.upper() + l = " {}: {}".format( + hex(next_addr)[2:].upper().rjust(4,"0"), + " ".join([hex_string[i:i+2] for i in range(0,len(hex_string),2)]) + ) + # Increment our address + next_addr += len(chunk) + # Append our line + target_files[file]["lines"].append(l) + target_files[file]["table"] += "\n"+l + # Remove any that didn't disassemble + for file in to_remove: + target_files.pop(file,None) + except Exception as e: + print(e) + return ({},failed) + finally: + os.chdir(cwd) + if temp: shutil.rmtree(temp,ignore_errors=True) + # Add/update any tables we loaded + for table in target_files: + self.acpi_tables[table] = target_files[table] + # Only return the newly loaded results + return (target_files, failed,) + + def get_latest_iasl(self): + # Helper to scrape https://www.intel.com/content/www/us/en/developer/topic-technology/open/acpica/download.html for the latest + # download binaries link - then scrape the contents of that page for the actual download + try: + #source = self.dl.get_string(self.acpi_binary_tools, headers=self.h) + source = self.fetcher.fetch_and_parse_content(self.acpi_binary_tools) + for line in source.split("\n"): + # iASL Compiler and Windows ACPI Tools + if "windows-binary-tools" in line and ">iasl compiler and windows acpi tools" in line.lower(): + # Try to scrape and load the next page + try: + dl_page_url = "https://www.intel.com" + line.split(' {} failed: {}".format(f,new_name,e)) + print("Dump successful!") + if disassemble: + return self.load(res) + return res + else: + print("Failed to locate acpidump.exe") + return + elif sys.platform.startswith("linux"): + table_dir = "/sys/firmware/acpi/tables" + if not os.path.isdir(table_dir): + print("Could not locate {}!".format(table_dir)) + return + print("Copying tables to {}...".format(res)) + copied_files = [] + for table in os.listdir(table_dir): + if not os.path.isfile(os.path.join(table_dir,table)): + continue # We only want files + target_path = os.path.join(res,table.upper()+".aml") + out = self.r.run({"args":["sudo","cp",os.path.join(table_dir,table),target_path]}) + if out[2] != 0: + print(" - {}".format(out[1])) + return + out = self.r.run({"args":["sudo","chown",getpass.getuser(), target_path]}) + if out[2] != 0: + print(" - {}".format(out[1])) + return + print("Dump successful!") + if disassemble: + return self.load(res) + return res + + def check_output(self, output): + t_folder = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), output) + if not os.path.isdir(t_folder): + os.makedirs(t_folder) + return t_folder + + def get_hex_from_int(self, total, pad_to = 4): + hex_str = hex(total)[2:].upper().rjust(pad_to,"0") + return "".join([hex_str[i:i + 2] for i in range(0, len(hex_str), 2)][::-1]) + + def get_hex(self, line): + # strip the header and commented end + return line.split(":")[1].split("//")[0].replace(" ","") + + def get_line(self, line): + # Strip the header and commented end - no space replacing though + line = line.split("//")[0] + if ":" in line: + return line.split(":")[1] + return line + + def get_hex_bytes(self, line): + return binascii.unhexlify(line) + + def get_table_with_id(self, table_id): + return next((v for k,v in self.acpi_tables.items() if table_id == v.get("id")),None) + + def get_table_with_signature(self, table_sig): + return next((v for k,v in self.acpi_tables.items() if table_sig == v.get("signature")),None) + + def get_table(self, table_id_or_sig): + return next((v for k,v in self.acpi_tables.items() if table_id_or_sig in (v.get("signature"),v.get("id"))),None) + + def get_dsdt(self): + return self.get_table_with_signature("DSDT") + + def get_dsdt_or_only(self): + dsdt = self.get_dsdt() + if dsdt: return dsdt + # Make sure we have only one table + if len(self.acpi_tables) != 1: + return None + return list(self.acpi_tables.values())[0] + + def find_previous_hex(self, index=0, table=None): + if not table: table = self.get_dsdt_or_only() + if not table: return ("",-1,-1) + # Returns the index of the previous set of hex digits before the passed index + start_index = -1 + end_index = -1 + old_hex = True + for i,line in enumerate(table.get("lines","")[index::-1]): + if old_hex: + if not self.is_hex(line): + # Broke out of the old hex + old_hex = False + continue + # Not old_hex territory - check if we got new hex + if self.is_hex(line): # Checks for a :, but not in comments + end_index = index-i + hex_text,start_index = self.get_hex_ending_at(end_index,table=table) + return (hex_text, start_index, end_index) + return ("",start_index,end_index) + + def find_next_hex(self, index=0, table=None): + if not table: table = self.get_dsdt_or_only() + if not table: return ("",-1,-1) + # Returns the index of the next set of hex digits after the passed index + start_index = -1 + end_index = -1 + old_hex = True + for i,line in enumerate(table.get("lines","")[index:]): + if old_hex: + if not self.is_hex(line): + # Broke out of the old hex + old_hex = False + continue + # Not old_hex territory - check if we got new hex + if self.is_hex(line): # Checks for a :, but not in comments + start_index = i+index + hex_text,end_index = self.get_hex_starting_at(start_index,table=table) + return (hex_text, start_index, end_index) + return ("",start_index,end_index) + + def is_hex(self, line): + return self.hex_match.match(line) is not None + + def get_hex_starting_at(self, start_index, table=None): + if not table: table = self.get_dsdt_or_only() + if not table: return ("",-1) + # Returns a tuple of the hex, and the ending index + hex_text = "" + index = -1 + for i,x in enumerate(table.get("lines","")[start_index:]): + if not self.is_hex(x): + break + hex_text += self.get_hex(x) + index = i+start_index + return (hex_text, index) + + def get_hex_ending_at(self, start_index, table=None): + if not table: table = self.get_dsdt_or_only() + if not table: return ("",-1) + # Returns a tuple of the hex, and the ending index + hex_text = "" + index = -1 + for i,x in enumerate(table.get("lines","")[start_index::-1]): + if not self.is_hex(x): + break + hex_text = self.get_hex(x)+hex_text + index = start_index-i + return (hex_text, index) + + def get_shortest_unique_pad(self, current_hex, index, instance=0, table=None): + if not table: table = self.get_dsdt_or_only() + if not table: return None + try: left_pad = self.get_unique_pad(current_hex, index, False, instance, table=table) + except: left_pad = None + try: right_pad = self.get_unique_pad(current_hex, index, True, instance, table=table) + except: right_pad = None + try: mid_pad = self.get_unique_pad(current_hex, index, None, instance, table=table) + except: mid_pad = None + if left_pad == right_pad == mid_pad is None: raise Exception("No unique pad found!") + # We got at least one unique pad + min_pad = None + for x in (left_pad,right_pad,mid_pad): + if x is None: continue # Skip + if min_pad is None or len(x[0]+x[1]) < len(min_pad[0]+min_pad[1]): + min_pad = x + return min_pad + + def get_unique_pad(self, current_hex, index, direction=None, instance=0, table=None): + if not table: table = self.get_dsdt_or_only() + if not table: raise Exception("No valid table passed!") + # Returns any pad needed to make the passed patch unique + # direction can be True = forward, False = backward, None = both + start_index = index + line,last_index = self.get_hex_starting_at(index,table=table) + if not current_hex in line: + raise Exception("{} not found in table at index {}-{}!".format(current_hex,start_index,last_index)) + padl = padr = "" + parts = line.split(current_hex) + if instance >= len(parts)-1: + raise Exception("Instance out of range!") + linel = current_hex.join(parts[0:instance+1]) + liner = current_hex.join(parts[instance+1:]) + last_check = True # Default to forward + while True: + # Check if our hex string is unique + check_bytes = self.get_hex_bytes(padl+current_hex+padr) + if table["raw"].count(check_bytes) == 1: # Got it! + break + if direction == True or (direction is None and len(padr)<=len(padl)): + # Let's check a forward byte + if not len(liner): + # Need to grab more + liner, _index, last_index = self.find_next_hex(last_index, table=table) + if last_index == -1: raise Exception("Hit end of file before unique hex was found!") + padr = padr+liner[0:2] + liner = liner[2:] + continue + if direction == False or (direction is None and len(padl)<=len(padr)): + # Let's check a backward byte + if not len(linel): + # Need to grab more + linel, start_index, _index = self.find_previous_hex(start_index, table=table) + if _index == -1: raise Exception("Hit end of file before unique hex was found!") + padl = linel[-2:]+padl + linel = linel[:-2] + continue + break + return (padl,padr) + + def get_devices(self,search=None,types=("Device (","Scope ("),strip_comments=False,table=None): + if not table: table = self.get_dsdt_or_only() + if not table: return [] + # Returns a list of tuples organized as (Device/Scope,d_s_index,matched_index) + if search is None: + return [] + last_device = None + device_index = 0 + devices = [] + for index,line in enumerate(table.get("lines","")): + if self.is_hex(line): + continue + line = self.get_line(line) if strip_comments else line + if any ((x for x in types if x in line)): + # Got a last_device match + last_device = line + device_index = index + if search in line: + # Got a search hit - add it + devices.append((last_device,device_index,index)) + return devices + + def get_scope(self,starting_index=0,add_hex=False,strip_comments=False,table=None): + if not table: table = self.get_dsdt_or_only() + if not table: return [] + # Walks the scope starting at starting_index, and returns when + # we've exited + brackets = None + scope = [] + for line in table.get("lines","")[starting_index:]: + if self.is_hex(line): + if add_hex: + scope.append(line) + continue + line = self.get_line(line) if strip_comments else line + scope.append(line) + if brackets is None: + if line.count("{"): + brackets = line.count("{") + continue + brackets = brackets + line.count("{") - line.count("}") + if brackets <= 0: + # We've exited the scope + return scope + return scope + + def get_scopes(self, table=None): + if not table: table = self.get_dsdt_or_only() + if not table: return [] + scopes = [] + for index,line in enumerate(table.get("lines","")): + if self.is_hex(line): continue + if any(x in line for x in ("Processor (","Scope (","Device (","Method (","Name (")): + scopes.append((line,index)) + return scopes + + def get_paths(self, table=None): + if not table: table = self.get_dsdt_or_only() + if not table: return [] + # Set up lists for complete paths, as well + # as our current path reference + path_list = [] + _path = [] + brackets = 0 + for i,line in enumerate(table.get("lines",[])): + line = self.get_line(line) + if self.is_hex(line): + # Skip hex + continue + brackets += line.count("{")-line.count("}") + while len(_path): + # Remove any path entries that are nested + # equal to or further than our current set + if _path[-1][-1] >= brackets: + del _path[-1] + else: + break + type_match = self.type_match.match(line) + if type_match: + # Add our path entry and save the full path + # to the path list as needed + _path.append((type_match.group("name"),brackets)) + if type_match.group("type") == "Scope": + continue + # Ensure that we only consider non-Scope paths that aren't + # already fully qualified with a \ prefix + path = [] + for p in _path[::-1]: + path.append(p[0]) + if p[0] in ("_SB","_SB_","_PR","_PR_") or p[0].startswith(("\\","_SB.","_SB_.","_PR.","_PR_.")): + # Fully qualified - bail here + break + path = ".".join(path[::-1]).split(".") + # Properly qualify the path + if len(path) and path[0] == "\\": path.pop(0) + if any("^" in x for x in path): # Accommodate caret notation + new_path = [] + for x in path: + if x.count("^"): + # Remove the last Y paths to account for going up a level + del new_path[-1*x.count("^"):] + new_path.append(x.replace("^","")) # Add the original, removing any ^ chars + path = new_path + if not path: + continue + path_str = ".".join(path) + path_str = "\\"+path_str if path_str[0] != "\\" else path_str + path_list.append((path_str,i,type_match.group("type"))) + return sorted(path_list) + + def get_path_of_type(self, obj_type="Device", obj="HPET", table=None): + if not table: table = self.get_dsdt_or_only() + if not table: return [] + paths = [] + for path in table.get("paths",[]): + if path[2].lower() == obj_type.lower() and path[0].upper().endswith(obj.upper()): + paths.append(path) + return sorted(paths) + + def get_device_paths(self, obj="HPET",table=None): + return self.get_path_of_type(obj_type="Device",obj=obj,table=table) + + def get_method_paths(self, obj="_STA",table=None): + return self.get_path_of_type(obj_type="Method",obj=obj,table=table) + + def get_name_paths(self, obj="CPU0",table=None): + return self.get_path_of_type(obj_type="Name",obj=obj,table=table) + + def get_processor_paths(self, obj_type="Processor",table=None): + return self.get_path_of_type(obj_type=obj_type,obj="",table=table) + + def get_device_paths_with_hid(self, hid="ACPI000E", table=None): + if not table: table = self.get_dsdt_or_only() + if not table: return [] + starting_indexes = [] + for index,line in enumerate(table.get("lines","")): + if self.is_hex(line): continue + if hid.upper() in line.upper(): + starting_indexes.append(index) + if not starting_indexes: return starting_indexes + devices = [] + for i in starting_indexes: + # Walk backwards and get the next parent device + pad = len(table.get("lines","")[i]) - len(table.get("lines","")[i].lstrip(" ")) + for sub,line in enumerate(table.get("lines","")[i::-1]): + if "Device (" in line and len(line)-len(line.lstrip(" ")) < pad: + # Add it if it's already in our dsdt_paths - if not, add the current line + device = next((x for x in table.get("paths",[]) if x[1]==i-sub),None) + if device: devices.append(device) + else: devices.append((line,i-sub)) + break + return devices \ No newline at end of file diff --git a/Scripts/efi_builder.py b/Scripts/efi_builder.py new file mode 100755 index 0000000..f504848 --- /dev/null +++ b/Scripts/efi_builder.py @@ -0,0 +1,505 @@ +from Scripts.datasets import cpu_data +from Scripts import acpi_guru +from Scripts import config_prodigy +from Scripts import kext_maestro +from Scripts import utils +import os +import shutil +import re + +class builder: + def __init__(self): + self.acpi = acpi_guru.ACPIGuru() + self.config = config_prodigy.ConfigProdigy() + self.kext = kext_maestro.KextMaestro() + self.utils = utils.Utils() + self.ock_files_dir = os.path.join(os.getcwd(), "OCK_Files") + self.oc_binary_data_dir = os.path.join(os.getcwd(), "OcBinaryData") + self.result_dir = os.path.join(os.getcwd(), "Results") + self.intel_igpu_properties = { + "Ice Lake": { + "Laptop": { + "AAPL,ig-platform-id": "0000528A", + "framebuffer-fbmem": "00009000", + "framebuffer-stolenmem": "00003001" + } + }, + "Comet Lake": { + "Desktop": { + "AAPL,ig-platform-idEx": "0300C89B", + "AAPL,ig-platform-id": "07009B3E", + "framebuffer-fbmem": "00009000", + "framebuffer-stolenmem": "00003001" + }, + "NUC": { + "AAPL,ig-platform-id": "07009B3E", + "device-id": "9B3E0000", + "framebuffer-fbmem": "00009000", + "framebuffer-stolenmem": "00003001" + }, + "Laptop": { + "AAPL,ig-platform-id": "00009B3E", + "device-id": "9B3E0000", + "framebuffer-fbmem": "00009000", + "framebuffer-stolenmem": "00003001" + } + }, + "Coffee Lake": { + "Desktop": { + "AAPL,ig-platform-idEx": "0300913E", + "AAPL,ig-platform-id": "07009B3E" + }, + "NUC": { + "AAPL,ig-platform-id": "07009B3E", + "device-id": "9B3E0000", + "framebuffer-fbmem": "00009000", + "framebuffer-stolenmem": "00003001" + }, + "Laptop": { + "AAPL,ig-platform-id": "0900A53E", + "device-id": "9B3E0000", + "framebuffer-fbmem": "00009000", + "framebuffer-stolenmem": "00003001" + } + }, + "Whiskey Lake": { + "NUC": { + "AAPL,ig-platform-id": "07009B3E", + "device-id": "9B3E0000", + "framebuffer-fbmem": "00009000", + "framebuffer-stolenmem": "00003001" + }, + "Laptop": { + "AAPL,ig-platform-id": "0900A53E", + "device-id": "9B3E0000", + "framebuffer-fbmem": "00009000", + "framebuffer-stolenmem": "00003001" + } + }, + "Amber Lake": { + "Laptop": { + "AAPL,ig-platform-id": "0000C087", + "framebuffer-fbmem": "00009000", + "framebuffer-stolenmem": "00003001" + } + }, + "Kaby Lake": { + "Desktop": { + "AAPL,ig-platform-idEx": "03001259", + "AAPL,ig-platform-id": "00001259", + "device-id": "12590000" + }, + "NUC": { + "AAPL,ig-platform-id": "00001659", + "device-id": "16590000", + "framebuffer-fbmem": "00009000", + "framebuffer-stolenmem": "00003001" + }, + "Laptop": { + "AAPL,ig-platform-id": "00001B59", + "device-id": "1B590000", + "framebuffer-con1-alldata": "01050A00 00080000 87010000 02040A00 00080000 87010000 FF000000 01000000 20000000", + "framebuffer-con1-enable": "01000000", + "#framebuffer-con2-alldata": "01050A00 00080000 87010000 03060A00 00040000 87010000 FF000000 01000000 20000000", + "#framebuffer-con2-enable": "01000000", + "framebuffer-fbmem": "00009000", + "framebuffer-stolenmem": "00003001" + } + }, + "Skylake": { + "Desktop": { + "AAPL,ig-platform-idEx": "01001219", + "AAPL,ig-platform-id": "00001219" + }, + "NUC": { + "AAPL,ig-platform-id": "05003B19", + "framebuffer-fbmem": "00009000", + "framebuffer-stolenmem": "00003001" + }, + "Laptop": { + "AAPL,ig-platform-id": "00001619", + "framebuffer-fbmem": "00009000", + "framebuffer-stolenmem": "00003001" + } + }, + "Broadwell": { + "Desktop": { + "AAPL,ig-platform-idEx": "07002216", + "AAPL,ig-platform-id": "07002216" + }, + "NUC": { + "AAPL,ig-platform-id": "02001616", + "framebuffer-fbmem": "00009000", + "framebuffer-stolenmem": "00003001" + }, + "Laptop": { + "AAPL,ig-platform-id": "06002616", + "framebuffer-fbmem": "00009000", + "framebuffer-stolenmem": "00003001" + } + }, + "Haswell": { + "Desktop": { + "AAPL,ig-platform-idEx": "04001204", + "AAPL,ig-platform-id": "0300220D" + }, + "NUC": { + "AAPL,ig-platform-id": "0300220D", + "device-id": "12040000", + "framebuffer-cursormem": "00009000" + }, + "Laptop": { + "AAPL,ig-platform-id": "0600260A", + "device-id": "12040000", + "framebuffer-cursormem": "00009000" + } + }, + "Ivy Bridge": { + "Desktop": { + "AAPL,ig-platform-idEx": "07006201", + "AAPL,ig-platform-id": "0A006601" + }, + "Laptop": { + "AAPL,ig-platform-id": "03006601" + } + }, + "Sandy Bridge": { + "Desktop": { + "AAPL,snb-platform-idEx": "00000500", + "AAPL,snb-platform-id": "10000300", + "device-id": "26010000" + }, + "Laptop": { + "AAPL,snb-platform-id": "00000100" + } + } + } + + def is_low_end_intel_cpu(self, processor_name): + return any(cpu_branding in processor_name for cpu_branding in ["Celeron", "Pentium"]) + + def check_igpu_compatibility(self, cpu_codename, macos_version): + return not (("Sandy Bridge" in cpu_codename and macos_version > 17) or ("Ivy Bridge" in cpu_codename and macos_version > 20) or (("Haswell" in cpu_codename or "Broadwell" in cpu_codename) and macos_version > 21) or (("Skylake" in cpu_codename or "Kaby Lake" in cpu_codename) and macos_version > 22) or (("Amber Lake" in cpu_codename or "Whiskey Lake" in cpu_codename) and macos_version == 17) or ("Ice Lake" in cpu_codename and 19 > macos_version)) + + def igpu_properties(self, platform, processor_name, gpu_codename, discrete_gpu, integrated_gpu_manufacturer, integrated_gpu_name, macos_version): + if "Skylake".lower() in gpu_codename.lower() and macos_version > 21: + gpu_codename = "Kaby Lake" + if "Kaby Lake-R".upper() in gpu_codename.upper() and macos_version > 22: + gpu_codename = "Coffee Lake" + + gpu_codename = self.utils.contains_any(cpu_data.IntelCPUGenerations, gpu_codename) + if not "Intel" in integrated_gpu_manufacturer or not integrated_gpu_name or self.is_low_end_intel_cpu(processor_name) or not self.check_igpu_compatibility(gpu_codename, macos_version) or not self.intel_igpu_properties.get(gpu_codename, True): + return {} + + igpu_properties = self.intel_igpu_properties[gpu_codename][platform] + + if "Desktop" in platform: + if discrete_gpu: + if "Sandy Bridge" in gpu_codename: + return { + "AAPL,snb-platform-id": igpu_properties["AAPL,snb-platform-idEx"], + "device-id": "02010000", + } + else: + return { + "AAPL,ig-platform-id": igpu_properties["AAPL,ig-platform-idEx"] + } + del igpu_properties["AAPL,ig-platform-idEx"] + if "Haswell" in gpu_codename and not "440" in integrated_gpu_name: + igpu_properties["device-id"] = "12040000" + elif "Skylake" in gpu_codename and "P530" in integrated_gpu_name: + igpu_properties["device-id"] = "12040000" + else: + if "Haswell" in gpu_codename and "5" in integrated_gpu_name: + igpu_properties["AAPL,ig-platform-id"] = "0500260A" + del igpu_properties["device-id"] + elif "Broadwell" in gpu_codename and "56" in integrated_gpu_name: + igpu_properties["device-id"] = "26160000" + elif "Skylake" in gpu_codename: + if "NUC" in platform: + if "51" in integrated_gpu_name: + igpu_properties["AAPL,ig-platform-id"] = "00001E19" + elif "52" in integrated_gpu_name or "53" in integrated_gpu_name: + igpu_properties["AAPL,ig-platform-id"] = "02001619" + elif "54" in integrated_gpu_name or "55" in integrated_gpu_name: + igpu_properties["AAPL,ig-platform-id"] = "02002619" + + if "510" in integrated_gpu_name: + igpu_properties["AAPL,ig-platform-id"] = "00001B19" + igpu_properties["device-id"] = "02190000" + elif "550" in integrated_gpu_name or "P530" in integrated_gpu_name: + igpu_properties["device-id"] = "16190000" + elif "Kaby Lake" in gpu_codename: + if "NUC" in platform: + if "15" in integrated_gpu_name: + igpu_properties["AAPL,ig-platform-id"] = "00001E59" + elif "63" in integrated_gpu_name: + igpu_properties["AAPL,ig-platform-id"] = "00001B59" + elif "40" in integrated_gpu_name or "65" in integrated_gpu_name: + igpu_properties["AAPL,ig-platform-id"] = "02002659" + else: + if "UHD" in integrated_gpu_name: + igpu_properties["AAPL,ig-platform-id"] = "0000C087" + igpu_properties["device-id"] = "16590000" + elif self.utils.contains_any(cpu_data.IntelCPUGenerations, gpu_codename, start=8, end=11): + if "NUC" in platform: + if "55" in integrated_gpu_name: + igpu_properties["AAPL,ig-platform-id"] = "0000A53E" + del igpu_properties["device-id"] + else: + if "3" in integrated_gpu_name: + igpu_properties["AAPL,ig-platform-id"] = "0900A53E" + + igpu_properties["hda-gfx"] = "onboard-1" + igpu_properties["framebuffer-patch-enable"] = "01000000" + return igpu_properties + + def system_product_info(self, platform, cpu_manufacturer, processor_name, cpu_codename, cpu_cores, discrete_gpu, igpu_props, macos_version): + product_name = "iMacPro1,1" if self.utils.contains_any(cpu_data.IntelCPUGenerations, cpu_codename, start=12) else "MacPro7,1" + + if "AMD" in cpu_manufacturer: + product_name = "MacBookPro16,3" if "Laptop" in platform else "iMacPro1,1" + + if igpu_props: + if "Kaby Lake-R".lower() in cpu_codename.lower() and macos_version > 22: + cpu_codename = "Coffee Lake" + + if "Sandy Bridge" in cpu_codename: + if "Desktop" in platform: + if macos_version < 18: + product_name = "iMac12,2" + else: + product_name = "MacPro6,1" + elif "NUC" in platform: + product_name = "Macmini5,1" if int(cpu_cores) < 4 else "Macmini5,3" + else: + product_name = "MacBookPro8,1" if int(cpu_cores) < 4 else "MacBookPro8,2" + elif "Ivy Bridge" in cpu_codename: + if macos_version == 20: + if "Desktop" in platform: + product_name = "iMac14,4" if not discrete_gpu else "iMac15,1" + elif "NUC" in platform: + product_name = "Macmini7,1" + else: + product_name = "MacBookPro11,1" if int(cpu_cores) < 4 else "MacBookPro11,5" + elif macos_version < 20: + if "Desktop" in platform: + product_name = "iMac13,1" if not discrete_gpu else "iMac13,2" + elif "NUC" in platform: + product_name = "Macmini6,1" if int(cpu_cores) < 4 else "Macmini6,2" + else: + product_name = "MacBookPro10,2" if int(cpu_cores) < 4 else "MacBookPro10,1" + else: + product_name = "MacPro6,1" + elif "Haswell" in cpu_codename: + if "Desktop" in platform: + product_name = "iMac14,4" if not discrete_gpu else "iMac15,1" + if macos_version == 21: + product_name = "iMac16,2" if not discrete_gpu else "iMac17,1" + elif "NUC" in platform: + product_name = "Macmini7,1" + else: + product_name = "MacBookPro11,1" if macos_version < 21 and int(cpu_cores) < 4 else "MacBookPro11,5" + elif "Broadwell" in cpu_codename: + if "Desktop" in platform: + product_name = "iMac16,2" if not discrete_gpu else "iMac17,1" + elif "NUC" in platform: + product_name = "iMac16,1" + else: + product_name = "MacBookPro12,1" if int(cpu_cores) < 4 else "MacBookPro11,5" + elif "Skylake" in cpu_codename: + product_name = "iMac17,1" + if "Laptop" in platform: + product_name = "MacBookPro13,1" if int(cpu_cores) < 4 else "MacBookPro13,3" + elif self.utils.contains_any(cpu_data.IntelCPUGenerations, cpu_codename, start=8, end=11): + product_name = "Macmini8,1" + if "Desktop" in platform: + product_name = "iMac18,3" if macos_version == 17 else "iMac19,1" + if "Comet Lake" in cpu_codename: + product_name = "iMac20,1" if int(cpu_cores) < 10 else "iMac20,2" + elif "Laptop" in platform: + if "-8" in processor_name: + product_name = "MacBookPro15,2" if int(cpu_cores) < 6 else "MacBookPro15,3" + else: + product_name = "MacBookPro16,3" if int(cpu_cores) < 6 else "MacBookPro16,1" + elif "Kaby Lake" in cpu_codename: + product_name = "iMac18,1" if not discrete_gpu else "iMac18,3" + if "Laptop" in platform: + product_name = "MacBookPro14,1" if int(cpu_cores) < 4 else "MacBookPro14,3" + elif "Amber Lake" in cpu_codename: + product_name = "MacBookAir8,1" + elif "Ice Lake" in cpu_codename: + product_name = "MacBookAir9,1" if int(cpu_cores) < 4 else "MacBookPro16,2" + + return product_name + + def clean_up(self, config, efi_directory): + files_to_remove = [] + + drivers_directory = os.path.join(efi_directory, "EFI", "OC", "Drivers") + driver_list = self.utils.recursively_search(drivers_directory, ".efi") + driver_loaded = [kext.get("Path") for kext in config.get("UEFI").get("Drivers")] + for driver_path in driver_list: + if not driver_path in driver_loaded: + files_to_remove.append(os.path.join(drivers_directory, driver_path)) + + kexts_directory = os.path.join(efi_directory, "EFI", "OC", "Kexts") + kext_list = self.utils.recursively_search(kexts_directory, ".kext") + kext_loaded = [kext.get("BundlePath") for kext in config.get("Kernel").get("Add")] + for kext_path in kext_list: + if not kext_path in kext_loaded: + files_to_remove.append(os.path.join(kexts_directory, kext_path)) + + tools_directory = os.path.join(efi_directory, "EFI", "OC", "Tools") + tool_list = self.utils.recursively_search(tools_directory, ".efi") + tool_loaded = [tool.get("Path") for tool in config.get("Misc").get("Tools")] + for tool_path in tool_list: + if not tool_path in tool_loaded: + files_to_remove.append(os.path.join(tools_directory, tool_path)) + + for path in files_to_remove: + try: + if os.path.isdir(path): + shutil.rmtree(path) + else: + os.remove(path) + except Exception as e: + print(f"Failed to remove file: {e}") + continue + + def build_efi(self, hardware, macos_version): + efi_directory = os.path.join(os.getcwd(), "Results") + + self.utils.mkdirs(efi_directory) + + if not os.path.exists(self.ock_files_dir): + raise Exception(f"Directory '{self.ock_files_dir}' does not exist.") + + source_efi_dir = os.path.join(self.ock_files_dir, "OpenCore") + shutil.copytree(source_efi_dir, efi_directory, dirs_exist_ok=True) + shutil.copytree(self.oc_binary_data_dir, os.path.join(efi_directory, "EFI", "OC"), dirs_exist_ok=True) + + hardware_shorc = {} + hardware_shorc["Motherboard Name"] = hardware["Motherboard"].get("Motherboard Name").upper() + hardware_shorc["Motherboard Chipset"] = hardware["Motherboard"].get("Motherboard Chipset").upper() + hardware_shorc["Platform"] = hardware["Motherboard"].get("Platform") + hardware_shorc["CPU Configuration"] = hardware["Motherboard"].get("CPU Configuration") + hardware_shorc["CPU Manufacturer"] = hardware["CPU"].get("CPU Manufacturer") + hardware_shorc["Processor Name"] = hardware["CPU"].get("Processor Name") + hardware_shorc["CPU Cores"] = hardware["CPU"].get("CPU Cores") + hardware_shorc["CPU Codename"] = hardware["CPU"].get("CPU Codename") + hardware_shorc["Integrated GPU"] = list(hardware.get("GPU").items())[-1][1] if "Integrated GPU" in list(hardware.get("GPU").items())[-1][1]["Device Type"] else {} + hardware_shorc["Integrated GPU Manufacturer"] = hardware_shorc["Integrated GPU"]["Manufacturer"] if hardware_shorc["Integrated GPU"] else "" + hardware_shorc["Integrated GPU Name"] = list(hardware.get("GPU").keys())[-1] if hardware_shorc["Integrated GPU"] else "" + hardware_shorc["Integrated GPU Codename"] = hardware_shorc["Integrated GPU"]["GPU Codename"] if hardware_shorc["Integrated GPU"] else "" + hardware_shorc["Discrete GPU"] = list(hardware.get("GPU").items())[0][1] if "Discrete GPU" in list(hardware.get("GPU").items())[0][1]["Device Type"] else {} + hardware_shorc["Discrete GPU Manufacturer"] = hardware_shorc["Discrete GPU"]["Manufacturer"] if hardware_shorc["Discrete GPU"] else "" + hardware_shorc["Discrete GPU Codename"] = hardware_shorc["Discrete GPU"]["GPU Codename"] if hardware_shorc["Discrete GPU"] else "" + hardware_shorc["Ethernet (PCI)"] = [] + for network_name, network_props in hardware["Network"].items(): + connection_name = network_props["Connection Name"] + bus_type = network_props["Bus Type"] + + if bus_type.startswith("PCI"): + if connection_name.startswith("WiFi"): + hardware_shorc["Wi-Fi (PCI)"] = network_props.get("Device ID") + elif connection_name.startswith("Ethernet"): + hardware_shorc["Ethernet (PCI)"].append(network_props.get("Device ID")) + hardware_shorc["Bluetooth"] = [device_props.get("Device ID") for device_name, device_props in hardware.get("Bluetooth", {}).items()] + hardware_shorc["Codec ID"] = next((device_props.get("Codec ID") for device_name, device_props in hardware.get("Audio").items()), None) + hardware_shorc["SD Controller"] = hardware.get("SD Controller") + hardware_shorc["Input"] = hardware.get("Input") + hardware_shorc["Storage Controllers"] = hardware.get("Storage").get("Storage Controllers") + hardware_shorc["USB Controllers"] = [controller_props.get("Device ID") for controller_name, controller_props in hardware.get("USB").get("USB Controllers").items()] + hardware_shorc["Intel MEI"] = hardware.get("Intel MEI") + hardware_shorc["Unsupported Devices"] = hardware.get("Compatibility").get("Unsupported Devices") + + forbidden_chars = r'[<>:"/\\|?*]' + hardware_shorc["Motherboard Name"] = re.sub(forbidden_chars, '_', hardware_shorc["Motherboard Name"]) + + efi_option = {} + efi_option["macOS Version"] = macos_version + efi_option["Custom CPU Name"] = not (" Core" in hardware_shorc.get("Processor Name") and self.utils.contains_any(cpu_data.IntelCPUGenerations, hardware_shorc.get("CPU Codename"), end=12)) + efi_option["Synchronize the TSC"] = "Laptop" in hardware_shorc["Platform"] and "ASUS" in hardware_shorc["Motherboard Name"] or "AMD" in hardware_shorc["Integrated GPU Manufacturer"] + efi_option["iGPU Properties"] = self.igpu_properties( + hardware_shorc["Platform"], + hardware_shorc.get("Processor Name"), + hardware_shorc.get("Integrated GPU Codename"), + hardware_shorc["Discrete GPU"], + hardware_shorc["Integrated GPU Manufacturer"], + hardware_shorc["Integrated GPU Name"], + efi_option.get("macOS Version")) + efi_option["SMBIOS"] = self.system_product_info( + hardware_shorc["Platform"], + hardware_shorc["CPU Manufacturer"], + hardware_shorc.get("Processor Name"), + hardware_shorc["CPU Codename"], + hardware_shorc["CPU Cores"], + hardware_shorc["Discrete GPU"], + efi_option["iGPU Properties"], + efi_option.get("macOS Version")) + + input_devices = ", ".join(list(hardware_shorc.get("Input", {}).keys())) + hardware_shorc["Touchpad Communication"] = "None" if not "Laptop" in hardware_shorc.get("Platform") else "I2C" if "I2C" in input_devices else "PS2" if "PS2" in input_devices else "None" + efi_option["ACPI"] = self.acpi.initialize_patches( + hardware_shorc["Motherboard Name"], + hardware_shorc["Motherboard Chipset"], + hardware_shorc["Platform"], + hardware_shorc["CPU Manufacturer"], + hardware_shorc["CPU Codename"], + hardware_shorc["Integrated GPU"], + hardware_shorc["Ethernet (PCI)"], + hardware_shorc["Touchpad Communication"], + efi_option.get("SMBIOS"), + hardware_shorc.get("Intel MEI"), + hardware_shorc["Unsupported Devices"], + efi_option.get("macOS Version"), + os.path.join(efi_directory, "EFI", "OC", "ACPI") + ) + + kexts = self.kext.gathering_kexts( + hardware_shorc["Motherboard Name"], + hardware_shorc["Platform"], + hardware_shorc["CPU Configuration"], + hardware_shorc["CPU Manufacturer"], + hardware_shorc["CPU Codename"], + hardware_shorc["Discrete GPU Codename"], + hardware_shorc["Integrated GPU"], + hardware_shorc.get("Wi-Fi (PCI)"), + hardware_shorc["Ethernet (PCI)"], + hardware_shorc.get("Bluetooth"), + hardware_shorc.get("Codec ID"), + hardware_shorc["Input"], + hardware_shorc.get("SD Controller"), + hardware_shorc.get("Storage Controllers"), + hardware_shorc["USB Controllers"], + efi_option.get("SMBIOS"), + efi_option.get("Custom CPU Name"), + efi_option.get("Synchronize the TSC"), + efi_option.get("ACPI").get("Battery Status Patch Needed"), + efi_option.get("macOS Version") + ) + + kexts_directory = os.path.join(efi_directory, "EFI", "OC", "Kexts") + self.kext.install_kexts_to_efi(kexts, efi_option.get("macOS Version"), kexts_directory) + efi_option["Kernel_Add"] = self.kext.load_kexts( + kexts, + hardware_shorc["Motherboard Name"], + hardware_shorc["Platform"], + hardware_shorc["CPU Manufacturer"], + hardware_shorc["Discrete GPU Codename"], + efi_option["macOS Version"] + ) + + config_file = os.path.join(efi_directory, "EFI", "OC", "config.plist") + config_data = self.utils.read_file(config_file) + + if not config_data: + raise Exception(f"Error: The file {config_file} does not exist.") + + self.config.genarate(hardware_shorc, efi_option, config_data) + self.utils.write_file(config_file, config_data) + + self.clean_up(config_data, efi_directory) + hardware_file = os.path.join(efi_directory, hardware_shorc.get("Motherboard Name") + ".json") + self.utils.write_file(hardware_file, hardware) \ No newline at end of file diff --git a/Scripts/gathering_files.py b/Scripts/gathering_files.py new file mode 100755 index 0000000..5f2e540 --- /dev/null +++ b/Scripts/gathering_files.py @@ -0,0 +1,317 @@ +from Scripts import github +from Scripts import resource_fetcher +from Scripts import utils +import os +import tempfile +import shutil +import subprocess +from datetime import datetime, timedelta + +class gatheringFiles: + def __init__(self): + self.utils = utils.Utils() + self.github = github.Github() + self.fetcher = resource_fetcher.ResourceFetcher(self.github.headers) + self.dortania_builds_url = "https://raw.githubusercontent.com/dortania/build-repo/builds/latest.json" + self.amd_vanilla_patches_url = f"https://raw.githubusercontent.com/AMD-OSX/AMD_Vanilla/beta/patches.plist" + self.temporary_dir = tempfile.mkdtemp() + self.ock_files_dir = os.path.join(os.getcwd(), "OCK_Files") + self.download_history_file = os.path.join(self.ock_files_dir, "history.json") + self.builds = [ + "AirportBrcmFixup", + "AppleALC", + "BrcmPatchRAM", + "BrightnessKeys", + "CryptexFixup", + "ECEnabler", + "HibernationFixup", + "IntelBluetoothFirmware", + "IntelMausi", + "Lilu", + "NVMeFix", + "RTCMemoryFixup", + "RealtekRTL8111", + "RestrictEvents", + "VirtualSMC", + "VoodooI2C", + "VoodooInput", + "VoodooPS2", + "VoodooSMBus", + "WhateverGreen" + ] + self.releases = [ + { + "owner": "blankmac", + "repo": "AlpsHID" + }, + { + "owner": "SongXiaoXi", + "repo": "AppleIGC" + }, + { + "owner": "hieplpvip", + "repo": "AsusSMC" + }, + { + "owner": "Xiashangning", + "repo": "BigSurface" + }, + { + "owner": "b00t0x", + "repo": "CpuTopologyRebuild" + }, + { + "owner": "0xFireWolf", + "repo": "RealtekCardReader" + }, + { + "owner": "0xFireWolf", + "repo": "RealtekCardReaderFriend" + }, + { + "owner": "VoodooSMBus", + "repo": "VoodooRMI" + }, + { + "owner": "OpenIntelWireless", + "repo": "itlwm" + }, + { + "owner": "ChefKissInc", + "repo": "NootRX" + }, + { + "owner": "ChefKissInc", + "repo": "NootedRed" + }, + { + "owner": "ChefKissInc", + "repo": "ForgedInvariant" + }, + { + "owner": "wjz304", + "repo": "OpenCore_Patch_Build" + } + ][-5:] + self.actions = [] + + def get_bootloader_kexts_data(self): + results = [ + { + "product_name": "AlpsHID", + "id": 69228327, + "url": "https://github.com/blankmac/AlpsHID/releases/download/v1.2/AlpsHID1.2_release.zip" + }, + { + "product_name": "AMFIPass", + "id": 826491527, + "url": "https://github.com/dortania/OpenCore-Legacy-Patcher/raw/76516394fddb7ce4526ccbcc5b806795c30e9a89/payloads/Kexts/Acidanthera/AMFIPass-v1.4.1-RELEASE.zip" + }, + { + "product_name": "AppleIGC", + "id": 138279923, + "url": "https://github.com/SongXiaoXi/AppleIGC/releases/download/v1.5/AppleIGC.kext.zip" + }, + { + "product_name": "AppleMCEReporterDisabler", + "id": 738162736, + "url": "https://github.com/acidanthera/bugtracker/files/3703498/AppleMCEReporterDisabler.kext.zip" + }, + { + "product_name": "AsusSMC", + "id": 41898282, + "url": "https://github.com/hieplpvip/AsusSMC/releases/download/1.4.1/AsusSMC-1.4.1-RELEASE.zip" + }, + { + "product_name": "AtherosE2200Ethernet", + "id": 9746382, + "url": "https://github.com/Mieze/AtherosE2200Ethernet/releases/download/2.2.2/AtherosE2200Ethernet-V2.2.2.zip" + }, + { + "product_name": "BigSurface", + "id": 18528518, + "url": "https://github.com/Xiashangning/BigSurface/releases/download/v6.5/BigSurface.zip" + }, + { + "product_name": "CtlnaAHCIPort", + "id": 10460478, + "url": "https://github.com/lzhoang2801/lzhoang2801.github.io/raw/main/public/extra-files/CtlnaAHCIPort-v3.4.1.zip" + }, + { + "product_name": "CpuTopologyRebuild", + "id": 13190749, + "url": "https://github.com/b00t0x/CpuTopologyRebuild/releases/download/1.1.0/CpuTopologyRebuild-1.1.0-RELEASE.zip" + }, + { + "product_name": "IO80211FamilyLegacy", + "id": 817294638, + "url": "https://github.com/dortania/OpenCore-Legacy-Patcher/raw/main/payloads/Kexts/Wifi/IO80211FamilyLegacy-v1.0.0.zip" + }, + { + "product_name": "IOSkywalkFamily", + "id": 926384761, + "url": "https://github.com/dortania/OpenCore-Legacy-Patcher/raw/main/payloads/Kexts/Wifi/IOSkywalkFamily-v1.1.0.zip" + }, + { + "product_name": "LucyRTL8125Ethernet", + "id": 159470181, + "url": "https://github.com/Mieze/LucyRTL8125Ethernet/releases/download/v1.2.0d5/LucyRTL8125Ethernet-V1.2.0d5.zip" + }, + { + "product_name": "NullEthernet", + "id": 182736492, + "url": "https://bitbucket.org/RehabMan/os-x-null-ethernet/downloads/RehabMan-NullEthernet-2016-1220.zip" + }, + { + "product_name": "VoodooRMI", + "id": 13190749, + "url": "https://github.com/VoodooSMBus/VoodooRMI/releases/download/1.3.5/VoodooRMI-1.3.5-Release.zip" + }, + { + "product_name": "RealtekRTL8100", + "id": 10460478, + "url": "https://github.com/lzhoang2801/lzhoang2801.github.io/raw/main/public/extra-files/RealtekRTL8100-v2.0.1.zip" + }, + { + "product_name": "RealtekCardReader", + "id": 10460478, + "url": "https://github.com/0xFireWolf/RealtekCardReader/releases/download/v0.9.7/RealtekCardReader_0.9.7_006a845_RELEASE.zip" + }, + { + "product_name": "RealtekCardReaderFriend", + "id": 10460478, + "url": "https://github.com/0xFireWolf/RealtekCardReaderFriend/releases/download/v1.0.4/RealtekCardReaderFriend_1.0.4_e1e3301_RELEASE.zip" + }, + { + "product_name": "GenericUSBXHCI", + "id": 120325166, + "url": "https://github.com/RattletraPM/GUX-RyzenXHCIFix/releases/download/v1.3.0b1-ryzenxhcifix/GenericUSBXHCI.kext.zip" + }, + { + "product_name": "XHCI-unsupported", + "id": 185465401, + "url": "https://github.com/daliansky/OS-X-USB-Inject-All/releases/download/v0.8.0/XHCI-unsupported.kext.zip" + } + ] + + dortania_builds_data = self.fetcher.fetch_and_parse_content(self.dortania_builds_url, "json") + + for product_name, product_data in dortania_builds_data.items(): + if product_name in self.builds: + results.append({ + "product_name": product_name, + "id": product_data["versions"][0]["release"]["id"], + "url": product_data["versions"][0]["links"]["release"] + }) + + for product in self.releases: + results.extend(self.github.get_latest_release(product["owner"], product["repo"])) + # [self.github.get_latest_artifact_id(product["owner"], product["repo"]) for product in self.actions] + + sorted_results = sorted(results, key=lambda x:x["product_name"]) + + return sorted_results + + def product_index_in_history(self, product_name, versions): + for index, item in enumerate(versions): + if product_name in item["product_name"]: + return index + return None + + def move_bootloader_kexts_to_product_directory(self, product_name): + product_directory = os.path.join(self.ock_files_dir, product_name) + + if not os.path.exists(self.temporary_dir): + raise FileNotFoundError(f"The directory {self.temporary_dir} does not exist.") + + if not "OpenCore" in product_name: + kext_paths = self.utils.recursively_search(self.temporary_dir, ".kext") + for kext_path in kext_paths: + source_kext_path = os.path.join(self.temporary_dir, kext_path) + destination_kext_path = os.path.join(product_directory, os.path.basename(kext_path)) + + if "Contents" in kext_path or "Debug".lower() in kext_path.lower(): + continue + + shutil.move(source_kext_path, destination_kext_path) + else: + source_bootloader_path = os.path.join(self.temporary_dir, product_name, "X64", "EFI") + if os.path.exists(source_bootloader_path): + destination_efi_path = os.path.join(product_directory, os.path.basename(source_bootloader_path)) + shutil.move(source_bootloader_path, destination_efi_path) + source_config_path = os.path.join(os.path.dirname(os.path.dirname(source_bootloader_path)), "Docs", "Sample.plist") + destination_config_path = os.path.join(destination_efi_path, "OC", "config.plist") + shutil.move(source_config_path, destination_config_path) + macserial_paths = self.utils.recursively_search(self.temporary_dir, product_name, matching_file_name_pattern="macserial") + if macserial_paths: + for macserial_path in macserial_paths: + file_name = os.path.basename(macserial_path) + source_macserial_path = os.path.join(self.temporary_dir, macserial_path) + destination_macserial_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), file_name) + shutil.move(source_macserial_path, destination_macserial_path) + if os.name != "nt": + subprocess.run(["chmod", "+x", destination_macserial_path]) + else: + raise FileNotFoundError("No bootloader or kexts files found in the product directory.") + + return True + + def gathering_bootloader_kexts(self): + download_history = self.utils.read_file(self.download_history_file) or { + "versions": [], + "last_updated": "2024-07-25T12:00:00" + } + + last_updated = datetime.fromisoformat(download_history["last_updated"]) + + current_time = datetime.now() + if current_time - last_updated < timedelta(minutes=10): + return + + ock_data = self.get_bootloader_kexts_data() + + self.utils.mkdirs(self.temporary_dir) + + for product_data in ock_data: + + product_index = self.product_index_in_history(product_data.get("product_name"), download_history.get("versions")) + if not product_index is None and product_data.get("id") == download_history.get("versions")[product_index].get("id"): + continue + + asset_dir = os.path.join(self.ock_files_dir, product_data.get("product_name")) + self.utils.mkdirs(asset_dir) + + zip_path = os.path.join(self.temporary_dir, product_data.get("product_name")) + ".zip" + self.fetcher.download_and_save_file(product_data.get("url"), zip_path) + if self.move_bootloader_kexts_to_product_directory(product_data.get("product_name")): + if product_index is None: + download_history["versions"].append({ + "product_name": product_data.get("product_name"), + "id": product_data.get("id") + }) + else: + download_history["versions"][product_index]["id"] = product_data.get("id") + + current_time = datetime.now().isoformat() + download_history["last_updated"] = current_time + + self.utils.write_file(self.download_history_file, download_history) + + shutil.rmtree(self.temporary_dir, ignore_errors=True) + + def get_amd_kernel_patches(self): + self.utils.head("Gathering Files") + print("") + print("Please wait for download AMD Vanilla Patches") + print(f"from {self.amd_vanilla_patches_url}") + print("") + + try: + response = self.fetcher.fetch_and_parse_content(self.amd_vanilla_patches_url, "plist") + + return response["Kernel"]["Patch"] + except: + print(self.utils.message("Unable to download AMD Vanilla Patches at this time.\nPlease try again later or apply them manually if you are using an AMD CPU system", "warning")) + print("") + self.utils.request_input() + return {} \ No newline at end of file diff --git a/Scripts/github.py b/Scripts/github.py new file mode 100755 index 0000000..e3854b5 --- /dev/null +++ b/Scripts/github.py @@ -0,0 +1,112 @@ +from Scripts import resource_fetcher +from Scripts import utils +from dotenv import load_dotenv +import os + +load_dotenv() + +class Github: + def __init__(self): + self.utils = utils.Utils() + # Load the GitHub token from environment variables + self.github_token = os.getenv("GITHUB_TOKEN") + # Set the headers for GitHub API requests + self.headers = { + "Accept": "application/vnd.github+json", + "#Authorization": f"token {self.github_token}", + "X-GitHub-Api-Version": "2022-11-28", + } + self.fetcher = resource_fetcher.ResourceFetcher(self.headers) + + def check_ratelimit(self): + url = "https://api.github.com/rate_limit" + + response = self.fetcher.fetch_and_parse_content(url, "json") + if response.get("rate").get("remaining") == 0: + raise Exception("Please try again later, you have exhausted your GitHub REST API request quota") + + def get_list_branches(self, owner, repo): + self.check_ratelimit() + + url = f"https://api.github.com/repos/{owner}/{repo}/branches" + + response = self.fetcher.fetch_and_parse_content(url, "json") + + if not response: + return [] + + return response + + def get_latest_artifact(self, owner, repo): + results = [] + + self.check_ratelimit() + + url = f"https://api.github.com/repos/{owner}/{repo}/actions/artifacts?per_page=1" + + response = self.fetcher.fetch_and_parse_content(url, "json") + + latest_artifact_id = response.get("artifacts")[0].get("id") + + results.append({ + "product_name": repo, + "id": latest_artifact_id, + "url": "https://api.github.com/repos/{}/{}/actions/artifacts/{}/{}".format(owner, repo, latest_artifact_id, "zip") + }) + + return results + + def get_latest_release(self, owner, repo): + result = [] + + self.check_ratelimit() + + url = f"https://api.github.com/repos/{owner}/{repo}/releases?per_page=1" + + response = self.fetcher.fetch_and_parse_content(url, "json") + + # Iterate over the assets in the release + for asset in response[0].get("assets"): + asset_id = asset.get("id") + download_url = asset.get("browser_download_url") + asset_name = self.extract_asset_name(asset.get("name")) + + if "apple" in download_url.lower() or ("app" not in download_url.lower() and "dsym" not in download_url.lower() and "adget" not in download_url): + if "lzhoang2601" in download_url or "tlwm" in download_url or ("tlwm" not in download_url and "DEBUG" not in download_url.upper()): + result.append({ + "product_name": asset_name, + "id": asset_id, + "url": download_url + }) + + return result + + def extract_asset_name(self, name): + # Extract the base name from the asset name + name_parts = name.split("-") if "-" in name else name.split("_") + + asset_name = name_parts[0].split(".")[0] + if asset_name[-1].isdigit(): + asset_name = asset_name[:-1] + + if (len(name_parts) > 1): + if "uns" in name_parts[1]: + asset_name += "-" + name_parts[1] + elif "Sonoma14.4" in name: + asset_name += "23.4" + elif "Sonoma" in name: + asset_name += "23" + elif "Ventura" in name: + asset_name += "22" + elif "Monterey" in name: + asset_name += "21" + elif "Catalina" in name: + asset_name += "19" + elif "Mojave" in name: + asset_name += "18" + elif "HighSierra" in name: + asset_name += "17" + elif "BigSur" in name: + asset_name += "20" + + return asset_name \ No newline at end of file diff --git a/Scripts/kext_maestro.py b/Scripts/kext_maestro.py new file mode 100755 index 0000000..095f1f2 --- /dev/null +++ b/Scripts/kext_maestro.py @@ -0,0 +1,774 @@ + +from Scripts.datasets import cpu_data +from Scripts.datasets import pci_data +from Scripts import utils +import os +import shutil + +class KextMaestro: + def __init__(self): + self.utils = utils.Utils() + self.matching_keys = [ + "IOPCIMatch", + "IONameMatch", + "IOPCIPrimaryMatch", + "idProduct", + "idVendor", + "HDAConfigDefault" + ] + self.ock_files_dir = os.path.join(os.getcwd(), "OCK_Files") + self.kext_loading_sequence = [ + { + "MainKext": "Lilu", + "BundlePath": "Lilu.kext", + "ExecutablePath": "Contents/MacOS/Lilu", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "VirtualSMC", + "BundlePath": "VirtualSMC.kext", + "ExecutablePath": "Contents/MacOS/VirtualSMC", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "ECEnabler", + "BundlePath": "ECEnabler.kext", + "ExecutablePath": "Contents/MacOS/ECEnabler", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "VirtualSMC", + "BundlePath": "SMCBatteryManager.kext", + "ExecutablePath": "Contents/MacOS/SMCBatteryManager", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "VirtualSMC", + "BundlePath": "SMCDellSensors.kext", + "ExecutablePath": "Contents/MacOS/SMCDellSensors", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "VirtualSMC", + "BundlePath": "SMCLightSensor.kext", + "ExecutablePath": "Contents/MacOS/SMCLightSensor", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "VirtualSMC", + "BundlePath": "SMCProcessor.kext", + "ExecutablePath": "Contents/MacOS/SMCProcessor", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "VirtualSMC", + "BundlePath": "SMCSuperIO.kext", + "ExecutablePath": "Contents/MacOS/SMCSuperIO", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "WhateverGreen", + "BundlePath": "WhateverGreen.kext", + "ExecutablePath": "Contents/MacOS/WhateverGreen", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "NootedRed", + "BundlePath": "NootedRed.kext", + "ExecutablePath": "Contents/MacOS/NootedRed", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "NootRX", + "BundlePath": "NootRX.kext", + "ExecutablePath": "Contents/MacOS/NootRX", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "AppleALC", + "BundlePath": "AppleALC.kext", + "ExecutablePath": "Contents/MacOS/AppleALC", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "AirportItlwm", + "BundlePath": "AirportItlwm.kext", + "ExecutablePath": "Contents/MacOS/AirportItlwm", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "itlwm", + "BundlePath": "itlwm.kext", + "ExecutablePath": "Contents/MacOS/itlwm", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "IOSkywalkFamily", + "BundlePath": "IOSkywalkFamily.kext", + "ExecutablePath": "Contents/MacOS/IOSkywalkFamily", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "IO80211FamilyLegacy", + "BundlePath": "IO80211FamilyLegacy.kext", + "ExecutablePath": "Contents/MacOS/IO80211FamilyLegacy", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "IO80211FamilyLegacy", + "BundlePath": "IO80211FamilyLegacy.kext/Contents/PlugIns/AirPortBrcmNIC.kext", + "ExecutablePath": "Contents/MacOS/AirPortBrcmNIC", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "AirportBrcmFixup", + "BundlePath": "AirportBrcmFixup.kext", + "ExecutablePath": "Contents/MacOS/AirportBrcmFixup", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "AirportBrcmFixup", + "BundlePath": "AirportBrcmFixup.kext/Contents/PlugIns/AirPortBrcm4360_Injector.kext", + "ExecutablePath": "", + "MaxKernel": "19.99.99", + "MinKernel": "" + }, + { + "MainKext": "AirportBrcmFixup", + "BundlePath": "AirportBrcmFixup.kext/Contents/PlugIns/AirPortBrcmNIC_Injector.kext", + "ExecutablePath": "", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "IntelBluetoothFirmware", + "BundlePath": "IntelBluetoothFirmware.kext", + "ExecutablePath": "Contents/MacOS/IntelBluetoothFirmware", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "IntelBluetoothFirmware", + "BundlePath": "IntelBTPatcher.kext", + "ExecutablePath": "Contents/MacOS/IntelBTPatcher", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "IntelBluetoothFirmware", + "BundlePath": "IntelBluetoothInjector.kext", + "ExecutablePath": "", + "MaxKernel": "20.99.99", + "MinKernel": "" + }, + { + "MainKext": "BlueToolFixup", + "BundlePath": "BlueToolFixup.kext", + "ExecutablePath": "Contents/MacOS/BlueToolFixup", + "MaxKernel": "", + "MinKernel": "21.0.0" + }, + { + "MainKext": "BrcmPatchRAM", + "BundlePath": "BrcmBluetoothInjector.kext", + "ExecutablePath": "", + "MaxKernel": "20.99.99", + "MinKernel": "" + }, + { + "MainKext": "BrcmPatchRAM", + "BundlePath": "BrcmFirmwareData.kext", + "ExecutablePath": "Contents/MacOS/BrcmFirmwareData", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "BrcmPatchRAM", + "BundlePath": "BrcmPatchRAM2.kext", + "ExecutablePath": "Contents/MacOS/BrcmPatchRAM2", + "MaxKernel": "18.99.99", + "MinKernel": "" + }, + { + "MainKext": "BrcmPatchRAM", + "BundlePath": "BrcmPatchRAM3.kext", + "ExecutablePath": "Contents/MacOS/BrcmPatchRAM3", + "MaxKernel": "", + "MinKernel": "19.0.0" + }, + { + "MainKext": "AppleIGC", + "BundlePath": "AppleIGC.kext", + "ExecutablePath": "Contents/MacOS/AppleIGC", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "AtherosE2200Ethernet", + "BundlePath": "AtherosE2200Ethernet.kext", + "ExecutablePath": "Contents/MacOS/AtherosE2200Ethernet", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "IntelMausi", + "BundlePath": "IntelMausi.kext", + "ExecutablePath": "Contents/MacOS/IntelMausi", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "LucyRTL8125Ethernet", + "BundlePath": "LucyRTL8125Ethernet.kext", + "ExecutablePath": "Contents/MacOS/LucyRTL8125Ethernet", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "NullEthernet", + "BundlePath": "NullEthernet.kext", + "ExecutablePath": "Contents/MacOS/NullEthernet", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "RealtekRTL8100", + "BundlePath": "RealtekRTL8100.kext", + "ExecutablePath": "Contents/MacOS/RealtekRTL8100", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "RealtekRTL8111", + "BundlePath": "RealtekRTL8111.kext", + "ExecutablePath": "Contents/MacOS/RealtekRTL8111", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "BrightnessKeys", + "BundlePath": "BrightnessKeys.kext", + "ExecutablePath": "Contents/MacOS/BrightnessKeys", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "AsusSMC", + "BundlePath": "AsusSMC.kext", + "ExecutablePath": "Contents/MacOS/AsusSMC", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "VoodooInput", + "BundlePath": "VoodooInput.kext", + "ExecutablePath": "Contents/MacOS/VoodooInput", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "VoodooPS2", + "BundlePath": "VoodooPS2Controller.kext", + "ExecutablePath": "Contents/MacOS/VoodooPS2Controller", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "VoodooPS2", + "BundlePath": "VoodooPS2Controller.kext/Contents/PlugIns/VoodooPS2Keyboard.kext", + "ExecutablePath": "Contents/MacOS/VoodooPS2Keyboard", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "VoodooPS2", + "BundlePath": "VoodooPS2Controller.kext/Contents/PlugIns/VoodooPS2Mouse.kext", + "ExecutablePath": "Contents/MacOS/VoodooPS2Mouse", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "VoodooPS2", + "BundlePath": "VoodooPS2Controller.kext/Contents/PlugIns/VoodooPS2Trackpad.kext", + "ExecutablePath": "Contents/MacOS/VoodooPS2Trackpad", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "VoodooRMI", + "BundlePath": "VoodooRMI.kext", + "ExecutablePath": "Contents/MacOS/VoodooRMI", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "VoodooRMI", + "BundlePath": "VoodooSMBus.kext", + "ExecutablePath": "Contents/MacOS/VoodooSMBus", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "VoodooSMBus", + "BundlePath": "VoodooSMBus.kext", + "ExecutablePath": "Contents/MacOS/VoodooSMBus", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "VoodooRMI", + "BundlePath": "VoodooRMI.kext/Contents/PlugIns/RMISMBus.kext", + "ExecutablePath": "Contents/MacOS/RMISMBus", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "VoodooI2C", + "BundlePath": "VoodooI2C.kext/Contents/PlugIns/VoodooI2CServices.kext", + "ExecutablePath": "Contents/MacOS/VoodooI2CServices", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "VoodooI2C", + "BundlePath": "VoodooI2C.kext/Contents/PlugIns/VoodooGPIO.kext", + "ExecutablePath": "Contents/MacOS/VoodooGPIO", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "VoodooI2C", + "BundlePath": "VoodooI2C.kext", + "ExecutablePath": "Contents/MacOS/VoodooI2C", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "BigSurface", + "BundlePath": "BigSurface.kext/Contents/PlugIns/VoodooInput.kext", + "ExecutablePath": "Contents/MacOS/VoodooInput", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "BigSurface", + "BundlePath": "BigSurface.kext/Contents/PlugIns/VoodooGPIO.kext", + "ExecutablePath": "Contents/MacOS/VoodooGPIO", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "BigSurface", + "BundlePath": "BigSurface.kext/Contents/PlugIns/VoodooSerial.kext", + "ExecutablePath": "Contents/MacOS/VoodooSerial", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "BigSurface", + "BundlePath": "BigSurface.kext", + "ExecutablePath": "Contents/MacOS/BigSurface", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "BigSurface", + "BundlePath": "BigSurface.kext/Contents/PlugIns/BigSurfaceHIDDriver.kext", + "ExecutablePath": "Contents/MacOS/BigSurfaceHIDDriver", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "VoodooRMI", + "BundlePath": "VoodooRMI.kext/Contents/PlugIns/RMII2C.kext", + "ExecutablePath": "Contents/MacOS/RMII2C", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "lzh", + "BundlePath": "VoodooI2CELAN.kext", + "ExecutablePath": "Contents/MacOS/VoodooI2CELAN", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "VoodooI2C", + "BundlePath": "VoodooI2CHID.kext", + "ExecutablePath": "Contents/MacOS/VoodooI2CHID", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "AlpsHID", + "BundlePath": "AlpsHID.kext", + "ExecutablePath": "Contents/MacOS/AlpsHID", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "lzh", + "BundlePath": "VoodooI2CSynaptics.kext", + "ExecutablePath": "Contents/MacOS/VoodooI2CSynaptics", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "AppleMCEReporterDisabler", + "BundlePath": "AppleMCEReporterDisabler.kext", + "ExecutablePath": "", + "MaxKernel": "", + "MinKernel": "21.0.0" + }, + { + "MainKext": "AMFIPass", + "BundlePath": "AMFIPass.kext", + "ExecutablePath": "Contents/MacOS/AMFIPass", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "CpuTopologyRebuild", + "BundlePath": "CpuTopologyRebuild.kext", + "ExecutablePath": "Contents/MacOS/CpuTopologyRebuild", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "CtlnaAHCIPort", + "BundlePath": "CtlnaAHCIPort.kext", + "ExecutablePath": "Contents/MacOS/CtlnaAHCIPort", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "RealtekCardReader", + "BundlePath": "RealtekCardReader.kext", + "ExecutablePath": "Contents/MacOS/RealtekCardReader", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "RealtekCardReaderFriend", + "BundlePath": "RealtekCardReaderFriend.kext", + "ExecutablePath": "Contents/MacOS/RealtekCardReaderFriend", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "ForgedInvariant", + "BundlePath": "ForgedInvariant.kext", + "ExecutablePath": "Contents/MacOS/ForgedInvariant", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "RestrictEvents", + "BundlePath": "RestrictEvents.kext", + "ExecutablePath": "Contents/MacOS/RestrictEvents", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "HibernationFixup", + "BundlePath": "HibernationFixup.kext", + "ExecutablePath": "Contents/MacOS/HibernationFixup", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "RTCMemoryFixup", + "BundlePath": "RTCMemoryFixup.kext", + "ExecutablePath": "Contents/MacOS/RTCMemoryFixup", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "NVMeFix", + "BundlePath": "NVMeFix.kext", + "ExecutablePath": "Contents/MacOS/NVMeFix", + "MaxKernel": "", + "MinKernel": "18.0.0" + }, + { + "MainKext": "CryptexFixup", + "BundlePath": "CryptexFixup.kext", + "ExecutablePath": "Contents/MacOS/CryptexFixup", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "GenericUSBXHCI", + "BundlePath": "GenericUSBXHCI.kext", + "ExecutablePath": "Contents/MacOS/GenericUSBXHCI", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "XHCI-unsupported", + "BundlePath": "XHCI-unsupported.kext", + "ExecutablePath": "", + "MaxKernel": "", + "MinKernel": "" + }, + { + "MainKext": "USBMap", + "BundlePath": "USBMap.kext", + "ExecutablePath": "", + "MaxKernel": "", + "MinKernel": "" + } + ] + self.latest_macos_version = "24.99.99" + + def extract_pci_id(self, kext_path): + if not os.path.exists(kext_path): + return [] + + plist_path = os.path.join(kext_path, "Contents", "Info.plist") + plist_data = self.utils.read_file(plist_path) + + pci_ids = [] + + # Iterate through the personalities in the plist + for personality_name, properties in plist_data.get("IOKitPersonalities", {}).items(): + matching_keys = [key for key in self.matching_keys if key in properties] + + if not matching_keys: + continue + + match_key = matching_keys[0] + + if match_key in ["IOPCIMatch", "IOPCIPrimaryMatch"]: + # Split PCI IDs and format them + pci_list = properties[match_key].split(" ") + for pci_id in pci_list: + vendor_id = pci_id[-4:] + device_id = pci_id[2:6] + pci_ids.append(f"{vendor_id}-{device_id}".upper()) + elif match_key == "IONameMatch": + # Process IONameMatch keys + for pci_id in properties[match_key]: + vendor_id = pci_id[3:7] + device_id = pci_id[-4:] + pci_ids.append(f"{vendor_id}-{device_id}".upper()) + elif match_key == "idProduct": + # Process idProduct and idVendor + vendor_id = self.utils.int_to_hex(properties["idVendor"]).zfill(4) + device_id = self.utils.int_to_hex(properties["idProduct"]).zfill(4) + pci_ids.append(f"{vendor_id}-{device_id}".upper()) + elif match_key == "HDAConfigDefault": + # Handle AppleALC configurations + for codec_layout in properties[match_key]: + codec_id = self.utils.int_to_hex(codec_layout.get("CodecID")).zfill(8) + pci_ids.append(f"{codec_id[:4]}-{codec_id[-4:]}") + pci_ids = sorted(list(set(pci_ids))) + + return pci_ids + + def gathering_kexts(self, motherboard_name, platform, cpu_configuration, cpu_manufacturer, cpu_codename, discrete_gpu_codename, integrated_gpu, wifi_pci, ethernet_pci, bluetooth, codec_id, input, sd_controller, storage_controllers, usb_controllers, smbios, custom_cpu_name, tsc_sync, battery_status_patch_needed, macos_version): + kexts = [ + "Lilu", + "VirtualSMC", + "USBMap" + ] + + if macos_version > 22 or custom_cpu_name or "MacPro7,1" in smbios: + kexts.append("RestrictEvents") + + if codec_id in pci_data.CodecIDs: + kexts.append("AppleALC") + + if "AMD" in cpu_manufacturer and macos_version > 21 or int(cpu_configuration) > 1 and macos_version > 18: + kexts.append("AppleMCEReporterDisabler") + + if macos_version > 21 and self.utils.contains_any(cpu_data.IntelCPUGenerations, cpu_codename, end=2): + kexts.append("CryptexFixup") + + if self.utils.contains_any(cpu_data.IntelCPUGenerations, cpu_codename, start=13): + kexts.append("CpuTopologyRebuild") + + if tsc_sync: + kexts.append("ForgedInvariant") + + if "AMD" in cpu_manufacturer and integrated_gpu and not discrete_gpu_codename: + kexts.append("NootedRed") + else: + kexts.append("NootRX" if "Navi 2" in discrete_gpu_codename else "WhateverGreen") + + if wifi_pci and wifi_pci in pci_data.NetworkIDs: + if wifi_pci.startswith("14E4"): + if wifi_pci in ["14E4-43A0", "14E4-43A3", "14E4-43BA"]: + if macos_version > 22: + kexts.extend(["AirportBrcmFixup", "IOSkywalkFamily", "IO80211FamilyLegacy", "AMFIPass"]) + elif wifi_pci in pci_data.NetworkIDs: + kexts.append("AirportBrcmFixup") + elif wifi_pci.startswith("8086"): + kexts.append("AirportItlwm" if macos_version < 23 else "itlwm") + + if not ethernet_pci or not (ethernet_pci[0] in pci_data.NetworkIDs or ethernet_pci[-1] in pci_data.NetworkIDs): + kexts.append("NullEthernet") + else: + for pci_id in ethernet_pci: + idx = pci_data.NetworkIDs.index(pci_id) + + if 108 <= idx <= 114: + kexts.append("AppleIGC") + elif 115 <= idx <= 121: + kexts.append("AtherosE2200Ethernet") + elif 122 <= idx <= 172: + kexts.append("IntelMausi") + elif 173 <= idx <= 175: + kexts.append("LucyRTL8125Ethernet") + elif idx == 176: + kexts.append("RealtekRTL8100") + elif 177 <= idx <= 180: + kexts.append("RealtekRTL8111") + + if bluetooth and macos_version > 20 and not wifi_pci in ["14E4-43A0", "14E4-43A3", "14E4-43BA"]: + kexts.append("BlueToolFixup") + for usb_id in bluetooth: + if usb_id in pci_data.BluetoothIDs: + idx = pci_data.BluetoothIDs.index(usb_id) + + if idx < 99: + kexts.append("BrcmPatchRAM") + else: + kexts.append("IntelBluetoothFirmware") + + if "Laptop" in platform: + if "SURFACE" in motherboard_name: + kexts.append("BigSurface") + else: + if "ASUS" in motherboard_name: + kexts.append("AsusSMC") + kexts.append("BrightnessKeys") + + for device_name, device_props in input.items(): + if not device_props.get("Bus Type", "").startswith("ACPI"): + continue + + if "PS/2" in device_name: + kexts.extend(["VoodooInput", "VoodooPS2"]) + if "I2C" in device_name: + kexts.extend(["VoodooInput", "VoodooI2C"]) + + device_id = device_props.get("Device ID") + if device_id in pci_data.InputIDs: + idx = pci_data.InputIDs.index(device_id) + + if idx < 77: + kexts.append("AlpsHID") + elif 76 < idx < 80: + kexts.append("VoodooSMBus") + else: + kexts.append("VoodooRMI") + + if "Laptop" in platform and "SURFACE" not in motherboard_name and battery_status_patch_needed: + kexts.append("ECEnabler") + + if sd_controller and sd_controller.get("Device ID") in pci_data.RealtekCardReaderIDs: + kexts.extend(["RealtekCardReader", "RealtekCardReaderFriend"]) + + for controller_name, controller_props in storage_controllers.items(): + if "NVMe" in controller_name or "NVM Express" in controller_props.get("Device Description"): + kexts.append("NVMeFix") + else: + if controller_props.get("Device ID") in pci_data.UnsupportedSATAControllerIDs: + kexts.append("CtlnaAHCIPort") + + for pci_id in usb_controllers: + if pci_id in pci_data.UnsupportedUSBControllerIDs: + idx = pci_data.UnsupportedUSBControllerIDs.index(pci_id) + if idx == 0: + kexts.append("GenericUSBXHCI") + else: + kexts.append("XHCI-unsupported") + + return list(set(kexts)) + + def install_kexts_to_efi(self, kexts, macos_version, kexts_directory): + for kext_name in kexts: + if "AirportItlwm" in kext_name: + kext_name = f"{kext_name}{macos_version}" + elif "BlueToolFixup" in kext_name or "BrcmPatchRAM" in kext_name: + kext_name = "BrcmPatchRAM" + + source_kext_dir = os.path.join(self.ock_files_dir, kext_name) + if os.path.exists(source_kext_dir): + shutil.copytree(source_kext_dir, kexts_directory, dirs_exist_ok=True) + + def load_kexts(self, kexts, motherboard_name, platform, cpu_manufacturer, discrete_gpu_codename, macos_version): + kernel_add = [] + unload_kext = [] + + if not "DELL" in motherboard_name: + unload_kext.append("SMCDellSensors") + if "Desktop" in platform: + unload_kext.extend([ + "SMCBatteryManager", + "SMCLightSensor" + ]) + if "AMD" in cpu_manufacturer: + unload_kext.extend(["SMCProcessor", "SMCSuperIO"]) + if "Navi 2" in discrete_gpu_codename: + unload_kext.append("SMCSuperIO") + elif "Laptop" in platform and not "SURFACE" in motherboard_name: + if "AMD" in cpu_manufacturer: + unload_kext.extend([ + "SMCProcessor", + "SMCSuperIO" + ]) + + if "VoodooSMBus" in kexts: + unload_kext.append("VoodooPS2Mouse") + elif "VoodooRMI" in kexts: + if not "VoodooI2C" in kexts: + unload_kext.append("RMII2C") + else: + unload_kext.extend([ + "VoodooSMBus", + "RMISMBus", + "VoodooI2CServices", + "VoodooGPIO", + "VoodooI2CHID" + ]) + + for kext in self.kext_loading_sequence: + if not kext.get("MainKext") in kexts or os.path.splitext(os.path.basename(kext.get("BundlePath")))[0] in unload_kext: + continue + max_supported_macos_version = kext.get("MaxKernel") or self.latest_macos_version + min_supported_macos_version = kext.get("MinKernel") or "17.0.0" + if not min_supported_macos_version[:2] <= str(macos_version) <= max_supported_macos_version[:2]: + continue + + kernel_add.append({ + "Arch": "x86_64", + "BundlePath": kext.get("BundlePath"), + "Comment": "", + "Enabled": True, + "ExecutablePath": kext.get("ExecutablePath") or "", + "MaxKernel": "", + "MinKernel": "", + "PlistPath": "Contents/Info.plist" + }) + + return kernel_add \ No newline at end of file diff --git a/Scripts/resource_fetcher.py b/Scripts/resource_fetcher.py new file mode 100755 index 0000000..1608603 --- /dev/null +++ b/Scripts/resource_fetcher.py @@ -0,0 +1,69 @@ +import requests +import ssl +import os +import certifi +import zipfile +import plistlib + +class ResourceFetcher: + def __init__(self, headers = None): + self.request_headers = headers + self.buffer_size = 16*1024 + self.ssl_context = self.create_ssl_context() + + def create_ssl_context(self): + try: + cafile = ssl.get_default_verify_paths().openssl_cafile + if not os.path.exists(cafile): + cafile = certifi.where() + ssl_context = ssl.create_default_context(cafile=cafile) + except Exception as e: + print(f"SSL Context Creation Error: {e}") + ssl_context = ssl._create_unverified_context() + return ssl_context + + def fetch_and_parse_content(self, resource_url, content_type=None): + response = requests.get(resource_url, headers=self.request_headers, verify=self.ssl_context.verify_mode != ssl.CERT_NONE) + response.raise_for_status() + + if content_type == 'json': + return response.json() + elif content_type == 'plist': + return plistlib.loads(response.content) + else: + return response.text + + def download_and_save_file(self, resource_url, destination_path, extract=True): + with requests.get(resource_url, headers=self.request_headers, stream=True, verify=self.ssl_context.verify_mode != ssl.CERT_NONE) as response: + response.raise_for_status() + + try: + total_size = int(response.headers.get('Content-Length', -1)) + except ValueError: + total_size = -1 + + bytes_downloaded = 0 + + print(f"Download from {resource_url}") + + with open(destination_path, 'wb') as file_writer: + while True: + chunk = response.raw.read(self.buffer_size) + if not chunk: + break + file_writer.write(chunk) + bytes_downloaded += len(chunk) + if total_size != -1: + print(f"Downloaded {bytes_downloaded / (1024 * 1024):.2f} MB of {total_size / (1024 * 1024):.2f} MB", end='\r') + + if extract and destination_path.lower().endswith('.zip'): + self.extract_zip_file(destination_path) + + def extract_zip_file(self, zip_path, extraction_directory=None): + if extraction_directory is None: + extraction_directory = os.path.splitext(zip_path)[0] + + os.makedirs(extraction_directory, exist_ok=True) + + with zipfile.ZipFile(zip_path, 'r') as zip_ref: + zip_ref.extractall(extraction_directory) \ No newline at end of file diff --git a/Scripts/run.py b/Scripts/run.py new file mode 100755 index 0000000..0987d08 --- /dev/null +++ b/Scripts/run.py @@ -0,0 +1,154 @@ +# Original source: +# https://github.com/corpnewt/SSDTTime/blob/7b3fb78112bf320a1bc6a7e50dddb2b375cb70b0/Scripts/run.py + +import sys, subprocess, time, threading, shlex +try: + from Queue import Queue, Empty +except: + from queue import Queue, Empty + +ON_POSIX = 'posix' in sys.builtin_module_names + +class Run: + + def __init__(self): + return + + def _read_output(self, pipe, q): + try: + for line in iter(lambda: pipe.read(1), b''): + q.put(line) + except ValueError: + pass + pipe.close() + + def _create_thread(self, output): + # Creates a new queue and thread object to watch based on the output pipe sent + q = Queue() + t = threading.Thread(target=self._read_output, args=(output, q)) + t.daemon = True + return (q,t) + + def _stream_output(self, comm, shell = False): + output = error = "" + p = None + try: + if shell and type(comm) is list: + comm = " ".join(shlex.quote(x) for x in comm) + if not shell and type(comm) is str: + comm = shlex.split(comm) + p = subprocess.Popen(comm, shell=shell, stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=0, universal_newlines=True, close_fds=ON_POSIX) + # Setup the stdout thread/queue + q,t = self._create_thread(p.stdout) + qe,te = self._create_thread(p.stderr) + # Start both threads + t.start() + te.start() + + while True: + c = z = "" + try: c = q.get_nowait() + except Empty: pass + else: + sys.stdout.write(c) + output += c + sys.stdout.flush() + try: z = qe.get_nowait() + except Empty: pass + else: + sys.stderr.write(z) + error += z + sys.stderr.flush() + if not c==z=="": continue # Keep going until empty + # No output - see if still running + p.poll() + if p.returncode != None: + # Subprocess ended + break + # No output, but subprocess still running - stall for 20ms + time.sleep(0.02) + + o, e = p.communicate() + return (output+o, error+e, p.returncode) + except: + if p: + try: o, e = p.communicate() + except: o = e = "" + return (output+o, error+e, p.returncode) + return ("", "Command not found!", 1) + + def _decode(self, value, encoding="utf-8", errors="ignore"): + # Helper method to only decode if bytes type + if sys.version_info >= (3,0) and isinstance(value, bytes): + return value.decode(encoding,errors) + return value + + def _run_command(self, comm, shell = False): + c = None + try: + if shell and type(comm) is list: + comm = " ".join(shlex.quote(x) for x in comm) + if not shell and type(comm) is str: + comm = shlex.split(comm) + p = subprocess.Popen(comm, shell=shell, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + c = p.communicate() + except: + if c == None: + return ("", "Command not found!", 1) + return (self._decode(c[0]), self._decode(c[1]), p.returncode) + + def run(self, command_list, leave_on_fail = False): + # Command list should be an array of dicts + if type(command_list) is dict: + # We only have one command + command_list = [command_list] + output_list = [] + for comm in command_list: + args = comm.get("args", []) + shell = comm.get("shell", False) + stream = comm.get("stream", False) + sudo = comm.get("sudo", False) + stdout = comm.get("stdout", False) + stderr = comm.get("stderr", False) + mess = comm.get("message", None) + show = comm.get("show", False) + + if not mess == None: + print(mess) + + if not len(args): + # nothing to process + continue + if sudo: + # Check if we have sudo + out = self._run_command(["which", "sudo"]) + if "sudo" in out[0]: + # Can sudo + if type(args) is list: + args.insert(0, out[0].replace("\n", "")) # add to start of list + elif type(args) is str: + args = out[0].replace("\n", "") + " " + args # add to start of string + + if show: + print(" ".join(args)) + + if stream: + # Stream it! + out = self._stream_output(args, shell) + else: + # Just run and gather output + out = self._run_command(args, shell) + if stdout and len(out[0]): + print(out[0]) + if stderr and len(out[1]): + print(out[1]) + # Append output + output_list.append(out) + # Check for errors + if leave_on_fail and out[2] != 0: + # Got an error - leave + break + if len(output_list) == 1: + # We only ran one command - just return that output + return output_list[0] + return output_list \ No newline at end of file diff --git a/Scripts/smbios.py b/Scripts/smbios.py new file mode 100755 index 0000000..65a643f --- /dev/null +++ b/Scripts/smbios.py @@ -0,0 +1,58 @@ +from Scripts import gathering_files +from Scripts import utils +import os +import subprocess +import uuid +import random + +class SMBIOS: + def __init__(self): + self.g = gathering_files.gatheringFiles() + self.utils = utils.Utils() + self.script_dir = os.path.dirname(os.path.realpath(__file__)) + self.macserial = self.check_macserial() + + def check_macserial(self, quit=False): + macserial_name = "macserial.exe" if os.name == "nt" else "macserial" + macserial_path = os.path.join(self.script_dir, macserial_name) + + if not os.path.exists(macserial_path): + download_history = self.utils.read_file(self.g.download_history_file) + + if download_history: + product_index = self.g.product_index_in_history("OpenCore", download_history["versions"]) + + if product_index: + download_history["versions"].pop(product_index) + download_history["last_updated"] = "2024-07-25T12:00:00" + self.utils.write_file(self.g.download_history_file, download_history) + + if quit: + raise Exception(f"{macserial_name} not found. Please reopen the program to download it") + else: + return macserial_path + + def generate_random_mac(self): + random_mac = ''.join([format(random.randint(0, 255), '02X') for _ in range(6)]) + return random_mac + + def generate(self, product_name): + if not self.macserial: + self.check_macserial(True) + + random_mac_address = self.generate_random_mac() + + result = subprocess.run( + [self.macserial, "-g", "--model", product_name], + capture_output=True, + check=True, # Raises CalledProcessError for non-zero return code + ) + first_serial = result.stdout.decode().splitlines()[0] + + return { + "MLB": "A" + "0"*15 + "Z" if " | " in first_serial else first_serial.split(" | ")[-1], + "ROM": random_mac_address, + "SystemProductName": product_name, + "SystemSerialNumber": "A" + "0"*10 + "9" if " | " in first_serial else first_serial.split(" | ")[0], + "SystemUUID": str(uuid.uuid4()).upper(), + } \ No newline at end of file diff --git a/Scripts/utils.py b/Scripts/utils.py new file mode 100755 index 0000000..152a0e5 --- /dev/null +++ b/Scripts/utils.py @@ -0,0 +1,244 @@ +from Scripts import resource_fetcher +import os +import json +import plistlib +import shutil +import re +import binascii +import subprocess +import pathlib + +class Utils: + def __init__(self, script_name = "OpCore Simplify"): + self.script_name = script_name + self.fetcher = resource_fetcher.ResourceFetcher({ + "Accept": "application/vnd.github+json", + "X-GitHub-Api-Version": "2022-11-28", + }) + self.repo_url = "https://raw.githubusercontent.com/lzhoang2801/OpCore-Simplify/main/version.json" + + def write_file(self, file_path, data): + file_extension = os.path.splitext(file_path)[1] + + with open(file_path, "w" if file_extension == ".json" else "wb") as file: + if file_extension == ".json": + json.dump(data, file, indent=4) + else: + if file_extension == ".plist": + data = plistlib.dumps(data) + + file.write(data) + + def read_file(self, file_path): + if not os.path.exists(file_path): + return None + + file_extension = os.path.splitext(file_path)[1] + + with open(file_path, "r" if file_extension == ".json" else "rb") as file_handle: + if file_extension == ".plist": + data = plistlib.load(file_handle) + elif file_extension == ".json": + data = json.load(file_handle) + else: + data = file_handle.read() + return data + + def search_dict_iter(self, dictionary, search_term, equal=True, reverse=False): + dictionary_copy = dictionary.copy() + + if reverse: + dictionary_copy = dict(list(dictionary_copy.items())[::-1]) + + stack = [(dictionary_copy, None)] + + while stack: + current_dict, parent_dict = stack.pop() + for key, value in current_dict.items(): + if equal and value == search_term or not equal and search_term in value: + return current_dict + if isinstance(value, dict): + stack.append((value, current_dict)) + if equal and key == search_term or not equal and search_term in key: + return value + + return {} + + def recursively_search(self, directory, matching_file_extension=None, matching_file_name_pattern=None, parent_directory=""): + matching_paths = [] + + if not os.path.exists(directory): + print(f"Error: The directory {directory} does not exist.") + return matching_paths + + for child_directory in os.listdir(directory): + if "MACOSX" in child_directory or "dSYM" in child_directory: + continue + + file_name = os.path.splitext(os.path.basename(child_directory))[0] + file_extension = os.path.splitext(os.path.basename(child_directory))[1] + + if (matching_file_extension is not None and matching_file_extension == file_extension) or (matching_file_name_pattern is not None and matching_file_name_pattern in file_name): + path = os.path.join(parent_directory, child_directory) + full_path = os.path.join(directory, child_directory) + + if not os.path.isdir(full_path) or not os.path.exists(os.path.join(full_path, file_name + file_extension)): + matching_paths.append(path) + + child_directory = os.path.join(directory, child_directory) + if os.path.isdir(child_directory): + matching_paths.extend(self.recursively_search(child_directory, matching_file_extension, matching_file_name_pattern, os.path.join(parent_directory, os.path.basename(child_directory)))) + + return matching_paths + + def sort_dict_by_key(self, input_dict, sort_key): + return dict(sorted(input_dict.items(), key=lambda item: item[1].get(sort_key, ""))) + + def mkdirs(self, *directories): + for directory in directories: + if not os.path.exists(os.path.dirname(directory)): + os.makedirs(os.path.dirname(directory)) + if os.path.exists(directory): + shutil.rmtree(directory) + os.mkdir(directory) + + def hex_to_bytes(self, string): + try: + # Remove non-hex characters (e.g., hyphens) + hex_string = re.sub(r'[^0-9a-fA-F]', '', string) + + if len(re.sub(r"\s+", "", string)) != len(hex_string): + return string + + # Convert hex string to bytes + bytes_data = binascii.unhexlify(hex_string) + + return bytes_data + except binascii.Error: + # Handle invalid hex string + return string + + def int_to_hex(self, number): + try: + return format(number, '02X') + except: + return number + + def hex_to_int(self, hex_string): + return int(hex_string, 16) + + def contains_any(self, data, search_item, start=0, end=None): + return next((item for item in data[start:end] if item.lower() in search_item.lower()), None) + + def check_latest_version(self): + response = self.fetcher.fetch_and_parse_content(self.repo_url, "json") + + latest_version = response.get('version') + + if not latest_version: + print("Version information is missing in the JSON file.") + return None + + return latest_version + + def normalize_path(self, path): + # Remove all surrounding quotes if present + path = re.sub(r'^[\'"]+|[\'"]+$', '', path) + + # Remove trailing spaces + path = path.strip() + + # Expand ~ to the user's home directory + path = os.path.expanduser(path) + + # Normalize path separators for the target operating system + if os.name == 'nt': # Windows + # Replace single backslashes with forward slashes + path = path.replace('\\', '/') + # Remove redundant slashes + path = re.sub(r'/+', '/', path) + else: + # Replace backslashes with forward slashes + path = path.replace('\\', '/') + + # Normalize the path + path = os.path.normpath(path) + + # Convert the path to an absolute path and normalize it according to the OS + return str(pathlib.Path(path).resolve()) + + def open_folder(self, folder_path): + if os.name == 'posix': + if 'darwin' in os.uname().sysname.lower(): + subprocess.run(['open', folder_path]) + else: + subprocess.run(['xdg-open', folder_path]) + elif os.name == 'nt': + os.startfile(folder_path) + else: + raise NotImplementedError("This function is only supported on macOS, Windows, and Linux.") + + def request_input(self, prompt="Press Enter to continue..."): + try: + user_response = input(prompt) + except NameError: + user_response = raw_input(prompt) + + if not isinstance(user_response, str): + user_response = str(user_response) + + return user_response + + def clear_screen(self): + os.system('cls' if os.name=='nt' else 'clear') + + def head(self, text = None, width = 68, resize=True): + if resize: + self.adjust_window_size() + self.clear_screen() + if text == None: + text = self.script_name + separator = "#" * width + title = f" {text} " + if len(title) > width - 2: + title = title[:width-4] + "..." + title = title.center(width - 2) # Center the title within the width minus 2 for the '#' characters + + print(f"{separator}\n#{title}#\n{separator}") + + def adjust_window_size(self, content=""): + lines = content.splitlines() + rows = len(lines) + cols = max(len(line) for line in lines) if lines else 0 + print('\033[8;{};{}t'.format(max(rows+6, 30), max(cols+2, 100))) + + @staticmethod + def message(text, msg_type="attention"): + # ANSI escape codes for different colors and bold font + RED_BOLD = "\033[1;31m" + YELLOW_BOLD = "\033[1;33m" + CYAN_BOLD = "\033[1;36m" + RESET = "\033[0m" + + if msg_type == "attention": + color_code = RED_BOLD + elif msg_type == "warning": + color_code = YELLOW_BOLD + elif msg_type == "reminder": + color_code = CYAN_BOLD + else: + color_code = RESET + + return f"{color_code}{text}{RESET}" + + def exit_program(self, custom_content=""): + self.head() + print(custom_content) + print("For more information, to report errors, or to contribute to the product:") + print("* Facebook: https://www.facebook.com/macforce2601") + print("* Telegram: https://t.me/lzhoang2601") + print("* GitHub: https://github.com/lzhoang2801/OpCore-Simplify") + print("") + + print("Thank you for using our program!\n") + exit(0) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..543ebd7 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +bs4 +requests +python-dotenv +pytz \ No newline at end of file diff --git a/version.json b/version.json new file mode 100644 index 0000000..a8908f6 --- /dev/null +++ b/version.json @@ -0,0 +1,3 @@ +{ + "version": "0.0.1" +} \ No newline at end of file