diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/customize.cpp b/Source/Atmosphere/stratosphere/loader/source/oc/customize.cpp index b5dd65d1..f423bf6c 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/customize.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/customize.cpp @@ -36,7 +36,7 @@ volatile CustomizeTable C = { .hpMode = DISABLED, .commonEmcMemVolt = 1175000, /* LPDDR4(X) JEDEC Specification */ -.eristaEmcMaxClock = 1600000, /* Maximum HB-MGCH ram rating */ +.eristaEmcMaxClock = 1633000, /* Maximum HB-MGCH ram rating */ /* Available: 66MHz step rate, 100MHz step rate, 133MHz step rate and jedec. */ /* Jedec freqs are 1333MHz, 1600MHz, 1866MHz, 2133MHz, 2400MHz, 2666MHz, 2933MHz, 3200MHz. */ diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_asm.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_asm.hpp index e8f24261..c3681238 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_asm.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_asm.hpp @@ -24,7 +24,7 @@ namespace ams::ldr::hoc::pcv { - constexpr u32 NopIns = 0x1f2003d5; + constexpr u32 NopIns = 0xD503201F; template u32 *ScanAssembly(u32 *ptr, u32 scanLimit, u32 pattern, Compare comp) { @@ -71,11 +71,27 @@ namespace ams::ldr::hoc::pcv { return ((ins1 & ImmMask) ^ (ins2 & ImmMask)) == 0; }; - /* Csel (Conditional Select) */ - /* - SF | Op | S | | RM | Cond | 0 | 0 | Rn | Rd - 31 | 30 | 29 | 28 27 26 25 24 23 | 20 19 18 17 16 | 15 14 13 12 | 11 | 10 | 9 8 7 6 5 | 4 3 2 1 0 - */ + inline auto AsmCbzCompareOpcodeOnly = [](u32 ins1, u32 ins2) { + return ((ins1 ^ ins2) >> 24) == 0; + }; + + inline bool AsmComparePrologue(u32 ins1, u32 ins2, u32 ins3, u32 cmp1, u32 cmp2, u32 cmp3) { + constexpr u32 StpImmMask = ~((((1u << 7) - 1u) << 15)); + + bool firstMatch = (ins1 & StpImmMask) == (cmp1 & StpImmMask); + + constexpr u32 StpRegsImmMask = ~(((1u << 5) - 1u) |(((1u << 5) - 1u) << 10) | (((1u << 7) - 1u) << 15)); + + bool secondMatch = (ins2 & StpRegsImmMask) == (cmp2 & StpRegsImmMask); + + + constexpr u32 MovMask = ~((1u << 5) - 1u); + + bool thirdMatch = (ins3 & MovMask) == (cmp3 & MovMask); + + return firstMatch && secondMatch && thirdMatch; + } + inline auto AsmCompareCselNoReg = [](u32 ins1, u32 ins2) { constexpr u32 ClearReg = ~(((1 << 10) - 1) | (((1 << 5) - 1) << 16)); return ((ins1 & ClearReg) ^ (ins2 & ClearReg)) == 0; diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_erista.cpp b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_erista.cpp index 4c0e9a0e..52a8936a 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_erista.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_erista.cpp @@ -562,12 +562,51 @@ namespace ams::ldr::hoc::pcv::erista { // R_SUCCEED(); // } + u32 matchCount = 0; + Result MemMtcTableNewFwAsm(u32 *ptr, u32 movCountPatch, u32 MovOffset) { + (void) movCountPatch; + constexpr u32 MtcRetMtcAsm = 0x103CC640; + constexpr u32 MtcCbzAsm = 0xB4000073; + + u32 *retPtr = ScanAssembly(ptr, 5, MtcRetMtcAsm, AsmCompareAdrpNoImm); + R_UNLESS(retPtr != nullptr, ldr::ResultInvalidMtcTablePattern()); + + u32 cbz = *(ptr - MovOffset - 1); + R_UNLESS(AsmCbzCompareOpcodeOnly(cbz, MtcCbzAsm), ldr::ResultInvalidMtcTablePattern()); + R_UNLESS(*(ptr - MovOffset - 2) == 0x54000461, ldr::ResultInvalidMtcTablePattern()); + + bool success = false; + u32 offset = 0; + for (u32 i = 0; i < 40; ++i) { + success = AsmComparePrologue(*(ptr - i), *(ptr - i - 1), *(ptr - i - 2), 0x910003FD, 0xA9014FF4, 0xA9BE7BFD); + if (success) { + offset = i; + break; + } + } + + if (!success) { + R_THROW(ldr::ResultInvalidMtcTable()); + } + + ++matchCount; + u32 strAferMov = *(ptr - MovOffset + 1); + + memset(ptr - offset + 2, NopIns, 184); + PATCH_OFFSET(ptr - MovOffset, movCountPatch); + PATCH_OFFSET(ptr - MovOffset + 1, strAferMov); + + // for (u32 i = 0; i < 32; ++i) { + // Log("0x%08X\n", __builtin_bswap32(*(ptr - offset - 3 + i))); + // } + } + R_SUCCEED(); Result MemMtcTableAsm(u32 *ptr) { constexpr u32 AddpOffset = 1; constexpr u32 BrOffset = 9; constexpr u32 MovOffset = 7; - + if (matchCount) return 1; /* Ensure we don't dereference memory before nso start. */ R_UNLESS(ptr - BrOffset >= nsoStart, ldr::ResultInvalidMtcTablePattern()); @@ -579,7 +618,7 @@ namespace ams::ldr::hoc::pcv::erista { /* Pray this does not break. */ u32 br = *(ptr - BrOffset); - R_UNLESS(AsmCompareBrNoRd(br, MtcBrAsm), ldr::ResultInvalidMtcTablePattern()); + bool oldFw = AsmCompareBrNoRd(br, MtcBrAsm); /* Pray this does not break either. */ u32 mov = *(ptr - MovOffset); @@ -588,7 +627,12 @@ namespace ams::ldr::hoc::pcv::erista { u8 movRd = asm_get_rd(mov); u32 movCountPatch = asm_set_rd(asm_set_imm16(MtcMovAsm, newEmcList.size()), movRd); - PATCH_OFFSET(ptr - BrOffset, NopIns); + if (!oldFw) { + MemMtcTableNewFwAsm(ptr, movCountPatch, MovOffset); + R_SUCCEED(); + } + + PATCH_OFFSET(ptr - BrOffset, NopIns); PATCH_OFFSET(ptr - MovOffset, movCountPatch); R_SUCCEED(); @@ -616,7 +660,7 @@ namespace ams::ldr::hoc::pcv::erista { {"MEM Freq Max", &MemFreqMax, 0, nullptr, EmcClkOSLimit }, {"MEM Freq PLLM", &MemFreqPllmLimit, 2, nullptr, EmcClkPllmLimit }, {"MEM Volt", &MemVoltHandler, 2, nullptr, MemVoltHOS }, - {"MEM Table Asm", &MemMtcTableAsm, 1, &MemMtcGetGetTablePatternFn }, + {"MEM Table Asm", &MemMtcTableAsm, 0, &MemMtcGetGetTablePatternFn }, }; for (uintptr_t ptr = mapped_nso; ptr <= mapped_nso + nso_size - sizeof(EristaMtcTable); ptr += sizeof(u32)) { @@ -628,9 +672,12 @@ namespace ams::ldr::hoc::pcv::erista { } } + // ViewLog(); + for (auto &entry : patches) { - LOGGING("%s Count: %zu\n", entry.description, entry.patched_count); + Log("%s Count: %zu\n", entry.description, entry.patched_count); if (R_FAILED(entry.CheckResult())) { + ViewLog(); panic::SmcError(panic::Patch); CRASH(entry.description); diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_erista.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_erista.hpp index 7e2a7e5b..b38ebf08 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_erista.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_erista.hpp @@ -159,4 +159,4 @@ namespace ams::ldr::hoc::pcv::erista { void Patch(uintptr_t mapped_nso, size_t nso_size); -} +} \ No newline at end of file