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:
@@ -522,7 +522,13 @@ void NdsLoader::HandleHomebrewPatching()
|
|||||||
void NdsLoader::ApplyArm7Patches()
|
void NdsLoader::ApplyArm7Patches()
|
||||||
{
|
{
|
||||||
sendToArm9(IPC_COMMAND_ARM9_APPLY_ARM7_PATCHES);
|
sendToArm9(IPC_COMMAND_ARM9_APPLY_ARM7_PATCHES);
|
||||||
|
sendToArm9(_cheats ? _cheats->length : 0);
|
||||||
void* patchSpaceStart = (void*)receiveFromArm9();
|
void* patchSpaceStart = (void*)receiveFromArm9();
|
||||||
|
void* cheatsPtr = (void*)receiveFromArm9();
|
||||||
|
if (cheatsPtr != nullptr && _cheats != nullptr)
|
||||||
|
{
|
||||||
|
memcpy(cheatsPtr, _cheats, _cheats->length);
|
||||||
|
}
|
||||||
if (patchSpaceStart)
|
if (patchSpaceStart)
|
||||||
{
|
{
|
||||||
u32 mbk6 = 0;
|
u32 mbk6 = 0;
|
||||||
|
|||||||
@@ -42,6 +42,13 @@ public:
|
|||||||
_argumentsLength = argumentsLength;
|
_argumentsLength = argumentsLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief Sets the cheats to apply to the rom.
|
||||||
|
/// @param cheats The cheats.
|
||||||
|
void SetCheats(const pload_cheats_t* cheats)
|
||||||
|
{
|
||||||
|
_cheats = cheats;
|
||||||
|
}
|
||||||
|
|
||||||
/// @brief Loads the rom according to the specified \p bootMode.
|
/// @brief Loads the rom according to the specified \p bootMode.
|
||||||
/// @param bootMode The boot mode.
|
/// @param bootMode The boot mode.
|
||||||
void Load(BootMode bootMode);
|
void Load(BootMode bootMode);
|
||||||
@@ -53,6 +60,7 @@ private:
|
|||||||
const TCHAR* _launcherPath = nullptr;
|
const TCHAR* _launcherPath = nullptr;
|
||||||
u32 _argumentsLength = 0;
|
u32 _argumentsLength = 0;
|
||||||
const char* _arguments = nullptr;
|
const char* _arguments = nullptr;
|
||||||
|
const pload_cheats_t* _cheats = nullptr;
|
||||||
nds_header_twl_t _romHeader;
|
nds_header_twl_t _romHeader;
|
||||||
DsiWareSaveResult _dsiwareSaveResult;
|
DsiWareSaveResult _dsiwareSaveResult;
|
||||||
|
|
||||||
|
|||||||
@@ -219,10 +219,19 @@ extern "C" void loaderMain()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
pload_cheats_t* cheats = nullptr;
|
||||||
|
if (gLoaderHeader.v3.cheats != nullptr && gLoaderHeader.v3.cheats->numberOfCheats != 0)
|
||||||
|
{
|
||||||
|
// Copy cheats to vram
|
||||||
|
cheats = (pload_cheats_t*)malloc(gLoaderHeader.v3.cheats->length);
|
||||||
|
memcpy(cheats, gLoaderHeader.v3.cheats, gLoaderHeader.v3.cheats->length);
|
||||||
|
}
|
||||||
|
|
||||||
sLoader.SetRomPath(gLoaderHeader.loadParams.romPath);
|
sLoader.SetRomPath(gLoaderHeader.loadParams.romPath);
|
||||||
handleSavePath();
|
handleSavePath();
|
||||||
sLoader.SetArguments(gLoaderHeader.loadParams.arguments, gLoaderHeader.loadParams.argumentsLength);
|
sLoader.SetArguments(gLoaderHeader.loadParams.arguments, gLoaderHeader.loadParams.argumentsLength);
|
||||||
sLoader.SetLauncherPath(gLoaderHeader.v2.launcherPath);
|
sLoader.SetLauncherPath(gLoaderHeader.v2.launcherPath);
|
||||||
|
sLoader.SetCheats(cheats);
|
||||||
sLoader.Load(BootMode::Normal);
|
sLoader.Load(BootMode::Normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,10 +15,12 @@
|
|||||||
#include "patches/arm7/DisableArm7WramClearPatch.h"
|
#include "patches/arm7/DisableArm7WramClearPatch.h"
|
||||||
#include "patches/arm7/sdk5/Sdk5DsiSdCardRedirectPatch.h"
|
#include "patches/arm7/sdk5/Sdk5DsiSdCardRedirectPatch.h"
|
||||||
#include "patches/arm7/PokemonDownloaderArm7Patch.h"
|
#include "patches/arm7/PokemonDownloaderArm7Patch.h"
|
||||||
|
#include "patches/arm7/cheats/CheatEnginePatch.h"
|
||||||
#include "Arm7Patcher.h"
|
#include "Arm7Patcher.h"
|
||||||
|
|
||||||
void* Arm7Patcher::ApplyPatches(const LoaderPlatform* loaderPlatform) const
|
void* Arm7Patcher::ApplyPatches(const LoaderPlatform* loaderPlatform, u32 cheatsLength, void*& cheatsPtr) const
|
||||||
{
|
{
|
||||||
|
cheatsPtr = nullptr;
|
||||||
auto romHeader = (const nds_header_ntr_t*)TWL_SHARED_MEMORY->ntrSharedMem.romHeader;
|
auto romHeader = (const nds_header_ntr_t*)TWL_SHARED_MEMORY->ntrSharedMem.romHeader;
|
||||||
auto twlRomHeader = (const nds_header_twl_t*)TWL_SHARED_MEMORY->twlRomHeader;
|
auto twlRomHeader = (const nds_header_twl_t*)TWL_SHARED_MEMORY->twlRomHeader;
|
||||||
ModuleParamsLocator moduleParamsLocator;
|
ModuleParamsLocator moduleParamsLocator;
|
||||||
@@ -91,10 +93,18 @@ void* Arm7Patcher::ApplyPatches(const LoaderPlatform* loaderPlatform) const
|
|||||||
patchCollection.AddPatch(new PokemonDownloaderArm7Patch());
|
patchCollection.AddPatch(new PokemonDownloaderArm7Patch());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CheatEnginePatch* cheatEnginePatch = nullptr;
|
||||||
|
if (cheatsLength > 0)
|
||||||
|
{
|
||||||
|
cheatEnginePatch = new CheatEnginePatch();
|
||||||
|
patchCollection.AddPatch(cheatEnginePatch);
|
||||||
|
}
|
||||||
|
|
||||||
if (arm7ArenaPatch->FindPatchTarget(patchContext))
|
if (arm7ArenaPatch->FindPatchTarget(patchContext))
|
||||||
{
|
{
|
||||||
const u32 arm7PatchSpaceSize = 0x800;
|
const u32 arm7PatchSpaceSize = 0x800;
|
||||||
void* privateWramHeapStart = arm7ArenaPatch->GetArm7PrivateWramArenaLo();
|
void* privateWramHeapStart = arm7ArenaPatch->GetArm7PrivateWramArenaLo();
|
||||||
|
u32 mainMemoryArenaLo = (u32)arm7ArenaPatch->GetMainMemoryArenaLo();
|
||||||
if (0x0380F780 - (u32)privateWramHeapStart - 0x2100 >= arm7PatchSpaceSize)
|
if (0x0380F780 - (u32)privateWramHeapStart - 0x2100 >= arm7PatchSpaceSize)
|
||||||
{
|
{
|
||||||
patchSpaceStart = privateWramHeapStart;
|
patchSpaceStart = privateWramHeapStart;
|
||||||
@@ -103,7 +113,6 @@ void* Arm7Patcher::ApplyPatches(const LoaderPlatform* loaderPlatform) const
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOG_DEBUG("Arm 7 patches placed in main memory\n");
|
LOG_DEBUG("Arm 7 patches placed in main memory\n");
|
||||||
u32 mainMemoryArenaLo = (u32)arm7ArenaPatch->GetMainMemoryArenaLo();
|
|
||||||
if (gIsDsiMode && romHeader->unitCode == 0)
|
if (gIsDsiMode && romHeader->unitCode == 0)
|
||||||
{
|
{
|
||||||
patchSpaceStart = (void*)(mainMemoryArenaLo & ~0xC00000); // 0x023...
|
patchSpaceStart = (void*)(mainMemoryArenaLo & ~0xC00000); // 0x023...
|
||||||
@@ -112,8 +121,24 @@ void* Arm7Patcher::ApplyPatches(const LoaderPlatform* loaderPlatform) const
|
|||||||
{
|
{
|
||||||
patchSpaceStart = (void*)(mainMemoryArenaLo | 0x800000); // make sure it ends up in the right place while in 16MB mode
|
patchSpaceStart = (void*)(mainMemoryArenaLo | 0x800000); // make sure it ends up in the right place while in 16MB mode
|
||||||
}
|
}
|
||||||
arm7ArenaPatch->SetMainMemoryArenaLo((u8*)mainMemoryArenaLo + arm7PatchSpaceSize);
|
mainMemoryArenaLo += arm7PatchSpaceSize;
|
||||||
}
|
}
|
||||||
|
if (cheatsLength > 0)
|
||||||
|
{
|
||||||
|
void* cheats;
|
||||||
|
if (gIsDsiMode && romHeader->unitCode == 0)
|
||||||
|
{
|
||||||
|
cheats = (void*)(mainMemoryArenaLo & ~0xC00000); // 0x023...
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cheats = (void*)(mainMemoryArenaLo | 0x800000); // make sure it ends up in the right place while in 16MB mode
|
||||||
|
}
|
||||||
|
cheatsPtr = cheats;
|
||||||
|
cheatEnginePatch->SetCheats(cheats);
|
||||||
|
mainMemoryArenaLo += cheatsLength;
|
||||||
|
}
|
||||||
|
arm7ArenaPatch->SetMainMemoryArenaLo((void*)mainMemoryArenaLo);
|
||||||
patchContext.GetPatchHeap().AddFreeSpace(patchSpaceStart, arm7PatchSpaceSize);
|
patchContext.GetPatchHeap().AddFreeSpace(patchSpaceStart, arm7PatchSpaceSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ class Arm7Patcher
|
|||||||
public:
|
public:
|
||||||
/// @brief Applies arm7 patches using the given \p loaderPlatform.
|
/// @brief Applies arm7 patches using the given \p loaderPlatform.
|
||||||
/// @param loaderPlatform The loader platform to use.
|
/// @param loaderPlatform The loader platform to use.
|
||||||
|
/// @param cheatsLength The length of the cheats data, or zero when there are no cheats.
|
||||||
|
/// @param cheatsPtr Pointer to where the cheats need to be stored, or \c nullptr when there are no cheats.
|
||||||
/// @return A pointer to the patch space in IWRAM, or \c nullptr if the patches have been placed in main memory.
|
/// @return A pointer to the patch space in IWRAM, or \c nullptr if the patches have been placed in main memory.
|
||||||
void* ApplyPatches(const LoaderPlatform* loaderPlatform) const;
|
void* ApplyPatches(const LoaderPlatform* loaderPlatform, u32 cheatsLength, void*& cheatsPtr) const;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -155,10 +155,12 @@ static void handleApplyArm9PatchesCommand()
|
|||||||
ipc_sendWordDirect(1);
|
ipc_sendWordDirect(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handleApplyArm7PatchesCommand()
|
static void handleApplyArm7PatchesCommand(u32 cheatsLength)
|
||||||
{
|
{
|
||||||
void* patchSpaceStart = Arm7Patcher().ApplyPatches(sLoaderPlatform);
|
void* cheats = nullptr;
|
||||||
|
void* patchSpaceStart = Arm7Patcher().ApplyPatches(sLoaderPlatform, cheatsLength, cheats);
|
||||||
ipc_sendWordDirect((u32)patchSpaceStart);
|
ipc_sendWordDirect((u32)patchSpaceStart);
|
||||||
|
ipc_sendWordDirect((u32)cheats);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handleSetAPInfoCommand()
|
static void handleSetAPInfoCommand()
|
||||||
@@ -289,7 +291,8 @@ static void handleArm7Command(u32 command)
|
|||||||
}
|
}
|
||||||
case IPC_COMMAND_ARM9_APPLY_ARM7_PATCHES:
|
case IPC_COMMAND_ARM9_APPLY_ARM7_PATCHES:
|
||||||
{
|
{
|
||||||
handleApplyArm7PatchesCommand();
|
u32 cheatsLength = receiveFromArm7();
|
||||||
|
handleApplyArm7PatchesCommand(cheatsLength);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IPC_COMMAND_ARM9_SET_AP_INFO:
|
case IPC_COMMAND_ARM9_SET_AP_INFO:
|
||||||
|
|||||||
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
|
.global cheatengine_entry
|
||||||
.type cheatengine_entry, %function
|
.type cheatengine_entry, %function
|
||||||
cheatengine_entry:
|
cheatengine_entry:
|
||||||
push {r4, lr}
|
pop {r0, r1}
|
||||||
|
mov lr, r1
|
||||||
|
push {r4, r5, lr}
|
||||||
ldr r4, cheatengine_cheatsPtr
|
ldr r4, cheatengine_cheatsPtr
|
||||||
|
ldr r5, [r4, #4] // pload_cheats_t::numberOfCheats
|
||||||
|
adds r4, #8
|
||||||
entry_cheats_loop:
|
entry_cheats_loop:
|
||||||
ldmia r4!, {r0} // r0 = cheat pointer
|
subs r5, #1
|
||||||
cmp r0, #0
|
bmi entry_end
|
||||||
beq entry_end
|
movs r0, r4
|
||||||
bl cheatengine_runCheat
|
bl cheatengine_runCheat
|
||||||
|
ldmia r4!, {r0} // r0 = length of cheat in bytes (pload_cheat_t::length)
|
||||||
|
adds r4, r0
|
||||||
b entry_cheats_loop
|
b entry_cheats_loop
|
||||||
entry_end:
|
entry_end:
|
||||||
pop {r4}
|
pop {r4, r5}
|
||||||
pop {r3}
|
pop {r3}
|
||||||
bx r3
|
bx r3
|
||||||
|
|
||||||
@@ -38,7 +44,8 @@ cheatengine_runCheat:
|
|||||||
mov r6, r10
|
mov r6, r10
|
||||||
mov r7, r11
|
mov r7, r11
|
||||||
push {r4, r5, r6, r7} // r8, r9, r10, 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
|
adds r1, r0
|
||||||
mov r8, r1 // r8 = end of cheat code
|
mov r8, r1 // r8 = end of cheat code
|
||||||
mov r9, r0 // r9 = loop start
|
mov r9, r0 // r9 = loop start
|
||||||
@@ -389,7 +396,6 @@ FX_end:
|
|||||||
|
|
||||||
.balign 4
|
.balign 4
|
||||||
|
|
||||||
// Pointer to list of pointers to cheat codes. Last pointer should be nullptr to terminate the list.
|
|
||||||
.global cheatengine_cheatsPtr
|
.global cheatengine_cheatsPtr
|
||||||
cheatengine_cheatsPtr:
|
cheatengine_cheatsPtr:
|
||||||
.word 0
|
.word 0
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
/// @brief The Pico Loader API version supported by this header file.
|
/// @brief The Pico Loader API version supported by this header file.
|
||||||
#define PICO_LOADER_API_VERSION 2
|
#define PICO_LOADER_API_VERSION 3
|
||||||
|
|
||||||
/// @brief Enum to specify the drive to boot from.
|
/// @brief Enum to specify the drive to boot from.
|
||||||
typedef enum
|
typedef enum
|
||||||
@@ -43,6 +43,46 @@ typedef struct
|
|||||||
char launcherPath[256];
|
char launcherPath[256];
|
||||||
} pload_header7_v2_t;
|
} pload_header7_v2_t;
|
||||||
|
|
||||||
|
/// @brief Struct representing a single Action Replay cheat opcode.
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
/// @brief The first part of the opcode.
|
||||||
|
u32 a;
|
||||||
|
|
||||||
|
/// @brief The second part of the opcode.
|
||||||
|
u32 b;
|
||||||
|
} pload_cheat_opcode_t;
|
||||||
|
|
||||||
|
/// @brief Struct representing a single Action Replay cheat.
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
/// @brief Length of \see opcodes in bytes.
|
||||||
|
u32 length;
|
||||||
|
|
||||||
|
/// @brief The cheat opcodes.
|
||||||
|
pload_cheat_opcode_t opcodes[1];
|
||||||
|
} pload_cheat_t;
|
||||||
|
|
||||||
|
/// @brief Struct representing one or more cheats. Cheats are adjacent starting from the firstCheat field.
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
/// @brief Length of this stucture (length field + numberOfCheats field + all cheats).
|
||||||
|
u32 length;
|
||||||
|
|
||||||
|
/// @brief The number of cheats.
|
||||||
|
u32 numberOfCheats;
|
||||||
|
|
||||||
|
/// @brief The first cheat.
|
||||||
|
pload_cheat_t firstCheat;
|
||||||
|
} pload_cheats_t;
|
||||||
|
|
||||||
|
/// @brief Struct representing the API version 3 part of the header of picoLoader7.bin.
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
/// @brief Pointer to the cheats, or \c nullptr when there are no cheats.
|
||||||
|
const pload_cheats_t* cheats;
|
||||||
|
} pload_header7_v3_t;
|
||||||
|
|
||||||
/// @brief Struct representing the header of picoLoader7.bin.
|
/// @brief Struct representing the header of picoLoader7.bin.
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
@@ -63,4 +103,7 @@ typedef struct
|
|||||||
|
|
||||||
/// @brief The API version 2 part of the header. Only access this when \see apiVersion >= 2.
|
/// @brief The API version 2 part of the header. Only access this when \see apiVersion >= 2.
|
||||||
pload_header7_v2_t v2;
|
pload_header7_v2_t v2;
|
||||||
|
|
||||||
|
/// @brief The API version 3 part of the header. Only access this when \see apiVersion >= 3.
|
||||||
|
pload_header7_v3_t v3;
|
||||||
} pload_header7_t;
|
} pload_header7_t;
|
||||||
|
|||||||
Reference in New Issue
Block a user