Files
pico-loader/arm9/source/SecureSysCallsUnusedSpaceLocator.cpp
2025-11-23 17:14:17 +01:00

137 lines
5.8 KiB
C++

#include "common.h"
#include "gameCode.h"
#include <algorithm>
#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<const svc_pattern_t, 18> 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<svc_pattern_t, sSvcPatterns.size()> 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<const svc_pattern_t*>(a)->pattern <=> static_cast<const svc_pattern_t*>(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);
}
}