Changed indentation style across the code to make it more readable, added newlines before comments, moved patches to separate functions, made memory operations slightly faster by compiling them with O3 (thanks TuxSH!)
This commit is contained in:
parent
6b64a10362
commit
3475cfe1e6
2
Makefile
2
Makefile
@ -96,6 +96,8 @@ $(dir_build)/main.elf: $(objects_cfw)
|
|||||||
# FatFs requires libgcc for __aeabi_uidiv
|
# FatFs requires libgcc for __aeabi_uidiv
|
||||||
$(CC) -nostartfiles $(LDFLAGS) -T linker.ld $(OUTPUT_OPTION) $^
|
$(CC) -nostartfiles $(LDFLAGS) -T linker.ld $(OUTPUT_OPTION) $^
|
||||||
|
|
||||||
|
$(dir_build)/memory.o : CFLAGS+=-O3
|
||||||
|
|
||||||
$(dir_build)/%.o: $(dir_source)/%.c $(dir_build)/patches.h $(dir_build)/loader.h $(dir_build)/screeninit.h
|
$(dir_build)/%.o: $(dir_source)/%.c $(dir_build)/patches.h $(dir_build)/loader.h $(dir_build)/screeninit.h
|
||||||
@mkdir -p "$(@D)"
|
@mkdir -p "$(@D)"
|
||||||
$(COMPILE.c) $(OUTPUT_OPTION) $<
|
$(COMPILE.c) $(OUTPUT_OPTION) $<
|
||||||
|
@ -11,7 +11,8 @@ static u32 config = 0;
|
|||||||
static u8 secureinfo[0x111] = {0};
|
static u8 secureinfo[0x111] = {0};
|
||||||
|
|
||||||
//Quick Search algorithm, adapted from http://igm.univ-mlv.fr/~lecroq/string/node19.html#SECTION00190
|
//Quick Search algorithm, adapted from http://igm.univ-mlv.fr/~lecroq/string/node19.html#SECTION00190
|
||||||
static u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize){
|
static u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize)
|
||||||
|
{
|
||||||
const u8 *patternc = (const u8 *)pattern;
|
const u8 *patternc = (const u8 *)pattern;
|
||||||
|
|
||||||
//Preprocessing
|
//Preprocessing
|
||||||
@ -25,7 +26,8 @@ static u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSiz
|
|||||||
//Searching
|
//Searching
|
||||||
u32 j = 0;
|
u32 j = 0;
|
||||||
|
|
||||||
while(j <= size - patternSize){
|
while(j <= size - patternSize)
|
||||||
|
{
|
||||||
if(memcmp(patternc, startPos + j, patternSize) == 0)
|
if(memcmp(patternc, startPos + j, patternSize) == 0)
|
||||||
return startPos + j;
|
return startPos + j;
|
||||||
j += table[startPos[j + patternSize]];
|
j += table[startPos[j + patternSize]];
|
||||||
@ -34,11 +36,14 @@ static u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSiz
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 patch_memory(u8 *start, u32 size, const void *pattern, u32 patsize, int offset, const void *replace, u32 repsize, u32 count){
|
static u32 patch_memory(u8 *start, u32 size, const void *pattern, u32 patsize, int offset, const void *replace, u32 repsize, u32 count)
|
||||||
|
{
|
||||||
u32 i;
|
u32 i;
|
||||||
|
|
||||||
for(i = 0; i < count; i++){
|
for(i = 0; i < count; i++)
|
||||||
|
{
|
||||||
u8 *found = memsearch(start, pattern, size, patsize);
|
u8 *found = memsearch(start, pattern, size, patsize);
|
||||||
|
|
||||||
if(found == NULL)
|
if(found == NULL)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -55,7 +60,8 @@ static u32 patch_memory(u8 *start, u32 size, const void *pattern, u32 patsize, i
|
|||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int file_open(IFile *file, FS_ArchiveID id, const char *path, int flags){
|
static int file_open(IFile *file, FS_ArchiveID id, const char *path, int flags)
|
||||||
|
{
|
||||||
FS_Archive archive;
|
FS_Archive archive;
|
||||||
FS_Path ppath;
|
FS_Path ppath;
|
||||||
|
|
||||||
@ -70,7 +76,8 @@ static int file_open(IFile *file, FS_ArchiveID id, const char *path, int flags){
|
|||||||
return IFile_Open(file, archive, ppath, flags);
|
return IFile_Open(file, archive, ppath, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int load_secureinfo(){
|
static int load_secureinfo()
|
||||||
|
{
|
||||||
IFile file;
|
IFile file;
|
||||||
Result ret;
|
Result ret;
|
||||||
u64 total;
|
u64 total;
|
||||||
@ -79,7 +86,8 @@ static int load_secureinfo(){
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
ret = file_open(&file, ARCHIVE_NAND_RW, "/sys/SecureInfo_C", FS_OPEN_READ);
|
ret = file_open(&file, ARCHIVE_NAND_RW, "/sys/SecureInfo_C", FS_OPEN_READ);
|
||||||
if(R_SUCCEEDED(ret)){
|
if(R_SUCCEEDED(ret))
|
||||||
|
{
|
||||||
ret = IFile_Read(&file, &total, secureinfo, sizeof(secureinfo));
|
ret = IFile_Read(&file, &total, secureinfo, sizeof(secureinfo));
|
||||||
IFile_Close(&file);
|
IFile_Close(&file);
|
||||||
if(R_SUCCEEDED(ret) && total == sizeof(secureinfo))
|
if(R_SUCCEEDED(ret) && total == sizeof(secureinfo))
|
||||||
@ -89,7 +97,8 @@ static int load_secureinfo(){
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int load_config(){
|
static int load_config()
|
||||||
|
{
|
||||||
IFile file;
|
IFile file;
|
||||||
Result ret;
|
Result ret;
|
||||||
u64 total;
|
u64 total;
|
||||||
@ -98,7 +107,8 @@ static int load_config(){
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
ret = file_open(&file, ARCHIVE_SDMC, "/aurei/config.bin", FS_OPEN_READ);
|
ret = file_open(&file, ARCHIVE_SDMC, "/aurei/config.bin", FS_OPEN_READ);
|
||||||
if(R_SUCCEEDED(ret)){
|
if(R_SUCCEEDED(ret))
|
||||||
|
{
|
||||||
ret = IFile_Read(&file, &total, (void *)&config, 3);
|
ret = IFile_Read(&file, &total, (void *)&config, 3);
|
||||||
IFile_Close(&file);
|
IFile_Close(&file);
|
||||||
}
|
}
|
||||||
@ -106,9 +116,10 @@ static int load_config(){
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 patch_code(u64 progid, u8 *code, u32 size){
|
u32 patch_code(u64 progid, u8 *code, u32 size)
|
||||||
switch(progid){
|
{
|
||||||
|
switch(progid)
|
||||||
|
{
|
||||||
case 0x0004003000008F02LL: // USA Menu
|
case 0x0004003000008F02LL: // USA Menu
|
||||||
case 0x0004003000008202LL: // EUR Menu
|
case 0x0004003000008202LL: // EUR Menu
|
||||||
case 0x0004003000009802LL: // JPN Menu
|
case 0x0004003000009802LL: // JPN Menu
|
||||||
@ -129,6 +140,7 @@ u32 patch_code(u64 progid, u8 *code, u32 size){
|
|||||||
regionFreePatch,
|
regionFreePatch,
|
||||||
sizeof(regionFreePatch), 1
|
sizeof(regionFreePatch), 1
|
||||||
);
|
);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,7 +172,8 @@ u32 patch_code(u64 progid, u8 *code, u32 size){
|
|||||||
sizeof(blockEShopUpdateCheckPatch), 1
|
sizeof(blockEShopUpdateCheckPatch), 1
|
||||||
);
|
);
|
||||||
|
|
||||||
if(R_SUCCEEDED(load_secureinfo())){
|
if(R_SUCCEEDED(load_secureinfo()))
|
||||||
|
{
|
||||||
static const char countryRespPattern[] = {
|
static const char countryRespPattern[] = {
|
||||||
0x01, 0x20, 0x01, 0x90, 0x22, 0x46, 0x06, 0x9B
|
0x01, 0x20, 0x01, 0x90, 0x22, 0x46, 0x06, 0x9B
|
||||||
};
|
};
|
||||||
@ -171,7 +184,8 @@ u32 patch_code(u64 progid, u8 *code, u32 size){
|
|||||||
const char *country;
|
const char *country;
|
||||||
char countryRespPatch[sizeof(countryRespPatchModel)];
|
char countryRespPatch[sizeof(countryRespPatchModel)];
|
||||||
|
|
||||||
switch(secureinfo[0x100]){
|
switch(secureinfo[0x100])
|
||||||
|
{
|
||||||
case 1: country = "US"; break;
|
case 1: country = "US"; break;
|
||||||
case 2: country = "GB"; break; // sorry rest-of-Europe, you have to change this
|
case 2: country = "GB"; break; // sorry rest-of-Europe, you have to change this
|
||||||
case 3: country = "AU"; break;
|
case 3: country = "AU"; break;
|
||||||
@ -194,6 +208,7 @@ u32 patch_code(u64 progid, u8 *code, u32 size){
|
|||||||
sizeof(countryRespPatch), 1
|
sizeof(countryRespPatch), 1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,7 +219,8 @@ u32 patch_code(u64 progid, u8 *code, u32 size){
|
|||||||
case 0x0004001000027000LL: // KOR MSET
|
case 0x0004001000027000LL: // KOR MSET
|
||||||
case 0x0004001000028000LL: // TWN MSET
|
case 0x0004001000028000LL: // TWN MSET
|
||||||
{
|
{
|
||||||
if(R_SUCCEEDED(load_config()) && ((config >> 5) & 1)){
|
if(R_SUCCEEDED(load_config()) && ((config >> 5) & 1))
|
||||||
|
{
|
||||||
static const u16 verPattern[] = u"Ver.";
|
static const u16 verPattern[] = u"Ver.";
|
||||||
const u32 currentFirm = ((config >> 12) & 1);
|
const u32 currentFirm = ((config >> 12) & 1);
|
||||||
const u32 currentNand = ((config >> 13) & 3);
|
const u32 currentNand = ((config >> 13) & 3);
|
||||||
@ -217,6 +233,7 @@ u32 patch_code(u64 progid, u8 *code, u32 size){
|
|||||||
sizeof(verPattern) - sizeof(u16), 1
|
sizeof(verPattern) - sizeof(u16), 1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,6 +252,7 @@ u32 patch_code(u64 progid, u8 *code, u32 size){
|
|||||||
stopCartUpdatesPatch,
|
stopCartUpdatesPatch,
|
||||||
sizeof(stopCartUpdatesPatch), 2
|
sizeof(stopCartUpdatesPatch), 2
|
||||||
);
|
);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -255,7 +273,8 @@ u32 patch_code(u64 progid, u8 *code, u32 size){
|
|||||||
sizeof(secureinfoSigCheckPatch), 1
|
sizeof(secureinfoSigCheckPatch), 1
|
||||||
);
|
);
|
||||||
|
|
||||||
if(R_SUCCEEDED(load_secureinfo())){
|
if(R_SUCCEEDED(load_secureinfo()))
|
||||||
|
{
|
||||||
static const u16 secureinfoFilenamePattern[] = u"SecureInfo_";
|
static const u16 secureinfoFilenamePattern[] = u"SecureInfo_";
|
||||||
static const u16 secureinfoFilenamePatch[] = u"C";
|
static const u16 secureinfoFilenamePatch[] = u"C";
|
||||||
|
|
||||||
@ -268,6 +287,7 @@ u32 patch_code(u64 progid, u8 *code, u32 size){
|
|||||||
sizeof(secureinfoFilenamePatch) - sizeof(u16), 2
|
sizeof(secureinfoFilenamePatch) - sizeof(u16), 2
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,9 +4,11 @@
|
|||||||
|
|
||||||
#define PAYLOAD_ADDRESS 0x23F00000
|
#define PAYLOAD_ADDRESS 0x23F00000
|
||||||
|
|
||||||
static u32 loadPayload(const char *path){
|
static u32 loadPayload(const char *path)
|
||||||
|
{
|
||||||
FIL payload;
|
FIL payload;
|
||||||
unsigned int br;
|
unsigned int br;
|
||||||
|
|
||||||
if(f_open(&payload, path, FA_READ) == FR_OK)
|
if(f_open(&payload, path, FA_READ) == FR_OK)
|
||||||
{
|
{
|
||||||
f_read(&payload, (void *)PAYLOAD_ADDRESS, f_size(&payload), &br);
|
f_read(&payload, (void *)PAYLOAD_ADDRESS, f_size(&payload), &br);
|
||||||
@ -18,7 +20,8 @@ static u32 loadPayload(const char *path){
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void main(void){
|
void main(void)
|
||||||
|
{
|
||||||
FATFS fs;
|
FATFS fs;
|
||||||
f_mount(&fs, "0:", 1);
|
f_mount(&fs, "0:", 1);
|
||||||
|
|
||||||
|
@ -12,7 +12,4 @@ _start:
|
|||||||
mcr p15, 0, r0, c7, c6, 0 @ flush D-cache
|
mcr p15, 0, r0, c7, c6, 0 @ flush D-cache
|
||||||
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
|
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
|
||||||
|
|
||||||
bl main
|
b main
|
||||||
|
|
||||||
.die:
|
|
||||||
b .die
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
void main(void){
|
void main(void)
|
||||||
|
{
|
||||||
vu32 *const arm11 = (u32 *)0x1FFFFFF8;
|
vu32 *const arm11 = (u32 *)0x1FFFFFF8;
|
||||||
|
|
||||||
*(vu32 *)0x10141200 = 0x1007F;
|
*(vu32 *)0x10141200 = 0x1007F;
|
||||||
@ -96,6 +97,7 @@ void main(void){
|
|||||||
|
|
||||||
//Wait for the entry to be set
|
//Wait for the entry to be set
|
||||||
while(!*arm11);
|
while(!*arm11);
|
||||||
|
|
||||||
//Jump to it
|
//Jump to it
|
||||||
((void (*)())*arm11)();
|
((void (*)())*arm11)();
|
||||||
}
|
}
|
@ -5,7 +5,4 @@ _start:
|
|||||||
@ Disable interrupts
|
@ Disable interrupts
|
||||||
CPSID aif
|
CPSID aif
|
||||||
|
|
||||||
bl main
|
b main
|
||||||
|
|
||||||
.die:
|
|
||||||
b .die
|
|
||||||
|
@ -239,14 +239,16 @@ static const u8 key2[0x10] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
//Get Nand CTR key
|
//Get Nand CTR key
|
||||||
static void getNandCTR(u8 *buf, u32 console){
|
static void getNandCTR(u8 *buf, u32 console)
|
||||||
|
{
|
||||||
u8 *addr = (console ? (u8 *)0x080D8BBC : (u8 *)0x080D797C) + 0x0F;
|
u8 *addr = (console ? (u8 *)0x080D8BBC : (u8 *)0x080D797C) + 0x0F;
|
||||||
for(u8 keyLen = 0x10; keyLen; keyLen--)
|
for(u8 keyLen = 0x10; keyLen; keyLen--)
|
||||||
*(buf++) = *(addr--);
|
*(buf++) = *(addr--);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Read firm0 from NAND and write to buffer
|
//Read firm0 from NAND and write to buffer
|
||||||
void nandFirm0(u8 *outbuf, u32 size, u32 console){
|
void nandFirm0(u8 *outbuf, u32 size, u32 console)
|
||||||
|
{
|
||||||
u8 CTR[0x10];
|
u8 CTR[0x10];
|
||||||
getNandCTR(CTR, console);
|
getNandCTR(CTR, console);
|
||||||
|
|
||||||
@ -258,8 +260,8 @@ void nandFirm0(u8 *outbuf, u32 size, u32 console){
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Decrypts the N3DS arm9bin
|
//Decrypts the N3DS arm9bin
|
||||||
void decryptArm9Bin(u8 *arm9Section, u32 mode){
|
void decryptArm9Bin(u8 *arm9Section, u32 mode)
|
||||||
|
{
|
||||||
//Firm keys
|
//Firm keys
|
||||||
u8 keyY[0x10];
|
u8 keyY[0x10];
|
||||||
u8 CTR[0x10];
|
u8 CTR[0x10];
|
||||||
@ -268,12 +270,15 @@ void decryptArm9Bin(u8 *arm9Section, u32 mode){
|
|||||||
//Setup keys needed for arm9bin decryption
|
//Setup keys needed for arm9bin decryption
|
||||||
memcpy(keyY, arm9Section + 0x10, 0x10);
|
memcpy(keyY, arm9Section + 0x10, 0x10);
|
||||||
memcpy(CTR, arm9Section + 0x20, 0x10);
|
memcpy(CTR, arm9Section + 0x20, 0x10);
|
||||||
|
|
||||||
|
//Calculate the size of the ARM9 binary
|
||||||
u32 size = 0;
|
u32 size = 0;
|
||||||
//http://stackoverflow.com/questions/12791077/atoi-implementation-in-c
|
//http://stackoverflow.com/questions/12791077/atoi-implementation-in-c
|
||||||
for(u8 *tmp = arm9Section + 0x30; *tmp; tmp++)
|
for(u8 *tmp = arm9Section + 0x30; *tmp; tmp++)
|
||||||
size = (size << 3) + (size << 1) + (*tmp) - '0';
|
size = (size << 3) + (size << 1) + (*tmp) - '0';
|
||||||
|
|
||||||
if(mode){
|
if(mode)
|
||||||
|
{
|
||||||
u8 keyX[0x10];
|
u8 keyX[0x10];
|
||||||
|
|
||||||
//Set 0x11 to key2 for the arm9bin and misc keys
|
//Set 0x11 to key2 for the arm9bin and misc keys
|
||||||
@ -292,15 +297,16 @@ void decryptArm9Bin(u8 *arm9Section, u32 mode){
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Sets the N3DS 9.6 KeyXs
|
//Sets the N3DS 9.6 KeyXs
|
||||||
void setKeyXs(u8 *arm9Section){
|
void setKeyXs(u8 *arm9Section)
|
||||||
|
{
|
||||||
u8 *keyData = arm9Section + 0x89814;
|
u8 *keyData = arm9Section + 0x89814;
|
||||||
u8 *decKey = keyData + 0x10;
|
u8 *decKey = keyData + 0x10;
|
||||||
|
|
||||||
//Set keys 0x19..0x1F keyXs
|
//Set keys 0x19..0x1F keyXs
|
||||||
aes_setkey(0x11, key2, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
|
aes_setkey(0x11, key2, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
aes_use_keyslot(0x11);
|
aes_use_keyslot(0x11);
|
||||||
for(u8 slot = 0x19; slot < 0x20; slot++){
|
for(u8 slot = 0x19; slot < 0x20; slot++)
|
||||||
|
{
|
||||||
aes(decKey, keyData, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
|
aes(decKey, keyData, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
|
||||||
aes_setkey(slot, decKey, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
aes_setkey(slot, decKey, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
*(keyData + 0xF) += 1;
|
*(keyData + 0xF) += 1;
|
||||||
|
@ -20,38 +20,47 @@ static const struct fb {
|
|||||||
u8 *bottom;
|
u8 *bottom;
|
||||||
} *const fb = (struct fb *)0x23FFFE00;
|
} *const fb = (struct fb *)0x23FFFE00;
|
||||||
|
|
||||||
static inline int strlen(const char *string){
|
static inline int strlen(const char *string)
|
||||||
|
{
|
||||||
char *stringEnd = (char *)string;
|
char *stringEnd = (char *)string;
|
||||||
while(*stringEnd) stringEnd++;
|
while(*stringEnd) stringEnd++;
|
||||||
return stringEnd - string;
|
return stringEnd - string;
|
||||||
}
|
}
|
||||||
|
|
||||||
void clearScreens(void){
|
void clearScreens(void)
|
||||||
|
{
|
||||||
memset32(fb->top_left, 0, 0x46500);
|
memset32(fb->top_left, 0, 0x46500);
|
||||||
memset32(fb->top_right, 0, 0x46500);
|
memset32(fb->top_right, 0, 0x46500);
|
||||||
memset32(fb->bottom, 0, 0x38400);
|
memset32(fb->bottom, 0, 0x38400);
|
||||||
}
|
}
|
||||||
|
|
||||||
void loadSplash(void){
|
void loadSplash(void)
|
||||||
|
{
|
||||||
clearScreens();
|
clearScreens();
|
||||||
|
|
||||||
//Don't delay boot if no splash image is on the SD
|
//Don't delay boot if no splash image is on the SD
|
||||||
if(fileRead(fb->top_left, "/aurei/splash.bin", 0x46500) +
|
if(fileRead(fb->top_left, "/aurei/splash.bin", 0x46500) +
|
||||||
fileRead(fb->bottom, "/aurei/splashbottom.bin", 0x38400)){
|
fileRead(fb->bottom, "/aurei/splashbottom.bin", 0x38400))
|
||||||
u64 i = 0x1300000; while(--i) __asm("mov r0, r0"); //Less Ghetto sleep func
|
{
|
||||||
|
u64 i = 0x1300000;
|
||||||
|
while(--i) __asm("mov r0, r0"); //Less Ghetto sleep func
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawCharacter(char character, int posX, int posY, u32 color){
|
void drawCharacter(char character, int posX, int posY, u32 color)
|
||||||
|
{
|
||||||
u8 *const select = fb->top_left;
|
u8 *const select = fb->top_left;
|
||||||
|
|
||||||
for(int y = 0; y < 8; y++){
|
for(int y = 0; y < 8; y++)
|
||||||
|
{
|
||||||
char charPos = font[character * 8 + y];
|
char charPos = font[character * 8 + y];
|
||||||
|
|
||||||
for(int x = 7; x >= 0; x--){
|
for(int x = 7; x >= 0; x--)
|
||||||
|
{
|
||||||
int screenPos = (posX * SCREEN_TOP_HEIGHT * 3 + (SCREEN_TOP_HEIGHT - y - posY - 1) * 3) + (7 - x) * 3 * SCREEN_TOP_HEIGHT;
|
int screenPos = (posX * SCREEN_TOP_HEIGHT * 3 + (SCREEN_TOP_HEIGHT - y - posY - 1) * 3) + (7 - x) * 3 * SCREEN_TOP_HEIGHT;
|
||||||
|
|
||||||
if ((charPos >> x) & 1) {
|
if ((charPos >> x) & 1)
|
||||||
|
{
|
||||||
select[screenPos] = color >> 16;
|
select[screenPos] = color >> 16;
|
||||||
select[screenPos + 1] = color >> 8;
|
select[screenPos + 1] = color >> 8;
|
||||||
select[screenPos + 2] = color;
|
select[screenPos + 2] = color;
|
||||||
@ -60,15 +69,19 @@ void drawCharacter(char character, int posX, int posY, u32 color){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int drawString(const char *string, int posX, int posY, u32 color){
|
int drawString(const char *string, int posX, int posY, u32 color)
|
||||||
|
{
|
||||||
int length = strlen(string);
|
int length = strlen(string);
|
||||||
|
|
||||||
for(int i = 0, line_i = 0; i < length; i++, line_i++){
|
for(int i = 0, line_i = 0; i < length; i++, line_i++)
|
||||||
if(string[i] == '\n'){
|
{
|
||||||
|
if(string[i] == '\n')
|
||||||
|
{
|
||||||
posY += SPACING_Y;
|
posY += SPACING_Y;
|
||||||
line_i = 0;
|
line_i = 0;
|
||||||
i++;
|
i++;
|
||||||
} else if(line_i >= (SCREEN_TOP_WIDTH - posX) / SPACING_X){
|
} else if(line_i >= (SCREEN_TOP_WIDTH - posX) / SPACING_X)
|
||||||
|
{
|
||||||
// Make sure we never get out of the screen.
|
// Make sure we never get out of the screen.
|
||||||
posY += SPACING_Y;
|
posY += SPACING_Y;
|
||||||
line_i = 2; // Little offset so we know the same string continues.
|
line_i = 2; // Little offset so we know the same string continues.
|
||||||
|
@ -8,7 +8,8 @@
|
|||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "fatfs/sdmmc/sdmmc.h"
|
#include "fatfs/sdmmc/sdmmc.h"
|
||||||
|
|
||||||
void getEmunandSect(u32 *off, u32 *head, u32 *emuNAND){
|
void getEmunandSect(u32 *off, u32 *head, u32 *emuNAND)
|
||||||
|
{
|
||||||
u8 *const temp = (u8 *)0x24300000;
|
u8 *const temp = (u8 *)0x24300000;
|
||||||
|
|
||||||
const u32 nandSize = getMMCDevice(0)->total_size;
|
const u32 nandSize = getMMCDevice(0)->total_size;
|
||||||
@ -16,19 +17,24 @@ void getEmunandSect(u32 *off, u32 *head, u32 *emuNAND){
|
|||||||
(nandSize > 0x200000 ? 0x400000 : 0x200000);
|
(nandSize > 0x200000 ? 0x400000 : 0x200000);
|
||||||
|
|
||||||
//Check for RedNAND
|
//Check for RedNAND
|
||||||
if(sdmmc_sdcard_readsectors(nandOffset + 1, 1, temp) == 0){
|
if(sdmmc_sdcard_readsectors(nandOffset + 1, 1, temp) == 0)
|
||||||
if(*(u32 *)(temp + 0x100) == NCSD_MAGIC){
|
{
|
||||||
|
if(*(u32 *)(temp + 0x100) == NCSD_MAGIC)
|
||||||
|
{
|
||||||
*off = nandOffset + 1;
|
*off = nandOffset + 1;
|
||||||
*head = nandOffset + 1;
|
*head = nandOffset + 1;
|
||||||
}
|
}
|
||||||
//Check for Gateway emuNAND
|
//Check for Gateway emuNAND
|
||||||
else if(sdmmc_sdcard_readsectors(nandOffset + nandSize, 1, temp) == 0){
|
else if(sdmmc_sdcard_readsectors(nandOffset + nandSize, 1, temp) == 0)
|
||||||
if(*(u32 *)(temp + 0x100) == NCSD_MAGIC){
|
{
|
||||||
|
if(*(u32 *)(temp + 0x100) == NCSD_MAGIC)
|
||||||
|
{
|
||||||
*off = nandOffset;
|
*off = nandOffset;
|
||||||
*head = nandOffset + nandSize;
|
*head = nandOffset + nandSize;
|
||||||
}
|
}
|
||||||
//Fallback to the first emuNAND if there's no second one
|
//Fallback to the first emuNAND if there's no second one
|
||||||
else if(*emuNAND == 2){
|
else if(*emuNAND == 2)
|
||||||
|
{
|
||||||
*emuNAND = 1;
|
*emuNAND = 1;
|
||||||
getEmunandSect(off, head, emuNAND);
|
getEmunandSect(off, head, emuNAND);
|
||||||
}
|
}
|
||||||
@ -37,7 +43,8 @@ void getEmunandSect(u32 *off, u32 *head, u32 *emuNAND){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 getSDMMC(u8 *pos, u32 size){
|
u32 getSDMMC(u8 *pos, u32 size)
|
||||||
|
{
|
||||||
//Look for struct code
|
//Look for struct code
|
||||||
const u8 pattern[] = {0x21, 0x20, 0x18, 0x20};
|
const u8 pattern[] = {0x21, 0x20, 0x18, 0x20};
|
||||||
const u8 *off = memsearch(pos, pattern, size, 4) - 1;
|
const u8 *off = memsearch(pos, pattern, size, 4) - 1;
|
||||||
@ -45,7 +52,8 @@ u32 getSDMMC(u8 *pos, u32 size){
|
|||||||
return *(u32 *)(off + 0x0A) + *(u32 *)(off + 0x0E);
|
return *(u32 *)(off + 0x0A) + *(u32 *)(off + 0x0E);
|
||||||
}
|
}
|
||||||
|
|
||||||
void getEmuRW(u8 *pos, u32 size, u32 *readOff, u32 *writeOff){
|
void getEmuRW(u8 *pos, u32 size, u32 *readOff, u32 *writeOff)
|
||||||
|
{
|
||||||
//Look for read/write code
|
//Look for read/write code
|
||||||
const u8 pattern[] = {0x1E, 0x00, 0xC8, 0x05};
|
const u8 pattern[] = {0x1E, 0x00, 0xC8, 0x05};
|
||||||
|
|
||||||
@ -53,14 +61,16 @@ void getEmuRW(u8 *pos, u32 size, u32 *readOff, u32 *writeOff){
|
|||||||
*writeOff = (u32)memsearch((u8 *)(*readOff + 0xA), pattern, 0x100, 4) - 6;
|
*writeOff = (u32)memsearch((u8 *)(*readOff + 0xA), pattern, 0x100, 4) - 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 *getMPU(u8 *pos, u32 size){
|
u32 *getMPU(u8 *pos, u32 size)
|
||||||
|
{
|
||||||
//Look for MPU pattern
|
//Look for MPU pattern
|
||||||
const u8 pattern[] = {0x03, 0x00, 0x24, 0x00};
|
const u8 pattern[] = {0x03, 0x00, 0x24, 0x00};
|
||||||
|
|
||||||
return (u32 *)memsearch(pos, pattern, size, 4);
|
return (u32 *)memsearch(pos, pattern, size, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *getEmuCode(u8 *proc9Offset){
|
void *getEmuCode(u8 *proc9Offset)
|
||||||
|
{
|
||||||
const u8 pattern[] = {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00};
|
const u8 pattern[] = {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00};
|
||||||
|
|
||||||
//Looking for the last free space before Process9
|
//Looking for the last free space before Process9
|
||||||
|
159
source/firm.c
159
source/firm.c
@ -38,14 +38,17 @@ static u32 firmSize,
|
|||||||
emuOffset,
|
emuOffset,
|
||||||
emuHeader;
|
emuHeader;
|
||||||
|
|
||||||
void setupCFW(void){
|
void setupCFW(void)
|
||||||
|
{
|
||||||
//Determine if booting with A9LH
|
//Determine if booting with A9LH
|
||||||
u32 a9lhBoot = (PDN_SPI_CNT == 0x0) ? 1 : 0;
|
u32 a9lhBoot = !PDN_SPI_CNT ? 1 : 0;
|
||||||
|
|
||||||
//Retrieve the last booted FIRM
|
//Retrieve the last booted FIRM
|
||||||
u8 previousFirm = CFG_BOOTENV;
|
u8 previousFirm = CFG_BOOTENV;
|
||||||
|
|
||||||
//Detect the console being used
|
//Detect the console being used
|
||||||
console = (PDN_MPCORE_CFG == 1) ? 0 : 1;
|
console = (PDN_MPCORE_CFG == 1) ? 0 : 1;
|
||||||
|
|
||||||
//Get pressed buttons
|
//Get pressed buttons
|
||||||
u16 pressed = HID_PAD;
|
u16 pressed = HID_PAD;
|
||||||
|
|
||||||
@ -57,14 +60,18 @@ void setupCFW(void){
|
|||||||
//Determine if A9LH is installed and the user has an updated sysNAND
|
//Determine if A9LH is installed and the user has an updated sysNAND
|
||||||
u32 updatedSys;
|
u32 updatedSys;
|
||||||
|
|
||||||
if(a9lhBoot || (config >> 2) & 1){
|
if(a9lhBoot || (config >> 2) & 1)
|
||||||
|
{
|
||||||
if(pressed == SAFE_MODE)
|
if(pressed == SAFE_MODE)
|
||||||
error("Using Safe Mode would brick you, or remove A9LH!");
|
error("Using Safe Mode would brick you, or remove A9LH!");
|
||||||
|
|
||||||
a9lhSetup = 1;
|
a9lhSetup = 1;
|
||||||
|
|
||||||
//Check setting for > 9.2 sysNAND
|
//Check setting for > 9.2 sysNAND
|
||||||
updatedSys = config & 1;
|
updatedSys = config & 1;
|
||||||
} else{
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
a9lhSetup = 0;
|
a9lhSetup = 0;
|
||||||
updatedSys = 0;
|
updatedSys = 0;
|
||||||
}
|
}
|
||||||
@ -73,29 +80,35 @@ void setupCFW(void){
|
|||||||
|
|
||||||
/* If booting with A9LH, it's a MCU reboot and a previous configuration exists,
|
/* If booting with A9LH, it's a MCU reboot and a previous configuration exists,
|
||||||
try to force boot options */
|
try to force boot options */
|
||||||
if(a9lhBoot && previousFirm && needConfig == 1){
|
if(a9lhBoot && previousFirm && needConfig == 1)
|
||||||
|
{
|
||||||
//Always force a sysNAND boot when quitting AGB_FIRM
|
//Always force a sysNAND boot when quitting AGB_FIRM
|
||||||
if(previousFirm == 7){
|
if(previousFirm == 7)
|
||||||
|
{
|
||||||
mode = updatedSys ? 1 : (config >> 12) & 1;
|
mode = updatedSys ? 1 : (config >> 12) & 1;
|
||||||
emuNAND = 0;
|
emuNAND = 0;
|
||||||
|
needConfig = 0;
|
||||||
|
|
||||||
//Flag to prevent multiple boot options-forcing
|
//Flag to prevent multiple boot options-forcing
|
||||||
tempConfig |= 1 << 15;
|
tempConfig |= 1 << 15;
|
||||||
needConfig = 0;
|
}
|
||||||
/* Else, force the last used boot options unless A, L or R are pressed
|
/* Else, force the last used boot options unless A/L/R/SELECT are pressed
|
||||||
or the no-forcing flag is set */
|
or the no-forcing flag is set */
|
||||||
} else if(!(pressed & OPTION_BUTTONS) && !((config >> 15) & 1)){
|
else if(!(pressed & OPTION_BUTTONS) && !((config >> 15) & 1))
|
||||||
|
{
|
||||||
mode = (config >> 12) & 1;
|
mode = (config >> 12) & 1;
|
||||||
emuNAND = (config >> 13) & 3;
|
emuNAND = (config >> 13) & 3;
|
||||||
needConfig = 0;
|
needConfig = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(needConfig){
|
//Boot options aren't being forced
|
||||||
|
if(needConfig)
|
||||||
|
{
|
||||||
/* If L and one of the payload buttons are pressed, and if not using A9LH
|
/* If L and one of the payload buttons are pressed, and if not using A9LH
|
||||||
the Safe Mode combo is not pressed, chainload an external payload */
|
the Safe Mode combo is not pressed, chainload an external payload */
|
||||||
if((pressed & BUTTON_L1) && (pressed & PAYLOAD_BUTTONS) &&
|
if((pressed & BUTTON_L1) && (pressed & PAYLOAD_BUTTONS) && pressed != SAFE_MODE)
|
||||||
pressed != SAFE_MODE) loadPayload();
|
loadPayload();
|
||||||
|
|
||||||
//If no configuration file exists or SELECT is held, load configuration menu
|
//If no configuration file exists or SELECT is held, load configuration menu
|
||||||
if(needConfig == 2 || (pressed & BUTTON_SELECT))
|
if(needConfig == 2 || (pressed & BUTTON_SELECT))
|
||||||
@ -104,14 +117,15 @@ void setupCFW(void){
|
|||||||
//If screens are inited, load splash screen
|
//If screens are inited, load splash screen
|
||||||
if(PDN_GPU_CNT != 1) loadSplash();
|
if(PDN_GPU_CNT != 1) loadSplash();
|
||||||
|
|
||||||
/* If L is pressed, boot 9.0 FIRM */
|
/* If L is pressed, or L or R are not pressed when it is the default FIRM,
|
||||||
|
boot 9.0 FIRM */
|
||||||
mode = ((config >> 3) & 1) ? ((!(pressed & BUTTON_L1R1)) ? 0 : 1) :
|
mode = ((config >> 3) & 1) ? ((!(pressed & BUTTON_L1R1)) ? 0 : 1) :
|
||||||
((pressed & BUTTON_L1) ? 0 : 1);
|
((pressed & BUTTON_L1) ? 0 : 1);
|
||||||
|
|
||||||
/* If L or R aren't pressed on a 9.0/9.2 sysNAND, or the 9.0 FIRM is selected
|
/* If L or R aren't pressed on a 9.0/9.2 sysNAND, or the 9.0 FIRM is selected
|
||||||
or R is pressed on a > 9.2 sysNAND, boot emuNAND */
|
or R is pressed on a > 9.2 sysNAND, boot emuNAND */
|
||||||
if((updatedSys && (!mode || (pressed & BUTTON_R1))) ||
|
if((updatedSys && (!mode || (pressed & BUTTON_R1))) || (!updatedSys && mode && !(pressed & BUTTON_R1)))
|
||||||
(!updatedSys && mode && !(pressed & BUTTON_R1))){
|
{
|
||||||
//If not 9.0 FIRM and B is pressed, attempt booting the second emuNAND
|
//If not 9.0 FIRM and B is pressed, attempt booting the second emuNAND
|
||||||
emuNAND = (mode && ((!(pressed & BUTTON_B)) == ((config >> 4) & 1))) ? 2 : 1;
|
emuNAND = (mode && ((!(pressed & BUTTON_B)) == ((config >> 4) & 1))) ? 2 : 1;
|
||||||
} else emuNAND = 0;
|
} else emuNAND = 0;
|
||||||
@ -124,7 +138,8 @@ void setupCFW(void){
|
|||||||
|
|
||||||
u32 usePatchedFirmSet = ((config >> 1) & 1);
|
u32 usePatchedFirmSet = ((config >> 1) & 1);
|
||||||
|
|
||||||
while(1){
|
while(1)
|
||||||
|
{
|
||||||
/* Determine which patched FIRM we need to write or attempt to use (if any).
|
/* Determine which patched FIRM we need to write or attempt to use (if any).
|
||||||
Patched 9.0 FIRM is only needed if "Use pre-patched FIRMs" is set */
|
Patched 9.0 FIRM is only needed if "Use pre-patched FIRMs" is set */
|
||||||
selectedFirm = mode ? (emuNAND ? (emuNAND == 1 ? 2 : 3) : 1) :
|
selectedFirm = mode ? (emuNAND ? (emuNAND == 1 ? 2 : 3) : 1) :
|
||||||
@ -133,11 +148,15 @@ void setupCFW(void){
|
|||||||
//If "Use pre-patched FIRMs" is set and the appropriate FIRM exists, use it
|
//If "Use pre-patched FIRMs" is set and the appropriate FIRM exists, use it
|
||||||
if(usePatchedFirmSet && fileExists(patchedFirms[selectedFirm - 1]))
|
if(usePatchedFirmSet && fileExists(patchedFirms[selectedFirm - 1]))
|
||||||
usePatchedFirm = 1;
|
usePatchedFirm = 1;
|
||||||
|
|
||||||
|
else if(emuNAND)
|
||||||
|
{
|
||||||
//Detect EmuNAND
|
//Detect EmuNAND
|
||||||
else if(emuNAND){
|
|
||||||
getEmunandSect(&emuOffset, &emuHeader, &emuNAND);
|
getEmunandSect(&emuOffset, &emuHeader, &emuNAND);
|
||||||
|
|
||||||
//If none exists, force SysNAND + 9.6/10.x FIRM and re-detect patched FIRMs
|
//If none exists, force SysNAND + 9.6/10.x FIRM and re-detect patched FIRMs
|
||||||
if(!emuNAND){
|
if(!emuNAND)
|
||||||
|
{
|
||||||
mode = 1;
|
mode = 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -148,27 +167,32 @@ void setupCFW(void){
|
|||||||
tempConfig |= (emuNAND << 13) | (mode << 12);
|
tempConfig |= (emuNAND << 13) | (mode << 12);
|
||||||
|
|
||||||
//If the boot configuration is different from previously, overwrite it
|
//If the boot configuration is different from previously, overwrite it
|
||||||
if(tempConfig != (config & 0xFFF000)){
|
if(tempConfig != (config & 0xFFF000))
|
||||||
|
{
|
||||||
//Preserve user settings (first 12 bits)
|
//Preserve user settings (first 12 bits)
|
||||||
tempConfig |= config & 0xFFF;
|
tempConfig |= config & 0xFFF;
|
||||||
|
|
||||||
fileWrite(&tempConfig, configPath, 3);
|
fileWrite(&tempConfig, configPath, 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Load FIRM into FCRAM
|
//Load FIRM into FCRAM
|
||||||
void loadFirm(void){
|
void loadFirm(void)
|
||||||
|
{
|
||||||
//If not using an A9LH setup or the patched FIRM, load 9.0 FIRM from NAND
|
//If not using an A9LH setup or the patched FIRM, load 9.0 FIRM from NAND
|
||||||
if(!usePatchedFirm && !a9lhSetup && !mode){
|
if(!usePatchedFirm && !a9lhSetup && !mode)
|
||||||
|
{
|
||||||
//Read FIRM from NAND and write to FCRAM
|
//Read FIRM from NAND and write to FCRAM
|
||||||
firmSize = console ? 0xF2000 : 0xE9000;
|
firmSize = console ? 0xF2000 : 0xE9000;
|
||||||
nandFirm0((u8 *)firm, firmSize, console);
|
nandFirm0((u8 *)firm, firmSize, console);
|
||||||
|
|
||||||
//Check for correct decryption
|
//Check for correct decryption
|
||||||
if(memcmp(firm, "FIRM", 4) != 0)
|
if(memcmp(firm, "FIRM", 4) != 0)
|
||||||
error("Couldn't decrypt NAND FIRM0 (O3DS not on 9.x?)");
|
error("Couldn't decrypt NAND FIRM0 (O3DS not on 9.x?)");
|
||||||
}
|
}
|
||||||
//Load FIRM from SD
|
//Load FIRM from SD
|
||||||
else{
|
else
|
||||||
|
{
|
||||||
const char *path = usePatchedFirm ? patchedFirms[selectedFirm - 1] :
|
const char *path = usePatchedFirm ? patchedFirms[selectedFirm - 1] :
|
||||||
(mode ? "/aurei/firmware.bin" : "/aurei/firmware90.bin");
|
(mode ? "/aurei/firmware.bin" : "/aurei/firmware90.bin");
|
||||||
firmSize = fileSize(path);
|
firmSize = fileSize(path);
|
||||||
@ -188,8 +212,8 @@ void loadFirm(void){
|
|||||||
}
|
}
|
||||||
|
|
||||||
//NAND redirection
|
//NAND redirection
|
||||||
static inline void loadEmu(u8 *proc9Offset){
|
static inline void patchEmuNAND(u8 *proc9Offset)
|
||||||
|
{
|
||||||
//Copy emuNAND code
|
//Copy emuNAND code
|
||||||
void *emuCodeOffset = getEmuCode(proc9Offset);
|
void *emuCodeOffset = getEmuCode(proc9Offset);
|
||||||
memcpy(emuCodeOffset, emunand, emunand_size);
|
memcpy(emuCodeOffset, emunand, emunand_size);
|
||||||
@ -227,23 +251,11 @@ static inline void loadEmu(u8 *proc9Offset){
|
|||||||
*(mpuOffset + 9) = mpuPatch[2];
|
*(mpuOffset + 9) = mpuPatch[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
//Patches
|
static inline void patchReboots(u8 *proc9Offset)
|
||||||
void patchFirm(void){
|
{
|
||||||
|
|
||||||
//Skip patching
|
|
||||||
if(usePatchedFirm) return;
|
|
||||||
|
|
||||||
if(mode || emuNAND){
|
|
||||||
//Find the Process9 NCCH location
|
|
||||||
u8 *proc9Offset = getProc9(arm9Section, section[2].size);
|
|
||||||
|
|
||||||
//Apply emuNAND patches
|
|
||||||
if(emuNAND) loadEmu(proc9Offset);
|
|
||||||
|
|
||||||
//Patch FIRM reboots, not on 9.0 FIRM as it breaks firmlaunchhax
|
|
||||||
if(mode){
|
|
||||||
//Calculate offset for the firmlaunch code
|
//Calculate offset for the firmlaunch code
|
||||||
void *rebootOffset = getReboot(arm9Section, section[2].size);
|
void *rebootOffset = getReboot(arm9Section, section[2].size);
|
||||||
|
|
||||||
//Calculate offset for the fOpen function
|
//Calculate offset for the fOpen function
|
||||||
u32 fOpenOffset = getfOpen(proc9Offset, rebootOffset);
|
u32 fOpenOffset = getfOpen(proc9Offset, rebootOffset);
|
||||||
|
|
||||||
@ -255,21 +267,59 @@ void patchFirm(void){
|
|||||||
*pos_fopen = fOpenOffset;
|
*pos_fopen = fOpenOffset;
|
||||||
|
|
||||||
//Patch path for emuNAND-patched FIRM
|
//Patch path for emuNAND-patched FIRM
|
||||||
if(emuNAND){
|
if(emuNAND)
|
||||||
|
{
|
||||||
void *pos_path = memsearch(rebootOffset, L"sy", reboot_size, 4);
|
void *pos_path = memsearch(rebootOffset, L"sy", reboot_size, 4);
|
||||||
memcpy(pos_path, emuNAND == 1 ? L"emu" : L"em2", 5);
|
memcpy(pos_path, emuNAND == 1 ? L"emu" : L"em2", 5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void injectLoader(void)
|
||||||
|
{
|
||||||
|
u32 loaderOffset,
|
||||||
|
loaderSize;
|
||||||
|
|
||||||
|
getLoader((u8 *)firm + section[0].offset, section[0].size, &loaderOffset, &loaderSize);
|
||||||
|
|
||||||
|
//Check that the injector CXI isn't larger than the original
|
||||||
|
if(injector_size <= (int)loaderSize)
|
||||||
|
{
|
||||||
|
memset((void *)loaderOffset, 0, loaderSize);
|
||||||
|
memcpy((void *)loaderOffset, injector, injector_size);
|
||||||
|
|
||||||
|
//Patch content size and ExeFS size to match the repaced loader's ones
|
||||||
|
*((u32 *)loaderOffset + 0x41) = loaderSize / 0x200;
|
||||||
|
*((u32 *)loaderOffset + 0x69) = loaderSize / 0x200 - 5;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(a9lhSetup && !emuNAND){
|
//Patches
|
||||||
//Patch FIRM partitions writes on sysNAND to protect A9LH
|
void patchFirm(void)
|
||||||
|
{
|
||||||
|
//Skip patching
|
||||||
|
if(usePatchedFirm) return;
|
||||||
|
|
||||||
|
if(mode || emuNAND)
|
||||||
|
{
|
||||||
|
//Find the Process9 NCCH location
|
||||||
|
u8 *proc9Offset = getProc9(arm9Section, section[2].size);
|
||||||
|
|
||||||
|
//Apply emuNAND patches
|
||||||
|
if(emuNAND) patchEmuNAND(proc9Offset);
|
||||||
|
|
||||||
|
//Apply FIRM reboot patches, not on 9.0 FIRM as it breaks firmlaunchhax
|
||||||
|
if(mode) patchReboots(proc9Offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Apply FIRM0/1 writes patches on sysNAND to protect A9LH
|
||||||
|
if(a9lhSetup && !emuNAND)
|
||||||
|
{
|
||||||
u16 *writeOffset = getFirmWrite(arm9Section, section[2].size);
|
u16 *writeOffset = getFirmWrite(arm9Section, section[2].size);
|
||||||
*writeOffset = writeBlock[0];
|
*writeOffset = writeBlock[0];
|
||||||
*(writeOffset + 1) = writeBlock[1];
|
*(writeOffset + 1) = writeBlock[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
//Disable signature checks
|
//Apply signature checks patches
|
||||||
u32 sigOffset,
|
u32 sigOffset,
|
||||||
sigOffset2;
|
sigOffset2;
|
||||||
|
|
||||||
@ -279,18 +329,7 @@ void patchFirm(void){
|
|||||||
*((u16 *)sigOffset2 + 1) = sigPatch[1];
|
*((u16 *)sigOffset2 + 1) = sigPatch[1];
|
||||||
|
|
||||||
//Replace the FIRM loader with the injector
|
//Replace the FIRM loader with the injector
|
||||||
u32 loaderOffset,
|
injectLoader();
|
||||||
loaderSize;
|
|
||||||
|
|
||||||
getLoader((u8 *)firm + section[0].offset, section[0].size, &loaderOffset, &loaderSize);
|
|
||||||
//Check that the injector CXI isn't larger than the original
|
|
||||||
if(injector_size <= (int)loaderSize){
|
|
||||||
memset((void *)loaderOffset, 0, loaderSize);
|
|
||||||
memcpy((void *)loaderOffset, injector, injector_size);
|
|
||||||
//Patch content size and ExeFS size to match the repaced loader's ones
|
|
||||||
*((u32 *)loaderOffset + 0x41) = loaderSize / 0x200;
|
|
||||||
*((u32 *)loaderOffset + 0x69) = loaderSize / 0x200 - 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Patch ARM9 entrypoint on N3DS to skip arm9loader
|
//Patch ARM9 entrypoint on N3DS to skip arm9loader
|
||||||
if(console)
|
if(console)
|
||||||
@ -302,8 +341,8 @@ void patchFirm(void){
|
|||||||
error("Couldn't write the patched FIRM (no free space?)");
|
error("Couldn't write the patched FIRM (no free space?)");
|
||||||
}
|
}
|
||||||
|
|
||||||
void launchFirm(void){
|
void launchFirm(void)
|
||||||
|
{
|
||||||
if(console && mode) setKeyXs(arm9Section);
|
if(console && mode) setKeyXs(arm9Section);
|
||||||
|
|
||||||
//Copy firm partitions to respective memory locations
|
//Copy firm partitions to respective memory locations
|
||||||
|
21
source/fs.c
21
source/fs.c
@ -9,18 +9,21 @@
|
|||||||
|
|
||||||
static FATFS fs;
|
static FATFS fs;
|
||||||
|
|
||||||
u32 mountSD(void){
|
u32 mountSD(void)
|
||||||
|
{
|
||||||
if(f_mount(&fs, "0:", 1) != FR_OK) return 0;
|
if(f_mount(&fs, "0:", 1) != FR_OK) return 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 fileRead(void *dest, const char *path, u32 size){
|
u32 fileRead(void *dest, const char *path, u32 size)
|
||||||
|
{
|
||||||
FRESULT fr;
|
FRESULT fr;
|
||||||
FIL fp;
|
FIL fp;
|
||||||
unsigned int br = 0;
|
unsigned int br = 0;
|
||||||
|
|
||||||
fr = f_open(&fp, path, FA_READ);
|
fr = f_open(&fp, path, FA_READ);
|
||||||
if(fr == FR_OK){
|
if(fr == FR_OK)
|
||||||
|
{
|
||||||
if(!size) size = f_size(&fp);
|
if(!size) size = f_size(&fp);
|
||||||
fr = f_read(&fp, dest, size, &br);
|
fr = f_read(&fp, dest, size, &br);
|
||||||
}
|
}
|
||||||
@ -29,7 +32,8 @@ u32 fileRead(void *dest, const char *path, u32 size){
|
|||||||
return fr ? 0 : 1;
|
return fr ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 fileWrite(const void *buffer, const char *path, u32 size){
|
u32 fileWrite(const void *buffer, const char *path, u32 size)
|
||||||
|
{
|
||||||
FRESULT fr;
|
FRESULT fr;
|
||||||
FIL fp;
|
FIL fp;
|
||||||
unsigned int br = 0;
|
unsigned int br = 0;
|
||||||
@ -41,7 +45,8 @@ u32 fileWrite(const void *buffer, const char *path, u32 size){
|
|||||||
return fr ? 0 : 1;
|
return fr ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 fileSize(const char *path){
|
u32 fileSize(const char *path)
|
||||||
|
{
|
||||||
FIL fp;
|
FIL fp;
|
||||||
u32 size = 0;
|
u32 size = 0;
|
||||||
|
|
||||||
@ -52,7 +57,8 @@ u32 fileSize(const char *path){
|
|||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 fileExists(const char *path){
|
u32 fileExists(const char *path)
|
||||||
|
{
|
||||||
FIL fp;
|
FIL fp;
|
||||||
u32 exists = 0;
|
u32 exists = 0;
|
||||||
|
|
||||||
@ -62,6 +68,7 @@ u32 fileExists(const char *path){
|
|||||||
return exists;
|
return exists;
|
||||||
}
|
}
|
||||||
|
|
||||||
void fileDelete(const char *path){
|
void fileDelete(const char *path)
|
||||||
|
{
|
||||||
f_unlink(path);
|
f_unlink(path);
|
||||||
}
|
}
|
40
source/i2c.c
40
source/i2c.c
@ -10,11 +10,13 @@ static const struct { u8 bus_id, reg_addr; } dev_data[] = {
|
|||||||
{2, 0xA4}, {2, 0x9A}, {2, 0xA0},
|
{2, 0xA4}, {2, 0x9A}, {2, 0xA0},
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline u8 i2cGetDeviceBusId(u8 device_id) {
|
static inline u8 i2cGetDeviceBusId(u8 device_id)
|
||||||
|
{
|
||||||
return dev_data[device_id].bus_id;
|
return dev_data[device_id].bus_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u8 i2cGetDeviceRegAddr(u8 device_id) {
|
static inline u8 i2cGetDeviceRegAddr(u8 device_id)
|
||||||
|
{
|
||||||
return dev_data[device_id].reg_addr;
|
return dev_data[device_id].reg_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,7 +28,8 @@ static vu8* reg_data_addrs[] = {
|
|||||||
(vu8*)(I2C3_REG_OFF + I2C_REG_DATA),
|
(vu8*)(I2C3_REG_OFF + I2C_REG_DATA),
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline vu8* i2cGetDataReg(u8 bus_id) {
|
static inline vu8* i2cGetDataReg(u8 bus_id)
|
||||||
|
{
|
||||||
return reg_data_addrs[bus_id];
|
return reg_data_addrs[bus_id];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,22 +41,27 @@ static vu8* reg_cnt_addrs[] = {
|
|||||||
(vu8*)(I2C3_REG_OFF + I2C_REG_CNT),
|
(vu8*)(I2C3_REG_OFF + I2C_REG_CNT),
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline vu8* i2cGetCntReg(u8 bus_id) {
|
static inline vu8* i2cGetCntReg(u8 bus_id)
|
||||||
|
{
|
||||||
return reg_cnt_addrs[bus_id];
|
return reg_cnt_addrs[bus_id];
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
static inline void i2cWaitBusy(u8 bus_id) {
|
static inline void i2cWaitBusy(u8 bus_id)
|
||||||
|
{
|
||||||
while (*i2cGetCntReg(bus_id) & 0x80);
|
while (*i2cGetCntReg(bus_id) & 0x80);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u32 i2cGetResult(u8 bus_id) {
|
static inline u32 i2cGetResult(u8 bus_id)
|
||||||
|
{
|
||||||
i2cWaitBusy(bus_id);
|
i2cWaitBusy(bus_id);
|
||||||
|
|
||||||
return (*i2cGetCntReg(bus_id) >> 4) & 1;
|
return (*i2cGetCntReg(bus_id) >> 4) & 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void i2cStop(u8 bus_id, u8 arg0) {
|
static void i2cStop(u8 bus_id, u8 arg0)
|
||||||
|
{
|
||||||
*i2cGetCntReg(bus_id) = (arg0 << 5) | 0xC0;
|
*i2cGetCntReg(bus_id) = (arg0 << 5) | 0xC0;
|
||||||
i2cWaitBusy(bus_id);
|
i2cWaitBusy(bus_id);
|
||||||
*i2cGetCntReg(bus_id) = 0xC5;
|
*i2cGetCntReg(bus_id) = 0xC5;
|
||||||
@ -61,32 +69,40 @@ static void i2cStop(u8 bus_id, u8 arg0) {
|
|||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
static u32 i2cSelectDevice(u8 bus_id, u8 dev_reg) {
|
static u32 i2cSelectDevice(u8 bus_id, u8 dev_reg)
|
||||||
|
{
|
||||||
i2cWaitBusy(bus_id);
|
i2cWaitBusy(bus_id);
|
||||||
*i2cGetDataReg(bus_id) = dev_reg;
|
*i2cGetDataReg(bus_id) = dev_reg;
|
||||||
*i2cGetCntReg(bus_id) = 0xC2;
|
*i2cGetCntReg(bus_id) = 0xC2;
|
||||||
|
|
||||||
return i2cGetResult(bus_id);
|
return i2cGetResult(bus_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 i2cSelectRegister(u8 bus_id, u8 reg) {
|
static u32 i2cSelectRegister(u8 bus_id, u8 reg)
|
||||||
|
{
|
||||||
i2cWaitBusy(bus_id);
|
i2cWaitBusy(bus_id);
|
||||||
*i2cGetDataReg(bus_id) = reg;
|
*i2cGetDataReg(bus_id) = reg;
|
||||||
*i2cGetCntReg(bus_id) = 0xC0;
|
*i2cGetCntReg(bus_id) = 0xC0;
|
||||||
|
|
||||||
return i2cGetResult(bus_id);
|
return i2cGetResult(bus_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
u32 i2cWriteRegister(u8 dev_id, u8 reg, u8 data) {
|
u32 i2cWriteRegister(u8 dev_id, u8 reg, u8 data)
|
||||||
|
{
|
||||||
u8 bus_id = i2cGetDeviceBusId(dev_id);
|
u8 bus_id = i2cGetDeviceBusId(dev_id);
|
||||||
u8 dev_addr = i2cGetDeviceRegAddr(dev_id);
|
u8 dev_addr = i2cGetDeviceRegAddr(dev_id);
|
||||||
|
|
||||||
for (int i = 0; i < 8; i++) {
|
for (u32 i = 0; i < 8; i++)
|
||||||
if (i2cSelectDevice(bus_id, dev_addr) && i2cSelectRegister(bus_id, reg)) {
|
{
|
||||||
|
if (i2cSelectDevice(bus_id, dev_addr) && i2cSelectRegister(bus_id, reg))
|
||||||
|
{
|
||||||
i2cWaitBusy(bus_id);
|
i2cWaitBusy(bus_id);
|
||||||
*i2cGetDataReg(bus_id) = data;
|
*i2cGetDataReg(bus_id) = data;
|
||||||
*i2cGetCntReg(bus_id) = 0xC1;
|
*i2cGetCntReg(bus_id) = 0xC1;
|
||||||
i2cStop(bus_id, 0);
|
i2cStop(bus_id, 0);
|
||||||
|
|
||||||
if (i2cGetResult(bus_id))
|
if (i2cGetResult(bus_id))
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -12,8 +12,10 @@
|
|||||||
|
|
||||||
#define PAYLOAD_ADDRESS 0x24F00000
|
#define PAYLOAD_ADDRESS 0x24F00000
|
||||||
|
|
||||||
void loadPayload(void){
|
void loadPayload(void)
|
||||||
if(fileExists("aurei/payloads/default.bin")){
|
{
|
||||||
|
if(fileExists("aurei/payloads/default.bin"))
|
||||||
|
{
|
||||||
initScreens();
|
initScreens();
|
||||||
memcpy((void *)PAYLOAD_ADDRESS, loader, loader_size);
|
memcpy((void *)PAYLOAD_ADDRESS, loader, loader_size);
|
||||||
((void (*)())PAYLOAD_ADDRESS)();
|
((void (*)())PAYLOAD_ADDRESS)();
|
||||||
|
@ -9,7 +9,8 @@
|
|||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
#include "firm.h"
|
#include "firm.h"
|
||||||
|
|
||||||
void main(void){
|
void main(void)
|
||||||
|
{
|
||||||
mountSD();
|
mountSD();
|
||||||
setupCFW();
|
setupCFW();
|
||||||
loadFirm();
|
loadFirm();
|
||||||
|
@ -8,36 +8,43 @@
|
|||||||
|
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
|
|
||||||
void memcpy(void *dest, const void *src, u32 size){
|
void memcpy(void *dest, const void *src, u32 size)
|
||||||
|
{
|
||||||
u8 *destc = (u8 *)dest;
|
u8 *destc = (u8 *)dest;
|
||||||
const u8 *srcc = (const u8 *)src;
|
const u8 *srcc = (const u8 *)src;
|
||||||
for(u32 i = 0; i < size; i++)
|
for(u32 i = 0; i < size; i++)
|
||||||
destc[i] = srcc[i];
|
destc[i] = srcc[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
void memset(void *dest, int filler, u32 size){
|
void memset(void *dest, int filler, u32 size)
|
||||||
|
{
|
||||||
u8 *destc = (u8 *)dest;
|
u8 *destc = (u8 *)dest;
|
||||||
for(u32 i = 0; i < size; i++)
|
for(u32 i = 0; i < size; i++)
|
||||||
destc[i] = (u8)filler;
|
destc[i] = (u8)filler;
|
||||||
}
|
}
|
||||||
|
|
||||||
void memset32(void *dest, u32 filler, u32 size){
|
void memset32(void *dest, u32 filler, u32 size)
|
||||||
|
{
|
||||||
u32 *dest32 = (u32 *)dest;
|
u32 *dest32 = (u32 *)dest;
|
||||||
for (u32 i = 0; i < size / 4; i++)
|
for (u32 i = 0; i < size / 4; i++)
|
||||||
dest32[i] = filler;
|
dest32[i] = filler;
|
||||||
}
|
}
|
||||||
|
|
||||||
int memcmp(const void *buf1, const void *buf2, u32 size){
|
int memcmp(const void *buf1, const void *buf2, u32 size)
|
||||||
|
{
|
||||||
const u8 *buf1c = (const u8 *)buf1;
|
const u8 *buf1c = (const u8 *)buf1;
|
||||||
const u8 *buf2c = (const u8 *)buf2;
|
const u8 *buf2c = (const u8 *)buf2;
|
||||||
for(u32 i = 0; i < size; i++){
|
for(u32 i = 0; i < size; i++)
|
||||||
|
{
|
||||||
int cmp = buf1c[i] - buf2c[i];
|
int cmp = buf1c[i] - buf2c[i];
|
||||||
if(cmp) return cmp;
|
if(cmp) return cmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize){
|
u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize)
|
||||||
|
{
|
||||||
const u8 *patternc = (const u8 *)pattern;
|
const u8 *patternc = (const u8 *)pattern;
|
||||||
|
|
||||||
//Preprocessing
|
//Preprocessing
|
||||||
@ -51,7 +58,8 @@ u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize){
|
|||||||
//Searching
|
//Searching
|
||||||
u32 j = 0;
|
u32 j = 0;
|
||||||
|
|
||||||
while(j <= size - patternSize){
|
while(j <= size - patternSize)
|
||||||
|
{
|
||||||
if(memcmp(patternc, startPos + j, patternSize) == 0)
|
if(memcmp(patternc, startPos + j, patternSize) == 0)
|
||||||
return startPos + j;
|
return startPos + j;
|
||||||
j += table[startPos[j + patternSize]];
|
j += table[startPos[j + patternSize]];
|
||||||
|
@ -23,11 +23,13 @@ const u16 writeBlock[2] = {0x2000, 0x46C0};
|
|||||||
* Functions
|
* Functions
|
||||||
**************************************************/
|
**************************************************/
|
||||||
|
|
||||||
u8 *getProc9(u8 *pos, u32 size){
|
u8 *getProc9(u8 *pos, u32 size)
|
||||||
|
{
|
||||||
return memsearch(pos, "ess9", size, 4);
|
return memsearch(pos, "ess9", size, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
void getSigChecks(u8 *pos, u32 size, u32 *off, u32 *off2){
|
void getSigChecks(u8 *pos, u32 size, u32 *off, u32 *off2)
|
||||||
|
{
|
||||||
//Look for signature checks
|
//Look for signature checks
|
||||||
const u8 pattern[] = {0xC0, 0x1C, 0x76, 0xE7},
|
const u8 pattern[] = {0xC0, 0x1C, 0x76, 0xE7},
|
||||||
pattern2[] = {0xB5, 0x22, 0x4D, 0x0C};
|
pattern2[] = {0xB5, 0x22, 0x4D, 0x0C};
|
||||||
@ -36,16 +38,19 @@ void getSigChecks(u8 *pos, u32 size, u32 *off, u32 *off2){
|
|||||||
*off2 = (u32)memsearch(pos, pattern2, size, 4) - 1;
|
*off2 = (u32)memsearch(pos, pattern2, size, 4) - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *getReboot(u8 *pos, u32 size){
|
void *getReboot(u8 *pos, u32 size)
|
||||||
|
{
|
||||||
//Look for FIRM reboot code
|
//Look for FIRM reboot code
|
||||||
const u8 pattern[] = {0xDE, 0x1F, 0x8D, 0xE2};
|
const u8 pattern[] = {0xDE, 0x1F, 0x8D, 0xE2};
|
||||||
|
|
||||||
return memsearch(pos, pattern, size, 4) - 0x10;
|
return memsearch(pos, pattern, size, 4) - 0x10;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 getfOpen(u8 *proc9Offset, void *rebootOffset){
|
u32 getfOpen(u8 *proc9Offset, void *rebootOffset)
|
||||||
|
{
|
||||||
//Offset Process9 code gets loaded to in memory (defined in ExHeader)
|
//Offset Process9 code gets loaded to in memory (defined in ExHeader)
|
||||||
u32 p9MemAddr = *(u32 *)(proc9Offset + 0xC);
|
u32 p9MemAddr = *(u32 *)(proc9Offset + 0xC);
|
||||||
|
|
||||||
//Process9 code offset (start of NCCH + ExeFS offset + ExeFS header size)
|
//Process9 code offset (start of NCCH + ExeFS offset + ExeFS header size)
|
||||||
u32 p9CodeOff = (u32)(proc9Offset - 0x204) + (*(u32 *)(proc9Offset - 0x64) * 0x200) + 0x200;
|
u32 p9CodeOff = (u32)(proc9Offset - 0x204) + (*(u32 *)(proc9Offset - 0x64) * 0x200) + 0x200;
|
||||||
|
|
||||||
@ -53,7 +58,8 @@ u32 getfOpen(u8 *proc9Offset, void *rebootOffset){
|
|||||||
return (u32)rebootOffset + 9 - (-((*(u32 *)rebootOffset & 0x00FFFFFF) << 2) & 0xFFFFF) - p9CodeOff + p9MemAddr;
|
return (u32)rebootOffset + 9 - (-((*(u32 *)rebootOffset & 0x00FFFFFF) << 2) & 0xFFFFF) - p9CodeOff + p9MemAddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 *getFirmWrite(u8 *pos, u32 size){
|
u16 *getFirmWrite(u8 *pos, u32 size)
|
||||||
|
{
|
||||||
//Look for FIRM writing code
|
//Look for FIRM writing code
|
||||||
u8 *const off = memsearch(pos, "exe:", size, 4);
|
u8 *const off = memsearch(pos, "exe:", size, 4);
|
||||||
const u8 pattern[] = {0x00, 0x28, 0x01, 0xDA};
|
const u8 pattern[] = {0x00, 0x28, 0x01, 0xDA};
|
||||||
@ -61,7 +67,8 @@ u16 *getFirmWrite(u8 *pos, u32 size){
|
|||||||
return (u16 *)memsearch(off - 0x100, pattern, 0x100, 4);
|
return (u16 *)memsearch(off - 0x100, pattern, 0x100, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
void getLoader(u8 *pos, u32 size, u32 *loaderOffset, u32 *loaderSize){
|
void getLoader(u8 *pos, u32 size, u32 *loaderOffset, u32 *loaderSize)
|
||||||
|
{
|
||||||
u8 *const off = memsearch(pos, "loade", size, 5);
|
u8 *const off = memsearch(pos, "loade", size, 5);
|
||||||
|
|
||||||
*loaderOffset = (u32)off - 0x200;
|
*loaderOffset = (u32)off - 0x200;
|
||||||
|
@ -17,8 +17,10 @@
|
|||||||
|
|
||||||
static vu32 *const arm11 = (u32 *)0x1FFFFFF8;
|
static vu32 *const arm11 = (u32 *)0x1FFFFFF8;
|
||||||
|
|
||||||
void deinitScreens(void){
|
void deinitScreens(void)
|
||||||
void __attribute__((naked)) ARM11(void){
|
{
|
||||||
|
void __attribute__((naked)) ARM11(void)
|
||||||
|
{
|
||||||
//Disable interrupts
|
//Disable interrupts
|
||||||
__asm(".word 0xF10C01C0");
|
__asm(".word 0xF10C01C0");
|
||||||
|
|
||||||
@ -32,22 +34,28 @@ void deinitScreens(void){
|
|||||||
|
|
||||||
//Wait for the entry to be set
|
//Wait for the entry to be set
|
||||||
while(!*arm11);
|
while(!*arm11);
|
||||||
|
|
||||||
//Jump to it
|
//Jump to it
|
||||||
((void (*)())*arm11)();
|
((void (*)())*arm11)();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(PDN_GPU_CNT != 1){
|
if(PDN_GPU_CNT != 1)
|
||||||
|
{
|
||||||
*arm11 = (u32)ARM11;
|
*arm11 = (u32)ARM11;
|
||||||
while(*arm11);
|
while(*arm11);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void initScreens(void){
|
void initScreens(void)
|
||||||
|
{
|
||||||
|
if(PDN_GPU_CNT == 1)
|
||||||
|
{
|
||||||
memcpy((void *)SCREENINIT_ADDRESS, screeninit, screeninit_size);
|
memcpy((void *)SCREENINIT_ADDRESS, screeninit, screeninit_size);
|
||||||
|
|
||||||
if(PDN_GPU_CNT == 1){
|
|
||||||
*arm11 = SCREENINIT_ADDRESS;
|
*arm11 = SCREENINIT_ADDRESS;
|
||||||
while(*arm11);
|
while(*arm11);
|
||||||
|
|
||||||
|
//Turn on backlight
|
||||||
i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x2A);
|
i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x2A);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,7 +50,4 @@ _start:
|
|||||||
mov r1, #0x340
|
mov r1, #0x340
|
||||||
str r1, [r0]
|
str r1, [r0]
|
||||||
|
|
||||||
bl main
|
b main
|
||||||
|
|
||||||
.die:
|
|
||||||
b .die
|
|
||||||
|
@ -21,7 +21,8 @@ struct option {
|
|||||||
u32 enabled;
|
u32 enabled;
|
||||||
};
|
};
|
||||||
|
|
||||||
static u16 waitInput(void){
|
static u16 waitInput(void)
|
||||||
|
{
|
||||||
u32 pressedKey = 0;
|
u32 pressedKey = 0;
|
||||||
u16 key;
|
u16 key;
|
||||||
|
|
||||||
@ -34,7 +35,8 @@ static u16 waitInput(void){
|
|||||||
key = HID_PAD;
|
key = HID_PAD;
|
||||||
|
|
||||||
//Make sure it's pressed
|
//Make sure it's pressed
|
||||||
for(u32 i = 0x13000; i; i--){
|
for(u32 i = 0x13000; i; i--)
|
||||||
|
{
|
||||||
if(key != HID_PAD) break;
|
if(key != HID_PAD) break;
|
||||||
if(i == 1) pressedKey = 1;
|
if(i == 1) pressedKey = 1;
|
||||||
}
|
}
|
||||||
@ -43,7 +45,8 @@ static u16 waitInput(void){
|
|||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
void configureCFW(const char *configPath, const char *firm90Path){
|
void configureCFW(const char *configPath, const char *firm90Path)
|
||||||
|
{
|
||||||
initScreens();
|
initScreens();
|
||||||
|
|
||||||
drawString(CONFIG_TITLE, 10, 10, COLOR_TITLE);
|
drawString(CONFIG_TITLE, 10, 10, COLOR_TITLE);
|
||||||
@ -62,6 +65,7 @@ void configureCFW(const char *configPath, const char *firm90Path){
|
|||||||
//Read and parse the existing configuration
|
//Read and parse the existing configuration
|
||||||
u32 tempConfig = 0;
|
u32 tempConfig = 0;
|
||||||
fileRead(&tempConfig, configPath, 3);
|
fileRead(&tempConfig, configPath, 3);
|
||||||
|
|
||||||
for(u32 i = 0; i < optionsAmount; i++)
|
for(u32 i = 0; i < optionsAmount; i++)
|
||||||
options[i].enabled = (tempConfig >> i) & 1;
|
options[i].enabled = (tempConfig >> i) & 1;
|
||||||
|
|
||||||
@ -69,18 +73,22 @@ void configureCFW(const char *configPath, const char *firm90Path){
|
|||||||
u32 selectedOption = 0;
|
u32 selectedOption = 0;
|
||||||
|
|
||||||
//Boring configuration menu
|
//Boring configuration menu
|
||||||
while(1){
|
while(1)
|
||||||
|
{
|
||||||
u16 pressed = 0;
|
u16 pressed = 0;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
for(u32 i = 0; i < optionsAmount; i++){
|
for(u32 i = 0; i < optionsAmount; i++)
|
||||||
|
{
|
||||||
options[i].posY = drawString(optionsText[i], 10, !i ? 60 : options[i - 1].posY + SPACING_Y, selectedOption == i ? COLOR_RED : COLOR_WHITE);
|
options[i].posY = drawString(optionsText[i], 10, !i ? 60 : options[i - 1].posY + SPACING_Y, selectedOption == i ? COLOR_RED : COLOR_WHITE);
|
||||||
drawCharacter('x', 10 + SPACING_X, options[i].posY, options[i].enabled ? (selectedOption == i ? COLOR_RED : COLOR_WHITE) : COLOR_BLACK);
|
drawCharacter('x', 10 + SPACING_X, options[i].posY, options[i].enabled ? (selectedOption == i ? COLOR_RED : COLOR_WHITE) : COLOR_BLACK);
|
||||||
}
|
}
|
||||||
|
|
||||||
pressed = waitInput();
|
pressed = waitInput();
|
||||||
} while(!(pressed & MENU_BUTTONS));
|
} while(!(pressed & MENU_BUTTONS));
|
||||||
|
|
||||||
switch(pressed){
|
switch(pressed)
|
||||||
|
{
|
||||||
case BUTTON_UP:
|
case BUTTON_UP:
|
||||||
selectedOption = !selectedOption ? optionsAmount - 1 : selectedOption - 1;
|
selectedOption = !selectedOption ? optionsAmount - 1 : selectedOption - 1;
|
||||||
break;
|
break;
|
||||||
@ -110,6 +118,7 @@ void configureCFW(const char *configPath, const char *firm90Path){
|
|||||||
//Parse and write the selected options
|
//Parse and write the selected options
|
||||||
for(u32 i = 0; i < optionsAmount; i++)
|
for(u32 i = 0; i < optionsAmount; i++)
|
||||||
tempConfig |= options[i].enabled << i;
|
tempConfig |= options[i].enabled << i;
|
||||||
|
|
||||||
fileWrite(&tempConfig, configPath, 3);
|
fileWrite(&tempConfig, configPath, 3);
|
||||||
|
|
||||||
//Zero the last booted FIRM flag
|
//Zero the last booted FIRM flag
|
||||||
@ -120,14 +129,17 @@ void configureCFW(const char *configPath, const char *firm90Path){
|
|||||||
while(1);
|
while(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void deleteFirms(const char *firmPaths[], u32 firms){
|
void deleteFirms(const char *firmPaths[], u32 firms)
|
||||||
while(firms){
|
{
|
||||||
|
while(firms)
|
||||||
|
{
|
||||||
fileDelete(firmPaths[firms - 1]);
|
fileDelete(firmPaths[firms - 1]);
|
||||||
firms--;
|
firms--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void error(const char *message){
|
void error(const char *message)
|
||||||
|
{
|
||||||
initScreens();
|
initScreens();
|
||||||
|
|
||||||
drawString("An error has occurred:", 10, 10, COLOR_RED);
|
drawString("An error has occurred:", 10, 10, COLOR_RED);
|
||||||
|
Reference in New Issue
Block a user