Compare commits

..

23 Commits
v4.0 ... v4.2

Author SHA1 Message Date
Aurora
3aacbd17ce Upped patch version 2016-04-05 02:29:36 +02:00
Aurora
6f8a9421ef Added basic support for configuring the brightness level for the built-in screen init 2016-04-05 02:24:21 +02:00
Aurora
bb437f6f7b Better commenting 2016-04-04 19:14:49 +02:00
Aurora
0001f301f8 Cleanup, fixed the second emuNAND patched FIRM still getting created, removed injector SOAP patch as it changes nothing without going to great lengths to change the region of a NNID, made L not needed to load payloads except for R and Select (Start is now default) 2016-04-04 18:07:13 +02:00
Aurora
f7bbc4bfec Made the AGB_FIRM splash screen optional
Apparently it causes compatibility issues
2016-04-04 01:08:42 +02:00
Aurora
a127a38438 Updated ReadME 2016-04-03 19:53:03 +02:00
Aurora
16225b97d7 Small changes 2016-04-03 18:18:44 +02:00
Aurora
0587c14162 Forgot stuff 2016-04-03 18:10:48 +02:00
Aurora
a181bba9f2 Added TWL/AGB FIRM patching/SD loading for New and Old 3DS (thanks to mid-kid of CakesFW for making it possible!) 2016-04-03 17:56:09 +02:00
Aurora
993e564fbb u32-ify 2016-04-02 22:02:16 +02:00
Aurora
956829864c This looks unused (my AUS N3DS has 2) 2016-04-02 18:57:52 +02:00
Aurora
24186a7148 Some more tidying up 2016-04-02 18:48:31 +02:00
Aurora
3475cfe1e6 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!) 2016-04-02 18:22:47 +02:00
Aurora
6b64a10362 Fixed ARM11 access to chainloaded payloads 2016-04-01 14:27:31 +02:00
Aurora
5e99fb3aa0 Fixed dumb mistakes 2016-03-31 18:25:50 +02:00
Aurora
060d8e9945 Comment things better 2016-03-31 16:04:12 +02:00
Aurora
1026471842 Leftover from testing 2016-03-31 15:59:40 +02:00
Aurora
645208ec82 EmuNAND is detected almost instantly when the CFW configures itself, if the user is attempting to load an EmuNAND and none is found, SysNAND and 9.6/10.x FIRM are forced. Also prevents the second EmuNAND patched FIRM from being created if no second EmuNAND exists. 2016-03-31 15:57:02 +02:00
Aurora
f4c48a64ca Fixed loading the alternate EmuNAND if 9.0 FIRM was set as default, improved comments and further cleanup of the injector 2016-03-31 01:38:28 +02:00
Aurora
c80ac985fe Further clean-up of the patcher code 2016-03-29 22:43:15 +02:00
Aurora
ac9bdc7665 Fixed exiting GBA games with updated SysNAND 2016-03-29 18:56:51 +02:00
Aurora
217d75024d These should be u32s 2016-03-29 18:47:30 +02:00
Aurora
12e5b4adb9 Updated readME 2016-03-29 18:17:22 +02:00
34 changed files with 1203 additions and 765 deletions

View File

@@ -11,6 +11,7 @@ version := $(shell git describe --abbrev=0 --tags)
dir_source := source dir_source := source
dir_patches := patches dir_patches := patches
dir_loader := loader dir_loader := loader
dir_screeninit := screeninit
dir_injector := injector dir_injector := injector
dir_mset := CakeHax dir_mset := CakeHax
dir_ninjhax := CakeBrah dir_ninjhax := CakeBrah
@@ -19,7 +20,6 @@ dir_out := out
ASFLAGS := -mlittle-endian -mcpu=arm946e-s -march=armv5te ASFLAGS := -mlittle-endian -mcpu=arm946e-s -march=armv5te
CFLAGS := -Wall -Wextra -MMD -MP -marm $(ASFLAGS) -fno-builtin -fshort-wchar -std=c11 -Wno-main -O2 -ffast-math CFLAGS := -Wall -Wextra -MMD -MP -marm $(ASFLAGS) -fno-builtin -fshort-wchar -std=c11 -Wno-main -O2 -ffast-math
CFLAGS += -DCONFIG_TITLE="\"$(name) $(version) configuration\""
FLAGS := name=$(name).dat dir_out=$(abspath $(dir_out)) ICON=$(abspath icon.png) APP_DESCRIPTION="Noob-friendly 3DS CFW." APP_AUTHOR="Reisyukaku/Aurora Wright" --no-print-directory FLAGS := name=$(name).dat dir_out=$(abspath $(dir_out)) ICON=$(abspath icon.png) APP_DESCRIPTION="Noob-friendly 3DS CFW." APP_AUTHOR="Reisyukaku/Aurora Wright" --no-print-directory
objects_cfw = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \ objects_cfw = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
@@ -48,6 +48,7 @@ clean:
@$(MAKE) $(FLAGS) -C $(dir_ninjhax) clean @$(MAKE) $(FLAGS) -C $(dir_ninjhax) clean
@rm -rf $(dir_out) $(dir_build) @rm -rf $(dir_out) $(dir_build)
@$(MAKE) -C $(dir_loader) clean @$(MAKE) -C $(dir_loader) clean
@$(MAKE) -C $(dir_screeninit) clean
@$(MAKE) -C $(dir_injector) clean @$(MAKE) -C $(dir_injector) clean
$(dir_out): $(dir_out):
@@ -58,7 +59,7 @@ $(dir_out)/$(name).dat: $(dir_build)/main.bin $(dir_out)
@dd if=$(dir_build)/main.bin of=$@ bs=512 seek=144 @dd if=$(dir_build)/main.bin of=$@ bs=512 seek=144
$(dir_out)/arm9loaderhax.bin: $(dir_build)/main.bin $(dir_out) $(dir_out)/arm9loaderhax.bin: $(dir_build)/main.bin $(dir_out)
@cp -av $(dir_build)/main.bin $@ @cp -a $(dir_build)/main.bin $@
$(dir_out)/3ds/$(name): $(dir_out) $(dir_out)/3ds/$(name): $(dir_out)
@mkdir -p "$(dir_out)/3ds/$(name)" @mkdir -p "$(dir_out)/3ds/$(name)"
@@ -82,6 +83,11 @@ $(dir_build)/loader.h: $(dir_loader)/Makefile
@mv $(dir_loader)/loader.bin $(dir_build) @mv $(dir_loader)/loader.bin $(dir_build)
@bin2c -o $@ -n loader $(dir_build)/loader.bin @bin2c -o $@ -n loader $(dir_build)/loader.bin
$(dir_build)/screeninit.h: $(dir_screeninit)/Makefile
@$(MAKE) -C $(dir_screeninit)
@mv $(dir_screeninit)/screeninit.bin $(dir_build)
@bin2c -o $@ -n screeninit $(dir_build)/screeninit.bin
$(dir_build)/main.bin: $(dir_build)/main.elf $(dir_build)/main.bin: $(dir_build)/main.elf
$(OC) -S -O binary $< $@ $(OC) -S -O binary $< $@
@@ -89,7 +95,10 @@ $(dir_build)/main.elf: $(objects_cfw)
# FatFs requires libgcc for __aeabi_uidiv # FatFs requires libgcc for __aeabi_uidiv
$(CC) -nostartfiles $(LDFLAGS) -T linker.ld $(OUTPUT_OPTION) $^ $(CC) -nostartfiles $(LDFLAGS) -T linker.ld $(OUTPUT_OPTION) $^
$(dir_build)/%.o: $(dir_source)/%.c $(dir_build)/patches.h $(dir_build)/loader.h $(dir_build)/memory.o : CFLAGS+=-O3
$(dir_build)/utils.o : CFLAGS += -DCONFIG_TITLE="\"$(name) $(version) configuration\""
$(dir_build)/%.o: $(dir_source)/%.c $(dir_build)/patches.h $(dir_build)/loader.h $(dir_build)/screeninit.h
@mkdir -p "$(@D)" @mkdir -p "$(@D)"
$(COMPILE.c) $(OUTPUT_OPTION) $< $(COMPILE.c) $(OUTPUT_OPTION) $<

View File

@@ -5,6 +5,8 @@
You'll need armips and [bin2c](https://sourceforge.net/projects/bin2c/) added to your Path. [HERE](http://www91.zippyshare.com/v/ePGpjk9r/file.html) is a pre-compiled version of armips. You'll need armips and [bin2c](https://sourceforge.net/projects/bin2c/) added to your Path. [HERE](http://www91.zippyshare.com/v/ePGpjk9r/file.html) is a pre-compiled version of armips.
You also need to have a recent build of makerom in your path for the injector to be built.
Lastly, just run Make and everything should work! Lastly, just run Make and everything should work!
Copy everything in 'out' folder to SD root and run! Copy everything in 'out' folder to SD root and run!
@@ -13,7 +15,7 @@ Copy everything in 'out' folder to SD root and run!
See https://github.com/Reisyukaku/ReiNand and http://gbatemp.net/threads/reinand-mod-o3ds-n3ds-sysnand.411110 See https://github.com/Reisyukaku/ReiNand and http://gbatemp.net/threads/reinand-mod-o3ds-n3ds-sysnand.411110
The FIRMs you need are [HERE](http://www99.zippyshare.com/v/kEIiQl0x/file.html). The FIRMs you need are [HERE](http://www77.zippyshare.com/v/oXDn2Hes/file.html).
**Credits:** **Credits:**
@@ -29,4 +31,6 @@ A skilled reverser gave me the new reboot patch.
The screen init code is from dark_samus, bil1s, Normmatt, delebile and everyone who contributed. The screen init code is from dark_samus, bil1s, Normmatt, delebile and everyone who contributed.
The code for printing to the screen is from CakesFW. The code for printing to the screen, and the heavy revision to the reboot patch to allow for AGB/TWL loading are from CakesFW.
ARM11 userland patching is only possible thanks to @yifanlu's 3ds_injector, which is bundled in the CFW.

View File

@@ -158,7 +158,7 @@ static Result load_code(u64 progid, prog_addrs_t *shared, u64 prog_handle, int i
} }
// patch // patch
patch_code(progid, (u8 *)shared->text_addr, shared->total_size << 12); patchCode(progid, (u8 *)shared->text_addr, shared->total_size << 12);
return 0; return 0;
} }

View File

@@ -11,11 +11,12 @@ static u32 config = 0;
static u8 secureinfo[0x111] = {0}; static u8 secureinfo[0x111] = {0};
//Quick Search algorithm, adapted from http://igm.univ-mlv.fr/~lecroq/string/node19.html#SECTION00190 //Quick Search algorithm, adapted from http://igm.univ-mlv.fr/~lecroq/string/node19.html#SECTION00190
static u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize){ static u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize)
{
const u8 *patternc = (const u8 *)pattern; const u8 *patternc = (const u8 *)pattern;
//Preprocessing //Preprocessing
int table[256]; u32 table[256];
for(u32 i = 0; i < 256; ++i) for(u32 i = 0; i < 256; ++i)
table[i] = patternSize + 1; table[i] = patternSize + 1;
@@ -25,7 +26,8 @@ static u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSiz
//Searching //Searching
u32 j = 0; u32 j = 0;
while(j <= size - patternSize){ while(j <= size - patternSize)
{
if(memcmp(patternc, startPos + j, patternSize) == 0) if(memcmp(patternc, startPos + j, patternSize) == 0)
return startPos + j; return startPos + j;
j += table[startPos[j + patternSize]]; j += table[startPos[j + patternSize]];
@@ -34,28 +36,32 @@ static u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSiz
return NULL; return NULL;
} }
static u32 patch_memory(u8 *start, u32 size, const void *pattern, u32 patsize, int offset, const void *replace, u32 repsize, u32 count){ static u32 patchMemory(u8 *start, u32 size, const void *pattern, u32 patSize, int offset, const void *replace, u32 repSize, u32 count)
{
u32 i; u32 i;
for(i = 0; i < count; i++){ for(i = 0; i < count; i++)
u8 *found = memsearch(start, pattern, size, patsize); {
u8 *found = memsearch(start, pattern, size, patSize);
if(found == NULL) if(found == NULL)
break; break;
memcpy(found + offset, replace, repsize); memcpy(found + offset, replace, repSize);
u32 at = (u32)(found - start); u32 at = (u32)(found - start);
if(at + patsize > size) size = 0; if(at + patSize > size) size = 0;
else size = size - (at + patsize); else size = size - (at + patSize);
start = found + patsize; start = found + patSize;
} }
return i; return i;
} }
static int file_open(IFile *file, FS_ArchiveID id, const char *path, int flags){ static int fileOpen(IFile *file, FS_ArchiveID id, const char *path, int flags)
{
FS_Archive archive; FS_Archive archive;
FS_Path ppath; FS_Path ppath;
@@ -67,10 +73,12 @@ static int file_open(IFile *file, FS_ArchiveID id, const char *path, int flags){
ppath.type = PATH_ASCII; ppath.type = PATH_ASCII;
ppath.data = path; ppath.data = path;
ppath.size = len+1; ppath.size = len+1;
return IFile_Open(file, archive, ppath, flags); return IFile_Open(file, archive, ppath, flags);
} }
static int patch_secureinfo(){ static int loadSecureinfo()
{
IFile file; IFile file;
Result ret; Result ret;
u64 total; u64 total;
@@ -78,33 +86,20 @@ static int patch_secureinfo(){
if(secureinfo[0] == 0xFF) if(secureinfo[0] == 0xFF)
return 0; return 0;
ret = file_open(&file, ARCHIVE_SDMC, "/SecureInfo_A", FS_OPEN_READ); ret = fileOpen(&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)){
ret = file_open(&file, ARCHIVE_NAND_RW, "/sys/SecureInfo_C", FS_OPEN_WRITE | FS_OPEN_CREATE);
if(R_SUCCEEDED(ret)){
ret = IFile_Write(&file, &total, secureinfo, sizeof(secureinfo), FS_WRITE_FLUSH);
IFile_Close(&file);
}
secureinfo[0] = 0xFF; // we repurpose this byte as status
}
}
else { // get file from NAND
ret = file_open(&file, ARCHIVE_NAND_RW, "/sys/SecureInfo_C", FS_OPEN_READ);
if(R_SUCCEEDED(ret)){
ret = IFile_Read(&file, &total, secureinfo, sizeof(secureinfo)); ret = IFile_Read(&file, &total, secureinfo, sizeof(secureinfo));
IFile_Close(&file); IFile_Close(&file);
if(R_SUCCEEDED(ret) && total == sizeof(secureinfo)) if(R_SUCCEEDED(ret) && total == sizeof(secureinfo))
secureinfo[0] = 0xFF; secureinfo[0] = 0xFF;
} }
}
return ret; return ret;
} }
static int open_config(){ static int loadConfig()
{
IFile file; IFile file;
Result ret; Result ret;
u64 total; u64 total;
@@ -112,23 +107,27 @@ static int open_config(){
if(config) if(config)
return 0; return 0;
ret = file_open(&file, ARCHIVE_SDMC, "/aurei/config.bin", FS_OPEN_READ); ret = fileOpen(&file, ARCHIVE_SDMC, "/aurei/config.bin", FS_OPEN_READ);
if(R_SUCCEEDED(ret)){ if(R_SUCCEEDED(ret))
ret = IFile_Read(&file, &total, (void *)&config, 3); {
ret = IFile_Read(&file, &total, &config, 3);
IFile_Close(&file); IFile_Close(&file);
} }
return ret; return ret;
} }
u32 patch_code(u64 progid, u8 *code, u32 size){ void patchCode(u64 progId, u8 *code, u32 size)
if( progid == 0x0004003000008F02LL || // USA Menu {
progid == 0x0004003000008202LL || // JPN Menu switch(progId)
progid == 0x0004003000009802LL || // EUR Menu {
progid == 0x000400300000A102LL || // CHN Menu case 0x0004003000008F02LL: // USA Menu
progid == 0x000400300000A902LL || // KOR Menu case 0x0004003000008202LL: // EUR Menu
progid == 0x000400300000B102LL // TWN Menu case 0x0004003000009802LL: // JPN Menu
){ case 0x000400300000A102LL: // CHN Menu
case 0x000400300000A902LL: // KOR Menu
case 0x000400300000B102LL: // TWN Menu
{
static const u8 regionFreePattern[] = { static const u8 regionFreePattern[] = {
0x00, 0x00, 0x55, 0xE3, 0x01, 0x10, 0xA0, 0xE3 0x00, 0x00, 0x55, 0xE3, 0x01, 0x10, 0xA0, 0xE3
}; };
@@ -136,97 +135,79 @@ u32 patch_code(u64 progid, u8 *code, u32 size){
0x01, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1 0x01, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1
}; };
patch_memory(code, size, //Patch SMDH region checks
patchMemory(code, size,
regionFreePattern, regionFreePattern,
sizeof(regionFreePattern), -16, sizeof(regionFreePattern), -16,
regionFreePatch, regionFreePatch,
sizeof(regionFreePatch), 1 sizeof(regionFreePatch), 1
); );
break;
} }
else if(progid == 0x0004013000002C02LL){ // NIM
case 0x0004013000002C02LL: // NIM
{
static const u8 blockAutoUpdatesPattern[] = { static const u8 blockAutoUpdatesPattern[] = {
0x25, 0x79, 0x0B, 0x99 0x25, 0x79, 0x0B, 0x99
}; };
static const u8 blockAutoUpdatesPatch[] = { static const u8 blockAutoUpdatesPatch[] = {
0xE3, 0xA0 0xE3, 0xA0
}; };
static const u8 blockEShopUpdateCheckPattern[] = { static const u8 skipEshopUpdateCheckPattern[] = {
0x30, 0xB5, 0xF1, 0xB0 0x30, 0xB5, 0xF1, 0xB0
}; };
static const u8 blockEShopUpdateCheckPatch[] = { static const u8 skipEshopUpdateCheckPatch[] = {
0x00, 0x20, 0x08, 0x60, 0x70, 0x47 0x00, 0x20, 0x08, 0x60, 0x70, 0x47
}; };
static const u8 countryRespPattern[] = {
0x01, 0x20, 0x01, 0x90, 0x22, 0x46, 0x06, 0x9B
};
static const char countryRespPatchModel[] = {
0x06, 0x9A, 0x03, 0x20, 0x90, 0x47, 0x55, 0x21, 0x01, 0x70, 0x53, 0x21, 0x41, 0x70, 0x00, 0x21,
0x81, 0x70, 0x60, 0x61, 0x00, 0x20
};
const char *country;
char countryRespPatch[sizeof(countryRespPatchModel)];
patch_memory(code, size, //Block silent auto-updates
patchMemory(code, size,
blockAutoUpdatesPattern, blockAutoUpdatesPattern,
sizeof(blockAutoUpdatesPattern), 0, sizeof(blockAutoUpdatesPattern), 0,
blockAutoUpdatesPatch, blockAutoUpdatesPatch,
sizeof(blockAutoUpdatesPatch), 1 sizeof(blockAutoUpdatesPatch), 1
); );
patch_memory(code, size,
blockEShopUpdateCheckPattern, //Skip update checks to access the EShop
sizeof(blockEShopUpdateCheckPattern), 0, patchMemory(code, size,
blockEShopUpdateCheckPatch, skipEshopUpdateCheckPattern,
sizeof(blockEShopUpdateCheckPatch), 1 sizeof(skipEshopUpdateCheckPattern), 0,
skipEshopUpdateCheckPatch,
sizeof(skipEshopUpdateCheckPatch), 1
); );
if(R_SUCCEEDED(patch_secureinfo())){
switch(secureinfo[0x100]){ break;
case 1: country = "US"; break;
case 2: country = "GB"; break; // sorry rest-of-Europe, you have to change this
case 3: country = "AU"; break;
case 4: country = "CN"; break;
case 5: country = "KR"; break;
case 6: country = "TW"; break;
default: case 0: country = "JP"; break;
} }
// patch XML response Country case 0x0004001000021000LL: // USA MSET
memcpy(countryRespPatch, case 0x0004001000020000LL: // JPN MSET
countryRespPatchModel, case 0x0004001000022000LL: // EUR MSET
sizeof(countryRespPatchModel) case 0x0004001000026000LL: // CHN MSET
); case 0x0004001000027000LL: // KOR MSET
countryRespPatch[6] = country[0]; case 0x0004001000028000LL: // TWN MSET
countryRespPatch[10] = country[1]; {
patch_memory(code, size, if(R_SUCCEEDED(loadConfig()) && ((config >> 5) & 1))
countryRespPattern, {
sizeof(countryRespPattern), 0, static const u16 verPattern[] = u"Ver.";
countryRespPatch, const u32 currentFirm = ((config >> 12) & 1);
sizeof(countryRespPatch), 1 const u32 currentNand = ((config >> 13) & 3);
);
}
}
else if(
progid == 0x0004001000021000LL || // USA MSET
progid == 0x0004001000020000LL || // JPN MSET
progid == 0x0004001000022000LL || // EUR MSET
progid == 0x0004001000026000LL || // CHN MSET
progid == 0x0004001000027000LL || // KOR MSET
progid == 0x0004001000028000LL // TWN MSET
){
if(R_SUCCEEDED(open_config()) && ((config >> 5) & 0x1)){
static const u16 VerPattern[] = u"Ver.";
const u32 currentFirm = ((config >> 12) & 0x1);
const u32 currentNand = ((config >> 13) & 0x3);
patch_memory(code, size, //Patch Ver. string
VerPattern, patchMemory(code, size,
sizeof(VerPattern) - sizeof(u16), 0, verPattern,
sizeof(verPattern) - sizeof(u16), 0,
currentNand ? ((currentNand == 1) ? ((currentFirm == 1) ? u" Emu" : u"Emu9") : u"Emu2") : currentNand ? ((currentNand == 1) ? ((currentFirm == 1) ? u" Emu" : u"Emu9") : u"Emu2") :
((currentFirm == 1) ? u" Sys" : u"Sys9"), ((currentFirm == 1) ? u" Sys" : u"Sys9"),
sizeof(VerPattern) - sizeof(u16), 1 sizeof(verPattern) - sizeof(u16), 1
); );
} }
break;
} }
else if (progid == 0x0004013000008002LL){ // NS
case 0x0004013000008002LL: // NS
{
static const u8 stopCartUpdatesPattern[] = { static const u8 stopCartUpdatesPattern[] = {
0x0C, 0x18, 0xE1, 0xD8 0x0C, 0x18, 0xE1, 0xD8
}; };
@@ -234,33 +215,41 @@ u32 patch_code(u64 progid, u8 *code, u32 size){
0x0B, 0x18, 0x21, 0xC8 0x0B, 0x18, 0x21, 0xC8
}; };
patch_memory(code, size, //Disable updates from foreign carts (makes carts region-free)
patchMemory(code, size,
stopCartUpdatesPattern, stopCartUpdatesPattern,
sizeof(stopCartUpdatesPattern), 0, sizeof(stopCartUpdatesPattern), 0,
stopCartUpdatesPatch, stopCartUpdatesPatch,
sizeof(stopCartUpdatesPatch), 2 sizeof(stopCartUpdatesPatch), 2
); );
break;
} }
else if(progid == 0x0004013000001702LL){ // CFG
case 0x0004013000001702LL: // CFG
{
static const u8 secureinfoSigCheckPattern[] = { static const u8 secureinfoSigCheckPattern[] = {
0x06, 0x46, 0x10, 0x48, 0xFC 0x06, 0x46, 0x10, 0x48, 0xFC
}; };
static const u8 secureinfoSigCheckPatch[] = { static const u8 secureinfoSigCheckPatch[] = {
0x00, 0x26 0x00, 0x26
}; };
static const u16 secureinfoFilenamePattern[] = u"SecureInfo_";
static const u16 secureinfoFilenamePatch[] = u"C";
// disable SecureInfo signature check //Disable SecureInfo signature check
patch_memory(code, size, patchMemory(code, size,
secureinfoSigCheckPattern, secureinfoSigCheckPattern,
sizeof(secureinfoSigCheckPattern), 0, sizeof(secureinfoSigCheckPattern), 0,
secureinfoSigCheckPatch, secureinfoSigCheckPatch,
sizeof(secureinfoSigCheckPatch), 1 sizeof(secureinfoSigCheckPatch), 1
); );
if(R_SUCCEEDED(patch_secureinfo())){
// use SecureInfo_C if(R_SUCCEEDED(loadSecureinfo()))
patch_memory(code, size, {
static const u16 secureinfoFilenamePattern[] = u"SecureInfo_";
static const u16 secureinfoFilenamePatch[] = u"C";
//Use SecureInfo_C
patchMemory(code, size,
secureinfoFilenamePattern, secureinfoFilenamePattern,
sizeof(secureinfoFilenamePattern) - sizeof(u16), sizeof(secureinfoFilenamePattern) - sizeof(u16),
sizeof(secureinfoFilenamePattern) - sizeof(u16), sizeof(secureinfoFilenamePattern) - sizeof(u16),
@@ -268,7 +257,8 @@ u32 patch_code(u64 progid, u8 *code, u32 size){
sizeof(secureinfoFilenamePatch) - sizeof(u16), 2 sizeof(secureinfoFilenamePatch) - sizeof(u16), 2
); );
} }
}
return 0; break;
}
}
} }

View File

@@ -2,4 +2,4 @@
#include <3ds/types.h> #include <3ds/types.h>
u32 patch_code(u64 progid, u8 *code, u32 size); void patchCode(u64 progId, u8 *code, u32 size);

View File

@@ -19,8 +19,6 @@ include $(DEVKITARM)/3ds_rules
export TARGET := $(shell basename $(CURDIR)) export TARGET := $(shell basename $(CURDIR))
BUILD := build BUILD := build
SOURCES := source source/fatfs source/fatfs/sdmmc SOURCES := source source/fatfs source/fatfs/sdmmc
DATA := data
INCLUDES := include source/fatfs source/fatfs/sdmmc
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
# Setup some defines # Setup some defines
@@ -43,14 +41,6 @@ CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
ASFLAGS := -g $(ARCH) ASFLAGS := -g $(ARCH)
LDFLAGS = -nostartfiles -g --specs=../stub.specs $(ARCH) -Wl,-Map,$(TARGET).map LDFLAGS = -nostartfiles -g --specs=../stub.specs $(ARCH) -Wl,-Map,$(TARGET).map
LIBS :=
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS :=
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional # no real need to edit anything past this point unless you need to add additional
# rules for different file extensions # rules for different file extensions
@@ -60,15 +50,13 @@ ifneq ($(BUILD),$(notdir $(CURDIR)))
export OUTPUT := $(CURDIR)/$(TARGET) export OUTPUT := $(CURDIR)/$(TARGET)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir))
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD) export DEPSDIR := $(CURDIR)/$(BUILD)
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C # use CXX for linking C++ projects, CC for standard C
@@ -84,14 +72,7 @@ else
endif endif
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
export OFILES := $(addsuffix .o,$(BINFILES)) \ export OFILES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
.PHONY: $(BUILD) clean all .PHONY: $(BUILD) clean all

View File

@@ -2,12 +2,11 @@
#include "types.h" #include "types.h"
#define HID_PAD (*(vu16 *)0x10146000 ^ 0xFFF) #define HID_PAD (*(vu32 *)0x10146000 ^ 0xFFF)
#define BUTTON_B (1 << 1)
#define BUTTON_X (1 << 10) #define BUTTON_X (1 << 10)
#define BUTTON_Y (1 << 11) #define BUTTON_Y (1 << 11)
#define BUTTON_R1 (1 << 8)
#define BUTTON_SELECT (1 << 2) #define BUTTON_SELECT (1 << 2)
#define BUTTON_START (1 << 3)
#define BUTTON_RIGHT (1 << 4) #define BUTTON_RIGHT (1 << 4)
#define BUTTON_LEFT (1 << 5) #define BUTTON_LEFT (1 << 5)
#define BUTTON_UP (1 << 6) #define BUTTON_UP (1 << 6)

View File

@@ -4,9 +4,11 @@
#define PAYLOAD_ADDRESS 0x23F00000 #define PAYLOAD_ADDRESS 0x23F00000
static u32 loadPayload(const char *path){ static u32 loadPayload(const char *path)
{
FIL payload; FIL payload;
unsigned int br; unsigned int br;
if(f_open(&payload, path, FA_READ) == FR_OK) if(f_open(&payload, path, FA_READ) == FR_OK)
{ {
f_read(&payload, (void *)PAYLOAD_ADDRESS, f_size(&payload), &br); f_read(&payload, (void *)PAYLOAD_ADDRESS, f_size(&payload), &br);
@@ -18,22 +20,23 @@ static u32 loadPayload(const char *path){
return 0; return 0;
} }
void main(void){ void main(void)
{
FATFS fs; FATFS fs;
f_mount(&fs, "0:", 1); f_mount(&fs, "0:", 1);
//Get pressed buttons //Get pressed buttons
u16 pressed = HID_PAD; u32 pressed = HID_PAD;
if(((pressed & BUTTON_B) && loadPayload("/aurei/payloads/b.bin")) || if(((pressed & BUTTON_RIGHT) && loadPayload("/aurei/payloads/right.bin")) ||
((pressed & BUTTON_X) && loadPayload("/aurei/payloads/x.bin")) ||
((pressed & BUTTON_Y) && loadPayload("/aurei/payloads/y.bin")) ||
((pressed & BUTTON_SELECT) && loadPayload("/aurei/payloads/select.bin")) ||
((pressed & BUTTON_START) && loadPayload("/aurei/payloads/start.bin")) ||
((pressed & BUTTON_RIGHT) && loadPayload("/aurei/payloads/right.bin")) ||
((pressed & BUTTON_LEFT) && loadPayload("/aurei/payloads/left.bin")) || ((pressed & BUTTON_LEFT) && loadPayload("/aurei/payloads/left.bin")) ||
((pressed & BUTTON_UP) && loadPayload("/aurei/payloads/up.bin")) || ((pressed & BUTTON_UP) && loadPayload("/aurei/payloads/up.bin")) ||
((pressed & BUTTON_DOWN) && loadPayload("/aurei/payloads/down.bin")) || ((pressed & BUTTON_DOWN) && loadPayload("/aurei/payloads/down.bin")) ||
((pressed & BUTTON_X) && loadPayload("/aurei/payloads/x.bin")) ||
((pressed & BUTTON_Y) && loadPayload("/aurei/payloads/y.bin")) ||
((pressed & BUTTON_SELECT) && loadPayload("/aurei/payloads/select.bin")) ||
((pressed & BUTTON_R1) && loadPayload("/aurei/payloads/r.bin")) ||
loadPayload("/aurei/payloads/default.bin")) loadPayload("/aurei/payloads/default.bin"))
((void (*)())PAYLOAD_ADDRESS)(); ((void (*)())PAYLOAD_ADDRESS)();
} }

View File

@@ -12,7 +12,4 @@ _start:
mcr p15, 0, r0, c7, c6, 0 @ flush D-cache mcr p15, 0, r0, c7, c6, 0 @ flush D-cache
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
bl main b main
.die:
b .die

View File

@@ -1,221 +1,232 @@
.arm.little .arm.little
byteswritten equ 0x2000E000 firm_addr equ 0x24000000 ; Temporary location where we'll load the FIRM to
kernelCode equ 0x080F0000 firm_maxsize equ 0x200000 ; Random value that's bigger than any of the currently known firm's sizes.
buffer equ 0x24000000 kernel_code equ 0x080F0000 ; Offset to copy the Kernel9 code to
fileOpen equ 0x4E45504F ;dummy
.create "reboot.bin", 0 .create "reboot.bin", 0
.arm .arm
//Code jumps here right after the sprintf call ; Interesting registers and locations to keep in mind, set before this code is ran:
process9Reboot: ; - sp + 0x3A8 - 0x70: FIRM path in exefs.
doPxi: ; - r7 (which is sp + 0x3A8 - 0x198): Reserved space for file handle
ldr r4, =0x44846 ; - *(sp + 0x3A8 - 0x198) + 0x28: fread function.
pxi_wait_recv:
ldr r2, =0x44846
ldr r0, =0x10008000 ldr r0, =0x10008000
readPxiLoop1: readPxiLoop1:
ldrh r1, [r0, #4] ldrh r1, [r0, #4]
.word 0xE1B01B81 //lsls r1, r1, #0x17 lsls r1, #0x17
bmi readPxiLoop1 bmi readPxiLoop1
ldr r0, [r0, #0xC] ldr r0, [r0, #0xC]
cmp r0, r4 cmp r0, r2
bne doPxi bne pxi_wait_recv
GetFirmPath: ; Convert 2 bytes of the path string
add r0, sp, #0x3A8-0x70+0x24 ; This will be the method of getting the lower 2 bytes of the title ID
ldr r1, [r0], #4 ; until someone bothers figuring out where the value is derived from.
ldr r2, =0x00300030 mov r0, #0 ; Result
cmp r1, r2 add r1, sp, #0x3A8 - 0x70
ldreq r1, [r0], #4 add r1, #0x22 ; The significant bytes
ldreq r2, =0x002F0032 mov r2, #4 ; Maximum loops (amount of bytes * 2)
cmpeq r1, r2
OpenFirm: hex_string_to_int_loop:
ldreq r1, =(FileName - OpenFirm - 12) ldr r3, [r1], #2 ; 2 because it's a utf-16 string.
addeq r1, pc and r3, #0xFF
addne r1, sp, #0x3A8-0x70
moveq r2, #1 ; Check if it"s a number
movne r2, #0 cmp r3, #'0'
str r2, [externalFirm] blo hex_string_to_int_end
mov r2, #1 sub r3, #'0'
cmp r3, #9
bls hex_string_to_int_calc
; Check if it"s a capital letter
cmp r3, #'A' - '0'
blo hex_string_to_int_end
sub r3, #'A' - '0' - 0xA ; Make the correct value: 0xF >= al >= 0xA
cmp r3, #0xF
bls hex_string_to_int_calc
; Incorrect value: x > "A"
bhi hex_string_to_int_end
hex_string_to_int_calc:
orr r0, r3, r0, lsl #4
subs r2, #1
bne hex_string_to_int_loop
hex_string_to_int_end:
; Get the FIRM path
cmp r0, #0x0002 ; NATIVE_FIRM
adreq r1, firm_fname
beq load_firm
ldr r5, =0x0102 ; TWL_FIRM
cmp r0, r5
adreq r1, twlfirm_fname
beq load_firm
ldr r5, =0x0202 ; AGB_FIRM
cmp r0, r5
adreq r1, agbfirm_fname
beq load_firm
bne fallback ; TODO: Stubbed
fallback:
; Fallback: Load specified FIRM from exefs
add r1, sp, #0x3A8-0x70 ; Location of exefs string.
b load_firm
load_firm:
; Open file
add r0, r7, #8 add r0, r7, #8
ldr r6, =fileOpen mov r2, #1
ldr r6, [fopen]
orr r6, 1
blx r6 blx r6
SeekFirm: cmp r0, #0 ; Check if we were able to load the FIRM
ldr r0, [externalFirm] bne fallback ; Otherwise, try again with the FIRM from exefs.
cmp r0, #1 ; This will loop indefinitely if the exefs FIRM fails to load, but whatever.
moveq r0, r7
ldreq r1, =byteswritten
ldreq r2, =buffer
ldreq r3, =0x0
ldreq r6, [sp,#0x3A8-0x198]
ldreq r6, [r6,#0x28] //fread function stored here
blxeq r6
ReadFirm: ; Read file
mov r0, r7 mov r0, r7
ldr r1, =byteswritten adr r1, bytes_read
ldr r2, =buffer mov r2, firm_addr
ldr r3, =0x200000 mov r3, firm_maxsize
ldr r6, [sp, #0x3A8-0x198] ldr r6, [sp, #0x3A8-0x198]
ldr r6, [r6,#0x28] //fread function stored here ldr r6, [r6, #0x28]
blx r6 blx r6
KernelSetState: ; Set kernel state
mov r0, #0
mov r1, #0
mov r2, #0 mov r2, #0
mov r3, r2 mov r3, #0
mov r1, r2 swi 0x7C
mov r0, r2
.word 0xEF00007C //SVC 0x7C
GoToReboot: goto_reboot:
ldr r0, =(KernelCodeStart - GoToReboot - 12) ; Jump to reboot code
ldr r0, =(kernelcode_start - goto_reboot - 12)
add r0, pc add r0, pc
ldr r1, =kernelCode ldr r1, =kernel_code
ldr r2, =0x300 ldr r2, =0x300
bl Memcpy bl memcpy32
ldr r0, =kernel_code
swi 0x7B
ldr r0, =kernelCode die:
.word 0xEF00007B //SVC 0x7B b die
InfiniteLoop: memcpy32: ; memcpy32(void *src, void *dst, unsigned int size)
b InfiniteLoop add r2, r0
memcpy32_loop:
ldmia r0!, {r3}
stmia r1!, {r3}
cmp r0, r2
blo memcpy32_loop
bx lr
Memcpy: bytes_read: .word 0
MOV R12, LR fopen: .ascii "OPEN"
STMFD SP!, {R0-R4} .pool
ADD R2, R2, R0 firm_fname: .dcw "sdmc:/aurei/patched_firmware_sys.bin"
.word 0x0
memcpyLoop: .pool
LDR R3, [R0],#4 twlfirm_fname: .dcw "sdmc:/aurei/patched_firmware_twl.bin"
STR R3, [R1],#4 .word 0x0
CMP R0, R2 .pool
BLT memcpyLoop agbfirm_fname: .dcw "sdmc:/aurei/patched_firmware_agb.bin"
LDMFD SP!, {R0-R4}
MOV LR, R12
BX LR
FileName:
.dcw "sdmc:/aurei/patched_firmware_sys.bin"
.word 0x0 .word 0x0
externalFirm:
.word 0x2000A000
.pool
// Kernel Code
.align 4 .align 4
KernelCodeStart: kernelcode_start:
memorySetting: ; Set MPU settings
MRC p15, 0, R0,c2,c0, 0 mrc p15, 0, r0, c2, c0, 0 ; dcacheable
MRC p15, 0, R12,c2,c0, 1 mrc p15, 0, r12, c2, c0, 1 ; icacheable
MRC p15, 0, R1,c3,c0, 0 mrc p15, 0, r1, c3, c0, 0 ; write bufferable
MRC p15, 0, R2,c5,c0, 2 mrc p15, 0, r2, c5, c0, 2 ; daccess
MRC p15, 0, R3,c5,c0, 3 mrc p15, 0, r3, c5, c0, 3 ; iaccess
LDR R4, =0x18000035 ldr r4, =0x18000035 ; 0x18000000 128M
BIC R2, R2, #0xF0000 bic r2, r2, #0xF0000 ; unprotect region 4
BIC R3, R3, #0xF0000 bic r3, r3, #0xF0000 ; unprotect region 4
ORR R0, R0, #0x10 orr r0, r0, #0x10 ; dcacheable region 4
ORR R2, R2, #0x30000 orr r2, r2, #0x30000 ; region 4 r/w
ORR R3, R3, #0x30000 orr r3, r3, #0x30000 ; region 4 r/w
ORR R12, R12, #0x10 orr r12, r12, #0x10 ; icacheable region 4
ORR R1, R1, #0x10 orr r1, r1, #0x10 ; write bufferable region 4
MCR p15, 0, R0,c2,c0, 0 mcr p15, 0, r0, c2, c0, 0
MCR p15, 0, R12,c2,c0, 1 mcr p15, 0, r12, c2, c0, 1
MCR p15, 0, R1,c3,c0, 0 mcr p15, 0, r1, c3, c0, 0 ; write bufferable
MCR p15, 0, R2,c5,c0, 2 mcr p15, 0, r2, c5, c0, 2 ; daccess
MCR p15, 0, R3,c5,c0, 3 mcr p15, 0, r3, c5, c0, 3 ; iaccess
MCR p15, 0, R4,c6,c4, 0 mcr p15, 0, r4, c6, c4, 0 ; region 4 (hmmm)
MRC p15, 0, R0,c2,c0, 0
MRC p15, 0, R1,c2,c0, 1
MRC p15, 0, R2,c3,c0, 0
ORR R0, R0, #0x20
ORR R1, R1, #0x20
ORR R2, R2, #0x20
MCR p15, 0, R0,c2,c0, 0
MCR p15, 0, R1,c2,c0, 1
MCR p15, 0, R2,c3,c0, 0
copyFirmPartitions: mrc p15, 0, r0, c2, c0, 0 ; dcacheable
LDR R4, =buffer mrc p15, 0, r1, c2, c0, 1 ; icacheable
ADD R3, R4, #0x40 mrc p15, 0, r2, c3, c0, 0 ; write bufferable
LDR R0, [R3] orr r0, r0, #0x20 ; dcacheable region 5
ADD R0, R0, R4 orr r1, r1, #0x20 ; icacheable region 5
LDR R1, [R3,#4] orr r2, r2, #0x20 ; write bufferable region 5
LDR R2, [R3,#8] mcr p15, 0, r0, c2, c0, 0 ; dcacheable
bl KernelMemcpy mcr p15, 0, r1, c2, c0, 1 ; icacheable
mcr p15, 0, r2, c3, c0, 0 ; write bufferable
ADD R3, R4, #0x70 ; Copy the firmware
LDR R0, [R3] mov r4, firm_addr
ADD R0, R0, R4 add r5, r4, #0x40 ; Start of loop
LDR R1, [R3,#4] add r6, r5, #0x30 * 3 ; End of loop (scan 4 entries)
LDR R2, [R3,#8]
bl KernelMemcpy
ADD R3, R4, #0xA0 copy_firm_loop:
LDR R0, [R3] ldr r0, [r5]
ADD R0, R0, R4 cmp r0, #0
LDR R1, [R3,#4] addne r0, r4 ; src
LDR R2, [R3,#8] ldrne r1, [r5, #4] ; dest
bl KernelMemcpy ldrne r2, [r5, #8] ; size
blne kernelmemcpy32
ADD R3, R4, #0xD0 cmp r5, r6
LDR R0, [R3] addlo r5, #0x30
CMP R0, #0 blo copy_firm_loop
BEQ invalidateDataCache
ADD R0, R0, R4
LDR R1, [R3,#4]
LDR R2, [R3,#8]
bl KernelMemcpy
invalidateDataCache: ; Flush cache
MOV R2, #0 mov r2, #0
MOV R1, R2 mov r1, r2
loc_809460C: flush_cache:
MOV R0, #0 mov r0, #0
MOV R3, R2,LSL#30 mov r3, r2, lsl #30
loc_8094614: flush_cache_inner_loop:
ORR R12, R3, R0,LSL#5 orr r12, r3, r0, lsl#5
MCR p15, 0, R1,c7,c10, 4 mcr p15, 0, r1, c7, c10, 4 ; drain write buffer
MCR p15, 0, R12,c7,c14, 2 mcr p15, 0, r12, c7, c14, 2 ; clean and flush dcache entry (index and segment)
ADD R0, R0, #1 add r0, #1
CMP R0, #0x20 cmp r0, #0x20
BCC loc_8094614 bcc flush_cache_inner_loop
ADD R2, R2, #1 add r2, #1
CMP R2, #4 cmp r2, #4
BCC loc_809460C bcc flush_cache
jumpToEntrypoint: ; Enable MPU
MCR p15, 0, R1,c7,c10, 4 ldr r0, =0x42078 ; alt vector select, enable itcm
LDR R0, =0x42078 mcr p15, 0, r0, c1, c0, 0
MCR p15, 0, R0,c1,c0, 0 mcr p15, 0, r1, c7, c5, 0 ; flush dcache
MCR p15, 0, R1,c7,c5, 0 mcr p15, 0, r1, c7, c6, 0 ; flush icache
MCR p15, 0, R1,c7,c6, 0 mcr p15, 0, r1, c7, c10, 4 ; drain write buffer
MCR p15, 0, R1,c7,c10, 4 mov r0, firm_addr
LDR R4, =buffer
MOV R1, #0x1FFFFFFC ; Boot FIRM
LDR R2, [R4,#8] mov r1, #0x1FFFFFFC
STR R2, [R1] ldr r2, [r0, #8] ; arm11 entry
LDR R0, [R4,#0xC] str r2, [r1]
BX R0 ldr r0, [r0, #0xC] ; arm9 entry
bx r0
.pool .pool
KernelMemcpy: kernelmemcpy32: ; memcpy32(void *src, void *dst, unsigned int size)
MOV R12, LR add r2, r0
STMFD SP!, {R0-R4} kmemcpy32_loop:
ADD R2, R2, R0 ldmia r0!, {r3}
stmia r1!, {r3}
kmemcpyLoop: cmp r0, r2
LDR R3, [R0],#4 blo kmemcpy32_loop
STR R3, [R1],#4 bx lr
CMP R0, R2
BLT kmemcpyLoop
LDMFD SP!, {R0-R4}
MOV LR, R12
BX LR
.pool
KernelCodeEnd:
.close .close

115
screeninit/Makefile Executable file
View File

@@ -0,0 +1,115 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
include $(DEVKITARM)/3ds_rules
#---------------------------------------------------------------------------------
# TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# DATA is a list of directories containing data files
# 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))
BUILD := build
SOURCES := source
#---------------------------------------------------------------------------------
# Setup some defines
#---------------------------------------------------------------------------------
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -mthumb -mthumb-interwork
CFLAGS := -g -Wall -O2\
-mcpu=mpcore -mlittle-endian\
-ffast-math -Wno-main -std=c99\
$(ARCH)
CFLAGS += $(INCLUDE) -DARM11
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
ASFLAGS := -g $(ARCH)
LDFLAGS = -nostartfiles -g --specs=../stub.specs $(ARCH) -Wl,-Map,$(TARGET).map
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export OUTPUT := $(CURDIR)/$(TARGET)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD)
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#---------------------------------------------------------------------------------
export LD := $(CC)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export LD := $(CXX)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
export OFILES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
.PHONY: $(BUILD) clean all
#---------------------------------------------------------------------------------
all: $(BUILD)
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) $(OUTPUT).elf
#---------------------------------------------------------------------------------
else
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
$(OUTPUT).bin : $(OUTPUT).elf
$(OUTPUT).elf : $(OFILES)
#---------------------------------------------------------------------------------
%.bin: %.elf
@$(OBJCOPY) -O binary $< $@
@echo built ... $(notdir $@)
-include $(DEPENDS)
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

105
screeninit/source/main.c Executable file
View File

@@ -0,0 +1,105 @@
#include "types.h"
void main(void)
{
const u32 brightness[4] = {0x5F, 0x4C, 0x39, 0x26};
u32 brightnessLevel = *(vu32 *)0x24F04000;
vu32 *const arm11 = (u32 *)0x1FFFFFF8;
*(vu32 *)0x10141200 = 0x1007F;
*(vu32 *)0x10202014 = 0x00000001;
*(vu32 *)0x1020200C &= 0xFFFEFFFE;
*(vu32 *)0x10202240 = brightness[brightnessLevel];
*(vu32 *)0x10202A40 = brightness[brightnessLevel];
*(vu32 *)0x10202244 = 0x1023E;
*(vu32 *)0x10202A44 = 0x1023E;
// Top screen
*(vu32 *)0x10400400 = 0x000001c2;
*(vu32 *)0x10400404 = 0x000000d1;
*(vu32 *)0x10400408 = 0x000001c1;
*(vu32 *)0x1040040c = 0x000001c1;
*(vu32 *)0x10400410 = 0x00000000;
*(vu32 *)0x10400414 = 0x000000cf;
*(vu32 *)0x10400418 = 0x000000d1;
*(vu32 *)0x1040041c = 0x01c501c1;
*(vu32 *)0x10400420 = 0x00010000;
*(vu32 *)0x10400424 = 0x0000019d;
*(vu32 *)0x10400428 = 0x00000002;
*(vu32 *)0x1040042c = 0x00000192;
*(vu32 *)0x10400430 = 0x00000192;
*(vu32 *)0x10400434 = 0x00000192;
*(vu32 *)0x10400438 = 0x00000001;
*(vu32 *)0x1040043c = 0x00000002;
*(vu32 *)0x10400440 = 0x01960192;
*(vu32 *)0x10400444 = 0x00000000;
*(vu32 *)0x10400448 = 0x00000000;
*(vu32 *)0x1040045C = 0x00f00190;
*(vu32 *)0x10400460 = 0x01c100d1;
*(vu32 *)0x10400464 = 0x01920002;
*(vu32 *)0x10400468 = 0x18300000;
*(vu32 *)0x10400470 = 0x80341;
*(vu32 *)0x10400474 = 0x00010501;
*(vu32 *)0x10400478 = 0;
*(vu32 *)0x10400490 = 0x000002D0;
*(vu32 *)0x1040049C = 0x00000000;
// Disco register
for(u32 i = 0; i < 256; i++)
*(vu32 *)0x10400484 = 0x10101 * i;
// Bottom screen
*(vu32 *)0x10400500 = 0x000001c2;
*(vu32 *)0x10400504 = 0x000000d1;
*(vu32 *)0x10400508 = 0x000001c1;
*(vu32 *)0x1040050c = 0x000001c1;
*(vu32 *)0x10400510 = 0x000000cd;
*(vu32 *)0x10400514 = 0x000000cf;
*(vu32 *)0x10400518 = 0x000000d1;
*(vu32 *)0x1040051c = 0x01c501c1;
*(vu32 *)0x10400520 = 0x00010000;
*(vu32 *)0x10400524 = 0x0000019d;
*(vu32 *)0x10400528 = 0x00000052;
*(vu32 *)0x1040052c = 0x00000192;
*(vu32 *)0x10400530 = 0x00000192;
*(vu32 *)0x10400534 = 0x0000004f;
*(vu32 *)0x10400538 = 0x00000050;
*(vu32 *)0x1040053c = 0x00000052;
*(vu32 *)0x10400540 = 0x01980194;
*(vu32 *)0x10400544 = 0x00000000;
*(vu32 *)0x10400548 = 0x00000011;
*(vu32 *)0x1040055C = 0x00f00140;
*(vu32 *)0x10400560 = 0x01c100d1;
*(vu32 *)0x10400564 = 0x01920052;
*(vu32 *)0x10400568 = 0x18300000 + 0x46500;
*(vu32 *)0x10400570 = 0x80301;
*(vu32 *)0x10400574 = 0x00010501;
*(vu32 *)0x10400578 = 0;
*(vu32 *)0x10400590 = 0x000002D0;
*(vu32 *)0x1040059C = 0x00000000;
// Disco register
for(u32 i = 0; i < 256; i++)
*(vu32 *)0x10400584 = 0x10101 * i;
*(vu32 *)0x10400468 = 0x18300000;
*(vu32 *)0x1040046c = 0x18300000;
*(vu32 *)0x10400494 = 0x18300000;
*(vu32 *)0x10400498 = 0x18300000;
*(vu32 *)0x10400568 = 0x18346500;
*(vu32 *)0x1040056c = 0x18346500;
//Set CakeBrah framebuffers
*((vu32 *)0x23FFFE00) = 0x18300000;
*((vu32 *)0x23FFFE04) = 0x18300000;
*((vu32 *)0x23FFFE08) = 0x18346500;
//Clear ARM11 entry offset
*arm11 = 0;
//Wait for the entry to be set
while(!*arm11);
//Jump to it
((void (*)())*arm11)();
}

View File

@@ -0,0 +1,8 @@
.section .text.start
.align 4
.global _start
_start:
@ Disable interrupts
CPSID aif
b main

19
screeninit/source/types.h Executable file
View File

@@ -0,0 +1,19 @@
/*
* types.h
* by Reisyukaku
* Copyright (c) 2015 All Rights Reserved
*/
#pragma once
#include <stdint.h>
//Common data types
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef volatile u8 vu8;
typedef volatile u16 vu16;
typedef volatile u32 vu32;
typedef volatile u64 vu64;

12
screeninit/stub.ld Executable file
View File

@@ -0,0 +1,12 @@
ENTRY(_start)
SECTIONS
{
. = 0x24F03000;
.text.start : { *(.text.start) }
.text : { *(.text) }
.data : { *(.data) }
.bss : { *(.bss COMMON) }
.rodata : { *(.rodata) }
. = ALIGN(4);
}

5
screeninit/stub.specs Executable file
View File

@@ -0,0 +1,5 @@
%rename link old_link
*link:
%(old_link) -T ../stub.ld%s

View File

@@ -8,19 +8,22 @@
#include "types.h" #include "types.h"
#define HID_PAD (*(vu16 *)0x10146000 ^ 0xFFF) #define HID_PAD (*(vu32 *)0x10146000 ^ 0xFFF)
#define BUTTON_R1 (1 << 8) #define BUTTON_R1 (1 << 8)
#define BUTTON_L1 (1 << 9) #define BUTTON_L1 (1 << 9)
#define BUTTON_A 1 #define BUTTON_A 1
#define BUTTON_B (1 << 1) #define BUTTON_B (1 << 1)
#define BUTTON_X (1 << 10)
#define BUTTON_Y (1 << 11)
#define BUTTON_SELECT (1 << 2) #define BUTTON_SELECT (1 << 2)
#define BUTTON_START (1 << 3) #define BUTTON_START (1 << 3)
#define BUTTON_RIGHT (1 << 4) #define BUTTON_RIGHT (1 << 4)
#define BUTTON_LEFT (1 << 5) #define BUTTON_LEFT (1 << 5)
#define BUTTON_UP (1 << 6) #define BUTTON_UP (1 << 6)
#define BUTTON_DOWN (1 << 7) #define BUTTON_DOWN (1 << 7)
#define BUTTON_L1R1 ((1 << 8) | (1 << 9)) #define BUTTON_L1R1 (BUTTON_R1 | BUTTON_L1)
#define SAFE_MODE (BUTTON_L1R1 | BUTTON_A | BUTTON_UP) #define SAFE_MODE (BUTTON_L1R1 | BUTTON_A | BUTTON_UP)
#define OPTION_BUTTONS (BUTTON_L1R1 | BUTTON_A) #define OVERRIDE_BUTTONS (BUTTON_B ^ 0xFFF)
#define PAYLOAD_BUTTONS ((BUTTON_L1 | BUTTON_A) ^ 0xFFF) #define SINGLE_PAYLOAD_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN | BUTTON_START | BUTTON_X | BUTTON_Y)
#define L_PAYLOAD_BUTTONS (BUTTON_R1 | BUTTON_SELECT)
#define MENU_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN | BUTTON_A | BUTTON_START) #define MENU_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN | BUTTON_A | BUTTON_START)

View File

@@ -239,14 +239,16 @@ static const u8 key2[0x10] = {
}; };
//Get Nand CTR key //Get Nand CTR key
static void getNandCTR(u8 *buf, u32 console){ static void getNandCTR(u8 *buf, u32 console)
{
u8 *addr = (console ? (u8 *)0x080D8BBC : (u8 *)0x080D797C) + 0x0F; u8 *addr = (console ? (u8 *)0x080D8BBC : (u8 *)0x080D797C) + 0x0F;
for(u8 keyLen = 0x10; keyLen; keyLen--) for(u8 keyLen = 0x10; keyLen; keyLen--)
*(buf++) = *(addr--); *(buf++) = *(addr--);
} }
//Read firm0 from NAND and write to buffer //Read firm0 from NAND and write to buffer
void nandFirm0(u8 *outbuf, u32 size, u32 console){ void nandFirm0(u8 *outbuf, u32 size, u32 console)
{
u8 CTR[0x10]; u8 CTR[0x10];
getNandCTR(CTR, console); getNandCTR(CTR, console);
@@ -258,8 +260,8 @@ void nandFirm0(u8 *outbuf, u32 size, u32 console){
} }
//Decrypts the N3DS arm9bin //Decrypts the N3DS arm9bin
void decryptArm9Bin(u8 *arm9Section, u32 mode){ void decryptArm9Bin(u8 *arm9Section, u32 mode)
{
//Firm keys //Firm keys
u8 keyY[0x10]; u8 keyY[0x10];
u8 CTR[0x10]; u8 CTR[0x10];
@@ -268,12 +270,15 @@ void decryptArm9Bin(u8 *arm9Section, u32 mode){
//Setup keys needed for arm9bin decryption //Setup keys needed for arm9bin decryption
memcpy(keyY, arm9Section + 0x10, 0x10); memcpy(keyY, arm9Section + 0x10, 0x10);
memcpy(CTR, arm9Section + 0x20, 0x10); memcpy(CTR, arm9Section + 0x20, 0x10);
//Calculate the size of the ARM9 binary
u32 size = 0; u32 size = 0;
//http://stackoverflow.com/questions/12791077/atoi-implementation-in-c //http://stackoverflow.com/questions/12791077/atoi-implementation-in-c
for(u8 *tmp = arm9Section + 0x30; *tmp; tmp++) for(u8 *tmp = arm9Section + 0x30; *tmp; tmp++)
size = (size << 3) + (size << 1) + (*tmp) - '0'; size = (size << 3) + (size << 1) + (*tmp) - '0';
if(mode){ if(mode)
{
u8 keyX[0x10]; u8 keyX[0x10];
//Set 0x11 to key2 for the arm9bin and misc keys //Set 0x11 to key2 for the arm9bin and misc keys
@@ -292,15 +297,16 @@ void decryptArm9Bin(u8 *arm9Section, u32 mode){
} }
//Sets the N3DS 9.6 KeyXs //Sets the N3DS 9.6 KeyXs
void setKeyXs(u8 *arm9Section){ void setKeyXs(u8 *arm9Section)
{
u8 *keyData = arm9Section + 0x89814; u8 *keyData = arm9Section + 0x89814;
u8 *decKey = keyData + 0x10; u8 *decKey = keyData + 0x10;
//Set keys 0x19..0x1F keyXs //Set keys 0x19..0x1F keyXs
aes_setkey(0x11, key2, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL); aes_setkey(0x11, key2, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_use_keyslot(0x11); aes_use_keyslot(0x11);
for(u8 slot = 0x19; slot < 0x20; slot++){ for(u8 slot = 0x19; slot < 0x20; slot++)
{
aes(decKey, keyData, 1, NULL, AES_ECB_DECRYPT_MODE, 0); aes(decKey, keyData, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
aes_setkey(slot, decKey, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL); aes_setkey(slot, decKey, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
*(keyData + 0xF) += 1; *(keyData + 0xF) += 1;

View File

@@ -20,38 +20,47 @@ static const struct fb {
u8 *bottom; u8 *bottom;
} *const fb = (struct fb *)0x23FFFE00; } *const fb = (struct fb *)0x23FFFE00;
static int strlen(const char *string){ static inline int strlen(const char *string)
{
char *stringEnd = (char *)string; char *stringEnd = (char *)string;
while(*stringEnd) stringEnd++; while(*stringEnd) stringEnd++;
return stringEnd - string; return stringEnd - string;
} }
void clearScreens(void){ void clearScreens(void)
{
memset32(fb->top_left, 0, 0x46500); memset32(fb->top_left, 0, 0x46500);
memset32(fb->top_right, 0, 0x46500); memset32(fb->top_right, 0, 0x46500);
memset32(fb->bottom, 0, 0x38400); memset32(fb->bottom, 0, 0x38400);
} }
void loadSplash(void){ void loadSplash(void)
{
clearScreens(); clearScreens();
//Don't delay boot if no splash image is on the SD //Don't delay boot if no splash image is on the SD
if(fileRead(fb->top_left, "/aurei/splash.bin", 0x46500) + if(fileRead(fb->top_left, "/aurei/splash.bin", 0x46500) +
fileRead(fb->bottom, "/aurei/splashbottom.bin", 0x38400)){ fileRead(fb->bottom, "/aurei/splashbottom.bin", 0x38400))
u64 i = 0x1300000; while(--i) __asm("mov r0, r0"); //Less Ghetto sleep func {
u64 i = 0x1300000;
while(--i) __asm("mov r0, r0"); //Less Ghetto sleep func
} }
} }
void drawCharacter(char character, int posX, int posY, u32 color){ void drawCharacter(char character, int posX, int posY, u32 color)
{
u8 *const select = fb->top_left; u8 *const select = fb->top_left;
for(int y = 0; y < 8; y++){ for(int y = 0; y < 8; y++)
{
char charPos = font[character * 8 + y]; char charPos = font[character * 8 + y];
for(int x = 7; x >= 0; x--){ for(int x = 7; x >= 0; x--)
{
int screenPos = (posX * SCREEN_TOP_HEIGHT * 3 + (SCREEN_TOP_HEIGHT - y - posY - 1) * 3) + (7 - x) * 3 * SCREEN_TOP_HEIGHT; int screenPos = (posX * SCREEN_TOP_HEIGHT * 3 + (SCREEN_TOP_HEIGHT - y - posY - 1) * 3) + (7 - x) * 3 * SCREEN_TOP_HEIGHT;
if ((charPos >> x) & 1) { if ((charPos >> x) & 1)
{
select[screenPos] = color >> 16; select[screenPos] = color >> 16;
select[screenPos + 1] = color >> 8; select[screenPos + 1] = color >> 8;
select[screenPos + 2] = color; select[screenPos + 2] = color;
@@ -60,15 +69,20 @@ void drawCharacter(char character, int posX, int posY, u32 color){
} }
} }
int drawString(const char *string, int posX, int posY, u32 color){ int drawString(const char *string, int posX, int posY, u32 color)
{
int length = strlen(string); int length = strlen(string);
for(int i = 0, line_i = 0; i < length; i++, line_i++){ for(int i = 0, line_i = 0; i < length; i++, line_i++)
if(string[i] == '\n'){ {
if(string[i] == '\n')
{
posY += SPACING_Y; posY += SPACING_Y;
line_i = 0; line_i = 0;
i++; i++;
} else if(line_i >= (SCREEN_TOP_WIDTH - posX) / SPACING_X){ }
else if(line_i >= (SCREEN_TOP_WIDTH - posX) / SPACING_X)
{
// Make sure we never get out of the screen. // Make sure we never get out of the screen.
posY += SPACING_Y; posY += SPACING_Y;
line_i = 2; // Little offset so we know the same string continues. line_i = 2; // Little offset so we know the same string continues.

View File

@@ -8,32 +8,49 @@
#include "memory.h" #include "memory.h"
#include "fatfs/sdmmc/sdmmc.h" #include "fatfs/sdmmc/sdmmc.h"
void getEmunandSect(u32 *off, u32 *head, u32 emuNAND){ u32 getEmunandSect(u32 *off, u32 *head, u32 *emuNAND)
{
u8 *const temp = (u8 *)0x24300000; u8 *const temp = (u8 *)0x24300000;
u32 nandSize = getMMCDevice(0)->total_size; const u32 nandSize = getMMCDevice(0)->total_size;
u32 nandOffset = emuNAND == 1 ? 0 : u32 nandOffset = *emuNAND == 1 ? 0 :
(nandSize > 0x200000 ? 0x400000 : 0x200000); (nandSize > 0x200000 ? 0x400000 : 0x200000);
//Check for RedNAND //Check for RedNAND
if(sdmmc_sdcard_readsectors(nandOffset + 1, 1, temp) == 0){ if(sdmmc_sdcard_readsectors(nandOffset + 1, 1, temp) == 0)
if(*(u32 *)(temp + 0x100) == NCSD_MAGIC){ {
if(*(u32 *)(temp + 0x100) == NCSD_MAGIC)
{
*off = nandOffset + 1; *off = nandOffset + 1;
*head = nandOffset + 1; *head = nandOffset + 1;
} }
//Check for Gateway emuNAND //Check for Gateway emuNAND
else if(sdmmc_sdcard_readsectors(nandOffset + nandSize, 1, temp) == 0){ else if(sdmmc_sdcard_readsectors(nandOffset + nandSize, 1, temp) == 0)
if(*(u32 *)(temp + 0x100) == NCSD_MAGIC){ {
if(*(u32 *)(temp + 0x100) == NCSD_MAGIC)
{
*off = nandOffset; *off = nandOffset;
*head = nandOffset + nandSize; *head = nandOffset + nandSize;
} }
//Fallback to the first emuNAND if there's no second one
else if(emuNAND == 2) getEmunandSect(off, head, 1); /* Fallback to the first emuNAND if there's no second one,
or to SysNAND if there isn't any */
else
{
(*emuNAND)--;
if(*emuNAND) getEmunandSect(off, head, emuNAND);
return 0;
} }
} }
} }
u32 getSDMMC(u8 *pos, u32 size){ return 1;
}
u32 getSDMMC(u8 *pos, u32 size)
{
//Look for struct code //Look for struct code
const u8 pattern[] = {0x21, 0x20, 0x18, 0x20}; const u8 pattern[] = {0x21, 0x20, 0x18, 0x20};
const u8 *off = memsearch(pos, pattern, size, 4) - 1; const u8 *off = memsearch(pos, pattern, size, 4) - 1;
@@ -41,7 +58,8 @@ u32 getSDMMC(u8 *pos, u32 size){
return *(u32 *)(off + 0x0A) + *(u32 *)(off + 0x0E); return *(u32 *)(off + 0x0A) + *(u32 *)(off + 0x0E);
} }
void getEmuRW(u8 *pos, u32 size, u32 *readOff, u32 *writeOff){ void getEmuRW(u8 *pos, u32 size, u32 *readOff, u32 *writeOff)
{
//Look for read/write code //Look for read/write code
const u8 pattern[] = {0x1E, 0x00, 0xC8, 0x05}; const u8 pattern[] = {0x1E, 0x00, 0xC8, 0x05};
@@ -49,14 +67,16 @@ void getEmuRW(u8 *pos, u32 size, u32 *readOff, u32 *writeOff){
*writeOff = (u32)memsearch((u8 *)(*readOff + 0xA), pattern, 0x100, 4) - 6; *writeOff = (u32)memsearch((u8 *)(*readOff + 0xA), pattern, 0x100, 4) - 6;
} }
u32 *getMPU(u8 *pos, u32 size){ u32 *getMPU(u8 *pos, u32 size)
{
//Look for MPU pattern //Look for MPU pattern
const u8 pattern[] = {0x03, 0x00, 0x24, 0x00}; const u8 pattern[] = {0x03, 0x00, 0x24, 0x00};
return (u32 *)memsearch(pos, pattern, size, 4); return (u32 *)memsearch(pos, pattern, size, 4);
} }
void *getEmuCode(u8 *proc9Offset){ void *getEmuCode(u8 *proc9Offset)
{
const u8 pattern[] = {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}; const u8 pattern[] = {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00};
//Looking for the last free space before Process9 //Looking for the last free space before Process9

View File

@@ -10,7 +10,7 @@
#define NCSD_MAGIC (0x4453434E) #define NCSD_MAGIC (0x4453434E)
void getEmunandSect(u32 *off, u32 *head, u32 emuNAND); u32 getEmunandSect(u32 *off, u32 *head, u32 *emuNAND);
u32 getSDMMC(u8 *pos, u32 size); u32 getSDMMC(u8 *pos, u32 size);
void getEmuRW(u8 *pos, u32 size, u32 *readOff, u32 *writeOff); void getEmuRW(u8 *pos, u32 size, u32 *readOff, u32 *writeOff);
u32 *getMPU(u8 *pos, u32 size); u32 *getMPU(u8 *pos, u32 size);

View File

@@ -18,7 +18,7 @@
#include "../build/patches.h" #include "../build/patches.h"
//FIRM patches version //FIRM patches version
#define PATCH_VER 2 #define PATCH_VER 4
static firmHeader *const firm = (firmHeader *)0x24000000; static firmHeader *const firm = (firmHeader *)0x24000000;
static const firmSectionHeader *section; static const firmSectionHeader *section;
@@ -26,130 +26,186 @@ static u8 *arm9Section;
static const char *patchedFirms[] = { "/aurei/patched_firmware_sys.bin", static const char *patchedFirms[] = { "/aurei/patched_firmware_sys.bin",
"/aurei/patched_firmware_emu.bin", "/aurei/patched_firmware_emu.bin",
"/aurei/patched_firmware_em2.bin", "/aurei/patched_firmware_em2.bin",
"/aurei/patched_firmware90.bin" }; "/aurei/patched_firmware90.bin",
"/aurei/patched_firmware_twl.bin",
"/aurei/patched_firmware_agb.bin" };
static u32 firmSize, static u32 firmSize,
console, console,
mode, mode,
emuNAND, emuNAND,
a9lhSetup, a9lhSetup,
selectedFirm, selectedFirm,
usePatchedFirm; usePatchedFirm,
emuOffset,
void setupCFW(void){ emuHeader;
u32 config;
void setupCFW(void)
{
//Determine if booting with A9LH //Determine if booting with A9LH
u32 a9lhBoot = (PDN_SPI_CNT == 0x0) ? 1 : 0; u32 a9lhBoot = !PDN_SPI_CNT ? 1 : 0;
//Retrieve the last booted FIRM //Retrieve the last booted FIRM
u8 previousFirm = CFG_BOOTENV; u32 previousFirm = CFG_BOOTENV;
//Detect the console being used //Detect the console being used
console = (PDN_MPCORE_CFG == 1) ? 0 : 1; console = (PDN_MPCORE_CFG == 1) ? 0 : 1;
//Get pressed buttons //Get pressed buttons
u16 pressed = HID_PAD; u32 pressed = HID_PAD;
//Attempt to read the configuration file //Attempt to read the configuration file
const char configPath[] = "aurei/config.bin"; const char configPath[] = "/aurei/config.bin";
u32 config = 0; u32 needConfig;
u32 needConfig = fileRead(&config, configPath, 3) ? 1 : 2; if(fileRead(&config, configPath, 3)) needConfig = 1;
else
{
config = 0;
needConfig = 2;
}
//Determine if A9LH is installed and the user has an updated sysNAND //Determine if A9LH is installed and the user has an updated sysNAND
u32 updatedSys; u32 updatedSys;
if(a9lhBoot || (config >> 2) & 0x1){ if(a9lhBoot || (config >> 2) & 1)
{
if(pressed == SAFE_MODE) if(pressed == SAFE_MODE)
error("Using Safe Mode would brick you, or remove A9LH!"); error("Using Safe Mode would brick you, or remove A9LH!");
a9lhSetup = 1; a9lhSetup = 1;
//Check setting for > 9.2 sysNAND //Check setting for > 9.2 sysNAND
updatedSys = config & 0x1; updatedSys = config & 1;
} else{ }
else
{
a9lhSetup = 0; a9lhSetup = 0;
updatedSys = 0; updatedSys = 0;
} }
u32 tempConfig = (PATCH_VER << 17) | (a9lhSetup << 16);
/* If booting with A9LH, it's a MCU reboot and a previous configuration exists, /* If booting with A9LH, it's a MCU reboot and a previous configuration exists,
try to force boot options */ try to force boot options */
if(a9lhBoot && previousFirm && needConfig == 1){ if(a9lhBoot && previousFirm && needConfig == 1)
{
//Always force a sysNAND boot when quitting AGB_FIRM //Always force a sysNAND boot when quitting AGB_FIRM
if(previousFirm == 0x7){ if(previousFirm == 7)
if(!updatedSys) mode = (config >> 12) & 0x1; {
mode = updatedSys ? 1 : (config >> 12) & 1;
emuNAND = 0; emuNAND = 0;
needConfig = 0; needConfig = 0;
//Else, force the last used boot options unless A, L or R are pressed
} else if(!(pressed & OPTION_BUTTONS)){ //Flag to prevent multiple boot options-forcing
mode = (config >> 12) & 0x1; tempConfig |= 1 << 15;
emuNAND = (config >> 13) & 0x3; }
/* Else, force the last used boot options unless a payload button or A/L/R are pressed
or the no-forcing flag is set */
else if(!(pressed & OVERRIDE_BUTTONS) && !((config >> 15) & 1))
{
mode = (config >> 12) & 1;
emuNAND = (config >> 13) & 3;
needConfig = 0; needConfig = 0;
} }
} }
if(needConfig){ //Boot options aren't being forced
if(needConfig)
/* If L and one of the payload buttons are pressed, and if not using A9LH {
/* If L and R/Select or one of the single payload buttons are pressed and, if not using A9LH,
the Safe Mode combo is not pressed, chainload an external payload */ the Safe Mode combo is not pressed, chainload an external payload */
if((pressed & BUTTON_L1) && (pressed & PAYLOAD_BUTTONS) && if(((pressed & SINGLE_PAYLOAD_BUTTONS) || ((pressed & BUTTON_L1) && (pressed & L_PAYLOAD_BUTTONS)))
pressed != SAFE_MODE) loadPayload(); && pressed != SAFE_MODE)
loadPayload();
//If no configuration file exists or SELECT is held, load configuration menu //If no configuration file exists or SELECT is held, load configuration menu
if(needConfig == 2 || (pressed & BUTTON_SELECT)) if(needConfig == 2 || (pressed & BUTTON_SELECT))
configureCFW(configPath, patchedFirms[3]); configureCFW(configPath, patchedFirms);
//If screens are inited, load splash screen //If screens are inited, load splash screen
if(PDN_GPU_CNT != 0x1) loadSplash(); if(PDN_GPU_CNT != 1) loadSplash();
/* If L is pressed, boot 9.0 FIRM */ /* If L is pressed, or L or R are not pressed when it is the default FIRM,
mode = ((config >> 3) & 0x1) ? ((!(pressed & BUTTON_L1R1)) ? 0 : 1) : boot 9.0 FIRM */
mode = ((config >> 3) & 1) ? ((!(pressed & BUTTON_L1R1)) ? 0 : 1) :
((pressed & BUTTON_L1) ? 0 : 1); ((pressed & BUTTON_L1) ? 0 : 1);
/* If L or R aren't pressed on a 9.0/9.2 sysNAND, or the 9.0 FIRM is selected /* If L or R aren't pressed on a 9.0/9.2 sysNAND, or the 9.0 FIRM is selected
or R is pressed on a > 9.2 sysNAND, boot emuNAND */ or R is pressed on a > 9.2 sysNAND, boot emuNAND */
if((updatedSys && (!mode || (pressed & BUTTON_R1))) || if((updatedSys && (!mode || (pressed & BUTTON_R1))) || (!updatedSys && mode && !(pressed & BUTTON_R1)))
(!updatedSys && mode && !(pressed & BUTTON_R1))){ {
//If not 9.0 FIRM and B is pressed, attempt booting the second emuNAND /* If not 9.0 FIRM and the second emuNAND is set as default and B isn't pressed, or vice-versa,
emuNAND = (mode && ((!(pressed & BUTTON_B)) == ((config >> 4) & 0x1))) ? 2 : 1; attempt to boot it */
} else emuNAND = 0; emuNAND = (mode && ((!(pressed & BUTTON_B)) == ((config >> 4) & 1))) ? 2 : 1;
}
u32 tempConfig = (PATCH_VER << 17) | (a9lhSetup << 16) | (emuNAND << 13) | (mode << 12); else emuNAND = 0;
/* If tha FIRM patches version is different or user switched to/from A9LH, /* If tha FIRM patches version is different or user switched to/from A9LH,
delete all patched FIRMs */ delete all patched FIRMs */
if((tempConfig & 0xFF0000) != (config & 0xFF0000)) if((tempConfig & 0xFF0000) != (config & 0xFF0000))
deleteFirms(patchedFirms, sizeof(patchedFirms) / sizeof(char *)); deleteFirms(patchedFirms, sizeof(patchedFirms) / sizeof(char *));
}
u32 usePatchedFirmSet = ((config >> 1) & 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) :
(usePatchedFirmSet ? 4 : 0);
//If "Use pre-patched FIRMs" is set and the appropriate FIRM exists, use it
if(usePatchedFirmSet && fileExists(patchedFirms[selectedFirm - 1]))
usePatchedFirm = 1;
/* If the user is booting EmuNAND but the chosen one is not found,
force 9.6/10.x FIRM and re-detect the patched FIRMs */
else if(emuNAND && !getEmunandSect(&emuOffset, &emuHeader, &emuNAND))
{
mode = 1;
continue;
}
break;
}
tempConfig |= (emuNAND << 13) | (mode << 12);
//If the boot configuration is different from previously, overwrite it //If the boot configuration is different from previously, overwrite it
if((tempConfig & 0xFFF000) != (config & 0xFFF000)){ if(tempConfig != (config & 0xFFF000))
{
//Preserve user settings (first 12 bits) //Preserve user settings (first 12 bits)
tempConfig |= config & 0xFFF; tempConfig |= config & 0xFFF;
fileWrite(&tempConfig, configPath, 3); fileWrite(&tempConfig, configPath, 3);
} }
} }
/* 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) :
(((config >> 1) & 0x1) ? 4 : 0);
//If "Use pre-patched FIRMs" is set and the appropriate FIRM exists, use it
usePatchedFirm = (((config >> 1) & 0x1) && fileExists(patchedFirms[selectedFirm - 1])) ? 1 : 0;
}
//Load FIRM into FCRAM //Load FIRM into FCRAM
void loadFirm(void){ void loadFirm(void)
{
//If not using an A9LH setup or the patched FIRM, load 9.0 FIRM from NAND //If not using an A9LH setup or the patched FIRM, load 9.0 FIRM from NAND
if(!usePatchedFirm && !a9lhSetup && !mode){ if(!usePatchedFirm && !a9lhSetup && !mode)
{
//Read FIRM from NAND and write to FCRAM //Read FIRM from NAND and write to FCRAM
firmSize = console ? 0xF2000 : 0xE9000; firmSize = console ? 0xF2000 : 0xE9000;
nandFirm0((u8 *)firm, firmSize, console); nandFirm0((u8 *)firm, firmSize, console);
//Check for correct decryption //Check for correct decryption
if(memcmp(firm, "FIRM", 4) != 0) if(memcmp(firm, "FIRM", 4) != 0)
error("Couldn't decrypt NAND FIRM0 (O3DS not on 9.x?)"); error("Couldn't decrypt NAND FIRM0 (O3DS not on 9.x?)");
} }
//Load FIRM from SD //Load FIRM from SD
else{ else
{
const char *path = usePatchedFirm ? patchedFirms[selectedFirm - 1] : const char *path = usePatchedFirm ? patchedFirms[selectedFirm - 1] :
(mode ? "/aurei/firmware.bin" : "/aurei/firmware90.bin"); (mode ? "/aurei/firmware.bin" : "/aurei/firmware90.bin");
firmSize = fileSize(path); firmSize = fileSize(path);
if(!firmSize) error("aurei/firmware(90).bin doesn't exist"); if(!firmSize) error(mode ? "aurei/firmware.bin doesn't exist" :
"aurei/firmware90.bin doesn't exist");
fileRead(firm, path, firmSize); fileRead(firm, path, firmSize);
} }
@@ -157,27 +213,99 @@ void loadFirm(void){
//Check that the loaded FIRM matches the console //Check that the loaded FIRM matches the console
if((((u32)section[2].address >> 8) & 0xFF) != (console ? 0x60 : 0x68)) if((((u32)section[2].address >> 8) & 0xFF) != (console ? 0x60 : 0x68))
error("aurei/firmware(90).bin doesn't match this\nconsole, or it's encrypted"); error(mode ? "aurei/firmware.bin doesn't match this console,\nor it's encrypted" :
"aurei/firmware90.bin doesn't match this console,\nor it's encrypted");
arm9Section = (u8 *)firm + section[2].offset; arm9Section = (u8 *)firm + section[2].offset;
if(console && !usePatchedFirm) decryptArm9Bin(arm9Section, mode); //On N3DS, decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
if(console && !usePatchedFirm)
{
decryptArm9Bin(arm9Section, mode);
firm->arm9Entry = (u8 *)0x801B01C;
}
}
static inline void patchTwlAgb(u32 whichFirm)
{
static firmHeader *const twlAgbFirm = (firmHeader *)0x25000000;
const char *path = whichFirm ? "/aurei/firmware_agb.bin" : "/aurei/firmware_twl.bin";
u32 size = fileSize(path);
//Skip patching if the file doesn't exist
if(!size) return;
fileRead(twlAgbFirm, path, size);
static const firmSectionHeader *twlAgbSection = twlAgbFirm->section;
//Check that the loaded FIRM matches the console
if((((u32)twlAgbSection[3].address >> 8) & 0xFF) != (console ? 0x60 : 0x68))
error(whichFirm ? "aurei/firmware_agb.bin doesn't match this\nconsole, or it's encrypted" :
"aurei/firmware_twl.bin doesn't match this\nconsole, or it's encrypted");
//On N3DS, decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
if(console)
{
decryptArm9Bin((u8 *)twlAgbFirm + twlAgbSection[3].offset, 0);
twlAgbFirm->arm9Entry = (u8 *)0x801301C;
}
struct patchData {
u32 offset[2];
union {
u8 type0[8];
u16 type1;
} patch;
u32 type;
};
static const struct patchData twlPatches[] = {
{{0x1650C0, 0x165D64}, {{ 6, 0x00, 0x20, 0x4E, 0xB0, 0x70, 0xBD }}, 0},
{{0x173A0E, 0x17474A}, { .type1 = 0x2001 }, 1},
{{0x174802, 0x17553E}, { .type1 = 0x2000 }, 2},
{{0x174964, 0x1756A0}, { .type1 = 0x2000 }, 2},
{{0x174D52, 0x175A8E}, { .type1 = 0x2001 }, 2},
{{0x174D5E, 0x175A9A}, { .type1 = 0x2001 }, 2},
{{0x174D6A, 0x175AA6}, { .type1 = 0x2001 }, 2},
{{0x174E56, 0x175B92}, { .type1 = 0x2001 }, 1},
{{0x174E58, 0x175B94}, { .type1 = 0x4770 }, 1}
};
static const struct patchData agbPatches[] = {
{{0x9D2A8, 0x9DF64}, {{ 6, 0x00, 0x20, 0x4E, 0xB0, 0x70, 0xBD }}, 0},
{{0xD7A12, 0xD8B8A}, { .type1 = 0xEF26 }, 1}
};
/* Calculate the amount of patches to apply. Only count the boot screen patch for AGB_FIRM
if the matching option was enabled (keep it as last) */
u32 numPatches = whichFirm ? (sizeof(agbPatches) / sizeof(struct patchData)) - !((config >> 6) & 1) :
(sizeof(twlPatches) / sizeof(struct patchData));
const struct patchData *patches = whichFirm ? agbPatches : twlPatches;
//Patch
for(u32 i = 0; i < numPatches; i++)
{
switch(patches[i].type)
{
case 0:
memcpy((u8 *)twlAgbFirm + patches[i].offset[console], patches[i].patch.type0 + 1, patches[i].patch.type0[0]);
break;
case 2:
*(u16 *)((u8 *)twlAgbFirm + patches[i].offset[console] + 2) = 0;
case 1:
*(u16 *)((u8 *)twlAgbFirm + patches[i].offset[console]) = patches[i].patch.type1;
break;
}
}
fileWrite(twlAgbFirm, whichFirm ? patchedFirms[5] : patchedFirms[4], size);
} }
//NAND redirection //NAND redirection
static void loadEmu(u8 *proc9Offset){ static inline void patchEmuNAND(u8 *proc9Offset)
{
u32 emuOffset,
emuHeader = 0,
emuRead,
emuWrite;
//Look for emuNAND
getEmunandSect(&emuOffset, &emuHeader, emuNAND);
//No emuNAND detected
if(!emuHeader) error("No emuNAND has been detected");
//Copy emuNAND code //Copy emuNAND code
void *emuCodeOffset = getEmuCode(proc9Offset); void *emuCodeOffset = getEmuCode(proc9Offset);
memcpy(emuCodeOffset, emunand, emunand_size); memcpy(emuCodeOffset, emunand, emunand_size);
@@ -197,6 +325,9 @@ static void loadEmu(u8 *proc9Offset){
section[2].offset + (u32)section[2].address; section[2].offset + (u32)section[2].address;
//Add emunand hooks //Add emunand hooks
u32 emuRead,
emuWrite;
getEmuRW(arm9Section, section[2].size, &emuRead, &emuWrite); getEmuRW(arm9Section, section[2].size, &emuRead, &emuWrite);
*(u16 *)emuRead = nandRedir[0]; *(u16 *)emuRead = nandRedir[0];
*((u16 *)emuRead + 1) = nandRedir[1]; *((u16 *)emuRead + 1) = nandRedir[1];
@@ -212,23 +343,11 @@ static void loadEmu(u8 *proc9Offset){
*(mpuOffset + 9) = mpuPatch[2]; *(mpuOffset + 9) = mpuPatch[2];
} }
//Patches static inline void patchReboots(u8 *proc9Offset)
void patchFirm(void){ {
//Skip patching
if(usePatchedFirm) return;
if(mode || emuNAND){
//Find the Process9 NCCH location
u8 *proc9Offset = getProc9(arm9Section, section[2].size);
//Apply emuNAND patches
if(emuNAND) loadEmu(proc9Offset);
//Patch FIRM reboots, not on 9.0 FIRM as it breaks firmlaunchhax
if(mode){
//Calculate offset for the firmlaunch code //Calculate offset for the firmlaunch code
void *rebootOffset = getReboot(arm9Section, section[2].size); void *rebootOffset = getReboot(arm9Section, section[2].size);
//Calculate offset for the fOpen function //Calculate offset for the fOpen function
u32 fOpenOffset = getfOpen(proc9Offset, rebootOffset); u32 fOpenOffset = getfOpen(proc9Offset, rebootOffset);
@@ -240,21 +359,66 @@ void patchFirm(void){
*pos_fopen = fOpenOffset; *pos_fopen = fOpenOffset;
//Patch path for emuNAND-patched FIRM //Patch path for emuNAND-patched FIRM
if(emuNAND){ if(emuNAND)
{
void *pos_path = memsearch(rebootOffset, L"sy", reboot_size, 4); void *pos_path = memsearch(rebootOffset, L"sy", reboot_size, 4);
memcpy(pos_path, emuNAND == 1 ? L"emu" : L"em2", 5); memcpy(pos_path, emuNAND == 1 ? L"emu" : L"em2", 5);
} }
} }
static inline void injectLoader(void)
{
u32 loaderOffset,
loaderSize;
getLoader((u8 *)firm + section[0].offset, section[0].size, &loaderOffset, &loaderSize);
//Check that the injector CXI isn't larger than the original
if(injector_size <= (int)loaderSize)
{
memset((void *)loaderOffset, 0, loaderSize);
memcpy((void *)loaderOffset, injector, injector_size);
//Patch content size and ExeFS size to match the repaced loader's ones
*((u32 *)loaderOffset + 0x41) = loaderSize / 0x200;
*((u32 *)loaderOffset + 0x69) = loaderSize / 0x200 - 5;
}
} }
if(a9lhSetup && !emuNAND){ //Patches
//Patch FIRM partitions writes on sysNAND to protect A9LH void patchFirm(void)
{
if(mode)
{
//Only patch AGB_FIRM/TWL_FIRM if the patched ones don't already exist
if(!fileExists(patchedFirms[4])) patchTwlAgb(0);
if(!fileExists(patchedFirms[5])) patchTwlAgb(1);
}
//Skip patching
if(usePatchedFirm) return;
if(mode || emuNAND)
{
//Find the Process9 NCCH location
u8 *proc9Offset = getProc9(arm9Section, section[2].size);
//Apply emuNAND patches
if(emuNAND) patchEmuNAND(proc9Offset);
//Apply FIRM reboot patches, not on 9.0 FIRM as it breaks firmlaunchhax
if(mode) patchReboots(proc9Offset);
}
//Apply FIRM0/1 writes patches on sysNAND to protect A9LH
if(a9lhSetup && !emuNAND)
{
u16 *writeOffset = getFirmWrite(arm9Section, section[2].size); u16 *writeOffset = getFirmWrite(arm9Section, section[2].size);
*writeOffset = writeBlock[0]; *writeOffset = writeBlock[0];
*(writeOffset + 1) = writeBlock[1]; *(writeOffset + 1) = writeBlock[1];
} }
//Disable signature checks //Apply signature checks patches
u32 sigOffset, u32 sigOffset,
sigOffset2; sigOffset2;
@@ -264,20 +428,7 @@ void patchFirm(void){
*((u16 *)sigOffset2 + 1) = sigPatch[1]; *((u16 *)sigOffset2 + 1) = sigPatch[1];
//Replace the FIRM loader with the injector //Replace the FIRM loader with the injector
u32 loaderOffset, injectLoader();
loaderSize;
getLoader((u8 *)firm + section[0].offset, section[0].size, &loaderOffset, &loaderSize);
if(injector_size <= (int)loaderSize){
memset((void *)loaderOffset, 0, loaderSize);
memcpy((void *)loaderOffset, injector, injector_size);
*((u32 *)loaderOffset + 0x41) = loaderSize / 0x200;
*((u32 *)loaderOffset + 0x69) = loaderSize / 0x200 - 5;
}
//Patch ARM9 entrypoint on N3DS to skip arm9loader
if(console)
firm->arm9Entry = (u8 *)0x801B01C;
//Write patched FIRM to SD if needed //Write patched FIRM to SD if needed
if(selectedFirm) if(selectedFirm)
@@ -285,8 +436,8 @@ void patchFirm(void){
error("Couldn't write the patched FIRM (no free space?)"); error("Couldn't write the patched FIRM (no free space?)");
} }
void launchFirm(void){ void launchFirm(void)
{
if(console && mode) setKeyXs(arm9Section); if(console && mode) setKeyXs(arm9Section);
//Copy firm partitions to respective memory locations //Copy firm partitions to respective memory locations

View File

@@ -8,8 +8,8 @@
#include "types.h" #include "types.h"
#define PDN_MPCORE_CFG (*(vu8 *)0x10140FFC) #define PDN_MPCORE_CFG (*(vu32 *)0x10140FFC)
#define PDN_SPI_CNT (*(vu8 *)0x101401C0) #define PDN_SPI_CNT (*(vu32 *)0x101401C0)
//FIRM Header layout //FIRM Header layout
typedef struct firmSectionHeader { typedef struct firmSectionHeader {

View File

@@ -9,18 +9,21 @@
static FATFS fs; static FATFS fs;
u32 mountSD(void){ u32 mountSD(void)
{
if(f_mount(&fs, "0:", 1) != FR_OK) return 0; if(f_mount(&fs, "0:", 1) != FR_OK) return 0;
return 1; return 1;
} }
u32 fileRead(void *dest, const char *path, u32 size){ u32 fileRead(void *dest, const char *path, u32 size)
{
FRESULT fr; FRESULT fr;
FIL fp; FIL fp;
unsigned int br = 0; unsigned int br = 0;
fr = f_open(&fp, path, FA_READ); fr = f_open(&fp, path, FA_READ);
if(fr == FR_OK){ if(fr == FR_OK)
{
if(!size) size = f_size(&fp); if(!size) size = f_size(&fp);
fr = f_read(&fp, dest, size, &br); fr = f_read(&fp, dest, size, &br);
} }
@@ -29,7 +32,8 @@ u32 fileRead(void *dest, const char *path, u32 size){
return fr ? 0 : 1; return fr ? 0 : 1;
} }
u32 fileWrite(const void *buffer, const char *path, u32 size){ u32 fileWrite(const void *buffer, const char *path, u32 size)
{
FRESULT fr; FRESULT fr;
FIL fp; FIL fp;
unsigned int br = 0; unsigned int br = 0;
@@ -41,7 +45,8 @@ u32 fileWrite(const void *buffer, const char *path, u32 size){
return fr ? 0 : 1; return fr ? 0 : 1;
} }
u32 fileSize(const char *path){ u32 fileSize(const char *path)
{
FIL fp; FIL fp;
u32 size = 0; u32 size = 0;
@@ -52,7 +57,8 @@ u32 fileSize(const char *path){
return size; return size;
} }
u32 fileExists(const char *path){ u32 fileExists(const char *path)
{
FIL fp; FIL fp;
u32 exists = 0; u32 exists = 0;
@@ -62,6 +68,7 @@ u32 fileExists(const char *path){
return exists; return exists;
} }
void fileDelete(const char *path){ void fileDelete(const char *path)
{
f_unlink(path); f_unlink(path);
} }

View File

@@ -10,11 +10,13 @@ static const struct { u8 bus_id, reg_addr; } dev_data[] = {
{2, 0xA4}, {2, 0x9A}, {2, 0xA0}, {2, 0xA4}, {2, 0x9A}, {2, 0xA0},
}; };
static inline u8 i2cGetDeviceBusId(u8 device_id) { static inline u8 i2cGetDeviceBusId(u8 device_id)
{
return dev_data[device_id].bus_id; return dev_data[device_id].bus_id;
} }
static inline u8 i2cGetDeviceRegAddr(u8 device_id) { static inline u8 i2cGetDeviceRegAddr(u8 device_id)
{
return dev_data[device_id].reg_addr; return dev_data[device_id].reg_addr;
} }
@@ -26,7 +28,8 @@ static vu8* reg_data_addrs[] = {
(vu8*)(I2C3_REG_OFF + I2C_REG_DATA), (vu8*)(I2C3_REG_OFF + I2C_REG_DATA),
}; };
static inline vu8* i2cGetDataReg(u8 bus_id) { static inline vu8* i2cGetDataReg(u8 bus_id)
{
return reg_data_addrs[bus_id]; return reg_data_addrs[bus_id];
} }
@@ -38,22 +41,27 @@ static vu8* reg_cnt_addrs[] = {
(vu8*)(I2C3_REG_OFF + I2C_REG_CNT), (vu8*)(I2C3_REG_OFF + I2C_REG_CNT),
}; };
static inline vu8* i2cGetCntReg(u8 bus_id) { static inline vu8* i2cGetCntReg(u8 bus_id)
{
return reg_cnt_addrs[bus_id]; return reg_cnt_addrs[bus_id];
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
static inline void i2cWaitBusy(u8 bus_id) { static inline void i2cWaitBusy(u8 bus_id)
{
while (*i2cGetCntReg(bus_id) & 0x80); while (*i2cGetCntReg(bus_id) & 0x80);
} }
static inline u32 i2cGetResult(u8 bus_id) { static inline u32 i2cGetResult(u8 bus_id)
{
i2cWaitBusy(bus_id); i2cWaitBusy(bus_id);
return (*i2cGetCntReg(bus_id) >> 4) & 1; return (*i2cGetCntReg(bus_id) >> 4) & 1;
} }
static void i2cStop(u8 bus_id, u8 arg0) { static void i2cStop(u8 bus_id, u8 arg0)
{
*i2cGetCntReg(bus_id) = (arg0 << 5) | 0xC0; *i2cGetCntReg(bus_id) = (arg0 << 5) | 0xC0;
i2cWaitBusy(bus_id); i2cWaitBusy(bus_id);
*i2cGetCntReg(bus_id) = 0xC5; *i2cGetCntReg(bus_id) = 0xC5;
@@ -61,32 +69,40 @@ static void i2cStop(u8 bus_id, u8 arg0) {
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
static u32 i2cSelectDevice(u8 bus_id, u8 dev_reg) { static u32 i2cSelectDevice(u8 bus_id, u8 dev_reg)
{
i2cWaitBusy(bus_id); i2cWaitBusy(bus_id);
*i2cGetDataReg(bus_id) = dev_reg; *i2cGetDataReg(bus_id) = dev_reg;
*i2cGetCntReg(bus_id) = 0xC2; *i2cGetCntReg(bus_id) = 0xC2;
return i2cGetResult(bus_id); return i2cGetResult(bus_id);
} }
static u32 i2cSelectRegister(u8 bus_id, u8 reg) { static u32 i2cSelectRegister(u8 bus_id, u8 reg)
{
i2cWaitBusy(bus_id); i2cWaitBusy(bus_id);
*i2cGetDataReg(bus_id) = reg; *i2cGetDataReg(bus_id) = reg;
*i2cGetCntReg(bus_id) = 0xC0; *i2cGetCntReg(bus_id) = 0xC0;
return i2cGetResult(bus_id); return i2cGetResult(bus_id);
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
u32 i2cWriteRegister(u8 dev_id, u8 reg, u8 data) { u32 i2cWriteRegister(u8 dev_id, u8 reg, u8 data)
{
u8 bus_id = i2cGetDeviceBusId(dev_id); u8 bus_id = i2cGetDeviceBusId(dev_id);
u8 dev_addr = i2cGetDeviceRegAddr(dev_id); u8 dev_addr = i2cGetDeviceRegAddr(dev_id);
for (int i = 0; i < 8; i++) { for (u32 i = 0; i < 8; i++)
if (i2cSelectDevice(bus_id, dev_addr) && i2cSelectRegister(bus_id, reg)) { {
if (i2cSelectDevice(bus_id, dev_addr) && i2cSelectRegister(bus_id, reg))
{
i2cWaitBusy(bus_id); i2cWaitBusy(bus_id);
*i2cGetDataReg(bus_id) = data; *i2cGetDataReg(bus_id) = data;
*i2cGetCntReg(bus_id) = 0xC1; *i2cGetCntReg(bus_id) = 0xC1;
i2cStop(bus_id, 0); i2cStop(bus_id, 0);
if (i2cGetResult(bus_id)) if (i2cGetResult(bus_id))
return 1; return 1;
} }

View File

@@ -12,8 +12,10 @@
#define PAYLOAD_ADDRESS 0x24F00000 #define PAYLOAD_ADDRESS 0x24F00000
void loadPayload(void){ void loadPayload(void)
if(fileExists("aurei/payloads/default.bin")){ {
if(fileExists("aurei/payloads/default.bin"))
{
initScreens(); initScreens();
memcpy((void *)PAYLOAD_ADDRESS, loader, loader_size); memcpy((void *)PAYLOAD_ADDRESS, loader, loader_size);
((void (*)())PAYLOAD_ADDRESS)(); ((void (*)())PAYLOAD_ADDRESS)();

View File

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

View File

@@ -8,40 +8,51 @@
#include "memory.h" #include "memory.h"
void memcpy(void *dest, const void *src, u32 size){ void memcpy(void *dest, const void *src, u32 size)
{
u8 *destc = (u8 *)dest; u8 *destc = (u8 *)dest;
const u8 *srcc = (const u8 *)src; const u8 *srcc = (const u8 *)src;
for(u32 i = 0; i < size; i++) for(u32 i = 0; i < size; i++)
destc[i] = srcc[i]; destc[i] = srcc[i];
} }
void memset(void *dest, int filler, u32 size){ void memset(void *dest, int filler, u32 size)
{
u8 *destc = (u8 *)dest; u8 *destc = (u8 *)dest;
for(u32 i = 0; i < size; i++) for(u32 i = 0; i < size; i++)
destc[i] = (u8)filler; destc[i] = (u8)filler;
} }
void memset32(void *dest, u32 filler, u32 size){ void memset32(void *dest, u32 filler, u32 size)
{
u32 *dest32 = (u32 *)dest; u32 *dest32 = (u32 *)dest;
for (u32 i = 0; i < size / 4; i++) for (u32 i = 0; i < size / 4; i++)
dest32[i] = filler; dest32[i] = filler;
} }
int memcmp(const void *buf1, const void *buf2, u32 size){ int memcmp(const void *buf1, const void *buf2, u32 size)
{
const u8 *buf1c = (const u8 *)buf1; const u8 *buf1c = (const u8 *)buf1;
const u8 *buf2c = (const u8 *)buf2; const u8 *buf2c = (const u8 *)buf2;
for(u32 i = 0; i < size; i++){
for(u32 i = 0; i < size; i++)
{
int cmp = buf1c[i] - buf2c[i]; int cmp = buf1c[i] - buf2c[i];
if(cmp) return cmp; if(cmp) return cmp;
} }
return 0; return 0;
} }
u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize){ u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize)
{
const u8 *patternc = (const u8 *)pattern; const u8 *patternc = (const u8 *)pattern;
//Preprocessing //Preprocessing
int table[256]; u32 table[256];
for(u32 i = 0; i < 256; ++i) for(u32 i = 0; i < 256; ++i)
table[i] = patternSize + 1; table[i] = patternSize + 1;
@@ -51,7 +62,8 @@ u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize){
//Searching //Searching
u32 j = 0; u32 j = 0;
while(j <= size - patternSize){ while(j <= size - patternSize)
{
if(memcmp(patternc, startPos + j, patternSize) == 0) if(memcmp(patternc, startPos + j, patternSize) == 0)
return startPos + j; return startPos + j;
j += table[startPos[j + patternSize]]; j += table[startPos[j + patternSize]];

View File

@@ -23,11 +23,13 @@ const u16 writeBlock[2] = {0x2000, 0x46C0};
* Functions * Functions
**************************************************/ **************************************************/
u8 *getProc9(u8 *pos, u32 size){ u8 *getProc9(u8 *pos, u32 size)
{
return memsearch(pos, "ess9", size, 4); return memsearch(pos, "ess9", size, 4);
} }
void getSigChecks(u8 *pos, u32 size, u32 *off, u32 *off2){ void getSigChecks(u8 *pos, u32 size, u32 *off, u32 *off2)
{
//Look for signature checks //Look for signature checks
const u8 pattern[] = {0xC0, 0x1C, 0x76, 0xE7}, const u8 pattern[] = {0xC0, 0x1C, 0x76, 0xE7},
pattern2[] = {0xB5, 0x22, 0x4D, 0x0C}; pattern2[] = {0xB5, 0x22, 0x4D, 0x0C};
@@ -36,16 +38,19 @@ void getSigChecks(u8 *pos, u32 size, u32 *off, u32 *off2){
*off2 = (u32)memsearch(pos, pattern2, size, 4) - 1; *off2 = (u32)memsearch(pos, pattern2, size, 4) - 1;
} }
void *getReboot(u8 *pos, u32 size){ void *getReboot(u8 *pos, u32 size)
{
//Look for FIRM reboot code //Look for FIRM reboot code
const u8 pattern[] = {0xDE, 0x1F, 0x8D, 0xE2}; const u8 pattern[] = {0xDE, 0x1F, 0x8D, 0xE2};
return memsearch(pos, pattern, size, 4) - 0x10; return memsearch(pos, pattern, size, 4) - 0x10;
} }
u32 getfOpen(u8 *proc9Offset, void *rebootOffset){ u32 getfOpen(u8 *proc9Offset, void *rebootOffset)
{
//Offset Process9 code gets loaded to in memory (defined in ExHeader) //Offset Process9 code gets loaded to in memory (defined in ExHeader)
u32 p9MemAddr = *(u32 *)(proc9Offset + 0xC); u32 p9MemAddr = *(u32 *)(proc9Offset + 0xC);
//Process9 code offset (start of NCCH + ExeFS offset + ExeFS header size) //Process9 code offset (start of NCCH + ExeFS offset + ExeFS header size)
u32 p9CodeOff = (u32)(proc9Offset - 0x204) + (*(u32 *)(proc9Offset - 0x64) * 0x200) + 0x200; u32 p9CodeOff = (u32)(proc9Offset - 0x204) + (*(u32 *)(proc9Offset - 0x64) * 0x200) + 0x200;
@@ -53,7 +58,8 @@ u32 getfOpen(u8 *proc9Offset, void *rebootOffset){
return (u32)rebootOffset + 9 - (-((*(u32 *)rebootOffset & 0x00FFFFFF) << 2) & 0xFFFFF) - p9CodeOff + p9MemAddr; return (u32)rebootOffset + 9 - (-((*(u32 *)rebootOffset & 0x00FFFFFF) << 2) & 0xFFFFF) - p9CodeOff + p9MemAddr;
} }
u16 *getFirmWrite(u8 *pos, u32 size){ u16 *getFirmWrite(u8 *pos, u32 size)
{
//Look for FIRM writing code //Look for FIRM writing code
u8 *const off = memsearch(pos, "exe:", size, 4); u8 *const off = memsearch(pos, "exe:", size, 4);
const u8 pattern[] = {0x00, 0x28, 0x01, 0xDA}; const u8 pattern[] = {0x00, 0x28, 0x01, 0xDA};
@@ -61,7 +67,8 @@ u16 *getFirmWrite(u8 *pos, u32 size){
return (u16 *)memsearch(off - 0x100, pattern, 0x100, 4); return (u16 *)memsearch(off - 0x100, pattern, 0x100, 4);
} }
void getLoader(u8 *pos, u32 size, u32 *loaderOffset, u32 *loaderSize){ void getLoader(u8 *pos, u32 size, u32 *loaderOffset, u32 *loaderSize)
{
u8 *const off = memsearch(pos, "loade", size, 5); u8 *const off = memsearch(pos, "loade", size, 5);
*loaderOffset = (u32)off - 0x200; *loaderOffset = (u32)off - 0x200;

View File

@@ -8,13 +8,19 @@
*/ */
#include "screeninit.h" #include "screeninit.h"
#include "memory.h"
#include "draw.h" #include "draw.h"
#include "i2c.h" #include "i2c.h"
#include "../build/screeninit.h"
#define SCREENINIT_ADDRESS 0x24F03000
static vu32 *const arm11 = (u32 *)0x1FFFFFF8; static vu32 *const arm11 = (u32 *)0x1FFFFFF8;
void deinitScreens(void){ void deinitScreens(void)
void __attribute__((naked)) ARM11(void){ {
void __attribute__((naked)) ARM11(void)
{
//Disable interrupts //Disable interrupts
__asm(".word 0xF10C01C0"); __asm(".word 0xF10C01C0");
@@ -28,124 +34,32 @@ void deinitScreens(void){
//Wait for the entry to be set //Wait for the entry to be set
while(!*arm11); while(!*arm11);
//Jump to it //Jump to it
((void (*)())*arm11)(); ((void (*)())*arm11)();
} }
if(PDN_GPU_CNT != 0x1){ if(PDN_GPU_CNT != 1)
{
*arm11 = (u32)ARM11; *arm11 = (u32)ARM11;
while(*arm11); while(*arm11);
} }
} }
void initScreens(void){ void initScreens(void)
void __attribute__((naked)) ARM11(void){ {
//Disable interrupts if(PDN_GPU_CNT == 1)
__asm(".word 0xF10C01C0"); {
//Write brightness level for the stub to pick up
*(vu32 *)0x24F04000 = (config >> 10) & 3;
*(vu32 *)0x10141200 = 0x1007F; memcpy((void *)SCREENINIT_ADDRESS, screeninit, screeninit_size);
*(vu32 *)0x10202014 = 0x00000001;
*(vu32 *)0x1020200C &= 0xFFFEFFFE;
*(vu32 *)0x10202240 = 0x45;
*(vu32 *)0x10202A40 = 0x45;
*(vu32 *)0x10202244 = 0x1023E;
*(vu32 *)0x10202A44 = 0x1023E;
// Top screen *arm11 = SCREENINIT_ADDRESS;
*(vu32 *)0x10400400 = 0x000001c2; while(*arm11);
*(vu32 *)0x10400404 = 0x000000d1;
*(vu32 *)0x10400408 = 0x000001c1;
*(vu32 *)0x1040040c = 0x000001c1;
*(vu32 *)0x10400410 = 0x00000000;
*(vu32 *)0x10400414 = 0x000000cf;
*(vu32 *)0x10400418 = 0x000000d1;
*(vu32 *)0x1040041c = 0x01c501c1;
*(vu32 *)0x10400420 = 0x00010000;
*(vu32 *)0x10400424 = 0x0000019d;
*(vu32 *)0x10400428 = 0x00000002;
*(vu32 *)0x1040042c = 0x00000192;
*(vu32 *)0x10400430 = 0x00000192;
*(vu32 *)0x10400434 = 0x00000192;
*(vu32 *)0x10400438 = 0x00000001;
*(vu32 *)0x1040043c = 0x00000002;
*(vu32 *)0x10400440 = 0x01960192;
*(vu32 *)0x10400444 = 0x00000000;
*(vu32 *)0x10400448 = 0x00000000;
*(vu32 *)0x1040045C = 0x00f00190;
*(vu32 *)0x10400460 = 0x01c100d1;
*(vu32 *)0x10400464 = 0x01920002;
*(vu32 *)0x10400468 = 0x18300000;
*(vu32 *)0x10400470 = 0x80341;
*(vu32 *)0x10400474 = 0x00010501;
*(vu32 *)0x10400478 = 0;
*(vu32 *)0x10400490 = 0x000002D0;
*(vu32 *)0x1040049C = 0x00000000;
// Disco register //Turn on backlight
for(vu32 i = 0; i < 256; i++)
*(vu32 *)0x10400484 = 0x10101 * i;
// Bottom screen
*(vu32 *)0x10400500 = 0x000001c2;
*(vu32 *)0x10400504 = 0x000000d1;
*(vu32 *)0x10400508 = 0x000001c1;
*(vu32 *)0x1040050c = 0x000001c1;
*(vu32 *)0x10400510 = 0x000000cd;
*(vu32 *)0x10400514 = 0x000000cf;
*(vu32 *)0x10400518 = 0x000000d1;
*(vu32 *)0x1040051c = 0x01c501c1;
*(vu32 *)0x10400520 = 0x00010000;
*(vu32 *)0x10400524 = 0x0000019d;
*(vu32 *)0x10400528 = 0x00000052;
*(vu32 *)0x1040052c = 0x00000192;
*(vu32 *)0x10400530 = 0x00000192;
*(vu32 *)0x10400534 = 0x0000004f;
*(vu32 *)0x10400538 = 0x00000050;
*(vu32 *)0x1040053c = 0x00000052;
*(vu32 *)0x10400540 = 0x01980194;
*(vu32 *)0x10400544 = 0x00000000;
*(vu32 *)0x10400548 = 0x00000011;
*(vu32 *)0x1040055C = 0x00f00140;
*(vu32 *)0x10400560 = 0x01c100d1;
*(vu32 *)0x10400564 = 0x01920052;
*(vu32 *)0x10400568 = 0x18300000 + 0x46500;
*(vu32 *)0x10400570 = 0x80301;
*(vu32 *)0x10400574 = 0x00010501;
*(vu32 *)0x10400578 = 0;
*(vu32 *)0x10400590 = 0x000002D0;
*(vu32 *)0x1040059C = 0x00000000;
// Disco register
for(vu32 i = 0; i < 256; i++)
*(vu32 *)0x10400584 = 0x10101 * i;
// Enable backlight
i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x2A); i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x2A);
*(vu32 *)0x10400468 = 0x18300000;
*(vu32 *)0x1040046c = 0x18300000;
*(vu32 *)0x10400494 = 0x18300000;
*(vu32 *)0x10400498 = 0x18300000;
*(vu32 *)0x10400568 = 0x18346500;
*(vu32 *)0x1040056c = 0x18346500;
//Set CakeBrah framebuffers
*((vu32 *)0x23FFFE00) = 0x18300000;
*((vu32 *)0x23FFFE04) = 0x18300000;
*((vu32 *)0x23FFFE08) = 0x18346500;
//Clear ARM11 entry offset
*arm11 = 0;
//Wait for the entry to be set
while(!*arm11);
//Jump to it
((void (*)())*arm11)();
}
if(PDN_GPU_CNT == 0x1){
*arm11 = (u32)ARM11;
while(*arm11);
} }
clearScreens(); clearScreens();

View File

@@ -13,5 +13,7 @@
#define PDN_GPU_CNT (*(vu8 *)0x10141200) #define PDN_GPU_CNT (*(vu8 *)0x10141200)
u32 config;
void deinitScreens(void); void deinitScreens(void);
void initScreens(void); void initScreens(void);

View File

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

View File

@@ -21,9 +21,10 @@ struct option {
u32 enabled; u32 enabled;
}; };
static u16 waitInput(void){ static u32 waitInput(void)
{
u32 pressedKey = 0; u32 pressedKey = 0;
u16 key; u32 key;
//Wait for no keys to be pressed //Wait for no keys to be pressed
while(HID_PAD); while(HID_PAD);
@@ -31,19 +32,23 @@ static u16 waitInput(void){
do { do {
//Wait for a key to be pressed //Wait for a key to be pressed
while(!HID_PAD); while(!HID_PAD);
key = HID_PAD; key = HID_PAD;
//Make sure it's pressed //Make sure it's pressed
for(u32 i = 0x13000; i; i--){ for(u32 i = 0x13000; i; i--)
{
if(key != HID_PAD) break; if(key != HID_PAD) break;
if(i == 1) pressedKey = 1; if(i == 1) pressedKey = 1;
} }
} while(!pressedKey); }
while(!pressedKey);
return key; return key;
} }
void configureCFW(const char *configPath, const char *firm90Path){ void configureCFW(const char *configPath, const char *patchedFirms[])
{
initScreens(); initScreens();
drawString(CONFIG_TITLE, 10, 10, COLOR_TITLE); drawString(CONFIG_TITLE, 10, 10, COLOR_TITLE);
@@ -54,7 +59,8 @@ void configureCFW(const char *configPath, const char *firm90Path){
"( ) Force A9LH detection", "( ) Force A9LH detection",
"( ) Use 9.0 FIRM as default", "( ) Use 9.0 FIRM as default",
"( ) Use second EmuNAND as default", "( ) Use second EmuNAND as default",
"( ) Show current NAND in System Settings" }; "( ) Show current NAND in System Settings",
"( ) Show GBA boot screen in patched AGB_FIRM" };
u32 optionsAmount = sizeof(optionsText) / sizeof(char *); u32 optionsAmount = sizeof(optionsText) / sizeof(char *);
struct option options[optionsAmount]; struct option options[optionsAmount];
@@ -62,30 +68,43 @@ void configureCFW(const char *configPath, const char *firm90Path){
//Read and parse the existing configuration //Read and parse the existing configuration
u32 tempConfig = 0; u32 tempConfig = 0;
fileRead(&tempConfig, configPath, 3); fileRead(&tempConfig, configPath, 3);
for(u32 i = 0; i < optionsAmount; i++) for(u32 i = 0; i < optionsAmount; i++)
options[i].enabled = (tempConfig >> i) & 0x1; options[i].enabled = (tempConfig >> i) & 1;
options[optionsAmount].enabled = (tempConfig >> 10) & 3;
//Pre-select the first configuration option //Pre-select the first configuration option
u32 selectedOption = 0; u32 selectedOption = 0;
//Boring configuration menu //Boring configuration menu
while(1){ while(1)
{
u16 pressed = 0; u16 pressed = 0;
do { do {
for(u32 i = 0; i < optionsAmount; i++){ options[optionsAmount].posY = drawString("Screen-init brightness: 4( ) 3( ) 2( ) 1( )", 10, 53, selectedOption == optionsAmount ? COLOR_RED : COLOR_WHITE);
options[i].posY = drawString(optionsText[i], 10, !i ? 60 : options[i - 1].posY + SPACING_Y, selectedOption == i ? COLOR_RED : COLOR_WHITE);
for(u32 i = 0; i < optionsAmount; i++)
{
options[i].posY = drawString(optionsText[i], 10, !i ? options[optionsAmount].posY + 2 * SPACING_Y : options[i - 1].posY + SPACING_Y, selectedOption == i ? COLOR_RED : COLOR_WHITE);
drawCharacter('x', 10 + SPACING_X, options[i].posY, options[i].enabled ? (selectedOption == i ? COLOR_RED : COLOR_WHITE) : COLOR_BLACK); drawCharacter('x', 10 + SPACING_X, options[i].posY, options[i].enabled ? (selectedOption == i ? COLOR_RED : COLOR_WHITE) : COLOR_BLACK);
} }
pressed = waitInput();
} while(!(pressed & MENU_BUTTONS));
switch(pressed){ for(u32 i = 0; i < 4; i++)
drawCharacter('x', 10 + (26 + 5 * i) * SPACING_X, options[optionsAmount].posY, options[optionsAmount].enabled == i ? (selectedOption == optionsAmount ? COLOR_RED : COLOR_WHITE) : COLOR_BLACK);
pressed = waitInput();
}
while(!(pressed & MENU_BUTTONS));
switch(pressed)
{
case BUTTON_UP: case BUTTON_UP:
selectedOption = !selectedOption ? optionsAmount - 1 : selectedOption - 1; selectedOption = !selectedOption ? optionsAmount : selectedOption - 1;
break; break;
case BUTTON_DOWN: case BUTTON_DOWN:
selectedOption = selectedOption == optionsAmount - 1 ? 0 : selectedOption + 1; selectedOption = selectedOption >= optionsAmount - 1 ? 0 : selectedOption + 1;
break; break;
case BUTTON_LEFT: case BUTTON_LEFT:
selectedOption = 0; selectedOption = 0;
@@ -94,7 +113,8 @@ void configureCFW(const char *configPath, const char *firm90Path){
selectedOption = optionsAmount - 1; selectedOption = optionsAmount - 1;
break; break;
case BUTTON_A: case BUTTON_A:
options[selectedOption].enabled = !options[selectedOption].enabled; if(selectedOption != optionsAmount) options[selectedOption].enabled = !options[selectedOption].enabled;
else options[optionsAmount].enabled = options[optionsAmount].enabled == 3 ? 0 : options[optionsAmount].enabled + 1;
break; break;
} }
@@ -102,8 +122,10 @@ void configureCFW(const char *configPath, const char *firm90Path){
} }
//If the user has been using A9LH and the "Updated SysNAND" setting changed, delete the patched 9.0 FIRM //If the user has been using A9LH and the "Updated SysNAND" setting changed, delete the patched 9.0 FIRM
if(((tempConfig >> 16) & 0x1) && ((tempConfig & 0x1) != options[0].enabled)) if(((tempConfig >> 16) & 1) && ((tempConfig & 1) != options[0].enabled)) fileDelete(patchedFirms[3]);
fileDelete(firm90Path);
//If the "Show GBA boot screen in patched AGB_FIRM" setting changed, delete the patched AGB_FIRM
if(((tempConfig >> 6) & 1) != options[6].enabled) fileDelete(patchedFirms[5]);
//Preserve the last-used boot options (last 12 bits) //Preserve the last-used boot options (last 12 bits)
tempConfig &= 0xFFF000; tempConfig &= 0xFFF000;
@@ -111,6 +133,9 @@ void configureCFW(const char *configPath, const char *firm90Path){
//Parse and write the selected options //Parse and write the selected options
for(u32 i = 0; i < optionsAmount; i++) for(u32 i = 0; i < optionsAmount; i++)
tempConfig |= options[i].enabled << i; tempConfig |= options[i].enabled << i;
tempConfig |= options[optionsAmount].enabled << 10;
fileWrite(&tempConfig, configPath, 3); fileWrite(&tempConfig, configPath, 3);
//Zero the last booted FIRM flag //Zero the last booted FIRM flag
@@ -121,14 +146,17 @@ void configureCFW(const char *configPath, const char *firm90Path){
while(1); while(1);
} }
void deleteFirms(const char *firmPaths[], u32 firms){ void deleteFirms(const char *firmPaths[], u32 firms)
while(firms){ {
while(firms)
{
fileDelete(firmPaths[firms - 1]); fileDelete(firmPaths[firms - 1]);
firms--; firms--;
} }
} }
void error(const char *message){ void error(const char *message)
{
initScreens(); initScreens();
drawString("An error has occurred:", 10, 10, COLOR_RED); drawString("An error has occurred:", 10, 10, COLOR_RED);

View File

@@ -8,8 +8,8 @@
#include "types.h" #include "types.h"
#define CFG_BOOTENV (*(vu8 *)0x10010000) #define CFG_BOOTENV (*(vu32 *)0x10010000)
void configureCFW(const char *configPath, const char *firm90Path); void configureCFW(const char *configPath, const char *patchedFirms[]);
void deleteFirms(const char *firmPaths[], u32 firms); void deleteFirms(const char *firmPaths[], u32 firms);
void error(const char *message); void error(const char *message);