Initial commit

This commit is contained in:
Hoang Hong Quan
2024-07-26 18:09:54 +07:00
commit 72a124244b
75 changed files with 10508 additions and 0 deletions

2
.gitattributes vendored Normal file
View File

@@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto

163
.gitignore vendored Normal file
View File

@@ -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

29
LICENSE Executable file
View File

@@ -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.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

397
OpCore-Simplify.bat Executable file
View File

@@ -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 <path> <py2v> <py2path> <py3v> <py3path>
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 <path> <py2v> <py2path> <py3v> <py3path>
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 <check_value>
set "var="&for /f "delims=0123456789." %%i in ("%~1") do set var=%%i
if defined var (exit /b 1)
exit /b 0
:comparepyversion <version1> <version2> <return>
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 <string_name> <string_value> <character>
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 <variable_name>
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

302
OpCore-Simplify.command Executable file
View File

@@ -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

232
OpCore-Simplify.py Executable file
View File

@@ -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)))

79
README.md Normal file
View File

@@ -0,0 +1,79 @@
<br/>
<div align="center">
<h3 align="center">OpCore Simplify</h3>
<p align="center">
A tool designed to simplify the creation of <a href="https://github.com/acidanthera/OpenCorePkg">OpenCore</a> EFI. It includes features such as auto-patching DSDT, adding suitable kexts, and customizing the config.plist to make Hackintosh installation easy for beginners.
<br />
<br />
<a href="https://github.com/lzhoang2601/OpCore-Simplify/issues">Report Bug</a>
·
<a href="https://github.com/lzhoang2601/OpCore-Simplify/issues">Request Feature</a>
</p>
</div>
<details>
<summary>Table of Contents</summary>
<ol>
<li><a href="#features">Features</a></li>
<li><a href="#usage-guide">Usage Guide</a></li>
<li><a href="#contributing">Contributing</a></li>
<li><a href="#license">License</a></li>
<li><a href="#contact">Contact</a></li>
</ol>
</details>
## 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

2842
Scripts/acpi_guru.py Executable file

File diff suppressed because it is too large Load Diff

606
Scripts/aida64.py Executable file
View File

@@ -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('<tr>'):
# Remove <tr> tag
line = line.replace('<tr>', '')
# Calculate the current level based on the number of <td> tags
level = (len(line) - len(line.lstrip('<td>'))) // 3 - 1
if level < 1:
continue
# Remove all <td> tags from the left
while line.startswith("<td>"):
line = line[line.find(">") + 1:]
if not line.startswith('<td') and '<td' in line:
idx = line.index('<td')
line = '{}{}{}{}'.format('<td>', line[:idx], '</td>', 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 '<td class="cc">' 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

951
Scripts/codec_layouts.py Executable file
View File

@@ -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
]
}

212
Scripts/compatibility_checker.py Executable file
View File

@@ -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

364
Scripts/config_prodigy.py Executable file
View File

@@ -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

161
Scripts/datasets/chipset_data.py Executable file
View File

@@ -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"
]

43
Scripts/datasets/cpu_data.py Executable file
View File

@@ -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"
]

1157
Scripts/datasets/pci_data.py Executable file

File diff suppressed because it is too large Load Diff

728
Scripts/dsdt.py Executable file
View File

@@ -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".*(?P<type>Processor|Scope|Device|Method|Name) \((?P<name>[^,\)]+).*")
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"):
# <a href="/content/www/us/en/download/774881/acpi-component-architecture-downloads-windows-binary-tools.html">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('<a href="')[1].split('"')[0]
#dl_page_source = self.dl.get_string(dl_page_url, headers=self.h)
dl_page_source = self.fetcher.fetch_and_parse_content(dl_page_url)
for line in dl_page_source.split("\n"):
if '"download-button"' in line: # Should have the right line
return line.split('data-href="')[1].split('"')[0]
except:
return None
except: pass
return None
def check_iasl(self, legacy=False, try_downloading=True):
if sys.platform == "win32":
targets = (os.path.join(os.path.dirname(os.path.realpath(__file__)), "iasl-legacy.exe" if legacy else "iasl.exe"),)
else:
if legacy:
targets = (os.path.join(os.path.dirname(os.path.realpath(__file__)), "iasl-legacy"),)
else:
targets = (
os.path.join(os.path.dirname(os.path.realpath(__file__)), "iasl-dev"),
os.path.join(os.path.dirname(os.path.realpath(__file__)), "iasl-stable"),
os.path.join(os.path.dirname(os.path.realpath(__file__)), "iasl")
)
target = next((t for t in targets if os.path.exists(t)),None)
if target or not try_downloading:
# Either found it - or we didn't, and have already tried downloading
return target
# Need to download
temp = tempfile.mkdtemp()
try:
if sys.platform == "darwin":
self._download_and_extract(temp,self.iasl_url_macOS_legacy if legacy else self.iasl_url_macOS)
elif sys.platform.startswith("linux"):
self._download_and_extract(temp,self.iasl_url_linux_legacy if legacy else self.iasl_url_linux)
elif sys.platform == "win32":
iasl_url_windows = self.iasl_url_windows_legacy if legacy else self.get_latest_iasl()
if not iasl_url_windows: raise Exception("Could not get latest iasl for Windows")
self._download_and_extract(temp,iasl_url_windows)
else:
raise Exception("Unknown OS")
except Exception as e:
print("An error occurred :(\n - {}".format(e))
shutil.rmtree(temp, ignore_errors=True)
# Check again after downloading
return self.check_iasl(legacy=legacy,try_downloading=False)
def _download_and_extract(self, temp, url):
self.u.head("Gathering Files")
print("")
print("Please wait for download iasl...")
print("")
ztemp = tempfile.mkdtemp(dir=temp)
zfile = os.path.basename(url)
#print("Downloading {}".format(os.path.basename(url)))
#self.dl.stream_to_file(url, os.path.join(ztemp,zfile), progress=False, headers=self.h)
self.fetcher.download_and_save_file(url, os.path.join(ztemp,zfile), False)
search_dir = ztemp
if zfile.lower().endswith(".zip"):
print(" - Extracting")
search_dir = tempfile.mkdtemp(dir=temp)
# Extract with built-in tools \o/
with zipfile.ZipFile(os.path.join(ztemp,zfile)) as z:
z.extractall(search_dir)
script_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)))
for x in os.listdir(search_dir):
if x.lower().startswith(("iasl","acpidump")):
# Found one
print(" - Found {}".format(x))
if sys.platform != "win32":
print(" - Chmod +x")
self.r.run({"args":["chmod","+x",os.path.join(search_dir,x)]})
print(" - Copying to {} directory".format(os.path.basename(script_dir)))
shutil.copy(os.path.join(search_dir,x), os.path.join(script_dir,x))
def dump_tables(self, output, disassemble=False):
# Helper to dump all ACPI tables to the specified
# output path
self.u.head("Dumping ACPI Tables")
print("")
res = self.check_output(output)
if os.name == "nt":
target = os.path.join(os.path.dirname(os.path.realpath(__file__)),"acpidump.exe")
if os.path.exists(target):
# Dump to the target folder
print("Dumping tables to {}...".format(res))
cwd = os.getcwd()
os.chdir(res)
out = self.r.run({"args":[target, "-b"]})
os.chdir(cwd)
if out[2] != 0:
print(" - {}".format(out[1]))
return
# Iterate the dumped files and ensure the names are uppercase, and the
# extension used is .aml, not the default .dat
print("Updating names...")
for f in os.listdir(res):
new_name = f.upper()
if new_name.endswith(".DAT"):
new_name = new_name[:-4]+".aml"
if new_name != f:
# Something changed - print it and rename it
try:
os.rename(os.path.join(res,f),os.path.join(res,new_name))
except Exception as e:
print(" - {} -> {} 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

505
Scripts/efi_builder.py Executable file
View File

@@ -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)

317
Scripts/gathering_files.py Executable file
View File

@@ -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 {}

112
Scripts/github.py Executable file
View File

@@ -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

774
Scripts/kext_maestro.py Executable file
View File

@@ -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

69
Scripts/resource_fetcher.py Executable file
View File

@@ -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)

154
Scripts/run.py Executable file
View File

@@ -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

58
Scripts/smbios.py Executable file
View File

@@ -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(),
}

244
Scripts/utils.py Executable file
View File

@@ -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)

4
requirements.txt Normal file
View File

@@ -0,0 +1,4 @@
bs4
requests
python-dotenv
pytz

3
version.json Normal file
View File

@@ -0,0 +1,3 @@
{
"version": "0.0.1"
}