diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..2eec736 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,162 @@ +# Changelog + +## [Unreleased] + +### Added +- Support for the SuperChis slot 2 card - by @edo9300 +- Most of the remaining SDK 2-4 DMA patches - by @taxicat1 + +### Fixed +- Star Wars Jedi Alliance patch - by @taxicat1 + +## [v1.5.0] - 1 Feb 2026 - Puppy Palace Release 🐶 +> [!IMPORTANT] +> With this release a new file `patchlist.bin` is introduced that needs to be copied to the `/_pico` folder on your SD card. + +### Added +- AP patch for Last Window: The Secret of Cape West - by @taxicat1 +- Missing CARDi_ReadRomIdCore signature for Top Spin 2 (USA) - by @taxicat1 + - Fixes Top Spin 2 (USA) on DSTT and slot 2 cards +- Patch list with misc arm9 patches and metafortress addresses - Implementation by @Gericom, patch list contents by @taxicat1 + - Puppy Palace (USA), My Puppy Shop (Europe), Machi no Pet-ya-san DS - 200 Piki Wan-chan Daishuugou (Japan) + - Castlevania - Portrait of Ruin (USA) and (Europe), Akumajou Dracula - Gallery of Labyrinth (Japan), Akumajou Dracula - Gallery of Labyrinth (Japan) (Rev 1) + - Luminous Arc 2 (USA) and (Europe), Luminous Arc 2 - Will (Japan) + - Children of Mana (USA) and (Europe), Seiken Densetsu DS - Children of Mana (Japan) + - Dementium II (USA) and (Europe), Tozasareta Byoutou - Dementium II (Japan) + - Grand Theft Auto - Chinatown Wars (USA), (Europe) and (Japan) + - Star Wars - The Clone Wars - Jedi Alliance (USA) and (Europe) + - C.O.P. - The Recruit (USA) and (Europe) + - Battle of Giants - Dragons (USA) (Rev 1), Combat of Giants - Dragons (Europe) + - Battle of Giants - Mutant Insects (USA), Combat of Giants - Mutant Insects (Europe) + - Captain America - Super Soldier (USA) and (Europe) + - Imagine - Resort Owner (USA), Imagine - Dream Resort (Europe) + - Might & Magic - Clash of Heroes (USA) and (Europe) + - Prince of Persia - The Forgotten Sands (USA) and (Europe) + - Kirby - Mass Attack (USA) and (Europe), Atsumete! Kirby (Japan), Moyeora! Kirby (Korea) +- Keep a valid stack pointer when booting the arm9 + - Fixes Battle of Giants - Mutant Insects (USA), Combat of Giants - Mutant Insects (Europe) together with the patch in the patch list +- System for adjusting addresses for autoload - by @taxicat1 + - Fixes New Super Mario Bros (USA) +- Attempt to fix rom hacks that decompress the arm9, but don't set compressedEnd to zero + - Fixes Pokemon SoulSilver Deluxe (together with the fix for roms repacked in unusual ways) +- Support for CARDi_ReadCard signature used by Chou Soujuu Mecha MG - by @taxicat1 + +### Changed +- Reduce size of some patch codes - by @edo9300 and @Gericom + - Fixes Dragon Quest Heroes - Rocket Slime (USA), Imagine - Fashion Designer (Europe) and Mugen Kouro (Japan) +- Improve handling of module params and locating of unused libsyscall space to support rom hacks that repack roms in unusual ways + - Fixes Coropata (English translation) + +### Fixed +- Ignore rom reads into null pointer destinations - by @taxicat1 + - Fixes Tony Hawk's Downhill Jam + +## [v1.4.0] - 11 Jan 2026 + +### Added +- Overlay patch to fix race condition in Kirby Super Star Ultra - by @taxicat1 +- Overlay patch for hombrew AP in Rabbids Go Home - by @taxicat1 +- Bypass region locking on iQue games - by @R-YaTian +- Properly set MBK9 (twl wram locking) settings - by @R-YaTian +- Support for SDK variant with a lot of inlining + - Fixes Tropix! ...Your Island Getaway and Think - Training für den Kopf - Kids - Spiel Dich Schlau! + - Note that these two games don't work yet on platforms that need card id patches (DSTT and slot2 platforms) +- Support for Slot 2 flashcarts using Compact Flash - by @edo9300 + - Supercard CF (SUPERCARDCF) + - GBA Media Player CF (MPCF) + - M3 Adapter CF (M3CF) + - Max Media Dock CF (MMCF) +- Proper detection of DS mode DSiWare + - Fixes DS Download Play and Pictochat DSiWare apps +- Support for the homebrew bootstub that allows to return to the launcher application + - The Pico Loader API was updated to v2 for this purpose. The new `launcherPath` field needs to be set to the path of the launcher rom. The bootstub is only inserted when `launcherPath` is specified. As such, you will also need to update your launcher. If you are using Pico Launcher, support was added in v1.1.0. + +### Changed +- Duplicate entries removed from save list and missing title added - by @synthic + - Fixes Disney Two Pack - Frozen Olaf's Quest + Big Hero 6 - Battle in the Bay (USA) +- Improve nocash print support detection to also detect melon ds - by @synthic +- Lock scfg9 when switching from DSi to DS mode + - Fixes homebrew with a DS mode header that tries to detect DSi mode. This for example fixes touch in DSCraft. + +### Fixed +- DATEL: Make read sector function vram safe - by @edo9300 + - Fixes some games that read directly to vram and fixes games that use OS_ResetSystem on the DATEL platform +- Proper handling of blx branches in CardiTryReadCardDmaPatch - by @taxicat1 + - Fixes Ninja Gaiden - Dragon Sword (USA) +- Fix sCARDiTryReadCardDmaPatternSdk3017530 matching multiple variants - by @taxicat1 + - 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) and LifeSigns - Surgical Unit (USA) +- Fix Shaberu! DS Oryouri Navi (Japan) (rev 0 and 1) by accounting for a spurious CARDi_ReadCard match + +## [v1.3.1] - 29 Dec 2025 + +### Fixed +- DATEL: Put back the full spi cycle routine when sending commands - by @edo9300 + - Fixes issues with some SD cards on the DATEL platform + +## [v1.3.0] - 28 Dec 2025 + +### Added +- Properly set the supported language, user language, and region based on the ROM's region - by @R-YaTian + - This bypasses the region lock or language lock in some dsiware games. +- Missing OS_ResetSystem signature - by @taxicat1 + - Fixes crashes in Tetris DS and other games that have this signature. +- Support for roms with a writable NAND chip. + - Fixes WarioWare D.I.Y., Face Training, Jam with the Band and Nintendo DS Guide. +- Special save initialization for Jam with the Band and Daigassou! Band-Brothers DX +- New supported platform: Datel (Games n' Music and Action Replay DS(i)) - by @edo9300 +- New supported platform: Stargate 3DS - by @lifehackerhansol + +### Changed +- Optimized space usage of supercard platform - by @edo9300 +- Check in CardiTaskThreadPatch that the required slot is actually mapped to arm7. + - Fixes Power Rangers - Samurai. + +### Fixed +- Fix CardiTaskThreadPatch to apply the right patch for all signatures + - This fixes various games, including Chibi Robo! Park Patrol, Rainbow Islands Revolution, MechAssault - Phantom War and Diddy Kong Racing DS (USA). + +## [v1.2.0] - 22 Dec 2025 + +### Added +- Support for DSProtect patches in static arm9 - by @taxicat1 +- Support for unusual DSProtect configurations - by @taxicat1 + - Fixes Dragon Ball: Origins 2 and Puyo Puyo 7 +- Proper implementation of save verification + - Fixes Madagascar, Bleach: Dark Souls and Final Fantasy Crystal Chronicles: Echoes of Time + +### Changed +- Improve Pokémon IR sensor AP patches - by @taxicat1 + - Fixes Pokémon HeartGold and SoulSilver +- Always boot roms with slot 1 and 2 mapped to arm7 + - Fixes FastVideoDSPlayer homebrew +- Improve Sdk5DsiSdCardRedirectPatch + +### Fixed +- Fix some retail roms being detected as homebrew + - Fixes Scooby Doo! - Unmasked and Kim Possible - Kimmunicator +- Fix some system tool DSi roms being misdetected as DSiWare + +## [v1.1.0] - 4 Dec 2025 + +### Added +- Support for EZ-Flash Parallel platform - by @lifehackerhansol +- Add a few more games to the DLDI patch blacklist + - Fixes Final Fantasy Crystal Chronicles - Ring of Fates (EU and US) and Nanashi no Geemu +- Clear all arm9 CPU registers before booting a game + - Fixes the Cake Ninja DSiWare titles + +## Changed +- Simplified and improved DSProtect patches - by @taxicat1 + - Fixes Saga 3: Shadow or Light and Solatorobo: Red the Hunter + +## [v1.0.1] - 29 Nov 2025 + +### Added +- Add Mario vs. Donkey Kong - Mini-Land Mayhem! US rev 2 (V2GE) to the AP list - by @IceKareemCheese + +### Fixed +- Fix the DSProtect v2.03 patch (thanks @taxicat1) + - Fixes Professor Layton and the Last Specter among others + +## [v1.0.0] - 25 Nov 2025 +- Initial release diff --git a/arm9/source/patches/arm9/sdk2to4/CardiTryReadCardDmaPatch.cpp b/arm9/source/patches/arm9/sdk2to4/CardiTryReadCardDmaPatch.cpp index d31cbb7..1b9d35f 100644 --- a/arm9/source/patches/arm9/sdk2to4/CardiTryReadCardDmaPatch.cpp +++ b/arm9/source/patches/arm9/sdk2to4/CardiTryReadCardDmaPatch.cpp @@ -7,14 +7,14 @@ #include "patches/arm9/RomOffsetToSdSectorPatchCode.h" #include "CardiTryReadCardDmaPatch.h" -static const u32 sCARDiTryReadCardDmaPatternPingPals[] = { 0xE92D47F0u, 0xE1A0A000u, 0xE59F9120u, 0xE3A08000u }; +static const u32 sCARDiTryReadCardDmaPatternPingPals[] = { 0xE92D47F0u, 0xE1A0A000u, 0xE59F9120u, 0xE3A08000u }; // unimplemented static const u32 sCARDiTryReadCardDmaPatternUnknown[] = { 0xE92D47F0u, 0xE59F9138u, 0xE3A06000u, 0xE5998020u }; -static const u32 sCARDiTryReadCardDmaPatternUnknown2[] = { 0xE92D47F0u, 0xE59F4134u, 0xE3A06000u, 0xE5949020u }; +static const u32 sCARDiTryReadCardDmaPatternSdk03007532HarvestMoon[] = { 0xE92D47F0u, 0xE59F4134u, 0xE3A06000u, 0xE5949020u }; static const u32 sCARDiTryReadCardDmaPatternUnknown3[] = { 0xE92D4FF8u, 0xE59FB140u, 0xE3A05000u, 0xE59B8020u }; -static const u32 sCARDiTryReadCardDmaPatternUnknown4[] = { 0xE92D47F0u, 0xE59F9138u, 0xE3A06000u, 0xE599801Cu }; +static const u32 sCARDiTryReadCardDmaPatternSdk02027533PokemonRanger[] = { 0xE92D47F0u, 0xE59F9138u, 0xE3A06000u, 0xE599801Cu }; static const u32 sCARDiTryReadCardDmaPattern20029A7[] = { 0xE92D47F0u, 0xE59F9128u, 0xE3A07000u, 0xE599401Cu }; static const u32 sCARDiTryReadCardDmaPattern2012774[] = { 0xE92D47F0u, 0xE59F9134u, 0xE3A07000u, 0xE599401Cu }; -static const u32 sCARDiTryReadCardDmaPattern2017532[] = { 0xE92D47F0u, 0xE59F9130u, 0xE3A07000u, 0xE599401Cu }; +static const u32 sCARDiTryReadCardDmaPattern2017532BrainAge[] = { 0xE92D47F0u, 0xE59F9130u, 0xE3A07000u, 0xE599401Cu }; static const u32 sCARDiTryReadCardDmaPattern2027530[] = { 0xE92D47F0u, 0xE59F913Cu, 0xE3A06000u, 0xE599801Cu }; static const u32 sCARDiTryReadCardDmaPattern[] = { 0xE92D47F0u, 0xE59F913Cu, 0xE3A06000u, 0xE5998020u }; static const u32 sCARDiTryReadCardDmaPatternSdk3017530[] = { 0xE92D4FF0u, 0xE24DD004u, 0xE59FB14Cu, 0xE3A07000u }; @@ -23,24 +23,21 @@ static const u32 sCARDiTryReadCardDmaPatternSdk3027530[] = { 0xE92D4FF0u, 0xE24D static const u32 sCARDiTryReadCardDmaPatternSdk4007530[] = { 0xE92D4FF8u, 0xE59FB144u, 0xE3A05000u, 0xE59B8020u }; static const u32 sCARDiTryReadCardDmaPatternSdk4007532[] = { 0xE92D4FF8u, 0xE59F416Cu, 0xE3A06000u, 0xE5949020u }; static const u32 sCARDiTryReadCardDmaPatternSdk4027539SpiritTracks[] = { 0xE92D4FF8u, 0xE59F4174u, 0xE3A06000u, 0xE5949020u }; -static const u32 sCARDiTryReadCardDmaPatternJpnPokemonDownloader[] = { 0xE92D4FF8u, 0xE59FB138u, 0xE3A05000u, 0xE59B8020u }; +static const u32 sCARDiTryReadCardDmaPatternJpnPokemonDownloader[] = { 0xE92D4FF8u, 0xE59FB138u, 0xE3A05000u, 0xE59B8020u }; // unimplemented static const u32 sCARDiTryReadCardDmaPatternThumbChouSoujuu[] = { 0xB083B5F0u, 0x48399000u, 0x6A0469C5u, 0x96012600u }; static const u32 sCARDiTryReadCardDmaPatternSdk2004F4CThumb[] = { 0xB083B5F0u, 0x4D359000u, 0x94012400u, 0x90020020u }; static const u32 sCARDiTryReadCardDmaPatternSdk2007531Thumb[] = { 0xB083B5F0u, 0x4D379000u, 0x94012400u, 0x90020020u }; static const u32 sCARDiTryReadCardDmaPatternSdk2027530Thumb[] = { 0xB083B5F0u, 0x483A9000u, 0x6A0469C5u, 0x96012600u }; static const u32 sCARDiTryReadCardDmaPatternSdk3007530Thumb[] = { 0xB083B5F0u, 0x483A9000u, 0x6A446A05u, 0x96012600u }; -static const u32 sCARDiTryReadCardDmaPatternSdk3012776Thumb[] = { 0xB083B5F0u, 0x483A9000u, 0x6A446A05u, 0x90012600u }; +static const u32 sCARDiTryReadCardDmaPatternSdk3012776Thumb[] = { 0xB083B5F0u, 0x483A9000u, 0x6A446A05u, 0x90012600u }; // TODO does this exist? static const u32 sCARDiTryReadCardDmaPatternSdk3017531Thumb[] = { 0xB085B5F0u, 0x483C9000u, 0x6A446A05u, 0x90012000u }; static const u32 sCARDiTryReadCardDmaPatternSdk3027530Thumb[] = { 0xB085B5F0u, 0x483D9000u, 0x6A446A05u, 0x90012000u }; static const u32 sCARDiTryReadCardDmaPatternSdkThumb[] = { 0xB084B5F8u, 0x483D9000u, 0x6A446A05u, 0x90032000u }; 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 +static const u32 sCARDiTryReadCardDmaPatternSdk4027531ThumbInlined[] = { 0xB083B5F0u, 0x485D9000u, 0x6A062500u, 0x1C286A44u }; // unimplemented void CardiTryReadCardDmaPatch::TryPattern(PatchContext& patchContext, const u32* pattern) { @@ -51,6 +48,20 @@ void CardiTryReadCardDmaPatch::TryPattern(PatchContext& patchContext, const u32* } } +void CardiTryReadCardDmaPatch::ApplyReturnFalsePatch() +{ + if (_thumb) + { + ((u16*)_cardiTryReadCardDma)[0] = THUMB_MOVS_IMM(0, 0); + ((u16*)_cardiTryReadCardDma)[1] = THUMB_BX_LR; + } + else + { + _cardiTryReadCardDma[0] = 0xE3A00000; // mov r0, #0 + _cardiTryReadCardDma[1] = 0xE12FFF1E; // bx lr + } +} + bool CardiTryReadCardDmaPatch::FindPatchTarget(PatchContext& patchContext) { if (patchContext.GetSdkVersion() >= 0x4007532) @@ -99,7 +110,7 @@ bool CardiTryReadCardDmaPatch::FindPatchTarget(PatchContext& patchContext) if (!_cardiTryReadCardDma) { - TryPattern(patchContext, sCARDiTryReadCardDmaPatternUnknown); + TryPattern(patchContext, sCARDiTryReadCardDmaPatternUnknown); if (!_cardiTryReadCardDma) TryPattern(patchContext, sCARDiTryReadCardDmaPatternSdk4007530); if (!_cardiTryReadCardDma) @@ -107,7 +118,7 @@ bool CardiTryReadCardDmaPatch::FindPatchTarget(PatchContext& patchContext) if (!_cardiTryReadCardDma) TryPattern(patchContext, sCARDiTryReadCardDmaPatternSdk3017530); if (!_cardiTryReadCardDma) - TryPattern(patchContext, sCARDiTryReadCardDmaPatternUnknown2); + TryPattern(patchContext, sCARDiTryReadCardDmaPatternSdk03007532HarvestMoon); if (!_cardiTryReadCardDma) TryPattern(patchContext, sCARDiTryReadCardDmaPatternUnknown3); if (!_cardiTryReadCardDma) @@ -117,11 +128,11 @@ bool CardiTryReadCardDmaPatch::FindPatchTarget(PatchContext& patchContext) if (patchContext.GetSdkVersion() < 0x3000000) { if (!_cardiTryReadCardDma) - TryPattern(patchContext, sCARDiTryReadCardDmaPattern2017532); + TryPattern(patchContext, sCARDiTryReadCardDmaPattern2017532BrainAge); if (!_cardiTryReadCardDma) TryPattern(patchContext, sCARDiTryReadCardDmaPatternPingPals); if (!_cardiTryReadCardDma) - TryPattern(patchContext, sCARDiTryReadCardDmaPatternUnknown4); + TryPattern(patchContext, sCARDiTryReadCardDmaPatternSdk02027533PokemonRanger); } if (patchContext.GetSdkVersion() >= 0x4000000) @@ -170,163 +181,392 @@ bool CardiTryReadCardDmaPatch::FindPatchTarget(PatchContext& patchContext) return true; //_cardiTryReadCardDma != nullptr; } +static u32 resolveCallWithAutoload(u32 callLocation, const IAutoloadAdjuster* autoloadAdjuster, bool isThumb) +{ + s32 callOffset; + if (isThumb) + { + callOffset = ArmHelper::GetThumbCallOffset(((u16*)callLocation)[0], ((u16*)callLocation)[1]); + } + else + { + callOffset = ArmHelper::GetArmCallOffset(*(u32*)callLocation); + } + if (autoloadAdjuster) + { + callLocation = autoloadAdjuster->AdjustInitialToFinal(callLocation); + } + u32 callDestination = callLocation + callOffset; + if (isThumb && (callDestination & 3) == 2) + { + // fix non-aligned Thumb call to ARM + callDestination &= ~2u; + } + return callDestination; +} + void CardiTryReadCardDmaPatch::ApplyPatch(PatchContext& patchContext) { if (!_cardiTryReadCardDma) return; + if (!patchContext.GetLoaderPlatform()->HasDmaSdReads()) + { + LOG_DEBUG("Platform does not support DMA\n"); + ApplyReturnFalsePatch(); + return; + } + + u32 cardiCommon; + u32 cardiOnReadCard; + u32 cardiSetCardDma; + u32 cardiSetCardDmaDmaCopyCallOffset; + u32 cardiOnReadCardDisableIrqCallOffset; + u32 cardiOnReadCardPatchOffset; + bool patchUsingPool = false; // needed for some SDK 2-3 Thumb + u32 cardiOnReadCardPoolOffset; if (_thumb) { - ((u16*)_cardiTryReadCardDma)[0] = sReturnFalsePatchThumb[0]; - ((u16*)_cardiTryReadCardDma)[1] = sReturnFalsePatchThumb[1]; - } - else - { - bool enableDma = patchContext.GetLoaderPlatform()->HasDmaSdReads(); - if (enableDma) + if (_foundPattern == sCARDiTryReadCardDmaPatternThumbChouSoujuu) { - u32 cardiCommon; - u32 cardiOnReadCard; - u32 cardiSetCardDma; - u32 cardiSetCardDmaDmaCopyCallOffset; - u32 cardiOnReadCardOffset; - if (_foundPattern == sCARDiTryReadCardDmaPattern20029A7) - { - cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x134); - cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x144); - cardiSetCardDma = ArmHelper::GetArmCallAddress((u32*)((u8*)_cardiTryReadCardDma + 0x124)); - if (*(u32*)cardiOnReadCard == 0xE92D40F0u) - { - cardiSetCardDmaDmaCopyCallOffset = 0x18; - cardiOnReadCardOffset = 0x40; - } - else - { - // old version is not supported yet - _cardiTryReadCardDma[0] = sReturnFalsePatchArm[0]; - _cardiTryReadCardDma[1] = sReturnFalsePatchArm[1]; - return; - } - } - else if (_foundPattern == sCARDiTryReadCardDmaPattern2012774) - { - cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x140); - cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x150); - cardiSetCardDma = ArmHelper::GetArmCallAddress((u32*)((u8*)_cardiTryReadCardDma + 0x130)); - cardiSetCardDmaDmaCopyCallOffset = 0x18; - cardiOnReadCardOffset = 0x40; - } - else if (_foundPattern == sCARDiTryReadCardDmaPattern) - { - cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x148) + 4; - cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x158); - cardiSetCardDma = ArmHelper::GetArmCallAddress((u32*)((u8*)_cardiTryReadCardDma + 0x138)); - cardiSetCardDmaDmaCopyCallOffset = 0x18; - cardiOnReadCardOffset = 0x40; - } - else if (_foundPattern == sCARDiTryReadCardDmaPatternSdk3017530) - { - cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x15C) + 4; - cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x16C); - if (*(u32*)((u8*)_cardiTryReadCardDma + 0x158) == 0xE12FFF1E) - { - cardiSetCardDma = ArmHelper::GetArmCallAddress((u32*)((u8*)_cardiTryReadCardDma + 0x148)); - } - else - { - cardiSetCardDma = ArmHelper::GetArmCallAddress((u32*)((u8*)_cardiTryReadCardDma + 0x14C)); - } - cardiSetCardDmaDmaCopyCallOffset = 0x18; - cardiOnReadCardOffset = 0x40; - } - else if (_foundPattern == sCARDiTryReadCardDmaPatternSdk3027530) - { - cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x160) + 4; - cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x170); - cardiSetCardDma = ArmHelper::GetArmCallAddress((u32*)((u8*)_cardiTryReadCardDma + 0x14C)); - cardiSetCardDmaDmaCopyCallOffset = 0x18; - cardiOnReadCardOffset = 0x40; - } - else if (_foundPattern == sCARDiTryReadCardDmaPatternSdk4007532) - { - cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x178) + 4; - cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x188); - cardiSetCardDma = ArmHelper::GetArmCallAddress((u32*)((u8*)_cardiTryReadCardDma + 0x16C)); - cardiSetCardDmaDmaCopyCallOffset = 0x1C; - cardiOnReadCardOffset = 0x48; - } - else if (_foundPattern == sCARDiTryReadCardDmaPatternSdk4027539SpiritTracks) - { - cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x180) + 4; - cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x190); - cardiSetCardDma = ArmHelper::GetArmCallAddress((u32*)((u8*)_cardiTryReadCardDma + 0x174)); - cardiSetCardDmaDmaCopyCallOffset = 0x1C; - cardiOnReadCardOffset = 0x48; - } - else - { - _cardiTryReadCardDma[0] = sReturnFalsePatchArm[0]; - _cardiTryReadCardDma[1] = sReturnFalsePatchArm[1]; - return; - } - - // 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 = ArmHelper::GetArmCallOffset(*(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 = ArmHelper::GetArmCallOffset(*(u32*)osDisableIrqMaskCallLocation); - if (autoloadAdjuster) - { - osDisableIrqMaskCallLocation = autoloadAdjuster->AdjustInitialToFinal(osDisableIrqMaskCallLocation); - } - u32 osDisableIrqMask = osDisableIrqMaskCallLocation + osDisableIrqMaskCallOffset; - - // patch CARDi_SetCardDma - auto sdReadDmaPatchCode = patchContext.GetLoaderPlatform()->CreateSdReadDmaPatchCode( - patchContext.GetPatchCodeCollection(), patchContext.GetPatchHeap(), (const void*)miiCardDmaCopy32); - auto romOffsetToSdSectorPatchCode = patchContext.GetPatchCodeCollection().GetOrAddSharedPatchCode([&] - { - return new RomOffsetToSdSectorPatchCode(patchContext.GetPatchHeap(), - (const rom_file_info_t*)((u32)SHARED_ROM_FILE_INFO - 0x02F00000 + 0x02700000)); - }); - auto cardiSetCardDmaPatchCode = patchContext.GetPatchCodeCollection().AddUniquePatchCode - ( - patchContext.GetPatchHeap(), - romOffsetToSdSectorPatchCode, - sdReadDmaPatchCode, - (const void*)cardiCommon, - (const void*)osDisableIrqMask - ); - *(u32*)(cardiSetCardDma + 0) = 0xE51FF004; // ldr pc,= entryAddress - *(u32*)(cardiSetCardDma + 4) = (u32)cardiSetCardDmaPatchCode->GetCardiSetCardDmaFunction(); - - // patch CARDi_OnReadCard - *(u32*)(cardiOnReadCard + cardiOnReadCardOffset + 0) = 0xE59F0000; // ldr r0,= entryAddress - *(u32*)(cardiOnReadCard + cardiOnReadCardOffset + 4) = 0xE12FFF30; // blx r0 - *(u32*)(cardiOnReadCard + cardiOnReadCardOffset + 8) = (u32)cardiSetCardDmaPatchCode->GetCardiOnReadCardPatchFunction(); - - LOG_DEBUG("DMA enabled\n"); + cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0xEC); + cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x110) & ~1u; + cardiSetCardDma = ArmHelper::GetThumbCallAddress((u16*)((u8*)_cardiTryReadCardDma + 0xE2)) & ~1u; + cardiSetCardDmaDmaCopyCallOffset = 0xC; + cardiOnReadCardDisableIrqCallOffset = 0x28; + cardiOnReadCardPatchOffset = 0x28; + patchUsingPool = true; + cardiOnReadCardPoolOffset = 0x94; + } + else if (_foundPattern == sCARDiTryReadCardDmaPatternSdk2004F4CThumb) + { + cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0xDC); + cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x100) & ~1u; + cardiSetCardDma = ArmHelper::GetThumbCallAddress((u16*)((u8*)_cardiTryReadCardDma + 0xCE)) & ~1u; + cardiSetCardDmaDmaCopyCallOffset = 0xC; + cardiOnReadCardDisableIrqCallOffset = 0x28; + cardiOnReadCardPatchOffset = 0x28; + patchUsingPool = true; + cardiOnReadCardPoolOffset = 0x50; + } + else if (_foundPattern == sCARDiTryReadCardDmaPatternSdk2007531Thumb) + { + cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0xE4); + cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x108) & ~1u; + cardiSetCardDma = ArmHelper::GetThumbCallAddress((u16*)((u8*)_cardiTryReadCardDma + 0xD6)) & ~1u; + cardiSetCardDmaDmaCopyCallOffset = 0xC; + cardiOnReadCardDisableIrqCallOffset = 0x28; + cardiOnReadCardPatchOffset = 0x28; + patchUsingPool = true; + cardiOnReadCardPoolOffset = 0x50; + } + else if (_foundPattern == sCARDiTryReadCardDmaPatternSdk2027530Thumb) + { + cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0xF0); + cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x114) & ~1u; + cardiSetCardDma = ArmHelper::GetThumbCallAddress((u16*)((u8*)_cardiTryReadCardDma + 0xE2)) & ~1u; + cardiSetCardDmaDmaCopyCallOffset = 0xC; + cardiOnReadCardDisableIrqCallOffset = 0x28; + cardiOnReadCardPatchOffset = 0x28; + patchUsingPool = true; + cardiOnReadCardPoolOffset = 0x9C; + } + else if (_foundPattern == sCARDiTryReadCardDmaPatternSdk3007530Thumb) + { + cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0xF0) + 4; + cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x114) & ~1u; + cardiSetCardDma = ArmHelper::GetThumbCallAddress((u16*)((u8*)_cardiTryReadCardDma + 0xE2)) & ~1u; + cardiSetCardDmaDmaCopyCallOffset = 0xC; + cardiOnReadCardDisableIrqCallOffset = 0x28; + cardiOnReadCardPatchOffset = 0x28; + patchUsingPool = true; + cardiOnReadCardPoolOffset = 0xA0; + } + else if (_foundPattern == sCARDiTryReadCardDmaPatternSdk3017531Thumb) + { + cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0xF8) + 4; + cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x11C) & ~1u; + cardiSetCardDma = ArmHelper::GetThumbCallAddress((u16*)((u8*)_cardiTryReadCardDma + 0xEA)) & ~1u; + cardiSetCardDmaDmaCopyCallOffset = 0xC; + cardiOnReadCardDisableIrqCallOffset = 0x28; + cardiOnReadCardPatchOffset = 0x28; + patchUsingPool = true; + cardiOnReadCardPoolOffset = 0xA0; + } + else if (_foundPattern == sCARDiTryReadCardDmaPatternSdk3027530Thumb) + { + cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0xFC) + 4; + cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x120) & ~1u; + cardiSetCardDma = ArmHelper::GetThumbCallAddress((u16*)((u8*)_cardiTryReadCardDma + 0xEC)) & ~1u; + cardiSetCardDmaDmaCopyCallOffset = 0xC; + cardiOnReadCardDisableIrqCallOffset = 0x28; + cardiOnReadCardPatchOffset = 0x28; + patchUsingPool = true; + cardiOnReadCardPoolOffset = 0xA0; + } + else if (_foundPattern == sCARDiTryReadCardDmaPatternSdkThumb) + { + cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0xFC) + 4; + cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x110) & ~1u; + cardiSetCardDma = ArmHelper::GetThumbCallAddress((u16*)((u8*)_cardiTryReadCardDma + 0xF2)) & ~1u; + cardiSetCardDmaDmaCopyCallOffset = 0x10; + cardiOnReadCardDisableIrqCallOffset = 0x32; + cardiOnReadCardPatchOffset = 0x30; + } + else if (_foundPattern == sCARDiTryReadCardDmaPatternSdk4007531Thumb) + { + cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x100) + 4; + cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x114) & ~1u; + cardiSetCardDma = ArmHelper::GetThumbCallAddress((u16*)((u8*)_cardiTryReadCardDma + 0xF4)) & ~1u; + cardiSetCardDmaDmaCopyCallOffset = 0x10; + cardiOnReadCardDisableIrqCallOffset = 0x32; + cardiOnReadCardPatchOffset = 0x30; + } + else if (_foundPattern == sCARDiTryReadCardDmaPatternSdk4017530Thumb || _foundPattern == sCARDiTryReadCardDmaPatternSdk4027530Thumb) + { + cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x124) + 4; + cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x138) & ~1u; + cardiSetCardDma = ArmHelper::GetThumbCallAddress((u16*)((u8*)_cardiTryReadCardDma + 0x118)) & ~1u; + cardiSetCardDmaDmaCopyCallOffset = 0x10; + cardiOnReadCardDisableIrqCallOffset = 0x32; + cardiOnReadCardPatchOffset = 0x30; } else { - _cardiTryReadCardDma[0] = sReturnFalsePatchArm[0]; - _cardiTryReadCardDma[1] = sReturnFalsePatchArm[1]; + LOG_DEBUG("Unsupported Thumb CARDi_TryReadCardDma signature\n"); + ApplyReturnFalsePatch(); + return; } } + else + { + if (_foundPattern == sCARDiTryReadCardDmaPatternUnknown) + { + cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x144) + 4; + cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x154); + cardiSetCardDma = ArmHelper::GetArmCallAddress((u32*)((u8*)_cardiTryReadCardDma + 0x138)); + cardiSetCardDmaDmaCopyCallOffset = 0x18; + cardiOnReadCardDisableIrqCallOffset = 0x44; + cardiOnReadCardPatchOffset = 0x40; + } + else if (_foundPattern == sCARDiTryReadCardDmaPatternSdk03007532HarvestMoon) + { + cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x140) + 4; + cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x150); + cardiSetCardDma = ArmHelper::GetArmCallAddress((u32*)((u8*)_cardiTryReadCardDma + 0x134)); + cardiSetCardDmaDmaCopyCallOffset = 0x1C; + cardiOnReadCardDisableIrqCallOffset = 0x4C; + cardiOnReadCardPatchOffset = 0x48; + } + else if (_foundPattern == sCARDiTryReadCardDmaPatternUnknown3) + { + cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x14C) + 4; + cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x15C); + cardiSetCardDma = ArmHelper::GetArmCallAddress((u32*)((u8*)_cardiTryReadCardDma + 0x140)); + cardiSetCardDmaDmaCopyCallOffset = 0x1C; + cardiOnReadCardDisableIrqCallOffset = 0x4C; + cardiOnReadCardPatchOffset = 0x48; + } + else if (_foundPattern == sCARDiTryReadCardDmaPatternSdk02027533PokemonRanger) + { + cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x148); + cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x158); + cardiSetCardDma = ArmHelper::GetArmCallAddress((u32*)((u8*)_cardiTryReadCardDma + 0x138)); + cardiSetCardDmaDmaCopyCallOffset = 0x18; + cardiOnReadCardDisableIrqCallOffset = 0x44; + cardiOnReadCardPatchOffset = 0x40; + } + else if (_foundPattern == sCARDiTryReadCardDmaPattern20029A7) + { + if (*(u32*)((u8*)_cardiTryReadCardDma + 0x140) == 0xE12FFF1E) + { + cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x144); + cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x154); + } + else + { + cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x134); + cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x144); + } + cardiSetCardDma = ArmHelper::GetArmCallAddress((u32*)((u8*)_cardiTryReadCardDma + 0x124)); + cardiSetCardDmaDmaCopyCallOffset = 0x18; + cardiOnReadCardDisableIrqCallOffset = 0x44; + cardiOnReadCardPatchOffset = 0x40; + if (!ArmHelper::IsArmUnconditionalBl(*(u32*)(cardiSetCardDma + cardiSetCardDmaDmaCopyCallOffset))) + { + // some versions have inlined MIi_CardDmaCopy32 + LOG_DEBUG("Failed to patch sCARDiTryReadCardDmaPattern20029A7\n"); + ApplyReturnFalsePatch(); + return; + } + } + else if (_foundPattern == sCARDiTryReadCardDmaPattern2012774) + { + cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x140); + cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x150); + cardiSetCardDma = ArmHelper::GetArmCallAddress((u32*)((u8*)_cardiTryReadCardDma + 0x130)); + cardiSetCardDmaDmaCopyCallOffset = 0x18; + cardiOnReadCardDisableIrqCallOffset = 0x44; + cardiOnReadCardPatchOffset = 0x40; + } + else if (_foundPattern == sCARDiTryReadCardDmaPattern2017532BrainAge) + { + cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x13C); + cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x14C); + cardiSetCardDma = ArmHelper::GetArmCallAddress((u32*)((u8*)_cardiTryReadCardDma + 0x130)); + cardiSetCardDmaDmaCopyCallOffset = 0x18; + cardiOnReadCardDisableIrqCallOffset = 0x44; + cardiOnReadCardPatchOffset = 0x40; + } + else if (_foundPattern == sCARDiTryReadCardDmaPattern2027530) + { + cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x148); + cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x158); + cardiSetCardDma = ArmHelper::GetArmCallAddress((u32*)((u8*)_cardiTryReadCardDma + 0x138)); + cardiSetCardDmaDmaCopyCallOffset = 0x18; + cardiOnReadCardDisableIrqCallOffset = 0x44; + cardiOnReadCardPatchOffset = 0x40; + } + else if (_foundPattern == sCARDiTryReadCardDmaPattern) + { + cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x148) + 4; + cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x158); + cardiSetCardDma = ArmHelper::GetArmCallAddress((u32*)((u8*)_cardiTryReadCardDma + 0x138)); + cardiSetCardDmaDmaCopyCallOffset = 0x18; + cardiOnReadCardDisableIrqCallOffset = 0x44; + cardiOnReadCardPatchOffset = 0x40; + } + else if (_foundPattern == sCARDiTryReadCardDmaPatternSdk3017530) + { + cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x15C) + 4; + cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x16C); + if (*(u32*)((u8*)_cardiTryReadCardDma + 0x158) == 0xE12FFF1E) + { + cardiSetCardDma = ArmHelper::GetArmCallAddress((u32*)((u8*)_cardiTryReadCardDma + 0x148)); + } + else + { + cardiSetCardDma = ArmHelper::GetArmCallAddress((u32*)((u8*)_cardiTryReadCardDma + 0x14C)); + } + cardiSetCardDmaDmaCopyCallOffset = 0x18; + cardiOnReadCardDisableIrqCallOffset = 0x44; + cardiOnReadCardPatchOffset = 0x40; + } + else if (_foundPattern == sCARDiTryReadCardDmaPatternSdk3017534) + { + cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x158) + 4; + cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x168); + cardiSetCardDma = ArmHelper::GetArmCallAddress((u32*)((u8*)_cardiTryReadCardDma + 0x148)); + cardiSetCardDmaDmaCopyCallOffset = 0x18; + cardiOnReadCardDisableIrqCallOffset = 0x44; + cardiOnReadCardPatchOffset = 0x40; + } + else if (_foundPattern == sCARDiTryReadCardDmaPatternSdk3027530) + { + cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x160) + 4; + cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x170); + cardiSetCardDma = ArmHelper::GetArmCallAddress((u32*)((u8*)_cardiTryReadCardDma + 0x14C)); + cardiSetCardDmaDmaCopyCallOffset = 0x18; + cardiOnReadCardDisableIrqCallOffset = 0x44; + cardiOnReadCardPatchOffset = 0x40; + } + else if (_foundPattern == sCARDiTryReadCardDmaPatternSdk4007530) + { + cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x150) + 4; + cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x160); + cardiSetCardDma = ArmHelper::GetArmCallAddress((u32*)((u8*)_cardiTryReadCardDma + 0x144)); + cardiSetCardDmaDmaCopyCallOffset = 0x1C; + cardiOnReadCardDisableIrqCallOffset = 0x4C; + cardiOnReadCardPatchOffset = 0x48; + } + else if (_foundPattern == sCARDiTryReadCardDmaPatternSdk4007532) + { + cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x178) + 4; + cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x188); + cardiSetCardDma = ArmHelper::GetArmCallAddress((u32*)((u8*)_cardiTryReadCardDma + 0x16C)); + cardiSetCardDmaDmaCopyCallOffset = 0x1C; + cardiOnReadCardDisableIrqCallOffset = 0x4C; + cardiOnReadCardPatchOffset = 0x48; + } + else if (_foundPattern == sCARDiTryReadCardDmaPatternSdk4027539SpiritTracks) + { + cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x180) + 4; + cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x190); + cardiSetCardDma = ArmHelper::GetArmCallAddress((u32*)((u8*)_cardiTryReadCardDma + 0x174)); + cardiSetCardDmaDmaCopyCallOffset = 0x1C; + cardiOnReadCardDisableIrqCallOffset = 0x4C; + cardiOnReadCardPatchOffset = 0x48; + } + else + { + LOG_DEBUG("Unsupported ARM CARDi_TryReadCardDma signature\n"); + ApplyReturnFalsePatch(); + return; + } + } + + // 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 and OS_DisableIrqMask are relative, but we need their final locations to call them later + u32 miiCardDmaCopy32 = resolveCallWithAutoload(cardiSetCardDma + cardiSetCardDmaDmaCopyCallOffset, autoloadAdjuster, _thumb); + u32 osDisableIrqMask = resolveCallWithAutoload(cardiOnReadCard + cardiOnReadCardDisableIrqCallOffset, autoloadAdjuster, _thumb); + + // begin with patching + auto sdReadDmaPatchCode = patchContext.GetLoaderPlatform()->CreateSdReadDmaPatchCode( + patchContext.GetPatchCodeCollection(), patchContext.GetPatchHeap(), (const void*)miiCardDmaCopy32); + auto romOffsetToSdSectorPatchCode = patchContext.GetPatchCodeCollection().GetOrAddSharedPatchCode([&] + { + return new RomOffsetToSdSectorPatchCode(patchContext.GetPatchHeap(), + (const rom_file_info_t*)((u32)SHARED_ROM_FILE_INFO - 0x02F00000 + 0x02700000)); + }); + auto cardiSetCardDmaPatchCode = patchContext.GetPatchCodeCollection().AddUniquePatchCode + ( + patchContext.GetPatchHeap(), + romOffsetToSdSectorPatchCode, + sdReadDmaPatchCode, + (const void*)cardiCommon, + (const void*)osDisableIrqMask + ); + + if (_thumb) + { + // patch CARDi_SetCardDma + *(u16*)(cardiSetCardDma + 0) = 0x4800; // ldr r0,= entryAddress + *(u16*)(cardiSetCardDma + 2) = 0x4700; // bx r0 + *(u32*)(cardiSetCardDma + 4) = (u32)cardiSetCardDmaPatchCode->GetCardiSetCardDmaFunction(); + + // patch CARDi_OnReadCard + if (patchUsingPool) + { + *(u16*)(cardiOnReadCard + cardiOnReadCardPatchOffset) = 0x4780; // blx r0 (pre-loaded from pool) + *(u32*)(cardiOnReadCard + cardiOnReadCardPoolOffset) = (u32)cardiSetCardDmaPatchCode->GetCardiOnReadCardPatchFunction(); + } + else + { + *(u16*)(cardiOnReadCard + cardiOnReadCardPatchOffset + 0) = 0x4800; // ldr r0,= entryAddress + *(u16*)(cardiOnReadCard + cardiOnReadCardPatchOffset + 2) = 0x4780; // blx r0 + *(u32*)(cardiOnReadCard + cardiOnReadCardPatchOffset + 4) = (u32)cardiSetCardDmaPatchCode->GetCardiOnReadCardPatchFunction(); + *(u16*)(cardiOnReadCard + cardiOnReadCardPatchOffset + 8) = 0x4600; // nop + } + } + else + { + // patch CARDi_SetCardDma + *(u32*)(cardiSetCardDma + 0) = 0xE51FF004; // ldr pc,= entryAddress + *(u32*)(cardiSetCardDma + 4) = (u32)cardiSetCardDmaPatchCode->GetCardiSetCardDmaFunction(); + + // patch CARDi_OnReadCard + *(u32*)(cardiOnReadCard + cardiOnReadCardPatchOffset + 0) = 0xE59F0000; // ldr r0,= entryAddress + *(u32*)(cardiOnReadCard + cardiOnReadCardPatchOffset + 4) = 0xE12FFF30; // blx r0 + *(u32*)(cardiOnReadCard + cardiOnReadCardPatchOffset + 8) = (u32)cardiSetCardDmaPatchCode->GetCardiOnReadCardPatchFunction(); + } + + LOG_DEBUG("DMA enabled\n"); } diff --git a/arm9/source/patches/arm9/sdk2to4/CardiTryReadCardDmaPatch.h b/arm9/source/patches/arm9/sdk2to4/CardiTryReadCardDmaPatch.h index e3a37f3..69b4b54 100644 --- a/arm9/source/patches/arm9/sdk2to4/CardiTryReadCardDmaPatch.h +++ b/arm9/source/patches/arm9/sdk2to4/CardiTryReadCardDmaPatch.h @@ -14,4 +14,5 @@ private: const u32* _foundPattern = nullptr; void TryPattern(PatchContext& patchContext, const u32* pattern); + void ApplyReturnFalsePatch(); }; diff --git a/data/patchlist.json b/data/patchlist.json index 79ec9d9..408d1be 100644 --- a/data/patchlist.json +++ b/data/patchlist.json @@ -284,7 +284,7 @@ { "type": "replace", "address": "0205653C", - "data": "03 00 58 6F 01 38 08 D0 05 DF 58 6F 01 38 04 D0 90 20 18 58 01 28 00 D0", + "data": "20 B5 05 00 68 6F 01 38 07 D0 05 DF 68 6F 01 38 03 D0 90 21 68 58 40 00 01 38 20 BD", } ] }, @@ -295,7 +295,7 @@ { "type": "replace", "address": "0205653C", - "data": "03 00 58 6F 01 38 08 D0 05 DF 58 6F 01 38 04 D0 90 20 18 58 01 28 00 D0", + "data": "20 B5 05 00 68 6F 01 38 07 D0 05 DF 68 6F 01 38 03 D0 90 21 68 58 40 00 01 38 20 BD", } ] },