Refactoring, fix bugs, move loader to itcm (without overwriting exception handlers), support for running Luma standalone

This commit is contained in:
Aurora Wright 2017-05-24 15:18:31 +02:00 committed by TuxSH
parent 0b65fcbdd7
commit 9f30244bfb
10 changed files with 163 additions and 82 deletions

View File

@ -4,11 +4,18 @@ OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
. = 0x27FFE000;
. = 0x01FF9000;
__start__ = ABSOLUTE(.);
.text : ALIGN(4) { *(.text.start) *(.text*); . = ALIGN(4); }
.rodata : ALIGN(4) { *(.rodata*); . = ALIGN(4); }
.data : ALIGN(4) { *(.data*); . = ALIGN(8); *(.bss* COMMON); . = ALIGN(8); }
. = ALIGN(4);
__end__ = ABSOLUTE(.);
__stack_top__ = 0x01FFB800;
__stack_bottom__ = 0x01FFA800;
}

View File

@ -27,25 +27,29 @@
void main(int argc, char **argv)
{
Firm *firm = (Firm *)0x20001000;
char *argvPassed[2],
absPath[24 + 255];
struct fb fbs[2];
char absPath[24 + 255];
if(argc == 2)
{
struct fb *fbsrc = (struct fb *)argv[1];
fbs[0] = fbsrc[0];
fbs[1] = fbsrc[1];
}
if(argc >= 1)
if(argc > 0)
{
u32 i;
for(i = 0; i < sizeof(absPath) - 1 && argv[0][i] != 0; i++)
absPath[i] = argv[0][i];
absPath[i] = 0;
argvPassed[0] = (char *)absPath;
}
char *argvPassed[2] = {absPath, (char *)&fbs};
if(argc == 2)
{
struct fb *fbsrc = (struct fb *)argv[1];
fbs[0] = fbsrc[0];
fbs[1] = fbsrc[1];
argvPassed[1] = (char *)&fbs;
}
launchFirm(firm, argc, argvPassed);
}

View File

@ -24,7 +24,7 @@
.align 4
.global _start
_start:
ldr sp, =0x27ffe000
ldr sp, =__stack_top__
b main
.text

View File

@ -324,6 +324,15 @@ static u32 fatStart;
FirmwareSource firmSource;
__attribute__((aligned(4))) static const u8 key1s[2][AES_BLOCK_SIZE] = {
{0x07, 0x29, 0x44, 0x38, 0xF8, 0xC9, 0x75, 0x93, 0xAA, 0x0E, 0x4A, 0xB4, 0xAE, 0x84, 0xC1, 0xD8},
{0xA2, 0xF4, 0x00, 0x3C, 0x7A, 0x95, 0x10, 0x25, 0xDF, 0x4E, 0x9E, 0x74, 0xE3, 0x0C, 0x92, 0x99}
},
key2s[2][AES_BLOCK_SIZE] = {
{0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0},
{0xFF, 0x77, 0xA0, 0x9A, 0x99, 0x81, 0xE9, 0x48, 0xEC, 0x51, 0xC9, 0x32, 0x5D, 0x14, 0xEC, 0x25}
};
void ctrNandInit(void)
{
__attribute__((aligned(4))) u8 cid[AES_BLOCK_SIZE],
@ -335,9 +344,6 @@ void ctrNandInit(void)
if(ISN3DS)
{
__attribute__((aligned(4))) u8 keyY0x5[AES_BLOCK_SIZE] = {0x4D, 0x80, 0x4F, 0x4E, 0x99, 0x90, 0x19, 0x46, 0x13, 0xA2, 0x04, 0xAC, 0x58, 0x44, 0x60, 0xBE};
aes_setkey(0x05, keyY0x5, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
nandSlot = 0x05;
fatStart = 0x5CAD7;
}
@ -441,6 +447,73 @@ bool decryptNusFirm(const Ticket *ticket, Cxi *cxi, u32 ncchSize)
return decryptExeFs(cxi);
}
static inline void twlConsoleInfoInit(void)
{
u64 twlConsoleId = CFG_UNITINFO != 0 ? OTP_DEVCONSOLEID : (0x80000000ULL | (*(vu64 *)0x01FFB808 ^ 0x8C267B7B358A6AFULL));
CFG_TWLUNITINFO = CFG_UNITINFO;
OTP_TWLCONSOLEID = twlConsoleId;
*REG_AESCNT = 0;
vu32 *k3X = REGs_AESTWLKEYS[3][1], *k1X = REGs_AESTWLKEYS[1][1];
k3X[0] = (u32)twlConsoleId;
k3X[3] = (u32)(twlConsoleId >> 32);
k1X[2] = (u32)(twlConsoleId >> 32);
k1X[3] = (u32)twlConsoleId;
}
void setupKeyslots(void)
{
//Setup 0x24 KeyY
__attribute__((aligned(4))) u8 keyY0x24[AES_BLOCK_SIZE] = {0x74, 0xCA, 0x07, 0x48, 0x84, 0xF4, 0x22, 0x8D, 0xEB, 0x2A, 0x1C, 0xA7, 0x2D, 0x28, 0x77, 0x62};
aes_setkey(0x24, keyY0x24, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
//Setup 0x25 KeyX and 0x2F KeyY
__attribute__((aligned(4))) const u8 keyX0x25s[2][AES_BLOCK_SIZE] = {
{0xCE, 0xE7, 0xD8, 0xAB, 0x30, 0xC0, 0x0D, 0xAE, 0x85, 0x0E, 0xF5, 0xE3, 0x82, 0xAC, 0x5A, 0xF3},
{0x81, 0x90, 0x7A, 0x4B, 0x6F, 0x1B, 0x47, 0x32, 0x3A, 0x67, 0x79, 0x74, 0xCE, 0x4A, 0xD7, 0x1B}
},
keyY0x2Fs[2][AES_BLOCK_SIZE] = {
{0xC3, 0x69, 0xBA, 0xA2, 0x1E, 0x18, 0x8A, 0x88, 0xA9, 0xAA, 0x94, 0xE5, 0x50, 0x6A, 0x9F, 0x16},
{0x73, 0x25, 0xC4, 0xEB, 0x14, 0x3A, 0x0D, 0x5F, 0x5D, 0xB6, 0xE5, 0xC5, 0x7A, 0x21, 0x95, 0xAC}
};
aes_setkey(0x25, keyX0x25s[ISDEVUNIT ? 1 : 0], AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_setkey(0x2F, keyY0x2Fs[ISDEVUNIT ? 1 : 0], AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
if(ISN3DS)
{
//Setup 0x05 KeyY
__attribute__((aligned(4))) u8 keyY0x5[AES_BLOCK_SIZE] = {0x4D, 0x80, 0x4F, 0x4E, 0x99, 0x90, 0x19, 0x46, 0x13, 0xA2, 0x04, 0xAC, 0x58, 0x44, 0x60, 0xBE};
aes_setkey(0x05, keyY0x5, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
//Setup TWL keys
twlConsoleInfoInit();
}
__attribute__((aligned(4))) u8 keyBlocks[2][AES_BLOCK_SIZE] = {
{0xA4, 0x8D, 0xE4, 0xF1, 0x0B, 0x36, 0x44, 0xAA, 0x90, 0x31, 0x28, 0xFF, 0x4D, 0xCA, 0x76, 0xDF},
{0xDD, 0xDA, 0xA4, 0xC6, 0x2C, 0xC4, 0x50, 0xE9, 0xDA, 0xB6, 0x9B, 0x0D, 0x9D, 0x2A, 0x21, 0x98}
}, decKey[AES_BLOCK_SIZE];
//Initialize Key 0x18
aes_setkey(0x11, key1s[ISDEVUNIT ? 1 : 0], AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_use_keyslot(0x11);
aes(decKey, keyBlocks[0], 1, NULL, AES_ECB_DECRYPT_MODE, 0);
aes_setkey(0x18, decKey, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
//Initialize Key 0x19-0x1F
aes_setkey(0x11, key2s[ISDEVUNIT ? 1 : 0], AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_use_keyslot(0x11);
for(u8 slot = 0x19; slot < 0x20; slot++, keyBlocks[1][0xF]++)
{
aes(decKey, keyBlocks[1], 1, NULL, AES_ECB_DECRYPT_MODE, 0);
aes_setkey(slot, decKey, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
}
}
void kernel9Loader(Arm9Bin *arm9Section)
{
//Determine the kernel9loader version
@ -460,16 +533,6 @@ void kernel9Loader(Arm9Bin *arm9Section)
u32 *startOfArm9Bin = (u32 *)((u8 *)arm9Section + 0x800);
if(*startOfArm9Bin == 0x47704770 || *startOfArm9Bin == 0xB0862000) return; //Already decrypted
//Set 0x11 keyslot
__attribute__((aligned(4))) const u8 key1s[2][AES_BLOCK_SIZE] = {
{0x07, 0x29, 0x44, 0x38, 0xF8, 0xC9, 0x75, 0x93, 0xAA, 0x0E, 0x4A, 0xB4, 0xAE, 0x84, 0xC1, 0xD8},
{0xA2, 0xF4, 0x00, 0x3C, 0x7A, 0x95, 0x10, 0x25, 0xDF, 0x4E, 0x9E, 0x74, 0xE3, 0x0C, 0x92, 0x99}
},
key2s[2][AES_BLOCK_SIZE] = {
{0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0},
{0xFF, 0x77, 0xA0, 0x9A, 0x99, 0x81, 0xE9, 0x48, 0xEC, 0x51, 0xC9, 0x32, 0x5D, 0x14, 0xEC, 0x25}
};
aes_setkey(0x11, k9lVersion == 2 ? key2s[ISDEVUNIT ? 1 : 0] : key1s[ISDEVUNIT ? 1 : 0], AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
u8 arm9BinSlot = k9lVersion == 0 ? 0x15 : 0x16;

View File

@ -115,5 +115,6 @@ int ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf);
int ctrNandWrite(u32 sector, u32 sectorCount, const u8 *inbuf);
bool decryptExeFs(Cxi *cxi);
bool decryptNusFirm(const Ticket *ticket, Cxi *cxi, u32 ncchSize);
void setupKeyslots(void);
void kernel9Loader(Arm9Bin *arm9Section);
void computePinHash(u8 *outbuf, const u8 *inbuf);

View File

@ -76,48 +76,51 @@ static inline bool loadFirmFromStorage(FirmwareType firmType)
static inline void mergeSection0(FirmwareType firmType, bool loadFromStorage)
{
u32 maxModuleSize = firmType == NATIVE_FIRM ? 0x60000 : 0x600000,
srcModuleSize;
u32 srcModuleSize;
const char *extModuleSizeError = "The external FIRM modules are too large.";
u32 nbModules = 0;
u32 nbCustomModules = 0;
u32 nbModules = 0,
isCustomModule = false;
struct
{
char name[8];
u8 *src;
u32 size;
} moduleList[8];
} moduleList[6];
//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)
for(u8 *src = (u8 *)firm + firm->section[0].offset, *srcEnd = src + firm->section[0].size; src < srcEnd; src += srcModuleSize, nbModules++)
{
memcpy(moduleList[nbModules].name, ((Cxi *)src)->exHeader.systemControlInfo.appTitle, 8);
moduleList[nbModules].src = src;
srcModuleSize = moduleList[nbModules++].size = ((Cxi *)src)->ncch.contentSize * 0x200;
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)
if(firmType == NATIVE_FIRM)
{
const char *name = ((Cxi *)src)->exHeader.systemControlInfo.appTitle;
//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++;
u32 i;
for(i = 0; i < nbModules && memcmp(name, moduleList[i].name, 8) != 0; i++);
memcpy(moduleList[index].name, ((Cxi *)src)->exHeader.systemControlInfo.appTitle, 8);
moduleList[index].src = src;
srcModuleSize = moduleList[index].size = ((Cxi *)src)->ncch.contentSize * 0x200;
if(i == nbModules) isCustomModule = true;
memcpy(moduleList[i].name, ((Cxi *)src)->exHeader.systemControlInfo.appTitle, 8);
moduleList[i].src = src;
srcModuleSize = moduleList[i].size = ((Cxi *)src)->ncch.contentSize * 0x200;
}
if(isCustomModule) nbModules++;
}
nbModules += nbCustomModules;
//4) Read or copy the modules
//3) Read or copy the modules
u8 *dst = firm->section[0].address;
for(u32 i = 0; i < nbModules; i++)
for(u32 i = 0, dstModuleSize; i < nbModules; i++)
{
const char *moduleName = moduleList[i].name;
dstModuleSize = 0;
if(loadFromStorage)
{
@ -126,37 +129,33 @@ static inline void mergeSection0(FirmwareType firmType, bool loadFromStorage)
//Read modules from files if they exist
sprintf(fileName, "sysmodules/%.8s.cxi", moduleList[i].name);
u32 dstModuleSize = getFileSize(fileName);
dstModuleSize = getFileSize(fileName);
if(dstModuleSize != 0)
{
if(dstModuleSize > maxModuleSize) error(extModuleSizeError);
if(dstModuleSize > 0x60000) 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)
memcmp(moduleList[i].name, ((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
if(!dstModuleSize)
{
memcpy(dst, moduleList[i].src, moduleList[i].size);
dst += moduleList[i].size;
}
}
//5) Patch NATIVE_FIRM if necessary
if(nbCustomModules != 0)
//4) Patch NATIVE_FIRM if necessary
if(isCustomModule)
{
if(patchK11ModuleLoading(firm->section[0].size, dst - firm->section[0].address, nbCustomModules, firm->section[1].address, firm->section[1].size) != 0)
if(patchK11ModuleLoading(firm->section[0].size, dst - firm->section[0].address, firm->section[1].address, firm->section[1].size) != 0)
error("Failed to inject custom sysmodule");
}
}
@ -442,7 +441,7 @@ bool checkFirmPayload(void)
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, 0x01FF8000, 0x01FF8000 + 0x8000)) ||
(overlaps((u32)section->address, (u32)section->address + section->size, 0x1FFFFC00, 0x20000000)) ||
(overlaps((u32)section->address, (u32)section->address + section->size, (u32)firm + section->offset, (u32)firm + size)))
return false;
@ -464,7 +463,7 @@ bool checkFirmPayload(void)
void launchFirm(int argc, char **argv)
{
u32 *loaderAddress = (u32 *)0x27FFE000;
u32 *loaderAddress = (u32 *)0x01FF9000;
prepareArm11ForFirmlaunch();

View File

@ -68,7 +68,11 @@ void main(int argc, char **argv, u32 magicWord)
isFirmlaunch = true;
}
else
error("Unsupported launcher or entrypoint (magic = 0x%08x, argc = %d).", magicWord, argc);
{
const char argv[] = "firm0:";
for(u32 i = 0; i < sizeof(argv); i++) //Copy and convert the path to UTF-16
launchedPath[i] = argv[i];
}
if(memcmp(launchedPath, u"sdmc", 8) == 0)
{
@ -81,6 +85,14 @@ void main(int argc, char **argv, u32 magicWord)
if(!mountFs(false, true)) error("Failed to mount CTRNAND.");
isSdMode = false;
}
else if(memcmp(launchedPath, u"firm", 8) == 0)
{
setupKeyslots();
if(mountFs(true, false)) isSdMode = true;
else if(mountFs(false, true)) isSdMode = false;
else error("Failed to mount SD and CTRNAND.");
}
else
{
char mountPoint[5];

View File

@ -237,33 +237,29 @@ u32 patchCheckForDevCommonKey(u8 *pos, u32 size)
return 0;
}
u32 patchK11ModuleLoading(u32 section0size, u32 modulesSize, u32 nbCustomModules, u8 *startPos, u32 size)
u32 patchK11ModuleLoading(u32 section0size, u32 modulesSize, u8 *pos, u32 size)
{
const u8 moduleLoadingPattern[] = {
0x01, 0x70, 0x87, 0xE2, // add r7, #1
0x05, 0x00, 0x57, 0xE3, // cmp r7, #5
};
const u8 moduleLoadingPattern[] = {0xE2, 0x05, 0x00, 0x57},
modulePidPattern[] = {0x06, 0xA0, 0xE1, 0xF2}; //GetSystemInfo
//GetSystemInfo
const u8 modulePidPattern[] = {
0x00, 0xF0, 0x20, 0xE3, // nop
0x05, 0x00, 0xA0, 0xE3, // mov r0, #5
};
u8 *off = memsearch(pos, moduleLoadingPattern, size, 4);
u8 *off = memsearch(startPos, moduleLoadingPattern, size, 8);
if(off == NULL) return 1;
off[4] += nbCustomModules;
off[1]++;
u32 *off32;
for(off32 = (u32 *)off; *off32 != 0xE59F0000; off32++);
for(off32 = (u32 *)(off - 3); *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);
off = memsearch(pos, modulePidPattern, size, 4);
if(off == NULL) return 1;
off[4] = 6;
off[0xB] = 6;
return 0;
}

View File

@ -46,7 +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 patchK11ModuleLoading(u32 section0size, u32 modulesSize, 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

@ -38,16 +38,15 @@
#include "screen.h"
#include "config.h"
#include "memory.h"
#include "cache.h"
#include "i2c.h"
#include "utils.h"
struct fb fbs[2];
static const u32 brightness[4] = {0x5F, 0x4C, 0x39, 0x26};
static volatile Arm11Operation *operation = (volatile Arm11Operation *)0x1FF80004;
struct fb fbs[2];
static void invokeArm11Function(Arm11Operation op)
{
while(*operation != ARM11_READY);