Merge remote-tracking branch 'origin/main' into multiple-controllers

This commit is contained in:
kalaposfos13 2025-05-25 16:01:33 +02:00
commit d8fd8915a9
205 changed files with 8118 additions and 1767 deletions

View File

@ -287,7 +287,7 @@ jobs:
sudo add-apt-repository 'deb http://apt.llvm.org/noble/ llvm-toolchain-noble-19 main' sudo add-apt-repository 'deb http://apt.llvm.org/noble/ llvm-toolchain-noble-19 main'
- name: Install dependencies - 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-19 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 - name: Cache CMake Configuration
uses: actions/cache@v4 uses: actions/cache@v4
@ -309,7 +309,7 @@ jobs:
key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }} key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
- name: Configure 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-19 -DCMAKE_CXX_COMPILER=clang++-19 -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 - name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $(nproc) run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $(nproc)
@ -348,7 +348,7 @@ jobs:
sudo add-apt-repository 'deb http://apt.llvm.org/noble/ llvm-toolchain-noble-19 main' sudo add-apt-repository 'deb http://apt.llvm.org/noble/ llvm-toolchain-noble-19 main'
- name: Install dependencies - 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-19 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 - name: Cache CMake Configuration
uses: actions/cache@v4 uses: actions/cache@v4
@ -370,7 +370,7 @@ jobs:
key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }} key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
- name: Configure 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-19 -DCMAKE_CXX_COMPILER=clang++-19 -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 - name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $(nproc) run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $(nproc)
@ -395,7 +395,7 @@ jobs:
submodules: recursive submodules: recursive
- name: Install dependencies - 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 - name: Cache CMake Configuration
uses: actions/cache@v4 uses: actions/cache@v4
@ -417,7 +417,7 @@ jobs:
key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }} key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
- name: Configure 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 - name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $(nproc) run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $(nproc)
@ -431,7 +431,7 @@ jobs:
submodules: recursive submodules: recursive
- name: Install dependencies - 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 - name: Cache CMake Configuration
uses: actions/cache@v4 uses: actions/cache@v4
@ -453,7 +453,7 @@ jobs:
key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }} key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
- name: Configure 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 - name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $(nproc) run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $(nproc)

4
.gitmodules vendored
View File

@ -30,10 +30,6 @@
path = externals/xbyak path = externals/xbyak
url = https://github.com/herumi/xbyak.git url = https://github.com/herumi/xbyak.git
shallow = true shallow = true
[submodule "externals/winpthreads"]
path = externals/winpthreads
url = https://github.com/shadps4-emu/winpthreads.git
shallow = true
[submodule "externals/magic_enum"] [submodule "externals/magic_enum"]
path = externals/magic_enum path = externals/magic_enum
url = https://github.com/Neargye/magic_enum.git url = https://github.com/Neargye/magic_enum.git

60
CMakeLists.txt Executable file → Normal file
View File

@ -54,9 +54,9 @@ else()
endif() endif()
if (ARCHITECTURE STREQUAL "x86_64") if (ARCHITECTURE STREQUAL "x86_64")
# Target the same CPU architecture as the PS4, to maintain the same level of compatibility. # Target x86-64-v3 CPU architecture as this is a good balance between supporting performance critical
# Exclude SSE4a as it is only available on AMD CPUs. # instructions like AVX2 and maintaining support for older CPUs.
add_compile_options(-march=btver2 -mtune=generic -mno-sse4a) add_compile_options(-march=x86-64-v3)
endif() endif()
if (APPLE AND ARCHITECTURE STREQUAL "x86_64" AND CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "arm64") if (APPLE AND ARCHITECTURE STREQUAL "x86_64" AND CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "arm64")
@ -134,6 +134,7 @@ if (GIT_REMOTE_RESULT OR GIT_REMOTE_NAME STREQUAL "")
ERROR_QUIET ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_STRIP_TRAILING_WHITESPACE
) )
message("got remote: ${GIT_REMOTE_NAME}")
endif() endif()
# If running in GitHub Actions and the above fails # If running in GitHub Actions and the above fails
@ -177,7 +178,7 @@ if (GIT_REMOTE_RESULT OR GIT_REMOTE_NAME STREQUAL "")
set(GIT_BRANCH "${GITHUB_BRANCH}") set(GIT_BRANCH "${GITHUB_BRANCH}")
elseif ("${PR_NUMBER}" STREQUAL "" AND NOT "${GITHUB_REF}" STREQUAL "") elseif ("${PR_NUMBER}" STREQUAL "" AND NOT "${GITHUB_REF}" STREQUAL "")
set(GIT_BRANCH "${GITHUB_REF}") set(GIT_BRANCH "${GITHUB_REF}")
else() elseif("${GIT_BRANCH}" STREQUAL "")
message("couldn't find branch") message("couldn't find branch")
set(GIT_BRANCH "detached-head") set(GIT_BRANCH "detached-head")
endif() endif()
@ -186,8 +187,8 @@ else()
string(FIND "${GIT_REMOTE_NAME}" "/" INDEX) string(FIND "${GIT_REMOTE_NAME}" "/" INDEX)
if (INDEX GREATER -1) if (INDEX GREATER -1)
string(SUBSTRING "${GIT_REMOTE_NAME}" 0 "${INDEX}" GIT_REMOTE_NAME) string(SUBSTRING "${GIT_REMOTE_NAME}" 0 "${INDEX}" GIT_REMOTE_NAME)
else() elseif("${GIT_REMOTE_NAME}" STREQUAL "")
# If no remote is present (only a branch name), default to origin message("reset to origin")
set(GIT_REMOTE_NAME "origin") set(GIT_REMOTE_NAME "origin")
endif() endif()
endif() endif()
@ -202,7 +203,7 @@ execute_process(
# Set Version # Set Version
set(EMULATOR_VERSION_MAJOR "0") set(EMULATOR_VERSION_MAJOR "0")
set(EMULATOR_VERSION_MINOR "8") set(EMULATOR_VERSION_MINOR "9")
set(EMULATOR_VERSION_PATCH "1") 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_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}")
@ -226,7 +227,7 @@ find_package(SDL3 3.1.2 CONFIG)
find_package(stb MODULE) find_package(stb MODULE)
find_package(toml11 4.2.0 CONFIG) find_package(toml11 4.2.0 CONFIG)
find_package(tsl-robin-map 1.3.0 CONFIG) find_package(tsl-robin-map 1.3.0 CONFIG)
find_package(VulkanHeaders 1.4.309 CONFIG) find_package(VulkanHeaders 1.4.314 CONFIG)
find_package(VulkanMemoryAllocator 3.1.0 CONFIG) find_package(VulkanMemoryAllocator 3.1.0 CONFIG)
find_package(xbyak 7.07 CONFIG) find_package(xbyak 7.07 CONFIG)
find_package(xxHash 0.8.2 MODULE) find_package(xxHash 0.8.2 MODULE)
@ -239,13 +240,6 @@ if (APPLE)
endif() endif()
list(POP_BACK CMAKE_MODULE_PATH) list(POP_BACK CMAKE_MODULE_PATH)
# Note: Windows always has these functions through winpthreads
include(CheckSymbolExists)
check_symbol_exists(pthread_mutex_timedlock "pthread.h" HAVE_PTHREAD_MUTEX_TIMEDLOCK)
if(HAVE_PTHREAD_MUTEX_TIMEDLOCK OR WIN32)
add_compile_options(-DHAVE_PTHREAD_MUTEX_TIMEDLOCK)
endif()
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
# libc++ requires -fexperimental-library to enable std::jthread and std::stop_token support. # libc++ requires -fexperimental-library to enable std::jthread and std::stop_token support.
include(CheckCXXSymbolExists) include(CheckCXXSymbolExists)
@ -371,11 +365,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.cpp
src/core/libraries/network/net_ctl_obj.h src/core/libraries/network/net_ctl_obj.h
src/core/libraries/network/net_ctl_codes.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/net.h
src/core/libraries/network/ssl.cpp src/core/libraries/network/ssl.cpp
src/core/libraries/network/ssl.h src/core/libraries/network/ssl.h
src/core/libraries/network/ssl2.cpp src/core/libraries/network/ssl2.cpp
src/core/libraries/network/ssl2.h 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 set(AVPLAYER_LIB src/core/libraries/avplayer/avplayer_common.cpp
@ -408,6 +410,7 @@ set(SYSTEM_LIBS src/core/libraries/system/commondialog.cpp
src/core/libraries/save_data/save_memory.h src/core/libraries/save_data/save_memory.h
src/core/libraries/save_data/savedata.cpp src/core/libraries/save_data/savedata.cpp
src/core/libraries/save_data/savedata.h src/core/libraries/save_data/savedata.h
src/core/libraries/save_data/savedata_error.h
src/core/libraries/save_data/dialog/savedatadialog.cpp src/core/libraries/save_data/dialog/savedatadialog.cpp
src/core/libraries/save_data/dialog/savedatadialog.h src/core/libraries/save_data/dialog/savedatadialog.h
src/core/libraries/save_data/dialog/savedatadialog_ui.cpp src/core/libraries/save_data/dialog/savedatadialog_ui.cpp
@ -589,8 +592,19 @@ set(MISC_LIBS src/core/libraries/screenshot/screenshot.cpp
src/core/libraries/move/move.h src/core/libraries/move/move.h
src/core/libraries/ulobjmgr/ulobjmgr.cpp src/core/libraries/ulobjmgr/ulobjmgr.cpp
src/core/libraries/ulobjmgr/ulobjmgr.h 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(COMPANION_LIBS src/core/libraries/companion/companion_httpd.cpp
src/core/libraries/companion/companion_httpd.h
src/core/libraries/companion/companion_error.h
)
set(DEV_TOOLS src/core/devtools/layer.cpp set(DEV_TOOLS src/core/devtools/layer.cpp
src/core/devtools/layer.h src/core/devtools/layer.h
src/core/devtools/options.cpp src/core/devtools/options.cpp
@ -608,6 +622,8 @@ set(DEV_TOOLS src/core/devtools/layer.cpp
src/core/devtools/widget/imgui_memory_editor.h src/core/devtools/widget/imgui_memory_editor.h
src/core/devtools/widget/memory_map.cpp src/core/devtools/widget/memory_map.cpp
src/core/devtools/widget/memory_map.h src/core/devtools/widget/memory_map.h
src/core/devtools/widget/module_list.cpp
src/core/devtools/widget/module_list.h
src/core/devtools/widget/reg_popup.cpp src/core/devtools/widget/reg_popup.cpp
src/core/devtools/widget/reg_popup.h src/core/devtools/widget/reg_popup.h
src/core/devtools/widget/reg_view.cpp src/core/devtools/widget/reg_view.cpp
@ -660,6 +676,8 @@ set(COMMON src/common/logging/backend.cpp
src/common/polyfill_thread.h src/common/polyfill_thread.h
src/common/rdtsc.cpp src/common/rdtsc.cpp
src/common/rdtsc.h src/common/rdtsc.h
src/common/recursive_lock.cpp
src/common/recursive_lock.h
src/common/sha1.h src/common/sha1.h
src/common/signal_context.h src/common/signal_context.h
src/common/signal_context.cpp src/common/signal_context.cpp
@ -754,6 +772,8 @@ set(CORE src/core/aerolib/stubs.cpp
${FIBER_LIB} ${FIBER_LIB}
${VDEC_LIB} ${VDEC_LIB}
${VR_LIBS} ${VR_LIBS}
${CAMERA_LIBS}
${COMPANION_LIBS}
${DEV_TOOLS} ${DEV_TOOLS}
src/core/debug_state.cpp src/core/debug_state.cpp
src/core/debug_state.h src/core/debug_state.h
@ -840,6 +860,7 @@ set(SHADER_RECOMPILER src/shader_recompiler/exception.h
src/shader_recompiler/ir/passes/identity_removal_pass.cpp src/shader_recompiler/ir/passes/identity_removal_pass.cpp
src/shader_recompiler/ir/passes/ir_passes.h 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_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/readlane_elimination_pass.cpp
src/shader_recompiler/ir/passes/resource_tracking_pass.cpp src/shader_recompiler/ir/passes/resource_tracking_pass.cpp
src/shader_recompiler/ir/passes/ring_access_elimination.cpp src/shader_recompiler/ir/passes/ring_access_elimination.cpp
@ -847,6 +868,7 @@ set(SHADER_RECOMPILER src/shader_recompiler/exception.h
src/shader_recompiler/ir/passes/shared_memory_barrier_pass.cpp src/shader_recompiler/ir/passes/shared_memory_barrier_pass.cpp
src/shader_recompiler/ir/passes/shared_memory_to_storage_pass.cpp src/shader_recompiler/ir/passes/shared_memory_to_storage_pass.cpp
src/shader_recompiler/ir/passes/ssa_rewrite_pass.cpp src/shader_recompiler/ir/passes/ssa_rewrite_pass.cpp
src/shader_recompiler/ir/abstract_syntax_list.cpp
src/shader_recompiler/ir/abstract_syntax_list.h src/shader_recompiler/ir/abstract_syntax_list.h
src/shader_recompiler/ir/attribute.cpp src/shader_recompiler/ir/attribute.cpp
src/shader_recompiler/ir/attribute.h src/shader_recompiler/ir/attribute.h
@ -1077,11 +1099,15 @@ if (ENABLE_DISCORD_RPC)
target_compile_definitions(shadps4 PRIVATE ENABLE_DISCORD_RPC) target_compile_definitions(shadps4 PRIVATE ENABLE_DISCORD_RPC)
endif() endif()
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
# Optional due to https://github.com/shadps4-emu/shadPS4/issues/1704 # Optional due to https://github.com/shadps4-emu/shadPS4/issues/1704
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" AND ENABLE_USERFAULTFD) if (ENABLE_USERFAULTFD)
target_compile_definitions(shadps4 PRIVATE ENABLE_USERFAULTFD) target_compile_definitions(shadps4 PRIVATE ENABLE_USERFAULTFD)
endif() endif()
target_link_libraries(shadps4 PRIVATE uuid)
endif()
if (APPLE) if (APPLE)
# Include MoltenVK, along with an ICD file so it can be found by the system Vulkan loader if used for loading layers. # Include MoltenVK, along with an ICD file so it can be found by the system Vulkan loader if used for loading layers.
if (ENABLE_QT_GUI) if (ENABLE_QT_GUI)
@ -1135,7 +1161,7 @@ if (ENABLE_QT_GUI)
endif() endif()
if (WIN32) if (WIN32)
target_link_libraries(shadps4 PRIVATE mincore winpthreads) target_link_libraries(shadps4 PRIVATE mincore)
if (MSVC) if (MSVC)
# MSVC likes putting opinions on what people can use, disable: # MSVC likes putting opinions on what people can use, disable:

View File

@ -37,7 +37,10 @@
<category translate="no">Game</category> <category translate="no">Game</category>
</categories> </categories>
<releases> <releases>
<release version="0.8.0" date="2025-05-23"> <release version="0.9.0" date="2025-05-22">
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/v.0.9.0</url>
</release>
<release version="0.8.0" date="2025-04-23">
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/v.0.8.0</url> <url>https://github.com/shadps4-emu/shadPS4/releases/tag/v.0.8.0</url>
</release> </release>
<release version="0.7.0" date="2025-03-23"> <release version="0.7.0" date="2025-03-23">

View File

@ -21,9 +21,9 @@ SPDX-License-Identifier: GPL-2.0-or-later
- A processor with at least 4 cores and 6 threads - A processor with at least 4 cores and 6 threads
- Above 2.5 GHz frequency - Above 2.5 GHz frequency
- A CPU supporting the following instruction sets: MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, AVX, F16C, CLMUL, AES, BMI1, MOVBE, XSAVE, ABM - A CPU supporting the x86-64-v3 baseline.
- **Intel**: Haswell generation or newer - **Intel**: Haswell generation or newer
- **AMD**: Jaguar generation or newer - **AMD**: Excavator generation or newer
- **Apple**: Rosetta 2 on macOS 15.4 or newer - **Apple**: Rosetta 2 on macOS 15.4 or newer
### GPU ### GPU

View File

@ -137,12 +137,6 @@ if (NOT TARGET Zydis::Zydis)
add_subdirectory(zydis) add_subdirectory(zydis)
endif() endif()
# Winpthreads
if (WIN32)
add_subdirectory(winpthreads)
target_include_directories(winpthreads INTERFACE winpthreads/include)
endif()
# sirit # sirit
add_subdirectory(sirit) add_subdirectory(sirit)
if (WIN32) if (WIN32)

@ -1 +1 @@
Subproject commit 87a8e8b13d4ad8835367fea1ebad1896d0460946 Subproject commit 3a0b07a24a4a681ffe70b461b1f4333b2729e2ef

@ -1 +1 @@
Subproject commit 7918775748c5e2f5c40d9918ce68825035b5a1e1 Subproject commit 969e75f7cc0718774231d029f9d52fa87d4ae1b2

2
externals/sdl3 vendored

@ -1 +1 @@
Subproject commit 4093e4a193971ef1d4928158e0a1832be42e4599 Subproject commit 86b206dadf8ad40e6657fa37db371a0aeff74e9c

2
externals/sirit vendored

@ -1 +1 @@
Subproject commit 427a42c9ed99b38204d9107bc3dc14e92458acf1 Subproject commit 6b450704f6fedb9413d0c89a9eb59d028eb1e6c0

@ -1 +1 @@
Subproject commit 5ceb9ed481e58e705d0d9b5326537daedd06b97d Subproject commit 9c77de5c3dd216f28e407eec65ed9c0a296c1f74

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

View File

@ -156,7 +156,7 @@ bool GetLoadGameSizeEnabled() {
std::filesystem::path GetSaveDataPath() { std::filesystem::path GetSaveDataPath() {
if (save_data_path.empty()) { if (save_data_path.empty()) {
return Common::FS::GetUserPath(Common::FS::PathType::SaveDataDir); return Common::FS::GetUserPath(Common::FS::PathType::UserDir) / "savedata";
} }
return save_data_path; return save_data_path;
} }

View File

@ -71,6 +71,7 @@ class ElfInfo {
PSFAttributes psf_attributes{}; PSFAttributes psf_attributes{};
std::filesystem::path splash_path{}; std::filesystem::path splash_path{};
std::filesystem::path game_folder{};
public: public:
static constexpr u32 FW_15 = 0x1500000; static constexpr u32 FW_15 = 0x1500000;
@ -123,6 +124,10 @@ public:
[[nodiscard]] const std::filesystem::path& GetSplashPath() const { [[nodiscard]] const std::filesystem::path& GetSplashPath() const {
return splash_path; return splash_path;
} }
[[nodiscard]] const std::filesystem::path& GetGameFolder() const {
return game_folder;
}
}; };
} // namespace Common } // namespace Common

View File

@ -131,9 +131,7 @@ namespace {
case SeekOrigin::End: case SeekOrigin::End:
return SEEK_END; return SEEK_END;
default: default:
LOG_ERROR(Common_Filesystem, "Unsupported origin {}, defaulting to SEEK_SET", UNREACHABLE_MSG("Impossible SeekOrigin {}", static_cast<u32>(origin));
static_cast<u32>(origin));
return SEEK_SET;
} }
} }

View File

@ -61,8 +61,6 @@ enum class SeekOrigin : u32 {
SetOrigin, // Seeks from the start of the file. SetOrigin, // Seeks from the start of the file.
CurrentPosition, // Seeks from the current file pointer position. CurrentPosition, // Seeks from the current file pointer position.
End, // Seeks from the end of the file. 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 { class IOFile final {

View File

@ -137,6 +137,9 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
SUB(Lib, NpParty) \ SUB(Lib, NpParty) \
SUB(Lib, Zlib) \ SUB(Lib, Zlib) \
SUB(Lib, Hmd) \ SUB(Lib, Hmd) \
SUB(Lib, SigninDialog) \
SUB(Lib, Camera) \
SUB(Lib, CompanionHttpd) \
CLS(Frontend) \ CLS(Frontend) \
CLS(Render) \ CLS(Render) \
SUB(Render, Vulkan) \ SUB(Render, Vulkan) \

View File

@ -104,6 +104,9 @@ enum class Class : u8 {
Lib_NpParty, ///< The LibSceNpParty implementation Lib_NpParty, ///< The LibSceNpParty implementation
Lib_Zlib, ///< The LibSceZlib implementation. Lib_Zlib, ///< The LibSceZlib implementation.
Lib_Hmd, ///< The LibSceHmd implementation. Lib_Hmd, ///< The LibSceHmd implementation.
Lib_SigninDialog, ///< The LibSigninDialog implementation.
Lib_Camera, ///< The LibCamera implementation.
Lib_CompanionHttpd, ///< The LibCompanionHttpd implementation.
Frontend, ///< Emulator UI Frontend, ///< Emulator UI
Render, ///< Video Core Render, ///< Video Core
Render_Vulkan, ///< Vulkan backend Render_Vulkan, ///< Vulkan backend

View File

@ -23,7 +23,7 @@
namespace MemoryPatcher { namespace MemoryPatcher {
uintptr_t g_eboot_address; EXPORT uintptr_t g_eboot_address;
uint64_t g_eboot_image_size; uint64_t g_eboot_image_size;
std::string g_game_serial; std::string g_game_serial;
std::string patchFile; std::string patchFile;
@ -169,7 +169,8 @@ void OnGameLoaded() {
if (type == "mask_jump32") if (type == "mask_jump32")
patchMask = MemoryPatcher::PatchMask::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); maskOffsetValue = std::stoi(maskOffsetStr, 0, 10);
} }

View File

@ -6,9 +6,15 @@
#include <string> #include <string>
#include <vector> #include <vector>
#if defined(WIN32)
#define EXPORT __declspec(dllexport)
#else
#define EXPORT __attribute__((visibility("default")))
#endif
namespace MemoryPatcher { namespace MemoryPatcher {
extern uintptr_t g_eboot_address; extern EXPORT uintptr_t g_eboot_address;
extern uint64_t g_eboot_image_size; extern uint64_t g_eboot_image_size;
extern std::string g_game_serial; extern std::string g_game_serial;
extern std::string patchFile; extern std::string patchFile;

View File

@ -128,7 +128,6 @@ static auto UserPaths = [] {
create_path(PathType::LogDir, user_dir / LOG_DIR); create_path(PathType::LogDir, user_dir / LOG_DIR);
create_path(PathType::ScreenshotsDir, user_dir / SCREENSHOTS_DIR); create_path(PathType::ScreenshotsDir, user_dir / SCREENSHOTS_DIR);
create_path(PathType::ShaderDir, user_dir / SHADER_DIR); create_path(PathType::ShaderDir, user_dir / SHADER_DIR);
create_path(PathType::SaveDataDir, user_dir / SAVEDATA_DIR);
create_path(PathType::GameDataDir, user_dir / GAMEDATA_DIR); create_path(PathType::GameDataDir, user_dir / GAMEDATA_DIR);
create_path(PathType::TempDataDir, user_dir / TEMPDATA_DIR); create_path(PathType::TempDataDir, user_dir / TEMPDATA_DIR);
create_path(PathType::SysModuleDir, user_dir / SYSMODULES_DIR); create_path(PathType::SysModuleDir, user_dir / SYSMODULES_DIR);

View File

@ -18,7 +18,6 @@ enum class PathType {
LogDir, // Where log files are stored. LogDir, // Where log files are stored.
ScreenshotsDir, // Where screenshots are stored. ScreenshotsDir, // Where screenshots are stored.
ShaderDir, // Where shaders are stored. ShaderDir, // Where shaders are stored.
SaveDataDir, // Where guest save data is stored.
TempDataDir, // Where game temp data is stored. TempDataDir, // Where game temp data is stored.
GameDataDir, // Where game data is stored. GameDataDir, // Where game data is stored.
SysModuleDir, // Where system modules are stored. SysModuleDir, // Where system modules are stored.
@ -36,7 +35,6 @@ constexpr auto PORTABLE_DIR = "user";
constexpr auto LOG_DIR = "log"; constexpr auto LOG_DIR = "log";
constexpr auto SCREENSHOTS_DIR = "screenshots"; constexpr auto SCREENSHOTS_DIR = "screenshots";
constexpr auto SHADER_DIR = "shader"; constexpr auto SHADER_DIR = "shader";
constexpr auto SAVEDATA_DIR = "savedata";
constexpr auto GAMEDATA_DIR = "data"; constexpr auto GAMEDATA_DIR = "data";
constexpr auto TEMPDATA_DIR = "temp"; constexpr auto TEMPDATA_DIR = "temp";
constexpr auto SYSMODULES_DIR = "sys_modules"; constexpr auto SYSMODULES_DIR = "sys_modules";

View File

@ -0,0 +1,37 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <unordered_map>
#include "common/assert.h"
#include "common/recursive_lock.h"
namespace Common::Detail {
struct RecursiveLockState {
RecursiveLockType type;
int count;
};
thread_local std::unordered_map<void*, RecursiveLockState> g_recursive_locks;
bool IncrementRecursiveLock(void* mutex, RecursiveLockType type) {
auto& state = g_recursive_locks[mutex];
if (state.count == 0) {
ASSERT(state.type == RecursiveLockType::None);
state.type = type;
}
ASSERT(state.type == type);
return state.count++ == 0;
}
bool DecrementRecursiveLock(void* mutex, RecursiveLockType type) {
auto& state = g_recursive_locks[mutex];
ASSERT(state.type == type && state.count > 0);
if (--state.count == 0) {
g_recursive_locks.erase(mutex);
return true;
}
return false;
}
} // namespace Common::Detail

View File

@ -0,0 +1,67 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <mutex>
#include <optional>
#include <shared_mutex>
namespace Common {
namespace Detail {
enum class RecursiveLockType { None, Shared, Exclusive };
bool IncrementRecursiveLock(void* mutex, RecursiveLockType type);
bool DecrementRecursiveLock(void* mutex, RecursiveLockType type);
} // namespace Detail
template <typename MutexType>
class RecursiveScopedLock {
public:
explicit RecursiveScopedLock(MutexType& mutex) : m_mutex(mutex), m_locked(false) {
if (Detail::IncrementRecursiveLock(&m_mutex, Detail::RecursiveLockType::Exclusive)) {
m_locked = true;
m_lock.emplace(m_mutex);
}
}
~RecursiveScopedLock() {
Detail::DecrementRecursiveLock(&m_mutex, Detail::RecursiveLockType::Exclusive);
if (m_locked) {
m_lock.reset();
}
}
private:
MutexType& m_mutex;
std::optional<std::unique_lock<MutexType>> m_lock;
bool m_locked = false;
};
template <typename MutexType>
class RecursiveSharedLock {
public:
explicit RecursiveSharedLock(MutexType& mutex) : m_mutex(mutex), m_locked(false) {
if (Detail::IncrementRecursiveLock(&m_mutex, Detail::RecursiveLockType::Shared)) {
m_locked = true;
m_lock.emplace(m_mutex);
}
}
~RecursiveSharedLock() {
Detail::DecrementRecursiveLock(&m_mutex, Detail::RecursiveLockType::Shared);
if (m_locked) {
m_lock.reset();
}
}
private:
MutexType& m_mutex;
std::optional<std::shared_lock<MutexType>> m_lock;
bool m_locked = false;
};
} // namespace Common

View File

@ -14,6 +14,9 @@ namespace Common {
struct SlotId { struct SlotId {
static constexpr u32 INVALID_INDEX = std::numeric_limits<u32>::max(); static constexpr u32 INVALID_INDEX = std::numeric_limits<u32>::max();
SlotId() noexcept = default;
constexpr SlotId(u32 index) noexcept : index(index) {}
constexpr auto operator<=>(const SlotId&) const noexcept = default; constexpr auto operator<=>(const SlotId&) const noexcept = default;
constexpr explicit operator bool() const noexcept { constexpr explicit operator bool() const noexcept {
@ -28,6 +31,63 @@ class SlotVector {
constexpr static std::size_t InitialCapacity = 2048; constexpr static std::size_t InitialCapacity = 2048;
public: public:
template <typename ValueType, typename Pointer, typename Reference>
class Iterator {
public:
using iterator_category = std::forward_iterator_tag;
using value_type = ValueType;
using difference_type = std::ptrdiff_t;
using pointer = Pointer;
using reference = Reference;
Iterator(SlotVector& vector_, SlotId index_) : vector(vector_), slot(index_) {
AdvanceToValid();
}
reference operator*() const {
return vector[slot];
}
pointer operator->() const {
return &vector[slot];
}
Iterator& operator++() {
++slot.index;
AdvanceToValid();
return *this;
}
Iterator operator++(int) {
Iterator temp = *this;
++(*this);
return temp;
}
bool operator==(const Iterator& other) const {
return slot == other.slot;
}
bool operator!=(const Iterator& other) const {
return !(*this == other);
}
private:
void AdvanceToValid() {
while (slot < vector.values_capacity && !vector.ReadStorageBit(slot.index)) {
++slot.index;
}
}
SlotVector& vector;
SlotId slot;
};
using iterator = Iterator<T, T*, T&>;
using const_iterator = Iterator<const T, const T*, const T&>;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
SlotVector() { SlotVector() {
Reserve(InitialCapacity); Reserve(InitialCapacity);
} }
@ -60,7 +120,7 @@ public:
} }
template <typename... Args> template <typename... Args>
[[nodiscard]] SlotId insert(Args&&... args) noexcept { SlotId insert(Args&&... args) noexcept {
const u32 index = FreeValueIndex(); const u32 index = FreeValueIndex();
new (&values[index].object) T(std::forward<Args>(args)...); new (&values[index].object) T(std::forward<Args>(args)...);
SetStorageBit(index); SetStorageBit(index);
@ -78,6 +138,54 @@ public:
return values_capacity - free_list.size(); return values_capacity - free_list.size();
} }
iterator begin() noexcept {
return iterator(*this, 0);
}
const_iterator begin() const noexcept {
return const_iterator(*this, 0);
}
const_iterator cbegin() const noexcept {
return begin();
}
iterator end() noexcept {
return iterator(*this, values_capacity);
}
const_iterator end() const noexcept {
return const_iterator(*this, values_capacity);
}
const_iterator cend() const noexcept {
return end();
}
reverse_iterator rbegin() noexcept {
return reverse_iterator(end());
}
const_reverse_iterator rbegin() const noexcept {
return const_reverse_iterator(end());
}
const_reverse_iterator crbegin() const noexcept {
return rbegin();
}
reverse_iterator rend() noexcept {
return reverse_iterator(begin());
}
const_reverse_iterator rend() const noexcept {
return const_reverse_iterator(begin());
}
const_reverse_iterator crend() const noexcept {
return rend();
}
private: private:
struct NonTrivialDummy { struct NonTrivialDummy {
NonTrivialDummy() noexcept {} NonTrivialDummy() noexcept {}

View File

@ -2,6 +2,7 @@
// SPDX-FileCopyrightText: 2014 Citra Emulator Project // SPDX-FileCopyrightText: 2014 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <ctime>
#include <string> #include <string>
#include <thread> #include <thread>
@ -104,14 +105,24 @@ void SetCurrentThreadPriority(ThreadPriority new_priority) {
SetThreadPriority(handle, windows_priority); SetThreadPriority(handle, windows_priority);
} }
static void AccurateSleep(std::chrono::nanoseconds duration) { bool AccurateSleep(const std::chrono::nanoseconds duration, std::chrono::nanoseconds* remaining,
const bool interruptible) {
const auto begin_sleep = std::chrono::high_resolution_clock::now();
LARGE_INTEGER interval{ LARGE_INTEGER interval{
.QuadPart = -1 * (duration.count() / 100u), .QuadPart = -1 * (duration.count() / 100u),
}; };
HANDLE timer = ::CreateWaitableTimer(NULL, TRUE, NULL); HANDLE timer = ::CreateWaitableTimer(NULL, TRUE, NULL);
SetWaitableTimer(timer, &interval, 0, NULL, NULL, 0); SetWaitableTimer(timer, &interval, 0, NULL, NULL, 0);
WaitForSingleObject(timer, INFINITE); const auto ret = WaitForSingleObjectEx(timer, INFINITE, interruptible);
::CloseHandle(timer); ::CloseHandle(timer);
if (remaining) {
const auto end_sleep = std::chrono::high_resolution_clock::now();
const auto sleep_time = end_sleep - begin_sleep;
*remaining = duration > sleep_time ? duration - sleep_time : std::chrono::nanoseconds(0);
}
return ret == WAIT_OBJECT_0;
} }
#else #else
@ -134,8 +145,24 @@ void SetCurrentThreadPriority(ThreadPriority new_priority) {
pthread_setschedparam(this_thread, scheduling_type, &params); pthread_setschedparam(this_thread, scheduling_type, &params);
} }
static void AccurateSleep(std::chrono::nanoseconds duration) { bool AccurateSleep(const std::chrono::nanoseconds duration, std::chrono::nanoseconds* remaining,
std::this_thread::sleep_for(duration); const bool interruptible) {
timespec request = {
.tv_sec = duration.count() / 1'000'000'000,
.tv_nsec = duration.count() % 1'000'000'000,
};
timespec remain;
int ret;
while ((ret = nanosleep(&request, &remain)) < 0 && errno == EINTR) {
if (interruptible) {
break;
}
request = remain;
}
if (remaining) {
*remaining = std::chrono::nanoseconds(remain.tv_sec * 1'000'000'000 + remain.tv_nsec);
}
return ret == 0 || errno != EINTR;
} }
#endif #endif
@ -196,9 +223,9 @@ AccurateTimer::AccurateTimer(std::chrono::nanoseconds target_interval)
: target_interval(target_interval) {} : target_interval(target_interval) {}
void AccurateTimer::Start() { void AccurateTimer::Start() {
auto begin_sleep = std::chrono::high_resolution_clock::now(); const auto begin_sleep = std::chrono::high_resolution_clock::now();
if (total_wait.count() > 0) { if (total_wait.count() > 0) {
AccurateSleep(total_wait); AccurateSleep(total_wait, nullptr, false);
} }
start_time = std::chrono::high_resolution_clock::now(); start_time = std::chrono::high_resolution_clock::now();
total_wait -= std::chrono::duration_cast<std::chrono::nanoseconds>(start_time - begin_sleep); total_wait -= std::chrono::duration_cast<std::chrono::nanoseconds>(start_time - begin_sleep);

View File

@ -25,6 +25,9 @@ void SetCurrentThreadName(const char* name);
void SetThreadName(void* thread, const char* name); void SetThreadName(void* thread, const char* name);
bool AccurateSleep(std::chrono::nanoseconds duration, std::chrono::nanoseconds* remaining,
bool interruptible);
class AccurateTimer { class AccurateTimer {
std::chrono::nanoseconds target_interval{}; std::chrono::nanoseconds target_interval{};
std::chrono::nanoseconds total_wait{}; std::chrono::nanoseconds total_wait{};

View File

@ -8,7 +8,7 @@
#define VA_ARGS \ #define VA_ARGS \
uint64_t rdi, uint64_t rsi, uint64_t rdx, uint64_t rcx, uint64_t r8, uint64_t r9, \ 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, \ 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) \ #define VA_CTX(ctx) \
alignas(16)::Common::VaCtx ctx{}; \ alignas(16)::Common::VaCtx ctx{}; \

View File

@ -19,8 +19,6 @@ enum class MemoryPermission : u32 {
}; };
DECLARE_ENUM_FLAG_OPERATORS(MemoryPermission) DECLARE_ENUM_FLAG_OPERATORS(MemoryPermission)
constexpr VAddr CODE_BASE_OFFSET = 0x100000000ULL;
constexpr VAddr SYSTEM_MANAGED_MIN = 0x00000400000ULL; constexpr VAddr SYSTEM_MANAGED_MIN = 0x00000400000ULL;
constexpr VAddr SYSTEM_MANAGED_MAX = 0x07FFFFBFFFULL; constexpr VAddr SYSTEM_MANAGED_MAX = 0x07FFFFBFFFULL;
constexpr VAddr SYSTEM_RESERVED_MIN = 0x07FFFFC000ULL; constexpr VAddr SYSTEM_RESERVED_MIN = 0x07FFFFC000ULL;

View File

@ -464,9 +464,8 @@ static std::pair<bool, u64> TryPatch(u8* code, PatchModule* module) {
if (needs_trampoline && instruction.length < 5) { if (needs_trampoline && instruction.length < 5) {
// Trampoline is needed but instruction is too short to patch. // Trampoline is needed but instruction is too short to patch.
// Return false and length to fall back to the illegal instruction handler, // Return false and length to signal to AOT compilation that this instruction
// or to signal to AOT compilation that this instruction should be skipped and // should be skipped and handled at runtime.
// handled at runtime.
return std::make_pair(false, instruction.length); return std::make_pair(false, instruction.length);
} }
@ -512,32 +511,58 @@ static std::pair<bool, u64> TryPatch(u8* code, PatchModule* module) {
#if defined(ARCH_X86_64) #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) { static bool TryExecuteIllegalInstruction(void* ctx, void* 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; ZydisDecodedInstruction instruction;
ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT]; ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT];
const auto status = const auto status =
Common::Decoder::Instance()->decodeInstruction(instruction, operands, code_address); Common::Decoder::Instance()->decodeInstruction(instruction, operands, code_address);
LOG_ERROR(Core, "Unhandled illegal instruction at code address {}: {}",
switch (instruction.mnemonic) { fmt::ptr(code_address),
case ZYDIS_MNEMONIC_EXTRQ: { ZYAN_SUCCESS(status) ? ZydisMnemonicGetString(instruction.mnemonic)
bool immediateForm = operands[1].type == ZYDIS_OPERAND_TYPE_IMMEDIATE && : "Failed to decode");
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; return false;
} 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; ASSERT(bytes[1] == 0x0F && bytes[2] == 0x79);
const auto srcIndex = operands[1].reg.value - ZYDIS_REGISTER_XMM0;
// 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: {
const auto dst = Common::GetXmmPointer(ctx, dstIndex); const auto dst = Common::GetXmmPointer(ctx, dstIndex);
const auto src = Common::GetXmmPointer(ctx, srcIndex); const auto src = Common::GetXmmPointer(ctx, srcIndex);
@ -571,32 +596,11 @@ static bool TryExecuteIllegalInstruction(void* ctx, void* code_address) {
memcpy(dst, &lowQWordDst, sizeof(lowQWordDst)); memcpy(dst, &lowQWordDst, sizeof(lowQWordDst));
Common::IncrementRip(ctx, instruction.length); Common::IncrementRip(ctx, 4);
return true; return true;
} }
break;
}
case ZYDIS_MNEMONIC_INSERTQ: { 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;
} 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 dst = Common::GetXmmPointer(ctx, dstIndex);
const auto src = Common::GetXmmPointer(ctx, srcIndex); const auto src = Common::GetXmmPointer(ctx, srcIndex);
@ -632,16 +636,12 @@ static bool TryExecuteIllegalInstruction(void* ctx, void* code_address) {
memcpy(dst, &lowQWordDst, sizeof(lowQWordDst)); memcpy(dst, &lowQWordDst, sizeof(lowQWordDst));
Common::IncrementRip(ctx, instruction.length); Common::IncrementRip(ctx, 4);
return true; return true;
} }
break;
}
default: { default: {
LOG_ERROR(Core, "Unhandled illegal instruction at code address {}: {}", UNREACHABLE();
fmt::ptr(code_address), ZydisMnemonicGetString(instruction.mnemonic));
return false;
} }
} }
@ -695,9 +695,22 @@ static bool PatchesAccessViolationHandler(void* context, void* /* fault_address
static bool PatchesIllegalInstructionHandler(void* context) { static bool PatchesIllegalInstructionHandler(void* context) {
void* code_address = Common::GetRip(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); 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; return true;
} }

View File

@ -40,6 +40,10 @@ public:
return ORBIS_KERNEL_ERROR_EBADF; 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) { virtual s64 lseek(s64 offset, int whence) {
return ORBIS_KERNEL_ERROR_EBADF; return ORBIS_KERNEL_ERROR_EBADF;
} }

View File

@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <cstdlib> #include <cstdlib>
#include <ctime>
#include "common/logging/log.h" #include "common/logging/log.h"
#include "random_device.h" #include "random_device.h"

View File

@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <cstdlib> #include <cstdlib>
#include <ctime>
#include "common/logging/log.h" #include "common/logging/log.h"
#include "srandom_device.h" #include "srandom_device.h"

View File

@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <cstdlib> #include <cstdlib>
#include <ctime>
#include "common/logging/log.h" #include "common/logging/log.h"
#include "urandom_device.h" #include "urandom_device.h"

View File

@ -1,11 +1,11 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "SDL3/SDL_log.h"
#include "layer.h" #include "layer.h"
#include <imgui.h> #include <imgui.h>
#include "SDL3/SDL_log.h"
#include "common/config.h" #include "common/config.h"
#include "common/singleton.h" #include "common/singleton.h"
#include "common/types.h" #include "common/types.h"
@ -17,6 +17,7 @@
#include "widget/frame_dump.h" #include "widget/frame_dump.h"
#include "widget/frame_graph.h" #include "widget/frame_graph.h"
#include "widget/memory_map.h" #include "widget/memory_map.h"
#include "widget/module_list.h"
#include "widget/shader_list.h" #include "widget/shader_list.h"
extern std::unique_ptr<Vulkan::Presenter> presenter; extern std::unique_ptr<Vulkan::Presenter> presenter;
@ -40,6 +41,7 @@ static bool just_opened_options = false;
static Widget::MemoryMapViewer memory_map; static Widget::MemoryMapViewer memory_map;
static Widget::ShaderList shader_list; static Widget::ShaderList shader_list;
static Widget::ModuleList module_list;
// clang-format off // clang-format off
static std::string help_text = static std::string help_text =
@ -108,6 +110,9 @@ void L::DrawMenuBar() {
if (MenuItem("Memory map")) { if (MenuItem("Memory map")) {
memory_map.open = true; memory_map.open = true;
} }
if (MenuItem("Module list")) {
module_list.open = true;
}
ImGui::EndMenu(); ImGui::EndMenu();
} }
@ -256,6 +261,9 @@ void L::DrawAdvanced() {
if (shader_list.open) { if (shader_list.open) {
shader_list.Draw(); shader_list.Draw();
} }
if (module_list.open) {
module_list.Draw();
}
} }
void L::DrawSimple() { void L::DrawSimple() {

View File

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

View File

@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <cstdio> #include <cstdio>
#include <ctime>
#include <fmt/chrono.h> #include <fmt/chrono.h>
#include <imgui.h> #include <imgui.h>
#include <magic_enum/magic_enum.hpp> #include <magic_enum/magic_enum.hpp>

View File

@ -0,0 +1,55 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "module_list.h"
#include <imgui.h>
#include "common.h"
#include "core/debug_state.h"
#include "imgui/imgui_std.h"
using namespace ImGui;
namespace Core::Devtools::Widget {
void ModuleList::Draw() {
SetNextWindowSize({550.0f, 600.0f}, ImGuiCond_FirstUseEver);
if (!Begin("Module List", &open)) {
End();
return;
}
if (BeginTable("ModuleTable", 3,
ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Sortable |
ImGuiTableFlags_RowBg)) {
TableSetupColumn("Modulname", ImGuiTableColumnFlags_WidthStretch);
TableHeadersRow();
std::scoped_lock lock(modules_mutex);
for (const auto& module : modules) {
TableNextRow();
TableSetColumnIndex(0);
TextUnformatted(module.name.c_str());
TableSetColumnIndex(1);
if (module.is_sys_module) {
TextColored({0.2f, 0.6f, 0.8f, 1.0f}, "System Module");
} else {
TextColored({0.8f, 0.4f, 0.2f, 1.0f}, "Game Module");
}
TableSetColumnIndex(2);
if (module.is_lle) {
TextColored({0.4f, 0.7f, 0.4f, 1.0f}, "LLE");
} else {
TextColored({0.7f, 0.4f, 0.5f, 1.0f}, "HLE");
}
}
EndTable();
}
End();
}
} // namespace Core::Devtools::Widget

View File

@ -0,0 +1,82 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <algorithm>
#include <filesystem>
#include <mutex>
#include <string>
#include <vector>
#include "common/elf_info.h"
#include "common/path_util.h"
namespace Core::Devtools::Widget {
class ModuleList {
public:
ModuleList() = default;
~ModuleList() = default;
void Draw();
bool open = false;
static bool IsSystemModule(const std::filesystem::path& path) {
const auto sys_modules_path = Common::FS::GetUserPath(Common::FS::PathType::SysModuleDir);
const auto abs_path = std::filesystem::absolute(path).lexically_normal();
const auto abs_sys_path = std::filesystem::absolute(sys_modules_path).lexically_normal();
const auto path_str = abs_path.string();
const auto sys_path_str = abs_sys_path.string();
return path_str.starts_with(sys_path_str);
}
static bool IsSystemModule(const std::string& name) {
const auto game_modules_path = Common::ElfInfo::Instance().GetGameFolder() / "sce_module";
const auto prx_path = game_modules_path / name;
if (!std::filesystem::exists(prx_path)) {
return true;
}
return false;
}
static void AddModule(const std::string& name, std::filesystem::path path) {
if (name == "eboot.bin") {
return;
}
std::scoped_lock lock(modules_mutex);
modules.push_back({name, IsSystemModule(path), true});
}
static void AddModule(std::string name) {
name = name + ".prx";
std::scoped_lock lock(modules_mutex);
bool is_sys_module = IsSystemModule(name);
bool is_lle = false;
auto it = std::find_if(modules.begin(), modules.end(),
[&name, is_sys_module, is_lle](const ModuleInfo& entry) {
return entry.name == name && !entry.is_lle;
});
if (it == modules.end()) {
modules.push_back({name, is_sys_module, is_lle});
}
}
private:
struct ModuleInfo {
std::string name;
bool is_sys_module;
bool is_lle;
};
static inline std::mutex modules_mutex;
static inline std::vector<ModuleInfo> modules;
};
} // namespace Core::Devtools::Widget

View 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

View 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

View 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;

View File

@ -0,0 +1,20 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
// companion_httpd error codes
constexpr int ORBIS_COMPANION_HTTPD_ERROR_UNKNOWN = 0x80E40001;
constexpr int ORBIS_COMPANION_HTTPD_ERROR_FATAL = 0x80E40002;
constexpr int ORBIS_COMPANION_HTTPD_ERROR_NOMEM = 0x80E40003;
constexpr int ORBIS_COMPANION_HTTPD_ERROR_INVALID_PARAM = 0x80E40004;
constexpr int ORBIS_COMPANION_HTTPD_ERROR_INVALID_OPERATION = 0x80E40005;
constexpr int ORBIS_COMPANION_HTTPD_ERROR_NOT_INITIALIZED = 0x80E40006;
constexpr int ORBIS_COMPANION_HTTPD_ERROR_ALREADY_INITIALIZED = 0x80E40007;
constexpr int ORBIS_COMPANION_HTTPD_ERROR_NO_EVENT = 0x80E40008;
constexpr int ORBIS_COMPANION_HTTPD_ERROR_NOT_GENERATE_RESPONSE = 0x80E40009;
constexpr int ORBIS_COMPANION_HTTPD_ERROR_ALREADY_STARTED = 0x80E4000A;
constexpr int ORBIS_COMPANION_HTTPD_ERROR_NOT_STARTED = 0x80E4000B;
constexpr int ORBIS_COMPANION_HTTPD_ERROR_ALREADY_REGISTERED = 0x80E4000;
constexpr int ORBIS_COMPANION_HTTPD_ERROR_NOT_CONNECTED = 0x80E4000D;
constexpr int ORBIS_COMPANION_HTTPD_ERROR_USER_NOT_FOUND = 0x80E4000E;

View File

@ -0,0 +1,142 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
#include "companion_error.h"
#include "core/libraries/companion/companion_httpd.h"
#include "core/libraries/error_codes.h"
#include "core/libraries/libs.h"
namespace Libraries::CompanionHttpd {
s32 PS4_SYSV_ABI sceCompanionHttpdAddHeader(const char* key, const char* value,
OrbisCompanionHttpdResponse* response) {
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI
sceCompanionHttpdGet2ndScreenStatus(Libraries::UserService::OrbisUserServiceUserId) {
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCompanionHttpdGetEvent(OrbisCompanionHttpdEvent* pEvent) {
pEvent->event = ORBIS_COMPANION_HTTPD_EVENT_DISCONNECT; // disconnected
LOG_DEBUG(Lib_CompanionHttpd, "device disconnected");
return ORBIS_COMPANION_HTTPD_ERROR_NO_EVENT; // No events to obtain
}
s32 PS4_SYSV_ABI
sceCompanionHttpdGetUserId(u32 addr, Libraries::UserService::OrbisUserServiceUserId* userId) {
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCompanionHttpdInitialize() {
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCompanionHttpdInitialize2() {
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCompanionHttpdOptParamInitialize() {
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCompanionHttpdRegisterRequestBodyReceptionCallback(
OrbisCompanionHttpdRequestBodyReceptionCallback function, void* param) {
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI
sceCompanionHttpdRegisterRequestCallback(OrbisCompanionHttpdRequestCallback function, void* param) {
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCompanionHttpdRegisterRequestCallback2(
OrbisCompanionHttpdRequestCallback function, void* param) {
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCompanionHttpdSetBody(const char* body, u64 bodySize,
OrbisCompanionHttpdResponse* response) {
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCompanionHttpdSetStatus(s32 status, OrbisCompanionHttpdResponse* response) {
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCompanionHttpdStart() {
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCompanionHttpdStop() {
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCompanionHttpdTerminate() {
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCompanionHttpdUnregisterRequestBodyReceptionCallback() {
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCompanionHttpdUnregisterRequestCallback() {
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
return ORBIS_OK;
}
void RegisterlibSceCompanionHttpd(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("8pWltDG7h6A", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
sceCompanionHttpdAddHeader);
LIB_FUNCTION("B-QBMeFdNgY", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
sceCompanionHttpdGet2ndScreenStatus);
LIB_FUNCTION("Vku4big+IYM", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
sceCompanionHttpdGetEvent);
LIB_FUNCTION("0SySxcuVNG0", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
sceCompanionHttpdGetUserId);
LIB_FUNCTION("ykNpWs3ktLY", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
sceCompanionHttpdInitialize);
LIB_FUNCTION("OA6FbORefbo", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
sceCompanionHttpdInitialize2);
LIB_FUNCTION("r-2-a0c7Kfc", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
sceCompanionHttpdOptParamInitialize);
LIB_FUNCTION("fHNmij7kAUM", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
sceCompanionHttpdRegisterRequestBodyReceptionCallback);
LIB_FUNCTION("OaWw+IVEdbI", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
sceCompanionHttpdRegisterRequestCallback);
LIB_FUNCTION("-0c9TCTwnGs", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
sceCompanionHttpdRegisterRequestCallback2);
LIB_FUNCTION("h3OvVxzX4qM", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
sceCompanionHttpdSetBody);
LIB_FUNCTION("w7oz0AWHpT4", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
sceCompanionHttpdSetStatus);
LIB_FUNCTION("k7F0FcDM-Xc", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
sceCompanionHttpdStart);
LIB_FUNCTION("0SCgzfVQHpo", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
sceCompanionHttpdStop);
LIB_FUNCTION("+-du9tWgE9s", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
sceCompanionHttpdTerminate);
LIB_FUNCTION("ZSHiUfYK+QI", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
sceCompanionHttpdUnregisterRequestBodyReceptionCallback);
LIB_FUNCTION("xweOi2QT-BE", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
sceCompanionHttpdUnregisterRequestCallback);
};
} // namespace Libraries::CompanionHttpd

View File

@ -0,0 +1,91 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/types.h"
#include "core/libraries/network/net.h"
#include "core/libraries/system/userservice.h"
namespace Core::Loader {
class SymbolsResolver;
}
namespace Libraries::CompanionHttpd {
// OrbisCompanionHttpdEvent event codes
constexpr int ORBIS_COMPANION_HTTPD_EVENT_CONNECT = 0x10000001;
constexpr int ORBIS_COMPANION_HTTPD_EVENT_DISCONNECT = 0x10000002;
struct OrbisCompanionHttpdHeader {
char* key;
char* value;
struct OrbisCompanionHttpdHeader* header;
};
struct OrbisCompanionHttpdRequest {
s32 method;
char* url;
OrbisCompanionHttpdHeader* header;
char* body;
u64 bodySize;
};
struct OrbisCompanionHttpdResponse {
s32 status;
OrbisCompanionHttpdHeader* header;
char* body;
u64 bodySize;
};
using OrbisCompanionHttpdRequestBodyReceptionCallback =
PS4_SYSV_ABI s32 (*)(s32 event, Libraries::UserService::OrbisUserServiceUserId userId,
const OrbisCompanionHttpdRequest* httpRequest, void* param);
using OrbisCompanionHttpdRequestCallback =
PS4_SYSV_ABI s32 (*)(Libraries::UserService::OrbisUserServiceUserId userId,
const OrbisCompanionHttpdRequest* httpRequest,
OrbisCompanionHttpdResponse* httpResponse, void* param);
struct OrbisCompanionUtilDeviceInfo {
Libraries::UserService::OrbisUserServiceUserId userId;
Libraries::Net::OrbisNetSockaddrIn addr;
char reserved[236];
};
struct OrbisCompanionHttpdEvent {
s32 event;
union {
OrbisCompanionUtilDeviceInfo deviceInfo;
Libraries::UserService::OrbisUserServiceUserId userId;
char reserved[256];
} data;
};
s32 PS4_SYSV_ABI sceCompanionHttpdAddHeader(const char* key, const char* value,
OrbisCompanionHttpdResponse* response);
s32 PS4_SYSV_ABI
sceCompanionHttpdGet2ndScreenStatus(Libraries::UserService::OrbisUserServiceUserId userId);
s32 PS4_SYSV_ABI sceCompanionHttpdGetEvent(OrbisCompanionHttpdEvent* pEvent);
s32 PS4_SYSV_ABI sceCompanionHttpdGetUserId(u32 addr,
Libraries::UserService::OrbisUserServiceUserId* userId);
s32 PS4_SYSV_ABI sceCompanionHttpdInitialize();
s32 PS4_SYSV_ABI sceCompanionHttpdInitialize2();
s32 PS4_SYSV_ABI sceCompanionHttpdOptParamInitialize();
s32 PS4_SYSV_ABI sceCompanionHttpdRegisterRequestBodyReceptionCallback(
OrbisCompanionHttpdRequestBodyReceptionCallback function, void* param);
s32 PS4_SYSV_ABI
sceCompanionHttpdRegisterRequestCallback(OrbisCompanionHttpdRequestCallback function, void* param);
s32 PS4_SYSV_ABI
sceCompanionHttpdRegisterRequestCallback2(OrbisCompanionHttpdRequestCallback function, void* param);
s32 PS4_SYSV_ABI sceCompanionHttpdSetBody(const char* body, u64 bodySize,
OrbisCompanionHttpdResponse* response);
s32 PS4_SYSV_ABI sceCompanionHttpdSetStatus(s32 status, OrbisCompanionHttpdResponse* response);
s32 PS4_SYSV_ABI sceCompanionHttpdStart();
s32 PS4_SYSV_ABI sceCompanionHttpdStop();
s32 PS4_SYSV_ABI sceCompanionHttpdTerminate();
s32 PS4_SYSV_ABI sceCompanionHttpdUnregisterRequestBodyReceptionCallback();
s32 PS4_SYSV_ABI sceCompanionHttpdUnregisterRequestCallback();
void RegisterlibSceCompanionHttpd(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::CompanionHttpd

View File

@ -179,7 +179,7 @@ s32 PS4_SYSV_ABI sceGnmComputeWaitOnAddress(u32* cmdbuf, u32 size, uintptr_t add
auto* wait_reg_mem = reinterpret_cast<PM4CmdWaitRegMem*>(cmdbuf); auto* wait_reg_mem = reinterpret_cast<PM4CmdWaitRegMem*>(cmdbuf);
wait_reg_mem->header = PM4Type3Header{PM4ItOpcode::WaitRegMem, 5}; wait_reg_mem->header = PM4Type3Header{PM4ItOpcode::WaitRegMem, 5};
wait_reg_mem->raw = (is_mem << 4u) | (cmp_func & 7u); 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->poll_addr_hi = u32(addr >> 32u);
wait_reg_mem->ref = ref; wait_reg_mem->ref = ref;
wait_reg_mem->mask = mask; wait_reg_mem->mask = mask;
@ -505,9 +505,10 @@ s32 PS4_SYSV_ABI sceGnmDrawIndexIndirectCountMulti(u32* cmdbuf, u32 size, u32 da
u32 flags) { u32 flags) {
LOG_TRACE(Lib_GnmDriver, "called"); LOG_TRACE(Lib_GnmDriver, "called");
if ((!sceKernelIsNeoMode() || !UseNeoCompatSequences) && !cmdbuf && (size == 16) && if ((!sceKernelIsNeoMode() || !UseNeoCompatSequences) && cmdbuf && (size == 16) &&
(shader_stage < ShaderStages::Max) && (vertex_sgpr_offset < 0x10u) && (vertex_sgpr_offset < 0x10u) && (instance_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 = WriteHeader<PM4ItOpcode::Nop>(cmdbuf, 2);
cmdbuf = WriteBody(cmdbuf, 0u); cmdbuf = WriteBody(cmdbuf, 0u);
@ -535,11 +536,34 @@ s32 PS4_SYSV_ABI sceGnmDrawIndexIndirectCountMulti(u32* cmdbuf, u32 size, u32 da
return -1; return -1;
} }
int PS4_SYSV_ABI sceGnmDrawIndexIndirectMulti() { int PS4_SYSV_ABI sceGnmDrawIndexIndirectMulti(u32* cmdbuf, u32 size, u32 data_offset, u32 max_count,
LOG_ERROR(Lib_GnmDriver, "(STUBBED) called"); u32 shader_stage, u32 vertex_sgpr_offset,
UNREACHABLE(); 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 ORBIS_OK;
} }
return -1;
}
int PS4_SYSV_ABI sceGnmDrawIndexMultiInstanced() { int PS4_SYSV_ABI sceGnmDrawIndexMultiInstanced() {
LOG_ERROR(Lib_GnmDriver, "(STUBBED) called"); LOG_ERROR(Lib_GnmDriver, "(STUBBED) called");

View File

@ -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 max_count, u64 count_addr, u32 shader_stage,
u32 vertex_sgpr_offset, u32 instance_sgpr_offset, u32 vertex_sgpr_offset, u32 instance_sgpr_offset,
u32 flags); 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(); int PS4_SYSV_ABI sceGnmDrawIndexMultiInstanced();
s32 PS4_SYSV_ABI sceGnmDrawIndexOffset(u32* cmdbuf, u32 size, u32 index_offset, u32 index_count, s32 PS4_SYSV_ABI sceGnmDrawIndexOffset(u32* cmdbuf, u32 size, u32 index_offset, u32 index_count,
u32 flags); u32 flags);

View File

@ -13,7 +13,7 @@ class SymbolsResolver;
namespace Libraries::ImeDialog { 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 { enum class Error : u32 {
OK = 0x0, OK = 0x0,

View File

@ -19,7 +19,7 @@ namespace Libraries::Kernel {
static s32* id_state; static s32* id_state;
static s32 id_index; static s32 id_index;
s32 sceKernelAioInitializeImpl(void* p, s32 size) { s32 PS4_SYSV_ABI sceKernelAioInitializeImpl(void* p, s32 size) {
return 0; return 0;
} }

View File

@ -12,12 +12,25 @@
namespace Libraries::Kernel { 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. // Events are uniquely identified by id and filter.
bool EqueueInternal::AddEvent(EqueueEvent& event) { bool EqueueInternal::AddEvent(EqueueEvent& event) {
std::scoped_lock lock{m_mutex}; std::scoped_lock lock{m_mutex};
event.time_added = std::chrono::steady_clock::now(); 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); const auto& it = std::ranges::find(m_events, event);
if (it != m_events.cend()) { if (it != m_events.cend()) {
@ -29,6 +42,47 @@ bool EqueueInternal::AddEvent(EqueueEvent& event) {
return true; 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 EqueueInternal::RemoveEvent(u64 id, s16 filter) {
bool has_found = false; bool has_found = false;
std::scoped_lock lock{m_mutex}; std::scoped_lock lock{m_mutex};
@ -152,18 +206,14 @@ int EqueueInternal::WaitForSmallTimer(SceKernelEvent* ev, int num, u32 micros) {
return count; return count;
} }
extern boost::asio::io_context io_context; bool EqueueInternal::EventExists(u64 id, s16 filter) {
extern void KernelSignalRequest(); 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, return it != m_events.cend();
SceKernelEvent kevent) {
static EqueueEvent event;
event.event = kevent;
event.event.data = HrTimerSpinlockThresholdUs;
eq->AddSmallTimer(event);
eq->TriggerEvent(kevent.ident, SceKernelEvent::Filter::HrTimer, kevent.udata);
} }
int PS4_SYSV_ABI sceKernelCreateEqueue(SceKernelEqueue* eq, const char* name) { 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; 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) { s32 PS4_SYSV_ABI sceKernelAddHRTimerEvent(SceKernelEqueue eq, int id, timespec* ts, void* udata) {
if (eq == nullptr) { if (eq == nullptr) {
return ORBIS_KERNEL_ERROR_EBADF; 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; return eq->AddSmallTimer(event) ? ORBIS_OK : ORBIS_KERNEL_ERROR_ENOMEM;
} }
event.timer = std::make_unique<boost::asio::steady_timer>( if (!eq->AddEvent(event) ||
io_context, std::chrono::microseconds(total_us - HrTimerSpinlockThresholdUs)); !eq->ScheduleEvent(id, SceKernelEvent::Filter::HrTimer, HrTimerCallback)) {
event.timer->async_wait(std::bind(SmallTimerCallback, std::placeholders::_1, eq, event.event));
if (!eq->AddEvent(event)) {
return ORBIS_KERNEL_ERROR_ENOMEM; return ORBIS_KERNEL_ERROR_ENOMEM;
} }
KernelSignalRequest();
return ORBIS_OK; 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) { int PS4_SYSV_ABI sceKernelAddUserEvent(SceKernelEqueue eq, int id) {
if (eq == nullptr) { if (eq == nullptr) {
return ORBIS_KERNEL_ERROR_EBADF; 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("WDszmSbWuDk", "libkernel", 1, "libkernel", 1, 1, sceKernelAddUserEventEdge);
LIB_FUNCTION("R74tt43xP6k", "libkernel", 1, "libkernel", 1, 1, sceKernelAddHRTimerEvent); LIB_FUNCTION("R74tt43xP6k", "libkernel", 1, "libkernel", 1, 1, sceKernelAddHRTimerEvent);
LIB_FUNCTION("J+LF6LwObXU", "libkernel", 1, "libkernel", 1, 1, sceKernelDeleteHRTimerEvent); 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("F6e0kwo4cnk", "libkernel", 1, "libkernel", 1, 1, sceKernelTriggerUserEvent);
LIB_FUNCTION("LJDwdSNTnDg", "libkernel", 1, "libkernel", 1, 1, sceKernelDeleteUserEvent); LIB_FUNCTION("LJDwdSNTnDg", "libkernel", 1, "libkernel", 1, 1, sceKernelDeleteUserEvent);
LIB_FUNCTION("mJ7aghmgvfc", "libkernel", 1, "libkernel", 1, 1, sceKernelGetEventId); LIB_FUNCTION("mJ7aghmgvfc", "libkernel", 1, "libkernel", 1, 1, sceKernelGetEventId);

View File

@ -21,6 +21,9 @@ namespace Libraries::Kernel {
class EqueueInternal; class EqueueInternal;
struct EqueueEvent; struct EqueueEvent;
using SceKernelUseconds = u32;
using SceKernelEqueue = EqueueInternal*;
struct SceKernelEvent { struct SceKernelEvent {
enum Filter : s16 { enum Filter : s16 {
None = 0, None = 0,
@ -61,10 +64,23 @@ struct SceKernelEvent {
void* udata = nullptr; /* opaque user data identifier */ 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 { struct EqueueEvent {
SceKernelEvent event; SceKernelEvent event;
void* data = nullptr; void* data = nullptr;
std::chrono::steady_clock::time_point time_added; std::chrono::steady_clock::time_point time_added;
std::chrono::microseconds timer_interval;
std::unique_ptr<boost::asio::steady_timer> timer; std::unique_ptr<boost::asio::steady_timer> timer;
void ResetTriggerState() { void ResetTriggerState() {
@ -84,19 +100,18 @@ struct EqueueEvent {
void TriggerDisplay(void* data) { void TriggerDisplay(void* data) {
is_triggered = true; is_triggered = true;
auto hint = reinterpret_cast<u64>(data); if (data != nullptr) {
if (hint != 0) { auto event_data = static_cast<OrbisVideoOutEventData>(event.data);
auto hint_h = static_cast<u32>(hint >> 8) & 0xFFFFFF; auto event_hint_raw = reinterpret_cast<u64>(data);
auto ident_h = static_cast<u32>(event.ident >> 40); auto event_hint = static_cast<OrbisVideoOutEventHint>(event_hint_raw);
if ((static_cast<u32>(hint) & 0xFF) == event.ident && event.ident != 0xFE && if (event_hint.event_id == event.ident && event.ident != 0xfe) {
((hint_h ^ ident_h) & 0xFF) == 0) {
auto time = Common::FencedRDTSC(); auto time = Common::FencedRDTSC();
auto mask = 0xF000; auto counter = event_data.count;
if ((static_cast<u32>(event.data) & 0xF000) != 0xF000) { if (counter != 0xf) {
mask = (static_cast<u32>(event.data) + 0x1000) & 0xF000; counter++;
} }
event.data = (mask | static_cast<u64>(static_cast<u32>(time) & 0xFFF) | event.data =
(hint & 0xFFFFFFFFFFFF0000)); (time & 0xfff) | (counter << 0xc) | (event_hint_raw & 0xffffffffffff0000);
} }
} }
} }
@ -122,6 +137,8 @@ public:
} }
bool AddEvent(EqueueEvent& event); bool AddEvent(EqueueEvent& event);
bool ScheduleEvent(u64 id, s16 filter,
void (*callback)(SceKernelEqueue, const SceKernelEvent&));
bool RemoveEvent(u64 id, s16 filter); bool RemoveEvent(u64 id, s16 filter);
int WaitForEvents(SceKernelEvent* ev, int num, u32 micros); int WaitForEvents(SceKernelEvent* ev, int num, u32 micros);
bool TriggerEvent(u64 ident, s16 filter, void* trigger_data); bool TriggerEvent(u64 ident, s16 filter, void* trigger_data);
@ -141,6 +158,8 @@ public:
int WaitForSmallTimer(SceKernelEvent* ev, int num, u32 micros); int WaitForSmallTimer(SceKernelEvent* ev, int num, u32 micros);
bool EventExists(u64 id, s16 filter);
private: private:
std::string m_name; std::string m_name;
std::mutex m_mutex; std::mutex m_mutex;
@ -149,9 +168,6 @@ private:
std::condition_variable m_cond; std::condition_variable m_cond;
}; };
using SceKernelUseconds = u32;
using SceKernelEqueue = EqueueInternal*;
u64 PS4_SYSV_ABI sceKernelGetEventData(const SceKernelEvent* ev); u64 PS4_SYSV_ABI sceKernelGetEventData(const SceKernelEvent* ev);
void RegisterEventQueue(Core::Loader::SymbolsResolver* sym); void RegisterEventQueue(Core::Loader::SymbolsResolver* sym);

View File

@ -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 write = (flags & 0x3) == ORBIS_KERNEL_O_WRONLY;
bool rdwr = (flags & 0x3) == ORBIS_KERNEL_O_RDWR; 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 nonblock = (flags & ORBIS_KERNEL_O_NONBLOCK) != 0;
bool append = (flags & ORBIS_KERNEL_O_APPEND) != 0; bool append = (flags & ORBIS_KERNEL_O_APPEND) != 0;
bool fsync = (flags & ORBIS_KERNEL_O_FSYNC) != 0; // Flags fsync and sync behave the same
bool sync = (flags & ORBIS_KERNEL_O_SYNC) != 0; bool sync = (flags & ORBIS_KERNEL_O_SYNC) != 0 || (flags & ORBIS_KERNEL_O_FSYNC) != 0;
bool create = (flags & ORBIS_KERNEL_O_CREAT) != 0; bool create = (flags & ORBIS_KERNEL_O_CREAT) != 0;
bool truncate = (flags & ORBIS_KERNEL_O_TRUNC) != 0; bool truncate = (flags & ORBIS_KERNEL_O_TRUNC) != 0;
bool excl = (flags & ORBIS_KERNEL_O_EXCL) != 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 direct = (flags & ORBIS_KERNEL_O_DIRECT) != 0;
bool directory = (flags & ORBIS_KERNEL_O_DIRECTORY) != 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}; std::string_view path{raw_path};
u32 handle = h->CreateHandle(); u32 handle = h->CreateHandle();
auto* file = h->GetFile(handle); auto* file = h->GetFile(handle);
@ -94,32 +104,11 @@ s32 PS4_SYSV_ABI open(const char* raw_path, s32 flags, u16 mode) {
} }
} }
if (directory) { bool read_only = false;
file->type = Core::FileSys::FileType::Directory;
file->m_guest_name = path; file->m_guest_name = path;
file->m_host_name = mnt->GetHostPath(file->m_guest_name); file->m_host_name = mnt->GetHostPath(file->m_guest_name, &read_only);
if (!std::filesystem::is_directory(file->m_host_name)) { // directory doesn't exist
h->DeleteHandle(handle);
*__Error() = POSIX_ENOENT;
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); bool exists = std::filesystem::exists(file->m_host_name);
int e = 0; s32 e = 0;
if (create) { if (create) {
if (excl && exists) { if (excl && exists) {
@ -128,42 +117,106 @@ s32 PS4_SYSV_ABI open(const char* raw_path, s32 flags, u16 mode) {
*__Error() = POSIX_EEXIST; *__Error() = POSIX_EEXIST;
return -1; return -1;
} }
// Create file if it doesn't exist
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); Common::FS::IOFile out(file->m_host_name, Common::FS::FileAccessMode::Write);
} else if (!exists) { } else if (!exists) {
// File to open doesn't exist, return ENOENT // If we're not creating a file, and it doesn't exist, return ENOENT
h->DeleteHandle(handle); h->DeleteHandle(handle);
*__Error() = POSIX_ENOENT; *__Error() = POSIX_ENOENT;
return -1; return -1;
} }
if (read) { if (std::filesystem::is_directory(file->m_host_name) || directory) {
// Read only // Directories can be opened even if the directory flag isn't set.
e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::Read); // In these cases, error behavior is identical to the directory code path.
} else if (write) { directory = true;
// 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);
} }
} else if (rdwr) {
// Read and write if (directory) {
if (append) { if (!std::filesystem::is_directory(file->m_host_name)) {
e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::Append); // If the opened file is not a directory, return ENOTDIR.
} else { // This will trigger when create & directory is specified, this is expected.
e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::ReadWrite); h->DeleteHandle(handle);
} *__Error() = POSIX_ENOTDIR;
} else {
// Invalid flags
*__Error() = POSIX_EINVAL;
return -1; return -1;
} }
if (truncate && e == 0) { file->type = Core::FileSys::FileType::Directory;
// If the file was opened successfully and truncate was enabled, reduce size to 0
// 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 {
file->type = Core::FileSys::FileType::Regular;
if (truncate && read_only) {
// Can't open files with truncate flag in a read only directory
h->DeleteHandle(handle);
*__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); 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
e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::Write);
} else if (rdwr) {
// Read and write
e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::ReadWrite);
}
}
if (e != 0) { if (e != 0) {
// Open failed in platform-specific code, errno needs to be converted. // Open failed in platform-specific code, errno needs to be converted.
@ -171,7 +224,7 @@ s32 PS4_SYSV_ABI open(const char* raw_path, s32 flags, u16 mode) {
SetPosixErrno(e); SetPosixErrno(e);
return -1; return -1;
} }
}
file->is_opened = true; file->is_opened = true;
return handle; return handle;
} }
@ -365,10 +418,10 @@ s64 PS4_SYSV_ABI posix_lseek(s32 fd, s64 offset, s32 whence) {
origin = Common::FS::SeekOrigin::CurrentPosition; origin = Common::FS::SeekOrigin::CurrentPosition;
} else if (whence == 2) { } else if (whence == 2) {
origin = Common::FS::SeekOrigin::End; origin = Common::FS::SeekOrigin::End;
} else if (whence == 3) { } else if (whence == 3 || whence == 4) {
origin = Common::FS::SeekOrigin::SeekHole; // whence parameter belongs to an unsupported POSIX extension
} else if (whence == 4) { *__Error() = POSIX_ENOTTY;
origin = Common::FS::SeekOrigin::SeekData; return -1;
} else { } else {
// whence parameter is invalid // whence parameter is invalid
*__Error() = POSIX_EINVAL; *__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); const std::filesystem::path dir_name = mnt->GetHostPath(path, &ro);
if (dir_name.empty() || !std::filesystem::is_directory(dir_name)) { if (ro) {
*__Error() = POSIX_ENOTDIR; *__Error() = POSIX_EROFS;
return -1; return -1;
} }
if (ro) { if (dir_name.empty() || !std::filesystem::is_directory(dir_name)) {
*__Error() = POSIX_EROFS; *__Error() = POSIX_ENOTDIR;
return -1; 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) { s32 PS4_SYSV_ABI posix_stat(const char* path, OrbisKernelStat* sb) {
LOG_INFO(Kernel_Fs, "(PARTIAL) path = {}", path); LOG_INFO(Kernel_Fs, "(PARTIAL) path = {}", path);
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance(); auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
bool ro = false; const auto path_name = mnt->GetHostPath(path);
const auto path_name = mnt->GetHostPath(path, &ro);
std::memset(sb, 0, sizeof(OrbisKernelStat)); std::memset(sb, 0, sizeof(OrbisKernelStat));
const bool is_dir = std::filesystem::is_directory(path_name); const bool is_dir = std::filesystem::is_directory(path_name);
const bool is_file = std::filesystem::is_regular_file(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; sb->st_blocks = (sb->st_size + 511) / 512;
// TODO incomplete // TODO incomplete
} }
if (ro) {
sb->st_mode &= ~0000555u;
}
return ORBIS_OK; return ORBIS_OK;
} }
@ -877,7 +926,7 @@ s32 PS4_SYSV_ABI sceKernelGetdirentries(s32 fd, char* buf, s32 nbytes, s64* base
return result; 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) { if (offset < 0) {
*__Error() = POSIX_EINVAL; *__Error() = POSIX_EINVAL;
return -1; 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}; std::scoped_lock lk{file->m_mutex};
if (file->type == Core::FileSys::FileType::Device) { 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) { if (result < 0) {
ErrSceToPosix(result); ErrSceToPosix(result);
return -1; return -1;
@ -908,7 +957,16 @@ s64 PS4_SYSV_ABI posix_pwrite(s32 fd, void* buf, size_t nbytes, s64 offset) {
*__Error() = POSIX_EIO; *__Error() = POSIX_EIO;
return -1; 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) { 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; 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) { s32 PS4_SYSV_ABI posix_unlink(const char* path) {
if (path == nullptr) { if (path == nullptr) {
*__Error() = POSIX_EINVAL; *__Error() = POSIX_EINVAL;
@ -1017,7 +1084,10 @@ void RegisterFileSystem(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("sfKygSjIbI8", "libkernel", 1, "libkernel", 1, 1, getdirentries); LIB_FUNCTION("sfKygSjIbI8", "libkernel", 1, "libkernel", 1, 1, getdirentries);
LIB_FUNCTION("taRWhTJFTgE", "libkernel", 1, "libkernel", 1, 1, sceKernelGetdirentries); LIB_FUNCTION("taRWhTJFTgE", "libkernel", 1, "libkernel", 1, 1, sceKernelGetdirentries);
LIB_FUNCTION("C2kJ-byS5rM", "libkernel", 1, "libkernel", 1, 1, posix_pwrite); 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("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); LIB_FUNCTION("AUXVxWeJU-A", "libkernel", 1, "libkernel", 1, 1, sceKernelUnlink);
} }

View File

@ -24,11 +24,16 @@
#include "core/libraries/kernel/threads/exception.h" #include "core/libraries/kernel/threads/exception.h"
#include "core/libraries/kernel/time.h" #include "core/libraries/kernel/time.h"
#include "core/libraries/libs.h" #include "core/libraries/libs.h"
#include "core/libraries/network/sys_net.h"
#ifdef _WIN64 #ifdef _WIN64
#include <Rpc.h> #include <Rpc.h>
#else
#include <uuid/uuid.h>
#endif #endif
#include <common/singleton.h> #include <common/singleton.h>
#include <core/libraries/network/net_error.h>
#include <core/libraries/network/sockets.h>
#include "aio.h" #include "aio.h"
namespace Libraries::Kernel { namespace Libraries::Kernel {
@ -103,6 +108,9 @@ void SetPosixErrno(int e) {
case EACCES: case EACCES:
g_posix_errno = POSIX_EACCES; g_posix_errno = POSIX_EACCES;
break; break;
case EFAULT:
g_posix_errno = POSIX_EFAULT;
break;
case EINVAL: case EINVAL:
g_posix_errno = POSIX_EINVAL; g_posix_errno = POSIX_EINVAL;
break; break;
@ -149,23 +157,23 @@ struct OrbisKernelUuid {
u8 clockSeqLow; u8 clockSeqLow;
u8 node[6]; u8 node[6];
}; };
static_assert(sizeof(OrbisKernelUuid) == 0x10);
int PS4_SYSV_ABI sceKernelUuidCreate(OrbisKernelUuid* orbisUuid) { int PS4_SYSV_ABI sceKernelUuidCreate(OrbisKernelUuid* orbisUuid) {
if (!orbisUuid) {
return ORBIS_KERNEL_ERROR_EINVAL;
}
#ifdef _WIN64 #ifdef _WIN64
UUID uuid; UUID uuid;
UuidCreate(&uuid); if (UuidCreate(&uuid) != RPC_S_OK) {
orbisUuid->timeLow = uuid.Data1; return ORBIS_KERNEL_ERROR_EFAULT;
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];
} }
#else #else
LOG_ERROR(Kernel, "sceKernelUuidCreate: Add linux"); uuid_t uuid;
uuid_generate(uuid);
#endif #endif
return 0; std::memcpy(orbisUuid, &uuid, sizeof(OrbisKernelUuid));
return ORBIS_OK;
} }
int PS4_SYSV_ABI kernel_ioctl(int fd, u64 cmd, VA_ARGS) { int PS4_SYSV_ABI kernel_ioctl(int fd, u64 cmd, VA_ARGS) {
@ -196,10 +204,6 @@ const char* PS4_SYSV_ABI sceKernelGetFsSandboxRandomWord() {
return path; return path;
} }
int PS4_SYSV_ABI posix_connect() {
return -1;
}
int PS4_SYSV_ABI _sigprocmask() { int PS4_SYSV_ABI _sigprocmask() {
return ORBIS_OK; return ORBIS_OK;
} }
@ -208,6 +212,24 @@ int PS4_SYSV_ABI posix_getpagesize() {
return 16_KB; 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) { void RegisterKernel(Core::Loader::SymbolsResolver* sym) {
service_thread = std::jthread{KernelServiceThread}; service_thread = std::jthread{KernelServiceThread};
@ -225,7 +247,6 @@ void RegisterKernel(Core::Loader::SymbolsResolver* sym) {
LIB_OBJ("f7uOxY9mM1U", "libkernel", 1, "libkernel", 1, 1, &g_stack_chk_guard); LIB_OBJ("f7uOxY9mM1U", "libkernel", 1, "libkernel", 1, 1, &g_stack_chk_guard);
LIB_FUNCTION("PfccT7qURYE", "libkernel", 1, "libkernel", 1, 1, kernel_ioctl); LIB_FUNCTION("PfccT7qURYE", "libkernel", 1, "libkernel", 1, 1, kernel_ioctl);
LIB_FUNCTION("JGfTMBOdUJo", "libkernel", 1, "libkernel", 1, 1, sceKernelGetFsSandboxRandomWord); 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("6xVpy0Fdq+I", "libkernel", 1, "libkernel", 1, 1, _sigprocmask);
LIB_FUNCTION("Xjoosiw+XPI", "libkernel", 1, "libkernel", 1, 1, sceKernelUuidCreate); LIB_FUNCTION("Xjoosiw+XPI", "libkernel", 1, "libkernel", 1, 1, sceKernelUuidCreate);
LIB_FUNCTION("Ou3iL1abvng", "libkernel", 1, "libkernel", 1, 1, stack_chk_fail); LIB_FUNCTION("Ou3iL1abvng", "libkernel", 1, "libkernel", 1, 1, stack_chk_fail);
@ -234,6 +255,24 @@ void RegisterKernel(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("k+AXqu2-eBc", "libScePosix", 1, "libkernel", 1, 1, posix_getpagesize); LIB_FUNCTION("k+AXqu2-eBc", "libScePosix", 1, "libkernel", 1, 1, posix_getpagesize);
LIB_FUNCTION("NWtTN10cJzE", "libSceLibcInternalExt", 1, "libSceLibcInternal", 1, 1, LIB_FUNCTION("NWtTN10cJzE", "libSceLibcInternalExt", 1, "libSceLibcInternal", 1, 1,
sceLibcHeapGetTraceInfo); 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 } // namespace Libraries::Kernel

View File

@ -3,9 +3,6 @@
#pragma once #pragma once
#include <algorithm>
#include <fmt/core.h>
#include "common/string_literal.h"
#include "common/types.h" #include "common/types.h"
#include "core/libraries/kernel/orbis_error.h" #include "core/libraries/kernel/orbis_error.h"
@ -18,27 +15,23 @@ namespace Libraries::Kernel {
void ErrSceToPosix(int result); void ErrSceToPosix(int result);
int ErrnoToSceKernelError(int e); int ErrnoToSceKernelError(int e);
void SetPosixErrno(int e); void SetPosixErrno(int e);
int* PS4_SYSV_ABI __Error();
template <StringLiteral name, class F, F f> template <class F, F f>
struct WrapperImpl; struct OrbisWrapperImpl;
template <StringLiteral name, class R, class... Args, PS4_SYSV_ABI R (*f)(Args...)> template <class R, class... Args, PS4_SYSV_ABI R (*f)(Args...)>
struct WrapperImpl<name, PS4_SYSV_ABI R (*)(Args...), f> { struct OrbisWrapperImpl<PS4_SYSV_ABI R (*)(Args...), f> {
static constexpr StringLiteral Name{name};
static R PS4_SYSV_ABI wrap(Args... args) { static R PS4_SYSV_ABI wrap(Args... args) {
u32 ret = f(args...); u32 ret = f(args...);
if (ret != 0) { if (ret != 0) {
// LOG_ERROR(Lib_Kernel, "Function {} returned {}", std::string_view{name.value}, ret);
ret += ORBIS_KERNEL_ERROR_UNKNOWN; ret += ORBIS_KERNEL_ERROR_UNKNOWN;
} }
return ret; return ret;
} }
}; };
template <StringLiteral name, class F, F f> #define ORBIS(func) (Libraries::Kernel::OrbisWrapperImpl<decltype(&(func)), func>::wrap)
constexpr auto OrbisWrapper = WrapperImpl<name, F, f>::wrap;
#define ORBIS(func) WrapperImpl<#func, decltype(&func), func>::wrap
int* PS4_SYSV_ABI __Error(); int* PS4_SYSV_ABI __Error();

View File

@ -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, s32 PS4_SYSV_ABI sceKernelVirtualQuery(const void* addr, int flags, OrbisVirtualQueryInfo* info,
size_t infoSize) { size_t infoSize) {
LOG_INFO(Kernel_Vmm, "called addr = {}, flags = {:#x}", fmt::ptr(addr), flags); LOG_INFO(Kernel_Vmm, "called addr = {}, flags = {:#x}", fmt::ptr(addr), flags);
if (!addr) {
return ORBIS_KERNEL_ERROR_EACCES;
}
auto* memory = Core::Memory::Instance(); auto* memory = Core::Memory::Instance();
return memory->VirtualQuery(std::bit_cast<VAddr>(addr), flags, info); 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) { s32 PS4_SYSV_ABI sceKernelReserveVirtualRange(void** addr, u64 len, int flags, u64 alignment) {
LOG_INFO(Kernel_Vmm, "addr = {}, len = {:#x}, flags = {:#x}, alignment = {:#x}", LOG_INFO(Kernel_Vmm, "addr = {}, len = {:#x}, flags = {:#x}, alignment = {:#x}",
fmt::ptr(*addr), len, flags, alignment); fmt::ptr(*addr), len, flags, alignment);
if (addr == nullptr) { if (addr == nullptr) {
LOG_ERROR(Kernel_Vmm, "Address is invalid!"); LOG_ERROR(Kernel_Vmm, "Address is invalid!");
return ORBIS_KERNEL_ERROR_EINVAL; 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(); auto* memory = Core::Memory::Instance();
const VAddr in_addr = reinterpret_cast<VAddr>(*addr); const VAddr in_addr = reinterpret_cast<VAddr>(*addr);
const auto map_flags = static_cast<Core::MemoryMapFlags>(flags); 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, 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!"); LOG_ERROR(Kernel_Vmm, "Map size is either zero or not 16KB aligned!");
return ORBIS_KERNEL_ERROR_EINVAL; return ORBIS_KERNEL_ERROR_EINVAL;
} }
if (!Common::Is16KBAligned(directMemoryStart)) { if (!Common::Is16KBAligned(directMemoryStart)) {
LOG_ERROR(Kernel_Vmm, "Start address is not 16KB aligned!"); LOG_ERROR(Kernel_Vmm, "Start address is not 16KB aligned!");
return ORBIS_KERNEL_ERROR_EINVAL; return ORBIS_KERNEL_ERROR_EINVAL;
} }
if (alignment != 0) { if (alignment != 0) {
if ((!std::has_single_bit(alignment) && !Common::Is16KBAligned(alignment))) { if ((!std::has_single_bit(alignment) && !Common::Is16KBAligned(alignment))) {
LOG_ERROR(Kernel_Vmm, "Alignment value is invalid!"); 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 VAddr in_addr = reinterpret_cast<VAddr>(*addr);
const auto mem_prot = static_cast<Core::MemoryProt>(prot); const auto mem_prot = static_cast<Core::MemoryProt>(prot);
const auto map_flags = static_cast<Core::MemoryMapFlags>(flags); const auto map_flags = static_cast<Core::MemoryMapFlags>(flags);
auto* memory = Core::Memory::Instance(); auto* memory = Core::Memory::Instance();
const auto ret = const auto ret =
memory->MapMemory(addr, in_addr, len, mem_prot, map_flags, Core::VMAType::Direct, "", false, memory->MapMemory(addr, in_addr, len, mem_prot, map_flags, Core::VMAType::Direct, name,
directMemoryStart, alignment); false, directMemoryStart, alignment);
LOG_INFO(Kernel_Vmm, "out_addr = {}", fmt::ptr(*addr)); LOG_INFO(Kernel_Vmm, "out_addr = {}", fmt::ptr(*addr));
return ret; return ret;
@ -199,7 +205,21 @@ 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, int PS4_SYSV_ABI sceKernelMapDirectMemory(void** addr, u64 len, int prot, int flags,
s64 directMemoryStart, u64 alignment) { s64 directMemoryStart, u64 alignment) {
LOG_INFO(Kernel_Vmm, "called, redirected to sceKernelMapNamedDirectMemory"); 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 sceKernelMapDirectMemory2(void** addr, u64 len, s32 type, s32 prot, s32 flags,
s64 phys_addr, u64 alignment) {
LOG_INFO(Kernel_Vmm, "called, redirected to sceKernelMapNamedDirectMemory");
const s32 ret =
sceKernelMapNamedDirectMemory(addr, len, prot, flags, phys_addr, alignment, "anon");
if (ret == 0) {
auto* memory = Core::Memory::Instance();
memory->SetDirectMemoryType(phys_addr, type);
}
return ret;
} }
s32 PS4_SYSV_ABI sceKernelMapNamedFlexibleMemory(void** addr_in_out, std::size_t len, int prot, s32 PS4_SYSV_ABI sceKernelMapNamedFlexibleMemory(void** addr_in_out, std::size_t len, int prot,
@ -210,17 +230,16 @@ s32 PS4_SYSV_ABI sceKernelMapNamedFlexibleMemory(void** addr_in_out, std::size_t
return ORBIS_KERNEL_ERROR_EINVAL; 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) { if (name == nullptr) {
LOG_ERROR(Kernel_Vmm, "name is invalid!"); LOG_ERROR(Kernel_Vmm, "name is invalid!");
return ORBIS_KERNEL_ERROR_EFAULT; 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 VAddr in_addr = reinterpret_cast<VAddr>(*addr_in_out);
const auto mem_prot = static_cast<Core::MemoryProt>(prot); const auto mem_prot = static_cast<Core::MemoryProt>(prot);
const auto map_flags = static_cast<Core::MemoryMapFlags>(flags); const auto map_flags = static_cast<Core::MemoryMapFlags>(flags);
@ -236,7 +255,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, s32 PS4_SYSV_ABI sceKernelMapFlexibleMemory(void** addr_in_out, std::size_t len, int prot,
int flags) { 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) { int PS4_SYSV_ABI sceKernelQueryMemoryProtection(void* addr, void** start, void** end, u32* prot) {
@ -284,6 +303,12 @@ int PS4_SYSV_ABI sceKernelGetDirectMemoryType(u64 addr, int* directMemoryTypeOut
directMemoryEndOut); directMemoryEndOut);
} }
int PS4_SYSV_ABI sceKernelIsStack(void* addr, void** start, void** end) {
LOG_DEBUG(Kernel_Vmm, "called, addr = {}", fmt::ptr(addr));
auto* memory = Core::Memory::Instance();
return memory->IsStack(std::bit_cast<VAddr>(addr), start, end);
}
s32 PS4_SYSV_ABI sceKernelBatchMap(OrbisKernelBatchMapEntry* entries, int numEntries, s32 PS4_SYSV_ABI sceKernelBatchMap(OrbisKernelBatchMapEntry* entries, int numEntries,
int* numEntriesOut) { int* numEntriesOut) {
return sceKernelBatchMap2(entries, numEntries, numEntriesOut, return sceKernelBatchMap2(entries, numEntries, numEntriesOut,
@ -304,7 +329,7 @@ s32 PS4_SYSV_ABI sceKernelBatchMap2(OrbisKernelBatchMapEntry* entries, int numEn
case MemoryOpTypes::ORBIS_KERNEL_MAP_OP_MAP_DIRECT: { case MemoryOpTypes::ORBIS_KERNEL_MAP_OP_MAP_DIRECT: {
result = sceKernelMapNamedDirectMemory(&entries[i].start, entries[i].length, result = sceKernelMapNamedDirectMemory(&entries[i].start, entries[i].length,
entries[i].protection, flags, entries[i].protection, flags,
static_cast<s64>(entries[i].offset), 0, ""); static_cast<s64>(entries[i].offset), 0, "anon");
LOG_INFO(Kernel_Vmm, LOG_INFO(Kernel_Vmm,
"entry = {}, operation = {}, len = {:#x}, offset = {:#x}, type = {}, " "entry = {}, operation = {}, len = {:#x}, offset = {:#x}, type = {}, "
"result = {}", "result = {}",
@ -326,7 +351,7 @@ s32 PS4_SYSV_ABI sceKernelBatchMap2(OrbisKernelBatchMapEntry* entries, int numEn
} }
case MemoryOpTypes::ORBIS_KERNEL_MAP_OP_MAP_FLEXIBLE: { case MemoryOpTypes::ORBIS_KERNEL_MAP_OP_MAP_FLEXIBLE: {
result = sceKernelMapNamedFlexibleMemory(&entries[i].start, entries[i].length, result = sceKernelMapNamedFlexibleMemory(&entries[i].start, entries[i].length,
entries[i].protection, flags, ""); entries[i].protection, flags, "anon");
LOG_INFO(Kernel_Vmm, LOG_INFO(Kernel_Vmm,
"entry = {}, operation = {}, len = {:#x}, type = {}, " "entry = {}, operation = {}, len = {:#x}, type = {}, "
"result = {}", "result = {}",
@ -356,16 +381,16 @@ s32 PS4_SYSV_ABI sceKernelBatchMap2(OrbisKernelBatchMapEntry* entries, int numEn
} }
s32 PS4_SYSV_ABI sceKernelSetVirtualRangeName(const void* addr, size_t len, const char* name) { 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) { if (name == nullptr) {
LOG_ERROR(Kernel_Vmm, "name is invalid!"); LOG_ERROR(Kernel_Vmm, "name is invalid!");
return ORBIS_KERNEL_ERROR_EFAULT; 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(); auto* memory = Core::Memory::Instance();
memory->NameVirtualRange(std::bit_cast<VAddr>(addr), len, name); memory->NameVirtualRange(std::bit_cast<VAddr>(addr), len, name);
return ORBIS_OK; return ORBIS_OK;
@ -377,13 +402,12 @@ s32 PS4_SYSV_ABI sceKernelMemoryPoolExpand(u64 searchStart, u64 searchEnd, size_
LOG_ERROR(Kernel_Vmm, "Provided address range is invalid!"); LOG_ERROR(Kernel_Vmm, "Provided address range is invalid!");
return ORBIS_KERNEL_ERROR_EINVAL; return ORBIS_KERNEL_ERROR_EINVAL;
} }
const bool is_in_range = searchEnd - searchStart >= len; if (len <= 0 || !Common::Is64KBAligned(len)) {
if (len <= 0 || !Common::Is64KBAligned(len) || !is_in_range) { LOG_ERROR(Kernel_Vmm, "Provided length {:#x} is invalid!", len);
LOG_ERROR(Kernel_Vmm, "Provided address range is invalid!");
return ORBIS_KERNEL_ERROR_EINVAL; return ORBIS_KERNEL_ERROR_EINVAL;
} }
if (alignment != 0 && !Common::Is64KBAligned(alignment)) { 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; return ORBIS_KERNEL_ERROR_EINVAL;
} }
if (physAddrOut == nullptr) { if (physAddrOut == nullptr) {
@ -391,8 +415,21 @@ s32 PS4_SYSV_ABI sceKernelMemoryPoolExpand(u64 searchStart, u64 searchEnd, size_
return ORBIS_KERNEL_ERROR_EINVAL; 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(); auto* memory = Core::Memory::Instance();
PAddr phys_addr = memory->PoolExpand(searchStart, searchEnd, len, alignment); PAddr phys_addr = memory->PoolExpand(searchStart, searchEnd, len, alignment);
if (phys_addr == -1) {
return ORBIS_KERNEL_ERROR_ENOMEM;
}
*physAddrOut = static_cast<s64>(phys_addr); *physAddrOut = static_cast<s64>(phys_addr);
LOG_INFO(Kernel_Vmm, LOG_INFO(Kernel_Vmm,
@ -407,10 +444,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}", LOG_INFO(Kernel_Vmm, "addrIn = {}, len = {:#x}, alignment = {:#x}, flags = {:#x}",
fmt::ptr(addrIn), len, alignment, flags); 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)) { if (len == 0 || !Common::Is2MBAligned(len)) {
LOG_ERROR(Kernel_Vmm, "Map size is either zero or not 2MB aligned!"); LOG_ERROR(Kernel_Vmm, "Map size is either zero or not 2MB aligned!");
return ORBIS_KERNEL_ERROR_EINVAL; return ORBIS_KERNEL_ERROR_EINVAL;
@ -463,9 +496,61 @@ s32 PS4_SYSV_ABI sceKernelMemoryPoolDecommit(void* addr, size_t len, int flags)
const VAddr pool_addr = reinterpret_cast<VAddr>(addr); const VAddr pool_addr = reinterpret_cast<VAddr>(addr);
auto* memory = Core::Memory::Instance(); 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, int PS4_SYSV_ABI sceKernelMmap(void* addr, u64 len, int prot, int flags, int fd, size_t offset,
@ -570,8 +655,10 @@ void RegisterMemory(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("7oxv3PPCumo", "libkernel", 1, "libkernel", 1, 1, sceKernelReserveVirtualRange); LIB_FUNCTION("7oxv3PPCumo", "libkernel", 1, "libkernel", 1, 1, sceKernelReserveVirtualRange);
LIB_FUNCTION("BC+OG5m9+bw", "libkernel", 1, "libkernel", 1, 1, sceKernelGetDirectMemoryType); LIB_FUNCTION("BC+OG5m9+bw", "libkernel", 1, "libkernel", 1, 1, sceKernelGetDirectMemoryType);
LIB_FUNCTION("pO96TwzOm5E", "libkernel", 1, "libkernel", 1, 1, sceKernelGetDirectMemorySize); 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("NcaWUxfMNIQ", "libkernel", 1, "libkernel", 1, 1, sceKernelMapNamedDirectMemory);
LIB_FUNCTION("L-Q3LEjIbgA", "libkernel", 1, "libkernel", 1, 1, sceKernelMapDirectMemory); LIB_FUNCTION("L-Q3LEjIbgA", "libkernel", 1, "libkernel", 1, 1, sceKernelMapDirectMemory);
LIB_FUNCTION("BQQniolj9tQ", "libkernel", 1, "libkernel", 1, 1, sceKernelMapDirectMemory2);
LIB_FUNCTION("WFcfL2lzido", "libkernel", 1, "libkernel", 1, 1, sceKernelQueryMemoryProtection); LIB_FUNCTION("WFcfL2lzido", "libkernel", 1, "libkernel", 1, 1, sceKernelQueryMemoryProtection);
LIB_FUNCTION("BHouLQzh0X0", "libkernel", 1, "libkernel", 1, 1, sceKernelDirectMemoryQuery); LIB_FUNCTION("BHouLQzh0X0", "libkernel", 1, "libkernel", 1, 1, sceKernelDirectMemoryQuery);
LIB_FUNCTION("MBuItvba6z8", "libkernel", 1, "libkernel", 1, 1, sceKernelReleaseDirectMemory); LIB_FUNCTION("MBuItvba6z8", "libkernel", 1, "libkernel", 1, 1, sceKernelReleaseDirectMemory);
@ -599,6 +686,7 @@ void RegisterMemory(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("pU-QydtGcGY", "libkernel", 1, "libkernel", 1, 1, sceKernelMemoryPoolReserve); LIB_FUNCTION("pU-QydtGcGY", "libkernel", 1, "libkernel", 1, 1, sceKernelMemoryPoolReserve);
LIB_FUNCTION("Vzl66WmfLvk", "libkernel", 1, "libkernel", 1, 1, sceKernelMemoryPoolCommit); LIB_FUNCTION("Vzl66WmfLvk", "libkernel", 1, "libkernel", 1, 1, sceKernelMemoryPoolCommit);
LIB_FUNCTION("LXo1tpFqJGs", "libkernel", 1, "libkernel", 1, 1, sceKernelMemoryPoolDecommit); 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", "libkernel", 1, "libkernel", 1, 1, posix_mmap);
LIB_FUNCTION("BPE9s9vQQXo", "libScePosix", 1, "libkernel", 1, 1, posix_mmap); LIB_FUNCTION("BPE9s9vQQXo", "libScePosix", 1, "libkernel", 1, 1, posix_mmap);

View File

@ -47,6 +47,8 @@ enum MemoryOpTypes : u32 {
ORBIS_KERNEL_MAP_OP_TYPE_PROTECT = 4 ORBIS_KERNEL_MAP_OP_TYPE_PROTECT = 4
}; };
constexpr u32 ORBIS_KERNEL_MAXIMUM_NAME_LENGTH = 32;
struct OrbisQueryInfo { struct OrbisQueryInfo {
uintptr_t start; uintptr_t start;
uintptr_t end; uintptr_t end;
@ -59,15 +61,15 @@ struct OrbisVirtualQueryInfo {
size_t offset; size_t offset;
s32 protection; s32 protection;
s32 memory_type; s32 memory_type;
union { u8 is_flexible : 1;
BitField<0, 1, u32> is_flexible; u8 is_direct : 1;
BitField<1, 1, u32> is_direct; u8 is_stack : 1;
BitField<2, 1, u32> is_stack; u8 is_pooled : 1;
BitField<3, 1, u32> is_pooled; u8 is_committed : 1;
BitField<4, 1, u32> is_committed; char name[ORBIS_KERNEL_MAXIMUM_NAME_LENGTH];
};
std::array<char, 32> name;
}; };
static_assert(sizeof(OrbisVirtualQueryInfo) == 72,
"OrbisVirtualQueryInfo struct size is incorrect");
struct OrbisKernelBatchMapEntry { struct OrbisKernelBatchMapEntry {
void* start; void* start;
@ -79,6 +81,48 @@ struct OrbisKernelBatchMapEntry {
int operation; 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(); u64 PS4_SYSV_ABI sceKernelGetDirectMemorySize();
int PS4_SYSV_ABI sceKernelAllocateDirectMemory(s64 searchStart, s64 searchEnd, u64 len, int PS4_SYSV_ABI sceKernelAllocateDirectMemory(s64 searchStart, s64 searchEnd, u64 len,
u64 alignment, int memoryType, s64* physAddrOut); 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, int PS4_SYSV_ABI sceKernelGetDirectMemoryType(u64 addr, int* directMemoryTypeOut,
void** directMemoryStartOut, void** directMemoryStartOut,
void** directMemoryEndOut); void** directMemoryEndOut);
int PS4_SYSV_ABI sceKernelIsStack(void* addr, void** start, void** end);
s32 PS4_SYSV_ABI sceKernelBatchMap(OrbisKernelBatchMapEntry* entries, int numEntries, s32 PS4_SYSV_ABI sceKernelBatchMap(OrbisKernelBatchMapEntry* entries, int numEntries,
int* numEntriesOut); int* numEntriesOut);
@ -128,6 +173,8 @@ s32 PS4_SYSV_ABI sceKernelMemoryPoolReserve(void* addrIn, size_t len, size_t ali
void** addrOut); void** addrOut);
s32 PS4_SYSV_ABI sceKernelMemoryPoolCommit(void* addr, size_t len, int type, int prot, int flags); 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 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); int PS4_SYSV_ABI sceKernelMunmap(void* addr, size_t len);

View File

@ -127,6 +127,62 @@ int PS4_SYSV_ABI sceKernelGetModuleInfoFromAddr(VAddr addr, int flags,
return ORBIS_OK; 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) { s32 PS4_SYSV_ABI exit(s32 status) {
UNREACHABLE_MSG("Exiting with status code {}", status); UNREACHABLE_MSG("Exiting with status code {}", status);
return 0; return 0;
@ -141,6 +197,9 @@ void RegisterProcess(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("LwG8g3niqwA", "libkernel", 1, "libkernel", 1, 1, sceKernelDlsym); LIB_FUNCTION("LwG8g3niqwA", "libkernel", 1, "libkernel", 1, 1, sceKernelDlsym);
LIB_FUNCTION("RpQJJVKTiFM", "libkernel", 1, "libkernel", 1, 1, sceKernelGetModuleInfoForUnwind); LIB_FUNCTION("RpQJJVKTiFM", "libkernel", 1, "libkernel", 1, 1, sceKernelGetModuleInfoForUnwind);
LIB_FUNCTION("f7KBOafysXo", "libkernel", 1, "libkernel", 1, 1, sceKernelGetModuleInfoFromAddr); 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); LIB_FUNCTION("6Z83sYWFlA8", "libkernel", 1, "libkernel", 1, 1, exit);
} }

View File

@ -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_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, int PS4_SYSV_ABI posix_pthread_create(PthreadT* thread, const PthreadAttrT* attr,
PthreadEntryFunc start_routine, void* arg); PthreadEntryFunc start_routine, void* arg);
@ -35,7 +41,7 @@ public:
this->func = std::move(func); this->func = std::move(func);
PthreadAttrT attr{}; PthreadAttrT attr{};
posix_pthread_attr_init(&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); posix_pthread_attr_destroy(&attr);
} }

View File

@ -315,7 +315,7 @@ int PS4_SYSV_ABI sceKernelPollEventFlag(OrbisKernelEventFlag ef, u64 bitPattern,
auto result = ef->Poll(bitPattern, wait, clear, pResultPat); auto result = ef->Poll(bitPattern, wait, clear, pResultPat);
if (result != ORBIS_OK && result != ORBIS_KERNEL_ERROR_EBUSY) { if (result != ORBIS_OK && result != ORBIS_KERNEL_ERROR_EBUSY) {
LOG_ERROR(Kernel_Event, "returned {}", result); LOG_DEBUG(Kernel_Event, "returned {:#x}", result);
} }
return 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); u32 result = ef->Wait(bitPattern, wait, clear, pResultPat, pTimeout);
if (result != ORBIS_OK && result != ORBIS_KERNEL_ERROR_ETIMEDOUT) { 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; return result;

View File

@ -6,6 +6,7 @@
#include "core/debug_state.h" #include "core/debug_state.h"
#include "core/libraries/kernel/kernel.h" #include "core/libraries/kernel/kernel.h"
#include "core/libraries/kernel/posix_error.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/pthread.h"
#include "core/libraries/kernel/threads/thread_state.h" #include "core/libraries/kernel/threads/thread_state.h"
#include "core/libraries/libs.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 */ /* Create thread */
new_thread->native_thr = Core::NativeThread(); new_thread->native_thr = Core::NativeThread();
int ret = new_thread->native_thr.Create(RunThread, new_thread, &new_thread->attr); int ret = new_thread->native_thr.Create(RunThread, new_thread, &new_thread->attr);
ASSERT_MSG(ret == 0, "Failed to create thread with error {}", ret); 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) { if (ret) {
*thread = nullptr; *thread = nullptr;
} }
@ -521,6 +527,85 @@ int PS4_SYSV_ABI posix_pthread_setcancelstate(PthreadCancelState state,
return 0; 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) { void RegisterThread(Core::Loader::SymbolsResolver* sym) {
// Posix // Posix
LIB_FUNCTION("Z4QosVuAsA0", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_once); 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("Z4QosVuAsA0", "libkernel", 1, "libkernel", 1, 1, posix_pthread_once);
LIB_FUNCTION("EotR8a3ASf4", "libkernel", 1, "libkernel", 1, 1, posix_pthread_self); 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("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 // Orbis
LIB_FUNCTION("14bOACANTBo", "libkernel", 1, "libkernel", 1, 1, ORBIS(posix_pthread_once)); 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("W0Hpm2X0uPE", "libkernel", 1, "libkernel", 1, 1, ORBIS(posix_pthread_setprio));
LIB_FUNCTION("rNhWz+lvOMU", "libkernel", 1, "libkernel", 1, 1, _sceKernelSetThreadDtors); LIB_FUNCTION("rNhWz+lvOMU", "libkernel", 1, "libkernel", 1, 1, _sceKernelSetThreadDtors);
LIB_FUNCTION("6XG4B33N09g", "libkernel", 1, "libkernel", 1, 1, sched_yield); 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 } // namespace Libraries::Kernel

View File

@ -159,6 +159,7 @@ enum class SchedPolicy : u32 {
struct Cpuset { struct Cpuset {
u64 bits; u64 bits;
u64 _reserved;
}; };
struct PthreadAttr { struct PthreadAttr {
@ -269,7 +270,7 @@ struct Pthread {
bool no_cancel; bool no_cancel;
bool cancel_async; bool cancel_async;
bool cancelling; bool cancelling;
Cpuset sigmask; u64 sigmask;
bool unblock_sigcancel; bool unblock_sigcancel;
bool in_sigsuspend; bool in_sigsuspend;
bool force_exit; bool force_exit;
@ -332,6 +333,8 @@ struct Pthread {
return true; return true;
} }
} }
int SetAffinity(const Cpuset* cpuset);
}; };
using PthreadT = Pthread*; using PthreadT = Pthread*;

View File

@ -243,7 +243,7 @@ int PS4_SYSV_ABI posix_pthread_attr_getaffinity_np(const PthreadAttrT* pattr, si
if (attr->cpuset != nullptr) if (attr->cpuset != nullptr)
memcpy(cpusetp, attr->cpuset, std::min(cpusetsize, attr->cpusetsize)); memcpy(cpusetp, attr->cpuset, std::min(cpusetsize, attr->cpusetsize));
else else
memset(cpusetp, -1, sizeof(Cpuset)); memset(cpusetp, -1, cpusetsize);
return 0; 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 (cpusetsize == 0 || cpusetp == nullptr) {
if (attr->cpuset != nullptr) { if (attr->cpuset != nullptr) {
free(attr->cpuset); free(attr->cpuset);
attr->cpuset = NULL; attr->cpuset = nullptr;
attr->cpusetsize = 0; attr->cpusetsize = 0;
} }
return 0; return 0;
} }
if (attr->cpuset == nullptr) { if (attr->cpuset == nullptr) {
attr->cpuset = (Cpuset*)calloc(1, sizeof(Cpuset)); attr->cpuset = static_cast<Cpuset*>(calloc(1, sizeof(Cpuset)));
attr->cpusetsize = sizeof(Cpuset); attr->cpusetsize = sizeof(Cpuset);
} }
memcpy(attr->cpuset, cpusetp, sizeof(Cpuset)); memcpy(attr->cpuset, cpusetp, std::min(cpusetsize, sizeof(Cpuset)));
return 0; return 0;
} }
int PS4_SYSV_ABI scePthreadAttrGetaffinity(PthreadAttrT* param_1, Cpuset* mask) { int PS4_SYSV_ABI scePthreadAttrGetaffinity(PthreadAttrT* attr, u64* mask) {
Cpuset cpuset; 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) { if (ret == 0) {
*mask = cpuset; *mask = cpuset.bits;
} }
return ret; return ret;
} }
int PS4_SYSV_ABI scePthreadAttrSetaffinity(PthreadAttrT* attr, const Cpuset mask) { int PS4_SYSV_ABI scePthreadAttrSetaffinity(PthreadAttrT* attr, const u64 mask) {
return posix_pthread_attr_setaffinity_np(attr, 0x10, &mask); const Cpuset cpuset = {.bits = mask};
return posix_pthread_attr_setaffinity_np(attr, sizeof(Cpuset), &cpuset);
} }
void RegisterThreadAttr(Core::Loader::SymbolsResolver* sym) { void RegisterThreadAttr(Core::Loader::SymbolsResolver* sym) {

View File

@ -5,24 +5,23 @@
#include "common/assert.h" #include "common/assert.h"
#include "common/native_clock.h" #include "common/native_clock.h"
#include "common/thread.h"
#include "core/libraries/kernel/kernel.h" #include "core/libraries/kernel/kernel.h"
#include "core/libraries/kernel/orbis_error.h" #include "core/libraries/kernel/orbis_error.h"
#include "core/libraries/kernel/posix_error.h"
#include "core/libraries/kernel/time.h" #include "core/libraries/kernel/time.h"
#include "core/libraries/libs.h" #include "core/libraries/libs.h"
#ifdef _WIN64 #ifdef _WIN64
#include <pthread_time.h>
#include <windows.h> #include <windows.h>
#include "common/ntapi.h" #include "common/ntapi.h"
#else #else
#if __APPLE__ #if __APPLE__
#include <date/tz.h> #include <date/tz.h>
#endif #endif
#include <ctime>
#include <sys/resource.h> #include <sys/resource.h>
#include <sys/time.h> #include <sys/time.h>
#include <time.h>
#include <unistd.h> #include <unistd.h>
#endif #endif
@ -52,88 +51,116 @@ u64 PS4_SYSV_ABI sceKernelReadTsc() {
return clock->GetUptime(); return clock->GetUptime();
} }
int PS4_SYSV_ABI sceKernelUsleep(u32 microseconds) { static s32 posix_nanosleep_impl(const OrbisKernelTimespec* rqtp, OrbisKernelTimespec* rmtp,
#ifdef _WIN64 const bool interruptible) {
const auto start_time = std::chrono::high_resolution_clock::now(); if (!rqtp || rqtp->tv_sec < 0 || rqtp->tv_nsec < 0 || rqtp->tv_nsec >= 1'000'000'000) {
auto total_wait_time = std::chrono::microseconds(microseconds); SetPosixErrno(EINVAL);
return -1;
while (total_wait_time.count() > 0) {
auto wait_time = std::chrono::ceil<std::chrono::milliseconds>(total_wait_time).count();
u64 res = SleepEx(static_cast<u64>(wait_time), true);
if (res == WAIT_IO_COMPLETION) {
auto elapsedTime = std::chrono::high_resolution_clock::now() - start_time;
auto elapsedMicroseconds =
std::chrono::duration_cast<std::chrono::microseconds>(elapsedTime).count();
total_wait_time = std::chrono::microseconds(microseconds - elapsedMicroseconds);
} else {
break;
} }
const auto duration = std::chrono::nanoseconds(rqtp->tv_sec * 1'000'000'000 + rqtp->tv_nsec);
std::chrono::nanoseconds remain;
const auto uninterrupted = Common::AccurateSleep(duration, &remain, interruptible);
if (rmtp) {
rmtp->tv_sec = remain.count() / 1'000'000'000;
rmtp->tv_nsec = remain.count() % 1'000'000'000;
} }
if (!uninterrupted) {
return 0; SetPosixErrno(EINTR);
#else return -1;
timespec start;
timespec remain;
start.tv_sec = microseconds / 1000000;
start.tv_nsec = (microseconds % 1000000) * 1000;
timespec* requested = &start;
int ret = 0;
do {
ret = nanosleep(requested, &remain);
requested = &remain;
} while (ret != 0);
return ret;
#endif
} }
int PS4_SYSV_ABI posix_usleep(u32 microseconds) {
return sceKernelUsleep(microseconds);
}
u32 PS4_SYSV_ABI sceKernelSleep(u32 seconds) {
std::this_thread::sleep_for(std::chrono::seconds(seconds));
return 0; return 0;
} }
#ifdef _WIN64 s32 PS4_SYSV_ABI posix_nanosleep(const OrbisKernelTimespec* rqtp, OrbisKernelTimespec* rmtp) {
#ifndef CLOCK_REALTIME return posix_nanosleep_impl(rqtp, rmtp, true);
#define CLOCK_REALTIME 0
#endif
#ifndef CLOCK_MONOTONIC
#define CLOCK_MONOTONIC 1
#endif
#ifndef CLOCK_PROCESS_CPUTIME_ID
#define CLOCK_PROCESS_CPUTIME_ID 2
#endif
#ifndef CLOCK_THREAD_CPUTIME_ID
#define CLOCK_THREAD_CPUTIME_ID 3
#endif
#ifndef CLOCK_REALTIME_COARSE
#define CLOCK_REALTIME_COARSE 5
#endif
#ifndef CLOCK_MONOTONIC_COARSE
#define CLOCK_MONOTONIC_COARSE 6
#endif
#define DELTA_EPOCH_IN_100NS 116444736000000000ULL
static u64 FileTimeTo100Ns(FILETIME& ft) {
return *reinterpret_cast<u64*>(&ft);
} }
static s32 clock_gettime(u32 clock_id, struct timespec* ts) { s32 PS4_SYSV_ABI sceKernelNanosleep(const OrbisKernelTimespec* rqtp, OrbisKernelTimespec* rmtp) {
if (const auto ret = posix_nanosleep_impl(rqtp, rmtp, false); ret < 0) {
return ErrnoToSceKernelError(*__Error());
}
return ORBIS_OK;
}
s32 PS4_SYSV_ABI posix_usleep(u32 microseconds) {
const OrbisKernelTimespec ts = {
.tv_sec = microseconds / 1'000'000,
.tv_nsec = (microseconds % 1'000'000) * 1'000,
};
return posix_nanosleep(&ts, nullptr);
}
s32 PS4_SYSV_ABI sceKernelUsleep(u32 microseconds) {
const OrbisKernelTimespec ts = {
.tv_sec = microseconds / 1'000'000,
.tv_nsec = (microseconds % 1'000'000) * 1'000,
};
return sceKernelNanosleep(&ts, nullptr);
}
u32 PS4_SYSV_ABI posix_sleep(u32 seconds) {
const OrbisKernelTimespec ts = {
.tv_sec = seconds,
.tv_nsec = 0,
};
OrbisKernelTimespec rm;
if (const auto ret = posix_nanosleep(&ts, &rm); ret < 0) {
return *__Error() == POSIX_EINTR ? rm.tv_sec + (rm.tv_nsec == 0 ? 0 : 1) : seconds;
}
return 0;
}
s32 PS4_SYSV_ABI sceKernelSleep(u32 seconds) {
return sceKernelUsleep(seconds * 1'000'000);
}
s32 PS4_SYSV_ABI posix_clock_gettime(u32 clock_id, OrbisKernelTimespec* ts) {
if (ts == nullptr) {
SetPosixErrno(EFAULT);
return -1;
}
if (clock_id == ORBIS_CLOCK_PROCTIME) {
const auto us = sceKernelGetProcessTime();
ts->tv_sec = static_cast<s64>(us / 1'000'000);
ts->tv_nsec = static_cast<s64>((us % 1'000'000) * 1000);
return 0;
}
if (clock_id == ORBIS_CLOCK_EXT_NETWORK || clock_id == ORBIS_CLOCK_EXT_DEBUG_NETWORK ||
clock_id == ORBIS_CLOCK_EXT_AD_NETWORK || clock_id == ORBIS_CLOCK_EXT_RAW_NETWORK) {
LOG_ERROR(Lib_Kernel, "Unsupported clock type {}, using CLOCK_MONOTONIC", clock_id);
clock_id = ORBIS_CLOCK_MONOTONIC;
}
#ifdef _WIN32
static const auto FileTimeTo100Ns = [](FILETIME& ft) { return *reinterpret_cast<u64*>(&ft); };
switch (clock_id) { switch (clock_id) {
case CLOCK_REALTIME: case ORBIS_CLOCK_REALTIME:
case CLOCK_REALTIME_COARSE: { case ORBIS_CLOCK_REALTIME_PRECISE: {
FILETIME ft; FILETIME ft;
GetSystemTimeAsFileTime(&ft); GetSystemTimePreciseAsFileTime(&ft);
const u64 ns = FileTimeTo100Ns(ft) - DELTA_EPOCH_IN_100NS; static constexpr u64 DeltaEpochIn100ns = 116444736000000000ULL;
const u64 ns = FileTimeTo100Ns(ft) - DeltaEpochIn100ns;
ts->tv_sec = ns / 10'000'000; ts->tv_sec = ns / 10'000'000;
ts->tv_nsec = (ns % 10'000'000) * 100; ts->tv_nsec = (ns % 10'000'000) * 100;
return 0; return 0;
} }
case CLOCK_MONOTONIC: case ORBIS_CLOCK_SECOND:
case CLOCK_MONOTONIC_COARSE: { case ORBIS_CLOCK_REALTIME_FAST: {
FILETIME ft;
GetSystemTimeAsFileTime(&ft);
static constexpr u64 DeltaEpochIn100ns = 116444736000000000ULL;
const u64 ns = FileTimeTo100Ns(ft) - DeltaEpochIn100ns;
ts->tv_sec = ns / 10'000'000;
ts->tv_nsec = (ns % 10'000'000) * 100;
return 0;
}
case ORBIS_CLOCK_UPTIME:
case ORBIS_CLOCK_UPTIME_PRECISE:
case ORBIS_CLOCK_MONOTONIC:
case ORBIS_CLOCK_MONOTONIC_PRECISE:
case ORBIS_CLOCK_UPTIME_FAST:
case ORBIS_CLOCK_MONOTONIC_FAST: {
static LARGE_INTEGER pf = [] { static LARGE_INTEGER pf = [] {
LARGE_INTEGER res{}; LARGE_INTEGER res{};
QueryPerformanceFrequency(&pf); QueryPerformanceFrequency(&pf);
@ -141,43 +168,53 @@ static s32 clock_gettime(u32 clock_id, struct timespec* ts) {
}(); }();
LARGE_INTEGER pc{}; LARGE_INTEGER pc{};
QueryPerformanceCounter(&pc); if (!QueryPerformanceCounter(&pc)) {
SetPosixErrno(EFAULT);
return -1;
}
ts->tv_sec = pc.QuadPart / pf.QuadPart; ts->tv_sec = pc.QuadPart / pf.QuadPart;
ts->tv_nsec = ((pc.QuadPart % pf.QuadPart) * 1000'000'000) / pf.QuadPart; ts->tv_nsec = ((pc.QuadPart % pf.QuadPart) * 1000'000'000) / pf.QuadPart;
return 0; return 0;
} }
case CLOCK_PROCESS_CPUTIME_ID: { case ORBIS_CLOCK_THREAD_CPUTIME_ID: {
FILETIME ct, et, kt, ut; FILETIME ct, et, kt, ut;
if (!GetProcessTimes(GetCurrentProcess(), &ct, &et, &kt, &ut)) { if (!GetThreadTimes(GetCurrentThread(), &ct, &et, &kt, &ut)) {
return EFAULT; SetPosixErrno(EFAULT);
return -1;
} }
const u64 ns = FileTimeTo100Ns(ut) + FileTimeTo100Ns(kt); const u64 ns = FileTimeTo100Ns(ut) + FileTimeTo100Ns(kt);
ts->tv_sec = ns / 10'000'000; ts->tv_sec = ns / 10'000'000;
ts->tv_nsec = (ns % 10'000'000) * 100; ts->tv_nsec = (ns % 10'000'000) * 100;
return 0; return 0;
} }
case CLOCK_THREAD_CPUTIME_ID: { case ORBIS_CLOCK_VIRTUAL: {
FILETIME ct, et, kt, ut; FILETIME ct, et, kt, ut;
if (!GetThreadTimes(GetCurrentThread(), &ct, &et, &kt, &ut)) { if (!GetProcessTimes(GetCurrentProcess(), &ct, &et, &kt, &ut)) {
return EFAULT; SetPosixErrno(EFAULT);
return -1;
} }
const u64 ns = FileTimeTo100Ns(ut) + FileTimeTo100Ns(kt); const u64 ns = FileTimeTo100Ns(ut);
ts->tv_sec = ns / 10'000'000;
ts->tv_nsec = (ns % 10'000'000) * 100;
return 0;
}
case ORBIS_CLOCK_PROF: {
FILETIME ct, et, kt, ut;
if (!GetProcessTimes(GetCurrentProcess(), &ct, &et, &kt, &ut)) {
SetPosixErrno(EFAULT);
return -1;
}
const u64 ns = FileTimeTo100Ns(kt);
ts->tv_sec = ns / 10'000'000; ts->tv_sec = ns / 10'000'000;
ts->tv_nsec = (ns % 10'000'000) * 100; ts->tv_nsec = (ns % 10'000'000) * 100;
return 0; return 0;
} }
default: default:
return EINVAL; SetPosixErrno(EFAULT);
return -1;
} }
} #else
#endif clockid_t pclock_id;
int PS4_SYSV_ABI orbis_clock_gettime(s32 clock_id, struct OrbisKernelTimespec* ts) {
if (ts == nullptr) {
return ORBIS_KERNEL_ERROR_EFAULT;
}
clockid_t pclock_id = CLOCK_MONOTONIC;
switch (clock_id) { switch (clock_id) {
case ORBIS_CLOCK_REALTIME: case ORBIS_CLOCK_REALTIME:
case ORBIS_CLOCK_REALTIME_PRECISE: case ORBIS_CLOCK_REALTIME_PRECISE:
@ -185,7 +222,7 @@ int PS4_SYSV_ABI orbis_clock_gettime(s32 clock_id, struct OrbisKernelTimespec* t
break; break;
case ORBIS_CLOCK_SECOND: case ORBIS_CLOCK_SECOND:
case ORBIS_CLOCK_REALTIME_FAST: case ORBIS_CLOCK_REALTIME_FAST:
#ifndef __APPLE__ #ifdef CLOCK_REALTIME_COARSE
pclock_id = CLOCK_REALTIME_COARSE; pclock_id = CLOCK_REALTIME_COARSE;
#else #else
pclock_id = CLOCK_REALTIME; pclock_id = CLOCK_REALTIME;
@ -199,7 +236,7 @@ int PS4_SYSV_ABI orbis_clock_gettime(s32 clock_id, struct OrbisKernelTimespec* t
break; break;
case ORBIS_CLOCK_UPTIME_FAST: case ORBIS_CLOCK_UPTIME_FAST:
case ORBIS_CLOCK_MONOTONIC_FAST: case ORBIS_CLOCK_MONOTONIC_FAST:
#ifndef __APPLE__ #ifdef CLOCK_MONOTONIC_COARSE
pclock_id = CLOCK_MONOTONIC_COARSE; pclock_id = CLOCK_MONOTONIC_COARSE;
#else #else
pclock_id = CLOCK_MONOTONIC; pclock_id = CLOCK_MONOTONIC;
@ -208,102 +245,155 @@ int PS4_SYSV_ABI orbis_clock_gettime(s32 clock_id, struct OrbisKernelTimespec* t
case ORBIS_CLOCK_THREAD_CPUTIME_ID: case ORBIS_CLOCK_THREAD_CPUTIME_ID:
pclock_id = CLOCK_THREAD_CPUTIME_ID; pclock_id = CLOCK_THREAD_CPUTIME_ID;
break; break;
case ORBIS_CLOCK_PROCTIME: {
const auto us = sceKernelGetProcessTime();
ts->tv_sec = us / 1'000'000;
ts->tv_nsec = (us % 1'000'000) * 1000;
return 0;
}
case ORBIS_CLOCK_VIRTUAL: { case ORBIS_CLOCK_VIRTUAL: {
#ifdef _WIN64 rusage ru;
FILETIME ct, et, kt, ut;
if (!GetProcessTimes(GetCurrentProcess(), &ct, &et, &kt, &ut)) {
return EFAULT;
}
const u64 ns = FileTimeTo100Ns(ut);
ts->tv_sec = ns / 10'000'000;
ts->tv_nsec = (ns % 10'000'000) * 100;
#else
struct rusage ru;
const auto res = getrusage(RUSAGE_SELF, &ru); const auto res = getrusage(RUSAGE_SELF, &ru);
if (res < 0) { if (res < 0) {
return res; SetPosixErrno(EFAULT);
return -1;
} }
ts->tv_sec = ru.ru_utime.tv_sec; ts->tv_sec = ru.ru_utime.tv_sec;
ts->tv_nsec = ru.ru_utime.tv_usec * 1000; ts->tv_nsec = ru.ru_utime.tv_usec * 1000;
#endif
return 0; return 0;
} }
case ORBIS_CLOCK_PROF: { case ORBIS_CLOCK_PROF: {
#ifdef _WIN64 rusage ru;
FILETIME ct, et, kt, ut;
if (!GetProcessTimes(GetCurrentProcess(), &ct, &et, &kt, &ut)) {
return EFAULT;
}
const u64 ns = FileTimeTo100Ns(kt);
ts->tv_sec = ns / 10'000'000;
ts->tv_nsec = (ns % 10'000'000) * 100;
#else
struct rusage ru;
const auto res = getrusage(RUSAGE_SELF, &ru); const auto res = getrusage(RUSAGE_SELF, &ru);
if (res < 0) { if (res < 0) {
return res; SetPosixErrno(EFAULT);
return -1;
} }
ts->tv_sec = ru.ru_stime.tv_sec; ts->tv_sec = ru.ru_stime.tv_sec;
ts->tv_nsec = ru.ru_stime.tv_usec * 1000; ts->tv_nsec = ru.ru_stime.tv_usec * 1000;
#endif
return 0; return 0;
} }
case ORBIS_CLOCK_EXT_NETWORK:
case ORBIS_CLOCK_EXT_DEBUG_NETWORK:
case ORBIS_CLOCK_EXT_AD_NETWORK:
case ORBIS_CLOCK_EXT_RAW_NETWORK:
pclock_id = CLOCK_MONOTONIC;
LOG_ERROR(Lib_Kernel, "unsupported = {} using CLOCK_MONOTONIC", clock_id);
break;
default: default:
return EINVAL; SetPosixErrno(EFAULT);
return -1;
} }
timespec t{}; timespec t{};
int result = clock_gettime(pclock_id, &t); const auto result = clock_gettime(pclock_id, &t);
ts->tv_sec = t.tv_sec; ts->tv_sec = t.tv_sec;
ts->tv_nsec = t.tv_nsec; ts->tv_nsec = t.tv_nsec;
return result; if (result < 0) {
SetPosixErrno(errno);
return -1;
}
return 0;
#endif
} }
int PS4_SYSV_ABI sceKernelClockGettime(s32 clock_id, OrbisKernelTimespec* tp) { s32 PS4_SYSV_ABI sceKernelClockGettime(const u32 clock_id, OrbisKernelTimespec* ts) {
const auto res = orbis_clock_gettime(clock_id, tp); if (const auto ret = posix_clock_gettime(clock_id, ts); ret < 0) {
if (res < 0) { return ErrnoToSceKernelError(*__Error());
return ErrnoToSceKernelError(res);
} }
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI posix_nanosleep(const OrbisKernelTimespec* rqtp, OrbisKernelTimespec* rmtp) { s32 PS4_SYSV_ABI posix_clock_getres(u32 clock_id, OrbisKernelTimespec* res) {
const auto* request = reinterpret_cast<const timespec*>(rqtp); if (res == nullptr) {
auto* remain = reinterpret_cast<timespec*>(rmtp); SetPosixErrno(EFAULT);
return nanosleep(request, remain); return -1;
} }
int PS4_SYSV_ABI sceKernelNanosleep(const OrbisKernelTimespec* rqtp, OrbisKernelTimespec* rmtp) { if (clock_id == ORBIS_CLOCK_EXT_NETWORK || clock_id == ORBIS_CLOCK_EXT_DEBUG_NETWORK ||
if (!rqtp || !rmtp) { clock_id == ORBIS_CLOCK_EXT_AD_NETWORK || clock_id == ORBIS_CLOCK_EXT_RAW_NETWORK) {
return ORBIS_KERNEL_ERROR_EFAULT; LOG_ERROR(Lib_Kernel, "Unsupported clock type {}, using CLOCK_MONOTONIC", clock_id);
clock_id = ORBIS_CLOCK_MONOTONIC;
} }
if (rqtp->tv_sec < 0 || rqtp->tv_nsec < 0) { #ifdef _WIN32
return ORBIS_KERNEL_ERROR_EINVAL; switch (clock_id) {
case ORBIS_CLOCK_SECOND:
case ORBIS_CLOCK_REALTIME_FAST: {
DWORD timeAdjustment;
DWORD timeIncrement;
BOOL isTimeAdjustmentDisabled;
if (!GetSystemTimeAdjustment(&timeAdjustment, &timeIncrement, &isTimeAdjustmentDisabled)) {
SetPosixErrno(EFAULT);
return -1;
}
res->tv_sec = 0;
res->tv_nsec = timeIncrement * 100;
return 0;
}
case ORBIS_CLOCK_REALTIME:
case ORBIS_CLOCK_REALTIME_PRECISE:
case ORBIS_CLOCK_UPTIME:
case ORBIS_CLOCK_UPTIME_PRECISE:
case ORBIS_CLOCK_MONOTONIC:
case ORBIS_CLOCK_MONOTONIC_PRECISE:
case ORBIS_CLOCK_UPTIME_FAST:
case ORBIS_CLOCK_MONOTONIC_FAST: {
LARGE_INTEGER pf;
if (!QueryPerformanceFrequency(&pf)) {
SetPosixErrno(EFAULT);
return -1;
}
res->tv_sec = 0;
res->tv_nsec =
std::max(static_cast<s32>((1000000000 + (pf.QuadPart >> 1)) / pf.QuadPart), 1);
return 0;
}
default:
UNREACHABLE();
}
#else
clockid_t pclock_id;
switch (clock_id) {
case ORBIS_CLOCK_REALTIME:
case ORBIS_CLOCK_REALTIME_PRECISE:
pclock_id = CLOCK_REALTIME;
break;
case ORBIS_CLOCK_SECOND:
case ORBIS_CLOCK_REALTIME_FAST:
#ifdef CLOCK_REALTIME_COARSE
pclock_id = CLOCK_REALTIME_COARSE;
#else
pclock_id = CLOCK_REALTIME;
#endif
break;
case ORBIS_CLOCK_UPTIME:
case ORBIS_CLOCK_UPTIME_PRECISE:
case ORBIS_CLOCK_MONOTONIC:
case ORBIS_CLOCK_MONOTONIC_PRECISE:
pclock_id = CLOCK_MONOTONIC;
break;
case ORBIS_CLOCK_UPTIME_FAST:
case ORBIS_CLOCK_MONOTONIC_FAST:
#ifdef CLOCK_MONOTONIC_COARSE
pclock_id = CLOCK_MONOTONIC_COARSE;
#else
pclock_id = CLOCK_MONOTONIC;
#endif
break;
default:
UNREACHABLE();
} }
return posix_nanosleep(rqtp, rmtp); timespec t{};
const auto result = clock_getres(pclock_id, &t);
res->tv_sec = t.tv_sec;
res->tv_nsec = t.tv_nsec;
if (result < 0) {
SetPosixErrno(errno);
return -1;
}
return 0;
#endif
} }
int PS4_SYSV_ABI sceKernelGettimeofday(OrbisKernelTimeval* tp) { s32 PS4_SYSV_ABI sceKernelClockGetres(const u32 clock_id, OrbisKernelTimespec* res) {
if (!tp) { if (const auto ret = posix_clock_getres(clock_id, res); ret < 0) {
return ORBIS_KERNEL_ERROR_EFAULT; return ErrnoToSceKernelError(*__Error());
}
return ORBIS_OK;
} }
s32 PS4_SYSV_ABI posix_gettimeofday(OrbisKernelTimeval* tp, OrbisKernelTimezone* tz) {
#ifdef _WIN64 #ifdef _WIN64
if (tp) {
FILETIME filetime; FILETIME filetime;
GetSystemTimePreciseAsFileTime(&filetime); GetSystemTimePreciseAsFileTime(&filetime);
@ -318,28 +408,8 @@ int PS4_SYSV_ABI sceKernelGettimeofday(OrbisKernelTimeval* tp) {
tp->tv_sec = ticks / TICKS_PER_SECOND; tp->tv_sec = ticks / TICKS_PER_SECOND;
tp->tv_usec = ticks % TICKS_PER_SECOND; tp->tv_usec = ticks % TICKS_PER_SECOND;
#else
timeval tv;
gettimeofday(&tv, nullptr);
tp->tv_sec = tv.tv_sec;
tp->tv_usec = tv.tv_usec;
#endif
return ORBIS_OK;
} }
int PS4_SYSV_ABI gettimeofday(OrbisKernelTimeval* tp, OrbisKernelTimezone* tz) {
// FreeBSD docs mention that the kernel generally does not track these values
// and they are usually returned as zero.
if (tz) { if (tz) {
tz->tz_minuteswest = 0;
tz->tz_dsttime = 0;
}
return sceKernelGettimeofday(tp);
}
s32 PS4_SYSV_ABI sceKernelGettimezone(OrbisKernelTimezone* tz) {
#ifdef _WIN64
ASSERT(tz);
static int tzflag = 0; static int tzflag = 0;
if (!tzflag) { if (!tzflag) {
_tzset(); _tzset();
@ -347,57 +417,54 @@ s32 PS4_SYSV_ABI sceKernelGettimezone(OrbisKernelTimezone* tz) {
} }
tz->tz_minuteswest = _timezone / 60; tz->tz_minuteswest = _timezone / 60;
tz->tz_dsttime = _daylight; tz->tz_dsttime = _daylight;
}
return 0;
#else #else
struct timezone tzz; struct timezone tzz;
struct timeval tv; timeval tv;
gettimeofday(&tv, &tzz); const auto ret = gettimeofday(&tv, &tzz);
if (tp) {
tp->tv_sec = tv.tv_sec;
tp->tv_usec = tv.tv_usec;
}
if (tz) {
tz->tz_dsttime = tzz.tz_dsttime; tz->tz_dsttime = tzz.tz_dsttime;
tz->tz_minuteswest = tzz.tz_minuteswest; tz->tz_minuteswest = tzz.tz_minuteswest;
}
if (ret < 0) {
SetPosixErrno(errno);
return -1;
}
return 0;
#endif #endif
}
s32 PS4_SYSV_ABI sceKernelGettimeofday(OrbisKernelTimeval* tp) {
if (const auto ret = posix_gettimeofday(tp, nullptr); ret < 0) {
return ErrnoToSceKernelError(*__Error());
}
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI posix_clock_getres(u32 clock_id, OrbisKernelTimespec* res) { s32 PS4_SYSV_ABI sceKernelGettimezone(OrbisKernelTimezone* tz) {
if (res == nullptr) { if (const auto ret = posix_gettimeofday(nullptr, tz); ret < 0) {
return ORBIS_KERNEL_ERROR_EFAULT; return ErrnoToSceKernelError(*__Error());
} }
clockid_t pclock_id = CLOCK_REALTIME;
switch (clock_id) {
case ORBIS_CLOCK_REALTIME:
case ORBIS_CLOCK_REALTIME_PRECISE:
case ORBIS_CLOCK_REALTIME_FAST:
pclock_id = CLOCK_REALTIME;
break;
case ORBIS_CLOCK_SECOND:
case ORBIS_CLOCK_MONOTONIC:
case ORBIS_CLOCK_MONOTONIC_PRECISE:
case ORBIS_CLOCK_MONOTONIC_FAST:
pclock_id = CLOCK_MONOTONIC;
break;
default:
UNREACHABLE();
}
timespec t{};
int result = clock_getres(pclock_id, &t);
res->tv_sec = t.tv_sec;
res->tv_nsec = t.tv_nsec;
if (result == 0) {
return ORBIS_OK; return ORBIS_OK;
} }
return ORBIS_KERNEL_ERROR_EINVAL;
}
int PS4_SYSV_ABI sceKernelConvertLocaltimeToUtc(time_t param_1, int64_t param_2, time_t* seconds, s32 PS4_SYSV_ABI sceKernelConvertLocaltimeToUtc(time_t param_1, int64_t param_2, time_t* seconds,
OrbisKernelTimezone* timezone, int* dst_seconds) { OrbisKernelTimezone* timezone, s32* dst_seconds) {
LOG_INFO(Kernel, "called"); LOG_INFO(Kernel, "called");
if (timezone) { if (timezone) {
sceKernelGettimezone(timezone); sceKernelGettimezone(timezone);
param_1 -= (timezone->tz_minuteswest + timezone->tz_dsttime) * 60; param_1 -= (timezone->tz_minuteswest + timezone->tz_dsttime) * 60;
if (seconds) if (seconds) {
*seconds = param_1; *seconds = param_1;
if (dst_seconds) }
if (dst_seconds) {
*dst_seconds = timezone->tz_dsttime * 60; *dst_seconds = timezone->tz_dsttime * 60;
}
} else { } else {
return ORBIS_KERNEL_ERROR_EINVAL; return ORBIS_KERNEL_ERROR_EINVAL;
} }
@ -415,7 +482,7 @@ Common::NativeClock* GetClock() {
} // namespace Dev } // namespace Dev
int PS4_SYSV_ABI sceKernelConvertUtcToLocaltime(time_t time, time_t* local_time, s32 PS4_SYSV_ABI sceKernelConvertUtcToLocaltime(time_t time, time_t* local_time,
struct OrbisTimesec* st, u64* dst_sec) { struct OrbisTimesec* st, u64* dst_sec) {
LOG_TRACE(Kernel, "Called"); LOG_TRACE(Kernel, "Called");
#ifdef __APPLE__ #ifdef __APPLE__
@ -444,28 +511,35 @@ int PS4_SYSV_ABI sceKernelConvertUtcToLocaltime(time_t time, time_t* local_time,
void RegisterTime(Core::Loader::SymbolsResolver* sym) { void RegisterTime(Core::Loader::SymbolsResolver* sym) {
clock = std::make_unique<Common::NativeClock>(); clock = std::make_unique<Common::NativeClock>();
initial_ptc = clock->GetUptime(); initial_ptc = clock->GetUptime();
// POSIX
LIB_FUNCTION("yS8U2TGCe1A", "libkernel", 1, "libkernel", 1, 1, posix_nanosleep);
LIB_FUNCTION("yS8U2TGCe1A", "libScePosix", 1, "libkernel", 1, 1, posix_nanosleep);
LIB_FUNCTION("QcteRwbsnV0", "libkernel", 1, "libkernel", 1, 1, posix_usleep);
LIB_FUNCTION("QcteRwbsnV0", "libScePosix", 1, "libkernel", 1, 1, posix_usleep);
LIB_FUNCTION("0wu33hunNdE", "libkernel", 1, "libkernel", 1, 1, posix_sleep);
LIB_FUNCTION("0wu33hunNdE", "libScePosix", 1, "libkernel", 1, 1, posix_sleep);
LIB_FUNCTION("lLMT9vJAck0", "libkernel", 1, "libkernel", 1, 1, posix_clock_gettime);
LIB_FUNCTION("lLMT9vJAck0", "libScePosix", 1, "libkernel", 1, 1, posix_clock_gettime);
LIB_FUNCTION("smIj7eqzZE8", "libkernel", 1, "libkernel", 1, 1, posix_clock_getres);
LIB_FUNCTION("smIj7eqzZE8", "libScePosix", 1, "libkernel", 1, 1, posix_clock_getres);
LIB_FUNCTION("n88vx3C5nW8", "libkernel", 1, "libkernel", 1, 1, posix_gettimeofday);
LIB_FUNCTION("n88vx3C5nW8", "libScePosix", 1, "libkernel", 1, 1, posix_gettimeofday);
// Orbis
LIB_FUNCTION("4J2sUJmuHZQ", "libkernel", 1, "libkernel", 1, 1, sceKernelGetProcessTime); LIB_FUNCTION("4J2sUJmuHZQ", "libkernel", 1, "libkernel", 1, 1, sceKernelGetProcessTime);
LIB_FUNCTION("fgxnMeTNUtY", "libkernel", 1, "libkernel", 1, 1, sceKernelGetProcessTimeCounter); LIB_FUNCTION("fgxnMeTNUtY", "libkernel", 1, "libkernel", 1, 1, sceKernelGetProcessTimeCounter);
LIB_FUNCTION("BNowx2l588E", "libkernel", 1, "libkernel", 1, 1, LIB_FUNCTION("BNowx2l588E", "libkernel", 1, "libkernel", 1, 1,
sceKernelGetProcessTimeCounterFrequency); sceKernelGetProcessTimeCounterFrequency);
LIB_FUNCTION("-2IRUCO--PM", "libkernel", 1, "libkernel", 1, 1, sceKernelReadTsc); LIB_FUNCTION("-2IRUCO--PM", "libkernel", 1, "libkernel", 1, 1, sceKernelReadTsc);
LIB_FUNCTION("1j3S3n-tTW4", "libkernel", 1, "libkernel", 1, 1, sceKernelGetTscFrequency); LIB_FUNCTION("1j3S3n-tTW4", "libkernel", 1, "libkernel", 1, 1, sceKernelGetTscFrequency);
LIB_FUNCTION("ejekcaNQNq0", "libkernel", 1, "libkernel", 1, 1, sceKernelGettimeofday);
LIB_FUNCTION("n88vx3C5nW8", "libkernel", 1, "libkernel", 1, 1, gettimeofday);
LIB_FUNCTION("n88vx3C5nW8", "libScePosix", 1, "libkernel", 1, 1, gettimeofday);
LIB_FUNCTION("QvsZxomvUHs", "libkernel", 1, "libkernel", 1, 1, sceKernelNanosleep); LIB_FUNCTION("QvsZxomvUHs", "libkernel", 1, "libkernel", 1, 1, sceKernelNanosleep);
LIB_FUNCTION("1jfXLRVzisc", "libkernel", 1, "libkernel", 1, 1, sceKernelUsleep); LIB_FUNCTION("1jfXLRVzisc", "libkernel", 1, "libkernel", 1, 1, sceKernelUsleep);
LIB_FUNCTION("QcteRwbsnV0", "libkernel", 1, "libkernel", 1, 1, posix_usleep);
LIB_FUNCTION("QcteRwbsnV0", "libScePosix", 1, "libkernel", 1, 1, posix_usleep);
LIB_FUNCTION("-ZR+hG7aDHw", "libkernel", 1, "libkernel", 1, 1, sceKernelSleep); LIB_FUNCTION("-ZR+hG7aDHw", "libkernel", 1, "libkernel", 1, 1, sceKernelSleep);
LIB_FUNCTION("0wu33hunNdE", "libScePosix", 1, "libkernel", 1, 1, sceKernelSleep);
LIB_FUNCTION("yS8U2TGCe1A", "libkernel", 1, "libkernel", 1, 1, posix_nanosleep);
LIB_FUNCTION("yS8U2TGCe1A", "libScePosix", 1, "libkernel", 1, 1, posix_nanosleep);
LIB_FUNCTION("QBi7HCK03hw", "libkernel", 1, "libkernel", 1, 1, sceKernelClockGettime); LIB_FUNCTION("QBi7HCK03hw", "libkernel", 1, "libkernel", 1, 1, sceKernelClockGettime);
LIB_FUNCTION("wRYVA5Zolso", "libkernel", 1, "libkernel", 1, 1, sceKernelClockGetres);
LIB_FUNCTION("ejekcaNQNq0", "libkernel", 1, "libkernel", 1, 1, sceKernelGettimeofday);
LIB_FUNCTION("kOcnerypnQA", "libkernel", 1, "libkernel", 1, 1, sceKernelGettimezone); LIB_FUNCTION("kOcnerypnQA", "libkernel", 1, "libkernel", 1, 1, sceKernelGettimezone);
LIB_FUNCTION("lLMT9vJAck0", "libkernel", 1, "libkernel", 1, 1, orbis_clock_gettime);
LIB_FUNCTION("lLMT9vJAck0", "libScePosix", 1, "libkernel", 1, 1, orbis_clock_gettime);
LIB_FUNCTION("smIj7eqzZE8", "libScePosix", 1, "libkernel", 1, 1, posix_clock_getres);
LIB_FUNCTION("0NTHN1NKONI", "libkernel", 1, "libkernel", 1, 1, sceKernelConvertLocaltimeToUtc); LIB_FUNCTION("0NTHN1NKONI", "libkernel", 1, "libkernel", 1, 1, sceKernelConvertLocaltimeToUtc);
LIB_FUNCTION("-o5uEDpN+oY", "libkernel", 1, "libkernel", 1, 1, sceKernelConvertUtcToLocaltime); LIB_FUNCTION("-o5uEDpN+oY", "libkernel", 1, "libkernel", 1, 1, sceKernelConvertUtcToLocaltime);
} }

View File

@ -75,14 +75,14 @@ u64 PS4_SYSV_ABI sceKernelGetProcessTime();
u64 PS4_SYSV_ABI sceKernelGetProcessTimeCounter(); u64 PS4_SYSV_ABI sceKernelGetProcessTimeCounter();
u64 PS4_SYSV_ABI sceKernelGetProcessTimeCounterFrequency(); u64 PS4_SYSV_ABI sceKernelGetProcessTimeCounterFrequency();
u64 PS4_SYSV_ABI sceKernelReadTsc(); u64 PS4_SYSV_ABI sceKernelReadTsc();
int PS4_SYSV_ABI sceKernelClockGettime(s32 clock_id, OrbisKernelTimespec* tp); s32 PS4_SYSV_ABI sceKernelClockGettime(u32 clock_id, OrbisKernelTimespec* tp);
s32 PS4_SYSV_ABI sceKernelGettimezone(OrbisKernelTimezone* tz); s32 PS4_SYSV_ABI sceKernelGettimezone(OrbisKernelTimezone* tz);
int PS4_SYSV_ABI sceKernelConvertLocaltimeToUtc(time_t param_1, int64_t param_2, time_t* seconds, s32 PS4_SYSV_ABI sceKernelConvertLocaltimeToUtc(time_t param_1, int64_t param_2, time_t* seconds,
OrbisKernelTimezone* timezone, int* dst_seconds); OrbisKernelTimezone* timezone, s32* dst_seconds);
int PS4_SYSV_ABI sceKernelConvertUtcToLocaltime(time_t time, time_t* local_time, OrbisTimesec* st, s32 PS4_SYSV_ABI sceKernelConvertUtcToLocaltime(time_t time, time_t* local_time, OrbisTimesec* st,
u64* dst_sec); u64* dst_sec);
int PS4_SYSV_ABI sceKernelUsleep(u32 microseconds); s32 PS4_SYSV_ABI sceKernelUsleep(u32 microseconds);
void RegisterTime(Core::Loader::SymbolsResolver* sym); void RegisterTime(Core::Loader::SymbolsResolver* sym);

View File

@ -56,7 +56,6 @@
#include <stdio.h> #include <stdio.h>
#include <cstdarg> #include <cstdarg>
#include <cstdbool>
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
#include <cstring> #include <cstring>

View File

@ -8,6 +8,8 @@
#include "core/libraries/audio/audioout.h" #include "core/libraries/audio/audioout.h"
#include "core/libraries/audio3d/audio3d.h" #include "core/libraries/audio3d/audio3d.h"
#include "core/libraries/avplayer/avplayer.h" #include "core/libraries/avplayer/avplayer.h"
#include "core/libraries/camera/camera.h"
#include "core/libraries/companion/companion_httpd.h"
#include "core/libraries/disc_map/disc_map.h" #include "core/libraries/disc_map/disc_map.h"
#include "core/libraries/game_live_streaming/gamelivestreaming.h" #include "core/libraries/game_live_streaming/gamelivestreaming.h"
#include "core/libraries/gnmdriver/gnmdriver.h" #include "core/libraries/gnmdriver/gnmdriver.h"
@ -45,6 +47,7 @@
#include "core/libraries/save_data/savedata.h" #include "core/libraries/save_data/savedata.h"
#include "core/libraries/screenshot/screenshot.h" #include "core/libraries/screenshot/screenshot.h"
#include "core/libraries/share_play/shareplay.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/commondialog.h"
#include "core/libraries/system/msgdialog.h" #include "core/libraries/system/msgdialog.h"
#include "core/libraries/system/posix.h" #include "core/libraries/system/posix.h"
@ -120,6 +123,9 @@ void InitHLELibs(Core::Loader::SymbolsResolver* sym) {
Libraries::Hmd::RegisterlibSceHmd(sym); Libraries::Hmd::RegisterlibSceHmd(sym);
Libraries::DiscMap::RegisterlibSceDiscMap(sym); Libraries::DiscMap::RegisterlibSceDiscMap(sym);
Libraries::Ulobjmgr::RegisterlibSceUlobjmgr(sym); Libraries::Ulobjmgr::RegisterlibSceUlobjmgr(sym);
Libraries::SigninDialog::RegisterlibSceSigninDialog(sym);
Libraries::Camera::RegisterlibSceCamera(sym);
Libraries::CompanionHttpd::RegisterlibSceCompanionHttpd(sym);
} }
} // namespace Libraries } // namespace Libraries

View File

@ -3,13 +3,9 @@
#pragma once #pragma once
#include <functional>
#include "common/logging/log.h"
#include "core/loader/elf.h" #include "core/loader/elf.h"
#include "core/loader/symbols_resolver.h" #include "core/loader/symbols_resolver.h"
#include "core/tls.h"
#define W(foo) foo
#define LIB_FUNCTION(nid, lib, libversion, mod, moduleVersionMajor, moduleVersionMinor, function) \ #define LIB_FUNCTION(nid, lib, libversion, mod, moduleVersionMajor, moduleVersionMinor, function) \
{ \ { \
@ -21,11 +17,11 @@
sr.module_version_major = moduleVersionMajor; \ sr.module_version_major = moduleVersionMajor; \
sr.module_version_minor = moduleVersionMinor; \ sr.module_version_minor = moduleVersionMinor; \
sr.type = Core::Loader::SymbolType::Function; \ sr.type = Core::Loader::SymbolType::Function; \
auto func = reinterpret_cast<u64>(function); \ auto func = reinterpret_cast<u64>(HOST_CALL(function)); \
sym->AddSymbol(sr, func); \ 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{}; \ Core::Loader::SymbolResolver sr{}; \
sr.name = nid; \ sr.name = nid; \
@ -35,8 +31,7 @@
sr.module_version_major = moduleVersionMajor; \ sr.module_version_major = moduleVersionMajor; \
sr.module_version_minor = moduleVersionMinor; \ sr.module_version_minor = moduleVersionMinor; \
sr.type = Core::Loader::SymbolType::Object; \ sr.type = Core::Loader::SymbolType::Object; \
auto func = reinterpret_cast<u64>(function); \ sym->AddSymbol(sr, reinterpret_cast<u64>(obj)); \
sym->AddSymbol(sr, func); \
} }
namespace Libraries { namespace Libraries {

View File

@ -10,16 +10,24 @@
#include <arpa/inet.h> #include <arpa/inet.h>
#endif #endif
#include <core/libraries/kernel/kernel.h>
#include "common/assert.h" #include "common/assert.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/singleton.h"
#include "core/libraries/error_codes.h" #include "core/libraries/error_codes.h"
#include "core/libraries/libs.h" #include "core/libraries/libs.h"
#include "core/libraries/network/net.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 { namespace Libraries::Net {
static thread_local int32_t net_errno = 0; static thread_local int32_t net_errno = 0;
static bool g_isNetInitialized = true; // TODO init it properly
int PS4_SYSV_ABI in6addr_any() { int PS4_SYSV_ABI in6addr_any() {
LOG_ERROR(Lib_Net, "(STUBBED) called"); LOG_ERROR(Lib_Net, "(STUBBED) called");
return ORBIS_OK; 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) { OrbisNetId PS4_SYSV_ABI sceNetAccept(OrbisNetId s, OrbisNetSockaddr* addr, u32* paddrlen) {
LOG_ERROR(Lib_Net, "(STUBBED) called"); if (!g_isNetInitialized) {
return ORBIS_OK; 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() { 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) { int PS4_SYSV_ABI sceNetBind(OrbisNetId s, const OrbisNetSockaddr* addr, u32 addrlen) {
LOG_ERROR(Lib_Net, "(STUBBED) called"); if (!g_isNetInitialized) {
return ORBIS_OK; 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() { int PS4_SYSV_ABI sceNetClearDnsCache() {
@ -465,9 +547,46 @@ int PS4_SYSV_ABI sceNetConfigWlanSetDeviceConfig() {
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceNetConnect() { int PS4_SYSV_ABI sceNetConnect(OrbisNetId s, const OrbisNetSockaddr* addr, u32 addrlen) {
LOG_ERROR(Lib_Net, "(STUBBED) called"); if (!g_isNetInitialized) {
return ORBIS_OK; 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() { int PS4_SYSV_ABI sceNetControl() {
@ -640,8 +759,15 @@ int PS4_SYSV_ABI sceNetGetIfnameNumList() {
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceNetGetMacAddress() { int PS4_SYSV_ABI sceNetGetMacAddress(Libraries::NetCtl::OrbisNetEtherAddr* addr, int flags) {
LOG_ERROR(Lib_Net, "(STUBBED) called"); 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; return ORBIS_OK;
} }
@ -655,9 +781,46 @@ int PS4_SYSV_ABI sceNetGetNameToIndex() {
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceNetGetpeername() { int PS4_SYSV_ABI sceNetGetpeername(OrbisNetId s, OrbisNetSockaddr* addr, u32* paddrlen) {
LOG_ERROR(Lib_Net, "(STUBBED) called"); if (!g_isNetInitialized) {
return ORBIS_OK; 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() { 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) { int PS4_SYSV_ABI sceNetGetsockname(OrbisNetId s, OrbisNetSockaddr* addr, u32* paddrlen) {
LOG_ERROR(Lib_Net, "(STUBBED) called"); if (!g_isNetInitialized) {
return ORBIS_OK; 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) { int PS4_SYSV_ABI sceNetGetsockopt(OrbisNetId s, int level, int optname, void* optval, u32* optlen) {
LOG_ERROR(Lib_Net, "(STUBBED) called"); LOG_INFO(Lib_Net, "s={} level={} optname={}", s, level, optname);
return ORBIS_OK; 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() { int PS4_SYSV_ABI sceNetGetStatisticsInfo() {
@ -781,9 +1019,46 @@ int PS4_SYSV_ABI sceNetIoctl() {
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceNetListen() { int PS4_SYSV_ABI sceNetListen(OrbisNetId s, int backlog) {
LOG_ERROR(Lib_Net, "(STUBBED) called"); if (!g_isNetInitialized) {
return ORBIS_OK; 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() { int PS4_SYSV_ABI sceNetMemoryAllocate() {
@ -829,20 +1104,131 @@ int PS4_SYSV_ABI sceNetPppoeStop() {
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceNetRecv() { int PS4_SYSV_ABI sceNetRecv(OrbisNetId s, void* buf, u64 len, int flags) {
LOG_ERROR(Lib_Net, "(STUBBED) called"); if (!g_isNetInitialized) {
return ORBIS_OK; 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
} }
int PS4_SYSV_ABI sceNetRecvfrom(OrbisNetId s, void* buf, size_t len, int flags, err = *Libraries::Kernel::__Error(); // Standard errno
OrbisNetSockaddr* addr, u32* paddrlen) {
LOG_ERROR(Lib_Net, "(STUBBED) called"); // Convert to positive error for comparison
return ORBIS_OK; int positiveErr = (err < 0) ? -err : err;
if ((positiveErr & 0xfff0000) != 0) {
// Unknown/fatal error range
*sceNetErrnoLoc() = ORBIS_NET_ERETURN;
return -positiveErr;
} }
int PS4_SYSV_ABI sceNetRecvmsg() { // Retry if interrupted
LOG_ERROR(Lib_Net, "(STUBBED) called"); } while (positiveErr == ORBIS_NET_EINTR);
return ORBIS_OK;
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, 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(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() { int PS4_SYSV_ABI sceNetResolverAbort() {
@ -915,19 +1301,131 @@ int PS4_SYSV_ABI sceNetResolverStartNtoaMultipleRecordsEx() {
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceNetSend() { int PS4_SYSV_ABI sceNetSend(OrbisNetId s, const void* buf, u64 len, int flags) {
LOG_ERROR(Lib_Net, "(STUBBED) called"); if (!g_isNetInitialized) {
return ORBIS_OK; 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
} }
int PS4_SYSV_ABI sceNetSendmsg() { err = *Libraries::Kernel::__Error(); // Standard errno
LOG_ERROR(Lib_Net, "(STUBBED) called");
return ORBIS_OK; // 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;
} }
int PS4_SYSV_ABI sceNetSendto() { // Retry if interrupted
LOG_ERROR(Lib_Net, "(STUBBED) called"); } while (positiveErr == ORBIS_NET_EINTR);
return ORBIS_OK;
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(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(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() { int PS4_SYSV_ABI sceNetSetDns6Info() {
@ -950,9 +1448,48 @@ int PS4_SYSV_ABI sceNetSetDnsInfoToKernel() {
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceNetSetsockopt() { int PS4_SYSV_ABI sceNetSetsockopt(OrbisNetId s, int level, int optname, const void* optval,
LOG_ERROR(Lib_Net, "(STUBBED) called"); u32 optlen) {
return ORBIS_OK; 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() { int PS4_SYSV_ABI sceNetShowIfconfig() {
@ -1035,24 +1572,172 @@ int PS4_SYSV_ABI sceNetShowRouteWithMemory() {
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceNetShutdown() { int PS4_SYSV_ABI sceNetShutdown(OrbisNetId s, int how) {
LOG_ERROR(Lib_Net, "(STUBBED) called"); if (!g_isNetInitialized) {
return ORBIS_OK; return ORBIS_NET_ERROR_ENOTINIT;
}
int result;
int err;
int positiveErr;
do {
result = sys_shutdown(s, how);
if (result >= 0) {
return result; // Success
} }
int PS4_SYSV_ABI sceNetSocket(const char* name, int family, int type, int protocol) { err = *Libraries::Kernel::__Error(); // Standard errno
LOG_ERROR(Lib_Net, "(STUBBED) called");
return ORBIS_OK; // 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;
} }
int PS4_SYSV_ABI sceNetSocketAbort() { // Retry if interrupted
LOG_ERROR(Lib_Net, "(STUBBED) called"); } while (positiveErr == ORBIS_NET_EINTR);
return ORBIS_OK;
if (positiveErr == ORBIS_NET_EADDRINUSE) {
result = -ORBIS_NET_EBADF;
} else if (positiveErr == ORBIS_NET_EALREADY) {
result = -ORBIS_NET_EINTR;
} else {
result = -positiveErr;
} }
int PS4_SYSV_ABI sceNetSocketClose() { *sceNetErrnoLoc() = -result;
LOG_ERROR(Lib_Net, "(STUBBED) called");
return ORBIS_OK; return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
}
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(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(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() { int PS4_SYSV_ABI sceNetSyncCreate() {

View File

@ -4,6 +4,7 @@
#pragma once #pragma once
#include "common/types.h" #include "common/types.h"
#include "netctl.h"
namespace Core::Loader { namespace Core::Loader {
class SymbolsResolver; class SymbolsResolver;
@ -19,6 +20,63 @@ class SymbolsResolver;
namespace Libraries::Net { 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; using OrbisNetId = s32;
struct OrbisNetSockaddr { struct OrbisNetSockaddr {
@ -27,6 +85,30 @@ struct OrbisNetSockaddr {
char sa_data[14]; 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_any();
int PS4_SYSV_ABI in6addr_loopback(); int PS4_SYSV_ABI in6addr_loopback();
int PS4_SYSV_ABI sce_net_dummy(); 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 sceNetConfigWlanInfraScanJoin();
int PS4_SYSV_ABI sceNetConfigWlanScan(); int PS4_SYSV_ABI sceNetConfigWlanScan();
int PS4_SYSV_ABI sceNetConfigWlanSetDeviceConfig(); 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 sceNetControl();
int PS4_SYSV_ABI sceNetDhcpdStart(); int PS4_SYSV_ABI sceNetDhcpdStart();
int PS4_SYSV_ABI sceNetDhcpdStop(); int PS4_SYSV_ABI sceNetDhcpdStop();
@ -151,10 +233,10 @@ int PS4_SYSV_ABI sceNetGetIfList();
int PS4_SYSV_ABI sceNetGetIfListOnce(); int PS4_SYSV_ABI sceNetGetIfListOnce();
int PS4_SYSV_ABI sceNetGetIfName(); int PS4_SYSV_ABI sceNetGetIfName();
int PS4_SYSV_ABI sceNetGetIfnameNumList(); 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 sceNetGetMemoryPoolStats();
int PS4_SYSV_ABI sceNetGetNameToIndex(); 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 sceNetGetRandom();
int PS4_SYSV_ABI sceNetGetRouteInfo(); int PS4_SYSV_ABI sceNetGetRouteInfo();
int PS4_SYSV_ABI sceNetGetSockInfo(); int PS4_SYSV_ABI sceNetGetSockInfo();
@ -177,7 +259,7 @@ int PS4_SYSV_ABI sceNetInfoDumpStop();
int PS4_SYSV_ABI sceNetInit(); int PS4_SYSV_ABI sceNetInit();
int PS4_SYSV_ABI sceNetInitParam(); int PS4_SYSV_ABI sceNetInitParam();
int PS4_SYSV_ABI sceNetIoctl(); 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 sceNetMemoryAllocate();
int PS4_SYSV_ABI sceNetMemoryFree(); int PS4_SYSV_ABI sceNetMemoryFree();
u32 PS4_SYSV_ABI sceNetNtohl(u32 net32); 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 sceNetPoolDestroy();
int PS4_SYSV_ABI sceNetPppoeStart(); int PS4_SYSV_ABI sceNetPppoeStart();
int PS4_SYSV_ABI sceNetPppoeStop(); int PS4_SYSV_ABI sceNetPppoeStop();
int PS4_SYSV_ABI sceNetRecv(); int PS4_SYSV_ABI sceNetRecv(OrbisNetId s, void* buf, u64 len, int flags);
int PS4_SYSV_ABI sceNetRecvfrom(OrbisNetId s, void* buf, size_t len, int flags, int PS4_SYSV_ABI sceNetRecvfrom(OrbisNetId s, void* buf, u64 len, int flags, OrbisNetSockaddr* addr,
OrbisNetSockaddr* addr, u32* paddrlen); u32* paddrlen);
int PS4_SYSV_ABI sceNetRecvmsg(); int PS4_SYSV_ABI sceNetRecvmsg(OrbisNetId s, OrbisNetMsghdr* msg, int flags);
int PS4_SYSV_ABI sceNetResolverAbort(); int PS4_SYSV_ABI sceNetResolverAbort();
int PS4_SYSV_ABI sceNetResolverConnect(); int PS4_SYSV_ABI sceNetResolverConnect();
int PS4_SYSV_ABI sceNetResolverConnectAbort(); int PS4_SYSV_ABI sceNetResolverConnectAbort();
@ -205,14 +287,16 @@ int PS4_SYSV_ABI sceNetResolverStartNtoa();
int PS4_SYSV_ABI sceNetResolverStartNtoa6(); int PS4_SYSV_ABI sceNetResolverStartNtoa6();
int PS4_SYSV_ABI sceNetResolverStartNtoaMultipleRecords(); int PS4_SYSV_ABI sceNetResolverStartNtoaMultipleRecords();
int PS4_SYSV_ABI sceNetResolverStartNtoaMultipleRecordsEx(); int PS4_SYSV_ABI sceNetResolverStartNtoaMultipleRecordsEx();
int PS4_SYSV_ABI sceNetSend(); int PS4_SYSV_ABI sceNetSend(OrbisNetId s, const void* buf, u64 len, int flags);
int PS4_SYSV_ABI sceNetSendmsg(); int PS4_SYSV_ABI sceNetSendmsg(OrbisNetId s, const OrbisNetMsghdr* msg, int flags);
int PS4_SYSV_ABI sceNetSendto(); 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 sceNetSetDns6Info();
int PS4_SYSV_ABI sceNetSetDns6InfoToKernel(); int PS4_SYSV_ABI sceNetSetDns6InfoToKernel();
int PS4_SYSV_ABI sceNetSetDnsInfo(); int PS4_SYSV_ABI sceNetSetDnsInfo();
int PS4_SYSV_ABI sceNetSetDnsInfoToKernel(); 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 sceNetShowIfconfig();
int PS4_SYSV_ABI sceNetShowIfconfigForBuffer(); int PS4_SYSV_ABI sceNetShowIfconfigForBuffer();
int PS4_SYSV_ABI sceNetShowIfconfigWithMemory(); int PS4_SYSV_ABI sceNetShowIfconfigWithMemory();
@ -229,10 +313,10 @@ int PS4_SYSV_ABI sceNetShowRoute6ForBuffer();
int PS4_SYSV_ABI sceNetShowRoute6WithMemory(); int PS4_SYSV_ABI sceNetShowRoute6WithMemory();
int PS4_SYSV_ABI sceNetShowRouteForBuffer(); int PS4_SYSV_ABI sceNetShowRouteForBuffer();
int PS4_SYSV_ABI sceNetShowRouteWithMemory(); int PS4_SYSV_ABI sceNetShowRouteWithMemory();
int PS4_SYSV_ABI sceNetShutdown(); int PS4_SYSV_ABI sceNetShutdown(OrbisNetId s, int how);
int PS4_SYSV_ABI sceNetSocket(const char* name, int family, int type, int protocol); OrbisNetId PS4_SYSV_ABI sceNetSocket(const char* name, int family, int type, int protocol);
int PS4_SYSV_ABI sceNetSocketAbort(); int PS4_SYSV_ABI sceNetSocketAbort(OrbisNetId s, int flags);
int PS4_SYSV_ABI sceNetSocketClose(); int PS4_SYSV_ABI sceNetSocketClose(OrbisNetId s);
int PS4_SYSV_ABI sceNetSyncCreate(); int PS4_SYSV_ABI sceNetSyncCreate();
int PS4_SYSV_ABI sceNetSyncDestroy(); int PS4_SYSV_ABI sceNetSyncDestroy();
int PS4_SYSV_ABI sceNetSyncGet(); int PS4_SYSV_ABI sceNetSyncGet();

View 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;

View 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

View 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

View File

@ -12,11 +12,13 @@
#include <unistd.h> #include <unistd.h>
#endif #endif
#include <common/singleton.h>
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/libraries/error_codes.h" #include "core/libraries/error_codes.h"
#include "core/libraries/libs.h" #include "core/libraries/libs.h"
#include "core/libraries/network/net_ctl_codes.h" #include "core/libraries/network/net_ctl_codes.h"
#include "core/libraries/network/netctl.h" #include "core/libraries/network/netctl.h"
#include "net_util.h"
namespace Libraries::NetCtl { namespace Libraries::NetCtl {
@ -162,6 +164,14 @@ int PS4_SYSV_ABI sceNetCtlGetInfo(int code, OrbisNetCtlInfo* info) {
case ORBIS_NET_CTL_INFO_DEVICE: case ORBIS_NET_CTL_INFO_DEVICE:
info->device = ORBIS_NET_CTL_DEVICE_WIRED; info->device = ORBIS_NET_CTL_DEVICE_WIRED;
break; 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: case ORBIS_NET_CTL_INFO_LINK:
info->link = ORBIS_NET_CTL_LINK_DISCONNECTED; info->link = ORBIS_NET_CTL_LINK_DISCONNECTED;
break; break;
@ -183,6 +193,7 @@ int PS4_SYSV_ABI sceNetCtlGetInfo(int code, OrbisNetCtlInfo* info) {
} }
break; break;
} }
default: default:
LOG_ERROR(Lib_NetCtl, "{} unsupported code", code); LOG_ERROR(Lib_NetCtl, "{} unsupported code", code);
} }

View File

@ -49,8 +49,26 @@ union OrbisNetCtlInfo {
// GetInfo codes // GetInfo codes
constexpr int ORBIS_NET_CTL_INFO_DEVICE = 1; 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_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_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 sceNetBweCheckCallbackIpcInt();
int PS4_SYSV_ABI sceNetBweClearEventIpcInt(); int PS4_SYSV_ABI sceNetBweClearEventIpcInt();

View 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

View 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

View 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

View 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

View 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

View File

@ -380,8 +380,7 @@ s32 PS4_SYSV_ABI sceNgs2GeomApply(const OrbisNgs2GeomListenerWork* listener,
s32 PS4_SYSV_ABI sceNgs2PanInit(OrbisNgs2PanWork* work, const float* aSpeakerAngle, float unitAngle, s32 PS4_SYSV_ABI sceNgs2PanInit(OrbisNgs2PanWork* work, const float* aSpeakerAngle, float unitAngle,
u32 numSpeakers) { u32 numSpeakers) {
LOG_ERROR(Lib_Ngs2, "aSpeakerAngle = {}, unitAngle = {}, numSpeakers = {}", *aSpeakerAngle, LOG_ERROR(Lib_Ngs2, "unitAngle = {}, numSpeakers = {}", unitAngle, numSpeakers);
unitAngle, numSpeakers);
return ORBIS_OK; return ORBIS_OK;
} }

View File

@ -206,6 +206,10 @@ s32 PS4_SYSV_ABI sceNpTrophyDestroyHandle(OrbisNpTrophyHandle handle) {
if (handle == ORBIS_NP_TROPHY_INVALID_HANDLE) if (handle == ORBIS_NP_TROPHY_INVALID_HANDLE)
return ORBIS_NP_TROPHY_ERROR_INVALID_HANDLE; return ORBIS_NP_TROPHY_ERROR_INVALID_HANDLE;
if (handle >= trophy_handles.size()) {
LOG_ERROR(Lib_NpTrophy, "Invalid handle {}", handle);
return ORBIS_NP_TROPHY_ERROR_INVALID_HANDLE;
}
if (!trophy_handles.is_allocated({static_cast<u32>(handle)})) { if (!trophy_handles.is_allocated({static_cast<u32>(handle)})) {
return ORBIS_NP_TROPHY_ERROR_INVALID_HANDLE; return ORBIS_NP_TROPHY_ERROR_INVALID_HANDLE;
} }

View File

@ -49,14 +49,12 @@ void SaveDialogResult::CopyTo(OrbisSaveDataDialogResult& result) const {
result.mode = this->mode; result.mode = this->mode;
result.result = this->result; result.result = this->result;
result.buttonId = this->button_id; result.buttonId = this->button_id;
if (mode == SaveDataDialogMode::LIST || ElfInfo::Instance().FirmwareVer() >= ElfInfo::FW_45) {
if (result.dirName != nullptr) { if (result.dirName != nullptr) {
result.dirName->data.FromString(this->dir_name); result.dirName->data.FromString(this->dir_name);
} }
if (result.param != nullptr && this->param.GetString(SaveParams::MAINTITLE).has_value()) { if (result.param != nullptr && this->param.GetString(SaveParams::MAINTITLE).has_value()) {
result.param->FromSFO(this->param); result.param->FromSFO(this->param);
} }
}
result.userData = this->user_data; result.userData = this->user_data;
} }
@ -157,7 +155,7 @@ SaveDialogState::SaveDialogState(const OrbisSaveDataDialogParam& param) {
if (item->focusPos != FocusPos::DIRNAME) { if (item->focusPos != FocusPos::DIRNAME) {
this->focus_pos = item->focusPos; this->focus_pos = item->focusPos;
} else { } else if (item->focusPosDirName != nullptr) {
this->focus_pos = item->focusPosDirName->data.to_string(); this->focus_pos = item->focusPosDirName->data.to_string();
} }
this->style = item->itemStyle; this->style = item->itemStyle;
@ -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); std::scoped_lock lock(draw_mutex, other.draw_mutex);
using std::swap; using std::swap;
swap(state, other.state); state = other.state;
swap(status, other.status); other.state = nullptr;
swap(result, other.result); status = other.status;
other.status = nullptr;
result = other.result;
other.result = nullptr;
if (status && *status == Status::RUNNING) { if (status && *status == Status::RUNNING) {
first_render = true; first_render = true;
AddLayer(this); AddLayer(this);

View File

@ -300,7 +300,8 @@ public:
~SaveDialogUi() override; ~SaveDialogUi() override;
SaveDialogUi(const SaveDialogUi& other) = delete; SaveDialogUi(const SaveDialogUi& other) = delete;
SaveDialogUi(SaveDialogUi&& other) noexcept; 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); void Finish(ButtonId buttonId, CommonDialog::Result r = CommonDialog::Result::OK);

View File

@ -10,15 +10,14 @@
#include <utility> #include <utility>
#include <fmt/format.h> #include <fmt/format.h>
#include <core/libraries/system/msgdialog_ui.h> #include "boost/icl/concept/interval.hpp"
#include "common/assert.h"
#include "common/elf_info.h" #include "common/elf_info.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/path_util.h" #include "common/path_util.h"
#include "common/singleton.h" #include "common/singleton.h"
#include "common/thread.h" #include "common/thread.h"
#include "core/file_sys/fs.h" #include "core/file_sys/fs.h"
#include "core/libraries/system/msgdialog_ui.h"
#include "save_instance.h" #include "save_instance.h"
using Common::FS::IOFile; using Common::FS::IOFile;
@ -35,11 +34,12 @@ namespace Libraries::SaveData::SaveMemory {
static Core::FileSys::MntPoints* g_mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance(); static Core::FileSys::MntPoints* g_mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
struct SlotData { struct SlotData {
OrbisUserServiceUserId user_id; OrbisUserServiceUserId user_id{};
std::string game_serial; std::string game_serial;
std::filesystem::path folder_path; std::filesystem::path folder_path;
PSF sfo; PSF sfo;
std::vector<u8> memory_cache; std::vector<u8> memory_cache;
size_t memory_cache_size{};
}; };
static std::mutex g_slot_mtx; static std::mutex g_slot_mtx;
@ -97,7 +97,8 @@ std::filesystem::path GetSavePath(OrbisUserServiceUserId user_id, u32 slot_id,
return SaveInstance::MakeDirSavePath(user_id, Common::ElfInfo::Instance().GameSerial(), dir); return SaveInstance::MakeDirSavePath(user_id, Common::ElfInfo::Instance().GameSerial(), dir);
} }
size_t SetupSaveMemory(OrbisUserServiceUserId user_id, u32 slot_id, std::string_view game_serial) { size_t SetupSaveMemory(OrbisUserServiceUserId user_id, u32 slot_id, std::string_view game_serial,
size_t memory_size) {
std::lock_guard lck{g_slot_mtx}; std::lock_guard lck{g_slot_mtx};
const auto save_dir = GetSavePath(user_id, slot_id, game_serial); const auto save_dir = GetSavePath(user_id, slot_id, game_serial);
@ -109,6 +110,7 @@ size_t SetupSaveMemory(OrbisUserServiceUserId user_id, u32 slot_id, std::string_
.folder_path = save_dir, .folder_path = save_dir,
.sfo = {}, .sfo = {},
.memory_cache = {}, .memory_cache = {},
.memory_cache_size = memory_size,
}; };
SaveInstance::SetupDefaultParamSFO(data.sfo, GetSaveDir(slot_id), std::string{game_serial}); SaveInstance::SetupDefaultParamSFO(data.sfo, GetSaveDir(slot_id), std::string{game_serial});
@ -196,9 +198,9 @@ void ReadMemory(u32 slot_id, void* buf, size_t buf_size, int64_t offset) {
auto& data = g_attached_slots[slot_id]; auto& data = g_attached_slots[slot_id];
auto& memory = data.memory_cache; auto& memory = data.memory_cache;
if (memory.empty()) { // Load file if (memory.empty()) { // Load file
memory.resize(data.memory_cache_size);
IOFile f{data.folder_path / FilenameSaveDataMemory, Common::FS::FileAccessMode::Read}; IOFile f{data.folder_path / FilenameSaveDataMemory, Common::FS::FileAccessMode::Read};
if (f.IsOpen()) { if (f.IsOpen()) {
memory.resize(f.GetSize());
f.Seek(0); f.Seek(0);
f.ReadSpan(std::span{memory}); f.ReadSpan(std::span{memory});
} }
@ -222,5 +224,4 @@ void WriteMemory(u32 slot_id, void* buf, size_t buf_size, int64_t offset) {
Backup::NewRequest(data.user_id, data.game_serial, GetSaveDir(slot_id), Backup::NewRequest(data.user_id, data.game_serial, GetSaveDir(slot_id),
Backup::OrbisSaveDataEventType::__DO_NOT_SAVE); Backup::OrbisSaveDataEventType::__DO_NOT_SAVE);
} }
} // namespace Libraries::SaveData::SaveMemory } // namespace Libraries::SaveData::SaveMemory

View File

@ -4,13 +4,13 @@
#pragma once #pragma once
#include <vector> #include <vector>
#include "save_backup.h" #include "core/libraries/save_data/save_backup.h"
class PSF; class PSF;
namespace Libraries::SaveData { namespace Libraries::SaveData {
using OrbisUserServiceUserId = s32; using OrbisUserServiceUserId = s32;
} } // namespace Libraries::SaveData
namespace Libraries::SaveData::SaveMemory { namespace Libraries::SaveData::SaveMemory {
@ -22,7 +22,8 @@ void PersistMemory(u32 slot_id, bool lock = true);
std::string_view game_serial); std::string_view game_serial);
// returns the size of the save memory if exists // returns the size of the save memory if exists
size_t SetupSaveMemory(OrbisUserServiceUserId user_id, u32 slot_id, std::string_view game_serial); size_t SetupSaveMemory(OrbisUserServiceUserId user_id, u32 slot_id, std::string_view game_serial,
size_t memory_size);
// Write the icon. Set buf to null to read the standard icon. // Write the icon. Set buf to null to read the standard icon.
void SetIcon(u32 slot_id, void* buf = nullptr, size_t buf_size = 0); void SetIcon(u32 slot_id, void* buf = nullptr, size_t buf_size = 0);

View File

@ -5,10 +5,10 @@
#include <thread> #include <thread>
#include <vector> #include <vector>
#include <core/libraries/system/msgdialog_ui.h>
#include <magic_enum/magic_enum.hpp> #include <magic_enum/magic_enum.hpp>
#include "common/assert.h" #include "common/assert.h"
#include "common/config.h"
#include "common/cstring.h" #include "common/cstring.h"
#include "common/elf_info.h" #include "common/elf_info.h"
#include "common/enum.h" #include "common/enum.h"
@ -20,7 +20,9 @@
#include "core/libraries/error_codes.h" #include "core/libraries/error_codes.h"
#include "core/libraries/libs.h" #include "core/libraries/libs.h"
#include "core/libraries/save_data/savedata.h" #include "core/libraries/save_data/savedata.h"
#include "core/libraries/save_data/savedata_error.h"
#include "core/libraries/system/msgdialog.h" #include "core/libraries/system/msgdialog.h"
#include "core/libraries/system/msgdialog_ui.h"
#include "save_backup.h" #include "save_backup.h"
#include "save_instance.h" #include "save_instance.h"
#include "save_memory.h" #include "save_memory.h"
@ -33,27 +35,6 @@ using Common::ElfInfo;
namespace Libraries::SaveData { namespace Libraries::SaveData {
enum class Error : u32 {
OK = 0,
USER_SERVICE_NOT_INITIALIZED = 0x80960002,
PARAMETER = 0x809F0000,
NOT_INITIALIZED = 0x809F0001,
OUT_OF_MEMORY = 0x809F0002,
BUSY = 0x809F0003,
NOT_MOUNTED = 0x809F0004,
EXISTS = 0x809F0007,
NOT_FOUND = 0x809F0008,
NO_SPACE_FS = 0x809F000A,
INTERNAL = 0x809F000B,
MOUNT_FULL = 0x809F000C,
BAD_MOUNTED = 0x809F000D,
BROKEN = 0x809F000F,
INVALID_LOGIN_USER = 0x809F0011,
MEMORY_NOT_READY = 0x809F0012,
BACKUP_BUSY = 0x809F0013,
BUSY_FOR_SAVING = 0x809F0016,
};
enum class OrbisSaveDataSaveDataMemoryOption : u32 { enum class OrbisSaveDataSaveDataMemoryOption : u32 {
NONE = 0, NONE = 0,
SET_PARAM = 1 << 0, SET_PARAM = 1 << 0,
@ -336,7 +317,9 @@ static std::array<std::optional<SaveInstance>, 16> g_mount_slots;
static void initialize() { static void initialize() {
g_initialized = true; g_initialized = true;
g_game_serial = ElfInfo::Instance().GameSerial(); g_game_serial = Common::Singleton<PSF>::Instance()
->GetString("INSTALL_DIR_SAVEDATA")
.value_or(ElfInfo::Instance().GameSerial());
g_fw_ver = ElfInfo::Instance().FirmwareVer(); g_fw_ver = ElfInfo::Instance().FirmwareVer();
Backup::StartThread(); Backup::StartThread();
} }
@ -456,7 +439,7 @@ static Error saveDataMount(const OrbisSaveDataMount2* mount_info,
LOG_INFO(Lib_SaveData, "called with invalid block size"); LOG_INFO(Lib_SaveData, "called with invalid block size");
} }
const auto root_save = Common::FS::GetUserPath(Common::FS::PathType::SaveDataDir); const auto root_save = Config::GetSaveDataPath();
fs::create_directories(root_save); fs::create_directories(root_save);
const auto available = fs::space(root_save).available; const auto available = fs::space(root_save).available;
@ -1593,8 +1576,8 @@ Error PS4_SYSV_ABI sceSaveDataSetupSaveDataMemory2(const OrbisSaveDataMemorySetu
} }
try { try {
size_t existed_size = size_t existed_size = SaveMemory::SetupSaveMemory(setupParam->userId, slot_id,
SaveMemory::SetupSaveMemory(setupParam->userId, slot_id, g_game_serial); g_game_serial, setupParam->memorySize);
if (existed_size == 0) { // Just created if (existed_size == 0) { // Just created
if (g_fw_ver >= ElfInfo::FW_45 && setupParam->initParam != nullptr) { if (g_fw_ver >= ElfInfo::FW_45 && setupParam->initParam != nullptr) {
auto& sfo = SaveMemory::GetParamSFO(slot_id); auto& sfo = SaveMemory::GetParamSFO(slot_id);

View File

@ -0,0 +1,27 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
namespace Libraries::SaveData {
enum class Error : u32 {
OK = 0,
USER_SERVICE_NOT_INITIALIZED = 0x80960002,
PARAMETER = 0x809F0000,
NOT_INITIALIZED = 0x809F0001,
OUT_OF_MEMORY = 0x809F0002,
BUSY = 0x809F0003,
NOT_MOUNTED = 0x809F0004,
EXISTS = 0x809F0007,
NOT_FOUND = 0x809F0008,
NO_SPACE_FS = 0x809F000A,
INTERNAL = 0x809F000B,
MOUNT_FULL = 0x809F000C,
BAD_MOUNTED = 0x809F000D,
BROKEN = 0x809F000F,
INVALID_LOGIN_USER = 0x809F0011,
MEMORY_NOT_READY = 0x809F0012,
BACKUP_BUSY = 0x809F0013,
BUSY_FOR_SAVING = 0x809F0016,
};
} // namespace Libraries::SaveData

View 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

View 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

View File

@ -17,10 +17,12 @@ int PS4_SYSV_ABI sceVideodecCreateDecoder(const OrbisVideodecConfigInfo* pCfgInf
LOG_INFO(Lib_Videodec, "called"); LOG_INFO(Lib_Videodec, "called");
if (!pCfgInfoIn || !pRsrcInfoIn || !pCtrlOut) { if (!pCfgInfoIn || !pRsrcInfoIn || !pCtrlOut) {
LOG_ERROR(Lib_Videodec, "Invalid arguments");
return ORBIS_VIDEODEC_ERROR_ARGUMENT_POINTER; return ORBIS_VIDEODEC_ERROR_ARGUMENT_POINTER;
} }
if (pCfgInfoIn->thisSize != sizeof(OrbisVideodecConfigInfo) || if (pCfgInfoIn->thisSize != sizeof(OrbisVideodecConfigInfo) ||
pRsrcInfoIn->thisSize != sizeof(OrbisVideodecResourceInfo)) { pRsrcInfoIn->thisSize != sizeof(OrbisVideodecResourceInfo)) {
LOG_ERROR(Lib_Videodec, "Invalid struct size");
return ORBIS_VIDEODEC_ERROR_STRUCT_SIZE; return ORBIS_VIDEODEC_ERROR_STRUCT_SIZE;
} }
@ -37,15 +39,18 @@ int PS4_SYSV_ABI sceVideodecDecode(OrbisVideodecCtrl* pCtrlIn,
OrbisVideodecPictureInfo* pPictureInfoOut) { OrbisVideodecPictureInfo* pPictureInfoOut) {
LOG_TRACE(Lib_Videodec, "called"); LOG_TRACE(Lib_Videodec, "called");
if (!pCtrlIn || !pInputDataIn || !pPictureInfoOut) { if (!pCtrlIn || !pInputDataIn || !pPictureInfoOut) {
LOG_ERROR(Lib_Videodec, "Invalid arguments");
return ORBIS_VIDEODEC_ERROR_ARGUMENT_POINTER; return ORBIS_VIDEODEC_ERROR_ARGUMENT_POINTER;
} }
if (pCtrlIn->thisSize != sizeof(OrbisVideodecCtrl) || if (pCtrlIn->thisSize != sizeof(OrbisVideodecCtrl) ||
pFrameBufferInOut->thisSize != sizeof(OrbisVideodecFrameBuffer)) { pFrameBufferInOut->thisSize != sizeof(OrbisVideodecFrameBuffer)) {
LOG_ERROR(Lib_Videodec, "Invalid struct size");
return ORBIS_VIDEODEC_ERROR_STRUCT_SIZE; return ORBIS_VIDEODEC_ERROR_STRUCT_SIZE;
} }
VdecDecoder* decoder = (VdecDecoder*)pCtrlIn->handle; VdecDecoder* decoder = (VdecDecoder*)pCtrlIn->handle;
if (!decoder) { if (!decoder) {
LOG_ERROR(Lib_Videodec, "Invalid decoder handle");
return ORBIS_VIDEODEC_ERROR_HANDLE; return ORBIS_VIDEODEC_ERROR_HANDLE;
} }
return decoder->Decode(*pInputDataIn, *pFrameBufferInOut, *pPictureInfoOut); return decoder->Decode(*pInputDataIn, *pFrameBufferInOut, *pPictureInfoOut);
@ -56,6 +61,7 @@ int PS4_SYSV_ABI sceVideodecDeleteDecoder(OrbisVideodecCtrl* pCtrlIn) {
VdecDecoder* decoder = (VdecDecoder*)pCtrlIn->handle; VdecDecoder* decoder = (VdecDecoder*)pCtrlIn->handle;
if (!decoder) { if (!decoder) {
LOG_ERROR(Lib_Videodec, "Invalid decoder handle");
return ORBIS_VIDEODEC_ERROR_HANDLE; return ORBIS_VIDEODEC_ERROR_HANDLE;
} }
delete decoder; delete decoder;
@ -68,15 +74,18 @@ int PS4_SYSV_ABI sceVideodecFlush(OrbisVideodecCtrl* pCtrlIn,
LOG_INFO(Lib_Videodec, "called"); LOG_INFO(Lib_Videodec, "called");
if (!pFrameBufferInOut || !pPictureInfoOut) { if (!pFrameBufferInOut || !pPictureInfoOut) {
LOG_ERROR(Lib_Videodec, "Invalid arguments");
return ORBIS_VIDEODEC_ERROR_ARGUMENT_POINTER; return ORBIS_VIDEODEC_ERROR_ARGUMENT_POINTER;
} }
if (pFrameBufferInOut->thisSize != sizeof(OrbisVideodecFrameBuffer) || if (pFrameBufferInOut->thisSize != sizeof(OrbisVideodecFrameBuffer) ||
pPictureInfoOut->thisSize != sizeof(OrbisVideodecPictureInfo)) { pPictureInfoOut->thisSize != sizeof(OrbisVideodecPictureInfo)) {
LOG_ERROR(Lib_Videodec, "Invalid struct size");
return ORBIS_VIDEODEC_ERROR_STRUCT_SIZE; return ORBIS_VIDEODEC_ERROR_STRUCT_SIZE;
} }
VdecDecoder* decoder = (VdecDecoder*)pCtrlIn->handle; VdecDecoder* decoder = (VdecDecoder*)pCtrlIn->handle;
if (!decoder) { if (!decoder) {
LOG_ERROR(Lib_Videodec, "Invalid decoder handle");
return ORBIS_VIDEODEC_ERROR_HANDLE; return ORBIS_VIDEODEC_ERROR_HANDLE;
} }
return decoder->Flush(*pFrameBufferInOut, *pPictureInfoOut); return decoder->Flush(*pFrameBufferInOut, *pPictureInfoOut);
@ -92,10 +101,12 @@ int PS4_SYSV_ABI sceVideodecQueryResourceInfo(const OrbisVideodecConfigInfo* pCf
LOG_INFO(Lib_Videodec, "called"); LOG_INFO(Lib_Videodec, "called");
if (!pCfgInfoIn || !pRsrcInfoOut) { if (!pCfgInfoIn || !pRsrcInfoOut) {
LOG_ERROR(Lib_Videodec, "Invalid arguments");
return ORBIS_VIDEODEC_ERROR_ARGUMENT_POINTER; return ORBIS_VIDEODEC_ERROR_ARGUMENT_POINTER;
} }
if (pCfgInfoIn->thisSize != sizeof(OrbisVideodecConfigInfo) || if (pCfgInfoIn->thisSize != sizeof(OrbisVideodecConfigInfo) ||
pRsrcInfoOut->thisSize != sizeof(OrbisVideodecResourceInfo)) { pRsrcInfoOut->thisSize != sizeof(OrbisVideodecResourceInfo)) {
LOG_ERROR(Lib_Videodec, "Invalid struct size");
return ORBIS_VIDEODEC_ERROR_STRUCT_SIZE; return ORBIS_VIDEODEC_ERROR_STRUCT_SIZE;
} }

View File

@ -17,9 +17,11 @@ sceVideodec2QueryComputeMemoryInfo(OrbisVideodec2ComputeMemoryInfo* computeMemIn
LOG_INFO(Lib_Vdec2, "called"); LOG_INFO(Lib_Vdec2, "called");
if (!computeMemInfo) { if (!computeMemInfo) {
LOG_ERROR(Lib_Vdec2, "Invalid arguments");
return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER; return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER;
} }
if (computeMemInfo->thisSize != sizeof(OrbisVideodec2ComputeMemoryInfo)) { if (computeMemInfo->thisSize != sizeof(OrbisVideodec2ComputeMemoryInfo)) {
LOG_ERROR(Lib_Vdec2, "Invalid struct size");
return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE; return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE;
} }
@ -47,10 +49,12 @@ sceVideodec2QueryDecoderMemoryInfo(const OrbisVideodec2DecoderConfigInfo* decode
LOG_INFO(Lib_Vdec2, "called"); LOG_INFO(Lib_Vdec2, "called");
if (!decoderCfgInfo || !decoderMemInfo) { if (!decoderCfgInfo || !decoderMemInfo) {
LOG_ERROR(Lib_Vdec2, "Invalid arguments");
return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER; return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER;
} }
if (decoderCfgInfo->thisSize != sizeof(OrbisVideodec2DecoderConfigInfo) || if (decoderCfgInfo->thisSize != sizeof(OrbisVideodec2DecoderConfigInfo) ||
decoderMemInfo->thisSize != sizeof(OrbisVideodec2DecoderMemoryInfo)) { decoderMemInfo->thisSize != sizeof(OrbisVideodec2DecoderMemoryInfo)) {
LOG_ERROR(Lib_Vdec2, "Invalid struct size");
return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE; return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE;
} }
@ -74,10 +78,12 @@ s32 PS4_SYSV_ABI sceVideodec2CreateDecoder(const OrbisVideodec2DecoderConfigInfo
LOG_INFO(Lib_Vdec2, "called"); LOG_INFO(Lib_Vdec2, "called");
if (!decoderCfgInfo || !decoderMemInfo || !decoder) { if (!decoderCfgInfo || !decoderMemInfo || !decoder) {
LOG_ERROR(Lib_Vdec2, "Invalid arguments");
return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER; return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER;
} }
if (decoderCfgInfo->thisSize != sizeof(OrbisVideodec2DecoderConfigInfo) || if (decoderCfgInfo->thisSize != sizeof(OrbisVideodec2DecoderConfigInfo) ||
decoderMemInfo->thisSize != sizeof(OrbisVideodec2DecoderMemoryInfo)) { decoderMemInfo->thisSize != sizeof(OrbisVideodec2DecoderMemoryInfo)) {
LOG_ERROR(Lib_Vdec2, "Invalid struct size");
return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE; return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE;
} }
@ -89,6 +95,7 @@ s32 PS4_SYSV_ABI sceVideodec2DeleteDecoder(OrbisVideodec2Decoder decoder) {
LOG_INFO(Lib_Vdec2, "called"); LOG_INFO(Lib_Vdec2, "called");
if (!decoder) { if (!decoder) {
LOG_ERROR(Lib_Vdec2, "Invalid arguments");
return ORBIS_VIDEODEC2_ERROR_DECODER_INSTANCE; return ORBIS_VIDEODEC2_ERROR_DECODER_INSTANCE;
} }
@ -103,13 +110,16 @@ s32 PS4_SYSV_ABI sceVideodec2Decode(OrbisVideodec2Decoder decoder,
LOG_TRACE(Lib_Vdec2, "called"); LOG_TRACE(Lib_Vdec2, "called");
if (!decoder) { if (!decoder) {
LOG_ERROR(Lib_Vdec2, "Invalid decoder instance");
return ORBIS_VIDEODEC2_ERROR_DECODER_INSTANCE; return ORBIS_VIDEODEC2_ERROR_DECODER_INSTANCE;
} }
if (!inputData || !frameBuffer || !outputInfo) { if (!inputData || !frameBuffer || !outputInfo) {
LOG_ERROR(Lib_Vdec2, "Invalid arguments");
return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER; return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER;
} }
if (inputData->thisSize != sizeof(OrbisVideodec2InputData) || if (inputData->thisSize != sizeof(OrbisVideodec2InputData) ||
frameBuffer->thisSize != sizeof(OrbisVideodec2FrameBuffer)) { frameBuffer->thisSize != sizeof(OrbisVideodec2FrameBuffer)) {
LOG_ERROR(Lib_Vdec2, "Invalid struct size");
return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE; return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE;
} }
@ -122,13 +132,16 @@ s32 PS4_SYSV_ABI sceVideodec2Flush(OrbisVideodec2Decoder decoder,
LOG_INFO(Lib_Vdec2, "called"); LOG_INFO(Lib_Vdec2, "called");
if (!decoder) { if (!decoder) {
LOG_ERROR(Lib_Vdec2, "Invalid decoder instance");
return ORBIS_VIDEODEC2_ERROR_DECODER_INSTANCE; return ORBIS_VIDEODEC2_ERROR_DECODER_INSTANCE;
} }
if (!frameBuffer || !outputInfo) { if (!frameBuffer || !outputInfo) {
LOG_ERROR(Lib_Vdec2, "Invalid arguments");
return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER; return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER;
} }
if (frameBuffer->thisSize != sizeof(OrbisVideodec2FrameBuffer) || if (frameBuffer->thisSize != sizeof(OrbisVideodec2FrameBuffer) ||
outputInfo->thisSize != sizeof(OrbisVideodec2OutputInfo)) { outputInfo->thisSize != sizeof(OrbisVideodec2OutputInfo)) {
LOG_ERROR(Lib_Vdec2, "Invalid struct size");
return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE; return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE;
} }
@ -139,6 +152,7 @@ s32 PS4_SYSV_ABI sceVideodec2Reset(OrbisVideodec2Decoder decoder) {
LOG_INFO(Lib_Vdec2, "called"); LOG_INFO(Lib_Vdec2, "called");
if (!decoder) { if (!decoder) {
LOG_ERROR(Lib_Vdec2, "Invalid decoder instance");
return ORBIS_VIDEODEC2_ERROR_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"); LOG_TRACE(Lib_Vdec2, "called");
if (!outputInfo) { if (!outputInfo) {
LOG_ERROR(Lib_Vdec2, "Invalid arguments");
return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER; return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER;
} }
if (outputInfo->thisSize != sizeof(OrbisVideodec2OutputInfo)) { if (outputInfo->thisSize != sizeof(OrbisVideodec2OutputInfo)) {
LOG_ERROR(Lib_Vdec2, "Invalid struct size");
return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE; return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE;
} }
if (outputInfo->pictureCount == 0 || gPictureInfos.empty()) { if (outputInfo->pictureCount == 0 || gPictureInfos.empty()) {
LOG_ERROR(Lib_Vdec2, "No picture info available");
return ORBIS_OK; return ORBIS_OK;
} }
@ -163,6 +180,7 @@ s32 PS4_SYSV_ABI sceVideodec2GetPictureInfo(const OrbisVideodec2OutputInfo* outp
OrbisVideodec2AvcPictureInfo* picInfo = OrbisVideodec2AvcPictureInfo* picInfo =
static_cast<OrbisVideodec2AvcPictureInfo*>(p1stPictureInfoOut); static_cast<OrbisVideodec2AvcPictureInfo*>(p1stPictureInfoOut);
if (picInfo->thisSize != sizeof(OrbisVideodec2AvcPictureInfo)) { if (picInfo->thisSize != sizeof(OrbisVideodec2AvcPictureInfo)) {
LOG_ERROR(Lib_Vdec2, "Invalid struct size");
return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE; return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE;
} }
*picInfo = gPictureInfos.back(); *picInfo = gPictureInfos.back();

View File

@ -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) { if (ev->ident != static_cast<s32>(OrbisVideoOutInternalEventId::Flip) || ev->data == 0) {
*data = event_data; *data = event_data;
} else { } else {
*data = event_data | 0xFFFF000000000000; *data = event_data | 0xffff000000000000;
} }
return ORBIS_OK; return ORBIS_OK;
} }
@ -233,7 +233,8 @@ s32 PS4_SYSV_ABI sceVideoOutGetEventCount(const Kernel::SceKernelEvent* ev) {
return ORBIS_VIDEO_OUT_ERROR_INVALID_EVENT; 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) { s32 PS4_SYSV_ABI sceVideoOutGetFlipStatus(s32 handle, FlipStatus* status) {

View File

@ -111,6 +111,12 @@ struct SceVideoOutColorSettings {
u32 reserved[3]; u32 reserved[3];
}; };
struct OrbisVideoOutEventData {
u64 time : 12;
u64 count : 4;
u64 flip_arg : 48;
};
void PS4_SYSV_ABI sceVideoOutSetBufferAttribute(BufferAttribute* attribute, PixelFormat pixelFormat, void PS4_SYSV_ABI sceVideoOutSetBufferAttribute(BufferAttribute* attribute, PixelFormat pixelFormat,
u32 tilingMode, u32 aspectRatio, u32 width, u32 tilingMode, u32 aspectRatio, u32 width,
u32 height, u32 pitchInPixel); 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, s32 PS4_SYSV_ABI sceVideoOutOpen(SceUserServiceUserId userId, s32 busType, s32 index,
const void* param); const void* param);
s32 PS4_SYSV_ABI sceVideoOutClose(s32 handle); s32 PS4_SYSV_ABI sceVideoOutClose(s32 handle);
int PS4_SYSV_ABI sceVideoOutGetEventId(const Kernel::SceKernelEvent* ev); s32 PS4_SYSV_ABI sceVideoOutGetEventId(const Kernel::SceKernelEvent* ev);
int PS4_SYSV_ABI sceVideoOutGetEventData(const Kernel::SceKernelEvent* ev, int64_t* data); s32 PS4_SYSV_ABI sceVideoOutGetEventData(const Kernel::SceKernelEvent* ev, s64* data);
s32 PS4_SYSV_ABI sceVideoOutColorSettingsSetGamma(SceVideoOutColorSettings* settings, float gamma); s32 PS4_SYSV_ABI sceVideoOutColorSettingsSetGamma(SceVideoOutColorSettings* settings, float gamma);
s32 PS4_SYSV_ABI sceVideoOutAdjustColor(s32 handle, const SceVideoOutColorSettings* settings); s32 PS4_SYSV_ABI sceVideoOutAdjustColor(s32 handle, const SceVideoOutColorSettings* settings);

View File

@ -12,6 +12,7 @@
#include "common/thread.h" #include "common/thread.h"
#include "core/aerolib/aerolib.h" #include "core/aerolib/aerolib.h"
#include "core/aerolib/stubs.h" #include "core/aerolib/stubs.h"
#include "core/devtools/widget/module_list.h"
#include "core/libraries/kernel/memory.h" #include "core/libraries/kernel/memory.h"
#include "core/libraries/kernel/threads.h" #include "core/libraries/kernel/threads.h"
#include "core/linker.h" #include "core/linker.h"
@ -127,7 +128,7 @@ void Linker::Execute(const std::vector<std::string> args) {
} }
} }
params.entry_addr = module->GetEntryAddress(); params.entry_addr = module->GetEntryAddress();
RunMainEntry(&params); ExecuteGuest(RunMainEntry, &params);
}); });
} }
@ -147,6 +148,9 @@ s32 Linker::LoadModule(const std::filesystem::path& elf_name, bool is_dynamic) {
num_static_modules += !is_dynamic; num_static_modules += !is_dynamic;
m_modules.emplace_back(std::move(module)); m_modules.emplace_back(std::move(module));
Core::Devtools::Widget::ModuleList::AddModule(elf_name.filename().string(), elf_name);
return m_modules.size() - 1; return m_modules.size() - 1;
} }
@ -325,6 +329,9 @@ bool Linker::Resolve(const std::string& name, Loader::SymbolType sym_type, Modul
} }
if (record) { if (record) {
*return_info = *record; *return_info = *record;
Core::Devtools::Widget::ModuleList::AddModule(sr.library);
return true; return true;
} }
@ -366,7 +373,8 @@ void* Linker::TlsGetAddr(u64 module_index, u64 offset) {
if (!addr) { if (!addr) {
// Module was just loaded by above code. Allocate TLS block for it. // Module was just loaded by above code. Allocate TLS block for it.
const u32 init_image_size = module->tls.init_image_size; 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); const u8* src = reinterpret_cast<const u8*>(module->tls.image_virtual_addr);
std::memcpy(dest, src, init_image_size); std::memcpy(dest, src, init_image_size);
std::memset(dest + init_image_size, 0, module->tls.image_size - init_image_size); std::memset(dest + init_image_size, 0, module->tls.image_size - init_image_size);

View File

@ -83,7 +83,7 @@ public:
} }
Module* GetModule(s32 index) const { 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 m_modules.at(index).get();
} }
return nullptr; return nullptr;

View File

@ -75,7 +75,8 @@ u64 MemoryManager::ClampRangeSize(VAddr virtual_addr, u64 size) {
// Clamp size to the remaining size of the current VMA. // Clamp size to the remaining size of the current VMA.
auto vma = FindVMA(virtual_addr); 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; u64 clamped_size = vma->second.base + vma->second.size - virtual_addr;
++vma; ++vma;
@ -96,6 +97,8 @@ u64 MemoryManager::ClampRangeSize(VAddr virtual_addr, u64 size) {
bool MemoryManager::TryWriteBacking(void* address, const void* data, u32 num_bytes) { bool MemoryManager::TryWriteBacking(void* address, const void* data, u32 num_bytes) {
const VAddr virtual_addr = std::bit_cast<VAddr>(address); const VAddr virtual_addr = std::bit_cast<VAddr>(address);
const auto& vma = FindVMA(virtual_addr)->second; 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) { if (vma.type != VMAType::Direct) {
return false; 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) { PAddr MemoryManager::PoolExpand(PAddr search_start, PAddr search_end, size_t size, u64 alignment) {
std::scoped_lock lk{mutex}; std::scoped_lock lk{mutex};
alignment = alignment > 0 ? alignment : 64_KB;
auto dmem_area = FindDmemArea(search_start); 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 = [&] { // Find the first free, large enough dmem area in the range.
const auto aligned_base = alignment > 0 ? Common::AlignUp(dmem_area->second.base, alignment) while (!dmem_area->second.is_free || dmem_area->second.GetEnd() < mapping_end) {
: dmem_area->second.base; // The current dmem_area isn't suitable, move to the next one.
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) {
dmem_area++; dmem_area++;
if (dmem_area == dmem_map.end()) {
break;
} }
ASSERT_MSG(is_suitable(), "Unable to find free direct memory area: size = {:#x}", size);
// Align free position // Update local variables based on the new dmem_area
PAddr free_addr = dmem_area->second.base; mapping_start = Common::AlignUp(dmem_area->second.base, alignment);
free_addr = alignment > 0 ? Common::AlignUp(free_addr, alignment) : free_addr; 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. // 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_free = false;
area.is_pooled = true; 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, PAddr MemoryManager::Allocate(PAddr search_start, PAddr search_end, size_t size, u64 alignment,
@ -145,10 +159,12 @@ PAddr MemoryManager::Allocate(PAddr search_start, PAddr search_end, size_t size,
auto mapping_end = mapping_start + size; auto mapping_end = mapping_start + size;
// Find the first free, large enough dmem area in the range. // Find the first free, large enough dmem area in the range.
while ((!dmem_area->second.is_free || dmem_area->second.GetEnd() < mapping_end) && while (!dmem_area->second.is_free || dmem_area->second.GetEnd() < mapping_end) {
dmem_area != dmem_map.end()) {
// The current dmem_area isn't suitable, move to the next one. // The current dmem_area isn't suitable, move to the next one.
dmem_area++; dmem_area++;
if (dmem_area == dmem_map.end()) {
break;
}
// Update local variables based on the new dmem_area // Update local variables based on the new dmem_area
mapping_start = Common::AlignUp(dmem_area->second.base, alignment); mapping_start = Common::AlignUp(dmem_area->second.base, alignment);
@ -172,7 +188,6 @@ void MemoryManager::Free(PAddr phys_addr, size_t size) {
std::scoped_lock lk{mutex}; std::scoped_lock lk{mutex};
auto dmem_area = CarveDmemArea(phys_addr, size); 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. // Release any dmem mappings that reference this physical block.
std::vector<std::pair<VAddr, u64>> remove_list; std::vector<std::pair<VAddr, u64>> remove_list;
@ -202,26 +217,32 @@ void MemoryManager::Free(PAddr phys_addr, size_t size) {
int MemoryManager::PoolReserve(void** out_addr, VAddr virtual_addr, size_t size, int MemoryManager::PoolReserve(void** out_addr, VAddr virtual_addr, size_t size,
MemoryMapFlags flags, u64 alignment) { MemoryMapFlags flags, u64 alignment) {
std::scoped_lock lk{mutex}; std::scoped_lock lk{mutex};
virtual_addr = (virtual_addr == 0) ? impl.SystemManagedVirtualBase() : virtual_addr;
alignment = alignment > 0 ? alignment : 2_MB; 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. // Fixed mapping means the virtual address must exactly match the provided one.
if (True(flags & MemoryMapFlags::Fixed)) { if (True(flags & MemoryMapFlags::Fixed)) {
auto& vma = FindVMA(mapped_addr)->second; // Make sure we're mapping to a valid address
// If the VMA is mapped, unmap the region first. mapped_addr = mapped_addr > min_address ? mapped_addr : min_address;
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); UnmapMemoryImpl(mapped_addr, size);
vma = FindVMA(mapped_addr)->second; 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)) { 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); 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 // Add virtual memory area
@ -229,9 +250,8 @@ int MemoryManager::PoolReserve(void** out_addr, VAddr virtual_addr, size_t size,
auto& new_vma = new_vma_handle->second; auto& new_vma = new_vma_handle->second;
new_vma.disallow_merge = True(flags & MemoryMapFlags::NoCoalesce); new_vma.disallow_merge = True(flags & MemoryMapFlags::NoCoalesce);
new_vma.prot = MemoryProt::NoAccess; new_vma.prot = MemoryProt::NoAccess;
new_vma.name = ""; new_vma.name = "anon";
new_vma.type = VMAType::PoolReserved; new_vma.type = VMAType::PoolReserved;
MergeAdjacent(vma_map, new_vma_handle);
*out_addr = std::bit_cast<void*>(mapped_addr); *out_addr = std::bit_cast<void*>(mapped_addr);
return ORBIS_OK; return ORBIS_OK;
@ -247,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. // Fixed mapping means the virtual address must exactly match the provided one.
if (True(flags & MemoryMapFlags::Fixed)) { if (True(flags & MemoryMapFlags::Fixed)) {
auto& vma = FindVMA(mapped_addr)->second; auto vma = FindVMA(mapped_addr)->second;
// If the VMA is mapped, unmap the region first. size_t remaining_size = vma.base + vma.size - mapped_addr;
if (vma.IsMapped()) { // 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); UnmapMemoryImpl(mapped_addr, size);
vma = FindVMA(mapped_addr)->second; 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. // Find the first free area starting with provided virtual address.
if (False(flags & MemoryMapFlags::Fixed)) { if (False(flags & MemoryMapFlags::Fixed)) {
mapped_addr = SearchFree(mapped_addr, size, alignment); 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 // Add virtual memory area
@ -267,7 +290,7 @@ int MemoryManager::Reserve(void** out_addr, VAddr virtual_addr, size_t size, Mem
auto& new_vma = new_vma_handle->second; auto& new_vma = new_vma_handle->second;
new_vma.disallow_merge = True(flags & MemoryMapFlags::NoCoalesce); new_vma.disallow_merge = True(flags & MemoryMapFlags::NoCoalesce);
new_vma.prot = MemoryProt::NoAccess; new_vma.prot = MemoryProt::NoAccess;
new_vma.name = ""; new_vma.name = "anon";
new_vma.type = VMAType::Reserved; new_vma.type = VMAType::Reserved;
MergeAdjacent(vma_map, new_vma_handle); MergeAdjacent(vma_map, new_vma_handle);
@ -280,29 +303,51 @@ int MemoryManager::PoolCommit(VAddr virtual_addr, size_t size, MemoryProt prot)
const u64 alignment = 64_KB; const u64 alignment = 64_KB;
// When virtual addr is zero, force it to virtual_base. The guest cannot pass Fixed // Input addresses to PoolCommit are treated as fixed.
// flag so we will take the branch that searches for free (or reserved) mappings.
virtual_addr = (virtual_addr == 0) ? impl.SystemManagedVirtualBase() : virtual_addr;
VAddr mapped_addr = Common::AlignUp(virtual_addr, alignment); VAddr mapped_addr = Common::AlignUp(virtual_addr, alignment);
// This should return SCE_KERNEL_ERROR_ENOMEM but shouldn't normally happen. auto& vma = FindVMA(mapped_addr)->second;
const auto& vma = FindVMA(mapped_addr)->second; if (vma.type != VMAType::PoolReserved) {
const size_t remaining_size = vma.base + vma.size - mapped_addr; // If we're attempting to commit non-pooled memory, return EINVAL
ASSERT_MSG(!vma.IsMapped() && remaining_size >= size); LOG_ERROR(Kernel_Vmm, "Attempting to commit non-pooled memory at {:#x}", mapped_addr);
return ORBIS_KERNEL_ERROR_EINVAL;
}
// Perform the mapping. if (!vma.Contains(mapped_addr, size)) {
void* out_addr = impl.Map(mapped_addr, size, alignment, -1, false); // If there's not enough space to commit, return EINVAL
TRACK_ALLOC(out_addr, size, "VMEM"); 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.disallow_merge = false;
new_vma.prot = prot; new_vma.prot = prot;
new_vma.name = ""; new_vma.name = "anon";
new_vma.type = Core::VMAType::Pooled; new_vma.type = Core::VMAType::Pooled;
new_vma.is_exec = false; new_vma.is_exec = false;
new_vma.phys_base = 0; new_vma.phys_base = 0;
// 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); rasterizer->MapMemory(mapped_addr, size);
}
return ORBIS_OK; return ORBIS_OK;
} }
@ -317,23 +362,44 @@ int MemoryManager::MapMemory(void** out_addr, VAddr virtual_addr, size_t size, M
return ORBIS_KERNEL_ERROR_ENOMEM; return ORBIS_KERNEL_ERROR_ENOMEM;
} }
// When virtual addr is zero, force it to virtual_base. The guest cannot pass Fixed // Limit the minumum address to SystemManagedVirtualBase to prevent hardware-specific issues.
// flag so we will take the branch that searches for free (or reserved) mappings. VAddr mapped_addr = (virtual_addr == 0) ? impl.SystemManagedVirtualBase() : virtual_addr;
virtual_addr = (virtual_addr == 0) ? impl.SystemManagedVirtualBase() : virtual_addr;
alignment = alignment > 0 ? alignment : 16_KB;
VAddr mapped_addr = alignment > 0 ? Common::AlignUp(virtual_addr, alignment) : virtual_addr;
// Fixed mapping means the virtual address must exactly match the provided one. // Fixed mapping means the virtual address must exactly match the provided one.
if (True(flags & MemoryMapFlags::Fixed)) { if (True(flags & MemoryMapFlags::Fixed)) {
// This should return SCE_KERNEL_ERROR_ENOMEM but shouldn't normally happen. auto vma = FindVMA(mapped_addr)->second;
const auto& vma = FindVMA(mapped_addr)->second; size_t remaining_size = vma.base + vma.size - mapped_addr;
const 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.
ASSERT_MSG(!vma.IsMapped() && remaining_size >= size); // To account for this, unmap any reserved areas within this mapping range first.
auto unmap_addr = mapped_addr;
auto unmap_size = size;
// If flag NoOverwrite is provided, don't overwrite mapped VMAs.
// When it isn't provided, VMAs can be overwritten regardless of if they're mapped.
while ((False(flags & MemoryMapFlags::NoOverwrite) || !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;
}
vma = FindVMA(mapped_addr)->second;
remaining_size = vma.base + vma.size - mapped_addr;
if (vma.IsMapped() || remaining_size < size) {
LOG_ERROR(Kernel_Vmm, "Unable to map {:#x} bytes at address {:#x}", size, mapped_addr);
return ORBIS_KERNEL_ERROR_ENOMEM;
}
} }
// Find the first free area starting with provided virtual address. // Find the first free area starting with provided virtual address.
if (False(flags & MemoryMapFlags::Fixed)) { if (False(flags & MemoryMapFlags::Fixed)) {
mapped_addr = SearchFree(mapped_addr, size, alignment); // Provided address needs to be aligned before we can map.
alignment = alignment > 0 ? alignment : 16_KB;
mapped_addr = SearchFree(Common::AlignUp(mapped_addr, alignment), size, alignment);
if (mapped_addr == -1) {
// No suitable memory areas to map to
return ORBIS_KERNEL_ERROR_ENOMEM;
}
} }
// Perform the mapping. // Perform the mapping.
@ -353,7 +419,10 @@ int MemoryManager::MapMemory(void** out_addr, VAddr virtual_addr, size_t size, M
if (type == VMAType::Flexible) { if (type == VMAType::Flexible) {
flexible_usage += size; flexible_usage += size;
} }
if (IsValidGpuMapping(mapped_addr, size)) {
rasterizer->MapMemory(mapped_addr, size); rasterizer->MapMemory(mapped_addr, size);
}
return ORBIS_OK; return ORBIS_OK;
} }
@ -366,12 +435,18 @@ int MemoryManager::MapFile(void** out_addr, VAddr virtual_addr, size_t size, Mem
// Find first free area to map the file. // Find first free area to map the file.
if (False(flags & MemoryMapFlags::Fixed)) { if (False(flags & MemoryMapFlags::Fixed)) {
mapped_addr = SearchFree(mapped_addr, size_aligned, 1); 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)) { if (True(flags & MemoryMapFlags::Fixed)) {
const auto& vma = FindVMA(virtual_addr)->second; const auto& vma = FindVMA(virtual_addr)->second;
const size_t remaining_size = vma.base + vma.size - virtual_addr; 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. // Map the file.
@ -389,7 +464,7 @@ int MemoryManager::MapFile(void** out_addr, VAddr virtual_addr, size_t size, Mem
return ORBIS_OK; 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}; std::scoped_lock lk{mutex};
const auto it = FindVMA(virtual_addr); const auto it = FindVMA(virtual_addr);
@ -404,7 +479,19 @@ void MemoryManager::PoolDecommit(VAddr virtual_addr, size_t size) {
const auto start_in_vma = virtual_addr - vma_base_addr; const auto start_in_vma = virtual_addr - vma_base_addr;
const auto type = vma_base.type; const auto type = vma_base.type;
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); rasterizer->UnmapMemory(virtual_addr, size);
}
// Mark region as free and attempt to coalesce it with neighbours. // Mark region as free and attempt to coalesce it with neighbours.
const auto new_it = CarveVMA(virtual_addr, size); const auto new_it = CarveVMA(virtual_addr, size);
@ -413,15 +500,19 @@ void MemoryManager::PoolDecommit(VAddr virtual_addr, size_t size) {
vma.prot = MemoryProt::NoAccess; vma.prot = MemoryProt::NoAccess;
vma.phys_base = 0; vma.phys_base = 0;
vma.disallow_merge = false; vma.disallow_merge = false;
vma.name = ""; vma.name = "anon";
MergeAdjacent(vma_map, new_it); MergeAdjacent(vma_map, new_it);
if (type != VMAType::PoolReserved) {
// Unmap the memory region. // Unmap the memory region.
impl.Unmap(vma_base_addr, vma_base_size, start_in_vma, start_in_vma + size, phys_base, is_exec, impl.Unmap(vma_base_addr, vma_base_size, start_in_vma, start_in_vma + size, phys_base,
false, false); is_exec, false, false);
TRACK_FREE(virtual_addr, "VMEM"); TRACK_FREE(virtual_addr, "VMEM");
} }
return ORBIS_OK;
}
s32 MemoryManager::UnmapMemory(VAddr virtual_addr, size_t size) { s32 MemoryManager::UnmapMemory(VAddr virtual_addr, size_t size) {
std::scoped_lock lk{mutex}; std::scoped_lock lk{mutex};
return UnmapMemoryImpl(virtual_addr, size); return UnmapMemoryImpl(virtual_addr, size);
@ -444,7 +535,10 @@ u64 MemoryManager::UnmapBytesFromEntry(VAddr virtual_addr, VirtualMemoryArea vma
if (type == VMAType::Flexible) { if (type == VMAType::Flexible) {
flexible_usage -= adjusted_size; flexible_usage -= adjusted_size;
} }
if (IsValidGpuMapping(virtual_addr, adjusted_size)) {
rasterizer->UnmapMemory(virtual_addr, adjusted_size); rasterizer->UnmapMemory(virtual_addr, adjusted_size);
}
// Mark region as free and attempt to coalesce it with neighbours. // Mark region as free and attempt to coalesce it with neighbours.
const auto new_it = CarveVMA(virtual_addr, adjusted_size); const auto new_it = CarveVMA(virtual_addr, adjusted_size);
@ -471,6 +565,8 @@ s32 MemoryManager::UnmapMemoryImpl(VAddr virtual_addr, u64 size) {
do { do {
auto it = FindVMA(virtual_addr + unmapped_bytes); auto it = FindVMA(virtual_addr + unmapped_bytes);
auto& vma_base = it->second; 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 = auto unmapped =
UnmapBytesFromEntry(virtual_addr + unmapped_bytes, vma_base, size - unmapped_bytes); UnmapBytesFromEntry(virtual_addr + unmapped_bytes, vma_base, size - unmapped_bytes);
ASSERT_MSG(unmapped > 0, "Failed to unmap memory, progress is impossible"); ASSERT_MSG(unmapped > 0, "Failed to unmap memory, progress is impossible");
@ -485,7 +581,10 @@ int MemoryManager::QueryProtection(VAddr addr, void** start, void** end, u32* pr
const auto it = FindVMA(addr); const auto it = FindVMA(addr);
const auto& vma = it->second; 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) { if (start != nullptr) {
*start = reinterpret_cast<void*>(vma.base); *start = reinterpret_cast<void*>(vma.base);
@ -552,17 +651,23 @@ s64 MemoryManager::ProtectBytes(VAddr addr, VirtualMemoryArea vma_base, size_t s
s32 MemoryManager::Protect(VAddr addr, size_t size, MemoryProt prot) { s32 MemoryManager::Protect(VAddr addr, size_t size, MemoryProt prot) {
std::scoped_lock lk{mutex}; std::scoped_lock lk{mutex};
s64 protected_bytes = 0; s64 protected_bytes = 0;
auto aligned_addr = Common::AlignDown(addr, 16_KB);
auto aligned_size = Common::AlignUp(size + addr - aligned_addr, 16_KB);
do { do {
auto it = FindVMA(addr + protected_bytes); auto it = FindVMA(aligned_addr + protected_bytes);
auto& vma_base = it->second; 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; 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) { if (result < 0) {
// ProtectBytes returned an error, return it // ProtectBytes returned an error, return it
return result; return result;
} }
protected_bytes += result; protected_bytes += result;
} while (protected_bytes < size); } while (protected_bytes < aligned_size);
return ORBIS_OK; return ORBIS_OK;
} }
@ -571,8 +676,16 @@ int MemoryManager::VirtualQuery(VAddr addr, int flags,
::Libraries::Kernel::OrbisVirtualQueryInfo* info) { ::Libraries::Kernel::OrbisVirtualQueryInfo* info) {
std::scoped_lock lk{mutex}; std::scoped_lock lk{mutex};
auto it = FindVMA(addr); // FindVMA on addresses before the vma_map return garbage data.
if (it->second.type == VMAType::Free && flags == 1) { 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; ++it;
} }
if (it->second.type == VMAType::Free) { if (it->second.type == VMAType::Free) {
@ -585,15 +698,17 @@ int MemoryManager::VirtualQuery(VAddr addr, int flags,
info->end = vma.base + vma.size; info->end = vma.base + vma.size;
info->offset = vma.phys_base; info->offset = vma.phys_base;
info->protection = static_cast<s32>(vma.prot); info->protection = static_cast<s32>(vma.prot);
info->is_flexible.Assign(vma.type == VMAType::Flexible); info->is_flexible = vma.type == VMAType::Flexible ? 1 : 0;
info->is_direct.Assign(vma.type == VMAType::Direct); info->is_direct = vma.type == VMAType::Direct ? 1 : 0;
info->is_stack.Assign(vma.type == VMAType::Stack); info->is_stack = vma.type == VMAType::Stack ? 1 : 0;
info->is_pooled.Assign(vma.type == VMAType::PoolReserved || vma.type == VMAType::Pooled); info->is_pooled = vma.type == VMAType::PoolReserved || vma.type == VMAType::Pooled ? 1 : 0;
info->is_committed.Assign(vma.IsMapped()); info->is_committed = vma.IsMapped() ? 1 : 0;
vma.name.copy(info->name.data(), std::min(info->name.size(), vma.name.size()));
strncpy(info->name, vma.name.data(), ::Libraries::Kernel::ORBIS_KERNEL_MAXIMUM_NAME_LENGTH);
if (vma.type == VMAType::Direct) { if (vma.type == VMAType::Direct) {
const auto dmem_it = FindDmemArea(vma.phys_base); 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; info->memory_type = dmem_it->second.memory_type;
} else { } else {
info->memory_type = ::Libraries::Kernel::SCE_KERNEL_WB_ONION; info->memory_type = ::Libraries::Kernel::SCE_KERNEL_WB_ONION;
@ -607,11 +722,11 @@ int MemoryManager::DirectMemoryQuery(PAddr addr, bool find_next,
std::scoped_lock lk{mutex}; std::scoped_lock lk{mutex};
auto dmem_area = FindDmemArea(addr); 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++; 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!"); LOG_ERROR(Core, "Unable to find allocated direct memory region to query!");
return ORBIS_KERNEL_ERROR_EACCES; return ORBIS_KERNEL_ERROR_EACCES;
} }
@ -670,6 +785,19 @@ int MemoryManager::DirectQueryAvailable(PAddr search_start, PAddr search_end, si
return ORBIS_OK; return ORBIS_OK;
} }
s32 MemoryManager::SetDirectMemoryType(s64 phys_addr, s32 memory_type) {
std::scoped_lock lk{mutex};
auto& dmem_area = FindDmemArea(phys_addr)->second;
ASSERT_MSG(phys_addr <= dmem_area.GetEnd() && !dmem_area.is_free,
"Direct memory area is not mapped");
dmem_area.memory_type = memory_type;
return ORBIS_OK;
}
void MemoryManager::NameVirtualRange(VAddr virtual_addr, size_t size, std::string_view name) { void MemoryManager::NameVirtualRange(VAddr virtual_addr, size_t size, std::string_view name) {
auto it = FindVMA(virtual_addr); auto it = FindVMA(virtual_addr);
@ -691,36 +819,56 @@ VAddr MemoryManager::SearchFree(VAddr virtual_addr, size_t size, u32 alignment)
virtual_addr = min_search_address; 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); 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 the VMA is free and contains the requested mapping we are done.
if (it->second.IsFree() && it->second.Contains(virtual_addr, size)) { if (it->second.IsFree() && it->second.Contains(virtual_addr, size)) {
return virtual_addr; return virtual_addr;
} }
// Search for the first free VMA that fits our mapping. // Search for the first free VMA that fits our mapping.
const auto is_suitable = [&] { while (it != vma_map.end()) {
if (!it->second.IsFree()) { if (!it->second.IsFree()) {
return false; it++;
continue;
} }
const auto& vma = it->second; const auto& vma = it->second;
virtual_addr = Common::AlignUp(vma.base, alignment); virtual_addr = Common::AlignUp(vma.base, alignment);
// Sometimes the alignment itself might be larger than the VMA. // Sometimes the alignment itself might be larger than the VMA.
if (virtual_addr > vma.base + vma.size) { 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; const size_t remaining_size = vma.base + vma.size - virtual_addr;
return remaining_size >= size; if (remaining_size >= size) {
};
while (!is_suitable()) {
++it;
}
return virtual_addr; return virtual_addr;
} }
it++;
}
// 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) { MemoryManager::VMAHandle MemoryManager::CarveVMA(VAddr virtual_addr, size_t size) {
auto vma_handle = FindVMA(virtual_addr); 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; const VirtualMemoryArea& vma = vma_handle->second;
ASSERT_MSG(vma.base <= virtual_addr, "Adding a mapping to already mapped region"); ASSERT_MSG(vma.base <= virtual_addr, "Adding a mapping to already mapped region");
@ -749,7 +897,7 @@ MemoryManager::VMAHandle MemoryManager::CarveVMA(VAddr virtual_addr, size_t size
MemoryManager::DMemHandle MemoryManager::CarveDmemArea(PAddr addr, size_t size) { MemoryManager::DMemHandle MemoryManager::CarveDmemArea(PAddr addr, size_t size) {
auto dmem_handle = FindDmemArea(addr); 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; const DirectMemoryArea& area = dmem_handle->second;
ASSERT_MSG(area.base <= addr, "Adding an allocation to already allocated region"); ASSERT_MSG(area.base <= addr, "Adding an allocation to already allocated region");
@ -804,7 +952,7 @@ int MemoryManager::GetDirectMemoryType(PAddr addr, int* directMemoryTypeOut,
auto dmem_area = FindDmemArea(addr); 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!"); LOG_ERROR(Core, "Unable to find allocated direct memory region to check type!");
return ORBIS_KERNEL_ERROR_ENOENT; return ORBIS_KERNEL_ERROR_ENOENT;
} }
@ -816,4 +964,33 @@ int MemoryManager::GetDirectMemoryType(PAddr addr, int* directMemoryTypeOut,
return ORBIS_OK; 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 } // namespace Core

View File

@ -157,6 +157,12 @@ public:
return impl.SystemReservedVirtualBase(); 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 { bool IsValidAddress(const void* addr) const noexcept {
const VAddr virtual_addr = reinterpret_cast<VAddr>(addr); const VAddr virtual_addr = reinterpret_cast<VAddr>(addr);
const auto end_it = std::prev(vma_map.end()); 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 PoolCommit(VAddr virtual_addr, size_t size, MemoryProt prot);
int MapMemory(void** out_addr, 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); bool is_exec = false, PAddr phys_addr = -1, u64 alignment = 0);
int MapFile(void** out_addr, VAddr virtual_addr, size_t size, MemoryProt prot, int MapFile(void** out_addr, VAddr virtual_addr, size_t size, MemoryProt prot,
MemoryMapFlags flags, uintptr_t fd, size_t offset); 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); s32 UnmapMemory(VAddr virtual_addr, size_t size);
@ -213,10 +219,14 @@ public:
int GetDirectMemoryType(PAddr addr, int* directMemoryTypeOut, void** directMemoryStartOut, int GetDirectMemoryType(PAddr addr, int* directMemoryTypeOut, void** directMemoryStartOut,
void** directMemoryEndOut); void** directMemoryEndOut);
s32 SetDirectMemoryType(s64 phys_addr, s32 memory_type);
void NameVirtualRange(VAddr virtual_addr, size_t size, std::string_view name); void NameVirtualRange(VAddr virtual_addr, size_t size, std::string_view name);
void InvalidateMemory(VAddr addr, u64 size) const; void InvalidateMemory(VAddr addr, u64 size) const;
int IsStack(VAddr addr, void** start, void** end);
private: private:
VMAHandle FindVMA(VAddr target) { VMAHandle FindVMA(VAddr target) {
return std::prev(vma_map.upper_bound(target)); return std::prev(vma_map.upper_bound(target));
@ -268,6 +278,7 @@ private:
size_t total_direct_size{}; size_t total_direct_size{};
size_t total_flexible_size{}; size_t total_flexible_size{};
size_t flexible_usage{}; size_t flexible_usage{};
size_t pool_budget{};
Vulkan::Rasterizer* rasterizer{}; Vulkan::Rasterizer* rasterizer{};
friend class ::Core::Devtools::Widget::MemoryMapViewer; friend class ::Core::Devtools::Widget::MemoryMapViewer;

View File

@ -19,8 +19,7 @@ namespace Core {
using EntryFunc = PS4_SYSV_ABI int (*)(size_t args, const void* argp, void* param); using EntryFunc = PS4_SYSV_ABI int (*)(size_t args, const void* argp, void* param);
static u64 LoadOffset = CODE_BASE_OFFSET; static constexpr u64 ModuleLoadBase = 0x800000000;
static constexpr u64 CODE_BASE_INCR = 0x010000000u;
static u64 GetAlignedSize(const elf_program_header& phdr) { static u64 GetAlignedSize(const elf_program_header& phdr) {
return (phdr.p_align != 0 ? (phdr.p_memsz + (phdr.p_align - 1)) & ~(phdr.p_align - 1) 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) 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); elf.Open(file);
if (elf.IsElfFile()) { if (elf.IsElfFile()) {
LoadModuleToMemory(max_tls_index); LoadModuleToMemory(max_tls_index);
@ -113,10 +112,8 @@ void Module::LoadModuleToMemory(u32& max_tls_index) {
// Map module segments (and possible TLS trampolines) // Map module segments (and possible TLS trampolines)
void** out_addr = reinterpret_cast<void**>(&base_virtual_addr); void** out_addr = reinterpret_cast<void**>(&base_virtual_addr);
memory->MapMemory(out_addr, memory->SystemReservedVirtualBase() + LoadOffset, memory->MapMemory(out_addr, ModuleLoadBase, aligned_base_size + TrampolineSize,
aligned_base_size + TrampolineSize, MemoryProt::CpuReadWrite, MemoryProt::CpuReadWrite, MemoryMapFlags::NoFlags, VMAType::Code, name, true);
MemoryMapFlags::Fixed, VMAType::Code, name, true);
LoadOffset += CODE_BASE_INCR * (1 + aligned_base_size / CODE_BASE_INCR);
LOG_INFO(Core_Linker, "Loading module {} to {}", name, fmt::ptr(*out_addr)); LOG_INFO(Core_Linker, "Loading module {} to {}", name, fmt::ptr(*out_addr));
#ifdef ARCH_X86_64 #ifdef ARCH_X86_64
@ -135,10 +132,14 @@ void Module::LoadModuleToMemory(u32& max_tls_index) {
if (do_map) { if (do_map) {
elf.LoadSegment(segment_addr, phdr.p_offset, phdr.p_filesz); elf.LoadSegment(segment_addr, phdr.p_offset, phdr.p_filesz);
} }
if (info.num_segments < 4) {
auto& segment = info.segments[info.num_segments++]; auto& segment = info.segments[info.num_segments++];
segment.address = segment_addr; segment.address = segment_addr;
segment.prot = phdr.p_flags; segment.prot = phdr.p_flags;
segment.size = GetAlignedSize(phdr); 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++) { 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); LOG_INFO(Core_Linker, "program entry addr ..........: {:#018x}", entry_addr);
if (MemoryPatcher::g_eboot_address == 0) { if (MemoryPatcher::g_eboot_address == 0) {
if (name == "eboot") { if (name == "eboot.bin") {
MemoryPatcher::g_eboot_address = base_virtual_addr; MemoryPatcher::g_eboot_address = base_virtual_addr;
MemoryPatcher::g_eboot_image_size = base_size; MemoryPatcher::g_eboot_image_size = base_size;
MemoryPatcher::OnGameLoaded(); MemoryPatcher::OnGameLoaded();

View File

@ -3,6 +3,7 @@
#pragma once #pragma once
#include <cstring>
#include "common/types.h" #include "common/types.h"
namespace Xbyak { namespace Xbyak {
@ -41,10 +42,31 @@ Tcb* GetTcbBase();
/// Makes sure TLS is initialized for the thread before entering guest. /// Makes sure TLS is initialized for the thread before entering guest.
void EnsureThreadInitialized(); 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> template <class ReturnType, class... FuncArgs, class... CallArgs>
ReturnType ExecuteGuest(PS4_SYSV_ABI ReturnType (*func)(FuncArgs...), CallArgs&&... args) { ReturnType ExecuteGuest(PS4_SYSV_ABI ReturnType (*func)(FuncArgs...), CallArgs&&... args) {
EnsureThreadInitialized(); EnsureThreadInitialized();
// clear stack to avoid trash from EnsureThreadInitialized
ClearStack<12_KB>();
return func(std::forward<CallArgs>(args)...); 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 } // namespace Core

View File

@ -10,18 +10,22 @@
#include "common/logging/log.h" #include "common/logging/log.h"
#ifdef ENABLE_QT_GUI #ifdef ENABLE_QT_GUI
#include <QtCore> #include <QtCore>
#include "common/memory_patcher.h"
#endif #endif
#include "common/assert.h" #include "common/assert.h"
#ifdef ENABLE_DISCORD_RPC #ifdef ENABLE_DISCORD_RPC
#include "common/discord_rpc_handler.h" #include "common/discord_rpc_handler.h"
#endif #endif
#ifdef _WIN32
#include <WinSock2.h>
#endif
#include "common/elf_info.h" #include "common/elf_info.h"
#include "common/memory_patcher.h"
#include "common/ntapi.h" #include "common/ntapi.h"
#include "common/path_util.h" #include "common/path_util.h"
#include "common/polyfill_thread.h" #include "common/polyfill_thread.h"
#include "common/scm_rev.h" #include "common/scm_rev.h"
#include "common/singleton.h" #include "common/singleton.h"
#include "core/devtools/widget/module_list.h"
#include "core/file_format/psf.h" #include "core/file_format/psf.h"
#include "core/file_format/trp.h" #include "core/file_format/trp.h"
#include "core/file_sys/fs.h" #include "core/file_sys/fs.h"
@ -46,27 +50,10 @@ Emulator::Emulator() {
#ifdef _WIN32 #ifdef _WIN32
Common::NtApi::Initialize(); Common::NtApi::Initialize();
SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS); SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS);
#endif // need to init this in order for winsock2 to work
WORD versionWanted = MAKEWORD(2, 2);
// Create stdin/stdout/stderr WSADATA wsaData;
Common::Singleton<FileSys::HandleTable>::Instance()->CreateStdHandles(); WSAStartup(versionWanted, &wsaData);
// Defer until after logging is initialized.
memory = Core::Memory::Instance();
controllers = Common::Singleton<Input::GameControllers>::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");
#endif #endif
} }
@ -91,37 +78,43 @@ 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. // Applications expect to be run from /app0 so mount the file's parent path as app0.
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance(); 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 // 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 id;
std::string title; std::string title;
std::string app_version; std::string app_version;
u32 fw_version; u32 fw_version;
Common::PSFAttributes psf_attributes{}; Common::PSFAttributes psf_attributes{};
if (param_sfo_exists) {
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)) {
auto* param_sfo = Common::Singleton<PSF>::Instance(); auto* param_sfo = Common::Singleton<PSF>::Instance();
const bool success = param_sfo->Open(param_sfo_path); ASSERT_MSG(param_sfo->Open(param_sfo_path), "Failed to open param.sfo");
ASSERT_MSG(success, "Failed to open param.sfo");
const auto content_id = param_sfo->GetString("CONTENT_ID"); const auto content_id = param_sfo->GetString("CONTENT_ID");
ASSERT_MSG(content_id.has_value(), "Failed to get CONTENT_ID"); ASSERT_MSG(content_id.has_value(), "Failed to get CONTENT_ID");
id = std::string(*content_id, 7, 9);
if (Config::getSeparateLogFilesEnabled()) { id = std::string(*content_id, 7, 9);
Common::Log::Initialize(id + ".log"); title = param_sfo->GetString("TITLE").value_or("Unknown title");
Common::Log::Start(); 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;
} }
}
// 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, "Starting shadps4 emulator v{} ", Common::g_version);
LOG_INFO(Loader, "Revision {}", Common::g_scm_rev); LOG_INFO(Loader, "Revision {}", Common::g_scm_rev);
LOG_INFO(Loader, "Branch {}", Common::g_scm_branch); LOG_INFO(Loader, "Branch {}", Common::g_scm_branch);
@ -142,7 +135,36 @@ void Emulator::Run(const std::filesystem::path& file, const std::vector<std::str
LOG_INFO(Config, "Vulkan guestMarkers: {}", Config::getVkGuestMarkersEnabled()); LOG_INFO(Config, "Vulkan guestMarkers: {}", Config::getVkGuestMarkersEnabled());
LOG_INFO(Config, "Vulkan rdocEnable: {}", Config::isRdocEnabled()); 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();
controllers = Common::Singleton<Input::GameControllers>::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; Libraries::NpTrophy::game_serial = id;
const auto trophyDir = const auto trophyDir =
Common::FS::GetUserPath(Common::FS::PathType::MetaDataDir) / id / "TrophyFiles"; Common::FS::GetUserPath(Common::FS::PathType::MetaDataDir) / id / "TrophyFiles";
if (!std::filesystem::exists(trophyDir)) { if (!std::filesystem::exists(trophyDir)) {
@ -151,41 +173,9 @@ void Emulator::Run(const std::filesystem::path& file, const std::vector<std::str
LOG_ERROR(Loader, "Couldn't extract trophies"); 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.initialized = true;
game_info.game_serial = id; game_info.game_serial = id;
game_info.title = title; game_info.title = title;
@ -194,18 +184,33 @@ void Emulator::Run(const std::filesystem::path& file, const std::vector<std::str
game_info.raw_firmware_ver = fw_version; game_info.raw_firmware_ver = fw_version;
game_info.psf_attributes = psf_attributes; 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;
}
game_info.game_folder = game_folder;
std::string game_title = fmt::format("{} - {} <{}>", id, title, app_version); std::string game_title = fmt::format("{} - {} <{}>", id, title, app_version);
std::string window_title = ""; std::string window_title = "";
if (Common::g_is_release) {
window_title = fmt::format("shadPS4 v{} | {}", Common::g_version, game_title);
} else {
std::string remote_url(Common::g_scm_remote_url); std::string remote_url(Common::g_scm_remote_url);
std::string remote_host; std::string remote_host;
try { try {
if (*remote_url.rbegin() == '/') {
remote_url.pop_back();
}
remote_host = remote_url.substr(19, remote_url.rfind('/') - 19); remote_host = remote_url.substr(19, remote_url.rfind('/') - 19);
} catch (...) { } catch (...) {
remote_host = "unknown"; remote_host = "unknown";
} }
if (Common::g_is_release) {
if (remote_host == "shadps4-emu" || remote_url.length() == 0) {
window_title = fmt::format("shadPS4 v{} | {}", Common::g_version, game_title);
} else {
window_title =
fmt::format("shadPS4 {}/v{} | {}", remote_host, Common::g_version, game_title);
}
} else {
if (remote_host == "shadps4-emu" || remote_url.length() == 0) { if (remote_host == "shadps4-emu" || remote_url.length() == 0) {
window_title = fmt::format("shadPS4 v{} {} {} | {}", Common::g_version, window_title = fmt::format("shadPS4 v{} {} {} | {}", Common::g_version,
Common::g_scm_branch, Common::g_scm_desc, game_title); Common::g_scm_branch, Common::g_scm_desc, game_title);
@ -224,11 +229,15 @@ void Emulator::Run(const std::filesystem::path& file, const std::vector<std::str
std::filesystem::create_directory(mount_data_dir); std::filesystem::create_directory(mount_data_dir);
} }
mnt->Mount(mount_data_dir, "/data"); // should just exist, manually create with game serial 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; const auto& mount_temp_dir = Common::FS::GetUserPath(Common::FS::PathType::TempDataDir) / id;
if (!std::filesystem::exists(mount_temp_dir)) { if (std::filesystem::exists(mount_temp_dir)) {
std::filesystem::create_directory(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"); mnt->Mount(mount_temp_dir, "/temp");
const auto& mount_download_dir = const auto& mount_download_dir =
@ -273,6 +282,25 @@ void Emulator::Run(const std::filesystem::path& file, const std::vector<std::str
} }
#endif #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); linker->Execute(args);
window->InitTimers(); window->InitTimers();

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