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:
142
arm9/source/patches/arm9/CardiReadRomIdCorePatch.cpp
Normal file
142
arm9/source/patches/arm9/CardiReadRomIdCorePatch.cpp
Normal file
@@ -0,0 +1,142 @@
|
||||
#include "common.h"
|
||||
#include "thumbInstructions.h"
|
||||
#include "../PatchContext.h"
|
||||
#include "../FunctionSignature.h"
|
||||
#include "CardiReadRomIdCorePatchAsm.h"
|
||||
#include "CardiReadRomIdCorePatch.h"
|
||||
|
||||
static constexpr auto sSignaturesArm = std::to_array<const FunctionSignature>
|
||||
({
|
||||
{ (const u32[]) { 0xE92D4000u, 0xE24DD004u, 0xE3A0032Eu, 0xE3A01000u }, 0x02004F50, 0x04017531 },
|
||||
{ (const u32[]) { 0xE92D4008u, 0xE3A0032Eu, 0xE3A01000u, 0xEBFFFF0Bu }, 0x03007532, 0x03017531 },
|
||||
{ (const u32[]) { 0xE92D4008u, 0xE3A0032Eu, 0xE3A01000u, 0xEBFFFF08u }, 0x03017530, 0x03017534 },
|
||||
{ (const u32[]) { 0xE92D4008u, 0xE3A0032Eu, 0xE3A01000u, 0xEBFFFF07u }, 0x03027530, 0x04007531 },
|
||||
{ (const u32[]) { 0xE92D4008u, 0xE3A0032Eu, 0xE3A01000u, 0xEBFFFEF2u }, 0x04007531, 0x04007531 },
|
||||
{ (const u32[]) { 0xE92D4008u, 0xE3A0032Eu, 0xE3A01000u, 0xEBFFFEFDu }, 0x04007532, 0x04007532 },
|
||||
{ (const u32[]) { 0xE92D4008u, 0xE3A0032Eu, 0xE3A01000u, 0xEBFFFEFBu }, 0x04017530, 0x04027539 },
|
||||
{ (const u32[]) { 0xE92D4008u, 0xE3A0032Eu, 0xE3A01000u, 0xEBFFFEE6u }, 0x04017533, 0x04017533 },
|
||||
{ (const u32[]) { 0xE92D4010u, 0xE3A04000u, 0xE1A01004u, 0xE3A0032Eu }, 0x04027537, 0x04027539 }
|
||||
});
|
||||
|
||||
static constexpr auto sSignaturesThumb = std::to_array<const FunctionSignature>
|
||||
({
|
||||
{ (const u32[]) { 0xB081B500u, 0x2100480Bu, 0xF98AF000u, 0x6801480Au }, 0x03007530, 0x03012776 },
|
||||
{ (const u32[]) { 0xB081B500u, 0x2100480Bu, 0xF990F000u, 0x6801480Au }, 0x03007532, 0x03007532 },
|
||||
{ (const u32[]) { 0x202EB508u, 0x21000680u, 0xFE8CF7FFu, 0x68014809u }, 0x03017531, 0x03017531 },
|
||||
{ (const u32[]) { 0xB081B500u, 0x2100480Bu, 0xF98EF000u, 0x6801480Au }, 0x03017531, 0x03017534 },
|
||||
{ (const u32[]) { 0xB081B500u, 0x2100480Cu, 0xF992F000u, 0x6800480Bu }, 0x03027530, 0x03027532 },
|
||||
{ (const u32[]) { 0x202EB508u, 0x21000680u, 0xFE8AF7FFu, 0x6800480Au }, 0x03027530, 0x04007531 },
|
||||
{ (const u32[]) { 0x202EB508u, 0x21000680u, 0xFE74F7FFu, 0x6800480Au }, 0x04017530, 0x04027539 },
|
||||
{ (const u32[]) { 0x202EB508u, 0x21000680u, 0xFE62F7FFu, 0x6800480Au }, 0x04027531, 0x04027531 },
|
||||
{ (const u32[]) { 0x202EB508u, 0x21000680u, 0xFE56F7FFu, 0x6800480Au }, 0x04027537, 0x04027537 }
|
||||
});
|
||||
|
||||
static constexpr auto sSignaturesArmSdk5 = std::to_array<const FunctionSignature>
|
||||
({
|
||||
{ (const u32[]) { 0xE92D4010u, 0xE3A040B8u, 0xEBFFFFD6u, 0xE3500000u }, 0x0500753B, 0x05027534 },
|
||||
{ (const u32[]) { 0xE92D4008u, 0xE3A000B8u, 0xE3A01000u, 0xEBFFFFCEu }, 0x05017536, 0x05047531 },
|
||||
{ (const u32[]) { 0xE92D4038u, 0xE3A050B8u, 0xEBFFFFD7u, 0xE3500000u }, 0x05017537, 0x05057535 },
|
||||
{ (const u32[]) { 0xE92D4010u, 0xE3A04000u, 0xE1A01004u, 0xE3A000B8u }, 0x05037531, 0x05057535 }
|
||||
});
|
||||
|
||||
static constexpr auto sSignaturesThumbSdk5 = std::to_array<const FunctionSignature>
|
||||
({
|
||||
{ (const u32[]) { 0x24B8B510u, 0xFFC4F7FFu, 0xD0002800u, 0x1C202490u }, 0x05007538, 0x05017537 },
|
||||
{ (const u32[]) { 0x20B8B508u, 0xF7FF2100u, 0x480AFFABu, 0x480A6801u }, 0x05017537, 0x05057535 },
|
||||
{ (const u32[]) { 0x24B8B510u, 0xFFC6F7FFu, 0xD0002800u, 0x1C202490u }, 0x05037531, 0x05057534 }
|
||||
});
|
||||
|
||||
bool CardiReadRomIdCorePatch::FindPatchTarget(PatchContext& patchContext)
|
||||
{
|
||||
if (patchContext.GetSdkVersion().IsTwlSdk())
|
||||
{
|
||||
for (const auto& signature : sSignaturesArmSdk5)
|
||||
{
|
||||
if (CheckSignature(patchContext, signature))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_cardiReadRomIdCore)
|
||||
{
|
||||
for (const auto& signature : sSignaturesThumbSdk5)
|
||||
{
|
||||
if (CheckSignature(patchContext, signature))
|
||||
{
|
||||
_thumb = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const auto& signature : sSignaturesArm)
|
||||
{
|
||||
if (CheckSignature(patchContext, signature))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_cardiReadRomIdCore)
|
||||
{
|
||||
for (const auto& signature : sSignaturesThumb)
|
||||
{
|
||||
if (CheckSignature(patchContext, signature))
|
||||
{
|
||||
_thumb = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!_cardiReadRomIdCore)
|
||||
{
|
||||
LOG_WARNING("CARDi_ReadRomIDCore not found\n");
|
||||
}
|
||||
|
||||
return true; //_cardiReadRomIdCore != nullptr;
|
||||
}
|
||||
|
||||
void CardiReadRomIdCorePatch::ApplyPatch(PatchContext& patchContext)
|
||||
{
|
||||
if (!_cardiReadRomIdCore)
|
||||
return;
|
||||
|
||||
auto patchCode = patchContext.GetPatchCodeCollection().AddUniquePatchCode<CardiReadRomIdCorePatchCode>
|
||||
(
|
||||
patchContext.GetPatchHeap(),
|
||||
(const void*)(patchContext.GetSdkVersion().IsTwlSdk() ? 0x02FFFC00 : 0x027FFC00)
|
||||
);
|
||||
|
||||
if (_thumb)
|
||||
{
|
||||
((u16*)_cardiReadRomIdCore)[0] = 0x4800;
|
||||
((u16*)_cardiReadRomIdCore)[1] = 0x4700;
|
||||
}
|
||||
else
|
||||
{
|
||||
_cardiReadRomIdCore[0] = 0xE51FF004;
|
||||
}
|
||||
|
||||
_cardiReadRomIdCore[1] = (u32)patchCode->GetCardiReadRomIdCoreFunction();
|
||||
}
|
||||
|
||||
bool CardiReadRomIdCorePatch::CheckSignature(const PatchContext& patchContext, const FunctionSignature& signature)
|
||||
{
|
||||
if (patchContext.GetSdkVersion() >= signature.GetMinimumSdkVersion() &&
|
||||
patchContext.GetSdkVersion() <= signature.GetMaximumSdkVersion())
|
||||
{
|
||||
_cardiReadRomIdCore = patchContext.FindPattern32(signature.GetPattern(), 16);
|
||||
if (_cardiReadRomIdCore)
|
||||
{
|
||||
LOG_DEBUG("Found CARDi_ReadRomIDCore at %p\n", _cardiReadRomIdCore);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
18
arm9/source/patches/arm9/CardiReadRomIdCorePatch.h
Normal file
18
arm9/source/patches/arm9/CardiReadRomIdCorePatch.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
#include "../Patch.h"
|
||||
|
||||
class FunctionSignature;
|
||||
|
||||
/// @brief Arm9 patch to avoid card id reads.
|
||||
class CardiReadRomIdCorePatch : public Patch
|
||||
{
|
||||
public:
|
||||
bool FindPatchTarget(PatchContext& patchContext) override;
|
||||
void ApplyPatch(PatchContext& patchContext) override;
|
||||
|
||||
private:
|
||||
bool CheckSignature(const PatchContext& patchContext, const FunctionSignature& signature);
|
||||
|
||||
u32* _cardiReadRomIdCore = nullptr;
|
||||
u16 _thumb = false;
|
||||
};
|
||||
24
arm9/source/patches/arm9/CardiReadRomIdCorePatchAsm.h
Normal file
24
arm9/source/patches/arm9/CardiReadRomIdCorePatchAsm.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
#include "../PatchCode.h"
|
||||
#include "sections.h"
|
||||
|
||||
DEFINE_SECTION_SYMBOLS(patch_cardireadromidcore);
|
||||
|
||||
extern "C" u32 patch_cardireadromidcore_entry(void);
|
||||
|
||||
extern u32 patch_cardireadromidcore_cardid_address;
|
||||
|
||||
class CardiReadRomIdCorePatchCode : public PatchCode
|
||||
{
|
||||
public:
|
||||
CardiReadRomIdCorePatchCode(PatchHeap& patchHeap, const void* cardIdPointer)
|
||||
: PatchCode(SECTION_START(patch_cardireadromidcore), SECTION_SIZE(patch_cardireadromidcore), patchHeap)
|
||||
{
|
||||
patch_cardireadromidcore_cardid_address = (u32)cardIdPointer;
|
||||
}
|
||||
|
||||
const void* GetCardiReadRomIdCoreFunction() const
|
||||
{
|
||||
return GetAddressAtTarget((void*)patch_cardireadromidcore_entry);
|
||||
}
|
||||
};
|
||||
21
arm9/source/patches/arm9/CardiReadRomIdCorePatchAsm.s
Normal file
21
arm9/source/patches/arm9/CardiReadRomIdCorePatchAsm.s
Normal file
@@ -0,0 +1,21 @@
|
||||
.cpu arm946e-s
|
||||
.section "patch_cardireadromidcore", "ax"
|
||||
.syntax unified
|
||||
|
||||
.thumb
|
||||
.global patch_cardireadromidcore_entry
|
||||
.type patch_cardireadromidcore_entry, %function
|
||||
patch_cardireadromidcore_entry:
|
||||
ldr r0, patch_cardireadromidcore_cardid_address
|
||||
ldr r0, [r0]
|
||||
bx lr
|
||||
|
||||
.balign 4
|
||||
|
||||
.global patch_cardireadromidcore_cardid_address
|
||||
patch_cardireadromidcore_cardid_address:
|
||||
.word 0x027FFC00
|
||||
|
||||
.pool
|
||||
|
||||
.end
|
||||
6
arm9/source/patches/arm9/FixCp15Asm.h
Normal file
6
arm9/source/patches/arm9/FixCp15Asm.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
#include "sections.h"
|
||||
|
||||
DEFINE_SECTION_SYMBOLS(fixcp15);
|
||||
|
||||
extern "C" void fix_cp15_asm();
|
||||
26
arm9/source/patches/arm9/FixCp15Asm.s
Normal file
26
arm9/source/patches/arm9/FixCp15Asm.s
Normal file
@@ -0,0 +1,26 @@
|
||||
.cpu arm946e-s
|
||||
.section "fixcp15", "ax"
|
||||
.syntax unified
|
||||
.arm
|
||||
|
||||
// to fix access to gba slot memory
|
||||
.global fix_cp15_asm
|
||||
.type fix_cp15_asm, %function
|
||||
fix_cp15_asm:
|
||||
mrc p15, 0, r0, c2, c0, 0
|
||||
bic r0, r0, #(1 << 3)
|
||||
mcr p15, 0, r0, c2, c0, 0
|
||||
mrc p15, 0, r0, c3, c0, 0
|
||||
bic r0, r0, #(1 << 3)
|
||||
mcr p15, 0, r0, c3, c0, 0
|
||||
mrc p15, 0, r0, c5, c0, 2
|
||||
bic r0, r0, #(0xF << 12)
|
||||
orr r0, r0, #(3 << 12)
|
||||
mcr p15, 0, r0, c5, c0, 2
|
||||
bx lr
|
||||
|
||||
.balign 4
|
||||
|
||||
.pool
|
||||
|
||||
.end
|
||||
125
arm9/source/patches/arm9/OSResetSystemPatch.cpp
Normal file
125
arm9/source/patches/arm9/OSResetSystemPatch.cpp
Normal file
@@ -0,0 +1,125 @@
|
||||
#include "common.h"
|
||||
#include "../PatchContext.h"
|
||||
#include "thumbInstructions.h"
|
||||
#include "../platform/LoaderPlatform.h"
|
||||
#include "OSResetSystemPatchAsm.h"
|
||||
#include "OSResetSystemPatch.h"
|
||||
|
||||
static const u32 sOSResetSystemPatternSdk2Old[] = { 0xE59F101Cu, 0xE3A00010u, 0xE5815000u, 0xEB000005u };
|
||||
static const u32 sOSResetSystemPatternSdk2[] = { 0xE59F1018u, 0xE3A00010u, 0xE5814000u, 0xEB000004u };
|
||||
static const u32 sOSResetSystemPatternSdk3[] = { 0xE59F1014u, 0xE3A00010u, 0xE5814000u, 0xEBFFFFD9u };
|
||||
static const u32 sOSResetSystemPatternSdk4[] = { 0xE59F103Cu, 0xE59F003Cu, 0xE5814000u, 0xEBFFFFD6u };
|
||||
static const u32 sOSResetSystemPatternPokemonDownloader[] = { 0xE59F1010u, 0xE3A00010u, 0xE5814000u, 0xEBFFFFDEu };
|
||||
|
||||
static const u32 sOSResetSystemPatternSdk5Old[] = { 0xE1A04000u, 0xE1D100B0u, 0xE3500002u, 0x1A000000u };
|
||||
static const u32 sOSResetSystemPatternSdk5New[] = { 0xE1A05000u, 0xE1D100B0u, 0xE3500002u, 0x1A000000u };
|
||||
static const u32 sOSResetSystemPatternSdk5HybridOld[] = { 0xE1A04000u, 0xE1D100B0u, 0xE3500002u, 0x0A000006 };
|
||||
static const u32 sOSResetSystemPatternSdk5HybridNew[] = { 0xE1A05000u, 0xE1D100B0u, 0xE3500002u, 0x0A000006 };
|
||||
|
||||
bool OSResetSystemPatch::FindPatchTarget(PatchContext& patchContext)
|
||||
{
|
||||
_osResetSystem = nullptr;
|
||||
if (patchContext.GetSdkVersion().IsTwlSdk())
|
||||
{
|
||||
_osResetSystem = patchContext.FindPattern32(sOSResetSystemPatternSdk5Old, sizeof(sOSResetSystemPatternSdk5Old));
|
||||
if (!_osResetSystem)
|
||||
{
|
||||
_osResetSystem = patchContext.FindPattern32(sOSResetSystemPatternSdk5New, sizeof(sOSResetSystemPatternSdk5New));
|
||||
}
|
||||
if (!_osResetSystem)
|
||||
{
|
||||
_osResetSystem = patchContext.FindPattern32(sOSResetSystemPatternSdk5HybridOld, sizeof(sOSResetSystemPatternSdk5HybridOld));
|
||||
_hybrid = true;
|
||||
}
|
||||
if (!_osResetSystem)
|
||||
{
|
||||
_osResetSystem = patchContext.FindPattern32(sOSResetSystemPatternSdk5HybridNew, sizeof(sOSResetSystemPatternSdk5HybridNew));
|
||||
_hybrid = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (patchContext.GetSdkVersion() >= 0x4017530)
|
||||
{
|
||||
_osResetSystem = patchContext.FindPattern32(sOSResetSystemPatternSdk4, sizeof(sOSResetSystemPatternSdk4));
|
||||
}
|
||||
if (!_osResetSystem && patchContext.GetSdkVersion() >= 0x3017530)
|
||||
{
|
||||
_osResetSystem = patchContext.FindPattern32(sOSResetSystemPatternSdk3, sizeof(sOSResetSystemPatternSdk3));
|
||||
}
|
||||
if (!_osResetSystem && patchContext.GetSdkVersion() >= 0x2004F50)
|
||||
{
|
||||
_osResetSystem = patchContext.FindPattern32(sOSResetSystemPatternSdk2, sizeof(sOSResetSystemPatternSdk2));
|
||||
}
|
||||
if (!_osResetSystem && patchContext.GetSdkVersion() >= 0x2004EE9)
|
||||
{
|
||||
_osResetSystem = patchContext.FindPattern32(sOSResetSystemPatternSdk2Old, sizeof(sOSResetSystemPatternSdk2Old));
|
||||
}
|
||||
if (!_osResetSystem)
|
||||
{
|
||||
_osResetSystem = patchContext.FindPattern32(sOSResetSystemPatternPokemonDownloader, sizeof(sOSResetSystemPatternPokemonDownloader));
|
||||
}
|
||||
}
|
||||
|
||||
if (_osResetSystem)
|
||||
{
|
||||
LOG_DEBUG("Found end of OS_ResetSystem at %p\n", _osResetSystem);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_DEBUG("OS_ResetSystem not found\n");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void OSResetSystemPatch::ApplyPatch(PatchContext& patchContext)
|
||||
{
|
||||
if (!_osResetSystem)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
u32 offset;
|
||||
if (patchContext.GetSdkVersion().IsTwlSdk())
|
||||
{
|
||||
patch_osresetsystem_arm7Entry_address = 0x02FFFE34;
|
||||
if (_hybrid)
|
||||
{
|
||||
offset = 0x80;
|
||||
if (!gIsDsiMode)
|
||||
{
|
||||
patch_osresetsystem_entry_jump_to_twl_arm7_sync = THUMB_NOP;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = 0x44;
|
||||
patch_osresetsystem_entry_jump_to_twl_arm7_sync = THUMB_NOP;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = 0xC;
|
||||
patch_osresetsystem_entry_jump_to_twl_arm7_sync = THUMB_NOP;
|
||||
}
|
||||
|
||||
auto loaderInfoTarget = (loader_info_t*)patchContext.GetPatchHeap().Alloc(sizeof(loader_info_t));
|
||||
memcpy(loaderInfoTarget, _loaderInfo, sizeof(loader_info_t));
|
||||
|
||||
auto sdReadPatchCode = patchContext.GetLoaderPlatform()->CreateSdReadPatchCode(
|
||||
patchContext.GetPatchCodeCollection(), patchContext.GetPatchHeap());
|
||||
auto patchCodePart2 = patchContext.GetPatchCodeCollection().AddUniquePatchCode<OSResetSystemPart2PatchCode>(
|
||||
patchContext.GetPatchHeap());
|
||||
auto patchCode = patchContext.GetPatchCodeCollection().AddUniquePatchCode<OSResetSystemPatchCode>
|
||||
(
|
||||
patchContext.GetPatchHeap(),
|
||||
loaderInfoTarget,
|
||||
sdReadPatchCode,
|
||||
patchCodePart2
|
||||
);
|
||||
|
||||
*(u32*)((u8*)_osResetSystem + offset) = 0xE51FF004;
|
||||
*(u32*)((u8*)_osResetSystem + offset + 4) = (u32)patchCode->GetOSResetSystemFunction();
|
||||
}
|
||||
|
||||
19
arm9/source/patches/arm9/OSResetSystemPatch.h
Normal file
19
arm9/source/patches/arm9/OSResetSystemPatch.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
#include "../Patch.h"
|
||||
#include "LoaderInfo.h"
|
||||
|
||||
/// @brief Arm9 patch to make OS_ResetSystem reboot into Pico Loader.
|
||||
class OSResetSystemPatch : public Patch
|
||||
{
|
||||
public:
|
||||
explicit OSResetSystemPatch(const loader_info_t* loaderInfo)
|
||||
: _loaderInfo(loaderInfo) { }
|
||||
|
||||
bool FindPatchTarget(PatchContext& patchContext) override;
|
||||
void ApplyPatch(PatchContext& patchContext) override;
|
||||
|
||||
private:
|
||||
u32* _osResetSystem = nullptr;
|
||||
u32 _hybrid = false;
|
||||
const loader_info_t* _loaderInfo;
|
||||
};
|
||||
49
arm9/source/patches/arm9/OSResetSystemPatchAsm.h
Normal file
49
arm9/source/patches/arm9/OSResetSystemPatchAsm.h
Normal file
@@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
#include "../PatchCode.h"
|
||||
#include "sections.h"
|
||||
#include "LoaderInfo.h"
|
||||
#include "../platform/SdReadPatchCode.h"
|
||||
|
||||
DEFINE_SECTION_SYMBOLS(patch_osresetsystem);
|
||||
DEFINE_SECTION_SYMBOLS(patch_osresetsystem_boot);
|
||||
|
||||
extern "C" void patch_osresetsystem_entry(void);
|
||||
extern "C" void patch_osresetsystem_bootPicoLoader(void);
|
||||
|
||||
extern const loader_info_t* patch_osresetsystem_loader_info_address;
|
||||
extern u32 patch_osresetsystem_readSdSectors_address;
|
||||
extern u32 patch_osresetsystem_bootPicoLoader_address;
|
||||
extern u16 patch_osresetsystem_entry_jump_to_twl_arm7_sync;
|
||||
extern u32 patch_osresetsystem_arm7Entry_address;
|
||||
|
||||
class OSResetSystemPart2PatchCode : public PatchCode
|
||||
{
|
||||
public:
|
||||
explicit OSResetSystemPart2PatchCode(PatchHeap& patchHeap)
|
||||
: PatchCode(SECTION_START(patch_osresetsystem_boot), SECTION_SIZE(patch_osresetsystem_boot), patchHeap)
|
||||
{
|
||||
}
|
||||
|
||||
const void* GetOSResetSystemPart2Function() const
|
||||
{
|
||||
return GetAddressAtTarget((void*)patch_osresetsystem_bootPicoLoader);
|
||||
}
|
||||
};
|
||||
|
||||
class OSResetSystemPatchCode : public PatchCode
|
||||
{
|
||||
public:
|
||||
OSResetSystemPatchCode(PatchHeap& patchHeap, const loader_info_t* loaderInfo,
|
||||
const SdReadPatchCode* sdReadPatchCode, const OSResetSystemPart2PatchCode* part2PatchCode)
|
||||
: PatchCode(SECTION_START(patch_osresetsystem), SECTION_SIZE(patch_osresetsystem), patchHeap)
|
||||
{
|
||||
patch_osresetsystem_loader_info_address = loaderInfo;
|
||||
patch_osresetsystem_readSdSectors_address = (u32)sdReadPatchCode->GetSdReadFunction();
|
||||
patch_osresetsystem_bootPicoLoader_address = (u32)part2PatchCode->GetOSResetSystemPart2Function();
|
||||
}
|
||||
|
||||
const void* GetOSResetSystemFunction() const
|
||||
{
|
||||
return GetAddressAtTarget((void*)patch_osresetsystem_entry);
|
||||
}
|
||||
};
|
||||
178
arm9/source/patches/arm9/OSResetSystemPatchAsm.s
Normal file
178
arm9/source/patches/arm9/OSResetSystemPatchAsm.s
Normal file
@@ -0,0 +1,178 @@
|
||||
.cpu arm946e-s
|
||||
.section "patch_osresetsystem", "ax"
|
||||
.syntax unified
|
||||
|
||||
.thumb
|
||||
.global patch_osresetsystem_entry
|
||||
.type patch_osresetsystem_entry, %function
|
||||
patch_osresetsystem_entry:
|
||||
adr r0, regIpcSync
|
||||
// regIpcSync, arm7ResetCommand, regVramCntA, vramAbcdLcdcSetting, readSdSectors_address, loader_info_address, vramCLcdcAddress, patch_osresetsystem_bootPicoLoader_address
|
||||
ldmia r0, {r0, r1, r2, r3, r4, r5, r6, r7}
|
||||
|
||||
// r9 = readSdSectors_address
|
||||
mov r9, r4
|
||||
mov r10, r7
|
||||
|
||||
// reset arm7
|
||||
1:
|
||||
ldr r6, [r0, #4]
|
||||
lsrs r6, r6, #2 // shift bit 1 to carry
|
||||
bcs 1b // while fifo full
|
||||
|
||||
str r1, [r0, #8]
|
||||
|
||||
adds r7, #(twl_arm7_sync - patch_osresetsystem_bootPicoLoader)
|
||||
mov lr, pc
|
||||
.global patch_osresetsystem_entry_jump_to_twl_arm7_sync
|
||||
patch_osresetsystem_entry_jump_to_twl_arm7_sync:
|
||||
bx r7
|
||||
|
||||
2:
|
||||
ldrb r7, [r0] // ipc sync
|
||||
cmp r7, #1
|
||||
bne 2b // while ipc sync from arm7 is not 1
|
||||
|
||||
// map vram ABCD to LCDC
|
||||
str r3, [r2]
|
||||
|
||||
// load pico loader arm9
|
||||
ldmia r5!, {r4,r6,r7} // clusterShift, database, clusterMap[0]
|
||||
ldr r7,= 0x06800000
|
||||
mov r11, pc
|
||||
b loadData
|
||||
|
||||
// load pico loader arm7
|
||||
ldr r5, patch_osresetsystem_loader_info_address
|
||||
adds r5, #52
|
||||
ldr r7, vramCLcdcAddress
|
||||
mov r11, pc
|
||||
b loadData
|
||||
|
||||
adr r5, patch_osresetsystem_loader_info_address
|
||||
bx r10
|
||||
|
||||
loadData_loop:
|
||||
subs r3, #2
|
||||
lsls r3, r4
|
||||
adds r0, r3, r6 // start sector
|
||||
movs r1, r7 // dst
|
||||
lsls r2, r4 // sector count
|
||||
lsls r3, r2, #9
|
||||
adds r7, r3
|
||||
|
||||
blx r9 // read sectors
|
||||
|
||||
loadData:
|
||||
ldmia r5!, {r2, r3} // ncl, startSector
|
||||
cmp r2, #0
|
||||
bne loadData_loop
|
||||
mov pc, r11
|
||||
|
||||
.balign 4
|
||||
|
||||
regIpcSync:
|
||||
.word 0x04000180
|
||||
|
||||
arm7ResetCommand:
|
||||
.word 0x4000C
|
||||
|
||||
regVramCntA:
|
||||
.word 0x04000240
|
||||
|
||||
vramAbcdLcdcSetting:
|
||||
.word 0x80808080
|
||||
|
||||
.global patch_osresetsystem_readSdSectors_address
|
||||
patch_osresetsystem_readSdSectors_address:
|
||||
.word 0
|
||||
|
||||
.global patch_osresetsystem_loader_info_address
|
||||
patch_osresetsystem_loader_info_address:
|
||||
.word 0
|
||||
|
||||
vramCLcdcAddress:
|
||||
.word 0x06840000
|
||||
|
||||
.global patch_osresetsystem_bootPicoLoader_address
|
||||
patch_osresetsystem_bootPicoLoader_address:
|
||||
.word 0
|
||||
|
||||
.pool
|
||||
|
||||
.section "patch_osresetsystem_boot", "ax"
|
||||
.thumb
|
||||
.global patch_osresetsystem_bootPicoLoader
|
||||
.type patch_osresetsystem_bootPicoLoader, %function
|
||||
patch_osresetsystem_bootPicoLoader:
|
||||
// loader_info_address, vramCLcdcAddress
|
||||
ldmia r5, {r3, r5}
|
||||
ldrh r0, [r3, #2] // loader_info_t::picoLoaderBootDrive
|
||||
strh r0, [r5, #8] // pload_header7_t::bootDrive
|
||||
ldr r0, [r5] // pload_header7_t::entryPoint
|
||||
|
||||
// set NTR_SHARED_MEMORY->romHeader.arm7EntryAddress
|
||||
ldr r4, patch_osresetsystem_arm7Entry_address
|
||||
str r0, [r4]
|
||||
|
||||
// map vram CD to arm7
|
||||
ldr r0,= 0x04000240
|
||||
ldr r7,= 0x8A82
|
||||
strh r7, [r0, #2]
|
||||
|
||||
adds r0, #(0x04000180 - 0x04000240) // REG_IPC_SYNC
|
||||
movs r1, #1
|
||||
strb r1, [r0, #1]
|
||||
|
||||
1:
|
||||
ldrb r7, [r0] // ipc sync
|
||||
cmp r7, #0
|
||||
bne 1b // while ipc sync from arm7 is not 0
|
||||
|
||||
movs r1, #0
|
||||
strb r1, [r0, #1]
|
||||
|
||||
movs r0, #0x68
|
||||
lsls r0, r0, #20 // 0x06800000
|
||||
bx r0
|
||||
|
||||
twl_arm7_sync:
|
||||
ldr r7,= 0x02FFFC24
|
||||
movs r1, #1
|
||||
strh r1, [r7, #4]
|
||||
|
||||
ldrh r6, [r7, #2]
|
||||
ldrh r1, [r7]
|
||||
1:
|
||||
adds r1, #1
|
||||
strh r1, [r7]
|
||||
ldrh r4, [r7, #2]
|
||||
cmp r6, r4
|
||||
beq 1b
|
||||
adds r1, #1
|
||||
strh r1, [r7]
|
||||
|
||||
movs r1, #3
|
||||
strh r1, [r7, #4]
|
||||
|
||||
ldrh r6, [r7, #2]
|
||||
ldrh r1, [r7]
|
||||
1:
|
||||
adds r1, #1
|
||||
strh r1, [r7]
|
||||
ldrh r4, [r7, #2]
|
||||
cmp r6, r4
|
||||
beq 1b
|
||||
adds r1, #1
|
||||
strh r1, [r7]
|
||||
|
||||
mov pc, lr
|
||||
|
||||
.balign 4
|
||||
|
||||
.global patch_osresetsystem_arm7Entry_address
|
||||
patch_osresetsystem_arm7Entry_address:
|
||||
.word 0x027FFE34
|
||||
|
||||
.pool
|
||||
.end
|
||||
@@ -0,0 +1,418 @@
|
||||
#include "common.h"
|
||||
#include "../../../PatchContext.h"
|
||||
#include "thumbInstructions.h"
|
||||
#include "gameCode.h"
|
||||
#include "DSProtectOverlayPatchv1Asm.h"
|
||||
#include "DSProtectOverlayPatchv2Asm.h"
|
||||
#include "DSProtectOverlayPatchv2sAsm.h"
|
||||
#include "DSProtectOverlayPatch.h"
|
||||
|
||||
const void* DSProtectOverlayPatch::InsertPatch(PatchContext& patchContext)
|
||||
{
|
||||
if (_version <= DSProtectVersion::v1_28)
|
||||
{
|
||||
return InsertPatchV1(patchContext);
|
||||
}
|
||||
else if (_version <= DSProtectVersion::v2_05)
|
||||
{
|
||||
return InsertPatchV2(patchContext);
|
||||
}
|
||||
else if (_version <= DSProtectVersion::v2_05s)
|
||||
{
|
||||
return InsertPatchV2s(patchContext);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_WARNING("Unsupported DSProtect version\n");
|
||||
return next ? (const void*)next->InsertPatch(patchContext) : nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void DSProtectOverlayPatch::SetOldV1Offsets(const u16* offsets) const
|
||||
{
|
||||
int offsetIdx = 0;
|
||||
|
||||
if (_functionMask & 0b000001)
|
||||
dsprotectpatchv1_stub_protectb1_offset = offsets[offsetIdx++];
|
||||
else
|
||||
dsprotectpatchv1_stub_protectb1_offset = 0; // does not exist
|
||||
|
||||
if (_functionMask & 0b000010)
|
||||
dsprotectpatchv1_stub_notprotectb1_offset = offsets[offsetIdx++];
|
||||
else
|
||||
dsprotectpatchv1_stub_notprotectb1_offset = 0; // does not exist
|
||||
|
||||
if (_functionMask & 0b000100)
|
||||
dsprotectpatchv1_stub_protectb2_offset = offsets[offsetIdx++];
|
||||
else
|
||||
dsprotectpatchv1_stub_protectb2_offset = 0; // does not exist
|
||||
|
||||
if (_functionMask & 0b001000)
|
||||
dsprotectpatchv1_stub_notprotectb2_offset = offsets[offsetIdx++];
|
||||
else
|
||||
dsprotectpatchv1_stub_notprotectb2_offset = 0; // does not exist
|
||||
|
||||
if (_functionMask & 0b010000)
|
||||
dsprotectpatchv1_stub_protectb3_offset = offsets[offsetIdx++];
|
||||
else
|
||||
dsprotectpatchv1_stub_protectb3_offset = 0; // does not exist
|
||||
|
||||
if (_functionMask & 0b100000)
|
||||
dsprotectpatchv1_stub_notprotectb3_offset = offsets[offsetIdx++];
|
||||
else
|
||||
dsprotectpatchv1_stub_notprotectb3_offset = 0; // does not exist
|
||||
}
|
||||
|
||||
const void* DSProtectOverlayPatch::InsertPatchV1(PatchContext& patchContext) const
|
||||
{
|
||||
const void* nextPatch = next ? (const void*)next->InsertPatch(patchContext) : nullptr;
|
||||
|
||||
dsprotectpatchv1_overlay_id = _overlayId;
|
||||
dsprotectpatchv1_base_offset = _overlayOffset;
|
||||
|
||||
switch (_version)
|
||||
{
|
||||
case DSProtectVersion::v1_05:
|
||||
{
|
||||
static u16 v105Offsets[] = { 0x858, 0x934, 0xA10, 0xAEC, 0xBC8, 0xC94 };
|
||||
SetOldV1Offsets(v105Offsets);
|
||||
|
||||
dsprotectpatchv1_nitro_static_init_offset = 0; // does not exist
|
||||
dsprotectpatchv1_protectb1_return_value = 0;
|
||||
dsprotectpatchv1_protectb2_return_value = 0;
|
||||
dsprotectpatchv1_protectb3_return_value = 0;
|
||||
dsprotectpatchv1_notprotectb1_return_value = 1;
|
||||
dsprotectpatchv1_notprotectb2_return_value = 1;
|
||||
dsprotectpatchv1_notprotectb3_return_value = 1;
|
||||
// Remove xor 0x320 from the callback pointer
|
||||
dsprotectpatchv1_moveCallback = 0xE230EE32; // eors lr, r0, #0x320
|
||||
break;
|
||||
}
|
||||
case DSProtectVersion::v1_06:
|
||||
{
|
||||
static u16 v106Offsets[] = { 0x860, 0x938, 0xA10, 0xAE8, 0xBC0, 0xC88 };
|
||||
SetOldV1Offsets(v106Offsets);
|
||||
|
||||
dsprotectpatchv1_nitro_static_init_offset = 0; // does not exist
|
||||
dsprotectpatchv1_protectb1_return_value = 0;
|
||||
dsprotectpatchv1_protectb2_return_value = 0;
|
||||
dsprotectpatchv1_protectb3_return_value = 0;
|
||||
dsprotectpatchv1_notprotectb1_return_value = 1;
|
||||
dsprotectpatchv1_notprotectb2_return_value = 1;
|
||||
dsprotectpatchv1_notprotectb3_return_value = 1;
|
||||
break;
|
||||
}
|
||||
case DSProtectVersion::v1_08:
|
||||
{
|
||||
static u16 v108Offsets[] = { 0x858, 0x930, 0xA08, 0xAE0, 0xBB8, 0xC94 };
|
||||
SetOldV1Offsets(v108Offsets);
|
||||
|
||||
dsprotectpatchv1_nitro_static_init_offset = 0; // does not exist
|
||||
dsprotectpatchv1_protectb1_return_value = 0;
|
||||
dsprotectpatchv1_protectb2_return_value = 0;
|
||||
dsprotectpatchv1_protectb3_return_value = 0;
|
||||
dsprotectpatchv1_notprotectb1_return_value = 1;
|
||||
dsprotectpatchv1_notprotectb2_return_value = 1;
|
||||
dsprotectpatchv1_notprotectb3_return_value = 1;
|
||||
break;
|
||||
}
|
||||
case DSProtectVersion::v1_10:
|
||||
{
|
||||
static u16 v110Offsets[] = { 0x860, 0x940, 0xA20, 0xB00, 0xBE0, 0xCB0 };
|
||||
SetOldV1Offsets(v110Offsets);
|
||||
|
||||
dsprotectpatchv1_nitro_static_init_offset = 0; // does not exist
|
||||
dsprotectpatchv1_protectb1_return_value = 0;
|
||||
dsprotectpatchv1_protectb2_return_value = 0;
|
||||
dsprotectpatchv1_protectb3_return_value = 0;
|
||||
dsprotectpatchv1_notprotectb1_return_value = 1;
|
||||
dsprotectpatchv1_notprotectb2_return_value = 1;
|
||||
dsprotectpatchv1_notprotectb3_return_value = 1;
|
||||
break;
|
||||
}
|
||||
case DSProtectVersion::v1_20:
|
||||
{
|
||||
switch (_functionMask)
|
||||
{
|
||||
case 0b001111:
|
||||
dsprotectpatchv1_stub_protectb1_offset = 0x864;
|
||||
dsprotectpatchv1_stub_notprotectb1_offset = 0x94C;
|
||||
dsprotectpatchv1_stub_protectb2_offset = 0xA34;
|
||||
dsprotectpatchv1_stub_notprotectb2_offset = 0xB1C;
|
||||
dsprotectpatchv1_stub_protectb3_offset = 0; // does not exist
|
||||
dsprotectpatchv1_stub_notprotectb3_offset = 0; // does not exist
|
||||
break;
|
||||
|
||||
case 0b010101:
|
||||
dsprotectpatchv1_stub_protectb1_offset = 0x644;
|
||||
dsprotectpatchv1_stub_notprotectb1_offset = 0; // does not exist
|
||||
dsprotectpatchv1_stub_protectb2_offset = 0x72C;
|
||||
dsprotectpatchv1_stub_notprotectb2_offset = 0; // does not exist
|
||||
dsprotectpatchv1_stub_protectb3_offset = 0x814;
|
||||
dsprotectpatchv1_stub_notprotectb3_offset = 0; // does not exist
|
||||
break;
|
||||
|
||||
case 0b010110:
|
||||
dsprotectpatchv1_stub_protectb1_offset = 0; // does not exist
|
||||
dsprotectpatchv1_stub_notprotectb1_offset = 0x644;
|
||||
dsprotectpatchv1_stub_protectb2_offset = 0x72C;
|
||||
dsprotectpatchv1_stub_notprotectb2_offset = 0; // does not exist
|
||||
dsprotectpatchv1_stub_protectb3_offset = 0x814;
|
||||
dsprotectpatchv1_stub_notprotectb3_offset = 0; // does not exist
|
||||
break;
|
||||
|
||||
case 0b011001:
|
||||
dsprotectpatchv1_stub_protectb1_offset = 0x644;
|
||||
dsprotectpatchv1_stub_notprotectb1_offset = 0; // does not exist
|
||||
dsprotectpatchv1_stub_protectb2_offset = 0;
|
||||
dsprotectpatchv1_stub_notprotectb2_offset = 0x72C;
|
||||
dsprotectpatchv1_stub_protectb3_offset = 0x814;
|
||||
dsprotectpatchv1_stub_notprotectb3_offset = 0; // does not exist
|
||||
break;
|
||||
|
||||
case 0b110101:
|
||||
dsprotectpatchv1_stub_protectb1_offset = 0x644;
|
||||
dsprotectpatchv1_stub_notprotectb1_offset = 0; // does not exist
|
||||
dsprotectpatchv1_stub_protectb2_offset = 0x72C;
|
||||
dsprotectpatchv1_stub_notprotectb2_offset = 0; // does not exist
|
||||
dsprotectpatchv1_stub_protectb3_offset = 0x814;
|
||||
dsprotectpatchv1_stub_notprotectb3_offset = 0x8DC;
|
||||
break;
|
||||
|
||||
case 0b111111:
|
||||
dsprotectpatchv1_stub_protectb1_offset = 0x864;
|
||||
dsprotectpatchv1_stub_notprotectb1_offset = 0x94C;
|
||||
dsprotectpatchv1_stub_protectb2_offset = 0xA34;
|
||||
dsprotectpatchv1_stub_notprotectb2_offset = 0xB1C;
|
||||
dsprotectpatchv1_stub_protectb3_offset = 0xC04;
|
||||
dsprotectpatchv1_stub_notprotectb3_offset = 0xCCC;
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_WARNING("Unsupported DSProtect function mask\n");
|
||||
return nextPatch;
|
||||
}
|
||||
dsprotectpatchv1_nitro_static_init_offset = 0; // does not exist
|
||||
dsprotectpatchv1_protectb1_return_value = 0;
|
||||
dsprotectpatchv1_protectb2_return_value = 0;
|
||||
dsprotectpatchv1_protectb3_return_value = 0;
|
||||
dsprotectpatchv1_notprotectb1_return_value = 1;
|
||||
dsprotectpatchv1_notprotectb2_return_value = 1;
|
||||
dsprotectpatchv1_notprotectb3_return_value = 1;
|
||||
break;
|
||||
}
|
||||
case DSProtectVersion::v1_22:
|
||||
{
|
||||
switch (_functionMask)
|
||||
{
|
||||
case 0b010101:
|
||||
dsprotectpatchv1_stub_protectb1_offset = 0x64C;
|
||||
dsprotectpatchv1_stub_notprotectb1_offset = 0; // does not exist
|
||||
dsprotectpatchv1_stub_protectb2_offset = 0x734;
|
||||
dsprotectpatchv1_stub_notprotectb2_offset = 0; // does not exist
|
||||
dsprotectpatchv1_stub_protectb3_offset = 0x81C;
|
||||
dsprotectpatchv1_stub_notprotectb3_offset = 0; // does not exist
|
||||
break;
|
||||
|
||||
case 0b010110:
|
||||
dsprotectpatchv1_stub_protectb1_offset = 0; // does not exist
|
||||
dsprotectpatchv1_stub_notprotectb1_offset = 0x64C;
|
||||
dsprotectpatchv1_stub_protectb2_offset = 0x734;
|
||||
dsprotectpatchv1_stub_notprotectb2_offset = 0; // does not exist
|
||||
dsprotectpatchv1_stub_protectb3_offset = 0x81C;
|
||||
dsprotectpatchv1_stub_notprotectb3_offset = 0; // does not exist
|
||||
break;
|
||||
|
||||
case 0b010111:
|
||||
dsprotectpatchv1_stub_protectb1_offset = 0x754;
|
||||
dsprotectpatchv1_stub_notprotectb1_offset = 0x83C;
|
||||
dsprotectpatchv1_stub_protectb2_offset = 0x924;
|
||||
dsprotectpatchv1_stub_notprotectb2_offset = 0; // does not exist
|
||||
dsprotectpatchv1_stub_protectb3_offset = 0xA0C;
|
||||
dsprotectpatchv1_stub_notprotectb3_offset = 0; // does not exist
|
||||
break;
|
||||
|
||||
case 0b011111:
|
||||
dsprotectpatchv1_stub_protectb1_offset = 0x874;
|
||||
dsprotectpatchv1_stub_notprotectb1_offset = 0x95C;
|
||||
dsprotectpatchv1_stub_protectb2_offset = 0xA44;
|
||||
dsprotectpatchv1_stub_notprotectb2_offset = 0xB2C;
|
||||
dsprotectpatchv1_stub_protectb3_offset = 0xC14;
|
||||
dsprotectpatchv1_stub_notprotectb3_offset = 0; // does not exist
|
||||
break;
|
||||
|
||||
case 0b111111:
|
||||
dsprotectpatchv1_stub_protectb1_offset = 0x874;
|
||||
dsprotectpatchv1_stub_notprotectb1_offset = 0x95C;
|
||||
dsprotectpatchv1_stub_protectb2_offset = 0xA44;
|
||||
dsprotectpatchv1_stub_notprotectb2_offset = 0xB2C;
|
||||
dsprotectpatchv1_stub_protectb3_offset = 0xC14;
|
||||
dsprotectpatchv1_stub_notprotectb3_offset = 0xCDC;
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_WARNING("Unsupported DSProtect function mask\n");
|
||||
return nextPatch;
|
||||
}
|
||||
|
||||
dsprotectpatchv1_nitro_static_init_offset = 0; // does not exist
|
||||
dsprotectpatchv1_protectb1_return_value = 0;
|
||||
dsprotectpatchv1_protectb2_return_value = 0;
|
||||
dsprotectpatchv1_protectb3_return_value = 0;
|
||||
dsprotectpatchv1_notprotectb1_return_value = 1;
|
||||
dsprotectpatchv1_notprotectb2_return_value = 1;
|
||||
dsprotectpatchv1_notprotectb3_return_value = 1;
|
||||
break;
|
||||
}
|
||||
case DSProtectVersion::v1_23:
|
||||
case DSProtectVersion::v1_23Z:
|
||||
{
|
||||
dsprotectpatchv1_stub_protectb1_offset = 0x410;
|
||||
dsprotectpatchv1_stub_protectb2_offset = 0x500;
|
||||
dsprotectpatchv1_stub_protectb3_offset = 0x5F0;
|
||||
dsprotectpatchv1_stub_notprotectb1_offset = 0x488;
|
||||
dsprotectpatchv1_stub_notprotectb2_offset = 0x578;
|
||||
dsprotectpatchv1_stub_notprotectb3_offset = 0x668;
|
||||
// this seems to be a decrypt function that is called from 5 static init functions
|
||||
dsprotectpatchv1_nitro_static_init_offset = 0xD78;
|
||||
dsprotectpatchv1_protectb1_return_value = 0;
|
||||
dsprotectpatchv1_protectb2_return_value = 0;
|
||||
dsprotectpatchv1_protectb3_return_value = 0;
|
||||
dsprotectpatchv1_notprotectb1_return_value = 1;
|
||||
dsprotectpatchv1_notprotectb2_return_value = 1;
|
||||
dsprotectpatchv1_notprotectb3_return_value = 1;
|
||||
break;
|
||||
}
|
||||
case DSProtectVersion::v1_25:
|
||||
case DSProtectVersion::v1_26:
|
||||
{
|
||||
dsprotectpatchv1_stub_protectb1_offset = 0x3DC;
|
||||
dsprotectpatchv1_stub_protectb2_offset = 0x4CC;
|
||||
dsprotectpatchv1_stub_protectb3_offset = 0x5BC;
|
||||
dsprotectpatchv1_stub_notprotectb1_offset = 0x454;
|
||||
dsprotectpatchv1_stub_notprotectb2_offset = 0x544;
|
||||
dsprotectpatchv1_stub_notprotectb3_offset = 0x634;
|
||||
dsprotectpatchv1_nitro_static_init_offset = 0x6AC;
|
||||
break;
|
||||
}
|
||||
case DSProtectVersion::v1_27:
|
||||
{
|
||||
dsprotectpatchv1_stub_protectb1_offset = 0x3A0;
|
||||
dsprotectpatchv1_stub_protectb2_offset = 0x418;
|
||||
dsprotectpatchv1_stub_protectb3_offset = 0x490;
|
||||
dsprotectpatchv1_stub_notprotectb1_offset = 0x3DC;
|
||||
dsprotectpatchv1_stub_notprotectb2_offset = 0x454;
|
||||
dsprotectpatchv1_stub_notprotectb3_offset = 0x4CC;
|
||||
dsprotectpatchv1_nitro_static_init_offset = 0x508;
|
||||
dsprotectpatchv1_loadReturnValue = 0; // Return the return value of the callback
|
||||
break;
|
||||
}
|
||||
case DSProtectVersion::v1_28:
|
||||
{
|
||||
dsprotectpatchv1_stub_protectb1_offset = 0x3A0;
|
||||
dsprotectpatchv1_stub_protectb2_offset = 0x418;
|
||||
dsprotectpatchv1_stub_protectb3_offset = 0x490;
|
||||
dsprotectpatchv1_stub_notprotectb1_offset = 0x3DC;
|
||||
dsprotectpatchv1_stub_notprotectb2_offset = 0x454;
|
||||
dsprotectpatchv1_stub_notprotectb3_offset = 0x4CC;
|
||||
dsprotectpatchv1_nitro_static_init_offset = 0x508;
|
||||
dsprotectpatchv1_loadReturnValue = 0; // Return the return value of the callback
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
LOG_WARNING("Unsupported DSProtect version\n");
|
||||
return nextPatch;
|
||||
}
|
||||
}
|
||||
dsprotectpatchv1_nextAddress = (u32)nextPatch;
|
||||
|
||||
u32 patch1Size = SECTION_SIZE(dsprotectpatchv1_part1);
|
||||
void* patch1Address = patchContext.GetPatchHeap().Alloc(patch1Size);
|
||||
u32 patch2Size = SECTION_SIZE(dsprotectpatchv1_part2);
|
||||
void* patch2Address = patchContext.GetPatchHeap().Alloc(patch2Size);
|
||||
|
||||
dsprotectpatchv1_part2_address = (u32)&dsprotectpatchv1_entry2 - (u32)SECTION_START(dsprotectpatchv1_part2) + (u32)patch2Address;
|
||||
|
||||
u32 entryAddress1 = (u32)&dsprotectpatchv1_entry1 - (u32)SECTION_START(dsprotectpatchv1_part1) + (u32)patch1Address;
|
||||
memcpy(patch1Address, SECTION_START(dsprotectpatchv1_part1), patch1Size);
|
||||
memcpy(patch2Address, SECTION_START(dsprotectpatchv1_part2), patch2Size);
|
||||
|
||||
return (const void*)entryAddress1;
|
||||
}
|
||||
|
||||
struct ds_protect_v2_patch_t
|
||||
{
|
||||
u32 checksumFix;
|
||||
u16 stubProtectb1Offset;
|
||||
u16 stubProtectb2Offset;
|
||||
u16 stubProtectb3Offset;
|
||||
u16 stubProtectb4Offset;
|
||||
u16 amInitOffset;
|
||||
u16 storeChecksumFix;
|
||||
};
|
||||
|
||||
static const ds_protect_v2_patch_t sDSProtectV2Patches[] =
|
||||
{
|
||||
{ 0x7CDBA8BD, 0x670, 0x6AC, 0x6E8, 0x724, 0x760, THUMB_STR_IMM(THUMB_R7, THUMB_R0, 0) }, // v2.00
|
||||
{ 0xA6FD7CE1, 0x1120, 0x115C, 0x1198, 0x11D4, 0x1210, THUMB_STR_IMM(THUMB_R7, THUMB_R0, 0) }, // v2.01
|
||||
{ 0x934DD0, 0x129C, 0x1324, 0x13AC, 0x1434, 0x14BC, THUMB_STR_IMM(THUMB_R7, THUMB_R0, 0) }, // v2.03
|
||||
{ 0x32E120D5, 0x132C, 0x13D8, 0x1484, 0x1530, 0x15DC, THUMB_STR_IMM(THUMB_R7, THUMB_R0, 8) }, // v2.05
|
||||
};
|
||||
|
||||
const void* DSProtectOverlayPatch::InsertPatchV2(PatchContext& patchContext) const
|
||||
{
|
||||
dsprotectpatchv2_nextAddress = next ? (u32)next->InsertPatch(patchContext) : 0u;
|
||||
dsprotectpatchv2_overlay_id = _overlayId;
|
||||
dsprotectpatchv2_base_offset = _overlayOffset;
|
||||
|
||||
const auto& patch = sDSProtectV2Patches[(u32)_version - (u32)DSProtectVersion::v2_00];
|
||||
dsprotectpatchv2_checksum_fix = patch.checksumFix;
|
||||
dsprotectpatchv2_stub_protectb1_offset = patch.stubProtectb1Offset;
|
||||
dsprotectpatchv2_stub_protectb2_offset = patch.stubProtectb2Offset;
|
||||
dsprotectpatchv2_stub_protectb3_offset = patch.stubProtectb3Offset;
|
||||
dsprotectpatchv2_stub_protectb4_offset = patch.stubProtectb4Offset;
|
||||
dsprotectpatchv2_am_init_offset = patch.amInitOffset;
|
||||
dsprotectpatchv2_store_checksum_fix = patch.storeChecksumFix;
|
||||
|
||||
u32 patchSize = SECTION_SIZE(dsprotectpatchv2);
|
||||
void* patchAddress = patchContext.GetPatchHeap().Alloc(patchSize);
|
||||
|
||||
u32 entryAddress = (u32)&dsprotectpatchv2_entry - (u32)SECTION_START(dsprotectpatchv2) + (u32)patchAddress;
|
||||
memcpy(patchAddress, SECTION_START(dsprotectpatchv2), patchSize);
|
||||
|
||||
return (const void*)entryAddress;
|
||||
}
|
||||
|
||||
struct ds_protect_v2s_patch_t
|
||||
{
|
||||
u32 checksumFix;
|
||||
u16 instantDetectOffset;
|
||||
u16 storeChecksumFix;
|
||||
};
|
||||
|
||||
static const ds_protect_v2s_patch_t sDSProtectV2sPatches[] =
|
||||
{
|
||||
{ 0xEDEA7F01, 0x1BC, THUMB_STR_IMM(THUMB_R7, THUMB_R0, 0) }, // v2.00s
|
||||
{ 0xEDEA7F1F, 0x1BC, THUMB_STR_IMM(THUMB_R7, THUMB_R0, 0) }, // v2.01s
|
||||
{ 0x167325AA, 0x20C, THUMB_STR_IMM(THUMB_R7, THUMB_R0, 0) }, // v2.03s
|
||||
{ 0x32E120D5, 0x230, THUMB_STR_IMM(THUMB_R7, THUMB_R0, 4) } // v2.05s
|
||||
};
|
||||
|
||||
const void* DSProtectOverlayPatch::InsertPatchV2s(PatchContext& patchContext) const
|
||||
{
|
||||
dsprotectpatchv2s_nextAddress = next ? (u32)next->InsertPatch(patchContext) : 0u;
|
||||
dsprotectpatchv2s_overlay_id = _overlayId;
|
||||
|
||||
const auto& patch = sDSProtectV2sPatches[(u32)_version - (u32)DSProtectVersion::v2_00s];
|
||||
dsprotectpatchv2s_checksum_fix = patch.checksumFix;
|
||||
dsprotectpatchv2s_stub_instantdetect_offset = patch.instantDetectOffset + _overlayOffset;
|
||||
dsprotectpatchv2s_store_checksum_fix = patch.storeChecksumFix;
|
||||
|
||||
u32 patchSize = SECTION_SIZE(dsprotectpatchv2s);
|
||||
void* patchAddress = patchContext.GetPatchHeap().Alloc(patchSize);
|
||||
u32 entryAddress = (u32)&dsprotectpatchv2s_entry - (u32)SECTION_START(dsprotectpatchv2s) + (u32)patchAddress;
|
||||
memcpy(patchAddress, SECTION_START(dsprotectpatchv2s), patchSize);
|
||||
|
||||
return (const void*)entryAddress;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
#include "../OverlayPatch.h"
|
||||
#include "DSProtectVersion.h"
|
||||
|
||||
/// @brief Arm9 overlay patch for DS Protect.
|
||||
class DSProtectOverlayPatch : public OverlayPatch
|
||||
{
|
||||
public:
|
||||
DSProtectOverlayPatch(u32 overlayId, u32 overlayOffset, DSProtectVersion version, u32 functionMask)
|
||||
: _overlayId(overlayId), _overlayOffset(overlayOffset), _version(version), _functionMask(functionMask) { }
|
||||
|
||||
const void* InsertPatch(PatchContext& patchContext) override;
|
||||
|
||||
private:
|
||||
u32 _overlayId;
|
||||
u32 _overlayOffset;
|
||||
DSProtectVersion _version;
|
||||
u32 _functionMask;
|
||||
|
||||
void SetOldV1Offsets(const u16* offsets) const;
|
||||
const void* InsertPatchV1(PatchContext& patchContext) const;
|
||||
const void* InsertPatchV2(PatchContext& patchContext) const;
|
||||
const void* InsertPatchV2s(PatchContext& patchContext) const;
|
||||
};
|
||||
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
#include "sections.h"
|
||||
|
||||
DEFINE_SECTION_SYMBOLS(dsprotectpatchv1_part1);
|
||||
extern "C" void dsprotectpatchv1_entry1();
|
||||
extern u16 dsprotectpatchv1_stub_protectb1_offset;
|
||||
extern u16 dsprotectpatchv1_stub_protectb2_offset;
|
||||
extern u16 dsprotectpatchv1_stub_protectb3_offset;
|
||||
extern u16 dsprotectpatchv1_nitro_static_init_offset;
|
||||
extern u16 dsprotectpatchv1_overlay_id;
|
||||
extern u32 dsprotectpatchv1_base_offset;
|
||||
extern u32 dsprotectpatchv1_part2_address;
|
||||
extern u32 dsprotectpatchv1_protectb1_return_value;
|
||||
extern u32 dsprotectpatchv1_protectb2_return_value;
|
||||
extern u32 dsprotectpatchv1_protectb3_return_value;
|
||||
|
||||
DEFINE_SECTION_SYMBOLS(dsprotectpatchv1_part2);
|
||||
extern "C" void dsprotectpatchv1_entry2();
|
||||
extern u16 dsprotectpatchv1_stub_notprotectb1_offset;
|
||||
extern u16 dsprotectpatchv1_stub_notprotectb2_offset;
|
||||
extern u16 dsprotectpatchv1_stub_notprotectb3_offset;
|
||||
extern u32 dsprotectpatchv1_nextAddress;
|
||||
extern u32 dsprotectpatchv1_notprotectb1_return_value;
|
||||
extern u32 dsprotectpatchv1_notprotectb2_return_value;
|
||||
extern u32 dsprotectpatchv1_notprotectb3_return_value;
|
||||
extern u32 dsprotectpatchv1_loadReturnValue;
|
||||
extern u32 dsprotectpatchv1_moveCallback;
|
||||
@@ -0,0 +1,168 @@
|
||||
.cpu arm946e-s
|
||||
.syntax unified
|
||||
.section "dsprotectpatchv1_part1", "ax"
|
||||
|
||||
.thumb
|
||||
|
||||
.global dsprotectpatchv1_entry1
|
||||
.type dsprotectpatchv1_entry1, %function
|
||||
dsprotectpatchv1_entry1:
|
||||
push {r4-r7,lr}
|
||||
adr r0, dsprotectpatchv1_stub_protectb1_offset
|
||||
ldrh r4, [r0, #(dsprotectpatchv1_overlay_id - dsprotectpatchv1_stub_protectb1_offset)]
|
||||
ldmia r5!, {r1, r2} // id, ram address
|
||||
cmp r1, r4
|
||||
bne continue_to_next
|
||||
|
||||
ldr r4, dsprotectpatchv1_base_offset
|
||||
adds r2, r4 // add base offset to overlay address
|
||||
|
||||
ldrh r4, [r0, #(dsprotectpatchv1_nitro_static_init_offset - dsprotectpatchv1_stub_protectb1_offset)]
|
||||
ldr r3,= 0xE12FFF1E // bx lr
|
||||
str r3, [r4, r2]
|
||||
|
||||
adr r4, protectbX_patch
|
||||
ldmia r4!, {r5,r6}
|
||||
|
||||
adds r3, r0, #(dsprotectpatchv1_nitro_static_init_offset - dsprotectpatchv1_stub_protectb1_offset)
|
||||
1:
|
||||
ldmia r4!, {r7}
|
||||
ldrh r1, [r0]
|
||||
adds r1, r2
|
||||
stmia r1!, {r5,r6,r7}
|
||||
adds r0, #2
|
||||
cmp r0, r3
|
||||
bne 1b
|
||||
|
||||
ldr r7, dsprotectpatchv1_part2_address
|
||||
bx r7
|
||||
|
||||
continue_to_next:
|
||||
ldr r7, dsprotectpatchv1_part2_address
|
||||
adds r7, #(dsprotectpatchv1_continue_to_next - dsprotectpatchv1_entry2)
|
||||
bx r7
|
||||
|
||||
.global dsprotectpatchv1_stub_protectb1_offset
|
||||
dsprotectpatchv1_stub_protectb1_offset:
|
||||
.short 0
|
||||
|
||||
.global dsprotectpatchv1_stub_protectb2_offset
|
||||
dsprotectpatchv1_stub_protectb2_offset:
|
||||
.short 0
|
||||
|
||||
.global dsprotectpatchv1_stub_protectb3_offset
|
||||
dsprotectpatchv1_stub_protectb3_offset:
|
||||
.short 0
|
||||
|
||||
.global dsprotectpatchv1_nitro_static_init_offset
|
||||
dsprotectpatchv1_nitro_static_init_offset:
|
||||
.short 0
|
||||
|
||||
.global dsprotectpatchv1_overlay_id
|
||||
dsprotectpatchv1_overlay_id:
|
||||
.short 0
|
||||
|
||||
.balign 4
|
||||
|
||||
.global dsprotectpatchv1_base_offset
|
||||
dsprotectpatchv1_base_offset:
|
||||
.word 0
|
||||
|
||||
.global dsprotectpatchv1_part2_address
|
||||
dsprotectpatchv1_part2_address:
|
||||
.word 0
|
||||
|
||||
.pool
|
||||
|
||||
.arm
|
||||
protectbX_patch:
|
||||
ldr r0, dsprotectpatchv1_protectb1_return_value
|
||||
bx lr
|
||||
.global dsprotectpatchv1_protectb1_return_value
|
||||
dsprotectpatchv1_protectb1_return_value:
|
||||
.word 1830601
|
||||
.global dsprotectpatchv1_protectb2_return_value
|
||||
dsprotectpatchv1_protectb2_return_value:
|
||||
.word 1830203
|
||||
.global dsprotectpatchv1_protectb3_return_value
|
||||
dsprotectpatchv1_protectb3_return_value:
|
||||
.word 1828014
|
||||
|
||||
.section "dsprotectpatchv1_part2", "ax"
|
||||
|
||||
.thumb
|
||||
|
||||
.global dsprotectpatchv1_entry2
|
||||
.type dsprotectpatchv1_entry2, %function
|
||||
dsprotectpatchv1_entry2:
|
||||
adr r0, dsprotectpatchv1_stub_notprotectb1_offset
|
||||
adds r1, r0, #(dsprotectpatchv1_stub_notprotectb3_offset - dsprotectpatchv1_stub_notprotectb1_offset + 2)
|
||||
mov lr, r1
|
||||
2:
|
||||
ldrh r1, [r0]
|
||||
adds r1, r2
|
||||
adr r3, notprotectbX_patch
|
||||
ldmia r3!, {r4,r5,r6,r7}
|
||||
stmia r1!, {r4,r5,r6,r7}
|
||||
ldmia r3!, {r4,r5,r6}
|
||||
stmia r1!, {r4,r5,r6}
|
||||
adds r0, #2
|
||||
cmp r0, lr
|
||||
bne 2b
|
||||
|
||||
ldmia r3!, {r6,r7}
|
||||
|
||||
adds r2, #0x18
|
||||
adr r0, dsprotectpatchv1_stub_notprotectb1_offset
|
||||
ldrh r1, [r0, #(dsprotectpatchv1_stub_notprotectb2_offset - dsprotectpatchv1_stub_notprotectb1_offset)]
|
||||
str r6, [r1, r2]
|
||||
ldrh r1, [r0, #(dsprotectpatchv1_stub_notprotectb3_offset - dsprotectpatchv1_stub_notprotectb1_offset)]
|
||||
str r7, [r1, r2]
|
||||
|
||||
dsprotectpatchv1_continue_to_next:
|
||||
ldr r0, dsprotectpatchv1_nextAddress
|
||||
pop {r4-r7,pc}
|
||||
|
||||
.global dsprotectpatchv1_stub_notprotectb1_offset
|
||||
dsprotectpatchv1_stub_notprotectb1_offset:
|
||||
.short 0
|
||||
|
||||
.global dsprotectpatchv1_stub_notprotectb2_offset
|
||||
dsprotectpatchv1_stub_notprotectb2_offset:
|
||||
.short 0
|
||||
|
||||
.global dsprotectpatchv1_stub_notprotectb3_offset
|
||||
dsprotectpatchv1_stub_notprotectb3_offset:
|
||||
.short 0
|
||||
|
||||
.balign 4
|
||||
|
||||
.global dsprotectpatchv1_nextAddress
|
||||
dsprotectpatchv1_nextAddress:
|
||||
.word 0
|
||||
|
||||
.pool
|
||||
|
||||
.arm
|
||||
notprotectbX_patch:
|
||||
push {lr}
|
||||
.global dsprotectpatchv1_moveCallback
|
||||
dsprotectpatchv1_moveCallback:
|
||||
movs lr, r0
|
||||
movne r0, r1
|
||||
blxne lr
|
||||
.global dsprotectpatchv1_loadReturnValue
|
||||
dsprotectpatchv1_loadReturnValue:
|
||||
ldr r0, dsprotectpatchv1_notprotectb1_return_value
|
||||
pop {pc}
|
||||
.global dsprotectpatchv1_notprotectb1_return_value
|
||||
dsprotectpatchv1_notprotectb1_return_value:
|
||||
.word 1831551
|
||||
.global dsprotectpatchv1_notprotectb2_return_value
|
||||
dsprotectpatchv1_notprotectb2_return_value:
|
||||
.word 1830859
|
||||
.global dsprotectpatchv1_notprotectb3_return_value
|
||||
dsprotectpatchv1_notprotectb3_return_value:
|
||||
.word 1829648
|
||||
|
||||
.end
|
||||
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
#include "sections.h"
|
||||
|
||||
DEFINE_SECTION_SYMBOLS(dsprotectpatchv2);
|
||||
|
||||
extern "C" void dsprotectpatchv2_entry();
|
||||
extern u16 dsprotectpatchv2_stub_protectb1_offset;
|
||||
extern u16 dsprotectpatchv2_stub_protectb2_offset;
|
||||
extern u16 dsprotectpatchv2_stub_protectb3_offset;
|
||||
extern u16 dsprotectpatchv2_stub_protectb4_offset;
|
||||
extern u16 dsprotectpatchv2_am_init_offset;
|
||||
extern u16 dsprotectpatchv2_overlay_id;
|
||||
extern u32 dsprotectpatchv2_nextAddress;
|
||||
extern u32 dsprotectpatchv2_checksum_fix;
|
||||
extern u32 dsprotectpatchv2_base_offset;
|
||||
|
||||
extern u16 dsprotectpatchv2_store_checksum_fix;
|
||||
@@ -0,0 +1,93 @@
|
||||
.cpu arm946e-s
|
||||
.section "dsprotectpatchv2", "ax"
|
||||
.syntax unified
|
||||
.thumb
|
||||
|
||||
.global dsprotectpatchv2_entry
|
||||
.type dsprotectpatchv2_entry, %function
|
||||
dsprotectpatchv2_entry:
|
||||
push {r4-r7,lr}
|
||||
|
||||
ldmia r5!, {r0,r1,r2}
|
||||
adds r3, r2, r1 // bss address
|
||||
|
||||
adr r2, dsprotectpatchv2_stub_protectb1_offset
|
||||
ldrh r7, [r2, #(dsprotectpatchv2_overlay_id - dsprotectpatchv2_stub_protectb1_offset)]
|
||||
cmp r0, r7
|
||||
bne continue_to_next
|
||||
|
||||
ldr r7, [r2, #(dsprotectpatchv2_base_offset - dsprotectpatchv2_stub_protectb1_offset)]
|
||||
adds r1, r7 // add base offset to overlay address
|
||||
|
||||
ldrh r0, [r2, #(dsprotectpatchv2_am_init_offset - dsprotectpatchv2_stub_protectb1_offset)]
|
||||
ldr r7,= 0xE12FFF1E // bx lr
|
||||
str r7, [r1, r0]
|
||||
|
||||
adr r0, stub_patch_code
|
||||
ldmia r0!, {r4,r5,r6,r7}
|
||||
|
||||
subs r1, #4 // write from 4 bytes before the actual function address
|
||||
adds r0, r2, #(dsprotectpatchv2_stub_protectb4_offset - dsprotectpatchv2_stub_protectb1_offset)
|
||||
mov lr, r0
|
||||
patch_loop:
|
||||
ldrh r0, [r2]
|
||||
adds r2, #2
|
||||
adds r0, r1
|
||||
stmia r0!, {r3,r4,r5,r6} // bss address + code
|
||||
.global dsprotectpatchv2_store_checksum_fix
|
||||
dsprotectpatchv2_store_checksum_fix:
|
||||
str r7, [r0, #0] // checksum fix
|
||||
cmp r2, lr
|
||||
ble patch_loop
|
||||
|
||||
continue_to_next:
|
||||
ldr r0, dsprotectpatchv2_nextAddress
|
||||
pop {r4-r7,pc}
|
||||
|
||||
.balign 4
|
||||
|
||||
.global dsprotectpatchv2_stub_protectb1_offset
|
||||
dsprotectpatchv2_stub_protectb1_offset:
|
||||
.short 0
|
||||
|
||||
.global dsprotectpatchv2_stub_protectb2_offset
|
||||
dsprotectpatchv2_stub_protectb2_offset:
|
||||
.short 0
|
||||
|
||||
.global dsprotectpatchv2_stub_protectb3_offset
|
||||
dsprotectpatchv2_stub_protectb3_offset:
|
||||
.short 0
|
||||
|
||||
.global dsprotectpatchv2_stub_protectb4_offset
|
||||
dsprotectpatchv2_stub_protectb4_offset:
|
||||
.short 0
|
||||
|
||||
.global dsprotectpatchv2_am_init_offset
|
||||
dsprotectpatchv2_am_init_offset:
|
||||
.short 0
|
||||
|
||||
.global dsprotectpatchv2_overlay_id
|
||||
dsprotectpatchv2_overlay_id:
|
||||
.short 0
|
||||
|
||||
.global dsprotectpatchv2_base_offset
|
||||
dsprotectpatchv2_base_offset:
|
||||
.word 0
|
||||
|
||||
.global dsprotectpatchv2_nextAddress
|
||||
dsprotectpatchv2_nextAddress:
|
||||
.word 0
|
||||
|
||||
.pool
|
||||
|
||||
.arm
|
||||
stub_patch_code:
|
||||
ldr r12, (. - 4)
|
||||
ldr r2, [r12], #4
|
||||
ldr pc, [r12, r2, lsl #2]
|
||||
|
||||
.global dsprotectpatchv2_checksum_fix
|
||||
dsprotectpatchv2_checksum_fix:
|
||||
.word 0
|
||||
|
||||
.end
|
||||
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include "sections.h"
|
||||
|
||||
DEFINE_SECTION_SYMBOLS(dsprotectpatchv2s);
|
||||
|
||||
extern "C" void dsprotectpatchv2s_entry();
|
||||
extern u32 dsprotectpatchv2s_stub_instantdetect_offset;
|
||||
extern u32 dsprotectpatchv2s_overlay_id;
|
||||
extern u32 dsprotectpatchv2s_nextAddress;
|
||||
extern u32 dsprotectpatchv2s_checksum_fix;
|
||||
|
||||
extern u16 dsprotectpatchv2s_store_checksum_fix;
|
||||
@@ -0,0 +1,64 @@
|
||||
.cpu arm946e-s
|
||||
.section "dsprotectpatchv2s", "ax"
|
||||
.syntax unified
|
||||
.thumb
|
||||
|
||||
.global dsprotectpatchv2s_entry
|
||||
.type dsprotectpatchv2s_entry, %function
|
||||
dsprotectpatchv2s_entry:
|
||||
push {r4-r7,lr}
|
||||
|
||||
ldmia r5!, {r0,r1,r2,r3,r4}
|
||||
|
||||
ldr r7, dsprotectpatchv2s_overlay_id
|
||||
cmp r0, r7
|
||||
bne continue_to_next
|
||||
|
||||
movs r3, #0
|
||||
movs r7, #0
|
||||
stmia r4!, {r3,r7}
|
||||
stmia r4!, {r3,r7}
|
||||
str r3, [r4]
|
||||
|
||||
adr r0, stub_patch_code
|
||||
ldmia r0!, {r3,r4,r5,r6,r7}
|
||||
|
||||
ldr r0, dsprotectpatchv2s_stub_instantdetect_offset
|
||||
adds r0, r1
|
||||
stmia r0!, {r3,r4,r5,r6} // code
|
||||
.global dsprotectpatchv2s_store_checksum_fix
|
||||
dsprotectpatchv2s_store_checksum_fix:
|
||||
str r7, [r0, #0] // checksum fix
|
||||
|
||||
continue_to_next:
|
||||
ldr r0, dsprotectpatchv2s_nextAddress
|
||||
pop {r4-r7,pc}
|
||||
|
||||
.balign 4
|
||||
|
||||
.global dsprotectpatchv2s_stub_instantdetect_offset
|
||||
dsprotectpatchv2s_stub_instantdetect_offset:
|
||||
.word 0
|
||||
|
||||
.global dsprotectpatchv2s_overlay_id
|
||||
dsprotectpatchv2s_overlay_id:
|
||||
.word 0
|
||||
|
||||
.global dsprotectpatchv2s_nextAddress
|
||||
dsprotectpatchv2s_nextAddress:
|
||||
.word 0
|
||||
|
||||
.pool
|
||||
|
||||
.arm
|
||||
stub_patch_code:
|
||||
movs r3, r0
|
||||
pusheq {r0,r1,lr}
|
||||
pushne {r1,r2,r3}
|
||||
pop {r0,r1,pc}
|
||||
|
||||
.global dsprotectpatchv2s_checksum_fix
|
||||
dsprotectpatchv2s_checksum_fix:
|
||||
.word 0
|
||||
|
||||
.end
|
||||
@@ -0,0 +1,160 @@
|
||||
#include "common.h"
|
||||
#include "../../PatchContext.h"
|
||||
#include "thumbInstructions.h"
|
||||
#include "FsStartOverlayHookPatch.h"
|
||||
|
||||
static const u32 sFSStartOverlayPatternSdk4[] = { 0xE59F10D0u, 0xE1A04000u, 0xE1D100B0u, 0xE3500002u }; // -0xC
|
||||
static const u32 sFSStartOverlayPatternSdk4Thumb[] = { 0x481F1C06u, 0x28028800u, 0x69E8D121u, 0x0E012700u }; // -8
|
||||
static const u32 sFSStartOverlayPattern[] = { 0xE3500001u, 0x0A00001Cu, 0xE595001Cu, 0xE3A03000u }; // -0x14
|
||||
static const u32 sFSStartOverlayPatternThumb[] = { 0x69E8D023u, 0x0E012600u, 0x42082002u, 0x491BD013u }; // -0x10
|
||||
static const u32 sFSStartOverlayPatternThumbHybrid[] = { 0x68691C07u, 0x42814828u, 0x4828D30Cu, 0xD2094281u }; // -8
|
||||
|
||||
extern "C" void fsstartoverlayhook_entry();
|
||||
|
||||
extern u8 __fsstartoverlayhook_start[];
|
||||
extern u8 __fsstartoverlayhook_end[];
|
||||
|
||||
extern u32 fsstartoverlayhook_dcFlushRangeOffset;
|
||||
extern u32 fsstartoverlayhook_hookFuncAddress;
|
||||
|
||||
bool FsStartOverlayHookPatch::FindPatchTarget(PatchContext& patchContext)
|
||||
{
|
||||
if (!_patchHead) // no patches
|
||||
return true;
|
||||
|
||||
if (patchContext.GetSdkVersion().GetMajor() <= 4)
|
||||
{
|
||||
_fsStartOverlay = patchContext.FindPattern32(sFSStartOverlayPatternSdk4, sizeof(sFSStartOverlayPatternSdk4));
|
||||
if (_fsStartOverlay)
|
||||
{
|
||||
_fsStartOverlay -= 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
_fsStartOverlay = patchContext.FindPattern32(sFSStartOverlayPatternSdk4Thumb, sizeof(sFSStartOverlayPatternSdk4Thumb));
|
||||
if (_fsStartOverlay)
|
||||
{
|
||||
_fsStartOverlay -= 2;
|
||||
_thumb = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_fsStartOverlay = patchContext.FindPattern32(sFSStartOverlayPattern, sizeof(sFSStartOverlayPattern));
|
||||
if (_fsStartOverlay)
|
||||
{
|
||||
_fsStartOverlay -= 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
_fsStartOverlay = patchContext.FindPattern32(sFSStartOverlayPatternThumb, sizeof(sFSStartOverlayPatternThumb));
|
||||
if (_fsStartOverlay)
|
||||
{
|
||||
_fsStartOverlay -= 4;
|
||||
_thumb = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_fsStartOverlay = patchContext.FindPattern32(sFSStartOverlayPatternThumbHybrid, sizeof(sFSStartOverlayPatternThumbHybrid));
|
||||
if (_fsStartOverlay)
|
||||
{
|
||||
_fsStartOverlay -= 2;
|
||||
_thumb = true;
|
||||
_hybrid = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_fsStartOverlay)
|
||||
{
|
||||
LOG_DEBUG("FS_StartOverlay found at 0x%p\n", _fsStartOverlay);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_WARNING("FS_StartOverlay not found\n");
|
||||
}
|
||||
|
||||
return _fsStartOverlay != nullptr;
|
||||
}
|
||||
|
||||
void FsStartOverlayHookPatch::ApplyPatch(PatchContext& patchContext)
|
||||
{
|
||||
if (!_fsStartOverlay)
|
||||
return;
|
||||
|
||||
if (!_patchHead) // no patches
|
||||
return;
|
||||
|
||||
const void* firstPatch = _patchHead->InsertPatch(patchContext);
|
||||
|
||||
if (!firstPatch)
|
||||
return;
|
||||
|
||||
fsstartoverlayhook_hookFuncAddress = (u32)firstPatch;
|
||||
|
||||
u32 patchOffset;
|
||||
if (_thumb)
|
||||
{
|
||||
u32 blDcFlushRange1;
|
||||
u32 blDcFlushRange2;
|
||||
if (_hybrid)
|
||||
{
|
||||
patchOffset = 0x8E;
|
||||
blDcFlushRange1 = *(u16*)((u8*)_fsStartOverlay + 0x92);
|
||||
blDcFlushRange2 = *(u16*)((u8*)_fsStartOverlay + 0x94);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (patchContext.GetSdkVersion().GetMajor() <= 4)
|
||||
{
|
||||
patchOffset = 0x68;
|
||||
blDcFlushRange1 = *(u16*)((u8*)_fsStartOverlay + 0x6C);
|
||||
blDcFlushRange2 = *(u16*)((u8*)_fsStartOverlay + 0x6E);
|
||||
}
|
||||
else
|
||||
{
|
||||
patchOffset = 0x6C;
|
||||
blDcFlushRange1 = *(u16*)((u8*)_fsStartOverlay + 0x70);
|
||||
blDcFlushRange2 = *(u16*)((u8*)_fsStartOverlay + 0x72);
|
||||
}
|
||||
}
|
||||
fsstartoverlayhook_dcFlushRangeOffset = ((int)((((blDcFlushRange1 & 0x7FF) << 11) | (blDcFlushRange2 & 0x7FF)) << 10) >> 9) - (_hybrid ? 5 : 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
patchOffset = 0xAC;
|
||||
u32 blDcFlushRange = *(u32*)((u8*)_fsStartOverlay + 0xB0);
|
||||
fsstartoverlayhook_dcFlushRangeOffset = (int)((blDcFlushRange & 0xFFFFFF) << 8) >> 6;
|
||||
}
|
||||
|
||||
u32 patch1Size = (u32)__fsstartoverlayhook_end - (u32)__fsstartoverlayhook_start;
|
||||
void* patch1Address = patchContext.GetPatchHeap().Alloc(patch1Size);
|
||||
|
||||
u32 entryAddress = (u32)&fsstartoverlayhook_entry - (u32)__fsstartoverlayhook_start + (u32)patch1Address;
|
||||
memcpy(patch1Address, __fsstartoverlayhook_start, patch1Size);
|
||||
|
||||
if (_thumb)
|
||||
{
|
||||
if (_hybrid)
|
||||
{
|
||||
*(u16*)((u8*)_fsStartOverlay + patchOffset + 0) = THUMB_LDR_PC_IMM(THUMB_R0, 4);
|
||||
*(u16*)((u8*)_fsStartOverlay + patchOffset + 2) = THUMB_NOP;
|
||||
*(u16*)((u8*)_fsStartOverlay + patchOffset + 4) = THUMB_BLX(THUMB_R0);
|
||||
*(u32*)((u8*)_fsStartOverlay + patchOffset + 6) = entryAddress;
|
||||
}
|
||||
else
|
||||
{
|
||||
*(u16*)((u8*)_fsStartOverlay + patchOffset + 0) = THUMB_LDR_PC_IMM(THUMB_R0, 0);
|
||||
*(u16*)((u8*)_fsStartOverlay + patchOffset + 2) = THUMB_BLX(THUMB_R0);
|
||||
*(u32*)((u8*)_fsStartOverlay + patchOffset + 4) = entryAddress;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*(u32*)((u8*)_fsStartOverlay + patchOffset + 0) = 0xE59F0000; // ldr r0,= entryAddress
|
||||
*(u32*)((u8*)_fsStartOverlay + patchOffset + 4) = 0xE12FFF30; // blx r0
|
||||
*(u32*)((u8*)_fsStartOverlay + patchOffset + 8) = entryAddress;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
#include "OverlayHookPatch.h"
|
||||
|
||||
/// @brief Arm9 patch to apply patches to overlays when they are loaded.
|
||||
class FsStartOverlayHookPatch : public OverlayHookPatch
|
||||
{
|
||||
public:
|
||||
bool FindPatchTarget(PatchContext& patchContext) override;
|
||||
void ApplyPatch(PatchContext& patchContext) override;
|
||||
|
||||
private:
|
||||
u32* _fsStartOverlay = nullptr;
|
||||
u16 _thumb = false;
|
||||
u16 _hybrid = false;
|
||||
};
|
||||
@@ -0,0 +1,45 @@
|
||||
.cpu arm946e-s
|
||||
.section ".fsstartoverlayhook", "ax"
|
||||
.syntax unified
|
||||
.thumb
|
||||
|
||||
.global __fsstartoverlayhook_start
|
||||
__fsstartoverlayhook_start:
|
||||
|
||||
.global fsstartoverlayhook_entry
|
||||
.type fsstartoverlayhook_entry, %function
|
||||
fsstartoverlayhook_entry:
|
||||
movs r0, #0x4
|
||||
add lr, r0
|
||||
ldr r2, fsstartoverlayhook_dcFlushRangeOffset
|
||||
add r2, lr
|
||||
push {r2,lr}
|
||||
ldr r0, fsstartoverlayhook_hookFuncAddress
|
||||
1:
|
||||
blx r0
|
||||
cmp r0, #0
|
||||
bne 1b
|
||||
|
||||
ldr r0, [r5, #4]
|
||||
ldr r1, [r5, #8]
|
||||
pop {r2}
|
||||
blx r2
|
||||
ldr r4, [r5, #0x10]
|
||||
pop {pc}
|
||||
|
||||
.balign 4
|
||||
|
||||
.global fsstartoverlayhook_dcFlushRangeOffset
|
||||
fsstartoverlayhook_dcFlushRangeOffset:
|
||||
.word 0
|
||||
|
||||
.global fsstartoverlayhook_hookFuncAddress
|
||||
fsstartoverlayhook_hookFuncAddress:
|
||||
.word 0
|
||||
|
||||
.pool
|
||||
|
||||
.global __fsstartoverlayhook_end
|
||||
__fsstartoverlayhook_end:
|
||||
|
||||
.end
|
||||
@@ -0,0 +1,34 @@
|
||||
#include "common.h"
|
||||
#include "../../../PatchContext.h"
|
||||
#include "GoldenSunDarkDawnOverlayHookPatchAsm.h"
|
||||
#include "GoldenSunDarkDawnOverlayHookPatch.h"
|
||||
|
||||
static const u32 sStartOverlayPattern[] = { 0xE92D4038u, 0xE1A05000u, 0xEBFFFF92u, 0xE595101Cu };
|
||||
|
||||
bool GoldenSunDarkDawnOverlayHookPatch::FindPatchTarget(PatchContext& patchContext)
|
||||
{
|
||||
_overlayStartFunc = patchContext.FindPattern32(sStartOverlayPattern, sizeof(sStartOverlayPattern));
|
||||
return _overlayStartFunc != nullptr;
|
||||
}
|
||||
|
||||
void GoldenSunDarkDawnOverlayHookPatch::ApplyPatch(PatchContext& patchContext)
|
||||
{
|
||||
if (!_overlayStartFunc)
|
||||
return;
|
||||
|
||||
if (!_patchHead) // no patches
|
||||
return;
|
||||
|
||||
gsddoverlayhookpatch_hookFuncAddress = (u32)_patchHead->InsertPatch(patchContext);
|
||||
gsddoverlayhookpatch_returnAddress = (u32)_overlayStartFunc + 0x30;
|
||||
|
||||
u32 patch1Size = SECTION_SIZE(gsddoverlayhookpatch);
|
||||
void* patch1Address = patchContext.GetPatchHeap().Alloc(patch1Size);
|
||||
|
||||
u32 entryAddress = (u32)&gsddoverlayhookpatch_entry - (u32)SECTION_START(gsddoverlayhookpatch) + (u32)patch1Address;
|
||||
|
||||
*(u32*)((u8*)_overlayStartFunc + 0x28) = 0xE51FF004; // ldr pc,= entryAddress
|
||||
*(u32*)((u8*)_overlayStartFunc + 0x2C) = entryAddress;
|
||||
|
||||
memcpy(patch1Address, SECTION_START(gsddoverlayhookpatch), patch1Size);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
#include "../OverlayHookPatch.h"
|
||||
|
||||
/// @brief Arm9 patch to apply patches to overlays when they are loaded in Golden Sun Dark Dawn.
|
||||
class GoldenSunDarkDawnOverlayHookPatch : public OverlayHookPatch
|
||||
{
|
||||
public:
|
||||
bool FindPatchTarget(PatchContext& patchContext) override;
|
||||
void ApplyPatch(PatchContext& patchContext) override;
|
||||
|
||||
private:
|
||||
u32* _overlayStartFunc;
|
||||
};
|
||||
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#include "sections.h"
|
||||
|
||||
DEFINE_SECTION_SYMBOLS(gsddoverlayhookpatch);
|
||||
|
||||
extern "C" void gsddoverlayhookpatch_entry();
|
||||
|
||||
extern u32 gsddoverlayhookpatch_hookFuncAddress;
|
||||
extern u32 gsddoverlayhookpatch_returnAddress;
|
||||
@@ -0,0 +1,34 @@
|
||||
.cpu arm946e-s
|
||||
.section "gsddoverlayhookpatch", "ax"
|
||||
.syntax unified
|
||||
.thumb
|
||||
|
||||
.global gsddoverlayhookpatch_entry
|
||||
.type gsddoverlayhookpatch_entry, %function
|
||||
gsddoverlayhookpatch_entry:
|
||||
ldr r0, gsddoverlayhookpatch_hookFuncAddress
|
||||
1:
|
||||
blx r0
|
||||
cmp r0, #0
|
||||
bne 1b
|
||||
|
||||
ldr r3, gsddoverlayhookpatch_returnAddress
|
||||
ldr r1, [r5, #8]
|
||||
movs r0, #1
|
||||
lsls r0, r0, #14 // r0 = 0x4000
|
||||
cmp r1, r0
|
||||
bx r3
|
||||
|
||||
.balign 4
|
||||
|
||||
.global gsddoverlayhookpatch_hookFuncAddress
|
||||
gsddoverlayhookpatch_hookFuncAddress:
|
||||
.word 0
|
||||
|
||||
.global gsddoverlayhookpatch_returnAddress
|
||||
gsddoverlayhookpatch_returnAddress:
|
||||
.word 0
|
||||
|
||||
.pool
|
||||
|
||||
.end
|
||||
24
arm9/source/patches/arm9/OverlayPatches/OverlayHookPatch.h
Normal file
24
arm9/source/patches/arm9/OverlayPatches/OverlayHookPatch.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
#include "../../Patch.h"
|
||||
#include "OverlayPatch.h"
|
||||
|
||||
/// @brief Abstract base class for a patch that applies patches to overlays when they are loaded.
|
||||
class OverlayHookPatch : public Patch
|
||||
{
|
||||
public:
|
||||
/// @brief Adds an overlay patch to the list.
|
||||
/// @param patch The overlay pach to add.
|
||||
void AddOverlayPatch(OverlayPatch* patch)
|
||||
{
|
||||
LOG_DEBUG("OverlayHookPatch::AddOverlayPatch\n");
|
||||
if (!_patchHead)
|
||||
_patchHead = patch;
|
||||
if (_patchTail)
|
||||
_patchTail->next = patch;
|
||||
_patchTail = patch;
|
||||
}
|
||||
|
||||
protected:
|
||||
OverlayPatch* _patchHead = nullptr;
|
||||
OverlayPatch* _patchTail = nullptr;
|
||||
};
|
||||
15
arm9/source/patches/arm9/OverlayPatches/OverlayPatch.h
Normal file
15
arm9/source/patches/arm9/OverlayPatches/OverlayPatch.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
class PatchContext;
|
||||
|
||||
/// @brief Patch to be applied when an overlay is loaded.
|
||||
class OverlayPatch
|
||||
{
|
||||
public:
|
||||
/// @brief Pointer to the next overlay patch, or \c nullptr when none.
|
||||
OverlayPatch* next = nullptr;
|
||||
|
||||
/// @brief Inserts the patch using the given \p patchContext.
|
||||
/// @param patchContext The patch context to use.
|
||||
/// @return A pointer to the patch function.
|
||||
virtual const void* InsertPatch(PatchContext& patchContext) = 0;
|
||||
};
|
||||
@@ -0,0 +1,13 @@
|
||||
#include "common.h"
|
||||
#include "../../../PatchContext.h"
|
||||
#include "PokemonBw1IrApPatchAsm.h"
|
||||
#include "PokemonBw1IrApPatch.h"
|
||||
|
||||
const void* PokemonBw1IrApPatch::InsertPatch(PatchContext& patchContext)
|
||||
{
|
||||
return patchContext.GetPatchCodeCollection().AddUniquePatchCode<PokemonBw1IrApPatchCode>
|
||||
(
|
||||
patchContext.GetPatchHeap(),
|
||||
next ? next->InsertPatch(patchContext) : nullptr
|
||||
)->GetPatchFunction();
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#include "../OverlayPatch.h"
|
||||
|
||||
/// @brief Arm9 overlay patch to disable the Pokemon Black & White IR-sensor anti-piracy.
|
||||
class PokemonBw1IrApPatch : public OverlayPatch
|
||||
{
|
||||
public:
|
||||
const void* InsertPatch(PatchContext& patchContext) override;
|
||||
};
|
||||
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
#include "sections.h"
|
||||
#include "../../../PatchCode.h"
|
||||
|
||||
DEFINE_SECTION_SYMBOLS(pokemonbw1irappatch);
|
||||
|
||||
extern "C" void pokemonbw1irappatch_entry();
|
||||
|
||||
extern u32 pokemonbw1irappatch_nextAddress;
|
||||
|
||||
class PokemonBw1IrApPatchCode : public PatchCode
|
||||
{
|
||||
public:
|
||||
PokemonBw1IrApPatchCode(PatchHeap& patchHeap, const void* nextPatch)
|
||||
: PatchCode(SECTION_START(pokemonbw1irappatch), SECTION_SIZE(pokemonbw1irappatch), patchHeap)
|
||||
{
|
||||
pokemonbw1irappatch_nextAddress = (u32)nextPatch;
|
||||
}
|
||||
|
||||
const void* GetPatchFunction() const
|
||||
{
|
||||
return GetAddressAtTarget((void*)pokemonbw1irappatch_entry);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,32 @@
|
||||
.cpu arm946e-s
|
||||
.syntax unified
|
||||
.section "pokemonbw1irappatch", "ax"
|
||||
.thumb
|
||||
|
||||
.global pokemonbw1irappatch_entry
|
||||
.type pokemonbw1irappatch_entry, %function
|
||||
pokemonbw1irappatch_entry:
|
||||
push {r5,lr}
|
||||
|
||||
ldmia r5!, {r1, r2} // id, ram address
|
||||
ldr r0,= 231 // target overlay id
|
||||
cmp r0, r1
|
||||
bne continue_to_next
|
||||
ldr r1,= 0x1CA // patch offset in overlay
|
||||
movs r0, #1 // force return value of function to 1 instead of 0
|
||||
adds r2, r1
|
||||
strb r0, [r2]
|
||||
|
||||
continue_to_next:
|
||||
ldr r0, pokemonbw1irappatch_nextAddress
|
||||
pop {r5,pc}
|
||||
|
||||
.balign 4
|
||||
|
||||
.global pokemonbw1irappatch_nextAddress
|
||||
pokemonbw1irappatch_nextAddress:
|
||||
.word 0
|
||||
|
||||
.pool
|
||||
|
||||
.end
|
||||
@@ -0,0 +1,13 @@
|
||||
#include "common.h"
|
||||
#include "../../../PatchContext.h"
|
||||
#include "PokemonBw2IrApPatchAsm.h"
|
||||
#include "PokemonBw2IrApPatch.h"
|
||||
|
||||
const void* PokemonBw2IrApPatch::InsertPatch(PatchContext& patchContext)
|
||||
{
|
||||
return patchContext.GetPatchCodeCollection().AddUniquePatchCode<PokemonBw2IrApPatchCode>
|
||||
(
|
||||
patchContext.GetPatchHeap(),
|
||||
next ? next->InsertPatch(patchContext) : nullptr
|
||||
)->GetPatchFunction();
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#include "../OverlayPatch.h"
|
||||
|
||||
/// @brief Arm9 overlay patch to disable the Pokemon Black & White 2 IR-sensor anti-piracy.
|
||||
class PokemonBw2IrApPatch : public OverlayPatch
|
||||
{
|
||||
public:
|
||||
const void* InsertPatch(PatchContext& patchContext) override;
|
||||
};
|
||||
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
#include "sections.h"
|
||||
#include "../../../PatchCode.h"
|
||||
|
||||
DEFINE_SECTION_SYMBOLS(pokemonbw2irappatch);
|
||||
|
||||
extern "C" void pokemonbw2irappatch_entry();
|
||||
|
||||
extern u32 pokemonbw2irappatch_nextAddress;
|
||||
|
||||
class PokemonBw2IrApPatchCode : public PatchCode
|
||||
{
|
||||
public:
|
||||
PokemonBw2IrApPatchCode(PatchHeap& patchHeap, const void* nextPatch)
|
||||
: PatchCode(SECTION_START(pokemonbw2irappatch), SECTION_SIZE(pokemonbw2irappatch), patchHeap)
|
||||
{
|
||||
pokemonbw2irappatch_nextAddress = (u32)nextPatch;
|
||||
}
|
||||
|
||||
const void* GetPatchFunction() const
|
||||
{
|
||||
return GetAddressAtTarget((void*)pokemonbw2irappatch_entry);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,36 @@
|
||||
.cpu arm946e-s
|
||||
.syntax unified
|
||||
.section "pokemonbw2irappatch", "ax"
|
||||
.thumb
|
||||
|
||||
.global pokemonbw2irappatch_entry
|
||||
.type pokemonbw2irappatch_entry, %function
|
||||
pokemonbw2irappatch_entry:
|
||||
push {r5,lr}
|
||||
|
||||
ldmia r5!, {r1, r2} // id, ram address
|
||||
ldr r0,= 338 // target overlay id
|
||||
cmp r0, r1
|
||||
bne continue_to_next
|
||||
movs r0, #0
|
||||
adds r2, #0xEC
|
||||
strh r0, [r2]
|
||||
adds r2, #(0x1B8 - 0xEC)
|
||||
ldr r0,= 0x47702001
|
||||
str r0, [r2]
|
||||
movs r0, #1
|
||||
strb r0, [r2, #(0x1CA - 0x1B8)]
|
||||
|
||||
continue_to_next:
|
||||
ldr r0, pokemonbw2irappatch_nextAddress
|
||||
pop {r5,pc}
|
||||
|
||||
.balign 4
|
||||
|
||||
.global pokemonbw2irappatch_nextAddress
|
||||
pokemonbw2irappatch_nextAddress:
|
||||
.word 0
|
||||
|
||||
.pool
|
||||
|
||||
.end
|
||||
36
arm9/source/patches/arm9/PokemonDownloaderArm9Patch.cpp
Normal file
36
arm9/source/patches/arm9/PokemonDownloaderArm9Patch.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
#include "common.h"
|
||||
#include "../PatchContext.h"
|
||||
#include "../platform/LoaderPlatform.h"
|
||||
#include "PokemonDownloaderArm9PatchAsm.h"
|
||||
#include "PokemonDownloaderArm9Patch.h"
|
||||
|
||||
static const u32 sBootFunctionPattern[] = { 0xE92D4010u, 0xE59F003Cu, 0xE5904000u, 0xE3540000u };
|
||||
|
||||
bool PokemonDownloaderArm9Patch::FindPatchTarget(PatchContext& patchContext)
|
||||
{
|
||||
_bootFunction = patchContext.FindPattern32(sBootFunctionPattern, sizeof(sBootFunctionPattern));
|
||||
return _bootFunction != nullptr;
|
||||
}
|
||||
|
||||
void PokemonDownloaderArm9Patch::ApplyPatch(PatchContext& patchContext)
|
||||
{
|
||||
if (!_bootFunction)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto loaderInfoTarget = (loader_info_t*)patchContext.GetPatchHeap().Alloc(sizeof(loader_info_t));
|
||||
memcpy(loaderInfoTarget, _loaderInfo, sizeof(loader_info_t));
|
||||
|
||||
auto sdReadPatchCode = patchContext.GetLoaderPlatform()->CreateSdReadPatchCode(
|
||||
patchContext.GetPatchCodeCollection(), patchContext.GetPatchHeap());
|
||||
auto patchCode = patchContext.GetPatchCodeCollection().AddUniquePatchCode<PokemonDownloaderArm9PatchCode>
|
||||
(
|
||||
patchContext.GetPatchHeap(),
|
||||
loaderInfoTarget,
|
||||
sdReadPatchCode
|
||||
);
|
||||
|
||||
_bootFunction[0] = 0xE51FF004;
|
||||
_bootFunction[1] = (u32)patchCode->GetBoot9Function();
|
||||
}
|
||||
18
arm9/source/patches/arm9/PokemonDownloaderArm9Patch.h
Normal file
18
arm9/source/patches/arm9/PokemonDownloaderArm9Patch.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
#include "../Patch.h"
|
||||
#include "LoaderInfo.h"
|
||||
|
||||
/// @brief Arm9 patch to make the Pokemon downloader reboot into Pico Loader.
|
||||
class PokemonDownloaderArm9Patch : public Patch
|
||||
{
|
||||
public:
|
||||
explicit PokemonDownloaderArm9Patch(const loader_info_t* loaderInfo)
|
||||
: _loaderInfo(loaderInfo) { }
|
||||
|
||||
bool FindPatchTarget(PatchContext& patchContext) override;
|
||||
void ApplyPatch(PatchContext& patchContext) override;
|
||||
|
||||
private:
|
||||
u32* _bootFunction = nullptr;
|
||||
const loader_info_t* _loaderInfo;
|
||||
};
|
||||
29
arm9/source/patches/arm9/PokemonDownloaderArm9PatchAsm.h
Normal file
29
arm9/source/patches/arm9/PokemonDownloaderArm9PatchAsm.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
#include "../PatchCode.h"
|
||||
#include "sections.h"
|
||||
#include "LoaderInfo.h"
|
||||
#include "../platform/SdReadPatchCode.h"
|
||||
|
||||
DEFINE_SECTION_SYMBOLS(patch_pokemondownloader9);
|
||||
|
||||
extern "C" void patch_pokemondownloader9_entry(void);
|
||||
|
||||
extern const loader_info_t* patch_pokemondownloader9_loader_info_address;
|
||||
extern u32 patch_pokemondownloader9_readSdSectors_address;
|
||||
|
||||
class PokemonDownloaderArm9PatchCode : public PatchCode
|
||||
{
|
||||
public:
|
||||
PokemonDownloaderArm9PatchCode(PatchHeap& patchHeap, const loader_info_t* loaderInfo,
|
||||
const SdReadPatchCode* sdReadPatchCode)
|
||||
: PatchCode(SECTION_START(patch_pokemondownloader9), SECTION_SIZE(patch_pokemondownloader9), patchHeap)
|
||||
{
|
||||
patch_pokemondownloader9_loader_info_address = loaderInfo;
|
||||
patch_pokemondownloader9_readSdSectors_address = (u32)sdReadPatchCode->GetSdReadFunction();
|
||||
}
|
||||
|
||||
const void* GetBoot9Function() const
|
||||
{
|
||||
return GetAddressAtTarget((void*)patch_pokemondownloader9_entry);
|
||||
}
|
||||
};
|
||||
99
arm9/source/patches/arm9/PokemonDownloaderArm9PatchAsm.s
Normal file
99
arm9/source/patches/arm9/PokemonDownloaderArm9PatchAsm.s
Normal file
@@ -0,0 +1,99 @@
|
||||
.cpu arm946e-s
|
||||
.section "patch_pokemondownloader9", "ax"
|
||||
.syntax unified
|
||||
|
||||
.thumb
|
||||
.global patch_pokemondownloader9_entry
|
||||
.type patch_pokemondownloader9_entry, %function
|
||||
patch_pokemondownloader9_entry:
|
||||
ldr r0,= 0x04000204
|
||||
ldrh r1, [r0]
|
||||
movs r2, #1
|
||||
lsls r2, r2, #11
|
||||
bics r1, r2
|
||||
strh r1, [r0]
|
||||
|
||||
adr r0, regVramCntA
|
||||
// regVramCntA, vramAbcdLcdcSetting, readSdSectors_address, loader_info_address
|
||||
ldmia r0!, {r2, r3, r4, r5}
|
||||
|
||||
// r9 = readSdSectors_address
|
||||
mov r9, r4
|
||||
|
||||
// map vram ABCD to LCDC
|
||||
str r3, [r2]
|
||||
|
||||
// load pico loader arm9
|
||||
ldmia r5!, {r4,r6,r7} // clusterShift, database, clusterMap[0]
|
||||
ldr r7,= 0x06800000
|
||||
mov r11, pc
|
||||
b loadData
|
||||
|
||||
// load pico loader arm7
|
||||
ldr r5, patch_pokemondownloader9_loader_info_address
|
||||
adds r5, #52
|
||||
ldr r7,= 0x06840000
|
||||
mov r11, pc
|
||||
b loadData
|
||||
|
||||
ldr r3, patch_pokemondownloader9_loader_info_address
|
||||
ldrh r0, [r3, #2] // loader_info_t::picoLoaderBootDrive
|
||||
movs r7, #1
|
||||
lsls r7, r7, #15 // PLOAD_BOOT_DRIVE_MULTIBOOT_FLAG
|
||||
orrs r0, r7
|
||||
ldr r5,= 0x06840000
|
||||
strh r0, [r5, #8] // pload_header7_t::bootDrive
|
||||
|
||||
// map vram CD to arm7
|
||||
ldr r0, regVramCntA
|
||||
ldr r7,= 0x8A82
|
||||
strh r7, [r0, #2]
|
||||
|
||||
adds r0, #(0x04000180 - 0x04000240) // REG_IPC_SYNC
|
||||
|
||||
1:
|
||||
ldrb r7, [r0] // ipc sync
|
||||
cmp r7, #1
|
||||
bne 1b // while ipc sync from arm7 is not 1
|
||||
|
||||
movs r1, #1
|
||||
strb r1, [r0, #1]
|
||||
|
||||
ldr r0,= 0x06800000
|
||||
bx r0
|
||||
|
||||
loadData_loop:
|
||||
subs r3, #2
|
||||
lsls r3, r4
|
||||
adds r0, r3, r6 // start sector
|
||||
movs r1, r7 // dst
|
||||
lsls r2, r4 // sector count
|
||||
lsls r3, r2, #9
|
||||
adds r7, r3
|
||||
|
||||
blx r9 // read sectors
|
||||
|
||||
loadData:
|
||||
ldmia r5!, {r2, r3} // ncl, startSector
|
||||
cmp r2, #0
|
||||
bne loadData_loop
|
||||
mov pc, r11
|
||||
|
||||
.balign 4
|
||||
|
||||
regVramCntA:
|
||||
.word 0x04000240
|
||||
|
||||
vramAbcdLcdcSetting:
|
||||
.word 0x80808080
|
||||
|
||||
.global patch_pokemondownloader9_readSdSectors_address
|
||||
patch_pokemondownloader9_readSdSectors_address:
|
||||
.word 0
|
||||
|
||||
.global patch_pokemondownloader9_loader_info_address
|
||||
patch_pokemondownloader9_loader_info_address:
|
||||
.word 0
|
||||
|
||||
.pool
|
||||
.end
|
||||
25
arm9/source/patches/arm9/RomOffsetToSdSectorAsm.h
Normal file
25
arm9/source/patches/arm9/RomOffsetToSdSectorAsm.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
#include "sections.h"
|
||||
#include "../SectorRemapPatchCode.h"
|
||||
#include "fileInfo.h"
|
||||
|
||||
DEFINE_SECTION_SYMBOLS(romoffsettosdsector);
|
||||
|
||||
extern "C" u32 rom_offset_to_sd_sector_asm(u32 romOffset);
|
||||
|
||||
extern u32 romoffsettosdsector_fatDataPtr;
|
||||
|
||||
class RomOffsetToSdSectorPatchCode : public SectorRemapPatchCode
|
||||
{
|
||||
public:
|
||||
RomOffsetToSdSectorPatchCode(PatchHeap& patchHeap, const rom_file_info_t* fatDataPtr)
|
||||
: SectorRemapPatchCode(SECTION_START(romoffsettosdsector), SECTION_SIZE(romoffsettosdsector), patchHeap)
|
||||
{
|
||||
romoffsettosdsector_fatDataPtr = (u32)fatDataPtr;
|
||||
}
|
||||
|
||||
const void* GetRemapFunction() const override
|
||||
{
|
||||
return GetAddressAtTarget((void*)rom_offset_to_sd_sector_asm);
|
||||
}
|
||||
};
|
||||
52
arm9/source/patches/arm9/RomOffsetToSdSectorAsm.s
Normal file
52
arm9/source/patches/arm9/RomOffsetToSdSectorAsm.s
Normal file
@@ -0,0 +1,52 @@
|
||||
.cpu arm946e-s
|
||||
.section "romoffsettosdsector", "ax"
|
||||
.syntax unified
|
||||
.thumb
|
||||
|
||||
// r0 = rom offset
|
||||
// returns sd sector in r0
|
||||
// returns cluster shift in r1
|
||||
// returns remaining sectors in cluster in lr
|
||||
.global rom_offset_to_sd_sector_asm
|
||||
.type rom_offset_to_sd_sector_asm, %function
|
||||
rom_offset_to_sd_sector_asm:
|
||||
push {r4,r5,lr}
|
||||
retry:
|
||||
ldr r5, romoffsettosdsector_fatDataPtr
|
||||
ldmia r5!, {r1,r2,r3,r4} // clusterShift, database, clusterMask, clusterMap[0]
|
||||
lsrs r0, r0, #9
|
||||
2:
|
||||
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, #0x40
|
||||
lsls r0, r0, #9
|
||||
b retry
|
||||
|
||||
.balign 4
|
||||
|
||||
.global romoffsettosdsector_fatDataPtr
|
||||
romoffsettosdsector_fatDataPtr:
|
||||
.word 0x027FF800
|
||||
|
||||
.pool
|
||||
|
||||
.end
|
||||
262
arm9/source/patches/arm9/sdk2to4/CardiReadCardPatch.cpp
Normal file
262
arm9/source/patches/arm9/sdk2to4/CardiReadCardPatch.cpp
Normal file
@@ -0,0 +1,262 @@
|
||||
#include "common.h"
|
||||
#include "patches/PatchContext.h"
|
||||
#include "fileInfo.h"
|
||||
#include "thumbInstructions.h"
|
||||
#include "patches/platform/LoaderPlatform.h"
|
||||
#include "patches/arm9/RomOffsetToSdSectorAsm.h"
|
||||
#include "patches/OffsetToSectorRemapAsm.h"
|
||||
#include "patches/arm9/FixCp15Asm.h"
|
||||
#include "CardiReadCardPatchAsm.h"
|
||||
#include "CardiReadCardPatch.h"
|
||||
|
||||
static const u32 sCARDiReadCardPatternUnknown[] = { 0xE92D4FF0u, 0xE24DD004u, 0xE1A0A000u, 0xE59F90D8u };
|
||||
static const u32 sCARDiReadCardPatternSdk20029A7[] = { 0xE92D4FF0u, 0xE24DD004u, 0xE1A0A000u, 0xE59F90E0u };
|
||||
static const u32 sCARDiReadCardPatternSdk2004E8BPingPals[] = { 0xE92D4FF0u, 0xE24DD004u, 0xE1A0A000u, 0xE59F90FCu };
|
||||
static const u32 sCARDiReadCardPatternSdk2004F4CThumb[] = { 0xB083B5F0u, 0x4E279000u, 0x30209001u, 0x4F269001u };
|
||||
static const u32 sCARDiReadCardPatternSdk2004F4DDebug[] = { 0xE92D47F0u, 0xE1A05000u, 0xE59F40D4u, 0xE5941018u };
|
||||
static const u32 sCARDiReadCardPatternSdk2027533ThumbChouSoujuu[] = { 0xB083B5F0u, 0x4E259000u, 0x30209001u, 0x4F249001u };
|
||||
static const u32 sCARDiReadCardPatternSdk3027530Thumb[] = { 0xB082B5F8u, 0x90019000u, 0x90013020u, 0x69C24825u };
|
||||
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 sCARDiReadCardPatternSdk4027539SpiritTracks[] = { 0xE92D4070u, 0xE59F40D4u, 0xE1A06000u, 0xE3A00C02u };
|
||||
|
||||
void CardiReadCardPatch::TryPattern(PatchContext& patchContext, const u32* pattern, u32 byteLength)
|
||||
{
|
||||
_cardiReadCard = patchContext.FindPattern32(pattern, byteLength);
|
||||
if (_cardiReadCard)
|
||||
_foundPattern = pattern;
|
||||
}
|
||||
|
||||
bool CardiReadCardPatch::FindPatchTarget(PatchContext& patchContext)
|
||||
{
|
||||
if (patchContext.GetSdkVersion() >= 0x4017530)
|
||||
TryPattern(patchContext, sCARDiReadCardPatternSdk4017530, sizeof(sCARDiReadCardPatternSdk4017530));
|
||||
else if (patchContext.GetSdkVersion() >= 0x4002774)
|
||||
TryPattern(patchContext, sCARDiReadCardPatternSdk4002774, sizeof(sCARDiReadCardPatternSdk4002774));
|
||||
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, sCARDiReadCardPatternSdk4002774, sizeof(sCARDiReadCardPatternSdk4002774));
|
||||
if (!_cardiReadCard)
|
||||
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));
|
||||
|
||||
if (_cardiReadCard)
|
||||
_thumb = true;
|
||||
}
|
||||
|
||||
if (_cardiReadCard)
|
||||
{
|
||||
LOG_DEBUG("Found CARDi_ReadCard at %p\n", _cardiReadCard);
|
||||
// patchContext.GetPatchHeap().AddFreeSpace((u8*)_cardiReadCard + 0x64, 0x34);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_DEBUG("CARDi_ReadCard not found\n");
|
||||
}
|
||||
return _cardiReadCard != nullptr;
|
||||
}
|
||||
|
||||
void CardiReadCardPatch::ApplyPatch(PatchContext& patchContext)
|
||||
{
|
||||
if (!_cardiReadCard)
|
||||
return;
|
||||
|
||||
// patch at CARDi_ReadCard + 0x58
|
||||
// r1 = rom src (512 byte aligned)
|
||||
// r8 = dst (32 bit aligned)
|
||||
// return to CARDi_ReadCard + 0x98
|
||||
|
||||
u32 patch1Size = SECTION_SIZE(patch_cardireadcard);
|
||||
void* patch1Address = patchContext.GetPatchHeap().Alloc(patch1Size);
|
||||
auto loaderPlatform = patchContext.GetLoaderPlatform();
|
||||
if (loaderPlatform->HasRomReads())
|
||||
{
|
||||
auto romReadPatchCode = loaderPlatform->CreateRomReadPatchCode(
|
||||
patchContext.GetPatchCodeCollection(), patchContext.GetPatchHeap());
|
||||
auto offsetToSectorRemapPatchCode = patchContext.GetPatchCodeCollection().GetOrAddSharedPatchCode([&]
|
||||
{
|
||||
return new OffsetToSectorRemapPatchCode(patchContext.GetPatchHeap());
|
||||
});
|
||||
__patch_cardireadcard_rom_offset_to_sd_sector_asm_address = (u32)offsetToSectorRemapPatchCode->GetRemapFunction();
|
||||
__patch_cardireadcard_sdread_asm_address = (u32)romReadPatchCode->GetSdReadFunction();
|
||||
}
|
||||
else
|
||||
{
|
||||
auto sdReadPatchCode = loaderPlatform->CreateSdReadPatchCode(
|
||||
patchContext.GetPatchCodeCollection(), patchContext.GetPatchHeap());
|
||||
auto romOffsetToSdSectorPatchCode = patchContext.GetPatchCodeCollection().GetOrAddSharedPatchCode([&]
|
||||
{
|
||||
return new RomOffsetToSdSectorPatchCode(patchContext.GetPatchHeap(),
|
||||
(const rom_file_info_t*)((u32)SHARED_ROM_FILE_INFO - 0x02F00000 + 0x02700000));
|
||||
});
|
||||
__patch_cardireadcard_rom_offset_to_sd_sector_asm_address = (u32)romOffsetToSdSectorPatchCode->GetRemapFunction();
|
||||
__patch_cardireadcard_sdread_asm_address = (u32)sdReadPatchCode->GetSdReadFunction();
|
||||
}
|
||||
u32 patch4Size = SECTION_SIZE(fixcp15);
|
||||
void* patch4Address = patchContext.GetPatchHeap().Alloc(patch4Size);
|
||||
__patch_cardireadcard_fix_cp15_asm_address = (u32)&fix_cp15_asm - (u32)SECTION_START(fixcp15) + (u32)patch4Address;
|
||||
|
||||
u32 entryAddress = (u32)&patch_cardireadcard_entry - (u32)SECTION_START(patch_cardireadcard) + (u32)patch1Address;
|
||||
|
||||
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_adjust_cardicommon_offset = THUMB_NOP;
|
||||
patch_cardireadcard_mov_r3_to_dst = THUMB_STR_SP_IMM(THUMB_R3, 4);
|
||||
}
|
||||
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_adjust_cardicommon_offset = THUMB_NOP;
|
||||
patch_cardireadcard_mov_r3_to_dst = THUMB_STR_SP_IMM(THUMB_R3, 4);
|
||||
}
|
||||
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
|
||||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_FATAL("Unsupported CARDi_ReadCard pattern\n");
|
||||
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;
|
||||
}
|
||||
else
|
||||
{
|
||||
u32 patchOffset;
|
||||
if (_foundPattern == sCARDiReadCardPatternSdk4027539SpiritTracks)
|
||||
{
|
||||
patchOffset = 0x44;
|
||||
patch_cardireadcard_return_offset = THUMB_MOVS_IMM(THUMB_R0, 0x44);
|
||||
patch_cardireadcard_mov_src_to_r0 = THUMB_MOVS_REG(THUMB_R0, THUMB_R2); // src
|
||||
patch_cardireadcard_mov_dst_to_r1 = THUMB_MOVS_REG(THUMB_R1, THUMB_R5); // dst
|
||||
patch_cardireadcard_mov_cardicommon_to_r6 = THUMB_MOVS_REG(THUMB_R6, THUMB_R4);
|
||||
patch_cardireadcard_adjust_cardicommon_offset = THUMB_NOP;
|
||||
patch_cardireadcard_mov_r3_to_dst = THUMB_MOVS_REG(THUMB_R5, THUMB_R3);
|
||||
}
|
||||
else if (_foundPattern == sCARDiReadCardPatternSdk4017530)
|
||||
{
|
||||
patchOffset = 0x44;
|
||||
patch_cardireadcard_return_offset = THUMB_MOVS_IMM(THUMB_R0, 0x48);
|
||||
patch_cardireadcard_mov_src_to_r0 = THUMB_MOVS_REG(THUMB_R0, THUMB_R2); // src
|
||||
patch_cardireadcard_mov_dst_to_r1 = THUMB_MOVS_REG(THUMB_R1, THUMB_R5); // dst
|
||||
patch_cardireadcard_mov_cardicommon_to_r6 = THUMB_MOVS_REG(THUMB_R6, THUMB_R4);
|
||||
patch_cardireadcard_adjust_cardicommon_offset = THUMB_NOP;
|
||||
patch_cardireadcard_mov_r3_to_dst = THUMB_MOVS_REG(THUMB_R5, THUMB_R3);
|
||||
}
|
||||
else if (_foundPattern == sCARDiReadCardPatternSdk4002774)
|
||||
{
|
||||
patchOffset = 0x44;
|
||||
patch_cardireadcard_return_offset = THUMB_MOVS_IMM(THUMB_R0, 0x40);
|
||||
patch_cardireadcard_mov_src_to_r0 = THUMB_MOVS_REG(THUMB_R0, THUMB_R2); // src
|
||||
patch_cardireadcard_mov_dst_to_r1 = THUMB_MOVS_REG(THUMB_R1, THUMB_R5); // dst
|
||||
patch_cardireadcard_mov_cardicommon_to_r6 = THUMB_MOVS_REG(THUMB_R6, THUMB_R4);
|
||||
patch_cardireadcard_adjust_cardicommon_offset = THUMB_NOP;
|
||||
patch_cardireadcard_mov_r3_to_dst = THUMB_MOVS_REG(THUMB_R5, THUMB_R3);
|
||||
}
|
||||
else if (_foundPattern == sCARDiReadCardPatternSdk20029A7 || _foundPattern == sCARDiReadCardPatternUnknown)
|
||||
{
|
||||
patchOffset = 0x58;
|
||||
patch_cardireadcard_return_offset = THUMB_MOVS_IMM(THUMB_R0, 0x38);
|
||||
patch_cardireadcard_mov_src_to_r0 = THUMB_MOVS_REG(THUMB_R0, THUMB_R1); // src
|
||||
patch_cardireadcard_mov_dst_to_r1 = THUMB_MOV_HIREG(THUMB_R1, THUMB_HI_R8); // dst
|
||||
patch_cardireadcard_mov_cardicommon_to_r6 = THUMB_MOV_HIREG(THUMB_R6, THUMB_HI_R9);
|
||||
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_MOV_HIREG(THUMB_HI_R8, THUMB_R3);
|
||||
}
|
||||
else if (_foundPattern == sCARDiReadCardPatternSdk2004E8BPingPals)
|
||||
{
|
||||
patchOffset = 0x5C;
|
||||
patch_cardireadcard_return_offset = THUMB_MOVS_IMM(THUMB_R0, 0x40);
|
||||
patch_cardireadcard_mov_src_to_r0 = THUMB_MOVS_REG(THUMB_R0, THUMB_R1); // src
|
||||
patch_cardireadcard_mov_dst_to_r1 = THUMB_MOV_HIREG(THUMB_R1, THUMB_HI_R8); // dst
|
||||
patch_cardireadcard_mov_cardicommon_to_r6 = THUMB_MOV_HIREG(THUMB_R6, THUMB_HI_R9);
|
||||
patch_cardireadcard_adjust_cardicommon_offset = THUMB_SUBS_IMM(THUMB_R6, THUMB_R6, 4);
|
||||
patch_cardireadcard_mov_r3_to_dst = THUMB_MOV_HIREG(THUMB_HI_R8, THUMB_R3);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_FATAL("Unsupported CARDi_ReadCard pattern\n");
|
||||
while (1);
|
||||
}
|
||||
|
||||
*(u32*)((u8*)_cardiReadCard + patchOffset + 0) = 0xE59F0000; // ldr r0,= entryAddress
|
||||
*(u32*)((u8*)_cardiReadCard + patchOffset + 4) = 0xE12FFF30; // blx r0
|
||||
*(u32*)((u8*)_cardiReadCard + patchOffset + 8) = entryAddress;
|
||||
}
|
||||
|
||||
memcpy(patch1Address, SECTION_START(patch_cardireadcard), patch1Size);
|
||||
memcpy(patch4Address, SECTION_START(fixcp15), patch4Size);
|
||||
}
|
||||
17
arm9/source/patches/arm9/sdk2to4/CardiReadCardPatch.h
Normal file
17
arm9/source/patches/arm9/sdk2to4/CardiReadCardPatch.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
#include "patches/Patch.h"
|
||||
|
||||
/// @brief Arm9 patch to redirect card reads on SDK 2-4.
|
||||
class CardiReadCardPatch : public Patch
|
||||
{
|
||||
public:
|
||||
bool FindPatchTarget(PatchContext& patchContext) override;
|
||||
void ApplyPatch(PatchContext& patchContext) override;
|
||||
|
||||
private:
|
||||
u32* _cardiReadCard = nullptr;
|
||||
u16 _thumb = false;
|
||||
const u32* _foundPattern = nullptr;
|
||||
|
||||
void TryPattern(PatchContext& patchContext, const u32* pattern, u32 byteLength);
|
||||
};
|
||||
17
arm9/source/patches/arm9/sdk2to4/CardiReadCardPatchAsm.h
Normal file
17
arm9/source/patches/arm9/sdk2to4/CardiReadCardPatchAsm.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
#include "sections.h"
|
||||
|
||||
DEFINE_SECTION_SYMBOLS(patch_cardireadcard);
|
||||
|
||||
extern "C" void patch_cardireadcard_entry();
|
||||
|
||||
extern u32 __patch_cardireadcard_fix_cp15_asm_address;
|
||||
extern u32 __patch_cardireadcard_rom_offset_to_sd_sector_asm_address;
|
||||
extern u32 __patch_cardireadcard_sdread_asm_address;
|
||||
|
||||
extern u16 patch_cardireadcard_return_offset;
|
||||
extern u16 patch_cardireadcard_mov_src_to_r0;
|
||||
extern u16 patch_cardireadcard_mov_dst_to_r1;
|
||||
extern u16 patch_cardireadcard_mov_cardicommon_to_r6;
|
||||
extern u16 patch_cardireadcard_adjust_cardicommon_offset;
|
||||
extern u16 patch_cardireadcard_mov_r3_to_dst;
|
||||
80
arm9/source/patches/arm9/sdk2to4/CardiReadCardPatchAsm.s
Normal file
80
arm9/source/patches/arm9/sdk2to4/CardiReadCardPatchAsm.s
Normal file
@@ -0,0 +1,80 @@
|
||||
.cpu arm946e-s
|
||||
.section "patch_cardireadcard", "ax"
|
||||
.syntax unified
|
||||
|
||||
.thumb
|
||||
.global patch_cardireadcard_entry
|
||||
.type patch_cardireadcard_entry, %function
|
||||
patch_cardireadcard_entry:
|
||||
|
||||
.global patch_cardireadcard_return_offset
|
||||
patch_cardireadcard_return_offset:
|
||||
movs r0, #0x38
|
||||
add lr, r0
|
||||
push {r3,r4,r6,lr}
|
||||
ldr r3, __patch_cardireadcard_fix_cp15_asm_address
|
||||
blx r3
|
||||
.global patch_cardireadcard_mov_src_to_r0
|
||||
patch_cardireadcard_mov_src_to_r0:
|
||||
nop
|
||||
ldr r3, __patch_cardireadcard_rom_offset_to_sd_sector_asm_address
|
||||
blx r3
|
||||
movs r2, #1 // r2 = sector count
|
||||
.global patch_cardireadcard_mov_dst_to_r1
|
||||
patch_cardireadcard_mov_dst_to_r1:
|
||||
mov r1, r8 // r1 = dst
|
||||
.global patch_cardireadcard_mov_cardicommon_to_r6
|
||||
patch_cardireadcard_mov_cardicommon_to_r6:
|
||||
movs r6, r4 // r6 = cardi_common
|
||||
.global patch_cardireadcard_adjust_cardicommon_offset
|
||||
patch_cardireadcard_adjust_cardicommon_offset:
|
||||
subs r6, #0
|
||||
ldr r4, [r6, #0x20] // r4 = actual dst
|
||||
cmp r4, r1
|
||||
bne do_read // if dst != actual dst the cache is in use
|
||||
|
||||
ldr r2, [r6, #0x24] // remaining length
|
||||
lsrs r2, r2, #9 // sectors left to read
|
||||
cmp r2, lr
|
||||
ble 1f
|
||||
mov r2, lr // clip to cluster boundary
|
||||
1:
|
||||
subs r4, r2, #1
|
||||
lsls r4, r4, #9
|
||||
ldr r3, [r6, #0x1C]
|
||||
adds r3, r3, r4
|
||||
str r3, [r6, #0x1C]
|
||||
ldr r3, [r6, #0x20]
|
||||
adds r3, r3, r4
|
||||
str r3, [r6, #0x20]
|
||||
|
||||
.global patch_cardireadcard_mov_r3_to_dst
|
||||
patch_cardireadcard_mov_r3_to_dst:
|
||||
mov r8, r3
|
||||
|
||||
ldr r3, [r6, #0x24]
|
||||
subs r3, r3, r4
|
||||
str r3, [r6, #0x24]
|
||||
|
||||
do_read:
|
||||
ldr r3, __patch_cardireadcard_sdread_asm_address
|
||||
blx r3
|
||||
pop {r3,r4,r6,pc}
|
||||
|
||||
.balign 4
|
||||
|
||||
.global __patch_cardireadcard_fix_cp15_asm_address
|
||||
__patch_cardireadcard_fix_cp15_asm_address:
|
||||
.word 0
|
||||
|
||||
.global __patch_cardireadcard_rom_offset_to_sd_sector_asm_address
|
||||
__patch_cardireadcard_rom_offset_to_sd_sector_asm_address:
|
||||
.word 0
|
||||
|
||||
.global __patch_cardireadcard_sdread_asm_address
|
||||
__patch_cardireadcard_sdread_asm_address:
|
||||
.word 0
|
||||
|
||||
.pool
|
||||
|
||||
.end
|
||||
41
arm9/source/patches/arm9/sdk2to4/CardiSetCardDmaPatchAsm.h
Normal file
41
arm9/source/patches/arm9/sdk2to4/CardiSetCardDmaPatchAsm.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
#include "patches/PatchCode.h"
|
||||
#include "sections.h"
|
||||
#include "patches/arm9/RomOffsetToSdSectorAsm.h"
|
||||
#include "patches/platform/SdReadDmaPatchCode.h"
|
||||
|
||||
DEFINE_SECTION_SYMBOLS(patch_cardisetcarddma);
|
||||
|
||||
extern "C" u32 patch_cardisetcarddma_entry(void);
|
||||
extern "C" u32 patch_cardionreadcard_entry(void);
|
||||
|
||||
extern u32 patch_cardisetcarddma_cardi_common;
|
||||
extern u32 patch_cardisetcarddma_rom_offset_to_sd_sector_asm_address;
|
||||
extern u32 patch_cardisetcarddma_sdreaddma_asm_address;
|
||||
extern u32 patch_cardionreadcard_osdisableirqmask_address;
|
||||
extern u32 patch_cardionreadcard_sdreaddma_finish_asm_address;
|
||||
|
||||
class CardiSetCardDmaPatchCode : public PatchCode
|
||||
{
|
||||
public:
|
||||
CardiSetCardDmaPatchCode(PatchHeap& patchHeap, const RomOffsetToSdSectorPatchCode* romOffsetToSdSectorPatchCode,
|
||||
const SdReadDmaPatchCode* sdReadDmaPatchCode, const void* cardiCommonPointer, const void* osDisableIrqMaskPointer)
|
||||
: PatchCode(SECTION_START(patch_cardisetcarddma), SECTION_SIZE(patch_cardisetcarddma), patchHeap)
|
||||
{
|
||||
patch_cardisetcarddma_cardi_common = (u32)cardiCommonPointer;
|
||||
patch_cardisetcarddma_rom_offset_to_sd_sector_asm_address = (u32)romOffsetToSdSectorPatchCode->GetRemapFunction();
|
||||
patch_cardisetcarddma_sdreaddma_asm_address = (u32)sdReadDmaPatchCode->GetSdReadDmaFunction();
|
||||
patch_cardionreadcard_osdisableirqmask_address = (u32)osDisableIrqMaskPointer;
|
||||
patch_cardionreadcard_sdreaddma_finish_asm_address = (u32)sdReadDmaPatchCode->GetSdReadDmaFinishFunction();
|
||||
}
|
||||
|
||||
const void* GetCardiSetCardDmaFunction() const
|
||||
{
|
||||
return GetAddressAtTarget((void*)patch_cardisetcarddma_entry);
|
||||
}
|
||||
|
||||
const void* GetCardiOnReadCardPatchFunction() const
|
||||
{
|
||||
return GetAddressAtTarget((void*)patch_cardionreadcard_entry);
|
||||
}
|
||||
};
|
||||
75
arm9/source/patches/arm9/sdk2to4/CardiSetCardDmaPatchAsm.s
Normal file
75
arm9/source/patches/arm9/sdk2to4/CardiSetCardDmaPatchAsm.s
Normal file
@@ -0,0 +1,75 @@
|
||||
.cpu arm946e-s
|
||||
.section "patch_cardisetcarddma", "ax"
|
||||
.syntax unified
|
||||
|
||||
.thumb
|
||||
.global patch_cardisetcarddma_entry
|
||||
.type patch_cardisetcarddma_entry, %function
|
||||
patch_cardisetcarddma_entry:
|
||||
push {r4,lr}
|
||||
|
||||
ldr r4, patch_cardisetcarddma_cardi_common
|
||||
ldr r0, [r4, #0x18] // src
|
||||
|
||||
ldr r3, patch_cardisetcarddma_rom_offset_to_sd_sector_asm_address
|
||||
blx r3
|
||||
|
||||
ldr r1, previousSector
|
||||
adr r2, previousSector
|
||||
str r0, [r2]
|
||||
ldr r2, [r4, #0x24] // dma channel
|
||||
ldr r3, [r4, #0x1C] // dst
|
||||
|
||||
ldr r4, patch_cardisetcarddma_sdreaddma_asm_address
|
||||
blx r4
|
||||
|
||||
pop {r4,pc}
|
||||
|
||||
.thumb
|
||||
.global patch_cardionreadcard_entry
|
||||
.type patch_cardionreadcard_entry, %function
|
||||
patch_cardionreadcard_entry:
|
||||
push {lr}
|
||||
ldr r0,= 0x80000
|
||||
ldr r1, patch_cardionreadcard_osdisableirqmask_address
|
||||
blx r1
|
||||
|
||||
ldr r0, patch_cardionreadcard_sdreaddma_finish_asm_address
|
||||
blx r0
|
||||
|
||||
movs r0, #0
|
||||
adr r1, previousSector
|
||||
str r0, [r1]
|
||||
|
||||
ldr r0,= 0x80000
|
||||
pop {r1}
|
||||
adds r1, #4
|
||||
bx r1
|
||||
|
||||
.balign 4
|
||||
|
||||
previousSector:
|
||||
.word 0
|
||||
|
||||
.global patch_cardisetcarddma_cardi_common
|
||||
patch_cardisetcarddma_cardi_common:
|
||||
.word 0
|
||||
|
||||
.global patch_cardisetcarddma_rom_offset_to_sd_sector_asm_address
|
||||
patch_cardisetcarddma_rom_offset_to_sd_sector_asm_address:
|
||||
.word 0
|
||||
|
||||
.global patch_cardisetcarddma_sdreaddma_asm_address
|
||||
patch_cardisetcarddma_sdreaddma_asm_address:
|
||||
.word 0
|
||||
|
||||
.global patch_cardionreadcard_osdisableirqmask_address
|
||||
patch_cardionreadcard_osdisableirqmask_address:
|
||||
.word 0
|
||||
|
||||
.global patch_cardionreadcard_sdreaddma_finish_asm_address
|
||||
patch_cardionreadcard_sdreaddma_finish_asm_address:
|
||||
.word 0
|
||||
|
||||
.pool
|
||||
.end
|
||||
299
arm9/source/patches/arm9/sdk2to4/CardiTryReadCardDmaPatch.cpp
Normal file
299
arm9/source/patches/arm9/sdk2to4/CardiTryReadCardDmaPatch.cpp
Normal file
@@ -0,0 +1,299 @@
|
||||
#include "common.h"
|
||||
#include "patches/PatchContext.h"
|
||||
#include "thumbInstructions.h"
|
||||
#include "CardiSetCardDmaPatchAsm.h"
|
||||
#include "patches/platform/LoaderPlatform.h"
|
||||
#include "CardiTryReadCardDmaPatch.h"
|
||||
|
||||
static const u32 sCARDiTryReadCardDmaPatternPingPals[] = { 0xE92D47F0u, 0xE1A0A000u, 0xE59F9120u, 0xE3A08000u };
|
||||
static const u32 sCARDiTryReadCardDmaPatternUnknown[] = { 0xE92D47F0u, 0xE59F9138u, 0xE3A06000u, 0xE5998020u };
|
||||
static const u32 sCARDiTryReadCardDmaPatternUnknown2[] = { 0xE92D47F0u, 0xE59F4134u, 0xE3A06000u, 0xE5949020u };
|
||||
static const u32 sCARDiTryReadCardDmaPatternUnknown3[] = { 0xE92D4FF8u, 0xE59FB140u, 0xE3A05000u, 0xE59B8020u };
|
||||
static const u32 sCARDiTryReadCardDmaPatternUnknown4[] = { 0xE92D47F0u, 0xE59F9138u, 0xE3A06000u, 0xE599801Cu };
|
||||
static const u32 sCARDiTryReadCardDmaPattern20029A7[] = { 0xE92D47F0u, 0xE59F9128u, 0xE3A07000u, 0xE599401Cu };
|
||||
static const u32 sCARDiTryReadCardDmaPattern2012774[] = { 0xE92D47F0u, 0xE59F9134u, 0xE3A07000u, 0xE599401Cu };
|
||||
static const u32 sCARDiTryReadCardDmaPattern2017532[] = { 0xE92D47F0u, 0xE59F9130u, 0xE3A07000u, 0xE599401Cu };
|
||||
static const u32 sCARDiTryReadCardDmaPattern2027530[] = { 0xE92D47F0u, 0xE59F913Cu, 0xE3A06000u, 0xE599801Cu };
|
||||
static const u32 sCARDiTryReadCardDmaPattern[] = { 0xE92D47F0u, 0xE59F913Cu, 0xE3A06000u, 0xE5998020u };
|
||||
static const u32 sCARDiTryReadCardDmaPatternSdk3017530[] = { 0xE92D4FF0u, 0xE24DD004u, 0xE59FB14Cu, 0xE3A07000u };
|
||||
static const u32 sCARDiTryReadCardDmaPatternSdk3017534[] = { 0xE92D4FF0u, 0xE24DD004u, 0xE59FB148u, 0xE3A07000u };
|
||||
static const u32 sCARDiTryReadCardDmaPatternSdk3027530[] = { 0xE92D4FF0u, 0xE24DD004u, 0xE59FB150u, 0xE3A07000u };
|
||||
static const u32 sCARDiTryReadCardDmaPatternSdk4007530[] = { 0xE92D4FF8u, 0xE59FB144u, 0xE3A05000u, 0xE59B8020u };
|
||||
static const u32 sCARDiTryReadCardDmaPatternSdk4007532[] = { 0xE92D4FF8u, 0xE59F416Cu, 0xE3A06000u, 0xE5949020u };
|
||||
static const u32 sCARDiTryReadCardDmaPatternSdk4027539SpiritTracks[] = { 0xE92D4FF8u, 0xE59F4174u, 0xE3A06000u, 0xE5949020u };
|
||||
static const u32 sCARDiTryReadCardDmaPatternJpnPokemonDownloader[] = { 0xE92D4FF8u, 0xE59FB138u, 0xE3A05000u, 0xE59B8020u };
|
||||
|
||||
static const u32 sCARDiTryReadCardDmaPatternThumbChouSoujuu[] = { 0xB083B5F0u, 0x48399000u, 0x6A0469C5u, 0x96012600u };
|
||||
static const u32 sCARDiTryReadCardDmaPatternSdk2004F4CThumb[] = { 0xB083B5F0u, 0x4D359000u, 0x94012400u, 0x90020020u };
|
||||
static const u32 sCARDiTryReadCardDmaPatternSdk2007531Thumb[] = { 0xB083B5F0u, 0x4D379000u, 0x94012400u, 0x90020020u };
|
||||
static const u32 sCARDiTryReadCardDmaPatternSdk2027530Thumb[] = { 0xB083B5F0u, 0x483A9000u, 0x6A0469C5u, 0x96012600u };
|
||||
static const u32 sCARDiTryReadCardDmaPatternSdk3007530Thumb[] = { 0xB083B5F0u, 0x483A9000u, 0x6A446A05u, 0x96012600u };
|
||||
static const u32 sCARDiTryReadCardDmaPatternSdk3012776Thumb[] = { 0xB083B5F0u, 0x483A9000u, 0x6A446A05u, 0x90012600u };
|
||||
static const u32 sCARDiTryReadCardDmaPatternSdk3017531Thumb[] = { 0xB085B5F0u, 0x483C9000u, 0x6A446A05u, 0x90012000u };
|
||||
static const u32 sCARDiTryReadCardDmaPatternSdk3027530Thumb[] = { 0xB085B5F0u, 0x483D9000u, 0x6A446A05u, 0x90012000u };
|
||||
static const u32 sCARDiTryReadCardDmaPatternSdkThumb[] = { 0xB084B5F8u, 0x483D9000u, 0x6A446A05u, 0x90032000u };
|
||||
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 u16 sReturnFalsePatchThumb[] = { THUMB_MOVS_IMM(0, 0), THUMB_BX_LR };
|
||||
static const u32 sReturnFalsePatchArm[] = { 0xE3A00000, 0xE12FFF1E }; // mov r0, #0; bx lr
|
||||
|
||||
void CardiTryReadCardDmaPatch::TryPattern(PatchContext& patchContext, const u32* pattern)
|
||||
{
|
||||
_cardiTryReadCardDma = patchContext.FindPattern32(pattern, 16);
|
||||
if (_cardiTryReadCardDma)
|
||||
{
|
||||
_foundPattern = pattern;
|
||||
}
|
||||
}
|
||||
|
||||
bool CardiTryReadCardDmaPatch::FindPatchTarget(PatchContext& patchContext)
|
||||
{
|
||||
if (patchContext.GetSdkVersion() >= 0x4007532)
|
||||
TryPattern(patchContext, sCARDiTryReadCardDmaPatternSdk4007532);
|
||||
else if (patchContext.GetSdkVersion() >= 0x4007530)
|
||||
TryPattern(patchContext, sCARDiTryReadCardDmaPatternSdk4007530);
|
||||
else if (patchContext.GetSdkVersion() >= 0x3027530)
|
||||
TryPattern(patchContext, sCARDiTryReadCardDmaPatternSdk3027530);
|
||||
else if (patchContext.GetSdkVersion() >= 0x3017530)
|
||||
TryPattern(patchContext, sCARDiTryReadCardDmaPatternSdk3017530);
|
||||
else if (patchContext.GetSdkVersion() > 0x2027534)
|
||||
TryPattern(patchContext, sCARDiTryReadCardDmaPattern);
|
||||
else if (patchContext.GetSdkVersion() > 0x2017532)
|
||||
TryPattern(patchContext, sCARDiTryReadCardDmaPattern2027530);
|
||||
else if (patchContext.GetSdkVersion() > 0x2004FB4)
|
||||
TryPattern(patchContext, sCARDiTryReadCardDmaPattern2012774);
|
||||
else
|
||||
TryPattern(patchContext, sCARDiTryReadCardDmaPattern20029A7);
|
||||
|
||||
if (!_cardiTryReadCardDma)
|
||||
{
|
||||
if (patchContext.GetSdkVersion() >= 0x4027530)
|
||||
TryPattern(patchContext, sCARDiTryReadCardDmaPatternSdk4027530Thumb);
|
||||
else if (patchContext.GetSdkVersion() >= 0x4017530)
|
||||
TryPattern(patchContext, sCARDiTryReadCardDmaPatternSdk4017530Thumb);
|
||||
else if (patchContext.GetSdkVersion() >= 0x4007531)
|
||||
TryPattern(patchContext, sCARDiTryReadCardDmaPatternSdk4007531Thumb);
|
||||
else if (patchContext.GetSdkVersion() >= 0x3027530)
|
||||
TryPattern(patchContext, sCARDiTryReadCardDmaPatternSdk3027530Thumb);
|
||||
else if (patchContext.GetSdkVersion() >= 0x3017531)
|
||||
TryPattern(patchContext, sCARDiTryReadCardDmaPatternSdk3017531Thumb);
|
||||
else if (patchContext.GetSdkVersion() >= 0x3017530)
|
||||
TryPattern(patchContext, sCARDiTryReadCardDmaPatternSdk3012776Thumb);
|
||||
else if (patchContext.GetSdkVersion() >= 0x3007530)
|
||||
TryPattern(patchContext, sCARDiTryReadCardDmaPatternSdk3007530Thumb);
|
||||
else if (patchContext.GetSdkVersion() >= 0x2027530)
|
||||
TryPattern(patchContext, sCARDiTryReadCardDmaPatternSdk2027530Thumb);
|
||||
else if (patchContext.GetSdkVersion() >= 0x2007531)
|
||||
TryPattern(patchContext, sCARDiTryReadCardDmaPatternSdk2007531Thumb);
|
||||
else if (patchContext.GetSdkVersion() >= 0x2004F4C)
|
||||
TryPattern(patchContext, sCARDiTryReadCardDmaPatternSdk2004F4CThumb);
|
||||
|
||||
if (_cardiTryReadCardDma)
|
||||
_thumb = true;
|
||||
}
|
||||
|
||||
if (!_cardiTryReadCardDma)
|
||||
{
|
||||
TryPattern(patchContext, sCARDiTryReadCardDmaPatternUnknown);
|
||||
if (!_cardiTryReadCardDma)
|
||||
TryPattern(patchContext, sCARDiTryReadCardDmaPatternSdk4007530);
|
||||
if (!_cardiTryReadCardDma)
|
||||
TryPattern(patchContext, sCARDiTryReadCardDmaPattern20029A7);
|
||||
if (!_cardiTryReadCardDma)
|
||||
TryPattern(patchContext, sCARDiTryReadCardDmaPatternSdk3017530);
|
||||
if (!_cardiTryReadCardDma)
|
||||
TryPattern(patchContext, sCARDiTryReadCardDmaPatternUnknown2);
|
||||
if (!_cardiTryReadCardDma)
|
||||
TryPattern(patchContext, sCARDiTryReadCardDmaPatternUnknown3);
|
||||
if (!_cardiTryReadCardDma)
|
||||
TryPattern(patchContext, sCARDiTryReadCardDmaPatternSdk3017534);
|
||||
if (!_cardiTryReadCardDma)
|
||||
TryPattern(patchContext, sCARDiTryReadCardDmaPattern);
|
||||
if (patchContext.GetSdkVersion() < 0x3000000)
|
||||
{
|
||||
if (!_cardiTryReadCardDma)
|
||||
TryPattern(patchContext, sCARDiTryReadCardDmaPattern2017532);
|
||||
if (!_cardiTryReadCardDma)
|
||||
TryPattern(patchContext, sCARDiTryReadCardDmaPatternPingPals);
|
||||
if (!_cardiTryReadCardDma)
|
||||
TryPattern(patchContext, sCARDiTryReadCardDmaPatternUnknown4);
|
||||
}
|
||||
|
||||
if (patchContext.GetSdkVersion() >= 0x4000000)
|
||||
{
|
||||
if (!_cardiTryReadCardDma)
|
||||
TryPattern(patchContext, sCARDiTryReadCardDmaPatternSdk4027539SpiritTracks);
|
||||
}
|
||||
}
|
||||
|
||||
if (!_cardiTryReadCardDma)
|
||||
{
|
||||
TryPattern(patchContext, sCARDiTryReadCardDmaPatternSdk4007531Thumb);
|
||||
if (!_cardiTryReadCardDma)
|
||||
TryPattern(patchContext, sCARDiTryReadCardDmaPatternSdkThumb);
|
||||
if (!_cardiTryReadCardDma)
|
||||
TryPattern(patchContext, sCARDiTryReadCardDmaPatternSdk2004F4CThumb);
|
||||
if (patchContext.GetSdkVersion() < 0x3000000)
|
||||
{
|
||||
if (!_cardiTryReadCardDma)
|
||||
TryPattern(patchContext, sCARDiTryReadCardDmaPatternThumbChouSoujuu);
|
||||
}
|
||||
|
||||
if (_cardiTryReadCardDma)
|
||||
_thumb = true;
|
||||
}
|
||||
|
||||
if (!_cardiTryReadCardDma)
|
||||
{
|
||||
_cardiTryReadCardDma = patchContext.FindPattern32(sCARDiTryReadCardDmaPatternJpnPokemonDownloader, sizeof(sCARDiTryReadCardDmaPatternJpnPokemonDownloader));
|
||||
}
|
||||
|
||||
if (!_cardiTryReadCardDma)
|
||||
{
|
||||
LOG_WARNING("CARDi_TryReadCardDma not found\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_DEBUG("Found CARDi_TryReadCardDma at %p\n", _cardiTryReadCardDma);
|
||||
}
|
||||
|
||||
// There are some sdk roms that do not contain this function at all
|
||||
return true; //_cardiTryReadCardDma != nullptr;
|
||||
}
|
||||
|
||||
static u32 getArmBlAddress(const u32* instructionPointer)
|
||||
{
|
||||
u32 blInstruction = *instructionPointer;
|
||||
return (u32)instructionPointer + 8 + ((int)((blInstruction & 0xFFFFFF) << 8) >> 6);
|
||||
}
|
||||
|
||||
void CardiTryReadCardDmaPatch::ApplyPatch(PatchContext& patchContext)
|
||||
{
|
||||
if (!_cardiTryReadCardDma)
|
||||
return;
|
||||
|
||||
if (_thumb)
|
||||
{
|
||||
((u16*)_cardiTryReadCardDma)[0] = sReturnFalsePatchThumb[0];
|
||||
((u16*)_cardiTryReadCardDma)[1] = sReturnFalsePatchThumb[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
bool enableDma = patchContext.GetLoaderPlatform()->HasDmaSdReads();
|
||||
if (enableDma)
|
||||
{
|
||||
u32 cardiCommon;
|
||||
u32 cardiOnReadCard;
|
||||
u32 cardiSetCardDma;
|
||||
u32 miiCardDmaCopy32;
|
||||
u32 cardiOnReadCardOffset;
|
||||
if (_foundPattern == sCARDiTryReadCardDmaPattern20029A7)
|
||||
{
|
||||
cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x134);
|
||||
cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x144);
|
||||
cardiSetCardDma = getArmBlAddress((u32*)((u8*)_cardiTryReadCardDma + 0x124));
|
||||
if (*(u32*)cardiOnReadCard == 0xE92D40F0u)
|
||||
{
|
||||
miiCardDmaCopy32 = getArmBlAddress((u32*)(cardiSetCardDma + 0x18));
|
||||
cardiOnReadCardOffset = 0x40;
|
||||
}
|
||||
else
|
||||
{
|
||||
// old version is not supported yet
|
||||
_cardiTryReadCardDma[0] = sReturnFalsePatchArm[0];
|
||||
_cardiTryReadCardDma[1] = sReturnFalsePatchArm[1];
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (_foundPattern == sCARDiTryReadCardDmaPattern2012774)
|
||||
{
|
||||
cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x140);
|
||||
cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x150);
|
||||
cardiSetCardDma = getArmBlAddress((u32*)((u8*)_cardiTryReadCardDma + 0x130));
|
||||
miiCardDmaCopy32 = getArmBlAddress((u32*)(cardiSetCardDma + 0x18));
|
||||
cardiOnReadCardOffset = 0x40;
|
||||
}
|
||||
else if (_foundPattern == sCARDiTryReadCardDmaPattern)
|
||||
{
|
||||
cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x148) + 4;
|
||||
cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x158);
|
||||
cardiSetCardDma = getArmBlAddress((u32*)((u8*)_cardiTryReadCardDma + 0x138));
|
||||
miiCardDmaCopy32 = getArmBlAddress((u32*)(cardiSetCardDma + 0x18));
|
||||
cardiOnReadCardOffset = 0x40;
|
||||
}
|
||||
else if (_foundPattern == sCARDiTryReadCardDmaPatternSdk3017530)
|
||||
{
|
||||
cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x15C) + 4;
|
||||
cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x16C);
|
||||
cardiSetCardDma = getArmBlAddress((u32*)((u8*)_cardiTryReadCardDma + 0x148));
|
||||
miiCardDmaCopy32 = getArmBlAddress((u32*)(cardiSetCardDma + 0x18));
|
||||
cardiOnReadCardOffset = 0x40;
|
||||
}
|
||||
else if (_foundPattern == sCARDiTryReadCardDmaPatternSdk3027530)
|
||||
{
|
||||
cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x160) + 4;
|
||||
cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x170);
|
||||
cardiSetCardDma = getArmBlAddress((u32*)((u8*)_cardiTryReadCardDma + 0x14C));
|
||||
miiCardDmaCopy32 = getArmBlAddress((u32*)(cardiSetCardDma + 0x18));
|
||||
cardiOnReadCardOffset = 0x40;
|
||||
}
|
||||
else if (_foundPattern == sCARDiTryReadCardDmaPatternSdk4007532)
|
||||
{
|
||||
cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x178) + 4;
|
||||
cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x188);
|
||||
cardiSetCardDma = getArmBlAddress((u32*)((u8*)_cardiTryReadCardDma + 0x16C));
|
||||
miiCardDmaCopy32 = getArmBlAddress((u32*)(cardiSetCardDma + 0x1C));
|
||||
cardiOnReadCardOffset = 0x48;
|
||||
}
|
||||
else if (_foundPattern == sCARDiTryReadCardDmaPatternSdk4027539SpiritTracks)
|
||||
{
|
||||
cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x180) + 4;
|
||||
cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x190);
|
||||
cardiSetCardDma = getArmBlAddress((u32*)((u8*)_cardiTryReadCardDma + 0x174));
|
||||
miiCardDmaCopy32 = getArmBlAddress((u32*)(cardiSetCardDma + 0x1C));
|
||||
cardiOnReadCardOffset = 0x48;
|
||||
}
|
||||
else
|
||||
{
|
||||
_cardiTryReadCardDma[0] = sReturnFalsePatchArm[0];
|
||||
_cardiTryReadCardDma[1] = sReturnFalsePatchArm[1];
|
||||
return;
|
||||
}
|
||||
|
||||
u32 osDisableIrqMask = getArmBlAddress((u32*)(cardiOnReadCard + cardiOnReadCardOffset + 4));
|
||||
|
||||
// patch CARDi_SetCardDma
|
||||
auto sdReadDmaPatchCode = patchContext.GetLoaderPlatform()->CreateSdReadDmaPatchCode(
|
||||
patchContext.GetPatchCodeCollection(), patchContext.GetPatchHeap(), (const void*)miiCardDmaCopy32);
|
||||
auto romOffsetToSdSectorPatchCode = patchContext.GetPatchCodeCollection().GetOrAddSharedPatchCode([&]
|
||||
{
|
||||
return new RomOffsetToSdSectorPatchCode(patchContext.GetPatchHeap(),
|
||||
(const rom_file_info_t*)((u32)SHARED_ROM_FILE_INFO - 0x02F00000 + 0x02700000));
|
||||
});
|
||||
auto cardiSetCardDmaPatchCode = patchContext.GetPatchCodeCollection().AddUniquePatchCode<CardiSetCardDmaPatchCode>
|
||||
(
|
||||
patchContext.GetPatchHeap(),
|
||||
romOffsetToSdSectorPatchCode,
|
||||
sdReadDmaPatchCode,
|
||||
(const void*)cardiCommon,
|
||||
(const void*)osDisableIrqMask
|
||||
);
|
||||
*(u32*)(cardiSetCardDma + 0) = 0xE51FF004; // ldr pc,= entryAddress
|
||||
*(u32*)(cardiSetCardDma + 4) = (u32)cardiSetCardDmaPatchCode->GetCardiSetCardDmaFunction();
|
||||
|
||||
// patch CARDi_OnReadCard
|
||||
*(u32*)(cardiOnReadCard + cardiOnReadCardOffset + 0) = 0xE59F0000; // ldr r0,= entryAddress
|
||||
*(u32*)(cardiOnReadCard + cardiOnReadCardOffset + 4) = 0xE12FFF30; // blx r0
|
||||
*(u32*)(cardiOnReadCard + cardiOnReadCardOffset + 8) = (u32)cardiSetCardDmaPatchCode->GetCardiOnReadCardPatchFunction();
|
||||
|
||||
LOG_DEBUG("DMA enabled\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
_cardiTryReadCardDma[0] = sReturnFalsePatchArm[0];
|
||||
_cardiTryReadCardDma[1] = sReturnFalsePatchArm[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
17
arm9/source/patches/arm9/sdk2to4/CardiTryReadCardDmaPatch.h
Normal file
17
arm9/source/patches/arm9/sdk2to4/CardiTryReadCardDmaPatch.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
#include "patches/Patch.h"
|
||||
|
||||
/// @brief Arm9 patch to redirect DMA card reads, or to disable them entirely, on SDK 2-4.
|
||||
class CardiTryReadCardDmaPatch : public Patch
|
||||
{
|
||||
public:
|
||||
bool FindPatchTarget(PatchContext& patchContext) override;
|
||||
void ApplyPatch(PatchContext& patchContext) override;
|
||||
|
||||
private:
|
||||
u32* _cardiTryReadCardDma = nullptr;
|
||||
u32 _thumb = false;
|
||||
const u32* _foundPattern = nullptr;
|
||||
|
||||
void TryPattern(PatchContext& patchContext, const u32* pattern);
|
||||
};
|
||||
@@ -0,0 +1,54 @@
|
||||
#include "common.h"
|
||||
#include "patches/PatchContext.h"
|
||||
#include "thumbInstructions.h"
|
||||
#include "CardiIsRomDmaAvailablePatch.h"
|
||||
|
||||
static const u32 sCARDiIsRomDmaAvailablePattern[] = { 0xE92D43F8u, 0xE3A04000u, 0xE1A09001u, 0xE1A08002u };
|
||||
static const u32 sCARDiIsRomDmaAvailablePatternThumb[] = { 0xB082B5F8u, 0x1C0D2400u, 0x1C1E9200u, 0x94011C21u };
|
||||
static const u32 sCARDiIsRomDmaAvailablePatternThumbHybrid[] = { 0xB082B5F8u, 0x21001C0Du, 0x92009101u, 0x27001C1Cu };
|
||||
|
||||
static const u32 sReturnFalsePatchArm[] = { 0xE3A00000, 0xE12FFF1E }; // mov r0, #0; bx lr
|
||||
|
||||
bool CardiIsRomDmaAvailablePatch::FindPatchTarget(PatchContext& patchContext)
|
||||
{
|
||||
_cardiIsRomDmaAvailable = patchContext.FindPattern32(sCARDiIsRomDmaAvailablePattern, sizeof(sCARDiIsRomDmaAvailablePattern));
|
||||
if (!_cardiIsRomDmaAvailable)
|
||||
{
|
||||
_cardiIsRomDmaAvailable = patchContext.FindPattern32(sCARDiIsRomDmaAvailablePatternThumbHybrid, sizeof(sCARDiIsRomDmaAvailablePatternThumbHybrid));
|
||||
if (_cardiIsRomDmaAvailable)
|
||||
{
|
||||
_thumb = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_cardiIsRomDmaAvailable = patchContext.FindPattern32(sCARDiIsRomDmaAvailablePatternThumb, sizeof(sCARDiIsRomDmaAvailablePatternThumb));
|
||||
if (_cardiIsRomDmaAvailable)
|
||||
{
|
||||
_thumb = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!_cardiIsRomDmaAvailable)
|
||||
{
|
||||
LOG_WARNING("CARDi_IsRomDmaAvailable not found\n");
|
||||
}
|
||||
|
||||
// If an application uses no rom reads, the function is not included in the rom.
|
||||
return true; //_cardiIsRomDmaAvailable != nullptr;
|
||||
}
|
||||
|
||||
void CardiIsRomDmaAvailablePatch::ApplyPatch(PatchContext& patchContext)
|
||||
{
|
||||
if (!_cardiIsRomDmaAvailable)
|
||||
return;
|
||||
if (_thumb)
|
||||
{
|
||||
((u16*)_cardiIsRomDmaAvailable)[0] = THUMB_MOVS_IMM(THUMB_R0, 0);
|
||||
((u16*)_cardiIsRomDmaAvailable)[1] = THUMB_BX_LR;
|
||||
}
|
||||
else
|
||||
{
|
||||
_cardiIsRomDmaAvailable[0] = sReturnFalsePatchArm[0];
|
||||
_cardiIsRomDmaAvailable[1] = sReturnFalsePatchArm[1];
|
||||
}
|
||||
}
|
||||
14
arm9/source/patches/arm9/sdk5/CardiIsRomDmaAvailablePatch.h
Normal file
14
arm9/source/patches/arm9/sdk5/CardiIsRomDmaAvailablePatch.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
#include "patches/Patch.h"
|
||||
|
||||
/// @brief Arm9 patch to disable DMA card reads on SDK 5.
|
||||
class CardiIsRomDmaAvailablePatch : public Patch
|
||||
{
|
||||
public:
|
||||
bool FindPatchTarget(PatchContext& patchContext) override;
|
||||
void ApplyPatch(PatchContext& patchContext) override;
|
||||
|
||||
private:
|
||||
u32* _cardiIsRomDmaAvailable = nullptr;
|
||||
u16 _thumb = false;
|
||||
};
|
||||
@@ -0,0 +1,63 @@
|
||||
#include "common.h"
|
||||
#include "patches/PatchContext.h"
|
||||
#include "thumbInstructions.h"
|
||||
#include "CardiReadCardWithHashInternalAsyncPatch.h"
|
||||
|
||||
static const u32 sCARDiReadCardWithHashInternalAsyncPattern[] = { 0xE92D40F8u, 0xE59F405Cu, 0xE3E0C000u, 0xE594E508u };
|
||||
static const u32 sCARDiReadCardWithHashInternalAsyncPattern54[] = { 0xE92D40F8u, 0xE59FC058u, 0xE1A04000u, 0xE59C0508u };
|
||||
static const u32 sCARDiReadCardWithHashInternalAsyncPatternThumb[] = { 0x1C06B5F8u, 0x1C0D480Eu, 0x20006881u, 0x1C1743C0u };
|
||||
// static const u32 sCARDiReadCardWithHashInternalAsyncPatternThumb5004E85[] = { 0x1C1CB538u, 0x689D4B0Bu, 0x43DB2300u, 0xD101429Du };
|
||||
|
||||
static const u32 sReturnZeroPatchArm[] = { 0xE3A00000, 0xE12FFF1E }; // mov r0, #0; bx lr
|
||||
|
||||
bool CardiReadCardWithHashInternalAsyncPatch::FindPatchTarget(PatchContext& patchContext)
|
||||
{
|
||||
_cardiReadCardWithHashInternalAsync = patchContext.FindPattern32Twl(
|
||||
sCARDiReadCardWithHashInternalAsyncPattern, sizeof(sCARDiReadCardWithHashInternalAsyncPattern));
|
||||
if (!_cardiReadCardWithHashInternalAsync)
|
||||
{
|
||||
_cardiReadCardWithHashInternalAsync = patchContext.FindPattern32Twl(
|
||||
sCARDiReadCardWithHashInternalAsyncPattern54, sizeof(sCARDiReadCardWithHashInternalAsyncPattern54));
|
||||
}
|
||||
if (!_cardiReadCardWithHashInternalAsync)
|
||||
{
|
||||
_cardiReadCardWithHashInternalAsync = patchContext.FindPattern32Twl(
|
||||
sCARDiReadCardWithHashInternalAsyncPatternThumb, sizeof(sCARDiReadCardWithHashInternalAsyncPatternThumb));
|
||||
if (!_cardiReadCardWithHashInternalAsync)
|
||||
{
|
||||
_cardiReadCardWithHashInternalAsync = patchContext.FindPattern32(
|
||||
sCARDiReadCardWithHashInternalAsyncPatternThumb, sizeof(sCARDiReadCardWithHashInternalAsyncPatternThumb));
|
||||
}
|
||||
// if (!_cardiReadCardWithHashInternalAsync)
|
||||
// {
|
||||
// _cardiReadCardWithHashInternalAsync = patchContext.FindPattern32(
|
||||
// sCARDiReadCardWithHashInternalAsyncPatternThumb5004E85, sizeof(sCARDiReadCardWithHashInternalAsyncPatternThumb5004E85));
|
||||
// }
|
||||
if (_cardiReadCardWithHashInternalAsync)
|
||||
{
|
||||
_thumb = true;
|
||||
}
|
||||
}
|
||||
if (!_cardiReadCardWithHashInternalAsync)
|
||||
{
|
||||
LOG_WARNING("CARDi_ReadCardWithHashInternalAsync not found\n");
|
||||
}
|
||||
return _cardiReadCardWithHashInternalAsync != nullptr;
|
||||
}
|
||||
|
||||
void CardiReadCardWithHashInternalAsyncPatch::ApplyPatch(PatchContext& patchContext)
|
||||
{
|
||||
if (!_cardiReadCardWithHashInternalAsync)
|
||||
return;
|
||||
|
||||
if (_thumb)
|
||||
{
|
||||
((u16*)_cardiReadCardWithHashInternalAsync)[0] = THUMB_MOVS_IMM(THUMB_R0, 0);
|
||||
((u16*)_cardiReadCardWithHashInternalAsync)[1] = THUMB_BX_LR;
|
||||
}
|
||||
else
|
||||
{
|
||||
_cardiReadCardWithHashInternalAsync[0] = sReturnZeroPatchArm[0];
|
||||
_cardiReadCardWithHashInternalAsync[1] = sReturnZeroPatchArm[1];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
#include "patches/Patch.h"
|
||||
|
||||
/// @brief Arm9 patch to disable DMA card reads on SDK 5.
|
||||
class CardiReadCardWithHashInternalAsyncPatch : public Patch
|
||||
{
|
||||
public:
|
||||
bool FindPatchTarget(PatchContext& patchContext) override;
|
||||
void ApplyPatch(PatchContext& patchContext) override;
|
||||
|
||||
private:
|
||||
u32* _cardiReadCardWithHashInternalAsync = nullptr;
|
||||
u16 _thumb = false;
|
||||
};
|
||||
145
arm9/source/patches/arm9/sdk5/CardiReadRomWithCpuPatch.cpp
Normal file
145
arm9/source/patches/arm9/sdk5/CardiReadRomWithCpuPatch.cpp
Normal file
@@ -0,0 +1,145 @@
|
||||
#include "common.h"
|
||||
#include "patches/PatchContext.h"
|
||||
#include "fileInfo.h"
|
||||
#include "thumbInstructions.h"
|
||||
#include "patches/platform/LoaderPlatform.h"
|
||||
#include "patches/arm9/RomOffsetToSdSectorAsm.h"
|
||||
#include "patches/OffsetToSectorRemapAsm.h"
|
||||
#include "CardiReadRomWithCpuPatchAsm.h"
|
||||
#include "patches/arm9/FixCp15Asm.h"
|
||||
#include "CardiReadRomWithCpuPatch.h"
|
||||
|
||||
static const u32 sCARDiReadRomWithCPUPattern500753B[] = { 0xE92D4FF8u, 0xE24DD008u, 0xE59F00FCu, 0xE1A08003u };
|
||||
static const u32 sCARDiReadRomWithCPUPatternThumb[] = { 0xB085B5F0u, 0x1C1D482Du, 0x91006840u, 0x95049201u };
|
||||
static const u32 sCARDiReadRomWithCPUPatternThumb5017537[] = { 0xB085B5F0u, 0x1C1D482Du, 0x91006800u, 0x95049201u };
|
||||
// static const u32 sCARDiReadRomWithCPUPatternThumb5004E85[] = { 0xB085B5F0u, 0x1C1D482Bu, 0x910068C0u, 0x95049201u };
|
||||
static const u32 sCARDiReadRomWithCPUPatternThumb5007538[] = { 0xB085B5F0u, 0x1C1D482Bu, 0x91006800u, 0x95049201u };
|
||||
static const u32 sCARDiReadRomWithCPUPatternThumb5037531[] = { 0xB086B5F8u, 0x1C1D482Fu, 0x91006800u, 0x482E9003u };
|
||||
static const u32 sCARDiReadRomWithCPUPatternThumbHybrid5037531[] = { 0xB086B5F8u, 0x1C1D482Fu, 0x91006840u, 0x482E9003u };
|
||||
|
||||
void CardiReadRomWithCpuPatch::TryPattern(PatchContext& patchContext, const u32* pattern)
|
||||
{
|
||||
_cardiReadRomWithCpu = patchContext.FindPattern32(pattern, 16);
|
||||
if (_cardiReadRomWithCpu)
|
||||
{
|
||||
_foundPattern = pattern;
|
||||
}
|
||||
}
|
||||
|
||||
bool CardiReadRomWithCpuPatch::FindPatchTarget(PatchContext& patchContext)
|
||||
{
|
||||
TryPattern(patchContext, sCARDiReadRomWithCPUPattern500753B);
|
||||
if (!_cardiReadRomWithCpu)
|
||||
{
|
||||
TryPattern(patchContext, sCARDiReadRomWithCPUPatternThumb5037531);
|
||||
if (!_cardiReadRomWithCpu)
|
||||
{
|
||||
TryPattern(patchContext, sCARDiReadRomWithCPUPatternThumbHybrid5037531);
|
||||
}
|
||||
if (!_cardiReadRomWithCpu)
|
||||
{
|
||||
TryPattern(patchContext, sCARDiReadRomWithCPUPatternThumb5017537);
|
||||
}
|
||||
if (!_cardiReadRomWithCpu)
|
||||
{
|
||||
TryPattern(patchContext, sCARDiReadRomWithCPUPatternThumb5007538);
|
||||
}
|
||||
if (!_cardiReadRomWithCpu)
|
||||
{
|
||||
TryPattern(patchContext, sCARDiReadRomWithCPUPatternThumb);
|
||||
}
|
||||
// if (!_cardiReadRomWithCpu)
|
||||
// {
|
||||
// TryPattern(patchContext, sCARDiReadRomWithCPUPatternThumb5004E85);
|
||||
// }
|
||||
if (_cardiReadRomWithCpu)
|
||||
{
|
||||
_thumb = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (_cardiReadRomWithCpu)
|
||||
{
|
||||
LOG_DEBUG("Found CARDi_ReadRomWithCPU at %p\n", _cardiReadRomWithCpu);
|
||||
if (_thumb)
|
||||
{
|
||||
LOG_DEBUG("thumb CARDi_ReadRomWithCPU\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_WARNING("CARDi_ReadRomWithCPU not found\n");
|
||||
}
|
||||
return _cardiReadRomWithCpu != nullptr;
|
||||
}
|
||||
|
||||
void CardiReadRomWithCpuPatch::ApplyPatch(PatchContext& patchContext)
|
||||
{
|
||||
if (!_cardiReadRomWithCpu)
|
||||
return;
|
||||
|
||||
auto loaderPlatform = patchContext.GetLoaderPlatform();
|
||||
if (loaderPlatform->HasRomReads())
|
||||
{
|
||||
auto romReadPatchCode = loaderPlatform->CreateRomReadPatchCode(
|
||||
patchContext.GetPatchCodeCollection(), patchContext.GetPatchHeap());
|
||||
auto offsetToSectorRemapPatchCode = patchContext.GetPatchCodeCollection().GetOrAddSharedPatchCode([&]
|
||||
{
|
||||
return new OffsetToSectorRemapPatchCode(patchContext.GetPatchHeap());
|
||||
});
|
||||
__patch_cardireadromwithcpu_rom_offset_to_sd_sector_asm_address = (u32)offsetToSectorRemapPatchCode->GetRemapFunction();
|
||||
__patch_cardireadromwithcpu_sdread_asm_address = (u32)romReadPatchCode->GetSdReadFunction();
|
||||
}
|
||||
else
|
||||
{
|
||||
auto sdReadPatchCode = loaderPlatform->CreateSdReadPatchCode(
|
||||
patchContext.GetPatchCodeCollection(), patchContext.GetPatchHeap());
|
||||
auto romOffsetToSdSectorPatchCode = patchContext.GetPatchCodeCollection().GetOrAddSharedPatchCode([&]
|
||||
{
|
||||
return new RomOffsetToSdSectorPatchCode(patchContext.GetPatchHeap(), SHARED_ROM_FILE_INFO);
|
||||
});
|
||||
__patch_cardireadromwithcpu_rom_offset_to_sd_sector_asm_address = (u32)romOffsetToSdSectorPatchCode->GetRemapFunction();
|
||||
__patch_cardireadromwithcpu_sdread_asm_address = (u32)sdReadPatchCode->GetSdReadFunction();
|
||||
}
|
||||
|
||||
u32 patch1Size = SECTION_SIZE(patch_cardireadromwithcpu);
|
||||
void* patch1Address = patchContext.GetPatchHeap().Alloc(patch1Size);
|
||||
u32 patch4Size = SECTION_SIZE(fixcp15);
|
||||
void* patch4Address = patchContext.GetPatchHeap().Alloc(patch4Size);
|
||||
__patch_cardireadromwithcpu_fix_cp15_asm_address = (u32)&fix_cp15_asm - (u32)SECTION_START(fixcp15) + (u32)patch4Address;
|
||||
u32 entryAddress = (u32)&patch_cardireadromwithcpu_entry - (u32)SECTION_START(patch_cardireadromwithcpu) + (u32)patch1Address;
|
||||
if (_thumb)
|
||||
{
|
||||
bool old = _foundPattern == sCARDiReadRomWithCPUPatternThumb5017537
|
||||
|| _foundPattern == sCARDiReadRomWithCPUPatternThumb5007538
|
||||
// || _foundPattern == sCARDiReadRomWithCPUPatternThumb5004E85
|
||||
|| _foundPattern == sCARDiReadRomWithCPUPatternThumb;
|
||||
u32 patchOffset = old ? 0x48 : 0x4C;
|
||||
u32 returnOffset = old ? 0x26 : 0x28;
|
||||
patch_cardireadromwithcpu_return_offset = THUMB_MOVS_IMM(THUMB_R0, returnOffset);
|
||||
patch_cardireadromwithcpu_mov_src_to_r0 = THUMB_MOVS_REG(THUMB_R0, THUMB_R1); // src
|
||||
patch_cardireadromwithcpu_mov_dst_to_r1 = THUMB_MOVS_REG(THUMB_R1, THUMB_R4); // dst
|
||||
patch_cardireadromwithcpu_mov_actual_dst_to_r3 = THUMB_LDR_SP_IMM(THUMB_R3, 4);
|
||||
patch_cardireadromwithcpu_mov_left_to_read_to_r2 = THUMB_MOVS_REG(THUMB_R2, THUMB_R5);
|
||||
|
||||
*(u16*)((u8*)_cardiReadRomWithCpu + patchOffset - 2) = THUMB_LDR_SP_IMM(THUMB_R1, 8); // load rom source to r1 instead of r0
|
||||
*(u16*)((u8*)_cardiReadRomWithCpu + patchOffset + 0) = 0x4800; // ldr r0,= entryAddress
|
||||
*(u16*)((u8*)_cardiReadRomWithCpu + patchOffset + 2) = THUMB_BLX(THUMB_R0);
|
||||
*(u32*)((u8*)_cardiReadRomWithCpu + patchOffset + 4) = entryAddress;
|
||||
}
|
||||
else
|
||||
{
|
||||
u32 patchOffset = 0x78;
|
||||
patch_cardireadromwithcpu_return_offset = THUMB_MOVS_IMM(THUMB_R0, 0x28);
|
||||
patch_cardireadromwithcpu_mov_src_to_r0 = THUMB_MOVS_REG(THUMB_R0, THUMB_R6); // src
|
||||
patch_cardireadromwithcpu_mov_dst_to_r1 = THUMB_MOVS_REG(THUMB_R1, THUMB_R5); // dst
|
||||
patch_cardireadromwithcpu_mov_actual_dst_to_r3 = THUMB_MOV_HIREG(THUMB_R3, THUMB_HI_R10);
|
||||
patch_cardireadromwithcpu_mov_left_to_read_to_r2 = THUMB_MOV_HIREG(THUMB_R2, THUMB_HI_R8);
|
||||
|
||||
*(u32*)((u8*)_cardiReadRomWithCpu + patchOffset + 0) = 0xE59F0000; // ldr r0,= entryAddress
|
||||
*(u32*)((u8*)_cardiReadRomWithCpu + patchOffset + 4) = 0xE12FFF30; // blx r0
|
||||
*(u32*)((u8*)_cardiReadRomWithCpu + patchOffset + 8) = entryAddress;
|
||||
}
|
||||
memcpy(patch1Address, SECTION_START(patch_cardireadromwithcpu), patch1Size);
|
||||
memcpy(patch4Address, SECTION_START(fixcp15), patch4Size);
|
||||
}
|
||||
17
arm9/source/patches/arm9/sdk5/CardiReadRomWithCpuPatch.h
Normal file
17
arm9/source/patches/arm9/sdk5/CardiReadRomWithCpuPatch.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
#include "patches/Patch.h"
|
||||
|
||||
/// @brief Arm9 patch to redirect card reads on SDK 2-4.
|
||||
class CardiReadRomWithCpuPatch : public Patch
|
||||
{
|
||||
public:
|
||||
bool FindPatchTarget(PatchContext& patchContext) override;
|
||||
void ApplyPatch(PatchContext& patchContext) override;
|
||||
|
||||
private:
|
||||
u32* _cardiReadRomWithCpu = nullptr;
|
||||
u16 _thumb = false;
|
||||
const u32* _foundPattern = nullptr;
|
||||
|
||||
void TryPattern(PatchContext& patchContext, const u32* pattern);
|
||||
};
|
||||
14
arm9/source/patches/arm9/sdk5/CardiReadRomWithCpuPatchAsm.h
Normal file
14
arm9/source/patches/arm9/sdk5/CardiReadRomWithCpuPatchAsm.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
#include "sections.h"
|
||||
|
||||
DEFINE_SECTION_SYMBOLS(patch_cardireadromwithcpu);
|
||||
|
||||
extern "C" void patch_cardireadromwithcpu_entry();
|
||||
extern u16 patch_cardireadromwithcpu_return_offset;
|
||||
extern u16 patch_cardireadromwithcpu_mov_src_to_r0;
|
||||
extern u16 patch_cardireadromwithcpu_mov_dst_to_r1;
|
||||
extern u16 patch_cardireadromwithcpu_mov_actual_dst_to_r3;
|
||||
extern u16 patch_cardireadromwithcpu_mov_left_to_read_to_r2;
|
||||
extern u32 __patch_cardireadromwithcpu_fix_cp15_asm_address;
|
||||
extern u32 __patch_cardireadromwithcpu_rom_offset_to_sd_sector_asm_address;
|
||||
extern u32 __patch_cardireadromwithcpu_sdread_asm_address;
|
||||
74
arm9/source/patches/arm9/sdk5/CardiReadRomWithCpuPatchAsm.s
Normal file
74
arm9/source/patches/arm9/sdk5/CardiReadRomWithCpuPatchAsm.s
Normal file
@@ -0,0 +1,74 @@
|
||||
.cpu arm946e-s
|
||||
.section "patch_cardireadromwithcpu", "ax"
|
||||
.syntax unified
|
||||
|
||||
.thumb
|
||||
.global patch_cardireadromwithcpu_entry
|
||||
.type patch_cardireadromwithcpu_entry, %function
|
||||
patch_cardireadromwithcpu_entry:
|
||||
|
||||
.global patch_cardireadromwithcpu_return_offset
|
||||
patch_cardireadromwithcpu_return_offset:
|
||||
movs r0, #0x38
|
||||
add lr, r0
|
||||
push {lr}
|
||||
ldr r3, __patch_cardireadromwithcpu_fix_cp15_asm_address
|
||||
blx r3
|
||||
|
||||
.global patch_cardireadromwithcpu_mov_src_to_r0
|
||||
patch_cardireadromwithcpu_mov_src_to_r0:
|
||||
nop
|
||||
ldr r3, __patch_cardireadromwithcpu_rom_offset_to_sd_sector_asm_address
|
||||
blx r3
|
||||
|
||||
movs r2, #1 // r2 = sector count
|
||||
.global patch_cardireadromwithcpu_mov_dst_to_r1
|
||||
patch_cardireadromwithcpu_mov_dst_to_r1:
|
||||
movs r1, r5 // r1 = dst
|
||||
|
||||
.global patch_cardireadromwithcpu_mov_actual_dst_to_r3
|
||||
patch_cardireadromwithcpu_mov_actual_dst_to_r3:
|
||||
mov r3, r10
|
||||
cmp r3, r1
|
||||
bne do_read // if dst != actual dst the cache is in use
|
||||
|
||||
.global patch_cardireadromwithcpu_mov_left_to_read_to_r2
|
||||
patch_cardireadromwithcpu_mov_left_to_read_to_r2:
|
||||
mov r2, r8
|
||||
lsrs r2, r2, #9 // sectors left to read
|
||||
cmp r2, lr
|
||||
ble 1f
|
||||
mov r2, lr // clip to cluster boundary
|
||||
1:
|
||||
lsls r7, r2, #9
|
||||
|
||||
do_read:
|
||||
ldr r3, __patch_cardireadromwithcpu_sdread_asm_address
|
||||
blx r3
|
||||
// arm
|
||||
// r7 = number of bytes read
|
||||
// r8 = number of bytes left to read
|
||||
// r10 = actual dst
|
||||
// thumb
|
||||
// r7 = number of bytes read
|
||||
// r5 = number of bytes left to read
|
||||
// [sp + 0 + 4] = actual dst
|
||||
pop {pc}
|
||||
|
||||
.balign 4
|
||||
|
||||
.global __patch_cardireadromwithcpu_fix_cp15_asm_address
|
||||
__patch_cardireadromwithcpu_fix_cp15_asm_address:
|
||||
.word 0
|
||||
|
||||
.global __patch_cardireadromwithcpu_rom_offset_to_sd_sector_asm_address
|
||||
__patch_cardireadromwithcpu_rom_offset_to_sd_sector_asm_address:
|
||||
.word 0
|
||||
|
||||
.global __patch_cardireadromwithcpu_sdread_asm_address
|
||||
__patch_cardireadromwithcpu_sdread_asm_address:
|
||||
.word 0
|
||||
|
||||
.pool
|
||||
|
||||
.end
|
||||
Reference in New Issue
Block a user