Files
pico-loader/arm9/source/patches/arm7/sdk5/CardiDoTaskFromArm9Patch.cpp

156 lines
7.3 KiB
C++
Raw Normal View History

2025-11-22 11:08:28 +01:00
#include "common.h"
#include "patches/PatchContext.h"
#include "thumbInstructions.h"
#include "fileInfo.h"
#include "patches/arm7/ReadSaveAsm.h"
#include "patches/arm7/WriteSaveAsm.h"
#include "patches/arm7/VerifySaveAsm.h"
#include "patches/SaveOffsetToSdSectorAsm.h"
2025-11-22 11:08:28 +01:00
#include "patches/platform/LoaderPlatform.h"
#include "patches/arm7/CardiTaskThreadPatchAsm.h"
#include "CardiDoTaskFromArm9Patch.h"
static const u32 sCARDiDoTaskFromARM9Pattern5007538[] = { 0xE92D4038u, 0xE59F4190u, 0xE3A01001u, 0xE5943000u }; // this one has branches instead of an offset table
static const u32 sCARDiDoTaskFromARM9Pattern5017537[] = { 0xE92D4070u, 0xE59F5168u, 0xE3A01001u, 0xE5953000u };
static const u32 sCARDiDoTaskFromARM9Pattern5057530[] = { 0xE92D4070u, 0xE59F5174u, 0xE3A01001u, 0xE5953000u };
static const u32 sCARDiDoTaskFromARM9Pattern5017537Thumb[] = { 0x4C3FB538u, 0x68214A3Fu, 0x23016E92u, 0x40936D88u };
static const u32 sCARDiDoTaskFromARM9Pattern5037531Thumb[] = { 0x4C3EB538u, 0x68214A3Eu, 0x23016E92u, 0x40936D88u };
static const u32 sCARDiDoTaskFromARM9Pattern5057530Thumb[] = { 0x4C40B538u, 0x68214A40u, 0x23016E92u, 0x40936D88u };
void CardiDoTaskFromArm9Patch::TryPattern(PatchContext& patchContext, const u32* pattern)
{
_cardiDoTaskFromArm9 = patchContext.FindPattern32(pattern, 16);
if (_cardiDoTaskFromArm9)
{
_foundPattern = pattern;
}
}
bool CardiDoTaskFromArm9Patch::FindPatchTarget(PatchContext& patchContext)
{
if (patchContext.GetSdkVersion() <= 0x5027535)
TryPattern(patchContext, sCARDiDoTaskFromARM9Pattern5007538);
if (!_cardiDoTaskFromArm9 && patchContext.GetSdkVersion() >= 0x5017537 && patchContext.GetSdkVersion() <= 0x5057534)
TryPattern(patchContext, sCARDiDoTaskFromARM9Pattern5017537);
if (!_cardiDoTaskFromArm9 && patchContext.GetSdkVersion() >= 0x5057530)
TryPattern(patchContext, sCARDiDoTaskFromARM9Pattern5057530);
if (!_cardiDoTaskFromArm9)
{
TryPattern(patchContext, sCARDiDoTaskFromARM9Pattern5057530Thumb);
if (!_cardiDoTaskFromArm9)
TryPattern(patchContext, sCARDiDoTaskFromARM9Pattern5037531Thumb);
if (!_cardiDoTaskFromArm9)
TryPattern(patchContext, sCARDiDoTaskFromARM9Pattern5017537Thumb);
if (_cardiDoTaskFromArm9)
{
_thumb = true;
}
}
if (_cardiDoTaskFromArm9)
{
LOG_DEBUG("CARDi_DoTaskFromARM9 found at 0x%p\n", _cardiDoTaskFromArm9);
}
return _cardiDoTaskFromArm9 != nullptr;
}
void CardiDoTaskFromArm9Patch::ApplyPatch(PatchContext& patchContext)
{
if (!_cardiDoTaskFromArm9)
return;
u32 patch1Size = SECTION_SIZE(patch_carditaskthread);
void* patch1Address = patchContext.GetPatchHeap().Alloc(patch1Size);
auto loaderPlatform = patchContext.GetLoaderPlatform();
auto readPatchCode = loaderPlatform->CreateSdReadPatchCode(
patchContext.GetPatchCodeCollection(), patchContext.GetPatchHeap());
auto writePatchCode = loaderPlatform->CreateSdWritePatchCode(
patchContext.GetPatchCodeCollection(), patchContext.GetPatchHeap());
auto sectorRemapPatchCode = patchContext.GetPatchCodeCollection().AddUniquePatchCode<SaveOffsetToSdSectorPatchCode>(
patchContext.GetPatchHeap(), SHARED_SAVE_FILE_INFO);
void* tmpBuffer = patchContext.GetPatchHeap().Alloc(512);
auto readSavePatchCode = patchContext.GetPatchCodeCollection().AddUniquePatchCode<ReadSavePatchCode>(
patchContext.GetPatchHeap(),
sectorRemapPatchCode,
readPatchCode,
tmpBuffer
);
auto writeSavePatchCode = patchContext.GetPatchCodeCollection().AddUniquePatchCode<WriteSavePatchCode>(
patchContext.GetPatchHeap(),
sectorRemapPatchCode,
readPatchCode,
writePatchCode,
tmpBuffer
);
auto verifySavePatchCode = patchContext.GetPatchCodeCollection().AddUniquePatchCode<VerifySavePatchCode>(
patchContext.GetPatchHeap(),
sectorRemapPatchCode,
readPatchCode,
tmpBuffer
);
2025-11-22 11:08:28 +01:00
__patch_carditaskthread_readsave_asm_address = (u32)readSavePatchCode->GetReadSaveFunction();
__patch_carditaskthread_writesave_asm_address = (u32)writeSavePatchCode->GetWriteSaveFunction();
__patch_carditaskthread_verifysave_asm_address = (u32)verifySavePatchCode->GetVerifySaveFunction();
if (loaderPlatform->GetPlatformType() == LoaderPlatformType::Slot1)
{
// Test REG_EXMEMSTAT bit 11
__patch_carditaskthread_lsls_exmemstat_bit_to_r1 = THUMB_LSLS_IMM(THUMB_R1, THUMB_R1, 31 - 11);
}
else
{
// Test REG_EXMEMSTAT bit 7
__patch_carditaskthread_lsls_exmemstat_bit_to_r1 = THUMB_LSLS_IMM(THUMB_R1, THUMB_R1, 31 - 7);
}
2025-11-22 11:08:28 +01:00
u32 patchOffset;
if (_thumb)
{
patchOffset = _foundPattern == sCARDiDoTaskFromARM9Pattern5057530Thumb ? 0x3A : 0x36;
u32 entryAddress = (u32)&__patch_carditaskthread_entry - (u32)SECTION_START(patch_carditaskthread) + (u32)patch1Address;
__patch_carditaskthread_mov_cardicommon_to_r4 = THUMB_NOP;
__patch_carditaskthread_mov_command_to_r0 = THUMB_NOP;
__patch_carditaskthread_successoffset = *(u16*)((u8*)_cardiDoTaskFromArm9 + patchOffset + 0x0C) + 9;
__patch_carditaskthread_failoffset = *(u16*)((u8*)_cardiDoTaskFromArm9 + patchOffset + 0x14) + 9;
*(u16*)((u8*)_cardiDoTaskFromArm9 + patchOffset + 0x00) = THUMB_LDR_PC_IMM(THUMB_R1, 4);
*(u16*)((u8*)_cardiDoTaskFromArm9 + patchOffset + 0x02) = THUMB_MOV_HIREG(THUMB_HI_LR, THUMB_HI_PC);
*(u16*)((u8*)_cardiDoTaskFromArm9 + patchOffset + 0x04) = THUMB_BX(THUMB_R1);
*(u32*)((u8*)_cardiDoTaskFromArm9 + patchOffset + 0x06) = entryAddress;
}
else
{
if (_foundPattern == sCARDiDoTaskFromARM9Pattern5007538)
{
// 0x4C = cmp r0, #0xF
patchOffset = 0x4C;
__patch_carditaskthread_successoffset = 4;
__patch_carditaskthread_failoffset = ((*(u32*)((u8*)_cardiDoTaskFromArm9 + patchOffset + 0x08) & 0xFFFFFF) << 2) + 4;
__patch_carditaskthread_mov_cardicommon_to_r4 = THUMB_NOP; // already in r4
__patch_carditaskthread_mov_command_to_r0 = THUMB_NOP;
}
else
{
// 0x58 = add r0, pc, r0, lsl #1
if (_foundPattern == sCARDiDoTaskFromARM9Pattern5057530)
patchOffset = 0x58;
else
patchOffset = 0x54;
__patch_carditaskthread_successoffset = *(u16*)((u8*)_cardiDoTaskFromArm9 + patchOffset + 0x0C) + 4;
__patch_carditaskthread_failoffset = *(u16*)((u8*)_cardiDoTaskFromArm9 + patchOffset + 0x14) + 4;
__patch_carditaskthread_mov_cardicommon_to_r4 = THUMB_MOVS_REG(THUMB_R4, THUMB_R5);
__patch_carditaskthread_mov_command_to_r0 = THUMB_NOP;
}
u32 entryAddress = (u32)&__patch_carditaskthread_entry - (u32)SECTION_START(patch_carditaskthread) + (u32)patch1Address;
*(u32*)((u8*)_cardiDoTaskFromArm9 + patchOffset + 0x00) = 0xe59f1004; // ldr r1,= entryAddress
*(u32*)((u8*)_cardiDoTaskFromArm9 + patchOffset + 0x04) = 0xe1a0e00f; // mov lr, pc
*(u32*)((u8*)_cardiDoTaskFromArm9 + patchOffset + 0x08) = 0xe12fff11; // bx r1
*(u32*)((u8*)_cardiDoTaskFromArm9 + patchOffset + 0x0C) = entryAddress;
}
memcpy(patch1Address, SECTION_START(patch_carditaskthread), patch1Size);
}