Compare commits
307 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6cd5a7eab9 | |||
| d119cf6e96 | |||
| 9b3a878c18 | |||
| 365b264656 | |||
| 1184d6aecb | |||
| b12edf70bb | |||
| 53c1da8f94 | |||
| 213b810279 | |||
| 8a4617d3c2 | |||
| c108b31954 | |||
| fd6829f757 | |||
| dabb2cc9a0 | |||
| 4ecb06c901 | |||
| 375bc4cc69 | |||
| 9265ff53d0 | |||
| 75ad56338b | |||
| db24ce7708 | |||
| 2d45ecff22 | |||
| 5d98f3866c | |||
| 106f31db6a | |||
| 9a5bdc9b4f | |||
| 0b829be798 | |||
| 94bb75fb7c | |||
| 7d84d0f83e | |||
| bc40b61ef1 | |||
| 73c3d5fc81 | |||
| 13575029c0 | |||
| ea016382f2 | |||
| 782344eed8 | |||
| 95fb7859d2 | |||
| 9d3e626b55 | |||
| a6e8b9037a | |||
| c9f91ecee9 | |||
| 7cb2d3f143 | |||
| a975b4937a | |||
| fce8e0fef0 | |||
| 12fe55a258 | |||
| 3bbc2c1f4c | |||
| 99671b754f | |||
| 9fc5f6271b | |||
| 4647f3046e | |||
| c44cddabfa | |||
| 9ff91c29f2 | |||
| e303cc536c | |||
| afdfefc9ad | |||
| 3033914e2d | |||
| 70b124cfa0 | |||
| 38a5313ed2 | |||
| 9291e2777d | |||
| 465da5136d | |||
| 568e7481d8 | |||
| a0297933ce | |||
| 50dad6801b | |||
| ee7475a9d4 | |||
| ba988f1d3f | |||
| db029ed29f | |||
| 41d38975f7 | |||
| eecadab387 | |||
| e27e6c0b2d | |||
| 30a5d646ec | |||
| 882fb3e049 | |||
| 0423781363 | |||
| 43cfb3cd10 | |||
| de15c9746f | |||
| 1371bf89e0 | |||
| 3b8f8d7fc8 | |||
| a828c214b5 | |||
| 3381144d2e | |||
| a19883f875 | |||
| 482722af0a | |||
| 02bac61c9c | |||
| e8ee5831d3 | |||
| 083b4f0d3b | |||
| c0280b43f2 | |||
| d153e977a7 | |||
| eee7bf0c97 | |||
| 0c94606fcf | |||
| ed75bab7b2 | |||
| bff6e0d277 | |||
| c325017675 | |||
| 4b12c9a9fc | |||
| 0d57744efa | |||
| e882d64d8a | |||
| 16f910e350 | |||
| e2c2ef9788 | |||
| a98b4adead | |||
| 186fe53279 | |||
| c9917c826a | |||
| aedebecae2 | |||
| 482dd0e8f8 | |||
| cae2e7de80 | |||
| e76ce05e29 | |||
| a98174be85 | |||
| b68cfbf794 | |||
| 17d8f2884e | |||
| 050b8fa7df | |||
| c30c9b2168 | |||
| 358735a199 | |||
| d909bbc297 | |||
| 2adb2f82d7 | |||
| 5a013127ec | |||
| 1219e5c244 | |||
| 4aec48c2ca | |||
| 8d54ddf426 | |||
| c21cdb8055 | |||
| 05824e6acd | |||
| b3b680f073 | |||
| 598fe85243 | |||
| e7ac84fca3 | |||
| b9ea6be842 | |||
| d46dbc0fa8 | |||
| 0e10f12ec0 | |||
| 8f178b2c29 | |||
| d41fe80b8e | |||
| 96e992bd26 | |||
| 465c421707 | |||
| f7e9622084 | |||
| 79e000f63d | |||
| 10af0e8c93 | |||
| d13cf0e29a | |||
| 1671922f7e | |||
| c9da795bf3 | |||
| 69eb1401a9 | |||
| aa06ac119f | |||
| 1afee59c95 | |||
| 4decad6f6b | |||
| a37f786a37 | |||
| 8f98e572e1 | |||
| c818f8af82 | |||
| fac8bcc20c | |||
| 1d004f2788 | |||
| cef4ea786a | |||
| 8ebf24d8e7 | |||
| 69b02f7e46 | |||
| b788e05396 | |||
| 5dc4e74c98 | |||
| 436ef1cff6 | |||
| d77a78cdf1 | |||
| 66cb855db0 | |||
| fb3aa9628d | |||
| 89c81d9f22 | |||
| cffcfad42a | |||
| 21f5976d35 | |||
| 21ada251fe | |||
| 44801c50f3 | |||
| 6a1fb8cb73 | |||
| 8e8cefb3f6 | |||
| e0e4fa3b3e | |||
| b9dbda5ddc | |||
| 931a2c516f | |||
| 2f9e1cf4df | |||
| 68d1c38f3b | |||
| c4acea6c82 | |||
| 7ebabddfe0 | |||
| a047ddffc0 | |||
| 92992a5406 | |||
| 593f850693 | |||
| f87db1ac14 | |||
| 363e498462 | |||
| a03dd44924 | |||
| 554b27a82a | |||
| 7062ead4fd | |||
| 5f2f084091 | |||
| a560121775 | |||
| b0a346709e | |||
| 7b64cd2a8e | |||
| 9ecfecb83e | |||
| ec4565263d | |||
| ed1da364e5 | |||
| 942dbbc8fa | |||
| 3e8f9cbbf2 | |||
| 322b5dac79 | |||
| 5a85fee3f1 | |||
| ca472b6750 | |||
| 8e3d0af08e | |||
| 12f2b900ca | |||
| 6228dff809 | |||
| d34b3190f7 | |||
| 4f5348c7d4 | |||
| aff871f127 | |||
| 9f00359e17 | |||
| 0871436488 | |||
| 6aa598b029 | |||
| 83e22fa9f0 | |||
| a230340578 | |||
| 2da78c6591 | |||
| 46350200d7 | |||
| 00502e94b5 | |||
| 70ce7ee106 | |||
| cf4ae38699 | |||
| 09f83e48ff | |||
| bcbce5dd48 | |||
| 0a0ef50caf | |||
| e20f1587cd | |||
| 715e3856f2 | |||
| 850166eca1 | |||
| 00cca7be69 | |||
| 0a43f69e87 | |||
| c84d2d895e | |||
| 87d5f45277 | |||
| 137f37cd41 | |||
| 18722d7874 | |||
| 307e1351df | |||
| 441fbd63bb | |||
| 073b723c09 | |||
| 37bc73865d | |||
| e2bced978e | |||
| a6d8c4343f | |||
| d5654d64d5 | |||
| 06459eb37b | |||
| d08fea551e | |||
| 924692bf1c | |||
| ec9e8916b1 | |||
| d3be8ee2b7 | |||
| 16f869fe5a | |||
| a90858193e | |||
| 6dcf63009e | |||
| 5f8f86b5a7 | |||
| a78117e094 | |||
| 44421920b3 | |||
| 0e79fbda05 | |||
| 9ab89c634b | |||
| 0a6f12f448 | |||
| 8612bdd03d | |||
| f08d3e12ca | |||
| deda47f461 | |||
| 2751f5e254 | |||
| 2ac1ff1d0a | |||
| 30e8c70055 | |||
| 62600b3be0 | |||
| 57b9130cf7 | |||
| b557a7fa16 | |||
| 73e336adfa | |||
| 86b27a3088 | |||
| cce699a465 | |||
| d662a39a12 | |||
| 49c6c2c529 | |||
| 29f3eec957 | |||
| c1d875d841 | |||
| d28e3c4f08 | |||
| cedfb95f9b | |||
| 59430ee83e | |||
| b436d2a7f4 | |||
| 84d2ad70e6 | |||
| 1bd9549e45 | |||
| 2409a0d04e | |||
| 635fed0427 | |||
| 5d7e75c5d8 | |||
| c0e97b4e96 | |||
| b2842dcd52 | |||
| 112f1016ed | |||
| c78c504043 | |||
| 27349c5c69 | |||
| 872aa2b358 | |||
| 72abc0f219 | |||
| 4d565eade6 | |||
| 2df7e46cb1 | |||
| 105205312b | |||
| 97f7461aa9 | |||
| 7e2eaf43ca | |||
| d752ab0151 | |||
| c87a7cb2c0 | |||
| 6aff2803e5 | |||
| fcfca6efda | |||
| 0ebe832f8e | |||
| 86ed82dcec | |||
| 769b69999f | |||
| 91ee066751 | |||
| 404d08ef6d | |||
| 11487cd591 | |||
| 51a30977d2 | |||
| c0366ba40c | |||
| 3f5bc3464d | |||
| fcd6be71b0 | |||
| ad22cf5051 | |||
| 8f66c50721 | |||
| 6f834e99d2 | |||
| 86c7b31b6d | |||
| 6d918b565f | |||
| 52575a44b2 | |||
| d5eebd6ab4 | |||
| 3f44ecb77a | |||
| 9bd4426225 | |||
| 4af0a33f1f | |||
| 636bde6343 | |||
| 16579e0b1f | |||
| 292d3faa9e | |||
| 6d2f7f6e54 | |||
| a131a41874 | |||
| 48ffc19193 | |||
| e75c0dbaa1 | |||
| 0c0f63a2a8 | |||
| c9942aa828 | |||
| ca56f0747e | |||
| e77c01d00a | |||
| c85775922e | |||
| da0c9c2ce9 | |||
| 42b388317e | |||
| 6a570ae57e | |||
| 5e6aa45658 | |||
| 5fa8af1c9a | |||
| 2e4bf9ef1b | |||
| ba9f55679d | |||
| 2c999a550b | |||
| 805de248d3 | |||
| 1240874e41 | |||
| feff50e7e0 |
@@ -1,10 +1,5 @@
|
||||
#!/bin/sh -ex
|
||||
|
||||
# Setup Qt variables
|
||||
export QT_BASE_DIR=/opt/qt"${QTVERMIN}"
|
||||
export PATH="$QT_BASE_DIR"/bin:"$PATH"
|
||||
export LD_LIBRARY_PATH="$QT_BASE_DIR"/lib/x86_64-linux-gnu:"$QT_BASE_DIR"/lib
|
||||
|
||||
if [ -z "$CIRRUS_CI" ]; then
|
||||
cd rpcs3 || exit 1
|
||||
fi
|
||||
|
||||
+55
-19
@@ -1,13 +1,17 @@
|
||||
#!/bin/sh -ex
|
||||
|
||||
export HOMEBREW_NO_AUTO_UPDATE=1
|
||||
brew install -f --overwrite nasm ninja git p7zip create-dmg ccache pipenv
|
||||
|
||||
#/usr/sbin/softwareupdate --install-rosetta --agree-to-license
|
||||
arch -x86_64 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
||||
arch -x86_64 /usr/local/homebrew/bin/brew update
|
||||
arch -x86_64 /usr/local/homebrew/bin/brew install -f --overwrite llvm@16 sdl2 glew cmake
|
||||
arch -x86_64 /usr/local/homebrew/bin/brew link -f llvm@16
|
||||
arch -x86_64 /usr/local/bin/brew update
|
||||
arch -x86_64 /usr/local/bin/brew install -f --overwrite llvm@16 sdl2 glew cmake faudio vulkan-headers
|
||||
arch -x86_64 /usr/local/bin/brew link -f llvm@16
|
||||
|
||||
# moltenvk based on commit for 1.2.4 release
|
||||
wget https://raw.githubusercontent.com/Homebrew/homebrew-core/b233d4f9f40f26d81da11140defbfd578cfe4a69/Formula/molten-vk.rb
|
||||
arch -x86_64 /usr/local/bin/brew install -f --overwrite ./molten-vk.rb
|
||||
#export MACOSX_DEPLOYMENT_TARGET=12.0
|
||||
export CXX=clang++
|
||||
export CC=clang
|
||||
@@ -15,7 +19,7 @@ export CC=clang
|
||||
export BREW_PATH;
|
||||
BREW_PATH="$(brew --prefix)"
|
||||
export BREW_X64_PATH;
|
||||
BREW_X64_PATH="$("/usr/local/homebrew/bin/brew" --prefix)"
|
||||
BREW_X64_PATH="$("/usr/local/bin/brew" --prefix)"
|
||||
export BREW_BIN="/usr/local/bin"
|
||||
export BREW_SBIN="/usr/local/sbin"
|
||||
export CMAKE_EXTRA_OPTS='-DLLVM_TARGETS_TO_BUILD=X86'
|
||||
@@ -24,23 +28,39 @@ export WORKDIR;
|
||||
WORKDIR="$(pwd)"
|
||||
|
||||
# Get Qt
|
||||
git clone https://github.com/engnr/qt-downloader.git
|
||||
cd qt-downloader
|
||||
git checkout f52efee0f18668c6d6de2dec0234b8c4bc54c597
|
||||
"/opt/homebrew/bin/pipenv" run pip3 install py7zr requests semantic_version lxml
|
||||
"/opt/homebrew/bin/pipenv" run ./qt-downloader macos desktop 5.15.2 clang_64 --opensource
|
||||
cd ..
|
||||
if [ ! -d "/tmp/Qt/$QT_VER" ]; then
|
||||
mkdir -p "/tmp/Qt"
|
||||
git clone https://github.com/engnr/qt-downloader.git
|
||||
cd qt-downloader
|
||||
git checkout f52efee0f18668c6d6de2dec0234b8c4bc54c597
|
||||
cd "/tmp/Qt"
|
||||
"/opt/homebrew/bin/pipenv" run pip3 install py7zr requests semantic_version lxml
|
||||
mkdir -p "$QT_VER/macos" ; ln -s "macos" "$QT_VER/clang_64"
|
||||
"/opt/homebrew/bin/pipenv" run "$WORKDIR/qt-downloader/qt-downloader" macos desktop "$QT_VER" clang_64 --opensource --addons qtmultimedia
|
||||
fi
|
||||
|
||||
export Qt5_DIR="$WORKDIR/qt-downloader/5.15.2/clang_64/lib/cmake/Qt5"
|
||||
cd "$WORKDIR"
|
||||
ditto "/tmp/Qt/$QT_VER" "qt-downloader/$QT_VER"
|
||||
|
||||
export Qt6_DIR="$WORKDIR/qt-downloader/$QT_VER/clang_64/lib/cmake/Qt$QT_VER_MAIN"
|
||||
export SDL2_DIR="$BREW_X64_PATH/opt/sdl2/lib/cmake/SDL2"
|
||||
|
||||
export PATH="$BREW_X64_PATH/opt/llvm@16/bin:$WORKDIR/qt-downloader/5.15.2/clang_64/bin:$BREW_BIN:$BREW_SBIN:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/Library/Apple/usr/bin:$PATH"
|
||||
export PATH="$BREW_X64_PATH/opt/llvm@16/bin:$WORKDIR/qt-downloader/$QT_VER/clang_64/bin:$BREW_BIN:$BREW_SBIN:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/Library/Apple/usr/bin:$PATH"
|
||||
export LDFLAGS="-L$BREW_X64_PATH/lib -Wl,-rpath,$BREW_X64_PATH/lib"
|
||||
export CPPFLAGS="-I$BREW_X64_PATH/include -msse -msse2 -mcx16 -no-pie"
|
||||
export LIBRARY_PATH="$BREW_X64_PATH/lib"
|
||||
export LD_LIBRARY_PATH="$BREW_X64_PATH/lib"
|
||||
|
||||
git submodule update --init --recursive --depth 1
|
||||
export VULKAN_SDK
|
||||
VULKAN_SDK="$BREW_X64_PATH/opt/molten-vk"
|
||||
ln -s "$VULKAN_SDK/lib/libMoltenVK.dylib" "$VULKAN_SDK/lib/libvulkan.dylib"
|
||||
export VK_ICD_FILENAMES="$VULKAN_SDK/share/vulkan/icd.d/MoltenVK_icd.json"
|
||||
|
||||
export LLVM_DIR
|
||||
LLVM_DIR="BREW_X64_PATH/opt/llvm@16"
|
||||
# exclude FAudio, SPIRV and LLVM, and sdl from submodule update
|
||||
# shellcheck disable=SC2046
|
||||
git submodule -q update --init --depth=1 --jobs=8 $(awk '/path/ && !/FAudio/ && !/llvm/ && !/SPIRV/ && !/SDL/ { print $3 }' .gitmodules)
|
||||
|
||||
# 3rdparty fixes
|
||||
sed -i '' "s/extern const double NSAppKitVersionNumber;/const double NSAppKitVersionNumber = 1343;/g" 3rdparty/hidapi/hidapi/mac/hid.c
|
||||
@@ -48,14 +68,30 @@ sed -i '' "s/extern const double NSAppKitVersionNumber;/const double NSAppKitVer
|
||||
mkdir build && cd build || exit 1
|
||||
|
||||
"$BREW_X64_PATH/bin/cmake" .. \
|
||||
-DUSE_SDL=ON -DUSE_DISCORD_RPC=OFF -DUSE_VULKAN=ON -DUSE_ALSA=OFF -DUSE_PULSE=OFF -DUSE_AUDIOUNIT=ON \
|
||||
-DLLVM_CCACHE_BUILD=OFF -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF \
|
||||
-DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=OFF \
|
||||
-DLLVM_INCLUDE_UTILS=OFF -DLLVM_USE_PERF=OFF -DLLVM_ENABLE_Z3_SOLVER=OFF \
|
||||
-DUSE_SDL=ON \
|
||||
-DUSE_DISCORD_RPC=ON \
|
||||
-DUSE_VULKAN=ON \
|
||||
-DUSE_ALSA=OFF \
|
||||
-DUSE_PULSE=OFF \
|
||||
-DUSE_AUDIOUNIT=ON \
|
||||
-DLLVM_CCACHE_BUILD=OFF \
|
||||
-DLLVM_BUILD_RUNTIME=OFF \
|
||||
-DLLVM_BUILD_TOOLS=OFF \
|
||||
-DLLVM_INCLUDE_DOCS=OFF \
|
||||
-DLLVM_INCLUDE_EXAMPLES=OFF \
|
||||
-DLLVM_INCLUDE_TESTS=OFF \
|
||||
-DLLVM_INCLUDE_TOOLS=OFF \
|
||||
-DLLVM_INCLUDE_UTILS=OFF \
|
||||
-DLLVM_USE_PERF=OFF \
|
||||
-DLLVM_ENABLE_Z3_SOLVER=OFF \
|
||||
-DUSE_NATIVE_INSTRUCTIONS=OFF \
|
||||
-DUSE_SYSTEM_MVK=OFF \
|
||||
-DUSE_SYSTEM_MVK=ON \
|
||||
-DUSE_SYSTEM_FAUDIO=ON \
|
||||
-DUSE_SYSTEM_SDL=ON \
|
||||
$CMAKE_EXTRA_OPTS \
|
||||
-DLLVM_TARGET_ARCH=X86_64 -DCMAKE_OSX_ARCHITECTURES=x86_64 -DCMAKE_IGNORE_PATH="$BREW_PATH/lib" \
|
||||
-DLLVM_TARGET_ARCH=X86_64 \
|
||||
-DCMAKE_OSX_ARCHITECTURES=x86_64 \
|
||||
-DCMAKE_IGNORE_PATH="$BREW_PATH/lib" \
|
||||
-G Ninja
|
||||
|
||||
"$BREW_PATH/bin/ninja"; build_status=$?;
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ echo "AVVER=$AVVER" >> ../.ci/ci-vars.env
|
||||
cd bin
|
||||
mkdir "rpcs3.app/Contents/lib/"
|
||||
|
||||
cp "/usr/local/Homebrew/opt/llvm@16/lib/c++/libc++abi.1.0.dylib" "rpcs3.app/Contents/lib/libc++abi.1.dylib"
|
||||
cp "/usr/local/opt/llvm@16/lib/c++/libc++abi.1.0.dylib" "rpcs3.app/Contents/lib/libc++abi.1.dylib"
|
||||
|
||||
rm -rf "rpcs3.app/Contents/Frameworks/QtPdf.framework" \
|
||||
"rpcs3.app/Contents/Frameworks/QtQml.framework" \
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# NOTE: this script is run under root permissions
|
||||
# shellcheck shell=sh disable=SC2096
|
||||
|
||||
# RPCS3 often needs recent Qt5 and Vulkan-Headers
|
||||
# RPCS3 often needs recent Qt and Vulkan-Headers
|
||||
sed -i '' 's/quarterly/latest/' /etc/pkg/FreeBSD.conf
|
||||
|
||||
export ASSUME_ALWAYS_YES=true
|
||||
@@ -11,8 +11,8 @@ pkg info # debug
|
||||
# Prefer newer Clang than in base system (see also .ci/build-freebsd.sh)
|
||||
pkg install llvm16
|
||||
|
||||
# Mandatory dependencies (qt5-dbus and qt5-gui are pulled via qt5-widgets)
|
||||
pkg install git ccache cmake ninja qt5-qmake qt5-buildtools qt5-widgets qt5-concurrent qt5-multimedia qt5-svg glew openal-soft ffmpeg
|
||||
# Mandatory dependencies (qt6-base and qt6-svg are pulled via qt6-multimedia)
|
||||
pkg install git ccache cmake ninja qt6-multimedia glew openal-soft ffmpeg
|
||||
|
||||
# Optional dependencies (libevdev is pulled by qt5-gui)
|
||||
# Optional dependencies (libevdev is pulled by qt6-base)
|
||||
pkg install pkgconf alsa-lib pulseaudio sdl2 evdev-proto vulkan-headers vulkan-loader
|
||||
|
||||
+11
-10
@@ -11,25 +11,26 @@ PR_NUMBER="$SYSTEM_PULLREQUEST_PULLREQUESTID"
|
||||
QT_HOST="http://qt.mirror.constant.com/"
|
||||
QT_URL_VER=$(echo "$QT_VER" | sed "s/\.//g")
|
||||
QT_VER_MSVC_UP=$(echo "${QT_VER_MSVC}" | tr '[:lower:]' '[:upper:]')
|
||||
QT_PREFIX="online/qtsdkrepository/windows_x86/desktop/qt${QT_VER_MAIN}_${QT_URL_VER}/qt.qt${QT_VER_MAIN}.${QT_URL_VER}.win64_${QT_VER_MSVC}_64/${QT_VER}-0-${QT_DATE}"
|
||||
QT_SUFFIX="-Windows-Windows_10-${QT_VER_MSVC_UP}-Windows-Windows_10-X86_64.7z"
|
||||
QT_BASE_URL="${QT_HOST}${QT_PREFIX}qtbase${QT_SUFFIX}"
|
||||
QT_WINE_URL="${QT_HOST}${QT_PREFIX}qtwinextras${QT_SUFFIX}"
|
||||
QT_DECL_URL="${QT_HOST}${QT_PREFIX}qtdeclarative${QT_SUFFIX}"
|
||||
QT_TOOL_URL="${QT_HOST}${QT_PREFIX}qttools${QT_SUFFIX}"
|
||||
QT_MM_URL="${QT_HOST}${QT_PREFIX}qtmultimedia${QT_SUFFIX}"
|
||||
QT_SVG_URL="${QT_HOST}${QT_PREFIX}qtsvg${QT_SUFFIX}"
|
||||
QT_PREFIX="online/qtsdkrepository/windows_x86/desktop/qt${QT_VER_MAIN}_${QT_URL_VER}/qt.qt${QT_VER_MAIN}.${QT_URL_VER}."
|
||||
QT_PREFIX_2="win64_${QT_VER_MSVC}_64/${QT_VER}-0-${QT_DATE}"
|
||||
QT_SUFFIX="-Windows-Windows_10_22H2-${QT_VER_MSVC_UP}-Windows-Windows_10_22H2-X86_64.7z"
|
||||
QT_BASE_URL="${QT_HOST}${QT_PREFIX}${QT_PREFIX_2}qtbase${QT_SUFFIX}"
|
||||
QT_DECL_URL="${QT_HOST}${QT_PREFIX}${QT_PREFIX_2}qtdeclarative${QT_SUFFIX}"
|
||||
QT_TOOL_URL="${QT_HOST}${QT_PREFIX}${QT_PREFIX_2}qttools${QT_SUFFIX}"
|
||||
QT_MM_URL="${QT_HOST}${QT_PREFIX}addons.qtmultimedia.${QT_PREFIX_2}qtmultimedia${QT_SUFFIX}"
|
||||
QT_SVG_URL="${QT_HOST}${QT_PREFIX}${QT_PREFIX_2}qtsvg${QT_SUFFIX}"
|
||||
QT_5CMP_URL="${QT_HOST}${QT_PREFIX}qt5compat.${QT_PREFIX_2}qt5compat${QT_SUFFIX}"
|
||||
LLVMLIBS_URL='https://github.com/RPCS3/llvm-mirror/releases/download/custom-build-win-16.0.1/llvmlibs_mt.7z'
|
||||
GLSLANG_URL='https://github.com/RPCS3/glslang/releases/download/custom-build-win/glslanglibs_mt.7z'
|
||||
VULKAN_SDK_URL="https://www.dropbox.com/s/cs77c3iv5mbo0bt/VulkanSDK-${VULKAN_VER}-Installer.exe"
|
||||
|
||||
DEP_URLS=" \
|
||||
$QT_BASE_URL \
|
||||
$QT_WINE_URL \
|
||||
$QT_DECL_URL \
|
||||
$QT_TOOL_URL \
|
||||
$QT_MM_URL \
|
||||
$QT_SVG_URL \
|
||||
$QT_5CMP_URL \
|
||||
$LLVMLIBS_URL \
|
||||
$GLSLANG_URL \
|
||||
$VULKAN_SDK_URL"
|
||||
@@ -40,7 +41,7 @@ DEP_URLS=" \
|
||||
# Pull all the submodules except llvm, since it is built separately and we just download that build
|
||||
# Note: Tried to use git submodule status, but it takes over 20 seconds
|
||||
# shellcheck disable=SC2046
|
||||
git submodule -q update --init --depth=1 --jobs=8 $(awk '/path/ && !/llvm/ && !/SPIRV/ { print $3 }' .gitmodules)
|
||||
git submodule -q update --init --depth=1 --jobs=8 $(awk '/path/ && !/FAudio/ && !/llvm/ && !/SPIRV/ { print $3 }' .gitmodules)
|
||||
|
||||
# Git bash doesn't have rev, so here it is
|
||||
rev()
|
||||
|
||||
+10
-6
@@ -6,6 +6,8 @@ env:
|
||||
BUILD_SOURCEVERSION: $CIRRUS_CHANGE_IN_REPO
|
||||
BUILD_SOURCEBRANCHNAME: $CIRRUS_BRANCH
|
||||
RPCS3_TOKEN: ENCRYPTED[!a4c3850e29ab150692286a74bec29819d25971a7ec431b86de2a35f7ed90c5b2ab3c93469f9298e30924d843599110e9!]
|
||||
QT_VER_MAIN: '6'
|
||||
QT_VER: '6.5.2'
|
||||
|
||||
windows_task:
|
||||
matrix:
|
||||
@@ -17,11 +19,9 @@ windows_task:
|
||||
env:
|
||||
CIRRUS_SHELL: "bash"
|
||||
COMPILER: msvc
|
||||
QT_VER_MAIN: '5'
|
||||
BUILD_ARTIFACTSTAGINGDIRECTORY: ${CIRRUS_WORKING_DIR}\artifacts\
|
||||
QT_VER: '5.15.2'
|
||||
QT_VER_MSVC: 'msvc2019'
|
||||
QT_DATE: '202011130602'
|
||||
QT_DATE: '202307080351'
|
||||
QTDIR: C:\Qt\${QT_VER}\${QT_VER_MSVC}_64
|
||||
VULKAN_VER: '1.3.224.1'
|
||||
VULKAN_SDK_SHA: '2029e652e39ee6a6036cff3765da31e1e6c595fd2413d3cd111dfab7855621ea'
|
||||
@@ -61,7 +61,7 @@ windows_task:
|
||||
|
||||
linux_task:
|
||||
container:
|
||||
image: rpcs3/rpcs3-ci-bionic:1.8
|
||||
image: rpcs3/rpcs3-ci-focal:1.0
|
||||
cpu: 4
|
||||
memory: 16G
|
||||
env:
|
||||
@@ -108,7 +108,7 @@ freebsd_task:
|
||||
matrix:
|
||||
- name: Cirrus FreeBSD
|
||||
freebsd_instance:
|
||||
image_family: freebsd-13-1
|
||||
image_family: freebsd-13-2
|
||||
cpu: 8
|
||||
memory: 8G
|
||||
env:
|
||||
@@ -121,12 +121,16 @@ freebsd_task:
|
||||
|
||||
macos_task:
|
||||
timeout_in: 12000m
|
||||
homebrew_cache:
|
||||
folder: /Users/admin/Library/Caches/Homebrew
|
||||
qt_cache:
|
||||
folder: /tmp/Qt
|
||||
ccache_cache:
|
||||
folder: /tmp/ccache_dir
|
||||
matrix:
|
||||
- name: Cirrus macOS
|
||||
macos_instance:
|
||||
image: ghcr.io/cirruslabs/macos-monterey-xcode:14
|
||||
image: ghcr.io/cirruslabs/macos-monterey-xcode:latest
|
||||
mac_script:
|
||||
- mkdir artifacts
|
||||
- chmod +x ".ci/build-mac.sh"
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
*.wav
|
||||
|
||||
/build
|
||||
/build-*
|
||||
/lib
|
||||
/tmp
|
||||
/ipch
|
||||
@@ -135,3 +136,7 @@ yaml-cpp.pc
|
||||
cacert.pem
|
||||
|
||||
_ReSharper.*/
|
||||
CMakeUserPresets.json
|
||||
|
||||
.cache/
|
||||
.lldbinit
|
||||
|
||||
Vendored
+36
-38
@@ -4,6 +4,11 @@ include(CMakeDependentOption)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
|
||||
# Warnings are silenced for 3rdparty code
|
||||
if(NOT MSVC)
|
||||
add_compile_options("$<$<COMPILE_LANGUAGE:CXX,C>:-w>")
|
||||
endif()
|
||||
|
||||
# Dummy target to use when lib isn't available
|
||||
add_library(3rdparty_dummy_lib INTERFACE)
|
||||
|
||||
@@ -42,16 +47,16 @@ endif()
|
||||
|
||||
|
||||
# libusb
|
||||
if(CMAKE_SYSTEM MATCHES "DragonFly|FreeBSD")
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "DragonFly|FreeBSD")
|
||||
pkg_check_modules(LIBUSB REQUIRED IMPORTED_TARGET libusb-1.0>=1.0 )
|
||||
CMAKE_DEPENDENT_OPTION( USE_SYSTEM_LIBUSB "Use system libusb-1.0 as shared library" ON
|
||||
cmake_dependent_option(USE_SYSTEM_LIBUSB "Use system libusb-1.0 as shared library" ON
|
||||
"LIBUSB_FOUND" OFF)
|
||||
else()
|
||||
pkg_check_modules(LIBUSB IMPORTED_TARGET libusb-1.0>=1.0 )
|
||||
CMAKE_DEPENDENT_OPTION( USE_SYSTEM_LIBUSB "Use system libusb-1.0 as shared library" OFF
|
||||
cmake_dependent_option(USE_SYSTEM_LIBUSB "Use system libusb-1.0 as shared library" OFF
|
||||
"LIBUSB_FOUND" OFF)
|
||||
endif()
|
||||
if(CMAKE_SYSTEM MATCHES "DragonFly|FreeBSD")
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "DragonFly|FreeBSD")
|
||||
# Always use system libusb as reference implementation isn't supported
|
||||
add_library(usb-1.0-shared INTERFACE)
|
||||
target_link_libraries(usb-1.0-shared INTERFACE PkgConfig::LIBUSB)
|
||||
@@ -100,10 +105,6 @@ endif()
|
||||
|
||||
# OpenGL
|
||||
|
||||
# Prefer GLVND for OpenGL rather than legacy, unless it's been defined elsewhere, in the case of AppImage builds
|
||||
if(NOT DEFINED OpenGL_GL_PREFERENCE)
|
||||
set(OpenGL_GL_PREFERENCE GLVND)
|
||||
endif()
|
||||
find_package(OpenGL REQUIRED)
|
||||
|
||||
add_library(3rdparty_opengl INTERFACE)
|
||||
@@ -111,17 +112,14 @@ target_include_directories(3rdparty_opengl INTERFACE GL)
|
||||
|
||||
if (WIN32)
|
||||
if(NOT MSVC)
|
||||
target_link_libraries(3rdparty_opengl INTERFACE ${OPENGL_LIBRARIES} opengl32.lib glu32.lib)
|
||||
target_link_libraries(3rdparty_opengl INTERFACE OpenGL::GL OpenGL::GLU)
|
||||
else()
|
||||
target_link_libraries(3rdparty_opengl INTERFACE dxgi.lib d2d1.lib dwrite.lib)
|
||||
endif()
|
||||
elseif(APPLE)
|
||||
target_link_libraries(3rdparty_opengl INTERFACE OpenGL::GL OpenGL::GLU)
|
||||
else()
|
||||
target_link_libraries(3rdparty_opengl INTERFACE ${OPENGL_LIBRARIES})
|
||||
|
||||
target_compile_definitions(3rdparty_opengl
|
||||
INTERFACE
|
||||
-DGL_GLEXT_PROTOTYPES
|
||||
-DGLX_GLXEXT_PROTOTYPES)
|
||||
target_link_libraries(3rdparty_opengl INTERFACE OpenGL::GL OpenGL::GLU OpenGL::GLX)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -160,9 +158,9 @@ set(VULKAN_TARGET 3rdparty_dummy_lib)
|
||||
if(USE_VULKAN)
|
||||
if(APPLE)
|
||||
if(USE_SYSTEM_MVK)
|
||||
message("-- RPCS3: Using system MoltenVK")
|
||||
message(STATUS "RPCS3: Using system MoltenVK")
|
||||
else()
|
||||
message("-- RPCS3: MoltenVK submodule")
|
||||
message(STATUS "RPCS3: MoltenVK submodule")
|
||||
|
||||
execute_process(COMMAND "${CMAKE_COMMAND}" -G "${CMAKE_GENERATOR}" .
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK"
|
||||
@@ -204,9 +202,9 @@ if(USE_VULKAN)
|
||||
|
||||
set(VULKAN_TARGET 3rdparty_vulkan)
|
||||
else()
|
||||
message("WARNING! USE_VULKAN was enabled, but libvulkan was not found. RPCS3 will be compiled without Vulkan support.")
|
||||
message(WARNING "USE_VULKAN was enabled, but libvulkan was not found. RPCS3 will be compiled without Vulkan support.")
|
||||
if(APPLE)
|
||||
message( FATAL_ERROR "ERROR! To build without Vulkan support on macOS, please disable USE_VULKAN.")
|
||||
message(FATAL_ERROR "To build without Vulkan support on macOS, please disable USE_VULKAN.")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
@@ -225,7 +223,7 @@ if(USE_FAUDIO)
|
||||
if (USE_SYSTEM_FAUDIO)
|
||||
if (NOT SDL2_FOUND OR SDL2_VERSION VERSION_LESS 2.0.12)
|
||||
message(WARNING
|
||||
"-- RPCS3: System FAudio requires SDL 2.0.9 or newer. Please note, this warning"
|
||||
"RPCS3: FAudio requires SDL 2.0.9 or newer. Please note, this warning"
|
||||
"can also be displayed with SDL2 versions between 2.0.9-2.0.12, as the"
|
||||
"CMake config files are not correctly installed. Since a valid SDL2"
|
||||
">=2.0.9 version cannot be found, building with FAudio will be skipped.")
|
||||
@@ -262,36 +260,36 @@ add_library(3rdparty_ffmpeg INTERFACE)
|
||||
|
||||
# Select the version of ffmpeg to use, default is builtin
|
||||
if(USE_SYSTEM_FFMPEG)
|
||||
message("-- RPCS3: using shared ffmpeg")
|
||||
message(STATUS "RPCS3: using shared ffmpeg")
|
||||
find_package(FFMPEG REQUIRED)
|
||||
|
||||
target_include_directories(3rdparty_ffmpeg INTERFACE ${FFMPEG_INCLUDE_DIR})
|
||||
target_link_libraries(3rdparty_ffmpeg INTERFACE ${FFMPEG_LIBRARIES})
|
||||
else()
|
||||
if (NOT MSVC AND WIN32)
|
||||
message("-- RPCS3: building ffmpeg submodule")
|
||||
message(STATUS "RPCS3: building ffmpeg submodule")
|
||||
|
||||
include(ProcessorCount)
|
||||
ProcessorCount(N)
|
||||
|
||||
ExternalProject_Add(ffmpeg-mingw
|
||||
DOWNLOAD_COMMAND ""
|
||||
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/ffmpeg
|
||||
BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/ffmpeg
|
||||
CONFIGURE_COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/ffmpeg/configure --prefix=./windows/x86_64 --arch=x86_64 --disable-avdevice --disable-programs --disable-avfilter --disable-postproc --disable-doc --disable-pthreads --enable-w32threads --disable-network --disable-everything --disable-encoders --disable-muxers --disable-hwaccels --disable-parsers --disable-protocols --enable-dxva2 --enable-static --disable-shared --enable-decoder=aac --enable-decoder=aac_latm --enable-decoder=atrac3 --enable-decoder=atrac3p --enable-decoder=mp3 --enable-decoder=pcm_s16le --enable-decoder=pcm_s8 --enable-decoder=h264 --enable-decoder=mpeg4 --enable-decoder=mpeg2video --enable-decoder=mjpeg --enable-decoder=mjpegb --enable-encoder=pcm_s16le --enable-encoder=ffv1 --enable-encoder=mpeg4 --enable-parser=h264 --enable-parser=mpeg4video --enable-parser=mpegaudio --enable-parser=mpegvideo --enable-parser=mjpeg --enable-parser=aac --enable-parser=aac_latm --enable-muxer=avi --enable-demuxer=h264 --enable-demuxer=m4v --enable-demuxer=mp3 --enable-demuxer=mpegvideo --enable-demuxer=mpegps --enable-demuxer=mjpeg --enable-demuxer=avi --enable-demuxer=aac --enable-demuxer=pmp --enable-demuxer=oma --enable-demuxer=pcm_s16le --enable-demuxer=pcm_s8 --enable-demuxer=wav --enable-hwaccel=h264_dxva2 --enable-indev=dshow --enable-protocol=file
|
||||
BUILD_COMMAND make -j 4
|
||||
CONFIGURE_COMMAND bash ${CMAKE_CURRENT_SOURCE_DIR}/ffmpeg/configure --prefix=./windows/x86_64 --arch=x86_64 --disable-avdevice --disable-programs --disable-avfilter --disable-postproc --disable-doc --disable-pthreads --enable-w32threads --disable-network --disable-everything --disable-encoders --disable-muxers --disable-hwaccels --disable-parsers --disable-protocols --enable-dxva2 --enable-static --disable-shared --enable-decoder=aac --enable-decoder=aac_latm --enable-decoder=atrac3 --enable-decoder=atrac3p --enable-decoder=mp3 --enable-decoder=pcm_s16le --enable-decoder=pcm_s8 --enable-decoder=h264 --enable-decoder=mpeg4 --enable-decoder=mpeg2video --enable-decoder=mjpeg --enable-decoder=mjpegb --enable-encoder=pcm_s16le --enable-encoder=ffv1 --enable-encoder=mpeg4 --enable-parser=h264 --enable-parser=mpeg4video --enable-parser=mpegaudio --enable-parser=mpegvideo --enable-parser=mjpeg --enable-parser=aac --enable-parser=aac_latm --enable-muxer=avi --enable-demuxer=h264 --enable-demuxer=m4v --enable-demuxer=mp3 --enable-demuxer=mpegvideo --enable-demuxer=mpegps --enable-demuxer=mjpeg --enable-demuxer=avi --enable-demuxer=aac --enable-demuxer=pmp --enable-demuxer=oma --enable-demuxer=pcm_s16le --enable-demuxer=pcm_s8 --enable-demuxer=wav --enable-hwaccel=h264_dxva2 --enable-indev=dshow --enable-protocol=file
|
||||
BUILD_COMMAND make -j ${N}
|
||||
INSTALL_COMMAND make install
|
||||
)
|
||||
|
||||
set(FFMPEG_LIB_AVFORMAT "${CMAKE_CURRENT_BINARY_DIR}/ffmpeg/windows/x86_64/lib/libavformat.a")
|
||||
set(FFMPEG_LIB_AVCODEC "${CMAKE_CURRENT_BINARY_DIR}/ffmpeg/windows/x86_64/lib/libavcodec.a")
|
||||
set(FFMPEG_LIB_AVUTIL "${CMAKE_CURRENT_BINARY_DIR}/ffmpeg/windows/x86_64/lib/libavutil.a")
|
||||
set(FFMPEG_LIB_SWSCALE "${CMAKE_CURRENT_BINARY_DIR}/ffmpeg/windows/x86_64/lib/libswscale.a")
|
||||
set(FFMPEG_LIB_SWRESAMPLE "${CMAKE_CURRENT_BINARY_DIR}/ffmpeg/windows/x86_64/lib/libswresample.a")
|
||||
target_link_directories(3rdparty_ffmpeg INTERFACE "${CMAKE_CURRENT_BINARY_DIR}/ffmpeg/windows/x86_64/lib")
|
||||
target_link_libraries(3rdparty_ffmpeg INTERFACE avformat avcodec avutil swscale swresample iconv)
|
||||
else()
|
||||
message("-- RPCS3: using builtin ffmpeg")
|
||||
message(STATUS "RPCS3: using builtin ffmpeg")
|
||||
|
||||
if (WIN32)
|
||||
set(FFMPEG_LIB_DIR "ffmpeg/windows/x86_64")
|
||||
target_link_libraries(3rdparty_ffmpeg INTERFACE "Bcrypt.lib")
|
||||
elseif(CMAKE_SYSTEM MATCHES "Linux")
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
set(FFMPEG_LIB_DIR "ffmpeg/linux/x86_64")
|
||||
elseif(APPLE)
|
||||
set(FFMPEG_LIB_DIR "ffmpeg/macos/x86_64")
|
||||
@@ -304,31 +302,31 @@ else()
|
||||
find_library(FFMPEG_LIB_AVUTIL avutil PATHS ${FFMPEG_LIB_DIR} NO_DEFAULT_PATH)
|
||||
find_library(FFMPEG_LIB_SWSCALE swscale PATHS ${FFMPEG_LIB_DIR} NO_DEFAULT_PATH)
|
||||
find_library(FFMPEG_LIB_SWRESAMPLE swresample PATHS ${FFMPEG_LIB_DIR} NO_DEFAULT_PATH)
|
||||
endif()
|
||||
|
||||
target_include_directories(3rdparty_ffmpeg INTERFACE "ffmpeg/include")
|
||||
|
||||
target_link_libraries(3rdparty_ffmpeg
|
||||
target_link_libraries(3rdparty_ffmpeg
|
||||
INTERFACE
|
||||
${FFMPEG_LIB_AVFORMAT}
|
||||
${FFMPEG_LIB_AVCODEC}
|
||||
${FFMPEG_LIB_AVUTIL}
|
||||
${FFMPEG_LIB_SWSCALE}
|
||||
${FFMPEG_LIB_SWRESAMPLE}
|
||||
)
|
||||
)
|
||||
endif()
|
||||
|
||||
target_include_directories(3rdparty_ffmpeg INTERFACE "ffmpeg/include")
|
||||
endif()
|
||||
|
||||
|
||||
# GLEW
|
||||
add_library(3rdparty_glew INTERFACE)
|
||||
if(NOT MSVC)
|
||||
find_package(GLEW 1.13.0 REQUIRED)
|
||||
find_package(GLEW REQUIRED)
|
||||
target_link_libraries(3rdparty_glew INTERFACE GLEW::GLEW)
|
||||
endif()
|
||||
|
||||
|
||||
# LLVM
|
||||
include(llvm.cmake)
|
||||
add_subdirectory(llvm EXCLUDE_FROM_ALL)
|
||||
|
||||
# WOLFSSL
|
||||
add_subdirectory(wolfssl EXCLUDE_FROM_ALL)
|
||||
|
||||
Vendored
+1
-1
Submodule 3rdparty/FAudio updated: cac0aca5f7...58cf606b5f
Vendored
+1
-1
@@ -1,5 +1,5 @@
|
||||
# OpenAL
|
||||
if (MSVC)
|
||||
if (WIN32)
|
||||
find_path(OPENAL_INCLUDE_DIR al.h PATHS include/)
|
||||
find_library(OPENAL_LIBRARY OpenAL32 PATHS libs/Win64/)
|
||||
else()
|
||||
|
||||
Vendored
+22
-10
@@ -1,24 +1,36 @@
|
||||
# CURL
|
||||
|
||||
if(USE_SYSTEM_CURL)
|
||||
message("-- RPCS3: using shared libcurl")
|
||||
message(STATUS "RPCS3: using shared libcurl")
|
||||
find_package(CURL REQUIRED)
|
||||
add_library(libcurl INTERFACE)
|
||||
target_link_libraries(libcurl INTERFACE CURL::libcurl)
|
||||
else()
|
||||
message("-- RPCS3: building libcurl + wolfssl submodules")
|
||||
add_compile_definitions(HAVE_SNI OPENSSL_EXTRA)
|
||||
option(BUILD_CURL_EXE "Set to ON to build curl executable." OFF)
|
||||
option(CURL_USE_WOLFSSL "enable wolfSSL for SSL/TLS" ON)
|
||||
option(HTTP_ONLY "disables all protocols except HTTP (This overrides all CURL_DISABLE_* options)" ON)
|
||||
option(CURL_ZLIB "Set to ON to enable building curl with zlib support." OFF)
|
||||
option(USE_LIBIDN2 "Use libidn2 for IDN support" OFF) # Disabled because MacOs CI doesn't work otherwise
|
||||
message(STATUS "RPCS3: building libcurl + wolfssl submodules")
|
||||
set(BUILD_CURL_EXE OFF CACHE BOOL "Set to ON to build curl executable.")
|
||||
# If set to ON then CURL can not find our wolfssl
|
||||
set(CURL_USE_WOLFSSL OFF CACHE BOOL "enable wolfSSL for SSL/TLS")
|
||||
set(CURL_USE_OPENSSL OFF CACHE BOOL "Use OpenSSL code. Experimental")
|
||||
set(HTTP_ONLY ON CACHE BOOL "disables all protocols except HTTP (This overrides all CURL_DISABLE_* options)")
|
||||
set(USE_LIBIDN2 OFF CACHE BOOL "Use libidn2 for IDN support") # Disabled because MacOS CI doesn't work otherwise
|
||||
set(CURL_CA_PATH "none" CACHE STRING "Location of default CA path. Set 'none' to disable or 'auto' for auto-detection. Defaults to 'auto'.")
|
||||
if(USE_MSVC_STATIC_CRT)
|
||||
set(CURL_STATIC_CRT ON CACHE BOOL "Use static crt to build curl" FORCE)
|
||||
set(CURL_STATIC_CRT ON CACHE BOOL "Use static crt to build curl")
|
||||
endif()
|
||||
if(WIN32)
|
||||
set(ENABLE_UNICODE ON CACHE BOOL "enable Unicode")
|
||||
endif()
|
||||
set(CURL_USE_LIBSSH2 OFF CACHE BOOL "Use libSSH2")
|
||||
set(CURL_USE_LIBPSL OFF CACHE BOOL "Use libPSL")
|
||||
|
||||
set(SSL_ENABLED ON)
|
||||
set(USE_WOLFSSL ON)
|
||||
|
||||
add_subdirectory(curl EXCLUDE_FROM_ALL)
|
||||
|
||||
set_property(TARGET libcurl PROPERTY FOLDER "3rdparty/")
|
||||
target_link_libraries(libcurl PRIVATE wolfssl)
|
||||
if(MSVC)
|
||||
target_compile_definitions(libcurl PRIVATE HAVE_SSIZE_T)
|
||||
endif()
|
||||
|
||||
endif()
|
||||
|
||||
Vendored
+1
-1
Submodule 3rdparty/curl/curl updated: 1561d06752...7ab9d43720
Vendored
+1
-1
@@ -14,7 +14,7 @@ if(APPLE)
|
||||
elseif(CMAKE_SYSTEM MATCHES "Linux")
|
||||
target_link_libraries(3rdparty_hidapi INTERFACE hidapi-hidraw udev)
|
||||
elseif(WIN32)
|
||||
target_link_libraries(3rdparty_hidapi INTERFACE hidapi-hid Shlwapi.lib)
|
||||
target_link_libraries(3rdparty_hidapi INTERFACE hidapi::hidapi hidapi::include Shlwapi.lib)
|
||||
else()
|
||||
target_link_libraries(3rdparty_hidapi INTERFACE hidapi-libusb usb)
|
||||
endif()
|
||||
|
||||
Vendored
+5
-4
@@ -2,14 +2,15 @@
|
||||
# Select the version of libpng to use, default is builtin
|
||||
if (NOT USE_SYSTEM_LIBPNG)
|
||||
# We use libpng's static library and don't need to build the shared library and run the tests
|
||||
set(PNG_SHARED OFF CACHE BOOL "Build shared lib" FORCE)
|
||||
set(PNG_TESTS OFF CACHE BOOL "Build libpng tests" FORCE)
|
||||
set(PNG_BUILD_ZLIB ON CACHE BOOL "ZLIB is already build or package is found" FORCE)
|
||||
set(PNG_SHARED OFF CACHE BOOL "Build shared lib")
|
||||
set(PNG_TESTS OFF CACHE BOOL "Build libpng tests")
|
||||
set(PNG_BUILD_ZLIB ON CACHE BOOL "ZLIB is already build or package is found")
|
||||
set(SKIP_INSTALL_ALL ON)
|
||||
add_subdirectory(libpng EXCLUDE_FROM_ALL)
|
||||
target_include_directories(png_static INTERFACE "${libpng_BINARY_DIR}" "${libpng_SOURCE_DIR}")
|
||||
target_link_libraries(png_static 3rdparty::zlib)
|
||||
|
||||
set(LIBPNG_TARGET png_static PARENT_SCOPE)
|
||||
set(LIBPNG_TARGET png_static PARENT_SCOPE)
|
||||
else()
|
||||
find_package(PNG REQUIRED)
|
||||
|
||||
|
||||
Vendored
+1
-1
Submodule 3rdparty/libpng/libpng updated: 07b8803110...f135775ad4
Vendored
+1
-1
Submodule 3rdparty/libsdl-org/SDL updated: ac13ca9ab6...ffa78e6bea
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 2.8.4)
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
|
||||
project(libusb)
|
||||
|
||||
|
||||
Vendored
+5
-1
@@ -89,7 +89,11 @@ set(PACKAGE_URL "http://www.libusb.org" CACHE INTERNAL "package url" FORCE)
|
||||
set(PACKAGE_TARNAME "libusb" CACHE INTERNAL "tarball name" FORCE)
|
||||
set(VERSION "${PACKAGE_VERSION}" CACHE INTERNAL "version" FORCE)
|
||||
|
||||
configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h @ONLY)
|
||||
if(MSVC)
|
||||
file(COPY libusb/msvc/config.h DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||
else()
|
||||
configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h @ONLY)
|
||||
endif()
|
||||
message(STATUS "Generated configuration file in ${CMAKE_CURRENT_BINARY_DIR}/config.h")
|
||||
|
||||
# for generated config.h
|
||||
|
||||
Vendored
+8
-17
@@ -3,22 +3,6 @@ include(os.cmake)
|
||||
include(config.cmake)
|
||||
include(FindThreads)
|
||||
|
||||
set (LIBUSB_COMMON
|
||||
core.c
|
||||
descriptor.c
|
||||
io.c
|
||||
sync.c
|
||||
hotplug.c
|
||||
strerror.c
|
||||
libusb-1.0.rc
|
||||
libusb-1.0.def
|
||||
)
|
||||
|
||||
foreach(SRC IN LISTS LIBUSB_COMMON)
|
||||
list(APPEND LIBUSB_COMMON_FINAL ${LIBUSB_SOURCE_DIR}/libusb/${SRC})
|
||||
endforeach()
|
||||
|
||||
|
||||
include_directories(${LIBUSB_SOURCE_DIR}/libusb)
|
||||
include_directories(${LIBUSB_SOURCE_DIR}/libusb/os)
|
||||
|
||||
@@ -28,7 +12,14 @@ endif()
|
||||
|
||||
add_library(usb-1.0-static
|
||||
STATIC
|
||||
${LIBUSB_COMMON_FINAL}
|
||||
libusb/libusb/core.c
|
||||
libusb/libusb/descriptor.c
|
||||
libusb/libusb/io.c
|
||||
libusb/libusb/sync.c
|
||||
libusb/libusb/hotplug.c
|
||||
libusb/libusb/strerror.c
|
||||
libusb/libusb/libusb-1.0.rc
|
||||
libusb/libusb/libusb-1.0.def
|
||||
${LIBUSB_PLATFORM}
|
||||
)
|
||||
|
||||
|
||||
Vendored
+22
-21
@@ -5,42 +5,43 @@ if (CMAKE_USE_PTHREADS_INIT)
|
||||
set(PTHREADS_ENABLED TRUE)
|
||||
endif()
|
||||
|
||||
if (WIN32 OR "${CMAKE_SYSTEM_NAME}" STREQUAL "CYGWIN")
|
||||
if (CYGWIN)
|
||||
add_compile_definitions(PLATFORM_WINDOWS=1)
|
||||
set(OS_WINDOWS 1 CACHE INTERNAL "controls config.h macro definition" FORCE)
|
||||
set(OS_WINDOWS 1)
|
||||
|
||||
# Enable MingW support for RC language (for CMake pre-2.8)
|
||||
if (MINGW)
|
||||
set(CMAKE_RC_COMPILER_INIT windres)
|
||||
set(CMAKE_RC_COMPILE_OBJECT "<CMAKE_RC_COMPILER> <FLAGS> -O coff <DEFINES> -i <SOURCE> -o <OBJECT>")
|
||||
endif()
|
||||
enable_language(RC)
|
||||
|
||||
if ("${CMAKE_SYSTEM_NAME}" STREQUAL "CYGWIN")
|
||||
message(STATUS "Detected cygwin")
|
||||
set(PTHREADS_ENABLED TRUE)
|
||||
set(WITHOUT_POLL_H TRUE CACHE INTERNAL "Disable using poll.h even if it's available - use windows poll instead fo cygwin's" FORCE)
|
||||
endif()
|
||||
message(STATUS "Detected Cygwin")
|
||||
set(PTHREADS_ENABLED TRUE)
|
||||
set(WITHOUT_POLL_H TRUE)
|
||||
|
||||
list(APPEND PLATFORM_SRC
|
||||
events_windows.c
|
||||
windows_usbdk.c
|
||||
windows_common.c
|
||||
windows_winusb.c
|
||||
threads_windows.c
|
||||
)
|
||||
|
||||
if (PTHREADS_ENABLED AND NOT WITHOUT_PTHREADS)
|
||||
list(APPEND PLATFORM_SRC threads_posix)
|
||||
else()
|
||||
list(APPEND PLATFORM_SRC threads_windows.c)
|
||||
endif()
|
||||
elseif(WIN32)
|
||||
add_compile_definitions(PLATFORM_WINDOWS=1)
|
||||
set(OS_WINDOWS 1)
|
||||
set(PTHREADS_ENABLED FALSE)
|
||||
|
||||
list(APPEND PLATFORM_SRC
|
||||
events_windows.c
|
||||
windows_usbdk.c
|
||||
windows_common.c
|
||||
windows_winusb.c
|
||||
)
|
||||
|
||||
list(APPEND PLATFORM_SRC threads_windows.c)
|
||||
elseif (APPLE)
|
||||
# Apple != OSX alone
|
||||
add_compile_definitions(PLATFORM_POSIX=1 HAVE_CLOCK_GETTIME)
|
||||
set(OS_DARWIN 1 CACHE INTERNAL "controls config.h macro definition" FORCE)
|
||||
set(OS_DARWIN 1)
|
||||
|
||||
if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
||||
set(PLATFORM_SRC
|
||||
darwin_usb.c
|
||||
threads_posix.c
|
||||
@@ -77,7 +78,7 @@ elseif (UNIX)
|
||||
# Unix is for all *NIX systems including OSX
|
||||
add_compile_definitions(PLATFORM_POSIX=1 HAVE_CLOCK_GETTIME)
|
||||
if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
|
||||
set(OS_LINUX 1 CACHE INTERNAL "controls config.h macro definition" FORCE)
|
||||
set(OS_LINUX 1)
|
||||
|
||||
set(PLATFORM_SRC
|
||||
linux_usbfs.c
|
||||
@@ -108,4 +109,4 @@ set(LIBUSB_LIBRARIES ${LIBUSB_LIBRARIES} PARENT_SCOPE)
|
||||
if (WITHOUT_PTHREADS)
|
||||
set(PTHREADS_ENABLED FALSE)
|
||||
endif()
|
||||
set(THREADS_POSIX ${PTHREADS_ENABLED} CACHE INTERNAL "use pthreads" FORCE)
|
||||
set(THREADS_POSIX ${PTHREADS_ENABLED})
|
||||
|
||||
+14
-15
@@ -1,6 +1,6 @@
|
||||
if(WITH_LLVM)
|
||||
CHECK_CXX_COMPILER_FLAG("-msse -msse2 -mcx16" COMPILER_X86)
|
||||
CHECK_CXX_COMPILER_FLAG("-march=armv8-a+lse" COMPILER_ARM)
|
||||
check_cxx_compiler_flag("-msse -msse2 -mcx16" COMPILER_X86)
|
||||
check_cxx_compiler_flag("-march=armv8-a+lse" COMPILER_ARM)
|
||||
|
||||
if(BUILD_LLVM)
|
||||
message(STATUS "LLVM will be built from the submodule.")
|
||||
@@ -14,28 +14,26 @@ if(WITH_LLVM)
|
||||
option(LLVM_INCLUDE_TESTS OFF)
|
||||
option(LLVM_INCLUDE_TOOLS OFF)
|
||||
option(LLVM_INCLUDE_UTILS OFF)
|
||||
option(LLVM_CCACHE_BUILD ON)
|
||||
# we globally enable ccache
|
||||
set(LLVM_CCACHE_BUILD OFF CACHE BOOL "Set to ON for a ccache enabled build")
|
||||
|
||||
if(WIN32)
|
||||
set(LLVM_USE_INTEL_JITEVENTS ON)
|
||||
endif()
|
||||
|
||||
if(CMAKE_SYSTEM MATCHES "Linux")
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
set(LLVM_USE_INTEL_JITEVENTS ON)
|
||||
set(LLVM_USE_PERF ON)
|
||||
endif()
|
||||
|
||||
set(CXX_FLAGS_OLD ${CMAKE_CXX_FLAGS})
|
||||
|
||||
if (MSVC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS")
|
||||
add_compile_definitions("$<$<COMPILE_LANGUAGE:CXX>:_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS>")
|
||||
endif()
|
||||
|
||||
# LLVM needs to be built out-of-tree
|
||||
add_subdirectory(${CMAKE_SOURCE_DIR}/3rdparty/llvm/llvm/llvm ${CMAKE_BINARY_DIR}/3rdparty/llvm/llvm_build EXCLUDE_FROM_ALL)
|
||||
set(LLVM_DIR "${CMAKE_BINARY_DIR}/3rdparty/llvm/llvm_build/lib/cmake/llvm/")
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/llvm/llvm ${CMAKE_CURRENT_BINARY_DIR}/llvm_build EXCLUDE_FROM_ALL)
|
||||
set(LLVM_DIR "${CMAKE_CURRENT_BINARY_DIR}/llvm_build/lib/cmake/llvm/")
|
||||
|
||||
set(CMAKE_CXX_FLAGS ${CXX_FLAGS_OLD})
|
||||
set(STATIC_LINK_LLVM ON CACHE BOOL "Link against LLVM statically. This will get set to ON if you build LLVM from the submodule." FORCE)
|
||||
|
||||
# now tries to find LLVM again
|
||||
@@ -72,11 +70,11 @@ if(WITH_LLVM)
|
||||
set(LLVM_TARGETS_TO_BUILD "X86" CACHE STRING "Semicolon-separated list of targets to build, or \"all\".")
|
||||
endif()
|
||||
endif()
|
||||
if(WIN32 OR CMAKE_SYSTEM MATCHES "Linux")
|
||||
set (LLVM_ADDITIONAL_LIBS ${LLVM_ADDITIONAL_LIBS} IntelJITEvents)
|
||||
if((WIN32 AND BUILD_LLVM) OR CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
list (APPEND LLVM_ADDITIONAL_LIBS IntelJITEvents)
|
||||
endif()
|
||||
if(CMAKE_SYSTEM MATCHES "Linux")
|
||||
set (LLVM_ADDITIONAL_LIBS ${LLVM_ADDITIONAL_LIBS} PerfJITEvents)
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
list (APPEND LLVM_ADDITIONAL_LIBS PerfJITEvents)
|
||||
endif()
|
||||
llvm_map_components_to_libnames(LLVM_LIBS
|
||||
${LLVM_TARGETS_TO_BUILD}
|
||||
@@ -92,7 +90,8 @@ if(WITH_LLVM)
|
||||
add_library(3rdparty_llvm INTERFACE)
|
||||
target_link_libraries(3rdparty_llvm INTERFACE ${LLVM_LIBS})
|
||||
target_include_directories(3rdparty_llvm INTERFACE ${LLVM_INCLUDE_DIRS})
|
||||
target_compile_definitions(3rdparty_llvm INTERFACE ${LLVM_DEFINITIONS} -DLLVM_AVAILABLE)
|
||||
separate_arguments(LLVM_DEFINITIONS_LIST NATIVE_COMMAND ${LLVM_DEFINITIONS})
|
||||
target_compile_definitions(3rdparty_llvm INTERFACE ${LLVM_DEFINITIONS_LIST} LLVM_AVAILABLE)
|
||||
|
||||
add_library(3rdparty::llvm ALIAS 3rdparty_llvm)
|
||||
else()
|
||||
Vendored
+8
-2
@@ -32,6 +32,12 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
constexpr SOCKET invalid_socket = INVALID_SOCKET;
|
||||
#else
|
||||
constexpr int invalid_socket = -1;
|
||||
#endif
|
||||
|
||||
namespace pine
|
||||
{
|
||||
/**
|
||||
@@ -381,7 +387,7 @@ namespace pine
|
||||
|
||||
m_msgsock = accept(m_sock, 0, 0);
|
||||
|
||||
if (m_msgsock == -1)
|
||||
if (m_msgsock == invalid_socket)
|
||||
{
|
||||
// everything else is non recoverable in our scope
|
||||
// we also mark as recoverable socket errors where it would block a
|
||||
@@ -541,7 +547,7 @@ namespace pine
|
||||
}
|
||||
server.sin_port = htons(Impl::get_port());
|
||||
|
||||
if (bind(m_sock, (struct sockaddr*)&server, sizeof(server)) == SOCKET_ERROR)
|
||||
if (bind(m_sock, reinterpret_cast<struct sockaddr*>(&server), sizeof(server)) == SOCKET_ERROR)
|
||||
{
|
||||
Impl::error("IPC: Error while binding to socket! Shutting down...");
|
||||
return;
|
||||
|
||||
Vendored
-45
@@ -1,45 +0,0 @@
|
||||
add_library(3rdparty_qt5 INTERFACE)
|
||||
|
||||
set(QT_MIN_VER 5.15.2)
|
||||
|
||||
find_package(Qt5 ${QT_MIN_VER} CONFIG COMPONENTS Widgets Concurrent Multimedia MultimediaWidgets Svg)
|
||||
if(WIN32)
|
||||
find_package(Qt5 ${QT_MIN_VER} COMPONENTS WinExtras REQUIRED)
|
||||
target_link_libraries(3rdparty_qt5 INTERFACE Qt5::Widgets Qt5::WinExtras Qt5::Concurrent Qt5::Multimedia Qt5::MultimediaWidgets Qt5::Svg)
|
||||
else()
|
||||
find_package(Qt5 ${QT_MIN_VER} COMPONENTS DBus Gui)
|
||||
if(Qt5DBus_FOUND)
|
||||
target_link_libraries(3rdparty_qt5 INTERFACE Qt5::Widgets Qt5::DBus Qt5::Concurrent Qt5::Multimedia Qt5::MultimediaWidgets Qt5::Svg)
|
||||
target_compile_definitions(3rdparty_qt5 INTERFACE -DHAVE_QTDBUS)
|
||||
else()
|
||||
target_link_libraries(3rdparty_qt5 INTERFACE Qt5::Widgets Qt5::Concurrent Qt5::Multimedia Qt5::MultimediaWidgets Qt5::Svg)
|
||||
endif()
|
||||
target_include_directories(3rdparty_qt5 INTERFACE ${Qt5Gui_PRIVATE_INCLUDE_DIRS})
|
||||
endif()
|
||||
|
||||
if(NOT Qt5Widgets_FOUND)
|
||||
if(Qt5Widgets_VERSION VERSION_LESS ${QT_MIN_VER})
|
||||
message("Minimum supported Qt5 version is ${QT_MIN_VER}! You have version ${Qt5Widgets_VERSION} installed, please upgrade!")
|
||||
if(CMAKE_SYSTEM MATCHES "Linux")
|
||||
message(FATAL_ERROR "Most distros do not provide an up-to-date version of Qt.
|
||||
If you're on Ubuntu or Linux Mint, there are PPAs you can use to install one of the latest qt5 versions.
|
||||
Find the correct ppa at https://launchpad.net/~beineri and follow the instructions.")
|
||||
elseif(WIN32)
|
||||
message(FATAL_ERROR "You can download the latest version of Qt5 here: https://www.qt.io/download-open-source/")
|
||||
else()
|
||||
message(FATAL_ERROR "Look online for instructions on installing an up-to-date Qt5 on ${CMAKE_SYSTEM}.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
message("CMake was unable to find Qt5!")
|
||||
if(WIN32)
|
||||
message(FATAL_ERROR "Make sure the QTDIR env variable has been set properly. (for example C:\\Qt\\${QT_MIN_VER}\\msvc2019_64\\)
|
||||
You can also try setting the Qt5_DIR preprocessor definiton.")
|
||||
elseif(CMAKE_SYSTEM MATCHES "Linux")
|
||||
message(FATAL_ERROR "Make sure to install your distro's qt5 package!")
|
||||
else()
|
||||
message(FATAL_ERROR "You need to have Qt5 installed, look online for instructions on installing Qt5 on ${CMAKE_SYSTEM}.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_library(3rdparty::qt5 ALIAS 3rdparty_qt5)
|
||||
Vendored
+45
@@ -0,0 +1,45 @@
|
||||
add_library(3rdparty_qt6 INTERFACE)
|
||||
|
||||
set(QT_MIN_VER 6.4.0)
|
||||
|
||||
find_package(Qt6 ${QT_MIN_VER} CONFIG COMPONENTS Widgets Concurrent Multimedia MultimediaWidgets Svg SvgWidgets)
|
||||
if(WIN32)
|
||||
find_package(Qt6 ${QT_MIN_VER} COMPONENTS WinExtras REQUIRED)
|
||||
target_link_libraries(3rdparty_qt6 INTERFACE Qt6::Widgets Qt6::WinExtras Qt6::Concurrent Qt6::Multimedia Qt6::MultimediaWidgets Qt6::Svg Qt6::SvgWidgets)
|
||||
else()
|
||||
find_package(Qt6 ${QT_MIN_VER} COMPONENTS DBus Gui)
|
||||
if(Qt6DBus_FOUND)
|
||||
target_link_libraries(3rdparty_qt6 INTERFACE Qt6::Widgets Qt6::DBus Qt6::Concurrent Qt6::Multimedia Qt6::MultimediaWidgets Qt6::Svg Qt6::SvgWidgets)
|
||||
target_compile_definitions(3rdparty_qt6 INTERFACE -DHAVE_QTDBUS)
|
||||
else()
|
||||
target_link_libraries(3rdparty_qt6 INTERFACE Qt6::Widgets Qt6::Concurrent Qt6::Multimedia Qt6::MultimediaWidgets Qt6::Svg Qt6::SvgWidgets)
|
||||
endif()
|
||||
target_include_directories(3rdparty_qt6 INTERFACE ${Qt6Gui_PRIVATE_INCLUDE_DIRS})
|
||||
endif()
|
||||
|
||||
if(Qt6Widgets_FOUND)
|
||||
if(Qt6Widgets_VERSION VERSION_LESS ${QT_MIN_VER})
|
||||
message("Minimum supported Qt version is ${QT_MIN_VER}! You have version ${Qt6Widgets_VERSION} installed, please upgrade!")
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
message(FATAL_ERROR "Most distros do not provide an up-to-date version of Qt.
|
||||
If you're on Ubuntu or Linux Mint, there are PPAs you can use to install one of the latest qt6 versions.
|
||||
Find the correct ppa at https://launchpad.net/~beineri and follow the instructions.")
|
||||
elseif(WIN32)
|
||||
message(FATAL_ERROR "You can download the latest version of Qt6 here: https://www.qt.io/download-open-source/")
|
||||
else()
|
||||
message(FATAL_ERROR "Look online for instructions on installing an up-to-date Qt6 on ${CMAKE_SYSTEM}.")
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
message("CMake was unable to find Qt6!")
|
||||
if(WIN32)
|
||||
message(FATAL_ERROR "Make sure the QTDIR env variable has been set properly. (for example C:\\Qt\\${QT_MIN_VER}\\msvc2019_64\\)
|
||||
You can also try setting the Qt6_DIR preprocessor definiton.")
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
message(FATAL_ERROR "Make sure to install your distro's qt6 package!")
|
||||
else()
|
||||
message(FATAL_ERROR "You need to have Qt6 installed, look online for instructions on installing Qt6 on ${CMAKE_SYSTEM}.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_library(3rdparty::qt6 ALIAS 3rdparty_qt6)
|
||||
+2551
File diff suppressed because it is too large
Load Diff
Vendored
+17
-31
@@ -1,40 +1,26 @@
|
||||
if(USE_SYSTEM_WOLFSSL)
|
||||
message("-- RPCS3: using shared wolfssl")
|
||||
message(STATUS "RPCS3: using shared wolfssl")
|
||||
pkg_check_modules(WolfSSL REQUIRED IMPORTED_TARGET wolfssl>=4.7.0)
|
||||
add_library(wolfssl INTERFACE)
|
||||
target_link_libraries(wolfssl INTERFACE PkgConfig::WolfSSL)
|
||||
else()
|
||||
# TODO(cjj19970505@live.cn)
|
||||
# OPENSSL_EXTRA, and HAVE_SNI are unconfigurable from CMake cache.
|
||||
# but they do have it in a TODO list (wolfssl/CMakeList, 1021)
|
||||
add_compile_definitions(OPENSSL_EXTRA WOLFSSL_DES_ECB HAVE_SNI HAVE_WRITE_DUP)
|
||||
add_compile_definitions(FP_MAX_BITS=8192)
|
||||
|
||||
set(WOLFSSL_TLS13 "no" CACHE INTERNAL "")
|
||||
set(WOLFSSL_SHA224 "yes" CACHE INTERNAL "")
|
||||
set(WOLFSSL_SHA3 "yes" CACHE INTERNAL "")
|
||||
set(WOLFSSL_SHAKE256 "yes" CACHE INTERNAL "")
|
||||
set(WOLFSSL_BASE64_ENCODE "no" CACHE INTERNAL "")
|
||||
set(WOLFSSL_DES3 "yes" CACHE INTERNAL "")
|
||||
set(WOLFSSL_POLY1305 "yes" CACHE INTERNAL "")
|
||||
set(WOLFSSL_CHACHA "yes" CACHE INTERNAL "")
|
||||
set(WOLFSSL_FILESYSTEM "yes" CACHE INTERNAL "")
|
||||
set(WOLFSSL_PWDBASED "yes" CACHE INTERNAL "")
|
||||
set(WOLFSSL_FAST_MATH "yes" CACHE INTERNAL "")
|
||||
set(WOLFSSL_EXAMPLES "no" CACHE INTERNAL "")
|
||||
set(WOLFSSL_CRYPT_TESTS "no" CACHE INTERNAL "")
|
||||
set(WOLFSSL_ASYNC_THREADS "no" CACHE INTERNAL "")
|
||||
set(WOLFSSL_CONFIG_H "no" CACHE INTERNAL "")
|
||||
set(WOLFSSL_TLS13 OFF CACHE STRING "Enable wolfSSL TLS v1.3 (default: enabled)")
|
||||
set(WOLFSSL_SHA3 ON CACHE STRING "Enable wolfSSL SHA-3 support (default: enabled on x86_64/aarch64)")
|
||||
set(WOLFSSL_SHAKE256 ON CACHE STRING "Enable wolfSSL SHAKE256 support (default: enabled on x86_64/aarch64)")
|
||||
set(WOLFSSL_BASE64_ENCODE OFF CACHE STRING "Enable Base64 encoding (default: enabled on x86_64)")
|
||||
set(WOLFSSL_DES3 ON CACHE STRING "Enable DES3 (default: disabled)")
|
||||
set(WOLFSSL_PWDBASED ON CACHE STRING "Enable PWDBASED (default: disabled)")
|
||||
set(WOLFSSL_FAST_MATH ON CACHE STRING "Enable fast math ops (default: disabled)")
|
||||
set(WOLFSSL_EXAMPLES OFF CACHE STRING "Enable examples (default: enabled)")
|
||||
set(WOLFSSL_CRYPT_TESTS OFF CACHE STRING "Enable Crypt Bench/Test (default: enabled)")
|
||||
set(WOLFSSL_ASYNC_THREADS OFF CACHE STRING "Enable Asynchronous Threading (default: enabled)")
|
||||
set(WOLFSSL_BUILD_OUT_OF_TREE ON CACHE STRING "Don't generate files in the source tree (default: no)")
|
||||
set(WOLFSSL_SNI ON CACHE STRING "Enable SNI (default: disabled)")
|
||||
set(WOLFSSL_OPENSSLEXTRA ON CACHE STRING "Enable extra OpenSSL API, size+ (default: disabled)")
|
||||
set(WOLFSSL_HARDEN OFF CACHE STRING "Enable Hardened build, Enables Timing Resistance and Blinding (default: enabled)")
|
||||
|
||||
add_subdirectory(wolfssl EXCLUDE_FROM_ALL)
|
||||
|
||||
set(WolfSSL_LIBRARY "$<TARGET_FILE:wolfssl>" CACHE INTERNAL "")
|
||||
|
||||
# "${CMAKE_CURRENT_SOURCE_DIR}/wolfssl/wolfssl/" provides openssl headers
|
||||
# So that curl can be built on an environment where openssl headers are not provided
|
||||
set(WolfSSL_INCLUDE_DIR
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/wolfssl/"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/wolfssl/wolfssl/"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/wolfssl/"
|
||||
CACHE INTERNAL "")
|
||||
target_compile_definitions(wolfssl PUBLIC WOLFSSL_DES_ECB HAVE_WRITE_DUP)
|
||||
target_compile_definitions(wolfssl PUBLIC FP_MAX_BITS=8192)
|
||||
endif()
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#define NO_PSK
|
||||
#define HAVE_EXTENDED_MASTER
|
||||
#define WOLFSSL_SNIFFER
|
||||
#define WOLFSSL_IGNORE_FILE_WARN
|
||||
#define HAVE_AESGCM
|
||||
#define HAVE_SUPPORTED_CURVES
|
||||
#define HAVE_TLS_EXTENSIONS
|
||||
@@ -63,11 +64,16 @@ extern FILE* wolfSSL_fopen_utf8(const char* name, const char* mode);
|
||||
#define XFWRITE fwrite
|
||||
#define XFCLOSE fclose
|
||||
#define XSEEK_END SEEK_END
|
||||
#define XSEEK_SET SEEK_SET
|
||||
#define XBADFILE NULL
|
||||
#define XFGETS fgets
|
||||
#define XFPRINTF fprintf
|
||||
#define XFFLUSH fflush
|
||||
|
||||
/* For some reason we need to define ssize_t */
|
||||
#define HAVE_SSIZE_T
|
||||
#define ssize_t __int64
|
||||
|
||||
#include <sys/stat.h>
|
||||
extern int wolfSSL_stat_utf8(const char* path, struct _stat* buffer);
|
||||
#define XSTAT wolfSSL_stat_utf8
|
||||
|
||||
Vendored
+1
-1
Submodule 3rdparty/wolfssl/wolfssl updated: 979707380c...3b3c175af0
Vendored
+1
@@ -73,6 +73,7 @@
|
||||
<ItemGroup>
|
||||
<ClCompile Include="wolfssl\src\crl.c" />
|
||||
<ClCompile Include="wolfssl\src\internal.c" />
|
||||
<ClCompile Include="wolfssl\src\ssl_asn1.c" />
|
||||
<ClCompile Include="wolfssl\src\wolfio.c" />
|
||||
<ClCompile Include="wolfssl\src\keys.c" />
|
||||
<ClCompile Include="wolfssl\src\ocsp.c" />
|
||||
|
||||
Vendored
+11
-9
@@ -1,14 +1,16 @@
|
||||
if (USE_SYSTEM_ZLIB)
|
||||
message(STATUS "-- RPCS3: Using syztem ZLIB")
|
||||
find_package(ZLIB QUIET)
|
||||
message(STATUS "RPCS3: Using system ZLIB")
|
||||
find_package(ZLIB QUIET)
|
||||
|
||||
add_library(3rdparty_zlib INTERFACE)
|
||||
target_link_libraries(3rdparty_zlib INTERFACE ${ZLIB_LIBRARIES})
|
||||
target_include_directories(3rdparty_zlib INTERFACE ${ZLIB_INCLUDE_DIRS})
|
||||
else()
|
||||
message(STATUS "-- RPCS3: Using builtin ZLIB")
|
||||
message(STATUS "RPCS3: Using builtin ZLIB")
|
||||
set(SKIP_INSTALL_ALL ON)
|
||||
add_subdirectory(zlib EXCLUDE_FROM_ALL)
|
||||
set(ZLIB_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/zlib" "${CMAKE_CURRENT_BINARY_DIR}/zlib")
|
||||
set(ZLIB_LIBRARY zlibstatic)
|
||||
endif()
|
||||
|
||||
add_library(3rdparty_zlib INTERFACE)
|
||||
target_link_libraries(3rdparty_zlib INTERFACE ${ZLIB_LIBRARY})
|
||||
target_include_directories(3rdparty_zlib INTERFACE ${ZLIB_INCLUDE_DIR})
|
||||
add_library(3rdparty_zlib INTERFACE)
|
||||
target_link_libraries(3rdparty_zlib INTERFACE zlibstatic)
|
||||
target_include_directories(3rdparty_zlib INTERFACE zlib ${CMAKE_CURRENT_BINARY_DIR}/zlib)
|
||||
endif()
|
||||
|
||||
+8
-15
@@ -9,11 +9,11 @@ Other instructions may be found [here](https://wiki.rpcs3.net/index.php?title=Bu
|
||||
|
||||
* [CMake 3.16.9+](https://www.cmake.org/download/) (add to PATH)
|
||||
* [Python 3.6+](https://www.python.org/downloads/) (add to PATH)
|
||||
* [Qt 5.15.2](https://www.qt.io/download-qt-installer)
|
||||
* [Qt 6.5.2](https://www.qt.io/download-qt-installer)
|
||||
* [Visual Studio 2019](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=Community)
|
||||
* [Vulkan SDK 1.3.224+](https://vulkan.lunarg.com/sdk/home) (See "Install the SDK" [here](https://vulkan.lunarg.com/doc/sdk/latest/windows/getting_started.html))
|
||||
|
||||
**Either add the** `QTDIR` **environment variable, e.g.** `<QtInstallFolder>\5.15.2\msvc2019_64\` **, or use the [Visual Studio Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.QtVisualStudioTools2019)**
|
||||
**Either add the** `QTDIR` **environment variable, e.g.** `<QtInstallFolder>\6.5.2\msvc2019_64\` **, or use the [Visual Studio Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.QtVisualStudioTools2019)**
|
||||
|
||||
### Linux
|
||||
|
||||
@@ -21,7 +21,7 @@ These are the essentials tools to build RPCS3 on Linux. Some of them can be inst
|
||||
|
||||
* Clang 12+ or GCC 11+
|
||||
* [CMake 3.16.9+](https://www.cmake.org/download/)
|
||||
* [Qt 5.15.2](https://www.qt.io/download-qt-installer)
|
||||
* [Qt 6.5.2](https://www.qt.io/download-qt-installer)
|
||||
* [Vulkan SDK 1.3.224+](https://vulkan.lunarg.com/sdk/home) (See "Install the SDK" [here](https://vulkan.lunarg.com/doc/sdk/latest/linux/getting_started.html))
|
||||
* [SDL2](https://github.com/libsdl-org/SDL/releases) (for the FAudio backend)
|
||||
|
||||
@@ -29,7 +29,7 @@ These are the essentials tools to build RPCS3 on Linux. Some of them can be inst
|
||||
|
||||
#### Arch Linux
|
||||
|
||||
sudo pacman -S glew openal cmake vulkan-validation-layers qt5-base qt5-declarative qt5-multimedia sdl2 sndio jack2 base-devel
|
||||
sudo pacman -S glew openal cmake vulkan-validation-layers qt6-base qt6-declarative qt6-multimedia sdl2 sndio jack2 base-devel
|
||||
|
||||
#### Debian & Ubuntu
|
||||
|
||||
@@ -38,14 +38,7 @@ These are the essentials tools to build RPCS3 on Linux. Some of them can be inst
|
||||
Ubuntu is usually horrendously out of date, and some packages need to be downloaded by hand. This part is for Qt, GCC, Vulkan, and CMake
|
||||
##### Qt PPA
|
||||
|
||||
Ubuntu usually does not have a new enough Qt package to suit rpcs3's needs. There is a PPA available to work around this. Run the following:
|
||||
```
|
||||
. /etc/os-release
|
||||
sudo add-apt-repository ppa:beineri/opt-qt-5.15.2-$UBUNTU_CODENAME
|
||||
sudo apt-get update
|
||||
sudo apt-get install qt515base qt515svg
|
||||
. /opt/qt515/bin/qt515-env.sh >/dev/null 2>&1
|
||||
```
|
||||
Ubuntu usually does not have a new enough Qt package to suit rpcs3's needs. There is currently no PPA available to work around this.
|
||||
|
||||
##### GCC 11.x installation
|
||||
|
||||
@@ -82,11 +75,11 @@ sudo apt-get install cmake
|
||||
|
||||
#### Fedora
|
||||
|
||||
sudo dnf install alsa-lib-devel cmake glew glew-devel libatomic libevdev-devel libudev-devel openal-devel qt5-qtbase-devel qt5-qtbase-private-devel vulkan-devel pipewire-jack-audio-connection-kit-devel qt5-qtmultimedia-devel qt5-qtsvg-devel
|
||||
sudo dnf install alsa-lib-devel cmake glew glew-devel libatomic libevdev-devel libudev-devel openal-devel qt6-qtbase-devel qt6-qtbase-private-devel vulkan-devel pipewire-jack-audio-connection-kit-devel qt6-qtmultimedia-devel qt6-qtsvg-devel
|
||||
|
||||
#### OpenSUSE
|
||||
|
||||
sudo zypper install git cmake libasound2 libpulse-devel openal-soft-devel glew-devel zlib-devel libedit-devel vulkan-devel libudev-devel libqt5-qtbase-devel libqt5-qtmultimedia-devel libqt5-qtsvg-devel libQt5Gui-private-headers-devel libevdev-devel libsndio7_1 libjack-devel
|
||||
sudo zypper install git cmake libasound2 libpulse-devel openal-soft-devel glew-devel zlib-devel libedit-devel vulkan-devel libudev-devel libqt6-qtbase-devel libqt6-qtmultimedia-devel libqt6-qtsvg-devel libQt6Gui-private-headers-devel libevdev-devel libsndio7_1 libjack-devel
|
||||
|
||||
## Setup the project
|
||||
|
||||
@@ -103,7 +96,7 @@ git submodule update --init
|
||||
#### Configuring the Qt plugin (if used)
|
||||
|
||||
1) Go to `Extensions->Qt VS Tools->Qt Versions`.
|
||||
2) Add the path to your Qt installation with compiler e.g. `<QtInstallFolder>\5.15.2\msvc2019_64`, version will fill in automatically.
|
||||
2) Add the path to your Qt installation with compiler e.g. `<QtInstallFolder>\6.5.2\msvc2019_64`, version will fill in automatically.
|
||||
3) Go to `Extensions->Qt VS Tools->Options->Legacy Project Format`.
|
||||
4) Set `Build: Run pre-build setup` to `true`.
|
||||
|
||||
|
||||
+16
-20
@@ -1,12 +1,14 @@
|
||||
cmake_minimum_required(VERSION 3.16.9)
|
||||
|
||||
project(rpcs3)
|
||||
project(rpcs3 LANGUAGES C CXX)
|
||||
|
||||
if(${CMAKE_CXX_COMPILER_ID} MATCHES "GNU")
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 11)
|
||||
message(FATAL_ERROR "RPCS3 requires at least gcc-11.")
|
||||
endif()
|
||||
elseif(${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")
|
||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 12.0)
|
||||
message(FATAL_ERROR "RPCS3 requires at least clang-12.0.")
|
||||
endif()
|
||||
@@ -25,7 +27,7 @@ option(USE_PRECOMPILED_HEADERS "Use precompiled headers" OFF)
|
||||
option(USE_SDL "Enables SDL input handler" OFF)
|
||||
option(USE_SYSTEM_SDL "Prefer system SDL instead of the builtin one" OFF)
|
||||
|
||||
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/buildfiles/cmake")
|
||||
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/buildfiles/cmake")
|
||||
|
||||
include(CheckCXXCompilerFlag)
|
||||
|
||||
@@ -43,7 +45,7 @@ else()
|
||||
endif()
|
||||
|
||||
if(CMAKE_BUILD_TYPE MATCHES "Debug" AND NOT MSVC)
|
||||
add_definitions(-D_DEBUG)
|
||||
add_compile_definitions(_DEBUG)
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
@@ -75,7 +77,7 @@ if(MSVC)
|
||||
# TODO(cjj19970505@live.cn)
|
||||
# offical QT uses dynamic CRT.
|
||||
# When building our lib with static CRT and debug build type
|
||||
# and linking with Qt with dynmaic CRT and debug build,
|
||||
# and linking with Qt with dynamic CRT and debug build,
|
||||
# error is encountered in runtime (which is expected).
|
||||
# But building our lib with static CRT and release build type,
|
||||
# and linking with Qt with dynamic CRT and release build seems to be working,
|
||||
@@ -90,6 +92,7 @@ if(MSVC)
|
||||
message(AUTHOR_WARNING "Debug build currently can not work with static CRT.")
|
||||
endif()
|
||||
endif()
|
||||
add_compile_options(/MP)
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
@@ -98,13 +101,12 @@ endif()
|
||||
|
||||
find_program(CCACHE_FOUND ccache)
|
||||
if(CCACHE_FOUND)
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
|
||||
set(CMAKE_CXX_COMPILER_LAUNCHER ccache)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
add_definitions(-DUNICODE)
|
||||
add_definitions(-D_WIN32_WINNT=0x0602)
|
||||
add_compile_definitions(UNICODE)
|
||||
add_compile_definitions(_WIN32_WINNT=0x0602)
|
||||
endif()
|
||||
|
||||
if(APPLE AND CMAKE_OSX_ARCHITECTURES STREQUAL "arm64")
|
||||
@@ -112,10 +114,7 @@ if(APPLE AND CMAKE_OSX_ARCHITECTURES STREQUAL "arm64")
|
||||
link_directories(/opt/homebrew/lib)
|
||||
endif()
|
||||
|
||||
# Warnings are silenced for 3rdparty code
|
||||
set(CMAKE_CXX_FLAGS -w)
|
||||
set(CMAKE_C_FLAGS -w)
|
||||
set(LLVM_ENABLE_WARNINGS OFF CACHE BOOL "")
|
||||
set(LLVM_ENABLE_WARNINGS OFF CACHE BOOL "Enable compiler warnings.")
|
||||
|
||||
if(MSVC)
|
||||
add_compile_options(/wd4530 /utf-8) # C++ exception handler used, but unwind semantics are not enabled
|
||||
@@ -123,9 +122,6 @@ endif()
|
||||
|
||||
add_subdirectory(3rdparty)
|
||||
|
||||
unset(CMAKE_CXX_FLAGS)
|
||||
unset(CMAKE_C_FLAGS)
|
||||
|
||||
if (DISABLE_LTO)
|
||||
if (CMAKE_C_FLAGS)
|
||||
string(REGEX REPLACE "-flto[^ ]*" "" CMAKE_C_FLAGS ${CMAKE_C_FLAGS})
|
||||
@@ -137,7 +133,7 @@ endif()
|
||||
|
||||
string(FIND "${CMAKE_C_FLAGS} ${CMAKE_CXX_FLAGS}" "-flto" FOUND_LTO)
|
||||
if (NOT FOUND_LTO EQUAL -1)
|
||||
message(FATAL_ERROR "Rpcs3 doesn't support building with LTO, use -DDISABLE_LTO=TRUE to force-disable it")
|
||||
message(FATAL_ERROR "RPCS3 doesn't support building with LTO, use -DDISABLE_LTO=TRUE to force-disable it")
|
||||
endif()
|
||||
|
||||
if(NOT WIN32)
|
||||
@@ -149,6 +145,6 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE "${PROJECT_BINARY_DIR}/bin")
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG "${PROJECT_BINARY_DIR}/bin")
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${PROJECT_BINARY_DIR}/bin")
|
||||
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
add_subdirectory(rpcs3)
|
||||
|
||||
set_directory_properties(PROPERTIES VS_STARTUP_PROJECT rpcs3)
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"version": 3,
|
||||
"configurePresets": [
|
||||
{
|
||||
"name": "gcc",
|
||||
"generator": "Ninja",
|
||||
"binaryDir": "build-gcc",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"USE_FAUDIO": "OFF",
|
||||
"USE_SYSTEM_CURL": "OFF",
|
||||
"USE_SYSTEM_ZLIB": "OFF",
|
||||
"USE_SYSTEM_LIBPNG": "OFF",
|
||||
"USE_NATIVE_INSTRUCTIONS": "ON",
|
||||
"USE_PRECOMPILED_HEADERS": "ON",
|
||||
"BUILD_LLVM": "OFF",
|
||||
"STATIC_LINK_LLVM": "ON"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "clang",
|
||||
"generator": "Ninja",
|
||||
"binaryDir": "build-clang64",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"USE_FAUDIO": "OFF",
|
||||
"USE_SYSTEM_CURL": "OFF",
|
||||
"USE_SYSTEM_ZLIB": "OFF",
|
||||
"USE_SYSTEM_LIBPNG": "OFF",
|
||||
"LLVM_ENABLE_LIBCXX": "ON",
|
||||
"USE_NATIVE_INSTRUCTIONS": "ON",
|
||||
"USE_PRECOMPILED_HEADERS": "ON",
|
||||
"BUILD_LLVM": "OFF",
|
||||
"STATIC_LINK_LLVM": "ON"
|
||||
},
|
||||
"environment": {
|
||||
"CXX": "clang++",
|
||||
"CC": "clang"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "msvc",
|
||||
"displayName": "Windows x64",
|
||||
"generator": "Visual Studio 17 2022",
|
||||
"binaryDir": "build-msvc",
|
||||
"architecture": {
|
||||
"value": "x64",
|
||||
"strategy": "external"
|
||||
},
|
||||
"cacheVariables": {
|
||||
"CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}",
|
||||
"USE_FAUDIO": "OFF",
|
||||
"USE_PRECOMPILED_HEADERS": "ON",
|
||||
"USE_SYSTEM_ZLIB": "OFF",
|
||||
"USE_NATIVE_INSTRUCTIONS": "ON",
|
||||
"BUILD_LLVM": "ON",
|
||||
"STATIC_LINK_LLVM": "ON"
|
||||
},
|
||||
"vendor": {
|
||||
"microsoft.com/VisualStudioSettings/CMake/1.0": {
|
||||
"hostOS": [
|
||||
"Windows"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
+2
-2
@@ -725,7 +725,7 @@ namespace CRCPP
|
||||
{
|
||||
while (size--)
|
||||
{
|
||||
#if defined(WIN32) || defined(_WIN32) || defined(WINCE)
|
||||
#ifdef _MSC_VER
|
||||
// Disable warning about data loss when doing (remainder >> CHAR_BIT) when
|
||||
// remainder is one byte long. The algorithm is still correct in this case,
|
||||
// though it's possible that one additional machine instruction will be executed.
|
||||
@@ -733,7 +733,7 @@ namespace CRCPP
|
||||
# pragma warning (disable : 4333)
|
||||
#endif
|
||||
remainder = (remainder >> CHAR_BIT) ^ lookupTable[static_cast<unsigned char>(remainder ^ *current++)];
|
||||
#if defined(WIN32) || defined(_WIN32) || defined(WINCE)
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning (pop)
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -7,6 +7,12 @@
|
||||
|
||||
LOG_CHANNEL(cfg_log, "CFG");
|
||||
|
||||
template <>
|
||||
void fmt_class_string<cfg::node>::format(std::string& out, u64 arg)
|
||||
{
|
||||
out += get_object(arg).to_string();
|
||||
}
|
||||
|
||||
namespace cfg
|
||||
{
|
||||
_base::_base(type _type)
|
||||
|
||||
+150
-17
@@ -130,6 +130,7 @@ static fs::error to_error(DWORD e)
|
||||
case ERROR_NOT_READY: return fs::error::noent;
|
||||
case ERROR_FILENAME_EXCED_RANGE: return fs::error::toolong;
|
||||
case ERROR_DISK_FULL: return fs::error::nospace;
|
||||
case ERROR_NOT_SAME_DEVICE: return fs::error::xdev;
|
||||
default: return fs::error::unknown;
|
||||
}
|
||||
}
|
||||
@@ -172,6 +173,7 @@ static fs::error to_error(int e)
|
||||
case EROFS: return fs::error::readonly;
|
||||
case EISDIR: return fs::error::isdir;
|
||||
case ENOSPC: return fs::error::nospace;
|
||||
case EXDEV: return fs::error::xdev;
|
||||
default: return fs::error::unknown;
|
||||
}
|
||||
}
|
||||
@@ -225,9 +227,9 @@ namespace fs
|
||||
{
|
||||
}
|
||||
|
||||
[[noreturn]] stat_t file_base::stat()
|
||||
[[noreturn]] stat_t file_base::get_stat()
|
||||
{
|
||||
fmt::throw_exception("fs::file::stat() not supported.");
|
||||
fmt::throw_exception("fs::file::get_stat() not supported.");
|
||||
}
|
||||
|
||||
void file_base::sync()
|
||||
@@ -244,6 +246,11 @@ namespace fs
|
||||
#endif
|
||||
}
|
||||
|
||||
file_id file_base::get_id()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
u64 file_base::write_gather(const iovec_clone* buffers, u64 buf_count)
|
||||
{
|
||||
u64 total = 0;
|
||||
@@ -272,6 +279,66 @@ namespace fs
|
||||
return this->write(buf.get(), total);
|
||||
}
|
||||
|
||||
file_id::operator bool() const
|
||||
{
|
||||
return !type.empty() && !data.empty();
|
||||
}
|
||||
|
||||
// Test if identical
|
||||
// For example: when LHS writes one byte to a file at X offset, RHS file be able to read that exact byte at X offset)
|
||||
bool file_id::is_mirror_of(const file_id& rhs) const
|
||||
{
|
||||
// If either is an invalid ID we cannot compare safely, return false
|
||||
return rhs && type == rhs.type && data == rhs.data;
|
||||
}
|
||||
|
||||
// Test if both files point to the same file
|
||||
// For example: if a file descriptor pointing to the complete file exists and is being truncated to 0 bytes from non-
|
||||
// -zero size state: this has to affect both RHS and LHS files.
|
||||
bool file_id::is_coherent_with(const file_id& rhs) const
|
||||
{
|
||||
struct id_view
|
||||
{
|
||||
std::string_view type_view;
|
||||
std::basic_string_view<u8> data_view;
|
||||
};
|
||||
|
||||
id_view _rhs{rhs.type, {rhs.data.data(), rhs.data.size()}};
|
||||
id_view _lhs{type, {data.data(), data.size()}};
|
||||
|
||||
// Peek through fs::file wrappers
|
||||
auto peek_wrapppers = [](id_view& id)
|
||||
{
|
||||
u64 offset_count = 0;
|
||||
constexpr auto lv2_view = "lv2_file::file_view: "sv;
|
||||
|
||||
for (usz pos = 0; (pos = id.type_view.find(lv2_view, pos)) != umax; pos += lv2_view.size())
|
||||
{
|
||||
offset_count++;
|
||||
}
|
||||
|
||||
// Remove offsets data
|
||||
id.data_view.remove_suffix(sizeof(u64) * offset_count);
|
||||
|
||||
// Get last category identifier
|
||||
if (usz sep = id.type_view.rfind(": "); sep != umax)
|
||||
{
|
||||
id.type_view.remove_prefix(sep + 2);
|
||||
}
|
||||
};
|
||||
|
||||
peek_wrapppers(_rhs);
|
||||
peek_wrapppers(_lhs);
|
||||
|
||||
// If either is an invalid ID we cannot compare safely, return false
|
||||
if (_rhs.type_view.empty() || _rhs.data_view.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return _rhs.type_view == _lhs.type_view && _rhs.data_view == _lhs.data_view;
|
||||
}
|
||||
|
||||
dir_base::~dir_base()
|
||||
{
|
||||
}
|
||||
@@ -384,12 +451,12 @@ shared_ptr<fs::device_base> fs::set_virtual_device(const std::string& name, shar
|
||||
return get_device_manager().set_device(name, std::move(device));
|
||||
}
|
||||
|
||||
std::string fs::get_parent_dir(std::string_view path, u32 levels)
|
||||
std::string_view fs::get_parent_dir_view(std::string_view path, u32 parent_level)
|
||||
{
|
||||
std::string_view result = path;
|
||||
|
||||
// Number of path components to remove
|
||||
usz to_remove = levels;
|
||||
usz to_remove = parent_level;
|
||||
|
||||
while (to_remove--)
|
||||
{
|
||||
@@ -432,10 +499,10 @@ std::string fs::get_parent_dir(std::string_view path, u32 levels)
|
||||
return "/";
|
||||
}
|
||||
|
||||
return std::string{result};
|
||||
return result;
|
||||
}
|
||||
|
||||
bool fs::stat(const std::string& path, stat_t& info)
|
||||
bool fs::get_stat(const std::string& path, stat_t& info)
|
||||
{
|
||||
// Ensure consistent information on failure
|
||||
info = {};
|
||||
@@ -551,13 +618,13 @@ bool fs::stat(const std::string& path, stat_t& info)
|
||||
bool fs::exists(const std::string& path)
|
||||
{
|
||||
fs::stat_t info{};
|
||||
return fs::stat(path, info);
|
||||
return fs::get_stat(path, info);
|
||||
}
|
||||
|
||||
bool fs::is_file(const std::string& path)
|
||||
{
|
||||
fs::stat_t info{};
|
||||
if (!fs::stat(path, info))
|
||||
if (!fs::get_stat(path, info))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -574,7 +641,7 @@ bool fs::is_file(const std::string& path)
|
||||
bool fs::is_dir(const std::string& path)
|
||||
{
|
||||
fs::stat_t info{};
|
||||
if (!fs::stat(path, info))
|
||||
if (!fs::get_stat(path, info))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -863,9 +930,20 @@ bool fs::copy_file(const std::string& from, const std::string& to, bool overwrit
|
||||
if (::fcopyfile(input, output, 0, COPYFILE_ALL))
|
||||
#elif defined(__linux__) || defined(__sun)
|
||||
// sendfile will work with non-socket output (i.e. regular file) on Linux 2.6.33+
|
||||
off_t bytes_copied = 0;
|
||||
struct ::stat fileinfo = { 0 };
|
||||
if (::fstat(input, &fileinfo) == -1 || ::sendfile(output, input, &bytes_copied, fileinfo.st_size) == -1)
|
||||
bool result = ::fstat(input, &fileinfo) != -1;
|
||||
if (result)
|
||||
{
|
||||
for (off_t bytes_copied = 0; bytes_copied < fileinfo.st_size; /* Do nothing, bytes_copied is increased by sendfile. */)
|
||||
{
|
||||
if (::sendfile(output, input, &bytes_copied, fileinfo.st_size - bytes_copied) == -1)
|
||||
{
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!result)
|
||||
#else
|
||||
#error "Native file copy implementation is missing"
|
||||
#endif
|
||||
@@ -1120,7 +1198,7 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
|
||||
CloseHandle(m_handle);
|
||||
}
|
||||
|
||||
stat_t stat() override
|
||||
stat_t get_stat() override
|
||||
{
|
||||
FILE_BASIC_INFO basic_info;
|
||||
ensure(GetFileInformationByHandleEx(m_handle, FileBasicInfo, &basic_info, sizeof(FILE_BASIC_INFO))); // "file::stat"
|
||||
@@ -1278,6 +1356,28 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
|
||||
{
|
||||
return m_handle;
|
||||
}
|
||||
|
||||
file_id get_id() override
|
||||
{
|
||||
file_id id{"windows_file"};
|
||||
id.data.resize(sizeof(FILE_ID_INFO));
|
||||
|
||||
FILE_ID_INFO info;
|
||||
|
||||
if (!GetFileInformationByHandleEx(m_handle, FileIdInfo, &info, sizeof(info)))
|
||||
{
|
||||
// Try GetFileInformationByHandle as a fallback
|
||||
BY_HANDLE_FILE_INFORMATION info2;
|
||||
ensure(GetFileInformationByHandle(m_handle, &info2));
|
||||
|
||||
info = {};
|
||||
info.VolumeSerialNumber = info2.dwVolumeSerialNumber;
|
||||
std::memcpy(&info.FileId, &info2.nFileIndexHigh, 8);
|
||||
}
|
||||
|
||||
std::memcpy(id.data.data(), &info, sizeof(info));
|
||||
return id;
|
||||
}
|
||||
};
|
||||
|
||||
m_file = std::make_unique<windows_file>(handle);
|
||||
@@ -1345,7 +1445,7 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
|
||||
::close(m_fd);
|
||||
}
|
||||
|
||||
stat_t stat() override
|
||||
stat_t get_stat() override
|
||||
{
|
||||
struct ::stat file_info;
|
||||
ensure(::fstat(m_fd, &file_info) == 0); // "file::stat"
|
||||
@@ -1470,6 +1570,19 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
|
||||
return m_fd;
|
||||
}
|
||||
|
||||
file_id get_id() override
|
||||
{
|
||||
struct ::stat file_info;
|
||||
ensure(::fstat(m_fd, &file_info) == 0); // "file::get_id"
|
||||
|
||||
file_id id{"unix_file"};
|
||||
id.data.resize(sizeof(file_info.st_dev) + sizeof(file_info.st_ino));
|
||||
|
||||
std::memcpy(id.data.data(), &file_info.st_dev, sizeof(file_info.st_dev));
|
||||
std::memcpy(id.data.data() + sizeof(file_info.st_dev), &file_info.st_ino, sizeof(file_info.st_ino));
|
||||
return id;
|
||||
}
|
||||
|
||||
u64 write_gather(const iovec_clone* buffers, u64 buf_count) override
|
||||
{
|
||||
static_assert(sizeof(iovec) == sizeof(iovec_clone), "Weird iovec size");
|
||||
@@ -1495,7 +1608,7 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
|
||||
|
||||
m_file = std::make_unique<unix_file>(fd);
|
||||
|
||||
if (mode & fs::isfile && !(mode & fs::write) && stat().is_directory)
|
||||
if (mode & fs::isfile && !(mode & fs::write) && get_stat().is_directory)
|
||||
{
|
||||
m_file.reset();
|
||||
g_tls_error = error::isdir;
|
||||
@@ -1604,6 +1717,16 @@ fs::native_handle fs::file::get_handle() const
|
||||
#endif
|
||||
}
|
||||
|
||||
fs::file_id fs::file::get_id() const
|
||||
{
|
||||
if (m_file)
|
||||
{
|
||||
return m_file->get_id();
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
bool fs::dir::open(const std::string& path)
|
||||
{
|
||||
if (path.empty())
|
||||
@@ -1646,7 +1769,7 @@ bool fs::dir::open(const std::string& path)
|
||||
to_utf8(info.name, found.cFileName);
|
||||
info.is_directory = (found.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
info.is_writable = (found.dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0;
|
||||
info.size = ((u64)found.nFileSizeHigh << 32) | (u64)found.nFileSizeLow;
|
||||
info.size = (static_cast<u64>(found.nFileSizeHigh) << 32) | static_cast<u64>(found.nFileSizeLow);
|
||||
info.atime = to_time(found.ftLastAccessTime);
|
||||
info.mtime = to_time(found.ftLastWriteTime);
|
||||
info.ctime = info.mtime;
|
||||
@@ -1991,13 +2114,13 @@ fs::file fs::make_gather(std::vector<fs::file> files)
|
||||
{
|
||||
}
|
||||
|
||||
fs::stat_t stat() override
|
||||
fs::stat_t get_stat() override
|
||||
{
|
||||
fs::stat_t result{};
|
||||
|
||||
if (!files.empty())
|
||||
{
|
||||
result = files[0].stat();
|
||||
result = files[0].get_stat();
|
||||
}
|
||||
|
||||
result.is_directory = false;
|
||||
@@ -2239,9 +2362,19 @@ void fmt_class_string<fs::error>::format(std::string& out, u64 arg)
|
||||
case fs::error::isdir: return "Is a directory";
|
||||
case fs::error::toolong: return "Path too long";
|
||||
case fs::error::nospace: return "Not enough space on the device";
|
||||
case fs::error::xdev: return "Device mismatch";
|
||||
case fs::error::unknown: return "Unknown system error";
|
||||
}
|
||||
|
||||
return unknown;
|
||||
});
|
||||
}
|
||||
|
||||
template<>
|
||||
void fmt_class_string<fs::file_id>::format(std::string& out, u64 arg)
|
||||
{
|
||||
const fs::file_id& id = get_object(arg);
|
||||
|
||||
// TODO: Format data
|
||||
fmt::append(out, "{type='%s'}", id.type);
|
||||
}
|
||||
|
||||
+28
-7
@@ -84,12 +84,22 @@ namespace fs
|
||||
usz iov_len;
|
||||
};
|
||||
|
||||
struct file_id
|
||||
{
|
||||
std::string type;
|
||||
std::vector<u8> data;
|
||||
|
||||
explicit operator bool() const;
|
||||
bool is_mirror_of(const file_id&) const;
|
||||
bool is_coherent_with(const file_id&) const;
|
||||
};
|
||||
|
||||
// File handle base
|
||||
struct file_base
|
||||
{
|
||||
virtual ~file_base();
|
||||
|
||||
[[noreturn]] virtual stat_t stat();
|
||||
[[noreturn]] virtual stat_t get_stat();
|
||||
virtual void sync();
|
||||
virtual bool trunc(u64 length) = 0;
|
||||
virtual u64 read(void* buffer, u64 size) = 0;
|
||||
@@ -98,6 +108,7 @@ namespace fs
|
||||
virtual u64 seek(s64 offset, seek_mode whence) = 0;
|
||||
virtual u64 size() = 0;
|
||||
virtual native_handle get_handle();
|
||||
virtual file_id get_id();
|
||||
virtual u64 write_gather(const iovec_clone* buffers, u64 buf_count);
|
||||
};
|
||||
|
||||
@@ -165,11 +176,17 @@ namespace fs
|
||||
// Set virtual device with specified name (nullptr for deletion)
|
||||
shared_ptr<device_base> set_virtual_device(const std::string& name, shared_ptr<device_base> device);
|
||||
|
||||
// Try to get parent directory (returns empty string on failure)
|
||||
std::string get_parent_dir(std::string_view path, u32 levels = 1);
|
||||
// Try to get parent directory
|
||||
std::string_view get_parent_dir_view(std::string_view path, u32 parent_level = 1);
|
||||
|
||||
// String (typical use) version
|
||||
inline std::string get_parent_dir(std::string_view path, u32 parent_level = 1)
|
||||
{
|
||||
return std::string{get_parent_dir_view(path, parent_level)};
|
||||
}
|
||||
|
||||
// Get file information
|
||||
bool stat(const std::string& path, stat_t& info);
|
||||
bool get_stat(const std::string& path, stat_t& info);
|
||||
|
||||
// Check whether a file or a directory exists (not recommended, use is_file() or is_dir() instead)
|
||||
bool exists(const std::string& path);
|
||||
@@ -267,14 +284,14 @@ namespace fs
|
||||
}
|
||||
|
||||
// Get file information
|
||||
stat_t stat(
|
||||
stat_t get_stat(
|
||||
u32 line = __builtin_LINE(),
|
||||
u32 col = __builtin_COLUMN(),
|
||||
const char* file = __builtin_FILE(),
|
||||
const char* func = __builtin_FUNCTION()) const
|
||||
{
|
||||
if (!m_file) xnull({line, col, file, func});
|
||||
return m_file->stat();
|
||||
return m_file->get_stat();
|
||||
}
|
||||
|
||||
// Sync file buffers
|
||||
@@ -499,6 +516,9 @@ namespace fs
|
||||
// Get native handle if available
|
||||
native_handle get_handle() const;
|
||||
|
||||
// Get file ID information (custom ID)
|
||||
file_id get_id() const;
|
||||
|
||||
// Gathered write
|
||||
u64 write_gather(const iovec_clone* buffers, u64 buf_count,
|
||||
u32 line = __builtin_LINE(),
|
||||
@@ -684,6 +704,7 @@ namespace fs
|
||||
isdir,
|
||||
toolong,
|
||||
nospace,
|
||||
xdev,
|
||||
unknown
|
||||
};
|
||||
|
||||
@@ -808,7 +829,7 @@ namespace fs
|
||||
return obj.size();
|
||||
}
|
||||
|
||||
stat_t stat() override
|
||||
stat_t get_stat() override
|
||||
{
|
||||
return m_stat;
|
||||
}
|
||||
|
||||
+1
-1
@@ -1505,7 +1505,7 @@ void jit_compiler::add(const std::string& path)
|
||||
|
||||
if (auto object_file = llvm::object::ObjectFile::createObjectFile(*cache))
|
||||
{
|
||||
m_engine->addObjectFile( std::move(*object_file) );
|
||||
m_engine->addObjectFile(llvm::object::OwningBinary<llvm::object::ObjectFile>(std::move(*object_file), std::move(cache)));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -63,7 +63,7 @@ std::string fmt::win_error_to_string(unsigned long error, void* module_handle)
|
||||
std::string message;
|
||||
LPWSTR message_buffer = nullptr;
|
||||
if (FormatMessageW((module_handle ? FORMAT_MESSAGE_FROM_HMODULE : FORMAT_MESSAGE_FROM_SYSTEM) | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
module_handle, error, 0, (LPWSTR)&message_buffer, 0, nullptr))
|
||||
module_handle, error, 0, reinterpret_cast<LPWSTR>(&message_buffer), 0, nullptr))
|
||||
{
|
||||
message = fmt::format("%s (0x%x)", fmt::trim(wchar_to_utf8(message_buffer), " \t\n\r\f\v"), error);
|
||||
}
|
||||
@@ -589,7 +589,7 @@ std::vector<std::string> fmt::split(std::string_view source, std::initializer_li
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string fmt::trim(const std::string& source, const std::string& values)
|
||||
std::string fmt::trim(const std::string& source, std::string_view values)
|
||||
{
|
||||
usz begin = source.find_first_not_of(values);
|
||||
|
||||
@@ -599,6 +599,12 @@ std::string fmt::trim(const std::string& source, const std::string& values)
|
||||
return source.substr(begin, source.find_last_not_of(values) + 1);
|
||||
}
|
||||
|
||||
void fmt::trim_back(std::string& source, std::string_view values)
|
||||
{
|
||||
const usz index = source.find_last_not_of(values);
|
||||
source.resize(index + 1);
|
||||
}
|
||||
|
||||
std::string fmt::to_upper(std::string_view string)
|
||||
{
|
||||
std::string result;
|
||||
|
||||
+21
-1
@@ -124,7 +124,8 @@ namespace fmt
|
||||
}
|
||||
|
||||
std::vector<std::string> split(std::string_view source, std::initializer_list<std::string_view> separators, bool is_skip_empty = true);
|
||||
std::string trim(const std::string& source, const std::string& values = " \t");
|
||||
std::string trim(const std::string& source, std::string_view values = " \t");
|
||||
void trim_back(std::string& source, std::string_view values = " \t");
|
||||
|
||||
template <typename T>
|
||||
std::string merge(const T& source, const std::string& separator)
|
||||
@@ -186,4 +187,23 @@ namespace fmt
|
||||
const u8* buf;
|
||||
usz len;
|
||||
};
|
||||
|
||||
struct string_hash
|
||||
{
|
||||
using hash_type = std::hash<std::string_view>;
|
||||
using is_transparent = void;
|
||||
|
||||
std::size_t operator()(const char* str) const
|
||||
{
|
||||
return hash_type{}(str);
|
||||
}
|
||||
std::size_t operator()(std::string_view str) const
|
||||
{
|
||||
return hash_type{}(str);
|
||||
}
|
||||
std::size_t operator()(std::string const& str) const
|
||||
{
|
||||
return hash_type{}(str);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
+7
-11
@@ -110,11 +110,7 @@ std::string dump_useful_thread_info()
|
||||
|
||||
if (auto cpu = get_current_cpu_thread())
|
||||
{
|
||||
// Wrap it to disable some internal exceptions when printing (not thrown on main thread)
|
||||
Emu.BlockingCallFromMainThread([&]()
|
||||
{
|
||||
cpu->dump_all(result);
|
||||
});
|
||||
cpu->dump_all(result);
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -1639,7 +1635,7 @@ bool handle_access_violation(u32 addr, bool is_writing, ucontext_t* context) noe
|
||||
if (!g_tls_access_violation_recovered)
|
||||
{
|
||||
vm_log.notice("\n%s", dump_useful_thread_info());
|
||||
vm_log.error("Access violation %s location 0x%x (%s)", is_writing ? "writing" : "reading", addr, (is_writing && vm::check_addr(addr)) ? "read-only memory" : "unmapped memory");
|
||||
vm_log.error("[%s] Access violation %s location 0x%x (%s)", cpu->get_name(), is_writing ? "writing" : "reading", addr, (is_writing && vm::check_addr(addr)) ? "read-only memory" : "unmapped memory");
|
||||
}
|
||||
|
||||
// TODO:
|
||||
@@ -1832,15 +1828,15 @@ static LONG exception_filter(PEXCEPTION_POINTERS pExp) noexcept
|
||||
const bool s_exception_handler_set = []() -> bool
|
||||
{
|
||||
#ifdef USE_ASAN
|
||||
if (!AddVectoredExceptionHandler(FALSE, (PVECTORED_EXCEPTION_HANDLER)exception_handler))
|
||||
if (!AddVectoredExceptionHandler(FALSE, static_cast<PVECTORED_EXCEPTION_HANDLER>(exception_handler)))
|
||||
#else
|
||||
if (!AddVectoredExceptionHandler(1, (PVECTORED_EXCEPTION_HANDLER)exception_handler))
|
||||
if (!AddVectoredExceptionHandler(1, static_cast<PVECTORED_EXCEPTION_HANDLER>(exception_handler)))
|
||||
#endif
|
||||
{
|
||||
report_fatal_error("AddVectoredExceptionHandler() failed.");
|
||||
}
|
||||
|
||||
if (!SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)exception_filter))
|
||||
if (!SetUnhandledExceptionFilter(static_cast<LPTOP_LEVEL_EXCEPTION_FILTER>(exception_filter)))
|
||||
{
|
||||
report_fatal_error("SetUnhandledExceptionFilter() failed.");
|
||||
}
|
||||
@@ -2046,7 +2042,7 @@ void thread_base::start()
|
||||
#ifdef _WIN32
|
||||
m_thread = ::_beginthreadex(nullptr, 0, entry_point, this, CREATE_SUSPENDED, nullptr);
|
||||
ensure(m_thread);
|
||||
ensure(::ResumeThread(reinterpret_cast<HANDLE>(+m_thread)) != -1);
|
||||
ensure(::ResumeThread(reinterpret_cast<HANDLE>(+m_thread)) != static_cast<DWORD>(-1));
|
||||
#elif defined(__APPLE__)
|
||||
pthread_attr_t stack_size_attr;
|
||||
pthread_attr_init(&stack_size_attr);
|
||||
@@ -2154,7 +2150,7 @@ u64 thread_base::finalize(thread_state result_state) noexcept
|
||||
tls_cycles += cycles;
|
||||
FILETIME ctime, etime, ktime, utime;
|
||||
GetThreadTimes(GetCurrentThread(), &ctime, &etime, &ktime, &utime);
|
||||
const u64 time = ((ktime.dwLowDateTime | (u64)ktime.dwHighDateTime << 32) + (utime.dwLowDateTime | (u64)utime.dwHighDateTime << 32)) * 100ull - tls_time;
|
||||
const u64 time = ((ktime.dwLowDateTime | static_cast<u64>(ktime.dwHighDateTime) << 32) + (utime.dwLowDateTime | static_cast<u64>(utime.dwHighDateTime) << 32)) * 100ull - tls_time;
|
||||
tls_time += time;
|
||||
const u64 fsoft = 0;
|
||||
const u64 fhard = 0;
|
||||
|
||||
+151
-30
@@ -77,6 +77,7 @@ void fmt_class_string<patch_type>::format(std::string& out, u64 arg)
|
||||
case patch_type::lef32: return "lef32";
|
||||
case patch_type::lef64: return "lef64";
|
||||
case patch_type::utf8: return "utf8";
|
||||
case patch_type::c_utf8: return "cutf8";
|
||||
case patch_type::move_file: return "move_file";
|
||||
case patch_type::hide_file: return "hide_file";
|
||||
}
|
||||
@@ -218,18 +219,18 @@ bool patch_engine::load(patch_map& patches_map, const std::string& path, std::st
|
||||
// Go through each main key in the file
|
||||
for (auto pair : root)
|
||||
{
|
||||
const auto& main_key = pair.first.Scalar();
|
||||
const std::string& main_key = pair.first.Scalar();
|
||||
|
||||
if (const auto yml_type = pair.second.Type(); yml_type != YAML::NodeType::Map)
|
||||
if (main_key.empty())
|
||||
{
|
||||
append_log_message(log_messages, fmt::format("Error: Skipping key %s: expected Map, found %s (location: %s, file: %s)", main_key, yml_type, get_yaml_node_location(pair.second), path), &patch_log.error);
|
||||
append_log_message(log_messages, fmt::format("Error: Skipping empty key (location: %s, file: %s)", get_yaml_node_location(pair.first), path), &patch_log.error);
|
||||
is_valid = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (main_key.empty())
|
||||
if (const auto yml_type = pair.second.Type(); yml_type != YAML::NodeType::Map)
|
||||
{
|
||||
append_log_message(log_messages, fmt::format("Error: Skipping empty key (location: %s, file: %s)", get_yaml_node_location(pair.second), path), &patch_log.error);
|
||||
append_log_message(log_messages, fmt::format("Error: Skipping key %s: expected Map, found %s (location: %s, file: %s)", main_key, yml_type, get_yaml_node_location(pair.second), path), &patch_log.error);
|
||||
is_valid = false;
|
||||
continue;
|
||||
}
|
||||
@@ -241,7 +242,7 @@ bool patch_engine::load(patch_map& patches_map, const std::string& path, std::st
|
||||
}
|
||||
|
||||
// Find or create an entry matching the key/hash in our map
|
||||
auto& container = patches_map[main_key];
|
||||
patch_container& container = patches_map[main_key];
|
||||
container.hash = main_key;
|
||||
container.version = version;
|
||||
|
||||
@@ -251,6 +252,13 @@ bool patch_engine::load(patch_map& patches_map, const std::string& path, std::st
|
||||
// Each key in "Patches" is also the patch description
|
||||
const std::string& description = patches_entry.first.Scalar();
|
||||
|
||||
if (description.empty())
|
||||
{
|
||||
append_log_message(log_messages, fmt::format("Error: Empty patch name (key: %s, location: %s, file: %s)", main_key, get_yaml_node_location(patches_entry.first), path), &patch_log.error);
|
||||
is_valid = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Compile patch information
|
||||
|
||||
if (const auto yml_type = patches_entry.second.Type(); yml_type != YAML::NodeType::Map)
|
||||
@@ -329,7 +337,7 @@ bool patch_engine::load(patch_map& patches_map, const std::string& path, std::st
|
||||
continue;
|
||||
}
|
||||
|
||||
patch_engine::patch_app_versions app_versions;
|
||||
patch_app_versions app_versions;
|
||||
|
||||
for (const auto version : serial_node.second)
|
||||
{
|
||||
@@ -578,6 +586,14 @@ bool patch_engine::load(patch_map& patches_map, const std::string& path, std::st
|
||||
{
|
||||
if (!read_patch_node(info, patch_node, root, log_messages))
|
||||
{
|
||||
for (const auto& it : patches_entry.second)
|
||||
{
|
||||
if (it.first.Scalar() == patch_key::patch)
|
||||
{
|
||||
append_log_message(log_messages, fmt::format("Skipping invalid patch node %s: (key: %s, location: %s)", info.description, main_key, get_yaml_node_location(it.first)), &patch_log.error);
|
||||
break;
|
||||
}
|
||||
}
|
||||
is_valid = false;
|
||||
}
|
||||
}
|
||||
@@ -702,6 +718,33 @@ bool patch_engine::add_patch_data(YAML::Node node, patch_info& info, u32 modifie
|
||||
|
||||
std::string error_message;
|
||||
|
||||
// Validate offset
|
||||
switch (p_data.type)
|
||||
{
|
||||
case patch_type::move_file:
|
||||
case patch_type::hide_file:
|
||||
break;
|
||||
default:
|
||||
{
|
||||
[[maybe_unused]] const u32 offset = get_yaml_node_value<u32>(addr_node, error_message);
|
||||
if (!error_message.empty())
|
||||
{
|
||||
error_message = fmt::format("Skipping patch data entry: [ %s, 0x%.8x, %s ] (key: %s, location: %s) Invalid patch offset '%s' (not a valid u32 or overflow)",
|
||||
p_data.type, p_data.offset, p_data.original_value.empty() ? "?" : p_data.original_value, info.hash, get_yaml_node_location(node), p_data.original_offset);
|
||||
append_log_message(log_messages, error_message, &patch_log.error);
|
||||
return false;
|
||||
}
|
||||
if ((0xFFFFFFFF - modifier) < p_data.offset)
|
||||
{
|
||||
error_message = fmt::format("Skipping patch data entry: [ %s, 0x%.8x, %s ] (key: %s, location: %s) Invalid combination of patch offset 0x%.8x and modifier 0x%.8x (overflow)",
|
||||
p_data.type, p_data.offset, p_data.original_value.empty() ? "?" : p_data.original_value, info.hash, get_yaml_node_location(node), p_data.offset, modifier);
|
||||
append_log_message(log_messages, error_message, &patch_log.error);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (p_data.type)
|
||||
{
|
||||
case patch_type::utf8:
|
||||
@@ -805,7 +848,7 @@ void unmap_vm_area(std::shared_ptr<vm::block_t>& ptr)
|
||||
}
|
||||
|
||||
// Returns old 'applied' size
|
||||
static usz apply_modification(std::basic_string<u32>& applied, patch_engine::patch_info& patch, u8* dst, u32 filesz, u32 min_addr)
|
||||
static usz apply_modification(std::basic_string<u32>& applied, patch_engine::patch_info& patch, std::function<u8*(u32, u32)> mem_translate, u32 filesz, u32 min_addr)
|
||||
{
|
||||
const usz old_applied_size = applied.size();
|
||||
|
||||
@@ -846,8 +889,8 @@ static usz apply_modification(std::basic_string<u32>& applied, patch_engine::pat
|
||||
{
|
||||
if (p.type != patch_type::alloc) continue;
|
||||
|
||||
// Do not allow null address or if dst is not a VM ptr
|
||||
if (const u32 alloc_at = vm::try_get_addr(dst + (p.offset & -4096)).first; alloc_at >> 16)
|
||||
// Do not allow null address or if resultant ptr is not a VM ptr
|
||||
if (const u32 alloc_at = (p.offset & -4096); alloc_at >> 16)
|
||||
{
|
||||
const u32 alloc_size = utils::align(static_cast<u32>(p.value.long_value) + alloc_at % 4096, 4096);
|
||||
|
||||
@@ -926,7 +969,74 @@ static usz apply_modification(std::basic_string<u32>& applied, patch_engine::pat
|
||||
relocate_instructions_at = 0;
|
||||
}
|
||||
|
||||
if (!relocate_instructions_at && (offset < min_addr || offset - min_addr >= filesz))
|
||||
u32 memory_size = 0;
|
||||
|
||||
switch (p.type)
|
||||
{
|
||||
case patch_type::invalid:
|
||||
case patch_type::load:
|
||||
{
|
||||
// Invalid in this context
|
||||
break;
|
||||
}
|
||||
case patch_type::alloc:
|
||||
{
|
||||
// Applied before
|
||||
memory_size = 0;
|
||||
continue;
|
||||
}
|
||||
case patch_type::byte:
|
||||
{
|
||||
memory_size = sizeof(u8);
|
||||
break;
|
||||
}
|
||||
case patch_type::le16:
|
||||
case patch_type::be16:
|
||||
{
|
||||
memory_size = sizeof(u16);
|
||||
break;
|
||||
}
|
||||
case patch_type::code_alloc:
|
||||
case patch_type::jump:
|
||||
case patch_type::jump_link:
|
||||
case patch_type::jump_func:
|
||||
case patch_type::le32:
|
||||
case patch_type::lef32:
|
||||
case patch_type::bd32:
|
||||
case patch_type::be32:
|
||||
case patch_type::bef32:
|
||||
{
|
||||
memory_size = sizeof(u32);
|
||||
break;
|
||||
}
|
||||
case patch_type::lef64:
|
||||
case patch_type::le64:
|
||||
case patch_type::bd64:
|
||||
case patch_type::be64:
|
||||
case patch_type::bef64:
|
||||
{
|
||||
memory_size = sizeof(u64);
|
||||
break;
|
||||
}
|
||||
case patch_type::utf8:
|
||||
{
|
||||
memory_size = p.original_value.size();
|
||||
break;
|
||||
}
|
||||
case patch_type::c_utf8:
|
||||
{
|
||||
memory_size = utils::add_saturate<u32>(p.original_value.size(), 1);
|
||||
break;
|
||||
}
|
||||
case patch_type::move_file:
|
||||
case patch_type::hide_file:
|
||||
{
|
||||
memory_size = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (memory_size != 0 && !relocate_instructions_at && (filesz < memory_size || offset < min_addr || offset - min_addr > filesz - memory_size))
|
||||
{
|
||||
// This patch is out of range for this segment
|
||||
continue;
|
||||
@@ -934,7 +1044,13 @@ static usz apply_modification(std::basic_string<u32>& applied, patch_engine::pat
|
||||
|
||||
offset -= min_addr;
|
||||
|
||||
auto ptr = dst + offset;
|
||||
auto ptr = mem_translate(offset, memory_size);
|
||||
|
||||
if (!ptr && memory_size != 0 && !relocate_instructions_at)
|
||||
{
|
||||
// Memory translation failed
|
||||
continue;
|
||||
}
|
||||
|
||||
if (relocate_instructions_at)
|
||||
{
|
||||
@@ -960,7 +1076,7 @@ static usz apply_modification(std::basic_string<u32>& applied, patch_engine::pat
|
||||
}
|
||||
case patch_type::code_alloc:
|
||||
{
|
||||
const u32 out_branch = vm::try_get_addr(dst + (offset & -4)).first;
|
||||
const u32 out_branch = vm::try_get_addr(relocate_instructions_at ? vm::get_super_ptr<u8>(offset & -4) : mem_translate(offset & -4, 4)).first;
|
||||
|
||||
// Allow only if points to a PPU executable instruction
|
||||
if (out_branch < 0x10000 || out_branch >= 0x4000'0000 || !vm::check_addr<4>(out_branch, vm::page_executable))
|
||||
@@ -1044,7 +1160,7 @@ static usz apply_modification(std::basic_string<u32>& applied, patch_engine::pat
|
||||
case patch_type::jump:
|
||||
case patch_type::jump_link:
|
||||
{
|
||||
const u32 out_branch = vm::try_get_addr(dst + (offset & -4)).first;
|
||||
const u32 out_branch = vm::try_get_addr(relocate_instructions_at ? vm::get_super_ptr<u8>(offset & -4) : mem_translate(offset & -4, 4)).first;
|
||||
const u32 dest = static_cast<u32>(p.value.long_value);
|
||||
|
||||
// Allow only if points to a PPU executable instruction
|
||||
@@ -1060,7 +1176,7 @@ static usz apply_modification(std::basic_string<u32>& applied, patch_engine::pat
|
||||
{
|
||||
const std::string& str = p.original_value;
|
||||
|
||||
const u32 out_branch = vm::try_get_addr(dst + (offset & -4)).first;
|
||||
const u32 out_branch = vm::try_get_addr(relocate_instructions_at ? vm::get_super_ptr<u8>(offset & -4) : mem_translate(offset & -4, 4)).first;
|
||||
const usz sep_pos = str.find_first_of(':');
|
||||
|
||||
// Must contain only a single ':' or none
|
||||
@@ -1076,7 +1192,7 @@ static usz apply_modification(std::basic_string<u32>& applied, patch_engine::pat
|
||||
|
||||
if (func_name.starts_with("0x"sv))
|
||||
{
|
||||
// Raw hexadeciaml-formatted FNID (real function name cannot contain a digit at the start, derived from C/CPP which were used in PS3 development)
|
||||
// Raw hexadecimal-formatted FNID (real function name cannot contain a digit at the start, derived from C/CPP which were used in PS3 development)
|
||||
const auto result = std::from_chars(func_name.data() + 2, func_name.data() + func_name.size() - 2, id, 16);
|
||||
|
||||
if (result.ec != std::errc() || str.data() + sep_pos != result.ptr)
|
||||
@@ -1197,6 +1313,11 @@ static usz apply_modification(std::basic_string<u32>& applied, patch_engine::pat
|
||||
std::memcpy(ptr, p.original_value.data(), p.original_value.size());
|
||||
break;
|
||||
}
|
||||
case patch_type::c_utf8:
|
||||
{
|
||||
std::memcpy(ptr, p.original_value.data(), p.original_value.size() + 1);
|
||||
break;
|
||||
}
|
||||
case patch_type::move_file:
|
||||
case patch_type::hide_file:
|
||||
{
|
||||
@@ -1251,7 +1372,7 @@ static usz apply_modification(std::basic_string<u32>& applied, patch_engine::pat
|
||||
return old_applied_size;
|
||||
}
|
||||
|
||||
std::basic_string<u32> patch_engine::apply(const std::string& name, u8* dst, u32 filesz, u32 min_addr)
|
||||
std::basic_string<u32> patch_engine::apply(const std::string& name, std::function<u8*(u32, u32)> mem_translate, u32 filesz, u32 min_addr)
|
||||
{
|
||||
if (!m_map.contains(name))
|
||||
{
|
||||
@@ -1259,11 +1380,11 @@ std::basic_string<u32> patch_engine::apply(const std::string& name, u8* dst, u32
|
||||
}
|
||||
|
||||
std::basic_string<u32> applied_total;
|
||||
const auto& container = ::at32(m_map, name);
|
||||
const auto& serial = Emu.GetTitleID();
|
||||
const auto& app_version = Emu.GetAppVersion();
|
||||
const patch_container& container = ::at32(m_map, name);
|
||||
const std::string& serial = Emu.GetTitleID();
|
||||
const std::string& app_version = Emu.GetAppVersion();
|
||||
|
||||
// Different containers in order to seperate the patches
|
||||
// Different containers in order to separate the patches
|
||||
std::vector<std::shared_ptr<patch_info>> patches_for_this_serial_and_this_version;
|
||||
std::vector<std::shared_ptr<patch_info>> patches_for_this_serial_and_all_versions;
|
||||
std::vector<std::shared_ptr<patch_info>> patches_for_all_serials_and_this_version;
|
||||
@@ -1295,7 +1416,7 @@ std::basic_string<u32> patch_engine::apply(const std::string& name, u8* dst, u32
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto& app_versions = ::at32(serials, found_serial);
|
||||
const patch_app_versions& app_versions = ::at32(serials, found_serial);
|
||||
std::string found_app_version;
|
||||
|
||||
if (app_versions.contains(app_version))
|
||||
@@ -1392,7 +1513,7 @@ std::basic_string<u32> patch_engine::apply(const std::string& name, u8* dst, u32
|
||||
{
|
||||
if (patch)
|
||||
{
|
||||
const usz old_size = apply_modification(applied_total, *patch, dst, filesz, min_addr);
|
||||
const usz old_size = apply_modification(applied_total, *patch, mem_translate, filesz, min_addr);
|
||||
|
||||
if (applied_total.size() != old_size)
|
||||
{
|
||||
@@ -1413,11 +1534,11 @@ void patch_engine::unload(const std::string& name)
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& container = ::at32(m_map, name);
|
||||
const patch_container& container = ::at32(m_map, name);
|
||||
|
||||
for (const auto& [description, patch] : container.patch_info_map)
|
||||
{
|
||||
for (auto& entry : patch.data_list)
|
||||
for (const patch_data& entry : patch.data_list)
|
||||
{
|
||||
// Deallocate used memory
|
||||
if (u32 addr = std::exchange(entry.alloc_addr, 0))
|
||||
@@ -1545,7 +1666,7 @@ static void append_patches(patch_engine::patch_map& existing_patches, const patc
|
||||
continue;
|
||||
}
|
||||
|
||||
auto& container = existing_patches[hash];
|
||||
patch_engine::patch_container& container = existing_patches[hash];
|
||||
|
||||
for (const auto& [description, new_info] : new_container.patch_info_map)
|
||||
{
|
||||
@@ -1556,7 +1677,7 @@ static void append_patches(patch_engine::patch_map& existing_patches, const patc
|
||||
continue;
|
||||
}
|
||||
|
||||
auto& info = container.patch_info_map[description];
|
||||
patch_engine::patch_info& info = container.patch_info_map[description];
|
||||
|
||||
bool ok;
|
||||
const bool version_is_bigger = utils::compare_versions(new_info.patch_version, info.patch_version, ok) > 0;
|
||||
@@ -1719,7 +1840,7 @@ bool patch_engine::save_patches(const patch_map& patches, const std::string& pat
|
||||
|
||||
bool patch_engine::import_patches(const patch_engine::patch_map& patches, const std::string& path, usz& count, usz& total, std::stringstream* log_messages)
|
||||
{
|
||||
patch_engine::patch_map existing_patches;
|
||||
patch_map existing_patches;
|
||||
|
||||
if (load(existing_patches, path, "", true, log_messages))
|
||||
{
|
||||
@@ -1732,13 +1853,13 @@ bool patch_engine::import_patches(const patch_engine::patch_map& patches, const
|
||||
|
||||
bool patch_engine::remove_patch(const patch_info& info)
|
||||
{
|
||||
patch_engine::patch_map patches;
|
||||
patch_map patches;
|
||||
|
||||
if (load(patches, info.source_path))
|
||||
{
|
||||
if (patches.contains(info.hash))
|
||||
{
|
||||
auto& container = patches[info.hash];
|
||||
patch_container& container = patches[info.hash];
|
||||
|
||||
if (container.patch_info_map.contains(info.description))
|
||||
{
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <functional>
|
||||
|
||||
#include "util/types.hpp"
|
||||
#include "util/yaml.hpp"
|
||||
@@ -52,13 +53,14 @@ enum class patch_type
|
||||
bef32,
|
||||
bef64,
|
||||
utf8, // Text of string (not null-terminated automatically)
|
||||
c_utf8, // Text of string (null-terminated automatically)
|
||||
move_file, // Move file
|
||||
hide_file, // Hide file
|
||||
};
|
||||
|
||||
static constexpr bool patch_type_uses_hex_offset(patch_type type)
|
||||
{
|
||||
return type >= patch_type::alloc && type <= patch_type::utf8;
|
||||
return type >= patch_type::alloc && type <= patch_type::c_utf8;
|
||||
}
|
||||
|
||||
enum class patch_configurable_type
|
||||
@@ -212,7 +214,7 @@ public:
|
||||
void append_title_patches(const std::string& title_id);
|
||||
|
||||
// Apply patch (returns the number of entries applied)
|
||||
std::basic_string<u32> apply(const std::string& name, u8* dst, u32 filesz = -1, u32 min_addr = 0);
|
||||
std::basic_string<u32> apply(const std::string& name, std::function<u8*(u32, u32)> mem_translate, u32 filesz = -1, u32 min_addr = 0);
|
||||
|
||||
// Deallocate memory used by patches
|
||||
void unload(const std::string& name);
|
||||
|
||||
@@ -73,12 +73,12 @@ namespace utils
|
||||
std::vector<std::string> get_backtrace_symbols(const std::vector<void*>& stack)
|
||||
{
|
||||
std::vector<std::string> result = {};
|
||||
std::vector<u8> symbol_buf(sizeof(SYMBOL_INFO) + sizeof(TCHAR) * 256);
|
||||
std::vector<u8> symbol_buf(sizeof(SYMBOL_INFOW) + sizeof(TCHAR) * 256);
|
||||
|
||||
const auto hProcess = ::GetCurrentProcess();
|
||||
|
||||
auto sym = reinterpret_cast<SYMBOL_INFO*>(symbol_buf.data());
|
||||
sym->SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||
auto sym = reinterpret_cast<SYMBOL_INFOW*>(symbol_buf.data());
|
||||
sym->SizeOfStruct = sizeof(SYMBOL_INFOW);
|
||||
sym->MaxNameLen = 256;
|
||||
|
||||
IMAGEHLP_LINEW64 line_info{};
|
||||
@@ -90,7 +90,7 @@ namespace utils
|
||||
for (const auto& pointer : stack)
|
||||
{
|
||||
DWORD64 unused;
|
||||
SymFromAddr(hProcess, reinterpret_cast<DWORD64>(pointer), &unused, sym);
|
||||
SymFromAddrW(hProcess, reinterpret_cast<DWORD64>(pointer), &unused, sym);
|
||||
|
||||
if (sym->NameLen)
|
||||
{
|
||||
@@ -98,7 +98,7 @@ namespace utils
|
||||
|
||||
// Attempt to get file and line information if available
|
||||
DWORD unused2;
|
||||
if (SymGetLineFromAddrW(hProcess, reinterpret_cast<DWORD64>(pointer), &unused2, &line_info))
|
||||
if (SymGetLineFromAddrW64(hProcess, reinterpret_cast<DWORD64>(pointer), &unused2, &line_info))
|
||||
{
|
||||
const auto full_path = fmt::format("%s:%u %s", wstr_to_utf8(line_info.FileName, -1), line_info.LineNumber, function_name);
|
||||
result.push_back(full_path);
|
||||
|
||||
+3
-3
@@ -65,10 +65,10 @@ jobs:
|
||||
- job: Windows_Build
|
||||
variables:
|
||||
COMPILER: msvc
|
||||
QT_VER_MAIN: '5'
|
||||
QT_VER: '5.15.2'
|
||||
QT_VER_MAIN: '6'
|
||||
QT_VER: '6.5.2'
|
||||
QT_VER_MSVC: 'msvc2019'
|
||||
QT_DATE: '202011130602'
|
||||
QT_DATE: '202307080351'
|
||||
QTDIR: C:\Qt\$(QT_VER)\$(QT_VER_MSVC)_64
|
||||
VULKAN_VER: '1.3.224.1'
|
||||
VULKAN_SDK_SHA: '2029e652e39ee6a6036cff3765da31e1e6c595fd2413d3cd111dfab7855621ea'
|
||||
|
||||
@@ -44,13 +44,13 @@ QLabel#gamelist_icon_background_color {
|
||||
}
|
||||
|
||||
/* log stylesheet */
|
||||
QTextEdit#tty_frame {
|
||||
QPlainTextEdit#tty_frame {
|
||||
background-color:#ffffff;
|
||||
}
|
||||
QLabel#tty_text {
|
||||
color:#000000;
|
||||
}
|
||||
QTextEdit#log_frame {
|
||||
QPlainTextEdit#log_frame {
|
||||
background-color:#ffffff;
|
||||
}
|
||||
QLabel#log_level_always {
|
||||
|
||||
@@ -253,7 +253,7 @@ QLabel#thumbnail_icon_color {
|
||||
}
|
||||
|
||||
/* Set Log colors */
|
||||
QTextEdit#log_frame {
|
||||
QPlainTextEdit#log_frame {
|
||||
background-color: #000; /* Black */
|
||||
}
|
||||
QLabel#log_level_always {
|
||||
@@ -285,7 +285,7 @@ QLabel#log_stack {
|
||||
}
|
||||
|
||||
/* Set TTY colors */
|
||||
QTextEdit#tty_frame {
|
||||
QPlainTextEdit#tty_frame {
|
||||
background-color: #000; /* Black */
|
||||
}
|
||||
QLabel#tty_text {
|
||||
@@ -384,3 +384,6 @@ QTreeView::branch:open:has-children:has-siblings:hover {
|
||||
#game_list_grid_item[focus="true"] #game_list_grid_item_title_label {
|
||||
background-color: #0078D7;
|
||||
}
|
||||
|
||||
/* Richtext link color */
|
||||
QLabel#richtext_link_color { color: #87cefa; }
|
||||
|
||||
@@ -579,7 +579,7 @@ QLabel#thumbnail_icon_color {
|
||||
}
|
||||
|
||||
/* Log colors */
|
||||
QTextEdit#log_frame {
|
||||
QPlainTextEdit#log_frame {
|
||||
background-color: #23262d;
|
||||
}
|
||||
|
||||
@@ -620,7 +620,7 @@ QLabel#log_stack {
|
||||
}
|
||||
|
||||
/* TTY colors */
|
||||
QTextEdit#tty_frame {
|
||||
QPlainTextEdit#tty_frame {
|
||||
background-color: #23262d;
|
||||
}
|
||||
|
||||
@@ -680,3 +680,6 @@ QTreeView::branch:open:has-children:has-siblings:hover {
|
||||
background-color: #2d3038;
|
||||
color: #8cf944;
|
||||
}
|
||||
|
||||
/* Richtext link color */
|
||||
QLabel#richtext_link_color { color: #8cf944; }
|
||||
|
||||
@@ -292,7 +292,7 @@ QLabel#debugger_frame_pc {
|
||||
}
|
||||
|
||||
/* Set Log colors */
|
||||
QTextEdit#log_frame {
|
||||
QPlainTextEdit#log_frame {
|
||||
background-color: #000000; /* Black */
|
||||
}
|
||||
QLabel#log_level_always {
|
||||
@@ -323,7 +323,7 @@ QLabel#log_stack {
|
||||
color: #ffffff; /* White */
|
||||
}
|
||||
/* Set TTY colors */
|
||||
QTextEdit#tty_frame {
|
||||
QPlainTextEdit#tty_frame {
|
||||
background-color: #000000; /* Black */
|
||||
}
|
||||
QLabel#tty_text {
|
||||
@@ -384,3 +384,6 @@ QTreeView::branch:open:has-children:has-siblings:hover {
|
||||
color: #e6e6e6;
|
||||
background-color: #4c4b4b;
|
||||
}
|
||||
|
||||
/* Richtext link color */
|
||||
QLabel#richtext_link_color { color: #87cefa; }
|
||||
|
||||
@@ -250,7 +250,7 @@ QLabel#thumbnail_icon_color {
|
||||
}
|
||||
|
||||
/* Set Log colors */
|
||||
QTextEdit#log_frame {
|
||||
QPlainTextEdit#log_frame {
|
||||
background-color: #181d24; /* Black */
|
||||
}
|
||||
QLabel#log_level_always {
|
||||
@@ -282,7 +282,7 @@ QLabel#log_stack {
|
||||
}
|
||||
|
||||
/* Set TTY colors */
|
||||
QTextEdit#tty_frame {
|
||||
QPlainTextEdit#tty_frame {
|
||||
background-color: #181d24; /* Black */
|
||||
}
|
||||
QLabel#tty_text {
|
||||
@@ -381,3 +381,6 @@ QTreeView::branch:open:has-children:has-siblings:hover {
|
||||
#game_list_grid_item[focus="true"] #game_list_grid_item_title_label {
|
||||
background-color: #0078D7;
|
||||
}
|
||||
|
||||
/* Richtext link color */
|
||||
QLabel#richtext_link_color { color: #87cefa; }
|
||||
|
||||
@@ -504,3 +504,6 @@ QWidget#trophy_notification_frame {
|
||||
background-color: #4d4940;
|
||||
color: #ffd785;
|
||||
}
|
||||
|
||||
/* Richtext link color */
|
||||
QLabel#richtext_link_color { color: #87cefa; }
|
||||
|
||||
@@ -611,7 +611,7 @@ QLineEdit:focus {
|
||||
}
|
||||
|
||||
/* Log colors */
|
||||
QTextEdit#log_frame {
|
||||
QPlainTextEdit#log_frame {
|
||||
background-color: #111525;
|
||||
}
|
||||
|
||||
@@ -720,3 +720,6 @@ QTreeView::branch:open:has-children:has-siblings:hover {
|
||||
background-color: #0f1d36;
|
||||
color: #2397ff;
|
||||
}
|
||||
|
||||
/* Richtext link color */
|
||||
QLabel#richtext_link_color { color: #0074e7; }
|
||||
|
||||
@@ -619,7 +619,7 @@ QLineEdit:focus {
|
||||
}
|
||||
|
||||
/* Log colors */
|
||||
QTextEdit#log_frame {
|
||||
QPlainTextEdit#log_frame {
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
# Check and configure compiler options for RPCS3
|
||||
|
||||
if(MSVC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zc:throwingNew- /constexpr:steps16777216 /D _CRT_SECURE_NO_DEPRECATE=1 /D _CRT_NON_CONFORMING_SWPRINTFS=1 /D _SCL_SECURE_NO_WARNINGS=1")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D NOMINMAX /D _ENABLE_EXTENDED_ALIGNED_STORAGE=1 /D _HAS_EXCEPTIONS=0")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SUBSYSTEM:WINDOWS /DYNAMICBASE:NO /BASE:0x10000 /FIXED")
|
||||
add_compile_options(/Zc:throwingNew- /constexpr:steps16777216)
|
||||
add_compile_definitions(
|
||||
_CRT_SECURE_NO_DEPRECATE=1 _CRT_NON_CONFORMING_SWPRINTFS=1 _SCL_SECURE_NO_WARNINGS=1
|
||||
NOMINMAX _ENABLE_EXTENDED_ALIGNED_STORAGE=1 _HAS_EXCEPTIONS=0)
|
||||
add_link_options(/DYNAMICBASE:NO /BASE:0x10000 /FIXED)
|
||||
|
||||
#TODO: Some of these could be cleaned up
|
||||
add_compile_options(/wd4805) # Comparing boolean and int
|
||||
@@ -12,19 +14,19 @@ if(MSVC)
|
||||
add_link_options(/ignore:4281) # Undesirable base address 0x10000
|
||||
|
||||
# MSVC 2017 uses iterator as base class internally, causing a lot of warning spam
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D _SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING=1")
|
||||
add_compile_definitions(_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING=1)
|
||||
|
||||
# Increase stack limit to 8 MB
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /STACK:8388608,1048576")
|
||||
add_link_options(/STACK:8388608,1048576)
|
||||
else()
|
||||
# Some distros have the compilers set to use PIE by default, but RPCS3 doesn't work with PIE, so we need to disable it.
|
||||
CHECK_CXX_COMPILER_FLAG("-no-pie" HAS_NO_PIE)
|
||||
CHECK_CXX_COMPILER_FLAG("-march=native" COMPILER_SUPPORTS_MARCH_NATIVE)
|
||||
CHECK_CXX_COMPILER_FLAG("-msse -msse2 -mcx16" COMPILER_X86)
|
||||
check_cxx_compiler_flag("-no-pie" HAS_NO_PIE)
|
||||
check_cxx_compiler_flag("-march=native" COMPILER_SUPPORTS_MARCH_NATIVE)
|
||||
check_cxx_compiler_flag("-msse -msse2 -mcx16" COMPILER_X86)
|
||||
if (APPLE)
|
||||
CHECK_CXX_COMPILER_FLAG("-march=armv8.4-a" COMPILER_ARM)
|
||||
check_cxx_compiler_flag("-march=armv8.4-a" COMPILER_ARM)
|
||||
else()
|
||||
CHECK_CXX_COMPILER_FLAG("-march=armv8.1-a" COMPILER_ARM)
|
||||
check_cxx_compiler_flag("-march=armv8.1-a" COMPILER_ARM)
|
||||
endif()
|
||||
|
||||
add_compile_options(-Wall)
|
||||
@@ -65,24 +67,24 @@ else()
|
||||
add_compile_options(-Wstrict-aliasing=1)
|
||||
#add_compile_options(-Wnull-dereference)
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
add_compile_options(-Werror=inconsistent-missing-override)
|
||||
elseif(${CMAKE_CXX_COMPILER_ID} MATCHES "GNU")
|
||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
add_compile_options(-Werror=suggest-override)
|
||||
add_compile_options(-Wclobbered)
|
||||
add_compile_options(-Wcast-function-type)
|
||||
# add_compile_options(-Wcast-function-type)
|
||||
add_compile_options(-Wduplicated-branches)
|
||||
add_compile_options(-Wduplicated-cond)
|
||||
endif()
|
||||
|
||||
#TODO Clean the code so these are removed
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
add_compile_options(-fconstexpr-steps=16777216)
|
||||
add_compile_options(-Wno-unused-lambda-capture)
|
||||
add_compile_options(-Wno-unused-private-field)
|
||||
add_compile_options(-Wno-delete-non-virtual-dtor)
|
||||
add_compile_options(-Wno-unused-command-line-argument)
|
||||
elseif(${CMAKE_CXX_COMPILER_ID} MATCHES "GNU")
|
||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
add_compile_options(-Wno-class-memaccess)
|
||||
endif()
|
||||
|
||||
@@ -92,10 +94,10 @@ else()
|
||||
|
||||
if(NOT APPLE AND NOT WIN32)
|
||||
# This hides our LLVM from mesa's LLVM, otherwise we get some unresolvable conflicts.
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,--exclude-libs,ALL")
|
||||
add_link_options(-Wl,--exclude-libs,ALL)
|
||||
|
||||
if(HAS_NO_PIE)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -no-pie")
|
||||
add_link_options(-no-pie)
|
||||
endif()
|
||||
elseif(APPLE)
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
@@ -103,20 +105,18 @@ else()
|
||||
endif()
|
||||
|
||||
if (CMAKE_OSX_ARCHITECTURES MATCHES "x86_64")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-image_base,0x10000 -Wl,-pagezero_size,0x10000")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-no_pie")
|
||||
add_link_options(-Wl,-image_base,0x10000 -Wl,-pagezero_size,0x10000)
|
||||
add_link_options(-Wl,-no_pie)
|
||||
endif()
|
||||
elseif(WIN32)
|
||||
set(CMAKE_RC_COMPILER_INIT windres)
|
||||
enable_language(RC)
|
||||
set(CMAKE_RC_COMPILE_OBJECT "<CMAKE_RC_COMPILER> <FLAGS> -O coff <DEFINES> -i <SOURCE> -o <OBJECT>")
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D__STDC_FORMAT_MACROS=1")
|
||||
add_compile_definitions(__STDC_FORMAT_MACROS=1)
|
||||
|
||||
# Workaround for mingw64 (MSYS2)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,--allow-multiple-definition")
|
||||
add_link_options(-Wl,--allow-multiple-definition)
|
||||
|
||||
# Increase stack limit to 8 MB
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,--stack -Wl,8388608")
|
||||
add_link_options(-Wl,--stack -Wl,8388608)
|
||||
|
||||
add_link_options(-Wl,--image-base,0x10000)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+48
-66
@@ -1,9 +1,4 @@
|
||||
|
||||
if(USE_PRECOMPILED_HEADERS AND NOT COMMAND target_precompile_headers)
|
||||
include(cotire)
|
||||
endif()
|
||||
|
||||
# Define GNU standard installation directories
|
||||
# Define GNU standard installation directories
|
||||
include(GNUInstallDirs)
|
||||
|
||||
# Generate git-version.h at build time.
|
||||
@@ -16,10 +11,10 @@ include(CheckFunctionExists)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
|
||||
set(ADDITIONAL_LIBS "")
|
||||
if(CMAKE_SYSTEM MATCHES "Linux")
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
#on some Linux distros shm_unlink and similar functions are in librt only
|
||||
set(ADDITIONAL_LIBS ${ADDITIONAL_LIBS} "rt")
|
||||
elseif(NOT MSVC AND NOT CMAKE_CXX_FLAGS MATCHES "LIBICONV_PLUG")
|
||||
elseif(NOT WIN32 AND NOT CMAKE_CXX_FLAGS MATCHES "LIBICONV_PLUG")
|
||||
#it seems like glibc includes the iconv functions we use but other libc
|
||||
#implementations like the one on OSX don't seem implement them
|
||||
set(ADDITIONAL_LIBS ${ADDITIONAL_LIBS} "iconv")
|
||||
@@ -34,24 +29,31 @@ if(UNIX AND NOT APPLE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT RPCS3_SRC_DIR)
|
||||
set(RPCS3_SRC_DIR ${CMAKE_CURRENT_LIST_DIR})
|
||||
message("-- Initializing RPCS3_SRC_DIR=${RPCS3_SRC_DIR}")
|
||||
else()
|
||||
message("-- Using Custom RPCS3_SRC_DIR=${RPCS3_SRC_DIR}")
|
||||
endif()
|
||||
|
||||
# Qt5
|
||||
# Qt
|
||||
# finds Qt libraries and setups custom commands for MOC and UIC
|
||||
# Must be done here because generated MOC and UIC targets cant
|
||||
# be found otherwise
|
||||
include(${CMAKE_SOURCE_DIR}/3rdparty/qt5.cmake)
|
||||
include(${CMAKE_SOURCE_DIR}/3rdparty/qt6.cmake)
|
||||
|
||||
# subdirectories
|
||||
add_subdirectory(Emu)
|
||||
add_subdirectory(rpcs3qt)
|
||||
|
||||
set(RPCS3_SRC
|
||||
if(WIN32)
|
||||
add_executable(rpcs3 WIN32)
|
||||
target_sources(rpcs3 PRIVATE rpcs3.rc)
|
||||
elseif(APPLE)
|
||||
add_executable(rpcs3 MACOSX_BUNDLE)
|
||||
target_sources(rpcs3 PRIVATE rpcs3.icns)
|
||||
set_target_properties(rpcs3
|
||||
PROPERTIES
|
||||
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/rpcs3.plist.in")
|
||||
else()
|
||||
add_executable(rpcs3)
|
||||
endif()
|
||||
|
||||
target_sources(rpcs3
|
||||
PRIVATE
|
||||
display_sleep_control.cpp
|
||||
headless_application.cpp
|
||||
main.cpp
|
||||
@@ -75,36 +77,20 @@ set(RPCS3_SRC
|
||||
Input/xinput_pad_handler.cpp
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
add_executable(rpcs3 WIN32 ${RPCS3_SRC})
|
||||
elseif(APPLE)
|
||||
add_executable(rpcs3 MACOSX_BUNDLE ${RPCS3_SRC} "${RPCS3_SRC_DIR}/rpcs3.icns")
|
||||
set_target_properties(rpcs3
|
||||
PROPERTIES
|
||||
MACOSX_BUNDLE_INFO_PLIST "${RPCS3_SRC_DIR}/rpcs3.plist.in")
|
||||
else()
|
||||
add_executable(rpcs3 ${RPCS3_SRC})
|
||||
endif()
|
||||
|
||||
gen_git_version(${RPCS3_SRC_DIR})
|
||||
gen_git_version(${CMAKE_CURRENT_SOURCE_DIR})
|
||||
set_target_properties(rpcs3
|
||||
PROPERTIES
|
||||
AUTOMOC ON
|
||||
AUTOUIC ON)
|
||||
|
||||
target_link_libraries(rpcs3 rpcs3_emu rpcs3_ui)
|
||||
target_link_libraries(rpcs3 3rdparty::discordRPC 3rdparty::qt5 3rdparty::hidapi 3rdparty::libusb 3rdparty::wolfssl 3rdparty::libcurl)
|
||||
target_link_libraries(rpcs3 ${ADDITIONAL_LIBS})
|
||||
|
||||
# Win resource file
|
||||
if(WIN32)
|
||||
target_sources(rpcs3 PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/rpcs3.rc")
|
||||
endif()
|
||||
target_link_libraries(rpcs3 PRIVATE rpcs3_emu rpcs3_ui)
|
||||
target_link_libraries(rpcs3 PRIVATE 3rdparty::discordRPC 3rdparty::qt6 3rdparty::hidapi 3rdparty::libusb 3rdparty::wolfssl 3rdparty::libcurl 3rdparty::zlib)
|
||||
target_link_libraries(rpcs3 PRIVATE ${ADDITIONAL_LIBS})
|
||||
|
||||
# Unix display manager
|
||||
if(X11_FOUND)
|
||||
target_include_directories(rpcs3 PUBLIC ${X11_INCLUDE_DIR})
|
||||
target_link_libraries(rpcs3 ${X11_LIBRARIES})
|
||||
target_link_libraries(rpcs3 PRIVATE ${X11_LIBRARIES})
|
||||
elseif(USE_VULKAN AND UNIX AND NOT WAYLAND_FOUND AND NOT APPLE)
|
||||
# Wayland has been checked in 3rdparty/CMakeLists.txt already.
|
||||
message(FATAL_ERROR "RPCS3 requires either X11 or Wayland (or both) for Vulkan.")
|
||||
@@ -113,30 +99,26 @@ endif()
|
||||
if(UNIX)
|
||||
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
|
||||
find_package(Threads REQUIRED)
|
||||
target_link_libraries(rpcs3 Threads::Threads)
|
||||
target_link_libraries(rpcs3 PRIVATE Threads::Threads)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(rpcs3 ws2_32.lib Iphlpapi.lib Winmm.lib Psapi.lib gdi32.lib setupapi.lib)
|
||||
target_link_libraries(rpcs3 PRIVATE ws2_32 Iphlpapi Winmm Psapi gdi32 setupapi pdh)
|
||||
else()
|
||||
target_link_libraries(rpcs3 ${CMAKE_DL_LIBS})
|
||||
target_link_libraries(rpcs3 PRIVATE ${CMAKE_DL_LIBS})
|
||||
endif()
|
||||
|
||||
if(USE_PRECOMPILED_HEADERS)
|
||||
if(COMMAND target_precompile_headers)
|
||||
target_precompile_headers(rpcs3 PRIVATE "${RPCS3_SRC_DIR}/stdafx.h")
|
||||
else()
|
||||
set_target_properties(rpcs3 PROPERTIES
|
||||
COTIRE_CXX_PREFIX_HEADER_INIT "${RPCS3_SRC_DIR}/stdafx.h"
|
||||
COTIRE_ADD_UNITY_BUILD OFF)
|
||||
|
||||
cotire(rpcs3)
|
||||
endif()
|
||||
target_precompile_headers(rpcs3 PRIVATE stdafx.h)
|
||||
endif()
|
||||
|
||||
get_target_property(_qmake_executable Qt5::qmake IMPORTED_LOCATION)
|
||||
get_target_property(_qmake_executable Qt6::qmake IMPORTED_LOCATION)
|
||||
get_filename_component(_qt_bin_dir "${_qmake_executable}" DIRECTORY)
|
||||
find_program(MACDEPLOYQT_EXECUTABLE macdeployqt HINTS "${_qt_bin_dir}")
|
||||
if(APPLE)
|
||||
find_program(MACDEPLOYQT_EXECUTABLE macdeployqt HINTS "${_qt_bin_dir}")
|
||||
elseif(WIN32)
|
||||
find_program(WINDEPLOYQT_EXECUTABLE windeployqt HINTS "${_qt_bin_dir}")
|
||||
endif()
|
||||
|
||||
# Copy icons to executable directory
|
||||
if(APPLE)
|
||||
@@ -147,7 +129,7 @@ if(APPLE)
|
||||
endif()
|
||||
add_custom_command(TARGET rpcs3 POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy
|
||||
${RPCS3_SRC_DIR}/rpcs3.icns $<TARGET_FILE_DIR:rpcs3>/../Resources/rpcs3.icns
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rpcs3.icns $<TARGET_FILE_DIR:rpcs3>/../Resources/rpcs3.icns
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||
${CMAKE_SOURCE_DIR}/bin/Icons $<TARGET_FILE_DIR:rpcs3>/../Resources/Icons
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||
@@ -174,27 +156,27 @@ elseif(WIN32)
|
||||
|
||||
# Qt installed from Qt installer has following hierarchy:
|
||||
# bin/ for release and debug dlls and windeployqt tools
|
||||
# lib/cmake/Qt5/ for Qt5_Dir
|
||||
# lib/cmake/Qt6/ for Qt6_Dir
|
||||
# Qt installed from vcpkg has following hierarchy:
|
||||
# bin/ for release dlls
|
||||
# debug/bin/ for debug dlls
|
||||
# tools/qt5/bin/ for tools including windeployqt
|
||||
# tools/qt5/debug/bin/ for tools with debug build including windeployqt
|
||||
# share/cmake/Qt5/ for Qt5_Dir
|
||||
# tools/qt6/bin/ for tools including windeployqt
|
||||
# tools/qt6/debug/bin/ for tools with debug build including windeployqt
|
||||
# share/cmake/Qt6/ for Qt6_Dir
|
||||
|
||||
# If Qt5 is installed from official Qt installer
|
||||
list(APPEND _QT5_TOOLS_PATHS "${Qt5_DIR}/../../../bin/")
|
||||
# If Qt is installed from official Qt installer
|
||||
# list(APPEND _QT6_TOOLS_PATHS "${Qt6_DIR}/../../../bin/")
|
||||
|
||||
# If Qt5 is installed from vcpkg
|
||||
list(APPEND _QT5_TOOLS_PATHS "${Qt5_DIR}/../../../tools/qt5$<$<CONFIG:Debug>:/debug>/bin/")
|
||||
# If Qt is installed from vcpkg
|
||||
# list(APPEND _QT6_TOOLS_PATHS "${Qt6_DIR}/../../../tools/qt6$<$<CONFIG:Debug>:/debug>/bin/")
|
||||
|
||||
add_custom_command(TARGET rpcs3 POST_BUILD
|
||||
COMMAND set PATH=${_QT5_TOOLS_PATHS}$<SEMICOLON>%PATH%
|
||||
# COMMAND set PATH=${_QT6_TOOLS_PATHS}$<SEMICOLON>%PATH%
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_directory "${CMAKE_SOURCE_DIR}/bin" "$<TARGET_FILE_DIR:rpcs3>"
|
||||
# If Qt5 is installed from vcpkg, add binary path to PATH
|
||||
# If Qt is installed from vcpkg, add binary path to PATH
|
||||
# otherwise windeployqt tool won't be able to locate necessary dlls
|
||||
COMMAND set PATH=${Qt5_DIR}/../../../$<$<CONFIG:Debug>:debug/>bin/$<SEMICOLON>%PATH%
|
||||
COMMAND "${_WINDEPLOYQT}" --no-angle --no-compiler-runtime --no-opengl-sw --no-patchqt --no-translations --no-quick --plugindir "$<TARGET_FILE_DIR:rpcs3>/qt/plugins" $<$<CONFIG:Debug>:--debug> $<$<CONFIG:Release>:--release> "$<TARGET_FILE:rpcs3>")
|
||||
# COMMAND set PATH=${Qt6_DIR}/../../../$<$<CONFIG:Debug>:debug/>bin/$<SEMICOLON>%PATH%
|
||||
COMMAND "${WINDEPLOYQT_EXECUTABLE}" --no-compiler-runtime --no-opengl-sw --no-patchqt --no-translations --no-quick --no-system-d3d-compiler --no-quick-import --plugindir "$<TARGET_FILE_DIR:rpcs3>/qt6/plugins" --verbose 0 "$<TARGET_FILE:rpcs3>")
|
||||
endif()
|
||||
|
||||
# Unix installation
|
||||
|
||||
@@ -11,46 +11,77 @@
|
||||
|
||||
LOG_CHANNEL(dec_log, "DECRYPT");
|
||||
|
||||
void decrypt_sprx_libraries(std::vector<std::string> modules, std::function<std::string(std::string old_path, std::string path, bool tried)> input_cb)
|
||||
usz decrypt_binaries_t::decrypt(std::string klic_input)
|
||||
{
|
||||
if (modules.empty())
|
||||
if (m_index >= m_modules.size())
|
||||
{
|
||||
std::cout << "No paths specified" << std::endl; // For CLI
|
||||
return;
|
||||
m_index = umax;
|
||||
return umax;
|
||||
}
|
||||
|
||||
dec_log.notice("Decrypting binaries...");
|
||||
std::cout << "Decrypting binaries..." << std::endl; // For CLI
|
||||
|
||||
// Always start with no KLIC
|
||||
std::vector<u128> klics{u128{}};
|
||||
|
||||
if (const auto keys = g_fxo->try_get<loaded_npdrm_keys>())
|
||||
if (m_klics.empty())
|
||||
{
|
||||
// Second klic: get it from a running game
|
||||
if (const u128 klic = keys->last_key())
|
||||
dec_log.notice("Decrypting binaries...");
|
||||
std::cout << "Decrypting binaries..." << std::endl; // For CLI
|
||||
|
||||
// Always start with no KLIC
|
||||
m_klics.emplace_back(u128{});
|
||||
|
||||
if (const auto keys = g_fxo->try_get<loaded_npdrm_keys>())
|
||||
{
|
||||
klics.emplace_back(klic);
|
||||
// Second klic: get it from a running game
|
||||
if (const u128 klic = keys->last_key())
|
||||
{
|
||||
m_klics.emplace_back(klic);
|
||||
}
|
||||
}
|
||||
|
||||
// Try to use the key that has been for the current running ELF
|
||||
m_klics.insert(m_klics.end(), Emu.klic.begin(), Emu.klic.end());
|
||||
}
|
||||
|
||||
if (std::string_view text = std::string_view{klic_input}.substr(klic_input.find_first_of('x') + 1); text.size() == 32)
|
||||
{
|
||||
// Allowed to fail (would simply repeat the operation if fails again)
|
||||
u64 lo = 0;
|
||||
u64 hi = 0;
|
||||
bool success = false;
|
||||
|
||||
if (auto res = std::from_chars(text.data() + 0, text.data() + 16, lo, 16); res.ec == std::errc() && res.ptr == text.data() + 16)
|
||||
{
|
||||
if (res = std::from_chars(text.data() + 16, text.data() + 32, hi, 16); res.ec == std::errc() && res.ptr == text.data() + 32)
|
||||
{
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (success)
|
||||
{
|
||||
lo = std::bit_cast<be_t<u64>>(lo);
|
||||
hi = std::bit_cast<be_t<u64>>(hi);
|
||||
|
||||
if (u128 input_key = ((u128{hi} << 64) | lo))
|
||||
{
|
||||
m_klics.emplace_back(input_key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Try to use the key that has been for the current running ELF
|
||||
klics.insert(klics.end(), Emu.klic.begin(), Emu.klic.end());
|
||||
|
||||
for (const std::string& _module : modules)
|
||||
while (m_index < m_modules.size())
|
||||
{
|
||||
const std::string& _module = m_modules[m_index];
|
||||
const std::string old_path = _module;
|
||||
|
||||
fs::file elf_file;
|
||||
|
||||
bool tried = false;
|
||||
bool invalid = false;
|
||||
usz key_it = 0;
|
||||
u32 file_magic{};
|
||||
|
||||
while (true)
|
||||
{
|
||||
for (; key_it < klics.size(); key_it++)
|
||||
for (; key_it < m_klics.size(); key_it++)
|
||||
{
|
||||
if (!elf_file.open(old_path) || !elf_file.read(file_magic))
|
||||
{
|
||||
@@ -62,7 +93,7 @@ void decrypt_sprx_libraries(std::vector<std::string> modules, std::function<std:
|
||||
case "SCE\0"_u32:
|
||||
{
|
||||
// First KLIC is no KLIC
|
||||
elf_file = decrypt_self(std::move(elf_file), key_it != 0 ? reinterpret_cast<u8*>(&klics[key_it]) : nullptr);
|
||||
elf_file = decrypt_self(std::move(elf_file), key_it != 0 ? reinterpret_cast<u8*>(&m_klics[key_it]) : nullptr);
|
||||
|
||||
if (!elf_file)
|
||||
{
|
||||
@@ -75,7 +106,7 @@ void decrypt_sprx_libraries(std::vector<std::string> modules, std::function<std:
|
||||
case "NPD\0"_u32:
|
||||
{
|
||||
// EDAT / SDAT
|
||||
elf_file = DecryptEDAT(elf_file, old_path, key_it != 0 ? 8 : 1, reinterpret_cast<u8*>(&klics[key_it]), true);
|
||||
elf_file = DecryptEDAT(elf_file, old_path, key_it != 0 ? 8 : 1, reinterpret_cast<u8*>(&m_klics[key_it]), true);
|
||||
|
||||
if (!elf_file)
|
||||
{
|
||||
@@ -111,11 +142,13 @@ void decrypt_sprx_libraries(std::vector<std::string> modules, std::function<std:
|
||||
new_file.write(elf_file.to_string());
|
||||
dec_log.success("Decrypted %s -> %s", old_path, new_path);
|
||||
std::cout << "Decrypted " << old_path << " -> " << new_path << std::endl; // For CLI
|
||||
m_index++;
|
||||
}
|
||||
else
|
||||
{
|
||||
dec_log.error("Failed to create %s", new_path);
|
||||
std::cout << "Failed to create " << new_path << std::endl; // For CLI
|
||||
m_index = umax;
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -124,42 +157,16 @@ void decrypt_sprx_libraries(std::vector<std::string> modules, std::function<std:
|
||||
if (!invalid)
|
||||
{
|
||||
// Allow the user to manually type KLIC if decryption failed
|
||||
|
||||
const std::string filename = old_path.substr(old_path.find_last_of(fs::delim) + 1);
|
||||
const std::string text = input_cb ? input_cb(old_path, filename, tried) : "";
|
||||
|
||||
if (!text.empty())
|
||||
{
|
||||
auto& klic = (tried ? klics.back() : klics.emplace_back());
|
||||
|
||||
ensure(text.size() == 32);
|
||||
|
||||
// It must succeed (only hex characters are present)
|
||||
u64 lo_ = 0;
|
||||
u64 hi_ = 0;
|
||||
std::from_chars(&text[0], &text[16], lo_, 16);
|
||||
std::from_chars(&text[16], &text[32], hi_, 16);
|
||||
|
||||
be_t<u64> lo = std::bit_cast<be_t<u64>>(lo_);
|
||||
be_t<u64> hi = std::bit_cast<be_t<u64>>(hi_);
|
||||
|
||||
klic = (u128{+hi} << 64) | +lo;
|
||||
|
||||
// Retry with specified KLIC
|
||||
key_it -= +std::exchange(tried, true); // Rewind on second and above attempt
|
||||
dec_log.notice("KLIC entered for %s: %s", filename, klic);
|
||||
continue;
|
||||
}
|
||||
|
||||
dec_log.notice("User has cancelled entering KLIC.");
|
||||
return m_index;
|
||||
}
|
||||
|
||||
dec_log.error("Failed to decrypt \"%s\".", old_path);
|
||||
std::cout << "Failed to decrypt \"" << old_path << "\"." << std::endl; // For CLI
|
||||
break;
|
||||
return m_index;
|
||||
}
|
||||
}
|
||||
|
||||
dec_log.notice("Finished decrypting all binaries.");
|
||||
std::cout << "Finished decrypting all binaries." << std::endl; // For CLI
|
||||
return m_index;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
void decrypt_sprx_libraries(std::vector<std::string> modules, std::function<std::string(std::string old_path, std::string path, bool tried)> input_cb);
|
||||
class decrypt_binaries_t
|
||||
{
|
||||
std::vector<u128> m_klics;
|
||||
std::vector<std::string> m_modules;
|
||||
usz m_index = 0;
|
||||
|
||||
public:
|
||||
decrypt_binaries_t(std::vector<std::string> modules) noexcept
|
||||
: m_modules(std::move(modules))
|
||||
{
|
||||
}
|
||||
|
||||
usz decrypt(std::string klic_input = {});
|
||||
|
||||
bool done() const
|
||||
{
|
||||
return m_index >= m_klics.size();
|
||||
}
|
||||
|
||||
const std::string& operator[](usz index) const
|
||||
{
|
||||
return ::at32(m_modules, index);
|
||||
}
|
||||
};
|
||||
|
||||
+65
-101
@@ -5,21 +5,9 @@
|
||||
#include "utils.h"
|
||||
#include <cstring>
|
||||
|
||||
static void bn_zero(u8* d, u32 n)
|
||||
static inline int bn_compare(u8* a, u8* b, u32 n)
|
||||
{
|
||||
memset(d, 0, n);
|
||||
}
|
||||
|
||||
static void bn_copy(u8* d, u8* a, u32 n)
|
||||
{
|
||||
memcpy(d, a, n);
|
||||
}
|
||||
|
||||
static int bn_compare(u8* a, u8* b, u32 n)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
for (u32 i = 0; i < n; i++)
|
||||
{
|
||||
if (a[i] < b[i])
|
||||
return -1;
|
||||
@@ -32,14 +20,10 @@ static int bn_compare(u8* a, u8* b, u32 n)
|
||||
|
||||
static u8 bn_add_1(u8* d, u8* a, u8* b, u32 n)
|
||||
{
|
||||
u32 i;
|
||||
u32 dig;
|
||||
u8 c;
|
||||
|
||||
c = 0;
|
||||
for (i = n - 1; i < n; i--)
|
||||
u8 c = 0;
|
||||
for (u32 i = n - 1; i != umax; i--)
|
||||
{
|
||||
dig = a[i] + b[i] + c;
|
||||
const u32 dig = a[i] + b[i] + c;
|
||||
c = dig >> 8;
|
||||
d[i] = dig;
|
||||
}
|
||||
@@ -49,14 +33,10 @@ static u8 bn_add_1(u8* d, u8* a, u8* b, u32 n)
|
||||
|
||||
static u8 bn_sub_1(u8* d, u8* a, u8* b, u32 n)
|
||||
{
|
||||
u32 i;
|
||||
u32 dig;
|
||||
u8 c;
|
||||
|
||||
c = 1;
|
||||
for (i = n - 1; i < n; i--)
|
||||
u8 c = 1;
|
||||
for (u32 i = n - 1; i != umax; i--)
|
||||
{
|
||||
dig = a[i] + 255 - b[i] + c;
|
||||
const u32 dig = a[i] + 255 - b[i] + c;
|
||||
c = dig >> 8;
|
||||
d[i] = dig;
|
||||
}
|
||||
@@ -105,15 +85,12 @@ static constexpr u8 inv256[0x80] = {
|
||||
|
||||
static void bn_mon_muladd_dig(u8* d, u8* a, u8 b, u8* N, u32 n)
|
||||
{
|
||||
u32 dig;
|
||||
u32 i;
|
||||
|
||||
const u8 z = -(d[n - 1] + a[n - 1] * b) * inv256[N[n - 1] / 2];
|
||||
|
||||
dig = d[n - 1] + a[n - 1] * b + N[n - 1] * z;
|
||||
u32 dig = d[n - 1] + a[n - 1] * b + N[n - 1] * z;
|
||||
dig >>= 8;
|
||||
|
||||
for (i = n - 2; i < n; i--)
|
||||
for (u32 i = n - 2; i < n; i--)
|
||||
{
|
||||
dig += d[i] + a[i] * b + N[i] * z;
|
||||
d[i + 1] = dig;
|
||||
@@ -132,21 +109,17 @@ static void bn_mon_muladd_dig(u8* d, u8* a, u8 b, u8* N, u32 n)
|
||||
static void bn_mon_mul(u8* d, u8* a, u8* b, u8* N, u32 n)
|
||||
{
|
||||
u8 t[512];
|
||||
u32 i;
|
||||
memset(t, 0, n);
|
||||
|
||||
bn_zero(t, n);
|
||||
|
||||
for (i = n - 1; i < n; i--)
|
||||
for (u32 i = n - 1; i != umax; i--)
|
||||
bn_mon_muladd_dig(t, a, b[i], N, n);
|
||||
|
||||
bn_copy(d, t, n);
|
||||
memcpy(d, t, n);
|
||||
}
|
||||
|
||||
static void bn_to_mon(u8* d, u8* N, u32 n)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < 8 * n; i++)
|
||||
for (u32 i = 0; i < 8 * n; i++)
|
||||
bn_add(d, d, d, N, n);
|
||||
}
|
||||
|
||||
@@ -154,7 +127,7 @@ static void bn_from_mon(u8* d, u8* N, u32 n)
|
||||
{
|
||||
u8 t[512];
|
||||
|
||||
bn_zero(t, n);
|
||||
memset(t, 0, n);
|
||||
t[n - 1] = 1;
|
||||
bn_mon_mul(d, d, t, N, n);
|
||||
}
|
||||
@@ -162,29 +135,29 @@ static void bn_from_mon(u8* d, u8* N, u32 n)
|
||||
static void bn_mon_exp(u8* d, u8* a, u8* N, u32 n, u8* e, u32 en)
|
||||
{
|
||||
u8 t[512];
|
||||
u32 i;
|
||||
u8 mask;
|
||||
|
||||
bn_zero(d, n);
|
||||
memset(d, 0, n);
|
||||
d[n - 1] = 1;
|
||||
bn_to_mon(d, N, n);
|
||||
|
||||
for (i = 0; i < en; i++)
|
||||
for (mask = 0x80; mask != 0; mask >>= 1)
|
||||
for (u32 i = 0; i < en; i++)
|
||||
{
|
||||
for (u8 mask = 0x80; mask != 0; mask >>= 1)
|
||||
{
|
||||
bn_mon_mul(t, d, d, N, n);
|
||||
if ((e[i] & mask) != 0)
|
||||
bn_mon_mul(d, t, a, N, n);
|
||||
else
|
||||
bn_copy(d, t, n);
|
||||
memcpy(d, t, n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void bn_mon_inv(u8* d, u8* a, u8* N, u32 n)
|
||||
{
|
||||
u8 t[512], s[512];
|
||||
|
||||
bn_zero(s, n);
|
||||
memset(s, 0, n);
|
||||
s[n - 1] = 2;
|
||||
bn_sub_1(t, N, s, n);
|
||||
bn_mon_exp(d, a, N, n, t, n);
|
||||
@@ -203,26 +176,16 @@ static thread_local u8 ec_N[21]{};
|
||||
static thread_local point ec_G{}; // mon
|
||||
static thread_local point ec_Q{}; // mon
|
||||
static thread_local u8 ec_k[21]{};
|
||||
static thread_local bool ec_curve_initialized{};
|
||||
static thread_local bool ec_pub_initialized{};
|
||||
|
||||
static void elt_copy(u8* d, u8* a)
|
||||
static inline bool elt_is_zero(u8* d)
|
||||
{
|
||||
memcpy(d, a, 20);
|
||||
}
|
||||
|
||||
static void elt_zero(u8* d)
|
||||
{
|
||||
memset(d, 0, 20);
|
||||
}
|
||||
|
||||
static int elt_is_zero(u8* d)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < 20; i++)
|
||||
for (u32 i = 0; i < 20; i++)
|
||||
if (d[i] != 0)
|
||||
return 0;
|
||||
return false;
|
||||
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void elt_add(u8* d, u8* a, u8* b)
|
||||
@@ -248,7 +211,7 @@ static void elt_square(u8* d, u8* a)
|
||||
static void elt_inv(u8* d, u8* a)
|
||||
{
|
||||
u8 s[20];
|
||||
elt_copy(s, a);
|
||||
memcpy(s, a, 20);
|
||||
bn_mon_inv(d, s, ec_p, 20);
|
||||
}
|
||||
|
||||
@@ -264,13 +227,13 @@ static void point_from_mon(point* p)
|
||||
bn_from_mon(p->y, ec_p, 20);
|
||||
}
|
||||
|
||||
static void point_zero(point* p)
|
||||
static inline void point_zero(point* p)
|
||||
{
|
||||
elt_zero(p->x);
|
||||
elt_zero(p->y);
|
||||
memset(p->x, 0, 20);
|
||||
memset(p->y, 0, 20);
|
||||
}
|
||||
|
||||
static int point_is_zero(point* p)
|
||||
static inline bool point_is_zero(point* p)
|
||||
{
|
||||
return elt_is_zero(p->x) && elt_is_zero(p->y);
|
||||
}
|
||||
@@ -278,15 +241,13 @@ static int point_is_zero(point* p)
|
||||
static void point_double(point* r, point* p)
|
||||
{
|
||||
u8 s[20], t[20];
|
||||
point pp;
|
||||
u8 *px, *py, *rx, *ry;
|
||||
|
||||
pp = *p;
|
||||
point pp = *p;
|
||||
|
||||
px = pp.x;
|
||||
py = pp.y;
|
||||
rx = r->x;
|
||||
ry = r->y;
|
||||
u8* px = pp.x;
|
||||
u8* py = pp.y;
|
||||
u8* rx = r->x;
|
||||
u8* ry = r->y;
|
||||
|
||||
if (elt_is_zero(py))
|
||||
{
|
||||
@@ -314,30 +275,28 @@ static void point_double(point* r, point* p)
|
||||
static void point_add(point* r, point* p, point* q)
|
||||
{
|
||||
u8 s[20], t[20], u[20];
|
||||
u8 *px, *py, *qx, *qy, *rx, *ry;
|
||||
point pp, qq;
|
||||
|
||||
pp = *p;
|
||||
qq = *q;
|
||||
point pp = *p;
|
||||
point qq = *q;
|
||||
|
||||
px = pp.x;
|
||||
py = pp.y;
|
||||
qx = qq.x;
|
||||
qy = qq.y;
|
||||
rx = r->x;
|
||||
ry = r->y;
|
||||
u8* px = pp.x;
|
||||
u8* py = pp.y;
|
||||
u8* qx = qq.x;
|
||||
u8* qy = qq.y;
|
||||
u8* rx = r->x;
|
||||
u8* ry = r->y;
|
||||
|
||||
if (point_is_zero(&pp))
|
||||
{
|
||||
elt_copy(rx, qx);
|
||||
elt_copy(ry, qy);
|
||||
memcpy(rx, qx, 20);
|
||||
memcpy(ry, qy, 20);
|
||||
return;
|
||||
}
|
||||
|
||||
if (point_is_zero(&qq))
|
||||
{
|
||||
elt_copy(rx, px);
|
||||
elt_copy(ry, py);
|
||||
memcpy(rx, px, 20);
|
||||
memcpy(ry, py, 20);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -369,21 +328,20 @@ static void point_add(point* r, point* p, point* q)
|
||||
|
||||
static void point_mul(point* d, u8* a, point* b) // a is bignum
|
||||
{
|
||||
u32 i;
|
||||
u8 mask;
|
||||
|
||||
point_zero(d);
|
||||
|
||||
for (i = 0; i < 21; i++)
|
||||
for (mask = 0x80; mask != 0; mask >>= 1)
|
||||
for (u32 i = 0; i < 21; i++)
|
||||
{
|
||||
for (u8 mask = 0x80; mask != 0; mask >>= 1)
|
||||
{
|
||||
point_double(d, d);
|
||||
if ((a[i] & mask) != 0)
|
||||
point_add(d, d, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int check_ecdsa(struct point* Q, u8* R, u8* S, u8* hash)
|
||||
static bool check_ecdsa(struct point* Q, u8* R, u8* S, u8* hash)
|
||||
{
|
||||
u8 Sinv[21];
|
||||
u8 e[21];
|
||||
@@ -424,8 +382,10 @@ static int check_ecdsa(struct point* Q, u8* R, u8* S, u8* hash)
|
||||
return (bn_compare(rr, R, 21) == 0);
|
||||
}
|
||||
|
||||
int ecdsa_set_curve(const u8* p, const u8* a, const u8* b, const u8* N, const u8* Gx, const u8* Gy)
|
||||
void ecdsa_set_curve(const u8* p, const u8* a, const u8* b, const u8* N, const u8* Gx, const u8* Gy)
|
||||
{
|
||||
if (ec_curve_initialized) return;
|
||||
|
||||
memcpy(ec_p, p, 20);
|
||||
memcpy(ec_a, a, 20);
|
||||
memcpy(ec_b, b, 20);
|
||||
@@ -438,14 +398,18 @@ int ecdsa_set_curve(const u8* p, const u8* a, const u8* b, const u8* N, const u8
|
||||
|
||||
point_to_mon(&ec_G);
|
||||
|
||||
return 0;
|
||||
ec_curve_initialized = true;
|
||||
}
|
||||
|
||||
void ecdsa_set_pub(const u8* Q)
|
||||
{
|
||||
if (ec_pub_initialized) return;
|
||||
|
||||
memcpy(ec_Q.x, Q, 20);
|
||||
memcpy(ec_Q.y, Q+20, 20);
|
||||
memcpy(ec_Q.y, Q + 20, 20);
|
||||
point_to_mon(&ec_Q);
|
||||
|
||||
ec_pub_initialized = true;
|
||||
}
|
||||
|
||||
void ecdsa_set_priv(const u8* k)
|
||||
@@ -453,7 +417,7 @@ void ecdsa_set_priv(const u8* k)
|
||||
memcpy(ec_k, k, sizeof ec_k);
|
||||
}
|
||||
|
||||
int ecdsa_verify(u8* hash, u8* R, u8* S)
|
||||
bool ecdsa_verify(u8* hash, u8* R, u8* S)
|
||||
{
|
||||
return check_ecdsa(&ec_Q, R, S, hash);
|
||||
}
|
||||
|
||||
+2
-2
@@ -6,7 +6,7 @@
|
||||
|
||||
#include "util/types.hpp"
|
||||
|
||||
int ecdsa_set_curve(const u8* p, const u8* a, const u8* b, const u8* N, const u8* Gx, const u8* Gy);
|
||||
void ecdsa_set_curve(const u8* p, const u8* a, const u8* b, const u8* N, const u8* Gx, const u8* Gy);
|
||||
void ecdsa_set_pub(const u8* Q);
|
||||
void ecdsa_set_priv(const u8* k);
|
||||
int ecdsa_verify(u8* hash, u8* R, u8* S);
|
||||
bool ecdsa_verify(u8* hash, u8* R, u8* S);
|
||||
|
||||
@@ -493,7 +493,9 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
|
||||
memcpy(signature_r + 01, metadata_signature, 0x14);
|
||||
memcpy(signature_s + 01, metadata_signature + 0x14, 0x14);
|
||||
if ((!memcmp(signature_r, zero_buf, 0x15)) || (!memcmp(signature_s, zero_buf, 0x15)))
|
||||
{
|
||||
edat_log.warning("Metadata signature is invalid!");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Setup signature hash.
|
||||
@@ -524,7 +526,9 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
|
||||
memcpy(signature_s + 01, header_signature + 0x14, 0x14);
|
||||
|
||||
if ((!memcmp(signature_r, zero_buf, 0x15)) || (!memcmp(signature_s, zero_buf, 0x15)))
|
||||
{
|
||||
edat_log.warning("Header signature is invalid!");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Setup header signature hash.
|
||||
|
||||
@@ -95,9 +95,9 @@ public:
|
||||
bool ReadHeader();
|
||||
u64 ReadData(u64 pos, u8* data, u64 size);
|
||||
|
||||
fs::stat_t stat() override
|
||||
fs::stat_t get_stat() override
|
||||
{
|
||||
fs::stat_t stats = edata_file.stat();
|
||||
fs::stat_t stats = edata_file.get_stat();
|
||||
stats.is_writable = false; // TODO
|
||||
stats.size = file_size;
|
||||
return stats;
|
||||
@@ -143,4 +143,11 @@ public:
|
||||
}
|
||||
|
||||
u64 size() override { return file_size; }
|
||||
|
||||
fs::file_id get_id() override
|
||||
{
|
||||
fs::file_id id = edata_file.get_id();
|
||||
id.type.insert(0, "EDATADecrypter: "sv);
|
||||
return id;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -67,7 +67,7 @@ bool package_reader::read_header()
|
||||
}
|
||||
|
||||
pkg_log.notice("Path: '%s'", m_path);
|
||||
pkg_log.notice("Header: pkg_magic = 0x%x = \"%s\"", +m_header.pkg_magic, std::string(reinterpret_cast<const char*>(&m_header.pkg_magic), 4));
|
||||
pkg_log.notice("Header: pkg_magic = 0x%x = \"%s\"", +m_header.pkg_magic, std::string_view(reinterpret_cast<const char*>(&m_header.pkg_magic + 1), 3)); // Skip 0x7F
|
||||
pkg_log.notice("Header: pkg_type = 0x%x = %d", m_header.pkg_type, m_header.pkg_type);
|
||||
pkg_log.notice("Header: pkg_platform = 0x%x = %d", m_header.pkg_platform, m_header.pkg_platform);
|
||||
pkg_log.notice("Header: meta_offset = 0x%x = %d", m_header.meta_offset, m_header.meta_offset);
|
||||
@@ -94,7 +94,7 @@ bool package_reader::read_header()
|
||||
return false;
|
||||
}
|
||||
|
||||
pkg_log.notice("Extended header: magic = 0x%x = \"%s\"", +ext_header.magic, std::string(reinterpret_cast<const char*>(&ext_header.magic), 4));
|
||||
pkg_log.notice("Extended header: magic = 0x%x = \"%s\"", +ext_header.magic, std::string_view(reinterpret_cast<const char*>(&ext_header.magic + 1), 3));
|
||||
pkg_log.notice("Extended header: unknown_1 = 0x%x = %d", ext_header.unknown_1, ext_header.unknown_1);
|
||||
pkg_log.notice("Extended header: ext_hdr_size = 0x%x = %d", ext_header.ext_hdr_size, ext_header.ext_hdr_size);
|
||||
pkg_log.notice("Extended header: ext_data_size = 0x%x = %d", ext_header.ext_data_size, ext_header.ext_data_size);
|
||||
@@ -782,7 +782,7 @@ bool package_reader::fill_data(std::map<std::string, install_entry*>& all_instal
|
||||
const bool is_psp = (entry.type & PKG_FILE_ENTRY_PSP) != 0u;
|
||||
decrypt(entry.name_offset, entry.name_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data());
|
||||
|
||||
const std::string name{reinterpret_cast<char*>(m_bufs.back().get()), entry.name_size};
|
||||
const std::string_view name{reinterpret_cast<char*>(m_bufs.back().get()), entry.name_size};
|
||||
std::string path = m_install_path + vfs::escape(name);
|
||||
|
||||
if (entry.pad || (entry.type & ~PKG_FILE_ENTRY_KNOWN_BITS))
|
||||
@@ -833,7 +833,7 @@ bool package_reader::fill_data(std::map<std::string, install_entry*>& all_instal
|
||||
|
||||
m_install_entries.push_back({
|
||||
.weak_reference = map_ptr,
|
||||
.name = name,
|
||||
.name = std::string(name),
|
||||
.file_offset = entry.file_offset,
|
||||
.file_size = entry.file_size,
|
||||
.type = entry.type,
|
||||
|
||||
@@ -871,7 +871,7 @@ bool SELFDecrypter::LoadHeaders(bool isElf32, SelfAdditionalInfo* out_info)
|
||||
|
||||
if (out_info)
|
||||
{
|
||||
out_info->valid = false;
|
||||
*out_info = {};
|
||||
}
|
||||
|
||||
// Check SCE magic.
|
||||
@@ -1411,7 +1411,7 @@ fs::file decrypt_self(fs::file elf_or_self, u8* klic_key, SelfAdditionalInfo* ou
|
||||
{
|
||||
if (out_info)
|
||||
{
|
||||
out_info->valid = false;
|
||||
*out_info = {};
|
||||
}
|
||||
|
||||
if (!elf_or_self)
|
||||
|
||||
@@ -158,6 +158,6 @@ AudioChannelCnt AudioBackend::convert_channel_count(u64 raw)
|
||||
case 1:
|
||||
return AudioChannelCnt::STEREO;
|
||||
case 0:
|
||||
fmt::throw_exception("Usupported channel count");
|
||||
fmt::throw_exception("Unsupported channel count");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -543,7 +543,7 @@ void CubebBackend::device_collection_changed_cb(cubeb* context, void* user_ptr)
|
||||
|
||||
if (context != cubeb->m_ctx)
|
||||
{
|
||||
Cubeb.error("device_collection_changed_cb called with unkown context");
|
||||
Cubeb.error("device_collection_changed_cb called with unknown context");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,13 @@
|
||||
#include <Windows.h>
|
||||
#include <system_error>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma comment(lib, "xaudio2_9redist.lib")
|
||||
#endif
|
||||
|
||||
#ifndef XAUDIO2_USE_DEFAULT_PROCESSOR
|
||||
#define XAUDIO2_USE_DEFAULT_PROCESSOR XAUDIO2_DEFAULT_PROCESSOR
|
||||
#endif
|
||||
|
||||
LOG_CHANNEL(XAudio);
|
||||
|
||||
@@ -26,6 +32,7 @@ void fmt_class_string<ERole>::format(std::string& out, u64 arg)
|
||||
case eConsole: return "eConsole";
|
||||
case eMultimedia: return "eMultimedia";
|
||||
case eCommunications: return "eCommunications";
|
||||
case ERole_enum_count: return unknown;
|
||||
}
|
||||
|
||||
return unknown;
|
||||
@@ -42,6 +49,7 @@ void fmt_class_string<EDataFlow>::format(std::string& out, u64 arg)
|
||||
case eRender: return "eRender";
|
||||
case eCapture: return "eCapture";
|
||||
case eAll: return "eAll";
|
||||
case EDataFlow_enum_count: return unknown;
|
||||
}
|
||||
|
||||
return unknown;
|
||||
@@ -309,9 +317,12 @@ f64 XAudio2Backend::GetCallbackFrameLen()
|
||||
return _10ms;
|
||||
}
|
||||
|
||||
#if _MSC_VER
|
||||
Microsoft::WRL::ComPtr<IXAudio2Extension> xaudio_ext{};
|
||||
#endif
|
||||
f64 min_latency{};
|
||||
|
||||
#if _MSC_VER
|
||||
if (HRESULT hr = m_xaudio2_instance->QueryInterface(IID_IXAudio2Extension, std::bit_cast<void**>(xaudio_ext.GetAddressOf())); FAILED(hr))
|
||||
{
|
||||
XAudio.error("QueryInterface() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
||||
@@ -326,6 +337,7 @@ f64 XAudio2Backend::GetCallbackFrameLen()
|
||||
min_latency = static_cast<f64>(samples_per_q) / freq;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return std::max<f64>(min_latency, _10ms); // 10ms is the minimum for XAudio
|
||||
}
|
||||
|
||||
@@ -8,7 +8,11 @@
|
||||
#include "Utilities/mutex.h"
|
||||
#include "Emu/Audio/AudioBackend.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <xaudio2redist.h>
|
||||
#else
|
||||
#include <xaudio2.h>
|
||||
#endif
|
||||
#include <wrl/client.h>
|
||||
#include <MMDeviceAPI.h>
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#ifndef _MSC_VER
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wsuggest-override"
|
||||
#pragma GCC diagnostic ignored "-Wold-style-cast"
|
||||
#endif
|
||||
#include "SoundTouch.h"
|
||||
#ifndef _MSC_VER
|
||||
|
||||
+34
-25
@@ -1,4 +1,4 @@
|
||||
add_library(rpcs3_emu
|
||||
add_library(rpcs3_emu STATIC
|
||||
cache_utils.cpp
|
||||
games_config.cpp
|
||||
IdManager.cpp
|
||||
@@ -19,8 +19,9 @@ add_library(rpcs3_emu
|
||||
IPC_socket.cpp
|
||||
)
|
||||
|
||||
# prevent WolfSSL from warning about not having harden options
|
||||
add_compile_definitions(WC_NO_HARDEN)
|
||||
if(USE_ASAN)
|
||||
set_source_files_properties(../../Utilities/Thread.cpp PROPERTIES COMPILE_DEFINITIONS USE_ASAN)
|
||||
endif()
|
||||
|
||||
target_link_libraries(rpcs3_emu
|
||||
PRIVATE
|
||||
@@ -36,7 +37,7 @@ target_link_libraries(rpcs3_emu
|
||||
# For stdafx.h
|
||||
target_include_directories(rpcs3_emu
|
||||
PUBLIC
|
||||
${RPCS3_SRC_DIR})
|
||||
${PROJECT_SOURCE_DIR}/rpcs3)
|
||||
|
||||
# Utilities
|
||||
target_sources(rpcs3_emu PRIVATE
|
||||
@@ -78,15 +79,27 @@ target_link_libraries(rpcs3_emu
|
||||
3rdparty::pugixml)
|
||||
|
||||
if(MSVC)
|
||||
set_source_files_properties("../../Utilities/JIT.cpp" PROPERTIES COMPILE_FLAGS /GR-)
|
||||
set_source_files_properties("../../Utilities/JIT.cpp" PROPERTIES
|
||||
COMPILE_FLAGS /GR-
|
||||
SKIP_PRECOMPILE_HEADERS ON
|
||||
)
|
||||
else()
|
||||
set_source_files_properties("../../Utilities/JIT.cpp" PROPERTIES COMPILE_FLAGS -fno-rtti)
|
||||
set_source_files_properties("../../Utilities/JIT.cpp" PROPERTIES
|
||||
COMPILE_FLAGS -fno-rtti
|
||||
SKIP_PRECOMPILE_HEADERS ON
|
||||
)
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
set_source_files_properties("../util/yaml.cpp" PROPERTIES COMPILE_FLAGS /EHsc)
|
||||
set_source_files_properties("../util/yaml.cpp" PROPERTIES
|
||||
COMPILE_FLAGS /EHsc
|
||||
SKIP_PRECOMPILE_HEADERS ON
|
||||
)
|
||||
else()
|
||||
set_source_files_properties("../util/yaml.cpp" PROPERTIES COMPILE_FLAGS -fexceptions)
|
||||
set_source_files_properties("../util/yaml.cpp" PROPERTIES
|
||||
COMPILE_FLAGS -fexceptions
|
||||
SKIP_PRECOMPILE_HEADERS ON
|
||||
)
|
||||
endif()
|
||||
|
||||
# Crypto
|
||||
@@ -139,9 +152,13 @@ if(USE_FAUDIO)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
target_include_directories(rpcs3_emu PUBLIC "${RPCS3_SRC_DIR}/../3rdparty/XAudio2Redist/include")
|
||||
target_link_libraries(rpcs3_emu PRIVATE "${RPCS3_SRC_DIR}/../3rdparty/XAudio2Redist/libs/xaudio2_9redist.lib")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /DELAYLOAD:xaudio2_9redist.dll")
|
||||
target_include_directories(rpcs3_emu PUBLIC "${PROJECT_SOURCE_DIR}/3rdparty/XAudio2Redist/include")
|
||||
if(MSVC)
|
||||
target_link_libraries(rpcs3_emu PRIVATE "${PROJECT_SOURCE_DIR}/3rdparty/XAudio2Redist/libs/xaudio2_9redist.lib")
|
||||
target_link_options(rpcs3_emu PRIVATE /DELAYLOAD:xaudio2_9redist.dll)
|
||||
else()
|
||||
target_link_libraries(rpcs3_emu PRIVATE xaudio2_8)
|
||||
endif()
|
||||
target_sources(rpcs3_emu PRIVATE
|
||||
Audio/XAudio2/XAudio2Backend.cpp
|
||||
Audio/XAudio2/xaudio2_enumerator.cpp
|
||||
@@ -366,7 +383,10 @@ target_sources(rpcs3_emu PRIVATE
|
||||
)
|
||||
|
||||
if(NOT MSVC)
|
||||
set_source_files_properties(Cell/PPUTranslator.cpp PROPERTIES COMPILE_FLAGS -fno-rtti)
|
||||
set_source_files_properties(Cell/PPUTranslator.cpp PROPERTIES
|
||||
COMPILE_FLAGS -fno-rtti
|
||||
SKIP_PRECOMPILE_HEADERS ON
|
||||
)
|
||||
endif()
|
||||
|
||||
target_link_libraries(rpcs3_emu
|
||||
@@ -576,23 +596,12 @@ target_link_libraries(rpcs3_emu
|
||||
|
||||
if(APPLE)
|
||||
check_function_exists(clock_gettime HAVE_CLOCK_GETTIME)
|
||||
if (${HAVE_CLOCK_GETTIME})
|
||||
if (HAVE_CLOCK_GETTIME)
|
||||
target_compile_definitions(rpcs3_emu PUBLIC -DHAVE_CLOCK_GETTIME)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
if(USE_PRECOMPILED_HEADERS)
|
||||
if(COMMAND target_precompile_headers)
|
||||
target_precompile_headers(rpcs3_emu PRIVATE "${RPCS3_SRC_DIR}/stdafx.h")
|
||||
else()
|
||||
# Setup cotire
|
||||
option(UNITY_BUILD_EMU "Use unity build for rpcs3_emu target" OFF)
|
||||
|
||||
set_target_properties(rpcs3_emu PROPERTIES
|
||||
COTIRE_CXX_PREFIX_HEADER_INIT "${RPCS3_SRC_DIR}/stdafx.h"
|
||||
COTIRE_ADD_UNITY_BUILD ${UNITY_BUILD_EMU})
|
||||
|
||||
cotire(rpcs3_emu)
|
||||
endif()
|
||||
target_precompile_headers(rpcs3_emu PRIVATE "${PROJECT_SOURCE_DIR}/rpcs3/stdafx.h")
|
||||
endif()
|
||||
|
||||
+34
-10
@@ -682,6 +682,7 @@ static atomic_t<u32> s_dummy_atomic = 0;
|
||||
bool cpu_thread::check_state() noexcept
|
||||
{
|
||||
bool cpu_sleep_called = false;
|
||||
bool cpu_memory_checked = false;
|
||||
bool cpu_can_stop = true;
|
||||
bool escape{}, retval{};
|
||||
|
||||
@@ -770,7 +771,7 @@ bool cpu_thread::check_state() noexcept
|
||||
if (!is_stopped(flags) && flags.none_of(cpu_flag::ret))
|
||||
{
|
||||
// Check pause flags which hold thread inside check_state (ignore suspend/debug flags on cpu_flag::temp)
|
||||
if (flags & (cpu_flag::pause + cpu_flag::memory) || (cpu_can_stop && flags & (cpu_flag::dbg_global_pause + cpu_flag::dbg_pause + cpu_flag::suspend + cpu_flag::yield + cpu_flag::preempt)))
|
||||
if (flags & cpu_flag::pause || (!cpu_memory_checked && flags & cpu_flag::memory) || (cpu_can_stop && flags & (cpu_flag::dbg_global_pause + cpu_flag::dbg_pause + cpu_flag::suspend + cpu_flag::yield + cpu_flag::preempt)))
|
||||
{
|
||||
if (!(flags & cpu_flag::wait))
|
||||
{
|
||||
@@ -789,12 +790,25 @@ bool cpu_thread::check_state() noexcept
|
||||
return store;
|
||||
}
|
||||
|
||||
if (flags & cpu_flag::wait)
|
||||
if (flags & (cpu_flag::wait + cpu_flag::memory))
|
||||
{
|
||||
flags -= cpu_flag::wait;
|
||||
flags -= (cpu_flag::wait + cpu_flag::memory);
|
||||
store = true;
|
||||
}
|
||||
|
||||
if (s_tls_thread_slot == umax)
|
||||
{
|
||||
if (cpu_flag::wait - this->state.load())
|
||||
{
|
||||
// Force wait flag (must be set during ownership of s_cpu_lock), this makes the atomic op fail as a side effect
|
||||
this->state += cpu_flag::wait;
|
||||
store = true;
|
||||
}
|
||||
|
||||
// Restore thread in the suspend list
|
||||
cpu_counter::add(this);
|
||||
}
|
||||
|
||||
retval = false;
|
||||
}
|
||||
else
|
||||
@@ -843,10 +857,12 @@ bool cpu_thread::check_state() noexcept
|
||||
|
||||
if (escape)
|
||||
{
|
||||
if (s_tls_thread_slot == umax && !retval)
|
||||
if (vm::g_range_lock_bits[1] && vm::g_tls_locked && *vm::g_tls_locked == this)
|
||||
{
|
||||
// Restore thread in the suspend list
|
||||
cpu_counter::add(this);
|
||||
state += cpu_flag::wait + cpu_flag::memory;
|
||||
cpu_sleep_called = false;
|
||||
cpu_memory_checked = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cpu_can_stop && state0 & cpu_flag::pending)
|
||||
@@ -859,6 +875,7 @@ bool cpu_thread::check_state() noexcept
|
||||
// Work could have changed flags
|
||||
// Reset internal flags as if check_state() has just been called
|
||||
cpu_sleep_called = false;
|
||||
cpu_memory_checked = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -876,6 +893,7 @@ bool cpu_thread::check_state() noexcept
|
||||
{
|
||||
cpu_sleep();
|
||||
cpu_sleep_called = true;
|
||||
cpu_memory_checked = false;
|
||||
|
||||
if (s_tls_thread_slot != umax)
|
||||
{
|
||||
@@ -900,6 +918,7 @@ bool cpu_thread::check_state() noexcept
|
||||
if (state0 & cpu_flag::memory)
|
||||
{
|
||||
vm::passive_lock(*this);
|
||||
cpu_memory_checked = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -997,7 +1016,7 @@ cpu_thread& cpu_thread::operator=(thread_state)
|
||||
{
|
||||
if (u32 resv = atomic_storage<u32>::load(thread->raddr))
|
||||
{
|
||||
vm::reservation_notifier(resv).notify_one();
|
||||
vm::reservation_notifier(resv).notify_all(-128);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1093,9 +1112,11 @@ std::shared_ptr<CPUDisAsm> make_disasm(const cpu_thread* cpu);
|
||||
|
||||
void cpu_thread::dump_all(std::string& ret) const
|
||||
{
|
||||
std::any func_data;
|
||||
|
||||
ret += dump_misc();
|
||||
ret += '\n';
|
||||
dump_regs(ret);
|
||||
dump_regs(ret, func_data);
|
||||
ret += '\n';
|
||||
ret += dump_callstack();
|
||||
ret += '\n';
|
||||
@@ -1118,7 +1139,7 @@ void cpu_thread::dump_all(std::string& ret) const
|
||||
}
|
||||
}
|
||||
|
||||
void cpu_thread::dump_regs(std::string&) const
|
||||
void cpu_thread::dump_regs(std::string&, std::any&) const
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1312,7 +1333,10 @@ bool cpu_thread::suspend_work::push(cpu_thread* _this) noexcept
|
||||
|
||||
void cpu_thread::cleanup() noexcept
|
||||
{
|
||||
ensure(!s_cpu_counter);
|
||||
if (u64 count = s_cpu_counter)
|
||||
{
|
||||
fmt::throw_exception("cpu_thread::cleanup(): %u threads are still active! (created=%u, destroyed=%u)", count, +g_threads_created, +g_threads_deleted);
|
||||
}
|
||||
|
||||
sys_log.notice("All CPU threads have been stopped. [+: %u]", +g_threads_created);
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "../Utilities/bit_set.h"
|
||||
|
||||
#include <vector>
|
||||
#include <any>
|
||||
|
||||
template <typename Derived, typename Base>
|
||||
concept DerivedFrom = std::is_base_of_v<Base, Derived> &&
|
||||
@@ -159,7 +160,7 @@ public:
|
||||
virtual void dump_all(std::string&) const;
|
||||
|
||||
// Get CPU register dump
|
||||
virtual void dump_regs(std::string&) const;
|
||||
virtual void dump_regs(std::string& ret, std::any& custom_data) const;
|
||||
|
||||
// Get CPU call stack dump
|
||||
virtual std::string dump_callstack() const;
|
||||
|
||||
@@ -70,5 +70,5 @@ void fmt_class_string<spu_mfc_cmd>::format(std::string& out, u64 arg)
|
||||
|
||||
const u8 tag = cmd.tag;
|
||||
|
||||
fmt::append(out, "%s #%02u 0x%05x:0x%08llx 0x%x%s", cmd.cmd, tag & 0x7f, cmd.lsa, u64{cmd.eah} << 32 | cmd.eal, cmd.size, (tag & 0x80) ? " (stalled)" : "");
|
||||
fmt::append(out, "%-8s #%02u 0x%05x:0x%08llx 0x%x%s", cmd.cmd, tag & 0x7f, cmd.lsa, u64{cmd.eah} << 32 | cmd.eal, cmd.size, (tag & 0x80) ? " (stalled)" : "");
|
||||
}
|
||||
|
||||
@@ -202,7 +202,7 @@ error_code cellVideoOutSetupDisplay(u32 videoOut)
|
||||
|
||||
error_code cellAudioInGetDeviceInfo(u32 deviceNumber, u32 deviceIndex, vm::ptr<CellAudioInDeviceInfo> info)
|
||||
{
|
||||
cellAvconfExt.todo("cellAudioInGetDeviceInfo(deviceNumber=0x%x, deviceIndex=0x%x, info=*0x%x)", deviceNumber, deviceIndex, info);
|
||||
cellAvconfExt.trace("cellAudioInGetDeviceInfo(deviceNumber=0x%x, deviceIndex=0x%x, info=*0x%x)", deviceNumber, deviceIndex, info);
|
||||
|
||||
if (deviceIndex != 0 || !info)
|
||||
{
|
||||
@@ -277,7 +277,7 @@ error_code cellVideoOutGetGamma(u32 videoOut, vm::ptr<f32> gamma)
|
||||
|
||||
error_code cellAudioInGetAvailableDeviceInfo(u32 count, vm::ptr<CellAudioInDeviceInfo> device_info)
|
||||
{
|
||||
cellAvconfExt.todo("cellAudioInGetAvailableDeviceInfo(count=%d, info=*0x%x)", count, device_info);
|
||||
cellAvconfExt.trace("cellAudioInGetAvailableDeviceInfo(count=%d, info=*0x%x)", count, device_info);
|
||||
|
||||
if (count > 16 || !device_info)
|
||||
{
|
||||
|
||||
@@ -1891,7 +1891,6 @@ bool camera_context::on_handler_state(camera_handler_base::camera_handler_state
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case camera_handler_base::camera_handler_state::not_available:
|
||||
case camera_handler_base::camera_handler_state::closed:
|
||||
{
|
||||
if (is_attached)
|
||||
|
||||
@@ -335,17 +335,7 @@ public:
|
||||
[[maybe_unused]] const s32 version = GET_OR_USE_SERIALIZATION_VERSION(ar.is_writing(), cellGem);
|
||||
|
||||
ar(attribute, vc_attribute, status_flags, enable_pitch_correction, inertial_counter, controllers
|
||||
, connected_controllers, update_started, camera_frame, memory_ptr);
|
||||
|
||||
if (version == 1 && !ar.is_writing())
|
||||
{
|
||||
u32 ts = ar;
|
||||
start_timestamp_us = ts;
|
||||
}
|
||||
else
|
||||
{
|
||||
ar(start_timestamp_us);
|
||||
}
|
||||
, connected_controllers, update_started, camera_frame, memory_ptr, start_timestamp_us);
|
||||
}
|
||||
|
||||
gem_config_data(utils::serial& ar)
|
||||
|
||||
@@ -7,8 +7,10 @@
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <codecvt>
|
||||
#ifdef _MSC_VER
|
||||
#pragma comment(lib, "Winhttp.lib")
|
||||
#endif
|
||||
#endif
|
||||
|
||||
LOG_CHANNEL(cellHttpUtil);
|
||||
|
||||
@@ -130,7 +132,7 @@ error_code cellHttpUtilParseUri(vm::ptr<CellHttpUri> uri, vm::cptr<char> str, vm
|
||||
parseError = "Error, URI didn't contain a slash";
|
||||
break;
|
||||
default:
|
||||
parseError = "Error, unkown error #" + std::to_string(static_cast<int>(URL.m_ErrorCode));
|
||||
parseError = "Error, unknown error #" + std::to_string(static_cast<int>(URL.m_ErrorCode));
|
||||
break;
|
||||
}
|
||||
cellHttpUtil.error("%s, while parsing URI, %s.", parseError, str.get_ptr());
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#ifdef _WIN32
|
||||
typedef int HostCode;
|
||||
#else
|
||||
#include <iconv.h>
|
||||
@@ -24,7 +24,7 @@ LOG_CHANNEL(cellL10n);
|
||||
// If this makes your compilation fail, try replace the string code with one in "iconv -l"
|
||||
bool _L10nCodeParse(s32 code, HostCode& retCode)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
#ifdef _WIN32
|
||||
retCode = 0;
|
||||
if ((code >= _L10N_CODE_) || (code < 0)) return false;
|
||||
switch (code)
|
||||
@@ -161,7 +161,7 @@ bool _L10nCodeParse(s32 code, HostCode& retCode)
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#ifdef _WIN32
|
||||
|
||||
// Use code page to transform std::string to std::wstring.
|
||||
s32 _OEM2Wide(HostCode oem_code, const std::string& src, std::wstring& dst)
|
||||
@@ -206,7 +206,7 @@ std::string _OemToOem(HostCode src_code, HostCode dst_code, const std::string& s
|
||||
|
||||
#endif
|
||||
|
||||
s32 _ConvertStr(s32 src_code, const void *src, s32 src_len, s32 dst_code, void *dst, s32 *dst_len, bool allowIncomplete)
|
||||
s32 _ConvertStr(s32 src_code, const void *src, s32 src_len, s32 dst_code, void *dst, s32 *dst_len, [[maybe_unused]] bool allowIncomplete)
|
||||
{
|
||||
HostCode srcCode = 0, dstCode = 0; //OEM code pages
|
||||
bool src_page_converted = _L10nCodeParse(src_code, srcCode); //Check if code is in list.
|
||||
@@ -216,13 +216,13 @@ s32 _ConvertStr(s32 src_code, const void *src, s32 src_len, s32 dst_code, void *
|
||||
|| ((!dst_page_converted) && (dstCode == 0)))
|
||||
return ConverterUnknown;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#ifdef _WIN32
|
||||
const std::string wrapped_source = std::string(static_cast<const char *>(src), src_len);
|
||||
const std::string target = _OemToOem(srcCode, dstCode, wrapped_source);
|
||||
|
||||
if (dst != nullptr)
|
||||
{
|
||||
if (target.length() > *dst_len) return DSTExhausted;
|
||||
if (target.length() > static_cast<usz>(*dst_len)) return DSTExhausted;
|
||||
memcpy(dst, target.c_str(), target.length());
|
||||
}
|
||||
*dst_len = ::narrow<s32>(target.size());
|
||||
|
||||
@@ -214,9 +214,9 @@ error_code open_msg_dialog(bool is_blocking, u32 type, vm::cptr<char> msgString,
|
||||
|
||||
dlg->type = _type;
|
||||
|
||||
dlg->on_close = [callback, userData, &return_code, wptr = std::weak_ptr<MsgDialogBase>(dlg)](s32 status)
|
||||
dlg->on_close = [callback, userData, is_blocking, &return_code, wptr = std::weak_ptr<MsgDialogBase>(dlg)](s32 status)
|
||||
{
|
||||
if (return_code)
|
||||
if (is_blocking && return_code)
|
||||
{
|
||||
*return_code = status;
|
||||
}
|
||||
@@ -533,13 +533,15 @@ error_code cellMsgDialogAbort()
|
||||
sysutil_send_system_cmd(CELL_SYSUTIL_DRAWING_END, 0);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
return CELL_OK; // Not CELL_MSGDIALOG_ERROR_DIALOG_NOT_OPENED, tested on HW.
|
||||
}
|
||||
|
||||
const auto dlg = g_fxo->get<msg_info>().get();
|
||||
|
||||
if (!dlg)
|
||||
{
|
||||
return CELL_MSGDIALOG_ERROR_DIALOG_NOT_OPENED;
|
||||
return CELL_OK; // Not CELL_MSGDIALOG_ERROR_DIALOG_NOT_OPENED, tested on HW.
|
||||
}
|
||||
|
||||
if (!dlg->state.compare_and_swap_test(MsgDialogState::Open, MsgDialogState::Abort))
|
||||
|
||||
@@ -155,7 +155,7 @@ error_code select_photo(std::string dst_dir)
|
||||
{
|
||||
fs::stat_t f_info{};
|
||||
|
||||
if (!fs::stat(info.path, f_info) || f_info.is_directory)
|
||||
if (!fs::get_stat(info.path, f_info) || f_info.is_directory)
|
||||
{
|
||||
cellPhotoImportUtil.error("Path does not belong to a valid file: '%s'", info.path);
|
||||
result = CELL_PHOTO_IMPORT_ERROR_ACCESS_ERROR; // TODO: is this correct ?
|
||||
|
||||
@@ -864,7 +864,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
|
||||
if (listSet->fixedListNum > CELL_SAVEDATA_LISTITEM_MAX)
|
||||
{
|
||||
// ****** sysutil savedata parameter error : 38 ******
|
||||
return {CELL_SAVEDATA_ERROR_PARAM, "38"};
|
||||
return {CELL_SAVEDATA_ERROR_PARAM, "38 (fixedListNum=%d)", listSet->fixedListNum};
|
||||
}
|
||||
|
||||
if (listSet->fixedListNum && !listSet->fixedList)
|
||||
@@ -921,7 +921,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
|
||||
default:
|
||||
{
|
||||
// ****** sysutil savedata parameter error : 43 ******
|
||||
return {CELL_SAVEDATA_ERROR_PARAM, "43"};
|
||||
return {CELL_SAVEDATA_ERROR_PARAM, "43 (iconPosition=0x%x)", listSet->newData->iconPosition};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1316,7 +1316,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
|
||||
|
||||
default :
|
||||
// ****** sysutil savedata parameter error : 81 ******
|
||||
return {CELL_SAVEDATA_ERROR_PARAM, "81"};
|
||||
return {CELL_SAVEDATA_ERROR_PARAM, "81 (option=0x%x)", fixedSet->option};
|
||||
}
|
||||
|
||||
if (selected == -1)
|
||||
@@ -1380,6 +1380,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
|
||||
bool recreated = false;
|
||||
|
||||
lv2_sleep(ppu, 250);
|
||||
ppu.state += cpu_flag::wait;
|
||||
|
||||
// Check if RPCS3_BLIST section exist in PARAM.SFO
|
||||
// This section contains the list of files in the save ordered as they would be in BSD filesystem
|
||||
@@ -1397,7 +1398,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
|
||||
}
|
||||
|
||||
fs::stat_t dir_info{};
|
||||
if (!fs::stat(dir_path, dir_info))
|
||||
if (!fs::get_stat(dir_path, dir_info))
|
||||
{
|
||||
// funcStat is called even if the directory doesn't exist.
|
||||
}
|
||||
@@ -1523,6 +1524,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
|
||||
|
||||
// Stat Callback
|
||||
funcStat(ppu, result, statGet, statSet);
|
||||
ppu.state += cpu_flag::wait;
|
||||
|
||||
if (const s32 res = result->result; res != CELL_SAVEDATA_CBRESULT_OK_NEXT)
|
||||
{
|
||||
@@ -1542,7 +1544,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
|
||||
if (statSet->setParam->attribute > CELL_SAVEDATA_ATTR_NODUPLICATE)
|
||||
{
|
||||
// ****** sysutil savedata parameter error : 57 ******
|
||||
return {CELL_SAVEDATA_ERROR_PARAM, "57"};
|
||||
return {CELL_SAVEDATA_ERROR_PARAM, "57 (attribute=0x%x)", statSet->setParam->attribute};
|
||||
}
|
||||
|
||||
if (g_ps3_process_info.sdk_ver > 0x36FFFF)
|
||||
@@ -1551,7 +1553,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
|
||||
if (statSet->setParam->parental_level)
|
||||
{
|
||||
// ****** sysutil savedata parameter error : 58 ******
|
||||
return {CELL_SAVEDATA_ERROR_PARAM, "58"};
|
||||
return {CELL_SAVEDATA_ERROR_PARAM, "58 (sdk_ver=0x%x, parental_level=%d)", g_ps3_process_info.sdk_ver, statSet->setParam->parental_level};
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1559,7 +1561,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
|
||||
if (statSet->setParam->parental_level > 11)
|
||||
{
|
||||
// ****** sysutil savedata parameter error : 58 ******
|
||||
return {CELL_SAVEDATA_ERROR_PARAM, "58"};
|
||||
return {CELL_SAVEDATA_ERROR_PARAM, "58 (sdk_ver=0x%x, parental_level=%d)", g_ps3_process_info.sdk_ver, statSet->setParam->parental_level};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1689,6 +1691,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
|
||||
std::memset(result.get_ptr(), 0, ::offset32(&CellSaveDataCBResult::userdata));
|
||||
|
||||
funcFile(ppu, result, fileGet, fileSet);
|
||||
ppu.state += cpu_flag::wait;
|
||||
|
||||
if (const s32 res = result->result; res != CELL_SAVEDATA_CBRESULT_OK_NEXT)
|
||||
{
|
||||
@@ -2045,7 +2048,7 @@ static NEVER_INLINE error_code savedata_get_list_item(vm::cptr<char> dirName, vm
|
||||
else if (userId > CELL_USERINFO_USER_MAX)
|
||||
{
|
||||
// ****** sysutil savedata parameter error : 137 ******
|
||||
return {CELL_SAVEDATA_ERROR_PARAM, "137"};
|
||||
return {CELL_SAVEDATA_ERROR_PARAM, "137 (userId=0x%x)", userId};
|
||||
}
|
||||
|
||||
if (!dirName)
|
||||
@@ -2099,7 +2102,7 @@ static NEVER_INLINE error_code savedata_get_list_item(vm::cptr<char> dirName, vm
|
||||
if (dir)
|
||||
{
|
||||
fs::stat_t dir_info{};
|
||||
if (!fs::stat(save_path, dir_info))
|
||||
if (!fs::get_stat(save_path, dir_info))
|
||||
{
|
||||
return CELL_SAVEDATA_ERROR_INTERNAL;
|
||||
}
|
||||
@@ -2406,8 +2409,10 @@ error_code cellSaveDataFixedExport(ppu_thread& ppu, vm::cptr<char> dirName, u32
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSaveDataGetListItem(vm::cptr<char> dirName, vm::ptr<CellSaveDataDirStat> dir, vm::ptr<CellSaveDataSystemFileParam> sysFileParam, vm::ptr<u32> bind, vm::ptr<u32> sizeKB)
|
||||
error_code cellSaveDataGetListItem(ppu_thread& ppu, vm::cptr<char> dirName, vm::ptr<CellSaveDataDirStat> dir, vm::ptr<CellSaveDataSystemFileParam> sysFileParam, vm::ptr<u32> bind, vm::ptr<u32> sizeKB)
|
||||
{
|
||||
ppu.state += cpu_flag::wait;
|
||||
|
||||
cellSaveData.warning("cellSaveDataGetListItem(dirName=%s, dir=*0x%x, sysFileParam=*0x%x, bind=*0x%x, sizeKB=*0x%x)", dirName, dir, sysFileParam, bind, sizeKB);
|
||||
|
||||
return savedata_get_list_item(dirName, dir, sysFileParam, bind, sizeKB, 0);
|
||||
|
||||
@@ -3091,7 +3091,8 @@ s32 _cellSpursWorkloadFlagReceiver(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, u3
|
||||
u8 FlagReceiver; // 0x77
|
||||
};
|
||||
|
||||
s32 res;
|
||||
s32 res = CELL_OK;
|
||||
|
||||
vm::reservation_op(ppu, vm::unsafe_ptr_cast<wklFlagOp>(spurs), [&](wklFlagOp& val)
|
||||
{
|
||||
if (is_set)
|
||||
@@ -3129,17 +3130,83 @@ s32 _cellSpursWorkloadFlagReceiver(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, u3
|
||||
}
|
||||
|
||||
res = CELL_OK;
|
||||
return;
|
||||
});
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/// Set/unset the recipient of the workload flag
|
||||
s32 _cellSpursWorkloadFlagReceiver2()
|
||||
s32 _cellSpursWorkloadFlagReceiver2(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, u32 wid, u32 is_set, u32 print_debug_output)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSpurs);
|
||||
return CELL_OK;
|
||||
cellSpurs.warning("_cellSpursWorkloadFlagReceiver2(spurs=*0x%x, wid=%d, is_set=%d, print_debug_output=%d)", spurs, wid, is_set, print_debug_output);
|
||||
|
||||
if (!spurs)
|
||||
{
|
||||
return CELL_SPURS_POLICY_MODULE_ERROR_NULL_POINTER;
|
||||
}
|
||||
|
||||
if (!spurs.aligned())
|
||||
{
|
||||
return CELL_SPURS_POLICY_MODULE_ERROR_ALIGN;
|
||||
}
|
||||
|
||||
if (wid >= spurs->max_workloads())
|
||||
{
|
||||
return CELL_SPURS_POLICY_MODULE_ERROR_INVAL;
|
||||
}
|
||||
|
||||
if ((spurs->wklEnabled.load() & (0x80000000u >> wid)) == 0u)
|
||||
{
|
||||
return CELL_SPURS_POLICY_MODULE_ERROR_SRCH;
|
||||
}
|
||||
|
||||
if (spurs->exception)
|
||||
{
|
||||
return CELL_SPURS_POLICY_MODULE_ERROR_STAT;
|
||||
}
|
||||
|
||||
atomic_fence_acq_rel();
|
||||
|
||||
s32 res = CELL_OK;
|
||||
|
||||
vm::atomic_op<true>(spurs->wklFlagReceiver, [&](u8& FlagReceiver)
|
||||
{
|
||||
if (is_set)
|
||||
{
|
||||
if (FlagReceiver != 0xff)
|
||||
{
|
||||
res = CELL_SPURS_POLICY_MODULE_ERROR_BUSY;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (FlagReceiver != wid)
|
||||
{
|
||||
res = CELL_SPURS_POLICY_MODULE_ERROR_PERM;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_set)
|
||||
{
|
||||
if (FlagReceiver == 0xff)
|
||||
{
|
||||
FlagReceiver = static_cast<u8>(wid);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (FlagReceiver == wid)
|
||||
{
|
||||
FlagReceiver = 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
res = CELL_OK;
|
||||
});
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/// Request assignment of idle SPUs
|
||||
@@ -3961,19 +4028,46 @@ s32 cellSpursGetTasksetId(vm::ptr<CellSpursTaskset> taskset, vm::ptr<u32> wid)
|
||||
return CELL_SPURS_TASK_ERROR_ALIGN;
|
||||
}
|
||||
|
||||
if (taskset->wid >= CELL_SPURS_MAX_WORKLOAD)
|
||||
{
|
||||
return CELL_SPURS_TASK_ERROR_INVAL;
|
||||
}
|
||||
|
||||
// Does not check its validity
|
||||
*wid = taskset->wid;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellSpursShutdownTaskset(vm::ptr<CellSpursTaskset> taskset)
|
||||
s32 cellSpursShutdownTaskset(ppu_thread& ppu, vm::ptr<CellSpursTaskset> taskset)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSpurs);
|
||||
return CELL_OK;
|
||||
cellSpurs.warning("cellSpursShutdownTaskset(taskset=*0x%x)", taskset);
|
||||
|
||||
if (!taskset)
|
||||
{
|
||||
return CELL_SPURS_TASK_ERROR_NULL_POINTER;
|
||||
}
|
||||
|
||||
if (!taskset.aligned())
|
||||
{
|
||||
return CELL_SPURS_TASK_ERROR_ALIGN;
|
||||
}
|
||||
|
||||
const u32 wid = taskset->wid;
|
||||
|
||||
if (wid >= CELL_SPURS_MAX_WORKLOAD)
|
||||
{
|
||||
return CELL_SPURS_TASK_ERROR_INVAL;
|
||||
}
|
||||
|
||||
const auto spurs = +taskset->spurs;
|
||||
u32 shutdown_error = ppu_execute<&cellSpursShutdownWorkload>(ppu, spurs, wid);
|
||||
|
||||
if (shutdown_error == CELL_SPURS_POLICY_MODULE_ERROR_STAT)
|
||||
{
|
||||
shutdown_error = CELL_SPURS_TASK_ERROR_STAT;
|
||||
}
|
||||
else if (shutdown_error == CELL_SPURS_POLICY_MODULE_ERROR_ALIGN || shutdown_error == CELL_SPURS_POLICY_MODULE_ERROR_SRCH)
|
||||
{
|
||||
// printf is used on fw in this case
|
||||
cellSpurs.error("cellSpursShutdownTaskset(taskset=*0x%x): Failed with %s (spurs=0x%x, wid=%d)", CellError{ shutdown_error }, spurs, wid);
|
||||
}
|
||||
|
||||
return shutdown_error;
|
||||
}
|
||||
|
||||
s32 _spurs::create_task(vm::ptr<CellSpursTaskset> taskset, vm::ptr<u32> task_id, vm::cptr<void> elf, vm::cptr<void> context, u32 size, vm::ptr<CellSpursTaskLsPattern> ls_pattern, vm::ptr<CellSpursTaskArgument> arg)
|
||||
|
||||
@@ -139,18 +139,19 @@ error_code cellSysCacheMount(vm::ptr<CellSysCacheParam> param)
|
||||
{
|
||||
});
|
||||
|
||||
std::lock_guard lock0(g_mp_sys_dev_hdd1.mutex);
|
||||
|
||||
// Check if can reuse existing cache (won't if cache id is an empty string)
|
||||
if (param->cacheId[0] && cache_id == cache.cache_id)
|
||||
{
|
||||
// Isn't mounted yet on first call to cellSysCacheMount
|
||||
vfs::mount("/dev_hdd1", new_path);
|
||||
if (vfs::mount("/dev_hdd1", new_path))
|
||||
g_fxo->get<lv2_fs_mount_info_map>().add("/dev_hdd1", &g_mp_sys_dev_hdd1);
|
||||
|
||||
cellSysutil.success("Mounted existing cache at %s", new_path);
|
||||
return not_an_error(CELL_SYSCACHE_RET_OK_RELAYED);
|
||||
}
|
||||
|
||||
std::lock_guard lock0(g_mp_sys_dev_hdd1.mutex);
|
||||
|
||||
// Clear existing cache
|
||||
if (!cache.cache_id.empty())
|
||||
{
|
||||
@@ -160,7 +161,8 @@ error_code cellSysCacheMount(vm::ptr<CellSysCacheParam> param)
|
||||
// Set new cache id
|
||||
cache.cache_id = std::move(cache_id);
|
||||
fs::create_dir(new_path);
|
||||
vfs::mount("/dev_hdd1", new_path);
|
||||
if (vfs::mount("/dev_hdd1", new_path))
|
||||
g_fxo->get<lv2_fs_mount_info_map>().add("/dev_hdd1", &g_mp_sys_dev_hdd1);
|
||||
|
||||
return not_an_error(CELL_SYSCACHE_RET_OK_CLEARED);
|
||||
}
|
||||
|
||||
@@ -468,7 +468,7 @@ error_code npDrmIsAvailable(vm::cptr<u8> k_licensee_addr, vm::cptr<char> drm_pat
|
||||
if (k_licensee_addr)
|
||||
{
|
||||
std::memcpy(&k_licensee, k_licensee_addr.get_ptr(), sizeof(k_licensee));
|
||||
sceNp.notice("npDrmIsAvailable(): KLicense key %s", std::bit_cast<be_t<u128>>(k_licensee));
|
||||
sceNp.notice("npDrmIsAvailable(): KLicense key or KLIC=%s", std::bit_cast<be_t<u128>>(k_licensee));
|
||||
}
|
||||
|
||||
if (Emu.GetFakeCat() == "PE")
|
||||
|
||||
@@ -244,6 +244,15 @@ void fmt_class_string<SceNpCommunicationSignature>::format(std::string& out, u64
|
||||
fmt::append(out, "%s", sign.data);
|
||||
}
|
||||
|
||||
template <>
|
||||
void fmt_class_string<SceNpCommunicationId>::format(std::string& out, u64 arg)
|
||||
{
|
||||
const auto& id = get_object(arg);
|
||||
|
||||
const u8 term = id.data[9];
|
||||
fmt::append(out, "{ data='%s', term='%s' (0x%x), num=%d, dummy=%d }", id.data, std::isprint(term) ? fmt::format("%c", term) : "", term, id.num, id.dummy);
|
||||
}
|
||||
|
||||
// Helpers
|
||||
|
||||
static error_code NpTrophyGetTrophyInfo(const trophy_context_t* ctxt, s32 trophyId, SceNpTrophyDetails* details, SceNpTrophyData* data);
|
||||
@@ -442,27 +451,48 @@ error_code sceNpTrophyCreateContext(vm::ptr<u32> context, vm::cptr<SceNpCommunic
|
||||
return SCE_NP_TROPHY_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
sceNpTrophy.warning("sceNpTrophyCreateContext(): commId = %s", *commId);
|
||||
|
||||
// rough checks for further fmt::format call
|
||||
if (commId->num > 99)
|
||||
const s32 comm_num = commId->num;
|
||||
if (comm_num > 99)
|
||||
{
|
||||
return SCE_NP_TROPHY_ERROR_INVALID_NP_COMM_ID;
|
||||
}
|
||||
|
||||
// NOTE: commId->term is unused in our code (at least until someone finds out if we need to account for it)
|
||||
|
||||
// generate trophy context name, limited to 9 characters
|
||||
std::string_view name_sv(commId->data, 9);
|
||||
// Generate trophy context name, limited to 9 characters
|
||||
// Read once for thread-safety reasons
|
||||
std::string name_str(commId->data, 9);
|
||||
|
||||
// resize the name if it was shorter than expected
|
||||
if (const auto pos = name_sv.find_first_of('\0'); pos != std::string_view::npos)
|
||||
if (const auto pos = name_str.find_first_of('\0'); pos != std::string_view::npos)
|
||||
{
|
||||
name_sv = name_sv.substr(0, pos);
|
||||
name_str = name_str.substr(0, pos);
|
||||
}
|
||||
|
||||
sceNpTrophy.warning("sceNpTrophyCreateContext(): data='%s' term=0x%x (0x%x) num=%d", name_sv, commId->data[9], commId->data[9], commId->num);
|
||||
const SceNpCommunicationSignature commSign_data = *commSign;
|
||||
|
||||
if (read_from_ptr<be_t<u32>>(commSign_data.data, 0) != NP_TROPHY_COMM_SIGN_MAGIC)
|
||||
{
|
||||
return SCE_NP_TROPHY_ERROR_INVALID_NP_COMM_ID;
|
||||
}
|
||||
|
||||
if (std::basic_string_view<u8>(&commSign_data.data[6], 6).find_first_not_of('\0') != umax)
|
||||
{
|
||||
// 6 padding bytes - must be 0
|
||||
return SCE_NP_TROPHY_ERROR_INVALID_NP_COMM_ID;
|
||||
}
|
||||
|
||||
if (read_from_ptr<be_t<u16>>(commSign_data.data, 4) != 0x100)
|
||||
{
|
||||
// Signifies version (1.00), although only one constant is allowed
|
||||
return SCE_NP_TROPHY_ERROR_INVALID_NP_COMM_ID;
|
||||
}
|
||||
|
||||
// append the commId number as "_xx"
|
||||
std::string name = fmt::format("%s_%02d", name_sv, commId->num);
|
||||
std::string name = fmt::format("%s_%02d", name_str, comm_num);
|
||||
|
||||
// create trophy context
|
||||
const auto ctxt = idm::make_ptr<trophy_context_t>();
|
||||
@@ -546,12 +576,28 @@ error_code sceNpTrophyRegisterContext(ppu_thread& ppu, u32 context, u32 handle,
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: Callbacks
|
||||
// From RE-ing a game's state machine, it seems the possible order is one of the following:
|
||||
// * Install (Not installed) - Setup - Progress * ? - Finalize - Complete - Installed
|
||||
// * Reinstall (Corrupted) - Setup - Progress * ? - Finalize - Complete - Installed
|
||||
// * Update (Required update) - Setup - Progress * ? - Finalize - Complete - Installed
|
||||
// * Installed
|
||||
// open trophy pack file
|
||||
std::string trp_path = vfs::get(Emu.GetDir() + "TROPDIR/" + ctxt->trp_name + "/TROPHY.TRP");
|
||||
fs::file stream(trp_path);
|
||||
|
||||
if (!stream && Emu.GetCat() == "GD")
|
||||
{
|
||||
sceNpTrophy.warning("sceNpTrophyRegisterContext failed to open trophy file from boot path: '%s' (%s)", trp_path, fs::g_tls_error);
|
||||
trp_path = vfs::get("/dev_bdvd/PS3_GAME/TROPDIR/" + ctxt->trp_name + "/TROPHY.TRP");
|
||||
stream.open(trp_path);
|
||||
}
|
||||
|
||||
// check if exists and opened
|
||||
if (!stream)
|
||||
{
|
||||
const std::string msg = fmt::format("Failed to open trophy file: '%s' (%s)", trp_path, fs::g_tls_error);
|
||||
return {SCE_NP_TROPHY_ERROR_CONF_DOES_NOT_EXIST, msg};
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// SCE_NP_TROPHY_STATUS_DATA_CORRUPT -> reinstall
|
||||
// SCE_NP_TROPHY_STATUS_REQUIRES_UPDATE -> reinstall (for example if a patch has updates for the trophy data)
|
||||
// SCE_NP_TROPHY_STATUS_CHANGES_DETECTED -> reinstall (only possible in dev mode)
|
||||
|
||||
const std::string trophyPath = "/dev_hdd0/home/" + Emu.GetUsr() + "/trophy/" + ctxt->trp_name;
|
||||
const s32 trp_status = fs::is_dir(vfs::get(trophyPath)) ? SCE_NP_TROPHY_STATUS_INSTALLED : SCE_NP_TROPHY_STATUS_NOT_INSTALLED;
|
||||
@@ -560,6 +606,7 @@ error_code sceNpTrophyRegisterContext(ppu_thread& ppu, u32 context, u32 handle,
|
||||
|
||||
sceNpTrophy.notice("sceNpTrophyRegisterContext(): Callback is being called (trp_status=%u)", trp_status);
|
||||
|
||||
// "Ask permission" to install the trophy data.
|
||||
// The callback is called once and then if it returns >= 0 the cb is called through events(coming from vsh) that are passed to the CB through cellSysutilCheckCallback
|
||||
if (statusCb(ppu, context, trp_status, 0, 0, arg) < 0)
|
||||
{
|
||||
@@ -599,24 +646,6 @@ error_code sceNpTrophyRegisterContext(ppu_thread& ppu, u32 context, u32 handle,
|
||||
return SCE_NP_TROPHY_ERROR_UNKNOWN_HANDLE;
|
||||
}
|
||||
|
||||
// open trophy pack file
|
||||
std::string trp_path = vfs::get(Emu.GetDir() + "TROPDIR/" + ctxt->trp_name + "/TROPHY.TRP");
|
||||
fs::file stream(trp_path);
|
||||
|
||||
if (!stream && Emu.GetCat() == "GD")
|
||||
{
|
||||
sceNpTrophy.warning("sceNpTrophyRegisterContext failed to open trophy file from boot path: '%s' (%s)", trp_path, fs::g_tls_error);
|
||||
trp_path = vfs::get("/dev_bdvd/PS3_GAME/TROPDIR/" + ctxt->trp_name + "/TROPHY.TRP");
|
||||
stream.open(trp_path);
|
||||
}
|
||||
|
||||
// check if exists and opened
|
||||
if (!stream)
|
||||
{
|
||||
const std::string msg = fmt::format("Failed to open trophy file: '%s' (%s)", trp_path, fs::g_tls_error);
|
||||
return {SCE_NP_TROPHY_ERROR_CONF_DOES_NOT_EXIST, msg};
|
||||
}
|
||||
|
||||
TRPLoader trp(stream);
|
||||
if (!trp.LoadHeader())
|
||||
{
|
||||
@@ -696,6 +725,7 @@ error_code sceNpTrophyRegisterContext(ppu_thread& ppu, u32 context, u32 handle,
|
||||
{
|
||||
sysutil_register_cb([statusCb, status, context, completed, arg, wkptr](ppu_thread& cb_ppu) -> s32
|
||||
{
|
||||
// TODO: it is possible that we need to check the return value here as well.
|
||||
statusCb(cb_ppu, context, status.first, completed, status.second, arg);
|
||||
|
||||
const auto queued = wkptr.lock();
|
||||
|
||||
@@ -151,6 +151,11 @@ enum
|
||||
SCE_NP_TROPHY_STATUS_CHANGES_DETECTED = 9,
|
||||
};
|
||||
|
||||
enum : u32
|
||||
{
|
||||
NP_TROPHY_COMM_SIGN_MAGIC = 0xB9DDE13B,
|
||||
};
|
||||
|
||||
using SceNpTrophyStatusCallback = s32(u32 context, u32 status, s32 completed, s32 total, vm::ptr<void> arg);
|
||||
|
||||
// Forward declare this function since trophyunlock needs it
|
||||
|
||||
+117
-83
@@ -78,7 +78,7 @@ void ppu_module::validate(u32 reloc)
|
||||
|
||||
if (size && size != funcs[index].size)
|
||||
{
|
||||
if (size + 4 != funcs[index].size || vm::read32(addr + size) != ppu_instructions::NOP())
|
||||
if (size + 4 != funcs[index].size || get_ref<u32>(addr + size) != ppu_instructions::NOP())
|
||||
{
|
||||
ppu_validator.error("%s.yml : function size mismatch at 0x%x(size=0x%x) (0x%x, 0x%x)", path, found, funcs[index].size, addr, size);
|
||||
}
|
||||
@@ -112,9 +112,9 @@ void ppu_module::validate(u32 reloc)
|
||||
}
|
||||
}
|
||||
|
||||
static u32 ppu_test(const vm::cptr<u32> ptr, vm::cptr<void> fend, ppu_pattern_array pat)
|
||||
static u32 ppu_test(const be_t<u32>* ptr, const void* fend, ppu_pattern_array pat)
|
||||
{
|
||||
vm::cptr<u32> cur = ptr;
|
||||
const be_t<u32>* cur = ptr;
|
||||
|
||||
for (auto& p : pat)
|
||||
{
|
||||
@@ -141,10 +141,10 @@ static u32 ppu_test(const vm::cptr<u32> ptr, vm::cptr<void> fend, ppu_pattern_ar
|
||||
cur++;
|
||||
}
|
||||
|
||||
return cur.addr() - ptr.addr();
|
||||
return (cur - ptr) * sizeof(*ptr);
|
||||
}
|
||||
|
||||
static u32 ppu_test(vm::cptr<u32> ptr, vm::cptr<void> fend, ppu_pattern_matrix pats)
|
||||
static u32 ppu_test(const be_t<u32>* ptr, const void* fend, ppu_pattern_matrix pats)
|
||||
{
|
||||
for (auto pat : pats)
|
||||
{
|
||||
@@ -585,6 +585,14 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
|
||||
return func;
|
||||
};
|
||||
|
||||
static const auto advance = [](auto& _ptr, auto& ptr, u32 count)
|
||||
{
|
||||
const auto old_ptr = ptr;
|
||||
_ptr += count;
|
||||
ptr += count;
|
||||
return old_ptr;
|
||||
};
|
||||
|
||||
// Register new TOC and find basic set of functions
|
||||
auto add_toc = [&](u32 toc)
|
||||
{
|
||||
@@ -596,16 +604,24 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
|
||||
// Grope for OPD section (TODO: optimization, better constraints)
|
||||
for (const auto& seg : segs)
|
||||
{
|
||||
if (!seg.addr) continue;
|
||||
if (seg.size < 8) continue;
|
||||
|
||||
for (vm::cptr<u32> ptr = vm::cast(seg.addr); ptr.addr() < seg.addr + seg.size; ptr++)
|
||||
const vm::cptr<void> seg_end = vm::cast(seg.addr + seg.size - 8);
|
||||
vm::cptr<u32> _ptr = vm::cast(seg.addr);
|
||||
auto ptr = get_ptr<u32>(_ptr);
|
||||
|
||||
for (; _ptr <= seg_end;)
|
||||
{
|
||||
if (ptr[0] >= start && ptr[0] < end && ptr[0] % 4 == 0 && ptr[1] == toc)
|
||||
if (ptr[1] == toc && ptr[0] >= start && ptr[0] < end && ptr[0] % 4 == 0)
|
||||
{
|
||||
// New function
|
||||
ppu_log.trace("OPD*: [0x%x] 0x%x (TOC=0x%x)", ptr, ptr[0], ptr[1]);
|
||||
add_func(*ptr, addr_heap.count(ptr.addr()) ? toc : 0, 0);
|
||||
ptr++;
|
||||
ppu_log.trace("OPD*: [0x%x] 0x%x (TOC=0x%x)", _ptr, ptr[0], ptr[1]);
|
||||
add_func(*ptr, addr_heap.count(_ptr.addr()) ? toc : 0, 0);
|
||||
advance(_ptr, ptr, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
advance(_ptr, ptr, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -621,9 +637,13 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
|
||||
// Find references indiscriminately
|
||||
for (const auto& seg : segs)
|
||||
{
|
||||
if (!seg.addr) continue;
|
||||
if (seg.size < 4) continue;
|
||||
|
||||
for (vm::cptr<u32> ptr = vm::cast(seg.addr); ptr.addr() < seg.addr + seg.size; ptr++)
|
||||
vm::cptr<u32> _ptr = vm::cast(seg.addr);
|
||||
const vm::cptr<void> seg_end = vm::cast(seg.addr + seg.size - 4);
|
||||
auto ptr = get_ptr<u32>(_ptr);
|
||||
|
||||
for (vm::cptr<u32> _ptr = vm::cast(seg.addr); _ptr <= seg_end; advance(_ptr, ptr, 1))
|
||||
{
|
||||
const u32 value = *ptr;
|
||||
|
||||
@@ -651,15 +671,17 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
|
||||
vm::cptr<void> sec_end = vm::cast(sec.addr + sec.size);
|
||||
|
||||
// Probe
|
||||
for (vm::cptr<u32> ptr = vm::cast(sec.addr); ptr < sec_end; ptr += 2)
|
||||
for (vm::cptr<u32> _ptr = vm::cast(sec.addr); _ptr < sec_end; _ptr += 2)
|
||||
{
|
||||
if (ptr + 6 <= sec_end && !ptr[0] && !ptr[2] && ptr[1] == ptr[4] && ptr[3] == ptr[5])
|
||||
auto ptr = get_ptr<u32>(_ptr);
|
||||
|
||||
if (_ptr + 6 <= sec_end && !ptr[0] && !ptr[2] && ptr[1] == ptr[4] && ptr[3] == ptr[5])
|
||||
{
|
||||
// Special OPD format case (some homebrews)
|
||||
ptr += 4;
|
||||
advance(_ptr, ptr, 4);
|
||||
}
|
||||
|
||||
if (ptr + 2 > sec_end)
|
||||
if (_ptr + 2 > sec_end)
|
||||
{
|
||||
sec_end.set(0);
|
||||
break;
|
||||
@@ -673,7 +695,7 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
|
||||
//const u32 _toc_end = _toc + 0x8000;
|
||||
|
||||
// TODO: improve TOC constraints
|
||||
if (_toc % 4 || !vm::check_addr(_toc) || _toc >= 0x40000000 || (_toc >= start && _toc < end))
|
||||
if (_toc % 4 || !get_ptr<u32>(_toc) || _toc >= 0x40000000 || (_toc >= start && _toc < end))
|
||||
{
|
||||
sec_end.set(0);
|
||||
break;
|
||||
@@ -689,18 +711,20 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
|
||||
if (sec_end) ppu_log.notice("Reading OPD section at 0x%x...", sec.addr);
|
||||
|
||||
// Mine
|
||||
for (vm::cptr<u32> ptr = vm::cast(sec.addr); ptr < sec_end; ptr += 2)
|
||||
for (vm::cptr<u32> _ptr = vm::cast(sec.addr); _ptr < sec_end; _ptr += 2)
|
||||
{
|
||||
auto ptr = get_ptr<u32>(_ptr);
|
||||
|
||||
// Special case: see "Probe"
|
||||
if (!ptr[0]) ptr += 4;
|
||||
if (!ptr[0]) advance(_ptr, ptr, 4);
|
||||
|
||||
// Add function and TOC
|
||||
const u32 addr = ptr[0];
|
||||
const u32 toc = ptr[1];
|
||||
ppu_log.trace("OPD: [0x%x] 0x%x (TOC=0x%x)", ptr, addr, toc);
|
||||
ppu_log.trace("OPD: [0x%x] 0x%x (TOC=0x%x)", _ptr, addr, toc);
|
||||
|
||||
TOCs.emplace(toc);
|
||||
auto& func = add_func(addr, addr_heap.count(ptr.addr()) ? toc : 0, 0);
|
||||
auto& func = add_func(addr, addr_heap.count(_ptr.addr()) ? toc : 0, 0);
|
||||
func.attr += ppu_attr::known_addr;
|
||||
known_functions.emplace(addr);
|
||||
}
|
||||
@@ -709,7 +733,7 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
|
||||
// Register TOC from entry point
|
||||
if (entry && !lib_toc)
|
||||
{
|
||||
lib_toc = vm::read32(entry) ? vm::read32(entry + 4) : vm::read32(entry + 20);
|
||||
lib_toc = get_ref<u32>(entry) ? get_ref<u32>(entry + 4) : get_ref<u32>(entry + 20);
|
||||
}
|
||||
|
||||
// Secondary attempt
|
||||
@@ -733,23 +757,25 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
|
||||
vm::cptr<void> sec_end = vm::cast(sec.addr + sec.size);
|
||||
|
||||
// Probe
|
||||
for (vm::cptr<u32> ptr = vm::cast(sec.addr); ptr < sec_end;)
|
||||
for (vm::cptr<u32> _ptr = vm::cast(sec.addr); _ptr < sec_end;)
|
||||
{
|
||||
if (!ptr.aligned() || ptr.addr() < sec.addr || ptr >= sec_end)
|
||||
if (!_ptr.aligned() || _ptr.addr() < sec.addr || _ptr >= sec_end)
|
||||
{
|
||||
sec_end.set(0);
|
||||
break;
|
||||
}
|
||||
|
||||
const auto ptr = get_ptr<u32>(_ptr);
|
||||
|
||||
const u32 size = ptr[0] + 4;
|
||||
|
||||
if (size == 4 && ptr + 1 == sec_end)
|
||||
if (size == 4 && _ptr + 1 == sec_end)
|
||||
{
|
||||
// Null terminator
|
||||
break;
|
||||
}
|
||||
|
||||
if (size % 4 || size < 0x10 || ptr + size / 4 > sec_end)
|
||||
if (size % 4 || size < 0x10 || _ptr + size / 4 > sec_end)
|
||||
{
|
||||
sec_end.set(0);
|
||||
break;
|
||||
@@ -757,7 +783,7 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
|
||||
|
||||
if (ptr[1])
|
||||
{
|
||||
const u32 cie_off = ptr.addr() - ptr[1] + 4;
|
||||
const u32 cie_off = _ptr.addr() - ptr[1] + 4;
|
||||
|
||||
if (cie_off % 4 || cie_off < sec.addr || cie_off >= sec_end.addr())
|
||||
{
|
||||
@@ -766,14 +792,16 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
|
||||
}
|
||||
}
|
||||
|
||||
ptr = vm::cast(ptr.addr() + size);
|
||||
_ptr = vm::cast(_ptr.addr() + size);
|
||||
}
|
||||
|
||||
if (sec_end && sec.size > 4) ppu_log.notice("Reading .eh_frame section at 0x%x...", sec.addr);
|
||||
|
||||
// Mine
|
||||
for (vm::cptr<u32> ptr = vm::cast(sec.addr); ptr < sec_end; ptr = vm::cast(ptr.addr() + ptr[0] + 4))
|
||||
for (vm::cptr<u32> _ptr = vm::cast(sec.addr); _ptr < sec_end; _ptr = vm::cast(_ptr.addr() + *get_ptr<u32>(_ptr) + 4))
|
||||
{
|
||||
const auto ptr = get_ptr<u32>(_ptr);
|
||||
|
||||
if (ptr[0] == 0u)
|
||||
{
|
||||
// Null terminator
|
||||
@@ -788,7 +816,7 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
|
||||
else
|
||||
{
|
||||
// Get associated CIE (currently unused)
|
||||
const vm::cptr<u32> cie = vm::cast(ptr.addr() - ptr[1] + 4);
|
||||
const vm::cptr<u32> cie = vm::cast(_ptr.addr() - ptr[1] + 4);
|
||||
|
||||
u32 addr = 0;
|
||||
u32 size = 0;
|
||||
@@ -817,7 +845,7 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
|
||||
// TODO: absolute/relative offset (approximation)
|
||||
if (addr > 0xc0000000)
|
||||
{
|
||||
addr += ptr.addr() + 8;
|
||||
addr += _ptr.addr() + 8;
|
||||
}
|
||||
|
||||
ppu_log.trace(".eh_frame: [0x%x] FDE 0x%x (cie=*0x%x, addr=0x%x, size=0x%x)", ptr, ptr[0], cie, addr, size);
|
||||
@@ -875,15 +903,16 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
|
||||
if (func.blocks.empty())
|
||||
{
|
||||
// Special function analysis
|
||||
const vm::cptr<u32> ptr = vm::cast(func.addr);
|
||||
const vm::cptr<u32> _ptr = vm::cast(func.addr);
|
||||
const vm::cptr<void> fend = vm::cast(end);
|
||||
const auto ptr = get_ptr<u32>(_ptr);
|
||||
|
||||
using namespace ppu_instructions;
|
||||
|
||||
if (ptr + 1 <= fend && (ptr[0] & 0xfc000001) == B({}, {}))
|
||||
if (_ptr + 1 <= fend && (ptr[0] & 0xfc000001) == B({}, {}))
|
||||
{
|
||||
// Simple trampoline
|
||||
const u32 target = (ptr[0] & 0x2 ? 0 : ptr.addr()) + ppu_opcode_t{ptr[0]}.bt24;
|
||||
const u32 target = (ptr[0] & 0x2 ? 0 : _ptr.addr()) + ppu_opcode_t{ptr[0]}.bt24;
|
||||
|
||||
if (target == func.addr)
|
||||
{
|
||||
@@ -913,7 +942,7 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
|
||||
}
|
||||
}
|
||||
|
||||
if (ptr + 0x4 <= fend &&
|
||||
if (_ptr + 0x4 <= fend &&
|
||||
(ptr[0] & 0xffff0000) == LIS(r11, 0) &&
|
||||
(ptr[1] & 0xffff0000) == ADDI(r11, r11, 0) &&
|
||||
ptr[2] == MTCTR(r11) &&
|
||||
@@ -941,7 +970,7 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
|
||||
}
|
||||
}
|
||||
|
||||
if (ptr + 0x7 <= fend &&
|
||||
if (_ptr + 0x7 <= fend &&
|
||||
ptr[0] == STD(r2, r1, 0x28) &&
|
||||
(ptr[1] & 0xffff0000) == ADDIS(r12, r2, {}) &&
|
||||
(ptr[2] & 0xffff0000) == LWZ(r11, r12, {}) &&
|
||||
@@ -957,9 +986,10 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
|
||||
func.attr += ppu_attr::known_size;
|
||||
|
||||
// Look for another imports to fill gaps (hack)
|
||||
auto p2 = ptr + 7;
|
||||
auto _p2 = _ptr + 7;
|
||||
auto p2 = get_ptr<u32>(_p2);
|
||||
|
||||
while (p2 + 0x7 <= fend &&
|
||||
while (_p2 + 0x7 <= fend &&
|
||||
p2[0] == STD(r2, r1, 0x28) &&
|
||||
(p2[1] & 0xffff0000) == ADDIS(r12, r2, {}) &&
|
||||
(p2[2] & 0xffff0000) == LWZ(r11, r12, {}) &&
|
||||
@@ -968,18 +998,18 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
|
||||
p2[5] == MTCTR(r11) &&
|
||||
p2[6] == BCTR())
|
||||
{
|
||||
auto& next = add_func(p2.addr(), -1, func.addr);
|
||||
auto& next = add_func(_p2.addr(), -1, func.addr);
|
||||
next.size = 0x1C;
|
||||
next.blocks.emplace(next.addr, next.size);
|
||||
next.attr += ppu_attr::known_addr;
|
||||
next.attr += ppu_attr::known_size;
|
||||
p2 += 7;
|
||||
advance(_p2, p2, 7);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ptr + 0x7 <= fend &&
|
||||
if (_ptr + 0x7 <= fend &&
|
||||
ptr[0] == STD(r2, r1, 0x28) &&
|
||||
(ptr[1] & 0xffff0000) == ADDIS(r2, r2, {}) &&
|
||||
(ptr[2] & 0xffff0000) == ADDI(r2, r2, {}) &&
|
||||
@@ -1008,11 +1038,11 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
|
||||
add_toc(toc);
|
||||
add_func(func.addr, toc, 0);
|
||||
}
|
||||
else if (new_func.toc - func.toc != toc_add)
|
||||
{
|
||||
//func.toc = -1;
|
||||
//new_func.toc = -1;
|
||||
}
|
||||
//else if (new_func.toc - func.toc != toc_add)
|
||||
//{
|
||||
// func.toc = -1;
|
||||
// new_func.toc = -1;
|
||||
//}
|
||||
|
||||
if (new_func.blocks.empty())
|
||||
{
|
||||
@@ -1029,7 +1059,7 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
|
||||
}
|
||||
}
|
||||
|
||||
if (ptr + 4 <= fend &&
|
||||
if (_ptr + 4 <= fend &&
|
||||
ptr[0] == STD(r2, r1, 0x28) &&
|
||||
(ptr[1] & 0xffff0000) == ADDIS(r2, r2, {}) &&
|
||||
(ptr[2] & 0xffff0000) == ADDI(r2, r2, {}) &&
|
||||
@@ -1037,7 +1067,7 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
|
||||
{
|
||||
// Trampoline with TOC
|
||||
const u32 toc_add = (ptr[1] << 16) + s16(ptr[2]);
|
||||
const u32 target = (ptr[3] & 0x2 ? 0 : (ptr + 3).addr()) + ppu_opcode_t{ptr[3]}.bt24;
|
||||
const u32 target = (ptr[3] & 0x2 ? 0 : (_ptr + 3).addr()) + ppu_opcode_t{ptr[3]}.bt24;
|
||||
|
||||
if (target >= start && target < end)
|
||||
{
|
||||
@@ -1055,11 +1085,11 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
|
||||
add_toc(toc);
|
||||
add_func(func.addr, toc, 0);
|
||||
}
|
||||
else if (new_func.toc - func.toc != toc_add)
|
||||
{
|
||||
//func.toc = -1;
|
||||
//new_func.toc = -1;
|
||||
}
|
||||
//else if (new_func.toc - func.toc != toc_add)
|
||||
//{
|
||||
// func.toc = -1;
|
||||
// new_func.toc = -1;
|
||||
//}
|
||||
|
||||
if (new_func.blocks.empty())
|
||||
{
|
||||
@@ -1076,7 +1106,7 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
|
||||
}
|
||||
}
|
||||
|
||||
if (ptr + 8 <= fend &&
|
||||
if (_ptr + 8 <= fend &&
|
||||
(ptr[0] & 0xffff0000) == LI(r12, 0) &&
|
||||
(ptr[1] & 0xffff0000) == ORIS(r12, r12, 0) &&
|
||||
(ptr[2] & 0xffff0000) == LWZ(r12, r12, 0) &&
|
||||
@@ -1095,9 +1125,10 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
|
||||
func.attr += ppu_attr::known_size;
|
||||
|
||||
// Look for another imports to fill gaps (hack)
|
||||
auto p2 = ptr + 8;
|
||||
auto _p2 = _ptr + 8;
|
||||
auto p2 = get_ptr<u32>(_p2);
|
||||
|
||||
while (p2 + 8 <= fend &&
|
||||
while (_p2 + 8 <= fend &&
|
||||
(p2[0] & 0xffff0000) == LI(r12, 0) &&
|
||||
(p2[1] & 0xffff0000) == ORIS(r12, r12, 0) &&
|
||||
(p2[2] & 0xffff0000) == LWZ(r12, r12, 0) &&
|
||||
@@ -1107,19 +1138,19 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
|
||||
p2[6] == MTCTR(r0) &&
|
||||
p2[7] == BCTR())
|
||||
{
|
||||
auto& next = add_func(p2.addr(), -1, func.addr);
|
||||
auto& next = add_func(_p2.addr(), -1, func.addr);
|
||||
next.size = 0x20;
|
||||
next.blocks.emplace(next.addr, next.size);
|
||||
next.attr += ppu_attr::known_addr;
|
||||
next.attr += ppu_attr::known_size;
|
||||
p2 += 8;
|
||||
advance(_p2, p2, 8);
|
||||
known_functions.emplace(next.addr);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ptr + 3 <= fend &&
|
||||
if (_ptr + 3 <= fend &&
|
||||
ptr[0] == 0x7c0004acu &&
|
||||
ptr[1] == 0x00000000u &&
|
||||
ptr[2] == BLR())
|
||||
@@ -1131,7 +1162,7 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
|
||||
continue;
|
||||
}
|
||||
|
||||
if (const u32 len = ppu_test(ptr, fend, ppu_patterns::abort))
|
||||
if (const u32 len = ppu_test(ptr, get_ptr<void>(fend), ppu_patterns::abort))
|
||||
{
|
||||
// Function "abort"
|
||||
ppu_log.notice("Function [0x%x]: 'abort'", func.addr);
|
||||
@@ -1199,10 +1230,13 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
|
||||
{
|
||||
auto& block = block_queue[j].get();
|
||||
|
||||
for (vm::cptr<u32> _ptr = vm::cast(block.first); _ptr.addr() < func_end;)
|
||||
vm::cptr<u32> _ptr = vm::cast(block.first);
|
||||
auto ptr = ensure(get_ptr<u32>(_ptr));
|
||||
|
||||
for (; _ptr.addr() < func_end;)
|
||||
{
|
||||
const u32 iaddr = _ptr.addr();
|
||||
const ppu_opcode_t op{*_ptr++};
|
||||
const ppu_opcode_t op{*advance(_ptr, ptr, 1)};
|
||||
const ppu_itype::type type = s_ppu_itype.decode(op.opcode);
|
||||
|
||||
if (type == ppu_itype::UNK)
|
||||
@@ -1276,9 +1310,9 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
|
||||
const u32 jt_addr = _ptr.addr();
|
||||
const u32 jt_end = func_end;
|
||||
|
||||
for (; _ptr.addr() < jt_end; _ptr++)
|
||||
for (; _ptr.addr() < jt_end; advance(_ptr, ptr, 1))
|
||||
{
|
||||
const u32 addr = jt_addr + *_ptr;
|
||||
const u32 addr = jt_addr + *ptr;
|
||||
|
||||
if (addr == jt_addr)
|
||||
{
|
||||
@@ -1331,7 +1365,7 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
|
||||
block.second = _ptr.addr() - block.first;
|
||||
break;
|
||||
}
|
||||
else if (type == ppu_itype::STDU && func.attr & ppu_attr::no_size && (op.opcode == *_ptr || *_ptr == ppu_instructions::BLR()))
|
||||
else if (type == ppu_itype::STDU && func.attr & ppu_attr::no_size && (op.opcode == *ptr || *ptr == ppu_instructions::BLR()))
|
||||
{
|
||||
// Hack
|
||||
ppu_log.success("[0x%x] Instruction repetition: 0x%08x", iaddr, op.opcode);
|
||||
@@ -1391,7 +1425,7 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
|
||||
for (vm::cptr<u32> _ptr = vm::cast(block.first); _ptr.addr() < block.first + block.second;)
|
||||
{
|
||||
const u32 iaddr = _ptr.addr();
|
||||
const ppu_opcode_t op{*_ptr++};
|
||||
const ppu_opcode_t op{get_ref<u32>(_ptr++)};
|
||||
const ppu_itype::type type = s_ppu_itype.decode(op.opcode);
|
||||
|
||||
if (type == ppu_itype::B || type == ppu_itype::BC)
|
||||
@@ -1465,14 +1499,15 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
|
||||
for (vm::cptr<u32> _ptr = vm::cast(start); _ptr.addr() < next;)
|
||||
{
|
||||
const u32 addr = _ptr.addr();
|
||||
const ppu_opcode_t op{*_ptr++};
|
||||
const ppu_opcode_t op{get_ref<u32>(_ptr++)};
|
||||
const ppu_itype::type type = s_ppu_itype.decode(op.opcode);
|
||||
|
||||
if (type == ppu_itype::UNK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (addr == start && op.opcode == ppu_instructions::NOP())
|
||||
|
||||
if (addr == start && op.opcode == ppu_instructions::NOP())
|
||||
{
|
||||
if (start == func.addr + func.size)
|
||||
{
|
||||
@@ -1483,16 +1518,19 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
|
||||
start += 4;
|
||||
continue;
|
||||
}
|
||||
else if (type == ppu_itype::SC && op.opcode != ppu_instructions::SC(0))
|
||||
|
||||
if (type == ppu_itype::SC && op.opcode != ppu_instructions::SC(0))
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (addr == start && op.opcode == ppu_instructions::BLR())
|
||||
|
||||
if (addr == start && op.opcode == ppu_instructions::BLR())
|
||||
{
|
||||
start += 4;
|
||||
continue;
|
||||
}
|
||||
else if (type == ppu_itype::B || type == ppu_itype::BC)
|
||||
|
||||
if (type == ppu_itype::B || type == ppu_itype::BC)
|
||||
{
|
||||
const u32 target = (op.aa ? 0 : addr) + (type == ppu_itype::B ? +op.bt24 : +op.bt14);
|
||||
|
||||
@@ -1539,7 +1577,7 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
|
||||
end = 0;
|
||||
}
|
||||
|
||||
for (auto&& [_, func] : as_rvalue(std::move(fmap)))
|
||||
for (auto&& [_, func] : as_rvalue(fmap))
|
||||
{
|
||||
if (func.attr & ppu_attr::no_size && entry)
|
||||
{
|
||||
@@ -1560,7 +1598,7 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto [addr, size] : func.blocks)
|
||||
for (const auto& [addr, size] : func.blocks)
|
||||
{
|
||||
if (!size)
|
||||
{
|
||||
@@ -1598,12 +1636,12 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
|
||||
for (auto& rel : this->relocs)
|
||||
{
|
||||
// Disabled (TODO)
|
||||
if (1 || !vm::check_addr<4>(rel.addr))
|
||||
//if (!vm::check_addr<4>(rel.addr))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const u32 target = vm::_ref<u32>(rel.addr);
|
||||
const u32 target = get_ref<u32>(rel.addr);
|
||||
|
||||
if (target % 4 || target < start || target >= end)
|
||||
{
|
||||
@@ -1680,7 +1718,7 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
|
||||
|
||||
for (; i_pos < lim; i_pos += 4)
|
||||
{
|
||||
const u32 opc = vm::_ref<u32>(i_pos);
|
||||
const u32 opc = get_ref<u32>(i_pos);
|
||||
|
||||
switch (auto type = s_ppu_itype.decode(opc))
|
||||
{
|
||||
@@ -1722,9 +1760,7 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
|
||||
break;
|
||||
}
|
||||
|
||||
const auto found = fmap.find(target);
|
||||
|
||||
if (target != i_pos && found == fmap.cend())
|
||||
if (target != i_pos && !fmap.contains(target))
|
||||
{
|
||||
if (block_set.count(target) == 0)
|
||||
{
|
||||
@@ -1782,9 +1818,7 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
|
||||
else if (is_good && is_fallback && lim < end)
|
||||
{
|
||||
// Register fallback target
|
||||
const auto found = fmap.find(lim);
|
||||
|
||||
if (found == fmap.cend() && block_set.count(lim) == 0)
|
||||
if (!fmap.contains(lim) && !block_set.contains(lim))
|
||||
{
|
||||
ppu_log.trace("Block target found: 0x%x (i_pos=0x%x)", lim, i_pos);
|
||||
block_queue.emplace_back(lim, 0);
|
||||
|
||||
@@ -3,8 +3,11 @@
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <deque>
|
||||
#include "util/types.hpp"
|
||||
#include "util/endian.hpp"
|
||||
#include "util/asm.hpp"
|
||||
#include "util/to_endian.hpp"
|
||||
|
||||
#include "Utilities/bit_set.h"
|
||||
#include "PPUOpcodes.h"
|
||||
@@ -65,6 +68,7 @@ struct ppu_segment
|
||||
u32 type;
|
||||
u32 flags;
|
||||
u32 filesz;
|
||||
void* ptr{};
|
||||
};
|
||||
|
||||
// PPU Module Information
|
||||
@@ -89,6 +93,8 @@ struct ppu_module
|
||||
std::vector<ppu_segment> segs{};
|
||||
std::vector<ppu_segment> secs{};
|
||||
std::vector<ppu_function> funcs{};
|
||||
std::deque<std::shared_ptr<void>> allocations;
|
||||
std::map<u32, u32> addr_to_seg_index;
|
||||
|
||||
// Copy info without functions
|
||||
void copy_part(const ppu_module& info)
|
||||
@@ -99,16 +105,90 @@ struct ppu_module
|
||||
relocs = info.relocs;
|
||||
segs = info.segs;
|
||||
secs = info.secs;
|
||||
allocations = info.allocations;
|
||||
addr_to_seg_index = info.addr_to_seg_index;
|
||||
}
|
||||
|
||||
bool analyse(u32 lib_toc, u32 entry, u32 end, const std::basic_string<u32>& applied, std::function<bool()> check_aborted = {});
|
||||
void validate(u32 reloc);
|
||||
|
||||
template <typename T>
|
||||
to_be_t<T>* get_ptr(u32 addr, u32 size_bytes) const
|
||||
{
|
||||
auto it = addr_to_seg_index.upper_bound(addr);
|
||||
|
||||
if (it == addr_to_seg_index.begin())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
it--;
|
||||
|
||||
const auto& seg = segs[it->second];
|
||||
const u32 seg_size = seg.size;
|
||||
const u32 seg_addr = seg.addr;
|
||||
|
||||
if (seg_size >= std::max<usz>(size_bytes, 1) && addr <= utils::align<u32>(seg_addr + seg_size, 0x10000) - size_bytes)
|
||||
{
|
||||
return reinterpret_cast<to_be_t<T>*>(static_cast<u8*>(seg.ptr) + (addr - seg_addr));
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
to_be_t<T>* get_ptr(u32 addr) const
|
||||
{
|
||||
constexpr usz size_element = std::is_void_v<T> ? 0 : sizeof(std::conditional_t<std::is_void_v<T>, char, T>);
|
||||
return get_ptr<T>(addr, u32{size_element});
|
||||
}
|
||||
|
||||
template <typename T, typename U> requires requires (const U& obj) { +obj.size() * 0; }
|
||||
to_be_t<T>* get_ptr(U&& addr) const
|
||||
{
|
||||
constexpr usz size_element = std::is_void_v<T> ? 0 : sizeof(std::conditional_t<std::is_void_v<T>, char, T>);
|
||||
return get_ptr<T>(addr.addr(), u32{size_element});
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
to_be_t<T>& get_ref(u32 addr,
|
||||
u32 line = __builtin_LINE(),
|
||||
u32 col = __builtin_COLUMN(),
|
||||
const char* file = __builtin_FILE(),
|
||||
const char* func = __builtin_FUNCTION()) const
|
||||
{
|
||||
constexpr usz size_element = std::is_void_v<T> ? 0 : sizeof(std::conditional_t<std::is_void_v<T>, char, T>);
|
||||
if (auto ptr = get_ptr<T>(addr, u32{size_element}))
|
||||
{
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
fmt::throw_exception("get_ref(): Failure! (addr=0x%x)%s", addr, src_loc{line, col, file, func});
|
||||
return *std::add_pointer_t<to_be_t<T>>{};
|
||||
}
|
||||
|
||||
template <typename T, typename U> requires requires (const U& obj) { +obj.size() * 0; }
|
||||
to_be_t<T>& get_ref(U&& addr,
|
||||
u32 line = __builtin_LINE(),
|
||||
u32 col = __builtin_COLUMN(),
|
||||
const char* file = __builtin_FILE(),
|
||||
const char* func = __builtin_FUNCTION()) const
|
||||
{
|
||||
constexpr usz size_element = std::is_void_v<T> ? 0 : sizeof(std::conditional_t<std::is_void_v<T>, char, T>);
|
||||
if (auto ptr = get_ptr<T>(addr.addr(), u32{size_element}))
|
||||
{
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
fmt::throw_exception("get_ref(): Failure! (addr=0x%x)%s", addr.addr(), src_loc{line, col, file, func});
|
||||
return *std::add_pointer_t<to_be_t<T>>{};
|
||||
}
|
||||
};
|
||||
|
||||
struct main_ppu_module : public ppu_module
|
||||
{
|
||||
u32 elf_entry;
|
||||
u32 seg0_code_end;
|
||||
u32 elf_entry{};
|
||||
u32 seg0_code_end{};
|
||||
std::basic_string<u32> applied_pathes;
|
||||
};
|
||||
|
||||
|
||||
@@ -14,6 +14,11 @@
|
||||
std::memcpy(ppu.syscall_args, ppu.gpr + 3, sizeof(ppu.syscall_args)); \
|
||||
ppu_func_detail::do_call(ppu, func);\
|
||||
static_cast<void>(ppu.test_stopped());\
|
||||
auto& history = ppu.syscall_history.data[ppu.syscall_history.index++ % ppu.syscall_history.data.size()];\
|
||||
history.cia = ppu.cia;\
|
||||
history.func_name = ppu.current_function;\
|
||||
history.error = ppu.gpr[3];\
|
||||
if (ppu.syscall_history.count_debug_arguments) std::copy_n(ppu.syscall_args, std::size(history.args), history.args.data());\
|
||||
ppu.current_function = old_f;\
|
||||
ppu.cia += 4;\
|
||||
__VA_ARGS__;\
|
||||
|
||||
+208
-108
@@ -335,9 +335,12 @@ static void ppu_initialize_modules(ppu_linkage_info* link, utils::serial* ar = n
|
||||
u32 alloc_addr = 0;
|
||||
|
||||
// "Use" all the modules for correct linkage
|
||||
for (auto& _module : registered)
|
||||
if (ppu_loader.trace)
|
||||
{
|
||||
ppu_loader.trace("Registered static module: %s", _module->name);
|
||||
for (auto& _module : registered)
|
||||
{
|
||||
ppu_loader.trace("Registered static module: %s", _module->name);
|
||||
}
|
||||
}
|
||||
|
||||
struct hle_vars_save
|
||||
@@ -751,7 +754,7 @@ static auto ppu_load_exports(ppu_linkage_info* link, u32 exports_start, u32 expo
|
||||
|
||||
if (lib.num_tlsvar)
|
||||
{
|
||||
ppu_loader.fatal("Unexpected num_tlsvar (%u)!", lib.num_tlsvar);
|
||||
ppu_loader.error("Unexpected num_tlsvar (%u)!", lib.num_tlsvar);
|
||||
}
|
||||
|
||||
const bool should_load = ppu_register_library_lock(module_name, true);
|
||||
@@ -886,7 +889,7 @@ static auto ppu_load_imports(std::vector<ppu_reloc>& relocs, ppu_linkage_info* l
|
||||
|
||||
if (lib.num_tlsvar)
|
||||
{
|
||||
ppu_loader.fatal("Unexpected num_tlsvar (%u)!", lib.num_tlsvar);
|
||||
ppu_loader.error("Unexpected num_tlsvar (%u)!", lib.num_tlsvar);
|
||||
}
|
||||
|
||||
// Static module
|
||||
@@ -1048,20 +1051,23 @@ void init_ppu_functions(utils::serial* ar, bool full = false)
|
||||
|
||||
if (full)
|
||||
{
|
||||
ensure(ar);
|
||||
|
||||
// Initialize HLE modules
|
||||
ppu_initialize_modules(&g_fxo->get<ppu_linkage_info>(), ar);
|
||||
}
|
||||
}
|
||||
|
||||
static void ppu_check_patch_spu_images(const ppu_segment& seg)
|
||||
static void ppu_check_patch_spu_images(const ppu_module& mod, const ppu_segment& seg)
|
||||
{
|
||||
const std::string_view seg_view{vm::get_super_ptr<char>(seg.addr), seg.size};
|
||||
if (!seg.size)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string_view seg_view{ensure(mod.get_ptr<char>(seg.addr)), seg.size};
|
||||
|
||||
for (usz i = seg_view.find("\177ELF"); i < seg.size; i = seg_view.find("\177ELF", i + 4))
|
||||
{
|
||||
const auto elf_header = vm::get_super_ptr<u8>(seg.addr + i);
|
||||
const auto elf_header = ensure(mod.get_ptr<u8>(seg.addr + i));
|
||||
|
||||
// Try to load SPU image
|
||||
const spu_exec_object obj(fs::file(elf_header, seg.size - i));
|
||||
@@ -1102,7 +1108,7 @@ static void ppu_check_patch_spu_images(const ppu_segment& seg)
|
||||
sha1_update(&sha2, (elf_header + prog.p_offset), prog.p_filesz);
|
||||
|
||||
// We assume that the string SPUNAME exists 0x14 bytes into the NOTE segment
|
||||
name = reinterpret_cast<char*>(elf_header + prog.p_offset + 0x14);
|
||||
name = ensure(mod.get_ptr<const char>(seg.addr + i + prog.p_offset + 0x14));
|
||||
|
||||
if (!name.empty())
|
||||
{
|
||||
@@ -1136,12 +1142,12 @@ static void ppu_check_patch_spu_images(const ppu_segment& seg)
|
||||
for (const auto& prog : obj.progs)
|
||||
{
|
||||
// Apply the patch
|
||||
applied += g_fxo->get<patch_engine>().apply(hash, (elf_header + prog.p_offset), prog.p_filesz, prog.p_vaddr);
|
||||
applied += g_fxo->get<patch_engine>().apply(hash, [&](u32 addr, u32 /*size*/) { return addr + elf_header + prog.p_offset; }, prog.p_filesz, prog.p_vaddr);
|
||||
|
||||
if (!Emu.GetTitleID().empty())
|
||||
{
|
||||
// Alternative patch
|
||||
applied += g_fxo->get<patch_engine>().apply(Emu.GetTitleID() + '-' + hash, (elf_header + prog.p_offset), prog.p_filesz, prog.p_vaddr);
|
||||
applied += g_fxo->get<patch_engine>().apply(Emu.GetTitleID() + '-' + hash, [&](u32 addr, u32 /*size*/) { return addr + elf_header + prog.p_offset; }, prog.p_filesz, prog.p_vaddr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1247,7 +1253,7 @@ const char* get_prx_name_by_cia(u32 addr)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::string& path, s64 file_offset, utils::serial* ar)
|
||||
std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, bool virtual_load, const std::string& path, s64 file_offset, utils::serial* ar)
|
||||
{
|
||||
if (elf != elf_error::ok)
|
||||
{
|
||||
@@ -1255,7 +1261,7 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
|
||||
}
|
||||
|
||||
// Create new PRX object
|
||||
const auto prx = !ar ? idm::make_ptr<lv2_obj, lv2_prx>() : std::make_shared<lv2_prx>();
|
||||
const auto prx = !ar && !virtual_load ? idm::make_ptr<lv2_obj, lv2_prx>() : std::make_shared<lv2_prx>();
|
||||
|
||||
// Access linkage information object
|
||||
auto& link = g_fxo->get<ppu_linkage_info>();
|
||||
@@ -1270,6 +1276,9 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
|
||||
u32 end = 0;
|
||||
u32 toc = 0;
|
||||
|
||||
// 0x100000: Workaround for analyser glitches
|
||||
u32 allocating_address = 0x100000;
|
||||
|
||||
for (const auto& prog : elf.progs)
|
||||
{
|
||||
ppu_loader.notice("** Segment: p_type=0x%x, p_vaddr=0x%llx, p_filesz=0x%llx, p_memsz=0x%llx, flags=0x%x", prog.p_type, prog.p_vaddr, prog.p_filesz, prog.p_memsz, prog.p_flags);
|
||||
@@ -1294,15 +1303,42 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
|
||||
|
||||
// Alloc segment memory
|
||||
// Or use saved address
|
||||
const u32 addr = !ar ? vm::alloc(mem_size, vm::main) : ar->operator u32();
|
||||
u32 addr = 0;
|
||||
|
||||
if (!vm::check_addr(addr))
|
||||
if (virtual_load)
|
||||
{
|
||||
addr = std::exchange(allocating_address, allocating_address + utils::align<u32>(mem_size, 0x10000));
|
||||
}
|
||||
else
|
||||
{
|
||||
addr = (!ar ? vm::alloc(mem_size, vm::main) : ar->operator u32());
|
||||
}
|
||||
|
||||
_seg.ptr = vm::base(addr);
|
||||
|
||||
if (virtual_load)
|
||||
{
|
||||
// Leave additional room for the analyser so it can safely access beyond limit a bit
|
||||
// Because with VM the address sapce is not really a limit so any u32 address is valid there, here it is UB to create pointer that goes beyond the boundaries
|
||||
// TODO: Use make_shared_for_overwrite when all compilers support it
|
||||
const usz alloc_size = utils::align<usz>(mem_size, 0x10000) + 4096;
|
||||
prx->allocations.push_back(std::shared_ptr<u8[]>(new u8[alloc_size]));
|
||||
_seg.ptr = prx->allocations.back().get();
|
||||
std::memset(static_cast<u8*>(_seg.ptr) + prog.bin.size(), 0, alloc_size - 4096 - prog.bin.size());
|
||||
}
|
||||
else if (!vm::check_addr(addr))
|
||||
{
|
||||
fmt::throw_exception("vm::alloc() failed (size=0x%x)", mem_size);
|
||||
}
|
||||
|
||||
_seg.addr = addr;
|
||||
_seg.size = mem_size;
|
||||
_seg.filesz = file_size;
|
||||
|
||||
prx->addr_to_seg_index.emplace(addr, prx->segs.size() - 1);
|
||||
|
||||
// Copy segment data
|
||||
if (!ar) std::memcpy(vm::base(addr), prog.bin.data(), file_size);
|
||||
if (!ar) std::memcpy(ensure(prx->get_ptr<void>(addr)), prog.bin.data(), file_size);
|
||||
ppu_loader.warning("**** Loaded to 0x%x...0x%x (size=0x%x)", addr, addr + mem_size - 1, mem_size);
|
||||
|
||||
// Hash segment
|
||||
@@ -1311,7 +1347,7 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
|
||||
sha1_update(&sha, prog.bin.data(), prog.bin.size());
|
||||
|
||||
// Initialize executable code if necessary
|
||||
if (prog.p_flags & 0x1)
|
||||
if (prog.p_flags & 0x1 && !virtual_load)
|
||||
{
|
||||
if (ar)
|
||||
{
|
||||
@@ -1321,10 +1357,6 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
|
||||
|
||||
ppu_register_range(addr, mem_size);
|
||||
}
|
||||
|
||||
_seg.addr = addr;
|
||||
_seg.size = mem_size;
|
||||
_seg.filesz = file_size;
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -1420,63 +1452,63 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
|
||||
{
|
||||
case 1: // R_PPC64_ADDR32
|
||||
{
|
||||
const u32 value = vm::_ref<u32>(raddr) = static_cast<u32>(rdata);
|
||||
const u32 value = *ensure(prx->get_ptr<u32>(raddr)) = static_cast<u32>(rdata);
|
||||
ppu_loader.trace("**** RELOCATION(1): 0x%x <- 0x%08x (0x%llx)", raddr, value, rdata);
|
||||
break;
|
||||
}
|
||||
|
||||
case 4: //R_PPC64_ADDR16_LO
|
||||
{
|
||||
const u16 value = vm::_ref<u16>(raddr) = static_cast<u16>(rdata);
|
||||
const u16 value = *ensure(prx->get_ptr<u16>(raddr)) = static_cast<u16>(rdata);
|
||||
ppu_loader.trace("**** RELOCATION(4): 0x%x <- 0x%04x (0x%llx)", raddr, value, rdata);
|
||||
break;
|
||||
}
|
||||
|
||||
case 5: //R_PPC64_ADDR16_HI
|
||||
{
|
||||
const u16 value = vm::_ref<u16>(raddr) = static_cast<u16>(rdata >> 16);
|
||||
const u16 value = *ensure(prx->get_ptr<u16>(raddr)) = static_cast<u16>(rdata >> 16);
|
||||
ppu_loader.trace("**** RELOCATION(5): 0x%x <- 0x%04x (0x%llx)", raddr, value, rdata);
|
||||
break;
|
||||
}
|
||||
|
||||
case 6: //R_PPC64_ADDR16_HA
|
||||
{
|
||||
const u16 value = vm::_ref<u16>(raddr) = static_cast<u16>(rdata >> 16) + (rdata & 0x8000 ? 1 : 0);
|
||||
const u16 value = *ensure(prx->get_ptr<u16>(raddr)) = static_cast<u16>(rdata >> 16) + (rdata & 0x8000 ? 1 : 0);
|
||||
ppu_loader.trace("**** RELOCATION(6): 0x%x <- 0x%04x (0x%llx)", raddr, value, rdata);
|
||||
break;
|
||||
}
|
||||
|
||||
case 10: //R_PPC64_REL24
|
||||
{
|
||||
const u32 value = vm::_ref<ppu_bf_t<be_t<u32>, 6, 24>>(raddr) = static_cast<u32>(rdata - raddr) >> 2;
|
||||
const u32 value = *ensure(prx->get_ptr<ppu_bf_t<be_t<u32>, 6, 24>>(raddr)) = static_cast<u32>(rdata - raddr) >> 2;
|
||||
ppu_loader.warning("**** RELOCATION(10): 0x%x <- 0x%06x (0x%llx)", raddr, value, rdata);
|
||||
break;
|
||||
}
|
||||
|
||||
case 11: //R_PPC64_REL14
|
||||
{
|
||||
const u32 value = vm::_ref<ppu_bf_t<be_t<u32>, 16, 14>>(raddr) = static_cast<u32>(rdata - raddr) >> 2;
|
||||
const u32 value = *ensure(prx->get_ptr<ppu_bf_t<be_t<u32>, 16, 14>>(raddr)) = static_cast<u32>(rdata - raddr) >> 2;
|
||||
ppu_loader.warning("**** RELOCATION(11): 0x%x <- 0x%06x (0x%llx)", raddr, value, rdata);
|
||||
break;
|
||||
}
|
||||
|
||||
case 38: //R_PPC64_ADDR64
|
||||
{
|
||||
const u64 value = vm::_ref<u64>(raddr) = rdata;
|
||||
const u64 value = *ensure(prx->get_ptr<u64>(raddr)) = rdata;
|
||||
ppu_loader.trace("**** RELOCATION(38): 0x%x <- 0x%016llx (0x%llx)", raddr, value, rdata);
|
||||
break;
|
||||
}
|
||||
|
||||
case 44: //R_PPC64_REL64
|
||||
{
|
||||
const u64 value = vm::_ref<u64>(raddr) = rdata - raddr;
|
||||
const u64 value = *ensure(prx->get_ptr<u64>(raddr)) = rdata - raddr;
|
||||
ppu_loader.trace("**** RELOCATION(44): 0x%x <- 0x%016llx (0x%llx)", raddr, value, rdata);
|
||||
break;
|
||||
}
|
||||
|
||||
case 57: //R_PPC64_ADDR16_LO_DS
|
||||
{
|
||||
const u16 value = vm::_ref<ppu_bf_t<be_t<u16>, 0, 14>>(raddr) = static_cast<u16>(rdata) >> 2;
|
||||
const u16 value = *ensure(prx->get_ptr<ppu_bf_t<be_t<u16>, 0, 14>>(raddr)) = static_cast<u16>(rdata) >> 2;
|
||||
ppu_loader.trace("**** RELOCATION(57): 0x%x <- 0x%04x (0x%llx)", raddr, value, rdata);
|
||||
break;
|
||||
}
|
||||
@@ -1511,7 +1543,7 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
|
||||
};
|
||||
|
||||
// Access library information (TODO)
|
||||
const vm::cptr<ppu_prx_library_info> lib_info = vm::cast(prx->segs[0].addr + elf.progs[0].p_paddr - elf.progs[0].p_offset);
|
||||
const auto lib_info = ensure(prx->get_ptr<const ppu_prx_library_info>(prx->segs[0].addr + elf.progs[0].p_paddr - elf.progs[0].p_offset));
|
||||
const std::string lib_name = lib_info->name;
|
||||
|
||||
strcpy_trunc(prx->module_info_name, lib_name);
|
||||
@@ -1522,7 +1554,7 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
|
||||
prx->exports_start = lib_info->exports_start;
|
||||
prx->exports_end = lib_info->exports_end;
|
||||
|
||||
for (usz start = prx->exports_start, size = 0;; size++, start += vm::read8(start) ? vm::read8(start) : sizeof(ppu_prx_module_info))
|
||||
for (usz start = prx->exports_start, size = 0;; size++)
|
||||
{
|
||||
if (start >= prx->exports_end)
|
||||
{
|
||||
@@ -1530,18 +1562,25 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
|
||||
prx->m_external_loaded_flags.resize(size);
|
||||
break;
|
||||
}
|
||||
|
||||
const u8 increment = *ensure(prx->get_ptr<u8>(start));
|
||||
start += increment ? increment : sizeof(ppu_prx_module_info);
|
||||
}
|
||||
|
||||
ppu_loader.warning("Library %s (rtoc=0x%x):", lib_name, lib_info->toc);
|
||||
|
||||
prx->specials = ppu_load_exports(&link, prx->exports_start, prx->exports_end, true);
|
||||
prx->imports = ppu_load_imports(prx->relocs, &link, lib_info->imports_start, lib_info->imports_end);
|
||||
if (!virtual_load)
|
||||
{
|
||||
prx->specials = ppu_load_exports(&link, prx->exports_start, prx->exports_end, true);
|
||||
prx->imports = ppu_load_imports(prx->relocs, &link, lib_info->imports_start, lib_info->imports_end);
|
||||
}
|
||||
|
||||
std::stable_sort(prx->relocs.begin(), prx->relocs.end());
|
||||
toc = lib_info->toc;
|
||||
}
|
||||
else
|
||||
{
|
||||
ppu_loader.fatal("Library %s: PRX library info not found");
|
||||
ppu_loader.error("Library %s: PRX library info not found");
|
||||
}
|
||||
|
||||
prx->start.set(prx->specials[0xbc9a0086]);
|
||||
@@ -1578,12 +1617,12 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
|
||||
const std::string hash_seg = fmt::format("%s-%u", hash, i);
|
||||
|
||||
// Apply the patch
|
||||
auto _applied = g_fxo->get<patch_engine>().apply(hash_seg, vm::get_super_ptr(seg.addr), seg.size);
|
||||
auto _applied = g_fxo->get<patch_engine>().apply(hash_seg, [&](u32 addr, u32 size) { return prx->get_ptr<u8>(addr + seg.addr, size); }, seg.size);
|
||||
|
||||
if (!Emu.GetTitleID().empty())
|
||||
{
|
||||
// Alternative patch
|
||||
_applied += g_fxo->get<patch_engine>().apply(Emu.GetTitleID() + '-' + hash_seg, vm::get_super_ptr(seg.addr), seg.size);
|
||||
_applied += g_fxo->get<patch_engine>().apply(Emu.GetTitleID() + '-' + hash_seg, [&](u32 addr, u32 size) { return prx->get_ptr<u8>(addr + seg.addr, size); }, seg.size);
|
||||
}
|
||||
|
||||
// Rebase patch offsets
|
||||
@@ -1604,12 +1643,15 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
|
||||
// Embedded SPU elf patching
|
||||
for (const auto& seg : prx->segs)
|
||||
{
|
||||
ppu_check_patch_spu_images(seg);
|
||||
ppu_check_patch_spu_images(*prx, seg);
|
||||
}
|
||||
|
||||
prx->analyse(toc, 0, end, applied);
|
||||
|
||||
try_spawn_ppu_if_exclusive_program(*prx);
|
||||
if (!ar && !virtual_load)
|
||||
{
|
||||
try_spawn_ppu_if_exclusive_program(*prx);
|
||||
}
|
||||
|
||||
return prx;
|
||||
}
|
||||
@@ -1666,7 +1708,10 @@ void ppu_unload_prx(const lv2_prx& prx)
|
||||
{
|
||||
if (!seg.size) continue;
|
||||
|
||||
vm::dealloc(seg.addr, vm::main);
|
||||
if (seg.ptr == vm::base(seg.addr))
|
||||
{
|
||||
vm::dealloc(seg.addr, vm::main);
|
||||
}
|
||||
|
||||
const std::string hash_seg = fmt::format("%s-%u", hash, &seg - prx.segs.data());
|
||||
|
||||
@@ -1681,7 +1726,7 @@ void ppu_unload_prx(const lv2_prx& prx)
|
||||
}
|
||||
}
|
||||
|
||||
bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar)
|
||||
bool ppu_load_exec(const ppu_exec_object& elf, bool virtual_load, const std::string& elf_path, utils::serial* ar)
|
||||
{
|
||||
if (elf != elf_error::ok)
|
||||
{
|
||||
@@ -1752,6 +1797,14 @@ bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar)
|
||||
|
||||
} error_handler{_main};
|
||||
|
||||
if (virtual_load)
|
||||
{
|
||||
// No need for cleanup
|
||||
error_handler.errored = false;
|
||||
}
|
||||
|
||||
const auto old_process_info = g_ps3_process_info;
|
||||
|
||||
// Allocate memory at fixed positions
|
||||
for (const auto& prog : elf.progs)
|
||||
{
|
||||
@@ -1773,13 +1826,25 @@ bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar)
|
||||
{
|
||||
if (prog.bin.size() > size || prog.bin.size() != prog.p_filesz)
|
||||
{
|
||||
ppu_loader.fatal("ppu_load_exec(): Invalid binary size (0x%llx, memsz=0x%x)", prog.bin.size(), size);
|
||||
ppu_loader.error("ppu_load_exec(): Invalid binary size (0x%llx, memsz=0x%x)", prog.bin.size(), size);
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool already_loaded = ar && vm::check_addr(addr, vm::page_readable, size);
|
||||
|
||||
if (already_loaded)
|
||||
_seg.ptr = vm::base(addr);
|
||||
|
||||
if (virtual_load)
|
||||
{
|
||||
// Leave additional room for the analyser so it can safely access beyond limit a bit
|
||||
// Because with VM the address sapce is not really a limit so any u32 address is valid there, here it is UB to create pointer that goes beyond the boundaries
|
||||
// TODO: Use make_shared_for_overwrite when all compilers support it
|
||||
const usz alloc_size = utils::align<usz>(size, 0x10000) + 4096;
|
||||
_main.allocations.push_back(std::shared_ptr<u8[]>(new u8[alloc_size]));
|
||||
_seg.ptr = _main.allocations.back().get();
|
||||
std::memset(static_cast<u8*>(_seg.ptr) + prog.bin.size(), 0, alloc_size - 4096 - prog.bin.size());
|
||||
}
|
||||
else if (already_loaded)
|
||||
{
|
||||
}
|
||||
else if (!vm::falloc(addr, size, vm::main))
|
||||
@@ -1788,15 +1853,19 @@ bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar)
|
||||
|
||||
if (!vm::falloc(addr, size))
|
||||
{
|
||||
ppu_loader.fatal("ppu_load_exec(): vm::falloc() failed (addr=0x%x, memsz=0x%x)", addr, size);
|
||||
ppu_loader.error("ppu_load_exec(): vm::falloc() failed (addr=0x%x, memsz=0x%x)", addr, size);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Store only LOAD segments (TODO)
|
||||
_main.segs.emplace_back(_seg);
|
||||
_main.addr_to_seg_index.emplace(addr, _main.segs.size() - 1);
|
||||
|
||||
// Copy segment data, hash it
|
||||
if (!already_loaded)
|
||||
{
|
||||
std::memcpy(vm::base(addr), prog.bin.data(), prog.bin.size());
|
||||
std::memcpy(_main.get_ptr<void>(addr), prog.bin.data(), prog.bin.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1811,7 +1880,7 @@ bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar)
|
||||
sha1_update(&sha, prog.bin.data(), prog.bin.size());
|
||||
|
||||
// Initialize executable code if necessary
|
||||
if (prog.p_flags & 0x1)
|
||||
if (prog.p_flags & 0x1 && !virtual_load)
|
||||
{
|
||||
if (already_loaded && ar)
|
||||
{
|
||||
@@ -1821,9 +1890,6 @@ bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar)
|
||||
|
||||
ppu_register_range(addr, size);
|
||||
}
|
||||
|
||||
// Store only LOAD segments (TODO)
|
||||
_main.segs.emplace_back(_seg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1867,12 +1933,12 @@ bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar)
|
||||
Emu.SetExecutableHash(hash);
|
||||
|
||||
// Apply the patch
|
||||
auto applied = g_fxo->get<patch_engine>().apply(!ar ? hash : std::string{}, vm::g_base_addr);
|
||||
auto applied = g_fxo->get<patch_engine>().apply(!ar ? hash : std::string{}, [&](u32 addr, u32 size) { return _main.get_ptr<u8>(addr, size); });
|
||||
|
||||
if (!ar && !Emu.GetTitleID().empty())
|
||||
{
|
||||
// Alternative patch
|
||||
applied += g_fxo->get<patch_engine>().apply(Emu.GetTitleID() + '-' + hash, vm::g_base_addr);
|
||||
applied += g_fxo->get<patch_engine>().apply(Emu.GetTitleID() + '-' + hash, [&](u32 addr, u32 size) { return _main.get_ptr<u8>(addr, size); });
|
||||
}
|
||||
|
||||
if (applied.empty())
|
||||
@@ -1890,11 +1956,11 @@ bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar)
|
||||
// Embedded SPU elf patching
|
||||
for (const auto& seg : _main.segs)
|
||||
{
|
||||
ppu_check_patch_spu_images(seg);
|
||||
ppu_check_patch_spu_images(_main, seg);
|
||||
}
|
||||
|
||||
// Static HLE patching
|
||||
if (g_cfg.core.hook_functions)
|
||||
if (g_cfg.core.hook_functions && !virtual_load)
|
||||
{
|
||||
auto shle = g_fxo->init<statichle_handler>(0);
|
||||
|
||||
@@ -1942,7 +2008,7 @@ bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar)
|
||||
|
||||
if ((prog.p_vaddr | prog.p_filesz | prog.p_memsz) > u32{umax})
|
||||
{
|
||||
ppu_loader.fatal("ppu_load_exec(): TLS segment is invalid!");
|
||||
ppu_loader.error("ppu_load_exec(): TLS segment is invalid!");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1969,7 +2035,7 @@ bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar)
|
||||
//be_t<u32> crash_dump_param_addr;
|
||||
};
|
||||
|
||||
const auto& info = vm::_ref<process_param_t>(vm::cast(prog.p_vaddr));
|
||||
const auto& info = *ensure(_main.get_ptr<process_param_t>(vm::cast(prog.p_vaddr)));
|
||||
|
||||
if (info.size < sizeof(process_param_t))
|
||||
{
|
||||
@@ -2024,7 +2090,7 @@ bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar)
|
||||
be_t<u32> unk2;
|
||||
};
|
||||
|
||||
const auto& proc_prx_param = vm::_ref<const ppu_proc_prx_param_t>(vm::cast(prog.p_vaddr));
|
||||
const auto& proc_prx_param = *ensure(_main.get_ptr<const ppu_proc_prx_param_t>(vm::cast(prog.p_vaddr)));
|
||||
|
||||
ppu_loader.notice("* libent_start = *0x%x", proc_prx_param.libent_start);
|
||||
ppu_loader.notice("* libstub_start = *0x%x", proc_prx_param.libstub_start);
|
||||
@@ -2033,12 +2099,16 @@ bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar)
|
||||
|
||||
if (proc_prx_param.magic != 0x1b434cecu)
|
||||
{
|
||||
ppu_loader.fatal("ppu_load_exec(): Bad magic! (0x%x)", proc_prx_param.magic);
|
||||
ppu_loader.error("ppu_load_exec(): Bad magic! (0x%x)", proc_prx_param.magic);
|
||||
return false;
|
||||
}
|
||||
|
||||
ppu_load_exports(&link, proc_prx_param.libent_start, proc_prx_param.libent_end);
|
||||
ppu_load_imports(_main.relocs, &link, proc_prx_param.libstub_start, proc_prx_param.libstub_end);
|
||||
if (!virtual_load)
|
||||
{
|
||||
ppu_load_exports(&link, proc_prx_param.libent_start, proc_prx_param.libent_end);
|
||||
ppu_load_imports(_main.relocs, &link, proc_prx_param.libstub_start, proc_prx_param.libstub_end);
|
||||
}
|
||||
|
||||
std::stable_sort(_main.relocs.begin(), _main.relocs.end());
|
||||
}
|
||||
break;
|
||||
@@ -2105,7 +2175,7 @@ bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar)
|
||||
load_libs.emplace("libsysmodule.sprx");
|
||||
}
|
||||
|
||||
if (ar || Emu.IsVsh())
|
||||
if (ar || Emu.IsVsh() || virtual_load)
|
||||
{
|
||||
// Cannot be used with vsh.self or savestates (they self-manage itself)
|
||||
load_libs.clear();
|
||||
@@ -2121,35 +2191,45 @@ bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar)
|
||||
}
|
||||
|
||||
// Program entry
|
||||
u32 entry = 0;
|
||||
u32 entry = static_cast<u32>(elf.header.e_entry); // Run entry from elf (HLE)
|
||||
|
||||
// Set path (TODO)
|
||||
_main.name.clear();
|
||||
_main.path = vfs::get(Emu.argv[0]);
|
||||
_main.path = elf_path;
|
||||
|
||||
_main.elf_entry = static_cast<u32>(elf.header.e_entry);
|
||||
_main.seg0_code_end = end;
|
||||
_main.applied_pathes = applied;
|
||||
|
||||
// Set SDK version
|
||||
g_ps3_process_info.sdk_ver = sdk_version;
|
||||
|
||||
// Set ppc fixed allocations segment permission
|
||||
g_ps3_process_info.ppc_seg = ppc_seg;
|
||||
|
||||
if (Emu.init_mem_containers)
|
||||
if (!virtual_load)
|
||||
{
|
||||
// Refer to sys_process_exit2 for explanation
|
||||
Emu.init_mem_containers(mem_size);
|
||||
}
|
||||
else if (!ar)
|
||||
{
|
||||
g_fxo->init<id_manager::id_map<lv2_memory_container>>();
|
||||
g_fxo->init<lv2_memory_container>(mem_size);
|
||||
}
|
||||
// Set SDK version
|
||||
g_ps3_process_info.sdk_ver = sdk_version;
|
||||
|
||||
void init_fxo_for_exec(utils::serial* ar, bool full);
|
||||
init_fxo_for_exec(ar, false);
|
||||
// Set ppc fixed allocations segment permission
|
||||
g_ps3_process_info.ppc_seg = ppc_seg;
|
||||
|
||||
if (Emu.init_mem_containers)
|
||||
{
|
||||
// Refer to sys_process_exit2 for explanation
|
||||
// Make init_mem_containers empty before call
|
||||
const auto callback = std::move(Emu.init_mem_containers);
|
||||
callback(mem_size);
|
||||
}
|
||||
else if (!ar)
|
||||
{
|
||||
g_fxo->init<id_manager::id_map<lv2_memory_container>>();
|
||||
g_fxo->init<lv2_memory_container>(mem_size);
|
||||
}
|
||||
|
||||
void init_fxo_for_exec(utils::serial* ar, bool full);
|
||||
init_fxo_for_exec(ar, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_ps3_process_info = old_process_info;
|
||||
Emu.ConfigurePPUCache();
|
||||
}
|
||||
|
||||
liblv2_begin = 0;
|
||||
liblv2_end = 0;
|
||||
@@ -2164,13 +2244,13 @@ bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar)
|
||||
{
|
||||
ppu_loader.warning("Loading library: %s", name);
|
||||
|
||||
auto prx = ppu_load_prx(obj, lle_dir + name, 0, nullptr);
|
||||
auto prx = ppu_load_prx(obj, false, lle_dir + name, 0, nullptr);
|
||||
prx->state = PRX_STATE_STARTED;
|
||||
prx->load_exports();
|
||||
|
||||
if (prx->funcs.empty())
|
||||
{
|
||||
ppu_loader.fatal("Module %s has no functions!", name);
|
||||
ppu_loader.error("Module %s has no functions!", name);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2195,7 +2275,7 @@ bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar)
|
||||
}
|
||||
}
|
||||
|
||||
if (ar)
|
||||
if (ar || virtual_load)
|
||||
{
|
||||
error_handler.errored = false;
|
||||
return true;
|
||||
@@ -2264,6 +2344,7 @@ bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar)
|
||||
ppu_thread_params p{};
|
||||
p.stack_addr = vm::cast(vm::alloc(primary_stacksize, vm::stack, 4096));
|
||||
p.stack_size = primary_stacksize;
|
||||
p.entry = vm::_ref<ppu_func_opd_t>(entry);
|
||||
|
||||
auto ppu = idm::make_ptr<named_thread<ppu_thread>>(p, "main_thread", primary_prio, 1);
|
||||
|
||||
@@ -2278,7 +2359,7 @@ bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar)
|
||||
|
||||
ppu->cmd_push({ppu_cmd::initialize, 0});
|
||||
|
||||
if (!entry && !Emu.IsVsh())
|
||||
if (entry == static_cast<u32>(elf.header.e_entry) && !Emu.IsVsh())
|
||||
{
|
||||
// Set TLS args, call sys_initialize_tls
|
||||
ppu->cmd_list
|
||||
@@ -2288,11 +2369,6 @@ bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar)
|
||||
});
|
||||
}
|
||||
|
||||
if (!entry)
|
||||
{
|
||||
entry = static_cast<u32>(elf.header.e_entry); // Run entry from elf
|
||||
}
|
||||
|
||||
// Run start functions
|
||||
for (const auto& prx : loaded_modules)
|
||||
{
|
||||
@@ -2315,7 +2391,7 @@ bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar)
|
||||
{ ppu_cmd::set_args, 8 }, u64{Emu.argv.size()}, u64{argv.addr()}, u64{envp.addr()}, u64{0}, u64{ppu->id}, u64{tls_vaddr}, u64{tls_fsize}, u64{tls_vsize},
|
||||
{ ppu_cmd::set_gpr, 11 }, u64{elf.header.e_entry},
|
||||
{ ppu_cmd::set_gpr, 12 }, u64{malloc_pagesize},
|
||||
{ ppu_cmd::lle_call, entry },
|
||||
{ ppu_cmd::entry_call, 0 },
|
||||
});
|
||||
|
||||
// Set actual memory protection (experimental)
|
||||
@@ -2335,7 +2411,7 @@ bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar)
|
||||
return true;
|
||||
}
|
||||
|
||||
std::pair<std::shared_ptr<lv2_overlay>, CellError> ppu_load_overlay(const ppu_exec_object& elf, const std::string& path, s64 file_offset, utils::serial* ar)
|
||||
std::pair<std::shared_ptr<lv2_overlay>, CellError> ppu_load_overlay(const ppu_exec_object& elf, bool virtual_load, const std::string& path, s64 file_offset, utils::serial* ar)
|
||||
{
|
||||
if (elf != elf_error::ok)
|
||||
{
|
||||
@@ -2399,11 +2475,23 @@ std::pair<std::shared_ptr<lv2_overlay>, CellError> ppu_load_overlay(const ppu_ex
|
||||
|
||||
const bool already_loaded = !!ar; // Unimplemented optimization for savestates
|
||||
|
||||
if (already_loaded)
|
||||
_seg.ptr = vm::base(addr);
|
||||
|
||||
if (virtual_load)
|
||||
{
|
||||
// Leave additional room for the analyser so it can safely access beyond limit a bit
|
||||
// Because with VM the address sapce is not really a limit so any u32 address is valid there, here it is UB to create pointer that goes beyond the boundaries
|
||||
// TODO: Use make_shared_for_overwrite when all compilers support it
|
||||
const usz alloc_size = utils::align<usz>(size, 0x10000) + 4096;
|
||||
ovlm->allocations.push_back(std::shared_ptr<u8[]>(new u8[alloc_size]));
|
||||
_seg.ptr = ovlm->allocations.back().get();
|
||||
std::memset(static_cast<u8*>(_seg.ptr) + prog.bin.size(), 0, alloc_size - 4096 - prog.bin.size());
|
||||
}
|
||||
else if (already_loaded)
|
||||
{
|
||||
if (!vm::check_addr(addr, vm::page_readable, size))
|
||||
{
|
||||
ppu_loader.fatal("ppu_load_overlay(): Archived PPU overlay memory has not been found! (addr=0x%x, memsz=0x%x)", addr, size);
|
||||
ppu_loader.error("ppu_load_overlay(): Archived PPU overlay memory has not been found! (addr=0x%x, memsz=0x%x)", addr, size);
|
||||
return {nullptr, CELL_EABORT};
|
||||
}
|
||||
}
|
||||
@@ -2421,14 +2509,18 @@ std::pair<std::shared_ptr<lv2_overlay>, CellError> ppu_load_overlay(const ppu_ex
|
||||
return {nullptr, CELL_EBUSY};
|
||||
}
|
||||
|
||||
// Store only LOAD segments (TODO)
|
||||
ovlm->segs.emplace_back(_seg);
|
||||
ovlm->addr_to_seg_index.emplace(addr, ovlm->segs.size() - 1);
|
||||
|
||||
// Copy segment data, hash it
|
||||
if (!already_loaded) std::memcpy(vm::base(addr), prog.bin.data(), prog.bin.size());
|
||||
if (!already_loaded) std::memcpy(ensure(ovlm->get_ptr<void>(addr)), prog.bin.data(), prog.bin.size());
|
||||
sha1_update(&sha, reinterpret_cast<const uchar*>(&prog.p_vaddr), sizeof(prog.p_vaddr));
|
||||
sha1_update(&sha, reinterpret_cast<const uchar*>(&prog.p_memsz), sizeof(prog.p_memsz));
|
||||
sha1_update(&sha, prog.bin.data(), prog.bin.size());
|
||||
|
||||
// Initialize executable code if necessary
|
||||
if (prog.p_flags & 0x1)
|
||||
if (prog.p_flags & 0x1 && !virtual_load)
|
||||
{
|
||||
if (ar)
|
||||
{
|
||||
@@ -2438,9 +2530,6 @@ std::pair<std::shared_ptr<lv2_overlay>, CellError> ppu_load_overlay(const ppu_ex
|
||||
|
||||
ppu_register_range(addr, size);
|
||||
}
|
||||
|
||||
// Store only LOAD segments (TODO)
|
||||
ovlm->segs.emplace_back(_seg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2482,18 +2571,18 @@ std::pair<std::shared_ptr<lv2_overlay>, CellError> ppu_load_overlay(const ppu_ex
|
||||
}
|
||||
|
||||
// Apply the patch
|
||||
auto applied = g_fxo->get<patch_engine>().apply(hash, vm::g_base_addr);
|
||||
auto applied = g_fxo->get<patch_engine>().apply(hash, [ovlm](u32 addr, u32 size) { return ovlm->get_ptr<u8>(addr, size); });
|
||||
|
||||
if (!Emu.GetTitleID().empty())
|
||||
{
|
||||
// Alternative patch
|
||||
applied += g_fxo->get<patch_engine>().apply(Emu.GetTitleID() + '-' + hash, vm::g_base_addr);
|
||||
applied += g_fxo->get<patch_engine>().apply(Emu.GetTitleID() + '-' + hash, [ovlm](u32 addr, u32 size) { return ovlm->get_ptr<u8>(addr, size); });
|
||||
}
|
||||
|
||||
// Embedded SPU elf patching
|
||||
for (const auto& seg : ovlm->segs)
|
||||
{
|
||||
ppu_check_patch_spu_images(seg);
|
||||
ppu_check_patch_spu_images(*ovlm, seg);
|
||||
}
|
||||
|
||||
if (applied.empty())
|
||||
@@ -2526,7 +2615,7 @@ std::pair<std::shared_ptr<lv2_overlay>, CellError> ppu_load_overlay(const ppu_ex
|
||||
//and a lot of zeros.
|
||||
};
|
||||
|
||||
const auto& info = vm::_ref<process_param_t>(vm::cast(prog.p_vaddr));
|
||||
const auto& info = *ensure(ovlm->get_ptr<process_param_t>(vm::cast(prog.p_vaddr)));
|
||||
|
||||
if (info.size < sizeof(process_param_t))
|
||||
{
|
||||
@@ -2564,7 +2653,7 @@ std::pair<std::shared_ptr<lv2_overlay>, CellError> ppu_load_overlay(const ppu_ex
|
||||
be_t<u32> unk2;
|
||||
};
|
||||
|
||||
const auto& proc_prx_param = vm::_ref<const ppu_proc_prx_param_t>(vm::cast(prog.p_vaddr));
|
||||
const auto& proc_prx_param = *ensure(ovlm->get_ptr<const ppu_proc_prx_param_t>(vm::cast(prog.p_vaddr)));
|
||||
|
||||
ppu_loader.notice("* libent_start = *0x%x", proc_prx_param.libent_start);
|
||||
ppu_loader.notice("* libstub_start = *0x%x", proc_prx_param.libstub_start);
|
||||
@@ -2576,8 +2665,11 @@ std::pair<std::shared_ptr<lv2_overlay>, CellError> ppu_load_overlay(const ppu_ex
|
||||
fmt::throw_exception("Bad magic! (0x%x)", proc_prx_param.magic);
|
||||
}
|
||||
|
||||
ppu_load_exports(&link, proc_prx_param.libent_start, proc_prx_param.libent_end);
|
||||
ppu_load_imports(ovlm->relocs, &link, proc_prx_param.libstub_start, proc_prx_param.libstub_end);
|
||||
if (!virtual_load)
|
||||
{
|
||||
ppu_load_exports(&link, proc_prx_param.libent_start, proc_prx_param.libent_end);
|
||||
ppu_load_imports(ovlm->relocs, &link, proc_prx_param.libstub_start, proc_prx_param.libstub_end);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -2590,13 +2682,21 @@ std::pair<std::shared_ptr<lv2_overlay>, CellError> ppu_load_overlay(const ppu_ex
|
||||
|
||||
ovlm->entry = static_cast<u32>(elf.header.e_entry);
|
||||
|
||||
const auto cpu = cpu_thread::get_current();
|
||||
|
||||
// Analyse executable (TODO)
|
||||
ovlm->analyse(0, ovlm->entry, end, applied);
|
||||
if (!ovlm->analyse(0, ovlm->entry, end, applied, !cpu ? std::function<bool()>() : [cpu, is_being_used_in_emulation = (vm::base(ovlm->segs[0].addr) == ovlm->segs[0].ptr)]()
|
||||
{
|
||||
return is_being_used_in_emulation && cpu->state & cpu_flag::exit;
|
||||
}))
|
||||
{
|
||||
return {nullptr, CellError{CELL_CANCEL + 0u}};
|
||||
}
|
||||
|
||||
// Validate analyser results (not required)
|
||||
ovlm->validate(0);
|
||||
|
||||
if (!ar)
|
||||
if (!ar && !virtual_load)
|
||||
{
|
||||
idm::import_existing<lv2_obj, lv2_overlay>(ovlm);
|
||||
try_spawn_ppu_if_exclusive_program(*ovlm);
|
||||
@@ -2644,7 +2744,7 @@ bool ppu_load_rel_exec(const ppu_rel_object& elf)
|
||||
|
||||
if (!addr)
|
||||
{
|
||||
ppu_loader.fatal("ppu_load_rel_exec(): vm::alloc() failed (memsz=0x%x)", memsize);
|
||||
ppu_loader.error("ppu_load_rel_exec(): vm::alloc() failed (memsz=0x%x)", memsize);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -674,6 +674,7 @@ namespace ppu_instructions
|
||||
|
||||
inline u32 ADDI(u32 rt, u32 ra, s32 si) { ppu_opcode_t op{ 0x0eu << 26 }; op.rd = rt; op.ra = ra; op.simm16 = si; return op.opcode; }
|
||||
inline u32 ADDIS(u32 rt, u32 ra, s32 si) { ppu_opcode_t op{ 0x0fu << 26 }; op.rd = rt; op.ra = ra; op.simm16 = si; return op.opcode; }
|
||||
inline u32 XORIS(u32 rt, u32 ra, s32 si) { ppu_opcode_t op{ 0x1bu << 26 }; op.rd = rt; op.ra = ra; op.simm16 = si; return op.opcode; }
|
||||
inline u32 ORI(u32 rt, u32 ra, u32 ui) { ppu_opcode_t op{ 0x18u << 26 }; op.rd = rt; op.ra = ra; op.uimm16 = ui; return op.opcode; }
|
||||
inline u32 ORIS(u32 rt, u32 ra, u32 ui) { ppu_opcode_t op{ 0x19u << 26 }; op.rd = rt; op.ra = ra; op.uimm16 = ui; return op.opcode; }
|
||||
inline u32 OR(u32 ra, u32 rs, u32 rb, bool rc = false) { ppu_opcode_t op{ 0x1fu << 26 | 0x1bcu << 1 }; op.rs = rs; op.ra = ra; op.rb = rb; op.rc = rc; return op.opcode; }
|
||||
@@ -685,6 +686,7 @@ namespace ppu_instructions
|
||||
inline u32 MFSPR(u32 rt, u32 spr) { ppu_opcode_t op{ 0x1fu << 26 | 0x153u << 1 }; op.rd = rt; op.spr = spr; return op.opcode; }
|
||||
inline u32 MTSPR(u32 spr, u32 rs) { ppu_opcode_t op{ 0x1fu << 26 | 0x1d3u << 1 }; op.rs = rs; op.spr = spr; return op.opcode; }
|
||||
inline u32 LWZ(u32 rt, u32 ra, s32 si) { ppu_opcode_t op{ 0x20u << 26 }; op.rd = rt; op.ra = ra; op.simm16 = si; return op.opcode; }
|
||||
inline u32 STW(u32 rt, u32 ra, s32 si) { ppu_opcode_t op{ 0x24u << 26 }; op.rd = rt; op.ra = ra; op.simm16 = si; return op.opcode; }
|
||||
inline u32 STD(u32 rs, u32 ra, s32 si) { ppu_opcode_t op{ 0x3eu << 26 }; op.rs = rs; op.ra = ra; op.ds = si / 4; return op.opcode; }
|
||||
inline u32 STDU(u32 rs, u32 ra, s32 si) { ppu_opcode_t op{ 0x3eu << 26 | 1 }; op.rs = rs; op.ra = ra; op.ds = si / 4; return op.opcode; }
|
||||
inline u32 LD(u32 rt, u32 ra, s32 si) { ppu_opcode_t op{ 0x3au << 26 }; op.rd = rt; op.ra = ra; op.ds = si / 4; return op.opcode; }
|
||||
@@ -697,6 +699,7 @@ namespace ppu_instructions
|
||||
inline u32 STVX(u32 vs, u32 ra, u32 rb) { ppu_opcode_t op{ 31 << 26 | 231 << 1 }; op.vs = vs; op.ra = ra; op.rb = rb; return op.opcode; }
|
||||
inline u32 LFD(u32 frd, u32 ra, s32 si) { ppu_opcode_t op{ 50u << 26 }; op.frd = frd; op.ra = ra; op.simm16 = si; return op.opcode; }
|
||||
inline u32 LVX(u32 vd, u32 ra, u32 rb) { ppu_opcode_t op{ 31 << 26 | 103 << 1 }; op.vd = vd; op.ra = ra; op.rb = rb; return op.opcode; }
|
||||
inline constexpr u32 EIEIO() { return 0x7c0006ac; }
|
||||
|
||||
namespace implicts
|
||||
{
|
||||
@@ -734,7 +737,7 @@ namespace ppu_instructions
|
||||
inline u32 CLRLDI(u32 x, u32 y, u32 n) { return RLDICL(x, y, 0, n, false); }
|
||||
inline u32 CLRRDI(u32 x, u32 y, u32 n) { return RLDICR(x, y, 0, 63 - n, false); }
|
||||
|
||||
inline u32 TRAP() { return 0x7FE00008; } // tw 31,r0,r0
|
||||
inline constexpr u32 TRAP() { return 0x7FE00008; } // tw 31,r0,r0
|
||||
}
|
||||
|
||||
using namespace implicts;
|
||||
|
||||
+485
-107
@@ -62,7 +62,9 @@
|
||||
#include <thread>
|
||||
#include <cfenv>
|
||||
#include <cctype>
|
||||
#include <span>
|
||||
#include <optional>
|
||||
|
||||
#include "util/asm.hpp"
|
||||
#include "util/vm.hpp"
|
||||
#include "util/v128.hpp"
|
||||
@@ -131,14 +133,26 @@ void fmt_class_string<typename ppu_thread::call_history_t>::format(std::string&
|
||||
|
||||
PPUDisAsm dis_asm(cpu_disasm_mode::normal, vm::g_sudo_addr);
|
||||
|
||||
for (u64 count = 0, idx = history.index - 1; idx != umax && count < ppu_thread::call_history_max_size; count++, idx--)
|
||||
for (u64 count = 0, idx = history.index - 1; idx != umax && count < history.data.size(); count++, idx--)
|
||||
{
|
||||
const u32 pc = history.data[idx % ppu_thread::call_history_max_size];
|
||||
const u32 pc = history.data[idx % history.data.size()];
|
||||
dis_asm.disasm(pc);
|
||||
fmt::append(out, "\n(%u) 0x%08x: %s", count, pc, dis_asm.last_opcode);
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void fmt_class_string<typename ppu_thread::syscall_history_t>::format(std::string& out, u64 arg)
|
||||
{
|
||||
const auto& history = get_object(arg);
|
||||
|
||||
for (u64 count = 0, idx = history.index - 1; idx != umax && count < history.data.size(); count++, idx--)
|
||||
{
|
||||
const auto& entry = history.data[idx % history.data.size()];
|
||||
fmt::append(out, "\n(%u) 0x%08x: %s, 0x%x, r3=0x%x, r4=0x%x, r5=0x%x, r6=0x%x", count, entry.cia, entry.func_name, entry.error, entry.args[0], entry.args[1], entry.args[2], entry.args[3]);
|
||||
}
|
||||
}
|
||||
|
||||
extern const ppu_decoder<ppu_itype> g_ppu_itype{};
|
||||
extern const ppu_decoder<ppu_iname> g_ppu_iname{};
|
||||
|
||||
@@ -161,9 +175,10 @@ extern void ppu_initialize();
|
||||
extern void ppu_finalize(const ppu_module& info);
|
||||
extern bool ppu_initialize(const ppu_module& info, bool = false);
|
||||
static void ppu_initialize2(class jit_compiler& jit, const ppu_module& module_part, const std::string& cache_path, const std::string& obj_name);
|
||||
extern std::pair<std::shared_ptr<lv2_overlay>, CellError> ppu_load_overlay(const ppu_exec_object&, const std::string& path, s64 file_offset, utils::serial* = nullptr);
|
||||
extern bool ppu_load_exec(const ppu_exec_object&, bool virtual_load, const std::string&, utils::serial* = nullptr);
|
||||
extern std::pair<std::shared_ptr<lv2_overlay>, CellError> ppu_load_overlay(const ppu_exec_object&, bool virtual_load, const std::string& path, s64 file_offset, utils::serial* = nullptr);
|
||||
extern void ppu_unload_prx(const lv2_prx&);
|
||||
extern std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object&, const std::string&, s64 file_offset, utils::serial* = nullptr);
|
||||
extern std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object&, bool virtual_load, const std::string&, s64 file_offset, utils::serial* = nullptr);
|
||||
extern void ppu_execute_syscall(ppu_thread& ppu, u64 code);
|
||||
static void ppu_break(ppu_thread&, ppu_opcode_t, be_t<u32>*, ppu_intrp_func*);
|
||||
|
||||
@@ -484,16 +499,198 @@ void ppu_reservation_fallback(ppu_thread& ppu)
|
||||
}
|
||||
}
|
||||
|
||||
static std::unordered_map<u32, u32>* s_ppu_toc;
|
||||
u32 ppu_read_mmio_aware_u32(u8* vm_base, u32 eal)
|
||||
{
|
||||
if (eal >= RAW_SPU_BASE_ADDR)
|
||||
{
|
||||
// RawSPU MMIO
|
||||
auto thread = idm::get<named_thread<spu_thread>>(spu_thread::find_raw_spu((eal - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET));
|
||||
|
||||
if (!thread)
|
||||
{
|
||||
// Access Violation
|
||||
}
|
||||
else if ((eal - RAW_SPU_BASE_ADDR) % RAW_SPU_OFFSET + sizeof(u32) - 1 < SPU_LS_SIZE) // LS access
|
||||
{
|
||||
}
|
||||
else if (u32 value{}; thread->read_reg(eal, value))
|
||||
{
|
||||
return std::bit_cast<be_t<u32>>(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
fmt::throw_exception("Invalid RawSPU MMIO offset (addr=0x%x)", eal);
|
||||
}
|
||||
}
|
||||
|
||||
// Value is assumed to be swapped
|
||||
return read_from_ptr<u32>(vm_base + eal);
|
||||
}
|
||||
|
||||
void ppu_write_mmio_aware_u32(u8* vm_base, u32 eal, u32 value)
|
||||
{
|
||||
if (eal >= RAW_SPU_BASE_ADDR)
|
||||
{
|
||||
// RawSPU MMIO
|
||||
auto thread = idm::get<named_thread<spu_thread>>(spu_thread::find_raw_spu((eal - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET));
|
||||
|
||||
if (!thread)
|
||||
{
|
||||
// Access Violation
|
||||
}
|
||||
else if ((eal - RAW_SPU_BASE_ADDR) % RAW_SPU_OFFSET + sizeof(u32) - 1 < SPU_LS_SIZE) // LS access
|
||||
{
|
||||
}
|
||||
else if (thread->write_reg(eal, std::bit_cast<be_t<u32>>(value)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
fmt::throw_exception("Invalid RawSPU MMIO offset (addr=0x%x)", eal);
|
||||
}
|
||||
}
|
||||
|
||||
// Value is assumed swapped
|
||||
write_to_ptr<u32>(vm_base + eal, value);
|
||||
}
|
||||
|
||||
extern bool ppu_test_address_may_be_mmio(std::span<const be_t<u32>> insts)
|
||||
{
|
||||
std::set<u32> reg_offsets;
|
||||
bool found_raw_spu_base = false;
|
||||
bool found_spu_area_offset_element = false;
|
||||
|
||||
for (u32 inst : insts)
|
||||
{
|
||||
// Common around MMIO (orders IO)
|
||||
if (inst == ppu_instructions::EIEIO())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
const u32 op_imm16 = (inst & 0xfc00ffff);
|
||||
|
||||
// RawSPU MMIO base
|
||||
// 0xe00000000 is a common constant so try to find an ORIS 0x10 or ADDIS 0x10 nearby (for multiplying SPU ID by it)
|
||||
if (op_imm16 == ppu_instructions::ADDIS({}, {}, -0x2000) || op_imm16 == ppu_instructions::ORIS({}, {}, 0xe000) || op_imm16 == ppu_instructions::XORIS({}, {}, 0xe000))
|
||||
{
|
||||
found_raw_spu_base = true;
|
||||
|
||||
if (found_spu_area_offset_element)
|
||||
{
|
||||
// Found both
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (op_imm16 == ppu_instructions::ORIS({}, {}, 0x10) || op_imm16 == ppu_instructions::ADDIS({}, {}, 0x10))
|
||||
{
|
||||
found_spu_area_offset_element = true;
|
||||
|
||||
if (found_raw_spu_base)
|
||||
{
|
||||
// Found both
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// RawSPU MMIO base + problem state offset
|
||||
else if (op_imm16 == ppu_instructions::ADDIS({}, {}, -0x1ffc))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (op_imm16 == ppu_instructions::ORIS({}, {}, 0xe004))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (op_imm16 == ppu_instructions::XORIS({}, {}, 0xe004))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// RawSPU MMIO base + problem state offset + 64k of SNR1 offset
|
||||
else if (op_imm16 == ppu_instructions::ADDIS({}, {}, -0x1ffb))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (op_imm16 == ppu_instructions::ORIS({}, {}, 0xe005))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (op_imm16 == ppu_instructions::XORIS({}, {}, 0xe005))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// RawSPU MMIO base + problem state offset + 264k of SNR2 offset (STW allows 32K+- offset so in order to access SNR2 it needs to first add another 64k)
|
||||
// SNR2 is the only register currently implemented that has its 0x80000 bit is set so its the only one its hardcoded access is done this way
|
||||
else if (op_imm16 == ppu_instructions::ADDIS({}, {}, -0x1ffa))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (op_imm16 == ppu_instructions::ORIS({}, {}, 0xe006))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (op_imm16 == ppu_instructions::XORIS({}, {}, 0xe006))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// Try to detect a function that receives RawSPU problem state base pointer as an argument
|
||||
else if ((op_imm16 & ~0xffff) == ppu_instructions::LWZ({}, {}, 0) ||
|
||||
(op_imm16 & ~0xffff) == ppu_instructions::STW({}, {}, 0) ||
|
||||
(op_imm16 & ~0xffff) == ppu_instructions::ADDI({}, {}, 0))
|
||||
{
|
||||
const bool is_load = (op_imm16 & ~0xffff) == ppu_instructions::LWZ({}, {}, 0);
|
||||
const bool is_store = (op_imm16 & ~0xffff) == ppu_instructions::STW({}, {}, 0);
|
||||
const bool is_neither = !is_store && !is_load;
|
||||
const bool is_snr = (is_store || is_neither) && ((op_imm16 & 0xffff) == (SPU_RdSigNotify2_offs & 0xffff) || (op_imm16 & 0xffff) == (SPU_RdSigNotify1_offs & 0xffff));
|
||||
|
||||
if (is_snr || spu_thread::test_is_problem_state_register_offset(op_imm16 & 0xffff, is_load || is_neither, is_store || is_neither))
|
||||
{
|
||||
reg_offsets.insert(op_imm16 & 0xffff);
|
||||
|
||||
if (reg_offsets.size() >= 2)
|
||||
{
|
||||
// Assume high MMIO likelyhood if more than one offset appears in nearby code
|
||||
// Such as common IN_MBOX + OUT_MBOX
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ppu_toc_manager
|
||||
{
|
||||
std::unordered_map<u32, u32> toc_map;
|
||||
|
||||
shared_mutex mutex;
|
||||
};
|
||||
|
||||
static void ppu_check_toc(ppu_thread& ppu, ppu_opcode_t op, be_t<u32>* this_op, ppu_intrp_func* next_fn)
|
||||
{
|
||||
// Compare TOC with expected value
|
||||
const auto found = s_ppu_toc->find(ppu.cia);
|
||||
ppu.cia = vm::get_addr(this_op);
|
||||
|
||||
if (ppu.gpr[2] != found->second)
|
||||
{
|
||||
ppu_log.error("Unexpected TOC (0x%x, expected 0x%x)", ppu.gpr[2], found->second);
|
||||
auto& toc_manager = g_fxo->get<ppu_toc_manager>();
|
||||
|
||||
reader_lock lock(toc_manager.mutex);
|
||||
|
||||
auto& ppu_toc = toc_manager.toc_map;
|
||||
|
||||
const auto found = ppu_toc.find(ppu.cia);
|
||||
|
||||
if (found != ppu_toc.end())
|
||||
{
|
||||
const u32 toc = atomic_storage<u32>::load(found->second);
|
||||
|
||||
// Compare TOC with expected value
|
||||
if (toc != umax && ppu.gpr[2] != toc)
|
||||
{
|
||||
ppu_log.error("Unexpected TOC (0x%x, expected 0x%x)", ppu.gpr[2], toc);
|
||||
atomic_storage<u32>::exchange(found->second, u32{umax});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to the interpreter function
|
||||
@@ -887,7 +1084,7 @@ void ppu_remove_hle_instructions(u32 addr, u32 size)
|
||||
}
|
||||
}
|
||||
|
||||
atomic_t<bool> g_debugger_pause_all_threads_on_bp = true;
|
||||
atomic_t<bool> g_debugger_pause_all_threads_on_bp = false;
|
||||
|
||||
// Breakpoint entry point
|
||||
static void ppu_break(ppu_thread& ppu, ppu_opcode_t, be_t<u32>* this_op, ppu_intrp_func* next_fn)
|
||||
@@ -1038,8 +1235,30 @@ std::array<u32, 2> op_branch_targets(u32 pc, ppu_opcode_t op)
|
||||
return res;
|
||||
}
|
||||
|
||||
void ppu_thread::dump_regs(std::string& ret) const
|
||||
void ppu_thread::dump_regs(std::string& ret, std::any& custom_data) const
|
||||
{
|
||||
const system_state emu_state = Emu.GetStatus(false);
|
||||
const bool is_stopped_or_frozen = state & cpu_flag::exit || emu_state == system_state::frozen || emu_state <= system_state::stopping;
|
||||
const ppu_debugger_mode mode = debugger_mode.load();
|
||||
|
||||
const bool is_decimal = !is_stopped_or_frozen && mode == ppu_debugger_mode::is_decimal;
|
||||
|
||||
struct dump_registers_data_t
|
||||
{
|
||||
u32 preferred_cr_field_index = 7;
|
||||
};
|
||||
|
||||
dump_registers_data_t* func_data = nullptr;
|
||||
|
||||
func_data = std::any_cast<dump_registers_data_t>(&custom_data);
|
||||
|
||||
if (!func_data)
|
||||
{
|
||||
custom_data.reset();
|
||||
custom_data = std::make_any<dump_registers_data_t>();
|
||||
func_data = ensure(std::any_cast<dump_registers_data_t>(&custom_data));
|
||||
}
|
||||
|
||||
PPUDisAsm dis_asm(cpu_disasm_mode::normal, vm::g_sudo_addr);
|
||||
|
||||
for (uint i = 0; i < 32; ++i)
|
||||
@@ -1081,7 +1300,14 @@ void ppu_thread::dump_regs(std::string& ret) const
|
||||
|
||||
if (!printed_error)
|
||||
{
|
||||
fmt::append(ret, "0x%-8llx", reg);
|
||||
if (is_decimal)
|
||||
{
|
||||
fmt::append(ret, "%-11d", reg);
|
||||
}
|
||||
else
|
||||
{
|
||||
fmt::append(ret, "0x%-8llx", reg);
|
||||
}
|
||||
}
|
||||
|
||||
constexpr u32 max_str_len = 32;
|
||||
@@ -1153,9 +1379,63 @@ void ppu_thread::dump_regs(std::string& ret) const
|
||||
}
|
||||
}
|
||||
|
||||
fmt::append(ret, "\n");
|
||||
fmt::trim_back(ret);
|
||||
ret += '\n';
|
||||
}
|
||||
|
||||
const u32 current_cia = cia;
|
||||
const u32 cr_packed = cr.pack();
|
||||
|
||||
for (u32 addr :
|
||||
{
|
||||
current_cia,
|
||||
current_cia + 4,
|
||||
current_cia + 8,
|
||||
current_cia - 4,
|
||||
current_cia + 12,
|
||||
})
|
||||
{
|
||||
dis_asm.disasm(addr);
|
||||
|
||||
if (dis_asm.last_opcode.size() <= 4)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (usz index = dis_asm.last_opcode.rfind(",cr"); index < dis_asm.last_opcode.size() - 4)
|
||||
{
|
||||
const char result = dis_asm.last_opcode[index + 3];
|
||||
|
||||
if (result >= '0' && result <= '7')
|
||||
{
|
||||
func_data->preferred_cr_field_index = result - '0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (usz index = dis_asm.last_opcode.rfind(" cr"); index < dis_asm.last_opcode.size() - 4)
|
||||
{
|
||||
const char result = dis_asm.last_opcode[index + 3];
|
||||
|
||||
if (result >= '0' && result <= '7')
|
||||
{
|
||||
func_data->preferred_cr_field_index = result - '0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (dis_asm.last_opcode.find("stdcx.") != umax || dis_asm.last_opcode.find("stwcx.") != umax)
|
||||
{
|
||||
// Modifying CR0
|
||||
func_data->preferred_cr_field_index = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const u32 displayed_cr_field = (cr_packed >> ((7 - func_data->preferred_cr_field_index) * 4)) & 0xf;
|
||||
|
||||
fmt::append(ret, "CR: 0x%08x, CR%d: [LT=%u GT=%u EQ=%u SO=%u]\n", cr_packed, func_data->preferred_cr_field_index, displayed_cr_field >> 3, (displayed_cr_field >> 2) & 1, (displayed_cr_field >> 1) & 1, displayed_cr_field & 1);
|
||||
|
||||
for (uint i = 0; i < 32; ++i)
|
||||
{
|
||||
const f64 r = fpr[i];
|
||||
@@ -1189,8 +1469,7 @@ void ppu_thread::dump_regs(std::string& ret) const
|
||||
}
|
||||
}
|
||||
|
||||
fmt::append(ret, "CIA: 0x%x\n", cia);
|
||||
fmt::append(ret, "CR: 0x%08x\n", cr.pack());
|
||||
fmt::append(ret, "CIA: 0x%x\n", current_cia);
|
||||
fmt::append(ret, "LR: 0x%llx\n", lr);
|
||||
fmt::append(ret, "CTR: 0x%llx\n", ctr);
|
||||
fmt::append(ret, "VRSAVE: 0x%08x\n", vrsave);
|
||||
@@ -1407,7 +1686,7 @@ void ppu_thread::dump_all(std::string& ret) const
|
||||
{
|
||||
cpu_thread::dump_all(ret);
|
||||
|
||||
if (!call_history.data.empty())
|
||||
if (call_history.data.size() > 1)
|
||||
{
|
||||
ret +=
|
||||
"\nCalling History:"
|
||||
@@ -1415,6 +1694,15 @@ void ppu_thread::dump_all(std::string& ret) const
|
||||
|
||||
fmt::append(ret, "%s", call_history);
|
||||
}
|
||||
|
||||
if (syscall_history.data.size() > 1)
|
||||
{
|
||||
ret +=
|
||||
"\nHLE/LV2 History:"
|
||||
"\n================";
|
||||
|
||||
fmt::append(ret, "%s", syscall_history);
|
||||
}
|
||||
}
|
||||
|
||||
extern thread_local std::string(*g_tls_log_prefix)();
|
||||
@@ -1479,6 +1767,14 @@ void ppu_thread::cpu_task()
|
||||
cmd_pop(), fast_call(opd[0], opd[1]);
|
||||
break;
|
||||
}
|
||||
case ppu_cmd::entry_call:
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
pthread_jit_write_protect_np(true);
|
||||
#endif
|
||||
cmd_pop(), fast_call(entry_func.addr, entry_func.rtoc, true);
|
||||
break;
|
||||
}
|
||||
case ppu_cmd::hle_call:
|
||||
{
|
||||
cmd_pop(), ::at32(ppu_function_manager::get(), arg)(*this, {arg}, vm::_ptr<u32>(cia - 4), &ppu_ret);
|
||||
@@ -1502,7 +1798,7 @@ void ppu_thread::cpu_task()
|
||||
case ppu_cmd::cia_call:
|
||||
{
|
||||
loaded_from_savestate = true;
|
||||
cmd_pop(), fast_call(std::exchange(cia, 0), gpr[2]);
|
||||
cmd_pop(), fast_call(std::exchange(cia, 0), gpr[2], true);
|
||||
break;
|
||||
}
|
||||
case ppu_cmd::initialize:
|
||||
@@ -1526,7 +1822,7 @@ void ppu_thread::cpu_task()
|
||||
// Wait until the progress dialog is closed.
|
||||
// We don't want to open a cell dialog while a native progress dialog is still open.
|
||||
thread_ctrl::wait_on<atomic_wait::op_ne>(g_progr_ptotal, 0);
|
||||
g_fxo->get<progress_dialog_workaround>().skip_the_progress_dialog = true;
|
||||
g_fxo->get<progress_dialog_workaround>().show_overlay_message_only = true;
|
||||
|
||||
// Sadly we can't postpone initializing guest time because we need to run PPU threads
|
||||
// (the farther it's postponed, the less accuracy of guest time has been lost)
|
||||
@@ -1609,7 +1905,7 @@ void ppu_thread::cpu_on_stop()
|
||||
}
|
||||
|
||||
// TODO: More conditions
|
||||
if (Emu.IsStopped() && g_cfg.core.spu_debug)
|
||||
if (Emu.IsStopped() && g_cfg.core.ppu_debug)
|
||||
{
|
||||
std::string ret;
|
||||
dump_all(ret);
|
||||
@@ -1656,7 +1952,7 @@ void ppu_thread::exec_task()
|
||||
|
||||
ppu_thread::~ppu_thread()
|
||||
{
|
||||
perf_log.notice("Perf stats for STCX reload: successs %u, failure %u", last_succ, last_fail);
|
||||
perf_log.notice("Perf stats for STCX reload: success %u, failure %u", last_succ, last_fail);
|
||||
perf_log.notice("Perf stats for instructions: total %u", exec_bytes / 4);
|
||||
}
|
||||
|
||||
@@ -1693,10 +1989,9 @@ ppu_thread::ppu_thread(const ppu_thread_params& param, std::string_view name, u3
|
||||
state += cpu_flag::memory;
|
||||
}
|
||||
|
||||
if (g_cfg.core.ppu_call_history)
|
||||
{
|
||||
call_history.data.resize(call_history_max_size);
|
||||
}
|
||||
call_history.data.resize(g_cfg.core.ppu_call_history ? call_history_max_size : 1);
|
||||
syscall_history.data.resize(g_cfg.core.ppu_call_history ? syscall_history_max_size : 1);
|
||||
syscall_history.count_debug_arguments = static_cast<u32>(g_cfg.core.ppu_call_history ? std::size(syscall_history.data[0].args) : 0);
|
||||
|
||||
#ifdef __APPLE__
|
||||
pthread_jit_write_protect_np(true);
|
||||
@@ -1735,21 +2030,7 @@ void ppu_thread::serialize_common(utils::serial& ar)
|
||||
{
|
||||
[[maybe_unused]] const s32 version = GET_OR_USE_SERIALIZATION_VERSION(ar.is_writing(), ppu);
|
||||
|
||||
ar(gpr, fpr, cr, fpscr.bits, lr, ctr, vrsave, cia, xer, sat, nj);
|
||||
|
||||
if (ar.is_writing())
|
||||
{
|
||||
ar(prio.load().all);
|
||||
}
|
||||
else if (version < 2)
|
||||
{
|
||||
prio.raw().all = 0;
|
||||
prio.raw().prio = ar.operator s32();
|
||||
}
|
||||
else
|
||||
{
|
||||
ar(prio.raw().all);
|
||||
}
|
||||
ar(gpr, fpr, cr, fpscr.bits, lr, ctr, vrsave, cia, xer, sat, nj, prio.raw().all);
|
||||
|
||||
ar(optional_savestate_state, vr);
|
||||
|
||||
@@ -1773,6 +2054,10 @@ ppu_thread::ppu_thread(utils::serial& ar)
|
||||
atomic_t<bool> inited = false;
|
||||
};
|
||||
|
||||
call_history.data.resize(g_cfg.core.ppu_call_history ? call_history_max_size : 1);
|
||||
syscall_history.data.resize(g_cfg.core.ppu_call_history ? syscall_history_max_size : 1);
|
||||
syscall_history.count_debug_arguments = static_cast<u32>(g_cfg.core.ppu_call_history ? std::size(syscall_history.data[0].args) : 0);
|
||||
|
||||
serialize_common(ar);
|
||||
|
||||
// Restore jm_mask
|
||||
@@ -1999,7 +2284,7 @@ be_t<u64>* ppu_thread::get_stack_arg(s32 i, u64 align)
|
||||
return vm::_ptr<u64>(vm::cast((gpr[1] + 0x30 + 0x8 * (i - 1)) & (0 - align)));
|
||||
}
|
||||
|
||||
void ppu_thread::fast_call(u32 addr, u64 rtoc)
|
||||
void ppu_thread::fast_call(u32 addr, u64 rtoc, bool is_thread_entry)
|
||||
{
|
||||
const auto old_cia = cia;
|
||||
const auto old_rtoc = gpr[2];
|
||||
@@ -2054,12 +2339,7 @@ void ppu_thread::fast_call(u32 addr, u64 rtoc)
|
||||
|
||||
auto at_ret = [&]()
|
||||
{
|
||||
if (std::uncaught_exceptions())
|
||||
{
|
||||
cpu_on_stop();
|
||||
current_function = old_func;
|
||||
}
|
||||
else if (old_cia)
|
||||
if (old_cia)
|
||||
{
|
||||
if (state & cpu_flag::again)
|
||||
{
|
||||
@@ -2070,6 +2350,20 @@ void ppu_thread::fast_call(u32 addr, u64 rtoc)
|
||||
gpr[2] = old_rtoc;
|
||||
lr = old_lr;
|
||||
}
|
||||
else if (state & cpu_flag::ret && cia == g_fxo->get<ppu_function_manager>().func_addr(1, true) + 4 && is_thread_entry)
|
||||
{
|
||||
std::string ret;
|
||||
dump_all(ret);
|
||||
|
||||
ppu_log.error("Returning from the thread entry function! (func=0x%x)", entry_func.addr);
|
||||
ppu_log.notice("Thread context: %s", ret);
|
||||
|
||||
lv2_obj::sleep(*this);
|
||||
|
||||
// For savestates
|
||||
state += cpu_flag::again;
|
||||
std::memcpy(syscall_args, &gpr[3], sizeof(syscall_args));
|
||||
}
|
||||
|
||||
current_function = old_func;
|
||||
g_tls_log_prefix = old_fmt;
|
||||
@@ -2249,7 +2543,7 @@ static T ppu_load_acquire_reservation(ppu_thread& ppu, u32 addr)
|
||||
ppu.use_full_rdata = false;
|
||||
}
|
||||
|
||||
if ((addr & addr_mask) == (ppu.last_faddr & addr_mask))
|
||||
if (ppu_log.trace && (addr & addr_mask) == (ppu.last_faddr & addr_mask))
|
||||
{
|
||||
ppu_log.trace(u8"LARX after fail: addr=0x%x, faddr=0x%x, time=%u c", addr, ppu.last_faddr, (perf0.get() - ppu.last_ftsc));
|
||||
}
|
||||
@@ -2837,9 +3131,9 @@ namespace
|
||||
{
|
||||
}
|
||||
|
||||
fs::stat_t stat() override
|
||||
fs::stat_t get_stat() override
|
||||
{
|
||||
return m_file.stat();
|
||||
return m_file.get_stat();
|
||||
}
|
||||
|
||||
bool trunc(u64) override
|
||||
@@ -2956,10 +3250,6 @@ extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<ppu_
|
||||
|
||||
const std::string firmware_sprx_path = vfs::get("/dev_flash/sys/external/");
|
||||
|
||||
// Map fixed address executables area, fake overlay support
|
||||
const bool had_ovl = !vm::map(0x3000'0000, 0x1000'0000, 0x202).operator bool();
|
||||
const u32 ppc_seg = std::exchange(g_ps3_process_info.ppc_seg, 0x3);
|
||||
|
||||
std::vector<std::pair<std::string, u64>> file_queue;
|
||||
file_queue.reserve(2000);
|
||||
|
||||
@@ -3044,7 +3334,7 @@ extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<ppu_
|
||||
}
|
||||
|
||||
// Check .self filename
|
||||
if (upper.ends_with(".SELF"))
|
||||
if (upper.ends_with(".SELF") && Emu.GetBoot() != dir_queue[i] + entry.name)
|
||||
{
|
||||
// Get full path
|
||||
file_queue.emplace_back(dir_queue[i] + entry.name, 0);
|
||||
@@ -3101,7 +3391,8 @@ extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<ppu_
|
||||
|
||||
atomic_t<usz> fnext = 0;
|
||||
|
||||
shared_mutex sprx_mtx, ovl_mtx;
|
||||
lf_queue<std::string> possible_exec_file_paths;
|
||||
shared_mutex ovl_mtx;
|
||||
|
||||
named_thread_group workers("SPRX Worker ", std::min<u32>(utils::get_thread_count(), ::size32(file_queue)), [&]
|
||||
{
|
||||
@@ -3153,17 +3444,11 @@ extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<ppu_
|
||||
|
||||
if (ppu_prx_object obj = src; (prx_err = obj, obj == elf_error::ok))
|
||||
{
|
||||
std::unique_lock lock(sprx_mtx);
|
||||
|
||||
if (auto prx = ppu_load_prx(obj, path, offset))
|
||||
if (auto prx = ppu_load_prx(obj, true, path, offset))
|
||||
{
|
||||
lock.unlock();
|
||||
obj.clear(), src.close(); // Clear decrypted file and elf object memory
|
||||
ppu_initialize(*prx);
|
||||
idm::remove<lv2_obj, lv2_prx>(idm::last_id());
|
||||
lock.lock();
|
||||
ppu_unload_prx(*prx);
|
||||
lock.unlock();
|
||||
ppu_finalize(*prx);
|
||||
continue;
|
||||
}
|
||||
@@ -3176,13 +3461,16 @@ extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<ppu_
|
||||
{
|
||||
while (ovl_err == elf_error::ok)
|
||||
{
|
||||
// Only one thread compiles OVL atm, other can compile PRX cuncurrently
|
||||
std::unique_lock lock(ovl_mtx);
|
||||
|
||||
auto [ovlm, error] = ppu_load_overlay(obj, path, offset);
|
||||
auto [ovlm, error] = ppu_load_overlay(obj, true, path, offset);
|
||||
|
||||
if (error)
|
||||
{
|
||||
if (error == CELL_CANCEL + 0u)
|
||||
{
|
||||
// Emulation stopped
|
||||
break;
|
||||
}
|
||||
|
||||
// Abort
|
||||
ovl_err = elf_error::header_type;
|
||||
break;
|
||||
@@ -3190,15 +3478,13 @@ extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<ppu_
|
||||
|
||||
obj.clear(), src.close(); // Clear decrypted file and elf object memory
|
||||
|
||||
ppu_initialize(*ovlm);
|
||||
|
||||
for (auto& seg : ovlm->segs)
|
||||
{
|
||||
vm::dealloc(seg.addr);
|
||||
// Does not really require this lock, this is done for performance reasons.
|
||||
// Seems like too many created threads is hard for Windows to manage efficiently with many CPU threads.
|
||||
std::lock_guard lock(ovl_mtx);
|
||||
ppu_initialize(*ovlm);
|
||||
}
|
||||
|
||||
lock.unlock();
|
||||
idm::remove<lv2_obj, lv2_overlay>(idm::last_id());
|
||||
ppu_finalize(*ovlm);
|
||||
break;
|
||||
}
|
||||
@@ -3209,7 +3495,8 @@ extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<ppu_
|
||||
}
|
||||
}
|
||||
|
||||
ppu_log.notice("Failed to precompile '%s' (prx: %s, ovl: %s)", path, prx_err, ovl_err);
|
||||
ppu_log.notice("Failed to precompile '%s' (prx: %s, ovl: %s): Attempting tratment as executable file", path, prx_err, ovl_err);
|
||||
possible_exec_file_paths.push(path);
|
||||
continue;
|
||||
}
|
||||
});
|
||||
@@ -3217,14 +3504,97 @@ extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<ppu_
|
||||
// Join every thread
|
||||
workers.join();
|
||||
|
||||
// Revert changes
|
||||
|
||||
if (!had_ovl)
|
||||
named_thread exec_worker("PPU Exec Worker", [&]
|
||||
{
|
||||
ensure(vm::unmap(0x3000'0000).second);
|
||||
}
|
||||
if (!possible_exec_file_paths)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
g_ps3_process_info.ppc_seg = ppc_seg;
|
||||
#ifdef __APPLE__
|
||||
pthread_jit_write_protect_np(false);
|
||||
#endif
|
||||
// Set low priority
|
||||
thread_ctrl::scoped_priority low_prio(-1);
|
||||
|
||||
auto slice = possible_exec_file_paths.pop_all();
|
||||
|
||||
auto main_module = std::move(g_fxo->get<main_ppu_module>());
|
||||
|
||||
for (; slice; slice.pop_front(), g_progr_fdone++)
|
||||
{
|
||||
g_progr_ftotal++;
|
||||
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::string path = *slice;
|
||||
|
||||
ppu_log.notice("Trying to load as executable: %s", path);
|
||||
|
||||
// Load MSELF, SPRX or SELF
|
||||
fs::file src{path};
|
||||
|
||||
if (!src)
|
||||
{
|
||||
ppu_log.error("Failed to open '%s' (%s)", path, fs::g_tls_error);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Some files may fail to decrypt due to the lack of klic
|
||||
src = decrypt_self(std::move(src));
|
||||
|
||||
if (!src)
|
||||
{
|
||||
ppu_log.notice("Failed to decrypt '%s'", path);
|
||||
continue;
|
||||
}
|
||||
|
||||
elf_error exec_err{};
|
||||
|
||||
if (ppu_exec_object obj = src; (exec_err = obj, obj == elf_error::ok))
|
||||
{
|
||||
while (exec_err == elf_error::ok)
|
||||
{
|
||||
main_ppu_module& _main = g_fxo->get<main_ppu_module>();
|
||||
_main = {};
|
||||
|
||||
if (!ppu_load_exec(obj, true, path))
|
||||
{
|
||||
// Abort
|
||||
exec_err = elf_error::header_type;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!_main.analyse(0, _main.elf_entry, _main.seg0_code_end, _main.applied_pathes, [](){ return Emu.IsStopped(); }))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
obj.clear(), src.close(); // Clear decrypted file and elf object memory
|
||||
|
||||
ppu_initialize(_main);
|
||||
ppu_finalize(_main);
|
||||
_main = {};
|
||||
break;
|
||||
}
|
||||
|
||||
if (exec_err == elf_error::ok)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
ppu_log.notice("Failed to precompile '%s' as executable (%s)", path, exec_err);
|
||||
continue;
|
||||
}
|
||||
|
||||
g_fxo->get<main_ppu_module>() = std::move(main_module);
|
||||
});
|
||||
|
||||
exec_worker();
|
||||
}
|
||||
|
||||
extern void ppu_initialize()
|
||||
@@ -3321,7 +3691,7 @@ extern void ppu_initialize()
|
||||
{
|
||||
const std::string eseibrd = mount_point + "/vsh/module/eseibrd.sprx";
|
||||
|
||||
if (auto prx = ppu_load_prx(ppu_prx_object{decrypt_self(fs::file{eseibrd})}, eseibrd, 0))
|
||||
if (auto prx = ppu_load_prx(ppu_prx_object{decrypt_self(fs::file{eseibrd})}, true, eseibrd, 0))
|
||||
{
|
||||
// Check if cache exists for this infinitesimally small prx
|
||||
dev_flash_located = ppu_initialize(*prx, true);
|
||||
@@ -3335,7 +3705,7 @@ extern void ppu_initialize()
|
||||
}
|
||||
|
||||
// Avoid compilation if main's cache exists or it is a standalone SELF with no PARAM.SFO
|
||||
if (compile_main && g_cfg.core.ppu_llvm_precompilation && !Emu.GetTitleID().empty())
|
||||
if (compile_main && g_cfg.core.ppu_llvm_precompilation && !Emu.GetTitleID().empty() && !Emu.IsChildProcess())
|
||||
{
|
||||
// Try to add all related directories
|
||||
const std::set<std::string> dirs = Emu.GetGameDirs();
|
||||
@@ -3367,24 +3737,20 @@ extern void ppu_initialize()
|
||||
}
|
||||
}
|
||||
|
||||
struct ppu_toc_manager
|
||||
{
|
||||
std::unordered_map<u32, u32> toc_map;
|
||||
|
||||
shared_mutex mutex;
|
||||
};
|
||||
|
||||
bool ppu_initialize(const ppu_module& info, bool check_only)
|
||||
{
|
||||
if (g_cfg.core.ppu_decoder != ppu_decoder_type::llvm)
|
||||
{
|
||||
if (check_only)
|
||||
if (check_only || vm::base(info.segs[0].addr) != info.segs[0].ptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Temporarily
|
||||
s_ppu_toc = &g_fxo->get<ppu_toc_manager>().toc_map;
|
||||
auto& toc_manager = g_fxo->get<ppu_toc_manager>();
|
||||
|
||||
std::lock_guard lock(toc_manager.mutex);
|
||||
|
||||
auto& ppu_toc = toc_manager.toc_map;
|
||||
|
||||
for (const auto& func : info.funcs)
|
||||
{
|
||||
@@ -3395,7 +3761,7 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
|
||||
|
||||
if (g_cfg.core.ppu_debug && func.size && func.toc != umax)
|
||||
{
|
||||
s_ppu_toc->emplace(func.addr, func.toc);
|
||||
ppu_toc[func.addr] = func.toc;
|
||||
ppu_ref(func.addr) = &ppu_check_toc;
|
||||
}
|
||||
}
|
||||
@@ -3423,6 +3789,8 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
|
||||
{ "__resupdate", reinterpret_cast<u64>(vm::reservation_update) },
|
||||
{ "__resinterp", reinterpret_cast<u64>(ppu_reservation_fallback) },
|
||||
{ "__escape", reinterpret_cast<u64>(+ppu_escape) },
|
||||
{ "__read_maybe_mmio32", reinterpret_cast<u64>(+ppu_read_mmio_aware_u32) },
|
||||
{ "__write_maybe_mmio32", reinterpret_cast<u64>(+ppu_write_mmio_aware_u32) },
|
||||
};
|
||||
|
||||
for (u64 index = 0; index < 1024; index++)
|
||||
@@ -3514,6 +3882,10 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
|
||||
|
||||
bool has_mfvscr = false;
|
||||
|
||||
const bool is_being_used_in_emulation = vm::base(info.segs[0].addr) == info.segs[0].ptr;
|
||||
|
||||
const cpu_thread* cpu = cpu_thread::get_current();
|
||||
|
||||
for (auto& func : info.funcs)
|
||||
{
|
||||
if (func.size == 0)
|
||||
@@ -3528,9 +3900,11 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
|
||||
continue;
|
||||
}
|
||||
|
||||
for (u32 i = addr; i < addr + size; i += 4)
|
||||
auto i_ptr = ensure(info.get_ptr<u32>(addr));
|
||||
|
||||
for (u32 i = addr; i < addr + size; i += 4, i_ptr++)
|
||||
{
|
||||
if (g_ppu_itype.decode(vm::read32(i)) == ppu_itype::MFVSCR)
|
||||
if (g_ppu_itype.decode(*i_ptr) == ppu_itype::MFVSCR)
|
||||
{
|
||||
ppu_log.warning("MFVSCR found");
|
||||
has_mfvscr = true;
|
||||
@@ -3553,7 +3927,7 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
|
||||
while (!jit_mod.init && fpos < info.funcs.size())
|
||||
{
|
||||
// Initialize compiler instance
|
||||
if (!jit && get_current_cpu_thread())
|
||||
if (!jit && is_being_used_in_emulation)
|
||||
{
|
||||
jit = std::make_shared<jit_compiler>(s_link_table, g_cfg.core.llvm_cpu);
|
||||
}
|
||||
@@ -3673,7 +4047,7 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
|
||||
if (roff > addr)
|
||||
{
|
||||
// Hash from addr to the beginning of the relocation
|
||||
sha1_update(&ctx, vm::_ptr<const u8>(addr), roff - addr);
|
||||
sha1_update(&ctx, ensure(info.get_ptr<const u8>(addr)), roff - addr);
|
||||
}
|
||||
|
||||
// Hash relocation type instead
|
||||
@@ -3686,9 +4060,11 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
|
||||
|
||||
if (has_dcbz == 1)
|
||||
{
|
||||
for (u32 i = addr, end = block.second + block.first - 1; i <= end; i += 4)
|
||||
auto i_ptr = ensure(info.get_ptr<u32>(addr));
|
||||
|
||||
for (u32 i = addr, end = block.second + block.first - 1; i <= end; i += 4, i_ptr++)
|
||||
{
|
||||
if (g_ppu_itype.decode(vm::read32(i)) == ppu_itype::DCBZ)
|
||||
if (g_ppu_itype.decode(*i_ptr) == ppu_itype::DCBZ)
|
||||
{
|
||||
has_dcbz = 2;
|
||||
break;
|
||||
@@ -3697,7 +4073,7 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
|
||||
}
|
||||
|
||||
// Hash from addr to the end of the block
|
||||
sha1_update(&ctx, vm::_ptr<const u8>(addr), block.second - (addr - block.first));
|
||||
sha1_update(&ctx, ensure(info.get_ptr<const u8>(addr)), block.second - (addr - block.first));
|
||||
}
|
||||
|
||||
if (reloc)
|
||||
@@ -3707,9 +4083,11 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
|
||||
|
||||
if (has_dcbz == 1)
|
||||
{
|
||||
for (u32 i = func.addr, end = func.addr + func.size - 1; i <= end; i += 4)
|
||||
auto i_ptr = ensure(info.get_ptr<u32>(func.addr));
|
||||
|
||||
for (u32 i = func.addr, end = func.addr + func.size - 1; i <= end; i += 4, i_ptr++)
|
||||
{
|
||||
if (g_ppu_itype.decode(vm::read32(i)) == ppu_itype::DCBZ)
|
||||
if (g_ppu_itype.decode(*i_ptr) == ppu_itype::DCBZ)
|
||||
{
|
||||
has_dcbz = 2;
|
||||
break;
|
||||
@@ -3717,7 +4095,7 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
|
||||
}
|
||||
}
|
||||
|
||||
sha1_update(&ctx, vm::_ptr<const u8>(func.addr), func.size);
|
||||
sha1_update(&ctx, ensure(info.get_ptr<const u8>(func.addr)), func.size);
|
||||
}
|
||||
|
||||
if (false)
|
||||
@@ -3885,7 +4263,7 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
|
||||
|
||||
g_watchdog_hold_ctr--;
|
||||
|
||||
if (Emu.IsStopped() || !get_current_cpu_thread())
|
||||
if (!is_being_used_in_emulation || (cpu ? cpu->state.all_of(cpu_flag::exit) : Emu.IsStopped()))
|
||||
{
|
||||
return compiled_new;
|
||||
}
|
||||
@@ -3898,7 +4276,7 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
|
||||
|
||||
for (auto [obj_name, is_compiled] : link_workload)
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
if (cpu ? cpu->state.all_of(cpu_flag::exit) : Emu.IsStopped())
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -3913,7 +4291,7 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
|
||||
}
|
||||
}
|
||||
|
||||
if (Emu.IsStopped() || !get_current_cpu_thread())
|
||||
if (!is_being_used_in_emulation || (cpu ? cpu->state.all_of(cpu_flag::exit) : Emu.IsStopped()))
|
||||
{
|
||||
return compiled_new;
|
||||
}
|
||||
@@ -3938,7 +4316,7 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
|
||||
ppu_register_function_at(func.addr, 4, addr);
|
||||
|
||||
if (g_cfg.core.ppu_debug)
|
||||
ppu_log.notice("Installing function %s at 0x%x: %p (reloc = 0x%x)", name, func.addr, ppu_ref(func.addr), reloc);
|
||||
ppu_log.trace("Installing function %s at 0x%x: %p (reloc = 0x%x)", name, func.addr, ppu_ref(func.addr), reloc);
|
||||
}
|
||||
|
||||
jit_mod.init = true;
|
||||
@@ -3957,7 +4335,7 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
|
||||
ppu_register_function_at(func.addr, 4, addr);
|
||||
|
||||
if (g_cfg.core.ppu_debug)
|
||||
ppu_log.notice("Reinstalling function at 0x%x: %p (reloc=0x%x)", func.addr, ppu_ref(func.addr), reloc);
|
||||
ppu_log.trace("Reinstalling function at 0x%x: %p (reloc=0x%x)", func.addr, ppu_ref(func.addr), reloc);
|
||||
}
|
||||
|
||||
index = 0;
|
||||
|
||||
@@ -22,6 +22,7 @@ enum class ppu_cmd : u32
|
||||
ptr_call, // Execute function by pointer
|
||||
opd_call, // Execute function by provided rtoc and address (unlike lle_call, does not read memory)
|
||||
cia_call, // Execute from current CIA, mo GPR modification applied
|
||||
entry_call, // Load addr and rtoc from entry_func
|
||||
initialize, // ppu_initialize()
|
||||
sleep,
|
||||
reset_stack, // resets stack address
|
||||
@@ -124,6 +125,14 @@ struct cmd64
|
||||
}
|
||||
};
|
||||
|
||||
enum class ppu_debugger_mode : u32
|
||||
{
|
||||
_default,
|
||||
is_decimal,
|
||||
|
||||
max_mode,
|
||||
};
|
||||
|
||||
class ppu_thread : public cpu_thread
|
||||
{
|
||||
public:
|
||||
@@ -132,7 +141,7 @@ public:
|
||||
static const u32 id_count = 100;
|
||||
static constexpr std::pair<u32, u32> id_invl_range = {12, 12};
|
||||
|
||||
virtual void dump_regs(std::string&) const override;
|
||||
virtual void dump_regs(std::string&, std::any& custom_data) const override;
|
||||
virtual std::string dump_callstack() const override;
|
||||
virtual std::vector<std::pair<u32, u32>> dump_callstack_list() const override;
|
||||
virtual std::string dump_misc() const override;
|
||||
@@ -299,6 +308,7 @@ public:
|
||||
u64 exec_bytes = 0; // Amount of "bytes" executed (4 for each instruction)
|
||||
|
||||
u32 dbg_step_pc = 0;
|
||||
atomic_t<ppu_debugger_mode> debugger_mode{};
|
||||
|
||||
struct call_history_t
|
||||
{
|
||||
@@ -310,6 +320,23 @@ public:
|
||||
|
||||
static constexpr u32 call_history_max_size = 4096;
|
||||
|
||||
struct syscall_history_t
|
||||
{
|
||||
struct entry_t
|
||||
{
|
||||
u64 cia;
|
||||
const char* func_name;
|
||||
u64 error;
|
||||
std::array<u64, 4> args;
|
||||
};
|
||||
|
||||
std::vector<entry_t> data;
|
||||
u64 index = 0;
|
||||
u32 count_debug_arguments;
|
||||
} syscall_history;
|
||||
|
||||
static constexpr u32 syscall_history_max_size = 2048;
|
||||
|
||||
struct hle_func_call_with_toc_info_t
|
||||
{
|
||||
u32 cia;
|
||||
@@ -339,7 +366,7 @@ public:
|
||||
|
||||
be_t<u64>* get_stack_arg(s32 i, u64 align = alignof(u64));
|
||||
void exec_task();
|
||||
void fast_call(u32 addr, u64 rtoc);
|
||||
void fast_call(u32 addr, u64 rtoc, bool is_thread_entry = false);
|
||||
|
||||
static std::pair<vm::addr_t, u32> stack_push(u32 size, u32 align_v);
|
||||
static void stack_pop_verbose(u32 addr, u32 size) noexcept;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "Emu/Cell/Common.h"
|
||||
#include "PPUTranslator.h"
|
||||
#include "PPUThread.h"
|
||||
#include "SPUThread.h"
|
||||
|
||||
#include "util/types.hpp"
|
||||
#include "util/endian.hpp"
|
||||
@@ -12,6 +13,7 @@
|
||||
#include "util/v128.hpp"
|
||||
#include "util/simd.hpp"
|
||||
#include <algorithm>
|
||||
#include <span>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
@@ -129,6 +131,7 @@ Type* PPUTranslator::GetContextType()
|
||||
}
|
||||
|
||||
u32 ppu_get_far_jump(u32 pc);
|
||||
bool ppu_test_address_may_be_mmio(std::span<const be_t<u32>> insts);
|
||||
|
||||
Function* PPUTranslator::Translate(const ppu_function& info)
|
||||
{
|
||||
@@ -150,7 +153,7 @@ Function* PPUTranslator::Translate(const ppu_function& info)
|
||||
|
||||
for (u32 addr = m_addr; addr < m_addr + info.size; addr += 4)
|
||||
{
|
||||
const u32 op = vm::read32(vm::cast(addr + base));
|
||||
const u32 op = *ensure(m_info.get_ptr<u32>(addr + base));
|
||||
|
||||
switch (g_ppu_itype.decode(op))
|
||||
{
|
||||
@@ -214,7 +217,7 @@ Function* PPUTranslator::Translate(const ppu_function& info)
|
||||
const auto block = std::make_pair(info.addr, info.size);
|
||||
{
|
||||
// Optimize BLR (prefetch LR)
|
||||
if (vm::read32(vm::cast(block.first + block.second - 4)) == ppu_instructions::BLR())
|
||||
if (*ensure(m_info.get_ptr<u32>(block.first + block.second - 4)) == ppu_instructions::BLR())
|
||||
{
|
||||
RegLoad(m_lr);
|
||||
}
|
||||
@@ -239,7 +242,10 @@ Function* PPUTranslator::Translate(const ppu_function& info)
|
||||
m_rel = nullptr;
|
||||
}
|
||||
|
||||
const u32 op = vm::read32(vm::cast(m_addr + base));
|
||||
// Reset MMIO hint
|
||||
m_may_be_mmio = true;
|
||||
|
||||
const u32 op = *ensure(m_info.get_ptr<u32>(m_addr + base));
|
||||
|
||||
(this->*(s_ppu_decoder.decode(op)))({op});
|
||||
|
||||
@@ -600,15 +606,53 @@ Value* PPUTranslator::ReadMemory(Value* addr, Type* type, bool is_be, u32 align)
|
||||
{
|
||||
const u32 size = ::narrow<u32>(+type->getPrimitiveSizeInBits());
|
||||
|
||||
if (m_may_be_mmio && size == 32)
|
||||
{
|
||||
// Test for MMIO patterns
|
||||
struct instructions_to_test
|
||||
{
|
||||
be_t<u32> insts[128];
|
||||
};
|
||||
|
||||
m_may_be_mmio = false;
|
||||
|
||||
if (auto ptr = m_info.get_ptr<instructions_to_test>(std::max<u32>(m_info.segs[0].addr, (m_reloc ? m_reloc->addr : 0) + utils::sub_saturate<u32>(m_addr, sizeof(instructions_to_test) / 2))))
|
||||
{
|
||||
if (ppu_test_address_may_be_mmio(std::span(ptr->insts)))
|
||||
{
|
||||
m_may_be_mmio = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (is_be ^ m_is_be && size > 8)
|
||||
{
|
||||
llvm::Value* value{};
|
||||
|
||||
// Read, byteswap, bitcast
|
||||
const auto int_type = m_ir->getIntNTy(size);
|
||||
const auto value = m_ir->CreateAlignedLoad(int_type, GetMemory(addr), llvm::MaybeAlign{align});
|
||||
value->setVolatile(true);
|
||||
|
||||
if (m_may_be_mmio && size == 32)
|
||||
{
|
||||
ppu_log.notice("LLVM: Detected potential MMIO32 read at [0x%08x]", m_addr + (m_reloc ? m_reloc->addr : 0));
|
||||
value = Call(GetType<u32>(), "__read_maybe_mmio32", m_base, addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto inst = m_ir->CreateAlignedLoad(int_type, GetMemory(addr), llvm::MaybeAlign{align});
|
||||
inst->setVolatile(true);
|
||||
value = inst;
|
||||
}
|
||||
|
||||
return bitcast(Call(int_type, fmt::format("llvm.bswap.i%u", size), value), type);
|
||||
}
|
||||
|
||||
if (m_may_be_mmio && size == 32)
|
||||
{
|
||||
ppu_log.notice("LLVM: Detected potential MMIO32 read at [0x%08x]", m_addr + (m_reloc ? m_reloc->addr : 0));
|
||||
return Call(GetType<u32>(), "__read_maybe_mmio32", m_base, addr);
|
||||
}
|
||||
|
||||
// Read normally
|
||||
const auto r = m_ir->CreateAlignedLoad(type, GetMemory(addr), llvm::MaybeAlign{align});
|
||||
r->setVolatile(true);
|
||||
@@ -627,6 +671,25 @@ void PPUTranslator::WriteMemory(Value* addr, Value* value, bool is_be, u32 align
|
||||
value = Call(int_type, fmt::format("llvm.bswap.i%u", size), bitcast(value, int_type));
|
||||
}
|
||||
|
||||
if (m_may_be_mmio && size == 32)
|
||||
{
|
||||
// Test for MMIO patterns
|
||||
struct instructions_to_test
|
||||
{
|
||||
be_t<u32> insts[128];
|
||||
};
|
||||
|
||||
if (auto ptr = m_info.get_ptr<instructions_to_test>(std::max<u32>(m_info.segs[0].addr, (m_reloc ? m_reloc->addr : 0) + utils::sub_saturate<u32>(m_addr, sizeof(instructions_to_test) / 2))))
|
||||
{
|
||||
if (ppu_test_address_may_be_mmio(std::span(ptr->insts)))
|
||||
{
|
||||
ppu_log.notice("LLVM: Detected potential MMIO32 write at [0x%08x]", m_addr + (m_reloc ? m_reloc->addr : 0));
|
||||
Call(GetType<void>(), "__write_maybe_mmio32", m_base, addr, value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write
|
||||
m_ir->CreateAlignedStore(value, GetMemory(addr), llvm::MaybeAlign{align})->setVolatile(true);
|
||||
}
|
||||
@@ -2527,6 +2590,7 @@ void PPUTranslator::LDX(ppu_opcode_t op)
|
||||
|
||||
void PPUTranslator::LWZX(ppu_opcode_t op)
|
||||
{
|
||||
m_may_be_mmio &= (op.ra != 1u && op.ra != 13u && op.rb != 1u && op.rb != 13u); // Stack register and TLS address register are unlikely to be used in MMIO address calculation
|
||||
SetGpr(op.rd, ReadMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), GetGpr(op.rb)) : GetGpr(op.rb), GetType<u32>()));
|
||||
}
|
||||
|
||||
@@ -2601,6 +2665,8 @@ void PPUTranslator::DCBST(ppu_opcode_t)
|
||||
|
||||
void PPUTranslator::LWZUX(ppu_opcode_t op)
|
||||
{
|
||||
m_may_be_mmio &= (op.ra != 1u && op.ra != 13u && op.rb != 1u && op.rb != 13u); // Stack register and TLS address register are unlikely to be used in MMIO address calculation
|
||||
|
||||
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), GetGpr(op.rb));
|
||||
SetGpr(op.rd, ReadMemory(addr, GetType<u32>()));
|
||||
SetGpr(op.ra, addr);
|
||||
@@ -2811,6 +2877,7 @@ void PPUTranslator::STWCX(ppu_opcode_t op)
|
||||
|
||||
void PPUTranslator::STWX(ppu_opcode_t op)
|
||||
{
|
||||
m_may_be_mmio &= (op.ra != 1u && op.ra != 13u && op.rb != 1u && op.rb != 13u); // Stack register and TLS address register are unlikely to be used in MMIO address calculation
|
||||
WriteMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), GetGpr(op.rb)) : GetGpr(op.rb), GetGpr(op.rs, 32));
|
||||
}
|
||||
|
||||
@@ -2830,6 +2897,7 @@ void PPUTranslator::STDUX(ppu_opcode_t op)
|
||||
void PPUTranslator::STWUX(ppu_opcode_t op)
|
||||
{
|
||||
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), GetGpr(op.rb));
|
||||
m_may_be_mmio &= (op.ra != 1u && op.ra != 13u && op.rb != 1u && op.rb != 13u); // Stack register and TLS address register are unlikely to be used in MMIO address calculation
|
||||
WriteMemory(addr, GetGpr(op.rs, 32));
|
||||
SetGpr(op.ra, addr);
|
||||
}
|
||||
@@ -3213,6 +3281,7 @@ void PPUTranslator::LWBRX(ppu_opcode_t op)
|
||||
|
||||
void PPUTranslator::LFSX(ppu_opcode_t op)
|
||||
{
|
||||
m_may_be_mmio &= (op.ra != 1u && op.ra != 13u && op.rb != 1u && op.rb != 13u); // Stack register and TLS address register are unlikely to be used in MMIO address calculation
|
||||
SetFpr(op.frd, ReadMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), GetGpr(op.rb)) : GetGpr(op.rb), GetType<f32>()));
|
||||
}
|
||||
|
||||
@@ -3541,6 +3610,44 @@ void PPUTranslator::LWZ(ppu_opcode_t op)
|
||||
m_rel = nullptr;
|
||||
}
|
||||
|
||||
m_may_be_mmio &= (op.ra != 1u && op.ra != 13u); // Stack register and TLS address register are unlikely to be used in MMIO address calculation
|
||||
m_may_be_mmio &= op.simm16 == 0 || spu_thread::test_is_problem_state_register_offset(op.uimm16, true, false); // Either exact MMIO address or MMIO base with completing s16 address offset
|
||||
|
||||
if (m_may_be_mmio && !op.simm16)
|
||||
{
|
||||
struct instructions_data
|
||||
{
|
||||
be_t<u32> insts[2];
|
||||
};
|
||||
|
||||
// Quick invalidation: expect exact MMIO address, so if the register is being reused with different offset than it's likely not MMIO
|
||||
if (auto ptr = m_info.get_ptr<instructions_data>(m_addr + 4 + (m_reloc ? m_reloc->addr : 0)))
|
||||
{
|
||||
for (u32 inst : ptr->insts)
|
||||
{
|
||||
ppu_opcode_t test_op{inst};
|
||||
|
||||
if (test_op.simm16 == op.simm16 || test_op.ra != op.ra)
|
||||
{
|
||||
// Same offset (at least according to this test) or different register
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (g_ppu_itype.decode(inst))
|
||||
{
|
||||
case ppu_itype::LWZ:
|
||||
case ppu_itype::STW:
|
||||
{
|
||||
// Not MMIO
|
||||
m_may_be_mmio = false;
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SetGpr(op.rd, ReadMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), imm) : imm, GetType<u32>()));
|
||||
}
|
||||
|
||||
@@ -3554,6 +3661,9 @@ void PPUTranslator::LWZU(ppu_opcode_t op)
|
||||
m_rel = nullptr;
|
||||
}
|
||||
|
||||
m_may_be_mmio &= (op.ra != 1u && op.ra != 13u); // Stack register and TLS address register are unlikely to be used in MMIO address calculation
|
||||
m_may_be_mmio &= op.simm16 == 0 || spu_thread::test_is_problem_state_register_offset(op.uimm16, true, false); // Either exact MMIO address or MMIO base with completing s16 address offset
|
||||
|
||||
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), imm);
|
||||
SetGpr(op.rd, ReadMemory(addr, GetType<u32>()));
|
||||
SetGpr(op.ra, addr);
|
||||
@@ -3597,6 +3707,44 @@ void PPUTranslator::STW(ppu_opcode_t op)
|
||||
m_rel = nullptr;
|
||||
}
|
||||
|
||||
m_may_be_mmio &= (op.ra != 1u && op.ra != 13u); // Stack register and TLS address register are unlikely to be used in MMIO address calculation
|
||||
m_may_be_mmio &= op.simm16 == 0 || spu_thread::test_is_problem_state_register_offset(op.uimm16, false, true); // Either exact MMIO address or MMIO base with completing s16 address offset
|
||||
|
||||
if (m_may_be_mmio && !op.simm16)
|
||||
{
|
||||
struct instructions_data
|
||||
{
|
||||
be_t<u32> insts[3];
|
||||
};
|
||||
|
||||
// Quick invalidation: expect exact MMIO address, so if the register is being reused with different offset than it's likely not MMIO
|
||||
if (auto ptr = m_info.get_ptr<instructions_data>(m_addr + 4 + (m_reloc ? m_reloc->addr : 0)))
|
||||
{
|
||||
for (u32 inst : ptr->insts)
|
||||
{
|
||||
ppu_opcode_t test_op{inst};
|
||||
|
||||
if (test_op.simm16 == op.simm16 || test_op.ra != op.ra)
|
||||
{
|
||||
// Same offset (at least according to this test) or different register
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (g_ppu_itype.decode(inst))
|
||||
{
|
||||
case ppu_itype::LWZ:
|
||||
case ppu_itype::STW:
|
||||
{
|
||||
// Not MMIO
|
||||
m_may_be_mmio = false;
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const auto value = GetGpr(op.rs, 32);
|
||||
const auto addr = op.ra ? m_ir->CreateAdd(GetGpr(op.ra), imm) : imm;
|
||||
WriteMemory(addr, value);
|
||||
@@ -3621,6 +3769,9 @@ void PPUTranslator::STWU(ppu_opcode_t op)
|
||||
m_rel = nullptr;
|
||||
}
|
||||
|
||||
m_may_be_mmio &= (op.ra != 1u && op.ra != 13u);// Stack register and TLS address register are unlikely to be used in MMIO address calculatio
|
||||
m_may_be_mmio &= op.simm16 == 0 || spu_thread::test_is_problem_state_register_offset(op.uimm16, false, true); // Either exact MMIO address or MMIO base with completing s16 address offset
|
||||
|
||||
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), imm);
|
||||
WriteMemory(addr, GetGpr(op.rs, 32));
|
||||
SetGpr(op.ra, addr);
|
||||
@@ -3740,6 +3891,8 @@ void PPUTranslator::STHU(ppu_opcode_t op)
|
||||
|
||||
void PPUTranslator::LMW(ppu_opcode_t op)
|
||||
{
|
||||
m_may_be_mmio &= op.rd == 31u && (op.ra != 1u && op.ra != 13u); // Stack register and TLS address register are unlikely to be used in MMIO address calculatio
|
||||
|
||||
for (u32 i = 0; i < 32 - op.rd; i++)
|
||||
{
|
||||
SetGpr(i + op.rd, ReadMemory(op.ra ? m_ir->CreateAdd(m_ir->getInt64(op.simm16 + i * 4), GetGpr(op.ra)) : m_ir->getInt64(op.simm16 + i * 4), GetType<u32>()));
|
||||
@@ -3748,6 +3901,8 @@ void PPUTranslator::LMW(ppu_opcode_t op)
|
||||
|
||||
void PPUTranslator::STMW(ppu_opcode_t op)
|
||||
{
|
||||
m_may_be_mmio &= op.rs == 31u && (op.ra != 1u && op.ra != 13u); // Stack register and TLS address register are unlikely to be used in MMIO address calculatio
|
||||
|
||||
for (u32 i = 0; i < 32 - op.rs; i++)
|
||||
{
|
||||
WriteMemory(op.ra ? m_ir->CreateAdd(m_ir->getInt64(op.simm16 + i * 4), GetGpr(op.ra)) : m_ir->getInt64(op.simm16 + i * 4), GetGpr(i + op.rs, 32));
|
||||
@@ -3764,6 +3919,9 @@ void PPUTranslator::LFS(ppu_opcode_t op)
|
||||
m_rel = nullptr;
|
||||
}
|
||||
|
||||
m_may_be_mmio &= (op.ra != 1u && op.ra != 13u); // Stack register and TLS address register are unlikely to be used in MMIO address calculatio
|
||||
m_may_be_mmio &= op.simm16 == 0 || spu_thread::test_is_problem_state_register_offset(op.uimm16, true, false); // Either exact MMIO address or MMIO base with completing s16 address offset
|
||||
|
||||
SetFpr(op.frd, ReadMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), imm) : imm, GetType<f32>()));
|
||||
}
|
||||
|
||||
@@ -3777,6 +3935,9 @@ void PPUTranslator::LFSU(ppu_opcode_t op)
|
||||
m_rel = nullptr;
|
||||
}
|
||||
|
||||
m_may_be_mmio &= (op.ra != 1u && op.ra != 13u); // Stack register and TLS address register are unlikely to be used in MMIO address calculatio
|
||||
m_may_be_mmio &= op.simm16 == 0 || spu_thread::test_is_problem_state_register_offset(op.uimm16, true, false); // Either exact MMIO address or MMIO base with completing s16 address offset
|
||||
|
||||
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), imm);
|
||||
SetFpr(op.frd, ReadMemory(addr, GetType<f32>()));
|
||||
SetGpr(op.ra, addr);
|
||||
@@ -3819,7 +3980,12 @@ void PPUTranslator::STFS(ppu_opcode_t op)
|
||||
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
|
||||
m_rel = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_may_be_mmio &= op.simm16 == 0 || spu_thread::test_is_problem_state_register_offset(op.uimm16, false, true); // Either exact MMIO address or MMIO base with completing s16 address offset
|
||||
}
|
||||
|
||||
m_may_be_mmio &= (op.ra != 1u && op.ra != 13u); // Stack register and TLS address register are unlikely to be used in MMIO address calculation
|
||||
WriteMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), imm) : imm, GetFpr(op.frs, 32));
|
||||
}
|
||||
|
||||
@@ -3832,6 +3998,12 @@ void PPUTranslator::STFSU(ppu_opcode_t op)
|
||||
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
|
||||
m_rel = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_may_be_mmio &= op.simm16 == 0 || spu_thread::test_is_problem_state_register_offset(op.uimm16, false, true); // Either exact MMIO address or MMIO base with completing s16 address offset
|
||||
}
|
||||
|
||||
m_may_be_mmio &= (op.ra != 1u && op.ra != 13u); // Stack register and TLS address register are unlikely to be used in MMIO address calculation
|
||||
|
||||
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), imm);
|
||||
WriteMemory(addr, GetFpr(op.frs, 32));
|
||||
|
||||
@@ -68,6 +68,7 @@ class PPUTranslator final : public cpu_translator
|
||||
llvm::Value** const m_fc = m_locals + 131; // FPSCR bits (used partially)
|
||||
|
||||
llvm::Value* nan_vec4;
|
||||
bool m_may_be_mmio = false;
|
||||
|
||||
#define DEF_VALUE(loc, glb, pos)\
|
||||
llvm::Value*& loc = m_locals[pos];\
|
||||
|
||||
@@ -318,6 +318,50 @@ bool spu_thread::write_reg(const u32 addr, const u32 value)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool spu_thread::test_is_problem_state_register_offset(u32 offset, bool for_read, bool for_write) noexcept
|
||||
{
|
||||
if (for_read)
|
||||
{
|
||||
switch (offset)
|
||||
{
|
||||
case MFC_CMDStatus_offs:
|
||||
case MFC_QStatus_offs:
|
||||
case SPU_Out_MBox_offs:
|
||||
case SPU_MBox_Status_offs:
|
||||
case SPU_Status_offs:
|
||||
case Prxy_TagStatus_offs:
|
||||
case SPU_NPC_offs:
|
||||
case SPU_RunCntl_offs:
|
||||
return true;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
if (for_write)
|
||||
{
|
||||
switch (offset)
|
||||
{
|
||||
case MFC_LSA_offs:
|
||||
case MFC_EAH_offs:
|
||||
case MFC_EAL_offs:
|
||||
case MFC_Size_Tag_offs:
|
||||
case MFC_Class_CMD_offs:
|
||||
case Prxy_QueryType_offs:
|
||||
case Prxy_QueryMask_offs:
|
||||
case SPU_In_MBox_offs:
|
||||
case SPU_RunCntl_offs:
|
||||
case SPU_NPC_offs:
|
||||
case SPU_RdSigNotify1_offs:
|
||||
case SPU_RdSigNotify2_offs:
|
||||
case (SPU_RdSigNotify2_offs & 0xffff): // Fow now accept both (this is used for an optimization so it can be imperfect)
|
||||
return true;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void spu_load_exec(const spu_exec_object& elf)
|
||||
{
|
||||
spu_thread::g_raw_spu_ctr++;
|
||||
|
||||
@@ -1551,7 +1551,8 @@ spu_function_t spu_runtime::rebuild_ubertrampoline(u32 id_inst)
|
||||
|
||||
spu_function_t spu_runtime::find(const u32* ls, u32 addr) const
|
||||
{
|
||||
for (auto& item : ::at32(m_stuff, ls[addr / 4] >> 12))
|
||||
const u32 index = ls[addr / 4] >> 12;
|
||||
for (const auto& item : ::at32(m_stuff, index))
|
||||
{
|
||||
if (const auto ptr = item.compiled.load())
|
||||
{
|
||||
@@ -3846,16 +3847,24 @@ void spu_recompiler_base::dump(const spu_program& result, std::string& out)
|
||||
fmt::append(hash, "%s", fmt::base57(output));
|
||||
}
|
||||
|
||||
fmt::append(out, "========== SPU BLOCK 0x%05x (size %u, %s) ==========\n", result.entry_point, result.data.size(), hash);
|
||||
fmt::append(out, "========== SPU BLOCK 0x%05x (size %u, %s) ==========\n\n", result.entry_point, result.data.size(), hash);
|
||||
|
||||
for (auto& bb : m_bbs)
|
||||
{
|
||||
for (u32 pos = bb.first, end = bb.first + bb.second.size * 4; pos < end; pos += 4)
|
||||
{
|
||||
dis_asm.disasm(pos);
|
||||
fmt::append(out, ">%s\n", dis_asm.last_opcode);
|
||||
|
||||
if (!dis_asm.last_opcode.ends_with('\n'))
|
||||
{
|
||||
dis_asm.last_opcode += '\n';
|
||||
}
|
||||
|
||||
fmt::append(out, ">%s", dis_asm.last_opcode);
|
||||
}
|
||||
|
||||
out += '\n';
|
||||
|
||||
if (m_block_info[bb.first / 4])
|
||||
{
|
||||
fmt::append(out, "A: [0x%05x] %s\n", bb.first, m_entry_info[bb.first / 4] ? (m_ret_info[bb.first / 4] ? "Chunk" : "Entry") : "Block");
|
||||
@@ -5822,7 +5831,7 @@ public:
|
||||
if (g_cfg.core.spu_debug)
|
||||
{
|
||||
out.flush();
|
||||
fs::file(m_spurt->get_cache_path() + "spu-ir.log", fs::write + fs::append).write(log);
|
||||
fs::write_file(m_spurt->get_cache_path() + "spu-ir.log", fs::create + fs::write + fs::append, log);
|
||||
}
|
||||
|
||||
#if defined(__APPLE__)
|
||||
@@ -6240,7 +6249,7 @@ public:
|
||||
|
||||
if (g_cfg.core.spu_debug)
|
||||
{
|
||||
fs::file(m_spurt->get_cache_path() + "spu-ir.log", fs::write + fs::append).write(log);
|
||||
fs::write_file(m_spurt->get_cache_path() + "spu-ir.log", fs::create + fs::write + fs::append, log);
|
||||
}
|
||||
|
||||
fmt::throw_exception("Compilation failed");
|
||||
@@ -6275,7 +6284,7 @@ public:
|
||||
if (g_cfg.core.spu_debug)
|
||||
{
|
||||
out.flush();
|
||||
fs::file(m_spurt->get_cache_path() + "spu-ir.log", fs::write + fs::append).write(log);
|
||||
fs::write_file(m_spurt->get_cache_path() + "spu-ir.log", fs::create + fs::write + fs::append, log);
|
||||
}
|
||||
|
||||
return spu_runtime::g_interpreter;
|
||||
@@ -6811,7 +6820,7 @@ public:
|
||||
}
|
||||
case MFC_Size:
|
||||
{
|
||||
set_reg_fixed(s_reg_mfc_size, trunc<u16>(val & 0x7fff).eval(m_ir));
|
||||
set_reg_fixed(s_reg_mfc_size, trunc<u16>(val).eval(m_ir));
|
||||
return;
|
||||
}
|
||||
case MFC_TagID:
|
||||
@@ -7779,19 +7788,27 @@ public:
|
||||
void ROTQMBY(spu_opcode_t op)
|
||||
{
|
||||
const auto a = get_vr<u8[16]>(op.ra);
|
||||
const auto b = get_vr<u8[16]>(op.rb);
|
||||
const auto b = get_vr<u32[4]>(op.rb);
|
||||
|
||||
auto minusb = eval(-b);
|
||||
if (auto [ok, x] = match_expr(b, -match<u32[4]>()); ok)
|
||||
{
|
||||
minusb = eval(x);
|
||||
}
|
||||
|
||||
const auto minusbx = bitcast<u8[16]>(minusb);
|
||||
|
||||
// Data with swapped endian from a load instruction
|
||||
if (auto [ok, as] = match_expr(a, byteswap(match<u8[16]>())); ok)
|
||||
{
|
||||
const auto sc = build<u8[16]>(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0);
|
||||
const auto sh = sc - (-splat_scalar(b) & 0x1f);
|
||||
const auto sh = sc - (splat_scalar(minusbx) & 0x1f);
|
||||
set_vr(op.rt, pshufb(as, sh));
|
||||
return;
|
||||
}
|
||||
|
||||
const auto sc = build<u8[16]>(112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127);
|
||||
const auto sh = sc + (-splat_scalar(b) & 0x1f);
|
||||
const auto sh = sc + (splat_scalar(minusbx) & 0x1f);
|
||||
set_vr(op.rt, pshufb(a, sh));
|
||||
}
|
||||
|
||||
@@ -8571,8 +8588,13 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
// (TODO: implement via known-bits-lookup) Check whether shuffle mask doesn't contain fixed value selectors
|
||||
const auto [perm_only, dummy1] = match_expr(c, match<u8[16]>() & 31);
|
||||
// Check whether shuffle mask doesn't contain fixed value selectors
|
||||
bool perm_only = false;
|
||||
|
||||
if (auto k = get_known_bits(c); !!(k.Zero & 0x80))
|
||||
{
|
||||
perm_only = true;
|
||||
}
|
||||
|
||||
const auto a = get_vr<u8[16]>(op.ra);
|
||||
const auto b = get_vr<u8[16]>(op.rb);
|
||||
@@ -8598,7 +8620,7 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
const auto x = avg(noncast<u8[16]>(sext<s8[16]>((c & 0xc0) == 0xc0)), noncast<u8[16]>(sext<s8[16]>((c & 0xe0) == 0xc0)));
|
||||
const auto x = pshufb(build<u8[16]>(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x80, 0x80), (c >> 4));
|
||||
const auto ax = pshufb(as, c);
|
||||
const auto bx = pshufb(bs, c);
|
||||
|
||||
@@ -8614,7 +8636,7 @@ public:
|
||||
if (data == v128::from8p(data._u8[0]))
|
||||
{
|
||||
// See above
|
||||
const auto x = avg(noncast<u8[16]>(sext<s8[16]>((c & 0xc0) == 0xc0)), noncast<u8[16]>(sext<s8[16]>((c & 0xe0) == 0xc0)));
|
||||
const auto x = pshufb(build<u8[16]>(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x80, 0x80), (c >> 4));
|
||||
const auto ax = pshufb(as, c);
|
||||
|
||||
if (perm_only)
|
||||
@@ -8633,7 +8655,7 @@ public:
|
||||
if (data == v128::from8p(data._u8[0]))
|
||||
{
|
||||
// See above
|
||||
const auto x = avg(noncast<u8[16]>(sext<s8[16]>((c & 0xc0) == 0xc0)), noncast<u8[16]>(sext<s8[16]>((c & 0xe0) == 0xc0)));
|
||||
const auto x = pshufb(build<u8[16]>(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x80, 0x80), (c >> 4));
|
||||
const auto bx = pshufb(bs, c);
|
||||
|
||||
if (perm_only)
|
||||
@@ -8661,7 +8683,7 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
const auto x = avg(noncast<u8[16]>(sext<s8[16]>((c & 0xc0) == 0xc0)), noncast<u8[16]>(sext<s8[16]>((c & 0xe0) == 0xc0)));
|
||||
const auto x = pshufb(build<u8[16]>(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x80, 0x80), (c >> 4));
|
||||
const auto cr = eval(c ^ 0xf);
|
||||
const auto ax = pshufb(a, cr);
|
||||
const auto bx = pshufb(b, cr);
|
||||
@@ -9849,6 +9871,15 @@ public:
|
||||
a = eval(a * s);
|
||||
|
||||
value_t<s32[4]> r;
|
||||
|
||||
if (m_use_avx512)
|
||||
{
|
||||
const auto sc = clamp_smax(a);
|
||||
r.value = m_ir->CreateFPToUI(sc.value, get_type<s32[4]>());
|
||||
set_vr(op.rt, r);
|
||||
return;
|
||||
}
|
||||
|
||||
r.value = m_ir->CreateFPToUI(a.value, get_type<s32[4]>());
|
||||
set_vr(op.rt, select(bitcast<s32[4]>(a) > splat<s32[4]>(((32 + 127) << 23) - 1), splat<s32[4]>(-1), r & ~(bitcast<s32[4]>(a) >> 31)));
|
||||
}
|
||||
@@ -11237,7 +11268,7 @@ struct spu_fast : public spu_recompiler_base
|
||||
{
|
||||
std::string log;
|
||||
this->dump(func, log);
|
||||
fs::file(m_spurt->get_cache_path() + "spu.log", fs::write + fs::append).write(log);
|
||||
fs::write_file(m_spurt->get_cache_path() + "spu.log", fs::create + fs::write + fs::append, log);
|
||||
}
|
||||
|
||||
// Allocate executable area with necessary size
|
||||
|
||||
@@ -326,6 +326,29 @@ extern thread_local u64 g_tls_fault_spu;
|
||||
|
||||
const spu_decoder<spu_itype> s_spu_itype;
|
||||
|
||||
namespace vm
|
||||
{
|
||||
extern atomic_t<u64, 64> g_range_lock_set[64];
|
||||
|
||||
// Defined here for performance reasons
|
||||
writer_lock::~writer_lock() noexcept
|
||||
{
|
||||
if (range_lock)
|
||||
{
|
||||
if (!*range_lock)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
g_range_lock_bits[1] &= ~(1ull << (range_lock - g_range_lock_set));
|
||||
range_lock->release(0);
|
||||
return;
|
||||
}
|
||||
|
||||
g_range_lock_bits[1].release(0);
|
||||
}
|
||||
}
|
||||
|
||||
namespace spu
|
||||
{
|
||||
namespace scheduler
|
||||
@@ -1017,9 +1040,14 @@ spu_imm_table_t::spu_imm_table_t()
|
||||
}
|
||||
}
|
||||
|
||||
void spu_thread::dump_regs(std::string& ret) const
|
||||
void spu_thread::dump_regs(std::string& ret, std::any& /*custom_data*/) const
|
||||
{
|
||||
const bool floats_only = debugger_float_mode.load();
|
||||
const system_state emu_state = Emu.GetStatus(false);
|
||||
const bool is_stopped_or_frozen = state & cpu_flag::exit || emu_state == system_state::frozen || emu_state <= system_state::stopping;
|
||||
const spu_debugger_mode mode = debugger_mode.load();
|
||||
|
||||
const bool floats_only = !is_stopped_or_frozen && mode == spu_debugger_mode::is_float;
|
||||
const bool is_decimal = !is_stopped_or_frozen && mode == spu_debugger_mode::is_decimal;
|
||||
|
||||
SPUDisAsm dis_asm(cpu_disasm_mode::normal, ls);
|
||||
|
||||
@@ -1097,12 +1125,26 @@ void spu_thread::dump_regs(std::string& ret) const
|
||||
if (!printed_error)
|
||||
{
|
||||
// Shortand formatting
|
||||
fmt::append(ret, "%08x", i3);
|
||||
if (is_decimal)
|
||||
{
|
||||
fmt::append(ret, "%-11d", i3);
|
||||
}
|
||||
else
|
||||
{
|
||||
fmt::append(ret, "%08x", i3);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fmt::append(ret, "%08x %08x %08x %08x", r.u32r[0], r.u32r[1], r.u32r[2], r.u32r[3]);
|
||||
if (is_decimal)
|
||||
{
|
||||
fmt::append(ret, "%-11d %-11d %-11d %-11d", r.u32r[0], r.u32r[1], r.u32r[2], r.u32r[3]);
|
||||
}
|
||||
else
|
||||
{
|
||||
fmt::append(ret, "%08x %08x %08x %08x", r.u32r[0], r.u32r[1], r.u32r[2], r.u32r[3]);
|
||||
}
|
||||
}
|
||||
|
||||
if (i3 >= 0x80 && is_exec_code(i3, ls))
|
||||
@@ -1143,6 +1185,17 @@ void spu_thread::dump_regs(std::string& ret) const
|
||||
fmt::append(ret, "SNR1: %s\n", ch_snr1);
|
||||
fmt::append(ret, "SNR2: %s\n", ch_snr2);
|
||||
|
||||
if (get_type() != spu_type::threaded)
|
||||
{
|
||||
for (usz i = 0; i < int_ctrl.size(); i++)
|
||||
{
|
||||
fmt::append(ret, "Int Ctrl[%u]: stat=0x%x, mask=0x%x\n", i, +int_ctrl[i].stat, +int_ctrl[i].mask);
|
||||
}
|
||||
|
||||
fmt::append(ret, "MFC Prxy Cmd: [%s written: %x]\n", mfc_prxy_cmd, mfc_prxy_write_state.all);
|
||||
fmt::append(ret, "MFC Prxy Mask: 0x%x\n", +mfc_prxy_mask);
|
||||
}
|
||||
|
||||
const u32 addr = raddr;
|
||||
|
||||
fmt::append(ret, "Reservation Addr: %s\n", addr ? fmt::format("0x%x", addr) : "N/A");
|
||||
@@ -1200,26 +1253,7 @@ std::vector<std::pair<u32, u32>> spu_thread::dump_callstack_list() const
|
||||
return !addr || !is_exec_code(addr, ls);
|
||||
};
|
||||
|
||||
if (is_invalid(lr))
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
// Function hasn't saved LR, could be because it's a leaf function
|
||||
// Use LR directly instead
|
||||
lr = gpr0;
|
||||
|
||||
if (is_invalid(lr))
|
||||
{
|
||||
// Skip it, workaround
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (first && lr._u32[3] != gpr0._u32[3] && !is_invalid(gpr0))
|
||||
if (first && lr._u32[3] != gpr0._u32[3] && !is_invalid(gpr0))
|
||||
{
|
||||
// Detect functions with no stack or before LR has been stored
|
||||
std::vector<bool> passed(SPU_LS_SIZE / 4);
|
||||
@@ -1308,8 +1342,15 @@ std::vector<std::pair<u32, u32>> spu_thread::dump_callstack_list() const
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: function addresses too
|
||||
call_stack_list.emplace_back(lr._u32[3], sp);
|
||||
if (!is_invalid(lr))
|
||||
{
|
||||
// TODO: function addresses too
|
||||
call_stack_list.emplace_back(lr._u32[3], sp);
|
||||
}
|
||||
else if (!first)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
const u32 temp_sp = _ref<u32>(sp);
|
||||
|
||||
@@ -1767,11 +1808,8 @@ void spu_thread::cleanup()
|
||||
// Free range lock (and signals cleanup was called to the destructor)
|
||||
vm::free_range_lock(range_lock);
|
||||
|
||||
// Signal the debugger about the termination
|
||||
if (!state.test_and_set(cpu_flag::exit))
|
||||
{
|
||||
state.notify_one();
|
||||
}
|
||||
// Terminate and join thread
|
||||
static_cast<named_thread<spu_thread>&>(*this) = thread_state::finished;
|
||||
}
|
||||
|
||||
spu_thread::~spu_thread()
|
||||
@@ -1783,7 +1821,7 @@ spu_thread::~spu_thread()
|
||||
utils::memory_release(ls - SPU_LS_SIZE * 2, SPU_LS_SIZE * 5);
|
||||
|
||||
perf_log.notice("Perf stats for transactions: success %u, failure %u", stx, ftx);
|
||||
perf_log.notice("Perf stats for PUTLLC reload: successs %u, failure %u", last_succ, last_fail);
|
||||
perf_log.notice("Perf stats for PUTLLC reload: success %u, failure %u", last_succ, last_fail);
|
||||
}
|
||||
|
||||
u8* spu_thread::map_ls(utils::shm& shm, void* ptr)
|
||||
@@ -3533,19 +3571,18 @@ bool spu_thread::do_putllc(const spu_mfc_cmd& args)
|
||||
{
|
||||
// Full lock (heavyweight)
|
||||
// TODO: vm::check_addr
|
||||
vm::writer_lock lock(addr);
|
||||
vm::writer_lock lock(addr, range_lock);
|
||||
|
||||
if (cmp_rdata(rdata, super_data))
|
||||
{
|
||||
mov_rdata(super_data, to_write);
|
||||
res += 64;
|
||||
return true;
|
||||
}
|
||||
|
||||
res -= 64;
|
||||
return false;
|
||||
}();
|
||||
|
||||
res += success ? 64 : 0 - 64;
|
||||
return success;
|
||||
}())
|
||||
{
|
||||
@@ -3680,7 +3717,8 @@ void do_cell_atomic_128_store(u32 addr, const void* to_write)
|
||||
vm::_ref<atomic_t<u32>>(addr) += 0;
|
||||
|
||||
// Hard lock
|
||||
vm::writer_lock lock(addr);
|
||||
auto spu = cpu ? cpu->try_get<spu_thread>() : nullptr;
|
||||
vm::writer_lock lock(addr, spu ? spu->range_lock : nullptr);
|
||||
mov_rdata(sdata, *static_cast<const spu_rdata_t*>(to_write));
|
||||
vm::reservation_acquire(addr) += 32;
|
||||
}
|
||||
@@ -4446,7 +4484,7 @@ bool spu_thread::reservation_check(u32 addr, const decltype(rdata)& data) const
|
||||
// Set range_lock first optimistically
|
||||
range_lock->store(u64{128} << 32 | addr);
|
||||
|
||||
u64 lock_val = vm::g_range_lock;
|
||||
u64 lock_val = *std::prev(std::end(vm::g_range_lock_set));
|
||||
u64 old_lock = 0;
|
||||
|
||||
while (lock_val != old_lock)
|
||||
@@ -4501,7 +4539,7 @@ bool spu_thread::reservation_check(u32 addr, const decltype(rdata)& data) const
|
||||
break;
|
||||
}
|
||||
|
||||
old_lock = std::exchange(lock_val, vm::g_range_lock);
|
||||
old_lock = std::exchange(lock_val, *std::prev(std::end(vm::g_range_lock_set)));
|
||||
}
|
||||
|
||||
if (!range_lock->load()) [[unlikely]]
|
||||
@@ -4604,9 +4642,9 @@ void spu_thread::set_interrupt_status(bool enable)
|
||||
// Detect enabling interrupts with events masked
|
||||
if (auto mask = ch_events.load().mask; mask & SPU_EVENT_INTR_BUSY_CHECK)
|
||||
{
|
||||
if (g_cfg.core.spu_decoder != spu_decoder_type::_static)
|
||||
if (g_cfg.core.spu_decoder != spu_decoder_type::_static && g_cfg.core.spu_decoder != spu_decoder_type::dynamic)
|
||||
{
|
||||
fmt::throw_exception("SPU Interrupts not implemented (mask=0x%x): Use static interpreter", mask);
|
||||
fmt::throw_exception("SPU Interrupts not implemented (mask=0x%x): Use [%s] SPU decoder", mask, spu_decoder_type::dynamic);
|
||||
}
|
||||
|
||||
spu_log.trace("SPU Interrupts (mask=0x%x) are using CPU busy checking mode", mask);
|
||||
@@ -5282,7 +5320,7 @@ bool spu_thread::set_ch_value(u32 ch, u32 value)
|
||||
|
||||
case MFC_Size:
|
||||
{
|
||||
ch_mfc_cmd.size = value & 0x7fff;
|
||||
ch_mfc_cmd.size = static_cast<u16>(std::min<u32>(value, 0xffff));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -608,10 +608,19 @@ struct spu_memory_segment_dump_data
|
||||
u32 flags = umax;
|
||||
};
|
||||
|
||||
enum class spu_debugger_mode : u32
|
||||
{
|
||||
_default,
|
||||
is_float,
|
||||
is_decimal,
|
||||
|
||||
max_mode,
|
||||
};
|
||||
|
||||
class spu_thread : public cpu_thread
|
||||
{
|
||||
public:
|
||||
virtual void dump_regs(std::string&) const override;
|
||||
virtual void dump_regs(std::string&, std::any& custom_data) const override;
|
||||
virtual std::string dump_callstack() const override;
|
||||
virtual std::vector<std::pair<u32, u32>> dump_callstack_list() const override;
|
||||
virtual std::string dump_misc() const override;
|
||||
@@ -782,7 +791,7 @@ public:
|
||||
|
||||
std::vector<mfc_cmd_dump> mfc_history;
|
||||
u64 mfc_dump_idx = 0;
|
||||
static constexpr u32 max_mfc_dump_idx = 2048;
|
||||
static constexpr u32 max_mfc_dump_idx = 4096;
|
||||
|
||||
bool in_cpu_work = false;
|
||||
bool allow_interrupts_in_cpu_work = false;
|
||||
@@ -794,7 +803,7 @@ public:
|
||||
u64 start_time{}; // Starting time of STOP or RDCH bloking function
|
||||
bool unsavable = false; // Flag indicating whether saving the spu thread state is currently unsafe
|
||||
|
||||
atomic_t<u8> debugger_float_mode = 0;
|
||||
atomic_t<spu_debugger_mode> debugger_mode{};
|
||||
|
||||
// PC-based breakpoint list
|
||||
std::array<atomic_t<bool>, SPU_LS_SIZE / 4> local_breakpoints{};
|
||||
@@ -865,6 +874,7 @@ public:
|
||||
|
||||
bool read_reg(const u32 addr, u32& value);
|
||||
bool write_reg(const u32 addr, const u32 value);
|
||||
static bool test_is_problem_state_register_offset(u32 offset, bool for_read, bool for_write) noexcept;
|
||||
|
||||
static atomic_t<u32> g_raw_spu_ctr;
|
||||
static atomic_t<u32> g_raw_spu_id[5];
|
||||
|
||||
@@ -84,6 +84,12 @@ void fmt_class_string<lv2_protocol>::format(std::string& out, u64 arg)
|
||||
});
|
||||
}
|
||||
|
||||
template <>
|
||||
void fmt_class_string<lv2_obj::name_64>::format(std::string& out, u64 arg)
|
||||
{
|
||||
out += lv2_obj::name64(get_object(arg).data);
|
||||
}
|
||||
|
||||
static void null_func_(ppu_thread& ppu, ppu_opcode_t, be_t<u32>* this_op, ppu_intrp_func*)
|
||||
{
|
||||
ppu_log.todo("Unimplemented syscall %s -> CELL_OK (r3=0x%llx, r4=0x%llx, r5=0x%llx, r6=0x%llx, r7=0x%llx, r8=0x%llx, r9=0x%llx, r10=0x%llx)", ppu_syscall_code(ppu.gpr[11]),
|
||||
@@ -576,7 +582,7 @@ const std::array<std::pair<ppu_intrp_func_t, std::string_view>, 1024> g_ppu_sysc
|
||||
null_func,//BIND_SYSC(sys_usbd_...), //555 (0x22B)
|
||||
BIND_SYSC(sys_usbd_get_device_speed), //556 (0x22C)
|
||||
null_func,//BIND_SYSC(sys_usbd_...), //557 (0x22D)
|
||||
null_func,//BIND_SYSC(sys_usbd_...), //558 (0x22E)
|
||||
BIND_SYSC(sys_usbd_unregister_extra_ldd), //558 (0x22E)
|
||||
BIND_SYSC(sys_usbd_register_extra_ldd), //559 (0x22F)
|
||||
null_func,//BIND_SYSC(sys_...), //560 (0x230) ROOT
|
||||
null_func,//BIND_SYSC(sys_...), //561 (0x231) ROOT
|
||||
@@ -1123,7 +1129,7 @@ public:
|
||||
|
||||
if (!m_stats.empty())
|
||||
{
|
||||
ppu_log.notice("PPU Syscall Usage Stats: %s", m_stats);
|
||||
ppu_log.notice("PPU Syscall Usage Stats:%s", m_stats);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1231,6 +1237,18 @@ namespace cpu_counter
|
||||
void remove(cpu_thread*) noexcept;
|
||||
}
|
||||
|
||||
std::string lv2_obj::name64(u64 name_u64)
|
||||
{
|
||||
const auto ptr = reinterpret_cast<const char*>(&name_u64);
|
||||
|
||||
// NTS string, ignore invalid/newline characters
|
||||
// Example: "lv2\n\0tx" will be printed as "lv2"
|
||||
std::string str{ptr, std::find(ptr, ptr + 7, '\0')};
|
||||
str.erase(std::remove_if(str.begin(), str.end(), [](uchar c){ return !std::isprint(c); }), str.end());
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
bool lv2_obj::sleep(cpu_thread& cpu, const u64 timeout)
|
||||
{
|
||||
// Should already be performed when using this flag
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user