ldr: fix patch
This commit is contained in:
@@ -80,6 +80,9 @@ namespace ams::ldr::hoc::pcv {
|
|||||||
return ((ins1 ^ ins2) >> 24) == 0;
|
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) {
|
inline bool AsmComparePrologue(u32 ins1, u32 ins2, u32 ins3, u32 cmp1, u32 cmp2, u32 cmp3) {
|
||||||
constexpr u32 StpImmMask = ~((((1u << 7) - 1u) << 15));
|
constexpr u32 StpImmMask = ~((((1u << 7) - 1u) << 15));
|
||||||
|
|
||||||
|
|||||||
@@ -562,78 +562,46 @@ namespace ams::ldr::hoc::pcv::erista {
|
|||||||
// R_SUCCEED();
|
// 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) {
|
Result MemMtcTableAsm(u32 *ptr) {
|
||||||
constexpr u32 AddpOffset = 1;
|
constexpr s32 GoodAdrpOffset = -1;
|
||||||
constexpr u32 BrOffset = 9;
|
constexpr s32 GoodMovOffset = -7;
|
||||||
constexpr u32 MovOffset = 7;
|
constexpr s32 GoodBlOffset = 1;
|
||||||
if (matchCount) return 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. */
|
/* Ensure we don't dereference memory before nso start. */
|
||||||
R_UNLESS(ptr - BrOffset >= nsoStart, ldr::ResultInvalidMtcTablePattern());
|
R_UNLESS(ptr + GoodMovOffset >= nsoStart, ldr::ResultInvalidMtcTablePattern());
|
||||||
|
|
||||||
u32 adrp = *(ptr - AddpOffset);
|
|
||||||
R_UNLESS(AsmCompareAdrpNoImm(adrp, MtcAdrpAsm), 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. */
|
/* 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. */
|
/* The correct instructions will always be x0 since the mtcTable pointer is returned. */
|
||||||
|
|
||||||
/* Pray this does not break. */
|
/* Pray this does not break. */
|
||||||
u32 br = *(ptr - BrOffset);
|
u32 bl = *(ptr + GoodBlOffset);
|
||||||
bool oldFw = AsmCompareBrNoRd(br, MtcBrAsm);
|
R_UNLESS(AsmBlCompareOpcodeOnly(bl, MtcGoodBlOpcode), ldr::ResultInvalidMtcTablePattern()); // Should always pass
|
||||||
|
|
||||||
|
|
||||||
/* Pray this does not break either. */
|
/* Pray this does not break either. */
|
||||||
u32 mov = *(ptr - MovOffset);
|
u32 mov = *(ptr + GoodMovOffset);
|
||||||
R_UNLESS(asm_compare_no_rd(mov, MtcMovAsm), ldr::ResultInvalidMtcTablePattern());
|
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()), asm_get_rd(mov));
|
||||||
u32 movCountPatch = asm_set_rd(asm_set_imm16(MtcMovAsm, newEmcList.size()), movRd);
|
|
||||||
|
|
||||||
if (!oldFw) {
|
PATCH_OFFSET(ptr + GoodMovOffset, movCountPatch);
|
||||||
MemMtcTableNewFwAsm(ptr, movCountPatch, MovOffset);
|
|
||||||
R_SUCCEED();
|
|
||||||
}
|
|
||||||
|
|
||||||
PATCH_OFFSET(ptr - BrOffset, NopIns);
|
|
||||||
PATCH_OFFSET(ptr - MovOffset, movCountPatch);
|
|
||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
@@ -660,7 +628,7 @@ namespace ams::ldr::hoc::pcv::erista {
|
|||||||
{"MEM Freq Max", &MemFreqMax, 0, nullptr, EmcClkOSLimit },
|
{"MEM Freq Max", &MemFreqMax, 0, nullptr, EmcClkOSLimit },
|
||||||
{"MEM Freq PLLM", &MemFreqPllmLimit, 2, nullptr, EmcClkPllmLimit },
|
{"MEM Freq PLLM", &MemFreqPllmLimit, 2, nullptr, EmcClkPllmLimit },
|
||||||
{"MEM Volt", &MemVoltHandler, 2, nullptr, MemVoltHOS },
|
{"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)) {
|
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();
|
// ViewLog();
|
||||||
|
|
||||||
for (auto &entry : patches) {
|
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())) {
|
if (R_FAILED(entry.CheckResult())) {
|
||||||
ViewLog();
|
// ViewLog();
|
||||||
panic::SmcError(panic::Patch);
|
panic::SmcError(panic::Patch);
|
||||||
|
|
||||||
CRASH(entry.description);
|
CRASH(entry.description);
|
||||||
|
|||||||
@@ -151,7 +151,7 @@ namespace ams::ldr::hoc::pcv::erista {
|
|||||||
constexpr u32 MtcMovAsm = 0x52800148;
|
constexpr u32 MtcMovAsm = 0x52800148;
|
||||||
constexpr u32 MtcAdrpAsm = 0xD0000081;
|
constexpr u32 MtcAdrpAsm = 0xD0000081;
|
||||||
constexpr u32 MtcAddAsm = 0x91131821;
|
constexpr u32 MtcAddAsm = 0x91131821;
|
||||||
|
constexpr u32 MtcBlIns = 0x97ffae64;
|
||||||
ALWAYS_INLINE bool MemMtcGetGetTablePatternFn(u32 *ptr) {
|
ALWAYS_INLINE bool MemMtcGetGetTablePatternFn(u32 *ptr) {
|
||||||
/* This builds an address that gets returned, so the register must be x0 by convention. */
|
/* This builds an address that gets returned, so the register must be x0 by convention. */
|
||||||
return AsmCompareAddNoImm12(*ptr, MtcAddAsm);
|
return AsmCompareAddNoImm12(*ptr, MtcAddAsm);
|
||||||
|
|||||||
BIN
dist/atmosphere/contents/00FF0000636C6BFF/exefs.nsp
vendored
BIN
dist/atmosphere/contents/00FF0000636C6BFF/exefs.nsp
vendored
Binary file not shown.
BIN
dist/atmosphere/kips/hoc.kip
vendored
BIN
dist/atmosphere/kips/hoc.kip
vendored
Binary file not shown.
BIN
dist/switch/.overlays/horizon-oc-overlay.ovl
vendored
BIN
dist/switch/.overlays/horizon-oc-overlay.ovl
vendored
Binary file not shown.
Reference in New Issue
Block a user