hoc-clk: add reversenx sync

This commit is contained in:
souldbminersmwc
2025-10-02 15:08:06 -04:00
parent 923dc00b53
commit fde9a5b1a3
16 changed files with 221 additions and 4 deletions

View File

@@ -0,0 +1,36 @@
#pragma once
#include <utility>
template<typename F>
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<typename F>
ScopeGuard<F> operator+=(F&& f) {
return ScopeGuard<F>(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

View File

@@ -11,6 +11,7 @@
#pragma once #pragma once
#ifdef __cplusplus #ifdef __cplusplus
#include "cpp_util.hpp"
extern "C" { extern "C" {
#endif #endif

View File

@@ -61,6 +61,15 @@ typedef enum
SysClkRamLoad_EnumMax SysClkRamLoad_EnumMax
} SysClkRamLoad; } SysClkRamLoad;
typedef enum
{
ReverseNX_NotFound = 0,
ReverseNX_SystemDefault = 0,
ReverseNX_Handheld,
ReverseNX_Docked,
} ReverseNXMode;
#define SYSCLK_ENUM_VALID(n, v) ((v) < n##_EnumMax) #define SYSCLK_ENUM_VALID(n, v) ((v) < n##_EnumMax)
static inline const char* sysclkFormatModule(SysClkModule module, bool pretty) static inline const char* sysclkFormatModule(SysClkModule module, bool pretty)

View File

@@ -31,6 +31,7 @@ Result sysclkIpcSetProfiles(u64 tid, SysClkTitleProfileList* profiles);
Result sysclkIpcGetConfigValues(SysClkConfigValueList* out_configValues); Result sysclkIpcGetConfigValues(SysClkConfigValueList* out_configValues);
Result sysclkIpcSetConfigValues(SysClkConfigValueList* configValues); Result sysclkIpcSetConfigValues(SysClkConfigValueList* configValues);
Result sysclkIpcGetFreqList(SysClkModule module, u32* list, u32 maxCount, u32* outCount); Result sysclkIpcGetFreqList(SysClkModule module, u32* list, u32 maxCount, u32* outCount);
Result sysclkIpcSetReverseNXRTMode(ReverseNXMode mode);
static inline Result sysclkIpcRemoveOverride(SysClkModule module) static inline Result sysclkIpcRemoveOverride(SysClkModule module)
{ {

View File

@@ -21,6 +21,7 @@ typedef enum {
SysClkConfigValue_CsvWriteIntervalMs, SysClkConfigValue_CsvWriteIntervalMs,
HocClkConfigValue_UncappedClocks, HocClkConfigValue_UncappedClocks,
HocClkConfigValue_OverwriteBoostMode, HocClkConfigValue_OverwriteBoostMode,
HocClkConfigValue_SyncReverseNXMode,
SysClkConfigValue_EnumMax, SysClkConfigValue_EnumMax,
} SysClkConfigValue; } SysClkConfigValue;
@@ -46,6 +47,8 @@ static inline const char* sysclkFormatConfigValue(SysClkConfigValue val, bool pr
return pretty ? "Uncapped Clocks" : "uncapped_clocks"; return pretty ? "Uncapped Clocks" : "uncapped_clocks";
case HocClkConfigValue_OverwriteBoostMode: case HocClkConfigValue_OverwriteBoostMode:
return pretty ? "Overwrite Boost Mode" : "ow_boost"; return pretty ? "Overwrite Boost Mode" : "ow_boost";
case HocClkConfigValue_SyncReverseNXMode:
return pretty ? "ReverseNX Sync" : "rnx_sync";
default: default:
return NULL; return NULL;
} }
@@ -63,6 +66,7 @@ static inline uint64_t sysclkDefaultConfigValue(SysClkConfigValue val)
case SysClkConfigValue_CsvWriteIntervalMs: case SysClkConfigValue_CsvWriteIntervalMs:
case HocClkConfigValue_UncappedClocks: case HocClkConfigValue_UncappedClocks:
case HocClkConfigValue_OverwriteBoostMode: case HocClkConfigValue_OverwriteBoostMode:
case HocClkConfigValue_SyncReverseNXMode:
return 0ULL; return 0ULL;
default: default:
return 0ULL; return 0ULL;
@@ -82,6 +86,7 @@ static inline uint64_t sysclkValidConfigValue(SysClkConfigValue val, uint64_t in
return input >= 0; return input >= 0;
case HocClkConfigValue_OverwriteBoostMode: case HocClkConfigValue_OverwriteBoostMode:
case HocClkConfigValue_UncappedClocks: case HocClkConfigValue_UncappedClocks:
case HocClkConfigValue_SyncReverseNXMode:
return (input & 0x1) == input; return (input & 0x1) == input;
default: default:
return false; return false;

View File

@@ -31,6 +31,7 @@ enum SysClkIpcCmd
SysClkIpcCmd_GetConfigValues = 9, SysClkIpcCmd_GetConfigValues = 9,
SysClkIpcCmd_SetConfigValues = 10, SysClkIpcCmd_SetConfigValues = 10,
SysClkIpcCmd_GetFreqList = 11, SysClkIpcCmd_GetFreqList = 11,
SysClkIpcCmd_SetReverseNXRTMode = 12,
}; };

View File

@@ -126,3 +126,8 @@ Result sysclkIpcGetFreqList(SysClkModule module, u32* list, u32 maxCount, u32* o
.buffers = {{list, maxCount * sizeof(u32)}}, .buffers = {{list, maxCount * sizeof(u32)}},
); );
} }
Result sysclkIpcSetReverseNXRTMode(ReverseNXMode mode)
{
return serviceDispatchIn(&g_sysclkSrv, SysClkIpcCmd_SetReverseNXRTMode, mode);
}

View File

@@ -23,6 +23,7 @@
#include "ipc.h" #include "ipc.h"
#if defined(__SWITCH__) && defined(__cplusplus) #if defined(__SWITCH__) && defined(__cplusplus)
#include "cpp_util.hpp"
extern "C" { extern "C" {
#endif #endif

View File

@@ -11,6 +11,8 @@
#pragma once #pragma once
#if defined(__cplusplus) #if defined(__cplusplus)
#include "cpp_util.hpp"
extern "C" extern "C"
{ {
#endif #endif

View File

@@ -43,7 +43,7 @@ void MiscGui::listUI()
this->listElement->addItem(new tsl::elm::CategoryHeader("Config")); this->listElement->addItem(new tsl::elm::CategoryHeader("Config"));
addConfigToggle(HocClkConfigValue_UncappedClocks); addConfigToggle(HocClkConfigValue_UncappedClocks);
addConfigToggle(HocClkConfigValue_OverwriteBoostMode); addConfigToggle(HocClkConfigValue_OverwriteBoostMode);
addConfigToggle(HocClkConfigValue_SyncReverseNXMode);
} }
void MiscGui::refresh() { void MiscGui::refresh() {

View File

@@ -15,6 +15,30 @@
#include "process_management.h" #include "process_management.h"
#include "errors.h" #include "errors.h"
#include "ipc_service.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() ClockManager::ClockManager()
{ {
this->config = Config::CreateDefault(); this->config = Config::CreateDefault();
@@ -34,6 +58,9 @@ ClockManager::ClockManager()
this->running = false; this->running = false;
this->lastTempLogNs = 0; this->lastTempLogNs = 0;
this->lastCsvWriteNs = 0; this->lastCsvWriteNs = 0;
this->rnxSync = new ReverseNXSync;
} }
ClockManager::~ClockManager() ClockManager::~ClockManager()
@@ -237,6 +264,8 @@ bool ClockManager::RefreshContext()
FileUtils::LogLine("[mgr] TitleID change: %016lX", applicationId); FileUtils::LogLine("[mgr] TitleID change: %016lX", applicationId);
this->context->applicationId = applicationId; this->context->applicationId = applicationId;
hasChanged = true; hasChanged = true;
this->rnxSync->Reset(applicationId);
} }
SysClkProfile profile = Board::GetProfile(); SysClkProfile profile = Board::GetProfile();
@@ -250,6 +279,7 @@ bool ClockManager::RefreshContext()
// restore clocks to stock values on app or profile change // restore clocks to stock values on app or profile change
if (hasChanged) if (hasChanged)
{ {
this->rnxSync->ToggleSync(this->GetConfig()->GetConfigValue(HocClkConfigValue_SyncReverseNXMode));
Board::ResetToStock(); Board::ResetToStock();
this->WaitForNextTick(); this->WaitForNextTick();
} }
@@ -347,3 +377,7 @@ bool ClockManager::RefreshContext()
return hasChanged; return hasChanged;
} }
void ClockManager::SetRNXRTMode(ReverseNXMode mode) {
this->rnxSync->SetRTMode(mode);
}

View File

@@ -16,10 +16,18 @@
#include "config.h" #include "config.h"
#include "board.h" #include "board.h"
#include <nxExt/cpp/lockable_mutex.h> #include <nxExt/cpp/lockable_mutex.h>
#include "integrations.h"
class ReverseNXSync;
class ClockManager class ClockManager
{ {
public: public:
static ClockManager* GetInstance();
static void Initialize();
static void Exit();
ClockManager(); ClockManager();
virtual ~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 GetFreqList(SysClkModule module, std::uint32_t* list, std::uint32_t maxCount, std::uint32_t* outCount);
void Tick(); void Tick();
void WaitForNextTick(); void WaitForNextTick();
void SetRNXRTMode(ReverseNXMode mode);
protected: protected:
bool IsAssignableHz(SysClkModule module, std::uint32_t hz); bool IsAssignableHz(SysClkModule module, std::uint32_t hz);
@@ -39,6 +48,8 @@ class ClockManager
void RefreshFreqTableRow(SysClkModule module); void RefreshFreqTableRow(SysClkModule module);
bool RefreshContext(); bool RefreshContext();
static ClockManager *instance;
std::atomic_bool running; std::atomic_bool running;
LockableMutex contextMutex; LockableMutex contextMutex;
struct { struct {
@@ -51,4 +62,5 @@ class ClockManager
std::uint64_t lastFreqLogNs; std::uint64_t lastFreqLogNs;
std::uint64_t lastPowerLogNs; std::uint64_t lastPowerLogNs;
std::uint64_t lastCsvWriteNs; std::uint64_t lastCsvWriteNs;
ReverseNXSync *rnxSync;
}; };

View File

@@ -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;
}

View File

@@ -0,0 +1,33 @@
#pragma once
#include <atomic>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <nxExt.h>
#include <sysclk.h>
#include <switch.h>
#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<ReverseNXMode> 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();
};

View File

@@ -13,7 +13,7 @@
#include <switch.h> #include <switch.h>
#include "file_utils.h" #include "file_utils.h"
#include "errors.h" #include "errors.h"
#include "clock_manager.h"
IpcService::IpcService(ClockManager* clockMgr) IpcService::IpcService(ClockManager* clockMgr)
{ {
std::int32_t priority; std::int32_t priority;
@@ -166,7 +166,12 @@ Result IpcService::ServiceHandlerFunc(void* arg, const IpcServerRequest* r, u8*
); );
} }
break; 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); return SYSCLK_ERROR(Generic);
@@ -318,3 +323,8 @@ Result IpcService::GetFreqList(SysClkIpc_GetFreqList_Args* args, std::uint32_t*
return 0; return 0;
} }
Result IpcService::SetReverseNXRTMode(ReverseNXMode mode) {
ClockManager::GetInstance()->SetRNXRTMode(mode);
return 0;
}

View File

@@ -36,6 +36,7 @@ class IpcService
Result GetConfigValues(SysClkConfigValueList* out_configValues); Result GetConfigValues(SysClkConfigValueList* out_configValues);
Result SetConfigValues(SysClkConfigValueList* 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 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; bool running;
Thread thread; Thread thread;