diff --git a/arm9/source/patches/arm7/sdk5/Sdk5DsiSdCardRedirectPatch.cpp b/arm9/source/patches/arm7/sdk5/Sdk5DsiSdCardRedirectPatch.cpp index a2634c8..c1aebe5 100644 --- a/arm9/source/patches/arm7/sdk5/Sdk5DsiSdCardRedirectPatch.cpp +++ b/arm9/source/patches/arm7/sdk5/Sdk5DsiSdCardRedirectPatch.cpp @@ -1,4 +1,5 @@ #include "common.h" +#include "ArmHelper.h" #include "sharedMemory.h" #include "ndsHeader.h" #include "moduleParams.h" @@ -12,11 +13,6 @@ static const u32 sAttachFunctionPatternThumb[] = { 0xB0FFB518u, 0xB0DFB0FFu, 0x4 #define BL_TO_GET_DRIVE_STRUCT_OFFSET (-0x20) #define BL_TO_GET_DRIVE_STRUCT_OFFSET_ALT 0x88 -static bool isArmUnconditionalBl(u32 armInstruction) -{ - return (armInstruction >> 24) == 0xEB; -} - bool Sdk5DsiSdCardRedirectPatch::FindPatchTarget(PatchContext& patchContext) { _attachFunction = patchContext.FindPattern32Twl(sAttachFunctionPattern, sizeof(sAttachFunctionPattern)); @@ -32,10 +28,10 @@ bool Sdk5DsiSdCardRedirectPatch::FindPatchTarget(PatchContext& patchContext) { LOG_DEBUG("Found FATFSi_sdmcRtfsAttach at %p\n", _attachFunction); _blToGetDriveStructOffset = BL_TO_GET_DRIVE_STRUCT_OFFSET; - if (!_thumb && !isArmUnconditionalBl(*(u32*)((u8*)_attachFunction + _blToGetDriveStructOffset))) + if (!_thumb && !ArmHelper::IsArmUnconditionalBl(*(u32*)((u8*)_attachFunction + _blToGetDriveStructOffset))) { _blToGetDriveStructOffset = BL_TO_GET_DRIVE_STRUCT_OFFSET_ALT; - if (!isArmUnconditionalBl(*(u32*)((u8*)_attachFunction + _blToGetDriveStructOffset))) + if (!ArmHelper::IsArmUnconditionalBl(*(u32*)((u8*)_attachFunction + _blToGetDriveStructOffset))) { LOG_WARNING("Unsupported arm7 version for SD redirection patches\n"); _attachFunction = nullptr; @@ -50,19 +46,6 @@ bool Sdk5DsiSdCardRedirectPatch::FindPatchTarget(PatchContext& patchContext) return _attachFunction != nullptr; } -static u32 getArmBlAddress(const u32* instructionPointer) -{ - u32 blInstruction = *instructionPointer; - return (u32)instructionPointer + 8 + ((int)((blInstruction & 0xFFFFFF) << 8) >> 6); -} - -static u32 getThumbBlAddress(const u32* instructionPointer) -{ - u32 blInstruction1 = ((u16*)instructionPointer)[0]; - u32 blInstruction2 = ((u16*)instructionPointer)[1]; - return (u32)instructionPointer + 5 + ((int)((((blInstruction1 & 0x7FF) << 11) | (blInstruction2 & 0x7FF)) << 10) >> 9); -} - void Sdk5DsiSdCardRedirectPatch::ApplyPatch(PatchContext& patchContext) { if (!_attachFunction) @@ -71,11 +54,11 @@ void Sdk5DsiSdCardRedirectPatch::ApplyPatch(PatchContext& patchContext) u32 getDriveStructAddress; if (_thumb) { - getDriveStructAddress = getThumbBlAddress((u32*)((u8*)_attachFunction + _blToGetDriveStructOffset)); + getDriveStructAddress = ArmHelper::GetThumbCallAddress((u32*)((u8*)_attachFunction + _blToGetDriveStructOffset)); } else { - getDriveStructAddress = getArmBlAddress((u32*)((u8*)_attachFunction + _blToGetDriveStructOffset)); + getDriveStructAddress = ArmHelper::GetArmCallAddress((u32*)((u8*)_attachFunction + _blToGetDriveStructOffset)); } auto arm7iAutoload = patchContext.GetAutoloadAdjusterTwl(); diff --git a/arm9/source/patches/arm9/LastWindowCrcPatch.cpp b/arm9/source/patches/arm9/LastWindowCrcPatch.cpp index ea16582..48c1ada 100644 --- a/arm9/source/patches/arm9/LastWindowCrcPatch.cpp +++ b/arm9/source/patches/arm9/LastWindowCrcPatch.cpp @@ -1,4 +1,5 @@ #include "common.h" +#include "ArmHelper.h" #include "patches/PatchContext.h" #include "LastWindowCrcPatchCode.h" #include "LastWindowCrcPatch.h" @@ -13,6 +14,6 @@ void LastWindowCrcPatch::ApplyPatch(PatchContext& patchContext) { auto patchCode = patchContext.GetPatchCodeCollection().AddUniquePatchCode(patchContext.GetPatchHeap()); u32 patchAddr = (u32)patchCode->GetLastWindowCrcFunction(); - *_getCrc16 = MakeBlxCall(patchAddr); + *_getCrc16 = ArmHelper::MakeArmCall((u32)_getCrc16, patchAddr); } diff --git a/arm9/source/patches/arm9/LastWindowCrcPatch.h b/arm9/source/patches/arm9/LastWindowCrcPatch.h index 2444ede..14db117 100644 --- a/arm9/source/patches/arm9/LastWindowCrcPatch.h +++ b/arm9/source/patches/arm9/LastWindowCrcPatch.h @@ -32,9 +32,4 @@ public: private: u32* _getCrc16 = nullptr; - - u32 MakeBlxCall(u32 patchAddr) const - { - return 0xFA000000 | (((patchAddr - (u32)_getCrc16 - 8) >> 2) & 0xFFFFFF); - } }; diff --git a/arm9/source/patches/arm9/sdk2to4/CardiTryReadCardDmaPatch.cpp b/arm9/source/patches/arm9/sdk2to4/CardiTryReadCardDmaPatch.cpp index 5619d6d..d31cbb7 100644 --- a/arm9/source/patches/arm9/sdk2to4/CardiTryReadCardDmaPatch.cpp +++ b/arm9/source/patches/arm9/sdk2to4/CardiTryReadCardDmaPatch.cpp @@ -1,4 +1,5 @@ #include "common.h" +#include "ArmHelper.h" #include "patches/PatchContext.h" #include "thumbInstructions.h" #include "CardiSetCardDmaPatchCode.h" @@ -169,17 +170,6 @@ bool CardiTryReadCardDmaPatch::FindPatchTarget(PatchContext& patchContext) return true; //_cardiTryReadCardDma != nullptr; } -static s32 getArmBlOffset(u32 blInstruction) -{ - return 8 + ((int)((blInstruction & 0xFFFFFF) << 8) >> 6); -} - -static u32 getArmBlAddress(const u32* instructionPointer) -{ - u32 blInstruction = *instructionPointer; - return (u32)instructionPointer + 8 + ((int)((blInstruction & 0xFFFFFF) << 8) >> 6) + ((blInstruction >> 24) == 0xFA ? 1 : 0); -} - void CardiTryReadCardDmaPatch::ApplyPatch(PatchContext& patchContext) { if (!_cardiTryReadCardDma) @@ -204,7 +194,7 @@ void CardiTryReadCardDmaPatch::ApplyPatch(PatchContext& patchContext) { cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x134); cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x144); - cardiSetCardDma = getArmBlAddress((u32*)((u8*)_cardiTryReadCardDma + 0x124)); + cardiSetCardDma = ArmHelper::GetArmCallAddress((u32*)((u8*)_cardiTryReadCardDma + 0x124)); if (*(u32*)cardiOnReadCard == 0xE92D40F0u) { cardiSetCardDmaDmaCopyCallOffset = 0x18; @@ -222,7 +212,7 @@ void CardiTryReadCardDmaPatch::ApplyPatch(PatchContext& patchContext) { cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x140); cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x150); - cardiSetCardDma = getArmBlAddress((u32*)((u8*)_cardiTryReadCardDma + 0x130)); + cardiSetCardDma = ArmHelper::GetArmCallAddress((u32*)((u8*)_cardiTryReadCardDma + 0x130)); cardiSetCardDmaDmaCopyCallOffset = 0x18; cardiOnReadCardOffset = 0x40; } @@ -230,7 +220,7 @@ void CardiTryReadCardDmaPatch::ApplyPatch(PatchContext& patchContext) { cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x148) + 4; cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x158); - cardiSetCardDma = getArmBlAddress((u32*)((u8*)_cardiTryReadCardDma + 0x138)); + cardiSetCardDma = ArmHelper::GetArmCallAddress((u32*)((u8*)_cardiTryReadCardDma + 0x138)); cardiSetCardDmaDmaCopyCallOffset = 0x18; cardiOnReadCardOffset = 0x40; } @@ -240,11 +230,11 @@ void CardiTryReadCardDmaPatch::ApplyPatch(PatchContext& patchContext) cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x16C); if (*(u32*)((u8*)_cardiTryReadCardDma + 0x158) == 0xE12FFF1E) { - cardiSetCardDma = getArmBlAddress((u32*)((u8*)_cardiTryReadCardDma + 0x148)); + cardiSetCardDma = ArmHelper::GetArmCallAddress((u32*)((u8*)_cardiTryReadCardDma + 0x148)); } else { - cardiSetCardDma = getArmBlAddress((u32*)((u8*)_cardiTryReadCardDma + 0x14C)); + cardiSetCardDma = ArmHelper::GetArmCallAddress((u32*)((u8*)_cardiTryReadCardDma + 0x14C)); } cardiSetCardDmaDmaCopyCallOffset = 0x18; cardiOnReadCardOffset = 0x40; @@ -253,7 +243,7 @@ void CardiTryReadCardDmaPatch::ApplyPatch(PatchContext& patchContext) { cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x160) + 4; cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x170); - cardiSetCardDma = getArmBlAddress((u32*)((u8*)_cardiTryReadCardDma + 0x14C)); + cardiSetCardDma = ArmHelper::GetArmCallAddress((u32*)((u8*)_cardiTryReadCardDma + 0x14C)); cardiSetCardDmaDmaCopyCallOffset = 0x18; cardiOnReadCardOffset = 0x40; } @@ -261,7 +251,7 @@ void CardiTryReadCardDmaPatch::ApplyPatch(PatchContext& patchContext) { cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x178) + 4; cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x188); - cardiSetCardDma = getArmBlAddress((u32*)((u8*)_cardiTryReadCardDma + 0x16C)); + cardiSetCardDma = ArmHelper::GetArmCallAddress((u32*)((u8*)_cardiTryReadCardDma + 0x16C)); cardiSetCardDmaDmaCopyCallOffset = 0x1C; cardiOnReadCardOffset = 0x48; } @@ -269,7 +259,7 @@ void CardiTryReadCardDmaPatch::ApplyPatch(PatchContext& patchContext) { cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x180) + 4; cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x190); - cardiSetCardDma = getArmBlAddress((u32*)((u8*)_cardiTryReadCardDma + 0x174)); + cardiSetCardDma = ArmHelper::GetArmCallAddress((u32*)((u8*)_cardiTryReadCardDma + 0x174)); cardiSetCardDmaDmaCopyCallOffset = 0x1C; cardiOnReadCardOffset = 0x48; } @@ -291,7 +281,7 @@ void CardiTryReadCardDmaPatch::ApplyPatch(PatchContext& patchContext) // MIi_CardDmaCopy32 is relative, but we need its final location to call it later u32 miiCardDmaCopy32CallLocation = cardiSetCardDma + cardiSetCardDmaDmaCopyCallOffset; - s32 miiCardDmaCopy32CallOffset = getArmBlOffset(*(u32*)miiCardDmaCopy32CallLocation); + s32 miiCardDmaCopy32CallOffset = ArmHelper::GetArmCallOffset(*(u32*)miiCardDmaCopy32CallLocation); if (autoloadAdjuster) { miiCardDmaCopy32CallLocation = autoloadAdjuster->AdjustInitialToFinal(miiCardDmaCopy32CallLocation); @@ -300,7 +290,7 @@ void CardiTryReadCardDmaPatch::ApplyPatch(PatchContext& patchContext) // same as above with OS_DisableIrqMask u32 osDisableIrqMaskCallLocation = cardiOnReadCard + cardiOnReadCardOffset + 4; - s32 osDisableIrqMaskCallOffset = getArmBlOffset(*(u32*)osDisableIrqMaskCallLocation); + s32 osDisableIrqMaskCallOffset = ArmHelper::GetArmCallOffset(*(u32*)osDisableIrqMaskCallLocation); if (autoloadAdjuster) { osDisableIrqMaskCallLocation = autoloadAdjuster->AdjustInitialToFinal(osDisableIrqMaskCallLocation); diff --git a/common/ArmHelper.h b/common/ArmHelper.h new file mode 100644 index 0000000..1012f09 --- /dev/null +++ b/common/ArmHelper.h @@ -0,0 +1,63 @@ +#pragma once + +/// @brief Class containing helper functions for manipulating ARM or Thumb assembly. +class ArmHelper +{ +public: + ArmHelper() = delete; + + /// @brief Check if an ARM instruction is an unconditional bl call. + /// @param instruction The ARM instruction to check. + /// @return True if the instruction is an unconditional bl call, false otherwise. + static bool IsArmUnconditionalBl(u32 instruction) + { + return (instruction >> 24) == 0xEB; + } + + /// @brief Get the offset of an ARM call (bl or blx). + /// @param callInstruction The ARM call instruction. + /// @return The offset to the destination function. +1 if Thumb. + static s32 GetArmCallOffset(u32 callInstruction) + { + return 8 + ((int)((callInstruction & 0xFFFFFF) << 8) >> 6) + + ((callInstruction >> 24) == 0xFA ? 1 : 0); + } + + /// @brief Get the address of the callee in an ARM call (bl or blx). + /// @param instructionPointer Pointer to the ARM call instruction. + /// @return The address of the function being called. +1 if Thumb. + static u32 GetArmCallAddress(const void* instructionPointer) + { + auto pc = (const u32*)((u32)instructionPointer & ~3); + return (u32)pc + GetArmCallOffset(*pc); + } + + /// @brief Create an ARM call instruction (bl or blx). + /// @param instructionAddress The address where the instruction is to be placed. + /// @param targetAddress The address of the function to call. +1 if Thumb. + /// @return The ARM call instruction to call the target. + static u32 MakeArmCall(u32 instructionAddress, u32 targetAddress) + { + u32 offset = targetAddress - instructionAddress - 8; + return ((targetAddress & 1) ? 0xFA000000 : 0xEB000000) | ((offset >> 2) & 0xFFFFFF); + } + + /// @brief Get the offset of a Thumb call (bl or blx). + /// @param callInstruction1 The first Thumb call instruction. + /// @param callInstruction2 The second Thumb call instruction. + /// @return The offset to the destination function. +1 if Thumb. + static s32 GetThumbCallOffset(u16 callInstruction1, u16 callInstruction2) + { + return 4 + ((int)((((callInstruction1 & 0x7FF) << 11) | (callInstruction2 & 0x7FF)) << 10) >> 9) + + ((callInstruction2 >> 11) == 0x1F ? 1 : 0); + } + + /// @brief Get the address of the callee in an Thumb call (bl or blx). + /// @param instructionPointer Pointer to the first Thumb call instruction. + /// @return The offset to the destination function. +1 if Thumb. + static u32 GetThumbCallAddress(const void* instructionPointer) + { + auto pc = (const u16*)((u32)instructionPointer & ~1); + return (u32)pc + GetThumbCallOffset(pc[0], pc[1]); + } +};