Merge remote-tracking branch 'origin/develop' into feature/homebrew-return-to-loader

This commit is contained in:
Gericom
2026-01-10 14:51:16 +01:00
9 changed files with 126 additions and 57 deletions

View File

@@ -39,6 +39,7 @@ void* Arm7Patcher::ApplyPatches(const LoaderPlatform* loaderPlatform) const
(romHeader->IsTwlRom()) ? twlRomHeader->arm7iSize : 0,
sdkVersion,
romHeader->gameCode,
romHeader->softwareVersion,
loaderPlatform
};
void* patchSpaceStart = nullptr;

View File

@@ -116,6 +116,7 @@ void Arm9Patcher::ApplyPatches(const LoaderPlatform* loaderPlatform, const ApLis
arm9iSize,
sdkVersion,
romHeader->gameCode,
romHeader->softwareVersion,
loaderPlatform
};
PatchCollection patchCollection;

View File

@@ -11,9 +11,9 @@ class PatchContext
{
public:
PatchContext(void* data, u32 dataSize, void* twlData, u32 twlDataSize,
SdkVersion sdkVersion, u32 gameCode, const LoaderPlatform* loaderPlatform)
SdkVersion sdkVersion, u32 gameCode, u8 gameRevision, const LoaderPlatform* loaderPlatform)
: _data(data), _dataSize(dataSize), _twlData(twlData), _twlDataSize(twlDataSize)
, _sdkVersion(sdkVersion), _gameCode(gameCode), _loaderPlatform(loaderPlatform) { }
, _sdkVersion(sdkVersion), _gameCode(gameCode), _gameRevision(gameRevision), _loaderPlatform(loaderPlatform) { }
/// @brief Tries to find the given \p pattern of the given \p byteLength in the ntr region.
/// @param pattern The pattern to find.
@@ -43,6 +43,10 @@ public:
/// @return The game code of the rom that is being patched.
constexpr u32 GetGameCode() const { return _gameCode; }
/// @brief Returns the game revision of the rom that is being patched.
/// @return The game revision of the rom that is being patched.
constexpr u8 GetGameRevision() const { return _gameRevision; }
/// @brief Returns the loader platform that should be used for the patches.
/// @return The loader platform that should be used for the patches.
constexpr const LoaderPlatform* GetLoaderPlatform() { return _loaderPlatform; }
@@ -54,6 +58,7 @@ private:
u32 _twlDataSize;
SdkVersion _sdkVersion;
u32 _gameCode;
u8 _gameRevision;
PatchHeap _patchHeap;
PatchCodeCollection _patchCodeCollection;

View File

@@ -6,6 +6,7 @@
#include "patches/arm9/RomOffsetToSdSectorPatchCode.h"
#include "patches/OffsetToSectorRemapPatchCode.h"
#include "patches/arm9/FixCp15Asm.h"
#include "gameCode.h"
#include "CardiReadCardPatchAsm.h"
#include "CardiReadCardPatch.h"
@@ -19,6 +20,7 @@ static const u32 sCARDiReadCardPatternSdk3027530Thumb[] = { 0xB082B5F8u, 0x90019
static const u32 sCARDiReadCardPatternSdk4002774[] = { 0xE92D4070u, 0xE59F40D0u, 0xE1A06000u, 0xE3A00C02u };
static const u32 sCARDiReadCardPatternSdk4017530[] = { 0xE92D4070u, 0xE59F40D8u, 0xE1A06000u, 0xE3A00C02u };
static const u32 sCARDiReadCardPatternSdk4017530Thumb[] = { 0xB082B5F8u, 0x90019000u, 0x90013020u, 0x69C24827u };
static const u32 sCARDiReadCardPatternSdk4027531ThumbInlined[] = { 0xB082B5F8u, 0x90019000u, 0x90013020u, 0x69C14841u };
static const u32 sCARDiReadCardPatternSdk4027539SpiritTracks[] = { 0xE92D4070u, 0xE59F40D4u, 0xE1A06000u, 0xE3A00C02u };
void CardiReadCardPatch::TryPattern(PatchContext& patchContext, const u32* pattern, u32 byteLength)
@@ -30,59 +32,71 @@ void CardiReadCardPatch::TryPattern(PatchContext& patchContext, const u32* patte
bool CardiReadCardPatch::FindPatchTarget(PatchContext& patchContext)
{
if (patchContext.GetSdkVersion() >= 0x4017530)
TryPattern(patchContext, sCARDiReadCardPatternSdk4017530, sizeof(sCARDiReadCardPatternSdk4017530));
else if (patchContext.GetSdkVersion() >= 0x4002774)
TryPattern(patchContext, sCARDiReadCardPatternSdk4002774, sizeof(sCARDiReadCardPatternSdk4002774));
if (patchContext.GetGameCode() == GAMECODE("A4VJ"))
{
// Shaberu! DS Oryouri Navi (Japan) has a spurious match
_foundPattern = sCARDiReadCardPatternUnknown;
_thumb = false;
_cardiReadCard = (u32*)(patchContext.GetGameRevision() == 0 ? 0x020DBD5C : 0x020DBD4C);
}
else
TryPattern(patchContext, sCARDiReadCardPatternSdk20029A7, sizeof(sCARDiReadCardPatternSdk20029A7));
if (!_cardiReadCard)
{
if (patchContext.GetSdkVersion() >= 0x4017530)
TryPattern(patchContext, sCARDiReadCardPatternSdk4017530Thumb, sizeof(sCARDiReadCardPatternSdk4017530Thumb));
else if (patchContext.GetSdkVersion() >= 0x3027530)
TryPattern(patchContext, sCARDiReadCardPatternSdk3027530Thumb, sizeof(sCARDiReadCardPatternSdk3027530Thumb));
else if (patchContext.GetSdkVersion() >= 0x2004F4C)
TryPattern(patchContext, sCARDiReadCardPatternSdk2004F4CThumb, sizeof(sCARDiReadCardPatternSdk2004F4CThumb));
if (_cardiReadCard)
_thumb = true;
}
if (!_cardiReadCard)
{
// if still nothing found try some of the patterns that appear all over the place
TryPattern(patchContext, sCARDiReadCardPatternUnknown, sizeof(sCARDiReadCardPatternUnknown));
if (!_cardiReadCard)
TryPattern(patchContext, sCARDiReadCardPatternSdk4017530, sizeof(sCARDiReadCardPatternSdk4017530));
else if (patchContext.GetSdkVersion() >= 0x4002774)
TryPattern(patchContext, sCARDiReadCardPatternSdk4002774, sizeof(sCARDiReadCardPatternSdk4002774));
if (!_cardiReadCard)
else
TryPattern(patchContext, sCARDiReadCardPatternSdk20029A7, sizeof(sCARDiReadCardPatternSdk20029A7));
if (patchContext.GetSdkVersion().GetMajor() >= SDK_VERSION_MAJOR_NITRO_4)
if (!_cardiReadCard)
{
if (!_cardiReadCard)
TryPattern(patchContext, sCARDiReadCardPatternSdk4027539SpiritTracks, sizeof(sCARDiReadCardPatternSdk4027539SpiritTracks));
if (patchContext.GetSdkVersion() >= 0x4017530)
TryPattern(patchContext, sCARDiReadCardPatternSdk4017530Thumb, sizeof(sCARDiReadCardPatternSdk4017530Thumb));
else if (patchContext.GetSdkVersion() >= 0x3027530)
TryPattern(patchContext, sCARDiReadCardPatternSdk3027530Thumb, sizeof(sCARDiReadCardPatternSdk3027530Thumb));
else if (patchContext.GetSdkVersion() >= 0x2004F4C)
TryPattern(patchContext, sCARDiReadCardPatternSdk2004F4CThumb, sizeof(sCARDiReadCardPatternSdk2004F4CThumb));
if (_cardiReadCard)
_thumb = true;
}
if (patchContext.GetSdkVersion().GetMajor() <= SDK_VERSION_MAJOR_NITRO_2)
if (!_cardiReadCard)
{
// if still nothing found try some of the patterns that appear all over the place
TryPattern(patchContext, sCARDiReadCardPatternUnknown, sizeof(sCARDiReadCardPatternUnknown));
if (!_cardiReadCard)
TryPattern(patchContext, sCARDiReadCardPatternSdk2004F4DDebug, sizeof(sCARDiReadCardPatternSdk2004F4DDebug));
TryPattern(patchContext, sCARDiReadCardPatternSdk4002774, sizeof(sCARDiReadCardPatternSdk4002774));
if (!_cardiReadCard)
TryPattern(patchContext, sCARDiReadCardPatternSdk2004E8BPingPals, sizeof(sCARDiReadCardPatternSdk2004E8BPingPals));
TryPattern(patchContext, sCARDiReadCardPatternSdk20029A7, sizeof(sCARDiReadCardPatternSdk20029A7));
if (patchContext.GetSdkVersion().GetMajor() >= SDK_VERSION_MAJOR_NITRO_4)
{
if (!_cardiReadCard)
TryPattern(patchContext, sCARDiReadCardPatternSdk4027539SpiritTracks, sizeof(sCARDiReadCardPatternSdk4027539SpiritTracks));
}
if (patchContext.GetSdkVersion().GetMajor() <= SDK_VERSION_MAJOR_NITRO_2)
{
if (!_cardiReadCard)
TryPattern(patchContext, sCARDiReadCardPatternSdk2004F4DDebug, sizeof(sCARDiReadCardPatternSdk2004F4DDebug));
if (!_cardiReadCard)
TryPattern(patchContext, sCARDiReadCardPatternSdk2004E8BPingPals, sizeof(sCARDiReadCardPatternSdk2004E8BPingPals));
}
}
}
if (!_cardiReadCard)
{
TryPattern(patchContext, sCARDiReadCardPatternSdk2004F4CThumb, sizeof(sCARDiReadCardPatternSdk2004F4CThumb));
if (!_cardiReadCard)
TryPattern(patchContext, sCARDiReadCardPatternSdk3027530Thumb, sizeof(sCARDiReadCardPatternSdk3027530Thumb));
if (!_cardiReadCard)
TryPattern(patchContext, sCARDiReadCardPatternSdk2027533ThumbChouSoujuu, sizeof(sCARDiReadCardPatternSdk2027533ThumbChouSoujuu));
{
TryPattern(patchContext, sCARDiReadCardPatternSdk2004F4CThumb, sizeof(sCARDiReadCardPatternSdk2004F4CThumb));
if (!_cardiReadCard)
TryPattern(patchContext, sCARDiReadCardPatternSdk3027530Thumb, sizeof(sCARDiReadCardPatternSdk3027530Thumb));
if (!_cardiReadCard)
TryPattern(patchContext, sCARDiReadCardPatternSdk2027533ThumbChouSoujuu, sizeof(sCARDiReadCardPatternSdk2027533ThumbChouSoujuu));
if (!_cardiReadCard)
TryPattern(patchContext, sCARDiReadCardPatternSdk4027531ThumbInlined, sizeof(sCARDiReadCardPatternSdk4027531ThumbInlined));
if (_cardiReadCard)
_thumb = true;
if (_cardiReadCard)
_thumb = true;
}
}
if (_cardiReadCard)
@@ -142,42 +156,53 @@ void CardiReadCardPatch::ApplyPatch(PatchContext& patchContext)
if (_thumb)
{
u32 patchOffset;
u32 cardiCommonOffset;
if (_foundPattern == sCARDiReadCardPatternSdk4017530Thumb)
{
patchOffset = 0x36;
cardiCommonOffset = 0x74;
patch_cardireadcard_return_offset = THUMB_MOVS_IMM(THUMB_R0, 0x3C);
patch_cardireadcard_mov_src_to_r0 = THUMB_MOVS_REG(THUMB_R0, THUMB_R1); // src
patch_cardireadcard_mov_dst_to_r1 = THUMB_MOVS_REG(THUMB_R1, THUMB_R4); // dst
patch_cardireadcard_mov_cardicommon_to_r6 = THUMB_LDR_SP_IMM(THUMB_R6, 0);
patch_cardireadcard_mov_cardicommon_to_r6 = THUMB_LDR_SP_IMM(THUMB_R6, 8); // r3 from the stack
patch_cardireadcard_adjust_cardicommon_offset = THUMB_NOP;
patch_cardireadcard_mov_r3_to_dst = THUMB_STR_SP_IMM(THUMB_R3, 4);
patch_cardireadcard_mov_r3_to_dst = THUMB_STR_SP_IMM(THUMB_R3, 0xC); // copy to r4 on the stack
*(u16*)((u8*)_cardiReadCard + patchOffset + 0) = THUMB_LDR_PC_IMM(THUMB_R3, 0x74); // ldr r3,= cardi_common
}
else if (_foundPattern == sCARDiReadCardPatternSdk3027530Thumb)
{
patchOffset = 0x36;
cardiCommonOffset = 0x6C;
patch_cardireadcard_return_offset = THUMB_MOVS_IMM(THUMB_R0, 0x36);
patch_cardireadcard_mov_src_to_r0 = THUMB_MOVS_REG(THUMB_R0, THUMB_R1); // src
patch_cardireadcard_mov_dst_to_r1 = THUMB_MOVS_REG(THUMB_R1, THUMB_R4); // dst
patch_cardireadcard_mov_cardicommon_to_r6 = THUMB_LDR_SP_IMM(THUMB_R6, 0);
patch_cardireadcard_mov_cardicommon_to_r6 = THUMB_LDR_SP_IMM(THUMB_R6, 8); // r3 from the stack
patch_cardireadcard_adjust_cardicommon_offset = THUMB_NOP;
patch_cardireadcard_mov_r3_to_dst = THUMB_STR_SP_IMM(THUMB_R3, 4);
patch_cardireadcard_mov_r3_to_dst = THUMB_STR_SP_IMM(THUMB_R3, 0xC); // copy to r4 on the stack
*(u16*)((u8*)_cardiReadCard + patchOffset + 0) = THUMB_LDR_PC_IMM(THUMB_R3, 0x6C); // ldr r3,= cardi_common
}
else if (_foundPattern == sCARDiReadCardPatternSdk2004F4CThumb)
{
patchOffset = 0x36;
cardiCommonOffset = 0;
patch_cardireadcard_return_offset = THUMB_MOVS_IMM(THUMB_R0, 0x2E);
patch_cardireadcard_mov_src_to_r0 = THUMB_MOVS_REG(THUMB_R0, THUMB_R1); // src
patch_cardireadcard_mov_dst_to_r1 = THUMB_MOVS_REG(THUMB_R1, THUMB_R5); // dst
patch_cardireadcard_mov_cardicommon_to_r6 = THUMB_LDR_SP_IMM(THUMB_R6, 8); // r6 from stack
patch_cardireadcard_mov_cardicommon_to_r6 = THUMB_LDR_SP_IMM(THUMB_R6, 0x10); // r6 from stack
if (patchContext.GetSdkVersion().GetMajor() <= SDK_VERSION_MAJOR_NITRO_2)
patch_cardireadcard_adjust_cardicommon_offset = THUMB_SUBS_IMM(THUMB_R6, THUMB_R6, 4);
else
patch_cardireadcard_adjust_cardicommon_offset = THUMB_NOP;
patch_cardireadcard_mov_r3_to_dst = THUMB_MOVS_REG(THUMB_R5, THUMB_R3);
*(u16*)((u8*)_cardiReadCard + patchOffset + 0) = THUMB_NOP;
}
else if (_foundPattern == sCARDiReadCardPatternSdk4027531ThumbInlined)
{
// This variant has a lot of inlining
patchOffset = 0x36;
patch_cardireadcard_return_offset = THUMB_MOVS_IMM(THUMB_R0, 0x64);
patch_cardireadcard_mov_src_to_r0 = THUMB_LDR_SP_IMM(THUMB_R0, 8); // src, r3 from the stack
patch_cardireadcard_mov_dst_to_r1 = THUMB_LDR_SP_IMM(THUMB_R1, 4); // dst, r2 from the stack
patch_cardireadcard_mov_cardicommon_to_r6 = THUMB_LDR_SP_IMM(THUMB_R6, 0); // r1 from the stack
patch_cardireadcard_adjust_cardicommon_offset = THUMB_NOP;
patch_cardireadcard_mov_r3_to_dst = THUMB_STR_SP_IMM(THUMB_R3, 4); // copy to r2 on the stack
*(u16*)((u8*)_cardiReadCard + patchOffset + 0) = THUMB_LDR_PC_IMM(THUMB_R1, 0xDC); // ldr r1,= cardi_common
}
else
{
@@ -185,7 +210,6 @@ void CardiReadCardPatch::ApplyPatch(PatchContext& patchContext)
while (1);
}
*(u16*)((u8*)_cardiReadCard + patchOffset + 0) = cardiCommonOffset == 0 ? THUMB_NOP : THUMB_LDR_PC_IMM(THUMB_R3, cardiCommonOffset); // ldr r0,= cardi_common
*(u16*)((u8*)_cardiReadCard + patchOffset + 2) = THUMB_LDR_PC_IMM(THUMB_R0, 0); // ldr r0,= entryAddress
*(u16*)((u8*)_cardiReadCard + patchOffset + 4) = THUMB_BLX(THUMB_R0);
*(u32*)((u8*)_cardiReadCard + patchOffset + 6) = entryAddress;

View File

@@ -11,7 +11,7 @@ patch_cardireadcard_entry:
patch_cardireadcard_return_offset:
movs r0, #0x38
add lr, r0
push {r3,r4,r6,lr}
push {r1,r2,r3,r4,r6,lr}
ldr r3, __patch_cardireadcard_fix_cp15_asm_address
blx r3
.global patch_cardireadcard_mov_src_to_r0
@@ -59,7 +59,7 @@ patch_cardireadcard_mov_r3_to_dst:
do_read:
ldr r3, __patch_cardireadcard_sdread_asm_address
blx r3
pop {r3,r4,r6,pc}
pop {r1,r2,r3,r4,r6,pc}
.balign 4

View File

@@ -36,6 +36,7 @@ static const u32 sCARDiTryReadCardDmaPatternSdkThumb[] = { 0xB084B5F8u, 0x483D90
static const u32 sCARDiTryReadCardDmaPatternSdk4007531Thumb[] = { 0xB084B5F8u, 0x483E9000u, 0x6A446A05u, 0x90032000u };
static const u32 sCARDiTryReadCardDmaPatternSdk4017530Thumb[] = { 0xB084B5F8u, 0x48479000u, 0x6A446A05u, 0x90032000u };
static const u32 sCARDiTryReadCardDmaPatternSdk4027530Thumb[] = { 0xB084B5F8u, 0x48479000u, 0x6A446A05u, 0x90032000u };
static const u32 sCARDiTryReadCardDmaPatternSdk4027531ThumbInlined[] = { 0xB083B5F0u, 0x485D9000u, 0x6A062500u, 0x1C286A44u };
static const u16 sReturnFalsePatchThumb[] = { THUMB_MOVS_IMM(0, 0), THUMB_BX_LR };
static const u32 sReturnFalsePatchArm[] = { 0xE3A00000, 0xE12FFF1E }; // mov r0, #0; bx lr
@@ -141,6 +142,10 @@ bool CardiTryReadCardDmaPatch::FindPatchTarget(PatchContext& patchContext)
if (!_cardiTryReadCardDma)
TryPattern(patchContext, sCARDiTryReadCardDmaPatternThumbChouSoujuu);
}
if (!_cardiTryReadCardDma && patchContext.GetSdkVersion() == 0x4027531)
{
TryPattern(patchContext, sCARDiTryReadCardDmaPatternSdk4027531ThumbInlined);
}
if (_cardiTryReadCardDma)
_thumb = true;
@@ -167,7 +172,7 @@ bool CardiTryReadCardDmaPatch::FindPatchTarget(PatchContext& patchContext)
static u32 getArmBlAddress(const u32* instructionPointer)
{
u32 blInstruction = *instructionPointer;
return (u32)instructionPointer + 8 + ((int)((blInstruction & 0xFFFFFF) << 8) >> 6);
return (u32)instructionPointer + 8 + ((int)((blInstruction & 0xFFFFFF) << 8) >> 6) + ((blInstruction >> 24) == 0xFA ? 1 : 0);
}
void CardiTryReadCardDmaPatch::ApplyPatch(PatchContext& patchContext)
@@ -228,7 +233,14 @@ void CardiTryReadCardDmaPatch::ApplyPatch(PatchContext& patchContext)
{
cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x15C) + 4;
cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x16C);
cardiSetCardDma = getArmBlAddress((u32*)((u8*)_cardiTryReadCardDma + 0x148));
if (*(u32*)((u8*)_cardiTryReadCardDma + 0x158) == 0xE12FFF1E)
{
cardiSetCardDma = getArmBlAddress((u32*)((u8*)_cardiTryReadCardDma + 0x148));
}
else
{
cardiSetCardDma = getArmBlAddress((u32*)((u8*)_cardiTryReadCardDma + 0x14C));
}
miiCardDmaCopy32 = getArmBlAddress((u32*)(cardiSetCardDma + 0x18));
cardiOnReadCardOffset = 0x40;
}