Merge branch 'shadps4-emu:main' into shader_cache

This commit is contained in:
Fire Cube 2025-04-30 11:15:54 +02:00 committed by GitHub
commit cbeaf46102
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
314 changed files with 33054 additions and 11842 deletions

View File

@ -53,3 +53,24 @@ body:
placeholder: "Example: Windows 11, Arch Linux, MacOS 15"
validations:
required: true
- type: input
id: cpu
attributes:
label: CPU
placeholder: "Example: Intel Core i7-8700"
validations:
required: true
- type: input
id: gpu
attributes:
label: GPU
placeholder: "Example: nVidia GTX 1650"
validations:
required: true
- type: input
id: ram
attributes:
label: Amount of RAM in GB
placeholder: "Example: 16 GB"
validations:
required: true

View File

@ -30,7 +30,7 @@ jobs:
- name: Install
run: |
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
sudo add-apt-repository 'deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-19 main'
sudo add-apt-repository 'deb http://apt.llvm.org/noble/ llvm-toolchain-noble-19 main'
sudo apt update
sudo apt install clang-format-19
- name: Build
@ -205,12 +205,12 @@ jobs:
run: |
mkdir upload
mv ${{github.workspace}}/build/shadps4 upload
cp ${{github.workspace}}/build/externals/MoltenVK/libMoltenVK.dylib upload
tar cf shadps4-macos-sdl.tar.gz -C upload .
mv ${{github.workspace}}/build/MoltenVK_icd.json upload
mv ${{github.workspace}}/build/libMoltenVK.dylib upload
- uses: actions/upload-artifact@v4
with:
name: shadps4-macos-sdl-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}
path: shadps4-macos-sdl.tar.gz
path: upload/
macos-qt:
runs-on: macos-15
@ -281,8 +281,13 @@ jobs:
with:
submodules: recursive
- name: Add LLVM repository
run: |
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
sudo add-apt-repository 'deb http://apt.llvm.org/noble/ llvm-toolchain-noble-19 main'
- name: Install dependencies
run: sudo apt-get update && sudo apt install -y libx11-dev libxext-dev libwayland-dev libdecor-0-dev libxkbcommon-dev libglfw3-dev libgles2-mesa-dev libfuse2 clang build-essential libasound2-dev libpulse-dev libopenal-dev libudev-dev
run: sudo apt-get update && sudo apt install -y libx11-dev libxext-dev libwayland-dev libdecor-0-dev libxkbcommon-dev libglfw3-dev libgles2-mesa-dev libfuse2 clang-19 mold build-essential libasound2-dev libpulse-dev libopenal-dev libudev-dev
- name: Cache CMake Configuration
uses: actions/cache@v4
@ -304,7 +309,7 @@ jobs:
key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
- name: Configure CMake
run: cmake --fresh -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE=ON -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
run: cmake --fresh -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE=ON -DCMAKE_C_COMPILER=clang-19 -DCMAKE_CXX_COMPILER=clang++-19 -DCMAKE_EXE_LINKER_FLAGS="-fuse-ld=mold" -DCMAKE_SHARED_LINKER_FLAGS="-fuse-ld=mold" -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
- name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $(nproc)
@ -337,8 +342,13 @@ jobs:
with:
submodules: recursive
- name: Add LLVM repository
run: |
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
sudo add-apt-repository 'deb http://apt.llvm.org/noble/ llvm-toolchain-noble-19 main'
- name: Install dependencies
run: sudo apt-get update && sudo apt install -y libx11-dev libxext-dev libwayland-dev libdecor-0-dev libxkbcommon-dev libglfw3-dev libgles2-mesa-dev libfuse2 clang build-essential qt6-base-dev qt6-tools-dev qt6-multimedia-dev libasound2-dev libpulse-dev libopenal-dev libudev-dev
run: sudo apt-get update && sudo apt install -y libx11-dev libxext-dev libwayland-dev libdecor-0-dev libxkbcommon-dev libglfw3-dev libgles2-mesa-dev libfuse2 clang-19 mold build-essential qt6-base-dev qt6-tools-dev qt6-multimedia-dev libasound2-dev libpulse-dev libopenal-dev libudev-dev
- name: Cache CMake Configuration
uses: actions/cache@v4
@ -360,7 +370,7 @@ jobs:
key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
- name: Configure CMake
run: cmake --fresh -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE=ON -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DENABLE_QT_GUI=ON -DENABLE_UPDATER=ON -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
run: cmake --fresh -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE=ON -DCMAKE_C_COMPILER=clang-19 -DCMAKE_CXX_COMPILER=clang++-19 -DCMAKE_EXE_LINKER_FLAGS="-fuse-ld=mold" -DCMAKE_SHARED_LINKER_FLAGS="-fuse-ld=mold" -DENABLE_QT_GUI=ON -DENABLE_UPDATER=ON -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
- name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $(nproc)
@ -385,7 +395,7 @@ jobs:
submodules: recursive
- name: Install dependencies
run: sudo apt-get update && sudo apt install -y libx11-dev libxext-dev libwayland-dev libdecor-0-dev libxkbcommon-dev libglfw3-dev libgles2-mesa-dev libfuse2 gcc-14 build-essential libasound2-dev libpulse-dev libopenal-dev libudev-dev
run: sudo apt-get update && sudo apt install -y libx11-dev libxext-dev libwayland-dev libdecor-0-dev libxkbcommon-dev libglfw3-dev libgles2-mesa-dev libfuse2 gcc-14 mold build-essential libasound2-dev libpulse-dev libopenal-dev libudev-dev
- name: Cache CMake Configuration
uses: actions/cache@v4
@ -407,7 +417,7 @@ jobs:
key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
- name: Configure CMake
run: cmake --fresh -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE=ON -DCMAKE_C_COMPILER=gcc-14 -DCMAKE_CXX_COMPILER=g++-14 -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
run: cmake --fresh -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE=ON -DCMAKE_C_COMPILER=gcc-14 -DCMAKE_CXX_COMPILER=g++-14 -DCMAKE_EXE_LINKER_FLAGS="-fuse-ld=mold" -DCMAKE_SHARED_LINKER_FLAGS="-fuse-ld=mold" -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
- name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $(nproc)
@ -421,7 +431,7 @@ jobs:
submodules: recursive
- name: Install dependencies
run: sudo apt-get update && sudo apt install -y libx11-dev libxext-dev libwayland-dev libdecor-0-dev libxkbcommon-dev libglfw3-dev libgles2-mesa-dev libfuse2 gcc-14 build-essential qt6-base-dev qt6-tools-dev qt6-multimedia-dev libasound2-dev libpulse-dev libopenal-dev libudev-dev
run: sudo apt-get update && sudo apt install -y libx11-dev libxext-dev libwayland-dev libdecor-0-dev libxkbcommon-dev libglfw3-dev libgles2-mesa-dev libfuse2 gcc-14 mold build-essential qt6-base-dev qt6-tools-dev qt6-multimedia-dev libasound2-dev libpulse-dev libopenal-dev libudev-dev
- name: Cache CMake Configuration
uses: actions/cache@v4
@ -443,7 +453,7 @@ jobs:
key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
- name: Configure CMake
run: cmake --fresh -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE=ON -DCMAKE_C_COMPILER=gcc-14 -DCMAKE_CXX_COMPILER=g++-14 -DENABLE_QT_GUI=ON -DENABLE_UPDATER=ON -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
run: cmake --fresh -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE=ON -DCMAKE_C_COMPILER=gcc-14 -DCMAKE_CXX_COMPILER=g++-14 -DCMAKE_EXE_LINKER_FLAGS="-fuse-ld=mold" -DCMAKE_SHARED_LINKER_FLAGS="-fuse-ld=mold" -DENABLE_QT_GUI=ON -DENABLE_UPDATER=ON -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
- name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $(nproc)

15
.gitmodules vendored
View File

@ -1,15 +1,3 @@
[submodule "externals/cryptopp-cmake"]
path = externals/cryptopp-cmake
url = https://github.com/shadps4-emu/ext-cryptopp-cmake.git
shallow = true
[submodule "externals/cryptopp"]
path = externals/cryptopp
url = https://github.com/shadps4-emu/ext-cryptopp.git
shallow = true
[submodule "externals/cryptoppwin"]
path = externals/cryptoppwin
url = https://github.com/shadps4-emu/ext-cryptoppwin.git
shallow = true
[submodule "externals/zlib-ng"]
path = externals/zlib-ng
url = https://github.com/shadps4-emu/ext-zlib-ng.git
@ -119,3 +107,6 @@
path = externals/MoltenVK/cereal
url = https://github.com/USCiLab/cereal
shallow = true
[submodule "externals/libusb"]
path = externals/libusb
url = https://github.com/libusb/libusb-cmake.git

View File

@ -9,7 +9,8 @@ set(CMAKE_CXX_STANDARD_REQUIRED True)
if(APPLE)
list(APPEND ADDITIONAL_LANGUAGES OBJC)
set(CMAKE_OSX_DEPLOYMENT_TARGET 14)
# Starting with 15.4, Rosetta 2 has support for all the necessary instruction sets.
set(CMAKE_OSX_DEPLOYMENT_TARGET 15.4 CACHE STRING "")
endif()
if (NOT CMAKE_BUILD_TYPE)
@ -37,8 +38,10 @@ option(ENABLE_UPDATER "Enables the options to updater" ON)
# First, determine whether to use CMAKE_OSX_ARCHITECTURES or CMAKE_SYSTEM_PROCESSOR.
if (APPLE AND CMAKE_OSX_ARCHITECTURES)
set(BASE_ARCHITECTURE "${CMAKE_OSX_ARCHITECTURES}")
else()
elseif (CMAKE_SYSTEM_PROCESSOR)
set(BASE_ARCHITECTURE "${CMAKE_SYSTEM_PROCESSOR}")
else()
set(BASE_ARCHITECTURE "${CMAKE_HOST_SYSTEM_PROCESSOR}")
endif()
# Next, match common architecture strings down to a known common value.
@ -50,7 +53,13 @@ else()
message(FATAL_ERROR "Unsupported CPU architecture: ${BASE_ARCHITECTURE}")
endif()
if (APPLE AND ARCHITECTURE STREQUAL "x86_64" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64")
if (ARCHITECTURE STREQUAL "x86_64")
# Target the same CPU architecture as the PS4, to maintain the same level of compatibility.
# Exclude SSE4a as it is only available on AMD CPUs.
add_compile_options(-march=btver2 -mtune=generic -mno-sse4a)
endif()
if (APPLE AND ARCHITECTURE STREQUAL "x86_64" AND CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "arm64")
# Exclude ARM homebrew path to avoid conflicts when cross compiling.
list(APPEND CMAKE_IGNORE_PREFIX_PATH "/opt/homebrew")
@ -96,38 +105,81 @@ if (CLANG_FORMAT)
unset(CCOMMENT)
endif()
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
# generate git revision information
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/externals/cmake-modules/")
include(GetGitRevisionDescription)
include("${CMAKE_CURRENT_SOURCE_DIR}/externals/cmake-modules/GetGitRevisionDescription.cmake")
get_git_head_revision(GIT_REF_SPEC GIT_REV)
git_describe(GIT_DESC --always --long --dirty)
git_branch_name(GIT_BRANCH)
string(TIMESTAMP BUILD_DATE "%Y-%m-%d %H:%M:%S")
message("start git things")
# Try to get the upstream remote and branch
message("check for remote and branch")
execute_process(
COMMAND git rev-parse --abbrev-ref --symbolic-full-name @{u}
OUTPUT_VARIABLE GIT_REMOTE_NAME
RESULT_VARIABLE GIT_BRANCH_RESULT
RESULT_VARIABLE GIT_REMOTE_RESULT
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE
)
# If there's no upstream set or the command failed, check remote.pushDefault
if (GIT_BRANCH_RESULT OR GIT_REMOTE_NAME STREQUAL "")
if (GIT_REMOTE_RESULT OR GIT_REMOTE_NAME STREQUAL "")
message("check default push")
execute_process(
COMMAND git config --get remote.pushDefault
OUTPUT_VARIABLE GIT_REMOTE_NAME
RESULT_VARIABLE GIT_PUSH_DEFAULT_RESULT
RESULT_VARIABLE GIT_REMOTE_RESULT
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE
)
# If remote.pushDefault is not set or fails, default to origin
if (GIT_PUSH_DEFAULT_RESULT OR GIT_REMOTE_NAME STREQUAL "")
set(GIT_REMOTE_NAME "origin")
endif()
# If running in GitHub Actions and the above fails
if (GIT_REMOTE_RESULT OR GIT_REMOTE_NAME STREQUAL "")
message("check github")
set(GIT_REMOTE_NAME "origin")
# Retrieve environment variables
if (DEFINED ENV{GITHUB_HEAD_REF} AND NOT "$ENV{GITHUB_HEAD_REF}" STREQUAL "")
message("github head ref: $ENV{GITHUB_HEAD_REF}")
set(GITHUB_HEAD_REF "$ENV{GITHUB_HEAD_REF}")
else()
set(GITHUB_HEAD_REF "")
endif()
if (DEFINED ENV{GITHUB_REF} AND NOT "$ENV{GITHUB_REF}" STREQUAL "")
message("github ref: $ENV{GITHUB_REF}")
string(REGEX REPLACE "^refs/[^/]*/" "" GITHUB_BRANCH "$ENV{GITHUB_REF}")
string(REGEX MATCH "refs/pull/([0-9]+)/merge" MATCHED_REF "$ENV{GITHUB_REF}")
if (MATCHED_REF)
set(PR_NUMBER "${CMAKE_MATCH_1}")
set(GITHUB_BRANCH "")
message("PR number: ${PR_NUMBER}")
else()
set(PR_NUMBER "")
endif()
else()
set(GITHUB_BRANCH "")
set(PR_NUMBER "")
endif()
if (NOT "${PR_NUMBER}" STREQUAL "" AND NOT "${GITHUB_HEAD_REF}" STREQUAL "")
set(GIT_BRANCH "pr-${PR_NUMBER}-${GITHUB_HEAD_REF}")
elseif (NOT "${PR_NUMBER}" STREQUAL "" AND NOT "${GITHUB_BRANCH}" STREQUAL "")
set(GIT_BRANCH "pr-${PR_NUMBER}-${GITHUB_BRANCH}")
elseif (NOT "${PR_NUMBER}" STREQUAL "")
set(GIT_BRANCH "pr-${PR_NUMBER}")
elseif ("${PR_NUMBER}" STREQUAL "" AND NOT "${GITHUB_HEAD_REF}" STREQUAL "")
set(GIT_BRANCH "${GITHUB_HEAD_REF}")
elseif ("${PR_NUMBER}" STREQUAL "" AND NOT "${GITHUB_BRANCH}" STREQUAL "")
set(GIT_BRANCH "${GITHUB_BRANCH}")
elseif ("${PR_NUMBER}" STREQUAL "" AND NOT "${GITHUB_REF}" STREQUAL "")
set(GIT_BRANCH "${GITHUB_REF}")
else()
message("couldn't find branch")
set(GIT_BRANCH "detached-head")
endif()
else()
# Extract remote name if the output contains a remote/branch format
@ -141,14 +193,27 @@ else()
endif()
# Get remote link
message("getting remote link")
execute_process(
COMMAND git config --get remote.${GIT_REMOTE_NAME}.url
OUTPUT_VARIABLE GIT_REMOTE_URL
OUTPUT_STRIP_TRAILING_WHITESPACE
)
# Set Version
set(EMULATOR_VERSION_MAJOR "0")
set(EMULATOR_VERSION_MINOR "8")
set(EMULATOR_VERSION_PATCH "1")
set_source_files_properties(src/shadps4.rc PROPERTIES COMPILE_DEFINITIONS "EMULATOR_VERSION_MAJOR=${EMULATOR_VERSION_MAJOR};EMULATOR_VERSION_MINOR=${EMULATOR_VERSION_MINOR};EMULATOR_VERSION_PATCH=${EMULATOR_VERSION_PATCH}")
set(APP_VERSION "${EMULATOR_VERSION_MAJOR}.${EMULATOR_VERSION_MINOR}.${EMULATOR_VERSION_PATCH} WIP")
set(APP_IS_RELEASE false)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/common/scm_rev.cpp.in" "${CMAKE_CURRENT_BINARY_DIR}/src/common/scm_rev.cpp" @ONLY)
message("end git things, remote: ${GIT_REMOTE_NAME}, branch: ${GIT_BRANCH}")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
find_package(Boost 1.84.0 CONFIG)
find_package(FFmpeg 5.1.2 MODULE)
find_package(fmt 10.2.0 CONFIG)
@ -161,21 +226,18 @@ find_package(SDL3 3.1.2 CONFIG)
find_package(stb MODULE)
find_package(toml11 4.2.0 CONFIG)
find_package(tsl-robin-map 1.3.0 CONFIG)
find_package(VulkanHeaders 1.4.305 CONFIG)
find_package(VulkanHeaders 1.4.309 CONFIG)
find_package(VulkanMemoryAllocator 3.1.0 CONFIG)
find_package(xbyak 7.07 CONFIG)
find_package(xxHash 0.8.2 MODULE)
find_package(ZLIB 1.3 MODULE)
find_package(Zydis 5.0.0 CONFIG)
find_package(pugixml 1.14 CONFIG)
if (NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR NOT MSVC)
find_package(cryptopp 8.9.0 MODULE)
endif()
find_package(libusb 1.0.27 MODULE)
if (APPLE)
find_package(date 3.0.1 CONFIG)
endif()
list(POP_BACK CMAKE_MODULE_PATH)
# Note: Windows always has these functions through winpthreads
include(CheckSymbolExists)
@ -278,6 +340,8 @@ set(KERNEL_LIB src/core/libraries/kernel/sync/mutex.cpp
src/core/libraries/kernel/threads/thread_state.h
src/core/libraries/kernel/process.cpp
src/core/libraries/kernel/process.h
src/core/libraries/kernel/debug.cpp
src/core/libraries/kernel/debug.h
src/core/libraries/kernel/equeue.cpp
src/core/libraries/kernel/equeue.h
src/core/libraries/kernel/file_system.cpp
@ -298,6 +362,7 @@ set(KERNEL_LIB src/core/libraries/kernel/sync/mutex.cpp
set(NETWORK_LIBS src/core/libraries/network/http.cpp
src/core/libraries/network/http.h
src/core/libraries/network/http_error.h
src/core/libraries/network/http2.cpp
src/core/libraries/network/http2.h
src/core/libraries/network/net.cpp
@ -370,12 +435,28 @@ set(SYSTEM_LIBS src/core/libraries/system/commondialog.cpp
src/core/libraries/ngs2/ngs2_error.h
src/core/libraries/ngs2/ngs2_impl.cpp
src/core/libraries/ngs2/ngs2_impl.h
src/core/libraries/ngs2/ngs2_custom.cpp
src/core/libraries/ngs2/ngs2_custom.h
src/core/libraries/ngs2/ngs2_reverb.cpp
src/core/libraries/ngs2/ngs2_reverb.h
src/core/libraries/ngs2/ngs2_geom.cpp
src/core/libraries/ngs2/ngs2_geom.h
src/core/libraries/ngs2/ngs2_pan.cpp
src/core/libraries/ngs2/ngs2_pan.h
src/core/libraries/ngs2/ngs2_report.cpp
src/core/libraries/ngs2/ngs2_report.h
src/core/libraries/ngs2/ngs2_eq.cpp
src/core/libraries/ngs2/ngs2_eq.h
src/core/libraries/ngs2/ngs2_mastering.cpp
src/core/libraries/ngs2/ngs2_mastering.h
src/core/libraries/ngs2/ngs2_sampler.cpp
src/core/libraries/ngs2/ngs2_sampler.h
src/core/libraries/ngs2/ngs2_submixer.cpp
src/core/libraries/ngs2/ngs2_submixer.h
src/core/libraries/ajm/ajm_error.h
src/core/libraries/audio3d/audio3d.cpp
src/core/libraries/audio3d/audio3d.h
src/core/libraries/audio3d/audio3d_error.h
src/core/libraries/audio3d/audio3d_impl.cpp
src/core/libraries/audio3d/audio3d_impl.h
src/core/libraries/game_live_streaming/gamelivestreaming.cpp
src/core/libraries/game_live_streaming/gamelivestreaming.h
src/core/libraries/remote_play/remoteplay.cpp
@ -489,6 +570,8 @@ set(NP_LIBS src/core/libraries/np_common/np_common.cpp
src/core/libraries/np_web_api/np_web_api.h
src/core/libraries/np_party/np_party.cpp
src/core/libraries/np_party/np_party.h
src/core/libraries/np_auth/np_auth.cpp
src/core/libraries/np_auth/np_auth.h
)
set(ZLIB_LIB src/core/libraries/zlib/zlib.cpp
@ -504,6 +587,8 @@ set(MISC_LIBS src/core/libraries/screenshot/screenshot.cpp
src/core/libraries/screenshot/screenshot.h
src/core/libraries/move/move.cpp
src/core/libraries/move/move.h
src/core/libraries/ulobjmgr/ulobjmgr.cpp
src/core/libraries/ulobjmgr/ulobjmgr.h
)
set(DEV_TOOLS src/core/devtools/layer.cpp
@ -543,6 +628,7 @@ set(COMMON src/common/logging/backend.cpp
src/common/logging/text_formatter.cpp
src/common/logging/text_formatter.h
src/common/logging/types.h
src/common/aes.h
src/common/alignment.h
src/common/arch.h
src/common/assert.cpp
@ -574,6 +660,7 @@ set(COMMON src/common/logging/backend.cpp
src/common/polyfill_thread.h
src/common/rdtsc.cpp
src/common/rdtsc.h
src/common/sha1.h
src/common/signal_context.h
src/common/signal_context.cpp
src/common/singleton.h
@ -583,6 +670,7 @@ set(COMMON src/common/logging/backend.cpp
src/common/spin_lock.h
src/common/stb.cpp
src/common/stb.h
src/common/string_literal.h
src/common/string_util.cpp
src/common/string_util.h
src/common/thread.cpp
@ -591,7 +679,6 @@ set(COMMON src/common/logging/backend.cpp
src/common/uint128.h
src/common/unique_function.h
src/common/va_ctx.h
src/common/version.h
src/common/ntapi.h
src/common/ntapi.cpp
src/common/number_utils.h
@ -612,9 +699,6 @@ set(CORE src/core/aerolib/stubs.cpp
src/core/aerolib/aerolib.h
src/core/address_space.cpp
src/core/address_space.h
src/core/crypto/crypto.cpp
src/core/crypto/crypto.h
src/core/crypto/keys.h
src/core/devices/base_device.cpp
src/core/devices/base_device.h
src/core/devices/ioccom.h
@ -632,22 +716,14 @@ set(CORE src/core/aerolib/stubs.cpp
src/core/devices/srandom_device.cpp
src/core/devices/srandom_device.h
src/core/file_format/pfs.h
src/core/file_format/pkg.cpp
src/core/file_format/pkg.h
src/core/file_format/pkg_type.cpp
src/core/file_format/pkg_type.h
src/core/file_format/psf.cpp
src/core/file_format/psf.h
src/core/file_format/playgo_chunk.cpp
src/core/file_format/playgo_chunk.h
src/core/file_format/trp.cpp
src/core/file_format/trp.h
src/core/file_format/splash.h
src/core/file_format/splash.cpp
src/core/file_sys/fs.cpp
src/core/file_sys/fs.h
src/core/loader.cpp
src/core/loader.h
src/core/loader/dwarf.cpp
src/core/loader/dwarf.h
src/core/loader/elf.cpp
@ -764,6 +840,8 @@ set(SHADER_RECOMPILER src/shader_recompiler/exception.h
src/shader_recompiler/ir/passes/identity_removal_pass.cpp
src/shader_recompiler/ir/passes/ir_passes.h
src/shader_recompiler/ir/passes/lower_buffer_format_to_raw.cpp
src/shader_recompiler/ir/passes/lower_fp64_to_fp32.cpp
src/shader_recompiler/ir/passes/readlane_elimination_pass.cpp
src/shader_recompiler/ir/passes/resource_tracking_pass.cpp
src/shader_recompiler/ir/passes/ring_access_elimination.cpp
src/shader_recompiler/ir/passes/shader_info_collection_pass.cpp
@ -844,6 +922,10 @@ set(VIDEO_CORE src/video_core/amdgpu/liverpool.cpp
src/video_core/renderer_vulkan/vk_shader_util.h
src/video_core/renderer_vulkan/vk_swapchain.cpp
src/video_core/renderer_vulkan/vk_swapchain.h
src/video_core/renderer_vulkan/host_passes/fsr_pass.cpp
src/video_core/renderer_vulkan/host_passes/fsr_pass.h
src/video_core/renderer_vulkan/host_passes/pp_pass.cpp
src/video_core/renderer_vulkan/host_passes/pp_pass.h
src/video_core/texture_cache/image.cpp
src/video_core/texture_cache/image.h
src/video_core/texture_cache/image_info.cpp
@ -916,6 +998,9 @@ set(QT_GUI src/qt_gui/about_dialog.cpp
src/qt_gui/control_settings.cpp
src/qt_gui/control_settings.h
src/qt_gui/control_settings.ui
src/qt_gui/kbm_gui.cpp
src/qt_gui/kbm_gui.h
src/qt_gui/kbm_gui.ui
src/qt_gui/main_window_ui.h
src/qt_gui/main_window.cpp
src/qt_gui/main_window.h
@ -929,10 +1014,6 @@ set(QT_GUI src/qt_gui/about_dialog.cpp
src/qt_gui/game_grid_frame.h
src/qt_gui/game_install_dialog.cpp
src/qt_gui/game_install_dialog.h
src/qt_gui/install_dir_select.cpp
src/qt_gui/install_dir_select.h
src/qt_gui/pkg_viewer.cpp
src/qt_gui/pkg_viewer.h
src/qt_gui/trophy_viewer.cpp
src/qt_gui/trophy_viewer.h
src/qt_gui/elf_viewer.cpp
@ -988,7 +1069,7 @@ endif()
create_target_directory_groups(shadps4)
target_link_libraries(shadps4 PRIVATE magic_enum::magic_enum fmt::fmt toml11::toml11 tsl::robin_map xbyak::xbyak Tracy::TracyClient RenderDoc::API FFmpeg::ffmpeg Dear_ImGui gcn half::half ZLIB::ZLIB PNG::PNG)
target_link_libraries(shadps4 PRIVATE Boost::headers GPUOpen::VulkanMemoryAllocator LibAtrac9 sirit Vulkan::Headers xxHash::xxhash Zydis::Zydis glslang::glslang SDL3::SDL3 pugixml::pugixml stb::headers)
target_link_libraries(shadps4 PRIVATE Boost::headers GPUOpen::VulkanMemoryAllocator LibAtrac9 sirit Vulkan::Headers xxHash::xxhash Zydis::Zydis glslang::glslang SDL3::SDL3 pugixml::pugixml stb::headers libusb::usb)
target_compile_definitions(shadps4 PRIVATE IMGUI_USER_CONFIG="imgui/imgui_config.h")
target_compile_definitions(Dear_ImGui PRIVATE IMGUI_USER_CONFIG="${PROJECT_SOURCE_DIR}/src/imgui/imgui_config.h")
@ -1003,46 +1084,49 @@ if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" AND ENABLE_USERFAULTFD)
endif()
if (APPLE)
if (ENABLE_QT_GUI)
# Include MoltenVK in the app bundle, along with an ICD file so it can be found by the system Vulkan loader if used for loading layers.
set(MVK_ICD ${CMAKE_CURRENT_SOURCE_DIR}/externals/MoltenVK/MoltenVK_icd.json)
target_sources(shadps4 PRIVATE ${MVK_ICD})
set_source_files_properties(${MVK_ICD} PROPERTIES MACOSX_PACKAGE_LOCATION Resources/vulkan/icd.d)
# Include MoltenVK, along with an ICD file so it can be found by the system Vulkan loader if used for loading layers.
if (ENABLE_QT_GUI)
set(MVK_BUNDLE_PATH "Resources/vulkan/icd.d")
set_property(TARGET shadps4 APPEND PROPERTY BUILD_RPATH "@executable_path/../${MVK_BUNDLE_PATH}")
set(MVK_DST ${CMAKE_CURRENT_BINARY_DIR}/shadps4.app/Contents/${MVK_BUNDLE_PATH})
else()
set_property(TARGET shadps4 APPEND PROPERTY BUILD_RPATH "@executable_path")
set(MVK_DST ${CMAKE_CURRENT_BINARY_DIR})
endif()
set(MVK_DYLIB_SRC ${CMAKE_CURRENT_BINARY_DIR}/externals/MoltenVK/libMoltenVK.dylib)
set(MVK_DYLIB_DST ${CMAKE_CURRENT_BINARY_DIR}/shadps4.app/Contents/Frameworks/libMoltenVK.dylib)
add_custom_command(
OUTPUT ${MVK_DYLIB_DST}
DEPENDS ${MVK_DYLIB_SRC}
COMMAND cmake -E copy ${MVK_DYLIB_SRC} ${MVK_DYLIB_DST})
add_custom_target(CopyMoltenVK DEPENDS ${MVK_DYLIB_DST})
add_dependencies(CopyMoltenVK MoltenVK)
add_dependencies(shadps4 CopyMoltenVK)
set_property(TARGET shadps4 APPEND PROPERTY BUILD_RPATH "@executable_path/../Frameworks")
else()
# For non-bundled SDL build, just do a normal library link.
target_link_libraries(shadps4 PRIVATE MoltenVK)
endif()
set(MVK_DYLIB_SRC ${CMAKE_CURRENT_BINARY_DIR}/externals/MoltenVK/libMoltenVK.dylib)
set(MVK_DYLIB_DST ${MVK_DST}/libMoltenVK.dylib)
set(MVK_ICD_SRC ${CMAKE_CURRENT_SOURCE_DIR}/externals/MoltenVK/MoltenVK/MoltenVK/icd/MoltenVK_icd.json)
set(MVK_ICD_DST ${MVK_DST}/MoltenVK_icd.json)
if (ARCHITECTURE STREQUAL "x86_64")
# Reserve system-managed memory space.
target_link_options(shadps4 PRIVATE -Wl,-no_pie,-no_fixup_chains,-no_huge,-pagezero_size,0x4000,-segaddr,TCB_SPACE,0x4000,-segaddr,SYSTEM_MANAGED,0x400000,-segaddr,SYSTEM_RESERVED,0x7FFFFC000,-image_base,0x20000000000)
endif()
add_custom_command(
OUTPUT ${MVK_DST}
COMMAND ${CMAKE_COMMAND} -E make_directory ${MVK_DST})
add_custom_command(
OUTPUT ${MVK_ICD_DST}
DEPENDS ${MVK_ICD_SRC} ${MVK_DST}
COMMAND ${CMAKE_COMMAND} -E copy ${MVK_ICD_SRC} ${MVK_ICD_DST})
add_custom_command(
OUTPUT ${MVK_DYLIB_DST}
DEPENDS ${MVK_DYLIB_SRC} ${MVK_DST}
COMMAND ${CMAKE_COMMAND} -E copy ${MVK_DYLIB_SRC} ${MVK_DYLIB_DST})
add_custom_target(CopyMoltenVK DEPENDS ${MVK_ICD_DST} ${MVK_DYLIB_DST})
add_dependencies(CopyMoltenVK MoltenVK)
add_dependencies(shadps4 CopyMoltenVK)
# Replacement for std::chrono::time_zone
target_link_libraries(shadps4 PRIVATE date::date-tz)
if (ARCHITECTURE STREQUAL "x86_64")
# Reserve system-managed memory space.
target_link_options(shadps4 PRIVATE -Wl,-no_pie,-no_fixup_chains,-no_huge,-pagezero_size,0x4000,-segaddr,TCB_SPACE,0x4000,-segaddr,SYSTEM_MANAGED,0x400000,-segaddr,SYSTEM_RESERVED,0x7FFFFC000,-image_base,0x20000000000)
endif()
# Replacement for std::chrono::time_zone
target_link_libraries(shadps4 PRIVATE date::date-tz)
endif()
if (NOT ENABLE_QT_GUI)
target_link_libraries(shadps4 PRIVATE SDL3::SDL3)
endif()
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND MSVC)
target_link_libraries(shadps4 PRIVATE cryptoppwin)
else()
target_link_libraries(shadps4 PRIVATE cryptopp::cryptopp)
endif()
if (ENABLE_QT_GUI)
target_link_libraries(shadps4 PRIVATE Qt6::Widgets Qt6::Concurrent Qt6::Network Qt6::Multimedia)
add_definitions(-DENABLE_QT_GUI)
@ -1105,7 +1189,7 @@ target_include_directories(shadps4 PRIVATE ${HOST_SHADERS_INCLUDE})
# embed resources
include(CMakeRC)
include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/CMakeRC.cmake")
cmrc_add_resource_library(embedded-resources
ALIAS res::embedded
NAMESPACE res
@ -1113,7 +1197,6 @@ cmrc_add_resource_library(embedded-resources
src/images/gold.png
src/images/platinum.png
src/images/silver.png)
target_link_libraries(shadps4 PRIVATE res::embedded)
# ImGui resources
@ -1127,8 +1210,8 @@ if (ENABLE_QT_GUI)
MACOSX_BUNDLE ON
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/dist/MacOSBundleInfo.plist.in"
MACOSX_BUNDLE_ICON_FILE "shadPS4.icns"
MACOSX_BUNDLE_SHORT_VERSION_STRING "0.4.1"
)
MACOSX_BUNDLE_SHORT_VERSION_STRING "${APP_VERSION}"
)
set_source_files_properties(src/images/shadPS4.icns PROPERTIES
MACOSX_PACKAGE_LOCATION Resources)

View File

@ -13,7 +13,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
<h1 align="center">
<a href="https://discord.gg/bFJxfftGW6">
<img src="https://img.shields.io/discord/1080089157554155590?color=5865F2&label=shadPS4 Discord&logo=Discord&logoColor=white" width="240">
<img src="https://img.shields.io/discord/1080089157554155590?color=5865F2&label=shadPS4%20Discord&logo=Discord&logoColor=white" width="275">
<a href="https://github.com/shadps4-emu/shadPS4/releases/latest">
<img src="https://img.shields.io/github/downloads/shadps4-emu/shadPS4/total.svg" width="140">
<a href="https://shadps4.net/">
@ -71,7 +71,7 @@ Check the build instructions for [**Linux**](https://github.com/shadps4-emu/shad
Check the build instructions for [**macOS**](https://github.com/shadps4-emu/shadPS4/blob/main/documents/building-macos.md).
> [!IMPORTANT]
> macOS users need at least macOS 15 on Apple Silicon-based Mac devices and at least macOS 14 on Intel-based Mac devices.
> macOS users need at least macOS 15.4 to run shadPS4. Due to GPU issues there are currently heavy bugs on Intel Macs.
# Debugging and reporting issues
@ -122,19 +122,37 @@ R3 | M |
Keyboard and mouse inputs can be customized in the settings menu by clicking the Controller button, and further details and help on controls are also found there. Custom bindings are saved per-game. Inputs support up to three keys per binding, mouse buttons, mouse movement mapped to joystick input, and more.
# Firmware files
shadPS4 can load some PlayStation 4 firmware files, these must be dumped from your legally owned PlayStation 4 console.\
The following firmware modules are supported and must be placed in shadPS4's `user/sys_modules` folder.
<div align="center">
| Modules | Modules | Modules | Modules |
|-------------------------|-------------------------|-------------------------|-------------------------|
| libSceCesCs.sprx | libSceFont.sprx | libSceFontFt.sprx | libSceFreeTypeOt.sprx |
| libSceJson.sprx | libSceJson2.sprx | libSceLibcInternal.sprx | libSceNgs2.sprx |
| libSceRtc.sprx | libSceUlt.sprx | | |
</div>
> [!Caution]
> The above modules are required to run the games properly and must be extracted from your PlayStation 4.\
> **We do not provide any information or support on how to do this**.
# Main team
- [**georgemoralis**](https://github.com/georgemoralis)
- [**raphaelthegreat**](https://github.com/raphaelthegreat)
- [**psucien**](https://github.com/psucien)
- [**skmp**](https://github.com/skmp)
- [**wheremyfoodat**](https://github.com/wheremyfoodat)
- [**raziel1000**](https://github.com/raziel1000)
- [**viniciuslrangel**](https://github.com/viniciuslrangel)
- [**roamic**](https://github.com/vladmikhalin)
- [**poly**](https://github.com/polybiusproxy)
- [**squidbus**](https://github.com/squidbus)
- [**frodo**](https://github.com/baggins183)
- [**Stephen Miller**](https://github.com/StevenMiller123)
- [**kalaposfos13**](https://github.com/kalaposfos13)
Logo is done by [**Xphalnos**](https://github.com/Xphalnos)
@ -145,11 +163,11 @@ Open a PR and we'll check it :)
# Translations
If you want to translate shadPS4 to your language we use [**crowdin**](https://crowdin.com/project/shadps4-emulator).
If you want to translate shadPS4 to your language we use [**Crowdin**](https://crowdin.com/project/shadps4-emulator).
# Contributors
<a href="https://github.com/shadps4-emu/shadPS4/graphs/contributors">
<img src="https://contrib.rocks/image?repo=shadps4-emu/shadPS4&max=15">
<img src="https://contrib.rocks/image?repo=shadps4-emu/shadPS4&max=24">
</a>

View File

@ -30,6 +30,7 @@ path = [
"src/images/dump_icon.png",
"src/images/exit_icon.png",
"src/images/file_icon.png",
"src/images/trophy_icon.png",
"src/images/flag_china.png",
"src/images/flag_eu.png",
"src/images/flag_jp.png",
@ -41,23 +42,33 @@ path = [
"src/images/grid_icon.png",
"src/images/keyboard_icon.png",
"src/images/iconsize_icon.png",
"src/images/KBM.png",
"src/images/ko-fi.png",
"src/images/list_icon.png",
"src/images/list_mode_icon.png",
"src/images/pause_icon.png",
"src/images/play_icon.png",
"src/images/ps4_controller.png",
"src/images/refresh_icon.png",
"src/images/restart_game_icon.png",
"src/images/refreshlist_icon.png",
"src/images/settings_icon.png",
"src/images/fullscreen_icon.png",
"src/images/stop_icon.png",
"src/images/utils_icon.png",
"src/images/shadPS4.icns",
"src/images/shadps4.ico",
"src/images/shadps4.png",
"src/images/net.shadps4.shadPS4.svg",
"src/images/themes_icon.png",
"src/images/update_icon.png",
"src/images/youtube.png",
"src/images/website.png",
"src/images/discord.svg",
"src/images/github.svg",
"src/images/ko-fi.svg",
"src/images/shadps4.svg",
"src/images/website.svg",
"src/images/youtube.svg",
"src/shadps4.qrc",
"src/shadps4.rc",
"src/qt_gui/translations/update_translation.sh",
@ -110,4 +121,9 @@ SPDX-License-Identifier = "CC0-1.0"
[[annotations]]
path = "cmake/CMakeRC.cmake"
SPDX-FileCopyrightText = "Copyright (c) 2017 vector-of-bool <vectorofbool@gmail.com>"
SPDX-License-Identifier = "MIT"
SPDX-License-Identifier = "MIT"
[[annotations]]
path = "src/video_core/host_shaders/fsr/*"
SPDX-FileCopyrightText = "Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved."
SPDX-License-Identifier = "MIT"

View File

@ -1,15 +0,0 @@
# SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
find_package(PkgConfig QUIET)
pkg_search_module(CRYPTOPP QUIET IMPORTED_TARGET libcryptopp)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(cryptopp
REQUIRED_VARS CRYPTOPP_LINK_LIBRARIES
VERSION_VAR CRYPTOPP_VERSION
)
if (cryptopp_FOUND AND NOT TARGET cryptopp::cryptopp)
add_library(cryptopp::cryptopp ALIAS PkgConfig::CRYPTOPP)
endif()

15
cmake/Findlibusb.cmake Normal file
View File

@ -0,0 +1,15 @@
# SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
find_package(PkgConfig QUIET)
pkg_search_module(LIBUSB QUIET IMPORTED_TARGET libusb-1.0)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(libusb
REQUIRED_VARS LIBUSB_LINK_LIBRARIES
VERSION_VAR LIBUSB_VERSION
)
if (libusb_FOUND AND NOT TARGET libusb::usb)
add_library(libusb::usb ALIAS PkgConfig::LIBUSB)
endif()

View File

@ -37,6 +37,12 @@
<category translate="no">Game</category>
</categories>
<releases>
<release version="0.8.0" date="2025-05-23">
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/v.0.8.0</url>
</release>
<release version="0.7.0" date="2025-03-23">
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/v.0.7.0</url>
</release>
<release version="0.6.0" date="2025-01-31">
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/v.0.6.0</url>
</release>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 658 KiB

View File

@ -13,7 +13,6 @@ SPDX-License-Identifier: GPL-2.0-or-later
- [**RAM**](#ram)
- [**OS**](#os)
- [**Have the latest WIP version**](#how-to-run-the-latest-work-in-progress-builds-of-shadps4)
- [**Install PKG files (Games and Updates)**](#install-pkg-files)
- [**Configure the emulator**](#configure-the-emulator)
## Minimum PC requirements
@ -25,13 +24,13 @@ SPDX-License-Identifier: GPL-2.0-or-later
- A CPU supporting the following instruction sets: MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, AVX, F16C, CLMUL, AES, BMI1, MOVBE, XSAVE, ABM
- **Intel**: Haswell generation or newer
- **AMD**: Jaguar generation or newer
- **Apple**: Rosetta 2 on macOS 15 or newer
- **Apple**: Rosetta 2 on macOS 15.4 or newer
### GPU
- A graphics card with at least 1GB of VRAM
- Keep your graphics drivers up to date
- Vulkan 1.3 support (required)
- Up-to-date graphics drivers
- Vulkan 1.3 with the `VK_KHR_swapchain` and `VK_KHR_push_descriptor` extensions
### RAM
@ -48,13 +47,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
2. Once downloaded, extract to its own folder, and run shadPS4's executable from the extracted folder.
3. Upon first launch, shadPS4 will prompt you to select a folder to store your installed games in. Select "Browse" and then select a folder that shadPS4 can use to install your PKG files to.
## Install PKG files
To install PKG files (game and updates), you will need the Qt application (with UI). You will have to go to "File" then to "Install Packages (PKG)", a window will open then you will have to select the files. You can install multiple PKG files at once. Once finished, the game should appear in the application.
<img src="https://github.com/shadps4-emu/shadPS4/blob/main/documents/Quickstart/2.png" width="800">
3. Upon first launch, shadPS4 will prompt you to select a folder to store your installed games in. Select "Browse" and then select a folder that contains your dumped games.
## Configure the emulator

View File

@ -108,7 +108,7 @@ Now run the emulator. If Qt was enabled at configure time:
./build/shadps4
```
Otherwise, specify the path to your PKG's boot file:
Otherwise, specify the path to your game's boot file:
```bash
./build/shadps4 /"PATH"/"TO"/"GAME"/"FOLDER"/eboot.bin

View File

@ -26,24 +26,7 @@ if (NOT TARGET fmt::fmt)
add_subdirectory(fmt)
endif()
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND MSVC)
# If it is clang and MSVC we will add a static lib
# CryptoPP
add_subdirectory(cryptoppwin)
target_include_directories(cryptoppwin INTERFACE cryptoppwin/include)
else()
# CryptoPP
if (NOT TARGET cryptopp::cryptopp)
set(CRYPTOPP_INSTALL OFF)
set(CRYPTOPP_BUILD_TESTING OFF)
set(CRYPTOPP_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/cryptopp)
add_subdirectory(cryptopp-cmake)
file(COPY cryptopp DESTINATION cryptopp FILES_MATCHING PATTERN "*.h")
# remove externals/cryptopp from include directories because it contains a conflicting zlib.h file
set_target_properties(cryptopp PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/cryptopp")
endif()
endif()
# FFmpeg
if (NOT TARGET FFmpeg::ffmpeg)
add_subdirectory(ffmpeg-core)
add_library(FFmpeg::ffmpeg ALIAS ffmpeg)
@ -218,6 +201,12 @@ if (NOT TARGET pugixml::pugixml)
add_subdirectory(pugixml)
endif()
# libusb
if (NOT TARGET libusb::usb)
add_subdirectory(libusb)
add_library(libusb::usb ALIAS usb-1.0)
endif()
# Discord RPC
if (ENABLE_DISCORD_RPC)
add_subdirectory(discord-rpc)

@ -1 +1 @@
Subproject commit 2048427e50f9eb20f2b8f98d316ecaee398c9b91
Subproject commit 87a8e8b13d4ad8835367fea1ebad1896d0460946

View File

@ -1,8 +0,0 @@
{
"file_format_version": "1.0.0",
"ICD": {
"library_path": "../../../Frameworks/libMoltenVK.dylib",
"api_version": "1.2.0",
"is_portability_driver": true
}
}

@ -1 +1 @@
Subproject commit 2c32b6bf86f3c4a5539aa1f0bacbd59fe61759cf
Subproject commit 7918775748c5e2f5c40d9918ce68825035b5a1e1

@ -1 +1 @@
Subproject commit d1fcec807b372f04e4c1041b3058e11c12853e6e
Subproject commit a56bad8bbb770ee266e930c95d37fff2a5be7fea

1
externals/cryptopp vendored

@ -1 +0,0 @@
Subproject commit 60f81a77e0c9a0e7ffc1ca1bc438ddfa2e43b78e

@ -1 +0,0 @@
Subproject commit 2c384c28265a93358a2455e610e76393358794df

@ -1 +0,0 @@
Subproject commit bc3441dd2d6a9728e747dc0180bc8b9065a2923c

2
externals/date vendored

@ -1 +1 @@
Subproject commit 28b7b232521ace2c8ef3f2ad4126daec3569c14f
Subproject commit a45ea7c17b4a7f320e199b71436074bd624c9e15

@ -1 +1 @@
Subproject commit 636cd4a7d623a2bc9bf59bb3acbb4ca075befba3
Subproject commit f4d9359095eff3eb03f685921edc1cf0e37b1687

@ -1 +1 @@
Subproject commit 51b09d426a4a1bcfa6ee6d4894e57d669f4a2e65
Subproject commit 19f66e6dcabb2268965f453db9e5774ede43238f

@ -1 +1 @@
Subproject commit 27de97c826b6b40c255891c37ac046a25836a575
Subproject commit b0de1dcca26c0ebfb8011b8e59dd17fc399db0ff

2
externals/fmt vendored

@ -1 +1 @@
Subproject commit 8ee89546ffcf046309d1f0d38c0393f02fde56c8
Subproject commit 64db979e38ec644b1798e41610b28c8d2c8a2739

2
externals/glslang vendored

@ -1 +1 @@
Subproject commit a0995c49ebcaca2c6d3b03efbabf74f3843decdb
Subproject commit ba1640446f3826a518721d1f083f3a8cca1120c3

1
externals/libusb vendored Submodule

@ -0,0 +1 @@
Subproject commit a63a7e43e0950a595cf4b98a0eaf4051749ace5f

@ -1 +1 @@
Subproject commit 1a1824df7ac798177a521eed952720681b0bf482
Subproject commit a413fcc9c46a020a746907136a384c227f3cd095

2
externals/pugixml vendored

@ -1 +1 @@
Subproject commit 4bc14418d12d289dd9978fdce9490a45deeb653e
Subproject commit caade5a28aad86b92a4b5337a9dc70c4ba73c5eb

2
externals/robin-map vendored

@ -1 +1 @@
Subproject commit fe845fd7852ef541c5479ae23b3d36b57f8608ee
Subproject commit 4ec1bf19c6a96125ea22062f38c2cf5b958e448e

2
externals/sdl3 vendored

@ -1 +1 @@
Subproject commit a336b62d8b0b97b09214e053203e442e2b6e2be5
Subproject commit 4093e4a193971ef1d4928158e0a1832be42e4599

2
externals/sirit vendored

@ -1 +1 @@
Subproject commit 8b9b12c2089505ac8b10fa56bf56b3ed49d9d7b0
Subproject commit 427a42c9ed99b38204d9107bc3dc14e92458acf1

2
externals/toml11 vendored

@ -1 +1 @@
Subproject commit 7f6c574ff5aa1053534e7e19c0a4f22bf4c6aaca
Subproject commit a01fe3b4c14c6d7b99ee3f07c9e80058c6403097

2
externals/vma vendored

@ -1 +1 @@
Subproject commit 5a53a198945ba8260fbc58fadb788745ce6aa263
Subproject commit f378e7b3f18f6e2b06b957f6ba7b1c7207d2a536

@ -1 +1 @@
Subproject commit a03d2f6d5753b365d704d58161825890baad0755
Subproject commit 5ceb9ed481e58e705d0d9b5326537daedd06b97d

@ -1 +1 @@
Subproject commit f00c973a6ab2a23573708568b8ef4acc20a9d36b
Subproject commit f35b0948d36a736e6a2d052ae295a3ffde09703f

2
externals/xbyak vendored

@ -1 +1 @@
Subproject commit 4e44f4614ddbf038f2a6296f5b906d5c72691e0f
Subproject commit 44a72f369268f7d552650891b296693e91db86bb

2
externals/xxhash vendored

@ -1 +1 @@
Subproject commit 2bf8313b934633b2a5b7e8fd239645b85e10c852
Subproject commit 953a09abc39096da9e216b6eb0002c681cdc1199

2
externals/zlib-ng vendored

@ -1 +1 @@
Subproject commit d54e3769be0c522015b784eca2af258b1c026107
Subproject commit fd0d263cedab1a136f40d65199987e3eaeecfcbd

2
externals/zydis vendored

@ -1 +1 @@
Subproject commit bffbb610cfea643b98e87658b9058382f7522807
Subproject commit 120e0e705f8e3b507dc49377ac2879979f0d545c

1195
src/common/aes.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -7,10 +7,10 @@
#include <fmt/xchar.h> // for wstring support
#include <toml.hpp>
#include "common/config.h"
#include "common/logging/formatter.h"
#include "common/path_util.h"
#include "config.h"
#include "logging/formatter.h"
#include "version.h"
#include "common/scm_rev.h"
namespace toml {
template <typename TC, typename K>
@ -32,6 +32,7 @@ std::filesystem::path find_fs_path_or(const basic_value<TC>& v, const K& ky,
namespace Config {
static bool isNeo = false;
static bool isDevKit = false;
static bool playBGM = false;
static bool isTrophyPopupDisabled = false;
static int BGMvolume = 50;
@ -40,7 +41,7 @@ static u32 screenWidth = 1280;
static u32 screenHeight = 720;
static s32 gpuId = -1; // Vulkan physical device index. Set to negative for auto select
static std::string logFilter;
static std::string logType = "async";
static std::string logType = "sync";
static std::string userName = "shadPS4";
static std::string updateChannel;
static std::string chooseHomeTab;
@ -53,7 +54,7 @@ static bool isShaderDebug = false;
static bool isShowSplash = false;
static bool isAutoUpdate = false;
static bool isAlwaysShowChangelog = false;
static bool isLeftSideTrophy = false;
static std::string isSideTrophy = "right";
static bool isNullGpu = false;
static bool shouldCopyGPUBuffers = false;
static bool shouldDumpShaders = false;
@ -74,14 +75,14 @@ static double trophyNotificationDuration = 6.0;
static bool useUnifiedInputConfig = true;
static bool overrideControllerColor = false;
static int controllerCustomColorRGB[3] = {0, 0, 255};
static bool separateupdatefolder = false;
static bool compatibilityData = false;
static bool checkCompatibilityOnStartup = false;
static std::string trophyKey;
// Gui
static bool load_game_size = true;
std::vector<std::filesystem::path> settings_install_dirs = {};
static std::vector<GameInstallDir> settings_install_dirs = {};
std::vector<bool> install_dirs_enabled = {};
std::filesystem::path settings_addon_install_dir = {};
std::filesystem::path save_data_path = {};
u32 main_window_geometry_x = 400;
@ -96,7 +97,6 @@ u32 m_slider_pos_grid = 0;
u32 m_table_mode = 0;
u32 m_window_size_W = 1280;
u32 m_window_size_H = 720;
std::vector<std::string> m_pkg_viewer;
std::vector<std::string> m_elf_viewer;
std::vector<std::string> m_recent_files;
std::string emulator_language = "en_US";
@ -105,6 +105,7 @@ static bool showBackgroundImage = true;
static bool isFullscreen = false;
static std::string fullscreenMode = "Windowed";
static bool isHDRAllowed = false;
static bool showLabelsUnderIcons = true;
// Language
u32 m_language = 1; // english
@ -166,10 +167,22 @@ bool isNeoModeConsole() {
return isNeo;
}
bool isDevKitConsole() {
return isDevKit;
}
bool getIsFullscreen() {
return isFullscreen;
}
bool getShowLabelsUnderIcons() {
return showLabelsUnderIcons;
}
bool setShowLabelsUnderIcons() {
return false;
}
std::string getFullscreenMode() {
return fullscreenMode;
}
@ -270,8 +283,8 @@ bool alwaysShowChangelog() {
return isAlwaysShowChangelog;
}
bool leftSideTrophy() {
return isLeftSideTrophy;
std::string sideTrophy() {
return isSideTrophy;
}
bool nullGpu() {
@ -338,10 +351,6 @@ void setVkGuestMarkersEnabled(bool enable) {
vkGuestMarkers = enable;
}
bool getSeparateUpdateEnabled() {
return separateupdatefolder;
}
bool getCompatibilityEnabled() {
return compatibilityData;
}
@ -381,8 +390,9 @@ void setAutoUpdate(bool enable) {
void setAlwaysShowChangelog(bool enable) {
isAlwaysShowChangelog = enable;
}
void setLeftSideTrophy(bool enable) {
isLeftSideTrophy = enable;
void setSideTrophy(std::string side) {
isSideTrophy = side;
}
void setNullGpu(bool enable) {
@ -420,6 +430,9 @@ void setVblankDiv(u32 value) {
void setIsFullscreen(bool enable) {
isFullscreen = enable;
}
static void setShowLabelsUnderIcons(bool enable) {
showLabelsUnderIcons = enable;
}
void setFullscreenMode(std::string mode) {
fullscreenMode = mode;
@ -499,10 +512,6 @@ void setIsMotionControlsEnabled(bool use) {
isMotionControlsEnabled = use;
}
void setSeparateUpdateEnabled(bool use) {
separateupdatefolder = use;
}
void setCompatibilityEnabled(bool use) {
compatibilityData = use;
}
@ -518,22 +527,34 @@ void setMainWindowGeometry(u32 x, u32 y, u32 w, u32 h) {
main_window_geometry_h = h;
}
bool addGameInstallDir(const std::filesystem::path& dir) {
if (std::find(settings_install_dirs.begin(), settings_install_dirs.end(), dir) ==
settings_install_dirs.end()) {
settings_install_dirs.push_back(dir);
return true;
bool addGameInstallDir(const std::filesystem::path& dir, bool enabled) {
for (const auto& install_dir : settings_install_dirs) {
if (install_dir.path == dir) {
return false;
}
}
return false;
settings_install_dirs.push_back({dir, enabled});
return true;
}
void removeGameInstallDir(const std::filesystem::path& dir) {
auto iterator = std::find(settings_install_dirs.begin(), settings_install_dirs.end(), dir);
auto iterator =
std::find_if(settings_install_dirs.begin(), settings_install_dirs.end(),
[&dir](const GameInstallDir& install_dir) { return install_dir.path == dir; });
if (iterator != settings_install_dirs.end()) {
settings_install_dirs.erase(iterator);
}
}
void setGameInstallDirEnabled(const std::filesystem::path& dir, bool enabled) {
auto iterator =
std::find_if(settings_install_dirs.begin(), settings_install_dirs.end(),
[&dir](const GameInstallDir& install_dir) { return install_dir.path == dir; });
if (iterator != settings_install_dirs.end()) {
iterator->enabled = enabled;
}
}
void setAddonInstallDir(const std::filesystem::path& dir) {
settings_addon_install_dir = dir;
}
@ -570,11 +591,6 @@ void setMainWindowHeight(u32 height) {
m_window_size_H = height;
}
void setPkgViewer(const std::vector<std::string>& pkgList) {
m_pkg_viewer.resize(pkgList.size());
m_pkg_viewer = pkgList;
}
void setElfViewer(const std::vector<std::string>& elfList) {
m_elf_viewer.resize(elfList.size());
m_elf_viewer = elfList;
@ -589,8 +605,15 @@ void setEmulatorLanguage(std::string language) {
emulator_language = language;
}
void setGameInstallDirs(const std::vector<std::filesystem::path>& settings_install_dirs_config) {
settings_install_dirs = settings_install_dirs_config;
void setGameInstallDirs(const std::vector<std::filesystem::path>& dirs_config) {
settings_install_dirs.clear();
for (const auto& dir : dirs_config) {
settings_install_dirs.push_back({dir, true});
}
}
void setAllGameInstallDirs(const std::vector<GameInstallDir>& dirs_config) {
settings_install_dirs = dirs_config;
}
void setSaveDataPath(const std::filesystem::path& path) {
@ -613,8 +636,22 @@ u32 getMainWindowGeometryH() {
return main_window_geometry_h;
}
const std::vector<std::filesystem::path>& getGameInstallDirs() {
return settings_install_dirs;
const std::vector<std::filesystem::path> getGameInstallDirs() {
std::vector<std::filesystem::path> enabled_dirs;
for (const auto& dir : settings_install_dirs) {
if (dir.enabled) {
enabled_dirs.push_back(dir.path);
}
}
return enabled_dirs;
}
const std::vector<bool> getGameInstallDirsEnabled() {
std::vector<bool> enabled_dirs;
for (const auto& dir : settings_install_dirs) {
enabled_dirs.push_back(dir.enabled);
}
return enabled_dirs;
}
std::filesystem::path getAddonInstallDir() {
@ -657,10 +694,6 @@ u32 getMainWindowHeight() {
return m_window_size_H;
}
std::vector<std::string> getPkgViewer() {
return m_pkg_viewer;
}
std::vector<std::string> getElfViewer() {
return m_elf_viewer;
}
@ -720,6 +753,7 @@ void load(const std::filesystem::path& path) {
const toml::value& general = data.at("General");
isNeo = toml::find_or<bool>(general, "isPS4Pro", false);
isDevKit = toml::find_or<bool>(general, "isDevKit", false);
playBGM = toml::find_or<bool>(general, "playBGM", false);
isTrophyPopupDisabled = toml::find_or<bool>(general, "isTrophyPopupDisabled", false);
trophyNotificationDuration =
@ -729,7 +763,7 @@ void load(const std::filesystem::path& path) {
logFilter = toml::find_or<std::string>(general, "logFilter", "");
logType = toml::find_or<std::string>(general, "logType", "sync");
userName = toml::find_or<std::string>(general, "userName", "shadPS4");
if (Common::isRelease) {
if (Common::g_is_release) {
updateChannel = toml::find_or<std::string>(general, "updateChannel", "Release");
} else {
updateChannel = toml::find_or<std::string>(general, "updateChannel", "Nightly");
@ -737,8 +771,7 @@ void load(const std::filesystem::path& path) {
isShowSplash = toml::find_or<bool>(general, "showSplash", true);
isAutoUpdate = toml::find_or<bool>(general, "autoUpdate", false);
isAlwaysShowChangelog = toml::find_or<bool>(general, "alwaysShowChangelog", false);
isLeftSideTrophy = toml::find_or<bool>(general, "leftSideTrophy", false);
separateupdatefolder = toml::find_or<bool>(general, "separateUpdateEnabled", false);
isSideTrophy = toml::find_or<std::string>(general, "sideTrophy", "right");
compatibilityData = toml::find_or<bool>(general, "compatibilityEnabled", false);
checkCompatibilityOnStartup =
toml::find_or<bool>(general, "checkCompatibilityOnStartup", false);
@ -807,9 +840,23 @@ void load(const std::filesystem::path& path) {
m_window_size_H = toml::find_or<int>(gui, "mw_height", 0);
const auto install_dir_array =
toml::find_or<std::vector<std::string>>(gui, "installDirs", {});
for (const auto& dir : install_dir_array) {
addGameInstallDir(std::filesystem::path{dir});
toml::find_or<std::vector<std::u8string>>(gui, "installDirs", {});
try {
install_dirs_enabled = toml::find<std::vector<bool>>(gui, "installDirsEnabled");
} catch (...) {
// If it does not exist, assume that all are enabled.
install_dirs_enabled.resize(install_dir_array.size(), true);
}
if (install_dirs_enabled.size() < install_dir_array.size()) {
install_dirs_enabled.resize(install_dir_array.size(), true);
}
settings_install_dirs.clear();
for (size_t i = 0; i < install_dir_array.size(); i++) {
settings_install_dirs.push_back(
{std::filesystem::path{install_dir_array[i]}, install_dirs_enabled[i]});
}
save_data_path = toml::find_fs_path_or(gui, "saveDataPath", {});
@ -819,7 +866,6 @@ void load(const std::filesystem::path& path) {
main_window_geometry_y = toml::find_or<int>(gui, "geometry_y", 0);
main_window_geometry_w = toml::find_or<int>(gui, "geometry_w", 0);
main_window_geometry_h = toml::find_or<int>(gui, "geometry_h", 0);
m_pkg_viewer = toml::find_or<std::vector<std::string>>(gui, "pkgDirs", {});
m_elf_viewer = toml::find_or<std::vector<std::string>>(gui, "elfDirs", {});
m_recent_files = toml::find_or<std::vector<std::string>>(gui, "recentFiles", {});
m_table_mode = toml::find_or<int>(gui, "gameTableMode", 0);
@ -852,6 +898,37 @@ void load(const std::filesystem::path& path) {
}
}
void sortTomlSections(toml::ordered_value& data) {
toml::ordered_value ordered_data;
std::vector<std::string> section_order = {"General", "Input", "GPU", "Vulkan",
"Debug", "Keys", "GUI", "Settings"};
for (const auto& section : section_order) {
if (data.contains(section)) {
std::vector<std::string> keys;
for (const auto& item : data.at(section).as_table()) {
keys.push_back(item.first);
}
std::sort(keys.begin(), keys.end(), [](const std::string& a, const std::string& b) {
return std::lexicographical_compare(
a.begin(), a.end(), b.begin(), b.end(), [](char a_char, char b_char) {
return std::tolower(a_char) < std::tolower(b_char);
});
});
toml::ordered_value ordered_section;
for (const auto& key : keys) {
ordered_section[key] = data.at(section).at(key);
}
ordered_data[section] = ordered_section;
}
}
data = ordered_data;
}
void save(const std::filesystem::path& path) {
toml::ordered_value data;
@ -875,6 +952,7 @@ void save(const std::filesystem::path& path) {
}
data["General"]["isPS4Pro"] = isNeo;
data["General"]["isDevKit"] = isDevKit;
data["General"]["isTrophyPopupDisabled"] = isTrophyPopupDisabled;
data["General"]["trophyNotificationDuration"] = trophyNotificationDuration;
data["General"]["playBGM"] = playBGM;
@ -888,8 +966,7 @@ void save(const std::filesystem::path& path) {
data["General"]["showSplash"] = isShowSplash;
data["General"]["autoUpdate"] = isAutoUpdate;
data["General"]["alwaysShowChangelog"] = isAlwaysShowChangelog;
data["General"]["leftSideTrophy"] = isLeftSideTrophy;
data["General"]["separateUpdateEnabled"] = separateupdatefolder;
data["General"]["sideTrophy"] = isSideTrophy;
data["General"]["compatibilityEnabled"] = compatibilityData;
data["General"]["checkCompatibilityOnStartup"] = checkCompatibilityOnStartup;
data["Input"]["cursorState"] = cursorState;
@ -921,14 +998,37 @@ void save(const std::filesystem::path& path) {
data["Debug"]["CollectShader"] = isShaderDebug;
data["Debug"]["isSeparateLogFilesEnabled"] = isSeparateLogFilesEnabled;
data["Debug"]["FPSColor"] = isFpsColor;
data["Keys"]["TrophyKey"] = trophyKey;
std::vector<std::string> install_dirs;
for (const auto& dirString : settings_install_dirs) {
install_dirs.emplace_back(std::string{fmt::UTF(dirString.u8string()).data});
std::vector<bool> install_dirs_enabled;
// temporary structure for ordering
struct DirEntry {
std::string path_str;
bool enabled;
};
std::vector<DirEntry> sorted_dirs;
for (const auto& dirInfo : settings_install_dirs) {
sorted_dirs.push_back(
{std::string{fmt::UTF(dirInfo.path.u8string()).data}, dirInfo.enabled});
}
// Sort directories alphabetically
std::sort(sorted_dirs.begin(), sorted_dirs.end(), [](const DirEntry& a, const DirEntry& b) {
return std::lexicographical_compare(
a.path_str.begin(), a.path_str.end(), b.path_str.begin(), b.path_str.end(),
[](char a_char, char b_char) { return std::tolower(a_char) < std::tolower(b_char); });
});
for (const auto& entry : sorted_dirs) {
install_dirs.push_back(entry.path_str);
install_dirs_enabled.push_back(entry.enabled);
}
data["GUI"]["installDirs"] = install_dirs;
data["GUI"]["installDirsEnabled"] = install_dirs_enabled;
data["GUI"]["saveDataPath"] = std::string{fmt::UTF(save_data_path.u8string()).data};
data["GUI"]["loadGameSizeEnabled"] = load_game_size;
@ -939,9 +1039,13 @@ void save(const std::filesystem::path& path) {
data["GUI"]["showBackgroundImage"] = showBackgroundImage;
data["Settings"]["consoleLanguage"] = m_language;
// Sorting of TOML sections
sortTomlSections(data);
std::ofstream file(path, std::ios::binary);
file << data;
file.close();
saveMainWindow(path);
}
@ -979,10 +1083,12 @@ void saveMainWindow(const std::filesystem::path& path) {
data["GUI"]["geometry_y"] = main_window_geometry_y;
data["GUI"]["geometry_w"] = main_window_geometry_w;
data["GUI"]["geometry_h"] = main_window_geometry_h;
data["GUI"]["pkgDirs"] = m_pkg_viewer;
data["GUI"]["elfDirs"] = m_elf_viewer;
data["GUI"]["recentFiles"] = m_recent_files;
// Sorting of TOML sections
sortTomlSections(data);
std::ofstream file(path, std::ios::binary);
file << data;
file.close();
@ -991,6 +1097,7 @@ void saveMainWindow(const std::filesystem::path& path) {
void setDefaultValues() {
isHDRAllowed = false;
isNeo = false;
isDevKit = false;
isFullscreen = false;
isTrophyPopupDisabled = false;
playBGM = false;
@ -999,9 +1106,9 @@ void setDefaultValues() {
screenWidth = 1280;
screenHeight = 720;
logFilter = "";
logType = "async";
logType = "sync";
userName = "shadPS4";
if (Common::isRelease) {
if (Common::g_is_release) {
updateChannel = "Release";
} else {
updateChannel = "Nightly";
@ -1018,7 +1125,7 @@ void setDefaultValues() {
isShowSplash = false;
isAutoUpdate = false;
isAlwaysShowChangelog = false;
isLeftSideTrophy = false;
isSideTrophy = "right";
isNullGpu = false;
shouldDumpShaders = false;
vblankDivider = 1;
@ -1032,7 +1139,6 @@ void setDefaultValues() {
emulator_language = "en_US";
m_language = 1;
gpuId = -1;
separateupdatefolder = false;
compatibilityData = false;
checkCompatibilityOnStartup = false;
backgroundImageOpacity = 50;

View File

@ -9,6 +9,11 @@
namespace Config {
struct GameInstallDir {
std::filesystem::path path;
bool enabled;
};
enum HideCursorState : s16 { Never, Idle, Always };
void load(const std::filesystem::path& path);
@ -21,13 +26,15 @@ bool GetLoadGameSizeEnabled();
std::filesystem::path GetSaveDataPath();
void setLoadGameSizeEnabled(bool enable);
bool getIsFullscreen();
bool getShowLabelsUnderIcons();
bool setShowLabelsUnderIcons();
std::string getFullscreenMode();
bool isNeoModeConsole();
bool isDevKitConsole();
bool getPlayBGM();
int getBGMvolume();
bool getisTrophyPopupDisabled();
bool getEnableDiscordRPC();
bool getSeparateUpdateEnabled();
bool getCompatibilityEnabled();
bool getCheckCompatibilityOnStartup();
int getBackgroundImageOpacity();
@ -63,7 +70,7 @@ bool collectShadersForDebug();
bool showSplash();
bool autoUpdate();
bool alwaysShowChangelog();
bool leftSideTrophy();
std::string sideTrophy();
bool nullGpu();
bool copyGPUCmdBuffers();
bool dumpShaders();
@ -77,7 +84,7 @@ void setCollectShaderForDebug(bool enable);
void setShowSplash(bool enable);
void setAutoUpdate(bool enable);
void setAlwaysShowChangelog(bool enable);
void setLeftSideTrophy(bool enable);
void setSideTrophy(std::string side);
void setNullGpu(bool enable);
void setAllowHDR(bool enable);
void setCopyGPUCmdBuffers(bool enable);
@ -97,8 +104,8 @@ void setNeoMode(bool enable);
void setUserName(const std::string& type);
void setUpdateChannel(const std::string& type);
void setChooseHomeTab(const std::string& type);
void setSeparateUpdateEnabled(bool use);
void setGameInstallDirs(const std::vector<std::filesystem::path>& settings_install_dirs_config);
void setGameInstallDirs(const std::vector<std::filesystem::path>& dirs_config);
void setAllGameInstallDirs(const std::vector<GameInstallDir>& dirs_config);
void setSaveDataPath(const std::filesystem::path& path);
void setCompatibilityEnabled(bool use);
void setCheckCompatibilityOnStartup(bool use);
@ -133,8 +140,9 @@ void setVkGuestMarkersEnabled(bool enable);
// Gui
void setMainWindowGeometry(u32 x, u32 y, u32 w, u32 h);
bool addGameInstallDir(const std::filesystem::path& dir);
bool addGameInstallDir(const std::filesystem::path& dir, bool enabled = true);
void removeGameInstallDir(const std::filesystem::path& dir);
void setGameInstallDirEnabled(const std::filesystem::path& dir, bool enabled);
void setAddonInstallDir(const std::filesystem::path& dir);
void setMainWindowTheme(u32 theme);
void setIconSize(u32 size);
@ -144,7 +152,6 @@ void setSliderPositionGrid(u32 pos);
void setTableMode(u32 mode);
void setMainWindowWidth(u32 width);
void setMainWindowHeight(u32 height);
void setPkgViewer(const std::vector<std::string>& pkgList);
void setElfViewer(const std::vector<std::string>& elfList);
void setRecentFiles(const std::vector<std::string>& recentFiles);
void setEmulatorLanguage(std::string language);
@ -153,7 +160,8 @@ u32 getMainWindowGeometryX();
u32 getMainWindowGeometryY();
u32 getMainWindowGeometryW();
u32 getMainWindowGeometryH();
const std::vector<std::filesystem::path>& getGameInstallDirs();
const std::vector<std::filesystem::path> getGameInstallDirs();
const std::vector<bool> getGameInstallDirsEnabled();
std::filesystem::path getAddonInstallDir();
u32 getMainWindowTheme();
u32 getIconSize();
@ -163,7 +171,6 @@ u32 getSliderPositionGrid();
u32 getTableMode();
u32 getMainWindowWidth();
u32 getMainWindowHeight();
std::vector<std::string> getPkgViewer();
std::vector<std::string> getElfViewer();
std::vector<std::string> getRecentFiles();
std::string getEmulatorLanguage();

View File

@ -3,6 +3,7 @@
#pragma once
#include <filesystem>
#include <string>
#include <string_view>
@ -69,6 +70,8 @@ class ElfInfo {
u32 raw_firmware_ver = 0;
PSFAttributes psf_attributes{};
std::filesystem::path splash_path{};
public:
static constexpr u32 FW_15 = 0x1500000;
static constexpr u32 FW_16 = 0x1600000;
@ -116,6 +119,10 @@ public:
ASSERT(initialized);
return psf_attributes;
}
[[nodiscard]] const std::filesystem::path& GetSplashPath() const {
return splash_path;
}
};
} // namespace Common

View File

@ -125,12 +125,15 @@ namespace {
[[nodiscard]] constexpr int ToSeekOrigin(SeekOrigin origin) {
switch (origin) {
case SeekOrigin::SetOrigin:
default:
return SEEK_SET;
case SeekOrigin::CurrentPosition:
return SEEK_CUR;
case SeekOrigin::End:
return SEEK_END;
default:
LOG_ERROR(Common_Filesystem, "Unsupported origin {}, defaulting to SEEK_SET",
static_cast<u32>(origin));
return SEEK_SET;
}
}
@ -377,20 +380,6 @@ bool IOFile::Seek(s64 offset, SeekOrigin origin) const {
return false;
}
if (False(file_access_mode & (FileAccessMode::Write | FileAccessMode::Append))) {
u64 size = GetSize();
if (origin == SeekOrigin::CurrentPosition && Tell() + offset > size) {
LOG_ERROR(Common_Filesystem, "Seeking past the end of the file");
return false;
} else if (origin == SeekOrigin::SetOrigin && (u64)offset > size) {
LOG_ERROR(Common_Filesystem, "Seeking past the end of the file");
return false;
} else if (origin == SeekOrigin::End && offset > 0) {
LOG_ERROR(Common_Filesystem, "Seeking past the end of the file");
return false;
}
}
errno = 0;
const auto seek_result = fseeko(file, offset, ToSeekOrigin(origin)) == 0;

View File

@ -61,6 +61,8 @@ enum class SeekOrigin : u32 {
SetOrigin, // Seeks from the start of the file.
CurrentPosition, // Seeks from the current file pointer position.
End, // Seeks from the end of the file.
SeekHole, // Seeks from the start of the next hole in the file.
SeekData, // Seeks from the start of the next non-hole region in the file.
};
class IOFile final {

View File

@ -101,6 +101,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
SUB(Lib, Ssl2) \
SUB(Lib, SysModule) \
SUB(Lib, Move) \
SUB(Lib, NpAuth) \
SUB(Lib, NpCommon) \
SUB(Lib, NpManager) \
SUB(Lib, NpScore) \

View File

@ -69,6 +69,7 @@ enum class Class : u8 {
Lib_Http2, ///< The LibSceHttp2 implementation.
Lib_SysModule, ///< The LibSceSysModule implementation
Lib_NpCommon, ///< The LibSceNpCommon implementation
Lib_NpAuth, ///< The LibSceNpAuth implementation
Lib_NpManager, ///< The LibSceNpManager implementation
Lib_NpScore, ///< The LibSceNpScore implementation
Lib_NpTrophy, ///< The LibSceNpTrophy implementation

View File

@ -169,7 +169,8 @@ void OnGameLoaded() {
if (type == "mask_jump32")
patchMask = MemoryPatcher::PatchMask::Mask_Jump32;
if (type == "mask" || type == "mask_jump32" && !maskOffsetStr.empty()) {
if ((type == "mask" || type == "mask_jump32") &&
!maskOffsetStr.empty()) {
maskOffsetValue = std::stoi(maskOffsetStr, 0, 10);
}

View File

@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <fstream>
#include <unordered_map>
#include "common/logging/log.h"
#include "common/path_util.h"
@ -16,6 +17,8 @@
#ifdef _WIN32
// This is the maximum number of UTF-16 code units permissible in Windows file paths
#define MAX_PATH 260
#include <Shlobj.h>
#include <windows.h>
#else
// This is the maximum number of UTF-8 code units permissible in all other OSes' file paths
#define MAX_PATH 1024
@ -57,7 +60,7 @@ static CFURLRef UntranslocateBundlePath(const CFURLRef bundle_path) {
return nullptr;
}
static std::filesystem::path GetBundleParentDirectory() {
static std::optional<std::filesystem::path> GetBundleParentDirectory() {
if (CFBundleRef bundle_ref = CFBundleGetMainBundle()) {
if (CFURLRef bundle_url_ref = CFBundleCopyBundleURL(bundle_ref)) {
SCOPE_EXIT {
@ -80,14 +83,16 @@ static std::filesystem::path GetBundleParentDirectory() {
}
}
}
return std::filesystem::current_path();
return std::nullopt;
}
#endif
static auto UserPaths = [] {
#ifdef __APPLE__
#if defined(__APPLE__) && defined(ENABLE_QT_GUI)
// Set the current path to the directory containing the app bundle.
std::filesystem::current_path(GetBundleParentDirectory());
if (const auto bundle_dir = GetBundleParentDirectory()) {
std::filesystem::current_path(*bundle_dir);
}
#endif
// Try the portable user directory first.
@ -105,6 +110,10 @@ static auto UserPaths = [] {
} else {
user_dir = std::filesystem::path(getenv("HOME")) / ".local" / "share" / "shadPS4";
}
#elif _WIN32
TCHAR appdata[MAX_PATH] = {0};
SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, appdata);
user_dir = std::filesystem::path(appdata) / "shadPS4";
#endif
}
@ -130,6 +139,21 @@ static auto UserPaths = [] {
create_path(PathType::MetaDataDir, user_dir / METADATA_DIR);
create_path(PathType::CustomTrophy, user_dir / CUSTOM_TROPHY);
std::ofstream notice_file(user_dir / CUSTOM_TROPHY / "Notice.txt");
if (notice_file.is_open()) {
notice_file
<< "++++++++++++++++++++++++++++++++\n+ Custom Trophy Images / Sound "
"+\n++++++++++++++++++++++++++++++++\n\nYou can add custom images to the "
"trophies.\n*We recommend a square resolution image, for example 200x200, 500x500, "
"the same size as the height and width.\nIn this folder ('user\\custom_trophy'), "
"add the files with the following "
"names:\n\nbronze.png\nsilver.png\ngold.png\nplatinum.png\n\nYou can add a custom "
"sound for trophy notifications.\n*By default, no audio is played unless it is in "
"this folder and you are using the QT version.\nIn this folder "
"('user\\custom_trophy'), add the files with the following names:\n\ntrophy.mp3";
notice_file.close();
}
return paths;
}();
@ -223,4 +247,4 @@ std::filesystem::path PathFromQString(const QString& path) {
}
#endif
} // namespace Common::FS
} // namespace Common::FS

View File

@ -3,21 +3,17 @@
#include "common/scm_rev.h"
#define GIT_REV "@GIT_REV@"
#define GIT_BRANCH "@GIT_BRANCH@"
#define GIT_DESC "@GIT_DESC@"
#define GIT_REMOTE_NAME "@GIT_REMOTE_NAME@"
#define GIT_REMOTE_URL "@GIT_REMOTE_URL@"
#define BUILD_DATE "@BUILD_DATE@"
namespace Common {
const char g_scm_rev[] = GIT_REV;
const char g_scm_branch[] = GIT_BRANCH;
const char g_scm_desc[] = GIT_DESC;
const char g_scm_remote_name[] = GIT_REMOTE_NAME;
const char g_scm_remote_url[] = GIT_REMOTE_URL;
const char g_scm_date[] = BUILD_DATE;
constexpr char g_version[] = "@APP_VERSION@";
constexpr bool g_is_release = @APP_IS_RELEASE@;
constexpr char g_scm_rev[] = "@GIT_REV@";
constexpr char g_scm_branch[] = "@GIT_BRANCH@";
constexpr char g_scm_desc[] = "@GIT_DESC@";
constexpr char g_scm_remote_name[] = "@GIT_REMOTE_NAME@";
constexpr char g_scm_remote_url[] = "@GIT_REMOTE_URL@";
constexpr char g_scm_date[] = "@BUILD_DATE@";
} // namespace

View File

@ -5,6 +5,9 @@
namespace Common {
extern const char g_version[];
extern const bool g_is_release;
extern const char g_scm_rev[];
extern const char g_scm_branch[];
extern const char g_scm_desc[];

180
src/common/sha1.h Normal file
View File

@ -0,0 +1,180 @@
// SPDX-FileCopyrightText: 2012 SAURAV MOHAPATRA <mohaps@gmail.com>
// SPDX-License-Identifier: MIT
#pragma once
#include <cstdint>
#include <cstdlib>
#include <cstring>
namespace sha1 {
class SHA1 {
public:
typedef uint32_t digest32_t[5];
typedef uint8_t digest8_t[20];
inline static uint32_t LeftRotate(uint32_t value, size_t count) {
return (value << count) ^ (value >> (32 - count));
}
SHA1() {
reset();
}
virtual ~SHA1() {}
SHA1(const SHA1& s) {
*this = s;
}
const SHA1& operator=(const SHA1& s) {
memcpy(m_digest, s.m_digest, 5 * sizeof(uint32_t));
memcpy(m_block, s.m_block, 64);
m_blockByteIndex = s.m_blockByteIndex;
m_byteCount = s.m_byteCount;
return *this;
}
SHA1& reset() {
m_digest[0] = 0x67452301;
m_digest[1] = 0xEFCDAB89;
m_digest[2] = 0x98BADCFE;
m_digest[3] = 0x10325476;
m_digest[4] = 0xC3D2E1F0;
m_blockByteIndex = 0;
m_byteCount = 0;
return *this;
}
SHA1& processByte(uint8_t octet) {
this->m_block[this->m_blockByteIndex++] = octet;
++this->m_byteCount;
if (m_blockByteIndex == 64) {
this->m_blockByteIndex = 0;
processBlock();
}
return *this;
}
SHA1& processBlock(const void* const start, const void* const end) {
const uint8_t* begin = static_cast<const uint8_t*>(start);
const uint8_t* finish = static_cast<const uint8_t*>(end);
while (begin != finish) {
processByte(*begin);
begin++;
}
return *this;
}
SHA1& processBytes(const void* const data, size_t len) {
const uint8_t* block = static_cast<const uint8_t*>(data);
processBlock(block, block + len);
return *this;
}
const uint32_t* getDigest(digest32_t digest) {
size_t bitCount = this->m_byteCount * 8;
processByte(0x80);
if (this->m_blockByteIndex > 56) {
while (m_blockByteIndex != 0) {
processByte(0);
}
while (m_blockByteIndex < 56) {
processByte(0);
}
} else {
while (m_blockByteIndex < 56) {
processByte(0);
}
}
processByte(0);
processByte(0);
processByte(0);
processByte(0);
processByte(static_cast<unsigned char>((bitCount >> 24) & 0xFF));
processByte(static_cast<unsigned char>((bitCount >> 16) & 0xFF));
processByte(static_cast<unsigned char>((bitCount >> 8) & 0xFF));
processByte(static_cast<unsigned char>((bitCount) & 0xFF));
memcpy(digest, m_digest, 5 * sizeof(uint32_t));
return digest;
}
const uint8_t* getDigestBytes(digest8_t digest) {
digest32_t d32;
getDigest(d32);
size_t di = 0;
digest[di++] = ((d32[0] >> 24) & 0xFF);
digest[di++] = ((d32[0] >> 16) & 0xFF);
digest[di++] = ((d32[0] >> 8) & 0xFF);
digest[di++] = ((d32[0]) & 0xFF);
digest[di++] = ((d32[1] >> 24) & 0xFF);
digest[di++] = ((d32[1] >> 16) & 0xFF);
digest[di++] = ((d32[1] >> 8) & 0xFF);
digest[di++] = ((d32[1]) & 0xFF);
digest[di++] = ((d32[2] >> 24) & 0xFF);
digest[di++] = ((d32[2] >> 16) & 0xFF);
digest[di++] = ((d32[2] >> 8) & 0xFF);
digest[di++] = ((d32[2]) & 0xFF);
digest[di++] = ((d32[3] >> 24) & 0xFF);
digest[di++] = ((d32[3] >> 16) & 0xFF);
digest[di++] = ((d32[3] >> 8) & 0xFF);
digest[di++] = ((d32[3]) & 0xFF);
digest[di++] = ((d32[4] >> 24) & 0xFF);
digest[di++] = ((d32[4] >> 16) & 0xFF);
digest[di++] = ((d32[4] >> 8) & 0xFF);
digest[di++] = ((d32[4]) & 0xFF);
return digest;
}
protected:
void processBlock() {
uint32_t w[80];
for (size_t i = 0; i < 16; i++) {
w[i] = (m_block[i * 4 + 0] << 24);
w[i] |= (m_block[i * 4 + 1] << 16);
w[i] |= (m_block[i * 4 + 2] << 8);
w[i] |= (m_block[i * 4 + 3]);
}
for (size_t i = 16; i < 80; i++) {
w[i] = LeftRotate((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]), 1);
}
uint32_t a = m_digest[0];
uint32_t b = m_digest[1];
uint32_t c = m_digest[2];
uint32_t d = m_digest[3];
uint32_t e = m_digest[4];
for (std::size_t i = 0; i < 80; ++i) {
uint32_t f = 0;
uint32_t k = 0;
if (i < 20) {
f = (b & c) | (~b & d);
k = 0x5A827999;
} else if (i < 40) {
f = b ^ c ^ d;
k = 0x6ED9EBA1;
} else if (i < 60) {
f = (b & c) | (b & d) | (c & d);
k = 0x8F1BBCDC;
} else {
f = b ^ c ^ d;
k = 0xCA62C1D6;
}
uint32_t temp = LeftRotate(a, 5) + f + e + k + w[i];
e = d;
d = c;
c = LeftRotate(b, 30);
b = a;
a = temp;
}
m_digest[0] += a;
m_digest[1] += b;
m_digest[2] += c;
m_digest[3] += d;
m_digest[4] += e;
}
private:
digest32_t m_digest;
uint8_t m_block[64];
size_t m_blockByteIndex;
size_t m_byteCount;
};
} // namespace sha1

View File

@ -0,0 +1,15 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
template <size_t N, typename C = char>
struct StringLiteral {
static constexpr size_t len = N;
constexpr StringLiteral(const C (&str)[N]) {
std::copy_n(str, N, value);
}
C value[N]{};
};

View File

@ -1,14 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <string>
#include <string_view>
namespace Common {
constexpr char VERSION[] = "0.6.1 WIP";
constexpr bool isRelease = false;
} // namespace Common

View File

@ -22,10 +22,6 @@
#include <windows.h>
#else
#include <pthread.h>
#ifdef __APPLE__
#include <half.hpp>
#include <sys/sysctl.h>
#endif
#endif
using namespace Xbyak::util;
@ -81,490 +77,6 @@ static Xbyak::Address ZydisToXbyakMemoryOperand(const ZydisDecodedOperand& opera
return ptr[expression];
}
static u64 ZydisToXbyakImmediateOperand(const ZydisDecodedOperand& operand) {
ASSERT_MSG(operand.type == ZYDIS_OPERAND_TYPE_IMMEDIATE,
"Expected immediate operand, got type: {}", static_cast<u32>(operand.type));
return operand.imm.value.u;
}
static std::unique_ptr<Xbyak::Operand> ZydisToXbyakOperand(const ZydisDecodedOperand& operand) {
switch (operand.type) {
case ZYDIS_OPERAND_TYPE_REGISTER: {
return std::make_unique<Xbyak::Reg>(ZydisToXbyakRegisterOperand(operand));
}
case ZYDIS_OPERAND_TYPE_MEMORY: {
return std::make_unique<Xbyak::Address>(ZydisToXbyakMemoryOperand(operand));
}
default:
UNREACHABLE_MSG("Unsupported operand type: {}", static_cast<u32>(operand.type));
}
}
static bool OperandUsesRegister(const Xbyak::Operand* operand, int index) {
if (operand->isREG()) {
return operand->getIdx() == index;
}
if (operand->isMEM()) {
const Xbyak::RegExp& reg_exp = operand->getAddress().getRegExp();
return reg_exp.getBase().getIdx() == index || reg_exp.getIndex().getIdx() == index;
}
UNREACHABLE_MSG("Unsupported operand kind: {}", static_cast<u32>(operand->getKind()));
}
static bool IsRegisterAllocated(
const std::initializer_list<const Xbyak::Operand*>& allocated_registers, const int index) {
return std::ranges::find_if(allocated_registers.begin(), allocated_registers.end(),
[index](const Xbyak::Operand* operand) {
return OperandUsesRegister(operand, index);
}) != allocated_registers.end();
}
static Xbyak::Reg AllocateScratchRegister(
const std::initializer_list<const Xbyak::Operand*> allocated_registers, const u32 bits) {
for (int index = Xbyak::Operand::R8; index <= Xbyak::Operand::R15; index++) {
if (!IsRegisterAllocated(allocated_registers, index)) {
return Xbyak::Reg32e(index, static_cast<int>(bits));
}
}
UNREACHABLE_MSG("Out of scratch registers!");
}
#ifdef __APPLE__
static pthread_key_t stack_pointer_slot;
static pthread_key_t patch_stack_slot;
static std::once_flag patch_context_slots_init_flag;
static constexpr u32 patch_stack_size = 0x1000;
static_assert(sizeof(void*) == sizeof(u64),
"Cannot fit a register inside a thread local storage slot.");
static void FreePatchStack(void* patch_stack) {
// Subtract back to the bottom of the stack for free.
std::free(static_cast<u8*>(patch_stack) - patch_stack_size);
}
static void InitializePatchContextSlots() {
ASSERT_MSG(pthread_key_create(&stack_pointer_slot, nullptr) == 0,
"Unable to allocate thread-local register for stack pointer.");
ASSERT_MSG(pthread_key_create(&patch_stack_slot, FreePatchStack) == 0,
"Unable to allocate thread-local register for patch stack.");
}
void InitializeThreadPatchStack() {
std::call_once(patch_context_slots_init_flag, InitializePatchContextSlots);
pthread_setspecific(patch_stack_slot,
static_cast<u8*>(std::malloc(patch_stack_size)) + patch_stack_size);
}
/// Saves the stack pointer to thread local storage and loads the patch stack.
static void SaveStack(Xbyak::CodeGenerator& c) {
std::call_once(patch_context_slots_init_flag, InitializePatchContextSlots);
// Save original stack pointer and load patch stack.
c.putSeg(gs);
c.mov(qword[reinterpret_cast<void*>(stack_pointer_slot * sizeof(void*))], rsp);
c.putSeg(gs);
c.mov(rsp, qword[reinterpret_cast<void*>(patch_stack_slot * sizeof(void*))]);
}
/// Restores the stack pointer from thread local storage.
static void RestoreStack(Xbyak::CodeGenerator& c) {
std::call_once(patch_context_slots_init_flag, InitializePatchContextSlots);
// Save patch stack pointer and load original stack.
c.putSeg(gs);
c.mov(qword[reinterpret_cast<void*>(patch_stack_slot * sizeof(void*))], rsp);
c.putSeg(gs);
c.mov(rsp, qword[reinterpret_cast<void*>(stack_pointer_slot * sizeof(void*))]);
}
#else
// These utilities are not implemented as we can't save anything to thread local storage without
// temporary registers.
void InitializeThreadPatchStack() {
// No-op
}
/// Saves the stack pointer to thread local storage and loads the patch stack.
static void SaveStack(Xbyak::CodeGenerator& c) {
UNIMPLEMENTED();
}
/// Restores the stack pointer from thread local storage.
static void RestoreStack(Xbyak::CodeGenerator& c) {
UNIMPLEMENTED();
}
#endif
/// Switches to the patch stack, saves registers, and restores the original stack.
static void SaveRegisters(Xbyak::CodeGenerator& c, const std::initializer_list<Xbyak::Reg> regs) {
SaveStack(c);
for (const auto& reg : regs) {
c.push(reg.cvt64());
}
RestoreStack(c);
}
/// Switches to the patch stack, restores registers, and restores the original stack.
static void RestoreRegisters(Xbyak::CodeGenerator& c,
const std::initializer_list<Xbyak::Reg> regs) {
SaveStack(c);
for (const auto& reg : regs) {
c.pop(reg.cvt64());
}
RestoreStack(c);
}
/// Switches to the patch stack and stores all registers.
static void SaveContext(Xbyak::CodeGenerator& c, bool save_flags = false) {
SaveStack(c);
for (int reg = Xbyak::Operand::RAX; reg <= Xbyak::Operand::R15; reg++) {
c.push(Xbyak::Reg64(reg));
}
c.lea(rsp, ptr[rsp - 32 * 16]);
for (int reg = 0; reg <= 15; reg++) {
c.vmovdqu(ptr[rsp + 32 * reg], Xbyak::Ymm(reg));
}
if (save_flags) {
c.pushfq();
}
}
/// Restores all registers and restores the original stack.
/// If the destination is a register, it is not restored to preserve the output.
static void RestoreContext(Xbyak::CodeGenerator& c, const Xbyak::Operand& dst,
bool restore_flags = false) {
if (restore_flags) {
c.popfq();
}
for (int reg = 15; reg >= 0; reg--) {
if ((!dst.isXMM() && !dst.isYMM()) || dst.getIdx() != reg) {
c.vmovdqu(Xbyak::Ymm(reg), ptr[rsp + 32 * reg]);
}
}
c.lea(rsp, ptr[rsp + 32 * 16]);
for (int reg = Xbyak::Operand::R15; reg >= Xbyak::Operand::RAX; reg--) {
if (!dst.isREG() || dst.getIdx() != reg) {
c.pop(Xbyak::Reg64(reg));
} else {
c.lea(rsp, ptr[rsp + 8]);
}
}
RestoreStack(c);
}
#ifdef __APPLE__
static void GenerateANDN(const ZydisDecodedOperand* operands, Xbyak::CodeGenerator& c) {
const auto dst = ZydisToXbyakRegisterOperand(operands[0]);
const auto src1 = ZydisToXbyakRegisterOperand(operands[1]);
const auto src2 = ZydisToXbyakOperand(operands[2]);
// Check if src2 is a memory operand or a register different to dst.
// In those cases, we don't need to use a temporary register and are free to modify dst.
// In cases where dst and src2 are the same register, a temporary needs to be used to avoid
// modifying src2.
bool src2_uses_dst = false;
if (src2->isMEM()) {
const auto base = src2->getAddress().getRegExp().getBase().getIdx();
const auto index = src2->getAddress().getRegExp().getIndex().getIdx();
src2_uses_dst = base == dst.getIdx() || index == dst.getIdx();
} else {
ASSERT(src2->isREG());
src2_uses_dst = src2->getReg() == dst;
}
if (!src2_uses_dst) {
if (dst != src1)
c.mov(dst, src1);
c.not_(dst);
c.and_(dst, *src2);
} else {
const auto scratch = AllocateScratchRegister({&dst, &src1, src2.get()}, dst.getBit());
SaveRegisters(c, {scratch});
c.mov(scratch, src1);
c.not_(scratch);
c.and_(scratch, *src2);
c.mov(dst, scratch);
RestoreRegisters(c, {scratch});
}
}
static void GenerateBEXTR(const ZydisDecodedOperand* operands, Xbyak::CodeGenerator& c) {
const auto dst = ZydisToXbyakRegisterOperand(operands[0]);
const auto src = ZydisToXbyakOperand(operands[1]);
const auto start_len = ZydisToXbyakRegisterOperand(operands[2]);
const Xbyak::Reg32e shift(Xbyak::Operand::RCX, static_cast<int>(start_len.getBit()));
const auto scratch1 =
AllocateScratchRegister({&dst, src.get(), &start_len, &shift}, dst.getBit());
const auto scratch2 =
AllocateScratchRegister({&dst, src.get(), &start_len, &shift, &scratch1}, dst.getBit());
if (dst.getIdx() == shift.getIdx()) {
SaveRegisters(c, {scratch1, scratch2});
} else {
SaveRegisters(c, {scratch1, scratch2, shift});
}
c.mov(scratch1, *src);
if (shift.getIdx() != start_len.getIdx()) {
c.mov(shift, start_len);
}
c.shr(scratch1, shift.cvt8());
c.shr(shift, 8);
c.mov(scratch2, 1);
c.shl(scratch2, shift.cvt8());
c.dec(scratch2);
c.mov(dst, scratch1);
c.and_(dst, scratch2);
if (dst.getIdx() == shift.getIdx()) {
RestoreRegisters(c, {scratch2, scratch1});
} else {
RestoreRegisters(c, {shift, scratch2, scratch1});
}
}
static void GenerateBLSI(const ZydisDecodedOperand* operands, Xbyak::CodeGenerator& c) {
const auto dst = ZydisToXbyakRegisterOperand(operands[0]);
const auto src = ZydisToXbyakOperand(operands[1]);
const auto scratch = AllocateScratchRegister({&dst, src.get()}, dst.getBit());
SaveRegisters(c, {scratch});
// BLSI sets CF to zero if source is zero, otherwise it sets CF to one.
Xbyak::Label clear_carry, end;
c.mov(scratch, *src);
c.neg(scratch); // NEG, like BLSI, clears CF if the source is zero and sets it otherwise
c.jnc(clear_carry);
c.and_(scratch, *src);
c.stc(); // setting/clearing carry needs to happen after the AND because that clears CF
c.jmp(end);
c.L(clear_carry);
c.and_(scratch, *src);
// We don't need to clear carry here since AND does that for us
c.L(end);
c.mov(dst, scratch);
RestoreRegisters(c, {scratch});
}
static void GenerateBLSMSK(const ZydisDecodedOperand* operands, Xbyak::CodeGenerator& c) {
const auto dst = ZydisToXbyakRegisterOperand(operands[0]);
const auto src = ZydisToXbyakOperand(operands[1]);
const auto scratch = AllocateScratchRegister({&dst, src.get()}, dst.getBit());
SaveRegisters(c, {scratch});
Xbyak::Label clear_carry, end;
// BLSMSK sets CF to zero if source is NOT zero, otherwise it sets CF to one.
c.mov(scratch, *src);
c.test(scratch, scratch);
c.jnz(clear_carry);
c.dec(scratch);
c.xor_(scratch, *src);
c.stc();
c.jmp(end);
c.L(clear_carry);
c.dec(scratch);
c.xor_(scratch, *src);
// We don't need to clear carry here since XOR does that for us
c.L(end);
c.mov(dst, scratch);
RestoreRegisters(c, {scratch});
}
static void GenerateBLSR(const ZydisDecodedOperand* operands, Xbyak::CodeGenerator& c) {
const auto dst = ZydisToXbyakRegisterOperand(operands[0]);
const auto src = ZydisToXbyakOperand(operands[1]);
const auto scratch = AllocateScratchRegister({&dst, src.get()}, dst.getBit());
SaveRegisters(c, {scratch});
Xbyak::Label clear_carry, end;
// BLSR sets CF to zero if source is NOT zero, otherwise it sets CF to one.
c.mov(scratch, *src);
c.test(scratch, scratch);
c.jnz(clear_carry);
c.dec(scratch);
c.and_(scratch, *src);
c.stc();
c.jmp(end);
c.L(clear_carry);
c.dec(scratch);
c.and_(scratch, *src);
// We don't need to clear carry here since AND does that for us
c.L(end);
c.mov(dst, scratch);
RestoreRegisters(c, {scratch});
}
static __attribute__((sysv_abi)) void PerformVCVTPH2PS(float* out, const half_float::half* in,
const u32 count) {
for (u32 i = 0; i < count; i++) {
out[i] = half_float::half_cast<float>(in[i]);
}
}
static void GenerateVCVTPH2PS(const ZydisDecodedOperand* operands, Xbyak::CodeGenerator& c) {
const auto dst = ZydisToXbyakRegisterOperand(operands[0]);
const auto src = ZydisToXbyakOperand(operands[1]);
const auto float_count = dst.getBit() / 32;
const auto byte_count = float_count * 4;
SaveContext(c, true);
// Allocate stack space for outputs and load into first parameter.
c.sub(rsp, byte_count);
c.mov(rdi, rsp);
if (src->isXMM()) {
// Allocate stack space for inputs and load into second parameter.
c.sub(rsp, byte_count);
c.mov(rsi, rsp);
// Move input to the allocated space.
c.movdqu(ptr[rsp], *reinterpret_cast<Xbyak::Xmm*>(src.get()));
} else {
c.lea(rsi, src->getAddress());
}
// Load float count into third parameter.
c.mov(rdx, float_count);
c.mov(rax, reinterpret_cast<u64>(PerformVCVTPH2PS));
c.call(rax);
if (src->isXMM()) {
// Clean up after inputs space.
c.add(rsp, byte_count);
}
// Load outputs into destination register and clean up space.
if (dst.isYMM()) {
c.vmovdqu(*reinterpret_cast<const Xbyak::Ymm*>(&dst), ptr[rsp]);
} else {
c.movdqu(*reinterpret_cast<const Xbyak::Xmm*>(&dst), ptr[rsp]);
}
c.add(rsp, byte_count);
RestoreContext(c, dst, true);
}
using SingleToHalfFloatConverter = half_float::half (*)(float);
static const SingleToHalfFloatConverter SingleToHalfFloatConverters[4] = {
half_float::half_cast<half_float::half, std::round_to_nearest, float>,
half_float::half_cast<half_float::half, std::round_toward_neg_infinity, float>,
half_float::half_cast<half_float::half, std::round_toward_infinity, float>,
half_float::half_cast<half_float::half, std::round_toward_zero, float>,
};
static __attribute__((sysv_abi)) void PerformVCVTPS2PH(half_float::half* out, const float* in,
const u32 count, const u8 rounding_mode) {
const auto conversion_func = SingleToHalfFloatConverters[rounding_mode];
for (u32 i = 0; i < count; i++) {
out[i] = conversion_func(in[i]);
}
}
static void GenerateVCVTPS2PH(const ZydisDecodedOperand* operands, Xbyak::CodeGenerator& c) {
const auto dst = ZydisToXbyakOperand(operands[0]);
const auto src = ZydisToXbyakRegisterOperand(operands[1]);
const auto ctrl = ZydisToXbyakImmediateOperand(operands[2]);
const auto float_count = src.getBit() / 32;
const auto byte_count = float_count * 4;
SaveContext(c, true);
if (dst->isXMM()) {
// Allocate stack space for outputs and load into first parameter.
c.sub(rsp, byte_count);
c.mov(rdi, rsp);
} else {
c.lea(rdi, dst->getAddress());
}
// Allocate stack space for inputs and load into second parameter.
c.sub(rsp, byte_count);
c.mov(rsi, rsp);
// Move input to the allocated space.
if (src.isYMM()) {
c.vmovdqu(ptr[rsp], *reinterpret_cast<const Xbyak::Ymm*>(&src));
} else {
c.movdqu(ptr[rsp], *reinterpret_cast<const Xbyak::Xmm*>(&src));
}
// Load float count into third parameter.
c.mov(rdx, float_count);
// Load rounding mode into fourth parameter.
if (ctrl & 4) {
// Load from MXCSR.RC.
c.stmxcsr(ptr[rsp - 4]);
c.mov(rcx, ptr[rsp - 4]);
c.shr(rcx, 13);
c.and_(rcx, 3);
} else {
c.mov(rcx, ctrl & 3);
}
c.mov(rax, reinterpret_cast<u64>(PerformVCVTPS2PH));
c.call(rax);
// Clean up after inputs space.
c.add(rsp, byte_count);
if (dst->isXMM()) {
// Load outputs into destination register and clean up space.
c.movdqu(*reinterpret_cast<Xbyak::Xmm*>(dst.get()), ptr[rsp]);
c.add(rsp, byte_count);
}
RestoreContext(c, *dst, true);
}
static bool FilterRosetta2Only(const ZydisDecodedOperand*) {
int ret = 0;
size_t size = sizeof(ret);
if (sysctlbyname("sysctl.proc_translated", &ret, &size, nullptr, 0) != 0) {
return false;
}
return ret;
}
#else // __APPLE__
static bool FilterTcbAccess(const ZydisDecodedOperand* operands) {
const auto& dst_op = operands[0];
const auto& src_op = operands[1];
@ -609,8 +121,6 @@ static void GenerateTcbAccess(const ZydisDecodedOperand* operands, Xbyak::CodeGe
#endif
}
#endif // __APPLE__
static bool FilterNoSSE4a(const ZydisDecodedOperand*) {
Cpu cpu;
return !cpu.has(Cpu::tSSE4a);
@ -887,28 +397,16 @@ struct PatchInfo {
};
static const std::unordered_map<ZydisMnemonic, PatchInfo> Patches = {
// SSE4a
{ZYDIS_MNEMONIC_EXTRQ, {FilterNoSSE4a, GenerateEXTRQ, true}},
{ZYDIS_MNEMONIC_INSERTQ, {FilterNoSSE4a, GenerateINSERTQ, true}},
#if defined(_WIN32)
// Windows needs a trampoline.
{ZYDIS_MNEMONIC_MOV, {FilterTcbAccess, GenerateTcbAccess, true}},
#elif !defined(__APPLE__)
{ZYDIS_MNEMONIC_MOV, {FilterTcbAccess, GenerateTcbAccess, false}},
#endif
{ZYDIS_MNEMONIC_EXTRQ, {FilterNoSSE4a, GenerateEXTRQ, true}},
{ZYDIS_MNEMONIC_INSERTQ, {FilterNoSSE4a, GenerateINSERTQ, true}},
#ifdef __APPLE__
// Patches for instruction sets not supported by Rosetta 2.
// BMI1
{ZYDIS_MNEMONIC_ANDN, {FilterRosetta2Only, GenerateANDN, true}},
{ZYDIS_MNEMONIC_BEXTR, {FilterRosetta2Only, GenerateBEXTR, true}},
{ZYDIS_MNEMONIC_BLSI, {FilterRosetta2Only, GenerateBLSI, true}},
{ZYDIS_MNEMONIC_BLSMSK, {FilterRosetta2Only, GenerateBLSMSK, true}},
{ZYDIS_MNEMONIC_BLSR, {FilterRosetta2Only, GenerateBLSR, true}},
// F16C
{ZYDIS_MNEMONIC_VCVTPH2PS, {FilterRosetta2Only, GenerateVCVTPH2PS, true}},
{ZYDIS_MNEMONIC_VCVTPS2PH, {FilterRosetta2Only, GenerateVCVTPS2PH, true}},
#endif
};
static std::once_flag init_flag;
@ -1225,18 +723,7 @@ void RegisterPatchModule(void* module_ptr, u64 module_size, void* trampoline_are
}
void PrePatchInstructions(u64 segment_addr, u64 segment_size) {
#if defined(__APPLE__)
// HACK: For some reason patching in the signal handler at the start of a page does not work
// under Rosetta 2. Patch any instructions at the start of a page ahead of time.
if (!Patches.empty()) {
auto* code_page = reinterpret_cast<u8*>(Common::AlignUp(segment_addr, 0x1000));
const auto* end_page = code_page + Common::AlignUp(segment_size, 0x1000);
while (code_page < end_page) {
TryPatchJit(code_page);
code_page += 0x1000;
}
}
#elif !defined(_WIN32)
#if !defined(_WIN32) && !defined(__APPLE__)
// Linux and others have an FS segment pointing to valid memory, so continue to do full
// ahead-of-time patching for now until a better solution is worked out.
if (!Patches.empty()) {

View File

@ -7,12 +7,6 @@
namespace Core {
/// Initializes a stack for the current thread for use by patch implementations.
void InitializeThreadPatchStack();
/// Cleans up the patch stack for the current thread.
void CleanupThreadPatchStack();
/// Registers a module for patching, providing an area to generate trampoline code.
void RegisterPatchModule(void* module_ptr, u64 module_size, void* trampoline_area_ptr,
u64 trampoline_area_size);

View File

@ -1,215 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <array>
#include "crypto.h"
CryptoPP::RSA::PrivateKey Crypto::key_pkg_derived_key3_keyset_init() {
CryptoPP::InvertibleRSAFunction params;
params.SetPrime1(CryptoPP::Integer(PkgDerivedKey3Keyset::Prime1, 0x80));
params.SetPrime2(CryptoPP::Integer(PkgDerivedKey3Keyset::Prime2, 0x80));
params.SetPublicExponent(CryptoPP::Integer(PkgDerivedKey3Keyset::PublicExponent, 4));
params.SetPrivateExponent(CryptoPP::Integer(PkgDerivedKey3Keyset::PrivateExponent, 0x100));
params.SetModPrime1PrivateExponent(CryptoPP::Integer(PkgDerivedKey3Keyset::Exponent1, 0x80));
params.SetModPrime2PrivateExponent(CryptoPP::Integer(PkgDerivedKey3Keyset::Exponent2, 0x80));
params.SetModulus(CryptoPP::Integer(PkgDerivedKey3Keyset::Modulus, 0x100));
params.SetMultiplicativeInverseOfPrime2ModPrime1(
CryptoPP::Integer(PkgDerivedKey3Keyset::Coefficient, 0x80));
CryptoPP::RSA::PrivateKey privateKey(params);
return privateKey;
}
CryptoPP::RSA::PrivateKey Crypto::FakeKeyset_keyset_init() {
CryptoPP::InvertibleRSAFunction params;
params.SetPrime1(CryptoPP::Integer(FakeKeyset::Prime1, 0x80));
params.SetPrime2(CryptoPP::Integer(FakeKeyset::Prime2, 0x80));
params.SetPublicExponent(CryptoPP::Integer(FakeKeyset::PublicExponent, 4));
params.SetPrivateExponent(CryptoPP::Integer(FakeKeyset::PrivateExponent, 0x100));
params.SetModPrime1PrivateExponent(CryptoPP::Integer(FakeKeyset::Exponent1, 0x80));
params.SetModPrime2PrivateExponent(CryptoPP::Integer(FakeKeyset::Exponent2, 0x80));
params.SetModulus(CryptoPP::Integer(FakeKeyset::Modulus, 0x100));
params.SetMultiplicativeInverseOfPrime2ModPrime1(
CryptoPP::Integer(FakeKeyset::Coefficient, 0x80));
CryptoPP::RSA::PrivateKey privateKey(params);
return privateKey;
}
CryptoPP::RSA::PrivateKey Crypto::DebugRifKeyset_init() {
CryptoPP::InvertibleRSAFunction params;
params.SetPrime1(CryptoPP::Integer(DebugRifKeyset::Prime1, sizeof(DebugRifKeyset::Prime1)));
params.SetPrime2(CryptoPP::Integer(DebugRifKeyset::Prime2, sizeof(DebugRifKeyset::Prime2)));
params.SetPublicExponent(
CryptoPP::Integer(DebugRifKeyset::PublicExponent, sizeof(DebugRifKeyset::PublicExponent)));
params.SetPrivateExponent(CryptoPP::Integer(DebugRifKeyset::PrivateExponent,
sizeof(DebugRifKeyset::PrivateExponent)));
params.SetModPrime1PrivateExponent(
CryptoPP::Integer(DebugRifKeyset::Exponent1, sizeof(DebugRifKeyset::Exponent1)));
params.SetModPrime2PrivateExponent(
CryptoPP::Integer(DebugRifKeyset::Exponent2, sizeof(DebugRifKeyset::Exponent2)));
params.SetModulus(CryptoPP::Integer(DebugRifKeyset::Modulus, sizeof(DebugRifKeyset::Modulus)));
params.SetMultiplicativeInverseOfPrime2ModPrime1(
CryptoPP::Integer(DebugRifKeyset::Coefficient, sizeof(DebugRifKeyset::Coefficient)));
CryptoPP::RSA::PrivateKey privateKey(params);
return privateKey;
}
void Crypto::RSA2048Decrypt(std::span<CryptoPP::byte, 32> dec_key,
std::span<const CryptoPP::byte, 256> ciphertext,
bool is_dk3) { // RSAES_PKCS1v15_
// Create an RSA decryptor
CryptoPP::RSA::PrivateKey privateKey;
if (is_dk3) {
privateKey = key_pkg_derived_key3_keyset_init();
} else {
privateKey = FakeKeyset_keyset_init();
}
CryptoPP::RSAES_PKCS1v15_Decryptor rsaDecryptor(privateKey);
// Allocate memory for the decrypted data
std::array<CryptoPP::byte, 256> decrypted;
// Perform the decryption
CryptoPP::AutoSeededRandomPool rng;
CryptoPP::DecodingResult result =
rsaDecryptor.Decrypt(rng, ciphertext.data(), decrypted.size(), decrypted.data());
std::copy(decrypted.begin(), decrypted.begin() + dec_key.size(), dec_key.begin());
}
void Crypto::ivKeyHASH256(std::span<const CryptoPP::byte, 64> cipher_input,
std::span<CryptoPP::byte, 32> ivkey_result) {
CryptoPP::SHA256 sha256;
std::array<CryptoPP::byte, CryptoPP::SHA256::DIGESTSIZE> hashResult;
auto array_sink = new CryptoPP::ArraySink(hashResult.data(), CryptoPP::SHA256::DIGESTSIZE);
auto filter = new CryptoPP::HashFilter(sha256, array_sink);
CryptoPP::ArraySource r(cipher_input.data(), cipher_input.size(), true, filter);
std::copy(hashResult.begin(), hashResult.begin() + ivkey_result.size(), ivkey_result.begin());
}
void Crypto::aesCbcCfb128Decrypt(std::span<const CryptoPP::byte, 32> ivkey,
std::span<const CryptoPP::byte, 256> ciphertext,
std::span<CryptoPP::byte, 256> decrypted) {
std::array<CryptoPP::byte, CryptoPP::AES::DEFAULT_KEYLENGTH> key;
std::array<CryptoPP::byte, CryptoPP::AES::DEFAULT_KEYLENGTH> iv;
std::copy(ivkey.begin() + 16, ivkey.begin() + 16 + key.size(), key.begin());
std::copy(ivkey.begin(), ivkey.begin() + iv.size(), iv.begin());
CryptoPP::AES::Decryption aesDecryption(key.data(), CryptoPP::AES::DEFAULT_KEYLENGTH);
CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, iv.data());
for (size_t i = 0; i < decrypted.size(); i += CryptoPP::AES::BLOCKSIZE) {
cbcDecryption.ProcessData(decrypted.data() + i, ciphertext.data() + i,
CryptoPP::AES::BLOCKSIZE);
}
}
void Crypto::aesCbcCfb128DecryptEntry(std::span<const CryptoPP::byte, 32> ivkey,
std::span<CryptoPP::byte> ciphertext,
std::span<CryptoPP::byte> decrypted) {
std::array<CryptoPP::byte, CryptoPP::AES::DEFAULT_KEYLENGTH> key;
std::array<CryptoPP::byte, CryptoPP::AES::DEFAULT_KEYLENGTH> iv;
std::copy(ivkey.begin() + 16, ivkey.begin() + 16 + key.size(), key.begin());
std::copy(ivkey.begin(), ivkey.begin() + iv.size(), iv.begin());
CryptoPP::AES::Decryption aesDecryption(key.data(), CryptoPP::AES::DEFAULT_KEYLENGTH);
CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, iv.data());
for (size_t i = 0; i < decrypted.size(); i += CryptoPP::AES::BLOCKSIZE) {
cbcDecryption.ProcessData(decrypted.data() + i, ciphertext.data() + i,
CryptoPP::AES::BLOCKSIZE);
}
}
void Crypto::decryptEFSM(std::span<CryptoPP::byte, 16> trophyKey,
std::span<CryptoPP::byte, 16> NPcommID,
std::span<CryptoPP::byte, 16> efsmIv, std::span<CryptoPP::byte> ciphertext,
std::span<CryptoPP::byte> decrypted) {
// step 1: Encrypt NPcommID
CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption encrypt;
std::vector<CryptoPP::byte> trophyIv(16, 0);
std::vector<CryptoPP::byte> trpKey(16);
encrypt.SetKeyWithIV(trophyKey.data(), trophyKey.size(), trophyIv.data());
encrypt.ProcessData(trpKey.data(), NPcommID.data(), 16);
// step 2: decrypt efsm.
CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption decrypt;
decrypt.SetKeyWithIV(trpKey.data(), trpKey.size(), efsmIv.data());
for (size_t i = 0; i < decrypted.size(); i += CryptoPP::AES::BLOCKSIZE) {
decrypt.ProcessData(decrypted.data() + i, ciphertext.data() + i, CryptoPP::AES::BLOCKSIZE);
}
}
void Crypto::PfsGenCryptoKey(std::span<const CryptoPP::byte, 32> ekpfs,
std::span<const CryptoPP::byte, 16> seed,
std::span<CryptoPP::byte, 16> dataKey,
std::span<CryptoPP::byte, 16> tweakKey) {
CryptoPP::HMAC<CryptoPP::SHA256> hmac(ekpfs.data(), ekpfs.size());
CryptoPP::SecByteBlock d(20); // Use Crypto++ SecByteBlock for better memory management
// Copy the bytes of 'index' to the 'd' array
uint32_t index = 1;
std::memcpy(d, &index, sizeof(uint32_t));
// Copy the bytes of 'seed' to the 'd' array starting from index 4
std::memcpy(d + sizeof(uint32_t), seed.data(), seed.size());
// Allocate memory for 'u64' using new
std::vector<CryptoPP::byte> data_tweak_key(hmac.DigestSize());
// Calculate the HMAC
hmac.CalculateDigest(data_tweak_key.data(), d, d.size());
std::copy(data_tweak_key.begin(), data_tweak_key.begin() + dataKey.size(), tweakKey.begin());
std::copy(data_tweak_key.begin() + tweakKey.size(),
data_tweak_key.begin() + tweakKey.size() + dataKey.size(), dataKey.begin());
}
void Crypto::decryptPFS(std::span<const CryptoPP::byte, 16> dataKey,
std::span<const CryptoPP::byte, 16> tweakKey, std::span<const u8> src_image,
std::span<CryptoPP::byte> dst_image, u64 sector) {
// Start at 0x10000 to keep the header when decrypting the whole pfs_image.
for (int i = 0; i < src_image.size(); i += 0x1000) {
const u64 current_sector = sector + (i / 0x1000);
CryptoPP::ECB_Mode<CryptoPP::AES>::Encryption encrypt(tweakKey.data(), tweakKey.size());
CryptoPP::ECB_Mode<CryptoPP::AES>::Decryption decrypt(dataKey.data(), dataKey.size());
std::array<CryptoPP::byte, 16> tweak{};
std::array<CryptoPP::byte, 16> encryptedTweak;
std::array<CryptoPP::byte, 16> xorBuffer;
std::memcpy(tweak.data(), &current_sector, sizeof(u64));
// Encrypt the tweak for each sector.
encrypt.ProcessData(encryptedTweak.data(), tweak.data(), 16);
for (int plaintextOffset = 0; plaintextOffset < 0x1000; plaintextOffset += 16) {
xtsXorBlock(xorBuffer.data(), src_image.data() + i + plaintextOffset,
encryptedTweak.data()); // x, c, t
decrypt.ProcessData(xorBuffer.data(), xorBuffer.data(), 16); // x, x
xtsXorBlock(dst_image.data() + i + plaintextOffset, xorBuffer.data(),
encryptedTweak.data()); //(p) c, x , t
xtsMult(encryptedTweak);
}
}
}

View File

@ -1,63 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <span>
#include <cryptopp/aes.h>
#include <cryptopp/filters.h>
#include <cryptopp/modes.h>
#include <cryptopp/oaep.h>
#include <cryptopp/osrng.h>
#include <cryptopp/rsa.h>
#include <cryptopp/sha.h>
#include "common/types.h"
#include "keys.h"
class Crypto {
public:
CryptoPP::RSA::PrivateKey key_pkg_derived_key3_keyset_init();
CryptoPP::RSA::PrivateKey FakeKeyset_keyset_init();
CryptoPP::RSA::PrivateKey DebugRifKeyset_init();
void RSA2048Decrypt(std::span<CryptoPP::byte, 32> dk3,
std::span<const CryptoPP::byte, 256> ciphertext,
bool is_dk3); // RSAES_PKCS1v15_
void ivKeyHASH256(std::span<const CryptoPP::byte, 64> cipher_input,
std::span<CryptoPP::byte, 32> ivkey_result);
void aesCbcCfb128Decrypt(std::span<const CryptoPP::byte, 32> ivkey,
std::span<const CryptoPP::byte, 256> ciphertext,
std::span<CryptoPP::byte, 256> decrypted);
void aesCbcCfb128DecryptEntry(std::span<const CryptoPP::byte, 32> ivkey,
std::span<CryptoPP::byte> ciphertext,
std::span<CryptoPP::byte> decrypted);
void decryptEFSM(std::span<CryptoPP::byte, 16> trophyKey,
std::span<CryptoPP::byte, 16> NPcommID, std::span<CryptoPP::byte, 16> efsmIv,
std::span<CryptoPP::byte> ciphertext, std::span<CryptoPP::byte> decrypted);
void PfsGenCryptoKey(std::span<const CryptoPP::byte, 32> ekpfs,
std::span<const CryptoPP::byte, 16> seed,
std::span<CryptoPP::byte, 16> dataKey,
std::span<CryptoPP::byte, 16> tweakKey);
void decryptPFS(std::span<const CryptoPP::byte, 16> dataKey,
std::span<const CryptoPP::byte, 16> tweakKey, std::span<const u8> src_image,
std::span<CryptoPP::byte> dst_image, u64 sector);
void xtsXorBlock(CryptoPP::byte* x, const CryptoPP::byte* a, const CryptoPP::byte* b) {
for (int i = 0; i < 16; i++) {
x[i] = a[i] ^ b[i];
}
}
void xtsMult(std::span<CryptoPP::byte, 16> encryptedTweak) {
int feedback = 0;
for (int k = 0; k < encryptedTweak.size(); k++) {
const auto tmp = (encryptedTweak[k] >> 7) & 1;
encryptedTweak[k] = ((encryptedTweak[k] << 1) + feedback) & 0xFF;
feedback = tmp;
}
if (feedback != 0) {
encryptedTweak[0] ^= 0x87;
}
}
};

View File

@ -1,305 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <cryptopp/rsa.h>
class FakeKeyset {
public:
// Constructor
static constexpr CryptoPP::byte Exponent1[] = {
0x6D, 0x48, 0xE0, 0x54, 0x40, 0x25, 0xC8, 0x41, 0x29, 0x52, 0x42, 0x27, 0xEB, 0xD2, 0xC7,
0xAB, 0x6B, 0x9C, 0x27, 0x0A, 0xB4, 0x1F, 0x94, 0x4E, 0xFA, 0x42, 0x1D, 0xB7, 0xBC, 0xB9,
0xAE, 0xBC, 0x04, 0x6F, 0x75, 0x8F, 0x10, 0x5F, 0x89, 0xAC, 0xAB, 0x9C, 0xD2, 0xFA, 0xE6,
0xA4, 0x13, 0x83, 0x68, 0xD4, 0x56, 0x38, 0xFE, 0xE5, 0x2B, 0x78, 0x44, 0x9C, 0x34, 0xE6,
0x5A, 0xA0, 0xBE, 0x05, 0x70, 0xAD, 0x15, 0xC3, 0x2D, 0x31, 0xAC, 0x97, 0x5D, 0x88, 0xFC,
0xC1, 0x62, 0x3D, 0xE2, 0xED, 0x11, 0xDB, 0xB6, 0x9E, 0xFC, 0x5A, 0x5A, 0x03, 0xF6, 0xCF,
0x08, 0xD4, 0x5D, 0x90, 0xC9, 0x2A, 0xB9, 0x9B, 0xCF, 0xC8, 0x1A, 0x65, 0xF3, 0x5B, 0xE8,
0x7F, 0xCF, 0xA5, 0xA6, 0x4C, 0x5C, 0x2A, 0x12, 0x0F, 0x92, 0xA5, 0xE3, 0xF0, 0x17, 0x1E,
0x9A, 0x97, 0x45, 0x86, 0xFD, 0xDB, 0x54, 0x25};
// exponent2 = d mod (q - 1)
static constexpr CryptoPP::byte Exponent2[] = {
0x2A, 0x51, 0xCE, 0x02, 0x44, 0x28, 0x50, 0xE8, 0x30, 0x20, 0x7C, 0x9C, 0x55, 0xBF, 0x60,
0x39, 0xBC, 0xD1, 0xF0, 0xE7, 0x68, 0xF8, 0x08, 0x5B, 0x61, 0x1F, 0xA7, 0xBF, 0xD0, 0xE8,
0x8B, 0xB5, 0xB1, 0xD5, 0xD9, 0x16, 0xAC, 0x75, 0x0C, 0x6D, 0xF2, 0xE0, 0xB5, 0x97, 0x75,
0xD2, 0x68, 0x16, 0x1F, 0x00, 0x7D, 0x8B, 0x17, 0xE8, 0x78, 0x48, 0x41, 0x71, 0x2B, 0x18,
0x96, 0x80, 0x11, 0xDB, 0x68, 0x39, 0x9C, 0xD6, 0xE0, 0x72, 0x42, 0x86, 0xF0, 0x1B, 0x16,
0x0D, 0x3E, 0x12, 0x94, 0x3D, 0x25, 0xA8, 0xA9, 0x30, 0x9E, 0x54, 0x5A, 0xD6, 0x36, 0x6C,
0xD6, 0x8C, 0x20, 0x62, 0x8F, 0xA1, 0x6B, 0x1F, 0x7C, 0x6D, 0xB2, 0xB1, 0xC1, 0x2E, 0xAD,
0x36, 0x02, 0x9C, 0x3A, 0xCA, 0x2F, 0x09, 0xD2, 0x45, 0x9E, 0xEB, 0xF2, 0xBC, 0x6C, 0xAA,
0x3B, 0x3E, 0x90, 0xBC, 0x38, 0x67, 0x35, 0x4D};
// e
static constexpr CryptoPP::byte PublicExponent[] = {0, 1, 0, 1};
// (InverseQ)(q) = 1 mod p
static constexpr CryptoPP::byte Coefficient[] = {
0x0B, 0x67, 0x1C, 0x0D, 0x6C, 0x57, 0xD3, 0xE7, 0x05, 0x65, 0x94, 0x31, 0x56, 0x55, 0xFD,
0x28, 0x08, 0xFA, 0x05, 0x8A, 0xCC, 0x55, 0x39, 0x61, 0x97, 0x63, 0xA0, 0x16, 0x27, 0x3D,
0xED, 0xC1, 0x16, 0x40, 0x2A, 0x12, 0xEA, 0x6F, 0xD9, 0xD8, 0x58, 0x56, 0xA8, 0x56, 0x8B,
0x0D, 0x38, 0x5E, 0x1E, 0x80, 0x3B, 0x5F, 0x40, 0x80, 0x6F, 0x62, 0x4F, 0x28, 0xA2, 0x69,
0xF3, 0xD3, 0xF7, 0xFD, 0xB2, 0xC3, 0x52, 0x43, 0x20, 0x92, 0x9D, 0x97, 0x8D, 0xA0, 0x15,
0x07, 0x15, 0x6E, 0xA4, 0x0D, 0x56, 0xD3, 0x37, 0x1A, 0xC4, 0x9E, 0xDF, 0x02, 0x49, 0xB8,
0x0A, 0x84, 0x62, 0xF5, 0xFA, 0xB9, 0x3F, 0xA4, 0x09, 0x76, 0xCC, 0xAA, 0xB9, 0x9B, 0xA6,
0x4F, 0xC1, 0x6A, 0x64, 0xCE, 0xD8, 0x77, 0xAB, 0x4B, 0xF9, 0xA0, 0xAE, 0xDA, 0xF1, 0x67,
0x87, 0x7C, 0x98, 0x5C, 0x7E, 0xB8, 0x73, 0xF5};
// n = p * q
static constexpr CryptoPP::byte Modulus[] = {
0xC6, 0xCF, 0x71, 0xE7, 0xE5, 0x9A, 0xF0, 0xD1, 0x2A, 0x2C, 0x45, 0x8B, 0xF9, 0x2A, 0x0E,
0xC1, 0x43, 0x05, 0x8B, 0xC3, 0x71, 0x17, 0x80, 0x1D, 0xCD, 0x49, 0x7D, 0xDE, 0x35, 0x9D,
0x25, 0x9B, 0xA0, 0xD7, 0xA0, 0xF2, 0x7D, 0x6C, 0x08, 0x7E, 0xAA, 0x55, 0x02, 0x68, 0x2B,
0x23, 0xC6, 0x44, 0xB8, 0x44, 0x18, 0xEB, 0x56, 0xCF, 0x16, 0xA2, 0x48, 0x03, 0xC9, 0xE7,
0x4F, 0x87, 0xEB, 0x3D, 0x30, 0xC3, 0x15, 0x88, 0xBF, 0x20, 0xE7, 0x9D, 0xFF, 0x77, 0x0C,
0xDE, 0x1D, 0x24, 0x1E, 0x63, 0xA9, 0x4F, 0x8A, 0xBF, 0x5B, 0xBE, 0x60, 0x19, 0x68, 0x33,
0x3B, 0xFC, 0xED, 0x9F, 0x47, 0x4E, 0x5F, 0xF8, 0xEA, 0xCB, 0x3D, 0x00, 0xBD, 0x67, 0x01,
0xF9, 0x2C, 0x6D, 0xC6, 0xAC, 0x13, 0x64, 0xE7, 0x67, 0x14, 0xF3, 0xDC, 0x52, 0x69, 0x6A,
0xB9, 0x83, 0x2C, 0x42, 0x30, 0x13, 0x1B, 0xB2, 0xD8, 0xA5, 0x02, 0x0D, 0x79, 0xED, 0x96,
0xB1, 0x0D, 0xF8, 0xCC, 0x0C, 0xDF, 0x81, 0x95, 0x4F, 0x03, 0x58, 0x09, 0x57, 0x0E, 0x80,
0x69, 0x2E, 0xFE, 0xFF, 0x52, 0x77, 0xEA, 0x75, 0x28, 0xA8, 0xFB, 0xC9, 0xBE, 0xBF, 0x9F,
0xBB, 0xB7, 0x79, 0x8E, 0x18, 0x05, 0xE1, 0x80, 0xBD, 0x50, 0x34, 0x94, 0x81, 0xD3, 0x53,
0xC2, 0x69, 0xA2, 0xD2, 0x4C, 0xCF, 0x6C, 0xF4, 0x57, 0x2C, 0x10, 0x4A, 0x3F, 0xFB, 0x22,
0xFD, 0x8B, 0x97, 0xE2, 0xC9, 0x5B, 0xA6, 0x2B, 0xCD, 0xD6, 0x1B, 0x6B, 0xDB, 0x68, 0x7F,
0x4B, 0xC2, 0xA0, 0x50, 0x34, 0xC0, 0x05, 0xE5, 0x8D, 0xEF, 0x24, 0x67, 0xFF, 0x93, 0x40,
0xCF, 0x2D, 0x62, 0xA2, 0xA0, 0x50, 0xB1, 0xF1, 0x3A, 0xA8, 0x3D, 0xFD, 0x80, 0xD1, 0xF9,
0xB8, 0x05, 0x22, 0xAF, 0xC8, 0x35, 0x45, 0x90, 0x58, 0x8E, 0xE3, 0x3A, 0x7C, 0xBD, 0x3E,
0x27};
// p
static constexpr CryptoPP::byte Prime1[] = {
0xFE, 0xF6, 0xBF, 0x1D, 0x69, 0xAB, 0x16, 0x25, 0x08, 0x47, 0x55, 0x6B, 0x86, 0xE4, 0x35,
0x88, 0x72, 0x2A, 0xB1, 0x3D, 0xF8, 0xB6, 0x44, 0xCA, 0xB3, 0xAB, 0x19, 0xD1, 0x04, 0x24,
0x28, 0x0A, 0x74, 0x55, 0xB8, 0x15, 0x45, 0x09, 0xCC, 0x13, 0x1C, 0xF2, 0xBA, 0x37, 0xA9,
0x03, 0x90, 0x8F, 0x02, 0x10, 0xFF, 0x25, 0x79, 0x86, 0xCC, 0x18, 0x50, 0x9A, 0x10, 0x5F,
0x5B, 0x4C, 0x1C, 0x4E, 0xB0, 0xA7, 0xE3, 0x59, 0xB1, 0x2D, 0xA0, 0xC6, 0xB0, 0x20, 0x2C,
0x21, 0x33, 0x12, 0xB3, 0xAF, 0x72, 0x34, 0x83, 0xCD, 0x52, 0x2F, 0xAF, 0x0F, 0x20, 0x5A,
0x1B, 0xC0, 0xE2, 0xA3, 0x76, 0x34, 0x0F, 0xD7, 0xFC, 0xC1, 0x41, 0xC9, 0xF9, 0x79, 0x40,
0x17, 0x42, 0x21, 0x3E, 0x9D, 0xFD, 0xC7, 0xC1, 0x50, 0xDE, 0x44, 0x5A, 0xC9, 0x31, 0x89,
0x6A, 0x78, 0x05, 0xBE, 0x65, 0xB4, 0xE8, 0x2D};
// q
static constexpr CryptoPP::byte Prime2[] = {
0xC7, 0x9E, 0x47, 0x58, 0x00, 0x7D, 0x62, 0x82, 0xB0, 0xD2, 0x22, 0x81, 0xD4, 0xA8, 0x97,
0x1B, 0x79, 0x0C, 0x3A, 0xB0, 0xD7, 0xC9, 0x30, 0xE3, 0xC3, 0x53, 0x8E, 0x57, 0xEF, 0xF0,
0x9B, 0x9F, 0xB3, 0x90, 0x52, 0xC6, 0x94, 0x22, 0x36, 0xAA, 0xE6, 0x4A, 0x5F, 0x72, 0x1D,
0x70, 0xE8, 0x76, 0x58, 0xC8, 0xB2, 0x91, 0xCE, 0x9C, 0xC3, 0xE9, 0x09, 0x7F, 0x2E, 0x47,
0x97, 0xCC, 0x90, 0x39, 0x15, 0x35, 0x31, 0xDE, 0x1F, 0x0C, 0x8C, 0x0D, 0xC1, 0xC2, 0x92,
0xBE, 0x97, 0xBF, 0x2F, 0x91, 0xA1, 0x8C, 0x7D, 0x50, 0xA8, 0x21, 0x2F, 0xD7, 0xA2, 0x9A,
0x7E, 0xB5, 0xA7, 0x2A, 0x90, 0x02, 0xD9, 0xF3, 0x3D, 0xD1, 0xEB, 0xB8, 0xE0, 0x5A, 0x79,
0x9E, 0x7D, 0x8D, 0xCA, 0x18, 0x6D, 0xBD, 0x9E, 0xA1, 0x80, 0x28, 0x6B, 0x2A, 0xFE, 0x51,
0x24, 0x9B, 0x6F, 0x4D, 0x84, 0x77, 0x80, 0x23};
static constexpr CryptoPP::byte PrivateExponent[] = {
0x7F, 0x76, 0xCD, 0x0E, 0xE2, 0xD4, 0xDE, 0x05, 0x1C, 0xC6, 0xD9, 0xA8, 0x0E, 0x8D, 0xFA,
0x7B, 0xCA, 0x1E, 0xAA, 0x27, 0x1A, 0x40, 0xF8, 0xF1, 0x22, 0x87, 0x35, 0xDD, 0xDB, 0xFD,
0xEE, 0xF8, 0xC2, 0xBC, 0xBD, 0x01, 0xFB, 0x8B, 0xE2, 0x3E, 0x63, 0xB2, 0xB1, 0x22, 0x5C,
0x56, 0x49, 0x6E, 0x11, 0xBE, 0x07, 0x44, 0x0B, 0x9A, 0x26, 0x66, 0xD1, 0x49, 0x2C, 0x8F,
0xD3, 0x1B, 0xCF, 0xA4, 0xA1, 0xB8, 0xD1, 0xFB, 0xA4, 0x9E, 0xD2, 0x21, 0x28, 0x83, 0x09,
0x8A, 0xF6, 0xA0, 0x0B, 0xA3, 0xD6, 0x0F, 0x9B, 0x63, 0x68, 0xCC, 0xBC, 0x0C, 0x4E, 0x14,
0x5B, 0x27, 0xA4, 0xA9, 0xF4, 0x2B, 0xB9, 0xB8, 0x7B, 0xC0, 0xE6, 0x51, 0xAD, 0x1D, 0x77,
0xD4, 0x6B, 0xB9, 0xCE, 0x20, 0xD1, 0x26, 0x66, 0x7E, 0x5E, 0x9E, 0xA2, 0xE9, 0x6B, 0x90,
0xF3, 0x73, 0xB8, 0x52, 0x8F, 0x44, 0x11, 0x03, 0x0C, 0x13, 0x97, 0x39, 0x3D, 0x13, 0x22,
0x58, 0xD5, 0x43, 0x82, 0x49, 0xDA, 0x6E, 0x7C, 0xA1, 0xC5, 0x8C, 0xA5, 0xB0, 0x09, 0xE0,
0xCE, 0x3D, 0xDF, 0xF4, 0x9D, 0x3C, 0x97, 0x15, 0xE2, 0x6A, 0xC7, 0x2B, 0x3C, 0x50, 0x93,
0x23, 0xDB, 0xBA, 0x4A, 0x22, 0x66, 0x44, 0xAC, 0x78, 0xBB, 0x0E, 0x1A, 0x27, 0x43, 0xB5,
0x71, 0x67, 0xAF, 0xF4, 0xAB, 0x48, 0x46, 0x93, 0x73, 0xD0, 0x42, 0xAB, 0x93, 0x63, 0xE5,
0x6C, 0x9A, 0xDE, 0x50, 0x24, 0xC0, 0x23, 0x7D, 0x99, 0x79, 0x3F, 0x22, 0x07, 0xE0, 0xC1,
0x48, 0x56, 0x1B, 0xDF, 0x83, 0x09, 0x12, 0xB4, 0x2D, 0x45, 0x6B, 0xC9, 0xC0, 0x68, 0x85,
0x99, 0x90, 0x79, 0x96, 0x1A, 0xD7, 0xF5, 0x4D, 0x1F, 0x37, 0x83, 0x40, 0x4A, 0xEC, 0x39,
0x37, 0xA6, 0x80, 0x92, 0x7D, 0xC5, 0x80, 0xC7, 0xD6, 0x6F, 0xFE, 0x8A, 0x79, 0x89, 0xC6,
0xB1};
};
class DebugRifKeyset {
public:
// std::uint8_t* PrivateExponent;
static constexpr CryptoPP::byte Exponent1[] = {
0xCD, 0x9A, 0x61, 0xB0, 0xB8, 0xD5, 0xB4, 0xE4, 0xE4, 0xF6, 0xAB, 0xF7, 0x27, 0xB7, 0x56,
0x59, 0x6B, 0xB9, 0x11, 0xE7, 0xF4, 0x83, 0xAF, 0xB9, 0x73, 0x99, 0x7F, 0x49, 0xA2, 0x9C,
0xF0, 0xB5, 0x6D, 0x37, 0x82, 0x14, 0x15, 0xF1, 0x04, 0x8A, 0xD4, 0x8E, 0xEB, 0x2E, 0x1F,
0xE2, 0x81, 0xA9, 0x62, 0x6E, 0xB1, 0x68, 0x75, 0x62, 0xF3, 0x0F, 0xFE, 0xD4, 0x91, 0x87,
0x98, 0x78, 0xBF, 0x26, 0xB5, 0x07, 0x58, 0xD0, 0xEE, 0x3F, 0x21, 0xE8, 0xC8, 0x0F, 0x5F,
0xFA, 0x1C, 0x64, 0x74, 0x49, 0x52, 0xEB, 0xE7, 0xEE, 0xDE, 0xBA, 0x23, 0x26, 0x4A, 0xF6,
0x9C, 0x1A, 0x09, 0x3F, 0xB9, 0x0B, 0x36, 0x26, 0x1A, 0xBE, 0xA9, 0x76, 0xE6, 0xF2, 0x69,
0xDE, 0xFF, 0xAF, 0xCC, 0x0C, 0x9A, 0x66, 0x03, 0x86, 0x0A, 0x1F, 0x49, 0xA4, 0x10, 0xB6,
0xBC, 0xC3, 0x7C, 0x88, 0xE8, 0xCE, 0x4B, 0xD9};
// exponent2 = d mod (q - 1)
static constexpr CryptoPP::byte Exponent2[] = {
0xB3, 0x73, 0xA3, 0x59, 0xE6, 0x97, 0xC0, 0xAB, 0x3B, 0x68, 0xFC, 0x39, 0xAC, 0xDB, 0x44,
0xB1, 0xB4, 0x9E, 0x35, 0x4D, 0xBE, 0xC5, 0x36, 0x69, 0x6C, 0x3D, 0xC5, 0xFC, 0xFE, 0x4B,
0x2F, 0xDC, 0x86, 0x80, 0x46, 0x96, 0x40, 0x1A, 0x0D, 0x6E, 0xFA, 0x8C, 0xE0, 0x47, 0x91,
0xAC, 0xAD, 0x95, 0x2B, 0x8E, 0x1F, 0xF2, 0x0A, 0x45, 0xF8, 0x29, 0x95, 0x70, 0xC6, 0x88,
0x5F, 0x71, 0x03, 0x99, 0x79, 0xBC, 0x84, 0x71, 0xBD, 0xE8, 0x84, 0x8C, 0x0E, 0xD4, 0x7B,
0x30, 0x74, 0x57, 0x1A, 0x95, 0xE7, 0x90, 0x19, 0x8D, 0xAD, 0x8B, 0x4C, 0x4E, 0xC3, 0xE7,
0x6B, 0x23, 0x86, 0x01, 0xEE, 0x9B, 0xE0, 0x2F, 0x15, 0xA2, 0x2C, 0x4C, 0x39, 0xD3, 0xDF,
0x9C, 0x39, 0x01, 0xF1, 0x8C, 0x44, 0x4A, 0x15, 0x44, 0xDC, 0x51, 0xF7, 0x22, 0xD7, 0x7F,
0x41, 0x7F, 0x68, 0xFA, 0xEE, 0x56, 0xE8, 0x05};
// e
static constexpr CryptoPP::byte PublicExponent[] = {0x00, 0x01, 0x00, 0x01};
// (InverseQ)(q) = 1 mod p
static constexpr CryptoPP::byte Coefficient[] = {
0xC0, 0x32, 0x43, 0xD3, 0x8C, 0x3D, 0xB4, 0xD2, 0x48, 0x8C, 0x42, 0x41, 0x24, 0x94, 0x6C,
0x80, 0xC9, 0xC1, 0x79, 0x36, 0x7F, 0xAC, 0xC3, 0xFF, 0x6A, 0x25, 0xEB, 0x2C, 0xFB, 0xD4,
0x2B, 0xA0, 0xEB, 0xFE, 0x25, 0xE9, 0xC6, 0x77, 0xCE, 0xFE, 0x2D, 0x23, 0xFE, 0xD0, 0xF4,
0x0F, 0xD9, 0x7E, 0xD5, 0xA5, 0x7D, 0x1F, 0xC0, 0xE8, 0xE8, 0xEC, 0x80, 0x5B, 0xC7, 0xFD,
0xE2, 0xBD, 0x94, 0xA6, 0x2B, 0xDD, 0x6A, 0x60, 0x45, 0x54, 0xAB, 0xCA, 0x42, 0x9C, 0x6A,
0x6C, 0xBF, 0x3C, 0x84, 0xF9, 0xA5, 0x0E, 0x63, 0x0C, 0x51, 0x58, 0x62, 0x6D, 0x5A, 0xB7,
0x3C, 0x3F, 0x49, 0x1A, 0xD0, 0x93, 0xB8, 0x4F, 0x1A, 0x6C, 0x5F, 0xC5, 0xE5, 0xA9, 0x75,
0xD4, 0x86, 0x9E, 0xDF, 0x87, 0x0F, 0x27, 0xB0, 0x26, 0x78, 0x4E, 0xFB, 0xC1, 0x8A, 0x4A,
0x24, 0x3F, 0x7F, 0x8F, 0x9A, 0x12, 0x51, 0xCB};
// n = p * q
static constexpr CryptoPP::byte Modulus[] = {
0xC2, 0xD2, 0x44, 0xBC, 0xDD, 0x84, 0x3F, 0xD9, 0xC5, 0x22, 0xAF, 0xF7, 0xFC, 0x88, 0x8A,
0x33, 0x80, 0xED, 0x8E, 0xE2, 0xCC, 0x81, 0xF7, 0xEC, 0xF8, 0x1C, 0x79, 0xBF, 0x02, 0xBB,
0x12, 0x8E, 0x61, 0x68, 0x29, 0x1B, 0x15, 0xB6, 0x5E, 0xC6, 0xF8, 0xBF, 0x5A, 0xE0, 0x3B,
0x6A, 0x6C, 0xD9, 0xD6, 0xF5, 0x75, 0xAB, 0xA0, 0x6F, 0x34, 0x81, 0x34, 0x9A, 0x5B, 0xAD,
0xED, 0x31, 0xE3, 0xC6, 0xEA, 0x1A, 0xD1, 0x13, 0x22, 0xBB, 0xB3, 0xDA, 0xB3, 0xB2, 0x53,
0xBD, 0x45, 0x79, 0x87, 0xAD, 0x0A, 0x01, 0x72, 0x18, 0x10, 0x29, 0x49, 0xF4, 0x41, 0x7F,
0xD6, 0x47, 0x0C, 0x72, 0x92, 0x9E, 0xE9, 0xBB, 0x95, 0xA9, 0x5D, 0x79, 0xEB, 0xE4, 0x30,
0x76, 0x90, 0x45, 0x4B, 0x9D, 0x9C, 0xCF, 0x92, 0x03, 0x60, 0x8C, 0x4B, 0x6C, 0xB3, 0x7A,
0x3A, 0x05, 0x39, 0xA0, 0x66, 0xA9, 0x35, 0xCF, 0xB9, 0xFA, 0xAD, 0x9C, 0xAB, 0xEB, 0xE4,
0x6A, 0x8C, 0xE9, 0x3B, 0xCC, 0x72, 0x12, 0x62, 0x63, 0xBD, 0x80, 0xC4, 0xEE, 0x37, 0x2B,
0x32, 0x03, 0xA3, 0x09, 0xF7, 0xA0, 0x61, 0x57, 0xAD, 0x0D, 0xCF, 0x15, 0x98, 0x9E, 0x4E,
0x49, 0xF8, 0xB5, 0xA3, 0x5C, 0x27, 0xEE, 0x45, 0x04, 0xEA, 0xE4, 0x4B, 0xBC, 0x8F, 0x87,
0xED, 0x19, 0x1E, 0x46, 0x75, 0x63, 0xC4, 0x5B, 0xD5, 0xBC, 0x09, 0x2F, 0x02, 0x73, 0x19,
0x3C, 0x58, 0x55, 0x49, 0x66, 0x4C, 0x11, 0xEC, 0x0F, 0x09, 0xFA, 0xA5, 0x56, 0x0A, 0x5A,
0x63, 0x56, 0xAD, 0xA0, 0x0D, 0x86, 0x08, 0xC1, 0xE6, 0xB6, 0x13, 0x22, 0x49, 0x2F, 0x7C,
0xDB, 0x4C, 0x56, 0x97, 0x0E, 0xC2, 0xD9, 0x2E, 0x87, 0xBC, 0x0E, 0x67, 0xC0, 0x1B, 0x58,
0xBC, 0x64, 0x2B, 0xC2, 0x6E, 0xE2, 0x93, 0x2E, 0xB5, 0x6B, 0x70, 0xA4, 0x42, 0x9F, 0x64,
0xC1};
// p
static constexpr CryptoPP::byte Prime1[] = {
0xE5, 0x62, 0xE1, 0x7F, 0x9F, 0x86, 0x08, 0xE2, 0x61, 0xD3, 0xD0, 0x42, 0xE2, 0xC4, 0xB6,
0xA8, 0x51, 0x09, 0x19, 0x14, 0xA4, 0x3A, 0x11, 0x4C, 0x33, 0xA5, 0x9C, 0x01, 0x5E, 0x34,
0xB6, 0x3F, 0x02, 0x1A, 0xCA, 0x47, 0xF1, 0x4F, 0x3B, 0x35, 0x2A, 0x07, 0x20, 0xEC, 0xD8,
0xC1, 0x15, 0xD9, 0xCA, 0x03, 0x4F, 0xB8, 0xE8, 0x09, 0x73, 0x3F, 0x85, 0xB7, 0x41, 0xD5,
0x51, 0x3E, 0x7B, 0xE3, 0x53, 0x2B, 0x48, 0x8B, 0x8E, 0xCB, 0xBA, 0xF7, 0xE0, 0x60, 0xF5,
0x35, 0x0E, 0x6F, 0xB0, 0xD9, 0x2A, 0x99, 0xD0, 0xFF, 0x60, 0x14, 0xED, 0x40, 0xEA, 0xF8,
0xD7, 0x0B, 0xC3, 0x8D, 0x8C, 0xE8, 0x81, 0xB3, 0x75, 0x93, 0x15, 0xB3, 0x7D, 0xF6, 0x39,
0x60, 0x1A, 0x00, 0xE7, 0xC3, 0x27, 0xAD, 0xA4, 0x33, 0xD5, 0x3E, 0xA4, 0x35, 0x48, 0x6F,
0x22, 0xEF, 0x5D, 0xDD, 0x7D, 0x7B, 0x61, 0x05};
// q
static constexpr CryptoPP::byte Prime2[] = {
0xD9, 0x6C, 0xC2, 0x0C, 0xF7, 0xAE, 0xD1, 0xF3, 0x3B, 0x3B, 0x49, 0x1E, 0x9F, 0x12, 0x9C,
0xA1, 0x78, 0x1F, 0x35, 0x1D, 0x98, 0x26, 0x13, 0x71, 0xF9, 0x09, 0xFD, 0xF0, 0xAD, 0x38,
0x55, 0xB7, 0xEE, 0x61, 0x04, 0x72, 0x51, 0x87, 0x2E, 0x05, 0x84, 0xB1, 0x1D, 0x0C, 0x0D,
0xDB, 0xD4, 0x25, 0x3E, 0x26, 0xED, 0xEA, 0xB8, 0xF7, 0x49, 0xFE, 0xA2, 0x94, 0xE6, 0xF2,
0x08, 0x92, 0xA7, 0x85, 0xF5, 0x30, 0xB9, 0x84, 0x22, 0xBF, 0xCA, 0xF0, 0x5F, 0xCB, 0x31,
0x20, 0x34, 0x49, 0x16, 0x76, 0x34, 0xCC, 0x7A, 0xCB, 0x96, 0xFE, 0x78, 0x7A, 0x41, 0xFE,
0x9A, 0xA2, 0x23, 0xF7, 0x68, 0x80, 0xD6, 0xCE, 0x4A, 0x78, 0xA5, 0xB7, 0x05, 0x77, 0x81,
0x1F, 0xDE, 0x5E, 0xA8, 0x6E, 0x3E, 0x87, 0xEC, 0x44, 0xD2, 0x69, 0xC6, 0x54, 0x91, 0x6B,
0x5E, 0x13, 0x8A, 0x03, 0x87, 0x05, 0x31, 0x8D};
static constexpr CryptoPP::byte PrivateExponent[] = {
0x01, 0x61, 0xAD, 0xD8, 0x9C, 0x06, 0x89, 0xD0, 0x60, 0xC8, 0x41, 0xF0, 0xB3, 0x83, 0x01,
0x5D, 0xE3, 0xA2, 0x6B, 0xA2, 0xBA, 0x9A, 0x0A, 0x58, 0xCD, 0x1A, 0xA0, 0x97, 0x64, 0xEC,
0xD0, 0x31, 0x1F, 0xCA, 0x36, 0x0E, 0x69, 0xDD, 0x40, 0xF7, 0x4E, 0xC0, 0xC6, 0xA3, 0x73,
0xF0, 0x69, 0x84, 0xB2, 0xF4, 0x4B, 0x29, 0x14, 0x2A, 0x6D, 0xB8, 0x23, 0xD8, 0x1B, 0x61,
0xD4, 0x9E, 0x87, 0xB3, 0xBB, 0xA9, 0xC4, 0x85, 0x4A, 0xF8, 0x03, 0x4A, 0xBF, 0xFE, 0xF9,
0xFE, 0x8B, 0xDD, 0x54, 0x83, 0xBA, 0xE0, 0x2F, 0x3F, 0xB1, 0xEF, 0xA5, 0x05, 0x5D, 0x28,
0x8B, 0xAB, 0xB5, 0xD0, 0x23, 0x2F, 0x8A, 0xCF, 0x48, 0x7C, 0xAA, 0xBB, 0xC8, 0x5B, 0x36,
0x27, 0xC5, 0x16, 0xA4, 0xB6, 0x61, 0xAC, 0x0C, 0x28, 0x47, 0x79, 0x3F, 0x38, 0xAE, 0x5E,
0x25, 0xC6, 0xAF, 0x35, 0xAE, 0xBC, 0xB0, 0xF3, 0xBC, 0xBD, 0xFD, 0xA4, 0x87, 0x0D, 0x14,
0x3D, 0x90, 0xE4, 0xDE, 0x5D, 0x1D, 0x46, 0x81, 0xF1, 0x28, 0x6D, 0x2F, 0x2C, 0x5E, 0x97,
0x2D, 0x89, 0x2A, 0x51, 0x72, 0x3C, 0x20, 0x02, 0x59, 0xB1, 0x98, 0x93, 0x05, 0x1E, 0x3F,
0xA1, 0x8A, 0x69, 0x30, 0x0E, 0x70, 0x84, 0x8B, 0xAE, 0x97, 0xA1, 0x08, 0x95, 0x63, 0x4C,
0xC7, 0xE8, 0x5D, 0x59, 0xCA, 0x78, 0x2A, 0x23, 0x87, 0xAC, 0x6F, 0x04, 0x33, 0xB1, 0x61,
0xB9, 0xF0, 0x95, 0xDA, 0x33, 0xCC, 0xE0, 0x4C, 0x82, 0x68, 0x82, 0x14, 0x51, 0xBE, 0x49,
0x1C, 0x58, 0xA2, 0x8B, 0x05, 0x4E, 0x98, 0x37, 0xEB, 0x94, 0x0B, 0x01, 0x22, 0xDC, 0xB3,
0x19, 0xCA, 0x77, 0xA6, 0x6E, 0x97, 0xFF, 0x8A, 0x53, 0x5A, 0xC5, 0x24, 0xE4, 0xAF, 0x6E,
0xA8, 0x2B, 0x53, 0xA4, 0xBE, 0x96, 0xA5, 0x7B, 0xCE, 0x22, 0x56, 0xA3, 0xF1, 0xCF, 0x14,
0xA5};
};
class PkgDerivedKey3Keyset {
public:
// std::uint8_t* PrivateExponent;
static constexpr CryptoPP::byte Exponent1[] = {
0x52, 0xCC, 0x2D, 0xA0, 0x9C, 0x9E, 0x75, 0xE7, 0x28, 0xEE, 0x3D, 0xDE, 0xE3, 0x45, 0xD1,
0x4F, 0x94, 0x1C, 0xCC, 0xC8, 0x87, 0x29, 0x45, 0x3B, 0x8D, 0x6E, 0xAB, 0x6E, 0x2A, 0xA7,
0xC7, 0x15, 0x43, 0xA3, 0x04, 0x8F, 0x90, 0x5F, 0xEB, 0xF3, 0x38, 0x4A, 0x77, 0xFA, 0x36,
0xB7, 0x15, 0x76, 0xB6, 0x01, 0x1A, 0x8E, 0x25, 0x87, 0x82, 0xF1, 0x55, 0xD8, 0xC6, 0x43,
0x2A, 0xC0, 0xE5, 0x98, 0xC9, 0x32, 0xD1, 0x94, 0x6F, 0xD9, 0x01, 0xBA, 0x06, 0x81, 0xE0,
0x6D, 0x88, 0xF2, 0x24, 0x2A, 0x25, 0x01, 0x64, 0x5C, 0xBF, 0xF2, 0xD9, 0x99, 0x67, 0x3E,
0xF6, 0x72, 0xEE, 0xE4, 0xE2, 0x33, 0x5C, 0xF8, 0x00, 0x40, 0xE3, 0x2A, 0x9A, 0xF4, 0x3D,
0x22, 0x86, 0x44, 0x3C, 0xFB, 0x0A, 0xA5, 0x7C, 0x3F, 0xCC, 0xF5, 0xF1, 0x16, 0xC4, 0xAC,
0x88, 0xB4, 0xDE, 0x62, 0x94, 0x92, 0x6A, 0x13};
// exponent2 = d mod (q - 1)
static constexpr CryptoPP::byte Exponent2[] = {
0x7C, 0x9D, 0xAD, 0x39, 0xE0, 0xD5, 0x60, 0x14, 0x94, 0x48, 0x19, 0x7F, 0x88, 0x95, 0xD5,
0x8B, 0x80, 0xAD, 0x85, 0x8A, 0x4B, 0x77, 0x37, 0x85, 0xD0, 0x77, 0xBB, 0xBF, 0x89, 0x71,
0x4A, 0x72, 0xCB, 0x72, 0x68, 0x38, 0xEC, 0x02, 0xC6, 0x7D, 0xC6, 0x44, 0x06, 0x33, 0x51,
0x1C, 0xC0, 0xFF, 0x95, 0x8F, 0x0D, 0x75, 0xDC, 0x25, 0xBB, 0x0B, 0x73, 0x91, 0xA9, 0x6D,
0x42, 0xD8, 0x03, 0xB7, 0x68, 0xD4, 0x1E, 0x75, 0x62, 0xA3, 0x70, 0x35, 0x79, 0x78, 0x00,
0xC8, 0xF5, 0xEF, 0x15, 0xB9, 0xFC, 0x4E, 0x47, 0x5A, 0xC8, 0x70, 0x70, 0x5B, 0x52, 0x98,
0xC0, 0xC2, 0x58, 0x4A, 0x70, 0x96, 0xCC, 0xB8, 0x10, 0xE1, 0x2F, 0x78, 0x8B, 0x2B, 0xA1,
0x7F, 0xF9, 0xAC, 0xDE, 0xF0, 0xBB, 0x2B, 0xE2, 0x66, 0xE3, 0x22, 0x92, 0x31, 0x21, 0x57,
0x92, 0xC4, 0xB8, 0xF2, 0x3E, 0x76, 0x20, 0x37};
// e
static constexpr CryptoPP::byte PublicExponent[] = {0, 1, 0, 1};
// (InverseQ)(q) = 1 mod p
static constexpr CryptoPP::byte Coefficient[] = {
0x45, 0x97, 0x55, 0xD4, 0x22, 0x08, 0x5E, 0xF3, 0x5C, 0xB4, 0x05, 0x7A, 0xFD, 0xAA, 0x42,
0x42, 0xAD, 0x9A, 0x8C, 0xA0, 0x6C, 0xBB, 0x1D, 0x68, 0x54, 0x54, 0x6E, 0x3E, 0x32, 0xE3,
0x53, 0x73, 0x76, 0xF1, 0x3E, 0x01, 0xEA, 0xD3, 0xCF, 0xEB, 0xEB, 0x23, 0x3E, 0xC0, 0xBE,
0xCE, 0xEC, 0x2C, 0x89, 0x5F, 0xA8, 0x27, 0x3A, 0x4C, 0xB7, 0xE6, 0x74, 0xBC, 0x45, 0x4C,
0x26, 0xC8, 0x25, 0xFF, 0x34, 0x63, 0x25, 0x37, 0xE1, 0x48, 0x10, 0xC1, 0x93, 0xA6, 0xAF,
0xEB, 0xBA, 0xE3, 0xA2, 0xF1, 0x3D, 0xEF, 0x63, 0xD8, 0xF4, 0xFD, 0xD3, 0xEE, 0xE2, 0x5D,
0xE9, 0x33, 0xCC, 0xAD, 0xBA, 0x75, 0x5C, 0x85, 0xAF, 0xCE, 0xA9, 0x3D, 0xD1, 0xA2, 0x17,
0xF3, 0xF6, 0x98, 0xB3, 0x50, 0x8E, 0x5E, 0xF6, 0xEB, 0x02, 0x8E, 0xA1, 0x62, 0xA7, 0xD6,
0x2C, 0xEC, 0x91, 0xFF, 0x15, 0x40, 0xD2, 0xE3};
// n = p * q
static constexpr CryptoPP::byte Modulus[] = {
0xd2, 0x12, 0xfc, 0x33, 0x5f, 0x6d, 0xdb, 0x83, 0x16, 0x09, 0x62, 0x8b, 0x03, 0x56, 0x27,
0x37, 0x82, 0xd4, 0x77, 0x85, 0x35, 0x29, 0x39, 0x2d, 0x52, 0x6b, 0x8c, 0x4c, 0x8c, 0xfb,
0x06, 0xc1, 0x84, 0x5b, 0xe7, 0xd4, 0xf7, 0xbc, 0xd2, 0x4e, 0x62, 0x45, 0xcd, 0x2a, 0xbb,
0xd7, 0x77, 0x76, 0x45, 0x36, 0x55, 0x27, 0x3f, 0xb3, 0xf5, 0xf9, 0x8e, 0xda, 0x4b, 0xef,
0xaa, 0x59, 0xae, 0xb3, 0x9b, 0xea, 0x54, 0x98, 0xd2, 0x06, 0x32, 0x6a, 0x58, 0x31, 0x2a,
0xe0, 0xd4, 0x4f, 0x90, 0xb5, 0x0a, 0x7d, 0xec, 0xf4, 0x3a, 0x9c, 0x52, 0x67, 0x2d, 0x99,
0x31, 0x8e, 0x0c, 0x43, 0xe6, 0x82, 0xfe, 0x07, 0x46, 0xe1, 0x2e, 0x50, 0xd4, 0x1f, 0x2d,
0x2f, 0x7e, 0xd9, 0x08, 0xba, 0x06, 0xb3, 0xbf, 0x2e, 0x20, 0x3f, 0x4e, 0x3f, 0xfe, 0x44,
0xff, 0xaa, 0x50, 0x43, 0x57, 0x91, 0x69, 0x94, 0x49, 0x15, 0x82, 0x82, 0xe4, 0x0f, 0x4c,
0x8d, 0x9d, 0x2c, 0xc9, 0x5b, 0x1d, 0x64, 0xbf, 0x88, 0x8b, 0xd4, 0xc5, 0x94, 0xe7, 0x65,
0x47, 0x84, 0x1e, 0xe5, 0x79, 0x10, 0xfb, 0x98, 0x93, 0x47, 0xb9, 0x7d, 0x85, 0x12, 0xa6,
0x40, 0x98, 0x2c, 0xf7, 0x92, 0xbc, 0x95, 0x19, 0x32, 0xed, 0xe8, 0x90, 0x56, 0x0d, 0x65,
0xc1, 0xaa, 0x78, 0xc6, 0x2e, 0x54, 0xfd, 0x5f, 0x54, 0xa1, 0xf6, 0x7e, 0xe5, 0xe0, 0x5f,
0x61, 0xc1, 0x20, 0xb4, 0xb9, 0xb4, 0x33, 0x08, 0x70, 0xe4, 0xdf, 0x89, 0x56, 0xed, 0x01,
0x29, 0x46, 0x77, 0x5f, 0x8c, 0xb8, 0xa9, 0xf5, 0x1e, 0x2e, 0xb3, 0xb9, 0xbf, 0xe0, 0x09,
0xb7, 0x8d, 0x28, 0xd4, 0xa6, 0xc3, 0xb8, 0x1e, 0x1f, 0x07, 0xeb, 0xb4, 0x12, 0x0b, 0x95,
0xb8, 0x85, 0x30, 0xfd, 0xdc, 0x39, 0x13, 0xd0, 0x7c, 0xdc, 0x8f, 0xed, 0xf9, 0xc9, 0xa3,
0xc1};
// p
static constexpr CryptoPP::byte Prime1[] = {
0xF9, 0x67, 0xAD, 0x99, 0x12, 0x31, 0x0C, 0x56, 0xA2, 0x2E, 0x16, 0x1C, 0x46, 0xB3, 0x4D,
0x5B, 0x43, 0xBE, 0x42, 0xA2, 0xF6, 0x86, 0x96, 0x80, 0x42, 0xC3, 0xC7, 0x3F, 0xC3, 0x42,
0xF5, 0x87, 0x49, 0x33, 0x9F, 0x07, 0x5D, 0x6E, 0x2C, 0x04, 0xFD, 0xE3, 0xE1, 0xB2, 0xAE,
0x0A, 0x0C, 0xF0, 0xC7, 0xA6, 0x1C, 0xA1, 0x63, 0x50, 0xC8, 0x09, 0x9C, 0x51, 0x24, 0x52,
0x6C, 0x5E, 0x5E, 0xBD, 0x1E, 0x27, 0x06, 0xBB, 0xBC, 0x9E, 0x94, 0xE1, 0x35, 0xD4, 0x6D,
0xB3, 0xCB, 0x3C, 0x68, 0xDD, 0x68, 0xB3, 0xFE, 0x6C, 0xCB, 0x8D, 0x82, 0x20, 0x76, 0x23,
0x63, 0xB7, 0xE9, 0x68, 0x10, 0x01, 0x4E, 0xDC, 0xBA, 0x27, 0x5D, 0x01, 0xC1, 0x2D, 0x80,
0x5E, 0x2B, 0xAF, 0x82, 0x6B, 0xD8, 0x84, 0xB6, 0x10, 0x52, 0x86, 0xA7, 0x89, 0x8E, 0xAE,
0x9A, 0xE2, 0x89, 0xC6, 0xF7, 0xD5, 0x87, 0xFB};
// q
static constexpr CryptoPP::byte Prime2[] = {
0xD7, 0xA1, 0x0F, 0x9A, 0x8B, 0xF2, 0xC9, 0x11, 0x95, 0x32, 0x9A, 0x8C, 0xF0, 0xD9, 0x40,
0x47, 0xF5, 0x68, 0xA0, 0x0D, 0xBD, 0xC1, 0xFC, 0x43, 0x2F, 0x65, 0xF9, 0xC3, 0x61, 0x0F,
0x25, 0x77, 0x54, 0xAD, 0xD7, 0x58, 0xAC, 0x84, 0x40, 0x60, 0x8D, 0x3F, 0xF3, 0x65, 0x89,
0x75, 0xB5, 0xC6, 0x2C, 0x51, 0x1A, 0x2F, 0x1F, 0x22, 0xE4, 0x43, 0x11, 0x54, 0xBE, 0xC9,
0xB4, 0xC7, 0xB5, 0x1B, 0x05, 0x0B, 0xBC, 0x56, 0x9A, 0xCD, 0x4A, 0xD9, 0x73, 0x68, 0x5E,
0x5C, 0xFB, 0x92, 0xB7, 0x8B, 0x0D, 0xFF, 0xF5, 0x07, 0xCA, 0xB4, 0xC8, 0x9B, 0x96, 0x3C,
0x07, 0x9E, 0x3E, 0x6B, 0x2A, 0x11, 0xF2, 0x8A, 0xB1, 0x8A, 0xD7, 0x2E, 0x1B, 0xA5, 0x53,
0x24, 0x06, 0xED, 0x50, 0xB8, 0x90, 0x67, 0xB1, 0xE2, 0x41, 0xC6, 0x92, 0x01, 0xEE, 0x10,
0xF0, 0x61, 0xBB, 0xFB, 0xB2, 0x7D, 0x4A, 0x73};
static constexpr CryptoPP::byte PrivateExponent[] = {
0x32, 0xD9, 0x03, 0x90, 0x8F, 0xBD, 0xB0, 0x8F, 0x57, 0x2B, 0x28, 0x5E, 0x0B, 0x8D, 0xB3,
0xEA, 0x5C, 0xD1, 0x7E, 0xA8, 0x90, 0x88, 0x8C, 0xDD, 0x6A, 0x80, 0xBB, 0xB1, 0xDF, 0xC1,
0xF7, 0x0D, 0xAA, 0x32, 0xF0, 0xB7, 0x7C, 0xCB, 0x88, 0x80, 0x0E, 0x8B, 0x64, 0xB0, 0xBE,
0x4C, 0xD6, 0x0E, 0x9B, 0x8C, 0x1E, 0x2A, 0x64, 0xE1, 0xF3, 0x5C, 0xD7, 0x76, 0x01, 0x41,
0x5E, 0x93, 0x5C, 0x94, 0xFE, 0xDD, 0x46, 0x62, 0xC3, 0x1B, 0x5A, 0xE2, 0xA0, 0xBC, 0x2D,
0xEB, 0xC3, 0x98, 0x0A, 0xA7, 0xB7, 0x85, 0x69, 0x70, 0x68, 0x2B, 0x64, 0x4A, 0xB3, 0x1F,
0xCC, 0x7D, 0xDC, 0x7C, 0x26, 0xF4, 0x77, 0xF6, 0x5C, 0xF2, 0xAE, 0x5A, 0x44, 0x2D, 0xD3,
0xAB, 0x16, 0x62, 0x04, 0x19, 0xBA, 0xFB, 0x90, 0xFF, 0xE2, 0x30, 0x50, 0x89, 0x6E, 0xCB,
0x56, 0xB2, 0xEB, 0xC0, 0x91, 0x16, 0x92, 0x5E, 0x30, 0x8E, 0xAE, 0xC7, 0x94, 0x5D, 0xFD,
0x35, 0xE1, 0x20, 0xF8, 0xAD, 0x3E, 0xBC, 0x08, 0xBF, 0xC0, 0x36, 0x74, 0x9F, 0xD5, 0xBB,
0x52, 0x08, 0xFD, 0x06, 0x66, 0xF3, 0x7A, 0xB3, 0x04, 0xF4, 0x75, 0x29, 0x5D, 0xE9, 0x5F,
0xAA, 0x10, 0x30, 0xB2, 0x0F, 0x5A, 0x1A, 0xC1, 0x2A, 0xB3, 0xFE, 0xCB, 0x21, 0xAD, 0x80,
0xEC, 0x8F, 0x20, 0x09, 0x1C, 0xDB, 0xC5, 0x58, 0x94, 0xC2, 0x9C, 0xC6, 0xCE, 0x82, 0x65,
0x3E, 0x57, 0x90, 0xBC, 0xA9, 0x8B, 0x06, 0xB4, 0xF0, 0x72, 0xF6, 0x77, 0xDF, 0x98, 0x64,
0xF1, 0xEC, 0xFE, 0x37, 0x2D, 0xBC, 0xAE, 0x8C, 0x08, 0x81, 0x1F, 0xC3, 0xC9, 0x89, 0x1A,
0xC7, 0x42, 0x82, 0x4B, 0x2E, 0xDC, 0x8E, 0x8D, 0x73, 0xCE, 0xB1, 0xCC, 0x01, 0xD9, 0x08,
0x70, 0x87, 0x3C, 0x44, 0x08, 0xEC, 0x49, 0x8F, 0x81, 0x5A, 0xE2, 0x40, 0xFF, 0x77, 0xFC,
0x0D};
};

View File

@ -158,6 +158,10 @@ public:
float Framerate = 1.0f / 60.0f;
float FrameDeltaTime;
std::pair<u32, u32> game_resolution{};
std::pair<u32, u32> output_resolution{};
bool is_using_fsr{};
void ShowDebugMessage(std::string message) {
if (message.empty()) {
return;

View File

@ -40,6 +40,10 @@ public:
return ORBIS_KERNEL_ERROR_EBADF;
}
virtual size_t pwritev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt, u64 offset) {
return ORBIS_KERNEL_ERROR_EBADF;
}
virtual s64 lseek(s64 offset, int whence) {
return ORBIS_KERNEL_ERROR_EBADF;
}

View File

@ -5,6 +5,7 @@
#include <imgui.h>
#include "SDL3/SDL_log.h"
#include "common/config.h"
#include "common/singleton.h"
#include "common/types.h"
@ -21,8 +22,8 @@
extern std::unique_ptr<Vulkan::Presenter> presenter;
using namespace ImGui;
using namespace Core::Devtools;
using L = Core::Devtools::Layer;
using namespace ::Core::Devtools;
using L = ::Core::Devtools::Layer;
static bool show_simple_fps = false;
static bool visibility_toggled = false;
@ -81,8 +82,24 @@ void L::DrawMenuBar() {
ImGui::EndMenu();
}
if (BeginMenu("Display")) {
auto& pp_settings = presenter->GetPPSettingsRef();
if (BeginMenu("Brightness")) {
SliderFloat("Gamma", &presenter->GetGammaRef(), 0.1f, 2.0f);
SliderFloat("Gamma", &pp_settings.gamma, 0.1f, 2.0f);
ImGui::EndMenu();
}
if (BeginMenu("FSR")) {
auto& fsr = presenter->GetFsrSettingsRef();
Checkbox("FSR Enabled", &fsr.enable);
BeginDisabled(!fsr.enable);
{
Checkbox("RCAS", &fsr.use_rcas);
BeginDisabled(!fsr.use_rcas);
{
SliderFloat("RCAS Attenuation", &fsr.rcas_attenuation, 0.0, 3.0);
}
EndDisabled();
}
EndDisabled();
ImGui::EndMenu();
}
ImGui::EndMenu();
@ -101,22 +118,6 @@ void L::DrawMenuBar() {
EndMainMenuBar();
}
if (IsKeyPressed(ImGuiKey_F9, false)) {
if (io.KeyCtrl && io.KeyAlt) {
if (!DebugState.ShouldPauseInSubmit()) {
DebugState.RequestFrameDump(dump_frame_count);
}
}
if (!io.KeyCtrl && !io.KeyAlt) {
if (isSystemPaused) {
DebugState.ResumeGuestThreads();
} else {
DebugState.PauseGuestThreads();
}
}
}
if (open_popup_options) {
OpenPopup("GPU Tools Options");
just_opened_options = true;
@ -365,6 +366,32 @@ void L::Draw() {
visibility_toggled = true;
}
if (IsKeyPressed(ImGuiKey_F9, false)) {
if (io.KeyCtrl && io.KeyAlt) {
if (!DebugState.ShouldPauseInSubmit()) {
DebugState.RequestFrameDump(dump_frame_count);
}
} else {
if (DebugState.IsGuestThreadsPaused()) {
DebugState.ResumeGuestThreads();
SDL_Log("Game resumed from Keyboard");
show_pause_status = false;
} else {
DebugState.PauseGuestThreads();
SDL_Log("Game paused from Keyboard");
show_pause_status = true;
}
visibility_toggled = true;
}
}
if (show_pause_status) {
ImVec2 pos = ImVec2(10, 10);
ImU32 color = IM_COL32(255, 255, 255, 255);
ImGui::GetForegroundDrawList()->AddText(pos, color, "Game Paused Press F9 to Resume");
}
if (show_simple_fps) {
if (Begin("Video Info", nullptr,
ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoDecoration |

View File

@ -19,6 +19,7 @@ public:
static void SetupSettings();
void Draw() override;
bool show_pause_status = false;
};
} // namespace Core::Devtools

View File

@ -1,9 +1,14 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "options.h"
#include <memory>
#include <imgui.h>
#include "options.h"
#include "video_core/renderer_vulkan/vk_presenter.h"
extern std::unique_ptr<Vulkan::Presenter> presenter;
namespace Core::Devtools {
@ -12,6 +17,7 @@ TOptions Options;
void LoadOptionsConfig(const char* line) {
char str[512];
int i;
float f;
if (sscanf(line, "disassembler_cli_isa=%511[^\n]", str) == 1) {
Options.disassembler_cli_isa = str;
return;
@ -24,12 +30,26 @@ void LoadOptionsConfig(const char* line) {
Options.frame_dump_render_on_collapse = i != 0;
return;
}
if (sscanf(line, "fsr_enabled=%d", &i) == 1) {
presenter->GetFsrSettingsRef().enable = i != 0;
return;
}
if (sscanf(line, "fsr_rcas_enabled=%d", &i) == 1) {
presenter->GetFsrSettingsRef().use_rcas = i != 0;
return;
}
if (sscanf(line, "fsr_rcas_attenuation=%f", &f) == 1) {
presenter->GetFsrSettingsRef().rcas_attenuation = f;
}
}
void SerializeOptionsConfig(ImGuiTextBuffer* buf) {
buf->appendf("disassembler_cli_isa=%s\n", Options.disassembler_cli_isa.c_str());
buf->appendf("disassembler_cli_spv=%s\n", Options.disassembler_cli_spv.c_str());
buf->appendf("frame_dump_render_on_collapse=%d\n", Options.frame_dump_render_on_collapse);
buf->appendf("fsr_enabled=%d\n", presenter->GetFsrSettingsRef().enable);
buf->appendf("fsr_rcas_enabled=%d\n", presenter->GetFsrSettingsRef().use_rcas);
buf->appendf("fsr_rcas_attenuation=%f\n", presenter->GetFsrSettingsRef().rcas_attenuation);
}
} // namespace Core::Devtools

View File

@ -74,7 +74,7 @@ void FrameGraph::Draw() {
if (!is_open) {
return;
}
SetNextWindowSize({340.0, 185.0f}, ImGuiCond_FirstUseEver);
SetNextWindowSize({308.0, 270.0f}, ImGuiCond_FirstUseEver);
if (Begin("Video debug info", &is_open)) {
const auto& ctx = *GImGui;
const auto& io = ctx.IO;
@ -88,13 +88,20 @@ void FrameGraph::Draw() {
frameRate = 1000.0f / deltaTime;
}
SeparatorText("Frame graph");
DrawFrameGraph();
SeparatorText("Renderer info");
Text("Frame time: %.3f ms (%.1f FPS)", deltaTime, frameRate);
Text("Presenter time: %.3f ms (%.1f FPS)", io.DeltaTime * 1000.0f, 1.0f / io.DeltaTime);
Text("Flip frame: %d Gnm submit frame: %d", DebugState.flip_frame_count.load(),
DebugState.gnm_frame_count.load());
SeparatorText("Frame graph");
DrawFrameGraph();
Text("Game Res: %dx%d", DebugState.game_resolution.first,
DebugState.game_resolution.second);
Text("Output Res: %dx%d", DebugState.output_resolution.first,
DebugState.output_resolution.second);
Text("FSR: %s", DebugState.is_using_fsr ? "on" : "off");
}
End();
}

View File

@ -627,65 +627,56 @@ void TextEditor::HandleKeyboardInputs() {
io.WantCaptureKeyboard = true;
io.WantTextInput = true;
if (!IsReadOnly() && ctrl && !shift && !alt &&
ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Z)))
if (!IsReadOnly() && ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_Z))
Undo();
else if (!IsReadOnly() && !ctrl && !shift && alt &&
ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Backspace)))
else if (!IsReadOnly() && !ctrl && !shift && alt && ImGui::IsKeyPressed(ImGuiKey_Backspace))
Undo();
else if (!IsReadOnly() && ctrl && !shift && !alt &&
ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Y)))
else if (!IsReadOnly() && ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_Y))
Redo();
else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_UpArrow)))
else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGuiKey_UpArrow))
MoveUp(1, shift);
else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_DownArrow)))
else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGuiKey_DownArrow))
MoveDown(1, shift);
else if (!alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_LeftArrow)))
else if (!alt && ImGui::IsKeyPressed(ImGuiKey_LeftArrow))
MoveLeft(1, shift, ctrl);
else if (!alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_RightArrow)))
else if (!alt && ImGui::IsKeyPressed(ImGuiKey_RightArrow))
MoveRight(1, shift, ctrl);
else if (!alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_PageUp)))
else if (!alt && ImGui::IsKeyPressed(ImGuiKey_PageUp))
MoveUp(GetPageSize() - 4, shift);
else if (!alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_PageDown)))
else if (!alt && ImGui::IsKeyPressed(ImGuiKey_PageDown))
MoveDown(GetPageSize() - 4, shift);
else if (!alt && ctrl && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Home)))
else if (!alt && ctrl && ImGui::IsKeyPressed(ImGuiKey_Home))
MoveTop(shift);
else if (ctrl && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_End)))
else if (ctrl && !alt && ImGui::IsKeyPressed(ImGuiKey_End))
MoveBottom(shift);
else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Home)))
else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGuiKey_Home))
MoveHome(shift);
else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_End)))
else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGuiKey_End))
MoveEnd(shift);
else if (!IsReadOnly() && !ctrl && !shift && !alt &&
ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Delete)))
else if (!IsReadOnly() && !ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_Delete))
Delete();
else if (!IsReadOnly() && !ctrl && !shift && !alt &&
ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Backspace)))
ImGui::IsKeyPressed(ImGuiKey_Backspace))
Backspace();
else if (!ctrl && !shift && !alt &&
ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Insert)))
else if (!ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_Insert))
mOverwrite ^= true;
else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Insert)))
else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_Insert))
Copy();
else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_C)))
else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_C))
Copy();
else if (!IsReadOnly() && !ctrl && shift && !alt &&
ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Insert)))
else if (!IsReadOnly() && !ctrl && shift && !alt && ImGui::IsKeyPressed(ImGuiKey_Insert))
Paste();
else if (!IsReadOnly() && ctrl && !shift && !alt &&
ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_V)))
else if (!IsReadOnly() && ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_V))
Paste();
else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_X)))
else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_X))
Cut();
else if (!ctrl && shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Delete)))
else if (!ctrl && shift && !alt && ImGui::IsKeyPressed(ImGuiKey_Delete))
Cut();
else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_A)))
else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_A))
SelectAll();
else if (!IsReadOnly() && !ctrl && !shift && !alt &&
ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Enter)))
else if (!IsReadOnly() && !ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_Enter))
EnterCharacter('\n', false);
else if (!IsReadOnly() && !ctrl && !alt &&
ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Tab)))
else if (!IsReadOnly() && !ctrl && !alt && ImGui::IsKeyPressed(ImGuiKey_Tab))
EnterCharacter('\t', shift);
if (!IsReadOnly() && !io.InputQueueCharacters.empty()) {

View File

@ -1,473 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <zlib.h>
#include "common/io_file.h"
#include "common/logging/formatter.h"
#include "core/file_format/pkg.h"
#include "core/file_format/pkg_type.h"
static void DecompressPFSC(std::span<char> compressed_data, std::span<char> decompressed_data) {
z_stream decompressStream;
decompressStream.zalloc = Z_NULL;
decompressStream.zfree = Z_NULL;
decompressStream.opaque = Z_NULL;
if (inflateInit(&decompressStream) != Z_OK) {
// std::cerr << "Error initializing zlib for deflation." << std::endl;
}
decompressStream.avail_in = compressed_data.size();
decompressStream.next_in = reinterpret_cast<unsigned char*>(compressed_data.data());
decompressStream.avail_out = decompressed_data.size();
decompressStream.next_out = reinterpret_cast<unsigned char*>(decompressed_data.data());
if (inflate(&decompressStream, Z_FINISH)) {
}
if (inflateEnd(&decompressStream) != Z_OK) {
// std::cerr << "Error ending zlib inflate" << std::endl;
}
}
u32 GetPFSCOffset(std::span<const u8> pfs_image) {
static constexpr u32 PfscMagic = 0x43534650;
u32 value;
for (u32 i = 0x20000; i < pfs_image.size(); i += 0x10000) {
std::memcpy(&value, &pfs_image[i], sizeof(u32));
if (value == PfscMagic)
return i;
}
return -1;
}
PKG::PKG() = default;
PKG::~PKG() = default;
bool PKG::Open(const std::filesystem::path& filepath, std::string& failreason) {
Common::FS::IOFile file(filepath, Common::FS::FileAccessMode::Read);
if (!file.IsOpen()) {
return false;
}
pkgSize = file.GetSize();
file.Read(pkgheader);
if (pkgheader.magic != 0x7F434E54)
return false;
for (const auto& flag : flagNames) {
if (isFlagSet(pkgheader.pkg_content_flags, flag.first)) {
if (!pkgFlags.empty())
pkgFlags += (", ");
pkgFlags += (flag.second);
}
}
// Find title id it is part of pkg_content_id starting at offset 0x40
file.Seek(0x47); // skip first 7 characters of content_id
file.Read(pkgTitleID);
u32 offset = pkgheader.pkg_table_entry_offset;
u32 n_files = pkgheader.pkg_table_entry_count;
if (!file.Seek(offset)) {
failreason = "Failed to seek to PKG table entry offset";
return false;
}
for (int i = 0; i < n_files; i++) {
PKGEntry entry{};
file.Read(entry.id);
file.Read(entry.filename_offset);
file.Read(entry.flags1);
file.Read(entry.flags2);
file.Read(entry.offset);
file.Read(entry.size);
file.Seek(8, Common::FS::SeekOrigin::CurrentPosition);
// Try to figure out the name
const auto name = GetEntryNameByType(entry.id);
if (name == "param.sfo") {
sfo.clear();
if (!file.Seek(entry.offset)) {
failreason = "Failed to seek to param.sfo offset";
return false;
}
sfo.resize(entry.size);
file.ReadRaw<u8>(sfo.data(), entry.size);
}
}
file.Close();
return true;
}
bool PKG::Extract(const std::filesystem::path& filepath, const std::filesystem::path& extract,
std::string& failreason) {
extract_path = extract;
pkgpath = filepath;
Common::FS::IOFile file(filepath, Common::FS::FileAccessMode::Read);
if (!file.IsOpen()) {
return false;
}
pkgSize = file.GetSize();
file.ReadRaw<u8>(&pkgheader, sizeof(PKGHeader));
if (pkgheader.magic != 0x7F434E54)
return false;
if (pkgheader.pkg_size > pkgSize) {
failreason = "PKG file size is different";
return false;
}
if ((pkgheader.pkg_content_size + pkgheader.pkg_content_offset) > pkgheader.pkg_size) {
failreason = "Content size is bigger than pkg size";
return false;
}
u32 offset = pkgheader.pkg_table_entry_offset;
u32 n_files = pkgheader.pkg_table_entry_count;
std::array<u8, 64> concatenated_ivkey_dk3;
std::array<u8, 32> seed_digest;
std::array<std::array<u8, 32>, 7> digest1;
std::array<std::array<u8, 256>, 7> key1;
std::array<u8, 256> imgkeydata;
if (!file.Seek(offset)) {
failreason = "Failed to seek to PKG table entry offset";
return false;
}
for (int i = 0; i < n_files; i++) {
PKGEntry entry{};
file.Read(entry.id);
file.Read(entry.filename_offset);
file.Read(entry.flags1);
file.Read(entry.flags2);
file.Read(entry.offset);
file.Read(entry.size);
file.Seek(8, Common::FS::SeekOrigin::CurrentPosition);
auto currentPos = file.Tell();
// Try to figure out the name
const auto name = GetEntryNameByType(entry.id);
const auto filepath = extract_path / "sce_sys" / name;
std::filesystem::create_directories(filepath.parent_path());
if (name.empty()) {
// Just print with id
Common::FS::IOFile out(extract_path / "sce_sys" / std::to_string(entry.id),
Common::FS::FileAccessMode::Write);
if (!file.Seek(entry.offset)) {
failreason = "Failed to seek to PKG entry offset";
return false;
}
std::vector<u8> data;
data.resize(entry.size);
file.ReadRaw<u8>(data.data(), entry.size);
out.WriteRaw<u8>(data.data(), entry.size);
out.Close();
file.Seek(currentPos);
continue;
}
if (entry.id == 0x1) { // DIGESTS, seek;
// file.Seek(entry.offset, fsSeekSet);
} else if (entry.id == 0x10) { // ENTRY_KEYS, seek;
file.Seek(entry.offset);
file.Read(seed_digest);
for (int i = 0; i < 7; i++) {
file.Read(digest1[i]);
}
for (int i = 0; i < 7; i++) {
file.Read(key1[i]);
}
PKG::crypto.RSA2048Decrypt(dk3_, key1[3], true); // decrypt DK3
} else if (entry.id == 0x20) { // IMAGE_KEY, seek; IV_KEY
file.Seek(entry.offset);
file.Read(imgkeydata);
// The Concatenated iv + dk3 imagekey for HASH256
std::memcpy(concatenated_ivkey_dk3.data(), &entry, sizeof(entry));
std::memcpy(concatenated_ivkey_dk3.data() + sizeof(entry), dk3_.data(), sizeof(dk3_));
PKG::crypto.ivKeyHASH256(concatenated_ivkey_dk3, ivKey); // ivkey_
// imgkey_ to use for last step to get ekpfs
PKG::crypto.aesCbcCfb128Decrypt(ivKey, imgkeydata, imgKey);
// ekpfs key to get data and tweak keys.
PKG::crypto.RSA2048Decrypt(ekpfsKey, imgKey, false);
} else if (entry.id == 0x80) {
// GENERAL_DIGESTS, seek;
// file.Seek(entry.offset, fsSeekSet);
}
Common::FS::IOFile out(extract_path / "sce_sys" / name, Common::FS::FileAccessMode::Write);
if (!file.Seek(entry.offset)) {
failreason = "Failed to seek to PKG entry offset";
return false;
}
std::vector<u8> data;
data.resize(entry.size);
file.ReadRaw<u8>(data.data(), entry.size);
out.WriteRaw<u8>(data.data(), entry.size);
out.Close();
// Decrypt Np stuff and overwrite.
if (entry.id == 0x400 || entry.id == 0x401 || entry.id == 0x402 ||
entry.id == 0x403) { // somehow 0x401 is not decrypting
decNp.resize(entry.size);
if (!file.Seek(entry.offset)) {
failreason = "Failed to seek to PKG entry offset";
return false;
}
std::vector<u8> data;
data.resize(entry.size);
file.ReadRaw<u8>(data.data(), entry.size);
std::span<u8> cipherNp(data.data(), entry.size);
std::array<u8, 64> concatenated_ivkey_dk3_;
std::memcpy(concatenated_ivkey_dk3_.data(), &entry, sizeof(entry));
std::memcpy(concatenated_ivkey_dk3_.data() + sizeof(entry), dk3_.data(), sizeof(dk3_));
PKG::crypto.ivKeyHASH256(concatenated_ivkey_dk3_, ivKey);
PKG::crypto.aesCbcCfb128DecryptEntry(ivKey, cipherNp, decNp);
Common::FS::IOFile out(extract_path / "sce_sys" / name,
Common::FS::FileAccessMode::Write);
out.Write(decNp);
out.Close();
}
file.Seek(currentPos);
}
// Read the seed
std::array<u8, 16> seed;
if (!file.Seek(pkgheader.pfs_image_offset + 0x370)) {
failreason = "Failed to seek to PFS image offset";
return false;
}
file.Read(seed);
// Get data and tweak keys.
PKG::crypto.PfsGenCryptoKey(ekpfsKey, seed, dataKey, tweakKey);
const u32 length = pkgheader.pfs_cache_size * 0x2; // Seems to be ok.
int num_blocks = 0;
std::vector<u8> pfsc(length);
if (length != 0) {
// Read encrypted pfs_image
std::vector<u8> pfs_encrypted(length);
file.Seek(pkgheader.pfs_image_offset);
file.Read(pfs_encrypted);
file.Close();
// Decrypt the pfs_image.
std::vector<u8> pfs_decrypted(length);
PKG::crypto.decryptPFS(dataKey, tweakKey, pfs_encrypted, pfs_decrypted, 0);
// Retrieve PFSC from decrypted pfs_image.
pfsc_offset = GetPFSCOffset(pfs_decrypted);
std::memcpy(pfsc.data(), pfs_decrypted.data() + pfsc_offset, length - pfsc_offset);
PFSCHdr pfsChdr;
std::memcpy(&pfsChdr, pfsc.data(), sizeof(pfsChdr));
num_blocks = (int)(pfsChdr.data_length / pfsChdr.block_sz2);
sectorMap.resize(num_blocks + 1); // 8 bytes, need extra 1 to get the last offset.
for (int i = 0; i < num_blocks + 1; i++) {
std::memcpy(&sectorMap[i], pfsc.data() + pfsChdr.block_offsets + i * 8, 8);
}
}
u32 ent_size = 0;
u32 ndinode = 0;
int ndinode_counter = 0;
bool dinode_reached = false;
bool uroot_reached = false;
std::vector<char> compressedData;
std::vector<char> decompressedData(0x10000);
// Get iNdoes and Dirents.
for (int i = 0; i < num_blocks; i++) {
const u64 sectorOffset = sectorMap[i];
const u64 sectorSize = sectorMap[i + 1] - sectorOffset;
compressedData.resize(sectorSize);
std::memcpy(compressedData.data(), pfsc.data() + sectorOffset, sectorSize);
if (sectorSize == 0x10000) // Uncompressed data
std::memcpy(decompressedData.data(), compressedData.data(), 0x10000);
else if (sectorSize < 0x10000) // Compressed data
DecompressPFSC(compressedData, decompressedData);
if (i == 0) {
std::memcpy(&ndinode, decompressedData.data() + 0x30, 4); // number of folders and files
}
int occupied_blocks =
(ndinode * 0xA8) / 0x10000; // how many blocks(0x10000) are taken by iNodes.
if (((ndinode * 0xA8) % 0x10000) != 0)
occupied_blocks += 1;
if (i >= 1 && i <= occupied_blocks) { // Get all iNodes, gives type, file size and location.
for (int p = 0; p < 0x10000; p += 0xA8) {
Inode node;
std::memcpy(&node, &decompressedData[p], sizeof(node));
if (node.Mode == 0) {
break;
}
iNodeBuf.push_back(node);
}
}
// let's deal with the root/uroot entries here.
// Sometimes it's more than 2 entries (Tomb Raider Remastered)
const std::string_view flat_path_table(&decompressedData[0x10], 15);
if (flat_path_table == "flat_path_table") {
uroot_reached = true;
}
if (uroot_reached) {
for (int i = 0; i < 0x10000; i += ent_size) {
Dirent dirent;
std::memcpy(&dirent, &decompressedData[i], sizeof(dirent));
ent_size = dirent.entsize;
if (dirent.ino != 0) {
ndinode_counter++;
} else {
// Set the the folder according to the current inode.
// Can be 2 or more (rarely)
auto parent_path = extract_path.parent_path();
auto title_id = GetTitleID();
if (parent_path.filename() != title_id &&
!fmt::UTF(extract_path.u8string()).data.ends_with("-UPDATE")) {
extractPaths[ndinode_counter] = parent_path / title_id;
} else {
// DLCs path has different structure
extractPaths[ndinode_counter] = extract_path;
}
uroot_reached = false;
break;
}
}
}
const char dot = decompressedData[0x10];
const std::string_view dotdot(&decompressedData[0x28], 2);
if (dot == '.' && dotdot == "..") {
dinode_reached = true;
}
// Get folder and file names.
bool end_reached = false;
if (dinode_reached) {
for (int j = 0; j < 0x10000; j += ent_size) { // Skip the first parent and child.
Dirent dirent;
std::memcpy(&dirent, &decompressedData[j], sizeof(dirent));
// Stop here and continue the main loop
if (dirent.ino == 0) {
break;
}
ent_size = dirent.entsize;
auto& table = fsTable.emplace_back();
table.name = std::string(dirent.name, dirent.namelen);
table.inode = dirent.ino;
table.type = dirent.type;
if (table.type == PFS_CURRENT_DIR) {
current_dir = extractPaths[table.inode];
}
extractPaths[table.inode] = current_dir / std::filesystem::path(table.name);
if (table.type == PFS_FILE || table.type == PFS_DIR) {
if (table.type == PFS_DIR) { // Create dirs.
std::filesystem::create_directory(extractPaths[table.inode]);
}
ndinode_counter++;
if ((ndinode_counter + 1) == ndinode) // 1 for the image itself (root).
end_reached = true;
}
}
if (end_reached) {
break;
}
}
}
return true;
}
void PKG::ExtractFiles(const int index) {
int inode_number = fsTable[index].inode;
int inode_type = fsTable[index].type;
std::string inode_name = fsTable[index].name;
if (inode_type == PFS_FILE) {
int sector_loc = iNodeBuf[inode_number].loc;
int nblocks = iNodeBuf[inode_number].Blocks;
int bsize = iNodeBuf[inode_number].Size;
Common::FS::IOFile inflated;
inflated.Open(extractPaths[inode_number], Common::FS::FileAccessMode::Write);
Common::FS::IOFile pkgFile; // Open the file for each iteration to avoid conflict.
pkgFile.Open(pkgpath, Common::FS::FileAccessMode::Read);
int size_decompressed = 0;
std::vector<char> compressedData;
std::vector<char> decompressedData(0x10000);
u64 pfsc_buf_size = 0x11000; // extra 0x1000
std::vector<u8> pfsc(pfsc_buf_size);
std::vector<u8> pfs_decrypted(pfsc_buf_size);
for (int j = 0; j < nblocks; j++) {
u64 sectorOffset =
sectorMap[sector_loc + j]; // offset into PFSC_image and not pfs_image.
u64 sectorSize = sectorMap[sector_loc + j + 1] -
sectorOffset; // indicates if data is compressed or not.
u64 fileOffset = (pkgheader.pfs_image_offset + pfsc_offset + sectorOffset);
u64 currentSector1 =
(pfsc_offset + sectorOffset) / 0x1000; // block size is 0x1000 for xts decryption.
int sectorOffsetMask = (sectorOffset + pfsc_offset) & 0xFFFFF000;
int previousData = (sectorOffset + pfsc_offset) - sectorOffsetMask;
pkgFile.Seek(fileOffset - previousData);
pkgFile.Read(pfsc);
PKG::crypto.decryptPFS(dataKey, tweakKey, pfsc, pfs_decrypted, currentSector1);
compressedData.resize(sectorSize);
std::memcpy(compressedData.data(), pfs_decrypted.data() + previousData, sectorSize);
if (sectorSize == 0x10000) // Uncompressed data
std::memcpy(decompressedData.data(), compressedData.data(), 0x10000);
else if (sectorSize < 0x10000) // Compressed data
DecompressPFSC(compressedData, decompressedData);
size_decompressed += 0x10000;
if (j < nblocks - 1) {
inflated.WriteRaw<u8>(decompressedData.data(), decompressedData.size());
} else {
// This is to remove the zeros at the end of the file.
const u32 write_size = decompressedData.size() - (size_decompressed - bsize);
inflated.WriteRaw<u8>(decompressedData.data(), write_size);
}
}
pkgFile.Close();
inflated.Close();
}
}

View File

@ -1,174 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <array>
#include <filesystem>
#include <string>
#include <unordered_map>
#include <vector>
#include "common/endian.h"
#include "core/crypto/crypto.h"
#include "pfs.h"
#include "trp.h"
struct PKGHeader {
u32_be magic; // Magic
u32_be pkg_type;
u32_be pkg_0x8; // unknown field
u32_be pkg_file_count;
u32_be pkg_table_entry_count;
u16_be pkg_sc_entry_count;
u16_be pkg_table_entry_count_2; // same as pkg_entry_count
u32_be pkg_table_entry_offset; // file table offset
u32_be pkg_sc_entry_data_size;
u64_be pkg_body_offset; // offset of PKG entries
u64_be pkg_body_size; // length of all PKG entries
u64_be pkg_content_offset;
u64_be pkg_content_size;
u8 pkg_content_id[0x24]; // packages' content ID as a 36-byte string
u8 pkg_padding[0xC]; // padding
u32_be pkg_drm_type; // DRM type
u32_be pkg_content_type; // Content type
u32_be pkg_content_flags; // Content flags
u32_be pkg_promote_size;
u32_be pkg_version_date;
u32_be pkg_version_hash;
u32_be pkg_0x088;
u32_be pkg_0x08C;
u32_be pkg_0x090;
u32_be pkg_0x094;
u32_be pkg_iro_tag;
u32_be pkg_drm_type_version;
u8 pkg_zeroes_1[0x60];
/* Digest table */
u8 digest_entries1[0x20]; // sha256 digest for main entry 1
u8 digest_entries2[0x20]; // sha256 digest for main entry 2
u8 digest_table_digest[0x20]; // sha256 digest for digest table
u8 digest_body_digest[0x20]; // sha256 digest for main table
u8 pkg_zeroes_2[0x280];
u32_be pkg_0x400;
u32_be pfs_image_count; // count of PFS images
u64_be pfs_image_flags; // PFS flags
u64_be pfs_image_offset; // offset to start of external PFS image
u64_be pfs_image_size; // size of external PFS image
u64_be mount_image_offset;
u64_be mount_image_size;
u64_be pkg_size;
u32_be pfs_signed_size;
u32_be pfs_cache_size;
u8 pfs_image_digest[0x20];
u8 pfs_signed_digest[0x20];
u64_be pfs_split_size_nth_0;
u64_be pfs_split_size_nth_1;
u8 pkg_zeroes_3[0xB50];
u8 pkg_digest[0x20];
};
enum class PKGContentFlag {
FIRST_PATCH = 0x100000,
PATCHGO = 0x200000,
REMASTER = 0x400000,
PS_CLOUD = 0x800000,
GD_AC = 0x2000000,
NON_GAME = 0x4000000,
UNKNOWN_0x8000000 = 0x8000000,
SUBSEQUENT_PATCH = 0x40000000,
DELTA_PATCH = 0x41000000,
CUMULATIVE_PATCH = 0x60000000
};
struct PKGEntry {
u32_be id; // File ID, useful for files without a filename entry
u32_be filename_offset; // Offset into the filenames table (ID 0x200) where this file's name is
// located
u32_be flags1; // Flags including encrypted flag, etc
u32_be flags2; // Flags including encryption key index, etc
u32_be offset; // Offset into PKG to find the file
u32_be size; // Size of the file
u64_be padding; // blank padding
};
static_assert(sizeof(PKGEntry) == 32);
class PKG {
public:
PKG();
~PKG();
bool Open(const std::filesystem::path& filepath, std::string& failreason);
void ExtractFiles(const int index);
bool Extract(const std::filesystem::path& filepath, const std::filesystem::path& extract,
std::string& failreason);
std::vector<u8> sfo;
u32 GetNumberOfFiles() {
return fsTable.size();
}
u64 GetPkgSize() {
return pkgSize;
}
std::string GetPkgFlags() {
return pkgFlags;
}
std::string_view GetTitleID() {
return std::string_view(pkgTitleID, 9);
}
PKGHeader GetPkgHeader() {
return pkgheader;
}
static bool isFlagSet(u32_be variable, PKGContentFlag flag) {
return (variable) & static_cast<u32>(flag);
}
static constexpr std::array<std::pair<PKGContentFlag, std::string_view>, 10> flagNames = {
{{PKGContentFlag::FIRST_PATCH, "FIRST_PATCH"},
{PKGContentFlag::PATCHGO, "PATCHGO"},
{PKGContentFlag::REMASTER, "REMASTER"},
{PKGContentFlag::PS_CLOUD, "PS_CLOUD"},
{PKGContentFlag::GD_AC, "GD_AC"},
{PKGContentFlag::NON_GAME, "NON_GAME"},
{PKGContentFlag::UNKNOWN_0x8000000, "UNKNOWN_0x8000000"},
{PKGContentFlag::SUBSEQUENT_PATCH, "SUBSEQUENT_PATCH"},
{PKGContentFlag::DELTA_PATCH, "DELTA_PATCH"},
{PKGContentFlag::CUMULATIVE_PATCH, "CUMULATIVE_PATCH"}}};
private:
Crypto crypto;
TRP trp;
u64 pkgSize = 0;
char pkgTitleID[9];
PKGHeader pkgheader;
std::string pkgFlags;
std::unordered_map<int, std::filesystem::path> extractPaths;
std::vector<pfs_fs_table> fsTable;
std::vector<Inode> iNodeBuf;
std::vector<u64> sectorMap;
u64 pfsc_offset;
std::array<u8, 32> dk3_;
std::array<u8, 32> ivKey;
std::array<u8, 256> imgKey;
std::array<u8, 32> ekpfsKey;
std::array<u8, 16> dataKey;
std::array<u8, 16> tweakKey;
std::vector<u8> decNp;
std::filesystem::path pkgpath;
std::filesystem::path current_dir;
std::filesystem::path extract_path;
};

View File

@ -1,638 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm>
#include <array>
#include "pkg_type.h"
struct PkgEntryValue {
u32 type;
std::string_view name;
operator u32() const noexcept {
return type;
}
};
constexpr static std::array<PkgEntryValue, 611> PkgEntries = {{
{0x0001, "digests"},
{0x0010, "entry_keys"},
{0x0020, "image_key"},
{0x0080, "general_digests"},
{0x0100, "metas"},
{0x0200, "entry_names"},
{0x0400, "license.dat"},
{0x0401, "license.info"},
{0x0402, "nptitle.dat"},
{0x0403, "npbind.dat"},
{0x0404, "selfinfo.dat"},
{0x0406, "imageinfo.dat"},
{0x0407, "target-deltainfo.dat"},
{0x0408, "origin-deltainfo.dat"},
{0x0409, "psreserved.dat"},
{0x1000, "param.sfo"},
{0x1001, "playgo-chunk.dat"},
{0x1002, "playgo-chunk.sha"},
{0x1003, "playgo-manifest.xml"},
{0x1004, "pronunciation.xml"},
{0x1005, "pronunciation.sig"},
{0x1006, "pic1.png"},
{0x1007, "pubtoolinfo.dat"},
{0x1008, "app/playgo-chunk.dat"},
{0x1009, "app/playgo-chunk.sha"},
{0x100A, "app/playgo-manifest.xml"},
{0x100B, "shareparam.json"},
{0x100C, "shareoverlayimage.png"},
{0x100D, "save_data.png"},
{0x100E, "shareprivacyguardimage.png"},
{0x1200, "icon0.png"},
{0x1201, "icon0_00.png"},
{0x1202, "icon0_01.png"},
{0x1203, "icon0_02.png"},
{0x1204, "icon0_03.png"},
{0x1205, "icon0_04.png"},
{0x1206, "icon0_05.png"},
{0x1207, "icon0_06.png"},
{0x1208, "icon0_07.png"},
{0x1209, "icon0_08.png"},
{0x120A, "icon0_09.png"},
{0x120B, "icon0_10.png"},
{0x120C, "icon0_11.png"},
{0x120D, "icon0_12.png"},
{0x120E, "icon0_13.png"},
{0x120F, "icon0_14.png"},
{0x1210, "icon0_15.png"},
{0x1211, "icon0_16.png"},
{0x1212, "icon0_17.png"},
{0x1213, "icon0_18.png"},
{0x1214, "icon0_19.png"},
{0x1215, "icon0_20.png"},
{0x1216, "icon0_21.png"},
{0x1217, "icon0_22.png"},
{0x1218, "icon0_23.png"},
{0x1219, "icon0_24.png"},
{0x121A, "icon0_25.png"},
{0x121B, "icon0_26.png"},
{0x121C, "icon0_27.png"},
{0x121D, "icon0_28.png"},
{0x121E, "icon0_29.png"},
{0x121F, "icon0_30.png"},
{0x1220, "pic0.png"},
{0x1240, "snd0.at9"},
{0x1241, "pic1_00.png"},
{0x1242, "pic1_01.png"},
{0x1243, "pic1_02.png"},
{0x1244, "pic1_03.png"},
{0x1245, "pic1_04.png"},
{0x1246, "pic1_05.png"},
{0x1247, "pic1_06.png"},
{0x1248, "pic1_07.png"},
{0x1249, "pic1_08.png"},
{0x124A, "pic1_09.png"},
{0x124B, "pic1_10.png"},
{0x124C, "pic1_11.png"},
{0x124D, "pic1_12.png"},
{0x124E, "pic1_13.png"},
{0x124F, "pic1_14.png"},
{0x1250, "pic1_15.png"},
{0x1251, "pic1_16.png"},
{0x1252, "pic1_17.png"},
{0x1253, "pic1_18.png"},
{0x1254, "pic1_19.png"},
{0x1255, "pic1_20.png"},
{0x1256, "pic1_21.png"},
{0x1257, "pic1_22.png"},
{0x1258, "pic1_23.png"},
{0x1259, "pic1_24.png"},
{0x125A, "pic1_25.png"},
{0x125B, "pic1_26.png"},
{0x125C, "pic1_27.png"},
{0x125D, "pic1_28.png"},
{0x125E, "pic1_29.png"},
{0x125F, "pic1_30.png"},
{0x1260, "changeinfo/changeinfo.xml"},
{0x1261, "changeinfo/changeinfo_00.xml"},
{0x1262, "changeinfo/changeinfo_01.xml"},
{0x1263, "changeinfo/changeinfo_02.xml"},
{0x1264, "changeinfo/changeinfo_03.xml"},
{0x1265, "changeinfo/changeinfo_04.xml"},
{0x1266, "changeinfo/changeinfo_05.xml"},
{0x1267, "changeinfo/changeinfo_06.xml"},
{0x1268, "changeinfo/changeinfo_07.xml"},
{0x1269, "changeinfo/changeinfo_08.xml"},
{0x126A, "changeinfo/changeinfo_09.xml"},
{0x126B, "changeinfo/changeinfo_10.xml"},
{0x126C, "changeinfo/changeinfo_11.xml"},
{0x126D, "changeinfo/changeinfo_12.xml"},
{0x126E, "changeinfo/changeinfo_13.xml"},
{0x126F, "changeinfo/changeinfo_14.xml"},
{0x1270, "changeinfo/changeinfo_15.xml"},
{0x1271, "changeinfo/changeinfo_16.xml"},
{0x1272, "changeinfo/changeinfo_17.xml"},
{0x1273, "changeinfo/changeinfo_18.xml"},
{0x1274, "changeinfo/changeinfo_19.xml"},
{0x1275, "changeinfo/changeinfo_20.xml"},
{0x1276, "changeinfo/changeinfo_21.xml"},
{0x1277, "changeinfo/changeinfo_22.xml"},
{0x1278, "changeinfo/changeinfo_23.xml"},
{0x1279, "changeinfo/changeinfo_24.xml"},
{0x127A, "changeinfo/changeinfo_25.xml"},
{0x127B, "changeinfo/changeinfo_26.xml"},
{0x127C, "changeinfo/changeinfo_27.xml"},
{0x127D, "changeinfo/changeinfo_28.xml"},
{0x127E, "changeinfo/changeinfo_29.xml"},
{0x127F, "changeinfo/changeinfo_30.xml"},
{0x1280, "icon0.dds"},
{0x1281, "icon0_00.dds"},
{0x1282, "icon0_01.dds"},
{0x1283, "icon0_02.dds"},
{0x1284, "icon0_03.dds"},
{0x1285, "icon0_04.dds"},
{0x1286, "icon0_05.dds"},
{0x1287, "icon0_06.dds"},
{0x1288, "icon0_07.dds"},
{0x1289, "icon0_08.dds"},
{0x128A, "icon0_09.dds"},
{0x128B, "icon0_10.dds"},
{0x128C, "icon0_11.dds"},
{0x128D, "icon0_12.dds"},
{0x128E, "icon0_13.dds"},
{0x128F, "icon0_14.dds"},
{0x1290, "icon0_15.dds"},
{0x1291, "icon0_16.dds"},
{0x1292, "icon0_17.dds"},
{0x1293, "icon0_18.dds"},
{0x1294, "icon0_19.dds"},
{0x1295, "icon0_20.dds"},
{0x1296, "icon0_21.dds"},
{0x1297, "icon0_22.dds"},
{0x1298, "icon0_23.dds"},
{0x1299, "icon0_24.dds"},
{0x129A, "icon0_25.dds"},
{0x129B, "icon0_26.dds"},
{0x129C, "icon0_27.dds"},
{0x129D, "icon0_28.dds"},
{0x129E, "icon0_29.dds"},
{0x129F, "icon0_30.dds"},
{0x12A0, "pic0.dds"},
{0x12C0, "pic1.dds"},
{0x12C1, "pic1_00.dds"},
{0x12C2, "pic1_01.dds"},
{0x12C3, "pic1_02.dds"},
{0x12C4, "pic1_03.dds"},
{0x12C5, "pic1_04.dds"},
{0x12C6, "pic1_05.dds"},
{0x12C7, "pic1_06.dds"},
{0x12C8, "pic1_07.dds"},
{0x12C9, "pic1_08.dds"},
{0x12CA, "pic1_09.dds"},
{0x12CB, "pic1_10.dds"},
{0x12CC, "pic1_11.dds"},
{0x12CD, "pic1_12.dds"},
{0x12CE, "pic1_13.dds"},
{0x12CF, "pic1_14.dds"},
{0x12D0, "pic1_15.dds"},
{0x12D1, "pic1_16.dds"},
{0x12D2, "pic1_17.dds"},
{0x12D3, "pic1_18.dds"},
{0x12D4, "pic1_19.dds"},
{0x12D5, "pic1_20.dds"},
{0x12D6, "pic1_21.dds"},
{0x12D7, "pic1_22.dds"},
{0x12D8, "pic1_23.dds"},
{0x12D9, "pic1_24.dds"},
{0x12DA, "pic1_25.dds"},
{0x12DB, "pic1_26.dds"},
{0x12DC, "pic1_27.dds"},
{0x12DD, "pic1_28.dds"},
{0x12DE, "pic1_29.dds"},
{0x12DF, "pic1_30.dds"},
{0x1400, "trophy/trophy00.trp"},
{0x1401, "trophy/trophy01.trp"},
{0x1402, "trophy/trophy02.trp"},
{0x1403, "trophy/trophy03.trp"},
{0x1404, "trophy/trophy04.trp"},
{0x1405, "trophy/trophy05.trp"},
{0x1406, "trophy/trophy06.trp"},
{0x1407, "trophy/trophy07.trp"},
{0x1408, "trophy/trophy08.trp"},
{0x1409, "trophy/trophy09.trp"},
{0x140A, "trophy/trophy10.trp"},
{0x140B, "trophy/trophy11.trp"},
{0x140C, "trophy/trophy12.trp"},
{0x140D, "trophy/trophy13.trp"},
{0x140E, "trophy/trophy14.trp"},
{0x140F, "trophy/trophy15.trp"},
{0x1410, "trophy/trophy16.trp"},
{0x1411, "trophy/trophy17.trp"},
{0x1412, "trophy/trophy18.trp"},
{0x1413, "trophy/trophy19.trp"},
{0x1414, "trophy/trophy20.trp"},
{0x1415, "trophy/trophy21.trp"},
{0x1416, "trophy/trophy22.trp"},
{0x1417, "trophy/trophy23.trp"},
{0x1418, "trophy/trophy24.trp"},
{0x1419, "trophy/trophy25.trp"},
{0x141A, "trophy/trophy26.trp"},
{0x141B, "trophy/trophy27.trp"},
{0x141C, "trophy/trophy28.trp"},
{0x141D, "trophy/trophy29.trp"},
{0x141E, "trophy/trophy30.trp"},
{0x141F, "trophy/trophy31.trp"},
{0x1420, "trophy/trophy32.trp"},
{0x1421, "trophy/trophy33.trp"},
{0x1422, "trophy/trophy34.trp"},
{0x1423, "trophy/trophy35.trp"},
{0x1424, "trophy/trophy36.trp"},
{0x1425, "trophy/trophy37.trp"},
{0x1426, "trophy/trophy38.trp"},
{0x1427, "trophy/trophy39.trp"},
{0x1428, "trophy/trophy40.trp"},
{0x1429, "trophy/trophy41.trp"},
{0x142A, "trophy/trophy42.trp"},
{0x142B, "trophy/trophy43.trp"},
{0x142C, "trophy/trophy44.trp"},
{0x142D, "trophy/trophy45.trp"},
{0x142E, "trophy/trophy46.trp"},
{0x142F, "trophy/trophy47.trp"},
{0x1430, "trophy/trophy48.trp"},
{0x1431, "trophy/trophy49.trp"},
{0x1432, "trophy/trophy50.trp"},
{0x1433, "trophy/trophy51.trp"},
{0x1434, "trophy/trophy52.trp"},
{0x1435, "trophy/trophy53.trp"},
{0x1436, "trophy/trophy54.trp"},
{0x1437, "trophy/trophy55.trp"},
{0x1438, "trophy/trophy56.trp"},
{0x1439, "trophy/trophy57.trp"},
{0x143A, "trophy/trophy58.trp"},
{0x143B, "trophy/trophy59.trp"},
{0x143C, "trophy/trophy60.trp"},
{0x143D, "trophy/trophy61.trp"},
{0x143E, "trophy/trophy62.trp"},
{0x143F, "trophy/trophy63.trp"},
{0x1440, "trophy/trophy64.trp"},
{0x1441, "trophy/trophy65.trp"},
{0x1442, "trophy/trophy66.trp"},
{0x1443, "trophy/trophy67.trp"},
{0x1444, "trophy/trophy68.trp"},
{0x1445, "trophy/trophy69.trp"},
{0x1446, "trophy/trophy70.trp"},
{0x1447, "trophy/trophy71.trp"},
{0x1448, "trophy/trophy72.trp"},
{0x1449, "trophy/trophy73.trp"},
{0x144A, "trophy/trophy74.trp"},
{0x144B, "trophy/trophy75.trp"},
{0x144C, "trophy/trophy76.trp"},
{0x144D, "trophy/trophy77.trp"},
{0x144E, "trophy/trophy78.trp"},
{0x144F, "trophy/trophy79.trp"},
{0x1450, "trophy/trophy80.trp"},
{0x1451, "trophy/trophy81.trp"},
{0x1452, "trophy/trophy82.trp"},
{0x1453, "trophy/trophy83.trp"},
{0x1454, "trophy/trophy84.trp"},
{0x1455, "trophy/trophy85.trp"},
{0x1456, "trophy/trophy86.trp"},
{0x1457, "trophy/trophy87.trp"},
{0x1458, "trophy/trophy88.trp"},
{0x1459, "trophy/trophy89.trp"},
{0x145A, "trophy/trophy90.trp"},
{0x145B, "trophy/trophy91.trp"},
{0x145C, "trophy/trophy92.trp"},
{0x145D, "trophy/trophy93.trp"},
{0x145E, "trophy/trophy94.trp"},
{0x145F, "trophy/trophy95.trp"},
{0x1460, "trophy/trophy96.trp"},
{0x1461, "trophy/trophy97.trp"},
{0x1462, "trophy/trophy98.trp"},
{0x1463, "trophy/trophy99.trp"},
{0x1600, "keymap_rp/001.png"},
{0x1601, "keymap_rp/002.png"},
{0x1602, "keymap_rp/003.png"},
{0x1603, "keymap_rp/004.png"},
{0x1604, "keymap_rp/005.png"},
{0x1605, "keymap_rp/006.png"},
{0x1606, "keymap_rp/007.png"},
{0x1607, "keymap_rp/008.png"},
{0x1608, "keymap_rp/009.png"},
{0x1609, "keymap_rp/010.png"},
{0x1610, "keymap_rp/00/001.png"},
{0x1611, "keymap_rp/00/002.png"},
{0x1612, "keymap_rp/00/003.png"},
{0x1613, "keymap_rp/00/004.png"},
{0x1614, "keymap_rp/00/005.png"},
{0x1615, "keymap_rp/00/006.png"},
{0x1616, "keymap_rp/00/007.png"},
{0x1617, "keymap_rp/00/008.png"},
{0x1618, "keymap_rp/00/009.png"},
{0x1619, "keymap_rp/00/010.png"},
{0x1620, "keymap_rp/01/001.png"},
{0x1621, "keymap_rp/01/002.png"},
{0x1622, "keymap_rp/01/003.png"},
{0x1623, "keymap_rp/01/004.png"},
{0x1624, "keymap_rp/01/005.png"},
{0x1625, "keymap_rp/01/006.png"},
{0x1626, "keymap_rp/01/007.png"},
{0x1627, "keymap_rp/01/008.png"},
{0x1628, "keymap_rp/01/009.png"},
{0x1629, "keymap_rp/01/010.png"},
{0x1630, "keymap_rp/02/001.png"},
{0x1631, "keymap_rp/02/002.png"},
{0x1632, "keymap_rp/02/003.png"},
{0x1633, "keymap_rp/02/004.png"},
{0x1634, "keymap_rp/02/005.png"},
{0x1635, "keymap_rp/02/006.png"},
{0x1636, "keymap_rp/02/007.png"},
{0x1637, "keymap_rp/02/008.png"},
{0x1638, "keymap_rp/02/009.png"},
{0x1639, "keymap_rp/02/010.png"},
{0x1640, "keymap_rp/03/001.png"},
{0x1641, "keymap_rp/03/002.png"},
{0x1642, "keymap_rp/03/003.png"},
{0x1643, "keymap_rp/03/004.png"},
{0x1644, "keymap_rp/03/005.png"},
{0x1645, "keymap_rp/03/006.png"},
{0x1646, "keymap_rp/03/007.png"},
{0x1647, "keymap_rp/03/008.png"},
{0x1648, "keymap_rp/03/0010.png"},
{0x1650, "keymap_rp/04/001.png"},
{0x1651, "keymap_rp/04/002.png"},
{0x1652, "keymap_rp/04/003.png"},
{0x1653, "keymap_rp/04/004.png"},
{0x1654, "keymap_rp/04/005.png"},
{0x1655, "keymap_rp/04/006.png"},
{0x1656, "keymap_rp/04/007.png"},
{0x1657, "keymap_rp/04/008.png"},
{0x1658, "keymap_rp/04/009.png"},
{0x1659, "keymap_rp/04/010.png"},
{0x1660, "keymap_rp/05/001.png"},
{0x1661, "keymap_rp/05/002.png"},
{0x1662, "keymap_rp/05/003.png"},
{0x1663, "keymap_rp/05/004.png"},
{0x1664, "keymap_rp/05/005.png"},
{0x1665, "keymap_rp/05/006.png"},
{0x1666, "keymap_rp/05/007.png"},
{0x1667, "keymap_rp/05/008.png"},
{0x1668, "keymap_rp/05/009.png"},
{0x1669, "keymap_rp/05/010.png"},
{0x1670, "keymap_rp/06/001.png"},
{0x1671, "keymap_rp/06/002.png"},
{0x1672, "keymap_rp/06/003.png"},
{0x1673, "keymap_rp/06/004.png"},
{0x1674, "keymap_rp/06/005.png"},
{0x1675, "keymap_rp/06/006.png"},
{0x1676, "keymap_rp/06/007.png"},
{0x1677, "keymap_rp/06/008.png"},
{0x1678, "keymap_rp/06/009.png"},
{0x1679, "keymap_rp/06/010.png"},
{0x1680, "keymap_rp/07/001.png"},
{0x1681, "keymap_rp/07/002.png"},
{0x1682, "keymap_rp/07/003.png"},
{0x1683, "keymap_rp/07/004.png"},
{0x1684, "keymap_rp/07/005.png"},
{0x1685, "keymap_rp/07/006.png"},
{0x1686, "keymap_rp/07/007.png"},
{0x1687, "keymap_rp/07/008.png"},
{0x1688, "keymap_rp/07/009.png"},
{0x1689, "keymap_rp/07/010.png"},
{0x1690, "keymap_rp/08/001.png"},
{0x1691, "keymap_rp/08/002.png"},
{0x1692, "keymap_rp/08/003.png"},
{0x1693, "keymap_rp/08/004.png"},
{0x1694, "keymap_rp/08/005.png"},
{0x1695, "keymap_rp/08/006.png"},
{0x1696, "keymap_rp/08/007.png"},
{0x1697, "keymap_rp/08/008.png"},
{0x1698, "keymap_rp/08/009.png"},
{0x1699, "keymap_rp/08/010.png"},
{0x16A0, "keymap_rp/09/001.png"},
{0x16A1, "keymap_rp/09/002.png"},
{0x16A2, "keymap_rp/09/003.png"},
{0x16A3, "keymap_rp/09/004.png"},
{0x16A4, "keymap_rp/09/005.png"},
{0x16A5, "keymap_rp/09/006.png"},
{0x16A6, "keymap_rp/09/007.png"},
{0x16A7, "keymap_rp/09/008.png"},
{0x16A8, "keymap_rp/09/009.png"},
{0x16A9, "keymap_rp/09/010.png"},
{0x16B0, "keymap_rp/10/001.png"},
{0x16B1, "keymap_rp/10/002.png"},
{0x16B2, "keymap_rp/10/003.png"},
{0x16B3, "keymap_rp/10/004.png"},
{0x16B4, "keymap_rp/10/005.png"},
{0x16B5, "keymap_rp/10/006.png"},
{0x16B6, "keymap_rp/10/007.png"},
{0x16B7, "keymap_rp/10/008.png"},
{0x16B8, "keymap_rp/10/009.png"},
{0x16B9, "keymap_rp/10/010.png"},
{0x16C0, "keymap_rp/11/001.png"},
{0x16C1, "keymap_rp/11/002.png"},
{0x16C2, "keymap_rp/11/003.png"},
{0x16C3, "keymap_rp/11/004.png"},
{0x16C4, "keymap_rp/11/005.png"},
{0x16C5, "keymap_rp/11/006.png"},
{0x16C6, "keymap_rp/11/007.png"},
{0x16C7, "keymap_rp/11/008.png"},
{0x16C8, "keymap_rp/11/009.png"},
{0x16C9, "keymap_rp/11/010.png"},
{0x16D0, "keymap_rp/12/001.png"},
{0x16D1, "keymap_rp/12/002.png"},
{0x16D2, "keymap_rp/12/003.png"},
{0x16D3, "keymap_rp/12/004.png"},
{0x16D4, "keymap_rp/12/005.png"},
{0x16D5, "keymap_rp/12/006.png"},
{0x16D6, "keymap_rp/12/007.png"},
{0x16D7, "keymap_rp/12/008.png"},
{0x16D8, "keymap_rp/12/009.png"},
{0x16D9, "keymap_rp/12/010.png"},
{0x16E0, "keymap_rp/13/001.png"},
{0x16E1, "keymap_rp/13/002.png"},
{0x16E2, "keymap_rp/13/003.png"},
{0x16E3, "keymap_rp/13/004.png"},
{0x16E4, "keymap_rp/13/005.png"},
{0x16E5, "keymap_rp/13/006.png"},
{0x16E6, "keymap_rp/13/007.png"},
{0x16E7, "keymap_rp/13/008.png"},
{0x16E8, "keymap_rp/13/009.png"},
{0x16E9, "keymap_rp/13/010.png"},
{0x16F0, "keymap_rp/14/001.png"},
{0x16F1, "keymap_rp/14/002.png"},
{0x16F2, "keymap_rp/14/003.png"},
{0x16F3, "keymap_rp/14/004.png"},
{0x16F4, "keymap_rp/14/005.png"},
{0x16F5, "keymap_rp/14/006.png"},
{0x16F6, "keymap_rp/14/007.png"},
{0x16F7, "keymap_rp/14/008.png"},
{0x16F8, "keymap_rp/14/009.png"},
{0x16F9, "keymap_rp/14/010.png"},
{0x1700, "keymap_rp/15/001.png"},
{0x1701, "keymap_rp/15/002.png"},
{0x1702, "keymap_rp/15/003.png"},
{0x1703, "keymap_rp/15/004.png"},
{0x1704, "keymap_rp/15/005.png"},
{0x1705, "keymap_rp/15/006.png"},
{0x1706, "keymap_rp/15/007.png"},
{0x1707, "keymap_rp/15/008.png"},
{0x1708, "keymap_rp/15/009.png"},
{0x1709, "keymap_rp/15/010.png"},
{0x1710, "keymap_rp/16/001.png"},
{0x1711, "keymap_rp/16/002.png"},
{0x1712, "keymap_rp/16/003.png"},
{0x1713, "keymap_rp/16/004.png"},
{0x1714, "keymap_rp/16/005.png"},
{0x1715, "keymap_rp/16/006.png"},
{0x1716, "keymap_rp/16/007.png"},
{0x1717, "keymap_rp/16/008.png"},
{0x1718, "keymap_rp/16/009.png"},
{0x1719, "keymap_rp/16/010.png"},
{0x1720, "keymap_rp/17/001.png"},
{0x1721, "keymap_rp/17/002.png"},
{0x1722, "keymap_rp/17/003.png"},
{0x1723, "keymap_rp/17/004.png"},
{0x1724, "keymap_rp/17/005.png"},
{0x1725, "keymap_rp/17/006.png"},
{0x1726, "keymap_rp/17/007.png"},
{0x1727, "keymap_rp/17/008.png"},
{0x1728, "keymap_rp/17/009.png"},
{0x1729, "keymap_rp/17/010.png"},
{0x1730, "keymap_rp/18/001.png"},
{0x1731, "keymap_rp/18/002.png"},
{0x1732, "keymap_rp/18/003.png"},
{0x1733, "keymap_rp/18/004.png"},
{0x1734, "keymap_rp/18/005.png"},
{0x1735, "keymap_rp/18/006.png"},
{0x1736, "keymap_rp/18/007.png"},
{0x1737, "keymap_rp/18/008.png"},
{0x1738, "keymap_rp/18/009.png"},
{0x1739, "keymap_rp/18/010.png"},
{0x1740, "keymap_rp/19/001.png"},
{0x1741, "keymap_rp/19/002.png"},
{0x1742, "keymap_rp/19/003.png"},
{0x1743, "keymap_rp/19/004.png"},
{0x1744, "keymap_rp/19/005.png"},
{0x1745, "keymap_rp/19/006.png"},
{0x1746, "keymap_rp/19/007.png"},
{0x1747, "keymap_rp/19/008.png"},
{0x1748, "keymap_rp/19/009.png"},
{0x1749, "keymap_rp/19/010.png"},
{0x1750, "keymap_rp/20/001.png"},
{0x1751, "keymap_rp/20/002.png"},
{0x1752, "keymap_rp/20/003.png"},
{0x1753, "keymap_rp/20/004.png"},
{0x1754, "keymap_rp/20/005.png"},
{0x1755, "keymap_rp/20/006.png"},
{0x1756, "keymap_rp/20/007.png"},
{0x1757, "keymap_rp/20/008.png"},
{0x1758, "keymap_rp/20/009.png"},
{0x1759, "keymap_rp/20/010.png"},
{0x1760, "keymap_rp/21/001.png"},
{0x1761, "keymap_rp/21/002.png"},
{0x1762, "keymap_rp/21/003.png"},
{0x1763, "keymap_rp/21/004.png"},
{0x1764, "keymap_rp/21/005.png"},
{0x1765, "keymap_rp/21/006.png"},
{0x1766, "keymap_rp/21/007.png"},
{0x1767, "keymap_rp/21/008.png"},
{0x1768, "keymap_rp/21/009.png"},
{0x1769, "keymap_rp/21/010.png"},
{0x1770, "keymap_rp/22/001.png"},
{0x1771, "keymap_rp/22/002.png"},
{0x1772, "keymap_rp/22/003.png"},
{0x1773, "keymap_rp/22/004.png"},
{0x1774, "keymap_rp/22/005.png"},
{0x1775, "keymap_rp/22/006.png"},
{0x1776, "keymap_rp/22/007.png"},
{0x1777, "keymap_rp/22/008.png"},
{0x1778, "keymap_rp/22/009.png"},
{0x1779, "keymap_rp/22/010.png"},
{0x1780, "keymap_rp/23/001.png"},
{0x1781, "keymap_rp/23/002.png"},
{0x1782, "keymap_rp/23/003.png"},
{0x1783, "keymap_rp/23/004.png"},
{0x1784, "keymap_rp/23/005.png"},
{0x1785, "keymap_rp/23/006.png"},
{0x1786, "keymap_rp/23/007.png"},
{0x1787, "keymap_rp/23/008.png"},
{0x1788, "keymap_rp/23/009.png"},
{0x1789, "keymap_rp/23/010.png"},
{0x1790, "keymap_rp/24/001.png"},
{0x1791, "keymap_rp/24/002.png"},
{0x1792, "keymap_rp/24/003.png"},
{0x1793, "keymap_rp/24/004.png"},
{0x1794, "keymap_rp/24/005.png"},
{0x1795, "keymap_rp/24/006.png"},
{0x1796, "keymap_rp/24/007.png"},
{0x1797, "keymap_rp/24/008.png"},
{0x1798, "keymap_rp/24/009.png"},
{0x1799, "keymap_rp/24/010.png"},
{0x17A0, "keymap_rp/25/001.png"},
{0x17A1, "keymap_rp/25/002.png"},
{0x17A2, "keymap_rp/25/003.png"},
{0x17A3, "keymap_rp/25/004.png"},
{0x17A4, "keymap_rp/25/005.png"},
{0x17A5, "keymap_rp/25/006.png"},
{0x17A6, "keymap_rp/25/007.png"},
{0x17A7, "keymap_rp/25/008.png"},
{0x17A8, "keymap_rp/25/009.png"},
{0x17A9, "keymap_rp/25/010.png"},
{0x17B0, "keymap_rp/26/001.png"},
{0x17B1, "keymap_rp/26/002.png"},
{0x17B2, "keymap_rp/26/003.png"},
{0x17B3, "keymap_rp/26/004.png"},
{0x17B4, "keymap_rp/26/005.png"},
{0x17B5, "keymap_rp/26/006.png"},
{0x17B6, "keymap_rp/26/007.png"},
{0x17B7, "keymap_rp/26/008.png"},
{0x17B8, "keymap_rp/26/009.png"},
{0x17B9, "keymap_rp/26/010.png"},
{0x17C0, "keymap_rp/27/001.png"},
{0x17C1, "keymap_rp/27/002.png"},
{0x17C2, "keymap_rp/27/003.png"},
{0x17C3, "keymap_rp/27/004.png"},
{0x17C4, "keymap_rp/27/005.png"},
{0x17C5, "keymap_rp/27/006.png"},
{0x17C6, "keymap_rp/27/007.png"},
{0x17C7, "keymap_rp/27/008.png"},
{0x17C8, "keymap_rp/27/009.png"},
{0x17C9, "keymap_rp/27/010.png"},
{0x17D0, "keymap_rp/28/001.png"},
{0x17D1, "keymap_rp/28/002.png"},
{0x17D2, "keymap_rp/28/003.png"},
{0x17D3, "keymap_rp/28/004.png"},
{0x17D4, "keymap_rp/28/005.png"},
{0x17D5, "keymap_rp/28/006.png"},
{0x17D6, "keymap_rp/28/007.png"},
{0x17D7, "keymap_rp/28/008.png"},
{0x17D8, "keymap_rp/28/009.png"},
{0x17D9, "keymap_rp/28/010.png"},
{0x17E0, "keymap_rp/29/001.png"},
{0x17E1, "keymap_rp/29/002.png"},
{0x17E2, "keymap_rp/29/003.png"},
{0x17E3, "keymap_rp/29/004.png"},
{0x17E4, "keymap_rp/29/005.png"},
{0x17E5, "keymap_rp/29/006.png"},
{0x17E6, "keymap_rp/29/007.png"},
{0x17E7, "keymap_rp/29/008.png"},
{0x17E8, "keymap_rp/29/009.png"},
{0x17E9, "keymap_rp/29/010.png"},
{0x17F0, "keymap_rp/30/001.png"},
{0x17F1, "keymap_rp/30/002.png"},
{0x17F2, "keymap_rp/30/003.png"},
{0x17F3, "keymap_rp/30/004.png"},
{0x17F4, "keymap_rp/30/005.png"},
{0x17F5, "keymap_rp/30/006.png"},
{0x17F6, "keymap_rp/30/007.png"},
{0x17F7, "keymap_rp/30/008.png"},
{0x17F8, "keymap_rp/30/009.png"},
{0x17F9, "keymap_rp/30/010.png"},
}};
std::string_view GetEntryNameByType(u32 type) {
const auto key = PkgEntryValue{type};
const auto it = std::ranges::lower_bound(PkgEntries, key);
if (it != PkgEntries.end() && it->type == type) {
return it->name;
}
return "";
}

View File

@ -1,10 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <string_view>
#include "common/types.h"
/// Retrieves the PKG entry name from its type identifier.
std::string_view GetEntryNameByType(u32 type);

View File

@ -1,38 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <fstream>
#include "common/assert.h"
#include "common/io_file.h"
#include "common/stb.h"
#include "splash.h"
bool Splash::Open(const std::filesystem::path& filepath) {
ASSERT_MSG(filepath.extension().string() == ".png", "Unexpected file format passed");
Common::FS::IOFile file(filepath, Common::FS::FileAccessMode::Read);
if (!file.IsOpen()) {
return false;
}
std::vector<u8> png_file{};
const auto png_size = file.GetSize();
png_file.resize(png_size);
file.Seek(0);
file.Read(png_file);
auto* img_mem = stbi_load_from_memory(png_file.data(), png_file.size(),
reinterpret_cast<int*>(&img_info.width),
reinterpret_cast<int*>(&img_info.height),
reinterpret_cast<int*>(&img_info.num_channels), 4);
if (!img_mem) {
return false;
}
const auto img_size = img_info.GetSizeBytes();
img_data.resize(img_size);
std::memcpy(img_data.data(), img_mem, img_size);
stbi_image_free(img_mem);
return true;
}

View File

@ -1,42 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <filesystem>
#include <string>
#include <vector>
#include "common/types.h"
class Splash {
public:
struct ImageInfo {
u32 width;
u32 height;
u32 num_channels;
u32 GetSizeBytes() const {
return width * height * 4; // we always forcing rgba8 for simplicity
}
};
Splash() = default;
~Splash() = default;
bool Open(const std::filesystem::path& filepath);
[[nodiscard]] bool IsLoaded() const {
return img_data.size();
}
const auto& GetImageData() const {
return img_data;
}
ImageInfo GetImageInfo() const {
return img_info;
}
private:
ImageInfo img_info{};
std::vector<u8> img_data{};
};

View File

@ -1,10 +1,25 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/aes.h"
#include "common/config.h"
#include "common/logging/log.h"
#include "common/path_util.h"
#include "trp.h"
#include "core/file_format/trp.h"
static void DecryptEFSM(std::span<u8, 16> trophyKey, std::span<u8, 16> NPcommID,
std::span<u8, 16> efsmIv, std::span<u8> ciphertext,
std::span<u8> decrypted) {
// Step 1: Encrypt NPcommID
std::array<u8, 16> trophyIv{};
std::array<u8, 16> trpKey;
aes::encrypt_cbc(NPcommID.data(), NPcommID.size(), trophyKey.data(), trophyKey.size(),
trophyIv.data(), trpKey.data(), trpKey.size(), false);
// Step 2: Decrypt EFSM
aes::decrypt_cbc(ciphertext.data(), ciphertext.size(), trpKey.data(), trpKey.size(),
efsmIv.data(), decrypted.data(), decrypted.size(), nullptr);
}
TRP::TRP() = default;
TRP::~TRP() = default;
@ -54,7 +69,7 @@ bool TRP::Extract(const std::filesystem::path& trophyPath, const std::string tit
return false;
}
std::array<CryptoPP::byte, 16> user_key{};
std::array<u8, 16> user_key{};
hexToBytes(user_key_str.c_str(), user_key.data());
for (int index = 0; const auto& it : std::filesystem::directory_iterator(gameSysDir)) {
@ -115,7 +130,7 @@ bool TRP::Extract(const std::filesystem::path& trophyPath, const std::string tit
return false;
}
file.Read(ESFM);
crypto.decryptEFSM(user_key, np_comm_id, esfmIv, ESFM, XML); // decrypt
DecryptEFSM(user_key, np_comm_id, esfmIv, ESFM, XML); // decrypt
removePadding(XML);
std::string xml_name = entry.entry_name;
size_t pos = xml_name.find("ESFM");

View File

@ -7,7 +7,6 @@
#include "common/endian.h"
#include "common/io_file.h"
#include "common/types.h"
#include "core/crypto/crypto.h"
struct TrpHeader {
u32_be magic; // (0xDCA24D00)
@ -37,10 +36,9 @@ public:
void GetNPcommID(const std::filesystem::path& trophyPath, int index);
private:
Crypto crypto;
std::vector<u8> NPcommID = std::vector<u8>(12);
std::array<u8, 16> np_comm_id{};
std::array<u8, 16> esfmIv{};
std::filesystem::path trpFilesPath;
static constexpr int iv_len = 16;
};
};

View File

@ -70,6 +70,10 @@ std::filesystem::path MntPoints::GetHostPath(std::string_view path, bool* is_rea
std::filesystem::path host_path = mount->host_path / rel_path;
std::filesystem::path patch_path = mount->host_path;
patch_path += "-UPDATE";
if (!std::filesystem::exists(patch_path)) {
patch_path = mount->host_path;
patch_path += "-patch";
}
patch_path /= rel_path;
if ((corrected_path.starts_with("/app0") || corrected_path.starts_with("/hostapp")) &&

View File

@ -191,6 +191,7 @@ int PS4_SYSV_ABI sceAudioOutGetPortState(s32 handle, OrbisAudioOutPortState* sta
case OrbisAudioOutPort::Main:
case OrbisAudioOutPort::Bgm:
case OrbisAudioOutPort::Voice:
case OrbisAudioOutPort::Audio3d:
state->output = 1;
state->channel = port.format_info.num_channels > 2 ? 2 : port.format_info.num_channels;
break;
@ -316,7 +317,7 @@ s32 PS4_SYSV_ABI sceAudioOutOpen(UserService::OrbisUserServiceUserId user_id,
return ORBIS_AUDIO_OUT_ERROR_NOT_INIT;
}
if ((port_type < OrbisAudioOutPort::Main || port_type > OrbisAudioOutPort::Padspk) &&
(port_type != OrbisAudioOutPort::Aux)) {
(port_type != OrbisAudioOutPort::Audio3d && port_type != OrbisAudioOutPort::Aux)) {
LOG_ERROR(Lib_AudioOut, "Invalid port type");
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT_TYPE;
}

View File

@ -20,7 +20,15 @@ class PortBackend;
constexpr s32 SCE_AUDIO_OUT_NUM_PORTS = 22;
constexpr s32 SCE_AUDIO_OUT_VOLUME_0DB = 32768; // max volume value
enum class OrbisAudioOutPort { Main = 0, Bgm = 1, Voice = 2, Personal = 3, Padspk = 4, Aux = 127 };
enum class OrbisAudioOutPort {
Main = 0,
Bgm = 1,
Voice = 2,
Personal = 3,
Padspk = 4,
Audio3d = 126,
Aux = 127,
};
enum class OrbisAudioOutParamFormat : u32 {
S16Mono = 0,

View File

@ -1,8 +1,13 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <SDL3/SDL_audio.h>
#include <magic_enum/magic_enum.hpp>
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/libraries/audio/audioout.h"
#include "core/libraries/audio/audioout_error.h"
#include "core/libraries/audio3d/audio3d.h"
#include "core/libraries/audio3d/audio3d_error.h"
#include "core/libraries/error_codes.h"
@ -10,331 +15,577 @@
namespace Libraries::Audio3d {
int PS4_SYSV_ABI sceAudio3dInitialize(s64 iReserved) {
LOG_INFO(Lib_Audio3d, "iReserved = {}", iReserved);
return ORBIS_OK;
static constexpr u32 AUDIO3D_SAMPLE_RATE = 48000;
static constexpr AudioOut::OrbisAudioOutParamFormat AUDIO3D_OUTPUT_FORMAT =
AudioOut::OrbisAudioOutParamFormat::S16Stereo;
static constexpr u32 AUDIO3D_OUTPUT_NUM_CHANNELS = 2;
static constexpr u32 AUDIO3D_OUTPUT_BUFFER_FRAMES = 0x100;
static std::unique_ptr<Audio3dState> state;
s32 PS4_SYSV_ABI sceAudio3dAudioOutClose(const s32 handle) {
LOG_INFO(Lib_Audio3d, "called, handle = {}", handle);
return AudioOut::sceAudioOutClose(handle);
}
int PS4_SYSV_ABI sceAudio3dTerminate() {
// TODO: When not initialized or some ports still open, return ORBIS_AUDIO3D_ERROR_NOT_READY
LOG_INFO(Lib_Audio3d, "called");
return ORBIS_OK;
}
void PS4_SYSV_ABI sceAudio3dGetDefaultOpenParameters(OrbisAudio3dOpenParameters* parameters) {
if (parameters == nullptr) {
LOG_ERROR(Lib_Audio3d, "Invalid OpenParameters ptr");
return;
}
parameters->size_this = sizeof(OrbisAudio3dOpenParameters);
parameters->granularity = 256;
parameters->rate = OrbisAudio3dRate::Rate48000;
parameters->max_objects = 512;
parameters->queue_depth = 2;
parameters->buffer_mode = OrbisAudio3dBufferMode::AdvanceAndPush;
parameters->num_beds = 2;
}
int PS4_SYSV_ABI sceAudio3dPortOpen(OrbisUserServiceUserId iUserId,
const OrbisAudio3dOpenParameters* pParameters,
OrbisAudio3dPortId* pId) {
LOG_INFO(Lib_Audio3d, "iUserId = {}", iUserId);
return ORBIS_OK;
}
int PS4_SYSV_ABI sceAudio3dPortClose(OrbisAudio3dPortId uiPortId) {
LOG_INFO(Lib_Audio3d, "uiPortId = {}", uiPortId);
return ORBIS_OK;
}
int PS4_SYSV_ABI sceAudio3dPortSetAttribute(OrbisAudio3dPortId uiPortId,
OrbisAudio3dAttributeId uiAttributeId,
const void* pAttribute, size_t szAttribute) {
LOG_INFO(Lib_Audio3d, "uiPortId = {}, uiAttributeId = {}, szAttribute = {}", uiPortId,
uiAttributeId, szAttribute);
return ORBIS_OK;
}
int PS4_SYSV_ABI sceAudio3dPortFlush(OrbisAudio3dPortId uiPortId) {
LOG_INFO(Lib_Audio3d, "uiPortId = {}", uiPortId);
return ORBIS_OK;
}
int PS4_SYSV_ABI sceAudio3dPortAdvance(OrbisAudio3dPortId uiPortId) {
LOG_TRACE(Lib_Audio3d, "uiPortId = {}", uiPortId);
return ORBIS_OK;
}
int PS4_SYSV_ABI sceAudio3dPortPush(OrbisAudio3dPortId uiPortId, OrbisAudio3dBlocking eBlocking) {
LOG_TRACE(Lib_Audio3d, "uiPortId = {}", uiPortId);
return ORBIS_OK;
}
int PS4_SYSV_ABI sceAudio3dPortGetAttributesSupported(OrbisAudio3dPortId uiPortId,
OrbisAudio3dAttributeId* pCapabilities,
u32* pNumCapabilities) {
LOG_INFO(Lib_Audio3d, "uiPortId = {}", uiPortId);
return ORBIS_OK;
}
int PS4_SYSV_ABI sceAudio3dPortGetQueueLevel(OrbisAudio3dPortId uiPortId, u32* pQueueLevel,
u32* pQueueAvailable) {
LOG_TRACE(Lib_Audio3d, "uiPortId = {}", uiPortId);
return ORBIS_OK;
}
int PS4_SYSV_ABI sceAudio3dObjectReserve(OrbisAudio3dPortId uiPortId, OrbisAudio3dObjectId* pId) {
LOG_INFO(Lib_Audio3d, "uiPortId = {}", uiPortId);
return ORBIS_OK;
}
int PS4_SYSV_ABI sceAudio3dObjectUnreserve(OrbisAudio3dPortId uiPortId,
OrbisAudio3dObjectId uiObjectId) {
LOG_INFO(Lib_Audio3d, "uiPortId = {}, uiObjectId = {}", uiPortId, uiObjectId);
return ORBIS_OK;
}
int PS4_SYSV_ABI sceAudio3dObjectSetAttributes(OrbisAudio3dPortId uiPortId,
OrbisAudio3dObjectId uiObjectId,
size_t szNumAttributes,
const OrbisAudio3dAttribute* pAttributeArray) {
LOG_INFO(Lib_Audio3d, "uiPortId = {}, uiObjectId = {}, szNumAttributes = {}", uiPortId,
uiObjectId, szNumAttributes);
return ORBIS_OK;
}
int PS4_SYSV_ABI sceAudio3dBedWrite(OrbisAudio3dPortId uiPortId, u32 uiNumChannels,
OrbisAudio3dFormat eFormat, const void* pBuffer,
u32 uiNumSamples) {
LOG_TRACE(Lib_Audio3d, "uiPortId = {}, uiNumChannels = {}, uiNumSamples = {}", uiPortId,
uiNumChannels, uiNumSamples);
return ORBIS_OK;
}
int PS4_SYSV_ABI sceAudio3dBedWrite2(OrbisAudio3dPortId uiPortId, u32 uiNumChannels,
OrbisAudio3dFormat eFormat, const void* pBuffer,
u32 uiNumSamples, OrbisAudio3dOutputRoute eOutputRoute,
bool bRestricted) {
LOG_INFO(Lib_Audio3d, "uiPortId = {}, uiNumChannels = {}, uiNumSamples = {}, bRestricted = {}",
uiPortId, uiNumChannels, uiNumSamples, bRestricted);
return ORBIS_OK;
}
size_t PS4_SYSV_ABI sceAudio3dGetSpeakerArrayMemorySize(u32 uiNumSpeakers, bool bIs3d) {
LOG_INFO(Lib_Audio3d, "uiNumSpeakers = {}, bIs3d = {}", uiNumSpeakers, bIs3d);
return ORBIS_OK;
}
int PS4_SYSV_ABI
sceAudio3dCreateSpeakerArray(OrbisAudio3dSpeakerArrayHandle* pHandle,
const OrbisAudio3dSpeakerArrayParameters* pParameters) {
if (pHandle == nullptr || pParameters == nullptr) {
LOG_ERROR(Lib_Audio3d, "invalid SpeakerArray parameters");
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
}
LOG_INFO(Lib_Audio3d, "called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceAudio3dDeleteSpeakerArray(OrbisAudio3dSpeakerArrayHandle handle) {
if (handle == nullptr) {
LOG_ERROR(Lib_Audio3d, "invalid SpeakerArrayHandle");
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
}
LOG_INFO(Lib_Audio3d, "called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceAudio3dGetSpeakerArrayMixCoefficients(OrbisAudio3dSpeakerArrayHandle handle,
OrbisAudio3dPosition pos, float fSpread,
float* pCoefficients,
u32 uiNumCoefficients) {
LOG_INFO(Lib_Audio3d, "fSpread = {}, uiNumCoefficients = {}", fSpread, uiNumCoefficients);
if (handle == nullptr) {
LOG_ERROR(Lib_Audio3d, "invalid SpeakerArrayHandle");
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
}
return ORBIS_OK;
}
int PS4_SYSV_ABI sceAudio3dGetSpeakerArrayMixCoefficients2(OrbisAudio3dSpeakerArrayHandle handle,
OrbisAudio3dPosition pos, float fSpread,
float* pCoefficients,
u32 uiNumCoefficients, bool bHeightAware,
float fDownmixSpreadRadius) {
s32 PS4_SYSV_ABI
sceAudio3dAudioOutOpen(const OrbisAudio3dPortId port_id, const OrbisUserServiceUserId user_id,
s32 type, const s32 index, const u32 len, const u32 freq,
const AudioOut::OrbisAudioOutParamExtendedInformation param) {
LOG_INFO(Lib_Audio3d,
"fSpread = {}, uiNumCoefficients = {}, bHeightAware = {}, fDownmixSpreadRadius = {}",
fSpread, uiNumCoefficients, bHeightAware, fDownmixSpreadRadius);
if (handle == nullptr) {
LOG_ERROR(Lib_Audio3d, "invalid SpeakerArrayHandle");
"called, port_id = {}, user_id = {}, type = {}, index = {}, len = {}, freq = {}",
port_id, user_id, type, index, len, freq);
if (!state->ports.contains(port_id)) {
LOG_ERROR(Lib_Audio3d, "!state->ports.contains(port_id)");
return ORBIS_AUDIO3D_ERROR_INVALID_PORT;
}
if (len != state->ports[port_id].parameters.granularity) {
LOG_ERROR(Lib_Audio3d, "len != state->ports[port_id].parameters.granularity");
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
}
return sceAudioOutOpen(user_id, static_cast<AudioOut::OrbisAudioOutPort>(type), index, len,
freq, param);
}
s32 PS4_SYSV_ABI sceAudio3dAudioOutOutput(const s32 handle, void* ptr) {
LOG_DEBUG(Lib_Audio3d, "called, handle = {}, ptr = {}", handle, ptr);
if (!ptr) {
LOG_ERROR(Lib_Audio3d, "!ptr");
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
}
if (handle < 0 || (handle & 0xFFFF) > 25) {
LOG_ERROR(Lib_Audio3d, "handle < 0 || (handle & 0xFFFF) > 25");
return ORBIS_AUDIO3D_ERROR_INVALID_PORT;
}
return AudioOut::sceAudioOutOutput(handle, ptr);
}
s32 PS4_SYSV_ABI sceAudio3dAudioOutOutputs(AudioOut::OrbisAudioOutOutputParam* param,
const u32 num) {
LOG_DEBUG(Lib_Audio3d, "called, param = {}, num = {}", static_cast<void*>(param), num);
if (!param || !num) {
LOG_ERROR(Lib_Audio3d, "!param || !num");
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
}
return AudioOut::sceAudioOutOutputs(param, num);
}
static s32 PortQueueAudio(Port& port, const OrbisAudio3dPcm& pcm, const u32 num_channels) {
// Audio3d output is configured for stereo signed 16-bit PCM. Convert the data to match.
const SDL_AudioSpec src_spec = {
.format = pcm.format == OrbisAudio3dFormat::ORBIS_AUDIO3D_FORMAT_S16 ? SDL_AUDIO_S16LE
: SDL_AUDIO_F32LE,
.channels = static_cast<int>(num_channels),
.freq = AUDIO3D_SAMPLE_RATE,
};
constexpr SDL_AudioSpec dst_spec = {
.format = SDL_AUDIO_S16LE,
.channels = AUDIO3D_OUTPUT_NUM_CHANNELS,
.freq = AUDIO3D_SAMPLE_RATE,
};
const auto src_size = pcm.num_samples *
(pcm.format == OrbisAudio3dFormat::ORBIS_AUDIO3D_FORMAT_S16 ? 2 : 4) *
num_channels;
u8* dst_data;
int dst_len;
if (!SDL_ConvertAudioSamples(&src_spec, static_cast<u8*>(pcm.sample_buffer),
static_cast<int>(src_size), &dst_spec, &dst_data, &dst_len)) {
LOG_ERROR(Lib_Audio3d, "SDL_ConvertAudioSamples failed: {}", SDL_GetError());
return ORBIS_AUDIO3D_ERROR_OUT_OF_MEMORY;
}
port.queue.emplace_back(AudioData{
.sample_buffer = dst_data,
.num_samples = pcm.num_samples,
});
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceAudio3dBedWrite(const OrbisAudio3dPortId port_id, const u32 num_channels,
const OrbisAudio3dFormat format, void* buffer,
const u32 num_samples) {
return sceAudio3dBedWrite2(port_id, num_channels, format, buffer, num_samples,
OrbisAudio3dOutputRoute::ORBIS_AUDIO3D_OUTPUT_BOTH, false);
}
s32 PS4_SYSV_ABI sceAudio3dBedWrite2(const OrbisAudio3dPortId port_id, const u32 num_channels,
const OrbisAudio3dFormat format, void* buffer,
const u32 num_samples,
const OrbisAudio3dOutputRoute output_route,
const bool restricted) {
LOG_DEBUG(
Lib_Audio3d,
"called, port_id = {}, num_channels = {}, format = {}, num_samples = {}, output_route "
"= {}, restricted = {}",
port_id, num_channels, magic_enum::enum_name(format), num_samples,
magic_enum::enum_name(output_route), restricted);
if (!state->ports.contains(port_id)) {
LOG_ERROR(Lib_Audio3d, "!state->ports.contains(port_id)");
return ORBIS_AUDIO3D_ERROR_INVALID_PORT;
}
if (output_route > OrbisAudio3dOutputRoute::ORBIS_AUDIO3D_OUTPUT_BOTH) {
LOG_ERROR(Lib_Audio3d, "output_route > ORBIS_AUDIO3D_OUTPUT_BOTH");
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
}
if (format > OrbisAudio3dFormat::ORBIS_AUDIO3D_FORMAT_FLOAT) {
LOG_ERROR(Lib_Audio3d, "format > ORBIS_AUDIO3D_FORMAT_FLOAT");
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
}
if (num_channels != 2 && num_channels != 8) {
LOG_ERROR(Lib_Audio3d, "num_channels != 2 && num_channels != 8");
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
}
if (!buffer || !num_samples) {
LOG_ERROR(Lib_Audio3d, "!buffer || !num_samples");
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
}
if (format == OrbisAudio3dFormat::ORBIS_AUDIO3D_FORMAT_FLOAT) {
if ((reinterpret_cast<uintptr_t>(buffer) & 3) != 0) {
LOG_ERROR(Lib_Audio3d, "buffer & 3 != 0");
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
}
} else if (format == OrbisAudio3dFormat::ORBIS_AUDIO3D_FORMAT_S16) {
if ((reinterpret_cast<uintptr_t>(buffer) & 1) != 0) {
LOG_ERROR(Lib_Audio3d, "buffer & 1 != 0");
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
}
}
return PortQueueAudio(state->ports[port_id],
OrbisAudio3dPcm{
.format = format,
.sample_buffer = buffer,
.num_samples = num_samples,
},
num_channels);
}
s32 PS4_SYSV_ABI sceAudio3dCreateSpeakerArray() {
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceAudio3dDeleteSpeakerArray() {
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceAudio3dGetDefaultOpenParameters(OrbisAudio3dOpenParameters* params) {
LOG_DEBUG(Lib_Audio3d, "called");
if (params) {
*params = OrbisAudio3dOpenParameters{
.size_this = 0x20,
.granularity = 0x100,
.rate = OrbisAudio3dRate::ORBIS_AUDIO3D_RATE_48000,
.max_objects = 512,
.queue_depth = 2,
.buffer_mode = OrbisAudio3dBufferMode::ORBIS_AUDIO3D_BUFFER_ADVANCE_AND_PUSH,
};
}
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceAudio3dAudioOutOpen(OrbisAudio3dPortId uiPortId, OrbisUserServiceUserId userId,
s32 type, s32 index, u32 len, u32 freq, u32 param) {
s32 PS4_SYSV_ABI sceAudio3dGetSpeakerArrayMemorySize() {
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceAudio3dGetSpeakerArrayMixCoefficients() {
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceAudio3dGetSpeakerArrayMixCoefficients2() {
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceAudio3dInitialize(const s64 reserved) {
LOG_INFO(Lib_Audio3d, "called, reserved = {}", reserved);
if (reserved != 0) {
LOG_ERROR(Lib_Audio3d, "reserved != 0");
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
}
if (state) {
LOG_ERROR(Lib_Audio3d, "already initialized");
return ORBIS_AUDIO3D_ERROR_NOT_READY;
}
state = std::make_unique<Audio3dState>();
if (const auto init_ret = AudioOut::sceAudioOutInit();
init_ret < 0 && init_ret != ORBIS_AUDIO_OUT_ERROR_ALREADY_INIT) {
return init_ret;
}
AudioOut::OrbisAudioOutParamExtendedInformation ext_info{};
ext_info.data_format.Assign(AUDIO3D_OUTPUT_FORMAT);
state->audio_out_handle =
AudioOut::sceAudioOutOpen(0xFF, AudioOut::OrbisAudioOutPort::Audio3d, 0,
AUDIO3D_OUTPUT_BUFFER_FRAMES, AUDIO3D_SAMPLE_RATE, ext_info);
if (state->audio_out_handle < 0) {
return state->audio_out_handle;
}
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceAudio3dObjectReserve(const OrbisAudio3dPortId port_id,
OrbisAudio3dObjectId* object_id) {
LOG_INFO(Lib_Audio3d, "called, port_id = {}, object_id = {}", port_id,
static_cast<void*>(object_id));
if (!state->ports.contains(port_id)) {
LOG_ERROR(Lib_Audio3d, "!state->ports.contains(port_id)");
return ORBIS_AUDIO3D_ERROR_INVALID_PORT;
}
if (!object_id) {
LOG_ERROR(Lib_Audio3d, "!object_id");
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
}
static int last_id = 0;
*object_id = ++last_id;
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceAudio3dObjectSetAttributes(const OrbisAudio3dPortId port_id,
OrbisAudio3dObjectId object_id,
const u64 num_attributes,
const OrbisAudio3dAttribute* attribute_array) {
LOG_DEBUG(Lib_Audio3d,
"called, port_id = {}, object_id = {}, num_attributes = {}, attribute_array = {}",
port_id, object_id, num_attributes, fmt::ptr(attribute_array));
if (!state->ports.contains(port_id)) {
LOG_ERROR(Lib_Audio3d, "!state->ports.contains(port_id)");
return ORBIS_AUDIO3D_ERROR_INVALID_PORT;
}
auto& port = state->ports[port_id];
for (u64 i = 0; i < num_attributes; i++) {
const auto& attribute = attribute_array[i];
switch (attribute.attribute_id) {
case OrbisAudio3dAttributeId::ORBIS_AUDIO3D_ATTRIBUTE_PCM: {
const auto pcm = static_cast<OrbisAudio3dPcm*>(attribute.value);
// Object audio has 1 channel.
if (const auto ret = PortQueueAudio(port, *pcm, 1); ret != ORBIS_OK) {
return ret;
}
break;
}
default:
LOG_ERROR(Lib_Audio3d, "Unsupported attribute ID: {:#x}",
static_cast<u32>(attribute.attribute_id));
break;
}
}
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceAudio3dObjectUnreserve() {
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceAudio3dPortAdvance(const OrbisAudio3dPortId port_id) {
LOG_DEBUG(Lib_Audio3d, "called, port_id = {}", port_id);
if (!state->ports.contains(port_id)) {
LOG_ERROR(Lib_Audio3d, "!state->ports.contains(port_id)");
return ORBIS_AUDIO3D_ERROR_INVALID_PORT;
}
if (state->ports[port_id].parameters.buffer_mode ==
OrbisAudio3dBufferMode::ORBIS_AUDIO3D_BUFFER_NO_ADVANCE) {
LOG_ERROR(Lib_Audio3d, "port doesn't have advance capability");
return ORBIS_AUDIO3D_ERROR_NOT_SUPPORTED;
}
auto& port = state->ports[port_id];
if (port.current_buffer.has_value()) {
// Free existing buffer before replacing.
SDL_free(port.current_buffer->sample_buffer);
}
if (!port.queue.empty()) {
port.current_buffer = port.queue.front();
port.queue.pop_front();
} else {
// Nothing to advance to.
LOG_DEBUG(Lib_Audio3d, "Port advance with no buffer queued");
port.current_buffer = std::nullopt;
}
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceAudio3dPortClose() {
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceAudio3dPortCreate() {
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceAudio3dPortDestroy() {
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceAudio3dPortFlush() {
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceAudio3dPortFreeState() {
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceAudio3dPortGetAttributesSupported() {
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceAudio3dPortGetList() {
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceAudio3dPortGetParameters() {
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceAudio3dPortGetQueueLevel(const OrbisAudio3dPortId port_id, u32* queue_level,
u32* queue_available) {
LOG_DEBUG(Lib_Audio3d, "called, port_id = {}, queue_level = {}, queue_available = {}", port_id,
static_cast<void*>(queue_level), static_cast<void*>(queue_available));
if (!state->ports.contains(port_id)) {
LOG_ERROR(Lib_Audio3d, "!state->ports.contains(port_id)");
return ORBIS_AUDIO3D_ERROR_INVALID_PORT;
}
if (!queue_level && !queue_available) {
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
}
const auto port = state->ports[port_id];
const size_t size = port.queue.size();
if (queue_level) {
*queue_level = size;
}
if (queue_available) {
*queue_available = port.parameters.queue_depth - size;
}
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceAudio3dPortGetState() {
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceAudio3dPortGetStatus() {
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceAudio3dPortOpen(const OrbisUserServiceUserId user_id,
const OrbisAudio3dOpenParameters* parameters,
OrbisAudio3dPortId* port_id) {
LOG_INFO(Lib_Audio3d, "called, user_id = {}, parameters = {}, id = {}", user_id,
static_cast<const void*>(parameters), static_cast<void*>(port_id));
if (!state) {
LOG_ERROR(Lib_Audio3d, "!initialized");
return ORBIS_AUDIO3D_ERROR_NOT_READY;
}
if (!parameters || !port_id) {
LOG_ERROR(Lib_Audio3d, "!parameters || !id");
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
}
const int id = static_cast<int>(state->ports.size()) + 1;
if (id > 3) {
LOG_ERROR(Lib_Audio3d, "id > 3");
return ORBIS_AUDIO3D_ERROR_OUT_OF_RESOURCES;
}
*port_id = id;
std::memcpy(&state->ports[id].parameters, parameters, sizeof(OrbisAudio3dOpenParameters));
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceAudio3dPortPush(const OrbisAudio3dPortId port_id,
const OrbisAudio3dBlocking blocking) {
LOG_DEBUG(Lib_Audio3d, "called, port_id = {}, blocking = {}", port_id,
magic_enum::enum_name(blocking));
if (!state->ports.contains(port_id)) {
LOG_ERROR(Lib_Audio3d, "!state->ports.contains(port_id)");
return ORBIS_AUDIO3D_ERROR_INVALID_PORT;
}
const auto& port = state->ports[port_id];
if (port.parameters.buffer_mode !=
OrbisAudio3dBufferMode::ORBIS_AUDIO3D_BUFFER_ADVANCE_AND_PUSH) {
LOG_ERROR(Lib_Audio3d, "port doesn't have push capability");
return ORBIS_AUDIO3D_ERROR_NOT_SUPPORTED;
}
if (!port.current_buffer.has_value()) {
// Nothing to push.
LOG_DEBUG(Lib_Audio3d, "Port push with no buffer ready");
return ORBIS_OK;
}
// TODO: Implement asynchronous blocking mode.
const auto& [sample_buffer, num_samples] = port.current_buffer.value();
return AudioOut::sceAudioOutOutput(state->audio_out_handle, sample_buffer);
}
s32 PS4_SYSV_ABI sceAudio3dPortQueryDebug() {
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceAudio3dPortSetAttribute(const OrbisAudio3dPortId port_id,
const OrbisAudio3dAttributeId attribute_id,
void* attribute, const u64 attribute_size) {
LOG_INFO(Lib_Audio3d,
"uiPortId = {}, userId = {}, type = {}, index = {}, len = {}, freq = {}, param = {}",
uiPortId, userId, type, index, len, freq, param);
return ORBIS_OK;
}
"called, port_id = {}, attribute_id = {}, attribute = {}, attribute_size = {}",
port_id, static_cast<u32>(attribute_id), attribute, attribute_size);
s32 PS4_SYSV_ABI sceAudio3dAudioOutClose(s32 handle) {
LOG_INFO(Lib_Audio3d, "handle = {}", handle);
return ORBIS_OK;
}
if (!state->ports.contains(port_id)) {
LOG_ERROR(Lib_Audio3d, "!state->ports.contains(port_id)");
return ORBIS_AUDIO3D_ERROR_INVALID_PORT;
}
s32 PS4_SYSV_ABI sceAudio3dAudioOutOutput(s32 handle, const void* ptr) {
LOG_TRACE(Lib_Audio3d, "handle = {}", handle);
if (ptr == nullptr) {
LOG_ERROR(Lib_Audio3d, "invalid Output ptr");
if (!attribute) {
LOG_ERROR(Lib_Audio3d, "!attribute");
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
}
// TODO
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceAudio3dAudioOutOutputs(::Libraries::AudioOut::OrbisAudioOutOutputParam* param,
s32 num) {
LOG_INFO(Lib_Audio3d, "num = {}", num);
if (param == nullptr) {
LOG_ERROR(Lib_Audio3d, "invalid OutputParam ptr");
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
}
return ORBIS_OK;
}
int PS4_SYSV_ABI sceAudio3dPortCreate(u32 uiGranularity, OrbisAudio3dRate eRate, s64 iReserved,
OrbisAudio3dPortId* pId) {
LOG_INFO(Lib_Audio3d, "uiGranularity = {}, iReserved = {}", uiGranularity, iReserved);
return ORBIS_OK;
}
int PS4_SYSV_ABI sceAudio3dPortDestroy(OrbisAudio3dPortId uiPortId) {
LOG_INFO(Lib_Audio3d, "uiPortId = {}", uiPortId);
return ORBIS_OK;
}
// Audio3dPrivate
const char* PS4_SYSV_ABI sceAudio3dStrError(int iErrorCode) {
LOG_ERROR(Lib_Audio3d, "(PRIVATE) called, iErrorCode = {}", iErrorCode);
return "NOT_IMPLEMENTED";
}
// Audio3dDebug
int PS4_SYSV_ABI sceAudio3dPortQueryDebug() {
LOG_WARNING(Lib_Audio3d, "(DEBUG) sceAudio3dPortQueryDebug called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceAudio3dPortGetList() {
LOG_WARNING(Lib_Audio3d, "(DEBUG) sceAudio3dPortGetList called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceAudio3dPortGetParameters() {
LOG_WARNING(Lib_Audio3d, "(DEBUG) sceAudio3dPortGetParameters called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceAudio3dPortGetState() {
LOG_WARNING(Lib_Audio3d, "(DEBUG) sceAudio3dPortGetState called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceAudio3dPortFreeState() {
LOG_WARNING(Lib_Audio3d, "(DEBUG) sceAudio3dPortFreeState called");
return ORBIS_OK;
}
// Unknown
int PS4_SYSV_ABI sceAudio3dPortGetBufferLevel() {
s32 PS4_SYSV_ABI sceAudio3dReportRegisterHandler() {
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceAudio3dPortGetStatus() {
s32 PS4_SYSV_ABI sceAudio3dReportUnregisterHandler() {
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceAudio3dReportRegisterHandler() {
s32 PS4_SYSV_ABI sceAudio3dSetGpuRenderer() {
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceAudio3dReportUnregisterHandler() {
s32 PS4_SYSV_ABI sceAudio3dStrError() {
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceAudio3dSetGpuRenderer() {
s32 PS4_SYSV_ABI sceAudio3dTerminate() {
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
return ORBIS_OK;
}
void RegisterlibSceAudio3d(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("pZlOm1aF3aA", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dAudioOutClose);
LIB_FUNCTION("ucEsi62soTo", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dAudioOutOpen);
LIB_FUNCTION("7NYEzJ9SJbM", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
sceAudio3dAudioOutOutput);
LIB_FUNCTION("HbxYY27lK6E", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
sceAudio3dAudioOutOutputs);
LIB_FUNCTION("9tEwE0GV0qo", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dBedWrite);
LIB_FUNCTION("xH4Q9UILL3o", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dBedWrite2);
LIB_FUNCTION("lvWMW6vEqFU", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
sceAudio3dCreateSpeakerArray);
LIB_FUNCTION("8hm6YdoQgwg", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
sceAudio3dDeleteSpeakerArray);
LIB_FUNCTION("Im+jOoa5WAI", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
sceAudio3dGetDefaultOpenParameters);
LIB_FUNCTION("kEqqyDkmgdI", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
sceAudio3dGetSpeakerArrayMemorySize);
LIB_FUNCTION("-R1DukFq7Dk", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
sceAudio3dGetSpeakerArrayMixCoefficients);
LIB_FUNCTION("-Re+pCWvwjQ", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
sceAudio3dGetSpeakerArrayMixCoefficients2);
LIB_FUNCTION("-pzYDZozm+M", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
sceAudio3dPortQueryDebug);
LIB_FUNCTION("1HXxo-+1qCw", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
sceAudio3dObjectUnreserve);
LIB_FUNCTION("UmCvjSmuZIw", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dInitialize);
LIB_FUNCTION("jO2tec4dJ2M", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dObjectReserve);
LIB_FUNCTION("4uyHN9q4ZeU", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
sceAudio3dObjectSetAttributes);
LIB_FUNCTION("7NYEzJ9SJbM", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
sceAudio3dAudioOutOutput);
LIB_FUNCTION("8hm6YdoQgwg", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
sceAudio3dDeleteSpeakerArray);
LIB_FUNCTION("1HXxo-+1qCw", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
sceAudio3dObjectUnreserve);
LIB_FUNCTION("lw0qrdSjZt8", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortAdvance);
LIB_FUNCTION("OyVqOeVNtSk", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortClose);
LIB_FUNCTION("UHFOgVNz0kk", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortCreate);
LIB_FUNCTION("Mw9mRQtWepY", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortDestroy);
LIB_FUNCTION("ZOGrxWLgQzE", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortFlush);
LIB_FUNCTION("uJ0VhGcxCTQ", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortFreeState);
LIB_FUNCTION("9ZA23Ia46Po", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
sceAudio3dPortGetAttributesSupported);
LIB_FUNCTION("9tEwE0GV0qo", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dBedWrite);
LIB_FUNCTION("Aacl5qkRU6U", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dStrError);
LIB_FUNCTION("CKHlRW2E9dA", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortGetState);
LIB_FUNCTION("HbxYY27lK6E", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
sceAudio3dAudioOutOutputs);
LIB_FUNCTION("Im+jOoa5WAI", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
sceAudio3dGetDefaultOpenParameters);
LIB_FUNCTION("Mw9mRQtWepY", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortDestroy);
LIB_FUNCTION("OyVqOeVNtSk", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortClose);
LIB_FUNCTION("QfNXBrKZeI0", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
sceAudio3dReportRegisterHandler);
LIB_FUNCTION("QqgTQQdzEMY", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
sceAudio3dPortGetBufferLevel);
LIB_FUNCTION("SEggctIeTcI", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortGetList);
LIB_FUNCTION("UHFOgVNz0kk", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortCreate);
LIB_FUNCTION("UmCvjSmuZIw", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dInitialize);
LIB_FUNCTION("VEVhZ9qd4ZY", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortPush);
LIB_FUNCTION("WW1TS2iz5yc", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dTerminate);
LIB_FUNCTION("XeDDK0xJWQA", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortOpen);
LIB_FUNCTION("YaaDbDwKpFM", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
sceAudio3dPortGetQueueLevel);
LIB_FUNCTION("Yq9bfUQ0uJg", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
sceAudio3dPortSetAttribute);
LIB_FUNCTION("ZOGrxWLgQzE", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortFlush);
LIB_FUNCTION("flPcUaXVXcw", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
sceAudio3dPortGetParameters);
LIB_FUNCTION("YaaDbDwKpFM", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
sceAudio3dPortGetQueueLevel);
LIB_FUNCTION("CKHlRW2E9dA", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortGetState);
LIB_FUNCTION("iRX6GJs9tvE", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortGetStatus);
LIB_FUNCTION("jO2tec4dJ2M", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dObjectReserve);
LIB_FUNCTION("kEqqyDkmgdI", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
sceAudio3dGetSpeakerArrayMemorySize);
LIB_FUNCTION("lvWMW6vEqFU", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
sceAudio3dCreateSpeakerArray);
LIB_FUNCTION("lw0qrdSjZt8", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortAdvance);
LIB_FUNCTION("pZlOm1aF3aA", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dAudioOutClose);
LIB_FUNCTION("XeDDK0xJWQA", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortOpen);
LIB_FUNCTION("VEVhZ9qd4ZY", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortPush);
LIB_FUNCTION("-pzYDZozm+M", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
sceAudio3dPortQueryDebug);
LIB_FUNCTION("Yq9bfUQ0uJg", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
sceAudio3dPortSetAttribute);
LIB_FUNCTION("QfNXBrKZeI0", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
sceAudio3dReportRegisterHandler);
LIB_FUNCTION("psv2gbihC1A", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
sceAudio3dReportUnregisterHandler);
LIB_FUNCTION("uJ0VhGcxCTQ", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortFreeState);
LIB_FUNCTION("ucEsi62soTo", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dAudioOutOpen);
LIB_FUNCTION("xH4Q9UILL3o", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dBedWrite2);
LIB_FUNCTION("yEYXcbAGK14", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
sceAudio3dSetGpuRenderer);
LIB_FUNCTION("Aacl5qkRU6U", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dStrError);
LIB_FUNCTION("WW1TS2iz5yc", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dTerminate);
};
} // namespace Libraries::Audio3d

View File

@ -1,11 +1,13 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/types.h"
#include <optional>
#include <queue>
#include <stddef.h>
#include "common/types.h"
#include "core/libraries/audio/audioout.h"
namespace Core::Loader {
class SymbolsResolver;
@ -13,123 +15,131 @@ class SymbolsResolver;
namespace Libraries::Audio3d {
class Audio3d;
using OrbisUserServiceUserId = s32;
using OrbisAudio3dPortId = u32;
using OrbisAudio3dObjectId = u32;
using OrbisAudio3dAttributeId = u32;
enum class OrbisAudio3dFormat {
S16 = 0,
Float = 1,
enum class OrbisAudio3dRate : u32 {
ORBIS_AUDIO3D_RATE_48000 = 0,
};
enum class OrbisAudio3dRate {
Rate48000 = 0,
enum class OrbisAudio3dBufferMode : u32 {
ORBIS_AUDIO3D_BUFFER_NO_ADVANCE = 0,
ORBIS_AUDIO3D_BUFFER_ADVANCE_NO_PUSH = 1,
ORBIS_AUDIO3D_BUFFER_ADVANCE_AND_PUSH = 2,
};
enum class OrbisAudio3dBufferMode { NoAdvance = 0, AdvanceNoPush = 1, AdvanceAndPush = 2 };
enum class OrbisAudio3dBlocking {
Async = 0,
Sync = 1,
};
enum class OrbisAudio3dPassthrough {
None = 0,
Left = 1,
Right = 2,
};
enum class OrbisAudio3dOutputRoute {
Both = 0,
HmuOnly = 1,
TvOnly = 2,
};
enum class OrbisAudio3dAmbisonics : u32 {
None = ~0U,
W = 0,
X = 1,
Y = 2,
Z = 3,
R = 4,
S = 5,
T = 6,
U = 7,
V = 8,
K = 9,
L = 10,
M = 11,
N = 12,
O = 13,
P = 14,
Q = 15
};
static const OrbisAudio3dAttributeId s_sceAudio3dAttributePcm = 0x00000001;
static const OrbisAudio3dAttributeId s_sceAudio3dAttributePriority = 0x00000002;
static const OrbisAudio3dAttributeId s_sceAudio3dAttributePosition = 0x00000003;
static const OrbisAudio3dAttributeId s_sceAudio3dAttributeSpread = 0x00000004;
static const OrbisAudio3dAttributeId s_sceAudio3dAttributeGain = 0x00000005;
static const OrbisAudio3dAttributeId s_sceAudio3dAttributePassthrough = 0x00000006;
static const OrbisAudio3dAttributeId s_sceAudio3dAttributeResetState = 0x00000007;
static const OrbisAudio3dAttributeId s_sceAudio3dAttributeApplicationSpecific = 0x00000008;
static const OrbisAudio3dAttributeId s_sceAudio3dAttributeAmbisonics = 0x00000009;
static const OrbisAudio3dAttributeId s_sceAudio3dAttributeRestricted = 0x0000000A;
static const OrbisAudio3dAttributeId s_sceAudio3dAttributeOutputRoute = 0x0000000B;
static const OrbisAudio3dAttributeId s_sceAudio3dAttributeLateReverbLevel = 0x00010001;
static const OrbisAudio3dAttributeId s_sceAudio3dAttributeDownmixSpreadRadius = 0x00010002;
static const OrbisAudio3dAttributeId s_sceAudio3dAttributeDownmixSpreadHeightAware = 0x00010003;
struct OrbisAudio3dSpeakerArray;
using OrbisAudio3dSpeakerArrayHandle = OrbisAudio3dSpeakerArray*; // head
struct OrbisAudio3dOpenParameters {
size_t size_this;
u64 size_this;
u32 granularity;
OrbisAudio3dRate rate;
u32 max_objects;
u32 queue_depth;
OrbisAudio3dBufferMode buffer_mode;
char padding[32];
int : 32;
u32 num_beds;
};
struct OrbisAudio3dAttribute {
OrbisAudio3dAttributeId attribute_id;
char padding[32];
const void* p_value;
size_t value;
enum class OrbisAudio3dFormat : u32 {
ORBIS_AUDIO3D_FORMAT_S16 = 0,
ORBIS_AUDIO3D_FORMAT_FLOAT = 1,
};
struct OrbisAudio3dPosition {
float fX;
float fY;
float fZ;
enum class OrbisAudio3dOutputRoute : u32 {
ORBIS_AUDIO3D_OUTPUT_BOTH = 0,
ORBIS_AUDIO3D_OUTPUT_HMU_ONLY = 1,
ORBIS_AUDIO3D_OUTPUT_TV_ONLY = 2,
};
enum class OrbisAudio3dBlocking : u32 {
ORBIS_AUDIO3D_BLOCKING_ASYNC = 0,
ORBIS_AUDIO3D_BLOCKING_SYNC = 1,
};
struct OrbisAudio3dPcm {
OrbisAudio3dFormat format;
const void* sample_buffer;
void* sample_buffer;
u32 num_samples;
};
struct OrbisAudio3dSpeakerArrayParameters {
OrbisAudio3dPosition* speaker_position;
u32 num_speakers;
bool is_3d;
void* buffer;
size_t size;
enum class OrbisAudio3dAttributeId : u32 {
ORBIS_AUDIO3D_ATTRIBUTE_PCM = 1,
};
struct OrbisAudio3dApplicationSpecific {
size_t size_this;
u8 application_specific[32];
using OrbisAudio3dPortId = u32;
using OrbisAudio3dObjectId = u32;
struct OrbisAudio3dAttribute {
OrbisAudio3dAttributeId attribute_id;
int : 32;
void* value;
u64 value_size;
};
void PS4_SYSV_ABI sceAudio3dGetDefaultOpenParameters(OrbisAudio3dOpenParameters* sParameters);
struct AudioData {
u8* sample_buffer;
u32 num_samples;
};
struct Port {
OrbisAudio3dOpenParameters parameters{};
std::deque<AudioData> queue; // Only stores PCM buffers for now
std::optional<AudioData> current_buffer{};
};
struct Audio3dState {
std::unordered_map<OrbisAudio3dPortId, Port> ports;
s32 audio_out_handle;
};
s32 PS4_SYSV_ABI sceAudio3dAudioOutClose(s32 handle);
s32 PS4_SYSV_ABI sceAudio3dAudioOutOpen(OrbisAudio3dPortId port_id, OrbisUserServiceUserId user_id,
s32 type, s32 index, u32 len, u32 freq,
AudioOut::OrbisAudioOutParamExtendedInformation param);
s32 PS4_SYSV_ABI sceAudio3dAudioOutOutput(s32 handle, void* ptr);
s32 PS4_SYSV_ABI sceAudio3dAudioOutOutputs(AudioOut::OrbisAudioOutOutputParam* param, u32 num);
s32 PS4_SYSV_ABI sceAudio3dBedWrite(OrbisAudio3dPortId port_id, u32 num_channels,
OrbisAudio3dFormat format, void* buffer, u32 num_samples);
s32 PS4_SYSV_ABI sceAudio3dBedWrite2(OrbisAudio3dPortId port_id, u32 num_channels,
OrbisAudio3dFormat format, void* buffer, u32 num_samples,
OrbisAudio3dOutputRoute output_route, bool restricted);
s32 PS4_SYSV_ABI sceAudio3dCreateSpeakerArray();
s32 PS4_SYSV_ABI sceAudio3dDeleteSpeakerArray();
s32 PS4_SYSV_ABI sceAudio3dGetDefaultOpenParameters(OrbisAudio3dOpenParameters* params);
s32 PS4_SYSV_ABI sceAudio3dGetSpeakerArrayMemorySize();
s32 PS4_SYSV_ABI sceAudio3dGetSpeakerArrayMixCoefficients();
s32 PS4_SYSV_ABI sceAudio3dGetSpeakerArrayMixCoefficients2();
s32 PS4_SYSV_ABI sceAudio3dInitialize(s64 reserved);
s32 PS4_SYSV_ABI sceAudio3dObjectReserve(OrbisAudio3dPortId port_id,
OrbisAudio3dObjectId* object_id);
s32 PS4_SYSV_ABI sceAudio3dObjectSetAttributes(OrbisAudio3dPortId port_id,
OrbisAudio3dObjectId object_id, u64 num_attributes,
const OrbisAudio3dAttribute* attribute_array);
s32 PS4_SYSV_ABI sceAudio3dObjectUnreserve();
s32 PS4_SYSV_ABI sceAudio3dPortAdvance(OrbisAudio3dPortId port_id);
s32 PS4_SYSV_ABI sceAudio3dPortClose();
s32 PS4_SYSV_ABI sceAudio3dPortCreate();
s32 PS4_SYSV_ABI sceAudio3dPortDestroy();
s32 PS4_SYSV_ABI sceAudio3dPortFlush();
s32 PS4_SYSV_ABI sceAudio3dPortFreeState();
s32 PS4_SYSV_ABI sceAudio3dPortGetAttributesSupported();
s32 PS4_SYSV_ABI sceAudio3dPortGetList();
s32 PS4_SYSV_ABI sceAudio3dPortGetParameters();
s32 PS4_SYSV_ABI sceAudio3dPortGetQueueLevel(OrbisAudio3dPortId port_id, u32* queue_level,
u32* queue_available);
s32 PS4_SYSV_ABI sceAudio3dPortGetState();
s32 PS4_SYSV_ABI sceAudio3dPortGetStatus();
s32 PS4_SYSV_ABI sceAudio3dPortOpen(OrbisUserServiceUserId user_id,
const OrbisAudio3dOpenParameters* parameters,
OrbisAudio3dPortId* port_id);
s32 PS4_SYSV_ABI sceAudio3dPortPush(OrbisAudio3dPortId port_id, OrbisAudio3dBlocking blocking);
s32 PS4_SYSV_ABI sceAudio3dPortQueryDebug();
s32 PS4_SYSV_ABI sceAudio3dPortSetAttribute(OrbisAudio3dPortId port_id,
OrbisAudio3dAttributeId attribute_id, void* attribute,
u64 attribute_size);
s32 PS4_SYSV_ABI sceAudio3dReportRegisterHandler();
s32 PS4_SYSV_ABI sceAudio3dReportUnregisterHandler();
s32 PS4_SYSV_ABI sceAudio3dSetGpuRenderer();
s32 PS4_SYSV_ABI sceAudio3dStrError();
s32 PS4_SYSV_ABI sceAudio3dTerminate();
void RegisterlibSceAudio3d(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::Audio3d

View File

@ -3,8 +3,6 @@
#pragma once
#include "core/libraries/error_codes.h"
constexpr int ORBIS_AUDIO3D_ERROR_UNKNOWN = 0x80EA0001;
constexpr int ORBIS_AUDIO3D_ERROR_INVALID_PORT = 0x80EA0002;
constexpr int ORBIS_AUDIO3D_ERROR_INVALID_OBJECT = 0x80EA0003;

View File

@ -1,16 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "audio3d.h"
namespace Libraries::Audio3d {
class Audio3d {
public:
private:
using OrbisAudio3dPluginId = u32;
};
} // namespace Libraries::Audio3d

View File

@ -9,29 +9,29 @@
namespace Libraries::DiscMap {
int PS4_SYSV_ABI sceDiscMapGetPackageSize() {
LOG_WARNING(Lib_DiscMap, "(DUMMY) called");
int PS4_SYSV_ABI sceDiscMapGetPackageSize(s64 fflags, int* ret1, int* ret2) {
return ORBIS_DISC_MAP_ERROR_NO_BITMAP_INFO;
}
int PS4_SYSV_ABI sceDiscMapIsRequestOnHDD() {
LOG_WARNING(Lib_DiscMap, "(DUMMY) called");
int PS4_SYSV_ABI sceDiscMapIsRequestOnHDD(char* path, s64 offset, s64 nbytes, int* ret) {
return ORBIS_DISC_MAP_ERROR_NO_BITMAP_INFO;
}
int PS4_SYSV_ABI Func_7C980FFB0AA27E7A() {
LOG_ERROR(Lib_DiscMap, "(STUBBED) called");
int PS4_SYSV_ABI Func_7C980FFB0AA27E7A(char* path, s64 offset, s64 nbytes, int* flags, int* ret1,
int* ret2) {
*flags = 0;
*ret1 = 0;
*ret2 = 0;
return ORBIS_OK;
}
int PS4_SYSV_ABI Func_8A828CAEE7EDD5E9() {
LOG_ERROR(Lib_DiscMap, "(STUBBED) called");
return ORBIS_OK;
int PS4_SYSV_ABI Func_8A828CAEE7EDD5E9(char* path, s64 offset, s64 nbytes, int* flags, int* ret1,
int* ret2) {
return ORBIS_DISC_MAP_ERROR_NO_BITMAP_INFO;
}
int PS4_SYSV_ABI Func_E7EBCE96E92F91F8() {
LOG_ERROR(Lib_DiscMap, "(STUBBED) called");
return ORBIS_OK;
return ORBIS_DISC_MAP_ERROR_NO_BITMAP_INFO;
}
void RegisterlibSceDiscMap(Core::Loader::SymbolsResolver* sym) {

View File

@ -10,10 +10,12 @@ class SymbolsResolver;
}
namespace Libraries::DiscMap {
int PS4_SYSV_ABI sceDiscMapGetPackageSize();
int PS4_SYSV_ABI sceDiscMapIsRequestOnHDD();
int PS4_SYSV_ABI Func_7C980FFB0AA27E7A();
int PS4_SYSV_ABI Func_8A828CAEE7EDD5E9();
int PS4_SYSV_ABI sceDiscMapGetPackageSize(s64 fflags, int* ret1, int* ret2);
int PS4_SYSV_ABI sceDiscMapIsRequestOnHDD(char* path, s64 offset, s64 nbytes, int* ret);
int PS4_SYSV_ABI Func_7C980FFB0AA27E7A(char* path, s64 offset, s64 nbytes, int* flags, int* ret1,
int* ret2);
int PS4_SYSV_ABI Func_8A828CAEE7EDD5E9(char* path, s64 offset, s64 nbytes, int* flags, int* ret1,
int* ret2);
int PS4_SYSV_ABI Func_E7EBCE96E92F91F8();
void RegisterlibSceDiscMap(Core::Loader::SymbolsResolver* sym);

View File

@ -1087,7 +1087,8 @@ s32 PS4_SYSV_ABI sceGnmInsertWaitFlipDone(u32* cmdbuf, u32 size, s32 vo_handle,
}
uintptr_t label_addr{};
VideoOut::sceVideoOutGetBufferLabelAddress(vo_handle, &label_addr);
ASSERT_MSG(VideoOut::sceVideoOutGetBufferLabelAddress(vo_handle, &label_addr) == 16,
"sceVideoOutGetBufferLabelAddress call failed");
auto* wait_reg_mem = reinterpret_cast<PM4CmdWaitRegMem*>(cmdbuf);
wait_reg_mem->header = PM4Type3Header{PM4ItOpcode::WaitRegMem, 5};
@ -2041,7 +2042,8 @@ static inline s32 PatchFlipRequest(u32* cmdbuf, u32 size, u32 vo_handle, u32 buf
}
uintptr_t label_addr{};
VideoOut::sceVideoOutGetBufferLabelAddress(vo_handle, &label_addr);
ASSERT_MSG(VideoOut::sceVideoOutGetBufferLabelAddress(vo_handle, &label_addr) == 16,
"sceVideoOutGetBufferLabelAddress call failed");
// Write event to lock the VO surface
auto* write_lock = reinterpret_cast<PM4CmdWriteData*>(cmdbuf);
@ -2802,7 +2804,7 @@ void RegisterlibSceGnmDriver(Core::Loader::SymbolsResolver* sym) {
liverpool = std::make_unique<AmdGpu::Liverpool>();
presenter = std::make_unique<Vulkan::Presenter>(*g_window, liverpool.get());
const int result = sceKernelGetCompiledSdkVersion(&sdk_version);
const s32 result = sceKernelGetCompiledSdkVersion(&sdk_version);
if (result != ORBIS_OK) {
sdk_version = 0;
}

View File

@ -49,9 +49,9 @@ public:
// Are we supposed to call the event handler on init with
// ADD_OSK?
if (!ime_mode && False(m_param.key.option & OrbisImeKeyboardOption::AddOsk)) {
/* if (!ime_mode && False(m_param.key.option & OrbisImeKeyboardOption::AddOsk)) {
Execute(nullptr, &openEvent, true);
}
}*/
if (ime_mode) {
g_ime_state = ImeState(&m_param.ime);
@ -274,6 +274,13 @@ s32 PS4_SYSV_ABI sceImeKeyboardOpen(s32 userId, const OrbisImeKeyboardParam* par
if (!param) {
return ORBIS_IME_ERROR_INVALID_ADDRESS;
}
if (!param->arg) {
return ORBIS_IME_ERROR_INVALID_ARG;
}
if (!param->handler) {
return ORBIS_IME_ERROR_INVALID_HANDLER;
}
if (g_keyboard_handler) {
return ORBIS_IME_ERROR_BUSY;
}

View File

@ -20,7 +20,7 @@ enum class OrbisImeKeyboardOption : u32 {
Repeat = 1,
RepeatEachKey = 2,
AddOsk = 4,
EffectiveWithTime = 8,
EffectiveWithIme = 8,
DisableResume = 16,
DisableCapslockWithoutShift = 32,
};

View File

@ -83,9 +83,35 @@ int PS4_SYSV_ABI sceImeDialogGetPanelPositionAndForm() {
return ORBIS_OK;
}
int PS4_SYSV_ABI sceImeDialogGetPanelSize() {
LOG_ERROR(Lib_ImeDialog, "(STUBBED) called");
return ORBIS_OK;
Error PS4_SYSV_ABI sceImeDialogGetPanelSize(const OrbisImeDialogParam* param, u32* width,
u32* height) {
LOG_INFO(Lib_ImeDialog, "called");
if (!width || !height) {
return Error::INVALID_ADDRESS;
}
switch (param->type) {
case OrbisImeType::Default:
case OrbisImeType::BasicLatin:
case OrbisImeType::Url:
case OrbisImeType::Mail:
*width = 500; // original: 793
if (True(param->option & OrbisImeDialogOption::Multiline)) {
*height = 300; // original: 576
} else {
*height = 150; // original: 476
}
break;
case OrbisImeType::Number:
*width = 370;
*height = 470;
break;
default:
LOG_ERROR(Lib_ImeDialog, "Unknown OrbisImeType: {}", (u32)param->type);
return Error::INVALID_PARAM;
}
return Error::OK;
}
int PS4_SYSV_ABI sceImeDialogGetPanelSizeExtended() {

View File

@ -13,7 +13,7 @@ class SymbolsResolver;
namespace Libraries::ImeDialog {
constexpr u32 ORBIS_IME_DIALOG_MAX_TEXT_LENGTH = 0x78;
constexpr u32 ORBIS_IME_DIALOG_MAX_TEXT_LENGTH = 2048;
enum class Error : u32 {
OK = 0x0,
@ -155,7 +155,8 @@ Error PS4_SYSV_ABI sceImeDialogForceClose();
Error PS4_SYSV_ABI sceImeDialogForTestFunction();
int PS4_SYSV_ABI sceImeDialogGetCurrentStarState();
int PS4_SYSV_ABI sceImeDialogGetPanelPositionAndForm();
int PS4_SYSV_ABI sceImeDialogGetPanelSize();
Error PS4_SYSV_ABI sceImeDialogGetPanelSize(const OrbisImeDialogParam* param, u32* width,
u32* height);
int PS4_SYSV_ABI sceImeDialogGetPanelSizeExtended();
Error PS4_SYSV_ABI sceImeDialogGetResult(OrbisImeDialogResult* result);
OrbisImeDialogStatus PS4_SYSV_ABI sceImeDialogGetStatus();

View File

@ -0,0 +1,20 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/assert.h"
#include "core/libraries/kernel/file_system.h"
#include "core/libraries/kernel/orbis_error.h"
#include "core/libraries/libs.h"
namespace Libraries::Kernel {
void PS4_SYSV_ABI sceKernelDebugOutText(void* unk, char* text) {
sceKernelWrite(1, text, strlen(text));
return;
}
void RegisterDebug(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("9JYNqN6jAKI", "libkernel", 1, "libkernel", 1, 1, sceKernelDebugOutText);
}
} // namespace Libraries::Kernel

View File

@ -0,0 +1,14 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
namespace Core::Loader {
class SymbolsResolver;
}
namespace Libraries::Kernel {
void RegisterDebug(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::Kernel

View File

@ -61,6 +61,18 @@ struct SceKernelEvent {
void* udata = nullptr; /* opaque user data identifier */
};
struct OrbisVideoOutEventHint {
u64 event_id : 8;
u64 video_id : 8;
u64 flip_arg : 48;
};
struct OrbisVideoOutEventData {
u64 time : 12;
u64 count : 4;
u64 flip_arg : 48;
};
struct EqueueEvent {
SceKernelEvent event;
void* data = nullptr;
@ -84,19 +96,18 @@ struct EqueueEvent {
void TriggerDisplay(void* data) {
is_triggered = true;
auto hint = reinterpret_cast<u64>(data);
if (hint != 0) {
auto hint_h = static_cast<u32>(hint >> 8) & 0xFFFFFF;
auto ident_h = static_cast<u32>(event.ident >> 40);
if ((static_cast<u32>(hint) & 0xFF) == event.ident && event.ident != 0xFE &&
((hint_h ^ ident_h) & 0xFF) == 0) {
if (data != nullptr) {
auto event_data = static_cast<OrbisVideoOutEventData>(event.data);
auto event_hint_raw = reinterpret_cast<u64>(data);
auto event_hint = static_cast<OrbisVideoOutEventHint>(event_hint_raw);
if (event_hint.event_id == event.ident && event.ident != 0xfe) {
auto time = Common::FencedRDTSC();
auto mask = 0xF000;
if ((static_cast<u32>(event.data) & 0xF000) != 0xF000) {
mask = (static_cast<u32>(event.data) + 0x1000) & 0xF000;
auto counter = event_data.count;
if (counter != 0xf) {
counter++;
}
event.data = (mask | static_cast<u64>(static_cast<u32>(time) & 0xFFF) |
(hint & 0xFFFFFFFFFFFF0000));
event.data =
(time & 0xfff) | (counter << 0xc) | (event_hint_raw & 0xffffffffffff0000);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -65,10 +65,10 @@ constexpr int ORBIS_KERNEL_O_DSYNC = 0x1000;
constexpr int ORBIS_KERNEL_O_DIRECT = 0x00010000;
constexpr int ORBIS_KERNEL_O_DIRECTORY = 0x00020000;
s64 PS4_SYSV_ABI sceKernelWrite(int d, const void* buf, size_t nbytes);
s64 PS4_SYSV_ABI sceKernelRead(int d, void* buf, size_t nbytes);
s64 PS4_SYSV_ABI sceKernelPread(int d, void* buf, size_t nbytes, s64 offset);
s64 PS4_SYSV_ABI sceKernelPwrite(int d, void* buf, size_t nbytes, s64 offset);
s64 PS4_SYSV_ABI sceKernelWrite(s32 fd, const void* buf, size_t nbytes);
s64 PS4_SYSV_ABI sceKernelRead(s32 fd, void* buf, size_t nbytes);
s64 PS4_SYSV_ABI sceKernelPread(s32 fd, void* buf, size_t nbytes, s64 offset);
s64 PS4_SYSV_ABI sceKernelPwrite(s32 fd, void* buf, size_t nbytes, s64 offset);
void RegisterFileSystem(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::Kernel

View File

@ -12,6 +12,7 @@
#include "common/va_ctx.h"
#include "core/file_sys/fs.h"
#include "core/libraries/error_codes.h"
#include "core/libraries/kernel/debug.h"
#include "core/libraries/kernel/equeue.h"
#include "core/libraries/kernel/file_system.h"
#include "core/libraries/kernel/kernel.h"
@ -85,17 +86,23 @@ int ErrnoToSceKernelError(int error) {
}
void SetPosixErrno(int e) {
// Some error numbers are different between supported OSes or the PS4
// Some error numbers are different between supported OSes
switch (e) {
case EPERM:
g_posix_errno = POSIX_EPERM;
break;
case EAGAIN:
g_posix_errno = POSIX_EAGAIN;
case ENOENT:
g_posix_errno = POSIX_ENOENT;
break;
case EDEADLK:
g_posix_errno = POSIX_EDEADLK;
break;
case ENOMEM:
g_posix_errno = POSIX_ENOMEM;
break;
case EACCES:
g_posix_errno = POSIX_EACCES;
break;
case EINVAL:
g_posix_errno = POSIX_EINVAL;
break;
@ -105,13 +112,14 @@ void SetPosixErrno(int e) {
case ERANGE:
g_posix_errno = POSIX_ERANGE;
break;
case EDEADLK:
g_posix_errno = POSIX_EDEADLK;
case EAGAIN:
g_posix_errno = POSIX_EAGAIN;
break;
case ETIMEDOUT:
g_posix_errno = POSIX_ETIMEDOUT;
break;
default:
LOG_WARNING(Kernel, "Unhandled errno {}", e);
g_posix_errno = e;
}
}
@ -133,14 +141,6 @@ void PS4_SYSV_ABI sceLibcHeapGetTraceInfo(HeapInfoInfo* info) {
info->getSegmentInfo = 0;
}
s64 PS4_SYSV_ABI ps4__write(int d, const char* buf, std::size_t nbytes) {
return sceKernelWrite(d, buf, nbytes);
}
s64 PS4_SYSV_ABI ps4__read(int d, void* buf, u64 nbytes) {
return sceKernelRead(d, buf, nbytes);
}
struct OrbisKernelUuid {
u32 timeLow;
u16 timeMid;
@ -220,6 +220,7 @@ void RegisterKernel(Core::Loader::SymbolsResolver* sym) {
Libraries::Kernel::RegisterProcess(sym);
Libraries::Kernel::RegisterException(sym);
Libraries::Kernel::RegisterAio(sym);
Libraries::Kernel::RegisterDebug(sym);
LIB_OBJ("f7uOxY9mM1U", "libkernel", 1, "libkernel", 1, 1, &g_stack_chk_guard);
LIB_FUNCTION("PfccT7qURYE", "libkernel", 1, "libkernel", 1, 1, kernel_ioctl);
@ -229,13 +230,10 @@ void RegisterKernel(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("Xjoosiw+XPI", "libkernel", 1, "libkernel", 1, 1, sceKernelUuidCreate);
LIB_FUNCTION("Ou3iL1abvng", "libkernel", 1, "libkernel", 1, 1, stack_chk_fail);
LIB_FUNCTION("9BcDykPmo1I", "libkernel", 1, "libkernel", 1, 1, __Error);
LIB_FUNCTION("DRuBt2pvICk", "libkernel", 1, "libkernel", 1, 1, ps4__read);
LIB_FUNCTION("k+AXqu2-eBc", "libkernel", 1, "libkernel", 1, 1, posix_getpagesize);
LIB_FUNCTION("k+AXqu2-eBc", "libScePosix", 1, "libkernel", 1, 1, posix_getpagesize);
LIB_FUNCTION("NWtTN10cJzE", "libSceLibcInternalExt", 1, "libSceLibcInternal", 1, 1,
sceLibcHeapGetTraceInfo);
LIB_FUNCTION("FxVZqBAA7ks", "libkernel", 1, "libkernel", 1, 1, ps4__write);
LIB_FUNCTION("FN4gaPmuFV8", "libScePosix", 1, "libkernel", 1, 1, ps4__write);
}
} // namespace Libraries::Kernel

View File

@ -5,6 +5,7 @@
#include <algorithm>
#include <fmt/core.h>
#include "common/string_literal.h"
#include "common/types.h"
#include "core/libraries/kernel/orbis_error.h"
@ -18,15 +19,6 @@ void ErrSceToPosix(int result);
int ErrnoToSceKernelError(int e);
void SetPosixErrno(int e);
template <size_t N>
struct StringLiteral {
constexpr StringLiteral(const char (&str)[N]) {
std::copy_n(str, N, value);
}
char value[N];
};
template <StringLiteral name, class F, F f>
struct WrapperImpl;

View File

@ -19,7 +19,7 @@
namespace Libraries::Kernel {
u64 PS4_SYSV_ABI sceKernelGetDirectMemorySize() {
LOG_WARNING(Kernel_Vmm, "called");
LOG_TRACE(Kernel_Vmm, "called");
const auto* memory = Core::Memory::Instance();
return memory->GetTotalDirectSize();
}
@ -79,6 +79,9 @@ s32 PS4_SYSV_ABI sceKernelAllocateMainDirectMemory(size_t len, size_t alignment,
}
s32 PS4_SYSV_ABI sceKernelCheckedReleaseDirectMemory(u64 start, size_t len) {
if (len == 0) {
return ORBIS_OK;
}
LOG_INFO(Kernel_Vmm, "called start = {:#x}, len = {:#x}", start, len);
auto* memory = Core::Memory::Instance();
memory->Free(start, len);
@ -86,6 +89,9 @@ s32 PS4_SYSV_ABI sceKernelCheckedReleaseDirectMemory(u64 start, size_t len) {
}
s32 PS4_SYSV_ABI sceKernelReleaseDirectMemory(u64 start, size_t len) {
if (len == 0) {
return ORBIS_OK;
}
auto* memory = Core::Memory::Instance();
memory->Free(start, len);
return ORBIS_OK;
@ -100,12 +106,6 @@ s32 PS4_SYSV_ABI sceKernelAvailableDirectMemorySize(u64 searchStart, u64 searchE
if (physAddrOut == nullptr || sizeOut == nullptr) {
return ORBIS_KERNEL_ERROR_EINVAL;
}
if (searchEnd > sceKernelGetDirectMemorySize()) {
return ORBIS_KERNEL_ERROR_EINVAL;
}
if (searchEnd <= searchStart) {
return ORBIS_KERNEL_ERROR_ENOMEM;
}
auto* memory = Core::Memory::Instance();
@ -507,7 +507,7 @@ s32 PS4_SYSV_ABI sceKernelConfiguredFlexibleMemorySize(u64* sizeOut) {
int PS4_SYSV_ABI sceKernelMunmap(void* addr, size_t len) {
LOG_INFO(Kernel_Vmm, "addr = {}, len = {:#x}", fmt::ptr(addr), len);
if (len == 0) {
return ORBIS_OK;
return ORBIS_KERNEL_ERROR_EINVAL;
}
auto* memory = Core::Memory::Instance();
return memory->UnmapMemory(std::bit_cast<VAddr>(addr), len);

View File

@ -32,44 +32,44 @@ void* PS4_SYSV_ABI sceKernelGetProcParam() {
return linker->GetProcParam();
}
s32 PS4_SYSV_ABI sceKernelLoadStartModule(const char* moduleFileName, size_t args, const void* argp,
s32 PS4_SYSV_ABI sceKernelLoadStartModule(const char* moduleFileName, u64 args, const void* argp,
u32 flags, const void* pOpt, int* pRes) {
LOG_INFO(Lib_Kernel, "called filename = {}, args = {}", moduleFileName, args);
if (flags != 0) {
return ORBIS_KERNEL_ERROR_EINVAL;
}
ASSERT(flags == 0);
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
const auto path = mnt->GetHostPath(moduleFileName);
// Load PRX module and relocate any modules that import it.
auto* linker = Common::Singleton<Core::Linker>::Instance();
u32 handle = linker->FindByName(path);
if (handle != -1) {
return handle;
}
handle = linker->LoadModule(path, true);
if (handle == -1) {
return ORBIS_KERNEL_ERROR_ESRCH;
}
auto* module = linker->GetModule(handle);
linker->RelocateAnyImports(module);
// If the new module has a TLS image, trigger its load when TlsGetAddr is called.
if (module->tls.image_size != 0) {
linker->AdvanceGenerationCounter();
std::filesystem::path path;
std::string guest_path(moduleFileName);
s32 handle = -1;
if (guest_path[0] == '/') {
// try load /system/common/lib/ +path
// try load /system/priv/lib/ +path
path = mnt->GetHostPath(guest_path);
handle = linker->LoadAndStartModule(path, args, argp, pRes);
if (handle != -1)
return handle;
} else {
if (!guest_path.contains('/')) {
path = mnt->GetHostPath("/app0/" + guest_path);
handle = linker->LoadAndStartModule(path, args, argp, pRes);
if (handle != -1)
return handle;
// if ((flags & 0x10000) != 0)
// try load /system/priv/lib/ +basename
// try load /system/common/lib/ +basename
} else {
path = mnt->GetHostPath(guest_path);
handle = linker->LoadAndStartModule(path, args, argp, pRes);
if (handle != -1)
return handle;
}
}
// Retrieve and verify proc param according to libkernel.
u64* param = module->GetProcParam<u64*>();
ASSERT_MSG(!param || param[0] >= 0x18, "Invalid module param size: {}", param[0]);
s32 ret = module->Start(args, argp, param);
if (pRes) {
*pRes = ret;
}
return handle;
return ORBIS_KERNEL_ERROR_ENOENT;
}
s32 PS4_SYSV_ABI sceKernelDlsym(s32 handle, const char* symbol, void** addrp) {
@ -85,19 +85,7 @@ s32 PS4_SYSV_ABI sceKernelDlsym(s32 handle, const char* symbol, void** addrp) {
return ORBIS_OK;
}
static constexpr size_t ORBIS_DBG_MAX_NAME_LENGTH = 256;
struct OrbisModuleInfoForUnwind {
u64 st_size;
std::array<char, ORBIS_DBG_MAX_NAME_LENGTH> name;
VAddr eh_frame_hdr_addr;
VAddr eh_frame_addr;
u64 eh_frame_size;
VAddr seg0_addr;
u64 seg0_size;
};
s32 PS4_SYSV_ABI sceKernelGetModuleInfoForUnwind(VAddr addr, int flags,
s32 PS4_SYSV_ABI sceKernelGetModuleInfoForUnwind(VAddr addr, s32 flags,
OrbisModuleInfoForUnwind* info) {
if (flags >= 3) {
std::memset(info, 0, sizeof(OrbisModuleInfoForUnwind));
@ -139,6 +127,67 @@ int PS4_SYSV_ABI sceKernelGetModuleInfoFromAddr(VAddr addr, int flags,
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceKernelGetModuleInfo(s32 handle, Core::OrbisKernelModuleInfo* info) {
if (info == nullptr) {
return ORBIS_KERNEL_ERROR_EFAULT;
}
if (info->st_size != sizeof(Core::OrbisKernelModuleInfo)) {
return ORBIS_KERNEL_ERROR_EINVAL;
}
auto* linker = Common::Singleton<Core::Linker>::Instance();
auto* module = linker->GetModule(handle);
if (module == nullptr) {
return ORBIS_KERNEL_ERROR_ESRCH;
}
*info = module->GetModuleInfo();
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceKernelGetModuleInfoInternal(s32 handle, Core::OrbisKernelModuleInfoEx* info) {
if (info == nullptr) {
return ORBIS_KERNEL_ERROR_EFAULT;
}
if (info->st_size != sizeof(Core::OrbisKernelModuleInfoEx)) {
return ORBIS_KERNEL_ERROR_EINVAL;
}
auto* linker = Common::Singleton<Core::Linker>::Instance();
auto* module = linker->GetModule(handle);
if (module == nullptr) {
return ORBIS_KERNEL_ERROR_ESRCH;
}
*info = module->GetModuleInfoEx();
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceKernelGetModuleList(s32* handles, u64 num_array, u64* out_count) {
if (handles == nullptr || out_count == nullptr) {
return ORBIS_KERNEL_ERROR_EFAULT;
}
auto* linker = Common::Singleton<Core::Linker>::Instance();
u64 count = 0;
auto* module = linker->GetModule(count);
while (module != nullptr && count < num_array) {
handles[count] = count;
count++;
module = linker->GetModule(count);
}
if (count == num_array && module != nullptr) {
return ORBIS_KERNEL_ERROR_ENOMEM;
}
*out_count = count;
return ORBIS_OK;
}
s32 PS4_SYSV_ABI exit(s32 status) {
UNREACHABLE_MSG("Exiting with status code {}", status);
return 0;
}
void RegisterProcess(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("WB66evu8bsU", "libkernel", 1, "libkernel", 1, 1, sceKernelGetCompiledSdkVersion);
LIB_FUNCTION("WslcK1FQcGI", "libkernel", 1, "libkernel", 1, 1, sceKernelIsNeoMode);
@ -148,6 +197,10 @@ void RegisterProcess(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("LwG8g3niqwA", "libkernel", 1, "libkernel", 1, 1, sceKernelDlsym);
LIB_FUNCTION("RpQJJVKTiFM", "libkernel", 1, "libkernel", 1, 1, sceKernelGetModuleInfoForUnwind);
LIB_FUNCTION("f7KBOafysXo", "libkernel", 1, "libkernel", 1, 1, sceKernelGetModuleInfoFromAddr);
LIB_FUNCTION("kUpgrXIrz7Q", "libkernel", 1, "libkernel", 1, 1, sceKernelGetModuleInfo);
LIB_FUNCTION("HZO7xOos4xc", "libkernel", 1, "libkernel", 1, 1, sceKernelGetModuleInfoInternal);
LIB_FUNCTION("IuxnUuXk6Bg", "libkernel", 1, "libkernel", 1, 1, sceKernelGetModuleList);
LIB_FUNCTION("6Z83sYWFlA8", "libkernel", 1, "libkernel", 1, 1, exit);
}
} // namespace Libraries::Kernel

View File

@ -11,10 +11,25 @@ class SymbolsResolver;
namespace Libraries::Kernel {
static constexpr size_t ORBIS_DBG_MAX_NAME_LENGTH = 256;
struct OrbisModuleInfoForUnwind {
u64 st_size;
std::array<char, ORBIS_DBG_MAX_NAME_LENGTH> name;
VAddr eh_frame_hdr_addr;
VAddr eh_frame_addr;
u64 eh_frame_size;
VAddr seg0_addr;
u64 seg0_size;
};
int PS4_SYSV_ABI sceKernelIsNeoMode();
int PS4_SYSV_ABI sceKernelGetCompiledSdkVersion(int* ver);
s32 PS4_SYSV_ABI sceKernelGetModuleInfoForUnwind(VAddr addr, s32 flags,
OrbisModuleInfoForUnwind* info);
void RegisterProcess(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::Kernel

View File

@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/assert.h"
#include "core/libraries/kernel/orbis_error.h"
#include "core/libraries/kernel/threads/exception.h"
#include "core/libraries/kernel/threads/pthread.h"
#include "core/libraries/libs.h"
@ -148,13 +149,19 @@ int PS4_SYSV_ABI sceKernelRaiseException(PthreadT thread, int signum) {
return 0;
}
int PS4_SYSV_ABI sceKernelDebugRaiseException() {
UNREACHABLE();
s32 PS4_SYSV_ABI sceKernelDebugRaiseException(s32 error, s64 unk) {
if (unk != 0) {
return ORBIS_KERNEL_ERROR_EINVAL;
}
UNREACHABLE_MSG("error {:#x}", error);
return 0;
}
int PS4_SYSV_ABI sceKernelDebugRaiseExceptionOnReleaseMode() {
UNREACHABLE();
s32 PS4_SYSV_ABI sceKernelDebugRaiseExceptionOnReleaseMode(s32 error, s64 unk) {
if (unk != 0) {
return ORBIS_KERNEL_ERROR_EINVAL;
}
UNREACHABLE_MSG("error {:#x}", error);
return 0;
}
@ -163,7 +170,7 @@ void RegisterException(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("WkwEd3N7w0Y", "libkernel_unity", 1, "libkernel", 1, 1,
sceKernelInstallExceptionHandler);
LIB_FUNCTION("Qhv5ARAoOEc", "libkernel_unity", 1, "libkernel", 1, 1,
sceKernelRemoveExceptionHandler)
sceKernelRemoveExceptionHandler);
LIB_FUNCTION("OMDRKKAZ8I4", "libkernel", 1, "libkernel", 1, 1, sceKernelDebugRaiseException);
LIB_FUNCTION("zE-wXIZjLoM", "libkernel", 1, "libkernel", 1, 1,
sceKernelDebugRaiseExceptionOnReleaseMode);

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