Add title version support to loader, only apply userland patches to suitable title versions, report used console and safe mode boots to loader separately from the config, remove eShop update check patch as older eShop version would fail anyway and it causes issues with background updates
This commit is contained in:
parent
3eaa706ccf
commit
9b724d776e
@ -9,7 +9,7 @@ typedef struct __attribute__((packed))
|
|||||||
u8 versionMajor;
|
u8 versionMajor;
|
||||||
u8 versionMinor;
|
u8 versionMinor;
|
||||||
u8 versionBuild;
|
u8 versionBuild;
|
||||||
u8 flags; /* bit 0: dev branch; bit 1: is release */
|
u8 flags;
|
||||||
|
|
||||||
u32 commitHash;
|
u32 commitHash;
|
||||||
|
|
||||||
|
@ -155,8 +155,10 @@ static Result load_code(u64 progid, prog_addrs_t *shared, u64 prog_handle, int i
|
|||||||
lzss_decompress((u8 *)shared->text_addr + size);
|
lzss_decompress((u8 *)shared->text_addr + size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u16 progver = g_exheader.codesetinfo.flags.remasterversion[1] | (g_exheader.codesetinfo.flags.remasterversion[0] << 8);
|
||||||
|
|
||||||
// patch
|
// patch
|
||||||
patchCode(progid, (u8 *)shared->text_addr, shared->total_size << 12);
|
patchCode(progid, progver, (u8 *)shared->text_addr, shared->total_size << 12);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ static Result openLumaFile(IFile *file, const char *path)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void loadCFWInfo(void)
|
static inline void loadCFWInfo(void)
|
||||||
{
|
{
|
||||||
static bool infoLoaded = false;
|
static bool infoLoaded = false;
|
||||||
|
|
||||||
@ -52,7 +52,7 @@ static void loadCFWInfo(void)
|
|||||||
svcGetCFWInfo(&info);
|
svcGetCFWInfo(&info);
|
||||||
|
|
||||||
IFile file;
|
IFile file;
|
||||||
if(BOOTCFG_SAFEMODE != 0 && R_SUCCEEDED(fileOpen(&file, ARCHIVE_SDMC, "/", FS_OPEN_READ))) //Init SD card if SAFE_MODE is being booted
|
if(LOADERFLAG(ISSAFEMODE) && R_SUCCEEDED(fileOpen(&file, ARCHIVE_SDMC, "/", FS_OPEN_READ))) //Init SD card if SAFE_MODE is being booted
|
||||||
IFile_Close(&file);
|
IFile_Close(&file);
|
||||||
|
|
||||||
infoLoaded = true;
|
infoLoaded = true;
|
||||||
@ -320,135 +320,105 @@ static void patchCfgGetRegion(u8 *code, u32 size, u8 regionId, u32 CFGUHandleOff
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void patchCode(u64 progId, u8 *code, u32 size)
|
void patchCode(u64 progId, u16 progVer, u8 *code, u32 size)
|
||||||
{
|
{
|
||||||
loadCFWInfo();
|
loadCFWInfo();
|
||||||
|
|
||||||
switch(progId)
|
if(((progId == 0x0004003000008F02LL || //USA Home Menu
|
||||||
|
progId == 0x0004003000008202LL || //JPN Home Menu
|
||||||
|
progId == 0x0004003000009802LL) //EUR Home Menu
|
||||||
|
&& progVer > 4) ||
|
||||||
|
(progId == 0x000400300000A902LL //KOR Home Menu
|
||||||
|
&& progVer > 0) ||
|
||||||
|
progId == 0x000400300000A102LL || //CHN Home Menu
|
||||||
|
progId == 0x000400300000B102LL) //TWN Home Menu
|
||||||
{
|
{
|
||||||
case 0x0004003000008F02LL: // USA Menu
|
static const u8 regionFreePattern[] = {
|
||||||
case 0x0004003000008202LL: // EUR Menu
|
0x0A, 0x0C, 0x00, 0x10
|
||||||
case 0x0004003000009802LL: // JPN Menu
|
},
|
||||||
case 0x000400300000A102LL: // CHN Menu
|
regionFreePatch[] = {
|
||||||
case 0x000400300000A902LL: // KOR Menu
|
0x01, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1
|
||||||
case 0x000400300000B102LL: // TWN Menu
|
};
|
||||||
|
|
||||||
|
//Patch SMDH region checks
|
||||||
|
patchMemory(code, size,
|
||||||
|
regionFreePattern,
|
||||||
|
sizeof(regionFreePattern), -31,
|
||||||
|
regionFreePatch,
|
||||||
|
sizeof(regionFreePatch), 1
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if(progId == 0x0004013000003202LL) // FRIENDS
|
||||||
|
{
|
||||||
|
static const u8 fpdVerPattern[] = {
|
||||||
|
0x42, 0xE0, 0x1E, 0xFF
|
||||||
|
};
|
||||||
|
|
||||||
|
u8 mostRecentFpdVer = 8;
|
||||||
|
|
||||||
|
u8 *off = memsearch(code, fpdVerPattern, size, sizeof(fpdVerPattern));
|
||||||
|
|
||||||
|
if(off == NULL) svcBreak(USERBREAK_ASSERT);
|
||||||
|
|
||||||
|
//Allow online access to work with old friends modules
|
||||||
|
if(off[0xA] < mostRecentFpdVer) off[0xA] = mostRecentFpdVer;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if((progId == 0x0004001000021000LL || // USA MSET
|
||||||
|
progId == 0x0004001000020000LL || // JPN MSET
|
||||||
|
progId == 0x0004001000022000LL || // EUR MSET
|
||||||
|
progId == 0x0004001000026000LL || // CHN MSET
|
||||||
|
progId == 0x0004001000027000LL || // KOR MSET
|
||||||
|
progId == 0x0004001000028000LL) // TWN MSET
|
||||||
|
&& CONFIG(PATCHVERSTRING))
|
||||||
|
{
|
||||||
|
static const u16 verPattern[] = u"Ve";
|
||||||
|
static u16 *verString;
|
||||||
|
u32 verStringSize = 0,
|
||||||
|
currentNand = BOOTCFG_NAND;
|
||||||
|
|
||||||
|
u16 customVerString[19];
|
||||||
|
loadCustomVerString(customVerString, &verStringSize, currentNand);
|
||||||
|
|
||||||
|
if(verStringSize != 0) verString = customVerString;
|
||||||
|
else
|
||||||
{
|
{
|
||||||
static const u8 regionFreePattern[] = {
|
verStringSize = 8;
|
||||||
0x0A, 0x0C, 0x00, 0x10
|
u32 currentFirm = BOOTCFG_FIRM;
|
||||||
},
|
|
||||||
regionFreePatch[] = {
|
|
||||||
0x01, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1
|
|
||||||
};
|
|
||||||
|
|
||||||
//Patch SMDH region checks
|
static u16 *verStringsNands[] = { u" Sys",
|
||||||
patchMemory(code, size,
|
u" Emu",
|
||||||
regionFreePattern,
|
u"Emu2",
|
||||||
sizeof(regionFreePattern), -31,
|
u"Emu3",
|
||||||
regionFreePatch,
|
u"Emu4" },
|
||||||
sizeof(regionFreePatch), 1
|
|
||||||
);
|
|
||||||
|
|
||||||
break;
|
*verStringsEmuSys[] = { u"EmuS",
|
||||||
|
u"Em2S",
|
||||||
|
u"Em3S",
|
||||||
|
u"Em4S" },
|
||||||
|
|
||||||
|
*verStringsSysEmu[] = { u"SysE",
|
||||||
|
u"SyE2",
|
||||||
|
u"SyE3",
|
||||||
|
u"SyE4" };
|
||||||
|
|
||||||
|
verString = (currentFirm != 0) == (currentNand != 0) ? verStringsNands[currentNand] :
|
||||||
|
(!currentNand ? verStringsSysEmu[currentFirm - 1] : verStringsEmuSys[currentNand - 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x0004013000002C02LL: // NIM
|
//Patch Ver. string
|
||||||
{
|
patchMemory(code, size,
|
||||||
//Apply only if the user booted with R
|
verPattern,
|
||||||
if((BOOTCFG_NAND != 0) != (BOOTCFG_FIRM != 0))
|
sizeof(verPattern) - 2, 0,
|
||||||
{
|
verString,
|
||||||
static const u8 skipEshopUpdateCheckPattern[] = {
|
verStringSize, 1
|
||||||
0x30, 0xB5, 0xF1, 0xB0
|
);
|
||||||
},
|
}
|
||||||
skipEshopUpdateCheckPatch[] = {
|
|
||||||
0x00, 0x20, 0x08, 0x60, 0x70, 0x47
|
|
||||||
};
|
|
||||||
|
|
||||||
//Skip update checks to access the EShop
|
else if(progId == 0x0004013000008002LL) // NS
|
||||||
patchMemory(code, size,
|
{
|
||||||
skipEshopUpdateCheckPattern,
|
if(progVer >= 0xD)
|
||||||
sizeof(skipEshopUpdateCheckPattern), 0,
|
|
||||||
skipEshopUpdateCheckPatch,
|
|
||||||
sizeof(skipEshopUpdateCheckPatch), 1
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 0x0004013000003202LL: // FRIENDS
|
|
||||||
{
|
|
||||||
static const u8 fpdVerPattern[] = {
|
|
||||||
0x42, 0xE0, 0x1E, 0xFF
|
|
||||||
};
|
|
||||||
|
|
||||||
u8 mostRecentFpdVer = 8;
|
|
||||||
|
|
||||||
u8 *fpdVer = memsearch(code, fpdVerPattern, size, sizeof(fpdVerPattern));
|
|
||||||
|
|
||||||
if(fpdVer == NULL) svcBreak(USERBREAK_ASSERT);
|
|
||||||
|
|
||||||
//Allow online access to work with old friends modules
|
|
||||||
if(fpdVer[0xA] < mostRecentFpdVer) fpdVer[0xA] = mostRecentFpdVer;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 0x0004001000021000LL: // USA MSET
|
|
||||||
case 0x0004001000020000LL: // JPN MSET
|
|
||||||
case 0x0004001000022000LL: // EUR MSET
|
|
||||||
case 0x0004001000026000LL: // CHN MSET
|
|
||||||
case 0x0004001000027000LL: // KOR MSET
|
|
||||||
case 0x0004001000028000LL: // TWN MSET
|
|
||||||
{
|
|
||||||
if(CONFIG(PATCHVERSTRING))
|
|
||||||
{
|
|
||||||
static const u16 verPattern[] = u"Ve";
|
|
||||||
static u16 *verString;
|
|
||||||
u32 verStringSize = 0,
|
|
||||||
currentNand = BOOTCFG_NAND;
|
|
||||||
|
|
||||||
u16 customVerString[19];
|
|
||||||
loadCustomVerString(customVerString, &verStringSize, currentNand);
|
|
||||||
|
|
||||||
if(verStringSize != 0) verString = customVerString;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
verStringSize = 8;
|
|
||||||
u32 currentFirm = BOOTCFG_FIRM;
|
|
||||||
|
|
||||||
static u16 *verStringsNands[] = { u" Sys",
|
|
||||||
u" Emu",
|
|
||||||
u"Emu2",
|
|
||||||
u"Emu3",
|
|
||||||
u"Emu4" },
|
|
||||||
|
|
||||||
*verStringsEmuSys[] = { u"EmuS",
|
|
||||||
u"Em2S",
|
|
||||||
u"Em3S",
|
|
||||||
u"Em4S" },
|
|
||||||
|
|
||||||
*verStringsSysEmu[] = { u"SysE",
|
|
||||||
u"SyE2",
|
|
||||||
u"SyE3",
|
|
||||||
u"SyE4" };
|
|
||||||
|
|
||||||
verString = (currentFirm != 0) == (currentNand != 0) ? verStringsNands[currentNand] :
|
|
||||||
(!currentNand ? verStringsSysEmu[currentFirm - 1] : verStringsEmuSys[currentNand - 1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Patch Ver. string
|
|
||||||
patchMemory(code, size,
|
|
||||||
verPattern,
|
|
||||||
sizeof(verPattern) - 2, 0,
|
|
||||||
verString,
|
|
||||||
verStringSize, 1
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 0x0004013000008002LL: // NS
|
|
||||||
{
|
{
|
||||||
static const u8 stopCartUpdatesPattern[] = {
|
static const u8 stopCartUpdatesPattern[] = {
|
||||||
0x0C, 0x18, 0xE1, 0xD8
|
0x0C, 0x18, 0xE1, 0xD8
|
||||||
@ -464,162 +434,148 @@ void patchCode(u64 progId, u8 *code, u32 size)
|
|||||||
stopCartUpdatesPatch,
|
stopCartUpdatesPatch,
|
||||||
sizeof(stopCartUpdatesPatch), 2
|
sizeof(stopCartUpdatesPatch), 2
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(LOADERFLAG(ISN3DS))
|
||||||
|
{
|
||||||
u32 cpuSetting = MULTICONFIG(NEWCPU);
|
u32 cpuSetting = MULTICONFIG(NEWCPU);
|
||||||
|
|
||||||
if(cpuSetting != 0)
|
if(cpuSetting != 0)
|
||||||
{
|
{
|
||||||
static const u8 cfgN3dsCpuPattern[] = {
|
static const u8 cfgN3dsCpuPattern[] = {
|
||||||
0x00, 0x40, 0xA0, 0xE1, 0x07
|
0x0C, 0x00, 0x94, 0x15
|
||||||
};
|
};
|
||||||
|
|
||||||
u32 *cfgN3dsCpuLoc = (u32 *)memsearch(code, cfgN3dsCpuPattern, size, sizeof(cfgN3dsCpuPattern));
|
u32 *off = (u32 *)memsearch(code, cfgN3dsCpuPattern, size, sizeof(cfgN3dsCpuPattern));
|
||||||
|
|
||||||
if(cfgN3dsCpuLoc == NULL) svcBreak(USERBREAK_ASSERT);
|
if(off == NULL) svcBreak(USERBREAK_ASSERT);
|
||||||
|
|
||||||
//Patch N3DS CPU Clock and L2 cache setting
|
//Patch N3DS CPU Clock and L2 cache setting
|
||||||
*(cfgN3dsCpuLoc + 1) = 0xE1A00000;
|
*(off - 4) = 0xE1A00000;
|
||||||
*(cfgN3dsCpuLoc + 8) = 0xE3A00000 | cpuSetting;
|
*(off + 3) = 0xE3A00000 | cpuSetting;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
case 0x0004013000001702LL: // CFG
|
else if(progId == 0x0004013000001702LL) // CFG
|
||||||
|
{
|
||||||
|
static const u8 secureinfoSigCheckPattern[] = {
|
||||||
|
0x06, 0x46, 0x10, 0x48
|
||||||
|
},
|
||||||
|
secureinfoSigCheckPatch[] = {
|
||||||
|
0x00, 0x26
|
||||||
|
};
|
||||||
|
|
||||||
|
//Disable SecureInfo signature check
|
||||||
|
patchMemory(code, size,
|
||||||
|
secureinfoSigCheckPattern,
|
||||||
|
sizeof(secureinfoSigCheckPattern), 0,
|
||||||
|
secureinfoSigCheckPatch,
|
||||||
|
sizeof(secureinfoSigCheckPatch), 1
|
||||||
|
);
|
||||||
|
|
||||||
|
if(secureInfoExists())
|
||||||
{
|
{
|
||||||
static const u8 secureinfoSigCheckPattern[] = {
|
static const u16 secureinfoFilenamePattern[] = u"SecureInfo_",
|
||||||
0x06, 0x46, 0x10, 0x48
|
secureinfoFilenamePatch[] = u"C";
|
||||||
},
|
|
||||||
secureinfoSigCheckPatch[] = {
|
|
||||||
0x00, 0x26
|
|
||||||
};
|
|
||||||
|
|
||||||
//Disable SecureInfo signature check
|
//Use SecureInfo_C
|
||||||
patchMemory(code, size,
|
patchMemory(code, size,
|
||||||
secureinfoSigCheckPattern,
|
secureinfoFilenamePattern,
|
||||||
sizeof(secureinfoSigCheckPattern), 0,
|
sizeof(secureinfoFilenamePattern) - 2,
|
||||||
secureinfoSigCheckPatch,
|
sizeof(secureinfoFilenamePattern) - 2,
|
||||||
sizeof(secureinfoSigCheckPatch), 1
|
secureinfoFilenamePatch,
|
||||||
|
sizeof(secureinfoFilenamePatch) - 2, 2
|
||||||
);
|
);
|
||||||
|
|
||||||
if(secureInfoExists())
|
|
||||||
{
|
|
||||||
static const u16 secureinfoFilenamePattern[] = u"SecureInfo_",
|
|
||||||
secureinfoFilenamePatch[] = u"C";
|
|
||||||
|
|
||||||
//Use SecureInfo_C
|
|
||||||
patchMemory(code, size,
|
|
||||||
secureinfoFilenamePattern,
|
|
||||||
sizeof(secureinfoFilenamePattern) - 2,
|
|
||||||
sizeof(secureinfoFilenamePattern) - 2,
|
|
||||||
secureinfoFilenamePatch,
|
|
||||||
sizeof(secureinfoFilenamePatch) - 2, 2
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
case 0x0004013000003702LL: // RO
|
else if(progId == 0x0004013000003702LL && progVer >= 1) // RO
|
||||||
|
{
|
||||||
|
static const u8 sigCheckPattern[] = {
|
||||||
|
0x20, 0xA0, 0xE1, 0x8B
|
||||||
|
},
|
||||||
|
sha256ChecksPattern1[] = {
|
||||||
|
0xE1, 0x30, 0x40, 0x2D
|
||||||
|
},
|
||||||
|
sha256ChecksPattern2[] = {
|
||||||
|
0x2D, 0xE9, 0x01, 0x70
|
||||||
|
},
|
||||||
|
stub[] = {
|
||||||
|
0x00, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1 // mov r0, #0; bx lr
|
||||||
|
};
|
||||||
|
|
||||||
|
//Disable CRR0 signature (RSA2048 with SHA256) check
|
||||||
|
patchMemory(code, size,
|
||||||
|
sigCheckPattern,
|
||||||
|
sizeof(sigCheckPattern), -9,
|
||||||
|
stub,
|
||||||
|
sizeof(stub), 1
|
||||||
|
);
|
||||||
|
|
||||||
|
//Disable CRO0/CRR0 SHA256 hash checks (section hashes, and hash table)
|
||||||
|
patchMemory(code, size,
|
||||||
|
sha256ChecksPattern1,
|
||||||
|
sizeof(sha256ChecksPattern1), 1,
|
||||||
|
stub,
|
||||||
|
sizeof(stub), 1
|
||||||
|
);
|
||||||
|
|
||||||
|
patchMemory(code, size,
|
||||||
|
sha256ChecksPattern2,
|
||||||
|
sizeof(sha256ChecksPattern2), -2,
|
||||||
|
stub,
|
||||||
|
sizeof(stub), 1
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if(progId == 0x0004003000008A02LL && MULTICONFIG(DEVOPTIONS) == 1) // ErrDisp
|
||||||
|
{
|
||||||
|
static const u8 unitinfoCheckPattern1[] = {
|
||||||
|
0x00, 0xD0, 0xE5, 0xDB
|
||||||
|
},
|
||||||
|
unitinfoCheckPattern2[] = {
|
||||||
|
0x14, 0x00, 0xD0, 0xE5, 0x01
|
||||||
|
},
|
||||||
|
unitinfoCheckPatch[] = {
|
||||||
|
0x00, 0x00, 0xA0, 0xE3
|
||||||
|
};
|
||||||
|
|
||||||
|
patchMemory(code, size,
|
||||||
|
unitinfoCheckPattern1,
|
||||||
|
sizeof(unitinfoCheckPattern1), -1,
|
||||||
|
unitinfoCheckPatch,
|
||||||
|
sizeof(unitinfoCheckPatch), 1
|
||||||
|
);
|
||||||
|
|
||||||
|
patchMemory(code, size,
|
||||||
|
unitinfoCheckPattern2,
|
||||||
|
sizeof(unitinfoCheckPattern2), 0,
|
||||||
|
unitinfoCheckPatch,
|
||||||
|
sizeof(unitinfoCheckPatch), 3
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if(CONFIG(USELANGEMUANDCODE) && (u32)((progId & 0xFFFFFFF000000000LL) >> 0x24) == 0x0004000)
|
||||||
|
{
|
||||||
|
//External .code section loading
|
||||||
|
loadTitleCodeSection(progId, code, size);
|
||||||
|
|
||||||
|
//Language emulation
|
||||||
|
u8 regionId = 0xFF,
|
||||||
|
languageId = 0xFF;
|
||||||
|
loadTitleLocaleConfig(progId, ®ionId, &languageId);
|
||||||
|
|
||||||
|
if(regionId != 0xFF || regionId != 0xFF)
|
||||||
{
|
{
|
||||||
static const u8 sigCheckPattern[] = {
|
u32 CFGUHandleOffset;
|
||||||
0x20, 0xA0, 0xE1, 0x8B
|
u8 *CFGU_GetConfigInfoBlk2_endPos = getCfgOffsets(code, size, &CFGUHandleOffset);
|
||||||
},
|
|
||||||
sha256ChecksPattern1[] = {
|
|
||||||
0xE1, 0x30, 0x40, 0x2D
|
|
||||||
},
|
|
||||||
sha256ChecksPattern2[] = {
|
|
||||||
0x2D, 0xE9, 0x01, 0x70
|
|
||||||
},
|
|
||||||
stub[] = {
|
|
||||||
0x00, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1 // mov r0, #0; bx lr
|
|
||||||
};
|
|
||||||
|
|
||||||
//Disable CRR0 signature (RSA2048 with SHA256) check
|
if(CFGU_GetConfigInfoBlk2_endPos != NULL)
|
||||||
patchMemory(code, size,
|
|
||||||
sigCheckPattern,
|
|
||||||
sizeof(sigCheckPattern), -9,
|
|
||||||
stub,
|
|
||||||
sizeof(stub), 1
|
|
||||||
);
|
|
||||||
|
|
||||||
//Disable CRO0/CRR0 SHA256 hash checks (section hashes, and hash table)
|
|
||||||
patchMemory(code, size,
|
|
||||||
sha256ChecksPattern1,
|
|
||||||
sizeof(sha256ChecksPattern1), 1,
|
|
||||||
stub,
|
|
||||||
sizeof(stub), 1
|
|
||||||
);
|
|
||||||
|
|
||||||
patchMemory(code, size,
|
|
||||||
sha256ChecksPattern2,
|
|
||||||
sizeof(sha256ChecksPattern2), -2,
|
|
||||||
stub,
|
|
||||||
sizeof(stub), 1
|
|
||||||
);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 0x0004003000008A02LL: // ErrDisp
|
|
||||||
{
|
|
||||||
if(MULTICONFIG(DEVOPTIONS) == 1)
|
|
||||||
{
|
{
|
||||||
static const u8 unitinfoCheckPattern1[] = {
|
if(languageId != 0xFF) patchCfgGetLanguage(code, size, languageId, CFGU_GetConfigInfoBlk2_endPos);
|
||||||
0x00, 0xD0, 0xE5, 0xDB
|
if(regionId != 0xFF) patchCfgGetRegion(code, size, regionId, CFGUHandleOffset);
|
||||||
},
|
|
||||||
unitinfoCheckPattern2[] = {
|
|
||||||
0x14, 0x00, 0xD0, 0xE5, 0x01
|
|
||||||
},
|
|
||||||
unitinfoCheckPatch[] = {
|
|
||||||
0x00, 0x00, 0xA0, 0xE3
|
|
||||||
} ;
|
|
||||||
|
|
||||||
patchMemory(code, size,
|
|
||||||
unitinfoCheckPattern1,
|
|
||||||
sizeof(unitinfoCheckPattern1), -1,
|
|
||||||
unitinfoCheckPatch,
|
|
||||||
sizeof(unitinfoCheckPatch), 1
|
|
||||||
);
|
|
||||||
|
|
||||||
patchMemory(code, size,
|
|
||||||
unitinfoCheckPattern2,
|
|
||||||
sizeof(unitinfoCheckPattern2), 0,
|
|
||||||
unitinfoCheckPatch,
|
|
||||||
sizeof(unitinfoCheckPatch), 3
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
|
||||||
if(CONFIG(USELANGEMUANDCODE))
|
|
||||||
{
|
|
||||||
if((u32)((progId & 0xFFFFFFF000000000LL) >> 0x24) == 0x0004000)
|
|
||||||
{
|
|
||||||
//External .code section loading
|
|
||||||
loadTitleCodeSection(progId, code, size);
|
|
||||||
|
|
||||||
//Language emulation
|
|
||||||
u8 regionId = 0xFF,
|
|
||||||
languageId = 0xFF;
|
|
||||||
loadTitleLocaleConfig(progId, ®ionId, &languageId);
|
|
||||||
|
|
||||||
if(regionId != 0xFF || regionId != 0xFF)
|
|
||||||
{
|
|
||||||
u32 CFGUHandleOffset;
|
|
||||||
u8 *CFGU_GetConfigInfoBlk2_endPos = getCfgOffsets(code, size, &CFGUHandleOffset);
|
|
||||||
|
|
||||||
if(CFGU_GetConfigInfoBlk2_endPos != NULL)
|
|
||||||
{
|
|
||||||
if(languageId != 0xFF) patchCfgGetLanguage(code, size, languageId, CFGU_GetConfigInfoBlk2_endPos);
|
|
||||||
if(regionId != 0xFF) patchCfgGetRegion(code, size, regionId, CFGUHandleOffset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,15 +2,15 @@
|
|||||||
|
|
||||||
#include <3ds/types.h>
|
#include <3ds/types.h>
|
||||||
|
|
||||||
#define CONFIG(a) (((info.config >> (a + 21)) & 1) != 0)
|
#define CONFIG(a) (((info.config >> (a + 20)) & 1) != 0)
|
||||||
#define MULTICONFIG(a) ((info.config >> (a * 2 + 9)) & 3)
|
#define MULTICONFIG(a) ((info.config >> (a * 2 + 8)) & 3)
|
||||||
#define BOOTCONFIG(a, b) ((info.config >> a) & b)
|
#define BOOTCONFIG(a, b) ((info.config >> a) & b)
|
||||||
|
#define LOADERFLAG(a) ((info.flags >> (a + 4)) & 1) != 0
|
||||||
|
|
||||||
#define BOOTCFG_NAND BOOTCONFIG(0, 7)
|
#define BOOTCFG_NAND BOOTCONFIG(0, 7)
|
||||||
#define BOOTCFG_FIRM BOOTCONFIG(3, 7)
|
#define BOOTCFG_FIRM BOOTCONFIG(3, 7)
|
||||||
#define BOOTCFG_A9LH BOOTCONFIG(6, 1)
|
#define BOOTCFG_A9LH BOOTCONFIG(6, 1)
|
||||||
#define BOOTCFG_NOFORCEFLAG BOOTCONFIG(7, 1)
|
#define BOOTCFG_NOFORCEFLAG BOOTCONFIG(7, 1)
|
||||||
#define BOOTCFG_SAFEMODE BOOTCONFIG(8, 1)
|
|
||||||
|
|
||||||
enum multiOptions
|
enum multiOptions
|
||||||
{
|
{
|
||||||
@ -34,4 +34,10 @@ enum singleOptions
|
|||||||
PATCHACCESS
|
PATCHACCESS
|
||||||
};
|
};
|
||||||
|
|
||||||
void patchCode(u64 progId, u8 *code, u32 size);
|
enum flags
|
||||||
|
{
|
||||||
|
ISN3DS = 0,
|
||||||
|
ISSAFEMODE
|
||||||
|
};
|
||||||
|
|
||||||
|
void patchCode(u64 progId, u16 progVer, u8 *code, u32 size);
|
@ -62,7 +62,7 @@ void writeConfig(ConfigurationStatus needConfig, u32 configTemp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Merge the new options and new boot configuration
|
//Merge the new options and new boot configuration
|
||||||
configData.config = (configData.config & 0xFFFFFE00) | (configTemp & 0x1FF);
|
configData.config = (configData.config & 0xFFFFFF00) | (configTemp & 0xFF);
|
||||||
|
|
||||||
if(!fileWrite(&configData, CONFIG_FILE, sizeof(CfgData)))
|
if(!fileWrite(&configData, CONFIG_FILE, sizeof(CfgData)))
|
||||||
error("Error writing the configuration file");
|
error("Error writing the configuration file");
|
||||||
@ -377,9 +377,9 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode)
|
|||||||
|
|
||||||
//Parse and write the new configuration
|
//Parse and write the new configuration
|
||||||
for(u32 i = 0; i < multiOptionsAmount; i++)
|
for(u32 i = 0; i < multiOptionsAmount; i++)
|
||||||
configData.config |= multiOptions[i].enabled << (i * 2 + 9);
|
configData.config |= multiOptions[i].enabled << (i * 2 + 8);
|
||||||
for(u32 i = 0; i < singleOptionsAmount; i++)
|
for(u32 i = 0; i < singleOptionsAmount; i++)
|
||||||
configData.config |= (singleOptions[i].enabled ? 1 : 0) << (i + 21);
|
configData.config |= (singleOptions[i].enabled ? 1 : 0) << (i + 20);
|
||||||
|
|
||||||
u32 newPinMode = MULTICONFIG(PIN);
|
u32 newPinMode = MULTICONFIG(PIN);
|
||||||
|
|
||||||
|
@ -24,19 +24,18 @@
|
|||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
#define CONFIG(a) (((configData.config >> (a + 21)) & 1) != 0)
|
#define CONFIG(a) (((configData.config >> (a + 20)) & 1) != 0)
|
||||||
#define MULTICONFIG(a) ((configData.config >> (a * 2 + 9)) & 3)
|
#define MULTICONFIG(a) ((configData.config >> (a * 2 + 8)) & 3)
|
||||||
#define BOOTCONFIG(a, b) ((configData.config >> a) & b)
|
#define BOOTCONFIG(a, b) ((configData.config >> a) & b)
|
||||||
|
|
||||||
#define CONFIG_FILE "config.bin"
|
#define CONFIG_FILE "config.bin"
|
||||||
#define CONFIG_VERSIONMAJOR 1
|
#define CONFIG_VERSIONMAJOR 1
|
||||||
#define CONFIG_VERSIONMINOR 6
|
#define CONFIG_VERSIONMINOR 7
|
||||||
|
|
||||||
#define BOOTCFG_NAND BOOTCONFIG(0, 7)
|
#define BOOTCFG_NAND BOOTCONFIG(0, 7)
|
||||||
#define BOOTCFG_FIRM BOOTCONFIG(3, 7)
|
#define BOOTCFG_FIRM BOOTCONFIG(3, 7)
|
||||||
#define BOOTCFG_A9LH BOOTCONFIG(6, 1)
|
#define BOOTCFG_A9LH BOOTCONFIG(6, 1)
|
||||||
#define BOOTCFG_NOFORCEFLAG BOOTCONFIG(7, 1)
|
#define BOOTCFG_NOFORCEFLAG BOOTCONFIG(7, 1)
|
||||||
#define BOOTCFG_SAFEMODE BOOTCONFIG(8, 1)
|
|
||||||
|
|
||||||
enum multiOptions
|
enum multiOptions
|
||||||
{
|
{
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
|
|
||||||
static Firm *firm = (Firm *)0x24000000;
|
static Firm *firm = (Firm *)0x24000000;
|
||||||
|
|
||||||
u32 loadFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStorage)
|
u32 loadFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStorage, bool isSafeMode)
|
||||||
{
|
{
|
||||||
const char *firmwareFiles[] = {
|
const char *firmwareFiles[] = {
|
||||||
"firmware.bin",
|
"firmware.bin",
|
||||||
@ -66,7 +66,7 @@ u32 loadFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStora
|
|||||||
if(nandType != FIRMWARE_SYSNAND)
|
if(nandType != FIRMWARE_SYSNAND)
|
||||||
error("An old unsupported EmuNAND has been detected.\nLuma3DS is unable to boot it.");
|
error("An old unsupported EmuNAND has been detected.\nLuma3DS is unable to boot it.");
|
||||||
|
|
||||||
if(BOOTCFG_SAFEMODE != 0) error("SAFE_MODE is not supported on 1.x/2.x FIRM.");
|
if(isSafeMode) error("SAFE_MODE is not supported on 1.x/2.x FIRM.");
|
||||||
|
|
||||||
*firmType = NATIVE_FIRM1X2X;
|
*firmType = NATIVE_FIRM1X2X;
|
||||||
}
|
}
|
||||||
@ -109,7 +109,7 @@ u32 loadFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStora
|
|||||||
return firmVersion;
|
return firmVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, bool isA9lhInstalled, u32 devMode)
|
u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, bool isA9lhInstalled, bool isSafeMode, u32 devMode)
|
||||||
{
|
{
|
||||||
u8 *arm9Section = (u8 *)firm + firm->section[2].offset,
|
u8 *arm9Section = (u8 *)firm + firm->section[2].offset,
|
||||||
*arm11Section1 = (u8 *)firm + firm->section[1].offset;
|
*arm11Section1 = (u8 *)firm + firm->section[1].offset;
|
||||||
@ -161,7 +161,7 @@ u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, boo
|
|||||||
ret += reimplementSvcBackdoor(arm11Section1, arm11SvcTable, baseK11VA, &freeK11Space);
|
ret += reimplementSvcBackdoor(arm11Section1, arm11SvcTable, baseK11VA, &freeK11Space);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret += implementSvcGetCFWInfo(arm11Section1, arm11SvcTable, baseK11VA, &freeK11Space);
|
ret += implementSvcGetCFWInfo(arm11Section1, arm11SvcTable, baseK11VA, &freeK11Space, isSafeMode);
|
||||||
|
|
||||||
//Apply UNITINFO patch
|
//Apply UNITINFO patch
|
||||||
if(devMode == 2) ret += patchUnitInfoValueSet(arm9Section, kernel9Size);
|
if(devMode == 2) ret += patchUnitInfoValueSet(arm9Section, kernel9Size);
|
||||||
|
@ -24,8 +24,8 @@
|
|||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
u32 loadFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStorage);
|
u32 loadFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStorage, bool isSafeMode);
|
||||||
u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, bool isA9lhInstalled, u32 devMode);
|
u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, bool isA9lhInstalled, bool isSafeMode, u32 devMode);
|
||||||
u32 patchTwlFirm(u32 firmVersion, u32 devMode);
|
u32 patchTwlFirm(u32 firmVersion, u32 devMode);
|
||||||
u32 patchAgbFirm(u32 devMode);
|
u32 patchAgbFirm(u32 devMode);
|
||||||
u32 patch1x2xNativeAndSafeFirm(u32 devMode);
|
u32 patch1x2xNativeAndSafeFirm(u32 devMode);
|
||||||
|
@ -36,7 +36,8 @@ extern FirmwareSource firmSource;
|
|||||||
|
|
||||||
void main(void)
|
void main(void)
|
||||||
{
|
{
|
||||||
bool isA9lhInstalled;
|
bool isA9lhInstalled,
|
||||||
|
isSafeMode = false;
|
||||||
u32 configTemp,
|
u32 configTemp,
|
||||||
emuHeader;
|
emuHeader;
|
||||||
FirmwareType firmType;
|
FirmwareType firmType;
|
||||||
@ -83,7 +84,7 @@ void main(void)
|
|||||||
u32 pressed = HID_PAD;
|
u32 pressed = HID_PAD;
|
||||||
|
|
||||||
//Save old options and begin saving the new boot configuration
|
//Save old options and begin saving the new boot configuration
|
||||||
configTemp = (configData.config & 0xFFFFFE00) | ((u32)ISA9LH << 6);
|
configTemp = (configData.config & 0xFFFFFF00) | ((u32)ISA9LH << 6);
|
||||||
|
|
||||||
//If it's a MCU reboot, try to force boot options
|
//If it's a MCU reboot, try to force boot options
|
||||||
if(ISA9LH && CFG_BOOTENV && needConfig != CREATE_CONFIGURATION)
|
if(ISA9LH && CFG_BOOTENV && needConfig != CREATE_CONFIGURATION)
|
||||||
@ -131,8 +132,7 @@ void main(void)
|
|||||||
nandType = FIRMWARE_SYSNAND;
|
nandType = FIRMWARE_SYSNAND;
|
||||||
firmSource = FIRMWARE_SYSNAND;
|
firmSource = FIRMWARE_SYSNAND;
|
||||||
|
|
||||||
//Flag to tell loader to init SD
|
isSafeMode = true;
|
||||||
configTemp |= 1 << 8;
|
|
||||||
|
|
||||||
//If the PIN has been verified, wait to make it easier to press the SAFE_MODE combo
|
//If the PIN has been verified, wait to make it easier to press the SAFE_MODE combo
|
||||||
if(pinExists && !shouldLoadConfigMenu)
|
if(pinExists && !shouldLoadConfigMenu)
|
||||||
@ -228,7 +228,7 @@ void main(void)
|
|||||||
if(isSdMode && !mountFs(false, false)) error("Failed to mount CTRNAND.");
|
if(isSdMode && !mountFs(false, false)) error("Failed to mount CTRNAND.");
|
||||||
|
|
||||||
bool loadFromStorage = CONFIG(LOADEXTFIRMSANDMODULES);
|
bool loadFromStorage = CONFIG(LOADEXTFIRMSANDMODULES);
|
||||||
u32 firmVersion = loadFirm(&firmType, firmSource, loadFromStorage);
|
u32 firmVersion = loadFirm(&firmType, firmSource, loadFromStorage, isSafeMode);
|
||||||
|
|
||||||
u32 devMode = MULTICONFIG(DEVOPTIONS);
|
u32 devMode = MULTICONFIG(DEVOPTIONS);
|
||||||
|
|
||||||
@ -236,7 +236,7 @@ void main(void)
|
|||||||
switch(firmType)
|
switch(firmType)
|
||||||
{
|
{
|
||||||
case NATIVE_FIRM:
|
case NATIVE_FIRM:
|
||||||
res = patchNativeFirm(firmVersion, nandType, emuHeader, isA9lhInstalled, devMode);
|
res = patchNativeFirm(firmVersion, nandType, emuHeader, isA9lhInstalled, isSafeMode, devMode);
|
||||||
break;
|
break;
|
||||||
case SAFE_FIRM:
|
case SAFE_FIRM:
|
||||||
case NATIVE_FIRM1X2X:
|
case NATIVE_FIRM1X2X:
|
||||||
|
@ -237,7 +237,7 @@ u32 reimplementSvcBackdoor(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA, u8 **free
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 implementSvcGetCFWInfo(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA, u8 **freeK11Space)
|
u32 implementSvcGetCFWInfo(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA, u8 **freeK11Space, bool isSafeMode)
|
||||||
{
|
{
|
||||||
u32 ret;
|
u32 ret;
|
||||||
|
|
||||||
@ -249,7 +249,7 @@ u32 implementSvcGetCFWInfo(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA, u8 **free
|
|||||||
struct CfwInfo
|
struct CfwInfo
|
||||||
{
|
{
|
||||||
char magic[4];
|
char magic[4];
|
||||||
|
|
||||||
u8 versionMajor;
|
u8 versionMajor;
|
||||||
u8 versionMinor;
|
u8 versionMinor;
|
||||||
u8 versionBuild;
|
u8 versionBuild;
|
||||||
@ -278,6 +278,10 @@ u32 implementSvcGetCFWInfo(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA, u8 **free
|
|||||||
|
|
||||||
if(isRelease) info->flags = 1;
|
if(isRelease) info->flags = 1;
|
||||||
|
|
||||||
|
if(ISN3DS) info->flags |= 1 << 4;
|
||||||
|
|
||||||
|
if(isSafeMode) info->flags |= 1 << 5;
|
||||||
|
|
||||||
arm11SvcTable[0x2E] = baseK11VA + *freeK11Space - pos; //Stubbed svc
|
arm11SvcTable[0x2E] = baseK11VA + *freeK11Space - pos; //Stubbed svc
|
||||||
*freeK11Space += svcGetCFWInfo_bin_size;
|
*freeK11Space += svcGetCFWInfo_bin_size;
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ u32 patchFirmlaunches(u8 *pos, u32 size, u32 process9MemAddr);
|
|||||||
u32 patchFirmWrites(u8 *pos, u32 size);
|
u32 patchFirmWrites(u8 *pos, u32 size);
|
||||||
u32 patchOldFirmWrites(u8 *pos, u32 size);
|
u32 patchOldFirmWrites(u8 *pos, u32 size);
|
||||||
u32 reimplementSvcBackdoor(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA, u8 **freeK11Space);
|
u32 reimplementSvcBackdoor(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA, u8 **freeK11Space);
|
||||||
u32 implementSvcGetCFWInfo(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA, u8 **freeK11Space);
|
u32 implementSvcGetCFWInfo(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA, u8 **freeK11Space, bool isSafeMode);
|
||||||
u32 patchArm9ExceptionHandlersInstall(u8 *pos, u32 size);
|
u32 patchArm9ExceptionHandlersInstall(u8 *pos, u32 size);
|
||||||
u32 getInfoForArm11ExceptionHandlers(u8 *pos, u32 size, u32 *codeSetOffset);
|
u32 getInfoForArm11ExceptionHandlers(u8 *pos, u32 size, u32 *codeSetOffset);
|
||||||
u32 patchSvcBreak9(u8 *pos, u32 size, u32 kernel9Address);
|
u32 patchSvcBreak9(u8 *pos, u32 size, u32 kernel9Address);
|
||||||
|
Reference in New Issue
Block a user