Support 3.x+ EmuNANDs and 3.x SysNANDs (partially), external FIRMs coming soonŧ
This commit is contained in:
parent
39ca23d609
commit
3f93bc5988
@ -114,6 +114,24 @@ static inline bool getFreeK9Space(u8 *pos, u32 size, u8 **freeK9Space)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline u32 getOldSdmmc(u32 *sdmmc, u32 firmVersion)
|
||||||
|
{
|
||||||
|
switch(firmVersion)
|
||||||
|
{
|
||||||
|
case 0x18:
|
||||||
|
*sdmmc = 0x080D91D8;
|
||||||
|
break;
|
||||||
|
case 0x1D:
|
||||||
|
case 0x1F:
|
||||||
|
*sdmmc = 0x080D8CD0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static inline u32 getSdmmc(u8 *pos, u32 size, u32 *sdmmc)
|
static inline u32 getSdmmc(u8 *pos, u32 size, u32 *sdmmc)
|
||||||
{
|
{
|
||||||
//Look for struct code
|
//Look for struct code
|
||||||
@ -166,7 +184,7 @@ static inline u32 patchMpu(u8 *pos, u32 size)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 patchEmuNand(u8 *arm9Section, u32 kernel9Size, u8 *process9Offset, u32 process9Size, u8 *kernel9Address)
|
u32 patchEmuNand(u8 *arm9Section, u32 kernel9Size, u8 *process9Offset, u32 process9Size, u8 *kernel9Address, u32 firmVersion)
|
||||||
{
|
{
|
||||||
u8 *freeK9Space;
|
u8 *freeK9Space;
|
||||||
|
|
||||||
@ -186,7 +204,7 @@ u32 patchEmuNand(u8 *arm9Section, u32 kernel9Size, u8 *process9Offset, u32 proce
|
|||||||
//Find and add the SDMMC struct
|
//Find and add the SDMMC struct
|
||||||
u32 *posSdmmc = (u32 *)memsearch(freeK9Space, "SDMC", emunand_bin_size, 4);
|
u32 *posSdmmc = (u32 *)memsearch(freeK9Space, "SDMC", emunand_bin_size, 4);
|
||||||
u32 sdmmc;
|
u32 sdmmc;
|
||||||
ret += getSdmmc(process9Offset, process9Size, &sdmmc);
|
ret += !ISN3DS && firmVersion < 0x25 ? getOldSdmmc(&sdmmc, firmVersion) : getSdmmc(process9Offset, process9Size, &sdmmc);
|
||||||
if(!ret) *posSdmmc = sdmmc;
|
if(!ret) *posSdmmc = sdmmc;
|
||||||
|
|
||||||
//Add EmuNAND hooks
|
//Add EmuNAND hooks
|
||||||
|
@ -38,4 +38,4 @@ extern u32 emuOffset,
|
|||||||
emuHeader;
|
emuHeader;
|
||||||
|
|
||||||
void locateEmuNand(FirmwareSource *nandType);
|
void locateEmuNand(FirmwareSource *nandType);
|
||||||
u32 patchEmuNand(u8 *arm9Section, u32 kernel9Size, u8 *process9Offset, u32 process9Size, u8 *kernel9Address);
|
u32 patchEmuNand(u8 *arm9Section, u32 kernel9Size, u8 *process9Offset, u32 process9Size, u8 *kernel9Address, u32 firmVersion);
|
||||||
|
@ -155,30 +155,20 @@ u32 loadNintendoFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadF
|
|||||||
|
|
||||||
if(firmVersion == 0xFFFFFFFF) error("Failed to get the CTRNAND FIRM.");
|
if(firmVersion == 0xFFFFFFFF) error("Failed to get the CTRNAND FIRM.");
|
||||||
|
|
||||||
bool mustLoadFromStorage = false;
|
if(!ISN3DS && *firmType == NATIVE_FIRM && !ISDEVUNIT && firmVersion < 0x18)
|
||||||
|
|
||||||
if(!ISN3DS && *firmType == NATIVE_FIRM && !ISDEVUNIT)
|
|
||||||
{
|
|
||||||
if(firmVersion < 0x18)
|
|
||||||
{
|
{
|
||||||
//We can't boot < 3.x EmuNANDs
|
//We can't boot < 3.x EmuNANDs
|
||||||
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(isSafeMode) 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
//We can't boot a 3.x/4.x NATIVE_FIRM EmuNAND, load one from SD/CTRNAND
|
|
||||||
//We can't boot a 3.x NATIVE_FIRM, load one from SD/CTRNAND too
|
|
||||||
else if(firmVersion < (nandType == FIRMWARE_SYSNAND ? 0x1D : 0x25)) mustLoadFromStorage = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool loadedFromStorage = false;
|
bool loadedFromStorage = false;
|
||||||
u32 firmSize;
|
u32 firmSize;
|
||||||
|
|
||||||
if(loadFromStorage || mustLoadFromStorage)
|
if(loadFromStorage)
|
||||||
{
|
{
|
||||||
u32 result = loadFirmFromStorage(*firmType);
|
u32 result = loadFirmFromStorage(*firmType);
|
||||||
|
|
||||||
@ -191,7 +181,6 @@ u32 loadNintendoFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadF
|
|||||||
|
|
||||||
if(!loadedFromStorage)
|
if(!loadedFromStorage)
|
||||||
{
|
{
|
||||||
if(mustLoadFromStorage) error("An old unsupported FIRM has been detected.\nCopy an external FIRM to boot.");
|
|
||||||
firmSize = decryptExeFs((Cxi *)firm);
|
firmSize = decryptExeFs((Cxi *)firm);
|
||||||
if(!firmSize) error("Unable to decrypt the CTRNAND FIRM.");
|
if(!firmSize) error("Unable to decrypt the CTRNAND FIRM.");
|
||||||
}
|
}
|
||||||
@ -229,7 +218,7 @@ void loadHomebrewFirm(u32 pressed)
|
|||||||
launchFirm((firm->reserved2[0] & 1) ? 2 : 1, argv);
|
launchFirm((firm->reserved2[0] & 1) ? 2 : 1, argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void mergeSection0(FirmwareType firmType, bool loadFromStorage)
|
static inline void mergeSection0(FirmwareType firmType, u32 firmVersion, bool loadFromStorage)
|
||||||
{
|
{
|
||||||
u32 srcModuleSize,
|
u32 srcModuleSize,
|
||||||
nbModules = 0;
|
nbModules = 0;
|
||||||
@ -249,7 +238,7 @@ static inline void mergeSection0(FirmwareType firmType, bool loadFromStorage)
|
|||||||
srcModuleSize = moduleList[nbModules].size = ((Cxi *)src)->ncch.contentSize * 0x200;
|
srcModuleSize = moduleList[nbModules].size = ((Cxi *)src)->ncch.contentSize * 0x200;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(firmType == NATIVE_FIRM)
|
if(firmType == NATIVE_FIRM && (ISN3DS || firmVersion >= 0x1D))
|
||||||
{
|
{
|
||||||
//2) Merge that info with our own modules'
|
//2) Merge that info with our own modules'
|
||||||
for(u8 *src = (u8 *)0x1FF60000; src < (u8 *)(0x1FF60000 + LUMA_SECTION0_SIZE); src += srcModuleSize)
|
for(u8 *src = (u8 *)0x1FF60000; src < (u8 *)(0x1FF60000 + LUMA_SECTION0_SIZE); src += srcModuleSize)
|
||||||
@ -274,7 +263,7 @@ static inline void mergeSection0(FirmwareType firmType, bool loadFromStorage)
|
|||||||
//3) Read or copy the modules
|
//3) Read or copy the modules
|
||||||
u8 *dst = firm->section[0].address;
|
u8 *dst = firm->section[0].address;
|
||||||
const char *extModuleSizeError = "The external FIRM modules are too large.";
|
const char *extModuleSizeError = "The external FIRM modules are too large.";
|
||||||
for(u32 i = 0, dstModuleSize, maxModuleSize = 0x60000; i < nbModules; i++, dst += dstModuleSize, maxModuleSize -= dstModuleSize)
|
for(u32 i = 0, dstModuleSize, maxModuleSize = firmType == NATIVE_FIRM ? 0x60000 : 0x600000; i < nbModules; i++, dst += dstModuleSize, maxModuleSize -= dstModuleSize)
|
||||||
{
|
{
|
||||||
if(loadFromStorage)
|
if(loadFromStorage)
|
||||||
{
|
{
|
||||||
@ -341,14 +330,18 @@ u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, bool loadFromStora
|
|||||||
u32 kernel9Size = (u32)(process9Offset - arm9Section) - sizeof(Cxi) - 0x200,
|
u32 kernel9Size = (u32)(process9Offset - arm9Section) - sizeof(Cxi) - 0x200,
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
|
//Skip on FIRMs < 4.0
|
||||||
|
if(!ISN3DS || firmVersion >= 0x1D)
|
||||||
|
{
|
||||||
ret += installK11Extension(arm11Section1, firm->section[1].size, isSafeMode, baseK11VA, arm11ExceptionsPage, &freeK11Space);
|
ret += installK11Extension(arm11Section1, firm->section[1].size, isSafeMode, baseK11VA, arm11ExceptionsPage, &freeK11Space);
|
||||||
ret += patchKernel11(arm11Section1, firm->section[1].size, baseK11VA, arm11SvcTable, arm11ExceptionsPage);
|
ret += patchKernel11(arm11Section1, firm->section[1].size, baseK11VA, arm11SvcTable, arm11ExceptionsPage);
|
||||||
|
}
|
||||||
|
|
||||||
//Apply signature patches
|
//Apply signature patches
|
||||||
ret += patchSignatureChecks(process9Offset, process9Size);
|
ret += patchSignatureChecks(process9Offset, process9Size);
|
||||||
|
|
||||||
//Apply EmuNAND patches
|
//Apply EmuNAND patches
|
||||||
if(nandType != FIRMWARE_SYSNAND) ret += patchEmuNand(arm9Section, kernel9Size, process9Offset, process9Size, firm->section[2].address);
|
if(nandType != FIRMWARE_SYSNAND) ret += patchEmuNand(arm9Section, kernel9Size, process9Offset, process9Size, firm->section[2].address, firmVersion);
|
||||||
|
|
||||||
//Apply FIRM0/1 writes patches on SysNAND to protect A9LH
|
//Apply FIRM0/1 writes patches on SysNAND to protect A9LH
|
||||||
else ret += patchFirmWrites(process9Offset, process9Size);
|
else ret += patchFirmWrites(process9Offset, process9Size);
|
||||||
@ -363,12 +356,8 @@ u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, bool loadFromStora
|
|||||||
ret += patchNandNcchEncryptionCheck(process9Offset, process9Size);
|
ret += patchNandNcchEncryptionCheck(process9Offset, process9Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
//11.0 FIRM patches
|
//Apply anti-anti-DG patches on 11.0+
|
||||||
if(firmVersion >= (ISN3DS ? 0x21 : 0x52))
|
if(firmVersion >= (ISN3DS ? 0x21 : 0x52)) ret += patchTitleInstallMinVersionChecks(process9Offset, process9Size, firmVersion);
|
||||||
{
|
|
||||||
//Apply anti-anti-DG patches
|
|
||||||
ret += patchTitleInstallMinVersionChecks(process9Offset, process9Size, firmVersion);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Apply UNITINFO patches
|
//Apply UNITINFO patches
|
||||||
if(doUnitinfoPatch)
|
if(doUnitinfoPatch)
|
||||||
@ -382,10 +371,9 @@ u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, bool loadFromStora
|
|||||||
ret += patchSvcBreak9(arm9Section, kernel9Size, (u32)firm->section[2].address);
|
ret += patchSvcBreak9(arm9Section, kernel9Size, (u32)firm->section[2].address);
|
||||||
ret += patchKernel9Panic(arm9Section, kernel9Size);
|
ret += patchKernel9Panic(arm9Section, kernel9Size);
|
||||||
|
|
||||||
if(CONFIG(PATCHACCESS))
|
if(CONFIG(PATCHACCESS)) ret += patchP9AccessChecks(process9Offset, process9Size);
|
||||||
ret += patchP9AccessChecks(process9Offset, process9Size);
|
|
||||||
|
|
||||||
mergeSection0(NATIVE_FIRM, loadFromStorage);
|
mergeSection0(NATIVE_FIRM, firmVersion, loadFromStorage);
|
||||||
firm->section[0].size = 0;
|
firm->section[0].size = 0;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -423,14 +411,14 @@ u32 patchTwlFirm(u32 firmVersion, bool loadFromStorage, bool doUnitinfoPatch)
|
|||||||
|
|
||||||
if(loadFromStorage)
|
if(loadFromStorage)
|
||||||
{
|
{
|
||||||
mergeSection0(TWL_FIRM, true);
|
mergeSection0(TWL_FIRM, firmVersion, true);
|
||||||
firm->section[0].size = 0;
|
firm->section[0].size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 patchAgbFirm(bool loadFromStorage, bool doUnitinfoPatch)
|
u32 patchAgbFirm(u32 firmVersion, bool loadFromStorage, bool doUnitinfoPatch)
|
||||||
{
|
{
|
||||||
u8 *arm9Section = (u8 *)firm + firm->section[3].offset;
|
u8 *arm9Section = (u8 *)firm + firm->section[3].offset;
|
||||||
|
|
||||||
@ -457,7 +445,7 @@ u32 patchAgbFirm(bool loadFromStorage, bool doUnitinfoPatch)
|
|||||||
|
|
||||||
if(loadFromStorage)
|
if(loadFromStorage)
|
||||||
{
|
{
|
||||||
mergeSection0(AGB_FIRM, true);
|
mergeSection0(AGB_FIRM, firmVersion, true);
|
||||||
firm->section[0].size = 0;
|
firm->section[0].size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,6 +33,6 @@ u32 loadNintendoFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadF
|
|||||||
void loadHomebrewFirm(u32 pressed);
|
void loadHomebrewFirm(u32 pressed);
|
||||||
u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, bool loadFromStorage, bool isSafeMode, bool doUnitinfoPatch);
|
u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, bool loadFromStorage, bool isSafeMode, bool doUnitinfoPatch);
|
||||||
u32 patchTwlFirm(u32 firmVersion, bool loadFromStorage, bool doUnitinfoPatch);
|
u32 patchTwlFirm(u32 firmVersion, bool loadFromStorage, bool doUnitinfoPatch);
|
||||||
u32 patchAgbFirm(bool loadFromStorage, bool doUnitinfoPatch);
|
u32 patchAgbFirm(u32 firmVersion, bool loadFromStorage, bool doUnitinfoPatch);
|
||||||
u32 patch1x2xNativeAndSafeFirm(void);
|
u32 patch1x2xNativeAndSafeFirm(void);
|
||||||
void launchFirm(int argc, char **argv);
|
void launchFirm(int argc, char **argv);
|
||||||
|
@ -299,7 +299,7 @@ boot:
|
|||||||
res = patchTwlFirm(firmVersion, loadFromStorage, doUnitinfoPatch);
|
res = patchTwlFirm(firmVersion, loadFromStorage, doUnitinfoPatch);
|
||||||
break;
|
break;
|
||||||
case AGB_FIRM:
|
case AGB_FIRM:
|
||||||
res = patchAgbFirm(loadFromStorage, doUnitinfoPatch);
|
res = patchAgbFirm(firmVersion, loadFromStorage, doUnitinfoPatch);
|
||||||
break;
|
break;
|
||||||
case SAFE_FIRM:
|
case SAFE_FIRM:
|
||||||
case SYSUPDATER_FIRM:
|
case SYSUPDATER_FIRM:
|
||||||
|
@ -35,8 +35,8 @@
|
|||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
#include "fmt.h"
|
#include "fmt.h"
|
||||||
|
#include "strings.h"
|
||||||
#include <stdarg.h>
|
#include "fs.h"
|
||||||
|
|
||||||
static void startChrono(void)
|
static void startChrono(void)
|
||||||
{
|
{
|
||||||
@ -123,8 +123,6 @@ void wait(u64 amount)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void error(const char *fmt, ...)
|
void error(const char *fmt, ...)
|
||||||
{
|
|
||||||
if(!isFirmlaunch)
|
|
||||||
{
|
{
|
||||||
char buf[DRAW_MAX_FORMATTED_STRING_SIZE + 1];
|
char buf[DRAW_MAX_FORMATTED_STRING_SIZE + 1];
|
||||||
|
|
||||||
@ -133,6 +131,8 @@ void error(const char *fmt, ...)
|
|||||||
vsprintf(buf, fmt, args);
|
vsprintf(buf, fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
|
if(!isFirmlaunch)
|
||||||
|
{
|
||||||
initScreens();
|
initScreens();
|
||||||
|
|
||||||
drawString(true, 10, 10, COLOR_RED, "An error has occurred:");
|
drawString(true, 10, 10, COLOR_RED, "An error has occurred:");
|
||||||
@ -141,6 +141,7 @@ void error(const char *fmt, ...)
|
|||||||
|
|
||||||
waitInput(false);
|
waitInput(false);
|
||||||
}
|
}
|
||||||
|
else fileWrite(buf, "firmlauncherror.txt", strlen(buf));
|
||||||
|
|
||||||
mcuPowerOff();
|
mcuPowerOff();
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user