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:
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