Improved handling of DSi roms and DSiWare. Fixes some system tools DSi roms being misdetected as DSiWare (related to #23)

This commit is contained in:
Gericom
2025-12-06 19:56:48 +01:00
parent 0d0fa445c9
commit 656f696411
6 changed files with 84 additions and 75 deletions

View File

@@ -165,9 +165,9 @@ void NdsLoader::Load(BootMode bootMode)
}
}
bool isHomebrew = (_romHeader.ntrHeader.makerCode[0] == 0 && _romHeader.ntrHeader.makerCode[1] == 0)
|| _romHeader.ntrHeader.arm9AutoLoadDoneHookAddress == 0
|| _romHeader.ntrHeader.arm7LoadAddress >= 0x03000000;
bool isHomebrew = (_romHeader.makerCode[0] == 0 && _romHeader.makerCode[1] == 0)
|| _romHeader.arm9AutoLoadDoneHookAddress == 0
|| _romHeader.arm7LoadAddress >= 0x03000000;
if (isHomebrew)
{
@@ -186,16 +186,7 @@ void NdsLoader::Load(BootMode bootMode)
memset(&_dsiwareSaveResult, 0, sizeof(_dsiwareSaveResult));
if (bootMode != BootMode::Multiboot)
{
if (!_romHeader.IsDsiWare())
{
if (bootMode != BootMode::SdkResetSystem)
{
HandleCardSave();
}
HandleAntiPiracy();
}
else
if (_romHeader.IsDsiWare())
{
if (bootMode == BootMode::SdkResetSystem)
{
@@ -210,6 +201,15 @@ void NdsLoader::Load(BootMode bootMode)
return;
}
}
else
{
if (bootMode != BootMode::SdkResetSystem)
{
HandleCardSave();
}
HandleAntiPiracy();
}
}
}
@@ -224,14 +224,14 @@ void NdsLoader::Load(BootMode bootMode)
SetupSharedMemory(cardId, agbMem, resetParam, romOffset, bootType);
if (Environment::IsDsiMode() && _romHeader.IsTwlRom())
{
SetupTwlConfig();
TwlAes().SetupAes(&_romHeader);
}
if (Environment::IsDsiMode())
{
if (_romHeader.IsTwlRom())
{
SetupTwlConfig();
TwlAes().SetupAes(&_romHeader);
}
RemapWram();
}
@@ -321,20 +321,20 @@ void NdsLoader::Load(BootMode bootMode)
if (Environment::IsDsiMode())
{
if (!_romHeader.IsTwlRom())
{
DSMode().SwitchToDSMode(_romHeader.ntrHeader.gameCode);
}
else
if (_romHeader.IsTwlRom())
{
if (!(_romHeader.twlFlags2 & 1))
{
DSMode().SwitchToDSTouchAndSoundMode(_romHeader.ntrHeader.gameCode);
DSMode().SwitchToDSTouchAndSoundMode(_romHeader.gameCode);
}
// Set back power button handling to irq mode
mcu_writeReg(MCU_REG_MODE, 1);
}
else
{
DSMode().SwitchToDSMode(_romHeader.gameCode);
}
}
if (isHomebrew)
@@ -349,11 +349,11 @@ void NdsLoader::Load(BootMode bootMode)
bool NdsLoader::IsCloneBootRom(u32 romOffset)
{
bool isCloneBootRom = false;
if (_romHeader.ntrHeader.ntrRomSize != 0)
if (_romHeader.ntrRomSize != 0)
{
UINT bytesRead = 0;
u16 signatureHeader;
if (f_lseek(&_romFile, romOffset + _romHeader.ntrHeader.ntrRomSize) == FR_OK &&
if (f_lseek(&_romFile, romOffset + _romHeader.ntrRomSize) == FR_OK &&
f_read(&_romFile, &signatureHeader, sizeof(signatureHeader), &bytesRead) == FR_OK &&
bytesRead == 2 &&
signatureHeader == 0x6361)
@@ -371,7 +371,7 @@ void NdsLoader::InsertArgv()
u32 argSize = 0;
// Find the address to write argv
u32 argDst = ((_romHeader.ntrHeader.arm9LoadAddress + _romHeader.ntrHeader.arm9Size + 3) & ~3) + 4;
u32 argDst = ((_romHeader.arm9LoadAddress + _romHeader.arm9Size + 3) & ~3) + 4;
if (_romHeader.IsTwlRom())
{
u32 argDstTwl = ((_romHeader.arm9iLoadAddress + _romHeader.arm9iSize + 3) & ~3) + 4;
@@ -475,8 +475,8 @@ void NdsLoader::SetupSharedMemory(u32 cardId, u32 agbMem, u32 resetParam, u32 ro
memcpy(TWL_SHARED_MEMORY->ntrSharedMem.romHeader, &_romHeader, sizeof(nds_header_ntr_t));
*(vu32*)&TWL_SHARED_MEMORY->ntrSharedMem.bootCheckInfo[0] = cardId;
*(vu32*)&TWL_SHARED_MEMORY->ntrSharedMem.bootCheckInfo[4] = cardId;
*(vu16*)&TWL_SHARED_MEMORY->ntrSharedMem.bootCheckInfo[8] = _romHeader.ntrHeader.headerCrc;
*(vu16*)&TWL_SHARED_MEMORY->ntrSharedMem.bootCheckInfo[0xA] = _romHeader.ntrHeader.secureAreaCrc;
*(vu16*)&TWL_SHARED_MEMORY->ntrSharedMem.bootCheckInfo[8] = _romHeader.headerCrc;
*(vu16*)&TWL_SHARED_MEMORY->ntrSharedMem.bootCheckInfo[0xA] = _romHeader.secureAreaCrc;
*(vu32*)&TWL_SHARED_MEMORY->ntrSharedMem.bootCheckInfo[0x10] = 0x5835; // use correct card id address
*(vu32*)&TWL_SHARED_MEMORY->ntrSharedMem.isDebuggerData[0x1C] = agbMem;
TWL_SHARED_MEMORY->ntrSharedMem.resetParam = resetParam;
@@ -536,7 +536,7 @@ bool NdsLoader::ShouldAttemptDldiPatch()
{
// Some games contain a fake dldi header to trick flashcards
// See also: https://shutterbug2000.github.io/very-clever/
switch (_romHeader.ntrHeader.gameCode)
switch (_romHeader.gameCode)
{
// Final Fantasy IV
case GAMECODE("YF4P"):
@@ -610,7 +610,7 @@ bool NdsLoader::TryLoadRomHeader(u32 romOffset)
void NdsLoader::HandleCardSave()
{
if (!CardSaveArranger().SetupCardSave(_romHeader.ntrHeader.gameCode, _savePath))
if (!CardSaveArranger().SetupCardSave(_romHeader.gameCode, _savePath))
{
ErrorDisplay().PrintError("Failed to setup save file.");
}
@@ -621,7 +621,7 @@ void NdsLoader::HandleAntiPiracy()
auto apList = ApListFactory().CreateFromFile(AP_LIST_PATH);
if (apList)
{
auto entry = apList->FindEntry(_romHeader.ntrHeader.gameCode, _romHeader.ntrHeader.softwareVersion);
auto entry = apList->FindEntry(_romHeader.gameCode, _romHeader.softwareVersion);
if (entry)
{
entry->Dump();
@@ -683,15 +683,15 @@ void NdsLoader::RemapWram()
bool NdsLoader::TryLoadArm9()
{
if (f_lseek(&_romFile, _romHeader.ntrHeader.arm9RomOffset + TWL_SHARED_MEMORY->ntrSharedMem.romOffset) != FR_OK)
if (f_lseek(&_romFile, _romHeader.arm9RomOffset + TWL_SHARED_MEMORY->ntrSharedMem.romOffset) != FR_OK)
{
LOG_FATAL("Failed to seek to arm9\n");
return false;
}
UINT bytesRead = 0;
FRESULT result = f_read(&_romFile, (void*)_romHeader.ntrHeader.arm9LoadAddress, _romHeader.ntrHeader.arm9Size, &bytesRead);
if (result != FR_OK || bytesRead != _romHeader.ntrHeader.arm9Size)
FRESULT result = f_read(&_romFile, (void*)_romHeader.arm9LoadAddress, _romHeader.arm9Size, &bytesRead);
if (result != FR_OK || bytesRead != _romHeader.arm9Size)
{
LOG_FATAL("Failed to read arm9. Result: %d, bytesRead: %d\n", result, bytesRead);
return false;
@@ -736,7 +736,7 @@ bool NdsLoader::TryLoadArm9i()
bool NdsLoader::TryDecryptArm9i()
{
if (!(_romHeader.ntrHeader.twlFlags & (1 << 1)))
if (!(_romHeader.twlFlags & (1 << 1)))
{
return true;
}
@@ -756,7 +756,7 @@ bool NdsLoader::TryDecryptArm9i()
bool NdsLoader::TryDecryptArm7i()
{
if (!(_romHeader.ntrHeader.twlFlags & (1 << 1)) || _romHeader.modcryptArea2Size == 0)
if (!(_romHeader.twlFlags & (1 << 1)) || _romHeader.modcryptArea2Size == 0)
{
return true;
}
@@ -776,15 +776,15 @@ bool NdsLoader::TryDecryptArm7i()
bool NdsLoader::TryLoadArm7()
{
if (f_lseek(&_romFile, _romHeader.ntrHeader.arm7RomOffset + TWL_SHARED_MEMORY->ntrSharedMem.romOffset) != FR_OK)
if (f_lseek(&_romFile, _romHeader.arm7RomOffset + TWL_SHARED_MEMORY->ntrSharedMem.romOffset) != FR_OK)
{
LOG_FATAL("Failed to seek to arm7\n");
return false;
}
UINT bytesRead = 0;
FRESULT result = f_read(&_romFile, (void*)_romHeader.ntrHeader.arm7LoadAddress, _romHeader.ntrHeader.arm7Size, &bytesRead);
if (result != FR_OK || bytesRead != _romHeader.ntrHeader.arm7Size)
FRESULT result = f_read(&_romFile, (void*)_romHeader.arm7LoadAddress, _romHeader.arm7Size, &bytesRead);
if (result != FR_OK || bytesRead != _romHeader.arm7Size)
{
LOG_FATAL("Failed to read arm7. Result: %d, bytesRead: %d\n", result, bytesRead);
return false;
@@ -828,19 +828,19 @@ void NdsLoader::HandleDldiPatching()
}
int arm9DldiAddr = sDldiStubMatcher.FindFirstOccurance(
(const u32*)_romHeader.ntrHeader.arm9LoadAddress, _romHeader.ntrHeader.arm9Size >> 2) << 2;
(const u32*)_romHeader.arm9LoadAddress, _romHeader.arm9Size >> 2) << 2;
if (arm9DldiAddr >= 0)
{
dldi_header_t* arm9Dldi = (dldi_header_t*)(_romHeader.ntrHeader.arm9LoadAddress + arm9DldiAddr);
dldi_header_t* arm9Dldi = (dldi_header_t*)(_romHeader.arm9LoadAddress + arm9DldiAddr);
LOG_DEBUG("Dldi found in arm9 at address %p\n", arm9Dldi);
dldi_patchTo(arm9Dldi);
}
int arm7DldiAddr = sDldiStubMatcher.FindFirstOccurance(
(const u32*)_romHeader.ntrHeader.arm7LoadAddress, _romHeader.ntrHeader.arm7Size >> 2) << 2;
(const u32*)_romHeader.arm7LoadAddress, _romHeader.arm7Size >> 2) << 2;
if (arm7DldiAddr >= 0)
{
dldi_header_t* arm7Dldi = (dldi_header_t*)(_romHeader.ntrHeader.arm7LoadAddress + arm7DldiAddr);
dldi_header_t* arm7Dldi = (dldi_header_t*)(_romHeader.arm7LoadAddress + arm7DldiAddr);
LOG_DEBUG("Dldi found in arm7 at address %p\n", arm7Dldi);
dldi_patchTo(arm7Dldi);
}
@@ -860,7 +860,7 @@ void NdsLoader::StartRom(BootMode bootMode)
REG_IF2 = ~0u;
}
((entrypoint_t)_romHeader.ntrHeader.arm7EntryAddress)();
((entrypoint_t)_romHeader.arm7EntryAddress)();
}
void NdsLoader::SetupTwlConfig()
@@ -970,20 +970,20 @@ bool NdsLoader::TrySetupDsiWareSave()
bool NdsLoader::TryDecryptSecureArea()
{
if (_romHeader.ntrHeader.arm9RomOffset < 0x4000 || _romHeader.ntrHeader.arm9RomOffset >= 0x8000)
if (_romHeader.arm9RomOffset < 0x4000 || _romHeader.arm9RomOffset >= 0x8000)
{
return true;
}
if (((u32*)_romHeader.ntrHeader.arm9LoadAddress)[0] == 0xE7FFDEFF &&
((u32*)_romHeader.ntrHeader.arm9LoadAddress)[1] == 0xE7FFDEFF)
if (((u32*)_romHeader.arm9LoadAddress)[0] == 0xE7FFDEFF &&
((u32*)_romHeader.arm9LoadAddress)[1] == 0xE7FFDEFF)
{
return true;
}
u16 secureAreaCrc = swi_getCrc16(0xFFFF,
(const void*)_romHeader.ntrHeader.arm9LoadAddress, 0x8000 - _romHeader.ntrHeader.arm9RomOffset);
if (secureAreaCrc != _romHeader.ntrHeader.secureAreaCrc)
(const void*)_romHeader.arm9LoadAddress, 0x8000 - _romHeader.arm9RomOffset);
if (secureAreaCrc != _romHeader.secureAreaCrc)
{
return true;
}
@@ -1000,13 +1000,13 @@ bool NdsLoader::TryDecryptSecureArea()
}
auto blowfish = std::make_unique<Blowfish>(keyTable.get());
blowfish->TransformTable(_romHeader.ntrHeader.gameCode, 3, 8);
blowfish->TransformTable(_romHeader.gameCode, 3, 8);
blowfish->Decrypt(
(const void*)_romHeader.ntrHeader.arm9LoadAddress,
(void*)_romHeader.ntrHeader.arm9LoadAddress,
0x4800 - _romHeader.ntrHeader.arm9RomOffset);
((u32*)_romHeader.ntrHeader.arm9LoadAddress)[0] = 0xE7FFDEFF;
((u32*)_romHeader.ntrHeader.arm9LoadAddress)[1] = 0xE7FFDEFF;
(const void*)_romHeader.arm9LoadAddress,
(void*)_romHeader.arm9LoadAddress,
0x4800 - _romHeader.arm9RomOffset);
((u32*)_romHeader.arm9LoadAddress)[0] = 0xE7FFDEFF;
((u32*)_romHeader.arm9LoadAddress)[1] = 0xE7FFDEFF;
LOG_DEBUG("Decrypted secure area\n");
return true;

View File

@@ -104,7 +104,7 @@ void TwlAes::DecryptModuleAes(void* data, u32 length, const aes_u128_t* iv) cons
void TwlAes::SetupModuleKeyXY(const nds_header_twl_t* romHeader) const
{
if ((romHeader->ntrHeader.twlFlags & (1 << 2)) || (romHeader->twlFlags2 & (1 << 7)))
if ((romHeader->twlFlags & (1 << 2)) || (romHeader->twlFlags2 & (1 << 7)))
{
// debug
aes_setKey(KEY_SLOT_MODULE, (const aes_u128_t*)romHeader);
@@ -116,8 +116,8 @@ void TwlAes::SetupModuleKeyXY(const nds_header_twl_t* romHeader) const
{
MODULE_KEYX_NINT,
MODULE_KEYX_ENDO,
romHeader->ntrHeader.gameCode,
__builtin_bswap32(romHeader->ntrHeader.gameCode)
romHeader->gameCode,
__builtin_bswap32(romHeader->gameCode)
}};
aes_setKeyXY(KEY_SLOT_MODULE, &keyX, (const aes_u128_t*)romHeader->arm9iSha1Hmac);
}

View File

@@ -49,15 +49,18 @@ void* Arm7Patcher::ApplyPatches(const LoaderPlatform* loaderPlatform) const
patchCollection.AddPatch(arm7ArenaPatch);
if (romHeader->unitCode == 0) // seems only present on NITRO, not on HYBRID or LIMITED
{
patchCollection.AddPatch(new DisableArm7WramClearPatch());
}
if (sdkVersion.IsTwlSdk())
{
if (gIsDsiMode && romHeader->IsTwlRom() && twlRomHeader->IsDsiWare())
if (gIsDsiMode && (twlRomHeader->HasNandAccess() || twlRomHeader->HasSdAccess()))
{
patchCollection.AddPatch(new Sdk5DsiSdCardRedirectPatch());
}
else
if (!twlRomHeader->IsDsiWare())
{
patchCollection.AddPatch(new CardiDoTaskFromArm9Patch());
}

View File

@@ -153,14 +153,13 @@ void Arm9Patcher::ApplyPatches(const LoaderPlatform* loaderPlatform, const ApLis
}
else
{
SecureSysCallsUnusedSpaceLocator secureSysCallsUnusedSpaceLocator;
secureSysCallsUnusedSpaceLocator.FindUnusedSpace(romHeader, patchContext.GetPatchHeap());
SecureSysCallsUnusedSpaceLocator().FindUnusedSpace(romHeader, patchContext.GetPatchHeap());
}
}
if (sdkVersion.IsTwlSdk())
{
if (!(romHeader->IsTwlRom() && twlRomHeader->IsDsiWare()))
if (!twlRomHeader->IsDsiWare())
{
// if ((romHeader->unitCode & 3) != 3)
{
@@ -168,7 +167,7 @@ void Arm9Patcher::ApplyPatches(const LoaderPlatform* loaderPlatform, const ApLis
}
patchCollection.AddPatch(new CardiReadRomWithCpuPatch());
if (gIsDsiMode && (romHeader->unitCode & 2))
if (gIsDsiMode && romHeader->IsTwlRom())
{
patchCollection.AddPatch(new CardiReadCardWithHashInternalAsyncPatch());
}

View File

@@ -67,7 +67,7 @@ static u32 correctAddressForArm7iAutoLoad(u32 address)
{
auto romHeader = (const nds_header_twl_t*)TWL_SHARED_MEMORY->twlRomHeader;
auto arm7iModuleParams = (const module_params_twl_t*)(
romHeader->ntrHeader.arm7LoadAddress + romHeader->arm7iModuleParamsAddress);
romHeader->arm7LoadAddress + romHeader->arm7iModuleParamsAddress);
auto autoLoadListEntry = (autoload_list_entry_sdk5_t*)arm7iModuleParams->autoloadListStart;
u32 currentAddress = arm7iModuleParams->autoloadStart;

View File

@@ -63,9 +63,11 @@ struct nds_header_ntr_t
static_assert(sizeof(nds_header_ntr_t) == 0x170, "Invalid size for nds_header_ntr_t");
struct nds_header_twl_t
#define NDS_HEADER_TWL_ACCESS_CONTROL_SD_ACCESS (1 << 3)
#define NDS_HEADER_TWL_ACCESS_CONTROL_NAND_ACCESS (1 << 4)
struct nds_header_twl_t : public nds_header_ntr_t
{
nds_header_ntr_t ntrHeader;
u8 gap170[0x10];
u32 globalMbkSettings[5]; // slot mapping
u32 arm9MbkSettings[3]; // wram mapping
@@ -130,14 +132,19 @@ struct nds_header_twl_t
u8 gapF00[0x80];
u8 headerRsaSha1Signature[0x80];
constexpr bool IsTwlRom() const
{
return ntrHeader.IsTwlRom();
}
constexpr bool IsDsiWare() const
{
return IsTwlRom() && ((titleId >> 32) & 0xFF) != 0;
return IsTwlRom() && ((titleId >> 32) & 4) != 0;
}
constexpr bool HasSdAccess() const
{
return IsTwlRom() && (accessControl & NDS_HEADER_TWL_ACCESS_CONTROL_SD_ACCESS) != 0;
}
constexpr bool HasNandAccess() const
{
return IsTwlRom() && (accessControl & NDS_HEADER_TWL_ACCESS_CONTROL_NAND_ACCESS) != 0;
}
};