From a424b252637fab772ddcdc6a8405247fbaecff35 Mon Sep 17 00:00:00 2001 From: TY <47445484+R-YaTian@users.noreply.github.com> Date: Sun, 4 Jan 2026 23:13:24 +0800 Subject: [PATCH 1/7] Impl `HandleiQueRegionFreePatching` to bypass region locking on certain iQue games (#83) --- arm7/source/loader/NdsLoader.cpp | 10 ++++++++++ arm7/source/loader/NdsLoader.h | 1 + 2 files changed, 11 insertions(+) diff --git a/arm7/source/loader/NdsLoader.cpp b/arm7/source/loader/NdsLoader.cpp index 7709061..ae13753 100644 --- a/arm7/source/loader/NdsLoader.cpp +++ b/arm7/source/loader/NdsLoader.cpp @@ -220,6 +220,7 @@ void NdsLoader::Load(BootMode bootMode) if (bootMode == BootMode::Normal) { bootType = _romHeader.IsDsiWare() ? BOOT_TYPE_NAND : BOOT_TYPE_CARD; + HandleIQueRegionFreePatching(); } else if (bootMode == BootMode::Multiboot) { @@ -1013,6 +1014,15 @@ bool NdsLoader::TryDecryptSecureArea() return true; } +void NdsLoader::HandleIQueRegionFreePatching() +{ + if ((_romHeader.flags & 0x80) == 0x80) + { + _romHeader.flags &= ~0x80; + _romHeader.headerCrc = swi_getCrc16(0xFFFF, (void*)&_romHeader, 0x15E); + } +} + ConsoleRegion NdsLoader::GetRomRegion(u32 gameCode) { u8 gameRegionCode = (gameCode >> 24) & 0xFF; diff --git a/arm7/source/loader/NdsLoader.h b/arm7/source/loader/NdsLoader.h index 14bd17a..663cc52 100644 --- a/arm7/source/loader/NdsLoader.h +++ b/arm7/source/loader/NdsLoader.h @@ -73,6 +73,7 @@ private: void InsertArgv(); bool TrySetupDsiWareSave(); bool TryDecryptSecureArea(); + void HandleIQueRegionFreePatching(); ConsoleRegion GetRomRegion(u32 gameCode); UserLanguage GetLanguageByRomRegion(ConsoleRegion romRegion); u32 GetSupportedLanguagesByRegion(ConsoleRegion region); From ef50e60ff9e81439d9506e1d29c6ad64733321bb Mon Sep 17 00:00:00 2001 From: TY <47445484+R-YaTian@users.noreply.github.com> Date: Tue, 6 Jan 2026 14:36:35 +0800 Subject: [PATCH 2/7] Set MBK9 settings from rom header after Arm7 Patching finish (#88) --- arm7/source/loader/NdsLoader.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arm7/source/loader/NdsLoader.cpp b/arm7/source/loader/NdsLoader.cpp index ae13753..021a175 100644 --- a/arm7/source/loader/NdsLoader.cpp +++ b/arm7/source/loader/NdsLoader.cpp @@ -297,6 +297,9 @@ void NdsLoader::Load(BootMode bootMode) { SetupDsiDeviceList(); + // Set twl wram locking (REG_MBK9) settings from rom header + REG_MBK9 = _romHeader.mbk9Setting[0] | (_romHeader.mbk9Setting[1] << 8) | (_romHeader.mbk9Setting[2] << 16); + u32 scfgExt7 = 0x93FBFB00 | (_romHeader.arm7ScfgExt7 & 0x40407); REG_SCFG_EXT = scfgExt7; REG_SCFG_CLK = 0x187; From fd08fd19a184998617c0d4eab9b364ba5cc08953 Mon Sep 17 00:00:00 2001 From: Mow <32942550+taxicat1@users.noreply.github.com> Date: Fri, 9 Jan 2026 09:39:23 -0500 Subject: [PATCH 3/7] Handle BLX branches in CardiTryReadCardDmaPatch (#91) --- arm9/source/patches/arm9/sdk2to4/CardiTryReadCardDmaPatch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arm9/source/patches/arm9/sdk2to4/CardiTryReadCardDmaPatch.cpp b/arm9/source/patches/arm9/sdk2to4/CardiTryReadCardDmaPatch.cpp index b7a4a60..d5977d9 100644 --- a/arm9/source/patches/arm9/sdk2to4/CardiTryReadCardDmaPatch.cpp +++ b/arm9/source/patches/arm9/sdk2to4/CardiTryReadCardDmaPatch.cpp @@ -167,7 +167,7 @@ bool CardiTryReadCardDmaPatch::FindPatchTarget(PatchContext& patchContext) static u32 getArmBlAddress(const u32* instructionPointer) { u32 blInstruction = *instructionPointer; - return (u32)instructionPointer + 8 + ((int)((blInstruction & 0xFFFFFF) << 8) >> 6); + return (u32)instructionPointer + 8 + ((int)((blInstruction & 0xFFFFFF) << 8) >> 6) + ((blInstruction >> 24) == 0xFA ? 1 : 0); } void CardiTryReadCardDmaPatch::ApplyPatch(PatchContext& patchContext) From 9f2dff39677a3a5b746af63621fe3efe6376c854 Mon Sep 17 00:00:00 2001 From: Mow <32942550+taxicat1@users.noreply.github.com> Date: Sat, 10 Jan 2026 05:05:14 -0500 Subject: [PATCH 4/7] Fix sCARDiTryReadCardDmaPatternSdk3017530 matching multiple card DMA variants (#93) Fixes - Unou no Tatsujin - Soukai! Machigai Museum 2 (Japan) - Trioncube (Europe) (En,Fr,De,Es,It) - Tetris DS (Korea) - Original Frisbee Disc Sports - Ultimate & Golf (USA) - LifeSigns - Surgical Unit (USA) --- .../patches/arm9/sdk2to4/CardiTryReadCardDmaPatch.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/arm9/source/patches/arm9/sdk2to4/CardiTryReadCardDmaPatch.cpp b/arm9/source/patches/arm9/sdk2to4/CardiTryReadCardDmaPatch.cpp index d5977d9..15502ba 100644 --- a/arm9/source/patches/arm9/sdk2to4/CardiTryReadCardDmaPatch.cpp +++ b/arm9/source/patches/arm9/sdk2to4/CardiTryReadCardDmaPatch.cpp @@ -228,7 +228,14 @@ void CardiTryReadCardDmaPatch::ApplyPatch(PatchContext& patchContext) { cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x15C) + 4; cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x16C); - cardiSetCardDma = getArmBlAddress((u32*)((u8*)_cardiTryReadCardDma + 0x148)); + if (*(u32*)((u8*)_cardiTryReadCardDma + 0x158) == 0xE12FFF1E) + { + cardiSetCardDma = getArmBlAddress((u32*)((u8*)_cardiTryReadCardDma + 0x148)); + } + else + { + cardiSetCardDma = getArmBlAddress((u32*)((u8*)_cardiTryReadCardDma + 0x14C)); + } miiCardDmaCopy32 = getArmBlAddress((u32*)(cardiSetCardDma + 0x18)); cardiOnReadCardOffset = 0x40; } From cd007d650588dd6545de6f2bd44c21f123de2a1d Mon Sep 17 00:00:00 2001 From: Gericom Date: Sat, 10 Jan 2026 11:52:23 +0100 Subject: [PATCH 5/7] Account for spurious CARDi_ReadCard match in Shaberu! DS Oryouri Navi (Japan) (rev 0 and 1) --- arm9/source/Arm7Patcher.cpp | 1 + arm9/source/Arm9Patcher.cpp | 1 + arm9/source/patches/PatchContext.h | 9 +- .../arm9/sdk2to4/CardiReadCardPatch.cpp | 87 +++++++++++-------- 4 files changed, 58 insertions(+), 40 deletions(-) diff --git a/arm9/source/Arm7Patcher.cpp b/arm9/source/Arm7Patcher.cpp index 9acfca1..43ba649 100644 --- a/arm9/source/Arm7Patcher.cpp +++ b/arm9/source/Arm7Patcher.cpp @@ -39,6 +39,7 @@ void* Arm7Patcher::ApplyPatches(const LoaderPlatform* loaderPlatform) const (romHeader->IsTwlRom()) ? twlRomHeader->arm7iSize : 0, sdkVersion, romHeader->gameCode, + romHeader->softwareVersion, loaderPlatform }; void* patchSpaceStart = nullptr; diff --git a/arm9/source/Arm9Patcher.cpp b/arm9/source/Arm9Patcher.cpp index 9c54189..3ff9dfc 100644 --- a/arm9/source/Arm9Patcher.cpp +++ b/arm9/source/Arm9Patcher.cpp @@ -116,6 +116,7 @@ void Arm9Patcher::ApplyPatches(const LoaderPlatform* loaderPlatform, const ApLis arm9iSize, sdkVersion, romHeader->gameCode, + romHeader->softwareVersion, loaderPlatform }; PatchCollection patchCollection; diff --git a/arm9/source/patches/PatchContext.h b/arm9/source/patches/PatchContext.h index 6e84766..2aad29c 100644 --- a/arm9/source/patches/PatchContext.h +++ b/arm9/source/patches/PatchContext.h @@ -11,9 +11,9 @@ class PatchContext { public: PatchContext(void* data, u32 dataSize, void* twlData, u32 twlDataSize, - SdkVersion sdkVersion, u32 gameCode, const LoaderPlatform* loaderPlatform) + SdkVersion sdkVersion, u32 gameCode, u8 gameRevision, const LoaderPlatform* loaderPlatform) : _data(data), _dataSize(dataSize), _twlData(twlData), _twlDataSize(twlDataSize) - , _sdkVersion(sdkVersion), _gameCode(gameCode), _loaderPlatform(loaderPlatform) { } + , _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. /// @param pattern The pattern to find. @@ -43,6 +43,10 @@ public: /// @return The game code of the rom that is being patched. constexpr u32 GetGameCode() const { return _gameCode; } + /// @brief Returns the game revision of the rom that is being patched. + /// @return The game revision of the rom that is being patched. + constexpr u8 GetGameRevision() const { return _gameRevision; } + /// @brief Returns the loader platform that should be used for the patches. /// @return The loader platform that should be used for the patches. constexpr const LoaderPlatform* GetLoaderPlatform() { return _loaderPlatform; } @@ -54,6 +58,7 @@ private: u32 _twlDataSize; SdkVersion _sdkVersion; u32 _gameCode; + u8 _gameRevision; PatchHeap _patchHeap; PatchCodeCollection _patchCodeCollection; diff --git a/arm9/source/patches/arm9/sdk2to4/CardiReadCardPatch.cpp b/arm9/source/patches/arm9/sdk2to4/CardiReadCardPatch.cpp index 1fb22b7..3f3c215 100644 --- a/arm9/source/patches/arm9/sdk2to4/CardiReadCardPatch.cpp +++ b/arm9/source/patches/arm9/sdk2to4/CardiReadCardPatch.cpp @@ -6,6 +6,7 @@ #include "patches/arm9/RomOffsetToSdSectorPatchCode.h" #include "patches/OffsetToSectorRemapPatchCode.h" #include "patches/arm9/FixCp15Asm.h" +#include "gameCode.h" #include "CardiReadCardPatchAsm.h" #include "CardiReadCardPatch.h" @@ -30,59 +31,69 @@ void CardiReadCardPatch::TryPattern(PatchContext& patchContext, const u32* patte bool CardiReadCardPatch::FindPatchTarget(PatchContext& patchContext) { - if (patchContext.GetSdkVersion() >= 0x4017530) - TryPattern(patchContext, sCARDiReadCardPatternSdk4017530, sizeof(sCARDiReadCardPatternSdk4017530)); - else if (patchContext.GetSdkVersion() >= 0x4002774) - TryPattern(patchContext, sCARDiReadCardPatternSdk4002774, sizeof(sCARDiReadCardPatternSdk4002774)); + if (patchContext.GetGameCode() == GAMECODE("A4VJ")) + { + // Shaberu! DS Oryouri Navi (Japan) has a spurious match + _foundPattern = sCARDiReadCardPatternUnknown; + _thumb = false; + _cardiReadCard = (u32*)(patchContext.GetGameRevision() == 0 ? 0x020DBD5C : 0x020DBD4C); + } else - TryPattern(patchContext, sCARDiReadCardPatternSdk20029A7, sizeof(sCARDiReadCardPatternSdk20029A7)); - - if (!_cardiReadCard) { if (patchContext.GetSdkVersion() >= 0x4017530) - TryPattern(patchContext, sCARDiReadCardPatternSdk4017530Thumb, sizeof(sCARDiReadCardPatternSdk4017530Thumb)); - else if (patchContext.GetSdkVersion() >= 0x3027530) - TryPattern(patchContext, sCARDiReadCardPatternSdk3027530Thumb, sizeof(sCARDiReadCardPatternSdk3027530Thumb)); - else if (patchContext.GetSdkVersion() >= 0x2004F4C) - TryPattern(patchContext, sCARDiReadCardPatternSdk2004F4CThumb, sizeof(sCARDiReadCardPatternSdk2004F4CThumb)); - - if (_cardiReadCard) - _thumb = true; - } - - if (!_cardiReadCard) - { - // if still nothing found try some of the patterns that appear all over the place - TryPattern(patchContext, sCARDiReadCardPatternUnknown, sizeof(sCARDiReadCardPatternUnknown)); - if (!_cardiReadCard) + TryPattern(patchContext, sCARDiReadCardPatternSdk4017530, sizeof(sCARDiReadCardPatternSdk4017530)); + else if (patchContext.GetSdkVersion() >= 0x4002774) TryPattern(patchContext, sCARDiReadCardPatternSdk4002774, sizeof(sCARDiReadCardPatternSdk4002774)); - if (!_cardiReadCard) + else TryPattern(patchContext, sCARDiReadCardPatternSdk20029A7, sizeof(sCARDiReadCardPatternSdk20029A7)); - if (patchContext.GetSdkVersion().GetMajor() >= SDK_VERSION_MAJOR_NITRO_4) + + if (!_cardiReadCard) { - if (!_cardiReadCard) - TryPattern(patchContext, sCARDiReadCardPatternSdk4027539SpiritTracks, sizeof(sCARDiReadCardPatternSdk4027539SpiritTracks)); + if (patchContext.GetSdkVersion() >= 0x4017530) + TryPattern(patchContext, sCARDiReadCardPatternSdk4017530Thumb, sizeof(sCARDiReadCardPatternSdk4017530Thumb)); + else if (patchContext.GetSdkVersion() >= 0x3027530) + TryPattern(patchContext, sCARDiReadCardPatternSdk3027530Thumb, sizeof(sCARDiReadCardPatternSdk3027530Thumb)); + else if (patchContext.GetSdkVersion() >= 0x2004F4C) + TryPattern(patchContext, sCARDiReadCardPatternSdk2004F4CThumb, sizeof(sCARDiReadCardPatternSdk2004F4CThumb)); + + if (_cardiReadCard) + _thumb = true; } - if (patchContext.GetSdkVersion().GetMajor() <= SDK_VERSION_MAJOR_NITRO_2) + if (!_cardiReadCard) { + // if still nothing found try some of the patterns that appear all over the place + TryPattern(patchContext, sCARDiReadCardPatternUnknown, sizeof(sCARDiReadCardPatternUnknown)); if (!_cardiReadCard) - TryPattern(patchContext, sCARDiReadCardPatternSdk2004F4DDebug, sizeof(sCARDiReadCardPatternSdk2004F4DDebug)); + TryPattern(patchContext, sCARDiReadCardPatternSdk4002774, sizeof(sCARDiReadCardPatternSdk4002774)); if (!_cardiReadCard) - TryPattern(patchContext, sCARDiReadCardPatternSdk2004E8BPingPals, sizeof(sCARDiReadCardPatternSdk2004E8BPingPals)); + TryPattern(patchContext, sCARDiReadCardPatternSdk20029A7, sizeof(sCARDiReadCardPatternSdk20029A7)); + if (patchContext.GetSdkVersion().GetMajor() >= SDK_VERSION_MAJOR_NITRO_4) + { + if (!_cardiReadCard) + TryPattern(patchContext, sCARDiReadCardPatternSdk4027539SpiritTracks, sizeof(sCARDiReadCardPatternSdk4027539SpiritTracks)); + } + + if (patchContext.GetSdkVersion().GetMajor() <= SDK_VERSION_MAJOR_NITRO_2) + { + if (!_cardiReadCard) + TryPattern(patchContext, sCARDiReadCardPatternSdk2004F4DDebug, sizeof(sCARDiReadCardPatternSdk2004F4DDebug)); + if (!_cardiReadCard) + TryPattern(patchContext, sCARDiReadCardPatternSdk2004E8BPingPals, sizeof(sCARDiReadCardPatternSdk2004E8BPingPals)); + } } - } - if (!_cardiReadCard) - { - TryPattern(patchContext, sCARDiReadCardPatternSdk2004F4CThumb, sizeof(sCARDiReadCardPatternSdk2004F4CThumb)); if (!_cardiReadCard) - TryPattern(patchContext, sCARDiReadCardPatternSdk3027530Thumb, sizeof(sCARDiReadCardPatternSdk3027530Thumb)); - if (!_cardiReadCard) - TryPattern(patchContext, sCARDiReadCardPatternSdk2027533ThumbChouSoujuu, sizeof(sCARDiReadCardPatternSdk2027533ThumbChouSoujuu)); + { + TryPattern(patchContext, sCARDiReadCardPatternSdk2004F4CThumb, sizeof(sCARDiReadCardPatternSdk2004F4CThumb)); + if (!_cardiReadCard) + TryPattern(patchContext, sCARDiReadCardPatternSdk3027530Thumb, sizeof(sCARDiReadCardPatternSdk3027530Thumb)); + if (!_cardiReadCard) + TryPattern(patchContext, sCARDiReadCardPatternSdk2027533ThumbChouSoujuu, sizeof(sCARDiReadCardPatternSdk2027533ThumbChouSoujuu)); - if (_cardiReadCard) - _thumb = true; + if (_cardiReadCard) + _thumb = true; + } } if (_cardiReadCard) From 1d18f06b4cd65d17a076543377f4d41516835c2b Mon Sep 17 00:00:00 2001 From: Gericom Date: Sat, 10 Jan 2026 14:04:30 +0100 Subject: [PATCH 6/7] =?UTF-8?q?Added=20support=20for=20SDK=20variant=20wit?= =?UTF-8?q?h=20a=20lot=20of=20inlining.=20Fixes=20#53.=20Fixes=20Tropix!?= =?UTF-8?q?=20...Your=20Island=20Getaway=20and=20Think=20-=20Training=20f?= =?UTF-8?q?=C3=BCr=20den=20Kopf=20-=20Kids=20-=20Spiel=20Dich=20Schlau!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../arm9/sdk2to4/CardiReadCardPatch.cpp | 33 +++++++++++++------ .../arm9/sdk2to4/CardiReadCardPatchAsm.s | 4 +-- .../arm9/sdk2to4/CardiTryReadCardDmaPatch.cpp | 5 +++ 3 files changed, 30 insertions(+), 12 deletions(-) diff --git a/arm9/source/patches/arm9/sdk2to4/CardiReadCardPatch.cpp b/arm9/source/patches/arm9/sdk2to4/CardiReadCardPatch.cpp index 3f3c215..783e084 100644 --- a/arm9/source/patches/arm9/sdk2to4/CardiReadCardPatch.cpp +++ b/arm9/source/patches/arm9/sdk2to4/CardiReadCardPatch.cpp @@ -20,6 +20,7 @@ static const u32 sCARDiReadCardPatternSdk3027530Thumb[] = { 0xB082B5F8u, 0x90019 static const u32 sCARDiReadCardPatternSdk4002774[] = { 0xE92D4070u, 0xE59F40D0u, 0xE1A06000u, 0xE3A00C02u }; static const u32 sCARDiReadCardPatternSdk4017530[] = { 0xE92D4070u, 0xE59F40D8u, 0xE1A06000u, 0xE3A00C02u }; static const u32 sCARDiReadCardPatternSdk4017530Thumb[] = { 0xB082B5F8u, 0x90019000u, 0x90013020u, 0x69C24827u }; +static const u32 sCARDiReadCardPatternSdk4027531ThumbInlined[] = { 0xB082B5F8u, 0x90019000u, 0x90013020u, 0x69C14841u }; static const u32 sCARDiReadCardPatternSdk4027539SpiritTracks[] = { 0xE92D4070u, 0xE59F40D4u, 0xE1A06000u, 0xE3A00C02u }; void CardiReadCardPatch::TryPattern(PatchContext& patchContext, const u32* pattern, u32 byteLength) @@ -90,6 +91,8 @@ bool CardiReadCardPatch::FindPatchTarget(PatchContext& patchContext) TryPattern(patchContext, sCARDiReadCardPatternSdk3027530Thumb, sizeof(sCARDiReadCardPatternSdk3027530Thumb)); if (!_cardiReadCard) TryPattern(patchContext, sCARDiReadCardPatternSdk2027533ThumbChouSoujuu, sizeof(sCARDiReadCardPatternSdk2027533ThumbChouSoujuu)); + if (!_cardiReadCard) + TryPattern(patchContext, sCARDiReadCardPatternSdk4027531ThumbInlined, sizeof(sCARDiReadCardPatternSdk4027531ThumbInlined)); if (_cardiReadCard) _thumb = true; @@ -153,42 +156,53 @@ void CardiReadCardPatch::ApplyPatch(PatchContext& patchContext) if (_thumb) { u32 patchOffset; - u32 cardiCommonOffset; if (_foundPattern == sCARDiReadCardPatternSdk4017530Thumb) { patchOffset = 0x36; - cardiCommonOffset = 0x74; patch_cardireadcard_return_offset = THUMB_MOVS_IMM(THUMB_R0, 0x3C); patch_cardireadcard_mov_src_to_r0 = THUMB_MOVS_REG(THUMB_R0, THUMB_R1); // src patch_cardireadcard_mov_dst_to_r1 = THUMB_MOVS_REG(THUMB_R1, THUMB_R4); // dst - patch_cardireadcard_mov_cardicommon_to_r6 = THUMB_LDR_SP_IMM(THUMB_R6, 0); + patch_cardireadcard_mov_cardicommon_to_r6 = THUMB_LDR_SP_IMM(THUMB_R6, 8); // r3 from the stack patch_cardireadcard_adjust_cardicommon_offset = THUMB_NOP; - patch_cardireadcard_mov_r3_to_dst = THUMB_STR_SP_IMM(THUMB_R3, 4); + patch_cardireadcard_mov_r3_to_dst = THUMB_STR_SP_IMM(THUMB_R3, 0xC); // copy to r4 on the stack + *(u16*)((u8*)_cardiReadCard + patchOffset + 0) = THUMB_LDR_PC_IMM(THUMB_R3, 0x74); // ldr r3,= cardi_common } else if (_foundPattern == sCARDiReadCardPatternSdk3027530Thumb) { patchOffset = 0x36; - cardiCommonOffset = 0x6C; patch_cardireadcard_return_offset = THUMB_MOVS_IMM(THUMB_R0, 0x36); patch_cardireadcard_mov_src_to_r0 = THUMB_MOVS_REG(THUMB_R0, THUMB_R1); // src patch_cardireadcard_mov_dst_to_r1 = THUMB_MOVS_REG(THUMB_R1, THUMB_R4); // dst - patch_cardireadcard_mov_cardicommon_to_r6 = THUMB_LDR_SP_IMM(THUMB_R6, 0); + patch_cardireadcard_mov_cardicommon_to_r6 = THUMB_LDR_SP_IMM(THUMB_R6, 8); // r3 from the stack patch_cardireadcard_adjust_cardicommon_offset = THUMB_NOP; - patch_cardireadcard_mov_r3_to_dst = THUMB_STR_SP_IMM(THUMB_R3, 4); + patch_cardireadcard_mov_r3_to_dst = THUMB_STR_SP_IMM(THUMB_R3, 0xC); // copy to r4 on the stack + *(u16*)((u8*)_cardiReadCard + patchOffset + 0) = THUMB_LDR_PC_IMM(THUMB_R3, 0x6C); // ldr r3,= cardi_common } else if (_foundPattern == sCARDiReadCardPatternSdk2004F4CThumb) { patchOffset = 0x36; - cardiCommonOffset = 0; patch_cardireadcard_return_offset = THUMB_MOVS_IMM(THUMB_R0, 0x2E); patch_cardireadcard_mov_src_to_r0 = THUMB_MOVS_REG(THUMB_R0, THUMB_R1); // src patch_cardireadcard_mov_dst_to_r1 = THUMB_MOVS_REG(THUMB_R1, THUMB_R5); // dst - patch_cardireadcard_mov_cardicommon_to_r6 = THUMB_LDR_SP_IMM(THUMB_R6, 8); // r6 from stack + patch_cardireadcard_mov_cardicommon_to_r6 = THUMB_LDR_SP_IMM(THUMB_R6, 0x10); // r6 from stack if (patchContext.GetSdkVersion().GetMajor() <= SDK_VERSION_MAJOR_NITRO_2) patch_cardireadcard_adjust_cardicommon_offset = THUMB_SUBS_IMM(THUMB_R6, THUMB_R6, 4); else patch_cardireadcard_adjust_cardicommon_offset = THUMB_NOP; patch_cardireadcard_mov_r3_to_dst = THUMB_MOVS_REG(THUMB_R5, THUMB_R3); + *(u16*)((u8*)_cardiReadCard + patchOffset + 0) = THUMB_NOP; + } + else if (_foundPattern == sCARDiReadCardPatternSdk4027531ThumbInlined) + { + // This variant has a lot of inlining + patchOffset = 0x36; + patch_cardireadcard_return_offset = THUMB_MOVS_IMM(THUMB_R0, 0x64); + patch_cardireadcard_mov_src_to_r0 = THUMB_LDR_SP_IMM(THUMB_R0, 8); // src, r3 from the stack + patch_cardireadcard_mov_dst_to_r1 = THUMB_LDR_SP_IMM(THUMB_R1, 4); // dst, r2 from the stack + patch_cardireadcard_mov_cardicommon_to_r6 = THUMB_LDR_SP_IMM(THUMB_R6, 0); // r1 from the stack + patch_cardireadcard_adjust_cardicommon_offset = THUMB_NOP; + patch_cardireadcard_mov_r3_to_dst = THUMB_STR_SP_IMM(THUMB_R3, 4); // copy to r2 on the stack + *(u16*)((u8*)_cardiReadCard + patchOffset + 0) = THUMB_LDR_PC_IMM(THUMB_R1, 0xDC); // ldr r1,= cardi_common } else { @@ -196,7 +210,6 @@ void CardiReadCardPatch::ApplyPatch(PatchContext& patchContext) while (1); } - *(u16*)((u8*)_cardiReadCard + patchOffset + 0) = cardiCommonOffset == 0 ? THUMB_NOP : THUMB_LDR_PC_IMM(THUMB_R3, cardiCommonOffset); // ldr r0,= cardi_common *(u16*)((u8*)_cardiReadCard + patchOffset + 2) = THUMB_LDR_PC_IMM(THUMB_R0, 0); // ldr r0,= entryAddress *(u16*)((u8*)_cardiReadCard + patchOffset + 4) = THUMB_BLX(THUMB_R0); *(u32*)((u8*)_cardiReadCard + patchOffset + 6) = entryAddress; diff --git a/arm9/source/patches/arm9/sdk2to4/CardiReadCardPatchAsm.s b/arm9/source/patches/arm9/sdk2to4/CardiReadCardPatchAsm.s index b344ceb..7e3a04e 100644 --- a/arm9/source/patches/arm9/sdk2to4/CardiReadCardPatchAsm.s +++ b/arm9/source/patches/arm9/sdk2to4/CardiReadCardPatchAsm.s @@ -11,7 +11,7 @@ patch_cardireadcard_entry: patch_cardireadcard_return_offset: movs r0, #0x38 add lr, r0 - push {r3,r4,r6,lr} + push {r1,r2,r3,r4,r6,lr} ldr r3, __patch_cardireadcard_fix_cp15_asm_address blx r3 .global patch_cardireadcard_mov_src_to_r0 @@ -59,7 +59,7 @@ patch_cardireadcard_mov_r3_to_dst: do_read: ldr r3, __patch_cardireadcard_sdread_asm_address blx r3 - pop {r3,r4,r6,pc} + pop {r1,r2,r3,r4,r6,pc} .balign 4 diff --git a/arm9/source/patches/arm9/sdk2to4/CardiTryReadCardDmaPatch.cpp b/arm9/source/patches/arm9/sdk2to4/CardiTryReadCardDmaPatch.cpp index 15502ba..eeb8840 100644 --- a/arm9/source/patches/arm9/sdk2to4/CardiTryReadCardDmaPatch.cpp +++ b/arm9/source/patches/arm9/sdk2to4/CardiTryReadCardDmaPatch.cpp @@ -36,6 +36,7 @@ static const u32 sCARDiTryReadCardDmaPatternSdkThumb[] = { 0xB084B5F8u, 0x483D90 static const u32 sCARDiTryReadCardDmaPatternSdk4007531Thumb[] = { 0xB084B5F8u, 0x483E9000u, 0x6A446A05u, 0x90032000u }; static const u32 sCARDiTryReadCardDmaPatternSdk4017530Thumb[] = { 0xB084B5F8u, 0x48479000u, 0x6A446A05u, 0x90032000u }; static const u32 sCARDiTryReadCardDmaPatternSdk4027530Thumb[] = { 0xB084B5F8u, 0x48479000u, 0x6A446A05u, 0x90032000u }; +static const u32 sCARDiTryReadCardDmaPatternSdk4027531ThumbInlined[] = { 0xB083B5F0u, 0x485D9000u, 0x6A062500u, 0x1C286A44u }; static const u16 sReturnFalsePatchThumb[] = { THUMB_MOVS_IMM(0, 0), THUMB_BX_LR }; static const u32 sReturnFalsePatchArm[] = { 0xE3A00000, 0xE12FFF1E }; // mov r0, #0; bx lr @@ -141,6 +142,10 @@ bool CardiTryReadCardDmaPatch::FindPatchTarget(PatchContext& patchContext) if (!_cardiTryReadCardDma) TryPattern(patchContext, sCARDiTryReadCardDmaPatternThumbChouSoujuu); } + if (!_cardiTryReadCardDma && patchContext.GetSdkVersion() == 0x4027531) + { + TryPattern(patchContext, sCARDiTryReadCardDmaPatternSdk4027531ThumbInlined); + } if (_cardiTryReadCardDma) _thumb = true; From eac8f7e7344f27e02f604c57f09ca0568e506b34 Mon Sep 17 00:00:00 2001 From: TY <47445484+R-YaTian@users.noreply.github.com> Date: Sat, 10 Jan 2026 21:21:48 +0800 Subject: [PATCH 7/7] ndsHeader: Added `HasShared2Access` and `HasSslCertAccess` and fix typo (#87) --- common/ndsHeader.h | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/common/ndsHeader.h b/common/ndsHeader.h index 4a1f41e..6d31449 100644 --- a/common/ndsHeader.h +++ b/common/ndsHeader.h @@ -63,8 +63,10 @@ struct nds_header_ntr_t static_assert(sizeof(nds_header_ntr_t) == 0x170, "Invalid size for nds_header_ntr_t"); -#define NDS_HEADER_TWL_ACCESS_CONTROL_SD_ACCESS (1 << 3) -#define NDS_HEADER_TWL_ACCESS_CONTROL_NAND_ACCESS (1 << 4) +#define NDS_HEADER_TWL_ACCESS_CONTROL_SD_ACCESS (1 << 3) +#define NDS_HEADER_TWL_ACCESS_CONTROL_NAND_ACCESS (1 << 4) +#define NDS_HEADER_TWL_ACCESS_CONTROL_SHARED2_ACCESS (1 << 6) +#define NDS_HEADER_TWL_ACCESS_CONTROL_SSLCERT_ACCESS (1 << 9) struct nds_header_twl_t : public nds_header_ntr_t { @@ -77,7 +79,7 @@ struct nds_header_twl_t : public nds_header_ntr_t u32 regionFlags; u32 accessControl; u32 arm7ScfgExt7; - u8 gap1B8[3]; + u8 gap1BC[3]; u8 twlFlags2; u32 arm9iRomOffset; u8 gap1C4[4]; @@ -146,6 +148,16 @@ struct nds_header_twl_t : public nds_header_ntr_t { return IsTwlRom() && (accessControl & NDS_HEADER_TWL_ACCESS_CONTROL_NAND_ACCESS) != 0; } + + constexpr bool HasShared2Access() const + { + return IsTwlRom() && (accessControl & NDS_HEADER_TWL_ACCESS_CONTROL_SHARED2_ACCESS) != 0; + } + + constexpr bool HasSslCertAccess() const + { + return IsTwlRom() && (accessControl & NDS_HEADER_TWL_ACCESS_CONTROL_SSLCERT_ACCESS) != 0; + } }; static_assert(sizeof(nds_header_twl_t) == 0x1000, "Invalid size for nds_header_twl_t");