diff --git a/README.md b/README.md index 383d3fe7..8880e441 100644 --- a/README.md +++ b/README.md @@ -146,9 +146,9 @@ This project will not be actively maintained or regularly updated along with Atm ### Patching sysmodules manually -This method is only served as reference. +This method is only served as reference as it could damage your MMC file system if not handled properly. -Patched sysmodules would be persistent until pcv or ptm was updated in new HOS (usually in `x.0.0`). +Patched sysmodules would be persistent until pcv or ptm was updated in new HOS (normally in `x.0.0`).
@@ -162,7 +162,7 @@ Patched sysmodules would be persistent until pcv or ptm was updated in new HOS ( 1. Dump `prod.keys` with Lockpick_RCM 2. Dump HOS firmware with TegraExplorer - 3. Configure and run `test.sh` in `/Source/Atmosphere/stratosphere/loader/source/oc/` to generate patched pcv & ptm + 3. Configure and run `test_patch.sh` to generate patched pcv & ptm sysmodules in nca 4. Replace nca in `SYSTEM:/Contents/registered/` with TegraExplorer 5. `ValidateAcidSignature()` should be stubbed to allow unsigned sysmodules to load (a.k.a. `loader_patch`) diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/Makefile b/Source/Atmosphere/stratosphere/loader/source/oc/Makefile index 754342a6..9496113d 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/Makefile +++ b/Source/Atmosphere/stratosphere/loader/source/oc/Makefile @@ -1,4 +1,4 @@ -export CC := g++-11 +export CC := g++ all: test diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/ldr_oc_suite.cpp b/Source/Atmosphere/stratosphere/loader/source/oc/ldr_oc_suite.cpp index 396059a6..8a560472 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/ldr_oc_suite.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/ldr_oc_suite.cpp @@ -28,33 +28,33 @@ namespace ams::ldr::oc { namespace pcv { Result MemPllmLimitHandler(u32* ptr) { clk_pll_param* entry = reinterpret_cast(ptr); - if (entry->max_0 != entry->max_1) - return ResultFailure(); + R_UNLESS(entry->max_0 == entry->max_1, ldr::ResultInvalidMemPllmEntry()); // Double the max clk simply u32 max_clk = entry->max_0 * 2; entry->max_0 = max_clk; entry->max_1 = max_clk; - return ResultSuccess(); + R_SUCCEED(); } template Result MtcOverwrite(M* des, M* src) { constexpr u32 mtc_magic = 0x5F43544D; - if (src->rev != mtc_magic) - return ResultFailure(); + R_UNLESS(src->rev == mtc_magic, ldr::ResultInvalidMtcMagic()); // Ignore params from dvfs_ver to clock_src; for (size_t offset = offsetof(M, clk_src_emc); offset < sizeof(M); offset += sizeof(u32)) { u32* src_ent = reinterpret_cast(reinterpret_cast(src) + offset); u32* des_ent = reinterpret_cast(reinterpret_cast(des) + offset); u32 src_val = *src_ent; - if (src_val != UINT32_MAX) { + + constexpr u32 ignore_val = UINT32_MAX; + if (src_val != ignore_val) { PatchOffset(des_ent, src_val); } } - return ResultSuccess(); + R_SUCCEED(); } } @@ -62,7 +62,7 @@ namespace ams::ldr::oc { constexpr u32 CpuClkOSLimit = 1785'000; constexpr u32 CpuClkOfficial = 1963'500; constexpr u32 CpuVoltOfficial = 1120; - constexpr u32 GpuClkOSLimit = 921'600; + // constexpr u32 GpuClkOSLimit = 921'600; constexpr u32 GpuClkOfficial = 1267'200; constexpr u32 MemClkOSLimit = 1600'000; constexpr u32 MemClkOSAlt = 1331'200; @@ -677,16 +677,13 @@ namespace ams::ldr::oc { } Result CpuClockVddHandler(u32* ptr) { - u32 value_1 = *(ptr + 2); - u32 value_2 = *(ptr + 12); - constexpr u32 pattern_1 = 0; - constexpr u32 pattern_2 = 1525000; - if (value_1 != pattern_1 || value_2 != pattern_2) - return ResultFailure(); + R_UNLESS(*(ptr + 2) == 0, ldr::ResultInvalidCpuClockVddEntry()); + R_UNLESS(*(ptr + 12) == 1525000, ldr::ResultInvalidCpuClockVddEntry()); if (C.marikoCpuMaxClock) PatchOffset(ptr, C.marikoCpuMaxClock); - return ResultSuccess(); + + R_SUCCEED(); } Result CpuDvfsHandler(u32* ptr, uintptr_t nso_end_offset) { @@ -696,21 +693,17 @@ namespace ams::ldr::oc { cpu_freq_cvb_table_t* entry_1020 = entry_204 + 8; uintptr_t entry_end_offset = reinterpret_cast(entry_free) + sizeof(NewCpuTables) - sizeof(u32); - if ( entry_end_offset >= nso_end_offset - || *(reinterpret_cast(entry_free)) != 0 - || *(reinterpret_cast(entry_204)) != 204'000 - || *(reinterpret_cast(entry_end_offset)) != 0 ) - { - return ResultFailure(); - } + R_UNLESS(entry_end_offset < nso_end_offset, ldr::ResultOutOfRange()); + R_UNLESS(*(reinterpret_cast(entry_free)) == 0, ldr::ResultInvalidCpuDvfs()); + R_UNLESS(*(reinterpret_cast(entry_204)) == 204'000, ldr::ResultInvalidCpuDvfs()); + R_UNLESS(*(reinterpret_cast(entry_end_offset)) == 0, ldr::ResultInvalidCpuDvfs()); if (C.marikoCpuMaxClock > CpuClkOfficial) std::memcpy(reinterpret_cast(entry_free), NewCpuTables, sizeof(NewCpuTables)); // Patch CPU max volt in CPU dvfs table cpu_freq_cvb_table_t* entry_current = entry_1020; - if (entry_current->cvb_pll_param.c0 != CpuVoltOfficial * 1000) - return ResultFailure(); + R_UNLESS(entry_current->cvb_pll_param.c0 == CpuVoltOfficial * 1000, ldr::ResultInvalidCpuDvfs()); if (C.marikoCpuMaxVolt) { while (entry_current->cvb_pll_param.c0 == CpuVoltOfficial * 1000) { @@ -719,7 +712,7 @@ namespace ams::ldr::oc { } } - return ResultSuccess(); + R_SUCCEED(); } Result GpuDvfsHandler(u32* ptr, uintptr_t nso_end_offset) { @@ -728,17 +721,15 @@ namespace ams::ldr::oc { gpu_cvb_pll_table_t* entry_76_8 = entry_free - 17; uintptr_t entry_end_offset = reinterpret_cast(entry_free) + sizeof(NewGpuTables) - sizeof(u32); - if ( entry_end_offset >= nso_end_offset - || *(reinterpret_cast(entry_free)) != 0 - || *(reinterpret_cast(entry_76_8)) != 76'800 - || *(reinterpret_cast(entry_end_offset)) != 0 ) - { - return ResultFailure(); - } + R_UNLESS(entry_end_offset < nso_end_offset, ldr::ResultOutOfRange()); + R_UNLESS(*(reinterpret_cast(entry_free)) == 0, ldr::ResultInvalidGpuDvfs()); + R_UNLESS(*(reinterpret_cast(entry_76_8)) == 76'800, ldr::ResultInvalidGpuDvfs()); + R_UNLESS(*(reinterpret_cast(entry_end_offset)) == 0, ldr::ResultInvalidGpuDvfs()); if (C.marikoGpuMaxClock > GpuClkOfficial) std::memcpy(reinterpret_cast(entry_free), NewGpuTables, sizeof(NewGpuTables)); - return ResultSuccess(); + + R_SUCCEED(); } Result CpuVoltRangeHandler(u32* ptr) { @@ -750,9 +741,9 @@ namespace ams::ldr::oc { case 610: if (C.marikoCpuMaxVolt) PatchOffset(ptr, C.marikoCpuMaxVolt); - return ResultSuccess(); + R_SUCCEED(); default: - return ResultFailure(); + R_THROW(ldr::ResultInvalidCpuMinVolt()); } } @@ -771,20 +762,19 @@ namespace ams::ldr::oc { PatchOffset(ptr_next, gpuMaxClockMarikoPattern[1] | reg_id); } - return ResultSuccess(); + R_SUCCEED(); } } - return ResultFailure(); + R_THROW(ldr::ResultInvalidGpuMaxClkPattern()); } Result MtcTableHandler(u32* ptr) { MarikoMtcTable* const mtc_table_max = reinterpret_cast(ptr - offsetof(MarikoMtcTable, rate_khz) / sizeof(u32)); MarikoMtcTable* const mtc_table_alt = mtc_table_max - 1; constexpr u32 mtc_mariko_rev = 3; - if ( mtc_table_max->rev != mtc_mariko_rev - || mtc_table_alt->rev != mtc_mariko_rev - || mtc_table_alt->rate_khz != MemClkOSAlt ) - return ResultFailure(); + R_UNLESS(mtc_table_max->rev == mtc_mariko_rev, ldr::ResultInvalidMtcTable()); + R_UNLESS(mtc_table_alt->rev == mtc_mariko_rev, ldr::ResultInvalidMtcTable()); + R_UNLESS(mtc_table_alt->rate_khz == MemClkOSAlt, ldr::ResultInvalidMtcTable()); MarikoMtcTable* const table = const_cast(C.marikoMtc); bool replace_entire_table = (C.mtcConf == ENTIRE_TABLE_MARIKO); @@ -797,7 +787,7 @@ namespace ams::ldr::oc { MtcTableAutoAdjust(mtc_table_max, mtc_table_alt); MtcPllmbDivHandler(mtc_table_max); std::memcpy(reinterpret_cast(mtc_table_alt), reinterpret_cast(table), sizeof(MarikoMtcTable)); - return ResultSuccess(); + R_SUCCEED(); } Result DvbTableHandler(u32* ptr) { @@ -805,11 +795,10 @@ namespace ams::ldr::oc { emc_dvb_dvfs_table_t* dvb_1331_entry = dvb_max_entry - 1; u32* dvb_1331_offset = reinterpret_cast(dvb_1331_entry); - if (*(dvb_1331_offset) != MemClkOSAlt) - return ResultFailure(); + R_UNLESS(*(dvb_1331_offset) == MemClkOSAlt, ldr::ResultInvalidDvbTable()); PatchOffset(dvb_1331_offset, MemClkOSLimit); - return ResultSuccess(); + R_SUCCEED(); } Result MemMaxClockHandler(u32* ptr) { @@ -821,26 +810,24 @@ namespace ams::ldr::oc { constexpr u32 mtc_min_volt = 1100; constexpr u32 dvb_entry_volt = 675; - Result rc = ResultSuccess(); - if (value_next == mtc_min_volt) { - rc = MtcTableHandler(ptr); + R_TRY(MtcTableHandler(ptr)); } else if (value_next2 == dvb_entry_volt) { - rc = DvbTableHandler(ptr); + R_TRY(DvbTableHandler(ptr)); } PatchOffset(ptr, C.marikoEmcMaxClock); - return rc; + R_SUCCEED(); } Result GpuPllLimitHandler(u32* ptr) { u32 value_next = *(ptr + 1); - if (value_next != 0) - return ResultFailure(); + R_UNLESS(value_next == 0, ldr::ResultInvalidGpuPllEntry()); + // Double the max clk simply u32 max_clk = *(ptr) * 2; PatchOffset(ptr, max_clk); - return ResultSuccess(); + R_SUCCEED(); } void Patch(uintptr_t mapped_nso, size_t nso_size) { @@ -922,14 +909,13 @@ namespace ams::ldr::oc { cnt[MEM_PLL_CLK], cnt[GPU_MAX_CLOCK]); - if ( cnt[CPU_CLOCK_VDD] != 1 - || cnt[CPU_TABLE] != 1 - || cnt[GPU_TABLE] != 1 - || cnt[CPU_MAX_VOLT] > 13 || !cnt[CPU_MAX_VOLT] - || cnt[MEM_CLOCK] == 0 - || cnt[GPU_PLL_CLK] != 1 - || cnt[MEM_PLL_CLK] != 2 - || cnt[GPU_MAX_CLOCK] != 2) + if (cnt[CPU_CLOCK_VDD] > 1 || + cnt[CPU_TABLE] > 1 || + cnt[GPU_TABLE] > 1 || + cnt[CPU_MAX_VOLT] > 13 || + cnt[GPU_PLL_CLK] > 1 || + cnt[MEM_PLL_CLK] > 2 || + cnt[GPU_MAX_CLOCK] > 2) { CRASH(); } @@ -974,18 +960,15 @@ namespace ams::ldr::oc { cpu_freq_cvb_table_t* entry_204 = entry_free - 16; uintptr_t entry_end_offset = reinterpret_cast(entry_free) + sizeof(NewCpuTables) - sizeof(u32); - if ( entry_end_offset >= nso_end_offset - || *(reinterpret_cast(entry_free)) != 0 - || *(reinterpret_cast(entry_204)) != 204'000 - || *(reinterpret_cast(entry_end_offset)) != 0 ) - { - return ResultFailure(); - } + R_UNLESS(entry_end_offset < nso_end_offset, ldr::ResultOutOfRange()); + R_UNLESS(*(reinterpret_cast(entry_free)) == 0, ldr::ResultInvalidCpuDvfs()); + R_UNLESS(*(reinterpret_cast(entry_204)) == 204'000, ldr::ResultInvalidCpuDvfs()); + R_UNLESS(*(reinterpret_cast(entry_end_offset)) == 0, ldr::ResultInvalidCpuDvfs()); if (C.eristaCpuOCEnable) std::memcpy(reinterpret_cast(entry_free), NewCpuTables, sizeof(NewCpuTables)); - return ResultSuccess(); + R_SUCCEED(); } Result CpuVoltRangeHandler(u32* ptr) { @@ -997,10 +980,10 @@ namespace ams::ldr::oc { case 810: if (C.eristaCpuMaxVolt) PatchOffset(ptr, C.eristaCpuMaxVolt); - return ResultSuccess(); + R_SUCCEED(); default: LOGGING("Invalid min voltage: %u @%p!", *(ptr-1), ptr-1); - return ResultFailure(); + R_THROW(ldr::ResultInvalidCpuMinVolt()); } } @@ -1012,21 +995,20 @@ namespace ams::ldr::oc { return MtcOverwrite(mtc_table_max, table); } - return ResultSuccess(); + R_SUCCEED(); } Result MemMaxClockHandler(u32* ptr) { u32 value_next = *(ptr + 1); constexpr u32 mtc_min_volt = 887; - Result rc = ResultSuccess(); - if (value_next == mtc_min_volt) { - rc = MtcTableHandler(ptr); - } + if (value_next == mtc_min_volt) + R_TRY(MtcTableHandler(ptr)); if (C.eristaEmcMaxClock > MemClkOSLimit) PatchOffset(ptr, C.eristaEmcMaxClock); - return rc; + + R_SUCCEED(); } Result MemVoltHandler(u32* ptr) { @@ -1035,10 +1017,11 @@ namespace ams::ldr::oc { constexpr u32 uv_step = 12'500; if (emc_uv % uv_step) emc_uv = emc_uv / uv_step * uv_step; + PatchOffset(ptr, emc_uv); } - return ResultSuccess(); + R_SUCCEED(); } void Patch(uintptr_t mapped_nso, size_t nso_size) { @@ -1099,11 +1082,9 @@ namespace ams::ldr::oc { cnt[MEM_VOLT], cnt[MEM_PLL_CLK]); - if ( cnt[CPU_CLOCK] != 1 - || cnt[CPU_MAX_VOLT] < 2 - || cnt[MEM_CLOCK] == 0 - || cnt[MEM_VOLT] != 2 - || cnt[MEM_PLL_CLK] != 2) + if (cnt[CPU_CLOCK] > 1 || + cnt[MEM_VOLT] > 2 || + cnt[MEM_PLL_CLK] > 2) { CRASH(); } @@ -1112,10 +1093,11 @@ namespace ams::ldr::oc { namespace pcv { void SafetyCheck() { - if ( C.custRev != CUST_REV - || C.marikoCpuMaxVolt >= 1300 - || C.eristaCpuMaxVolt >= 1400 - || (C.eristaEmcVolt && (C.eristaEmcVolt < 600'000 || C.eristaEmcVolt > 1250'000))) + if (C.custRev != CUST_REV || + C.marikoCpuMaxVolt >= 1300 || + C.eristaCpuMaxVolt >= 1400 || + (C.eristaEmcVolt && + (C.eristaEmcVolt < 600'000 || C.eristaEmcVolt > 1250'000))) { CRASH(); } diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/ldr_oc_suite.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/ldr_oc_suite.hpp index 9fab6bc5..149d1c88 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/ldr_oc_suite.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/ldr_oc_suite.hpp @@ -14,9 +14,30 @@ * along with this program. If not, see . */ #pragma once +#include "mtc_timing_table.hpp" #define CUST_REV 2 -#include "mtc_timing_table.hpp" + +#ifdef ATMOSPHERE_IS_STRATOSPHERE +#include +#define LOGGING(fmt, ...) ((void)0) +#endif + +#define CRASH() { AMS_ABORT(); __builtin_unreachable(); } + +namespace ams::ldr { + R_DEFINE_ERROR_RESULT(OutOfRange, 1000); + R_DEFINE_ERROR_RESULT(InvalidMemPllmEntry, 1001); + R_DEFINE_ERROR_RESULT(InvalidMtcMagic, 1002); + R_DEFINE_ERROR_RESULT(InvalidMtcTable, 1003); + R_DEFINE_ERROR_RESULT(InvalidDvbTable, 1004); + R_DEFINE_ERROR_RESULT(InvalidCpuClockVddEntry, 1005); + R_DEFINE_ERROR_RESULT(InvalidCpuDvfs, 1006); + R_DEFINE_ERROR_RESULT(InvalidCpuMinVolt, 1007); + R_DEFINE_ERROR_RESULT(InvalidGpuDvfs, 1008); + R_DEFINE_ERROR_RESULT(InvalidGpuMaxClkPattern, 1009); + R_DEFINE_ERROR_RESULT(InvalidGpuPllEntry, 1010); +} namespace ams::ldr::oc { enum MtcConfig { @@ -26,7 +47,7 @@ namespace ams::ldr::oc { ENTIRE_TABLE_MARIKO = 3, }; - typedef struct { + typedef struct CustomizeTable { u8 cust[4] = {'C', 'U', 'S', 'T'}; u16 custRev = CUST_REV; u16 mtcConf = AUTO_ADJ_MARIKO_SAFE; @@ -47,16 +68,8 @@ namespace ams::ldr::oc { inline void PatchOffset(u32* offset, u32 value) { *(offset) = value; } - inline Result ResultFailure() { return -1; } - - #ifdef ATMOSPHERE_IS_STRATOSPHERE - #define LOGGING(fmt, ...) ((void)0) - #endif - - #define CRASH() { AMS_ABORT(); __builtin_unreachable(); } - namespace pcv { - typedef struct { + typedef struct cvb_coefficients { s32 c0 = 0; s32 c1 = 0; s32 c2 = 0; @@ -65,24 +78,24 @@ namespace ams::ldr::oc { s32 c5 = 0; } cvb_coefficients; - typedef struct { + typedef struct cpu_freq_cvb_table_t { u64 freq; cvb_coefficients cvb_dfll_param; cvb_coefficients cvb_pll_param; // only c0 is reserved } cpu_freq_cvb_table_t; - typedef struct { + typedef struct gpu_cvb_pll_table_t { u64 freq; cvb_coefficients cvb_dfll_param; // empty, dfll clock source not selected cvb_coefficients cvb_pll_param; } gpu_cvb_pll_table_t; - typedef struct { + typedef struct emc_dvb_dvfs_table_t { u64 freq; s32 volt[4] = {0}; } emc_dvb_dvfs_table_t; - typedef struct { + typedef struct clk_pll_param { u32 max_0; u32 unk[5]; u32 max_1; diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/ldr_oc_suite_test.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/ldr_oc_suite_test.hpp index 2962772c..ea38dd4a 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/ldr_oc_suite_test.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/ldr_oc_suite_test.hpp @@ -11,12 +11,17 @@ typedef int32_t s32; typedef uint64_t u64; typedef int Result; -#define R_SUCCEEDED(arg) (arg == ResultSuccess()) -#define R_FAILED(arg) (!R_SUCCEEDED(arg)) -#define LOGGING(fmt, ...) { printf(fmt "\n\tin %s\n", ##__VA_ARGS__, __PRETTY_FUNCTION__); } -#define AMS_ABORT() { fprintf(stderr, "Failed in %s!\n", __PRETTY_FUNCTION__); exit(-1); } +#define R_SUCCEEDED(arg) (arg == 0) +#define R_FAILED(arg) (arg != 0) +#define LOGGING(fmt, ...) { printf(fmt "\n\tin %s\n", ##__VA_ARGS__, __PRETTY_FUNCTION__); } +#define AMS_ABORT() { fprintf(stderr, "Failed in %s!\n", __PRETTY_FUNCTION__); exit(-1); } +#define R_SUCCEED() { return 0; } +#define R_THROW(err) { return err; } +#define R_TRY(expr) { Result _rc = (expr); if (R_FAILED(_rc)) { return _rc; } } +#define R_UNLESS(expr, rc) { if (!(expr)) { return rc; } } -inline Result ResultSuccess() { return 0; } +#define R_DEFINE_ERROR_RESULT(name, rc) \ + inline Result Result##name() { return rc; } #include "ldr_oc_suite.hpp" diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/test.cpp b/Source/Atmosphere/stratosphere/loader/source/oc/test.cpp index 354243b2..039ffbae 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/test.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/test.cpp @@ -18,6 +18,7 @@ #include #include #include +#include namespace ams::ldr::oc { namespace pcv { diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/test.sh b/test_patch.sh similarity index 100% rename from Source/Atmosphere/stratosphere/loader/source/oc/test.sh rename to test_patch.sh