diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 787aba251..ceb915f6a 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -287,7 +287,7 @@ jobs:
sudo add-apt-repository 'deb http://apt.llvm.org/noble/ llvm-toolchain-noble-19 main'
- name: Install dependencies
- run: sudo apt-get update && sudo apt install -y libx11-dev libxext-dev libwayland-dev libdecor-0-dev libxkbcommon-dev libglfw3-dev libgles2-mesa-dev libfuse2 clang-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
uses: actions/cache@v4
@@ -309,7 +309,7 @@ jobs:
key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
- name: Configure CMake
- run: cmake --fresh -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE=ON -DCMAKE_C_COMPILER=clang-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
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'
- 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
uses: actions/cache@v4
@@ -370,7 +370,7 @@ jobs:
key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
- name: Configure CMake
- run: cmake --fresh -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE=ON -DCMAKE_C_COMPILER=clang-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
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $(nproc)
@@ -395,7 +395,7 @@ jobs:
submodules: recursive
- name: Install dependencies
- run: sudo apt-get update && sudo apt install -y libx11-dev libxext-dev libwayland-dev libdecor-0-dev libxkbcommon-dev libglfw3-dev libgles2-mesa-dev libfuse2 gcc-14 build-essential libasound2-dev libpulse-dev libopenal-dev libudev-dev
+ run: sudo apt-get update && sudo apt install -y libx11-dev libxext-dev libwayland-dev libdecor-0-dev libxkbcommon-dev libglfw3-dev libgles2-mesa-dev libfuse2 gcc-14 mold build-essential libasound2-dev libpulse-dev libopenal-dev libudev-dev
- name: Cache CMake Configuration
uses: actions/cache@v4
@@ -417,7 +417,7 @@ jobs:
key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
- name: Configure CMake
- run: cmake --fresh -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE=ON -DCMAKE_C_COMPILER=gcc-14 -DCMAKE_CXX_COMPILER=g++-14 -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
+ run: cmake --fresh -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE=ON -DCMAKE_C_COMPILER=gcc-14 -DCMAKE_CXX_COMPILER=g++-14 -DCMAKE_EXE_LINKER_FLAGS="-fuse-ld=mold" -DCMAKE_SHARED_LINKER_FLAGS="-fuse-ld=mold" -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
- name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $(nproc)
@@ -431,7 +431,7 @@ jobs:
submodules: recursive
- name: Install dependencies
- run: sudo apt-get update && sudo apt install -y libx11-dev libxext-dev libwayland-dev libdecor-0-dev libxkbcommon-dev libglfw3-dev libgles2-mesa-dev libfuse2 gcc-14 build-essential qt6-base-dev qt6-tools-dev qt6-multimedia-dev libasound2-dev libpulse-dev libopenal-dev libudev-dev
+ run: sudo apt-get update && sudo apt install -y libx11-dev libxext-dev libwayland-dev libdecor-0-dev libxkbcommon-dev libglfw3-dev libgles2-mesa-dev libfuse2 gcc-14 mold build-essential qt6-base-dev qt6-tools-dev qt6-multimedia-dev libasound2-dev libpulse-dev libopenal-dev libudev-dev
- name: Cache CMake Configuration
uses: actions/cache@v4
@@ -453,7 +453,7 @@ jobs:
key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
- name: Configure CMake
- run: cmake --fresh -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE=ON -DCMAKE_C_COMPILER=gcc-14 -DCMAKE_CXX_COMPILER=g++-14 -DENABLE_QT_GUI=ON -DENABLE_UPDATER=ON -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
+ run: cmake --fresh -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE=ON -DCMAKE_C_COMPILER=gcc-14 -DCMAKE_CXX_COMPILER=g++-14 -DCMAKE_EXE_LINKER_FLAGS="-fuse-ld=mold" -DCMAKE_SHARED_LINKER_FLAGS="-fuse-ld=mold" -DENABLE_QT_GUI=ON -DENABLE_UPDATER=ON -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
- name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $(nproc)
diff --git a/.gitmodules b/.gitmodules
index 065a4570f..25b5d307b 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -30,10 +30,6 @@
path = externals/xbyak
url = https://github.com/herumi/xbyak.git
shallow = true
-[submodule "externals/winpthreads"]
- path = externals/winpthreads
- url = https://github.com/shadps4-emu/winpthreads.git
- shallow = true
[submodule "externals/magic_enum"]
path = externals/magic_enum
url = https://github.com/Neargye/magic_enum.git
diff --git a/CMakeLists.txt b/CMakeLists.txt
old mode 100755
new mode 100644
index 96cce0b10..7962488c8
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -54,9 +54,9 @@ else()
endif()
if (ARCHITECTURE STREQUAL "x86_64")
- # Target the same CPU architecture as the PS4, to maintain the same level of compatibility.
- # Exclude SSE4a as it is only available on AMD CPUs.
- add_compile_options(-march=btver2 -mtune=generic -mno-sse4a)
+ # Target x86-64-v3 CPU architecture as this is a good balance between supporting performance critical
+ # instructions like AVX2 and maintaining support for older CPUs.
+ add_compile_options(-march=x86-64-v3)
endif()
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
OUTPUT_STRIP_TRAILING_WHITESPACE
)
+ message("got remote: ${GIT_REMOTE_NAME}")
endif()
# 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}")
elseif ("${PR_NUMBER}" STREQUAL "" AND NOT "${GITHUB_REF}" STREQUAL "")
set(GIT_BRANCH "${GITHUB_REF}")
- else()
+ elseif("${GIT_BRANCH}" STREQUAL "")
message("couldn't find branch")
set(GIT_BRANCH "detached-head")
endif()
@@ -186,8 +187,8 @@ else()
string(FIND "${GIT_REMOTE_NAME}" "/" INDEX)
if (INDEX GREATER -1)
string(SUBSTRING "${GIT_REMOTE_NAME}" 0 "${INDEX}" GIT_REMOTE_NAME)
- else()
- # If no remote is present (only a branch name), default to origin
+ elseif("${GIT_REMOTE_NAME}" STREQUAL "")
+ message("reset to origin")
set(GIT_REMOTE_NAME "origin")
endif()
endif()
@@ -202,7 +203,7 @@ execute_process(
# Set Version
set(EMULATOR_VERSION_MAJOR "0")
-set(EMULATOR_VERSION_MINOR "8")
+set(EMULATOR_VERSION_MINOR "9")
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}")
@@ -226,7 +227,7 @@ find_package(SDL3 3.1.2 CONFIG)
find_package(stb MODULE)
find_package(toml11 4.2.0 CONFIG)
find_package(tsl-robin-map 1.3.0 CONFIG)
-find_package(VulkanHeaders 1.4.309 CONFIG)
+find_package(VulkanHeaders 1.4.314 CONFIG)
find_package(VulkanMemoryAllocator 3.1.0 CONFIG)
find_package(xbyak 7.07 CONFIG)
find_package(xxHash 0.8.2 MODULE)
@@ -239,13 +240,6 @@ if (APPLE)
endif()
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")
# libc++ requires -fexperimental-library to enable std::jthread and std::stop_token support.
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.h
src/core/libraries/network/net_ctl_codes.h
+ src/core/libraries/network/net_util.cpp
+ src/core/libraries/network/net_util.h
+ src/core/libraries/network/net_error.h
src/core/libraries/network/net.h
src/core/libraries/network/ssl.cpp
src/core/libraries/network/ssl.h
src/core/libraries/network/ssl2.cpp
src/core/libraries/network/ssl2.h
+ src/core/libraries/network/sys_net.cpp
+ src/core/libraries/network/sys_net.h
+ src/core/libraries/network/posix_sockets.cpp
+ src/core/libraries/network/p2p_sockets.cpp
+ src/core/libraries/network/sockets.h
)
set(AVPLAYER_LIB src/core/libraries/avplayer/avplayer_common.cpp
@@ -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/savedata.cpp
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.h
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/ulobjmgr/ulobjmgr.cpp
src/core/libraries/ulobjmgr/ulobjmgr.h
+ src/core/libraries/signin_dialog/signindialog.cpp
+ src/core/libraries/signin_dialog/signindialog.h
)
+set(CAMERA_LIBS src/core/libraries/camera/camera.cpp
+ src/core/libraries/camera/camera.h
+ src/core/libraries/camera/camera_error.h
+)
+
+set(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
src/core/devtools/layer.h
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/memory_map.cpp
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.h
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/rdtsc.cpp
src/common/rdtsc.h
+ src/common/recursive_lock.cpp
+ src/common/recursive_lock.h
src/common/sha1.h
src/common/signal_context.h
src/common/signal_context.cpp
@@ -754,6 +772,8 @@ set(CORE src/core/aerolib/stubs.cpp
${FIBER_LIB}
${VDEC_LIB}
${VR_LIBS}
+ ${CAMERA_LIBS}
+ ${COMPANION_LIBS}
${DEV_TOOLS}
src/core/debug_state.cpp
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/ir_passes.h
src/shader_recompiler/ir/passes/lower_buffer_format_to_raw.cpp
+ src/shader_recompiler/ir/passes/lower_fp64_to_fp32.cpp
src/shader_recompiler/ir/passes/readlane_elimination_pass.cpp
src/shader_recompiler/ir/passes/resource_tracking_pass.cpp
src/shader_recompiler/ir/passes/ring_access_elimination.cpp
@@ -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_to_storage_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/attribute.cpp
src/shader_recompiler/ir/attribute.h
@@ -1077,9 +1099,13 @@ if (ENABLE_DISCORD_RPC)
target_compile_definitions(shadps4 PRIVATE ENABLE_DISCORD_RPC)
endif()
-# Optional due to https://github.com/shadps4-emu/shadPS4/issues/1704
-if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" AND ENABLE_USERFAULTFD)
- target_compile_definitions(shadps4 PRIVATE ENABLE_USERFAULTFD)
+if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
+ # Optional due to https://github.com/shadps4-emu/shadPS4/issues/1704
+ if (ENABLE_USERFAULTFD)
+ target_compile_definitions(shadps4 PRIVATE ENABLE_USERFAULTFD)
+ endif()
+
+ target_link_libraries(shadps4 PRIVATE uuid)
endif()
if (APPLE)
@@ -1135,7 +1161,7 @@ if (ENABLE_QT_GUI)
endif()
if (WIN32)
- target_link_libraries(shadps4 PRIVATE mincore winpthreads)
+ target_link_libraries(shadps4 PRIVATE mincore)
if (MSVC)
# MSVC likes putting opinions on what people can use, disable:
diff --git a/dist/net.shadps4.shadPS4.metainfo.xml b/dist/net.shadps4.shadPS4.metainfo.xml
index 9f7b4f9c5..493dc0df6 100644
--- a/dist/net.shadps4.shadPS4.metainfo.xml
+++ b/dist/net.shadps4.shadPS4.metainfo.xml
@@ -37,7 +37,10 @@
Game
-
+
+ https://github.com/shadps4-emu/shadPS4/releases/tag/v.0.9.0
+
+
https://github.com/shadps4-emu/shadPS4/releases/tag/v.0.8.0
diff --git a/documents/Quickstart/Quickstart.md b/documents/Quickstart/Quickstart.md
index 62df95e71..e2145ebbd 100644
--- a/documents/Quickstart/Quickstart.md
+++ b/documents/Quickstart/Quickstart.md
@@ -21,9 +21,9 @@ SPDX-License-Identifier: GPL-2.0-or-later
- A processor with at least 4 cores and 6 threads
- 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
- - **AMD**: Jaguar generation or newer
+ - **AMD**: Excavator generation or newer
- **Apple**: Rosetta 2 on macOS 15.4 or newer
### GPU
@@ -55,4 +55,4 @@ To configure the emulator, you can go through the interface and go to "settings"
You can also configure the emulator by editing the `config.toml` file located in the `user` folder created after the application is started (Mostly useful if you are using the SDL version).
Some settings may be related to more technical development and debugging.\
-For more information on this, see [**Debugging**](https://github.com/shadps4-emu/shadPS4/blob/main/documents/Debugging/Debugging.md#configuration).
\ No newline at end of file
+For more information on this, see [**Debugging**](https://github.com/shadps4-emu/shadPS4/blob/main/documents/Debugging/Debugging.md#configuration).
diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt
index b92e13795..89b0fbfdd 100644
--- a/externals/CMakeLists.txt
+++ b/externals/CMakeLists.txt
@@ -137,12 +137,6 @@ if (NOT TARGET Zydis::Zydis)
add_subdirectory(zydis)
endif()
-# Winpthreads
-if (WIN32)
- add_subdirectory(winpthreads)
- target_include_directories(winpthreads INTERFACE winpthreads/include)
-endif()
-
# sirit
add_subdirectory(sirit)
if (WIN32)
diff --git a/externals/MoltenVK/MoltenVK b/externals/MoltenVK/MoltenVK
index 87a8e8b13..3a0b07a24 160000
--- a/externals/MoltenVK/MoltenVK
+++ b/externals/MoltenVK/MoltenVK
@@ -1 +1 @@
-Subproject commit 87a8e8b13d4ad8835367fea1ebad1896d0460946
+Subproject commit 3a0b07a24a4a681ffe70b461b1f4333b2729e2ef
diff --git a/externals/MoltenVK/SPIRV-Cross b/externals/MoltenVK/SPIRV-Cross
index 791877574..969e75f7c 160000
--- a/externals/MoltenVK/SPIRV-Cross
+++ b/externals/MoltenVK/SPIRV-Cross
@@ -1 +1 @@
-Subproject commit 7918775748c5e2f5c40d9918ce68825035b5a1e1
+Subproject commit 969e75f7cc0718774231d029f9d52fa87d4ae1b2
diff --git a/externals/sdl3 b/externals/sdl3
index 4093e4a19..86b206dad 160000
--- a/externals/sdl3
+++ b/externals/sdl3
@@ -1 +1 @@
-Subproject commit 4093e4a193971ef1d4928158e0a1832be42e4599
+Subproject commit 86b206dadf8ad40e6657fa37db371a0aeff74e9c
diff --git a/externals/sirit b/externals/sirit
index 427a42c9e..6b450704f 160000
--- a/externals/sirit
+++ b/externals/sirit
@@ -1 +1 @@
-Subproject commit 427a42c9ed99b38204d9107bc3dc14e92458acf1
+Subproject commit 6b450704f6fedb9413d0c89a9eb59d028eb1e6c0
diff --git a/externals/vulkan-headers b/externals/vulkan-headers
index 5ceb9ed48..9c77de5c3 160000
--- a/externals/vulkan-headers
+++ b/externals/vulkan-headers
@@ -1 +1 @@
-Subproject commit 5ceb9ed481e58e705d0d9b5326537daedd06b97d
+Subproject commit 9c77de5c3dd216f28e407eec65ed9c0a296c1f74
diff --git a/externals/winpthreads b/externals/winpthreads
deleted file mode 160000
index f35b0948d..000000000
--- a/externals/winpthreads
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit f35b0948d36a736e6a2d052ae295a3ffde09703f
diff --git a/src/common/config.cpp b/src/common/config.cpp
index 6a0810346..e8bca3749 100644
--- a/src/common/config.cpp
+++ b/src/common/config.cpp
@@ -156,7 +156,7 @@ bool GetLoadGameSizeEnabled() {
std::filesystem::path GetSaveDataPath() {
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;
}
diff --git a/src/common/elf_info.h b/src/common/elf_info.h
index 062cee012..02b845cb5 100644
--- a/src/common/elf_info.h
+++ b/src/common/elf_info.h
@@ -71,6 +71,7 @@ class ElfInfo {
PSFAttributes psf_attributes{};
std::filesystem::path splash_path{};
+ std::filesystem::path game_folder{};
public:
static constexpr u32 FW_15 = 0x1500000;
@@ -123,6 +124,10 @@ public:
[[nodiscard]] const std::filesystem::path& GetSplashPath() const {
return splash_path;
}
+
+ [[nodiscard]] const std::filesystem::path& GetGameFolder() const {
+ return game_folder;
+ }
};
} // namespace Common
diff --git a/src/common/io_file.cpp b/src/common/io_file.cpp
index 3efadc6ea..6fa9062a7 100644
--- a/src/common/io_file.cpp
+++ b/src/common/io_file.cpp
@@ -131,9 +131,7 @@ namespace {
case SeekOrigin::End:
return SEEK_END;
default:
- LOG_ERROR(Common_Filesystem, "Unsupported origin {}, defaulting to SEEK_SET",
- static_cast(origin));
- return SEEK_SET;
+ UNREACHABLE_MSG("Impossible SeekOrigin {}", static_cast(origin));
}
}
diff --git a/src/common/io_file.h b/src/common/io_file.h
index fb20a2bc5..45787a092 100644
--- a/src/common/io_file.h
+++ b/src/common/io_file.h
@@ -61,8 +61,6 @@ enum class SeekOrigin : u32 {
SetOrigin, // Seeks from the start of the file.
CurrentPosition, // Seeks from the current file pointer position.
End, // Seeks from the end of the file.
- SeekHole, // Seeks from the start of the next hole in the file.
- SeekData, // Seeks from the start of the next non-hole region in the file.
};
class IOFile final {
diff --git a/src/common/logging/filter.cpp b/src/common/logging/filter.cpp
index 867d62916..231cbf849 100644
--- a/src/common/logging/filter.cpp
+++ b/src/common/logging/filter.cpp
@@ -137,6 +137,9 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
SUB(Lib, NpParty) \
SUB(Lib, Zlib) \
SUB(Lib, Hmd) \
+ SUB(Lib, SigninDialog) \
+ SUB(Lib, Camera) \
+ SUB(Lib, CompanionHttpd) \
CLS(Frontend) \
CLS(Render) \
SUB(Render, Vulkan) \
diff --git a/src/common/logging/types.h b/src/common/logging/types.h
index e5714a81a..e4eae59af 100644
--- a/src/common/logging/types.h
+++ b/src/common/logging/types.h
@@ -104,6 +104,9 @@ enum class Class : u8 {
Lib_NpParty, ///< The LibSceNpParty implementation
Lib_Zlib, ///< The LibSceZlib implementation.
Lib_Hmd, ///< The LibSceHmd implementation.
+ Lib_SigninDialog, ///< The LibSigninDialog implementation.
+ Lib_Camera, ///< The LibCamera implementation.
+ Lib_CompanionHttpd, ///< The LibCompanionHttpd implementation.
Frontend, ///< Emulator UI
Render, ///< Video Core
Render_Vulkan, ///< Vulkan backend
diff --git a/src/common/memory_patcher.cpp b/src/common/memory_patcher.cpp
index 2a8b26acb..cb51828cc 100644
--- a/src/common/memory_patcher.cpp
+++ b/src/common/memory_patcher.cpp
@@ -23,7 +23,7 @@
namespace MemoryPatcher {
-uintptr_t g_eboot_address;
+EXPORT uintptr_t g_eboot_address;
uint64_t g_eboot_image_size;
std::string g_game_serial;
std::string patchFile;
@@ -169,7 +169,8 @@ void OnGameLoaded() {
if (type == "mask_jump32")
patchMask = MemoryPatcher::PatchMask::Mask_Jump32;
- if (type == "mask" || type == "mask_jump32" && !maskOffsetStr.empty()) {
+ if ((type == "mask" || type == "mask_jump32") &&
+ !maskOffsetStr.empty()) {
maskOffsetValue = std::stoi(maskOffsetStr, 0, 10);
}
diff --git a/src/common/memory_patcher.h b/src/common/memory_patcher.h
index 29045a6a2..968903a85 100644
--- a/src/common/memory_patcher.h
+++ b/src/common/memory_patcher.h
@@ -6,9 +6,15 @@
#include
#include
+#if defined(WIN32)
+#define EXPORT __declspec(dllexport)
+#else
+#define EXPORT __attribute__((visibility("default")))
+#endif
+
namespace MemoryPatcher {
-extern uintptr_t g_eboot_address;
+extern EXPORT uintptr_t g_eboot_address;
extern uint64_t g_eboot_image_size;
extern std::string g_game_serial;
extern std::string patchFile;
diff --git a/src/common/path_util.cpp b/src/common/path_util.cpp
index 1a6ff9ec8..3270c24dd 100644
--- a/src/common/path_util.cpp
+++ b/src/common/path_util.cpp
@@ -128,7 +128,6 @@ static auto UserPaths = [] {
create_path(PathType::LogDir, user_dir / LOG_DIR);
create_path(PathType::ScreenshotsDir, user_dir / SCREENSHOTS_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::TempDataDir, user_dir / TEMPDATA_DIR);
create_path(PathType::SysModuleDir, user_dir / SYSMODULES_DIR);
diff --git a/src/common/path_util.h b/src/common/path_util.h
index 2fd9b1588..b8053a229 100644
--- a/src/common/path_util.h
+++ b/src/common/path_util.h
@@ -18,7 +18,6 @@ enum class PathType {
LogDir, // Where log files are stored.
ScreenshotsDir, // Where screenshots are stored.
ShaderDir, // Where shaders are stored.
- SaveDataDir, // Where guest save data is stored.
TempDataDir, // Where game temp data is stored.
GameDataDir, // Where game data is stored.
SysModuleDir, // Where system modules are stored.
@@ -36,7 +35,6 @@ constexpr auto PORTABLE_DIR = "user";
constexpr auto LOG_DIR = "log";
constexpr auto SCREENSHOTS_DIR = "screenshots";
constexpr auto SHADER_DIR = "shader";
-constexpr auto SAVEDATA_DIR = "savedata";
constexpr auto GAMEDATA_DIR = "data";
constexpr auto TEMPDATA_DIR = "temp";
constexpr auto SYSMODULES_DIR = "sys_modules";
diff --git a/src/common/recursive_lock.cpp b/src/common/recursive_lock.cpp
new file mode 100644
index 000000000..2471a2ee0
--- /dev/null
+++ b/src/common/recursive_lock.cpp
@@ -0,0 +1,37 @@
+// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include
+#include "common/assert.h"
+#include "common/recursive_lock.h"
+
+namespace Common::Detail {
+
+struct RecursiveLockState {
+ RecursiveLockType type;
+ int count;
+};
+
+thread_local std::unordered_map 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
diff --git a/src/common/recursive_lock.h b/src/common/recursive_lock.h
new file mode 100644
index 000000000..5a5fc6658
--- /dev/null
+++ b/src/common/recursive_lock.h
@@ -0,0 +1,67 @@
+// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include
+#include
+#include
+
+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
+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> m_lock;
+ bool m_locked = false;
+};
+
+template
+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> m_lock;
+ bool m_locked = false;
+};
+
+} // namespace Common
\ No newline at end of file
diff --git a/src/common/slot_vector.h b/src/common/slot_vector.h
index d4ac51361..2f693fb28 100644
--- a/src/common/slot_vector.h
+++ b/src/common/slot_vector.h
@@ -14,6 +14,9 @@ namespace Common {
struct SlotId {
static constexpr u32 INVALID_INDEX = std::numeric_limits::max();
+ SlotId() noexcept = default;
+ constexpr SlotId(u32 index) noexcept : index(index) {}
+
constexpr auto operator<=>(const SlotId&) const noexcept = default;
constexpr explicit operator bool() const noexcept {
@@ -28,6 +31,63 @@ class SlotVector {
constexpr static std::size_t InitialCapacity = 2048;
public:
+ template
+ 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;
+ using const_iterator = Iterator;
+ using reverse_iterator = std::reverse_iterator;
+ using const_reverse_iterator = std::reverse_iterator;
+
SlotVector() {
Reserve(InitialCapacity);
}
@@ -60,7 +120,7 @@ public:
}
template
- [[nodiscard]] SlotId insert(Args&&... args) noexcept {
+ SlotId insert(Args&&... args) noexcept {
const u32 index = FreeValueIndex();
new (&values[index].object) T(std::forward(args)...);
SetStorageBit(index);
@@ -78,6 +138,54 @@ public:
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:
struct NonTrivialDummy {
NonTrivialDummy() noexcept {}
diff --git a/src/common/thread.cpp b/src/common/thread.cpp
index 9ef1e86d8..982041ebb 100644
--- a/src/common/thread.cpp
+++ b/src/common/thread.cpp
@@ -2,6 +2,7 @@
// SPDX-FileCopyrightText: 2014 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
+#include
#include
#include
@@ -104,14 +105,24 @@ void SetCurrentThreadPriority(ThreadPriority new_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{
.QuadPart = -1 * (duration.count() / 100u),
};
HANDLE timer = ::CreateWaitableTimer(NULL, TRUE, NULL);
SetWaitableTimer(timer, &interval, 0, NULL, NULL, 0);
- WaitForSingleObject(timer, INFINITE);
+ const auto ret = WaitForSingleObjectEx(timer, INFINITE, interruptible);
::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
@@ -134,8 +145,24 @@ void SetCurrentThreadPriority(ThreadPriority new_priority) {
pthread_setschedparam(this_thread, scheduling_type, ¶ms);
}
-static void AccurateSleep(std::chrono::nanoseconds duration) {
- std::this_thread::sleep_for(duration);
+bool AccurateSleep(const std::chrono::nanoseconds duration, std::chrono::nanoseconds* remaining,
+ 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
@@ -196,9 +223,9 @@ AccurateTimer::AccurateTimer(std::chrono::nanoseconds target_interval)
: target_interval(target_interval) {}
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) {
- AccurateSleep(total_wait);
+ AccurateSleep(total_wait, nullptr, false);
}
start_time = std::chrono::high_resolution_clock::now();
total_wait -= std::chrono::duration_cast(start_time - begin_sleep);
diff --git a/src/common/thread.h b/src/common/thread.h
index 92cc0c59d..5bd83d35c 100644
--- a/src/common/thread.h
+++ b/src/common/thread.h
@@ -25,6 +25,9 @@ void SetCurrentThreadName(const char* name);
void SetThreadName(void* thread, const char* name);
+bool AccurateSleep(std::chrono::nanoseconds duration, std::chrono::nanoseconds* remaining,
+ bool interruptible);
+
class AccurateTimer {
std::chrono::nanoseconds target_interval{};
std::chrono::nanoseconds total_wait{};
diff --git a/src/common/va_ctx.h b/src/common/va_ctx.h
index e0b8c0bab..cffe468ff 100644
--- a/src/common/va_ctx.h
+++ b/src/common/va_ctx.h
@@ -8,7 +8,7 @@
#define VA_ARGS \
uint64_t rdi, uint64_t rsi, uint64_t rdx, uint64_t rcx, uint64_t r8, uint64_t r9, \
uint64_t overflow_arg_area, __m128 xmm0, __m128 xmm1, __m128 xmm2, __m128 xmm3, \
- __m128 xmm4, __m128 xmm5, __m128 xmm6, __m128 xmm7, ...
+ __m128 xmm4, __m128 xmm5, __m128 xmm6, __m128 xmm7
#define VA_CTX(ctx) \
alignas(16)::Common::VaCtx ctx{}; \
diff --git a/src/core/address_space.h b/src/core/address_space.h
index 7ccc2cd1e..d7f3efc75 100644
--- a/src/core/address_space.h
+++ b/src/core/address_space.h
@@ -19,8 +19,6 @@ enum class MemoryPermission : u32 {
};
DECLARE_ENUM_FLAG_OPERATORS(MemoryPermission)
-constexpr VAddr CODE_BASE_OFFSET = 0x100000000ULL;
-
constexpr VAddr SYSTEM_MANAGED_MIN = 0x00000400000ULL;
constexpr VAddr SYSTEM_MANAGED_MAX = 0x07FFFFBFFFULL;
constexpr VAddr SYSTEM_RESERVED_MIN = 0x07FFFFC000ULL;
diff --git a/src/core/cpu_patches.cpp b/src/core/cpu_patches.cpp
index c8106b270..8937ef04b 100644
--- a/src/core/cpu_patches.cpp
+++ b/src/core/cpu_patches.cpp
@@ -464,9 +464,8 @@ static std::pair TryPatch(u8* code, PatchModule* module) {
if (needs_trampoline && instruction.length < 5) {
// Trampoline is needed but instruction is too short to patch.
- // Return false and length to fall back to the illegal instruction handler,
- // or to signal to AOT compilation that this instruction should be skipped and
- // handled at runtime.
+ // Return false and length to signal to AOT compilation that this instruction
+ // should be skipped and handled at runtime.
return std::make_pair(false, instruction.length);
}
@@ -512,136 +511,137 @@ static std::pair TryPatch(u8* code, PatchModule* module) {
#if defined(ARCH_X86_64)
+static bool Is4ByteExtrqOrInsertq(void* code_address) {
+ u8* bytes = (u8*)code_address;
+ if (bytes[0] == 0x66 && bytes[1] == 0x0F && bytes[2] == 0x79) {
+ return true; // extrq
+ } else if (bytes[0] == 0xF2 && bytes[1] == 0x0F && bytes[2] == 0x79) {
+ return true; // insertq
+ } else {
+ return false;
+ }
+}
+
static bool TryExecuteIllegalInstruction(void* ctx, void* code_address) {
- ZydisDecodedInstruction instruction;
- ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT];
- const auto status =
- Common::Decoder::Instance()->decodeInstruction(instruction, operands, code_address);
+ // We need to decode the instruction to find out what it is. Normally we'd use a fully fleshed
+ // out decoder like Zydis, however Zydis does a bunch of stuff that impact performance that we
+ // don't care about. We can get information about the instruction a lot faster by writing a mini
+ // decoder here, since we know it is definitely an extrq or an insertq. If for some reason we
+ // need to interpret more instructions in the future (I don't see why we would), we can revert
+ // to using Zydis.
+ ZydisMnemonic mnemonic;
+ u8* bytes = (u8*)code_address;
+ if (bytes[0] == 0x66) {
+ mnemonic = ZYDIS_MNEMONIC_EXTRQ;
+ } else if (bytes[0] == 0xF2) {
+ mnemonic = ZYDIS_MNEMONIC_INSERTQ;
+ } else {
+ ZydisDecodedInstruction instruction;
+ ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT];
+ const auto status =
+ Common::Decoder::Instance()->decodeInstruction(instruction, operands, code_address);
+ LOG_ERROR(Core, "Unhandled illegal instruction at code address {}: {}",
+ fmt::ptr(code_address),
+ ZYAN_SUCCESS(status) ? ZydisMnemonicGetString(instruction.mnemonic)
+ : "Failed to decode");
+ return false;
+ }
- switch (instruction.mnemonic) {
+ ASSERT(bytes[1] == 0x0F && bytes[2] == 0x79);
+
+ // Note: It's guaranteed that there's no REX prefix in these instructions checked by
+ // Is4ByteExtrqOrInsertq
+ u8 modrm = bytes[3];
+ u8 rm = modrm & 0b111;
+ u8 reg = (modrm >> 3) & 0b111;
+ u8 mod = (modrm >> 6) & 0b11;
+
+ ASSERT(mod == 0b11); // Any instruction we interpret here uses reg/reg addressing only
+
+ int dstIndex = reg;
+ int srcIndex = rm;
+
+ switch (mnemonic) {
case ZYDIS_MNEMONIC_EXTRQ: {
- bool immediateForm = operands[1].type == ZYDIS_OPERAND_TYPE_IMMEDIATE &&
- operands[2].type == ZYDIS_OPERAND_TYPE_IMMEDIATE;
- if (immediateForm) {
- LOG_CRITICAL(Core, "EXTRQ immediate form should have been patched at code address: {}",
- fmt::ptr(code_address));
- return false;
+ const auto dst = Common::GetXmmPointer(ctx, dstIndex);
+ const auto src = Common::GetXmmPointer(ctx, srcIndex);
+
+ u64 lowQWordSrc;
+ memcpy(&lowQWordSrc, src, sizeof(lowQWordSrc));
+
+ u64 lowQWordDst;
+ memcpy(&lowQWordDst, dst, sizeof(lowQWordDst));
+
+ u64 length = lowQWordSrc & 0x3F;
+ u64 mask;
+ if (length == 0) {
+ length = 64; // for the check below
+ mask = 0xFFFF'FFFF'FFFF'FFFF;
} else {
- ASSERT_MSG(operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER &&
- operands[1].type == ZYDIS_OPERAND_TYPE_REGISTER &&
- operands[0].reg.value >= ZYDIS_REGISTER_XMM0 &&
- operands[0].reg.value <= ZYDIS_REGISTER_XMM15 &&
- operands[1].reg.value >= ZYDIS_REGISTER_XMM0 &&
- operands[1].reg.value <= ZYDIS_REGISTER_XMM15,
- "Unexpected operand types for EXTRQ instruction");
-
- const auto dstIndex = operands[0].reg.value - ZYDIS_REGISTER_XMM0;
- const auto srcIndex = operands[1].reg.value - ZYDIS_REGISTER_XMM0;
-
- const auto dst = Common::GetXmmPointer(ctx, dstIndex);
- const auto src = Common::GetXmmPointer(ctx, srcIndex);
-
- u64 lowQWordSrc;
- memcpy(&lowQWordSrc, src, sizeof(lowQWordSrc));
-
- u64 lowQWordDst;
- memcpy(&lowQWordDst, dst, sizeof(lowQWordDst));
-
- u64 length = lowQWordSrc & 0x3F;
- u64 mask;
- if (length == 0) {
- length = 64; // for the check below
- mask = 0xFFFF'FFFF'FFFF'FFFF;
- } else {
- mask = (1ULL << length) - 1;
- }
-
- u64 index = (lowQWordSrc >> 8) & 0x3F;
- if (length + index > 64) {
- // Undefined behavior if length + index is bigger than 64 according to the spec,
- // we'll warn and continue execution.
- LOG_TRACE(Core,
- "extrq at {} with length {} and index {} is bigger than 64, "
- "undefined behavior",
- fmt::ptr(code_address), length, index);
- }
-
- lowQWordDst >>= index;
- lowQWordDst &= mask;
-
- memcpy(dst, &lowQWordDst, sizeof(lowQWordDst));
-
- Common::IncrementRip(ctx, instruction.length);
-
- return true;
+ mask = (1ULL << length) - 1;
}
- break;
+
+ u64 index = (lowQWordSrc >> 8) & 0x3F;
+ if (length + index > 64) {
+ // Undefined behavior if length + index is bigger than 64 according to the spec,
+ // we'll warn and continue execution.
+ LOG_TRACE(Core,
+ "extrq at {} with length {} and index {} is bigger than 64, "
+ "undefined behavior",
+ fmt::ptr(code_address), length, index);
+ }
+
+ lowQWordDst >>= index;
+ lowQWordDst &= mask;
+
+ memcpy(dst, &lowQWordDst, sizeof(lowQWordDst));
+
+ Common::IncrementRip(ctx, 4);
+
+ return true;
}
case ZYDIS_MNEMONIC_INSERTQ: {
- bool immediateForm = operands[2].type == ZYDIS_OPERAND_TYPE_IMMEDIATE &&
- operands[3].type == ZYDIS_OPERAND_TYPE_IMMEDIATE;
- if (immediateForm) {
- LOG_CRITICAL(Core,
- "INSERTQ immediate form should have been patched at code address: {}",
- fmt::ptr(code_address));
- return false;
+ const auto dst = Common::GetXmmPointer(ctx, dstIndex);
+ const auto src = Common::GetXmmPointer(ctx, srcIndex);
+
+ u64 lowQWordSrc, highQWordSrc;
+ memcpy(&lowQWordSrc, src, sizeof(lowQWordSrc));
+ memcpy(&highQWordSrc, (u8*)src + 8, sizeof(highQWordSrc));
+
+ u64 lowQWordDst;
+ memcpy(&lowQWordDst, dst, sizeof(lowQWordDst));
+
+ u64 length = highQWordSrc & 0x3F;
+ u64 mask;
+ if (length == 0) {
+ length = 64; // for the check below
+ mask = 0xFFFF'FFFF'FFFF'FFFF;
} else {
- ASSERT_MSG(operands[2].type == ZYDIS_OPERAND_TYPE_UNUSED &&
- operands[3].type == ZYDIS_OPERAND_TYPE_UNUSED,
- "operands 2 and 3 must be unused for register form.");
-
- ASSERT_MSG(operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER &&
- operands[1].type == ZYDIS_OPERAND_TYPE_REGISTER,
- "operands 0 and 1 must be registers.");
-
- const auto dstIndex = operands[0].reg.value - ZYDIS_REGISTER_XMM0;
- const auto srcIndex = operands[1].reg.value - ZYDIS_REGISTER_XMM0;
-
- const auto dst = Common::GetXmmPointer(ctx, dstIndex);
- const auto src = Common::GetXmmPointer(ctx, srcIndex);
-
- u64 lowQWordSrc, highQWordSrc;
- memcpy(&lowQWordSrc, src, sizeof(lowQWordSrc));
- memcpy(&highQWordSrc, (u8*)src + 8, sizeof(highQWordSrc));
-
- u64 lowQWordDst;
- memcpy(&lowQWordDst, dst, sizeof(lowQWordDst));
-
- u64 length = highQWordSrc & 0x3F;
- u64 mask;
- if (length == 0) {
- length = 64; // for the check below
- mask = 0xFFFF'FFFF'FFFF'FFFF;
- } else {
- mask = (1ULL << length) - 1;
- }
-
- u64 index = (highQWordSrc >> 8) & 0x3F;
- if (length + index > 64) {
- // Undefined behavior if length + index is bigger than 64 according to the spec,
- // we'll warn and continue execution.
- LOG_TRACE(Core,
- "insertq at {} with length {} and index {} is bigger than 64, "
- "undefined behavior",
- fmt::ptr(code_address), length, index);
- }
-
- lowQWordSrc &= mask;
- lowQWordDst &= ~(mask << index);
- lowQWordDst |= lowQWordSrc << index;
-
- memcpy(dst, &lowQWordDst, sizeof(lowQWordDst));
-
- Common::IncrementRip(ctx, instruction.length);
-
- return true;
+ mask = (1ULL << length) - 1;
}
- break;
+
+ u64 index = (highQWordSrc >> 8) & 0x3F;
+ if (length + index > 64) {
+ // Undefined behavior if length + index is bigger than 64 according to the spec,
+ // we'll warn and continue execution.
+ LOG_TRACE(Core,
+ "insertq at {} with length {} and index {} is bigger than 64, "
+ "undefined behavior",
+ fmt::ptr(code_address), length, index);
+ }
+
+ lowQWordSrc &= mask;
+ lowQWordDst &= ~(mask << index);
+ lowQWordDst |= lowQWordSrc << index;
+
+ memcpy(dst, &lowQWordDst, sizeof(lowQWordDst));
+
+ Common::IncrementRip(ctx, 4);
+
+ return true;
}
default: {
- LOG_ERROR(Core, "Unhandled illegal instruction at code address {}: {}",
- fmt::ptr(code_address), ZydisMnemonicGetString(instruction.mnemonic));
- return false;
+ UNREACHABLE();
}
}
@@ -695,9 +695,22 @@ static bool PatchesAccessViolationHandler(void* context, void* /* fault_address
static bool PatchesIllegalInstructionHandler(void* context) {
void* code_address = Common::GetRip(context);
- if (!TryPatchJit(code_address)) {
+ if (Is4ByteExtrqOrInsertq(code_address)) {
+ // The instruction is not big enough for a relative jump, don't try to patch it and pass it
+ // to our illegal instruction interpreter directly
return TryExecuteIllegalInstruction(context, code_address);
+ } else {
+ if (!TryPatchJit(code_address)) {
+ ZydisDecodedInstruction instruction;
+ ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT];
+ const auto status =
+ Common::Decoder::Instance()->decodeInstruction(instruction, operands, code_address);
+ LOG_ERROR(Core, "Failed to patch address {:x} -- mnemonic: {}", (u64)code_address,
+ ZYAN_SUCCESS(status) ? ZydisMnemonicGetString(instruction.mnemonic)
+ : "Failed to decode");
+ }
}
+
return true;
}
diff --git a/src/core/devices/base_device.h b/src/core/devices/base_device.h
index 36614b8f4..0cbbd3a00 100644
--- a/src/core/devices/base_device.h
+++ b/src/core/devices/base_device.h
@@ -40,6 +40,10 @@ public:
return ORBIS_KERNEL_ERROR_EBADF;
}
+ virtual size_t pwritev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt, u64 offset) {
+ return ORBIS_KERNEL_ERROR_EBADF;
+ }
+
virtual s64 lseek(s64 offset, int whence) {
return ORBIS_KERNEL_ERROR_EBADF;
}
diff --git a/src/core/devices/random_device.cpp b/src/core/devices/random_device.cpp
index 50934e3b8..b2754fe58 100644
--- a/src/core/devices/random_device.cpp
+++ b/src/core/devices/random_device.cpp
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include
+#include
#include "common/logging/log.h"
#include "random_device.h"
diff --git a/src/core/devices/srandom_device.cpp b/src/core/devices/srandom_device.cpp
index ab78ddbe2..5e51b1c39 100644
--- a/src/core/devices/srandom_device.cpp
+++ b/src/core/devices/srandom_device.cpp
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include
+#include
#include "common/logging/log.h"
#include "srandom_device.h"
diff --git a/src/core/devices/urandom_device.cpp b/src/core/devices/urandom_device.cpp
index c001aab83..7318a6ff7 100644
--- a/src/core/devices/urandom_device.cpp
+++ b/src/core/devices/urandom_device.cpp
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include
+#include
#include "common/logging/log.h"
#include "urandom_device.h"
diff --git a/src/core/devtools/layer.cpp b/src/core/devtools/layer.cpp
index 94b39e801..5380d3be9 100644
--- a/src/core/devtools/layer.cpp
+++ b/src/core/devtools/layer.cpp
@@ -1,11 +1,11 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
-#include "SDL3/SDL_log.h"
#include "layer.h"
#include
+#include "SDL3/SDL_log.h"
#include "common/config.h"
#include "common/singleton.h"
#include "common/types.h"
@@ -17,6 +17,7 @@
#include "widget/frame_dump.h"
#include "widget/frame_graph.h"
#include "widget/memory_map.h"
+#include "widget/module_list.h"
#include "widget/shader_list.h"
extern std::unique_ptr presenter;
@@ -40,6 +41,7 @@ static bool just_opened_options = false;
static Widget::MemoryMapViewer memory_map;
static Widget::ShaderList shader_list;
+static Widget::ModuleList module_list;
// clang-format off
static std::string help_text =
@@ -108,6 +110,9 @@ void L::DrawMenuBar() {
if (MenuItem("Memory map")) {
memory_map.open = true;
}
+ if (MenuItem("Module list")) {
+ module_list.open = true;
+ }
ImGui::EndMenu();
}
@@ -256,6 +261,9 @@ void L::DrawAdvanced() {
if (shader_list.open) {
shader_list.Draw();
}
+ if (module_list.open) {
+ module_list.Draw();
+ }
}
void L::DrawSimple() {
diff --git a/src/core/devtools/options.cpp b/src/core/devtools/options.cpp
index 2def42071..f4b0ceb9a 100644
--- a/src/core/devtools/options.cpp
+++ b/src/core/devtools/options.cpp
@@ -1,9 +1,14 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
+#include "options.h"
+
+#include
#include
-#include "options.h"
+#include "video_core/renderer_vulkan/vk_presenter.h"
+
+extern std::unique_ptr presenter;
namespace Core::Devtools {
@@ -12,6 +17,7 @@ TOptions Options;
void LoadOptionsConfig(const char* line) {
char str[512];
int i;
+ float f;
if (sscanf(line, "disassembler_cli_isa=%511[^\n]", str) == 1) {
Options.disassembler_cli_isa = str;
return;
@@ -24,12 +30,26 @@ void LoadOptionsConfig(const char* line) {
Options.frame_dump_render_on_collapse = i != 0;
return;
}
+ if (sscanf(line, "fsr_enabled=%d", &i) == 1) {
+ presenter->GetFsrSettingsRef().enable = i != 0;
+ return;
+ }
+ if (sscanf(line, "fsr_rcas_enabled=%d", &i) == 1) {
+ presenter->GetFsrSettingsRef().use_rcas = i != 0;
+ return;
+ }
+ if (sscanf(line, "fsr_rcas_attenuation=%f", &f) == 1) {
+ presenter->GetFsrSettingsRef().rcas_attenuation = f;
+ }
}
void SerializeOptionsConfig(ImGuiTextBuffer* buf) {
buf->appendf("disassembler_cli_isa=%s\n", Options.disassembler_cli_isa.c_str());
buf->appendf("disassembler_cli_spv=%s\n", Options.disassembler_cli_spv.c_str());
buf->appendf("frame_dump_render_on_collapse=%d\n", Options.frame_dump_render_on_collapse);
+ buf->appendf("fsr_enabled=%d\n", presenter->GetFsrSettingsRef().enable);
+ buf->appendf("fsr_rcas_enabled=%d\n", presenter->GetFsrSettingsRef().use_rcas);
+ buf->appendf("fsr_rcas_attenuation=%f\n", presenter->GetFsrSettingsRef().rcas_attenuation);
}
} // namespace Core::Devtools
diff --git a/src/core/devtools/widget/frame_dump.cpp b/src/core/devtools/widget/frame_dump.cpp
index 646ccb6d6..2445bdcb5 100644
--- a/src/core/devtools/widget/frame_dump.cpp
+++ b/src/core/devtools/widget/frame_dump.cpp
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include
+#include
#include
#include
#include
diff --git a/src/core/devtools/widget/module_list.cpp b/src/core/devtools/widget/module_list.cpp
new file mode 100644
index 000000000..73afe3462
--- /dev/null
+++ b/src/core/devtools/widget/module_list.cpp
@@ -0,0 +1,55 @@
+// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "module_list.h"
+
+#include
+
+#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
\ No newline at end of file
diff --git a/src/core/devtools/widget/module_list.h b/src/core/devtools/widget/module_list.h
new file mode 100644
index 000000000..4c961919e
--- /dev/null
+++ b/src/core/devtools/widget/module_list.h
@@ -0,0 +1,82 @@
+// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include
+#include
+#include
+#include
+#include
+#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 modules;
+};
+
+} // namespace Core::Devtools::Widget
\ No newline at end of file
diff --git a/src/core/libraries/camera/camera.cpp b/src/core/libraries/camera/camera.cpp
new file mode 100644
index 000000000..996d1c895
--- /dev/null
+++ b/src/core/libraries/camera/camera.cpp
@@ -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
\ No newline at end of file
diff --git a/src/core/libraries/camera/camera.h b/src/core/libraries/camera/camera.h
new file mode 100644
index 000000000..51aa8b729
--- /dev/null
+++ b/src/core/libraries/camera/camera.h
@@ -0,0 +1,308 @@
+// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include
+#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
\ No newline at end of file
diff --git a/src/core/libraries/camera/camera_error.h b/src/core/libraries/camera/camera_error.h
new file mode 100644
index 000000000..acb04dd02
--- /dev/null
+++ b/src/core/libraries/camera/camera_error.h
@@ -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;
\ No newline at end of file
diff --git a/src/core/libraries/companion/companion_error.h b/src/core/libraries/companion/companion_error.h
new file mode 100644
index 000000000..2d1a3833c
--- /dev/null
+++ b/src/core/libraries/companion/companion_error.h
@@ -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;
diff --git a/src/core/libraries/companion/companion_httpd.cpp b/src/core/libraries/companion/companion_httpd.cpp
new file mode 100644
index 000000000..39081fa4e
--- /dev/null
+++ b/src/core/libraries/companion/companion_httpd.cpp
@@ -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
\ No newline at end of file
diff --git a/src/core/libraries/companion/companion_httpd.h b/src/core/libraries/companion/companion_httpd.h
new file mode 100644
index 000000000..b6d441653
--- /dev/null
+++ b/src/core/libraries/companion/companion_httpd.h
@@ -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
\ No newline at end of file
diff --git a/src/core/libraries/gnmdriver/gnmdriver.cpp b/src/core/libraries/gnmdriver/gnmdriver.cpp
index 25ac4921c..9cf340050 100644
--- a/src/core/libraries/gnmdriver/gnmdriver.cpp
+++ b/src/core/libraries/gnmdriver/gnmdriver.cpp
@@ -179,7 +179,7 @@ s32 PS4_SYSV_ABI sceGnmComputeWaitOnAddress(u32* cmdbuf, u32 size, uintptr_t add
auto* wait_reg_mem = reinterpret_cast(cmdbuf);
wait_reg_mem->header = PM4Type3Header{PM4ItOpcode::WaitRegMem, 5};
wait_reg_mem->raw = (is_mem << 4u) | (cmp_func & 7u);
- wait_reg_mem->poll_addr_lo = u32(addr & addr_mask);
+ wait_reg_mem->poll_addr_lo_raw = u32(addr & addr_mask);
wait_reg_mem->poll_addr_hi = u32(addr >> 32u);
wait_reg_mem->ref = ref;
wait_reg_mem->mask = mask;
@@ -505,9 +505,10 @@ s32 PS4_SYSV_ABI sceGnmDrawIndexIndirectCountMulti(u32* cmdbuf, u32 size, u32 da
u32 flags) {
LOG_TRACE(Lib_GnmDriver, "called");
- if ((!sceKernelIsNeoMode() || !UseNeoCompatSequences) && !cmdbuf && (size == 16) &&
- (shader_stage < ShaderStages::Max) && (vertex_sgpr_offset < 0x10u) &&
- (instance_sgpr_offset < 0x10u)) {
+ if ((!sceKernelIsNeoMode() || !UseNeoCompatSequences) && cmdbuf && (size == 16) &&
+ (vertex_sgpr_offset < 0x10u) && (instance_sgpr_offset < 0x10u) &&
+ (shader_stage == ShaderStages::Vs || shader_stage == ShaderStages::Es ||
+ shader_stage == ShaderStages::Ls)) {
cmdbuf = WriteHeader(cmdbuf, 2);
cmdbuf = WriteBody(cmdbuf, 0u);
@@ -535,10 +536,33 @@ s32 PS4_SYSV_ABI sceGnmDrawIndexIndirectCountMulti(u32* cmdbuf, u32 size, u32 da
return -1;
}
-int PS4_SYSV_ABI sceGnmDrawIndexIndirectMulti() {
- LOG_ERROR(Lib_GnmDriver, "(STUBBED) called");
- UNREACHABLE();
- return ORBIS_OK;
+int PS4_SYSV_ABI sceGnmDrawIndexIndirectMulti(u32* cmdbuf, u32 size, u32 data_offset, u32 max_count,
+ u32 shader_stage, u32 vertex_sgpr_offset,
+ u32 instance_sgpr_offset, u32 flags) {
+ LOG_TRACE(Lib_GnmDriver, "called");
+
+ if (cmdbuf && (size == 11) && (vertex_sgpr_offset < 0x10u) && (instance_sgpr_offset < 0x10u) &&
+ (shader_stage == ShaderStages::Vs || shader_stage == ShaderStages::Es ||
+ shader_stage == ShaderStages::Ls)) {
+
+ const auto predicate = flags & 1 ? PM4Predicate::PredEnable : PM4Predicate::PredDisable;
+ cmdbuf = WriteHeader(
+ cmdbuf, 6, PM4ShaderType::ShaderGraphics, predicate);
+
+ const auto sgpr_offset = indirect_sgpr_offsets[shader_stage];
+
+ cmdbuf[0] = data_offset;
+ cmdbuf[1] = vertex_sgpr_offset == 0 ? 0 : (vertex_sgpr_offset & 0xffffu) + sgpr_offset;
+ cmdbuf[2] = instance_sgpr_offset == 0 ? 0 : (instance_sgpr_offset & 0xffffu) + sgpr_offset;
+ cmdbuf[3] = max_count;
+ cmdbuf[4] = sizeof(DrawIndexedIndirectArgs);
+ cmdbuf[5] = sceKernelIsNeoMode() ? flags & 0xe0000000u : 0;
+
+ cmdbuf += 6;
+ WriteTrailingNop<3>(cmdbuf);
+ return ORBIS_OK;
+ }
+ return -1;
}
int PS4_SYSV_ABI sceGnmDrawIndexMultiInstanced() {
diff --git a/src/core/libraries/gnmdriver/gnmdriver.h b/src/core/libraries/gnmdriver/gnmdriver.h
index 94d06c85f..a3d4968d3 100644
--- a/src/core/libraries/gnmdriver/gnmdriver.h
+++ b/src/core/libraries/gnmdriver/gnmdriver.h
@@ -51,7 +51,9 @@ s32 PS4_SYSV_ABI sceGnmDrawIndexIndirectCountMulti(u32* cmdbuf, u32 size, u32 da
u32 max_count, u64 count_addr, u32 shader_stage,
u32 vertex_sgpr_offset, u32 instance_sgpr_offset,
u32 flags);
-int PS4_SYSV_ABI sceGnmDrawIndexIndirectMulti();
+int PS4_SYSV_ABI sceGnmDrawIndexIndirectMulti(u32* cmdbuf, u32 size, u32 data_offset, u32 max_count,
+ u32 shader_stage, u32 vertex_sgpr_offset,
+ u32 instance_sgpr_offset, u32 flags);
int PS4_SYSV_ABI sceGnmDrawIndexMultiInstanced();
s32 PS4_SYSV_ABI sceGnmDrawIndexOffset(u32* cmdbuf, u32 size, u32 index_offset, u32 index_count,
u32 flags);
diff --git a/src/core/libraries/ime/ime_dialog.h b/src/core/libraries/ime/ime_dialog.h
index 33abc7ecd..526e5f022 100644
--- a/src/core/libraries/ime/ime_dialog.h
+++ b/src/core/libraries/ime/ime_dialog.h
@@ -13,7 +13,7 @@ class SymbolsResolver;
namespace Libraries::ImeDialog {
-constexpr u32 ORBIS_IME_DIALOG_MAX_TEXT_LENGTH = 0x78;
+constexpr u32 ORBIS_IME_DIALOG_MAX_TEXT_LENGTH = 2048;
enum class Error : u32 {
OK = 0x0,
diff --git a/src/core/libraries/kernel/aio.cpp b/src/core/libraries/kernel/aio.cpp
index e017010cb..1d746860b 100644
--- a/src/core/libraries/kernel/aio.cpp
+++ b/src/core/libraries/kernel/aio.cpp
@@ -19,7 +19,7 @@ namespace Libraries::Kernel {
static s32* id_state;
static s32 id_index;
-s32 sceKernelAioInitializeImpl(void* p, s32 size) {
+s32 PS4_SYSV_ABI sceKernelAioInitializeImpl(void* p, s32 size) {
return 0;
}
diff --git a/src/core/libraries/kernel/equeue.cpp b/src/core/libraries/kernel/equeue.cpp
index a4916208a..958019cd3 100644
--- a/src/core/libraries/kernel/equeue.cpp
+++ b/src/core/libraries/kernel/equeue.cpp
@@ -12,12 +12,25 @@
namespace Libraries::Kernel {
+extern boost::asio::io_context io_context;
+extern void KernelSignalRequest();
+
+static constexpr auto HrTimerSpinlockThresholdUs = 1200u;
+
// Events are uniquely identified by id and filter.
bool EqueueInternal::AddEvent(EqueueEvent& event) {
std::scoped_lock lock{m_mutex};
event.time_added = std::chrono::steady_clock::now();
+ if (event.event.filter == SceKernelEvent::Filter::Timer ||
+ event.event.filter == SceKernelEvent::Filter::HrTimer) {
+ // HrTimer events are offset by the threshold of time at the end that we spinlock for
+ // greater accuracy.
+ const auto offset =
+ event.event.filter == SceKernelEvent::Filter::HrTimer ? HrTimerSpinlockThresholdUs : 0u;
+ event.timer_interval = std::chrono::microseconds(event.event.data - offset);
+ }
const auto& it = std::ranges::find(m_events, event);
if (it != m_events.cend()) {
@@ -29,6 +42,47 @@ bool EqueueInternal::AddEvent(EqueueEvent& event) {
return true;
}
+bool EqueueInternal::ScheduleEvent(u64 id, s16 filter,
+ void (*callback)(SceKernelEqueue, const SceKernelEvent&)) {
+ std::scoped_lock lock{m_mutex};
+
+ const auto& it = std::ranges::find_if(m_events, [id, filter](auto& ev) {
+ return ev.event.ident == id && ev.event.filter == filter;
+ });
+ if (it == m_events.cend()) {
+ return false;
+ }
+
+ const auto& event = *it;
+ ASSERT(event.event.filter == SceKernelEvent::Filter::Timer ||
+ event.event.filter == SceKernelEvent::Filter::HrTimer);
+
+ if (!it->timer) {
+ it->timer = std::make_unique(io_context, event.timer_interval);
+ } else {
+ // If the timer already exists we are scheduling a reoccurrence after the next period.
+ // Set the expiration time to the previous occurrence plus the period.
+ it->timer->expires_at(it->timer->expiry() + event.timer_interval);
+ }
+
+ it->timer->async_wait(
+ [this, event_data = event.event, callback](const boost::system::error_code& ec) {
+ if (ec) {
+ if (ec != boost::system::errc::operation_canceled) {
+ LOG_ERROR(Kernel_Event, "Timer callback error: {}", ec.message());
+ } else {
+ // Timer was cancelled (removed) before it triggered
+ LOG_DEBUG(Kernel_Event, "Timer cancelled");
+ }
+ return;
+ }
+ callback(this, event_data);
+ });
+ KernelSignalRequest();
+
+ return true;
+}
+
bool EqueueInternal::RemoveEvent(u64 id, s16 filter) {
bool has_found = false;
std::scoped_lock lock{m_mutex};
@@ -152,18 +206,14 @@ int EqueueInternal::WaitForSmallTimer(SceKernelEvent* ev, int num, u32 micros) {
return count;
}
-extern boost::asio::io_context io_context;
-extern void KernelSignalRequest();
+bool EqueueInternal::EventExists(u64 id, s16 filter) {
+ std::scoped_lock lock{m_mutex};
-static constexpr auto HrTimerSpinlockThresholdUs = 1200u;
+ const auto& it = std::ranges::find_if(m_events, [id, filter](auto& ev) {
+ return ev.event.ident == id && ev.event.filter == filter;
+ });
-static void SmallTimerCallback(const boost::system::error_code& error, SceKernelEqueue eq,
- SceKernelEvent kevent) {
- static EqueueEvent event;
- event.event = kevent;
- event.event.data = HrTimerSpinlockThresholdUs;
- eq->AddSmallTimer(event);
- eq->TriggerEvent(kevent.ident, SceKernelEvent::Filter::HrTimer, kevent.udata);
+ return it != m_events.cend();
}
int PS4_SYSV_ABI sceKernelCreateEqueue(SceKernelEqueue* eq, const char* name) {
@@ -243,6 +293,14 @@ int PS4_SYSV_ABI sceKernelWaitEqueue(SceKernelEqueue eq, SceKernelEvent* ev, int
return ORBIS_OK;
}
+static void HrTimerCallback(SceKernelEqueue eq, const SceKernelEvent& kevent) {
+ static EqueueEvent event;
+ event.event = kevent;
+ event.event.data = HrTimerSpinlockThresholdUs;
+ eq->AddSmallTimer(event);
+ eq->TriggerEvent(kevent.ident, SceKernelEvent::Filter::HrTimer, kevent.udata);
+}
+
s32 PS4_SYSV_ABI sceKernelAddHRTimerEvent(SceKernelEqueue eq, int id, timespec* ts, void* udata) {
if (eq == nullptr) {
return ORBIS_KERNEL_ERROR_EBADF;
@@ -273,17 +331,10 @@ s32 PS4_SYSV_ABI sceKernelAddHRTimerEvent(SceKernelEqueue eq, int id, timespec*
return eq->AddSmallTimer(event) ? ORBIS_OK : ORBIS_KERNEL_ERROR_ENOMEM;
}
- event.timer = std::make_unique(
- io_context, std::chrono::microseconds(total_us - HrTimerSpinlockThresholdUs));
-
- event.timer->async_wait(std::bind(SmallTimerCallback, std::placeholders::_1, eq, event.event));
-
- if (!eq->AddEvent(event)) {
+ if (!eq->AddEvent(event) ||
+ !eq->ScheduleEvent(id, SceKernelEvent::Filter::HrTimer, HrTimerCallback)) {
return ORBIS_KERNEL_ERROR_ENOMEM;
}
-
- KernelSignalRequest();
-
return ORBIS_OK;
}
@@ -300,6 +351,57 @@ int PS4_SYSV_ABI sceKernelDeleteHRTimerEvent(SceKernelEqueue eq, int id) {
}
}
+static void TimerCallback(SceKernelEqueue eq, const SceKernelEvent& kevent) {
+ if (eq->EventExists(kevent.ident, kevent.filter)) {
+ eq->TriggerEvent(kevent.ident, SceKernelEvent::Filter::Timer, kevent.udata);
+
+ if (!(kevent.flags & SceKernelEvent::Flags::OneShot)) {
+ // Reschedule the event for its next period.
+ eq->ScheduleEvent(kevent.ident, kevent.filter, TimerCallback);
+ }
+ }
+}
+
+int PS4_SYSV_ABI sceKernelAddTimerEvent(SceKernelEqueue eq, int id, SceKernelUseconds usec,
+ void* udata) {
+ if (eq == nullptr) {
+ return ORBIS_KERNEL_ERROR_EBADF;
+ }
+
+ EqueueEvent event{};
+ event.event.ident = static_cast(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(udata));
+
+ if (!eq->AddEvent(event) ||
+ !eq->ScheduleEvent(id, SceKernelEvent::Filter::Timer, TimerCallback)) {
+ return ORBIS_KERNEL_ERROR_ENOMEM;
+ }
+ return ORBIS_OK;
+}
+
+int PS4_SYSV_ABI sceKernelDeleteTimerEvent(SceKernelEqueue eq, int id) {
+ if (eq == nullptr) {
+ return ORBIS_KERNEL_ERROR_EBADF;
+ }
+
+ return eq->RemoveEvent(id, SceKernelEvent::Filter::Timer) ? ORBIS_OK
+ : ORBIS_KERNEL_ERROR_ENOENT;
+}
+
int PS4_SYSV_ABI sceKernelAddUserEvent(SceKernelEqueue eq, int id) {
if (eq == nullptr) {
return ORBIS_KERNEL_ERROR_EBADF;
@@ -380,6 +482,8 @@ void RegisterEventQueue(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("WDszmSbWuDk", "libkernel", 1, "libkernel", 1, 1, sceKernelAddUserEventEdge);
LIB_FUNCTION("R74tt43xP6k", "libkernel", 1, "libkernel", 1, 1, sceKernelAddHRTimerEvent);
LIB_FUNCTION("J+LF6LwObXU", "libkernel", 1, "libkernel", 1, 1, sceKernelDeleteHRTimerEvent);
+ LIB_FUNCTION("57ZK+ODEXWY", "libkernel", 1, "libkernel", 1, 1, sceKernelAddTimerEvent);
+ LIB_FUNCTION("YWQFUyXIVdU", "libkernel", 1, "libkernel", 1, 1, sceKernelDeleteTimerEvent);
LIB_FUNCTION("F6e0kwo4cnk", "libkernel", 1, "libkernel", 1, 1, sceKernelTriggerUserEvent);
LIB_FUNCTION("LJDwdSNTnDg", "libkernel", 1, "libkernel", 1, 1, sceKernelDeleteUserEvent);
LIB_FUNCTION("mJ7aghmgvfc", "libkernel", 1, "libkernel", 1, 1, sceKernelGetEventId);
diff --git a/src/core/libraries/kernel/equeue.h b/src/core/libraries/kernel/equeue.h
index 11c09bb37..a0367c66a 100644
--- a/src/core/libraries/kernel/equeue.h
+++ b/src/core/libraries/kernel/equeue.h
@@ -21,6 +21,9 @@ namespace Libraries::Kernel {
class EqueueInternal;
struct EqueueEvent;
+using SceKernelUseconds = u32;
+using SceKernelEqueue = EqueueInternal*;
+
struct SceKernelEvent {
enum Filter : s16 {
None = 0,
@@ -61,10 +64,23 @@ struct SceKernelEvent {
void* udata = nullptr; /* opaque user data identifier */
};
+struct OrbisVideoOutEventHint {
+ u64 event_id : 8;
+ u64 video_id : 8;
+ u64 flip_arg : 48;
+};
+
+struct OrbisVideoOutEventData {
+ u64 time : 12;
+ u64 count : 4;
+ u64 flip_arg : 48;
+};
+
struct EqueueEvent {
SceKernelEvent event;
void* data = nullptr;
std::chrono::steady_clock::time_point time_added;
+ std::chrono::microseconds timer_interval;
std::unique_ptr timer;
void ResetTriggerState() {
@@ -84,19 +100,18 @@ struct EqueueEvent {
void TriggerDisplay(void* data) {
is_triggered = true;
- auto hint = reinterpret_cast(data);
- if (hint != 0) {
- auto hint_h = static_cast(hint >> 8) & 0xFFFFFF;
- auto ident_h = static_cast(event.ident >> 40);
- if ((static_cast(hint) & 0xFF) == event.ident && event.ident != 0xFE &&
- ((hint_h ^ ident_h) & 0xFF) == 0) {
+ if (data != nullptr) {
+ auto event_data = static_cast(event.data);
+ auto event_hint_raw = reinterpret_cast(data);
+ auto event_hint = static_cast(event_hint_raw);
+ if (event_hint.event_id == event.ident && event.ident != 0xfe) {
auto time = Common::FencedRDTSC();
- auto mask = 0xF000;
- if ((static_cast(event.data) & 0xF000) != 0xF000) {
- mask = (static_cast(event.data) + 0x1000) & 0xF000;
+ auto counter = event_data.count;
+ if (counter != 0xf) {
+ counter++;
}
- event.data = (mask | static_cast(static_cast(time) & 0xFFF) |
- (hint & 0xFFFFFFFFFFFF0000));
+ event.data =
+ (time & 0xfff) | (counter << 0xc) | (event_hint_raw & 0xffffffffffff0000);
}
}
}
@@ -122,6 +137,8 @@ public:
}
bool AddEvent(EqueueEvent& event);
+ bool ScheduleEvent(u64 id, s16 filter,
+ void (*callback)(SceKernelEqueue, const SceKernelEvent&));
bool RemoveEvent(u64 id, s16 filter);
int WaitForEvents(SceKernelEvent* ev, int num, u32 micros);
bool TriggerEvent(u64 ident, s16 filter, void* trigger_data);
@@ -141,6 +158,8 @@ public:
int WaitForSmallTimer(SceKernelEvent* ev, int num, u32 micros);
+ bool EventExists(u64 id, s16 filter);
+
private:
std::string m_name;
std::mutex m_mutex;
@@ -149,9 +168,6 @@ private:
std::condition_variable m_cond;
};
-using SceKernelUseconds = u32;
-using SceKernelEqueue = EqueueInternal*;
-
u64 PS4_SYSV_ABI sceKernelGetEventData(const SceKernelEvent* ev);
void RegisterEventQueue(Core::Loader::SymbolsResolver* sym);
diff --git a/src/core/libraries/kernel/file_system.cpp b/src/core/libraries/kernel/file_system.cpp
index bc34dff98..ad372325c 100644
--- a/src/core/libraries/kernel/file_system.cpp
+++ b/src/core/libraries/kernel/file_system.cpp
@@ -67,10 +67,16 @@ s32 PS4_SYSV_ABI open(const char* raw_path, s32 flags, u16 mode) {
bool write = (flags & 0x3) == ORBIS_KERNEL_O_WRONLY;
bool rdwr = (flags & 0x3) == ORBIS_KERNEL_O_RDWR;
+ if (!read && !write && !rdwr) {
+ // Start by checking for invalid flags.
+ *__Error() = POSIX_EINVAL;
+ return -1;
+ }
+
bool nonblock = (flags & ORBIS_KERNEL_O_NONBLOCK) != 0;
bool append = (flags & ORBIS_KERNEL_O_APPEND) != 0;
- bool fsync = (flags & ORBIS_KERNEL_O_FSYNC) != 0;
- bool sync = (flags & ORBIS_KERNEL_O_SYNC) != 0;
+ // Flags fsync and sync behave the same
+ bool sync = (flags & ORBIS_KERNEL_O_SYNC) != 0 || (flags & ORBIS_KERNEL_O_FSYNC) != 0;
bool create = (flags & ORBIS_KERNEL_O_CREAT) != 0;
bool truncate = (flags & ORBIS_KERNEL_O_TRUNC) != 0;
bool excl = (flags & ORBIS_KERNEL_O_EXCL) != 0;
@@ -78,6 +84,10 @@ s32 PS4_SYSV_ABI open(const char* raw_path, s32 flags, u16 mode) {
bool direct = (flags & ORBIS_KERNEL_O_DIRECT) != 0;
bool directory = (flags & ORBIS_KERNEL_O_DIRECTORY) != 0;
+ if (sync || direct || dsync || nonblock) {
+ LOG_WARNING(Kernel_Fs, "flags {:#x} not fully handled", flags);
+ }
+
std::string_view path{raw_path};
u32 handle = h->CreateHandle();
auto* file = h->GetFile(handle);
@@ -94,84 +104,127 @@ s32 PS4_SYSV_ABI open(const char* raw_path, s32 flags, u16 mode) {
}
}
- if (directory) {
- file->type = Core::FileSys::FileType::Directory;
- file->m_guest_name = path;
- file->m_host_name = mnt->GetHostPath(file->m_guest_name);
- if (!std::filesystem::is_directory(file->m_host_name)) { // directory doesn't exist
+ bool read_only = false;
+ file->m_guest_name = path;
+ file->m_host_name = mnt->GetHostPath(file->m_guest_name, &read_only);
+ bool exists = std::filesystem::exists(file->m_host_name);
+ s32 e = 0;
+
+ if (create) {
+ if (excl && exists) {
+ // Error if file exists
h->DeleteHandle(handle);
- *__Error() = POSIX_ENOENT;
+ *__Error() = POSIX_EEXIST;
+ return -1;
+ }
+
+ if (read_only) {
+ // Can't create files in a read only directory
+ h->DeleteHandle(handle);
+ *__Error() = POSIX_EROFS;
+ return -1;
+ }
+ // Create a file if it doesn't exist
+ Common::FS::IOFile out(file->m_host_name, Common::FS::FileAccessMode::Write);
+ } else if (!exists) {
+ // If we're not creating a file, and it doesn't exist, return ENOENT
+ h->DeleteHandle(handle);
+ *__Error() = POSIX_ENOENT;
+ return -1;
+ }
+
+ if (std::filesystem::is_directory(file->m_host_name) || directory) {
+ // Directories can be opened even if the directory flag isn't set.
+ // In these cases, error behavior is identical to the directory code path.
+ directory = true;
+ }
+
+ if (directory) {
+ if (!std::filesystem::is_directory(file->m_host_name)) {
+ // If the opened file is not a directory, return ENOTDIR.
+ // This will trigger when create & directory is specified, this is expected.
+ h->DeleteHandle(handle);
+ *__Error() = POSIX_ENOTDIR;
+ return -1;
+ }
+
+ file->type = Core::FileSys::FileType::Directory;
+
+ // Populate directory contents
+ mnt->IterateDirectory(file->m_guest_name,
+ [&file](const auto& ent_path, const auto ent_is_file) {
+ auto& dir_entry = file->dirents.emplace_back();
+ dir_entry.name = ent_path.filename().string();
+ dir_entry.isFile = ent_is_file;
+ });
+ file->dirents_index = 0;
+
+ if (read) {
+ e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::Read);
+ } else if (write || rdwr) {
+ // Cannot open directories with any type of write access
+ h->DeleteHandle(handle);
+ *__Error() = POSIX_EISDIR;
+ return -1;
+ }
+
+ if (e == EACCES) {
+ // Hack to bypass some platform limitations, ignore the error and continue as normal.
+ LOG_WARNING(Kernel_Fs, "Opening directories is not fully supported on this platform");
+ e = 0;
+ }
+
+ if (truncate) {
+ // Cannot open directories with truncate
+ h->DeleteHandle(handle);
+ *__Error() = POSIX_EISDIR;
return -1;
- } else {
- if (create) {
- return handle; // dir already exists
- } else {
- mnt->IterateDirectory(file->m_guest_name,
- [&file](const auto& ent_path, const auto ent_is_file) {
- auto& dir_entry = file->dirents.emplace_back();
- dir_entry.name = ent_path.filename().string();
- dir_entry.isFile = ent_is_file;
- });
- file->dirents_index = 0;
- }
}
} else {
- file->m_guest_name = path;
- file->m_host_name = mnt->GetHostPath(file->m_guest_name);
- bool exists = std::filesystem::exists(file->m_host_name);
- int e = 0;
+ file->type = Core::FileSys::FileType::Regular;
- if (create) {
- if (excl && exists) {
- // Error if file exists
- h->DeleteHandle(handle);
- *__Error() = POSIX_EEXIST;
- return -1;
- }
- // Create file if it doesn't exist
- Common::FS::IOFile out(file->m_host_name, Common::FS::FileAccessMode::Write);
- } else if (!exists) {
- // File to open doesn't exist, return ENOENT
+ if (truncate && read_only) {
+ // Can't open files with truncate flag in a read only directory
h->DeleteHandle(handle);
- *__Error() = POSIX_ENOENT;
+ *__Error() = POSIX_EROFS;
return -1;
+ } else if (truncate) {
+ // Open the file as read-write so we can truncate regardless of flags.
+ // Since open starts by closing the file, this won't interfere with later open calls.
+ e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::ReadWrite);
+ if (e == 0) {
+ // If the file was opened successfully, reduce size to 0
+ file->f.SetSize(0);
+ }
}
if (read) {
// Read only
e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::Read);
+ } else if (read_only) {
+ // Can't open files with write/read-write access in a read only directory
+ h->DeleteHandle(handle);
+ *__Error() = POSIX_EROFS;
+ return -1;
+ } else if (append) {
+ // Append can be specified with rdwr or write, but we treat it as a separate mode.
+ e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::Append);
} else if (write) {
// Write only
- if (append) {
- e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::Append);
- } else {
- e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::Write);
- }
+ e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::Write);
} else if (rdwr) {
// Read and write
- if (append) {
- e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::Append);
- } else {
- e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::ReadWrite);
- }
- } else {
- // Invalid flags
- *__Error() = POSIX_EINVAL;
- return -1;
- }
-
- if (truncate && e == 0) {
- // If the file was opened successfully and truncate was enabled, reduce size to 0
- file->f.SetSize(0);
- }
-
- if (e != 0) {
- // Open failed in platform-specific code, errno needs to be converted.
- h->DeleteHandle(handle);
- SetPosixErrno(e);
- return -1;
+ e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::ReadWrite);
}
}
+
+ if (e != 0) {
+ // Open failed in platform-specific code, errno needs to be converted.
+ h->DeleteHandle(handle);
+ SetPosixErrno(e);
+ return -1;
+ }
+
file->is_opened = true;
return handle;
}
@@ -365,10 +418,10 @@ s64 PS4_SYSV_ABI posix_lseek(s32 fd, s64 offset, s32 whence) {
origin = Common::FS::SeekOrigin::CurrentPosition;
} else if (whence == 2) {
origin = Common::FS::SeekOrigin::End;
- } else if (whence == 3) {
- origin = Common::FS::SeekOrigin::SeekHole;
- } else if (whence == 4) {
- origin = Common::FS::SeekOrigin::SeekData;
+ } else if (whence == 3 || whence == 4) {
+ // whence parameter belongs to an unsupported POSIX extension
+ *__Error() = POSIX_ENOTTY;
+ return -1;
} else {
// whence parameter is invalid
*__Error() = POSIX_EINVAL;
@@ -486,13 +539,13 @@ s32 PS4_SYSV_ABI posix_rmdir(const char* path) {
const std::filesystem::path dir_name = mnt->GetHostPath(path, &ro);
- if (dir_name.empty() || !std::filesystem::is_directory(dir_name)) {
- *__Error() = POSIX_ENOTDIR;
+ if (ro) {
+ *__Error() = POSIX_EROFS;
return -1;
}
- if (ro) {
- *__Error() = POSIX_EROFS;
+ if (dir_name.empty() || !std::filesystem::is_directory(dir_name)) {
+ *__Error() = POSIX_ENOTDIR;
return -1;
}
@@ -523,8 +576,7 @@ s32 PS4_SYSV_ABI sceKernelRmdir(const char* path) {
s32 PS4_SYSV_ABI posix_stat(const char* path, OrbisKernelStat* sb) {
LOG_INFO(Kernel_Fs, "(PARTIAL) path = {}", path);
auto* mnt = Common::Singleton::Instance();
- bool ro = false;
- const auto path_name = mnt->GetHostPath(path, &ro);
+ const auto path_name = mnt->GetHostPath(path);
std::memset(sb, 0, sizeof(OrbisKernelStat));
const bool is_dir = std::filesystem::is_directory(path_name);
const bool is_file = std::filesystem::is_regular_file(path_name);
@@ -545,9 +597,6 @@ s32 PS4_SYSV_ABI posix_stat(const char* path, OrbisKernelStat* sb) {
sb->st_blocks = (sb->st_size + 511) / 512;
// TODO incomplete
}
- if (ro) {
- sb->st_mode &= ~0000555u;
- }
return ORBIS_OK;
}
@@ -877,7 +926,7 @@ s32 PS4_SYSV_ABI sceKernelGetdirentries(s32 fd, char* buf, s32 nbytes, s64* base
return result;
}
-s64 PS4_SYSV_ABI posix_pwrite(s32 fd, void* buf, size_t nbytes, s64 offset) {
+s64 PS4_SYSV_ABI posix_pwritev(s32 fd, const SceKernelIovec* iov, s32 iovcnt, s64 offset) {
if (offset < 0) {
*__Error() = POSIX_EINVAL;
return -1;
@@ -893,7 +942,7 @@ s64 PS4_SYSV_ABI posix_pwrite(s32 fd, void* buf, size_t nbytes, s64 offset) {
std::scoped_lock lk{file->m_mutex};
if (file->type == Core::FileSys::FileType::Device) {
- s64 result = file->device->pwrite(buf, nbytes, offset);
+ s64 result = file->device->pwritev(iov, iovcnt, offset);
if (result < 0) {
ErrSceToPosix(result);
return -1;
@@ -908,7 +957,16 @@ s64 PS4_SYSV_ABI posix_pwrite(s32 fd, void* buf, size_t nbytes, s64 offset) {
*__Error() = POSIX_EIO;
return -1;
}
- return file->f.WriteRaw(buf, nbytes);
+ size_t total_written = 0;
+ for (int i = 0; i < iovcnt; i++) {
+ total_written += file->f.WriteRaw(iov[i].iov_base, iov[i].iov_len);
+ }
+ return total_written;
+}
+
+s64 PS4_SYSV_ABI posix_pwrite(s32 fd, void* buf, size_t nbytes, s64 offset) {
+ SceKernelIovec iovec{buf, nbytes};
+ return posix_pwritev(fd, &iovec, 1, offset);
}
s64 PS4_SYSV_ABI sceKernelPwrite(s32 fd, void* buf, size_t nbytes, s64 offset) {
@@ -920,6 +978,15 @@ s64 PS4_SYSV_ABI sceKernelPwrite(s32 fd, void* buf, size_t nbytes, s64 offset) {
return result;
}
+s64 PS4_SYSV_ABI sceKernelPwritev(s32 fd, const SceKernelIovec* iov, s32 iovcnt, s64 offset) {
+ s64 result = posix_pwritev(fd, iov, iovcnt, offset);
+ if (result < 0) {
+ LOG_ERROR(Kernel_Fs, "error = {}", *__Error());
+ return ErrnoToSceKernelError(*__Error());
+ }
+ return result;
+}
+
s32 PS4_SYSV_ABI posix_unlink(const char* path) {
if (path == nullptr) {
*__Error() = POSIX_EINVAL;
@@ -1017,7 +1084,10 @@ void RegisterFileSystem(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("sfKygSjIbI8", "libkernel", 1, "libkernel", 1, 1, getdirentries);
LIB_FUNCTION("taRWhTJFTgE", "libkernel", 1, "libkernel", 1, 1, sceKernelGetdirentries);
LIB_FUNCTION("C2kJ-byS5rM", "libkernel", 1, "libkernel", 1, 1, posix_pwrite);
+ LIB_FUNCTION("FCcmRZhWtOk", "libScePosix", 1, "libkernel", 1, 1, posix_pwritev);
+ LIB_FUNCTION("FCcmRZhWtOk", "libkernel", 1, "libkernel", 1, 1, posix_pwritev);
LIB_FUNCTION("nKWi-N2HBV4", "libkernel", 1, "libkernel", 1, 1, sceKernelPwrite);
+ LIB_FUNCTION("mBd4AfLP+u8", "libkernel", 1, "libkernel", 1, 1, sceKernelPwritev);
LIB_FUNCTION("AUXVxWeJU-A", "libkernel", 1, "libkernel", 1, 1, sceKernelUnlink);
}
diff --git a/src/core/libraries/kernel/kernel.cpp b/src/core/libraries/kernel/kernel.cpp
index 33602bfe8..180850217 100644
--- a/src/core/libraries/kernel/kernel.cpp
+++ b/src/core/libraries/kernel/kernel.cpp
@@ -24,11 +24,16 @@
#include "core/libraries/kernel/threads/exception.h"
#include "core/libraries/kernel/time.h"
#include "core/libraries/libs.h"
+#include "core/libraries/network/sys_net.h"
#ifdef _WIN64
#include
+#else
+#include
#endif
#include
+#include
+#include
#include "aio.h"
namespace Libraries::Kernel {
@@ -103,6 +108,9 @@ void SetPosixErrno(int e) {
case EACCES:
g_posix_errno = POSIX_EACCES;
break;
+ case EFAULT:
+ g_posix_errno = POSIX_EFAULT;
+ break;
case EINVAL:
g_posix_errno = POSIX_EINVAL;
break;
@@ -149,23 +157,23 @@ struct OrbisKernelUuid {
u8 clockSeqLow;
u8 node[6];
};
+static_assert(sizeof(OrbisKernelUuid) == 0x10);
int PS4_SYSV_ABI sceKernelUuidCreate(OrbisKernelUuid* orbisUuid) {
+ if (!orbisUuid) {
+ return ORBIS_KERNEL_ERROR_EINVAL;
+ }
#ifdef _WIN64
UUID uuid;
- UuidCreate(&uuid);
- orbisUuid->timeLow = uuid.Data1;
- orbisUuid->timeMid = uuid.Data2;
- orbisUuid->timeHiAndVersion = uuid.Data3;
- orbisUuid->clockSeqHiAndReserved = uuid.Data4[0];
- orbisUuid->clockSeqLow = uuid.Data4[1];
- for (int i = 0; i < 6; i++) {
- orbisUuid->node[i] = uuid.Data4[2 + i];
+ if (UuidCreate(&uuid) != RPC_S_OK) {
+ return ORBIS_KERNEL_ERROR_EFAULT;
}
#else
- LOG_ERROR(Kernel, "sceKernelUuidCreate: Add linux");
+ uuid_t uuid;
+ uuid_generate(uuid);
#endif
- return 0;
+ std::memcpy(orbisUuid, &uuid, sizeof(OrbisKernelUuid));
+ return ORBIS_OK;
}
int PS4_SYSV_ABI kernel_ioctl(int fd, u64 cmd, VA_ARGS) {
@@ -196,10 +204,6 @@ const char* PS4_SYSV_ABI sceKernelGetFsSandboxRandomWord() {
return path;
}
-int PS4_SYSV_ABI posix_connect() {
- return -1;
-}
-
int PS4_SYSV_ABI _sigprocmask() {
return ORBIS_OK;
}
@@ -208,6 +212,24 @@ int PS4_SYSV_ABI posix_getpagesize() {
return 16_KB;
}
+int PS4_SYSV_ABI posix_getsockname(Libraries::Net::OrbisNetId s,
+ Libraries::Net::OrbisNetSockaddr* addr, u32* paddrlen) {
+ auto* netcall = Common::Singleton::Instance();
+ auto sock = netcall->FindSocket(s);
+ if (!sock) {
+ *Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF;
+ LOG_ERROR(Lib_Net, "socket id is invalid = {}", s);
+ return -1;
+ }
+ int returncode = sock->GetSocketAddress(addr, paddrlen);
+ if (returncode >= 0) {
+ LOG_ERROR(Lib_Net, "return code : {:#x}", (u32)returncode);
+ return 0;
+ }
+ *Libraries::Kernel::__Error() = 0x20;
+ LOG_ERROR(Lib_Net, "error code returned : {:#x}", (u32)returncode);
+ return -1;
+}
void RegisterKernel(Core::Loader::SymbolsResolver* sym) {
service_thread = std::jthread{KernelServiceThread};
@@ -225,7 +247,6 @@ void RegisterKernel(Core::Loader::SymbolsResolver* sym) {
LIB_OBJ("f7uOxY9mM1U", "libkernel", 1, "libkernel", 1, 1, &g_stack_chk_guard);
LIB_FUNCTION("PfccT7qURYE", "libkernel", 1, "libkernel", 1, 1, kernel_ioctl);
LIB_FUNCTION("JGfTMBOdUJo", "libkernel", 1, "libkernel", 1, 1, sceKernelGetFsSandboxRandomWord);
- LIB_FUNCTION("XVL8So3QJUk", "libkernel", 1, "libkernel", 1, 1, posix_connect);
LIB_FUNCTION("6xVpy0Fdq+I", "libkernel", 1, "libkernel", 1, 1, _sigprocmask);
LIB_FUNCTION("Xjoosiw+XPI", "libkernel", 1, "libkernel", 1, 1, sceKernelUuidCreate);
LIB_FUNCTION("Ou3iL1abvng", "libkernel", 1, "libkernel", 1, 1, stack_chk_fail);
@@ -234,6 +255,24 @@ void RegisterKernel(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("k+AXqu2-eBc", "libScePosix", 1, "libkernel", 1, 1, posix_getpagesize);
LIB_FUNCTION("NWtTN10cJzE", "libSceLibcInternalExt", 1, "libSceLibcInternal", 1, 1,
sceLibcHeapGetTraceInfo);
+
+ // network
+ LIB_FUNCTION("XVL8So3QJUk", "libkernel", 1, "libkernel", 1, 1, Libraries::Net::sys_connect);
+ LIB_FUNCTION("TU-d9PfIHPM", "libkernel", 1, "libkernel", 1, 1, Libraries::Net::sys_socketex);
+ LIB_FUNCTION("KuOmgKoqCdY", "libkernel", 1, "libkernel", 1, 1, Libraries::Net::sys_bind);
+ LIB_FUNCTION("pxnCmagrtao", "libkernel", 1, "libkernel", 1, 1, Libraries::Net::sys_listen);
+ LIB_FUNCTION("3e+4Iv7IJ8U", "libkernel", 1, "libkernel", 1, 1, Libraries::Net::sys_accept);
+ LIB_FUNCTION("TU-d9PfIHPM", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sys_socket);
+ LIB_FUNCTION("oBr313PppNE", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sys_sendto);
+ LIB_FUNCTION("lUk6wrGXyMw", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sys_recvfrom);
+ LIB_FUNCTION("fFxGkxF2bVo", "libScePosix", 1, "libkernel", 1, 1,
+ Libraries::Net::sys_setsockopt);
+ // LIB_FUNCTION("RenI1lL1WFk", "libScePosix", 1, "libkernel", 1, 1, posix_getsockname);
+ LIB_FUNCTION("KuOmgKoqCdY", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sys_bind);
+ LIB_FUNCTION("5jRCs2axtr4", "libScePosix", 1, "libkernel", 1, 1,
+ Libraries::Net::sceNetInetNtop); // TODO fix it to sys_ ...
+ LIB_FUNCTION("4n51s0zEf0c", "libScePosix", 1, "libkernel", 1, 1,
+ Libraries::Net::sceNetInetPton); // TODO fix it to sys_ ...
}
} // namespace Libraries::Kernel
diff --git a/src/core/libraries/kernel/kernel.h b/src/core/libraries/kernel/kernel.h
index 58911727d..aaa22aec1 100644
--- a/src/core/libraries/kernel/kernel.h
+++ b/src/core/libraries/kernel/kernel.h
@@ -3,9 +3,6 @@
#pragma once
-#include
-#include
-#include "common/string_literal.h"
#include "common/types.h"
#include "core/libraries/kernel/orbis_error.h"
@@ -18,27 +15,23 @@ namespace Libraries::Kernel {
void ErrSceToPosix(int result);
int ErrnoToSceKernelError(int e);
void SetPosixErrno(int e);
+int* PS4_SYSV_ABI __Error();
-template
-struct WrapperImpl;
+template
+struct OrbisWrapperImpl;
-template
-struct WrapperImpl {
- static constexpr StringLiteral Name{name};
+template
+struct OrbisWrapperImpl {
static R PS4_SYSV_ABI wrap(Args... args) {
u32 ret = f(args...);
if (ret != 0) {
- // LOG_ERROR(Lib_Kernel, "Function {} returned {}", std::string_view{name.value}, ret);
ret += ORBIS_KERNEL_ERROR_UNKNOWN;
}
return ret;
}
};
-template
-constexpr auto OrbisWrapper = WrapperImpl::wrap;
-
-#define ORBIS(func) WrapperImpl<#func, decltype(&func), func>::wrap
+#define ORBIS(func) (Libraries::Kernel::OrbisWrapperImpl::wrap)
int* PS4_SYSV_ABI __Error();
diff --git a/src/core/libraries/kernel/memory.cpp b/src/core/libraries/kernel/memory.cpp
index 8a0c91479..cb41a664a 100644
--- a/src/core/libraries/kernel/memory.cpp
+++ b/src/core/libraries/kernel/memory.cpp
@@ -126,9 +126,6 @@ s32 PS4_SYSV_ABI sceKernelAvailableDirectMemorySize(u64 searchStart, u64 searchE
s32 PS4_SYSV_ABI sceKernelVirtualQuery(const void* addr, int flags, OrbisVirtualQueryInfo* info,
size_t infoSize) {
LOG_INFO(Kernel_Vmm, "called addr = {}, flags = {:#x}", fmt::ptr(addr), flags);
- if (!addr) {
- return ORBIS_KERNEL_ERROR_EACCES;
- }
auto* memory = Core::Memory::Instance();
return memory->VirtualQuery(std::bit_cast(addr), flags, info);
}
@@ -136,7 +133,6 @@ s32 PS4_SYSV_ABI sceKernelVirtualQuery(const void* addr, int flags, OrbisVirtual
s32 PS4_SYSV_ABI sceKernelReserveVirtualRange(void** addr, u64 len, int flags, u64 alignment) {
LOG_INFO(Kernel_Vmm, "addr = {}, len = {:#x}, flags = {:#x}, alignment = {:#x}",
fmt::ptr(*addr), len, flags, alignment);
-
if (addr == nullptr) {
LOG_ERROR(Kernel_Vmm, "Address is invalid!");
return ORBIS_KERNEL_ERROR_EINVAL;
@@ -155,9 +151,12 @@ s32 PS4_SYSV_ABI sceKernelReserveVirtualRange(void** addr, u64 len, int flags, u
auto* memory = Core::Memory::Instance();
const VAddr in_addr = reinterpret_cast(*addr);
const auto map_flags = static_cast(flags);
- memory->Reserve(addr, in_addr, len, map_flags, alignment);
- return ORBIS_OK;
+ s32 result = memory->Reserve(addr, in_addr, len, map_flags, alignment);
+ if (result == 0) {
+ LOG_INFO(Kernel_Vmm, "out_addr = {}", fmt::ptr(*addr));
+ }
+ return result;
}
int PS4_SYSV_ABI sceKernelMapNamedDirectMemory(void** addr, u64 len, int prot, int flags,
@@ -172,10 +171,12 @@ int PS4_SYSV_ABI sceKernelMapNamedDirectMemory(void** addr, u64 len, int prot, i
LOG_ERROR(Kernel_Vmm, "Map size is either zero or not 16KB aligned!");
return ORBIS_KERNEL_ERROR_EINVAL;
}
+
if (!Common::Is16KBAligned(directMemoryStart)) {
LOG_ERROR(Kernel_Vmm, "Start address is not 16KB aligned!");
return ORBIS_KERNEL_ERROR_EINVAL;
}
+
if (alignment != 0) {
if ((!std::has_single_bit(alignment) && !Common::Is16KBAligned(alignment))) {
LOG_ERROR(Kernel_Vmm, "Alignment value is invalid!");
@@ -183,14 +184,19 @@ int PS4_SYSV_ABI sceKernelMapNamedDirectMemory(void** addr, u64 len, int prot, i
}
}
+ if (std::strlen(name) >= ORBIS_KERNEL_MAXIMUM_NAME_LENGTH) {
+ LOG_ERROR(Kernel_Vmm, "name exceeds 32 bytes!");
+ return ORBIS_KERNEL_ERROR_ENAMETOOLONG;
+ }
+
const VAddr in_addr = reinterpret_cast(*addr);
const auto mem_prot = static_cast(prot);
const auto map_flags = static_cast(flags);
auto* memory = Core::Memory::Instance();
const auto ret =
- memory->MapMemory(addr, in_addr, len, mem_prot, map_flags, Core::VMAType::Direct, "", false,
- directMemoryStart, alignment);
+ memory->MapMemory(addr, in_addr, len, mem_prot, map_flags, Core::VMAType::Direct, name,
+ false, directMemoryStart, alignment);
LOG_INFO(Kernel_Vmm, "out_addr = {}", fmt::ptr(*addr));
return ret;
@@ -199,7 +205,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,
s64 directMemoryStart, u64 alignment) {
LOG_INFO(Kernel_Vmm, "called, redirected to sceKernelMapNamedDirectMemory");
- return sceKernelMapNamedDirectMemory(addr, len, prot, flags, directMemoryStart, alignment, "");
+ return sceKernelMapNamedDirectMemory(addr, len, prot, flags, directMemoryStart, alignment,
+ "anon");
+}
+
+s32 PS4_SYSV_ABI 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,
@@ -210,17 +230,16 @@ s32 PS4_SYSV_ABI sceKernelMapNamedFlexibleMemory(void** addr_in_out, std::size_t
return ORBIS_KERNEL_ERROR_EINVAL;
}
- static constexpr size_t MaxNameSize = 32;
- if (std::strlen(name) > MaxNameSize) {
- LOG_ERROR(Kernel_Vmm, "name exceeds 32 bytes!");
- return ORBIS_KERNEL_ERROR_ENAMETOOLONG;
- }
-
if (name == nullptr) {
LOG_ERROR(Kernel_Vmm, "name is invalid!");
return ORBIS_KERNEL_ERROR_EFAULT;
}
+ if (std::strlen(name) >= ORBIS_KERNEL_MAXIMUM_NAME_LENGTH) {
+ LOG_ERROR(Kernel_Vmm, "name exceeds 32 bytes!");
+ return ORBIS_KERNEL_ERROR_ENAMETOOLONG;
+ }
+
const VAddr in_addr = reinterpret_cast(*addr_in_out);
const auto mem_prot = static_cast(prot);
const auto map_flags = static_cast(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,
int flags) {
- return sceKernelMapNamedFlexibleMemory(addr_in_out, len, prot, flags, "");
+ return sceKernelMapNamedFlexibleMemory(addr_in_out, len, prot, flags, "anon");
}
int PS4_SYSV_ABI sceKernelQueryMemoryProtection(void* addr, void** start, void** end, u32* prot) {
@@ -284,6 +303,12 @@ int PS4_SYSV_ABI sceKernelGetDirectMemoryType(u64 addr, int* directMemoryTypeOut
directMemoryEndOut);
}
+int PS4_SYSV_ABI sceKernelIsStack(void* addr, void** start, void** end) {
+ LOG_DEBUG(Kernel_Vmm, "called, addr = {}", fmt::ptr(addr));
+ auto* memory = Core::Memory::Instance();
+ return memory->IsStack(std::bit_cast(addr), start, end);
+}
+
s32 PS4_SYSV_ABI sceKernelBatchMap(OrbisKernelBatchMapEntry* entries, int numEntries,
int* 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: {
result = sceKernelMapNamedDirectMemory(&entries[i].start, entries[i].length,
entries[i].protection, flags,
- static_cast(entries[i].offset), 0, "");
+ static_cast(entries[i].offset), 0, "anon");
LOG_INFO(Kernel_Vmm,
"entry = {}, operation = {}, len = {:#x}, offset = {:#x}, type = {}, "
"result = {}",
@@ -326,7 +351,7 @@ s32 PS4_SYSV_ABI sceKernelBatchMap2(OrbisKernelBatchMapEntry* entries, int numEn
}
case MemoryOpTypes::ORBIS_KERNEL_MAP_OP_MAP_FLEXIBLE: {
result = sceKernelMapNamedFlexibleMemory(&entries[i].start, entries[i].length,
- entries[i].protection, flags, "");
+ entries[i].protection, flags, "anon");
LOG_INFO(Kernel_Vmm,
"entry = {}, operation = {}, len = {:#x}, type = {}, "
"result = {}",
@@ -356,16 +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) {
- static constexpr size_t MaxNameSize = 32;
- if (std::strlen(name) > MaxNameSize) {
- LOG_ERROR(Kernel_Vmm, "name exceeds 32 bytes!");
- return ORBIS_KERNEL_ERROR_ENAMETOOLONG;
- }
-
if (name == nullptr) {
LOG_ERROR(Kernel_Vmm, "name is invalid!");
return ORBIS_KERNEL_ERROR_EFAULT;
}
+
+ if (std::strlen(name) >= ORBIS_KERNEL_MAXIMUM_NAME_LENGTH) {
+ LOG_ERROR(Kernel_Vmm, "name exceeds 32 bytes!");
+ return ORBIS_KERNEL_ERROR_ENAMETOOLONG;
+ }
+
auto* memory = Core::Memory::Instance();
memory->NameVirtualRange(std::bit_cast(addr), len, name);
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!");
return ORBIS_KERNEL_ERROR_EINVAL;
}
- const bool is_in_range = searchEnd - searchStart >= len;
- if (len <= 0 || !Common::Is64KBAligned(len) || !is_in_range) {
- LOG_ERROR(Kernel_Vmm, "Provided address range is invalid!");
+ if (len <= 0 || !Common::Is64KBAligned(len)) {
+ LOG_ERROR(Kernel_Vmm, "Provided length {:#x} is invalid!", len);
return ORBIS_KERNEL_ERROR_EINVAL;
}
if (alignment != 0 && !Common::Is64KBAligned(alignment)) {
- LOG_ERROR(Kernel_Vmm, "Alignment value is invalid!");
+ LOG_ERROR(Kernel_Vmm, "Alignment {:#x} is invalid!", alignment);
return ORBIS_KERNEL_ERROR_EINVAL;
}
if (physAddrOut == nullptr) {
@@ -391,8 +415,21 @@ s32 PS4_SYSV_ABI sceKernelMemoryPoolExpand(u64 searchStart, u64 searchEnd, size_
return ORBIS_KERNEL_ERROR_EINVAL;
}
+ const bool is_in_range = searchEnd - searchStart >= len;
+ if (searchEnd <= searchStart || searchEnd < len || !is_in_range) {
+ LOG_ERROR(Kernel_Vmm,
+ "Provided address range is too small!"
+ " searchStart = {:#x}, searchEnd = {:#x}, length = {:#x}",
+ searchStart, searchEnd, len);
+ return ORBIS_KERNEL_ERROR_ENOMEM;
+ }
+
auto* memory = Core::Memory::Instance();
PAddr phys_addr = memory->PoolExpand(searchStart, searchEnd, len, alignment);
+ if (phys_addr == -1) {
+ return ORBIS_KERNEL_ERROR_ENOMEM;
+ }
+
*physAddrOut = static_cast(phys_addr);
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}",
fmt::ptr(addrIn), len, alignment, flags);
- if (addrIn == nullptr) {
- LOG_ERROR(Kernel_Vmm, "Address is invalid!");
- return ORBIS_KERNEL_ERROR_EINVAL;
- }
if (len == 0 || !Common::Is2MBAligned(len)) {
LOG_ERROR(Kernel_Vmm, "Map size is either zero or not 2MB aligned!");
return ORBIS_KERNEL_ERROR_EINVAL;
@@ -463,9 +496,61 @@ s32 PS4_SYSV_ABI sceKernelMemoryPoolDecommit(void* addr, size_t len, int flags)
const VAddr pool_addr = reinterpret_cast(addr);
auto* memory = Core::Memory::Instance();
- memory->PoolDecommit(pool_addr, len);
- return ORBIS_OK;
+ return memory->PoolDecommit(pool_addr, len);
+}
+
+s32 PS4_SYSV_ABI sceKernelMemoryPoolBatch(const OrbisKernelMemoryPoolBatchEntry* entries, s32 count,
+ s32* num_processed, s32 flags) {
+ if (entries == nullptr) {
+ return ORBIS_KERNEL_ERROR_EINVAL;
+ }
+ s32 result = ORBIS_OK;
+ s32 processed = 0;
+
+ for (s32 i = 0; i < count; i++, processed++) {
+ OrbisKernelMemoryPoolBatchEntry entry = entries[i];
+ switch (entry.opcode) {
+ case OrbisKernelMemoryPoolOpcode::Commit: {
+ result = sceKernelMemoryPoolCommit(entry.commit_params.addr, entry.commit_params.len,
+ entry.commit_params.type, entry.commit_params.prot,
+ entry.flags);
+ break;
+ }
+ case OrbisKernelMemoryPoolOpcode::Decommit: {
+ result = sceKernelMemoryPoolDecommit(entry.decommit_params.addr,
+ entry.decommit_params.len, entry.flags);
+ break;
+ }
+ case OrbisKernelMemoryPoolOpcode::Protect: {
+ result = sceKernelMProtect(entry.protect_params.addr, entry.protect_params.len,
+ entry.protect_params.prot);
+ break;
+ }
+ case OrbisKernelMemoryPoolOpcode::TypeProtect: {
+ result = sceKernelMTypeProtect(
+ entry.type_protect_params.addr, entry.type_protect_params.len,
+ entry.type_protect_params.type, entry.type_protect_params.prot);
+ break;
+ }
+ case OrbisKernelMemoryPoolOpcode::Move: {
+ UNREACHABLE_MSG("Unimplemented sceKernelMemoryPoolBatch opcode Move");
+ }
+ default: {
+ result = ORBIS_KERNEL_ERROR_EINVAL;
+ break;
+ }
+ }
+
+ if (result != ORBIS_OK) {
+ break;
+ }
+ }
+
+ if (num_processed != nullptr) {
+ *num_processed = processed;
+ }
+ return result;
}
int PS4_SYSV_ABI sceKernelMmap(void* addr, u64 len, int prot, int flags, int fd, size_t offset,
@@ -570,8 +655,10 @@ void RegisterMemory(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("7oxv3PPCumo", "libkernel", 1, "libkernel", 1, 1, sceKernelReserveVirtualRange);
LIB_FUNCTION("BC+OG5m9+bw", "libkernel", 1, "libkernel", 1, 1, sceKernelGetDirectMemoryType);
LIB_FUNCTION("pO96TwzOm5E", "libkernel", 1, "libkernel", 1, 1, sceKernelGetDirectMemorySize);
+ LIB_FUNCTION("yDBwVAolDgg", "libkernel", 1, "libkernel", 1, 1, sceKernelIsStack);
LIB_FUNCTION("NcaWUxfMNIQ", "libkernel", 1, "libkernel", 1, 1, sceKernelMapNamedDirectMemory);
LIB_FUNCTION("L-Q3LEjIbgA", "libkernel", 1, "libkernel", 1, 1, sceKernelMapDirectMemory);
+ LIB_FUNCTION("BQQniolj9tQ", "libkernel", 1, "libkernel", 1, 1, sceKernelMapDirectMemory2);
LIB_FUNCTION("WFcfL2lzido", "libkernel", 1, "libkernel", 1, 1, sceKernelQueryMemoryProtection);
LIB_FUNCTION("BHouLQzh0X0", "libkernel", 1, "libkernel", 1, 1, sceKernelDirectMemoryQuery);
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("Vzl66WmfLvk", "libkernel", 1, "libkernel", 1, 1, sceKernelMemoryPoolCommit);
LIB_FUNCTION("LXo1tpFqJGs", "libkernel", 1, "libkernel", 1, 1, sceKernelMemoryPoolDecommit);
+ LIB_FUNCTION("YN878uKRBbE", "libkernel", 1, "libkernel", 1, 1, sceKernelMemoryPoolBatch);
LIB_FUNCTION("BPE9s9vQQXo", "libkernel", 1, "libkernel", 1, 1, posix_mmap);
LIB_FUNCTION("BPE9s9vQQXo", "libScePosix", 1, "libkernel", 1, 1, posix_mmap);
diff --git a/src/core/libraries/kernel/memory.h b/src/core/libraries/kernel/memory.h
index 400b6c3fc..92e158a00 100644
--- a/src/core/libraries/kernel/memory.h
+++ b/src/core/libraries/kernel/memory.h
@@ -47,6 +47,8 @@ enum MemoryOpTypes : u32 {
ORBIS_KERNEL_MAP_OP_TYPE_PROTECT = 4
};
+constexpr u32 ORBIS_KERNEL_MAXIMUM_NAME_LENGTH = 32;
+
struct OrbisQueryInfo {
uintptr_t start;
uintptr_t end;
@@ -59,15 +61,15 @@ struct OrbisVirtualQueryInfo {
size_t offset;
s32 protection;
s32 memory_type;
- union {
- BitField<0, 1, u32> is_flexible;
- BitField<1, 1, u32> is_direct;
- BitField<2, 1, u32> is_stack;
- BitField<3, 1, u32> is_pooled;
- BitField<4, 1, u32> is_committed;
- };
- std::array name;
+ u8 is_flexible : 1;
+ u8 is_direct : 1;
+ u8 is_stack : 1;
+ u8 is_pooled : 1;
+ u8 is_committed : 1;
+ char name[ORBIS_KERNEL_MAXIMUM_NAME_LENGTH];
};
+static_assert(sizeof(OrbisVirtualQueryInfo) == 72,
+ "OrbisVirtualQueryInfo struct size is incorrect");
struct OrbisKernelBatchMapEntry {
void* start;
@@ -79,6 +81,48 @@ struct OrbisKernelBatchMapEntry {
int operation;
};
+enum class OrbisKernelMemoryPoolOpcode : u32 {
+ Commit = 1,
+ Decommit = 2,
+ Protect = 3,
+ TypeProtect = 4,
+ Move = 5,
+};
+
+struct OrbisKernelMemoryPoolBatchEntry {
+ OrbisKernelMemoryPoolOpcode opcode;
+ u32 flags;
+ union {
+ struct {
+ void* addr;
+ u64 len;
+ u8 prot;
+ u8 type;
+ } commit_params;
+ struct {
+ void* addr;
+ u64 len;
+ } decommit_params;
+ struct {
+ void* addr;
+ u64 len;
+ u8 prot;
+ } protect_params;
+ struct {
+ void* addr;
+ u64 len;
+ u8 prot;
+ u8 type;
+ } type_protect_params;
+ struct {
+ void* dest_addr;
+ void* src_addr;
+ u64 len;
+ } move_params;
+ uintptr_t padding[3];
+ };
+};
+
u64 PS4_SYSV_ABI sceKernelGetDirectMemorySize();
int PS4_SYSV_ABI sceKernelAllocateDirectMemory(s64 searchStart, s64 searchEnd, u64 len,
u64 alignment, int memoryType, s64* physAddrOut);
@@ -114,6 +158,7 @@ void PS4_SYSV_ABI _sceKernelRtldSetApplicationHeapAPI(void* func[]);
int PS4_SYSV_ABI sceKernelGetDirectMemoryType(u64 addr, int* directMemoryTypeOut,
void** directMemoryStartOut,
void** directMemoryEndOut);
+int PS4_SYSV_ABI sceKernelIsStack(void* addr, void** start, void** end);
s32 PS4_SYSV_ABI sceKernelBatchMap(OrbisKernelBatchMapEntry* entries, int numEntries,
int* numEntriesOut);
@@ -128,6 +173,8 @@ s32 PS4_SYSV_ABI sceKernelMemoryPoolReserve(void* addrIn, size_t len, size_t ali
void** addrOut);
s32 PS4_SYSV_ABI sceKernelMemoryPoolCommit(void* addr, size_t len, int type, int prot, int flags);
s32 PS4_SYSV_ABI sceKernelMemoryPoolDecommit(void* addr, size_t len, int flags);
+s32 PS4_SYSV_ABI sceKernelMemoryPoolBatch(const OrbisKernelMemoryPoolBatchEntry* entries, s32 count,
+ s32* num_processed, s32 flags);
int PS4_SYSV_ABI sceKernelMunmap(void* addr, size_t len);
diff --git a/src/core/libraries/kernel/process.cpp b/src/core/libraries/kernel/process.cpp
index 02f8a538d..8a37e78d5 100644
--- a/src/core/libraries/kernel/process.cpp
+++ b/src/core/libraries/kernel/process.cpp
@@ -127,6 +127,62 @@ int PS4_SYSV_ABI sceKernelGetModuleInfoFromAddr(VAddr addr, int flags,
return ORBIS_OK;
}
+s32 PS4_SYSV_ABI sceKernelGetModuleInfo(s32 handle, Core::OrbisKernelModuleInfo* info) {
+ if (info == nullptr) {
+ return ORBIS_KERNEL_ERROR_EFAULT;
+ }
+ if (info->st_size != sizeof(Core::OrbisKernelModuleInfo)) {
+ return ORBIS_KERNEL_ERROR_EINVAL;
+ }
+
+ auto* linker = Common::Singleton::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::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::Instance();
+ u64 count = 0;
+ auto* module = linker->GetModule(count);
+ while (module != nullptr && count < num_array) {
+ handles[count] = count;
+ count++;
+ module = linker->GetModule(count);
+ }
+
+ if (count == num_array && module != nullptr) {
+ return ORBIS_KERNEL_ERROR_ENOMEM;
+ }
+
+ *out_count = count;
+ return ORBIS_OK;
+}
+
s32 PS4_SYSV_ABI exit(s32 status) {
UNREACHABLE_MSG("Exiting with status code {}", status);
return 0;
@@ -141,6 +197,9 @@ void RegisterProcess(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("LwG8g3niqwA", "libkernel", 1, "libkernel", 1, 1, sceKernelDlsym);
LIB_FUNCTION("RpQJJVKTiFM", "libkernel", 1, "libkernel", 1, 1, sceKernelGetModuleInfoForUnwind);
LIB_FUNCTION("f7KBOafysXo", "libkernel", 1, "libkernel", 1, 1, sceKernelGetModuleInfoFromAddr);
+ LIB_FUNCTION("kUpgrXIrz7Q", "libkernel", 1, "libkernel", 1, 1, sceKernelGetModuleInfo);
+ LIB_FUNCTION("HZO7xOos4xc", "libkernel", 1, "libkernel", 1, 1, sceKernelGetModuleInfoInternal);
+ LIB_FUNCTION("IuxnUuXk6Bg", "libkernel", 1, "libkernel", 1, 1, sceKernelGetModuleList);
LIB_FUNCTION("6Z83sYWFlA8", "libkernel", 1, "libkernel", 1, 1, exit);
}
diff --git a/src/core/libraries/kernel/threads.h b/src/core/libraries/kernel/threads.h
index 409136968..bcccf1695 100644
--- a/src/core/libraries/kernel/threads.h
+++ b/src/core/libraries/kernel/threads.h
@@ -17,6 +17,12 @@ int PS4_SYSV_ABI posix_pthread_attr_init(PthreadAttrT* attr);
int PS4_SYSV_ABI posix_pthread_attr_destroy(PthreadAttrT* attr);
+int PS4_SYSV_ABI posix_pthread_attr_getaffinity_np(const PthreadAttrT* pattr, size_t cpusetsize,
+ Cpuset* cpusetp);
+
+int PS4_SYSV_ABI posix_pthread_attr_setaffinity_np(PthreadAttrT* pattr, size_t cpusetsize,
+ const Cpuset* cpusetp);
+
int PS4_SYSV_ABI posix_pthread_create(PthreadT* thread, const PthreadAttrT* attr,
PthreadEntryFunc start_routine, void* arg);
@@ -35,7 +41,7 @@ public:
this->func = std::move(func);
PthreadAttrT attr{};
posix_pthread_attr_init(&attr);
- posix_pthread_create(&thread, &attr, RunWrapper, this);
+ posix_pthread_create(&thread, &attr, HOST_CALL(RunWrapper), this);
posix_pthread_attr_destroy(&attr);
}
diff --git a/src/core/libraries/kernel/threads/event_flag.cpp b/src/core/libraries/kernel/threads/event_flag.cpp
index 24ddcb927..91b17bd49 100644
--- a/src/core/libraries/kernel/threads/event_flag.cpp
+++ b/src/core/libraries/kernel/threads/event_flag.cpp
@@ -315,7 +315,7 @@ int PS4_SYSV_ABI sceKernelPollEventFlag(OrbisKernelEventFlag ef, u64 bitPattern,
auto result = ef->Poll(bitPattern, wait, clear, pResultPat);
if (result != ORBIS_OK && result != ORBIS_KERNEL_ERROR_EBUSY) {
- LOG_ERROR(Kernel_Event, "returned {}", result);
+ LOG_DEBUG(Kernel_Event, "returned {:#x}", result);
}
return result;
@@ -361,7 +361,7 @@ int PS4_SYSV_ABI sceKernelWaitEventFlag(OrbisKernelEventFlag ef, u64 bitPattern,
u32 result = ef->Wait(bitPattern, wait, clear, pResultPat, pTimeout);
if (result != ORBIS_OK && result != ORBIS_KERNEL_ERROR_ETIMEDOUT) {
- LOG_ERROR(Kernel_Event, "returned {:#x}", result);
+ LOG_DEBUG(Kernel_Event, "returned {:#x}", result);
}
return result;
diff --git a/src/core/libraries/kernel/threads/pthread.cpp b/src/core/libraries/kernel/threads/pthread.cpp
index c4127ecf2..61310bfb5 100644
--- a/src/core/libraries/kernel/threads/pthread.cpp
+++ b/src/core/libraries/kernel/threads/pthread.cpp
@@ -6,6 +6,7 @@
#include "core/debug_state.h"
#include "core/libraries/kernel/kernel.h"
#include "core/libraries/kernel/posix_error.h"
+#include "core/libraries/kernel/threads.h"
#include "core/libraries/kernel/threads/pthread.h"
#include "core/libraries/kernel/threads/thread_state.h"
#include "core/libraries/libs.h"
@@ -289,7 +290,12 @@ int PS4_SYSV_ABI posix_pthread_create_name_np(PthreadT* thread, const PthreadAtt
/* Create thread */
new_thread->native_thr = Core::NativeThread();
int ret = new_thread->native_thr.Create(RunThread, new_thread, &new_thread->attr);
+
ASSERT_MSG(ret == 0, "Failed to create thread with error {}", ret);
+
+ if (attr != nullptr && *attr != nullptr && (*attr)->cpuset != nullptr) {
+ new_thread->SetAffinity((*attr)->cpuset);
+ }
if (ret) {
*thread = nullptr;
}
@@ -521,6 +527,85 @@ int PS4_SYSV_ABI posix_pthread_setcancelstate(PthreadCancelState state,
return 0;
}
+int Pthread::SetAffinity(const Cpuset* cpuset) {
+ const auto processor_count = std::thread::hardware_concurrency();
+ if (processor_count < 8) {
+ return 0;
+ }
+ if (cpuset == nullptr) {
+ return POSIX_EINVAL;
+ }
+
+ uintptr_t handle = native_thr.GetHandle();
+ if (handle == 0) {
+ return POSIX_ESRCH;
+ }
+
+ // We don't use this currently because some games gets performance problems
+ // when applying affinity even on strong hardware
+ /*
+ u64 mask = cpuset->bits;
+ #ifdef _WIN64
+ DWORD_PTR affinity_mask = static_cast(mask);
+ if (!SetThreadAffinityMask(reinterpret_cast(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(handle), sizeof(cpu_set_t), &cpu_set);
+ if (result != 0) {
+ return POSIX_EINVAL;
+ }
+ #endif
+ */
+ return 0;
+}
+
+int PS4_SYSV_ABI posix_pthread_getaffinity_np(PthreadT thread, size_t cpusetsize, Cpuset* cpusetp) {
+ if (thread == nullptr || cpusetp == nullptr) {
+ return POSIX_EINVAL;
+ }
+ auto* attr_ptr = &thread->attr;
+ return posix_pthread_attr_getaffinity_np(&attr_ptr, cpusetsize, cpusetp);
+}
+
+int PS4_SYSV_ABI posix_pthread_setaffinity_np(PthreadT thread, size_t cpusetsize,
+ const Cpuset* cpusetp) {
+ if (thread == nullptr || cpusetp == nullptr) {
+ return POSIX_EINVAL;
+ }
+ auto* attr_ptr = &thread->attr;
+ if (const auto ret = posix_pthread_attr_setaffinity_np(&attr_ptr, cpusetsize, cpusetp)) {
+ return ret;
+ }
+ return thread->SetAffinity(thread->attr.cpuset);
+}
+
+int PS4_SYSV_ABI scePthreadGetaffinity(PthreadT thread, u64* mask) {
+ Cpuset cpuset;
+ const int ret = posix_pthread_getaffinity_np(thread, sizeof(Cpuset), &cpuset);
+ if (ret == 0) {
+ *mask = cpuset.bits;
+ }
+ return ret;
+}
+
+int PS4_SYSV_ABI scePthreadSetaffinity(PthreadT thread, const u64 mask) {
+ const Cpuset cpuset = {.bits = mask};
+ return posix_pthread_setaffinity_np(thread, sizeof(Cpuset), &cpuset);
+}
+
void RegisterThread(Core::Loader::SymbolsResolver* sym) {
// Posix
LIB_FUNCTION("Z4QosVuAsA0", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_once);
@@ -544,6 +629,8 @@ void RegisterThread(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("Z4QosVuAsA0", "libkernel", 1, "libkernel", 1, 1, posix_pthread_once);
LIB_FUNCTION("EotR8a3ASf4", "libkernel", 1, "libkernel", 1, 1, posix_pthread_self);
LIB_FUNCTION("OxhIB8LB-PQ", "libkernel", 1, "libkernel", 1, 1, posix_pthread_create);
+ LIB_FUNCTION("Jb2uGFMr688", "libkernel", 1, "libkernel", 1, 1, posix_pthread_getaffinity_np);
+ LIB_FUNCTION("5KWrg7-ZqvE", "libkernel", 1, "libkernel", 1, 1, posix_pthread_setaffinity_np);
// Orbis
LIB_FUNCTION("14bOACANTBo", "libkernel", 1, "libkernel", 1, 1, ORBIS(posix_pthread_once));
@@ -566,6 +653,8 @@ void RegisterThread(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("W0Hpm2X0uPE", "libkernel", 1, "libkernel", 1, 1, ORBIS(posix_pthread_setprio));
LIB_FUNCTION("rNhWz+lvOMU", "libkernel", 1, "libkernel", 1, 1, _sceKernelSetThreadDtors);
LIB_FUNCTION("6XG4B33N09g", "libkernel", 1, "libkernel", 1, 1, sched_yield);
+ LIB_FUNCTION("rcrVFJsQWRY", "libkernel", 1, "libkernel", 1, 1, ORBIS(scePthreadGetaffinity));
+ LIB_FUNCTION("bt3CTBKmGyI", "libkernel", 1, "libkernel", 1, 1, ORBIS(scePthreadSetaffinity));
}
} // namespace Libraries::Kernel
diff --git a/src/core/libraries/kernel/threads/pthread.h b/src/core/libraries/kernel/threads/pthread.h
index 089156776..ebcc4aed3 100644
--- a/src/core/libraries/kernel/threads/pthread.h
+++ b/src/core/libraries/kernel/threads/pthread.h
@@ -159,6 +159,7 @@ enum class SchedPolicy : u32 {
struct Cpuset {
u64 bits;
+ u64 _reserved;
};
struct PthreadAttr {
@@ -269,7 +270,7 @@ struct Pthread {
bool no_cancel;
bool cancel_async;
bool cancelling;
- Cpuset sigmask;
+ u64 sigmask;
bool unblock_sigcancel;
bool in_sigsuspend;
bool force_exit;
@@ -332,6 +333,8 @@ struct Pthread {
return true;
}
}
+
+ int SetAffinity(const Cpuset* cpuset);
};
using PthreadT = Pthread*;
diff --git a/src/core/libraries/kernel/threads/pthread_attr.cpp b/src/core/libraries/kernel/threads/pthread_attr.cpp
index a8e60ccf8..71f6438a6 100644
--- a/src/core/libraries/kernel/threads/pthread_attr.cpp
+++ b/src/core/libraries/kernel/threads/pthread_attr.cpp
@@ -243,7 +243,7 @@ int PS4_SYSV_ABI posix_pthread_attr_getaffinity_np(const PthreadAttrT* pattr, si
if (attr->cpuset != nullptr)
memcpy(cpusetp, attr->cpuset, std::min(cpusetsize, attr->cpusetsize));
else
- memset(cpusetp, -1, sizeof(Cpuset));
+ memset(cpusetp, -1, cpusetsize);
return 0;
}
@@ -259,30 +259,31 @@ int PS4_SYSV_ABI posix_pthread_attr_setaffinity_np(PthreadAttrT* pattr, size_t c
if (cpusetsize == 0 || cpusetp == nullptr) {
if (attr->cpuset != nullptr) {
free(attr->cpuset);
- attr->cpuset = NULL;
+ attr->cpuset = nullptr;
attr->cpusetsize = 0;
}
return 0;
}
if (attr->cpuset == nullptr) {
- attr->cpuset = (Cpuset*)calloc(1, sizeof(Cpuset));
+ attr->cpuset = static_cast(calloc(1, sizeof(Cpuset)));
attr->cpusetsize = sizeof(Cpuset);
}
- memcpy(attr->cpuset, cpusetp, sizeof(Cpuset));
+ memcpy(attr->cpuset, cpusetp, std::min(cpusetsize, sizeof(Cpuset)));
return 0;
}
-int PS4_SYSV_ABI scePthreadAttrGetaffinity(PthreadAttrT* param_1, Cpuset* mask) {
+int PS4_SYSV_ABI scePthreadAttrGetaffinity(PthreadAttrT* attr, u64* mask) {
Cpuset cpuset;
- const int ret = posix_pthread_attr_getaffinity_np(param_1, 0x10, &cpuset);
+ const int ret = posix_pthread_attr_getaffinity_np(attr, sizeof(Cpuset), &cpuset);
if (ret == 0) {
- *mask = cpuset;
+ *mask = cpuset.bits;
}
return ret;
}
-int PS4_SYSV_ABI scePthreadAttrSetaffinity(PthreadAttrT* attr, const Cpuset mask) {
- return posix_pthread_attr_setaffinity_np(attr, 0x10, &mask);
+int PS4_SYSV_ABI scePthreadAttrSetaffinity(PthreadAttrT* attr, const u64 mask) {
+ const Cpuset cpuset = {.bits = mask};
+ return posix_pthread_attr_setaffinity_np(attr, sizeof(Cpuset), &cpuset);
}
void RegisterThreadAttr(Core::Loader::SymbolsResolver* sym) {
diff --git a/src/core/libraries/kernel/time.cpp b/src/core/libraries/kernel/time.cpp
index b7e4c1756..2fe74d0a3 100644
--- a/src/core/libraries/kernel/time.cpp
+++ b/src/core/libraries/kernel/time.cpp
@@ -5,24 +5,23 @@
#include "common/assert.h"
#include "common/native_clock.h"
+#include "common/thread.h"
#include "core/libraries/kernel/kernel.h"
#include "core/libraries/kernel/orbis_error.h"
+#include "core/libraries/kernel/posix_error.h"
#include "core/libraries/kernel/time.h"
#include "core/libraries/libs.h"
#ifdef _WIN64
-#include
#include
-
#include "common/ntapi.h"
-
#else
#if __APPLE__
#include
#endif
+#include
#include
#include
-#include
#include
#endif
@@ -52,88 +51,116 @@ u64 PS4_SYSV_ABI sceKernelReadTsc() {
return clock->GetUptime();
}
-int PS4_SYSV_ABI sceKernelUsleep(u32 microseconds) {
-#ifdef _WIN64
- const auto start_time = std::chrono::high_resolution_clock::now();
- auto total_wait_time = std::chrono::microseconds(microseconds);
+static s32 posix_nanosleep_impl(const OrbisKernelTimespec* rqtp, OrbisKernelTimespec* rmtp,
+ const bool interruptible) {
+ if (!rqtp || rqtp->tv_sec < 0 || rqtp->tv_nsec < 0 || rqtp->tv_nsec >= 1'000'000'000) {
+ SetPosixErrno(EINVAL);
+ return -1;
+ }
+ 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) {
+ SetPosixErrno(EINTR);
+ return -1;
+ }
+ return 0;
+}
- while (total_wait_time.count() > 0) {
- auto wait_time = std::chrono::ceil(total_wait_time).count();
- u64 res = SleepEx(static_cast(wait_time), true);
- if (res == WAIT_IO_COMPLETION) {
- auto elapsedTime = std::chrono::high_resolution_clock::now() - start_time;
- auto elapsedMicroseconds =
- std::chrono::duration_cast(elapsedTime).count();
- total_wait_time = std::chrono::microseconds(microseconds - elapsedMicroseconds);
- } else {
- break;
- }
+s32 PS4_SYSV_ABI posix_nanosleep(const OrbisKernelTimespec* rqtp, OrbisKernelTimespec* rmtp) {
+ return posix_nanosleep_impl(rqtp, rmtp, true);
+}
+
+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;
}
- return 0;
-#else
- 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
-}
+ if (clock_id == ORBIS_CLOCK_PROCTIME) {
+ const auto us = sceKernelGetProcessTime();
+ ts->tv_sec = static_cast(us / 1'000'000);
+ ts->tv_nsec = static_cast((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;
+ }
-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;
-}
-
-#ifdef _WIN64
-#ifndef CLOCK_REALTIME
-#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(&ft);
-}
-
-static s32 clock_gettime(u32 clock_id, struct timespec* ts) {
+#ifdef _WIN32
+ static const auto FileTimeTo100Ns = [](FILETIME& ft) { return *reinterpret_cast(&ft); };
switch (clock_id) {
- case CLOCK_REALTIME:
- case CLOCK_REALTIME_COARSE: {
+ case ORBIS_CLOCK_REALTIME:
+ case ORBIS_CLOCK_REALTIME_PRECISE: {
FILETIME ft;
- GetSystemTimeAsFileTime(&ft);
- const u64 ns = FileTimeTo100Ns(ft) - DELTA_EPOCH_IN_100NS;
+ GetSystemTimePreciseAsFileTime(&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 CLOCK_MONOTONIC:
- case CLOCK_MONOTONIC_COARSE: {
+ case ORBIS_CLOCK_SECOND:
+ 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 = [] {
LARGE_INTEGER res{};
QueryPerformanceFrequency(&pf);
@@ -141,43 +168,53 @@ static s32 clock_gettime(u32 clock_id, struct timespec* ts) {
}();
LARGE_INTEGER pc{};
- QueryPerformanceCounter(&pc);
+ if (!QueryPerformanceCounter(&pc)) {
+ SetPosixErrno(EFAULT);
+ return -1;
+ }
ts->tv_sec = pc.QuadPart / pf.QuadPart;
ts->tv_nsec = ((pc.QuadPart % pf.QuadPart) * 1000'000'000) / pf.QuadPart;
return 0;
}
- case CLOCK_PROCESS_CPUTIME_ID: {
+ case ORBIS_CLOCK_THREAD_CPUTIME_ID: {
FILETIME ct, et, kt, ut;
- if (!GetProcessTimes(GetCurrentProcess(), &ct, &et, &kt, &ut)) {
- return EFAULT;
+ if (!GetThreadTimes(GetCurrentThread(), &ct, &et, &kt, &ut)) {
+ SetPosixErrno(EFAULT);
+ return -1;
}
const u64 ns = FileTimeTo100Ns(ut) + FileTimeTo100Ns(kt);
ts->tv_sec = ns / 10'000'000;
ts->tv_nsec = (ns % 10'000'000) * 100;
return 0;
}
- case CLOCK_THREAD_CPUTIME_ID: {
+ case ORBIS_CLOCK_VIRTUAL: {
FILETIME ct, et, kt, ut;
- if (!GetThreadTimes(GetCurrentThread(), &ct, &et, &kt, &ut)) {
- return EFAULT;
+ if (!GetProcessTimes(GetCurrentProcess(), &ct, &et, &kt, &ut)) {
+ 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_nsec = (ns % 10'000'000) * 100;
return 0;
}
default:
- return EINVAL;
+ SetPosixErrno(EFAULT);
+ return -1;
}
-}
-#endif
-
-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;
+#else
+ clockid_t pclock_id;
switch (clock_id) {
case ORBIS_CLOCK_REALTIME:
case ORBIS_CLOCK_REALTIME_PRECISE:
@@ -185,7 +222,7 @@ int PS4_SYSV_ABI orbis_clock_gettime(s32 clock_id, struct OrbisKernelTimespec* t
break;
case ORBIS_CLOCK_SECOND:
case ORBIS_CLOCK_REALTIME_FAST:
-#ifndef __APPLE__
+#ifdef CLOCK_REALTIME_COARSE
pclock_id = CLOCK_REALTIME_COARSE;
#else
pclock_id = CLOCK_REALTIME;
@@ -199,7 +236,7 @@ int PS4_SYSV_ABI orbis_clock_gettime(s32 clock_id, struct OrbisKernelTimespec* t
break;
case ORBIS_CLOCK_UPTIME_FAST:
case ORBIS_CLOCK_MONOTONIC_FAST:
-#ifndef __APPLE__
+#ifdef CLOCK_MONOTONIC_COARSE
pclock_id = CLOCK_MONOTONIC_COARSE;
#else
pclock_id = CLOCK_MONOTONIC;
@@ -208,196 +245,226 @@ int PS4_SYSV_ABI orbis_clock_gettime(s32 clock_id, struct OrbisKernelTimespec* t
case ORBIS_CLOCK_THREAD_CPUTIME_ID:
pclock_id = CLOCK_THREAD_CPUTIME_ID;
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: {
-#ifdef _WIN64
- 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;
+ rusage ru;
const auto res = getrusage(RUSAGE_SELF, &ru);
if (res < 0) {
- return res;
+ SetPosixErrno(EFAULT);
+ return -1;
}
ts->tv_sec = ru.ru_utime.tv_sec;
ts->tv_nsec = ru.ru_utime.tv_usec * 1000;
-#endif
return 0;
}
case ORBIS_CLOCK_PROF: {
-#ifdef _WIN64
- 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;
+ rusage ru;
const auto res = getrusage(RUSAGE_SELF, &ru);
if (res < 0) {
- return res;
+ SetPosixErrno(EFAULT);
+ return -1;
}
ts->tv_sec = ru.ru_stime.tv_sec;
ts->tv_nsec = ru.ru_stime.tv_usec * 1000;
-#endif
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:
- return EINVAL;
+ SetPosixErrno(EFAULT);
+ return -1;
}
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_nsec = t.tv_nsec;
- return result;
-}
-
-int PS4_SYSV_ABI sceKernelClockGettime(s32 clock_id, OrbisKernelTimespec* tp) {
- const auto res = orbis_clock_gettime(clock_id, tp);
- if (res < 0) {
- return ErrnoToSceKernelError(res);
+ if (result < 0) {
+ SetPosixErrno(errno);
+ return -1;
}
- return ORBIS_OK;
-}
-
-int PS4_SYSV_ABI posix_nanosleep(const OrbisKernelTimespec* rqtp, OrbisKernelTimespec* rmtp) {
- const auto* request = reinterpret_cast(rqtp);
- auto* remain = reinterpret_cast(rmtp);
- return nanosleep(request, remain);
-}
-
-int PS4_SYSV_ABI sceKernelNanosleep(const OrbisKernelTimespec* rqtp, OrbisKernelTimespec* rmtp) {
- if (!rqtp || !rmtp) {
- return ORBIS_KERNEL_ERROR_EFAULT;
- }
-
- if (rqtp->tv_sec < 0 || rqtp->tv_nsec < 0) {
- return ORBIS_KERNEL_ERROR_EINVAL;
- }
-
- return posix_nanosleep(rqtp, rmtp);
-}
-
-int PS4_SYSV_ABI sceKernelGettimeofday(OrbisKernelTimeval* tp) {
- if (!tp) {
- return ORBIS_KERNEL_ERROR_EFAULT;
- }
-
-#ifdef _WIN64
- FILETIME filetime;
- GetSystemTimePreciseAsFileTime(&filetime);
-
- constexpr u64 UNIX_TIME_START = 0x295E9648864000;
- constexpr u64 TICKS_PER_SECOND = 1000000;
-
- u64 ticks = filetime.dwHighDateTime;
- ticks <<= 32;
- ticks |= filetime.dwLowDateTime;
- ticks /= 10;
- ticks -= UNIX_TIME_START;
-
- tp->tv_sec = 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;
+ return 0;
#endif
+}
+
+s32 PS4_SYSV_ABI sceKernelClockGettime(const u32 clock_id, OrbisKernelTimespec* ts) {
+ if (const auto ret = posix_clock_gettime(clock_id, ts); ret < 0) {
+ return ErrnoToSceKernelError(*__Error());
+ }
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) {
- 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;
- if (!tzflag) {
- _tzset();
- tzflag++;
- }
- tz->tz_minuteswest = _timezone / 60;
- tz->tz_dsttime = _daylight;
-#else
- struct timezone tzz;
- struct timeval tv;
- gettimeofday(&tv, &tzz);
- tz->tz_dsttime = tzz.tz_dsttime;
- tz->tz_minuteswest = tzz.tz_minuteswest;
-#endif
- return ORBIS_OK;
-}
-
-int PS4_SYSV_ABI posix_clock_getres(u32 clock_id, OrbisKernelTimespec* res) {
+s32 PS4_SYSV_ABI posix_clock_getres(u32 clock_id, OrbisKernelTimespec* res) {
if (res == nullptr) {
- return ORBIS_KERNEL_ERROR_EFAULT;
+ SetPosixErrno(EFAULT);
+ return -1;
}
- clockid_t pclock_id = CLOCK_REALTIME;
+
+ 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
+ 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((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:
- case ORBIS_CLOCK_REALTIME_FAST:
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:
- case ORBIS_CLOCK_MONOTONIC_FAST:
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();
}
timespec t{};
- int result = clock_getres(pclock_id, &t);
+ const auto result = clock_getres(pclock_id, &t);
res->tv_sec = t.tv_sec;
res->tv_nsec = t.tv_nsec;
- if (result == 0) {
- return ORBIS_OK;
+ if (result < 0) {
+ SetPosixErrno(errno);
+ return -1;
}
- return ORBIS_KERNEL_ERROR_EINVAL;
+ return 0;
+#endif
}
-int PS4_SYSV_ABI sceKernelConvertLocaltimeToUtc(time_t param_1, int64_t param_2, time_t* seconds,
- OrbisKernelTimezone* timezone, int* dst_seconds) {
+s32 PS4_SYSV_ABI sceKernelClockGetres(const u32 clock_id, OrbisKernelTimespec* res) {
+ if (const auto ret = posix_clock_getres(clock_id, res); ret < 0) {
+ return ErrnoToSceKernelError(*__Error());
+ }
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI posix_gettimeofday(OrbisKernelTimeval* tp, OrbisKernelTimezone* tz) {
+#ifdef _WIN64
+ if (tp) {
+ FILETIME filetime;
+ GetSystemTimePreciseAsFileTime(&filetime);
+
+ constexpr u64 UNIX_TIME_START = 0x295E9648864000;
+ constexpr u64 TICKS_PER_SECOND = 1000000;
+
+ u64 ticks = filetime.dwHighDateTime;
+ ticks <<= 32;
+ ticks |= filetime.dwLowDateTime;
+ ticks /= 10;
+ ticks -= UNIX_TIME_START;
+
+ tp->tv_sec = ticks / TICKS_PER_SECOND;
+ tp->tv_usec = ticks % TICKS_PER_SECOND;
+ }
+ if (tz) {
+ static int tzflag = 0;
+ if (!tzflag) {
+ _tzset();
+ tzflag++;
+ }
+ tz->tz_minuteswest = _timezone / 60;
+ tz->tz_dsttime = _daylight;
+ }
+ return 0;
+#else
+ struct timezone tzz;
+ timeval tv;
+ 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_minuteswest = tzz.tz_minuteswest;
+ }
+ if (ret < 0) {
+ SetPosixErrno(errno);
+ return -1;
+ }
+ return 0;
+#endif
+}
+
+s32 PS4_SYSV_ABI sceKernelGettimeofday(OrbisKernelTimeval* tp) {
+ if (const auto ret = posix_gettimeofday(tp, nullptr); ret < 0) {
+ return ErrnoToSceKernelError(*__Error());
+ }
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceKernelGettimezone(OrbisKernelTimezone* tz) {
+ if (const auto ret = posix_gettimeofday(nullptr, tz); ret < 0) {
+ return ErrnoToSceKernelError(*__Error());
+ }
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceKernelConvertLocaltimeToUtc(time_t param_1, int64_t param_2, time_t* seconds,
+ OrbisKernelTimezone* timezone, s32* dst_seconds) {
LOG_INFO(Kernel, "called");
if (timezone) {
sceKernelGettimezone(timezone);
param_1 -= (timezone->tz_minuteswest + timezone->tz_dsttime) * 60;
- if (seconds)
+ if (seconds) {
*seconds = param_1;
- if (dst_seconds)
+ }
+ if (dst_seconds) {
*dst_seconds = timezone->tz_dsttime * 60;
+ }
} else {
return ORBIS_KERNEL_ERROR_EINVAL;
}
@@ -415,7 +482,7 @@ Common::NativeClock* GetClock() {
} // 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) {
LOG_TRACE(Kernel, "Called");
#ifdef __APPLE__
@@ -444,28 +511,35 @@ int PS4_SYSV_ABI sceKernelConvertUtcToLocaltime(time_t time, time_t* local_time,
void RegisterTime(Core::Loader::SymbolsResolver* sym) {
clock = std::make_unique();
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("fgxnMeTNUtY", "libkernel", 1, "libkernel", 1, 1, sceKernelGetProcessTimeCounter);
LIB_FUNCTION("BNowx2l588E", "libkernel", 1, "libkernel", 1, 1,
sceKernelGetProcessTimeCounterFrequency);
LIB_FUNCTION("-2IRUCO--PM", "libkernel", 1, "libkernel", 1, 1, sceKernelReadTsc);
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("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("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("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("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("-o5uEDpN+oY", "libkernel", 1, "libkernel", 1, 1, sceKernelConvertUtcToLocaltime);
}
diff --git a/src/core/libraries/kernel/time.h b/src/core/libraries/kernel/time.h
index 407b6f9ed..c80de7bc4 100644
--- a/src/core/libraries/kernel/time.h
+++ b/src/core/libraries/kernel/time.h
@@ -75,14 +75,14 @@ u64 PS4_SYSV_ABI sceKernelGetProcessTime();
u64 PS4_SYSV_ABI sceKernelGetProcessTimeCounter();
u64 PS4_SYSV_ABI sceKernelGetProcessTimeCounterFrequency();
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);
-int PS4_SYSV_ABI sceKernelConvertLocaltimeToUtc(time_t param_1, int64_t param_2, time_t* seconds,
- OrbisKernelTimezone* timezone, int* dst_seconds);
+s32 PS4_SYSV_ABI sceKernelConvertLocaltimeToUtc(time_t param_1, int64_t param_2, time_t* 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);
-int PS4_SYSV_ABI sceKernelUsleep(u32 microseconds);
+s32 PS4_SYSV_ABI sceKernelUsleep(u32 microseconds);
void RegisterTime(Core::Loader::SymbolsResolver* sym);
diff --git a/src/core/libraries/libc_internal/printf.h b/src/core/libraries/libc_internal/printf.h
index fe63481a0..9c22e922c 100644
--- a/src/core/libraries/libc_internal/printf.h
+++ b/src/core/libraries/libc_internal/printf.h
@@ -56,7 +56,6 @@
#include
#include
-#include
#include
#include
#include
diff --git a/src/core/libraries/libs.cpp b/src/core/libraries/libs.cpp
index 3f5baf640..2ab46d3a0 100644
--- a/src/core/libraries/libs.cpp
+++ b/src/core/libraries/libs.cpp
@@ -8,6 +8,8 @@
#include "core/libraries/audio/audioout.h"
#include "core/libraries/audio3d/audio3d.h"
#include "core/libraries/avplayer/avplayer.h"
+#include "core/libraries/camera/camera.h"
+#include "core/libraries/companion/companion_httpd.h"
#include "core/libraries/disc_map/disc_map.h"
#include "core/libraries/game_live_streaming/gamelivestreaming.h"
#include "core/libraries/gnmdriver/gnmdriver.h"
@@ -45,6 +47,7 @@
#include "core/libraries/save_data/savedata.h"
#include "core/libraries/screenshot/screenshot.h"
#include "core/libraries/share_play/shareplay.h"
+#include "core/libraries/signin_dialog/signindialog.h"
#include "core/libraries/system/commondialog.h"
#include "core/libraries/system/msgdialog.h"
#include "core/libraries/system/posix.h"
@@ -120,6 +123,9 @@ void InitHLELibs(Core::Loader::SymbolsResolver* sym) {
Libraries::Hmd::RegisterlibSceHmd(sym);
Libraries::DiscMap::RegisterlibSceDiscMap(sym);
Libraries::Ulobjmgr::RegisterlibSceUlobjmgr(sym);
+ Libraries::SigninDialog::RegisterlibSceSigninDialog(sym);
+ Libraries::Camera::RegisterlibSceCamera(sym);
+ Libraries::CompanionHttpd::RegisterlibSceCompanionHttpd(sym);
}
} // namespace Libraries
diff --git a/src/core/libraries/libs.h b/src/core/libraries/libs.h
index aa5ba4a97..d9c8216a5 100644
--- a/src/core/libraries/libs.h
+++ b/src/core/libraries/libs.h
@@ -3,13 +3,9 @@
#pragma once
-#include
-
-#include "common/logging/log.h"
#include "core/loader/elf.h"
#include "core/loader/symbols_resolver.h"
-
-#define W(foo) foo
+#include "core/tls.h"
#define LIB_FUNCTION(nid, lib, libversion, mod, moduleVersionMajor, moduleVersionMinor, function) \
{ \
@@ -21,11 +17,11 @@
sr.module_version_major = moduleVersionMajor; \
sr.module_version_minor = moduleVersionMinor; \
sr.type = Core::Loader::SymbolType::Function; \
- auto func = reinterpret_cast(function); \
+ auto func = reinterpret_cast(HOST_CALL(function)); \
sym->AddSymbol(sr, func); \
}
-#define LIB_OBJ(nid, lib, libversion, mod, moduleVersionMajor, moduleVersionMinor, function) \
+#define LIB_OBJ(nid, lib, libversion, mod, moduleVersionMajor, moduleVersionMinor, obj) \
{ \
Core::Loader::SymbolResolver sr{}; \
sr.name = nid; \
@@ -35,8 +31,7 @@
sr.module_version_major = moduleVersionMajor; \
sr.module_version_minor = moduleVersionMinor; \
sr.type = Core::Loader::SymbolType::Object; \
- auto func = reinterpret_cast(function); \
- sym->AddSymbol(sr, func); \
+ sym->AddSymbol(sr, reinterpret_cast(obj)); \
}
namespace Libraries {
diff --git a/src/core/libraries/network/net.cpp b/src/core/libraries/network/net.cpp
index 161fc5214..0ef4a84f5 100644
--- a/src/core/libraries/network/net.cpp
+++ b/src/core/libraries/network/net.cpp
@@ -10,16 +10,24 @@
#include
#endif
+#include
#include "common/assert.h"
#include "common/logging/log.h"
+#include "common/singleton.h"
#include "core/libraries/error_codes.h"
#include "core/libraries/libs.h"
#include "core/libraries/network/net.h"
+#include "net_error.h"
+#include "net_util.h"
+#include "netctl.h"
+#include "sys_net.h"
namespace Libraries::Net {
static thread_local int32_t net_errno = 0;
+static bool g_isNetInitialized = true; // TODO init it properly
+
int PS4_SYSV_ABI in6addr_any() {
LOG_ERROR(Lib_Net, "(STUBBED) called");
return ORBIS_OK;
@@ -61,8 +69,45 @@ int PS4_SYSV_ABI sce_net_in6addr_nodelocal_allnodes() {
}
OrbisNetId PS4_SYSV_ABI sceNetAccept(OrbisNetId s, OrbisNetSockaddr* addr, u32* paddrlen) {
- LOG_ERROR(Lib_Net, "(STUBBED) called");
- return ORBIS_OK;
+ if (!g_isNetInitialized) {
+ return ORBIS_NET_ERROR_ENOTINIT;
+ }
+ int result;
+ int err;
+ int positiveErr;
+
+ do {
+ result = sys_accept(s, addr, paddrlen);
+
+ if (result >= 0) {
+ return result; // Success
+ }
+
+ err = *Libraries::Kernel::__Error(); // Standard errno
+
+ // Convert to positive error for comparison
+ int positiveErr = (err < 0) ? -err : err;
+
+ if ((positiveErr & 0xfff0000) != 0) {
+ // Unknown/fatal error range
+ *sceNetErrnoLoc() = ORBIS_NET_ERETURN;
+ return -positiveErr;
+ }
+
+ // Retry if interrupted
+ } while (positiveErr == ORBIS_NET_EINTR);
+
+ if (positiveErr == ORBIS_NET_EADDRINUSE) {
+ result = -ORBIS_NET_EBADF;
+ } else if (positiveErr == ORBIS_NET_EALREADY) {
+ result = -ORBIS_NET_EINTR;
+ } else {
+ result = -positiveErr;
+ }
+
+ *sceNetErrnoLoc() = -result;
+
+ return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
}
int PS4_SYSV_ABI sceNetAddrConfig6GetInfo() {
@@ -121,8 +166,45 @@ int PS4_SYSV_ABI sceNetBandwidthControlSetPolicy() {
}
int PS4_SYSV_ABI sceNetBind(OrbisNetId s, const OrbisNetSockaddr* addr, u32 addrlen) {
- LOG_ERROR(Lib_Net, "(STUBBED) called");
- return ORBIS_OK;
+ if (!g_isNetInitialized) {
+ return ORBIS_NET_ERROR_ENOTINIT;
+ }
+ int result;
+ int err;
+ int positiveErr;
+
+ do {
+ result = sys_bind(s, addr, addrlen);
+
+ if (result >= 0) {
+ return result; // Success
+ }
+
+ err = *Libraries::Kernel::__Error(); // Standard errno
+
+ // Convert to positive error for comparison
+ int positiveErr = (err < 0) ? -err : err;
+
+ if ((positiveErr & 0xfff0000) != 0) {
+ // Unknown/fatal error range
+ *sceNetErrnoLoc() = ORBIS_NET_ERETURN;
+ return -positiveErr;
+ }
+
+ // Retry if interrupted
+ } while (positiveErr == ORBIS_NET_EINTR);
+
+ if (positiveErr == ORBIS_NET_EADDRINUSE) {
+ result = -ORBIS_NET_EBADF;
+ } else if (positiveErr == ORBIS_NET_EALREADY) {
+ result = -ORBIS_NET_EINTR;
+ } else {
+ result = -positiveErr;
+ }
+
+ *sceNetErrnoLoc() = -result;
+
+ return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
}
int PS4_SYSV_ABI sceNetClearDnsCache() {
@@ -465,9 +547,46 @@ int PS4_SYSV_ABI sceNetConfigWlanSetDeviceConfig() {
return ORBIS_OK;
}
-int PS4_SYSV_ABI sceNetConnect() {
- LOG_ERROR(Lib_Net, "(STUBBED) called");
- return ORBIS_OK;
+int PS4_SYSV_ABI sceNetConnect(OrbisNetId s, const OrbisNetSockaddr* addr, u32 addrlen) {
+ if (!g_isNetInitialized) {
+ return ORBIS_NET_ERROR_ENOTINIT;
+ }
+ int result;
+ int err;
+ int positiveErr;
+
+ do {
+ result = sys_connect(s, addr, addrlen);
+
+ if (result >= 0) {
+ return result; // Success
+ }
+
+ err = *Libraries::Kernel::__Error(); // Standard errno
+
+ // Convert to positive error for comparison
+ int positiveErr = (err < 0) ? -err : err;
+
+ if ((positiveErr & 0xfff0000) != 0) {
+ // Unknown/fatal error range
+ *sceNetErrnoLoc() = ORBIS_NET_ERETURN;
+ return -positiveErr;
+ }
+
+ // Retry if interrupted
+ } while (positiveErr == ORBIS_NET_EINTR);
+
+ if (positiveErr == ORBIS_NET_EADDRINUSE) {
+ result = -ORBIS_NET_EBADF;
+ } else if (positiveErr == ORBIS_NET_EALREADY) {
+ result = -ORBIS_NET_EINTR;
+ } else {
+ result = -positiveErr;
+ }
+
+ *sceNetErrnoLoc() = -result;
+
+ return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
}
int PS4_SYSV_ABI sceNetControl() {
@@ -640,8 +759,15 @@ int PS4_SYSV_ABI sceNetGetIfnameNumList() {
return ORBIS_OK;
}
-int PS4_SYSV_ABI sceNetGetMacAddress() {
- LOG_ERROR(Lib_Net, "(STUBBED) called");
+int PS4_SYSV_ABI sceNetGetMacAddress(Libraries::NetCtl::OrbisNetEtherAddr* addr, int flags) {
+ if (addr == nullptr) {
+ LOG_ERROR(Lib_Net, "addr is null!");
+ return ORBIS_NET_EINVAL;
+ }
+ auto* netinfo = Common::Singleton::Instance();
+ netinfo->RetrieveEthernetAddr();
+ memcpy(addr->data, netinfo->GetEthernetAddr().data(), 6);
+
return ORBIS_OK;
}
@@ -655,9 +781,46 @@ int PS4_SYSV_ABI sceNetGetNameToIndex() {
return ORBIS_OK;
}
-int PS4_SYSV_ABI sceNetGetpeername() {
- LOG_ERROR(Lib_Net, "(STUBBED) called");
- return ORBIS_OK;
+int PS4_SYSV_ABI sceNetGetpeername(OrbisNetId s, OrbisNetSockaddr* addr, u32* paddrlen) {
+ if (!g_isNetInitialized) {
+ return ORBIS_NET_ERROR_ENOTINIT;
+ }
+ int result;
+ int err;
+ int positiveErr;
+
+ do {
+ result = sys_getpeername(s, addr, paddrlen);
+
+ if (result >= 0) {
+ return result; // Success
+ }
+
+ err = *Libraries::Kernel::__Error(); // Standard errno
+
+ // Convert to positive error for comparison
+ int positiveErr = (err < 0) ? -err : err;
+
+ if ((positiveErr & 0xfff0000) != 0) {
+ // Unknown/fatal error range
+ *sceNetErrnoLoc() = ORBIS_NET_ERETURN;
+ return -positiveErr;
+ }
+
+ // Retry if interrupted
+ } while (positiveErr == ORBIS_NET_EINTR);
+
+ if (positiveErr == ORBIS_NET_EADDRINUSE) {
+ result = -ORBIS_NET_EBADF;
+ } else if (positiveErr == ORBIS_NET_EALREADY) {
+ result = -ORBIS_NET_EINTR;
+ } else {
+ result = -positiveErr;
+ }
+
+ *sceNetErrnoLoc() = -result;
+
+ return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
}
int PS4_SYSV_ABI sceNetGetRandom() {
@@ -681,13 +844,88 @@ int PS4_SYSV_ABI sceNetGetSockInfo6() {
}
int PS4_SYSV_ABI sceNetGetsockname(OrbisNetId s, OrbisNetSockaddr* addr, u32* paddrlen) {
- LOG_ERROR(Lib_Net, "(STUBBED) called");
- return ORBIS_OK;
+ if (!g_isNetInitialized) {
+ return ORBIS_NET_ERROR_ENOTINIT;
+ }
+ int result;
+ int err;
+ int positiveErr;
+
+ do {
+ result = sys_getsockname(s, addr, paddrlen);
+
+ if (result >= 0) {
+ return result; // Success
+ }
+
+ err = *Libraries::Kernel::__Error(); // Standard errno
+
+ // Convert to positive error for comparison
+ int positiveErr = (err < 0) ? -err : err;
+
+ if ((positiveErr & 0xfff0000) != 0) {
+ // Unknown/fatal error range
+ *sceNetErrnoLoc() = ORBIS_NET_ERETURN;
+ return -positiveErr;
+ }
+
+ // Retry if interrupted
+ } while (positiveErr == ORBIS_NET_EINTR);
+
+ if (positiveErr == ORBIS_NET_EADDRINUSE) {
+ result = -ORBIS_NET_EBADF;
+ } else if (positiveErr == ORBIS_NET_EALREADY) {
+ result = -ORBIS_NET_EINTR;
+ } else {
+ result = -positiveErr;
+ }
+
+ *sceNetErrnoLoc() = -result;
+
+ return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
}
int PS4_SYSV_ABI sceNetGetsockopt(OrbisNetId s, int level, int optname, void* optval, u32* optlen) {
- LOG_ERROR(Lib_Net, "(STUBBED) called");
- return ORBIS_OK;
+ LOG_INFO(Lib_Net, "s={} level={} optname={}", s, level, optname);
+ if (!g_isNetInitialized) {
+ return ORBIS_NET_ERROR_ENOTINIT;
+ }
+ int result;
+ int err;
+ int positiveErr;
+
+ do {
+ result = sys_getsockopt(s, level, optname, optval, optlen);
+
+ if (result >= 0) {
+ return result; // Success
+ }
+
+ err = *Libraries::Kernel::__Error(); // Standard errno
+
+ // Convert to positive error for comparison
+ int positiveErr = (err < 0) ? -err : err;
+
+ if ((positiveErr & 0xfff0000) != 0) {
+ // Unknown/fatal error range
+ *sceNetErrnoLoc() = ORBIS_NET_ERETURN;
+ return -positiveErr;
+ }
+
+ // Retry if interrupted
+ } while (positiveErr == ORBIS_NET_EINTR);
+
+ if (positiveErr == ORBIS_NET_EADDRINUSE) {
+ result = -ORBIS_NET_EBADF;
+ } else if (positiveErr == ORBIS_NET_EALREADY) {
+ result = -ORBIS_NET_EINTR;
+ } else {
+ result = -positiveErr;
+ }
+
+ *sceNetErrnoLoc() = -result;
+
+ return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
}
int PS4_SYSV_ABI sceNetGetStatisticsInfo() {
@@ -781,9 +1019,46 @@ int PS4_SYSV_ABI sceNetIoctl() {
return ORBIS_OK;
}
-int PS4_SYSV_ABI sceNetListen() {
- LOG_ERROR(Lib_Net, "(STUBBED) called");
- return ORBIS_OK;
+int PS4_SYSV_ABI sceNetListen(OrbisNetId s, int backlog) {
+ if (!g_isNetInitialized) {
+ return ORBIS_NET_ERROR_ENOTINIT;
+ }
+ int result;
+ int err;
+ int positiveErr;
+
+ do {
+ result = sys_listen(s, backlog);
+
+ if (result >= 0) {
+ return result; // Success
+ }
+
+ err = *Libraries::Kernel::__Error(); // Standard errno
+
+ // Convert to positive error for comparison
+ int positiveErr = (err < 0) ? -err : err;
+
+ if ((positiveErr & 0xfff0000) != 0) {
+ // Unknown/fatal error range
+ *sceNetErrnoLoc() = ORBIS_NET_ERETURN;
+ return -positiveErr;
+ }
+
+ // Retry if interrupted
+ } while (positiveErr == ORBIS_NET_EINTR);
+
+ if (positiveErr == ORBIS_NET_EADDRINUSE) {
+ result = -ORBIS_NET_EBADF;
+ } else if (positiveErr == ORBIS_NET_EALREADY) {
+ result = -ORBIS_NET_EINTR;
+ } else {
+ result = -positiveErr;
+ }
+
+ *sceNetErrnoLoc() = -result;
+
+ return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
}
int PS4_SYSV_ABI sceNetMemoryAllocate() {
@@ -829,20 +1104,131 @@ int PS4_SYSV_ABI sceNetPppoeStop() {
return ORBIS_OK;
}
-int PS4_SYSV_ABI sceNetRecv() {
- LOG_ERROR(Lib_Net, "(STUBBED) called");
- return ORBIS_OK;
+int PS4_SYSV_ABI sceNetRecv(OrbisNetId s, void* buf, u64 len, int flags) {
+ if (!g_isNetInitialized) {
+ return ORBIS_NET_ERROR_ENOTINIT;
+ }
+ int result;
+ int err;
+ int positiveErr;
+
+ do {
+ result = sys_recvfrom(s, buf, len, flags | 0x40000000, nullptr, 0);
+
+ if (result >= 0) {
+ return result; // Success
+ }
+
+ err = *Libraries::Kernel::__Error(); // Standard errno
+
+ // Convert to positive error for comparison
+ int positiveErr = (err < 0) ? -err : err;
+
+ if ((positiveErr & 0xfff0000) != 0) {
+ // Unknown/fatal error range
+ *sceNetErrnoLoc() = ORBIS_NET_ERETURN;
+ return -positiveErr;
+ }
+
+ // Retry if interrupted
+ } while (positiveErr == ORBIS_NET_EINTR);
+
+ if (positiveErr == ORBIS_NET_EADDRINUSE) {
+ result = -ORBIS_NET_EBADF;
+ } else if (positiveErr == ORBIS_NET_EALREADY) {
+ result = -ORBIS_NET_EINTR;
+ } else {
+ result = -positiveErr;
+ }
+
+ *sceNetErrnoLoc() = -result;
+
+ return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
}
-int PS4_SYSV_ABI sceNetRecvfrom(OrbisNetId s, void* buf, size_t len, int flags,
- OrbisNetSockaddr* addr, u32* paddrlen) {
- LOG_ERROR(Lib_Net, "(STUBBED) called");
- return ORBIS_OK;
+int PS4_SYSV_ABI sceNetRecvfrom(OrbisNetId s, void* buf, u64 len, int flags, OrbisNetSockaddr* addr,
+ u32* paddrlen) {
+ if (!g_isNetInitialized) {
+ return ORBIS_NET_ERROR_ENOTINIT;
+ }
+ int result;
+ int err;
+ int positiveErr;
+
+ do {
+ result = sys_recvfrom(s, buf, len, flags | 0x40000000, addr, paddrlen);
+
+ if (result >= 0) {
+ return result; // Success
+ }
+
+ err = *Libraries::Kernel::__Error(); // Standard errno
+
+ // Convert to positive error for comparison
+ int positiveErr = (err < 0) ? -err : err;
+
+ if ((positiveErr & 0xfff0000) != 0) {
+ // Unknown/fatal error range
+ *sceNetErrnoLoc() = ORBIS_NET_ERETURN;
+ return -positiveErr;
+ }
+
+ // Retry if interrupted
+ } while (positiveErr == ORBIS_NET_EINTR);
+
+ if (positiveErr == ORBIS_NET_EADDRINUSE) {
+ result = -ORBIS_NET_EBADF;
+ } else if (positiveErr == ORBIS_NET_EALREADY) {
+ result = -ORBIS_NET_EINTR;
+ } else {
+ result = -positiveErr;
+ }
+
+ *sceNetErrnoLoc() = -result;
+
+ return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
}
-int PS4_SYSV_ABI sceNetRecvmsg() {
- LOG_ERROR(Lib_Net, "(STUBBED) called");
- return ORBIS_OK;
+int PS4_SYSV_ABI sceNetRecvmsg(OrbisNetId s, OrbisNetMsghdr* msg, int flags) {
+ if (!g_isNetInitialized) {
+ return ORBIS_NET_ERROR_ENOTINIT;
+ }
+ int result;
+ int err;
+ int positiveErr;
+
+ do {
+ result = sys_recvmsg(s, msg, flags | 0x40000000);
+
+ if (result >= 0) {
+ return result; // Success
+ }
+
+ err = *Libraries::Kernel::__Error(); // Standard errno
+
+ // Convert to positive error for comparison
+ int positiveErr = (err < 0) ? -err : err;
+
+ if ((positiveErr & 0xfff0000) != 0) {
+ // Unknown/fatal error range
+ *sceNetErrnoLoc() = ORBIS_NET_ERETURN;
+ return -positiveErr;
+ }
+
+ // Retry if interrupted
+ } while (positiveErr == ORBIS_NET_EINTR);
+
+ if (positiveErr == ORBIS_NET_EADDRINUSE) {
+ result = -ORBIS_NET_EBADF;
+ } else if (positiveErr == ORBIS_NET_EALREADY) {
+ result = -ORBIS_NET_EINTR;
+ } else {
+ result = -positiveErr;
+ }
+
+ *sceNetErrnoLoc() = -result;
+
+ return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
}
int PS4_SYSV_ABI sceNetResolverAbort() {
@@ -915,19 +1301,131 @@ int PS4_SYSV_ABI sceNetResolverStartNtoaMultipleRecordsEx() {
return ORBIS_OK;
}
-int PS4_SYSV_ABI sceNetSend() {
- LOG_ERROR(Lib_Net, "(STUBBED) called");
- return ORBIS_OK;
+int PS4_SYSV_ABI sceNetSend(OrbisNetId s, const void* buf, u64 len, int flags) {
+ if (!g_isNetInitialized) {
+ return ORBIS_NET_ERROR_ENOTINIT;
+ }
+ int result;
+ int err;
+ int positiveErr;
+
+ do {
+ result = sys_sendto(s, buf, len, flags | 0x40020000, nullptr, 0);
+
+ if (result >= 0) {
+ return result; // Success
+ }
+
+ err = *Libraries::Kernel::__Error(); // Standard errno
+
+ // Convert to positive error for comparison
+ int positiveErr = (err < 0) ? -err : err;
+
+ if ((positiveErr & 0xfff0000) != 0) {
+ // Unknown/fatal error range
+ *sceNetErrnoLoc() = ORBIS_NET_ERETURN;
+ return -positiveErr;
+ }
+
+ // Retry if interrupted
+ } while (positiveErr == ORBIS_NET_EINTR);
+
+ if (positiveErr == ORBIS_NET_EADDRINUSE) {
+ result = -ORBIS_NET_EBADF;
+ } else if (positiveErr == ORBIS_NET_EALREADY) {
+ result = -ORBIS_NET_EINTR;
+ } else {
+ result = -positiveErr;
+ }
+
+ *sceNetErrnoLoc() = -result;
+
+ return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
}
-int PS4_SYSV_ABI sceNetSendmsg() {
- LOG_ERROR(Lib_Net, "(STUBBED) called");
- return ORBIS_OK;
+int PS4_SYSV_ABI sceNetSendmsg(OrbisNetId s, const OrbisNetMsghdr* msg, int flags) {
+ if (!g_isNetInitialized) {
+ return ORBIS_NET_ERROR_ENOTINIT;
+ }
+ int result;
+ int err;
+ int positiveErr;
+
+ do {
+ result = sys_sendmsg(s, msg, flags | 0x40020000);
+
+ if (result >= 0) {
+ return result; // Success
+ }
+
+ err = *Libraries::Kernel::__Error(); // Standard errno
+
+ // Convert to positive error for comparison
+ int positiveErr = (err < 0) ? -err : err;
+
+ if ((positiveErr & 0xfff0000) != 0) {
+ // Unknown/fatal error range
+ *sceNetErrnoLoc() = ORBIS_NET_ERETURN;
+ return -positiveErr;
+ }
+
+ // Retry if interrupted
+ } while (positiveErr == ORBIS_NET_EINTR);
+
+ if (positiveErr == ORBIS_NET_EADDRINUSE) {
+ result = -ORBIS_NET_EBADF;
+ } else if (positiveErr == ORBIS_NET_EALREADY) {
+ result = -ORBIS_NET_EINTR;
+ } else {
+ result = -positiveErr;
+ }
+
+ *sceNetErrnoLoc() = -result;
+
+ return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
}
-int PS4_SYSV_ABI sceNetSendto() {
- LOG_ERROR(Lib_Net, "(STUBBED) called");
- return ORBIS_OK;
+int PS4_SYSV_ABI sceNetSendto(OrbisNetId s, const void* buf, u64 len, int flags,
+ const OrbisNetSockaddr* addr, u32 addrlen) {
+ if (!g_isNetInitialized) {
+ return ORBIS_NET_ERROR_ENOTINIT;
+ }
+ int result;
+ int err;
+ int positiveErr;
+
+ do {
+ result = sys_sendto(s, buf, len, flags | 0x40020000, addr, addrlen);
+
+ if (result >= 0) {
+ return result; // Success
+ }
+
+ err = *Libraries::Kernel::__Error(); // Standard errno
+
+ // Convert to positive error for comparison
+ int positiveErr = (err < 0) ? -err : err;
+
+ if ((positiveErr & 0xfff0000) != 0) {
+ // Unknown/fatal error range
+ *sceNetErrnoLoc() = ORBIS_NET_ERETURN;
+ return -positiveErr;
+ }
+
+ // Retry if interrupted
+ } while (positiveErr == ORBIS_NET_EINTR);
+
+ if (positiveErr == ORBIS_NET_EADDRINUSE) {
+ result = -ORBIS_NET_EBADF;
+ } else if (positiveErr == ORBIS_NET_EALREADY) {
+ result = -ORBIS_NET_EINTR;
+ } else {
+ result = -positiveErr;
+ }
+
+ *sceNetErrnoLoc() = -result;
+
+ return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
}
int PS4_SYSV_ABI sceNetSetDns6Info() {
@@ -950,9 +1448,48 @@ int PS4_SYSV_ABI sceNetSetDnsInfoToKernel() {
return ORBIS_OK;
}
-int PS4_SYSV_ABI sceNetSetsockopt() {
- LOG_ERROR(Lib_Net, "(STUBBED) called");
- return ORBIS_OK;
+int PS4_SYSV_ABI sceNetSetsockopt(OrbisNetId s, int level, int optname, const void* optval,
+ u32 optlen) {
+ LOG_INFO(Lib_Net, "s={} level={} optname={} optlen={}", s, level, optname, optlen);
+ if (!g_isNetInitialized) {
+ return ORBIS_NET_ERROR_ENOTINIT;
+ }
+ int result;
+ int err;
+ int positiveErr;
+
+ do {
+ result = sys_setsockopt(s, level, optname, optval, optlen);
+
+ if (result >= 0) {
+ return result; // Success
+ }
+
+ err = *Libraries::Kernel::__Error(); // Standard errno
+
+ // Convert to positive error for comparison
+ int positiveErr = (err < 0) ? -err : err;
+
+ if ((positiveErr & 0xfff0000) != 0) {
+ // Unknown/fatal error range
+ *sceNetErrnoLoc() = ORBIS_NET_ERETURN;
+ return -positiveErr;
+ }
+
+ // Retry if interrupted
+ } while (positiveErr == ORBIS_NET_EINTR);
+
+ if (positiveErr == ORBIS_NET_EADDRINUSE) {
+ result = -ORBIS_NET_EBADF;
+ } else if (positiveErr == ORBIS_NET_EALREADY) {
+ result = -ORBIS_NET_EINTR;
+ } else {
+ result = -positiveErr;
+ }
+
+ *sceNetErrnoLoc() = -result;
+
+ return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
}
int PS4_SYSV_ABI sceNetShowIfconfig() {
@@ -1035,24 +1572,172 @@ int PS4_SYSV_ABI sceNetShowRouteWithMemory() {
return ORBIS_OK;
}
-int PS4_SYSV_ABI sceNetShutdown() {
- LOG_ERROR(Lib_Net, "(STUBBED) called");
- return ORBIS_OK;
+int PS4_SYSV_ABI sceNetShutdown(OrbisNetId s, int how) {
+ if (!g_isNetInitialized) {
+ return ORBIS_NET_ERROR_ENOTINIT;
+ }
+ int result;
+ int err;
+ int positiveErr;
+
+ do {
+ result = sys_shutdown(s, how);
+
+ if (result >= 0) {
+ return result; // Success
+ }
+
+ err = *Libraries::Kernel::__Error(); // Standard errno
+
+ // Convert to positive error for comparison
+ int positiveErr = (err < 0) ? -err : err;
+
+ if ((positiveErr & 0xfff0000) != 0) {
+ // Unknown/fatal error range
+ *sceNetErrnoLoc() = ORBIS_NET_ERETURN;
+ return -positiveErr;
+ }
+
+ // Retry if interrupted
+ } while (positiveErr == ORBIS_NET_EINTR);
+
+ if (positiveErr == ORBIS_NET_EADDRINUSE) {
+ result = -ORBIS_NET_EBADF;
+ } else if (positiveErr == ORBIS_NET_EALREADY) {
+ result = -ORBIS_NET_EINTR;
+ } else {
+ result = -positiveErr;
+ }
+
+ *sceNetErrnoLoc() = -result;
+
+ return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
}
-int PS4_SYSV_ABI sceNetSocket(const char* name, int family, int type, int protocol) {
- LOG_ERROR(Lib_Net, "(STUBBED) called");
- return ORBIS_OK;
+OrbisNetId PS4_SYSV_ABI sceNetSocket(const char* name, int family, int type, int protocol) {
+ if (!g_isNetInitialized) {
+ return ORBIS_NET_ERROR_ENOTINIT;
+ }
+ int result;
+ int err;
+ int positiveErr;
+
+ do {
+ result = sys_socketex(name, family, type, protocol);
+
+ if (result >= 0) {
+ return result; // Success
+ }
+
+ err = *Libraries::Kernel::__Error(); // Standard errno
+
+ // Convert to positive error for comparison
+ int positiveErr = (err < 0) ? -err : err;
+
+ if ((positiveErr & 0xfff0000) != 0) {
+ // Unknown/fatal error range
+ *sceNetErrnoLoc() = ORBIS_NET_ERETURN;
+ return -positiveErr;
+ }
+
+ // Retry if interrupted
+ } while (positiveErr == ORBIS_NET_EINTR);
+
+ if (positiveErr == ORBIS_NET_EADDRINUSE) {
+ result = -ORBIS_NET_EBADF;
+ } else if (positiveErr == ORBIS_NET_EALREADY) {
+ result = -ORBIS_NET_EINTR;
+ } else {
+ result = -positiveErr;
+ }
+
+ *sceNetErrnoLoc() = -result;
+
+ return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
}
-int PS4_SYSV_ABI sceNetSocketAbort() {
- LOG_ERROR(Lib_Net, "(STUBBED) called");
- return ORBIS_OK;
+int PS4_SYSV_ABI sceNetSocketAbort(OrbisNetId s, int flags) {
+ if (!g_isNetInitialized) {
+ return ORBIS_NET_ERROR_ENOTINIT;
+ }
+ int result;
+ int err;
+ int positiveErr;
+
+ do {
+ result = sys_netabort(s, flags);
+
+ if (result >= 0) {
+ return result; // Success
+ }
+
+ err = *Libraries::Kernel::__Error(); // Standard errno
+
+ // Convert to positive error for comparison
+ int positiveErr = (err < 0) ? -err : err;
+
+ if ((positiveErr & 0xfff0000) != 0) {
+ // Unknown/fatal error range
+ *sceNetErrnoLoc() = ORBIS_NET_ERETURN;
+ return -positiveErr;
+ }
+
+ // Retry if interrupted
+ } while (positiveErr == ORBIS_NET_EINTR);
+
+ if (positiveErr == ORBIS_NET_EADDRINUSE) {
+ result = -ORBIS_NET_EBADF;
+ } else if (positiveErr == ORBIS_NET_EALREADY) {
+ result = -ORBIS_NET_EINTR;
+ } else {
+ result = -positiveErr;
+ }
+
+ *sceNetErrnoLoc() = -result;
+
+ return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
}
-int PS4_SYSV_ABI sceNetSocketClose() {
- LOG_ERROR(Lib_Net, "(STUBBED) called");
- return ORBIS_OK;
+int PS4_SYSV_ABI sceNetSocketClose(OrbisNetId s) {
+ if (!g_isNetInitialized) {
+ return ORBIS_NET_ERROR_ENOTINIT;
+ }
+ int result;
+ int err;
+ int positiveErr;
+
+ do {
+ result = sys_socketclose(s);
+
+ if (result >= 0) {
+ return result; // Success
+ }
+
+ err = *Libraries::Kernel::__Error(); // Standard errno
+
+ // Convert to positive error for comparison
+ int positiveErr = (err < 0) ? -err : err;
+
+ if ((positiveErr & 0xfff0000) != 0) {
+ // Unknown/fatal error range
+ *sceNetErrnoLoc() = ORBIS_NET_ERETURN;
+ return -positiveErr;
+ }
+
+ // Retry if interrupted
+ } while (positiveErr == ORBIS_NET_EINTR);
+
+ if (positiveErr == ORBIS_NET_EADDRINUSE) {
+ result = -ORBIS_NET_EBADF;
+ } else if (positiveErr == ORBIS_NET_EALREADY) {
+ result = -ORBIS_NET_EINTR;
+ } else {
+ result = -positiveErr;
+ }
+
+ *sceNetErrnoLoc() = -result;
+
+ return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
}
int PS4_SYSV_ABI sceNetSyncCreate() {
diff --git a/src/core/libraries/network/net.h b/src/core/libraries/network/net.h
index beef38b56..812ee6bd7 100644
--- a/src/core/libraries/network/net.h
+++ b/src/core/libraries/network/net.h
@@ -4,6 +4,7 @@
#pragma once
#include "common/types.h"
+#include "netctl.h"
namespace Core::Loader {
class SymbolsResolver;
@@ -19,6 +20,63 @@ class SymbolsResolver;
namespace Libraries::Net {
+enum OrbisNetSocketType : u32 {
+ ORBIS_NET_SOCK_STREAM = 1,
+ ORBIS_NET_SOCK_DGRAM = 2,
+ ORBIS_NET_SOCK_RAW = 3,
+ ORBIS_NET_SOCK_DGRAM_P2P = 6,
+ ORBIS_NET_SOCK_STREAM_P2P = 10
+};
+
+enum OrbisNetProtocol : u32 {
+ ORBIS_NET_IPPROTO_IP = 0,
+ ORBIS_NET_IPPROTO_ICMP = 1,
+ ORBIS_NET_IPPROTO_IGMP = 2,
+ ORBIS_NET_IPPROTO_TCP = 6,
+ ORBIS_NET_IPPROTO_UDP = 17,
+ ORBIS_NET_SOL_SOCKET = 0xFFFF
+};
+
+enum OrbisNetSocketOption : u32 {
+ /* IP */
+ ORBIS_NET_IP_HDRINCL = 2,
+ ORBIS_NET_IP_TOS = 3,
+ ORBIS_NET_IP_TTL = 4,
+ ORBIS_NET_IP_MULTICAST_IF = 9,
+ ORBIS_NET_IP_MULTICAST_TTL = 10,
+ ORBIS_NET_IP_MULTICAST_LOOP = 11,
+ ORBIS_NET_IP_ADD_MEMBERSHIP = 12,
+ ORBIS_NET_IP_DROP_MEMBERSHIP = 13,
+ ORBIS_NET_IP_TTLCHK = 23,
+ ORBIS_NET_IP_MAXTTL = 24,
+ /* TCP */
+ ORBIS_NET_TCP_NODELAY = 1,
+ ORBIS_NET_TCP_MAXSEG = 2,
+ ORBIS_NET_TCP_MSS_TO_ADVERTISE = 3,
+ /* SOCKET */
+ ORBIS_NET_SO_REUSEADDR = 0x00000004,
+ ORBIS_NET_SO_KEEPALIVE = 0x00000008,
+ ORBIS_NET_SO_BROADCAST = 0x00000020,
+ ORBIS_NET_SO_LINGER = 0x00000080,
+ ORBIS_NET_SO_REUSEPORT = 0x00000200,
+ ORBIS_NET_SO_ONESBCAST = 0x00010000,
+ ORBIS_NET_SO_USECRYPTO = 0x00020000,
+ ORBIS_NET_SO_USESIGNATURE = 0x00040000,
+ ORBIS_NET_SO_SNDBUF = 0x1001,
+ ORBIS_NET_SO_RCVBUF = 0x1002,
+ ORBIS_NET_SO_ERROR = 0x1007,
+ ORBIS_NET_SO_TYPE = 0x1008,
+ ORBIS_NET_SO_SNDTIMEO = 0x1105,
+ ORBIS_NET_SO_RCVTIMEO = 0x1106,
+ ORBIS_NET_SO_ERROR_EX = 0x1107,
+ ORBIS_NET_SO_ACCEPTTIMEO = 0x1108,
+ ORBIS_NET_SO_CONNECTTIMEO = 0x1109,
+ ORBIS_NET_SO_NBIO = 0x1200,
+ ORBIS_NET_SO_POLICY = 0x1201,
+ ORBIS_NET_SO_NAME = 0x1202,
+ ORBIS_NET_SO_PRIORITY = 0x1203
+};
+
using OrbisNetId = s32;
struct OrbisNetSockaddr {
@@ -27,6 +85,30 @@ struct OrbisNetSockaddr {
char sa_data[14];
};
+struct OrbisNetSockaddrIn {
+ u8 sin_len;
+ u8 sin_family;
+ u16 sin_port;
+ u32 sin_addr;
+ u16 sin_vport;
+ char sin_zero[6];
+};
+
+struct OrbisNetIovec {
+ void* iov_base;
+ u64 iov_len;
+};
+
+struct OrbisNetMsghdr {
+ void* msg_name;
+ u32 msg_namelen;
+ OrbisNetIovec* msg_iov;
+ int msg_iovlen;
+ void* msg_control;
+ u32 msg_controllen;
+ int msg_flags;
+};
+
int PS4_SYSV_ABI in6addr_any();
int PS4_SYSV_ABI in6addr_loopback();
int PS4_SYSV_ABI sce_net_dummy();
@@ -116,7 +198,7 @@ int PS4_SYSV_ABI sceNetConfigWlanInfraLeave();
int PS4_SYSV_ABI sceNetConfigWlanInfraScanJoin();
int PS4_SYSV_ABI sceNetConfigWlanScan();
int PS4_SYSV_ABI sceNetConfigWlanSetDeviceConfig();
-int PS4_SYSV_ABI sceNetConnect();
+int PS4_SYSV_ABI sceNetConnect(OrbisNetId s, const OrbisNetSockaddr* addr, u32 addrlen);
int PS4_SYSV_ABI sceNetControl();
int PS4_SYSV_ABI sceNetDhcpdStart();
int PS4_SYSV_ABI sceNetDhcpdStop();
@@ -151,10 +233,10 @@ int PS4_SYSV_ABI sceNetGetIfList();
int PS4_SYSV_ABI sceNetGetIfListOnce();
int PS4_SYSV_ABI sceNetGetIfName();
int PS4_SYSV_ABI sceNetGetIfnameNumList();
-int PS4_SYSV_ABI sceNetGetMacAddress();
+int PS4_SYSV_ABI sceNetGetMacAddress(Libraries::NetCtl::OrbisNetEtherAddr* addr, int flags);
int PS4_SYSV_ABI sceNetGetMemoryPoolStats();
int PS4_SYSV_ABI sceNetGetNameToIndex();
-int PS4_SYSV_ABI sceNetGetpeername();
+int PS4_SYSV_ABI sceNetGetpeername(OrbisNetId s, OrbisNetSockaddr* addr, u32* paddrlen);
int PS4_SYSV_ABI sceNetGetRandom();
int PS4_SYSV_ABI sceNetGetRouteInfo();
int PS4_SYSV_ABI sceNetGetSockInfo();
@@ -177,7 +259,7 @@ int PS4_SYSV_ABI sceNetInfoDumpStop();
int PS4_SYSV_ABI sceNetInit();
int PS4_SYSV_ABI sceNetInitParam();
int PS4_SYSV_ABI sceNetIoctl();
-int PS4_SYSV_ABI sceNetListen();
+int PS4_SYSV_ABI sceNetListen(OrbisNetId s, int backlog);
int PS4_SYSV_ABI sceNetMemoryAllocate();
int PS4_SYSV_ABI sceNetMemoryFree();
u32 PS4_SYSV_ABI sceNetNtohl(u32 net32);
@@ -187,10 +269,10 @@ int PS4_SYSV_ABI sceNetPoolCreate(const char* name, int size, int flags);
int PS4_SYSV_ABI sceNetPoolDestroy();
int PS4_SYSV_ABI sceNetPppoeStart();
int PS4_SYSV_ABI sceNetPppoeStop();
-int PS4_SYSV_ABI sceNetRecv();
-int PS4_SYSV_ABI sceNetRecvfrom(OrbisNetId s, void* buf, size_t len, int flags,
- OrbisNetSockaddr* addr, u32* paddrlen);
-int PS4_SYSV_ABI sceNetRecvmsg();
+int PS4_SYSV_ABI sceNetRecv(OrbisNetId s, void* buf, u64 len, int flags);
+int PS4_SYSV_ABI sceNetRecvfrom(OrbisNetId s, void* buf, u64 len, int flags, OrbisNetSockaddr* addr,
+ u32* paddrlen);
+int PS4_SYSV_ABI sceNetRecvmsg(OrbisNetId s, OrbisNetMsghdr* msg, int flags);
int PS4_SYSV_ABI sceNetResolverAbort();
int PS4_SYSV_ABI sceNetResolverConnect();
int PS4_SYSV_ABI sceNetResolverConnectAbort();
@@ -205,14 +287,16 @@ int PS4_SYSV_ABI sceNetResolverStartNtoa();
int PS4_SYSV_ABI sceNetResolverStartNtoa6();
int PS4_SYSV_ABI sceNetResolverStartNtoaMultipleRecords();
int PS4_SYSV_ABI sceNetResolverStartNtoaMultipleRecordsEx();
-int PS4_SYSV_ABI sceNetSend();
-int PS4_SYSV_ABI sceNetSendmsg();
-int PS4_SYSV_ABI sceNetSendto();
+int PS4_SYSV_ABI sceNetSend(OrbisNetId s, const void* buf, u64 len, int flags);
+int PS4_SYSV_ABI sceNetSendmsg(OrbisNetId s, const OrbisNetMsghdr* msg, int flags);
+int PS4_SYSV_ABI sceNetSendto(OrbisNetId s, const void* buf, u64 len, int flags,
+ const OrbisNetSockaddr* addr, u32 addrlen);
int PS4_SYSV_ABI sceNetSetDns6Info();
int PS4_SYSV_ABI sceNetSetDns6InfoToKernel();
int PS4_SYSV_ABI sceNetSetDnsInfo();
int PS4_SYSV_ABI sceNetSetDnsInfoToKernel();
-int PS4_SYSV_ABI sceNetSetsockopt();
+int PS4_SYSV_ABI sceNetSetsockopt(OrbisNetId s, int level, int optname, const void* optval,
+ u32 optlen);
int PS4_SYSV_ABI sceNetShowIfconfig();
int PS4_SYSV_ABI sceNetShowIfconfigForBuffer();
int PS4_SYSV_ABI sceNetShowIfconfigWithMemory();
@@ -229,10 +313,10 @@ int PS4_SYSV_ABI sceNetShowRoute6ForBuffer();
int PS4_SYSV_ABI sceNetShowRoute6WithMemory();
int PS4_SYSV_ABI sceNetShowRouteForBuffer();
int PS4_SYSV_ABI sceNetShowRouteWithMemory();
-int PS4_SYSV_ABI sceNetShutdown();
-int PS4_SYSV_ABI sceNetSocket(const char* name, int family, int type, int protocol);
-int PS4_SYSV_ABI sceNetSocketAbort();
-int PS4_SYSV_ABI sceNetSocketClose();
+int PS4_SYSV_ABI sceNetShutdown(OrbisNetId s, int how);
+OrbisNetId PS4_SYSV_ABI sceNetSocket(const char* name, int family, int type, int protocol);
+int PS4_SYSV_ABI sceNetSocketAbort(OrbisNetId s, int flags);
+int PS4_SYSV_ABI sceNetSocketClose(OrbisNetId s);
int PS4_SYSV_ABI sceNetSyncCreate();
int PS4_SYSV_ABI sceNetSyncDestroy();
int PS4_SYSV_ABI sceNetSyncGet();
diff --git a/src/core/libraries/network/net_error.h b/src/core/libraries/network/net_error.h
new file mode 100644
index 000000000..ab65300c0
--- /dev/null
+++ b/src/core/libraries/network/net_error.h
@@ -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;
diff --git a/src/core/libraries/network/net_util.cpp b/src/core/libraries/network/net_util.cpp
new file mode 100644
index 000000000..d0f0a81da
--- /dev/null
+++ b/src/core/libraries/network/net_util.cpp
@@ -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
+#include
+#include
+typedef SOCKET net_socket;
+typedef int socklen_t;
+#else
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+typedef int net_socket;
+#endif
+#if defined(__APPLE__)
+#include
+#include
+#endif
+
+#include