Refactoring, fix bugs, move loader to itcm (without overwriting exception handlers), support for running Luma standalone
This commit is contained in:
parent
0b65fcbdd7
commit
9f30244bfb
@ -4,11 +4,18 @@ OUTPUT_ARCH(arm)
|
|||||||
ENTRY(_start)
|
ENTRY(_start)
|
||||||
SECTIONS
|
SECTIONS
|
||||||
{
|
{
|
||||||
. = 0x27FFE000;
|
. = 0x01FF9000;
|
||||||
|
|
||||||
|
__start__ = ABSOLUTE(.);
|
||||||
|
|
||||||
.text : ALIGN(4) { *(.text.start) *(.text*); . = ALIGN(4); }
|
.text : ALIGN(4) { *(.text.start) *(.text*); . = ALIGN(4); }
|
||||||
.rodata : ALIGN(4) { *(.rodata*); . = ALIGN(4); }
|
.rodata : ALIGN(4) { *(.rodata*); . = ALIGN(4); }
|
||||||
.data : ALIGN(4) { *(.data*); . = ALIGN(8); *(.bss* COMMON); . = ALIGN(8); }
|
.data : ALIGN(4) { *(.data*); . = ALIGN(8); *(.bss* COMMON); . = ALIGN(8); }
|
||||||
|
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
|
|
||||||
|
__end__ = ABSOLUTE(.);
|
||||||
|
|
||||||
|
__stack_top__ = 0x01FFB800;
|
||||||
|
__stack_bottom__ = 0x01FFA800;
|
||||||
}
|
}
|
||||||
|
@ -27,25 +27,29 @@
|
|||||||
void main(int argc, char **argv)
|
void main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
Firm *firm = (Firm *)0x20001000;
|
Firm *firm = (Firm *)0x20001000;
|
||||||
|
char *argvPassed[2],
|
||||||
|
absPath[24 + 255];
|
||||||
struct fb fbs[2];
|
struct fb fbs[2];
|
||||||
char absPath[24 + 255];
|
|
||||||
|
|
||||||
if(argc == 2)
|
if(argc > 0)
|
||||||
{
|
|
||||||
struct fb *fbsrc = (struct fb *)argv[1];
|
|
||||||
fbs[0] = fbsrc[0];
|
|
||||||
fbs[1] = fbsrc[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
if(argc >= 1)
|
|
||||||
{
|
{
|
||||||
u32 i;
|
u32 i;
|
||||||
for(i = 0; i < sizeof(absPath) - 1 && argv[0][i] != 0; i++)
|
for(i = 0; i < sizeof(absPath) - 1 && argv[0][i] != 0; i++)
|
||||||
absPath[i] = argv[0][i];
|
absPath[i] = argv[0][i];
|
||||||
absPath[i] = 0;
|
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);
|
launchFirm(firm, argc, argvPassed);
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
.align 4
|
.align 4
|
||||||
.global _start
|
.global _start
|
||||||
_start:
|
_start:
|
||||||
ldr sp, =0x27ffe000
|
ldr sp, =__stack_top__
|
||||||
b main
|
b main
|
||||||
|
|
||||||
.text
|
.text
|
||||||
|
@ -324,6 +324,15 @@ static u32 fatStart;
|
|||||||
|
|
||||||
FirmwareSource firmSource;
|
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)
|
void ctrNandInit(void)
|
||||||
{
|
{
|
||||||
__attribute__((aligned(4))) u8 cid[AES_BLOCK_SIZE],
|
__attribute__((aligned(4))) u8 cid[AES_BLOCK_SIZE],
|
||||||
@ -335,9 +344,6 @@ void ctrNandInit(void)
|
|||||||
|
|
||||||
if(ISN3DS)
|
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;
|
nandSlot = 0x05;
|
||||||
fatStart = 0x5CAD7;
|
fatStart = 0x5CAD7;
|
||||||
}
|
}
|
||||||
@ -441,6 +447,73 @@ bool decryptNusFirm(const Ticket *ticket, Cxi *cxi, u32 ncchSize)
|
|||||||
return decryptExeFs(cxi);
|
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)
|
void kernel9Loader(Arm9Bin *arm9Section)
|
||||||
{
|
{
|
||||||
//Determine the kernel9loader version
|
//Determine the kernel9loader version
|
||||||
@ -460,16 +533,6 @@ void kernel9Loader(Arm9Bin *arm9Section)
|
|||||||
u32 *startOfArm9Bin = (u32 *)((u8 *)arm9Section + 0x800);
|
u32 *startOfArm9Bin = (u32 *)((u8 *)arm9Section + 0x800);
|
||||||
if(*startOfArm9Bin == 0x47704770 || *startOfArm9Bin == 0xB0862000) return; //Already decrypted
|
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);
|
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;
|
u8 arm9BinSlot = k9lVersion == 0 ? 0x15 : 0x16;
|
||||||
|
@ -115,5 +115,6 @@ int ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf);
|
|||||||
int ctrNandWrite(u32 sector, u32 sectorCount, const u8 *inbuf);
|
int ctrNandWrite(u32 sector, u32 sectorCount, const u8 *inbuf);
|
||||||
bool decryptExeFs(Cxi *cxi);
|
bool decryptExeFs(Cxi *cxi);
|
||||||
bool decryptNusFirm(const Ticket *ticket, Cxi *cxi, u32 ncchSize);
|
bool decryptNusFirm(const Ticket *ticket, Cxi *cxi, u32 ncchSize);
|
||||||
|
void setupKeyslots(void);
|
||||||
void kernel9Loader(Arm9Bin *arm9Section);
|
void kernel9Loader(Arm9Bin *arm9Section);
|
||||||
void computePinHash(u8 *outbuf, const u8 *inbuf);
|
void computePinHash(u8 *outbuf, const u8 *inbuf);
|
||||||
|
@ -76,27 +76,28 @@ static inline bool loadFirmFromStorage(FirmwareType firmType)
|
|||||||
|
|
||||||
static inline void mergeSection0(FirmwareType firmType, bool loadFromStorage)
|
static inline void mergeSection0(FirmwareType firmType, bool loadFromStorage)
|
||||||
{
|
{
|
||||||
u32 maxModuleSize = firmType == NATIVE_FIRM ? 0x60000 : 0x600000,
|
u32 srcModuleSize;
|
||||||
srcModuleSize;
|
|
||||||
const char *extModuleSizeError = "The external FIRM modules are too large.";
|
const char *extModuleSizeError = "The external FIRM modules are too large.";
|
||||||
|
|
||||||
u32 nbModules = 0;
|
u32 nbModules = 0,
|
||||||
u32 nbCustomModules = 0;
|
isCustomModule = false;
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
char name[8];
|
char name[8];
|
||||||
u8 *src;
|
u8 *src;
|
||||||
u32 size;
|
u32 size;
|
||||||
} moduleList[8];
|
} moduleList[6];
|
||||||
|
|
||||||
//1) Parse info concerning Nintendo's modules
|
//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);
|
memcpy(moduleList[nbModules].name, ((Cxi *)src)->exHeader.systemControlInfo.appTitle, 8);
|
||||||
moduleList[nbModules].src = src;
|
moduleList[nbModules].src = src;
|
||||||
srcModuleSize = moduleList[nbModules++].size = ((Cxi *)src)->ncch.contentSize * 0x200;
|
srcModuleSize = moduleList[nbModules].size = ((Cxi *)src)->ncch.contentSize * 0x200;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(firmType == NATIVE_FIRM)
|
||||||
|
{
|
||||||
//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)
|
||||||
{
|
{
|
||||||
@ -104,20 +105,22 @@ static inline void mergeSection0(FirmwareType firmType, bool loadFromStorage)
|
|||||||
|
|
||||||
u32 i;
|
u32 i;
|
||||||
for(i = 0; i < nbModules && memcmp(name, moduleList[i].name, 8) != 0; 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);
|
if(i == nbModules) isCustomModule = true;
|
||||||
moduleList[index].src = src;
|
|
||||||
srcModuleSize = moduleList[index].size = ((Cxi *)src)->ncch.contentSize * 0x200;
|
memcpy(moduleList[i].name, ((Cxi *)src)->exHeader.systemControlInfo.appTitle, 8);
|
||||||
|
moduleList[i].src = src;
|
||||||
|
srcModuleSize = moduleList[i].size = ((Cxi *)src)->ncch.contentSize * 0x200;
|
||||||
}
|
}
|
||||||
|
|
||||||
nbModules += nbCustomModules;
|
if(isCustomModule) nbModules++;
|
||||||
|
}
|
||||||
|
|
||||||
//4) Read or copy the modules
|
//3) Read or copy the modules
|
||||||
u8 *dst = firm->section[0].address;
|
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)
|
if(loadFromStorage)
|
||||||
{
|
{
|
||||||
@ -126,37 +129,33 @@ static inline void mergeSection0(FirmwareType firmType, bool loadFromStorage)
|
|||||||
//Read modules from files if they exist
|
//Read modules from files if they exist
|
||||||
sprintf(fileName, "sysmodules/%.8s.cxi", moduleList[i].name);
|
sprintf(fileName, "sysmodules/%.8s.cxi", moduleList[i].name);
|
||||||
|
|
||||||
u32 dstModuleSize = getFileSize(fileName);
|
dstModuleSize = getFileSize(fileName);
|
||||||
|
|
||||||
if(dstModuleSize != 0)
|
if(dstModuleSize != 0)
|
||||||
{
|
{
|
||||||
if(dstModuleSize > maxModuleSize) error(extModuleSizeError);
|
if(dstModuleSize > 0x60000) error(extModuleSizeError);
|
||||||
|
|
||||||
if(dstModuleSize <= sizeof(Cxi) + 0x200 ||
|
if(dstModuleSize <= sizeof(Cxi) + 0x200 ||
|
||||||
fileRead(dst, fileName, dstModuleSize) != dstModuleSize ||
|
fileRead(dst, fileName, dstModuleSize) != dstModuleSize ||
|
||||||
memcmp(((Cxi *)dst)->ncch.magic, "NCCH", 4) != 0 ||
|
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.");
|
error("An external FIRM module is invalid or corrupted.");
|
||||||
|
|
||||||
dst += dstModuleSize;
|
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);
|
memcpy(dst, moduleList[i].src, moduleList[i].size);
|
||||||
dst += moduleList[i].size;
|
dst += moduleList[i].size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//5) Patch NATIVE_FIRM if necessary
|
//4) Patch NATIVE_FIRM if necessary
|
||||||
if(nbCustomModules != 0)
|
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");
|
error("Failed to inject custom sysmodule");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -442,7 +441,7 @@ bool checkFirmPayload(void)
|
|||||||
if((section->offset < 0x200) ||
|
if((section->offset < 0x200) ||
|
||||||
(section->address + section->size < section->address) || //Overflow check
|
(section->address + section->size < section->address) || //Overflow check
|
||||||
((u32)section->address & 3) || (section->offset & 0x1FF) || (section->size & 0x1FF) || //Alignment 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, 0x1FFFFC00, 0x20000000)) ||
|
||||||
(overlaps((u32)section->address, (u32)section->address + section->size, (u32)firm + section->offset, (u32)firm + size)))
|
(overlaps((u32)section->address, (u32)section->address + section->size, (u32)firm + section->offset, (u32)firm + size)))
|
||||||
return false;
|
return false;
|
||||||
@ -464,7 +463,7 @@ bool checkFirmPayload(void)
|
|||||||
|
|
||||||
void launchFirm(int argc, char **argv)
|
void launchFirm(int argc, char **argv)
|
||||||
{
|
{
|
||||||
u32 *loaderAddress = (u32 *)0x27FFE000;
|
u32 *loaderAddress = (u32 *)0x01FF9000;
|
||||||
|
|
||||||
prepareArm11ForFirmlaunch();
|
prepareArm11ForFirmlaunch();
|
||||||
|
|
||||||
|
@ -68,7 +68,11 @@ void main(int argc, char **argv, u32 magicWord)
|
|||||||
isFirmlaunch = true;
|
isFirmlaunch = true;
|
||||||
}
|
}
|
||||||
else
|
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)
|
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.");
|
if(!mountFs(false, true)) error("Failed to mount CTRNAND.");
|
||||||
isSdMode = false;
|
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
|
else
|
||||||
{
|
{
|
||||||
char mountPoint[5];
|
char mountPoint[5];
|
||||||
|
@ -237,33 +237,29 @@ u32 patchCheckForDevCommonKey(u8 *pos, u32 size)
|
|||||||
return 0;
|
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[] = {
|
const u8 moduleLoadingPattern[] = {0xE2, 0x05, 0x00, 0x57},
|
||||||
0x01, 0x70, 0x87, 0xE2, // add r7, #1
|
modulePidPattern[] = {0x06, 0xA0, 0xE1, 0xF2}; //GetSystemInfo
|
||||||
0x05, 0x00, 0x57, 0xE3, // cmp r7, #5
|
|
||||||
};
|
|
||||||
|
|
||||||
//GetSystemInfo
|
u8 *off = memsearch(pos, moduleLoadingPattern, size, 4);
|
||||||
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;
|
if(off == NULL) return 1;
|
||||||
off[4] += nbCustomModules;
|
|
||||||
|
off[1]++;
|
||||||
|
|
||||||
u32 *off32;
|
u32 *off32;
|
||||||
for(off32 = (u32 *)off; *off32 != 0xE59F0000; off32++);
|
for(off32 = (u32 *)(off - 3); *off32 != 0xE59F0000; off32++);
|
||||||
off32 += 2;
|
off32 += 2;
|
||||||
off32[1] = off32[0] + modulesSize;
|
off32[1] = off32[0] + modulesSize;
|
||||||
for(; *off32 != section0size; off32++);
|
for(; *off32 != section0size; off32++);
|
||||||
*off32 += ((modulesSize + 0x1FF) >> 9) << 9;
|
*off32 += ((modulesSize + 0x1FF) >> 9) << 9;
|
||||||
|
|
||||||
off = memsearch(startPos, modulePidPattern, size, 8);
|
off = memsearch(pos, modulePidPattern, size, 4);
|
||||||
|
|
||||||
if(off == NULL) return 1;
|
if(off == NULL) return 1;
|
||||||
off[4] = 6;
|
|
||||||
|
off[0xB] = 6;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ u32 patchOldFirmWrites(u8 *pos, u32 size);
|
|||||||
u32 patchTitleInstallMinVersionChecks(u8 *pos, u32 size, u32 firmVersion);
|
u32 patchTitleInstallMinVersionChecks(u8 *pos, u32 size, u32 firmVersion);
|
||||||
u32 patchZeroKeyNcchEncryptionCheck(u8 *pos, u32 size);
|
u32 patchZeroKeyNcchEncryptionCheck(u8 *pos, u32 size);
|
||||||
u32 patchNandNcchEncryptionCheck(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 patchCheckForDevCommonKey(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 stubSvcRestrictGpuDma(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA);
|
u32 stubSvcRestrictGpuDma(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA);
|
||||||
|
@ -38,16 +38,15 @@
|
|||||||
#include "screen.h"
|
#include "screen.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "cache.h"
|
|
||||||
#include "i2c.h"
|
#include "i2c.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
|
struct fb fbs[2];
|
||||||
|
|
||||||
static const u32 brightness[4] = {0x5F, 0x4C, 0x39, 0x26};
|
static const u32 brightness[4] = {0x5F, 0x4C, 0x39, 0x26};
|
||||||
|
|
||||||
static volatile Arm11Operation *operation = (volatile Arm11Operation *)0x1FF80004;
|
static volatile Arm11Operation *operation = (volatile Arm11Operation *)0x1FF80004;
|
||||||
|
|
||||||
struct fb fbs[2];
|
|
||||||
|
|
||||||
static void invokeArm11Function(Arm11Operation op)
|
static void invokeArm11Function(Arm11Operation op)
|
||||||
{
|
{
|
||||||
while(*operation != ARM11_READY);
|
while(*operation != ARM11_READY);
|
||||||
|
Reference in New Issue
Block a user