diff --git a/Makefile b/Makefile index 303566f..1a9fad3 100644 --- a/Makefile +++ b/Makefile @@ -96,6 +96,8 @@ $(dir_build)/main.elf: $(objects_cfw) # FatFs requires libgcc for __aeabi_uidiv $(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 @mkdir -p "$(@D)" $(COMPILE.c) $(OUTPUT_OPTION) $< diff --git a/injector/source/patcher.c b/injector/source/patcher.c index 36f1b4f..5410956 100644 --- a/injector/source/patcher.c +++ b/injector/source/patcher.c @@ -11,7 +11,8 @@ static u32 config = 0; static u8 secureinfo[0x111] = {0}; //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; //Preprocessing @@ -25,7 +26,8 @@ static u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSiz //Searching u32 j = 0; - while(j <= size - patternSize){ + while(j <= size - patternSize) + { if(memcmp(patternc, startPos + j, patternSize) == 0) return startPos + j; j += table[startPos[j + patternSize]]; @@ -34,11 +36,14 @@ static u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSiz 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; - for(i = 0; i < count; i++){ + for(i = 0; i < count; i++) + { u8 *found = memsearch(start, pattern, size, patsize); + if(found == NULL) break; @@ -55,7 +60,8 @@ static u32 patch_memory(u8 *start, u32 size, const void *pattern, u32 patsize, 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_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); } -static int load_secureinfo(){ +static int load_secureinfo() +{ IFile file; Result ret; u64 total; @@ -79,7 +86,8 @@ static int load_secureinfo(){ return 0; 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)); IFile_Close(&file); if(R_SUCCEEDED(ret) && total == sizeof(secureinfo)) @@ -89,7 +97,8 @@ static int load_secureinfo(){ return ret; } -static int load_config(){ +static int load_config() +{ IFile file; Result ret; u64 total; @@ -98,7 +107,8 @@ static int load_config(){ return 0; 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); IFile_Close(&file); } @@ -106,9 +116,10 @@ static int load_config(){ return ret; } -u32 patch_code(u64 progid, u8 *code, u32 size){ - switch(progid){ - +u32 patch_code(u64 progid, u8 *code, u32 size) +{ + switch(progid) + { case 0x0004003000008F02LL: // USA Menu case 0x0004003000008202LL: // EUR Menu case 0x0004003000009802LL: // JPN Menu @@ -129,6 +140,7 @@ u32 patch_code(u64 progid, u8 *code, u32 size){ regionFreePatch, sizeof(regionFreePatch), 1 ); + break; } @@ -160,7 +172,8 @@ u32 patch_code(u64 progid, u8 *code, u32 size){ sizeof(blockEShopUpdateCheckPatch), 1 ); - if(R_SUCCEEDED(load_secureinfo())){ + if(R_SUCCEEDED(load_secureinfo())) + { static const char countryRespPattern[] = { 0x01, 0x20, 0x01, 0x90, 0x22, 0x46, 0x06, 0x9B }; @@ -171,7 +184,8 @@ u32 patch_code(u64 progid, u8 *code, u32 size){ const char *country; char countryRespPatch[sizeof(countryRespPatchModel)]; - switch(secureinfo[0x100]){ + switch(secureinfo[0x100]) + { case 1: country = "US"; break; case 2: country = "GB"; break; // sorry rest-of-Europe, you have to change this case 3: country = "AU"; break; @@ -194,6 +208,7 @@ u32 patch_code(u64 progid, u8 *code, u32 size){ sizeof(countryRespPatch), 1 ); } + break; } @@ -204,7 +219,8 @@ u32 patch_code(u64 progid, u8 *code, u32 size){ case 0x0004001000027000LL: // KOR 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."; const u32 currentFirm = ((config >> 12) & 1); const u32 currentNand = ((config >> 13) & 3); @@ -217,6 +233,7 @@ u32 patch_code(u64 progid, u8 *code, u32 size){ sizeof(verPattern) - sizeof(u16), 1 ); } + break; } @@ -235,6 +252,7 @@ u32 patch_code(u64 progid, u8 *code, u32 size){ stopCartUpdatesPatch, sizeof(stopCartUpdatesPatch), 2 ); + break; } @@ -255,7 +273,8 @@ u32 patch_code(u64 progid, u8 *code, u32 size){ sizeof(secureinfoSigCheckPatch), 1 ); - if(R_SUCCEEDED(load_secureinfo())){ + if(R_SUCCEEDED(load_secureinfo())) + { static const u16 secureinfoFilenamePattern[] = u"SecureInfo_"; static const u16 secureinfoFilenamePatch[] = u"C"; @@ -268,6 +287,7 @@ u32 patch_code(u64 progid, u8 *code, u32 size){ sizeof(secureinfoFilenamePatch) - sizeof(u16), 2 ); } + break; } } diff --git a/loader/Makefile b/loader/Makefile index ba86e0b..f13bf4a 100644 --- a/loader/Makefile +++ b/loader/Makefile @@ -16,7 +16,7 @@ include $(DEVKITARM)/3ds_rules # INCLUDES is a list of directories containing header files # SPECS is the directory containing the important build and link files #--------------------------------------------------------------------------------- -export TARGET := $(shell basename $(CURDIR)) +export TARGET := $(shell basename $(CURDIR)) BUILD := build SOURCES := source source/fatfs source/fatfs/sdmmc diff --git a/loader/source/main.c b/loader/source/main.c index f154920..75f65bd 100644 --- a/loader/source/main.c +++ b/loader/source/main.c @@ -4,9 +4,11 @@ #define PAYLOAD_ADDRESS 0x23F00000 -static u32 loadPayload(const char *path){ +static u32 loadPayload(const char *path) +{ FIL payload; unsigned int br; + if(f_open(&payload, path, FA_READ) == FR_OK) { f_read(&payload, (void *)PAYLOAD_ADDRESS, f_size(&payload), &br); @@ -18,7 +20,8 @@ static u32 loadPayload(const char *path){ return 0; } -void main(void){ +void main(void) +{ FATFS fs; f_mount(&fs, "0:", 1); diff --git a/loader/source/start.s b/loader/source/start.s index 4cd3d0a..eaa8c5c 100644 --- a/loader/source/start.s +++ b/loader/source/start.s @@ -12,7 +12,4 @@ _start: mcr p15, 0, r0, c7, c6, 0 @ flush D-cache mcr p15, 0, r0, c7, c10, 4 @ drain write buffer - bl main - -.die: - b .die + b main diff --git a/screeninit/Makefile b/screeninit/Makefile index cb66828..7fa9bf2 100755 --- a/screeninit/Makefile +++ b/screeninit/Makefile @@ -16,7 +16,7 @@ include $(DEVKITARM)/3ds_rules # INCLUDES is a list of directories containing header files # SPECS is the directory containing the important build and link files #--------------------------------------------------------------------------------- -export TARGET := $(shell basename $(CURDIR)) +export TARGET := $(shell basename $(CURDIR)) BUILD := build SOURCES := source diff --git a/screeninit/source/main.c b/screeninit/source/main.c index 552373a..01bce2c 100755 --- a/screeninit/source/main.c +++ b/screeninit/source/main.c @@ -1,6 +1,7 @@ #include "types.h" -void main(void){ +void main(void) +{ vu32 *const arm11 = (u32 *)0x1FFFFFF8; *(vu32 *)0x10141200 = 0x1007F; @@ -96,6 +97,7 @@ void main(void){ //Wait for the entry to be set while(!*arm11); + //Jump to it ((void (*)())*arm11)(); } \ No newline at end of file diff --git a/screeninit/source/start.s b/screeninit/source/start.s index c76ce79..a02aa4c 100644 --- a/screeninit/source/start.s +++ b/screeninit/source/start.s @@ -5,7 +5,4 @@ _start: @ Disable interrupts CPSID aif - bl main - -.die: - b .die + b main diff --git a/source/crypto.c b/source/crypto.c index 8763c98..39e6120 100755 --- a/source/crypto.c +++ b/source/crypto.c @@ -239,14 +239,16 @@ static const u8 key2[0x10] = { }; //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; for(u8 keyLen = 0x10; keyLen; keyLen--) *(buf++) = *(addr--); } //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]; getNandCTR(CTR, console); @@ -258,8 +260,8 @@ void nandFirm0(u8 *outbuf, u32 size, u32 console){ } //Decrypts the N3DS arm9bin -void decryptArm9Bin(u8 *arm9Section, u32 mode){ - +void decryptArm9Bin(u8 *arm9Section, u32 mode) +{ //Firm keys u8 keyY[0x10]; u8 CTR[0x10]; @@ -268,12 +270,15 @@ void decryptArm9Bin(u8 *arm9Section, u32 mode){ //Setup keys needed for arm9bin decryption memcpy(keyY, arm9Section + 0x10, 0x10); memcpy(CTR, arm9Section + 0x20, 0x10); + + //Calculate the size of the ARM9 binary u32 size = 0; //http://stackoverflow.com/questions/12791077/atoi-implementation-in-c for(u8 *tmp = arm9Section + 0x30; *tmp; tmp++) size = (size << 3) + (size << 1) + (*tmp) - '0'; - if(mode){ + if(mode) + { u8 keyX[0x10]; //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 -void setKeyXs(u8 *arm9Section){ - +void setKeyXs(u8 *arm9Section) +{ u8 *keyData = arm9Section + 0x89814; u8 *decKey = keyData + 0x10; //Set keys 0x19..0x1F keyXs aes_setkey(0x11, key2, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL); 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_setkey(slot, decKey, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL); *(keyData + 0xF) += 1; diff --git a/source/draw.c b/source/draw.c index db5ff14..cee5928 100644 --- a/source/draw.c +++ b/source/draw.c @@ -20,38 +20,47 @@ static const struct fb { u8 *bottom; } *const fb = (struct fb *)0x23FFFE00; -static inline int strlen(const char *string){ +static inline int strlen(const char *string) +{ char *stringEnd = (char *)string; while(*stringEnd) stringEnd++; return stringEnd - string; } -void clearScreens(void){ +void clearScreens(void) +{ memset32(fb->top_left, 0, 0x46500); memset32(fb->top_right, 0, 0x46500); memset32(fb->bottom, 0, 0x38400); } -void loadSplash(void){ +void loadSplash(void) +{ clearScreens(); //Don't delay boot if no splash image is on the SD if(fileRead(fb->top_left, "/aurei/splash.bin", 0x46500) + - fileRead(fb->bottom, "/aurei/splashbottom.bin", 0x38400)){ - u64 i = 0x1300000; while(--i) __asm("mov r0, r0"); //Less Ghetto sleep func + fileRead(fb->bottom, "/aurei/splashbottom.bin", 0x38400)) + { + 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; - for(int y = 0; y < 8; y++){ + for(int y = 0; y < 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; - if ((charPos >> x) & 1) { + if ((charPos >> x) & 1) + { select[screenPos] = color >> 16; select[screenPos + 1] = color >> 8; 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); - for(int i = 0, line_i = 0; i < length; i++, line_i++){ - if(string[i] == '\n'){ + for(int i = 0, line_i = 0; i < length; i++, line_i++) + { + if(string[i] == '\n') + { posY += SPACING_Y; line_i = 0; 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. posY += SPACING_Y; line_i = 2; // Little offset so we know the same string continues. diff --git a/source/emunand.c b/source/emunand.c index 51c1575..93138f2 100644 --- a/source/emunand.c +++ b/source/emunand.c @@ -8,7 +8,8 @@ #include "memory.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; const u32 nandSize = getMMCDevice(0)->total_size; @@ -16,19 +17,24 @@ void getEmunandSect(u32 *off, u32 *head, u32 *emuNAND){ (nandSize > 0x200000 ? 0x400000 : 0x200000); //Check for RedNAND - if(sdmmc_sdcard_readsectors(nandOffset + 1, 1, temp) == 0){ - if(*(u32 *)(temp + 0x100) == NCSD_MAGIC){ + if(sdmmc_sdcard_readsectors(nandOffset + 1, 1, temp) == 0) + { + if(*(u32 *)(temp + 0x100) == NCSD_MAGIC) + { *off = nandOffset + 1; *head = nandOffset + 1; } //Check for Gateway emuNAND - else if(sdmmc_sdcard_readsectors(nandOffset + nandSize, 1, temp) == 0){ - if(*(u32 *)(temp + 0x100) == NCSD_MAGIC){ + else if(sdmmc_sdcard_readsectors(nandOffset + nandSize, 1, temp) == 0) + { + if(*(u32 *)(temp + 0x100) == NCSD_MAGIC) + { *off = nandOffset; *head = nandOffset + nandSize; } //Fallback to the first emuNAND if there's no second one - else if(*emuNAND == 2){ + else if(*emuNAND == 2) + { *emuNAND = 1; 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 const u8 pattern[] = {0x21, 0x20, 0x18, 0x20}; 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); } -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 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; } -u32 *getMPU(u8 *pos, u32 size){ +u32 *getMPU(u8 *pos, u32 size) +{ //Look for MPU pattern const u8 pattern[] = {0x03, 0x00, 0x24, 0x00}; return (u32 *)memsearch(pos, pattern, size, 4); } -void *getEmuCode(u8 *proc9Offset){ +void *getEmuCode(u8 *proc9Offset) +{ const u8 pattern[] = {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}; //Looking for the last free space before Process9 diff --git a/source/firm.c b/source/firm.c index dc4cf1c..5a34c72 100755 --- a/source/firm.c +++ b/source/firm.c @@ -38,14 +38,17 @@ static u32 firmSize, emuOffset, emuHeader; -void setupCFW(void){ - +void setupCFW(void) +{ //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 u8 previousFirm = CFG_BOOTENV; + //Detect the console being used console = (PDN_MPCORE_CFG == 1) ? 0 : 1; + //Get pressed buttons u16 pressed = HID_PAD; @@ -57,14 +60,18 @@ void setupCFW(void){ //Determine if A9LH is installed and the user has an updated sysNAND u32 updatedSys; - if(a9lhBoot || (config >> 2) & 1){ + if(a9lhBoot || (config >> 2) & 1) + { if(pressed == SAFE_MODE) error("Using Safe Mode would brick you, or remove A9LH!"); a9lhSetup = 1; + //Check setting for > 9.2 sysNAND updatedSys = config & 1; - } else{ + } + else + { a9lhSetup = 0; updatedSys = 0; } @@ -73,29 +80,35 @@ void setupCFW(void){ /* If booting with A9LH, it's a MCU reboot and a previous configuration exists, try to force boot options */ - if(a9lhBoot && previousFirm && needConfig == 1){ + if(a9lhBoot && previousFirm && needConfig == 1) + { //Always force a sysNAND boot when quitting AGB_FIRM - if(previousFirm == 7){ + if(previousFirm == 7) + { mode = updatedSys ? 1 : (config >> 12) & 1; emuNAND = 0; + needConfig = 0; + //Flag to prevent multiple boot options-forcing 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 */ - } else if(!(pressed & OPTION_BUTTONS) && !((config >> 15) & 1)){ + else if(!(pressed & OPTION_BUTTONS) && !((config >> 15) & 1)) + { mode = (config >> 12) & 1; emuNAND = (config >> 13) & 3; 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 the Safe Mode combo is not pressed, chainload an external payload */ - if((pressed & BUTTON_L1) && (pressed & PAYLOAD_BUTTONS) && - pressed != SAFE_MODE) loadPayload(); + if((pressed & BUTTON_L1) && (pressed & PAYLOAD_BUTTONS) && pressed != SAFE_MODE) + loadPayload(); //If no configuration file exists or SELECT is held, load configuration menu if(needConfig == 2 || (pressed & BUTTON_SELECT)) @@ -104,14 +117,15 @@ void setupCFW(void){ //If screens are inited, load splash screen 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) : ((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 or R is pressed on a > 9.2 sysNAND, boot emuNAND */ - if((updatedSys && (!mode || (pressed & BUTTON_R1))) || - (!updatedSys && mode && !(pressed & BUTTON_R1))){ + if((updatedSys && (!mode || (pressed & BUTTON_R1))) || (!updatedSys && mode && !(pressed & BUTTON_R1))) + { //If not 9.0 FIRM and B is pressed, attempt booting the second emuNAND emuNAND = (mode && ((!(pressed & BUTTON_B)) == ((config >> 4) & 1))) ? 2 : 1; } else emuNAND = 0; @@ -124,7 +138,8 @@ void setupCFW(void){ u32 usePatchedFirmSet = ((config >> 1) & 1); - while(1){ + while(1) + { /* 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 */ 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(usePatchedFirmSet && fileExists(patchedFirms[selectedFirm - 1])) usePatchedFirm = 1; - //Detect EmuNAND - else if(emuNAND){ + + else if(emuNAND) + { + //Detect EmuNAND getEmunandSect(&emuOffset, &emuHeader, &emuNAND); + //If none exists, force SysNAND + 9.6/10.x FIRM and re-detect patched FIRMs - if(!emuNAND){ + if(!emuNAND) + { mode = 1; continue; } @@ -148,29 +167,34 @@ void setupCFW(void){ tempConfig |= (emuNAND << 13) | (mode << 12); //If the boot configuration is different from previously, overwrite it - if(tempConfig != (config & 0xFFF000)){ + if(tempConfig != (config & 0xFFF000)) + { //Preserve user settings (first 12 bits) tempConfig |= config & 0xFFF; + fileWrite(&tempConfig, configPath, 3); } } //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(!usePatchedFirm && !a9lhSetup && !mode){ + if(!usePatchedFirm && !a9lhSetup && !mode) + { //Read FIRM from NAND and write to FCRAM firmSize = console ? 0xF2000 : 0xE9000; nandFirm0((u8 *)firm, firmSize, console); + //Check for correct decryption if(memcmp(firm, "FIRM", 4) != 0) error("Couldn't decrypt NAND FIRM0 (O3DS not on 9.x?)"); } //Load FIRM from SD - else{ + else + { const char *path = usePatchedFirm ? patchedFirms[selectedFirm - 1] : - (mode ? "/aurei/firmware.bin" : "/aurei/firmware90.bin"); + (mode ? "/aurei/firmware.bin" : "/aurei/firmware90.bin"); firmSize = fileSize(path); if(!firmSize) error("aurei/firmware(90).bin doesn't exist"); fileRead(firm, path, firmSize); @@ -188,8 +212,8 @@ void loadFirm(void){ } //NAND redirection -static inline void loadEmu(u8 *proc9Offset){ - +static inline void patchEmuNAND(u8 *proc9Offset) +{ //Copy emuNAND code void *emuCodeOffset = getEmuCode(proc9Offset); memcpy(emuCodeOffset, emunand, emunand_size); @@ -227,49 +251,75 @@ static inline void loadEmu(u8 *proc9Offset){ *(mpuOffset + 9) = mpuPatch[2]; } -//Patches -void patchFirm(void){ +static inline void patchReboots(u8 *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); + } +} + +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 if(usePatchedFirm) return; - if(mode || emuNAND){ + if(mode || emuNAND) + { //Find the Process9 NCCH location u8 *proc9Offset = getProc9(arm9Section, section[2].size); //Apply emuNAND patches - if(emuNAND) loadEmu(proc9Offset); + if(emuNAND) patchEmuNAND(proc9Offset); - //Patch FIRM reboots, not on 9.0 FIRM as it breaks firmlaunchhax - if(mode){ - //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); - } - } + //Apply FIRM reboot patches, not on 9.0 FIRM as it breaks firmlaunchhax + if(mode) patchReboots(proc9Offset); } - if(a9lhSetup && !emuNAND){ - //Patch FIRM partitions writes on sysNAND to protect A9LH + //Apply FIRM0/1 writes patches on sysNAND to protect A9LH + if(a9lhSetup && !emuNAND) + { u16 *writeOffset = getFirmWrite(arm9Section, section[2].size); *writeOffset = writeBlock[0]; *(writeOffset + 1) = writeBlock[1]; } - //Disable signature checks + //Apply signature checks patches u32 sigOffset, sigOffset2; @@ -279,18 +329,7 @@ void patchFirm(void){ *((u16 *)sigOffset2 + 1) = sigPatch[1]; //Replace the FIRM loader with the injector - 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; - } + injectLoader(); //Patch ARM9 entrypoint on N3DS to skip arm9loader if(console) @@ -302,8 +341,8 @@ void patchFirm(void){ error("Couldn't write the patched FIRM (no free space?)"); } -void launchFirm(void){ - +void launchFirm(void) +{ if(console && mode) setKeyXs(arm9Section); //Copy firm partitions to respective memory locations diff --git a/source/fs.c b/source/fs.c index d5fb4a8..15c095f 100644 --- a/source/fs.c +++ b/source/fs.c @@ -9,18 +9,21 @@ static FATFS fs; -u32 mountSD(void){ +u32 mountSD(void) +{ if(f_mount(&fs, "0:", 1) != FR_OK) return 0; return 1; } -u32 fileRead(void *dest, const char *path, u32 size){ +u32 fileRead(void *dest, const char *path, u32 size) +{ FRESULT fr; FIL fp; unsigned int br = 0; fr = f_open(&fp, path, FA_READ); - if(fr == FR_OK){ + if(fr == FR_OK) + { if(!size) size = f_size(&fp); fr = f_read(&fp, dest, size, &br); } @@ -29,7 +32,8 @@ u32 fileRead(void *dest, const char *path, u32 size){ 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; FIL fp; unsigned int br = 0; @@ -41,7 +45,8 @@ u32 fileWrite(const void *buffer, const char *path, u32 size){ return fr ? 0 : 1; } -u32 fileSize(const char *path){ +u32 fileSize(const char *path) +{ FIL fp; u32 size = 0; @@ -52,7 +57,8 @@ u32 fileSize(const char *path){ return size; } -u32 fileExists(const char *path){ +u32 fileExists(const char *path) +{ FIL fp; u32 exists = 0; @@ -62,6 +68,7 @@ u32 fileExists(const char *path){ return exists; } -void fileDelete(const char *path){ +void fileDelete(const char *path) +{ f_unlink(path); } \ No newline at end of file diff --git a/source/i2c.c b/source/i2c.c index 6f03579..cdbb9a8 100644 --- a/source/i2c.c +++ b/source/i2c.c @@ -10,11 +10,13 @@ static const struct { u8 bus_id, reg_addr; } dev_data[] = { {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; } -static inline u8 i2cGetDeviceRegAddr(u8 device_id) { +static inline u8 i2cGetDeviceRegAddr(u8 device_id) +{ return dev_data[device_id].reg_addr; } @@ -26,7 +28,8 @@ static vu8* reg_data_addrs[] = { (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]; } @@ -38,22 +41,27 @@ static vu8* reg_cnt_addrs[] = { (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]; } //----------------------------------------------------------------------------- -static inline void i2cWaitBusy(u8 bus_id) { +static inline void i2cWaitBusy(u8 bus_id) +{ while (*i2cGetCntReg(bus_id) & 0x80); } -static inline u32 i2cGetResult(u8 bus_id) { +static inline u32 i2cGetResult(u8 bus_id) +{ i2cWaitBusy(bus_id); + 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; i2cWaitBusy(bus_id); *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); *i2cGetDataReg(bus_id) = dev_reg; *i2cGetCntReg(bus_id) = 0xC2; + return i2cGetResult(bus_id); } -static u32 i2cSelectRegister(u8 bus_id, u8 reg) { +static u32 i2cSelectRegister(u8 bus_id, u8 reg) +{ i2cWaitBusy(bus_id); *i2cGetDataReg(bus_id) = reg; *i2cGetCntReg(bus_id) = 0xC0; + 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 dev_addr = i2cGetDeviceRegAddr(dev_id); - for (int i = 0; i < 8; i++) { - if (i2cSelectDevice(bus_id, dev_addr) && i2cSelectRegister(bus_id, reg)) { + for (u32 i = 0; i < 8; i++) + { + if (i2cSelectDevice(bus_id, dev_addr) && i2cSelectRegister(bus_id, reg)) + { i2cWaitBusy(bus_id); *i2cGetDataReg(bus_id) = data; *i2cGetCntReg(bus_id) = 0xC1; i2cStop(bus_id, 0); + if (i2cGetResult(bus_id)) return 1; } @@ -95,4 +111,4 @@ u32 i2cWriteRegister(u8 dev_id, u8 reg, u8 data) { } return 0; -} +} \ No newline at end of file diff --git a/source/loader.c b/source/loader.c index 845e1f9..db33c8c 100644 --- a/source/loader.c +++ b/source/loader.c @@ -12,8 +12,10 @@ #define PAYLOAD_ADDRESS 0x24F00000 -void loadPayload(void){ - if(fileExists("aurei/payloads/default.bin")){ +void loadPayload(void) +{ + if(fileExists("aurei/payloads/default.bin")) + { initScreens(); memcpy((void *)PAYLOAD_ADDRESS, loader, loader_size); ((void (*)())PAYLOAD_ADDRESS)(); diff --git a/source/main.c b/source/main.c index 9d785ea..0ea5977 100644 --- a/source/main.c +++ b/source/main.c @@ -9,7 +9,8 @@ #include "fs.h" #include "firm.h" -void main(void){ +void main(void) +{ mountSD(); setupCFW(); loadFirm(); diff --git a/source/memory.c b/source/memory.c index 05d4cdc..b409d2d 100644 --- a/source/memory.c +++ b/source/memory.c @@ -8,36 +8,43 @@ #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; const u8 *srcc = (const u8 *)src; for(u32 i = 0; i < size; 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; for(u32 i = 0; i < size; i++) destc[i] = (u8)filler; } -void memset32(void *dest, u32 filler, u32 size){ +void memset32(void *dest, u32 filler, u32 size) +{ u32 *dest32 = (u32 *)dest; for (u32 i = 0; i < size / 4; i++) 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 *buf2c = (const u8 *)buf2; - for(u32 i = 0; i < size; i++){ + for(u32 i = 0; i < size; i++) + { int cmp = buf1c[i] - buf2c[i]; if(cmp) return cmp; } + 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; //Preprocessing @@ -51,7 +58,8 @@ u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize){ //Searching u32 j = 0; - while(j <= size - patternSize){ + while(j <= size - patternSize) + { if(memcmp(patternc, startPos + j, patternSize) == 0) return startPos + j; j += table[startPos[j + patternSize]]; diff --git a/source/patches.c b/source/patches.c index aef053b..b072cd4 100644 --- a/source/patches.c +++ b/source/patches.c @@ -23,11 +23,13 @@ const u16 writeBlock[2] = {0x2000, 0x46C0}; * Functions **************************************************/ -u8 *getProc9(u8 *pos, u32 size){ +u8 *getProc9(u8 *pos, u32 size) +{ 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 const u8 pattern[] = {0xC0, 0x1C, 0x76, 0xE7}, 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; } -void *getReboot(u8 *pos, u32 size){ +void *getReboot(u8 *pos, u32 size) +{ //Look for FIRM reboot code const u8 pattern[] = {0xDE, 0x1F, 0x8D, 0xE2}; 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) u32 p9MemAddr = *(u32 *)(proc9Offset + 0xC); + //Process9 code offset (start of NCCH + ExeFS offset + ExeFS header size) 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; } -u16 *getFirmWrite(u8 *pos, u32 size){ +u16 *getFirmWrite(u8 *pos, u32 size) +{ //Look for FIRM writing code u8 *const off = memsearch(pos, "exe:", size, 4); 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); } -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); *loaderOffset = (u32)off - 0x200; diff --git a/source/screeninit.c b/source/screeninit.c index 400fe73..81143f2 100644 --- a/source/screeninit.c +++ b/source/screeninit.c @@ -17,8 +17,10 @@ static vu32 *const arm11 = (u32 *)0x1FFFFFF8; -void deinitScreens(void){ - void __attribute__((naked)) ARM11(void){ +void deinitScreens(void) +{ + void __attribute__((naked)) ARM11(void) + { //Disable interrupts __asm(".word 0xF10C01C0"); @@ -32,22 +34,28 @@ void deinitScreens(void){ //Wait for the entry to be set while(!*arm11); + //Jump to it ((void (*)())*arm11)(); } - if(PDN_GPU_CNT != 1){ + if(PDN_GPU_CNT != 1) + { *arm11 = (u32)ARM11; while(*arm11); } } -void initScreens(void){ - memcpy((void *)SCREENINIT_ADDRESS, screeninit, screeninit_size); +void initScreens(void) +{ + if(PDN_GPU_CNT == 1) + { + memcpy((void *)SCREENINIT_ADDRESS, screeninit, screeninit_size); - if(PDN_GPU_CNT == 1){ *arm11 = SCREENINIT_ADDRESS; while(*arm11); + + //Turn on backlight i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x2A); } diff --git a/source/start.s b/source/start.s index 729f02c..2061b5f 100644 --- a/source/start.s +++ b/source/start.s @@ -50,7 +50,4 @@ _start: mov r1, #0x340 str r1, [r0] - bl main - -.die: - b .die + b main diff --git a/source/utils.c b/source/utils.c index fccf783..b3eafd3 100644 --- a/source/utils.c +++ b/source/utils.c @@ -21,7 +21,8 @@ struct option { u32 enabled; }; -static u16 waitInput(void){ +static u16 waitInput(void) +{ u32 pressedKey = 0; u16 key; @@ -34,7 +35,8 @@ static u16 waitInput(void){ key = HID_PAD; //Make sure it's pressed - for(u32 i = 0x13000; i; i--){ + for(u32 i = 0x13000; i; i--) + { if(key != HID_PAD) break; if(i == 1) pressedKey = 1; } @@ -43,7 +45,8 @@ static u16 waitInput(void){ return key; } -void configureCFW(const char *configPath, const char *firm90Path){ +void configureCFW(const char *configPath, const char *firm90Path) +{ initScreens(); 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 u32 tempConfig = 0; fileRead(&tempConfig, configPath, 3); + for(u32 i = 0; i < optionsAmount; i++) options[i].enabled = (tempConfig >> i) & 1; @@ -69,18 +73,22 @@ void configureCFW(const char *configPath, const char *firm90Path){ u32 selectedOption = 0; //Boring configuration menu - while(1){ + while(1) + { u16 pressed = 0; - do{ - for(u32 i = 0; i < optionsAmount; i++){ + do { + 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); drawCharacter('x', 10 + SPACING_X, options[i].posY, options[i].enabled ? (selectedOption == i ? COLOR_RED : COLOR_WHITE) : COLOR_BLACK); } + pressed = waitInput(); } while(!(pressed & MENU_BUTTONS)); - switch(pressed){ + switch(pressed) + { case BUTTON_UP: selectedOption = !selectedOption ? optionsAmount - 1 : selectedOption - 1; break; @@ -110,6 +118,7 @@ void configureCFW(const char *configPath, const char *firm90Path){ //Parse and write the selected options for(u32 i = 0; i < optionsAmount; i++) tempConfig |= options[i].enabled << i; + fileWrite(&tempConfig, configPath, 3); //Zero the last booted FIRM flag @@ -120,14 +129,17 @@ void configureCFW(const char *configPath, const char *firm90Path){ while(1); } -void deleteFirms(const char *firmPaths[], u32 firms){ - while(firms){ +void deleteFirms(const char *firmPaths[], u32 firms) +{ + while(firms) + { fileDelete(firmPaths[firms - 1]); firms--; } } -void error(const char *message){ +void error(const char *message) +{ initScreens(); drawString("An error has occurred:", 10, 10, COLOR_RED);