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:
Aurora 2016-04-02 17:58:06 +02:00
parent 6b64a10362
commit 3475cfe1e6
21 changed files with 333 additions and 186 deletions

View File

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

View File

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

View File

@ -16,7 +16,7 @@ include $(DEVKITARM)/3ds_rules
# INCLUDES is a list of directories containing header files # INCLUDES is a list of directories containing header files
# SPECS is the directory containing the important build and link files # SPECS is the directory containing the important build and link files
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
export TARGET := $(shell basename $(CURDIR)) export TARGET := $(shell basename $(CURDIR))
BUILD := build BUILD := build
SOURCES := source source/fatfs source/fatfs/sdmmc SOURCES := source source/fatfs source/fatfs/sdmmc

View File

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

View File

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

View File

@ -16,7 +16,7 @@ include $(DEVKITARM)/3ds_rules
# INCLUDES is a list of directories containing header files # INCLUDES is a list of directories containing header files
# SPECS is the directory containing the important build and link files # SPECS is the directory containing the important build and link files
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
export TARGET := $(shell basename $(CURDIR)) export TARGET := $(shell basename $(CURDIR))
BUILD := build BUILD := build
SOURCES := source SOURCES := source

View File

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

View File

@ -5,7 +5,4 @@ _start:
@ Disable interrupts @ Disable interrupts
CPSID aif CPSID aif
bl main b main
.die:
b .die

View File

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

View File

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

View File

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

View File

@ -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;
//Detect EmuNAND
else if(emuNAND){ else if(emuNAND)
{
//Detect 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,29 +167,34 @@ 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);
if(!firmSize) error("aurei/firmware(90).bin doesn't exist"); if(!firmSize) error("aurei/firmware(90).bin doesn't exist");
fileRead(firm, path, firmSize); fileRead(firm, path, firmSize);
@ -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,49 +251,75 @@ static inline void loadEmu(u8 *proc9Offset){
*(mpuOffset + 9) = mpuPatch[2]; *(mpuOffset + 9) = mpuPatch[2];
} }
//Patches static inline void patchReboots(u8 *proc9Offset)
void patchFirm(void){ {
//Calculate offset for the firmlaunch code
void *rebootOffset = getReboot(arm9Section, section[2].size);
//Calculate offset for the fOpen function
u32 fOpenOffset = getfOpen(proc9Offset, rebootOffset);
//Copy firmlaunch code
memcpy(rebootOffset, reboot, reboot_size);
//Put the fOpen offset in the right location
u32 *pos_fopen = (u32 *)memsearch(rebootOffset, "OPEN", reboot_size, 4);
*pos_fopen = fOpenOffset;
//Patch path for emuNAND-patched FIRM
if(emuNAND)
{
void *pos_path = memsearch(rebootOffset, L"sy", reboot_size, 4);
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;
}
}
//Patches
void patchFirm(void)
{
//Skip patching //Skip patching
if(usePatchedFirm) return; if(usePatchedFirm) return;
if(mode || emuNAND){ if(mode || emuNAND)
{
//Find the Process9 NCCH location //Find the Process9 NCCH location
u8 *proc9Offset = getProc9(arm9Section, section[2].size); u8 *proc9Offset = getProc9(arm9Section, section[2].size);
//Apply emuNAND patches //Apply emuNAND patches
if(emuNAND) loadEmu(proc9Offset); if(emuNAND) patchEmuNAND(proc9Offset);
//Patch FIRM reboots, not on 9.0 FIRM as it breaks firmlaunchhax //Apply FIRM reboot patches, not on 9.0 FIRM as it breaks firmlaunchhax
if(mode){ if(mode) patchReboots(proc9Offset);
//Calculate offset for the firmlaunch code
void *rebootOffset = getReboot(arm9Section, section[2].size);
//Calculate offset for the fOpen function
u32 fOpenOffset = getfOpen(proc9Offset, rebootOffset);
//Copy firmlaunch code
memcpy(rebootOffset, reboot, reboot_size);
//Put the fOpen offset in the right location
u32 *pos_fopen = (u32 *)memsearch(rebootOffset, "OPEN", reboot_size, 4);
*pos_fopen = fOpenOffset;
//Patch path for emuNAND-patched FIRM
if(emuNAND){
void *pos_path = memsearch(rebootOffset, L"sy", reboot_size, 4);
memcpy(pos_path, emuNAND == 1 ? L"emu" : L"em2", 5);
}
}
} }
if(a9lhSetup && !emuNAND){ //Apply FIRM0/1 writes patches on sysNAND to protect A9LH
//Patch FIRM partitions writes 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

View File

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

View File

@ -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;
} }
@ -95,4 +111,4 @@ u32 i2cWriteRegister(u8 dev_id, u8 reg, u8 data) {
} }
return 0; return 0;
} }

View File

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

View File

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

View File

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

View File

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

View File

@ -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)
memcpy((void *)SCREENINIT_ADDRESS, screeninit, screeninit_size); {
if(PDN_GPU_CNT == 1)
{
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);
} }

View File

@ -50,7 +50,4 @@ _start:
mov r1, #0x340 mov r1, #0x340
str r1, [r0] str r1, [r0]
bl main b main
.die:
b .die

View File

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