initial commit

This commit is contained in:
KazushiM
2021-07-05 17:02:51 +08:00
commit 586c36d6f2
32 changed files with 2175 additions and 0 deletions

View File

@@ -0,0 +1,51 @@
--- stratosphere/loader/source/ldr_patcher.cpp @a672917
+++ stratosphere/loader/source/ldr_patcher.cpp
@@ -15,11 +15,27 @@
*/
#include <stratosphere.hpp>
#include "ldr_patcher.hpp"
+#include "ldr_pcv_patch.hpp"
namespace ams::ldr {
namespace {
+ constexpr u8 PcvModuleId[2][20] = {
+ { 0x91, 0xD6, 0x1D, 0x59, 0xD7, 0x00, 0x23, 0x78, 0xE3, 0x55, 0x84, 0xFC, 0x0B, 0x38, 0xC7, 0x69, 0x3A, 0x3A, 0xBA, 0xB5, }, //11.0.0
+ { 0xC5, 0x03, 0xE9, 0x65, 0x50, 0xF3, 0x02, 0xE1, 0x21, 0x87, 0x31, 0x36, 0xB8, 0x14, 0xA5, 0x29, 0x86, 0x3D, 0x94, 0x9B, }, //12.0.0
+ };
+
+ constexpr u8 NifmModuleId[2][20] = {
+ { 0x7A, 0x43, 0xF8, 0x40, 0x33, 0x7C, 0x28, 0xD4, 0x53, 0x71, 0x88, 0x43, 0x60, 0x8E, 0xEF, 0xF7, 0x8A, 0xFD, 0x46, 0x0B, }, //11.0.0
+ { 0xA8, 0x5F, 0x50, 0xFB, 0xA1, 0x0E, 0x06, 0xA3, 0xEB, 0xA3, 0xD3, 0xFA, 0xCB, 0x9E, 0x07, 0x5B, 0x21, 0x8C, 0x7D, 0x6D, },
+ };
+
+ constexpr u8 AmModuleId[2][20] = {
+ { 0x25, 0x50, 0x97, 0xEF, 0x11, 0xC0, 0x75, 0x9B, 0x1F, 0x36, 0x13, 0x2F, 0x73, 0xBD, 0xDB, 0x04, 0xC3, 0xEF, 0x9A, 0xBE, }, //11.0.0
+ { 0x5E, 0x5F, 0x1C, 0xC2, 0x4D, 0x37, 0x45, 0x91, 0xAF, 0xC2, 0xA2, 0x33, 0x6C, 0x94, 0x53, 0xCC, 0xFA, 0x39, 0x61, 0xC1, },
+ };
+
constexpr const char *NsoPatchesDirectory = "exefs_patches";
/* Exefs patches want to prevent modification of header, */
@@ -113,6 +129,20 @@ namespace ams::ldr {
/* Apply IPS patches. */
void LocateAndApplyIpsPatchesToModule(const u8 *build_id, uintptr_t mapped_nso, size_t mapped_size) {
+ for(int i = 0; i < 2; i++)
+ {
+ if(memcmp(PcvModuleId[i], build_id, sizeof(PcvModuleId[i])) == 0) {
+ ApplyPcvPatch(reinterpret_cast<u8 *>(mapped_nso), mapped_size, i);
+ return; // Return here since pcv module loads before sd card can be mounted
+ }
+ else if(memcmp(NifmModuleId[i], build_id, sizeof(NifmModuleId[i])) == 0) {
+ ApplyCtestPatch(reinterpret_cast<u8 *>(mapped_nso), mapped_size, i);
+ }
+ else if(memcmp(AmModuleId[i], build_id, sizeof(AmModuleId[i])) == 0) {
+ ApplyCopyrightPatch(reinterpret_cast<u8 *>(mapped_nso), mapped_size, i);
+ }
+ }
+
if (!EnsureSdCardMounted()) {
return;
}

View File

@@ -0,0 +1,268 @@
// placed in Atmosphere/stratosphere/loader/source/
#include <stratosphere.hpp>
#define EMC_OVERCLOCK 1
#define EMC_OVERVOLT 1
namespace ams::ldr {
namespace {
constexpr u32 CtestOffset[2] = { 0xF400, 0x1079C };
constexpr u32 CopyrightOffset[2] = { 0xC6128, 0xCA414 }; //am_no_copyright port
constexpr u8 BehemothPatch[8] = { 0xE0, 0x03, 0x1F, 0xAA, 0xC0, 0x03, 0x5F, 0xD6 }; //🤔
typedef struct {
u32 hz = 0;
u32 volt = 0;
u32 unk[6] = {0};
s32 coeffs[6] = {0};
} gpu_clock_table_t;
constexpr u32 EmcFreqOffsets[2][30] = {
{ 0xD7C60, 0xD7C68, 0xD7C70, 0xD7C78, 0xD7C80, 0xD7C88, 0xD7C90, 0xD7C98, 0xD7CA0, 0xD7CA8, 0xE1800, 0xEEFA0, 0xF2478, 0xFE284, 0x10A304, 0x10D7DC, 0x110A40, 0x113CA4, 0x116F08, 0x11A16C, 0x11D3D0, 0x120634, 0x123898, 0x126AFC, 0x129D60, 0x12CFC4, 0x130228, 0x13BFE0, 0x140D00, 0x140D50, },
{ 0xE1810, 0xE6530, 0xE6580, 0xE6AB0, 0xE6AB8, 0xE6AC0, 0xE6AC8, 0xE6AD0, 0xE6AD8, 0xE6AE0, 0xE6AE8, 0xE6AF0, 0xE6AF8, 0xF0650, 0xFDDF0, 0x1012C8, 0x10D0D4, 0x119154, 0x11C62C, 0x11F890, 0x122AF4, 0x125D58, 0x128FBC, 0x12C220, 0x12F484, 0x1326E8, 0x13594C, 0x138BB0, 0x13BE14, 0x13F078, }
};
// RAM freqs to choose: 1731200, 1862400, 1996800, 2131200
constexpr u32 NewEmcFreq = 1862400;
// RAM overclock could be UNSTABLE on some RAM without bumping up voltage,
// and therefore show graphical glitches, hang randomly or even worse, corrupt your NAND
namespace Erista {
typedef struct {
u32 hz = 0;
u32 unk = 0;
u32 volt = 0;
u32 unk2[5] = {0};
s32 coeffs[6] = {0};
} cpu_clock_table_t;
/* CPU */
constexpr u32 CpuVoltageLimitOffsets[2][3] = {
{ 0xE1AC8, 0xE1AD4, 0xE37E4 },
{ 0xF0918, 0xF0924, 0xF2634 },
};
constexpr u32 NewCpuVoltageLimit = 1358;
static_assert(NewCpuVoltageLimit <= 1400);
constexpr u32 CpuTablesFreeSpace[2] = { 0xE3B78, 0xF29C8 };
constexpr cpu_clock_table_t NewCpuTables[] = {
{ 1887000, 0, 1240000, {}, { 5100873, -279186, 4747 } },
{ 1963500, 0, 1262000, {}, { 5100873, -279186, 4747 } },
{ 2091000, 0, 1298000, {}, { 5100873, -279186, 4747 } },
{ 2193000, 0, 1328000, {}, { 5100873, -279186, 4747 } },
{ 2295000, 0, 1358000, {}, { 5100873, -279186, 4747 } },
};
static_assert(sizeof(NewCpuTables) <= sizeof(cpu_clock_table_t)*16);
/* GPU */
constexpr u32 GpuTablesFreeSpace[2] = { 0xE2B58, 0xF19A8 };
constexpr gpu_clock_table_t NewGpuTables[] = {
{ 998400, 0, {}, { 1316991, 8144, -940, 808, -21583, 226 } },
{ 1075200, 0, {}, { 1358883, 8144, -940, 808, -21583, 226 } },
};
static_assert(sizeof(NewGpuTables) <= sizeof(gpu_clock_table_t)*20);
/* EMC */
constexpr u32 EmcVolatageOffsets[2][2] = {
{ 0x143998, 0x14399C },
{ 0x142878, 0x14287C },
};
constexpr u32 NewEmcVoltage = 1150000;
static_assert(NewEmcVoltage <= 1250000);
// 1150mV for 1862.4 MHz and 1200 mV for 2131.2 MHz, according to the feedback in RetroNX Discord
// 1125mV(HOS default) for 1731.2 MHz and 1175mV for 1996.8 MHz
};
namespace Mariko {
typedef struct {
u32 hz = 0;
u32 unk1 = 0;
s32 coeffs[6] = {0};
u32 volt = 0;
u32 unk3[5] = {0};
} cpu_clock_table_t;
/* CPU */
constexpr u32 CpuVoltageLimitOffsets[2][11] = {
{ 0xE1A8C, 0xE1A98, 0xE1AA4, 0xE1AB0, 0xE1AF8, 0xE1B04, 0xE1B10, 0xE1B1C, 0xE1B28, 0xE1B34, 0xE1F4C },
{ 0xF08DC, 0xF08E8, 0xF08F4, 0xF0900, 0xF0948, 0xF0954, 0xF0960, 0xF096C, 0xF0978, 0xF0984, 0xF0D9C },
};
constexpr u32 NewCpuVoltageLimit = 1220;
static_assert(NewCpuVoltageLimit <= 1300); //1300mV hangs for me
constexpr u32 CpuVoltageCoeffTable[2][10] = {
{ 0xE2140, 0xE2178, 0xE21B0, 0xE21E8, 0xE2220, 0xE2258, 0xE2290, 0xE22C8, 0xE2300, 0xE2338 },
{ 0xF0F90, 0xF0FC8, 0xF1000, 0xF1038, 0xF1070, 0xF10A8, 0xF10E0, 0xF1118, 0xF1150, 0xF1188 },
};
constexpr u32 NewCpuVoltageCoeff = NewCpuVoltageLimit * 1000;
constexpr u32 CpuTablesFreeSpace[2] = { 0xE2350, 0xF11A0 };
constexpr cpu_clock_table_t NewCpuTables[] = {
{2091000, 0, {1719782, -40440, 27}, NewCpuVoltageCoeff, {}},
{2193000, 0, {1809766, -41939, 27}, NewCpuVoltageCoeff, {}},
{2295000, 0, {1904458, -43439, 27}, NewCpuVoltageCoeff, {}},
{2397000, 0, {2004105, -44938, 27}, NewCpuVoltageCoeff, {}},
/*{2499000, 0, {2108966, -46437, 27}, NewCpuVoltageCoeff, {}},
{2601000, 0, {2219313, -47937, 27}, NewCpuVoltageCoeff, {}},
{2703000, 0, {2335434, -49436, 27}, NewCpuVoltageCoeff, {}},
{2805000, 0, {2457630, -50936, 27}, NewCpuVoltageCoeff, {}},
{2907000, 0, {2586221, -52435, 27}, NewCpuVoltageCoeff, {}},
{3009000, 0, {2721539, -53934, 27}, NewCpuVoltageCoeff, {}},*/
// calculated using linear regression:
// coeffs[0]=604531*exp(0.0000005*hz)
// coeffs[1]=-0.0147*hz-9702.1
};
static_assert(sizeof(NewCpuTables) <= sizeof(cpu_clock_table_t)*14);
constexpr u32 MaxCpuClockOffset[2] = { 0xE2740, 0xF1590 };
constexpr u32 NewMaxCpuClock = 2397000;
/* GPU */
constexpr u32 GpuTablesFreeSpace[2] = { 0xE3410, 0xF2260 };
constexpr gpu_clock_table_t NewGpuTables[] = {
{ 1305600, 0, {}, {1380113, -13465, -874, 0, 2580, 648} },
{ 1344000, 0, {}, {1420000, -14000, -870, 0, 2193, 824} },
/*{ 1382400, 0, {}, {1423200, -14188, -868, 0, 2150, 830} },
{ 1420800, 0, {}, {1426290, -14368, -860, 0, 2100, 850} },
{ 1305600, 0, {}, {1380113, -13465, -874, 0, 2580, 648} },
{ 1344000, 0, {}, {1420000, -14100, -870, 0, 2193, 824} },
{ 1382400, 0, {}, {1426290, -14368, -860, 0, 2100, 850} },
{ 1420800, 0, {}, {1450000, -14600, -860, 0, 2000, 850} },
{ 1382400, 0, {}, {1454061, -14500, -868, 0, 2000, 900} },
{ 1382400, 0, {}, {1474061, -15277, -866, 0, 1710, 1024} },
{ 1382400, 0, {}, {1500000, -15500, -880, 0, 1000, 548} },
{ 1420800, 0, {}, {1550000, -16500, -885, 0, 1500, 300} },*/
// some arbitrary coeffs I guessed and tested, YMMV
};
static_assert(sizeof(NewGpuTables) <= sizeof(gpu_clock_table_t)*15);
constexpr u32 Reg1MaxGpuOffset[2] = { 0x2E0AC, 0x3F6CC };
constexpr u8 Reg1NewMaxGpuClock[2][0xC] = {
// Original: 1267MHz
/*
MOV W13,#0x5600
MOVK W13,#0x13,LSL #16
NOP
*/
// Bump to 1536MHz
/*
MOV W13,#0x7000
MOVK W13,#0x17,LSL #16
NOP
*/
//0x0D, 0xC0, 0x8A, 0x52, 0x6D, 0x02, 0xA0, 0x72, 0x1F, 0x20, 0x03, 0xD5
{ 0x0D, 0x00, 0x8E, 0x52, 0xED, 0x02, 0xA0, 0x72, 0x1F, 0x20, 0x03, 0xD5 },
{ 0x0B, 0x00, 0x8E, 0x52, 0xEB, 0x02, 0xA0, 0x72, 0x1F, 0x20, 0x03, 0xD5 },
};
constexpr u32 Reg2MaxGpuOffset[2] = { 0x2E110, 0x3F730 };
constexpr u8 Reg2NewMaxGpuClock[2][0x8] = {
// Original: 1267MHz
/*
MOV W13,#0x5600
MOVK W13,#0x13,LSL #16
*/
// Bump to 1536MHz
/*
MOV W13,#0x7000
MOVK W13,#0x17,LSL #16
*/
//0x0D, 0xC0, 0x8A, 0x52, 0x6D, 0x02, 0xA0, 0x72
{ 0x0D, 0x00, 0x8E, 0x52, 0xED, 0x02, 0xA0, 0x72, },
{ 0x0B, 0x00, 0x8E, 0x52, 0xEB, 0x02, 0xA0, 0x72, },
};
/* EMC */
// Not available on Mariko
/*constexpr u32 EmcVolatageOffsets[2][2] = {
{
0x145FE4, //max77812_dram
0x144BA4, //max77812_dram
},
{
0x143A84,
0x144EC4,
}
};
constexpr u32 NewEmcVoltage = 650000;
static_assert(NewEmcVoltage <= 750000);*/
};
}
void ApplyPcvPatch(u8 *mapped_module, size_t mapped_size, int i) {
/* Add new CPU and GPU clock tables for Erista */
AMS_ABORT_UNLESS(Erista::CpuTablesFreeSpace[i] <= mapped_size && Erista::GpuTablesFreeSpace[i] <= mapped_size);
std::memcpy(mapped_module + Erista::CpuTablesFreeSpace[i], Erista::NewCpuTables, sizeof(Erista::NewCpuTables));
std::memcpy(mapped_module + Erista::GpuTablesFreeSpace[i], Erista::NewGpuTables, sizeof(Erista::NewGpuTables));
/* Patch max CPU voltage on Erista */
for(int j = 0; j < 3; j++) {
std::memcpy(mapped_module + Erista::CpuVoltageLimitOffsets[i][j], &Erista::NewCpuVoltageLimit, sizeof(Erista::NewCpuVoltageLimit));
}
/* Add new CPU and GPU clock tables for Mariko */
AMS_ABORT_UNLESS(Mariko::CpuTablesFreeSpace[i] <= mapped_size && Mariko::GpuTablesFreeSpace[i] <= mapped_size);
std::memcpy(mapped_module + Mariko::CpuTablesFreeSpace[i], Mariko::NewCpuTables, sizeof(Mariko::NewCpuTables));
std::memcpy(mapped_module + Mariko::GpuTablesFreeSpace[i], Mariko::NewGpuTables, sizeof(Mariko::NewGpuTables));
/* Patch Mariko max CPU and GPU clockrates */
AMS_ABORT_UNLESS(Mariko::MaxCpuClockOffset[i] <= mapped_size && Mariko::Reg1MaxGpuOffset[i] <= mapped_size && Mariko::Reg2MaxGpuOffset[i] <= mapped_size);
std::memcpy(mapped_module + Mariko::MaxCpuClockOffset[i], &Mariko::NewMaxCpuClock, sizeof(Mariko::NewMaxCpuClock));
std::memcpy(mapped_module + Mariko::Reg1MaxGpuOffset[i], Mariko::Reg1NewMaxGpuClock, sizeof(Mariko::Reg1NewMaxGpuClock[i]));
std::memcpy(mapped_module + Mariko::Reg2MaxGpuOffset[i], Mariko::Reg2NewMaxGpuClock, sizeof(Mariko::Reg2NewMaxGpuClock[i]));
/* Patch max cpu voltage on Mariko */
for(int j = 0; j < 11; j++) {
std::memcpy(mapped_module + Mariko::CpuVoltageLimitOffsets[i][j], &Mariko::NewCpuVoltageLimit, sizeof(Mariko::NewCpuVoltageLimit));
}
for(int j = 0; j < 10; j++) {
std::memcpy(mapped_module + Mariko::CpuVoltageCoeffTable[i][j], &Mariko::NewCpuVoltageCoeff, sizeof(Mariko::NewCpuVoltageCoeff));
}
/* Patch EMC clocks and voltage if enabled.
Note: On Erista, this requires removing or modifiying minerva */
if constexpr(EMC_OVERCLOCK) {
for(u32 j = 0; j < sizeof(EmcFreqOffsets[i])/sizeof(u32); j++) {
AMS_ABORT_UNLESS(EmcFreqOffsets[i][j] <= mapped_size);
std::memcpy(mapped_module + EmcFreqOffsets[i][j], &NewEmcFreq, sizeof(NewEmcFreq));
}
}
if constexpr(EMC_OVERVOLT) {
if(spl::GetSocType() == spl::SocType_Erista) {
for(u32 j = 0; j < sizeof(Erista::EmcVolatageOffsets[i])/sizeof(u32); j++) {
AMS_ABORT_UNLESS(Erista::EmcVolatageOffsets[i][j] <= mapped_size);
std::memcpy(mapped_module + Erista::EmcVolatageOffsets[i][j], &Erista::NewEmcVoltage, sizeof(Erista::NewEmcVoltage));
}
}
// Not available on Mariko
/*else if(spl::GetSocType() == spl::SocType_Mariko) {
for(u32 j = 0; j < sizeof(Mariko::EmcVolatageOffsets[i])/sizeof(u32); j++) {
AMS_ABORT_UNLESS(Mariko::EmcVolatageOffsets[i][j] <= mapped_size);
std::memcpy(mapped_module + Mariko::EmcVolatageOffsets[i][j], &Mariko::NewEmcVoltage, sizeof(Mariko::NewEmcVoltage));
}
}*/
}
return;
}
void ApplyCtestPatch(u8 *mapped_module, size_t mapped_size, int i) {
AMS_ABORT_UNLESS(CtestOffset[i] - 0x100 <= mapped_size);
std::memcpy(mapped_module + CtestOffset[i] - 0x100, BehemothPatch, sizeof(BehemothPatch));
}
void ApplyCopyrightPatch(u8 *mapped_module, size_t mapped_size, int i) {
AMS_ABORT_UNLESS(CopyrightOffset[i] - 0x100 <= mapped_size);
std::memcpy(mapped_module + CopyrightOffset[i] - 0x100, BehemothPatch, sizeof(BehemothPatch));
}
}

View File

@@ -0,0 +1,14 @@
// placed in Atmosphere/stratosphere/loader/source/
#pragma once
#include <stratosphere.hpp>
namespace ams::ldr {
void ApplyPcvPatch(u8 *mapped_module, size_t mapped_size, int i);
void ApplyCtestPatch(u8 *mapped_module, size_t mapped_size, int i);
void ApplyCopyrightPatch(u8 *mapped_module, size_t mapped_size, int i);
}

160
Source/Patch/12-ptm.pchtxt Normal file
View File

@@ -0,0 +1,160 @@
@nsobid-A79706954C6C45568B0FFE610627E2E89D8FB0D4
@flag offset_shift 0x100
// PTM PerformanceConfiguration Patch for 12.0.x
// Change all RAM freqs to 1862.4 MHz and Boost CPU freqs to 1963.5 MHz by default
// RAM
// 1731.2 MHz - 00043067
// 1862.4 MHz - 00F8016F
// 1996.8 MHz - 00C00477
// 2131.2 MHz - 0088077F
// CPU
// 1963.5 MHz - E0A10875
// 2295.0 MHz - C0EBCA88
// All values are Little-Endian
// See https://switchbrew.org/wiki/PTM_services#PerformanceConfiguration for details
// Use IPSwitch(https://github.com/3096/ipswitch/) to convert into ips patch
//0x00010000: 1020, 384.0, 1600.0
@enabled
000C5E14 00F7CB3C
000C5E18 00F7CB3C
000C5E1C 0060E316
000C5E20 0060E316
000C5E24 00F8016F
000C5E28 00F8016F
//0x00010001: 1020, 768.0, 1600.0
@enabled
000C5E34 00F7CB3C
000C5E38 00F7CB3C
000C5E3C 00C0C62D
000C5E40 00C0C62D
000C5E44 00F8016F
000C5E48 00F8016F
//0x00010002: 1224, 691.0, 1600.0
@enabled
000C5E54 00C2F448
000C5E58 00C2F448
000C5E5C 00E03229
000C5E60 00E03229
000C5E64 00F8016F
000C5E68 00F8016F
//0x00020000: 1020, 230.4, 1600.0
@enabled
000C5E74 00F7CB3C
000C5E78 00F7CB3C
000C5E7C 00A0BB0D
000C5E80 00A0BB0D
000C5E84 00F8016F
000C5E88 00F8016F
//0x00020001: 1020, 307.2, 1600.0
@enabled
000C5E94 00F7CB3C
000C5E98 00F7CB3C
000C5E9C 00804F12
000C5EA0 00804F12
000C5EA4 00F8016F
000C5EA8 00F8016F
//0x00020002: 1224, 230.4, 1600.0
@enabled
000C5EB4 00C2F448
000C5EB8 00C2F448
000C5EBC 00A0BB0D
000C5EC0 00A0BB0D
000C5EC4 00F8016F
000C5EC8 00F8016F
//0x00020003: 1020, 307.2, 1331.2
@enabled
000C5ED4 00F7CB3C
000C5ED8 00F7CB3C
000C5EDC 00804F12
000C5EE0 00804F12
000C5EE4 00F8016F
000C5EE8 00F8016F
//0x00020004: 1020, 384.0, 1331.2
@enabled
000C5EF4 00F7CB3C
000C5EF8 00F7CB3C
000C5EFC 0060E316
000C5F00 0060E316
000C5F04 00F8016F
000C5F08 00F8016F
//0x00020005: 1020, 307.0, 1065.6
@enabled
000C5F14 00F7CB3C
000C5F18 00F7CB3C
000C5F1C 00804F12
000C5F20 00804F12
000C5F24 00F8016F
000C5F28 00F8016F
//0x00020006: 1020, 384.0, 1065.6
@enabled
000C5F34 00F7CB3C
000C5F38 00F7CB3C
000C5F3C 0060E316
000C5F40 0060E316
000C5F44 00F8016F
000C5F48 00F8016F
//0x92220007: 1020, 460.0, 1600.0
@enabled
000C5F54 00F7CB3C
000C5F58 00F7CB3C
000C5F5C 0040771B
000C5F60 0040771B
000C5F64 00F8016F
000C5F68 00F8016F
//0x92220008: 1020, 460.0, 1331.2
@enabled
000C5F74 00F7CB3C
000C5F78 00F7CB3C
000C5F7C 0040771B
000C5F80 0040771B
000C5F84 00F8016F
000C5F88 00F8016F
//0x92220009: 1785, 76.8, 1600.0
@enabled
000C5F94 E0A10875
000C5F98 E0A10875
000C5F9C 00E09304
000C5FA0 00E09304
000C5FA4 00F8016F
000C5FA8 00F8016F
//0x9222000A: 1785, 76.8, 1331.2
@enabled
000C5FB4 E0A10875
000C5FB8 E0A10875
000C5FBC 00E09304
000C5FC0 00E09304
000C5FC4 00F8016F
000C5FC8 00F8016F
//0x9222000B: 1020, 76.8, 1600.0
@enabled
000C5FD4 00F7CB3C
000C5FD8 00F7CB3C
000C5FDC 00E09304
000C5FE0 00E09304
000C5FE4 00F8016F
000C5FE8 00F8016F
//0x9222000C: 1020, 76.8, 1331.2
@enabled
000C5FF4 00F7CB3C
000C5FF8 00F7CB3C
000C5FFC 00E09304
000C6000 00E09304
000C6004 00F8016F
000C6008 00F8016F

View File

@@ -0,0 +1,190 @@
diff --git a/.gitignore b/.gitignore
index 3e35c18..6b42bc5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,4 @@ build/
*.nacp
*.nro
+*.DS_Store
diff --git a/Overlay/libs/Atmosphere-libs b/Overlay/libs/Atmosphere-libs
index 2d522dc..bc08912 160000
--- a/Overlay/libs/Atmosphere-libs
+++ b/Overlay/libs/Atmosphere-libs
@@ -1 +1 @@
-Subproject commit 2d522dc6a12b2eb5eb3f103a8c5b5126ca301b1a
+Subproject commit bc08912dd31bb172467add8e24b4f0adac431939
diff --git a/Overlay/libs/libtesla b/Overlay/libs/libtesla
index 6628524..a5ce77d 160000
--- a/Overlay/libs/libtesla
+++ b/Overlay/libs/libtesla
@@ -1 +1 @@
-Subproject commit 66285245361a02e5480c7bb7dac9ef6449ae6181
+Subproject commit a5ce77d14f144a24c21684128ae79ef1e808734c
diff --git a/Overlay/source/main.cpp b/Overlay/source/main.cpp
index cec060c..7b7d8b1 100644
--- a/Overlay/source/main.cpp
+++ b/Overlay/source/main.cpp
@@ -2,8 +2,12 @@
#include <tesla.hpp> // The Tesla Header
#include "dmntcht.h"
+#define PROCESS_MANAGEMENT_QLAUNCH_TID 0x0100000000001000ULL
+
bool def = true;
+bool defChanged = false;
bool isDocked = false;
+bool isDockedChanged = false;
bool PluginRunning = false;
bool closed = false;
Handle debug;
@@ -17,6 +21,7 @@ bool dmntcht = false;
bool SaltySD = false;
bool bak = false;
bool plugin = false;
+bool sysclkComm = false;
char DockedChar[32];
char SystemChar[32];
char PluginChar[36];
@@ -54,6 +59,29 @@ bool isServiceRunning(const char *serviceName) {
}
}
+u64 GetCurrentApplicationId()
+{
+ // Copied from sys-clk
+ Result rc = 0;
+ std::uint64_t pid = 0;
+ std::uint64_t tid = 0;
+ rc = pmdmntGetApplicationProcessId(&pid);
+
+ if (rc == 0x20f)
+ {
+ return PROCESS_MANAGEMENT_QLAUNCH_TID;
+ }
+
+ rc = pminfoGetProgramId(&tid, pid);
+
+ if (rc == 0x20f)
+ {
+ return PROCESS_MANAGEMENT_QLAUNCH_TID;
+ }
+
+ return tid;
+}
+
class GuiTest : public tsl::Gui {
public:
GuiTest(u8 arg1, u8 arg2, bool arg3) { }
@@ -95,9 +123,10 @@ class GuiTest : public tsl::Gui {
if (MAGIC == 0x06BA7E39) {
auto *clickableListItem = new tsl::elm::ListItem("Change system control");
clickableListItem->setClickListener([](u64 keys) {
- if (keys & KEY_A) {
+ if (keys & HidNpadButton_A) {
if (PluginRunning == true) {
def = !def;
+ defChanged = true;
if (dmntcht == true) {
dmntchtWriteCheatProcessMemory(def_address, &def, 0x1);
dmntchtReadCheatProcessMemory(def_address, &def, 0x1);
@@ -120,9 +149,10 @@ class GuiTest : public tsl::Gui {
auto *clickableListItem2 = new tsl::elm::ListItem("Change mode");
clickableListItem2->setClickListener([](u64 keys) {
- if (keys & KEY_A) {
+ if (keys & HidNpadButton_A) {
if (PluginRunning == true && def == false) {
isDocked =! isDocked;
+ isDockedChanged = true;
if (dmntcht == true) {
dmntchtWriteCheatProcessMemory(docked_address, &isDocked, 0x1);
dmntchtReadCheatProcessMemory(docked_address, &isDocked, 0x1);
@@ -145,7 +175,7 @@ class GuiTest : public tsl::Gui {
else if (SaltySD == true && plugin == true && check == false) {
auto *clickableListItem = new tsl::elm::ListItem("(De)activate plugin");
clickableListItem->setClickListener([](u64 keys) {
- if (keys & KEY_A) {
+ if (keys & HidNpadButton_A) {
if (bak == false) {
rename("sdmc:/SaltySD/plugins/ReverseNX-RT.elf", "sdmc:/SaltySD/plugins/ReverseNX-RT.elf.bak");
bak = true;
@@ -185,6 +215,38 @@ class GuiTest : public tsl::Gui {
svcReadDebugProcessMemory(&isDocked, debug, docked_address, 0x1);
svcCloseHandle(debug);
}
+ if (sysclkComm && isDockedChanged && def == false && bak == false)
+ {
+ uint8_t sysclkConfArr[9];
+ u64 currentTID = GetCurrentApplicationId();
+ if (currentTID != PROCESS_MANAGEMENT_QLAUNCH_TID)
+ {
+ for(int i = 0; i < 8; i++) // TID to hex
+ sysclkConfArr[i] = currentTID >> 8*(7-i);
+ sysclkConfArr[8] = isDocked + 1;
+
+ FILE* sysclkConf = fopen("/config/sys-clk/ReverseNX-RT.conf", "wb+");
+ fwrite(sysclkConfArr, sizeof(sysclkConfArr), 1, sysclkConf);
+ fclose(sysclkConf);
+ }
+ isDockedChanged = false;
+ }
+ if (sysclkComm && defChanged && def == true && bak == false) // change from force mode to system-controlled mode
+ {
+ uint8_t sysclkConfArr[9];
+ u64 currentTID = GetCurrentApplicationId();
+ if (currentTID != PROCESS_MANAGEMENT_QLAUNCH_TID)
+ {
+ for(int i = 0; i < 8; i++) // TID to hex
+ sysclkConfArr[i] = currentTID >> 8*(7-i);
+ sysclkConfArr[8] = 3;
+
+ FILE* sysclkConf = fopen("/config/sys-clk/ReverseNX-RT.conf", "wb+");
+ fwrite(sysclkConfArr, sizeof(sysclkConfArr), 1, sysclkConf);
+ fclose(sysclkConf);
+ }
+ defChanged = false;
+ }
i = 0;
}
else i++;
@@ -202,7 +264,7 @@ class GuiTest : public tsl::Gui {
}
// Called once every frame to handle inputs not handled by other UI elements
- virtual bool handleInput(u64 keysDown, u64 keysHeld, touchPosition touchInput, JoystickPosition leftJoyStick, JoystickPosition rightJoyStick) override {
+ virtual bool handleInput(u64 keysDown, u64 keysHeld, const HidTouchState &touchPos, HidAnalogStickState joyStickPosLeft, HidAnalogStickState joyStickPosRight) override {
return false; // Return true here to singal the inputs have been consumed
}
};
@@ -213,6 +275,7 @@ class OverlayTest : public tsl::Overlay {
virtual void initServices() override {
smInitialize();
fsdevMountSdmc();
+ pminfoInitialize();
SaltySD = CheckPort();
if (SaltySD == false) return;
@@ -234,6 +297,14 @@ class OverlayTest : public tsl::Overlay {
else return;
}
+ // Check if sys-clk exist
+ temp = fopen("/atmosphere/contents/00FF0000636C6BFF/flags/boot2.flag", "r");
+ if (temp != NULL)
+ {
+ sysclkComm = true;
+ fclose(temp);
+ }
+
if (R_FAILED(pmdmntGetApplicationProcessId(&PID))) remove("sdmc:/SaltySD/ReverseNX-RT.hex");
else {
check = true;
@@ -284,6 +355,7 @@ class OverlayTest : public tsl::Overlay {
virtual void exitServices() override {
dmntchtExit();
if (dmntcht == false) svcCloseHandle(debug);
+ pminfoExit();
fsdevUnmountDevice("sdmc");
smExit();
} // Callet at the end to clean up all services previously initialized

997
Source/Patch/sys-clk.diff Normal file
View File

@@ -0,0 +1,997 @@
diff --git a/common/src/apm_profile_table.c b/common/src/apm_profile_table.c
index 7439ff1..19f5b68 100644
--- a/common/src/apm_profile_table.c
+++ b/common/src/apm_profile_table.c
@@ -23,8 +23,8 @@ SysClkApmConfiguration sysclk_g_apm_configurations[] = {
{0x00020006, 1020000000, 384000000, 1065600000},
{0x92220007, 1020000000, 460800000, 1600000000},
{0x92220008, 1020000000, 460800000, 1331200000},
- {0x92220009, 1785000000, 76800000, 1600000000},
- {0x9222000A, 1785000000, 76800000, 1331200000},
+ {0x92220009, 1963500000, 76800000, 1600000000},
+ {0x9222000A, 1963500000, 76800000, 1331200000},
{0x9222000B, 1020000000, 76800000, 1600000000},
{0x9222000C, 1020000000, 76800000, 1331200000},
{0, 0, 0, 0},
diff --git a/common/src/clock_table.c b/common/src/clock_table.c
index a8164dc..2765962 100644
--- a/common/src/clock_table.c
+++ b/common/src/clock_table.c
@@ -11,11 +11,15 @@
#include <stdint.h>
uint32_t sysclk_g_freq_table_mem_hz[] = {
- 665600000,
- 800000000,
- 1065600000,
+ //665600000,
+ //800000000,
+ //1065600000,
1331200000,
- 1600000000,
+ //1600000000,
+ 1731200000,
+ 1862400000,
+ 1996800000,
+ 2131200000,
0,
};
@@ -32,6 +36,12 @@ uint32_t sysclk_g_freq_table_cpu_hz[] = {
1581000000,
1683000000,
1785000000,
+ 1887000000,
+ 1963500000,
+ 2091000000,
+ 2193000000,
+ 2295000000,
+ 2397000000,
0,
};
@@ -48,5 +58,14 @@ uint32_t sysclk_g_freq_table_gpu_hz[] = {
768000000,
844800000,
921600000,
+ 998400000,
+ 1075200000,
+ 1152000000,
+ 1228800000,
+ 1267200000,
+ 1305600000,
+ 1344000000,
+ //1382400000,
+ //1420800000,
0,
};
diff --git a/manager/src/advanced_settings_tab.cpp b/manager/src/advanced_settings_tab.cpp
index 325d228..6d9725e 100644
--- a/manager/src/advanced_settings_tab.cpp
+++ b/manager/src/advanced_settings_tab.cpp
@@ -77,7 +77,7 @@ AdvancedSettingsTab::AdvancedSettingsTab()
});
// MEM
- brls::SelectListItem *memFreqListItem = createFreqListItem(SysClkModule_MEM, context.overrideFreqs[SysClkModule_MEM] / 1000000);
+ /*brls::SelectListItem *memFreqListItem = createFreqListItem(SysClkModule_MEM, context.overrideFreqs[SysClkModule_MEM] / 1000000);
memFreqListItem->getValueSelectedEvent()->subscribe([](int result)
{
Result rc = result == 0 ?
@@ -90,11 +90,11 @@ AdvancedSettingsTab::AdvancedSettingsTab()
errorResult(result == 0 ? "sysclkIpcRemoveOverride" : "sysclkIpcSetOverride", rc);
// TODO: Reset selected value
}
- });
+ });*/
this->addView(cpuFreqListItem);
this->addView(gpuFreqListItem);
- this->addView(memFreqListItem);
+ //this->addView(memFreqListItem);
// Config
this->addView(new brls::Header("Configuration"));
diff --git a/manager/src/app_profile_frame.cpp b/manager/src/app_profile_frame.cpp
index 4ad9545..0ea6af3 100644
--- a/manager/src/app_profile_frame.cpp
+++ b/manager/src/app_profile_frame.cpp
@@ -116,7 +116,7 @@ void AppProfileFrame::addFreqs(brls::List* list, SysClkProfile profile)
list->addView(gpuListItem);
// MEM
- brls::SelectListItem* memListItem = createFreqListItem(SysClkModule_MEM, this->profiles.mhzMap[profile][SysClkModule_MEM]);
+ /*brls::SelectListItem* memListItem = createFreqListItem(SysClkModule_MEM, this->profiles.mhzMap[profile][SysClkModule_MEM]);
this->profiles.mhzMap[profile][SysClkModule_MEM] *= 1000000;
@@ -126,7 +126,7 @@ void AppProfileFrame::addFreqs(brls::List* list, SysClkProfile profile)
brls::Logger::debug("Caching freq for module %d and profile %d to %" PRIu32, SysClkModule_MEM, profile, this->profiles.mhzMap[profile][SysClkModule_MEM]);
});
- list->addView(memListItem);
+ list->addView(memListItem);*/
}
void AppProfileFrame::onProfileChanged()
diff --git a/manager/src/cheat_sheet_tab.cpp b/manager/src/cheat_sheet_tab.cpp
index 6823e0e..08a91bf 100644
--- a/manager/src/cheat_sheet_tab.cpp
+++ b/manager/src/cheat_sheet_tab.cpp
@@ -19,6 +19,8 @@
*/
#include "cheat_sheet_tab.h"
+#include "ipc/client.h"
+#include "utils.h"
#include <borealis.hpp>
@@ -28,8 +30,9 @@ CheatSheetTab::CheatSheetTab()
this->addView(new brls::Header("CPU Clocks"));
brls::Table *cpuTable = new brls::Table();
- cpuTable->addRow(brls::TableRowType::BODY, "Maximum", "1785 MHz");
- cpuTable->addRow(brls::TableRowType::BODY, "Official Docked and Handheld", "1020 MHz");
+ cpuTable->addRow(brls::TableRowType::BODY, "OC Suite Maximum", "2397.0 MHz");
+ cpuTable->addRow(brls::TableRowType::BODY, "Official Boost", "1785.0 MHz");
+ cpuTable->addRow(brls::TableRowType::BODY, "Official Docked and Handheld", "1020.0 MHz");
this->addView(cpuTable);
@@ -37,10 +40,10 @@ CheatSheetTab::CheatSheetTab()
this->addView(new brls::Header("GPU Clocks"));
brls::Table *gpuTable = new brls::Table();
- gpuTable->addRow(brls::TableRowType::BODY, "Maximum", "921 MHz");
- gpuTable->addRow(brls::TableRowType::BODY, "Official Docked", "768 MHz");
- gpuTable->addRow(brls::TableRowType::BODY, "Maximum Handheld", "460 MHz");
- gpuTable->addRow(brls::TableRowType::BODY, "Official Handheld", "384 MHz");
+ gpuTable->addRow(brls::TableRowType::BODY, "OC Suite Maximum", "1344.0 MHz");
+ gpuTable->addRow(brls::TableRowType::BODY, "Official Maximum", "921.6 MHz");
+ gpuTable->addRow(brls::TableRowType::BODY, "Official Docked", "768.0 MHz");
+ gpuTable->addRow(brls::TableRowType::BODY, "Official Handheld", "384.0/460.8 MHz");
this->addView(gpuTable);
@@ -48,8 +51,20 @@ CheatSheetTab::CheatSheetTab()
this->addView(new brls::Header("MEM Clocks"));
brls::Table *memTable = new brls::Table();
- memTable->addRow(brls::TableRowType::BODY, "Maximum, Official Docked", "1600 MHz");
- memTable->addRow(brls::TableRowType::BODY, "Official Handheld", "1331 MHz");
+ // Get context
+ SysClkContext context;
+ Result rc = sysclkIpcGetCurrentContext(&context);
+
+ if (R_FAILED(rc))
+ {
+ brls::Logger::error("Unable to get context");
+ errorResult("sysclkIpcGetCurrentContext", rc);
+ brls::Application::crash("Could not get the current sys-clk context, please check that it is correctly installed and enabled.");
+ return;
+ }
+
+ memTable->addRow(brls::TableRowType::BODY, "OC Suite", formatFreq(context.freqs[SysClkModule_MEM]));
+ memTable->addRow(brls::TableRowType::BODY, "Official", "1331.2/1600.0 MHz");
this->addView(memTable);
}
diff --git a/overlay/src/ui/gui/app_profile_gui.cpp b/overlay/src/ui/gui/app_profile_gui.cpp
index 29adfe5..116c803 100644
--- a/overlay/src/ui/gui/app_profile_gui.cpp
+++ b/overlay/src/ui/gui/app_profile_gui.cpp
@@ -62,7 +62,7 @@ void AppProfileGui::addProfileUI(SysClkProfile profile)
this->listElement->addItem(new tsl::elm::CategoryHeader(sysclkFormatProfile(profile, true)));
this->addModuleListItem(profile, SysClkModule_CPU, &sysclk_g_freq_table_cpu_hz[0]);
this->addModuleListItem(profile, SysClkModule_GPU, &sysclk_g_freq_table_gpu_hz[0]);
- this->addModuleListItem(profile, SysClkModule_MEM, &sysclk_g_freq_table_mem_hz[0]);
+ //this->addModuleListItem(profile, SysClkModule_MEM, &sysclk_g_freq_table_mem_hz[0]);
}
void AppProfileGui::listUI()
diff --git a/overlay/src/ui/gui/global_override_gui.cpp b/overlay/src/ui/gui/global_override_gui.cpp
index 3ea98e4..91742b7 100644
--- a/overlay/src/ui/gui/global_override_gui.cpp
+++ b/overlay/src/ui/gui/global_override_gui.cpp
@@ -62,7 +62,7 @@ void GlobalOverrideGui::listUI()
{
this->addModuleListItem(SysClkModule_CPU, &sysclk_g_freq_table_cpu_hz[0]);
this->addModuleListItem(SysClkModule_GPU, &sysclk_g_freq_table_gpu_hz[0]);
- this->addModuleListItem(SysClkModule_MEM, &sysclk_g_freq_table_mem_hz[0]);
+ //this->addModuleListItem(SysClkModule_MEM, &sysclk_g_freq_table_mem_hz[0]);
}
void GlobalOverrideGui::refresh()
diff --git a/sysmodule/src/clock_manager.cpp b/sysmodule/src/clock_manager.cpp
index 46d7207..4139f34 100644
--- a/sysmodule/src/clock_manager.cpp
+++ b/sysmodule/src/clock_manager.cpp
@@ -8,10 +8,14 @@
* --------------------------------------------------------------------------
*/
+#define FORCE_ALL_HANDHELD_MODES_TO_USE_DOCK_CLOCK
+#include <nxExt.h>
+#include "errors.h"
#include "clock_manager.h"
#include "file_utils.h"
#include "clocks.h"
#include "process_management.h"
+#include <cstring>
ClockManager* ClockManager::instance = NULL;
@@ -59,6 +63,136 @@ ClockManager::~ClockManager()
delete this->context;
}
+bool ClockManager::IsCpuBoostMode()
+{
+ std::uint32_t confId = 0;
+ Result rc = 0;
+ rc = apmExtGetCurrentPerformanceConfiguration(&confId);
+ ASSERT_RESULT_OK(rc, "apmExtGetCurrentPerformanceConfiguration");
+ if(confId == 0x92220009 || confId == 0x9222000A)
+ return true;
+ else
+ return false;
+}
+
+SysClkProfile ClockManager::ReverseNXProfile(bool ForceDock)
+{
+ RealProfile = Clocks::GetCurrentProfile();
+ switch(RealProfile)
+ {
+ case SysClkProfile_HandheldChargingOfficial:
+#ifdef FORCE_ALL_HANDHELD_MODES_TO_USE_DOCK_CLOCK
+ case SysClkProfile_HandheldChargingUSB:
+ case SysClkProfile_HandheldCharging:
+ case SysClkProfile_Handheld:
+#endif
+ if (ForceDock)
+ return SysClkProfile_Docked;
+ else
+ return RealProfile;
+ case SysClkProfile_Docked:
+ if (ForceDock)
+ return SysClkProfile_Docked;
+ else
+ return FileUtils::IsDownclockDockEnabled() ? SysClkProfile_HandheldChargingOfficial : SysClkProfile_Docked;
+ default:
+ return RealProfile;
+ }
+}
+
+void ClockManager::checkReverseNXTool()
+{
+ char ReverseNXToolAsm[] = "_ZN2nn2oe18GetPerformanceModeEv.asm64"; // Checking one asm64 file is enough
+ char ReverseNXToolAsmPath[128];
+ uint8_t flag = 0;
+ snprintf(ReverseNXToolAsmPath, sizeof ReverseNXToolAsmPath, "/SaltySD/patches/%s", ReverseNXToolAsm);
+
+ FILE *readReverseNXToolAsm;
+ readReverseNXToolAsm = fopen(ReverseNXToolAsmPath, "rb");
+
+ // Enforce mode globally: Enabled
+ if(readReverseNXToolAsm != NULL)
+ {
+ checkReverseNXToolAsm(readReverseNXToolAsm, &flag);
+ switch(flag)
+ {
+ case 1:
+ FileUtils::LogLine("[mgr] ReverseNX-Tool patches detected: Enforce Handheld globally");
+ this->context->profile = ReverseNXProfile(false);
+ isDockedReverseNX = false;
+ isEnabledReverseNX = true;
+ isEnabledReverseNXTool = true;
+ break;
+ case 2:
+ FileUtils::LogLine("[mgr] ReverseNX-Tool patches detected: Enforce Docked globally");
+ this->context->profile = ReverseNXProfile(true);
+ isDockedReverseNX = true;
+ isEnabledReverseNX = true;
+ isEnabledReverseNXTool = true;
+ break;
+ }
+ }
+ else
+ {
+ snprintf(ReverseNXToolAsmPath, sizeof ReverseNXToolAsmPath, "/SaltySD/patches/%016lX/%s", this->context->applicationId, ReverseNXToolAsm);
+ readReverseNXToolAsm = fopen(ReverseNXToolAsmPath, "rb");
+ // Found game-specific setting
+ if(readReverseNXToolAsm != NULL)
+ {
+ checkReverseNXToolAsm(readReverseNXToolAsm, &flag);
+ switch(flag)
+ {
+ case 1:
+ FileUtils::LogLine("[mgr] ReverseNX-Tool patches detected: Force Handheld in %016lX", this->context->applicationId);
+ this->context->profile = ReverseNXProfile(false);
+ isDockedReverseNX = false;
+ isEnabledReverseNX = true;
+ isEnabledReverseNXTool = true;
+ break;
+ case 2:
+ FileUtils::LogLine("[mgr] ReverseNX-Tool patches detected: Force Docked in %016lX", this->context->applicationId);
+ this->context->profile = ReverseNXProfile(true);
+ isDockedReverseNX = true;
+ isEnabledReverseNX = true;
+ isEnabledReverseNXTool = true;
+ break;
+ default:
+ isEnabledReverseNXTool = false;
+ }
+ }
+ }
+}
+
+bool ClockManager::GameStartBoost()
+{
+ if (tickStartBoost && this->GetConfig()->Enabled())
+ {
+ if (Clocks::GetCurrentHz(SysClkModule_CPU) != MAX_CPU)
+ {
+ Clocks::SetHz(SysClkModule_CPU, MAX_CPU);
+ this->context->freqs[SysClkModule_CPU] = MAX_CPU;
+ }
+
+ std::uint64_t applicationId = ProcessManagement::GetCurrentApplicationId();
+ // If user exit the game
+ if (applicationId != this->context->applicationId)
+ {
+ tickStartBoost = 0;
+ return false;
+ }
+
+ if (tickStartBoost == 1)
+ {
+ FileUtils::LogLine("[mgr] Boost done, reset to stock");
+ Clocks::ResetToStock();
+ }
+ tickStartBoost--;
+ return true;
+ }
+
+ return false;
+}
+
void ClockManager::SetRunning(bool running)
{
this->running = running;
@@ -72,27 +206,75 @@ bool ClockManager::Running()
void ClockManager::Tick()
{
std::scoped_lock lock{this->contextMutex};
- if (this->RefreshContext() || this->config->Refresh())
+
+ if(!GameStartBoost())
{
- std::uint32_t hz = 0;
- for (unsigned int module = 0; module < SysClkModule_EnumMax; module++)
+ bool cpuBoost = FileUtils::IsBoostEnabled() ? IsCpuBoostMode() : false;
+ if (this->RefreshContext() || this->config->Refresh())
{
- hz = this->context->overrideFreqs[module];
-
- if(!hz)
+ std::uint32_t hz = 0;
+ std::uint32_t hzForceOverride = 0;
+ for (unsigned int module = 0; module < SysClkModule_EnumMax; module++)
{
- hz = this->config->GetAutoClockHz(this->context->applicationId, (SysClkModule)module, this->context->profile);
- }
+ hz = this->context->overrideFreqs[module];
- if (hz)
- {
- hz = Clocks::GetNearestHz((SysClkModule)module, this->context->profile, hz);
+ if(!hz)
+ {
+ hz = this->config->GetAutoClockHz(this->context->applicationId, (SysClkModule)module, this->context->profile);
+ hzForceOverride = this->config->GetAutoClockHz(0xA111111111111111, (SysClkModule)module, this->context->profile);
+ if (!hz && hzForceOverride)
+ hz = hzForceOverride;
- if (hz != this->context->freqs[module] && this->context->enabled)
+ if(isEnabledReverseNX && !hz)
+ {
+ switch(module)
+ {
+ case SysClkModule_CPU:
+ hz = 1020'000'000;
+ break;
+ case SysClkModule_GPU:
+ if (!isDockedReverseNX && ((FileUtils::IsDownclockDockEnabled() && RealProfile == SysClkProfile_Docked)
+ || RealProfile != SysClkProfile_Docked))
+ hz = 460'800'000;
+ else
+ hz = 768'000'000;
+ break;
+ }
+ }
+
+ }
+
+ if (hz)
{
- FileUtils::LogLine("[mgr] %s clock set : %u.%u Mhz", Clocks::GetModuleName((SysClkModule)module, true), hz/1000000, hz/100000 - hz/1000000*10);
- Clocks::SetHz((SysClkModule)module, hz);
- this->context->freqs[module] = hz;
+ hz = Clocks::GetNearestHz((SysClkModule)module, isEnabledReverseNX ? RealProfile : this->context->profile, hz);
+
+ if (hz != this->context->freqs[module] && this->context->enabled)
+ {
+ if (cpuBoost)
+ {
+ if (module == SysClkModule_CPU && hz < MAX_CPU)
+ {
+ hz = MAX_CPU;
+ FileUtils::LogLine("[mgr] CpuBoostMode detected, bump CPU to max");
+ }
+ }
+ FileUtils::LogLine("[mgr] %s clock set : %u.%u Mhz", Clocks::GetModuleName((SysClkModule)module, true), hz/1000000, hz/100000 - hz/1000000*10);
+ Clocks::SetHz((SysClkModule)module, hz);
+ this->context->freqs[module] = hz;
+ }
+ }
+ }
+ }
+ else if (FileUtils::IsBoostEnabled())
+ {
+ // If user doesn't set any freq but with sys-clk enabled, then boost CPU in CpuBoostMode
+ if(cpuBoost && this->GetConfig()->Enabled())
+ {
+ if(this->context->freqs[SysClkModule_CPU] != MAX_CPU)
+ {
+ FileUtils::LogLine("[mgr] CpuBoostMode detected, bump CPU to max");
+ Clocks::SetHz(SysClkModule_CPU, MAX_CPU);
+ this->context->freqs[SysClkModule_CPU] = MAX_CPU;
}
}
}
@@ -104,6 +286,56 @@ void ClockManager::WaitForNextTick()
svcSleepThread(this->GetConfig()->GetConfigValue(SysClkConfigValue_PollingIntervalMs) * 1000000ULL);
}
+void ClockManager::checkReverseNXToolAsm(FILE* readFile, uint8_t* flag)
+{
+ // Copied from ReverseNXTool
+ uint8_t Docked[0x10] = {0xE0, 0x03, 0x00, 0x32, 0xC0, 0x03, 0x5F, 0xD6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ uint8_t Handheld[0x10] = {0x00, 0x00, 0xA0, 0x52, 0xC0, 0x03, 0x5F, 0xD6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ uint8_t filebuffer[0x10] = {0};
+ uint8_t cmpresult = 0;
+ fread(&filebuffer, 1, 16, readFile);
+ cmpresult = memcmp(filebuffer, Docked, sizeof(Docked));
+ if (cmpresult != 0)
+ {
+ cmpresult = memcmp(filebuffer, Handheld, sizeof(Handheld));
+ if (cmpresult != 0)
+ *flag = 0; // Set to default
+ else
+ *flag = 1; // Handheld
+ }
+ else
+ *flag = 2; // Docked
+
+ fclose(readFile);
+}
+
+void ClockManager::checkReverseNXRT(bool recheckReverseNX, uint8_t* flag)
+{
+ FILE* readReverseNXRTConf = fopen(FILE_REVERSENX_RT_CONF_PATH, "rb");
+ if (readReverseNXRTConf != NULL)
+ {
+ uint8_t ReverseNXRTConfArr[9];
+ fread(ReverseNXRTConfArr, 9, 1, readReverseNXRTConf);
+ fclose(readReverseNXRTConf);
+ remove(FILE_REVERSENX_RT_CONF_PATH);
+
+ uint8_t currentTid[8];
+ for(int i = 0; i < 8; i++)
+ currentTid[i] = this->context->applicationId >> 8*(7-i);
+
+ uint8_t cmpresult = memcmp(currentTid, ReverseNXRTConfArr, sizeof(currentTid));
+
+ if (cmpresult == 0)
+ *flag = ReverseNXRTConfArr[8]; // 1: Handheld, 2: Docked, 3: Reset
+ else
+ *flag = 0; // 0: Not applicable
+ }
+ else if (recheckReverseNX)
+ *flag = prevReverseNXRT; // Use previous state when profile changes
+ else
+ *flag = 0;
+}
+
bool ClockManager::RefreshContext()
{
bool hasChanged = false;
@@ -120,21 +352,103 @@ bool ClockManager::RefreshContext()
if (applicationId != this->context->applicationId)
{
FileUtils::LogLine("[mgr] TitleID change: %016lX", applicationId);
+ prevReverseNXRT = 0; // Reset ReverseNX-RT previous state when Title ID changes
this->context->applicationId = applicationId;
hasChanged = true;
+
+ if (FileUtils::IsReverseNXEnabled() || recheckReverseNX)
+ {
+ // A new game starts or the real profile changes, then we need to check if ReverseNXTool patches are applied
+ isEnabledReverseNX = false;
+
+ // Check if ReverseNXTool patches are applied
+ if (applicationId != PROCESS_MANAGEMENT_QLAUNCH_TID)
+ this->checkReverseNXTool();
+ }
+
+ if (FileUtils::IsBoostStartEnabled() && this->context->applicationId != PROCESS_MANAGEMENT_QLAUNCH_TID)
+ {
+ // If a game starts and override for CPU clock is not enabled, then set MAX_CPU for 10 sec
+ std::uint32_t overcpu = this->context->overrideFreqs[SysClkModule_CPU];
+ if (!overcpu)
+ {
+ tickStartBoost = (std::uint32_t)( 10'000 / this->GetConfig()->GetConfigValue(SysClkConfigValue_PollingIntervalMs) ) + 1;
+ FileUtils::LogLine("[mgr] A game starts, bump CPU to max for 10 sec");
+ return true;
+ }
+ }
}
+ if (!tickCheckReverseNXRT || recheckReverseNX)
+ {
+ uint8_t flag = 0;
+ checkReverseNXRT(recheckReverseNX, &flag);
+
+ switch(flag)
+ {
+ case 1:
+ FileUtils::LogLine("[mgr] ReverseNX-RT detected: Enforce Handheld Mode");
+ this->context->profile = ReverseNXProfile(false);
+ prevReverseNXRT = flag;
+ isEnabledReverseNX = true;
+ isDockedReverseNX = false;
+ hasChanged = true;
+ break;
+ case 2:
+ FileUtils::LogLine("[mgr] ReverseNX-RT detected: Enforce Docked Mode");
+ this->context->profile = ReverseNXProfile(true);
+ prevReverseNXRT = flag;
+ isEnabledReverseNX = true;
+ isDockedReverseNX = true;
+ hasChanged = true;
+ break;
+ case 3:
+ FileUtils::LogLine("[mgr] ReverseNX-RT disabled: Reset to System-controlled Mode and recheck ReverseNX-Tool");
+ RealProfile = Clocks::GetCurrentProfile();
+ this->context->profile = RealProfile;
+ prevReverseNXRT = 0;
+ isEnabledReverseNX = false;
+ isDockedReverseNX = false;
+ hasChanged = true;
+ if (this->context->applicationId != PROCESS_MANAGEMENT_QLAUNCH_TID)
+ this->checkReverseNXTool();
+ break;
+ case 0:
+ if (recheckReverseNX && isEnabledReverseNXTool && this->context->applicationId != PROCESS_MANAGEMENT_QLAUNCH_TID)
+ this->checkReverseNXTool();
+ break;
+ }
+ // Check once per sec
+ tickCheckReverseNXRT = (std::uint32_t)( 1'000 / this->GetConfig()->GetConfigValue(SysClkConfigValue_PollingIntervalMs) ) + 1;
+ }
+ tickCheckReverseNXRT--;
+
+ if (recheckReverseNX)
+ recheckReverseNX = false;
+
SysClkProfile profile = Clocks::GetCurrentProfile();
- if (profile != this->context->profile)
+ if (profile != this->context->profile && !isEnabledReverseNX)
{
FileUtils::LogLine("[mgr] Profile change: %s", Clocks::GetProfileName(profile, true));
this->context->profile = profile;
hasChanged = true;
}
+ if (profile != RealProfile && isEnabledReverseNX)
+ {
+ FileUtils::LogLine("[mgr] Profile change: %s, recheck ReverseNX", Clocks::GetProfileName(profile, true));
+ this->context->profile = profile;
+ RealProfile = profile;
+ hasChanged = true;
+ recheckReverseNX = true;
+ }
// restore clocks to stock values on app or profile change
if(hasChanged)
{
+ if (profile == SysClkProfile_Handheld)
+ MAX_CPU = 1963'500'000;
+ else
+ MAX_CPU = 2295'000'000;
Clocks::ResetToStock();
}
@@ -142,7 +456,9 @@ bool ClockManager::RefreshContext()
for (unsigned int module = 0; module < SysClkModule_EnumMax; module++)
{
hz = Clocks::GetCurrentHz((SysClkModule)module);
- if (hz != 0 && hz != this->context->freqs[module])
+ uint32_t cur_mhz = hz/1000'000;
+ uint32_t be4_mhz = this->context->freqs[module]/1000'000;
+ if (hz != 0 && cur_mhz != be4_mhz)
{
FileUtils::LogLine("[mgr] %s clock change: %u.%u Mhz", Clocks::GetModuleName((SysClkModule)module, true), hz/1000000, hz/100000 - hz/1000000*10);
this->context->freqs[module] = hz;
diff --git a/sysmodule/src/clock_manager.h b/sysmodule/src/clock_manager.h
index 3eecb21..fd5dce2 100644
--- a/sysmodule/src/clock_manager.h
+++ b/sysmodule/src/clock_manager.h
@@ -20,14 +20,32 @@
class ClockManager
{
public:
+ std::uint32_t MAX_CPU = 1963500000;
+
static ClockManager* GetInstance();
static void Initialize();
static void Exit();
+ bool recheckReverseNX = false;
+ bool isEnabledReverseNX = false;
+ bool isEnabledReverseNXTool = false;
+ bool isDockedReverseNX = false;
+ std::uint16_t tickCheckReverseNXRT = 0;
+ std::uint16_t tickStartBoost = 0;
+ char prevReverseNXRT = 0;
+ SysClkProfile RealProfile;
+
+ bool IsCpuBoostMode();
+ SysClkProfile ReverseNXProfile(bool);
+ void checkReverseNXTool();
+ bool GameStartBoost();
+
void SetRunning(bool running);
bool Running();
void Tick();
void WaitForNextTick();
+ void checkReverseNXToolAsm(FILE*, uint8_t*);
+ void checkReverseNXRT(bool, uint8_t*);
SysClkContext GetCurrentContext();
Config* GetConfig();
diff --git a/sysmodule/src/clocks.cpp b/sysmodule/src/clocks.cpp
index 62ef40f..3ef7e15 100644
--- a/sysmodule/src/clocks.cpp
+++ b/sysmodule/src/clocks.cpp
@@ -12,6 +12,8 @@
#include "clocks.h"
#include "errors.h"
+bool Clocks::isMariko = false;
+
void Clocks::GetList(SysClkModule module, std::uint32_t **outClocks)
{
switch(module)
@@ -60,6 +62,26 @@ void Clocks::Initialize()
rc = tcInitialize();
ASSERT_RESULT_OK(rc, "tcInitialize");
}
+
+ // Check if it's Mariko
+ u64 hardware_type = 0;
+ splInitialize();
+ splGetConfig(SplConfigItem_HardwareType, &hardware_type);
+ splExit();
+
+ switch(hardware_type) {
+ case 0: //Icosa
+ case 1: //Copper
+ break;
+ case 2: //Hoag
+ case 3: //Iowa
+ case 4: //Calcio
+ case 5: //Aula
+ isMariko = true;
+ break;
+ default:
+ break;
+ }
}
void Clocks::Exit()
@@ -171,7 +193,8 @@ void Clocks::ResetToStock()
Clocks::SetHz(SysClkModule_CPU, apmConfiguration->cpu_hz);
Clocks::SetHz(SysClkModule_GPU, apmConfiguration->gpu_hz);
- Clocks::SetHz(SysClkModule_MEM, apmConfiguration->mem_hz);
+ // We don't need to set MEM freqs any more
+ //Clocks::SetHz(SysClkModule_MEM, apmConfiguration->mem_hz);
}
else
{
@@ -195,16 +218,16 @@ SysClkProfile Clocks::GetCurrentProfile()
return SysClkProfile_Docked;
}
- ChargerType chargerType;
+ PsmChargerType chargerType;
rc = psmGetChargerType(&chargerType);
ASSERT_RESULT_OK(rc, "psmGetChargerType");
- if(chargerType == ChargerType_Charger)
+ if(chargerType == PsmChargerType_EnoughPower)
{
return SysClkProfile_HandheldChargingOfficial;
}
- else if(chargerType == ChargerType_Usb)
+ else if(chargerType == PsmChargerType_LowPower || chargerType == PsmChargerType_NotSupported)
{
return SysClkProfile_HandheldChargingUSB;
}
@@ -214,6 +237,10 @@ SysClkProfile Clocks::GetCurrentProfile()
void Clocks::SetHz(SysClkModule module, std::uint32_t hz)
{
+ // We don't need to set MEM freqs any more
+ if (module == SysClkModule_MEM)
+ return;
+
Result rc = 0;
if(hosversionAtLeast(8,0,0))
@@ -222,7 +249,6 @@ void Clocks::SetHz(SysClkModule module, std::uint32_t hz)
rc = clkrstOpenSession(&session, Clocks::GetPcvModuleId(module), 3);
ASSERT_RESULT_OK(rc, "clkrstOpenSession");
-
rc = clkrstSetClockRate(&session, hz);
ASSERT_RESULT_OK(rc, "clkrstSetClockRate");
@@ -248,7 +274,7 @@ std::uint32_t Clocks::GetCurrentHz(SysClkModule module)
ASSERT_RESULT_OK(rc, "clkrstOpenSession");
rc = clkrstGetClockRate(&session, &hz);
- ASSERT_RESULT_OK(rc, "clkrstSetClockRate");
+ ASSERT_RESULT_OK(rc, "clkrstGetClockRate");
clkrstCloseSession(&session);
}
@@ -280,11 +306,11 @@ std::uint32_t Clocks::GetMaxAllowedHz(SysClkModule module, SysClkProfile profile
{
if(profile < SysClkProfile_HandheldCharging)
{
- return SYSCLK_GPU_HANDHELD_MAX_HZ;
+ return isMariko ? 1536000000 : SYSCLK_GPU_HANDHELD_MAX_HZ;
}
else if(profile <= SysClkProfile_HandheldChargingUSB)
{
- return SYSCLK_GPU_UNOFFICIAL_CHARGER_MAX_HZ;
+ return isMariko ? 1536000000 : SYSCLK_GPU_UNOFFICIAL_CHARGER_MAX_HZ;
}
}
@@ -293,6 +319,79 @@ std::uint32_t Clocks::GetMaxAllowedHz(SysClkModule module, SysClkProfile profile
std::uint32_t Clocks::GetNearestHz(SysClkModule module, std::uint32_t inHz)
{
+ // Hardcoded values to return, I don't know why it will bump to max when excessive OC
+ if(module == SysClkModule_MEM)
+ {
+ switch(inHz)
+ {
+ case 1331000000:
+ return 1331200000;
+ case 1731000000:
+ return 1731200000;
+ case 1862000000:
+ return 1862400000;
+ case 1996000000:
+ return 1996800000;
+ default:
+ return inHz;
+ }
+ }
+
+ if(module == SysClkModule_CPU)
+ {
+ switch(inHz)
+ {
+ case 1963000000:
+ return 1963500000;
+ default:
+ return inHz;
+ }
+ }
+
+ if(module == SysClkModule_GPU)
+ {
+ switch(inHz)
+ {
+ case 76000000:
+ return 76800000;
+ case 153000000:
+ return 153600000;
+ case 230000000:
+ return 230400000;
+ case 307000000:
+ return 307200000;
+ case 460000000:
+ return 460800000;
+ case 537000000:
+ return 537600000;
+ case 614000000:
+ return 614400000;
+ case 691000000:
+ return 691200000;
+ case 844000000:
+ return 844800000;
+ case 921000000:
+ return 921600000;
+ case 998000000:
+ return 998400000;
+ case 1075000000:
+ return 1075200000;
+ case 1228000000:
+ return 1228800000;
+ case 1267000000:
+ return 1267200000;
+ case 1305000000:
+ return 1305600000;
+ case 1382000000:
+ return 1382400000;
+ case 1420000000:
+ return 1420800000;
+ default:
+ return inHz;
+ }
+ }
+
+ return inHz;
std::uint32_t *clockTable = NULL;
GetList(module, &clockTable);
diff --git a/sysmodule/src/clocks.h b/sysmodule/src/clocks.h
index 7f86be8..5ff180b 100644
--- a/sysmodule/src/clocks.h
+++ b/sysmodule/src/clocks.h
@@ -16,6 +16,7 @@
class Clocks
{
public:
+ static bool isMariko;
static void Exit();
static void Initialize();
static void ResetToStock();
diff --git a/sysmodule/src/file_utils.cpp b/sysmodule/src/file_utils.cpp
index 5503f44..8f91a1a 100644
--- a/sysmodule/src/file_utils.cpp
+++ b/sysmodule/src/file_utils.cpp
@@ -9,12 +9,19 @@
*/
#include "file_utils.h"
+#include "clocks.h"
+#include <dirent.h>
+#include <filesystem>
#include <nxExt.h>
static LockableMutex g_log_mutex;
static LockableMutex g_csv_mutex;
static std::atomic_bool g_has_initialized = false;
static bool g_log_enabled = false;
+static bool g_boost_enabled = false;
+static bool g_boost_start_enabled = false;
+static bool g_downclock_dock_enabled = false;
+static bool g_reversenx_enabled = false;
static std::uint64_t g_last_flag_check = 0;
extern "C" void __libnx_init_time(void);
@@ -124,9 +131,55 @@ void FileUtils::RefreshFlags(bool force)
g_log_enabled = false;
}
+ // Only Enable Boost for Mariko
+ if (Clocks::isMariko)
+ {
+ file = fopen(FILE_BOOST_FLAG_PATH, "r");
+ if (file)
+ {
+ g_boost_enabled = true;
+ fclose(file);
+ } else {
+ g_boost_enabled = false;
+ }
+
+ file = fopen(FILE_BOOST_START_FLAG_PATH, "r");
+ if (file)
+ {
+ g_boost_start_enabled = true;
+ fclose(file);
+ } else {
+ g_boost_start_enabled = false;
+ }
+ }
+
+ file = fopen(FILE_DOWNCLOCK_DOCK_FLAG_PATH, "r");
+ if (file)
+ {
+ g_downclock_dock_enabled = true;
+ fclose(file);
+ } else {
+ g_downclock_dock_enabled = false;
+ }
+
g_last_flag_check = now;
}
+bool FileUtils::IsBoostEnabled()
+{
+ return g_boost_enabled;
+}
+
+bool FileUtils::IsBoostStartEnabled()
+{
+ return g_boost_start_enabled;
+}
+
+bool FileUtils::IsDownclockDockEnabled()
+{
+ return g_downclock_dock_enabled;
+}
+
void FileUtils::InitializeAsync()
{
Thread initThread = {0};
@@ -163,9 +216,23 @@ Result FileUtils::Initialize()
FileUtils::LogLine("=== " TARGET " " TARGET_VERSION " ===");
}
+ FILE *file = fopen(FILE_SALTYNX_PATH, "r");
+ if (file)
+ {
+ g_reversenx_enabled = true;
+ fclose(file);
+ } else {
+ g_reversenx_enabled = false;
+ }
+
return rc;
}
+bool FileUtils::IsReverseNXEnabled()
+{
+ return g_reversenx_enabled;
+}
+
void FileUtils::Exit()
{
if (!g_has_initialized)
diff --git a/sysmodule/src/file_utils.h b/sysmodule/src/file_utils.h
index 4f1642e..336e63b 100644
--- a/sysmodule/src/file_utils.h
+++ b/sysmodule/src/file_utils.h
@@ -22,6 +22,11 @@
#define FILE_CONTEXT_CSV_PATH FILE_CONFIG_DIR "/context.csv"
#define FILE_LOG_FLAG_PATH FILE_CONFIG_DIR "/log.flag"
#define FILE_LOG_FILE_PATH FILE_CONFIG_DIR "/log.txt"
+#define FILE_BOOST_FLAG_PATH FILE_CONFIG_DIR "/boost.flag"
+#define FILE_BOOST_START_FLAG_PATH FILE_CONFIG_DIR "/boost_start.flag"
+#define FILE_DOWNCLOCK_DOCK_FLAG_PATH FILE_CONFIG_DIR "/downclock_dock.flag"
+#define FILE_SALTYNX_PATH "/atmosphere/contents/0000000000534C56/flags/boot2.flag" // Just check for SaltyNX boot flag
+#define FILE_REVERSENX_RT_CONF_PATH FILE_CONFIG_DIR "/ReverseNX-RT.conf"
class FileUtils
{
@@ -30,6 +35,10 @@ class FileUtils
static Result Initialize();
static bool IsInitialized();
static bool IsLogEnabled();
+ static bool IsBoostEnabled();
+ static bool IsBoostStartEnabled();
+ static bool IsDownclockDockEnabled();
+ static bool IsReverseNXEnabled();
static void InitializeAsync();
static void LogLine(const char *format, ...);
static void WriteContextToCsv(const SysClkContext* context);