Initial commit

This commit is contained in:
Gericom
2025-11-22 11:08:28 +01:00
commit 9cf3ffbfcf
358 changed files with 58350 additions and 0 deletions

View File

@@ -0,0 +1,139 @@
#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/SaveOffsetToSdSectorAsm.h"
#include "patches/platform/LoaderPlatform.h"
#include "patches/OffsetToSectorRemapAsm.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
);
__patch_carditaskthread_readsave_asm_address = (u32)readSavePatchCode->GetReadSaveFunction();
__patch_carditaskthread_writesave_asm_address = (u32)writeSavePatchCode->GetWriteSaveFunction();
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);
}

View File

@@ -0,0 +1,17 @@
#pragma once
#include "patches/Patch.h"
/// @brief Arm7 patch for redirecting save reads and writes on SDK 5.
class CardiDoTaskFromArm9Patch : public Patch
{
public:
bool FindPatchTarget(PatchContext& patchContext) override;
void ApplyPatch(PatchContext& patchContext) override;
private:
u32* _cardiDoTaskFromArm9 = nullptr;
const u32* _foundPattern = nullptr;
u16 _thumb = false;
void TryPattern(PatchContext& patchContext, const u32* pattern);
};

View File

@@ -0,0 +1,14 @@
#pragma once
#include "sections.h"
DEFINE_SECTION_SYMBOLS(patch_cardidotaskfromarm9);
extern "C" void __patch_cardidotaskfromarm9_entry();
extern u32 __patch_cardidotaskfromarm9_failoffset;
extern u32 __patch_cardidotaskfromarm9_successoffset;
extern u16 __patch_cardidotaskfromarm9_move_statereg;
extern u32 __patch_cardidotaskfromarm9_readsave_asm_address;
extern u32 __patch_cardidotaskfromarm9_writesave_asm_address;

View File

@@ -0,0 +1,82 @@
#include "common.h"
#include "patches/platform/LoaderPlatform.h"
#include "Sdk5DsiSdCardRedirectPatchAsm.h"
#include "Sdk5DsiSdCardRedirectPatch.h"
static const u32 sAttachFunctionPattern[] = { 0xE92D4018u, 0xE24DDF5Du, 0xE24DDB01u, 0xE59FE050u };
static const u32 sAttachFunctionPatternThumb[] = { 0xB0FFB518u, 0xB0DFB0FFu, 0x4A0E490Du, 0x64CA4469u };
bool Sdk5DsiSdCardRedirectPatch::FindPatchTarget(PatchContext& patchContext)
{
_attachFunction = patchContext.FindPattern32Twl(sAttachFunctionPattern, sizeof(sAttachFunctionPattern));
if (!_attachFunction)
{
_attachFunction = patchContext.FindPattern32Twl(sAttachFunctionPatternThumb, sizeof(sAttachFunctionPatternThumb));
if (_attachFunction)
{
_thumb = true;
}
}
if (_attachFunction)
{
LOG_DEBUG("Found FATFSi_sdmcRtfsAttach at %p\n", _attachFunction);
}
else
{
LOG_WARNING("FATFSi_sdmcRtfsAttach not found\n");
}
return _attachFunction != nullptr;
}
static u32 getArmBlAddress(const u32* instructionPointer)
{
u32 blInstruction = *instructionPointer;
return (u32)instructionPointer + 8 + ((int)((blInstruction & 0xFFFFFF) << 8) >> 6);
}
static u32 getThumbBlAddress(const u32* instructionPointer)
{
u32 blInstruction1 = ((u16*)instructionPointer)[0];
u32 blInstruction2 = ((u16*)instructionPointer)[1];
return (u32)instructionPointer + 5 + ((int)((((blInstruction1 & 0x7FF) << 11) | (blInstruction2 & 0x7FF)) << 10) >> 9);
}
void Sdk5DsiSdCardRedirectPatch::ApplyPatch(PatchContext& patchContext)
{
if (!_attachFunction)
return;
u32 getDriveStructAddress;
if (_thumb)
{
getDriveStructAddress = getThumbBlAddress((u32*)((u8*)_attachFunction - 0x20));
}
else
{
getDriveStructAddress = getArmBlAddress((u32*)((u8*)_attachFunction - 0x20));
}
auto sdRead = patchContext.GetLoaderPlatform()->CreateSdReadPatchCode(
patchContext.GetPatchCodeCollection(), patchContext.GetPatchHeap());
auto sdWrite = patchContext.GetLoaderPlatform()->CreateSdWritePatchCode(
patchContext.GetPatchCodeCollection(), patchContext.GetPatchHeap());
auto patch = patchContext.GetPatchCodeCollection().AddUniquePatchCode<Sdk5DsiSdCardRedirectPatchCode>
(
patchContext.GetPatchHeap(),
sdRead,
sdWrite,
getDriveStructAddress
);
if (_thumb)
{
*(u32*)((u8*)_attachFunction + 0x44) = (u32)patch->GetIoFunction();
*(u32*)((u8*)_attachFunction + 0x48) = (u32)patch->GetControlFunction();
}
else
{
*(u32*)((u8*)_attachFunction + 0x64) = (u32)patch->GetIoFunction();
*(u32*)((u8*)_attachFunction + 0x68) = (u32)patch->GetControlFunction();
}
}

View File

@@ -0,0 +1,14 @@
#pragma once
#include "patches/Patch.h"
/// @brief Arm7 patch for redirecting access to the DSi sd card to the flashcard sd card.
class Sdk5DsiSdCardRedirectPatch : public Patch
{
public:
bool FindPatchTarget(PatchContext& patchContext) override;
void ApplyPatch(PatchContext& patchContext) override;
private:
u32* _attachFunction = nullptr;
u16 _thumb = false;
};

View File

@@ -0,0 +1,37 @@
#pragma once
#include "patches/PatchCode.h"
#include "sections.h"
#include "patches/platform/SdReadPatchCode.h"
#include "patches/platform/SdWritePatchCode.h"
DEFINE_SECTION_SYMBOLS(patch_dsisdredirect);
extern "C" bool __patch_dsisdredirect_io(u32 driveNumber, u32 startSector, void* buffer, u32 sectorCount, bool isRead);
extern "C" u32 __patch_dsisdredirect_control(u32 driveNumber, u32 command, void* argumentBuffer);
extern u32 __patch_dsisdredirect_io_readsd_asm_address;
extern u32 __patch_dsisdredirect_io_writesd_asm_address;
extern u32 __patch_dsisdredirect_control_get_drive_struct_address;
class Sdk5DsiSdCardRedirectPatchCode : public PatchCode
{
public:
Sdk5DsiSdCardRedirectPatchCode(PatchHeap& patchHeap, const SdReadPatchCode* sdReadPatchCode,
const SdWritePatchCode* sdWritePatchCode, u32 getDriveStructAddress)
: PatchCode(SECTION_START(patch_dsisdredirect), SECTION_SIZE(patch_dsisdredirect), patchHeap)
{
__patch_dsisdredirect_io_readsd_asm_address = (u32)sdReadPatchCode->GetSdReadFunction();
__patch_dsisdredirect_io_writesd_asm_address = (u32)sdWritePatchCode->GetSdWriteFunction();
__patch_dsisdredirect_control_get_drive_struct_address = getDriveStructAddress;
}
const void* GetIoFunction() const
{
return GetAddressAtTarget((void*)__patch_dsisdredirect_io);
}
const void* GetControlFunction() const
{
return GetAddressAtTarget((void*)__patch_dsisdredirect_control);
}
};

View File

@@ -0,0 +1,80 @@
.cpu arm7tdmi
.section "patch_dsisdredirect", "ax"
.syntax unified
.thumb
// r0 = drive number
// r1 = start sector
// r2 = source/destination buffer
// r3 = sector count
// [sp] = isReading (0 = write, otherwise read)
.global __patch_dsisdredirect_io
.type __patch_dsisdredirect_io, %function
__patch_dsisdredirect_io:
push {r4,lr}
movs r0, r1
movs r1, r2
movs r2, r3
ldr r4, [sp, #8] // reading
cmp r4, #0
bne 1f
ldr r3, __patch_dsisdredirect_io_writesd_asm_address
bl blx_r3
movs r0, #1 // success
b return
1:
ldr r3, __patch_dsisdredirect_io_readsd_asm_address
bl blx_r3
movs r0, #1 // success
return:
pop {r4}
pop {r3}
blx_r3:
bx r3
// r0 = drive number
// r1 = command
// r2 = argument buffer
.global __patch_dsisdredirect_control
.type __patch_dsisdredirect_control, %function
__patch_dsisdredirect_control:
push {lr}
cmp r1, #1 // startup
bne returnZero
ldr r3, __patch_dsisdredirect_control_get_drive_struct_address
bl blx_r3
ldr r1,= 0x4B4
movs r2, #0
str r2, [r0, r1] // partition 0
subs r1, r1, #4
ldr r2, [r0, r1]
movs r3, #0x83 // valid, partitioned, inserted
orrs r2, r2, r3
str r2, [r0, r1]
returnZero:
movs r0, #0
pop {r3}
bx r3
.balign 4
.global __patch_dsisdredirect_io_readsd_asm_address
__patch_dsisdredirect_io_readsd_asm_address:
.word 0
.global __patch_dsisdredirect_io_writesd_asm_address
__patch_dsisdredirect_io_writesd_asm_address:
.word 0
.global __patch_dsisdredirect_control_get_drive_struct_address
__patch_dsisdredirect_control_get_drive_struct_address:
.word 0
.pool
.end