Compare commits

..
2 Commits
Author SHA1 Message Date
Elad 4f37124c1d LLVM: Add short fallback for get_known_bits
Supports: when value is the immediate result of either a bitwise OR operation or a bitwise AND when either operands is a constant.

Prevents some false positives when the value has PHI nodes in its ancestors.
2026-07-21 18:42:57 +03:00
RipleyTom 24e1ce4ceb Fix: get_known_bits fix 2026-07-21 17:44:40 +03:00
648 changed files with 15748 additions and 38077 deletions
+25 -10
View File
@@ -9,12 +9,23 @@ AVVER="${COMM_TAG}-${COMM_COUNT}"
export LVER="${COMM_TAG}-${COMM_COUNT}-${COMM_HASH}"
echo "AVVER=$AVVER" >> .ci/ci-vars.env
# Clang depends on LLVM_COMPILER_VER so it needs to be installed here.
sudo port install "clang-$LLVM_COMPILER_VER"
export HOMEBREW_NO_AUTO_UPDATE=1
export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1
export HOMEBREW_NO_ENV_HINTS=1
export HOMEBREW_NO_INSTALL_CLEANUP=1
brew install -f --overwrite --quiet ccache "llvm@$LLVM_COMPILER_VER"
brew link -f --overwrite --quiet "llvm@$LLVM_COMPILER_VER"
brew install -f --overwrite --quiet googletest opencv@4 sdl3 vulkan-headers vulkan-loader molten-vk
brew unlink --quiet ffmpeg fmt qtbase qtsvg qtdeclarative protobuf || true
export CXX=clang++
export CC=clang
export BREW_PATH;
BREW_PATH="$(brew --prefix)"
export BREW_BIN="$BREW_PATH/bin"
export BREW_SBIN="$BREW_PATH/sbin"
export WORKDIR;
WORKDIR="$(pwd)"
@@ -42,16 +53,20 @@ 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 SDL3_DIR="/opt/local/lib/cmake/SDL3"
export OpenCV_DIR="/opt/local/libexec/opencv4"
export PATH="/opt/local/libexec/llvm-$LLVM_COMPILER_VER/bin:/$WORKDIR/qt-downloader/$QT_VER/clang_64/bin:/opt/local/bin:/opt/local/sbin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/Library/Apple/usr/bin:$PATH"
export LDFLAGS="-L/opt/local/lib -Wl,-rpath,/opt/local/lib"
export VULKAN_SDK="/opt/local"
export LLVM_DIR="/opt/local/libexec/llvm-$LLVM_COMPILER_VER"
export SDL3_DIR="$BREW_PATH/opt/sdl3/lib/cmake/SDL3"
export PATH="$BREW_PATH/opt/llvm@$LLVM_COMPILER_VER/bin:$PATH"
export LDFLAGS="-L$BREW_PATH/opt/llvm@$LLVM_COMPILER_VER/lib/c++ -L$BREW_PATH/opt/llvm@$LLVM_COMPILER_VER/lib/unwind -lunwind"
export VULKAN_SDK
VULKAN_SDK="$BREW_PATH/opt/molten-vk"
ln -s "$BREW_PATH/opt/vulkan-loader/lib/libvulkan.dylib" "$VULKAN_SDK/lib/libvulkan.dylib"
export LLVM_DIR
LLVM_DIR="$BREW_PATH/opt/llvm@$LLVM_COMPILER_VER"
# Pull all the submodules except some
# shellcheck disable=SC2046
git submodule -q update --init --depth=1 --jobs=8 $(awk '/path/ && !/llvm/ && !/opencv/ && !/libsdl-org/ && !/feralinteractive/ && !/curl/ && !/zlib/ { print $3 }' .gitmodules)
git submodule -q update --init --depth=1 --jobs=8 $(awk '/path/ && !/llvm/ && !/opencv/ && !/SDL/ && !/feralinteractive/ { print $3 }' .gitmodules)
mkdir build && cd build || exit 1
# The below should be uncommented once bugs with Qt 6 QListWidgets when using the OS 26 visual style are resolved.
@@ -76,7 +91,7 @@ cmake .. \
-DUSE_SYSTEM_OPENCV=ON \
-G Ninja
ninja; build_status=$?;
ninja -j4; build_status=$?;
cd ..
+2 -2
View File
@@ -37,7 +37,7 @@ if [ "$DEPLOY_APPIMAGE" = "true" ]; then
# Download translations
mkdir -p "./AppDir/usr/translations"
ZIP_URL=$(curl -fsSL --retry 3 --retry-delay 60 "https://api.github.com/repos/RPCS3/rpcs3_translations/releases/latest" \
ZIP_URL=$(curl -fsSL "https://api.github.com/repos/RPCS3/rpcs3_translations/releases/latest" \
| grep "browser_download_url" \
| grep "RPCS3-languages.zip" \
| cut -d '"' -f 4)
@@ -45,7 +45,7 @@ if [ "$DEPLOY_APPIMAGE" = "true" ]; then
echo "Failed to find RPCS3-languages.zip in the latest release. Continuing without translations."
else
echo "Downloading translations from: $ZIP_URL"
curl -fsSL --retry 3 --retry-delay 60 -o translations.zip "$ZIP_URL" || {
curl -L -o translations.zip "$ZIP_URL" || {
echo "Failed to download translations.zip. Continuing without translations."
exit 0
}
+31 -8
View File
@@ -5,12 +5,15 @@ cd build || exit 1
cd bin
mkdir -p "rpcs3.app/Contents/Resources/vulkan/icd.d" || true
wget https://github.com/KhronosGroup/MoltenVK/releases/download/v1.4.2/MoltenVK-macos-privateapi.tar
wget https://github.com/KhronosGroup/MoltenVK/releases/download/v1.4.2-rc1/MoltenVK-macos-privateapi.tar
tar -xvf MoltenVK-macos-privateapi.tar
cp "MoltenVK/MoltenVK/dynamic/dylib/macOS/libMoltenVK.dylib" "rpcs3.app/Contents/Frameworks/libMoltenVK.dylib"
cp "MoltenVK/MoltenVK/dynamic/dylib/macOS/MoltenVK_icd.json" "rpcs3.app/Contents/Resources/vulkan/icd.d/MoltenVK_icd.json"
sed -i '' "s/.\//..\/..\/..\/Frameworks\//g" "rpcs3.app/Contents/Resources/vulkan/icd.d/MoltenVK_icd.json"
cp "$(realpath $BREW_PATH/opt/llvm@$LLVM_COMPILER_VER/lib/c++/libc++abi.1.0.dylib)" "rpcs3.app/Contents/Frameworks/libc++abi.1.dylib"
cp "$(realpath $BREW_PATH/opt/gcc/lib/gcc/current/libgcc_s.1.1.dylib)" "rpcs3.app/Contents/Frameworks/libgcc_s.1.1.dylib"
rm -rf "rpcs3.app/Contents/Frameworks/QtPdf.framework" \
"rpcs3.app/Contents/Frameworks/QtQml.framework" \
"rpcs3.app/Contents/Frameworks/QtQmlModels.framework" \
@@ -23,12 +26,12 @@ rm -rf "rpcs3.app/Contents/Frameworks/QtPdf.framework" \
../../.ci/optimize-mac.sh rpcs3.app
# Download translations
mkdir -p "rpcs3.app/Contents/Resources/translations"
mkdir -p "rpcs3.app/Contents/translations"
ZIP_URL="https://github.com/RPCS3/rpcs3_translations/releases/latest/download/RPCS3-languages.zip"
echo "Downloading translations from: $ZIP_URL"
if curl -fsSL --retry 3 --retry-delay 60 "$ZIP_URL" -o "translations.zip"; then
if curl -fsSL "$ZIP_URL" -o "translations.zip"; then
echo "Successfully downloaded translations."
if unzip -o translations.zip -d "rpcs3.app/Contents/Resources/translations" >/dev/null 2>&1; then
if unzip -o translations.zip -d "rpcs3.app/Contents/translations" >/dev/null 2>&1; then
rm -f translations.zip
else
echo "Failed to extract translations.zip. Continuing without translations."
@@ -40,15 +43,35 @@ fi
# Copy Qt translations manually
QT_TRANS="$WORKDIR/qt-downloader/$QT_VER/clang_64/translations"
cp $QT_TRANS/qt_*.qm rpcs3.app/Contents/Resources/translations
cp $QT_TRANS/qtbase_*.qm rpcs3.app/Contents/Resources/translations
cp $QT_TRANS/qtmultimedia_*.qm rpcs3.app/Contents/Resources/translations
rm -f rpcs3.app/Contents/Resources/translations/qt_help_*.qm || true
cp $QT_TRANS/qt_*.qm rpcs3.app/Contents/translations
cp $QT_TRANS/qtbase_*.qm rpcs3.app/Contents/translations
cp $QT_TRANS/qtmultimedia_*.qm rpcs3.app/Contents/translations
rm -f rpcs3.app/Contents/translations/qt_help_*.qm || true
# Need to do this rename hack due to case insensitive filesystem
mv rpcs3.app RPCS3_.app
mv RPCS3_.app RPCS3.app
# Hack to fix rpath issues
BIN="RPCS3.app/Contents/MacOS/rpcs3"
install_name_tool -delete_rpath /opt/homebrew/lib $BIN || true
install_name_tool -delete_rpath /usr/local/lib $BIN || true
# Fix dylib IDs
for lib in RPCS3.app/Contents/Frameworks/*.dylib; do
name=$(basename "$lib")
install_name_tool -id "@rpath/$name" "$lib"
done
# Rewrite any hardcoded Homebrew paths to use @rpath
find "RPCS3.app/Contents/" -type f \( -perm +111 -o -name "*.dylib" \) | while read -r bin; do
otool -L "$bin" | grep -E "/opt/homebrew|/usr/local" | awk '{print $1}' | while read -r dep; do
base=$(basename "$dep")
echo "Fixing $dep -> @rpath/$base in $bin"
install_name_tool -change "$dep" "@rpath/$base" "$bin"
done
done
# NOTE: "--deep" is deprecated
codesign --deep -fs - RPCS3.app
+2 -2
View File
@@ -28,7 +28,7 @@ curl -fsSL 'https://api.rpcs3.net/config/?api=v1' | iconv -f ISO-8859-1 -t UTF-8
# Download translations
mkdir -p ./bin/share/qt6/translations
ZIP_URL=$(curl -fsSL --retry 3 --retry-delay 60 "https://api.github.com/repos/RPCS3/rpcs3_translations/releases/latest" \
ZIP_URL=$(curl -fsSL "https://api.github.com/repos/RPCS3/rpcs3_translations/releases/latest" \
| grep "browser_download_url" \
| grep "RPCS3-languages.zip" \
| cut -d '"' -f 4)
@@ -36,7 +36,7 @@ if [ -z "$ZIP_URL" ]; then
echo "Failed to find RPCS3-languages.zip in the latest release. Continuing without translations."
else
echo "Downloading translations from: $ZIP_URL"
curl -fsSL --retry 3 --retry-delay 60 -o translations.zip "$ZIP_URL" || {
curl -L -o translations.zip "$ZIP_URL" || {
echo "Failed to download translations.zip. Continuing without translations."
exit 0
}
+2 -2
View File
@@ -18,7 +18,7 @@ curl -fsSL 'https://api.rpcs3.net/config/?api=v1' | iconv -t UTF-8 1> ./bin/GuiC
# Download translations
mkdir -p ./bin/qt6/translations
ZIP_URL=$(curl -fsSL --retry 3 --retry-delay 60 "https://api.github.com/repos/RPCS3/rpcs3_translations/releases/latest" \
ZIP_URL=$(curl -fsSL "https://api.github.com/repos/RPCS3/rpcs3_translations/releases/latest" \
| grep "browser_download_url" \
| grep "RPCS3-languages.zip" \
| cut -d '"' -f 4)
@@ -26,7 +26,7 @@ if [ -z "$ZIP_URL" ]; then
echo "Failed to find RPCS3-languages.zip in the latest release. Continuing without translations."
else
echo "Downloading translations from: $ZIP_URL"
curl -fsSL --retry 3 --retry-delay 60 -o translations.zip "$ZIP_URL" || {
curl -L -o translations.zip "$ZIP_URL" || {
echo "Failed to download translations.zip. Continuing without translations."
exit 0
}
+1 -1
View File
@@ -8,7 +8,7 @@ sed -i '' 's/quarterly/latest/' /etc/pkg/FreeBSD.conf
export ASSUME_ALWAYS_YES=true
pkg info # debug
# WITH_LLVM and Clang compiler
# WITH_LLVM
pkg install "llvm$LLVM_COMPILER_VER"
# Mandatory dependencies (qtX-base is pulled via qtX-multimedia)
+25 -32
View File
@@ -7,7 +7,14 @@ body:
attributes:
value: |
# Summary
Please do not ask for help here, use the [RPCS3 Discord server](https://discord.gg/rpcs3) or the [RPCS3 Forum](https://forums.rpcs3.net/) instead.
Please do not ask for help or report compatibility regressions here, use [RPCS3 Discord server](https://discord.gg/rpcs3) or [forums](https://forums.rpcs3.net/) instead.
- type: textarea
id: quick-summary
attributes:
label: Quick summary
description: Please briefly describe what has stopped working correctly.
validations:
required: true
- type: textarea
id: details
attributes:
@@ -19,29 +26,21 @@ body:
attributes:
value: |
# Identify the regressed build
Please provide the _exact_ build information that **introduced** the regression you're reporting (i.e. the first version where it happens).
Please provide the _exact_ build (or commit) information that introduced the regression you're reporting.
* Please see [How to find the build that caused a regression](https://wiki.rpcs3.net/index.php?title=Help:Using_different_versions_of_RPCS3#How_to_find_the_build_that_caused_a_regression.3F) in our wiki.
* You can find the [History of RPCS3 builds](https://rpcs3.net/builds) here.
* You can find [History of RPCS3 builds](https://rpcs3.net/compatibility?b) here.
Make sure you're running with settings as close to default as possible
* **Do NOT enable any emulator game patches when reporting issues**
* **Only change settings that are required for the game to work**
* Only change settings that are required for the game to work
- type: input
id: last-good-build
id: regressed-build
attributes:
label: Last working build
description: Provide the _exact_ last working build. This needs to be the build right before the first broken build.
label: Build with regression
description: Provide _exact_ build (or commit) information that introduced the regression you're reporting.
placeholder: v0.0.23-13948-31df99f7
validations:
required: true
- type: input
id: first-bad-build
attributes:
label: First broken build
description: Provide the _exact_ first broken build. This needs to be the build right after the last working build.
placeholder: v0.0.23-13949-d1a46b49
validations:
required: true
- type: markdown
attributes:
value: |
@@ -57,25 +56,12 @@ body:
- type: textarea
id: logs
attributes:
label: Attach 3 log files
label: Attach two log files
description: |
* A RPCS3 log file for the last working build
* A RPCS3 log file for the first broken build
* A RPCS3 log file for the latest master build (not required if latest master build is the first broken build)
Attach one file for the build with regression and another for a build that works.
Drag & drop the files into this input field, or upload them to another service (f.ex. Dropbox, Mega) and provide a link.
validations:
required: true
- type: dropdown
id: require-log-files
attributes:
label: I have attached all 3 required log files
options:
- "Yes"
- "No"
default: 1
validations:
required: true
- type: markdown
attributes:
value: |
@@ -87,8 +73,8 @@ body:
- type: textarea
id: captures
attributes:
label: Attach the RSX (.rrc) or RenderDoc (.rdc) capture files for visual issues
description: Compress your capture with .7z, .gz, etc. and attach it here, or upload it to another service (f.ex. Dropbox, Mega) and provide a link.
label: Attach capture files for visual issues
description: Compress your capture with 7z, Rar etc. and attach it here, or upload it to the cloud (Dropbox, Mega etc) and add a link to it.
validations:
required: false
- type: textarea
@@ -98,3 +84,10 @@ body:
description: Provide information about your system, such as operating system, CPU and GPU model, GPU driver version and other information that describes your system configuration.
validations:
required: false
- type: textarea
id: other-details
attributes:
label: Other details
description: Include anything else you deem to be important.
validations:
required: false
-9
View File
@@ -1,9 +0,0 @@
ports:
- name: abseil
- name: ccache
- name: gtest
- name: opencv4
- name: sdl3
- name: vulkan-headers
- name: vulkan-loader
- name: MoltenVK
-51
View File
@@ -1,51 +0,0 @@
name: Label PRs
on:
pull_request_target:
types:
- opened
- edited
jobs:
Label_PRs:
name: Label from title and linked issues
runs-on: ubuntu-latest
if: github.repository == 'RPCS3/rpcs3'
permissions:
issues: read
pull-requests: write
steps:
- name: Add labels from title and linked issues
uses: actions/github-script@v9
with:
retries: 3
script: |
const AREAS = [
'Build and CI', 'CLI', 'Filesystem', 'GUI', 'Input', 'ISO', 'Localization', 'Overlay', 'Render: Vulkan', 'RSX', 'Savestates',
];
const {repository: {pullRequest: pull}} = await github.graphql(`
query($owner: String!, $repo: String!, $number: Int!) {
repository(owner: $owner, name: $repo) {
pullRequest(number: $number) {
labels(first: 100) { nodes { name } }
closingIssuesReferences(first: 50) { nodes { labels(first: 100) { nodes { name } } } }
timelineItems(itemTypes: [UNLABELED_EVENT], last: 100) { nodes { ... on UnlabeledEvent { label { name } } } }
}
}
}`, {...context.repo, number: context.issue.number});
if (pull.labels.nodes.some(x => AREAS.includes(x.name)))
return;
// Skip labels a maintainer removed
const removed = pull.timelineItems.nodes.map(x => x.label.name);
const fromTitle = /^rsx\b/i.test(context.payload.pull_request.title) ? ['RSX'] : [];
const fromIssues = pull.closingIssuesReferences.nodes.flatMap(i => i.labels.nodes.map(x => x.name));
const labels = [...new Set([...fromTitle, ...fromIssues])]
.filter(name => AREAS.includes(name) && !removed.includes(name));
if (labels.length > 0) {
console.log(`Adding labels: ${labels.join(', ')}`);
await github.rest.issues.addLabels({...context.repo, issue_number: context.issue.number, labels});
}
+51 -221
View File
@@ -22,95 +22,31 @@ env:
BUILD_ARTIFACTSTAGINGDIRECTORY: ${{ github.workspace }}/artifacts/
jobs:
Clean_Code_Caches:
name: Clean caches
runs-on: ubuntu-latest
permissions:
actions: write
contents: read
pull-requests: read
outputs:
skip_ccache: ${{ steps.pr_labels.outputs.skip_ccache }}
steps:
- name: "Look for the 'CI: Disable Build Caches' label on the PR"
id: pr_labels
if: github.event_name == 'pull_request'
continue-on-error: true
env:
GH_TOKEN: ${{ github.token }}
run: |
# Query the live labels so adding the label and re-running all jobs works without a new push
labels=$(gh api "repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}" --jq '.labels[].name' 2>/dev/null) \
|| labels=$(jq -r '.pull_request.labels[]?.name' "$GITHUB_EVENT_PATH")
echo "Labels: ${labels:-<none>}"
skip=false
if grep -qix 'ci: disable build caches' <<< "$labels"; then
skip=true
echo "Builds will not restore ccache because of the 'CI: Disable Build Caches' label." >> "$GITHUB_STEP_SUMMARY"
fi
echo "skip_ccache=$skip" >> "$GITHUB_OUTPUT"
- name: "Look for the 'Shaders' or 'CI: Disable Build Caches' label on the merged PR"
id: labels
if: github.event_name == 'push' && github.repository == 'RPCS3/rpcs3' && github.ref_name == 'master'
continue-on-error: true
env:
GH_TOKEN: ${{ github.token }}
run: |
found=false
for sha in $(jq -r '[.after, (.commits[]?.id)] | map(select(. != null)) | unique[]' "$GITHUB_EVENT_PATH"); do
labels=$(gh api "repos/${{ github.repository }}/commits/$sha/pulls" --jq '.[].labels[].name' 2>/dev/null || true)
echo "$sha: ${labels:-<no associated PR>}"
if grep -qixE 'shaders|ci: disable build caches' <<< "$labels"; then
found=true
fi
done
echo "clean=$found" >> "$GITHUB_OUTPUT"
- name: Remove all code caches
if: steps.labels.outputs.clean == 'true'
continue-on-error: true
env:
GH_TOKEN: ${{ github.token }}
run: |
gh api --paginate "repos/${{ github.repository }}/actions/caches?per_page=100" \
--jq '.actions_caches[] | select(.key | contains("-ccache-")) | "\(.id)\t\(.key)"' > code_caches.tsv
if [ ! -s code_caches.tsv ]; then
echo "No code caches to remove."
exit 0
fi
while IFS=$'\t' read -r id key; do
echo "Removing $key (id $id)"
gh api -X DELETE "repos/${{ github.repository }}/actions/caches/$id" --silent
done < code_caches.tsv
echo "Removed $(wc -l < code_caches.tsv) code cache(s) after merging a 'Shaders' or 'CI: Disable Build Caches' PR." >> "$GITHUB_STEP_SUMMARY"
Linux_Build:
# Only run push event on master branch of main repo, but run all PRs
needs: Clean_Code_Caches
if: github.event_name != 'push' || (github.repository == 'RPCS3/rpcs3' && github.ref_name == 'master')
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-24.04
docker_img: "rpcs3/rpcs3-ci-jammy:2.1"
docker_img: "rpcs3/rpcs3-ci-jammy:1.14"
build_sh: "/rpcs3/.ci/build-linux.sh"
compiler: clang
UPLOAD_COMMIT_HASH: d812f1254a1157c80fd402f94446310560f54e5f
UPLOAD_REPO_FULL_NAME: "rpcs3/rpcs3-binaries-linux"
- os: ubuntu-24.04
docker_img: "rpcs3/rpcs3-ci-jammy:2.1"
docker_img: "rpcs3/rpcs3-ci-jammy:1.14"
build_sh: "/rpcs3/.ci/build-linux.sh"
compiler: gcc
- os: ubuntu-24.04-arm
docker_img: "rpcs3/rpcs3-ci-jammy-aarch64:2.1"
docker_img: "rpcs3/rpcs3-ci-jammy-aarch64:1.14"
build_sh: "/rpcs3/.ci/build-linux-aarch64.sh"
compiler: clang
UPLOAD_COMMIT_HASH: a1d35836e8d45bfc6f63c26f0a3e5d46ef622fe1
UPLOAD_REPO_FULL_NAME: "rpcs3/rpcs3-binaries-linux-arm64"
- os: ubuntu-24.04-arm
docker_img: "rpcs3/rpcs3-ci-jammy-aarch64:2.1"
docker_img: "rpcs3/rpcs3-ci-jammy-aarch64:1.14"
build_sh: "/rpcs3/.ci/build-linux-aarch64.sh"
compiler: gcc
name: RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }}
@@ -132,7 +68,6 @@ jobs:
fetch-depth: 0
- name: Restore build Ccache
if: needs.Clean_Code_Caches.outputs.skip_ccache != 'true'
uses: actions/cache/restore@main
id: restore-build-ccache
with:
@@ -182,7 +117,6 @@ jobs:
Mac_Build:
# Only run push event on master branch of main repo, but run all PRs
needs: Clean_Code_Caches
if: github.event_name != 'push' || (github.repository == 'RPCS3/rpcs3' && github.ref_name == 'master')
strategy:
fail-fast: false
@@ -200,26 +134,20 @@ jobs:
runs-on: ${{ matrix.runs-on }}
env:
CCACHE_DIR: /tmp/ccache_dir
QT_VER: '6.12.0'
QT_VER: '6.11.1'
QT_VER_MAIN: '6'
LLVM_COMPILER_VER: '22'
LLVM_COMPILER_VER: '21'
RELEASE_MESSAGE: ../GitHubReleaseMessage.txt
UPLOAD_COMMIT_HASH: ${{ matrix.UPLOAD_COMMIT_HASH }}
UPLOAD_REPO_FULL_NAME: ${{ matrix.UPLOAD_REPO_FULL_NAME }}
RUN_UNIT_TESTS: github.event_name == 'pull_request' && 'ON' || 'OFF'
RUN_UNIT_TESTS: ${{ matrix.name == 'Apple Silicon' && (github.event_name == 'pull_request' && 'ON') || 'OFF' }}
steps:
- name: Checkout repository
uses: actions/checkout@main
with:
fetch-depth: 0
- name: Setup MacPorts
uses: melusina-org/setup-macports@v1
with:
cache: 'disable'
- name: Restore Build Ccache
if: needs.Clean_Code_Caches.outputs.skip_ccache != 'true'
uses: actions/cache/restore@main
id: restore-build-ccache
with:
@@ -278,17 +206,16 @@ jobs:
Windows_Build:
# Only run push event on master branch of main repo, but run all PRs
needs: Clean_Code_Caches
if: github.event_name != 'push' || (github.repository == 'RPCS3/rpcs3' && github.ref_name == 'master')
name: RPCS3 Windows
runs-on: windows-2025-vs2026
env:
COMPILER: msvc
QT_VER_MAIN: '6'
QT_VER: '6.12.0'
QT_VER: '6.11.1'
QT_VER_MSVC: 'msvc2022'
QT_DATE: '202609280346'
LLVM_VER: '22.1.8'
QT_DATE: '202605090529'
LLVM_VER: '19.1.7'
VULKAN_VER: '1.4.341.1'
VULKAN_SDK_SHA: 'bcf2d75aa9556889ab974858666e20b3655b6055a0db704ccb47279ff33b5bfe'
CCACHE_SHA: '859141059ac950e1e8cd042c66f842f26b9e3a62a1669a69fe6ba180cb58bbdf'
@@ -296,12 +223,9 @@ jobs:
CCACHE_DIR: 'C:\ccache'
CCACHE_INODECACHE: 'true'
CCACHE_SLOPPINESS: 'time_macros'
CCACHE_MAXSIZE: '7G'
CCACHE_LAUNCH_ARGS: '-DCMAKE_C_COMPILER_LAUNCHER=C:\ccache_bin\ccache.exe -DCMAKE_CXX_COMPILER_LAUNCHER=C:\ccache_bin\ccache.exe'
DEPS_CACHE_DIR: ./dependency_cache
UPLOAD_COMMIT_HASH: 7d09e3be30805911226241afbb14f8cdc2eb054e
UPLOAD_REPO_FULL_NAME: "RPCS3/rpcs3-binaries-win"
SKIP_RPCS3_TEST: 'true'
steps:
- name: Checkout repository
@@ -325,132 +249,6 @@ jobs:
run: .ci/get_keys-windows.sh
- name: Restore Build Ccache
if: needs.Clean_Code_Caches.outputs.skip_ccache != 'true'
uses: actions/cache/restore@main
id: restore-build-ccache
with:
path: ${{ env.CCACHE_DIR }}
key: "${{ runner.os }}-ccache-${{ env.COMPILER }}-${{github.run_id}}"
restore-keys: ${{ runner.os }}-ccache-${{ env.COMPILER }}-
- name: Restore Dependencies Cache
uses: actions/cache/restore@main
id: restore-dependencies-cache
with:
path: ${{ env.DEPS_CACHE_DIR }}
key: "${{ runner.os }}-${{ env.COMPILER }}-${{ env.QT_VER }}-${{ env.VULKAN_SDK_SHA }}-${{ env.CCACHE_SHA }}-${{ hashFiles('llvm.lock') }}"
restore-keys: ${{ runner.os }}-${{ env.COMPILER }}-
- name: Download and unpack dependencies
run: |
.ci/setup-windows.sh
.ci/setup-windows-ci-vars.sh win64 msvc
- name: Export Variables
run: |
while IFS='=' read -r key val; do
# Skip lines that are empty or start with '#'
[[ -z "$key" || "$key" =~ ^# ]] && continue
echo "$key=$val" >> "${{ github.env }}"
done < .ci/ci-vars.env
- name: Add msbuild to PATH
uses: microsoft/setup-msbuild@main
- name: Compile RPCS3
shell: pwsh
run: msbuild rpcs3.sln /p:Configuration=Release /v:minimal /p:Platform=x64 /p:PreferredToolArchitecture=x64 /p:CLToolPath=${{ env.CCACHE_BIN_DIR }} /p:UseMultiToolTask=true /p:CustomAfterMicrosoftCommonTargets="${{ github.workspace }}\buildfiles\msvc\ci_only.targets"
- name: Pack up build artifacts
run: |
mkdir -p "${{ env.BUILD_ARTIFACTSTAGINGDIRECTORY }}"
.ci/deploy-windows.sh
- name: Upload artifacts (7z)
uses: actions/upload-artifact@main
with:
name: RPCS3 for Windows (MSVC)
path: ${{ env.BUILD_ARTIFACTSTAGINGDIRECTORY }}
compression-level: 0
if-no-files-found: error
- name: Deploy master build to GitHub Releases
if: |
github.event_name != 'pull_request' &&
github.repository == 'RPCS3/rpcs3' &&
github.ref == 'refs/heads/master'
env:
RPCS3_TOKEN: ${{ secrets.RPCS3_TOKEN }}
run: .ci/github-upload.sh
- name: Show ccache stats
if: github.ref == 'refs/heads/master'
run: ccache --show-stats --verbose
- name: Save Build Ccache
if: github.ref == 'refs/heads/master'
uses: actions/cache/save@main
with:
path: ${{ env.CCACHE_DIR }}
key: ${{ steps.restore-build-ccache.outputs.cache-primary-key }}
- name: Save Dependencies Cache
if: github.ref == 'refs/heads/master'
uses: actions/cache/save@main
with:
path: ${{ env.DEPS_CACHE_DIR }}
key: ${{ steps.restore-dependencies-cache.outputs.cache-primary-key }}
Windows_Build_Test:
# Only run push event on master branch of main repo, but run all PRs
needs: Clean_Code_Caches
if: github.event_name != 'push' || (github.repository == 'RPCS3/rpcs3' && github.ref_name == 'master')
name: RPCS3 Windows Unit Test
runs-on: windows-2025-vs2026
env:
COMPILER: msvc
QT_VER_MAIN: '6'
QT_VER: '6.12.0'
QT_VER_MSVC: 'msvc2022'
QT_DATE: '202609280346'
LLVM_VER: '22.1.8'
VULKAN_VER: '1.4.341.1'
VULKAN_SDK_SHA: 'bcf2d75aa9556889ab974858666e20b3655b6055a0db704ccb47279ff33b5bfe'
CCACHE_SHA: '859141059ac950e1e8cd042c66f842f26b9e3a62a1669a69fe6ba180cb58bbdf'
CCACHE_BIN_DIR: 'C:\ccache_bin'
CCACHE_DIR: 'C:\ccache'
CCACHE_INODECACHE: 'true'
CCACHE_SLOPPINESS: 'time_macros'
CCACHE_MAXSIZE: '7G'
CCACHE_LAUNCH_ARGS: '-DCMAKE_C_COMPILER_LAUNCHER=C:\ccache_bin\ccache.exe -DCMAKE_CXX_COMPILER_LAUNCHER=C:\ccache_bin\ccache.exe'
DEPS_CACHE_DIR: ./dependency_cache
UPLOAD_COMMIT_HASH: 7d09e3be30805911226241afbb14f8cdc2eb054e
UPLOAD_REPO_FULL_NAME: "RPCS3/rpcs3-binaries-win"
SKIP_RPCS3_EXE: 'true'
steps:
- name: Checkout repository
uses: actions/checkout@main
with:
fetch-depth: 0
- name: Setup NuGet
uses: nuget/setup-nuget@v4
- name: Restore NuGet packages
run: nuget restore rpcs3.sln
- name: Setup env
shell: pwsh
run: |
echo "QTDIR=C:\Qt\${{ env.QT_VER }}\${{ env.QT_VER_MSVC }}_64" >> ${{ github.env }}
echo "VULKAN_SDK=C:\VulkanSDK\${{ env.VULKAN_VER }}" >> ${{ github.env }}
- name: Get Cache Keys
run: .ci/get_keys-windows.sh
- name: Restore Build Ccache
if: needs.Clean_Code_Caches.outputs.skip_ccache != 'true'
uses: actions/cache/restore@main
id: restore-build-ccache
with:
@@ -491,9 +289,44 @@ jobs:
shell: pwsh
run: build\lib\Release-x64\rpcs3_test.exe
- name: Pack up build artifacts
run: |
mkdir -p "${{ env.BUILD_ARTIFACTSTAGINGDIRECTORY }}"
.ci/deploy-windows.sh
- name: Upload artifacts (7z)
uses: actions/upload-artifact@main
with:
name: RPCS3 for Windows (MSVC)
path: ${{ env.BUILD_ARTIFACTSTAGINGDIRECTORY }}
compression-level: 0
if-no-files-found: error
- name: Deploy master build to GitHub Releases
if: |
github.event_name != 'pull_request' &&
github.repository == 'RPCS3/rpcs3' &&
github.ref == 'refs/heads/master'
env:
RPCS3_TOKEN: ${{ secrets.RPCS3_TOKEN }}
run: .ci/github-upload.sh
- name: Save Build Ccache
if: github.ref == 'refs/heads/master'
uses: actions/cache/save@main
with:
path: ${{ env.CCACHE_DIR }}
key: ${{ steps.restore-build-ccache.outputs.cache-primary-key }}
- name: Save Dependencies Cache
if: github.ref == 'refs/heads/master'
uses: actions/cache/save@main
with:
path: ${{ env.DEPS_CACHE_DIR }}
key: ${{ steps.restore-dependencies-cache.outputs.cache-primary-key }}
Windows_Build_Clang:
# Only run push event on master branch of main repo, but run all PRs
needs: Clean_Code_Caches
if: github.event_name != 'push' || (github.repository == 'RPCS3/rpcs3' && github.ref_name == 'master')
strategy:
fail-fast: false
@@ -553,7 +386,6 @@ jobs:
p7zip
- name: Restore build Ccache
if: needs.Clean_Code_Caches.outputs.skip_ccache != 'true'
uses: actions/cache/restore@main
id: restore-build-ccache
with:
@@ -604,7 +436,6 @@ jobs:
FreeBSD_Build:
# Only run push event on master branch of main repo, but run all PRs
needs: Clean_Code_Caches
if: github.event_name != 'push' || (github.repository == 'RPCS3/rpcs3' && github.ref_name == 'master')
name: RPCS3 FreeBSD
runs-on: ubuntu-latest
@@ -612,10 +443,10 @@ jobs:
env:
CCACHE_DIR: ${{ github.workspace }}/ccache
QT_VER_MAIN: '6'
LLVM_COMPILER_VER: '22'
LLVM_CONFIG: 'llvm-config22'
CC: 'clang22'
CXX: 'clang++22'
LLVM_COMPILER_VER: '-devel'
CC: 'clang-devel'
CXX: 'clang++-devel'
LLVM_CONFIG: 'llvm-config-devel'
steps:
- name: Checkout repository
@@ -624,7 +455,6 @@ jobs:
fetch-depth: 0
- name: Restore Build Ccache
if: needs.Clean_Code_Caches.outputs.skip_ccache != 'true'
uses: actions/cache/restore@main
id: restore-build-ccache
with:
@@ -639,7 +469,7 @@ jobs:
envs: 'QT_VER_MAIN LLVM_COMPILER_VER CCACHE_DIR CC CXX LLVM_CONFIG'
usesh: true
copyback: false
release: "14.5"
release: "14.3"
run: .ci/install-freebsd.sh && .ci/build-freebsd.sh
- name: Save Build Ccache
-3
View File
@@ -126,6 +126,3 @@ CMakeUserPresets.json
.cache/
.lldbinit
# claude
CLAUDE.md
+4 -45
View File
@@ -49,57 +49,16 @@
<PropertyGroup Label="UserMacros">
<CmakeReleaseCLI>call vsdevcmd.bat -arch=amd64
cd "$(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)"
if not defined CCACHE_LAUNCH_ARGS set CCACHE_LAUNCH_ARGS=
cmake -G Ninja ^
-DCMAKE_CXX_COMPILER="cl.exe" ^
-DCMAKE_C_COMPILER="cl.exe" ^
%25CCACHE_LAUNCH_ARGS%25 ^
-DCMAKE_BUILD_TYPE="Release" ^
-DCMAKE_INSTALL_PREFIX="./Release" ^
-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded ^
-DCMAKE_SYSTEM_VERSION=10.0 ^
-DLIBTYPE=STATIC ^
-DFORCE_STATIC_VCRT=true ^
-DALSOFT_UTILS=false ^
-DALSOFT_EXAMPLES=false ^
-DALSOFT_INSTALL=false ^
-DALSOFT_INSTALL_CONFIG=false ^
-DALSOFT_INSTALL_HRTF_DATA=false ^
-DALSOFT_INSTALL_AMBDEC_PRESETS=false ^
-DALSOFT_INSTALL_EXAMPLES=false ^
-DALSOFT_INSTALL_UTILS=false ^
"$(SolutionDir)3rdparty\OpenAL\openal-soft"
cmake -G Ninja -DCMAKE_CXX_COMPILER="cl.exe" -DCMAKE_C_COMPILER="cl.exe" -DCMAKE_BUILD_TYPE="Release" -DCMAKE_INSTALL_PREFIX="./Release" -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded -DCMAKE_SYSTEM_VERSION=10.0 -DLIBTYPE=STATIC -DFORCE_STATIC_VCRT=true -DALSOFT_UTILS=false -DALSOFT_EXAMPLES=false -DALSOFT_INSTALL=false -DALSOFT_INSTALL_CONFIG=false -DALSOFT_INSTALL_HRTF_DATA=false -DALSOFT_INSTALL_AMBDEC_PRESETS=false -DALSOFT_INSTALL_EXAMPLES=false -DALSOFT_INSTALL_UTILS=false "$(SolutionDir)3rdparty\OpenAL\openal-soft"
</CmakeReleaseCLI>
<CmakeDebugCLI>call vsdevcmd.bat -arch=amd64
cd "$(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)"
if not defined CCACHE_LAUNCH_ARGS set CCACHE_LAUNCH_ARGS=
cmake -G Ninja ^
-DCMAKE_CXX_COMPILER="cl.exe" ^
-DCMAKE_C_COMPILER="cl.exe" ^
%25CCACHE_LAUNCH_ARGS%25 ^
-DCMAKE_BUILD_TYPE="Debug" ^
-DCMAKE_INSTALL_PREFIX="./Debug" ^
-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDebug ^
-DCMAKE_SYSTEM_VERSION=10.0 ^
-DALSOFT_UTILS=false ^
-DALSOFT_EXAMPLES=false ^
-DALSOFT_INSTALL=false ^
-DALSOFT_INSTALL_CONFIG=false ^
-DALSOFT_INSTALL_HRTF_DATA=false ^
-DALSOFT_INSTALL_AMBDEC_PRESETS=false ^
-DALSOFT_INSTALL_EXAMPLES=false ^
-DALSOFT_INSTALL_UTILS=false ^
"$(SolutionDir)3rdparty\OpenAL\openal-soft"
cmake -G Ninja -DCMAKE_CXX_COMPILER="cl.exe" -DCMAKE_C_COMPILER="cl.exe" -DCMAKE_BUILD_TYPE="Debug" -DCMAKE_INSTALL_PREFIX="./Debug" -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDebug -DCMAKE_SYSTEM_VERSION=10.0 -DLIBTYPE=STATIC -DALSOFT_UTILS=false -DALSOFT_EXAMPLES=false -DALSOFT_INSTALL=false -DALSOFT_INSTALL_CONFIG=false -DALSOFT_INSTALL_HRTF_DATA=false -DALSOFT_INSTALL_AMBDEC_PRESETS=false -DALSOFT_INSTALL_EXAMPLES=false -DALSOFT_INSTALL_UTILS=false "$(SolutionDir)3rdparty\OpenAL\openal-soft"
</CmakeDebugCLI>
<CmakeCopyCLI>
echo Copying..
copy "$(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)\OpenAL32.lib" "$(SolutionDir)build\lib\$(Configuration)-$(Platform)"
</CmakeCopyCLI>
<CmakeCopyDebugCLI>
echo Copying..
copy "$(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)\OpenAL32.lib" "$(SolutionDir)build\lib\$(Configuration)-$(Platform)"
copy "$(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)\OpenAL32.dll" "$(SolutionDir)bin"
</CmakeCopyDebugCLI>
<CmakeCleanCLI>
echo Cleaning..
del "$(SolutionDir)build\lib\$(Configuration)-$(Platform)\OpenAL32.lib"
@@ -112,13 +71,13 @@
<NMakeBuildCommandLine>
$(CmakeDebugCLI)
ninja
$(CmakeCopyDebugCLI)
$(CmakeCopyCLI)
</NMakeBuildCommandLine>
<NMakeReBuildCommandLine>
$(CmakeCleanCLI)
$(CmakeDebugCLI)
ninja
$(CmakeCopyDebugCLI)
$(CmakeCopyCLI)
</NMakeReBuildCommandLine>
<NMakeCleanCommandLine>
$(CmakeCleanCLI)
+430 -117
View File
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
@@ -11,20 +11,16 @@
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<Keyword>MakeFileProj</Keyword>
<ProjectGuid>{DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}</ProjectGuid>
<RootNamespace>libcurl</RootNamespace>
</PropertyGroup>
<Import Project="$(SolutionDir)\buildfiles\msvc\common_default.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<Import Project="$(SolutionDir)\buildfiles\msvc\common_default_macros.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Makefile</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Makefile</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PropertyGroup Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup>
@@ -35,119 +31,436 @@
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros">
<CmakeReleaseCLI>call vsdevcmd.bat -arch=amd64
cd "$(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)"
if not defined CCACHE_LAUNCH_ARGS set CCACHE_LAUNCH_ARGS=
cmake -G Ninja ^
-DCMAKE_CXX_COMPILER="cl.exe" ^
-DCMAKE_C_COMPILER="cl.exe" ^
%25CCACHE_LAUNCH_ARGS%25 ^
-DCMAKE_BUILD_TYPE="Release" ^
-DCMAKE_INSTALL_PREFIX="./Release" ^
-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded ^
-DCMAKE_SYSTEM_VERSION=10.0 ^
-DBUILD_SHARED_LIBS=OFF ^
-DBUILD_CURL_EXE=OFF ^
-DBUILD_TESTING=OFF ^
-DCURL_USE_WOLFSSL=ON ^
-DCURL_USE_IPV6=ON ^
-DCURL_USE_SCHANNEL=OFF ^
-DCURL_USE_OPENSSL=OFF ^
-DCURL_USE_LIBPSL=OFF ^
-DCURL_ZLIB=OFF ^
-DCURL_ZSTD=OFF ^
-DCURL_USE_LIBSSH2=OFF ^
-DCMAKE_C_FLAGS="/DWOLFSSL_ALT_CERT_CHAINS /DHAVE_SNI /DNO_MD4 /DWOLFSSL_USER_SETTINGS /DUSE_IPV6 /I\"$(SolutionDir)3rdparty\curl\extra\" /I\"$(SolutionDir)3rdparty\wolfssl\wolfssl\" /I\"$(SolutionDir)3rdparty\wolfssl\wolfssl\wolfssl\" /I\"$(SolutionDir)3rdparty\wolfssl\extra\win32\"" ^
-DCMAKE_C_FLAGS_RELEASE="/O2 /Ob1 /GF /Gy" ^
-DWOLFSSL_INCLUDE_DIR="$(SolutionDir)3rdparty\wolfssl\wolfssl" ^
-DWOLFSSL_LIBRARY="$(SolutionDir)build\lib\$(Configuration)-$(Platform)\wolfssl.lib" ^
"$(SolutionDir)3rdparty\curl\curl"
</CmakeReleaseCLI>
<CmakeDebugCLI>call vsdevcmd.bat -arch=amd64
cd "$(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)"
if not defined CCACHE_LAUNCH_ARGS set CCACHE_LAUNCH_ARGS=
cmake -G Ninja ^
-DCMAKE_CXX_COMPILER="cl.exe" ^
-DCMAKE_C_COMPILER="cl.exe" ^
%25CCACHE_LAUNCH_ARGS%25 ^
-DCMAKE_BUILD_TYPE="Debug" ^
-DCMAKE_INSTALL_PREFIX="./Debug" ^
-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDebug ^
-DCMAKE_SYSTEM_VERSION=10.0 ^
-DBUILD_SHARED_LIBS=OFF ^
-DBUILD_CURL_EXE=OFF ^
-DBUILD_TESTING=OFF ^
-DCURL_USE_WOLFSSL=ON ^
-DCURL_USE_IPV6=ON ^
-DCURL_USE_SCHANNEL=OFF ^
-DCURL_USE_OPENSSL=OFF ^
-DCURL_USE_LIBPSL=OFF ^
-DCURL_ZLIB=OFF ^
-DCURL_USE_LIBSSH2=OFF ^
-DCMAKE_C_FLAGS="/DWOLFSSL_ALT_CERT_CHAINS /DHAVE_SNI /DNO_MD4 /DWOLFSSL_USER_SETTINGS /DUSE_IPV6 /I\"$(SolutionDir)3rdparty\curl\extra\" /I\"$(SolutionDir)3rdparty\wolfssl\wolfssl\" /I\"$(SolutionDir)3rdparty\wolfssl\wolfssl\wolfssl\" /I\"$(SolutionDir)3rdparty\wolfssl\extra\win32\"" ^
-DCMAKE_C_FLAGS_DEBUG="/Od /Ob0 /GF /Gy" ^
-DWOLFSSL_INCLUDE_DIR="$(SolutionDir)3rdparty\wolfssl\wolfssl" ^
-DWOLFSSL_LIBRARY="$(SolutionDir)build\lib\$(Configuration)-$(Platform)\wolfssl.lib" ^
"$(SolutionDir)3rdparty\curl\curl"
</CmakeDebugCLI>
<CmakeCopyCLI>
echo Copying..
copy "$(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)\lib\libcurl.lib" "$(SolutionDir)build\lib\$(Configuration)-$(Platform)"
</CmakeCopyCLI>
<CmakeCopyDebugCLI>
echo Copying..
copy "$(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)\lib\libcurl-d.lib" "$(SolutionDir)build\lib\$(Configuration)-$(Platform)"
</CmakeCopyDebugCLI>
<CmakeCleanCLI>
echo Cleaning..
del "$(SolutionDir)build\lib\$(Configuration)-$(Platform)\libcurl.lib"
rmdir /s /q "$(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)"
</CmakeCleanCLI>
<CmakeCleanDebugCLI>
echo Cleaning..
del "$(SolutionDir)build\lib\$(Configuration)-$(Platform)\libcurl-d.lib"
rmdir /s /q "$(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)"
</CmakeCleanDebugCLI>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<PropertyGroup>
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
<OutDir>$(SolutionDir)build\lib\$(Configuration)-$(Platform)\</OutDir>
<IntDir>$(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)\</IntDir>
<NMakeBuildCommandLine>
$(CmakeDebugCLI)
ninja
$(CmakeCopyDebugCLI)
</NMakeBuildCommandLine>
<NMakeReBuildCommandLine>
$(CmakeCleanDebugCLI)
$(CmakeDebugCLI)
ninja
$(CmakeCopyDebugCLI)
</NMakeReBuildCommandLine>
<NMakeCleanCommandLine>
$(CmakeCleanDebugCLI)
</NMakeCleanCommandLine>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>$(SolutionDir)build\lib\$(Configuration)-$(Platform)\</OutDir>
<IntDir>$(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)\</IntDir>
<NMakeBuildCommandLine>
$(CmakeReleaseCLI)
ninja
$(CmakeCopyCLI)
</NMakeBuildCommandLine>
<NMakeReBuildCommandLine>
$(CmakeCleanCLI)
$(CmakeReleaseCLI)
ninja
$(CmakeCopyCLI)
</NMakeReBuildCommandLine>
<NMakeCleanCommandLine>
$(CmakeCleanCLI)
</NMakeCleanCommandLine>
</PropertyGroup>
<ItemDefinitionGroup>
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>curl\include;curl\lib;extra;$(SolutionDir)3rdparty\wolfssl\wolfssl\wolfssl;$(SolutionDir)3rdparty\wolfssl\wolfssl;$(SolutionDir)3rdparty\wolfssl\extra\win32;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WOLFSSL_ALT_CERT_CHAINS;HAVE_SNI;NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_WOLFSSL;NO_MD4;WOLFSSL_USER_SETTINGS;USE_IPV6;SIZEOF_LONG=4;SIZEOF_LONG_LONG=8;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<FunctionLevelLinking>true</FunctionLevelLinking>
<WarningLevel>TurnOffAllWarnings</WarningLevel>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0409</Culture>
</ResourceCompile>
<Lib>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<TargetMachine>MachineX64</TargetMachine>
</Lib>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="curl\lib\altsvc.c" />
<ClCompile Include="curl\lib\amigaos.c" />
<ClCompile Include="curl\lib\asyn-ares.c" />
<ClCompile Include="curl\lib\asyn-base.c" />
<ClCompile Include="curl\lib\asyn-thrdd.c" />
<ClCompile Include="curl\lib\bufq.c" />
<ClCompile Include="curl\lib\bufref.c" />
<ClCompile Include="curl\lib\cf-dns.c" />
<ClCompile Include="curl\lib\cf-h1-proxy.c" />
<ClCompile Include="curl\lib\cf-h2-proxy.c" />
<ClCompile Include="curl\lib\cf-haproxy.c" />
<ClCompile Include="curl\lib\cf-https-connect.c" />
<ClCompile Include="curl\lib\cf-ip-happy.c" />
<ClCompile Include="curl\lib\cf-recvbuf.c" />
<ClCompile Include="curl\lib\cf-setup.c" />
<ClCompile Include="curl\lib\cf-socket.c" />
<ClCompile Include="curl\lib\cfilters.c" />
<ClCompile Include="curl\lib\conncache.c" />
<ClCompile Include="curl\lib\connect.c" />
<ClCompile Include="curl\lib\content_encoding.c" />
<ClCompile Include="curl\lib\cookie.c" />
<ClCompile Include="curl\lib\creds.c" />
<ClCompile Include="curl\lib\cshutdn.c" />
<ClCompile Include="curl\lib\curlx\base64.c" />
<ClCompile Include="curl\lib\curlx\basename.c" />
<ClCompile Include="curl\lib\curlx\dynbuf.c" />
<ClCompile Include="curl\lib\curlx\fopen.c" />
<ClCompile Include="curl\lib\curlx\inet_ntop.c" />
<ClCompile Include="curl\lib\curlx\inet_pton.c" />
<ClCompile Include="curl\lib\curlx\multibyte.c" />
<ClCompile Include="curl\lib\curlx\nonblock.c" />
<ClCompile Include="curl\lib\curlx\snprintf.c" />
<ClCompile Include="curl\lib\curlx\strcopy.c" />
<ClCompile Include="curl\lib\curlx\strdup.c" />
<ClCompile Include="curl\lib\curlx\strerr.c" />
<ClCompile Include="curl\lib\curlx\strparse.c" />
<ClCompile Include="curl\lib\curlx\timediff.c" />
<ClCompile Include="curl\lib\curlx\timeval.c" />
<ClCompile Include="curl\lib\curlx\version_win32.c" />
<ClCompile Include="curl\lib\curlx\wait.c" />
<ClCompile Include="curl\lib\curlx\warnless.c" />
<ClCompile Include="curl\lib\curlx\winapi.c" />
<ClCompile Include="curl\lib\curl_addrinfo.c" />
<ClCompile Include="curl\lib\curl_endian.c" />
<ClCompile Include="curl\lib\curl_fnmatch.c" />
<ClCompile Include="curl\lib\curl_fopen.c" />
<ClCompile Include="curl\lib\curl_gethostname.c" />
<ClCompile Include="curl\lib\curl_get_line.c" />
<ClCompile Include="curl\lib\curl_gssapi.c" />
<ClCompile Include="curl\lib\curl_memrchr.c" />
<ClCompile Include="curl\lib\curl_ntlm_core.c" />
<ClCompile Include="curl\lib\curl_range.c" />
<ClCompile Include="curl\lib\curl_sasl.c" />
<ClCompile Include="curl\lib\curl_sha512_256.c" />
<ClCompile Include="curl\lib\curl_share.c" />
<ClCompile Include="curl\lib\curl_sspi.c" />
<ClCompile Include="curl\lib\curl_threads.c" />
<ClCompile Include="curl\lib\curl_trc.c" />
<ClCompile Include="curl\lib\cw-out.c" />
<ClCompile Include="curl\lib\cw-pause.c" />
<ClCompile Include="curl\lib\dict.c" />
<ClCompile Include="curl\lib\dllmain.c" />
<ClCompile Include="curl\lib\dnscache.c" />
<ClCompile Include="curl\lib\doh.c" />
<ClCompile Include="curl\lib\dynhds.c" />
<ClCompile Include="curl\lib\easy.c" />
<ClCompile Include="curl\lib\easygetopt.c" />
<ClCompile Include="curl\lib\easyoptions.c" />
<ClCompile Include="curl\lib\escape.c" />
<ClCompile Include="curl\lib\fake_addrinfo.c" />
<ClCompile Include="curl\lib\file.c" />
<ClCompile Include="curl\lib\fileinfo.c" />
<ClCompile Include="curl\lib\formdata.c" />
<ClCompile Include="curl\lib\ftp.c" />
<ClCompile Include="curl\lib\ftplistparser.c" />
<ClCompile Include="curl\lib\getenv.c" />
<ClCompile Include="curl\lib\getinfo.c" />
<ClCompile Include="curl\lib\gopher.c" />
<ClCompile Include="curl\lib\hash.c" />
<ClCompile Include="curl\lib\headers.c" />
<ClCompile Include="curl\lib\hmac.c" />
<ClCompile Include="curl\lib\hostip.c" />
<ClCompile Include="curl\lib\hostip4.c" />
<ClCompile Include="curl\lib\hostip6.c" />
<ClCompile Include="curl\lib\hsts.c" />
<ClCompile Include="curl\lib\http.c" />
<ClCompile Include="curl\lib\http1.c" />
<ClCompile Include="curl\lib\http2.c" />
<ClCompile Include="curl\lib\httpsrr.c" />
<ClCompile Include="curl\lib\http_aws_sigv4.c" />
<ClCompile Include="curl\lib\http_chunks.c" />
<ClCompile Include="curl\lib\http_digest.c" />
<ClCompile Include="curl\lib\http_negotiate.c" />
<ClCompile Include="curl\lib\http_ntlm.c" />
<ClCompile Include="curl\lib\http_proxy.c" />
<ClCompile Include="curl\lib\idn.c" />
<ClCompile Include="curl\lib\if2ip.c" />
<ClCompile Include="curl\lib\imap.c" />
<ClCompile Include="curl\lib\ldap.c" />
<ClCompile Include="curl\lib\llist.c" />
<ClCompile Include="curl\lib\macos.c" />
<ClCompile Include="curl\lib\md4.c" />
<ClCompile Include="curl\lib\md5.c" />
<ClCompile Include="curl\lib\memdebug.c" />
<ClCompile Include="curl\lib\mime.c" />
<ClCompile Include="curl\lib\mprintf.c" />
<ClCompile Include="curl\lib\mqtt.c" />
<ClCompile Include="curl\lib\multi.c" />
<ClCompile Include="curl\lib\multi_ev.c" />
<ClCompile Include="curl\lib\multi_ntfy.c" />
<ClCompile Include="curl\lib\netrc.c" />
<ClCompile Include="curl\lib\openldap.c" />
<ClCompile Include="curl\lib\parsedate.c" />
<ClCompile Include="curl\lib\peer.c" />
<ClCompile Include="curl\lib\pingpong.c" />
<ClCompile Include="curl\lib\pop3.c" />
<ClCompile Include="curl\lib\progress.c" />
<ClCompile Include="curl\lib\protocol.c" />
<ClCompile Include="curl\lib\proxy.c" />
<ClCompile Include="curl\lib\psl.c" />
<ClCompile Include="curl\lib\rand.c" />
<ClCompile Include="curl\lib\ratelimit.c" />
<ClCompile Include="curl\lib\request.c" />
<ClCompile Include="curl\lib\rtsp.c" />
<ClCompile Include="curl\lib\select.c" />
<ClCompile Include="curl\lib\sendf.c" />
<ClCompile Include="curl\lib\setopt.c" />
<ClCompile Include="curl\lib\sha256.c" />
<ClCompile Include="curl\lib\slist.c" />
<ClCompile Include="curl\lib\smb.c" />
<ClCompile Include="curl\lib\smtp.c" />
<ClCompile Include="curl\lib\socketpair.c" />
<ClCompile Include="curl\lib\socks.c" />
<ClCompile Include="curl\lib\socks_gssapi.c" />
<ClCompile Include="curl\lib\socks_sspi.c" />
<ClCompile Include="curl\lib\splay.c" />
<ClCompile Include="curl\lib\strcase.c" />
<ClCompile Include="curl\lib\strequal.c" />
<ClCompile Include="curl\lib\strerror.c" />
<ClCompile Include="curl\lib\system_win32.c" />
<ClCompile Include="curl\lib\telnet.c" />
<ClCompile Include="curl\lib\tftp.c" />
<ClCompile Include="curl\lib\thrdpool.c" />
<ClCompile Include="curl\lib\thrdqueue.c" />
<ClCompile Include="curl\lib\transfer.c" />
<ClCompile Include="curl\lib\uint-bset.c" />
<ClCompile Include="curl\lib\uint-hash.c" />
<ClCompile Include="curl\lib\uint-spbset.c" />
<ClCompile Include="curl\lib\uint-table.c" />
<ClCompile Include="curl\lib\url.c" />
<ClCompile Include="curl\lib\urlapi.c" />
<ClCompile Include="curl\lib\vauth\gsasl.c" />
<ClCompile Include="curl\lib\version.c" />
<ClCompile Include="curl\lib\vquic\capsule.c" />
<ClCompile Include="curl\lib\vquic\cf-capsule.c" />
<ClCompile Include="curl\lib\vquic\cf-ngtcp2-cmn.c" />
<ClCompile Include="curl\lib\vquic\cf-ngtcp2-proxy.c" />
<ClCompile Include="curl\lib\vquic\cf-ngtcp2.c" />
<ClCompile Include="curl\lib\vquic\cf-quiche.c" />
<ClCompile Include="curl\lib\vquic\vquic-tls.c" />
<ClCompile Include="curl\lib\vssh\vssh.c" />
<ClCompile Include="curl\lib\vtls\apple.c" />
<ClCompile Include="curl\lib\vtls\cipher_suite.c" />
<ClCompile Include="curl\lib\vtls\hostcheck.c" />
<ClCompile Include="curl\lib\vtls\rustls.c" />
<ClCompile Include="curl\lib\vtls\vtls_config.c" />
<ClCompile Include="curl\lib\vtls\vtls_scache.c" />
<ClCompile Include="curl\lib\vtls\vtls_spack.c" />
<ClCompile Include="curl\lib\vtls\x509asn1.c" />
<ClCompile Include="curl\lib\vauth\cleartext.c" />
<ClCompile Include="curl\lib\vauth\cram.c" />
<ClCompile Include="curl\lib\vauth\digest.c" />
<ClCompile Include="curl\lib\vauth\digest_sspi.c" />
<ClCompile Include="curl\lib\vauth\krb5_gssapi.c" />
<ClCompile Include="curl\lib\vauth\krb5_sspi.c" />
<ClCompile Include="curl\lib\vauth\ntlm.c" />
<ClCompile Include="curl\lib\vauth\ntlm_sspi.c" />
<ClCompile Include="curl\lib\vauth\oauth2.c" />
<ClCompile Include="curl\lib\vauth\spnego_gssapi.c" />
<ClCompile Include="curl\lib\vauth\spnego_sspi.c" />
<ClCompile Include="curl\lib\vauth\vauth.c" />
<ClCompile Include="curl\lib\vquic\vquic.c" />
<ClCompile Include="curl\lib\vssh\libssh.c" />
<ClCompile Include="curl\lib\vssh\libssh2.c" />
<ClCompile Include="curl\lib\vtls\gtls.c" />
<ClCompile Include="curl\lib\vtls\keylog.c" />
<ClCompile Include="curl\lib\vtls\mbedtls.c" />
<ClCompile Include="curl\lib\vtls\openssl.c" />
<ClCompile Include="curl\lib\vtls\schannel.c" />
<ClCompile Include="curl\lib\vtls\schannel_verify.c" />
<ClCompile Include="curl\lib\vtls\vtls.c" />
<ClCompile Include="curl\lib\vtls\wolfssl.c" />
<ClCompile Include="curl\lib\ws.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="curl\include\curl\curl.h" />
<ClInclude Include="curl\include\curl\curlver.h" />
<ClInclude Include="curl\include\curl\easy.h" />
<ClInclude Include="curl\include\curl\mprintf.h" />
<ClInclude Include="curl\include\curl\multi.h" />
<ClInclude Include="curl\include\curl\stdcheaders.h" />
<ClInclude Include="curl\include\curl\system.h" />
<ClInclude Include="curl\include\curl\typecheck-gcc.h" />
<ClInclude Include="curl\include\curl\urlapi.h" />
<ClInclude Include="curl\lib\altsvc.h" />
<ClInclude Include="curl\lib\amigaos.h" />
<ClInclude Include="curl\lib\arpa_telnet.h" />
<ClInclude Include="curl\lib\asyn.h" />
<ClInclude Include="curl\lib\bufq.h" />
<ClInclude Include="curl\lib\bufref.h" />
<ClInclude Include="curl\lib\cf-dns.h" />
<ClInclude Include="curl\lib\cf-h1-proxy.h" />
<ClInclude Include="curl\lib\cf-h2-proxy.h" />
<ClInclude Include="curl\lib\cf-haproxy.h" />
<ClInclude Include="curl\lib\cf-https-connect.h" />
<ClInclude Include="curl\lib\cf-ip-happy.h" />
<ClInclude Include="curl\lib\cf-recvbuf.h" />
<ClInclude Include="curl\lib\cf-setup.h" />
<ClInclude Include="curl\lib\cf-socket.h" />
<ClInclude Include="curl\lib\cfilters.h" />
<ClInclude Include="curl\lib\config-mac.h" />
<ClInclude Include="curl\lib\config-os400.h" />
<ClInclude Include="curl\lib\config-plan9.h" />
<ClInclude Include="curl\lib\config-riscos.h" />
<ClInclude Include="curl\lib\config-win32.h" />
<ClInclude Include="curl\lib\conncache.h" />
<ClInclude Include="curl\lib\connect.h" />
<ClInclude Include="curl\lib\content_encoding.h" />
<ClInclude Include="curl\lib\cookie.h" />
<ClInclude Include="curl\lib\creds.h" />
<ClInclude Include="curl\lib\cshutdn.h" />
<ClInclude Include="curl\lib\curlx\base64.h" />
<ClInclude Include="curl\lib\curlx\basename.h" />
<ClInclude Include="curl\lib\curlx\binmode.h" />
<ClInclude Include="curl\lib\curlx\dynbuf.h" />
<ClInclude Include="curl\lib\curlx\fopen.h" />
<ClInclude Include="curl\lib\curlx\inet_ntop.h" />
<ClInclude Include="curl\lib\curlx\inet_pton.h" />
<ClInclude Include="curl\lib\curlx\multibyte.h" />
<ClInclude Include="curl\lib\curlx\nonblock.h" />
<ClInclude Include="curl\lib\curlx\snprintf.h" />
<ClInclude Include="curl\lib\curlx\strcopy.h" />
<ClInclude Include="curl\lib\curlx\strdup.h" />
<ClInclude Include="curl\lib\curlx\strerr.h" />
<ClInclude Include="curl\lib\curlx\strparse.h" />
<ClInclude Include="curl\lib\curlx\timediff.h" />
<ClInclude Include="curl\lib\curlx\timeval.h" />
<ClInclude Include="curl\lib\curlx\version_win32.h" />
<ClInclude Include="curl\lib\curlx\wait.h" />
<ClInclude Include="curl\lib\curlx\warnless.h" />
<ClInclude Include="curl\lib\curlx\winapi.h" />
<ClInclude Include="curl\lib\curl_addrinfo.h" />
<ClInclude Include="curl\lib\curl_ctype.h" />
<ClInclude Include="curl\lib\curl_endian.h" />
<ClInclude Include="curl\lib\curl_fnmatch.h" />
<ClInclude Include="curl\lib\curl_fopen.h" />
<ClInclude Include="curl\lib\curl_gethostname.h" />
<ClInclude Include="curl\lib\curl_get_line.h" />
<ClInclude Include="curl\lib\curl_gssapi.h" />
<ClInclude Include="curl\lib\curl_hmac.h" />
<ClInclude Include="curl\lib\curl_ldap.h" />
<ClInclude Include="curl\lib\curl_md4.h" />
<ClInclude Include="curl\lib\curl_md5.h" />
<ClInclude Include="curl\lib\curl_memrchr.h" />
<ClInclude Include="curl\lib\curl_ntlm_core.h" />
<ClInclude Include="curl\lib\curl_printf.h" />
<ClInclude Include="curl\lib\curl_range.h" />
<ClInclude Include="curl\lib\curl_sasl.h" />
<ClInclude Include="curl\lib\curl_setup.h" />
<ClInclude Include="curl\lib\curl_setup_once.h" />
<ClInclude Include="curl\lib\curl_sha256.h" />
<ClInclude Include="curl\lib\curl_sha512_256.h" />
<ClInclude Include="curl\lib\curl_share.h" />
<ClInclude Include="curl\lib\curl_sspi.h" />
<ClInclude Include="curl\lib\curl_threads.h" />
<ClInclude Include="curl\lib\curl_trc.h" />
<ClInclude Include="curl\lib\cw-out.h" />
<ClInclude Include="curl\lib\cw-pause.h" />
<ClInclude Include="curl\lib\dict.h" />
<ClInclude Include="curl\lib\dnscache.h" />
<ClInclude Include="curl\lib\doh.h" />
<ClInclude Include="curl\lib\dynhds.h" />
<ClInclude Include="curl\lib\easyif.h" />
<ClInclude Include="curl\lib\easyoptions.h" />
<ClInclude Include="curl\lib\easy_lock.h" />
<ClInclude Include="curl\lib\escape.h" />
<ClInclude Include="curl\lib\fake_addrinfo.h" />
<ClInclude Include="curl\lib\file.h" />
<ClInclude Include="curl\lib\fileinfo.h" />
<ClInclude Include="curl\lib\formdata.h" />
<ClInclude Include="curl\lib\ftp-int.h" />
<ClInclude Include="curl\lib\ftp.h" />
<ClInclude Include="curl\lib\ftplistparser.h" />
<ClInclude Include="curl\lib\functypes.h" />
<ClInclude Include="curl\lib\getinfo.h" />
<ClInclude Include="curl\lib\gopher.h" />
<ClInclude Include="curl\lib\hash.h" />
<ClInclude Include="curl\lib\headers.h" />
<ClInclude Include="curl\lib\hostip.h" />
<ClInclude Include="curl\lib\hsts.h" />
<ClInclude Include="curl\lib\http.h" />
<ClInclude Include="curl\lib\http1.h" />
<ClInclude Include="curl\lib\http2.h" />
<ClInclude Include="curl\lib\httpsrr.h" />
<ClInclude Include="curl\lib\http_aws_sigv4.h" />
<ClInclude Include="curl\lib\http_chunks.h" />
<ClInclude Include="curl\lib\http_digest.h" />
<ClInclude Include="curl\lib\http_negotiate.h" />
<ClInclude Include="curl\lib\http_ntlm.h" />
<ClInclude Include="curl\lib\http_proxy.h" />
<ClInclude Include="curl\lib\idn.h" />
<ClInclude Include="curl\lib\if2ip.h" />
<ClInclude Include="curl\lib\imap.h" />
<ClInclude Include="curl\lib\llist.h" />
<ClInclude Include="curl\lib\macos.h" />
<ClInclude Include="curl\lib\mime.h" />
<ClInclude Include="curl\lib\mqtt.h" />
<ClInclude Include="curl\lib\multihandle.h" />
<ClInclude Include="curl\lib\multiif.h" />
<ClInclude Include="curl\lib\multi_ev.h" />
<ClInclude Include="curl\lib\multi_ntfy.h" />
<ClInclude Include="curl\lib\netrc.h" />
<ClInclude Include="curl\lib\parsedate.h" />
<ClInclude Include="curl\lib\peer.h" />
<ClInclude Include="curl\lib\pingpong.h" />
<ClInclude Include="curl\lib\pop3.h" />
<ClInclude Include="curl\lib\progress.h" />
<ClInclude Include="curl\lib\protocol.h" />
<ClInclude Include="curl\lib\proxy.h" />
<ClInclude Include="curl\lib\psl.h" />
<ClInclude Include="curl\lib\rand.h" />
<ClInclude Include="curl\lib\ratelimit.h" />
<ClInclude Include="curl\lib\request.h" />
<ClInclude Include="curl\lib\rtsp.h" />
<ClInclude Include="curl\lib\select.h" />
<ClInclude Include="curl\lib\sendf.h" />
<ClInclude Include="curl\lib\setopt.h" />
<ClInclude Include="curl\lib\setup-os400.h" />
<ClInclude Include="curl\lib\setup-vms.h" />
<ClInclude Include="curl\lib\setup-win32.h" />
<ClInclude Include="curl\lib\sigpipe.h" />
<ClInclude Include="curl\lib\slist.h" />
<ClInclude Include="curl\lib\smb.h" />
<ClInclude Include="curl\lib\smtp.h" />
<ClInclude Include="curl\lib\sockaddr.h" />
<ClInclude Include="curl\lib\socketpair.h" />
<ClInclude Include="curl\lib\socks.h" />
<ClInclude Include="curl\lib\splay.h" />
<ClInclude Include="curl\lib\strcase.h" />
<ClInclude Include="curl\lib\strdup.h" />
<ClInclude Include="curl\lib\strerror.h" />
<ClInclude Include="curl\lib\strtok.h" />
<ClInclude Include="curl\lib\strtoofft.h" />
<ClInclude Include="curl\lib\system_win32.h" />
<ClInclude Include="curl\lib\telnet.h" />
<ClInclude Include="curl\lib\tftp.h" />
<ClInclude Include="curl\lib\thrdpool.h" />
<ClInclude Include="curl\lib\thrdqueue.h" />
<ClInclude Include="curl\lib\transfer.h" />
<ClInclude Include="curl\lib\uint-bset.h" />
<ClInclude Include="curl\lib\uint-hash.h" />
<ClInclude Include="curl\lib\uint-spbset.h" />
<ClInclude Include="curl\lib\uint-table.h" />
<ClInclude Include="curl\lib\url.h" />
<ClInclude Include="curl\lib\urlapi-int.h" />
<ClInclude Include="curl\lib\urldata.h" />
<ClInclude Include="curl\lib\vquic\capsule.h" />
<ClInclude Include="curl\lib\vquic\cf-capsule.h" />
<ClInclude Include="curl\lib\vquic\cf-ngtcp2-cmn.h" />
<ClInclude Include="curl\lib\vquic\cf-ngtcp2-proxy.h" />
<ClInclude Include="curl\lib\vquic\cf-ngtcp2.h" />
<ClInclude Include="curl\lib\vquic\cf-quiche.h" />
<ClInclude Include="curl\lib\vquic\vquic-tls.h" />
<ClInclude Include="curl\lib\vquic\vquic_int.h" />
<ClInclude Include="curl\lib\vssh\vssh.h" />
<ClInclude Include="curl\lib\vtls\apple.h" />
<ClInclude Include="curl\lib\vtls\cipher_suite.h" />
<ClInclude Include="curl\lib\vtls\hostcheck.h" />
<ClInclude Include="curl\lib\vtls\rustls.h" />
<ClInclude Include="curl\lib\vtls\schannel_int.h" />
<ClInclude Include="curl\lib\vtls\vtls_config.h" />
<ClInclude Include="curl\lib\vtls\vtls_int.h" />
<ClInclude Include="curl\lib\vtls\vtls_scache.h" />
<ClInclude Include="curl\lib\vtls\vtls_spack.h" />
<ClInclude Include="curl\lib\vtls\x509asn1.h" />
<ClInclude Include="curl\lib\vauth\digest.h" />
<ClInclude Include="curl\lib\vauth\ntlm.h" />
<ClInclude Include="curl\lib\vauth\vauth.h" />
<ClInclude Include="curl\lib\vquic\vquic.h" />
<ClInclude Include="curl\lib\vssh\ssh.h" />
<ClInclude Include="curl\lib\vtls\gtls.h" />
<ClInclude Include="curl\lib\vtls\keylog.h" />
<ClInclude Include="curl\lib\vtls\mbedtls.h" />
<ClInclude Include="curl\lib\vtls\openssl.h" />
<ClInclude Include="curl\lib\vtls\schannel.h" />
<ClInclude Include="curl\lib\vtls\vtls.h" />
<ClInclude Include="curl\lib\vtls\wolfssl.h" />
<ClInclude Include="curl\lib\ws.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="curl\lib\libcurl.rc" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
File diff suppressed because it is too large Load Diff
-4
View File
@@ -15,9 +15,7 @@
<ClInclude Include="fusion\Fusion\FusionAhrs.h" />
<ClInclude Include="fusion\Fusion\FusionBias.h" />
<ClInclude Include="fusion\Fusion\FusionCompass.h" />
<ClInclude Include="fusion\Fusion\FusionConfig.h" />
<ClInclude Include="fusion\Fusion\FusionConvention.h" />
<ClInclude Include="fusion\Fusion\FusionInline.h" />
<ClInclude Include="fusion\Fusion\FusionMath.h" />
<ClInclude Include="fusion\Fusion\FusionModel.h" />
<ClInclude Include="fusion\Fusion\FusionRemap.h" />
@@ -26,8 +24,6 @@
<ClCompile Include="fusion\Fusion\FusionAhrs.c" />
<ClCompile Include="fusion\Fusion\FusionBias.c" />
<ClCompile Include="fusion\Fusion\FusionCompass.c" />
<ClCompile Include="fusion\Fusion\FusionConvention.c" />
<ClCompile Include="fusion\Fusion\FusionRemap.c" />
</ItemGroup>
<PropertyGroup Label="Globals">
<RootNamespace>Fusion</RootNamespace>
-8
View File
@@ -14,8 +14,6 @@
<ClInclude Include="fusion\Fusion\FusionBias.h" />
<ClInclude Include="fusion\Fusion\FusionModel.h" />
<ClInclude Include="fusion\Fusion\FusionRemap.h" />
<ClInclude Include="fusion\Fusion\FusionConfig.h" />
<ClInclude Include="fusion\Fusion\FusionInline.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="fusion\Fusion\FusionAhrs.c">
@@ -27,11 +25,5 @@
<ClCompile Include="fusion\Fusion\FusionBias.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="fusion\Fusion\FusionConvention.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="fusion\Fusion\FusionRemap.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>
+14 -39
View File
@@ -37,46 +37,19 @@
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros">
<CmakeGenerator>"Visual Studio $(VisualStudioVersion.Substring(0,2))"</CmakeGenerator>
<CmakeReleaseCLI>call vsdevcmd.bat -arch=amd64
cd "$(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)"
if not defined CCACHE_LAUNCH_ARGS set CCACHE_LAUNCH_ARGS=
cmake -G Ninja ^
-DCMAKE_CXX_COMPILER="cl.exe" ^
-DCMAKE_C_COMPILER="cl.exe" ^
%25CCACHE_LAUNCH_ARGS%25 ^
-DCMAKE_BUILD_TYPE="Release" ^
-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded ^
-DGLSLANG_TESTS=OFF ^
-DENABLE_GLSLANG_BINARIES=OFF ^
-DBUILD_EXTERNAL=OFF ^
-DENABLE_SPVREMAPPER=OFF ^
-DENABLE_HLSL=OFF ^
-DENABLE_OPT=OFF ^
-S "$(SolutionDir)3rdparty\glslang\glslang"
cmake -G $(CmakeGenerator) -A x64 -DCMAKE_BUILD_TYPE="Release" -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded -DGLSLANG_TESTS=OFF -DENABLE_GLSLANG_BINARIES=OFF -DBUILD_EXTERNAL=OFF -DENABLE_SPVREMAPPER=OFF -DENABLE_HLSL=OFF -DENABLE_OPT=OFF -S glslang -B "$(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)"
</CmakeReleaseCLI>
<CmakeDebugCLI>call vsdevcmd.bat -arch=amd64
cd "$(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)"
if not defined CCACHE_LAUNCH_ARGS set CCACHE_LAUNCH_ARGS=
cmake -G Ninja ^
-DCMAKE_CXX_COMPILER="cl.exe" ^
-DCMAKE_C_COMPILER="cl.exe" ^
%25CCACHE_LAUNCH_ARGS%25 ^
-DCMAKE_BUILD_TYPE="Debug" ^
-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDebug ^
-DGLSLANG_TESTS=OFF ^
-DENABLE_GLSLANG_BINARIES=OFF ^
-DBUILD_EXTERNAL=OFF ^
-DENABLE_SPVREMAPPER=OFF ^
-DENABLE_HLSL=OFF ^
-DENABLE_OPT=OFF ^
-S "$(SolutionDir)3rdparty\glslang\glslang"
cmake -G $(CmakeGenerator) -A x64 -DCMAKE_BUILD_TYPE="Debug" -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDebug -DGLSLANG_TESTS=OFF -DENABLE_GLSLANG_BINARIES=OFF -DBUILD_EXTERNAL=OFF -DENABLE_SPVREMAPPER=OFF -DENABLE_HLSL=OFF -DENABLE_OPT=OFF -S glslang -B "$(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)"
</CmakeDebugCLI>
<CmakeCopyCLI>
echo Copying..
mkdir "$(SolutionDir)build\lib\$(Configuration)-$(Platform)\$(ProjectName)"
copy "$(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)\SPIRV\*.lib" "$(SolutionDir)build\lib\$(Configuration)-$(Platform)\$(ProjectName)"
copy "$(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)\glslang\OSDependent\Windows\*.lib" "$(SolutionDir)build\lib\$(Configuration)-$(Platform)\$(ProjectName)"
copy "$(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)\glslang\*.lib" "$(SolutionDir)build\lib\$(Configuration)-$(Platform)\$(ProjectName)"
copy "$(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)\SPIRV\$(CONFIGURATION)\*.lib" "$(SolutionDir)build\lib\$(Configuration)-$(Platform)\$(ProjectName)"
copy "$(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)\glslang\OSDependent\Windows\$(CONFIGURATION)\*.lib" "$(SolutionDir)build\lib\$(Configuration)-$(Platform)\$(ProjectName)"
copy "$(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)\glslang\$(CONFIGURATION)\*.lib" "$(SolutionDir)build\lib\$(Configuration)-$(Platform)\$(ProjectName)"
</CmakeCopyCLI>
<CmakeCleanCLI>
echo Cleaning..
@@ -90,16 +63,17 @@
<IntDir>$(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)\</IntDir>
<NMakeBuildCommandLine>
$(CmakeReleaseCLI)
ninja
msbuild.exe "$(IntDir)\ALL_BUILD.vcxproj" /t:build /p:Configuration=Release /p:ForceImportBeforeCppTargets="$(PropsAbsPath)" /m
$(CmakeCopyCLI)
</NMakeBuildCommandLine>
<NMakeReBuildCommandLine>
$(CmakeCleanCLI)
$(CmakeReleaseCLI)
ninja
msbuild.exe "$(IntDir)\ALL_BUILD.vcxproj" /t:rebuild /p:Configuration=Release /p:ForceImportBeforeCppTargets="$(PropsAbsPath)" /m
$(CmakeCopyCLI)
</NMakeReBuildCommandLine>
<NMakeCleanCommandLine>
$(CmakeReleaseCLI)
msbuild.exe "$(IntDir)\ALL_BUILD.vcxproj" /t:clean /p:Configuration=Release /p:ForceImportBeforeCppTargets="$(PropsAbsPath)" /m
$(CmakeCleanCLI)
</NMakeCleanCommandLine>
</PropertyGroup>
@@ -108,16 +82,17 @@
<IntDir>$(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)\</IntDir>
<NMakeBuildCommandLine>
$(CmakeDebugCLI)
ninja
msbuild.exe "$(IntDir)\ALL_BUILD.vcxproj" /t:build /p:Configuration=Debug /p:ForceImportBeforeCppTargets="$(PropsAbsPath)" /m
$(CmakeCopyCLI)
</NMakeBuildCommandLine>
<NMakeReBuildCommandLine>
$(CmakeCleanCLI)
$(CmakeDebugCLI)
ninja
msbuild.exe "$(IntDir)\ALL_BUILD.vcxproj" /t:rebuild /p:Configuration=Debug /p:ForceImportBeforeCppTargets="$(PropsAbsPath)" /m
$(CmakeCopyCLI)
</NMakeReBuildCommandLine>
<NMakeCleanCommandLine>
$(CmakeDebugCLI)
msbuild.exe "$(IntDir)\ALL_BUILD.vcxproj" /t:clean /p:Configuration=Debug /p:ForceImportBeforeCppTargets="$(PropsAbsPath)" /m
$(CmakeCleanCLI)
</NMakeCleanCommandLine>
</PropertyGroup>
+2
View File
@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" />
+1 -1
View File
@@ -51,7 +51,7 @@ if(WITH_LLVM)
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)
find_package(LLVM 22.1 CONFIG)
find_package(LLVM 19.1 CONFIG)
if(NOT LLVM_FOUND)
message(FATAL_ERROR "Couldn't build LLVM from the submodule. You might need to run `git submodule update --init`")
endif()
+2 -56
View File
@@ -40,65 +40,11 @@
<PropertyGroup Label="UserMacros">
<CmakeReleaseCLI>call vsdevcmd.bat -arch=amd64
cd "$(SolutionDir)build\tmp\llvm_build-$(Configuration)-$(Platform)"
cmake -G Ninja ^
-DCMAKE_CXX_COMPILER="cl.exe" ^
-DCMAKE_C_COMPILER="cl.exe" ^
-DCMAKE_BUILD_TYPE="Release" ^
-DCMAKE_INSTALL_PREFIX="$(SolutionDir)build\lib\$(Configuration)-$(Platform)\llvm_build" ^
-DCMAKE_SYSTEM_VERSION=10.0 ^
-DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) ^
-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded ^
-DLLVM_TARGETS_TO_BUILD=X86 ^
-DLLVM_DEFAULT_TARGET_TRIPLE:STRING=x86_64-pc-windows-msvc ^
-DLLVM_HOST_TRIPLE:STRING=x86_64-pc-windows-msvc ^
-DLLVM_BUILD_RUNTIME=OFF ^
-DLLVM_BUILD_TOOLS=OFF ^
-DLLVM_BUILD_BENCHMARKS=OFF ^
-DLLVM_BUILD_DOCS=OFF ^
-DLLVM_BUILD_EXAMPLES=OFF ^
-DLLVM_BUILD_TESTS=OFF ^
-DLLVM_INCLUDE_TOOLS=OFF ^
-DLLVM_INCLUDE_DOCS=OFF ^
-DLLVM_INCLUDE_EXAMPLES=OFF ^
-DLLVM_INCLUDE_TESTS=OFF ^
-DLLVM_INCLUDE_BENCHMARKS=OFF ^
-DLLVM_INCLUDE_UTILS=OFF ^
-DLLVM_INSTALL_UTILS=OFF ^
-DLLVM_ENABLE_DIA_SDK=OFF ^
-DLLVM_ENABLE_PDB=OFF ^
-DLLVM_USE_INTEL_JITEVENTS=ON ^
"$(SolutionDir)3rdparty\llvm\llvm\llvm"
cmake -G Ninja -DCMAKE_CXX_COMPILER="cl.exe" -DCMAKE_C_COMPILER="cl.exe" -DCMAKE_BUILD_TYPE="Release" -DCMAKE_INSTALL_PREFIX="$(SolutionDir)build\lib\$(Configuration)-$(Platform)\llvm_build" -DCMAKE_SYSTEM_VERSION=10.0 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_DEFAULT_TARGET_TRIPLE:STRING=x86_64-pc-windows-msvc -DLLVM_HOST_TRIPLE:STRING=x86_64-pc-windows-msvc -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_BUILD_BENCHMARKS=OFF -DLLVM_BUILD_DOCS=OFF -DLLVM_BUILD_EXAMPLES=OFF -DLLVM_BUILD_TESTS=OFF\ -DLLVM_INCLUDE_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_BENCHMARKS=OFF -DLLVM_INCLUDE_UTILS=OFF -DLLVM_INSTALL_UTILS=OFF -DLLVM_ENABLE_DIA_SDK=OFF -DLLVM_ENABLE_PDB=OFF -DLLVM_USE_INTEL_JITEVENTS=ON "$(SolutionDir)3rdparty\llvm\llvm\llvm"
</CmakeReleaseCLI>
<CmakeDebugCLI>call vsdevcmd.bat -arch=amd64
cd "$(SolutionDir)build\tmp\llvm_build-$(Configuration)-$(Platform)"
cmake -G Ninja ^
-DCMAKE_CXX_COMPILER="cl.exe" ^
-DCMAKE_C_COMPILER="cl.exe" ^
-DCMAKE_BUILD_TYPE="Debug" ^
-DCMAKE_INSTALL_PREFIX="$(SolutionDir)build\lib\$(Configuration)-$(Platform)\llvm_build" ^
-DCMAKE_SYSTEM_VERSION=10.0 ^
-DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) ^
-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDebugDLL ^
-DLLVM_TARGETS_TO_BUILD=X86 ^
-DLLVM_DEFAULT_TARGET_TRIPLE:STRING=x86_64-pc-windows-msvc ^
-DLLVM_HOST_TRIPLE:STRING=x86_64-pc-windows-msvc ^
-DLLVM_BUILD_RUNTIME=OFF ^
-DLLVM_BUILD_TOOLS=OFF ^
-DLLVM_BUILD_BENCHMARKS=OFF ^
-DLLVM_BUILD_DOCS=OFF ^
-DLLVM_BUILD_EXAMPLES=OFF ^
-DLLVM_BUILD_TESTS=OFF ^
-DLLVM_INCLUDE_TOOLS=OFF ^
-DLLVM_INCLUDE_DOCS=OFF ^
-DLLVM_INCLUDE_EXAMPLES=OFF ^
-DLLVM_INCLUDE_TESTS=OFF ^
-DLLVM_INCLUDE_BENCHMARKS=OFF ^
-DLLVM_INCLUDE_UTILS=OFF ^
-DLLVM_INSTALL_UTILS=OFF ^
-DLLVM_ENABLE_DIA_SDK=OFF ^
-DLLVM_ENABLE_PDB=OFF ^
-DLLVM_USE_INTEL_JITEVENTS=ON ^
"$(SolutionDir)3rdparty\llvm\llvm\llvm"
cmake -G Ninja -DCMAKE_CXX_COMPILER="cl.exe" -DCMAKE_C_COMPILER="cl.exe" -DCMAKE_BUILD_TYPE="Debug" -DCMAKE_INSTALL_PREFIX="$(SolutionDir)build\lib\$(Configuration)-$(Platform)\llvm_build" -DCMAKE_SYSTEM_VERSION=10.0 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDebugDLL -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_DEFAULT_TARGET_TRIPLE:STRING=x86_64-pc-windows-msvc -DLLVM_HOST_TRIPLE:STRING=x86_64-pc-windows-msvc -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_BUILD_BENCHMARKS=OFF -DLLVM_BUILD_DOCS=OFF -DLLVM_BUILD_EXAMPLES=OFF -DLLVM_BUILD_TESTS=OFF\ -DLLVM_INCLUDE_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_BENCHMARKS=OFF -DLLVM_INCLUDE_UTILS=OFF -DLLVM_INSTALL_UTILS=OFF -DLLVM_ENABLE_DIA_SDK=OFF -DLLVM_ENABLE_PDB=OFF -DLLVM_USE_INTEL_JITEVENTS=ON "$(SolutionDir)3rdparty\llvm\llvm\llvm"
</CmakeDebugCLI>
<CmakeCleanCLI>
echo Cleaning..
+2 -56
View File
@@ -40,65 +40,11 @@
<PropertyGroup Label="UserMacros">
<CmakeReleaseCLI>call vsdevcmd.bat -arch=amd64
cd "$(SolutionDir)build\tmp\llvm_build-$(Configuration)-$(Platform)"
cmake -G Ninja ^
-DCMAKE_CXX_COMPILER="clang-cl.exe" ^
-DCMAKE_C_COMPILER="clang-cl.exe" ^
-DCMAKE_BUILD_TYPE="Release" ^
-DCMAKE_INSTALL_PREFIX="$(SolutionDir)build\lib\$(Configuration)-$(Platform)\llvm_build" ^
-DCMAKE_SYSTEM_VERSION=10.0 ^
-DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) ^
-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded ^
-DLLVM_TARGETS_TO_BUILD=X86 ^
-DLLVM_DEFAULT_TARGET_TRIPLE:STRING=x86_64-pc-windows-msvc ^
-DLLVM_HOST_TRIPLE:STRING=x86_64-pc-windows-msvc ^
-DLLVM_BUILD_RUNTIME=OFF ^
-DLLVM_BUILD_TOOLS=OFF ^
-DLLVM_BUILD_BENCHMARKS=OFF ^
-DLLVM_BUILD_DOCS=OFF ^
-DLLVM_BUILD_EXAMPLES=OFF ^
-DLLVM_BUILD_TESTS=OFF ^
-DLLVM_INCLUDE_TOOLS=OFF ^
-DLLVM_INCLUDE_DOCS=OFF ^
-DLLVM_INCLUDE_EXAMPLES=OFF ^
-DLLVM_INCLUDE_TESTS=OFF ^
-DLLVM_INCLUDE_BENCHMARKS=OFF ^
-DLLVM_INCLUDE_UTILS=OFF ^
-DLLVM_INSTALL_UTILS=OFF ^
-DLLVM_ENABLE_DIA_SDK=OFF ^
-DLLVM_ENABLE_PDB=OFF ^
-DLLVM_USE_INTEL_JITEVENTS=ON ^
"$(SolutionDir)3rdparty\llvm\llvm\llvm"
cmake -G Ninja -DCMAKE_CXX_COMPILER="clang-cl.exe" -DCMAKE_C_COMPILER="clang-cl.exe" -DCMAKE_BUILD_TYPE="Release" -DCMAKE_INSTALL_PREFIX="$(SolutionDir)build\lib\$(Configuration)-$(Platform)\llvm_build" -DCMAKE_SYSTEM_VERSION=10.0 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_DEFAULT_TARGET_TRIPLE:STRING=x86_64-pc-windows-msvc -DLLVM_HOST_TRIPLE:STRING=x86_64-pc-windows-msvc -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_BUILD_BENCHMARKS=OFF -DLLVM_BUILD_DOCS=OFF -DLLVM_BUILD_EXAMPLES=OFF -DLLVM_BUILD_TESTS=OFF\ -DLLVM_INCLUDE_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_BENCHMARKS=OFF -DLLVM_INCLUDE_UTILS=OFF -DLLVM_INSTALL_UTILS=OFF -DLLVM_ENABLE_DIA_SDK=OFF -DLLVM_ENABLE_PDB=OFF -DLLVM_USE_INTEL_JITEVENTS=ON "$(SolutionDir)3rdparty\llvm\llvm\llvm"
</CmakeReleaseCLI>
<CmakeDebugCLI>call vsdevcmd.bat -arch=amd64
cd "$(SolutionDir)build\tmp\llvm_build-$(Configuration)-$(Platform)"
cmake -G Ninja ^
-DCMAKE_CXX_COMPILER="clang-cl.exe" ^
-DCMAKE_C_COMPILER="clang-cl.exe" ^
-DCMAKE_BUILD_TYPE="Debug" ^
-DCMAKE_INSTALL_PREFIX="$(SolutionDir)build\lib\$(Configuration)-$(Platform)\llvm_build" ^
-DCMAKE_SYSTEM_VERSION=10.0 ^
-DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) ^
-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDebugDLL ^
-DLLVM_TARGETS_TO_BUILD=X86 ^
-DLLVM_DEFAULT_TARGET_TRIPLE:STRING=x86_64-pc-windows-msvc ^
-DLLVM_HOST_TRIPLE:STRING=x86_64-pc-windows-msvc ^
-DLLVM_BUILD_RUNTIME=OFF ^
-DLLVM_BUILD_TOOLS=OFF ^
-DLLVM_BUILD_BENCHMARKS=OFF ^
-DLLVM_BUILD_DOCS=OFF ^
-DLLVM_BUILD_EXAMPLES=OFF ^
-DLLVM_BUILD_TESTS=OFF ^
-DLLVM_INCLUDE_TOOLS=OFF ^
-DLLVM_INCLUDE_DOCS=OFF ^
-DLLVM_INCLUDE_EXAMPLES=OFF ^
-DLLVM_INCLUDE_TESTS=OFF ^
-DLLVM_INCLUDE_BENCHMARKS=OFF ^
-DLLVM_INCLUDE_UTILS=OFF ^
-DLLVM_INSTALL_UTILS=OFF ^
-DLLVM_ENABLE_DIA_SDK=OFF ^
-DLLVM_ENABLE_PDB=OFF ^
-DLLVM_USE_INTEL_JITEVENTS=ON ^
"$(SolutionDir)3rdparty\llvm\llvm\llvm"
cmake -G Ninja -DCMAKE_CXX_COMPILER="clang-cl.exe" -DCMAKE_C_COMPILER="clang-cl.exe" -DCMAKE_BUILD_TYPE="Debug" -DCMAKE_INSTALL_PREFIX="$(SolutionDir)build\lib\$(Configuration)-$(Platform)\llvm_build" -DCMAKE_SYSTEM_VERSION=10.0 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDebugDLL -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_DEFAULT_TARGET_TRIPLE:STRING=x86_64-pc-windows-msvc -DLLVM_HOST_TRIPLE:STRING=x86_64-pc-windows-msvc -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_BUILD_BENCHMARKS=OFF -DLLVM_BUILD_DOCS=OFF -DLLVM_BUILD_EXAMPLES=OFF -DLLVM_BUILD_TESTS=OFF\ -DLLVM_INCLUDE_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_BENCHMARKS=OFF -DLLVM_INCLUDE_UTILS=OFF -DLLVM_INSTALL_UTILS=OFF -DLLVM_ENABLE_DIA_SDK=OFF -DLLVM_ENABLE_PDB=OFF -DLLVM_USE_INTEL_JITEVENTS=ON "$(SolutionDir)3rdparty\llvm\llvm\llvm"
</CmakeDebugCLI>
<CmakeCleanCLI>
echo Cleaning..
+53 -63
View File
@@ -56,63 +56,6 @@ namespace pine
typedef unsigned long long SOCKET;
#ifndef _WIN32
inline std::string get_socket_path(std::string_view file_name, int slot, int default_slot)
{
#ifdef __APPLE__
const char* runtime_dir = std::getenv("TMPDIR");
#else
const char* runtime_dir = std::getenv("XDG_RUNTIME_DIR");
#endif
// fallback in case macOS or other OSes don't implement the XDG base
// spec
std::string path = runtime_dir ? std::string(runtime_dir) + '/' : std::string("/tmp/");
path += file_name;
if (slot != default_slot)
{
fmt::append(path, ".%d", slot);
}
return path;
}
#endif
#ifdef _WIN32
inline const char* bind_and_listen(SOCKET sock, u16 port)
{
const int exclusive = 1;
if (setsockopt(sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, reinterpret_cast<const char*>(&exclusive), sizeof(exclusive)) != 0)
return "setsockopt(SO_EXCLUSIVEADDRUSE) failed";
sockaddr_in server{};
server.sin_family = AF_INET;
server.sin_port = htons(port);
if (inet_pton(AF_INET, "127.0.0.1", &server.sin_addr.s_addr) != 1)
return "inet_pton failed";
#else
inline const char* bind_and_listen(int sock, const std::string& socket_path)
{
sockaddr_un server{};
if (socket_path.size() >= sizeof(server.sun_path))
return "socket path is too long";
server.sun_family = AF_UNIX;
std::memcpy(server.sun_path, socket_path.c_str(), socket_path.size() + 1);
unlink(socket_path.c_str());
#endif
if (bind(sock, reinterpret_cast<sockaddr*>(&server), sizeof(server)) != 0)
return "bind failed";
if (listen(sock, 4096) != 0)
return "listen failed";
return nullptr;
}
template<typename Impl>
class pine_server : public Impl
{
@@ -585,6 +528,7 @@ namespace pine
{
#ifdef _WIN32
WSADATA wsa {};
struct sockaddr_in server {};
m_sock = INVALID_SOCKET;
m_msgsock = INVALID_SOCKET;
@@ -600,9 +544,45 @@ namespace pine
return;
}
const char* failure = bind_and_listen(m_sock, static_cast<u16>(Impl::get_port()));
// yes very good windows s/sun/sin/g sure is fine
server.sin_family = AF_INET;
// localhost only
if (!inet_pton(server.sin_family, "127.0.0.1", &server.sin_addr.s_addr))
{
fmt::throw_exception("IPC: Failed to convert localhost");
}
server.sin_port = htons(Impl::get_port());
if (bind(m_sock, reinterpret_cast<struct sockaddr*>(&server), sizeof(server)) == SOCKET_ERROR)
{
Impl::error("IPC: Error while binding to socket! Shutting down...");
return;
}
#else
m_socket_name = get_socket_path("rpcs3.sock", Impl::get_port(), IPC_DEFAULT_SLOT);
char* runtime_dir = nullptr;
#ifdef __APPLE__
runtime_dir = std::getenv("TMPDIR");
#else
runtime_dir = std::getenv("XDG_RUNTIME_DIR");
#endif
// fallback in case macOS or other OSes don't implement the XDG base
// spec
if (runtime_dir == nullptr)
m_socket_name = "/tmp/rpcs3.sock";
else
{
m_socket_name = runtime_dir;
m_socket_name += "/rpcs3.sock";
}
const int slot = Impl::get_port();
if (slot != IPC_DEFAULT_SLOT)
{
fmt::append(m_socket_name, ".%d", slot);
}
struct sockaddr_un server {};
m_sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (m_sock < 0)
@@ -610,13 +590,23 @@ namespace pine
Impl::error("IPC: Cannot open socket! Shutting down...");
return;
}
server.sun_family = AF_UNIX;
strcpy(server.sun_path, m_socket_name.c_str());
const char* failure = bind_and_listen(m_sock, m_socket_name);
#endif
if (failure)
// we unlink the socket so that when releasing this thread the socket gets
// freed even if we didn't close correctly the loop
unlink(m_socket_name.c_str());
if (bind(m_sock, std::bit_cast<struct sockaddr*>(&server), sizeof(struct sockaddr_un)))
{
Impl::error("IPC: Error while setting up socket (%s)! Shutting down...", failure);
Impl::error("IPC: Error while binding to socket! Shutting down...");
return;
}
#endif
// maximum queue of 4096 commands before refusing, approximated to the
// nearest legal value. We do not use SOMAXCONN as windows have this idea
// that a "reasonable" value is 5, which is not.
listen(m_sock, 4096);
}
pine_server(const pine_server&) = delete;
+2 -48
View File
@@ -41,58 +41,12 @@
<CmakeReleaseCLI>call vsdevcmd.bat -arch=amd64
if not exist "$(SolutionDir)build\tmp\protobuf_build-$(Configuration)-$(Platform)" mkdir "$(SolutionDir)build\tmp\protobuf_build-$(Configuration)-$(Platform)"
cd "$(SolutionDir)build\tmp\protobuf_build-$(Configuration)-$(Platform)"
if not defined CCACHE_LAUNCH_ARGS set CCACHE_LAUNCH_ARGS=
cmake -G Ninja ^
-DCMAKE_CXX_COMPILER="cl.exe" ^
-DCMAKE_C_COMPILER="cl.exe" ^
%25CCACHE_LAUNCH_ARGS%25 ^
-DCMAKE_CXX_STANDARD=20 ^
-DCMAKE_BUILD_TYPE="Release" ^
-DCMAKE_INSTALL_PREFIX="$(SolutionDir)build\lib\$(Configuration)-$(Platform)\protobuf_build" ^
-DCMAKE_SYSTEM_VERSION=10.0 ^
-DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) ^
-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded ^
-Dprotobuf_INSTALL=ON ^
-Dprotobuf_BUILD_TESTS=OFF ^
-Dprotobuf_BUILD_CONFORMANCE=OFF ^
-Dprotobuf_BUILD_EXAMPLES=OFF ^
-Dprotobuf_BUILD_PROTOBUF_BINARIES=ON ^
-Dprotobuf_BUILD_PROTOC_BINARIES=OFF ^
-Dprotobuf_BUILD_LIBPROTOC=OFF ^
-Dprotobuf_BUILD_LIBUPB=OFF ^
-Dprotobuf_ALLOW_CCACHE=ON ^
-Dprotobuf_FORCE_FETCH_DEPENDENCIES=ON ^
-Dprotobuf_WITH_ZLIB=OFF ^
-Dprotobuf_MSVC_STATIC_RUNTIME=ON ^
"$(SolutionDir)3rdparty\protobuf\protobuf"
cmake -G Ninja -DCMAKE_CXX_COMPILER="cl.exe" -DCMAKE_C_COMPILER="cl.exe" -DCMAKE_CXX_STANDARD=20 -DCMAKE_BUILD_TYPE="Release" -DCMAKE_INSTALL_PREFIX="$(SolutionDir)build\lib\$(Configuration)-$(Platform)\protobuf_build" -DCMAKE_SYSTEM_VERSION=10.0 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded -Dprotobuf_INSTALL=ON -Dprotobuf_BUILD_TESTS=OFF -Dprotobuf_BUILD_CONFORMANCE=OFF -Dprotobuf_BUILD_EXAMPLES=OFF -Dprotobuf_BUILD_PROTOBUF_BINARIES=ON -Dprotobuf_BUILD_PROTOC_BINARIES=OFF -Dprotobuf_BUILD_LIBPROTOC=OFF -Dprotobuf_BUILD_LIBUPB=OFF -Dprotobuf_ALLOW_CCACHE=ON -Dprotobuf_FORCE_FETCH_DEPENDENCIES=ON -Dprotobuf_WITH_ZLIB=OFF -Dprotobuf_MSVC_STATIC_RUNTIME=ON "$(SolutionDir)3rdparty\protobuf\protobuf"
</CmakeReleaseCLI>
<CmakeDebugCLI>call vsdevcmd.bat -arch=amd64
if not exist "$(SolutionDir)build\tmp\protobuf_build-$(Configuration)-$(Platform)" mkdir "$(SolutionDir)build\tmp\protobuf_build-$(Configuration)-$(Platform)"
cd "$(SolutionDir)build\tmp\protobuf_build-$(Configuration)-$(Platform)"
if not defined CCACHE_LAUNCH_ARGS set CCACHE_LAUNCH_ARGS=
cmake -G Ninja ^
-DCMAKE_CXX_COMPILER="cl.exe" ^
-DCMAKE_C_COMPILER="cl.exe" ^
%25CCACHE_LAUNCH_ARGS%25 ^
-DCMAKE_CXX_STANDARD=20 ^
-DCMAKE_BUILD_TYPE="Debug" ^
-DCMAKE_INSTALL_PREFIX="$(SolutionDir)build\lib\$(Configuration)-$(Platform)\protobuf_build" ^
-DCMAKE_SYSTEM_VERSION=10.0 ^
-DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) ^
-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDebugDLL ^
-Dprotobuf_INSTALL=ON ^
-Dprotobuf_BUILD_TESTS=OFF ^
-Dprotobuf_BUILD_CONFORMANCE=OFF ^
-Dprotobuf_BUILD_EXAMPLES=OFF ^
-Dprotobuf_BUILD_PROTOBUF_BINARIES=ON ^
-Dprotobuf_BUILD_PROTOC_BINARIES=OFF ^
-Dprotobuf_BUILD_LIBPROTOC=OFF ^
-Dprotobuf_BUILD_LIBUPB=OFF ^
-Dprotobuf_ALLOW_CCACHE=ON ^
-Dprotobuf_FORCE_FETCH_DEPENDENCIES=ON ^
-Dprotobuf_WITH_ZLIB=OFF ^
-Dprotobuf_MSVC_STATIC_RUNTIME=OFF ^
"$(SolutionDir)3rdparty\protobuf\protobuf"
cmake -G Ninja -DCMAKE_CXX_COMPILER="cl.exe" -DCMAKE_C_COMPILER="cl.exe" -DCMAKE_CXX_STANDARD=20 -DCMAKE_BUILD_TYPE="Debug" -DCMAKE_INSTALL_PREFIX="$(SolutionDir)build\lib\$(Configuration)-$(Platform)\protobuf_build" -DCMAKE_SYSTEM_VERSION=10.0 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDebugDLL -Dprotobuf_INSTALL=ON -Dprotobuf_BUILD_TESTS=OFF -Dprotobuf_BUILD_CONFORMANCE=OFF -Dprotobuf_BUILD_EXAMPLES=OFF -Dprotobuf_BUILD_PROTOBUF_BINARIES=ON -Dprotobuf_BUILD_PROTOC_BINARIES=OFF -Dprotobuf_BUILD_LIBPROTOC=OFF -Dprotobuf_BUILD_LIBUPB=OFF -Dprotobuf_ALLOW_CCACHE=ON -Dprotobuf_FORCE_FETCH_DEPENDENCIES=ON -Dprotobuf_WITH_ZLIB=OFF -Dprotobuf_MSVC_STATIC_RUNTIME=OFF "$(SolutionDir)3rdparty\protobuf\protobuf"
</CmakeDebugCLI>
<CmakeCleanCLI>
echo Cleaning..
+2 -3
View File
@@ -4,7 +4,7 @@ if(USE_SYSTEM_WOLFSSL)
add_library(wolfssl INTERFACE)
target_link_libraries(wolfssl INTERFACE PkgConfig::WolfSSL)
else()
set(WOLFSSL_TLS13 ON CACHE INTERNAL "" FORCE)
set(WOLFSSL_TLS13 OFF CACHE INTERNAL "")
set(WOLFSSL_SHA3 ON CACHE INTERNAL "")
set(WOLFSSL_SHAKE256 ON CACHE INTERNAL "")
set(WOLFSSL_BASE64_ENCODE OFF CACHE INTERNAL "")
@@ -21,6 +21,5 @@ else()
add_subdirectory(wolfssl EXCLUDE_FROM_ALL)
target_compile_definitions(wolfssl PUBLIC WOLFSSL_DES_ECB HAVE_WRITE_DUP FP_MAX_BITS=8192)
target_compile_definitions(wolfssl INTERFACE WOLFSSL_USE_OPTIONS_H)
target_compile_definitions(wolfssl PUBLIC WOLFSSL_DES_ECB HAVE_WRITE_DUP FP_MAX_BITS=8192 WOLFSSL_USE_OPTIONS_H)
endif()
-4
View File
@@ -86,21 +86,17 @@
<ClCompile Include="wolfssl\src\ssl_api_crl_ocsp.c" />
<ClCompile Include="wolfssl\src\ssl_api_dtls.c" />
<ClCompile Include="wolfssl\src\ssl_api_ext.c" />
<ClCompile Include="wolfssl\src\ssl_api_hs.c" />
<ClCompile Include="wolfssl\src\ssl_api_pk.c" />
<ClCompile Include="wolfssl\src\ssl_api_rw.c" />
<ClCompile Include="wolfssl\src\ssl_asn1.c" />
<ClCompile Include="wolfssl\src\ssl_bn.c" />
<ClCompile Include="wolfssl\src\ssl_certman.c" />
<ClCompile Include="wolfssl\src\ssl_crypto.c" />
<ClCompile Include="wolfssl\src\ssl_ech.c" />
<ClCompile Include="wolfssl\src\ssl_err.c" />
<ClCompile Include="wolfssl\src\ssl_load.c" />
<ClCompile Include="wolfssl\src\ssl_misc.c" />
<ClCompile Include="wolfssl\src\ssl_p7p12.c" />
<ClCompile Include="wolfssl\src\ssl_sess.c" />
<ClCompile Include="wolfssl\src\ssl_sk.c" />
<ClCompile Include="wolfssl\src\ssl_tsp.c" />
<ClCompile Include="wolfssl\src\wolfio.c" />
<ClCompile Include="wolfssl\src\keys.c" />
<ClCompile Include="wolfssl\src\ocsp.c" />
+14 -23
View File
@@ -20,26 +20,26 @@ The following tools are required to build RPCS3 on Windows 10 or later:
with standalone **CMake** tool.
- [Python 3.6+](https://www.python.org/downloads/) (add to PATH)
- [Qt 6.12.0](https://www.qt.io/download-qt-installer) In case you can't download from the official installer, you can use [Another Qt installer](https://github.com/miurahr/aqtinstall) (In that case you will need to manually add the "qtmultimedia" module when installing Qt)
- [Qt 6.11.1](https://www.qt.io/download-qt-installer) In case you can't download from the official installer, you can use [Another Qt installer](https://github.com/miurahr/aqtinstall) (In that case you will need to manually add the "qtmultimedia" module when installing Qt)
- [Vulkan SDK 1.4.341.1](https://vulkan.lunarg.com/sdk/home) (see "Install the SDK" [here](https://vulkan.lunarg.com/doc/sdk/latest/windows/getting_started.html)). Note that future SDKs may not work.
The `sln` solution available only on **Visual Studio** is the preferred building solution. It easily allows to build the **RPCS3** application in `Release` and `Debug` mode.
In order to build **RPCS3** with the `sln` solution (with **Visual Studio**), **Qt** libs need to be detected. To detect the libs:
- add and set the `QTDIR` environment variable, e.g. `<QtInstallFolder>\6.12.0\msvc2022_64\`
- add and set the `QTDIR` environment variable, e.g. `<QtInstallFolder>\6.11.1\msvc2022_64\`
- or use the [Visual Studio Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.QtVisualStudioTools2022)
**NOTE:** If you have issues with the **Visual Studio Qt Plugin**, you may want to uninstall it and install the [Legacy Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.LEGACYQtVisualStudioTools2022) instead.
In order to build **RPCS3** with the `CMake` solution (with both **Visual Studio** and standalone **CMake** tool):
- add and set the `Qt6_ROOT` environment variable to the **Qt** libs path, e.g. `<QtInstallFolder>\6.12.0\msvc2022_64\`
- add and set the `Qt6_ROOT` environment variable to the **Qt** libs path, e.g. `<QtInstallFolder>\6.11.1\msvc2022_64\`
### Linux
These are the essentials tools to build RPCS3 on Linux. Some of them can be installed through your favorite package manager:
- Clang 17+ or GCC 13+
- [CMake 3.28.0+](https://www.cmake.org/download/)
- [Qt 6.12.0](https://www.qt.io/download-qt-installer)
- [Qt 6.11.1](https://www.qt.io/download-qt-installer)
- [Vulkan SDK 1.4.341.1](https://vulkan.lunarg.com/sdk/home) (See "Install the SDK" [here](https://vulkan.lunarg.com/doc/sdk/latest/linux/getting_started.html)). Note that future SDKs may not work.
- [SDL3](https://github.com/libsdl-org/SDL/releases) (for the FAudio backend)
@@ -72,7 +72,14 @@ You can either use `update-alternatives` to setup `gcc-13`/`g++-13` as your defa
##### Vulkan SDK
For Ubuntu systems, it is strongly recommended to use the official [Linux Tarball Vulkan SDK](https://vulkan.lunarg.com/doc/view/1.4.341.0/linux/getting_started.html) which will provide a compatible Vulkan SDK to compile RPCS3. If your Vulkan SDK is older, it can lead to compilation errors.
For Ubuntu systems, it is strongly recommended to use the PPA from [LunarG](https://packages.lunarg.com/) which will provide a compatible Vulkan SDK to compile RPCS3. If your Vulkan SDK is older, it can lead to compilation errors.
```
. /etc/os-release
wget -qO - https://packages.lunarg.com/lunarg-signing-key-pub.asc | sudo apt-key add -
sudo wget -qO /etc/apt/sources.list.d/lunarg-vulkan-1.3.268-$UBUNTU_CODENAME.list https://packages.lunarg.com/vulkan/1.3.268/lunarg-vulkan-1.3.268-$UBUNTU_CODENAME.list
sudo apt update
sudo apt install vulkan-sdk
```
##### CMake
@@ -116,7 +123,7 @@ Start **Visual Studio**, click on `Open a project or solution` and select the `r
##### 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>\6.12.0\msvc2022_64`, version will fill in automatically
2) add the path to your Qt installation with compiler e.g. `<QtInstallFolder>\6.11.1\msvc2022_64`, version will fill in automatically
3) go to `Extensions->Qt VS Tools->Options->Legacy Project Format`. (Only available in the **Legacy Qt Plugin**)
4) set `Build: Run pre-build setup` to `true`. (Only available in the **Legacy Qt Plugin**)
@@ -125,7 +132,7 @@ Start **Visual Studio**, click on `Open a project or solution` and select the `r
**NOTE:** The recommended build configuration is `Release`. (On older revisions: `Release - LLVM`)
To speed up the compilation time, you may want to download and extract to `<rpcs3_root>\build\lib_ext\<$(Configuration)>-x64` (e.g. `c:\rpcs3\build\lib_ext\Release-x64`; the path needs to be created) the following precompiled lib:
- [LLVM libs](https://github.com/RPCS3/llvm-mirror/releases/download/custom-build-win-22.1.8/llvmlibs_mt.7z)
- [LLVM libs](https://github.com/RPCS3/llvm-mirror/releases/download/custom-build-win-19.1.7/llvmlibs_mt.7z)
**NOTES:**
- `<$(Configuration)>` can assume values `Release` or `Debug`.
@@ -172,22 +179,6 @@ In case you preferred to install and use the standalone **CMake** tool:
```
3) once the build is completed, the **RPCS3** application will be available under the `<rpcs3_root>\build-msvc\bin` folder
#### Building with the PowerShell script
As an alternative to building through Visual Studio, run the PowerShell helper from the repository root:
```powershell
.\scripts\win_build.ps1
```
The script locates a supported Visual Studio installation, finds Qt from `Qt6_ROOT` or a standard `C:\Qt` installation, configures a Release Ninja Multi-Config build, and then builds it. Pass `-Cores <count>` to set the parallel build count; by default it uses all logical processors:
```powershell
.\scripts\win_build.ps1 -Cores 8
```
The resulting application is placed in `<rpcs3_root>\build\bin`.
### Linux
While still in the project root:
-2
View File
@@ -29,7 +29,6 @@ else()
endif()
option(USE_NATIVE_INSTRUCTIONS "USE_NATIVE_INSTRUCTIONS makes rpcs3 compile with -march=native, which is useful for local builds, but not good for packages." ON)
option(USE_ARM_LSE2 "Compile with LSE2 instructions" OFF)
option(WITH_LLVM "Enable usage of LLVM library" ON)
option(BUILD_LLVM "Build LLVM from git submodule" OFF)
option(STATIC_LINK_LLVM "Link against LLVM statically. This will get set to ON if you build LLVM from the submodule." OFF)
@@ -64,7 +63,6 @@ option(USE_LTO "Use LTO for building" ON)
option(BUILD_RPCS3_TESTS "Build RPCS3 unit tests." OFF)
option(RUN_RPCS3_TESTS "Run RPCS3 unit tests. Requires BUILD_RPCS3_TESTS" OFF)
option(USE_GAMEMODE "Choose whether to enable GameMode features or not." ON)
option(BUNDLE_UDEV_RULES "Include udev rules on Linux/FreeBSD" OFF)
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/buildfiles/cmake")
-21
View File
@@ -2,7 +2,6 @@
#include "Config.h"
#include "util/types.hpp"
#include "util/yaml.hpp"
#include "util/cctype.hpp"
#include <charconv>
@@ -713,26 +712,6 @@ bool cfg::node::validate(std::string_view value)
return false;
}
bool cfg::_bool::from_string(std::string_view value, bool /*dynamic*/)
{
if (value.size() != 4 && value.size() != 5)
{
return false;
}
char copy[5];
std::transform(value.begin(), value.end(), std::begin(copy), utils::tolower<char>);
if (value.size() == 5 && std::string_view{copy, 5} == "false")
m_value = false;
else if (value.size() == 4 && std::string_view{copy, 4} == "true")
m_value = true;
else
return false;
return true;
}
std::string cfg::map_entry::get_value(std::string_view key)
{
if (auto it = m_map.find(key); it != m_map.end())
+19 -6
View File
@@ -212,7 +212,25 @@ namespace cfg
return def ? "true" : "false";
}
bool from_string(std::string_view value, bool dynamic = false) override;
bool from_string(std::string_view value, bool /*dynamic*/ = false) override
{
if (value.size() != 4 && value.size() != 5)
{
return false;
}
char copy[5];
std::transform(value.begin(), value.end(), std::begin(copy), ::tolower);
if (value.size() == 5 && std::string_view{copy, 5} == "false")
m_value = false;
else if (value.size() == 4 && std::string_view{copy, 4} == "true")
m_value = true;
else
return false;
return true;
}
void set(const bool& value)
{
@@ -689,11 +707,6 @@ namespace cfg
return *m_value.load().get();
}
std::string get() const
{
return *m_value.load().get();
}
std::string def_to_string() const override
{
return def;
+22 -323
View File
@@ -26,7 +26,6 @@ std::string g_android_cache_dir;
#include <cwchar>
#include <Windows.h>
#include <winioctl.h>
static std::unique_ptr<wchar_t[]> to_wchar(std::string_view source)
{
@@ -148,7 +147,6 @@ static fs::error to_error(DWORD e)
#include <sys/statvfs.h>
#include <sys/file.h>
#include <sys/uio.h>
#include <sys/ioctl.h>
#include <dirent.h>
#include <fcntl.h>
#include <libgen.h>
@@ -160,19 +158,12 @@ static fs::error to_error(DWORD e)
#include <copyfile.h>
#include <mach-o/dyld.h>
#include <limits.h>
#include <sys/disk.h>
#include <sys/param.h>
#include <sys/mount.h>
#elif defined(__linux__) || defined(__sun)
#include <sys/sendfile.h>
#include <sys/syscall.h>
#include <sys/sysmacros.h>
#include <linux/fs.h>
#else
#include <fstream>
#include <sys/disk.h>
#include <sys/param.h>
#include <sys/mount.h>
#endif
static fs::error to_error(int e)
@@ -193,96 +184,6 @@ static fs::error to_error(int e)
}
}
#if defined(__linux__)
// Major numbers of the block devices an optical disc can be accessed through (see "Documentation/admin-guide/devices.txt")
constexpr unsigned int s_scsi_cdrom_major = 11; // Optical drive (e.g. "/dev/sr0")
constexpr unsigned int s_loopback_major = 7; // Disc image attached with "mount"/"losetup" (e.g. "/dev/loop0")
#endif
// Check whether the provided device node is an optical drive (e.g. a Blu-Ray Disc drive) or a mounted disc image
static bool is_optical_device_node(const struct ::stat& file_info)
{
#if defined(__linux__)
// An optical drive is exposed as a block device using the SCSI CD-ROM major number (e.g. "/dev/sr0", "/dev/scd0" or the "/dev/cdrom" link).
// A disc image attached through "mount -o loop" (or "losetup") is exposed as a loopback block device instead (e.g. "/dev/loop0"):
// it is the counterpart of an ISO file mounted on Windows, where the resulting virtual drive is reported as DRIVE_CDROM
if (!S_ISBLK(file_info.st_mode))
{
return false;
}
const unsigned int device_major = major(file_info.st_rdev);
return device_major == s_scsi_cdrom_major || device_major == s_loopback_major;
#elif defined(__APPLE__)
// The raw (unbuffered) device is a character device (e.g. "/dev/rdisk2").
// NOTE: there is no cheap way to tell an optical drive from any other raw disk here, so any raw disk node is accepted
return S_ISCHR(file_info.st_mode);
#else
// On the BSDs an optical drive is a character device (e.g. "/dev/cd0")
return S_ISCHR(file_info.st_mode) || S_ISBLK(file_info.st_mode);
#endif
}
// Check whether the path is the root of a mounted filesystem (e.g. the mount point of a disc): "st_dev" changes when crossing a mount point
[[maybe_unused]] static bool is_mount_point(const std::string& path, const struct ::stat& file_info)
{
// A file is never a mount point: discard it without any syscall (the "stat()" below would fail with ENOTDIR anyway)
if (!S_ISDIR(file_info.st_mode))
{
return false;
}
struct ::stat parent_info;
if (::stat((path + "/..").c_str(), &parent_info) != 0)
{
return false;
}
return parent_info.st_dev != file_info.st_dev;
}
// Retrieve the size of a raw device: "fstat()" reports no size (0) on such a device
static u64 get_raw_device_size(int fd)
{
#if defined(__linux__)
if (u64 size = 0; ::ioctl(fd, BLKGETSIZE64, &size) == 0)
{
return size;
}
#elif defined(__APPLE__)
u64 block_count = 0;
u32 block_size = 0;
if (::ioctl(fd, DKIOCGETBLOCKCOUNT, &block_count) == 0 && ::ioctl(fd, DKIOCGETBLOCKSIZE, &block_size) == 0)
{
if (block_size && block_count > u64{umax} / block_size)
{
fmt::throw_exception("Raw device size overflow (block count: 0x%x, block size: 0x%x)", block_count, block_size);
}
return block_count * block_size;
}
#elif defined(__FreeBSD__) || defined(__DragonFly__)
if (off_t media_size = 0; ::ioctl(fd, DIOCGMEDIASIZE, &media_size) == 0)
{
return static_cast<u64>(media_size);
}
#endif
// Fallback: seek to the end of the device (restoring the current position afterwards)
const off_t old_pos = ::lseek(fd, 0, SEEK_CUR);
const off_t end_pos = ::lseek(fd, 0, SEEK_END);
if (old_pos >= 0)
{
::lseek(fd, old_pos, SEEK_SET);
}
return end_pos > 0 ? static_cast<u64>(end_pos) : 0;
}
#endif
static std::string path_append(std::string_view path, std::string_view more)
@@ -510,12 +411,12 @@ namespace fs
class windows_file final : public file_base
{
HANDLE m_handle;
u64 m_raw_device_size; // Size of the raw device, 0 if it's not one: it never changes, so it's retrieved once when the file is opened
bool m_raw_device;
atomic_t<u64> m_pos {0};
public:
windows_file(HANDLE handle, u64 raw_device_size = 0)
: m_handle(handle), m_raw_device_size(raw_device_size)
windows_file(HANDLE handle, bool raw_device = false)
: m_handle(handle), m_raw_device(raw_device)
{
}
@@ -675,7 +576,7 @@ namespace fs
u64 size() override
{
if (!m_raw_device_size)
if (!m_raw_device)
{
// NOTE: this can fail if we access a mounted empty drive (e.g. after unmounting an iso).
LARGE_INTEGER size;
@@ -684,8 +585,11 @@ namespace fs
return size.QuadPart;
}
// For a raw device, the size was already retrieved with DeviceIoControl() when the file was opened
return m_raw_device_size;
// For a raw device, we need to use DeviceIoControl.
DISK_GEOMETRY_EX geometry;
ensure(DeviceIoControl(m_handle, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, nullptr, 0, &geometry, sizeof(geometry), nullptr, nullptr));
return geometry.DiskSize.QuadPart;
}
native_handle get_handle() override
@@ -724,11 +628,10 @@ namespace fs
class unix_file final : public file_base
{
int m_fd;
u64 m_raw_device_size; // Size of the raw device, 0 if it's not one: it never changes, so it's retrieved once when the file is opened
public:
unix_file(int fd, u64 raw_device_size = 0)
: m_fd(fd), m_raw_device_size(raw_device_size)
unix_file(int fd)
: m_fd(fd)
{
}
@@ -747,8 +650,8 @@ namespace fs
stat_t info {};
info.is_directory = S_ISDIR(file_info.st_mode);
info.is_writable = !m_raw_device_size && (file_info.st_mode & 0200); // HACK: approximation
info.size = m_raw_device_size ? m_raw_device_size : static_cast<u64>(file_info.st_size); // A raw device reports no size through "fstat()"
info.is_writable = file_info.st_mode & 0200; // HACK: approximation
info.size = file_info.st_size;
info.atime = file_info.st_atime;
info.mtime = file_info.st_mtime;
info.ctime = info.mtime;
@@ -854,16 +757,10 @@ namespace fs
u64 size() override
{
if (!m_raw_device_size)
{
struct ::stat file_info;
ensure(::fstat(m_fd, &file_info) == 0); // "file::size"
struct ::stat file_info;
ensure(::fstat(m_fd, &file_info) == 0); // "file::size"
return file_info.st_size;
}
// For a raw device, the size was already retrieved with an ioctl when the file was opened
return m_raw_device_size;
return file_info.st_size;
}
native_handle get_handle() override
@@ -1215,39 +1112,15 @@ bool fs::is_symlink(const std::string& path)
return true;
}
bool fs::is_optical_raw_device(const std::string& path)
bool fs::is_optical_raw_device([[maybe_unused]] const std::string& path)
{
#ifdef _WIN32
if (path.starts_with("\\\\.\\"))
{
return true;
}
#endif
return false;
#else
#ifdef __APPLE__
// On Mac OS X optical disks will only ever be mounted under /dev/disk(whatever), similar for raw devices,
// so reject anything not containing the disk string.
if (!path.starts_with("/dev/disk") && !path.starts_with("/dev/rdisk"))
{
return false;
}
#else
// Skip a useless check if the path cannot point to a device node (device nodes always live in "/dev")
if (!path.starts_with("/dev/"))
{
return false;
}
#endif
struct ::stat file_info;
if (::stat(path.c_str(), &file_info) != 0)
{
return false;
}
return is_optical_device_node(file_info);
#endif
}
bool fs::get_optical_raw_device(const std::string& path, std::string* raw_device)
@@ -1284,132 +1157,8 @@ bool fs::get_optical_raw_device(const std::string& path, std::string* raw_device
return true;
}
return false;
#elif defined(__linux__)
// Here the path points to a mounted optical disc (e.g. "/media/user/PS3_DISC") or to a mounted disc image
// (e.g. "mount -o loop game.iso /mnt/game"), so retrieve the device backing the filesystem it belongs to
struct ::stat file_info;
if (::stat(path.c_str(), &file_info) != 0)
{
return false;
}
// "st_dev" of anything stored on a filesystem backed by a block device matches "st_rdev" of the device itself
const dev_t device_id = file_info.st_dev;
const unsigned int device_major = major(device_id);
// Discard at once anything which is not backed by an optical drive or by a loopback device, so that the checks
// below (each one costing at least a syscall) only run on an actual candidate
if (device_major != s_scsi_cdrom_major && device_major != s_loopback_major)
{
return false;
}
// Skip a useless check to detect an optical raw device if the path is not the mount point of the disc, it means we are
// navigating on subfolders (on Windows, in the same way, only the drive root is accepted)
if (!is_mount_point(path, file_info))
{
return false;
}
const unsigned int device_minor = minor(device_id);
// Retrieve the device name from sysfs (e.g. "/sys/dev/block/11:0" -> "../../devices/[...]/block/sr0")
std::string device_path;
char link_target[1024]; // NOTE: "readlink()" never null terminates, so the buffer is used through the returned length only
if (const ssize_t len = ::readlink(("/sys/dev/block/" + std::to_string(device_major) + ":" + std::to_string(device_minor)).c_str(), link_target, sizeof(link_target)); len > 0)
{
const std::string_view target{link_target, static_cast<usz>(len)};
device_path = "/dev/";
device_path += target.substr(target.find_last_of('/') + 1);
}
else if (device_major == s_scsi_cdrom_major)
{
// Fallback (sysfs not available): the minor number matches the index of the SCSI CD-ROM device
device_path = "/dev/sr" + std::to_string(device_minor);
}
else
{
return false;
}
// Ensure the resolved node really points to the same optical device
struct ::stat device_info;
if (::stat(device_path.c_str(), &device_info) != 0 || device_info.st_rdev != device_id || !is_optical_device_node(device_info))
{
return false;
}
if (raw_device)
{
*raw_device = device_path;
}
return true;
#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
// Here the path points to a mounted optical disc or to a mounted disc image (e.g. attached with "hdiutil"/"mdconfig"),
// so retrieve the device backing the filesystem it belongs to
struct ::stat file_info;
if (::stat(path.c_str(), &file_info) != 0)
{
return false;
}
// Skip a useless check to detect an optical raw device if the path is not the mount point of the disc, it means we are
// navigating on subfolders (on Windows, in the same way, only the drive root is accepted). There is no cheap way to
// discard a device here (unlike the major number on Linux), so this is the filter which must come first: it rejects
// any file without a single syscall and any other folder with just one more
if (!is_mount_point(path, file_info))
{
return false;
}
struct ::statfs mount_info;
if (::statfs(path.c_str(), &mount_info) != 0)
{
return false;
}
std::string device_path = mount_info.f_mntfromname; // e.g. "/dev/disk2"
if (!device_path.starts_with("/dev/"))
{
return false;
}
#ifdef __APPLE__
// Use the raw (unbuffered) device (e.g. "/dev/disk2" -> "/dev/rdisk2")
if (!device_path.starts_with("/dev/r"))
{
device_path.insert(5, 1, 'r');
}
#endif
// Ensure the resolved node really points to a raw device
struct ::stat device_info;
if (::stat(device_path.c_str(), &device_info) != 0 || !is_optical_device_node(device_info))
{
return false;
}
if (raw_device)
{
*raw_device = device_path;
}
return true;
#else
// Not supported on this platform
return false;
#endif
}
bool fs::statfs(const std::string& path, fs::device_stat& info)
@@ -1892,29 +1641,11 @@ bool fs::utime(const std::string& path, s64 atime, s64 mtime)
#endif
}
void fs::sync(const std::string& path)
void fs::sync()
{
#ifdef _WIN32
static_cast<void>(path);
fs::g_tls_error = fs::error::unknown;
#elif defined(__linux__)
// Only flush the filesystem containing the path: a global sync() also waits on every other mounted
// filesystem and may block indefinitely on a slow or stalled one (e.g. network or FUSE mounts)
const int fd = ::open(path.c_str(), O_RDONLY | O_CLOEXEC);
if (fd == -1)
{
fs::g_tls_error = to_error(errno);
return;
}
const int res = ::syncfs(fd);
const int err = errno;
::close(fd);
fs::g_tls_error = res == 0 ? fs::error::ok : to_error(err);
#else
static_cast<void>(path);
::sync();
fs::g_tls_error = fs::error::ok;
#endif
@@ -2012,7 +1743,7 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
return;
}
m_file = std::make_unique<windows_file>(handle, static_cast<u64>(ensure(geometry.DiskSize.QuadPart)));
m_file = std::make_unique<windows_file>(handle, true);
return;
}
@@ -2042,7 +1773,7 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
return;
}
if ((mode & fs::write) && (info.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM))
if (info.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
{
CloseHandle(handle);
g_tls_error = fs::error::acces;
@@ -2058,9 +1789,6 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
m_file = std::make_unique<windows_file>(handle);
#else
// An optical raw device can only be read: any write related flag makes the opening fail (handled as any other error)
const bool raw_device = is_optical_raw_device(path);
int flags = O_CLOEXEC; // Ensures all files are closed on execl for auto updater
if (mode & fs::read && mode & fs::write) flags |= O_RDWR;
@@ -2076,7 +1804,7 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
if (mode & fs::write && mode & fs::unread)
{
if (!raw_device && !(mode & (fs::excl + fs::lock)) && mode & fs::trunc)
if (!(mode & (fs::excl + fs::lock)) && mode & fs::trunc)
{
// Alternative to truncation for "unread" flag (TODO)
if (mode & fs::create)
@@ -2109,23 +1837,6 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
ensure(::ftruncate(fd, 0) == 0);
}
// If path points to an optical raw device, complete the file opening
if (raw_device)
{
// Try to retrieve the size of the content. If it fails, no disc is probably mounted so abort the file opening
const u64 raw_device_size = get_raw_device_size(fd);
if (!raw_device_size)
{
::close(fd);
g_tls_error = fs::error::noent;
return;
}
m_file = std::make_unique<unix_file>(fd, raw_device_size);
return;
}
m_file = std::make_unique<unix_file>(fd);
if (mode & fs::isfile && !(mode & fs::write) && get_stat().is_directory)
@@ -2252,17 +1963,6 @@ fs::native_handle fs::file::get_handle() const
#endif
}
bool fs::set_sparse([[maybe_unused]] const fs::file& file)
{
#ifdef _WIN32
FILE_SET_SPARSE_BUFFER sparse{TRUE};
DWORD returned = 0;
return DeviceIoControl(file.get_handle(), FSCTL_SET_SPARSE, &sparse, sizeof(sparse), nullptr, 0, &returned, nullptr) != FALSE;
#else
return true;
#endif
}
fs::file_id fs::file::get_id() const
{
if (m_file)
@@ -2547,7 +2247,6 @@ const std::string& fs::get_config_dir([[maybe_unused]] bool get_config_subdirect
// Clear buffer on failure and notify user
MessageBoxA(nullptr, fmt::format("GetEnvironmentVariable(RPCS3_CONFIG_DIR) failed: error: %s", fmt::win_error{GetLastError(), nullptr}).c_str(), "fs::get_config_dir()", MB_ICONERROR);
buf.clear();
size = 0;
}
}
+4 -21
View File
@@ -198,19 +198,6 @@ namespace fs
// Return "path" plus an ending delimiter (if missing) if "path" is an existing directory. Otherwise, an empty string
std::string get_path_if_dir(const std::string& path);
// Check whether the path is the bare name of a drive (e.g. "E:"), that is a root path whose trailing delimiter was
// trimmed: such a path does not point to the root of the drive but to the current directory of that drive, so the
// delimiter must be restored before using or storing it.
// NOTE: always false on the other platforms, where a name ending with ':' is a regular path component
inline bool is_drive_name([[maybe_unused]] std::string_view path)
{
#ifdef _WIN32
return !path.empty() && path.back() == ':';
#else
return false;
#endif
}
// Get file information
bool get_stat(const std::string& path, stat_t& info);
@@ -226,11 +213,10 @@ namespace fs
// Check whether the path points to an existing symlink
bool is_symlink(const std::string& path);
// Check whether the path points to a raw device (e.g. "\\.\E:" on Windows, "/dev/sr0" on Linux, "/dev/rdisk2" on macOS)
// Check whether the path points to a raw device
bool is_optical_raw_device(const std::string& path);
// Check whether the path points to an optical drive or to a mounted disc image (either the raw device itself or the
// mount point of the disc/image). If so, provide the raw device in "raw_device" if requested
// Check whether the path points to an optical drive. If so, provide the raw device in "raw_device" if requested
bool get_optical_raw_device(const std::string& path, std::string* raw_device = nullptr);
// Get filesystem information
@@ -263,8 +249,8 @@ namespace fs
// Set file access/modification time
bool utime(const std::string& path, s64 atime, s64 mtime);
// Synchronize the filesystem containing the given path (only that filesystem where supported)
void sync(const std::string& path);
// Synchronize filesystems (TODO)
void sync();
class file final
{
@@ -510,9 +496,6 @@ namespace fs
}
};
// Enable sparse-file semantics when required by the host platform.
bool set_sparse(const file& file);
class dir final
{
std::unique_ptr<dir_base> m_dir{};
+9 -3
View File
@@ -14,8 +14,6 @@
#if defined(__APPLE__)
#include <pthread.h>
#elif defined(ANDROID)
#include "util/cctype.hpp"
#endif
LOG_CHANNEL(jit_log, "JIT");
@@ -709,7 +707,11 @@ jit_compiler::jit_compiler(const std::unordered_map<std::string, u64>& _link, st
std::string result;
auto null_mod = std::make_unique<llvm::Module> ("null_", *m_context);
#if LLVM_VERSION_MAJOR >= 21 && (LLVM_VERSION_MINOR >= 1 || LLVM_VERSION_MAJOR >= 22)
null_mod->setTargetTriple(llvm::Triple(jit_compiler::triple1()));
#else
null_mod->setTargetTriple(jit_compiler::triple1());
#endif
std::unique_ptr<llvm::RTDyldMemoryManager> mem;
@@ -723,7 +725,11 @@ jit_compiler::jit_compiler(const std::unordered_map<std::string, u64>& _link, st
else
{
mem = std::make_unique<MemoryManager2>(std::move(symbols_cement));
#if LLVM_VERSION_MAJOR >= 21 && (LLVM_VERSION_MINOR >= 1 || LLVM_VERSION_MAJOR >= 22)
null_mod->setTargetTriple(llvm::Triple(jit_compiler::triple2()));
#else
null_mod->setTargetTriple(jit_compiler::triple2());
#endif
}
}
else
@@ -1041,7 +1047,7 @@ const char * fallback_cpu_detection()
return "cortex-a78";
}
std::transform(result.begin(), result.end(), result.begin(), utils::tolower<char>);
std::transform(result.begin(), result.end(), result.begin(), ::tolower);
return result;
}();
+1 -2
View File
@@ -26,7 +26,6 @@
*/
#include "LUrlParser.h"
#include "util/cctype.hpp"
#include <algorithm>
#include <cstring>
@@ -37,7 +36,7 @@ static bool IsSchemeValid( const std::string& SchemeName )
{
return std::all_of(SchemeName.cbegin(), SchemeName.cend(), [](const auto& c)
{
return utils::isalpha(c) || c == '+' || c == '-' || c == '.';
return isalpha(c) || c == '+' || c == '-' || c == '.';
});
}
+6 -7
View File
@@ -3,7 +3,6 @@
#include "cfmt.h"
#include "util/endian.hpp"
#include "util/v128.hpp"
#include "util/cctype.hpp"
#include <locale>
#include <codecvt>
@@ -199,12 +198,12 @@ fmt::base57_result fmt::base57_result::from_string(std::string_view str)
{
auto to_val = [](u8 c) -> u64
{
if (utils::isdigit(c))
if (std::isdigit(c))
{
return c - '0';
}
if (utils::isupper(c))
if (std::isupper(c))
{
// Omitted characters
if (c == 'B' || c == 'D' || c == 'I' || c == 'O')
@@ -232,7 +231,7 @@ fmt::base57_result fmt::base57_result::from_string(std::string_view str)
return c - 'A' + 10;
}
if (utils::islower(c))
if (std::islower(c))
{
// Omitted characters
if (c == 'l')
@@ -612,7 +611,7 @@ void fmt_class_string<std::source_location>::format(std::string& out, u64 arg)
#ifdef _WIN32
if (DWORD error = GetLastError())
{
fmt::append(out, " (error=%s)", fmt::win_error_to_string(error));
fmt::append(out, " (error=%s)", error, fmt::win_error_to_string(error));
}
#else
if (int error = errno)
@@ -953,7 +952,7 @@ std::string fmt::to_upper(std::string_view string)
{
std::string result;
result.resize(string.size());
std::transform(string.begin(), string.end(), result.begin(), utils::toupper<char>);
std::transform(string.begin(), string.end(), result.begin(), ::toupper);
return result;
}
@@ -961,7 +960,7 @@ std::string fmt::to_lower(std::string_view string)
{
std::string result;
result.resize(string.size());
std::transform(string.begin(), string.end(), result.begin(), utils::tolower<char>);
std::transform(string.begin(), string.end(), result.begin(), ::tolower);
return result;
}
+3 -25
View File
@@ -161,7 +161,7 @@ namespace fmt
std::string_view trim_back_sv(std::string_view source, std::string_view values = " \t");
template <typename T>
std::string merge(const T& source, std::string_view separator, bool is_skip_empty = false)
std::string merge(const T& source, std::string_view separator)
{
if (source.empty())
{
@@ -180,23 +180,6 @@ namespace fmt
auto it = source.begin();
auto end = source.end();
if (is_skip_empty)
{
for (; it != end; ++it)
{
if (it->empty()) continue;
if (!result.empty() && !separator.empty())
{
result.append(separator);
}
result.append(*it);
}
return result;
}
for (--end; it != end; ++it)
{
result.append(*it);
@@ -209,7 +192,7 @@ namespace fmt
}
template <typename T>
std::string merge(std::initializer_list<T> sources, std::string_view separator, bool is_skip_empty = false)
std::string merge(std::initializer_list<T> sources, std::string_view separator)
{
if (!sources.size())
{
@@ -230,11 +213,6 @@ namespace fmt
for (const auto& v : sources)
{
if (v.empty()) continue;
std::string sub = fmt::merge(v, separator, is_skip_empty);
if (sub.empty()) continue;
if (first)
{
first = false;
@@ -244,7 +222,7 @@ namespace fmt
result.append(separator);
}
result.append(std::move(sub));
result.append(fmt::merge(v, separator));
}
return result;
+19 -530
View File
@@ -6,7 +6,6 @@
#include "Emu/Cell/lv2/sys_event.h"
#include "Emu/Cell/lv2/sys_process.h"
#include "Emu/RSX/RSXThread.h"
#include "Emu/system_config.h"
#include "Thread.h"
#include "Utilities/JIT.h"
#include <cfenv>
@@ -97,7 +96,6 @@ DYNAMIC_IMPORT_RENAME("Kernel32.dll", SetThreadDescriptionImport, "SetThreadDesc
#include "util/asm.hpp"
#include "util/v128.hpp"
#include "util/simd.hpp"
#include "util/cctype.hpp"
#include "util/sysinfo.hpp"
#include "Emu/Memory/vm_locking.h"
@@ -187,9 +185,9 @@ bool IsDebuggerPresent()
for (const char* cp = status.data() + found + 10; cp <= status.data() + num_read; ++cp)
{
if (!utils::isspace(*cp))
if (!std::isspace(*cp))
{
return utils::isdigit(*cp) != 0 && *cp != '0';
return std::isdigit(*cp) != 0 && *cp != '0';
}
}
@@ -386,7 +384,7 @@ void decode_x64_reg_op(const u8* code, x64_op_t& out_op, x64_reg_t& out_reg, usz
case 0x67: // group 4
{
sig_log.error("decode_x64_reg_op(%016llxh): address-size override prefix found", code - out_length);
sig_log.error("decode_x64_reg_op(%016llxh): address-size override prefix found", code - out_length, prefix);
out_op = X64OP_NONE;
out_reg = X64_NOT_SET;
out_size = 0;
@@ -1252,296 +1250,20 @@ usz get_x64_access_size(x64_context* context, x64_op_t op, x64_reg_t reg, usz d_
#elif defined(ARCH_ARM64)
#ifdef _WIN32
#define RIP(context) (reinterpret_cast<CONTEXT*>((context))->Pc)
#define GPR(context, index) (reinterpret_cast<CONTEXT*>((context))->X[index])
#elif defined(__APPLE__)
#if defined(__APPLE__)
// https://github.com/bombela/backward-cpp/issues/200
#define RIP(context) ((context)->uc_mcontext->__ss.__pc)
#define GPR(context, index) ((context)->uc_mcontext->__ss.__x[(index)])
#elif defined(__FreeBSD__)
#define RIP(context) ((context)->uc_mcontext.mc_gpregs.gp_elr)
#define GPR(context, index) ((context)->uc_mcontext.mc_gpregs.gp_x[(index)])
#elif defined(__NetBSD__)
#define RIP(context) ((context)->uc_mcontext.__gregs[_REG_PC])
#define GPR(context, index) ((context)->uc_mcontext.__gregs[(index)])
#elif defined(__OpenBSD__)
#define RIP(context) ((context)->sc_elr)
#define GPR(context, index) ((context)->sc_x[(index)])
#else
#define RIP(context) ((context)->uc_mcontext.pc)
#define GPR(context, index) ((context)->uc_mcontext.regs[(index)])
#endif
enum mem_a64_op_t
{
A64_INVALID = 0,
A64_LOAD,
A64_STORE,
};
struct a64_mem_info_t
{
mem_a64_op_t op;
u32 mem_size; // Bytes accessed in memory
u32 reg_size; // Register width (4 or 8 bytes)
u32 reg_num;
bool reg_signed;
};
a64_mem_info_t decode_a64_mem_inst(u32 inst)
{
a64_mem_info_t r{ A64_INVALID, 0, 0, inst % 32, false };
// Exclude SIMD/FP loads/stores
if ((inst >> 26) & 1)
{
return r;
}
// Scalar load/store immediate, unsigned offset variants only:
// size[31:30]
// V[26]
// opc[23:22]
// class bits[29:24] = 111001
if ((inst & 0x3B000000) == 0x39000000)
{
const u32 size = (inst >> 30) & 3;
const u32 opc = (inst >> 22) & 3;
r.mem_size = 1u << size;
switch (opc)
{
case 0:
{
// STR
r.op = A64_STORE;
r.reg_size = r.mem_size;
return r;
}
case 1:
{
// LDR unsigned zero-extend
// size=3 (64-bit) -> Xt; everything else -> Wt
r.op = A64_LOAD;
r.reg_size = (size == 3) ? 8u : 4u;
r.reg_signed = false;
return r;
}
case 2:
case 3:
{
if (size == 3)
{
return r;
}
if (size == 2 && opc == 3)
{
// Invalid LDRSW
return r;
}
// LDRSB/LDRSH/LDRSW
// size determines extension type:
// 00 LDRSB
// 01 LDRSH
// 10 LDRSW
r.op = A64_LOAD;
if (size == 2)
{
// LDUSW
r.reg_size = 8;
}
else
{
// LDRSB/LDRSH
// opc=2 -> Wt, opc=3 -> Xt
r.reg_size = (opc == 3) ? 4 : 8;
}
r.reg_signed = true;
return r;
}
default:
return r;
}
}
// Scalar load/store unscaled immediate (LDUR/STUR)
// size[31:30]
// V[26]
// opc[23:22]
if ((inst & 0x3B200C00u) == 0x38000000u)
{
const u32 size = (inst >> 30) & 3;
const u32 opc = (inst >> 22) & 3;
r.mem_size = 1u << size;
switch (opc)
{
case 0:
{
// STURB/STURH/STUR Wt/STUR Xt
r.op = A64_STORE;
// Source register width
r.reg_size = r.mem_size;
return r;
}
case 1:
{
// LDURB/LDURH/LDUR Wt/LDUR Xt
r.op = A64_LOAD;
// Destination register width
r.reg_size = (size == 3) ? 8 : 4;
r.reg_signed = false;
return r;
}
case 2:
case 3:
{
// LDURSB/LDURSH/LDURSW
if (size == 3)
{
return r;
}
r.op = A64_LOAD;
r.reg_signed = true;
if (size == 2)
{
// LDURSW
r.reg_size = 8;
}
else
{
// LDURSB/LDURSH
// opc=2 -> Wt, opc=3 -> Xt
r.reg_size = (opc == 3) ? 4 : 8;
}
return r;
}
default:
return r;
}
}
//
// Literal loads:
//
// LDR Wt, label
// LDR Xt, label
// LDRSW Xt, label
//
// This is not needed for MMIO (which is the only use for this function)
// if ((inst & 0x3B000000) == 0x18000000)
// {
// u32 opc = (inst >> 30) & 3;
// r.op = A64_LOAD;
// switch (opc)
// {
// case 0: // LDR Wt literal
// {
// r.mem_size = 4;
// r.reg_size = 4;
// return r;
// }
// case 1: // LDR Xt literal
// {
// r.mem_size = 8;
// r.reg_size = 8;
// return r;
// }
// case 2: // LDRSW literal
// {
// r.mem_size = 4;
// r.reg_size = 8;
// r.reg_signed = true;
// return r;
// }
// default:
// {
// break;
// }
// }
// }
return r;
}
void put_a64_reg_value(ucontext_t* context, u32 reg_index, u32 reg_size, bool reg_signed, u32 mem_size, u64 value)
{
ensure(mem_size == 1 || mem_size == 2 || mem_size == 4 || mem_size == 8);
ensure(reg_size == 1 || reg_size == 2 || reg_size == 4 || reg_size == 8);
ensure(reg_size >= mem_size);
ensure(reg_index < 32);
if (reg_index == 31)
{
// XZR "register"
ensure(false);
}
auto make_mask = [](u32 bytes) -> u64
{
if (bytes == 8)
{
return umax;
}
const u64 bits = bytes * 8;
return (u64{1} << bits) - 1;
};
// Mask for sign-extending the value
const u64 sign_bit = value & (make_mask(mem_size) / 2 + 1);
const u64 sign_mask = (reg_signed && sign_bit != 0 && reg_size > mem_size) ? (make_mask(reg_size) & ~make_mask(mem_size)) : 0;
u64 temp_reg_value = 0;
temp_reg_value |= (value & make_mask(mem_size)); // Set value (adjusted by size)
temp_reg_value |= sign_mask; // Apply sign-extension
GPR(context, reg_index) = temp_reg_value;
}
u64 get_a64_reg_value(ucontext_t* context, u32 reg_index, u32 reg_size)
{
ensure(reg_size == 1 || reg_size == 2 || reg_size == 4 || reg_size == 8);
ensure(reg_index < 32);
if (reg_index == 31)
{
// XZR "register"
return 0;
}
auto make_mask = [](u32 bytes) -> u64
{
if (bytes == 8)
{
return umax;
}
const u64 bits = bytes * 8;
return (u64{1} << bits) - 1;
};
return (GPR(context, reg_index) & make_mask(reg_size));
}
#endif /* ARCH_ARM64 */
#endif /* ARCH_ */
namespace rsx
{
@@ -1756,11 +1478,11 @@ bool handle_access_violation(u32 addr, bool is_writing, bool is_exec, ucontext_t
if (a_size == 4)
{
value = std::bit_cast<be_t<u32>>(value);
value = stx::se_storage<u32>::swap(value);
}
else if (a_size == 2)
{
value = std::bit_cast<be_t<u16>>(static_cast<u16>(value));
value = stx::se_storage<u16>::swap(value);
}
else
{
@@ -1834,126 +1556,8 @@ bool handle_access_violation(u32 addr, bool is_writing, bool is_exec, ucontext_t
g_tls_fault_spu++;
return true;
} while (0);
#elif defined(ARCH_ARM64)
const u8* const code = reinterpret_cast<u8*>(RIP(context));
const u32 instruction = read_from_ptr_unsafe<u32>(code);
const auto [op, mem_size, reg_size, reg_index, reg_signed] = decode_a64_mem_inst(instruction);
auto report_opcode = [&]()
{
sig_log.error("decode_a64_mem_inst(%p): unsupported opcode: %s", code, +std::bit_cast<be_t<u32>>(instruction));
};
if (0x1'0000'0000ull - addr < mem_size)
{
sig_log.error("Invalid mem_size (0x%llx)", mem_size);
report_opcode();
return false;
}
// check if address is RawSPU MMIO register
do if (addr - RAW_SPU_BASE_ADDR < (6 * RAW_SPU_OFFSET) && (addr % RAW_SPU_OFFSET) >= RAW_SPU_PROB_OFFSET)
{
auto thread = idm::get_unlocked<named_thread<spu_thread>>(spu_thread::find_raw_spu((addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET));
if (!thread || is_exec)
{
break;
}
if (!mem_size)
{
sig_log.error("Invalid or unsupported instruction (reg=%d, mem_size=%lld, reg_size=0x%llx)", reg_index, mem_size, reg_size);
report_opcode();
return false;
}
bool handled = true;
switch (op)
{
case A64_LOAD:
{
u32 value;
const u32 addr_aligned = addr & -4;
if (addr % 4 + mem_size > 4)
{
handled = false;
break;
}
if (is_writing || !thread->read_reg(addr_aligned, value))
{
return false;
}
// Adjust value for 8-bit and 16-bit reads
value >>= ((4 - mem_size) * 8) - ((addr % 4) * 8);
value &= mem_size == 4 ? u32{umax} : ((1u << (mem_size * 8)) - 1);
if (mem_size == 4)
{
value = std::bit_cast<be_t<u32>>(value);
}
else if (mem_size == 2)
{
value = std::bit_cast<be_t<u16>>(static_cast<u16>(value));
}
else
{
ensure(mem_size == 1);
}
// Update register value
put_a64_reg_value(context, reg_index, reg_size, reg_signed, mem_size, value);
break;
}
case A64_STORE:
{
if (mem_size != 4)
{
// Might be unimplemented, such as writing MFC proxy EAL+EAH using 64-bit store
handled = false;
break;
}
if (!is_writing)
{
return false;
}
const u64 reg_value = get_a64_reg_value(context, reg_index, reg_size);
const u32 val32 = static_cast<u32>(reg_value);
if (!thread->write_reg(addr, std::bit_cast<be_t<u32>>(val32)))
{
return false;
}
break;
}
default:
{
sig_log.error("Invalid or unsupported operation (reg=%d, mem_size=%lld, reg_size=0x%llx)", reg_index, mem_size, reg_size);
report_opcode();
return false;
}
}
if (!handled)
{
sig_log.error("Invalid or unsupported operation (reg=%d, mem_size=%lld, reg_size=0x%llx)", reg_index, mem_size, reg_size);
report_opcode();
break;
}
// skip processed instruction
RIP(context) = reinterpret_cast<std::remove_cvref_t<decltype(RIP(context))>>(reinterpret_cast<const char*>(RIP(context)) + 4);
g_tls_fault_spu++;
return true;
} while (0);
#else
static_cast<void>(context);
#endif /* ARCH_ */
const auto required_page_perms = (is_writing ? vm::page_writable : vm::page_readable) + (is_exec ? vm::page_executable : 0);
@@ -1966,15 +1570,8 @@ bool handle_access_violation(u32 addr, bool is_writing, bool is_exec, ucontext_t
// Hack: allocate memory in case the emulator is stopping
const auto hack_alloc = [&]()
{
const bool added_flag = cpu && !cpu->state.test_and_set(cpu_flag::wait);
if (vm::check_addr(addr, required_page_perms))
{
if (added_flag)
{
cpu->check_state();
}
return true;
}
@@ -1982,11 +1579,6 @@ bool handle_access_violation(u32 addr, bool is_writing, bool is_exec, ucontext_t
if (!area)
{
if (added_flag)
{
cpu->check_state();
}
return false;
}
@@ -2007,11 +1599,6 @@ bool handle_access_violation(u32 addr, bool is_writing, bool is_exec, ucontext_t
{
ppu_register_range(addr & -0x10000, 0x10000);
}
if (added_flag)
{
cpu->check_state();
}
g_tls_access_violation_recovered = addr;
return true;
@@ -2026,20 +1613,10 @@ bool handle_access_violation(u32 addr, bool is_writing, bool is_exec, ucontext_t
ppu_register_range(addr & -0x10000, 0x10000);
}
if (added_flag)
{
cpu->check_state();
}
g_tls_access_violation_recovered = addr;
return true;
}
if (added_flag)
{
cpu->check_state();
}
return false;
};
@@ -2276,12 +1853,12 @@ bool handle_access_violation(u32 addr, bool is_writing, bool is_exec, ucontext_t
if (Emu.IsStopped())
{
// Keep retrying until the page is mapped: the thread must be able to resume so it can observe cpu_flag::exit and terminate cleanly.
// Reporting the violation as unhandled here would escalate a guest crash into an unhandled host exception.
while (!hack_alloc())
{
thread_ctrl::wait_for(1000);
}
return false;
}
return true;
@@ -2330,11 +1907,10 @@ static LONG exception_handler(PEXCEPTION_POINTERS pExp) noexcept
is_exec = true;
addr = static_cast<u32>(exec64);
}
else if (const usz seg_off = (ptr - vm::g_exec_addr - vm::g_exec_addr_seg_offset); seg_off <= u32{umax} / 2)
else if (const usz exec64 = (ptr - vm::g_exec_addr - vm::g_exec_addr_seg_offset); exec64 <= u32{umax})
{
// Segment map holds one u16 per 4 bytes of guest code: ptr = g_exec_addr + g_exec_addr_seg_offset + (addr >> 1)
is_exec = true;
addr = static_cast<u32>(seg_off * 2);
addr = static_cast<u32>(exec64);
}
else
{
@@ -2557,7 +2133,7 @@ static void signal_handler(int /*sig*/, siginfo_t* info, void* uct) noexcept
}
#else
const u32 insn = is_executing ? 0 : read_from_ptr_unsafe<u32>(RIP(context));
const u32 insn = is_executing ? 0 : *reinterpret_cast<u32*>(RIP(context));
const bool is_writing =
(insn & 0xbfff0000) == 0x0c000000 || // STR <Wt>, [<Xn>, #<imm>] (store word with immediate offset)
(insn & 0xbfe00000) == 0x0c800000 || // STP <Wt1>, <Wt2>, [<Xn>, #<imm>] (store pair of registers with immediate offset)
@@ -2579,8 +2155,7 @@ static void signal_handler(int /*sig*/, siginfo_t* info, void* uct) noexcept
#endif
const u64 exec64 = (reinterpret_cast<u64>(info->si_addr) - reinterpret_cast<u64>(vm::g_exec_addr)) / 2;
// Segment map holds one u16 per 4 bytes of guest code: si_addr = g_exec_addr + g_exec_addr_seg_offset + (addr >> 1)
const u64 seg_off = (reinterpret_cast<u64>(info->si_addr) - reinterpret_cast<u64>(vm::g_exec_addr)) - vm::g_exec_addr_seg_offset;
const u64 exec64_2 = (reinterpret_cast<u64>(info->si_addr) - reinterpret_cast<u64>(vm::g_exec_addr)) - vm::g_exec_addr_seg_offset;
const auto cause = is_executing ? "executing" : is_writing ? "writing" : "reading";
if (auto [addr, ok] = vm::try_get_addr(info->si_addr); ok && !is_executing)
@@ -2599,9 +2174,9 @@ static void signal_handler(int /*sig*/, siginfo_t* info, void* uct) noexcept
return;
}
}
else if (seg_off < 0x80000000ull && !is_executing)
else if (exec64_2 < 0x100000000ull && !is_executing)
{
if (thread_ctrl::get_current() && handle_access_violation(static_cast<u32>(seg_off * 2), is_writing, true, context))
if (thread_ctrl::get_current() && handle_access_violation(static_cast<u32>(exec64_2), is_writing, true, context))
{
return;
}
@@ -2764,8 +2339,8 @@ void thread_base::start()
pthread_attr_t attrs;
pthread_t thread_id{};
struct sched_param sp;
memset(&sp, 0, sizeof(struct sched_param));
sp.sched_priority=99;
memset(&sp, 0, sizeof(struct sched_param));
sp.sched_priority=99;
pthread_attr_init(&attrs);
pthread_attr_setstacksize(&attrs, 0x800000);
@@ -2811,14 +2386,6 @@ void thread_base::initialize(void (*error_cb)())
}
#endif
#if !defined(ANDROID) && (defined(__linux__) || defined(__DragonFly__) || defined(__FreeBSD__))
// A new thread inherits its creator's affinity mask (e.g. compile workers spawned by a pinned PPU thread): reset it to the process mask
if (g_cfg.core.thread_scheduler != thread_scheduler_mode::os)
{
thread_ctrl::set_thread_affinity_mask(0);
}
#endif
// Initialize TLS variables
thread_ctrl::g_tls_this_thread = this;
@@ -4043,81 +3610,3 @@ bool thread_ctrl::is_main()
{
return get_tid() == utils::main_tid;
}
usz map_workload(std::string_view thread_name, usz thread_count, usz count, std::function<void(usz)>&& func)
{
ensure(!!func);
if (thread_count <= 1)
{
for (usz i = 0; i < count; i++)
{
func(i);
}
return 1;
}
atomic_t<u32> num_threads_succeeded {0}; // Check if any thread didn't finish. For example when hitting an exception.
atomic_t<usz> indexer = 0;
const auto iterate = [count, &func, &indexer]()
{
while (thread_ctrl::state() != thread_state::aborting)
{
// Make sure indexer does not exceed count
const usz index = indexer.fetch_op([count](usz& v)
{
if (v < count)
{
v++;
return true;
}
return false;
}).first;
if (index >= count)
{
break;
}
func(index);
}
};
named_thread_group workers(thread_name, ::narrow<u32>(thread_count) - 1, [&iterate, &num_threads_succeeded]()
{
iterate();
num_threads_succeeded++;
});
iterate();
workers.join();
return num_threads_succeeded + 1;
}
usz map_workload(std::string_view thread_name, usz thread_count, std::function<void()>&& func)
{
ensure(!!func);
if (thread_count <= 1)
{
func();
return 1;
}
atomic_t<u32> num_threads_succeeded {0}; // Check if any thread didn't finish. For example when hitting an exception.
named_thread_group workers(thread_name, ::narrow<u32>(thread_count) - 1, [&func, &num_threads_succeeded]()
{
func();
num_threads_succeeded++;
});
func();
workers.join();
return num_threads_succeeded + 1;
}
-3
View File
@@ -905,6 +905,3 @@ public:
::operator delete(static_cast<void*>(m_threads), std::align_val_t{alignof(Thread)});
}
};
usz map_workload(std::string_view thread_name, usz thread_count, usz count, std::function<void(usz)>&& func);
usz map_workload(std::string_view thread_name, usz thread_count, std::function<void()>&& func);
+9 -26
View File
@@ -5,13 +5,11 @@
#include "version.h"
#include "Emu/IdManager.h"
#include "Emu/Memory/vm.h"
#include "Emu/emu_callbacks.h"
#include "Emu/System.h"
#include "Emu/VFS.h"
#include "util/types.hpp"
#include "util/asm.hpp"
#include "util/cctype.hpp"
#include <charconv>
#include <regex>
@@ -331,7 +329,7 @@ bool patch_engine::load(patch_map& patches_map, const std::string& path, std::st
is_valid = false;
continue;
}
else if (serial.size() != 9 || !std::all_of(serial.begin(), serial.end(), [](char c) { return utils::isalnum(c); }))
else if (serial.size() != 9 || !std::all_of(serial.begin(), serial.end(), [](char c) { return std::isalnum(static_cast<unsigned char>(c)); }))
{
append_log_message(log_messages, fmt::format("Error: Serial '%s' invalid (patch: %s, key: %s, location: %s, file: %s)", serial, description, main_key, get_yaml_node_location(serial_node), path), &patch_log.error);
is_valid = false;
@@ -964,7 +962,7 @@ static usz apply_modification(std::vector<u32>& applied, patch_engine::patch_inf
const u32 alloc_size = utils::align(static_cast<u32>(p.value.long_value) + alloc_at % 4096, 4096);
// Allocate map if needed, if allocated flags will indicate that bit 62 is set (unique identifier)
auto alloc_map = vm::reserve_map(vm::any, alloc_at & -0x10000, utils::align(alloc_size, 0x10000), vm::block_size_64k | (1ull << 62));
auto alloc_map = vm::reserve_map(vm::any, alloc_at & -0x10000, utils::align(alloc_size, 0x10000), vm::page_size_64k | (1ull << 62));
u64 flags = vm::alloc_unwritable;
@@ -1190,7 +1188,7 @@ static usz apply_modification(std::vector<u32>& applied, patch_engine::patch_inf
if (!addr)
{
patch_log.error("Failed to allocate 0x%x bytes for code (entry=0x%x)", alloc_size, out_branch);
patch_log.error("Failed to allocate 0x%x bytes for code (entry=0x%x)", alloc_size, addr, out_branch);
continue;
}
@@ -1388,7 +1386,7 @@ static usz apply_modification(std::vector<u32>& applied, patch_engine::patch_inf
if (exec_addr)
{
g_emu_callbacks.add_breakpoint(exec_addr);
Emu.GetCallbacks().add_breakpoint(exec_addr);
}
break;
@@ -1436,7 +1434,7 @@ static usz apply_modification(std::vector<u32>& applied, patch_engine::patch_inf
if (dest_path.empty())
{
patch_log.error("Failed to patch file path at '%s': destination is not mounted", original_vfs_path);
patch_log.error("Failed to patch file path at '%s': destination is not mounted", original_vfs_path, dest_vfs_path);
continue;
}
@@ -1805,9 +1803,8 @@ static void append_patches(patch_engine::patch_map& existing_patches, const patc
bool patch_engine::save_patches(const patch_map& patches, const std::string& path, std::stringstream* log_messages)
{
fs::pending_file file(path);
if (!file.file)
fs::file file(path, fs::rewrite);
if (!file)
{
append_log_message(log_messages, fmt::format("Failed to open patch file %s (%s)", path, fs::g_tls_error), &patch_log.fatal);
return false;
@@ -1907,17 +1904,7 @@ bool patch_engine::save_patches(const patch_map& patches, const std::string& pat
out << YAML::Flow;
out << YAML::BeginSeq;
out << fmt::format("%s", data.type);
if (patch_type_uses_hex_offset(data.type))
{
out << fmt::format("0x%.8x", data.offset);
}
else
{
// This element is a path for move_file and hide_file, not an address
out << data.original_offset;
}
out << fmt::format("0x%.8x", data.offset);
out << data.original_value;
out << YAML::EndSeq;
}
@@ -1931,11 +1918,7 @@ bool patch_engine::save_patches(const patch_map& patches, const std::string& pat
out << YAML::EndMap;
if (file.file.write(out.c_str(), out.size()) < out.size() || !file.commit())
{
append_log_message(log_messages, fmt::format("Failed to write patch file %s (%s)", path, fs::g_tls_error), &patch_log.fatal);
return false;
}
file.write(out.c_str(), out.size());
return true;
}
+6 -22
View File
@@ -146,41 +146,25 @@ public:
constexpr bool test_and_set(T bit)
{
const under s = shift(bit);
const bool r = (m_data & s) != 0;
m_data |= s;
return r;
}
constexpr bool test_and_set(T bit, bool value)
{
const under s = shift(bit);
const bool r = (m_data & s) != 0;
m_data = (value ? (m_data | s) : (m_data & ~s));
bool r = (m_data & shift(bit)) != 0;
m_data |= shift(bit);
return r;
}
constexpr bool test_and_reset(T bit)
{
const under s = shift(bit);
const bool r = (m_data & s) != 0;
m_data &= ~s;
bool r = (m_data & shift(bit)) != 0;
m_data &= ~shift(bit);
return r;
}
constexpr bool test_and_complement(T bit)
{
const under s = shift(bit);
const bool r = (m_data & s) != 0;
m_data ^= s;
bool r = (m_data & shift(bit)) != 0;
m_data ^= shift(bit);
return r;
}
constexpr bool test(bs_t arg) const
{
return (m_data & arg.m_data) != 0;
}
constexpr bool all_of(bs_t arg) const
{
return (m_data & arg.m_data) == arg.m_data;
-83
View File
@@ -91,24 +91,6 @@ usz cfmt_append(Dst& out, const Char* fmt, Src&& src)
}
};
const auto write_binary = [&](auto value, u64 min_num)
{
if constexpr (sizeof(value) == 16)
{
out.resize(out.size() + std::max<u64>(min_num, 128 - utils::clz128(value | 1)), '0');
}
else
{
out.resize(out.size() + std::max<u64>(min_num, 64 - std::countl_zero<u64>(value | 1)), '0');
}
// Write in reversed order
for (auto i = out.rbegin(); value; i++, value >>= 1)
{
*i = static_cast<usz>(value & 0b1) ? '1' : '0';
}
};
const auto write_decimal = [&](auto value, s64 min_size)
{
const usz start = out.size();
@@ -653,71 +635,6 @@ usz cfmt_append(Dst& out, const Char* fmt, Src&& src)
break;
}
case 'b':
case 'B':
{
if (!src.test(ctx.args)) [[unlikely]]
{
drop_sequence();
break;
}
const usz src_type = src.type(ctx.args);
if (!ctx.type || src_type > 8)
{
ctx.type = static_cast<u8>(src_type);
if (!ctx.type)
{
ctx.type = src.size_int;
}
}
const u64 mask =
ctx.type == 1 ? 0xff :
ctx.type == 2 ? 0xffff :
ctx.type == 4 ? 0xffff'ffffu :
0xffff'ffff'ffff'ffffu;
// Trunc sign-extended signed types
const u64 val = src.template get<u64>(ctx.args) & mask;
const usz start = out.size();
if (!ctx.dot || ctx.prec)
{
if (ctx.type >= 16)
{
u128 val2 = *reinterpret_cast<const u128*>(val);
write_binary(val2, ctx.prec);
}
else
{
write_binary(val, ctx.prec);
}
}
const usz size2 = out.size() - start;
if (size2 < ctx.width)
{
// Add padding if necessary
if (ctx.zeros && !ctx.left && !ctx.dot)
{
out.insert(out.begin() + start + (ctx.alter && val ? 2 : 0), ctx.width - size2, '0');
}
else
{
out.insert(ctx.left ? out.end() : out.begin() + start, ctx.width - size2, ' ');
}
}
src.skip(ctx.args);
ctx = {0};
break;
}
case 'p':
{
if (!src.test(ctx.args) || ctx.type) [[unlikely]]
+1 -1
View File
@@ -47,7 +47,7 @@ namespace date_time
std::string parse_buf;
if constexpr (separator != 0)
if constexpr(separator != 0)
parse_buf = std::string("%Y") + separator + "%m" + separator + "%d" + separator + "%H" + separator + "%M" + separator + "%S";
else
parse_buf = "%Y%m%d%H%M%S";
+3 -57
View File
@@ -724,24 +724,15 @@ struct coord3_base
struct { T width, height, depth; };
};
constexpr coord3_base()
: position{}, size{}
constexpr coord3_base() : position{}, size{}
{
}
constexpr coord3_base(const position3_base<T>& position, const size3_base<T>& size)
: position{ position }, size{ size }
constexpr coord3_base(const position3_base<T>& position, const size3_base<T>& size) : position{ position }, size{ size }
{
}
constexpr coord3_base(T x, T y, T z, T width, T height, T depth)
: x{ x }, y{ y }, z{ z }, width{ width }, height{ height }, depth{ depth }
{
}
constexpr coord3_base(const area_base<T>& area, T z = 0, T depth = 1)
: x{ area.x1 }, y{ area.y1 }, z{ z }
, width{ area.x2 - area.x1 }, height{ area.y2 - area.y1 }, depth{ depth }
constexpr coord3_base(T x, T y, T z, T width, T height, T depth) : x{ x }, y{ y }, z{ z }, width{ width }, height{ height }, depth{ depth }
{
}
@@ -764,51 +755,6 @@ struct coord3_base
{
return{ static_cast<NT>(x), static_cast<NT>(y), static_cast<NT>(z), static_cast<NT>(width), static_cast<NT>(height), static_cast<NT>(depth) };
}
void flip_horizontal()
requires std::is_signed_v<T>
{
auto x2 = x + width;
x = x2;
width = -width;
}
void flip_vertical()
requires std::is_signed_v<T>
{
auto y2 = y + height;
y = y2;
height = -height;
}
bool is_flipped() const
requires std::is_signed_v<T>
{
return width < 0 || height < 0 || depth < 0;
}
area_base<T> to_area() const
{
return { x, y, x + width, y + height };
}
T abs_width() const
requires std::is_signed_v<T>
{
return width < 0 ? -width : width;
}
T abs_height() const
requires std::is_signed_v<T>
{
return height < 0 ? -height : height;
}
T abs_depth() const
requires std::is_signed_v<T>
{
return depth < 0 ? -depth : depth;
}
};
-5
View File
@@ -28,11 +28,6 @@ class shared_mutex final
public:
constexpr shared_mutex() = default;
const atomic_t<u32>& raw() const
{
return m_value;
}
bool try_lock_shared()
{
const u32 value = m_value.load();
-29
View File
@@ -13,33 +13,6 @@
namespace utils
{
void clean_backtrace(std::vector<std::string>& result)
{
for (usz it = 1, first_in_seq = 0, del_count = 0;;)
{
if (it >= result.size() || result[it] != result[first_in_seq])
{
if (del_count)
{
fmt::append(result[first_in_seq], " x%u", del_count + 1);
}
if (it < result.size())
{
first_in_seq = it;
it++;
del_count = 0;
continue;
}
break;
}
result.erase(result.begin() + it);
del_count++;
}
}
#ifdef _WIN32
std::string wstr_to_utf8(LPWSTR data, int str_len)
{
@@ -166,7 +139,6 @@ namespace utils
}
}
clean_backtrace(result);
return result;
}
#else
@@ -194,7 +166,6 @@ namespace utils
free(symbols);
#endif
clean_backtrace(result);
return result;
}
#endif
+1 -2
View File
@@ -55,8 +55,7 @@ namespace utils
int compare_versions(const std::string& v1, const std::string& v2, bool& ok)
{
// Check if both version strings are valid
static const std::regex comp = std::regex("[0-9.]*");
ok = std::regex_match(v1, comp) && std::regex_match(v2, comp);
ok = std::regex_match(v1, std::regex("[0-9.]*")) && std::regex_match(v2, std::regex("[0-9.]*"));
if (!ok)
{
-10
View File
@@ -208,16 +208,6 @@ QComboBox {
padding-bottom: 0.2em;
padding-left: 0.4em;
}
QComboBox QAbstractItemView {
background-color: #323232;
color: #fff;
border: 0.05em solid #1e1e1e;
}
QComboBox QAbstractItemView::item:selected,
QComboBox QAbstractItemView::item:hover {
background-color: #444444;
color: #fff;
}
QComboBox::disabled {
background-color: #828790;
color: #fff;
File diff suppressed because it is too large Load Diff
Binary file not shown.
Binary file not shown.
-4
View File
@@ -1,9 +1,5 @@
# Check and configure compiler options for RPCS3
if(USE_ARM_LSE2)
add_compile_definitions(ARM_FEATURE_LSE2=1)
endif()
if(MSVC)
add_compile_options(/Zc:throwingNew- /constexpr:steps16777216)
add_compile_definitions(
+4 -17
View File
@@ -3,22 +3,9 @@ if(USE_SYSTEM_ZLIB)
find_package(ZLIB)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR})
else()
if(NOT TARGET ZLIB::ZLIB)
add_library(ZLIB::ZLIB STATIC IMPORTED GLOBAL)
if(MSVC)
# On MSVC, zlib builds as zs.lib (Release) / zsd.lib (Debug) in per-config subdirectories
set_target_properties(ZLIB::ZLIB PROPERTIES
IMPORTED_LOCATION_RELEASE "${CMAKE_BINARY_DIR}/3rdparty/zlib/zlib/Release/zs.lib"
IMPORTED_LOCATION_DEBUG "${CMAKE_BINARY_DIR}/3rdparty/zlib/zlib/Debug/zsd.lib"
IMPORTED_LOCATION_RELWITHDEBINFO "${CMAKE_BINARY_DIR}/3rdparty/zlib/zlib/RelWithDebInfo/zs.lib"
IMPORTED_LOCATION_MINSIZEREL "${CMAKE_BINARY_DIR}/3rdparty/zlib/zlib/MinSizeRel/zs.lib")
else()
# On non-MSVC, zlib OUTPUT_NAME is "z" → libz.a
set_target_properties(ZLIB::ZLIB PROPERTIES
IMPORTED_LOCATION "${CMAKE_BINARY_DIR}/3rdparty/zlib/zlib/libz.a")
endif()
set_target_properties(ZLIB::ZLIB PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR}/3rdparty/zlib/zlib;${CMAKE_BINARY_DIR}/3rdparty/zlib/zlib")
endif()
add_library(ZLIB::ZLIB STATIC IMPORTED)
set_target_properties(ZLIB::ZLIB PROPERTIES
IMPORTED_LOCATION "${CMAKE_BINARY_DIR}/3rdparty/zlib/zlib/libzlibstatic.a"
INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR}/3rdparty/zlib/zlib;${CMAKE_BINARY_DIR}/3rdparty/zlib/zlib")
set(ZLIB_FOUND TRUE)
endif()
+5 -26
View File
@@ -8,9 +8,9 @@
<LibraryPath>$(SolutionDir)build\lib\$(Configuration)-$(Platform)\;$(UniversalCRT_LibraryPath_x64);$(LibraryPath)</LibraryPath>
<IntDir>$(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)\</IntDir>
<GTestPath>$(SolutionDir)packages\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-static.1.8.1.8\build\native\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-static.targets</GTestPath>
<GTestInstalled Condition="Exists('$(GTestPath)') AND '$(SKIP_RPCS3_TEST)' == ''">true</GTestInstalled>
<OpenCvBuildDir>$(SolutionDir)3rdparty\opencv\opencv\opencv414\build</OpenCvBuildDir>
<OpenCvWorld>opencv_world4140</OpenCvWorld>
<GTestInstalled Condition="Exists('$(GTestPath)')">true</GTestInstalled>
<OpenCvBuildDir>$(SolutionDir)3rdparty\opencv\opencv\opencv413\build</OpenCvBuildDir>
<OpenCvWorld>opencv_world4130</OpenCvWorld>
</PropertyGroup>
<ItemDefinitionGroup>
<Lib>
@@ -36,7 +36,6 @@
avutil.lib;
swresample.lib;
swscale.lib;
LLVMABI.lib;
LLVMAggressiveInstCombine.lib;
LLVMAnalysis.lib;
LLVMAsmParser.lib;
@@ -45,10 +44,9 @@
LLVMBitReader.lib;
LLVMBitstreamReader.lib;
LLVMBitWriter.lib;
LLVMCAS.lib;
LLVMCFGuard.lib;
LLVMCGData.lib;
LLVMCodeGen.lib;
LLVMCodeGenData.lib;
LLVMCodeGenTypes.lib;
LLVMCore.lib;
LLVMCoroutines.lib;
@@ -57,15 +55,12 @@
LLVMDebugInfoCodeView.lib;
LLVMDebuginfod.lib;
LLVMDebugInfoDWARF.lib;
LLVMDebugInfoDWARFLowLevel.lib;
LLVMDebugInfoGSYM.lib;
LLVMDebugInfoLogicalView.lib;
LLVMDebugInfoMSF.lib;
LLVMDebugInfoPDB.lib;
LLVMDemangle.lib;
LLVMDlltoolDriver.lib;
LLVMDTLTO.lib;
LLVMDWARFCFIChecker.lib;
LLVMDWARFLinker.lib;
LLVMDWARFLinkerClassic.lib;
LLVMDWARFLinkerParallel.lib;
@@ -73,8 +68,6 @@
LLVMExecutionEngine.lib;
LLVMExtensions.lib;
LLVMFileCheck.lib;
LLVMFrontendAtomic.lib;
LLVMFrontendDirective.lib;
LLVMFrontendDriver.lib;
LLVMFrontendHLSL.lib;
LLVMFrontendOffloading.lib;
@@ -114,7 +107,6 @@
LLVMOrcShared.lib;
LLVMOrcTargetProcess.lib;
LLVMPasses.lib;
LLVMPlugins.lib;
LLVMProfileData.lib;
LLVMRemarks.lib;
LLVMRuntimeDyld.lib;
@@ -122,14 +114,12 @@
LLVMScalarOpts.lib;
LLVMSelectionDAG.lib;
LLVMSupport.lib;
LLVMSupportLSP.lib;
LLVMSymbolize.lib;
LLVMTableGen.lib;
LLVMTableGenBasic.lib;
LLVMTableGenCommon.lib;
LLVMTarget.lib;
LLVMTargetParser.lib;
LLVMTelemetry.lib;
LLVMTextAPI.lib;
LLVMTextAPIBinaryReader.lib;
LLVMTransformUtils.lib;
@@ -233,23 +223,12 @@
absl_time_zone.lib;
libutf8_validity.lib;
libutf8_range.lib;
libprotobuf-lite.lib;
</AdditionalDependencies>
<AdditionalLibraryDirectories>$(SolutionDir)3rdparty\ffmpeg\lib\windows\x86_64</AdditionalLibraryDirectories>
<StackReserveSize>8388608</StackReserveSize>
<StackCommitSize>1048576</StackCommitSize>
</Link>
<Link Condition="'$(Configuration)'=='Release'">
<AdditionalDependencies>
libprotobuf-lite.lib;
%(AdditionalDependencies)
</AdditionalDependencies>
</Link>
<Link Condition="'$(Configuration)'=='Debug'">
<AdditionalDependencies>
libprotobuf-lited.lib;
%(AdditionalDependencies)
</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup />
</Project>
-49
View File
@@ -1,49 +0,0 @@
# DualShock 3
notify 100 {
match "system" "USB";
match "subsystem" "INTERFACE";
match "type" "ATTACH";
match "vendor" "0x054c";
match "product" "0x0268";
action "chmod 0666 /dev/$cdev";
};
# DualShock 4
notify 100 {
match "system" "USB";
match "subsystem" "INTERFACE";
match "type" "ATTACH";
match "vendor" "0x054c";
match "product" "0x05c4";
action "chmod 0666 /dev/$cdev";
};
# DualShock 4 Wireless Adapter
notify 100 {
match "system" "USB";
match "subsystem" "INTERFACE";
match "type" "ATTACH";
match "vendor" "0x054c";
match "product" "0x0ba0";
action "chmod 0666 /dev/$cdev";
};
# DualShock 4 Slim
notify 100 {
match "system" "USB";
match "subsystem" "INTERFACE";
match "type" "ATTACH";
match "vendor" "0x054c";
match "product" "0x09cc";
action "chmod 0666 /dev/$cdev";
};
# DualSense
notify 100 {
match "system" "USB";
match "subsystem" "INTERFACE";
match "type" "ATTACH";
match "vendor" "0x054c";
match "product" "0x0ce6";
action "chmod 0666 /dev/$cdev";
};
-26
View File
@@ -1,26 +0,0 @@
# DualShock 3 over USB
KERNEL=="hidraw*", ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0268", MODE="0666"
# DualShock 3 over Bluetooth
KERNEL=="hidraw*", KERNELS=="*054C:0268*", MODE="0666"
# DualShock 4 over USB
KERNEL=="hidraw*", ATTRS{idVendor}=="054c", ATTRS{idProduct}=="05c4", MODE="0666"
# DualShock 4 Wireless Adapter over USB
KERNEL=="hidraw*", ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0ba0", MODE="0666"
# DualShock 4 Slim over USB
KERNEL=="hidraw*", ATTRS{idVendor}=="054c", ATTRS{idProduct}=="09cc", MODE="0666"
# DualShock 4 over Bluetooth
KERNEL=="hidraw*", KERNELS=="*054C:05C4*", MODE="0666"
# DualShock 4 Slim over Bluetooth
KERNEL=="hidraw*", KERNELS=="*054C:09CC*", MODE="0666"
# PS5 DualSense controller over USB hidraw
KERNEL=="hidraw*", ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0ce6", MODE="0666", TAG+="uaccess"
# PS5 DualSense controller over bluetooth hidraw
KERNEL=="hidraw*", KERNELS=="*054C:0CE6*", MODE="0666", TAG+="uaccess"
+5 -20
View File
@@ -182,21 +182,17 @@ if(BUILD_RPCS3_TESTS)
target_sources(rpcs3_test
PRIVATE
tests/test.cpp
tests/test_address_range.cpp
tests/test_bit_set.cpp
tests/test_cctype.cpp
tests/test_dmux_pamf.cpp
tests/test_fmt.cpp
tests/test_iso_open.cpp
tests/test_iso_extent.cpp
tests/test_pair.cpp
tests/test_tuple.cpp
tests/test_simple_array.cpp
tests/test_address_range.cpp
tests/test_sys_fs.cpp
tests/test_rsx_cfg.cpp
tests/test_rsx_fp_asm.cpp
tests/test_rsx_mm_queue.cpp
tests/test_simple_array.cpp
tests/test_dmux_pamf.cpp
tests/test_spu_analyser.cpp
tests/test_sys_fs.cpp
tests/test_tuple.cpp
tests/test_types_util.cpp
)
@@ -225,14 +221,3 @@ if(BUILD_RPCS3_TESTS)
)
endif()
endif()
# Udev rules, per platform
if (BUNDLE_UDEV_RULES)
if(CMAKE_SYSTEM_NAME MATCHES "Linux")
install(FILES ../config/udev/udev.rules
DESTINATION ${CMAKE_INSTALL_LIBDIR}/udev/rules.d/ RENAME 99-rpcs3.rules)
elseif(CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
install(FILES ../config/udev/devd.conf
DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/devd/ RENAME rpcs3.conf)
endif()
endif()
+156 -194
View File
@@ -9,28 +9,24 @@
#include "Emu/system_utils.hpp"
#include "util/asm.hpp"
#include "util/cctype.hpp"
#include <algorithm>
#include <span>
LOG_CHANNEL(edat_log, "EDAT");
void generate_key(int crypto_mode, int version, u8* key_final, u8* iv_final, const u8* key, const u8* iv)
void generate_key(int crypto_mode, int version, unsigned char *key_final, unsigned char *iv_final, unsigned char *key, unsigned char *iv)
{
const int mode = crypto_mode & 0xF0000000;
int mode = crypto_mode & 0xF0000000;
uchar temp_iv[16]{};
switch (mode)
{
case 0x10000000:
{
// Encrypted ERK.
// Decrypt the key with EDAT_KEY + EDAT_IV and copy the original IV.
u8 temp_iv[16]{};
memcpy(temp_iv, EDAT_IV, 0x10);
aescbc128_decrypt(const_cast<u8*>(version ? EDAT_KEY_1 : EDAT_KEY_0), temp_iv, key, key_final, 0x10);
memcpy(iv_final, iv, 0x10);
break;
}
case 0x20000000:
// Default ERK.
// Use EDAT_KEY and EDAT_IV.
@@ -46,20 +42,18 @@ void generate_key(int crypto_mode, int version, u8* key_final, u8* iv_final, con
}
}
void generate_hash(int hash_mode, int version, u8* hash_final, const u8* hash)
void generate_hash(int hash_mode, int version, unsigned char *hash_final, unsigned char *hash)
{
const int mode = hash_mode & 0xF0000000;
int mode = hash_mode & 0xF0000000;
uchar temp_iv[16]{};
switch (mode)
{
case 0x10000000:
{
// Encrypted HASH.
// Decrypt the hash with EDAT_KEY + EDAT_IV.
u8 temp_iv[16]{};
memcpy(temp_iv, EDAT_IV, 0x10);
aescbc128_decrypt(const_cast<u8*>(version ? EDAT_KEY_1 : EDAT_KEY_0), temp_iv, hash, hash_final, 0x10);
break;
}
case 0x20000000:
// Default HASH.
// Use EDAT_HASH.
@@ -73,13 +67,13 @@ void generate_hash(int hash_mode, int version, u8* hash_final, const u8* hash)
};
}
bool decrypt(int hash_mode, int crypto_mode, int version, const u8* in, u8* out, usz length, const u8* key, const u8* iv, const u8* hash, const u8* test_hash)
bool decrypt(int hash_mode, int crypto_mode, int version, unsigned char *in, unsigned char *out, usz length, unsigned char *key, unsigned char *iv, unsigned char *hash, unsigned char *test_hash)
{
// Setup buffers for key, iv and hash.
u8 key_final[0x10] = {};
u8 iv_final[0x10] = {};
u8 hash_final_10[0x10] = {};
u8 hash_final_14[0x14] = {};
unsigned char key_final[0x10] = {};
unsigned char iv_final[0x10] = {};
unsigned char hash_final_10[0x10] = {};
unsigned char hash_final_14[0x14] = {};
// Generate crypto key and hash.
generate_key(crypto_mode, version, key_final, iv_final, key, iv);
@@ -122,25 +116,25 @@ bool decrypt(int hash_mode, int crypto_mode, int version, const u8* in, u8* out,
}
// EDAT/SDAT functions.
std::tuple<u64, s32, s32> dec_section(const u8* metadata)
std::tuple<u64, s32, s32> dec_section(unsigned char* metadata)
{
std::array<u8, 0x10> dec;
dec[0x0] = (metadata[0xC] ^ metadata[0x8] ^ metadata[0x10]);
dec[0x1] = (metadata[0xD] ^ metadata[0x9] ^ metadata[0x11]);
dec[0x2] = (metadata[0xE] ^ metadata[0xA] ^ metadata[0x12]);
dec[0x3] = (metadata[0xF] ^ metadata[0xB] ^ metadata[0x13]);
dec[0x4] = (metadata[0x4] ^ metadata[0x8] ^ metadata[0x14]);
dec[0x5] = (metadata[0x5] ^ metadata[0x9] ^ metadata[0x15]);
dec[0x6] = (metadata[0x6] ^ metadata[0xA] ^ metadata[0x16]);
dec[0x7] = (metadata[0x7] ^ metadata[0xB] ^ metadata[0x17]);
dec[0x8] = (metadata[0xC] ^ metadata[0x0] ^ metadata[0x18]);
dec[0x9] = (metadata[0xD] ^ metadata[0x1] ^ metadata[0x19]);
dec[0xA] = (metadata[0xE] ^ metadata[0x2] ^ metadata[0x1A]);
dec[0xB] = (metadata[0xF] ^ metadata[0x3] ^ metadata[0x1B]);
dec[0xC] = (metadata[0x4] ^ metadata[0x0] ^ metadata[0x1C]);
dec[0xD] = (metadata[0x5] ^ metadata[0x1] ^ metadata[0x1D]);
dec[0xE] = (metadata[0x6] ^ metadata[0x2] ^ metadata[0x1E]);
dec[0xF] = (metadata[0x7] ^ metadata[0x3] ^ metadata[0x1F]);
dec[0x00] = (metadata[0xC] ^ metadata[0x8] ^ metadata[0x10]);
dec[0x01] = (metadata[0xD] ^ metadata[0x9] ^ metadata[0x11]);
dec[0x02] = (metadata[0xE] ^ metadata[0xA] ^ metadata[0x12]);
dec[0x03] = (metadata[0xF] ^ metadata[0xB] ^ metadata[0x13]);
dec[0x04] = (metadata[0x4] ^ metadata[0x8] ^ metadata[0x14]);
dec[0x05] = (metadata[0x5] ^ metadata[0x9] ^ metadata[0x15]);
dec[0x06] = (metadata[0x6] ^ metadata[0xA] ^ metadata[0x16]);
dec[0x07] = (metadata[0x7] ^ metadata[0xB] ^ metadata[0x17]);
dec[0x08] = (metadata[0xC] ^ metadata[0x0] ^ metadata[0x18]);
dec[0x09] = (metadata[0xD] ^ metadata[0x1] ^ metadata[0x19]);
dec[0x0A] = (metadata[0xE] ^ metadata[0x2] ^ metadata[0x1A]);
dec[0x0B] = (metadata[0xF] ^ metadata[0x3] ^ metadata[0x1B]);
dec[0x0C] = (metadata[0x4] ^ metadata[0x0] ^ metadata[0x1C]);
dec[0x0D] = (metadata[0x5] ^ metadata[0x1] ^ metadata[0x1D]);
dec[0x0E] = (metadata[0x6] ^ metadata[0x2] ^ metadata[0x1E]);
dec[0x0F] = (metadata[0x7] ^ metadata[0x3] ^ metadata[0x1F]);
u64 offset = read_from_ptr<be_t<u64>>(dec, 0);
s32 length = read_from_ptr<be_t<s32>>(dec, 8);
@@ -149,26 +143,26 @@ std::tuple<u64, s32, s32> dec_section(const u8* metadata)
return std::make_tuple(offset, length, compression_end);
}
u128 get_block_key(int block, const NPD_HEADER& npd)
u128 get_block_key(int block, NPD_HEADER *npd)
{
const u8 empty_key[0x10] = {};
const u8* src_key = (npd.version <= 1) ? empty_key : npd.dev_hash;
unsigned char empty_key[0x10] = {};
unsigned char *src_key = (npd->version <= 1) ? empty_key : npd->dev_hash;
u128 dest_key{};
std::memcpy(&dest_key, src_key, 0xC);
const s32 swappedBlock = std::bit_cast<be_t<s32>>(block);
std::memcpy(reinterpret_cast<u8*>(&dest_key) + 0xC, &swappedBlock, sizeof(swappedBlock));
s32 swappedBlock = std::bit_cast<be_t<s32>>(block);
std::memcpy(reinterpret_cast<uchar*>(&dest_key) + 0xC, &swappedBlock, sizeof(swappedBlock));
return dest_key;
}
// for out data, allocate a buffer the size of 'edat.block_size'
// for out data, allocate a buffer the size of 'edat->block_size'
// Also, set 'in file' to the beginning of the encrypted data, which may be offset if inside another file, but normally just reset to beginning of file
// returns number of bytes written, -1 for error
s64 decrypt_block(const fs::file& in, std::vector<u8>& out, const EDAT_HEADER& edat, const NPD_HEADER& npd, const u8* crypt_key, u32 block_num, u32 total_blocks, u64 size_left, bool is_out_buffer_aligned = false, bool verbose = true)
s64 decrypt_block(const fs::file* in, u8* out, EDAT_HEADER *edat, NPD_HEADER *npd, u8* crypt_key, u32 block_num, u32 total_blocks, u64 size_left, bool is_out_buffer_aligned = false)
{
// Get metadata info and setup buffers.
const u64 metadata_section_size = ((edat.flags & EDAT_COMPRESSED_FLAG) != 0 || (edat.flags & EDAT_FLAG_0x20) != 0) ? 0x20 : 0x10;
constexpr u64 metadata_offset = 0x100;
const int metadata_section_size = ((edat->flags & EDAT_COMPRESSED_FLAG) != 0 || (edat->flags & EDAT_FLAG_0x20) != 0) ? 0x20 : 0x10;
const int metadata_offset = 0x100;
u8 hash[0x10] = { 0 };
u8 key_result[0x10] = { 0 };
@@ -178,20 +172,20 @@ s64 decrypt_block(const fs::file& in, std::vector<u8>& out, const EDAT_HEADER& e
u64 metadata_sec_offset = 0;
u64 length = 0;
s32 compression_end = 0;
u8 empty_iv[0x10] = {};
unsigned char empty_iv[0x10] = {};
// Decrypt the metadata.
if ((edat.flags & EDAT_COMPRESSED_FLAG) != 0)
if ((edat->flags & EDAT_COMPRESSED_FLAG) != 0)
{
metadata_sec_offset = metadata_offset + u64{block_num} * metadata_section_size;
u8 metadata[0x20]{};
in.read_at(metadata_sec_offset, metadata, 0x20);
in->read_at(metadata_sec_offset, metadata, 0x20);
// If the data is compressed, decrypt the metadata.
// NOTE: For NPD version 1 the metadata is not encrypted.
if (npd.version <= 1)
if (npd->version <= 1)
{
offset = read_from_ptr<be_t<u64>>(metadata, 0x10);
length = read_from_ptr<be_t<s32>>(metadata, 0x18);
@@ -204,13 +198,13 @@ s64 decrypt_block(const fs::file& in, std::vector<u8>& out, const EDAT_HEADER& e
std::memcpy(hash_result, metadata, 0x10);
}
else if ((edat.flags & EDAT_FLAG_0x20) != 0)
else if ((edat->flags & EDAT_FLAG_0x20) != 0)
{
// If FLAG 0x20, the metadata precedes each data block.
metadata_sec_offset = metadata_offset + u64{block_num} * (metadata_section_size + edat.block_size);
metadata_sec_offset = metadata_offset + u64{block_num} * (metadata_section_size + edat->block_size);
u8 metadata[0x20]{};
in.read_at(metadata_sec_offset, metadata, 0x20);
in->read_at(metadata_sec_offset, metadata, 0x20);
std::memcpy(hash_result, metadata, 0x14);
@@ -219,22 +213,22 @@ s64 decrypt_block(const fs::file& in, std::vector<u8>& out, const EDAT_HEADER& e
hash_result[j] = metadata[j] ^ metadata[j + 0x10];
offset = metadata_sec_offset + 0x20;
length = edat.block_size;
length = edat->block_size;
if ((block_num == (total_blocks - 1)) && (edat.file_size % edat.block_size))
length = static_cast<s32>(edat.file_size % edat.block_size);
if ((block_num == (total_blocks - 1)) && (edat->file_size % edat->block_size))
length = static_cast<s32>(edat->file_size % edat->block_size);
}
else
{
metadata_sec_offset = metadata_offset + u64{block_num} * metadata_section_size;
in.read_at(metadata_sec_offset, hash_result, 0x10);
in->read_at(metadata_sec_offset, hash_result, 0x10);
offset = metadata_offset + u64{block_num} * edat.block_size + total_blocks * metadata_section_size;
length = edat.block_size;
offset = metadata_offset + u64{block_num} * edat->block_size + total_blocks * metadata_section_size;
length = edat->block_size;
if ((block_num == (total_blocks - 1)) && (edat.file_size % edat.block_size))
length = static_cast<s32>(edat.file_size % edat.block_size);
if ((block_num == (total_blocks - 1)) && (edat->file_size % edat->block_size))
length = static_cast<s32>(edat->file_size % edat->block_size);
}
// Locate the real data.
@@ -246,24 +240,23 @@ s64 decrypt_block(const fs::file& in, std::vector<u8>& out, const EDAT_HEADER& e
std::vector<u8> dec_data_buf(length);
// Try to use out buffer for file reads if no padding is needed instead of a new buffer
std::vector<u8>* enc_data = enc_data_buf.empty() ? &out : &enc_data_buf;
u8* enc_data = enc_data_buf.empty() ? out : enc_data_buf.data();
// Variable to avoid copies when possible
std::vector<u8>* dec_data = &dec_data_buf;
u8* dec_data = dec_data_buf.data();
std::memset(hash, 0, 0x10);
std::memset(key_result, 0, 0x10);
ensure(enc_data->size() >= length);
in.read_at(offset, enc_data->data(), length);
in->read_at(offset, enc_data, length);
// Generate a key for the current block.
auto b_key = get_block_key(block_num, npd);
// Encrypt the block key with the crypto key.
aesecb128_encrypt(crypt_key, reinterpret_cast<u8*>(&b_key), key_result);
aesecb128_encrypt(crypt_key, reinterpret_cast<uchar*>(&b_key), key_result);
if ((edat.flags & EDAT_FLAG_0x10) != 0)
if ((edat->flags & EDAT_FLAG_0x10) != 0)
{
aesecb128_encrypt(crypt_key, key_result, hash); // If FLAG 0x10 is set, encrypt again to get the final hash.
}
@@ -273,25 +266,25 @@ s64 decrypt_block(const fs::file& in, std::vector<u8>& out, const EDAT_HEADER& e
}
// Setup the crypto and hashing mode based on the extra flags.
int crypto_mode = ((edat.flags & EDAT_FLAG_0x02) == 0) ? 0x2 : 0x1;
int crypto_mode = ((edat->flags & EDAT_FLAG_0x02) == 0) ? 0x2 : 0x1;
int hash_mode;
if ((edat.flags & EDAT_FLAG_0x10) == 0)
if ((edat->flags & EDAT_FLAG_0x10) == 0)
hash_mode = 0x02;
else if ((edat.flags & EDAT_FLAG_0x20) == 0)
else if ((edat->flags & EDAT_FLAG_0x20) == 0)
hash_mode = 0x04;
else
hash_mode = 0x01;
if ((edat.flags & EDAT_ENCRYPTED_KEY_FLAG) != 0)
if ((edat->flags & EDAT_ENCRYPTED_KEY_FLAG) != 0)
{
crypto_mode |= 0x10000000;
hash_mode |= 0x10000000;
}
const bool should_decompress = ((edat.flags & EDAT_COMPRESSED_FLAG) != 0) && compression_end;
const bool should_decompress = ((edat->flags & EDAT_COMPRESSED_FLAG) != 0) && compression_end;
if ((edat.flags & EDAT_DEBUG_DATA_FLAG) != 0)
if ((edat->flags & EDAT_DEBUG_DATA_FLAG) != 0)
{
// Reset the flags.
crypto_mode |= 0x01000000;
@@ -300,7 +293,7 @@ s64 decrypt_block(const fs::file& in, std::vector<u8>& out, const EDAT_HEADER& e
// Simply copy the data without the header or the footer.
if (should_decompress)
{
std::memcpy(dec_data->data(), enc_data->data(), length);
std::memcpy(dec_data, enc_data, length);
}
else
{
@@ -311,16 +304,12 @@ s64 decrypt_block(const fs::file& in, std::vector<u8>& out, const EDAT_HEADER& e
else
{
// IV is null if NPD version is 1 or 0.
const u8* iv = (npd.version <= 1) ? empty_iv : npd.digest;
u8* iv = (npd->version <= 1) ? empty_iv : npd->digest;
// Call main crypto routine on this data block.
if (!decrypt(hash_mode, crypto_mode, (npd.version == 4), enc_data->data(), dec_data->data(), length, key_result, iv, hash, hash_result))
if (!decrypt(hash_mode, crypto_mode, (npd->version == 4), enc_data, dec_data, length, key_result, iv, hash, hash_result))
{
if (verbose)
{
edat_log.error("Block at offset 0x%llx has invalid hash!", offset);
}
edat_log.error("Block at offset 0x%llx has invalid hash!", offset);
return -1;
}
}
@@ -328,7 +317,7 @@ s64 decrypt_block(const fs::file& in, std::vector<u8>& out, const EDAT_HEADER& e
// Apply additional de-compression if needed and write the decrypted data.
if (should_decompress)
{
const int res = decompress(out.data(), dec_data->data(), edat.block_size);
const int res = decompress(out, dec_data, edat->block_size);
size_left -= res;
@@ -344,46 +333,44 @@ s64 decrypt_block(const fs::file& in, std::vector<u8>& out, const EDAT_HEADER& e
return res;
}
if (dec_data != &out)
if (dec_data != out)
{
ensure(out.size() >= pad_length);
ensure(dec_data->size() >= pad_length);
std::memcpy(out.data(), dec_data->data(), pad_length);
std::memcpy(out, dec_data, pad_length);
}
return pad_length;
}
// set file offset to beginning before calling
bool check_data(const u8* key, const EDAT_HEADER& edat, const NPD_HEADER& npd, const fs::file& f, bool verbose)
bool check_data(u8* key, EDAT_HEADER* edat, NPD_HEADER* npd, const fs::file* f, bool verbose)
{
u8 header[0xA0] = { 0 };
u8 empty_header[0xA0] = { 0 };
u8 header_hash[0x10] = { 0 };
u8 metadata_hash[0x10] = { 0 };
const u64 file_offset = f.pos();
const u64 file_offset = f->pos();
// Check NPD version and flags.
if ((npd.version == 0) || (npd.version == 1))
if ((npd->version == 0) || (npd->version == 1))
{
if (edat.flags & 0x7EFFFFFE)
if (edat->flags & 0x7EFFFFFE)
{
edat_log.error("Bad header flags!");
return false;
}
}
else if (npd.version == 2)
else if (npd->version == 2)
{
if (edat.flags & 0x7EFFFFE0)
if (edat->flags & 0x7EFFFFE0)
{
edat_log.error("Bad header flags!");
return false;
}
}
else if ((npd.version == 3) || (npd.version == 4))
else if ((npd->version == 3) || (npd->version == 4))
{
if (edat.flags & 0x7EFFFFC0)
if (edat->flags & 0x7EFFFFC0)
{
edat_log.error("Bad header flags!");
return false;
@@ -396,17 +383,17 @@ bool check_data(const u8* key, const EDAT_HEADER& edat, const NPD_HEADER& npd, c
}
// Read in the file header.
f.read(header, 0xA0);
f->read(header, 0xA0);
// Read in the header and metadata section hashes.
f.seek(file_offset + 0x90);
f.read(metadata_hash, 0x10);
f.read(header_hash, 0x10);
f->seek(file_offset + 0x90);
f->read(metadata_hash, 0x10);
f->read(header_hash, 0x10);
// Setup the hashing mode and the crypto mode used in the file.
constexpr int crypto_mode = 0x1;
int hash_mode = ((edat.flags & EDAT_ENCRYPTED_KEY_FLAG) == 0) ? 0x00000002 : 0x10000002;
if ((edat.flags & EDAT_DEBUG_DATA_FLAG) != 0)
const int crypto_mode = 0x1;
int hash_mode = ((edat->flags & EDAT_ENCRYPTED_KEY_FLAG) == 0) ? 0x00000002 : 0x10000002;
if ((edat->flags & EDAT_DEBUG_DATA_FLAG) != 0)
{
hash_mode |= 0x01000000;
@@ -415,17 +402,17 @@ bool check_data(const u8* key, const EDAT_HEADER& edat, const NPD_HEADER& npd, c
}
// Setup header key and iv buffers.
u8 header_key[0x10] = { 0 };
u8 header_iv[0x10] = { 0 };
unsigned char header_key[0x10] = { 0 };
unsigned char header_iv[0x10] = { 0 };
// Test the header hash (located at offset 0xA0).
if (!decrypt(hash_mode, crypto_mode, (npd.version == 4), header, empty_header, 0xA0, header_key, header_iv, key, header_hash))
if (!decrypt(hash_mode, crypto_mode, (npd->version == 4), header, empty_header, 0xA0, header_key, header_iv, key, header_hash))
{
if (verbose)
edat_log.warning("Header hash is invalid!");
// If the header hash test fails and the data is not DEBUG, then RAP/RIF/KLIC key is invalid.
if ((edat.flags & EDAT_DEBUG_DATA_FLAG) != EDAT_DEBUG_DATA_FLAG)
if ((edat->flags & EDAT_DEBUG_DATA_FLAG) != EDAT_DEBUG_DATA_FLAG)
{
edat_log.error("RAP/RIF/KLIC key is invalid!");
return false;
@@ -433,25 +420,24 @@ bool check_data(const u8* key, const EDAT_HEADER& edat, const NPD_HEADER& npd, c
}
// Parse the metadata info.
if ((edat.flags & EDAT_COMPRESSED_FLAG) != 0)
const int metadata_section_size = ((edat->flags & EDAT_COMPRESSED_FLAG) != 0 || (edat->flags & EDAT_FLAG_0x20) != 0) ? 0x20 : 0x10;
if (((edat->flags & EDAT_COMPRESSED_FLAG) != 0))
{
if (verbose)
edat_log.warning("COMPRESSED data detected!");
}
if (!edat.block_size)
if (!edat->block_size)
{
return false;
}
const u64 metadata_section_size = ((edat.flags & EDAT_COMPRESSED_FLAG) != 0 || (edat.flags & EDAT_FLAG_0x20) != 0) ? 0x20 : 0x10;
const usz block_num = utils::aligned_div<u64>(edat.file_size, edat.block_size);
const usz block_num = utils::aligned_div<u64>(edat->file_size, edat->block_size);
constexpr usz metadata_offset = 0x100;
const usz metadata_size = utils::mul_saturate<u64>(metadata_section_size, block_num);
u64 metadata_section_offset = metadata_offset;
if (utils::add_saturate<u64>(utils::add_saturate<u64>(file_offset, metadata_section_offset), metadata_size) > f.size())
if (utils::add_saturate<u64>(utils::add_saturate<u64>(file_offset, metadata_section_offset), metadata_size) > f->size())
{
return false;
}
@@ -466,43 +452,43 @@ bool check_data(const u8* key, const EDAT_HEADER& edat, const NPD_HEADER& npd, c
const usz offset = file_offset + metadata_section_offset;
// Read in the metadata.
f.read_at(offset, metadata.get() + bytes_read, metadata_section_size);
f->read_at(offset, metadata.get() + bytes_read, metadata_section_size);
// Adjust sizes.
bytes_read += metadata_section_size;
if (((edat.flags & EDAT_FLAG_0x20) != 0)) // Metadata block before each data block.
metadata_section_offset += (metadata_section_size + edat.block_size);
if (((edat->flags & EDAT_FLAG_0x20) != 0)) // Metadata block before each data block.
metadata_section_offset += (metadata_section_size + edat->block_size);
else
metadata_section_offset += metadata_section_size;
}
// Test the metadata section hash (located at offset 0x90).
if (!decrypt(hash_mode, crypto_mode, (npd.version == 4), metadata.get(), empty_metadata.get(), metadata_size, header_key, header_iv, key, metadata_hash))
if (!decrypt(hash_mode, crypto_mode, (npd->version == 4), metadata.get(), empty_metadata.get(), metadata_size, header_key, header_iv, key, metadata_hash))
{
if (verbose)
edat_log.warning("Metadata section hash is invalid!");
}
// Checking ECDSA signatures.
if ((edat.flags & EDAT_DEBUG_DATA_FLAG) == 0)
if ((edat->flags & EDAT_DEBUG_DATA_FLAG) == 0)
{
// Setup buffers.
u8 metadata_signature[0x28] = { 0 };
u8 header_signature[0x28] = { 0 };
u8 signature_hash[20] = { 0 };
u8 signature_r[0x15] = { 0 };
u8 signature_s[0x15] = { 0 };
u8 zero_buf[0x15] = { 0 };
unsigned char metadata_signature[0x28] = { 0 };
unsigned char header_signature[0x28] = { 0 };
unsigned char signature_hash[20] = { 0 };
unsigned char signature_r[0x15] = { 0 };
unsigned char signature_s[0x15] = { 0 };
unsigned char zero_buf[0x15] = { 0 };
// Setup ECDSA curve and public key.
ecdsa_set_curve(VSH_CURVE_P, VSH_CURVE_A, VSH_CURVE_B, VSH_CURVE_N, VSH_CURVE_GX, VSH_CURVE_GY);
ecdsa_set_pub(VSH_PUB);
// Read in the metadata and header signatures.
f.seek(0xB0);
f.read(metadata_signature, 0x28);
f.read(header_signature, 0x28);
f->seek(0xB0);
f->read(metadata_signature, 0x28);
f->read(header_signature, 0x28);
// Checking metadata signature.
// Setup signature r and s.
@@ -517,13 +503,13 @@ bool check_data(const u8* key, const EDAT_HEADER& edat, const NPD_HEADER& npd, c
else
{
// Setup signature hash.
if ((edat.flags & EDAT_FLAG_0x20) != 0) //Sony failed again, they used buffer from 0x100 with half size of real metadata.
if ((edat->flags & EDAT_FLAG_0x20) != 0) //Sony failed again, they used buffer from 0x100 with half size of real metadata.
{
const usz metadata_buf_size = block_num * 0x10;
std::vector<u8> metadata_buf(metadata_buf_size);
f.read_at(file_offset + metadata_offset, metadata_buf.data(), metadata_buf_size);
f->read_at(file_offset + metadata_offset, metadata_buf.data(), metadata_buf_size);
sha1(metadata_buf.data(), metadata_buf_size, signature_hash);
}
@@ -533,7 +519,7 @@ bool check_data(const u8* key, const EDAT_HEADER& edat, const NPD_HEADER& npd, c
if (!ecdsa_verify(signature_hash, signature_r, signature_s))
{
edat_log.warning("Metadata signature is invalid!");
if (((edat.block_size + 0ull) * block_num) > 0x100000000)
if (((edat->block_size + 0ull) * block_num) > 0x100000000)
edat_log.warning("*Due to large file size, metadata signature status may be incorrect!");
}
}
@@ -556,7 +542,7 @@ bool check_data(const u8* key, const EDAT_HEADER& edat, const NPD_HEADER& npd, c
u8 header_buf[0xD8]{};
f.read_at(file_offset, header_buf, 0xD8);
f->read_at(file_offset, header_buf, 0xD8);
sha1(header_buf, 0xD8, signature_hash);
if (!ecdsa_verify(signature_hash, signature_r, signature_s))
@@ -567,27 +553,27 @@ bool check_data(const u8* key, const EDAT_HEADER& edat, const NPD_HEADER& npd, c
return true;
}
bool validate_dev_klic(const u8* klicensee, const NPD_HEADER& npd)
bool validate_dev_klic(const u8* klicensee, NPD_HEADER *npd)
{
if ((npd.license & 0x3) != 0x3)
if ((npd->license & 0x3) != 0x3)
{
return true;
}
u8 dev[0x60]{};
unsigned char dev[0x60]{};
// Build the dev buffer (first 0x60 bytes of NPD header in big-endian).
std::memcpy(dev, &npd, 0x60);
std::memcpy(dev, npd, 0x60);
// Fix endianness.
s32 version = std::bit_cast<be_t<s32>>(npd.version);
s32 license = std::bit_cast<be_t<s32>>(npd.license);
s32 type = std::bit_cast<be_t<s32>>(npd.type);
s32 version = std::bit_cast<be_t<s32>>(npd->version);
s32 license = std::bit_cast<be_t<s32>>(npd->license);
s32 type = std::bit_cast<be_t<s32>>(npd->type);
std::memcpy(dev + 0x4, &version, 4);
std::memcpy(dev + 0x8, &license, 4);
std::memcpy(dev + 0xC, &type, 4);
// Check for an empty dev_hash (can't validate if devklic is nullptr);
// Check for an empty dev_hash (can't validate if devklic is NULL);
u128 klic;
std::memcpy(&klic, klicensee, sizeof(klic));
@@ -595,13 +581,13 @@ bool validate_dev_klic(const u8* klicensee, const NPD_HEADER& npd)
u128 key = klic ^ std::bit_cast<u128>(NP_OMAC_KEY_2);
// Hash with generated key and compare with dev_hash.
return cmac_hash_compare(reinterpret_cast<u8*>(&key), 0x10, dev, 0x60, npd.dev_hash, 0x10);
return cmac_hash_compare(reinterpret_cast<uchar*>(&key), 0x10, dev, 0x60, npd->dev_hash, 0x10);
}
bool validate_npd_hashes(std::string_view file_name, const u8* klicensee, const NPD_HEADER& npd, const EDAT_HEADER& edat, bool verbose)
bool validate_npd_hashes(std::string_view file_name, const u8* klicensee, NPD_HEADER* npd, EDAT_HEADER* edat, bool verbose)
{
// Ignore header validation in DEBUG data.
if (edat.flags & EDAT_DEBUG_DATA_FLAG)
if (edat->flags & EDAT_DEBUG_DATA_FLAG)
{
return true;
}
@@ -623,7 +609,7 @@ bool validate_npd_hashes(std::string_view file_name, const u8* klicensee, const
std::unique_ptr<u8[]> buf_upper(new u8[buf_len]);
// Build the title buffer (content_id + file_name).
std::memcpy(buf.get(), npd.content_id, 0x30);
std::memcpy(buf.get(), npd->content_id, 0x30);
std::memcpy(buf.get() + 0x30, file_name.data(), file_name.size());
std::memcpy(buf_lower.get(), buf.get(), buf_len);
@@ -634,16 +620,16 @@ bool validate_npd_hashes(std::string_view file_name, const u8* klicensee, const
for (usz i = std::distance(it, buf_span.rend()) - 1; i < buf_len; ++i)
{
const u8 c = buf[i];
buf_upper[i] = utils::toupper(c);
buf_lower[i] = utils::tolower(c);
buf_upper[i] = std::toupper(c);
buf_lower[i] = std::tolower(c);
}
// Hash with NPDRM_OMAC_KEY_3 and compare with title_hash.
// Try to ignore case sensivity with file extension
const bool title_hash_result =
cmac_hash_compare(const_cast<u8*>(NP_OMAC_KEY_3), 0x10, buf.get(), buf_len, npd.title_hash, 0x10) ||
cmac_hash_compare(const_cast<u8*>(NP_OMAC_KEY_3), 0x10, buf_lower.get(), buf_len, npd.title_hash, 0x10) ||
cmac_hash_compare(const_cast<u8*>(NP_OMAC_KEY_3), 0x10, buf_upper.get(), buf_len, npd.title_hash, 0x10);
cmac_hash_compare(const_cast<u8*>(NP_OMAC_KEY_3), 0x10, buf.get(), buf_len, npd->title_hash, 0x10) ||
cmac_hash_compare(const_cast<u8*>(NP_OMAC_KEY_3), 0x10, buf_lower.get(), buf_len, npd->title_hash, 0x10) ||
cmac_hash_compare(const_cast<u8*>(NP_OMAC_KEY_3), 0x10, buf_upper.get(), buf_len, npd->title_hash, 0x10);
if (verbose)
{
@@ -658,8 +644,8 @@ bool validate_npd_hashes(std::string_view file_name, const u8* klicensee, const
void read_npd_edat_header(const fs::file* input, NPD_HEADER& NPD, EDAT_HEADER& EDAT)
{
u8 npd_header[0x80]{};
u8 edat_header[0x10]{};
char npd_header[0x80]{};
char edat_header[0x10]{};
usz pos = input->pos();
pos += input->read_at(pos, npd_header, sizeof(npd_header));
@@ -677,7 +663,7 @@ void read_npd_edat_header(const fs::file* input, NPD_HEADER& NPD, EDAT_HEADER& E
NPD.expire_time = read_from_ptr<be_t<s64>>(npd_header, 120);
EDAT.flags = read_from_ptr<be_t<s32>>(edat_header, 0);
EDAT.block_size = read_from_ptr<be_t<u32>>(edat_header, 4);
EDAT.block_size = read_from_ptr<be_t<s32>>(edat_header, 4);
EDAT.file_size = read_from_ptr<be_t<u64>>(edat_header, 8);
}
@@ -688,7 +674,7 @@ u128 GetEdatRifKeyFromRapFile(const fs::file& rap_file)
rap_file.read<u128>(rapkey);
rap_to_rif(reinterpret_cast<const u8*>(&rapkey), reinterpret_cast<u8*>(&rifkey));
rap_to_rif(reinterpret_cast<const uchar*>(&rapkey), reinterpret_cast<uchar*>(&rifkey));
return rifkey;
}
@@ -717,7 +703,7 @@ bool VerifyEDATHeaderWithKLicense(const fs::file& input, std::string_view input_
// Perform header validation (EDAT only).
char real_file_name[CRYPTO_MAX_PATH]{};
extract_file_name(input_file_name, real_file_name);
if (!validate_npd_hashes(real_file_name, custom_klic, NPD, EDAT, false))
if (!validate_npd_hashes(real_file_name, custom_klic, &NPD, &EDAT, false))
{
edat_log.error("NPD hash validation failed!");
return false;
@@ -772,16 +758,16 @@ fs::file DecryptEDAT(const fs::file& input, const std::string& input_file_name,
memcpy(&devklic, NP_PSP_KEY_2, 0x10);
break;
case 8:
{
if (custom_klic)
memcpy(&devklic, custom_klic, 0x10);
else
{
edat_log.error("Invalid custom klic!");
return fs::file{};
if (custom_klic != NULL)
memcpy(&devklic, custom_klic, 0x10);
else
{
edat_log.error("Invalid custom klic!");
return fs::file{};
}
break;
}
break;
}
default:
edat_log.error("Invalid mode!");
return fs::file{};
@@ -801,7 +787,7 @@ fs::file DecryptEDAT(const fs::file& input, const std::string& input_file_name,
return output;
}
bool EDATADecrypter::ReadHeader(bool verbose)
bool EDATADecrypter::ReadHeader()
{
edata_file.seek(0);
@@ -822,29 +808,14 @@ bool EDATADecrypter::ReadHeader(bool verbose)
}
else
{
// extract key from RIF
char real_file_name[CRYPTO_MAX_PATH]{};
extract_file_name(m_file_name, real_file_name);
// A klicensee that does not match the header decrypts nothing, so there is nothing to carry on with.
// DEBUG data carries no key at all, hence the exception
if (!(edatHeader.flags & EDAT_DEBUG_DATA_FLAG) && !validate_dev_klic(reinterpret_cast<const u8*>(&dec_key), npdHeader))
if (!validate_npd_hashes(real_file_name, reinterpret_cast<const u8*>(&dec_key), &npdHeader, &edatHeader, false))
{
if (verbose)
{
edat_log.error("Invalid klicensee for this file!");
}
return false;
}
// Beyond the key, this checks the title hash, taken over the name the file was packaged with: a file
// renamed since then decrypts all the same, so a mismatch is only worth a warning
if (!validate_npd_hashes(real_file_name, reinterpret_cast<const u8*>(&dec_key), npdHeader, edatHeader, false))
{
if (verbose)
{
edat_log.warning("NPD title hash is invalid!");
}
edat_log.error("NPD hash validation failed!");
return true;
}
// Select EDAT key.
@@ -860,7 +831,7 @@ bool EDATADecrypter::ReadHeader(bool verbose)
// Type 2: Use key from RAP file (RIF key). (also used for type 1 at the moment)
else
{
const std::string rap_path = rpcs3::utils::get_rap_file_path(npdHeader.get_content_id());
const std::string rap_path = rpcs3::utils::get_rap_file_path(npdHeader.content_id);
if (fs::file rap{rap_path}; rap && rap.size() >= sizeof(dec_key))
{
@@ -870,9 +841,8 @@ bool EDATADecrypter::ReadHeader(bool verbose)
// Make sure we don't have an empty RIF key.
if (!dec_key)
{
edat_log.error("A valid RAP file is needed for this EDAT file! (content id '%s', license=%d, expected '%s')",
npdHeader.get_content_id(), npdHeader.license, rap_path);
return false;
edat_log.error("A valid RAP file is needed for this EDAT file! (license=%d)", npdHeader.license);
return true;
}
edat_log.trace("RIFKEY: %s", std::bit_cast<be_t<u128>>(dec_key));
@@ -890,25 +860,21 @@ bool EDATADecrypter::ReadHeader(bool verbose)
//}
file_size = edatHeader.file_size;
total_blocks = (edatHeader.block_size == 0) ? 0 : ::narrow<u32>(utils::aligned_div(edatHeader.file_size, edatHeader.block_size));
total_blocks = ::narrow<u32>(utils::aligned_div(edatHeader.file_size, edatHeader.block_size));
// Try decrypting the first block instead
u8 data_sample[1];
if (file_size && !ReadData(0, data_sample, 1, verbose))
if (file_size && !ReadData(0, data_sample, 1))
{
if (verbose)
{
edat_log.error("NPDRM ReadData() failed!");
}
edat_log.error("NPDRM ReadData() failed!");
return false;
}
return true;
}
u64 EDATADecrypter::ReadData(u64 pos, u8* data, u64 size, bool verbose)
u64 EDATADecrypter::ReadData(u64 pos, u8* data, u64 size)
{
size = std::min<u64>(size, pos > edatHeader.file_size ? 0 : edatHeader.file_size - pos);
@@ -932,15 +898,11 @@ u64 EDATADecrypter::ReadData(u64 pos, u8* data, u64 size, bool verbose)
for (u32 i = starting_block; i < ending_block; i++)
{
u64 res = decrypt_block(edata_file, data_buf, edatHeader, npdHeader, reinterpret_cast<u8*>(&dec_key), i, total_blocks, edatHeader.file_size, true, verbose);
u64 res = decrypt_block(&edata_file, data_buf.data(), &edatHeader, &npdHeader, reinterpret_cast<uchar*>(&dec_key), i, total_blocks, edatHeader.file_size, true);
if (res == umax)
{
if (verbose)
{
edat_log.error("Error Decrypting data");
}
edat_log.error("Error Decrypting data");
return 0;
}
+4 -11
View File
@@ -49,18 +49,12 @@ struct NPD_HEADER
u8 dev_hash[0x10];
s64 activate_time;
s64 expire_time;
std::string get_content_id() const
{
const std::string_view id{content_id, sizeof(content_id)};
return std::string{id.substr(0, id.find_first_of('\0'))};
}
};
struct EDAT_HEADER
{
s32 flags;
u32 block_size;
s32 block_size;
u64 file_size;
};
@@ -107,10 +101,9 @@ public:
{
}
// false if invalid. Clearing "verbose" mutes the log of a key that does not fit, which for a caller
// trying one candidate after another is an answer rather than a failure
bool ReadHeader(bool verbose = true);
u64 ReadData(u64 pos, u8* data, u64 size, bool verbose = true);
// false if invalid
bool ReadHeader();
u64 ReadData(u64 pos, u8* data, u64 size);
fs::stat_t get_stat() override
{
+56 -265
View File
@@ -2,7 +2,6 @@
#include "aes.h"
#include "sha1.h"
#include "key_vault.h"
#include "util/asm.hpp"
#include "util/logs.hpp"
#include "Utilities/StrUtil.h"
#include "Utilities/Thread.h"
@@ -17,51 +16,6 @@
LOG_CHANNEL(pkg_log, "PKG");
// Every path in here is UTF-8, and these two conversions never fail: on Windows a byte no sequence accounts for
// becomes U+FFFD, elsewhere a path is the bytes themselves
static std::filesystem::path fs_path_from_utf8(std::string_view utf8)
{
#ifdef _WIN32
return utf8_to_wchar(utf8);
#else
return std::filesystem::path(utf8);
#endif
}
static std::string fs_path_to_utf8(const std::filesystem::path& path)
{
#ifdef _WIN32
return wchar_to_utf8(path.native());
#else
return path.native();
#endif
}
// Whether a name read from the package could reach outside the directory it is joined to: a leading "/", or a "."
// or ".." component. "/" is the only separator that counts, vfs::escape writes any other one the host may know, and
// ":", as plain characters
static bool leaves_directory(std::string_view name)
{
if (name.starts_with('/'))
{
return true;
}
for (std::string_view rest = name; !rest.empty();)
{
const usz sep = rest.find('/');
const std::string_view component = rest.substr(0, sep);
rest = sep == umax ? std::string_view{} : rest.substr(sep + 1);
if (component == "." || component == "..")
{
return true;
}
}
return false;
}
package_reader::package_reader(const std::string& path, fs::file file)
: m_path(path)
, m_file(std::move(file))
@@ -166,9 +120,9 @@ bool package_reader::read_header()
return false;
}
if (m_header.file_count > PKG_MAX_FILE_COUNT || u64(m_header.file_count) > u64(m_header.data_size) / sizeof(PKGEntry))
if (u64{umax} / sizeof(PKGEntry) < u64(m_header.file_count))
{
pkg_log.error("PKG file count is invalid! (count=0x%x, data_size=0x%llx)", m_header.file_count, m_header.data_size);
pkg_log.error("PKG file count is too large! (0x%x)", m_header.file_count);
return false;
}
@@ -236,8 +190,7 @@ bool package_reader::read_header()
m_file = fs::make_gather(std::move(filelist));
}
if ((m_header.data_size + m_header.data_offset) > m_header.pkg_size ||
m_header.data_size > (u64{umax} - m_header.data_offset)) // Check for overflow
if (m_header.data_size + m_header.data_offset > m_header.pkg_size)
{
pkg_log.error("PKG data size mismatch (data_size=0x%llx, data_offset=0x%llx, file_size=0x%llx)", m_header.data_size, m_header.data_offset, m_header.pkg_size);
return false;
@@ -250,7 +203,7 @@ bool package_reader::read_metadata()
{
// Read title ID and use it as an installation directory
m_install_dir.resize(9);
archive_read_block(55, {reinterpret_cast<u8*>(m_install_dir.data()), m_install_dir.size()}, m_install_dir.size());
archive_read_block(55, &m_install_dir.front(), m_install_dir.size());
// Read package metadata
@@ -302,27 +255,7 @@ bool package_reader::read_metadata()
if (packet.size == sizeof(m_metadata.package_type))
{
archive_read(&m_metadata.package_type, sizeof(m_metadata.package_type));
std::vector<std::string> package_flags;
if (m_metadata.package_type & pkg_flag::PKG_FLAG_0x01) package_flags.push_back("0x01");
if (m_metadata.package_type & pkg_flag::PKG_FLAG_EBOOT) package_flags.push_back("EBOOT");
if (m_metadata.package_type & pkg_flag::PKG_FLAG_REQUIRE_LICENSE) package_flags.push_back("REQUIRE_LICENSE");
if (m_metadata.package_type & pkg_flag::PKG_FLAG_HDD_MC) package_flags.push_back("HDD_MC");
if (m_metadata.package_type & pkg_flag::PKG_FLAG_PATCH) package_flags.push_back("PATCH");
if (m_metadata.package_type & pkg_flag::PKG_FLAG_0x20) package_flags.push_back("0x20");
if (m_metadata.package_type & pkg_flag::PKG_FLAG_RENAME_DIRECTORY) package_flags.push_back("RENAME_DIRECTORY");
if (m_metadata.package_type & pkg_flag::PKG_FLAG_EDAT) package_flags.push_back("EDAT");
if (m_metadata.package_type & pkg_flag::PKG_FLAG_0x100) package_flags.push_back("0x100");
if (m_metadata.package_type & pkg_flag::PKG_FLAG_EMULATOR) package_flags.push_back("EMULATOR");
if (m_metadata.package_type & pkg_flag::PKG_FLAG_VSH_MODULE) package_flags.push_back("VSH_MODULE");
if (m_metadata.package_type & pkg_flag::PKG_FLAG_DISC_BOUND) package_flags.push_back("DISC_BOUND");
if (m_metadata.package_type & pkg_flag::PKG_FLAG_UNKNOWN) package_flags.push_back("UNKNOWN");
if (m_metadata.package_type & pkg_flag::PKG_FLAG_PS_VITA_CARD) package_flags.push_back("PS_VITA_CARD");
if (m_metadata.package_type & pkg_flag::PKG_FLAG_PS_VITA_NON_GAME) package_flags.push_back("PS_VITA_NON_GAME");
if (m_metadata.package_type & pkg_flag::PKG_FLAG_0x8000) package_flags.push_back("0x8000");
pkg_log.notice("Metadata: Package Type = 0x%x = %d", m_metadata.package_type, m_metadata.package_type);
pkg_log.notice("Metadata: Package Flags = %s", package_flags.empty() ? "{}" : fmt::merge(package_flags, ", "));
continue;
}
else
@@ -595,7 +528,7 @@ bool package_reader::read_entries(std::vector<PKGEntry>& entries)
entries.clear();
entries.resize(m_header.file_count + BUF_PADDING / sizeof(PKGEntry) + 1);
const usz read_size = decrypt(0, m_header.file_count * sizeof(PKGEntry), m_header.pkg_platform == PKG_PLATFORM_TYPE_PSP_PSVITA ? PKG_AES_KEY2 : m_dec_key.data(), std::span<u8>{reinterpret_cast<u8*>(entries.data()), entries.size() * sizeof(PKGEntry)});
const usz read_size = decrypt(0, m_header.file_count * sizeof(PKGEntry), m_header.pkg_platform == PKG_PLATFORM_TYPE_PSP_PSVITA ? PKG_AES_KEY2 : m_dec_key.data(), entries.data());
if (read_size < m_header.file_count * sizeof(PKGEntry))
{
@@ -667,7 +600,7 @@ bool package_reader::read_param_sfo()
std::string name_buf(entry.name_size + BUF_PADDING, '\0');
if (usz read_size = decrypt(entry.name_offset, entry.name_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data(), std::span<u8>{reinterpret_cast<u8*>(name_buf.data()), name_buf.size()}); read_size < entry.name_size)
if (usz read_size = decrypt(entry.name_offset, entry.name_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data(), name_buf.data()); read_size < entry.name_size)
{
pkg_log.error("PKG name could not be read (size=0x%x, offset=0x%x)", entry.name_size, entry.name_offset);
continue;
@@ -690,7 +623,7 @@ bool package_reader::read_param_sfo()
data_buf.resize(block_size + BUF_PADDING);
if (decrypt(entry.file_offset + pos, block_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data(), data_buf) != block_size)
if (decrypt(entry.file_offset + pos, block_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data(), data_buf.data()) != block_size)
{
pkg_log.error("Failed to decrypt PARAM.SFO file");
return false;
@@ -720,6 +653,7 @@ bool package_reader::read_param_sfo()
return false;
}
// TODO: maybe also check if VERSION matches
package_install_result package_reader::check_target_app_version() const
{
if (!m_is_valid)
@@ -764,13 +698,7 @@ package_install_result package_reader::check_target_app_version() const
{
// We are unable to compare anything with the target app version
pkg_log.error("A target app version is required (%s), but no PARAM.SFO was found for %s. (path='%s', error=%s)", target_app_ver, title_id, sfo_path, fs::g_tls_error);
return {
.error = package_install_result::error_type::app_version,
.version = {
.app_ver = std::string(app_ver),
.expected = std::string(target_app_ver)
}
};
return {package_install_result::error_type::app_version, {std::string(target_app_ver)}};
}
// There is nothing we need to compare, so we may install the package
@@ -799,12 +727,6 @@ package_install_result package_reader::check_target_app_version() const
if (target_app_ver.empty())
{
if (!(m_metadata.package_type & pkg_flag::PKG_FLAG_PATCH))
{
// This should be a DLC. Let's allow DLCs even with smaller APP_VER.
return {package_install_result::error_type::no_error};
}
// This is most likely the first patch. Let's make sure its version is high enough for the installed game.
const double new_version = std::strtod(app_ver.data(), &ev1);
@@ -822,13 +744,7 @@ package_install_result package_reader::check_target_app_version() const
}
pkg_log.error("The new app version (%s) is smaller than the installed app version (%s)", app_ver, installed_app_ver);
return {
.error = package_install_result::error_type::app_version,
.version = {
.app_ver = std::string(app_ver),
.installed = std::string(installed_app_ver)
}
};
return {package_install_result::error_type::app_version, {std::string(app_ver), std::string(installed_app_ver)}};
}
// Check if the installed app version matches the target app version
@@ -848,14 +764,7 @@ package_install_result package_reader::check_target_app_version() const
}
pkg_log.error("The installed app version (%s) does not match the target app version (%s)", installed_app_ver, target_app_ver);
return {
.error = package_install_result::error_type::app_version,
.version = {
.app_ver = std::string(app_ver),
.expected = std::string(target_app_ver),
.installed = std::string(installed_app_ver)
}
};
return {package_install_result::error_type::app_version, {std::string(target_app_ver), std::string(installed_app_ver)}};
}
bool package_reader::set_install_path()
@@ -900,16 +809,7 @@ bool package_reader::set_install_path()
// TODO: Verify whether other content types require appending title ID
// Append title ID depending on content type
if (m_metadata.content_type != PKG_CONTENT_TYPE_THEME && m_metadata.content_type != PKG_CONTENT_TYPE_LICENSE)
{
// The name is read as it comes from the package
if (m_install_dir.empty() || leaves_directory(m_install_dir))
{
pkg_log.error("Invalid installation directory name '%s'", m_install_dir);
return false;
}
dir += vfs::escape(m_install_dir) + '/';
}
dir += m_install_dir + '/';
// If false, an existing directory is being overwritten: cannot cancel the operation
m_was_null = !fs::is_dir(dir);
@@ -931,46 +831,6 @@ bool package_reader::fill_data(std::map<std::string, install_entry*>& all_instal
return false;
}
const auto canonicalize = [](std::string_view utf8_path)
{
std::error_code ec;
auto result = std::filesystem::weakly_canonical(fs_path_from_utf8(utf8_path), ec);
if (ec)
{
pkg_log.warning("Failed to canonicalize path '%s' (%s); falling back to lexical normalization.", utf8_path, ec.message());
result = fs_path_from_utf8(utf8_path).lexically_normal();
}
return result;
};
// weakly_canonical stats every prefix of a path that does not exist yet, and a package holds thousands of files in a
// few hundred directories: a directory is resolved once, and a file not on disk is that result plus its own name
std::map<std::string, std::filesystem::path, std::less<>> canonical_dirs;
// The installation directory is resolved without its closing "/", like every entry below it: on a file system that
// cannot resolve it, the lexical form would keep that separator as an empty last element no entry can match
std::string_view install_dir = m_install_path;
while (install_dir.ends_with('/'))
{
install_dir.remove_suffix(1);
}
const std::filesystem::path install_path = canonicalize(install_dir);
if (install_path.empty())
{
pkg_log.error("Failed to normalize installation path for '%s'", m_install_path);
return false;
}
const auto is_inside_install_path = [&install_path](const std::filesystem::path& path)
{
return std::mismatch(install_path.begin(), install_path.end(), path.begin(), path.end()).first == install_path.end();
};
m_install_entries.clear();
m_bootable_file_path.clear();
m_entry_indexer = 0;
@@ -999,7 +859,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;
if (const usz read_size = decrypt(entry.name_offset, entry.name_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data(), std::span<u8>{reinterpret_cast<u8*>(name_buf.data()), name_buf.size()}); read_size < entry.name_size)
if (const usz read_size = decrypt(entry.name_offset, entry.name_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data(), name_buf.data()); read_size < entry.name_size)
{
num_failures++;
pkg_log.error("PKG name could not be read (size=0x%x, offset=0x%x)", entry.name_size, entry.name_offset);
@@ -1008,53 +868,8 @@ bool package_reader::fill_data(std::map<std::string, install_entry*>& all_instal
std::string_view name = fmt::trim_back_sv(name_buf, "\0"sv);
if (leaves_directory(name))
{
num_failures++;
pkg_log.error("PKG entry path escapes installation directory: '%s'", name);
break;
}
std::string path = m_install_path + vfs::escape(name);
const u8 entry_type = entry.type & 0xff;
const bool is_folder = entry_type == PKG_FILE_ENTRY_FOLDER || entry_type == 0x12;
std::filesystem::path canonical_path;
// A path already on disk is resolved as a whole: it may be a link, or be spelt otherwise there
if (is_folder || fs::exists(path))
{
canonical_path = canonicalize(path);
if (is_folder)
{
canonical_dirs.emplace(path, canonical_path);
}
}
else
{
const usz slash = path.rfind('/');
const std::string_view dir(path.data(), slash);
auto found = canonical_dirs.find(dir);
if (found == canonical_dirs.end())
{
found = canonical_dirs.emplace(std::string(dir), canonicalize(dir)).first;
}
canonical_path = found->second / fs_path_from_utf8(std::string_view(path).substr(slash + 1));
}
if (canonical_path.empty() || !is_inside_install_path(canonical_path))
{
num_failures++;
pkg_log.error("PKG entry path escapes installation directory: '%s'", name);
break;
}
path = fs_path_to_utf8(canonical_path);
if (entry.pad || (entry.type & ~PKG_FILE_ENTRY_KNOWN_BITS))
{
pkg_log.todo("Entry with unknown type or padding: type=0x%08x, pad=0x%x, name='%s'", entry.type, entry.pad, name);
@@ -1064,6 +879,8 @@ bool package_reader::fill_data(std::map<std::string, install_entry*>& all_instal
pkg_log.notice("Entry: type=0x%08x, name='%s'", entry.type, name);
}
const u8 entry_type = entry.type & 0xff;
switch (entry_type)
{
case PKG_FILE_ENTRY_FOLDER:
@@ -1088,8 +905,16 @@ bool package_reader::fill_data(std::map<std::string, install_entry*>& all_instal
}
default:
{
// "path" went through "vfs::escape", which also takes care of the bytes that are not valid UTF-8
auto map_ptr = &*all_install_entries.try_emplace(std::move(path)).first;
// TODO: check for valid utf8 characters
const std::string true_path = std::filesystem::weakly_canonical(path).string();
if (true_path.empty())
{
num_failures++;
pkg_log.error("Failed to get weakly_canonical path for '%s'", path);
break;
}
auto map_ptr = &*all_install_entries.try_emplace(true_path).first;
m_install_entries.push_back({
.weak_reference = map_ptr,
@@ -1213,7 +1038,7 @@ void package_reader::extract_worker()
const install_entry& m_entry;
usz m_pos;
explicit pkg_file_reader(std::function<u64(u64, void*, u64)> read_func, const install_entry& entry) noexcept
explicit pkg_file_reader(std::function<u64(u64, void* buffer, u64)> read_func, const install_entry& entry) noexcept
: m_read_func(std::move(read_func))
, m_entry(entry)
, m_pos(0)
@@ -1282,9 +1107,6 @@ void package_reader::extract_worker()
read_cache.clear();
// 16MB buffer
std::vector<u8> buffer(std::min<usz>(entry.file_size, 1u << 24) + BUF_PADDING);
auto reader = std::make_unique<pkg_file_reader>([&, cache_off = u64{umax}](usz pos, void* ptr, usz size) mutable -> u64
{
if (pos >= entry.file_size || !size)
@@ -1292,7 +1114,6 @@ void package_reader::extract_worker()
return 0;
}
const usz original_size = size;
size = std::min<u64>(entry.file_size - pos, size);
u64 size_cache_end = 0;
@@ -1327,7 +1148,7 @@ void package_reader::extract_worker()
read_cache.resize(block_size + BUF_PADDING);
cache_off = pos;
const usz advance_size = decrypt(entry.file_offset + pos, block_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data(), read_cache);
const usz advance_size = decrypt(entry.file_offset + pos, block_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data(), read_cache.data());
if (!advance_size)
{
@@ -1345,17 +1166,8 @@ void package_reader::extract_worker()
while (read_size < size)
{
const u64 block_size = std::min<u64>(BUF_SIZE, size - read_size);
u64 available_buffer_size = original_size - read_size;
if (buffer.data() == ptr)
{
available_buffer_size = buffer.size() - read_size;
ensure(buffer.size() == original_size + BUF_PADDING);
}
ensure(available_buffer_size >= block_size);
const usz advance_size = decrypt(entry.file_offset + pos, block_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data(), std::span<u8>{static_cast<u8*>(ptr) + read_size, available_buffer_size});
const usz advance_size = decrypt(entry.file_offset + pos, block_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data(), static_cast<u8*>(ptr) + read_size);
if (!advance_size)
{
@@ -1390,6 +1202,9 @@ void package_reader::extract_worker()
break;
}
// 16MB buffer
std::vector<u8> buffer(std::min<usz>(entry.file_size, 1u << 24) + BUF_PADDING);
while (usz read_size = final_data.read(buffer.data(), buffer.size() - BUF_PADDING))
{
out.write(buffer.data(), read_size);
@@ -1439,7 +1254,7 @@ void package_reader::extract_worker()
}
}
package_install_result package_reader::extract_data(std::deque<package_reader>& readers, std::deque<std::string>& bootable_paths, bool from_optical_drive)
package_install_result package_reader::extract_data(std::deque<package_reader>& readers, std::deque<std::string>& bootable_paths)
{
package_install_result::error_type error = package_install_result::error_type::no_error;
usz num_failures = 0;
@@ -1491,18 +1306,15 @@ package_install_result package_reader::extract_data(std::deque<package_reader>&
if (reader.m_num_failures == 0)
{
// Disc archives don't like multithreaded file reads, so let's just use a single thread here
const usz thread_count = from_optical_drive ? 1 : std::min<usz>(utils::get_thread_count(), reader.m_install_entries.size());
const usz num_threads_succeeded = map_workload("PKG Installer "sv, thread_count, [&reader]()
const usz thread_count = std::min<usz>(utils::get_thread_count(), reader.m_install_entries.size());
named_thread_group workers("PKG Installer "sv, std::max<u32>(::narrow<u32>(thread_count), 1) - 1, [&]()
{
reader.extract_worker();
});
if (thread_count != num_threads_succeeded)
{
pkg_log.error("%d thread(s) failed with an exception!", thread_count - num_threads_succeeded);
reader.m_num_failures++;
}
reader.extract_worker();
workers.join();
}
num_failures += reader.m_num_failures;
@@ -1570,16 +1382,14 @@ u64 package_reader::archive_read(void* data_ptr, const u64 num_bytes)
return m_file ? m_file.read(data_ptr, num_bytes) : 0;
}
std::span<const char> package_reader::archive_read_block(u64 offset, std::span<u8> dst, u64 num_bytes)
std::span<const char> package_reader::archive_read_block(u64 offset, void* data_ptr, u64 num_bytes)
{
ensure(dst.size() >= num_bytes);
const usz read_n = m_file.read_at(offset, data_ptr, num_bytes);
const usz read_n = m_file.read_at(offset, dst.data(), num_bytes);
return {reinterpret_cast<const char*>(dst.data()), read_n};
return {static_cast<const char*>(data_ptr), read_n};
}
usz package_reader::decrypt(u64 offset, u64 size, const uchar* key, std::span<u8> local_buf)
usz package_reader::decrypt(u64 offset, u64 size, const uchar* key, void* local_buf)
{
if (!m_is_valid)
{
@@ -1591,26 +1401,15 @@ usz package_reader::decrypt(u64 offset, u64 size, const uchar* key, std::span<u8
return 0;
}
ensure(local_buf.size() >= size);
// Read the data and set available size
const auto data_span = archive_read_block(m_header.data_offset + offset, local_buf, size);
ensure(data_span.data() == static_cast<void*>(local_buf.data()));
ensure(data_span.size() <= size);
ensure(data_span.data() == static_cast<void*>(local_buf));
// Clear padding
if (data_span.size() < local_buf.size())
{
std::memset(&local_buf[data_span.size()], 0, local_buf.size() - data_span.size());
}
// Get block count
const u64 blocks = (data_span.size() + 15) / 16;
const auto out_data = reinterpret_cast<u8*>(local_buf);
// Get block count. Round up.
const u64 blocks = utils::aligned_div<u64>(data_span.size(), sizeof(u128));
const u64 read_size = blocks * sizeof(u128);
switch (m_header.pkg_type)
{
case PKG_RELEASE_TYPE_DEBUG:
if (m_header.pkg_type == PKG_RELEASE_TYPE_DEBUG)
{
// Debug key
be_t<u64> input[8] =
@@ -1624,7 +1423,7 @@ usz package_reader::decrypt(u64 offset, u64 size, const uchar* key, std::span<u8
for (u64 i = 0; i < blocks; i++)
{
// Initialize stream cipher for current position
input[7] = offset / sizeof(u128) + i;
input[7] = offset / 16 + i;
struct sha1_hash
{
@@ -1633,13 +1432,11 @@ usz package_reader::decrypt(u64 offset, u64 size, const uchar* key, std::span<u8
sha1(reinterpret_cast<const u8*>(input), sizeof(input), hash.data);
const u128 v = read_from_ptr<u128>(local_buf, i * sizeof(u128));
write_to_ptr<u128>(local_buf, i * sizeof(u128), v ^ read_from_ptr<u128>(hash.data));
const u128 v = read_from_ptr_unsafe<u128>(out_data, i * 16);
write_to_ptr_unsafe<u128>(out_data, i * 16, v ^ read_from_ptr<u128>(hash.data));
}
break;
}
case PKG_RELEASE_TYPE_RELEASE:
else if (m_header.pkg_type == PKG_RELEASE_TYPE_RELEASE)
{
aes_context ctx;
@@ -1647,7 +1444,7 @@ usz package_reader::decrypt(u64 offset, u64 size, const uchar* key, std::span<u8
aes_setkey_enc(&ctx, key, 128);
// Initialize stream cipher for start position
be_t<u128> input = m_header.klicensee.value() + offset / sizeof(u128);
be_t<u128> input = m_header.klicensee.value() + offset / 16;
// Increment stream position for every block
for (u64 i = 0; i < blocks; i++, input++)
@@ -1656,25 +1453,19 @@ usz package_reader::decrypt(u64 offset, u64 size, const uchar* key, std::span<u8
aes_crypt_ecb(&ctx, AES_ENCRYPT, reinterpret_cast<const u8*>(&input), reinterpret_cast<u8*>(&key));
const u128 v = read_from_ptr<u128>(local_buf, i * sizeof(u128));
write_to_ptr<u128>(local_buf, i * sizeof(u128), v ^ key);
const u128 v = read_from_ptr_unsafe<u128>(out_data, i * 16);
write_to_ptr_unsafe<u128>(out_data, i * 16, v ^ key);
}
break;
}
default:
else
{
pkg_log.error("Unknown release type (0x%x)", m_header.pkg_type);
break;
}
}
if (read_size > size)
if (blocks * 16 != size)
{
// Put NTS and other zeroes on unaligned reads
const u64 pad_size = read_size - size;
ensure(local_buf.size() >= (size + pad_size));
std::memset(&local_buf[size], 0, pad_size);
std::memset(out_data + size, 0, blocks * 16 - size);
}
// Return the amount of data written in buf
+14 -38
View File
@@ -14,7 +14,6 @@ enum : u32
{
PKG_HEADER_SIZE = 0xC0, // sizeof(pkg_header) + sizeof(pkg_unk_checksum)
PKG_HEADER_SIZE2 = 0x280,
PKG_MAX_FILE_COUNT = 0x7FFF'FFFF,
PKG_MAX_FILENAME_SIZE = 256,
};
@@ -43,7 +42,7 @@ enum : u32
PKG_FILE_ENTRY_KNOWN_BITS = 0xff | PKG_FILE_ENTRY_PSP | PKG_FILE_ENTRY_OVERWRITE,
};
enum pkg_content_type : u32
enum : u32
{
PKG_CONTENT_TYPE_UNKNOWN_1 = 0x01, // ?
PKG_CONTENT_TYPE_UNKNOWN_2 = 0x02, // ?
@@ -64,39 +63,18 @@ enum pkg_content_type : u32
PKG_CONTENT_TYPE_VMC = 0x11, // VMC
PKG_CONTENT_TYPE_PS2_CLASSIC = 0x12, // ?PS2Classic? Seen on PS2 classic
PKG_CONTENT_TYPE_UNKNOWN_5 = 0x13, // ?
PKG_CONTENT_TYPE_PSP_REMASTERED = 0x14, // PSP Remastered
PKG_CONTENT_TYPE_PSP_REMASTERED = 0x14, // ?
PKG_CONTENT_TYPE_PSP2_GD = 0x15, // PSVita Game Data
PKG_CONTENT_TYPE_PSP2_AC = 0x16, // PSVita Additional Content
PKG_CONTENT_TYPE_PSP2_LA = 0x17, // PSVita LiveArea
PKG_CONTENT_TYPE_PSM = 0x18, // PSVita PSM
PKG_CONTENT_TYPE_PSM_1 = 0x18, // PSVita PSM ?
PKG_CONTENT_TYPE_WT = 0x19, // Web TV ?
PKG_CONTENT_TYPE_PS4_GD = 0x1A, // PS4 GameData
PKG_CONTENT_TYPE_PS4_AC = 0x1B, // PS4 Additional Content
PKG_CONTENT_TYPE_PS4_AL = 0x1C, // PS4 Additional License
PKG_CONTENT_TYPE_PSM_UNITY = 0x1D, // PSVita PSM for Unity
PKG_CONTENT_TYPE_PS4_DP = 0x1E, // PS4 Delta patch
PKG_CONTENT_TYPE_UNKNOWN_6 = 0x1A, // ?
PKG_CONTENT_TYPE_UNKNOWN_7 = 0x1B, // ?
PKG_CONTENT_TYPE_UNKNOWN_8 = 0x1C, // ?
PKG_CONTENT_TYPE_PSM_2 = 0x1D, // PSVita PSM ?
PKG_CONTENT_TYPE_UNKNOWN_9 = 0x1E, // ?
PKG_CONTENT_TYPE_PSP2_THEME = 0x1F, // PSVita Theme
PKG_CONTENT_TYPE_PS5_GAME_DATA = 0x20, // PS5 GameData
};
enum pkg_flag : u32
{
PKG_FLAG_0x01 = 0x01,
PKG_FLAG_EBOOT = 0x02,
PKG_FLAG_REQUIRE_LICENSE = 0x04,
PKG_FLAG_HDD_MC = 0x08,
PKG_FLAG_PATCH = 0x10,
PKG_FLAG_0x20 = 0x20,
PKG_FLAG_RENAME_DIRECTORY = 0x40,
PKG_FLAG_EDAT = 0x80,
PKG_FLAG_0x100 = 0x100,
PKG_FLAG_EMULATOR = 0x200,
PKG_FLAG_VSH_MODULE = 0x400,
PKG_FLAG_DISC_BOUND = 0x800,
PKG_FLAG_UNKNOWN = 0x1000,
PKG_FLAG_PS_VITA_CARD = 0x2000,
PKG_FLAG_PS_VITA_NON_GAME = 0x4000,
PKG_FLAG_0x8000 = 0x8000,
};
// Structs
@@ -327,11 +305,10 @@ struct package_install_result
app_version,
other
} error = error_type::no_error;
struct versions
struct version
{
std::string app_ver;
std::string expected;
std::string installed;
std::string found;
} version;
};
@@ -371,9 +348,8 @@ public:
bool is_valid() const { return m_is_valid; }
const PKGHeader& get_header() const { return m_header; }
const PKGMetaData& get_metadata() const { return m_metadata; }
package_install_result check_target_app_version() const;
static package_install_result extract_data(std::deque<package_reader>& readers, std::deque<std::string>& bootable_paths, bool from_optical_drive);
static package_install_result extract_data(std::deque<package_reader>& readers, std::deque<std::string>& bootable_paths);
const psf::registry& get_psf() const { return m_psf; }
result get_result() const { return m_result; };
@@ -381,7 +357,7 @@ public:
void abort_extract();
fs::file& file()
fs::file &file()
{
return m_file;
}
@@ -396,8 +372,8 @@ private:
u64 archive_read(void* data_ptr, u64 num_bytes);
bool set_install_path();
bool fill_data(std::map<std::string, install_entry*>& all_install_entries);
std::span<const char> archive_read_block(u64 offset, std::span<u8> dst, u64 num_bytes);
usz decrypt(u64 offset, u64 size, const uchar* key, std::span<u8> local_buf);
std::span<const char> archive_read_block(u64 offset, void* data_ptr, u64 num_bytes);
usz decrypt(u64 offset, u64 size, const uchar* key, void* local_buf);
void extract_worker();
std::deque<install_entry> m_install_entries;
+82 -127
View File
@@ -90,7 +90,7 @@ inline void Write64(const fs::file& f, const be_t<u64> data)
f.write(&data, sizeof(data));
}
void WriteEhdr(const fs::file& f, const Elf64_Ehdr& ehdr)
void WriteEhdr(const fs::file& f, Elf64_Ehdr& ehdr)
{
Write32(f, ehdr.e_magic);
Write8(f, ehdr.e_class);
@@ -113,7 +113,7 @@ void WriteEhdr(const fs::file& f, const Elf64_Ehdr& ehdr)
Write16(f, ehdr.e_shstrndx);
}
void WritePhdr(const fs::file& f, const Elf64_Phdr& phdr)
void WritePhdr(const fs::file& f, Elf64_Phdr& phdr)
{
Write32(f, phdr.p_type);
Write32(f, phdr.p_flags);
@@ -125,7 +125,7 @@ void WritePhdr(const fs::file& f, const Elf64_Phdr& phdr)
Write64(f, phdr.p_align);
}
void WriteShdr(const fs::file& f, const Elf64_Shdr& shdr)
void WriteShdr(const fs::file& f, Elf64_Shdr& shdr)
{
Write32(f, shdr.sh_name);
Write32(f, shdr.sh_type);
@@ -139,7 +139,7 @@ void WriteShdr(const fs::file& f, const Elf64_Shdr& shdr)
Write64(f, shdr.sh_entsize);
}
void WriteEhdr(const fs::file& f, const Elf32_Ehdr& ehdr)
void WriteEhdr(const fs::file& f, Elf32_Ehdr& ehdr)
{
Write32(f, ehdr.e_magic);
Write8(f, ehdr.e_class);
@@ -162,7 +162,7 @@ void WriteEhdr(const fs::file& f, const Elf32_Ehdr& ehdr)
Write16(f, ehdr.e_shstrndx);
}
void WritePhdr(const fs::file& f, const Elf32_Phdr& phdr)
void WritePhdr(const fs::file& f, Elf32_Phdr& phdr)
{
Write32(f, phdr.p_type);
Write32(f, phdr.p_offset);
@@ -174,7 +174,7 @@ void WritePhdr(const fs::file& f, const Elf32_Phdr& phdr)
Write32(f, phdr.p_align);
}
void WriteShdr(const fs::file& f, const Elf32_Shdr& shdr)
void WriteShdr(const fs::file& f, Elf32_Shdr& shdr)
{
Write32(f, shdr.sh_name);
Write32(f, shdr.sh_type);
@@ -323,7 +323,7 @@ void supplemental_header::Show() const
self_log.notice("Version: 0x%08x", PS3_npdrm_header.npd.version);
self_log.notice("License: 0x%08x", PS3_npdrm_header.npd.license);
self_log.notice("Type: 0x%08x", PS3_npdrm_header.npd.type);
self_log.notice("ContentID: %s", PS3_npdrm_header.npd.get_content_id());
self_log.notice("ContentID: %s", PS3_npdrm_header.npd.content_id);
self_log.notice("Digest: %s", PS3_npdrm_header.npd.digest);
self_log.notice("Inverse digest: %s", PS3_npdrm_header.npd.title_hash);
self_log.notice("XOR digest: %s", PS3_npdrm_header.npd.dev_hash);
@@ -627,20 +627,7 @@ bool SCEDecrypter::LoadMetadata(const u8 erk[32], const u8 riv[16])
{
aes_context aes;
std::vector<u8> metadata_info(sizeof(meta_info));
constexpr usz sizeof_meta_and_header = sizeof(meta_info) + sizeof(sce_hdr);
const usz metadata_offset = static_cast<usz>(sce_hdr.se_meta);
if (metadata_offset > usz{umax} - sizeof_meta_and_header ||
sce_hdr.se_hsize < sizeof_meta_and_header + metadata_offset ||
sce_hdr.se_hsize - (sizeof_meta_and_header + metadata_offset) < sizeof(meta_hdr) ||
sce_hdr.se_hsize > sce_f.size())
{
self_log.error("Invalid SCE metadata header size!");
return false;
}
const usz metadata_headers_offset = sizeof_meta_and_header + metadata_offset;
std::vector<u8> metadata_headers(sce_hdr.se_hsize - metadata_headers_offset);
std::vector<u8> metadata_headers(sce_hdr.se_hsize - (sizeof(sce_hdr) + sce_hdr.se_meta + sizeof(meta_info)));
// Locate and read the encrypted metadata info.
sce_f.seek(sce_hdr.se_meta + sizeof(sce_hdr));
@@ -687,7 +674,7 @@ bool SCEDecrypter::LoadMetadata(const u8 erk[32], const u8 riv[16])
// Load the metadata section headers.
meta_shdr.clear();
for (u32 i = 0; i < meta_hdr.section_count; i++)
for (unsigned int i = 0; i < meta_hdr.section_count; i++)
{
const usz shdr_offset = sizeof(meta_hdr) + sizeof(MetadataSectionHeader) * i;
ensure(metadata_headers.size() > shdr_offset);
@@ -697,11 +684,10 @@ bool SCEDecrypter::LoadMetadata(const u8 erk[32], const u8 riv[16])
}
// Copy the decrypted data keys.
data_keys.resize(static_cast<u64>(meta_hdr.key_count) * 0x10);
data_keys.resize(meta_hdr.key_count * 0x10);
const usz data_keys_offset = sizeof(meta_hdr) + meta_hdr.section_count * sizeof(MetadataSectionHeader);
ensure(metadata_headers.size() >= (data_keys_offset + data_keys.size()));
ensure(data_keys.size() <= (usz{umax} - data_keys_offset)); // Check for overflow
std::memcpy(data_keys.data(), metadata_headers.data() + data_keys_offset, data_keys.size());
return true;
@@ -713,9 +699,9 @@ bool SCEDecrypter::DecryptData()
usz data_buf_length = 0;
// Calculate the total data size.
for (const MetadataSectionHeader& hdr : meta_shdr)
for (unsigned int i = 0; i < meta_hdr.section_count; i++)
{
data_buf_length += ::narrow<u32>(hdr.data_size);
data_buf_length += ::narrow<u32>(meta_shdr[i].data_size);
}
// Allocate a buffer to store decrypted data.
@@ -724,55 +710,52 @@ bool SCEDecrypter::DecryptData()
// Set initial offset.
u32 data_buf_offset = 0;
// Tmp buffer
std::vector<u8> buf;
u8 ctr_stream_block[0x10];
// Parse the metadata section headers to find the offsets of encrypted data.
for (const MetadataSectionHeader& hdr : meta_shdr)
for (unsigned int i = 0; i < meta_hdr.section_count; i++)
{
usz ctr_nc_off = 0;
u8 ctr_stream_block[0x10];
u8 data_key[0x10];
u8 data_iv[0x10];
// Check if this is an encrypted section.
if (hdr.encrypted == 3)
if (meta_shdr[i].encrypted == 3)
{
// Make sure the key and iv are not out of boundaries.
if ((hdr.key_idx < meta_hdr.key_count) && (hdr.iv_idx < meta_hdr.key_count))
if ((meta_shdr[i].key_idx <= meta_hdr.key_count - 1) && (meta_shdr[i].iv_idx <= meta_hdr.key_count))
{
// Get the key and iv from the previously stored key buffer.
const std::array<u8, 0x10> data_key = read_from_ptr<std::array<u8, 0x10>>(data_keys, static_cast<usz>(hdr.key_idx) * 0x10);
std::array<u8, 0x10> data_iv = read_from_ptr<std::array<u8, 0x10>>(data_keys, static_cast<usz>(hdr.iv_idx) * 0x10);
std::memcpy(data_key, data_keys.data() + meta_shdr[i].key_idx * 0x10, 0x10);
std::memcpy(data_iv, data_keys.data() + meta_shdr[i].iv_idx * 0x10, 0x10);
// Allocate a buffer to hold the data.
auto buf = std::make_unique<u8[]>(meta_shdr[i].data_size);
// Seek to the section data offset and read the encrypted data.
buf.resize(hdr.data_size);
sce_f.seek(hdr.data_offset);
sce_f.read(buf.data(), buf.size());
sce_f.seek(meta_shdr[i].data_offset);
sce_f.read(buf.get(), meta_shdr[i].data_size);
// Zero out our ctr nonce.
std::memset(ctr_stream_block, 0, sizeof(ctr_stream_block));
// Perform AES-CTR encryption on the data blocks.
usz ctr_nc_off = 0;
aes_setkey_enc(&aes, data_key.data(), 128);
aes_crypt_ctr(&aes, buf.size(), &ctr_nc_off, data_iv.data(), ctr_stream_block, buf.data(), buf.data());
aes_setkey_enc(&aes, data_key, 128);
aes_crypt_ctr(&aes, meta_shdr[i].data_size, &ctr_nc_off, data_iv, ctr_stream_block, buf.get(), buf.get());
// Copy the decrypted data.
ensure(data_buf.size() >= (buf.size() + data_buf_offset));
ensure(buf.size() <= (usz{umax} - static_cast<usz>(data_buf_offset))); // Check for overflow
std::memcpy(data_buf.data() + data_buf_offset, buf.data(), buf.size());
std::memcpy(data_buf.data() + data_buf_offset, buf.get(), meta_shdr[i].data_size);
}
}
else
{
buf.resize(hdr.data_size);
sce_f.seek(hdr.data_offset);
sce_f.read(buf.data(), buf.size());
ensure(data_buf.size() >= (buf.size() + data_buf_offset));
ensure(buf.size() <= (usz{umax} - static_cast<usz>(data_buf_offset))); // Check for overflow
std::memcpy(data_buf.data() + data_buf_offset, buf.data(), buf.size());
auto buf = std::make_unique<u8[]>(meta_shdr[i].data_size);
sce_f.seek(meta_shdr[i].data_offset);
sce_f.read(buf.get(), meta_shdr[i].data_size);
std::memcpy(data_buf.data() + data_buf_offset, buf.get(), meta_shdr[i].data_size);
}
// Advance the buffer's offset.
data_buf_offset += ::narrow<u32>(hdr.data_size);
data_buf_offset += ::narrow<u32>(meta_shdr[i].data_size);
}
return true;
@@ -787,8 +770,9 @@ std::vector<fs::file> SCEDecrypter::MakeFile()
u32 data_buf_offset = 0;
// Write data.
for (const MetadataSectionHeader& hdr : meta_shdr)
for (u32 i = 0; i < meta_hdr.section_count; i++)
{
const MetadataSectionHeader& hdr = meta_shdr[i];
const u8* src = data_buf.data() + data_buf_offset;
fs::file out_f = fs::make_stream<std::vector<u8>>();
@@ -867,13 +851,13 @@ bool SELFDecrypter::LoadHeaders(bool isElf32, SelfAdditionalInfo* out_info)
if (isElf32)
{
phdr32_arr.clear();
if (elf32_hdr.e_phoff == 0 && elf32_hdr.e_phnum)
if(elf32_hdr.e_phoff == 0 && elf32_hdr.e_phnum)
{
self_log.error("ELF program header offset is null!");
return false;
}
self_f.seek(m_ext_hdr.phdr_offset);
for (u32 i = 0; i < elf32_hdr.e_phnum; ++i)
for(u32 i = 0; i < elf32_hdr.e_phnum; ++i)
{
phdr32_arr.emplace_back();
phdr32_arr.back().Load(self_f);
@@ -902,7 +886,7 @@ bool SELFDecrypter::LoadHeaders(bool isElf32, SelfAdditionalInfo* out_info)
m_seg_ext_hdr.clear();
self_f.seek(m_ext_hdr.segment_ext_hdr_offset);
for (u32 i = 0; i < (isElf32 ? elf32_hdr.e_phnum : elf64_hdr.e_phnum); ++i)
for(u32 i = 0; i < (isElf32 ? elf32_hdr.e_phnum : elf64_hdr.e_phnum); ++i)
{
if (self_f.pos() >= self_size)
{
@@ -968,7 +952,7 @@ bool SELFDecrypter::LoadHeaders(bool isElf32, SelfAdditionalInfo* out_info)
self_f.seek(m_ext_hdr.shdr_offset);
for (u32 i = 0; i < elf32_hdr.e_shnum; ++i)
for(u32 i = 0; i < elf32_hdr.e_shnum; ++i)
{
shdr32_arr.emplace_back();
shdr32_arr.back().Load(self_f);
@@ -985,7 +969,7 @@ bool SELFDecrypter::LoadHeaders(bool isElf32, SelfAdditionalInfo* out_info)
self_f.seek(m_ext_hdr.shdr_offset);
for (u32 i = 0; i < elf64_hdr.e_shnum; ++i)
for(u32 i = 0; i < elf64_hdr.e_shnum; ++i)
{
shdr64_arr.emplace_back();
shdr64_arr.back().Load(self_f);
@@ -1020,21 +1004,13 @@ void SELFDecrypter::ShowHeaders(bool isElf32)
self_log.notice("----------------------------------------------------");
self_log.notice("ELF program headers");
self_log.notice("----------------------------------------------------");
if (isElf32)
{
for (const Elf32_Phdr& hdr : phdr32_arr)
hdr.Show();
}
else
{
for (const Elf64_Phdr& hdr : phdr64_arr)
hdr.Show();
}
for(unsigned int i = 0; i < ((isElf32) ? phdr32_arr.size() : phdr64_arr.size()); i++)
isElf32 ? phdr32_arr[i].Show() : phdr64_arr[i].Show();
self_log.notice("----------------------------------------------------");
self_log.notice("Section info");
self_log.notice("----------------------------------------------------");
for (const segment_ext_header& hdr : m_seg_ext_hdr)
hdr.Show();
for(unsigned int i = 0; i < m_seg_ext_hdr.size(); i++)
m_seg_ext_hdr[i].Show();
self_log.notice("----------------------------------------------------");
self_log.notice("SCE version info");
self_log.notice("----------------------------------------------------");
@@ -1042,21 +1018,13 @@ void SELFDecrypter::ShowHeaders(bool isElf32)
self_log.notice("----------------------------------------------------");
self_log.notice("Control info");
self_log.notice("----------------------------------------------------");
for (const supplemental_header& hdr : m_supplemental_hdr_arr)
hdr.Show();
for(unsigned int i = 0; i < m_supplemental_hdr_arr.size(); i++)
m_supplemental_hdr_arr[i].Show();
self_log.notice("----------------------------------------------------");
self_log.notice("ELF section headers");
self_log.notice("----------------------------------------------------");
if (isElf32)
{
for (const Elf32_Shdr& hdr : shdr32_arr)
hdr.Show();
}
else
{
for (const Elf64_Shdr& hdr : shdr64_arr)
hdr.Show();
}
for(unsigned int i = 0; i < ((isElf32) ? shdr32_arr.size() : shdr64_arr.size()); i++)
isElf32 ? shdr32_arr[i].Show() : shdr64_arr[i].Show();
self_log.notice("----------------------------------------------------");
}
@@ -1078,7 +1046,7 @@ bool SELFDecrypter::DecryptNPDRM(u8 *metadata, u32 metadata_size)
if (npd->license == 1) // Network license.
{
// Try to find a RAP file to get the key.
if (!GetKeyFromRap(npd->get_content_id(), npdrm_key))
if (!GetKeyFromRap(npd->content_id, npdrm_key))
{
self_log.error("Can't decrypt network NPDRM!");
return false;
@@ -1087,7 +1055,7 @@ bool SELFDecrypter::DecryptNPDRM(u8 *metadata, u32 metadata_size)
else if (npd->license == 2) // Local license.
{
// Try to find a RAP file to get the key.
if (!GetKeyFromRap(npd->get_content_id(), npdrm_key))
if (!GetKeyFromRap(npd->content_id, npdrm_key))
{
self_log.error("Can't find RAP file for NPDRM decryption!");
return false;
@@ -1136,20 +1104,7 @@ bool SELFDecrypter::LoadMetadata(const u8* klic_key)
{
aes_context aes;
std::vector<u8> metadata_info(sizeof(meta_info));
constexpr usz sizeof_meta_and_header = sizeof(meta_info) + sizeof(sce_hdr);
const usz metadata_offset = static_cast<usz>(sce_hdr.se_meta);
if (metadata_offset > usz{umax} - sizeof_meta_and_header ||
sce_hdr.se_hsize < sizeof_meta_and_header + metadata_offset ||
sce_hdr.se_hsize - (sizeof_meta_and_header + metadata_offset) < sizeof(meta_hdr) ||
sce_hdr.se_hsize > self_f.size())
{
self_log.error("Invalid SELF metadata header size!");
return false;
}
const usz metadata_headers_offset = sizeof_meta_and_header + metadata_offset;
std::vector<u8> metadata_headers(sce_hdr.se_hsize - metadata_headers_offset);
std::vector<u8> metadata_headers(sce_hdr.se_hsize - (sizeof(sce_hdr) + sce_hdr.se_meta + sizeof(meta_info)));
// Locate and read the encrypted metadata info.
self_f.seek(sce_hdr.se_meta + sizeof(sce_hdr));
@@ -1207,7 +1162,7 @@ bool SELFDecrypter::LoadMetadata(const u8* klic_key)
// Load the metadata section headers.
meta_shdr.clear();
for (u32 i = 0; i < meta_hdr.section_count; i++)
for (unsigned int i = 0; i < meta_hdr.section_count; i++)
{
const usz shdr_offset = sizeof(meta_hdr) + sizeof(MetadataSectionHeader) * i;
ensure(metadata_headers.size() > shdr_offset);
@@ -1217,11 +1172,10 @@ bool SELFDecrypter::LoadMetadata(const u8* klic_key)
}
// Copy the decrypted data keys.
data_keys.resize(static_cast<u64>(meta_hdr.key_count) * 0x10);
data_keys.resize(meta_hdr.key_count * 0x10);
const usz data_keys_offset = sizeof(meta_hdr) + meta_hdr.section_count * sizeof(MetadataSectionHeader);
ensure(metadata_headers.size() >= (data_keys_offset + data_keys.size()));
ensure(data_keys.size() <= (usz{umax} - data_keys_offset)); // Check for overflow
std::memcpy(data_keys.data(), metadata_headers.data() + data_keys_offset, data_keys.size());
return true;
@@ -1233,12 +1187,12 @@ bool SELFDecrypter::DecryptData()
usz data_buf_length = 0;
// Calculate the total data size.
for (const MetadataSectionHeader& hdr : meta_shdr)
for (unsigned int i = 0; i < meta_hdr.section_count; i++)
{
if (hdr.encrypted == 3)
if (meta_shdr[i].encrypted == 3)
{
if ((hdr.key_idx < meta_hdr.key_count) && (hdr.iv_idx < meta_hdr.key_count))
data_buf_length += ::narrow<u32>(hdr.data_size);
if ((meta_shdr[i].key_idx <= meta_hdr.key_count - 1) && (meta_shdr[i].iv_idx <= meta_hdr.key_count))
data_buf_length += ::narrow<u32>(meta_shdr[i].data_size);
}
}
@@ -1248,43 +1202,43 @@ bool SELFDecrypter::DecryptData()
// Set initial offset.
u32 data_buf_offset = 0;
// Tmp buffer
std::vector<u8> buf;
u8 ctr_stream_block[0x10];
// Parse the metadata section headers to find the offsets of encrypted data.
for (const MetadataSectionHeader& hdr : meta_shdr)
for (unsigned int i = 0; i < meta_hdr.section_count; i++)
{
usz ctr_nc_off = 0;
u8 ctr_stream_block[0x10];
u8 data_key[0x10];
u8 data_iv[0x10];
// Check if this is an encrypted section.
if (hdr.encrypted == 3)
if (meta_shdr[i].encrypted == 3)
{
// Make sure the key and iv are not out of boundaries.
if ((hdr.key_idx < meta_hdr.key_count) && (hdr.iv_idx < meta_hdr.key_count))
if((meta_shdr[i].key_idx <= meta_hdr.key_count - 1) && (meta_shdr[i].iv_idx <= meta_hdr.key_count))
{
// Get the key and iv from the previously stored key buffer.
const std::array<u8, 0x10> data_key = read_from_ptr<std::array<u8, 0x10>>(data_keys, static_cast<usz>(hdr.key_idx) * 0x10);
std::array<u8, 0x10> data_iv = read_from_ptr<std::array<u8, 0x10>>(data_keys, static_cast<usz>(hdr.iv_idx) * 0x10);
std::memcpy(data_key, data_keys.data() + meta_shdr[i].key_idx * 0x10, 0x10);
std::memcpy(data_iv, data_keys.data() + meta_shdr[i].iv_idx * 0x10, 0x10);
// Allocate a buffer to hold the data.
auto buf = std::make_unique<u8[]>(meta_shdr[i].data_size);
// Seek to the section data offset and read the encrypted data.
buf.resize(hdr.data_size);
self_f.seek(hdr.data_offset);
self_f.read(buf.data(), buf.size());
self_f.seek(meta_shdr[i].data_offset);
self_f.read(buf.get(), meta_shdr[i].data_size);
// Zero out our ctr nonce.
std::memset(ctr_stream_block, 0, sizeof(ctr_stream_block));
// Perform AES-CTR encryption on the data blocks.
usz ctr_nc_off = 0;
aes_setkey_enc(&aes, data_key.data(), 128);
aes_crypt_ctr(&aes, buf.size(), &ctr_nc_off, data_iv.data(), ctr_stream_block, buf.data(), buf.data());
aes_setkey_enc(&aes, data_key, 128);
aes_crypt_ctr(&aes, meta_shdr[i].data_size, &ctr_nc_off, data_iv, ctr_stream_block, buf.get(), buf.get());
// Copy the decrypted data.
ensure(data_buf.size() >= (buf.size() + data_buf_offset));
ensure(buf.size() <= (usz{umax} - static_cast<usz>(data_buf_offset))); // Check for overflow
std::memcpy(data_buf.data() + data_buf_offset, buf.data(), buf.size());
std::memcpy(data_buf.data() + data_buf_offset, buf.get(), meta_shdr[i].data_size);
// Advance the buffer's offset.
data_buf_offset += ::narrow<u32>(hdr.data_size);
data_buf_offset += ::narrow<u32>(meta_shdr[i].data_size);
}
}
}
@@ -1309,13 +1263,14 @@ fs::file SELFDecrypter::MakeElf(bool isElf32)
return e;
}
bool SELFDecrypter::GetKeyFromRap(std::string_view content_id, u8* npdrm_key)
bool SELFDecrypter::GetKeyFromRap(const char* content_id, u8* npdrm_key)
{
// Set empty RAP key.
std::array<u8, 0x10> rap_key {};
// Try to find a matching RAP file under exdata folder.
const std::string rap_path = rpcs3::utils::get_rap_file_path(content_id);
const std::string ci_str = content_id;
const std::string rap_path = rpcs3::utils::get_rap_file_path(ci_str);
// Open the RAP file and read the key.
const fs::file rap_file(rap_path);
@@ -1328,7 +1283,7 @@ bool SELFDecrypter::GetKeyFromRap(std::string_view content_id, u8* npdrm_key)
return false;
}
self_log.notice("Loading RAP file %s.rap", content_id);
self_log.notice("Loading RAP file %s.rap", ci_str);
if (rap_file.read(rap_key.data(), rap_key.size()) != rap_key.size())
{
+23 -37
View File
@@ -478,11 +478,11 @@ public:
bool DecryptData();
bool DecryptNPDRM(u8 *metadata, u32 metadata_size);
const NPD_HEADER* GetNPDHeader() const;
static bool GetKeyFromRap(std::string_view content_id, u8 *npdrm_key);
static bool GetKeyFromRap(const char *content_id, u8 *npdrm_key);
private:
template<typename EHdr, typename SHdr, typename PHdr>
void WriteElf(fs::file& e, EHdr ehdr, const std::vector<SHdr>& shdrs, const std::vector<PHdr>& phdrs)
void WriteElf(fs::file& e, EHdr ehdr, SHdr shdr, PHdr phdr)
{
// Set initial offset.
u32 data_buf_offset = 0;
@@ -491,35 +491,32 @@ private:
WriteEhdr(e, ehdr);
// Write program headers.
for (const PHdr& phdr : phdrs)
for (u32 i = 0; i < ehdr.e_phnum; ++i)
{
WritePhdr(e, phdr);
WritePhdr(e, phdr[i]);
}
// Tmp buffer
std::vector<u8> decomp_buf;
for (const MetadataSectionHeader& hdr : meta_shdr)
for (unsigned int i = 0; i < meta_hdr.section_count; i++)
{
// PHDR type.
if (hdr.type == 2)
if (meta_shdr[i].type == 2)
{
const PHdr& phdr = ::at32(phdrs, hdr.program_idx);
// Decompress if necessary.
if (hdr.compressed == 2)
if (meta_shdr[i].compressed == 2)
{
const auto filesz = phdr.p_filesz;
decomp_buf.resize(filesz);
const auto filesz = phdr[meta_shdr[i].program_idx].p_filesz;
// Create a pointer to a buffer for decompression.
std::unique_ptr<u8[]> decomp_buf(new u8[filesz]);
// Create a buffer separate from data_buf to uncompress.
ensure(data_buf.size() > data_buf_offset);
const std::vector<u8> zlib_buf(data_buf.cbegin() + data_buf_offset, data_buf.cend());
std::vector<u8> zlib_buf = data_buf;
uLongf decomp_buf_length = ::narrow<uLongf>(filesz);
// Use zlib uncompress on the new buffer.
// decomp_buf_length changes inside the call to uncompress
uLongf decomp_buf_length = ::narrow<uLongf>(filesz);
const int rv = uncompress(decomp_buf.data(), &decomp_buf_length, zlib_buf.data(), ::size32(zlib_buf));
const int rv = uncompress(decomp_buf.get(), &decomp_buf_length, zlib_buf.data() + data_buf_offset, ::size32(zlib_buf));
// Check for errors (TODO: Probably safe to remove this once these changes have passed testing.)
switch (rv)
@@ -530,30 +527,19 @@ private:
default: break;
}
ensure(decomp_buf_length <= decomp_buf.size());
// Warn if the final data is smaller than expected
if (decomp_buf_length < decomp_buf.size())
{
self_log.warning("zlib uncompress returned a buffer of less size than expected (size=%d, expected=%d)", decomp_buf_length, decomp_buf.size());
}
// Seek to the program header data offset and write the data.
e.seek(phdr.p_offset);
e.write(decomp_buf.data(), decomp_buf_length);
e.seek(phdr[meta_shdr[i].program_idx].p_offset);
e.write(decomp_buf.get(), filesz);
}
else
{
// Seek to the program header data offset and write the data.
ensure(data_buf.size() >= (hdr.data_size + data_buf_offset));
ensure(hdr.data_size <= (u64{umax} - static_cast<u64>(data_buf_offset))); // Check for overflow
e.seek(phdr.p_offset);
e.write(data_buf.data() + data_buf_offset, hdr.data_size);
e.seek(phdr[meta_shdr[i].program_idx].p_offset);
e.write(data_buf.data() + data_buf_offset, meta_shdr[i].data_size);
}
// Advance the data buffer offset by data size.
data_buf_offset += ::narrow<u32>(hdr.data_size);
data_buf_offset += ::narrow<u32>(meta_shdr[i].data_size);
}
}
@@ -562,9 +548,9 @@ private:
{
e.seek(ehdr.e_shoff);
for (const SHdr& shdr : shdrs)
for (u32 i = 0; i < ehdr.e_shnum; ++i)
{
WriteShdr(e, shdr);
WriteShdr(e, shdr[i]);
}
}
}
+1
View File
@@ -4,6 +4,7 @@
#include "stdafx.h"
#include "FAudioBackend.h"
#include "Emu/System.h"
#include "Emu/Audio/audio_device_enumerator.h"
#include "Utilities/StrUtil.h"
@@ -4,6 +4,7 @@
#include <algorithm>
#include "util/logs.hpp"
#include "Emu/System.h"
#include "Emu/Audio/audio_device_enumerator.h"
#include "Utilities/StrUtil.h"
+3 -3
View File
@@ -1,7 +1,7 @@
#include "stdafx.h"
#include "audio_utils.h"
#include "Emu/system_config.h"
#include "Emu/emu_callbacks.h"
#include "Emu/System.h"
#include "Emu/IdManager.h"
#include "Emu/RSX/Overlays/overlay_message.h"
#include <cmath>
@@ -17,7 +17,7 @@ namespace audio
{
audio_fxo& fxo = g_fxo->get<audio_fxo>();
fxo.audio_muted = !fxo.audio_muted;
g_emu_callbacks.update_emu_settings();
Emu.GetCallbacks().update_emu_settings();
rsx::overlays::queue_message(fxo.audio_muted ? localized_string_id::AUDIO_MUTED : localized_string_id::AUDIO_UNMUTED, 3'000'000);
}
@@ -50,7 +50,7 @@ namespace audio
return;
g_cfg.audio.volume.set(std::clamp<s32>(new_volume, g_cfg.audio.volume.min, g_cfg.audio.volume.max));
g_emu_callbacks.update_emu_settings();
Emu.GetCallbacks().update_emu_settings();
rsx::overlays::queue_message(localized_string(localized_string_id::AUDIO_CHANGED, "%d%%", g_cfg.audio.volume.get()), 3'000'000, {}, rsx::overlays::message_pin_location::top_left, {}, true, true);
}
+1 -26
View File
@@ -19,7 +19,6 @@ add_library(rpcs3_emu STATIC
perf_monitor.cpp
IPC_config.cpp
IPC_socket.cpp
Io/SkylanderPortalIPC_config.cpp
)
if(USE_LTO)
@@ -30,17 +29,6 @@ if(USE_ASAN)
set_source_files_properties(../../Utilities/Thread.cpp PROPERTIES COMPILE_DEFINITIONS USE_ASAN)
endif()
# GCC overemits weak type information when using LTO
# This causes an issue with LLVM 22 which is build without RTTI
# Issue is specifically related to vfs::ProxyFileSystem
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set_source_files_properties(
Cell/PPUThread.cpp
Cell/SPULLVMRecompiler.cpp
PROPERTIES COMPILE_OPTIONS -fno-lto
)
endif()
if(NOT USE_SYSTEM_OPENAL)
target_compile_definitions(rpcs3_emu PUBLIC AL_LIBTYPE_STATIC)
endif()
@@ -138,8 +126,6 @@ target_sources(rpcs3_emu PRIVATE
../Loader/PSF.cpp
../Loader/PUP.cpp
../Loader/TAR.cpp
../Loader/IRD.cpp
../Loader/IRD_validation.cpp
../Loader/ISO.cpp
../Loader/iso_cache.cpp
../Loader/content_validation.cpp
@@ -201,7 +187,6 @@ target_sources(rpcs3_emu PRIVATE
Cell/SPUThread.cpp
Cell/lv2/lv2.cpp
Cell/lv2/sys_bdemu.cpp
Cell/lv2/sys_bluetooth.cpp
Cell/lv2/sys_btsetting.cpp
Cell/lv2/sys_cond.cpp
Cell/lv2/sys_console.cpp
@@ -429,7 +414,6 @@ target_sources(rpcs3_emu PRIVATE
Io/GHLtar.cpp
Io/GunCon3.cpp
Io/Infinity.cpp
Io/wiimote_config.cpp
Io/interception.cpp
Io/KamenRider.cpp
Io/KeyboardHandler.cpp
@@ -447,7 +431,6 @@ target_sources(rpcs3_emu PRIVATE
Io/RB3MidiKeyboard.cpp
Io/recording_config.cpp
Io/Skylander.cpp
Io/SkylanderPortalIPC.cpp
Io/TopShotElite.cpp
Io/TopShotFearmaster.cpp
Io/Turntable.cpp
@@ -524,12 +507,6 @@ target_sources(rpcs3_emu PRIVATE
RSX/Overlays/HomeMenu/overlay_home_menu_page.cpp
RSX/Overlays/HomeMenu/overlay_home_menu_settings.cpp
RSX/Overlays/HomeMenu/overlay_home_menu_savestate.cpp
RSX/Overlays/HomeMenu/overlay_home_menu_sidebar_page.cpp
RSX/Overlays/BigPicture/overlay_big_picture.cpp
RSX/Overlays/BigPicture/overlay_big_picture_game_details.cpp
RSX/Overlays/BigPicture/overlay_big_picture_game_grid.cpp
RSX/Overlays/BigPicture/overlay_big_picture_game_info.cpp
RSX/Overlays/BigPicture/overlay_big_picture_main_menu.cpp
RSX/Overlays/Network/overlay_recvmessage_dialog.cpp
RSX/Overlays/Network/overlay_sendmessage_dialog.cpp
RSX/Overlays/Trophies/overlay_trophy_list_dialog.cpp
@@ -586,8 +563,8 @@ target_sources(rpcs3_emu PRIVATE
RSX/RSXThread.cpp
RSX/RSXZCULL.cpp
RSX/rsx_methods.cpp
RSX/rsx_utils.cpp
RSX/rsx_vertex_data.cpp
RSX/Utils/rsx_utils.cpp
)
if(NOT ANDROID AND NOT APPLE)
@@ -633,7 +610,6 @@ if(TARGET 3rdparty_vulkan)
RSX/VK/vkutils/commands.cpp
RSX/VK/vkutils/ex.cpp
RSX/VK/vkutils/data_heap.cpp
RSX/VK/vkutils/debug_print.cpp
RSX/VK/vkutils/descriptors.cpp
RSX/VK/vkutils/image.cpp
RSX/VK/vkutils/image_helpers.cpp
@@ -699,7 +675,6 @@ target_link_libraries(rpcs3_emu
3rdparty::vulkan
3rdparty::glew
3rdparty::libusb
3rdparty::hidapi
3rdparty::wolfssl
3rdparty::openal
3rdparty::cubeb
+15 -3
View File
@@ -691,6 +691,7 @@ void cpu_thread::operator()()
static thread_local struct thread_cleanup_t
{
cpu_thread* _this = nullptr;
std::string name;
std::string(*log_prefix)() = nullptr;
void cleanup()
@@ -727,11 +728,22 @@ void cpu_thread::operator()()
~thread_cleanup_t()
{
cleanup();
if (_this)
{
cleanup();
auto log_thread = named_thread("CPU Thread Cleanup Logger", [name = name]()
{
sys_log.warning("CPU Thread '%s' terminated abnormally!", name);
});
log_thread();
}
}
} cleanup;
cleanup._this = this;
cleanup.name = thread_ctrl::get_name();
cleanup.log_prefix = old_prefix;
// Check thread status
@@ -1270,8 +1282,8 @@ u32 cpu_thread::get_pc() const
}
case thread_class::rsx:
{
const auto& ctrl = static_cast<const rsx::thread*>(this)->fifo_ctrl;
return ctrl ? ctrl->get_pos() : umax;
const auto ctrl = static_cast<const rsx::thread*>(this)->ctrl;
return ctrl ? ctrl->get.load() : umax;
}
default: break;
}
+36 -48
View File
@@ -58,11 +58,7 @@ cpu_translator::cpu_translator(llvm::Module* _module, bool is_be)
const auto prev = ci->getParent();
const auto next = prev->splitBasicBlock(ci->getNextNode());
#if LLVM_VERSION_MAJOR >= 23
llvm::cast<llvm::UncondBrInst>(m_ir->GetInsertBlock()->getTerminator())->setSuccessor(loop);
#else
llvm::cast<llvm::BranchInst>(m_ir->GetInsertBlock()->getTerminator())->setOperand(0, loop);
#endif
llvm::Value* result;
//m_ir->CreateBr(loop);
@@ -75,7 +71,11 @@ cpu_translator::cpu_translator(llvm::Module* _module, bool is_be)
result = m_ir->CreateInsertElement(v, m_ir->CreateExtractElement(data0, m_ir->CreateExtractElement(mask, i)), i);
v->addIncoming(result, loop);
m_ir->CreateCondBr(m_ir->CreateICmpULT(i, m_ir->getInt32(16)), loop, next);
#if LLVM_VERSION_MAJOR >= 21 || (LLVM_VERSION_MAJOR == 20 && LLVM_VERSION_MINOR >= 1)
m_ir->SetInsertPoint(next->getFirstNonPHIIt());
#else
m_ir->SetInsertPoint(next->getFirstNonPHI());
#endif
result = m_ir->CreateSelect(m_ir->CreateICmpSLT(index, zeros), zeros, result);
return result;
@@ -260,7 +260,9 @@ llvm::Value* cpu_translator::bitcast(llvm::Value* val, llvm::Type* type, std::so
}
// Skip use iteration for values that don't have use lists
#if LLVM_VERSION_MAJOR >= 21
if (source_val->hasUseList())
#endif
{
for (llvm::Value* it_val : source_val->uses())
{
@@ -285,10 +287,12 @@ llvm::Value* cpu_translator::bitcast(llvm::Value* val, llvm::Type* type, std::so
}
// Check if bci has use list before accessing use_begin()
#if LLVM_VERSION_MAJOR >= 21
if (!bci->hasUseList())
{
break;
}
#endif
if (bci->use_begin() == bci->use_end())
{
@@ -313,9 +317,6 @@ llvm::Value* cpu_translator::bitcast(llvm::Value* val, llvm::Type* type, std::so
template <>
std::pair<bool, v128> cpu_translator::get_const_vector<v128>(llvm::Value* c, u32 _pos, u32 _line)
{
// Bitcasts do not matter
c = peek_through_bitcasts(c);
v128 result{};
if (!llvm::isa<llvm::Constant>(c))
@@ -345,27 +346,6 @@ std::pair<bool, v128> cpu_translator::get_const_vector<v128>(llvm::Value* c, u32
fmt::throw_exception("[0x%x, %u] Bad vector size: i%ux%u", _pos, _line, v->getScalarSizeInBits(), v->getNumElements());
}
// Vector splats may be represented as ConstantInt/ConstantFP with a vector type (default for ConstantFP since LLVM 23)
const auto splat = [&](const llvm::APInt& elem) -> std::pair<bool, v128>
{
const auto cv = llvm::APInt::getSplat(128, elem);
result._u64[0] = cv.extractBitsAsZExtValue(64, 0);
result._u64[1] = cv.extractBitsAsZExtValue(64, 64);
return {true, result};
};
if (const auto ci = llvm::dyn_cast<llvm::ConstantInt>(c))
{
return splat(ci->getValue());
}
if (const auto cfp = llvm::dyn_cast<llvm::ConstantFP>(c))
{
return splat(cfp->getValueAPF().bitcastToAPInt());
}
const auto cv = llvm::dyn_cast<llvm::ConstantDataVector>(c);
if (!cv)
@@ -601,8 +581,10 @@ void cpu_translator::erase_stores(llvm::ArrayRef<llvm::Value*> args)
for (auto v : args)
{
// Skip use iteration for values that don't have use lists
#if LLVM_VERSION_MAJOR >= 21
if (!v->hasUseList())
continue;
#endif
for (llvm::Value* i : v->uses())
{
@@ -612,8 +594,10 @@ void cpu_translator::erase_stores(llvm::ArrayRef<llvm::Value*> args)
while (i && (bci = llvm::dyn_cast<llvm::CastInst>(i)) && bci->getOpcode() == llvm::Instruction::BitCast)
{
// Check if bci has use list before accessing use_begin()
#if LLVM_VERSION_MAJOR >= 21
if (!bci->hasUseList())
break;
#endif
i = *bci->use_begin();
}
@@ -634,7 +618,7 @@ llvm::KnownBits cpu_translator::get_known_bits_fallback(llvm::Value* value)
if (!type->isVectorTy())
{
if (llvm::isa<llvm::IntegerType>(type))
if (const auto it = llvm::dyn_cast<llvm::IntegerType>(type))
{
if (auto bin_inst = llvm::dyn_cast<llvm::BinaryOperator>(value))
{
@@ -676,7 +660,20 @@ llvm::KnownBits cpu_translator::get_known_bits_fallback(llvm::Value* value)
return llvm::KnownBits(type->getScalarSizeInBits());
}
const auto cv = llvm::dyn_cast<llvm::ConstantDataVector>(value);
if (!cv)
{
if (llvm::isa<llvm::ConstantAggregateZero>(value))
{
llvm::KnownBits ret(type->getScalarSizeInBits());
ret.Zero.setAllBits();
return ret;
}
}
const auto original_value = peek_through_bitcasts(value);
const auto original_type = original_value->getType();
auto bin_inst = llvm::dyn_cast<llvm::BinaryOperator>(original_value);
@@ -699,40 +696,31 @@ llvm::KnownBits cpu_translator::get_known_bits_fallback(llvm::Value* value)
ensure(ok);
llvm::APInt all_lanes{};
llvm::APInt any_lanes{};
llvm::APInt dest{};
auto combine_bits = [&](const auto& array, u32 size)
{
auto all = +array[0];
auto any = +array[0];
auto first = +array[0];
for (u32 i = 1; i < size; i++)
for (u32 i = 0; i < size; i++)
{
all &= +array[i];
any |= +array[i];
first &= +array[i];
}
return std::make_pair(all, any);
return first;
};
if (type->getScalarType()->isIntegerTy(8))
{
const auto [all, any] = combine_bits(v128_const._u8, 16);
all_lanes = llvm::APInt(8, all);
any_lanes = llvm::APInt(8, any);
dest = llvm::APInt(8, combine_bits(v128_const._u8, 16));
}
else if (type->getScalarType()->isIntegerTy(16))
{
const auto [all, any] = combine_bits(v128_const._u16, 8);
all_lanes = llvm::APInt(16, all);
any_lanes = llvm::APInt(16, any);
dest = llvm::APInt(16, combine_bits(v128_const._u16, 8));
}
else if (type->getScalarType()->isIntegerTy(32))
{
const auto [all, any] = combine_bits(v128_const._u32, 4);
all_lanes = llvm::APInt(32, all);
any_lanes = llvm::APInt(32, any);
dest = llvm::APInt(32, combine_bits(v128_const._u32, 4));
}
else // if (type->getScalarType()->isIntegerTy(64))
{
@@ -742,14 +730,14 @@ llvm::KnownBits cpu_translator::get_known_bits_fallback(llvm::Value* value)
if (bin_inst->getOpcode() == llvm::Instruction::Or)
{
llvm::KnownBits ret(type->getScalarSizeInBits());
ret.One = all_lanes;
ret.One = dest;
return ret;
}
if (bin_inst->getOpcode() == llvm::Instruction::And)
{
llvm::KnownBits ret(type->getScalarSizeInBits());
ret.Zero = any_lanes;
ret.Zero = dest;
ret.Zero.flipAllBits();
return ret;
}
+38 -96
View File
@@ -8,10 +8,6 @@
#include "Utilities/JIT.h"
#include "util/v128.hpp"
#ifdef ARCH_X64
#include <immintrin.h>
#endif
#ifdef _MSC_VER
#pragma warning(push, 0)
#else
@@ -25,14 +21,15 @@
#pragma GCC diagnostic ignored "-Wmissing-noreturn"
#pragma GCC diagnostic ignored "-Wredundant-decls"
#endif
#include "llvm/Config/llvm-config.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Module.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Support/KnownBits.h"
#if LLVM_VERSION_MAJOR >= 21
#include "llvm/Support/KnownFPClass.h"
#endif
#include "llvm/Analysis/SimplifyQuery.h"
#include "llvm/Analysis/ConstantFolding.h"
#include "llvm/Analysis/ValueTracking.h"
@@ -48,13 +45,6 @@
#pragma GCC diagnostic pop
#endif
// MSVC can use intrinsics without compiling for its target feature
#if defined(_MSC_VER) || !defined(ARCH_X64)
#define GNUC_X64_TARGET(x)
#else
#define GNUC_X64_TARGET(x) [[gnu::target(x)]]
#endif
#include <functional>
#include <unordered_map>
#include <source_location>
@@ -62,26 +52,6 @@
// Helper function
llvm::Value* peek_through_bitcasts(llvm::Value*);
inline bool llvm_has_terminator(const llvm::BasicBlock* bb)
{
#if LLVM_VERSION_MAJOR >= 23
return bb->hasTerminator();
#else
return bb->getTerminator() != nullptr;
#endif
}
// Constant fold the result of IRBuilder::CreateIntrinsic (LLVM 23+ IRBuilder may already return a folded constant)
inline llvm::Constant* llvm_const_fold(llvm::Value* v)
{
if (auto c = llvm::dyn_cast<llvm::Constant>(v))
{
return c;
}
return llvm::ConstantFoldInstruction(llvm::cast<llvm::Instruction>(v), llvm::DataLayout(""));
}
enum class i2 : char
{
};
@@ -1210,7 +1180,11 @@ struct llvm_fshl
static llvm::Function* get_fshl(llvm::IRBuilder<>* ir)
{
const auto _module = ir->GetInsertBlock()->getParent()->getParent();
#if LLVM_VERSION_MAJOR >= 21 || (LLVM_VERSION_MAJOR == 20 && LLVM_VERSION_MINOR >= 1)
return llvm::Intrinsic::getOrInsertDeclaration(_module, llvm::Intrinsic::fshl, {llvm_value_t<T>::get_type(ir->getContext())});
#else
return llvm::Intrinsic::getDeclaration(_module, llvm::Intrinsic::fshl, {llvm_value_t<T>::get_type(ir->getContext())});
#endif
}
static llvm::Value* fold(llvm::IRBuilder<>* ir, llvm::Value* v1, llvm::Value* v2, llvm::Value* v3)
@@ -1282,7 +1256,11 @@ struct llvm_fshr
static llvm::Function* get_fshr(llvm::IRBuilder<>* ir)
{
const auto _module = ir->GetInsertBlock()->getParent()->getParent();
#if LLVM_VERSION_MAJOR >= 21 || (LLVM_VERSION_MAJOR == 20 && LLVM_VERSION_MINOR >= 1)
return llvm::Intrinsic::getOrInsertDeclaration(_module, llvm::Intrinsic::fshr, {llvm_value_t<T>::get_type(ir->getContext())});
#else
return llvm::Intrinsic::getDeclaration(_module, llvm::Intrinsic::fshr, {llvm_value_t<T>::get_type(ir->getContext())});
#endif
}
static llvm::Value* fold(llvm::IRBuilder<>* ir, llvm::Value* v1, llvm::Value* v2, llvm::Value* v3)
@@ -2388,7 +2366,11 @@ struct llvm_add_sat
static llvm::Function* get_add_sat(llvm::IRBuilder<>* ir)
{
const auto _module = ir->GetInsertBlock()->getParent()->getParent();
#if LLVM_VERSION_MAJOR >= 21 || (LLVM_VERSION_MAJOR == 20 && LLVM_VERSION_MINOR >= 1)
return llvm::Intrinsic::getOrInsertDeclaration(_module, intr, {llvm_value_t<T>::get_type(ir->getContext())});
#else
return llvm::Intrinsic::getDeclaration(_module, intr, {llvm_value_t<T>::get_type(ir->getContext())});
#endif
}
llvm::Value* eval(llvm::IRBuilder<>* ir) const
@@ -2471,7 +2453,11 @@ struct llvm_sub_sat
static llvm::Function* get_sub_sat(llvm::IRBuilder<>* ir)
{
const auto _module = ir->GetInsertBlock()->getParent()->getParent();
#if LLVM_VERSION_MAJOR >= 21 || (LLVM_VERSION_MAJOR == 20 && LLVM_VERSION_MINOR >= 1)
return llvm::Intrinsic::getOrInsertDeclaration(_module, intr, {llvm_value_t<T>::get_type(ir->getContext())});
#else
return llvm::Intrinsic::getDeclaration(_module, intr, {llvm_value_t<T>::get_type(ir->getContext())});
#endif
}
llvm::Value* eval(llvm::IRBuilder<>* ir) const
@@ -2789,7 +2775,7 @@ struct llvm_ctlz
if (llvm::isa<llvm::Constant>(v))
{
return llvm_const_fold(ir->CreateIntrinsic(llvm::Intrinsic::ctlz, {v->getType()}, {v, ir->getFalse()}));
return llvm::ConstantFoldInstruction(ir->CreateIntrinsic(llvm::Intrinsic::ctlz, {v->getType()}, {v, ir->getFalse()}), llvm::DataLayout(""));
}
return ir->CreateIntrinsic(llvm::Intrinsic::ctlz, {v->getType()}, {v, ir->getFalse()});
@@ -2834,7 +2820,7 @@ struct llvm_ctpop
if (llvm::isa<llvm::Constant>(v))
{
return llvm_const_fold(ir->CreateUnaryIntrinsic(llvm::Intrinsic::ctpop, v));
return llvm::ConstantFoldInstruction(ir->CreateUnaryIntrinsic(llvm::Intrinsic::ctpop, v), llvm::DataLayout(""));
}
return ir->CreateUnaryIntrinsic(llvm::Intrinsic::ctpop, v);
@@ -2955,7 +2941,7 @@ struct llvm_fsqrt
if (llvm::isa<llvm::Constant>(v))
{
if (auto c = llvm_const_fold(ir->CreateUnaryIntrinsic(llvm::Intrinsic::sqrt, v)))
if (auto c = llvm::ConstantFoldInstruction(ir->CreateUnaryIntrinsic(llvm::Intrinsic::sqrt, v), llvm::DataLayout("")))
{
// Will fail in some cases (such as negative constant)
return c;
@@ -3001,7 +2987,7 @@ struct llvm_fabs
if (llvm::isa<llvm::Constant>(v))
{
return llvm_const_fold(ir->CreateUnaryIntrinsic(llvm::Intrinsic::fabs, v));
return llvm::ConstantFoldInstruction(ir->CreateUnaryIntrinsic(llvm::Intrinsic::fabs, v), llvm::DataLayout(""));
}
return ir->CreateUnaryIntrinsic(llvm::Intrinsic::fabs, v);
@@ -3048,7 +3034,7 @@ struct llvm_fmuladd
if (llvm::isa<llvm::Constant>(v1) && llvm::isa<llvm::Constant>(v2) && llvm::isa<llvm::Constant>(v3))
{
return llvm_const_fold(ir->CreateIntrinsic(llvm::Intrinsic::fma, {v1->getType()}, {v1, v2, v3}));
return llvm::ConstantFoldInstruction(ir->CreateIntrinsic(llvm::Intrinsic::fma, {v1->getType()}, {v1, v2, v3}), llvm::DataLayout(""));
}
return ir->CreateIntrinsic(strict_fma ? llvm::Intrinsic::fma : llvm::Intrinsic::fmuladd, {v1->getType()}, {v1, v2, v3});
@@ -3818,7 +3804,11 @@ public:
llvm::Function* get_intrinsic(llvm::Intrinsic::ID id)
{
const auto _module = m_ir->GetInsertBlock()->getParent()->getParent();
#if LLVM_VERSION_MAJOR >= 21 || (LLVM_VERSION_MAJOR == 20 && LLVM_VERSION_MINOR >= 1)
return llvm::Intrinsic::getOrInsertDeclaration(_module, id, {get_type<Types>()...});
#else
return llvm::Intrinsic::getDeclaration(_module, id, {get_type<Types>()...});
#endif
}
template <typename T1, typename T2, typename T3>
@@ -3839,25 +3829,13 @@ public:
}
template <typename T1, typename T2>
GNUC_X64_TARGET("gfni") value_t<u8[16]> gf2p8affineqb(T1 a, T2 b, u8 c)
value_t<u8[16]> gf2p8affineqb(T1 a, T2 b, u8 c)
{
value_t<u8[16]> result;
const auto data0 = a.eval(m_ir);
const auto data1 = b.eval(m_ir);
#ifdef ARCH_X64
const auto [a_is_const, a_data] = get_const_vector(data0, -1);
const auto [b_is_const, b_data] = get_const_vector(data1, -1);
if (a_is_const && b_is_const)
{
const auto affine = _mm_xor_si128(_mm_gf2p8affine_epi64_epi8(a_data, b_data, 0), _mm_set1_epi8(c));
result.value = llvm::ConstantDataVector::get(m_context, llvm::ArrayRef(static_cast<v128>(affine)._u8.m_data, 16));
return result;
}
#endif
const auto immediate = (llvm_const_int<u8>{c});
const auto imm8 = immediate.eval(m_ir);
@@ -3873,27 +3851,14 @@ public:
const auto data0 = a.eval(m_ir);
const auto data1 = b.eval(m_ir);
const auto data2 = c.eval(m_ir);
#ifdef ARCH_X64
const auto [a_is_const, a_data] = get_const_vector(data0, -1);
const auto [b_is_const, b_data] = get_const_vector(data1, -1);
const auto [c_is_const, c_data] = get_const_vector(data2, -1);
if (a_is_const && b_is_const && c_is_const)
{
__m128i dpbusd;
if (utils::has_avx512_icl())
dpbusd = _mm_wrapper_dpbusd_avx512vnni(a_data, b_data, c_data);
else
dpbusd = _mm_wrapper_dpbusd_avxvnni(a_data, b_data, c_data);
result.value = llvm::ConstantDataVector::get(m_context, llvm::ArrayRef(static_cast<v128>(dpbusd)._u32.m_data, 4));
return result;
}
#endif
#if LLVM_VERSION_MAJOR >= 22
// LLVM 22+ changed the intrinsic signature from v4i32 to v16i8 for operands 2 and 3
result.value = m_ir->CreateCall(get_intrinsic(llvm::Intrinsic::x86_avx512_vpdpbusd_128),
{data0, m_ir->CreateBitCast(data1, get_type<u8[16]>()), m_ir->CreateBitCast(data2, get_type<u8[16]>())});
#else
result.value = m_ir->CreateCall(get_intrinsic(llvm::Intrinsic::x86_avx512_vpdpbusd_128), {data0, data1, data2});
#endif
return result;
}
@@ -4259,27 +4224,13 @@ template <typename T1, typename T2, typename T3>
}
template <typename T1, typename T2, typename T3>
GNUC_X64_TARGET("avx512vl") value_t<f32[4]> vfixupimmps(T1 a, T2 b, T3 c, u8 d, u8 e)
value_t<f32[4]> vfixupimmps(T1 a, T2 b, T3 c, u8 d, u8 e)
{
value_t<f32[4]> result;
const auto data0 = a.eval(m_ir);
const auto data1 = b.eval(m_ir);
const auto data2 = c.eval(m_ir);
#ifdef ARCH_X64
const auto [a_is_const, a_data] = get_const_vector(data0, -1);
const auto [b_is_const, b_data] = get_const_vector(data1, -1);
const auto [c_is_const, c_data] = get_const_vector(data2, -1);
if (a_is_const && b_is_const && c_is_const)
{
const auto vfixup = _mm_mask_fixupimm_ps(a_data, e, b_data, c_data, 0); // flag reporting doesn't matter for constants
result.value = llvm::ConstantDataVector::get(m_context, llvm::ArrayRef(static_cast<v128>(vfixup)._f.m_data, 4));
return result;
}
#endif
const auto immediate = (llvm_const_int<u32>{d});
const auto imm32 = immediate.eval(m_ir);
const auto immediate2 = (llvm_const_int<u8>{e});
@@ -4382,27 +4333,18 @@ template <typename T1, typename T2, typename T3>
{
static_assert(depth <= llvm::MaxAnalysisRecursionDepth, "Depth parameter can only decrease search. Default is max.");
#if LLVM_VERSION_MAJOR >= 21
const llvm::SimplifyQuery SQ(m_module->getDataLayout());
return llvm::computeKnownFPClass(a.eval(m_ir), interested_classes, SQ, llvm::MaxAnalysisRecursionDepth - depth);
#else
return llvm::computeKnownFPClass(a.eval(m_ir), m_module->getDataLayout(), interested_classes, llvm::MaxAnalysisRecursionDepth - depth);
#endif
}
private:
// Custom intrinsic table
std::unordered_map<std::string_view, std::function<llvm::Value*(llvm::CallInst*)>> m_intrinsics;
#ifdef ARCH_X64
// LLVM uses the same intrinsic despite different encodings
GNUC_X64_TARGET("avx512vnni,avx512vl") __m128i _mm_wrapper_dpbusd_avx512vnni(__m128i a, __m128i b, __m128i c)
{
return _mm_dpbusd_epi32(a, b, c);
}
GNUC_X64_TARGET("avxvnni") __m128i _mm_wrapper_dpbusd_avxvnni(__m128i a, __m128i b, __m128i c)
{
return _mm_dpbusd_avx_epi32(a, b, c);
}
#endif
public:
// Call custom intrinsic by name
template <typename RT, typename... Args>
-151
View File
@@ -199,154 +199,3 @@ inline struct ppu_frsqrte_lut_t
}
}
} ppu_frqrte_lut;
constexpr u32 ppu_vrefp_segments[32][2] =
{
{0x7ff800, 0x3e1}, {0x783800, 0x3a7}, {0x70ea00, 0x371}, {0x6a0800, 0x340},
{0x638800, 0x313}, {0x5d6200, 0x2ea}, {0x579000, 0x2c4}, {0x520800, 0x2a0},
{0x4cc800, 0x27f}, {0x47ca00, 0x261}, {0x430800, 0x245}, {0x3e8000, 0x22a},
{0x3a2c00, 0x212}, {0x360800, 0x1fb}, {0x321400, 0x1e5}, {0x2e4a00, 0x1d1},
{0x2aa800, 0x1be}, {0x272c00, 0x1ac}, {0x23d600, 0x19b}, {0x209e00, 0x18b},
{0x1d8800, 0x17c}, {0x1a9000, 0x16e}, {0x17ae00, 0x15b}, {0x14f800, 0x15b},
{0x124400, 0x143}, {0x0fbe00, 0x143}, {0x0d3800, 0x12d}, {0x0ade00, 0x12d},
{0x088400, 0x11a}, {0x065000, 0x11a}, {0x041c00, 0x108}, {0x020c00, 0x106},
};
constexpr u32 ppu_vrsqrtefp_segments[32][3] =
{
{0x34fd00, 0x568, 0x00}, {0x2f9700, 0x4f3, 0x26}, {0x2aa500, 0x48d, 0xc8}, {0x261800, 0x435, 0xc8},
{0x21e400, 0x3e7, 0x26}, {0x1dfe00, 0x3a2, 0x88}, {0x1a5c00, 0x365, 0xc8}, {0x16f800, 0x32e, 0x22},
{0x13ca00, 0x2fc, 0x00}, {0x10ce00, 0x2d0, 0x00}, {0x0dfe00, 0x2a8, 0x00}, {0x0b5700, 0x283, 0x26},
{0x08d400, 0x261, 0xc8}, {0x067300, 0x243, 0x26}, {0x043100, 0x226, 0x22}, {0x020b00, 0x20b, 0x26},
{0x7ff400, 0x7a4, 0x00}, {0x785200, 0x700, 0x00}, {0x715400, 0x670, 0x00}, {0x6ae400, 0x5f2, 0x88},
{0x64f200, 0x584, 0x00}, {0x5f6e00, 0x524, 0x00}, {0x5a4c00, 0x4cc, 0x00}, {0x558000, 0x47e, 0x22},
{0x510200, 0x43a, 0x88}, {0x4cca00, 0x3fa, 0x88}, {0x48d000, 0x3c2, 0x88}, {0x450e00, 0x38e, 0x22},
{0x418200, 0x35e, 0x22}, {0x3e2400, 0x332, 0x88}, {0x3af200, 0x30a, 0x88}, {0x37e800, 0x2e6, 0x22},
};
constexpr u16 ppu_vlogefp_segments[16][2] =
{
{0x0000, 12}, {0x0600, 10}, {0x0b00, 10}, {0x1000, 9},
{0x1480, 9}, {0x1900, 9}, {0x1d80, 8}, {0x2180, 8},
{0x2580, 8}, {0x297f, 7}, {0x2cff, 7}, {0x307f, 7},
{0x33fe, 6}, {0x36fe, 6}, {0x39fe, 6}, {0x3cfe, 6},
};
constexpr u16 ppu_vexptefp_segments[16][2] =
{
{0x0006, 6}, {0x0306, 6}, {0x0606, 6}, {0x0906, 6},
{0x0c07, 7}, {0x0f87, 7}, {0x1307, 7}, {0x1680, 8},
{0x1a80, 8}, {0x1e80, 8}, {0x2288, 9}, {0x2708, 9},
{0x2b88, 9}, {0x3008, 10}, {0x3508, 10}, {0x3a08, 12},
};
constexpr void ppu_vnormalize(s32& e, u32& m)
{
const u32 shift = std::countl_zero(m) - 8;
m = (m << shift) & 0x7fffff;
e = 1 - static_cast<s32>(shift);
}
constexpr u32 ppu_vrefp(u32 x, bool nj)
{
const u32 s = x & 0x80000000;
s32 e = (x >> 23) & 0xff;
u32 m = x & 0x7fffff;
if (e == 0xff)
return m ? x | 0x400000 : s;
if (e == 0 && (nj || m == 0))
return s | 0x7f800000;
if (e == 0)
ppu_vnormalize(e, m);
const auto& seg = ppu_vrefp_segments[m >> 18];
const u32 mant = seg[0] - seg[1] * ((m >> 9) & 0x1ff);
const s32 exp = 253 - e;
if (exp >= 0xff)
return s | 0x7f800000;
if (exp > 0)
return s | exp << 23 | mant;
if (nj)
return s;
const u32 full = mant | 0x800000, shift = 1 - exp, half = 1u << (shift - 1);
const u32 rest = full & ((half << 1) - 1);
return s | ((full >> shift) + (rest > half || (rest == half && (full >> shift) & 1)));
}
constexpr u32 ppu_vrsqrtefp(u32 x, bool nj)
{
const u32 s = x & 0x80000000;
s32 e = (x >> 23) & 0xff;
u32 m = x & 0x7fffff;
if (e == 0xff)
return m ? x | 0x400000 : s ? 0x7fc00000 : 0;
if (e == 0 && (nj || m == 0))
return s | 0x7f800000;
if (s)
return 0x7fc00000;
if (e == 0)
ppu_vnormalize(e, m);
const auto& seg = ppu_vrsqrtefp_segments[(e & 1) << 4 | m >> 19];
const u32 key = (m >> 9) & 0x3ff;
return (380 - e) >> 1 << 23 | (seg[0] - ((seg[1] * key) >> 2) - ((seg[2] >> (key & 7)) & 1));
}
constexpr u32 ppu_vlogefp(u32 x, bool nj)
{
const u32 s = x & 0x80000000;
s32 e = (x >> 23) & 0xff;
u32 m = x & 0x7fffff;
if (e == 0xff)
return m ? x | 0x400000 : s ? 0x7fc00000 : x;
if (e == 0 && (nj || m == 0))
return 0xff800000;
if (s)
return 0x7fc00000;
if (e == 0)
ppu_vnormalize(e, m);
const u32 key = m >> 12;
const auto& seg = ppu_vlogefp_segments[key >> 7];
const s32 fixed = (e - 127) * 2048 + ((seg[0] + seg[1] * (key & 0x7f)) >> 3);
return std::bit_cast<u32>(static_cast<f32>(fixed) / 2048);
}
constexpr u32 ppu_vexptefp(u32 x, bool)
{
const u32 s = x & 0x80000000, e = (x >> 23) & 0xff, m = x & 0x7fffff;
if (e == 0xff)
return m ? x | 0x400000 : s ? 0 : x;
if (e > 150)
return s ? 0 : 0x7f800000;
const s64 mag = e >= 135 ? s64{m | 0x800000} << (e - 135) : e > 111 ? (m | 0x800000) >> (135 - e) : 0;
const s64 fixed = (s ? -mag : mag) >> 4;
const s64 exp = 127 + (fixed >> 11);
if (exp >= 0xff)
return 0x7f800000;
if (exp <= 0)
return 0;
const auto& seg = ppu_vexptefp_segments[(fixed >> 7) & 0xf];
return static_cast<u32>(exp) << 23 | ((seg[0] + seg[1] * (fixed & 0x7f)) >> 3) << 12;
}
File diff suppressed because it is too large Load Diff
+9 -62
View File
@@ -1,7 +1,6 @@
#pragma once
#include "Emu/Memory/vm_ptr.h"
#include "Emu/Cell/ErrorCodes.h"
#include "Utilities/Thread.h"
#include "Utilities/simple_ringbuf.h"
#include "Emu/Memory/vm.h"
@@ -11,8 +10,6 @@
#include "Emu/system_config_types.h"
struct lv2_event_queue;
struct lv2_memory;
class ppu_thread;
// Error codes
enum CellAudioError : u32
@@ -125,24 +122,6 @@ enum : u32
PORT_BUFFER_TAG_LAST_8CH = AUDIO_BLOCK_SIZE_8CH - 1,
PORT_BUFFER_TAG_DELTA_8CH = PORT_BUFFER_TAG_LAST_8CH / (PORT_BUFFER_TAG_COUNT - 1),
PORT_BUFFER_TAG_FIRST_8CH = PORT_BUFFER_TAG_LAST_8CH % (PORT_BUFFER_TAG_COUNT - 1),
// The tags above are spread over the block diagonally, so on an 8 channel port they all land on channels
// 2 to 7. A game may legitimately never write those: one that was told the output is stereo fills only
// front left/right of an 8 channel port, and cellAudioAdd2chData does the same. Such a port keeps every
// tag at its initial value and looks untouched forever, which silences it while buffering is enabled.
// These extra marks sit on the front right channel, which any audio content writes, and are only used to
// tell "the game wrote nothing" apart from "the game wrote the front channels only". They carry no state:
// a mark counts as written when it no longer is the negative zero that tag() put there. On a two channel
// port they coincide with the tags, so only wider ports carry their own.
PORT_BUFFER_MARK_CHANNEL = 1,
PORT_BUFFER_MARK_DELTA_SAMPLE = (AUDIO_BUFFER_SAMPLES - 1) / (PORT_BUFFER_TAG_COUNT - 1),
// How many periods a port must go without moving a single tag before the marks are believed and it is
// treated as one that only ever fills its front channels. A game writing genuine surround moves a tag
// every period, so it never gets anywhere near this; one that fills the buffer one channel at a time
// and stalls mid-pass is covered by the same margin. Below the threshold the tags alone decide, so the
// marks are a fallback for a case the tags cannot see rather than a rule of their own.
PORT_FRONT_ONLY_SETTLE_PERIODS = 8,
};
enum class audio_port_state : u32
@@ -157,8 +136,6 @@ struct audio_port
atomic_t<audio_port_state> state = audio_port_state::closed;
u32 number = 0;
u32 server_index = 0;
bool mapped = false;
vm::ptr<char> addr{};
vm::ptr<u64> index{};
@@ -182,7 +159,7 @@ struct audio_port
u32 block_size() const
{
return std::max(num_channels, 1u) * AUDIO_BUFFER_SAMPLES;
return num_channels * AUDIO_BUFFER_SAMPLES;
}
u32 buf_size() const
@@ -196,10 +173,14 @@ struct audio_port
return (cur_pos + ofs) % num_blocks;
}
be_t<f32>* get_vm_ptr() const
u32 buf_addr(s32 offset = 0) const
{
const u32 block = static_cast<u16>(*index) & (num_blocks - 1);
return vm::_ptr<f32>(addr.addr() + block * buf_size());
return addr.addr() + position(offset) * buf_size();
}
be_t<f32>* get_vm_ptr(s32 offset = 0) const
{
return vm::_ptr<f32>(buf_addr(offset));
}
@@ -207,12 +188,7 @@ struct audio_port
u32 prev_touched_tag_nr = 0;
f32 last_tag_value[PORT_BUFFER_TAG_COUNT] = { 0 };
u32 mark_position(u32 tag_nr) const
{
return tag_nr * PORT_BUFFER_MARK_DELTA_SAMPLE * num_channels + PORT_BUFFER_MARK_CHANNEL;
}
void tag(be_t<f32>* port_buf);
void tag(s32 offset = 0);
audio_port() = default;
@@ -394,7 +370,6 @@ class cell_audio_thread
{
private:
std::unique_ptr<audio_ringbuffer> ringbuffer{};
be_t<f32>* get_buffer(const audio_port& port, s32 offset = 0) const;
void reset_ports(s32 offset = 0);
void advance(u64 timestamp);
@@ -413,14 +388,6 @@ public:
shared_mutex mutex{};
atomic_t<u8> init = 0;
u32 shared_area = 0;
u32 shared_address = 0;
u32 shared_refs = 0;
shared_ptr<lv2_memory> shared_memory;
std::array<shared_ptr<lv2_memory>, AUDIO_PORT_COUNT> port_memories;
u32 free_port_count = 0;
std::array<u32, AUDIO_PORT_COUNT> free_ports{};
std::array<u32, AUDIO_PORT_COUNT> free_indices{};
u32 key_count = 0;
u8 event_period = 0;
@@ -447,23 +414,6 @@ public:
bool m_backend_failed = false;
bool m_audio_should_restart = false;
// Whether we already reported that a port carries front channel audio only. Diagnostics for a condition
// that is otherwise indistinguishable from a game that simply went silent, so it is worth one line per
// port. Deliberately not serialized: a savestate that reloads into the same condition may report it
// again, which is harmless and arguably useful.
std::array<bool, AUDIO_PORT_COUNT> m_front_only_reported{};
// Periods since each port last moved one of its buffer tags, saturating. Tells a port that fills only
// its front channels apart from one that is merely between two passes of a channel by channel write,
// see PORT_FRONT_ONLY_SETTLE_PERIODS. Deliberately not serialized: it starts at zero, which is the
// conservative end, and settles again within a few periods.
std::array<u8, AUDIO_PORT_COUNT> m_periods_without_tag{};
// Whether the marks have shown that a port only ever fills its front channels; cleared when a tag moves.
// They only describe the current block, so without this a port fed in bursts would look untouched
// between its writes and stall the thread on a timeout. Not serialized: it settles again in a few periods.
std::array<bool, AUDIO_PORT_COUNT> m_front_only_port{};
void operator()();
SAVESTATE_INIT_POS(9);
@@ -473,9 +423,6 @@ public:
void save(utils::serial& ar);
audio_port* open_port();
error_code allocate_port(ppu_thread& ppu, audio_port& port);
void close_port(ppu_thread& ppu, audio_port& port);
void release_shared_memory(ppu_thread& ppu);
static constexpr auto thread_name = "cellAudio Thread"sv;
};
-2
View File
@@ -25,8 +25,6 @@ enum CellAudioInDeviceMode
enum CellAudioInPortType
{
CELL_AUDIO_IN_PORT_EYETOY1 = 1, // speculative, EyeToy
CELL_AUDIO_IN_PORT_EYETOY2 = 2, // speculative, PS EYE
CELL_AUDIO_IN_PORT_USB = 3,
CELL_AUDIO_IN_PORT_BLUETOOTH = 4,
};
+2 -46
View File
@@ -2,7 +2,7 @@
#include "Emu/system_config.h"
#include "Emu/Cell/PPUModule.h"
#include "Emu/IdManager.h"
#include "Emu/RSX/Utils/rsx_utils.h"
#include "Emu/RSX/rsx_utils.h"
#include "Utilities/StrUtil.h"
#include "cellMic.h"
@@ -89,50 +89,6 @@ avconf_manager::avconf_manager()
}
break;
}
case microphone_handler::eye_toy:
{
for (u32 index = 0; index < mic_list.size(); index++)
{
device_info device {};
device.info.portType = CELL_AUDIO_IN_PORT_EYETOY1;
device.info.availableModeCount = 1;
device.info.state = CELL_AUDIO_IN_DEVICE_STATE_AVAILABLE;
device.info.deviceId = 0xE11CC0DE + curindex;
device.info.type = 0xC0DEE11C;
device.info.availableModes[0].type = CELL_AUDIO_IN_CODING_TYPE_LPCM;
device.info.availableModes[0].channel = CELL_AUDIO_IN_CHNUM_2;
device.info.availableModes[0].fs = CELL_AUDIO_IN_FS_8KHZ | CELL_AUDIO_IN_FS_12KHZ | CELL_AUDIO_IN_FS_16KHZ | CELL_AUDIO_IN_FS_24KHZ | CELL_AUDIO_IN_FS_32KHZ | CELL_AUDIO_IN_FS_48KHZ;
device.info.deviceNumber = curindex;
device.full_device_name = mic_list[index];
strcpy_trunc(device.info.name, device.full_device_name);
devices.push_back(std::move(device));
curindex++;
}
break;
}
case microphone_handler::ps_eye:
{
for (u32 index = 0; index < mic_list.size(); index++)
{
device_info device {};
device.info.portType = CELL_AUDIO_IN_PORT_EYETOY2;
device.info.availableModeCount = 1;
device.info.state = CELL_AUDIO_IN_DEVICE_STATE_AVAILABLE;
device.info.deviceId = 0xE11CC0DE + curindex;
device.info.type = 0xC0DEE11C;
device.info.availableModes[0].type = CELL_AUDIO_IN_CODING_TYPE_LPCM;
device.info.availableModes[0].channel = CELL_AUDIO_IN_CHNUM_2;
device.info.availableModes[0].fs = CELL_AUDIO_IN_FS_8KHZ | CELL_AUDIO_IN_FS_12KHZ | CELL_AUDIO_IN_FS_16KHZ | CELL_AUDIO_IN_FS_24KHZ | CELL_AUDIO_IN_FS_32KHZ | CELL_AUDIO_IN_FS_48KHZ;
device.info.deviceNumber = curindex;
device.full_device_name = mic_list[index];
strcpy_trunc(device.info.name, device.full_device_name);
devices.push_back(std::move(device));
curindex++;
}
break;
}
case microphone_handler::real_singstar:
case microphone_handler::singstar:
{
@@ -274,7 +230,7 @@ error_code cellAudioInGetDeviceInfo(u32 deviceNumber, u32 deviceIndex, vm::ptr<C
std::lock_guard lock(av_manager.mutex);
if (deviceNumber >= av_manager.devices.size())
return CELL_AUDIO_IN_ERROR_DEVICE_NOT_FOUND;
return CELL_AUDIO_OUT_ERROR_DEVICE_NOT_FOUND;
av_manager.copy_device_info(deviceNumber, info);
+8 -25
View File
@@ -1,7 +1,6 @@
#include "stdafx.h"
#include "cellCamera.h"
#include "Emu/emu_callbacks.h"
#include "Emu/System.h"
#include "Emu/system_config.h"
#include "Emu/Cell/PPUModule.h"
@@ -505,10 +504,8 @@ error_code cellCameraInit()
return CELL_OK;
}
error_code cellCameraEnd(ppu_thread& ppu)
error_code cellCameraEnd()
{
ppu.state += cpu_flag::wait;
cellCamera.todo("cellCameraEnd()");
auto& g_camera = g_fxo->get<camera_thread>();
@@ -573,7 +570,7 @@ error_code cellCameraOpenAsync()
return CELL_OK;
}
error_code cellCameraOpenEx(ppu_thread& ppu, s32 dev_num, vm::ptr<CellCameraInfoEx> info)
error_code cellCameraOpenEx(s32 dev_num, vm::ptr<CellCameraInfoEx> info)
{
cellCamera.todo("cellCameraOpenEx(dev_num=%d, info=*0x%x)", dev_num, info);
@@ -624,8 +621,6 @@ error_code cellCameraOpenEx(ppu_thread& ppu, s32 dev_num, vm::ptr<CellCameraInfo
const auto vbuf_size = get_video_buffer_size(*info);
ppu.state += cpu_flag::wait;
std::lock_guard lock(g_camera.mutex);
// TODO: find out if the buffers are also checked for nullptr
@@ -671,10 +666,8 @@ error_code cellCameraOpenPost()
return CELL_OK;
}
error_code cellCameraClose(ppu_thread& ppu, s32 dev_num)
error_code cellCameraClose(s32 dev_num)
{
ppu.state += cpu_flag::wait;
cellCamera.notice("cellCameraClose(dev_num=%d)", dev_num);
if (error_code error = check_init_and_open(dev_num))
@@ -701,19 +694,14 @@ error_code cellCameraClose(ppu_thread& ppu, s32 dev_num)
if (g_camera.info.buffer)
{
vm::dealloc(g_camera.info.buffer.addr(), vm::main);
g_camera.info.buffer = vm::null;
}
if (g_camera.info.pbuf[0])
{
vm::dealloc(g_camera.info.pbuf[0].addr(), vm::main);
g_camera.info.pbuf[0] = vm::null;
}
if (g_camera.info.pbuf[1])
{
vm::dealloc(g_camera.info.pbuf[1].addr(), vm::main);
g_camera.info.pbuf[1] = vm::null;
}
g_camera.close_camera();
@@ -1419,7 +1407,7 @@ error_code cellCameraReadEx(s32 dev_num, vm::ptr<CellCameraReadEx> read)
u64 frame_number{};
u64 bytes_read{};
if (!g_camera.get_camera_frame(g_camera.info.buffer ? g_camera.info.buffer.get_ptr() : nullptr, width, height, frame_number, bytes_read))
if (!g_camera.get_camera_frame(g_camera.info.buffer.get_ptr(), width, height, frame_number, bytes_read))
{
return CELL_CAMERA_ERROR_DEVICE_NOT_FOUND;
}
@@ -1717,20 +1705,20 @@ void camera_context::operator()()
{
if (auto queue = lv2_event_queue::find(key))
{
constexpr u64 camera_id = 0;
u64 data2 = 0;
u64 data3 = 0;
if (read_mode.load() == CELL_CAMERA_READ_DIRECT)
{
const u64 image_data_size = static_cast<u64>(info.bytesize);
const u64 camera_id = 0;
data2 = image_data_size << 32 | buffer_number << 16 | camera_id;
data3 = get_guest_system_time() - start_timestamp_us; // timestamp
}
else // CELL_CAMERA_READ_FUNCCALL, also default
{
data2 = camera_id;
data2 = 0; // device id (always 0)
data3 = 0; // unused
}
@@ -1771,7 +1759,7 @@ bool camera_context::open_camera()
Emu.BlockingCallFromMainThread([this]()
{
handler.reset();
handler = g_emu_callbacks.get_camera_handler();
handler = Emu.GetCallbacks().get_camera_handler();
if (handler)
{
handler->open_camera();
@@ -1853,19 +1841,14 @@ void camera_context::reset_state()
if (info.buffer)
{
vm::dealloc(info.buffer.addr(), vm::main);
info.buffer = vm::null;
}
if (info.pbuf[0])
{
vm::dealloc(info.pbuf[0].addr(), vm::main);
info.pbuf[0] = vm::null;
}
if (info.pbuf[1])
{
vm::dealloc(info.pbuf[1].addr(), vm::main);
info.pbuf[1] = vm::null;
}
std::scoped_lock lock(mutex_notify_data_map);
@@ -1998,7 +1981,7 @@ bool camera_context::on_handler_state(camera_handler_base::camera_handler_state
{
if (!is_attached)
{
cellCamera.warning("Camera handler not attached (state=%d). Sending attach event...", static_cast<int>(state));
cellCamera.warning("Camera handler not attached. Sending attach event...", static_cast<int>(state));
is_attached = true;
is_attached_dirty = true;
}
+23 -49
View File
@@ -1,6 +1,5 @@
#include "stdafx.h"
#include "Emu/localized_string.h"
#include "Emu/emu_callbacks.h"
#include "Emu/System.h"
#include "Emu/system_utils.hpp"
#include "Emu/VFS.h"
@@ -19,7 +18,6 @@
#include "Utilities/StrUtil.h"
#include "util/init_mutex.hpp"
#include "util/asm.hpp"
#include "util/cctype.hpp"
#include "Crypto/utils.h"
#include <span>
@@ -188,18 +186,6 @@ struct content_permission final
}
};
// Content directory of the last cellGameDataCheckCreate2() call, measured by cellGameDataGetSizeKB()
// A game may check several different directories: Rock Band 2 checks its own game data and then Rock Band's
// in order to import its songs, so the size always refers to the dirName of the check which asked for it
struct game_data_check final
{
shared_mutex mutex; // Checks may be issued from more than one thread of the game
std::string dir; // "/dev_hdd0/game/" + dirName, empty until the first check
void set_dir(std::string_view path) { std::lock_guard lock(mutex); dir = path; }
std::string get_dir() { reader_lock lock(mutex); return dir; }
};
template<>
void fmt_class_string<content_permission::check_mode>::format(std::string& out, u64 arg)
{
@@ -242,26 +228,26 @@ static bool check_system_ver(vm::cptr<char> systemVersion)
return (
systemVersion &&
std::strlen(systemVersion.get_ptr()) == 7 &&
utils::isdigit(systemVersion[0]) &&
utils::isdigit(systemVersion[1]) &&
std::isdigit(systemVersion[0]) &&
std::isdigit(systemVersion[1]) &&
systemVersion[2] == '.' &&
utils::isdigit(systemVersion[3]) &&
utils::isdigit(systemVersion[4]) &&
utils::isdigit(systemVersion[5]) &&
utils::isdigit(systemVersion[6])
std::isdigit(systemVersion[3]) &&
std::isdigit(systemVersion[4]) &&
std::isdigit(systemVersion[5]) &&
std::isdigit(systemVersion[6])
);
}
disc_change_manager::disc_change_manager()
{
g_emu_callbacks.enable_disc_eject(false);
g_emu_callbacks.enable_disc_insert(false);
Emu.GetCallbacks().enable_disc_eject(false);
Emu.GetCallbacks().enable_disc_insert(false);
}
disc_change_manager::~disc_change_manager()
{
g_emu_callbacks.enable_disc_eject(false);
g_emu_callbacks.enable_disc_insert(false);
Emu.GetCallbacks().enable_disc_eject(false);
Emu.GetCallbacks().enable_disc_insert(false);
}
error_code disc_change_manager::register_callbacks(vm::ptr<CellGameDiscEjectCallback> func_eject, vm::ptr<CellGameDiscInsertCallback> func_insert)
@@ -278,8 +264,8 @@ error_code disc_change_manager::register_callbacks(vm::ptr<CellGameDiscEjectCall
state = is_disc_mounted ? eject_state::inserted : eject_state::ejected;
}
g_emu_callbacks.enable_disc_eject(!!func_eject && is_disc_mounted);
g_emu_callbacks.enable_disc_insert(!!func_insert && !is_disc_mounted);
Emu.GetCallbacks().enable_disc_eject(!!func_eject && is_disc_mounted);
Emu.GetCallbacks().enable_disc_insert(!!func_insert && !is_disc_mounted);
return CELL_OK;
}
@@ -291,8 +277,8 @@ error_code disc_change_manager::unregister_callbacks()
eject_callback = vm::null;
insert_callback = vm::null;
g_emu_callbacks.enable_disc_eject(false);
g_emu_callbacks.enable_disc_insert(false);
Emu.GetCallbacks().enable_disc_eject(false);
Emu.GetCallbacks().enable_disc_insert(false);
};
if (is_inserting)
@@ -323,7 +309,7 @@ void disc_change_manager::eject_disc()
}
state = eject_state::busy;
g_emu_callbacks.enable_disc_eject(false);
Emu.GetCallbacks().enable_disc_eject(false);
ensure(eject_callback);
@@ -340,7 +326,7 @@ void disc_change_manager::eject_disc()
dcm.state = eject_state::ejected;
// Re-enable disc insertion only if the callback is still registered
g_emu_callbacks.enable_disc_insert(!!dcm.insert_callback);
Emu.GetCallbacks().enable_disc_insert(!!dcm.insert_callback);
return CELL_OK;
});
@@ -359,7 +345,7 @@ void disc_change_manager::insert_disc(u32 disc_type, std::string title_id)
}
state = eject_state::busy;
g_emu_callbacks.enable_disc_insert(false);
Emu.GetCallbacks().enable_disc_insert(false);
ensure(insert_callback);
@@ -385,7 +371,7 @@ void disc_change_manager::insert_disc(u32 disc_type, std::string title_id)
dcm.state = eject_state::inserted;
// Re-enable disc ejection only if the callback is still registered
g_emu_callbacks.enable_disc_eject(!!dcm.eject_callback);
Emu.GetCallbacks().enable_disc_eject(!!dcm.eject_callback);
dcm.is_inserting = false;
@@ -705,14 +691,11 @@ error_code cellGameDataGetSizeKB(ppu_thread& ppu, vm::ptr<u32> size)
return CELL_GAMEDATA_ERROR_PARAM;
}
const std::string content_dir = g_fxo->get<game_data_check>().get_dir();
lv2_obj::sleep(ppu);
const u64 start_sleep = ppu.start_time;
// Until the first check there is no dirName to go by: the booted directory is the game data itself for an HDD game
const std::string local_dir = vfs::get(content_dir.empty() ? Emu.GetDir() : content_dir);
const std::string local_dir = vfs::get(Emu.GetDir());
const auto dirsz = fs::get_dir_size(local_dir, 1024);
@@ -724,15 +707,11 @@ error_code cellGameDataGetSizeKB(ppu_thread& ppu, vm::ptr<u32> size)
{
const auto error = fs::g_tls_error;
if (!fs::exists(local_dir))
if (fs::exists(local_dir))
{
// The content directory is only created once the status callback has returned
ppu.check_state();
*size = 0;
return CELL_OK;
cellGame.error("cellGameDataGetSizeKB(): Unknown failure on calculating directory '%s' size (%s)", local_dir, error);
}
cellGame.error("cellGameDataGetSizeKB(): Unknown failure on calculating directory '%s' size (%s)", local_dir, error);
return CELL_GAMEDATA_ERROR_FAILURE;
}
@@ -1130,9 +1109,6 @@ error_code cellGameDataCheckCreate2(ppu_thread& ppu, u32 version, vm::cptr<char>
strcpy_trunc(cbGet->getParam.titleLang[i], psf::get_string(sfo, fmt::format("TITLE_%02d", i)));
}
// The status callback may ask for the size of this directory through cellGameDataGetSizeKB()
g_fxo->get<game_data_check>().set_dir(dir);
lv2_sleep(5000, &ppu);
funcStat(ppu, cbResult, cbGet, cbSet);
@@ -1337,7 +1313,7 @@ error_code cellGameDeleteGameData(vm::cptr<char> dirName)
{
cellGame.warning("cellGameDeleteGameData(dirName=%s)", dirName);
if (!dirName || sysutil_check_name_string(dirName.get_ptr(), 1, CELL_GAME_DIRNAME_SIZE) != 0)
if (!dirName)
{
return CELL_GAME_ERROR_PARAM;
}
@@ -1349,9 +1325,7 @@ error_code cellGameDeleteGameData(vm::cptr<char> dirName)
auto remove_gd = [&]() -> error_code
{
const std::string_view boot_dir = fmt::trim_back_sv(Emu.GetDir(), fs::delim);
if (Emu.GetCat() == "GD" && boot_dir.substr(boot_dir.find_last_of(fs::delim) + 1) == vfs::escape(name))
if (Emu.GetCat() == "GD" && Emu.GetDir().substr(Emu.GetDir().find_last_of('/') + 1) == vfs::escape(name))
{
// Boot patch cannot delete its own directory
return CELL_GAME_ERROR_NOTSUPPORTED;
+1 -4
View File
@@ -3,8 +3,6 @@
#include "Emu/IdManager.h"
#include "Emu/System.h"
#include "Utilities/StrUtil.h"
#include "cellGame.h"
LOG_CHANNEL(cellGameExec);
@@ -110,8 +108,7 @@ error_code cellGameGetBootGameInfo(vm::ptr<u32> type, vm::ptr<char> dirName, vm:
if (source_type == CELL_GAME_GAMETYPE_HDD)
{
const std::string_view boot_dir = fmt::trim_back_sv(Emu.GetDir(), fs::delim);
const std::string dir_name{boot_dir.substr(boot_dir.find_last_of(fs::delim) + 1)};
const std::string dir_name = Emu.GetDir();
if (dir_name.size() >= CELL_GAME_DIRNAME_SIZE)
{
+1 -3
View File
@@ -389,8 +389,6 @@ u32 g_defaultCommandBufferBegin, g_defaultCommandBufferFragmentCount;
// Called by cellGcmInit
error_code _cellGcmInitBody(ppu_thread& ppu, vm::pptr<CellGcmContextData> context, u32 cmdSize, u32 ioSize, u32 ioAddress)
{
ppu.state += cpu_flag::wait;
cellGcmSys.warning("_cellGcmInitBody(context=**0x%x, cmdSize=0x%x, ioSize=0x%x, ioAddress=0x%x)", context, cmdSize, ioSize, ioAddress);
auto& gcm_cfg = g_fxo->get<gcm_config>();
@@ -1105,7 +1103,7 @@ error_code cellGcmMapMainMemory(ppu_thread& ppu, u32 ea, u32 size, vm::ptr<u32>
std::lock_guard lock(gcm_cfg.gcmio_mutex);
// Use the offset table to find the next free io address
for (u32 io = 0, end = (rsx::get_current_renderer()->main_mem_size - gcm_cfg.reserved_size) >> 20, unmap_count = 1; unmap_count + io <= end; unmap_count++)
for (u32 io = 0, end = (rsx::get_current_renderer()->main_mem_size - gcm_cfg.reserved_size) >> 20, unmap_count = 1; io < end; unmap_count++)
{
if (gcm_cfg.offsetTable.eaAddress[io + unmap_count - 1] > 0xBFF)
{
+81 -102
View File
@@ -323,7 +323,7 @@ public:
{
const auto& pad = ::at32(handler->GetPads(), pad_num(i));
const bool connected = pad && pad->is_connected() && !pad->is_copilot() && i < attribute.max_connect;
const bool is_real_move = g_cfg.io.move != move_handler::real || (pad && pad->m_pad_handler == pad_handler::move);
const bool is_real_move = g_cfg.io.move != move_handler::real || pad->m_pad_handler == pad_handler::move;
update_connection(i, connected && is_real_move);
}
@@ -1572,24 +1572,18 @@ public:
return true;
}
bool set_image(vm::cptr<void> buf)
bool set_image(u32 addr)
{
if (!buf)
if (!addr)
return false;
auto& g_camera = g_fxo->get<camera_thread>();
std::lock_guard lock(g_camera.mutex);
m_camera_info = g_camera.info;
if (m_camera_info.buffer.addr() != buf.addr() && m_camera_info.pbuf[0].addr() != buf.addr() && m_camera_info.pbuf[1].addr() != buf.addr())
if (m_camera_info.buffer.addr() != addr && m_camera_info.pbuf[0].addr() != addr && m_camera_info.pbuf[1].addr() != addr)
{
// The game passes its own buffer. Let's just ignore this and log a warning. We use our own camera buffer for tracking for now anyway.
cellGem.warning("gem_tracker: unexpected image address: addr=0x%x, expected one of: 0x%x, 0x%x, 0x%x", buf.addr(), m_camera_info.buffer.addr(), m_camera_info.pbuf[0].addr(), m_camera_info.pbuf[1].addr());
}
if (!m_camera_info.buffer)
{
cellGem.error("gem_tracker: camer buffer not set");
cellGem.error("gem_tracker: unexpected image address: addr=0x%x, expected one of: 0x%x, 0x%x, 0x%x", addr, m_camera_info.buffer.addr(), m_camera_info.pbuf[0].addr(), m_camera_info.pbuf[1].addr());
return false;
}
@@ -1776,10 +1770,10 @@ static bool check_gem_num(u32 gem_num)
return gem_num < CELL_GEM_MAX_NUM;
}
static inline void draw_overlay_cursor(u32 gem_num, const gem_config::gem_controller&, f32 x_pos, f32 y_pos)
static inline void draw_overlay_cursor(u32 gem_num, const gem_config::gem_controller&, s32 x_pos, s32 y_pos, s32 x_max, s32 y_max)
{
const s16 x = static_cast<s16>(x_pos * rsx::overlays::overlay::virtual_width);
const s16 y = static_cast<s16>(y_pos * rsx::overlays::overlay::virtual_height);
const s16 x = static_cast<s16>(x_pos / (x_max / static_cast<f32>(rsx::overlays::overlay::virtual_width)));
const s16 y = static_cast<s16>(y_pos / (y_max / static_cast<f32>(rsx::overlays::overlay::virtual_height)));
// Note: We shouldn't use sphere_rgb here. The game will set it to black in many cases.
const gem_config_data::gem_color& rgb = gem_config_data::gem_color::get_default_color(gem_num);
@@ -1788,24 +1782,30 @@ static inline void draw_overlay_cursor(u32 gem_num, const gem_config::gem_contro
rsx::overlays::set_cursor(rsx::overlays::cursor_offset::cell_gem + gem_num, x, y, color, 2'000'000, false);
}
static inline void pos_to_gem_image_state(u32 gem_num, gem_config::gem_controller& controller, vm::ptr<CellGemImageState>& gem_image_state, f32 x_pos, f32 y_pos)
static inline void pos_to_gem_image_state(u32 gem_num, gem_config::gem_controller& controller, vm::ptr<CellGemImageState>& gem_image_state, s32 x_pos, s32 y_pos, s32 x_max, s32 y_max)
{
const auto& shared_data = g_fxo->get<gem_camera_shared>();
if (x_max <= 0) x_max = shared_data.width;
if (y_max <= 0) y_max = shared_data.height;
// Move the cursor out of the screen if we're at the screen border (Time Crisis 4 needs this)
if (x_pos <= 0) x_pos -= 0.1f; else if (x_pos >= 1.0f) x_pos += 0.1f;
if (y_pos <= 0) y_pos -= 0.1f; else if (y_pos >= 1.0f) y_pos += 0.1f;
if (x_pos <= 0) x_pos -= x_max / 10; else if (x_pos >= x_max) x_pos += x_max / 10;
if (y_pos <= 0) y_pos -= y_max / 10; else if (y_pos >= y_max) y_pos += y_max / 10;
const f32 scaling_width = x_max / static_cast<f32>(shared_data.width);
const f32 scaling_height = y_max / static_cast<f32>(shared_data.height);
const f32 mmPerPixel = controller.radius <= 0.0f ? 0.0f : (CELL_GEM_SPHERE_RADIUS_MM / controller.radius);
// Image coordinates in pixels
const f32 image_x = x_pos * shared_data.width;
const f32 image_y = y_pos * shared_data.height;
const f32 image_x = static_cast<f32>(x_pos) / scaling_width;
const f32 image_y = static_cast<f32>(y_pos) / scaling_height;
// Centered image coordinates in pixels
const f32 centered_x = image_x - (shared_data.width / 2.f);
const f32 centered_y = (shared_data.height / 2.f) - image_y; // Image coordinates increase downwards, so we have to invert this
// Camera coordinates in mm (centered, so it's the same as world coordinates)
const f32 mmPerPixel = controller.radius <= 0.0f ? 0.0f : (CELL_GEM_SPHERE_RADIUS_MM / controller.radius);
const f32 camera_x = centered_x * mmPerPixel;
const f32 camera_y = centered_y * mmPerPixel;
@@ -1821,12 +1821,12 @@ static inline void pos_to_gem_image_state(u32 gem_num, gem_config::gem_controlle
if (g_cfg.io.move != move_handler::real)
{
// Let's say the sphere is not visible if the position is at the edge of the screen
controller.radius_valid = x_pos > 0.0f && x_pos < 1.0f && y_pos > 0.0f && y_pos < 1.0f;
controller.radius_valid = x_pos > 0 && x_pos < x_max && y_pos > 0 && y_pos < y_max;
}
if (g_cfg.io.show_move_cursor)
{
draw_overlay_cursor(gem_num, controller, x_pos, y_pos);
draw_overlay_cursor(gem_num, controller, x_pos, y_pos, x_max, y_max);
}
if (g_cfg.io.paint_move_spheres)
@@ -1835,17 +1835,24 @@ static inline void pos_to_gem_image_state(u32 gem_num, gem_config::gem_controlle
}
}
static inline void pos_to_gem_state(u32 gem_num, gem_config::gem_controller& controller, vm::ptr<CellGemState>& gem_state, f32 x_pos, f32 y_pos, ps_move_data& move_data)
static inline void pos_to_gem_state(u32 gem_num, gem_config::gem_controller& controller, vm::ptr<CellGemState>& gem_state, s32 x_pos, s32 y_pos, s32 x_max, s32 y_max, ps_move_data& move_data)
{
const auto& shared_data = g_fxo->get<gem_camera_shared>();
if (x_max <= 0) x_max = shared_data.width;
if (y_max <= 0) y_max = shared_data.height;
// Move the cursor out of the screen if we're at the screen border (Time Crisis 4 needs this)
if (x_pos <= 0.0f) x_pos -= 0.1f; else if (x_pos >= 1.0f) x_pos += 0.1f;
if (y_pos <= 0.0f) y_pos -= 0.1f; else if (y_pos >= 1.0f) y_pos += 0.1f;
if (x_pos <= 0) x_pos -= x_max / 10; else if (x_pos >= x_max) x_pos += x_max / 10;
if (y_pos <= 0) y_pos -= y_max / 10; else if (y_pos >= y_max) y_pos += y_max / 10;
const f32 scaling_width = x_max / static_cast<f32>(shared_data.width);
const f32 scaling_height = y_max / static_cast<f32>(shared_data.height);
const f32 mmPerPixel = controller.radius <= 0.0f ? 0.0f : (CELL_GEM_SPHERE_RADIUS_MM / controller.radius);
// Image coordinates in pixels
const f32 image_x = x_pos * shared_data.width;
const f32 image_y = y_pos * shared_data.height;
const f32 image_x = static_cast<f32>(x_pos) / scaling_width;
const f32 image_y = static_cast<f32>(y_pos) / scaling_height;
// Half of the camera image
const f32 half_width = shared_data.width / 2.f;
@@ -1856,7 +1863,6 @@ static inline void pos_to_gem_state(u32 gem_num, gem_config::gem_controller& con
const f32 centered_y = half_height - image_y; // Image coordinates increase downwards, so we have to invert this
// Camera coordinates in mm (centered, so it's the same as world coordinates)
const f32 mmPerPixel = controller.radius <= 0.0f ? 0.0f : (CELL_GEM_SPHERE_RADIUS_MM / controller.radius);
const f32 camera_x = centered_x * mmPerPixel;
const f32 camera_y = centered_y * mmPerPixel;
@@ -1895,7 +1901,7 @@ static inline void pos_to_gem_state(u32 gem_num, gem_config::gem_controller& con
gem_state->quat[3] = quat.w();
// Calculate handle position based on our world coordinate and the current orientation
constexpr ps_move_data::vect<3> offset_local_mm({0.f, 0.f, 45.f}); // handle is ~45 mm below sphere
constexpr ps_move_data::vect<3> offset_local_mm({0.f, 0.f, -45.f}); // handle is ~45 mm below sphere
const ps_move_data::vect<3> offset_world = ps_move_data::rotate_vector(quat, offset_local_mm);
gem_state->handle_pos[0] = gem_state->pos[0] - offset_world.x(); // Flip x offset
@@ -1923,12 +1929,12 @@ static inline void pos_to_gem_state(u32 gem_num, gem_config::gem_controller& con
if (g_cfg.io.move != move_handler::real)
{
// Let's say the sphere is not visible if the position is at the edge of the screen
controller.radius_valid = x_pos > 0.0f && x_pos < 1.0f && y_pos > 0.0f && y_pos < 1.0f;
controller.radius_valid = x_pos > 0 && x_pos < x_max && y_pos > 0 && y_pos < y_max;
}
if (g_cfg.io.show_move_cursor)
{
draw_overlay_cursor(gem_num, controller, x_pos, y_pos);
draw_overlay_cursor(gem_num, controller, x_pos, y_pos, x_max, y_max);
}
if (g_cfg.io.paint_move_spheres)
@@ -2014,10 +2020,13 @@ static void ds3_input_to_pad(const u32 gem_num, be_t<u16>& digital_buttons, be_t
}
}
static inline void ds3_get_stick_values(u32 gem_num, const std::shared_ptr<Pad>& pad, f32& x_pos, f32& y_pos)
constexpr u16 ds3_max_x = 255;
constexpr u16 ds3_max_y = 255;
static inline void ds3_get_stick_values(u32 gem_num, const std::shared_ptr<Pad>& pad, s32& x_pos, s32& y_pos)
{
x_pos = 0.0f;
y_pos = 0.0f;
x_pos = 0;
y_pos = 0;
const auto& cfg = ::at32(g_cfg_gem_fake.players, gem_num);
cfg->handle_input(pad, true, [&](const auto& value, bool& /*abort*/)
@@ -2027,8 +2036,8 @@ static inline void ds3_get_stick_values(u32 gem_num, const std::shared_ptr<Pad>&
switch (value.btn)
{
case gem_btn::x_axis: x_pos = value.value / 255.0f; break;
case gem_btn::y_axis: y_pos = value.value / 255.0f; break;
case gem_btn::x_axis: x_pos = value.value; break;
case gem_btn::y_axis: y_pos = value.value; break;
default: break;
}
});
@@ -2052,16 +2061,16 @@ static void ds3_pos_to_gem_state(u32 gem_num, gem_config::gem_controller& contro
return;
}
f32 ds3_pos_x, ds3_pos_y;
s32 ds3_pos_x, ds3_pos_y;
ds3_get_stick_values(gem_num, pad, ds3_pos_x, ds3_pos_y);
if constexpr (std::is_same_v<T, vm::ptr<CellGemState>>)
{
pos_to_gem_state(gem_num, controller, gem_state, ds3_pos_x, ds3_pos_y, pad->move_data);
pos_to_gem_state(gem_num, controller, gem_state, ds3_pos_x, ds3_pos_y, ds3_max_x, ds3_max_y, pad->move_data);
}
else if constexpr (std::is_same_v<T, vm::ptr<CellGemImageState>>)
{
pos_to_gem_image_state(gem_num, controller, gem_state, ds3_pos_x, ds3_pos_y);
pos_to_gem_image_state(gem_num, controller, gem_state, ds3_pos_x, ds3_pos_y, ds3_max_x, ds3_max_y);
}
}
@@ -2101,11 +2110,11 @@ static void ps_move_pos_to_gem_state(u32 gem_num, gem_config::gem_controller& co
gem_state->angaccel[i] = pad->move_data.angaccel_world[i];
}
pos_to_gem_state(gem_num, controller, gem_state, info.x_pos, info.y_pos, pad->move_data);
pos_to_gem_state(gem_num, controller, gem_state, info.x_pos, info.y_pos, info.x_max, info.y_max, pad->move_data);
}
else if constexpr (std::is_same_v<T, vm::ptr<CellGemImageState>>)
{
pos_to_gem_image_state(gem_num, controller, gem_state, info.x_pos, info.y_pos);
pos_to_gem_image_state(gem_num, controller, gem_state, info.x_pos, info.y_pos, info.x_max, info.y_max);
}
}
@@ -2151,12 +2160,12 @@ static const std::unordered_map<gem_btn, u16> ext_btn_indices =
{ gem_btn::racing_wheel_l2, 1 },
{ gem_btn::racing_wheel_r2, 2 },
{ gem_btn::racing_wheel_paddle_l, 3 },
{ gem_btn::racing_wheel_paddle_r, 3 },
{ gem_btn::racing_wheel_paddle_r, 4 },
{ gem_btn::combo_racing_wheel_throttle, 0 },
{ gem_btn::combo_racing_wheel_l2, 1 },
{ gem_btn::combo_racing_wheel_r2, 2 },
{ gem_btn::combo_racing_wheel_paddle_l, 3 },
{ gem_btn::combo_racing_wheel_paddle_r, 3 },
{ gem_btn::combo_racing_wheel_paddle_r, 4 },
};
static u32 ext_device_id(gem_ext_id id)
@@ -2267,23 +2276,23 @@ static void input_to_ext(u32 external_device_id, CellGemExtPortData& ext, std::s
{
switch (value.btn)
{
case gem_btn::racing_wheel_throttle:
case gem_btn::racing_wheel_l2:
case gem_btn::racing_wheel_r2:
case gem_btn::combo_racing_wheel_throttle:
case gem_btn::combo_racing_wheel_l2:
case gem_btn::combo_racing_wheel_r2:
ext.custom[::at32(ext_btn_indices, value.btn)] = static_cast<u8>(value.value);
break;
case gem_btn::racing_wheel_paddle_l:
case gem_btn::racing_wheel_paddle_r:
case gem_btn::combo_racing_wheel_paddle_l:
case gem_btn::combo_racing_wheel_paddle_r:
ext.custom[::at32(ext_btn_indices, value.btn)] |= ::at32(ext_btn_map, value.btn);
break;
case gem_btn::racing_wheel_d_pad_up:
case gem_btn::racing_wheel_d_pad_right:
case gem_btn::racing_wheel_d_pad_down:
case gem_btn::racing_wheel_d_pad_left:
case gem_btn::combo_racing_wheel_d_pad_up:
case gem_btn::combo_racing_wheel_d_pad_right:
case gem_btn::combo_racing_wheel_d_pad_down:
case gem_btn::combo_racing_wheel_d_pad_left:
ext.digital1 |= ::at32(ext_btn_map, value.btn);
break;
case gem_btn::racing_wheel_l1:
case gem_btn::racing_wheel_r1:
case gem_btn::combo_racing_wheel_l1:
case gem_btn::combo_racing_wheel_r1:
ext.digital2 |= ::at32(ext_btn_map, value.btn);
break;
default:
@@ -2637,11 +2646,11 @@ static void mouse_pos_to_gem_state(u32 mouse_no, gem_config::gem_controller& con
if constexpr (std::is_same_v<T, vm::ptr<CellGemState>>)
{
ps_move_data& move_data = ::at32(g_fxo->get<gem_config>().fake_move_data, mouse_no);
pos_to_gem_state(mouse_no, controller, gem_state, mouse.x_pos, mouse.y_pos, move_data);
pos_to_gem_state(mouse_no, controller, gem_state, mouse.x_pos, mouse.y_pos, mouse.x_max, mouse.y_max, move_data);
}
else if constexpr (std::is_same_v<T, vm::ptr<CellGemImageState>>)
{
pos_to_gem_image_state(mouse_no, controller, gem_state, mouse.x_pos, mouse.y_pos);
pos_to_gem_image_state(mouse_no, controller, gem_state, mouse.x_pos, mouse.y_pos, mouse.x_max, mouse.y_max);
}
}
@@ -2692,23 +2701,25 @@ static void gun_pos_to_gem_state(u32 gem_no, gem_config::gem_controller& control
if (!gem_state || !is_input_allowed())
return;
f32 x_pos, y_pos;
int x_pos, y_pos, x_max, y_max;
{
gun_thread& gun = g_fxo->get<gun_thread>();
std::scoped_lock lock(gun.handler.mutex);
x_pos = gun.handler.get_axis_x(gem_no);
y_pos = gun.handler.get_axis_y(gem_no);
x_max = gun.handler.get_axis_x_max(gem_no);
y_max = gun.handler.get_axis_y_max(gem_no);
}
if constexpr (std::is_same_v<T, vm::ptr<CellGemState>>)
{
ps_move_data& move_data = ::at32(g_fxo->get<gem_config>().fake_move_data, gem_no);
pos_to_gem_state(gem_no, controller, gem_state, x_pos, y_pos, move_data);
pos_to_gem_state(gem_no, controller, gem_state, x_pos, y_pos, x_max, y_max, move_data);
}
else if constexpr (std::is_same_v<T, vm::ptr<CellGemImageState>>)
{
pos_to_gem_image_state(gem_no, controller, gem_state, x_pos, y_pos);
pos_to_gem_image_state(gem_no, controller, gem_state, x_pos, y_pos, x_max, y_max);
}
}
#endif
@@ -3068,7 +3079,7 @@ error_code cellGemGetAccelerometerPositionInDevice(u32 gem_num, vm::ptr<f32> pos
error_code cellGemGetAllTrackableHues(vm::ptr<u8> hues)
{
cellGem.todo("cellGemGetAllTrackableHues(hues=*0x%x)", hues);
cellGem.todo("cellGemGetAllTrackableHues(hues=*0x%x)");
auto& gem = g_fxo->get<gem_config>();
@@ -3576,19 +3587,12 @@ error_code cellGemHSVtoRGB(f32 h, f32 s, f32 v, vm::ptr<f32> r, vm::ptr<f32> g,
{
cellGem.warning("cellGemHSVtoRGB(h=%f, s=%f, v=%f, r=*0x%x, g=*0x%x, b=*0x%x)", h, s, v, r, g, b);
if (!r || !g || !b)
if (s < 0.0f || s > 1.0f || v < 0.0f || v > 1.0f || !r || !g || !b)
{
return CELL_GEM_ERROR_INVALID_PARAMETER;
}
h = std::fmod(h, 360.0f);
s = std::clamp(s, 0.0f, 1.0f);
v = std::clamp(v, 0.0f, 1.0f);
if (h < 0.0)
{
h += 360.0f;
}
h = std::clamp(h, 0.0f, 360.0f);
const f32 c = v * s;
const f32 x = c * (1.0f - fabs(fmod(h / 60.0f, 2.0f) - 1.0f));
@@ -3629,9 +3633,9 @@ error_code cellGemHSVtoRGB(f32 h, f32 s, f32 v, vm::ptr<f32> r, vm::ptr<f32> g,
b_tmp = x;
}
*r = std::clamp(r_tmp + m, 0.0f, 1.0f);
*g = std::clamp(g_tmp + m, 0.0f, 1.0f);
*b = std::clamp(b_tmp + m, 0.0f, 1.0f);
*r = (r_tmp + m) * 255.0f;
*g = (g_tmp + m) * 255.0f;
*b = (b_tmp + m) * 255.0f;
return CELL_OK;
}
@@ -3993,15 +3997,9 @@ error_code cellGemSetRumble(u32 gem_num, u8 rumble)
return CELL_OK;
}
error_code cellGemSetYaw(u32 gem_num, v128 z_direction)
error_code cellGemSetYaw(u32 gem_num, vm::ptr<f32> z_direction)
{
// Unpack vector argument
const f32 z_direction_x = z_direction.fr[0];
const f32 z_direction_y = z_direction.fr[1];
const f32 z_direction_z = z_direction.fr[2];
const f32 z_direction_w = z_direction.fr[3];
cellGem.warning("cellGemSetYaw(gem_num=%d, z_direction_x=%f, z_direction_y=%f, z_direction_z=%f, z_direction_w=%f)", gem_num, z_direction_x, z_direction_y, z_direction_z, z_direction_w);
cellGem.todo("cellGemSetYaw(gem_num=%d, z_direction=*0x%x)", gem_num, z_direction);
auto& gem = g_fxo->get<gem_config>();
@@ -4012,31 +4010,12 @@ error_code cellGemSetYaw(u32 gem_num, v128 z_direction)
return CELL_GEM_ERROR_UNINITIALIZED;
}
if (!check_gem_num(gem_num))
if (!z_direction || !check_gem_num(gem_num))
{
return CELL_GEM_ERROR_INVALID_PARAMETER;
}
if (g_cfg.io.move != move_handler::real)
{
return CELL_OK;
}
std::lock_guard pad_lock(pad::g_pad_mutex);
const auto handler = pad::get_pad_thread();
const auto& pad = ::at32(handler->GetPads(), pad_num(gem_num));
if (pad && pad->m_pad_handler == pad_handler::move && !pad->is_copilot())
{
// z_direction is the direction of the controller's z axis (sphere -> handle) in world coordinates.
// This function is usually used when the game wants to re-orient the ps move towards the camera, e.g. during calibration or as a surrogate for it.
// So far we've seen:
// A: (0,0,1,0): The controller points straight at the camera along the camera axis. This is our default orientation.
// B: The current sphere position (CellGemState.pos) while pointing at the camera.
// This is equal to A if the controller is on the camera axis. Otherwise the correct yaw would be atan2(x, z).
// For now we simply reset the orientation (including pitch and roll) instead of only adjusting the yaw.
pad->move_data.orientation_reset_requested = true;
}
// TODO
return CELL_OK;
}
@@ -4197,7 +4176,7 @@ error_code cellGemUpdateStart(vm::cptr<void> camera_frame, u64 timestamp)
gem.camera_frame = camera_frame.addr();
const bool image_set = tracker.set_image(camera_frame);
const bool image_set = tracker.set_image(gem.camera_frame);
tracker.wake_up_tracker();
+9 -10
View File
@@ -502,8 +502,8 @@ error_code cellGifDecDecodeData(vm::ptr<GifDecoder> mainHandle, vm::cptr<GifStre
}
//Decode GIF file. (TODO: Is there any faster alternative? Can we do it without external libraries?)
int width = 0, height = 0, actual_components = 0;
auto image = std::unique_ptr<u8, decltype(&::free)>
int width, height, actual_components;
auto image = std::unique_ptr<unsigned char,decltype(&::free)>
(
stbi_load_from_memory(gif.get(), ::narrow<int>(fileSize), &width, &height, &actual_components, 4),
&::free
@@ -515,7 +515,6 @@ error_code cellGifDecDecodeData(vm::ptr<GifDecoder> mainHandle, vm::cptr<GifStre
const int bytesPerLine = static_cast<int>(dataCtrlParam->outputBytesPerLine);
constexpr char nComponents = 4;
const u32 image_size = width * height * nComponents;
u8* src = image.get();
switch(current_outParam.outputColorSpace)
{
@@ -528,12 +527,12 @@ error_code cellGifDecDecodeData(vm::ptr<GifDecoder> mainHandle, vm::cptr<GifStre
{
const int dstOffset = i * bytesPerLine;
const int srcOffset = width * nComponents * i;
std::memcpy(&data[dstOffset], &src[srcOffset], linesize);
memcpy(&data[dstOffset], &image.get()[srcOffset], linesize);
}
}
else
{
std::memcpy(data.get_ptr(), src, image_size);
memcpy(data.get_ptr(), image.get(), image_size);
}
break;
}
@@ -550,10 +549,10 @@ error_code cellGifDecDecodeData(vm::ptr<GifDecoder> mainHandle, vm::cptr<GifStre
const int srcOffset = width * nComponents * i;
for (int j = 0; j < linesize; j += nComponents)
{
output[j + 0] = src[srcOffset + j + 3];
output[j + 1] = src[srcOffset + j + 0];
output[j + 2] = src[srcOffset + j + 1];
output[j + 3] = src[srcOffset + j + 2];
output[j + 0] = image.get()[srcOffset + j + 3];
output[j + 1] = image.get()[srcOffset + j + 0];
output[j + 2] = image.get()[srcOffset + j + 1];
output[j + 3] = image.get()[srcOffset + j + 2];
}
std::memcpy(&data[dstOffset], output.get(), linesize);
}
@@ -561,7 +560,7 @@ error_code cellGifDecDecodeData(vm::ptr<GifDecoder> mainHandle, vm::cptr<GifStre
else
{
const auto img = std::make_unique<uint[]>(image_size);
uint* source_current = reinterpret_cast<uint*>(src);
uint* source_current = reinterpret_cast<uint*>(image.get());
uint* dest_current = img.get();
for (uint i = 0; i < image_size / nComponents; i++)
{
+1 -1
View File
@@ -3702,7 +3702,7 @@ error_code cellHttpEndExternalCache()
error_code cellHttpInitExternalCache(vm::ptr<void> buf, u32 size)
{
cellHttp.todo("cellHttpInitExternalCache(buf=*0x%x, size=0x%x)", buf, size);
cellHttp.todo("cellHttpInitExternalCache(buf=*0x%x, size=0x%x)", size);
auto& man = g_fxo->get<http_manager>();
std::lock_guard lock(man.mtx);
+3 -3
View File
@@ -507,14 +507,14 @@ error_code cellHttpUtilEscapeUri(vm::ptr<char> out, u32 outSize, vm::cptr<u8> in
u32 size_needed = 0;
u32 out_pos = 0;
u32 in_size = 0;
s32 rindex = 0;
if (const u32 end = in.addr() + inSize; end && end >= in.addr())
{
in_size = inSize;
rindex = inSize;
}
for (u32 pos = 0; pos < in_size; pos++)
for (u32 pos = 0; rindex >= 0; rindex--, pos++)
{
const char c1 = in[pos];
+3 -2
View File
@@ -1158,10 +1158,11 @@ static error_code cellImeJpGetCandidateList(CellImeJpHandle hImeJpHandle, vm::pt
for (const ime_jp_manager::candidate& can : list)
{
// Copy the candidate
for (u32 i = 0; i < can.text.length(); i++)
for (u32 i = pos; i < can.text.length(); i++)
{
pCandidateString[pos++] = can.text[i];
pCandidateString[i] = can.text[i];
}
pos += ::narrow<u32>(can.text.length());
// Add null terminator
pCandidateString[pos++] = 0;
+2 -2
View File
@@ -2,8 +2,8 @@
#include "Emu/IdManager.h"
#include "Emu/System.h"
#include "Emu/Cell/PPUModule.h"
#include "Emu/Io/KeyboardHandler.h"
#include "util/cctype.hpp"
#include "cellKb.h"
error_code sys_config_start(ppu_thread& ppu);
@@ -198,7 +198,7 @@ u16 cellKbCnvRawCode(u32 arrange, u32 mkey, u32 led, u16 rawcode)
const auto get_ascii = [&](u16 raw, u16 shifted = 0, u16 altered = 0)
{
// Usually caps lock only applies uppercase to letters, but some layouts treat it as shift lock for all keys.
if ((is_shift || (is_caps_lock && (is_shift_lock || utils::isalpha(raw)))) && shifted)
if ((is_shift || (is_caps_lock && (is_shift_lock || std::isalpha(raw)))) && shifted)
{
return shifted;
}
+1 -15
View File
@@ -208,8 +208,6 @@ u32 mic_context::register_device(const std::string& device_name)
case microphone_handler::standard:
case microphone_handler::real_singstar:
case microphone_handler::rocksmith:
case microphone_handler::eye_toy:
case microphone_handler::ps_eye:
{
microphone_device& device = ::at32(mic_list, index);
device = microphone_device(g_cfg.audio.microphone_type.get());
@@ -330,8 +328,6 @@ error_code microphone_device::open_microphone(const u8 type, const u32 dsp_r, co
switch (device_type)
{
case microphone_handler::standard:
case microphone_handler::eye_toy:
case microphone_handler::ps_eye:
break;
case microphone_handler::singstar:
case microphone_handler::real_singstar:
@@ -733,8 +729,6 @@ void microphone_device::get_data(const u32 num_samples)
}
case microphone_handler::standard:
case microphone_handler::rocksmith:
case microphone_handler::eye_toy:
case microphone_handler::ps_eye:
{
constexpr u8 channel_size = bit_resolution / 8;
const usz bufsize = num_samples * sample_size;
@@ -1464,15 +1458,7 @@ error_code cellMicGetType(s32 dev_num, vm::ptr<s32> ptr_type)
return CELL_MICIN_ERROR_NOT_INIT;
// TODO: get proper type (log message is trace because of massive spam)
if (dev_num < static_cast<s32>(mic_thr.mic_list.size()))
{
const microphone_device& device = ::at32(mic_thr.mic_list, dev_num);
*ptr_type = device.get_mic_type();
}
else
{
*ptr_type = CELLMIC_TYPE_UNDEF;
}
*ptr_type = CELLMIC_TYPE_USBAUDIO; // Needed for Guitar Hero: Warriors of Rock (BLUS30487)
return CELL_OK;
}
+2 -12
View File
@@ -2,7 +2,6 @@
#include "Utilities/Thread.h"
#include "Utilities/mutex.h"
#include "Emu/system_config_types.h"
#include "alc.h"
@@ -114,8 +113,8 @@ enum CellMicType : s32
{
CELLMIC_TYPE_UNDEF = -1,
CELLMIC_TYPE_UNKNOWN = 0,
CELLMIC_TYPE_EYETOY1 = 1, // EyeToy
CELLMIC_TYPE_EYETOY2 = 2, // PS EYE
CELLMIC_TYPE_EYETOY1 = 1,
CELLMIC_TYPE_EYETOY2 = 2,
CELLMIC_TYPE_USBAUDIO = 3,
CELLMIC_TYPE_BLUETOOTH = 4,
CELLMIC_TYPE_A2DP = 5,
@@ -311,15 +310,6 @@ public:
return 1; // BE
}
}
s32 get_mic_type() const
{
switch(device_type)
{
case microphone_handler::eye_toy: return CELLMIC_TYPE_EYETOY1;
case microphone_handler::ps_eye: return CELLMIC_TYPE_EYETOY2;
default: return CELLMIC_TYPE_USBAUDIO; // Needed for Guitar Hero: Warriors of Rock (BLUS30487)
}
}
u32 read_raw(u8* buf, u32 size) { return rbuf_raw.read_bytes(buf, size); }
u32 read_dsp(u8* buf, u32 size) { return rbuf_dsp.read_bytes(buf, size); }
+1 -2
View File
@@ -1,5 +1,4 @@
#include "stdafx.h"
#include "Emu/emu_callbacks.h"
#include "Emu/System.h"
#include "Emu/Cell/PPUModule.h"
#include "Emu/Cell/PPUThread.h"
@@ -76,7 +75,7 @@ struct msg_info
return nullptr;
}
dlg = g_emu_callbacks.get_msg_dialog();
dlg = Emu.GetCallbacks().get_msg_dialog();
return dlg;
}
+2 -2
View File
@@ -4,7 +4,7 @@
#include "Emu/Cell/lv2/sys_lwcond.h"
#include "Emu/Cell/lv2/sys_spu.h"
#include "Emu/Io/music_handler_base.h"
#include "Emu/emu_callbacks.h"
#include "Emu/System.h"
#include "Emu/VFS.h"
#include "Emu/RSX/Overlays/overlay_media_list_dialog.h"
#include "cellSearch.h"
@@ -79,7 +79,7 @@ public:
music_state()
{
handler = g_emu_callbacks.get_music_handler();
handler = Emu.GetCallbacks().get_music_handler();
handler->set_event_status_callback([this](u32 status)
{
if (!func)
+70 -53
View File
@@ -188,71 +188,77 @@ error_code cell_music_decode_read(vm::ptr<void> buf, vm::ptr<u32> startTime, u64
auto& dec = g_fxo->get<Music_Decode>();
std::lock_guard lock(dec.mutex);
std::scoped_lock slock(dec.decoder.m_mtx);
if (dec.decoder.has_error())
if (dec.decoder.has_error)
{
return CELL_MUSIC_DECODE_ERROR_DECODE_FAILURE;
}
if (dec.decoder.m_size == 0)
{
std::scoped_lock data_lock(dec.decoder.data_mutex());
const u64 size = dec.decoder.size();
return { CELL_MUSIC_DECODE_ERROR_NO_LPCM_DATA, "m_size == 0" };
}
if (size == 0)
{
return { CELL_MUSIC_DECODE_ERROR_NO_LPCM_DATA, "size == 0" };
}
ensure(dec.decoder.m_size >= dec.read_pos);
const u64 size_left = dec.decoder.m_size - dec.read_pos;
ensure(size >= dec.read_pos);
const u64 size_left = size - dec.read_pos;
if (dec.read_pos == 0)
if (dec.read_pos == 0)
{
cellMusicDecode.trace("cell_music_decode_read: position=CELL_MUSIC_DECODE_POSITION_START, read_pos=%d, reqSize=%d, m_size=%d", dec.read_pos, reqSize, dec.decoder.m_size.load());
*position = CELL_MUSIC_DECODE_POSITION_START;
}
else if (!dec.decoder.track_fully_decoded || size_left > reqSize) // track_fully_decoded is not guarded by a mutex, but since it is set to true after the decode, it should be fine.
{
cellMusicDecode.trace("cell_music_decode_read: position=CELL_MUSIC_DECODE_POSITION_MID, read_pos=%d, reqSize=%d, m_size=%d", dec.read_pos, reqSize, dec.decoder.m_size.load());
*position = CELL_MUSIC_DECODE_POSITION_MID;
}
else
{
if (dec.decoder.set_next_index(true) == umax)
{
cellMusicDecode.trace("cell_music_decode_read: position=CELL_MUSIC_DECODE_POSITION_START, read_pos=%d, reqSize=%d, size=%d", dec.read_pos, reqSize, size);
*position = CELL_MUSIC_DECODE_POSITION_START;
}
else if (!dec.decoder.track_fully_decoded() || size_left > reqSize) // track_fully_decoded is not guarded by a mutex, but since it is set to true after the decode, it should be fine.
{
cellMusicDecode.trace("cell_music_decode_read: position=CELL_MUSIC_DECODE_POSITION_MID, read_pos=%d, reqSize=%d, size=%d", dec.read_pos, reqSize, size);
*position = CELL_MUSIC_DECODE_POSITION_MID;
cellMusicDecode.trace("cell_music_decode_read: position=CELL_MUSIC_DECODE_POSITION_END_LIST_END, read_pos=%d, reqSize=%d, m_size=%d", dec.read_pos, reqSize, dec.decoder.m_size.load());
*position = CELL_MUSIC_DECODE_POSITION_END_LIST_END;
}
else
{
if (dec.decoder.set_next_index(true) == umax)
{
cellMusicDecode.trace("cell_music_decode_read: position=CELL_MUSIC_DECODE_POSITION_END_LIST_END, read_pos=%d, reqSize=%d, size=%d", dec.read_pos, reqSize, size);
*position = CELL_MUSIC_DECODE_POSITION_END_LIST_END;
}
else
{
cellMusicDecode.trace("cell_music_decode_read: position=CELL_MUSIC_DECODE_POSITION_END, read_pos=%d, reqSize=%d, size=%d", dec.read_pos, reqSize, size);
*position = CELL_MUSIC_DECODE_POSITION_END;
}
cellMusicDecode.trace("cell_music_decode_read: position=CELL_MUSIC_DECODE_POSITION_END, read_pos=%d, reqSize=%d, m_size=%d", dec.read_pos, reqSize, dec.decoder.m_size.load());
*position = CELL_MUSIC_DECODE_POSITION_END;
}
const u64 read_size = dec.decoder.read(buf.get_ptr(), dec.read_pos, reqSize);
*readSize = read_size;
if (read_size == 0)
{
return { CELL_MUSIC_DECODE_ERROR_NO_LPCM_DATA, "read_size == 0" }; // TODO: speculative
}
if (read_size < reqSize)
{
// Set the rest of the buffer to zero to prevent loud pops at the end of the stream if the game ignores the readSize.
std::memset(vm::static_ptr_cast<u8>(buf).get_ptr() + read_size, 0, reqSize - read_size);
}
dec.read_pos += read_size;
const s64 start_time_ms = dec.decoder.get_start_time_ms(dec.read_pos);
*startTime = static_cast<u32>(start_time_ms); // startTime is milliseconds
cellMusicDecode.trace("cell_music_decode_read(read_size=%d, samples=%d, start_time_ms=%d)", read_size, read_size / sizeof(u64), start_time_ms);
}
const u64 size_to_read = std::min(reqSize, size_left);
*readSize = size_to_read;
if (size_to_read == 0)
{
return { CELL_MUSIC_DECODE_ERROR_NO_LPCM_DATA, "size_to_read == 0" }; // TODO: speculative
}
std::memcpy(buf.get_ptr(), &::at32(dec.decoder.data, dec.read_pos), size_to_read);
if (size_to_read < reqSize)
{
// Set the rest of the buffer to zero to prevent loud pops at the end of the stream if the game ignores the readSize.
std::memset(vm::static_ptr_cast<u8>(buf).get_ptr() + size_to_read, 0, reqSize - size_to_read);
}
dec.read_pos += size_to_read;
s64 start_time_ms = 0;
if (!dec.decoder.timestamps_ms.empty())
{
start_time_ms = dec.decoder.timestamps_ms.front().second;
while (dec.decoder.timestamps_ms.size() > 1 && dec.read_pos >= ::at32(dec.decoder.timestamps_ms, 1).first)
{
dec.decoder.timestamps_ms.pop_front();
}
}
*startTime = static_cast<u32>(start_time_ms); // startTime is milliseconds
switch (*position)
{
case CELL_MUSIC_DECODE_POSITION_END_LIST_END:
@@ -266,7 +272,8 @@ error_code cell_music_decode_read(vm::ptr<void> buf, vm::ptr<u32> startTime, u64
{
dec.read_pos = 0;
dec.decoder.clear();
dec.decoder.wake_up();
dec.decoder.track_fully_consumed = 1;
dec.decoder.track_fully_consumed.notify_one();
break;
}
default:
@@ -275,6 +282,8 @@ error_code cell_music_decode_read(vm::ptr<void> buf, vm::ptr<u32> startTime, u64
}
}
cellMusicDecode.trace("cell_music_decode_read(size_to_read=%d, samples=%d, start_time_ms=%d)", size_to_read, size_to_read / sizeof(u64), start_time_ms);
return CELL_OK;
}
@@ -366,7 +375,11 @@ error_code cellMusicDecodeSetDecodeCommand(s32 command)
if (!dec.func)
return CELL_MUSIC_DECODE_ERROR_GENERIC;
const error_code result = dec.set_decode_command(command);
error_code result = CELL_OK;
{
std::scoped_lock slock(dec.decoder.m_mtx);
result = dec.set_decode_command(command);
}
sysutil_register_cb([&dec, result](ppu_thread& ppu) -> s32
{
@@ -553,7 +566,11 @@ error_code cellMusicDecodeSetDecodeCommand2(s32 command)
if (!dec.func)
return CELL_MUSIC_DECODE_ERROR_GENERIC;
const error_code result = dec.set_decode_command(command);
error_code result = CELL_OK;
{
std::scoped_lock slock(dec.decoder.m_mtx);
result = dec.set_decode_command(command);
}
sysutil_register_cb([&dec, result](ppu_thread& ppu) -> s32
{
@@ -17,22 +17,7 @@ bool music_selection_context::set(const CellMusicSelectionContext& in)
}
constexpr u32 pos = sizeof(magic);
const std::string_view data{&in.data[pos], sizeof(in.data) - pos};
const std::string_view new_hash = data.substr(0, data.find_first_of('\0'));
const bool is_valid_hash = !new_hash.empty() && std::all_of(new_hash.begin(), new_hash.end(), [](char c)
{
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '-' || c == '_';
});
if (!is_valid_hash)
{
cellMusicSelectionContext.error("Invalid music selection context hash, context = %s", context_to_hex(in));
return false;
}
hash = std::string{new_hash};
hash = &in.data[pos];
return load_playlist();
}
@@ -50,7 +35,7 @@ CellMusicSelectionContext music_selection_context::get() const
std::memset(out.data, 0, CELL_MUSIC_SELECTION_CONTEXT_SIZE);
std::memcpy(out.data, magic, sizeof(magic));
pos += sizeof(magic);
std::memcpy(&out.data[pos], hash.data(), hash.size());
std::memcpy(&out.data[pos], hash.c_str(), hash.size());
return out;
}

Some files were not shown because too many files have changed in this diff Show More