#include "common.h" #include "gameCode.h" #include #include "patches/PatchHeap.h" #include "thumbInstructions.h" #include "SecureSysCallsUnusedSpaceLocator.h" #define THUMB_MOVS_R0_R1 THUMB_MOVS_REG(0, 1) #define THUMB_MOVS_R2_0 THUMB_MOVS_IMM(2, 0) static const u16 sSvcSoftResetPattern[] = { THUMB_SVC(0), THUMB_BX_LR }; static const u16 sSvcWaitByLoopPattern[] = { THUMB_SVC(3), THUMB_BX_LR }; static const u16 sSvcWaitIntrPattern[] = { THUMB_MOVS_R2_0, THUMB_SVC(4), THUMB_BX_LR }; static const u16 sSvcWaitVBlankIntrPattern[] = { THUMB_MOVS_R2_0, THUMB_SVC(5), THUMB_BX_LR }; static const u16 sSvcHaltPattern[] = { THUMB_SVC(6), THUMB_BX_LR }; static const u16 sSvcDivPattern[] = { THUMB_SVC(9), THUMB_BX_LR }; static const u16 sSvcDivRemPattern[] = { THUMB_SVC(9), THUMB_MOVS_R0_R1, THUMB_BX_LR }; static const u16 sSvcCpuSetPattern[] = { THUMB_SVC(0xB), THUMB_BX_LR }; static const u16 sSvcCpuSetFastPattern[] = { THUMB_SVC(0xC), THUMB_BX_LR }; static const u16 sSvcSqrtPattern[] = { THUMB_SVC(0xD), THUMB_BX_LR }; static const u16 sSvcGetCrc16Pattern[] = { THUMB_SVC(0xE), THUMB_BX_LR }; static const u16 sSvcIsMainMemExpandedPattern[] = { THUMB_SVC(0xF), THUMB_BX_LR }; static const u16 sSvcUnpackBitsPattern[] = { THUMB_SVC(0x10), THUMB_BX_LR }; static const u16 sSvcUncompressLz8Pattern[] = { THUMB_SVC(0x11), THUMB_BX_LR }; static const u16 sSvcUncompressLz16FromDevicePattern[] = { THUMB_SVC(0x12), THUMB_BX_LR }; static const u16 sSvcUncompressHuffmanFromDevicePattern[] = { THUMB_SVC(0x13), THUMB_BX_LR }; static const u16 sSvcUncompressRl8Pattern[] = { THUMB_SVC(0x14), THUMB_BX_LR }; static const u16 sSvcUncompressRl16FromDevicePattern[] = { THUMB_SVC(0x15), THUMB_BX_LR }; struct svc_pattern_t { const u16* pattern; u32 length; }; static const std::array sSvcPatterns { svc_pattern_t { sSvcSoftResetPattern, sizeof(sSvcSoftResetPattern) }, svc_pattern_t { sSvcWaitByLoopPattern, sizeof(sSvcWaitByLoopPattern) }, svc_pattern_t { sSvcWaitIntrPattern, sizeof(sSvcWaitIntrPattern) }, svc_pattern_t { sSvcWaitVBlankIntrPattern, sizeof(sSvcWaitVBlankIntrPattern) }, svc_pattern_t { sSvcHaltPattern, sizeof(sSvcHaltPattern) }, svc_pattern_t { sSvcDivPattern, sizeof(sSvcDivPattern) }, svc_pattern_t { sSvcDivRemPattern, sizeof(sSvcDivRemPattern) }, svc_pattern_t { sSvcCpuSetPattern, sizeof(sSvcCpuSetPattern) }, svc_pattern_t { sSvcCpuSetFastPattern, sizeof(sSvcCpuSetFastPattern) }, svc_pattern_t { sSvcSqrtPattern, sizeof(sSvcSqrtPattern) }, svc_pattern_t { sSvcGetCrc16Pattern, sizeof(sSvcGetCrc16Pattern) }, svc_pattern_t { sSvcIsMainMemExpandedPattern, sizeof(sSvcIsMainMemExpandedPattern) }, svc_pattern_t { sSvcUnpackBitsPattern, sizeof(sSvcUnpackBitsPattern) }, svc_pattern_t { sSvcUncompressLz8Pattern, sizeof(sSvcUncompressLz8Pattern) }, svc_pattern_t { sSvcUncompressLz16FromDevicePattern, sizeof(sSvcUncompressLz16FromDevicePattern) }, svc_pattern_t { sSvcUncompressHuffmanFromDevicePattern, sizeof(sSvcUncompressHuffmanFromDevicePattern) }, svc_pattern_t { sSvcUncompressRl8Pattern, sizeof(sSvcUncompressRl8Pattern) }, svc_pattern_t { sSvcUncompressRl16FromDevicePattern, sizeof(sSvcUncompressRl16FromDevicePattern) } }; const u16* SecureSysCallsUnusedSpaceLocator::FindPattern(const u16* data, u32 length, const u16* pattern, u32 patternLength) const { length >>= 1; patternLength >>= 1; for (u32 i = 0; i < length - patternLength; i++) { bool ok = true; for (u32 j = 0; j < patternLength; j++) { if (data[i + j] != pattern[j]) { ok = false; break; } } if (ok) return &data[i]; } return nullptr; } void SecureSysCallsUnusedSpaceLocator::FindUnusedSpace(const nds_header_ntr_t* romHeader, PatchHeap& patchHeap) const { if (romHeader->arm9RomOffset != 0x4000) return; u32 secureStart = romHeader->arm9LoadAddress; if (*(u32*)(secureStart + 0x800) == 0x4770DF00) { // secure area for development purposes has this area empty patchHeap.AddFreeSpace((void*)secureStart, 0x800); LOG_DEBUG("Added free space starting at 0x%x with size 0x%x\n", secureStart, 0x800); return; } std::array patternLocations; for (u32 i = 0; i < sSvcPatterns.size(); i++) { patternLocations[i].pattern = FindPattern((const u16*)secureStart, 0x800, sSvcPatterns[i].pattern, sSvcPatterns[i].length); patternLocations[i].length = sSvcPatterns[i].length; } std::qsort(patternLocations.begin(), patternLocations.size(), sizeof(svc_pattern_t), [](const void* a, const void* b) { const auto cmp = static_cast(a)->pattern <=> static_cast(b)->pattern; if (cmp < 0) { return -1; } if (cmp > 0) { return 1; } return 0; }); u32 current = secureStart; for (u32 i = 0; i < sSvcPatterns.size(); i++) { if (!patternLocations[i].pattern) continue; u32 freeSpaceEnd = (u32)patternLocations[i].pattern & ~3; if (current < freeSpaceEnd) { u32 freeSpace = freeSpaceEnd - current; patchHeap.AddFreeSpace((void*)current, freeSpace); LOG_DEBUG("Added free space starting at 0x%x with size 0x%x\n", current, freeSpace); } current = ((u32)patternLocations[i].pattern + patternLocations[i].length + 3) & ~3; } if (current < secureStart + 0x800) { u32 freeSpace = secureStart + 0x800 - current; patchHeap.AddFreeSpace((void*)current, freeSpace); LOG_DEBUG("Added free space starting at 0x%x with size 0x%x\n", current, freeSpace); } }