mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-05-14 08:12:16 +00:00
Compare commits
87 commits
Author | SHA1 | Date | |
---|---|---|---|
|
26c965cf4a | ||
|
99eaba7c96 | ||
|
1639640902 | ||
|
647b1d3ee4 | ||
|
6abda17532 | ||
|
3ab69e24db | ||
|
073f931729 | ||
|
0d127a82dd | ||
|
e5b675d607 | ||
|
1832ec2ac2 | ||
|
484fbcc320 | ||
|
7334fb620b | ||
|
f97c0deea9 | ||
|
4cd13ea9d8 | ||
|
e6a144ddb0 | ||
|
3a10fda008 | ||
|
2a3a701115 | ||
|
6bbb424c28 | ||
|
3a3a6d8e45 | ||
|
b23f6fdc1d | ||
|
9baa58dd92 | ||
|
5ab5fa7024 | ||
|
b3abb83fc5 | ||
|
f94c7e52b7 | ||
|
8909d9bb89 | ||
|
678f18ddb9 | ||
|
02d3ed4973 | ||
|
6206986914 | ||
|
c0562a6b1b | ||
|
3a090e988c | ||
|
ff1339b0b6 | ||
|
afcf3a12a3 | ||
|
6ece91c763 | ||
|
7eea1fc4d6 | ||
|
c6ea7d8f76 | ||
|
6477dc4f1e | ||
|
a1439b15cf | ||
|
8d7cbf9943 | ||
|
b130fe6ed5 | ||
|
8e7c5a4d99 | ||
|
46b88bd10f | ||
|
58df609ba0 | ||
|
3b7c36e1ba | ||
|
1aa7eb8a42 | ||
|
c7fb3ebd93 | ||
|
fed064931a | ||
|
9a22185ab7 | ||
|
17b6343f18 | ||
|
d542d952f4 | ||
|
0ba9ea6a3b | ||
|
eb09c4ccce | ||
|
6c39bf229c | ||
|
b0e4e87ff3 | ||
|
4202d9d621 | ||
|
5fd5b62539 | ||
|
10b24d04bc | ||
|
c47d9b2ad6 | ||
|
ede60e8f7f | ||
|
c08f92aca1 | ||
|
a3bbf2274f | ||
|
bb59cd81fa | ||
|
53b2ccffca | ||
|
fa9f58446f | ||
|
5e3157a82c | ||
|
beb9c86749 | ||
|
81fa9b7fff | ||
|
385c5a4507 | ||
|
59d060bc16 | ||
|
83fd0683fa | ||
|
81ad31ce31 | ||
|
ff984d3cde | ||
|
b505829e16 | ||
|
254375ef0c | ||
|
cef795b80b | ||
|
410313ca87 | ||
|
c09fff2da6 | ||
|
e816bc4b99 | ||
|
632ed99ee7 | ||
|
15d6a45dcd | ||
|
d370ea32f4 | ||
|
c01590175a | ||
|
a12d447bd6 | ||
|
ce3aded3e5 | ||
|
4ecdcf77d1 | ||
|
3f4249084c | ||
|
aeee7706ee | ||
|
5db162cbcd |
134 changed files with 5548 additions and 1080 deletions
28
.github/workflows/build.yml
vendored
28
.github/workflows/build.yml
vendored
|
@ -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
|
||||
|
@ -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)
|
||||
|
|
65
CMakeLists.txt
Executable file → Normal file
65
CMakeLists.txt
Executable file → Normal file
|
@ -203,12 +203,12 @@ execute_process(
|
|||
# Set Version
|
||||
set(EMULATOR_VERSION_MAJOR "0")
|
||||
set(EMULATOR_VERSION_MINOR "8")
|
||||
set(EMULATOR_VERSION_PATCH "0")
|
||||
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}")
|
||||
set(APP_IS_RELEASE true)
|
||||
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}")
|
||||
|
@ -371,11 +371,19 @@ set(NETWORK_LIBS src/core/libraries/network/http.cpp
|
|||
src/core/libraries/network/net_ctl_obj.cpp
|
||||
src/core/libraries/network/net_ctl_obj.h
|
||||
src/core/libraries/network/net_ctl_codes.h
|
||||
src/core/libraries/network/net_util.cpp
|
||||
src/core/libraries/network/net_util.h
|
||||
src/core/libraries/network/net_error.h
|
||||
src/core/libraries/network/net.h
|
||||
src/core/libraries/network/ssl.cpp
|
||||
src/core/libraries/network/ssl.h
|
||||
src/core/libraries/network/ssl2.cpp
|
||||
src/core/libraries/network/ssl2.h
|
||||
src/core/libraries/network/sys_net.cpp
|
||||
src/core/libraries/network/sys_net.h
|
||||
src/core/libraries/network/posix_sockets.cpp
|
||||
src/core/libraries/network/p2p_sockets.cpp
|
||||
src/core/libraries/network/sockets.h
|
||||
)
|
||||
|
||||
set(AVPLAYER_LIB src/core/libraries/avplayer/avplayer_common.cpp
|
||||
|
@ -589,6 +597,13 @@ set(MISC_LIBS src/core/libraries/screenshot/screenshot.cpp
|
|||
src/core/libraries/move/move.h
|
||||
src/core/libraries/ulobjmgr/ulobjmgr.cpp
|
||||
src/core/libraries/ulobjmgr/ulobjmgr.h
|
||||
src/core/libraries/signin_dialog/signindialog.cpp
|
||||
src/core/libraries/signin_dialog/signindialog.h
|
||||
)
|
||||
|
||||
set(CAMERA_LIBS src/core/libraries/camera/camera.cpp
|
||||
src/core/libraries/camera/camera.h
|
||||
src/core/libraries/camera/camera_error.h
|
||||
)
|
||||
|
||||
set(DEV_TOOLS src/core/devtools/layer.cpp
|
||||
|
@ -754,6 +769,7 @@ set(CORE src/core/aerolib/stubs.cpp
|
|||
${FIBER_LIB}
|
||||
${VDEC_LIB}
|
||||
${VR_LIBS}
|
||||
${CAMERA_LIBS}
|
||||
${DEV_TOOLS}
|
||||
src/core/debug_state.cpp
|
||||
src/core/debug_state.h
|
||||
|
@ -840,6 +856,7 @@ 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
|
||||
|
@ -1077,40 +1094,42 @@ if (ENABLE_DISCORD_RPC)
|
|||
target_compile_definitions(shadps4 PRIVATE ENABLE_DISCORD_RPC)
|
||||
endif()
|
||||
|
||||
# Optional due to https://github.com/shadps4-emu/shadPS4/issues/1704
|
||||
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" AND ENABLE_USERFAULTFD)
|
||||
target_compile_definitions(shadps4 PRIVATE ENABLE_USERFAULTFD)
|
||||
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||
# Optional due to https://github.com/shadps4-emu/shadPS4/issues/1704
|
||||
if (ENABLE_USERFAULTFD)
|
||||
target_compile_definitions(shadps4 PRIVATE ENABLE_USERFAULTFD)
|
||||
endif()
|
||||
|
||||
target_link_libraries(shadps4 PRIVATE uuid)
|
||||
endif()
|
||||
|
||||
if (APPLE)
|
||||
# Include MoltenVK, along with an ICD file so it can be found by the system Vulkan loader if used for loading layers.
|
||||
set(MVK_DYLIB_SRC ${CMAKE_CURRENT_BINARY_DIR}/externals/MoltenVK/libMoltenVK.dylib)
|
||||
|
||||
if (ENABLE_QT_GUI)
|
||||
set_property(TARGET shadps4 APPEND PROPERTY BUILD_RPATH "@executable_path/../Frameworks")
|
||||
set(MVK_ICD_DST ${CMAKE_CURRENT_BINARY_DIR}/shadps4.app/Contents/Resources/vulkan/icd.d/MoltenVK_icd.json)
|
||||
set(MVK_DYLIB_DST ${CMAKE_CURRENT_BINARY_DIR}/shadps4.app/Contents/Frameworks/libMoltenVK.dylib)
|
||||
set(MVK_DYLIB_ICD_PATH "../../../Frameworks/libMoltenVK.dylib")
|
||||
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_ICD_DST ${CMAKE_CURRENT_BINARY_DIR}/MoltenVK_icd.json)
|
||||
set(MVK_DYLIB_DST ${CMAKE_CURRENT_BINARY_DIR}/libMoltenVK.dylib)
|
||||
set(MVK_DYLIB_ICD_PATH "./libMoltenVK.dylib")
|
||||
set(MVK_DST ${CMAKE_CURRENT_BINARY_DIR})
|
||||
endif()
|
||||
|
||||
cmake_path(GET MVK_ICD_DST PARENT_PATH MVK_ICD_DST_PARENT)
|
||||
cmake_path(GET MVK_DYLIB_DST PARENT_PATH MVK_DYLIB_DST_PARENT)
|
||||
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)
|
||||
|
||||
set(MVK_ICD "\\\{ \\\"file_format_version\\\": \\\"1.0.0\\\", \\\"ICD\\\": \\\{ \\\"library_path\\\": \\\"${MVK_DYLIB_ICD_PATH}\\\", \\\"api_version\\\": \\\"1.2.0\\\", \\\"is_portability_driver\\\": true \\\} \\\}")
|
||||
add_custom_command(
|
||||
OUTPUT ${MVK_DST}
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${MVK_DST})
|
||||
add_custom_command(
|
||||
OUTPUT ${MVK_ICD_DST}
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${MVK_ICD_DST_PARENT} && ${CMAKE_COMMAND} -E echo ${MVK_ICD} > ${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}
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${MVK_DYLIB_DST_PARENT} && ${CMAKE_COMMAND} -E copy ${MVK_DYLIB_SRC} ${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)
|
||||
|
|
2
externals/MoltenVK/MoltenVK
vendored
2
externals/MoltenVK/MoltenVK
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 4cf8f94684c53e581eb9cc694dd3305d1f7d9959
|
||||
Subproject commit 87a8e8b13d4ad8835367fea1ebad1896d0460946
|
2
externals/MoltenVK/SPIRV-Cross
vendored
2
externals/MoltenVK/SPIRV-Cross
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 2275d0efc4f2fa46851035d9d3c67c105bc8b99e
|
||||
Subproject commit 7918775748c5e2f5c40d9918ce68825035b5a1e1
|
2
externals/sdl3
vendored
2
externals/sdl3
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 4093e4a193971ef1d4928158e0a1832be42e4599
|
||||
Subproject commit 86b206dadf8ad40e6657fa37db371a0aeff74e9c
|
2
externals/sirit
vendored
2
externals/sirit
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 427a42c9ed99b38204d9107bc3dc14e92458acf1
|
||||
Subproject commit 09a1416ab1b59ddfebd2618412f118f2004f3b2c
|
|
@ -131,9 +131,7 @@ namespace {
|
|||
case SeekOrigin::End:
|
||||
return SEEK_END;
|
||||
default:
|
||||
LOG_ERROR(Common_Filesystem, "Unsupported origin {}, defaulting to SEEK_SET",
|
||||
static_cast<u32>(origin));
|
||||
return SEEK_SET;
|
||||
UNREACHABLE_MSG("Impossible SeekOrigin {}", static_cast<u32>(origin));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -61,8 +61,6 @@ 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 {
|
||||
|
|
|
@ -137,6 +137,8 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
|
|||
SUB(Lib, NpParty) \
|
||||
SUB(Lib, Zlib) \
|
||||
SUB(Lib, Hmd) \
|
||||
SUB(Lib, SigninDialog) \
|
||||
SUB(Lib, Camera) \
|
||||
CLS(Frontend) \
|
||||
CLS(Render) \
|
||||
SUB(Render, Vulkan) \
|
||||
|
|
|
@ -104,6 +104,8 @@ enum class Class : u8 {
|
|||
Lib_NpParty, ///< The LibSceNpParty implementation
|
||||
Lib_Zlib, ///< The LibSceZlib implementation.
|
||||
Lib_Hmd, ///< The LibSceHmd implementation.
|
||||
Lib_SigninDialog, ///< The LibSigninDialog implementation.
|
||||
Lib_Camera, ///< The LibCamera implementation.
|
||||
Frontend, ///< Emulator UI
|
||||
Render, ///< Video Core
|
||||
Render_Vulkan, ///< Vulkan backend
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
namespace MemoryPatcher {
|
||||
|
||||
uintptr_t g_eboot_address;
|
||||
EXPORT uintptr_t g_eboot_address;
|
||||
uint64_t g_eboot_image_size;
|
||||
std::string g_game_serial;
|
||||
std::string patchFile;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,9 +6,15 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#if defined(WIN32)
|
||||
#define EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define EXPORT __attribute__((visibility("default")))
|
||||
#endif
|
||||
|
||||
namespace MemoryPatcher {
|
||||
|
||||
extern uintptr_t g_eboot_address;
|
||||
extern EXPORT uintptr_t g_eboot_address;
|
||||
extern uint64_t g_eboot_image_size;
|
||||
extern std::string g_game_serial;
|
||||
extern std::string patchFile;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
#define VA_ARGS \
|
||||
uint64_t rdi, uint64_t rsi, uint64_t rdx, uint64_t rcx, uint64_t r8, uint64_t r9, \
|
||||
uint64_t overflow_arg_area, __m128 xmm0, __m128 xmm1, __m128 xmm2, __m128 xmm3, \
|
||||
__m128 xmm4, __m128 xmm5, __m128 xmm6, __m128 xmm7, ...
|
||||
__m128 xmm4, __m128 xmm5, __m128 xmm6, __m128 xmm7
|
||||
|
||||
#define VA_CTX(ctx) \
|
||||
alignas(16)::Common::VaCtx ctx{}; \
|
||||
|
|
|
@ -19,8 +19,6 @@ enum class MemoryPermission : u32 {
|
|||
};
|
||||
DECLARE_ENUM_FLAG_OPERATORS(MemoryPermission)
|
||||
|
||||
constexpr VAddr CODE_BASE_OFFSET = 0x100000000ULL;
|
||||
|
||||
constexpr VAddr SYSTEM_MANAGED_MIN = 0x00000400000ULL;
|
||||
constexpr VAddr SYSTEM_MANAGED_MAX = 0x07FFFFBFFFULL;
|
||||
constexpr VAddr SYSTEM_RESERVED_MIN = 0x07FFFFC000ULL;
|
||||
|
|
|
@ -464,9 +464,8 @@ static std::pair<bool, u64> TryPatch(u8* code, PatchModule* module) {
|
|||
|
||||
if (needs_trampoline && instruction.length < 5) {
|
||||
// Trampoline is needed but instruction is too short to patch.
|
||||
// Return false and length to fall back to the illegal instruction handler,
|
||||
// or to signal to AOT compilation that this instruction should be skipped and
|
||||
// handled at runtime.
|
||||
// Return false and length to signal to AOT compilation that this instruction
|
||||
// should be skipped and handled at runtime.
|
||||
return std::make_pair(false, instruction.length);
|
||||
}
|
||||
|
||||
|
@ -512,136 +511,137 @@ static std::pair<bool, u64> TryPatch(u8* code, PatchModule* module) {
|
|||
|
||||
#if defined(ARCH_X86_64)
|
||||
|
||||
static bool Is4ByteExtrqOrInsertq(void* code_address) {
|
||||
u8* bytes = (u8*)code_address;
|
||||
if (bytes[0] == 0x66 && bytes[1] == 0x0F && bytes[2] == 0x79) {
|
||||
return true; // extrq
|
||||
} else if (bytes[0] == 0xF2 && bytes[1] == 0x0F && bytes[2] == 0x79) {
|
||||
return true; // insertq
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool TryExecuteIllegalInstruction(void* ctx, void* code_address) {
|
||||
ZydisDecodedInstruction instruction;
|
||||
ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT];
|
||||
const auto status =
|
||||
Common::Decoder::Instance()->decodeInstruction(instruction, operands, code_address);
|
||||
// We need to decode the instruction to find out what it is. Normally we'd use a fully fleshed
|
||||
// out decoder like Zydis, however Zydis does a bunch of stuff that impact performance that we
|
||||
// don't care about. We can get information about the instruction a lot faster by writing a mini
|
||||
// decoder here, since we know it is definitely an extrq or an insertq. If for some reason we
|
||||
// need to interpret more instructions in the future (I don't see why we would), we can revert
|
||||
// to using Zydis.
|
||||
ZydisMnemonic mnemonic;
|
||||
u8* bytes = (u8*)code_address;
|
||||
if (bytes[0] == 0x66) {
|
||||
mnemonic = ZYDIS_MNEMONIC_EXTRQ;
|
||||
} else if (bytes[0] == 0xF2) {
|
||||
mnemonic = ZYDIS_MNEMONIC_INSERTQ;
|
||||
} else {
|
||||
ZydisDecodedInstruction instruction;
|
||||
ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT];
|
||||
const auto status =
|
||||
Common::Decoder::Instance()->decodeInstruction(instruction, operands, code_address);
|
||||
LOG_ERROR(Core, "Unhandled illegal instruction at code address {}: {}",
|
||||
fmt::ptr(code_address),
|
||||
ZYAN_SUCCESS(status) ? ZydisMnemonicGetString(instruction.mnemonic)
|
||||
: "Failed to decode");
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (instruction.mnemonic) {
|
||||
ASSERT(bytes[1] == 0x0F && bytes[2] == 0x79);
|
||||
|
||||
// Note: It's guaranteed that there's no REX prefix in these instructions checked by
|
||||
// Is4ByteExtrqOrInsertq
|
||||
u8 modrm = bytes[3];
|
||||
u8 rm = modrm & 0b111;
|
||||
u8 reg = (modrm >> 3) & 0b111;
|
||||
u8 mod = (modrm >> 6) & 0b11;
|
||||
|
||||
ASSERT(mod == 0b11); // Any instruction we interpret here uses reg/reg addressing only
|
||||
|
||||
int dstIndex = reg;
|
||||
int srcIndex = rm;
|
||||
|
||||
switch (mnemonic) {
|
||||
case ZYDIS_MNEMONIC_EXTRQ: {
|
||||
bool immediateForm = operands[1].type == ZYDIS_OPERAND_TYPE_IMMEDIATE &&
|
||||
operands[2].type == ZYDIS_OPERAND_TYPE_IMMEDIATE;
|
||||
if (immediateForm) {
|
||||
LOG_CRITICAL(Core, "EXTRQ immediate form should have been patched at code address: {}",
|
||||
fmt::ptr(code_address));
|
||||
return false;
|
||||
const auto dst = Common::GetXmmPointer(ctx, dstIndex);
|
||||
const auto src = Common::GetXmmPointer(ctx, srcIndex);
|
||||
|
||||
u64 lowQWordSrc;
|
||||
memcpy(&lowQWordSrc, src, sizeof(lowQWordSrc));
|
||||
|
||||
u64 lowQWordDst;
|
||||
memcpy(&lowQWordDst, dst, sizeof(lowQWordDst));
|
||||
|
||||
u64 length = lowQWordSrc & 0x3F;
|
||||
u64 mask;
|
||||
if (length == 0) {
|
||||
length = 64; // for the check below
|
||||
mask = 0xFFFF'FFFF'FFFF'FFFF;
|
||||
} else {
|
||||
ASSERT_MSG(operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER &&
|
||||
operands[1].type == ZYDIS_OPERAND_TYPE_REGISTER &&
|
||||
operands[0].reg.value >= ZYDIS_REGISTER_XMM0 &&
|
||||
operands[0].reg.value <= ZYDIS_REGISTER_XMM15 &&
|
||||
operands[1].reg.value >= ZYDIS_REGISTER_XMM0 &&
|
||||
operands[1].reg.value <= ZYDIS_REGISTER_XMM15,
|
||||
"Unexpected operand types for EXTRQ instruction");
|
||||
|
||||
const auto dstIndex = operands[0].reg.value - ZYDIS_REGISTER_XMM0;
|
||||
const auto srcIndex = operands[1].reg.value - ZYDIS_REGISTER_XMM0;
|
||||
|
||||
const auto dst = Common::GetXmmPointer(ctx, dstIndex);
|
||||
const auto src = Common::GetXmmPointer(ctx, srcIndex);
|
||||
|
||||
u64 lowQWordSrc;
|
||||
memcpy(&lowQWordSrc, src, sizeof(lowQWordSrc));
|
||||
|
||||
u64 lowQWordDst;
|
||||
memcpy(&lowQWordDst, dst, sizeof(lowQWordDst));
|
||||
|
||||
u64 length = lowQWordSrc & 0x3F;
|
||||
u64 mask;
|
||||
if (length == 0) {
|
||||
length = 64; // for the check below
|
||||
mask = 0xFFFF'FFFF'FFFF'FFFF;
|
||||
} else {
|
||||
mask = (1ULL << length) - 1;
|
||||
}
|
||||
|
||||
u64 index = (lowQWordSrc >> 8) & 0x3F;
|
||||
if (length + index > 64) {
|
||||
// Undefined behavior if length + index is bigger than 64 according to the spec,
|
||||
// we'll warn and continue execution.
|
||||
LOG_TRACE(Core,
|
||||
"extrq at {} with length {} and index {} is bigger than 64, "
|
||||
"undefined behavior",
|
||||
fmt::ptr(code_address), length, index);
|
||||
}
|
||||
|
||||
lowQWordDst >>= index;
|
||||
lowQWordDst &= mask;
|
||||
|
||||
memcpy(dst, &lowQWordDst, sizeof(lowQWordDst));
|
||||
|
||||
Common::IncrementRip(ctx, instruction.length);
|
||||
|
||||
return true;
|
||||
mask = (1ULL << length) - 1;
|
||||
}
|
||||
break;
|
||||
|
||||
u64 index = (lowQWordSrc >> 8) & 0x3F;
|
||||
if (length + index > 64) {
|
||||
// Undefined behavior if length + index is bigger than 64 according to the spec,
|
||||
// we'll warn and continue execution.
|
||||
LOG_TRACE(Core,
|
||||
"extrq at {} with length {} and index {} is bigger than 64, "
|
||||
"undefined behavior",
|
||||
fmt::ptr(code_address), length, index);
|
||||
}
|
||||
|
||||
lowQWordDst >>= index;
|
||||
lowQWordDst &= mask;
|
||||
|
||||
memcpy(dst, &lowQWordDst, sizeof(lowQWordDst));
|
||||
|
||||
Common::IncrementRip(ctx, 4);
|
||||
|
||||
return true;
|
||||
}
|
||||
case ZYDIS_MNEMONIC_INSERTQ: {
|
||||
bool immediateForm = operands[2].type == ZYDIS_OPERAND_TYPE_IMMEDIATE &&
|
||||
operands[3].type == ZYDIS_OPERAND_TYPE_IMMEDIATE;
|
||||
if (immediateForm) {
|
||||
LOG_CRITICAL(Core,
|
||||
"INSERTQ immediate form should have been patched at code address: {}",
|
||||
fmt::ptr(code_address));
|
||||
return false;
|
||||
const auto dst = Common::GetXmmPointer(ctx, dstIndex);
|
||||
const auto src = Common::GetXmmPointer(ctx, srcIndex);
|
||||
|
||||
u64 lowQWordSrc, highQWordSrc;
|
||||
memcpy(&lowQWordSrc, src, sizeof(lowQWordSrc));
|
||||
memcpy(&highQWordSrc, (u8*)src + 8, sizeof(highQWordSrc));
|
||||
|
||||
u64 lowQWordDst;
|
||||
memcpy(&lowQWordDst, dst, sizeof(lowQWordDst));
|
||||
|
||||
u64 length = highQWordSrc & 0x3F;
|
||||
u64 mask;
|
||||
if (length == 0) {
|
||||
length = 64; // for the check below
|
||||
mask = 0xFFFF'FFFF'FFFF'FFFF;
|
||||
} else {
|
||||
ASSERT_MSG(operands[2].type == ZYDIS_OPERAND_TYPE_UNUSED &&
|
||||
operands[3].type == ZYDIS_OPERAND_TYPE_UNUSED,
|
||||
"operands 2 and 3 must be unused for register form.");
|
||||
|
||||
ASSERT_MSG(operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER &&
|
||||
operands[1].type == ZYDIS_OPERAND_TYPE_REGISTER,
|
||||
"operands 0 and 1 must be registers.");
|
||||
|
||||
const auto dstIndex = operands[0].reg.value - ZYDIS_REGISTER_XMM0;
|
||||
const auto srcIndex = operands[1].reg.value - ZYDIS_REGISTER_XMM0;
|
||||
|
||||
const auto dst = Common::GetXmmPointer(ctx, dstIndex);
|
||||
const auto src = Common::GetXmmPointer(ctx, srcIndex);
|
||||
|
||||
u64 lowQWordSrc, highQWordSrc;
|
||||
memcpy(&lowQWordSrc, src, sizeof(lowQWordSrc));
|
||||
memcpy(&highQWordSrc, (u8*)src + 8, sizeof(highQWordSrc));
|
||||
|
||||
u64 lowQWordDst;
|
||||
memcpy(&lowQWordDst, dst, sizeof(lowQWordDst));
|
||||
|
||||
u64 length = highQWordSrc & 0x3F;
|
||||
u64 mask;
|
||||
if (length == 0) {
|
||||
length = 64; // for the check below
|
||||
mask = 0xFFFF'FFFF'FFFF'FFFF;
|
||||
} else {
|
||||
mask = (1ULL << length) - 1;
|
||||
}
|
||||
|
||||
u64 index = (highQWordSrc >> 8) & 0x3F;
|
||||
if (length + index > 64) {
|
||||
// Undefined behavior if length + index is bigger than 64 according to the spec,
|
||||
// we'll warn and continue execution.
|
||||
LOG_TRACE(Core,
|
||||
"insertq at {} with length {} and index {} is bigger than 64, "
|
||||
"undefined behavior",
|
||||
fmt::ptr(code_address), length, index);
|
||||
}
|
||||
|
||||
lowQWordSrc &= mask;
|
||||
lowQWordDst &= ~(mask << index);
|
||||
lowQWordDst |= lowQWordSrc << index;
|
||||
|
||||
memcpy(dst, &lowQWordDst, sizeof(lowQWordDst));
|
||||
|
||||
Common::IncrementRip(ctx, instruction.length);
|
||||
|
||||
return true;
|
||||
mask = (1ULL << length) - 1;
|
||||
}
|
||||
break;
|
||||
|
||||
u64 index = (highQWordSrc >> 8) & 0x3F;
|
||||
if (length + index > 64) {
|
||||
// Undefined behavior if length + index is bigger than 64 according to the spec,
|
||||
// we'll warn and continue execution.
|
||||
LOG_TRACE(Core,
|
||||
"insertq at {} with length {} and index {} is bigger than 64, "
|
||||
"undefined behavior",
|
||||
fmt::ptr(code_address), length, index);
|
||||
}
|
||||
|
||||
lowQWordSrc &= mask;
|
||||
lowQWordDst &= ~(mask << index);
|
||||
lowQWordDst |= lowQWordSrc << index;
|
||||
|
||||
memcpy(dst, &lowQWordDst, sizeof(lowQWordDst));
|
||||
|
||||
Common::IncrementRip(ctx, 4);
|
||||
|
||||
return true;
|
||||
}
|
||||
default: {
|
||||
LOG_ERROR(Core, "Unhandled illegal instruction at code address {}: {}",
|
||||
fmt::ptr(code_address), ZydisMnemonicGetString(instruction.mnemonic));
|
||||
return false;
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -695,9 +695,22 @@ static bool PatchesAccessViolationHandler(void* context, void* /* fault_address
|
|||
|
||||
static bool PatchesIllegalInstructionHandler(void* context) {
|
||||
void* code_address = Common::GetRip(context);
|
||||
if (!TryPatchJit(code_address)) {
|
||||
if (Is4ByteExtrqOrInsertq(code_address)) {
|
||||
// The instruction is not big enough for a relative jump, don't try to patch it and pass it
|
||||
// to our illegal instruction interpreter directly
|
||||
return TryExecuteIllegalInstruction(context, code_address);
|
||||
} else {
|
||||
if (!TryPatchJit(code_address)) {
|
||||
ZydisDecodedInstruction instruction;
|
||||
ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT];
|
||||
const auto status =
|
||||
Common::Decoder::Instance()->decodeInstruction(instruction, operands, code_address);
|
||||
LOG_ERROR(Core, "Failed to patch address {:x} -- mnemonic: {}", (u64)code_address,
|
||||
ZYAN_SUCCESS(status) ? ZydisMnemonicGetString(instruction.mnemonic)
|
||||
: "Failed to decode");
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include "common/logging/log.h"
|
||||
#include "random_device.h"
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include "common/logging/log.h"
|
||||
#include "srandom_device.h"
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include "common/logging/log.h"
|
||||
#include "urandom_device.h"
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "SDL3/SDL_log.h"
|
||||
#include "layer.h"
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
#include "SDL3/SDL_log.h"
|
||||
#include "common/config.h"
|
||||
#include "common/singleton.h"
|
||||
#include "common/types.h"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <cstdio>
|
||||
#include <ctime>
|
||||
#include <fmt/chrono.h>
|
||||
#include <imgui.h>
|
||||
#include <magic_enum/magic_enum.hpp>
|
||||
|
|
517
src/core/libraries/camera/camera.cpp
Normal file
517
src/core/libraries/camera/camera.cpp
Normal file
|
@ -0,0 +1,517 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/libraries/camera/camera.h"
|
||||
#include "core/libraries/camera/camera_error.h"
|
||||
#include "core/libraries/error_codes.h"
|
||||
#include "core/libraries/libs.h"
|
||||
|
||||
namespace Libraries::Camera {
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraAccGetData() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraAudioClose() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraAudioGetData() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraAudioGetData2() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraAudioOpen() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraAudioReset() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraChangeAppModuleState() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraClose(s32 handle) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraCloseByHandle() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraDeviceOpen() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetAttribute(s32 handle, OrbisCameraAttribute* pAttribute) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetAutoExposureGain(s32 handle, OrbisCameraChannel channel, u32* pEnable,
|
||||
void* pOption) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetAutoWhiteBalance(s32 handle, OrbisCameraChannel channel, u32* pEnable,
|
||||
void* pOption) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetCalibData() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetCalibDataFromDevice() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetCalibrationData() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetConfig(s32 handle, OrbisCameraConfig* pConfig) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetContrast(s32 handle, OrbisCameraChannel channel, u32* pContrast,
|
||||
void* pOption) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetDefectivePixelCancellation(s32 handle, OrbisCameraChannel channel,
|
||||
u32* pEnable, void* pOption) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetDeviceConfig() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetDeviceConfigWithoutHandle() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetDeviceID() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetDeviceIDWithoutOpen() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetDeviceInfo(s32 reserved, OrbisCameraDeviceInfo* pDeviceInfo) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetExposureGain(s32 handle, OrbisCameraChannel channel,
|
||||
OrbisCameraExposureGain* pExposureGain, void* pOption) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetFrameData(int handle, OrbisCameraFrameData* pFrameData) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetGamma(s32 handle, OrbisCameraChannel channel, OrbisCameraGamma* pGamma,
|
||||
void* pOption) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetHue(s32 handle, OrbisCameraChannel channel, s32* pHue, void* pOption) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetLensCorrection(s32 handle, OrbisCameraChannel channel, u32* pEnable,
|
||||
void* pOption) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetMmapConnectedCount() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetProductInfo() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetRegister() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetRegistryInfo() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetSaturation(s32 handle, OrbisCameraChannel channel, u32* pSaturation,
|
||||
void* pOption) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetSharpness(s32 handle, OrbisCameraChannel channel, u32* pSharpness,
|
||||
void* pOption) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetVrCaptureInfo() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraGetWhiteBalance(s32 handle, OrbisCameraChannel channel,
|
||||
OrbisCameraWhiteBalance* pWhiteBalance, void* pOption) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraInitializeRegistryCalibData() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraIsAttached(s32 index) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraIsConfigChangeDone() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraIsValidFrameData(int handle, OrbisCameraFrameData* pFrameData) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraOpen(Libraries::UserService::OrbisUserServiceUserId userId, s32 type,
|
||||
s32 index, OrbisCameraOpenParameter* pParam) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraOpenByModuleId() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraRemoveAppModuleFocus() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetAppModuleFocus() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetAttribute(s32 handle, OrbisCameraAttribute* pAttribute) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetAttributeInternal() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetAutoExposureGain(s32 handle, OrbisCameraChannel channel, u32 enable,
|
||||
void* pOption) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetAutoWhiteBalance(s32 handle, OrbisCameraChannel channel, u32 enable,
|
||||
void* pOption) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetCalibData() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetConfig(s32 handle, OrbisCameraConfig* pConfig) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetConfigInternal() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetContrast(s32 handle, OrbisCameraChannel channel, u32 contrast,
|
||||
void* pOption) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetDebugStop() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetDefectivePixelCancellation(s32 handle, OrbisCameraChannel channel,
|
||||
u32 enable, void* pOption) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetDefectivePixelCancellationInternal() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetExposureGain(s32 handle, OrbisCameraChannel channel,
|
||||
OrbisCameraExposureGain* pExposureGain, void* pOption) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetForceActivate() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetGamma(s32 handle, OrbisCameraChannel channel, OrbisCameraGamma* pGamma,
|
||||
void* pOption) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetHue(s32 handle, OrbisCameraChannel channel, s32 hue, void* pOption) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetLensCorrection(s32 handle, OrbisCameraChannel channel, u32 enable,
|
||||
void* pOption) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetLensCorrectionInternal() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetProcessFocus() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetProcessFocusByHandle() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetRegister() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetSaturation(s32 handle, OrbisCameraChannel channel, u32 saturation,
|
||||
void* pOption) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetSharpness(s32 handle, OrbisCameraChannel channel, u32 sharpness,
|
||||
void* pOption) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetTrackerMode() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetUacModeInternal() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetVideoSync(s32 handle, OrbisCameraVideoSyncParameter* pVideoSync) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetVideoSyncInternal() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraSetWhiteBalance(s32 handle, OrbisCameraChannel channel,
|
||||
OrbisCameraWhiteBalance* pWhiteBalance, void* pOption) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraStart(s32 handle, OrbisCameraStartParameter* pParam) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraStartByHandle() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraStop(s32 handle) {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraStopByHandle() {
|
||||
LOG_ERROR(Lib_Camera, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
void RegisterlibSceCamera(Core::Loader::SymbolsResolver* sym) {
|
||||
LIB_FUNCTION("QhjrPkRPUZQ", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraAccGetData);
|
||||
LIB_FUNCTION("UFonL7xopFM", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraAudioClose);
|
||||
LIB_FUNCTION("fkZE7Hup2ro", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraAudioGetData);
|
||||
LIB_FUNCTION("hftC5A1C8OQ", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraAudioGetData2);
|
||||
LIB_FUNCTION("DhqqFiBU+6g", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraAudioOpen);
|
||||
LIB_FUNCTION("wyU98EXAYxU", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraAudioReset);
|
||||
LIB_FUNCTION("Y0pCDajzkVQ", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraChangeAppModuleState);
|
||||
LIB_FUNCTION("OMS9LlcrvBo", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraClose);
|
||||
LIB_FUNCTION("ztqH5qNTpTk", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraCloseByHandle);
|
||||
LIB_FUNCTION("nBH6i2s4Glc", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraDeviceOpen);
|
||||
LIB_FUNCTION("0btIPD5hg5A", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetAttribute);
|
||||
LIB_FUNCTION("oEi6vM-3E2c", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraGetAutoExposureGain);
|
||||
LIB_FUNCTION("qTPRMh4eY60", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraGetAutoWhiteBalance);
|
||||
LIB_FUNCTION("hHA1frlMxYE", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetCalibData);
|
||||
LIB_FUNCTION("5Oie5RArfWs", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraGetCalibDataFromDevice);
|
||||
LIB_FUNCTION("RHYJ7GKOSMg", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraGetCalibrationData);
|
||||
LIB_FUNCTION("ZaqmGEtYuL0", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetConfig);
|
||||
LIB_FUNCTION("a5xFueMZIMs", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetContrast);
|
||||
LIB_FUNCTION("tslCukqFE+E", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraGetDefectivePixelCancellation);
|
||||
LIB_FUNCTION("DSOLCrc3Kh8", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetDeviceConfig);
|
||||
LIB_FUNCTION("n+rFeP1XXyM", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraGetDeviceConfigWithoutHandle);
|
||||
LIB_FUNCTION("jTJCdyv9GLU", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetDeviceID);
|
||||
LIB_FUNCTION("-H3UwGQvNZI", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraGetDeviceIDWithoutOpen);
|
||||
LIB_FUNCTION("WZpxnSAM-ds", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetDeviceInfo);
|
||||
LIB_FUNCTION("ObIste7hqdk", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetExposureGain);
|
||||
LIB_FUNCTION("mxgMmR+1Kr0", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetFrameData);
|
||||
LIB_FUNCTION("WVox2rwGuSc", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetGamma);
|
||||
LIB_FUNCTION("zrIUDKZx0iE", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetHue);
|
||||
LIB_FUNCTION("XqYRHc4aw3w", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraGetLensCorrection);
|
||||
LIB_FUNCTION("B260o9pSzM8", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraGetMmapConnectedCount);
|
||||
LIB_FUNCTION("ULxbwqiYYuU", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetProductInfo);
|
||||
LIB_FUNCTION("olojYZKYiYs", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetRegister);
|
||||
LIB_FUNCTION("hawKak+Auw4", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetRegistryInfo);
|
||||
LIB_FUNCTION("RTDOsWWqdME", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetSaturation);
|
||||
LIB_FUNCTION("c6Fp9M1EXXc", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetSharpness);
|
||||
LIB_FUNCTION("IAz2HgZQWzE", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetVrCaptureInfo);
|
||||
LIB_FUNCTION("HX5524E5tMY", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetWhiteBalance);
|
||||
LIB_FUNCTION("0wnf2a60FqI", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraInitializeRegistryCalibData);
|
||||
LIB_FUNCTION("p6n3Npi3YY4", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraIsAttached);
|
||||
LIB_FUNCTION("wQfd7kfRZvo", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraIsConfigChangeDone);
|
||||
LIB_FUNCTION("U3BVwQl2R5Q", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraIsValidFrameData);
|
||||
LIB_FUNCTION("BHn83xrF92E", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraOpen);
|
||||
LIB_FUNCTION("eTywOSWsEiI", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraOpenByModuleId);
|
||||
LIB_FUNCTION("py8p6kZcHmA", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraRemoveAppModuleFocus);
|
||||
LIB_FUNCTION("j5isFVIlZLk", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraSetAppModuleFocus);
|
||||
LIB_FUNCTION("doPlf33ab-U", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetAttribute);
|
||||
LIB_FUNCTION("96F7zp1Xo+k", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraSetAttributeInternal);
|
||||
LIB_FUNCTION("yfSdswDaElo", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraSetAutoExposureGain);
|
||||
LIB_FUNCTION("zIKL4kZleuc", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraSetAutoWhiteBalance);
|
||||
LIB_FUNCTION("LEMk5cTHKEA", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetCalibData);
|
||||
LIB_FUNCTION("VQ+5kAqsE2Q", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetConfig);
|
||||
LIB_FUNCTION("9+SNhbctk64", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraSetConfigInternal);
|
||||
LIB_FUNCTION("3i5MEzrC1pg", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetContrast);
|
||||
LIB_FUNCTION("vejouEusC7g", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetDebugStop);
|
||||
LIB_FUNCTION("jMv40y2A23g", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraSetDefectivePixelCancellation);
|
||||
LIB_FUNCTION("vER3cIMBHqI", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraSetDefectivePixelCancellationInternal);
|
||||
LIB_FUNCTION("wgBMXJJA6K4", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetExposureGain);
|
||||
LIB_FUNCTION("jeTpU0MqKU0", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetForceActivate);
|
||||
LIB_FUNCTION("lhEIsHzB8r4", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetGamma);
|
||||
LIB_FUNCTION("QI8GVJUy2ZY", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetHue);
|
||||
LIB_FUNCTION("K7W7H4ZRwbc", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraSetLensCorrection);
|
||||
LIB_FUNCTION("eHa3vhGu2rQ", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraSetLensCorrectionInternal);
|
||||
LIB_FUNCTION("lS0tM6n+Q5E", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetProcessFocus);
|
||||
LIB_FUNCTION("NVITuK83Z7o", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraSetProcessFocusByHandle);
|
||||
LIB_FUNCTION("8MjO05qk5hA", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetRegister);
|
||||
LIB_FUNCTION("bSKEi2PzzXI", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetSaturation);
|
||||
LIB_FUNCTION("P-7MVfzvpsM", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetSharpness);
|
||||
LIB_FUNCTION("3VJOpzKoIeM", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetTrackerMode);
|
||||
LIB_FUNCTION("nnR7KAIDPv8", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraSetUacModeInternal);
|
||||
LIB_FUNCTION("wpeyFwJ+UEI", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetVideoSync);
|
||||
LIB_FUNCTION("8WtmqmE4edw", "libSceCamera", 1, "libSceCamera", 1, 1,
|
||||
sceCameraSetVideoSyncInternal);
|
||||
LIB_FUNCTION("k3zPIcgFNv0", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetWhiteBalance);
|
||||
LIB_FUNCTION("9EpRYMy7rHU", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraStart);
|
||||
LIB_FUNCTION("cLxF1QtHch0", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraStartByHandle);
|
||||
LIB_FUNCTION("2G2C0nmd++M", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraStop);
|
||||
LIB_FUNCTION("+X1Kgnn3bzg", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraStopByHandle);
|
||||
};
|
||||
|
||||
} // namespace Libraries::Camera
|
308
src/core/libraries/camera/camera.h
Normal file
308
src/core/libraries/camera/camera.h
Normal file
|
@ -0,0 +1,308 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <core/libraries/system/userservice.h>
|
||||
#include "common/types.h"
|
||||
|
||||
namespace Core::Loader {
|
||||
class SymbolsResolver;
|
||||
}
|
||||
|
||||
namespace Libraries::Camera {
|
||||
|
||||
constexpr int ORBIS_CAMERA_MAX_DEVICE_NUM = 2;
|
||||
constexpr int ORBIS_CAMERA_MAX_FORMAT_LEVEL_NUM = 4;
|
||||
|
||||
enum OrbisCameraChannel {
|
||||
ORBIS_CAMERA_CHANNEL_0 = 1,
|
||||
ORBIS_CAMERA_CHANNEL_1 = 2,
|
||||
ORBIS_CAMERA_CHANNEL_BOTH = 3,
|
||||
};
|
||||
|
||||
struct OrbisCameraOpenParameter {
|
||||
u32 sizeThis;
|
||||
u32 reserved1;
|
||||
u32 reserved2;
|
||||
u32 reserved3;
|
||||
};
|
||||
|
||||
enum OrbisCameraConfigType {
|
||||
ORBIS_CAMERA_CONFIG_TYPE1 = 0x01,
|
||||
ORBIS_CAMERA_CONFIG_TYPE2 = 0x02,
|
||||
ORBIS_CAMERA_CONFIG_TYPE3 = 0x03,
|
||||
ORBIS_CAMERA_CONFIG_TYPE4 = 0x04,
|
||||
ORBIS_CAMERA_CONFIG_TYPE5 = 0x05,
|
||||
ORBIS_CAMERA_CONFIG_EXTENTION = 0x10,
|
||||
};
|
||||
|
||||
enum OrbisCameraResolution {
|
||||
ORBIS_CAMERA_RESOLUTION_1280X800 = 0x0,
|
||||
ORBIS_CAMERA_RESOLUTION_640X400 = 0x1,
|
||||
ORBIS_CAMERA_RESOLUTION_320X200 = 0x2,
|
||||
ORBIS_CAMERA_RESOLUTION_160X100 = 0x3,
|
||||
ORBIS_CAMERA_RESOLUTION_320X192 = 0x4,
|
||||
ORBIS_CAMERA_RESOLUTION_SPECIFIED_WIDTH_HEIGHT,
|
||||
ORBIS_CAMERA_RESOLUTION_UNKNOWN = 0xFF,
|
||||
};
|
||||
|
||||
enum OrbisCameraFramerate {
|
||||
ORBIS_CAMERA_FRAMERATE_UNKNOWN = 0,
|
||||
ORBIS_CAMERA_FRAMERATE_7_5 = 7,
|
||||
ORBIS_CAMERA_FRAMERATE_15 = 15,
|
||||
ORBIS_CAMERA_FRAMERATE_30 = 30,
|
||||
ORBIS_CAMERA_FRAMERATE_60 = 60,
|
||||
ORBIS_CAMERA_FRAMERATE_120 = 120,
|
||||
ORBIS_CAMERA_FRAMERATE_240 = 240,
|
||||
};
|
||||
|
||||
enum OrbisCameraBaseFormat {
|
||||
ORBIS_CAMERA_FORMAT_YUV422 = 0x0,
|
||||
ORBIS_CAMERA_FORMAT_RAW16,
|
||||
ORBIS_CAMERA_FORMAT_RAW8,
|
||||
ORBIS_CAMERA_FORMAT_NO_USE = 0x10,
|
||||
ORBIS_CAMERA_FORMAT_UNKNOWN = 0xFF,
|
||||
};
|
||||
|
||||
enum OrbisCameraScaleFormat {
|
||||
ORBIS_CAMERA_SCALE_FORMAT_YUV422 = 0x0,
|
||||
ORBIS_CAMERA_SCALE_FORMAT_Y16 = 0x3,
|
||||
ORBIS_CAMERA_SCALE_FORMAT_Y8,
|
||||
ORBIS_CAMERA_SCALE_FORMAT_NO_USE = 0x10,
|
||||
ORBIS_CAMERA_SCALE_FORMAT_UNKNOWN = 0xFF,
|
||||
};
|
||||
|
||||
struct OrbisCameraFormat {
|
||||
OrbisCameraBaseFormat formatLevel0;
|
||||
OrbisCameraScaleFormat formatLevel1;
|
||||
OrbisCameraScaleFormat formatLevel2;
|
||||
OrbisCameraScaleFormat formatLevel3;
|
||||
};
|
||||
|
||||
struct OrbisCameraConfigExtention {
|
||||
OrbisCameraFormat format;
|
||||
OrbisCameraResolution resolution;
|
||||
OrbisCameraFramerate framerate;
|
||||
u32 width;
|
||||
u32 height;
|
||||
u32 reserved1;
|
||||
void* pBaseOption;
|
||||
};
|
||||
|
||||
struct OrbisCameraConfig {
|
||||
u32 sizeThis;
|
||||
OrbisCameraConfigType configType;
|
||||
OrbisCameraConfigExtention configExtention[ORBIS_CAMERA_MAX_DEVICE_NUM];
|
||||
};
|
||||
|
||||
enum OrbisCameraAecAgcTarget {
|
||||
ORBIS_CAMERA_ATTRIBUTE_AECAGC_TARGET_DEF = 0x00,
|
||||
ORBIS_CAMERA_ATTRIBUTE_AECAGC_TARGET_2_0 = 0x20,
|
||||
ORBIS_CAMERA_ATTRIBUTE_AECAGC_TARGET_1_6 = 0x16,
|
||||
ORBIS_CAMERA_ATTRIBUTE_AECAGC_TARGET_1_4 = 0x14,
|
||||
ORBIS_CAMERA_ATTRIBUTE_AECAGC_TARGET_1_2 = 0x12,
|
||||
ORBIS_CAMERA_ATTRIBUTE_AECAGC_TARGET_1_0 = 0x10,
|
||||
ORBIS_CAMERA_ATTRIBUTE_AECAGC_TARGET_0_8 = 0x08,
|
||||
ORBIS_CAMERA_ATTRIBUTE_AECAGC_TARGET_0_6 = 0x06,
|
||||
ORBIS_CAMERA_ATTRIBUTE_AECAGC_TARGET_0_4 = 0x04,
|
||||
ORBIS_CAMERA_ATTRIBUTE_AECAGC_TARGET_0_2 = 0x02,
|
||||
};
|
||||
|
||||
struct OrbisCameraDeviceInfo {
|
||||
u32 sizeThis;
|
||||
u32 infoRevision;
|
||||
u32 deviceRevision;
|
||||
u32 padding;
|
||||
};
|
||||
|
||||
struct OrbisCameraStartParameter {
|
||||
u32 sizeThis;
|
||||
u32 formatLevel[ORBIS_CAMERA_MAX_DEVICE_NUM];
|
||||
void* pStartOption;
|
||||
};
|
||||
|
||||
struct OrbisCameraVideoSyncParameter {
|
||||
u32 sizeThis;
|
||||
u32 videoSyncMode;
|
||||
void* pModeOption;
|
||||
};
|
||||
|
||||
struct OrbisCameraFramePosition {
|
||||
u32 x;
|
||||
u32 y;
|
||||
u32 xSize;
|
||||
u32 ySize;
|
||||
};
|
||||
|
||||
struct OrbisCameraAutoExposureGainTarget {
|
||||
u32 sizeThis;
|
||||
OrbisCameraAecAgcTarget target;
|
||||
};
|
||||
|
||||
struct OrbisCameraExposureGain {
|
||||
u32 exposureControl;
|
||||
u32 exposure;
|
||||
u32 gain;
|
||||
u32 mode;
|
||||
};
|
||||
|
||||
struct OrbisCameraWhiteBalance {
|
||||
u32 whiteBalanceControl;
|
||||
u32 gainRed;
|
||||
u32 gainBlue;
|
||||
u32 gainGreen;
|
||||
};
|
||||
|
||||
struct OrbisCameraGamma {
|
||||
u32 gammaControl;
|
||||
u32 value;
|
||||
u8 reserved[16];
|
||||
};
|
||||
|
||||
struct OrbisCameraMeta {
|
||||
u32 metaMode;
|
||||
u32 format[ORBIS_CAMERA_MAX_DEVICE_NUM][ORBIS_CAMERA_MAX_FORMAT_LEVEL_NUM];
|
||||
u64 frame[ORBIS_CAMERA_MAX_DEVICE_NUM];
|
||||
u64 timestamp[ORBIS_CAMERA_MAX_DEVICE_NUM];
|
||||
u32 deviceTimestamp[ORBIS_CAMERA_MAX_DEVICE_NUM];
|
||||
OrbisCameraExposureGain exposureGain[ORBIS_CAMERA_MAX_DEVICE_NUM];
|
||||
OrbisCameraWhiteBalance whiteBalance[ORBIS_CAMERA_MAX_DEVICE_NUM];
|
||||
OrbisCameraGamma gamma[ORBIS_CAMERA_MAX_DEVICE_NUM];
|
||||
u32 luminance[ORBIS_CAMERA_MAX_DEVICE_NUM];
|
||||
float acceleration_x;
|
||||
float acceleration_y;
|
||||
float acceleration_z;
|
||||
u64 vcounter;
|
||||
u32 reserved[14];
|
||||
};
|
||||
|
||||
struct OrbisCameraFrameData {
|
||||
u32 sizeThis;
|
||||
u32 readMode;
|
||||
OrbisCameraFramePosition framePosition[ORBIS_CAMERA_MAX_DEVICE_NUM]
|
||||
[ORBIS_CAMERA_MAX_FORMAT_LEVEL_NUM];
|
||||
void* pFramePointerList[ORBIS_CAMERA_MAX_DEVICE_NUM][ORBIS_CAMERA_MAX_FORMAT_LEVEL_NUM];
|
||||
u32 frameSize[ORBIS_CAMERA_MAX_DEVICE_NUM][ORBIS_CAMERA_MAX_FORMAT_LEVEL_NUM];
|
||||
u32 status[ORBIS_CAMERA_MAX_DEVICE_NUM];
|
||||
OrbisCameraMeta meta;
|
||||
void* pFramePointerListGarlic[ORBIS_CAMERA_MAX_DEVICE_NUM][ORBIS_CAMERA_MAX_FORMAT_LEVEL_NUM];
|
||||
};
|
||||
|
||||
struct OrbisCameraAttribute {
|
||||
u32 sizeThis;
|
||||
OrbisCameraChannel channel;
|
||||
OrbisCameraFramePosition framePosition;
|
||||
OrbisCameraExposureGain exposureGain;
|
||||
OrbisCameraWhiteBalance whiteBalance;
|
||||
OrbisCameraGamma gamma;
|
||||
u32 saturation;
|
||||
u32 contrast;
|
||||
u32 sharpness;
|
||||
s32 hue;
|
||||
u32 reserved1;
|
||||
u32 reserved2;
|
||||
u32 reserved3;
|
||||
u32 reserved4;
|
||||
};
|
||||
|
||||
s32 PS4_SYSV_ABI sceCameraAccGetData();
|
||||
s32 PS4_SYSV_ABI sceCameraAudioClose();
|
||||
s32 PS4_SYSV_ABI sceCameraAudioGetData();
|
||||
s32 PS4_SYSV_ABI sceCameraAudioGetData2();
|
||||
s32 PS4_SYSV_ABI sceCameraAudioOpen();
|
||||
s32 PS4_SYSV_ABI sceCameraAudioReset();
|
||||
s32 PS4_SYSV_ABI sceCameraChangeAppModuleState();
|
||||
s32 PS4_SYSV_ABI sceCameraClose(s32 handle);
|
||||
s32 PS4_SYSV_ABI sceCameraCloseByHandle();
|
||||
s32 PS4_SYSV_ABI sceCameraDeviceOpen();
|
||||
s32 PS4_SYSV_ABI sceCameraGetAttribute(s32 handle, OrbisCameraAttribute* pAttribute);
|
||||
s32 PS4_SYSV_ABI sceCameraGetAutoExposureGain(s32 handle, OrbisCameraChannel channel, u32* pEnable,
|
||||
void* pOption);
|
||||
s32 PS4_SYSV_ABI sceCameraGetAutoWhiteBalance(s32 handle, OrbisCameraChannel channel, u32* pEnable,
|
||||
void* pOption);
|
||||
s32 PS4_SYSV_ABI sceCameraGetCalibData();
|
||||
s32 PS4_SYSV_ABI sceCameraGetCalibDataFromDevice();
|
||||
s32 PS4_SYSV_ABI sceCameraGetCalibrationData();
|
||||
s32 PS4_SYSV_ABI sceCameraGetConfig(s32 handle, OrbisCameraConfig* pConfig);
|
||||
s32 PS4_SYSV_ABI sceCameraGetContrast(s32 handle, OrbisCameraChannel channel, u32* pContrast,
|
||||
void* pOption);
|
||||
s32 PS4_SYSV_ABI sceCameraGetDefectivePixelCancellation(s32 handle, OrbisCameraChannel channel,
|
||||
u32* pEnable, void* pOption);
|
||||
s32 PS4_SYSV_ABI sceCameraGetDeviceConfig();
|
||||
s32 PS4_SYSV_ABI sceCameraGetDeviceConfigWithoutHandle();
|
||||
s32 PS4_SYSV_ABI sceCameraGetDeviceID();
|
||||
s32 PS4_SYSV_ABI sceCameraGetDeviceIDWithoutOpen();
|
||||
s32 PS4_SYSV_ABI sceCameraGetDeviceInfo(s32 reserved, OrbisCameraDeviceInfo* pDeviceInfo);
|
||||
s32 PS4_SYSV_ABI sceCameraGetExposureGain(s32 handle, OrbisCameraChannel channel,
|
||||
OrbisCameraExposureGain* pExposureGain, void* pOption);
|
||||
s32 PS4_SYSV_ABI sceCameraGetFrameData(int handle, OrbisCameraFrameData* pFrameData);
|
||||
s32 PS4_SYSV_ABI sceCameraGetGamma(s32 handle, OrbisCameraChannel channel, OrbisCameraGamma* pGamma,
|
||||
void* pOption);
|
||||
s32 PS4_SYSV_ABI sceCameraGetHue(s32 handle, OrbisCameraChannel channel, s32* pHue, void* pOption);
|
||||
s32 PS4_SYSV_ABI sceCameraGetLensCorrection(s32 handle, OrbisCameraChannel channel, u32* pEnable,
|
||||
void* pOption);
|
||||
s32 PS4_SYSV_ABI sceCameraGetMmapConnectedCount();
|
||||
s32 PS4_SYSV_ABI sceCameraGetProductInfo();
|
||||
s32 PS4_SYSV_ABI sceCameraGetRegister();
|
||||
s32 PS4_SYSV_ABI sceCameraGetRegistryInfo();
|
||||
s32 PS4_SYSV_ABI sceCameraGetSaturation(s32 handle, OrbisCameraChannel channel, u32* pSaturation,
|
||||
void* pOption);
|
||||
s32 PS4_SYSV_ABI sceCameraGetSharpness(s32 handle, OrbisCameraChannel channel, u32* pSharpness,
|
||||
void* pOption);
|
||||
s32 PS4_SYSV_ABI sceCameraGetVrCaptureInfo();
|
||||
s32 PS4_SYSV_ABI sceCameraGetWhiteBalance(s32 handle, OrbisCameraChannel channel,
|
||||
OrbisCameraWhiteBalance* pWhiteBalance, void* pOption);
|
||||
s32 PS4_SYSV_ABI sceCameraInitializeRegistryCalibData();
|
||||
s32 PS4_SYSV_ABI sceCameraIsAttached(s32 index);
|
||||
s32 PS4_SYSV_ABI sceCameraIsConfigChangeDone();
|
||||
s32 PS4_SYSV_ABI sceCameraIsValidFrameData(int handle, OrbisCameraFrameData* pFrameData);
|
||||
s32 PS4_SYSV_ABI sceCameraOpen(Libraries::UserService::OrbisUserServiceUserId userId, s32 type,
|
||||
s32 index, OrbisCameraOpenParameter* pParam);
|
||||
s32 PS4_SYSV_ABI sceCameraOpenByModuleId();
|
||||
s32 PS4_SYSV_ABI sceCameraRemoveAppModuleFocus();
|
||||
s32 PS4_SYSV_ABI sceCameraSetAppModuleFocus();
|
||||
s32 PS4_SYSV_ABI sceCameraSetAttribute(s32 handle, OrbisCameraAttribute* pAttribute);
|
||||
s32 PS4_SYSV_ABI sceCameraSetAttributeInternal();
|
||||
s32 PS4_SYSV_ABI sceCameraSetAutoExposureGain(s32 handle, OrbisCameraChannel channel, u32 enable,
|
||||
void* pOption);
|
||||
s32 PS4_SYSV_ABI sceCameraSetAutoWhiteBalance(s32 handle, OrbisCameraChannel channel, u32 enable,
|
||||
void* pOption);
|
||||
s32 PS4_SYSV_ABI sceCameraSetCalibData();
|
||||
s32 PS4_SYSV_ABI sceCameraSetConfig(s32 handle, OrbisCameraConfig* pConfig);
|
||||
s32 PS4_SYSV_ABI sceCameraSetConfigInternal();
|
||||
s32 PS4_SYSV_ABI sceCameraSetContrast(s32 handle, OrbisCameraChannel channel, u32 contrast,
|
||||
void* pOption);
|
||||
s32 PS4_SYSV_ABI sceCameraSetDebugStop();
|
||||
s32 PS4_SYSV_ABI sceCameraSetDefectivePixelCancellation(s32 handle, OrbisCameraChannel channel,
|
||||
u32 enable, void* pOption);
|
||||
s32 PS4_SYSV_ABI sceCameraSetDefectivePixelCancellationInternal();
|
||||
s32 PS4_SYSV_ABI sceCameraSetExposureGain(s32 handle, OrbisCameraChannel channel,
|
||||
OrbisCameraExposureGain* pExposureGain, void* pOption);
|
||||
s32 PS4_SYSV_ABI sceCameraSetForceActivate();
|
||||
s32 PS4_SYSV_ABI sceCameraSetGamma(s32 handle, OrbisCameraChannel channel, OrbisCameraGamma* pGamma,
|
||||
void* pOption);
|
||||
s32 PS4_SYSV_ABI sceCameraSetHue(s32 handle, OrbisCameraChannel channel, s32 hue, void* pOption);
|
||||
s32 PS4_SYSV_ABI sceCameraSetLensCorrection(s32 handle, OrbisCameraChannel channel, u32 enable,
|
||||
void* pOption);
|
||||
s32 PS4_SYSV_ABI sceCameraSetLensCorrectionInternal();
|
||||
s32 PS4_SYSV_ABI sceCameraSetProcessFocus();
|
||||
s32 PS4_SYSV_ABI sceCameraSetProcessFocusByHandle();
|
||||
s32 PS4_SYSV_ABI sceCameraSetRegister();
|
||||
s32 PS4_SYSV_ABI sceCameraSetSaturation(s32 handle, OrbisCameraChannel channel, u32 saturation,
|
||||
void* pOption);
|
||||
s32 PS4_SYSV_ABI sceCameraSetSharpness(s32 handle, OrbisCameraChannel channel, u32 sharpness,
|
||||
void* pOption);
|
||||
s32 PS4_SYSV_ABI sceCameraSetTrackerMode();
|
||||
s32 PS4_SYSV_ABI sceCameraSetUacModeInternal();
|
||||
s32 PS4_SYSV_ABI sceCameraSetVideoSync(s32 handle, OrbisCameraVideoSyncParameter* pVideoSync);
|
||||
s32 PS4_SYSV_ABI sceCameraSetVideoSyncInternal();
|
||||
s32 PS4_SYSV_ABI sceCameraSetWhiteBalance(s32 handle, OrbisCameraChannel channel,
|
||||
OrbisCameraWhiteBalance* pWhiteBalance, void* pOption);
|
||||
s32 PS4_SYSV_ABI sceCameraStart(s32 handle, OrbisCameraStartParameter* pParam);
|
||||
s32 PS4_SYSV_ABI sceCameraStartByHandle();
|
||||
s32 PS4_SYSV_ABI sceCameraStop(s32 handle);
|
||||
s32 PS4_SYSV_ABI sceCameraStopByHandle();
|
||||
|
||||
void RegisterlibSceCamera(Core::Loader::SymbolsResolver* sym);
|
||||
} // namespace Libraries::Camera
|
29
src/core/libraries/camera/camera_error.h
Normal file
29
src/core/libraries/camera/camera_error.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
constexpr int ORBIS_CAMERA_ERROR_PARAM = 0x802E0000;
|
||||
constexpr int ORBIS_CAMERA_ERROR_ALREADY_INIT = 0x802E0001;
|
||||
constexpr int ORBIS_CAMERA_ERROR_NOT_INIT = 0x802E0002;
|
||||
constexpr int ORBIS_CAMERA_ERROR_ALREADY_OPEN = 0x802E0003;
|
||||
constexpr int ORBIS_CAMERA_ERROR_NOT_OPEN = 0x802E0004;
|
||||
constexpr int ORBIS_CAMERA_ERROR_ALREADY_START = 0x802E0005;
|
||||
constexpr int ORBIS_CAMERA_ERROR_NOT_START = 0x802E0006;
|
||||
constexpr int ORBIS_CAMERA_ERROR_FORMAT_UNKNOWN = 0x802E0007;
|
||||
constexpr int ORBIS_CAMERA_ERROR_RESOLUTION_UNKNOWN = 0x802E0008;
|
||||
constexpr int ORBIS_CAMERA_ERROR_BAD_FRAMERATE = 0x802E0009;
|
||||
constexpr int ORBIS_CAMERA_ERROR_TIMEOUT = 0x802E000A;
|
||||
constexpr int ORBIS_CAMERA_ERROR_ATTRIBUTE_UNKNOWN = 0x802E000B;
|
||||
constexpr int ORBIS_CAMERA_ERROR_BUSY = 0x802E000C;
|
||||
constexpr int ORBIS_CAMERA_ERROR_UNKNOWN_CONFIG = 0x802E000D;
|
||||
constexpr int ORBIS_CAMERA_ERROR_ALREADY_READ = 0x802E000F;
|
||||
constexpr int ORBIS_CAMERA_ERROR_NOT_CONNECTED = 0x802E0010;
|
||||
constexpr int ORBIS_CAMERA_ERROR_NOT_SUPPORTED = 0x802E0011;
|
||||
constexpr int ORBIS_CAMERA_ERROR_INVALID_CONFIG = 0x802E0013;
|
||||
constexpr int ORBIS_CAMERA_ERROR_MAX_HANDLE = 0x802E0014;
|
||||
constexpr int ORBIS_CAMERA_ERROR_MAX_PROCESS = 0x802E00FB;
|
||||
constexpr int ORBIS_CAMERA_ERROR_COPYOUT_FAILED = 0x802E00FC;
|
||||
constexpr int ORBIS_CAMERA_ERROR_COPYIN_FAILED = 0x802E00FD;
|
||||
constexpr int ORBIS_CAMERA_ERROR_KPROC_CREATE = 0x802E00FE;
|
||||
constexpr int ORBIS_CAMERA_ERROR_FATAL = 0x802E00FF;
|
|
@ -179,7 +179,7 @@ s32 PS4_SYSV_ABI sceGnmComputeWaitOnAddress(u32* cmdbuf, u32 size, uintptr_t add
|
|||
auto* wait_reg_mem = reinterpret_cast<PM4CmdWaitRegMem*>(cmdbuf);
|
||||
wait_reg_mem->header = PM4Type3Header{PM4ItOpcode::WaitRegMem, 5};
|
||||
wait_reg_mem->raw = (is_mem << 4u) | (cmp_func & 7u);
|
||||
wait_reg_mem->poll_addr_lo = u32(addr & addr_mask);
|
||||
wait_reg_mem->poll_addr_lo_raw = u32(addr & addr_mask);
|
||||
wait_reg_mem->poll_addr_hi = u32(addr >> 32u);
|
||||
wait_reg_mem->ref = ref;
|
||||
wait_reg_mem->mask = mask;
|
||||
|
@ -505,9 +505,10 @@ s32 PS4_SYSV_ABI sceGnmDrawIndexIndirectCountMulti(u32* cmdbuf, u32 size, u32 da
|
|||
u32 flags) {
|
||||
LOG_TRACE(Lib_GnmDriver, "called");
|
||||
|
||||
if ((!sceKernelIsNeoMode() || !UseNeoCompatSequences) && !cmdbuf && (size == 16) &&
|
||||
(shader_stage < ShaderStages::Max) && (vertex_sgpr_offset < 0x10u) &&
|
||||
(instance_sgpr_offset < 0x10u)) {
|
||||
if ((!sceKernelIsNeoMode() || !UseNeoCompatSequences) && cmdbuf && (size == 16) &&
|
||||
(vertex_sgpr_offset < 0x10u) && (instance_sgpr_offset < 0x10u) &&
|
||||
(shader_stage == ShaderStages::Vs || shader_stage == ShaderStages::Es ||
|
||||
shader_stage == ShaderStages::Ls)) {
|
||||
|
||||
cmdbuf = WriteHeader<PM4ItOpcode::Nop>(cmdbuf, 2);
|
||||
cmdbuf = WriteBody(cmdbuf, 0u);
|
||||
|
@ -535,10 +536,33 @@ s32 PS4_SYSV_ABI sceGnmDrawIndexIndirectCountMulti(u32* cmdbuf, u32 size, u32 da
|
|||
return -1;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceGnmDrawIndexIndirectMulti() {
|
||||
LOG_ERROR(Lib_GnmDriver, "(STUBBED) called");
|
||||
UNREACHABLE();
|
||||
return ORBIS_OK;
|
||||
int PS4_SYSV_ABI sceGnmDrawIndexIndirectMulti(u32* cmdbuf, u32 size, u32 data_offset, u32 max_count,
|
||||
u32 shader_stage, u32 vertex_sgpr_offset,
|
||||
u32 instance_sgpr_offset, u32 flags) {
|
||||
LOG_TRACE(Lib_GnmDriver, "called");
|
||||
|
||||
if (cmdbuf && (size == 11) && (vertex_sgpr_offset < 0x10u) && (instance_sgpr_offset < 0x10u) &&
|
||||
(shader_stage == ShaderStages::Vs || shader_stage == ShaderStages::Es ||
|
||||
shader_stage == ShaderStages::Ls)) {
|
||||
|
||||
const auto predicate = flags & 1 ? PM4Predicate::PredEnable : PM4Predicate::PredDisable;
|
||||
cmdbuf = WriteHeader<PM4ItOpcode::DrawIndexIndirectMulti>(
|
||||
cmdbuf, 6, PM4ShaderType::ShaderGraphics, predicate);
|
||||
|
||||
const auto sgpr_offset = indirect_sgpr_offsets[shader_stage];
|
||||
|
||||
cmdbuf[0] = data_offset;
|
||||
cmdbuf[1] = vertex_sgpr_offset == 0 ? 0 : (vertex_sgpr_offset & 0xffffu) + sgpr_offset;
|
||||
cmdbuf[2] = instance_sgpr_offset == 0 ? 0 : (instance_sgpr_offset & 0xffffu) + sgpr_offset;
|
||||
cmdbuf[3] = max_count;
|
||||
cmdbuf[4] = sizeof(DrawIndexedIndirectArgs);
|
||||
cmdbuf[5] = sceKernelIsNeoMode() ? flags & 0xe0000000u : 0;
|
||||
|
||||
cmdbuf += 6;
|
||||
WriteTrailingNop<3>(cmdbuf);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceGnmDrawIndexMultiInstanced() {
|
||||
|
|
|
@ -51,7 +51,9 @@ s32 PS4_SYSV_ABI sceGnmDrawIndexIndirectCountMulti(u32* cmdbuf, u32 size, u32 da
|
|||
u32 max_count, u64 count_addr, u32 shader_stage,
|
||||
u32 vertex_sgpr_offset, u32 instance_sgpr_offset,
|
||||
u32 flags);
|
||||
int PS4_SYSV_ABI sceGnmDrawIndexIndirectMulti();
|
||||
int PS4_SYSV_ABI sceGnmDrawIndexIndirectMulti(u32* cmdbuf, u32 size, u32 data_offset, u32 max_count,
|
||||
u32 shader_stage, u32 vertex_sgpr_offset,
|
||||
u32 instance_sgpr_offset, u32 flags);
|
||||
int PS4_SYSV_ABI sceGnmDrawIndexMultiInstanced();
|
||||
s32 PS4_SYSV_ABI sceGnmDrawIndexOffset(u32* cmdbuf, u32 size, u32 index_offset, u32 index_count,
|
||||
u32 flags);
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace Libraries::Kernel {
|
|||
static s32* id_state;
|
||||
static s32 id_index;
|
||||
|
||||
s32 sceKernelAioInitializeImpl(void* p, s32 size) {
|
||||
s32 PS4_SYSV_ABI sceKernelAioInitializeImpl(void* p, s32 size) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -12,12 +12,25 @@
|
|||
|
||||
namespace Libraries::Kernel {
|
||||
|
||||
extern boost::asio::io_context io_context;
|
||||
extern void KernelSignalRequest();
|
||||
|
||||
static constexpr auto HrTimerSpinlockThresholdUs = 1200u;
|
||||
|
||||
// Events are uniquely identified by id and filter.
|
||||
|
||||
bool EqueueInternal::AddEvent(EqueueEvent& event) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
|
||||
event.time_added = std::chrono::steady_clock::now();
|
||||
if (event.event.filter == SceKernelEvent::Filter::Timer ||
|
||||
event.event.filter == SceKernelEvent::Filter::HrTimer) {
|
||||
// HrTimer events are offset by the threshold of time at the end that we spinlock for
|
||||
// greater accuracy.
|
||||
const auto offset =
|
||||
event.event.filter == SceKernelEvent::Filter::HrTimer ? HrTimerSpinlockThresholdUs : 0u;
|
||||
event.timer_interval = std::chrono::microseconds(event.event.data - offset);
|
||||
}
|
||||
|
||||
const auto& it = std::ranges::find(m_events, event);
|
||||
if (it != m_events.cend()) {
|
||||
|
@ -29,6 +42,47 @@ bool EqueueInternal::AddEvent(EqueueEvent& event) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool EqueueInternal::ScheduleEvent(u64 id, s16 filter,
|
||||
void (*callback)(SceKernelEqueue, const SceKernelEvent&)) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
|
||||
const auto& it = std::ranges::find_if(m_events, [id, filter](auto& ev) {
|
||||
return ev.event.ident == id && ev.event.filter == filter;
|
||||
});
|
||||
if (it == m_events.cend()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& event = *it;
|
||||
ASSERT(event.event.filter == SceKernelEvent::Filter::Timer ||
|
||||
event.event.filter == SceKernelEvent::Filter::HrTimer);
|
||||
|
||||
if (!it->timer) {
|
||||
it->timer = std::make_unique<boost::asio::steady_timer>(io_context, event.timer_interval);
|
||||
} else {
|
||||
// If the timer already exists we are scheduling a reoccurrence after the next period.
|
||||
// Set the expiration time to the previous occurrence plus the period.
|
||||
it->timer->expires_at(it->timer->expiry() + event.timer_interval);
|
||||
}
|
||||
|
||||
it->timer->async_wait(
|
||||
[this, event_data = event.event, callback](const boost::system::error_code& ec) {
|
||||
if (ec) {
|
||||
if (ec != boost::system::errc::operation_canceled) {
|
||||
LOG_ERROR(Kernel_Event, "Timer callback error: {}", ec.message());
|
||||
} else {
|
||||
// Timer was cancelled (removed) before it triggered
|
||||
LOG_DEBUG(Kernel_Event, "Timer cancelled");
|
||||
}
|
||||
return;
|
||||
}
|
||||
callback(this, event_data);
|
||||
});
|
||||
KernelSignalRequest();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EqueueInternal::RemoveEvent(u64 id, s16 filter) {
|
||||
bool has_found = false;
|
||||
std::scoped_lock lock{m_mutex};
|
||||
|
@ -152,18 +206,14 @@ int EqueueInternal::WaitForSmallTimer(SceKernelEvent* ev, int num, u32 micros) {
|
|||
return count;
|
||||
}
|
||||
|
||||
extern boost::asio::io_context io_context;
|
||||
extern void KernelSignalRequest();
|
||||
bool EqueueInternal::EventExists(u64 id, s16 filter) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
|
||||
static constexpr auto HrTimerSpinlockThresholdUs = 1200u;
|
||||
const auto& it = std::ranges::find_if(m_events, [id, filter](auto& ev) {
|
||||
return ev.event.ident == id && ev.event.filter == filter;
|
||||
});
|
||||
|
||||
static void SmallTimerCallback(const boost::system::error_code& error, SceKernelEqueue eq,
|
||||
SceKernelEvent kevent) {
|
||||
static EqueueEvent event;
|
||||
event.event = kevent;
|
||||
event.event.data = HrTimerSpinlockThresholdUs;
|
||||
eq->AddSmallTimer(event);
|
||||
eq->TriggerEvent(kevent.ident, SceKernelEvent::Filter::HrTimer, kevent.udata);
|
||||
return it != m_events.cend();
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceKernelCreateEqueue(SceKernelEqueue* eq, const char* name) {
|
||||
|
@ -243,6 +293,14 @@ int PS4_SYSV_ABI sceKernelWaitEqueue(SceKernelEqueue eq, SceKernelEvent* ev, int
|
|||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
static void HrTimerCallback(SceKernelEqueue eq, const SceKernelEvent& kevent) {
|
||||
static EqueueEvent event;
|
||||
event.event = kevent;
|
||||
event.event.data = HrTimerSpinlockThresholdUs;
|
||||
eq->AddSmallTimer(event);
|
||||
eq->TriggerEvent(kevent.ident, SceKernelEvent::Filter::HrTimer, kevent.udata);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelAddHRTimerEvent(SceKernelEqueue eq, int id, timespec* ts, void* udata) {
|
||||
if (eq == nullptr) {
|
||||
return ORBIS_KERNEL_ERROR_EBADF;
|
||||
|
@ -273,17 +331,10 @@ s32 PS4_SYSV_ABI sceKernelAddHRTimerEvent(SceKernelEqueue eq, int id, timespec*
|
|||
return eq->AddSmallTimer(event) ? ORBIS_OK : ORBIS_KERNEL_ERROR_ENOMEM;
|
||||
}
|
||||
|
||||
event.timer = std::make_unique<boost::asio::steady_timer>(
|
||||
io_context, std::chrono::microseconds(total_us - HrTimerSpinlockThresholdUs));
|
||||
|
||||
event.timer->async_wait(std::bind(SmallTimerCallback, std::placeholders::_1, eq, event.event));
|
||||
|
||||
if (!eq->AddEvent(event)) {
|
||||
if (!eq->AddEvent(event) ||
|
||||
!eq->ScheduleEvent(id, SceKernelEvent::Filter::HrTimer, HrTimerCallback)) {
|
||||
return ORBIS_KERNEL_ERROR_ENOMEM;
|
||||
}
|
||||
|
||||
KernelSignalRequest();
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
|
@ -300,6 +351,57 @@ int PS4_SYSV_ABI sceKernelDeleteHRTimerEvent(SceKernelEqueue eq, int id) {
|
|||
}
|
||||
}
|
||||
|
||||
static void TimerCallback(SceKernelEqueue eq, const SceKernelEvent& kevent) {
|
||||
if (eq->EventExists(kevent.ident, kevent.filter)) {
|
||||
eq->TriggerEvent(kevent.ident, SceKernelEvent::Filter::Timer, kevent.udata);
|
||||
|
||||
if (!(kevent.flags & SceKernelEvent::Flags::OneShot)) {
|
||||
// Reschedule the event for its next period.
|
||||
eq->ScheduleEvent(kevent.ident, kevent.filter, TimerCallback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceKernelAddTimerEvent(SceKernelEqueue eq, int id, SceKernelUseconds usec,
|
||||
void* udata) {
|
||||
if (eq == nullptr) {
|
||||
return ORBIS_KERNEL_ERROR_EBADF;
|
||||
}
|
||||
|
||||
EqueueEvent event{};
|
||||
event.event.ident = static_cast<u64>(id);
|
||||
event.event.filter = SceKernelEvent::Filter::Timer;
|
||||
event.event.flags = SceKernelEvent::Flags::Add;
|
||||
event.event.fflags = 0;
|
||||
event.event.data = usec;
|
||||
event.event.udata = udata;
|
||||
|
||||
if (eq->EventExists(event.event.ident, event.event.filter)) {
|
||||
eq->RemoveEvent(id, SceKernelEvent::Filter::Timer);
|
||||
LOG_DEBUG(Kernel_Event,
|
||||
"Timer event already exists, removing it: queue name={}, queue id={}",
|
||||
eq->GetName(), event.event.ident);
|
||||
}
|
||||
|
||||
LOG_DEBUG(Kernel_Event, "Added timing event: queue name={}, queue id={}, usec={}, pointer={:x}",
|
||||
eq->GetName(), event.event.ident, usec, reinterpret_cast<uintptr_t>(udata));
|
||||
|
||||
if (!eq->AddEvent(event) ||
|
||||
!eq->ScheduleEvent(id, SceKernelEvent::Filter::Timer, TimerCallback)) {
|
||||
return ORBIS_KERNEL_ERROR_ENOMEM;
|
||||
}
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceKernelDeleteTimerEvent(SceKernelEqueue eq, int id) {
|
||||
if (eq == nullptr) {
|
||||
return ORBIS_KERNEL_ERROR_EBADF;
|
||||
}
|
||||
|
||||
return eq->RemoveEvent(id, SceKernelEvent::Filter::Timer) ? ORBIS_OK
|
||||
: ORBIS_KERNEL_ERROR_ENOENT;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceKernelAddUserEvent(SceKernelEqueue eq, int id) {
|
||||
if (eq == nullptr) {
|
||||
return ORBIS_KERNEL_ERROR_EBADF;
|
||||
|
@ -380,6 +482,8 @@ void RegisterEventQueue(Core::Loader::SymbolsResolver* sym) {
|
|||
LIB_FUNCTION("WDszmSbWuDk", "libkernel", 1, "libkernel", 1, 1, sceKernelAddUserEventEdge);
|
||||
LIB_FUNCTION("R74tt43xP6k", "libkernel", 1, "libkernel", 1, 1, sceKernelAddHRTimerEvent);
|
||||
LIB_FUNCTION("J+LF6LwObXU", "libkernel", 1, "libkernel", 1, 1, sceKernelDeleteHRTimerEvent);
|
||||
LIB_FUNCTION("57ZK+ODEXWY", "libkernel", 1, "libkernel", 1, 1, sceKernelAddTimerEvent);
|
||||
LIB_FUNCTION("YWQFUyXIVdU", "libkernel", 1, "libkernel", 1, 1, sceKernelDeleteTimerEvent);
|
||||
LIB_FUNCTION("F6e0kwo4cnk", "libkernel", 1, "libkernel", 1, 1, sceKernelTriggerUserEvent);
|
||||
LIB_FUNCTION("LJDwdSNTnDg", "libkernel", 1, "libkernel", 1, 1, sceKernelDeleteUserEvent);
|
||||
LIB_FUNCTION("mJ7aghmgvfc", "libkernel", 1, "libkernel", 1, 1, sceKernelGetEventId);
|
||||
|
|
|
@ -21,6 +21,9 @@ namespace Libraries::Kernel {
|
|||
class EqueueInternal;
|
||||
struct EqueueEvent;
|
||||
|
||||
using SceKernelUseconds = u32;
|
||||
using SceKernelEqueue = EqueueInternal*;
|
||||
|
||||
struct SceKernelEvent {
|
||||
enum Filter : s16 {
|
||||
None = 0,
|
||||
|
@ -61,10 +64,23 @@ 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;
|
||||
std::chrono::steady_clock::time_point time_added;
|
||||
std::chrono::microseconds timer_interval;
|
||||
std::unique_ptr<boost::asio::steady_timer> timer;
|
||||
|
||||
void ResetTriggerState() {
|
||||
|
@ -84,19 +100,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -122,6 +137,8 @@ public:
|
|||
}
|
||||
|
||||
bool AddEvent(EqueueEvent& event);
|
||||
bool ScheduleEvent(u64 id, s16 filter,
|
||||
void (*callback)(SceKernelEqueue, const SceKernelEvent&));
|
||||
bool RemoveEvent(u64 id, s16 filter);
|
||||
int WaitForEvents(SceKernelEvent* ev, int num, u32 micros);
|
||||
bool TriggerEvent(u64 ident, s16 filter, void* trigger_data);
|
||||
|
@ -141,6 +158,8 @@ public:
|
|||
|
||||
int WaitForSmallTimer(SceKernelEvent* ev, int num, u32 micros);
|
||||
|
||||
bool EventExists(u64 id, s16 filter);
|
||||
|
||||
private:
|
||||
std::string m_name;
|
||||
std::mutex m_mutex;
|
||||
|
@ -149,9 +168,6 @@ private:
|
|||
std::condition_variable m_cond;
|
||||
};
|
||||
|
||||
using SceKernelUseconds = u32;
|
||||
using SceKernelEqueue = EqueueInternal*;
|
||||
|
||||
u64 PS4_SYSV_ABI sceKernelGetEventData(const SceKernelEvent* ev);
|
||||
|
||||
void RegisterEventQueue(Core::Loader::SymbolsResolver* sym);
|
||||
|
|
|
@ -67,10 +67,16 @@ s32 PS4_SYSV_ABI open(const char* raw_path, s32 flags, u16 mode) {
|
|||
bool write = (flags & 0x3) == ORBIS_KERNEL_O_WRONLY;
|
||||
bool rdwr = (flags & 0x3) == ORBIS_KERNEL_O_RDWR;
|
||||
|
||||
if (!read && !write && !rdwr) {
|
||||
// Start by checking for invalid flags.
|
||||
*__Error() = POSIX_EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool nonblock = (flags & ORBIS_KERNEL_O_NONBLOCK) != 0;
|
||||
bool append = (flags & ORBIS_KERNEL_O_APPEND) != 0;
|
||||
bool fsync = (flags & ORBIS_KERNEL_O_FSYNC) != 0;
|
||||
bool sync = (flags & ORBIS_KERNEL_O_SYNC) != 0;
|
||||
// Flags fsync and sync behave the same
|
||||
bool sync = (flags & ORBIS_KERNEL_O_SYNC) != 0 || (flags & ORBIS_KERNEL_O_FSYNC) != 0;
|
||||
bool create = (flags & ORBIS_KERNEL_O_CREAT) != 0;
|
||||
bool truncate = (flags & ORBIS_KERNEL_O_TRUNC) != 0;
|
||||
bool excl = (flags & ORBIS_KERNEL_O_EXCL) != 0;
|
||||
|
@ -78,6 +84,10 @@ s32 PS4_SYSV_ABI open(const char* raw_path, s32 flags, u16 mode) {
|
|||
bool direct = (flags & ORBIS_KERNEL_O_DIRECT) != 0;
|
||||
bool directory = (flags & ORBIS_KERNEL_O_DIRECTORY) != 0;
|
||||
|
||||
if (sync || direct || dsync || nonblock) {
|
||||
LOG_WARNING(Kernel_Fs, "flags {:#x} not fully handled", flags);
|
||||
}
|
||||
|
||||
std::string_view path{raw_path};
|
||||
u32 handle = h->CreateHandle();
|
||||
auto* file = h->GetFile(handle);
|
||||
|
@ -94,84 +104,127 @@ s32 PS4_SYSV_ABI open(const char* raw_path, s32 flags, u16 mode) {
|
|||
}
|
||||
}
|
||||
|
||||
if (directory) {
|
||||
file->type = Core::FileSys::FileType::Directory;
|
||||
file->m_guest_name = path;
|
||||
file->m_host_name = mnt->GetHostPath(file->m_guest_name);
|
||||
if (!std::filesystem::is_directory(file->m_host_name)) { // directory doesn't exist
|
||||
bool read_only = false;
|
||||
file->m_guest_name = path;
|
||||
file->m_host_name = mnt->GetHostPath(file->m_guest_name, &read_only);
|
||||
bool exists = std::filesystem::exists(file->m_host_name);
|
||||
s32 e = 0;
|
||||
|
||||
if (create) {
|
||||
if (excl && exists) {
|
||||
// Error if file exists
|
||||
h->DeleteHandle(handle);
|
||||
*__Error() = POSIX_ENOENT;
|
||||
*__Error() = POSIX_EEXIST;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (read_only) {
|
||||
// Can't create files in a read only directory
|
||||
h->DeleteHandle(handle);
|
||||
*__Error() = POSIX_EROFS;
|
||||
return -1;
|
||||
}
|
||||
// Create a file if it doesn't exist
|
||||
Common::FS::IOFile out(file->m_host_name, Common::FS::FileAccessMode::Write);
|
||||
} else if (!exists) {
|
||||
// If we're not creating a file, and it doesn't exist, return ENOENT
|
||||
h->DeleteHandle(handle);
|
||||
*__Error() = POSIX_ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (std::filesystem::is_directory(file->m_host_name) || directory) {
|
||||
// Directories can be opened even if the directory flag isn't set.
|
||||
// In these cases, error behavior is identical to the directory code path.
|
||||
directory = true;
|
||||
}
|
||||
|
||||
if (directory) {
|
||||
if (!std::filesystem::is_directory(file->m_host_name)) {
|
||||
// If the opened file is not a directory, return ENOTDIR.
|
||||
// This will trigger when create & directory is specified, this is expected.
|
||||
h->DeleteHandle(handle);
|
||||
*__Error() = POSIX_ENOTDIR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
file->type = Core::FileSys::FileType::Directory;
|
||||
|
||||
// Populate directory contents
|
||||
mnt->IterateDirectory(file->m_guest_name,
|
||||
[&file](const auto& ent_path, const auto ent_is_file) {
|
||||
auto& dir_entry = file->dirents.emplace_back();
|
||||
dir_entry.name = ent_path.filename().string();
|
||||
dir_entry.isFile = ent_is_file;
|
||||
});
|
||||
file->dirents_index = 0;
|
||||
|
||||
if (read) {
|
||||
e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::Read);
|
||||
} else if (write || rdwr) {
|
||||
// Cannot open directories with any type of write access
|
||||
h->DeleteHandle(handle);
|
||||
*__Error() = POSIX_EISDIR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (e == EACCES) {
|
||||
// Hack to bypass some platform limitations, ignore the error and continue as normal.
|
||||
LOG_WARNING(Kernel_Fs, "Opening directories is not fully supported on this platform");
|
||||
e = 0;
|
||||
}
|
||||
|
||||
if (truncate) {
|
||||
// Cannot open directories with truncate
|
||||
h->DeleteHandle(handle);
|
||||
*__Error() = POSIX_EISDIR;
|
||||
return -1;
|
||||
} else {
|
||||
if (create) {
|
||||
return handle; // dir already exists
|
||||
} else {
|
||||
mnt->IterateDirectory(file->m_guest_name,
|
||||
[&file](const auto& ent_path, const auto ent_is_file) {
|
||||
auto& dir_entry = file->dirents.emplace_back();
|
||||
dir_entry.name = ent_path.filename().string();
|
||||
dir_entry.isFile = ent_is_file;
|
||||
});
|
||||
file->dirents_index = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
file->m_guest_name = path;
|
||||
file->m_host_name = mnt->GetHostPath(file->m_guest_name);
|
||||
bool exists = std::filesystem::exists(file->m_host_name);
|
||||
int e = 0;
|
||||
file->type = Core::FileSys::FileType::Regular;
|
||||
|
||||
if (create) {
|
||||
if (excl && exists) {
|
||||
// Error if file exists
|
||||
h->DeleteHandle(handle);
|
||||
*__Error() = POSIX_EEXIST;
|
||||
return -1;
|
||||
}
|
||||
// Create file if it doesn't exist
|
||||
Common::FS::IOFile out(file->m_host_name, Common::FS::FileAccessMode::Write);
|
||||
} else if (!exists) {
|
||||
// File to open doesn't exist, return ENOENT
|
||||
if (truncate && read_only) {
|
||||
// Can't open files with truncate flag in a read only directory
|
||||
h->DeleteHandle(handle);
|
||||
*__Error() = POSIX_ENOENT;
|
||||
*__Error() = POSIX_EROFS;
|
||||
return -1;
|
||||
} else if (truncate) {
|
||||
// Open the file as read-write so we can truncate regardless of flags.
|
||||
// Since open starts by closing the file, this won't interfere with later open calls.
|
||||
e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::ReadWrite);
|
||||
if (e == 0) {
|
||||
// If the file was opened successfully, reduce size to 0
|
||||
file->f.SetSize(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (read) {
|
||||
// Read only
|
||||
e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::Read);
|
||||
} else if (read_only) {
|
||||
// Can't open files with write/read-write access in a read only directory
|
||||
h->DeleteHandle(handle);
|
||||
*__Error() = POSIX_EROFS;
|
||||
return -1;
|
||||
} else if (append) {
|
||||
// Append can be specified with rdwr or write, but we treat it as a separate mode.
|
||||
e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::Append);
|
||||
} else if (write) {
|
||||
// Write only
|
||||
if (append) {
|
||||
e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::Append);
|
||||
} else {
|
||||
e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::Write);
|
||||
}
|
||||
e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::Write);
|
||||
} else if (rdwr) {
|
||||
// Read and write
|
||||
if (append) {
|
||||
e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::Append);
|
||||
} else {
|
||||
e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::ReadWrite);
|
||||
}
|
||||
} else {
|
||||
// Invalid flags
|
||||
*__Error() = POSIX_EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (truncate && e == 0) {
|
||||
// If the file was opened successfully and truncate was enabled, reduce size to 0
|
||||
file->f.SetSize(0);
|
||||
}
|
||||
|
||||
if (e != 0) {
|
||||
// Open failed in platform-specific code, errno needs to be converted.
|
||||
h->DeleteHandle(handle);
|
||||
SetPosixErrno(e);
|
||||
return -1;
|
||||
e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::ReadWrite);
|
||||
}
|
||||
}
|
||||
|
||||
if (e != 0) {
|
||||
// Open failed in platform-specific code, errno needs to be converted.
|
||||
h->DeleteHandle(handle);
|
||||
SetPosixErrno(e);
|
||||
return -1;
|
||||
}
|
||||
|
||||
file->is_opened = true;
|
||||
return handle;
|
||||
}
|
||||
|
@ -365,10 +418,10 @@ s64 PS4_SYSV_ABI posix_lseek(s32 fd, s64 offset, s32 whence) {
|
|||
origin = Common::FS::SeekOrigin::CurrentPosition;
|
||||
} else if (whence == 2) {
|
||||
origin = Common::FS::SeekOrigin::End;
|
||||
} else if (whence == 3) {
|
||||
origin = Common::FS::SeekOrigin::SeekHole;
|
||||
} else if (whence == 4) {
|
||||
origin = Common::FS::SeekOrigin::SeekData;
|
||||
} else if (whence == 3 || whence == 4) {
|
||||
// whence parameter belongs to an unsupported POSIX extension
|
||||
*__Error() = POSIX_ENOTTY;
|
||||
return -1;
|
||||
} else {
|
||||
// whence parameter is invalid
|
||||
*__Error() = POSIX_EINVAL;
|
||||
|
@ -486,13 +539,13 @@ s32 PS4_SYSV_ABI posix_rmdir(const char* path) {
|
|||
|
||||
const std::filesystem::path dir_name = mnt->GetHostPath(path, &ro);
|
||||
|
||||
if (dir_name.empty() || !std::filesystem::is_directory(dir_name)) {
|
||||
*__Error() = POSIX_ENOTDIR;
|
||||
if (ro) {
|
||||
*__Error() = POSIX_EROFS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ro) {
|
||||
*__Error() = POSIX_EROFS;
|
||||
if (dir_name.empty() || !std::filesystem::is_directory(dir_name)) {
|
||||
*__Error() = POSIX_ENOTDIR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -523,8 +576,7 @@ s32 PS4_SYSV_ABI sceKernelRmdir(const char* path) {
|
|||
s32 PS4_SYSV_ABI posix_stat(const char* path, OrbisKernelStat* sb) {
|
||||
LOG_INFO(Kernel_Fs, "(PARTIAL) path = {}", path);
|
||||
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
|
||||
bool ro = false;
|
||||
const auto path_name = mnt->GetHostPath(path, &ro);
|
||||
const auto path_name = mnt->GetHostPath(path);
|
||||
std::memset(sb, 0, sizeof(OrbisKernelStat));
|
||||
const bool is_dir = std::filesystem::is_directory(path_name);
|
||||
const bool is_file = std::filesystem::is_regular_file(path_name);
|
||||
|
@ -545,9 +597,6 @@ s32 PS4_SYSV_ABI posix_stat(const char* path, OrbisKernelStat* sb) {
|
|||
sb->st_blocks = (sb->st_size + 511) / 512;
|
||||
// TODO incomplete
|
||||
}
|
||||
if (ro) {
|
||||
sb->st_mode &= ~0000555u;
|
||||
}
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
@ -877,7 +926,7 @@ s32 PS4_SYSV_ABI sceKernelGetdirentries(s32 fd, char* buf, s32 nbytes, s64* base
|
|||
return result;
|
||||
}
|
||||
|
||||
s64 PS4_SYSV_ABI posix_pwrite(s32 fd, void* buf, size_t nbytes, s64 offset) {
|
||||
s64 PS4_SYSV_ABI posix_pwritev(s32 fd, const SceKernelIovec* iov, s32 iovcnt, s64 offset) {
|
||||
if (offset < 0) {
|
||||
*__Error() = POSIX_EINVAL;
|
||||
return -1;
|
||||
|
@ -893,7 +942,7 @@ s64 PS4_SYSV_ABI posix_pwrite(s32 fd, void* buf, size_t nbytes, s64 offset) {
|
|||
std::scoped_lock lk{file->m_mutex};
|
||||
|
||||
if (file->type == Core::FileSys::FileType::Device) {
|
||||
s64 result = file->device->pwrite(buf, nbytes, offset);
|
||||
s64 result = file->device->pwritev(iov, iovcnt, offset);
|
||||
if (result < 0) {
|
||||
ErrSceToPosix(result);
|
||||
return -1;
|
||||
|
@ -908,7 +957,16 @@ s64 PS4_SYSV_ABI posix_pwrite(s32 fd, void* buf, size_t nbytes, s64 offset) {
|
|||
*__Error() = POSIX_EIO;
|
||||
return -1;
|
||||
}
|
||||
return file->f.WriteRaw<u8>(buf, nbytes);
|
||||
size_t total_written = 0;
|
||||
for (int i = 0; i < iovcnt; i++) {
|
||||
total_written += file->f.WriteRaw<u8>(iov[i].iov_base, iov[i].iov_len);
|
||||
}
|
||||
return total_written;
|
||||
}
|
||||
|
||||
s64 PS4_SYSV_ABI posix_pwrite(s32 fd, void* buf, size_t nbytes, s64 offset) {
|
||||
SceKernelIovec iovec{buf, nbytes};
|
||||
return posix_pwritev(fd, &iovec, 1, offset);
|
||||
}
|
||||
|
||||
s64 PS4_SYSV_ABI sceKernelPwrite(s32 fd, void* buf, size_t nbytes, s64 offset) {
|
||||
|
@ -920,6 +978,15 @@ s64 PS4_SYSV_ABI sceKernelPwrite(s32 fd, void* buf, size_t nbytes, s64 offset) {
|
|||
return result;
|
||||
}
|
||||
|
||||
s64 PS4_SYSV_ABI sceKernelPwritev(s32 fd, const SceKernelIovec* iov, s32 iovcnt, s64 offset) {
|
||||
s64 result = posix_pwritev(fd, iov, iovcnt, offset);
|
||||
if (result < 0) {
|
||||
LOG_ERROR(Kernel_Fs, "error = {}", *__Error());
|
||||
return ErrnoToSceKernelError(*__Error());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI posix_unlink(const char* path) {
|
||||
if (path == nullptr) {
|
||||
*__Error() = POSIX_EINVAL;
|
||||
|
@ -1017,7 +1084,10 @@ void RegisterFileSystem(Core::Loader::SymbolsResolver* sym) {
|
|||
LIB_FUNCTION("sfKygSjIbI8", "libkernel", 1, "libkernel", 1, 1, getdirentries);
|
||||
LIB_FUNCTION("taRWhTJFTgE", "libkernel", 1, "libkernel", 1, 1, sceKernelGetdirentries);
|
||||
LIB_FUNCTION("C2kJ-byS5rM", "libkernel", 1, "libkernel", 1, 1, posix_pwrite);
|
||||
LIB_FUNCTION("FCcmRZhWtOk", "libScePosix", 1, "libkernel", 1, 1, posix_pwritev);
|
||||
LIB_FUNCTION("FCcmRZhWtOk", "libkernel", 1, "libkernel", 1, 1, posix_pwritev);
|
||||
LIB_FUNCTION("nKWi-N2HBV4", "libkernel", 1, "libkernel", 1, 1, sceKernelPwrite);
|
||||
LIB_FUNCTION("mBd4AfLP+u8", "libkernel", 1, "libkernel", 1, 1, sceKernelPwritev);
|
||||
LIB_FUNCTION("AUXVxWeJU-A", "libkernel", 1, "libkernel", 1, 1, sceKernelUnlink);
|
||||
}
|
||||
|
||||
|
|
|
@ -24,11 +24,16 @@
|
|||
#include "core/libraries/kernel/threads/exception.h"
|
||||
#include "core/libraries/kernel/time.h"
|
||||
#include "core/libraries/libs.h"
|
||||
#include "core/libraries/network/sys_net.h"
|
||||
|
||||
#ifdef _WIN64
|
||||
#include <Rpc.h>
|
||||
#else
|
||||
#include <uuid/uuid.h>
|
||||
#endif
|
||||
#include <common/singleton.h>
|
||||
#include <core/libraries/network/net_error.h>
|
||||
#include <core/libraries/network/sockets.h>
|
||||
#include "aio.h"
|
||||
|
||||
namespace Libraries::Kernel {
|
||||
|
@ -149,23 +154,23 @@ struct OrbisKernelUuid {
|
|||
u8 clockSeqLow;
|
||||
u8 node[6];
|
||||
};
|
||||
static_assert(sizeof(OrbisKernelUuid) == 0x10);
|
||||
|
||||
int PS4_SYSV_ABI sceKernelUuidCreate(OrbisKernelUuid* orbisUuid) {
|
||||
if (!orbisUuid) {
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
#ifdef _WIN64
|
||||
UUID uuid;
|
||||
UuidCreate(&uuid);
|
||||
orbisUuid->timeLow = uuid.Data1;
|
||||
orbisUuid->timeMid = uuid.Data2;
|
||||
orbisUuid->timeHiAndVersion = uuid.Data3;
|
||||
orbisUuid->clockSeqHiAndReserved = uuid.Data4[0];
|
||||
orbisUuid->clockSeqLow = uuid.Data4[1];
|
||||
for (int i = 0; i < 6; i++) {
|
||||
orbisUuid->node[i] = uuid.Data4[2 + i];
|
||||
if (UuidCreate(&uuid) != RPC_S_OK) {
|
||||
return ORBIS_KERNEL_ERROR_EFAULT;
|
||||
}
|
||||
#else
|
||||
LOG_ERROR(Kernel, "sceKernelUuidCreate: Add linux");
|
||||
uuid_t uuid;
|
||||
uuid_generate(uuid);
|
||||
#endif
|
||||
return 0;
|
||||
std::memcpy(orbisUuid, &uuid, sizeof(OrbisKernelUuid));
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI kernel_ioctl(int fd, u64 cmd, VA_ARGS) {
|
||||
|
@ -196,10 +201,6 @@ const char* PS4_SYSV_ABI sceKernelGetFsSandboxRandomWord() {
|
|||
return path;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_connect() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI _sigprocmask() {
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
@ -208,6 +209,24 @@ int PS4_SYSV_ABI posix_getpagesize() {
|
|||
return 16_KB;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_getsockname(Libraries::Net::OrbisNetId s,
|
||||
Libraries::Net::OrbisNetSockaddr* addr, u32* paddrlen) {
|
||||
auto* netcall = Common::Singleton<Libraries::Net::NetInternal>::Instance();
|
||||
auto sock = netcall->FindSocket(s);
|
||||
if (!sock) {
|
||||
*Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF;
|
||||
LOG_ERROR(Lib_Net, "socket id is invalid = {}", s);
|
||||
return -1;
|
||||
}
|
||||
int returncode = sock->GetSocketAddress(addr, paddrlen);
|
||||
if (returncode >= 0) {
|
||||
LOG_ERROR(Lib_Net, "return code : {:#x}", (u32)returncode);
|
||||
return 0;
|
||||
}
|
||||
*Libraries::Kernel::__Error() = 0x20;
|
||||
LOG_ERROR(Lib_Net, "error code returned : {:#x}", (u32)returncode);
|
||||
return -1;
|
||||
}
|
||||
void RegisterKernel(Core::Loader::SymbolsResolver* sym) {
|
||||
service_thread = std::jthread{KernelServiceThread};
|
||||
|
||||
|
@ -225,7 +244,6 @@ void RegisterKernel(Core::Loader::SymbolsResolver* sym) {
|
|||
LIB_OBJ("f7uOxY9mM1U", "libkernel", 1, "libkernel", 1, 1, &g_stack_chk_guard);
|
||||
LIB_FUNCTION("PfccT7qURYE", "libkernel", 1, "libkernel", 1, 1, kernel_ioctl);
|
||||
LIB_FUNCTION("JGfTMBOdUJo", "libkernel", 1, "libkernel", 1, 1, sceKernelGetFsSandboxRandomWord);
|
||||
LIB_FUNCTION("XVL8So3QJUk", "libkernel", 1, "libkernel", 1, 1, posix_connect);
|
||||
LIB_FUNCTION("6xVpy0Fdq+I", "libkernel", 1, "libkernel", 1, 1, _sigprocmask);
|
||||
LIB_FUNCTION("Xjoosiw+XPI", "libkernel", 1, "libkernel", 1, 1, sceKernelUuidCreate);
|
||||
LIB_FUNCTION("Ou3iL1abvng", "libkernel", 1, "libkernel", 1, 1, stack_chk_fail);
|
||||
|
@ -234,6 +252,24 @@ void RegisterKernel(Core::Loader::SymbolsResolver* sym) {
|
|||
LIB_FUNCTION("k+AXqu2-eBc", "libScePosix", 1, "libkernel", 1, 1, posix_getpagesize);
|
||||
LIB_FUNCTION("NWtTN10cJzE", "libSceLibcInternalExt", 1, "libSceLibcInternal", 1, 1,
|
||||
sceLibcHeapGetTraceInfo);
|
||||
|
||||
// network
|
||||
LIB_FUNCTION("XVL8So3QJUk", "libkernel", 1, "libkernel", 1, 1, Libraries::Net::sys_connect);
|
||||
LIB_FUNCTION("TU-d9PfIHPM", "libkernel", 1, "libkernel", 1, 1, Libraries::Net::sys_socketex);
|
||||
LIB_FUNCTION("KuOmgKoqCdY", "libkernel", 1, "libkernel", 1, 1, Libraries::Net::sys_bind);
|
||||
LIB_FUNCTION("pxnCmagrtao", "libkernel", 1, "libkernel", 1, 1, Libraries::Net::sys_listen);
|
||||
LIB_FUNCTION("3e+4Iv7IJ8U", "libkernel", 1, "libkernel", 1, 1, Libraries::Net::sys_accept);
|
||||
LIB_FUNCTION("TU-d9PfIHPM", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sys_socket);
|
||||
LIB_FUNCTION("oBr313PppNE", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sys_sendto);
|
||||
LIB_FUNCTION("lUk6wrGXyMw", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sys_recvfrom);
|
||||
LIB_FUNCTION("fFxGkxF2bVo", "libScePosix", 1, "libkernel", 1, 1,
|
||||
Libraries::Net::sys_setsockopt);
|
||||
// LIB_FUNCTION("RenI1lL1WFk", "libScePosix", 1, "libkernel", 1, 1, posix_getsockname);
|
||||
LIB_FUNCTION("KuOmgKoqCdY", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sys_bind);
|
||||
LIB_FUNCTION("5jRCs2axtr4", "libScePosix", 1, "libkernel", 1, 1,
|
||||
Libraries::Net::sceNetInetNtop); // TODO fix it to sys_ ...
|
||||
LIB_FUNCTION("4n51s0zEf0c", "libScePosix", 1, "libkernel", 1, 1,
|
||||
Libraries::Net::sceNetInetPton); // TODO fix it to sys_ ...
|
||||
}
|
||||
|
||||
} // namespace Libraries::Kernel
|
||||
|
|
|
@ -3,9 +3,6 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <fmt/core.h>
|
||||
#include "common/string_literal.h"
|
||||
#include "common/types.h"
|
||||
#include "core/libraries/kernel/orbis_error.h"
|
||||
|
||||
|
@ -18,27 +15,23 @@ namespace Libraries::Kernel {
|
|||
void ErrSceToPosix(int result);
|
||||
int ErrnoToSceKernelError(int e);
|
||||
void SetPosixErrno(int e);
|
||||
int* PS4_SYSV_ABI __Error();
|
||||
|
||||
template <StringLiteral name, class F, F f>
|
||||
struct WrapperImpl;
|
||||
template <class F, F f>
|
||||
struct OrbisWrapperImpl;
|
||||
|
||||
template <StringLiteral name, class R, class... Args, PS4_SYSV_ABI R (*f)(Args...)>
|
||||
struct WrapperImpl<name, PS4_SYSV_ABI R (*)(Args...), f> {
|
||||
static constexpr StringLiteral Name{name};
|
||||
template <class R, class... Args, PS4_SYSV_ABI R (*f)(Args...)>
|
||||
struct OrbisWrapperImpl<PS4_SYSV_ABI R (*)(Args...), f> {
|
||||
static R PS4_SYSV_ABI wrap(Args... args) {
|
||||
u32 ret = f(args...);
|
||||
if (ret != 0) {
|
||||
// LOG_ERROR(Lib_Kernel, "Function {} returned {}", std::string_view{name.value}, ret);
|
||||
ret += ORBIS_KERNEL_ERROR_UNKNOWN;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
template <StringLiteral name, class F, F f>
|
||||
constexpr auto OrbisWrapper = WrapperImpl<name, F, f>::wrap;
|
||||
|
||||
#define ORBIS(func) WrapperImpl<#func, decltype(&func), func>::wrap
|
||||
#define ORBIS(func) (Libraries::Kernel::OrbisWrapperImpl<decltype(&(func)), func>::wrap)
|
||||
|
||||
int* PS4_SYSV_ABI __Error();
|
||||
|
||||
|
|
|
@ -126,9 +126,6 @@ s32 PS4_SYSV_ABI sceKernelAvailableDirectMemorySize(u64 searchStart, u64 searchE
|
|||
s32 PS4_SYSV_ABI sceKernelVirtualQuery(const void* addr, int flags, OrbisVirtualQueryInfo* info,
|
||||
size_t infoSize) {
|
||||
LOG_INFO(Kernel_Vmm, "called addr = {}, flags = {:#x}", fmt::ptr(addr), flags);
|
||||
if (!addr) {
|
||||
return ORBIS_KERNEL_ERROR_EACCES;
|
||||
}
|
||||
auto* memory = Core::Memory::Instance();
|
||||
return memory->VirtualQuery(std::bit_cast<VAddr>(addr), flags, info);
|
||||
}
|
||||
|
@ -136,7 +133,6 @@ s32 PS4_SYSV_ABI sceKernelVirtualQuery(const void* addr, int flags, OrbisVirtual
|
|||
s32 PS4_SYSV_ABI sceKernelReserveVirtualRange(void** addr, u64 len, int flags, u64 alignment) {
|
||||
LOG_INFO(Kernel_Vmm, "addr = {}, len = {:#x}, flags = {:#x}, alignment = {:#x}",
|
||||
fmt::ptr(*addr), len, flags, alignment);
|
||||
|
||||
if (addr == nullptr) {
|
||||
LOG_ERROR(Kernel_Vmm, "Address is invalid!");
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
|
@ -155,9 +151,12 @@ s32 PS4_SYSV_ABI sceKernelReserveVirtualRange(void** addr, u64 len, int flags, u
|
|||
auto* memory = Core::Memory::Instance();
|
||||
const VAddr in_addr = reinterpret_cast<VAddr>(*addr);
|
||||
const auto map_flags = static_cast<Core::MemoryMapFlags>(flags);
|
||||
memory->Reserve(addr, in_addr, len, map_flags, alignment);
|
||||
|
||||
return ORBIS_OK;
|
||||
s32 result = memory->Reserve(addr, in_addr, len, map_flags, alignment);
|
||||
if (result == 0) {
|
||||
LOG_INFO(Kernel_Vmm, "out_addr = {}", fmt::ptr(*addr));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceKernelMapNamedDirectMemory(void** addr, u64 len, int prot, int flags,
|
||||
|
@ -172,10 +171,12 @@ int PS4_SYSV_ABI sceKernelMapNamedDirectMemory(void** addr, u64 len, int prot, i
|
|||
LOG_ERROR(Kernel_Vmm, "Map size is either zero or not 16KB aligned!");
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
|
||||
if (!Common::Is16KBAligned(directMemoryStart)) {
|
||||
LOG_ERROR(Kernel_Vmm, "Start address is not 16KB aligned!");
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
|
||||
if (alignment != 0) {
|
||||
if ((!std::has_single_bit(alignment) && !Common::Is16KBAligned(alignment))) {
|
||||
LOG_ERROR(Kernel_Vmm, "Alignment value is invalid!");
|
||||
|
@ -183,14 +184,19 @@ int PS4_SYSV_ABI sceKernelMapNamedDirectMemory(void** addr, u64 len, int prot, i
|
|||
}
|
||||
}
|
||||
|
||||
if (std::strlen(name) >= ORBIS_KERNEL_MAXIMUM_NAME_LENGTH) {
|
||||
LOG_ERROR(Kernel_Vmm, "name exceeds 32 bytes!");
|
||||
return ORBIS_KERNEL_ERROR_ENAMETOOLONG;
|
||||
}
|
||||
|
||||
const VAddr in_addr = reinterpret_cast<VAddr>(*addr);
|
||||
const auto mem_prot = static_cast<Core::MemoryProt>(prot);
|
||||
const auto map_flags = static_cast<Core::MemoryMapFlags>(flags);
|
||||
|
||||
auto* memory = Core::Memory::Instance();
|
||||
const auto ret =
|
||||
memory->MapMemory(addr, in_addr, len, mem_prot, map_flags, Core::VMAType::Direct, "", false,
|
||||
directMemoryStart, alignment);
|
||||
memory->MapMemory(addr, in_addr, len, mem_prot, map_flags, Core::VMAType::Direct, name,
|
||||
false, directMemoryStart, alignment);
|
||||
|
||||
LOG_INFO(Kernel_Vmm, "out_addr = {}", fmt::ptr(*addr));
|
||||
return ret;
|
||||
|
@ -199,7 +205,8 @@ int PS4_SYSV_ABI sceKernelMapNamedDirectMemory(void** addr, u64 len, int prot, i
|
|||
int PS4_SYSV_ABI sceKernelMapDirectMemory(void** addr, u64 len, int prot, int flags,
|
||||
s64 directMemoryStart, u64 alignment) {
|
||||
LOG_INFO(Kernel_Vmm, "called, redirected to sceKernelMapNamedDirectMemory");
|
||||
return sceKernelMapNamedDirectMemory(addr, len, prot, flags, directMemoryStart, alignment, "");
|
||||
return sceKernelMapNamedDirectMemory(addr, len, prot, flags, directMemoryStart, alignment,
|
||||
"anon");
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelMapNamedFlexibleMemory(void** addr_in_out, std::size_t len, int prot,
|
||||
|
@ -210,17 +217,16 @@ s32 PS4_SYSV_ABI sceKernelMapNamedFlexibleMemory(void** addr_in_out, std::size_t
|
|||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
|
||||
static constexpr size_t MaxNameSize = 32;
|
||||
if (std::strlen(name) > MaxNameSize) {
|
||||
LOG_ERROR(Kernel_Vmm, "name exceeds 32 bytes!");
|
||||
return ORBIS_KERNEL_ERROR_ENAMETOOLONG;
|
||||
}
|
||||
|
||||
if (name == nullptr) {
|
||||
LOG_ERROR(Kernel_Vmm, "name is invalid!");
|
||||
return ORBIS_KERNEL_ERROR_EFAULT;
|
||||
}
|
||||
|
||||
if (std::strlen(name) >= ORBIS_KERNEL_MAXIMUM_NAME_LENGTH) {
|
||||
LOG_ERROR(Kernel_Vmm, "name exceeds 32 bytes!");
|
||||
return ORBIS_KERNEL_ERROR_ENAMETOOLONG;
|
||||
}
|
||||
|
||||
const VAddr in_addr = reinterpret_cast<VAddr>(*addr_in_out);
|
||||
const auto mem_prot = static_cast<Core::MemoryProt>(prot);
|
||||
const auto map_flags = static_cast<Core::MemoryMapFlags>(flags);
|
||||
|
@ -236,7 +242,7 @@ s32 PS4_SYSV_ABI sceKernelMapNamedFlexibleMemory(void** addr_in_out, std::size_t
|
|||
|
||||
s32 PS4_SYSV_ABI sceKernelMapFlexibleMemory(void** addr_in_out, std::size_t len, int prot,
|
||||
int flags) {
|
||||
return sceKernelMapNamedFlexibleMemory(addr_in_out, len, prot, flags, "");
|
||||
return sceKernelMapNamedFlexibleMemory(addr_in_out, len, prot, flags, "anon");
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceKernelQueryMemoryProtection(void* addr, void** start, void** end, u32* prot) {
|
||||
|
@ -284,6 +290,13 @@ int PS4_SYSV_ABI sceKernelGetDirectMemoryType(u64 addr, int* directMemoryTypeOut
|
|||
directMemoryEndOut);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceKernelIsStack(void* addr, void** start, void** end) {
|
||||
LOG_DEBUG(Kernel_Vmm, "called, addr = {:#x}, start = {:#x}, end = {:#x}", fmt::ptr(addr),
|
||||
fmt::ptr(start), fmt::ptr(end));
|
||||
auto* memory = Core::Memory::Instance();
|
||||
return memory->IsStack(std::bit_cast<VAddr>(addr), start, end);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelBatchMap(OrbisKernelBatchMapEntry* entries, int numEntries,
|
||||
int* numEntriesOut) {
|
||||
return sceKernelBatchMap2(entries, numEntries, numEntriesOut,
|
||||
|
@ -304,7 +317,7 @@ s32 PS4_SYSV_ABI sceKernelBatchMap2(OrbisKernelBatchMapEntry* entries, int numEn
|
|||
case MemoryOpTypes::ORBIS_KERNEL_MAP_OP_MAP_DIRECT: {
|
||||
result = sceKernelMapNamedDirectMemory(&entries[i].start, entries[i].length,
|
||||
entries[i].protection, flags,
|
||||
static_cast<s64>(entries[i].offset), 0, "");
|
||||
static_cast<s64>(entries[i].offset), 0, "anon");
|
||||
LOG_INFO(Kernel_Vmm,
|
||||
"entry = {}, operation = {}, len = {:#x}, offset = {:#x}, type = {}, "
|
||||
"result = {}",
|
||||
|
@ -326,7 +339,7 @@ s32 PS4_SYSV_ABI sceKernelBatchMap2(OrbisKernelBatchMapEntry* entries, int numEn
|
|||
}
|
||||
case MemoryOpTypes::ORBIS_KERNEL_MAP_OP_MAP_FLEXIBLE: {
|
||||
result = sceKernelMapNamedFlexibleMemory(&entries[i].start, entries[i].length,
|
||||
entries[i].protection, flags, "");
|
||||
entries[i].protection, flags, "anon");
|
||||
LOG_INFO(Kernel_Vmm,
|
||||
"entry = {}, operation = {}, len = {:#x}, type = {}, "
|
||||
"result = {}",
|
||||
|
@ -356,16 +369,16 @@ s32 PS4_SYSV_ABI sceKernelBatchMap2(OrbisKernelBatchMapEntry* entries, int numEn
|
|||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelSetVirtualRangeName(const void* addr, size_t len, const char* name) {
|
||||
static constexpr size_t MaxNameSize = 32;
|
||||
if (std::strlen(name) > MaxNameSize) {
|
||||
LOG_ERROR(Kernel_Vmm, "name exceeds 32 bytes!");
|
||||
return ORBIS_KERNEL_ERROR_ENAMETOOLONG;
|
||||
}
|
||||
|
||||
if (name == nullptr) {
|
||||
LOG_ERROR(Kernel_Vmm, "name is invalid!");
|
||||
return ORBIS_KERNEL_ERROR_EFAULT;
|
||||
}
|
||||
|
||||
if (std::strlen(name) >= ORBIS_KERNEL_MAXIMUM_NAME_LENGTH) {
|
||||
LOG_ERROR(Kernel_Vmm, "name exceeds 32 bytes!");
|
||||
return ORBIS_KERNEL_ERROR_ENAMETOOLONG;
|
||||
}
|
||||
|
||||
auto* memory = Core::Memory::Instance();
|
||||
memory->NameVirtualRange(std::bit_cast<VAddr>(addr), len, name);
|
||||
return ORBIS_OK;
|
||||
|
@ -377,13 +390,12 @@ s32 PS4_SYSV_ABI sceKernelMemoryPoolExpand(u64 searchStart, u64 searchEnd, size_
|
|||
LOG_ERROR(Kernel_Vmm, "Provided address range is invalid!");
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
const bool is_in_range = searchEnd - searchStart >= len;
|
||||
if (len <= 0 || !Common::Is64KBAligned(len) || !is_in_range) {
|
||||
LOG_ERROR(Kernel_Vmm, "Provided address range is invalid!");
|
||||
if (len <= 0 || !Common::Is64KBAligned(len)) {
|
||||
LOG_ERROR(Kernel_Vmm, "Provided length {:#x} is invalid!", len);
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
if (alignment != 0 && !Common::Is64KBAligned(alignment)) {
|
||||
LOG_ERROR(Kernel_Vmm, "Alignment value is invalid!");
|
||||
LOG_ERROR(Kernel_Vmm, "Alignment {:#x} is invalid!", alignment);
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
if (physAddrOut == nullptr) {
|
||||
|
@ -391,8 +403,21 @@ s32 PS4_SYSV_ABI sceKernelMemoryPoolExpand(u64 searchStart, u64 searchEnd, size_
|
|||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
|
||||
const bool is_in_range = searchEnd - searchStart >= len;
|
||||
if (searchEnd <= searchStart || searchEnd < len || !is_in_range) {
|
||||
LOG_ERROR(Kernel_Vmm,
|
||||
"Provided address range is too small!"
|
||||
" searchStart = {:#x}, searchEnd = {:#x}, length = {:#x}",
|
||||
searchStart, searchEnd, len);
|
||||
return ORBIS_KERNEL_ERROR_ENOMEM;
|
||||
}
|
||||
|
||||
auto* memory = Core::Memory::Instance();
|
||||
PAddr phys_addr = memory->PoolExpand(searchStart, searchEnd, len, alignment);
|
||||
if (phys_addr == -1) {
|
||||
return ORBIS_KERNEL_ERROR_ENOMEM;
|
||||
}
|
||||
|
||||
*physAddrOut = static_cast<s64>(phys_addr);
|
||||
|
||||
LOG_INFO(Kernel_Vmm,
|
||||
|
@ -407,10 +432,6 @@ s32 PS4_SYSV_ABI sceKernelMemoryPoolReserve(void* addrIn, size_t len, size_t ali
|
|||
LOG_INFO(Kernel_Vmm, "addrIn = {}, len = {:#x}, alignment = {:#x}, flags = {:#x}",
|
||||
fmt::ptr(addrIn), len, alignment, flags);
|
||||
|
||||
if (addrIn == nullptr) {
|
||||
LOG_ERROR(Kernel_Vmm, "Address is invalid!");
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
if (len == 0 || !Common::Is2MBAligned(len)) {
|
||||
LOG_ERROR(Kernel_Vmm, "Map size is either zero or not 2MB aligned!");
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
|
@ -463,9 +484,61 @@ s32 PS4_SYSV_ABI sceKernelMemoryPoolDecommit(void* addr, size_t len, int flags)
|
|||
|
||||
const VAddr pool_addr = reinterpret_cast<VAddr>(addr);
|
||||
auto* memory = Core::Memory::Instance();
|
||||
memory->PoolDecommit(pool_addr, len);
|
||||
|
||||
return ORBIS_OK;
|
||||
return memory->PoolDecommit(pool_addr, len);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelMemoryPoolBatch(const OrbisKernelMemoryPoolBatchEntry* entries, s32 count,
|
||||
s32* num_processed, s32 flags) {
|
||||
if (entries == nullptr) {
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
s32 result = ORBIS_OK;
|
||||
s32 processed = 0;
|
||||
|
||||
for (s32 i = 0; i < count; i++, processed++) {
|
||||
OrbisKernelMemoryPoolBatchEntry entry = entries[i];
|
||||
switch (entry.opcode) {
|
||||
case OrbisKernelMemoryPoolOpcode::Commit: {
|
||||
result = sceKernelMemoryPoolCommit(entry.commit_params.addr, entry.commit_params.len,
|
||||
entry.commit_params.type, entry.commit_params.prot,
|
||||
entry.flags);
|
||||
break;
|
||||
}
|
||||
case OrbisKernelMemoryPoolOpcode::Decommit: {
|
||||
result = sceKernelMemoryPoolDecommit(entry.decommit_params.addr,
|
||||
entry.decommit_params.len, entry.flags);
|
||||
break;
|
||||
}
|
||||
case OrbisKernelMemoryPoolOpcode::Protect: {
|
||||
result = sceKernelMProtect(entry.protect_params.addr, entry.protect_params.len,
|
||||
entry.protect_params.prot);
|
||||
break;
|
||||
}
|
||||
case OrbisKernelMemoryPoolOpcode::TypeProtect: {
|
||||
result = sceKernelMTypeProtect(
|
||||
entry.type_protect_params.addr, entry.type_protect_params.len,
|
||||
entry.type_protect_params.type, entry.type_protect_params.prot);
|
||||
break;
|
||||
}
|
||||
case OrbisKernelMemoryPoolOpcode::Move: {
|
||||
UNREACHABLE_MSG("Unimplemented sceKernelMemoryPoolBatch opcode Move");
|
||||
}
|
||||
default: {
|
||||
result = ORBIS_KERNEL_ERROR_EINVAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (result != ORBIS_OK) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (num_processed != nullptr) {
|
||||
*num_processed = processed;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceKernelMmap(void* addr, u64 len, int prot, int flags, int fd, size_t offset,
|
||||
|
@ -570,6 +643,7 @@ void RegisterMemory(Core::Loader::SymbolsResolver* sym) {
|
|||
LIB_FUNCTION("7oxv3PPCumo", "libkernel", 1, "libkernel", 1, 1, sceKernelReserveVirtualRange);
|
||||
LIB_FUNCTION("BC+OG5m9+bw", "libkernel", 1, "libkernel", 1, 1, sceKernelGetDirectMemoryType);
|
||||
LIB_FUNCTION("pO96TwzOm5E", "libkernel", 1, "libkernel", 1, 1, sceKernelGetDirectMemorySize);
|
||||
LIB_FUNCTION("yDBwVAolDgg", "libkernel", 1, "libkernel", 1, 1, sceKernelIsStack);
|
||||
LIB_FUNCTION("NcaWUxfMNIQ", "libkernel", 1, "libkernel", 1, 1, sceKernelMapNamedDirectMemory);
|
||||
LIB_FUNCTION("L-Q3LEjIbgA", "libkernel", 1, "libkernel", 1, 1, sceKernelMapDirectMemory);
|
||||
LIB_FUNCTION("WFcfL2lzido", "libkernel", 1, "libkernel", 1, 1, sceKernelQueryMemoryProtection);
|
||||
|
@ -599,6 +673,7 @@ void RegisterMemory(Core::Loader::SymbolsResolver* sym) {
|
|||
LIB_FUNCTION("pU-QydtGcGY", "libkernel", 1, "libkernel", 1, 1, sceKernelMemoryPoolReserve);
|
||||
LIB_FUNCTION("Vzl66WmfLvk", "libkernel", 1, "libkernel", 1, 1, sceKernelMemoryPoolCommit);
|
||||
LIB_FUNCTION("LXo1tpFqJGs", "libkernel", 1, "libkernel", 1, 1, sceKernelMemoryPoolDecommit);
|
||||
LIB_FUNCTION("YN878uKRBbE", "libkernel", 1, "libkernel", 1, 1, sceKernelMemoryPoolBatch);
|
||||
|
||||
LIB_FUNCTION("BPE9s9vQQXo", "libkernel", 1, "libkernel", 1, 1, posix_mmap);
|
||||
LIB_FUNCTION("BPE9s9vQQXo", "libScePosix", 1, "libkernel", 1, 1, posix_mmap);
|
||||
|
|
|
@ -47,6 +47,8 @@ enum MemoryOpTypes : u32 {
|
|||
ORBIS_KERNEL_MAP_OP_TYPE_PROTECT = 4
|
||||
};
|
||||
|
||||
constexpr u32 ORBIS_KERNEL_MAXIMUM_NAME_LENGTH = 32;
|
||||
|
||||
struct OrbisQueryInfo {
|
||||
uintptr_t start;
|
||||
uintptr_t end;
|
||||
|
@ -59,15 +61,15 @@ struct OrbisVirtualQueryInfo {
|
|||
size_t offset;
|
||||
s32 protection;
|
||||
s32 memory_type;
|
||||
union {
|
||||
BitField<0, 1, u32> is_flexible;
|
||||
BitField<1, 1, u32> is_direct;
|
||||
BitField<2, 1, u32> is_stack;
|
||||
BitField<3, 1, u32> is_pooled;
|
||||
BitField<4, 1, u32> is_committed;
|
||||
};
|
||||
std::array<char, 32> name;
|
||||
u8 is_flexible : 1;
|
||||
u8 is_direct : 1;
|
||||
u8 is_stack : 1;
|
||||
u8 is_pooled : 1;
|
||||
u8 is_committed : 1;
|
||||
char name[ORBIS_KERNEL_MAXIMUM_NAME_LENGTH];
|
||||
};
|
||||
static_assert(sizeof(OrbisVirtualQueryInfo) == 72,
|
||||
"OrbisVirtualQueryInfo struct size is incorrect");
|
||||
|
||||
struct OrbisKernelBatchMapEntry {
|
||||
void* start;
|
||||
|
@ -79,6 +81,48 @@ struct OrbisKernelBatchMapEntry {
|
|||
int operation;
|
||||
};
|
||||
|
||||
enum class OrbisKernelMemoryPoolOpcode : u32 {
|
||||
Commit = 1,
|
||||
Decommit = 2,
|
||||
Protect = 3,
|
||||
TypeProtect = 4,
|
||||
Move = 5,
|
||||
};
|
||||
|
||||
struct OrbisKernelMemoryPoolBatchEntry {
|
||||
OrbisKernelMemoryPoolOpcode opcode;
|
||||
u32 flags;
|
||||
union {
|
||||
struct {
|
||||
void* addr;
|
||||
u64 len;
|
||||
u8 prot;
|
||||
u8 type;
|
||||
} commit_params;
|
||||
struct {
|
||||
void* addr;
|
||||
u64 len;
|
||||
} decommit_params;
|
||||
struct {
|
||||
void* addr;
|
||||
u64 len;
|
||||
u8 prot;
|
||||
} protect_params;
|
||||
struct {
|
||||
void* addr;
|
||||
u64 len;
|
||||
u8 prot;
|
||||
u8 type;
|
||||
} type_protect_params;
|
||||
struct {
|
||||
void* dest_addr;
|
||||
void* src_addr;
|
||||
u64 len;
|
||||
} move_params;
|
||||
uintptr_t padding[3];
|
||||
};
|
||||
};
|
||||
|
||||
u64 PS4_SYSV_ABI sceKernelGetDirectMemorySize();
|
||||
int PS4_SYSV_ABI sceKernelAllocateDirectMemory(s64 searchStart, s64 searchEnd, u64 len,
|
||||
u64 alignment, int memoryType, s64* physAddrOut);
|
||||
|
@ -114,6 +158,7 @@ void PS4_SYSV_ABI _sceKernelRtldSetApplicationHeapAPI(void* func[]);
|
|||
int PS4_SYSV_ABI sceKernelGetDirectMemoryType(u64 addr, int* directMemoryTypeOut,
|
||||
void** directMemoryStartOut,
|
||||
void** directMemoryEndOut);
|
||||
int PS4_SYSV_ABI sceKernelIsStack(void* addr, void** start, void** end);
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelBatchMap(OrbisKernelBatchMapEntry* entries, int numEntries,
|
||||
int* numEntriesOut);
|
||||
|
@ -128,6 +173,8 @@ s32 PS4_SYSV_ABI sceKernelMemoryPoolReserve(void* addrIn, size_t len, size_t ali
|
|||
void** addrOut);
|
||||
s32 PS4_SYSV_ABI sceKernelMemoryPoolCommit(void* addr, size_t len, int type, int prot, int flags);
|
||||
s32 PS4_SYSV_ABI sceKernelMemoryPoolDecommit(void* addr, size_t len, int flags);
|
||||
s32 PS4_SYSV_ABI sceKernelMemoryPoolBatch(const OrbisKernelMemoryPoolBatchEntry* entries, s32 count,
|
||||
s32* num_processed, s32 flags);
|
||||
|
||||
int PS4_SYSV_ABI sceKernelMunmap(void* addr, size_t len);
|
||||
|
||||
|
|
|
@ -127,6 +127,62 @@ 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;
|
||||
|
@ -141,6 +197,9 @@ 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,12 @@ int PS4_SYSV_ABI posix_pthread_attr_init(PthreadAttrT* attr);
|
|||
|
||||
int PS4_SYSV_ABI posix_pthread_attr_destroy(PthreadAttrT* attr);
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_attr_getaffinity_np(const PthreadAttrT* pattr, size_t cpusetsize,
|
||||
Cpuset* cpusetp);
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_attr_setaffinity_np(PthreadAttrT* pattr, size_t cpusetsize,
|
||||
const Cpuset* cpusetp);
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_create(PthreadT* thread, const PthreadAttrT* attr,
|
||||
PthreadEntryFunc start_routine, void* arg);
|
||||
|
||||
|
@ -35,7 +41,7 @@ public:
|
|||
this->func = std::move(func);
|
||||
PthreadAttrT attr{};
|
||||
posix_pthread_attr_init(&attr);
|
||||
posix_pthread_create(&thread, &attr, RunWrapper, this);
|
||||
posix_pthread_create(&thread, &attr, HOST_CALL(RunWrapper), this);
|
||||
posix_pthread_attr_destroy(&attr);
|
||||
}
|
||||
|
||||
|
|
|
@ -315,7 +315,7 @@ int PS4_SYSV_ABI sceKernelPollEventFlag(OrbisKernelEventFlag ef, u64 bitPattern,
|
|||
auto result = ef->Poll(bitPattern, wait, clear, pResultPat);
|
||||
|
||||
if (result != ORBIS_OK && result != ORBIS_KERNEL_ERROR_EBUSY) {
|
||||
LOG_ERROR(Kernel_Event, "returned {}", result);
|
||||
LOG_DEBUG(Kernel_Event, "returned {:#x}", result);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -361,7 +361,7 @@ int PS4_SYSV_ABI sceKernelWaitEventFlag(OrbisKernelEventFlag ef, u64 bitPattern,
|
|||
u32 result = ef->Wait(bitPattern, wait, clear, pResultPat, pTimeout);
|
||||
|
||||
if (result != ORBIS_OK && result != ORBIS_KERNEL_ERROR_ETIMEDOUT) {
|
||||
LOG_ERROR(Kernel_Event, "returned {:#x}", result);
|
||||
LOG_DEBUG(Kernel_Event, "returned {:#x}", result);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "core/debug_state.h"
|
||||
#include "core/libraries/kernel/kernel.h"
|
||||
#include "core/libraries/kernel/posix_error.h"
|
||||
#include "core/libraries/kernel/threads.h"
|
||||
#include "core/libraries/kernel/threads/pthread.h"
|
||||
#include "core/libraries/kernel/threads/thread_state.h"
|
||||
#include "core/libraries/libs.h"
|
||||
|
@ -289,7 +290,12 @@ int PS4_SYSV_ABI posix_pthread_create_name_np(PthreadT* thread, const PthreadAtt
|
|||
/* Create thread */
|
||||
new_thread->native_thr = Core::NativeThread();
|
||||
int ret = new_thread->native_thr.Create(RunThread, new_thread, &new_thread->attr);
|
||||
|
||||
ASSERT_MSG(ret == 0, "Failed to create thread with error {}", ret);
|
||||
|
||||
if (attr != nullptr && *attr != nullptr && (*attr)->cpuset != nullptr) {
|
||||
new_thread->SetAffinity((*attr)->cpuset);
|
||||
}
|
||||
if (ret) {
|
||||
*thread = nullptr;
|
||||
}
|
||||
|
@ -521,6 +527,85 @@ int PS4_SYSV_ABI posix_pthread_setcancelstate(PthreadCancelState state,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int Pthread::SetAffinity(const Cpuset* cpuset) {
|
||||
const auto processor_count = std::thread::hardware_concurrency();
|
||||
if (processor_count < 8) {
|
||||
return 0;
|
||||
}
|
||||
if (cpuset == nullptr) {
|
||||
return POSIX_EINVAL;
|
||||
}
|
||||
|
||||
uintptr_t handle = native_thr.GetHandle();
|
||||
if (handle == 0) {
|
||||
return POSIX_ESRCH;
|
||||
}
|
||||
|
||||
// We don't use this currently because some games gets performance problems
|
||||
// when applying affinity even on strong hardware
|
||||
/*
|
||||
u64 mask = cpuset->bits;
|
||||
#ifdef _WIN64
|
||||
DWORD_PTR affinity_mask = static_cast<DWORD_PTR>(mask);
|
||||
if (!SetThreadAffinityMask(reinterpret_cast<HANDLE>(handle), affinity_mask)) {
|
||||
return POSIX_EINVAL;
|
||||
}
|
||||
|
||||
#elif defined(__linux__)
|
||||
cpu_set_t cpu_set;
|
||||
CPU_ZERO(&cpu_set);
|
||||
|
||||
u64 mask = cpuset->bits;
|
||||
for (int cpu = 0; cpu < std::min(64, CPU_SETSIZE); ++cpu) {
|
||||
if (mask & (1ULL << cpu)) {
|
||||
CPU_SET(cpu, &cpu_set);
|
||||
}
|
||||
}
|
||||
|
||||
int result =
|
||||
pthread_setaffinity_np(static_cast<pthread_t>(handle), sizeof(cpu_set_t), &cpu_set);
|
||||
if (result != 0) {
|
||||
return POSIX_EINVAL;
|
||||
}
|
||||
#endif
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_getaffinity_np(PthreadT thread, size_t cpusetsize, Cpuset* cpusetp) {
|
||||
if (thread == nullptr || cpusetp == nullptr) {
|
||||
return POSIX_EINVAL;
|
||||
}
|
||||
auto* attr_ptr = &thread->attr;
|
||||
return posix_pthread_attr_getaffinity_np(&attr_ptr, cpusetsize, cpusetp);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_setaffinity_np(PthreadT thread, size_t cpusetsize,
|
||||
const Cpuset* cpusetp) {
|
||||
if (thread == nullptr || cpusetp == nullptr) {
|
||||
return POSIX_EINVAL;
|
||||
}
|
||||
auto* attr_ptr = &thread->attr;
|
||||
if (const auto ret = posix_pthread_attr_setaffinity_np(&attr_ptr, cpusetsize, cpusetp)) {
|
||||
return ret;
|
||||
}
|
||||
return thread->SetAffinity(thread->attr.cpuset);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI scePthreadGetaffinity(PthreadT thread, u64* mask) {
|
||||
Cpuset cpuset;
|
||||
const int ret = posix_pthread_getaffinity_np(thread, sizeof(Cpuset), &cpuset);
|
||||
if (ret == 0) {
|
||||
*mask = cpuset.bits;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI scePthreadSetaffinity(PthreadT thread, const u64 mask) {
|
||||
const Cpuset cpuset = {.bits = mask};
|
||||
return posix_pthread_setaffinity_np(thread, sizeof(Cpuset), &cpuset);
|
||||
}
|
||||
|
||||
void RegisterThread(Core::Loader::SymbolsResolver* sym) {
|
||||
// Posix
|
||||
LIB_FUNCTION("Z4QosVuAsA0", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_once);
|
||||
|
@ -544,6 +629,8 @@ void RegisterThread(Core::Loader::SymbolsResolver* sym) {
|
|||
LIB_FUNCTION("Z4QosVuAsA0", "libkernel", 1, "libkernel", 1, 1, posix_pthread_once);
|
||||
LIB_FUNCTION("EotR8a3ASf4", "libkernel", 1, "libkernel", 1, 1, posix_pthread_self);
|
||||
LIB_FUNCTION("OxhIB8LB-PQ", "libkernel", 1, "libkernel", 1, 1, posix_pthread_create);
|
||||
LIB_FUNCTION("Jb2uGFMr688", "libkernel", 1, "libkernel", 1, 1, posix_pthread_getaffinity_np);
|
||||
LIB_FUNCTION("5KWrg7-ZqvE", "libkernel", 1, "libkernel", 1, 1, posix_pthread_setaffinity_np);
|
||||
|
||||
// Orbis
|
||||
LIB_FUNCTION("14bOACANTBo", "libkernel", 1, "libkernel", 1, 1, ORBIS(posix_pthread_once));
|
||||
|
@ -566,6 +653,8 @@ void RegisterThread(Core::Loader::SymbolsResolver* sym) {
|
|||
LIB_FUNCTION("W0Hpm2X0uPE", "libkernel", 1, "libkernel", 1, 1, ORBIS(posix_pthread_setprio));
|
||||
LIB_FUNCTION("rNhWz+lvOMU", "libkernel", 1, "libkernel", 1, 1, _sceKernelSetThreadDtors);
|
||||
LIB_FUNCTION("6XG4B33N09g", "libkernel", 1, "libkernel", 1, 1, sched_yield);
|
||||
LIB_FUNCTION("rcrVFJsQWRY", "libkernel", 1, "libkernel", 1, 1, ORBIS(scePthreadGetaffinity));
|
||||
LIB_FUNCTION("bt3CTBKmGyI", "libkernel", 1, "libkernel", 1, 1, ORBIS(scePthreadSetaffinity));
|
||||
}
|
||||
|
||||
} // namespace Libraries::Kernel
|
||||
|
|
|
@ -159,6 +159,7 @@ enum class SchedPolicy : u32 {
|
|||
|
||||
struct Cpuset {
|
||||
u64 bits;
|
||||
u64 _reserved;
|
||||
};
|
||||
|
||||
struct PthreadAttr {
|
||||
|
@ -269,7 +270,7 @@ struct Pthread {
|
|||
bool no_cancel;
|
||||
bool cancel_async;
|
||||
bool cancelling;
|
||||
Cpuset sigmask;
|
||||
u64 sigmask;
|
||||
bool unblock_sigcancel;
|
||||
bool in_sigsuspend;
|
||||
bool force_exit;
|
||||
|
@ -332,6 +333,8 @@ struct Pthread {
|
|||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
int SetAffinity(const Cpuset* cpuset);
|
||||
};
|
||||
using PthreadT = Pthread*;
|
||||
|
||||
|
|
|
@ -243,7 +243,7 @@ int PS4_SYSV_ABI posix_pthread_attr_getaffinity_np(const PthreadAttrT* pattr, si
|
|||
if (attr->cpuset != nullptr)
|
||||
memcpy(cpusetp, attr->cpuset, std::min(cpusetsize, attr->cpusetsize));
|
||||
else
|
||||
memset(cpusetp, -1, sizeof(Cpuset));
|
||||
memset(cpusetp, -1, cpusetsize);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -259,30 +259,31 @@ int PS4_SYSV_ABI posix_pthread_attr_setaffinity_np(PthreadAttrT* pattr, size_t c
|
|||
if (cpusetsize == 0 || cpusetp == nullptr) {
|
||||
if (attr->cpuset != nullptr) {
|
||||
free(attr->cpuset);
|
||||
attr->cpuset = NULL;
|
||||
attr->cpuset = nullptr;
|
||||
attr->cpusetsize = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (attr->cpuset == nullptr) {
|
||||
attr->cpuset = (Cpuset*)calloc(1, sizeof(Cpuset));
|
||||
attr->cpuset = static_cast<Cpuset*>(calloc(1, sizeof(Cpuset)));
|
||||
attr->cpusetsize = sizeof(Cpuset);
|
||||
}
|
||||
memcpy(attr->cpuset, cpusetp, sizeof(Cpuset));
|
||||
memcpy(attr->cpuset, cpusetp, std::min(cpusetsize, sizeof(Cpuset)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI scePthreadAttrGetaffinity(PthreadAttrT* param_1, Cpuset* mask) {
|
||||
int PS4_SYSV_ABI scePthreadAttrGetaffinity(PthreadAttrT* attr, u64* mask) {
|
||||
Cpuset cpuset;
|
||||
const int ret = posix_pthread_attr_getaffinity_np(param_1, 0x10, &cpuset);
|
||||
const int ret = posix_pthread_attr_getaffinity_np(attr, sizeof(Cpuset), &cpuset);
|
||||
if (ret == 0) {
|
||||
*mask = cpuset;
|
||||
*mask = cpuset.bits;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI scePthreadAttrSetaffinity(PthreadAttrT* attr, const Cpuset mask) {
|
||||
return posix_pthread_attr_setaffinity_np(attr, 0x10, &mask);
|
||||
int PS4_SYSV_ABI scePthreadAttrSetaffinity(PthreadAttrT* attr, const u64 mask) {
|
||||
const Cpuset cpuset = {.bits = mask};
|
||||
return posix_pthread_attr_setaffinity_np(attr, sizeof(Cpuset), &cpuset);
|
||||
}
|
||||
|
||||
void RegisterThreadAttr(Core::Loader::SymbolsResolver* sym) {
|
||||
|
|
|
@ -56,7 +56,6 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#include <cstdarg>
|
||||
#include <cstdbool>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "core/libraries/audio/audioout.h"
|
||||
#include "core/libraries/audio3d/audio3d.h"
|
||||
#include "core/libraries/avplayer/avplayer.h"
|
||||
#include "core/libraries/camera/camera.h"
|
||||
#include "core/libraries/disc_map/disc_map.h"
|
||||
#include "core/libraries/game_live_streaming/gamelivestreaming.h"
|
||||
#include "core/libraries/gnmdriver/gnmdriver.h"
|
||||
|
@ -45,6 +46,7 @@
|
|||
#include "core/libraries/save_data/savedata.h"
|
||||
#include "core/libraries/screenshot/screenshot.h"
|
||||
#include "core/libraries/share_play/shareplay.h"
|
||||
#include "core/libraries/signin_dialog/signindialog.h"
|
||||
#include "core/libraries/system/commondialog.h"
|
||||
#include "core/libraries/system/msgdialog.h"
|
||||
#include "core/libraries/system/posix.h"
|
||||
|
@ -120,6 +122,8 @@ void InitHLELibs(Core::Loader::SymbolsResolver* sym) {
|
|||
Libraries::Hmd::RegisterlibSceHmd(sym);
|
||||
Libraries::DiscMap::RegisterlibSceDiscMap(sym);
|
||||
Libraries::Ulobjmgr::RegisterlibSceUlobjmgr(sym);
|
||||
Libraries::SigninDialog::RegisterlibSceSigninDialog(sym);
|
||||
Libraries::Camera::RegisterlibSceCamera(sym);
|
||||
}
|
||||
|
||||
} // namespace Libraries
|
||||
|
|
|
@ -3,13 +3,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/loader/elf.h"
|
||||
#include "core/loader/symbols_resolver.h"
|
||||
|
||||
#define W(foo) foo
|
||||
#include "core/tls.h"
|
||||
|
||||
#define LIB_FUNCTION(nid, lib, libversion, mod, moduleVersionMajor, moduleVersionMinor, function) \
|
||||
{ \
|
||||
|
@ -21,11 +17,11 @@
|
|||
sr.module_version_major = moduleVersionMajor; \
|
||||
sr.module_version_minor = moduleVersionMinor; \
|
||||
sr.type = Core::Loader::SymbolType::Function; \
|
||||
auto func = reinterpret_cast<u64>(function); \
|
||||
auto func = reinterpret_cast<u64>(HOST_CALL(function)); \
|
||||
sym->AddSymbol(sr, func); \
|
||||
}
|
||||
|
||||
#define LIB_OBJ(nid, lib, libversion, mod, moduleVersionMajor, moduleVersionMinor, function) \
|
||||
#define LIB_OBJ(nid, lib, libversion, mod, moduleVersionMajor, moduleVersionMinor, obj) \
|
||||
{ \
|
||||
Core::Loader::SymbolResolver sr{}; \
|
||||
sr.name = nid; \
|
||||
|
@ -35,8 +31,7 @@
|
|||
sr.module_version_major = moduleVersionMajor; \
|
||||
sr.module_version_minor = moduleVersionMinor; \
|
||||
sr.type = Core::Loader::SymbolType::Object; \
|
||||
auto func = reinterpret_cast<u64>(function); \
|
||||
sym->AddSymbol(sr, func); \
|
||||
sym->AddSymbol(sr, reinterpret_cast<u64>(obj)); \
|
||||
}
|
||||
|
||||
namespace Libraries {
|
||||
|
|
|
@ -10,16 +10,24 @@
|
|||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#include <core/libraries/kernel/kernel.h>
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/singleton.h"
|
||||
#include "core/libraries/error_codes.h"
|
||||
#include "core/libraries/libs.h"
|
||||
#include "core/libraries/network/net.h"
|
||||
#include "net_error.h"
|
||||
#include "net_util.h"
|
||||
#include "netctl.h"
|
||||
#include "sys_net.h"
|
||||
|
||||
namespace Libraries::Net {
|
||||
|
||||
static thread_local int32_t net_errno = 0;
|
||||
|
||||
static bool g_isNetInitialized = true; // TODO init it properly
|
||||
|
||||
int PS4_SYSV_ABI in6addr_any() {
|
||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
|
@ -61,8 +69,45 @@ int PS4_SYSV_ABI sce_net_in6addr_nodelocal_allnodes() {
|
|||
}
|
||||
|
||||
OrbisNetId PS4_SYSV_ABI sceNetAccept(OrbisNetId s, OrbisNetSockaddr* addr, u32* paddrlen) {
|
||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
if (!g_isNetInitialized) {
|
||||
return ORBIS_NET_ERROR_ENOTINIT;
|
||||
}
|
||||
int result;
|
||||
int err;
|
||||
int positiveErr;
|
||||
|
||||
do {
|
||||
result = sys_accept(s, addr, paddrlen);
|
||||
|
||||
if (result >= 0) {
|
||||
return result; // Success
|
||||
}
|
||||
|
||||
err = *Libraries::Kernel::__Error(); // Standard errno
|
||||
|
||||
// Convert to positive error for comparison
|
||||
int positiveErr = (err < 0) ? -err : err;
|
||||
|
||||
if ((positiveErr & 0xfff0000) != 0) {
|
||||
// Unknown/fatal error range
|
||||
*sceNetErrnoLoc() = ORBIS_NET_ERETURN;
|
||||
return -positiveErr;
|
||||
}
|
||||
|
||||
// Retry if interrupted
|
||||
} while (positiveErr == ORBIS_NET_EINTR);
|
||||
|
||||
if (positiveErr == ORBIS_NET_EADDRINUSE) {
|
||||
result = -ORBIS_NET_EBADF;
|
||||
} else if (positiveErr == ORBIS_NET_EALREADY) {
|
||||
result = -ORBIS_NET_EINTR;
|
||||
} else {
|
||||
result = -positiveErr;
|
||||
}
|
||||
|
||||
*sceNetErrnoLoc() = -result;
|
||||
|
||||
return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNetAddrConfig6GetInfo() {
|
||||
|
@ -121,8 +166,45 @@ int PS4_SYSV_ABI sceNetBandwidthControlSetPolicy() {
|
|||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNetBind(OrbisNetId s, const OrbisNetSockaddr* addr, u32 addrlen) {
|
||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
if (!g_isNetInitialized) {
|
||||
return ORBIS_NET_ERROR_ENOTINIT;
|
||||
}
|
||||
int result;
|
||||
int err;
|
||||
int positiveErr;
|
||||
|
||||
do {
|
||||
result = sys_bind(s, addr, addrlen);
|
||||
|
||||
if (result >= 0) {
|
||||
return result; // Success
|
||||
}
|
||||
|
||||
err = *Libraries::Kernel::__Error(); // Standard errno
|
||||
|
||||
// Convert to positive error for comparison
|
||||
int positiveErr = (err < 0) ? -err : err;
|
||||
|
||||
if ((positiveErr & 0xfff0000) != 0) {
|
||||
// Unknown/fatal error range
|
||||
*sceNetErrnoLoc() = ORBIS_NET_ERETURN;
|
||||
return -positiveErr;
|
||||
}
|
||||
|
||||
// Retry if interrupted
|
||||
} while (positiveErr == ORBIS_NET_EINTR);
|
||||
|
||||
if (positiveErr == ORBIS_NET_EADDRINUSE) {
|
||||
result = -ORBIS_NET_EBADF;
|
||||
} else if (positiveErr == ORBIS_NET_EALREADY) {
|
||||
result = -ORBIS_NET_EINTR;
|
||||
} else {
|
||||
result = -positiveErr;
|
||||
}
|
||||
|
||||
*sceNetErrnoLoc() = -result;
|
||||
|
||||
return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNetClearDnsCache() {
|
||||
|
@ -465,9 +547,46 @@ int PS4_SYSV_ABI sceNetConfigWlanSetDeviceConfig() {
|
|||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNetConnect() {
|
||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
int PS4_SYSV_ABI sceNetConnect(OrbisNetId s, const OrbisNetSockaddr* addr, u32 addrlen) {
|
||||
if (!g_isNetInitialized) {
|
||||
return ORBIS_NET_ERROR_ENOTINIT;
|
||||
}
|
||||
int result;
|
||||
int err;
|
||||
int positiveErr;
|
||||
|
||||
do {
|
||||
result = sys_connect(s, addr, addrlen);
|
||||
|
||||
if (result >= 0) {
|
||||
return result; // Success
|
||||
}
|
||||
|
||||
err = *Libraries::Kernel::__Error(); // Standard errno
|
||||
|
||||
// Convert to positive error for comparison
|
||||
int positiveErr = (err < 0) ? -err : err;
|
||||
|
||||
if ((positiveErr & 0xfff0000) != 0) {
|
||||
// Unknown/fatal error range
|
||||
*sceNetErrnoLoc() = ORBIS_NET_ERETURN;
|
||||
return -positiveErr;
|
||||
}
|
||||
|
||||
// Retry if interrupted
|
||||
} while (positiveErr == ORBIS_NET_EINTR);
|
||||
|
||||
if (positiveErr == ORBIS_NET_EADDRINUSE) {
|
||||
result = -ORBIS_NET_EBADF;
|
||||
} else if (positiveErr == ORBIS_NET_EALREADY) {
|
||||
result = -ORBIS_NET_EINTR;
|
||||
} else {
|
||||
result = -positiveErr;
|
||||
}
|
||||
|
||||
*sceNetErrnoLoc() = -result;
|
||||
|
||||
return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNetControl() {
|
||||
|
@ -640,8 +759,15 @@ int PS4_SYSV_ABI sceNetGetIfnameNumList() {
|
|||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNetGetMacAddress() {
|
||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||
int PS4_SYSV_ABI sceNetGetMacAddress(Libraries::NetCtl::OrbisNetEtherAddr* addr, int flags) {
|
||||
if (addr == nullptr) {
|
||||
LOG_ERROR(Lib_Net, "addr is null!");
|
||||
return ORBIS_NET_EINVAL;
|
||||
}
|
||||
auto* netinfo = Common::Singleton<NetUtil::NetUtilInternal>::Instance();
|
||||
netinfo->RetrieveEthernetAddr();
|
||||
memcpy(addr->data, netinfo->GetEthernetAddr().data(), 6);
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
|
@ -655,9 +781,46 @@ int PS4_SYSV_ABI sceNetGetNameToIndex() {
|
|||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNetGetpeername() {
|
||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
int PS4_SYSV_ABI sceNetGetpeername(OrbisNetId s, OrbisNetSockaddr* addr, u32* paddrlen) {
|
||||
if (!g_isNetInitialized) {
|
||||
return ORBIS_NET_ERROR_ENOTINIT;
|
||||
}
|
||||
int result;
|
||||
int err;
|
||||
int positiveErr;
|
||||
|
||||
do {
|
||||
result = sys_getpeername(s, addr, paddrlen);
|
||||
|
||||
if (result >= 0) {
|
||||
return result; // Success
|
||||
}
|
||||
|
||||
err = *Libraries::Kernel::__Error(); // Standard errno
|
||||
|
||||
// Convert to positive error for comparison
|
||||
int positiveErr = (err < 0) ? -err : err;
|
||||
|
||||
if ((positiveErr & 0xfff0000) != 0) {
|
||||
// Unknown/fatal error range
|
||||
*sceNetErrnoLoc() = ORBIS_NET_ERETURN;
|
||||
return -positiveErr;
|
||||
}
|
||||
|
||||
// Retry if interrupted
|
||||
} while (positiveErr == ORBIS_NET_EINTR);
|
||||
|
||||
if (positiveErr == ORBIS_NET_EADDRINUSE) {
|
||||
result = -ORBIS_NET_EBADF;
|
||||
} else if (positiveErr == ORBIS_NET_EALREADY) {
|
||||
result = -ORBIS_NET_EINTR;
|
||||
} else {
|
||||
result = -positiveErr;
|
||||
}
|
||||
|
||||
*sceNetErrnoLoc() = -result;
|
||||
|
||||
return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNetGetRandom() {
|
||||
|
@ -681,13 +844,88 @@ int PS4_SYSV_ABI sceNetGetSockInfo6() {
|
|||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNetGetsockname(OrbisNetId s, OrbisNetSockaddr* addr, u32* paddrlen) {
|
||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
if (!g_isNetInitialized) {
|
||||
return ORBIS_NET_ERROR_ENOTINIT;
|
||||
}
|
||||
int result;
|
||||
int err;
|
||||
int positiveErr;
|
||||
|
||||
do {
|
||||
result = sys_getsockname(s, addr, paddrlen);
|
||||
|
||||
if (result >= 0) {
|
||||
return result; // Success
|
||||
}
|
||||
|
||||
err = *Libraries::Kernel::__Error(); // Standard errno
|
||||
|
||||
// Convert to positive error for comparison
|
||||
int positiveErr = (err < 0) ? -err : err;
|
||||
|
||||
if ((positiveErr & 0xfff0000) != 0) {
|
||||
// Unknown/fatal error range
|
||||
*sceNetErrnoLoc() = ORBIS_NET_ERETURN;
|
||||
return -positiveErr;
|
||||
}
|
||||
|
||||
// Retry if interrupted
|
||||
} while (positiveErr == ORBIS_NET_EINTR);
|
||||
|
||||
if (positiveErr == ORBIS_NET_EADDRINUSE) {
|
||||
result = -ORBIS_NET_EBADF;
|
||||
} else if (positiveErr == ORBIS_NET_EALREADY) {
|
||||
result = -ORBIS_NET_EINTR;
|
||||
} else {
|
||||
result = -positiveErr;
|
||||
}
|
||||
|
||||
*sceNetErrnoLoc() = -result;
|
||||
|
||||
return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNetGetsockopt(OrbisNetId s, int level, int optname, void* optval, u32* optlen) {
|
||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
LOG_INFO(Lib_Net, "s={} level={} optname={}", s, level, optname);
|
||||
if (!g_isNetInitialized) {
|
||||
return ORBIS_NET_ERROR_ENOTINIT;
|
||||
}
|
||||
int result;
|
||||
int err;
|
||||
int positiveErr;
|
||||
|
||||
do {
|
||||
result = sys_getsockopt(s, level, optname, optval, optlen);
|
||||
|
||||
if (result >= 0) {
|
||||
return result; // Success
|
||||
}
|
||||
|
||||
err = *Libraries::Kernel::__Error(); // Standard errno
|
||||
|
||||
// Convert to positive error for comparison
|
||||
int positiveErr = (err < 0) ? -err : err;
|
||||
|
||||
if ((positiveErr & 0xfff0000) != 0) {
|
||||
// Unknown/fatal error range
|
||||
*sceNetErrnoLoc() = ORBIS_NET_ERETURN;
|
||||
return -positiveErr;
|
||||
}
|
||||
|
||||
// Retry if interrupted
|
||||
} while (positiveErr == ORBIS_NET_EINTR);
|
||||
|
||||
if (positiveErr == ORBIS_NET_EADDRINUSE) {
|
||||
result = -ORBIS_NET_EBADF;
|
||||
} else if (positiveErr == ORBIS_NET_EALREADY) {
|
||||
result = -ORBIS_NET_EINTR;
|
||||
} else {
|
||||
result = -positiveErr;
|
||||
}
|
||||
|
||||
*sceNetErrnoLoc() = -result;
|
||||
|
||||
return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNetGetStatisticsInfo() {
|
||||
|
@ -781,9 +1019,46 @@ int PS4_SYSV_ABI sceNetIoctl() {
|
|||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNetListen() {
|
||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
int PS4_SYSV_ABI sceNetListen(OrbisNetId s, int backlog) {
|
||||
if (!g_isNetInitialized) {
|
||||
return ORBIS_NET_ERROR_ENOTINIT;
|
||||
}
|
||||
int result;
|
||||
int err;
|
||||
int positiveErr;
|
||||
|
||||
do {
|
||||
result = sys_listen(s, backlog);
|
||||
|
||||
if (result >= 0) {
|
||||
return result; // Success
|
||||
}
|
||||
|
||||
err = *Libraries::Kernel::__Error(); // Standard errno
|
||||
|
||||
// Convert to positive error for comparison
|
||||
int positiveErr = (err < 0) ? -err : err;
|
||||
|
||||
if ((positiveErr & 0xfff0000) != 0) {
|
||||
// Unknown/fatal error range
|
||||
*sceNetErrnoLoc() = ORBIS_NET_ERETURN;
|
||||
return -positiveErr;
|
||||
}
|
||||
|
||||
// Retry if interrupted
|
||||
} while (positiveErr == ORBIS_NET_EINTR);
|
||||
|
||||
if (positiveErr == ORBIS_NET_EADDRINUSE) {
|
||||
result = -ORBIS_NET_EBADF;
|
||||
} else if (positiveErr == ORBIS_NET_EALREADY) {
|
||||
result = -ORBIS_NET_EINTR;
|
||||
} else {
|
||||
result = -positiveErr;
|
||||
}
|
||||
|
||||
*sceNetErrnoLoc() = -result;
|
||||
|
||||
return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNetMemoryAllocate() {
|
||||
|
@ -829,20 +1104,131 @@ int PS4_SYSV_ABI sceNetPppoeStop() {
|
|||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNetRecv() {
|
||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
int PS4_SYSV_ABI sceNetRecv(OrbisNetId s, void* buf, u64 len, int flags) {
|
||||
if (!g_isNetInitialized) {
|
||||
return ORBIS_NET_ERROR_ENOTINIT;
|
||||
}
|
||||
int result;
|
||||
int err;
|
||||
int positiveErr;
|
||||
|
||||
do {
|
||||
result = sys_recvfrom(s, buf, len, flags | 0x40000000, nullptr, 0);
|
||||
|
||||
if (result >= 0) {
|
||||
return result; // Success
|
||||
}
|
||||
|
||||
err = *Libraries::Kernel::__Error(); // Standard errno
|
||||
|
||||
// Convert to positive error for comparison
|
||||
int positiveErr = (err < 0) ? -err : err;
|
||||
|
||||
if ((positiveErr & 0xfff0000) != 0) {
|
||||
// Unknown/fatal error range
|
||||
*sceNetErrnoLoc() = ORBIS_NET_ERETURN;
|
||||
return -positiveErr;
|
||||
}
|
||||
|
||||
// Retry if interrupted
|
||||
} while (positiveErr == ORBIS_NET_EINTR);
|
||||
|
||||
if (positiveErr == ORBIS_NET_EADDRINUSE) {
|
||||
result = -ORBIS_NET_EBADF;
|
||||
} else if (positiveErr == ORBIS_NET_EALREADY) {
|
||||
result = -ORBIS_NET_EINTR;
|
||||
} else {
|
||||
result = -positiveErr;
|
||||
}
|
||||
|
||||
*sceNetErrnoLoc() = -result;
|
||||
|
||||
return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNetRecvfrom(OrbisNetId s, void* buf, size_t len, int flags,
|
||||
OrbisNetSockaddr* addr, u32* paddrlen) {
|
||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
int PS4_SYSV_ABI sceNetRecvfrom(OrbisNetId s, void* buf, u64 len, int flags, OrbisNetSockaddr* addr,
|
||||
u32* paddrlen) {
|
||||
if (!g_isNetInitialized) {
|
||||
return ORBIS_NET_ERROR_ENOTINIT;
|
||||
}
|
||||
int result;
|
||||
int err;
|
||||
int positiveErr;
|
||||
|
||||
do {
|
||||
result = sys_recvfrom(s, buf, len, flags | 0x40000000, addr, paddrlen);
|
||||
|
||||
if (result >= 0) {
|
||||
return result; // Success
|
||||
}
|
||||
|
||||
err = *Libraries::Kernel::__Error(); // Standard errno
|
||||
|
||||
// Convert to positive error for comparison
|
||||
int positiveErr = (err < 0) ? -err : err;
|
||||
|
||||
if ((positiveErr & 0xfff0000) != 0) {
|
||||
// Unknown/fatal error range
|
||||
*sceNetErrnoLoc() = ORBIS_NET_ERETURN;
|
||||
return -positiveErr;
|
||||
}
|
||||
|
||||
// Retry if interrupted
|
||||
} while (positiveErr == ORBIS_NET_EINTR);
|
||||
|
||||
if (positiveErr == ORBIS_NET_EADDRINUSE) {
|
||||
result = -ORBIS_NET_EBADF;
|
||||
} else if (positiveErr == ORBIS_NET_EALREADY) {
|
||||
result = -ORBIS_NET_EINTR;
|
||||
} else {
|
||||
result = -positiveErr;
|
||||
}
|
||||
|
||||
*sceNetErrnoLoc() = -result;
|
||||
|
||||
return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNetRecvmsg() {
|
||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
int PS4_SYSV_ABI sceNetRecvmsg(OrbisNetId s, OrbisNetMsghdr* msg, int flags) {
|
||||
if (!g_isNetInitialized) {
|
||||
return ORBIS_NET_ERROR_ENOTINIT;
|
||||
}
|
||||
int result;
|
||||
int err;
|
||||
int positiveErr;
|
||||
|
||||
do {
|
||||
result = sys_recvmsg(s, msg, flags | 0x40000000);
|
||||
|
||||
if (result >= 0) {
|
||||
return result; // Success
|
||||
}
|
||||
|
||||
err = *Libraries::Kernel::__Error(); // Standard errno
|
||||
|
||||
// Convert to positive error for comparison
|
||||
int positiveErr = (err < 0) ? -err : err;
|
||||
|
||||
if ((positiveErr & 0xfff0000) != 0) {
|
||||
// Unknown/fatal error range
|
||||
*sceNetErrnoLoc() = ORBIS_NET_ERETURN;
|
||||
return -positiveErr;
|
||||
}
|
||||
|
||||
// Retry if interrupted
|
||||
} while (positiveErr == ORBIS_NET_EINTR);
|
||||
|
||||
if (positiveErr == ORBIS_NET_EADDRINUSE) {
|
||||
result = -ORBIS_NET_EBADF;
|
||||
} else if (positiveErr == ORBIS_NET_EALREADY) {
|
||||
result = -ORBIS_NET_EINTR;
|
||||
} else {
|
||||
result = -positiveErr;
|
||||
}
|
||||
|
||||
*sceNetErrnoLoc() = -result;
|
||||
|
||||
return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNetResolverAbort() {
|
||||
|
@ -915,19 +1301,131 @@ int PS4_SYSV_ABI sceNetResolverStartNtoaMultipleRecordsEx() {
|
|||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNetSend() {
|
||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
int PS4_SYSV_ABI sceNetSend(OrbisNetId s, const void* buf, u64 len, int flags) {
|
||||
if (!g_isNetInitialized) {
|
||||
return ORBIS_NET_ERROR_ENOTINIT;
|
||||
}
|
||||
int result;
|
||||
int err;
|
||||
int positiveErr;
|
||||
|
||||
do {
|
||||
result = sys_sendto(s, buf, len, flags | 0x40020000, nullptr, 0);
|
||||
|
||||
if (result >= 0) {
|
||||
return result; // Success
|
||||
}
|
||||
|
||||
err = *Libraries::Kernel::__Error(); // Standard errno
|
||||
|
||||
// Convert to positive error for comparison
|
||||
int positiveErr = (err < 0) ? -err : err;
|
||||
|
||||
if ((positiveErr & 0xfff0000) != 0) {
|
||||
// Unknown/fatal error range
|
||||
*sceNetErrnoLoc() = ORBIS_NET_ERETURN;
|
||||
return -positiveErr;
|
||||
}
|
||||
|
||||
// Retry if interrupted
|
||||
} while (positiveErr == ORBIS_NET_EINTR);
|
||||
|
||||
if (positiveErr == ORBIS_NET_EADDRINUSE) {
|
||||
result = -ORBIS_NET_EBADF;
|
||||
} else if (positiveErr == ORBIS_NET_EALREADY) {
|
||||
result = -ORBIS_NET_EINTR;
|
||||
} else {
|
||||
result = -positiveErr;
|
||||
}
|
||||
|
||||
*sceNetErrnoLoc() = -result;
|
||||
|
||||
return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNetSendmsg() {
|
||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
int PS4_SYSV_ABI sceNetSendmsg(OrbisNetId s, const OrbisNetMsghdr* msg, int flags) {
|
||||
if (!g_isNetInitialized) {
|
||||
return ORBIS_NET_ERROR_ENOTINIT;
|
||||
}
|
||||
int result;
|
||||
int err;
|
||||
int positiveErr;
|
||||
|
||||
do {
|
||||
result = sys_sendmsg(s, msg, flags | 0x40020000);
|
||||
|
||||
if (result >= 0) {
|
||||
return result; // Success
|
||||
}
|
||||
|
||||
err = *Libraries::Kernel::__Error(); // Standard errno
|
||||
|
||||
// Convert to positive error for comparison
|
||||
int positiveErr = (err < 0) ? -err : err;
|
||||
|
||||
if ((positiveErr & 0xfff0000) != 0) {
|
||||
// Unknown/fatal error range
|
||||
*sceNetErrnoLoc() = ORBIS_NET_ERETURN;
|
||||
return -positiveErr;
|
||||
}
|
||||
|
||||
// Retry if interrupted
|
||||
} while (positiveErr == ORBIS_NET_EINTR);
|
||||
|
||||
if (positiveErr == ORBIS_NET_EADDRINUSE) {
|
||||
result = -ORBIS_NET_EBADF;
|
||||
} else if (positiveErr == ORBIS_NET_EALREADY) {
|
||||
result = -ORBIS_NET_EINTR;
|
||||
} else {
|
||||
result = -positiveErr;
|
||||
}
|
||||
|
||||
*sceNetErrnoLoc() = -result;
|
||||
|
||||
return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNetSendto() {
|
||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
int PS4_SYSV_ABI sceNetSendto(OrbisNetId s, const void* buf, u64 len, int flags,
|
||||
const OrbisNetSockaddr* addr, u32 addrlen) {
|
||||
if (!g_isNetInitialized) {
|
||||
return ORBIS_NET_ERROR_ENOTINIT;
|
||||
}
|
||||
int result;
|
||||
int err;
|
||||
int positiveErr;
|
||||
|
||||
do {
|
||||
result = sys_sendto(s, buf, len, flags | 0x40020000, addr, addrlen);
|
||||
|
||||
if (result >= 0) {
|
||||
return result; // Success
|
||||
}
|
||||
|
||||
err = *Libraries::Kernel::__Error(); // Standard errno
|
||||
|
||||
// Convert to positive error for comparison
|
||||
int positiveErr = (err < 0) ? -err : err;
|
||||
|
||||
if ((positiveErr & 0xfff0000) != 0) {
|
||||
// Unknown/fatal error range
|
||||
*sceNetErrnoLoc() = ORBIS_NET_ERETURN;
|
||||
return -positiveErr;
|
||||
}
|
||||
|
||||
// Retry if interrupted
|
||||
} while (positiveErr == ORBIS_NET_EINTR);
|
||||
|
||||
if (positiveErr == ORBIS_NET_EADDRINUSE) {
|
||||
result = -ORBIS_NET_EBADF;
|
||||
} else if (positiveErr == ORBIS_NET_EALREADY) {
|
||||
result = -ORBIS_NET_EINTR;
|
||||
} else {
|
||||
result = -positiveErr;
|
||||
}
|
||||
|
||||
*sceNetErrnoLoc() = -result;
|
||||
|
||||
return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNetSetDns6Info() {
|
||||
|
@ -950,9 +1448,48 @@ int PS4_SYSV_ABI sceNetSetDnsInfoToKernel() {
|
|||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNetSetsockopt() {
|
||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
int PS4_SYSV_ABI sceNetSetsockopt(OrbisNetId s, int level, int optname, const void* optval,
|
||||
u32 optlen) {
|
||||
LOG_INFO(Lib_Net, "s={} level={} optname={} optlen={}", s, level, optname, optlen);
|
||||
if (!g_isNetInitialized) {
|
||||
return ORBIS_NET_ERROR_ENOTINIT;
|
||||
}
|
||||
int result;
|
||||
int err;
|
||||
int positiveErr;
|
||||
|
||||
do {
|
||||
result = sys_setsockopt(s, level, optname, optval, optlen);
|
||||
|
||||
if (result >= 0) {
|
||||
return result; // Success
|
||||
}
|
||||
|
||||
err = *Libraries::Kernel::__Error(); // Standard errno
|
||||
|
||||
// Convert to positive error for comparison
|
||||
int positiveErr = (err < 0) ? -err : err;
|
||||
|
||||
if ((positiveErr & 0xfff0000) != 0) {
|
||||
// Unknown/fatal error range
|
||||
*sceNetErrnoLoc() = ORBIS_NET_ERETURN;
|
||||
return -positiveErr;
|
||||
}
|
||||
|
||||
// Retry if interrupted
|
||||
} while (positiveErr == ORBIS_NET_EINTR);
|
||||
|
||||
if (positiveErr == ORBIS_NET_EADDRINUSE) {
|
||||
result = -ORBIS_NET_EBADF;
|
||||
} else if (positiveErr == ORBIS_NET_EALREADY) {
|
||||
result = -ORBIS_NET_EINTR;
|
||||
} else {
|
||||
result = -positiveErr;
|
||||
}
|
||||
|
||||
*sceNetErrnoLoc() = -result;
|
||||
|
||||
return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNetShowIfconfig() {
|
||||
|
@ -1035,24 +1572,172 @@ int PS4_SYSV_ABI sceNetShowRouteWithMemory() {
|
|||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNetShutdown() {
|
||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
int PS4_SYSV_ABI sceNetShutdown(OrbisNetId s, int how) {
|
||||
if (!g_isNetInitialized) {
|
||||
return ORBIS_NET_ERROR_ENOTINIT;
|
||||
}
|
||||
int result;
|
||||
int err;
|
||||
int positiveErr;
|
||||
|
||||
do {
|
||||
result = sys_shutdown(s, how);
|
||||
|
||||
if (result >= 0) {
|
||||
return result; // Success
|
||||
}
|
||||
|
||||
err = *Libraries::Kernel::__Error(); // Standard errno
|
||||
|
||||
// Convert to positive error for comparison
|
||||
int positiveErr = (err < 0) ? -err : err;
|
||||
|
||||
if ((positiveErr & 0xfff0000) != 0) {
|
||||
// Unknown/fatal error range
|
||||
*sceNetErrnoLoc() = ORBIS_NET_ERETURN;
|
||||
return -positiveErr;
|
||||
}
|
||||
|
||||
// Retry if interrupted
|
||||
} while (positiveErr == ORBIS_NET_EINTR);
|
||||
|
||||
if (positiveErr == ORBIS_NET_EADDRINUSE) {
|
||||
result = -ORBIS_NET_EBADF;
|
||||
} else if (positiveErr == ORBIS_NET_EALREADY) {
|
||||
result = -ORBIS_NET_EINTR;
|
||||
} else {
|
||||
result = -positiveErr;
|
||||
}
|
||||
|
||||
*sceNetErrnoLoc() = -result;
|
||||
|
||||
return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNetSocket(const char* name, int family, int type, int protocol) {
|
||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
OrbisNetId PS4_SYSV_ABI sceNetSocket(const char* name, int family, int type, int protocol) {
|
||||
if (!g_isNetInitialized) {
|
||||
return ORBIS_NET_ERROR_ENOTINIT;
|
||||
}
|
||||
int result;
|
||||
int err;
|
||||
int positiveErr;
|
||||
|
||||
do {
|
||||
result = sys_socketex(name, family, type, protocol);
|
||||
|
||||
if (result >= 0) {
|
||||
return result; // Success
|
||||
}
|
||||
|
||||
err = *Libraries::Kernel::__Error(); // Standard errno
|
||||
|
||||
// Convert to positive error for comparison
|
||||
int positiveErr = (err < 0) ? -err : err;
|
||||
|
||||
if ((positiveErr & 0xfff0000) != 0) {
|
||||
// Unknown/fatal error range
|
||||
*sceNetErrnoLoc() = ORBIS_NET_ERETURN;
|
||||
return -positiveErr;
|
||||
}
|
||||
|
||||
// Retry if interrupted
|
||||
} while (positiveErr == ORBIS_NET_EINTR);
|
||||
|
||||
if (positiveErr == ORBIS_NET_EADDRINUSE) {
|
||||
result = -ORBIS_NET_EBADF;
|
||||
} else if (positiveErr == ORBIS_NET_EALREADY) {
|
||||
result = -ORBIS_NET_EINTR;
|
||||
} else {
|
||||
result = -positiveErr;
|
||||
}
|
||||
|
||||
*sceNetErrnoLoc() = -result;
|
||||
|
||||
return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNetSocketAbort() {
|
||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
int PS4_SYSV_ABI sceNetSocketAbort(OrbisNetId s, int flags) {
|
||||
if (!g_isNetInitialized) {
|
||||
return ORBIS_NET_ERROR_ENOTINIT;
|
||||
}
|
||||
int result;
|
||||
int err;
|
||||
int positiveErr;
|
||||
|
||||
do {
|
||||
result = sys_netabort(s, flags);
|
||||
|
||||
if (result >= 0) {
|
||||
return result; // Success
|
||||
}
|
||||
|
||||
err = *Libraries::Kernel::__Error(); // Standard errno
|
||||
|
||||
// Convert to positive error for comparison
|
||||
int positiveErr = (err < 0) ? -err : err;
|
||||
|
||||
if ((positiveErr & 0xfff0000) != 0) {
|
||||
// Unknown/fatal error range
|
||||
*sceNetErrnoLoc() = ORBIS_NET_ERETURN;
|
||||
return -positiveErr;
|
||||
}
|
||||
|
||||
// Retry if interrupted
|
||||
} while (positiveErr == ORBIS_NET_EINTR);
|
||||
|
||||
if (positiveErr == ORBIS_NET_EADDRINUSE) {
|
||||
result = -ORBIS_NET_EBADF;
|
||||
} else if (positiveErr == ORBIS_NET_EALREADY) {
|
||||
result = -ORBIS_NET_EINTR;
|
||||
} else {
|
||||
result = -positiveErr;
|
||||
}
|
||||
|
||||
*sceNetErrnoLoc() = -result;
|
||||
|
||||
return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNetSocketClose() {
|
||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
int PS4_SYSV_ABI sceNetSocketClose(OrbisNetId s) {
|
||||
if (!g_isNetInitialized) {
|
||||
return ORBIS_NET_ERROR_ENOTINIT;
|
||||
}
|
||||
int result;
|
||||
int err;
|
||||
int positiveErr;
|
||||
|
||||
do {
|
||||
result = sys_socketclose(s);
|
||||
|
||||
if (result >= 0) {
|
||||
return result; // Success
|
||||
}
|
||||
|
||||
err = *Libraries::Kernel::__Error(); // Standard errno
|
||||
|
||||
// Convert to positive error for comparison
|
||||
int positiveErr = (err < 0) ? -err : err;
|
||||
|
||||
if ((positiveErr & 0xfff0000) != 0) {
|
||||
// Unknown/fatal error range
|
||||
*sceNetErrnoLoc() = ORBIS_NET_ERETURN;
|
||||
return -positiveErr;
|
||||
}
|
||||
|
||||
// Retry if interrupted
|
||||
} while (positiveErr == ORBIS_NET_EINTR);
|
||||
|
||||
if (positiveErr == ORBIS_NET_EADDRINUSE) {
|
||||
result = -ORBIS_NET_EBADF;
|
||||
} else if (positiveErr == ORBIS_NET_EALREADY) {
|
||||
result = -ORBIS_NET_EINTR;
|
||||
} else {
|
||||
result = -positiveErr;
|
||||
}
|
||||
|
||||
*sceNetErrnoLoc() = -result;
|
||||
|
||||
return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNetSyncCreate() {
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "common/types.h"
|
||||
#include "netctl.h"
|
||||
|
||||
namespace Core::Loader {
|
||||
class SymbolsResolver;
|
||||
|
@ -19,6 +20,63 @@ class SymbolsResolver;
|
|||
|
||||
namespace Libraries::Net {
|
||||
|
||||
enum OrbisNetSocketType : u32 {
|
||||
ORBIS_NET_SOCK_STREAM = 1,
|
||||
ORBIS_NET_SOCK_DGRAM = 2,
|
||||
ORBIS_NET_SOCK_RAW = 3,
|
||||
ORBIS_NET_SOCK_DGRAM_P2P = 6,
|
||||
ORBIS_NET_SOCK_STREAM_P2P = 10
|
||||
};
|
||||
|
||||
enum OrbisNetProtocol : u32 {
|
||||
ORBIS_NET_IPPROTO_IP = 0,
|
||||
ORBIS_NET_IPPROTO_ICMP = 1,
|
||||
ORBIS_NET_IPPROTO_IGMP = 2,
|
||||
ORBIS_NET_IPPROTO_TCP = 6,
|
||||
ORBIS_NET_IPPROTO_UDP = 17,
|
||||
ORBIS_NET_SOL_SOCKET = 0xFFFF
|
||||
};
|
||||
|
||||
enum OrbisNetSocketOption : u32 {
|
||||
/* IP */
|
||||
ORBIS_NET_IP_HDRINCL = 2,
|
||||
ORBIS_NET_IP_TOS = 3,
|
||||
ORBIS_NET_IP_TTL = 4,
|
||||
ORBIS_NET_IP_MULTICAST_IF = 9,
|
||||
ORBIS_NET_IP_MULTICAST_TTL = 10,
|
||||
ORBIS_NET_IP_MULTICAST_LOOP = 11,
|
||||
ORBIS_NET_IP_ADD_MEMBERSHIP = 12,
|
||||
ORBIS_NET_IP_DROP_MEMBERSHIP = 13,
|
||||
ORBIS_NET_IP_TTLCHK = 23,
|
||||
ORBIS_NET_IP_MAXTTL = 24,
|
||||
/* TCP */
|
||||
ORBIS_NET_TCP_NODELAY = 1,
|
||||
ORBIS_NET_TCP_MAXSEG = 2,
|
||||
ORBIS_NET_TCP_MSS_TO_ADVERTISE = 3,
|
||||
/* SOCKET */
|
||||
ORBIS_NET_SO_REUSEADDR = 0x00000004,
|
||||
ORBIS_NET_SO_KEEPALIVE = 0x00000008,
|
||||
ORBIS_NET_SO_BROADCAST = 0x00000020,
|
||||
ORBIS_NET_SO_LINGER = 0x00000080,
|
||||
ORBIS_NET_SO_REUSEPORT = 0x00000200,
|
||||
ORBIS_NET_SO_ONESBCAST = 0x00010000,
|
||||
ORBIS_NET_SO_USECRYPTO = 0x00020000,
|
||||
ORBIS_NET_SO_USESIGNATURE = 0x00040000,
|
||||
ORBIS_NET_SO_SNDBUF = 0x1001,
|
||||
ORBIS_NET_SO_RCVBUF = 0x1002,
|
||||
ORBIS_NET_SO_ERROR = 0x1007,
|
||||
ORBIS_NET_SO_TYPE = 0x1008,
|
||||
ORBIS_NET_SO_SNDTIMEO = 0x1105,
|
||||
ORBIS_NET_SO_RCVTIMEO = 0x1106,
|
||||
ORBIS_NET_SO_ERROR_EX = 0x1107,
|
||||
ORBIS_NET_SO_ACCEPTTIMEO = 0x1108,
|
||||
ORBIS_NET_SO_CONNECTTIMEO = 0x1109,
|
||||
ORBIS_NET_SO_NBIO = 0x1200,
|
||||
ORBIS_NET_SO_POLICY = 0x1201,
|
||||
ORBIS_NET_SO_NAME = 0x1202,
|
||||
ORBIS_NET_SO_PRIORITY = 0x1203
|
||||
};
|
||||
|
||||
using OrbisNetId = s32;
|
||||
|
||||
struct OrbisNetSockaddr {
|
||||
|
@ -27,6 +85,30 @@ struct OrbisNetSockaddr {
|
|||
char sa_data[14];
|
||||
};
|
||||
|
||||
struct OrbisNetSockaddrIn {
|
||||
u8 sin_len;
|
||||
u8 sin_family;
|
||||
u16 sin_port;
|
||||
u32 sin_addr;
|
||||
u16 sin_vport;
|
||||
char sin_zero[6];
|
||||
};
|
||||
|
||||
struct OrbisNetIovec {
|
||||
void* iov_base;
|
||||
u64 iov_len;
|
||||
};
|
||||
|
||||
struct OrbisNetMsghdr {
|
||||
void* msg_name;
|
||||
u32 msg_namelen;
|
||||
OrbisNetIovec* msg_iov;
|
||||
int msg_iovlen;
|
||||
void* msg_control;
|
||||
u32 msg_controllen;
|
||||
int msg_flags;
|
||||
};
|
||||
|
||||
int PS4_SYSV_ABI in6addr_any();
|
||||
int PS4_SYSV_ABI in6addr_loopback();
|
||||
int PS4_SYSV_ABI sce_net_dummy();
|
||||
|
@ -116,7 +198,7 @@ int PS4_SYSV_ABI sceNetConfigWlanInfraLeave();
|
|||
int PS4_SYSV_ABI sceNetConfigWlanInfraScanJoin();
|
||||
int PS4_SYSV_ABI sceNetConfigWlanScan();
|
||||
int PS4_SYSV_ABI sceNetConfigWlanSetDeviceConfig();
|
||||
int PS4_SYSV_ABI sceNetConnect();
|
||||
int PS4_SYSV_ABI sceNetConnect(OrbisNetId s, const OrbisNetSockaddr* addr, u32 addrlen);
|
||||
int PS4_SYSV_ABI sceNetControl();
|
||||
int PS4_SYSV_ABI sceNetDhcpdStart();
|
||||
int PS4_SYSV_ABI sceNetDhcpdStop();
|
||||
|
@ -151,10 +233,10 @@ int PS4_SYSV_ABI sceNetGetIfList();
|
|||
int PS4_SYSV_ABI sceNetGetIfListOnce();
|
||||
int PS4_SYSV_ABI sceNetGetIfName();
|
||||
int PS4_SYSV_ABI sceNetGetIfnameNumList();
|
||||
int PS4_SYSV_ABI sceNetGetMacAddress();
|
||||
int PS4_SYSV_ABI sceNetGetMacAddress(Libraries::NetCtl::OrbisNetEtherAddr* addr, int flags);
|
||||
int PS4_SYSV_ABI sceNetGetMemoryPoolStats();
|
||||
int PS4_SYSV_ABI sceNetGetNameToIndex();
|
||||
int PS4_SYSV_ABI sceNetGetpeername();
|
||||
int PS4_SYSV_ABI sceNetGetpeername(OrbisNetId s, OrbisNetSockaddr* addr, u32* paddrlen);
|
||||
int PS4_SYSV_ABI sceNetGetRandom();
|
||||
int PS4_SYSV_ABI sceNetGetRouteInfo();
|
||||
int PS4_SYSV_ABI sceNetGetSockInfo();
|
||||
|
@ -177,7 +259,7 @@ int PS4_SYSV_ABI sceNetInfoDumpStop();
|
|||
int PS4_SYSV_ABI sceNetInit();
|
||||
int PS4_SYSV_ABI sceNetInitParam();
|
||||
int PS4_SYSV_ABI sceNetIoctl();
|
||||
int PS4_SYSV_ABI sceNetListen();
|
||||
int PS4_SYSV_ABI sceNetListen(OrbisNetId s, int backlog);
|
||||
int PS4_SYSV_ABI sceNetMemoryAllocate();
|
||||
int PS4_SYSV_ABI sceNetMemoryFree();
|
||||
u32 PS4_SYSV_ABI sceNetNtohl(u32 net32);
|
||||
|
@ -187,10 +269,10 @@ int PS4_SYSV_ABI sceNetPoolCreate(const char* name, int size, int flags);
|
|||
int PS4_SYSV_ABI sceNetPoolDestroy();
|
||||
int PS4_SYSV_ABI sceNetPppoeStart();
|
||||
int PS4_SYSV_ABI sceNetPppoeStop();
|
||||
int PS4_SYSV_ABI sceNetRecv();
|
||||
int PS4_SYSV_ABI sceNetRecvfrom(OrbisNetId s, void* buf, size_t len, int flags,
|
||||
OrbisNetSockaddr* addr, u32* paddrlen);
|
||||
int PS4_SYSV_ABI sceNetRecvmsg();
|
||||
int PS4_SYSV_ABI sceNetRecv(OrbisNetId s, void* buf, u64 len, int flags);
|
||||
int PS4_SYSV_ABI sceNetRecvfrom(OrbisNetId s, void* buf, u64 len, int flags, OrbisNetSockaddr* addr,
|
||||
u32* paddrlen);
|
||||
int PS4_SYSV_ABI sceNetRecvmsg(OrbisNetId s, OrbisNetMsghdr* msg, int flags);
|
||||
int PS4_SYSV_ABI sceNetResolverAbort();
|
||||
int PS4_SYSV_ABI sceNetResolverConnect();
|
||||
int PS4_SYSV_ABI sceNetResolverConnectAbort();
|
||||
|
@ -205,14 +287,16 @@ int PS4_SYSV_ABI sceNetResolverStartNtoa();
|
|||
int PS4_SYSV_ABI sceNetResolverStartNtoa6();
|
||||
int PS4_SYSV_ABI sceNetResolverStartNtoaMultipleRecords();
|
||||
int PS4_SYSV_ABI sceNetResolverStartNtoaMultipleRecordsEx();
|
||||
int PS4_SYSV_ABI sceNetSend();
|
||||
int PS4_SYSV_ABI sceNetSendmsg();
|
||||
int PS4_SYSV_ABI sceNetSendto();
|
||||
int PS4_SYSV_ABI sceNetSend(OrbisNetId s, const void* buf, u64 len, int flags);
|
||||
int PS4_SYSV_ABI sceNetSendmsg(OrbisNetId s, const OrbisNetMsghdr* msg, int flags);
|
||||
int PS4_SYSV_ABI sceNetSendto(OrbisNetId s, const void* buf, u64 len, int flags,
|
||||
const OrbisNetSockaddr* addr, u32 addrlen);
|
||||
int PS4_SYSV_ABI sceNetSetDns6Info();
|
||||
int PS4_SYSV_ABI sceNetSetDns6InfoToKernel();
|
||||
int PS4_SYSV_ABI sceNetSetDnsInfo();
|
||||
int PS4_SYSV_ABI sceNetSetDnsInfoToKernel();
|
||||
int PS4_SYSV_ABI sceNetSetsockopt();
|
||||
int PS4_SYSV_ABI sceNetSetsockopt(OrbisNetId s, int level, int optname, const void* optval,
|
||||
u32 optlen);
|
||||
int PS4_SYSV_ABI sceNetShowIfconfig();
|
||||
int PS4_SYSV_ABI sceNetShowIfconfigForBuffer();
|
||||
int PS4_SYSV_ABI sceNetShowIfconfigWithMemory();
|
||||
|
@ -229,10 +313,10 @@ int PS4_SYSV_ABI sceNetShowRoute6ForBuffer();
|
|||
int PS4_SYSV_ABI sceNetShowRoute6WithMemory();
|
||||
int PS4_SYSV_ABI sceNetShowRouteForBuffer();
|
||||
int PS4_SYSV_ABI sceNetShowRouteWithMemory();
|
||||
int PS4_SYSV_ABI sceNetShutdown();
|
||||
int PS4_SYSV_ABI sceNetSocket(const char* name, int family, int type, int protocol);
|
||||
int PS4_SYSV_ABI sceNetSocketAbort();
|
||||
int PS4_SYSV_ABI sceNetSocketClose();
|
||||
int PS4_SYSV_ABI sceNetShutdown(OrbisNetId s, int how);
|
||||
OrbisNetId PS4_SYSV_ABI sceNetSocket(const char* name, int family, int type, int protocol);
|
||||
int PS4_SYSV_ABI sceNetSocketAbort(OrbisNetId s, int flags);
|
||||
int PS4_SYSV_ABI sceNetSocketClose(OrbisNetId s);
|
||||
int PS4_SYSV_ABI sceNetSyncCreate();
|
||||
int PS4_SYSV_ABI sceNetSyncDestroy();
|
||||
int PS4_SYSV_ABI sceNetSyncGet();
|
||||
|
|
162
src/core/libraries/network/net_error.h
Normal file
162
src/core/libraries/network/net_error.h
Normal file
|
@ -0,0 +1,162 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
// net errno codes
|
||||
constexpr int ORBIS_NET_EPERM = 1;
|
||||
constexpr int ORBIS_NET_ENOENT = 2;
|
||||
constexpr int ORBIS_NET_EINTR = 4;
|
||||
constexpr int ORBIS_NET_EBADF = 9;
|
||||
constexpr int ORBIS_NET_EACCES = 13;
|
||||
constexpr int ORBIS_NET_EFAULT = 14;
|
||||
constexpr int ORBIS_NET_ENOTBLK = 15;
|
||||
constexpr int ORBIS_NET_EBUSY = 16;
|
||||
constexpr int ORBIS_NET_EEXIST = 17;
|
||||
constexpr int ORBIS_NET_ENODEV = 19;
|
||||
constexpr int ORBIS_NET_EINVAL = 22;
|
||||
constexpr int ORBIS_NET_EMFILE = 24;
|
||||
constexpr int ORBIS_NET_ENOSPC = 28;
|
||||
constexpr int ORBIS_NET_EPIPE = 32;
|
||||
constexpr int ORBIS_NET_EAGAIN = 35;
|
||||
constexpr int ORBIS_NET_EWOULDBLOCK = 35;
|
||||
constexpr int ORBIS_NET_EINPROGRESS = 36;
|
||||
constexpr int ORBIS_NET_EALREADY = 37;
|
||||
constexpr int ORBIS_NET_ENOTSOCK = 38;
|
||||
constexpr int ORBIS_NET_EDESTADDRREQ = 39;
|
||||
constexpr int ORBIS_NET_EMSGSIZE = 40;
|
||||
constexpr int ORBIS_NET_EPROTOTYPE = 41;
|
||||
constexpr int ORBIS_NET_ENOPROTOOPT = 42;
|
||||
constexpr int ORBIS_NET_EPROTONOSUPPORT = 43;
|
||||
constexpr int ORBIS_NET_EOPNOTSUPP = 45;
|
||||
constexpr int ORBIS_NET_EAFNOSUPPORT = 47;
|
||||
constexpr int ORBIS_NET_EADDRINUSE = 48;
|
||||
constexpr int ORBIS_NET_EADDRNOTAVAIL = 49;
|
||||
constexpr int ORBIS_NET_ENETDOWN = 50;
|
||||
constexpr int ORBIS_NET_ENETUNREACH = 51;
|
||||
constexpr int ORBIS_NET_ENETRESET = 52;
|
||||
constexpr int ORBIS_NET_ECONNABORTED = 53;
|
||||
constexpr int ORBIS_NET_ECONNRESET = 54;
|
||||
constexpr int ORBIS_NET_EISCONN = 56;
|
||||
constexpr int ORBIS_NET_ENOTCONN = 57;
|
||||
constexpr int ORBIS_NET_ETOOMANYREFS = 59;
|
||||
constexpr int ORBIS_NET_ETIMEDOUT = 60;
|
||||
constexpr int ORBIS_NET_ECONNREFUSED = 61;
|
||||
constexpr int ORBIS_NET_ELOOP = 62;
|
||||
constexpr int ORBIS_NET_ENAMETOOLONG = 63;
|
||||
constexpr int ORBIS_NET_EHOSTDOWN = 64;
|
||||
constexpr int ORBIS_NET_EHOSTUNREACH = 65;
|
||||
constexpr int ORBIS_NET_ENOTEMPTY = 66;
|
||||
constexpr int ORBIS_NET_EPROCUNAVAIL = 76;
|
||||
constexpr int ORBIS_NET_EPROTO = 92;
|
||||
constexpr int ORBIS_NET_EADHOC = 160;
|
||||
constexpr int ORBIS_NET_EINACTIVEDISABLED = 163;
|
||||
constexpr int ORBIS_NET_ENODATA = 164;
|
||||
constexpr int ORBIS_NET_EDESC = 165;
|
||||
constexpr int ORBIS_NET_EDESCTIMEDOUT = 166;
|
||||
constexpr int ORBIS_NET_ENOTINIT = 200;
|
||||
constexpr int ORBIS_NET_ENOLIBMEM = 201;
|
||||
constexpr int ORBIS_NET_ECALLBACK = 203;
|
||||
constexpr int ORBIS_NET_EINTERNAL = 204;
|
||||
constexpr int ORBIS_NET_ERETURN = 205;
|
||||
constexpr int ORBIS_NET_ENOALLOCMEM = 206;
|
||||
|
||||
// errno for dns resolver
|
||||
constexpr int ORBIS_NET_RESOLVER_EINTERNAL = 220;
|
||||
constexpr int ORBIS_NET_RESOLVER_EBUSY = 221;
|
||||
constexpr int ORBIS_NET_RESOLVER_ENOSPACE = 222;
|
||||
constexpr int ORBIS_NET_RESOLVER_EPACKET = 223;
|
||||
constexpr int ORBIS_NET_RESOLVER_ENODNS = 225;
|
||||
constexpr int ORBIS_NET_RESOLVER_ETIMEDOUT = 226;
|
||||
constexpr int ORBIS_NET_RESOLVER_ENOSUPPORT = 227;
|
||||
constexpr int ORBIS_NET_RESOLVER_EFORMAT = 228;
|
||||
constexpr int ORBIS_NET_RESOLVER_ESERVERFAILURE = 229;
|
||||
constexpr int ORBIS_NET_RESOLVER_ENOHOST = 230;
|
||||
constexpr int ORBIS_NET_RESOLVER_ENOTIMPLEMENTED = 231;
|
||||
constexpr int ORBIS_NET_RESOLVER_ESERVERREFUSED = 232;
|
||||
constexpr int ORBIS_NET_RESOLVER_ENORECORD = 233;
|
||||
constexpr int ORBIS_NET_RESOLVER_EALIGNMENT = 234;
|
||||
|
||||
// common errno
|
||||
constexpr int ORBIS_NET_ENOMEM = 12;
|
||||
constexpr int ORBIS_NET_ENOBUFS = 55;
|
||||
|
||||
// error codes
|
||||
constexpr int ORBIS_NET_ERROR_BASE = 0x80410100; // not existed used for calculation
|
||||
constexpr int ORBIS_NET_ERROR_EPERM = 0x80410101;
|
||||
constexpr int ORBIS_NET_ERROR_ENOENT = 0x80410102;
|
||||
constexpr int ORBIS_NET_ERROR_EINTR = 0x80410104;
|
||||
constexpr int ORBIS_NET_ERROR_EBADF = 0x80410109;
|
||||
constexpr int ORBIS_NET_ERROR_ENOMEM = 0x8041010c;
|
||||
constexpr int ORBIS_NET_ERROR_EACCES = 0x8041010d;
|
||||
constexpr int ORBIS_NET_ERROR_EFAULT = 0x8041010e;
|
||||
constexpr int ORBIS_NET_ERROR_ENOTBLK = 0x8041010f;
|
||||
constexpr int ORBIS_NET_ERROR_EEXIST = 0x80410111;
|
||||
constexpr int ORBIS_NET_ERROR_ENODEV = 0x80410113;
|
||||
constexpr int ORBIS_NET_ERROR_EINVAL = 0x80410116;
|
||||
constexpr int ORBIS_NET_ERROR_ENFILE = 0x80410117;
|
||||
constexpr int ORBIS_NET_ERROR_EMFILE = 0x80410118;
|
||||
constexpr int ORBIS_NET_ERROR_ENOSPC = 0x8041011c;
|
||||
constexpr int ORBIS_NET_ERROR_EPIPE = 0x80410120;
|
||||
constexpr int ORBIS_NET_ERROR_EAGAIN = 0x80410123;
|
||||
constexpr int ORBIS_NET_ERROR_EWOULDBLOCK = 0x80410123;
|
||||
constexpr int ORBIS_NET_ERROR_EINPROGRESS = 0x80410124;
|
||||
constexpr int ORBIS_NET_ERROR_EALREADY = 0x80410125;
|
||||
constexpr int ORBIS_NET_ERROR_ENOTSOCK = 0x80410126;
|
||||
constexpr int ORBIS_NET_ERROR_EDESTADDRREQ = 0x80410127;
|
||||
constexpr int ORBIS_NET_ERROR_EMSGSIZE = 0x80410128;
|
||||
constexpr int ORBIS_NET_ERROR_EPROTOTYPE = 0x80410129;
|
||||
constexpr int ORBIS_NET_ERROR_ENOPROTOOPT = 0x8041012a;
|
||||
constexpr int ORBIS_NET_ERROR_EPROTONOSUPPORT = 0x8041012b;
|
||||
constexpr int ORBIS_NET_ERROR_EOPNOTSUPP = 0x8041012d;
|
||||
constexpr int ORBIS_NET_ERROR_EPFNOSUPPORT = 0x8041012e;
|
||||
constexpr int ORBIS_NET_ERROR_EAFNOSUPPORT = 0x8041012f;
|
||||
constexpr int ORBIS_NET_ERROR_EADDRINUSE = 0x80410130;
|
||||
constexpr int ORBIS_NET_ERROR_EADDRNOTAVAIL = 0x80410131;
|
||||
constexpr int ORBIS_NET_ERROR_ENETDOWN = 0x80410132;
|
||||
constexpr int ORBIS_NET_ERROR_ENETUNREACH = 0x80410133;
|
||||
constexpr int ORBIS_NET_ERROR_ENETRESET = 0x80410134;
|
||||
constexpr int ORBIS_NET_ERROR_ECONNABORTED = 0x80410135;
|
||||
constexpr int ORBIS_NET_ERROR_ECONNRESET = 0x80410136;
|
||||
constexpr int ORBIS_NET_ERROR_ENOBUFS = 0x80410137;
|
||||
constexpr int ORBIS_NET_ERROR_EISCONN = 0x80410138;
|
||||
constexpr int ORBIS_NET_ERROR_ENOTCONN = 0x80410139;
|
||||
constexpr int ORBIS_NET_ERROR_ESHUTDOWN = 0x8041013a;
|
||||
constexpr int ORBIS_NET_ERROR_ETOOMANYREFS = 0x8041013b;
|
||||
constexpr int ORBIS_NET_ERROR_ETIMEDOUT = 0x8041013c;
|
||||
constexpr int ORBIS_NET_ERROR_ECONNREFUSED = 0x8041013d;
|
||||
constexpr int ORBIS_NET_ERROR_ELOOP = 0x8041013e;
|
||||
constexpr int ORBIS_NET_ERROR_ENAMETOOLONG = 0x8041013f;
|
||||
constexpr int ORBIS_NET_ERROR_EHOSTDOWN = 0x80410140;
|
||||
constexpr int ORBIS_NET_ERROR_EHOSTUNREACH = 0x80410141;
|
||||
constexpr int ORBIS_NET_ERROR_ENOTEMPTY = 0x80410142;
|
||||
constexpr int ORBIS_NET_ERROR_EPROCUNAVAIL = 0x8041014C;
|
||||
constexpr int ORBIS_NET_ERROR_ECANCELED = 0x80410157;
|
||||
constexpr int ORBIS_NET_ERROR_EPROTO = 0x8041015C;
|
||||
constexpr int ORBIS_NET_ERROR_EADHOC = 0x804101a0;
|
||||
constexpr int ORBIS_NET_ERROR_ERESERVED161 = 0x804101a1;
|
||||
constexpr int ORBIS_NET_ERROR_ERESERVED162 = 0x804101a2;
|
||||
constexpr int ORBIS_NET_ERROR_EINACTIVEDISABLED = 0x804101a3;
|
||||
constexpr int ORBIS_NET_ERROR_ENODATA = 0x804101a4;
|
||||
constexpr int ORBIS_NET_ERROR_EDESC = 0x804101a5;
|
||||
constexpr int ORBIS_NET_ERROR_EDESCTIMEDOUT = 0x804101a6;
|
||||
constexpr int ORBIS_NET_ERROR_ENOTINIT = 0x804101c8;
|
||||
constexpr int ORBIS_NET_ERROR_ENOLIBMEM = 0x804101c9;
|
||||
constexpr int ORBIS_NET_ERROR_ECALLBACK = 0x804101cb;
|
||||
constexpr int ORBIS_NET_ERROR_EINTERNAL = 0x804101cc;
|
||||
constexpr int ORBIS_NET_ERROR_ERETURN = 0x804101cd;
|
||||
constexpr int ORBIS_NET_ERROR_ENOALLOCMEM = 0x804101ce;
|
||||
constexpr int ORBIS_NET_ERROR_RESOLVER_EINTERNAL = 0x804101dc;
|
||||
constexpr int ORBIS_NET_ERROR_RESOLVER_EBUSY = 0x804101dd;
|
||||
constexpr int ORBIS_NET_ERROR_RESOLVER_ENOSPACE = 0x804101de;
|
||||
constexpr int ORBIS_NET_ERROR_RESOLVER_EPACKET = 0x804101df;
|
||||
constexpr int ORBIS_NET_ERROR_RESOLVER_ENODNS = 0x804101e1;
|
||||
constexpr int ORBIS_NET_ERROR_RESOLVER_ETIMEDOUT = 0x804101e2;
|
||||
constexpr int ORBIS_NET_ERROR_RESOLVER_ENOSUPPORT = 0x804101e3;
|
||||
constexpr int ORBIS_NET_ERROR_RESOLVER_EFORMAT = 0x804101e4;
|
||||
constexpr int ORBIS_NET_ERROR_RESOLVER_ESERVERFAILURE = 0x804101e5;
|
||||
constexpr int ORBIS_NET_ERROR_RESOLVER_ENOHOST = 0x804101e6;
|
||||
constexpr int ORBIS_NET_ERROR_RESOLVER_ENOTIMPLEMENTED = 0x804101e7;
|
||||
constexpr int ORBIS_NET_ERROR_RESOLVER_ESERVERREFUSED = 0x804101e8;
|
||||
constexpr int ORBIS_NET_ERROR_RESOLVER_ENORECORD = 0x804101e9;
|
||||
constexpr int ORBIS_NET_ERROR_RESOLVER_EALIGNMENT = 0x804101ea;
|
110
src/core/libraries/network/net_util.cpp
Normal file
110
src/core/libraries/network/net_util.cpp
Normal file
|
@ -0,0 +1,110 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#ifdef _WIN32
|
||||
#define _WINSOCK_DEPRECATED_NO_WARNINGS
|
||||
#include <Ws2tcpip.h>
|
||||
#include <iphlpapi.h>
|
||||
#include <winsock2.h>
|
||||
typedef SOCKET net_socket;
|
||||
typedef int socklen_t;
|
||||
#else
|
||||
#include <cerrno>
|
||||
#include <arpa/inet.h>
|
||||
#include <net/if.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
typedef int net_socket;
|
||||
#endif
|
||||
#if defined(__APPLE__)
|
||||
#include <ifaddrs.h>
|
||||
#include <net/if_dl.h>
|
||||
#endif
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
#include <string.h>
|
||||
#include "net_util.h"
|
||||
|
||||
namespace NetUtil {
|
||||
|
||||
const std::array<u8, 6>& NetUtilInternal::GetEthernetAddr() const {
|
||||
return ether_address;
|
||||
}
|
||||
|
||||
bool NetUtilInternal::RetrieveEthernetAddr() {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
#ifdef _WIN32
|
||||
std::vector<u8> adapter_infos(sizeof(IP_ADAPTER_INFO));
|
||||
ULONG size_infos = sizeof(IP_ADAPTER_INFO);
|
||||
|
||||
if (GetAdaptersInfo(reinterpret_cast<PIP_ADAPTER_INFO>(adapter_infos.data()), &size_infos) ==
|
||||
ERROR_BUFFER_OVERFLOW)
|
||||
adapter_infos.resize(size_infos);
|
||||
|
||||
if (GetAdaptersInfo(reinterpret_cast<PIP_ADAPTER_INFO>(adapter_infos.data()), &size_infos) ==
|
||||
NO_ERROR &&
|
||||
size_infos) {
|
||||
PIP_ADAPTER_INFO info = reinterpret_cast<PIP_ADAPTER_INFO>(adapter_infos.data());
|
||||
memcpy(ether_address.data(), info[0].Address, 6);
|
||||
return true;
|
||||
}
|
||||
#elif defined(__APPLE__)
|
||||
ifaddrs* ifap;
|
||||
|
||||
if (getifaddrs(&ifap) == 0) {
|
||||
ifaddrs* p;
|
||||
for (p = ifap; p; p = p->ifa_next) {
|
||||
if (p->ifa_addr->sa_family == AF_LINK) {
|
||||
sockaddr_dl* sdp = reinterpret_cast<sockaddr_dl*>(p->ifa_addr);
|
||||
memcpy(ether_address.data(), sdp->sdl_data + sdp->sdl_nlen, 6);
|
||||
freeifaddrs(ifap);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
freeifaddrs(ifap);
|
||||
}
|
||||
#else
|
||||
ifreq ifr;
|
||||
ifconf ifc;
|
||||
char buf[1024];
|
||||
int success = 0;
|
||||
|
||||
int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
|
||||
if (sock == -1)
|
||||
return false;
|
||||
|
||||
ifc.ifc_len = sizeof(buf);
|
||||
ifc.ifc_buf = buf;
|
||||
if (ioctl(sock, SIOCGIFCONF, &ifc) == -1)
|
||||
return false;
|
||||
|
||||
ifreq* it = ifc.ifc_req;
|
||||
const ifreq* const end = it + (ifc.ifc_len / sizeof(ifreq));
|
||||
|
||||
for (; it != end; ++it) {
|
||||
strcpy(ifr.ifr_name, it->ifr_name);
|
||||
if (ioctl(sock, SIOCGIFFLAGS, &ifr) == 0) {
|
||||
if (!(ifr.ifr_flags & IFF_LOOPBACK)) {
|
||||
if (ioctl(sock, SIOCGIFHWADDR, &ifr) == 0) {
|
||||
success = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (success) {
|
||||
memcpy(ether_address.data(), ifr.ifr_hwaddr.sa_data, 6);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
} // namespace NetUtil
|
24
src/core/libraries/network/net_util.h
Normal file
24
src/core/libraries/network/net_util.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include "common/types.h"
|
||||
|
||||
namespace NetUtil {
|
||||
|
||||
class NetUtilInternal {
|
||||
public:
|
||||
explicit NetUtilInternal() = default;
|
||||
~NetUtilInternal() = default;
|
||||
|
||||
private:
|
||||
std::array<u8, 6> ether_address{};
|
||||
std::mutex m_mutex;
|
||||
|
||||
public:
|
||||
const std::array<u8, 6>& GetEthernetAddr() const;
|
||||
bool RetrieveEthernetAddr();
|
||||
};
|
||||
} // namespace NetUtil
|
|
@ -12,11 +12,13 @@
|
|||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <common/singleton.h>
|
||||
#include "common/logging/log.h"
|
||||
#include "core/libraries/error_codes.h"
|
||||
#include "core/libraries/libs.h"
|
||||
#include "core/libraries/network/net_ctl_codes.h"
|
||||
#include "core/libraries/network/netctl.h"
|
||||
#include "net_util.h"
|
||||
|
||||
namespace Libraries::NetCtl {
|
||||
|
||||
|
@ -162,6 +164,14 @@ int PS4_SYSV_ABI sceNetCtlGetInfo(int code, OrbisNetCtlInfo* info) {
|
|||
case ORBIS_NET_CTL_INFO_DEVICE:
|
||||
info->device = ORBIS_NET_CTL_DEVICE_WIRED;
|
||||
break;
|
||||
case ORBIS_NET_CTL_INFO_ETHER_ADDR: {
|
||||
auto* netinfo = Common::Singleton<NetUtil::NetUtilInternal>::Instance();
|
||||
netinfo->RetrieveEthernetAddr();
|
||||
memcpy(info->ether_addr.data, netinfo->GetEthernetAddr().data(), 6);
|
||||
} break;
|
||||
case ORBIS_NET_CTL_INFO_MTU:
|
||||
info->mtu = 1500; // default value
|
||||
break;
|
||||
case ORBIS_NET_CTL_INFO_LINK:
|
||||
info->link = ORBIS_NET_CTL_LINK_DISCONNECTED;
|
||||
break;
|
||||
|
@ -183,6 +193,7 @@ int PS4_SYSV_ABI sceNetCtlGetInfo(int code, OrbisNetCtlInfo* info) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
LOG_ERROR(Lib_NetCtl, "{} unsupported code", code);
|
||||
}
|
||||
|
|
|
@ -49,8 +49,26 @@ union OrbisNetCtlInfo {
|
|||
|
||||
// GetInfo codes
|
||||
constexpr int ORBIS_NET_CTL_INFO_DEVICE = 1;
|
||||
constexpr int ORBIS_NET_CTL_INFO_ETHER_ADDR = 2;
|
||||
constexpr int ORBIS_NET_CTL_INFO_MTU = 3;
|
||||
constexpr int ORBIS_NET_CTL_INFO_LINK = 4;
|
||||
constexpr int ORBIS_NET_CTL_INFO_BSSID = 5;
|
||||
constexpr int ORBIS_NET_CTL_INFO_SSID = 6;
|
||||
constexpr int ORBIS_NET_CTL_INFO_WIFI_SECURITY = 7;
|
||||
constexpr int ORBIS_NET_CTL_INFO_RSSI_DBM = 8;
|
||||
constexpr int ORBIS_NET_CTL_INFO_RSSI_PERCENTAGE = 9;
|
||||
constexpr int ORBIS_NET_CTL_INFO_CHANNEL = 10;
|
||||
constexpr int ORBIS_NET_CTL_INFO_IP_CONFIG = 11;
|
||||
constexpr int ORBIS_NET_CTL_INFO_DHCP_HOSTNAME = 12;
|
||||
constexpr int ORBIS_NET_CTL_INFO_PPPOE_AUTH_NAME = 13;
|
||||
constexpr int ORBIS_NET_CTL_INFO_IP_ADDRESS = 14;
|
||||
constexpr int ORBIS_NET_CTL_INFO_NETMASK = 15;
|
||||
constexpr int ORBIS_NET_CTL_INFO_DEFAULT_ROUTE = 16;
|
||||
constexpr int ORBIS_NET_CTL_INFO_PRIMARY_DNS = 17;
|
||||
constexpr int ORBIS_NET_CTL_INFO_SECONDARY_DNS = 18;
|
||||
constexpr int ORBIS_NET_CTL_INFO_HTTP_PROXY_CONFIG = 19;
|
||||
constexpr int ORBIS_NET_CTL_INFO_HTTP_PROXY_SERVER = 20;
|
||||
constexpr int ORBIS_NET_CTL_INFO_HTTP_PROXY_PORT = 21;
|
||||
|
||||
int PS4_SYSV_ABI sceNetBweCheckCallbackIpcInt();
|
||||
int PS4_SYSV_ABI sceNetBweClearEventIpcInt();
|
||||
|
|
60
src/core/libraries/network/p2p_sockets.cpp
Normal file
60
src/core/libraries/network/p2p_sockets.cpp
Normal file
|
@ -0,0 +1,60 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <common/assert.h>
|
||||
#include "net.h"
|
||||
#include "net_error.h"
|
||||
#include "sockets.h"
|
||||
|
||||
namespace Libraries::Net {
|
||||
|
||||
int P2PSocket::Close() {
|
||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
int P2PSocket::SetSocketOptions(int level, int optname, const void* optval, u32 optlen) {
|
||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
int P2PSocket::GetSocketOptions(int level, int optname, void* optval, u32* optlen) {
|
||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int P2PSocket::Bind(const OrbisNetSockaddr* addr, u32 addrlen) {
|
||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int P2PSocket::Listen(int backlog) {
|
||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int P2PSocket::SendPacket(const void* msg, u32 len, int flags, const OrbisNetSockaddr* to,
|
||||
u32 tolen) {
|
||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int P2PSocket::ReceivePacket(void* buf, u32 len, int flags, OrbisNetSockaddr* from, u32* fromlen) {
|
||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||
return -1;
|
||||
}
|
||||
|
||||
SocketPtr P2PSocket::Accept(OrbisNetSockaddr* addr, u32* addrlen) {
|
||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int P2PSocket::Connect(const OrbisNetSockaddr* addr, u32 namelen) {
|
||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int P2PSocket::GetSocketAddress(OrbisNetSockaddr* name, u32* namelen) {
|
||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace Libraries::Net
|
395
src/core/libraries/network/posix_sockets.cpp
Normal file
395
src/core/libraries/network/posix_sockets.cpp
Normal file
|
@ -0,0 +1,395 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <common/assert.h>
|
||||
#include "net.h"
|
||||
#include "net_error.h"
|
||||
#include "sockets.h"
|
||||
|
||||
namespace Libraries::Net {
|
||||
|
||||
#ifdef _WIN32
|
||||
#define ERROR_CASE(errname) \
|
||||
case (WSA##errname): \
|
||||
return ORBIS_NET_ERROR_##errname;
|
||||
#else
|
||||
#define ERROR_CASE(errname) \
|
||||
case (errname): \
|
||||
return ORBIS_NET_ERROR_##errname;
|
||||
#endif
|
||||
|
||||
static int ConvertReturnErrorCode(int retval) {
|
||||
if (retval < 0) {
|
||||
#ifdef _WIN32
|
||||
switch (WSAGetLastError()) {
|
||||
#else
|
||||
switch (errno) {
|
||||
#endif
|
||||
#ifndef _WIN32 // These errorcodes don't exist in WinSock
|
||||
ERROR_CASE(EPERM)
|
||||
ERROR_CASE(ENOENT)
|
||||
// ERROR_CASE(ESRCH)
|
||||
// ERROR_CASE(EIO)
|
||||
// ERROR_CASE(ENXIO)
|
||||
// ERROR_CASE(E2BIG)
|
||||
// ERROR_CASE(ENOEXEC)
|
||||
// ERROR_CASE(EDEADLK)
|
||||
ERROR_CASE(ENOMEM)
|
||||
// ERROR_CASE(ECHILD)
|
||||
// ERROR_CASE(EBUSY)
|
||||
ERROR_CASE(EEXIST)
|
||||
// ERROR_CASE(EXDEV)
|
||||
ERROR_CASE(ENODEV)
|
||||
// ERROR_CASE(ENOTDIR)
|
||||
// ERROR_CASE(EISDIR)
|
||||
ERROR_CASE(ENFILE)
|
||||
// ERROR_CASE(ENOTTY)
|
||||
// ERROR_CASE(ETXTBSY)
|
||||
// ERROR_CASE(EFBIG)
|
||||
ERROR_CASE(ENOSPC)
|
||||
// ERROR_CASE(ESPIPE)
|
||||
// ERROR_CASE(EROFS)
|
||||
// ERROR_CASE(EMLINK)
|
||||
ERROR_CASE(EPIPE)
|
||||
// ERROR_CASE(EDOM)
|
||||
// ERROR_CASE(ERANGE)
|
||||
// ERROR_CASE(ENOLCK)
|
||||
// ERROR_CASE(ENOSYS)
|
||||
// ERROR_CASE(EIDRM)
|
||||
// ERROR_CASE(EOVERFLOW)
|
||||
// ERROR_CASE(EILSEQ)
|
||||
// ERROR_CASE(ENOTSUP)
|
||||
ERROR_CASE(ECANCELED)
|
||||
// ERROR_CASE(EBADMSG)
|
||||
ERROR_CASE(ENODATA)
|
||||
// ERROR_CASE(ENOSR)
|
||||
// ERROR_CASE(ENOSTR)
|
||||
// ERROR_CASE(ETIME)
|
||||
#endif
|
||||
ERROR_CASE(EINTR)
|
||||
ERROR_CASE(EBADF)
|
||||
ERROR_CASE(EACCES)
|
||||
ERROR_CASE(EFAULT)
|
||||
ERROR_CASE(EINVAL)
|
||||
ERROR_CASE(EMFILE)
|
||||
ERROR_CASE(EWOULDBLOCK)
|
||||
ERROR_CASE(EINPROGRESS)
|
||||
ERROR_CASE(EALREADY)
|
||||
ERROR_CASE(ENOTSOCK)
|
||||
ERROR_CASE(EDESTADDRREQ)
|
||||
ERROR_CASE(EMSGSIZE)
|
||||
ERROR_CASE(EPROTOTYPE)
|
||||
ERROR_CASE(ENOPROTOOPT)
|
||||
ERROR_CASE(EPROTONOSUPPORT)
|
||||
#if defined(__APPLE__) || defined(_WIN32)
|
||||
ERROR_CASE(EOPNOTSUPP)
|
||||
#endif
|
||||
ERROR_CASE(EAFNOSUPPORT)
|
||||
ERROR_CASE(EADDRINUSE)
|
||||
ERROR_CASE(EADDRNOTAVAIL)
|
||||
ERROR_CASE(ENETDOWN)
|
||||
ERROR_CASE(ENETUNREACH)
|
||||
ERROR_CASE(ENETRESET)
|
||||
ERROR_CASE(ECONNABORTED)
|
||||
ERROR_CASE(ECONNRESET)
|
||||
ERROR_CASE(ENOBUFS)
|
||||
ERROR_CASE(EISCONN)
|
||||
ERROR_CASE(ENOTCONN)
|
||||
ERROR_CASE(ETIMEDOUT)
|
||||
ERROR_CASE(ECONNREFUSED)
|
||||
ERROR_CASE(ELOOP)
|
||||
ERROR_CASE(ENAMETOOLONG)
|
||||
ERROR_CASE(EHOSTUNREACH)
|
||||
ERROR_CASE(ENOTEMPTY)
|
||||
}
|
||||
return ORBIS_NET_ERROR_EINTERNAL;
|
||||
}
|
||||
// if it is 0 or positive return it as it is
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int ConvertLevels(int level) {
|
||||
switch (level) {
|
||||
case ORBIS_NET_SOL_SOCKET:
|
||||
return SOL_SOCKET;
|
||||
case ORBIS_NET_IPPROTO_IP:
|
||||
return IPPROTO_IP;
|
||||
case ORBIS_NET_IPPROTO_TCP:
|
||||
return IPPROTO_TCP;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void convertOrbisNetSockaddrToPosix(const OrbisNetSockaddr* src, sockaddr* dst) {
|
||||
if (src == nullptr || dst == nullptr)
|
||||
return;
|
||||
memset(dst, 0, sizeof(sockaddr));
|
||||
const OrbisNetSockaddrIn* src_in = (const OrbisNetSockaddrIn*)src;
|
||||
sockaddr_in* dst_in = (sockaddr_in*)dst;
|
||||
dst_in->sin_family = src_in->sin_family;
|
||||
dst_in->sin_port = src_in->sin_port;
|
||||
memcpy(&dst_in->sin_addr, &src_in->sin_addr, 4);
|
||||
}
|
||||
|
||||
static void convertPosixSockaddrToOrbis(sockaddr* src, OrbisNetSockaddr* dst) {
|
||||
if (src == nullptr || dst == nullptr)
|
||||
return;
|
||||
memset(dst, 0, sizeof(OrbisNetSockaddr));
|
||||
OrbisNetSockaddrIn* dst_in = (OrbisNetSockaddrIn*)dst;
|
||||
sockaddr_in* src_in = (sockaddr_in*)src;
|
||||
dst_in->sin_family = static_cast<unsigned char>(src_in->sin_family);
|
||||
dst_in->sin_port = src_in->sin_port;
|
||||
memcpy(&dst_in->sin_addr, &src_in->sin_addr, 4);
|
||||
}
|
||||
|
||||
int PosixSocket::Close() {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
#ifdef _WIN32
|
||||
auto out = closesocket(sock);
|
||||
#else
|
||||
auto out = ::close(sock);
|
||||
#endif
|
||||
return ConvertReturnErrorCode(out);
|
||||
}
|
||||
|
||||
int PosixSocket::Bind(const OrbisNetSockaddr* addr, u32 addrlen) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
sockaddr addr2;
|
||||
convertOrbisNetSockaddrToPosix(addr, &addr2);
|
||||
return ConvertReturnErrorCode(::bind(sock, &addr2, sizeof(sockaddr_in)));
|
||||
}
|
||||
|
||||
int PosixSocket::Listen(int backlog) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
return ConvertReturnErrorCode(::listen(sock, backlog));
|
||||
}
|
||||
|
||||
int PosixSocket::SendPacket(const void* msg, u32 len, int flags, const OrbisNetSockaddr* to,
|
||||
u32 tolen) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
if (to != nullptr) {
|
||||
sockaddr addr;
|
||||
convertOrbisNetSockaddrToPosix(to, &addr);
|
||||
return ConvertReturnErrorCode(
|
||||
sendto(sock, (const char*)msg, len, flags, &addr, sizeof(sockaddr_in)));
|
||||
} else {
|
||||
return ConvertReturnErrorCode(send(sock, (const char*)msg, len, flags));
|
||||
}
|
||||
}
|
||||
|
||||
int PosixSocket::ReceivePacket(void* buf, u32 len, int flags, OrbisNetSockaddr* from,
|
||||
u32* fromlen) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
if (from != nullptr) {
|
||||
sockaddr addr;
|
||||
int res = recvfrom(sock, (char*)buf, len, flags, &addr, (socklen_t*)fromlen);
|
||||
convertPosixSockaddrToOrbis(&addr, from);
|
||||
*fromlen = sizeof(OrbisNetSockaddrIn);
|
||||
return ConvertReturnErrorCode(res);
|
||||
} else {
|
||||
return ConvertReturnErrorCode(recv(sock, (char*)buf, len, flags));
|
||||
}
|
||||
}
|
||||
|
||||
SocketPtr PosixSocket::Accept(OrbisNetSockaddr* addr, u32* addrlen) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
sockaddr addr2;
|
||||
net_socket new_socket = ::accept(sock, &addr2, (socklen_t*)addrlen);
|
||||
#ifdef _WIN32
|
||||
if (new_socket != INVALID_SOCKET) {
|
||||
#else
|
||||
if (new_socket >= 0) {
|
||||
#endif
|
||||
convertPosixSockaddrToOrbis(&addr2, addr);
|
||||
*addrlen = sizeof(OrbisNetSockaddrIn);
|
||||
return std::make_shared<PosixSocket>(new_socket);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int PosixSocket::Connect(const OrbisNetSockaddr* addr, u32 namelen) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
sockaddr addr2;
|
||||
convertOrbisNetSockaddrToPosix(addr, &addr2);
|
||||
return ::connect(sock, &addr2, sizeof(sockaddr_in));
|
||||
}
|
||||
|
||||
int PosixSocket::GetSocketAddress(OrbisNetSockaddr* name, u32* namelen) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
sockaddr addr;
|
||||
convertOrbisNetSockaddrToPosix(name, &addr);
|
||||
if (name != nullptr) {
|
||||
*namelen = sizeof(sockaddr_in);
|
||||
}
|
||||
int res = getsockname(sock, &addr, (socklen_t*)namelen);
|
||||
if (res >= 0) {
|
||||
convertPosixSockaddrToOrbis(&addr, name);
|
||||
*namelen = sizeof(OrbisNetSockaddrIn);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
#define CASE_SETSOCKOPT(opt) \
|
||||
case ORBIS_NET_##opt: \
|
||||
return ConvertReturnErrorCode(setsockopt(sock, level, opt, (const char*)optval, optlen))
|
||||
|
||||
#define CASE_SETSOCKOPT_VALUE(opt, value) \
|
||||
case opt: \
|
||||
if (optlen != sizeof(*value)) { \
|
||||
return ORBIS_NET_ERROR_EFAULT; \
|
||||
} \
|
||||
memcpy(value, optval, optlen); \
|
||||
return 0
|
||||
|
||||
int PosixSocket::SetSocketOptions(int level, int optname, const void* optval, u32 optlen) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
level = ConvertLevels(level);
|
||||
::linger native_linger;
|
||||
if (level == SOL_SOCKET) {
|
||||
switch (optname) {
|
||||
CASE_SETSOCKOPT(SO_REUSEADDR);
|
||||
CASE_SETSOCKOPT(SO_KEEPALIVE);
|
||||
CASE_SETSOCKOPT(SO_BROADCAST);
|
||||
// CASE_SETSOCKOPT(SO_LINGER);
|
||||
CASE_SETSOCKOPT(SO_SNDBUF);
|
||||
CASE_SETSOCKOPT(SO_RCVBUF);
|
||||
CASE_SETSOCKOPT(SO_SNDTIMEO);
|
||||
CASE_SETSOCKOPT(SO_RCVTIMEO);
|
||||
CASE_SETSOCKOPT(SO_ERROR);
|
||||
CASE_SETSOCKOPT(SO_TYPE);
|
||||
CASE_SETSOCKOPT_VALUE(ORBIS_NET_SO_REUSEPORT, &sockopt_so_reuseport);
|
||||
CASE_SETSOCKOPT_VALUE(ORBIS_NET_SO_ONESBCAST, &sockopt_so_onesbcast);
|
||||
CASE_SETSOCKOPT_VALUE(ORBIS_NET_SO_USECRYPTO, &sockopt_so_usecrypto);
|
||||
CASE_SETSOCKOPT_VALUE(ORBIS_NET_SO_USESIGNATURE, &sockopt_so_usesignature);
|
||||
case ORBIS_NET_SO_LINGER: {
|
||||
if (socket_type != ORBIS_NET_SOCK_STREAM) {
|
||||
return ORBIS_NET_EPROCUNAVAIL;
|
||||
}
|
||||
if (optlen < sizeof(OrbisNetLinger)) {
|
||||
LOG_ERROR(Lib_Net, "size missmatched! optlen = {} OrbisNetLinger={}", optlen,
|
||||
sizeof(OrbisNetLinger));
|
||||
return ORBIS_NET_ERROR_EINVAL;
|
||||
}
|
||||
|
||||
const void* native_val = &native_linger;
|
||||
u32 native_len = sizeof(native_linger);
|
||||
native_linger.l_onoff = reinterpret_cast<const OrbisNetLinger*>(optval)->l_onoff;
|
||||
native_linger.l_linger = reinterpret_cast<const OrbisNetLinger*>(optval)->l_linger;
|
||||
return ConvertReturnErrorCode(
|
||||
setsockopt(sock, level, SO_LINGER, (const char*)native_val, native_len));
|
||||
}
|
||||
|
||||
case ORBIS_NET_SO_NAME:
|
||||
return ORBIS_NET_ERROR_EINVAL; // don't support set for name
|
||||
case ORBIS_NET_SO_NBIO: {
|
||||
if (optlen != sizeof(sockopt_so_nbio)) {
|
||||
return ORBIS_NET_ERROR_EFAULT;
|
||||
}
|
||||
memcpy(&sockopt_so_nbio, optval, optlen);
|
||||
#ifdef _WIN32
|
||||
static_assert(sizeof(u_long) == sizeof(sockopt_so_nbio),
|
||||
"type used for ioctlsocket value does not have the expected size");
|
||||
return ConvertReturnErrorCode(ioctlsocket(sock, FIONBIO, (u_long*)&sockopt_so_nbio));
|
||||
#else
|
||||
return ConvertReturnErrorCode(ioctl(sock, FIONBIO, &sockopt_so_nbio));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
} else if (level == IPPROTO_IP) {
|
||||
switch (optname) {
|
||||
// CASE_SETSOCKOPT(IP_HDRINCL);
|
||||
CASE_SETSOCKOPT(IP_TOS);
|
||||
CASE_SETSOCKOPT(IP_TTL);
|
||||
CASE_SETSOCKOPT(IP_MULTICAST_IF);
|
||||
CASE_SETSOCKOPT(IP_MULTICAST_TTL);
|
||||
CASE_SETSOCKOPT(IP_MULTICAST_LOOP);
|
||||
CASE_SETSOCKOPT(IP_ADD_MEMBERSHIP);
|
||||
CASE_SETSOCKOPT(IP_DROP_MEMBERSHIP);
|
||||
CASE_SETSOCKOPT_VALUE(ORBIS_NET_IP_TTLCHK, &sockopt_ip_ttlchk);
|
||||
CASE_SETSOCKOPT_VALUE(ORBIS_NET_IP_MAXTTL, &sockopt_ip_maxttl);
|
||||
case ORBIS_NET_IP_HDRINCL: {
|
||||
if (socket_type != ORBIS_NET_SOCK_RAW) {
|
||||
return ORBIS_NET_EPROCUNAVAIL;
|
||||
}
|
||||
return ConvertReturnErrorCode(
|
||||
setsockopt(sock, level, optname, (const char*)optval, optlen));
|
||||
}
|
||||
}
|
||||
} else if (level == IPPROTO_TCP) {
|
||||
switch (optname) {
|
||||
CASE_SETSOCKOPT(TCP_NODELAY);
|
||||
CASE_SETSOCKOPT(TCP_MAXSEG);
|
||||
CASE_SETSOCKOPT_VALUE(ORBIS_NET_TCP_MSS_TO_ADVERTISE, &sockopt_tcp_mss_to_advertise);
|
||||
}
|
||||
}
|
||||
|
||||
UNREACHABLE_MSG("Unknown level ={} optname ={}", level, optname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define CASE_GETSOCKOPT(opt) \
|
||||
case ORBIS_NET_##opt: { \
|
||||
socklen_t optlen_temp = *optlen; \
|
||||
auto retval = \
|
||||
ConvertReturnErrorCode(getsockopt(sock, level, opt, (char*)optval, &optlen_temp)); \
|
||||
*optlen = optlen_temp; \
|
||||
return retval; \
|
||||
}
|
||||
#define CASE_GETSOCKOPT_VALUE(opt, value) \
|
||||
case opt: \
|
||||
if (*optlen < sizeof(value)) { \
|
||||
*optlen = sizeof(value); \
|
||||
return ORBIS_NET_ERROR_EFAULT; \
|
||||
} \
|
||||
*optlen = sizeof(value); \
|
||||
*(decltype(value)*)optval = value; \
|
||||
return 0;
|
||||
|
||||
int PosixSocket::GetSocketOptions(int level, int optname, void* optval, u32* optlen) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
level = ConvertLevels(level);
|
||||
if (level == SOL_SOCKET) {
|
||||
switch (optname) {
|
||||
CASE_GETSOCKOPT(SO_REUSEADDR);
|
||||
CASE_GETSOCKOPT(SO_KEEPALIVE);
|
||||
CASE_GETSOCKOPT(SO_BROADCAST);
|
||||
CASE_GETSOCKOPT(SO_LINGER);
|
||||
CASE_GETSOCKOPT(SO_SNDBUF);
|
||||
CASE_GETSOCKOPT(SO_RCVBUF);
|
||||
CASE_GETSOCKOPT(SO_SNDTIMEO);
|
||||
CASE_GETSOCKOPT(SO_RCVTIMEO);
|
||||
CASE_GETSOCKOPT(SO_ERROR);
|
||||
CASE_GETSOCKOPT(SO_TYPE);
|
||||
CASE_GETSOCKOPT_VALUE(ORBIS_NET_SO_NBIO, sockopt_so_nbio);
|
||||
CASE_GETSOCKOPT_VALUE(ORBIS_NET_SO_REUSEPORT, sockopt_so_reuseport);
|
||||
CASE_GETSOCKOPT_VALUE(ORBIS_NET_SO_ONESBCAST, sockopt_so_onesbcast);
|
||||
CASE_GETSOCKOPT_VALUE(ORBIS_NET_SO_USECRYPTO, sockopt_so_usecrypto);
|
||||
CASE_GETSOCKOPT_VALUE(ORBIS_NET_SO_USESIGNATURE, sockopt_so_usesignature);
|
||||
CASE_GETSOCKOPT_VALUE(ORBIS_NET_SO_NAME,
|
||||
(char)0); // writes an empty string to the output buffer
|
||||
}
|
||||
} else if (level == IPPROTO_IP) {
|
||||
switch (optname) {
|
||||
CASE_GETSOCKOPT(IP_HDRINCL);
|
||||
CASE_GETSOCKOPT(IP_TOS);
|
||||
CASE_GETSOCKOPT(IP_TTL);
|
||||
CASE_GETSOCKOPT(IP_MULTICAST_IF);
|
||||
CASE_GETSOCKOPT(IP_MULTICAST_TTL);
|
||||
CASE_GETSOCKOPT(IP_MULTICAST_LOOP);
|
||||
CASE_GETSOCKOPT(IP_ADD_MEMBERSHIP);
|
||||
CASE_GETSOCKOPT(IP_DROP_MEMBERSHIP);
|
||||
CASE_GETSOCKOPT_VALUE(ORBIS_NET_IP_TTLCHK, sockopt_ip_ttlchk);
|
||||
CASE_GETSOCKOPT_VALUE(ORBIS_NET_IP_MAXTTL, sockopt_ip_maxttl);
|
||||
}
|
||||
} else if (level == IPPROTO_TCP) {
|
||||
switch (optname) {
|
||||
CASE_GETSOCKOPT(TCP_NODELAY);
|
||||
CASE_GETSOCKOPT(TCP_MAXSEG);
|
||||
CASE_GETSOCKOPT_VALUE(ORBIS_NET_TCP_MSS_TO_ADVERTISE, sockopt_tcp_mss_to_advertise);
|
||||
}
|
||||
}
|
||||
UNREACHABLE_MSG("Unknown level ={} optname ={}", level, optname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace Libraries::Net
|
120
src/core/libraries/network/sockets.h
Normal file
120
src/core/libraries/network/sockets.h
Normal file
|
@ -0,0 +1,120 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef _WIN32
|
||||
#define _WINSOCK_DEPRECATED_NO_WARNINGS
|
||||
#include <Ws2tcpip.h>
|
||||
#include <iphlpapi.h>
|
||||
#include <winsock2.h>
|
||||
typedef SOCKET net_socket;
|
||||
typedef int socklen_t;
|
||||
#else
|
||||
#include <cerrno>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
typedef int net_socket;
|
||||
#endif
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include "net.h"
|
||||
|
||||
namespace Libraries::Net {
|
||||
|
||||
struct Socket;
|
||||
|
||||
typedef std::shared_ptr<Socket> SocketPtr;
|
||||
|
||||
struct OrbisNetLinger {
|
||||
s32 l_onoff;
|
||||
s32 l_linger;
|
||||
};
|
||||
struct Socket {
|
||||
explicit Socket(int domain, int type, int protocol) {}
|
||||
virtual ~Socket() = default;
|
||||
virtual int Close() = 0;
|
||||
virtual int SetSocketOptions(int level, int optname, const void* optval, u32 optlen) = 0;
|
||||
virtual int GetSocketOptions(int level, int optname, void* optval, u32* optlen) = 0;
|
||||
virtual int Bind(const OrbisNetSockaddr* addr, u32 addrlen) = 0;
|
||||
virtual int Listen(int backlog) = 0;
|
||||
virtual int SendPacket(const void* msg, u32 len, int flags, const OrbisNetSockaddr* to,
|
||||
u32 tolen) = 0;
|
||||
virtual SocketPtr Accept(OrbisNetSockaddr* addr, u32* addrlen) = 0;
|
||||
virtual int ReceivePacket(void* buf, u32 len, int flags, OrbisNetSockaddr* from,
|
||||
u32* fromlen) = 0;
|
||||
virtual int Connect(const OrbisNetSockaddr* addr, u32 namelen) = 0;
|
||||
virtual int GetSocketAddress(OrbisNetSockaddr* name, u32* namelen) = 0;
|
||||
std::mutex m_mutex;
|
||||
};
|
||||
|
||||
struct PosixSocket : public Socket {
|
||||
net_socket sock;
|
||||
int sockopt_so_reuseport = 0;
|
||||
int sockopt_so_onesbcast = 0;
|
||||
int sockopt_so_usecrypto = 0;
|
||||
int sockopt_so_usesignature = 0;
|
||||
int sockopt_so_nbio = 0;
|
||||
int sockopt_ip_ttlchk = 0;
|
||||
int sockopt_ip_maxttl = 0;
|
||||
int sockopt_tcp_mss_to_advertise = 0;
|
||||
int socket_type;
|
||||
explicit PosixSocket(int domain, int type, int protocol)
|
||||
: Socket(domain, type, protocol), sock(socket(domain, type, protocol)) {
|
||||
socket_type = type;
|
||||
}
|
||||
explicit PosixSocket(net_socket sock) : Socket(0, 0, 0), sock(sock) {}
|
||||
int Close() override;
|
||||
int SetSocketOptions(int level, int optname, const void* optval, u32 optlen) override;
|
||||
int GetSocketOptions(int level, int optname, void* optval, u32* optlen) override;
|
||||
int Bind(const OrbisNetSockaddr* addr, u32 addrlen) override;
|
||||
int Listen(int backlog) override;
|
||||
int SendPacket(const void* msg, u32 len, int flags, const OrbisNetSockaddr* to,
|
||||
u32 tolen) override;
|
||||
int ReceivePacket(void* buf, u32 len, int flags, OrbisNetSockaddr* from, u32* fromlen) override;
|
||||
SocketPtr Accept(OrbisNetSockaddr* addr, u32* addrlen) override;
|
||||
int Connect(const OrbisNetSockaddr* addr, u32 namelen) override;
|
||||
int GetSocketAddress(OrbisNetSockaddr* name, u32* namelen) override;
|
||||
};
|
||||
|
||||
struct P2PSocket : public Socket {
|
||||
explicit P2PSocket(int domain, int type, int protocol) : Socket(domain, type, protocol) {}
|
||||
int Close() override;
|
||||
int SetSocketOptions(int level, int optname, const void* optval, u32 optlen) override;
|
||||
int GetSocketOptions(int level, int optname, void* optval, u32* optlen) override;
|
||||
int Bind(const OrbisNetSockaddr* addr, u32 addrlen) override;
|
||||
int Listen(int backlog) override;
|
||||
int SendPacket(const void* msg, u32 len, int flags, const OrbisNetSockaddr* to,
|
||||
u32 tolen) override;
|
||||
int ReceivePacket(void* buf, u32 len, int flags, OrbisNetSockaddr* from, u32* fromlen) override;
|
||||
SocketPtr Accept(OrbisNetSockaddr* addr, u32* addrlen) override;
|
||||
int Connect(const OrbisNetSockaddr* addr, u32 namelen) override;
|
||||
int GetSocketAddress(OrbisNetSockaddr* name, u32* namelen) override;
|
||||
};
|
||||
|
||||
class NetInternal {
|
||||
public:
|
||||
explicit NetInternal() = default;
|
||||
~NetInternal() = default;
|
||||
SocketPtr FindSocket(int sockid) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
const auto it = socks.find(sockid);
|
||||
if (it != socks.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public:
|
||||
std::mutex m_mutex;
|
||||
typedef std::map<int, SocketPtr> NetSockets;
|
||||
NetSockets socks;
|
||||
int next_sock_id = 0;
|
||||
};
|
||||
} // namespace Libraries::Net
|
228
src/core/libraries/network/sys_net.cpp
Normal file
228
src/core/libraries/network/sys_net.cpp
Normal file
|
@ -0,0 +1,228 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <common/assert.h>
|
||||
#include <common/logging/log.h>
|
||||
#include <core/libraries/kernel/kernel.h>
|
||||
#include "common/singleton.h"
|
||||
#include "net_error.h"
|
||||
#include "sockets.h"
|
||||
#include "sys_net.h"
|
||||
|
||||
namespace Libraries::Net {
|
||||
|
||||
int PS4_SYSV_ABI sys_connect(OrbisNetId s, const OrbisNetSockaddr* addr, u32 addrlen) {
|
||||
auto* netcall = Common::Singleton<NetInternal>::Instance();
|
||||
auto sock = netcall->FindSocket(s);
|
||||
if (!sock) {
|
||||
*Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF;
|
||||
LOG_ERROR(Lib_Net, "socket id is invalid = {}", s);
|
||||
return -1;
|
||||
}
|
||||
int returncode = sock->Connect(addr, addrlen);
|
||||
if (returncode >= 0) {
|
||||
return returncode;
|
||||
}
|
||||
*Libraries::Kernel::__Error() = returncode;
|
||||
LOG_ERROR(Lib_Net, "error code returned : {:#x}", (u32)returncode);
|
||||
return -1;
|
||||
}
|
||||
int PS4_SYSV_ABI sys_bind(OrbisNetId s, const OrbisNetSockaddr* addr, u32 addrlen) {
|
||||
auto* netcall = Common::Singleton<NetInternal>::Instance();
|
||||
auto sock = netcall->FindSocket(s);
|
||||
if (!sock) {
|
||||
*Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF;
|
||||
LOG_ERROR(Lib_Net, "socket id is invalid = {}", s);
|
||||
return -1;
|
||||
}
|
||||
int returncode = sock->Bind(addr, addrlen);
|
||||
if (returncode >= 0) {
|
||||
return returncode;
|
||||
}
|
||||
*Libraries::Kernel::__Error() = returncode;
|
||||
LOG_ERROR(Lib_Net, "error code returned : {:#x}", (u32)returncode);
|
||||
return -1;
|
||||
}
|
||||
int PS4_SYSV_ABI sys_accept(OrbisNetId s, OrbisNetSockaddr* addr, u32* paddrlen) {
|
||||
auto* netcall = Common::Singleton<NetInternal>::Instance();
|
||||
auto sock = netcall->FindSocket(s);
|
||||
if (!sock) {
|
||||
*Libraries::Kernel::__Error() = ORBIS_NET_EBADF;
|
||||
LOG_ERROR(Lib_Net, "socket id is invalid = {}", s);
|
||||
return -1;
|
||||
}
|
||||
auto new_sock = sock->Accept(addr, paddrlen);
|
||||
if (!new_sock) {
|
||||
*Libraries::Kernel::__Error() = ORBIS_NET_EBADF;
|
||||
LOG_ERROR(Lib_Net, "error creating new socket for accepting");
|
||||
return -1;
|
||||
}
|
||||
auto id = ++netcall->next_sock_id;
|
||||
netcall->socks.emplace(id, new_sock);
|
||||
return id;
|
||||
}
|
||||
int PS4_SYSV_ABI sys_getpeername(OrbisNetId s, const OrbisNetSockaddr* addr, u32* paddrlen) {
|
||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||
return -1;
|
||||
}
|
||||
int PS4_SYSV_ABI sys_getsockname(OrbisNetId s, OrbisNetSockaddr* addr, u32* paddrlen) {
|
||||
auto* netcall = Common::Singleton<NetInternal>::Instance();
|
||||
auto sock = netcall->FindSocket(s);
|
||||
if (!sock) {
|
||||
*Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF;
|
||||
LOG_ERROR(Lib_Net, "socket id is invalid = {}", s);
|
||||
return -1;
|
||||
}
|
||||
int returncode = sock->GetSocketAddress(addr, paddrlen);
|
||||
if (returncode >= 0) {
|
||||
return returncode;
|
||||
}
|
||||
*Libraries::Kernel::__Error() = returncode;
|
||||
LOG_ERROR(Lib_Net, "error code returned : {:#x}", (u32)returncode);
|
||||
return -1;
|
||||
}
|
||||
int PS4_SYSV_ABI sys_getsockopt(OrbisNetId s, int level, int optname, void* optval, u32* optlen) {
|
||||
auto* netcall = Common::Singleton<NetInternal>::Instance();
|
||||
auto sock = netcall->FindSocket(s);
|
||||
if (!sock) {
|
||||
*Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF;
|
||||
LOG_ERROR(Lib_Net, "socket id is invalid = {}", s);
|
||||
return -1;
|
||||
}
|
||||
int returncode = sock->GetSocketOptions(level, optname, optval, optlen);
|
||||
if (returncode >= 0) {
|
||||
return returncode;
|
||||
}
|
||||
*Libraries::Kernel::__Error() = returncode;
|
||||
LOG_ERROR(Lib_Net, "error code returned : {:#x}", (u32)returncode);
|
||||
return -1;
|
||||
}
|
||||
int PS4_SYSV_ABI sys_listen(OrbisNetId s, int backlog) {
|
||||
auto* netcall = Common::Singleton<NetInternal>::Instance();
|
||||
auto sock = netcall->FindSocket(s);
|
||||
if (!sock) {
|
||||
*Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF;
|
||||
LOG_ERROR(Lib_Net, "socket id is invalid = {}", s);
|
||||
return -1;
|
||||
}
|
||||
int returncode = sock->Listen(backlog);
|
||||
if (returncode >= 0) {
|
||||
return returncode;
|
||||
}
|
||||
*Libraries::Kernel::__Error() = returncode;
|
||||
LOG_ERROR(Lib_Net, "error code returned : {:#x}", (u32)returncode);
|
||||
return -1;
|
||||
}
|
||||
int PS4_SYSV_ABI sys_setsockopt(OrbisNetId s, int level, int optname, const void* optval,
|
||||
u32 optlen) {
|
||||
auto* netcall = Common::Singleton<NetInternal>::Instance();
|
||||
auto sock = netcall->FindSocket(s);
|
||||
if (!sock) {
|
||||
*Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF;
|
||||
LOG_ERROR(Lib_Net, "socket id is invalid = {}", s);
|
||||
return -1;
|
||||
}
|
||||
int returncode = sock->SetSocketOptions(level, optname, optval, optlen);
|
||||
if (returncode >= 0) {
|
||||
return returncode;
|
||||
}
|
||||
*Libraries::Kernel::__Error() = returncode;
|
||||
LOG_ERROR(Lib_Net, "error code returned : {:#x}", (u32)returncode);
|
||||
return -1;
|
||||
}
|
||||
int PS4_SYSV_ABI sys_shutdown(OrbisNetId s, int how) {
|
||||
return -1;
|
||||
}
|
||||
int PS4_SYSV_ABI sys_socketex(const char* name, int family, int type, int protocol) {
|
||||
if (name == nullptr) {
|
||||
LOG_INFO(Lib_Net, "name = no-named family = {} type = {} protocol = {}", family, type,
|
||||
protocol);
|
||||
} else {
|
||||
LOG_INFO(Lib_Net, "name = {} family = {} type = {} protocol = {}", std::string(name),
|
||||
family, type, protocol);
|
||||
}
|
||||
SocketPtr sock;
|
||||
switch (type) {
|
||||
case ORBIS_NET_SOCK_STREAM:
|
||||
case ORBIS_NET_SOCK_DGRAM:
|
||||
case ORBIS_NET_SOCK_RAW:
|
||||
sock = std::make_shared<PosixSocket>(family, type, protocol);
|
||||
break;
|
||||
case ORBIS_NET_SOCK_DGRAM_P2P:
|
||||
case ORBIS_NET_SOCK_STREAM_P2P:
|
||||
sock = std::make_shared<P2PSocket>(family, type, protocol);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE_MSG("Unknown type {}", type);
|
||||
}
|
||||
auto* netcall = Common::Singleton<NetInternal>::Instance();
|
||||
auto id = ++netcall->next_sock_id;
|
||||
netcall->socks.emplace(id, sock);
|
||||
return id;
|
||||
}
|
||||
int PS4_SYSV_ABI sys_socket(int family, int type, int protocol) {
|
||||
return sys_socketex(nullptr, family, type, protocol);
|
||||
}
|
||||
int PS4_SYSV_ABI sys_netabort(OrbisNetId s, int flags) {
|
||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||
return -1;
|
||||
}
|
||||
int PS4_SYSV_ABI sys_socketclose(OrbisNetId s) {
|
||||
auto* netcall = Common::Singleton<NetInternal>::Instance();
|
||||
auto sock = netcall->FindSocket(s);
|
||||
if (!sock) {
|
||||
*Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF;
|
||||
LOG_ERROR(Lib_Net, "socket id is invalid = {}", s);
|
||||
return -1;
|
||||
}
|
||||
int returncode = sock->Close();
|
||||
if (returncode >= 0) {
|
||||
return returncode;
|
||||
}
|
||||
*Libraries::Kernel::__Error() = returncode;
|
||||
LOG_ERROR(Lib_Net, "error code returned : {:#x}", (u32)returncode);
|
||||
return -1;
|
||||
}
|
||||
int PS4_SYSV_ABI sys_sendto(OrbisNetId s, const void* buf, u64 len, int flags,
|
||||
const OrbisNetSockaddr* addr, u32 addrlen) {
|
||||
auto* netcall = Common::Singleton<NetInternal>::Instance();
|
||||
auto sock = netcall->FindSocket(s);
|
||||
if (!sock) {
|
||||
*Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF;
|
||||
LOG_ERROR(Lib_Net, "socket id is invalid = {}", s);
|
||||
return -1;
|
||||
}
|
||||
int returncode = sock->SendPacket(buf, len, flags, addr, addrlen);
|
||||
if (returncode >= 0) {
|
||||
return returncode;
|
||||
}
|
||||
*Libraries::Kernel::__Error() = returncode;
|
||||
LOG_ERROR(Lib_Net, "error code returned : {:#x}", (u32)returncode);
|
||||
return -1;
|
||||
}
|
||||
int PS4_SYSV_ABI sys_sendmsg(OrbisNetId s, const OrbisNetMsghdr* msg, int flags) {
|
||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||
return -1;
|
||||
}
|
||||
int PS4_SYSV_ABI sys_recvfrom(OrbisNetId s, void* buf, u64 len, int flags, OrbisNetSockaddr* addr,
|
||||
u32* paddrlen) {
|
||||
auto* netcall = Common::Singleton<NetInternal>::Instance();
|
||||
auto sock = netcall->FindSocket(s);
|
||||
if (!sock) {
|
||||
*Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF;
|
||||
LOG_ERROR(Lib_Net, "socket id is invalid = {}", s);
|
||||
return -1;
|
||||
}
|
||||
int returncode = sock->ReceivePacket(buf, len, flags, addr, paddrlen);
|
||||
if (returncode >= 0) {
|
||||
return returncode;
|
||||
}
|
||||
*Libraries::Kernel::__Error() = returncode;
|
||||
LOG_ERROR(Lib_Net, "error code returned : {:#x}", (u32)returncode);
|
||||
return -1;
|
||||
}
|
||||
int PS4_SYSV_ABI sys_recvmsg(OrbisNetId s, OrbisNetMsghdr* msg, int flags) {
|
||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||
return -1;
|
||||
}
|
||||
} // namespace Libraries::Net
|
31
src/core/libraries/network/sys_net.h
Normal file
31
src/core/libraries/network/sys_net.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/types.h"
|
||||
#include "net.h"
|
||||
|
||||
namespace Libraries::Net {
|
||||
|
||||
int PS4_SYSV_ABI sys_connect(OrbisNetId s, const OrbisNetSockaddr* addr, u32 addrlen);
|
||||
int PS4_SYSV_ABI sys_bind(OrbisNetId s, const OrbisNetSockaddr* addr, u32 addrlen);
|
||||
int PS4_SYSV_ABI sys_accept(OrbisNetId s, OrbisNetSockaddr* addr, u32* paddrlen);
|
||||
int PS4_SYSV_ABI sys_getpeername(OrbisNetId s, const OrbisNetSockaddr* addr, u32* paddrlen);
|
||||
int PS4_SYSV_ABI sys_getsockname(OrbisNetId s, OrbisNetSockaddr* addr, u32* paddrlen);
|
||||
int PS4_SYSV_ABI sys_getsockopt(OrbisNetId s, int level, int optname, void* optval, u32* optlen);
|
||||
int PS4_SYSV_ABI sys_listen(OrbisNetId s, int backlog);
|
||||
int PS4_SYSV_ABI sys_setsockopt(OrbisNetId s, int level, int optname, const void* optval,
|
||||
u32 optlen);
|
||||
int PS4_SYSV_ABI sys_shutdown(OrbisNetId s, int how);
|
||||
int PS4_SYSV_ABI sys_socketex(const char* name, int family, int type, int protocol);
|
||||
int PS4_SYSV_ABI sys_socket(int family, int type, int protocol);
|
||||
int PS4_SYSV_ABI sys_netabort(OrbisNetId s, int flags);
|
||||
int PS4_SYSV_ABI sys_socketclose(OrbisNetId s);
|
||||
int PS4_SYSV_ABI sys_sendto(OrbisNetId s, const void* buf, u64 len, int flags,
|
||||
const OrbisNetSockaddr* addr, u32 addrlen);
|
||||
int PS4_SYSV_ABI sys_sendmsg(OrbisNetId s, const OrbisNetMsghdr* msg, int flags);
|
||||
int PS4_SYSV_ABI sys_recvfrom(OrbisNetId s, void* buf, u64 len, int flags, OrbisNetSockaddr* addr,
|
||||
u32* paddrlen);
|
||||
int PS4_SYSV_ABI sys_recvmsg(OrbisNetId s, OrbisNetMsghdr* msg, int flags);
|
||||
} // namespace Libraries::Net
|
|
@ -380,8 +380,7 @@ s32 PS4_SYSV_ABI sceNgs2GeomApply(const OrbisNgs2GeomListenerWork* listener,
|
|||
|
||||
s32 PS4_SYSV_ABI sceNgs2PanInit(OrbisNgs2PanWork* work, const float* aSpeakerAngle, float unitAngle,
|
||||
u32 numSpeakers) {
|
||||
LOG_ERROR(Lib_Ngs2, "aSpeakerAngle = {}, unitAngle = {}, numSpeakers = {}", *aSpeakerAngle,
|
||||
unitAngle, numSpeakers);
|
||||
LOG_ERROR(Lib_Ngs2, "unitAngle = {}, numSpeakers = {}", unitAngle, numSpeakers);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -49,13 +49,11 @@ void SaveDialogResult::CopyTo(OrbisSaveDataDialogResult& result) const {
|
|||
result.mode = this->mode;
|
||||
result.result = this->result;
|
||||
result.buttonId = this->button_id;
|
||||
if (mode == SaveDataDialogMode::LIST || ElfInfo::Instance().FirmwareVer() >= ElfInfo::FW_45) {
|
||||
if (result.dirName != nullptr) {
|
||||
result.dirName->data.FromString(this->dir_name);
|
||||
}
|
||||
if (result.param != nullptr && this->param.GetString(SaveParams::MAINTITLE).has_value()) {
|
||||
result.param->FromSFO(this->param);
|
||||
}
|
||||
if (result.dirName != nullptr) {
|
||||
result.dirName->data.FromString(this->dir_name);
|
||||
}
|
||||
if (result.param != nullptr && this->param.GetString(SaveParams::MAINTITLE).has_value()) {
|
||||
result.param->FromSFO(this->param);
|
||||
}
|
||||
result.userData = this->user_data;
|
||||
}
|
||||
|
@ -345,12 +343,15 @@ SaveDialogUi::SaveDialogUi(SaveDialogUi&& other) noexcept
|
|||
}
|
||||
}
|
||||
|
||||
SaveDialogUi& SaveDialogUi::operator=(SaveDialogUi other) {
|
||||
SaveDialogUi& SaveDialogUi::operator=(SaveDialogUi&& other) noexcept {
|
||||
std::scoped_lock lock(draw_mutex, other.draw_mutex);
|
||||
using std::swap;
|
||||
swap(state, other.state);
|
||||
swap(status, other.status);
|
||||
swap(result, other.result);
|
||||
state = other.state;
|
||||
other.state = nullptr;
|
||||
status = other.status;
|
||||
other.status = nullptr;
|
||||
result = other.result;
|
||||
other.result = nullptr;
|
||||
if (status && *status == Status::RUNNING) {
|
||||
first_render = true;
|
||||
AddLayer(this);
|
||||
|
|
|
@ -300,7 +300,8 @@ public:
|
|||
~SaveDialogUi() override;
|
||||
SaveDialogUi(const SaveDialogUi& other) = delete;
|
||||
SaveDialogUi(SaveDialogUi&& other) noexcept;
|
||||
SaveDialogUi& operator=(SaveDialogUi other);
|
||||
SaveDialogUi& operator=(SaveDialogUi& other) = delete;
|
||||
SaveDialogUi& operator=(SaveDialogUi&& other) noexcept;
|
||||
|
||||
void Finish(ButtonId buttonId, CommonDialog::Result r = CommonDialog::Result::OK);
|
||||
|
||||
|
|
64
src/core/libraries/signin_dialog/signindialog.cpp
Normal file
64
src/core/libraries/signin_dialog/signindialog.cpp
Normal file
|
@ -0,0 +1,64 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
// Generated By moduleGenerator
|
||||
#include "common/logging/log.h"
|
||||
#include "core/libraries/error_codes.h"
|
||||
#include "core/libraries/libs.h"
|
||||
#include "signindialog.h"
|
||||
|
||||
namespace Libraries::SigninDialog {
|
||||
|
||||
s32 PS4_SYSV_ABI sceSigninDialogInitialize() {
|
||||
LOG_ERROR(Lib_SigninDialog, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceSigninDialogOpen() {
|
||||
LOG_ERROR(Lib_SigninDialog, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
Status PS4_SYSV_ABI sceSigninDialogGetStatus() {
|
||||
LOG_ERROR(Lib_SigninDialog, "(STUBBED) called, return 'finished' status");
|
||||
return Status::FINISHED;
|
||||
}
|
||||
|
||||
Status PS4_SYSV_ABI sceSigninDialogUpdateStatus() {
|
||||
LOG_ERROR(Lib_SigninDialog, "(STUBBED) called, return 'finished' status");
|
||||
return Status::FINISHED;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceSigninDialogGetResult() {
|
||||
LOG_ERROR(Lib_SigninDialog, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceSigninDialogClose() {
|
||||
LOG_ERROR(Lib_SigninDialog, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceSigninDialogTerminate() {
|
||||
LOG_ERROR(Lib_SigninDialog, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
void RegisterlibSceSigninDialog(Core::Loader::SymbolsResolver* sym) {
|
||||
LIB_FUNCTION("mlYGfmqE3fQ", "libSceSigninDialog", 1, "libSceSigninDialog", 1, 1,
|
||||
sceSigninDialogInitialize);
|
||||
LIB_FUNCTION("JlpJVoRWv7U", "libSceSigninDialog", 1, "libSceSigninDialog", 1, 1,
|
||||
sceSigninDialogOpen);
|
||||
LIB_FUNCTION("2m077aeC+PA", "libSceSigninDialog", 1, "libSceSigninDialog", 1, 1,
|
||||
sceSigninDialogGetStatus);
|
||||
LIB_FUNCTION("Bw31liTFT3A", "libSceSigninDialog", 1, "libSceSigninDialog", 1, 1,
|
||||
sceSigninDialogUpdateStatus);
|
||||
LIB_FUNCTION("nqG7rqnYw1U", "libSceSigninDialog", 1, "libSceSigninDialog", 1, 1,
|
||||
sceSigninDialogGetResult);
|
||||
LIB_FUNCTION("M3OkENHcyiU", "libSceSigninDialog", 1, "libSceSigninDialog", 1, 1,
|
||||
sceSigninDialogClose);
|
||||
LIB_FUNCTION("LXlmS6PvJdU", "libSceSigninDialog", 1, "libSceSigninDialog", 1, 1,
|
||||
sceSigninDialogTerminate);
|
||||
};
|
||||
|
||||
} // namespace Libraries::SigninDialog
|
29
src/core/libraries/signin_dialog/signindialog.h
Normal file
29
src/core/libraries/signin_dialog/signindialog.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
#include "common/types.h"
|
||||
|
||||
namespace Core::Loader {
|
||||
class SymbolsResolver;
|
||||
}
|
||||
|
||||
enum class Status : u32 {
|
||||
NONE = 0,
|
||||
INITIALIZED = 1,
|
||||
RUNNING = 2,
|
||||
FINISHED = 3,
|
||||
};
|
||||
|
||||
namespace Libraries::SigninDialog {
|
||||
|
||||
s32 PS4_SYSV_ABI sceSigninDialogInitialize();
|
||||
s32 PS4_SYSV_ABI sceSigninDialogOpen();
|
||||
Status PS4_SYSV_ABI sceSigninDialogGetStatus();
|
||||
Status PS4_SYSV_ABI sceSigninDialogUpdateStatus();
|
||||
s32 PS4_SYSV_ABI sceSigninDialogGetResult();
|
||||
s32 PS4_SYSV_ABI sceSigninDialogClose();
|
||||
s32 PS4_SYSV_ABI sceSigninDialogTerminate();
|
||||
|
||||
void RegisterlibSceSigninDialog(Core::Loader::SymbolsResolver* sym);
|
||||
} // namespace Libraries::SigninDialog
|
|
@ -19,11 +19,40 @@ int PS4_SYSV_ABI sceSysmoduleGetModuleHandleInternal() {
|
|||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceSysmoduleGetModuleInfoForUnwind(VAddr addr, s32 flags, void* info) {
|
||||
LOG_ERROR(Lib_SysModule, "(STUBBED) called");
|
||||
Kernel::OrbisModuleInfoForUnwind module_info;
|
||||
module_info.st_size = 0x130;
|
||||
s32 res = Kernel::sceKernelGetModuleInfoForUnwind(addr, flags, &module_info);
|
||||
s32 PS4_SYSV_ABI sceSysmoduleGetModuleInfoForUnwind(VAddr addr, s32 flags,
|
||||
Kernel::OrbisModuleInfoForUnwind* info) {
|
||||
LOG_TRACE(Lib_SysModule, "sceSysmoduleGetModuleInfoForUnwind(addr=0x{:X}, flags=0x{:X})", addr,
|
||||
flags);
|
||||
|
||||
s32 res = Kernel::sceKernelGetModuleInfoForUnwind(addr, flags, info);
|
||||
if (res != 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
static constexpr std::array<std::string_view, 17> modules_to_hide = {
|
||||
"libc.prx",
|
||||
"libc.sprx",
|
||||
"libSceAudioLatencyEstimation.prx",
|
||||
"libSceFace.prx",
|
||||
"libSceFaceTracker.prx",
|
||||
"libSceFios2.prx",
|
||||
"libSceFios2.sprx",
|
||||
"libSceFontGsm.prx",
|
||||
"libSceHand.prx",
|
||||
"libSceHandTracker.prx",
|
||||
"libSceHeadTracker.prx",
|
||||
"libSceJobManager.prx",
|
||||
"libSceNpCppWebApi.prx",
|
||||
"libSceNpToolkit.prx",
|
||||
"libSceNpToolkit2.prx",
|
||||
"libSceS3DConversion.prx",
|
||||
"libSceSmart.prx",
|
||||
};
|
||||
|
||||
const std::string_view module_name = info->name.data();
|
||||
if (std::ranges::find(modules_to_hide, module_name) != modules_to_hide.end()) {
|
||||
std::ranges::fill(info->name, '\0');
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -56,7 +85,6 @@ int PS4_SYSV_ABI sceSysmoduleIsLoadedInternal(OrbisSysModuleInternal id) {
|
|||
}
|
||||
|
||||
int PS4_SYSV_ABI sceSysmoduleLoadModule(OrbisSysModule id) {
|
||||
auto color_name = magic_enum::enum_name(id);
|
||||
LOG_ERROR(Lib_SysModule, "(DUMMY) called module = {}", magic_enum::enum_name(id));
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "common/types.h"
|
||||
#include "core/libraries/kernel/process.h"
|
||||
|
||||
namespace Core::Loader {
|
||||
class SymbolsResolver;
|
||||
|
@ -152,7 +153,8 @@ enum class OrbisSysModuleInternal : u32 {
|
|||
};
|
||||
|
||||
int PS4_SYSV_ABI sceSysmoduleGetModuleHandleInternal();
|
||||
s32 PS4_SYSV_ABI sceSysmoduleGetModuleInfoForUnwind(VAddr addr, s32 flags, void* info);
|
||||
s32 PS4_SYSV_ABI sceSysmoduleGetModuleInfoForUnwind(VAddr addr, s32 flags,
|
||||
Kernel::OrbisModuleInfoForUnwind* info);
|
||||
int PS4_SYSV_ABI sceSysmoduleIsCalledFromSysModule();
|
||||
int PS4_SYSV_ABI sceSysmoduleIsCameraPreloaded();
|
||||
int PS4_SYSV_ABI sceSysmoduleIsLoaded(OrbisSysModule id);
|
||||
|
|
|
@ -17,10 +17,12 @@ int PS4_SYSV_ABI sceVideodecCreateDecoder(const OrbisVideodecConfigInfo* pCfgInf
|
|||
LOG_INFO(Lib_Videodec, "called");
|
||||
|
||||
if (!pCfgInfoIn || !pRsrcInfoIn || !pCtrlOut) {
|
||||
LOG_ERROR(Lib_Videodec, "Invalid arguments");
|
||||
return ORBIS_VIDEODEC_ERROR_ARGUMENT_POINTER;
|
||||
}
|
||||
if (pCfgInfoIn->thisSize != sizeof(OrbisVideodecConfigInfo) ||
|
||||
pRsrcInfoIn->thisSize != sizeof(OrbisVideodecResourceInfo)) {
|
||||
LOG_ERROR(Lib_Videodec, "Invalid struct size");
|
||||
return ORBIS_VIDEODEC_ERROR_STRUCT_SIZE;
|
||||
}
|
||||
|
||||
|
@ -37,15 +39,18 @@ int PS4_SYSV_ABI sceVideodecDecode(OrbisVideodecCtrl* pCtrlIn,
|
|||
OrbisVideodecPictureInfo* pPictureInfoOut) {
|
||||
LOG_TRACE(Lib_Videodec, "called");
|
||||
if (!pCtrlIn || !pInputDataIn || !pPictureInfoOut) {
|
||||
LOG_ERROR(Lib_Videodec, "Invalid arguments");
|
||||
return ORBIS_VIDEODEC_ERROR_ARGUMENT_POINTER;
|
||||
}
|
||||
if (pCtrlIn->thisSize != sizeof(OrbisVideodecCtrl) ||
|
||||
pFrameBufferInOut->thisSize != sizeof(OrbisVideodecFrameBuffer)) {
|
||||
LOG_ERROR(Lib_Videodec, "Invalid struct size");
|
||||
return ORBIS_VIDEODEC_ERROR_STRUCT_SIZE;
|
||||
}
|
||||
|
||||
VdecDecoder* decoder = (VdecDecoder*)pCtrlIn->handle;
|
||||
if (!decoder) {
|
||||
LOG_ERROR(Lib_Videodec, "Invalid decoder handle");
|
||||
return ORBIS_VIDEODEC_ERROR_HANDLE;
|
||||
}
|
||||
return decoder->Decode(*pInputDataIn, *pFrameBufferInOut, *pPictureInfoOut);
|
||||
|
@ -56,6 +61,7 @@ int PS4_SYSV_ABI sceVideodecDeleteDecoder(OrbisVideodecCtrl* pCtrlIn) {
|
|||
|
||||
VdecDecoder* decoder = (VdecDecoder*)pCtrlIn->handle;
|
||||
if (!decoder) {
|
||||
LOG_ERROR(Lib_Videodec, "Invalid decoder handle");
|
||||
return ORBIS_VIDEODEC_ERROR_HANDLE;
|
||||
}
|
||||
delete decoder;
|
||||
|
@ -68,15 +74,18 @@ int PS4_SYSV_ABI sceVideodecFlush(OrbisVideodecCtrl* pCtrlIn,
|
|||
LOG_INFO(Lib_Videodec, "called");
|
||||
|
||||
if (!pFrameBufferInOut || !pPictureInfoOut) {
|
||||
LOG_ERROR(Lib_Videodec, "Invalid arguments");
|
||||
return ORBIS_VIDEODEC_ERROR_ARGUMENT_POINTER;
|
||||
}
|
||||
if (pFrameBufferInOut->thisSize != sizeof(OrbisVideodecFrameBuffer) ||
|
||||
pPictureInfoOut->thisSize != sizeof(OrbisVideodecPictureInfo)) {
|
||||
LOG_ERROR(Lib_Videodec, "Invalid struct size");
|
||||
return ORBIS_VIDEODEC_ERROR_STRUCT_SIZE;
|
||||
}
|
||||
|
||||
VdecDecoder* decoder = (VdecDecoder*)pCtrlIn->handle;
|
||||
if (!decoder) {
|
||||
LOG_ERROR(Lib_Videodec, "Invalid decoder handle");
|
||||
return ORBIS_VIDEODEC_ERROR_HANDLE;
|
||||
}
|
||||
return decoder->Flush(*pFrameBufferInOut, *pPictureInfoOut);
|
||||
|
@ -92,10 +101,12 @@ int PS4_SYSV_ABI sceVideodecQueryResourceInfo(const OrbisVideodecConfigInfo* pCf
|
|||
LOG_INFO(Lib_Videodec, "called");
|
||||
|
||||
if (!pCfgInfoIn || !pRsrcInfoOut) {
|
||||
LOG_ERROR(Lib_Videodec, "Invalid arguments");
|
||||
return ORBIS_VIDEODEC_ERROR_ARGUMENT_POINTER;
|
||||
}
|
||||
if (pCfgInfoIn->thisSize != sizeof(OrbisVideodecConfigInfo) ||
|
||||
pRsrcInfoOut->thisSize != sizeof(OrbisVideodecResourceInfo)) {
|
||||
LOG_ERROR(Lib_Videodec, "Invalid struct size");
|
||||
return ORBIS_VIDEODEC_ERROR_STRUCT_SIZE;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,9 +17,11 @@ sceVideodec2QueryComputeMemoryInfo(OrbisVideodec2ComputeMemoryInfo* computeMemIn
|
|||
LOG_INFO(Lib_Vdec2, "called");
|
||||
|
||||
if (!computeMemInfo) {
|
||||
LOG_ERROR(Lib_Vdec2, "Invalid arguments");
|
||||
return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER;
|
||||
}
|
||||
if (computeMemInfo->thisSize != sizeof(OrbisVideodec2ComputeMemoryInfo)) {
|
||||
LOG_ERROR(Lib_Vdec2, "Invalid struct size");
|
||||
return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE;
|
||||
}
|
||||
|
||||
|
@ -47,10 +49,12 @@ sceVideodec2QueryDecoderMemoryInfo(const OrbisVideodec2DecoderConfigInfo* decode
|
|||
LOG_INFO(Lib_Vdec2, "called");
|
||||
|
||||
if (!decoderCfgInfo || !decoderMemInfo) {
|
||||
LOG_ERROR(Lib_Vdec2, "Invalid arguments");
|
||||
return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER;
|
||||
}
|
||||
if (decoderCfgInfo->thisSize != sizeof(OrbisVideodec2DecoderConfigInfo) ||
|
||||
decoderMemInfo->thisSize != sizeof(OrbisVideodec2DecoderMemoryInfo)) {
|
||||
LOG_ERROR(Lib_Vdec2, "Invalid struct size");
|
||||
return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE;
|
||||
}
|
||||
|
||||
|
@ -74,10 +78,12 @@ s32 PS4_SYSV_ABI sceVideodec2CreateDecoder(const OrbisVideodec2DecoderConfigInfo
|
|||
LOG_INFO(Lib_Vdec2, "called");
|
||||
|
||||
if (!decoderCfgInfo || !decoderMemInfo || !decoder) {
|
||||
LOG_ERROR(Lib_Vdec2, "Invalid arguments");
|
||||
return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER;
|
||||
}
|
||||
if (decoderCfgInfo->thisSize != sizeof(OrbisVideodec2DecoderConfigInfo) ||
|
||||
decoderMemInfo->thisSize != sizeof(OrbisVideodec2DecoderMemoryInfo)) {
|
||||
LOG_ERROR(Lib_Vdec2, "Invalid struct size");
|
||||
return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE;
|
||||
}
|
||||
|
||||
|
@ -89,6 +95,7 @@ s32 PS4_SYSV_ABI sceVideodec2DeleteDecoder(OrbisVideodec2Decoder decoder) {
|
|||
LOG_INFO(Lib_Vdec2, "called");
|
||||
|
||||
if (!decoder) {
|
||||
LOG_ERROR(Lib_Vdec2, "Invalid arguments");
|
||||
return ORBIS_VIDEODEC2_ERROR_DECODER_INSTANCE;
|
||||
}
|
||||
|
||||
|
@ -103,13 +110,16 @@ s32 PS4_SYSV_ABI sceVideodec2Decode(OrbisVideodec2Decoder decoder,
|
|||
LOG_TRACE(Lib_Vdec2, "called");
|
||||
|
||||
if (!decoder) {
|
||||
LOG_ERROR(Lib_Vdec2, "Invalid decoder instance");
|
||||
return ORBIS_VIDEODEC2_ERROR_DECODER_INSTANCE;
|
||||
}
|
||||
if (!inputData || !frameBuffer || !outputInfo) {
|
||||
LOG_ERROR(Lib_Vdec2, "Invalid arguments");
|
||||
return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER;
|
||||
}
|
||||
if (inputData->thisSize != sizeof(OrbisVideodec2InputData) ||
|
||||
frameBuffer->thisSize != sizeof(OrbisVideodec2FrameBuffer)) {
|
||||
LOG_ERROR(Lib_Vdec2, "Invalid struct size");
|
||||
return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE;
|
||||
}
|
||||
|
||||
|
@ -122,13 +132,16 @@ s32 PS4_SYSV_ABI sceVideodec2Flush(OrbisVideodec2Decoder decoder,
|
|||
LOG_INFO(Lib_Vdec2, "called");
|
||||
|
||||
if (!decoder) {
|
||||
LOG_ERROR(Lib_Vdec2, "Invalid decoder instance");
|
||||
return ORBIS_VIDEODEC2_ERROR_DECODER_INSTANCE;
|
||||
}
|
||||
if (!frameBuffer || !outputInfo) {
|
||||
LOG_ERROR(Lib_Vdec2, "Invalid arguments");
|
||||
return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER;
|
||||
}
|
||||
if (frameBuffer->thisSize != sizeof(OrbisVideodec2FrameBuffer) ||
|
||||
outputInfo->thisSize != sizeof(OrbisVideodec2OutputInfo)) {
|
||||
LOG_ERROR(Lib_Vdec2, "Invalid struct size");
|
||||
return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE;
|
||||
}
|
||||
|
||||
|
@ -139,6 +152,7 @@ s32 PS4_SYSV_ABI sceVideodec2Reset(OrbisVideodec2Decoder decoder) {
|
|||
LOG_INFO(Lib_Vdec2, "called");
|
||||
|
||||
if (!decoder) {
|
||||
LOG_ERROR(Lib_Vdec2, "Invalid decoder instance");
|
||||
return ORBIS_VIDEODEC2_ERROR_DECODER_INSTANCE;
|
||||
}
|
||||
|
||||
|
@ -150,12 +164,15 @@ s32 PS4_SYSV_ABI sceVideodec2GetPictureInfo(const OrbisVideodec2OutputInfo* outp
|
|||
LOG_TRACE(Lib_Vdec2, "called");
|
||||
|
||||
if (!outputInfo) {
|
||||
LOG_ERROR(Lib_Vdec2, "Invalid arguments");
|
||||
return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER;
|
||||
}
|
||||
if (outputInfo->thisSize != sizeof(OrbisVideodec2OutputInfo)) {
|
||||
LOG_ERROR(Lib_Vdec2, "Invalid struct size");
|
||||
return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE;
|
||||
}
|
||||
if (outputInfo->pictureCount == 0 || gPictureInfos.empty()) {
|
||||
LOG_ERROR(Lib_Vdec2, "No picture info available");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
|
@ -163,6 +180,7 @@ s32 PS4_SYSV_ABI sceVideodec2GetPictureInfo(const OrbisVideodec2OutputInfo* outp
|
|||
OrbisVideodec2AvcPictureInfo* picInfo =
|
||||
static_cast<OrbisVideodec2AvcPictureInfo*>(p1stPictureInfoOut);
|
||||
if (picInfo->thisSize != sizeof(OrbisVideodec2AvcPictureInfo)) {
|
||||
LOG_ERROR(Lib_Vdec2, "Invalid struct size");
|
||||
return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE;
|
||||
}
|
||||
*picInfo = gPictureInfos.back();
|
||||
|
|
|
@ -220,7 +220,7 @@ s32 PS4_SYSV_ABI sceVideoOutGetEventData(const Kernel::SceKernelEvent* ev, s64*
|
|||
if (ev->ident != static_cast<s32>(OrbisVideoOutInternalEventId::Flip) || ev->data == 0) {
|
||||
*data = event_data;
|
||||
} else {
|
||||
*data = event_data | 0xFFFF000000000000;
|
||||
*data = event_data | 0xffff000000000000;
|
||||
}
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
@ -233,7 +233,8 @@ s32 PS4_SYSV_ABI sceVideoOutGetEventCount(const Kernel::SceKernelEvent* ev) {
|
|||
return ORBIS_VIDEO_OUT_ERROR_INVALID_EVENT;
|
||||
}
|
||||
|
||||
return (ev->data >> 0xc) & 0xf;
|
||||
auto event_data = static_cast<OrbisVideoOutEventData>(ev->data);
|
||||
return event_data.count;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVideoOutGetFlipStatus(s32 handle, FlipStatus* status) {
|
||||
|
|
|
@ -111,6 +111,12 @@ struct SceVideoOutColorSettings {
|
|||
u32 reserved[3];
|
||||
};
|
||||
|
||||
struct OrbisVideoOutEventData {
|
||||
u64 time : 12;
|
||||
u64 count : 4;
|
||||
u64 flip_arg : 48;
|
||||
};
|
||||
|
||||
void PS4_SYSV_ABI sceVideoOutSetBufferAttribute(BufferAttribute* attribute, PixelFormat pixelFormat,
|
||||
u32 tilingMode, u32 aspectRatio, u32 width,
|
||||
u32 height, u32 pitchInPixel);
|
||||
|
@ -128,8 +134,8 @@ s32 PS4_SYSV_ABI sceVideoOutGetResolutionStatus(s32 handle, SceVideoOutResolutio
|
|||
s32 PS4_SYSV_ABI sceVideoOutOpen(SceUserServiceUserId userId, s32 busType, s32 index,
|
||||
const void* param);
|
||||
s32 PS4_SYSV_ABI sceVideoOutClose(s32 handle);
|
||||
int PS4_SYSV_ABI sceVideoOutGetEventId(const Kernel::SceKernelEvent* ev);
|
||||
int PS4_SYSV_ABI sceVideoOutGetEventData(const Kernel::SceKernelEvent* ev, int64_t* data);
|
||||
s32 PS4_SYSV_ABI sceVideoOutGetEventId(const Kernel::SceKernelEvent* ev);
|
||||
s32 PS4_SYSV_ABI sceVideoOutGetEventData(const Kernel::SceKernelEvent* ev, s64* data);
|
||||
s32 PS4_SYSV_ABI sceVideoOutColorSettingsSetGamma(SceVideoOutColorSettings* settings, float gamma);
|
||||
s32 PS4_SYSV_ABI sceVideoOutAdjustColor(s32 handle, const SceVideoOutColorSettings* settings);
|
||||
|
||||
|
|
|
@ -127,7 +127,7 @@ void Linker::Execute(const std::vector<std::string> args) {
|
|||
}
|
||||
}
|
||||
params.entry_addr = module->GetEntryAddress();
|
||||
RunMainEntry(¶ms);
|
||||
ExecuteGuest(RunMainEntry, ¶ms);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -366,7 +366,8 @@ void* Linker::TlsGetAddr(u64 module_index, u64 offset) {
|
|||
if (!addr) {
|
||||
// Module was just loaded by above code. Allocate TLS block for it.
|
||||
const u32 init_image_size = module->tls.init_image_size;
|
||||
u8* dest = reinterpret_cast<u8*>(heap_api->heap_malloc(module->tls.image_size));
|
||||
u8* dest = reinterpret_cast<u8*>(
|
||||
Core::ExecuteGuest(heap_api->heap_malloc, module->tls.image_size));
|
||||
const u8* src = reinterpret_cast<const u8*>(module->tls.image_virtual_addr);
|
||||
std::memcpy(dest, src, init_image_size);
|
||||
std::memset(dest + init_image_size, 0, module->tls.image_size - init_image_size);
|
||||
|
|
|
@ -83,7 +83,7 @@ public:
|
|||
}
|
||||
|
||||
Module* GetModule(s32 index) const {
|
||||
if (index >= 0 || index < m_modules.size()) {
|
||||
if (index >= 0 && index < m_modules.size()) {
|
||||
return m_modules.at(index).get();
|
||||
}
|
||||
return nullptr;
|
||||
|
|
|
@ -75,7 +75,8 @@ u64 MemoryManager::ClampRangeSize(VAddr virtual_addr, u64 size) {
|
|||
|
||||
// Clamp size to the remaining size of the current VMA.
|
||||
auto vma = FindVMA(virtual_addr);
|
||||
ASSERT_MSG(vma != vma_map.end(), "Attempted to access invalid GPU address {:#x}", virtual_addr);
|
||||
ASSERT_MSG(vma->second.Contains(virtual_addr, 0),
|
||||
"Attempted to access invalid GPU address {:#x}", virtual_addr);
|
||||
u64 clamped_size = vma->second.base + vma->second.size - virtual_addr;
|
||||
++vma;
|
||||
|
||||
|
@ -96,6 +97,8 @@ u64 MemoryManager::ClampRangeSize(VAddr virtual_addr, u64 size) {
|
|||
bool MemoryManager::TryWriteBacking(void* address, const void* data, u32 num_bytes) {
|
||||
const VAddr virtual_addr = std::bit_cast<VAddr>(address);
|
||||
const auto& vma = FindVMA(virtual_addr)->second;
|
||||
ASSERT_MSG(vma.Contains(virtual_addr, 0),
|
||||
"Attempting to access out of bounds memory at address {:#x}", virtual_addr);
|
||||
if (vma.type != VMAType::Direct) {
|
||||
return false;
|
||||
}
|
||||
|
@ -106,31 +109,42 @@ bool MemoryManager::TryWriteBacking(void* address, const void* data, u32 num_byt
|
|||
|
||||
PAddr MemoryManager::PoolExpand(PAddr search_start, PAddr search_end, size_t size, u64 alignment) {
|
||||
std::scoped_lock lk{mutex};
|
||||
alignment = alignment > 0 ? alignment : 64_KB;
|
||||
|
||||
auto dmem_area = FindDmemArea(search_start);
|
||||
auto mapping_start = search_start > dmem_area->second.base
|
||||
? Common::AlignUp(search_start, alignment)
|
||||
: Common::AlignUp(dmem_area->second.base, alignment);
|
||||
auto mapping_end = mapping_start + size;
|
||||
|
||||
const auto is_suitable = [&] {
|
||||
const auto aligned_base = alignment > 0 ? Common::AlignUp(dmem_area->second.base, alignment)
|
||||
: dmem_area->second.base;
|
||||
const auto alignment_size = aligned_base - dmem_area->second.base;
|
||||
const auto remaining_size =
|
||||
dmem_area->second.size >= alignment_size ? dmem_area->second.size - alignment_size : 0;
|
||||
return dmem_area->second.is_free && remaining_size >= size;
|
||||
};
|
||||
while (!is_suitable() && dmem_area->second.GetEnd() <= search_end) {
|
||||
// Find the first free, large enough dmem area in the range.
|
||||
while (!dmem_area->second.is_free || dmem_area->second.GetEnd() < mapping_end) {
|
||||
// The current dmem_area isn't suitable, move to the next one.
|
||||
dmem_area++;
|
||||
}
|
||||
ASSERT_MSG(is_suitable(), "Unable to find free direct memory area: size = {:#x}", size);
|
||||
if (dmem_area == dmem_map.end()) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Align free position
|
||||
PAddr free_addr = dmem_area->second.base;
|
||||
free_addr = alignment > 0 ? Common::AlignUp(free_addr, alignment) : free_addr;
|
||||
// Update local variables based on the new dmem_area
|
||||
mapping_start = Common::AlignUp(dmem_area->second.base, alignment);
|
||||
mapping_end = mapping_start + size;
|
||||
}
|
||||
|
||||
if (dmem_area == dmem_map.end()) {
|
||||
// There are no suitable mappings in this range
|
||||
LOG_ERROR(Kernel_Vmm, "Unable to find free direct memory area: size = {:#x}", size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Add the allocated region to the list and commit its pages.
|
||||
auto& area = CarveDmemArea(free_addr, size)->second;
|
||||
auto& area = CarveDmemArea(mapping_start, size)->second;
|
||||
area.is_free = false;
|
||||
area.is_pooled = true;
|
||||
return free_addr;
|
||||
|
||||
// Track how much dmem was allocated for pools.
|
||||
pool_budget += size;
|
||||
|
||||
return mapping_start;
|
||||
}
|
||||
|
||||
PAddr MemoryManager::Allocate(PAddr search_start, PAddr search_end, size_t size, u64 alignment,
|
||||
|
@ -142,19 +156,19 @@ PAddr MemoryManager::Allocate(PAddr search_start, PAddr search_end, size_t size,
|
|||
auto mapping_start = search_start > dmem_area->second.base
|
||||
? Common::AlignUp(search_start, alignment)
|
||||
: Common::AlignUp(dmem_area->second.base, alignment);
|
||||
auto mapping_end = Common::AlignUp(mapping_start + size, alignment);
|
||||
auto mapping_end = mapping_start + size;
|
||||
|
||||
// Find the first free, large enough dmem area in the range.
|
||||
while ((!dmem_area->second.is_free || dmem_area->second.GetEnd() < mapping_end) &&
|
||||
dmem_area != dmem_map.end()) {
|
||||
while (!dmem_area->second.is_free || dmem_area->second.GetEnd() < mapping_end) {
|
||||
// The current dmem_area isn't suitable, move to the next one.
|
||||
dmem_area++;
|
||||
if (dmem_area == dmem_map.end()) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Update local variables based on the new dmem_area
|
||||
mapping_start = search_start > dmem_area->second.base
|
||||
? Common::AlignUp(search_start, alignment)
|
||||
: Common::AlignUp(dmem_area->second.base, alignment);
|
||||
mapping_end = Common::AlignUp(mapping_start + size, alignment);
|
||||
mapping_start = Common::AlignUp(dmem_area->second.base, alignment);
|
||||
mapping_end = mapping_start + size;
|
||||
}
|
||||
|
||||
if (dmem_area == dmem_map.end()) {
|
||||
|
@ -174,7 +188,6 @@ void MemoryManager::Free(PAddr phys_addr, size_t size) {
|
|||
std::scoped_lock lk{mutex};
|
||||
|
||||
auto dmem_area = CarveDmemArea(phys_addr, size);
|
||||
ASSERT(dmem_area != dmem_map.end() && dmem_area->second.size >= size);
|
||||
|
||||
// Release any dmem mappings that reference this physical block.
|
||||
std::vector<std::pair<VAddr, u64>> remove_list;
|
||||
|
@ -204,26 +217,32 @@ void MemoryManager::Free(PAddr phys_addr, size_t size) {
|
|||
int MemoryManager::PoolReserve(void** out_addr, VAddr virtual_addr, size_t size,
|
||||
MemoryMapFlags flags, u64 alignment) {
|
||||
std::scoped_lock lk{mutex};
|
||||
|
||||
virtual_addr = (virtual_addr == 0) ? impl.SystemManagedVirtualBase() : virtual_addr;
|
||||
alignment = alignment > 0 ? alignment : 2_MB;
|
||||
VAddr mapped_addr = alignment > 0 ? Common::AlignUp(virtual_addr, alignment) : virtual_addr;
|
||||
VAddr min_address = Common::AlignUp(impl.SystemManagedVirtualBase(), alignment);
|
||||
VAddr mapped_addr = Common::AlignUp(virtual_addr, alignment);
|
||||
|
||||
// Fixed mapping means the virtual address must exactly match the provided one.
|
||||
if (True(flags & MemoryMapFlags::Fixed)) {
|
||||
auto& vma = FindVMA(mapped_addr)->second;
|
||||
// If the VMA is mapped, unmap the region first.
|
||||
if (vma.IsMapped()) {
|
||||
// Make sure we're mapping to a valid address
|
||||
mapped_addr = mapped_addr > min_address ? mapped_addr : min_address;
|
||||
auto vma = FindVMA(mapped_addr)->second;
|
||||
size_t remaining_size = vma.base + vma.size - mapped_addr;
|
||||
// If the VMA is mapped or there's not enough space, unmap the region first.
|
||||
if (vma.IsMapped() || remaining_size < size) {
|
||||
UnmapMemoryImpl(mapped_addr, size);
|
||||
vma = FindVMA(mapped_addr)->second;
|
||||
}
|
||||
const size_t remaining_size = vma.base + vma.size - mapped_addr;
|
||||
ASSERT_MSG(vma.type == VMAType::Free && remaining_size >= size);
|
||||
}
|
||||
|
||||
// Find the first free area starting with provided virtual address.
|
||||
if (False(flags & MemoryMapFlags::Fixed)) {
|
||||
// When MemoryMapFlags::Fixed is not specified, and mapped_addr is 0,
|
||||
// search from address 0x200000000 instead.
|
||||
mapped_addr = mapped_addr == 0 ? 0x200000000 : mapped_addr;
|
||||
mapped_addr = SearchFree(mapped_addr, size, alignment);
|
||||
if (mapped_addr == -1) {
|
||||
// No suitable memory areas to map to
|
||||
return ORBIS_KERNEL_ERROR_ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
// Add virtual memory area
|
||||
|
@ -231,9 +250,8 @@ int MemoryManager::PoolReserve(void** out_addr, VAddr virtual_addr, size_t size,
|
|||
auto& new_vma = new_vma_handle->second;
|
||||
new_vma.disallow_merge = True(flags & MemoryMapFlags::NoCoalesce);
|
||||
new_vma.prot = MemoryProt::NoAccess;
|
||||
new_vma.name = "";
|
||||
new_vma.name = "anon";
|
||||
new_vma.type = VMAType::PoolReserved;
|
||||
MergeAdjacent(vma_map, new_vma_handle);
|
||||
|
||||
*out_addr = std::bit_cast<void*>(mapped_addr);
|
||||
return ORBIS_OK;
|
||||
|
@ -249,19 +267,22 @@ int MemoryManager::Reserve(void** out_addr, VAddr virtual_addr, size_t size, Mem
|
|||
|
||||
// Fixed mapping means the virtual address must exactly match the provided one.
|
||||
if (True(flags & MemoryMapFlags::Fixed)) {
|
||||
auto& vma = FindVMA(mapped_addr)->second;
|
||||
// If the VMA is mapped, unmap the region first.
|
||||
if (vma.IsMapped()) {
|
||||
auto vma = FindVMA(mapped_addr)->second;
|
||||
size_t remaining_size = vma.base + vma.size - mapped_addr;
|
||||
// If the VMA is mapped or there's not enough space, unmap the region first.
|
||||
if (vma.IsMapped() || remaining_size < size) {
|
||||
UnmapMemoryImpl(mapped_addr, size);
|
||||
vma = FindVMA(mapped_addr)->second;
|
||||
}
|
||||
const size_t remaining_size = vma.base + vma.size - mapped_addr;
|
||||
ASSERT_MSG(vma.type == VMAType::Free && remaining_size >= size);
|
||||
}
|
||||
|
||||
// Find the first free area starting with provided virtual address.
|
||||
if (False(flags & MemoryMapFlags::Fixed)) {
|
||||
mapped_addr = SearchFree(mapped_addr, size, alignment);
|
||||
if (mapped_addr == -1) {
|
||||
// No suitable memory areas to map to
|
||||
return ORBIS_KERNEL_ERROR_ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
// Add virtual memory area
|
||||
|
@ -269,7 +290,7 @@ int MemoryManager::Reserve(void** out_addr, VAddr virtual_addr, size_t size, Mem
|
|||
auto& new_vma = new_vma_handle->second;
|
||||
new_vma.disallow_merge = True(flags & MemoryMapFlags::NoCoalesce);
|
||||
new_vma.prot = MemoryProt::NoAccess;
|
||||
new_vma.name = "";
|
||||
new_vma.name = "anon";
|
||||
new_vma.type = VMAType::Reserved;
|
||||
MergeAdjacent(vma_map, new_vma_handle);
|
||||
|
||||
|
@ -282,29 +303,51 @@ int MemoryManager::PoolCommit(VAddr virtual_addr, size_t size, MemoryProt prot)
|
|||
|
||||
const u64 alignment = 64_KB;
|
||||
|
||||
// When virtual addr is zero, force it to virtual_base. The guest cannot pass Fixed
|
||||
// flag so we will take the branch that searches for free (or reserved) mappings.
|
||||
virtual_addr = (virtual_addr == 0) ? impl.SystemManagedVirtualBase() : virtual_addr;
|
||||
// Input addresses to PoolCommit are treated as fixed.
|
||||
VAddr mapped_addr = Common::AlignUp(virtual_addr, alignment);
|
||||
|
||||
// This should return SCE_KERNEL_ERROR_ENOMEM but shouldn't normally happen.
|
||||
const auto& vma = FindVMA(mapped_addr)->second;
|
||||
const size_t remaining_size = vma.base + vma.size - mapped_addr;
|
||||
ASSERT_MSG(!vma.IsMapped() && remaining_size >= size);
|
||||
auto& vma = FindVMA(mapped_addr)->second;
|
||||
if (vma.type != VMAType::PoolReserved) {
|
||||
// If we're attempting to commit non-pooled memory, return EINVAL
|
||||
LOG_ERROR(Kernel_Vmm, "Attempting to commit non-pooled memory at {:#x}", mapped_addr);
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
|
||||
// Perform the mapping.
|
||||
void* out_addr = impl.Map(mapped_addr, size, alignment, -1, false);
|
||||
TRACK_ALLOC(out_addr, size, "VMEM");
|
||||
if (!vma.Contains(mapped_addr, size)) {
|
||||
// If there's not enough space to commit, return EINVAL
|
||||
LOG_ERROR(Kernel_Vmm,
|
||||
"Pooled region {:#x} to {:#x} is not large enough to commit from {:#x} to {:#x}",
|
||||
vma.base, vma.base + vma.size, mapped_addr, mapped_addr + size);
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
|
||||
auto& new_vma = CarveVMA(mapped_addr, size)->second;
|
||||
if (pool_budget <= size) {
|
||||
// If there isn't enough pooled memory to perform the mapping, return ENOMEM
|
||||
LOG_ERROR(Kernel_Vmm, "Not enough pooled memory to perform mapping");
|
||||
return ORBIS_KERNEL_ERROR_ENOMEM;
|
||||
} else {
|
||||
// Track how much pooled memory this commit will take
|
||||
pool_budget -= size;
|
||||
}
|
||||
|
||||
// Carve out the new VMA representing this mapping
|
||||
const auto new_vma_handle = CarveVMA(mapped_addr, size);
|
||||
auto& new_vma = new_vma_handle->second;
|
||||
new_vma.disallow_merge = false;
|
||||
new_vma.prot = prot;
|
||||
new_vma.name = "";
|
||||
new_vma.name = "anon";
|
||||
new_vma.type = Core::VMAType::Pooled;
|
||||
new_vma.is_exec = false;
|
||||
new_vma.phys_base = 0;
|
||||
|
||||
rasterizer->MapMemory(mapped_addr, size);
|
||||
// Perform the mapping
|
||||
void* out_addr = impl.Map(mapped_addr, size, alignment, -1, false);
|
||||
TRACK_ALLOC(out_addr, size, "VMEM");
|
||||
|
||||
if (IsValidGpuMapping(mapped_addr, size)) {
|
||||
rasterizer->MapMemory(mapped_addr, size);
|
||||
}
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
|
@ -327,15 +370,34 @@ int MemoryManager::MapMemory(void** out_addr, VAddr virtual_addr, size_t size, M
|
|||
|
||||
// Fixed mapping means the virtual address must exactly match the provided one.
|
||||
if (True(flags & MemoryMapFlags::Fixed)) {
|
||||
// This should return SCE_KERNEL_ERROR_ENOMEM but shouldn't normally happen.
|
||||
const auto& vma = FindVMA(mapped_addr)->second;
|
||||
const size_t remaining_size = vma.base + vma.size - mapped_addr;
|
||||
ASSERT_MSG(!vma.IsMapped() && remaining_size >= size);
|
||||
auto vma = FindVMA(mapped_addr)->second;
|
||||
size_t remaining_size = vma.base + vma.size - mapped_addr;
|
||||
// There's a possible edge case where we're mapping to a partially reserved range.
|
||||
// To account for this, unmap any reserved areas within this mapping range first.
|
||||
auto unmap_addr = mapped_addr;
|
||||
auto unmap_size = size;
|
||||
while (!vma.IsMapped() && unmap_addr < mapped_addr + size && remaining_size < size) {
|
||||
auto unmapped = UnmapBytesFromEntry(unmap_addr, vma, unmap_size);
|
||||
unmap_addr += unmapped;
|
||||
unmap_size -= unmapped;
|
||||
vma = FindVMA(unmap_addr)->second;
|
||||
}
|
||||
|
||||
// This should return SCE_KERNEL_ERROR_ENOMEM but rarely happens.
|
||||
vma = FindVMA(mapped_addr)->second;
|
||||
remaining_size = vma.base + vma.size - mapped_addr;
|
||||
ASSERT_MSG(!vma.IsMapped() && remaining_size >= size,
|
||||
"Memory region {:#x} to {:#x} isn't free enough to map region {:#x} to {:#x}",
|
||||
vma.base, vma.base + vma.size, virtual_addr, virtual_addr + size);
|
||||
}
|
||||
|
||||
// Find the first free area starting with provided virtual address.
|
||||
if (False(flags & MemoryMapFlags::Fixed)) {
|
||||
mapped_addr = SearchFree(mapped_addr, size, alignment);
|
||||
if (mapped_addr == -1) {
|
||||
// No suitable memory areas to map to
|
||||
return ORBIS_KERNEL_ERROR_ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
// Perform the mapping.
|
||||
|
@ -355,7 +417,10 @@ int MemoryManager::MapMemory(void** out_addr, VAddr virtual_addr, size_t size, M
|
|||
if (type == VMAType::Flexible) {
|
||||
flexible_usage += size;
|
||||
}
|
||||
rasterizer->MapMemory(mapped_addr, size);
|
||||
|
||||
if (IsValidGpuMapping(mapped_addr, size)) {
|
||||
rasterizer->MapMemory(mapped_addr, size);
|
||||
}
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
@ -368,12 +433,18 @@ int MemoryManager::MapFile(void** out_addr, VAddr virtual_addr, size_t size, Mem
|
|||
// Find first free area to map the file.
|
||||
if (False(flags & MemoryMapFlags::Fixed)) {
|
||||
mapped_addr = SearchFree(mapped_addr, size_aligned, 1);
|
||||
if (mapped_addr == -1) {
|
||||
// No suitable memory areas to map to
|
||||
return ORBIS_KERNEL_ERROR_ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
if (True(flags & MemoryMapFlags::Fixed)) {
|
||||
const auto& vma = FindVMA(virtual_addr)->second;
|
||||
const size_t remaining_size = vma.base + vma.size - virtual_addr;
|
||||
ASSERT_MSG(!vma.IsMapped() && remaining_size >= size);
|
||||
ASSERT_MSG(!vma.IsMapped() && remaining_size >= size,
|
||||
"Memory region {:#x} to {:#x} isn't free enough to map region {:#x} to {:#x}",
|
||||
vma.base, vma.base + vma.size, virtual_addr, virtual_addr + size);
|
||||
}
|
||||
|
||||
// Map the file.
|
||||
|
@ -391,7 +462,7 @@ int MemoryManager::MapFile(void** out_addr, VAddr virtual_addr, size_t size, Mem
|
|||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
void MemoryManager::PoolDecommit(VAddr virtual_addr, size_t size) {
|
||||
s32 MemoryManager::PoolDecommit(VAddr virtual_addr, size_t size) {
|
||||
std::scoped_lock lk{mutex};
|
||||
|
||||
const auto it = FindVMA(virtual_addr);
|
||||
|
@ -406,7 +477,19 @@ void MemoryManager::PoolDecommit(VAddr virtual_addr, size_t size) {
|
|||
const auto start_in_vma = virtual_addr - vma_base_addr;
|
||||
const auto type = vma_base.type;
|
||||
|
||||
rasterizer->UnmapMemory(virtual_addr, size);
|
||||
if (type != VMAType::PoolReserved && type != VMAType::Pooled) {
|
||||
LOG_ERROR(Kernel_Vmm, "Attempting to decommit non-pooled memory!");
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
|
||||
if (type == VMAType::Pooled) {
|
||||
// Track how much pooled memory is decommitted
|
||||
pool_budget += size;
|
||||
}
|
||||
|
||||
if (IsValidGpuMapping(virtual_addr, size)) {
|
||||
rasterizer->UnmapMemory(virtual_addr, size);
|
||||
}
|
||||
|
||||
// Mark region as free and attempt to coalesce it with neighbours.
|
||||
const auto new_it = CarveVMA(virtual_addr, size);
|
||||
|
@ -415,13 +498,17 @@ void MemoryManager::PoolDecommit(VAddr virtual_addr, size_t size) {
|
|||
vma.prot = MemoryProt::NoAccess;
|
||||
vma.phys_base = 0;
|
||||
vma.disallow_merge = false;
|
||||
vma.name = "";
|
||||
vma.name = "anon";
|
||||
MergeAdjacent(vma_map, new_it);
|
||||
|
||||
// Unmap the memory region.
|
||||
impl.Unmap(vma_base_addr, vma_base_size, start_in_vma, start_in_vma + size, phys_base, is_exec,
|
||||
false, false);
|
||||
TRACK_FREE(virtual_addr, "VMEM");
|
||||
if (type != VMAType::PoolReserved) {
|
||||
// Unmap the memory region.
|
||||
impl.Unmap(vma_base_addr, vma_base_size, start_in_vma, start_in_vma + size, phys_base,
|
||||
is_exec, false, false);
|
||||
TRACK_FREE(virtual_addr, "VMEM");
|
||||
}
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 MemoryManager::UnmapMemory(VAddr virtual_addr, size_t size) {
|
||||
|
@ -446,7 +533,10 @@ u64 MemoryManager::UnmapBytesFromEntry(VAddr virtual_addr, VirtualMemoryArea vma
|
|||
if (type == VMAType::Flexible) {
|
||||
flexible_usage -= adjusted_size;
|
||||
}
|
||||
rasterizer->UnmapMemory(virtual_addr, adjusted_size);
|
||||
|
||||
if (IsValidGpuMapping(virtual_addr, adjusted_size)) {
|
||||
rasterizer->UnmapMemory(virtual_addr, adjusted_size);
|
||||
}
|
||||
|
||||
// Mark region as free and attempt to coalesce it with neighbours.
|
||||
const auto new_it = CarveVMA(virtual_addr, adjusted_size);
|
||||
|
@ -473,6 +563,8 @@ s32 MemoryManager::UnmapMemoryImpl(VAddr virtual_addr, u64 size) {
|
|||
do {
|
||||
auto it = FindVMA(virtual_addr + unmapped_bytes);
|
||||
auto& vma_base = it->second;
|
||||
ASSERT_MSG(vma_base.Contains(virtual_addr + unmapped_bytes, 0),
|
||||
"Address {:#x} is out of bounds", virtual_addr + unmapped_bytes);
|
||||
auto unmapped =
|
||||
UnmapBytesFromEntry(virtual_addr + unmapped_bytes, vma_base, size - unmapped_bytes);
|
||||
ASSERT_MSG(unmapped > 0, "Failed to unmap memory, progress is impossible");
|
||||
|
@ -487,7 +579,10 @@ int MemoryManager::QueryProtection(VAddr addr, void** start, void** end, u32* pr
|
|||
|
||||
const auto it = FindVMA(addr);
|
||||
const auto& vma = it->second;
|
||||
ASSERT_MSG(vma.type != VMAType::Free, "Provided address is not mapped");
|
||||
if (!vma.Contains(addr, 0) || vma.IsFree()) {
|
||||
LOG_ERROR(Kernel_Vmm, "Address {:#x} is not mapped", addr);
|
||||
return ORBIS_KERNEL_ERROR_EACCES;
|
||||
}
|
||||
|
||||
if (start != nullptr) {
|
||||
*start = reinterpret_cast<void*>(vma.base);
|
||||
|
@ -554,17 +649,23 @@ s64 MemoryManager::ProtectBytes(VAddr addr, VirtualMemoryArea vma_base, size_t s
|
|||
s32 MemoryManager::Protect(VAddr addr, size_t size, MemoryProt prot) {
|
||||
std::scoped_lock lk{mutex};
|
||||
s64 protected_bytes = 0;
|
||||
|
||||
auto aligned_addr = Common::AlignDown(addr, 16_KB);
|
||||
auto aligned_size = Common::AlignUp(size + addr - aligned_addr, 16_KB);
|
||||
do {
|
||||
auto it = FindVMA(addr + protected_bytes);
|
||||
auto it = FindVMA(aligned_addr + protected_bytes);
|
||||
auto& vma_base = it->second;
|
||||
ASSERT_MSG(vma_base.Contains(addr + protected_bytes, 0), "Address {:#x} is out of bounds",
|
||||
addr + protected_bytes);
|
||||
auto result = 0;
|
||||
result = ProtectBytes(addr + protected_bytes, vma_base, size - protected_bytes, prot);
|
||||
result = ProtectBytes(aligned_addr + protected_bytes, vma_base,
|
||||
aligned_size - protected_bytes, prot);
|
||||
if (result < 0) {
|
||||
// ProtectBytes returned an error, return it
|
||||
return result;
|
||||
}
|
||||
protected_bytes += result;
|
||||
} while (protected_bytes < size);
|
||||
} while (protected_bytes < aligned_size);
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
@ -573,8 +674,16 @@ int MemoryManager::VirtualQuery(VAddr addr, int flags,
|
|||
::Libraries::Kernel::OrbisVirtualQueryInfo* info) {
|
||||
std::scoped_lock lk{mutex};
|
||||
|
||||
auto it = FindVMA(addr);
|
||||
if (it->second.type == VMAType::Free && flags == 1) {
|
||||
// FindVMA on addresses before the vma_map return garbage data.
|
||||
auto query_addr =
|
||||
addr < impl.SystemManagedVirtualBase() ? impl.SystemManagedVirtualBase() : addr;
|
||||
if (addr < query_addr && flags == 0) {
|
||||
LOG_WARNING(Kernel_Vmm, "VirtualQuery on free memory region");
|
||||
return ORBIS_KERNEL_ERROR_EACCES;
|
||||
}
|
||||
auto it = FindVMA(query_addr);
|
||||
|
||||
while (it->second.type == VMAType::Free && flags == 1 && it != --vma_map.end()) {
|
||||
++it;
|
||||
}
|
||||
if (it->second.type == VMAType::Free) {
|
||||
|
@ -587,15 +696,17 @@ int MemoryManager::VirtualQuery(VAddr addr, int flags,
|
|||
info->end = vma.base + vma.size;
|
||||
info->offset = vma.phys_base;
|
||||
info->protection = static_cast<s32>(vma.prot);
|
||||
info->is_flexible.Assign(vma.type == VMAType::Flexible);
|
||||
info->is_direct.Assign(vma.type == VMAType::Direct);
|
||||
info->is_stack.Assign(vma.type == VMAType::Stack);
|
||||
info->is_pooled.Assign(vma.type == VMAType::PoolReserved || vma.type == VMAType::Pooled);
|
||||
info->is_committed.Assign(vma.IsMapped());
|
||||
vma.name.copy(info->name.data(), std::min(info->name.size(), vma.name.size()));
|
||||
info->is_flexible = vma.type == VMAType::Flexible ? 1 : 0;
|
||||
info->is_direct = vma.type == VMAType::Direct ? 1 : 0;
|
||||
info->is_stack = vma.type == VMAType::Stack ? 1 : 0;
|
||||
info->is_pooled = vma.type == VMAType::PoolReserved || vma.type == VMAType::Pooled ? 1 : 0;
|
||||
info->is_committed = vma.IsMapped() ? 1 : 0;
|
||||
|
||||
strncpy(info->name, vma.name.data(), ::Libraries::Kernel::ORBIS_KERNEL_MAXIMUM_NAME_LENGTH);
|
||||
|
||||
if (vma.type == VMAType::Direct) {
|
||||
const auto dmem_it = FindDmemArea(vma.phys_base);
|
||||
ASSERT(dmem_it != dmem_map.end());
|
||||
ASSERT_MSG(vma.phys_base <= dmem_it->second.GetEnd(), "vma.phys_base is not in dmem_map!");
|
||||
info->memory_type = dmem_it->second.memory_type;
|
||||
} else {
|
||||
info->memory_type = ::Libraries::Kernel::SCE_KERNEL_WB_ONION;
|
||||
|
@ -609,11 +720,11 @@ int MemoryManager::DirectMemoryQuery(PAddr addr, bool find_next,
|
|||
std::scoped_lock lk{mutex};
|
||||
|
||||
auto dmem_area = FindDmemArea(addr);
|
||||
while (dmem_area != dmem_map.end() && dmem_area->second.is_free && find_next) {
|
||||
while (dmem_area != --dmem_map.end() && dmem_area->second.is_free && find_next) {
|
||||
dmem_area++;
|
||||
}
|
||||
|
||||
if (dmem_area == dmem_map.end() || dmem_area->second.is_free) {
|
||||
if (dmem_area->second.is_free) {
|
||||
LOG_ERROR(Core, "Unable to find allocated direct memory region to query!");
|
||||
return ORBIS_KERNEL_ERROR_EACCES;
|
||||
}
|
||||
|
@ -693,36 +804,56 @@ VAddr MemoryManager::SearchFree(VAddr virtual_addr, size_t size, u32 alignment)
|
|||
virtual_addr = min_search_address;
|
||||
}
|
||||
|
||||
// If the requested address is beyond the maximum our code can handle, throw an assert
|
||||
auto max_search_address = impl.UserVirtualBase() + impl.UserVirtualSize();
|
||||
ASSERT_MSG(virtual_addr <= max_search_address, "Input address {:#x} is out of bounds",
|
||||
virtual_addr);
|
||||
|
||||
auto it = FindVMA(virtual_addr);
|
||||
ASSERT_MSG(it != vma_map.end(), "Specified mapping address was not found!");
|
||||
|
||||
// If the VMA is free and contains the requested mapping we are done.
|
||||
if (it->second.IsFree() && it->second.Contains(virtual_addr, size)) {
|
||||
return virtual_addr;
|
||||
}
|
||||
|
||||
// Search for the first free VMA that fits our mapping.
|
||||
const auto is_suitable = [&] {
|
||||
while (it != vma_map.end()) {
|
||||
if (!it->second.IsFree()) {
|
||||
return false;
|
||||
it++;
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto& vma = it->second;
|
||||
virtual_addr = Common::AlignUp(vma.base, alignment);
|
||||
// Sometimes the alignment itself might be larger than the VMA.
|
||||
if (virtual_addr > vma.base + vma.size) {
|
||||
return false;
|
||||
it++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Make sure the address is within our defined bounds
|
||||
if (virtual_addr >= max_search_address) {
|
||||
// There are no free mappings within our safely usable address space.
|
||||
break;
|
||||
}
|
||||
|
||||
// If there's enough space in the VMA, return the address.
|
||||
const size_t remaining_size = vma.base + vma.size - virtual_addr;
|
||||
return remaining_size >= size;
|
||||
};
|
||||
while (!is_suitable()) {
|
||||
++it;
|
||||
if (remaining_size >= size) {
|
||||
return virtual_addr;
|
||||
}
|
||||
it++;
|
||||
}
|
||||
return virtual_addr;
|
||||
|
||||
// Couldn't find a suitable VMA, return an error.
|
||||
LOG_ERROR(Kernel_Vmm, "Couldn't find a free mapping for address {:#x}, size {:#x}",
|
||||
virtual_addr, size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
MemoryManager::VMAHandle MemoryManager::CarveVMA(VAddr virtual_addr, size_t size) {
|
||||
auto vma_handle = FindVMA(virtual_addr);
|
||||
ASSERT_MSG(vma_handle != vma_map.end(), "Virtual address not in vm_map");
|
||||
ASSERT_MSG(vma_handle->second.Contains(virtual_addr, 0), "Virtual address not in vm_map");
|
||||
|
||||
const VirtualMemoryArea& vma = vma_handle->second;
|
||||
ASSERT_MSG(vma.base <= virtual_addr, "Adding a mapping to already mapped region");
|
||||
|
@ -751,7 +882,7 @@ MemoryManager::VMAHandle MemoryManager::CarveVMA(VAddr virtual_addr, size_t size
|
|||
|
||||
MemoryManager::DMemHandle MemoryManager::CarveDmemArea(PAddr addr, size_t size) {
|
||||
auto dmem_handle = FindDmemArea(addr);
|
||||
ASSERT_MSG(dmem_handle != dmem_map.end(), "Physical address not in dmem_map");
|
||||
ASSERT_MSG(addr <= dmem_handle->second.GetEnd(), "Physical address not in dmem_map");
|
||||
|
||||
const DirectMemoryArea& area = dmem_handle->second;
|
||||
ASSERT_MSG(area.base <= addr, "Adding an allocation to already allocated region");
|
||||
|
@ -806,7 +937,7 @@ int MemoryManager::GetDirectMemoryType(PAddr addr, int* directMemoryTypeOut,
|
|||
|
||||
auto dmem_area = FindDmemArea(addr);
|
||||
|
||||
if (dmem_area == dmem_map.end() || dmem_area->second.is_free) {
|
||||
if (addr > dmem_area->second.GetEnd() || dmem_area->second.is_free) {
|
||||
LOG_ERROR(Core, "Unable to find allocated direct memory region to check type!");
|
||||
return ORBIS_KERNEL_ERROR_ENOENT;
|
||||
}
|
||||
|
@ -818,4 +949,33 @@ int MemoryManager::GetDirectMemoryType(PAddr addr, int* directMemoryTypeOut,
|
|||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int MemoryManager::IsStack(VAddr addr, void** start, void** end) {
|
||||
auto vma_handle = FindVMA(addr);
|
||||
if (vma_handle == vma_map.end()) {
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
|
||||
const VirtualMemoryArea& vma = vma_handle->second;
|
||||
if (!vma.Contains(addr, 0) || vma.IsFree()) {
|
||||
return ORBIS_KERNEL_ERROR_EACCES;
|
||||
}
|
||||
|
||||
auto stack_start = 0ul;
|
||||
auto stack_end = 0ul;
|
||||
if (vma.type == VMAType::Stack) {
|
||||
stack_start = vma.base;
|
||||
stack_end = vma.base + vma.size;
|
||||
}
|
||||
|
||||
if (start != nullptr) {
|
||||
*start = reinterpret_cast<void*>(stack_start);
|
||||
}
|
||||
|
||||
if (end != nullptr) {
|
||||
*end = reinterpret_cast<void*>(stack_end);
|
||||
}
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
} // namespace Core
|
||||
|
|
|
@ -157,6 +157,12 @@ public:
|
|||
return impl.SystemReservedVirtualBase();
|
||||
}
|
||||
|
||||
bool IsValidGpuMapping(VAddr virtual_addr, u64 size) {
|
||||
// The PS4's GPU can only handle 40 bit addresses.
|
||||
const VAddr max_gpu_address{0x10000000000};
|
||||
return virtual_addr + size < max_gpu_address;
|
||||
}
|
||||
|
||||
bool IsValidAddress(const void* addr) const noexcept {
|
||||
const VAddr virtual_addr = reinterpret_cast<VAddr>(addr);
|
||||
const auto end_it = std::prev(vma_map.end());
|
||||
|
@ -186,13 +192,13 @@ public:
|
|||
int PoolCommit(VAddr virtual_addr, size_t size, MemoryProt prot);
|
||||
|
||||
int MapMemory(void** out_addr, VAddr virtual_addr, size_t size, MemoryProt prot,
|
||||
MemoryMapFlags flags, VMAType type, std::string_view name = "",
|
||||
MemoryMapFlags flags, VMAType type, std::string_view name = "anon",
|
||||
bool is_exec = false, PAddr phys_addr = -1, u64 alignment = 0);
|
||||
|
||||
int MapFile(void** out_addr, VAddr virtual_addr, size_t size, MemoryProt prot,
|
||||
MemoryMapFlags flags, uintptr_t fd, size_t offset);
|
||||
|
||||
void PoolDecommit(VAddr virtual_addr, size_t size);
|
||||
s32 PoolDecommit(VAddr virtual_addr, size_t size);
|
||||
|
||||
s32 UnmapMemory(VAddr virtual_addr, size_t size);
|
||||
|
||||
|
@ -217,6 +223,8 @@ public:
|
|||
|
||||
void InvalidateMemory(VAddr addr, u64 size) const;
|
||||
|
||||
int IsStack(VAddr addr, void** start, void** end);
|
||||
|
||||
private:
|
||||
VMAHandle FindVMA(VAddr target) {
|
||||
return std::prev(vma_map.upper_bound(target));
|
||||
|
@ -268,6 +276,7 @@ private:
|
|||
size_t total_direct_size{};
|
||||
size_t total_flexible_size{};
|
||||
size_t flexible_usage{};
|
||||
size_t pool_budget{};
|
||||
Vulkan::Rasterizer* rasterizer{};
|
||||
|
||||
friend class ::Core::Devtools::Widget::MemoryMapViewer;
|
||||
|
|
|
@ -19,8 +19,7 @@ namespace Core {
|
|||
|
||||
using EntryFunc = PS4_SYSV_ABI int (*)(size_t args, const void* argp, void* param);
|
||||
|
||||
static u64 LoadOffset = CODE_BASE_OFFSET;
|
||||
static constexpr u64 CODE_BASE_INCR = 0x010000000u;
|
||||
static constexpr u64 ModuleLoadBase = 0x800000000;
|
||||
|
||||
static u64 GetAlignedSize(const elf_program_header& phdr) {
|
||||
return (phdr.p_align != 0 ? (phdr.p_memsz + (phdr.p_align - 1)) & ~(phdr.p_align - 1)
|
||||
|
@ -84,7 +83,7 @@ static std::string StringToNid(std::string_view symbol) {
|
|||
}
|
||||
|
||||
Module::Module(Core::MemoryManager* memory_, const std::filesystem::path& file_, u32& max_tls_index)
|
||||
: memory{memory_}, file{file_}, name{file.stem().string()} {
|
||||
: memory{memory_}, file{file_}, name{file.filename().string()} {
|
||||
elf.Open(file);
|
||||
if (elf.IsElfFile()) {
|
||||
LoadModuleToMemory(max_tls_index);
|
||||
|
@ -113,10 +112,8 @@ void Module::LoadModuleToMemory(u32& max_tls_index) {
|
|||
|
||||
// Map module segments (and possible TLS trampolines)
|
||||
void** out_addr = reinterpret_cast<void**>(&base_virtual_addr);
|
||||
memory->MapMemory(out_addr, memory->SystemReservedVirtualBase() + LoadOffset,
|
||||
aligned_base_size + TrampolineSize, MemoryProt::CpuReadWrite,
|
||||
MemoryMapFlags::Fixed, VMAType::Code, name, true);
|
||||
LoadOffset += CODE_BASE_INCR * (1 + aligned_base_size / CODE_BASE_INCR);
|
||||
memory->MapMemory(out_addr, ModuleLoadBase, aligned_base_size + TrampolineSize,
|
||||
MemoryProt::CpuReadWrite, MemoryMapFlags::NoFlags, VMAType::Code, name, true);
|
||||
LOG_INFO(Core_Linker, "Loading module {} to {}", name, fmt::ptr(*out_addr));
|
||||
|
||||
#ifdef ARCH_X86_64
|
||||
|
@ -135,10 +132,14 @@ void Module::LoadModuleToMemory(u32& max_tls_index) {
|
|||
if (do_map) {
|
||||
elf.LoadSegment(segment_addr, phdr.p_offset, phdr.p_filesz);
|
||||
}
|
||||
auto& segment = info.segments[info.num_segments++];
|
||||
segment.address = segment_addr;
|
||||
segment.prot = phdr.p_flags;
|
||||
segment.size = GetAlignedSize(phdr);
|
||||
if (info.num_segments < 4) {
|
||||
auto& segment = info.segments[info.num_segments++];
|
||||
segment.address = segment_addr;
|
||||
segment.prot = phdr.p_flags;
|
||||
segment.size = GetAlignedSize(phdr);
|
||||
} else {
|
||||
LOG_ERROR(Core_Linker, "Attempting to add too many segments!");
|
||||
}
|
||||
};
|
||||
|
||||
for (u16 i = 0; i < elf_header.e_phnum; i++) {
|
||||
|
@ -225,7 +226,7 @@ void Module::LoadModuleToMemory(u32& max_tls_index) {
|
|||
LOG_INFO(Core_Linker, "program entry addr ..........: {:#018x}", entry_addr);
|
||||
|
||||
if (MemoryPatcher::g_eboot_address == 0) {
|
||||
if (name == "eboot") {
|
||||
if (name == "eboot.bin") {
|
||||
MemoryPatcher::g_eboot_address = base_virtual_addr;
|
||||
MemoryPatcher::g_eboot_image_size = base_size;
|
||||
MemoryPatcher::OnGameLoaded();
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <cstring>
|
||||
#include "common/types.h"
|
||||
|
||||
namespace Xbyak {
|
||||
|
@ -41,10 +42,31 @@ Tcb* GetTcbBase();
|
|||
/// Makes sure TLS is initialized for the thread before entering guest.
|
||||
void EnsureThreadInitialized();
|
||||
|
||||
template <size_t size>
|
||||
__attribute__((optnone)) void ClearStack() {
|
||||
volatile void* buf = alloca(size);
|
||||
memset(const_cast<void*>(buf), 0, size);
|
||||
buf = nullptr;
|
||||
}
|
||||
|
||||
template <class ReturnType, class... FuncArgs, class... CallArgs>
|
||||
ReturnType ExecuteGuest(PS4_SYSV_ABI ReturnType (*func)(FuncArgs...), CallArgs&&... args) {
|
||||
EnsureThreadInitialized();
|
||||
// clear stack to avoid trash from EnsureThreadInitialized
|
||||
ClearStack<13_KB>();
|
||||
return func(std::forward<CallArgs>(args)...);
|
||||
}
|
||||
|
||||
template <class F, F f>
|
||||
struct HostCallWrapperImpl;
|
||||
|
||||
template <class ReturnType, class... Args, PS4_SYSV_ABI ReturnType (*func)(Args...)>
|
||||
struct HostCallWrapperImpl<PS4_SYSV_ABI ReturnType (*)(Args...), func> {
|
||||
static ReturnType PS4_SYSV_ABI wrap(Args... args) {
|
||||
return func(args...);
|
||||
}
|
||||
};
|
||||
|
||||
#define HOST_CALL(func) (Core::HostCallWrapperImpl<decltype(&(func)), func>::wrap)
|
||||
|
||||
} // namespace Core
|
||||
|
|
205
src/emulator.cpp
205
src/emulator.cpp
|
@ -10,13 +10,16 @@
|
|||
#include "common/logging/log.h"
|
||||
#ifdef ENABLE_QT_GUI
|
||||
#include <QtCore>
|
||||
#include "common/memory_patcher.h"
|
||||
#endif
|
||||
#include "common/assert.h"
|
||||
#ifdef ENABLE_DISCORD_RPC
|
||||
#include "common/discord_rpc_handler.h"
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
#include <WinSock2.h>
|
||||
#endif
|
||||
#include "common/elf_info.h"
|
||||
#include "common/memory_patcher.h"
|
||||
#include "common/ntapi.h"
|
||||
#include "common/path_util.h"
|
||||
#include "common/polyfill_thread.h"
|
||||
|
@ -46,27 +49,10 @@ Emulator::Emulator() {
|
|||
#ifdef _WIN32
|
||||
Common::NtApi::Initialize();
|
||||
SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS);
|
||||
#endif
|
||||
|
||||
// Create stdin/stdout/stderr
|
||||
Common::Singleton<FileSys::HandleTable>::Instance()->CreateStdHandles();
|
||||
|
||||
// Defer until after logging is initialized.
|
||||
memory = Core::Memory::Instance();
|
||||
controller = Common::Singleton<Input::GameController>::Instance();
|
||||
linker = Common::Singleton<Core::Linker>::Instance();
|
||||
|
||||
// Load renderdoc module.
|
||||
VideoCore::LoadRenderDoc();
|
||||
|
||||
// Start the timer (Play Time)
|
||||
#ifdef ENABLE_QT_GUI
|
||||
start_time = std::chrono::steady_clock::now();
|
||||
const auto user_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir);
|
||||
QString filePath = QString::fromStdString((user_dir / "play_time.txt").string());
|
||||
QFile file(filePath);
|
||||
ASSERT_MSG(file.open(QIODevice::ReadWrite | QIODevice::Text),
|
||||
"Error opening or creating play_time.txt");
|
||||
// need to init this in order for winsock2 to work
|
||||
WORD versionWanted = MAKEWORD(2, 2);
|
||||
WSADATA wsaData;
|
||||
WSAStartup(versionWanted, &wsaData);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -91,58 +77,93 @@ void Emulator::Run(const std::filesystem::path& file, const std::vector<std::str
|
|||
|
||||
// Applications expect to be run from /app0 so mount the file's parent path as app0.
|
||||
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
|
||||
mnt->Mount(game_folder, "/app0");
|
||||
mnt->Mount(game_folder, "/app0", true);
|
||||
// Certain games may use /hostapp as well such as CUSA001100
|
||||
mnt->Mount(game_folder, "/hostapp");
|
||||
mnt->Mount(game_folder, "/hostapp", true);
|
||||
|
||||
auto& game_info = Common::ElfInfo::Instance();
|
||||
const auto param_sfo_path = mnt->GetHostPath("/app0/sce_sys/param.sfo");
|
||||
const auto param_sfo_exists = std::filesystem::exists(param_sfo_path);
|
||||
|
||||
// Loading param.sfo file if exists
|
||||
// Load param.sfo details if it exists
|
||||
std::string id;
|
||||
std::string title;
|
||||
std::string app_version;
|
||||
u32 fw_version;
|
||||
Common::PSFAttributes psf_attributes{};
|
||||
|
||||
const auto param_sfo_path = mnt->GetHostPath("/app0/sce_sys/param.sfo");
|
||||
if (!std::filesystem::exists(param_sfo_path) || !Config::getSeparateLogFilesEnabled()) {
|
||||
Common::Log::Initialize();
|
||||
Common::Log::Start();
|
||||
}
|
||||
|
||||
if (std::filesystem::exists(param_sfo_path)) {
|
||||
if (param_sfo_exists) {
|
||||
auto* param_sfo = Common::Singleton<PSF>::Instance();
|
||||
const bool success = param_sfo->Open(param_sfo_path);
|
||||
ASSERT_MSG(success, "Failed to open param.sfo");
|
||||
ASSERT_MSG(param_sfo->Open(param_sfo_path), "Failed to open param.sfo");
|
||||
|
||||
const auto content_id = param_sfo->GetString("CONTENT_ID");
|
||||
ASSERT_MSG(content_id.has_value(), "Failed to get CONTENT_ID");
|
||||
|
||||
id = std::string(*content_id, 7, 9);
|
||||
|
||||
if (Config::getSeparateLogFilesEnabled()) {
|
||||
Common::Log::Initialize(id + ".log");
|
||||
Common::Log::Start();
|
||||
title = param_sfo->GetString("TITLE").value_or("Unknown title");
|
||||
fw_version = param_sfo->GetInteger("SYSTEM_VER").value_or(0x4700000);
|
||||
app_version = param_sfo->GetString("APP_VER").value_or("Unknown version");
|
||||
if (const auto raw_attributes = param_sfo->GetInteger("ATTRIBUTE")) {
|
||||
psf_attributes.raw = *raw_attributes;
|
||||
}
|
||||
LOG_INFO(Loader, "Starting shadps4 emulator v{} ", Common::g_version);
|
||||
LOG_INFO(Loader, "Revision {}", Common::g_scm_rev);
|
||||
LOG_INFO(Loader, "Branch {}", Common::g_scm_branch);
|
||||
LOG_INFO(Loader, "Description {}", Common::g_scm_desc);
|
||||
LOG_INFO(Loader, "Remote {}", Common::g_scm_remote_url);
|
||||
}
|
||||
|
||||
LOG_INFO(Config, "General LogType: {}", Config::getLogType());
|
||||
LOG_INFO(Config, "General isNeo: {}", Config::isNeoModeConsole());
|
||||
LOG_INFO(Config, "GPU isNullGpu: {}", Config::nullGpu());
|
||||
LOG_INFO(Config, "GPU shouldDumpShaders: {}", Config::dumpShaders());
|
||||
LOG_INFO(Config, "GPU vblankDivider: {}", Config::vblankDiv());
|
||||
LOG_INFO(Config, "Vulkan gpuId: {}", Config::getGpuId());
|
||||
LOG_INFO(Config, "Vulkan vkValidation: {}", Config::vkValidationEnabled());
|
||||
LOG_INFO(Config, "Vulkan vkValidationSync: {}", Config::vkValidationSyncEnabled());
|
||||
LOG_INFO(Config, "Vulkan vkValidationGpu: {}", Config::vkValidationGpuEnabled());
|
||||
LOG_INFO(Config, "Vulkan crashDiagnostics: {}", Config::getVkCrashDiagnosticEnabled());
|
||||
LOG_INFO(Config, "Vulkan hostMarkers: {}", Config::getVkHostMarkersEnabled());
|
||||
LOG_INFO(Config, "Vulkan guestMarkers: {}", Config::getVkGuestMarkersEnabled());
|
||||
LOG_INFO(Config, "Vulkan rdocEnable: {}", Config::isRdocEnabled());
|
||||
// Initialize logging as soon as possible
|
||||
if (!id.empty() && Config::getSeparateLogFilesEnabled()) {
|
||||
Common::Log::Initialize(id + ".log");
|
||||
} else {
|
||||
Common::Log::Initialize();
|
||||
}
|
||||
Common::Log::Start();
|
||||
|
||||
LOG_INFO(Loader, "Starting shadps4 emulator v{} ", Common::g_version);
|
||||
LOG_INFO(Loader, "Revision {}", Common::g_scm_rev);
|
||||
LOG_INFO(Loader, "Branch {}", Common::g_scm_branch);
|
||||
LOG_INFO(Loader, "Description {}", Common::g_scm_desc);
|
||||
LOG_INFO(Loader, "Remote {}", Common::g_scm_remote_url);
|
||||
|
||||
LOG_INFO(Config, "General LogType: {}", Config::getLogType());
|
||||
LOG_INFO(Config, "General isNeo: {}", Config::isNeoModeConsole());
|
||||
LOG_INFO(Config, "GPU isNullGpu: {}", Config::nullGpu());
|
||||
LOG_INFO(Config, "GPU shouldDumpShaders: {}", Config::dumpShaders());
|
||||
LOG_INFO(Config, "GPU vblankDivider: {}", Config::vblankDiv());
|
||||
LOG_INFO(Config, "Vulkan gpuId: {}", Config::getGpuId());
|
||||
LOG_INFO(Config, "Vulkan vkValidation: {}", Config::vkValidationEnabled());
|
||||
LOG_INFO(Config, "Vulkan vkValidationSync: {}", Config::vkValidationSyncEnabled());
|
||||
LOG_INFO(Config, "Vulkan vkValidationGpu: {}", Config::vkValidationGpuEnabled());
|
||||
LOG_INFO(Config, "Vulkan crashDiagnostics: {}", Config::getVkCrashDiagnosticEnabled());
|
||||
LOG_INFO(Config, "Vulkan hostMarkers: {}", Config::getVkHostMarkersEnabled());
|
||||
LOG_INFO(Config, "Vulkan guestMarkers: {}", Config::getVkGuestMarkersEnabled());
|
||||
LOG_INFO(Config, "Vulkan rdocEnable: {}", Config::isRdocEnabled());
|
||||
|
||||
if (param_sfo_exists) {
|
||||
LOG_INFO(Loader, "Game id: {} Title: {}", id, title);
|
||||
LOG_INFO(Loader, "Fw: {:#x} App Version: {}", fw_version, app_version);
|
||||
}
|
||||
if (!args.empty()) {
|
||||
const auto argc = std::min<size_t>(args.size(), 32);
|
||||
for (auto i = 0; i < argc; i++) {
|
||||
LOG_INFO(Loader, "Game argument {}: {}", i, args[i]);
|
||||
}
|
||||
if (args.size() > 32) {
|
||||
LOG_ERROR(Loader, "Too many game arguments, only passing the first 32");
|
||||
}
|
||||
}
|
||||
|
||||
// Create stdin/stdout/stderr
|
||||
Common::Singleton<FileSys::HandleTable>::Instance()->CreateStdHandles();
|
||||
|
||||
// Initialize components
|
||||
memory = Core::Memory::Instance();
|
||||
controller = Common::Singleton<Input::GameController>::Instance();
|
||||
linker = Common::Singleton<Core::Linker>::Instance();
|
||||
|
||||
// Load renderdoc module
|
||||
VideoCore::LoadRenderDoc();
|
||||
|
||||
// Initialize patcher and trophies
|
||||
if (!id.empty()) {
|
||||
MemoryPatcher::g_game_serial = id;
|
||||
Libraries::NpTrophy::game_serial = id;
|
||||
|
||||
const auto trophyDir =
|
||||
Common::FS::GetUserPath(Common::FS::PathType::MetaDataDir) / id / "TrophyFiles";
|
||||
if (!std::filesystem::exists(trophyDir)) {
|
||||
|
@ -151,41 +172,9 @@ void Emulator::Run(const std::filesystem::path& file, const std::vector<std::str
|
|||
LOG_ERROR(Loader, "Couldn't extract trophies");
|
||||
}
|
||||
}
|
||||
#ifdef ENABLE_QT_GUI
|
||||
MemoryPatcher::g_game_serial = id;
|
||||
|
||||
// Timer for 'Play Time'
|
||||
QTimer* timer = new QTimer();
|
||||
QObject::connect(timer, &QTimer::timeout, [this, id]() {
|
||||
UpdatePlayTime(id);
|
||||
start_time = std::chrono::steady_clock::now();
|
||||
});
|
||||
timer->start(60000); // 60000 ms = 1 minute
|
||||
#endif
|
||||
title = param_sfo->GetString("TITLE").value_or("Unknown title");
|
||||
LOG_INFO(Loader, "Game id: {} Title: {}", id, title);
|
||||
fw_version = param_sfo->GetInteger("SYSTEM_VER").value_or(0x4700000);
|
||||
app_version = param_sfo->GetString("APP_VER").value_or("Unknown version");
|
||||
LOG_INFO(Loader, "Fw: {:#x} App Version: {}", fw_version, app_version);
|
||||
if (const auto raw_attributes = param_sfo->GetInteger("ATTRIBUTE")) {
|
||||
psf_attributes.raw = *raw_attributes;
|
||||
}
|
||||
if (!args.empty()) {
|
||||
int argc = std::min<int>(args.size(), 32);
|
||||
for (int i = 0; i < argc; i++) {
|
||||
LOG_INFO(Loader, "Game argument {}: {}", i, args[i]);
|
||||
}
|
||||
if (args.size() > 32) {
|
||||
LOG_ERROR(Loader, "Too many game arguments, only passing the first 32");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const auto pic1_path = mnt->GetHostPath("/app0/sce_sys/pic1.png");
|
||||
if (std::filesystem::exists(pic1_path)) {
|
||||
game_info.splash_path = pic1_path;
|
||||
}
|
||||
|
||||
auto& game_info = Common::ElfInfo::Instance();
|
||||
game_info.initialized = true;
|
||||
game_info.game_serial = id;
|
||||
game_info.title = title;
|
||||
|
@ -194,6 +183,11 @@ void Emulator::Run(const std::filesystem::path& file, const std::vector<std::str
|
|||
game_info.raw_firmware_ver = fw_version;
|
||||
game_info.psf_attributes = psf_attributes;
|
||||
|
||||
const auto pic1_path = mnt->GetHostPath("/app0/sce_sys/pic1.png");
|
||||
if (std::filesystem::exists(pic1_path)) {
|
||||
game_info.splash_path = pic1_path;
|
||||
}
|
||||
|
||||
std::string game_title = fmt::format("{} - {} <{}>", id, title, app_version);
|
||||
std::string window_title = "";
|
||||
if (Common::g_is_release) {
|
||||
|
@ -224,11 +218,15 @@ void Emulator::Run(const std::filesystem::path& file, const std::vector<std::str
|
|||
std::filesystem::create_directory(mount_data_dir);
|
||||
}
|
||||
mnt->Mount(mount_data_dir, "/data"); // should just exist, manually create with game serial
|
||||
|
||||
// Mounting temp folders
|
||||
const auto& mount_temp_dir = Common::FS::GetUserPath(Common::FS::PathType::TempDataDir) / id;
|
||||
if (!std::filesystem::exists(mount_temp_dir)) {
|
||||
std::filesystem::create_directory(mount_temp_dir);
|
||||
if (std::filesystem::exists(mount_temp_dir)) {
|
||||
// Temp folder should be cleared on each boot.
|
||||
std::filesystem::remove_all(mount_temp_dir);
|
||||
}
|
||||
mnt->Mount(mount_temp_dir, "/temp0"); // called in app_content ==> stat/mkdir
|
||||
std::filesystem::create_directory(mount_temp_dir);
|
||||
mnt->Mount(mount_temp_dir, "/temp0");
|
||||
mnt->Mount(mount_temp_dir, "/temp");
|
||||
|
||||
const auto& mount_download_dir =
|
||||
|
@ -273,6 +271,25 @@ void Emulator::Run(const std::filesystem::path& file, const std::vector<std::str
|
|||
}
|
||||
#endif
|
||||
|
||||
// Start the timer (Play Time)
|
||||
#ifdef ENABLE_QT_GUI
|
||||
if (!id.empty()) {
|
||||
auto* timer = new QTimer();
|
||||
QObject::connect(timer, &QTimer::timeout, [this, id]() {
|
||||
UpdatePlayTime(id);
|
||||
start_time = std::chrono::steady_clock::now();
|
||||
});
|
||||
timer->start(60000); // 60000 ms = 1 minute
|
||||
|
||||
start_time = std::chrono::steady_clock::now();
|
||||
const auto user_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir);
|
||||
QString filePath = QString::fromStdString((user_dir / "play_time.txt").string());
|
||||
QFile file(filePath);
|
||||
ASSERT_MSG(file.open(QIODevice::ReadWrite | QIODevice::Text),
|
||||
"Error opening or creating play_time.txt");
|
||||
}
|
||||
#endif
|
||||
|
||||
linker->Execute(args);
|
||||
|
||||
window->InitTimers();
|
||||
|
|
|
@ -4,8 +4,11 @@
|
|||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <vector>
|
||||
#include <imgui.h>
|
||||
|
||||
#include "common/types.h"
|
||||
|
||||
namespace ImGui {
|
||||
|
||||
namespace Core::TextureManager {
|
||||
|
|
|
@ -112,6 +112,8 @@ void Initialize(const ::Vulkan::Instance& instance, const Frontend::WindowSDL& w
|
|||
if (const auto dpi = SDL_GetWindowDisplayScale(window.GetSDLWindow()); dpi > 0.0f) {
|
||||
GetIO().FontGlobalScale = dpi;
|
||||
}
|
||||
|
||||
std::at_quick_exit([] { SaveIniSettingsToDisk(GetIO().IniFilename); });
|
||||
}
|
||||
|
||||
void OnResize() {
|
||||
|
|
|
@ -60,7 +60,7 @@ Uint32 MousePolling(void* param, Uint32 id, Uint32 interval) {
|
|||
float angle = atan2(d_y, d_x);
|
||||
float a_x = cos(angle) * output_speed, a_y = sin(angle) * output_speed;
|
||||
|
||||
if (d_x != 0 && d_y != 0) {
|
||||
if (d_x != 0 || d_y != 0) {
|
||||
controller->Axis(0, axis_x, GetAxis(-0x80, 0x7f, a_x));
|
||||
controller->Axis(0, axis_y, GetAxis(-0x80, 0x7f, a_y));
|
||||
} else {
|
||||
|
|
|
@ -154,7 +154,7 @@ int main(int argc, char* argv[]) {
|
|||
// If no game directory is set and no command line argument, prompt for it
|
||||
if (Config::getGameInstallDirs().empty()) {
|
||||
std::cout << "Warning: No game folder set, please set it by calling shadps4"
|
||||
" with the --add-game-folder <folder_name> argument";
|
||||
" with the --add-game-folder <folder_name> argument\n";
|
||||
}
|
||||
|
||||
if (!has_game_argument) {
|
||||
|
|
|
@ -1387,7 +1387,7 @@ void CheatsPatches::applyPatch(const QString& patchName, bool enabled) {
|
|||
if (type == "mask_jump32")
|
||||
patchMask = MemoryPatcher::PatchMask::Mask_Jump32;
|
||||
|
||||
if (type == "mask" || type == "mask_jump32" && !maskOffsetStr.toStdString().empty()) {
|
||||
if ((type == "mask" || type == "mask_jump32") && !maskOffsetStr.toStdString().empty()) {
|
||||
maskOffsetValue = std::stoi(maskOffsetStr.toStdString(), 0, 10);
|
||||
}
|
||||
|
||||
|
|
|
@ -608,21 +608,28 @@ void KBMSettings::CheckMapping(QPushButton*& button) {
|
|||
MappingTimer -= 1;
|
||||
button->setText(tr("Press a key") + " [" + QString::number(MappingTimer) + "]");
|
||||
|
||||
if (pressedKeys.size() > 0) {
|
||||
QStringList keyStrings;
|
||||
|
||||
for (const QString& buttonAction : pressedKeys) {
|
||||
keyStrings << buttonAction;
|
||||
}
|
||||
|
||||
QString combo = keyStrings.join(",");
|
||||
SetMapping(combo);
|
||||
MappingCompleted = true;
|
||||
EnableMapping = false;
|
||||
|
||||
MappingButton->setText(combo);
|
||||
pressedKeys.clear();
|
||||
timer->stop();
|
||||
}
|
||||
if (MappingCompleted) {
|
||||
EnableMapping = false;
|
||||
EnableMappingButtons();
|
||||
timer->stop();
|
||||
|
||||
if (mapping == "lshift" || mapping == "lalt" || mapping == "lctrl" || mapping == "lmeta" ||
|
||||
mapping == "lwin") {
|
||||
modifier = "";
|
||||
}
|
||||
|
||||
if (modifier != "") {
|
||||
button->setText(modifier + ", " + mapping);
|
||||
} else {
|
||||
button->setText(mapping);
|
||||
}
|
||||
button->setText(mapping);
|
||||
}
|
||||
|
||||
if (MappingTimer <= 0) {
|
||||
|
@ -647,322 +654,346 @@ bool KBMSettings::eventFilter(QObject* obj, QEvent* event) {
|
|||
}
|
||||
|
||||
if (EnableMapping) {
|
||||
if (Qt::ShiftModifier & QApplication::keyboardModifiers()) {
|
||||
modifier = "lshift";
|
||||
} else if (Qt::AltModifier & QApplication::keyboardModifiers()) {
|
||||
modifier = "lalt";
|
||||
} else if (Qt::ControlModifier & QApplication::keyboardModifiers()) {
|
||||
modifier = "lctrl";
|
||||
} else if (Qt::MetaModifier & QApplication::keyboardModifiers()) {
|
||||
#ifdef _WIN32
|
||||
modifier = "lwin";
|
||||
#else
|
||||
modifier = "lmeta";
|
||||
#endif
|
||||
}
|
||||
|
||||
if (event->type() == QEvent::KeyPress) {
|
||||
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
|
||||
|
||||
if (keyEvent->isAutoRepeat())
|
||||
return true;
|
||||
|
||||
if (pressedKeys.size() >= 3) {
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (keyEvent->key()) {
|
||||
case Qt::Key_Space:
|
||||
SetMapping("space");
|
||||
pressedKeys.insert("space");
|
||||
break;
|
||||
case Qt::Key_Comma:
|
||||
if (Qt::KeypadModifier & QApplication::keyboardModifiers()) {
|
||||
SetMapping("kpcomma");
|
||||
pressedKeys.insert("kpcomma");
|
||||
} else {
|
||||
SetMapping("comma");
|
||||
pressedKeys.insert("comma");
|
||||
}
|
||||
break;
|
||||
case Qt::Key_Period:
|
||||
if (Qt::KeypadModifier & QApplication::keyboardModifiers()) {
|
||||
SetMapping("kpperiod");
|
||||
pressedKeys.insert("kpperiod");
|
||||
} else {
|
||||
SetMapping("period");
|
||||
pressedKeys.insert("period");
|
||||
}
|
||||
break;
|
||||
case Qt::Key_Slash:
|
||||
if (Qt::KeypadModifier & QApplication::keyboardModifiers())
|
||||
SetMapping("kpdivide");
|
||||
pressedKeys.insert("kpdivide");
|
||||
break;
|
||||
case Qt::Key_Asterisk:
|
||||
if (Qt::KeypadModifier & QApplication::keyboardModifiers())
|
||||
SetMapping("kpmultiply");
|
||||
pressedKeys.insert("kpmultiply");
|
||||
break;
|
||||
case Qt::Key_Question:
|
||||
SetMapping("question");
|
||||
pressedKeys.insert("question");
|
||||
break;
|
||||
case Qt::Key_Semicolon:
|
||||
SetMapping("semicolon");
|
||||
pressedKeys.insert("semicolon");
|
||||
break;
|
||||
case Qt::Key_Minus:
|
||||
if (Qt::KeypadModifier & QApplication::keyboardModifiers()) {
|
||||
SetMapping("kpminus");
|
||||
pressedKeys.insert("kpminus");
|
||||
} else {
|
||||
SetMapping("minus");
|
||||
pressedKeys.insert("minus");
|
||||
}
|
||||
break;
|
||||
case Qt::Key_Plus:
|
||||
if (Qt::KeypadModifier & QApplication::keyboardModifiers()) {
|
||||
SetMapping("kpplus");
|
||||
pressedKeys.insert("kpplus");
|
||||
} else {
|
||||
SetMapping("plus");
|
||||
pressedKeys.insert("plus");
|
||||
}
|
||||
break;
|
||||
case Qt::Key_ParenLeft:
|
||||
SetMapping("lparenthesis");
|
||||
pressedKeys.insert("lparenthesis");
|
||||
break;
|
||||
case Qt::Key_ParenRight:
|
||||
SetMapping("rparenthesis");
|
||||
pressedKeys.insert("rparenthesis");
|
||||
break;
|
||||
case Qt::Key_BracketLeft:
|
||||
SetMapping("lbracket");
|
||||
pressedKeys.insert("lbracket");
|
||||
break;
|
||||
case Qt::Key_BracketRight:
|
||||
SetMapping("rbracket");
|
||||
pressedKeys.insert("rbracket");
|
||||
break;
|
||||
case Qt::Key_BraceLeft:
|
||||
SetMapping("lbrace");
|
||||
pressedKeys.insert("lbrace");
|
||||
break;
|
||||
case Qt::Key_BraceRight:
|
||||
SetMapping("rbrace");
|
||||
pressedKeys.insert("rbrace");
|
||||
break;
|
||||
case Qt::Key_Backslash:
|
||||
SetMapping("backslash");
|
||||
pressedKeys.insert("backslash");
|
||||
break;
|
||||
case Qt::Key_Tab:
|
||||
SetMapping("tab");
|
||||
pressedKeys.insert("tab");
|
||||
break;
|
||||
case Qt::Key_Backspace:
|
||||
SetMapping("backspace");
|
||||
pressedKeys.insert("backspace");
|
||||
break;
|
||||
case Qt::Key_Return:
|
||||
SetMapping("enter");
|
||||
pressedKeys.insert("enter");
|
||||
break;
|
||||
case Qt::Key_Enter:
|
||||
SetMapping("kpenter");
|
||||
pressedKeys.insert("kpenter");
|
||||
break;
|
||||
case Qt::Key_Home:
|
||||
pressedKeys.insert("home");
|
||||
break;
|
||||
case Qt::Key_End:
|
||||
pressedKeys.insert("end");
|
||||
break;
|
||||
case Qt::Key_PageDown:
|
||||
pressedKeys.insert("pgdown");
|
||||
break;
|
||||
case Qt::Key_PageUp:
|
||||
pressedKeys.insert("pgup");
|
||||
break;
|
||||
case Qt::Key_CapsLock:
|
||||
pressedKeys.insert("capslock");
|
||||
break;
|
||||
case Qt::Key_Escape:
|
||||
SetMapping("unmapped");
|
||||
pressedKeys.insert("unmapped");
|
||||
break;
|
||||
case Qt::Key_Shift:
|
||||
SetMapping("lshift");
|
||||
if (keyEvent->nativeScanCode() == rshift) {
|
||||
pressedKeys.insert("rshift");
|
||||
} else {
|
||||
pressedKeys.insert("lshift");
|
||||
}
|
||||
break;
|
||||
case Qt::Key_Alt:
|
||||
SetMapping("lalt");
|
||||
if (keyEvent->nativeScanCode() == ralt) {
|
||||
pressedKeys.insert("ralt");
|
||||
} else {
|
||||
pressedKeys.insert("lalt");
|
||||
}
|
||||
break;
|
||||
case Qt::Key_Control:
|
||||
SetMapping("lctrl");
|
||||
if (keyEvent->nativeScanCode() == rctrl) {
|
||||
pressedKeys.insert("rctrl");
|
||||
} else {
|
||||
pressedKeys.insert("lctrl");
|
||||
}
|
||||
break;
|
||||
case Qt::Key_Meta:
|
||||
activateWindow();
|
||||
#ifdef _WIN32
|
||||
SetMapping("lwin");
|
||||
pressedKeys.insert("lwin");
|
||||
#else
|
||||
SetMapping("lmeta");
|
||||
pressedKeys.insert("lmeta");
|
||||
#endif
|
||||
case Qt::Key_1:
|
||||
if (Qt::KeypadModifier & QApplication::keyboardModifiers()) {
|
||||
SetMapping("kp1");
|
||||
pressedKeys.insert("kp1");
|
||||
} else {
|
||||
SetMapping("1");
|
||||
pressedKeys.insert("1");
|
||||
}
|
||||
break;
|
||||
case Qt::Key_2:
|
||||
if (Qt::KeypadModifier & QApplication::keyboardModifiers()) {
|
||||
SetMapping("kp2");
|
||||
pressedKeys.insert("kp2");
|
||||
} else {
|
||||
SetMapping("2");
|
||||
pressedKeys.insert("2");
|
||||
}
|
||||
break;
|
||||
case Qt::Key_3:
|
||||
if (Qt::KeypadModifier & QApplication::keyboardModifiers()) {
|
||||
SetMapping("kp3");
|
||||
pressedKeys.insert("kp3");
|
||||
} else {
|
||||
SetMapping("3");
|
||||
pressedKeys.insert("3");
|
||||
}
|
||||
break;
|
||||
case Qt::Key_4:
|
||||
if (Qt::KeypadModifier & QApplication::keyboardModifiers()) {
|
||||
SetMapping("kp4");
|
||||
pressedKeys.insert("kp4");
|
||||
} else {
|
||||
SetMapping("4");
|
||||
pressedKeys.insert("4");
|
||||
}
|
||||
break;
|
||||
case Qt::Key_5:
|
||||
if (Qt::KeypadModifier & QApplication::keyboardModifiers()) {
|
||||
SetMapping("kp5");
|
||||
pressedKeys.insert("kp5");
|
||||
} else {
|
||||
SetMapping("5");
|
||||
pressedKeys.insert("5");
|
||||
}
|
||||
break;
|
||||
case Qt::Key_6:
|
||||
if (Qt::KeypadModifier & QApplication::keyboardModifiers()) {
|
||||
SetMapping("kp6");
|
||||
pressedKeys.insert("kp6");
|
||||
} else {
|
||||
SetMapping("6");
|
||||
pressedKeys.insert("6");
|
||||
}
|
||||
break;
|
||||
case Qt::Key_7:
|
||||
if (Qt::KeypadModifier & QApplication::keyboardModifiers()) {
|
||||
SetMapping("kp7");
|
||||
pressedKeys.insert("kp7");
|
||||
} else {
|
||||
SetMapping("7");
|
||||
pressedKeys.insert("7");
|
||||
}
|
||||
break;
|
||||
case Qt::Key_8:
|
||||
if (Qt::KeypadModifier & QApplication::keyboardModifiers()) {
|
||||
SetMapping("kp8");
|
||||
pressedKeys.insert("kp8");
|
||||
} else {
|
||||
SetMapping("8");
|
||||
pressedKeys.insert("8");
|
||||
}
|
||||
break;
|
||||
case Qt::Key_9:
|
||||
if (Qt::KeypadModifier & QApplication::keyboardModifiers()) {
|
||||
SetMapping("kp9");
|
||||
pressedKeys.insert("kp9");
|
||||
} else {
|
||||
SetMapping("9");
|
||||
pressedKeys.insert("9");
|
||||
}
|
||||
break;
|
||||
case Qt::Key_0:
|
||||
if (Qt::KeypadModifier & QApplication::keyboardModifiers()) {
|
||||
SetMapping("kp0");
|
||||
pressedKeys.insert("kp0");
|
||||
} else {
|
||||
SetMapping("0");
|
||||
pressedKeys.insert("0");
|
||||
}
|
||||
break;
|
||||
case Qt::Key_Up:
|
||||
activateWindow();
|
||||
SetMapping("up");
|
||||
pressedKeys.insert("up");
|
||||
break;
|
||||
case Qt::Key_Down:
|
||||
SetMapping("down");
|
||||
pressedKeys.insert("down");
|
||||
break;
|
||||
case Qt::Key_Left:
|
||||
SetMapping("left");
|
||||
pressedKeys.insert("left");
|
||||
break;
|
||||
case Qt::Key_Right:
|
||||
SetMapping("right");
|
||||
pressedKeys.insert("right");
|
||||
break;
|
||||
case Qt::Key_A:
|
||||
SetMapping("a");
|
||||
pressedKeys.insert("a");
|
||||
break;
|
||||
case Qt::Key_B:
|
||||
SetMapping("b");
|
||||
pressedKeys.insert("b");
|
||||
break;
|
||||
case Qt::Key_C:
|
||||
SetMapping("c");
|
||||
pressedKeys.insert("c");
|
||||
break;
|
||||
case Qt::Key_D:
|
||||
SetMapping("d");
|
||||
pressedKeys.insert("d");
|
||||
break;
|
||||
case Qt::Key_E:
|
||||
SetMapping("e");
|
||||
pressedKeys.insert("e");
|
||||
break;
|
||||
case Qt::Key_F:
|
||||
SetMapping("f");
|
||||
pressedKeys.insert("f");
|
||||
break;
|
||||
case Qt::Key_G:
|
||||
SetMapping("g");
|
||||
pressedKeys.insert("g");
|
||||
break;
|
||||
case Qt::Key_H:
|
||||
SetMapping("h");
|
||||
pressedKeys.insert("h");
|
||||
break;
|
||||
case Qt::Key_I:
|
||||
SetMapping("i");
|
||||
pressedKeys.insert("i");
|
||||
break;
|
||||
case Qt::Key_J:
|
||||
SetMapping("j");
|
||||
pressedKeys.insert("j");
|
||||
break;
|
||||
case Qt::Key_K:
|
||||
SetMapping("k");
|
||||
pressedKeys.insert("k");
|
||||
break;
|
||||
case Qt::Key_L:
|
||||
SetMapping("l");
|
||||
pressedKeys.insert("l");
|
||||
break;
|
||||
case Qt::Key_M:
|
||||
SetMapping("m");
|
||||
pressedKeys.insert("m");
|
||||
break;
|
||||
case Qt::Key_N:
|
||||
SetMapping("n");
|
||||
pressedKeys.insert("n");
|
||||
break;
|
||||
case Qt::Key_O:
|
||||
SetMapping("o");
|
||||
pressedKeys.insert("o");
|
||||
break;
|
||||
case Qt::Key_P:
|
||||
SetMapping("p");
|
||||
pressedKeys.insert("p");
|
||||
break;
|
||||
case Qt::Key_Q:
|
||||
SetMapping("q");
|
||||
pressedKeys.insert("q");
|
||||
break;
|
||||
case Qt::Key_R:
|
||||
SetMapping("r");
|
||||
pressedKeys.insert("r");
|
||||
break;
|
||||
case Qt::Key_S:
|
||||
SetMapping("s");
|
||||
pressedKeys.insert("s");
|
||||
break;
|
||||
case Qt::Key_T:
|
||||
SetMapping("t");
|
||||
pressedKeys.insert("t");
|
||||
break;
|
||||
case Qt::Key_U:
|
||||
SetMapping("u");
|
||||
pressedKeys.insert("u");
|
||||
break;
|
||||
case Qt::Key_V:
|
||||
SetMapping("v");
|
||||
pressedKeys.insert("v");
|
||||
break;
|
||||
case Qt::Key_W:
|
||||
SetMapping("w");
|
||||
pressedKeys.insert("w");
|
||||
break;
|
||||
case Qt::Key_X:
|
||||
SetMapping("x");
|
||||
pressedKeys.insert("x");
|
||||
break;
|
||||
case Qt::Key_Y:
|
||||
SetMapping("Y");
|
||||
pressedKeys.insert("Y");
|
||||
break;
|
||||
case Qt::Key_Z:
|
||||
SetMapping("z");
|
||||
pressedKeys.insert("z");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (event->type() == QEvent::MouseButtonPress) {
|
||||
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
|
||||
if (event->type() == QEvent::MouseButtonPress) {
|
||||
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
|
||||
if (pressedKeys.size() < 3) {
|
||||
switch (mouseEvent->button()) {
|
||||
case Qt::LeftButton:
|
||||
SetMapping("leftbutton");
|
||||
pressedKeys.insert("leftbutton");
|
||||
break;
|
||||
case Qt::RightButton:
|
||||
SetMapping("rightbutton");
|
||||
pressedKeys.insert("rightbutton");
|
||||
break;
|
||||
case Qt::MiddleButton:
|
||||
SetMapping("middlebutton");
|
||||
pressedKeys.insert("middlebutton");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
const QList<QPushButton*> AxisList = {
|
||||
ui->LStickUpButton, ui->LStickDownButton, ui->LStickLeftButton, ui->LStickRightButton,
|
||||
ui->RStickUpButton, ui->LStickDownButton, ui->LStickLeftButton, ui->RStickRightButton};
|
||||
const QList<QPushButton*> AxisList = {
|
||||
ui->LStickUpButton, ui->LStickDownButton, ui->LStickLeftButton, ui->LStickRightButton,
|
||||
ui->RStickUpButton, ui->LStickDownButton, ui->LStickLeftButton, ui->RStickRightButton};
|
||||
|
||||
if (event->type() == QEvent::Wheel) {
|
||||
QWheelEvent* wheelEvent = static_cast<QWheelEvent*>(event);
|
||||
if (event->type() == QEvent::Wheel) {
|
||||
QWheelEvent* wheelEvent = static_cast<QWheelEvent*>(event);
|
||||
if (pressedKeys.size() < 3) {
|
||||
if (wheelEvent->angleDelta().y() > 5) {
|
||||
if (std::find(AxisList.begin(), AxisList.end(), MappingButton) == AxisList.end()) {
|
||||
SetMapping("mousewheelup");
|
||||
pressedKeys.insert("mousewheelup");
|
||||
} else {
|
||||
QMessageBox::information(this, tr("Cannot set mapping"),
|
||||
tr("Mousewheel cannot be mapped to stick outputs"));
|
||||
}
|
||||
} else if (wheelEvent->angleDelta().y() < -5) {
|
||||
if (std::find(AxisList.begin(), AxisList.end(), MappingButton) == AxisList.end()) {
|
||||
SetMapping("mousewheeldown");
|
||||
pressedKeys.insert("mousewheeldown");
|
||||
} else {
|
||||
QMessageBox::information(this, tr("Cannot set mapping"),
|
||||
tr("Mousewheel cannot be mapped to stick outputs"));
|
||||
|
@ -972,9 +1003,9 @@ bool KBMSettings::eventFilter(QObject* obj, QEvent* event) {
|
|||
if (std::find(AxisList.begin(), AxisList.end(), MappingButton) == AxisList.end()) {
|
||||
// QT changes scrolling to horizontal for all widgets with the alt modifier
|
||||
if (Qt::AltModifier & QApplication::keyboardModifiers()) {
|
||||
SetMapping("mousewheelup");
|
||||
pressedKeys.insert("mousewheelup");
|
||||
} else {
|
||||
SetMapping("mousewheelright");
|
||||
pressedKeys.insert("mousewheelright");
|
||||
}
|
||||
} else {
|
||||
QMessageBox::information(this, tr("Cannot set mapping"),
|
||||
|
@ -983,18 +1014,18 @@ bool KBMSettings::eventFilter(QObject* obj, QEvent* event) {
|
|||
} else if (wheelEvent->angleDelta().x() < -5) {
|
||||
if (std::find(AxisList.begin(), AxisList.end(), MappingButton) == AxisList.end()) {
|
||||
if (Qt::AltModifier & QApplication::keyboardModifiers()) {
|
||||
SetMapping("mousewheeldown");
|
||||
pressedKeys.insert("mousewheeldown");
|
||||
} else {
|
||||
SetMapping("mousewheelleft");
|
||||
pressedKeys.insert("mousewheelleft");
|
||||
}
|
||||
} else {
|
||||
QMessageBox::information(this, tr("Cannot set mapping"),
|
||||
tr("Mousewheel cannot be mapped to stick outputs"));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return QDialog::eventFilter(obj, event);
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,22 @@ private:
|
|||
std::unique_ptr<Ui::KBMSettings> ui;
|
||||
std::shared_ptr<GameInfoClass> m_game_info;
|
||||
|
||||
#ifdef _WIN32
|
||||
const int lctrl = 29;
|
||||
const int rctrl = 57373;
|
||||
const int lalt = 56;
|
||||
const int ralt = 57400;
|
||||
const int lshift = 42;
|
||||
const int rshift = 54;
|
||||
#else
|
||||
const int lctrl = 37;
|
||||
const int rctrl = 105;
|
||||
const int lalt = 64;
|
||||
const int ralt = 108;
|
||||
const int lshift = 50;
|
||||
const int rshift = 62;
|
||||
#endif
|
||||
|
||||
bool eventFilter(QObject* obj, QEvent* event) override;
|
||||
void ButtonConnects();
|
||||
void SetUIValuestoMappings(std::string config_id);
|
||||
|
@ -33,6 +49,7 @@ private:
|
|||
void EnableMappingButtons();
|
||||
void SetMapping(QString input);
|
||||
|
||||
QSet<QString> pressedKeys;
|
||||
bool EnableMapping = false;
|
||||
bool MappingCompleted = false;
|
||||
bool HelpWindowOpen = false;
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#include "main_window.h"
|
||||
#include "settings_dialog.h"
|
||||
|
||||
#include "video_core/renderer_vulkan/vk_instance.h"
|
||||
#ifdef ENABLE_DISCORD_RPC
|
||||
#include "common/discord_rpc_handler.h"
|
||||
#endif
|
||||
|
@ -53,7 +52,6 @@ bool MainWindow::Init() {
|
|||
CreateConnects();
|
||||
SetLastUsedTheme();
|
||||
SetLastIconSizeBullet();
|
||||
GetPhysicalDevices();
|
||||
// show ui
|
||||
setMinimumSize(720, 405);
|
||||
std::string window_title = "";
|
||||
|
@ -368,19 +366,6 @@ void MainWindow::CheckUpdateMain(bool checkSave) {
|
|||
}
|
||||
#endif
|
||||
|
||||
void MainWindow::GetPhysicalDevices() {
|
||||
Vulkan::Instance instance(false, false);
|
||||
auto physical_devices = instance.GetPhysicalDevices();
|
||||
for (const vk::PhysicalDevice physical_device : physical_devices) {
|
||||
auto prop = physical_device.getProperties();
|
||||
QString name = QString::fromUtf8(prop.deviceName, -1);
|
||||
if (prop.apiVersion < Vulkan::TargetVulkanApiVersion) {
|
||||
name += tr(" * Unsupported Vulkan Version");
|
||||
}
|
||||
m_physical_devices.push_back(name);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::CreateConnects() {
|
||||
connect(this, &MainWindow::WindowResized, this, &MainWindow::HandleResize);
|
||||
connect(ui->mw_searchbar, &QLineEdit::textChanged, this, &MainWindow::SearchGameTable);
|
||||
|
@ -421,7 +406,7 @@ void MainWindow::CreateConnects() {
|
|||
&MainWindow::StartGame);
|
||||
|
||||
connect(ui->configureAct, &QAction::triggered, this, [this]() {
|
||||
auto settingsDialog = new SettingsDialog(m_physical_devices, m_compat_info, this);
|
||||
auto settingsDialog = new SettingsDialog(m_compat_info, this);
|
||||
|
||||
connect(settingsDialog, &SettingsDialog::LanguageChanged, this,
|
||||
&MainWindow::OnLanguageChanged);
|
||||
|
@ -454,7 +439,7 @@ void MainWindow::CreateConnects() {
|
|||
});
|
||||
|
||||
connect(ui->settingsButton, &QPushButton::clicked, this, [this]() {
|
||||
auto settingsDialog = new SettingsDialog(m_physical_devices, m_compat_info, this);
|
||||
auto settingsDialog = new SettingsDialog(m_compat_info, this);
|
||||
|
||||
connect(settingsDialog, &SettingsDialog::LanguageChanged, this,
|
||||
&MainWindow::OnLanguageChanged);
|
||||
|
|
|
@ -60,7 +60,6 @@ private:
|
|||
void toggleFullscreen();
|
||||
void CreateRecentGameActions();
|
||||
void CreateDockWindows();
|
||||
void GetPhysicalDevices();
|
||||
void LoadGameLists();
|
||||
|
||||
#ifdef ENABLE_UPDATER
|
||||
|
@ -96,8 +95,6 @@ private:
|
|||
QScopedPointer<ElfViewer> m_elf_viewer;
|
||||
// Status Bar.
|
||||
QScopedPointer<QStatusBar> statusBar;
|
||||
// Available GPU devices
|
||||
std::vector<QString> m_physical_devices;
|
||||
|
||||
PSF psf;
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <vector>
|
||||
#include <QCompleter>
|
||||
#include <QDirIterator>
|
||||
#include <QFileDialog>
|
||||
|
@ -25,6 +26,7 @@
|
|||
#include "common/logging/filter.h"
|
||||
#include "settings_dialog.h"
|
||||
#include "ui_settings_dialog.h"
|
||||
#include "video_core/renderer_vulkan/vk_instance.h"
|
||||
QStringList languageNames = {"Arabic",
|
||||
"Czech",
|
||||
"Danish",
|
||||
|
@ -67,8 +69,9 @@ QMap<QString, QString> chooseHomeTabMap;
|
|||
int backgroundImageOpacitySlider_backup;
|
||||
int bgm_volume_backup;
|
||||
|
||||
SettingsDialog::SettingsDialog(std::span<const QString> physical_devices,
|
||||
std::shared_ptr<CompatibilityInfoClass> m_compat_info,
|
||||
static std::vector<QString> m_physical_devices;
|
||||
|
||||
SettingsDialog::SettingsDialog(std::shared_ptr<CompatibilityInfoClass> m_compat_info,
|
||||
QWidget* parent)
|
||||
: QDialog(parent), ui(new Ui::SettingsDialog) {
|
||||
ui->setupUi(this);
|
||||
|
@ -89,9 +92,23 @@ SettingsDialog::SettingsDialog(std::span<const QString> physical_devices,
|
|||
{tr("Input"), "Input"}, {tr("Paths"), "Paths"},
|
||||
{tr("Debug"), "Debug"}};
|
||||
|
||||
if (m_physical_devices.empty()) {
|
||||
// Populate cache of physical devices.
|
||||
Vulkan::Instance instance(false, false);
|
||||
auto physical_devices = instance.GetPhysicalDevices();
|
||||
for (const vk::PhysicalDevice physical_device : physical_devices) {
|
||||
auto prop = physical_device.getProperties();
|
||||
QString name = QString::fromUtf8(prop.deviceName, -1);
|
||||
if (prop.apiVersion < Vulkan::TargetVulkanApiVersion) {
|
||||
name += tr(" * Unsupported Vulkan Version");
|
||||
}
|
||||
m_physical_devices.push_back(name);
|
||||
}
|
||||
}
|
||||
|
||||
// Add list of available GPUs
|
||||
ui->graphicsAdapterBox->addItem(tr("Auto Select")); // -1, auto selection
|
||||
for (const auto& device : physical_devices) {
|
||||
for (const auto& device : m_physical_devices) {
|
||||
ui->graphicsAdapterBox->addItem(device);
|
||||
}
|
||||
|
||||
|
|
|
@ -20,8 +20,7 @@ class SettingsDialog;
|
|||
class SettingsDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SettingsDialog(std::span<const QString> physical_devices,
|
||||
std::shared_ptr<CompatibilityInfoClass> m_compat_info,
|
||||
explicit SettingsDialog(std::shared_ptr<CompatibilityInfoClass> m_compat_info,
|
||||
QWidget* parent = nullptr);
|
||||
~SettingsDialog();
|
||||
|
||||
|
|
|
@ -384,23 +384,23 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Nothing</source>
|
||||
<translation>Không có gì</translation>
|
||||
<translation>Không chạy được</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Boots</source>
|
||||
<translation>Giày ủng</translation>
|
||||
<translation>Chạy được</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Menus</source>
|
||||
<translation>Menu</translation>
|
||||
<translation>Vào được menu</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Ingame</source>
|
||||
<translation>Trong game</translation>
|
||||
<translation>Vào được trò chơi</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Playable</source>
|
||||
<translation>Có thể chơi</translation>
|
||||
<translation>Chơi được</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
@ -411,7 +411,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>D-Pad</source>
|
||||
<translation type="unfinished">D-Pad</translation>
|
||||
<translation>D-Pad</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Up</source>
|
||||
|
@ -447,7 +447,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Common Config</source>
|
||||
<translation type="unfinished">Common Config</translation>
|
||||
<translation>Cài Đặt Chung</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use per-game configs</source>
|
||||
|
@ -551,26 +551,26 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Save</source>
|
||||
<translation type="unfinished">Save</translation>
|
||||
<translation>Lưu</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Apply</source>
|
||||
<translation type="unfinished">Apply</translation>
|
||||
<translation>Áp dụng</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Restore Defaults</source>
|
||||
<translation type="unfinished">Restore Defaults</translation>
|
||||
<translation>Khôi Phục Mặc Định</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished">Cancel</translation>
|
||||
<translation>Hủy</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>EditorDialog</name>
|
||||
<message>
|
||||
<source>Edit Keyboard + Mouse and Controller input bindings</source>
|
||||
<translation type="unfinished">Edit Keyboard + Mouse and Controller input bindings</translation>
|
||||
<translation>Tùy chỉnh phím được gán cho Bàn phím + Chuột và Tay cầm</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use Per-Game configs</source>
|
||||
|
@ -578,7 +578,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Error</source>
|
||||
<translation type="unfinished">Error</translation>
|
||||
<translation>Lỗi</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Could not open the file for reading</source>
|
||||
|
@ -590,15 +590,15 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Save Changes</source>
|
||||
<translation type="unfinished">Save Changes</translation>
|
||||
<translation>Lưu Thay Đổi</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Do you want to save changes?</source>
|
||||
<translation type="unfinished">Do you want to save changes?</translation>
|
||||
<translation>Bạn có muốn lưu thay đổi?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Help</source>
|
||||
<translation type="unfinished">Help</translation>
|
||||
<translation>Trợ giúp</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Do you want to reset your custom default config to the original default config?</source>
|
||||
|
@ -706,15 +706,15 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>h</source>
|
||||
<translation type="unfinished">h</translation>
|
||||
<translation>giờ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>m</source>
|
||||
<translation type="unfinished">m</translation>
|
||||
<translation>phút</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>s</source>
|
||||
<translation type="unfinished">s</translation>
|
||||
<translation>giây</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Compatibility is untested</source>
|
||||
|
@ -722,23 +722,23 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Game does not initialize properly / crashes the emulator</source>
|
||||
<translation type="unfinished">Game does not initialize properly / crashes the emulator</translation>
|
||||
<translation>Trò chơi không được khởi chạy đúng cách / khiến giả lập bị văng</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Game boots, but only displays a blank screen</source>
|
||||
<translation type="unfinished">Game boots, but only displays a blank screen</translation>
|
||||
<translation>Trò chơi có thể khởi chạy, nhưng chẳng hiện gì cả</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Game displays an image but does not go past the menu</source>
|
||||
<translation type="unfinished">Game displays an image but does not go past the menu</translation>
|
||||
<translation>Trò chơi hiển thị được hình ảnh, nhưng không thể tiếp tục từ menu</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Game has game-breaking glitches or unplayable performance</source>
|
||||
<translation type="unfinished">Game has game-breaking glitches or unplayable performance</translation>
|
||||
<translation>Trò chơi có lỗi ảnh hưởng đến trải nghiệm, hoặc hiệu năng khi chơi không ổn định</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Game can be completed with playable performance and no major glitches</source>
|
||||
<translation type="unfinished">Game can be completed with playable performance and no major glitches</translation>
|
||||
<translation>Trò chơi có thể được hoàn thành từ đầu đến cuối, hiệu năng ổn định và không có lỗi ảnh hưởng đến trải nghiệm</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Click to see details on github</source>
|
||||
|
@ -1170,19 +1170,19 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Save</source>
|
||||
<translation type="unfinished">Save</translation>
|
||||
<translation>Lưu</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Apply</source>
|
||||
<translation type="unfinished">Apply</translation>
|
||||
<translation>Áp dụng</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Restore Defaults</source>
|
||||
<translation type="unfinished">Restore Defaults</translation>
|
||||
<translation>Khôi Phục Mặc Định</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished">Cancel</translation>
|
||||
<translation>Hủy</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
@ -1193,7 +1193,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Boot Game</source>
|
||||
<translation type="unfinished">Boot Game</translation>
|
||||
<translation>Khởi Chạy Trò Chơi</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Check for Updates</source>
|
||||
|
@ -1201,7 +1201,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>About shadPS4</source>
|
||||
<translation type="unfinished">About shadPS4</translation>
|
||||
<translation>Thông Tin Về shadPS4</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Configure...</source>
|
||||
|
@ -1213,23 +1213,23 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Open shadPS4 Folder</source>
|
||||
<translation type="unfinished">Open shadPS4 Folder</translation>
|
||||
<translation>Mở Thư Mục Của shadPS4</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Exit</source>
|
||||
<translation type="unfinished">Exit</translation>
|
||||
<translation>Thoát</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Exit shadPS4</source>
|
||||
<translation type="unfinished">Exit shadPS4</translation>
|
||||
<translation>Thoát shadPS4</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Exit the application.</source>
|
||||
<translation type="unfinished">Exit the application.</translation>
|
||||
<translation>Thoát ứng dụng.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Show Game List</source>
|
||||
<translation type="unfinished">Show Game List</translation>
|
||||
<translation>Hiển Thị Danh Sách Trò Chơi</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Game List Refresh</source>
|
||||
|
|
|
@ -270,6 +270,10 @@ void SetupCapabilities(const Info& info, const Profile& profile, EmitContext& ct
|
|||
if (info.has_image_query) {
|
||||
ctx.AddCapability(spv::Capability::ImageQuery);
|
||||
}
|
||||
if (info.uses_atomic_float_min_max && profile.supports_image_fp32_atomic_min_max) {
|
||||
ctx.AddExtension("SPV_EXT_shader_atomic_float_min_max");
|
||||
ctx.AddCapability(spv::Capability::AtomicFloat32MinMaxEXT);
|
||||
}
|
||||
if (info.uses_lane_id) {
|
||||
ctx.AddCapability(spv::Capability::GroupNonUniform);
|
||||
}
|
||||
|
@ -335,8 +339,7 @@ void DefineEntryPoint(const Info& info, EmitContext& ctx, Id main) {
|
|||
ctx.AddExecutionMode(main, spv::ExecutionMode::OriginUpperLeft);
|
||||
}
|
||||
if (info.has_discard) {
|
||||
ctx.AddExtension("SPV_EXT_demote_to_helper_invocation");
|
||||
ctx.AddCapability(spv::Capability::DemoteToHelperInvocationEXT);
|
||||
ctx.AddCapability(spv::Capability::DemoteToHelperInvocation);
|
||||
}
|
||||
if (info.stores.GetAny(IR::Attribute::Depth)) {
|
||||
ctx.AddExecutionMode(main, spv::ExecutionMode::DepthReplacing);
|
||||
|
|
|
@ -38,6 +38,7 @@ Id BufferAtomicU32BoundsCheck(EmitContext& ctx, Id index, Id buffer_size, auto e
|
|||
const Id ib_label = ctx.OpLabel();
|
||||
const Id oob_label = ctx.OpLabel();
|
||||
const Id end_label = ctx.OpLabel();
|
||||
ctx.OpSelectionMerge(end_label, spv::SelectionControlMask::MaskNone);
|
||||
ctx.OpBranchConditional(in_bounds, ib_label, oob_label);
|
||||
ctx.AddLabel(ib_label);
|
||||
const Id ib_result = emit_func();
|
||||
|
@ -74,6 +75,14 @@ Id ImageAtomicU32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id va
|
|||
const auto [scope, semantics]{AtomicArgs(ctx)};
|
||||
return (ctx.*atomic_func)(ctx.U32[1], pointer, scope, semantics, value);
|
||||
}
|
||||
|
||||
Id ImageAtomicF32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id value,
|
||||
Id (Sirit::Module::*atomic_func)(Id, Id, Id, Id, Id)) {
|
||||
const auto& texture = ctx.images[handle & 0xFFFF];
|
||||
const Id pointer{ctx.OpImageTexelPointer(ctx.image_f32, texture.id, coords, ctx.ConstU32(0U))};
|
||||
const auto [scope, semantics]{AtomicArgs(ctx)};
|
||||
return (ctx.*atomic_func)(ctx.F32[1], pointer, scope, semantics, value);
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
Id EmitSharedAtomicIAdd32(EmitContext& ctx, Id offset, Id value) {
|
||||
|
@ -186,6 +195,40 @@ Id EmitImageAtomicUMax32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords
|
|||
return ImageAtomicU32(ctx, inst, handle, coords, value, &Sirit::Module::OpAtomicUMax);
|
||||
}
|
||||
|
||||
Id EmitImageAtomicFMax32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id value) {
|
||||
if (ctx.profile.supports_image_fp32_atomic_min_max) {
|
||||
return ImageAtomicF32(ctx, inst, handle, coords, value, &Sirit::Module::OpAtomicFMax);
|
||||
}
|
||||
|
||||
const auto u32_value = ctx.OpBitcast(ctx.U32[1], value);
|
||||
const auto sign_bit_set =
|
||||
ctx.OpBitFieldUExtract(ctx.U32[1], u32_value, ctx.ConstU32(31u), ctx.ConstU32(1u));
|
||||
|
||||
const auto result = ctx.OpSelect(
|
||||
ctx.F32[1], sign_bit_set,
|
||||
EmitBitCastF32U32(ctx, EmitImageAtomicUMin32(ctx, inst, handle, coords, u32_value)),
|
||||
EmitBitCastF32U32(ctx, EmitImageAtomicSMax32(ctx, inst, handle, coords, u32_value)));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Id EmitImageAtomicFMin32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id value) {
|
||||
if (ctx.profile.supports_image_fp32_atomic_min_max) {
|
||||
return ImageAtomicF32(ctx, inst, handle, coords, value, &Sirit::Module::OpAtomicFMin);
|
||||
}
|
||||
|
||||
const auto u32_value = ctx.OpBitcast(ctx.U32[1], value);
|
||||
const auto sign_bit_set =
|
||||
ctx.OpBitFieldUExtract(ctx.U32[1], u32_value, ctx.ConstU32(31u), ctx.ConstU32(1u));
|
||||
|
||||
const auto result = ctx.OpSelect(
|
||||
ctx.F32[1], sign_bit_set,
|
||||
EmitBitCastF32U32(ctx, EmitImageAtomicUMax32(ctx, inst, handle, coords, u32_value)),
|
||||
EmitBitCastF32U32(ctx, EmitImageAtomicSMin32(ctx, inst, handle, coords, u32_value)));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Id EmitImageAtomicInc32(EmitContext&, IR::Inst*, u32, Id, Id) {
|
||||
// TODO: This is not yet implemented
|
||||
throw NotImplementedException("SPIR-V Instruction");
|
||||
|
|
|
@ -64,10 +64,6 @@ Id EmitBitCastU32F32(EmitContext& ctx, Id value) {
|
|||
return ctx.OpBitcast(ctx.U32[1], value);
|
||||
}
|
||||
|
||||
Id EmitBitCastU64F64(EmitContext& ctx, Id value) {
|
||||
return ctx.OpBitcast(ctx.U64, value);
|
||||
}
|
||||
|
||||
Id EmitBitCastF16U16(EmitContext& ctx, Id value) {
|
||||
return ctx.OpBitcast(ctx.F16[1], value);
|
||||
}
|
||||
|
@ -76,10 +72,6 @@ Id EmitBitCastF32U32(EmitContext& ctx, Id value) {
|
|||
return ctx.OpBitcast(ctx.F32[1], value);
|
||||
}
|
||||
|
||||
void EmitBitCastF64U64(EmitContext&) {
|
||||
UNREACHABLE_MSG("SPIR-V Instruction");
|
||||
}
|
||||
|
||||
Id EmitPackUint2x32(EmitContext& ctx, Id value) {
|
||||
return ctx.OpBitcast(ctx.U64, value);
|
||||
}
|
||||
|
@ -88,10 +80,14 @@ Id EmitUnpackUint2x32(EmitContext& ctx, Id value) {
|
|||
return ctx.OpBitcast(ctx.U32[2], value);
|
||||
}
|
||||
|
||||
Id EmitPackFloat2x32(EmitContext& ctx, Id value) {
|
||||
Id EmitPackDouble2x32(EmitContext& ctx, Id value) {
|
||||
return ctx.OpBitcast(ctx.F64[1], value);
|
||||
}
|
||||
|
||||
Id EmitUnpackDouble2x32(EmitContext& ctx, Id value) {
|
||||
return ctx.OpBitcast(ctx.U32[2], value);
|
||||
}
|
||||
|
||||
Id EmitPackUnorm2x16(EmitContext& ctx, Id value) {
|
||||
return ctx.OpPackUnorm2x16(ctx.U32[1], value);
|
||||
}
|
||||
|
|
|
@ -529,7 +529,7 @@ void EmitStoreBufferBoundsCheck(EmitContext& ctx, Id index, Id buffer_size, auto
|
|||
// Bounds checking enabled, wrap in a conditional branch.
|
||||
auto compare_index = index;
|
||||
if (N > 1) {
|
||||
index = ctx.OpIAdd(ctx.U32[1], index, ctx.ConstU32(N - 1));
|
||||
compare_index = ctx.OpIAdd(ctx.U32[1], index, ctx.ConstU32(N - 1));
|
||||
}
|
||||
const Id in_bounds = ctx.OpULessThan(ctx.U1[1], compare_index, buffer_size);
|
||||
const Id in_bounds_label = ctx.OpLabel();
|
||||
|
|
|
@ -202,13 +202,12 @@ Id EmitSelectF32(EmitContext& ctx, Id cond, Id true_value, Id false_value);
|
|||
Id EmitSelectF64(EmitContext& ctx, Id cond, Id true_value, Id false_value);
|
||||
Id EmitBitCastU16F16(EmitContext& ctx, Id value);
|
||||
Id EmitBitCastU32F32(EmitContext& ctx, Id value);
|
||||
Id EmitBitCastU64F64(EmitContext& ctx, Id value);
|
||||
Id EmitBitCastF16U16(EmitContext& ctx, Id value);
|
||||
Id EmitBitCastF32U32(EmitContext& ctx, Id value);
|
||||
void EmitBitCastF64U64(EmitContext& ctx);
|
||||
Id EmitPackUint2x32(EmitContext& ctx, Id value);
|
||||
Id EmitUnpackUint2x32(EmitContext& ctx, Id value);
|
||||
Id EmitPackFloat2x32(EmitContext& ctx, Id value);
|
||||
Id EmitPackDouble2x32(EmitContext& ctx, Id value);
|
||||
Id EmitUnpackDouble2x32(EmitContext& ctx, Id value);
|
||||
Id EmitPackUnorm2x16(EmitContext& ctx, Id value);
|
||||
Id EmitUnpackUnorm2x16(EmitContext& ctx, Id value);
|
||||
Id EmitPackSnorm2x16(EmitContext& ctx, Id value);
|
||||
|
@ -483,6 +482,8 @@ Id EmitImageAtomicSMin32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords
|
|||
Id EmitImageAtomicUMin32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id value);
|
||||
Id EmitImageAtomicSMax32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id value);
|
||||
Id EmitImageAtomicUMax32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id value);
|
||||
Id EmitImageAtomicFMax32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id value);
|
||||
Id EmitImageAtomicFMin32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id value);
|
||||
Id EmitImageAtomicInc32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id value);
|
||||
Id EmitImageAtomicDec32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id value);
|
||||
Id EmitImageAtomicAnd32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id value);
|
||||
|
|
|
@ -869,6 +869,7 @@ void EmitContext::DefineImagesAndSamplers() {
|
|||
}
|
||||
if (std::ranges::any_of(info.images, &ImageResource::is_atomic)) {
|
||||
image_u32 = TypePointer(spv::StorageClass::Image, U32[1]);
|
||||
image_f32 = TypePointer(spv::StorageClass::Image, F32[1]);
|
||||
}
|
||||
if (info.samplers.empty()) {
|
||||
return;
|
||||
|
|
|
@ -207,6 +207,7 @@ public:
|
|||
Id invocation_id{};
|
||||
Id subgroup_local_invocation_id{};
|
||||
Id image_u32{};
|
||||
Id image_f32{};
|
||||
|
||||
Id shared_memory_u8{};
|
||||
Id shared_memory_u16{};
|
||||
|
|
|
@ -53,7 +53,7 @@ void Translator::S_LOAD_DWORD(int num_dwords, const GcnInst& inst) {
|
|||
ir.CompositeConstruct(ir.GetScalarReg(sbase), ir.GetScalarReg(sbase + 1));
|
||||
IR::ScalarReg dst_reg{inst.dst[0].code};
|
||||
for (u32 i = 0; i < num_dwords; i++) {
|
||||
ir.SetScalarReg(dst_reg++, ir.ReadConst(base, ir.Imm32(dword_offset + i)));
|
||||
ir.SetScalarReg(dst_reg + i, ir.ReadConst(base, ir.Imm32(dword_offset + i)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,7 +75,7 @@ void Translator::S_BUFFER_LOAD_DWORD(int num_dwords, const GcnInst& inst) {
|
|||
IR::ScalarReg dst_reg{inst.dst[0].code};
|
||||
for (u32 i = 0; i < num_dwords; i++) {
|
||||
const IR::U32 index = ir.IAdd(dword_offset, ir.Imm32(i));
|
||||
ir.SetScalarReg(dst_reg++, ir.ReadConstBuffer(vsharp, index));
|
||||
ir.SetScalarReg(dst_reg + i, ir.ReadConstBuffer(vsharp, index));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -336,7 +336,7 @@ T Translator::GetSrc64(const InstOperand& operand) {
|
|||
const auto value_lo = ir.GetVectorReg(IR::VectorReg(operand.code));
|
||||
const auto value_hi = ir.GetVectorReg(IR::VectorReg(operand.code + 1));
|
||||
if constexpr (is_float) {
|
||||
value = ir.PackFloat2x32(ir.CompositeConstruct(value_lo, value_hi));
|
||||
value = ir.PackDouble2x32(ir.CompositeConstruct(value_lo, value_hi));
|
||||
} else {
|
||||
value = ir.PackUint2x32(ir.CompositeConstruct(value_lo, value_hi));
|
||||
}
|
||||
|
@ -444,10 +444,9 @@ void Translator::SetDst64(const InstOperand& operand, const IR::U64F64& value_ra
|
|||
value_untyped = ir.FPSaturate(value_raw);
|
||||
}
|
||||
}
|
||||
const IR::U64 value =
|
||||
is_float ? ir.BitCast<IR::U64>(IR::F64{value_untyped}) : IR::U64{value_untyped};
|
||||
|
||||
const IR::Value unpacked{ir.UnpackUint2x32(value)};
|
||||
const IR::Value unpacked{is_float ? ir.UnpackDouble2x32(IR::F64{value_untyped})
|
||||
: ir.UnpackUint2x32(IR::U64{value_untyped})};
|
||||
const IR::U32 lo{ir.CompositeExtract(unpacked, 0U)};
|
||||
const IR::U32 hi{ir.CompositeExtract(unpacked, 1U)};
|
||||
switch (operand.field) {
|
||||
|
@ -518,7 +517,9 @@ void Translator::EmitFetch(const GcnInst& inst) {
|
|||
const auto values =
|
||||
ir.CompositeConstruct(ir.GetAttribute(attr, 0), ir.GetAttribute(attr, 1),
|
||||
ir.GetAttribute(attr, 2), ir.GetAttribute(attr, 3));
|
||||
const auto swizzled = ApplySwizzle(ir, values, buffer.DstSelect());
|
||||
const auto converted =
|
||||
IR::ApplyReadNumberConversionVec4(ir, values, buffer.GetNumberConversion());
|
||||
const auto swizzled = ApplySwizzle(ir, converted, buffer.DstSelect());
|
||||
for (u32 i = 0; i < 4; i++) {
|
||||
ir.SetVectorReg(dst_reg++, IR::F32{ir.CompositeExtract(swizzled, i)});
|
||||
}
|
||||
|
|
|
@ -513,13 +513,13 @@ void Translator::V_LSHLREV_B32(const GcnInst& inst) {
|
|||
|
||||
void Translator::V_AND_B32(const GcnInst& inst) {
|
||||
const IR::U32 src0{GetSrc(inst.src[0])};
|
||||
const IR::U32 src1{ir.GetVectorReg(IR::VectorReg(inst.src[1].code))};
|
||||
const IR::U32 src1{GetSrc(inst.src[1])};
|
||||
SetDst(inst.dst[0], ir.BitwiseAnd(src0, src1));
|
||||
}
|
||||
|
||||
void Translator::V_OR_B32(bool is_xor, const GcnInst& inst) {
|
||||
const IR::U32 src0{GetSrc(inst.src[0])};
|
||||
const IR::U32 src1{ir.GetVectorReg(IR::VectorReg(inst.src[1].code))};
|
||||
const IR::U32 src1{GetSrc(inst.src[1])};
|
||||
SetDst(inst.dst[0], is_xor ? ir.BitwiseXor(src0, src1) : IR::U32(ir.BitwiseOr(src0, src1)));
|
||||
}
|
||||
|
||||
|
@ -579,7 +579,7 @@ void Translator::V_MBCNT_U32_B32(bool is_low, const GcnInst& inst) {
|
|||
void Translator::V_ADD_I32(const GcnInst& inst) {
|
||||
// Signed or unsigned components
|
||||
const IR::U32 src0{GetSrc(inst.src[0])};
|
||||
const IR::U32 src1{ir.GetVectorReg(IR::VectorReg(inst.src[1].code))};
|
||||
const IR::U32 src1{GetSrc(inst.src[1])};
|
||||
const IR::U32 result{ir.IAdd(src0, src1)};
|
||||
SetDst(inst.dst[0], result);
|
||||
|
||||
|
@ -989,13 +989,22 @@ void Translator::V_CMP_NE_U64(const GcnInst& inst) {
|
|||
}
|
||||
};
|
||||
const IR::U1 src0{get_src(inst.src[0])};
|
||||
ASSERT(inst.src[1].field == OperandField::ConstZero); // src0 != 0
|
||||
auto op = [&inst, this](auto x) {
|
||||
switch (inst.src[1].field) {
|
||||
case OperandField::ConstZero:
|
||||
return x;
|
||||
case OperandField::SignedConstIntNeg:
|
||||
return ir.LogicalNot(x);
|
||||
default:
|
||||
UNREACHABLE_MSG("unhandled V_CMP_NE_U64 source argument {}", u32(inst.src[1].field));
|
||||
}
|
||||
};
|
||||
switch (inst.dst[1].field) {
|
||||
case OperandField::VccLo:
|
||||
ir.SetVcc(src0);
|
||||
ir.SetVcc(op(src0));
|
||||
break;
|
||||
case OperandField::ScalarGPR:
|
||||
ir.SetThreadBitScalarReg(IR::ScalarReg(inst.dst[1].code), src0);
|
||||
ir.SetThreadBitScalarReg(IR::ScalarReg(inst.dst[1].code), op(src0));
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
|
|
|
@ -115,8 +115,12 @@ void Translator::EmitVectorMemory(const GcnInst& inst) {
|
|||
return IMAGE_ATOMIC(AtomicOp::Smin, inst);
|
||||
case Opcode::IMAGE_ATOMIC_UMIN:
|
||||
return IMAGE_ATOMIC(AtomicOp::Umin, inst);
|
||||
case Opcode::IMAGE_ATOMIC_FMIN:
|
||||
return IMAGE_ATOMIC(AtomicOp::Fmin, inst);
|
||||
case Opcode::IMAGE_ATOMIC_SMAX:
|
||||
return IMAGE_ATOMIC(AtomicOp::Smax, inst);
|
||||
case Opcode::IMAGE_ATOMIC_FMAX:
|
||||
return IMAGE_ATOMIC(AtomicOp::Fmax, inst);
|
||||
case Opcode::IMAGE_ATOMIC_UMAX:
|
||||
return IMAGE_ATOMIC(AtomicOp::Umax, inst);
|
||||
case Opcode::IMAGE_ATOMIC_AND:
|
||||
|
@ -139,6 +143,7 @@ void Translator::EmitVectorMemory(const GcnInst& inst) {
|
|||
case Opcode::IMAGE_SAMPLE_C_LZ:
|
||||
case Opcode::IMAGE_SAMPLE_O:
|
||||
case Opcode::IMAGE_SAMPLE_L_O:
|
||||
case Opcode::IMAGE_SAMPLE_B_O:
|
||||
case Opcode::IMAGE_SAMPLE_LZ_O:
|
||||
case Opcode::IMAGE_SAMPLE_C_O:
|
||||
case Opcode::IMAGE_SAMPLE_C_LZ_O:
|
||||
|
@ -466,6 +471,10 @@ void Translator::IMAGE_ATOMIC(AtomicOp op, const GcnInst& inst) {
|
|||
return ir.ImageAtomicIMax(handle, body, value, true, info);
|
||||
case AtomicOp::Umax:
|
||||
return ir.ImageAtomicUMax(handle, body, value, info);
|
||||
case AtomicOp::Fmax:
|
||||
return ir.ImageAtomicFMax(handle, body, value, info);
|
||||
case AtomicOp::Fmin:
|
||||
return ir.ImageAtomicFMin(handle, body, value, info);
|
||||
case AtomicOp::And:
|
||||
return ir.ImageAtomicAnd(handle, body, value, info);
|
||||
case AtomicOp::Or:
|
||||
|
|
|
@ -62,7 +62,14 @@ struct BufferResource {
|
|||
}
|
||||
|
||||
bool IsStorage(const AmdGpu::Buffer& buffer, const Profile& profile) const noexcept {
|
||||
return buffer.GetSize() > profile.max_ubo_size || is_written;
|
||||
// When using uniform buffers, a size is required at compilation time, so we need to
|
||||
// either compile a lot of shader specializations to handle each size or just force it to
|
||||
// the maximum possible size always. However, for some vendors the shader-supplied size is
|
||||
// used for bounds checking uniform buffer accesses, so the latter would effectively turn
|
||||
// off buffer robustness behavior. Instead, force storage buffers which are bounds checked
|
||||
// using the actual buffer size. We are assuming the performance hit from this is
|
||||
// acceptable.
|
||||
return true; // buffer.GetSize() > profile.max_ubo_size || is_written;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr AmdGpu::Buffer GetSharp(const Info& info) const noexcept;
|
||||
|
@ -196,6 +203,7 @@ struct Info {
|
|||
bool has_discard{};
|
||||
bool has_image_gather{};
|
||||
bool has_image_query{};
|
||||
bool uses_atomic_float_min_max{};
|
||||
bool uses_lane_id{};
|
||||
bool uses_group_quad{};
|
||||
bool uses_group_ballot{};
|
||||
|
@ -280,6 +288,11 @@ constexpr AmdGpu::Image ImageResource::GetSharp(const Info& info) const noexcept
|
|||
// Fall back to null image if unbound.
|
||||
return AmdGpu::Image::Null();
|
||||
}
|
||||
const auto data_fmt = image.GetDataFmt();
|
||||
if (is_depth && data_fmt != AmdGpu::DataFormat::Format16 &&
|
||||
data_fmt != AmdGpu::DataFormat::Format32) {
|
||||
return AmdGpu::Image::NullDepth();
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue