From 7cc6881a579869ad544e8b7f7fd81b99d4983116 Mon Sep 17 00:00:00 2001 From: Eladash Date: Tue, 17 Dec 2019 21:55:16 +0200 Subject: [PATCH] Implement sceNpTrophyTerm resources deallocation - Implement sceNpTrophyAbortHandle, if handle is aborted an error code will be returned on its usage. - Free context & handles in sceNpTrophyTerm. - Return SCE_NP_TROPHY_ERROR_INVALID_ARGUMENT on invalid context & handles ids. - Implement id resource shortage error checking. - Check negative sceNpTrophyGetTrophyInfo trophy id. - Minor error checking fix for sceNpTrophySetSoundLevel --- rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp | 358 ++++++++++++++++--------- rpcs3/Emu/Cell/Modules/sceNpTrophy.h | 7 - 2 files changed, 229 insertions(+), 136 deletions(-) diff --git a/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp b/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp index 6b87e8ae39..81b3356e77 100644 --- a/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp +++ b/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp @@ -30,7 +30,7 @@ struct trophy_context_t { static const u32 id_base = 1; static const u32 id_step = 1; - static const u32 id_count = 1023; + static const u32 id_count = 4; std::string trp_name; fs::file trp_stream; @@ -41,7 +41,60 @@ struct trophy_handle_t { static const u32 id_base = 1; static const u32 id_step = 1; - static const u32 id_count = 1023; + static const u32 id_count = 4; + + bool is_aborted = false; +}; + +struct sce_np_trophy_manager +{ + shared_mutex mtx; + std::atomic is_initialized = false; + + // Get context + check handle given + static std::pair get_context_ex(u32 context, u32 handle) + { + decltype(get_context_ex(0, 0)) res{}; + auto& [ctxt, error] = res; + + if (context < trophy_context_t::id_base || + context >= trophy_context_t::id_base + trophy_context_t::id_count) + { + // Id was not in range of valid ids + error = SCE_NP_TROPHY_ERROR_INVALID_ARGUMENT; + return res; + } + + ctxt = idm::check(context); + + if (!ctxt) + { + error = SCE_NP_TROPHY_ERROR_UNKNOWN_CONTEXT; + return res; + } + + if (handle < trophy_handle_t::id_base || + handle >= trophy_handle_t::id_base + trophy_handle_t::id_count) + { + error = SCE_NP_TROPHY_ERROR_INVALID_ARGUMENT; + return res; + } + + const auto hndl = idm::check(handle); + + if (!hndl) + { + error = SCE_NP_TROPHY_ERROR_UNKNOWN_HANDLE; + return res; + } + else if (hndl->is_aborted) + { + error = SCE_NP_TROPHY_ERROR_ABORT; + return res; + } + + return res; + } }; template<> @@ -108,6 +161,8 @@ error_code sceNpTrophyInit(vm::ptr pool, u32 poolSize, u32 containerId, u6 const auto trophy_manager = g_fxo->get(); + std::scoped_lock lock(trophy_manager->mtx); + if (trophy_manager->is_initialized) { return SCE_NP_TROPHY_ERROR_ALREADY_INITIALIZED; @@ -129,11 +184,42 @@ error_code sceNpTrophyTerm() const auto trophy_manager = g_fxo->get(); + std::scoped_lock lock(trophy_manager->mtx); + if (!trophy_manager->is_initialized) { return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED; } + u32 it = 0; + u32 ids[std::max(trophy_context_t::id_count, trophy_handle_t::id_count)]; + + const auto get_handles = [&](u32 id, trophy_handle_t&) + { + ids[it++] = id; + }; + + const auto get_contexts = [&](u32 id, trophy_context_t&) + { + ids[it++] = id; + }; + + // This functionality could be implemented in idm instead + idm::select(get_handles); + + while (it) + { + idm::remove(ids[--it]); + } + + it = 0; + idm::select(get_contexts); + + while (it) + { + idm::remove(ids[--it]); + } + trophy_manager->is_initialized = false; return CELL_OK; @@ -143,7 +229,11 @@ error_code sceNpTrophyCreateHandle(vm::ptr handle) { sceNpTrophy.warning("sceNpTrophyCreateHandle(handle=*0x%x)", handle); - if (!g_fxo->get()->is_initialized) + const auto trophy_manager = g_fxo->get(); + + std::scoped_lock lock(trophy_manager->mtx); + + if (!trophy_manager->is_initialized) { return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED; } @@ -153,8 +243,14 @@ error_code sceNpTrophyCreateHandle(vm::ptr handle) return SCE_NP_TROPHY_ERROR_INVALID_ARGUMENT; } - *handle = idm::make(); + const u32 id = idm::make(); + if (!id) + { + return SCE_NP_TROPHY_ERROR_EXCEEDS_MAX; + } + + *handle = id; return CELL_OK; } @@ -162,21 +258,27 @@ error_code sceNpTrophyDestroyHandle(u32 handle) { sceNpTrophy.warning("sceNpTrophyDestroyHandle(handle=0x%x)", handle); + const auto trophy_manager = g_fxo->get(); + + std::scoped_lock lock(trophy_manager->mtx); + // TODO: find out if this is checked - //if (!g_fxo->get()->is_initialized) + //if (!trophy_manager->is_initialized) //{ // return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED; //} - const auto hndl = idm::get(handle); + if (handle < trophy_handle_t::id_base || + handle >= trophy_handle_t::id_base + trophy_handle_t::id_count) + { + return SCE_NP_TROPHY_ERROR_INVALID_ARGUMENT; + } - if (!hndl) + if (!idm::remove(handle)) { return SCE_NP_TROPHY_ERROR_UNKNOWN_HANDLE; } - idm::remove(handle); - return CELL_OK; } @@ -190,19 +292,32 @@ error_code sceNpTrophyAbortHandle(u32 handle) { sceNpTrophy.todo("sceNpTrophyAbortHandle(handle=0x%x)", handle); + const auto trophy_manager = g_fxo->get(); + + std::scoped_lock lock(trophy_manager->mtx); + // TODO: find out if this is checked - //if (!g_fxo->get()->is_initialized) + //if (!trophy_manager->is_initialized) //{ // return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED; //} - const auto hndl = idm::get(handle); + if (handle < trophy_handle_t::id_base || + handle >= trophy_handle_t::id_base + trophy_handle_t::id_count) + { + return SCE_NP_TROPHY_ERROR_INVALID_ARGUMENT; + } + + const auto hndl = idm::check(handle); if (!hndl) { return SCE_NP_TROPHY_ERROR_UNKNOWN_HANDLE; } + // Once it is aborted it cannot be used anymore + // TODO: Implement function abortion process maybe? (depends if its actually make sense for some functions) + hndl->is_aborted = true; return CELL_OK; } @@ -228,7 +343,11 @@ error_code sceNpTrophyCreateContext(vm::ptr context, vm::cptrget()->is_initialized) + const auto trophy_manager = g_fxo->get(); + + std::scoped_lock lock(trophy_manager->mtx); + + if (!trophy_manager->is_initialized) { return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED; } @@ -281,6 +400,11 @@ error_code sceNpTrophyCreateContext(vm::ptr context, vm::cptr(); + if (!ctxt) + { + return SCE_NP_TROPHY_ERROR_EXCEEDS_MAX; + } + // set trophy context parameters (could be passed to constructor through make_ptr call) ctxt->trp_name = std::move(name); ctxt->trp_stream = std::move(stream); @@ -293,20 +417,26 @@ error_code sceNpTrophyDestroyContext(u32 context) { sceNpTrophy.warning("sceNpTrophyDestroyContext(context=0x%x)", context); - if (!g_fxo->get()->is_initialized) + const auto trophy_manager = g_fxo->get(); + + std::scoped_lock lock(trophy_manager->mtx); + + if (!trophy_manager->is_initialized) { return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED; } - const auto ctxt = idm::get(context); + if (context < trophy_context_t::id_base || + context >= trophy_context_t::id_base + trophy_context_t::id_count) + { + return SCE_NP_TROPHY_ERROR_INVALID_ARGUMENT; + } - if (!ctxt) + if (!idm::remove(context)) { return SCE_NP_TROPHY_ERROR_UNKNOWN_CONTEXT; } - idm::remove(context); - return CELL_OK; } @@ -314,23 +444,20 @@ error_code sceNpTrophyRegisterContext(ppu_thread& ppu, u32 context, u32 handle, { sceNpTrophy.error("sceNpTrophyRegisterContext(context=0x%x, handle=0x%x, statusCb=*0x%x, arg=*0x%x, options=0x%llx)", context, handle, statusCb, arg, options); - if (!g_fxo->get()->is_initialized) + const auto trophy_manager = g_fxo->get(); + + std::shared_lock lock(trophy_manager->mtx); + + if (!trophy_manager->is_initialized) { return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED; } - const auto ctxt = idm::get(context); + const auto [ctxt, error] = trophy_manager->get_context_ex(context, handle); - if (!ctxt) + if (error) { - return SCE_NP_TROPHY_ERROR_UNKNOWN_CONTEXT; - } - - const auto hndl = idm::get(handle); - - if (!hndl) - { - return SCE_NP_TROPHY_ERROR_UNKNOWN_HANDLE; + return error; } if (!statusCb) @@ -473,23 +600,20 @@ error_code sceNpTrophyGetRequiredDiskSpace(u32 context, u32 handle, vm::ptr return SCE_NP_TROPHY_ERROR_NOT_SUPPORTED; } - if (!g_fxo->get()->is_initialized) + const auto trophy_manager = g_fxo->get(); + + std::shared_lock lock(trophy_manager->mtx); + + if (!trophy_manager->is_initialized) { return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED; } - const auto ctxt = idm::get(context); + const auto [ctxt, error] = trophy_manager->get_context_ex(context, handle); - if (!ctxt) + if (error) { - return SCE_NP_TROPHY_ERROR_UNKNOWN_CONTEXT; - } - - const auto hndl = idm::get(handle); - - if (!hndl) - { - return SCE_NP_TROPHY_ERROR_UNKNOWN_HANDLE; + return error; } if (!fs::is_dir(vfs::get("/dev_hdd0/home/" + Emu.GetUsr() + "/trophy/" + ctxt->trp_name))) @@ -511,7 +635,7 @@ error_code sceNpTrophySetSoundLevel(u32 context, u32 handle, u32 level, u64 opti { sceNpTrophy.todo("sceNpTrophySetSoundLevel(context=0x%x, handle=0x%x, level=%d, options=0x%llx)", context, handle, level, options); - if (level > 100 || level < 19) // is < 19 really checked here? + if (level > 100 || level < 20) { return SCE_NP_TROPHY_ERROR_INVALID_ARGUMENT; } @@ -521,23 +645,20 @@ error_code sceNpTrophySetSoundLevel(u32 context, u32 handle, u32 level, u64 opti return SCE_NP_TROPHY_ERROR_NOT_SUPPORTED; } - if (!g_fxo->get()->is_initialized) + const auto trophy_manager = g_fxo->get(); + + std::shared_lock lock(trophy_manager->mtx); + + if (!trophy_manager->is_initialized) { return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED; } - const auto ctxt = idm::get(context); + const auto [ctxt, error] = trophy_manager->get_context_ex(context, handle); - if (!ctxt) + if (error) { - return SCE_NP_TROPHY_ERROR_UNKNOWN_CONTEXT; - } - - const auto hndl = idm::get(handle); - - if (!hndl) - { - return SCE_NP_TROPHY_ERROR_UNKNOWN_HANDLE; + return error; } return CELL_OK; @@ -547,23 +668,20 @@ error_code sceNpTrophyGetGameInfo(u32 context, u32 handle, vm::ptrget()->is_initialized) + const auto trophy_manager = g_fxo->get(); + + std::shared_lock lock(trophy_manager->mtx); + + if (!trophy_manager->is_initialized) { return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED; } - const auto ctxt = idm::get(context); + const auto [ctxt, error] = trophy_manager->get_context_ex(context, handle); - if (!ctxt) + if (error) { - return SCE_NP_TROPHY_ERROR_UNKNOWN_CONTEXT; - } - - const auto hndl = idm::get(handle); - - if (!hndl) - { - return SCE_NP_TROPHY_ERROR_UNKNOWN_HANDLE; + return error; } if (!details && !data) @@ -656,23 +774,20 @@ error_code sceNpTrophyUnlockTrophy(u32 context, u32 handle, s32 trophyId, vm::pt { sceNpTrophy.error("sceNpTrophyUnlockTrophy(context=0x%x, handle=0x%x, trophyId=%d, platinumId=*0x%x)", context, handle, trophyId, platinumId); - if (!g_fxo->get()->is_initialized) + const auto trophy_manager = g_fxo->get(); + + std::shared_lock lock(trophy_manager->mtx); + + if (!trophy_manager->is_initialized) { return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED; } - const auto ctxt = idm::get(context); + const auto [ctxt, error] = trophy_manager->get_context_ex(context, handle); - if (!ctxt) + if (error) { - return SCE_NP_TROPHY_ERROR_UNKNOWN_CONTEXT; - } - - const auto hndl = idm::get(handle); - - if (!hndl) - { - return SCE_NP_TROPHY_ERROR_UNKNOWN_HANDLE; + return error; } if (trophyId < 0 || trophyId >= static_cast(ctxt->tropusr->GetTrophiesCount())) @@ -726,23 +841,20 @@ error_code sceNpTrophyGetTrophyUnlockState(u32 context, u32 handle, vm::ptrget()->is_initialized) + const auto trophy_manager = g_fxo->get(); + + std::shared_lock lock(trophy_manager->mtx); + + if (!trophy_manager->is_initialized) { return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED; } - const auto ctxt = idm::get(context); + const auto [ctxt, error] = trophy_manager->get_context_ex(context, handle); - if (!ctxt) + if (error) { - return SCE_NP_TROPHY_ERROR_UNKNOWN_CONTEXT; - } - - const auto hndl = idm::get(handle); - - if (!hndl) - { - return SCE_NP_TROPHY_ERROR_UNKNOWN_HANDLE; + return error; } const u32 count_ = ctxt->tropusr->GetTrophiesCount(); @@ -775,28 +887,25 @@ error_code sceNpTrophyGetTrophyInfo(u32 context, u32 handle, s32 trophyId, vm::p { sceNpTrophy.warning("sceNpTrophyGetTrophyInfo(context=0x%x, handle=0x%x, trophyId=%d, details=*0x%x, data=*0x%x)", context, handle, trophyId, details, data); - if (trophyId > 127) // max 128 trophies + if (trophyId < 0 || trophyId > 127) // max 128 trophies { return SCE_NP_TROPHY_ERROR_INVALID_TROPHY_ID; } - if (!g_fxo->get()->is_initialized) + const auto trophy_manager = g_fxo->get(); + + std::shared_lock lock(trophy_manager->mtx); + + if (!trophy_manager->is_initialized) { return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED; } - const auto ctxt = idm::get(context); + const auto [ctxt, error] = trophy_manager->get_context_ex(context, handle); - if (!ctxt) + if (error) { - return SCE_NP_TROPHY_ERROR_UNKNOWN_CONTEXT; - } - - const auto hndl = idm::get(handle); - - if (!hndl) - { - return SCE_NP_TROPHY_ERROR_UNKNOWN_HANDLE; + return error; } if (!details && !data) @@ -895,23 +1004,20 @@ error_code sceNpTrophyGetGameProgress(u32 context, u32 handle, vm::ptr perc return SCE_NP_TROPHY_ERROR_INVALID_ARGUMENT; } - if (!g_fxo->get()->is_initialized) + const auto trophy_manager = g_fxo->get(); + + std::shared_lock lock(trophy_manager->mtx); + + if (!trophy_manager->is_initialized) { return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED; } - const auto ctxt = idm::get(context); + const auto [ctxt, error] = trophy_manager->get_context_ex(context, handle); - if (!ctxt) + if (error) { - return SCE_NP_TROPHY_ERROR_UNKNOWN_CONTEXT; - } - - const auto hndl = idm::get(handle); - - if (!hndl) - { - return SCE_NP_TROPHY_ERROR_UNKNOWN_HANDLE; + return error; } const u32 unlocked = ctxt->tropusr->GetUnlockedTrophiesCount(); @@ -929,23 +1035,20 @@ error_code sceNpTrophyGetGameIcon(u32 context, u32 handle, vm::ptr buffer, { sceNpTrophy.warning("sceNpTrophyGetGameIcon(context=0x%x, handle=0x%x, buffer=*0x%x, size=*0x%x)", context, handle, buffer, size); - if (!g_fxo->get()->is_initialized) + const auto trophy_manager = g_fxo->get(); + + std::shared_lock lock(trophy_manager->mtx); + + if (!trophy_manager->is_initialized) { return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED; } - const auto ctxt = idm::get(context); + const auto [ctxt, error] = trophy_manager->get_context_ex(context, handle); - if (!ctxt) + if (error) { - return SCE_NP_TROPHY_ERROR_UNKNOWN_CONTEXT; - } - - const auto hndl = idm::get(handle); - - if (!hndl) - { - return SCE_NP_TROPHY_ERROR_UNKNOWN_HANDLE; + return error; } if (!size) @@ -982,23 +1085,20 @@ error_code sceNpTrophyGetTrophyIcon(u32 context, u32 handle, s32 trophyId, vm::p { sceNpTrophy.warning("sceNpTrophyGetTrophyIcon(context=0x%x, handle=0x%x, trophyId=%d, buffer=*0x%x, size=*0x%x)", context, handle, trophyId, buffer, size); - if (!g_fxo->get()->is_initialized) + const auto trophy_manager = g_fxo->get(); + + std::shared_lock lock(trophy_manager->mtx); + + if (!trophy_manager->is_initialized) { return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED; } - const auto ctxt = idm::get(context); + const auto [ctxt, error] = trophy_manager->get_context_ex(context, handle); - if (!ctxt) + if (error) { - return SCE_NP_TROPHY_ERROR_UNKNOWN_CONTEXT; - } - - const auto hndl = idm::get(handle); - - if (!hndl) - { - return SCE_NP_TROPHY_ERROR_UNKNOWN_HANDLE; + return error; } if (!size) diff --git a/rpcs3/Emu/Cell/Modules/sceNpTrophy.h b/rpcs3/Emu/Cell/Modules/sceNpTrophy.h index 5fbe5a9239..e75dcfdf10 100644 --- a/rpcs3/Emu/Cell/Modules/sceNpTrophy.h +++ b/rpcs3/Emu/Cell/Modules/sceNpTrophy.h @@ -154,10 +154,3 @@ public: virtual s32 ShowTrophyNotification(const SceNpTrophyDetails& trophy, const std::vector& trophyIconBfr) = 0; }; - -// fxm objects - -struct sce_np_trophy_manager -{ - std::atomic is_initialized = false; -};