Changed indentation style across the code to make it more readable, added newlines before comments, moved patches to separate functions, made memory operations slightly faster by compiling them with O3 (thanks TuxSH!)
This commit is contained in:
parent
6b64a10362
commit
3475cfe1e6
2
Makefile
2
Makefile
@ -96,6 +96,8 @@ $(dir_build)/main.elf: $(objects_cfw)
|
||||
# FatFs requires libgcc for __aeabi_uidiv
|
||||
$(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) $<
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)();
|
||||
}
|
@ -5,7 +5,4 @@ _start:
|
||||
@ Disable interrupts
|
||||
CPSID aif
|
||||
|
||||
bl main
|
||||
|
||||
.die:
|
||||
b .die
|
||||
b main
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
159
source/firm.c
159
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;
|
||||
|
||||
else if(emuNAND)
|
||||
{
|
||||
//Detect EmuNAND
|
||||
else if(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,27 +167,32 @@ 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");
|
||||
firmSize = fileSize(path);
|
||||
@ -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,23 +251,11 @@ static inline void loadEmu(u8 *proc9Offset){
|
||||
*(mpuOffset + 9) = mpuPatch[2];
|
||||
}
|
||||
|
||||
//Patches
|
||||
void patchFirm(void){
|
||||
|
||||
//Skip patching
|
||||
if(usePatchedFirm) return;
|
||||
|
||||
if(mode || emuNAND){
|
||||
//Find the Process9 NCCH location
|
||||
u8 *proc9Offset = getProc9(arm9Section, section[2].size);
|
||||
|
||||
//Apply emuNAND patches
|
||||
if(emuNAND) loadEmu(proc9Offset);
|
||||
|
||||
//Patch FIRM reboots, not on 9.0 FIRM as it breaks firmlaunchhax
|
||||
if(mode){
|
||||
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);
|
||||
|
||||
@ -255,21 +267,59 @@ void patchFirm(void){
|
||||
*pos_fopen = fOpenOffset;
|
||||
|
||||
//Patch path for emuNAND-patched FIRM
|
||||
if(emuNAND){
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if(a9lhSetup && !emuNAND){
|
||||
//Patch FIRM partitions writes on sysNAND to protect A9LH
|
||||
//Patches
|
||||
void patchFirm(void)
|
||||
{
|
||||
//Skip patching
|
||||
if(usePatchedFirm) return;
|
||||
|
||||
if(mode || emuNAND)
|
||||
{
|
||||
//Find the Process9 NCCH location
|
||||
u8 *proc9Offset = getProc9(arm9Section, section[2].size);
|
||||
|
||||
//Apply emuNAND patches
|
||||
if(emuNAND) patchEmuNAND(proc9Offset);
|
||||
|
||||
//Apply FIRM reboot patches, not on 9.0 FIRM as it breaks firmlaunchhax
|
||||
if(mode) patchReboots(proc9Offset);
|
||||
}
|
||||
|
||||
//Apply FIRM0/1 writes patches on sysNAND to protect A9LH
|
||||
if(a9lhSetup && !emuNAND)
|
||||
{
|
||||
u16 *writeOffset = getFirmWrite(arm9Section, section[2].size);
|
||||
*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
|
||||
|
21
source/fs.c
21
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);
|
||||
}
|
40
source/i2c.c
40
source/i2c.c
@ -10,11 +10,13 @@ static const struct { u8 bus_id, reg_addr; } dev_data[] = {
|
||||
{2, 0xA4}, {2, 0x9A}, {2, 0xA0},
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -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)();
|
||||
|
@ -9,7 +9,8 @@
|
||||
#include "fs.h"
|
||||
#include "firm.h"
|
||||
|
||||
void main(void){
|
||||
void main(void)
|
||||
{
|
||||
mountSD();
|
||||
setupCFW();
|
||||
loadFirm();
|
||||
|
@ -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]];
|
||||
|
@ -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;
|
||||
|
@ -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){
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -50,7 +50,4 @@ _start:
|
||||
mov r1, #0x340
|
||||
str r1, [r0]
|
||||
|
||||
bl main
|
||||
|
||||
.die:
|
||||
b .die
|
||||
b main
|
||||
|
@ -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++){
|
||||
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);
|
||||
|
Reference in New Issue
Block a user