diff --git a/Source/sys-clk/common/include/cpp_util.hpp b/Source/sys-clk/common/include/cpp_util.hpp new file mode 100644 index 00000000..34e5621f --- /dev/null +++ b/Source/sys-clk/common/include/cpp_util.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include + +template +class ScopeGuard { +public: + ScopeGuard(F&& f) + : f(f), engaged(true) {}; + + ~ScopeGuard() { + if (engaged) + f(); + }; + + ScopeGuard(ScopeGuard&& rhs) + : f(std::move(rhs.f)) {}; + + void dismiss() { engaged = false; } + +private: + F f; + bool engaged; +}; + +struct MakeScopeExit { + template + ScopeGuard operator+=(F&& f) { + return ScopeGuard(std::move(f)); + }; +}; + +#define STRING_CAT2(x, y) x##y +#define STRING_CAT(x, y) STRING_CAT2(x, y) +#define SCOPE_GUARD MakeScopeExit() += [&]() __attribute__((always_inline)) +#define SCOPE_EXIT auto STRING_CAT(scope_exit_, __LINE__) = SCOPE_GUARD \ No newline at end of file diff --git a/Source/sys-clk/common/include/sysclk.h b/Source/sys-clk/common/include/sysclk.h index 18e644f3..ffcd71d7 100644 --- a/Source/sys-clk/common/include/sysclk.h +++ b/Source/sys-clk/common/include/sysclk.h @@ -11,6 +11,7 @@ #pragma once #ifdef __cplusplus +#include "cpp_util.hpp" extern "C" { #endif diff --git a/Source/sys-clk/common/include/sysclk/board.h b/Source/sys-clk/common/include/sysclk/board.h index 9bb2ecdf..43849629 100644 --- a/Source/sys-clk/common/include/sysclk/board.h +++ b/Source/sys-clk/common/include/sysclk/board.h @@ -61,6 +61,15 @@ typedef enum SysClkRamLoad_EnumMax } SysClkRamLoad; +typedef enum +{ + ReverseNX_NotFound = 0, + ReverseNX_SystemDefault = 0, + ReverseNX_Handheld, + ReverseNX_Docked, +} ReverseNXMode; + + #define SYSCLK_ENUM_VALID(n, v) ((v) < n##_EnumMax) static inline const char* sysclkFormatModule(SysClkModule module, bool pretty) diff --git a/Source/sys-clk/common/include/sysclk/client/ipc.h b/Source/sys-clk/common/include/sysclk/client/ipc.h index 6a05ec1d..c903807f 100644 --- a/Source/sys-clk/common/include/sysclk/client/ipc.h +++ b/Source/sys-clk/common/include/sysclk/client/ipc.h @@ -31,6 +31,7 @@ Result sysclkIpcSetProfiles(u64 tid, SysClkTitleProfileList* profiles); Result sysclkIpcGetConfigValues(SysClkConfigValueList* out_configValues); Result sysclkIpcSetConfigValues(SysClkConfigValueList* configValues); Result sysclkIpcGetFreqList(SysClkModule module, u32* list, u32 maxCount, u32* outCount); +Result sysclkIpcSetReverseNXRTMode(ReverseNXMode mode); static inline Result sysclkIpcRemoveOverride(SysClkModule module) { diff --git a/Source/sys-clk/common/include/sysclk/config.h b/Source/sys-clk/common/include/sysclk/config.h index 0128f66d..1accb40d 100644 --- a/Source/sys-clk/common/include/sysclk/config.h +++ b/Source/sys-clk/common/include/sysclk/config.h @@ -21,6 +21,7 @@ typedef enum { SysClkConfigValue_CsvWriteIntervalMs, HocClkConfigValue_UncappedClocks, HocClkConfigValue_OverwriteBoostMode, + HocClkConfigValue_SyncReverseNXMode, SysClkConfigValue_EnumMax, } SysClkConfigValue; @@ -46,6 +47,8 @@ static inline const char* sysclkFormatConfigValue(SysClkConfigValue val, bool pr return pretty ? "Uncapped Clocks" : "uncapped_clocks"; case HocClkConfigValue_OverwriteBoostMode: return pretty ? "Overwrite Boost Mode" : "ow_boost"; + case HocClkConfigValue_SyncReverseNXMode: + return pretty ? "ReverseNX Sync" : "rnx_sync"; default: return NULL; } @@ -63,6 +66,7 @@ static inline uint64_t sysclkDefaultConfigValue(SysClkConfigValue val) case SysClkConfigValue_CsvWriteIntervalMs: case HocClkConfigValue_UncappedClocks: case HocClkConfigValue_OverwriteBoostMode: + case HocClkConfigValue_SyncReverseNXMode: return 0ULL; default: return 0ULL; @@ -82,6 +86,7 @@ static inline uint64_t sysclkValidConfigValue(SysClkConfigValue val, uint64_t in return input >= 0; case HocClkConfigValue_OverwriteBoostMode: case HocClkConfigValue_UncappedClocks: + case HocClkConfigValue_SyncReverseNXMode: return (input & 0x1) == input; default: return false; diff --git a/Source/sys-clk/common/include/sysclk/ipc.h b/Source/sys-clk/common/include/sysclk/ipc.h index 722e07af..48437c8d 100644 --- a/Source/sys-clk/common/include/sysclk/ipc.h +++ b/Source/sys-clk/common/include/sysclk/ipc.h @@ -31,6 +31,7 @@ enum SysClkIpcCmd SysClkIpcCmd_GetConfigValues = 9, SysClkIpcCmd_SetConfigValues = 10, SysClkIpcCmd_GetFreqList = 11, + SysClkIpcCmd_SetReverseNXRTMode = 12, }; diff --git a/Source/sys-clk/common/src/client/ipc.c b/Source/sys-clk/common/src/client/ipc.c index a0e635cd..8bc6801a 100644 --- a/Source/sys-clk/common/src/client/ipc.c +++ b/Source/sys-clk/common/src/client/ipc.c @@ -126,3 +126,8 @@ Result sysclkIpcGetFreqList(SysClkModule module, u32* list, u32 maxCount, u32* o .buffers = {{list, maxCount * sizeof(u32)}}, ); } + +Result sysclkIpcSetReverseNXRTMode(ReverseNXMode mode) +{ + return serviceDispatchIn(&g_sysclkSrv, SysClkIpcCmd_SetReverseNXRTMode, mode); +} diff --git a/Source/sys-clk/manager/src/ipc/client.h b/Source/sys-clk/manager/src/ipc/client.h index 1b90c52a..0c73d214 100644 --- a/Source/sys-clk/manager/src/ipc/client.h +++ b/Source/sys-clk/manager/src/ipc/client.h @@ -23,6 +23,7 @@ #include "ipc.h" #if defined(__SWITCH__) && defined(__cplusplus) +#include "cpp_util.hpp" extern "C" { #endif diff --git a/Source/sys-clk/overlay/src/ipc.h b/Source/sys-clk/overlay/src/ipc.h index 56c9bcdf..282cc427 100644 --- a/Source/sys-clk/overlay/src/ipc.h +++ b/Source/sys-clk/overlay/src/ipc.h @@ -11,6 +11,8 @@ #pragma once #if defined(__cplusplus) +#include "cpp_util.hpp" + extern "C" { #endif diff --git a/Source/sys-clk/overlay/src/ui/gui/misc_gui.cpp b/Source/sys-clk/overlay/src/ui/gui/misc_gui.cpp index 3917d5b7..54ed48ac 100644 --- a/Source/sys-clk/overlay/src/ui/gui/misc_gui.cpp +++ b/Source/sys-clk/overlay/src/ui/gui/misc_gui.cpp @@ -43,7 +43,7 @@ void MiscGui::listUI() this->listElement->addItem(new tsl::elm::CategoryHeader("Config")); addConfigToggle(HocClkConfigValue_UncappedClocks); addConfigToggle(HocClkConfigValue_OverwriteBoostMode); - + addConfigToggle(HocClkConfigValue_SyncReverseNXMode); } void MiscGui::refresh() { diff --git a/Source/sys-clk/sysmodule/src/clock_manager.cpp b/Source/sys-clk/sysmodule/src/clock_manager.cpp index 7b2fab4b..7f8b9e77 100644 --- a/Source/sys-clk/sysmodule/src/clock_manager.cpp +++ b/Source/sys-clk/sysmodule/src/clock_manager.cpp @@ -15,6 +15,30 @@ #include "process_management.h" #include "errors.h" #include "ipc_service.h" + +ClockManager* ClockManager::instance = NULL; + +ClockManager* ClockManager::GetInstance() +{ + return instance; +} + +void ClockManager::Exit() +{ + if(instance) + { + delete instance; + } +} + +void ClockManager::Initialize() +{ + if(!instance) + { + instance = new ClockManager(); + } +} + ClockManager::ClockManager() { this->config = Config::CreateDefault(); @@ -34,6 +58,9 @@ ClockManager::ClockManager() this->running = false; this->lastTempLogNs = 0; this->lastCsvWriteNs = 0; + + this->rnxSync = new ReverseNXSync; + } ClockManager::~ClockManager() @@ -237,6 +264,8 @@ bool ClockManager::RefreshContext() FileUtils::LogLine("[mgr] TitleID change: %016lX", applicationId); this->context->applicationId = applicationId; hasChanged = true; + this->rnxSync->Reset(applicationId); + } SysClkProfile profile = Board::GetProfile(); @@ -250,6 +279,7 @@ bool ClockManager::RefreshContext() // restore clocks to stock values on app or profile change if (hasChanged) { + this->rnxSync->ToggleSync(this->GetConfig()->GetConfigValue(HocClkConfigValue_SyncReverseNXMode)); Board::ResetToStock(); this->WaitForNextTick(); } @@ -347,3 +377,7 @@ bool ClockManager::RefreshContext() return hasChanged; } + +void ClockManager::SetRNXRTMode(ReverseNXMode mode) { + this->rnxSync->SetRTMode(mode); +} \ No newline at end of file diff --git a/Source/sys-clk/sysmodule/src/clock_manager.h b/Source/sys-clk/sysmodule/src/clock_manager.h index 5fa12afd..a56e6112 100644 --- a/Source/sys-clk/sysmodule/src/clock_manager.h +++ b/Source/sys-clk/sysmodule/src/clock_manager.h @@ -16,10 +16,18 @@ #include "config.h" #include "board.h" #include +#include "integrations.h" + +class ReverseNXSync; class ClockManager { public: + static ClockManager* GetInstance(); + static void Initialize(); + static void Exit(); + + ClockManager(); virtual ~ClockManager(); @@ -30,6 +38,7 @@ class ClockManager void GetFreqList(SysClkModule module, std::uint32_t* list, std::uint32_t maxCount, std::uint32_t* outCount); void Tick(); void WaitForNextTick(); + void SetRNXRTMode(ReverseNXMode mode); protected: bool IsAssignableHz(SysClkModule module, std::uint32_t hz); @@ -39,6 +48,8 @@ class ClockManager void RefreshFreqTableRow(SysClkModule module); bool RefreshContext(); + static ClockManager *instance; + std::atomic_bool running; LockableMutex contextMutex; struct { @@ -51,4 +62,5 @@ class ClockManager std::uint64_t lastFreqLogNs; std::uint64_t lastPowerLogNs; std::uint64_t lastCsvWriteNs; + ReverseNXSync *rnxSync; }; diff --git a/Source/sys-clk/sysmodule/src/integrations.cpp b/Source/sys-clk/sysmodule/src/integrations.cpp new file mode 100644 index 00000000..7ac0b04e --- /dev/null +++ b/Source/sys-clk/sysmodule/src/integrations.cpp @@ -0,0 +1,66 @@ +#include "integrations.h" + +ReverseNXSync::ReverseNXSync() + : m_rt_mode(ReverseNX_NotFound), m_tool_mode(ReverseNX_NotFound) { + FILE *fp = fopen("/atmosphere/contents/0000000000534C56/flags/boot2.flag", "r"); + m_tool_enabled = fp ? true : false; + if (fp) + fclose(fp); +} + +SysClkProfile ReverseNXSync::GetProfile(SysClkProfile real) { + switch (this->GetMode()) { + case ReverseNX_Docked: + return SysClkProfile_Docked; + case ReverseNX_Handheld: + if (real == SysClkProfile_Docked) + return SysClkProfile_HandheldChargingOfficial; + default: + return real; + } +} + +ReverseNXMode ReverseNXSync::GetMode() { + if (!this->m_sync_enabled) + return ReverseNX_NotFound; + if (this->m_rt_mode) + return this->m_rt_mode; + return this->m_tool_mode; +} + +ReverseNXMode ReverseNXSync::GetToolModeFromPatch(const char* patch_path) { + constexpr uint32_t DOCKED_MAGIC = 0x320003E0; + constexpr uint32_t HANDHELD_MAGIC = 0x52A00000; + FILE *fp = fopen(patch_path, "rb"); + if (fp) { + uint32_t buf = 0; + fread(&buf, sizeof(buf), 1, fp); + fclose(fp); + + if (buf == DOCKED_MAGIC) + return ReverseNX_Docked; + if (buf == HANDHELD_MAGIC) + return ReverseNX_Handheld; + } + + return ReverseNX_NotFound; +} + +ReverseNXMode ReverseNXSync::RecheckToolMode() { + ReverseNXMode mode = ReverseNX_NotFound; + if (this->m_tool_enabled) { + const char* fileName = "_ZN2nn2oe18GetPerformanceModeEv.asm64"; // or _ZN2nn2oe18GetPerformanceModeEv.asm64 + const char* filePath = new char[72]; + SCOPE_EXIT { delete[] filePath; }; + /* Check per-game patch */ + snprintf((char*)filePath, 72, "/SaltySD/patches/%016lX/%s", this->m_app_id, fileName); + mode = this->GetToolModeFromPatch(filePath); + if (!mode) { + /* Check global patch */ + snprintf((char*)filePath, 72, "/SaltySD/patches/%s", fileName); + mode = this->GetToolModeFromPatch(filePath); + } + } + + return mode; +} \ No newline at end of file diff --git a/Source/sys-clk/sysmodule/src/integrations.h b/Source/sys-clk/sysmodule/src/integrations.h new file mode 100644 index 00000000..0222d216 --- /dev/null +++ b/Source/sys-clk/sysmodule/src/integrations.h @@ -0,0 +1,33 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include "errors.h" +#include "file_utils.h" + +class ReverseNXSync { +public: + ReverseNXSync (); + + void ToggleSync(bool enable) { m_sync_enabled = enable; }; + void Reset(uint64_t app_id) { m_app_id = app_id; SetRTMode(ReverseNX_NotFound); GetToolMode(); } + ReverseNXMode GetRTMode() { return m_rt_mode; }; + void SetRTMode(ReverseNXMode mode) { m_rt_mode = mode; }; + ReverseNXMode GetToolMode() { return m_tool_mode = RecheckToolMode(); }; + SysClkProfile GetProfile(SysClkProfile real); + ReverseNXMode GetMode(); + +protected: + std::atomic m_rt_mode; + ReverseNXMode m_tool_mode; + uint64_t m_app_id = 0; + bool m_tool_enabled; + bool m_sync_enabled; + + ReverseNXMode GetToolModeFromPatch(const char* patch_path); + ReverseNXMode RecheckToolMode(); +}; diff --git a/Source/sys-clk/sysmodule/src/ipc_service.cpp b/Source/sys-clk/sysmodule/src/ipc_service.cpp index 330be004..47bbdd8b 100644 --- a/Source/sys-clk/sysmodule/src/ipc_service.cpp +++ b/Source/sys-clk/sysmodule/src/ipc_service.cpp @@ -13,7 +13,7 @@ #include #include "file_utils.h" #include "errors.h" - +#include "clock_manager.h" IpcService::IpcService(ClockManager* clockMgr) { std::int32_t priority; @@ -166,7 +166,12 @@ Result IpcService::ServiceHandlerFunc(void* arg, const IpcServerRequest* r, u8* ); } break; - + case SysClkIpcCmd_SetReverseNXRTMode: + if (r->data.size >= sizeof(ReverseNXMode)) { + ReverseNXMode mode = *((ReverseNXMode*)r->data.ptr); + return ipcSrv->SetReverseNXRTMode(mode); + } + break; } return SYSCLK_ERROR(Generic); @@ -317,4 +322,9 @@ Result IpcService::GetFreqList(SysClkIpc_GetFreqList_Args* args, std::uint32_t* this->clockMgr->GetFreqList(args->module, out_list, args->maxCount, out_count); return 0; -} \ No newline at end of file +} + +Result IpcService::SetReverseNXRTMode(ReverseNXMode mode) { + ClockManager::GetInstance()->SetRNXRTMode(mode); + return 0; +} diff --git a/Source/sys-clk/sysmodule/src/ipc_service.h b/Source/sys-clk/sysmodule/src/ipc_service.h index 2220e235..de74082e 100644 --- a/Source/sys-clk/sysmodule/src/ipc_service.h +++ b/Source/sys-clk/sysmodule/src/ipc_service.h @@ -36,6 +36,7 @@ class IpcService Result GetConfigValues(SysClkConfigValueList* out_configValues); Result SetConfigValues(SysClkConfigValueList* configValues); Result GetFreqList(SysClkIpc_GetFreqList_Args* args, std::uint32_t* out_list, std::size_t size, std::uint32_t* out_count); + Result SetReverseNXRTMode(ReverseNXMode mode); bool running; Thread thread;