diff --git a/CMakeLists.txt b/CMakeLists.txt index 9898e406..70f4ba92 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -270,6 +270,8 @@ set(NP_LIBS src/core/libraries/np_manager/np_manager.cpp ) set(MISC_LIBS src/core/libraries/screenshot/screenshot.cpp src/core/libraries/screenshot/screenshot.h + src/core/libraries/ult/ult.cpp + src/core/libraries/ult/ult.h ) set(COMMON src/common/logging/backend.cpp diff --git a/src/common/logging/filter.cpp b/src/common/logging/filter.cpp index 2c4a20de..413d51c6 100644 --- a/src/common/logging/filter.cpp +++ b/src/common/logging/filter.cpp @@ -100,6 +100,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) { SUB(Lib, NpScore) \ SUB(Lib, NpTrophy) \ SUB(Lib, Screenshot) \ + SUB(Lib, Ult) \ SUB(Lib, LibCInternal) \ SUB(Lib, AppContent) \ SUB(Lib, Rtc) \ diff --git a/src/common/logging/types.h b/src/common/logging/types.h index dccb838a..76ade84d 100644 --- a/src/common/logging/types.h +++ b/src/common/logging/types.h @@ -67,6 +67,7 @@ enum class Class : u8 { Lib_NpScore, ///< The LibSceNpScore implementation Lib_NpTrophy, ///< The LibSceNpTrophy implementation Lib_Screenshot, ///< The LibSceScreenshot implementation + Lib_Ult, ///< The LibSceUlt implementation Lib_LibCInternal, ///< The LibCInternal implementation. Lib_AppContent, ///< The LibSceAppContent implementation. Lib_Rtc, ///< The LibSceRtc implementation. diff --git a/src/core/libraries/error_codes.h b/src/core/libraries/error_codes.h index 74aeef67..3e0ed8a8 100644 --- a/src/core/libraries/error_codes.h +++ b/src/core/libraries/error_codes.h @@ -472,3 +472,11 @@ constexpr int ORBIS_AVPLAYER_ERROR_INFO_OTHER_ENCRY = 0x806A00BF; // AppContent library constexpr int ORBIS_APP_CONTENT_ERROR_PARAMETER = 0x80D90002; + +// Ult Library +constexpr int ORBIS_ULT_ERROR_STATE = 0x80810006; +constexpr int ORBIS_ULT_ERROR_NULL = 0x80810001; +constexpr int ORBIS_ULT_ERROR_ALIGNMENT = 0x80810002; +constexpr int ORBIS_ULT_ERROR_INVALID = 0x80810004; +constexpr int ORBIS_ULT_ERROR_NOT_INITIALIZE = 0x8081000A; +constexpr int ORBIS_ULT_ERROR_PERMISSION = 0x80810005; \ No newline at end of file diff --git a/src/core/libraries/libs.cpp b/src/core/libraries/libs.cpp index 20efd3c0..428127d5 100644 --- a/src/core/libraries/libs.cpp +++ b/src/core/libraries/libs.cpp @@ -24,6 +24,7 @@ #include "core/libraries/rtc/rtc.h" #include "core/libraries/save_data/savedata.h" #include "core/libraries/screenshot/screenshot.h" +#include "core/libraries/ult/ult.h" #include "core/libraries/system/commondialog.h" #include "core/libraries/system/msgdialog.h" #include "core/libraries/system/posix.h" @@ -69,6 +70,7 @@ void InitHLELibs(Core::Loader::SymbolsResolver* sym) { Libraries::NpScore::RegisterlibSceNpScore(sym); Libraries::NpTrophy::RegisterlibSceNpTrophy(sym); Libraries::ScreenShot::RegisterlibSceScreenShot(sym); + Libraries::Ult::RegisterlibSceUlt(sym); Libraries::AppContent::RegisterlibSceAppContent(sym); Libraries::PngDec::RegisterlibScePngDec(sym); Libraries::PlayGo::RegisterlibScePlayGo(sym); diff --git a/src/core/libraries/ult/ult.cpp b/src/core/libraries/ult/ult.cpp new file mode 100644 index 00000000..0219b7c0 --- /dev/null +++ b/src/core/libraries/ult/ult.cpp @@ -0,0 +1,222 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/logging/log.h" +#include "core/libraries/error_codes.h" +#include "core/libraries/libs.h" +#include "ult.h" + +namespace Libraries::Ult { + +bool isUltInitialized = false; +int PS4_SYSV_ABI sceUltInitialize() { + LOG_INFO(Lib_Ult, "called"); + if (isUltInitialized) { + return ORBIS_ULT_ERROR_STATE; + } + + isUltInitialized = true; + return ORBIS_OK; +} +int PS4_SYSV_ABI _sceUltUlthreadRuntimeCreate(OrbisUltUlthreadRuntime* runtime, const char* name, + uint32_t maxNumUlthread, uint32_t numWorkerThread, + void* workArea, + OrbisUltUlthreadRuntimeOptParam* optParam) { + LOG_ERROR(Lib_Ult, "(STUBBED) called"); + return ORBIS_OK; +} + +int PS4_SYSV_ABI _sceUltUlthreadCreate(OrbisUltUlthread* ulthread, const char* name, + OrbisUltUlthreadEntry entry, uint64_t arg, void* context, + uint64_t sizeContext, OrbisUltUlthreadRuntime* runtime, + OrbisUltUlthreadOptParam* optParam) { + LOG_ERROR(Lib_Ult, "(STUBBED) called"); + return ORBIS_OK; +} + +int PS4_SYSV_ABI _sceUltWaitingQueueResourcePoolCreate( + OrbisUltWaitingQueueResourcePool* pool, const char* name, uint32_t numThreads, + uint32_t numSyncObjects, void* workArea, OrbisUltWaitingQueueResourcePoolOptParam* optParam) { + LOG_ERROR(Lib_Ult, "(STUBBED) called"); + + if (pool == nullptr) + return ORBIS_ULT_ERROR_NULL; + + if (name != nullptr) + LOG_INFO(Lib_Ult, "Creating WaitingQueueResourcePool for {}", name); + + // TODO: Check memory alignment + // TODO: Set ORBIS_ULT_ERROR_NOT_INITIALIZE + + if (optParam != nullptr) { + // TODO: Check memory alignment + // TODO: FUN_0100678(optParam) + } + + // TODO: FUN_01011b10(&pool->field41_0x30,numThreads,numSyncObjects,(long)workArea); + + if (numThreads > 0 && numSyncObjects > 0 && workArea != nullptr) { + pool->workArea = workArea; + } + + // IF NO ERROR + strncpy((char*)pool, name, 0x1f); + pool->field32_0x20 = 0x100; // ?? + pool->field33_0x22 = '\x06'; // ?? + pool->numThreads = numThreads * 2; + pool->numSyncObjects = numSyncObjects; + // BG26hBGiNlw(pool, 0x16, &pool->field178_0xc0); + // ENDIF + + return ORBIS_OK; +} + +int PS4_SYSV_ABI _sceUltQueueDataResourcePoolCreate( + OrbisUltQueueDataResourcePool* pool, const char* name, uint32_t numData, uint64_t dataSize, + uint32_t numQueueObjects, OrbisUltWaitingQueueResourcePool* waitingQueueResourcePool, + void* workArea, OrbisUltQueueDataResourcePoolOptParam* optParam) { + + LOG_ERROR(Lib_Ult, "(STUBBED) called"); + + if (pool == nullptr) + return ORBIS_ULT_ERROR_NULL; + + // TODO: Check 8 bit alignment + + strncpy((char*)pool, name, 0x1f); + + pool->uk_200 = 0x200; // TODO: Why? + pool->uk_a = '\a'; // TODO: Why? + pool->numData = numData; + pool->numQueueObjects = numQueueObjects; + pool->waitingPool = waitingQueueResourcePool; + pool->workArea = workArea; + + // TODO: BG26hBGiNlw(pool,0x17,&pool->field347_0x170); + + return ORBIS_OK; +} + +int PS4_SYSV_ABI _sceUltQueueCreate(OrbisUltQueue* queue, const char* name, uint64_t dataSize, + OrbisUltQueueDataResourcePool* queueDataResourcePool, + OrbisUltWaitingQueueResourcePool* waitingQueueResourcePool, + OrbisUltQueueOptParam* optParam) { + LOG_ERROR(Lib_Ult, "(STUBBED) called"); + + // TODO: Put data pool + Waiting Pool into Queue + + if (queue != nullptr && name != nullptr && waitingQueueResourcePool->workArea != nullptr) { + // TODO: Check 8bit alignment + if (optParam == nullptr) { + // TODO: Check 8bit alignment + // TODO: Handle default args. It looks like it just sets everything to 0. + } else { + // TODO: Handle optional params + } + + // TODO: Do this in a more readable way + strncpy((char*)queue, name, 0x1f); + + queue->waitingWorkArea = waitingQueueResourcePool->workArea; + queue->dataWorkArea = queueDataResourcePool->workArea; + queue->datasize = dataSize; + + } else { + return ORBIS_ULT_ERROR_NULL; + } + + return ORBIS_OK; +} + +int PS4_SYSV_ABI _sceUltQueueOptParamInitialize(OrbisUltQueueOptParam* optParam) { + LOG_ERROR(Lib_Ult, "(STUBBED) called"); + return ORBIS_OK; +} + +int PS4_SYSV_ABI sceUltQueueTryPush(OrbisUltQueue* queue, void* data) { + LOG_ERROR(Lib_Ult, "(STUBBED) called"); + return ORBIS_OK; +} + +int PS4_SYSV_ABI sceUltQueuePush(OrbisUltQueue* queue, void* data) { + LOG_ERROR(Lib_Ult, "(STUBBED) called"); + + if (queue == nullptr || data == nullptr) + return ORBIS_ULT_ERROR_NULL; + + // If there is no data in the queue when sceUltQueuePop() is executed, the thread is in the wait + // state until data is added to the queue. + void* addr = (char*)queue->waitingWorkArea + (queue->datasize) * (queue->uk5); + + if (!addr) // Empty + return ORBIS_OK; + + memcpy(addr, data, queue->datasize); + + queue->uk5++; + + return ORBIS_OK; +} + +int PS4_SYSV_ABI sceUltQueueTryPop(OrbisUltQueue* queue, void* data) { + LOG_ERROR(Lib_Ult, "(STUBBED) called"); + return ORBIS_OK; +} + +int PS4_SYSV_ABI sceUltQueuePop(OrbisUltQueue* queue, void* data) { + LOG_ERROR(Lib_Ult, "(STUBBED) called"); + + if (queue == nullptr || data == nullptr) + return ORBIS_ULT_ERROR_NULL; + + if (queue->uk5 < 1) // Thread should wait + return ORBIS_OK; + + // If there is no data in the queue when sceUltQueuePop() is executed, the thread is in the wait state until data is added to the queue. + void* addr = (char*)queue->waitingWorkArea + (queue->datasize) * (queue->uk5 - 1); + + if (!addr) // Empty + return ORBIS_OK; + + memcpy(data, addr, queue->datasize); + + queue->uk5--; + + return ORBIS_OK; +} + +u64 PS4_SYSV_ABI sceUltWaitingQueueResourcePoolGetWorkAreaSize(uint32_t numThreads, + uint32_t numSyncObjects) { + u64 size = (numSyncObjects + 2 + numThreads * 2) << 5; + LOG_INFO(Lib_Ult, "WaitingQueueResourcePoolSize: {}", size); + return size; +} + +u64 PS4_SYSV_ABI sceUltQueueDataResourcePoolGetWorkAreaSize(uint32_t numData, uint64_t dataSize, + uint32_t numQueueObjects) { + u64 size = numData * dataSize + (numQueueObjects + 3 + numData * 2) * 0x20; + LOG_INFO(Lib_Ult, "QueueDataResourcePoolSize: {}", size); + return size; +} + +void RegisterlibSceUlt(Core::Loader::SymbolsResolver* sym) { + LIB_FUNCTION("hZIg1EWGsHM", "libSceUlt", 1, "libSceUlt", 1, 1, sceUltInitialize); + LIB_FUNCTION("jw9FkZBXo-g", "libSceUlt", 1, "libSceUlt", 1, 1, _sceUltUlthreadRuntimeCreate); + LIB_FUNCTION("uZz3ci7XYqc", "libSceUlt", 1, "libSceUlt", 1, 1, sceUltQueueTryPop); + LIB_FUNCTION("RVSq2tsm2yw", "libSceUlt", 1, "libSceUlt", 1, 1, sceUltQueuePop); + LIB_FUNCTION("znI3q8S7KQ4", "libSceUlt", 1, "libSceUlt", 1, 1, _sceUltUlthreadCreate); + LIB_FUNCTION("6Mc2Xs7pI1I", "libSceUlt", 1, "libSceUlt", 1, 1, sceUltQueueTryPush); + LIB_FUNCTION("dUwpX3e5NDE", "libSceUlt", 1, "libSceUlt", 1, 1, sceUltQueuePush); + LIB_FUNCTION("YiHujOG9vXY", "libSceUlt", 1, "libSceUlt", 1, 1, + _sceUltWaitingQueueResourcePoolCreate); + LIB_FUNCTION("TFHm6-N6vks", "libSceUlt", 1, "libSceUlt", 1, 1, + _sceUltQueueDataResourcePoolCreate); + LIB_FUNCTION("9Y5keOvb6ok", "libSceUlt", 1, "libSceUlt", 1, 1, _sceUltQueueCreate); + LIB_FUNCTION("TkASc9I-xX0", "libSceUlt", 1, "libSceUlt", 1, 1, _sceUltQueueOptParamInitialize); + LIB_FUNCTION("WIWV1Qd7PFU", "libSceUlt", 1, "libSceUlt", 1, 1, + sceUltWaitingQueueResourcePoolGetWorkAreaSize); + LIB_FUNCTION("evj9YPkS8s4", "libSceUlt", 1, "libSceUlt", 1, 1, + sceUltQueueDataResourcePoolGetWorkAreaSize); +}; + +} // namespace Libraries::Ult \ No newline at end of file diff --git a/src/core/libraries/ult/ult.h b/src/core/libraries/ult/ult.h new file mode 100644 index 00000000..94e289e4 --- /dev/null +++ b/src/core/libraries/ult/ult.h @@ -0,0 +1,134 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/types.h" + +namespace Core::Loader { +class SymbolsResolver; +} + +namespace Libraries::Ult { + +typedef int32_t (*OrbisUltUlthreadEntry)(uint64_t arg); + +struct OrbisUltQueue { + char queue_name[31]; + char uk[8]; + u64 uk2; + u64 uk3; + u64 uk4; + void* ukP; + u32 uk5; + char uk6[131]; + void* waitingWorkArea; + void* dataWorkArea; + char unknown2[24]; + size_t datasize; + // private +}; + +struct OrbisUltUlthreadRuntimeOptParam { + uint64_t oneShotThreadStackSize; + u64 workerThreadCpuAffinityMask; + int32_t workerThreadPriority; + int inheritSched; + /* other members are private */ +}; + +struct OrbisUltUlthreadRuntime { + // private +}; + +struct OrbisUltUlthread { + // private +}; + +struct OrbisUltUlthreadOptParam { + uint32_t attribute; + // rest private +}; + +struct OrbisUltWaitingQueueResourcePool { + char queue_name[31]; + char unknown_char; + u16 field32_0x20; + char field33_0x22; + char unknkown_char3; + u32 numThreads; + u32 numSyncObjects; + char unkown_padding2[4]; + void* workArea; + // More unkowns... +}; + +struct OrbisUltWaitingQueueResourcePoolOptParam { + // private +}; + +struct OrbisUltQueueDataResourcePool { + char queue_name[31]; + short uk_200; + char uk_a; + char unknown_char; + u32 numData; + u32 numQueueObjects; + char unknkown_char3[4]; + void* workArea; + char padd[130]; + char unkown_padding2[4]; + OrbisUltWaitingQueueResourcePool* waitingPool; + // private +}; + +struct OrbisUltQueueDataResourcePoolOptParam { + // private +}; + +struct OrbisUltQueueOptParam { + // Private +}; + +int PS4_SYSV_ABI sceUltInitialize(); + +int PS4_SYSV_ABI _sceUltUlthreadRuntimeCreate(OrbisUltUlthreadRuntime* runtime, const char* name, + uint32_t maxNumUlthread, uint32_t numWorkerThread, + void* workArea, + OrbisUltUlthreadRuntimeOptParam* optParam); + +int PS4_SYSV_ABI _sceUltUlthreadCreate(OrbisUltUlthread* ulthread, const char* name, + OrbisUltUlthreadEntry entry, uint64_t arg, void* context, + uint64_t sizeContext, OrbisUltUlthreadRuntime* runtime, + OrbisUltUlthreadOptParam* optParam); + +int PS4_SYSV_ABI _sceUltWaitingQueueResourcePoolCreate( + OrbisUltWaitingQueueResourcePool* pool, const char* name, uint32_t numThreads, + uint32_t numSyncObjects, void* workArea, OrbisUltWaitingQueueResourcePoolOptParam* optParam); + +int PS4_SYSV_ABI _sceUltQueueDataResourcePoolCreate( + OrbisUltQueueDataResourcePool* pool, const char* name, uint32_t numData, uint64_t dataSize, + uint32_t numQueueObjects, OrbisUltWaitingQueueResourcePool* waitingQueueResourcePool, + void* workArea, OrbisUltQueueDataResourcePoolOptParam* optParam); + +int PS4_SYSV_ABI _sceUltQueueCreate(OrbisUltQueue* queue, const char* name, uint64_t dataSize, + OrbisUltQueueDataResourcePool* queueDataResourcePool, + OrbisUltWaitingQueueResourcePool* waitingQueueResourcePool, + OrbisUltQueueOptParam* optParam); + +int PS4_SYSV_ABI _sceUltQueueOptParamInitialize(OrbisUltQueueOptParam* optParam); + +int PS4_SYSV_ABI sceUltQueueTryPush(OrbisUltQueue* queue, void* data); +int PS4_SYSV_ABI sceUltQueuePush(OrbisUltQueue* queue, void* data); + +int PS4_SYSV_ABI sceUltQueueTryPop(OrbisUltQueue* queue, void* data); +int PS4_SYSV_ABI sceUltQueuePop(OrbisUltQueue* queue, void* data); + +u64 PS4_SYSV_ABI sceUltWaitingQueueResourcePoolGetWorkAreaSize(uint32_t numThreads, + uint32_t numSyncObjects); + +u64 PS4_SYSV_ABI sceUltQueueDataResourcePoolGetWorkAreaSize(uint32_t numData, uint64_t dataSize, + uint32_t numQueueObjects); + +void RegisterlibSceUlt(Core::Loader::SymbolsResolver* sym); +} // namespace Libraries::Ult \ No newline at end of file