From 99eaba7c963797b4282af4a4b78ec8d8ea358d80 Mon Sep 17 00:00:00 2001 From: squidbus <175574877+squidbus@users.noreply.github.com> Date: Tue, 13 May 2025 16:08:25 -0700 Subject: [PATCH 1/8] liverpool: Lower SetQueueReg to warning log. (#2930) --- src/video_core/amdgpu/liverpool.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/video_core/amdgpu/liverpool.cpp b/src/video_core/amdgpu/liverpool.cpp index 686e8e84f..d1cd98634 100644 --- a/src/video_core/amdgpu/liverpool.cpp +++ b/src/video_core/amdgpu/liverpool.cpp @@ -885,8 +885,9 @@ Liverpool::Task Liverpool::ProcessCompute(const u32* acb, u32 acb_dwords, u32 vq } case PM4ItOpcode::SetQueueReg: { const auto* set_data = reinterpret_cast(header); - UNREACHABLE_MSG("Encountered compute SetQueueReg: vqid = {}, reg_offset = {:#x}", - set_data->vqid.Value(), set_data->reg_offset.Value()); + LOG_WARNING(Render, "Encountered compute SetQueueReg: vqid = {}, reg_offset = {:#x}", + set_data->vqid.Value(), set_data->reg_offset.Value()); + break; } case PM4ItOpcode::DispatchDirect: { const auto* dispatch_direct = reinterpret_cast(header); From 26c965cf4aee39903067015c2759f38f7f4444b0 Mon Sep 17 00:00:00 2001 From: squidbus <175574877+squidbus@users.noreply.github.com> Date: Tue, 13 May 2025 17:31:23 -0700 Subject: [PATCH 2/8] equeue: Fix timer cancel error code check. --- src/core/libraries/kernel/equeue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/libraries/kernel/equeue.cpp b/src/core/libraries/kernel/equeue.cpp index ec3b50cd5..958019cd3 100644 --- a/src/core/libraries/kernel/equeue.cpp +++ b/src/core/libraries/kernel/equeue.cpp @@ -68,7 +68,7 @@ bool EqueueInternal::ScheduleEvent(u64 id, s16 filter, it->timer->async_wait( [this, event_data = event.event, callback](const boost::system::error_code& ec) { if (ec) { - if (ec.value() != boost::system::errc::operation_canceled) { + if (ec != boost::system::errc::operation_canceled) { LOG_ERROR(Kernel_Event, "Timer callback error: {}", ec.message()); } else { // Timer was cancelled (removed) before it triggered From 6d38100a4118f161fdbf50cc0a1012d863d475d0 Mon Sep 17 00:00:00 2001 From: Stephen Miller <56742918+StevenMiller123@users.noreply.github.com> Date: Wed, 14 May 2025 09:09:23 -0500 Subject: [PATCH 3/8] Avoid logging nulls in sceKernelIsStack (#2933) Games would crash if providing nullptr to start or end. Also don't need the :# part when logging pointers, as they're automatically formatted. --- src/core/libraries/kernel/memory.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/core/libraries/kernel/memory.cpp b/src/core/libraries/kernel/memory.cpp index 7af67d6d3..bddfcfc84 100644 --- a/src/core/libraries/kernel/memory.cpp +++ b/src/core/libraries/kernel/memory.cpp @@ -291,8 +291,7 @@ int PS4_SYSV_ABI sceKernelGetDirectMemoryType(u64 addr, int* directMemoryTypeOut } int PS4_SYSV_ABI sceKernelIsStack(void* addr, void** start, void** end) { - LOG_DEBUG(Kernel_Vmm, "called, addr = {:#x}, start = {:#x}, end = {:#x}", fmt::ptr(addr), - fmt::ptr(start), fmt::ptr(end)); + LOG_DEBUG(Kernel_Vmm, "called, addr = {}", fmt::ptr(addr)); auto* memory = Core::Memory::Instance(); return memory->IsStack(std::bit_cast(addr), start, end); } From 98faff425ea325c693ce6e6d00f65d32e15d6665 Mon Sep 17 00:00:00 2001 From: MajorP93 Date: Wed, 14 May 2025 19:37:16 +0200 Subject: [PATCH 4/8] build: Target x86-64-v3 CPU architecture (#2934) --- CMakeLists.txt | 6 +++--- documents/Quickstart/Quickstart.md | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6780db417..8daa98dea 100644 --- 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") 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). From aeb453698821f5d346de9602d9d7e8114f94a89a Mon Sep 17 00:00:00 2001 From: squidbus <175574877+squidbus@users.noreply.github.com> Date: Thu, 15 May 2025 13:59:34 -0700 Subject: [PATCH 5/8] externals: Remove winpthreads. (#2932) --- .gitmodules | 4 - CMakeLists.txt | 9 +- externals/CMakeLists.txt | 6 - externals/winpthreads | 1 - src/common/thread.cpp | 39 +- src/common/thread.h | 3 + src/core/libraries/kernel/kernel.cpp | 3 + src/core/libraries/kernel/time.cpp | 560 +++++++++++++++------------ src/core/libraries/kernel/time.h | 10 +- 9 files changed, 362 insertions(+), 273 deletions(-) delete mode 160000 externals/winpthreads 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 index 8daa98dea..6c5dde7bf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -239,13 +239,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) @@ -1156,7 +1149,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/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/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/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/core/libraries/kernel/kernel.cpp b/src/core/libraries/kernel/kernel.cpp index c7eafe799..180850217 100644 --- a/src/core/libraries/kernel/kernel.cpp +++ b/src/core/libraries/kernel/kernel.cpp @@ -108,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; 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); From 18ff65efc81bce0c2bb731418aac157a67f347fb Mon Sep 17 00:00:00 2001 From: Stephen Miller <56742918+StevenMiller123@users.noreply.github.com> Date: Fri, 16 May 2025 07:38:40 -0500 Subject: [PATCH 6/8] Implement sceKernelMapDirectMemory2 (#2940) * Implement sceKernelMapDirectMemory2 Behaves similarly to sceKernelMapDirectMemory, but has a type parameter. * Simplify No need to copy all the MapDirectMemory code over, can just call the function, then do the SetDirectMemoryType call * Clang --- src/core/libraries/kernel/memory.cpp | 14 ++++++++++++++ src/core/memory.cpp | 13 +++++++++++++ src/core/memory.h | 2 ++ 3 files changed, 29 insertions(+) diff --git a/src/core/libraries/kernel/memory.cpp b/src/core/libraries/kernel/memory.cpp index bddfcfc84..cb41a664a 100644 --- a/src/core/libraries/kernel/memory.cpp +++ b/src/core/libraries/kernel/memory.cpp @@ -209,6 +209,19 @@ int PS4_SYSV_ABI sceKernelMapDirectMemory(void** addr, u64 len, int prot, int fl "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, int flags, const char* name) { @@ -645,6 +658,7 @@ void RegisterMemory(Core::Loader::SymbolsResolver* sym) { 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); diff --git a/src/core/memory.cpp b/src/core/memory.cpp index ec03d6c5e..13290336c 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -783,6 +783,19 @@ int MemoryManager::DirectQueryAvailable(PAddr search_start, PAddr search_end, si return ORBIS_OK; } +s32 MemoryManager::SetDirectMemoryType(s64 phys_addr, s32 memory_type) { + std::scoped_lock lk{mutex}; + + auto& dmem_area = FindDmemArea(phys_addr)->second; + + ASSERT_MSG(phys_addr <= dmem_area.GetEnd() && !dmem_area.is_free, + "Direct memory area is not mapped"); + + dmem_area.memory_type = memory_type; + + return ORBIS_OK; +} + void MemoryManager::NameVirtualRange(VAddr virtual_addr, size_t size, std::string_view name) { auto it = FindVMA(virtual_addr); diff --git a/src/core/memory.h b/src/core/memory.h index 4c143ff6f..883b48854 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -219,6 +219,8 @@ public: int GetDirectMemoryType(PAddr addr, int* directMemoryTypeOut, void** directMemoryStartOut, void** directMemoryEndOut); + s32 SetDirectMemoryType(s64 phys_addr, s32 memory_type); + void NameVirtualRange(VAddr virtual_addr, size_t size, std::string_view name); void InvalidateMemory(VAddr addr, u64 size) const; From 7de6aec337b68d01c88fa2696e4f3cd7e27ed7a6 Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Fri, 16 May 2025 16:17:37 +0300 Subject: [PATCH 7/8] [Libs] Companion httpd (#2942) * stubbed companion httpd * sceCompanionHttpdGetEvent returns disconnected device * more function definations * added error codes file --- CMakeLists.txt | 5 + src/common/logging/filter.cpp | 1 + src/common/logging/types.h | 1 + .../libraries/companion/companion_error.h | 20 +++ .../libraries/companion/companion_httpd.cpp | 142 ++++++++++++++++++ .../libraries/companion/companion_httpd.h | 91 +++++++++++ src/core/libraries/libs.cpp | 2 + 7 files changed, 262 insertions(+) create mode 100644 src/core/libraries/companion/companion_error.h create mode 100644 src/core/libraries/companion/companion_httpd.cpp create mode 100644 src/core/libraries/companion/companion_httpd.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 6c5dde7bf..0e14b8467 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -599,6 +599,10 @@ set(CAMERA_LIBS src/core/libraries/camera/camera.cpp 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 @@ -763,6 +767,7 @@ set(CORE src/core/aerolib/stubs.cpp ${VDEC_LIB} ${VR_LIBS} ${CAMERA_LIBS} + ${COMPANION_LIBS} ${DEV_TOOLS} src/core/debug_state.cpp src/core/debug_state.h diff --git a/src/common/logging/filter.cpp b/src/common/logging/filter.cpp index 1b605e9ed..231cbf849 100644 --- a/src/common/logging/filter.cpp +++ b/src/common/logging/filter.cpp @@ -139,6 +139,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) { 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 5746b648e..e4eae59af 100644 --- a/src/common/logging/types.h +++ b/src/common/logging/types.h @@ -106,6 +106,7 @@ enum class Class : u8 { 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/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/libs.cpp b/src/core/libraries/libs.cpp index 5ef4b259d..2ab46d3a0 100644 --- a/src/core/libraries/libs.cpp +++ b/src/core/libraries/libs.cpp @@ -9,6 +9,7 @@ #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" @@ -124,6 +125,7 @@ void InitHLELibs(Core::Loader::SymbolsResolver* sym) { Libraries::Ulobjmgr::RegisterlibSceUlobjmgr(sym); Libraries::SigninDialog::RegisterlibSceSigninDialog(sym); Libraries::Camera::RegisterlibSceCamera(sym); + Libraries::CompanionHttpd::RegisterlibSceCompanionHttpd(sym); } } // namespace Libraries From 4d769d9c7ebf14d8e993cb72c565f1d8209c92c0 Mon Sep 17 00:00:00 2001 From: Stephen Miller <56742918+StevenMiller123@users.noreply.github.com> Date: Fri, 16 May 2025 09:41:22 -0500 Subject: [PATCH 8/8] Proper error handling for MapMemory errors (#2938) * Properly handle ENOMEM error return in MapMemory Needed for Assassin's Creed Unity to behave properly. * Change error message If I left the message as-is, we'd probably see inexperienced people claiming the assert means your device needs more memory, which is completely false. * Clang You know you're doing something right when Clang complains. * Attempt to handle MemoryMapFlags::NoOverwrite Based on my interpretation of red_prig's descriptions. These changes are untested, as I'm not able to test right now. * Fix flag description * Move overwrite check to while condition --- src/core/memory.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 13290336c..a08f8b0e9 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -376,19 +376,22 @@ int MemoryManager::MapMemory(void** out_addr, VAddr virtual_addr, size_t size, M // To account for this, unmap any reserved areas within this mapping range first. auto unmap_addr = mapped_addr; auto unmap_size = size; - while (!vma.IsMapped() && unmap_addr < mapped_addr + size && remaining_size < size) { + // If flag NoOverwrite is provided, don't overwrite mapped VMAs. + // When it isn't provided, VMAs can be overwritten regardless of if they're mapped. + while ((False(flags & MemoryMapFlags::NoOverwrite) || !vma.IsMapped()) && + unmap_addr < mapped_addr + size && remaining_size < size) { auto unmapped = UnmapBytesFromEntry(unmap_addr, vma, unmap_size); unmap_addr += unmapped; unmap_size -= unmapped; vma = FindVMA(unmap_addr)->second; } - // This should return SCE_KERNEL_ERROR_ENOMEM but rarely happens. vma = FindVMA(mapped_addr)->second; remaining_size = vma.base + vma.size - mapped_addr; - ASSERT_MSG(!vma.IsMapped() && remaining_size >= size, - "Memory region {:#x} to {:#x} isn't free enough to map region {:#x} to {:#x}", - vma.base, vma.base + vma.size, virtual_addr, virtual_addr + size); + if (vma.IsMapped() || remaining_size < size) { + LOG_ERROR(Kernel_Vmm, "Unable to map {:#x} bytes at address {:#x}", size, mapped_addr); + return ORBIS_KERNEL_ERROR_ENOMEM; + } } // Find the first free area starting with provided virtual address.