mirror of
https://github.com/LNH-team/pico-loader.git
synced 2026-06-02 01:06:50 +02:00
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:
@@ -57,83 +57,88 @@ 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 (moduleParams)
|
if (romHeader->gameCode == GAMECODE("AS2E"))
|
||||||
{
|
{
|
||||||
LOG_DEBUG("Module params found at 0x%p\n", moduleParams);
|
// Spider-Man 2 (USA) is probably the only game without module params
|
||||||
LOG_DEBUG("Sdk version: 0x%x\n", moduleParams->sdkVersion);
|
sdkVersion = 0x02004F50;
|
||||||
const u32* miiUncompressBackward = nullptr;
|
arm9Autoload = std::make_unique<AutoloadAdjuster<autoload_list_entry_t>>(
|
||||||
if (moduleParams->compressedEnd)
|
(autoload_list_entry_t*)0x0215DBA0,
|
||||||
{
|
(autoload_list_entry_t*)0x0215DBB8,
|
||||||
miiUncompressBackward = FindMIiUncompressBackward(romHeader->arm9LoadAddress, sdkVersion);
|
0x02157CC0);
|
||||||
if (miiUncompressBackward)
|
|
||||||
{
|
|
||||||
arm9Size = moduleParams->compressedEnd + *(u32*)(moduleParams->compressedEnd - 4) - romHeader->arm9LoadAddress;
|
|
||||||
((uncompress_func_t)miiUncompressBackward)((void*)moduleParams->compressedEnd);
|
|
||||||
compressedEnd = moduleParams->compressedEnd;
|
|
||||||
moduleParams->compressedEnd = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LOG_DEBUG("MIi_UncompressBackward not found\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sdkVersion.IsTwlSdk())
|
|
||||||
{
|
|
||||||
arm9Autoload = std::make_unique<AutoloadAdjuster<autoload_list_entry_sdk5_t>>(
|
|
||||||
(autoload_list_entry_sdk5_t*)moduleParams->autoloadListStart,
|
|
||||||
(autoload_list_entry_sdk5_t*)moduleParams->autoloadListEnd,
|
|
||||||
moduleParams->autoloadStart);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
arm9Autoload = std::make_unique<AutoloadAdjuster<autoload_list_entry_t>>(
|
|
||||||
(autoload_list_entry_t*)moduleParams->autoloadListStart,
|
|
||||||
(autoload_list_entry_t*)moduleParams->autoloadListEnd,
|
|
||||||
moduleParams->autoloadStart);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gIsDsiMode && romHeader->SupportsDsiMode())
|
|
||||||
{
|
|
||||||
auto arm9iModuleParams = (module_params_twl_t*)(romHeader->arm9LoadAddress + twlRomHeader->arm9iModuleParamsAddress);
|
|
||||||
if (arm9iModuleParams->magicBigEndian == MODULE_PARAMS_TWL_MAGIC_BE &&
|
|
||||||
arm9iModuleParams->magicLittleEndian == MODULE_PARAMS_TWL_MAGIC_LE)
|
|
||||||
{
|
|
||||||
if (arm9iModuleParams->compressedEnd != 0)
|
|
||||||
{
|
|
||||||
LOG_DEBUG("Compressed arm9i found\n");
|
|
||||||
if (miiUncompressBackward)
|
|
||||||
{
|
|
||||||
arm9iSize = arm9iModuleParams->compressedEnd + *(u32*)(arm9iModuleParams->compressedEnd - 4) - twlRomHeader->arm9iLoadAddress;
|
|
||||||
((uncompress_func_t)miiUncompressBackward)((void*)arm9iModuleParams->compressedEnd);
|
|
||||||
arm9iModuleParams->compressedEnd = 0;
|
|
||||||
LOG_DEBUG("Decompressed arm9i\n");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LOG_DEBUG("Could not decompress arm9i\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
arm9iAutoload = std::make_unique<AutoloadAdjuster<autoload_list_entry_sdk5_t>>(
|
|
||||||
(autoload_list_entry_sdk5_t*)arm9iModuleParams->autoloadListStart,
|
|
||||||
(autoload_list_entry_sdk5_t*)arm9iModuleParams->autoloadListEnd,
|
|
||||||
arm9iModuleParams->autoloadStart);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOG_DEBUG("Module params not found!\n");
|
moduleParams = ModuleParamsLocator().FindModuleParams(romHeader);
|
||||||
if (romHeader->gameCode == GAMECODE("AS2E"))
|
if (moduleParams)
|
||||||
{
|
{
|
||||||
// Spider-Man 2 (USA) is probably the only game without module params
|
LOG_DEBUG("Module params found at 0x%p\n", moduleParams);
|
||||||
sdkVersion = 0x02004F50;
|
sdkVersion = moduleParams->sdkVersion;
|
||||||
arm9Autoload = std::make_unique<AutoloadAdjuster<autoload_list_entry_t>>(
|
LOG_DEBUG("Sdk version: 0x%x\n", sdkVersion);
|
||||||
(autoload_list_entry_t*)0x0215DBA0,
|
const u32* miiUncompressBackward = nullptr;
|
||||||
(autoload_list_entry_t*)0x0215DBB8,
|
if (moduleParams->compressedEnd)
|
||||||
0x02157CC0);
|
{
|
||||||
|
miiUncompressBackward = FindMIiUncompressBackward(romHeader->arm9LoadAddress, sdkVersion);
|
||||||
|
if (miiUncompressBackward)
|
||||||
|
{
|
||||||
|
arm9Size = moduleParams->compressedEnd + *(u32*)(moduleParams->compressedEnd - 4) - romHeader->arm9LoadAddress;
|
||||||
|
((uncompress_func_t)miiUncompressBackward)((void*)moduleParams->compressedEnd);
|
||||||
|
compressedEnd = moduleParams->compressedEnd;
|
||||||
|
moduleParams->compressedEnd = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG_ERROR("MIi_UncompressBackward not found\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sdkVersion.IsTwlSdk())
|
||||||
|
{
|
||||||
|
arm9Autoload = std::make_unique<AutoloadAdjuster<autoload_list_entry_sdk5_t>>(
|
||||||
|
(autoload_list_entry_sdk5_t*)moduleParams->autoloadListStart,
|
||||||
|
(autoload_list_entry_sdk5_t*)moduleParams->autoloadListEnd,
|
||||||
|
moduleParams->autoloadStart);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
arm9Autoload = std::make_unique<AutoloadAdjuster<autoload_list_entry_t>>(
|
||||||
|
(autoload_list_entry_t*)moduleParams->autoloadListStart,
|
||||||
|
(autoload_list_entry_t*)moduleParams->autoloadListEnd,
|
||||||
|
moduleParams->autoloadStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gIsDsiMode && romHeader->SupportsDsiMode())
|
||||||
|
{
|
||||||
|
auto arm9iModuleParams = (module_params_twl_t*)(romHeader->arm9LoadAddress + twlRomHeader->arm9iModuleParamsAddress);
|
||||||
|
if (arm9iModuleParams->magicBigEndian == MODULE_PARAMS_TWL_MAGIC_BE &&
|
||||||
|
arm9iModuleParams->magicLittleEndian == MODULE_PARAMS_TWL_MAGIC_LE)
|
||||||
|
{
|
||||||
|
if (arm9iModuleParams->compressedEnd != 0)
|
||||||
|
{
|
||||||
|
LOG_DEBUG("Compressed arm9i found\n");
|
||||||
|
if (miiUncompressBackward)
|
||||||
|
{
|
||||||
|
arm9iSize = arm9iModuleParams->compressedEnd + *(u32*)(arm9iModuleParams->compressedEnd - 4) - twlRomHeader->arm9iLoadAddress;
|
||||||
|
((uncompress_func_t)miiUncompressBackward)((void*)arm9iModuleParams->compressedEnd);
|
||||||
|
arm9iModuleParams->compressedEnd = 0;
|
||||||
|
LOG_DEBUG("Decompressed arm9i\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG_ERROR("Could not decompress arm9i\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
arm9iAutoload = std::make_unique<AutoloadAdjuster<autoload_list_entry_sdk5_t>>(
|
||||||
|
(autoload_list_entry_sdk5_t*)arm9iModuleParams->autoloadListStart,
|
||||||
|
(autoload_list_entry_sdk5_t*)arm9iModuleParams->autoloadListEnd,
|
||||||
|
arm9iModuleParams->autoloadStart);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG_ERROR("Module params not found!\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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++)
|
||||||
|
|||||||
Reference in New Issue
Block a user