Merge branch 'shadps4-emu:main' into hybrid

This commit is contained in:
Lander Gallastegi 2025-05-16 17:54:49 +02:00 committed by GitHub
commit 4d6503a396
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 672 additions and 289 deletions

4
.gitmodules vendored
View File

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

View File

@ -54,9 +54,9 @@ else()
endif() endif()
if (ARCHITECTURE STREQUAL "x86_64") if (ARCHITECTURE STREQUAL "x86_64")
# Target the same CPU architecture as the PS4, to maintain the same level of compatibility. # Target x86-64-v3 CPU architecture as this is a good balance between supporting performance critical
# Exclude SSE4a as it is only available on AMD CPUs. # instructions like AVX2 and maintaining support for older CPUs.
add_compile_options(-march=btver2 -mtune=generic -mno-sse4a) add_compile_options(-march=x86-64-v3)
endif() endif()
if (APPLE AND ARCHITECTURE STREQUAL "x86_64" AND CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "arm64") if (APPLE AND ARCHITECTURE STREQUAL "x86_64" AND CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "arm64")
@ -239,13 +239,6 @@ if (APPLE)
endif() endif()
list(POP_BACK CMAKE_MODULE_PATH) list(POP_BACK CMAKE_MODULE_PATH)
# Note: Windows always has these functions through winpthreads
include(CheckSymbolExists)
check_symbol_exists(pthread_mutex_timedlock "pthread.h" HAVE_PTHREAD_MUTEX_TIMEDLOCK)
if(HAVE_PTHREAD_MUTEX_TIMEDLOCK OR WIN32)
add_compile_options(-DHAVE_PTHREAD_MUTEX_TIMEDLOCK)
endif()
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
# libc++ requires -fexperimental-library to enable std::jthread and std::stop_token support. # libc++ requires -fexperimental-library to enable std::jthread and std::stop_token support.
include(CheckCXXSymbolExists) include(CheckCXXSymbolExists)
@ -606,6 +599,10 @@ set(CAMERA_LIBS src/core/libraries/camera/camera.cpp
src/core/libraries/camera/camera_error.h src/core/libraries/camera/camera_error.h
) )
set(COMPANION_LIBS src/core/libraries/companion/companion_httpd.cpp
src/core/libraries/companion/companion_httpd.h
src/core/libraries/companion/companion_error.h
)
set(DEV_TOOLS src/core/devtools/layer.cpp set(DEV_TOOLS src/core/devtools/layer.cpp
src/core/devtools/layer.h src/core/devtools/layer.h
src/core/devtools/options.cpp src/core/devtools/options.cpp
@ -772,6 +769,7 @@ set(CORE src/core/aerolib/stubs.cpp
${VDEC_LIB} ${VDEC_LIB}
${VR_LIBS} ${VR_LIBS}
${CAMERA_LIBS} ${CAMERA_LIBS}
${COMPANION_LIBS}
${DEV_TOOLS} ${DEV_TOOLS}
src/core/debug_state.cpp src/core/debug_state.cpp
src/core/debug_state.h src/core/debug_state.h
@ -1159,7 +1157,7 @@ if (ENABLE_QT_GUI)
endif() endif()
if (WIN32) if (WIN32)
target_link_libraries(shadps4 PRIVATE mincore winpthreads) target_link_libraries(shadps4 PRIVATE mincore)
if (MSVC) if (MSVC)
# MSVC likes putting opinions on what people can use, disable: # MSVC likes putting opinions on what people can use, disable:

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -68,7 +68,7 @@ bool EqueueInternal::ScheduleEvent(u64 id, s16 filter,
it->timer->async_wait( it->timer->async_wait(
[this, event_data = event.event, callback](const boost::system::error_code& ec) { [this, event_data = event.event, callback](const boost::system::error_code& ec) {
if (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()); LOG_ERROR(Kernel_Event, "Timer callback error: {}", ec.message());
} else { } else {
// Timer was cancelled (removed) before it triggered // Timer was cancelled (removed) before it triggered

View File

@ -108,6 +108,9 @@ void SetPosixErrno(int e) {
case EACCES: case EACCES:
g_posix_errno = POSIX_EACCES; g_posix_errno = POSIX_EACCES;
break; break;
case EFAULT:
g_posix_errno = POSIX_EFAULT;
break;
case EINVAL: case EINVAL:
g_posix_errno = POSIX_EINVAL; g_posix_errno = POSIX_EINVAL;
break; break;

View File

@ -209,6 +209,19 @@ int PS4_SYSV_ABI sceKernelMapDirectMemory(void** addr, u64 len, int prot, int fl
"anon"); "anon");
} }
s32 PS4_SYSV_ABI sceKernelMapDirectMemory2(void** addr, u64 len, s32 type, s32 prot, s32 flags,
s64 phys_addr, u64 alignment) {
LOG_INFO(Kernel_Vmm, "called, redirected to sceKernelMapNamedDirectMemory");
const s32 ret =
sceKernelMapNamedDirectMemory(addr, len, prot, flags, phys_addr, alignment, "anon");
if (ret == 0) {
auto* memory = Core::Memory::Instance();
memory->SetDirectMemoryType(phys_addr, type);
}
return ret;
}
s32 PS4_SYSV_ABI sceKernelMapNamedFlexibleMemory(void** addr_in_out, std::size_t len, int prot, s32 PS4_SYSV_ABI sceKernelMapNamedFlexibleMemory(void** addr_in_out, std::size_t len, int prot,
int flags, const char* name) { int flags, const char* name) {
@ -291,8 +304,7 @@ int PS4_SYSV_ABI sceKernelGetDirectMemoryType(u64 addr, int* directMemoryTypeOut
} }
int PS4_SYSV_ABI sceKernelIsStack(void* addr, void** start, void** end) { 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), LOG_DEBUG(Kernel_Vmm, "called, addr = {}", fmt::ptr(addr));
fmt::ptr(start), fmt::ptr(end));
auto* memory = Core::Memory::Instance(); auto* memory = Core::Memory::Instance();
return memory->IsStack(std::bit_cast<VAddr>(addr), start, end); return memory->IsStack(std::bit_cast<VAddr>(addr), start, end);
} }
@ -646,6 +658,7 @@ void RegisterMemory(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("yDBwVAolDgg", "libkernel", 1, "libkernel", 1, 1, sceKernelIsStack); LIB_FUNCTION("yDBwVAolDgg", "libkernel", 1, "libkernel", 1, 1, sceKernelIsStack);
LIB_FUNCTION("NcaWUxfMNIQ", "libkernel", 1, "libkernel", 1, 1, sceKernelMapNamedDirectMemory); LIB_FUNCTION("NcaWUxfMNIQ", "libkernel", 1, "libkernel", 1, 1, sceKernelMapNamedDirectMemory);
LIB_FUNCTION("L-Q3LEjIbgA", "libkernel", 1, "libkernel", 1, 1, sceKernelMapDirectMemory); LIB_FUNCTION("L-Q3LEjIbgA", "libkernel", 1, "libkernel", 1, 1, sceKernelMapDirectMemory);
LIB_FUNCTION("BQQniolj9tQ", "libkernel", 1, "libkernel", 1, 1, sceKernelMapDirectMemory2);
LIB_FUNCTION("WFcfL2lzido", "libkernel", 1, "libkernel", 1, 1, sceKernelQueryMemoryProtection); LIB_FUNCTION("WFcfL2lzido", "libkernel", 1, "libkernel", 1, 1, sceKernelQueryMemoryProtection);
LIB_FUNCTION("BHouLQzh0X0", "libkernel", 1, "libkernel", 1, 1, sceKernelDirectMemoryQuery); LIB_FUNCTION("BHouLQzh0X0", "libkernel", 1, "libkernel", 1, 1, sceKernelDirectMemoryQuery);
LIB_FUNCTION("MBuItvba6z8", "libkernel", 1, "libkernel", 1, 1, sceKernelReleaseDirectMemory); LIB_FUNCTION("MBuItvba6z8", "libkernel", 1, "libkernel", 1, 1, sceKernelReleaseDirectMemory);

View File

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

View File

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

View File

@ -9,6 +9,7 @@
#include "core/libraries/audio3d/audio3d.h" #include "core/libraries/audio3d/audio3d.h"
#include "core/libraries/avplayer/avplayer.h" #include "core/libraries/avplayer/avplayer.h"
#include "core/libraries/camera/camera.h" #include "core/libraries/camera/camera.h"
#include "core/libraries/companion/companion_httpd.h"
#include "core/libraries/disc_map/disc_map.h" #include "core/libraries/disc_map/disc_map.h"
#include "core/libraries/game_live_streaming/gamelivestreaming.h" #include "core/libraries/game_live_streaming/gamelivestreaming.h"
#include "core/libraries/gnmdriver/gnmdriver.h" #include "core/libraries/gnmdriver/gnmdriver.h"
@ -124,6 +125,7 @@ void InitHLELibs(Core::Loader::SymbolsResolver* sym) {
Libraries::Ulobjmgr::RegisterlibSceUlobjmgr(sym); Libraries::Ulobjmgr::RegisterlibSceUlobjmgr(sym);
Libraries::SigninDialog::RegisterlibSceSigninDialog(sym); Libraries::SigninDialog::RegisterlibSceSigninDialog(sym);
Libraries::Camera::RegisterlibSceCamera(sym); Libraries::Camera::RegisterlibSceCamera(sym);
Libraries::CompanionHttpd::RegisterlibSceCompanionHttpd(sym);
} }
} // namespace Libraries } // namespace Libraries

View File

@ -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. // To account for this, unmap any reserved areas within this mapping range first.
auto unmap_addr = mapped_addr; auto unmap_addr = mapped_addr;
auto unmap_size = size; 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); auto unmapped = UnmapBytesFromEntry(unmap_addr, vma, unmap_size);
unmap_addr += unmapped; unmap_addr += unmapped;
unmap_size -= unmapped; unmap_size -= unmapped;
vma = FindVMA(unmap_addr)->second; vma = FindVMA(unmap_addr)->second;
} }
// This should return SCE_KERNEL_ERROR_ENOMEM but rarely happens.
vma = FindVMA(mapped_addr)->second; vma = FindVMA(mapped_addr)->second;
remaining_size = vma.base + vma.size - mapped_addr; remaining_size = vma.base + vma.size - mapped_addr;
ASSERT_MSG(!vma.IsMapped() && remaining_size >= size, if (vma.IsMapped() || remaining_size < size) {
"Memory region {:#x} to {:#x} isn't free enough to map region {:#x} to {:#x}", LOG_ERROR(Kernel_Vmm, "Unable to map {:#x} bytes at address {:#x}", size, mapped_addr);
vma.base, vma.base + vma.size, virtual_addr, virtual_addr + size); return ORBIS_KERNEL_ERROR_ENOMEM;
}
} }
// Find the first free area starting with provided virtual address. // Find the first free area starting with provided virtual address.
@ -783,6 +786,19 @@ int MemoryManager::DirectQueryAvailable(PAddr search_start, PAddr search_end, si
return ORBIS_OK; return ORBIS_OK;
} }
s32 MemoryManager::SetDirectMemoryType(s64 phys_addr, s32 memory_type) {
std::scoped_lock lk{mutex};
auto& dmem_area = FindDmemArea(phys_addr)->second;
ASSERT_MSG(phys_addr <= dmem_area.GetEnd() && !dmem_area.is_free,
"Direct memory area is not mapped");
dmem_area.memory_type = memory_type;
return ORBIS_OK;
}
void MemoryManager::NameVirtualRange(VAddr virtual_addr, size_t size, std::string_view name) { void MemoryManager::NameVirtualRange(VAddr virtual_addr, size_t size, std::string_view name) {
auto it = FindVMA(virtual_addr); auto it = FindVMA(virtual_addr);

View File

@ -219,6 +219,8 @@ public:
int GetDirectMemoryType(PAddr addr, int* directMemoryTypeOut, void** directMemoryStartOut, int GetDirectMemoryType(PAddr addr, int* directMemoryTypeOut, void** directMemoryStartOut,
void** directMemoryEndOut); void** directMemoryEndOut);
s32 SetDirectMemoryType(s64 phys_addr, s32 memory_type);
void NameVirtualRange(VAddr virtual_addr, size_t size, std::string_view name); void NameVirtualRange(VAddr virtual_addr, size_t size, std::string_view name);
void InvalidateMemory(VAddr addr, u64 size) const; void InvalidateMemory(VAddr addr, u64 size) const;

View File

@ -886,8 +886,9 @@ Liverpool::Task Liverpool::ProcessCompute(const u32* acb, u32 acb_dwords, u32 vq
} }
case PM4ItOpcode::SetQueueReg: { case PM4ItOpcode::SetQueueReg: {
const auto* set_data = reinterpret_cast<const PM4CmdSetQueueReg*>(header); const auto* set_data = reinterpret_cast<const PM4CmdSetQueueReg*>(header);
UNREACHABLE_MSG("Encountered compute SetQueueReg: vqid = {}, reg_offset = {:#x}", LOG_WARNING(Render, "Encountered compute SetQueueReg: vqid = {}, reg_offset = {:#x}",
set_data->vqid.Value(), set_data->reg_offset.Value()); set_data->vqid.Value(), set_data->reg_offset.Value());
break;
} }
case PM4ItOpcode::DispatchDirect: { case PM4ItOpcode::DispatchDirect: {
const auto* dispatch_direct = reinterpret_cast<const PM4CmdDispatchDirect*>(header); const auto* dispatch_direct = reinterpret_cast<const PM4CmdDispatchDirect*>(header);