Compare commits

...

63 Commits

Author SHA1 Message Date
Aurora
fc151f7595 Consistency 2016-09-04 14:05:29 +02:00
Aurora
2b4e97bec5 Get rid of the PIN on/off toggle and add an Off status to the multi option, change the config layout to allow for more multi options, add macros for all options 2016-09-04 13:45:03 +02:00
Aurora
97ae8d2d44 Forgot this 2016-09-04 00:55:20 +02:00
Aurora
201fe05a06 Implement selectable PIN size, added support for the directional pad in PINs 2016-09-04 00:38:17 +02:00
Aurora
5cd1a207c9 Forgot an instance where the PIN path is used 2016-09-03 23:07:51 +02:00
Aurora
7612e38d41 Increase the config minor version 2016-09-03 22:00:49 +02:00
Aurora
bd992fca15 Remove the TWL dev launcher patch as it became unnecessary 2016-09-03 19:11:44 +02:00
Aurora
a2bca96d47 Cleanup, use sizeof() for pattern memsearches 2016-09-03 18:15:00 +02:00
Aurora
fc3a69d9ca Small cleanup 2016-09-02 22:56:57 +02:00
Aurora
eba56d0f64 Save 4 bytes as we are space constrained on N3DS 2016-09-02 15:40:28 +02:00
Aurora
c93a97f8d7 mcuReboot now checks for isFirmlaunch 2016-09-02 15:19:14 +02:00
Aurora
9bc62ec12d Move config and PIN paths to the respective headers 2016-09-02 14:14:19 +02:00
Aurora
263a5eda56 Update to latest FatFs patch 2016-09-02 13:40:20 +02:00
Aurora
7fb17ce52f Remove exceptions folder from Luma-dev when cleaning 2016-09-01 18:01:21 +02:00
Aurora
631fad24c0 Make firmware.bin check more readable 2016-09-01 17:56:33 +02:00
Aurora
c0f042bc2a Can not support safe_firm firmlaunches without 3ds_injector at the moment 2016-08-31 19:50:37 +02:00
TuxSH
8982ff259a Add support for 1.x NATIVE_FIRM (on sysNAND) and the O3DS v0 SAFE_FIRM 2016-08-31 19:30:45 +02:00
Aurora
0057ab9c5a Fix config not being written in a rare circumstance 2016-08-31 16:11:44 +02:00
Aurora
a84f393bd5 Move the itoa function to strings.c 2016-08-30 21:32:15 +02:00
Aurora
5406d648bc Fix derp 2016-08-30 20:01:45 +02:00
Aurora
a2003fba95 Add -O3 optimization for the string functions 2016-08-30 19:48:21 +02:00
Aurora
a76c15d018 Introduce a strcat replacement 2016-08-30 17:48:41 +02:00
Aurora
f221915a95 Get rid of createDirectory and make fileWrite handle directory tree creation 2016-08-30 17:04:29 +02:00
Aurora
7f93733107 Rewrite the module copying function 2016-08-30 02:18:32 +02:00
TuxSH
06fe06f9f1 Update CFWInfo.h 2016-08-29 18:23:06 +02:00
Aurora
abf7c8e565 Replace pinKeyToLetter with a C implementation, minor cleanup 2016-08-29 18:11:59 +02:00
TuxSH
46227e6763 Fix build issues on some environments. 2016-08-29 17:51:03 +02:00
Aurora
2ffe4a5451 Revert "Skip PIN verification after a MCU reboot on A9LH"
This reverts commit 18bd4bbcf6.
2016-08-29 16:04:17 +02:00
Aurora
18bd4bbcf6 Skip PIN verification after a MCU reboot on A9LH 2016-08-29 15:57:32 +02:00
Aurora
8209433696 Cleanup and refactoring 2016-08-29 15:42:54 +02:00
Aurora
ad9e00acaa Add delay if a PIN was just verified and SAFE_MODE is being booted 2016-08-29 13:56:23 +02:00
Aurora
c96f96258f Only patch 2.x NATIVE_FIRM on A9LH 2016-08-29 01:58:01 +02:00
Aurora
82699f3e00 Merge readPin and verifyPin 2016-08-28 23:41:41 +02:00
Aurora
e2d828a4a2 Fixed derp 2016-08-28 15:58:10 +02:00
Aurora
92328c6a7e Made it easier to change your PIN, added PIN file deletion when needed 2016-08-28 15:51:54 +02:00
Aurora
3f8ad17e86 Minor PIN cleanup and UI changes 2016-08-28 14:59:33 +02:00
Aurora
52999db43a Readability stuff 2016-08-28 14:41:18 +02:00
Aurora
760aa99709 Revert "Add back reboot patch on 2.x"
This reverts commit 51c514de84.
2016-08-28 12:33:00 +02:00
TuxSH
51c514de84 Add back reboot patch on 2.x 2016-08-28 11:48:35 +02:00
Aurora
317899b4bf Fix another derp 2016-08-28 02:56:46 +02:00
Aurora
4c93d2b1f9 Better to put this here 2016-08-28 02:49:53 +02:00
Aurora
71c5404bfe Fix derp 2016-08-28 02:41:00 +02:00
Aurora
9c5248b87a Cleanup previous commit 2016-08-28 02:38:52 +02:00
TuxSH
83a0293af4 Add support (firmprot and firmlaunch patches) for 2.x on sysNAND 2016-08-28 00:32:47 +02:00
TuxSH
a5c6b908b6 Fix reboot patch for 5.x/6.x 2016-08-27 18:10:51 +02:00
Aurora
94f0d873df Cleanup 2016-08-27 17:34:37 +02:00
Aurora
d6f66d24fa Consistency 2016-08-27 16:11:37 +02:00
Aurora
31458e9938 Implement a new config file format which allows invalidating the config with new releases, fix config-related bugs, cleanup 2016-08-27 16:00:15 +02:00
Aurora
c711ed6253 Added a different error for < 3.x NANDs as they can not be booted currently 2016-08-27 00:34:25 +02:00
Aurora
356268eae5 Welcome back to the 1,25s speed boost 2016-08-26 22:24:23 +02:00
Aurora
2dd64b8a92 Merge branch 'master' of https://github.com/AuroraWright/Luma3DS 2016-08-26 21:38:36 +02:00
Aurora
b5cddedb7d Fix config derp 2016-08-26 21:38:03 +02:00
TuxSH
7afdc2b3b5 "Fix" the twlbg patches and make them optional 2016-08-26 19:09:14 +02:00
Aurora
60c4956290 Fix wrong bootconfig being picked up by 3ds_injector, cleanup 2016-08-26 18:44:39 +02:00
TuxSH
7331a919e4 Fix bug. 2016-08-25 18:53:37 +02:00
TuxSH
33238cee54 Remove loading of /luma/TwlBg.cxi, fix bugs. 2016-08-25 16:39:43 +02:00
TuxSH
384dd2ad81 Implement on-the-fly patching of TwlBg
(and port the patches from https://github.com/ahezard/twl_firm_patcher; big thanks to ahezard and people mentioned in this page; also to Subv for the original patching idea (for NATIVE_FIRM))
2016-08-25 00:13:43 +02:00
TuxSH
74ac76ba84 Merge branch 'master' of https://github.com/AuroraWright/Luma3DS 2016-08-21 22:09:47 +02:00
TuxSH
253e031f83 Add support for loading /luma/TwlBg.cxi (on dev branch this will take precedence) 2016-08-21 22:09:27 +02:00
TuxSH
ef1ecf859c Update draw.c 2016-08-20 19:59:25 +02:00
TuxSH
a302ad3bea R.I.P boot speed boost (for now) 2016-08-20 18:45:56 +02:00
TuxSH
b87dadbb72 Update patches.c 2016-08-18 00:36:28 +02:00
TuxSH
50a2424001 Implement svcGetCFWInfo in place of svc 0x2e (which is stubbed). Luma3DS now boots ca. 1.5s faster
Fix bug in pin.c where the START button wasn't recognized as well.
2016-08-17 23:47:30 +02:00
37 changed files with 776 additions and 444 deletions

View File

@@ -13,6 +13,7 @@ OC := arm-none-eabi-objcopy
name := Luma3DS
revision := $(shell git describe --tags --match v[0-9]* --abbrev=8 | sed 's/-[0-9]*-g/-/i')
commit := $(shell git rev-parse --short=8 HEAD)
dir_source := source
dir_patches := patches
@@ -32,7 +33,8 @@ objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
$(call rwildcard, $(dir_source), *.s *.c)))
bundled = $(dir_build)/rebootpatch.h $(dir_build)/emunandpatch.h $(dir_build)/injector.h $(dir_build)/loader.h
bundled = $(dir_build)/rebootpatch.h $(dir_build)/emunandpatch.h $(dir_build)/svcGetCFWInfopatch.h $(dir_build)/injector.h \
$(dir_build)/loader.h
.PHONY: all
all: launcher a9lh ninjhax
@@ -55,7 +57,7 @@ clean:
@$(MAKE) $(FLAGS) -C $(dir_ninjhax) clean
@$(MAKE) -C $(dir_loader) clean
@$(MAKE) -C $(dir_injector) clean
@rm -rf $(dir_out) $(dir_build)
@rm -rf $(dir_out) $(dir_build) exceptions
$(dir_out):
@mkdir -p "$(dir_out)"
@@ -91,6 +93,11 @@ $(dir_build)/rebootpatch.h: $(dir_patches)/reboot.s
@armips $<
@bin2c -o $@ -n reboot $(@D)/reboot.bin
$(dir_build)/svcGetCFWInfopatch.h: $(dir_patches)/svcGetCFWInfo.s
@mkdir -p "$(@D)"
@armips $<
@bin2c -o $@ -n svcGetCFWInfo $(@D)/svcGetCFWInfo.bin
$(dir_build)/injector.h: $(dir_injector)/Makefile
@mkdir -p "$(@D)"
@$(MAKE) -C $(dir_injector)
@@ -100,8 +107,9 @@ $(dir_build)/loader.h: $(dir_loader)/Makefile
@$(MAKE) -C $(dir_loader)
@bin2c -o $@ -n loader $(@D)/loader.bin
$(dir_build)/memory.o: CFLAGS += -O3
$(dir_build)/memory.o $(dir_build)/strings.o: CFLAGS += -O3
$(dir_build)/config.o: CFLAGS += -DCONFIG_TITLE="\"$(name) $(revision) configuration\""
$(dir_build)/patches.o: CFLAGS += -DREVISION=\"$(revision)\" -DCOMMIT_HASH="0x$(commit)"
$(dir_build)/%.o: $(dir_source)/%.c $(bundled)
@mkdir -p "$(@D)"

View File

@@ -22,13 +22,13 @@ LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
INCLUDE := $(foreach dir,$(LIBDIRS),-I$(dir)/include)
ARCH := -mcpu=mpcore -mfloat-abi=hard -mtp=soft
CFLAGS := -Wall -Wextra -MMD -MP -marm $(ARCH) -fno-builtin -std=c11 -O2 -flto -ffast-math -mword-relocations \
ASFLAGS := -mcpu=mpcore -mfloat-abi=hard -mtp=soft
CFLAGS := -Wall -Wextra -MMD -MP -marm $(ASFLAGS) -fno-builtin -std=c11 -O2 -flto -ffast-math -mword-relocations \
-ffunction-sections -fdata-sections $(INCLUDE) -DARM11 -D_3DS
LDFLAGS := -Xlinker --defsym="__start__=0x14000000" -specs=3dsx.specs $(ARCH)
LDFLAGS := -Xlinker --defsym="__start__=0x14000000" -specs=3dsx.specs $(ASFLAGS)
objects = $(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
$(call rwildcard, $(dir_source), *.c))
$(call rwildcard, $(dir_source), *.s *.c))
.PHONY: all
all: ../$(dir_build)/$(name).cxi
@@ -48,4 +48,8 @@ $(dir_build)/memory.o : CFLAGS += -O3
$(dir_build)/%.o: $(dir_source)/%.c
@mkdir -p "$(@D)"
$(COMPILE.c) $(OUTPUT_OPTION) $<
$(dir_build)/%.o: $(dir_source)/%.s
@mkdir -p "$(@D)"
$(COMPILE.s) $(OUTPUT_OPTION) $<
include $(call rwildcard, $(dir_build), *.d)

19
injector/source/CFWInfo.h Normal file
View File

@@ -0,0 +1,19 @@
#pragma once
#include <3ds/types.h>
typedef struct __attribute__((packed))
{
char magic[4];
u8 versionMajor;
u8 versionMinor;
u8 versionBuild;
u8 flags; /* bit 0: dev branch; bit 1: is release */
u32 commitHash;
u32 config;
} CFWInfo;
void svcGetCFWInfo(CFWInfo *info);

View File

@@ -0,0 +1,9 @@
.text
.arm
.align 4
.global svcGetCFWInfo
.type svcGetCFWInfo, %function
svcGetCFWInfo:
svc 0x2e
bx lr

View File

@@ -2,13 +2,9 @@
#include "memory.h"
#include "patcher.h"
#include "ifile.h"
#include "CFWInfo.h"
#ifndef PATH_MAX
#define PATH_MAX 255
#define CONFIG(a) (((loadConfig() >> (a + 16)) & 1) != 0)
#define MULTICONFIG(a) ((loadConfig() >> (a * 2 + 6)) & 3)
#define BOOTCONFIG(a, b) ((loadConfig() >> a) & b)
#endif
static CFWInfo info;
static int memcmp(const void *buf1, const void *buf2, u32 size)
{
@@ -90,6 +86,22 @@ static int fileOpen(IFile *file, FS_ArchiveID archiveId, const char *path, int f
return IFile_Open(file, archiveId, archivePath, filePath, flags);
}
static void loadCFWInfo(void)
{
static bool infoLoaded = false;
if(!infoLoaded)
{
svcGetCFWInfo(&info);
IFile file;
if(BOOTCFG_SAFEMODE != 0 && R_SUCCEEDED(fileOpen(&file, ARCHIVE_SDMC, "/", FS_OPEN_READ))) //Init SD card if SAFE_MODE is being booted
IFile_Close(&file);
infoLoaded = true;
}
}
static bool secureInfoExists(void)
{
static bool exists = false;
@@ -107,24 +119,6 @@ static bool secureInfoExists(void)
return exists;
}
static u32 loadConfig(void)
{
static u32 config = 0;
if(!config)
{
IFile file;
if(R_SUCCEEDED(fileOpen(&file, ARCHIVE_SDMC, "/luma/config.bin", FS_OPEN_READ)))
{
u64 total;
if(R_SUCCEEDED(IFile_Read(&file, &total, &config, 4))) config |= 1 << 4;
IFile_Close(&file);
}
}
return config;
}
static void progIdToStr(char *strEnd, u64 progId)
{
while(progId)
@@ -148,12 +142,12 @@ static void loadTitleCodeSection(u64 progId, u8 *code, u32 size)
if(R_SUCCEEDED(ret))
{
u64 fileSize, total;
u64 fileSize;
ret = IFile_GetSize(&file, &fileSize);
if(R_SUCCEEDED(ret) && fileSize <= size)
{
u64 total;
ret = IFile_Read(&file, &total, code, fileSize);
IFile_Close(&file);
}
@@ -319,6 +313,8 @@ static void patchCfgGetRegion(u8 *code, u32 size, u8 regionId, u32 CFGUHandleOff
void patchCode(u64 progId, u8 *code, u32 size)
{
loadCFWInfo();
switch(progId)
{
case 0x0004003000008F02LL: // USA Menu
@@ -329,7 +325,7 @@ void patchCode(u64 progId, u8 *code, u32 size)
case 0x000400300000B102LL: // TWN Menu
{
static const u8 regionFreePattern[] = {
0x00, 0x00, 0x55, 0xE3, 0x01, 0x10, 0xA0, 0xE3
0x00, 0x00, 0x55, 0xE3, 0x01, 0x10, 0xA0
};
static const u8 regionFreePatch[] = {
0x01, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1
@@ -364,7 +360,7 @@ void patchCode(u64 progId, u8 *code, u32 size)
);
//Apply only if the updated NAND hasn't been booted
if((BOOTCONFIG(0, 3) != 0) == (BOOTCONFIG(2, 1) && CONFIG(1)))
if((BOOTCFG_NAND != 0) == (BOOTCFG_FIRM != 0 && CONFIG_USESYSFIRM))
{
static const u8 skipEshopUpdateCheckPattern[] = {
0x30, 0xB5, 0xF1, 0xB0
@@ -388,7 +384,7 @@ void patchCode(u64 progId, u8 *code, u32 size)
case 0x0004013000003202LL: // FRIENDS
{
static const u8 fpdVerPattern[] = {
0xE0, 0x1E, 0xFF, 0x2F, 0xE1, 0x01, 0x01, 0x01
0xE0, 0x1E, 0xFF, 0x2F, 0xE1, 0x01, 0x01
};
static const u8 mostRecentFpdVer = 0x06;
@@ -408,7 +404,7 @@ void patchCode(u64 progId, u8 *code, u32 size)
case 0x0004001000027000LL: // KOR MSET
case 0x0004001000028000LL: // TWN MSET
{
if(CONFIG(4))
if(CONFIG_SHOWNAND)
{
static const u16 verPattern[] = u"Ver.";
const u32 currentNand = BOOTCONFIG(0, 3);
@@ -444,12 +440,12 @@ void patchCode(u64 progId, u8 *code, u32 size)
sizeof(stopCartUpdatesPatch), 2
);
u32 cpuSetting = MULTICONFIG(1);
u32 cpuSetting = CONFIG_NEWCPU;
if(cpuSetting)
{
static const u8 cfgN3dsCpuPattern[] = {
0x00, 0x40, 0xA0, 0xE1, 0x07, 0x00
0x00, 0x40, 0xA0, 0xE1, 0x07
};
u32 *cfgN3dsCpuLoc = (u32 *)memsearch(code, cfgN3dsCpuPattern, size, sizeof(cfgN3dsCpuPattern));
@@ -468,7 +464,7 @@ void patchCode(u64 progId, u8 *code, u32 size)
case 0x0004013000001702LL: // CFG
{
static const u8 secureinfoSigCheckPattern[] = {
0x06, 0x46, 0x10, 0x48, 0xFC
0x06, 0x46, 0x10, 0x48
};
static const u8 secureinfoSigCheckPatch[] = {
0x00, 0x26
@@ -543,7 +539,7 @@ void patchCode(u64 progId, u8 *code, u32 size)
}
default:
if(CONFIG(3))
if(CONFIG_USELANGEMUANDCODE)
{
u32 tidHigh = (progId & 0xFFFFFFF000000000LL) >> 0x24;

View File

@@ -2,4 +2,18 @@
#include <3ds/types.h>
#define PATH_MAX 255
#define CONFIG(a) (((info.config >> (a + 20)) & 1) != 0)
#define MULTICONFIG(a) ((info.config >> (a * 2 + 6)) & 3)
#define BOOTCONFIG(a, b) ((info.config >> a) & b)
#define BOOTCFG_NAND BOOTCONFIG(0, 3)
#define BOOTCFG_FIRM BOOTCONFIG(2, 1)
#define BOOTCFG_SAFEMODE BOOTCONFIG(5, 1)
#define CONFIG_NEWCPU MULTICONFIG(2)
#define CONFIG_USESYSFIRM CONFIG(1)
#define CONFIG_USELANGEMUANDCODE CONFIG(3)
#define CONFIG_SHOWNAND CONFIG(4)
void patchCode(u64 progId, u8 *code, u32 size);

View File

@@ -23,7 +23,7 @@
#include "memory.h"
#include "cache.h"
extern u32 payloadSize; //defined in start.s
extern u32 payloadSize; //Defined in start.s
void main(void)
{

View File

@@ -43,4 +43,4 @@ nand_sd:
sdmmc: .ascii "SDMC"
nand_offset: .ascii "NAND" ; for rednand this should be 1
ncsd_header_offset: .ascii "NCSD" ; depends on nand manufacturer + emunand type (GW/RED)
.close
.close

View File

@@ -5,10 +5,14 @@ payload_maxsize equ 0x10000 ; Maximum size for the payload (maximum that CakeB
.create "build/reboot.bin", 0
.arm
; 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.
; Interesting registers and locations to keep in mind, set just before this code is ran:
; - r1: FIRM path in exefs.
; - r7: pointer to file object
; - *r7: vtable
; - *(vtable + 0x28): fread function
; - *(r7 + 8): file handle
mov r8, r1
pxi_wait_recv:
ldr r2, =0x44846
@@ -47,7 +51,7 @@ payload_maxsize equ 0x10000 ; Maximum size for the payload (maximum that CakeB
cmp r4, #0
movne r3, #0x12000 ; Skip the first 0x12000 bytes.
moveq r3, payload_maxsize
ldr r6, [sp, #0x3A8-0x198]
ldr r6, [r7]
ldr r6, [r6, #0x28]
blx r6
cmp r4, #0
@@ -55,8 +59,7 @@ payload_maxsize equ 0x10000 ; Maximum size for the payload (maximum that CakeB
bne read_payload ; Go read the real payload.
; Copy the low TID (in UTF-16) of the wanted firm to the 5th byte of the payload
add r0, sp, #0x3A8 - 0x70
add r0, 0x1A
add r0, r8, 0x1A
add r1, r0, #0x10
ldr r2, =payload_addr + 4
copy_TID_low:
@@ -75,7 +78,7 @@ payload_maxsize equ 0x10000 ; Maximum size for the payload (maximum that CakeB
goto_reboot:
; Jump to reboot code
ldr r0, =(kernelcode_start - goto_reboot - 12)
add r0, pc
add r0, pc ; pc is two instructions ahead of the instruction being executed (12 = 2*4 + 4)
swi 0x7B
die:
@@ -122,4 +125,4 @@ dat_fname: .dcw "sdmc:/Luma3DS.dat"
bx r0
.pool
.close
.close

47
patches/svcGetCFWInfo.s Normal file
View File

@@ -0,0 +1,47 @@
;
; This file is part of Luma3DS
; Copyright (C) 2016 Aurora Wright, TuxSH
;
; This program is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, either version 3 of the License, or
; (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program. If not, see <http://www.gnu.org/licenses/>.
;
; Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
; reasonable legal notices or author attributions in that material or in the Appropriate Legal
; Notices displayed by works containing it.
;
.arm.little
.create "build/svcGetCFWInfo.bin", 0
.arm
adr r1, infoStart
add r2, r0, #(infoEnd - infoStart)
loop:
ldrb r3, [r1], #1
strbt r3, [r0], #1
cmp r0, r2
blo loop
bx lr
.pool
infoStart:
.ascii "LUMA" ; magic
.word 0 ; version
.word 0 ; truncated commit hash
.word 0 ; config
infoEnd:
.close

View File

@@ -43,4 +43,4 @@
#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_A | BUTTON_SELECT)
#define MENU_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN | BUTTON_A | BUTTON_START)
#define PIN_BUTTONS (BUTTON_A | BUTTON_B | BUTTON_X | BUTTON_Y | BUTTON_START)
#define PIN_BUTTONS (BUTTON_A | BUTTON_B | BUTTON_X | BUTTON_Y | BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN | BUTTON_START)

View File

@@ -21,13 +21,50 @@
*/
#include "config.h"
#include "memory.h"
#include "fs.h"
#include "utils.h"
#include "screen.h"
#include "draw.h"
#include "fs.h"
#include "buttons.h"
#include "pin.h"
void configureCFW(const char *configPath)
bool readConfig(void)
{
if(fileRead(&configData, CONFIG_PATH) != sizeof(cfgData) ||
memcmp(configData.magic, "CONF", 4) != 0 ||
configData.formatVersionMajor != CONFIG_VERSIONMAJOR ||
configData.formatVersionMinor != CONFIG_VERSIONMINOR)
{
configData.config = 0;
return false;
}
return true;
}
void writeConfig(ConfigurationStatus needConfig, u32 configTemp)
{
/* If the configuration is different from previously, overwrite it.
Just the no-forcing flag being set is not enough */
if(needConfig == CREATE_CONFIGURATION || (configTemp & 0xFFFFFFEF) != configData.config)
{
if(needConfig == CREATE_CONFIGURATION)
{
memcpy(configData.magic, "CONF", 4);
configData.formatVersionMajor = CONFIG_VERSIONMAJOR;
configData.formatVersionMinor = CONFIG_VERSIONMINOR;
}
//Merge the new options and new boot configuration
configData.config = (configData.config & 0xFFFFFFC0) | (configTemp & 0x3F);
if(!fileWrite(&configData, CONFIG_PATH, sizeof(cfgData)))
error("Error writing the configuration file");
}
}
void configMenu(bool oldPinStatus)
{
initScreens();
@@ -35,6 +72,7 @@ void configureCFW(const char *configPath)
drawString("Press A to select, START to save", 10, 30, COLOR_WHITE);
const char *multiOptionsText[] = { "Screen brightness: 4( ) 3( ) 2( ) 1( )",
"PIN lock: Off( ) 4( ) 6( ) 8( ) digits",
"New 3DS CPU: Off( ) Clock( ) L2( ) Clock+L2( )" };
const char *singleOptionsText[] = { "( ) Autoboot SysNAND",
@@ -43,8 +81,7 @@ void configureCFW(const char *configPath)
"( ) Enable region/language emu. and ext. .code",
"( ) Show current NAND in System Settings",
"( ) Show GBA boot screen in patched AGB_FIRM",
"( ) Display splash screen before payloads",
"( ) Use a PIN" };
"( ) Display splash screen before payloads" };
struct multiOption {
int posXs[4];
@@ -52,6 +89,7 @@ void configureCFW(const char *configPath)
u32 enabled;
} multiOptions[] = {
{ .posXs = {21, 26, 31, 36} },
{ .posXs = {14, 19, 24, 29} },
{ .posXs = {17, 26, 32, 44} }
};
@@ -184,22 +222,22 @@ void configureCFW(const char *configPath)
}
}
u32 oldPinLength = CONFIG_PIN;
//Preserve the last-used boot options (last 12 bits)
config &= 0x3F;
configData.config &= 0x3F;
//Parse and write the new configuration
for(u32 i = 0; i < multiOptionsAmount; i++)
config |= multiOptions[i].enabled << (i * 2 + 6);
configData.config |= multiOptions[i].enabled << (i * 2 + 6);
for(u32 i = 0; i < singleOptionsAmount; i++)
config |= (singleOptions[i].enabled ? 1 : 0) << (i + 16);
configData.config |= (singleOptions[i].enabled ? 1 : 0) << (i + 20);
if(!fileWrite(&config, configPath, 4))
{
createDirectory("luma");
if(!fileWrite(&config, configPath, 4))
error("Error writing the configuration file");
}
if(CONFIG_PIN != 0) newPin(oldPinStatus && CONFIG_PIN == oldPinLength);
else if(oldPinStatus) fileDelete(PIN_PATH);
//Wait for the pressed buttons to change
while(HID_PAD == BUTTON_START);
while(HID_PAD & PIN_BUTTONS);
chrono(2);
}

View File

@@ -24,10 +24,44 @@
#include "types.h"
#define CONFIG(a) (((config >> (a + 16)) & 1) != 0)
#define MULTICONFIG(a) ((config >> (a * 2 + 6)) & 3)
#define BOOTCONFIG(a, b) ((config >> a) & b)
#define CONFIG(a) (((configData.config >> (a + 20)) & 1) != 0)
#define MULTICONFIG(a) ((configData.config >> (a * 2 + 6)) & 3)
#define BOOTCONFIG(a, b) ((configData.config >> a) & b)
extern u32 config;
#define CONFIG_PATH "/luma/config.bin"
#define CONFIG_VERSIONMAJOR 1
#define CONFIG_VERSIONMINOR 2
void configureCFW(const char *configPath);
#define BOOTCFG_NAND BOOTCONFIG(0, 3)
#define BOOTCFG_FIRM BOOTCONFIG(2, 1)
#define BOOTCFG_A9LH BOOTCONFIG(3, 1)
#define BOOTCFG_NOFORCEFLAG BOOTCONFIG(4, 1)
#define BOOTCFG_SAFEMODE BOOTCONFIG(5, 1)
#define CONFIG_BRIGHTNESS MULTICONFIG(0)
#define CONFIG_PIN MULTICONFIG(1)
#define CONFIG_AUTOBOOTSYS CONFIG(0)
#define CONFIG_USESYSFIRM CONFIG(1)
#define CONFIG_USESECONDEMU CONFIG(2)
#define CONFIG_SHOWGBABOOT CONFIG(5)
#define CONFIG_PAYLOADSPLASH CONFIG(6)
typedef struct __attribute__((packed))
{
char magic[4];
u16 formatVersionMajor, formatVersionMinor;
u32 config;
} cfgData;
typedef enum ConfigurationStatus
{
DONT_CONFIGURE = 0,
MODIFY_CONFIGURATION = 1,
CREATE_CONFIGURATION = 2
} ConfigurationStatus;
extern cfgData configData;
bool readConfig(void);
void writeConfig(ConfigurationStatus needConfig, u32 configTemp);
void configMenu(bool oldPinStatus);

View File

@@ -457,14 +457,13 @@ void arm9Loader(u8 *arm9Section)
}
}
void computePINHash(u8 out[32], u8 *in, u32 blockCount)
void computePinHash(u8 *out, u8 *in)
{
u8 __attribute__((aligned(4))) cid[0x10];
u8 __attribute__((aligned(4))) cipherText[0x10];
sdmmc_get_cid(1, (u32 *)cid);
aes_use_keyslot(4); // console-unique keyslot which keys are set by the Arm9 bootROM
aes(cipherText, in, blockCount, cid, AES_CBC_ENCRYPT_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_use_keyslot(4); //Console-unique keyslot whose keys are set by the ARM9 bootROM
aes(cipherText, in, 1, cid, AES_CBC_ENCRYPT_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
sha(out, cipherText, 0x10, SHA_256_MODE);
}

View File

@@ -100,8 +100,7 @@
#define SHA_1_HASH_SIZE (160 / 8)
extern u32 emuOffset;
extern bool isN3DS;
extern bool isDevUnit;
extern bool isN3DS, isDevUnit;
extern FirmwareSource firmSource;
void ctrNandInit(void);
@@ -109,5 +108,4 @@ u32 ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf);
void setRSAMod0DerivedKeys(void);
void decryptExeFs(u8 *inbuf);
void arm9Loader(u8 *arm9Section);
void computePINHash(u8 out[32], u8 *in, u32 blockCount);
void computePinHash(u8 *out, u8 *in);

View File

@@ -26,24 +26,16 @@
*/
#include "draw.h"
#include "strings.h"
#include "screen.h"
#include "utils.h"
#include "fs.h"
#include "font.h"
static inline int strlen(const char *string)
{
char *stringEnd = (char *)string;
while(*stringEnd) stringEnd++;
return stringEnd - string;
}
bool loadSplash(void)
{
//Don't delay boot nor init the screens if no splash image is on the SD
if(getFileSize("/luma/splash.bin") + getFileSize("/luma/splash.bin") == 0)
if(getFileSize("/luma/splash.bin") + getFileSize("/luma/splashbottom.bin") == 0)
return false;
initScreens();

View File

@@ -25,12 +25,12 @@
#include "fatfs/sdmmc/sdmmc.h"
#include "../build/emunandpatch.h"
void locateEmuNAND(u32 *off, u32 *head, FirmwareSource *emuNAND)
void locateEmuNand(u32 *off, u32 *head, FirmwareSource *emuNand)
{
static u8 temp[0x200];
const u32 nandSize = getMMCDevice(0)->total_size;
u32 nandOffset = *emuNAND == FIRMWARE_EMUNAND ? 0 :
u32 nandOffset = *emuNand == FIRMWARE_EMUNAND ? 0 :
(nandSize > 0x200000 ? 0x400000 : 0x200000);
//Check for RedNAND
@@ -53,37 +53,37 @@ void locateEmuNAND(u32 *off, u32 *head, FirmwareSource *emuNAND)
or to SysNAND if there isn't any */
else
{
*emuNAND = (*emuNAND == FIRMWARE_EMUNAND2) ? FIRMWARE_EMUNAND : FIRMWARE_SYSNAND;
if(*emuNAND) locateEmuNAND(off, head, emuNAND);
*emuNand = (*emuNand == FIRMWARE_EMUNAND2) ? FIRMWARE_EMUNAND : FIRMWARE_SYSNAND;
if(*emuNand) locateEmuNand(off, head, emuNand);
}
}
static inline void *getEmuCode(u8 *pos, u32 size)
static inline void *getFreeK9Space(u8 *pos, u32 size)
{
const u8 pattern[] = {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00};
//Looking for the last free space before Process9
return memsearch(pos + 0x13500, pattern, size - 0x13500, 6) + 0x455;
return memsearch(pos + 0x13500, pattern, size - 0x13500, sizeof(pattern)) + 0x455;
}
static inline u32 getSDMMC(u8 *pos, u32 size)
static inline 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);
const u8 *off = memsearch(pos, pattern, size, sizeof(pattern));
return *(u32 *)(off + 9) + *(u32 *)(off + 0xD);
}
static inline void patchNANDRW(u8 *pos, u32 size, u32 branchOffset)
static inline void patchNandRw(u8 *pos, u32 size, u32 branchOffset)
{
const u16 nandRedir[2] = {0x4C00, 0x47A0};
//Look for read/write code
const u8 pattern[] = {0x1E, 0x00, 0xC8, 0x05};
u16 *readOffset = (u16 *)memsearch(pos, pattern, size, 4) - 3,
*writeOffset = (u16 *)memsearch((u8 *)(readOffset + 5), pattern, 0x100, 4) - 3;
u16 *readOffset = (u16 *)memsearch(pos, pattern, size, sizeof(pattern)) - 3,
*writeOffset = (u16 *)memsearch((u8 *)(readOffset + 5), pattern, 0x100, sizeof(pattern)) - 3;
*readOffset = nandRedir[0];
readOffset[1] = nandRedir[1];
@@ -93,40 +93,38 @@ static inline void patchNANDRW(u8 *pos, u32 size, u32 branchOffset)
((u32 *)writeOffset)[1] = branchOffset;
}
static inline void patchMPU(u8 *pos, u32 size)
static inline void patchMpu(u8 *pos, u32 size)
{
const u32 mpuPatch[3] = {0x00360003, 0x00200603, 0x001C0603};
//Look for MPU pattern
const u8 pattern[] = {0x03, 0x00, 0x24, 0x00};
u32 *off = (u32 *)memsearch(pos, pattern, size, 4);
u32 *off = (u32 *)memsearch(pos, pattern, size, sizeof(pattern));
off[0] = mpuPatch[0];
off[6] = mpuPatch[1];
off[9] = mpuPatch[2];
off[0] = 0x00360003;
off[6] = 0x00200603;
off[9] = 0x001C0603;
}
void patchEmuNAND(u8 *arm9Section, u32 arm9SectionSize, u8 *process9Offset, u32 process9Size, u32 emuOffset, u32 emuHeader, u32 branchAdditive)
void patchEmuNand(u8 *arm9Section, u32 arm9SectionSize, u8 *process9Offset, u32 process9Size, u32 emuHeader, u32 branchAdditive)
{
//Copy emuNAND code
void *emuCodeOffset = getEmuCode(arm9Section, arm9SectionSize);
memcpy(emuCodeOffset, emunand, emunand_size);
void *freeK9Space = getFreeK9Space(arm9Section, arm9SectionSize);
memcpy(freeK9Space, emunand, emunand_size);
//Add the data of the found emuNAND
u32 *pos_offset = (u32 *)memsearch(emuCodeOffset, "NAND", emunand_size, 4),
*pos_header = (u32 *)memsearch(emuCodeOffset, "NCSD", emunand_size, 4);
*pos_offset = emuOffset;
*pos_header = emuHeader;
u32 *posOffset = (u32 *)memsearch(freeK9Space, "NAND", emunand_size, 4),
*posHeader = (u32 *)memsearch(freeK9Space, "NCSD", emunand_size, 4);
*posOffset = emuOffset;
*posHeader = emuHeader;
//Find and add the SDMMC struct
u32 *pos_sdmmc = (u32 *)memsearch(emuCodeOffset, "SDMC", emunand_size, 4);
*pos_sdmmc = getSDMMC(process9Offset, process9Size);
u32 *posSdmmc = (u32 *)memsearch(freeK9Space, "SDMC", emunand_size, 4);
*posSdmmc = getSdmmc(process9Offset, process9Size);
//Add emuNAND hooks
u32 branchOffset = (u32)emuCodeOffset - branchAdditive;
patchNANDRW(process9Offset, process9Size, branchOffset);
u32 branchOffset = (u32)freeK9Space - branchAdditive;
patchNandRw(process9Offset, process9Size, branchOffset);
//Set MPU for emu code region
patchMPU(arm9Section, arm9SectionSize);
patchMpu(arm9Section, arm9SectionSize);
}

View File

@@ -26,5 +26,7 @@
#define NCSD_MAGIC 0x4453434E
void locateEmuNAND(u32 *off, u32 *head, FirmwareSource *emuNAND);
void patchEmuNAND(u8 *arm9Section, u32 arm9SectionSize, u8 *process9Offset, u32 process9Size, u32 emuOffset, u32 emuHeader, u32 branchAdditive);
extern u32 emuOffset;
void locateEmuNand(u32 *off, u32 *head, FirmwareSource *emuNand);
void patchEmuNand(u8 *arm9Section, u32 arm9SectionSize, u8 *process9Offset, u32 process9Size, u32 emuHeader, u32 branchAdditive);

View File

@@ -2266,7 +2266,7 @@ FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too many S
if (res != FR_OK) return res;
dp->blk_ofs = dp->dptr - SZDIRE * (nent - 1); /* Set block position */
if (dp->obj.stat & 4) { /* Has the sub-directory been stretched? */
if (dp->obj.sclust != 0 && (dp->obj.stat & 4)) { /* Has the sub-directory been stretched? */
dp->obj.stat &= 3;
dp->obj.objsize += (DWORD)fs->csize * SS(fs); /* Increase object size by cluster size */
res = fill_fat_chain(&dp->obj); /* Complement FAT chain if needed */
@@ -2430,7 +2430,7 @@ void get_fileinfo ( /* No return code */
}
#endif
if (i >= _MAX_LFN) { i = 0; break; } /* No LFN if buffer overflow */
fno->fname[i++] = (char)w;
fno->fname[i++] = (TCHAR)w;
}
fno->fname[i] = 0; /* Terminate the LFN */
}
@@ -3680,7 +3680,9 @@ FRESULT f_sync (
FATFS *fs;
DWORD tm;
BYTE *dir;
#if _FS_EXFAT
DEF_NAMBUF
#endif
res = validate(fp, &fs); /* Check validity of the object */
if (res == FR_OK) {
@@ -3990,7 +3992,7 @@ FRESULT f_lseek (
#if !_FS_TINY
#if !_FS_READONLY
if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */
if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fp, FR_DISK_ERR);
if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);
fp->flag &= ~FA_DIRTY;
}
#endif
@@ -4007,6 +4009,9 @@ FRESULT f_lseek (
/* Normal Seek */
{
#if _FS_EXFAT
if (fs->fs_type != FS_EXFAT && ofs >= 0x100000000) ofs = 0xFFFFFFFF; /* Clip at 4GiB-1 if at FATxx */
#endif
if (ofs > fp->obj.objsize && (_FS_READONLY || !(fp->flag & FA_WRITE))) { /* In read-only mode, clip offset with the file size */
ofs = fp->obj.objsize;
}
@@ -4016,7 +4021,7 @@ FRESULT f_lseek (
bcs = (DWORD)fs->csize * SS(fs); /* Cluster size (byte) */
if (ifptr > 0 &&
(ofs - 1) / bcs >= (ifptr - 1) / bcs) { /* When seek to same or following cluster, */
fp->fptr = (ifptr - 1) & ~(bcs - 1); /* start from the current cluster */
fp->fptr = (ifptr - 1) & ~(QWORD)(bcs - 1); /* start from the current cluster */
ofs -= fp->fptr;
clst = fp->clust;
} else { /* When seek to back cluster, */
@@ -4033,11 +4038,16 @@ FRESULT f_lseek (
}
if (clst != 0) {
while (ofs > bcs) { /* Cluster following loop */
ofs -= bcs; fp->fptr += bcs;
#if !_FS_READONLY
if (fp->flag & FA_WRITE) { /* Check if in write mode or not */
if (_FS_EXFAT && fp->fptr > fp->obj.objsize) { /* No FAT chain object needs correct objsize to generate FAT value */
fp->obj.objsize = fp->fptr;
fp->flag |= FA_MODIFIED;
}
clst = create_chain(&fp->obj, clst); /* Force stretch if in write mode */
if (clst == 0) { /* When disk gets full, clip file size */
ofs = bcs; break;
ofs = 0; break;
}
} else
#endif
@@ -4045,8 +4055,6 @@ FRESULT f_lseek (
if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR);
if (clst <= 1 || clst >= fs->n_fatent) ABORT(fs, FR_INT_ERR);
fp->clust = clst;
fp->fptr += bcs;
ofs -= bcs;
}
fp->fptr += ofs;
if (ofs % SS(fs)) {
@@ -5298,7 +5306,7 @@ FRESULT f_mkfs (
#if _FS_EXFAT
if (fmt == FS_EXFAT) { /* Create an exFAT volume */
DWORD sum, szb_bit, szb_case;
DWORD szb_bit, szb_case, sum, nb, cl;
WCHAR ch, si;
UINT j, st;
BYTE b;
@@ -5363,32 +5371,37 @@ FRESULT f_mkfs (
tbl[1] = (szb_case + au * ss - 1) / (au * ss); /* Number of up-case clusters */
/* Initialize the allocation bitmap */
mem_set(buf, 0, szb_buf); /* Set in-use flags of bitmap, up-case and root dir */
for (i = 0, n = tbl[0] + tbl[1] + tbl[2]; n >= 8; buf[i++] = 0xFF, n -= 8) ;
for (b = 1; n; buf[i] |= b, b <<= 1, n--) ;
sect = b_data; n = (szb_bit + ss - 1) / ss; /* Start of bitmap and number of the sectors */
do { /* Fill allocation bitmap sectors */
ns = (n > sz_buf) ? sz_buf : n;
nb = tbl[0] + tbl[1] + tbl[2]; /* Number of clusters in-use by system */
do {
mem_set(buf, 0, szb_buf);
for (i = 0; nb >= 8 && i < szb_buf; buf[i++] = 0xFF, nb -= 8) ;
for (b = 1; nb && i < szb_buf; buf[i] |= b, b <<= 1, nb--) ;
ns = (n > sz_buf) ? sz_buf : n; /* Write the buffered data */
if (disk_write(pdrv, buf, sect, ns) != RES_OK) return FR_DISK_ERR;
sect += ns;
mem_set(buf, 0, ss);
} while (n -= ns);
sect += ns; n -= ns;
} while (n);
/* Initialize the FAT */
st_qword(buf, 0xFFFFFFFFFFFFFFF8); /* Entry 0 and 1 */
for (j = 0, i = 2; j < 3; j++) { /* Set entries of bitmap, up-case and root dir */
for (n = tbl[j]; n; n--) {
st_dword(buf + i * 4, (n >= 2) ? i + 1 : 0xFFFFFFFF);
i++;
}
}
sect = b_fat; n = sz_fat; /* Start of FAT and number of the sectors */
do { /* Fill FAT sectors */
ns = (n > sz_buf) ? sz_buf : n;
j = nb = cl = 0;
do {
mem_set(buf, 0, szb_buf); i = 0;
if (cl == 0) { /* Set entry 0 and 1 */
st_dword(buf + i, 0xFFFFFFF8); i += 4; cl++;
st_dword(buf + i, 0xFFFFFFFF); i += 4; cl++;
}
do { /* Create chains of bitmap, up-case and root dir */
while (nb && i < szb_buf) { /* Create a chain */
st_dword(buf + i, (nb > 1) ? cl + 1 : 0xFFFFFFFF);
i += 4; cl++; nb--;
}
if (!nb && j < 3) nb = tbl[j++]; /* Next chain */
} while (nb && i < szb_buf);
ns = (n > sz_buf) ? sz_buf : n; /* Write the buffered data */
if (disk_write(pdrv, buf, sect, ns) != RES_OK) return FR_DISK_ERR;
sect += ns;
mem_set(buf, 0, ss);
} while (n -= ns);
sect += ns; n -= ns;
} while (n);
/* Initialize the root directory */
mem_set(buf, 0, ss);

View File

@@ -1,4 +1,3 @@
#pragma once
#include <stdbool.h>
#include "../../types.h"

View File

@@ -35,24 +35,25 @@
#include "pin.h"
#include "../build/injector.h"
extern u16 launchedFirmTIDLow[8]; //defined in start.s
extern u16 launchedFirmTidLow[8]; //Defined in start.s
static firmHeader *const firm = (firmHeader *)0x24000000;
static const firmSectionHeader *section;
u32 config,
emuOffset;
u32 emuOffset;
bool isN3DS, isDevUnit;
bool isN3DS,
isDevUnit,
isFirmlaunch;
cfgData configData;
FirmwareSource firmSource;
void main(void)
{
bool isFirmlaunch,
isA9lh;
bool isA9lh;
u32 newConfig,
u32 configTemp,
emuHeader;
FirmwareType firmType;
@@ -68,40 +69,36 @@ void main(void)
//Mount filesystems. CTRNAND will be mounted only if/when needed
mountFs();
const char configPath[] = "/luma/config.bin";
//Attempt to read the configuration file
needConfig = fileRead(&config, configPath) ? MODIFY_CONFIGURATION : CREATE_CONFIGURATION;
needConfig = readConfig() ? MODIFY_CONFIGURATION : CREATE_CONFIGURATION;
//Determine if this is a firmlaunch boot
if(launchedFirmTIDLow[5] != 0)
if(launchedFirmTidLow[5] != 0)
{
if(needConfig == CREATE_CONFIGURATION) mcuReboot();
isFirmlaunch = true;
//'0' = NATIVE_FIRM, '1' = TWL_FIRM, '2' = AGB_FIRM
firmType = launchedFirmTIDLow[7] == u'3' ? SAFE_FIRM : (FirmwareType)(launchedFirmTIDLow[5] - u'0');
if(needConfig == CREATE_CONFIGURATION) mcuReboot();
nandType = (FirmwareSource)BOOTCONFIG(0, 3);
firmSource = (FirmwareSource)BOOTCONFIG(2, 1);
isA9lh = BOOTCONFIG(3, 1) != 0;
//'0' = NATIVE_FIRM, '1' = TWL_FIRM, '2' = AGB_FIRM
firmType = launchedFirmTidLow[7] == u'3' ? SAFE_FIRM : (FirmwareType)(launchedFirmTidLow[5] - u'0');
nandType = (FirmwareSource)BOOTCFG_NAND;
firmSource = (FirmwareSource)BOOTCFG_FIRM;
isA9lh = BOOTCFG_A9LH != 0;
}
else
{
//Get pressed buttons
u32 pressed = HID_PAD;
isFirmlaunch = false;
firmType = NATIVE_FIRM;
//Determine if booting with A9LH
isA9lh = !PDN_SPI_CNT;
//Determine if the user chose to use the SysNAND FIRM as default for a R boot
bool useSysAsDefault = isA9lh ? CONFIG(1) : false;
//Get pressed buttons
u32 pressed = HID_PAD;
newConfig = (u32)isA9lh << 3;
//Save old options and begin saving the new boot configuration
configTemp = (configData.config & 0xFFFFFFC0) | ((u32)isA9lh << 3);
//If it's a MCU reboot, try to force boot options
if(isA9lh && CFG_BOOTENV)
@@ -110,19 +107,19 @@ void main(void)
if(CFG_BOOTENV == 7)
{
nandType = FIRMWARE_SYSNAND;
firmSource = useSysAsDefault ? FIRMWARE_SYSNAND : (FirmwareSource)BOOTCONFIG(2, 1);
firmSource = CONFIG_USESYSFIRM ? FIRMWARE_SYSNAND : (FirmwareSource)BOOTCFG_FIRM;
needConfig = DONT_CONFIGURE;
//Flag to prevent multiple boot options-forcing
newConfig |= 1 << 4;
configTemp |= 1 << 4;
}
/* Else, force the last used boot options unless a button is pressed
or the no-forcing flag is set */
else if(!pressed && !BOOTCONFIG(4, 1))
else if(needConfig != CREATE_CONFIGURATION && !pressed && !BOOTCFG_NOFORCEFLAG)
{
nandType = (FirmwareSource)BOOTCONFIG(0, 3);
firmSource = (FirmwareSource)BOOTCONFIG(2, 1);
nandType = (FirmwareSource)BOOTCFG_NAND;
firmSource = (FirmwareSource)BOOTCFG_FIRM;
needConfig = DONT_CONFIGURE;
}
}
@@ -130,23 +127,14 @@ void main(void)
//Boot options aren't being forced
if(needConfig != DONT_CONFIGURE)
{
PINData pin;
bool pinExists = CONFIG(7) && readPin(&pin);
//If we get here we should check the PIN (if it exists) in all cases
if(pinExists) verifyPin(&pin);
bool pinExists = CONFIG_PIN != 0 && verifyPin();
//If no configuration file exists or SELECT is held, load configuration menu
bool shouldLoadConfigurationMenu = needConfig == CREATE_CONFIGURATION || ((pressed & BUTTON_SELECT) && !(pressed & BUTTON_L1));
bool shouldLoadConfigMenu = needConfig == CREATE_CONFIGURATION || ((pressed & BUTTON_SELECT) && !(pressed & BUTTON_L1));
if(shouldLoadConfigurationMenu)
if(shouldLoadConfigMenu)
{
configureCFW(configPath);
if(!pinExists && CONFIG(7)) newPin();
chrono(2);
configMenu(pinExists);
//Update pressed buttons
pressed = HID_PAD;
@@ -156,37 +144,50 @@ void main(void)
{
nandType = FIRMWARE_SYSNAND;
firmSource = FIRMWARE_SYSNAND;
//Flag to tell loader to init SD
configTemp |= 1 << 5;
//If the PIN has been verified, wait to make it easier to press the SAFE_MODE combo
if(pinExists && !shouldLoadConfigMenu)
{
while(HID_PAD & PIN_BUTTONS);
chrono(2);
}
}
else
{
if(CONFIG(6) && loadSplash()) pressed = HID_PAD;
if(CONFIG_PAYLOADSPLASH && loadSplash()) pressed = HID_PAD;
/* If L and R/A/Select or one of the single payload buttons are pressed,
chainload an external payload (the PIN, if any, has been verified)*/
chainload an external payload */
bool shouldLoadPayload = (pressed & SINGLE_PAYLOAD_BUTTONS) || ((pressed & BUTTON_L1) && (pressed & L_PAYLOAD_BUTTONS));
if(shouldLoadPayload) loadPayload(pressed);
if(!CONFIG(6)) loadSplash();
if(!CONFIG_PAYLOADSPLASH) loadSplash();
//Determine if the user chose to use the SysNAND FIRM as default for a R boot
bool useSysAsDefault = isA9lh ? CONFIG_USESYSFIRM : false;
//If R is pressed, boot the non-updated NAND with the FIRM of the opposite one
if(pressed & BUTTON_R1)
{
nandType = (useSysAsDefault) ? FIRMWARE_EMUNAND : FIRMWARE_SYSNAND;
firmSource = (useSysAsDefault) ? FIRMWARE_SYSNAND : FIRMWARE_EMUNAND;
nandType = useSysAsDefault ? FIRMWARE_EMUNAND : FIRMWARE_SYSNAND;
firmSource = useSysAsDefault ? FIRMWARE_SYSNAND : FIRMWARE_EMUNAND;
}
/* Else, boot the NAND the user set to autoboot or the opposite one, depending on L,
with their own FIRM */
else
{
nandType = (CONFIG(0) != !(pressed & BUTTON_L1)) ? FIRMWARE_EMUNAND : FIRMWARE_SYSNAND;
nandType = (CONFIG_AUTOBOOTSYS != !(pressed & BUTTON_L1)) ? FIRMWARE_EMUNAND : FIRMWARE_SYSNAND;
firmSource = nandType;
}
/* If we're booting emuNAND the second emuNAND is set as default and B isn't pressed,
or vice-versa, boot the second emuNAND */
if(nandType != FIRMWARE_SYSNAND && (CONFIG(2) == !(pressed & BUTTON_B))) nandType = FIRMWARE_EMUNAND2;
if(nandType != FIRMWARE_SYSNAND && (CONFIG_USESECONDEMU == !(pressed & BUTTON_B))) nandType = FIRMWARE_EMUNAND2;
}
}
}
@@ -194,31 +195,21 @@ void main(void)
//If we need to boot emuNAND, make sure it exists
if(nandType != FIRMWARE_SYSNAND)
{
locateEmuNAND(&emuOffset, &emuHeader, &nandType);
locateEmuNand(&emuOffset, &emuHeader, &nandType);
if(nandType == FIRMWARE_SYSNAND) firmSource = FIRMWARE_SYSNAND;
}
//Same if we're using emuNAND as the FIRM source
else if(firmSource != FIRMWARE_SYSNAND)
locateEmuNAND(&emuOffset, &emuHeader, &firmSource);
locateEmuNand(&emuOffset, &emuHeader, &firmSource);
if(!isFirmlaunch)
{
newConfig |= (u32)nandType | ((u32)firmSource << 2);
/* If the boot configuration is different from previously, overwrite it.
Just the no-forcing flag being set is not enough */
if((newConfig & 0x2F) != (config & 0x3F))
{
//Preserve user settings (last 26 bits)
newConfig |= config & 0xFFFFFFC0;
if(!fileWrite(&newConfig, configPath, 4))
error("Error writing the configuration file");
}
configTemp |= (u32)nandType | ((u32)firmSource << 2);
writeConfig(needConfig, configTemp);
}
u32 firmVersion = loadFirm(firmType);
u32 firmVersion = loadFirm(&firmType, firmSource);
switch(firmType)
{
@@ -226,7 +217,8 @@ void main(void)
patchNativeFirm(firmVersion, nandType, emuHeader, isA9lh);
break;
case SAFE_FIRM:
patchSafeFirm();
case NATIVE_FIRM1X2X:
if(isA9lh) patch1x2xNativeAndSafeFirm();
break;
default:
//Skip patching on unsupported O3DS AGB/TWL FIRMs
@@ -234,25 +226,41 @@ void main(void)
break;
}
launchFirm(firmType, isFirmlaunch);
launchFirm(firmType);
}
static inline u32 loadFirm(FirmwareType firmType)
static inline u32 loadFirm(FirmwareType *firmType, FirmwareSource firmSource)
{
section = firm->section;
//Load FIRM from CTRNAND, unless it's an O3DS and we're loading a pre-5.0 NATIVE FIRM
u32 firmVersion = firmRead(firm, (u32)firmType);
//Load FIRM from CTRNAND
u32 firmVersion = firmRead(firm, (u32)*firmType);
if(!isN3DS && firmType == NATIVE_FIRM && firmVersion < 0x25)
if(!isN3DS && *firmType == NATIVE_FIRM)
{
if(!fileRead(firm, "/luma/firmware.bin") || (((u32)section[2].address >> 8) & 0xFF) != 0x68)
error("An old unsupported FIRM has been detected.\nCopy firmware.bin in /luma to boot");
if(firmVersion < 0x18)
{
//We can't boot < 3.x EmuNANDs
if(firmSource != FIRMWARE_SYSNAND)
error("An old unsupported EmuNAND has been detected.\nLuma3DS is unable to boot it");
//No assumption regarding FIRM version
firmVersion = 0xffffffff;
if(BOOTCFG_SAFEMODE != 0) error("SAFE_MODE is not supported on 1.x/2.x FIRM");
*firmType = NATIVE_FIRM1X2X;
}
//We can't boot a 3.x/4.x NATIVE_FIRM, load one from SD
else if(firmVersion < 0x25)
{
if(!fileRead(firm, "/luma/firmware.bin") || section[2].address != (u8 *)0x8006800)
error("An old unsupported FIRM has been detected.\nCopy firmware.bin in /luma to boot");
//No assumption regarding FIRM version
firmVersion = 0xFFFFFFFF;
}
}
else decryptExeFs((u8 *)firm);
if(firmVersion != 0xFFFFFFFF) decryptExeFs((u8 *)firm);
return firmVersion;
}
@@ -260,6 +268,7 @@ static inline u32 loadFirm(FirmwareType firmType)
static inline void patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, bool isA9lh)
{
u8 *arm9Section = (u8 *)firm + section[2].offset;
u8 *arm11Section1 = (u8 *)firm + section[1].offset;
if(isN3DS)
{
@@ -276,6 +285,10 @@ static inline void patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32
process9MemAddr;
u8 *process9Offset = getProcess9(arm9Section + 0x15000, section[2].size - 0x15000, &process9Size, &process9MemAddr);
//Find Kernel11 SVC table and free space locations
u8 *freeK11Space;
u32 *arm11SvcTable = getKernel11Info(arm11Section1, section[1].size, &freeK11Space);
//Apply signature patches
patchSignatureChecks(process9Offset, process9Size);
@@ -283,7 +296,7 @@ static inline void patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32
if(nandType != FIRMWARE_SYSNAND)
{
u32 branchAdditive = (u32)firm + section[2].offset - (u32)section[2].address;
patchEmuNAND(arm9Section, section[2].size, process9Offset, process9Size, emuOffset, emuHeader, branchAdditive);
patchEmuNand(arm9Section, section[2].size, process9Offset, process9Size, emuHeader, branchAdditive);
}
//Apply FIRM0/1 writes patches on sysNAND to protect A9LH
@@ -299,8 +312,10 @@ static inline void patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32
patchTitleInstallMinVersionCheck(process9Offset, process9Size);
//Restore svcBackdoor
reimplementSvcBackdoor((u8 *)firm + section[1].offset, section[1].size);
reimplementSvcBackdoor(arm11Section1, arm11SvcTable, &freeK11Space);
}
implementSvcGetCFWInfo(arm11Section1, arm11SvcTable, &freeK11Space);
}
static inline void patchLegacyFirm(FirmwareType firmType)
@@ -315,7 +330,7 @@ static inline void patchLegacyFirm(FirmwareType firmType)
applyLegacyFirmPatches((u8 *)firm, firmType);
}
static inline void patchSafeFirm(void)
static inline void patch1x2xNativeAndSafeFirm(void)
{
u8 *arm9Section = (u8 *)firm + section[2].offset;
@@ -327,28 +342,44 @@ static inline void patchSafeFirm(void)
patchFirmWrites(arm9Section, section[2].size);
}
else patchFirmWriteSafe(arm9Section, section[2].size);
else patchOldFirmWrites(arm9Section, section[2].size);
}
static inline void copySection0AndInjectLoader(void)
static inline void copySection0AndInjectSystemModules(void)
{
u8 *arm11Section0 = (u8 *)firm + section[0].offset;
u32 srcModuleSize,
dstModuleSize;
u32 loaderSize;
u32 loaderOffset = getLoader(arm11Section0, &loaderSize);
for(u8 *src = (u8 *)firm + section[0].offset, *srcEnd = src + section[0].size, *dst = section[0].address;
src < srcEnd; src += srcModuleSize, dst += dstModuleSize)
{
srcModuleSize = *(u32 *)(src + 0x104) * 0x200;
char *moduleName = (char *)(src + 0x200);
memcpy(section[0].address, arm11Section0, loaderOffset);
memcpy(section[0].address + loaderOffset, injector, injector_size);
memcpy(section[0].address + loaderOffset + injector_size, arm11Section0 + loaderOffset + loaderSize, section[0].size - (loaderOffset + loaderSize));
void *module;
if(memcmp(moduleName, "loader", 6) == 0)
{
module = (void *)injector;
dstModuleSize = injector_size;
}
else
{
module = src;
dstModuleSize = srcModuleSize;
}
memcpy(dst, module, dstModuleSize);
}
}
static inline void launchFirm(FirmwareType firmType, bool isFirmlaunch)
static inline void launchFirm(FirmwareType firmType)
{
//If we're booting NATIVE_FIRM, section0 needs to be copied separately to inject 3ds_injector
u32 sectionNum;
if(firmType == NATIVE_FIRM)
{
copySection0AndInjectLoader();
copySection0AndInjectSystemModules();
sectionNum = 1;
}
else sectionNum = 0;

View File

@@ -24,10 +24,10 @@
#include "types.h"
#define CFG_BOOTENV (*(vu32 *)0x10010000)
#define CFG_UNITINFO (*(vu8 *)0x10010010)
#define PDN_MPCORE_CFG (*(vu32 *)0x10140FFC)
#define PDN_SPI_CNT (*(vu32 *)0x101401C0)
#define CFG_BOOTENV (*(vu32 *)0x10010000)
#define CFG_UNITINFO (*(vu8 *)0x10010010)
//FIRM Header layout
typedef struct firmSectionHeader {
@@ -46,17 +46,10 @@ typedef struct firmHeader {
u8 reserved2[0x30];
firmSectionHeader section[4];
} firmHeader;
typedef enum ConfigurationStatus
{
DONT_CONFIGURE = 0,
MODIFY_CONFIGURATION = 1,
CREATE_CONFIGURATION = 2
} ConfigurationStatus;
static inline u32 loadFirm(FirmwareType firmType);
static inline u32 loadFirm(FirmwareType *firmType, FirmwareSource firmSource);
static inline void patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, bool isA9lh);
static inline void patchLegacyFirm(FirmwareType firmType);
static inline void patchSafeFirm(void);
static inline void copySection0AndInjectLoader(void);
static inline void launchFirm(FirmwareType firmType, bool isFirmlaunch);
static inline void patch1x2xNativeAndSafeFirm(void);
static inline void copySection0AndInjectSystemModules(void);
static inline void launchFirm(FirmwareType firmType);

View File

@@ -22,6 +22,7 @@
#include "fs.h"
#include "memory.h"
#include "strings.h"
#include "cache.h"
#include "screen.h"
#include "fatfs/ff.h"
@@ -64,7 +65,9 @@ bool fileWrite(const void *buffer, const char *path, u32 size)
{
FIL file;
if(f_open(&file, path, FA_WRITE | FA_OPEN_ALWAYS) == FR_OK)
FRESULT result = f_open(&file, path, FA_WRITE | FA_OPEN_ALWAYS);
if(result == FR_OK)
{
unsigned int written;
f_write(&file, buffer, size, &written);
@@ -72,13 +75,26 @@ bool fileWrite(const void *buffer, const char *path, u32 size)
return true;
}
else if(result == FR_NO_PATH)
{
char folder[256];
return false;
for(u32 i = 1; path[i] != 0; i++)
if(path[i] == '/')
{
memcpy(folder, path, i);
folder[i] = 0;
f_mkdir(folder);
}
return fileWrite(buffer, path, size);
}
else return false;
}
void createDirectory(const char *path)
void fileDelete(const char *path)
{
f_mkdir(path);
f_unlink(path);
}
void loadPayload(u32 pressed)
@@ -112,8 +128,8 @@ void loadPayload(u32 pressed)
memcpy(loaderAddress, loader, loader_size);
path[14] = '/';
memcpy(&path[15], info.altname, 13);
concatenateStrings(path, "/");
concatenateStrings(path, info.altname);
loaderAddress[1] = fileRead((void *)0x24F00000, path);
@@ -131,8 +147,9 @@ u32 firmRead(void *dest, u32 firmType)
{ "00000202", "20000202" },
{ "00000003", "20000003" }};
char path[48] = "1:/title/00040138/00000000/content";
memcpy(&path[18], firmFolders[firmType][isN3DS ? 1 : 0], 8);
char path[48] = "1:/title/00040138/";
concatenateStrings(path, firmFolders[firmType][isN3DS ? 1 : 0]);
concatenateStrings(path, "/content");
DIR dir;
FILINFO info;
@@ -162,19 +179,10 @@ u32 firmRead(void *dest, u32 firmType)
f_closedir(&dir);
//Complete the string with the .app name
memcpy(&path[34], "/00000000.app", 14);
//Last digit of the .app
u32 i = 42;
concatenateStrings(path, "/00000000.app");
//Convert back the .app name from integer to array
u32 tempVersion = firmVersion;
while(tempVersion)
{
static const char hexDigits[] = "0123456789ABCDEF";
path[i--] = hexDigits[tempVersion & 0xF];
tempVersion >>= 4;
}
hexItoa(firmVersion, &path[35]);
fileRead(dest, path);

View File

@@ -24,7 +24,7 @@
#include "types.h"
#define PATTERN(a) a "_*.bin"
#define PATTERN(a) a "_*.bin"
extern bool isN3DS;
@@ -32,6 +32,6 @@ void mountFs(void);
u32 fileRead(void *dest, const char *path);
u32 getFileSize(const char *path);
bool fileWrite(const void *buffer, const char *path, u32 size);
void createDirectory(const char *path);
void fileDelete(const char *path);
void loadPayload(u32 pressed);
u32 firmRead(void *dest, u32 firmType);

View File

@@ -41,7 +41,7 @@ void memset32(void *dest, u32 filler, u32 size)
{
u32 *dest32 = (u32 *)dest;
for (u32 i = 0; i < size / 4; i++)
for(u32 i = 0; i < size / 4; i++)
dest32[i] = filler;
}

View File

@@ -24,6 +24,7 @@
#include "memory.h"
#include "config.h"
#include "../build/rebootpatch.h"
#include "../build/svcGetCFWInfopatch.h"
u8 *getProcess9(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr)
{
@@ -36,6 +37,22 @@ u8 *getProcess9(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr)
return off - 0x204 + (*(u32 *)(off - 0x64) * 0x200) + 0x200;
}
u32 *getKernel11Info(u8 *pos, u32 size, u8 **freeK11Space)
{
const u8 pattern[] = {0x00, 0xB0, 0x9C, 0xE5};
u32 *arm11ExceptionsPage = (u32 *)memsearch(pos, pattern, size, sizeof(pattern)) - 0xB;
u32 svcOffset = (-((arm11ExceptionsPage[2] & 0xFFFFFF) << 2) & (0xFFFFFF << 2)) - 8; //Branch offset + 8 for prefetch
u32 *arm11SvcTable = (u32 *)(pos + *(u32 *)(pos + 0xFFFF0008 - svcOffset - 0xFFF00000 + 8) - 0xFFF00000); //SVC handler address
while(*arm11SvcTable) arm11SvcTable++; //Look for SVC0 (NULL)
const u8 pattern2[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
*freeK11Space = memsearch(pos, pattern2, size, sizeof(pattern2)) + 1;
return arm11SvcTable;
}
void patchSignatureChecks(u8 *pos, u32 size)
{
const u16 sigPatch[2] = {0x2000, 0x4770};
@@ -44,8 +61,8 @@ void patchSignatureChecks(u8 *pos, u32 size)
const u8 pattern[] = {0xC0, 0x1C, 0x76, 0xE7},
pattern2[] = {0xB5, 0x22, 0x4D, 0x0C};
u16 *off = (u16 *)memsearch(pos, pattern, size, 4),
*off2 = (u16 *)(memsearch(pos, pattern2, size, 4) - 1);
u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern)),
*off2 = (u16 *)(memsearch(pos, pattern2, size, sizeof(pattern2)) - 1);
*off = sigPatch[0];
off2[0] = sigPatch[0];
@@ -55,9 +72,9 @@ void patchSignatureChecks(u8 *pos, u32 size)
void patchFirmlaunches(u8 *pos, u32 size, u32 process9MemAddr)
{
//Look for firmlaunch code
const u8 pattern[] = {0xDE, 0x1F, 0x8D, 0xE2};
const u8 pattern[] = {0xE2, 0x20, 0x20, 0x90};
u8 *off = memsearch(pos, pattern, size, 4) - 0x10;
u8 *off = memsearch(pos, pattern, size, sizeof(pattern)) - 0x13;
//Firmlaunch function offset - offset in BLX opcode (A4-16 - ARM DDI 0100E) + 1
u32 fOpenOffset = (u32)(off + 9 - (-((*(u32 *)off & 0x00FFFFFF) << 2) & (0xFFFFFF << 2)) - pos + process9MemAddr);
@@ -72,70 +89,82 @@ void patchFirmlaunches(u8 *pos, u32 size, u32 process9MemAddr)
void patchFirmWrites(u8 *pos, u32 size)
{
const u16 writeBlock[2] = {0x2000, 0x46C0};
//Look for FIRM writing code
u8 *const off1 = memsearch(pos, "exe:", size, 4);
const u8 pattern[] = {0x00, 0x28, 0x01, 0xDA};
u16 *off2 = (u16 *)memsearch(off1 - 0x100, pattern, 0x100, 4);
u16 *off2 = (u16 *)memsearch(off1 - 0x100, pattern, 0x100, sizeof(pattern));
off2[0] = writeBlock[0];
off2[1] = writeBlock[1];
off2[0] = 0x2000;
off2[1] = 0x46C0;
}
void patchFirmWriteSafe(u8 *pos, u32 size)
void patchOldFirmWrites(u8 *pos, u32 size)
{
const u16 writeBlockSafe[2] = {0x2400, 0xE01D};
//Look for FIRM writing code
const u8 pattern[] = {0x04, 0x1E, 0x1D, 0xDB};
u16 *off = (u16 *)memsearch(pos, pattern, size, 4);
u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
off[0] = writeBlockSafe[0];
off[1] = writeBlockSafe[1];
off[0] = 0x2400;
off[1] = 0xE01D;
}
void reimplementSvcBackdoor(u8 *pos, u32 size)
void reimplementSvcBackdoor(u8 *pos, u32 *arm11SvcTable, u8 **freeK11Space)
{
//Official implementation of svcBackdoor
const u8 svcBackdoor[40] = {0xFF, 0x10, 0xCD, 0xE3, //bic r1, sp, #0xff
0x0F, 0x1C, 0x81, 0xE3, //orr r1, r1, #0xf00
0x28, 0x10, 0x81, 0xE2, //add r1, r1, #0x28
0x00, 0x20, 0x91, 0xE5, //ldr r2, [r1]
0x00, 0x60, 0x22, 0xE9, //stmdb r2!, {sp, lr}
0x02, 0xD0, 0xA0, 0xE1, //mov sp, r2
0x30, 0xFF, 0x2F, 0xE1, //blx r0
0x03, 0x00, 0xBD, 0xE8, //pop {r0, r1}
0x00, 0xD0, 0xA0, 0xE1, //mov sp, r0
0x11, 0xFF, 0x2F, 0xE1}; //bx r1
const u8 svcBackdoor[40] = {0xFF, 0x10, 0xCD, 0xE3, //bic r1, sp, #0xff
0x0F, 0x1C, 0x81, 0xE3, //orr r1, r1, #0xf00
0x28, 0x10, 0x81, 0xE2, //add r1, r1, #0x28
0x00, 0x20, 0x91, 0xE5, //ldr r2, [r1]
0x00, 0x60, 0x22, 0xE9, //stmdb r2!, {sp, lr}
0x02, 0xD0, 0xA0, 0xE1, //mov sp, r2
0x30, 0xFF, 0x2F, 0xE1, //blx r0
0x03, 0x00, 0xBD, 0xE8, //pop {r0, r1}
0x00, 0xD0, 0xA0, 0xE1, //mov sp, r0
0x11, 0xFF, 0x2F, 0xE1}; //bx r1
const u8 pattern[] = {0x00, 0xB0, 0x9C, 0xE5}; //cpsid aif
u32 *exceptionsPage = (u32 *)memsearch(pos, pattern, size, 4) - 0xB;
u32 svcOffset = (-((exceptionsPage[2] & 0xFFFFFF) << 2) & (0xFFFFFF << 2)) - 8; //Branch offset + 8 for prefetch
u32 *svcTable = (u32 *)(pos + *(u32 *)(pos + 0xFFFF0008 - svcOffset - 0xFFF00000 + 8) - 0xFFF00000); //SVC handler address
while(*svcTable) svcTable++; //Look for SVC0 (NULL)
if(svcTable[0x7B] == 0)
if(!arm11SvcTable[0x7B])
{
u32 *freeSpace;
for(freeSpace = exceptionsPage; *freeSpace != 0xFFFFFFFF; freeSpace++);
memcpy(*freeK11Space, svcBackdoor, 40);
memcpy(freeSpace, svcBackdoor, 40);
svcTable[0x7B] = 0xFFFF0000 + ((u8 *)freeSpace - (u8 *)exceptionsPage);
arm11SvcTable[0x7B] = 0xFFF00000 + *freeK11Space - pos;
*freeK11Space += 40;
}
}
void implementSvcGetCFWInfo(u8 *pos, u32 *arm11SvcTable, u8 **freeK11Space)
{
memcpy(*freeK11Space, svcGetCFWInfo, svcGetCFWInfo_size);
CFWInfo *info = (CFWInfo *)memsearch(*freeK11Space, "LUMA", svcGetCFWInfo_size, 4);
const char *rev = REVISION;
bool isRelease;
info->commitHash = COMMIT_HASH;
info->config = configData.config;
info->versionMajor = (u8)(rev[1] - '0');
info->versionMinor = (u8)(rev[3] - '0');
if(rev[4] == '.')
{
info->versionBuild = (u8)(rev[5] - '0');
isRelease = rev[6] == 0;
}
else isRelease = rev[4] == 0;
info->flags = 0 /* master branch */ | ((isRelease ? 1 : 0) << 1) /* is release */;
arm11SvcTable[0x2E] = 0xFFF00000 + *freeK11Space - pos; //Stubbed svc
*freeK11Space += svcGetCFWInfo_size;
}
void patchTitleInstallMinVersionCheck(u8 *pos, u32 size)
{
const u8 pattern[] = {0x0A, 0x81, 0x42, 0x02};
u8 *off = memsearch(pos, pattern, size, 4);
u8 *off = memsearch(pos, pattern, size, sizeof(pattern));
if(off != NULL) off[4] = 0xE0;
}
@@ -160,7 +189,7 @@ void applyLegacyFirmPatches(u8 *pos, FirmwareType firmType)
/* 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 = firmType == TWL_FIRM ? (sizeof(twlPatches) / sizeof(patchData)) :
(sizeof(agbPatches) / sizeof(patchData) - !CONFIG(5));
(sizeof(agbPatches) / sizeof(patchData) - !CONFIG_SHOWGBABOOT);
const patchData *patches = firmType == TWL_FIRM ? twlPatches : agbPatches;
//Patch
@@ -178,21 +207,4 @@ void applyLegacyFirmPatches(u8 *pos, FirmwareType firmType)
break;
}
}
}
u32 getLoader(u8 *pos, u32 *loaderSize)
{
u8 *off = pos;
u32 size;
while(true)
{
size = *(u32 *)(off + 0x104) * 0x200;
if(*(u32 *)(off + 0x200) == 0x64616F6C) break;
off += size;
}
*loaderSize = size;
return (u32)(off - pos);
}

View File

@@ -33,14 +33,29 @@ typedef struct patchData {
u32 type;
} patchData;
typedef struct __attribute__((packed))
{
char magic[4];
u8 versionMajor;
u8 versionMinor;
u8 versionBuild;
u8 flags;
u32 commitHash;
u32 config;
} CFWInfo;
extern bool isN3DS;
u8 *getProcess9(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr);
u32 *getKernel11Info(u8 *pos, u32 size, u8 **freeK11Space);
void patchSignatureChecks(u8 *pos, u32 size);
void patchTitleInstallMinVersionCheck(u8 *pos, u32 size);
void patchFirmlaunches(u8 *pos, u32 size, u32 process9MemAddr);
void patchFirmWrites(u8 *pos, u32 size);
void patchFirmWriteSafe(u8 *pos, u32 size);
void reimplementSvcBackdoor(u8 *pos, u32 size);
void applyLegacyFirmPatches(u8 *pos, FirmwareType firmType);
u32 getLoader(u8 *pos, u32 *loaderSize);
void patchOldFirmWrites(u8 *pos, u32 size);
void reimplementSvcBackdoor(u8 *pos, u32 *arm11SvcTable, u8 **freeK11Space);
void implementSvcGetCFWInfo(u8 *pos, u32 *arm11SvcTable, u8 **freeK11Space);
void applyLegacyFirmPatches(u8 *pos, FirmwareType firmType);

View File

@@ -26,6 +26,7 @@
*/
#include "draw.h"
#include "config.h"
#include "screen.h"
#include "utils.h"
#include "memory.h"
@@ -34,95 +35,32 @@
#include "pin.h"
#include "crypto.h"
bool readPin(PINData *out)
static char pinKeyToLetter(u32 pressed)
{
u8 __attribute__((aligned(4))) zeroes[16] = {0};
u8 __attribute__((aligned(4))) tmp[32] = {0};
if(fileRead(out, "/luma/pin.bin") != sizeof(PINData)) return false;
if(memcmp(out->magic, "PINF", 4) != 0) return false;
computePINHash(tmp, zeroes, 1);
return memcmp(out->testHash, tmp, 32) == 0; //test vector verification (SD card has (or hasn't) been used on another console)
}
static inline char PINKeyToLetter(u32 pressed)
{
const char keys[] = "AB--------XY";
const char keys[] = "AB--RLUD--XY";
u32 i;
__asm__ volatile("clz %[i], %[pressed]" : [i] "=r" (i) : [pressed] "r" (pressed));
for(i = 31; pressed > 1; i--) pressed /= 2;
return keys[31 - i];
}
void newPin(void)
void newPin(bool allowSkipping)
{
clearScreens();
drawString("Enter your NEW PIN: ", 10, 10, COLOR_WHITE);
char *title = allowSkipping ? "Press START to skip or enter a new PIN" : "Enter a new PIN to proceed";
drawString(title, 10, 10, COLOR_TITLE);
drawString("PIN: ", 10, 10 + 2 * SPACING_Y, COLOR_WHITE);
// Set the default value as 0x00 so we can check if there are any unentered characters.
u8 __attribute__((aligned(4))) enteredPassword[16 * ((PIN_LENGTH + 15) / 16)] = {0}; // pad to AES block length
//Pad to AES block length with zeroes
u8 __attribute__((aligned(4))) enteredPassword[0x10] = {0};
u32 cnt = 0;
int charDrawPos = 20 * SPACING_X;
while(cnt < PIN_LENGTH)
{
u32 pressed;
do
{
pressed = waitInput();
}
while(!(pressed & PIN_BUTTONS & ~BUTTON_START));
pressed &= PIN_BUTTONS & ~BUTTON_START;
if(!pressed) continue;
char key = PINKeyToLetter(pressed);
enteredPassword[cnt++] = (u8)key; // add character to password.
// visualize character on screen.
drawCharacter(key, 10 + charDrawPos, 10, COLOR_WHITE);
charDrawPos += 2 * SPACING_X;
}
PINData pin = {0};
u8 __attribute__((aligned(4))) tmp[32] = {0};
u8 __attribute__((aligned(4))) zeroes[16] = {0};
memcpy(pin.magic, "PINF", 4);
pin.formatVersionMajor = 1;
pin.formatVersionMinor = 0;
computePINHash(tmp, zeroes, 1);
memcpy(pin.testHash, tmp, 32);
computePINHash(tmp, enteredPassword, (PIN_LENGTH + 15) / 16);
memcpy(pin.hash, tmp, 32);
fileWrite(&pin, "/luma/pin.bin", sizeof(PINData));
while(HID_PAD & PIN_BUTTONS);
}
void verifyPin(PINData *in)
{
initScreens();
drawString("Press START to shutdown or enter pin to proceed.", 10, 10, COLOR_WHITE);
drawString("Pin: ", 10, 10 + 2 * SPACING_Y, COLOR_WHITE);
// Set the default characters as 0x00 so we can check if there are any unentered characters.
u8 __attribute__((aligned(4))) enteredPassword[16 * ((PIN_LENGTH + 15) / 16)] = {0};
u32 cnt = 0;
bool unlock = false;
u8 length = 4 + 2 * (CONFIG_PIN - 1),
cnt = 0;
int charDrawPos = 5 * SPACING_X;
while(!unlock)
while(cnt < length)
{
u32 pressed;
do
@@ -131,25 +69,97 @@ void verifyPin(PINData *in)
}
while(!(pressed & PIN_BUTTONS));
pressed &= PIN_BUTTONS & ~BUTTON_START;
pressed &= PIN_BUTTONS;
if(!allowSkipping) pressed &= ~BUTTON_START;
if(pressed & BUTTON_START) return;
if(!pressed) continue;
char key = pinKeyToLetter(pressed);
enteredPassword[cnt++] = (u8)key; //Add character to password
//Visualize character on screen
drawCharacter(key, 10 + charDrawPos, 10 + 2 * SPACING_Y, COLOR_WHITE);
charDrawPos += 2 * SPACING_X;
}
PINData pin;
memcpy(pin.magic, "PINF", 4);
pin.formatVersionMajor = PIN_VERSIONMAJOR;
pin.formatVersionMinor = PIN_VERSIONMINOR;
pin.length = length;
u8 __attribute__((aligned(4))) tmp[0x20];
u8 __attribute__((aligned(4))) zeroes[0x10] = {0};
computePinHash(tmp, zeroes);
memcpy(pin.testHash, tmp, sizeof(tmp));
computePinHash(tmp, enteredPassword);
memcpy(pin.hash, tmp, sizeof(tmp));
if(!fileWrite(&pin, PIN_PATH, sizeof(PINData)))
error("Error writing the PIN file");
}
bool verifyPin(void)
{
initScreens();
PINData pin;
if(fileRead(&pin, PIN_PATH) != sizeof(PINData) ||
memcmp(pin.magic, "PINF", 4) != 0 ||
pin.formatVersionMajor != PIN_VERSIONMAJOR ||
pin.formatVersionMinor != PIN_VERSIONMINOR ||
pin.length != 4 + 2 * (CONFIG_PIN - 1))
return false;
u8 __attribute__((aligned(4))) zeroes[0x10] = {0};
u8 __attribute__((aligned(4))) tmp[0x20];
computePinHash(tmp, zeroes);
//Test vector verification (SD card has, or hasn't been used on another console)
if(memcmp(pin.testHash, tmp, sizeof(tmp)) != 0) return false;
//Pad to AES block length with zeroes
u8 __attribute__((aligned(4))) enteredPassword[0x10] = {0};
u8 cnt = 0;
bool unlock = false;
int charDrawPos = 5 * SPACING_X;
while(!unlock)
{
drawString("Press START to shutdown or enter PIN to proceed", 10, 10, COLOR_TITLE);
drawString("PIN: ", 10, 10 + 2 * SPACING_Y, COLOR_WHITE);
u32 pressed;
do
{
pressed = waitInput();
}
while(!(pressed & PIN_BUTTONS));
if(pressed & BUTTON_START) mcuPowerOff();
char key = PINKeyToLetter(pressed);
enteredPassword[cnt++] = (u8)key; // add character to password.
pressed &= PIN_BUTTONS;
// visualize character on screen.
if(!pressed) continue;
char key = pinKeyToLetter(pressed);
enteredPassword[cnt++] = (u8)key; //Add character to password
//Visualize character on screen
drawCharacter(key, 10 + charDrawPos, 10 + 2 * SPACING_Y, COLOR_WHITE);
charDrawPos += 2 * SPACING_X;
if(cnt >= PIN_LENGTH)
if(cnt >= pin.length)
{
u8 __attribute__((aligned(4))) tmp[32] = {0};
computePINHash(tmp, enteredPassword, (PIN_LENGTH + 15) / 16);
unlock = memcmp(in->hash, tmp, 32) == 0;
computePinHash(tmp, enteredPassword);
unlock = memcmp(pin.hash, tmp, sizeof(tmp)) == 0;
if(!unlock)
{
@@ -158,10 +168,10 @@ void verifyPin(PINData *in)
clearScreens();
drawString("Press START to shutdown or enter pin to proceed.", 10, 10, COLOR_WHITE);
drawString("Pin: ", 10, 10 + 2 * SPACING_Y, COLOR_WHITE);
drawString("Wrong pin! Try again!", 10, 10 + 3 * SPACING_Y, COLOR_RED);
drawString("Wrong PIN, try again", 10, 10 + 4 * SPACING_Y, COLOR_RED);
}
}
}
return true;
}

View File

@@ -30,17 +30,19 @@
#include "types.h"
#define PIN_LENGTH 4
#define PIN_PATH "/luma/pin.bin"
#define PIN_VERSIONMAJOR 1
#define PIN_VERSIONMINOR 2
typedef struct __attribute__((packed))
{
char magic[4];
u16 formatVersionMajor, formatVersionMinor;
u8 length;
u8 testHash[32];
u8 hash[32];
} PINData;
bool readPin(PINData* out);
void newPin(void);
void verifyPin(PINData *in);
void newPin(bool allowSkipping);
bool verifyPin(void);

View File

@@ -147,7 +147,7 @@ void initScreens(void)
//Disable interrupts
__asm(".word 0xF10C01C0");
u32 brightnessLevel = brightness[MULTICONFIG(0)];
u32 brightnessLevel = brightness[CONFIG_BRIGHTNESS];
*(vu32 *)0x10141200 = 0x1007F;
*(vu32 *)0x10202014 = 0x00000001;
@@ -242,7 +242,7 @@ void initScreens(void)
if(PDN_GPU_CNT == 1)
{
flushDCacheRange(&config, 4);
flushDCacheRange(&configData, sizeof(cfgData));
flushDCacheRange((void *)fb, sizeof(struct fb));
invokeArm11Function(ARM11);
@@ -254,6 +254,6 @@ void initScreens(void)
else
{
clearScreens();
updateBrightness(MULTICONFIG(0));
updateBrightness(CONFIG_BRIGHTNESS);
}
}

View File

@@ -29,9 +29,10 @@
#include "types.h"
#define PDN_GPU_CNT (*(vu8 *)0x10141200)
#define ARM11_STUB_ADDRESS (0x25000000 - 0x30) //It's currently only 0x28 bytes large. We're putting 0x30 just to be sure here
#define WAIT_FOR_ARM9() *arm11Entry = 0; while(!*arm11Entry); ((void (*)())*arm11Entry)();
#define PDN_GPU_CNT (*(vu8 *)0x10141200)
#define ARM11_STUB_ADDRESS (0x25000000 - 0x30) //It's currently only 0x28 bytes large. We're putting 0x30 just to be sure here
#define WAIT_FOR_ARM9() *arm11Entry = 0; while(!*arm11Entry); ((void (*)())*arm11Entry)();
static volatile struct fb {
u8 *top_left;

View File

@@ -26,8 +26,8 @@
_start:
b start
.global launchedFirmTIDLow
launchedFirmTIDLow:
.global launchedFirmTidLow
launchedFirmTidLow:
.hword 0, 0, 0, 0, 0, 0, 0, 0
start:

55
source/strings.c Normal file
View File

@@ -0,0 +1,55 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
*/
#include "strings.h"
#include "memory.h"
int strlen(const char *string)
{
char *stringEnd = (char *)string;
while(*stringEnd) stringEnd++;
return stringEnd - string;
}
void concatenateStrings(char *destination, const char *source)
{
int i = strlen(source),
j = strlen(destination);
memcpy(&destination[j], source, i + 1);
}
void hexItoa(u32 number, char *out)
{
const char hexDigits[] = "0123456789ABCDEF";
u32 i = 0;
while(number > 0)
{
out[7 - i++] = hexDigits[number & 0xF];
number >>= 4;
}
for(; i < 8; i++) out[7 - i] = '0';
}

29
source/strings.h Normal file
View File

@@ -0,0 +1,29 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
*/
#pragma once
#include "types.h"
int strlen(const char *string);
void concatenateStrings(char *destination, const char *source);
void hexItoa(u32 number, char *out);

View File

@@ -36,7 +36,7 @@ typedef volatile u16 vu16;
typedef volatile u32 vu32;
typedef volatile u64 vu64;
//Used by multiple files:
//Used by multiple files
typedef enum FirmwareSource
{
FIRMWARE_SYSNAND = 0,
@@ -49,5 +49,6 @@ typedef enum FirmwareType
NATIVE_FIRM = 0,
TWL_FIRM = 1,
AGB_FIRM = 2,
SAFE_FIRM = 3
SAFE_FIRM = 3,
NATIVE_FIRM1X2X = 4
} FirmwareType;

View File

@@ -56,7 +56,7 @@ u32 waitInput(void)
void mcuReboot(void)
{
if(PDN_GPU_CNT != 1) clearScreens();
if(!isFirmlaunch && PDN_GPU_CNT != 1) clearScreens();
flushEntireDCache(); //Ensure that all memory transfers have completed and that the data cache has been flushed
@@ -66,7 +66,7 @@ void mcuReboot(void)
void mcuPowerOff(void)
{
if(PDN_GPU_CNT != 1) clearScreens();
if(!isFirmlaunch && PDN_GPU_CNT != 1) clearScreens();
flushEntireDCache(); //Ensure that all memory transfers have completed and that the data cache has been flushed

View File

@@ -28,6 +28,8 @@
#define REG_TIMER_CNT(i) *(vu16 *)(0x10003002 + 4 * i)
#define REG_TIMER_VAL(i) *(vu16 *)(0x10003000 + 4 * i)
extern bool isFirmlaunch;
u32 waitInput(void);
void mcuReboot(void);
void mcuPowerOff(void);