mirror of
https://github.com/LNH-team/pico-loader.git
synced 2026-04-11 21:13:52 +02:00
Fix bug in handling of E cheat opcode, add cheat support for all remaining games
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
#include "common.h"
|
||||
#include "thumbInstructions.h"
|
||||
#include "CheatEnginePatchCode.h"
|
||||
#include "CheatEnginePatch.h"
|
||||
|
||||
@@ -7,6 +8,10 @@ static const u32 sVBlankIntrPatternArm0[] = { 0xE92D4000u, 0xE24DD004u, 0xE59F00
|
||||
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
|
||||
static const u32 sVBlankIntrPatternThumb2[] = { 0x46C04718u, 0x0000FFFFu, 0x4804B508u, 0x28006800u }; // +8
|
||||
static const u32 sVBlankIntrPatternThumb3[] = { 0xE51FF004u, 0x037FD67Cu, 0x4804B508u, 0x28006800u }; // +8
|
||||
static const u32 sVBlankIntrPatternThumb4[] = { 0x46C04770u, 0x02FFFE1Du, 0x4804B508u, 0x28006800u }; // +8
|
||||
static const u32 sVBlankIntrPatternThumb5[] = { 0xE51FF004u, 0x037FA868u, 0x4804B508u, 0x28006800u }; // +8
|
||||
|
||||
bool CheatEnginePatch::FindPatchTarget(PatchContext& patchContext)
|
||||
{
|
||||
@@ -41,6 +46,42 @@ bool CheatEnginePatch::FindPatchTarget(PatchContext& patchContext)
|
||||
_vblankIrqHandler += 2;
|
||||
}
|
||||
}
|
||||
if (!_vblankIrqHandler)
|
||||
{
|
||||
_vblankIrqHandler = patchContext.FindPattern32(sVBlankIntrPatternThumb2, sizeof(sVBlankIntrPatternThumb2));
|
||||
if (_vblankIrqHandler)
|
||||
{
|
||||
_foundPattern = sVBlankIntrPatternThumb2;
|
||||
_vblankIrqHandler += 2;
|
||||
}
|
||||
}
|
||||
if (!_vblankIrqHandler)
|
||||
{
|
||||
_vblankIrqHandler = patchContext.FindPattern32(sVBlankIntrPatternThumb3, sizeof(sVBlankIntrPatternThumb3));
|
||||
if (_vblankIrqHandler)
|
||||
{
|
||||
_foundPattern = sVBlankIntrPatternThumb3;
|
||||
_vblankIrqHandler += 2;
|
||||
}
|
||||
}
|
||||
if (!_vblankIrqHandler)
|
||||
{
|
||||
_vblankIrqHandler = patchContext.FindPattern32(sVBlankIntrPatternThumb4, sizeof(sVBlankIntrPatternThumb4));
|
||||
if (_vblankIrqHandler)
|
||||
{
|
||||
_foundPattern = sVBlankIntrPatternThumb4;
|
||||
_vblankIrqHandler += 2;
|
||||
}
|
||||
}
|
||||
if (!_vblankIrqHandler)
|
||||
{
|
||||
_vblankIrqHandler = patchContext.FindPattern32(sVBlankIntrPatternThumb5, sizeof(sVBlankIntrPatternThumb5));
|
||||
if (_vblankIrqHandler)
|
||||
{
|
||||
_foundPattern = sVBlankIntrPatternThumb5;
|
||||
_vblankIrqHandler += 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (_vblankIrqHandler)
|
||||
{
|
||||
@@ -89,6 +130,8 @@ void CheatEnginePatch::ApplyPatch(PatchContext& patchContext)
|
||||
// 1:
|
||||
// pop {r3,lr}
|
||||
// bx lr
|
||||
_vblankIrqHandler[6] = 0xE51FF004; // ldr pc,= address
|
||||
_vblankIrqHandler[7] = (u32)cheatEnginePatchCode->GetCheatEngineFunctionArm(); // address
|
||||
}
|
||||
else if (_foundPattern == sVBlankIntrPatternThumb0)
|
||||
{
|
||||
@@ -104,8 +147,15 @@ void CheatEnginePatch::ApplyPatch(PatchContext& patchContext)
|
||||
// pop {r3}
|
||||
// bx r3
|
||||
// nop
|
||||
((u16*)_vblankIrqHandler)[8] = THUMB_LDR_PC_IMM(THUMB_R1, 0); // ldr r1,= address
|
||||
((u16*)_vblankIrqHandler)[9] = THUMB_BX(THUMB_R1); // bx r1
|
||||
_vblankIrqHandler[10 >> 1] = (u32)cheatEnginePatchCode->GetCheatEngineFunction(); // address
|
||||
}
|
||||
else if (_foundPattern == sVBlankIntrPatternThumb1)
|
||||
else if (_foundPattern == sVBlankIntrPatternThumb1
|
||||
|| _foundPattern == sVBlankIntrPatternThumb2
|
||||
|| _foundPattern == sVBlankIntrPatternThumb3
|
||||
|| _foundPattern == sVBlankIntrPatternThumb4
|
||||
|| _foundPattern == sVBlankIntrPatternThumb5)
|
||||
{
|
||||
// push {r3,lr}
|
||||
// ldr r0,=
|
||||
@@ -117,6 +167,23 @@ void CheatEnginePatch::ApplyPatch(PatchContext& patchContext)
|
||||
// pop {r3}
|
||||
// pop {r3}
|
||||
// bx r3
|
||||
|
||||
// rewrite the function to
|
||||
// add r1, pc, #4
|
||||
// ldr r0,=
|
||||
// ldr r2,= cheatengine_entry_thumb_replace
|
||||
// bx r2
|
||||
// beq 1f
|
||||
// bl
|
||||
// 1:
|
||||
// mov pc, r4
|
||||
// .word cheatengine_entry_thumb_replace
|
||||
|
||||
((u16*)_vblankIrqHandler)[0] = THUMB_ADD_PC_IMM(THUMB_R1, 4); // add r1, pc, #4
|
||||
((u16*)_vblankIrqHandler)[2] = THUMB_LDR_PC_IMM(THUMB_R2, 8); // ldr r2,= cheatengine_entry_thumb_replace
|
||||
((u16*)_vblankIrqHandler)[3] = THUMB_BX(THUMB_R2); // bx r2
|
||||
((u16*)_vblankIrqHandler)[7] = THUMB_MOV_HIREG(THUMB_HI_PC, THUMB_R4); // mov pc, r4
|
||||
_vblankIrqHandler[8 >> 1] = (u32)cheatEnginePatchCode->GetCheatEngineFunctionThumbReplace(); // .word cheatengine_entry_thumb_replace
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
DEFINE_SECTION_SYMBOLS(patch_cheatengine);
|
||||
|
||||
extern "C" void cheatengine_entry_arm(void);
|
||||
extern "C" void cheatengine_entry_thumb_replace(void);
|
||||
extern "C" void cheatengine_entry(void);
|
||||
|
||||
extern const void* cheatengine_cheatsPtr;
|
||||
@@ -21,4 +23,14 @@ public:
|
||||
{
|
||||
return GetAddressAtTarget((void*)cheatengine_entry);
|
||||
}
|
||||
|
||||
const void* GetCheatEngineFunctionArm() const
|
||||
{
|
||||
return GetAddressAtTarget((void*)cheatengine_entry_arm);
|
||||
}
|
||||
|
||||
const void* GetCheatEngineFunctionThumbReplace() const
|
||||
{
|
||||
return GetAddressAtTarget((void*)cheatengine_entry_thumb_replace);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,12 +1,34 @@
|
||||
.cpu arm7tdmi
|
||||
.section "patch_cheatengine", "ax"
|
||||
.syntax unified
|
||||
.thumb
|
||||
|
||||
// For reference on how Action Replay codes work for the DS
|
||||
// - https://problemkaputt.de/gbatek-ds-cart-cheat-action-replay-ds.htm
|
||||
// - https://github.com/melonDS-emu/melonDS/blob/master/src/AREngine.cpp
|
||||
|
||||
.arm
|
||||
.global cheatengine_entry_arm
|
||||
.type cheatengine_entry_arm, %function
|
||||
cheatengine_entry_arm:
|
||||
adr r12, cheatengine_entry + 1
|
||||
bx r12
|
||||
|
||||
.thumb
|
||||
.global cheatengine_entry_thumb_replace
|
||||
.type cheatengine_entry_thumb_replace, %function
|
||||
cheatengine_entry_thumb_replace:
|
||||
push {r4, r5, lr} // r5 is a dummy
|
||||
ldr r0, [r0]
|
||||
adr r4, cheatengine_entry_thumb_replace_return
|
||||
cmp r0, #0
|
||||
mov pc, r1
|
||||
|
||||
.balign 4
|
||||
|
||||
cheatengine_entry_thumb_replace_return:
|
||||
pop {r4}
|
||||
nop
|
||||
|
||||
.global cheatengine_entry
|
||||
.type cheatengine_entry, %function
|
||||
cheatengine_entry:
|
||||
@@ -79,7 +101,7 @@ runCheat_opcode_loop:
|
||||
cmp r3, #0xE0
|
||||
bne runCheat_opcode_loop
|
||||
|
||||
// opcode E0 has a dynamic length
|
||||
// opcode E has a dynamic length
|
||||
adds r2, #7
|
||||
movs r3, #7
|
||||
bics r2, r3 // pad length to multiple of 8
|
||||
@@ -385,10 +407,11 @@ opcode_DC: // offset += b
|
||||
opcode_EX: // copy b param bytes to address a+offset
|
||||
push {r0}
|
||||
|
||||
adds r0, r2
|
||||
adds r0, #7
|
||||
movs r3, #7
|
||||
bics r0, r3 // pad length to multiple of 8
|
||||
// pad length to multiple of 8
|
||||
adds r3, r2, #7
|
||||
lsrs r3, r3, #3
|
||||
lsls r3, r3, #3
|
||||
adds r0, r3
|
||||
|
||||
pop {r3}
|
||||
push {r0}
|
||||
|
||||
@@ -32,4 +32,5 @@
|
||||
#define THUMB_STR_IMM(rd, rb, imm) (0x6000 | (((imm) >> 2) << 6) | ((rb) << 3) | (rd))
|
||||
#define THUMB_STR_SP_IMM(rd, imm) (0x9000 | ((rd) << 8) | (((imm) >> 2) & 0xFF))
|
||||
#define THUMB_LDR_SP_IMM(rd, imm) (0x9800 | ((rd) << 8) | (((imm) >> 2) & 0xFF))
|
||||
#define THUMB_ADD_PC_IMM(rd, imm) (0xA000 | ((rd) << 8) | (((imm) >> 2) & 0xFF))
|
||||
#define THUMB_SVC(x) (0xDF00 | (x))
|
||||
Reference in New Issue
Block a user