Begin turning Luma3DS into a proper firm

Unfinished work
This commit is contained in:
TuxSH
2017-05-23 02:44:04 +02:00
parent 8308e1a8b8
commit 53209b9be0
20 changed files with 717 additions and 377 deletions

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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)

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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