Add system for adjusting addresses for autoload (#118) Fixes #41

This commit is contained in:
Mow
2026-01-31 14:54:37 -05:00
committed by GitHub
parent d07516a50d
commit f5a8498e08
8 changed files with 197 additions and 47 deletions

View File

@@ -1,6 +1,7 @@
#pragma once
#include <memory>
#include "SdkVersion.h"
#include "AutoloadAdjuster.h"
#include "PatchHeap.h"
#include "PatchCodeCollection.h"
@@ -10,9 +11,11 @@ class LoaderPlatform;
class PatchContext
{
public:
PatchContext(void* data, u32 dataSize, void* twlData, u32 twlDataSize,
PatchContext(void* data, u32 dataSize, std::unique_ptr<IAutoloadAdjuster> autoloadAdjuster,
void* twlData, u32 twlDataSize, std::unique_ptr<IAutoloadAdjuster> twlAutoloadAdjuster,
SdkVersion sdkVersion, u32 gameCode, u8 gameRevision, const LoaderPlatform* loaderPlatform)
: _data(data), _dataSize(dataSize), _twlData(twlData), _twlDataSize(twlDataSize)
: _data(data), _dataSize(dataSize), _autoloadAdjuster(std::move(autoloadAdjuster))
, _twlData(twlData), _twlDataSize(twlDataSize), _twlAutoloadAdjuster(std::move(twlAutoloadAdjuster))
, _sdkVersion(sdkVersion), _gameCode(gameCode), _gameRevision(gameRevision), _loaderPlatform(loaderPlatform) { }
/// @brief Tries to find the given \p pattern of the given \p byteLength in the ntr region.
@@ -27,6 +30,14 @@ public:
/// @return A pointer to the first location where the pattern was found, or \c nullptr if the pattern was not found.
u32* FindPattern32Twl(const u32* pattern, u32 byteLength) const;
/// @brief Returns the ntr autoload adjuster of this context.
/// @return The ntr autoload adjuster of this context.
constexpr const IAutoloadAdjuster* GetAutoloadAdjuster() const { return _autoloadAdjuster.get(); }
/// @brief Returns the twl autoload adjuster of this context.
/// @return The twl autoload adjuster of this context.
constexpr const IAutoloadAdjuster* GetAutoloadAdjusterTwl() const { return _twlAutoloadAdjuster.get(); }
/// @brief Returns the patch heap of this context.
/// @return The patch heap of this context.
constexpr PatchHeap& GetPatchHeap() { return _patchHeap; }
@@ -54,8 +65,10 @@ public:
private:
void* _data;
u32 _dataSize;
std::unique_ptr<IAutoloadAdjuster> _autoloadAdjuster;
void* _twlData;
u32 _twlDataSize;
std::unique_ptr<IAutoloadAdjuster> _twlAutoloadAdjuster;
SdkVersion _sdkVersion;
u32 _gameCode;
u8 _gameRevision;

View File

@@ -63,29 +63,6 @@ static u32 getThumbBlAddress(const u32* instructionPointer)
return (u32)instructionPointer + 5 + ((int)((((blInstruction1 & 0x7FF) << 11) | (blInstruction2 & 0x7FF)) << 10) >> 9);
}
static u32 correctAddressForArm7iAutoLoad(u32 address)
{
auto romHeader = (const nds_header_twl_t*)TWL_SHARED_MEMORY->twlRomHeader;
auto arm7iModuleParams = (const module_params_twl_t*)(
romHeader->arm7LoadAddress + romHeader->arm7iModuleParamsAddress);
auto autoLoadListEntry = (autoload_list_entry_sdk5_t*)arm7iModuleParams->autoloadListStart;
u32 currentAddress = arm7iModuleParams->autoloadStart;
while (autoLoadListEntry != (autoload_list_entry_sdk5_t*)arm7iModuleParams->autoloadListEnd)
{
if (address >= currentAddress && address < currentAddress + autoLoadListEntry->size)
{
address -= currentAddress;
address += autoLoadListEntry->targetAddress;
break;
}
currentAddress += autoLoadListEntry->size;
autoLoadListEntry++;
}
return address;
}
void Sdk5DsiSdCardRedirectPatch::ApplyPatch(PatchContext& patchContext)
{
if (!_attachFunction)
@@ -101,7 +78,8 @@ void Sdk5DsiSdCardRedirectPatch::ApplyPatch(PatchContext& patchContext)
getDriveStructAddress = getArmBlAddress((u32*)((u8*)_attachFunction + _blToGetDriveStructOffset));
}
getDriveStructAddress = correctAddressForArm7iAutoLoad(getDriveStructAddress);
auto arm7iAutoload = patchContext.GetAutoloadAdjusterTwl();
getDriveStructAddress = arm7iAutoload->AdjustInitialToFinal(getDriveStructAddress);
auto sdRead = patchContext.GetLoaderPlatform()->CreateSdReadPatchCode(
patchContext.GetPatchCodeCollection(), patchContext.GetPatchHeap());

View File

@@ -169,6 +169,11 @@ 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;
@@ -193,7 +198,7 @@ void CardiTryReadCardDmaPatch::ApplyPatch(PatchContext& patchContext)
u32 cardiCommon;
u32 cardiOnReadCard;
u32 cardiSetCardDma;
u32 miiCardDmaCopy32;
u32 cardiSetCardDmaDmaCopyCallOffset;
u32 cardiOnReadCardOffset;
if (_foundPattern == sCARDiTryReadCardDmaPattern20029A7)
{
@@ -202,7 +207,7 @@ void CardiTryReadCardDmaPatch::ApplyPatch(PatchContext& patchContext)
cardiSetCardDma = getArmBlAddress((u32*)((u8*)_cardiTryReadCardDma + 0x124));
if (*(u32*)cardiOnReadCard == 0xE92D40F0u)
{
miiCardDmaCopy32 = getArmBlAddress((u32*)(cardiSetCardDma + 0x18));
cardiSetCardDmaDmaCopyCallOffset = 0x18;
cardiOnReadCardOffset = 0x40;
}
else
@@ -218,7 +223,7 @@ void CardiTryReadCardDmaPatch::ApplyPatch(PatchContext& patchContext)
cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x140);
cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x150);
cardiSetCardDma = getArmBlAddress((u32*)((u8*)_cardiTryReadCardDma + 0x130));
miiCardDmaCopy32 = getArmBlAddress((u32*)(cardiSetCardDma + 0x18));
cardiSetCardDmaDmaCopyCallOffset = 0x18;
cardiOnReadCardOffset = 0x40;
}
else if (_foundPattern == sCARDiTryReadCardDmaPattern)
@@ -226,7 +231,7 @@ void CardiTryReadCardDmaPatch::ApplyPatch(PatchContext& patchContext)
cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x148) + 4;
cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x158);
cardiSetCardDma = getArmBlAddress((u32*)((u8*)_cardiTryReadCardDma + 0x138));
miiCardDmaCopy32 = getArmBlAddress((u32*)(cardiSetCardDma + 0x18));
cardiSetCardDmaDmaCopyCallOffset = 0x18;
cardiOnReadCardOffset = 0x40;
}
else if (_foundPattern == sCARDiTryReadCardDmaPatternSdk3017530)
@@ -241,7 +246,7 @@ void CardiTryReadCardDmaPatch::ApplyPatch(PatchContext& patchContext)
{
cardiSetCardDma = getArmBlAddress((u32*)((u8*)_cardiTryReadCardDma + 0x14C));
}
miiCardDmaCopy32 = getArmBlAddress((u32*)(cardiSetCardDma + 0x18));
cardiSetCardDmaDmaCopyCallOffset = 0x18;
cardiOnReadCardOffset = 0x40;
}
else if (_foundPattern == sCARDiTryReadCardDmaPatternSdk3027530)
@@ -249,7 +254,7 @@ void CardiTryReadCardDmaPatch::ApplyPatch(PatchContext& patchContext)
cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x160) + 4;
cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x170);
cardiSetCardDma = getArmBlAddress((u32*)((u8*)_cardiTryReadCardDma + 0x14C));
miiCardDmaCopy32 = getArmBlAddress((u32*)(cardiSetCardDma + 0x18));
cardiSetCardDmaDmaCopyCallOffset = 0x18;
cardiOnReadCardOffset = 0x40;
}
else if (_foundPattern == sCARDiTryReadCardDmaPatternSdk4007532)
@@ -257,7 +262,7 @@ void CardiTryReadCardDmaPatch::ApplyPatch(PatchContext& patchContext)
cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x178) + 4;
cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x188);
cardiSetCardDma = getArmBlAddress((u32*)((u8*)_cardiTryReadCardDma + 0x16C));
miiCardDmaCopy32 = getArmBlAddress((u32*)(cardiSetCardDma + 0x1C));
cardiSetCardDmaDmaCopyCallOffset = 0x1C;
cardiOnReadCardOffset = 0x48;
}
else if (_foundPattern == sCARDiTryReadCardDmaPatternSdk4027539SpiritTracks)
@@ -265,7 +270,7 @@ void CardiTryReadCardDmaPatch::ApplyPatch(PatchContext& patchContext)
cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x180) + 4;
cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x190);
cardiSetCardDma = getArmBlAddress((u32*)((u8*)_cardiTryReadCardDma + 0x174));
miiCardDmaCopy32 = getArmBlAddress((u32*)(cardiSetCardDma + 0x1C));
cardiSetCardDmaDmaCopyCallOffset = 0x1C;
cardiOnReadCardOffset = 0x48;
}
else
@@ -275,7 +280,32 @@ void CardiTryReadCardDmaPatch::ApplyPatch(PatchContext& patchContext)
return;
}
u32 osDisableIrqMask = getArmBlAddress((u32*)(cardiOnReadCard + cardiOnReadCardOffset + 4));
// correct all addresses for autoload, if libcard is in an autoload block (New Super Mario Bros.)
auto autoloadAdjuster = patchContext.GetAutoloadAdjuster();
// CARDi_OnReadCard address is the final location, but we need its initial location to patch it now
if (autoloadAdjuster)
{
cardiOnReadCard = autoloadAdjuster->AdjustFinalToInitial(cardiOnReadCard);
}
// MIi_CardDmaCopy32 is relative, but we need its final location to call it later
u32 miiCardDmaCopy32CallLocation = cardiSetCardDma + cardiSetCardDmaDmaCopyCallOffset;
s32 miiCardDmaCopy32CallOffset = getArmBlOffset(*(u32*)miiCardDmaCopy32CallLocation);
if (autoloadAdjuster)
{
miiCardDmaCopy32CallLocation = autoloadAdjuster->AdjustInitialToFinal(miiCardDmaCopy32CallLocation);
}
u32 miiCardDmaCopy32 = miiCardDmaCopy32CallLocation + miiCardDmaCopy32CallOffset;
// same as above with OS_DisableIrqMask
u32 osDisableIrqMaskCallLocation = cardiOnReadCard + cardiOnReadCardOffset + 4;
s32 osDisableIrqMaskCallOffset = getArmBlOffset(*(u32*)osDisableIrqMaskCallLocation);
if (autoloadAdjuster)
{
osDisableIrqMaskCallLocation = autoloadAdjuster->AdjustInitialToFinal(osDisableIrqMaskCallLocation);
}
u32 osDisableIrqMask = osDisableIrqMaskCallLocation + osDisableIrqMaskCallOffset;
// patch CARDi_SetCardDma
auto sdReadDmaPatchCode = patchContext.GetLoaderPlatform()->CreateSdReadDmaPatchCode(