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 171b46f8..53ff75d5 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_asm.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_asm.hpp @@ -80,6 +80,9 @@ namespace ams::ldr::hoc::pcv { return ((ins1 ^ ins2) >> 24) == 0; }; + inline auto AsmBlCompareOpcodeOnly = [](u32 ins1, u32 ins2) { + return ((ins1 ^ ins2) >> 26) == 0; + }; inline bool AsmComparePrologue(u32 ins1, u32 ins2, u32 ins3, u32 cmp1, u32 cmp2, u32 cmp3) { constexpr u32 StpImmMask = ~((((1u << 7) - 1u) << 15)); 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 52a8936a..4c77041f 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_erista.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_erista.cpp @@ -562,78 +562,46 @@ 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; + constexpr s32 GoodAdrpOffset = -1; + constexpr s32 GoodMovOffset = -7; + constexpr s32 GoodBlOffset = 1; + constexpr u32 MtcGoodBlOpcode = 0x97fe6cfc; + + constexpr u32 MtcBadBlOpcode0 = 0x97ffae64; // bl nn::pcv::GetHardwareType + constexpr u32 MtcBadBlOpcode1 = 0x940036d5; // bl nn::pcv::GetHardwareType + constexpr u32 MtcBadAdrpAsm = 0xd00000a1; // adrp x1, s_ModuleResetStatus_ + + constexpr s32 MtcBadBlOffset0 = 2; + constexpr s32 MtcBadBlOffset1 = -1; + constexpr s32 MtcBadAdrpOffset = 1; + /* Ensure we don't dereference memory before nso start. */ - R_UNLESS(ptr - BrOffset >= nsoStart, ldr::ResultInvalidMtcTablePattern()); - - u32 adrp = *(ptr - AddpOffset); - R_UNLESS(AsmCompareAdrpNoImm(adrp, MtcAdrpAsm), ldr::ResultInvalidMtcTablePattern()); + R_UNLESS(ptr + GoodMovOffset >= nsoStart, ldr::ResultInvalidMtcTablePattern()); + /* Check for GetHardwareType asm and skip if it is found */ + if(AsmCompareAdrpNoImm(*(ptr + MtcBadAdrpOffset), MtcBadAdrpAsm) && AsmBlCompareOpcodeOnly(*(ptr + MtcBadBlOffset0), MtcBadBlOpcode0) && AsmBlCompareOpcodeOnly(*(ptr + MtcBadBlOffset1), MtcBadBlOpcode1)) { + R_SKIP(); + } + + u32 adrp = *(ptr + GoodAdrpOffset); + R_UNLESS(AsmCompareAdrpNoImm(adrp, MtcAdrpAsm), ldr::ResultInvalidMtcTablePattern()); // Should always pass + /* We don't check for matching register because both registers must be x0 in order to pass the previous checks. */ /* The correct instructions will always be x0 since the mtcTable pointer is returned. */ /* Pray this does not break. */ - u32 br = *(ptr - BrOffset); - bool oldFw = AsmCompareBrNoRd(br, MtcBrAsm); + u32 bl = *(ptr + GoodBlOffset); + R_UNLESS(AsmBlCompareOpcodeOnly(bl, MtcGoodBlOpcode), ldr::ResultInvalidMtcTablePattern()); // Should always pass + /* Pray this does not break either. */ - u32 mov = *(ptr - MovOffset); + u32 mov = *(ptr + GoodMovOffset); R_UNLESS(asm_compare_no_rd(mov, MtcMovAsm), ldr::ResultInvalidMtcTablePattern()); - u8 movRd = asm_get_rd(mov); - u32 movCountPatch = asm_set_rd(asm_set_imm16(MtcMovAsm, newEmcList.size()), movRd); + u32 movCountPatch = asm_set_rd(asm_set_imm16(MtcMovAsm, newEmcList.size()), asm_get_rd(mov)); - if (!oldFw) { - MemMtcTableNewFwAsm(ptr, movCountPatch, MovOffset); - R_SUCCEED(); - } - - PATCH_OFFSET(ptr - BrOffset, NopIns); - PATCH_OFFSET(ptr - MovOffset, movCountPatch); + PATCH_OFFSET(ptr + GoodMovOffset, movCountPatch); R_SUCCEED(); } @@ -660,7 +628,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, 0, &MemMtcGetGetTablePatternFn }, + {"MEM Table Asm", &MemMtcTableAsm, 4, &MemMtcGetGetTablePatternFn }, }; for (uintptr_t ptr = mapped_nso; ptr <= mapped_nso + nso_size - sizeof(EristaMtcTable); ptr += sizeof(u32)) { @@ -675,9 +643,9 @@ namespace ams::ldr::hoc::pcv::erista { // ViewLog(); for (auto &entry : patches) { - Log("%s Count: %zu\n", entry.description, entry.patched_count); + LOGGING("%s Count: %zu\n", entry.description, entry.patched_count); if (R_FAILED(entry.CheckResult())) { - ViewLog(); + // 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 b38ebf08..147d884b 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_erista.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_erista.hpp @@ -151,7 +151,7 @@ namespace ams::ldr::hoc::pcv::erista { constexpr u32 MtcMovAsm = 0x52800148; constexpr u32 MtcAdrpAsm = 0xD0000081; constexpr u32 MtcAddAsm = 0x91131821; - + constexpr u32 MtcBlIns = 0x97ffae64; ALWAYS_INLINE bool MemMtcGetGetTablePatternFn(u32 *ptr) { /* This builds an address that gets returned, so the register must be x0 by convention. */ return AsmCompareAddNoImm12(*ptr, MtcAddAsm); diff --git a/dist/atmosphere/contents/00FF0000636C6BFF/exefs.nsp b/dist/atmosphere/contents/00FF0000636C6BFF/exefs.nsp index 3e25c109..3f4cbf14 100644 Binary files a/dist/atmosphere/contents/00FF0000636C6BFF/exefs.nsp and b/dist/atmosphere/contents/00FF0000636C6BFF/exefs.nsp differ diff --git a/dist/atmosphere/kips/hoc.kip b/dist/atmosphere/kips/hoc.kip index 7b93f65b..7b3ed225 100644 Binary files a/dist/atmosphere/kips/hoc.kip and b/dist/atmosphere/kips/hoc.kip differ diff --git a/dist/switch/.overlays/horizon-oc-overlay.ovl b/dist/switch/.overlays/horizon-oc-overlay.ovl index 4140e662..a946da1c 100644 Binary files a/dist/switch/.overlays/horizon-oc-overlay.ovl and b/dist/switch/.overlays/horizon-oc-overlay.ovl differ