Begin turning Luma3DS into a proper firm
Unfinished work
This commit is contained in:
250
source/firm.c
250
source/firm.c
@@ -38,11 +38,11 @@
|
||||
static inline bool loadFirmFromStorage(FirmwareType firmType)
|
||||
{
|
||||
const char *firmwareFiles[] = {
|
||||
"firmware.bin",
|
||||
"firmware_twl.bin",
|
||||
"firmware_agb.bin",
|
||||
"firmware_safe.bin",
|
||||
"firmware_sysupdater.bin"
|
||||
"native.firm",
|
||||
"twl.firm",
|
||||
"agb.firm",
|
||||
"safe.firm",
|
||||
"sysupdater.firm"
|
||||
},
|
||||
*cetkFiles[] = {
|
||||
"cetk",
|
||||
@@ -74,6 +74,93 @@ static inline bool loadFirmFromStorage(FirmwareType firmType)
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void mergeSection0(FirmwareType firmType, bool loadFromStorage)
|
||||
{
|
||||
u32 maxModuleSize = firmType == NATIVE_FIRM ? 0x60000 : 0x600000,
|
||||
srcModuleSize;
|
||||
const char *extModuleSizeError = "The external FIRM modules are too large.";
|
||||
|
||||
u32 nbModules = 0;
|
||||
u32 nbCustomModules = 0;
|
||||
struct
|
||||
{
|
||||
char name[8];
|
||||
u8 *src;
|
||||
u32 size;
|
||||
} moduleList[8];
|
||||
|
||||
//1) Parse info concerning Nintendo's modules
|
||||
for(u8 *src = (u8 *)firm + firm->section[0].offset, *srcEnd = src + firm->section[0].size; src < srcEnd; src += srcModuleSize)
|
||||
{
|
||||
memcpy(moduleList[nbModules].name, ((Cxi *)src)->exHeader.systemControlInfo.appTitle, 8);
|
||||
moduleList[nbModules].src = src;
|
||||
srcModuleSize = moduleList[nbModules++].size = ((Cxi *)src)->ncch.contentSize * 0x200;
|
||||
}
|
||||
|
||||
//2) Merge that info with our own modules'
|
||||
for(u8 *src = (u8 *)0x1FF60000; src < (u8 *)(0x1FF60000 + LUMA_SECTION0_SIZE); src += srcModuleSize)
|
||||
{
|
||||
const char *name = ((Cxi *)src)->exHeader.systemControlInfo.appTitle;
|
||||
|
||||
u32 i;
|
||||
for(i = 0; i < nbModules && memcmp(name, moduleList[i].name, 8) != 0; i++);
|
||||
u32 index = i < nbModules || firmType != NATIVE_FIRM ? i : nbModules + nbCustomModules++;
|
||||
|
||||
memcpy(moduleList[index].name, ((Cxi *)src)->exHeader.systemControlInfo.appTitle, 8);
|
||||
moduleList[index].src = src;
|
||||
srcModuleSize = moduleList[index].size = ((Cxi *)src)->ncch.contentSize * 0x200;
|
||||
}
|
||||
|
||||
nbModules += nbCustomModules;
|
||||
|
||||
//4) Read or copy the modules
|
||||
u8 *dst = firm->section[0].address;
|
||||
for(u32 i = 0; i < nbModules; i++)
|
||||
{
|
||||
const char *moduleName = moduleList[i].name;
|
||||
|
||||
if(loadFromStorage)
|
||||
{
|
||||
char fileName[24];
|
||||
|
||||
//Read modules from files if they exist
|
||||
sprintf(fileName, "sysmodules/%.8s.cxi", moduleList[i].name);
|
||||
|
||||
u32 dstModuleSize = getFileSize(fileName);
|
||||
|
||||
if(dstModuleSize != 0)
|
||||
{
|
||||
if(dstModuleSize > maxModuleSize) error(extModuleSizeError);
|
||||
|
||||
if(dstModuleSize <= sizeof(Cxi) + 0x200 ||
|
||||
fileRead(dst, fileName, dstModuleSize) != dstModuleSize ||
|
||||
memcmp(((Cxi *)dst)->ncch.magic, "NCCH", 4) != 0 ||
|
||||
memcmp(moduleName, ((Cxi *)dst)->exHeader.systemControlInfo.appTitle, sizeof(((Cxi *)dst)->exHeader.systemControlInfo.appTitle)) != 0)
|
||||
error("An external FIRM module is invalid or corrupted.");
|
||||
|
||||
dst += dstModuleSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(dst, moduleList[i].src, moduleList[i].size);
|
||||
dst += moduleList[i].size;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(dst, moduleList[i].src, moduleList[i].size);
|
||||
dst += moduleList[i].size;
|
||||
}
|
||||
}
|
||||
|
||||
//5) Patch NATIVE_FIRM if necessary
|
||||
if(nbCustomModules != 0)
|
||||
{
|
||||
if(patchK11ModuleLoading(firm->section[0].size, dst - firm->section[0].address, nbCustomModules, firm->section[1].address, firm->section[1].size) != 0)
|
||||
error("Failed to inject custom sysmodule");
|
||||
}
|
||||
}
|
||||
|
||||
u32 loadFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStorage, bool isSafeMode)
|
||||
{
|
||||
//Load FIRM from CTRNAND
|
||||
@@ -111,7 +198,7 @@ u32 loadFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStora
|
||||
return firmVersion;
|
||||
}
|
||||
|
||||
u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, bool isSafeMode, bool doUnitinfoPatch, bool enableExceptionHandlers)
|
||||
u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, bool loadFromStorage, bool isSafeMode, bool doUnitinfoPatch, bool enableExceptionHandlers)
|
||||
{
|
||||
u8 *arm9Section = (u8 *)firm + firm->section[2].offset,
|
||||
*arm11Section1 = (u8 *)firm + firm->section[1].offset;
|
||||
@@ -209,10 +296,13 @@ u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, boo
|
||||
}
|
||||
}
|
||||
|
||||
mergeSection0(NATIVE_FIRM, loadFromStorage);
|
||||
firm->section[0].size = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
u32 patchTwlFirm(u32 firmVersion, bool doUnitinfoPatch)
|
||||
u32 patchTwlFirm(u32 firmVersion, bool loadFromStorage, bool doUnitinfoPatch)
|
||||
{
|
||||
u8 *arm9Section = (u8 *)firm + firm->section[3].offset;
|
||||
|
||||
@@ -242,10 +332,16 @@ u32 patchTwlFirm(u32 firmVersion, bool doUnitinfoPatch)
|
||||
//Apply UNITINFO patch
|
||||
if(doUnitinfoPatch) ret += patchUnitInfoValueSet(arm9Section, kernel9Size);
|
||||
|
||||
if(loadFromStorage)
|
||||
{
|
||||
mergeSection0(TWL_FIRM, true);
|
||||
firm->section[0].size = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
u32 patchAgbFirm(bool doUnitinfoPatch)
|
||||
u32 patchAgbFirm(bool loadFromStorage, bool doUnitinfoPatch)
|
||||
{
|
||||
u8 *arm9Section = (u8 *)firm + firm->section[3].offset;
|
||||
|
||||
@@ -270,6 +366,12 @@ u32 patchAgbFirm(bool doUnitinfoPatch)
|
||||
//Apply UNITINFO patch
|
||||
if(doUnitinfoPatch) ret += patchUnitInfoValueSet(arm9Section, kernel9Size);
|
||||
|
||||
if(loadFromStorage)
|
||||
{
|
||||
mergeSection0(AGB_FIRM, true);
|
||||
firm->section[0].size = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -306,85 +408,69 @@ u32 patch1x2xNativeAndSafeFirm(bool enableExceptionHandlers)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void copySection0AndInjectSystemModules(FirmwareType firmType, bool loadFromStorage)
|
||||
static __attribute__((noinline)) bool overlaps(u32 as, u32 ae, u32 bs, u32 be)
|
||||
{
|
||||
u32 maxModuleSize = firmType == NATIVE_FIRM ? 0x80000 : 0x600000,
|
||||
srcModuleSize,
|
||||
dstModuleSize;
|
||||
const char *extModuleSizeError = "The external FIRM modules are too large.";
|
||||
|
||||
for(u8 *src = (u8 *)firm + firm->section[0].offset, *srcEnd = src + firm->section[0].size, *dst = firm->section[0].address;
|
||||
src < srcEnd; src += srcModuleSize, dst += dstModuleSize, maxModuleSize -= dstModuleSize)
|
||||
{
|
||||
srcModuleSize = ((Cxi *)src)->ncch.contentSize * 0x200;
|
||||
const char *moduleName = ((Cxi *)src)->exHeader.systemControlInfo.appTitle;
|
||||
|
||||
if(loadFromStorage)
|
||||
{
|
||||
char fileName[24];
|
||||
|
||||
//Read modules from files if they exist
|
||||
sprintf(fileName, "sysmodules/%.8s.cxi", moduleName);
|
||||
|
||||
dstModuleSize = getFileSize(fileName);
|
||||
|
||||
if(dstModuleSize != 0)
|
||||
{
|
||||
if(dstModuleSize > maxModuleSize) error(extModuleSizeError);
|
||||
|
||||
if(dstModuleSize <= sizeof(Cxi) + 0x200 ||
|
||||
fileRead(dst, fileName, dstModuleSize) != dstModuleSize ||
|
||||
memcmp(((Cxi *)dst)->ncch.magic, "NCCH", 4) != 0 ||
|
||||
memcmp(moduleName, ((Cxi *)dst)->exHeader.systemControlInfo.appTitle, sizeof(((Cxi *)dst)->exHeader.systemControlInfo.appTitle)) != 0)
|
||||
error("An external FIRM module is invalid or corrupted.");
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
const u8 *module;
|
||||
|
||||
if(firmType == NATIVE_FIRM && memcmp(moduleName, "loader", 6) == 0)
|
||||
{
|
||||
module = injector_bin;
|
||||
dstModuleSize = injector_bin_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
module = src;
|
||||
dstModuleSize = srcModuleSize;
|
||||
}
|
||||
|
||||
if(dstModuleSize > maxModuleSize) error(extModuleSizeError);
|
||||
|
||||
memcpy(dst, module, dstModuleSize);
|
||||
}
|
||||
if (as <= bs && bs <= ae)
|
||||
return true;
|
||||
else if (bs <= as && as <= be)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void launchFirm(FirmwareType firmType, bool loadFromStorage)
|
||||
bool checkFirmPayload(void)
|
||||
{
|
||||
//Allow module injection and/or inject 3ds_injector on new NATIVE_FIRMs and LGY FIRMs
|
||||
u32 sectionNum;
|
||||
if(firmType == NATIVE_FIRM || (loadFromStorage && (firmType == TWL_FIRM || firmType == AGB_FIRM)))
|
||||
if(memcmp(firm->magic, "FIRM", 4) != 0 || firm->arm9Entry == NULL) //Allow for the ARM11 entrypoint to be zero in which case nothing is done on the ARM11 side
|
||||
return false;
|
||||
|
||||
u32 size = 0x200;
|
||||
for(u32 i = 0; i < 4; i++)
|
||||
size += firm->section[i].size;
|
||||
|
||||
bool arm9EpFound = false,
|
||||
arm11EpFound = false;
|
||||
|
||||
for(u32 i = 0; i < 4; i++)
|
||||
{
|
||||
copySection0AndInjectSystemModules(firmType, loadFromStorage);
|
||||
sectionNum = 1;
|
||||
__attribute__((aligned(4))) u8 hash[0x20];
|
||||
|
||||
FirmSection *section = &firm->section[i];
|
||||
|
||||
//Allow empty sections
|
||||
if(section->size == 0)
|
||||
continue;
|
||||
|
||||
if((section->offset < 0x200) ||
|
||||
(section->address + section->size < section->address) || //Overflow check
|
||||
((u32)section->address & 3) || (section->offset & 0x1FF) || (section->size & 0x1FF) || //Alignment check
|
||||
(overlaps((u32)section->address, (u32)section->address + section->size, 0x27FFE000 - 0x1000, 0x28000000)) ||
|
||||
(overlaps((u32)section->address, (u32)section->address + section->size, (u32)firm + section->offset, (u32)firm + size)))
|
||||
return false;
|
||||
|
||||
sha(hash, (u8 *)firm + section->offset, section->size, SHA_256_MODE);
|
||||
|
||||
if(memcmp(hash, section->hash, 0x20) != 0)
|
||||
return false;
|
||||
|
||||
if(firm->arm9Entry >= section->address && firm->arm9Entry < (section->address + section->size))
|
||||
arm9EpFound = true;
|
||||
|
||||
if(firm->arm11Entry >= section->address && firm->arm11Entry < (section->address + section->size))
|
||||
arm11EpFound = true;
|
||||
}
|
||||
else sectionNum = 0;
|
||||
|
||||
//Copy FIRM sections to respective memory locations
|
||||
for(; sectionNum < 4 && firm->section[sectionNum].size != 0; sectionNum++)
|
||||
memcpy(firm->section[sectionNum].address, (u8 *)firm + firm->section[sectionNum].offset, firm->section[sectionNum].size);
|
||||
|
||||
if(!isFirmlaunch) deinitScreens();
|
||||
|
||||
//Set ARM11 kernel entrypoint
|
||||
*ARM11_CORE0_MAILBOX_ENTRYPOINT = (u32)firm->arm11Entry;
|
||||
|
||||
//Ensure that all memory transfers have completed and that the caches have been flushed
|
||||
flushEntireDCache();
|
||||
flushEntireICache();
|
||||
|
||||
//Final jump to ARM9 kernel
|
||||
((void (*)())firm->arm9Entry)();
|
||||
return arm9EpFound && (firm->arm11Entry == NULL || arm11EpFound);
|
||||
}
|
||||
|
||||
void launchFirm(int argc, char **argv)
|
||||
{
|
||||
u32 *loaderAddress = (u32 *)0x27FFE000;
|
||||
|
||||
prepareArm11ForFirmlaunch();
|
||||
|
||||
memcpy(loaderAddress, loader_bin, loader_bin_size);
|
||||
|
||||
flushDCacheRange(loaderAddress, loader_bin_size);
|
||||
flushICacheRange(loaderAddress, loader_bin_size);
|
||||
|
||||
((void (*)(int, char **, u32))loaderAddress)(argc, argv, 0x0000BEEF);
|
||||
}
|
||||
|
||||
@@ -25,11 +25,14 @@
|
||||
#include "types.h"
|
||||
#include "3dsheaders.h"
|
||||
|
||||
static Firm *const firm = (Firm *const)0x24000000;
|
||||
static Firm *const firm = (Firm *const)0x20001000;
|
||||
|
||||
u32 loadFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStorage, bool isSafeMode);
|
||||
u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, bool isSafeMode, bool doUnitinfoPatch, bool enableExceptionHandlers);
|
||||
u32 patchTwlFirm(u32 firmVersion, bool doUnitinfoPatch);
|
||||
u32 patchAgbFirm(bool doUnitinfoPatch);
|
||||
u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, bool loadFromStorage, bool isSafeMode, bool doUnitinfoPatch, bool enableExceptionHandlers);
|
||||
u32 patchTwlFirm(u32 firmVersion, bool loadFromStorage, bool doUnitinfoPatch);
|
||||
u32 patchAgbFirm(bool loadFromStorage, bool doUnitinfoPatch);
|
||||
u32 patch1x2xNativeAndSafeFirm(bool enableExceptionHandlers);
|
||||
void launchFirm(FirmwareType firmType, bool loadFromStorage);
|
||||
|
||||
bool checkFirmPayload(void);
|
||||
void launchFirm(int argc, char **argv);
|
||||
|
||||
|
||||
65
source/fs.c
65
source/fs.c
@@ -118,64 +118,10 @@ void fileDelete(const char *path)
|
||||
f_unlink(path);
|
||||
}
|
||||
|
||||
static __attribute__((noinline)) bool overlaps(u32 as, u32 ae, u32 bs, u32 be)
|
||||
{
|
||||
if (as <= bs && bs <= ae)
|
||||
return true;
|
||||
else if (bs <= as && as <= be)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool checkFirmPayload(void)
|
||||
{
|
||||
if(memcmp(firm->magic, "FIRM", 4) != 0 || firm->arm9Entry == NULL) //Allow for the ARM11 entrypoint to be zero in which case nothing is done on the ARM11 side
|
||||
return false;
|
||||
|
||||
u32 size = 0x200;
|
||||
for(u32 i = 0; i < 4; i++)
|
||||
size += firm->section[i].size;
|
||||
|
||||
bool arm9EpFound = false,
|
||||
arm11EpFound = false;
|
||||
|
||||
for(u32 i = 0; i < 4; i++)
|
||||
{
|
||||
__attribute__((aligned(4))) u8 hash[0x20];
|
||||
|
||||
FirmSection *section = &firm->section[i];
|
||||
|
||||
//Allow empty sections
|
||||
if(section->size == 0)
|
||||
continue;
|
||||
|
||||
if((section->offset < 0x200) ||
|
||||
(section->address + section->size < section->address) || //Overflow check
|
||||
((u32)section->address & 3) || (section->offset & 0x1FF) || (section->size & 0x1FF) || //Alignment check
|
||||
(overlaps((u32)section->address, (u32)section->address + section->size, 0x27FFE000 - 0x1000, 0x28000000)) ||
|
||||
(overlaps((u32)section->address, (u32)section->address + section->size, (u32)firm, (u32)firm + size)))
|
||||
return false;
|
||||
|
||||
sha(hash, (u8 *)firm + section->offset, section->size, SHA_256_MODE);
|
||||
|
||||
if(memcmp(hash, section->hash, 0x20) != 0)
|
||||
return false;
|
||||
|
||||
if(firm->arm9Entry >= section->address && firm->arm9Entry < (section->address + section->size))
|
||||
arm9EpFound = true;
|
||||
|
||||
if(firm->arm11Entry >= section->address && firm->arm11Entry < (section->address + section->size))
|
||||
arm11EpFound = true;
|
||||
}
|
||||
|
||||
return arm9EpFound && (firm->arm11Entry == NULL || arm11EpFound);
|
||||
}
|
||||
|
||||
void loadPayload(u32 pressed, const char *payloadPath)
|
||||
{
|
||||
u32 *loaderAddress = (u32 *)0x27FFE000;
|
||||
u32 payloadSize = 0,
|
||||
maxPayloadSize = (u32)((u8 *)loaderAddress - (u8 *)firm);
|
||||
maxPayloadSize = (u32)((u8 *)0x27FFE000 - (u8 *)firm);
|
||||
|
||||
char absPath[24 + _MAX_LFN];
|
||||
char path[10 + _MAX_LFN];
|
||||
@@ -225,14 +171,11 @@ void loadPayload(u32 pressed, const char *payloadPath)
|
||||
sprintf(absPath, "sdmc:/luma/%s", path);
|
||||
|
||||
char *argv[1] = {absPath};
|
||||
memcpy(loaderAddress, loader_bin, loader_bin_size);
|
||||
|
||||
initScreens();
|
||||
|
||||
flushDCacheRange(loaderAddress, loader_bin_size);
|
||||
flushICacheRange(loaderAddress, loader_bin_size);
|
||||
|
||||
((void (*)(int, char **, u32))loaderAddress)(1, argv, 0x0000BEEF);
|
||||
if((u8 *)firm + payloadSize < (u8 *)0x23FFFE00)
|
||||
memcpy((void *)0x23FFFE00, fbs, sizeof(fbs));
|
||||
launchFirm(1, argv);
|
||||
}
|
||||
|
||||
void payloadMenu(void)
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "crypto.h"
|
||||
#include "fmt.h"
|
||||
#include "memory.h"
|
||||
#include "screen.h"
|
||||
|
||||
extern CfgData configData;
|
||||
extern ConfigurationStatus needConfig;
|
||||
@@ -290,13 +291,13 @@ boot:
|
||||
switch(firmType)
|
||||
{
|
||||
case NATIVE_FIRM:
|
||||
res = patchNativeFirm(firmVersion, nandType, emuHeader, isSafeMode, doUnitinfoPatch, enableExceptionHandlers);
|
||||
res = patchNativeFirm(firmVersion, nandType, emuHeader, loadFromStorage, isSafeMode, doUnitinfoPatch, enableExceptionHandlers);
|
||||
break;
|
||||
case TWL_FIRM:
|
||||
res = patchTwlFirm(firmVersion, doUnitinfoPatch);
|
||||
res = patchTwlFirm(firmVersion, loadFromStorage, doUnitinfoPatch);
|
||||
break;
|
||||
case AGB_FIRM:
|
||||
res = patchAgbFirm(doUnitinfoPatch);
|
||||
res = patchAgbFirm(loadFromStorage, doUnitinfoPatch);
|
||||
break;
|
||||
case SAFE_FIRM:
|
||||
case SYSUPDATER_FIRM:
|
||||
@@ -311,5 +312,6 @@ boot:
|
||||
error(errbuf);
|
||||
}
|
||||
|
||||
launchFirm(firmType, loadFromStorage);
|
||||
if(!isFirmlaunch) deinitScreens();
|
||||
launchFirm(0, NULL);
|
||||
}
|
||||
|
||||
@@ -237,6 +237,37 @@ u32 patchCheckForDevCommonKey(u8 *pos, u32 size)
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 patchK11ModuleLoading(u32 section0size, u32 modulesSize, u32 nbCustomModules, u8 *startPos, u32 size)
|
||||
{
|
||||
const u8 moduleLoadingPattern[] = {
|
||||
0x01, 0x70, 0x87, 0xE2, // add r7, #1
|
||||
0x05, 0x00, 0x57, 0xE3, // cmp r7, #5
|
||||
};
|
||||
|
||||
//GetSystemInfo
|
||||
const u8 modulePidPattern[] = {
|
||||
0x00, 0xF0, 0x20, 0xE3, // nop
|
||||
0x05, 0x00, 0xA0, 0xE3, // mov r0, #5
|
||||
};
|
||||
|
||||
u8 *off = memsearch(startPos, moduleLoadingPattern, size, 8);
|
||||
if(off == NULL) return 1;
|
||||
off[4] += nbCustomModules;
|
||||
|
||||
u32 *off32;
|
||||
for(off32 = (u32 *)off; *off32 != 0xE59F0000; off32++);
|
||||
off32 += 2;
|
||||
off32[1] = off32[0] + modulesSize;
|
||||
for(; *off32 != section0size; off32++);
|
||||
*off32 += ((modulesSize + 0x1FF) >> 9) << 9;
|
||||
|
||||
off = memsearch(startPos, modulePidPattern, size, 8);
|
||||
if(off == NULL) return 1;
|
||||
off[4] = 6;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 reimplementSvcBackdoor(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA, u8 **freeK11Space)
|
||||
{
|
||||
if(arm11SvcTable[0x7B] != 0) return 0;
|
||||
|
||||
@@ -46,6 +46,7 @@ u32 patchOldFirmWrites(u8 *pos, u32 size);
|
||||
u32 patchTitleInstallMinVersionChecks(u8 *pos, u32 size, u32 firmVersion);
|
||||
u32 patchZeroKeyNcchEncryptionCheck(u8 *pos, u32 size);
|
||||
u32 patchNandNcchEncryptionCheck(u8 *pos, u32 size);
|
||||
u32 patchK11ModuleLoading(u32 section0size, u32 modulesSize, u32 nbCustomModules, u8 *startPos, u32 size);
|
||||
u32 patchCheckForDevCommonKey(u8 *pos, u32 size);
|
||||
u32 reimplementSvcBackdoor(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA, u8 **freeK11Space);
|
||||
u32 stubSvcRestrictGpuDma(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA);
|
||||
|
||||
240
source/screen.c
240
source/screen.c
@@ -42,244 +42,77 @@
|
||||
#include "i2c.h"
|
||||
#include "utils.h"
|
||||
|
||||
static vu32 *arm11Entry = ARM11_CORE0_MAILBOX_ENTRYPOINT;
|
||||
|
||||
static const u32 brightness[4] = {0x5F, 0x4C, 0x39, 0x26};
|
||||
|
||||
void __attribute__((naked)) arm11Stub(void)
|
||||
static volatile Arm11Operation *operation = (volatile Arm11Operation *)0x1FFFFFF0;
|
||||
|
||||
struct fb fbs[2];
|
||||
|
||||
static void invokeArm11Function(Arm11Operation op)
|
||||
{
|
||||
WAIT_FOR_ARM9();
|
||||
while(*operation != NO_ARM11_OPERATION);
|
||||
*operation = op;
|
||||
while(*operation != NO_ARM11_OPERATION);
|
||||
}
|
||||
|
||||
static void invokeArm11Function(void (*func)())
|
||||
void prepareArm11ForFirmlaunch(void)
|
||||
{
|
||||
static bool hasCopiedStub = false;
|
||||
|
||||
if(!hasCopiedStub)
|
||||
{
|
||||
memcpy((void *)ARM11_STUB_ADDRESS, arm11Stub, 0x2C);
|
||||
hasCopiedStub = true;
|
||||
}
|
||||
|
||||
*arm11Entry = (u32)func;
|
||||
while(*arm11Entry);
|
||||
*arm11Entry = ARM11_STUB_ADDRESS;
|
||||
while(*arm11Entry);
|
||||
invokeArm11Function(PREPARE_ARM11_FOR_FIRMLAUNCH);
|
||||
}
|
||||
|
||||
void deinitScreens(void)
|
||||
{
|
||||
void __attribute__((naked)) ARM11(void)
|
||||
{
|
||||
//Disable interrupts
|
||||
__asm(".word 0xF10C01C0");
|
||||
|
||||
//Shutdown LCDs
|
||||
*(vu32 *)0x10202A44 = 0;
|
||||
*(vu32 *)0x10202244 = 0;
|
||||
*(vu32 *)0x10202014 = 0;
|
||||
|
||||
WAIT_FOR_ARM9();
|
||||
}
|
||||
|
||||
if(ARESCREENSINITIALIZED) invokeArm11Function(ARM11);
|
||||
if(ARESCREENSINITIALIZED) invokeArm11Function(DEINIT_SCREENS);
|
||||
}
|
||||
|
||||
void updateBrightness(u32 brightnessIndex)
|
||||
{
|
||||
static u32 brightnessLevel;
|
||||
brightnessLevel = brightness[brightnessIndex];
|
||||
|
||||
void __attribute__((naked)) ARM11(void)
|
||||
{
|
||||
//Disable interrupts
|
||||
__asm(".word 0xF10C01C0");
|
||||
|
||||
//Change brightness
|
||||
*(vu32 *)0x10202240 = brightnessLevel;
|
||||
*(vu32 *)0x10202A40 = brightnessLevel;
|
||||
|
||||
WAIT_FOR_ARM9();
|
||||
}
|
||||
|
||||
flushDCacheRange(&brightnessLevel, 4);
|
||||
invokeArm11Function(ARM11);
|
||||
*(vu32 *)ARM11_PARAMETERS_ADDRESS = brightness[brightnessIndex];
|
||||
invokeArm11Function(UPDATE_BRIGHTNESS);
|
||||
}
|
||||
|
||||
void swapFramebuffers(bool isAlternate)
|
||||
{
|
||||
static u32 isAlternateTmp;
|
||||
isAlternateTmp = isAlternate ? 1 : 0;
|
||||
|
||||
void __attribute__((naked)) ARM11(void)
|
||||
{
|
||||
//Disable interrupts
|
||||
__asm(".word 0xF10C01C0");
|
||||
|
||||
*(vu32 *)0x10400478 = (*(vu32 *)0x10400478 & 0xFFFFFFFE) | isAlternateTmp;
|
||||
*(vu32 *)0x10400578 = (*(vu32 *)0x10400478 & 0xFFFFFFFE) | isAlternateTmp;
|
||||
|
||||
WAIT_FOR_ARM9();
|
||||
}
|
||||
|
||||
flushDCacheRange(&isAlternateTmp, 4);
|
||||
invokeArm11Function(ARM11);
|
||||
*(volatile bool *)ARM11_PARAMETERS_ADDRESS = isAlternate;
|
||||
invokeArm11Function(SWAP_FRAMEBUFFERS);
|
||||
}
|
||||
|
||||
void clearScreens(bool isAlternate)
|
||||
{
|
||||
static volatile struct fb *fbTmp;
|
||||
fbTmp = isAlternate ? &fbs[1] : &fbs[0];
|
||||
struct fb *fbTemp = isAlternate ? &fbs[1] : &fbs[0];
|
||||
|
||||
void __attribute__((naked)) ARM11(void)
|
||||
{
|
||||
//Disable interrupts
|
||||
__asm(".word 0xF10C01C0");
|
||||
*(volatile struct fb *)ARM11_PARAMETERS_ADDRESS = *fbTemp;
|
||||
invokeArm11Function(CLEAR_SCREENS);
|
||||
}
|
||||
|
||||
//Setting up two simultaneous memory fills using the GPU
|
||||
static void initScreensSequence(void)
|
||||
{
|
||||
*(vu32 *)ARM11_PARAMETERS_ADDRESS = brightness[MULTICONFIG(BRIGHTNESS)];
|
||||
invokeArm11Function(INIT_SCREENS_SEQUENCE);
|
||||
}
|
||||
|
||||
vu32 *REGs_PSC0 = (vu32 *)0x10400010,
|
||||
*REGs_PSC1 = (vu32 *)0x10400020;
|
||||
static void setupFramebuffers(void)
|
||||
{
|
||||
fbs[0].top_left = (u8 *)0x18300000;
|
||||
fbs[1].top_left = (u8 *)0x18400000;
|
||||
fbs[0].top_right = (u8 *)0x18300000;
|
||||
fbs[1].top_right = (u8 *)0x18400000;
|
||||
fbs[0].bottom = (u8 *)0x18346500;
|
||||
fbs[1].bottom = (u8 *)0x18446500;
|
||||
|
||||
REGs_PSC0[0] = (u32)fbTmp->top_left >> 3; //Start address
|
||||
REGs_PSC0[1] = (u32)(fbTmp->top_left + SCREEN_TOP_FBSIZE) >> 3; //End address
|
||||
REGs_PSC0[2] = 0; //Fill value
|
||||
REGs_PSC0[3] = (2 << 8) | 1; //32-bit pattern; start
|
||||
|
||||
REGs_PSC1[0] = (u32)fbTmp->bottom >> 3; //Start address
|
||||
REGs_PSC1[1] = (u32)(fbTmp->bottom + SCREEN_BOTTOM_FBSIZE) >> 3; //End address
|
||||
REGs_PSC1[2] = 0; //Fill value
|
||||
REGs_PSC1[3] = (2 << 8) | 1; //32-bit pattern; start
|
||||
|
||||
while(!((REGs_PSC0[3] & 2) && (REGs_PSC1[3] & 2)));
|
||||
|
||||
WAIT_FOR_ARM9();
|
||||
}
|
||||
|
||||
flushDCacheRange((void *)fbTmp, sizeof(struct fb));
|
||||
flushDCacheRange(&fbTmp, 4);
|
||||
invokeArm11Function(ARM11);
|
||||
memcpy((void *)ARM11_PARAMETERS_ADDRESS, fbs, sizeof(fbs));
|
||||
invokeArm11Function(SETUP_FRAMEBUFFERS);
|
||||
}
|
||||
|
||||
void initScreens(void)
|
||||
{
|
||||
void __attribute__((naked)) initSequence(void)
|
||||
{
|
||||
//Disable interrupts
|
||||
__asm(".word 0xF10C01C0");
|
||||
|
||||
u32 brightnessLevel = brightness[MULTICONFIG(BRIGHTNESS)];
|
||||
|
||||
*(vu32 *)0x10141200 = 0x1007F;
|
||||
*(vu32 *)0x10202014 = 0x00000001;
|
||||
*(vu32 *)0x1020200C &= 0xFFFEFFFE;
|
||||
*(vu32 *)0x10202240 = brightnessLevel;
|
||||
*(vu32 *)0x10202A40 = brightnessLevel;
|
||||
*(vu32 *)0x10202244 = 0x1023E;
|
||||
*(vu32 *)0x10202A44 = 0x1023E;
|
||||
|
||||
//Top screen
|
||||
*(vu32 *)0x10400400 = 0x000001c2;
|
||||
*(vu32 *)0x10400404 = 0x000000d1;
|
||||
*(vu32 *)0x10400408 = 0x000001c1;
|
||||
*(vu32 *)0x1040040c = 0x000001c1;
|
||||
*(vu32 *)0x10400410 = 0x00000000;
|
||||
*(vu32 *)0x10400414 = 0x000000cf;
|
||||
*(vu32 *)0x10400418 = 0x000000d1;
|
||||
*(vu32 *)0x1040041c = 0x01c501c1;
|
||||
*(vu32 *)0x10400420 = 0x00010000;
|
||||
*(vu32 *)0x10400424 = 0x0000019d;
|
||||
*(vu32 *)0x10400428 = 0x00000002;
|
||||
*(vu32 *)0x1040042c = 0x00000192;
|
||||
*(vu32 *)0x10400430 = 0x00000192;
|
||||
*(vu32 *)0x10400434 = 0x00000192;
|
||||
*(vu32 *)0x10400438 = 0x00000001;
|
||||
*(vu32 *)0x1040043c = 0x00000002;
|
||||
*(vu32 *)0x10400440 = 0x01960192;
|
||||
*(vu32 *)0x10400444 = 0x00000000;
|
||||
*(vu32 *)0x10400448 = 0x00000000;
|
||||
*(vu32 *)0x1040045C = 0x00f00190;
|
||||
*(vu32 *)0x10400460 = 0x01c100d1;
|
||||
*(vu32 *)0x10400464 = 0x01920002;
|
||||
*(vu32 *)0x10400468 = 0x18300000;
|
||||
*(vu32 *)0x10400470 = 0x80341;
|
||||
*(vu32 *)0x10400474 = 0x00010501;
|
||||
*(vu32 *)0x10400478 = 0;
|
||||
*(vu32 *)0x10400490 = 0x000002D0;
|
||||
*(vu32 *)0x1040049C = 0x00000000;
|
||||
|
||||
//Disco register
|
||||
for(u32 i = 0; i < 256; i++)
|
||||
*(vu32 *)0x10400484 = 0x10101 * i;
|
||||
|
||||
//Bottom screen
|
||||
*(vu32 *)0x10400500 = 0x000001c2;
|
||||
*(vu32 *)0x10400504 = 0x000000d1;
|
||||
*(vu32 *)0x10400508 = 0x000001c1;
|
||||
*(vu32 *)0x1040050c = 0x000001c1;
|
||||
*(vu32 *)0x10400510 = 0x000000cd;
|
||||
*(vu32 *)0x10400514 = 0x000000cf;
|
||||
*(vu32 *)0x10400518 = 0x000000d1;
|
||||
*(vu32 *)0x1040051c = 0x01c501c1;
|
||||
*(vu32 *)0x10400520 = 0x00010000;
|
||||
*(vu32 *)0x10400524 = 0x0000019d;
|
||||
*(vu32 *)0x10400528 = 0x00000052;
|
||||
*(vu32 *)0x1040052c = 0x00000192;
|
||||
*(vu32 *)0x10400530 = 0x00000192;
|
||||
*(vu32 *)0x10400534 = 0x0000004f;
|
||||
*(vu32 *)0x10400538 = 0x00000050;
|
||||
*(vu32 *)0x1040053c = 0x00000052;
|
||||
*(vu32 *)0x10400540 = 0x01980194;
|
||||
*(vu32 *)0x10400544 = 0x00000000;
|
||||
*(vu32 *)0x10400548 = 0x00000011;
|
||||
*(vu32 *)0x1040055C = 0x00f00140;
|
||||
*(vu32 *)0x10400560 = 0x01c100d1;
|
||||
*(vu32 *)0x10400564 = 0x01920052;
|
||||
*(vu32 *)0x10400568 = 0x18300000 + 0x46500;
|
||||
*(vu32 *)0x10400570 = 0x80301;
|
||||
*(vu32 *)0x10400574 = 0x00010501;
|
||||
*(vu32 *)0x10400578 = 0;
|
||||
*(vu32 *)0x10400590 = 0x000002D0;
|
||||
*(vu32 *)0x1040059C = 0x00000000;
|
||||
|
||||
//Disco register
|
||||
for(u32 i = 0; i < 256; i++)
|
||||
*(vu32 *)0x10400584 = 0x10101 * i;
|
||||
|
||||
WAIT_FOR_ARM9();
|
||||
}
|
||||
|
||||
//Set CakeBrah framebuffers
|
||||
void __attribute__((naked)) setupFramebuffers(void)
|
||||
{
|
||||
//Disable interrupts
|
||||
__asm(".word 0xF10C01C0");
|
||||
|
||||
fbs[0].top_left = (u8 *)0x18300000;
|
||||
fbs[1].top_left = (u8 *)0x18400000;
|
||||
fbs[0].top_right = (u8 *)0x18300000;
|
||||
fbs[1].top_right = (u8 *)0x18400000;
|
||||
fbs[0].bottom = (u8 *)0x18346500;
|
||||
fbs[1].bottom = (u8 *)0x18446500;
|
||||
|
||||
*(vu32 *)0x10400468 = (u32)fbs[0].top_left;
|
||||
*(vu32 *)0x1040046c = (u32)fbs[1].top_left;
|
||||
*(vu32 *)0x10400494 = (u32)fbs[0].top_right;
|
||||
*(vu32 *)0x10400498 = (u32)fbs[1].top_right;
|
||||
*(vu32 *)0x10400568 = (u32)fbs[0].bottom;
|
||||
*(vu32 *)0x1040056c = (u32)fbs[1].bottom;
|
||||
|
||||
WAIT_FOR_ARM9();
|
||||
}
|
||||
|
||||
static bool needToSetup = true;
|
||||
|
||||
if(needToSetup)
|
||||
{
|
||||
if(!ARESCREENSINITIALIZED)
|
||||
{
|
||||
flushDCacheRange(&configData, sizeof(CfgData));
|
||||
invokeArm11Function(initSequence);
|
||||
initScreensSequence();
|
||||
|
||||
//Turn on backlight
|
||||
i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x2A);
|
||||
@@ -287,8 +120,7 @@ void initScreens(void)
|
||||
}
|
||||
else updateBrightness(MULTICONFIG(BRIGHTNESS));
|
||||
|
||||
flushDCacheRange((void *)fbs, 2 * sizeof(struct fb));
|
||||
invokeArm11Function(setupFramebuffers);
|
||||
setupFramebuffers();
|
||||
needToSetup = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -33,8 +33,7 @@
|
||||
|
||||
#define ARESCREENSINITIALIZED (PDN_GPU_CNT != 1)
|
||||
|
||||
#define ARM11_STUB_ADDRESS 0x1FFFFF00
|
||||
#define WAIT_FOR_ARM9() *arm11Entry = 0; while(!*arm11Entry); ((void (*)())*arm11Entry)();
|
||||
#define ARM11_PARAMETERS_ADDRESS 0x1FFFC000
|
||||
|
||||
#define SCREEN_TOP_WIDTH 400
|
||||
#define SCREEN_BOTTOM_WIDTH 320
|
||||
@@ -42,14 +41,29 @@
|
||||
#define SCREEN_TOP_FBSIZE (3 * SCREEN_TOP_WIDTH * SCREEN_HEIGHT)
|
||||
#define SCREEN_BOTTOM_FBSIZE (3 * SCREEN_BOTTOM_WIDTH * SCREEN_HEIGHT)
|
||||
|
||||
static volatile struct fb {
|
||||
struct fb {
|
||||
u8 *top_left;
|
||||
u8 *top_right;
|
||||
u8 *bottom;
|
||||
} __attribute__((packed)) *const fbs = (volatile struct fb *)0x23FFFE00;
|
||||
} __attribute__((packed)); //*const fbs = (volatile struct fb *)0x23FFFE00;
|
||||
|
||||
extern struct fb fbs[2];
|
||||
|
||||
typedef enum
|
||||
{
|
||||
NO_ARM11_OPERATION = 0,
|
||||
INIT_SCREENS_SEQUENCE,
|
||||
SETUP_FRAMEBUFFERS,
|
||||
CLEAR_SCREENS,
|
||||
SWAP_FRAMEBUFFERS,
|
||||
UPDATE_BRIGHTNESS,
|
||||
DEINIT_SCREENS,
|
||||
PREPARE_ARM11_FOR_FIRMLAUNCH,
|
||||
} Arm11Operation;
|
||||
|
||||
extern CfgData configData;
|
||||
|
||||
void prepareArm11ForFirmlaunch(void);
|
||||
void deinitScreens(void);
|
||||
void swapFramebuffers(bool isAlternate);
|
||||
void updateBrightness(u32 brightnessIndex);
|
||||
|
||||
@@ -37,7 +37,7 @@ _start:
|
||||
mov r10, r1
|
||||
|
||||
@ Change the stack pointer
|
||||
mov sp, #0x27000000
|
||||
mov sp, #0x08100000
|
||||
|
||||
@ Disable caches / MPU
|
||||
mrc p15, 0, r4, c1, c0, 0 @ read control register
|
||||
|
||||
Reference in New Issue
Block a user