Improved handling of module params and locating of unused libsyscall space to support rom hacks that repack roms in unusual ways. Fixes #129

This commit is contained in:
Gericom
2026-02-01 11:04:59 +01:00
parent f5a8498e08
commit df614fb89f
4 changed files with 100 additions and 93 deletions

View File

@@ -57,12 +57,25 @@ void Arm9Patcher::ApplyPatches(const LoaderPlatform* loaderPlatform, const ApLis
u32 compressedEnd = 0; u32 compressedEnd = 0;
std::unique_ptr<IAutoloadAdjuster> arm9Autoload; std::unique_ptr<IAutoloadAdjuster> arm9Autoload;
std::unique_ptr<IAutoloadAdjuster> arm9iAutoload; std::unique_ptr<IAutoloadAdjuster> arm9iAutoload;
auto moduleParams = ModuleParamsLocator().FindModuleParams(romHeader); module_params_ntr_t* moduleParams = nullptr;
SdkVersion sdkVersion = moduleParams ? moduleParams->sdkVersion : 0u; SdkVersion sdkVersion = 0u;
if (romHeader->gameCode == GAMECODE("AS2E"))
{
// Spider-Man 2 (USA) is probably the only game without module params
sdkVersion = 0x02004F50;
arm9Autoload = std::make_unique<AutoloadAdjuster<autoload_list_entry_t>>(
(autoload_list_entry_t*)0x0215DBA0,
(autoload_list_entry_t*)0x0215DBB8,
0x02157CC0);
}
else
{
moduleParams = ModuleParamsLocator().FindModuleParams(romHeader);
if (moduleParams) if (moduleParams)
{ {
LOG_DEBUG("Module params found at 0x%p\n", moduleParams); LOG_DEBUG("Module params found at 0x%p\n", moduleParams);
LOG_DEBUG("Sdk version: 0x%x\n", moduleParams->sdkVersion); sdkVersion = moduleParams->sdkVersion;
LOG_DEBUG("Sdk version: 0x%x\n", sdkVersion);
const u32* miiUncompressBackward = nullptr; const u32* miiUncompressBackward = nullptr;
if (moduleParams->compressedEnd) if (moduleParams->compressedEnd)
{ {
@@ -76,7 +89,7 @@ void Arm9Patcher::ApplyPatches(const LoaderPlatform* loaderPlatform, const ApLis
} }
else else
{ {
LOG_DEBUG("MIi_UncompressBackward not found\n"); LOG_ERROR("MIi_UncompressBackward not found\n");
} }
} }
@@ -113,7 +126,7 @@ void Arm9Patcher::ApplyPatches(const LoaderPlatform* loaderPlatform, const ApLis
} }
else else
{ {
LOG_DEBUG("Could not decompress arm9i\n"); LOG_ERROR("Could not decompress arm9i\n");
} }
} }
arm9iAutoload = std::make_unique<AutoloadAdjuster<autoload_list_entry_sdk5_t>>( arm9iAutoload = std::make_unique<AutoloadAdjuster<autoload_list_entry_sdk5_t>>(
@@ -125,15 +138,7 @@ void Arm9Patcher::ApplyPatches(const LoaderPlatform* loaderPlatform, const ApLis
} }
else else
{ {
LOG_DEBUG("Module params not found!\n"); LOG_ERROR("Module params not found!\n");
if (romHeader->gameCode == GAMECODE("AS2E"))
{
// Spider-Man 2 (USA) is probably the only game without module params
sdkVersion = 0x02004F50;
arm9Autoload = std::make_unique<AutoloadAdjuster<autoload_list_entry_t>>(
(autoload_list_entry_t*)0x0215DBA0,
(autoload_list_entry_t*)0x0215DBB8,
0x02157CC0);
} }
} }
LOG_DEBUG("Arm9 region: 0x%x - 0x%x\n", romHeader->arm9LoadAddress, romHeader->arm9LoadAddress + arm9Size); LOG_DEBUG("Arm9 region: 0x%x - 0x%x\n", romHeader->arm9LoadAddress, romHeader->arm9LoadAddress + arm9Size);

View File

@@ -1,19 +1,26 @@
#include "common.h" #include "common.h"
#include "ModuleParamsLocator.h" #include "ModuleParamsLocator.h"
module_params_ntr_t* ModuleParamsLocator::FindModuleParams(const nds_header_ntr_t* romHeader) static bool isValidArm9Address(const nds_header_ntr_t* romHeader, const void* address)
{
return romHeader->arm9LoadAddress <= (u32)address && (u32)address < romHeader->arm9LoadAddress + romHeader->arm9Size;
}
module_params_ntr_t* ModuleParamsLocator::FindModuleParams(const nds_header_ntr_t* romHeader) const
{ {
//todo: static footer //todo: static footer
module_params_ntr_t* moduleParams = nullptr; module_params_ntr_t* moduleParams = nullptr;
if (romHeader->arm9ModuleParamsAddress != 0) if (romHeader->arm9ModuleParamsAddress != 0)
{ {
moduleParams = (module_params_ntr_t*)(romHeader->arm9LoadAddress + romHeader->arm9ModuleParamsAddress); moduleParams = (module_params_ntr_t*)(romHeader->arm9LoadAddress + romHeader->arm9ModuleParamsAddress);
if (moduleParams->magicBigEndian != MODULE_PARAMS_NTR_MAGIC_BE || if (!isValidArm9Address(romHeader, &moduleParams->magicLittleEndian) ||
moduleParams->magicBigEndian != MODULE_PARAMS_NTR_MAGIC_BE ||
moduleParams->magicLittleEndian != MODULE_PARAMS_NTR_MAGIC_LE) moduleParams->magicLittleEndian != MODULE_PARAMS_NTR_MAGIC_LE)
{ {
// try again by subtracting arm9 rom address // try again by subtracting arm9 rom address
moduleParams = (module_params_ntr_t*)((u8*)moduleParams - romHeader->arm9RomOffset); moduleParams = (module_params_ntr_t*)((u8*)moduleParams - romHeader->arm9RomOffset);
if (moduleParams->magicBigEndian != MODULE_PARAMS_NTR_MAGIC_BE || if (!isValidArm9Address(romHeader, &moduleParams->magicLittleEndian) ||
moduleParams->magicBigEndian != MODULE_PARAMS_NTR_MAGIC_BE ||
moduleParams->magicLittleEndian != MODULE_PARAMS_NTR_MAGIC_LE) moduleParams->magicLittleEndian != MODULE_PARAMS_NTR_MAGIC_LE)
{ {
LOG_DEBUG("Module params not found at header specified offset 0x%x\n", romHeader->arm9ModuleParamsAddress); LOG_DEBUG("Module params not found at header specified offset 0x%x\n", romHeader->arm9ModuleParamsAddress);
@@ -29,21 +36,6 @@ module_params_ntr_t* ModuleParamsLocator::FindModuleParams(const nds_header_ntr_
if (!moduleParams) if (!moduleParams)
{ {
// try searching for the module params as not all roms have the address in the header // try searching for the module params as not all roms have the address in the header
// it should be within the first 0x1000 bytes of the arm9
for (u32 i = 0; i < 0x1000; i += 4)
{
u32* ptr = (u32*)(romHeader->arm9LoadAddress + i);
if (ptr[0] == MODULE_PARAMS_NTR_MAGIC_BE && ptr[1] == MODULE_PARAMS_NTR_MAGIC_LE)
{
moduleParams = (module_params_ntr_t*)((u8*)ptr + 8 - sizeof(module_params_ntr_t));
break;
}
}
}
if (!moduleParams)
{
// as a last resort, scan the entire arm9 binary
for (u32 i = 0; i < romHeader->arm9Size; i += 4) for (u32 i = 0; i < romHeader->arm9Size; i += 4)
{ {
u32* ptr = (u32*)(romHeader->arm9LoadAddress + i); u32* ptr = (u32*)(romHeader->arm9LoadAddress + i);
@@ -53,6 +45,11 @@ module_params_ntr_t* ModuleParamsLocator::FindModuleParams(const nds_header_ntr_
break; break;
} }
} }
if (moduleParams != nullptr && (u32)moduleParams - romHeader->arm9LoadAddress > 0x1000)
{
LOG_WARNING("Module params not found in first 0x1000 bytes of arm9\n");
}
} }
return moduleParams; return moduleParams;

View File

@@ -9,5 +9,5 @@ public:
/// @brief Searches for the module params of the arm9 of the rom with the given \p romHeader. /// @brief Searches for the module params of the arm9 of the rom with the given \p romHeader.
/// @param romHeader The header of the rom. /// @param romHeader The header of the rom.
/// @return A pointer to the found module params, or \c nullptr if the module params could not be found. /// @return A pointer to the found module params, or \c nullptr if the module params could not be found.
module_params_ntr_t* FindModuleParams(const nds_header_ntr_t* romHeader); module_params_ntr_t* FindModuleParams(const nds_header_ntr_t* romHeader) const;
}; };

View File

@@ -78,8 +78,7 @@ const u16* SecureSysCallsUnusedSpaceLocator::FindPattern(const u16* data, u32 le
void SecureSysCallsUnusedSpaceLocator::FindUnusedSpace(const nds_header_ntr_t* romHeader, PatchHeap& patchHeap) const void SecureSysCallsUnusedSpaceLocator::FindUnusedSpace(const nds_header_ntr_t* romHeader, PatchHeap& patchHeap) const
{ {
if (romHeader->arm9RomOffset != 0x4000) // NOTE: We can not check if arm9RomOffset == 0x4000, because some rom hacks repack the rom in unusual ways.
return;
u32 secureStart = romHeader->arm9LoadAddress; u32 secureStart = romHeader->arm9LoadAddress;
@@ -91,6 +90,12 @@ void SecureSysCallsUnusedSpaceLocator::FindUnusedSpace(const nds_header_ntr_t* r
return; return;
} }
if (((u32*)secureStart)[0] != 0xE7FFDEFF || ((u32*)secureStart)[1] != 0xE7FFDEFF)
{
LOG_ERROR("No secure area space found\n");
return;
}
std::array<svc_pattern_t, sSvcPatterns.size()> patternLocations; std::array<svc_pattern_t, sSvcPatterns.size()> patternLocations;
for (u32 i = 0; i < sSvcPatterns.size(); i++) for (u32 i = 0; i < sSvcPatterns.size(); i++)