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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -9,7 +9,8 @@
#include "fs.h"
#include "firm.h"
void main(void){
void main(void)
{
mountSD();
setupCFW();
loadFirm();

View File

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

View File

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

View File

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

View File

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

View File

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