Compare commits

..

20 Commits
v4.0.1 ... 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
34 changed files with 1197 additions and 763 deletions

View File

@@ -11,6 +11,7 @@ version := $(shell git describe --abbrev=0 --tags)
dir_source := source
dir_patches := patches
dir_loader := loader
dir_screeninit := screeninit
dir_injector := injector
dir_mset := CakeHax
dir_ninjhax := CakeBrah
@@ -19,7 +20,6 @@ dir_out := out
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 += -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
objects_cfw = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
@@ -48,6 +48,7 @@ clean:
@$(MAKE) $(FLAGS) -C $(dir_ninjhax) clean
@rm -rf $(dir_out) $(dir_build)
@$(MAKE) -C $(dir_loader) clean
@$(MAKE) -C $(dir_screeninit) clean
@$(MAKE) -C $(dir_injector) clean
$(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
$(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)
@mkdir -p "$(dir_out)/3ds/$(name)"
@@ -82,6 +83,11 @@ $(dir_build)/loader.h: $(dir_loader)/Makefile
@mv $(dir_loader)/loader.bin $(dir_build)
@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
$(OC) -S -O binary $< $@
@@ -89,7 +95,10 @@ $(dir_build)/main.elf: $(objects_cfw)
# FatFs requires libgcc for __aeabi_uidiv
$(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)"
$(COMPILE.c) $(OUTPUT_OPTION) $<

View File

@@ -15,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
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:**
@@ -31,6 +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 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_code(progid, (u8 *)shared->text_addr, shared->total_size << 12);
patchCode(progid, (u8 *)shared->text_addr, shared->total_size << 12);
return 0;
}

View File

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

View File

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

View File

@@ -16,11 +16,9 @@ include $(DEVKITARM)/3ds_rules
# INCLUDES is a list of directories containing header files
# SPECS is the directory containing the important build and link files
#---------------------------------------------------------------------------------
export TARGET := $(shell basename $(CURDIR))
export TARGET := $(shell basename $(CURDIR))
BUILD := build
SOURCES := source source/fatfs source/fatfs/sdmmc
DATA := data
INCLUDES := include source/fatfs source/fatfs/sdmmc
SOURCES := source source/fatfs source/fatfs/sdmmc
#---------------------------------------------------------------------------------
# Setup some defines
@@ -43,14 +41,6 @@ CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
ASFLAGS := -g $(ARCH)
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
# rules for different file extensions
@@ -60,15 +50,13 @@ ifneq ($(BUILD),$(notdir $(CURDIR)))
export OUTPUT := $(CURDIR)/$(TARGET)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
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)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
@@ -84,14 +72,7 @@ else
endif
#---------------------------------------------------------------------------------
export OFILES := $(addsuffix .o,$(BINFILES)) \
$(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)
export OFILES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
.PHONY: $(BUILD) clean all

View File

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

View File

@@ -4,9 +4,11 @@
#define PAYLOAD_ADDRESS 0x23F00000
static u32 loadPayload(const char *path){
static u32 loadPayload(const char *path)
{
FIL payload;
unsigned int br;
if(f_open(&payload, path, FA_READ) == FR_OK)
{
f_read(&payload, (void *)PAYLOAD_ADDRESS, f_size(&payload), &br);
@@ -18,22 +20,23 @@ static u32 loadPayload(const char *path){
return 0;
}
void main(void){
void main(void)
{
FATFS fs;
f_mount(&fs, "0:", 1);
//Get pressed buttons
u16 pressed = HID_PAD;
u32 pressed = HID_PAD;
if(((pressed & BUTTON_B) && loadPayload("/aurei/payloads/b.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")) ||
if(((pressed & BUTTON_RIGHT) && loadPayload("/aurei/payloads/right.bin")) ||
((pressed & BUTTON_LEFT) && loadPayload("/aurei/payloads/left.bin")) ||
((pressed & BUTTON_UP) && loadPayload("/aurei/payloads/up.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"))
((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, c10, 4 @ drain write buffer
bl main
.die:
b .die
b main

View File

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

View File

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

View File

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

View File

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

View File

@@ -10,7 +10,7 @@
#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);
void getEmuRW(u8 *pos, u32 size, u32 *readOff, u32 *writeOff);
u32 *getMPU(u8 *pos, u32 size);

View File

@@ -18,7 +18,7 @@
#include "../build/patches.h"
//FIRM patches version
#define PATCH_VER 2
#define PATCH_VER 4
static firmHeader *const firm = (firmHeader *)0x24000000;
static const firmSectionHeader *section;
@@ -26,130 +26,186 @@ static u8 *arm9Section;
static const char *patchedFirms[] = { "/aurei/patched_firmware_sys.bin",
"/aurei/patched_firmware_emu.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,
console,
mode,
emuNAND,
a9lhSetup,
selectedFirm,
usePatchedFirm;
void setupCFW(void){
usePatchedFirm,
emuOffset,
emuHeader;
u32 config;
void setupCFW(void)
{
//Determine if booting with A9LH
u32 a9lhBoot = (PDN_SPI_CNT == 0x0) ? 1 : 0;
u32 a9lhBoot = !PDN_SPI_CNT ? 1 : 0;
//Retrieve the last booted FIRM
u8 previousFirm = CFG_BOOTENV;
u32 previousFirm = CFG_BOOTENV;
//Detect the console being used
console = (PDN_MPCORE_CFG == 1) ? 0 : 1;
//Get pressed buttons
u16 pressed = HID_PAD;
u32 pressed = HID_PAD;
//Attempt to read the configuration file
const char configPath[] = "aurei/config.bin";
u32 config = 0;
u32 needConfig = fileRead(&config, configPath, 3) ? 1 : 2;
const char configPath[] = "/aurei/config.bin";
u32 needConfig;
if(fileRead(&config, configPath, 3)) needConfig = 1;
else
{
config = 0;
needConfig = 2;
}
//Determine if A9LH is installed and the user has an updated sysNAND
u32 updatedSys;
if(a9lhBoot || (config >> 2) & 0x1){
if(a9lhBoot || (config >> 2) & 1)
{
if(pressed == SAFE_MODE)
error("Using Safe Mode would brick you, or remove A9LH!");
a9lhSetup = 1;
//Check setting for > 9.2 sysNAND
updatedSys = config & 0x1;
} else{
updatedSys = config & 1;
}
else
{
a9lhSetup = 0;
updatedSys = 0;
}
u32 tempConfig = (PATCH_VER << 17) | (a9lhSetup << 16);
/* If booting with A9LH, it's a MCU reboot and a previous configuration exists,
try to force boot options */
if(a9lhBoot && previousFirm && needConfig == 1){
if(a9lhBoot && previousFirm && needConfig == 1)
{
//Always force a sysNAND boot when quitting AGB_FIRM
if(previousFirm == 0x7){
mode = updatedSys ? 1 : (config >> 12) & 0x1;
if(previousFirm == 7)
{
mode = updatedSys ? 1 : (config >> 12) & 1;
emuNAND = 0;
needConfig = 0;
//Else, force the last used boot options unless A, L or R are pressed
} else if(!(pressed & OPTION_BUTTONS)){
mode = (config >> 12) & 0x1;
emuNAND = (config >> 13) & 0x3;
//Flag to prevent multiple boot options-forcing
tempConfig |= 1 << 15;
}
/* 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;
}
}
if(needConfig){
/* If L and one of the payload buttons are pressed, and if not using A9LH
//Boot options aren't being forced
if(needConfig)
{
/* 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 */
if((pressed & BUTTON_L1) && (pressed & PAYLOAD_BUTTONS) &&
pressed != SAFE_MODE) loadPayload();
if(((pressed & SINGLE_PAYLOAD_BUTTONS) || ((pressed & BUTTON_L1) && (pressed & L_PAYLOAD_BUTTONS)))
&& pressed != SAFE_MODE)
loadPayload();
//If no configuration file exists or SELECT is held, load configuration menu
if(needConfig == 2 || (pressed & BUTTON_SELECT))
configureCFW(configPath, patchedFirms[3]);
configureCFW(configPath, patchedFirms);
//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 */
mode = ((config >> 3) & 0x1) ? ((!(pressed & BUTTON_L1R1)) ? 0 : 1) :
((pressed & BUTTON_L1) ? 0 : 1);
/* If L is pressed, or L or R are not pressed when it is the default FIRM,
boot 9.0 FIRM */
mode = ((config >> 3) & 1) ? ((!(pressed & BUTTON_L1R1)) ? 0 : 1) :
((pressed & BUTTON_L1) ? 0 : 1);
/* If L or R aren't pressed on a 9.0/9.2 sysNAND, or the 9.0 FIRM is selected
or R is pressed on a > 9.2 sysNAND, boot emuNAND */
if((updatedSys && (!mode || (pressed & BUTTON_R1))) ||
(!updatedSys && mode && !(pressed & BUTTON_R1))){
//If not 9.0 FIRM and B is pressed, attempt booting the second emuNAND
emuNAND = (mode && ((!(pressed & BUTTON_B)) == ((config >> 4) & 0x1))) ? 2 : 1;
} else emuNAND = 0;
u32 tempConfig = (PATCH_VER << 17) | (a9lhSetup << 16) | (emuNAND << 13) | (mode << 12);
if((updatedSys && (!mode || (pressed & BUTTON_R1))) || (!updatedSys && mode && !(pressed & BUTTON_R1)))
{
/* If not 9.0 FIRM and the second emuNAND is set as default and B isn't pressed, or vice-versa,
attempt to boot it */
emuNAND = (mode && ((!(pressed & BUTTON_B)) == ((config >> 4) & 1))) ? 2 : 1;
}
else emuNAND = 0;
/* If tha FIRM patches version is different or user switched to/from A9LH,
delete all patched FIRMs */
if((tempConfig & 0xFF0000) != (config & 0xFF0000))
deleteFirms(patchedFirms, sizeof(patchedFirms) / sizeof(char *));
//If the boot configuration is different from previously, overwrite it
if((tempConfig & 0xFFF000) != (config & 0xFFF000)){
//Preserve user settings (first 12 bits)
tempConfig |= config & 0xFFF;
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);
u32 usePatchedFirmSet = ((config >> 1) & 1);
//If "Use pre-patched FIRMs" is set and the appropriate FIRM exists, use it
usePatchedFirm = (((config >> 1) & 0x1) && fileExists(patchedFirms[selectedFirm - 1])) ? 1 : 0;
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(tempConfig != (config & 0xFFF000))
{
//Preserve user settings (first 12 bits)
tempConfig |= config & 0xFFF;
fileWrite(&tempConfig, configPath, 3);
}
}
//Load FIRM into FCRAM
void loadFirm(void){
void loadFirm(void)
{
//If not using an A9LH setup or the patched FIRM, load 9.0 FIRM from NAND
if(!usePatchedFirm && !a9lhSetup && !mode){
if(!usePatchedFirm && !a9lhSetup && !mode)
{
//Read FIRM from NAND and write to FCRAM
firmSize = console ? 0xF2000 : 0xE9000;
nandFirm0((u8 *)firm, firmSize, console);
//Check for correct decryption
if(memcmp(firm, "FIRM", 4) != 0)
error("Couldn't decrypt NAND FIRM0 (O3DS not on 9.x?)");
}
//Load FIRM from SD
else{
else
{
const char *path = usePatchedFirm ? patchedFirms[selectedFirm - 1] :
(mode ? "/aurei/firmware.bin" : "/aurei/firmware90.bin");
(mode ? "/aurei/firmware.bin" : "/aurei/firmware90.bin");
firmSize = fileSize(path);
if(!firmSize) error("aurei/firmware(90).bin doesn't exist");
if(!firmSize) error(mode ? "aurei/firmware.bin doesn't exist" :
"aurei/firmware90.bin doesn't exist");
fileRead(firm, path, firmSize);
}
@@ -157,27 +213,99 @@ void loadFirm(void){
//Check that the loaded FIRM matches the console
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;
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
static void loadEmu(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");
static inline void patchEmuNAND(u8 *proc9Offset)
{
//Copy emuNAND code
void *emuCodeOffset = getEmuCode(proc9Offset);
memcpy(emuCodeOffset, emunand, emunand_size);
@@ -197,6 +325,9 @@ static void loadEmu(u8 *proc9Offset){
section[2].offset + (u32)section[2].address;
//Add emunand hooks
u32 emuRead,
emuWrite;
getEmuRW(arm9Section, section[2].size, &emuRead, &emuWrite);
*(u16 *)emuRead = nandRedir[0];
*((u16 *)emuRead + 1) = nandRedir[1];
@@ -212,49 +343,82 @@ static void loadEmu(u8 *proc9Offset){
*(mpuOffset + 9) = mpuPatch[2];
}
static inline void patchReboots(u8 *proc9Offset)
{
//Calculate offset for the firmlaunch code
void *rebootOffset = getReboot(arm9Section, section[2].size);
//Calculate offset for the fOpen function
u32 fOpenOffset = getfOpen(proc9Offset, rebootOffset);
//Copy firmlaunch code
memcpy(rebootOffset, reboot, reboot_size);
//Put the fOpen offset in the right location
u32 *pos_fopen = (u32 *)memsearch(rebootOffset, "OPEN", reboot_size, 4);
*pos_fopen = fOpenOffset;
//Patch path for emuNAND-patched FIRM
if(emuNAND)
{
void *pos_path = memsearch(rebootOffset, L"sy", reboot_size, 4);
memcpy(pos_path, emuNAND == 1 ? L"emu" : L"em2", 5);
}
}
static inline void injectLoader(void)
{
u32 loaderOffset,
loaderSize;
getLoader((u8 *)firm + section[0].offset, section[0].size, &loaderOffset, &loaderSize);
//Check that the injector CXI isn't larger than the original
if(injector_size <= (int)loaderSize)
{
memset((void *)loaderOffset, 0, loaderSize);
memcpy((void *)loaderOffset, injector, injector_size);
//Patch content size and ExeFS size to match the repaced loader's ones
*((u32 *)loaderOffset + 0x41) = loaderSize / 0x200;
*((u32 *)loaderOffset + 0x69) = loaderSize / 0x200 - 5;
}
}
//Patches
void patchFirm(void){
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){
if(mode || emuNAND)
{
//Find the Process9 NCCH location
u8 *proc9Offset = getProc9(arm9Section, section[2].size);
//Apply emuNAND patches
if(emuNAND) loadEmu(proc9Offset);
if(emuNAND) patchEmuNAND(proc9Offset);
//Patch FIRM reboots, not on 9.0 FIRM as it breaks firmlaunchhax
if(mode){
//Calculate offset for the firmlaunch code
void *rebootOffset = getReboot(arm9Section, section[2].size);
//Calculate offset for the fOpen function
u32 fOpenOffset = getfOpen(proc9Offset, rebootOffset);
//Copy firmlaunch code
memcpy(rebootOffset, reboot, reboot_size);
//Put the fOpen offset in the right location
u32 *pos_fopen = (u32 *)memsearch(rebootOffset, "OPEN", reboot_size, 4);
*pos_fopen = fOpenOffset;
//Patch path for emuNAND-patched FIRM
if(emuNAND){
void *pos_path = memsearch(rebootOffset, L"sy", reboot_size, 4);
memcpy(pos_path, emuNAND == 1 ? L"emu" : L"em2", 5);
}
}
//Apply FIRM reboot patches, not on 9.0 FIRM as it breaks firmlaunchhax
if(mode) patchReboots(proc9Offset);
}
if(a9lhSetup && !emuNAND){
//Patch FIRM partitions writes on sysNAND to protect A9LH
//Apply FIRM0/1 writes patches on sysNAND to protect A9LH
if(a9lhSetup && !emuNAND)
{
u16 *writeOffset = getFirmWrite(arm9Section, section[2].size);
*writeOffset = writeBlock[0];
*(writeOffset + 1) = writeBlock[1];
}
//Disable signature checks
//Apply signature checks patches
u32 sigOffset,
sigOffset2;
@@ -264,20 +428,7 @@ void patchFirm(void){
*((u16 *)sigOffset2 + 1) = sigPatch[1];
//Replace the FIRM loader with the injector
u32 loaderOffset,
loaderSize;
getLoader((u8 *)firm + section[0].offset, section[0].size, &loaderOffset, &loaderSize);
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;
injectLoader();
//Write patched FIRM to SD if needed
if(selectedFirm)
@@ -285,8 +436,8 @@ void patchFirm(void){
error("Couldn't write the patched FIRM (no free space?)");
}
void launchFirm(void){
void launchFirm(void)
{
if(console && mode) setKeyXs(arm9Section);
//Copy firm partitions to respective memory locations

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -8,13 +8,19 @@
*/
#include "screeninit.h"
#include "memory.h"
#include "draw.h"
#include "i2c.h"
#include "../build/screeninit.h"
#define SCREENINIT_ADDRESS 0x24F03000
static vu32 *const arm11 = (u32 *)0x1FFFFFF8;
void deinitScreens(void){
void __attribute__((naked)) ARM11(void){
void deinitScreens(void)
{
void __attribute__((naked)) ARM11(void)
{
//Disable interrupts
__asm(".word 0xF10C01C0");
@@ -28,124 +34,32 @@ void deinitScreens(void){
//Wait for the entry to be set
while(!*arm11);
//Jump to it
((void (*)())*arm11)();
}
if(PDN_GPU_CNT != 0x1){
if(PDN_GPU_CNT != 1)
{
*arm11 = (u32)ARM11;
while(*arm11);
}
}
void initScreens(void){
void __attribute__((naked)) ARM11(void){
//Disable interrupts
__asm(".word 0xF10C01C0");
void initScreens(void)
{
if(PDN_GPU_CNT == 1)
{
//Write brightness level for the stub to pick up
*(vu32 *)0x24F04000 = (config >> 10) & 3;
*(vu32 *)0x10141200 = 0x1007F;
*(vu32 *)0x10202014 = 0x00000001;
*(vu32 *)0x1020200C &= 0xFFFEFFFE;
*(vu32 *)0x10202240 = 0x45;
*(vu32 *)0x10202A40 = 0x45;
*(vu32 *)0x10202244 = 0x1023E;
*(vu32 *)0x10202A44 = 0x1023E;
memcpy((void *)SCREENINIT_ADDRESS, screeninit, screeninit_size);
// 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(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);
*(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;
*arm11 = SCREENINIT_ADDRESS;
while(*arm11);
//Turn on backlight
i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x2A);
}
clearScreens();

View File

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

View File

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

View File

@@ -21,9 +21,10 @@ struct option {
u32 enabled;
};
static u16 waitInput(void){
static u32 waitInput(void)
{
u32 pressedKey = 0;
u16 key;
u32 key;
//Wait for no keys to be pressed
while(HID_PAD);
@@ -31,19 +32,23 @@ static u16 waitInput(void){
do {
//Wait for a key to be pressed
while(!HID_PAD);
key = HID_PAD;
//Make sure it's pressed
for(u32 i = 0x13000; i; i--){
for(u32 i = 0x13000; i; i--)
{
if(key != HID_PAD) break;
if(i == 1) pressedKey = 1;
}
} while(!pressedKey);
}
while(!pressedKey);
return key;
}
void configureCFW(const char *configPath, const char *firm90Path){
void configureCFW(const char *configPath, const char *patchedFirms[])
{
initScreens();
drawString(CONFIG_TITLE, 10, 10, COLOR_TITLE);
@@ -54,7 +59,8 @@ void configureCFW(const char *configPath, const char *firm90Path){
"( ) Force A9LH detection",
"( ) Use 9.0 FIRM 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 *);
struct option options[optionsAmount];
@@ -62,30 +68,43 @@ void configureCFW(const char *configPath, const char *firm90Path){
//Read and parse the existing configuration
u32 tempConfig = 0;
fileRead(&tempConfig, configPath, 3);
for(u32 i = 0; i < optionsAmount; i++)
options[i].enabled = (tempConfig >> i) & 0x1;
options[i].enabled = (tempConfig >> i) & 1;
options[optionsAmount].enabled = (tempConfig >> 10) & 3;
//Pre-select the first configuration option
u32 selectedOption = 0;
//Boring configuration menu
while(1){
while(1)
{
u16 pressed = 0;
do{
for(u32 i = 0; i < optionsAmount; i++){
options[i].posY = drawString(optionsText[i], 10, !i ? 60 : options[i - 1].posY + SPACING_Y, selectedOption == i ? COLOR_RED : COLOR_WHITE);
do {
options[optionsAmount].posY = drawString("Screen-init brightness: 4( ) 3( ) 2( ) 1( )", 10, 53, selectedOption == optionsAmount ? 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);
}
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:
selectedOption = !selectedOption ? optionsAmount - 1 : selectedOption - 1;
selectedOption = !selectedOption ? optionsAmount : selectedOption - 1;
break;
case BUTTON_DOWN:
selectedOption = selectedOption == optionsAmount - 1 ? 0 : selectedOption + 1;
selectedOption = selectedOption >= optionsAmount - 1 ? 0 : selectedOption + 1;
break;
case BUTTON_LEFT:
selectedOption = 0;
@@ -94,7 +113,8 @@ void configureCFW(const char *configPath, const char *firm90Path){
selectedOption = optionsAmount - 1;
break;
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;
}
@@ -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(((tempConfig >> 16) & 0x1) && ((tempConfig & 0x1) != options[0].enabled))
fileDelete(firm90Path);
if(((tempConfig >> 16) & 1) && ((tempConfig & 1) != options[0].enabled)) fileDelete(patchedFirms[3]);
//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)
tempConfig &= 0xFFF000;
@@ -111,6 +133,9 @@ void configureCFW(const char *configPath, const char *firm90Path){
//Parse and write the selected options
for(u32 i = 0; i < optionsAmount; i++)
tempConfig |= options[i].enabled << i;
tempConfig |= options[optionsAmount].enabled << 10;
fileWrite(&tempConfig, configPath, 3);
//Zero the last booted FIRM flag
@@ -121,14 +146,17 @@ void configureCFW(const char *configPath, const char *firm90Path){
while(1);
}
void deleteFirms(const char *firmPaths[], u32 firms){
while(firms){
void deleteFirms(const char *firmPaths[], u32 firms)
{
while(firms)
{
fileDelete(firmPaths[firms - 1]);
firms--;
}
}
void error(const char *message){
void error(const char *message)
{
initScreens();
drawString("An error has occurred:", 10, 10, COLOR_RED);

View File

@@ -8,8 +8,8 @@
#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 error(const char *message);