mirror of
https://github.com/LNH-team/pico-loader.git
synced 2026-06-02 01:06:50 +02:00
Further work on implementing support for cheats
This commit is contained in:
125
arm9/source/patches/arm7/cheats/CheatEnginePatch.cpp
Normal file
125
arm9/source/patches/arm7/cheats/CheatEnginePatch.cpp
Normal file
@@ -0,0 +1,125 @@
|
||||
#include "common.h"
|
||||
#include "CheatEnginePatchCode.h"
|
||||
#include "CheatEnginePatch.h"
|
||||
|
||||
// sdk2-4
|
||||
static const u32 sVBlankIntrPatternArm0[] = { 0xE92D4000u, 0xE24DD004u, 0xE59F0018u, 0xE5900000u };
|
||||
static const u32 sVBlankIntrPatternArm1[] = { 0xE92D4008u, 0xE59F0014u, 0xE5900000u, 0xE3500000u };
|
||||
static const u32 sVBlankIntrPatternThumb0[] = { 0x00000000u, 0xB081B500u, 0x68004804u, 0xD0012800u }; // +4
|
||||
static const u32 sVBlankIntrPatternThumb1[] = { 0x46C04770u, 0x027FFE1Du, 0x4804B508u, 0x28006800u }; // +8
|
||||
|
||||
bool CheatEnginePatch::FindPatchTarget(PatchContext& patchContext)
|
||||
{
|
||||
_vblankIrqHandler = patchContext.FindPattern32(sVBlankIntrPatternArm0, sizeof(sVBlankIntrPatternArm0));
|
||||
if (_vblankIrqHandler)
|
||||
{
|
||||
_foundPattern = sVBlankIntrPatternArm0;
|
||||
}
|
||||
if (!_vblankIrqHandler)
|
||||
{
|
||||
_vblankIrqHandler = patchContext.FindPattern32(sVBlankIntrPatternArm1, sizeof(sVBlankIntrPatternArm1));
|
||||
if (_vblankIrqHandler)
|
||||
{
|
||||
_foundPattern = sVBlankIntrPatternArm1;
|
||||
}
|
||||
}
|
||||
if (!_vblankIrqHandler)
|
||||
{
|
||||
_vblankIrqHandler = patchContext.FindPattern32(sVBlankIntrPatternThumb0, sizeof(sVBlankIntrPatternThumb0));
|
||||
if (_vblankIrqHandler)
|
||||
{
|
||||
_foundPattern = sVBlankIntrPatternThumb0;
|
||||
_vblankIrqHandler += 1;
|
||||
}
|
||||
}
|
||||
if (!_vblankIrqHandler)
|
||||
{
|
||||
_vblankIrqHandler = patchContext.FindPattern32(sVBlankIntrPatternThumb1, sizeof(sVBlankIntrPatternThumb1));
|
||||
if (_vblankIrqHandler)
|
||||
{
|
||||
_foundPattern = sVBlankIntrPatternThumb1;
|
||||
_vblankIrqHandler += 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (_vblankIrqHandler)
|
||||
{
|
||||
LOG_DEBUG("ARM7 VBlankIntr found at 0x%p\n", _vblankIrqHandler);
|
||||
}
|
||||
|
||||
return _vblankIrqHandler != nullptr;
|
||||
}
|
||||
|
||||
void CheatEnginePatch::ApplyPatch(PatchContext& patchContext)
|
||||
{
|
||||
if (!_vblankIrqHandler || !_cheats)
|
||||
return;
|
||||
|
||||
auto cheatEnginePatchCode = patchContext.GetPatchCodeCollection().AddUniquePatchCode<CheatEnginePatchCode>
|
||||
(
|
||||
patchContext.GetPatchHeap(),
|
||||
_cheats
|
||||
);
|
||||
|
||||
if (_foundPattern == sVBlankIntrPatternArm0)
|
||||
{
|
||||
// push {lr}
|
||||
// sub sp, sp, #4
|
||||
// ldr r0,=
|
||||
// ldr r0, [r0]
|
||||
// cmp r0, #0
|
||||
// beq 1f
|
||||
// bl
|
||||
// 1:
|
||||
// add sp, sp, #4
|
||||
// pop {lr}
|
||||
// bx lr
|
||||
_vblankIrqHandler[7] = 0xE59F0000; // ldr r0,= address
|
||||
_vblankIrqHandler[8] = 0xE12FFF10; // bx r0
|
||||
_vblankIrqHandler[9] = (u32)cheatEnginePatchCode->GetCheatEngineFunction(); // address
|
||||
}
|
||||
else if (_foundPattern == sVBlankIntrPatternArm1)
|
||||
{
|
||||
// push {r3,lr}
|
||||
// ldr r0,=
|
||||
// ldr r0, [r0]
|
||||
// cmp r0, #0
|
||||
// beq 1f
|
||||
// bl
|
||||
// 1:
|
||||
// pop {r3,lr}
|
||||
// bx lr
|
||||
}
|
||||
else if (_foundPattern == sVBlankIntrPatternThumb0)
|
||||
{
|
||||
// push {lr}
|
||||
// sub sp, sp, #4
|
||||
// ldr r0,=
|
||||
// ldr r0, [r0]
|
||||
// cmp r0, #0
|
||||
// beq 1f
|
||||
// bl
|
||||
// 1:
|
||||
// add sp, sp, #4
|
||||
// pop {r3}
|
||||
// bx r3
|
||||
// nop
|
||||
}
|
||||
else if (_foundPattern == sVBlankIntrPatternThumb1)
|
||||
{
|
||||
// push {r3,lr}
|
||||
// ldr r0,=
|
||||
// ldr r0, [r0]
|
||||
// cmp r0, #0
|
||||
// beq 1f
|
||||
// bl
|
||||
// 1:
|
||||
// pop {r3}
|
||||
// pop {r3}
|
||||
// bx r3
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("ARM7 VBlankIntr signature not implemented\n");
|
||||
}
|
||||
}
|
||||
20
arm9/source/patches/arm7/cheats/CheatEnginePatch.h
Normal file
20
arm9/source/patches/arm7/cheats/CheatEnginePatch.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
#include "patches/Patch.h"
|
||||
|
||||
/// @brief Arm7 patch for injecting the cheat engine in the vblank interrupt handler.
|
||||
class CheatEnginePatch : public Patch
|
||||
{
|
||||
public:
|
||||
bool FindPatchTarget(PatchContext& patchContext) override;
|
||||
void ApplyPatch(PatchContext& patchContext) override;
|
||||
|
||||
void SetCheats(const void* cheats)
|
||||
{
|
||||
_cheats = cheats;
|
||||
}
|
||||
|
||||
private:
|
||||
const void* _cheats = nullptr;
|
||||
u32* _vblankIrqHandler = nullptr;
|
||||
const u32* _foundPattern = nullptr;
|
||||
};
|
||||
24
arm9/source/patches/arm7/cheats/CheatEnginePatchCode.h
Normal file
24
arm9/source/patches/arm7/cheats/CheatEnginePatchCode.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
#include "sections.h"
|
||||
#include "patches/PatchCode.h"
|
||||
|
||||
DEFINE_SECTION_SYMBOLS(patch_cheatengine);
|
||||
|
||||
extern "C" void cheatengine_entry(void);
|
||||
|
||||
extern const void* cheatengine_cheatsPtr;
|
||||
|
||||
class CheatEnginePatchCode : public PatchCode
|
||||
{
|
||||
public:
|
||||
CheatEnginePatchCode(PatchHeap& patchHeap, const void* cheatsAddress)
|
||||
: PatchCode(SECTION_START(patch_cheatengine), SECTION_SIZE(patch_cheatengine), patchHeap)
|
||||
{
|
||||
cheatengine_cheatsPtr = cheatsAddress;
|
||||
}
|
||||
|
||||
const void* GetCheatEngineFunction() const
|
||||
{
|
||||
return GetAddressAtTarget((void*)cheatengine_entry);
|
||||
}
|
||||
};
|
||||
@@ -10,16 +10,22 @@
|
||||
.global cheatengine_entry
|
||||
.type cheatengine_entry, %function
|
||||
cheatengine_entry:
|
||||
push {r4, lr}
|
||||
pop {r0, r1}
|
||||
mov lr, r1
|
||||
push {r4, r5, lr}
|
||||
ldr r4, cheatengine_cheatsPtr
|
||||
ldr r5, [r4, #4] // pload_cheats_t::numberOfCheats
|
||||
adds r4, #8
|
||||
entry_cheats_loop:
|
||||
ldmia r4!, {r0} // r0 = cheat pointer
|
||||
cmp r0, #0
|
||||
beq entry_end
|
||||
subs r5, #1
|
||||
bmi entry_end
|
||||
movs r0, r4
|
||||
bl cheatengine_runCheat
|
||||
ldmia r4!, {r0} // r0 = length of cheat in bytes (pload_cheat_t::length)
|
||||
adds r4, r0
|
||||
b entry_cheats_loop
|
||||
entry_end:
|
||||
pop {r4}
|
||||
pop {r4, r5}
|
||||
pop {r3}
|
||||
bx r3
|
||||
|
||||
@@ -38,7 +44,8 @@ cheatengine_runCheat:
|
||||
mov r6, r10
|
||||
mov r7, r11
|
||||
push {r4, r5, r6, r7} // r8, r9, r10, r11
|
||||
ldr r1, [r0] // r1 = length of cheat code
|
||||
|
||||
ldmia r0!, {r1} // r1 = length of cheat code
|
||||
adds r1, r0
|
||||
mov r8, r1 // r8 = end of cheat code
|
||||
mov r9, r0 // r9 = loop start
|
||||
@@ -389,7 +396,6 @@ FX_end:
|
||||
|
||||
.balign 4
|
||||
|
||||
// Pointer to list of pointers to cheat codes. Last pointer should be nullptr to terminate the list.
|
||||
.global cheatengine_cheatsPtr
|
||||
cheatengine_cheatsPtr:
|
||||
.word 0
|
||||
|
||||
Reference in New Issue
Block a user