mirror of
https://github.com/LNH-team/pico-loader.git
synced 2026-06-02 09:16:49 +02:00
Initial commit
This commit is contained in:
15
arm9/source/patches/arm7/CardiTaskThreadPatchAsm.h
Normal file
15
arm9/source/patches/arm7/CardiTaskThreadPatchAsm.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
#include "sections.h"
|
||||
|
||||
DEFINE_SECTION_SYMBOLS(patch_carditaskthread);
|
||||
|
||||
extern "C" void __patch_carditaskthread_entry();
|
||||
extern "C" void __patch_carditaskthread_entry_sdk4();
|
||||
|
||||
extern u16 __patch_carditaskthread_mov_cardicommon_to_r4;
|
||||
extern u16 __patch_carditaskthread_mov_command_to_r0;
|
||||
|
||||
extern u32 __patch_carditaskthread_failoffset;
|
||||
extern u32 __patch_carditaskthread_successoffset;
|
||||
extern u32 __patch_carditaskthread_readsave_asm_address;
|
||||
extern u32 __patch_carditaskthread_writesave_asm_address;
|
||||
123
arm9/source/patches/arm7/CardiTaskThreadPatchAsm.s
Normal file
123
arm9/source/patches/arm7/CardiTaskThreadPatchAsm.s
Normal file
@@ -0,0 +1,123 @@
|
||||
.cpu arm7tdmi
|
||||
.section "patch_carditaskthread", "ax"
|
||||
.syntax unified
|
||||
.thumb
|
||||
|
||||
.global __patch_carditaskthread_entry_sdk4
|
||||
.type __patch_carditaskthread_entry_sdk4, %function
|
||||
__patch_carditaskthread_entry_sdk4:
|
||||
push {r4,lr}
|
||||
beq end_success
|
||||
b __patch_carditaskthread_mov_cardicommon_to_r4
|
||||
|
||||
.global __patch_carditaskthread_entry
|
||||
.type __patch_carditaskthread_entry, %function
|
||||
__patch_carditaskthread_entry:
|
||||
push {r4,lr}
|
||||
.global __patch_carditaskthread_mov_cardicommon_to_r4
|
||||
__patch_carditaskthread_mov_cardicommon_to_r4:
|
||||
mov r4, r9
|
||||
.global __patch_carditaskthread_mov_command_to_r0
|
||||
__patch_carditaskthread_mov_command_to_r0:
|
||||
ldr r0, [r4, #4] // r0 = command
|
||||
|
||||
cmp r0, #2
|
||||
beq identify_backup
|
||||
|
||||
cmp r0, #6
|
||||
beq read_backup
|
||||
|
||||
cmp r0, #7
|
||||
beq write_backup
|
||||
|
||||
cmp r0, #8
|
||||
beq write_backup
|
||||
|
||||
cmp r0, #9
|
||||
beq verify_backup
|
||||
|
||||
// erase
|
||||
cmp r0, #10
|
||||
beq end_success
|
||||
cmp r0, #11
|
||||
beq end_success
|
||||
cmp r0, #12
|
||||
beq end_success
|
||||
cmp r0, #15
|
||||
beq end_success
|
||||
|
||||
end_fail:
|
||||
ldr r0, __patch_carditaskthread_failoffset
|
||||
b end
|
||||
|
||||
end_success:
|
||||
ldr r0, __patch_carditaskthread_successoffset
|
||||
end:
|
||||
pop {r4}
|
||||
pop {r3}
|
||||
adds r3, r0
|
||||
bx r3
|
||||
|
||||
identify_backup:
|
||||
b end_success
|
||||
|
||||
read_backup:
|
||||
ldr r0, [r4]
|
||||
movs r1, #0
|
||||
str r1, [r0] // result
|
||||
ldr r1, [r0, #0xC] // src
|
||||
ldr r2, [r0, #0x10] // dst
|
||||
ldr r3, [r0, #0x14] // len
|
||||
cmp r3, #0
|
||||
beq end_success
|
||||
|
||||
ldr r0, __patch_carditaskthread_readsave_asm_address
|
||||
bl blx_r0
|
||||
|
||||
b end_success
|
||||
|
||||
write_backup:
|
||||
ldr r0, [r4]
|
||||
movs r1, #0
|
||||
str r1, [r0] // result
|
||||
ldr r1, [r0, #0xC] // src
|
||||
ldr r2, [r0, #0x10] // dst
|
||||
ldr r3, [r0, #0x14] // len
|
||||
cmp r3, #0
|
||||
beq end_success
|
||||
|
||||
ldr r0, __patch_carditaskthread_writesave_asm_address
|
||||
bl blx_r0
|
||||
|
||||
b end_success
|
||||
|
||||
verify_backup:
|
||||
ldr r0, [r4]
|
||||
movs r1, #0
|
||||
str r1, [r0] // result
|
||||
b end_success
|
||||
|
||||
blx_r0:
|
||||
bx r0
|
||||
|
||||
.balign 4
|
||||
|
||||
.global __patch_carditaskthread_failoffset
|
||||
__patch_carditaskthread_failoffset:
|
||||
.word 0
|
||||
|
||||
.global __patch_carditaskthread_successoffset
|
||||
__patch_carditaskthread_successoffset:
|
||||
.word 4
|
||||
|
||||
.global __patch_carditaskthread_readsave_asm_address
|
||||
__patch_carditaskthread_readsave_asm_address:
|
||||
.word 0
|
||||
|
||||
.global __patch_carditaskthread_writesave_asm_address
|
||||
__patch_carditaskthread_writesave_asm_address:
|
||||
.word 0
|
||||
|
||||
.pool
|
||||
|
||||
.end
|
||||
39
arm9/source/patches/arm7/DisableArm7WramClearPatch.cpp
Normal file
39
arm9/source/patches/arm7/DisableArm7WramClearPatch.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
#include "common.h"
|
||||
#include "../PatchContext.h"
|
||||
#include "sharedMemory.h"
|
||||
#include "ndsHeader.h"
|
||||
#include "DisableArm7WramClearPatch.h"
|
||||
|
||||
bool DisableArm7WramClearPatch::FindPatchTarget(PatchContext& patchContext)
|
||||
{
|
||||
auto romHeader = (const nds_header_ntr_t*)TWL_SHARED_MEMORY->ntrSharedMem.romHeader;
|
||||
_clearEndPool = nullptr;
|
||||
for (u32 i = 0; i < 0x100; i += 4)
|
||||
{
|
||||
u32* ptr = (u32*)(romHeader->arm7LoadAddress + i);
|
||||
if (*ptr == 0x380FF00)
|
||||
{
|
||||
_clearEndPool = ptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (_clearEndPool)
|
||||
{
|
||||
LOG_DEBUG("Arm7 wram clear end pool value found at 0x%p\n", _clearEndPool);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_WARNING("Arm7 wram clear end pool value not found\n");
|
||||
}
|
||||
|
||||
return _clearEndPool != nullptr;
|
||||
}
|
||||
|
||||
void DisableArm7WramClearPatch::ApplyPatch(PatchContext& patchContext)
|
||||
{
|
||||
if (!_clearEndPool)
|
||||
return;
|
||||
|
||||
*_clearEndPool = 0;
|
||||
}
|
||||
13
arm9/source/patches/arm7/DisableArm7WramClearPatch.h
Normal file
13
arm9/source/patches/arm7/DisableArm7WramClearPatch.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
#include "../Patch.h"
|
||||
|
||||
/// @brief Arm7 patch to disabling clearing of wram.
|
||||
class DisableArm7WramClearPatch : public Patch
|
||||
{
|
||||
public:
|
||||
bool FindPatchTarget(PatchContext& patchContext) override;
|
||||
void ApplyPatch(PatchContext& patchContext) override;
|
||||
|
||||
private:
|
||||
u32* _clearEndPool = nullptr;
|
||||
};
|
||||
97
arm9/source/patches/arm7/OsGetInitArenaLoPatch.cpp
Normal file
97
arm9/source/patches/arm7/OsGetInitArenaLoPatch.cpp
Normal file
@@ -0,0 +1,97 @@
|
||||
#include "common.h"
|
||||
#include "../PatchContext.h"
|
||||
#include "OsGetInitArenaLoPatch.h"
|
||||
|
||||
static const u32 sOSGetInitArenaLoPatternOld[] = { 0xE3A0050Eu, 0xE59F1014u, 0xE351050Eu, 0x81A00001u }; // -0x34
|
||||
static const u32 sOSGetInitArenaLoPattern[] = { 0xE59F1018u, 0xE3A0050Eu, 0xE351050Eu, 0x81A00001u }; // -0x34
|
||||
static const u32 sOSGetInitArenaLoPattern2[] = { 0xE59F101Cu, 0xE3A0050Eu, 0xE351050Eu, 0x81A00001u }; // -0x3C
|
||||
static const u32 sOSGetInitArenaLoPatternThumb[] = { 0xD0042801u, 0xD0042807u, 0xD0092808u, 0x4809E00Fu };
|
||||
static const u32 sOSGetInitArenaLoPatternThumbSdk50[] = { 0x2801B508u, 0x2807D004u, 0x2808D006u, 0xE010D00Au };
|
||||
|
||||
bool OsGetInitArenaLoPatch::FindPatchTarget(PatchContext& patchContext)
|
||||
{
|
||||
if (_osGetInitArenaLo)
|
||||
return true;
|
||||
_osGetInitArenaLo = patchContext.FindPattern32(sOSGetInitArenaLoPattern, sizeof(sOSGetInitArenaLoPattern));
|
||||
if (!_osGetInitArenaLo)
|
||||
_osGetInitArenaLo = patchContext.FindPattern32(sOSGetInitArenaLoPatternOld, sizeof(sOSGetInitArenaLoPatternOld));
|
||||
if (_osGetInitArenaLo)
|
||||
{
|
||||
_osGetInitArenaLo -= 13;
|
||||
_wramBssOffset = 0x54;
|
||||
}
|
||||
else
|
||||
{
|
||||
_osGetInitArenaLo = patchContext.FindPattern32(sOSGetInitArenaLoPattern2, sizeof(sOSGetInitArenaLoPattern2));
|
||||
if (_osGetInitArenaLo)
|
||||
{
|
||||
_osGetInitArenaLo -= 15;
|
||||
_wramBssOffset = 0x60;
|
||||
}
|
||||
else
|
||||
{
|
||||
_osGetInitArenaLo = patchContext.FindPattern32(sOSGetInitArenaLoPatternThumb, sizeof(sOSGetInitArenaLoPatternThumb));
|
||||
if (_osGetInitArenaLo)
|
||||
{
|
||||
_wramBssOffset = 0x38;
|
||||
}
|
||||
else
|
||||
{
|
||||
_osGetInitArenaLo = patchContext.FindPattern32(sOSGetInitArenaLoPatternThumbSdk50, sizeof(sOSGetInitArenaLoPatternThumbSdk50));
|
||||
if (_osGetInitArenaLo)
|
||||
{
|
||||
_wramBssOffset = 0x40;
|
||||
}
|
||||
else
|
||||
{
|
||||
_osGetInitArenaLo = patchContext.FindPattern32Twl(sOSGetInitArenaLoPattern, sizeof(sOSGetInitArenaLoPattern));
|
||||
if (!_osGetInitArenaLo)
|
||||
_osGetInitArenaLo = patchContext.FindPattern32Twl(sOSGetInitArenaLoPatternOld, sizeof(sOSGetInitArenaLoPatternOld));
|
||||
if (_osGetInitArenaLo)
|
||||
{
|
||||
_osGetInitArenaLo -= 13;
|
||||
_wramBssOffset = 0x54;
|
||||
}
|
||||
else
|
||||
{
|
||||
_osGetInitArenaLo = patchContext.FindPattern32Twl(sOSGetInitArenaLoPattern2, sizeof(sOSGetInitArenaLoPattern2));
|
||||
if (_osGetInitArenaLo)
|
||||
{
|
||||
_osGetInitArenaLo -= 15;
|
||||
_wramBssOffset = 0x60;
|
||||
}
|
||||
else
|
||||
{
|
||||
_osGetInitArenaLo = patchContext.FindPattern32Twl(sOSGetInitArenaLoPatternThumb, sizeof(sOSGetInitArenaLoPatternThumb));
|
||||
if (_osGetInitArenaLo)
|
||||
{
|
||||
_wramBssOffset = 0x38;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_osGetInitArenaLo)
|
||||
{
|
||||
LOG_DEBUG("Found OS_GetInitArenaLo at %p\n", _osGetInitArenaLo);
|
||||
_wramBssEnd = (void*)*(u32*)((u8*)_osGetInitArenaLo + _wramBssOffset);
|
||||
LOG_DEBUG("Bss end: 0x%p\n", _wramBssEnd);
|
||||
_mainMemoryArenaLo = (void*)*(u32*)((u8*)_osGetInitArenaLo + _wramBssOffset - 4);
|
||||
LOG_DEBUG("Main memory arena lo: 0x%p\n", _mainMemoryArenaLo);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_WARNING("OS_GetInitArenaLo not found\n");
|
||||
}
|
||||
return _osGetInitArenaLo != nullptr;
|
||||
}
|
||||
|
||||
void OsGetInitArenaLoPatch::ApplyPatch(PatchContext& patchContext)
|
||||
{
|
||||
if (!_osGetInitArenaLo)
|
||||
return;
|
||||
*(u32*)((u8*)_osGetInitArenaLo + _wramBssOffset) = (u32)_wramBssEnd;
|
||||
*(u32*)((u8*)_osGetInitArenaLo + _wramBssOffset - 4) = (u32)_mainMemoryArenaLo;
|
||||
}
|
||||
21
arm9/source/patches/arm7/OsGetInitArenaLoPatch.h
Normal file
21
arm9/source/patches/arm7/OsGetInitArenaLoPatch.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
#include "../Patch.h"
|
||||
|
||||
/// @brief Arm7 patch to get and update the arena low addresses for wram and main memory.
|
||||
class OsGetInitArenaLoPatch : public Patch
|
||||
{
|
||||
public:
|
||||
bool FindPatchTarget(PatchContext& patchContext) override;
|
||||
void ApplyPatch(PatchContext& patchContext) override;
|
||||
|
||||
void* GetArm7PrivateWramArenaLo() const { return _wramBssEnd; }
|
||||
void SetArm7PrivateWramArenaLo(void* wramBssEnd) { _wramBssEnd = wramBssEnd; }
|
||||
void* GetMainMemoryArenaLo() const { return _mainMemoryArenaLo; }
|
||||
void SetMainMemoryArenaLo(void* mainMemoryArenaLo) { _mainMemoryArenaLo = mainMemoryArenaLo; }
|
||||
|
||||
private:
|
||||
u32* _osGetInitArenaLo = nullptr;
|
||||
u32 _wramBssOffset = 0;
|
||||
void* _wramBssEnd = nullptr;
|
||||
void* _mainMemoryArenaLo = nullptr;
|
||||
};
|
||||
27
arm9/source/patches/arm7/PokemonDownloaderArm7Patch.cpp
Normal file
27
arm9/source/patches/arm7/PokemonDownloaderArm7Patch.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
#include "common.h"
|
||||
#include "../PatchContext.h"
|
||||
#include "PokemonDownloaderArm7PatchAsm.h"
|
||||
#include "PokemonDownloaderArm7Patch.h"
|
||||
|
||||
static const u32 sBootFunctionPattern[] = { 0xE92D4070u, 0xE59F0098u, 0xE5904004u, 0xE3540000u };
|
||||
|
||||
bool PokemonDownloaderArm7Patch::FindPatchTarget(PatchContext& patchContext)
|
||||
{
|
||||
_bootFunction = patchContext.FindPattern32(sBootFunctionPattern, sizeof(sBootFunctionPattern));
|
||||
return _bootFunction != nullptr;
|
||||
}
|
||||
|
||||
void PokemonDownloaderArm7Patch::ApplyPatch(PatchContext& patchContext)
|
||||
{
|
||||
if (!_bootFunction)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto patchCode = patchContext.GetPatchCodeCollection().AddUniquePatchCode<PokemonDownloaderArm7PatchCode>(
|
||||
patchContext.GetPatchHeap());
|
||||
|
||||
_bootFunction[0] = 0xE59F0000; // ldr r0,= address
|
||||
_bootFunction[1] = 0xE12FFF10; // bx r0
|
||||
_bootFunction[2] = (u32)patchCode->GetBoot7Function(); // address
|
||||
}
|
||||
14
arm9/source/patches/arm7/PokemonDownloaderArm7Patch.h
Normal file
14
arm9/source/patches/arm7/PokemonDownloaderArm7Patch.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
#include "../Patch.h"
|
||||
#include "LoaderInfo.h"
|
||||
|
||||
/// @brief Arm7 patch to make the Pokemon downloader reboot into Pico Loader.
|
||||
class PokemonDownloaderArm7Patch : public Patch
|
||||
{
|
||||
public:
|
||||
bool FindPatchTarget(PatchContext& patchContext) override;
|
||||
void ApplyPatch(PatchContext& patchContext) override;
|
||||
|
||||
private:
|
||||
u32* _bootFunction = nullptr;
|
||||
};
|
||||
19
arm9/source/patches/arm7/PokemonDownloaderArm7PatchAsm.h
Normal file
19
arm9/source/patches/arm7/PokemonDownloaderArm7PatchAsm.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
#include "../PatchCode.h"
|
||||
#include "sections.h"
|
||||
|
||||
DEFINE_SECTION_SYMBOLS(patch_pokemondownloader7);
|
||||
|
||||
extern "C" void patch_pokemondownloader7_entry(void);
|
||||
|
||||
class PokemonDownloaderArm7PatchCode : public PatchCode
|
||||
{
|
||||
public:
|
||||
explicit PokemonDownloaderArm7PatchCode(PatchHeap& patchHeap)
|
||||
: PatchCode(SECTION_START(patch_pokemondownloader7), SECTION_SIZE(patch_pokemondownloader7), patchHeap) { }
|
||||
|
||||
const void* GetBoot7Function() const
|
||||
{
|
||||
return GetAddressAtTarget((void*)patch_pokemondownloader7_entry);
|
||||
}
|
||||
};
|
||||
25
arm9/source/patches/arm7/PokemonDownloaderArm7PatchAsm.s
Normal file
25
arm9/source/patches/arm7/PokemonDownloaderArm7PatchAsm.s
Normal file
@@ -0,0 +1,25 @@
|
||||
.cpu arm7tdmi
|
||||
.section "patch_pokemondownloader7", "ax"
|
||||
.syntax unified
|
||||
|
||||
.thumb
|
||||
.global patch_pokemondownloader7_entry
|
||||
.type patch_pokemondownloader7_entry, %function
|
||||
patch_pokemondownloader7_entry:
|
||||
ldr r0,= 0x04000180 // REG_IPC_SYNC
|
||||
movs r1, #1
|
||||
strb r1, [r0, #1]
|
||||
|
||||
1:
|
||||
ldrb r7, [r0] // ipc sync
|
||||
cmp r7, #1
|
||||
bne 1b // while ipc sync from arm9 is not 1
|
||||
|
||||
ldr r0,= 0x06000000
|
||||
ldr r0, [r0]
|
||||
bx r0
|
||||
|
||||
.balign 4
|
||||
|
||||
.pool
|
||||
.end
|
||||
31
arm9/source/patches/arm7/ReadSaveAsm.h
Normal file
31
arm9/source/patches/arm7/ReadSaveAsm.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
#include "sections.h"
|
||||
#include "../PatchCode.h"
|
||||
#include "../SectorRemapPatchCode.h"
|
||||
#include "../platform/SdReadPatchCode.h"
|
||||
|
||||
DEFINE_SECTION_SYMBOLS(readsave);
|
||||
|
||||
extern "C" void readsave_asm(u32, u32 saveSrc, void* memoryDst, u32 byteLength);
|
||||
|
||||
extern u32 readsave_tmpBufferPtr;
|
||||
extern u32 readsave_save_offset_to_sd_sector_asm_address;
|
||||
extern u32 readsave_sdread_asm_address;
|
||||
|
||||
class ReadSavePatchCode : public PatchCode
|
||||
{
|
||||
public:
|
||||
ReadSavePatchCode(PatchHeap& patchHeap, const SectorRemapPatchCode* sectorRemapPatchCode,
|
||||
const SdReadPatchCode* sdReadPatchCode, void* tmpBuffer)
|
||||
: PatchCode(SECTION_START(readsave), SECTION_SIZE(readsave), patchHeap)
|
||||
{
|
||||
readsave_save_offset_to_sd_sector_asm_address = (u32)sectorRemapPatchCode->GetRemapFunction();
|
||||
readsave_sdread_asm_address = (u32)sdReadPatchCode->GetSdReadFunction();
|
||||
readsave_tmpBufferPtr = (u32)tmpBuffer;
|
||||
}
|
||||
|
||||
const void* GetReadSaveFunction() const
|
||||
{
|
||||
return GetAddressAtTarget((void*)readsave_asm);
|
||||
}
|
||||
};
|
||||
75
arm9/source/patches/arm7/ReadSaveAsm.s
Normal file
75
arm9/source/patches/arm7/ReadSaveAsm.s
Normal file
@@ -0,0 +1,75 @@
|
||||
.cpu arm7tdmi
|
||||
.section "readsave", "ax"
|
||||
.syntax unified
|
||||
.thumb
|
||||
|
||||
// r1 = save src
|
||||
// r2 = memory dst
|
||||
// r3 = byte length
|
||||
.global readsave_asm
|
||||
.type readsave_asm, %function
|
||||
readsave_asm:
|
||||
push {r4,r5,r6,r7,lr}
|
||||
movs r4, r3 // remaining bytes
|
||||
movs r5, r1
|
||||
movs r6, r2
|
||||
1:
|
||||
movs r0, r5 // will be rounded down by function
|
||||
ldr r3, readsave_save_offset_to_sd_sector_asm_address
|
||||
bl blx_r3
|
||||
cmp r0, #0
|
||||
beq end // out of bounds
|
||||
|
||||
ldr r1, readsave_tmpBufferPtr
|
||||
movs r2, #1 // single sector
|
||||
lsls r7, r2, #9 // 512
|
||||
ldr r3, readsave_sdread_asm_address
|
||||
bl blx_r3
|
||||
|
||||
// copy bytes
|
||||
lsls r2, r5, #23
|
||||
lsrs r2, r2, #23 // r2 = byte offset in sector
|
||||
subs r0, r6, r2
|
||||
subs r7, r7, r2 // remaining in sector
|
||||
cmp r7, r4 // if remaining in sector > requested read length
|
||||
bls 2f
|
||||
movs r7, r4 // clamp to requested read length
|
||||
2:
|
||||
subs r4, r7
|
||||
adds r5, r7
|
||||
adds r6, r7
|
||||
ldr r1, readsave_tmpBufferPtr
|
||||
|
||||
3:
|
||||
ldrb r3, [r1, r2]
|
||||
strb r3, [r0, r2]
|
||||
adds r2, #1
|
||||
subs r7, #1
|
||||
bne 3b
|
||||
|
||||
cmp r4, #0
|
||||
bne 1b
|
||||
|
||||
end:
|
||||
pop {r4,r5,r6,r7,pc}
|
||||
|
||||
blx_r3:
|
||||
bx r3
|
||||
|
||||
.balign 4
|
||||
|
||||
.global readsave_tmpBufferPtr
|
||||
readsave_tmpBufferPtr:
|
||||
.word 0
|
||||
|
||||
.global readsave_save_offset_to_sd_sector_asm_address
|
||||
readsave_save_offset_to_sd_sector_asm_address:
|
||||
.word 0
|
||||
|
||||
.global readsave_sdread_asm_address
|
||||
readsave_sdread_asm_address:
|
||||
.word 0
|
||||
|
||||
.pool
|
||||
|
||||
.end
|
||||
25
arm9/source/patches/arm7/SaveOffsetToSdSectorAsm.h
Normal file
25
arm9/source/patches/arm7/SaveOffsetToSdSectorAsm.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
#include "sections.h"
|
||||
#include "../SectorRemapPatchCode.h"
|
||||
#include "fileInfo.h"
|
||||
|
||||
DEFINE_SECTION_SYMBOLS(saveoffsettosdsector);
|
||||
|
||||
extern "C" u32 save_offset_to_sd_sector_asm(u32 saveOffset);
|
||||
|
||||
extern u32 saveoffsettosdsector_fatDataPtr;
|
||||
|
||||
class SaveOffsetToSdSectorPatchCode : public SectorRemapPatchCode
|
||||
{
|
||||
public:
|
||||
SaveOffsetToSdSectorPatchCode(PatchHeap& patchHeap, const save_file_info_t* fatDataPtr)
|
||||
: SectorRemapPatchCode(SECTION_START(saveoffsettosdsector), SECTION_SIZE(saveoffsettosdsector), patchHeap)
|
||||
{
|
||||
saveoffsettosdsector_fatDataPtr = (u32)fatDataPtr;
|
||||
}
|
||||
|
||||
const void* GetRemapFunction() const override
|
||||
{
|
||||
return GetAddressAtTarget((void*)save_offset_to_sd_sector_asm);
|
||||
}
|
||||
};
|
||||
50
arm9/source/patches/arm7/SaveOffsetToSdSectorAsm.s
Normal file
50
arm9/source/patches/arm7/SaveOffsetToSdSectorAsm.s
Normal file
@@ -0,0 +1,50 @@
|
||||
.cpu arm7tdmi
|
||||
.section "saveoffsettosdsector", "ax"
|
||||
.syntax unified
|
||||
.thumb
|
||||
|
||||
// r0 = save offset
|
||||
// returns sd sector in r0
|
||||
// returns cluster shift in r1
|
||||
// returns remaining sectors in cluster in lr
|
||||
.global save_offset_to_sd_sector_asm
|
||||
.type save_offset_to_sd_sector_asm, %function
|
||||
save_offset_to_sd_sector_asm:
|
||||
push {r4,r5,lr}
|
||||
retry:
|
||||
ldr r5, saveoffsettosdsector_fatDataPtr
|
||||
ldmia r5!, {r1,r2,r3,r4} // clusterShift, database, clusterMask, clusterMap[0]
|
||||
lsrs r0, r0, #9
|
||||
adds r4, r3, #1
|
||||
ands r3, r0
|
||||
subs r4, r3
|
||||
mov lr, r4 // remaining sectors in cluster
|
||||
adds r3, r2
|
||||
lsrs r0, r1 // cl
|
||||
1:
|
||||
ldmia r5!, {r2,r4} // ncl, startSector
|
||||
cmp r2, #0
|
||||
beq out_of_bounds
|
||||
subs r0, r2 // cl -= ncl
|
||||
bcs 1b
|
||||
|
||||
adds r0, r2
|
||||
adds r0, r4 // + startSector
|
||||
subs r0, #2 // - 2
|
||||
lsls r0, r1
|
||||
adds r0, r3 // r0 = src sector
|
||||
pop {r4,r5,pc}
|
||||
|
||||
out_of_bounds:
|
||||
movs r0, #0
|
||||
pop {r4,r5,pc}
|
||||
|
||||
.balign 4
|
||||
|
||||
.global saveoffsettosdsector_fatDataPtr
|
||||
saveoffsettosdsector_fatDataPtr:
|
||||
.word 0x027FFA00
|
||||
|
||||
.pool
|
||||
|
||||
.end
|
||||
34
arm9/source/patches/arm7/WriteSaveAsm.h
Normal file
34
arm9/source/patches/arm7/WriteSaveAsm.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
#include "sections.h"
|
||||
#include "../PatchCode.h"
|
||||
#include "../SectorRemapPatchCode.h"
|
||||
#include "../platform/SdReadPatchCode.h"
|
||||
#include "../platform/SdWritePatchCode.h"
|
||||
|
||||
DEFINE_SECTION_SYMBOLS(writesave);
|
||||
|
||||
extern "C" void writesave_asm(u32, const void* memorySrc, u32 saveDst, u32 byteLength);
|
||||
|
||||
extern u32 writesave_tmpBufferPtr;
|
||||
extern u32 writesave_save_offset_to_sd_sector_asm_address;
|
||||
extern u32 writesave_sdread_asm_address;
|
||||
extern u32 writesave_sdwrite_asm_address;
|
||||
|
||||
class WriteSavePatchCode : public PatchCode
|
||||
{
|
||||
public:
|
||||
WriteSavePatchCode(PatchHeap& patchHeap, const SectorRemapPatchCode* sectorRemapPatchCode,
|
||||
const SdReadPatchCode* sdReadPatchCode, const SdWritePatchCode* sdWritePatchCode, void* tmpBuffer)
|
||||
: PatchCode(SECTION_START(writesave), SECTION_SIZE(writesave), patchHeap)
|
||||
{
|
||||
writesave_save_offset_to_sd_sector_asm_address = (u32)sectorRemapPatchCode->GetRemapFunction();
|
||||
writesave_sdread_asm_address = (u32)sdReadPatchCode->GetSdReadFunction();
|
||||
writesave_sdwrite_asm_address = (u32)sdWritePatchCode->GetSdWriteFunction();
|
||||
writesave_tmpBufferPtr = (u32)tmpBuffer;
|
||||
}
|
||||
|
||||
const void* GetWriteSaveFunction() const
|
||||
{
|
||||
return GetAddressAtTarget((void*)writesave_asm);
|
||||
}
|
||||
};
|
||||
86
arm9/source/patches/arm7/WriteSaveAsm.s
Normal file
86
arm9/source/patches/arm7/WriteSaveAsm.s
Normal file
@@ -0,0 +1,86 @@
|
||||
.cpu arm7tdmi
|
||||
.section "writesave", "ax"
|
||||
.syntax unified
|
||||
.thumb
|
||||
|
||||
// r1 = memory src
|
||||
// r2 = save dst
|
||||
// r3 = byte length
|
||||
.global writesave_asm
|
||||
.type writesave_asm, %function
|
||||
writesave_asm:
|
||||
push {r4,r5,r6,r7,lr}
|
||||
movs r4, r3 // remaining bytes
|
||||
movs r5, r2
|
||||
movs r6, r1
|
||||
1:
|
||||
movs r0, r5 // will be rounded down by function
|
||||
ldr r3, writesave_save_offset_to_sd_sector_asm_address
|
||||
bl blx_r3
|
||||
cmp r0, #0
|
||||
beq end // out of bounds
|
||||
|
||||
push {r0}
|
||||
|
||||
ldr r1, writesave_tmpBufferPtr
|
||||
movs r2, #1 // single sector
|
||||
lsls r7, r2, #9 // 512
|
||||
ldr r3, writesave_sdread_asm_address
|
||||
bl blx_r3
|
||||
|
||||
// copy bytes
|
||||
lsls r2, r5, #23
|
||||
lsrs r2, r2, #23 // r2 = byte offset in sector
|
||||
subs r0, r6, r2
|
||||
subs r7, r7, r2 // remaining in sector
|
||||
cmp r7, r4 // if remaining in sector > requested read length
|
||||
bls 2f
|
||||
movs r7, r4 // clamp to requested read length
|
||||
2:
|
||||
subs r4, r7
|
||||
adds r5, r7
|
||||
adds r6, r7
|
||||
ldr r1, writesave_tmpBufferPtr
|
||||
|
||||
3:
|
||||
ldrb r3, [r0, r2]
|
||||
strb r3, [r1, r2]
|
||||
adds r2, #1
|
||||
subs r7, #1
|
||||
bne 3b
|
||||
|
||||
pop {r0}
|
||||
movs r2, #1 // single sector
|
||||
ldr r3, writesave_sdwrite_asm_address
|
||||
bl blx_r3
|
||||
|
||||
cmp r4, #0
|
||||
bne 1b
|
||||
|
||||
end:
|
||||
pop {r4,r5,r6,r7,pc}
|
||||
|
||||
blx_r3:
|
||||
bx r3
|
||||
|
||||
.balign 4
|
||||
|
||||
.global writesave_tmpBufferPtr
|
||||
writesave_tmpBufferPtr:
|
||||
.word 0
|
||||
|
||||
.global writesave_save_offset_to_sd_sector_asm_address
|
||||
writesave_save_offset_to_sd_sector_asm_address:
|
||||
.word 0
|
||||
|
||||
.global writesave_sdread_asm_address
|
||||
writesave_sdread_asm_address:
|
||||
.word 0
|
||||
|
||||
.global writesave_sdwrite_asm_address
|
||||
writesave_sdwrite_asm_address:
|
||||
.word 0
|
||||
|
||||
.pool
|
||||
|
||||
.end
|
||||
285
arm9/source/patches/arm7/sdk2to4/CardiTaskThreadPatch.cpp
Normal file
285
arm9/source/patches/arm7/sdk2to4/CardiTaskThreadPatch.cpp
Normal file
@@ -0,0 +1,285 @@
|
||||
#include "common.h"
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include "fileInfo.h"
|
||||
#include "patches/PatchContext.h"
|
||||
#include "patches/arm7/ReadSaveAsm.h"
|
||||
#include "patches/arm7/WriteSaveAsm.h"
|
||||
#include "patches/FunctionSignature.h"
|
||||
#include "patches/platform/LoaderPlatform.h"
|
||||
#include "patches/arm7/SaveOffsetToSdSectorAsm.h"
|
||||
#include "patches/OffsetToSectorRemapAsm.h"
|
||||
#include "patches/arm7/CardiTaskThreadPatchAsm.h"
|
||||
#include "thumbInstructions.h"
|
||||
#include "CardiTaskThreadPatch.h"
|
||||
|
||||
static constexpr auto sSignaturesArm = std::to_array<const FunctionSignature>
|
||||
({
|
||||
{ (const u32[]) { 0xE92D4FF0u, 0xE24DD004u, 0xE59FA108u, 0xE28A5040u }, 0x020029A0, 0x02005015 },
|
||||
{ (const u32[]) { 0xE92D4FF0u, 0xE24DD004u, 0xE59FA10Cu, 0xE28A5040u }, 0x02004F50, 0x02017532 },
|
||||
{ (const u32[]) { 0xE92D4FF0u, 0xE24DD004u, 0xE59F91DCu, 0xE2895044u }, 0x02017532, 0x02017532 },
|
||||
{ (const u32[]) { 0xE92D4FF0u, 0xE24DD004u, 0xE59F91E0u, 0xE2895044u }, 0x02017532, 0x02027534 },
|
||||
{ (const u32[]) { 0xE92D4FF0u, 0xE24DD004u, 0xE59F91E0u, 0xE2895048u }, 0x030028A0, 0x03004E86 },
|
||||
{ (const u32[]) { 0xE92D4FF0u, 0xE24DD004u, 0xE59F91D4u, 0xE2895048u }, 0x03004F4C, 0x03017534 },
|
||||
{ (const u32[]) { 0xE92D4FF0u, 0xE24DD004u, 0xE59F91F8u, 0xE2895048u }, 0x03017530, 0x04017530 },
|
||||
{ (const u32[]) { 0xE92D41F0u, 0xE59F4200u, 0xE3A05000u, 0xEBFFEADCu }, 0x04002774, 0x04017533 },
|
||||
{ (const u32[]) { 0xE92D41F0u, 0xE59F4200u, 0xE3A05000u, 0xEBFFEACEu }, 0x04007531, 0x04007531 },
|
||||
{ (const u32[]) { 0xE92D41F0u, 0xE59F4200u, 0xE3A05000u, 0xEBFFEABFu }, 0x04007530, 0x04007531 },
|
||||
{ (const u32[]) { 0xE92D41F0u, 0xE59F4200u, 0xE3A05000u, 0xEBFFEAAAu }, 0x04017530, 0x04017533 },
|
||||
{ (const u32[]) { 0xE92D41F0u, 0xE59F4200u, 0xE3A05000u, 0xEBFFEA94u }, 0x04017530, 0x04017533 },
|
||||
{ (const u32[]) { 0xE92D41F0u, 0xE59F4200u, 0xE3A05000u, 0xEBFFEA8Du }, 0x04017531, 0x04017533 },
|
||||
{ (const u32[]) { 0xE92D41F0u, 0xE59F4200u, 0xE3A05000u, 0xEBFFEA77u }, 0x04017533, 0x04017533 },
|
||||
{ (const u32[]) { 0xE92D41F0u, 0xE59F4224u, 0xE3A05000u, 0xEBFFEA70u }, 0x04027530, 0x04027539 },
|
||||
{ (const u32[]) { 0xE92D41F0u, 0xE59F4224u, 0xE3A05000u, 0xEBFFEA8Du }, 0x04027530, 0x04027539 },
|
||||
{ (const u32[]) { 0xE92D41F0u, 0xE59F4224u, 0xE3A05000u, 0xEBFFEA6Cu }, 0x04027531, 0x04027531 },
|
||||
{ (const u32[]) { 0xE92D41F0u, 0xE59F4224u, 0xE3A05000u, 0xEBFFEA77u }, 0x04027531, 0x04027539 },
|
||||
{ (const u32[]) { 0xE92D41F0u, 0xE59F4224u, 0xE3A05000u, 0xEBFFEA5Au }, 0x04027533, 0x04027533 },
|
||||
{ (const u32[]) { 0xE92D41F0u, 0xE59F4200u, 0xE3A05000u, 0xEBFFFAD7u }, 0x03017531, 0x03017531 },
|
||||
{ (const u32[]) { 0xE92D41F0u, 0xE59F4200u, 0xE3A05000u, 0xEBFFFAA5u }, 0x03027531, 0x03027531 },
|
||||
{ (const u32[]) { 0xE92D41F0u, 0xE59F4200u, 0xE3A05000u, 0xEBFFEADBu }, 0x03027531, 0x03027531 },
|
||||
{ (const u32[]) { 0xE92D41F0u, 0xE59F4224u, 0xE3A05000u, 0xEBFFEA68u }, 0x04027533, 0x04027533 }
|
||||
});
|
||||
|
||||
static constexpr auto sSignaturesThumb = std::to_array<const FunctionSignature>
|
||||
({
|
||||
{ (const u32[]) { 0xB081B5F0u, 0x1C2E4D2Du, 0x27103640u, 0xF7FC2400u }, 0x02004FB0, 0x02004FB4 },
|
||||
{ (const u32[]) { 0xB081B5F0u, 0x1C2E4D2Bu, 0x27103640u, 0xF7FC2400u }, 0x02007531, 0x02017532 },
|
||||
{ (const u32[]) { 0xB081B5F0u, 0x1C264C57u, 0x27103644u, 0xF7FC2500u }, 0x02027532, 0x02027535 },
|
||||
{ (const u32[]) { 0xB081B5F0u, 0x1C264C55u, 0x27103648u, 0xF7FC2500u }, 0x03007530, 0x03012776 },
|
||||
{ (const u32[]) { 0xB081B5F0u, 0x1C264C5Cu, 0x27033648u, 0xF7FC2500u }, 0x03017531, 0x03027532 },
|
||||
{ (const u32[]) { 0x4C5CB5F8u, 0xF7FC2500u, 0x1C26FAB3u, 0x36481C07u }, 0x04007531, 0x04007531 },
|
||||
{ (const u32[]) { 0x4C5CB5F8u, 0xF7FC2500u, 0x1C26FA97u, 0x36481C07u }, 0x04007531, 0x04007531 },
|
||||
{ (const u32[]) { 0x4C5CB5F8u, 0xF7FC2500u, 0x1C26FA4Fu, 0x36481C07u }, 0x04017530, 0x04017533 },
|
||||
{ (const u32[]) { 0x4C5CB5F8u, 0xF7FC2500u, 0x1C26FA23u, 0x36481C07u }, 0x04017531, 0x04017531 },
|
||||
{ (const u32[]) { 0x4D62B5F8u, 0xF7FC2400u, 0x1C2EFA2Du, 0x36481C07u }, 0x04027531, 0x04027539 }
|
||||
});
|
||||
|
||||
bool CardiTaskThreadPatch::FindPatchTarget(PatchContext& patchContext)
|
||||
{
|
||||
for (const auto& signature : sSignaturesArm)
|
||||
{
|
||||
if (CheckSignature(patchContext, signature))
|
||||
{
|
||||
if (signature.GetPattern()[2] == 0xE59F91DCu)
|
||||
{
|
||||
_peach = true;
|
||||
}
|
||||
else if (signature.GetPattern()[3] == 0xEBFFFAD7u
|
||||
|| signature.GetPattern()[3] == 0xEBFFFAA5u
|
||||
|| signature.GetPattern()[3] == 0xEBFFEADBu)
|
||||
{
|
||||
_pokemonDownloader = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_cardiTaskThread)
|
||||
{
|
||||
for (const auto& signature : sSignaturesThumb)
|
||||
{
|
||||
if (CheckSignature(patchContext, signature))
|
||||
{
|
||||
_thumb = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!_cardiTaskThread)
|
||||
{
|
||||
LOG_FATAL("CARDi_TaskThread not found\n");
|
||||
}
|
||||
|
||||
return _cardiTaskThread != nullptr;
|
||||
}
|
||||
|
||||
void CardiTaskThreadPatch::ApplyPatch(PatchContext& patchContext)
|
||||
{
|
||||
if (!_cardiTaskThread)
|
||||
return;
|
||||
//0xA4 = ADDLS PC, PC, R0,LSL#2
|
||||
|
||||
u32 patch1Size = SECTION_SIZE(patch_carditaskthread);
|
||||
void* patch1Address = patchContext.GetPatchHeap().Alloc(patch1Size);
|
||||
auto loaderPlatform = patchContext.GetLoaderPlatform();
|
||||
const SdReadPatchCode* readPatchCode;
|
||||
const SdWritePatchCode* writePatchCode;
|
||||
const SectorRemapPatchCode* sectorRemapPatchCode;
|
||||
readPatchCode = loaderPlatform->CreateSdReadPatchCode(
|
||||
patchContext.GetPatchCodeCollection(), patchContext.GetPatchHeap());
|
||||
writePatchCode = loaderPlatform->CreateSdWritePatchCode(
|
||||
patchContext.GetPatchCodeCollection(), patchContext.GetPatchHeap());
|
||||
sectorRemapPatchCode = patchContext.GetPatchCodeCollection().AddUniquePatchCode<SaveOffsetToSdSectorPatchCode>
|
||||
(
|
||||
patchContext.GetPatchHeap(),
|
||||
(const save_file_info_t*)((u32)SHARED_SAVE_FILE_INFO - 0x02F00000 + 0x02700000)
|
||||
);
|
||||
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 entryAddress;
|
||||
u32 patchOffset;
|
||||
if (_thumb)
|
||||
{
|
||||
if (patchContext.GetSdkVersion() >= 0x4027531)
|
||||
{
|
||||
patchOffset = 0x90;
|
||||
entryAddress = (u32)&__patch_carditaskthread_entry - (u32)SECTION_START(patch_carditaskthread) + (u32)patch1Address;
|
||||
__patch_carditaskthread_mov_cardicommon_to_r4 = THUMB_MOVS_REG(THUMB_R4, THUMB_R5);
|
||||
__patch_carditaskthread_successoffset = *(u16*)((u8*)_cardiTaskThread + patchOffset + 0x0C) + 9;
|
||||
__patch_carditaskthread_failoffset = *(u16*)((u8*)_cardiTaskThread + patchOffset + 0x14) + 9;
|
||||
|
||||
*(u16*)((u8*)_cardiTaskThread + patchOffset + 0x00) = THUMB_LDR_PC_IMM(THUMB_R1, 4);
|
||||
*(u16*)((u8*)_cardiTaskThread + patchOffset + 0x02) = THUMB_MOV_HIREG(THUMB_HI_LR, THUMB_HI_PC);
|
||||
*(u16*)((u8*)_cardiTaskThread + patchOffset + 0x04) = THUMB_BX(THUMB_R1);
|
||||
*(u32*)((u8*)_cardiTaskThread + patchOffset + 0x08) = entryAddress;
|
||||
}
|
||||
else if (patchContext.GetSdkVersion() >= 0x4007530)
|
||||
{
|
||||
patchOffset = 0x90;
|
||||
entryAddress = (u32)&__patch_carditaskthread_entry - (u32)SECTION_START(patch_carditaskthread) + (u32)patch1Address;
|
||||
__patch_carditaskthread_mov_cardicommon_to_r4 = THUMB_NOP;
|
||||
__patch_carditaskthread_successoffset = *(u16*)((u8*)_cardiTaskThread + patchOffset + 0x0C) + 9;
|
||||
__patch_carditaskthread_failoffset = *(u16*)((u8*)_cardiTaskThread + patchOffset + 0x14) + 9;
|
||||
|
||||
*(u16*)((u8*)_cardiTaskThread + patchOffset + 0x00) = THUMB_LDR_PC_IMM(THUMB_R1, 4);
|
||||
*(u16*)((u8*)_cardiTaskThread + patchOffset + 0x02) = THUMB_MOV_HIREG(THUMB_HI_LR, THUMB_HI_PC);
|
||||
*(u16*)((u8*)_cardiTaskThread + patchOffset + 0x04) = THUMB_BX(THUMB_R1);
|
||||
*(u32*)((u8*)_cardiTaskThread + patchOffset + 0x08) = entryAddress;
|
||||
}
|
||||
else if (patchContext.GetSdkVersion() >= 0x3027531)
|
||||
{
|
||||
patchOffset = 0x98;
|
||||
entryAddress = (u32)&__patch_carditaskthread_entry - (u32)SECTION_START(patch_carditaskthread) + (u32)patch1Address;
|
||||
__patch_carditaskthread_mov_cardicommon_to_r4 = THUMB_NOP;
|
||||
__patch_carditaskthread_successoffset = *(u16*)((u8*)_cardiTaskThread + patchOffset + 0x0E) + 8;
|
||||
__patch_carditaskthread_failoffset = *(u16*)((u8*)_cardiTaskThread + patchOffset + 0x18) + 8;
|
||||
|
||||
*(u16*)((u8*)_cardiTaskThread + patchOffset + 0x00) = THUMB_LDR_PC_IMM(THUMB_R1, 4);
|
||||
*(u16*)((u8*)_cardiTaskThread + patchOffset + 0x02) = THUMB_MOV_HIREG(THUMB_HI_LR, THUMB_HI_PC);
|
||||
*(u16*)((u8*)_cardiTaskThread + patchOffset + 0x04) = THUMB_BX(THUMB_R1);
|
||||
*(u32*)((u8*)_cardiTaskThread + patchOffset + 0x08) = entryAddress;
|
||||
}
|
||||
else if (patchContext.GetSdkVersion() >= 0x3012776
|
||||
|| (patchContext.GetSdkVersion() >= 0x2027532 && patchContext.GetSdkVersion() <= 0x2027535))
|
||||
{
|
||||
patchOffset = 0x82;
|
||||
entryAddress = (u32)&__patch_carditaskthread_entry - (u32)SECTION_START(patch_carditaskthread) + (u32)patch1Address;
|
||||
__patch_carditaskthread_mov_cardicommon_to_r4 = THUMB_NOP;
|
||||
__patch_carditaskthread_successoffset = *(u16*)((u8*)_cardiTaskThread + patchOffset + 0x0E) + 8;
|
||||
__patch_carditaskthread_failoffset = *(u16*)((u8*)_cardiTaskThread + patchOffset + 0x18) + 8;
|
||||
|
||||
*(u16*)((u8*)_cardiTaskThread + patchOffset + 0x00) = THUMB_LDR_PC_IMM(THUMB_R1, 4);
|
||||
*(u16*)((u8*)_cardiTaskThread + patchOffset + 0x02) = THUMB_MOV_HIREG(THUMB_HI_LR, THUMB_HI_PC);
|
||||
*(u16*)((u8*)_cardiTaskThread + patchOffset + 0x04) = THUMB_BX(THUMB_R1);
|
||||
*(u32*)((u8*)_cardiTaskThread + patchOffset + 0x06) = entryAddress;
|
||||
}
|
||||
else if (patchContext.GetSdkVersion() >= 0x2004FB0)
|
||||
{
|
||||
patchOffset = patchContext.GetSdkVersion() >= 0x2007531 ? 0x60 : 0x64;
|
||||
entryAddress = (u32)&__patch_carditaskthread_entry - (u32)SECTION_START(patch_carditaskthread) + (u32)patch1Address;
|
||||
__patch_carditaskthread_mov_cardicommon_to_r4 = THUMB_MOVS_REG(THUMB_R4, THUMB_R5);
|
||||
__patch_carditaskthread_failoffset = 0;
|
||||
__patch_carditaskthread_successoffset = 0;
|
||||
*(u16*)((u8*)_cardiTaskThread + patchOffset + 0x00) = THUMB_LDR_PC_IMM(THUMB_R1, 0);
|
||||
*(u16*)((u8*)_cardiTaskThread + patchOffset + 0x02) = 0xE001; // jump over entryAddress
|
||||
*(u32*)((u8*)_cardiTaskThread + patchOffset + 0x04) = entryAddress;
|
||||
*(u16*)((u8*)_cardiTaskThread + patchOffset + 0x08) = THUMB_NOP;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_FATAL("Unsupported thumb CARDi_TaskThread\n");
|
||||
while(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (patchContext.GetSdkVersion() < 0x2020000 && !_peach)
|
||||
{
|
||||
// uses a table dispatch
|
||||
//0xA4 = ldr r1,= table
|
||||
__patch_carditaskthread_failoffset = 4;
|
||||
__patch_carditaskthread_successoffset = 4;
|
||||
if (patchContext.GetSdkVersion() >= 0x2005015)//0x2007532)//0x2012774)
|
||||
patchOffset = 0xA4;
|
||||
else
|
||||
patchOffset = 0xA0;
|
||||
|
||||
entryAddress = (u32)&__patch_carditaskthread_entry - (u32)SECTION_START(patch_carditaskthread) + (u32)patch1Address;
|
||||
__patch_carditaskthread_mov_cardicommon_to_r4 = THUMB_MOV_HIREG(THUMB_R4, THUMB_HI_R10);
|
||||
|
||||
*(u32*)((u8*)_cardiTaskThread + patchOffset + 0x00) = 0xe59f0004; // ldr r0,= entryAddress
|
||||
*(u32*)((u8*)_cardiTaskThread + patchOffset + 0x04) = 0xe1a0e00f; // mov lr, pc
|
||||
*(u32*)((u8*)_cardiTaskThread + patchOffset + 0x08) = 0xe12fff10; // bx r0
|
||||
*(u32*)((u8*)_cardiTaskThread + patchOffset + 0x0C) = entryAddress;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (patchContext.GetSdkVersion() >= 0x4027531)
|
||||
{
|
||||
patchOffset = 0xA8;
|
||||
entryAddress = (u32)&__patch_carditaskthread_entry_sdk4 - (u32)SECTION_START(patch_carditaskthread) + (u32)patch1Address;
|
||||
__patch_carditaskthread_mov_cardicommon_to_r4 = THUMB_NOP;
|
||||
}
|
||||
else if (patchContext.GetSdkVersion() >= 0x4007530 || _pokemonDownloader)
|
||||
{
|
||||
patchOffset = 0xA8;
|
||||
entryAddress = (u32)&__patch_carditaskthread_entry - (u32)SECTION_START(patch_carditaskthread) + (u32)patch1Address;
|
||||
__patch_carditaskthread_mov_cardicommon_to_r4 = THUMB_NOP;
|
||||
}
|
||||
else if (patchContext.GetSdkVersion() >= 0x3017531)
|
||||
{
|
||||
patchOffset = 0xB4;
|
||||
entryAddress = (u32)&__patch_carditaskthread_entry - (u32)SECTION_START(patch_carditaskthread) + (u32)patch1Address;
|
||||
__patch_carditaskthread_mov_cardicommon_to_r4 = THUMB_MOV_HIREG(THUMB_R4, THUMB_HI_R9);
|
||||
}
|
||||
else
|
||||
{
|
||||
patchOffset = 0x9C;
|
||||
entryAddress = (u32)&__patch_carditaskthread_entry - (u32)SECTION_START(patch_carditaskthread) + (u32)patch1Address;
|
||||
__patch_carditaskthread_mov_cardicommon_to_r4 = THUMB_MOV_HIREG(THUMB_R4, THUMB_HI_R9);
|
||||
}
|
||||
|
||||
*(u32*)((u8*)_cardiTaskThread + patchOffset + 0x00) = 0xe59f000C; // ldr r0,= entryAddress
|
||||
*(u32*)((u8*)_cardiTaskThread + patchOffset + 0x04) = 0xe1a0e00f; // mov lr, pc
|
||||
*(u32*)((u8*)_cardiTaskThread + patchOffset + 0x08) = 0xe12fff10; // bx r0
|
||||
*(u32*)((u8*)_cardiTaskThread + patchOffset + 0x14) = entryAddress;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(patch1Address, SECTION_START(patch_carditaskthread), patch1Size);
|
||||
}
|
||||
|
||||
bool CardiTaskThreadPatch::CheckSignature(const PatchContext& patchContext, const FunctionSignature& signature)
|
||||
{
|
||||
if (patchContext.GetSdkVersion() >= signature.GetMinimumSdkVersion() &&
|
||||
patchContext.GetSdkVersion() <= signature.GetMaximumSdkVersion())
|
||||
{
|
||||
_cardiTaskThread = patchContext.FindPattern32(signature.GetPattern(), 16);
|
||||
if (_cardiTaskThread)
|
||||
{
|
||||
LOG_DEBUG("CARDi_TaskThread found at 0x%p\n", _cardiTaskThread);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
20
arm9/source/patches/arm7/sdk2to4/CardiTaskThreadPatch.h
Normal file
20
arm9/source/patches/arm7/sdk2to4/CardiTaskThreadPatch.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
#include "patches/Patch.h"
|
||||
|
||||
class FunctionSignature;
|
||||
|
||||
/// @brief Arm7 patch for redirecting save reads and writes on SDK 2-4.
|
||||
class CardiTaskThreadPatch : public Patch
|
||||
{
|
||||
public:
|
||||
bool FindPatchTarget(PatchContext& patchContext) override;
|
||||
void ApplyPatch(PatchContext& patchContext) override;
|
||||
|
||||
private:
|
||||
u32* _cardiTaskThread = nullptr;
|
||||
u16 _thumb = false;
|
||||
u16 _peach = false;
|
||||
u16 _pokemonDownloader = false;
|
||||
|
||||
bool CheckSignature(const PatchContext& patchContext, const FunctionSignature& signature);
|
||||
};
|
||||
139
arm9/source/patches/arm7/sdk5/CardiDoTaskFromArm9Patch.cpp
Normal file
139
arm9/source/patches/arm7/sdk5/CardiDoTaskFromArm9Patch.cpp
Normal 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);
|
||||
}
|
||||
17
arm9/source/patches/arm7/sdk5/CardiDoTaskFromArm9Patch.h
Normal file
17
arm9/source/patches/arm7/sdk5/CardiDoTaskFromArm9Patch.h
Normal 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);
|
||||
};
|
||||
14
arm9/source/patches/arm7/sdk5/CardiDoTaskFromArm9PatchAsm.h
Normal file
14
arm9/source/patches/arm7/sdk5/CardiDoTaskFromArm9PatchAsm.h
Normal 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;
|
||||
82
arm9/source/patches/arm7/sdk5/Sdk5DsiSdCardRedirectPatch.cpp
Normal file
82
arm9/source/patches/arm7/sdk5/Sdk5DsiSdCardRedirectPatch.cpp
Normal 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();
|
||||
}
|
||||
}
|
||||
14
arm9/source/patches/arm7/sdk5/Sdk5DsiSdCardRedirectPatch.h
Normal file
14
arm9/source/patches/arm7/sdk5/Sdk5DsiSdCardRedirectPatch.h
Normal 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;
|
||||
};
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user